mirror of
https://github.com/whekin/household-bot.git
synced 2026-03-31 19:14:03 +00:00
feat(finance): add settlement currency and cycle fx rates
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
export { BillingPeriod } from './billing-period'
|
||||
export { DOMAIN_ERROR_CODE, DomainError } from './errors'
|
||||
export { BillingCycleId, HouseholdId, MemberId, PurchaseEntryId } from './ids'
|
||||
export { CURRENCIES, Money } from './money'
|
||||
export { CURRENCIES, FX_RATE_SCALE_MICROS, Money, convertMoney } from './money'
|
||||
export { normalizeSupportedLocale, SUPPORTED_LOCALES } from './locale'
|
||||
export {
|
||||
Temporal,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DOMAIN_ERROR_CODE, DomainError } from './errors'
|
||||
|
||||
export const CURRENCIES = ['GEL', 'USD'] as const
|
||||
export const FX_RATE_SCALE_MICROS = 1_000_000n
|
||||
|
||||
export type CurrencyCode = (typeof CURRENCIES)[number]
|
||||
|
||||
@@ -73,6 +74,23 @@ function formatMajorUnits(minor: bigint): string {
|
||||
return `${sign}${whole.toString()}.${fractionString}`
|
||||
}
|
||||
|
||||
function divideRoundedHalfUp(dividend: bigint, divisor: bigint): bigint {
|
||||
if (divisor === 0n) {
|
||||
throw new DomainError(DOMAIN_ERROR_CODE.INVALID_MONEY_AMOUNT, 'Division by zero')
|
||||
}
|
||||
|
||||
const sign = dividend < 0n ? -1n : 1n
|
||||
const absoluteDividend = dividend < 0n ? -dividend : dividend
|
||||
const quotient = absoluteDividend / divisor
|
||||
const remainder = absoluteDividend % divisor
|
||||
|
||||
if (remainder * 2n >= divisor) {
|
||||
return (quotient + 1n) * sign
|
||||
}
|
||||
|
||||
return quotient * sign
|
||||
}
|
||||
|
||||
export class Money {
|
||||
readonly amountMinor: bigint
|
||||
readonly currency: CurrencyCode
|
||||
@@ -257,3 +275,23 @@ export class Money {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function convertMoney(
|
||||
amount: Money,
|
||||
targetCurrency: CurrencyCode,
|
||||
rateMicros: bigint
|
||||
): Money {
|
||||
if (rateMicros <= 0n) {
|
||||
throw new DomainError(
|
||||
DOMAIN_ERROR_CODE.INVALID_MONEY_AMOUNT,
|
||||
`Exchange rate must be positive: ${rateMicros.toString()}`
|
||||
)
|
||||
}
|
||||
|
||||
if (amount.currency === targetCurrency) {
|
||||
return amount
|
||||
}
|
||||
|
||||
const convertedMinor = divideRoundedHalfUp(amount.amountMinor * rateMicros, FX_RATE_SCALE_MICROS)
|
||||
return Money.fromMinor(convertedMinor, targetCurrency)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user