From b54eeb1fc35807b380824a25bdd37c4ba34b73d0 Mon Sep 17 00:00:00 2001 From: Alexander Presthus <56009327+alexpresthus@users.noreply.github.com> Date: Thu, 21 Nov 2024 13:00:34 +0100 Subject: [PATCH] fix(fractionless): honor decimals in fractionless amounts (#265) Honor the configured precision, as defined by `options.decimals` or `currency` if `options.decimals = undefined`, when instatiating with `.fromFractionlessAmount()` and converting `.toFractionlessAmount()`. Fixes old behavior: ``` Money.fromFractionlessAmount(1000, 'NOK', { decimals: 3 }) => 10.000 NOK money.toFractionlessAmount() => 1000 NOK ``` To expected behavior: ``` Money.fromFractionlessAmount(1000, 'NOK', { decimals: 3 }) => 1.000 NOK money.toFractionlessAmount() => 1000 NOK ``` --- README.md | 5 ++++- src/__tests__/money.test.ts | 26 ++++++++++++++++++++++++++ src/index.ts | 14 +++++++++----- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0804b96..ffeddcb 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,8 @@ export declare class Money { * * Example: * Money.fromFractionlessAmount(1000, 'NOK') => 10.00 NOK + * Money.fromFractionlessAmount(1000, 'NOK', { decimals: 2 }) => 10.00 NOK + * Money.fromFractionlessAmount(1000, 'NOK', { decimals: 3 }) => 1.000 NOK */ static fromFractionlessAmount( amount: number, @@ -314,7 +316,8 @@ export declare class Money { // Converters /** - * Converts the money amount into a whole number given in the minor unit of the currency + * Converts the money amount into a whole number given in the minor unit of the currency. + * Honors the current precision in use. */ toFractionlessAmount: () => number; /** diff --git a/src/__tests__/money.test.ts b/src/__tests__/money.test.ts index 154c4ab..7d447b9 100644 --- a/src/__tests__/money.test.ts +++ b/src/__tests__/money.test.ts @@ -152,6 +152,32 @@ describe("money", () => { expect(result).toBe("10.00"); }); + it("should instantiate from fractionless amount and honor decimals in options", () => { + const result = Money.fromFractionlessAmount(1000, "NOK", { + decimals: 3, + }).toString(); + expect(result).toBe("1.000"); + }); + + it("should convert to fractionless amount", () => { + const result = Money.of(10, "NOK").toFractionlessAmount(); + expect(result).toBe(1000); + }); + + it("should convert from fractionless amount to fractionless amount and honor decimals in options", () => { + const result = Money.fromFractionlessAmount(1000, "NOK", { + decimals: 3, + }).toFractionlessAmount(); + expect(result).toBe(1000); + }); + + it("should convert from normal to fractionless amount and honor decimals in options", () => { + const result = Money.of(10, "NOK", { + decimals: 4, + }).toFractionlessAmount(); + expect(result).toBe(100000); + }); + it("should print in locale", () => { const result = Money.of(5.5, "NOK").toLocaleString("no-NB"); expect(result).toBe("5,50"); diff --git a/src/index.ts b/src/index.ts index 69e7ef3..ab51f0a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -146,15 +146,16 @@ export class Money { * * Example: * Money.fromFractionlessAmount(1000, 'NOK') => 10.00 NOK + * Money.fromFractionlessAmount(1000, 'NOK', { decimals: 2 }) => 10.00 NOK + * Money.fromFractionlessAmount(1000, 'NOK', { decimals: 3 }) => 1.000 NOK */ static fromFractionlessAmount( amount: number, currency: string, options?: AdditionalOptions, ): Money { - return Money.of(amount, currency, options).divide( - 10 ** currencyToDecimals(currency), - ); + const decimals = options?.decimals ?? currencyToDecimals(currency); + return Money.of(amount, currency, options).divide(10 ** decimals); } /** @@ -309,10 +310,13 @@ export class Money { }; /** - * Converts the money amount into a whole number given in the minor unit of the currency + * Converts the money amount into a whole number given in the minor unit of the currency. + * Honors the current precision in use. */ toFractionlessAmount = (): number => { - return this.multiply(10 ** currencyToDecimals(this.currency())) + const decimals = + this.getDecimals() ?? currencyToDecimals(this.currency()); + return this.multiply(10 ** decimals) .round(0) .toNumber(); };