116 lines
4.4 KiB
TypeScript
116 lines
4.4 KiB
TypeScript
import type { CheckResult, DocumentStatus, FileOut, FileType, FileWarningOut, IssueCountsOut, Severity } from '../../types/api';
|
||
import { formatMoscowDate } from '../../utils/dates';
|
||
import { documentStatusLabel, documentTypeLabel, periodLabel } from '../../utils/labels';
|
||
|
||
import { toFileWarnings, warningsLevel } from './fileWarnings';
|
||
|
||
export type RowStatus = 'success' | 'warning' | 'processing' | 'error';
|
||
|
||
export interface DocumentRow {
|
||
key: string;
|
||
/** id документа; null — строка файла без документов */
|
||
documentId: string | null;
|
||
/** id файла: удаление и замена — файлом целиком */
|
||
fileId: string;
|
||
name: string;
|
||
fileType: FileType;
|
||
subtitle: string;
|
||
period: string;
|
||
periodCheck?: CheckResult | null;
|
||
counterpartyCheck?: CheckResult | null;
|
||
status: RowStatus;
|
||
statusLabel: string;
|
||
errorReason: string | null;
|
||
linkable: boolean;
|
||
/** предупреждения разбора файла (общие для всех документов файла) */
|
||
fileWarnings: FileWarningOut[];
|
||
mappingWarnings: string[];
|
||
/** счётчики issues документа; у строки файла без документов — нули */
|
||
issueCounts: IssueCountsOut;
|
||
/** число комментариев документа; у строки файла без документов — 0 */
|
||
commentsCount: number;
|
||
}
|
||
|
||
/** Значок у статуса (P6-12): число предупреждений и цвет уровня; ничего нет — null. */
|
||
export function rowBadge(row: DocumentRow): { count: number; level: Severity } | null {
|
||
const count = row.fileWarnings.length + row.issueCounts.error + row.issueCounts.info;
|
||
if (count === 0) return null;
|
||
const level = warningsLevel(row.fileWarnings) === 'error' || row.issueCounts.error > 0 ? 'error' : 'info';
|
||
return { count, level };
|
||
}
|
||
|
||
const LINKABLE = new Set(['OSV', 'BALANCE', 'INCOME']);
|
||
|
||
const join = (parts: (string | null)[]) => parts.filter(Boolean).join(' · ');
|
||
|
||
function errorReason(f: FileOut): string | null {
|
||
if (f.status !== 'ERROR' || !f.job) return null;
|
||
return f.job.mapping_error ?? f.job.error_message ?? f.job.error_code ?? null;
|
||
}
|
||
|
||
function documentRowStatus(status: DocumentStatus): RowStatus {
|
||
if (status === 'CONFIRMED') return 'success';
|
||
if (status === 'ERROR') return 'error';
|
||
return 'warning';
|
||
}
|
||
|
||
/** Файлы → строки таблицы: одна строка на документ, файл без документов — одна строка на файл. */
|
||
export function buildDocumentRows(files: FileOut[], labelFor?: (f: FileOut) => string | null): DocumentRow[] {
|
||
return files.flatMap((f): DocumentRow[] => {
|
||
const extra = labelFor?.(f) ?? null;
|
||
const name = f.original_name ?? 'без имени';
|
||
const date = formatMoscowDate(f.uploaded_at);
|
||
const fileWarnings = toFileWarnings(f.job?.warnings);
|
||
const mappingWarnings = f.job?.mapping_warnings ?? [];
|
||
if (f.documents.length === 0) {
|
||
const failed = f.status === 'ERROR';
|
||
return [
|
||
{
|
||
key: f.id,
|
||
documentId: null,
|
||
fileId: f.id,
|
||
name,
|
||
fileType: f.file_type,
|
||
subtitle: join([f.file_type, date, extra]),
|
||
period: '—',
|
||
status: failed ? 'error' : 'processing',
|
||
statusLabel: failed ? 'Ошибка' : 'Обработка',
|
||
errorReason: errorReason(f),
|
||
linkable: false,
|
||
fileWarnings,
|
||
mappingWarnings,
|
||
issueCounts: { error: 0, info: 0 },
|
||
commentsCount: 0,
|
||
},
|
||
];
|
||
}
|
||
return f.documents.map((d) => {
|
||
const typeText =
|
||
d.document_type === 'DISCLOSURE' || d.document_type === 'OTHER'
|
||
? 'Прочий документ'
|
||
: documentTypeLabel(d.document_type, d.osv_account_code);
|
||
const status = documentRowStatus(d.status);
|
||
return {
|
||
key: d.id,
|
||
documentId: d.id,
|
||
fileId: f.id,
|
||
name,
|
||
fileType: f.file_type,
|
||
subtitle: join([typeText, f.file_type, date, extra]),
|
||
period: periodLabel(d.period_year, d.period_quarter, d.is_cumulative),
|
||
periodCheck: d.period_check,
|
||
counterpartyCheck: d.counterparty_check,
|
||
status,
|
||
statusLabel: documentStatusLabel(d.status),
|
||
errorReason: null,
|
||
linkable: LINKABLE.has(d.document_type),
|
||
fileWarnings,
|
||
mappingWarnings,
|
||
// ядро без v5.19 не присылает issue_counts — считаем, что замечаний нет
|
||
issueCounts: d.issue_counts ?? { error: 0, info: 0 },
|
||
commentsCount: d.comments_count ?? 0,
|
||
};
|
||
});
|
||
});
|
||
}
|