Возврат тестирования 11.11: - tableColumns считал множитель по MRT column, у которого нет accessorKey, — getMoneyUnit видел пустой ключ и считал денежной любую колонку (НДС, курс, сумма в валюте, площадь масштабировались). getMoneyUnit теперь берёт column.columnDef ?? column. - текстовые колонки (комментарии, обоснования, реквизиты договоров, коды) попадали в правило «иначе thousand»: «123» в комментарии делилось, а при «млн»/«млрд» редактор обоснования закрывался как денежный. Добавлен isTextColumn: такие колонки не масштабируются и не форматируются как числа (внутренний заказ 10123 и комментарий «123» показываются как есть). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
162 lines
7.2 KiB
JavaScript
162 lines
7.2 KiB
JavaScript
import assert from 'node:assert/strict';
|
||
import test from 'node:test';
|
||
import {
|
||
AHR_LIMIT_SHEET,
|
||
DEFAULT_DENOMINATION,
|
||
TEXT_COLUMN_IDS,
|
||
UNIT_IN_RUB,
|
||
getDisplayFactor,
|
||
getMoneyUnit,
|
||
isTextColumn,
|
||
resolveDenomination,
|
||
} from './moneyUtils.js';
|
||
|
||
test('getDisplayFactor converts between units with thousand as the base', () => {
|
||
assert.equal(getDisplayFactor('thousand', 'thousand'), 1);
|
||
assert.equal(getDisplayFactor('thousand', 'million'), 0.001);
|
||
assert.equal(getDisplayFactor('thousand', 'rub'), 1000);
|
||
assert.equal(getDisplayFactor('rub', 'thousand'), 0.001);
|
||
});
|
||
|
||
test('getMoneyUnit defaults ordinary money columns to thousand', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.plan.q1' }, 'AHR'), 'thousand');
|
||
});
|
||
|
||
test('getMoneyUnit returns null for quantities, rates, codes and ids regardless of sheet', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.qty_q1' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.contract.vat_rate' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.contract_detail.exchange_rate' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.rented_area' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.header.section_code' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.header.internal_order' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.header.num_group' }), null);
|
||
});
|
||
|
||
test('getMoneyUnit returns null for other *_qty columns via the suffix pattern', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.some_qty' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.header.amount_foreign' }), null);
|
||
});
|
||
|
||
test('getMoneyUnit returns null for TEXT_COLUMN_IDS not covered by the generic suffix list', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.article_id' }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.code_razdela' }), null);
|
||
assert.ok(TEXT_COLUMN_IDS.has('data.article_id'));
|
||
});
|
||
|
||
test('getMoneyUnit treats AHR_LIMIT limits and amounts as rub, not thousand', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.amount_q1' }, 'AHR_LIMIT'), 'rub');
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.limit_without_vat' }, 'AHR_LIMIT'), 'rub');
|
||
// тот же accessorKey на другом листе — обычная денежная колонка в тыс. руб.
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.amount_q1' }, 'OPER'), 'thousand');
|
||
});
|
||
|
||
test('getMoneyUnit respects an explicit moneyUnit override, including null', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.plan.q1', moneyUnit: null }), null);
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.qty_q1', moneyUnit: 'rub' }), 'rub');
|
||
});
|
||
|
||
// AURORA-1899, возврат тестирования 11.11: tableColumns передаёт в расчёт множителя
|
||
// MRT column (column.id + column.columnDef), у которого нет своего accessorKey.
|
||
test('getMoneyUnit reads accessorKey from an MRT column object via columnDef', () => {
|
||
const mrtColumn = (accessorKey) => ({ id: accessorKey, columnDef: { accessorKey } });
|
||
assert.equal(getMoneyUnit(mrtColumn('data.contract_detail.vat_rate'), 'OPER'), null);
|
||
assert.equal(getMoneyUnit(mrtColumn('data.contract_detail.exchange_rate'), 'OPER'), null);
|
||
assert.equal(getMoneyUnit(mrtColumn('data.contract_detail.amount_foreign'), 'OPER'), null);
|
||
assert.equal(getMoneyUnit(mrtColumn('data.header.internal_order'), 'OPER'), null);
|
||
assert.equal(getMoneyUnit(mrtColumn('data.rented_area'), 'AHR_RENT'), null);
|
||
assert.equal(getMoneyUnit(mrtColumn('data.plan.q1'), 'OPER'), 'thousand');
|
||
assert.equal(getMoneyUnit(mrtColumn('data.amount_q1'), 'AHR_LIMIT'), 'rub');
|
||
assert.equal(getMoneyUnit({ id: 'data.plan.q1', columnDef: { accessorKey: 'data.plan.q1', moneyUnit: null } }), null);
|
||
});
|
||
|
||
test('getMoneyUnit returns null for text columns: comments, justifications and other free text', () => {
|
||
for (const accessorKey of [
|
||
'data.plan.comment',
|
||
'data.q2.adj_comment',
|
||
'data.q2.base_correction_comment',
|
||
'data.q1.transfer_next_comment',
|
||
'data.q1.transfer_far_comment',
|
||
'data.seq_dfip.justification',
|
||
'data.header.justification',
|
||
'data.collegial.note',
|
||
'data.header.name',
|
||
'data.contract.counterparty',
|
||
'data.contract.subject',
|
||
'data.contract.reference',
|
||
'data.contract.deadline',
|
||
'data.contract.date',
|
||
'data.contract.currency',
|
||
'data.contract.act',
|
||
'data.contract.scheme',
|
||
'data.contract_detail.payment_scheme',
|
||
'data.contract_detail.rf_schedule',
|
||
'data.contract_detail.addenda',
|
||
'data.ckk.proc_plan',
|
||
'data.ckk.proc_method',
|
||
'data.allocation.property',
|
||
'data.collegial.protocol',
|
||
'data.collegial.approved',
|
||
'data.contract_summary.centralized_flag',
|
||
'data.contract_end_date',
|
||
'data.object_type',
|
||
'data.unit',
|
||
'data.address',
|
||
]) {
|
||
assert.equal(getMoneyUnit({ accessorKey }, 'OPER'), null, accessorKey);
|
||
}
|
||
});
|
||
|
||
// Возврат 11.11: внутренний заказ 10123 и комментарий «123» ожидаются как исходный текст,
|
||
// а не «10 123,0» / «123,0»; ставки и количества остаются числами.
|
||
test('isTextColumn marks codes and free text as text, numeric non-money columns as numbers', () => {
|
||
const mrtColumn = (accessorKey) => ({ id: accessorKey, columnDef: { accessorKey } });
|
||
for (const accessorKey of [
|
||
'data.header.internal_order',
|
||
'data.header.section_code',
|
||
'data.header.item_id',
|
||
'data.plan.comment',
|
||
'data.q2.adj_comment',
|
||
'data.seq_dfip.justification',
|
||
'data.contract.counterparty',
|
||
'data.article_id',
|
||
]) {
|
||
assert.equal(isTextColumn({ accessorKey }), true, accessorKey);
|
||
assert.equal(isTextColumn(mrtColumn(accessorKey)), true, `mrt ${accessorKey}`);
|
||
}
|
||
for (const accessorKey of [
|
||
'data.contract_detail.vat_rate',
|
||
'data.contract_detail.exchange_rate',
|
||
'data.contract_detail.amount_foreign',
|
||
'data.rented_area',
|
||
'data.qty_q1',
|
||
'data.acquired_qty',
|
||
'data.plan.q1',
|
||
]) {
|
||
assert.equal(isTextColumn({ accessorKey }), false, accessorKey);
|
||
}
|
||
});
|
||
|
||
test('getMoneyUnit keeps money columns whose names resemble text ones as thousand', () => {
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.collegial.amount' }, 'OPER'), 'thousand');
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.q1.transfer_q2_delay_acts' }, 'OPER'), 'thousand');
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.approved.q1' }, 'OPER'), 'thousand');
|
||
assert.equal(getMoneyUnit({ accessorKey: 'data.q1.pay_amount' }, 'OPER'), 'thousand');
|
||
});
|
||
|
||
test('resolveDenomination falls back to thousand when nothing is stored', () => {
|
||
assert.equal(resolveDenomination(null), DEFAULT_DENOMINATION);
|
||
assert.equal(resolveDenomination(undefined), 'thousand');
|
||
assert.equal(resolveDenomination(''), 'thousand');
|
||
assert.equal(resolveDenomination('rub'), 'rub');
|
||
});
|
||
|
||
test('UNIT_IN_RUB defines the four denominations the selector supports', () => {
|
||
assert.deepEqual(Object.keys(UNIT_IN_RUB).sort(), ['billion', 'million', 'rub', 'thousand']);
|
||
});
|
||
|
||
test('AHR_LIMIT_SHEET names the sheet without a denomination selector', () => {
|
||
// Используется tableColumns.jsx/SettingPanel.jsx, чтобы отключить масштабирование и редактирование
|
||
// денежных колонок на листе, где значения всегда показываются как есть.
|
||
assert.equal(AHR_LIMIT_SHEET, 'AHR_LIMIT');
|
||
});
|