Skip to content

Commit

Permalink
feat: support setting fractionless exponent
Browse files Browse the repository at this point in the history
Support importing a number from fractionless where the accuracy is higher than the lowest exponent of the currency.

Example:

```
Money.fromFractionlessAmount(1000, "NOK")
// 10.00

Money.fromFractionlessAmount(1000, "NOK", { exponent: 3})
// 1.00

Money.fromFractionlessAmount(1000, "NOK", { exponent: 3, decimals: 3})
// 1.000
```
  • Loading branch information
andersem committed Nov 20, 2024
1 parent fb6bffb commit ca5c149
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 3 deletions.
20 changes: 20 additions & 0 deletions src/__tests__/money.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,26 @@ describe("money", () => {
expect(result).toBe("0.0600000000");
});

it("should keep higher precicion fromPrice", () => {
const result = Money.fromPrice(2.164727, "NOK", { decimals: 6 });
expect(result.toString()).toBe("2.164727");
});

it("should keep higher precicion from fractionless when explicitly set", () => {
const result = Money.fromFractionlessAmount(2164727, "NOK", {
exponent: 6,
decimals: 6,
});
expect(result.toString()).toBe("2.164727");
});

it("should import with higher precision from fractionless, but round when decimals not set", () => {
const result = Money.fromFractionlessAmount(2165727, "NOK", {
exponent: 6,
});
expect(result.toString()).toBe("2.17");
});

it("should be able to convert large numbers within double precision", () => {
Money.of("1234567891234.25", "NOK").toNumber();
});
Expand Down
25 changes: 22 additions & 3 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export type AdditionalOptions = {
tags?: Partial<Tags>;
};

export type FractionLessAdditionalOptions = AdditionalOptions & {
exponent?: number;
};

export type MoneyInputData = {
amount: NumberInput;
currency: string;
Expand All @@ -36,7 +40,22 @@ type MoneyData = {

const DEFAULT_DECIMALS_PRICE = 10;

const currencyToDecimals = (currency: string): number => {
const isOptionsWithExponent = (
options: AdditionalOptions | FractionLessAdditionalOptions | undefined,
): options is Required<Pick<FractionLessAdditionalOptions, "exponent">> => {
return (
options !== undefined &&
(options as FractionLessAdditionalOptions).exponent !== undefined
);
};

const currencyToDecimals = (
currency: string,
options?: AdditionalOptions | FractionLessAdditionalOptions,
): number => {
if (isOptionsWithExponent(options)) {
return options.exponent;
}
const decimals = cc.code(currency)?.digits;
if (decimals === undefined) {
if (currency === "UNKNOWN") {
Expand Down Expand Up @@ -150,10 +169,10 @@ export class Money {
static fromFractionlessAmount(
amount: number,
currency: string,
options?: AdditionalOptions,
options?: FractionLessAdditionalOptions,
): Money {
return Money.of(amount, currency, options).divide(
10 ** currencyToDecimals(currency),
10 ** currencyToDecimals(currency, options),
);
}

Expand Down

0 comments on commit ca5c149

Please sign in to comment.