fix(money): zero-decimal currency handling (D7)

Stripe sends zero-decimal currencies (JPY/KRW/VND/...) already in the
major unit; the unconditional /100 recorded a JPY dues charge 100x
understated in the ledger + receipt. minorToMajor is now currency-aware
(shared ZERO_DECIMAL_CURRENCIES/isZeroDecimalCurrency in
notifications-logic); formatMoney renders no fractional part for those.
Never fires for USD; closes silent ledger corruption for such tenants.
Tests added; suite 526+.
This commit is contained in:
Moheeb Zara
2026-05-18 18:38:25 -07:00
parent c9c0909ad7
commit 7b0948ddd6
5 changed files with 44 additions and 15 deletions
+4
View File
@@ -85,6 +85,10 @@ describe('formatMoney', () => {
expect(formatMoney(undefined, 'usd')).toBe('')
expect(formatMoney(NaN, 'usd')).toBe('')
})
it('renders zero-decimal currencies with no fractional part', () => {
expect(formatMoney(3000, 'jpy')).toBe('3000 JPY')
expect(formatMoney(50000, 'KRW')).toBe('50000 KRW')
})
})
describe('renderDuesEmail', () => {
+11 -5
View File
@@ -140,10 +140,16 @@ describe('laterPeriodEnd (never rewind on out-of-order events)', () => {
})
})
describe('minorToMajor', () => {
it('divides by 100, treats nullish as 0', () => {
expect(minorToMajor(2500)).toBe(25)
expect(minorToMajor(null)).toBe(0)
expect(minorToMajor(undefined)).toBe(0)
describe('minorToMajor (currency-aware)', () => {
it('divides by 100 for normal 2-decimal currencies', () => {
expect(minorToMajor(2500, 'usd')).toBe(25)
expect(minorToMajor(2500, 'EUR')).toBe(25)
expect(minorToMajor(null, 'usd')).toBe(0)
expect(minorToMajor(undefined, undefined)).toBe(0)
})
it('does NOT divide zero-decimal currencies (JPY/KRW already major)', () => {
expect(minorToMajor(3000, 'jpy')).toBe(3000)
expect(minorToMajor(50000, 'KRW')).toBe(50000)
expect(minorToMajor(1000, 'VND')).toBe(1000)
})
})