Фронт к RSHB/arm-core#80. Строки и ячейки с id = null (достроены сервером) редактируются; правка уходит в PATCH по line_code, строки из БД — по line_id. Ключ достроенной строки code-<код> (R-10). Строки 1600/1700 формы BALANCE выделены фоном #f9f0ff и жирным (R-7). OpenSpec change statement-template-lines. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
107 lines
4.2 KiB
TypeScript
107 lines
4.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
||
import { formLayout } from './formLayout';
|
||
import type { GridRow } from './statementGrid';
|
||
|
||
const row = (code: string | null, name: string | null = `строка ${code}`): GridRow => ({
|
||
key: code ?? 'x',
|
||
lineId: code ?? 'x',
|
||
origin: 'source',
|
||
code,
|
||
name,
|
||
cells: {},
|
||
});
|
||
const shape = (rows: ReturnType<typeof formLayout>) =>
|
||
rows.map((r) => (r.kind === 'section' ? `# ${r.title}` : `${r.row.code}${r.total ? ' (итог)' : ''}`));
|
||
|
||
describe('formLayout — бухгалтерский баланс (0710001)', () => {
|
||
it('порядок формы: статьи раздела, затем итог; 1600 после раздела II; 1700 в конце', () => {
|
||
const rows = ['1100', '1105', '1150', '1200', '1210', '1300', '1310', '1400', '1410', '1500', '1510', '1600', '1700'].map((c) =>
|
||
row(c),
|
||
);
|
||
expect(shape(formLayout('BALANCE', rows))).toEqual([
|
||
'# АКТИВ',
|
||
'# I. Внеоборотные активы',
|
||
'1105',
|
||
'1150',
|
||
'1100 (итог)',
|
||
'# II. Оборотные активы',
|
||
'1210',
|
||
'1200 (итог)',
|
||
'1600 (итог)',
|
||
'# ПАССИВ',
|
||
'# III. Капитал и резервы',
|
||
'1310',
|
||
'1300 (итог)',
|
||
'# IV. Долгосрочные обязательства',
|
||
'1410',
|
||
'1400 (итог)',
|
||
'# V. Краткосрочные обязательства',
|
||
'1510',
|
||
'1500 (итог)',
|
||
'1700 (итог)',
|
||
]);
|
||
});
|
||
it('пустой раздел не выводится; строки вне формы — в конце под «Прочие строки»', () => {
|
||
const rows = [row('1150'), row('9999'), row(null, 'без кода')];
|
||
expect(shape(formLayout('BALANCE', rows))).toEqual(['# АКТИВ', '# I. Внеоборотные активы', '1150', '# Прочие строки', '9999', 'null']);
|
||
});
|
||
it('срезает приклеенные OCR заголовки разделов из названия, полное — в fullName', () => {
|
||
const [, , line] = formLayout('BALANCE', [row('1105', 'АКТИВ I. Внеоборотные активы Гудвил')]);
|
||
expect(line.kind === 'line' && line.displayName).toBe('Гудвил');
|
||
expect(line.kind === 'line' && line.fullName).toBe('АКТИВ I. Внеоборотные активы Гудвил');
|
||
});
|
||
it('если после среза ничего не осталось — название не трогаем', () => {
|
||
const [, , line] = formLayout('BALANCE', [row('1110', 'I. Внеоборотные активы')]);
|
||
expect(line.kind === 'line' && line.displayName).toBe('I. Внеоборотные активы');
|
||
expect(line.kind === 'line' && line.fullName).toBeNull();
|
||
});
|
||
});
|
||
|
||
describe('formLayout — ОФР (0710002)', () => {
|
||
it('итог XX00 — после статей своей сотни, без заголовков разделов', () => {
|
||
const rows = ['2100', '2110', '2120', '2200', '2210', '2300', '2310', '2400', '2410'].map((c) => row(c));
|
||
expect(shape(formLayout('INCOME', rows))).toEqual([
|
||
'2110',
|
||
'2120',
|
||
'2100 (итог)',
|
||
'2210',
|
||
'2200 (итог)',
|
||
'2310',
|
||
'2300 (итог)',
|
||
'2410',
|
||
'2400 (итог)',
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe('formLayout — ОФР, справочные строки', () => {
|
||
it('2900 «Базовая прибыль на акцию» — не итог и стоит перед 2910', () => {
|
||
expect(
|
||
shape(
|
||
formLayout(
|
||
'INCOME',
|
||
['2910', '2900', '2400', '2410'].map((c) => row(c)),
|
||
),
|
||
),
|
||
).toEqual(['2410', '2400 (итог)', '2900', '2910']);
|
||
});
|
||
});
|
||
|
||
describe('formLayout — строки «БАЛАНС»', () => {
|
||
it('1600 и 1700 у баланса помечены grand, остальные итоги — нет', () => {
|
||
const layout = formLayout(
|
||
'BALANCE',
|
||
['1100', '1150', '1600', '1300', '1310', '1700'].map((c) => row(c)),
|
||
);
|
||
const grand = layout.filter((r) => r.kind === 'line' && r.grand).map((r) => (r.kind === 'line' ? r.row.code : ''));
|
||
expect(grand).toEqual(['1600', '1700']);
|
||
});
|
||
it('у ОФР grand нет', () => {
|
||
const layout = formLayout(
|
||
'INCOME',
|
||
['2110', '2100', '2400'].map((c) => row(c)),
|
||
);
|
||
expect(layout.some((r) => r.kind === 'line' && r.grand)).toBe(false);
|
||
});
|
||
});
|