arm-web/src/widgets/DocumentReview/formLayout.test.ts
Andrey Epifancev 9e89b9fde7 feat(review): шаблонные строки ББ/ОФР и выделение строк «БАЛАНС» (#19)
Фронт к 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>
2026-10-09 12:18:44 +04:00

107 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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