Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/domain/shared/money/JMDAmount.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { getCurrencyMajorExponent } from "@domain/fiat/display-currency"

import Money from "../bigint-money"
import Money, { Round } from "../bigint-money"

import { BigIntConversionError } from "../errors"
import { WalletCurrency } from "../primitives"
Expand All @@ -26,7 +26,13 @@ export class JMDAmount extends MoneyAmount {

static dollars(d: number): JMDAmount | BigIntConversionError {
try {
return new JMDAmount(BigInt(d) * 100n)
// Mirror USDAmount.dollars: use the Money lib for a decimal-safe conversion.
// BigInt(d) throws on any fractional rate (e.g. an NCB rate of 155.5), which
// is what the exchange-rate value virtually always is.
const dollarAmt = new Money(d.toString(), "JMDollars", Round.HALF_TO_EVEN)
const cents = JMDAmount.cents("100")
if (cents instanceof BigIntConversionError) return cents // should never happen
return new JMDAmount(cents.money.multiply(dollarAmt).toFixed(2))
} catch (error) {
return new BigIntConversionError(
error instanceof Error ? error.message : String(error),
Expand Down
13 changes: 13 additions & 0 deletions test/flash/unit/domain/shared/Money.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ describe("Money Amount", () => {
const jmdprice = usdAmount.convertAtRate(rate)
expect(jmdprice.asDollars()).toBe("16000.00")
})

// Regression: the live NCB cashout rate is virtually always fractional
// (e.g. 155.5, 152.7). The old JMDAmount.dollars did `BigInt(d) * 100n`,
// which threw on any non-integer, breaking every JMD cashout offer.
// This imports JMDAmount from @domain/shared — the exact barrel-resolved
// class the cashout path uses (see ErpNext.getCashoutExchangeRate).
it("accepts fractional JMD rates (regression: NCB rate 155.5)", () => {
const amt = JMDAmount.dollars(155.5)
if (amt instanceof Error) throw amt
expect(amt.asDollars()).toBe("155.50")
expect(JMDAmount.dollars(152.7)).not.toBeInstanceOf(Error)
expect(JMDAmount.dollars(0.5)).not.toBeInstanceOf(Error)
})
})

describe("USD Amount", () => {
Expand Down
Loading