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'); });