import { newInvestmentCredit, validateInvestmentCredit, calculateInvestmentCredit, deductInvestmentCredit, investmentCreditSource, investmentAssetIdentity, investmentAssetClaimed, type InvestmentCredit, } from './irpc-investment-credit.ts'; import { inputText } from './input-text.ts'; import { carryPlan, carryIdentity, carrySource, newCreditCarry, validateCreditCarry, type CreditCarry, } from './irpc-credit-carry.ts'; import { economicTaxProof, economicGroupPending, economicDistributionIdentity, economicPosition, economicDeduction, economicSource, newEconomicCredits, validateEconomic, type EconomicCredits, } from './irpc-economic-credit.ts'; import { validateProofParcel, requireProofParcel, parcelProjection, overlappingProofParcels, canonicalParcel, type FiscalProofParcel, } from './fiscal-proof-parcel.ts'; import { validateInternational, internationalProofValue, internationalGroupPending, internationalPosition, internationalDeduction, internationalCreditSource, creditMoney, creditCompare, newInternationalCredits, type InternationalCredits, type InternationalTaxProof, } from './irpc-international-credit.ts'; import { validatePec, pecPaymentValue, pecDeduction, pecSource, type PecPayments, } from './irpc-pec.ts'; import { normalBook, normalCurrent } from './irpc-normal.ts'; import { irpcBook, irpcCurrent } from './irpc-withholdings.ts'; import { acquisitionScope } from './iva-acquisitions.ts'; import { closureFingerprint } from './iva-closure.ts'; import { addFractions, subtractFractions, decimalFraction, fraction, fractionPresentation, type FiscalFraction, } from './fiscal-rational.ts'; export const annualSettlementVersion = 'IRPC-annual-settlement/1'; export const annualSettlementSource = 'CIRPC, arts. 63 e 67 (Lei 34/2007 e natureza da retenção na redacção aplicável da Lei 12/2025); Regulamento, Decreto 9/2008, arts. 21(2–5) e 27(1–2/6). Recorte: 2026, residente no regime geral, ano civil e MZN. Colecta corrente válida, retenções efectivamente sofridas por conta e PPC comprovados. PEC/créditos positivos e tributação autónoma ficam fora deste fecho inicial. Art. 27(6): montante inferior a 100 MZN sem cobrança/reembolso; saldo aritmético exacto conservado. Saldo simulado por colecta projectada; não é declaração submetida, pagamento ou reembolso recebido.'; type State = '' | 'known' | 'absent'; type Evidence = { state: State; amount: string; reference: string }; type Group = { state: State; reference: string }; export type AnnualWithholding = FiscalProofParcel & { id: string; rowId: string; paymentId: string; sourceKey: string; subjectNuit: string; year: string; amount: string; incomeIncluded: '' | 'yes' | 'no'; reference: string; }; export type AnnualPpc = FiscalProofParcel & { id: string; document: string; issuer: string; date: string; subjectNuit: string; year: string; currency: string; proofAmount: string; amount: string; effective: '' | 'yes' | 'no'; reference: string; }; type AnnualRecord = { version: typeof annualSettlementVersion; key: string; createdAt: string; model: AnnualModel; }; export type AnnualBook = { version: 1 | 2 | 3; subjectNuit: string; year: string; reference: string; assessment: '' | 'normal' | 'special'; assessmentKey: string; assessmentReference: string; withholdings: Group & { rows: AnnualWithholding[] }; ppc: Group & { rows: AnnualPpc[] }; pec: Evidence; pecPayments?: PecPayments; credits: Evidence; internationalCredits?: InternationalCredits; creditCarry?: CreditCarry; economicCredits?: EconomicCredits; investmentCredit?: InvestmentCredit; result?: AnnualRecord; history: AnnualRecord[]; }; export const annualSource = (b: AnnualBook) => { const excluded = b.internationalCredits ? b.pecPayments ? 'Créditos económicos/benefícios positivos' : 'PEC/créditos económicos/benefícios positivos' : b.pecPayments ? 'Créditos próprios positivos' : 'PEC/créditos positivos'; return ( annualSettlementSource.replace( 'PEC/créditos positivos', b.economicCredits ? b.pecPayments ? 'Benefícios positivos' : 'PEC/benefícios positivos' : excluded, ) + (b.pecPayments ? ' ' + pecSource : '') + (b.internationalCredits ? ' ' + internationalCreditSource : '') + (b.creditCarry ? ' ' + carrySource : '') + (b.economicCredits ? ' ' + economicSource : '') + (b.investmentCredit ? ' ' + investmentCreditSource : '') ); }; export function prepareInvestmentCredit( d: Record, b: AnnualBook, ): AnnualBook { if (b.investmentCredit) return b; const next = prepareInternationalBook(b), c = newInvestmentCredit(), a = annualAssessment(d); c.subjectNuit = b.subjectNuit; c.year = b.year; c.assessmentKey = b.assessmentKey; c.qualification.from = a.period?.from ?? ''; c.qualification.to = a.period?.to ?? ''; return { ...next, version: 2, investmentCredit: c }; } export function prepareInvestmentCarry( d: Record, b: AnnualBook, ): AnnualBook { const next = prepareInvestmentCredit(d, b); if (next.investmentCredit!.carryForward) return next; return { ...next, version: 3, investmentCredit: { ...next.investmentCredit!, version: 2, carryForward: { reference: '', useReconciled: '', currentState: '', currentReference: '', }, }, }; } export function prepareEconomicBook(b: AnnualBook): AnnualBook { if (b.economicCredits) return b; const next = prepareInternationalBook(b), e = newEconomicCredits(), old = next.internationalCredits!.economic; if (old.state === 'absent') { e.state = 'absent'; e.reference = old.reference; } return { ...next, economicCredits: e }; } export function prepareCreditCarry(b: AnnualBook): AnnualBook { return b.creditCarry ? b : { ...b, creditCarry: newCreditCarry() }; } export function prepareInternationalBook(b: AnnualBook): AnnualBook { if (b.internationalCredits) return b; const c = newInternationalCredits(), old = b.credits; if ( old.state === 'absent' || (old.state === 'known' && old.amount === '0') ) { c.economic = structuredClone(old); c.benefits = structuredClone(old); if (old.state === 'absent') { c.state = 'absent'; c.reference = old.reference; } } return { ...b, internationalCredits: c }; } const evidence = (): Evidence => ({ state: '', amount: '', reference: '' }); export const newAnnualBook = (): AnnualBook => ({ version: 1, subjectNuit: '', year: '', reference: '', assessment: '', assessmentKey: '', assessmentReference: '', withholdings: { state: '', reference: '', rows: [] }, ppc: { state: '', reference: '', rows: [] }, pec: evidence(), credits: evidence(), history: [], }); export const newAnnualPpc = (id: string): AnnualPpc => ({ id, document: '', issuer: '', date: '', subjectNuit: '', year: '', currency: 'MZN', proofAmount: '', amount: '', effective: '', reference: '', }); export const newInternationalProof = (id: string): InternationalTaxProof => ({ ...newAnnualPpc(id), incomeTax: '', taxReference: '', exerciseReference: '', }); const zero = () => fraction(0n), cmp = (a: FiscalFraction, b: FiscalFraction) => BigInt(a.numerator) * BigInt(b.denominator) - BigInt(b.numerator) * BigInt(a.denominator); const iso = (s: string) => /^20\d{2}-\d{2}-\d{2}$/.test(s) && Number.isFinite(Date.parse(s)) && new Date(s).toISOString().slice(0, 10) === s; const moneyInput = (s: string) => { if (!/^\d{1,18}(\.\d{1,2})?$/.test(s)) throw Error( 'MontanteMZN em falta/inválido;máximo dois decimais,sem zero presumido.', ); return decimalFraction(s); }; const canonical = (s: string) => s.normalize('NFKC').trim().toLocaleLowerCase('pt').replace(/\s+/g, ' '); const proofIdentity = (issuer: string, document: string, _date: string) => JSON.stringify([canonical(issuer), canonical(document)]); function store(d: Record) { const s = JSON.parse( inputText(d.modelo_a_snapshot || '{"version":1,"books":{}}'), ); if ( s.version !== 1 || !s.books || typeof s.books !== 'object' || Array.isArray(s.books) ) throw Error('Livros fiscais não recuperáveis;originais conservados.'); return s; } function books(d: Record): Record { const m = store(d).irpcAnnual; if (m === undefined) return {}; if (!m || typeof m !== 'object' || Array.isArray(m)) throw Error('MapaL8 não recuperável;originais conservados.'); return m; } export function validateAnnual(b: AnnualBook) { if (b?.investmentCredit !== undefined) validateInvestmentCredit(b.investmentCredit); if (b?.economicCredits !== undefined) validateEconomic(b.economicCredits); if (b?.creditCarry !== undefined) validateCreditCarry(b.creditCarry); if (b?.pecPayments !== undefined) validatePec(b.pecPayments); if (b?.internationalCredits !== undefined) validateInternational(b.internationalCredits); if ( !b || ![1, 2, 3].includes(b.version) || (b.version >= 2 && b.investmentCredit === undefined) || (b.investmentCredit !== undefined && b.version !== (b.investmentCredit.carryForward ? 3 : 2)) || [ 'subjectNuit', 'year', 'reference', 'assessmentKey', 'assessmentReference', ].some((k) => typeof b[k as 'year'] !== 'string') || !['', 'normal', 'special'].includes(b.assessment) || !Array.isArray(b.history) ) throw Error('PreparaçãoL8 não recuperável.'); for (const g of [b.withholdings, b.ppc, b.pec, b.credits]) if ( !g || !['', 'known', 'absent'].includes(g.state) || typeof g.reference !== 'string' ) throw Error('EstadoL8 não recuperável.'); for (const g of [b.pec, b.credits]) if (typeof g.amount !== 'string') throw Error('CréditoL8 não recuperável.'); const w = [ 'id', 'rowId', 'paymentId', 'sourceKey', 'subjectNuit', 'year', 'amount', 'incomeIncluded', 'reference', ], p = Object.keys(newAnnualPpc('')); for (const [rows, keys] of [ [b.withholdings.rows, w], [b.ppc.rows, p], ] as const) if ( !Array.isArray(rows) || new Set(rows.map((r) => r?.id)).size !== rows.length || rows.some( (r) => !r || keys.some( (k) => typeof (r as unknown as Record)[ k ] !== 'string', ), ) ) throw Error( 'ComprovativosL8 não recuperáveis ou identificador repetido.', ); for (const r of [...b.withholdings.rows, ...b.ppc.rows]) validateProofParcel(r); if ( b.withholdings.rows.some( (r) => !['', 'yes', 'no'].includes(r.incomeIncluded), ) || b.ppc.rows.some((r) => !['', 'yes', 'no'].includes(r.effective)) ) throw Error('QualificaçãoL8 não recuperável.'); for (const r of [b.result, ...b.history]) if ( r && (r.version !== annualSettlementVersion || typeof r.key !== 'string' || typeof r.createdAt !== 'string' || !r.model || !Array.isArray(r.model.pending)) ) throw Error('HistóricoL8 não recuperável.'); } export function annualBook(d: Record) { const b = books(d)[acquisitionScope(d)]; if (b) validateAnnual(b); return b; } export function saveAnnualBook(d: Record, b: AnnualBook) { validateAnnual(b); return JSON.stringify({ ...store(d), irpcAnnual: { ...books(d), [acquisitionScope(d)]: b }, }); } export function annualAssessment(d: Record) { const b = normalBook(d), r = b.result, m = r?.model; return { book: b, record: r, current: normalCurrent(d, b), key: r ? closureFingerprint(r) : '', subjectNuit: b.base?.subjectNuit ?? '', year: b.year, period: m?.periodsFx ? { from: m.periodsFx.input.from, to: m.periodsFx.input.to } : (m?.fiscalPeriod ?? m?.assessment?.period ?? null), kind: b.special ? ('special' as const) : ('normal' as const), colecta: b.special ? (m?.special?.colecta ?? null) : (m?.colecta ?? null), autonomous: b.special ? (m?.special?.expenses.autonomousTax ?? null) : zero(), }; } export function reuseAnnualAssessment( d: Record, b: AnnualBook, ): AnnualBook { const a = annualAssessment(d); return { ...b, subjectNuit: b.subjectNuit || a.subjectNuit, year: b.year || a.year, assessment: a.kind, assessmentKey: a.key, assessmentReference: b.assessmentReference || a.book.assessment?.reference || '', }; } export function annualWithholdingOptions(d: Record) { const b = irpcBook(d), current = irpcCurrent(d, b); return b.rows.flatMap((r) => r.allocations.map((a) => { const p = b.payments.find((p) => p.id === a.paymentId), v = b.result?.rows.find((v) => v.id === r.id), issues: string[] = []; if (!current || !b.result) issues.push('Recalcule e guardeL5 com as entradas actuais.'); if ( r.direction !== 'received' || r.origin !== 'effective' || v?.direction !== 'received' || v.status !== 'calculated' || v.nature !== 'on_account' || r.settlement !== 'complete' || v.settled === null ) issues.push( 'Apenas retenção recebida/efectiva por conta,calculada e reconciliada emL5;remessa por terceiros,definitiva ou projecção não é crédito próprio.', ); if ( !p || p.kind !== 'withholding_proof' || p.currency !== 'MZN' || r.currency !== 'MZN' || !iso(p.date) || !p.reference.trim() ) issues.push( 'Comprovativo de retenção sofrida emMZN em falta ou fora do recorte.', ); return { rowId: r.id, paymentId: a.paymentId, document: p?.reference ?? '', issuer: r.counterparty, date: p?.date ?? '', eventDate: v?.eventDate ?? '', year: v?.eventDate.slice(0, 4) ?? '', amount: a.amount, proofAmount: p?.amount ?? '', identity: proofIdentity( r.counterparty, p?.reference ?? '', p?.date ?? '', ), key: closureFingerprint([r, v, p, a]), ready: !issues.length, reason: issues.join(' '), }; }), ); } export function reuseAnnualWithholding( d: Record, b: AnnualBook, rowId: string, paymentId: string, id: string, ): AnnualBook { const o = annualWithholdingOptions(d).find( (o) => o.rowId === rowId && o.paymentId === paymentId, ); if (!o) throw Error('ComprovativoL5 não encontrado;originais conservados.'); if ( b.withholdings.rows.some( (r) => r.rowId === rowId && r.paymentId === paymentId, ) ) throw Error( 'Retenção/prova já seleccionada;altere a parcela existente sem duplicar.', ); return { ...b, withholdings: { ...b.withholdings, rows: [ ...b.withholdings.rows, { id, rowId, paymentId, sourceKey: o.key, subjectNuit: b.subjectNuit, year: o.year, amount: o.amount, incomeIncluded: '', reference: '', }, ], }, }; } function dependencies(d: Record, includeInvestment = false) { let normal: unknown, L5: unknown; try { const a = annualAssessment(d); normal = [a.record, a.current]; } catch (e) { normal = String(e); } try { const b = irpcBook(d); L5 = [b.rows, b.payments, b.result, irpcCurrent(d, b)]; } catch (e) { L5 = String(e); } return [ normal, L5, Object.entries(books(d)) .filter(([k]) => k !== acquisitionScope(d)) .map(([k, b]) => [ k, b.subjectNuit, b.year, b.withholdings, b.ppc, ...(b.pecPayments ? [b.pecPayments] : []), ...(b.internationalCredits ? [b.internationalCredits] : []), ...(b.creditCarry ? [b.creditCarry] : []), ...(b.economicCredits ? [b.economicCredits] : []), ...(includeInvestment && b.investmentCredit ? [b.investmentCredit] : []), ]), ]; } function key(d: Record, b: AnnualBook) { const { result: _, history: __, ...input } = b; return closureFingerprint([ annualSettlementVersion, acquisitionScope(d), input, dependencies(d, !!b.investmentCredit), ]); } export function annualCurrent(d: Record, b: AnnualBook) { return !!b.result && b.result.key === key(d, b); } export function calculateAnnual(d: Record, b: AnnualBook) { validateAnnual(b); const { result: _result, history: _history, ...input } = b; const pending: string[] = [], warn: string[] = []; let assessment: ReturnType | null = null, colecta: FiscalFraction | null = null; let options: ReturnType = []; try { assessment = annualAssessment(d); const a = assessment, m = a.record?.model; if ( !a.record || !a.current || a.key !== b.assessmentKey || b.assessment !== a.kind ) pending.push( 'Colecta de origem ausente,alterada ou não corrente;reutilize a execuçãoL6/L7 aplicável,não some nem contorne efeitosL7.', ); if ( !/^\d{9}$/.test(b.subjectNuit) || b.subjectNuit !== a.subjectNuit || b.year !== '2026' || b.year !== a.year || a.book.scope !== 'resident_general' || m?.currency !== 'MZN' || a.period?.from !== '2026-01-01' || a.period?.to !== '2026-12-31' ) pending.push( 'Entidade/NUIT,exercício ou âmbito fora do recorte residente/ano civil2026/MZN;períodos especiais permanecem separados.', ); if (!b.reference.trim() || !b.assessmentReference.trim()) pending.push( 'Falta suporte do fecho do sujeito/exercício e da colecta seleccionada.', ); if (!a.colecta || cmp(a.colecta, zero()) < 0n) pending.push( 'Colecta aplicável indeterminada;uma parcelaL6 não substitui totalL7 pendente.', ); else colecta = structuredClone(a.colecta); if ( a.kind === 'special' && (!m?.special || !a.autonomous || cmp(a.autonomous, zero()) !== 0n) ) pending.push( 'Tributação autónoma positiva/indeterminada exige liquidação própria;este primeiro saldo não a ignora nem a compensa.', ); } catch (e) { pending.push('Origem da colecta não recuperável: ' + String(e)); } try { options = annualWithholdingOptions(d); } catch (e) { if (b.withholdings.state === 'known' || b.withholdings.rows.length) pending.push('OrigemL5 não recuperável: ' + String(e)); } const group = (g: Group, rows: unknown[], label: string) => { if (!g.state || !g.reference.trim()) pending.push( label + ':identifique valor conhecido,ausência declarada ou informação em falta com suporte.', ); if (g.state === 'absent' && rows.length) pending.push( label + ':ausência declarada contradiz parcelas presentes;conserve e reconcilie.', ); if (g.state === 'known' && !rows.length) pending.push( label + ':não há comprovativos seleccionados;ausência exige declaração própria.', ); }; group(b.withholdings, b.withholdings.rows, 'Retenções sofridas por conta'); group(b.ppc, b.ppc.rows, 'PPC efectuados'); try { if ( b.withholdings.state === 'absent' && options.some( (o) => o.ready && o.year === b.year && cmp(moneyInput(o.amount), zero()) > 0n, ) ) pending.push( 'Ausência de retenções sofridas contradiz provaL5 efectiva por conta no exercício;reconcilie sem a ignorar.', ); } catch (e) { pending.push('Reconciliação da ausência de retenções: ' + String(e)); } for (const [label, e] of [ ...(b.pecPayments ? [] : [['PEC', b.pec] as const]), ...(b.internationalCredits ? [] : [['Créditos com regras próprias', b.credits] as const]), ]) { try { if (!e.state || !e.reference.trim()) throw Error('presença/ausência e suporte em falta'); if (e.state === 'absent') { if (e.amount.trim()) throw Error('ausência contradiz montante preenchido'); } else if (cmp(moneyInput(e.amount), zero()) !== 0n) throw Error( 'montante positivo fora deste recorte:corresponder ordem,limite e transporte próprios;sem abatimento ou reembolso automático', ); } catch (err) { pending.push(label + ': ' + String(err)); } } const claims: Array< FiscalProofParcel & { id: string; kind: | 'withholding' | 'ppc' | 'pec' | 'foreign_credit' | 'economic_credit'; country?: string; positionId?: string; previouslyUsed?: FiscalFraction; identity: string; proofAmount: FiscalFraction | null; value: FiscalFraction | null; sourceKey: string; allocationAmount: FiscalFraction | null; document: string; issuer: string; date: string; subjectNuit: string; year: string; reason: string; } > = []; for (const r of b.withholdings.rows) { const o = options.find( (o) => o.rowId === r.rowId && o.paymentId === r.paymentId, ), issues: string[] = []; let value: FiscalFraction | null = null, proofAmount: FiscalFraction | null = null; try { requireProofParcel(r); if (!o || !o.ready || r.sourceKey !== o.key) throw Error( o?.reason || 'provaL5 ausente ou alterada;reutilize sem duplicar', ); if ( r.subjectNuit !== b.subjectNuit || r.year !== b.year || o.year !== b.year || !o.date.startsWith(b.year + '-') ) throw Error( 'entidade/exercício da retenção não correspondem ao fecho', ); if (r.incomeIncluded !== 'yes' || !r.reference.trim()) throw Error( 'confirme o próprio beneficiário/NUIT e inclusão do rendimento na base do exercício com suporte', ); value = moneyInput(r.amount); proofAmount = moneyInput(o.proofAmount); if (cmp(value, moneyInput(o.amount)) > 0n) throw Error( 'parcela ultrapassa a retenção efectivamente comprovada e afectada emL5', ); if ( b.withholdings.rows.filter( (x) => x.rowId === r.rowId && x.paymentId === r.paymentId, ).length !== 1 ) throw Error( 'retenção/prova repetida;uma afectação por linhaL5', ); if ( assessment?.record?.model.special?.cooperative.status === 'calculated' && cmp(value, zero()) > 0n ) throw Error( 'cooperativa integralmente elegível declara ausência de rendimentos retidos;segregue o casoL7 antes do crédito anual', ); } catch (e) { issues.push(String(e)); value = null; } claims.push({ ...parcelProjection(r), id: r.id, kind: 'withholding', identity: o?.identity ?? '', proofAmount, value, sourceKey: r.sourceKey, allocationAmount: o && value ? moneyInput(o.amount) : null, document: o?.document ?? r.paymentId, issuer: o?.issuer ?? '', date: o?.date ?? '', subjectNuit: r.subjectNuit, year: r.year, reason: issues.join(' '), }); } for (const r of b.ppc.rows) { const issues: string[] = []; let value: FiscalFraction | null = null, proofAmount: FiscalFraction | null = null; try { requireProofParcel(r); if ( !r.document.trim() || !r.issuer.trim() || !r.reference.trim() || r.effective !== 'yes' || r.currency !== 'MZN' || !iso(r.date) || !r.date.startsWith(b.year + '-') || r.subjectNuit !== b.subjectNuit || r.year !== b.year ) throw Error( 'PPC exige comprovativo efectivo,MZN,data,entidade e exercício correspondentes;projecção/tesouraria não é pagamento', ); value = moneyInput(r.amount); proofAmount = moneyInput(r.proofAmount); if (cmp(value, proofAmount) > 0n) throw Error('parcelaPPC ultrapassa o montante comprovado'); } catch (e) { issues.push(String(e)); value = null; } claims.push({ ...parcelProjection(r), id: r.id, kind: 'ppc', identity: proofIdentity(r.issuer, r.document, r.date), proofAmount, value, sourceKey: '', allocationAmount: null, document: r.document, issuer: r.issuer, date: r.date, subjectNuit: r.subjectNuit, year: r.year, reason: issues.join(' '), }); } if (b.pecPayments) { group( b.pecPayments, b.pecPayments.rows, 'PEC pagos no próprio exercício', ); for (const r of b.pecPayments.rows) { let value: FiscalFraction | null = null, proofAmount: FiscalFraction | null = null, previouslyUsed: FiscalFraction | undefined; let reason = ''; try { ({ value, proofAmount, previouslyUsed } = pecPaymentValue( r, b.subjectNuit, b.year, )); } catch (e) { reason = String(e); } claims.push({ ...parcelProjection(r), id: r.id, kind: 'pec', identity: proofIdentity(r.issuer, r.document, r.date), value, proofAmount, previouslyUsed, sourceKey: '', allocationAmount: null, document: r.document, issuer: r.issuer, date: r.date, subjectNuit: r.subjectNuit, year: r.year, reason, }); } } if (b.internationalCredits) { pending.push( ...internationalGroupPending( b.internationalCredits, !!b.economicCredits, !!b.investmentCredit, ), ); const countries = b.internationalCredits.positions.map( (p) => p.country, ); if (new Set(countries).size !== countries.length) pending.push( 'Um país/exercício tem várias posições;consolide rendimentos e comprovativos sob uma única fracção nacional,sem repetir o limite.', ); for (const p of b.internationalCredits.positions) for (const r of p.payments) { let value: FiscalFraction | null = null, proofAmount: FiscalFraction | null = null, reason = ''; try { ({ value, proofAmount } = internationalProofValue( r, b.subjectNuit, b.year, )); } catch (e) { reason = String(e); } claims.push({ ...parcelProjection(r), id: r.id, kind: 'foreign_credit', country: p.country, positionId: p.id, identity: proofIdentity(r.issuer, r.document, r.date), proofAmount, value, sourceKey: '', allocationAmount: null, document: r.document, issuer: r.issuer, date: r.date, subjectNuit: r.subjectNuit, year: r.year, reason, }); } } if (b.economicCredits) { pending.push(...economicGroupPending(b.economicCredits)); if (!b.internationalCredits) pending.push( 'Distinguir o detalhe económico do inventário internacional e dos benefícios; use a preparação existente sem apagar o resumo anterior.', ); for (const r of b.economicCredits.rows) { let value: FiscalFraction | null = null, proofAmount: FiscalFraction | null = null, previouslyUsed: FiscalFraction | undefined, reason = ''; try { ({ value, proofAmount, previouslyUsed } = economicTaxProof(r)); } catch (e) { reason = String(e); } claims.push({ id: r.id, kind: 'economic_credit', positionId: r.id, identity: proofIdentity( r.taxIssuer, r.taxDocument, r.distributionDate, ), parcel: r.taxParcel, parcelReference: r.parcelReference, proofAmount, value, previouslyUsed, sourceKey: '', allocationAmount: null, document: r.taxDocument, issuer: r.taxIssuer, date: r.distributionDate, subjectNuit: r.subjectNuit, year: r.year, reason, }); } } const elsewhere: Array< FiscalProofParcel & { identity: string; subjectNuit: string; year: string; value: FiscalFraction; proofAmount: FiscalFraction; sourceKey: string; kind: | 'ppc' | 'pec' | 'withholding' | 'foreign_credit' | 'economic_credit'; country?: string; previouslyUsed?: FiscalFraction; } > = []; for (const [scope, other] of Object.entries(books(d))) { if (scope === acquisitionScope(d)) continue; try { validateAnnual(other); for (const r of other.economicCredits?.rows ?? []) { if ( b.economicCredits?.rows.some( (x) => economicDistributionIdentity(x) === economicDistributionIdentity(r), ) ) pending.push( 'Parcela de lucros económicos já preparada noutro mapa;consolide sem duplicar o crédito, mesmo com documentos de imposto diferentes.', ); const v = economicTaxProof(r); elsewhere.push({ identity: proofIdentity( r.taxIssuer, r.taxDocument, r.distributionDate, ), parcel: r.taxParcel, parcelReference: r.parcelReference, subjectNuit: r.subjectNuit, year: r.year, ...v, sourceKey: '', kind: 'economic_credit', }); } for (const p of other.internationalCredits?.positions ?? []) { if ( other.subjectNuit === b.subjectNuit && other.year === b.year && b.internationalCredits?.positions.some( (x) => x.country === p.country, ) ) pending.push( 'País ' + p.country + ' já preparado noutro mapa da entidade/exercício;consolide a fracção nacional e usos sem duplicar quotas.', ); for (const r of p.payments) { const v = internationalProofValue( r, other.subjectNuit, other.year, ); elsewhere.push({ ...parcelProjection(r), identity: proofIdentity(r.issuer, r.document, r.date), subjectNuit: r.subjectNuit, year: r.year, ...v, sourceKey: '', kind: 'foreign_credit', country: p.country, }); } } for (const r of other.pecPayments?.rows ?? []) { const p = pecPaymentValue(r, other.subjectNuit, other.year); elsewhere.push({ ...parcelProjection(r), identity: proofIdentity(r.issuer, r.document, r.date), subjectNuit: r.subjectNuit, year: r.year, ...p, sourceKey: '', kind: 'pec', }); } for (const r of other.ppc.rows) elsewhere.push({ ...parcelProjection(r), identity: proofIdentity(r.issuer, r.document, r.date), subjectNuit: r.subjectNuit, year: r.year, value: moneyInput(r.amount), proofAmount: moneyInput(r.proofAmount), sourceKey: '', kind: 'ppc', }); for (const r of other.withholdings.rows) { const source = (store(d).irpcWithholdings ?? {})[scope]; const row = source?.rows?.find( (x: { id: string }) => x.id === r.rowId, ), p = source?.payments?.find( (x: { id: string }) => x.id === r.paymentId, ); if (row && p) elsewhere.push({ ...parcelProjection(r), identity: proofIdentity( row.counterparty, p.reference, p.date, ), subjectNuit: r.subjectNuit, year: r.year, value: moneyInput(r.amount), proofAmount: moneyInput(p.amount), sourceKey: r.sourceKey, kind: 'withholding', }); } } catch (e) { if (other?.subjectNuit === b.subjectNuit) pending.push( 'Outro mapa da mesma entidade não recuperável para conferir duplicações: ' + scope + ';' + String(e), ); } } for (const c of claims) { if (!c.value || !c.proofAmount) continue; const same = claims.filter( (x) => overlappingProofParcels(x, c) && x.value, ), other = elsewhere.filter((x) => overlappingProofParcels(x, c)); let issue = ''; if ( (same.filter((x) => x.kind !== 'withholding').length > 1 && !same.every((x) => x.kind === 'economic_credit')) || new Set(same.map((x) => x.kind)).size > 1 ) issue = 'Mesmo comprovativo repetido ou usado com naturezas diferentes (retenção/PPC/PEC/crédito internacional);reconcilie sem dedução dupla.'; if ( other.some( (x) => x.subjectNuit !== b.subjectNuit || x.year !== b.year, ) ) issue = 'Mesmo comprovativo já associado a outra entidade/exercício;reconcilie a titularidade e a afectação.'; if ( [...same, ...other].some( (x) => x.proofAmount && cmp(x.proofAmount, c.proofAmount!) !== 0n, ) || cmp( addFractions([ ...same.flatMap((x) => (x.value ? [x.value] : [])), ...other.map((x) => x.value), ]), c.proofAmount, ) > 0n ) issue = 'Comprovativo utilizado além do montante disponível ou com montantes divergentes neste/outro mapa.'; if ( (c.kind === 'pec' || c.kind === 'economic_credit') && c.previouslyUsed ) { if ( other.some((x) => x.kind !== c.kind) || [...same, ...other].some( (x) => !x.previouslyUsed || cmp(x.previouslyUsed, c.previouslyUsed!) !== 0n, ) || cmp( addFractions([ c.previouslyUsed, ...same.flatMap((x) => (x.value ? [x.value] : [])), ...other.map((x) => x.value), ]), c.proofAmount, ) > 0n ) issue = 'PEC/IRPC económico com utilização/atribuição anterior divergente, natureza incompatível ou parcelas acima do saldo disponível.'; } if (other.some((x) => x.kind !== c.kind)) issue = 'Comprovativo já afectado a outra natureza (retenção/PPC/PEC/crédito internacional);sem dupla dedução.'; if ( c.kind === 'foreign_credit' && other.some((x) => x.country !== c.country) ) issue = 'Comprovativo estrangeiro associado a outro país/natureza;reconcilie sem duplicação.'; if ( c.kind === 'withholding' && c.sourceKey && c.allocationAmount && cmp( addFractions([ ...claims .filter( (x) => x.kind === 'withholding' && x.sourceKey === c.sourceKey, ) .flatMap((x) => (x.value ? [x.value] : [])), ...elsewhere .filter( (x) => x.kind === 'withholding' && x.sourceKey === c.sourceKey, ) .map((x) => x.value), ]), c.allocationAmount, ) > 0n ) issue = 'Mesma afectação L5 reutilizada além da parcela disponível, ainda que o comprovativo global seja maior.'; if (issue) c.reason = [c.reason, issue].filter(Boolean).join(' '); } for (const c of claims) if (c.reason) pending.push((c.document || c.id) + ': ' + c.reason); const knownWithholdings = addFractions( claims .filter((c) => c.kind === 'withholding' && !c.reason && c.value) .map((c) => c.value!), ), knownPpc = addFractions( claims .filter((c) => c.kind === 'ppc' && !c.reason && c.value) .map((c) => c.value!), ); const positions = b.internationalCredits?.positions.map((p) => { const own = claims.filter( (c) => c.kind === 'foreign_credit' && c.positionId === p.id, ); const m = internationalPosition( p, addFractions( own .filter((c) => !c.reason && c.value) .map((c) => c.value!), ), own.filter((c) => c.reason).map((c) => c.reason), b.subjectNuit, b.year, b.assessmentKey, { ordinary: assessment?.kind === 'normal' && assessment.current && assessment.key === b.assessmentKey, taxableBase: assessment?.record?.model.taxableBase ?? null, colecta: assessment?.colecta ?? null, }, ); pending.push( ...m.pending.map((e) => 'País ' + p.country + ': ' + e), ); return m; }) ?? []; const derivedNational = positions.flatMap((p) => p.nationalDerivation ? [p.nationalDerivation.income] : [], ); const currentBase = assessment?.record?.model.taxableBase; if (currentBase && cmp(addFractions(derivedNational), currentBase) > 0n) pending.push( 'As parcelas estrangeiras com fracção derivada excedem em conjunto a matéria colectável corrente; reconcilie a afectação por país.', ); const economicRows = b.economicCredits?.rows.map((r) => { const issues = claims .filter( (c) => c.kind === 'economic_credit' && c.positionId === r.id && c.reason, ) .map((c) => c.reason); const m = economicPosition( r, b.subjectNuit, b.year, b.assessmentKey, colecta, issues, { ordinary: assessment?.kind === 'normal' && assessment.current && assessment.key === b.assessmentKey, taxableBase: assessment?.record?.model.taxableBase ?? null, }, ); pending.push( ...m.pending.map( (e) => 'Lucros ' + r.distributionDocument + ': ' + e, ), ); return m; }) ?? []; if (b.economicCredits) { if ( currentBase && cmp( addFractions( economicRows.flatMap((r) => r.nationalDerivation ? [r.nationalDerivation.included] : [], ), ), currentBase, ) > 0n ) pending.push( 'As parcelas económicas com quotas derivadas excedem em conjunto a matéria colectável; reconcilie os lucros e acréscimos por origem.', ); if (b.economicCredits.rows.length && assessment?.kind !== 'normal') pending.push( 'Crédito económico delimitado à colecta normal corrente;efeitos L7 exigem correspondência própria.', ); } const investmentPreview = b.investmentCredit && assessment?.record ? calculateInvestmentCredit( b.investmentCredit, assessment.book, assessment.record.model, assessment.key, assessment.current, ) : null; if (b.investmentCredit && !investmentPreview) pending.push('CréditoCBF15 exige colecta L6 recuperável.'); if (investmentPreview) pending.push(...investmentPreview.pending); if ( investmentPreview?.available && cmp(investmentPreview.available, zero()) > 0n && (!investmentPreview.projectCeiling || cmp(investmentPreview.projectCeiling, zero()) > 0n) && b.creditCarry?.lots.length ) pending.push( 'CombinaçãoCBF15 com saldos anteriores exige correspondência própria; transportes anteriores preservados.', ); if ( b.investmentCredit?.qualification.state === 'known' && b.investmentCredit.qualification.eligible === 'yes' && investmentPreview?.nominal && cmp(investmentPreview.nominal, zero()) > 0n ) { for (const [scope, other] of Object.entries(books(d))) { if ( scope === acquisitionScope(d) || other.subjectNuit !== b.subjectNuit || other.year !== b.year || !other.investmentCredit ) continue; try { validateInvestmentCredit(other.investmentCredit); const c = other.investmentCredit; if ( c.qualification.state !== 'known' || c.qualification.eligible !== 'yes' ) continue; if (!c.assets.some(investmentAssetClaimed)) continue; for (const r of b.investmentCredit.assets.filter( investmentAssetClaimed, )) { const id = investmentAssetIdentity(r), others = c.assets.filter( (x) => investmentAssetClaimed(x) && investmentAssetIdentity(x) === id, ); if (!others.length) continue; const proof = creditMoney(r.proofAmount); if ( others.some( (x) => creditCompare( creditMoney(x.proofAmount), proof, ) !== 0n, ) ) pending.push( 'Montante documentalCBF15 contraditório entre mapas; reconcilie a prova.', ); const own = b.investmentCredit.assets.filter( (x) => investmentAssetClaimed(x) && investmentAssetIdentity(x) === id, ); if ( creditCompare( addFractions( [...own, ...others].map((x) => creditMoney(x.amount), ), ), proof, ) > 0n ) pending.push( 'InvestimentoCBF15 atribuído entre mapas ultrapassa o documento efectivo; não duplicar capacidade.', ); } const sameProject = canonicalParcel(c.projectReference) === canonicalParcel(b.investmentCredit.projectReference); const sharedAsset = c.assets .filter(investmentAssetClaimed) .some((r) => b.investmentCredit!.assets.some((p) => overlappingProofParcels( { ...r, identity: investmentAssetIdentity(r) }, { ...p, identity: investmentAssetIdentity(p) }, ), ), ); if (sameProject || sharedAsset) pending.push( 'CBF15 já preparado noutro mapa da entidade; consolide projecto/documentos sem duplicar: ' + scope, ); } catch (e) { pending.push( 'Outro mapaCBF15 não recuperável para conferir duplicação: ' + scope + '; ' + String(e), ); } } } const economicPreview = b.economicCredits ? economicDeduction(economicRows, colecta, true) : null; const remainingForCarry = economicPreview?.afterCredit ?? colecta; const pecAvailable = addFractions( claims .filter((c) => c.kind === 'pec' && !c.reason && c.value) .map((c) => c.value!), ); const carryDuplicates: string[] = []; if (b.creditCarry) for (const [scope, other] of Object.entries(books(d))) { if ( scope === acquisitionScope(d) || other.subjectNuit !== b.subjectNuit ) continue; try { validateAnnual(other); if ( other.creditCarry?.lots.some((r) => b.creditCarry!.lots.some( (x) => carryIdentity(x) === carryIdentity(r), ), ) ) carryDuplicates.push( 'Saldo anterior já preparado noutro mapa da entidade;consolide a origem e usos sem duplicar: ' + scope, ); } catch (e) { carryDuplicates.push( 'Outro mapa da entidade não recuperável para conferir saldos anteriores: ' + scope + ';' + String(e), ); } } const carry = b.creditCarry ? carryPlan( b.creditCarry, b.subjectNuit, b.year, b.assessmentKey, addFractions( positions.flatMap((p) => p.available && !p.pending.length ? [p.available] : [], ), ), pecAvailable, remainingForCarry, carryDuplicates, ) : null; if (carry) pending.push(...carry.pending); if (investmentPreview?.projectCeiling && !pending.length) { const beforeInternational = economicPreview?.afterCredit ?? colecta; const preview = b.internationalCredits ? internationalDeduction( positions, beforeInternational, true, carry?.international ?? undefined, ) : null; const remaining = carry ? subtractFractions( preview?.afterCredit ?? beforeInternational!, carry.priorInternational, ) : (preview?.afterCredit ?? beforeInternational); if (!remaining || cmp(investmentPreview.projectCeiling, remaining) > 0n) pending.push( 'Quota residualCBF15 do projecto excede a colecta após créditos económicos/internacionais; reconcilie a atribuição antes de deduzir.', ); } const ready = pending.length === 0 && colecta !== null, economic = b.economicCredits ? economicDeduction(economicRows, colecta, ready) : null, afterEconomic = economic?.afterCredit ?? colecta; const international = b.internationalCredits ? internationalDeduction( positions, afterEconomic, ready, carry?.international ?? undefined, ) : null; const creditCollecta = ready && carry ? subtractFractions( international?.afterCredit ?? afterEconomic!, carry.priorInternational, ) : (international?.afterCredit ?? afterEconomic); const investment = investmentPreview ? deductInvestmentCredit(investmentPreview, creditCollecta, ready) : null; const afterInvestment = investment?.afterCredit ?? creditCollecta; const pec = b.pecPayments ? pecDeduction( pecAvailable, afterInvestment, ready, carry?.pec ?? undefined, ) : null; const afterPec = ready && carry ? subtractFractions( pec?.afterPec ?? afterInvestment!, carry.priorPec, ) : (pec?.afterPec ?? afterInvestment); const arithmeticBalance = ready ? subtractFractions( subtractFractions(afterPec!, knownWithholdings), knownPpc, ) : null; if ( international && international.insufficientCollecta && cmp(international.insufficientCollecta, zero()) > 0n ) warn.push( 'Crédito elegível sem colecta suficiente:sem reembolso,transporte ou escolha automática da afectação por país.', ); let payable: FiscalFraction | null = null, recoverable: FiscalFraction | null = null, belowMinimum: FiscalFraction | null = null; let status: | 'payable' | 'recoverable' | 'balanced' | 'below_minimum' | 'indeterminate' = 'indeterminate'; if (arithmeticBalance) { const n = BigInt(arithmeticBalance.numerator), abs = fraction( n < 0n ? -n : n, BigInt(arithmeticBalance.denominator), ); payable = zero(); recoverable = zero(); belowMinimum = zero(); if (!n) status = 'balanced'; else if (cmp(abs, fraction(100n)) < 0n) { status = 'below_minimum'; belowMinimum = abs; warn.push( 'Art27(6):saldo inferior a100MZN,sem cobrança/reembolso neste recorte;aritmética conservada,não é transporte de crédito.', ); } else if (n > 0n) { status = 'payable'; payable = abs; } else { status = 'recoverable'; recoverable = abs; } } return { version: annualSettlementVersion, input: structuredClone(input), subjectNuit: b.subjectNuit, year: b.year, assessment: assessment?.record ? { key: b.assessmentKey, kind: b.assessment, version: assessment.record.model.version, createdAt: assessment.record.createdAt, colecta, period: assessment.period, origin: assessment.record.model.origin, } : null, claims, ...(economic ? { economicCredit: economic } : {}), internationalCredit: international, ...(investment ? { investmentCredit: investment } : {}), pecDeduction: pec, ...(carry ? { creditCarry: { ...carry, afterInternational: ready ? creditCollecta : null, afterPec: ready ? afterPec : null, }, } : {}), knownWithholdings, knownPpc, arithmeticBalance, payable, recoverable, belowMinimum, status, pending: [...new Set(pending)], warnings: warn, source: annualSource(b), officialBalancesConsumed: false, submitted: false, refundReceived: false, limitations: [ ...(b.economicCredits ? [ 'Crédito económico: IRPC correspondente, inclusão/acréscimo53 e quota proporcional reconciliados com a colecta corrente. Partilha64(3) separa rendimento elegível e excesso com natureza de mais-valia; associações64(4) têm modalidade/adaptação próprias. Preparação L6 é explícita; exclusão40, benefícios e restantes regras mantêm âmbito próprio. Sem reembolso ou transporte económico presumidos.', ] : []), ...(b.creditCarry ? [ 'Saldos anteriores documentados: escolha explícita das parcelas correntes e anteriores, sem prioridade presumida entre exercícios, reembolso ou criação/consumo de saldos oficiais.', ] : []), ...(b.internationalCredits ? [ (positions.some((p) => p.nationalDerivation) ? 'Crédito internacional do próprio exercício:fracção nacional derivada no caso L6 ordinário com parcela líquida correspondida;CDT e montantes MZN documentados;sem repartição presumida de custos/perdas,transporte ou consumo oficial. ' : 'Crédito internacional do próprio exercício:fracção nacional,convenção e montantes MZN são documentados;sem cálculo presumido,transporte ou consumo oficial. ') + (b.economicCredits ? b.investmentCredit ? 'CBF15 do primeiro exercício no detalhe próprio;restantes benefícios positivos separados;crédito económico no detalhe próprio.' : 'Benefícios positivos ficam separados;crédito económico no detalhe próprio.' : b.investmentCredit ? 'CBF15 do primeiro exercício no detalhe próprio;restantes créditos económicos/benefícios positivos separados.' : 'Créditos económicos/benefícios positivos ficam separados.'), ] : []), b.economicCredits ? 'L8 parcial:benefícios próprios,derivação automática de quotas,inclusão/correcção económica na base,liquidação/associações,obrigações,autónomos,períodos especiais,moedas eM20/M22 separados. Saldos anteriores só quando detalhados e documentados.' : b.creditCarry ? 'L8 parcial:créditos económicos/benefícios,obrigações,tributação autónoma,períodos especiais,outras moedas e correspondência M20/M22 separados. Prazos dos saldos anteriores demonstrados apenas para origens anuais ordinárias documentadas;sem criação automática de transporte.' : b.internationalCredits ? 'L8 parcial:créditos económicos/benefícios positivos,transporte/caducidade,obrigações,tributação autónoma,períodos especiais e outras moedas separados. PEC sem reembolso ou transporte automático.' : b.pecPayments ? 'L8 parcial:transporte/caducidade de PEC, cálculo da obrigação, créditos próprios positivos, tributação autónoma, períodos especiais e outras moedas separados. Excedente PEC não é reembolso nem saldo transportado oficialmente.' : 'L8 parcial:PEC e créditos positivos,tributação autónoma,períodos especiais e pagamentos noutra moeda exigem regras próprias.', 'PPC aqui é pagamento comprovado;não cálculo automático da obrigação ou calendário.', 'Retenção sofrida não é retenção entregue pela empresa por conta de terceiros.', 'Valores racionais exactos;camposM20/M22 e representação não presumidos.', 'Saldo simulado por colecta projectada;sem pagamento,submissão ou reembolso automático.', ], }; } export type AnnualModel = ReturnType; export function recordAnnual( d: Record, b: AnnualBook, now = new Date().toISOString(), ): AnnualBook { return { ...b, history: b.result ? [...b.history, structuredClone(b.result)] : b.history, result: { version: annualSettlementVersion, key: key(d, b), createdAt: now, model: calculateAnnual(d, b), }, }; } const show = (v: FiscalFraction | null) => v ? (fractionPresentation(v).approximate ? '≈' : '') + fractionPresentation(v).decimal + ' MZN (exacto ' + v.numerator + '/' + v.denominator + ')' : 'Indeterminado'; const stateLabel = (s: State) => s === 'known' ? 'Valor conhecido' : s === 'absent' ? 'Ausência declarada' : 'Informação em falta'; export function annualReportRows( d: Record, ): Array<[string, string, string, string]> { try { const b = annualBook(d), r = b?.result; if (!b || !r) return []; const m = r.model; const status = { payable: 'A pagar', recoverable: 'A recuperar', balanced: 'Saldo zero', below_minimum: 'Inferior ao mínimo de cobrança/reembolso', indeterminate: 'Indeterminado', }[m.status]; return [ [ 'IRPC — L8', 'Fecho anual — âmbito e origem', 'NUIT: ' + m.subjectNuit + '; exercício: ' + m.year + '; colecta: ' + show(m.assessment?.colecta ?? null) + '; origem: ' + (m.assessment?.kind === 'special' ? 'L7 qualificado' : 'L6 normal') + '. ' + (annualCurrent(d, b) ? 'Entradas correspondentes.' : 'Histórico; origem/entradas alteradas: recalcule o saldo corrente.') + ' Saldo simulado, não liquidação submetida.', m.input.reference + '; ' + m.input.assessmentReference + '; ' + m.source, ], ...m.claims.map( (c) => [ 'IRPC — L8', (c.kind === 'withholding' ? 'Retenção sofrida' : c.kind === 'pec' ? 'PEC' : c.kind === 'economic_credit' ? 'IRPC correspondente aos lucros' : c.kind === 'foreign_credit' ? 'Imposto estrangeiro' : 'PPC') + ' — ' + (c.document || c.id), 'Entidade: ' + c.subjectNuit + '; exercício: ' + c.year + '; emitente: ' + c.issuer + '; data: ' + c.date + '; comprovado: ' + show(c.proofAmount) + '; parcela: ' + (c.reason ? 'Indeterminado' : show(c.value)) + (c.parcel ? '; parcela documental: ' + c.parcel + '; ' + (c.parcelReference ?? '') : '') + '. ' + (c.reason || 'Reconciliada sem utilização duplicada.'), c.kind === 'economic_credit' ? (m.input.economicCredits?.reference ?? '') + '; ' + (m.input.economicCredits?.rows.find( (r) => r.id === c.id, )?.attributionReference ?? '') : c.kind === 'withholding' ? m.input.withholdings.reference + '; ' + (m.input.withholdings.rows.find( (r) => r.id === c.id, )?.reference ?? '') : c.kind === 'foreign_credit' ? (m.input.internationalCredits?.reference ?? '') + '; ' + (m.input.internationalCredits?.positions .flatMap((p) => p.payments) .find((r) => r.id === c.id)?.reference ?? '') + '; ' + (m.input.internationalCredits?.positions .flatMap((p) => p.payments) .find((r) => r.id === c.id) ?.exerciseReference ?? '') : c.kind === 'pec' ? (m.input.pecPayments?.reference ?? '') + '; ' + (m.input.pecPayments?.rows.find( (r) => r.id === c.id, )?.reference ?? '') + '; utilizações anteriores: ' + (m.input.pecPayments?.rows.find( (r) => r.id === c.id, )?.previouslyUsed ?? '') + ' MZN; ' + (m.input.pecPayments?.rows.find( (r) => r.id === c.id, )?.priorUseReference ?? '') : m.input.ppc.reference + '; ' + (m.input.ppc.rows.find((r) => r.id === c.id) ?.reference ?? ''), ] as [string, string, string, string], ), ...(m.economicCredit ? [ ...m.economicCredit.rows.map( (r) => [ 'IRPC — L8', 'Crédito económico — ' + r.input.distributionDocument, 'Lucros incluídos: ' + r.input.income + ' MZN;IRPC correspondente: ' + r.input.taxAmount + ' MZN;crédito nominal60%: ' + show(r.nominal) + ';acréscimo53 incluído: ' + r.input.grossUpIncluded + ' MZN;quota proporcional: ' + show(r.nationalLimit) + (r.nationalDerivation ? '; derivação L6: colecta ' + show(r.nationalDerivation.colecta) + ' × lucros mais acréscimo53 ' + show( r.nationalDerivation.included, ) + ' / matéria colectável ' + show( r.nationalDerivation .taxableBase, ) + '; exacta ' + r.nationalLimit?.numerator + '/' + r.nationalLimit?.denominator : '') + (r.liquidation ? '; partilha64(3): valor atribuído ' + show(r.liquidation.attributed) + '; entradas efectivas ' + show(r.liquidation.paidInCapital) + '; limite ' + show(r.liquidation.ceiling) + '; rendimento elegível ' + show(r.liquidation.eligibleIncome) + '; excesso com natureza de mais-valia ' + show( r.liquidation.excessCapitalGain, ) + '; ' + r.liquidation.version + '; ' + r.liquidation.reference : '') + (r.association ? '; ' + r.association.version + '; modalidade ' + r.association.kind + '; tributação efectiva ' + r.association.effectivelyTaxed + '; ' + r.association.reference : '') + ';elegível: ' + show(r.eligible) + ';uso efectivo anterior: ' + show(r.previousUse) + ';disponível: ' + show(r.available) + ';estado: ' + r.status + '. ' + r.pending.join(' | '), r.input.qualificationReference + ';40(1): ' + r.input.article40Reference + ';inclusão: ' + r.input.incomeReference + ';53: ' + r.input.grossUpReference + ';quota: ' + (r.nationalDerivation ? r.nationalDerivation.version + '; correspondência: ' + r.nationalDerivation.reference + '; limite manual anterior conservado, não utilizado' : r.input.nationalLimitReference) + ';uso: ' + r.input.previousUse.reference, ] as [string, string, string, string], ), [ 'IRPC — L8', 'Crédito económico — antes do internacional', 'Disponível: ' + show(m.economicCredit.available) + ';dedução: ' + show(m.economicCredit.deducted) + ';colecta após crédito económico: ' + show(m.economicCredit.afterCredit) + '. Sem reembolso ou criação/consumo de saldo oficial.', m.economicCredit.source + '; ' + (m.input.economicCredits?.reference ?? ''), ] as [string, string, string, string], ] : []), ...(m.internationalCredit ? [ ...m.internationalCredit.positions.map( (p) => [ 'IRPC — L8', 'Crédito internacional — ' + p.country, 'Imposto pago seleccionado: ' + show(p.paid) + '; fracção nacional: ' + show(p.nationalLimit) + (p.nationalDerivation ? '; derivação L6: colecta ' + show(p.nationalDerivation.colecta) + ' × parcela líquida ' + show(p.nationalDerivation.income) + ' / matéria colectável ' + show( p.nationalDerivation .taxableBase, ) + '; exacta ' + p.nationalLimit?.numerator + '/' + p.nationalLimit?.denominator : '; limite documentado') + '; limite CDT: ' + (p.input.treaty === 'no' ? 'Não aplicável documentado' : show(p.treatyLimit)) + (p.treatyDerivation ? '; ' + p.treatyDerivation.version + '; bruto ' + show(p.treatyDerivation.gross) + ' × ' + p.treatyDerivation.rate + '%; período ' + p.treatyDerivation.from + ' a ' + p.treatyDerivation.to + '; ' + p.treatyDerivation.reference + '; ' + p.treatyDerivation.source : '') + '; elegível: ' + show(p.eligible) + '; utilização anterior: ' + show(p.previousUse) + '; disponível: ' + show(p.available) + '; imposto acima dos limites: ' + show(p.aboveLimit) + '. ' + p.pending.join(' | '), p.input.incomeReference + '; ' + (p.nationalDerivation ? 'Limite manual anterior conservado, não utilizado nesta derivação' : p.input.nationalLimitReference) + (p.nationalDerivation ? '; correspondência: ' + p.nationalDerivation.reference + '; ' + p.nationalDerivation.version : '') + '; ' + p.input.treatyReference + '; ' + p.input.previousUse.reference, ] as [string, string, string, string], ), [ 'IRPC — L8', 'Crédito internacional — antes do PEC', 'Disponível conhecido: ' + show(m.internationalCredit.available) + '; dedução: ' + show(m.internationalCredit.deducted) + '; colecta após crédito: ' + show(m.internationalCredit.afterCredit) + '; elegível não deduzido por insuficiência de colecta: ' + show(m.internationalCredit.insufficientCollecta) + (m.creditCarry ? '; crédito corrente não escolhido: ' + show( m.internationalCredit.notSelected ?? null, ) : '') + '. Sem reembolso,transporte ou afectação oficial por país. Estado: ' + stateLabel( m.input.internationalCredits?.state ?? '', ) + '. Créditos económicos/benefícios: ' + stateLabel( m.input.internationalCredits?.economic .state ?? '', ) + ' / ' + stateLabel( m.input.internationalCredits?.benefits .state ?? '', ) + (m.investmentCredit ? '. Resumo anterior dos benefícios conservado, não reaplicado; CBF15 no detalhe próprio.' : '.'), m.internationalCredit.source + '; ' + (m.input.internationalCredits?.reference ?? '') + '; ' + (m.input.internationalCredits?.economic .reference ?? '') + '; ' + (m.input.internationalCredits?.benefits .reference ?? ''), ] as [string, string, string, string], ] : []), ...(m.creditCarry ? [ ...m.creditCarry.lots.map( (l) => [ 'IRPC — L8', 'Saldo anterior — ' + (l.kind === 'pec' ? 'PEC' : 'Crédito internacional ' + l.country) + ' — ' + l.year, 'Remanescente da origem: ' + show(l.opening) + '; usos efectivos: ' + show(l.used) + '; disponível: ' + show(l.available) + '; parcela escolhida: ' + show(l.selected) + '; saldo aritmético posterior: ' + show(l.remaining) + '; último exercício ordinário: ' + (l.lastYear ?? 'Indeterminado') + '; prazo terminado: ' + (l.expired ? 'Sim' : 'Não') + '. ' + l.pending.join(' | '), l.input.originDocument + '; ' + l.input.originReference + '; ' + l.input.ruleReference + '; ' + l.input.usesReference + '; ' + l.input.uses .map( (u) => u.year + ': ' + u.amount + ' MZN; ' + u.document + '; ' + u.reference, ) .join(' | '), ] as [string, string, string, string], ), [ 'IRPC — L8', 'Afectação escolhida entre exercícios', 'Corrente internacional: ' + show(m.creditCarry.international) + '; anterior internacional: ' + show(m.creditCarry.priorInternational) + '; PEC corrente: ' + show(m.creditCarry.pec) + '; PEC anterior: ' + show(m.creditCarry.priorPec) + '; colecta após créditos internacionais: ' + show(m.creditCarry.afterInternational) + '; colecta após todos os PEC: ' + show(m.creditCarry.afterPec) + '. Parcelas só deduzidas se o saldo estiver determinado. Sem criação ou consumo de saldo oficial. ' + m.creditCarry.pending.join(' | '), (m.input.creditCarry?.reference ?? '') + '; ' + (m.input.creditCarry?.allocationReference ?? '') + '; ' + m.creditCarry.source, ] as [string, string, string, string], ] : []), ...(m.investmentCredit ? [ ...m.investmentCredit.rows.map( (r) => [ 'IRPC — L8', 'CBF15 — ' + r.input.issuer + ' / ' + r.input.document + ' / ' + r.input.parcel + '; data ' + r.input.date, 'Valor declarado: ' + r.input.amount + ' ' + r.input.currency + '; investimento elegível: ' + show(r.value), r.input.reference + '; ' + r.reason + '; parcela: ' + r.input.parcelReference + '; ' + r.pending.join(' | '), ] as [string, string, string, string], ), [ 'IRPC — L8', 'CBF15 — crédito fiscal por investimento', 'Investimento: ' + show(m.investmentCredit.investment) + '; taxa ' + (m.investmentCredit.rate === null ? 'não aplicável' : m.investmentCredit.rate + '%') + '; nominal ' + show(m.investmentCredit.nominal) + '; uso anterior ' + show(m.investmentCredit.priorUse) + (m.investmentCredit.input.carryForward ? '; TransporteCBF15/1: nominal corrente ' + show( m.investmentCredit.currentNominal ?? null, ) + '; nominal de origem anterior ' + show( m.investmentCredit.carryNominal ?? null, ) + '; parcela expirada ' + show(m.investmentCredit.expired ?? null) + '; ' + m.investmentCredit.input.carryForward .reference + '; investimento corrente ' + m.investmentCredit.input.carryForward .currentState + ': ' + m.investmentCredit.input.carryForward .currentReference : '') + '; disponível ' + show(m.investmentCredit.available) + '; dedução ' + show(m.investmentCredit.deducted) + '; sem colecta neste exercício ' + show(m.investmentCredit.unused) + (m.investmentCredit.projectCeiling ? '; quota documental do projecto ' + show(m.investmentCredit.projectCeiling) : '') + '; colecta após benefício ' + show(m.investmentCredit.afterCredit), m.investmentCredit.version + '; ' + m.investmentCredit.source + (m.investmentCredit.window ? '; JanelaCBF15/1: exercícios ' + m.investmentCredit.window.firstYear + '–' + m.investmentCredit.window.lastYear + '; exercício ' + m.investmentCredit.window.exercise + '/5; ' + (m.investmentCredit.window.status === 'expired' ? 'prazo expirado' : 'dentro do prazo') : '') + '; projecto ' + m.investmentCredit.input.projectReference + '; ' + m.investmentCredit.input.qualification.reference + '; período ' + m.investmentCredit.input.qualification.from + ' a ' + m.investmentCredit.input.qualification.to + '; ' + m.investmentCredit.input.qualification .periodReference + '; ' + m.investmentCredit.input.locationReference + '; ' + 'início ' + m.investmentCredit.input.startDate + '; ' + m.investmentCredit.input.startReference + '; reconhecimento ' + m.investmentCredit.input.recognitionReference + '; exclusividade ' + (m.investmentCredit.input.soleProject === 'no' ? m.investmentCredit.input.projectQuota ?.reference : m.investmentCredit.input .soleProjectReference) + '; outros benefícios: ' + m.investmentCredit.input .noOtherBenefitsReference + (m.investmentCredit.input.carryForward ? '; origens: ' + m.investmentCredit.input.assets .filter( (r) => r.originYear !== undefined, ) .map( (r) => r.issuer + '/' + r.document + '/' + r.parcel + ': exercício ' + r.originYear + '; NUIT ' + r.originNuit + '; projecto ' + r.originProject + ', taxa ' + r.originRate + '%; ' + r.originReference, ) .join(' | ') : '') + '; uso anterior: ' + m.investmentCredit.input.previousUse.reference + '; ' + m.investmentCredit.pending.join(' | '), ] as [string, string, string, string], ] : []), ...(m.pecDeduction ? [ [ 'IRPC — L8', 'PEC — dedução limitada à colecta', 'Estado: ' + stateLabel(m.input.pecPayments?.state ?? '') + '; parcelas disponíveis: ' + show(m.pecDeduction.available) + '; dedução: ' + show(m.pecDeduction.deducted) + '; colecta após PEC, antes de retenções/PPC: ' + show(m.pecDeduction.afterPec) + '; parcela seleccionada não deduzida: ' + show(m.pecDeduction.remaining) + '. Excedente sem reembolso PEC; transporte/caducidade não automáticos. Subtotais não resolvem informação em falta.', (m.input.pecPayments?.reference ?? '') + '; ' + m.pecDeduction.source, ] as [string, string, string, string], ] : []), [ 'IRPC — L8', 'Saldo anual simulado', 'Estado: ' + status + '. Retenções conhecidas: ' + show(m.knownWithholdings) + '; PPC conhecidos: ' + show(m.knownPpc) + '; saldo aritmético: ' + show(m.arithmeticBalance) + '; a pagar: ' + show(m.payable) + '; a recuperar: ' + show(m.recoverable) + '. ' + m.pending.join(' | ') + ' ' + m.warnings.join(' '), m.source, ], [ 'IRPC — L8', 'Estados dos comprovativos', 'Retenções sofridas: ' + stateLabel(m.input.withholdings.state) + '; PPC: ' + stateLabel(m.input.ppc.state) + '. Subtotais conhecidos não substituem informação em falta.', m.input.withholdings.reference + '; ' + m.input.ppc.reference, ], [ 'IRPC — L8', 'PEC e créditos separados', (m.input.pecPayments ? 'Declaração PEC anterior conservada (substituída nesta execução pelo detalhe comprovado): ' : 'PEC: ') + stateLabel(m.input.pec.state) + '; montante declarado: ' + (m.input.pec.amount || 'Não preenchido') + (m.input.internationalCredits ? '; resumo anterior de créditos conservado,substituído nesta execução pelo detalhe: ' : '; créditos: ') + stateLabel(m.input.credits.state) + '; montante declarado: ' + (m.input.credits.amount || 'Não preenchido') + '. Sem dedução, transporte ou reembolso presumidos. ' + m.limitations.join(' '), m.input.pec.reference + '; ' + m.input.credits.reference, ], ]; } catch (e) { return [ [ 'IRPC — L8', 'Não recuperável', String(e), 'Originais e históricos conservados.', ], ]; } } export function annualHtml(d: Record) { const b = annualBook(d); if (!b?.result || !annualCurrent(d, b)) throw Error( 'Calcule e guardeL8 com as fontes actuais antes de exportar.', ); const esc = (s: string) => s.replace( /[&<>"']/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', })[c]!, ); return ( 'IRPC — L8 saldo anual simulado

IRPC — colecta e saldo anual simulado

Não é declaração submetida,pagamento efectuado ou reembolso recebido.

' + annualReportRows(d) .map( (r) => '

' + esc(r[1]) + '

' + esc(r[2]) + '

' + esc(r[3]) + '
', ) .join('') + '' ); }