57 lines
2.9 KiB
TypeScript
57 lines
2.9 KiB
TypeScript
import type { MrftaModel } from './irpc-mrfta.ts';
|
|
import { closureFingerprint } from './iva-closure.ts';
|
|
import {
|
|
fractionPresentation,
|
|
type FiscalFraction,
|
|
} from './fiscal-rational.ts';
|
|
|
|
// Groups are working sheets, never a decision to split an official declaration.
|
|
export function mrftaCases(m: MrftaModel) {
|
|
return m.lines.map((line) => ({
|
|
key: closureFingerprint([m.period, line.rubric, line.rate, line.cer]),
|
|
period: m.period,
|
|
rubric: line.rubric,
|
|
rate: line.rate,
|
|
cer: line.cer,
|
|
ids: [...line.ids],
|
|
documents: [...line.documents],
|
|
references: [...line.references],
|
|
base: structuredClone(line.base),
|
|
tax: structuredClone(line.tax),
|
|
paid: structuredClone(line.paid),
|
|
pending:
|
|
!line.cer ||
|
|
!/^\d+$/.test(line.cer) ||
|
|
!line.ids.every((id) =>
|
|
m.input.codes.find((c) => c.rowId === id)?.reference.trim(),
|
|
)
|
|
? 'CER ou referência por corresponder;sem preenchimento presumido.'
|
|
: 'CER transcrito com referência do caso;sem validação por catálogo oficial. Código provisório ou de simulação não é correspondência oficial.',
|
|
officialSeparation:
|
|
'A correspondência de linhas/anexos/declaração oficial permanece por resolver quando há taxas/CER distintos na mesma rubrica.',
|
|
}));
|
|
}
|
|
export function mrftaCaseHtml(m: MrftaModel, key: string): string {
|
|
const c = mrftaCases(m).find((c) => c.key === key);
|
|
if (!c)
|
|
throw Error('Caso MRFTA não encontrado;reprepare as entradas actuais.');
|
|
const esc = (v: unknown) =>
|
|
String(v).replace(
|
|
/[&<>"']/g,
|
|
(c) =>
|
|
({
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": ''',
|
|
})[c]!,
|
|
);
|
|
const money = (v: FiscalFraction | null) => {
|
|
if (!v) return 'Indeterminado';
|
|
const p = fractionPresentation(v);
|
|
return (p.approximate ? '≈' : '') + p.decimal + ' MZN';
|
|
};
|
|
return `<!doctype html><html lang="pt"><meta charset="utf-8"><title>MRFTA — ficha de caso</title><body><h1>MRFTA — ficha de trabalho por caso</h1><p>Não é uma declaração autónoma,guia,anexo oficial ou submissão. Não funde taxas nem substitui o total do período.</p><p>Período:${esc(c.period)};rubrica:${esc(c.rubric)};taxa:${c.rate}%;CER:${esc(c.cer || 'Por corresponder')}.</p><p>Base:${esc(money(c.base))};imposto:${esc(money(c.tax))};entregas:${esc(money(c.paid))}.</p><p>Documentos:${esc(c.documents.join(';'))};origens:${esc(c.ids.join(';'))}.</p><p>${esc(c.references.join(' | '))}</p><p>${esc(c.pending)}</p><p>${esc(c.officialSeparation)}</p><h2>Pendências do período — conservadas</h2><ul>${m.pending.map((p) => '<li>' + esc(p) + '</li>').join('')}</ul><small>${esc(m.source)}</small></body></html>`;
|
|
}
|