From 3170f2525a21aca5fe6f480a1ada54275bb909e5 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Mon, 19 Dec 2022 01:51:07 -0500 Subject: [PATCH] feat(formatters): add Currency Formatter and GroupTotalFormatter --- README.md | 2 +- packages/common/src/constants.ts | 4 +- .../__tests__/currencyFormatter.spec.ts | 158 +++++++++++++++++ .../src/formatters/currencyFormatter.ts | 32 ++++ .../formatters/dollarColoredBoldFormatter.ts | 2 +- .../src/formatters/dollarColoredFormatter.ts | 2 +- .../common/src/formatters/dollarFormatter.ts | 2 +- .../src/formatters/formatterUtilities.ts | 16 +- .../common/src/formatters/formatters.index.ts | 10 ++ .../avgTotalsCurrencyFormatters.spec.ts | 152 ++++++++++++++++ .../avgTotalsDollarFormatters.spec.ts | 22 +-- .../sumTotalsCurrencyColoredFormatter.spec.ts | 166 ++++++++++++++++++ .../sumTotalsCurrencyFormatter.spec.ts | 166 ++++++++++++++++++ .../sumTotalsDollarColoredFormatter.spec.ts | 54 +++--- .../sumTotalsDollarFormatter.spec.ts | 54 +++--- .../avgTotalsCurrencyFormatter.ts | 26 +++ .../avgTotalsDollarFormatter.ts | 2 +- .../groupingFormatters.index.ts | 23 +++ .../sumTotalsCurrencyColoredFormatter.ts | 27 +++ .../sumTotalsCurrencyFormatter.ts | 27 +++ .../sumTotalsDollarBoldFormatter.ts | 2 +- .../sumTotalsDollarColoredBoldFormatter.ts | 2 +- .../sumTotalsDollarColoredFormatter.ts | 2 +- .../sumTotalsDollarFormatter.ts | 2 +- packages/excel-export/src/excelUtils.spec.ts | 95 +++++++++- packages/excel-export/src/excelUtils.ts | 37 ++-- 26 files changed, 981 insertions(+), 106 deletions(-) create mode 100644 packages/common/src/formatters/__tests__/currencyFormatter.spec.ts create mode 100644 packages/common/src/formatters/currencyFormatter.ts create mode 100644 packages/common/src/grouping-formatters/__tests__/avgTotalsCurrencyFormatters.spec.ts create mode 100644 packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyColoredFormatter.spec.ts create mode 100644 packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyFormatter.spec.ts create mode 100644 packages/common/src/grouping-formatters/avgTotalsCurrencyFormatter.ts create mode 100644 packages/common/src/grouping-formatters/sumTotalsCurrencyColoredFormatter.ts create mode 100644 packages/common/src/grouping-formatters/sumTotalsCurrencyFormatter.ts diff --git a/README.md b/README.md index b4e8c7408..3629dfe7f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ The GitHub [live demo](https://ghiscoding.github.io/slickgrid-universal) shows 2 The Vanilla Implementation (which is not associated to any framework) was built with [WebPack](https://webpack.js.org/) and is also used to run and test all the UI functionalities [Cypress](https://www.cypress.io/) (E2E tests). The [Vanilla-force-bundle](https://github.com/ghiscoding/slickgrid-universal/tree/master/packages/vanilla-bundle), which extends the `vanilla-bundle` package is what we use in our SalesForce implementation (with Lightning Web Component), hence the creation of this monorepo library. ### Fully Tested with [Jest](https://jestjs.io/) (Unit Tests) - [Cypress](https://www.cypress.io/) (E2E Tests) -Slickgrid-Universal has **100%** Unit Test Coverage, we are talking about +15,000 lines of code (+3,700 unit tests) that are fully tested with [Jest](https://jestjs.io/). There are also +450 Cypress E2E tests to cover all [Examples](https://ghiscoding.github.io/slickgrid-universal/) and most UI functionalities (there's also an additional +500 tests in Angular/Aurelia-Slickgrid) +Slickgrid-Universal has **100%** Unit Test Coverage, we are talking about +15,000 lines of code (~4,000 unit tests) that are fully tested with [Jest](https://jestjs.io/). There are also +450 Cypress E2E tests to cover all [Examples](https://ghiscoding.github.io/slickgrid-universal/) and most UI functionalities (there's also an additional +500 tests in Angular/Aurelia-Slickgrid) ### Available Public Packages diff --git a/packages/common/src/constants.ts b/packages/common/src/constants.ts index 882013673..ed3516e20 100644 --- a/packages/common/src/constants.ts +++ b/packages/common/src/constants.ts @@ -80,8 +80,8 @@ export class Constants { }; static readonly DEFAULT_FORMATTER_NUMBER_MIN_DECIMAL = 2; static readonly DEFAULT_FORMATTER_NUMBER_MAX_DECIMAL = 2; - static readonly DEFAULT_FORMATTER_DOLLAR_MIN_DECIMAL = 2; - static readonly DEFAULT_FORMATTER_DOLLAR_MAX_DECIMAL = 4; + static readonly DEFAULT_FORMATTER_CURRENCY_MIN_DECIMAL = 2; + static readonly DEFAULT_FORMATTER_CURRENCY_MAX_DECIMAL = 4; static readonly DEFAULT_FORMATTER_PERCENT_MIN_DECIMAL = undefined; static readonly DEFAULT_FORMATTER_PERCENT_MAX_DECIMAL = undefined; static readonly DEFAULT_NUMBER_DECIMAL_SEPARATOR = '.'; diff --git a/packages/common/src/formatters/__tests__/currencyFormatter.spec.ts b/packages/common/src/formatters/__tests__/currencyFormatter.spec.ts new file mode 100644 index 000000000..60b9a061d --- /dev/null +++ b/packages/common/src/formatters/__tests__/currencyFormatter.spec.ts @@ -0,0 +1,158 @@ +import { Column, GridOption, SlickGrid } from '../../interfaces/index'; +import { currencyFormatter } from '../currencyFormatter'; + +describe('the Currency Formatter', () => { + const gridStub = { + getOptions: jest.fn() + } as unknown as SlickGrid; + + beforeEach(() => { + jest.spyOn(global.console, 'warn').mockReturnValue(); + }); + + it('should display an empty string when no value is provided', () => { + const output = currencyFormatter(1, 1, '', {} as Column, {}, {} as any); + expect(output).toBe(''); + }); + + it('should display original string when non-numeric value is provided', () => { + const output = currencyFormatter(1, 1, 'hello', {} as Column, {}, {} as any); + expect(output).toBe('hello'); + }); + + it('should display €0 when number 0 is provided', () => { + const input = 0; + const output = currencyFormatter(1, 1, input, {} as Column, {}, {} as any); + expect(output).toBe('0.00'); + }); + + it('should display a decimal number with negative when a negative number is provided', () => { + const input = -15; + const output = currencyFormatter(1, 1, input, {} as Column, {}, {} as any); + expect(output).toBe('-15.00'); + }); + + it('should display a decimal number with when a number is provided', () => { + const input = 99; + const output = currencyFormatter(1, 1, input, {} as Column, {}, {} as any); + expect(output).toBe('99.00'); + }); + + it('should display a decimal number with a prefix when numberPrefix is provided', () => { + const input = 99; + const output = currencyFormatter(1, 1, input, { params: { numberPrefix: 'USD ' } } as Column, {}, {} as any); + expect(output).toBe('USD 99.00'); + }); + + it('should display a negative decimal number with a prefix when numberPrefix is provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { currencyPrefix: '€' } } as Column, {}, {} as any); + expect(output).toBe('-€99.00'); + }); + + it('should display a negative decimal number with a prefix when numberPrefix is provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { numberPrefix: '€' } } as Column, {}, {} as any); + expect(output).toBe('€-99.00'); + }); + + it('should display a negative decimal number with a prefix when currencyPrefix and numberPrefix are provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { currencyPrefix: '€', numberPrefix: 'Price ' } } as Column, {}, {} as any); + expect(output).toBe('Price -€99.00'); + }); + + it('should display a negative decimal number with a prefix when numberPrefix is provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true, currencyPrefix: '€' } } as Column, {}, {} as any); + expect(output).toBe('(€99.00)'); + }); + + it('should display a negative decimal number with a prefix when numberPrefix is provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true, numberPrefix: '€' } } as Column, {}, {} as any); + expect(output).toBe('€(99.00)'); + }); + + it('should display a decimal number with a prefix when numberSuffix is provided', () => { + const input = 99; + const output = currencyFormatter(1, 1, input, { params: { numberSuffix: ' USD' } } as Column, {}, {} as any); + expect(output).toBe('99.00 USD'); + }); + + it('should display a decimal number with a prefix when numberSuffix is provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { numberSuffix: ' USD' } } as Column, {}, {} as any); + expect(output).toBe('-99.00 USD'); + }); + + it('should display a negative decimal number with a suffix when currencySuffix and numberSuffix are provided', () => { + const input = -99; + const output = currencyFormatter(1, 1, input, { params: { currencySuffix: '€', numberSuffix: ' EUR' } } as Column, {}, {} as any); + expect(output).toBe('-99.00€ EUR'); + }); + + it('should display a decimal number with when a string number is provided', () => { + const input = '99'; + const output = currencyFormatter(1, 1, input, {} as Column, {}, {} as any); + expect(output).toBe('99.00'); + }); + + it('should display a decimal number with and use "minDecimal" params', () => { + const input = 99.1; + const output = currencyFormatter(1, 1, input, { params: { minDecimal: 2 } } as Column, {}, {} as any); + expect(output).toBe('99.10'); + }); + + it('should display a decimal number with and use "minDecimal" params', () => { + const input = 12345678.1; + + const output1 = currencyFormatter(1, 1, input, { params: { minDecimal: 2 } } as Column, {}, {} as any); + const output2 = currencyFormatter(1, 1, input, { params: { decimalPlaces: 2 } } as Column, {}, {} as any); + const output3 = currencyFormatter(1, 1, input, { params: { decimalPlaces: 2, thousandSeparator: ',' } } as Column, {}, {} as any); + const output4 = currencyFormatter(1, 1, input, { params: { decimalPlaces: 2, decimalSeparator: ',', thousandSeparator: ' ' } } as Column, {}, {} as any); + + expect(output1).toBe('12345678.10'); + expect(output2).toBe('12345678.10'); + expect(output3).toBe('12,345,678.10'); + expect(output4).toBe('12 345 678,10'); + }); + + it('should display a decimal number with and use "maxDecimal" params', () => { + const input = 88.156789; + const output = currencyFormatter(1, 1, input, { params: { maxDecimal: 3 } } as Column, {}, {} as any); + expect(output).toBe(`88.157`); + }); + + it('should display a negative number with parentheses when "displayNegativeNumberWithParentheses" is enabled in the "params"', () => { + const input = -2.4; + const output = currencyFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true } } as Column, {}, {} as any); + expect(output).toBe(`(2.40)`); + }); + + it('should display a negative number with parentheses when "displayNegativeNumberWithParentheses" is enabled and thousand separator in the "params"', () => { + const input = -12345678.4; + const output = currencyFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}, {} as any); + expect(output).toBe(`(12,345,678.40)`); + }); + + it('should display a negative number with parentheses when "displayNegativeNumberWithParentheses" is enabled and thousand separator in the "params"', () => { + const input = -12345678.4; + const output = currencyFormatter(1, 1, input, { params: { currencyPrefix: '€', numberPrefix: 'Price ', currencySuffix: ' EUR', numberSuffix: ' /item', displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}, {} as any); + expect(output).toBe(`Price (€12,345,678.40 EUR) /item`); + }); + + it('should display a negative average with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => { + gridStub.getOptions = () => ({ formatterOptions: { displayNegativeNumberWithParentheses: true, minDecimal: 2 } } as GridOption); + const input = -2.4; + const output = currencyFormatter(1, 1, input, {} as Column, {}, gridStub); + expect(output).toBe(`(2.40)`); + }); + + it('should display a negative average with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled and thousand separator in the Formatter Options', () => { + gridStub.getOptions = () => ({ formatterOptions: { displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: ' ' } } as GridOption); + const input = -12345678.4; + const output = currencyFormatter(1, 1, input, {} as Column, {}, gridStub); + expect(output).toBe(`(12 345 678,40)`); + }); +}); diff --git a/packages/common/src/formatters/currencyFormatter.ts b/packages/common/src/formatters/currencyFormatter.ts new file mode 100644 index 000000000..dbf9a9f6c --- /dev/null +++ b/packages/common/src/formatters/currencyFormatter.ts @@ -0,0 +1,32 @@ +import { isNumber } from '@slickgrid-universal/utils'; + +import { Formatter } from '../interfaces/index'; +import { formatNumber } from '../services/utilities'; +import { retrieveFormatterOptions } from './formatterUtilities'; + +/** + * This Formatters allow the user to provide any currency symbol (as symbol prefix/suffix) and also provide extra text prefix/suffix. + * So with this, it allows the user to provide dual prefixes/suffixes via the following params + * You can pass "minDecimal", "maxDecimal", "decimalSeparator", "thousandSeparator", "numberPrefix", "currencyPrefix", "currencySuffix", and "numberSuffix" to the "params" property. + * For example:: `{ formatter: Formatters.decimal, params: { minDecimal: 2, maxDecimal: 4, prefix: 'Price ', currencyPrefix: '€', currencySuffix: ' EUR' }}` + * with value of 33.45 would result into: "Price €33.45 EUR" + */ +export const currencyFormatter: Formatter = (_row, _cell, value, columnDef, _dataContext, grid) => { + const { + currencyPrefix, + currencySuffix, + minDecimal, + maxDecimal, + numberPrefix, + numberSuffix, + decimalSeparator, + thousandSeparator, + wrapNegativeNumber, + } = retrieveFormatterOptions(columnDef, grid, 'decimal', 'cell'); + + if (isNumber(value)) { + const formattedNumber = formatNumber(value, minDecimal, maxDecimal, wrapNegativeNumber, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); + return `${numberPrefix}${formattedNumber}${numberSuffix}`; + } + return value; +}; diff --git a/packages/common/src/formatters/dollarColoredBoldFormatter.ts b/packages/common/src/formatters/dollarColoredBoldFormatter.ts index acf3ab90e..488094e79 100644 --- a/packages/common/src/formatters/dollarColoredBoldFormatter.ts +++ b/packages/common/src/formatters/dollarColoredBoldFormatter.ts @@ -12,7 +12,7 @@ export const dollarColoredBoldFormatter: Formatter = (_row, _cell, value, column decimalSeparator, thousandSeparator, wrapNegativeNumber, - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'cell'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'cell'); if (isNumber(value)) { const colorStyle = (value >= 0) ? 'green' : 'red'; diff --git a/packages/common/src/formatters/dollarColoredFormatter.ts b/packages/common/src/formatters/dollarColoredFormatter.ts index d18ff6523..ef5d9be41 100644 --- a/packages/common/src/formatters/dollarColoredFormatter.ts +++ b/packages/common/src/formatters/dollarColoredFormatter.ts @@ -12,7 +12,7 @@ export const dollarColoredFormatter: Formatter = (_row, _cell, value, columnDef, decimalSeparator, thousandSeparator, wrapNegativeNumber, - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'cell'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'cell'); if (isNumber(value)) { const colorStyle = (value >= 0) ? 'green' : 'red'; diff --git a/packages/common/src/formatters/dollarFormatter.ts b/packages/common/src/formatters/dollarFormatter.ts index 0b045d5d2..49ec99f7f 100644 --- a/packages/common/src/formatters/dollarFormatter.ts +++ b/packages/common/src/formatters/dollarFormatter.ts @@ -12,7 +12,7 @@ export const dollarFormatter: Formatter = (_row, _cell, value, columnDef, _dataC decimalSeparator, thousandSeparator, wrapNegativeNumber, - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'cell'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'cell'); if (isNumber(value)) { return formatNumber(value, minDecimal, maxDecimal, wrapNegativeNumber, '$', '', decimalSeparator, thousandSeparator); diff --git a/packages/common/src/formatters/formatterUtilities.ts b/packages/common/src/formatters/formatterUtilities.ts index c1b0bc990..b3bc2230c 100644 --- a/packages/common/src/formatters/formatterUtilities.ts +++ b/packages/common/src/formatters/formatterUtilities.ts @@ -8,7 +8,7 @@ import { Constants } from '../constants'; const moment = (moment_ as any)['default'] || moment_; // patch to fix rollup "moment has no default export" issue, document here https://github.com/rollup/rollup/issues/670 export type FormatterType = 'group' | 'cell'; -export type NumberType = 'decimal' | 'dollar' | 'percent' | 'regular'; +export type NumberType = 'decimal' | 'currency' | 'percent' | 'regular'; /** * Automatically add a Custom Formatter on all column definitions that have an Editor. @@ -44,14 +44,14 @@ export function retrieveFormatterOptions(columnDef: Column, grid: SlickGrid, num let numberSuffix = ''; switch (numberType) { + case 'currency': + defaultMinDecimal = Constants.DEFAULT_FORMATTER_CURRENCY_MIN_DECIMAL; + defaultMaxDecimal = Constants.DEFAULT_FORMATTER_CURRENCY_MAX_DECIMAL; + break; case 'decimal': defaultMinDecimal = Constants.DEFAULT_FORMATTER_NUMBER_MIN_DECIMAL; defaultMaxDecimal = Constants.DEFAULT_FORMATTER_NUMBER_MAX_DECIMAL; break; - case 'dollar': - defaultMinDecimal = Constants.DEFAULT_FORMATTER_DOLLAR_MIN_DECIMAL; - defaultMaxDecimal = Constants.DEFAULT_FORMATTER_DOLLAR_MAX_DECIMAL; - break; case 'percent': defaultMinDecimal = Constants.DEFAULT_FORMATTER_PERCENT_MIN_DECIMAL; defaultMaxDecimal = Constants.DEFAULT_FORMATTER_PERCENT_MAX_DECIMAL; @@ -64,13 +64,15 @@ export function retrieveFormatterOptions(columnDef: Column, grid: SlickGrid, num const decimalSeparator = getValueFromParamsOrFormatterOptions('decimalSeparator', columnDef, grid, Constants.DEFAULT_NUMBER_DECIMAL_SEPARATOR); const thousandSeparator = getValueFromParamsOrFormatterOptions('thousandSeparator', columnDef, grid, Constants.DEFAULT_NUMBER_THOUSAND_SEPARATOR); const wrapNegativeNumber = getValueFromParamsOrFormatterOptions('displayNegativeNumberWithParentheses', columnDef, grid, Constants.DEFAULT_NEGATIVE_NUMBER_WRAPPED_IN_BRAQUET); + const currencyPrefix = getValueFromParamsOrFormatterOptions('currencyPrefix', columnDef, grid, ''); + const currencySuffix = getValueFromParamsOrFormatterOptions('currencySuffix', columnDef, grid, ''); if (formatterType === 'cell') { numberPrefix = getValueFromParamsOrFormatterOptions('numberPrefix', columnDef, grid, ''); numberSuffix = getValueFromParamsOrFormatterOptions('numberSuffix', columnDef, grid, ''); } - return { minDecimal, maxDecimal, decimalSeparator, thousandSeparator, wrapNegativeNumber, numberPrefix, numberSuffix }; + return { minDecimal, maxDecimal, decimalSeparator, thousandSeparator, wrapNegativeNumber, currencyPrefix, currencySuffix, numberPrefix, numberSuffix }; } /** @@ -85,7 +87,7 @@ export function getValueFromParamsOrFormatterOptions(optionName: string, columnD if (params && params.hasOwnProperty(optionName)) { return params[optionName]; - } else if (gridOptions.formatterOptions?.hasOwnProperty(optionName)) { + } else if (gridOptions?.formatterOptions?.hasOwnProperty(optionName)) { return (gridOptions.formatterOptions as any)[optionName]; } return defaultValue; diff --git a/packages/common/src/formatters/formatters.index.ts b/packages/common/src/formatters/formatters.index.ts index 833782ce5..bd65e4c6a 100644 --- a/packages/common/src/formatters/formatters.index.ts +++ b/packages/common/src/formatters/formatters.index.ts @@ -8,6 +8,7 @@ import { centerFormatter } from './centerFormatter'; import { checkboxFormatter } from './checkboxFormatter'; import { checkmarkFormatter } from './checkmarkFormatter'; import { checkmarkMaterialFormatter } from './checkmarkMaterialFormatter'; +import { currencyFormatter } from './currencyFormatter'; import { collectionFormatter } from './collectionFormatter'; import { collectionEditorFormatter } from './collectionEditorFormatter'; import { complexObjectFormatter } from './complexObjectFormatter'; @@ -112,6 +113,15 @@ export const Formatters = { */ collectionEditor: collectionEditorFormatter, + /** + * Similar to "Formatters.decimal", but it allows you to provide prefixes and suffixes (currencyPrefix, currencySuffix, numberPrefix, numberSuffix) + * So with this, it allows the user to provide dual prefixes/suffixes via the following params + * You can pass "minDecimal", "maxDecimal", "decimalSeparator", "thousandSeparator", "numberPrefix", "currencyPrefix", "currencySuffix", and "numberSuffix" to the "params" property. + * For example:: `{ formatter: Formatters.decimal, params: { minDecimal: 2, maxDecimal: 4, prefix: 'Price ', currencyPrefix: '€', currencySuffix: ' EUR' }}` + * with value of 33.45 would result into: "Price €33.45 EUR" + */ + currency: currencyFormatter, + /** Takes a Date object and displays it as an ISO Date format (YYYY-MM-DD) */ dateIso: getAssociatedDateFormatter(FieldType.dateIso, '-'), diff --git a/packages/common/src/grouping-formatters/__tests__/avgTotalsCurrencyFormatters.spec.ts b/packages/common/src/grouping-formatters/__tests__/avgTotalsCurrencyFormatters.spec.ts new file mode 100644 index 000000000..7b97253e8 --- /dev/null +++ b/packages/common/src/grouping-formatters/__tests__/avgTotalsCurrencyFormatters.spec.ts @@ -0,0 +1,152 @@ +import { Column, GridOption, SlickGrid } from '../../interfaces/index'; +import { avgTotalsCurrencyFormatter } from '../avgTotalsCurrencyFormatter'; + +describe('avgTotalsCurrencyFormatter', () => { + // stub some methods of the SlickGrid Grid instance + const gridStub = { + getOptions: jest.fn() + } as unknown as SlickGrid; + + it('should display an empty string when no value is provided', () => { + const output = avgTotalsCurrencyFormatter({}, {} as Column, gridStub); + expect(output).toBe(''); + }); + + it('should display an empty string when the "avg" does not find the field property in its object', () => { + const columnDef = { id: 'column3', field: 'column3' } as Column; + const totals = { avg: { column1: 123, column2: 345 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the average number is null', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { avg: { column1: null } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the average input is not a number', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { avg: { column1: 'abc' } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display a negative average with Currency sign when its input is negative', () => { + const columnDef = { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€' } } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -2.45 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe('-€2.45'); + }); + + it('should display a negative average with Currency sign and thousand separator when its input is negative', () => { + const columnDef = { id: 'column3', field: 'column3', params: { thousandSeparator: ',', groupFormatterCurrencyPrefix: '€' } } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -12345678.45 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe('-€12,345,678.45'); + }); + + it('should display a negative average with Currency sign, comma as decimal separator and underscore as thousand separator when its input is negative', () => { + const columnDef = { id: 'column3', field: 'column3', params: { decimalSeparator: ',', thousandSeparator: '_', groupFormatterCurrencyPrefix: '€' } } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -12345678.45 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe('-€12_345_678,45'); + }); + + it('should display a negative average with parentheses instead of the negative sign with Currency sign when its input is negative', () => { + const columnDef = { id: 'column3', field: 'column3', params: { displayNegativeNumberWithParentheses: true } } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -2.4 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe('(2.40)'); + }); + + it('should display a negative average with parentheses instead of the negative sign with Currency sign and thousand separator when its input is negative', () => { + const columnDef = { id: 'column3', field: 'column3', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -12345678.4 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe('(12,345,678.40)'); + }); + + it('should display a negative average with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { displayNegativeNumberWithParentheses: true } } as GridOption); + const columnDef = { id: 'column3', field: 'column3' } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -2.4 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, gridStub); + expect(output).toBe('(2.40)'); + }); + + it('should display a negative average with parentheses and thousand separator when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as GridOption); + const columnDef = { id: 'column3', field: 'column3' } as Column; + const totals = { avg: { column1: 123, column2: 345, column3: -12345678.4 } }; + const output = avgTotalsCurrencyFormatter(totals, columnDef, gridStub); + expect(output).toBe('(12,345,678.40)'); + }); + + it('should display an average number with at least 2 decimals but no more than 4 by default, and Currency sign when a positive number is provided', () => { + const totals = { avg: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = avgTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = avgTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€' } } as Column, {} as SlickGrid); + + expect(output1).toBe('123.4568'); + expect(output2).toBe('€345.20'); + }); + + it('should display an average number with user defined minimum & maximum decimal count', () => { + const totals = { avg: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = avgTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2 } } as Column, {} as SlickGrid); + const output2 = avgTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterCurrencyPrefix: '€', } } as Column, {} as SlickGrid); + const output3 = avgTotalsCurrencyFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('123.46'); + expect(output2).toBe('€345.2'); + expect(output3).toBe('(€2.450)'); + }); + + it('should display an average number with user defined minimum & maximum decimal count in his grid option', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { minDecimal: 0, maxDecimal: 3, displayNegativeNumberWithParentheses: true } } as GridOption); + const totals = { avg: { column1: 123.45678, column2: 345, column3: -2.45 } }; + const output1 = avgTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencySuffix: '€' } } as Column, gridStub); + const output2 = avgTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€' } } as Column, gridStub); + const output3 = avgTotalsCurrencyFormatter(totals, { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'Avg: ' } } as Column, gridStub); + + expect(output1).toBe('123.457€'); + expect(output2).toBe('€345'); + expect(output3).toBe('Avg: (€2.45)'); + }); + + it('should display an average number with prefix and suffix', () => { + const totals = { avg: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = avgTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'Avg: ' } } as Column, {} as SlickGrid); + const output2 = avgTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterCurrencyPrefix: '€', groupFormatterSuffix: ' (avg)' } } as Column, {} as SlickGrid); + const output3 = avgTotalsCurrencyFormatter( + totals, { + id: 'column3', field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'Avg: ', groupFormatterSuffix: '/item' } + } as Column, {} as SlickGrid); + + expect(output1).toBe('Avg: €123.46'); + expect(output2).toBe('€345.2 (avg)'); + expect(output3).toBe('Avg: (€2.450)/item'); + }); + + it('should display an average number with prefix, suffix and thousand separator', () => { + const totals = { avg: { column1: 12345678.45678, column2: 345678.2, column3: -345678.45 } }; + + const output1 = avgTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Avg: ', groupFormatterCurrencyPrefix: '€', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output2 = avgTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (avg)', groupFormatterCurrencyPrefix: '€', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output3 = avgTotalsCurrencyFormatter( + totals, { + id: 'column3', field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Avg: ', groupFormatterCurrencyPrefix: '€', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } + } as Column, {} as SlickGrid); + + expect(output1).toBe('Avg: €12_345_678,46'); + expect(output2).toBe('€345_678,2 (avg)'); + expect(output3).toBe('Avg: (€345_678,450)/item'); + }); +}); diff --git a/packages/common/src/grouping-formatters/__tests__/avgTotalsDollarFormatters.spec.ts b/packages/common/src/grouping-formatters/__tests__/avgTotalsDollarFormatters.spec.ts index 8b63c8be3..484465a51 100644 --- a/packages/common/src/grouping-formatters/__tests__/avgTotalsDollarFormatters.spec.ts +++ b/packages/common/src/grouping-formatters/__tests__/avgTotalsDollarFormatters.spec.ts @@ -8,63 +8,63 @@ describe('avgTotalsDollarFormatter', () => { } as unknown as SlickGrid; it('should display an empty string when no value is provided', () => { - const output = avgTotalsDollarFormatter({}, {} as Column); + const output = avgTotalsDollarFormatter({}, {} as Column, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the "avg" does not find the field property in its object', () => { const columnDef = { id: 'column3', field: 'column3' } as Column; const totals = { avg: { column1: 123, column2: 345 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the average number is null', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { avg: { column1: null } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the average input is not a number', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { avg: { column1: 'abc' } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display a negative average with dollar sign when its input is negative', () => { const columnDef = { id: 'column3', field: 'column3' } as Column; const totals = { avg: { column1: 123, column2: 345, column3: -2.45 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe('-$2.45'); }); it('should display a negative average with dollar sign and thousand separator when its input is negative', () => { const columnDef = { id: 'column3', field: 'column3', params: { thousandSeparator: ',' } } as Column; const totals = { avg: { column1: 123, column2: 345, column3: -12345678.45 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe('-$12,345,678.45'); }); it('should display a negative average with dollar sign, comma as decimal separator and underscore as thousand separator when its input is negative', () => { const columnDef = { id: 'column3', field: 'column3', params: { decimalSeparator: ',', thousandSeparator: '_' } } as Column; const totals = { avg: { column1: 123, column2: 345, column3: -12345678.45 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe('-$12_345_678,45'); }); it('should display a negative average with parentheses instead of the negative sign with dollar sign when its input is negative', () => { const columnDef = { id: 'column3', field: 'column3', params: { displayNegativeNumberWithParentheses: true } } as Column; const totals = { avg: { column1: 123, column2: 345, column3: -2.4 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe('($2.40)'); }); it('should display a negative average with parentheses instead of the negative sign with dollar sign and thousand separator when its input is negative', () => { const columnDef = { id: 'column3', field: 'column3', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column; const totals = { avg: { column1: 123, column2: 345, column3: -12345678.4 } }; - const output = avgTotalsDollarFormatter(totals, columnDef, {}); + const output = avgTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe('($12,345,678.40)'); }); @@ -128,7 +128,7 @@ describe('avgTotalsDollarFormatter', () => { totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Avg: ', groupFormatterSuffix: '/item' } - } as Column); + } as Column, {} as SlickGrid); expect(output1).toBe('Avg: $123.46'); expect(output2).toBe('$345.2 (avg)'); @@ -144,7 +144,7 @@ describe('avgTotalsDollarFormatter', () => { totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Avg: ', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } - } as Column); + } as Column, {} as SlickGrid); expect(output1).toBe('Avg: $12_345_678,46'); expect(output2).toBe('$345_678,2 (avg)'); diff --git a/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyColoredFormatter.spec.ts b/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyColoredFormatter.spec.ts new file mode 100644 index 000000000..31e58e32c --- /dev/null +++ b/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyColoredFormatter.spec.ts @@ -0,0 +1,166 @@ +import { Column, GridOption, SlickGrid } from '../../interfaces/index'; +import { sumTotalsCurrencyColoredFormatter } from '../sumTotalsCurrencyColoredFormatter'; + +describe('sumTotalsCurrencyColoredFormatter', () => { + // stub some methods of the SlickGrid Grid instance + const gridStub = { + getOptions: jest.fn() + } as unknown as SlickGrid; + + it('should display an empty string when no value is provided', () => { + const output = sumTotalsCurrencyColoredFormatter({}, {} as Column, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the "sum" does not find the field property in its object', () => { + const columnDef = { id: 'column3', field: 'column3' } as Column; + const totals = { sum: { column1: 123, column2: 345 } }; + const output = sumTotalsCurrencyColoredFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the sum property is null', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { sum: { column1: null } }; + const output = sumTotalsCurrencyColoredFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the average input is not a number', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { sum: { column1: 'abc' } }; + const output = sumTotalsCurrencyColoredFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display a negative sum with at least 2 decimals in red when its input is negative', () => { + const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2 } } as Column, {} as SlickGrid); + + expect(output1).toBe('-123.00'); + expect(output2).toBe('-€34.57'); + }); + + it('should display a negative sum in red and thousand separator when its input is negative', () => { + const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + + expect(output1).toBe('-€12,345,678.00'); + expect(output2).toBe('-€345,678.57'); + expect(output3).toBe('-€345_678,57'); + }); + + it('should display a negative sum in red with parentheses instead of the negative sign when its input is negative', () => { + const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('(€123.00)'); + expect(output2).toBe('(€34.57)'); + }); + + it('should display a negative sum in red with thousand separator and parentheses instead of the negative sign when its input is negative', () => { + const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + + expect(output1).toBe('(€12,345,678.00)'); + expect(output2).toBe('(345,678.57)'); + expect(output3).toBe('(€345_678,57)'); + }); + + it('should display a negative sum with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { displayNegativeNumberWithParentheses: true } } as GridOption); + const columnDef = { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€' } } as Column; + const totals = { sum: { column1: 123, column2: 345, column3: -2.4 } }; + const output = sumTotalsCurrencyColoredFormatter(totals, columnDef, gridStub); + expect(output).toBe('(€2.40)'); + }); + + it('should display a positive sum number with at least 2 decimals, even when displayNegativeNumberWithParentheses is enabled', () => { + const totals = { sum: { column1: 123, column2: 34.5678, column3: 2.4 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('€123.00'); + expect(output2).toBe('€34.57'); + }); + + it('should display the same sum value in green with at least 2 decimals when a number with decimals is provided', () => { + const totals = { sum: { column1: 123.55678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€' } } as Column, {} as SlickGrid); + + expect(output1).toBe('123.5568'); + expect(output2).toBe('€345.20'); + }); + + it('should display an sum number with user defined minimum & maximum decimal count in his grid option', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { minDecimal: 0, maxDecimal: 3, displayNegativeNumberWithParentheses: true } } as GridOption); + const totals = { sum: { column1: 123.45678, column2: 345, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€' } } as Column, gridStub); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2' } as Column, gridStub); + const output3 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€' } } as Column, gridStub); + + expect(output1).toBe('€123.457'); + expect(output2).toBe('345'); + expect(output3).toBe('(€2.45)'); + }); + + it('should display a sum number in correct color with at least 2 decimals when user provided minimum & maximum decimal count', () => { + const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2 } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€', minDecimal: 3, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('€123.46'); + expect(output2).toBe('345.2'); + expect(output3).toBe('(€2.450)'); + }); + + it('should display a sum number with at least 2 decimals with prefix and suffix', () => { + const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, groupFormatterPrefix: 'sum: ' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', minDecimal: 0, groupFormatterSuffix: ' (max)' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyColoredFormatter( + totals, { + id: 'column3', + field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'sum: ', groupFormatterSuffix: '/item' } + } as Column, {} as SlickGrid + ); + + expect(output1).toBe('sum: €123.46'); + expect(output2).toBe('€345.2 (max)'); + expect(output3).toBe('sum: (€2.450)/item'); + }); + + it('should display a sum number with prefix, suffix and thousand separator', () => { + const totals = { sum: { column1: 12345678.45678, column2: 345678.2, column3: -345678.45 } }; + + const output1 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'Sum: ', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterCurrencyPrefix: '€', groupFormatterSuffix: ' (sum)', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyColoredFormatter( + totals, { + id: 'column3', field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Sum: ', groupFormatterCurrencyPrefix: '€', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } + } as Column, {} as SlickGrid); + + expect(output1).toBe('Sum: €12_345_678,46'); + expect(output2).toBe('€345_678,2 (sum)'); + expect(output3).toBe('Sum: (€345_678,450)/item'); + }); +}); diff --git a/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyFormatter.spec.ts b/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyFormatter.spec.ts new file mode 100644 index 000000000..2a2eca1c6 --- /dev/null +++ b/packages/common/src/grouping-formatters/__tests__/sumTotalsCurrencyFormatter.spec.ts @@ -0,0 +1,166 @@ +import { Column, GridOption, SlickGrid } from '../../interfaces/index'; +import { sumTotalsCurrencyFormatter } from '../sumTotalsCurrencyFormatter'; + +describe('sumTotalsCurrencyFormatter', () => { + // stub some methods of the SlickGrid Grid instance + const gridStub = { + getOptions: jest.fn() + } as unknown as SlickGrid; + + it('should display an empty string when no value is provided', () => { + const output = sumTotalsCurrencyFormatter({}, {} as Column, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the "sum" does not find the field property in its object', () => { + const columnDef = { id: 'column3', field: 'column3' } as Column; + const totals = { sum: { column1: 123, column2: 345 } }; + const output = sumTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the sum property is null', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { sum: { column1: null } }; + const output = sumTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display an empty string when the average input is not a number', () => { + const columnDef = { id: 'column1', field: 'column1' } as Column; + const totals = { sum: { column1: 'abc' } }; + const output = sumTotalsCurrencyFormatter(totals, columnDef, {} as SlickGrid); + expect(output).toBe(''); + }); + + it('should display a negative sum with at least 2 decimals in red when its input is negative', () => { + const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2 } } as Column, {} as SlickGrid); + + expect(output1).toBe('-123.00'); + expect(output2).toBe('-€34.57'); + }); + + it('should display a negative sum with at least 2 decimals and thousand separator when its input is negative', () => { + const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + + expect(output1).toBe('-€12,345,678.00'); + expect(output2).toBe('-€345,678.57'); + expect(output3).toBe('-€345_678,57'); + }); + + it('should display a negative sum in red with at least 2 decimals with parentheses instead of the negative sign when its input is negative', () => { + const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { groupFormatterCurrencyPrefix: '€', maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('(€123.00)'); + expect(output2).toBe('(€34.57)'); + }); + + it('should display a negative sum with thousand separator and parentheses instead of the negative sign when its input is negative', () => { + const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + + expect(output1).toBe('(€12,345,678.00)'); + expect(output2).toBe('(€345,678.57)'); + expect(output3).toBe('(€345_678,57)'); + }); + + it('should display a negative sum with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { displayNegativeNumberWithParentheses: true } } as GridOption); + const columnDef = { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€' } } as Column; + const totals = { sum: { column1: 123, column2: 345, column3: -2.4 } }; + const output = sumTotalsCurrencyFormatter(totals, columnDef, gridStub); + expect(output).toBe('(€2.40)'); + }); + + it('should display a positive sum number with at least 2 decimals, even when displayNegativeNumberWithParentheses is enabled', () => { + const totals = { sum: { column1: 123, column2: 34.5678, column3: 2.4 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('€123.00'); + expect(output2).toBe('34.57'); + }); + + it('should display the same sum value in green with at least 2 decimals when a number with decimals is provided', () => { + const totals = { sum: { column1: 123.55678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2' } as Column, {} as SlickGrid); + + expect(output1).toBe('€123.5568'); + expect(output2).toBe('345.20'); + }); + + it('should display an sum number with user defined minimum & maximum decimal count in his grid option', () => { + (gridStub.getOptions as jest.Mock).mockReturnValue({ formatterOptions: { minDecimal: 0, maxDecimal: 3, displayNegativeNumberWithParentheses: true } } as GridOption); + const totals = { sum: { column1: 123.45678, column2: 345, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { groupFormatterCurrencyPrefix: '€' } } as Column, gridStub); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2' } as Column, gridStub); + const output3 = sumTotalsCurrencyFormatter(totals, { id: 'column3', field: 'column3', params: { groupFormatterCurrencyPrefix: '€' } } as Column, gridStub); + + expect(output1).toBe('€123.457'); + expect(output2).toBe('345'); + expect(output3).toBe('(€2.45)'); + }); + + it('should display a sum number in correct color with at least 2 decimals when user provided minimum & maximum decimal count', () => { + const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, groupFormatterCurrencyPrefix: '€', displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + + expect(output1).toBe('€123.46'); + expect(output2).toBe('345.2'); + expect(output3).toBe('(€2.450)'); + }); + + it('should display a sum number with at least 2 decimals with prefix and suffix', () => { + const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'sum: ' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterCurrencyPrefix: '€', groupFormatterSuffix: ' (max)' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyFormatter( + totals, { + id: 'column3', + field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'sum: ', groupFormatterSuffix: '/item' } + } as Column, {} as SlickGrid + ); + + expect(output1).toBe('sum: €123.46'); + expect(output2).toBe('€345.2 (max)'); + expect(output3).toBe('sum: (€2.450)/item'); + }); + + it('should display a sum number with prefix, suffix and thousand separator', () => { + const totals = { sum: { column1: 12345678.45678, column2: 345678.2, column3: -345678.45 } }; + + const output1 = sumTotalsCurrencyFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Sum: ', groupFormatterCurrencyPrefix: '€', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output2 = sumTotalsCurrencyFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (sum)', groupFormatterCurrencyPrefix: '€', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output3 = sumTotalsCurrencyFormatter( + totals, { + id: 'column3', field: 'column3', + params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterCurrencyPrefix: '€', groupFormatterPrefix: 'Sum: ', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } + } as Column, {} as SlickGrid); + + expect(output1).toBe('Sum: €12_345_678,46'); + expect(output2).toBe('€345_678,2 (sum)'); + expect(output3).toBe('Sum: (€345_678,450)/item'); + }); +}); diff --git a/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarColoredFormatter.spec.ts b/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarColoredFormatter.spec.ts index b8aeffaa3..78056dfe4 100644 --- a/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarColoredFormatter.spec.ts +++ b/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarColoredFormatter.spec.ts @@ -8,36 +8,36 @@ describe('sumTotalsDollarColoredFormatter', () => { } as unknown as SlickGrid; it('should display an empty string when no value is provided', () => { - const output = sumTotalsDollarColoredFormatter({}, {} as Column); + const output = sumTotalsDollarColoredFormatter({}, {} as Column, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the "sum" does not find the field property in its object', () => { const columnDef = { id: 'column3', field: 'column3' } as Column; const totals = { sum: { column1: 123, column2: 345 } }; - const output = sumTotalsDollarColoredFormatter(totals, columnDef, {}); + const output = sumTotalsDollarColoredFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the sum property is null', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { sum: { column1: null } }; - const output = sumTotalsDollarColoredFormatter(totals, columnDef, {}); + const output = sumTotalsDollarColoredFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the average input is not a number', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { sum: { column1: 'abc' } }; - const output = sumTotalsDollarColoredFormatter(totals, columnDef, {}); + const output = sumTotalsDollarColoredFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display a negative sum with at least 2 decimals in red when its input is negative', () => { const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2 } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2 } } as Column, {} as SlickGrid); expect(output1).toBe('-$123.00'); expect(output2).toBe('-$34.57'); @@ -46,9 +46,9 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a negative sum in red and thousand separator when its input is negative', () => { const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { thousandSeparator: ',' } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, thousandSeparator: ',' } } as Column, {}); - const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); expect(output1).toBe('-$12,345,678.00'); expect(output2).toBe('-$345,678.57'); @@ -58,8 +58,8 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a negative sum in red with parentheses instead of the negative sign when its input is negative', () => { const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('($123.00)'); expect(output2).toBe('($34.57)'); @@ -68,9 +68,9 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a negative sum in red with thousand separator and parentheses instead of the negative sign when its input is negative', () => { const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}); - const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); expect(output1).toBe('($12,345,678.00)'); expect(output2).toBe('($345,678.57)'); @@ -88,8 +88,8 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a positive sum number with at least 2 decimals, even when displayNegativeNumberWithParentheses is enabled', () => { const totals = { sum: { column1: 123, column2: 34.5678, column3: 2.4 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('$123.00'); expect(output2).toBe('$34.57'); @@ -98,8 +98,8 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display the same sum value in green with at least 2 decimals when a number with decimals is provided', () => { const totals = { sum: { column1: 123.55678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2' } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2' } as Column, {} as SlickGrid); expect(output1).toBe('$123.5568'); expect(output2).toBe('$345.20'); @@ -121,9 +121,9 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a sum number in correct color with at least 2 decimals when user provided minimum & maximum decimal count', () => { const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2 } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {}); - const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2 } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarColoredFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('$123.46'); expect(output2).toBe('$345.2'); @@ -133,14 +133,14 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a sum number with at least 2 decimals with prefix and suffix', () => { const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'sum: ' } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (max)' } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'sum: ' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (max)' } } as Column, {} as SlickGrid); const output3 = sumTotalsDollarColoredFormatter( totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'sum: ', groupFormatterSuffix: '/item' } - } as Column + } as Column, {} as SlickGrid ); expect(output1).toBe('sum: $123.46'); @@ -151,13 +151,13 @@ describe('sumTotalsDollarColoredFormatter', () => { it('should display a sum number with prefix, suffix and thousand separator', () => { const totals = { sum: { column1: 12345678.45678, column2: 345678.2, column3: -345678.45 } }; - const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Sum: ', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); - const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (sum)', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarColoredFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Sum: ', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarColoredFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (sum)', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); const output3 = sumTotalsDollarColoredFormatter( totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Sum: ', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } - } as Column); + } as Column, {} as SlickGrid); expect(output1).toBe('Sum: $12_345_678,46'); expect(output2).toBe('$345_678,2 (sum)'); diff --git a/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarFormatter.spec.ts b/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarFormatter.spec.ts index 43ff35892..2e1a153a5 100644 --- a/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarFormatter.spec.ts +++ b/packages/common/src/grouping-formatters/__tests__/sumTotalsDollarFormatter.spec.ts @@ -8,36 +8,36 @@ describe('sumTotalsDollarFormatter', () => { } as unknown as SlickGrid; it('should display an empty string when no value is provided', () => { - const output = sumTotalsDollarFormatter({}, {} as Column); + const output = sumTotalsDollarFormatter({}, {} as Column, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the "sum" does not find the field property in its object', () => { const columnDef = { id: 'column3', field: 'column3' } as Column; const totals = { sum: { column1: 123, column2: 345 } }; - const output = sumTotalsDollarFormatter(totals, columnDef, {}); + const output = sumTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the sum property is null', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { sum: { column1: null } }; - const output = sumTotalsDollarFormatter(totals, columnDef, {}); + const output = sumTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display an empty string when the average input is not a number', () => { const columnDef = { id: 'column1', field: 'column1' } as Column; const totals = { sum: { column1: 'abc' } }; - const output = sumTotalsDollarFormatter(totals, columnDef, {}); + const output = sumTotalsDollarFormatter(totals, columnDef, {} as SlickGrid); expect(output).toBe(''); }); it('should display a negative sum with at least 2 decimals in red when its input is negative', () => { const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1' } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2 } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2 } } as Column, {} as SlickGrid); expect(output1).toBe('-$123.00'); expect(output2).toBe('-$34.57'); @@ -46,9 +46,9 @@ describe('sumTotalsDollarFormatter', () => { it('should display a negative sum with at least 2 decimals and thousand separator when its input is negative', () => { const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { thousandSeparator: ',' } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, thousandSeparator: ',' } } as Column, {}); - const output3 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); expect(output1).toBe('-$12,345,678.00'); expect(output2).toBe('-$345,678.57'); @@ -58,8 +58,8 @@ describe('sumTotalsDollarFormatter', () => { it('should display a negative sum in red with at least 2 decimals with parentheses instead of the negative sign when its input is negative', () => { const totals = { sum: { column1: -123, column2: -34.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('($123.00)'); expect(output2).toBe('($34.57)'); @@ -68,9 +68,9 @@ describe('sumTotalsDollarFormatter', () => { it('should display a negative sum with thousand separator and parentheses instead of the negative sign when its input is negative', () => { const totals = { sum: { column1: -12345678, column2: -345678.5678, column3: -2.4 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {}); - const output3 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true, decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); expect(output1).toBe('($12,345,678.00)'); expect(output2).toBe('($345,678.57)'); @@ -88,8 +88,8 @@ describe('sumTotalsDollarFormatter', () => { it('should display a positive sum number with at least 2 decimals, even when displayNegativeNumberWithParentheses is enabled', () => { const totals = { sum: { column1: 123, column2: 34.5678, column3: 2.4 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { maxDecimal: 2, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('$123.00'); expect(output2).toBe('$34.57'); @@ -98,8 +98,8 @@ describe('sumTotalsDollarFormatter', () => { it('should display the same sum value in green with at least 2 decimals when a number with decimals is provided', () => { const totals = { sum: { column1: 123.55678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1' } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2' } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1' } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2' } as Column, {} as SlickGrid); expect(output1).toBe('$123.5568'); expect(output2).toBe('$345.20'); @@ -121,9 +121,9 @@ describe('sumTotalsDollarFormatter', () => { it('should display a sum number in correct color with at least 2 decimals when user provided minimum & maximum decimal count', () => { const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2 } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {}); - const output3 = sumTotalsDollarFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2 } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0 } } as Column, {} as SlickGrid); + const output3 = sumTotalsDollarFormatter(totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true } } as Column, {} as SlickGrid); expect(output1).toBe('$123.46'); expect(output2).toBe('$345.2'); @@ -133,14 +133,14 @@ describe('sumTotalsDollarFormatter', () => { it('should display a sum number with at least 2 decimals with prefix and suffix', () => { const totals = { sum: { column1: 123.45678, column2: 345.2, column3: -2.45 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'sum: ' } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (max)' } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'sum: ' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (max)' } } as Column, {} as SlickGrid); const output3 = sumTotalsDollarFormatter( totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'sum: ', groupFormatterSuffix: '/item' } - } as Column + } as Column, {} as SlickGrid ); expect(output1).toBe('sum: $123.46'); @@ -151,13 +151,13 @@ describe('sumTotalsDollarFormatter', () => { it('should display a sum number with prefix, suffix and thousand separator', () => { const totals = { sum: { column1: 12345678.45678, column2: 345678.2, column3: -345678.45 } }; - const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Sum: ', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); - const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (sum)', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {}); + const output1 = sumTotalsDollarFormatter(totals, { id: 'column1', field: 'column1', params: { maxDecimal: 2, groupFormatterPrefix: 'Sum: ', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); + const output2 = sumTotalsDollarFormatter(totals, { id: 'column2', field: 'column2', params: { minDecimal: 0, groupFormatterSuffix: ' (sum)', decimalSeparator: ',', thousandSeparator: '_' } } as Column, {} as SlickGrid); const output3 = sumTotalsDollarFormatter( totals, { id: 'column3', field: 'column3', params: { minDecimal: 3, displayNegativeNumberWithParentheses: true, groupFormatterPrefix: 'Sum: ', groupFormatterSuffix: '/item', decimalSeparator: ',', thousandSeparator: '_' } - } as Column); + } as Column, {} as SlickGrid); expect(output1).toBe('Sum: $12_345_678,46'); expect(output2).toBe('$345_678,2 (sum)'); diff --git a/packages/common/src/grouping-formatters/avgTotalsCurrencyFormatter.ts b/packages/common/src/grouping-formatters/avgTotalsCurrencyFormatter.ts new file mode 100644 index 000000000..51dd96d7d --- /dev/null +++ b/packages/common/src/grouping-formatters/avgTotalsCurrencyFormatter.ts @@ -0,0 +1,26 @@ +import { Column, GroupTotalsFormatter, SlickGrid } from '../interfaces/index'; +import { retrieveFormatterOptions } from '../formatters/formatterUtilities'; +import { formatNumber } from '../services/utilities'; + +export const avgTotalsCurrencyFormatter: GroupTotalsFormatter = (totals: any, columnDef: Column, grid: SlickGrid) => { + const field = columnDef.field ?? ''; + const val = totals.avg?.[field]; + const params = columnDef?.params; + const prefix = params?.groupFormatterPrefix || ''; + const suffix = params?.groupFormatterSuffix || ''; + const currencyPrefix = params?.groupFormatterCurrencyPrefix || ''; + const currencySuffix = params?.groupFormatterCurrencySuffix || ''; + const { + minDecimal, + maxDecimal, + decimalSeparator, + thousandSeparator, + wrapNegativeNumber + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); + + if (val !== null && !isNaN(+val)) { + const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); + return `${prefix}${formattedNumber}${suffix}`; + } + return ''; +}; diff --git a/packages/common/src/grouping-formatters/avgTotalsDollarFormatter.ts b/packages/common/src/grouping-formatters/avgTotalsDollarFormatter.ts index 3e5cf6798..cc696d1f6 100644 --- a/packages/common/src/grouping-formatters/avgTotalsDollarFormatter.ts +++ b/packages/common/src/grouping-formatters/avgTotalsDollarFormatter.ts @@ -14,7 +14,7 @@ export const avgTotalsDollarFormatter: GroupTotalsFormatter = (totals: any, colu decimalSeparator, thousandSeparator, wrapNegativeNumber - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'group'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); if (val !== null && !isNaN(+val)) { const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, '$', '', decimalSeparator, thousandSeparator); diff --git a/packages/common/src/grouping-formatters/groupingFormatters.index.ts b/packages/common/src/grouping-formatters/groupingFormatters.index.ts index f5bb03826..87bb397ef 100644 --- a/packages/common/src/grouping-formatters/groupingFormatters.index.ts +++ b/packages/common/src/grouping-formatters/groupingFormatters.index.ts @@ -1,9 +1,12 @@ import { avgTotalsPercentageFormatter } from './avgTotalsPercentageFormatter'; import { avgTotalsDollarFormatter } from './avgTotalsDollarFormatter'; +import { avgTotalsCurrencyFormatter } from './avgTotalsCurrencyFormatter'; import { avgTotalsFormatter } from './avgTotalsFormatter'; import { minTotalsFormatter } from './minTotalsFormatter'; import { maxTotalsFormatter } from './maxTotalsFormatter'; import { sumTotalsColoredFormatter } from './sumTotalsColoredFormatter'; +import { sumTotalsCurrencyFormatter } from './sumTotalsCurrencyFormatter'; +import { sumTotalsCurrencyColoredFormatter } from './sumTotalsCurrencyColoredFormatter'; import { sumTotalsDollarColoredBoldFormatter } from './sumTotalsDollarColoredBoldFormatter'; import { sumTotalsDollarColoredFormatter } from './sumTotalsDollarColoredFormatter'; import { sumTotalsDollarBoldFormatter } from './sumTotalsDollarBoldFormatter'; @@ -19,6 +22,12 @@ export const GroupTotalFormatters = { */ avgTotals: avgTotalsFormatter, + /** + * Average all the column totals and display currency prefix/suffix via "groupFormatterCurrencyPrefix" and/or "groupFormatterCurrencySuffix" + * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: 'Total: ', groupFormatterSuffix: '$' } + */ + avgTotalsCurrency: avgTotalsCurrencyFormatter, + /** * Average all the column totals and display '$' at the end of the value * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g.: params: { groupFormatterPrefix: 'Total: ', groupFormatterSuffix: '$' } @@ -61,6 +70,20 @@ export const GroupTotalFormatters = { */ sumTotalsColored: sumTotalsColoredFormatter, + /** + * Sums up all the column totals and display currency + * Extra options available in "params":: "groupFormatterPrefix", "groupFormatterSuffix", "groupFormatterCurrencyPrefix" and/or "groupFormatterCurrencySuffix" + * e.g: params: { groupFormatterPrefix: 'Total: ', groupFormatterSuffix: '$' } + */ + sumTotalsCurrency: sumTotalsCurrencyFormatter, + + /** + * Sums up all the column totals and display currency with color of red/green text on negative/positive values + * Extra options available in "params":: "groupFormatterPrefix", "groupFormatterSuffix", "groupFormatterCurrencyPrefix" and/or "groupFormatterCurrencySuffix" + * e.g: params: { groupFormatterPrefix: 'Total: ', groupFormatterSuffix: '$' } + */ + sumTotalsCurrencyColored: sumTotalsCurrencyColoredFormatter, + /** * Sums up all the column totals and display dollar sign * Extra options available in "params":: "groupFormatterPrefix" and "groupFormatterSuffix", e.g: params: { groupFormatterPrefix: 'Total: ', groupFormatterSuffix: '$' } diff --git a/packages/common/src/grouping-formatters/sumTotalsCurrencyColoredFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsCurrencyColoredFormatter.ts new file mode 100644 index 000000000..20ec43478 --- /dev/null +++ b/packages/common/src/grouping-formatters/sumTotalsCurrencyColoredFormatter.ts @@ -0,0 +1,27 @@ +import { Column, GroupTotalsFormatter, SlickGrid } from '../interfaces/index'; +import { formatNumber } from '../services/utilities'; +import { retrieveFormatterOptions } from '../formatters/formatterUtilities'; + +export const sumTotalsCurrencyColoredFormatter: GroupTotalsFormatter = (totals: any, columnDef: Column, grid: SlickGrid) => { + const field = columnDef.field ?? ''; + const val = totals.sum?.[field]; + const params = columnDef?.params; + const prefix = params?.groupFormatterPrefix || ''; + const suffix = params?.groupFormatterSuffix || ''; + const currencyPrefix = params?.groupFormatterCurrencyPrefix || ''; + const currencySuffix = params?.groupFormatterCurrencySuffix || ''; + const { + minDecimal, + maxDecimal, + decimalSeparator, + thousandSeparator, + wrapNegativeNumber + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); + + if (val !== null && !isNaN(+val)) { + const colorStyle = (val >= 0) ? 'green' : 'red'; + const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); + return `${prefix}${formattedNumber}${suffix}`; + } + return ''; +}; diff --git a/packages/common/src/grouping-formatters/sumTotalsCurrencyFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsCurrencyFormatter.ts new file mode 100644 index 000000000..61e428303 --- /dev/null +++ b/packages/common/src/grouping-formatters/sumTotalsCurrencyFormatter.ts @@ -0,0 +1,27 @@ +import { Column, GroupTotalsFormatter, SlickGrid } from '../interfaces/index'; +import { formatNumber } from '../services/utilities'; +import { retrieveFormatterOptions } from '../formatters/formatterUtilities'; + +export const sumTotalsCurrencyFormatter: GroupTotalsFormatter = (totals: any, columnDef: Column, grid: SlickGrid) => { + const field = columnDef.field ?? ''; + const val = totals.sum?.[field]; + const params = columnDef?.params; + const prefix = params?.groupFormatterPrefix || ''; + const suffix = params?.groupFormatterSuffix || ''; + const currencyPrefix = params?.groupFormatterCurrencyPrefix || ''; + const currencySuffix = params?.groupFormatterCurrencySuffix || ''; + + const { + minDecimal, + maxDecimal, + decimalSeparator, + thousandSeparator, + wrapNegativeNumber + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); + + if (val !== null && !isNaN(+val)) { + const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, currencyPrefix, currencySuffix, decimalSeparator, thousandSeparator); + return `${prefix}${formattedNumber}${suffix}`; + } + return ''; +}; diff --git a/packages/common/src/grouping-formatters/sumTotalsDollarBoldFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsDollarBoldFormatter.ts index ff993aeb1..ac223c30b 100644 --- a/packages/common/src/grouping-formatters/sumTotalsDollarBoldFormatter.ts +++ b/packages/common/src/grouping-formatters/sumTotalsDollarBoldFormatter.ts @@ -14,7 +14,7 @@ export const sumTotalsDollarBoldFormatter: GroupTotalsFormatter = (totals: any, decimalSeparator, thousandSeparator, wrapNegativeNumber - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'group'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); if (val !== null && !isNaN(+val)) { const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, '$', '', decimalSeparator, thousandSeparator); diff --git a/packages/common/src/grouping-formatters/sumTotalsDollarColoredBoldFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsDollarColoredBoldFormatter.ts index 33b2e27f9..b10a2cdbe 100644 --- a/packages/common/src/grouping-formatters/sumTotalsDollarColoredBoldFormatter.ts +++ b/packages/common/src/grouping-formatters/sumTotalsDollarColoredBoldFormatter.ts @@ -14,7 +14,7 @@ export const sumTotalsDollarColoredBoldFormatter: GroupTotalsFormatter = (totals decimalSeparator, thousandSeparator, wrapNegativeNumber - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'group'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); if (val !== null && !isNaN(+val)) { const colorStyle = (val >= 0) ? 'green' : 'red'; diff --git a/packages/common/src/grouping-formatters/sumTotalsDollarColoredFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsDollarColoredFormatter.ts index 582c584e7..a5a2beddb 100644 --- a/packages/common/src/grouping-formatters/sumTotalsDollarColoredFormatter.ts +++ b/packages/common/src/grouping-formatters/sumTotalsDollarColoredFormatter.ts @@ -14,7 +14,7 @@ export const sumTotalsDollarColoredFormatter: GroupTotalsFormatter = (totals: an decimalSeparator, thousandSeparator, wrapNegativeNumber - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'group'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); if (val !== null && !isNaN(+val)) { const colorStyle = (val >= 0) ? 'green' : 'red'; diff --git a/packages/common/src/grouping-formatters/sumTotalsDollarFormatter.ts b/packages/common/src/grouping-formatters/sumTotalsDollarFormatter.ts index 3a5da155a..252987e35 100644 --- a/packages/common/src/grouping-formatters/sumTotalsDollarFormatter.ts +++ b/packages/common/src/grouping-formatters/sumTotalsDollarFormatter.ts @@ -14,7 +14,7 @@ export const sumTotalsDollarFormatter: GroupTotalsFormatter = (totals: any, colu decimalSeparator, thousandSeparator, wrapNegativeNumber - } = retrieveFormatterOptions(columnDef, grid, 'dollar', 'group'); + } = retrieveFormatterOptions(columnDef, grid, 'currency', 'group'); if (val !== null && !isNaN(+val)) { const formattedNumber = formatNumber(val, minDecimal, maxDecimal, wrapNegativeNumber, '$', '', decimalSeparator, thousandSeparator); diff --git a/packages/excel-export/src/excelUtils.spec.ts b/packages/excel-export/src/excelUtils.spec.ts index eeff7432e..87153834e 100644 --- a/packages/excel-export/src/excelUtils.spec.ts +++ b/packages/excel-export/src/excelUtils.spec.ts @@ -330,6 +330,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -348,6 +350,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: ',', maxDecimal: 4, minDecimal: 2, @@ -365,6 +369,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -382,6 +388,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -399,6 +407,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -416,6 +426,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: undefined, minDecimal: undefined, @@ -433,6 +445,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -450,6 +464,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -467,6 +483,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -484,6 +502,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -502,6 +522,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -520,6 +542,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'group'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -540,6 +564,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -558,6 +584,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -576,6 +604,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 4, minDecimal: 2, @@ -594,6 +624,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: undefined, minDecimal: undefined, @@ -612,6 +644,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: undefined, minDecimal: undefined, @@ -630,6 +664,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: undefined, minDecimal: undefined, @@ -648,6 +684,8 @@ describe('excelUtils', () => { const output = getNumericFormatterOptions(column, gridStub, 'cell'); expect(output).toEqual({ + currencyPrefix: '', + currencySuffix: '', decimalSeparator: '.', maxDecimal: 2, minDecimal: 2, @@ -673,6 +711,18 @@ describe('excelUtils', () => { expect(output).toEqual({ groupType: 'avg', stylesheetFormatter: { id: 135 } }); }); + it('should get excel excel metadata style format for GroupTotalFormatters.avgTotalsCurrency', () => { + const column = { + type: FieldType.number, + formatter: Formatters.decimal, groupTotalsFormatter: GroupTotalFormatters.avgTotalsCurrency, + params: { thousandSeparator: ' ', decimalSeparator: ',', numberSuffix: ' USD' } + } as Column; + + const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'group'); + + expect(output).toEqual({ groupType: 'avg', stylesheetFormatter: { id: 135 } }); + }); + it('should get excel excel metadata style format for GroupTotalFormatters.avgTotalsDollar', () => { const column = { type: FieldType.number, @@ -685,7 +735,7 @@ describe('excelUtils', () => { expect(output).toEqual({ groupType: 'avg', stylesheetFormatter: { id: 135 } }); }); - it('should get excel excel metadata style format for GroupTotalFormatters.sumTotalsDollarColored', () => { + it('should get excel excel metadata style format for GroupTotalFormatters.avgTotals', () => { const column = { type: FieldType.number, formatter: Formatters.decimal, groupTotalsFormatter: GroupTotalFormatters.avgTotals, } as Column; @@ -721,6 +771,24 @@ describe('excelUtils', () => { expect(output).toEqual({ groupType: 'sum', stylesheetFormatter: { id: 135 } }); }); + it('should get excel excel metadata style format for GroupTotalFormatters.sumTotalsCurrencyColored', () => { + const column = { + type: FieldType.number, formatter: Formatters.decimal, groupTotalsFormatter: GroupTotalFormatters.sumTotalsCurrencyColored, + } as Column; + const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'group'); + + expect(output).toEqual({ groupType: 'sum', stylesheetFormatter: { id: 135 } }); + }); + + it('should get excel excel metadata style format for GroupTotalFormatters.sumTotalsCurrencyColored', () => { + const column = { + type: FieldType.number, formatter: Formatters.decimal, groupTotalsFormatter: GroupTotalFormatters.sumTotalsCurrencyColored, + } as Column; + const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'group'); + + expect(output).toEqual({ groupType: 'sum', stylesheetFormatter: { id: 135 } }); + }); + it('should get excel excel metadata style format for GroupTotalFormatters.sumTotalsDollarColoredBold', () => { const column = { type: FieldType.number, formatter: Formatters.decimal, groupTotalsFormatter: GroupTotalFormatters.sumTotalsDollarColoredBold, @@ -787,20 +855,21 @@ describe('excelUtils', () => { }); describe('with regular Formatters', () => { - it('should get excel excel metadata style format for Formatters.dollarColoredBold', () => { + it('should get excel excel metadata style format for Formatters.currency', () => { const column = { - type: FieldType.number, formatter: Formatters.dollarColoredBold, - params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } + type: FieldType.number, + formatter: Formatters.currency, + params: { displayNegativeNumberWithParentheses: false, thousandSeparator: ' ' } } as Column; const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'cell'); expect(output).toEqual({ groupType: '', stylesheetFormatter: { id: 135 } }); }); - it('should get excel excel metadata style format for Formatters.dollarColored', () => { + it('should get excel excel metadata style format for Formatters.dollar', () => { const column = { type: FieldType.number, - formatter: Formatters.dollarColored, + formatter: Formatters.dollar, params: { displayNegativeNumberWithParentheses: false, thousandSeparator: ' ' } } as Column; const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'cell'); @@ -808,10 +877,10 @@ describe('excelUtils', () => { expect(output).toEqual({ groupType: '', stylesheetFormatter: { id: 135 } }); }); - it('should get excel excel metadata style format for Formatters.dollar', () => { + it('should get excel excel metadata style format for Formatters.dollarColored', () => { const column = { type: FieldType.number, - formatter: Formatters.dollar, + formatter: Formatters.dollarColored, params: { displayNegativeNumberWithParentheses: false, thousandSeparator: ' ' } } as Column; const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'cell'); @@ -819,6 +888,16 @@ describe('excelUtils', () => { expect(output).toEqual({ groupType: '', stylesheetFormatter: { id: 135 } }); }); + it('should get excel excel metadata style format for Formatters.dollarColoredBold', () => { + const column = { + type: FieldType.number, formatter: Formatters.dollarColoredBold, + params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } + } as Column; + const output = getExcelFormatFromGridFormatter(stylesheetStub, {}, column, gridStub, 'cell'); + + expect(output).toEqual({ groupType: '', stylesheetFormatter: { id: 135 } }); + }); + it('should get excel excel metadata style format for Formatters.percent', () => { const column = { type: FieldType.number, diff --git a/packages/excel-export/src/excelUtils.ts b/packages/excel-export/src/excelUtils.ts index eaa7a072d..a0033ba3e 100644 --- a/packages/excel-export/src/excelUtils.ts +++ b/packages/excel-export/src/excelUtils.ts @@ -83,16 +83,19 @@ export function getGroupTotalValue(totals: any, groupType: string, colField: str /** Get numeric formatter options when defined or use default values (minDecimal, maxDecimal, thousandSeparator, decimalSeparator, wrapNegativeNumber) */ export function getNumericFormatterOptions(columnDef: Column, grid: SlickGrid, formatterType: FormatterType) { - let dataType: 'decimal' | 'dollar' | 'percent' | 'regular'; + let dataType: 'currency' | 'decimal' | 'percent' | 'regular'; if (formatterType === 'group') { switch (columnDef.groupTotalsFormatter) { + case GroupTotalFormatters.avgTotalsCurrency: case GroupTotalFormatters.avgTotalsDollar: - case GroupTotalFormatters.sumTotalsDollarColoredBold: - case GroupTotalFormatters.sumTotalsDollarColored: - case GroupTotalFormatters.sumTotalsDollarBold: + case GroupTotalFormatters.sumTotalsCurrency: + case GroupTotalFormatters.sumTotalsCurrencyColored: case GroupTotalFormatters.sumTotalsDollar: - dataType = 'dollar'; + case GroupTotalFormatters.sumTotalsDollarBold: + case GroupTotalFormatters.sumTotalsDollarColored: + case GroupTotalFormatters.sumTotalsDollarColoredBold: + dataType = 'currency'; break; case GroupTotalFormatters.avgTotalsPercentage: dataType = 'percent'; @@ -100,8 +103,8 @@ export function getNumericFormatterOptions(columnDef: Column, grid: SlickGrid, f case GroupTotalFormatters.avgTotals: case GroupTotalFormatters.minTotals: case GroupTotalFormatters.maxTotals: - case GroupTotalFormatters.sumTotalsColored: case GroupTotalFormatters.sumTotals: + case GroupTotalFormatters.sumTotalsColored: case GroupTotalFormatters.sumTotalsBold: default: // side note, formatters are using "regular" without any decimal limits (min, max), @@ -111,15 +114,16 @@ export function getNumericFormatterOptions(columnDef: Column, grid: SlickGrid, f } } else { switch (columnDef.formatter) { - case Formatters.dollarColoredBold: - case Formatters.dollarColored: + case Formatters.currency: case Formatters.dollar: - dataType = 'dollar'; + case Formatters.dollarColored: + case Formatters.dollarColoredBold: + dataType = 'currency'; break; case Formatters.percent: + case Formatters.percentComplete: case Formatters.percentCompleteBar: case Formatters.percentCompleteBarWithText: - case Formatters.percentComplete: case Formatters.percentSymbol: dataType = 'percent'; break; @@ -142,6 +146,7 @@ export function getExcelFormatFromGridFormatter(stylesheet: ExcelStylesheet, sty if (formatterType === 'group') { switch (columnDef.groupTotalsFormatter) { case GroupTotalFormatters.avgTotals: + case GroupTotalFormatters.avgTotalsCurrency: case GroupTotalFormatters.avgTotalsDollar: case GroupTotalFormatters.avgTotalsPercentage: groupType = 'avg'; @@ -155,6 +160,8 @@ export function getExcelFormatFromGridFormatter(stylesheet: ExcelStylesheet, sty case GroupTotalFormatters.sumTotals: case GroupTotalFormatters.sumTotalsBold: case GroupTotalFormatters.sumTotalsColored: + case GroupTotalFormatters.sumTotalsCurrency: + case GroupTotalFormatters.sumTotalsCurrencyColored: case GroupTotalFormatters.sumTotalsDollar: case GroupTotalFormatters.sumTotalsDollarColoredBold: case GroupTotalFormatters.sumTotalsDollarColored: @@ -169,15 +176,16 @@ export function getExcelFormatFromGridFormatter(stylesheet: ExcelStylesheet, sty switch (fieldType) { case FieldType.number: switch (columnDef.formatter) { - case Formatters.dollarColoredBold: - case Formatters.dollarColored: + case Formatters.currency: + case Formatters.decimal: case Formatters.dollar: + case Formatters.dollarColored: + case Formatters.dollarColoredBold: case Formatters.percent: case Formatters.percentComplete: case Formatters.percentCompleteBar: case Formatters.percentCompleteBarWithText: case Formatters.percentSymbol: - case Formatters.decimal: format = createExcelFormatFromGridFormatter(columnDef, grid, 'cell'); break; default: @@ -217,11 +225,10 @@ function createFormatFromNumber(formattedVal: string) { suffix ] = formattedVal?.match(/^([^\d\(\-]*)([\(]?)([^\d]*)([\-]?[\w]]?[\d\s]*[.,\d]*[\d]*[^)\s\%]?)([^\d.,)]*)([\)]?)([^\d]*)$/i) || []; + // we use 1 so that they won't be removed when rounding numbers, however Excel uses 0 and # symbol // replace 1's by 0's (required numbers) and replace 2's by "#" (optional numbers) const replacedNumber = (number || '').replace(/1/g, '0').replace(/[2]/g, '#'); - // console.log('createFormatFromNumber', formattedVal.trim(), '|prefix:', prefix ?? '', '|openBraquet:', openBraquet ?? '', '|symbolPrefix:', symbolPrefix ?? '', '|input:', replacedNumber, '|symbolSuffix:', symbolSuffix ?? '', '|closingBraquet:', closingBraquet ?? '', '|suffix:', suffix ?? ''); - const format = [ escapeQuotes(prefix ?? ''), openBraquet ?? '',