Merge pull request 'AURORA-1835: свод 1 и сводные проектов: форматтер чисел создаётся один раз' (#217) from feat/210-aurora-1835-svod1-formatter into test

This commit is contained in:
aep 2026-11-08 10:33:50 +03:00
commit ab9616ae0a
3 changed files with 51 additions and 4 deletions

View File

@ -8,6 +8,7 @@ import { buildRowHierarchy } from '../../components/RealtimeTable/utils/rowUtils
import { createFixedRowVirtualizerOptions, getRootFontSizePx } from '../../components/RealtimeTable/utils/virtualizerOptions';
import DenominationSelect from '../../components/common/DenominationSelect';
import useDenomination from '../../components/common/useDenomination';
import { formatSummaryAmount } from './summaryFormat';
const tableSize = (rem) => rem * 16;
// Высота строки задана в rem явно (строка и ячейка), виртуализатор layout не читает.
@ -78,10 +79,9 @@ const scaleColumns = (columns, factor, denomination) =>
Cell: ({ cell }) => {
const value = cell.getValue();
if (value === null || value === undefined || value === '') return originalCell ? originalCell({ cell }) : '—';
const numeric = Number(value);
if (!Number.isFinite(numeric)) return originalCell ? originalCell({ cell }) : value;
if (numeric === 0) return '-';
return new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2 }).format(numeric * factor);
const formatted = formatSummaryAmount(value, factor);
if (formatted !== null) return formatted;
return originalCell ? originalCell({ cell }) : value;
},
}
: {}),

View File

@ -0,0 +1,10 @@
const amountFormatter = new Intl.NumberFormat('ru-RU', { maximumFractionDigits: 2 });
// Возвращает null, если значение не число: вызывающий отдаёт исходное значение.
export const formatSummaryAmount = (value, factor) => {
if (value === null || value === undefined || value === '') return null;
const numeric = Number(value);
if (!Number.isFinite(numeric)) return null;
if (numeric === 0) return '-';
return amountFormatter.format(numeric * factor);
};

View File

@ -0,0 +1,37 @@
import assert from 'node:assert/strict';
import test from 'node:test';
const NBSP = ' ';
test('formatSummaryAmount: форматирование и множители', async () => {
const { formatSummaryAmount } = await import('./summaryFormat.js');
assert.equal(formatSummaryAmount(0, 1), '-');
assert.equal(formatSummaryAmount('0', 1e-3), '-');
assert.equal(formatSummaryAmount(1234.567, 1), `1${NBSP}234,57`);
assert.equal(formatSummaryAmount(5_000_000, 1e-3), `5${NBSP}000`);
assert.equal(formatSummaryAmount(5_000_000, 1e-6), '5');
assert.equal(formatSummaryAmount('1500', 1), `1${NBSP}500`);
});
test('formatSummaryAmount: нечисловые значения возвращают null', async () => {
const { formatSummaryAmount } = await import('./summaryFormat.js');
for (const v of [null, undefined, '', 'abc', Number.NaN, Number.POSITIVE_INFINITY]) {
assert.equal(formatSummaryAmount(v, 1), null);
}
});
test('Intl.NumberFormat создаётся один раз на модуль', async () => {
const Original = Intl.NumberFormat;
let created = 0;
Intl.NumberFormat = function CountingNumberFormat(...args) {
created += 1;
return new Original(...args);
};
try {
const { formatSummaryAmount } = await import('./summaryFormat.js?fresh');
for (let i = 1; i <= 50; i += 1) formatSummaryAmount(i * 100, 1e-3);
assert.equal(created, 1);
} finally {
Intl.NumberFormat = Original;
}
});