import { decimalFraction, addFractions, subtractFractions, fractionPresentation, type FiscalFraction, } from './fiscal-rational.ts'; export const pecPlanVersion = 'IRPC-PEC-plan/1'; export const pecPlanSource = 'RIRPC29(1):mesesJunho/Agosto/Outubro e opção de pagamento único. Montantes repartidos e mês único são hipótese explícita do utilizador,sem regra de igualdade,arredondamento,guia ou prazo legal presumidos. Conferência de prazo da opção única permanece separada.'; export type PecPlan = { version: 1; mode: '' | 'three' | 'single'; reference: string; singleMonth: string; june: string; august: string; october: string; }; export const newPecPlan = (): PecPlan => ({ version: 1, mode: '', reference: '', singleMonth: '', june: '', august: '', october: '', }); export function validatePecPlan(p: PecPlan) { if ( !p || p.version !== 1 || Object.keys(newPecPlan()) .filter((k) => k !== 'version') .some( (k) => typeof (p as unknown as Record)[k] !== 'string', ) || !['', 'three', 'single'].includes(p.mode) ) throw Error('Projecção PEC não recuperável;original preservado.'); } export function calculatePecPlan( p: PecPlan, total: FiscalFraction | null, notApplicable: boolean, year: string, ) { validatePecPlan(p); const pending: string[] = []; let rows: Array<{ month: string; amount: FiscalFraction }> = []; if (!total) pending.push( 'Projecção PEC:total estimado indeterminada;reconciliar a base antes de preparar os montantes.', ); else if (notApplicable || BigInt(total.numerator) === 0n) pending.push( 'Projecção PEC:sem estimativa positiva,não se distribuem saídas de caixa.', ); if (year !== '2026') pending.push('Projecção PEC:exercício fora do recorte2026.'); if (!p.reference.trim()) pending.push( 'Projecção PEC:identifique o fundamento da opção e dos montantes preparados.', ); if (!['three', 'single'].includes(p.mode)) pending.push( 'Projecção PEC:escolha três prestações ou pagamento único.', ); if (!pending.length && total) { if (p.mode === 'three') { const values = [p.june, p.august, p.october]; if (!values.every((v) => /^\d{1,18}(\.\d{1,2})?$/.test(v))) pending.push( 'Projecção PEC:preencha os três montantes em MZN,com até dois decimais;sem preenchimento automático.', ); else { const amounts = values.map(decimalFraction); if (amounts.some((v) => BigInt(v.numerator) <= 0n)) pending.push( 'Projecção PEC:três prestações exigem três montantes positivos.', ); else if ( BigInt( subtractFractions(addFractions(amounts), total) .numerator, ) !== 0n ) pending.push( 'Projecção PEC:a soma das três prestações difere do total preparado;sem arredondamento ou compensação silenciosos.', ); else rows = amounts.map((amount, i) => ({ month: ['2026-06', '2026-08', '2026-10'][i], amount, })); } } else if (!/^2026-(0[1-9]|1[0-2])$/.test(p.singleMonth)) pending.push( 'Projecção PEC:indique o mês previsto do pagamento único;isto não valida o prazo legal.', ); else rows = [{ month: p.singleMonth, amount: total }]; } return { version: pecPlanVersion, source: pecPlanSource, mode: p.mode, pending, rows, total, allocationReconciled: pending.length === 0, legalDeadlineValidated: false, paymentExecuted: false, annualDeductionCreated: false, }; } export function pecPlanReport( p: PecPlan, total: FiscalFraction | null, notApplicable: boolean, year: string, ): Array<[string, string, string, string]> { const m = calculatePecPlan(p, total, notApplicable, year); return [ [ 'IRPC — L8', 'PEC — projecção de tesouraria', m.pending.length ? m.pending.join(' ') : (m.mode === 'single' ? 'Saída de caixa concentrada (hipótese): ' : 'Distribuição de caixa (hipótese): ') + m.rows .map( (r) => r.month + ': ' + fractionPresentation(r.amount).decimal + ' MZN', ) .join('; ') + '. Soma reconciliada;prazo legal não validado. Não é pagamento ou dedução.', p.reference + '; ' + m.source, ], ]; }