Skip to content

Commit

Permalink
fix(toDecimal): teach toDecimal how to handle negative units (#690)
Browse files Browse the repository at this point in the history
Previously, `toDecimal` would format an amount like -1050 as '-10.-50',
when we'd expect '-10.50'. We now use the absolute value of all but the
first unit when building the decimal string.
  • Loading branch information
jparise committed Dec 9, 2022
1 parent 2117fd3 commit 81c5566
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 4 deletions.
17 changes: 13 additions & 4 deletions packages/core/src/api/toDecimal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NON_DECIMAL_CURRENCY_MESSAGE } from '../checks';
import { assert } from '../helpers';
import type { Calculator, Dinero, Formatter, Transformer } from '../types';
import { computeBase, equal, isArray } from '../utils';
import { absolute, computeBase, equal, isArray } from '../utils';

import { toUnits } from './toUnits';

Expand Down Expand Up @@ -33,7 +33,7 @@ export function toDecimal<TAmount, TOutput>(calculator: Calculator<TAmount>) {

const units = toUnitsFn(dineroObject);

const getDecimalFn = getDecimal(dineroObject.formatter);
const getDecimalFn = getDecimal(calculator, dineroObject.formatter);
const value = getDecimalFn(units, scale);

if (!transformer) {
Expand All @@ -44,12 +44,21 @@ export function toDecimal<TAmount, TOutput>(calculator: Calculator<TAmount>) {
};
}

function getDecimal<TAmount>(formatter: Formatter<TAmount>) {
function getDecimal<TAmount>(
calculator: Calculator<TAmount>,
formatter: Formatter<TAmount>
) {
const absoluteFn = absolute(calculator);

return (units: readonly TAmount[], scale: TAmount) => {
return units
.map((unit, index) => {
const isFirst = index === 0;
const isLast = units.length - 1 === index;
const unitAsString = formatter.toString(unit);

const unitAsString = formatter.toString(
isFirst ? unit : absoluteFn(unit)
);

if (isLast) {
return unitAsString.padStart(formatter.toNumber(scale), '0');
Expand Down
15 changes: 15 additions & 0 deletions packages/dinero.js/src/api/__tests__/toDecimal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toBe('5.00');
});
it('returns the negative amount in decimal format', () => {
const d = dinero({ amount: -1050, currency: USD });

expect(toDecimal(d)).toEqual('-10.50');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: 1050, currency: USD });

Expand Down Expand Up @@ -108,6 +113,11 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toBe('5.00');
});
it('returns the negative amount in decimal format', () => {
const d = dinero({ amount: -1050n, currency: bigintUSD });

expect(toDecimal(d)).toEqual('-10.50');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: 1050n, currency: bigintUSD });

Expand Down Expand Up @@ -183,6 +193,11 @@ describe('toDecimal', () => {

expect(toDecimal(d)).toBe('5.00');
});
it('returns the negative amount in decimal format', () => {
const d = dinero({ amount: new Big(-1005), currency: bigjsUSD });

expect(toDecimal(d)).toEqual('-10.05');
});
it('uses a custom transformer', () => {
const d = dinero({ amount: new Big(1050), currency: bigjsUSD });

Expand Down

1 comment on commit 81c5566

@vercel
Copy link

@vercel vercel bot commented on 81c5566 Dec 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

dinerojs – ./

dinerojs-git-main-dinerojs.vercel.app
v2.dinerojs.com
dinerojs-dinerojs.vercel.app

Please sign in to comment.