import { addFractions, fraction, subtractFractions, fractionPresentation, type FiscalFraction, } from './fiscal-rational.ts'; import { fiscalMoney } from './irpc-normal-schedules.ts'; export const normalCostsVersion = 'IRPC-normal-adjustments/6'; export const costRules = { allowance: [ 'Ajudas de custo/deslocação em viatura própria', 'expenseCorrections', '36(1)e', ], representation: [ 'Despesas de representação', 'expenseCorrections', '36(1)f/36(3)', ], advertising: [ 'Publicidade ordinária — limite anual partilhado', 'expenseCorrections', '36(1)n,Lei20/2009', ], vehicle: [ 'Outros encargos com viatura ligeira de passageiros', 'expenseCorrections', '36(4)', ], fuel: [ 'Combustível — prova do activo/locação e consumo normal', 'expenseCorrections', '36(1)i/36(4)', ], rental: [ 'Aluguer sem condutor — parcela de quota não aceite documentada', 'expenseCorrections', '36(1)h/36(4)', ], credit: [ 'Provisão/perda por imparidade de créditos ordinários', 'expenseCorrections', '28(1)a/29', ], stock: [ 'Provisão/perda por imparidade de existências', 'expenseCorrections', '28(1)b', ], litigation: [ 'Provisão para processo judicial em curso', 'expenseCorrections', '28(1)c', ], provision_reversal: [ 'Reversão de provisão antes deduzida', 'incomeCorrections', '28(2)', ], taxed_reversal: [ 'Reversão contabilística de provisão antes tributada', 'incomeCorrections', '17/28;sem dupla tributação da parcela comprovada', ], prior_cost: [ 'Custo de exercício anterior incluído no resultado actual', 'timing', '18(2)', ], prior_income: [ 'Proveito de exercício anterior incluído no resultado actual', 'timing', '18(2)', ], estimated_work_loss: [ 'Perda estimada em obra plurianual em curso', 'expenseCorrections', '36(1)m,Lei20/2009', ], work: [ 'Resultado de obra plurianual — percentagem/encerramento', 'timing', '19(1–6)', ], } as const; export type CostRule = keyof typeof costRules; export type CostRow = { id: string; rule: '' | CostRule; document: string; line: string; amount: string; sourceCode: string; reference: string; conditions: '' | 'yes'; facts: Record; }; export type NormalCostsInput = { version: 1; rows: CostRow[]; advertisingReference: string; salesOrdinary: '' | 'yes'; creditBase: string; creditPrevious: string; creditReference: string; creditRegime: '' | 'ordinary' | 'regulated'; }; export const newNormalCosts = (): NormalCostsInput => ({ version: 1, rows: [], advertisingReference: '', salesOrdinary: '', creditBase: '', creditPrevious: '', creditReference: '', creditRegime: '', }); export const newCostRow = (id: string): CostRow => ({ id, rule: '', document: '', line: '', amount: '', sourceCode: '', reference: '', conditions: '', facts: {}, }); export function validateNormalCosts(i: NormalCostsInput) { if ( !i || i.version !== 1 || !Array.isArray(i.rows) || [ 'advertisingReference', 'creditBase', 'creditPrevious', 'creditReference', ].some((k) => typeof i[k as 'creditBase'] !== 'string') || !['', 'yes'].includes(i.salesOrdinary) || !['', 'ordinary', 'regulated'].includes(i.creditRegime) ) throw Error('Mapa de custos/provisões/periodização não recuperável.'); if (new Set(i.rows.map((r) => r.id)).size !== i.rows.length) throw Error('Identificador repetido no mapa de custos.'); for (const r of i.rows) if ( !r || [ 'id', 'rule', 'document', 'line', 'amount', 'sourceCode', 'reference', 'conditions', ].some((k) => typeof r[k as 'id'] !== 'string') || (r.rule !== '' && !Object.hasOwn(costRules, r.rule)) || !['', 'yes'].includes(r.conditions) || !r.facts || typeof r.facts !== 'object' || Array.isArray(r.facts) || Object.values(r.facts).some((v) => typeof v !== 'string') ) throw Error( 'Linha de custos/provisões/periodização não recuperável.', ); } type Source = { currency: string; accountingLines: Array<{ code: string; total: string; accountingEffect: string; }>; cashSchedule?: Array<{ salesReceivablesBalance: string | null; openingReceivablesBalance: string; }>; }; export type CostClaim = { document: string; line: string; sourceCode: string; amount: string; }; const z = () => fraction(0n), cmp = (a: FiscalFraction, b: FiscalFraction) => BigInt(a.numerator) * BigInt(b.denominator) - BigInt(b.numerator) * BigInt(a.denominator); const mul = (a: FiscalFraction, n: bigint, d = 1n) => fraction(BigInt(a.numerator) * n, BigInt(a.denominator) * d); const min = (...v: FiscalFraction[]) => v.reduce((a, b) => (cmp(a, b) < 0n ? a : b)), _max0 = (v: FiscalFraction) => (cmp(v, z()) < 0n ? z() : v); const costMoney = (v: FiscalFraction | null) => { if (!v) return 'Indeterminado'; const p = fractionPresentation(v); return ( (p.approximate ? '≈' : '') + p.decimal + ' MZN' + (p.approximate ? ' (exacto ' + v.numerator + '/' + v.denominator + ')' : '') ); }; const identity = (r: { document: string; line: string }) => r.document.trim() + '\u0000' + r.line.trim(); export function reusableCreditBalance(source: Source | null) { const l = source?.cashSchedule?.at(-1); if (!l || l.salesReceivablesBalance === null) return null; try { return addFractions([ fiscalMoney(l.salesReceivablesBalance), fiscalMoney(l.openingReceivablesBalance), ]); } catch { return null; } } export function calculateNormalCosts( input: NormalCostsInput, source: Source | null, existing: CostClaim[], period: { from: string; to: string }, short = false, ) { validateNormalCosts(input); const rows = input.rows, claims = rows.flatMap((r) => [ { ...r }, ...(r.rule === 'work' ? [ { id: r.id, document: r.document, line: r.line + '/custos', sourceCode: r.facts.costSource ?? '', amount: r.facts.bookCost ?? '', }, ] : []), ]), pending: string[] = []; const sourceAmount = (code: string, effect: string) => { const l = source?.accountingLines.find((l) => l.code === code); if (!l || l.accountingEffect !== effect) throw Error('Seleccione uma linha contabilística compatível.'); return fiscalMoney(l.total); }; const pool = (rule: CostRule) => addFractions( rows .filter((r) => r.rule === rule) .map((r) => fiscalMoney(r.amount)), ); const pools: Record< string, { label: string; base: FiscalFraction; previous: FiscalFraction | null; annualLimit: FiscalFraction; accumulatedLimit: FiscalFraction | null; reference: string; } > = {}; const results = rows.map((r) => { const issues: string[] = [], rule = r.rule ? costRules[r.rule] : null, topic = rule?.[1] ?? '', f = r.facts; let amount: FiscalFraction | null = null, accepted: FiscalFraction | null = null, adjustment: FiscalFraction | null = null, limit: FiscalFraction | null = null; const details: string[] = []; const a = (key: string) => { if (!f[key]?.trim()) throw Error('Falta parâmetro: ' + (factLabels[key] ?? key)); return fiscalMoney(f[key]); }; const yesno = (key: string) => { if (!['yes', 'no'].includes(f[key])) throw Error( 'Falta condição documentada: ' + (factLabels[key] ?? key), ); return f[key] === 'yes'; }; const ref = (key: string) => { if (!f[key]?.trim()) throw Error('Falta suporte: ' + (factLabels[key] ?? key)); }; const balance = () => { ref('balanceKey'); if ( rows.some((q) => q !== r && q.facts.balanceKey === f.balanceKey) ) throw Error( 'Saldo/objecto fiscal repetido entre linhas; agregue as parcelas no mesmo mapa para não reutilizar o limite.', ); return a('previous'); }; const checkOrigin = ( code: string, value: FiscalFraction, effect: string, ) => { if (cmp(value, z()) === 0n && !code) return; if (['depreciation', 'interest_expense'].includes(code)) throw Error( 'Parcela de amortização/juros exige reconciliação própria com o mapa existente; sem dupla qualificação neste incremento.', ); const total = sourceAmount(code, effect); const allocated = addFractions( [...existing, ...claims] .filter((c) => c.sourceCode === code) .map((c) => fiscalMoney(c.amount)), ); if (cmp(allocated, total) > 0n) throw Error( 'Parcelas dos mapas excedem a linha de origem; reconcilie sem duplicar ajustamentos.', ); }; if ( !rule || !r.document.trim() || !r.line.trim() || !r.reference.trim() || r.conditions !== 'yes' ) issues.push( 'Regra, documento/linha, condições e suporte em falta.', ); if ( [ ...existing, ...claims.filter((c) => c !== r && c.id !== r.id), ].some((c) => identity(c) === identity(r)) ) issues.push('Documento/linha repetidos entre mapas.'); if (claims.filter((c) => identity(c) === identity(r)).length > 1) issues.push('Documento/linha repetidos no mapa.'); if (short && ['credit', 'advertising'].includes(r.rule)) issues.push( 'Limite anual neste período curto por corresponder;sem proporcionalização ou anualização presumida.', ); if (source?.currency !== 'MZN' || !period.to.startsWith('2026-')) issues.push( 'Recorte anual emMZN com termo em2026 por reconciliar.', ); try { amount = fiscalMoney(r.amount); if (cmp(amount, z()) <= 0n && r.rule !== 'work') throw Error('Identifique parcela positiva conhecida.'); const isIncome = [ 'provision_reversal', 'taxed_reversal', 'prior_income', 'work', ].includes(r.rule); const omitted = r.rule === 'provision_reversal' && f.inResult === 'no'; if (!omitted) checkOrigin( r.sourceCode, amount, isIncome ? 'income' : 'expense', ); else if (r.sourceCode) throw Error( 'Reversão não incluída no resultado não deve repetir uma linha de proveitos.', ); switch (r.rule) { case 'allowance': { const billed = a('billed'), taxed = a('taxedNotBilled'); if (cmp(addFractions([billed, taxed]), amount) > 0n) throw Error( 'Parcelas facturadas e tributadas emIRPS não podem sobrepor-se ou exceder o encargo.', ); const limited = subtractFractions( subtractFractions(amount, billed), taxed, ); adjustment = mul(limited, 1n, 2n); accepted = subtractFractions(amount, adjustment); limit = mul(limited, 1n, 2n); details.push( '50% só da parcela não facturada a clientes nem tributada emIRPS; parcelas mutuamente exclusivas.', ); break; } case 'representation': accepted = mul(amount, 1n, 5n); adjustment = subtractFractions(amount, accepted); details.push( '20% aceite;80% acrescido. Eventual tributação autónoma não calculada, âmbitoL7.', ); break; case 'advertising': { if (f.campaign !== 'no') throw Error( 'Campanha de lançamento com horizonte superior a um ano: periodização36-A e articulação do limite não correspondidas; não tratar como publicidade ordinária.', ); if ( input.salesOrdinary !== 'yes' || !input.advertisingReference.trim() ) throw Error( 'Confirme completude da publicidade e correspondência do volume de vendas normal do exercício à receita declarada.', ); const total = pool('advertising'); limit = mul(sourceAmount('revenue', 'income'), 1n, 100n); pools.advertising = { label: 'Publicidade — limite anual partilhado', base: sourceAmount('revenue', 'income'), previous: null, annualLimit: limit, accumulatedLimit: null, reference: input.advertisingReference, }; const eligible = min(total, limit); accepted = fraction( BigInt(amount.numerator) * BigInt(eligible.numerator) * BigInt(total.denominator), BigInt(amount.denominator) * BigInt(eligible.denominator) * BigInt(total.numerator), ); adjustment = subtractFractions(amount, accepted); details.push( 'Limite único anual1% das vendas normais; repartição aritmética proporcional entre parcelas para a simulação, sem ordem fiscal obrigatória.', ); break; } case 'vehicle': { if (!yesno('passenger')) { accepted = amount; details.push( 'Viatura fora da categoria ligeira de passageiros;36(4)não aplicado, restantes condições ordinárias documentadas.', ); } else { accepted = yesno('publicOrRental') ? amount : mul(amount, 1n, 2n); details.push( '50% dos outros encargos de passageiros, excepto serviço público de transportes/locação na actividade normal; não inclui quotas, aluguer sem condutor ou combustível já discriminados.', ); } adjustment = subtractFractions(amount, accepted); break; } case 'fuel': case 'rental': { let eligible: FiscalFraction; if (r.rule === 'fuel') { eligible = a('supportedNormal'); if (cmp(eligible, amount) > 0n) throw Error( 'Consumo normal comprovado excede o encargo.', ); details.push( '36i: parcela ligada a activo próprio/locado e consumo normal comprovados.', ); } else { const excluded = a('nonAcceptedQuota'); ref('quotaReference'); if (cmp(excluded, amount) > 0n) throw Error( 'Parcela de quota não aceite excede a renda.', ); eligible = subtractFractions(amount, excluded); details.push( '36h: reutiliza parcela de quota não aceite documentada; o portal não apura automaticamente essa quota de viatura.', ); } if (yesno('passenger') && !yesno('publicOrRental')) { if (cmp(eligible, amount) !== 0n) throw Error( 'Articulação da parcela excluída por36h/i com os50% de36(4) ainda não correspondida; este caso combinado fica pendente, sem somar nem repartir correcções por presunção.', ); eligible = mul(eligible, 1n, 2n); details.push( '36(4):50% do encargo; sem parcela excluída concorrente porh/i.', ); } accepted = eligible; adjustment = subtractFractions(amount, accepted); break; } case 'credit': { if (input.creditRegime !== 'ordinary') throw Error( 'Regime das provisões por identificar ou sujeito a supervisão financeira/seguradora28d; sem limites29 aplicados por aproximação.', ); if (!input.creditReference.trim()) throw Error( 'Saldo de créditos ordinários e provisão fiscal anterior por documentar.', ); if (!input.creditBase.trim()) throw Error( 'Créditos ordinários existentes no fim do exercício em falta.', ); if (!input.creditPrevious.trim()) throw Error( 'Provisão fiscal anterior dos créditos em falta; não presumir zero.', ); const base = fiscalMoney(input.creditBase), previous = fiscalMoney(input.creditPrevious), total = pool('credit'), annual = mul(base, 15n, 1000n), accumulated = mul(base, 6n, 100n); pools.credit = { label: 'Créditos — limites anual e acumulado', base, previous, annualLimit: annual, accumulatedLimit: accumulated, reference: input.creditReference, }; if (cmp(previous, accumulated) > 0n) throw Error( 'Provisão fiscal anterior excede6% dos créditos finais; reconcilie subsistência/reversão28(2), sem saldo presumido.', ); limit = min( annual, subtractFractions(accumulated, previous), ); const eligible = min(total, limit); accepted = fraction( BigInt(amount.numerator) * BigInt(eligible.numerator) * BigInt(total.denominator), BigInt(amount.denominator) * BigInt(eligible.denominator) * BigInt(total.numerator), ); adjustment = subtractFractions(amount, accepted); details.push( '29:1,5% anual,6% acumulado sobre créditos da actividade normal existentes no fim; saldo fiscal anterior conhecido. Repartição proporcional do limite único, sem consumir saldo oficial.', ); break; } case 'stock': case 'litigation': { let previous: FiscalFraction; if (r.rule === 'litigation') { if (!yesno('caseOngoing')) { accepted = z(); adjustment = amount; details.push( 'Não há processo judicial em curso; provisão não elegível por28c.', ); break; } if (!yesno('chargeDeductible')) { accepted = z(); adjustment = amount; details.push( 'Obrigação não daria lugar a custo dedutível; provisão não aceite por28c.', ); break; } } else if (!yesno('lossObserved')) { accepted = z(); adjustment = amount; details.push( 'Perda de valor não efectivamente observada; estimativa não aceite por28b.', ); break; } previous = balance(); limit = a( r.rule === 'stock' ? 'observedLoss' : 'obligation', ); if (cmp(previous, limit) > 0n) throw Error( 'Saldo fiscal anterior excede a cobertura actual; reconcilie a reversão28(2).', ); accepted = min(amount, subtractFractions(limit, previous)); adjustment = subtractFractions(amount, accepted); details.push( r.rule === 'stock' ? '28b:limite das perdas efectivamente observadas, incluindo saldo anterior.' : '28c:obrigações de processo judicial em curso que seriam custos dedutíveis, com saldo anterior reconciliado.', ); break; } case 'provision_reversal': case 'taxed_reversal': { const previous = balance(); if (cmp(amount, previous) > 0n) throw Error( 'Reversão excede a parcela fiscal anterior demonstrada.', ); if (!yesno('eventEnded')) throw Error( 'Evento não cessou/não houve utilização diferente; fundamento da reversão por corresponder.', ); const inResult = yesno('inResult'); if (r.rule === 'taxed_reversal' && !inResult) throw Error( 'Só excluir proveito de reversão já incluído na contabilidade e antes não deduzido.', ); accepted = amount; adjustment = r.rule === 'taxed_reversal' ? mul(amount, -1n) : inResult ? z() : amount; details.push( r.rule === 'taxed_reversal' ? 'Parcela antes tributada comprovada; exclui a reversão contabilística sem duplicar dedução.' : '28(2):proveito da provisão antes deduzida; só acresce quando ainda não incluído no resultado.', ); break; } case 'prior_cost': case 'prior_income': { if ( !/^20\d{2}$/.test(f.originalYear) || Number(f.originalYear) >= 2026 ) throw Error( 'Exercício de origem deve ser anterior ao exercício actual.', ); ref('closingEvidence'); const unknown = yesno('unknownAtClose'); accepted = unknown ? amount : z(); adjustment = unknown ? z() : r.rule === 'prior_cost' ? amount : mul(amount, -1n); details.push( unknown ? '18(2):imprevisível ou manifestamente desconhecido no encerramento anterior; imputável ao actual.' : '18(2):conhecido/previsível no encerramento anterior; excluído do actual, sem alterar declarações/históricos anteriores.', ); break; } case 'estimated_work_loss': accepted = z(); adjustment = amount; details.push( '36m:perda meramente estimada em obra em curso não dedutível; custo efectivo não confundido com estimativa.', ); break; case 'work': { const price = a('price'), totalCost = a('totalCost'), incurred = a('incurred'), priorRevenue = a('priorRevenue'), priorCost = a('priorCost'), bookCost = a('bookCost'); ref('projectKey'); if ( rows.some( (q) => q !== r && q.facts.projectKey === f.projectKey, ) ) throw Error( 'Obra repetida; agregue os valores acumulados sem duplicar resultados.', ); checkOrigin(f.costSource ?? '', bookCost, 'expense'); if ( cmp(totalCost, z()) <= 0n || cmp(incurred, totalCost) > 0n || cmp(priorCost, incurred) > 0n || cmp(priorRevenue, price) > 0n ) throw Error( 'Preço, custo total, incorrido e valores fiscais anteriores incoerentes.', ); if (!yesno('consistentMethod')) throw Error( 'Mudança de critério exige correspondência à autorização19(6).', ); const mandatory = yesno('partialBilling') || yesno('ownFractionalDelivery'); let revenue: FiscalFraction, cost: FiscalFraction; if (f.method === 'percentage') { revenue = fraction( BigInt(price.numerator) * BigInt(incurred.numerator) * BigInt(totalCost.denominator), BigInt(price.denominator) * BigInt(incurred.denominator) * BigInt(totalCost.numerator), ); cost = incurred; } else if (f.method === 'closing') { if (mandatory) throw Error( 'Facturação parcial com acabamento correspondente/entrega fraccionada: critério da percentagem obrigatório19(2).', ); const concluded = cmp(mul(incurred, 100n), mul(totalCost, 95n)) >= 0n || yesno('publicReception'); revenue = concluded ? price : z(); cost = concluded ? incurred : z(); } else throw Error( 'Seleccione percentagem de acabamento ou encerramento.', ); if ( cmp(priorRevenue, revenue) > 0n || cmp(priorCost, cost) > 0n ) throw Error( 'Acumulados fiscais anteriores excedem o resultado reconhecível pelo critério; reconcilie sem correcção retrospectiva presumida.', ); const deferred = a('deferredReceipt'); if (cmp(deferred, z()) !== 0n) throw Error( 'Receita antecipada19(5) de montante não zero exige correspondência própria.', ); const currentRevenue = subtractFractions( revenue, priorRevenue, ), currentCost = subtractFractions(cost, priorCost); accepted = currentCost; adjustment = addFractions([ subtractFractions(currentRevenue, amount), subtractFractions(bookCost, currentCost), ]); limit = currentRevenue; details.push( '19:grau=incorrido/custo total;valores fiscais do exercício obtidos dos acumulados menos o já reconhecido. Proveito fiscal corrente:' + costMoney(currentRevenue) + ';custo fiscal corrente:' + costMoney(currentCost) + ';sem imposto/pagamento ou perda estimada presumidos.', ); break; } default: throw Error('Categoria por identificar.'); } } catch (e) { issues.push(e instanceof Error ? e.message : String(e)); accepted = null; adjustment = null; } if (issues.length) { accepted = null; adjustment = null; pending.push((r.document || r.id) + ': ' + issues.join(' ')); } return { ...structuredClone(r), topic, amountValue: amount, accepted, adjustment, limit, status: issues.length ? ('indeterminate' as const) : ('calculated' as const), reason: issues.join(' ') || details.join(' '), ruleSource: rule ? 'CIRPC' + rule[2] : '', }; }); return { input: structuredClone(input), rows: results, pools, pending, effects: results.map((r) => ({ id: r.id, topic: r.topic, amount: r.amountValue, effect: r.adjustment, reason: r.reason, })), net: addFractions( results.flatMap((r) => (r.adjustment ? [r.adjustment] : [])), ), source: 'CIRPC18(2)/19/28/29/36;Lei34/2007,Lei20/2009,alterações4/2012 e19/2013 e diplomas posteriores inventariados. Recorte2026/MZN,condições documentadas,sem efeitos retroactivos ou consumo de saldos oficiais;L7/L8 separados.', }; } export type NormalCostsModel = ReturnType; const factLabels: Record = { billed: 'Facturado a clientes', taxedNotBilled: 'Tributado emIRPS e não facturado', campaign: 'Campanha plurianual', passenger: 'Ligeira de passageiros', publicOrRental: 'Serviço público/locação na actividade normal', supportedNormal: 'Consumo normal comprovado', nonAcceptedQuota: 'Quota não aceite documentada', quotaReference: 'Suporte da quota', balanceKey: 'Identificação do saldo/objecto', previous: 'Parcela fiscal anterior', lossObserved: 'Perda efectivamente observada', observedLoss: 'Perda total observada', caseOngoing: 'Processo judicial em curso', chargeDeductible: 'Obrigação fiscalmente dedutível', obligation: 'Obrigação coberta', eventEnded: 'Evento cessou/utilização diferente', inResult: 'Incluído no resultado', originalYear: 'Exercício de origem', unknownAtClose: 'Imprevisível/desconhecido no encerramento', closingEvidence: 'Suporte do encerramento', projectKey: 'Obra', method: 'Critério', price: 'Preço', totalCost: 'Custo total estimado', incurred: 'Custos incorporados acumulados', priorRevenue: 'Proveitos fiscais anteriores', priorCost: 'Custos fiscais anteriores', costSource: 'Origem dos custos', bookCost: 'Custo contabilizado corrente', partialBilling: 'Facturação parcial com acabamento correspondente', ownFractionalDelivery: 'Venda/entrega fraccionada por conta própria', consistentMethod: 'Critério uniforme e mantido', publicReception: 'Recepção provisória pública', deferredReceipt: 'Receita antecipada proposta', }; const originLabels: Record = { revenue: 'Receitas do plano', cost_of_sales: 'Custo das vendas', operating_expenses: 'Despesas operacionais', personnel: 'Pessoal', depreciation: 'Depreciação contabilística', interest_expense: 'Juros financeiros', }; export function normalCostReport( m: NormalCostsModel, ): Array<[string, string, string, string]> { const money = costMoney; return [ [ 'IRPC normal — L6', 'Custos com limites, provisões e periodização', `Efeito líquido das parcelas resolvidas:${money(m.net)};${m.pending.join(' | ')}`, m.source, ], ...Object.values(m.pools).map( (p) => [ 'IRPC normal — L6', p.label, `Base documentada:${money(p.base)};limite anual:${money(p.annualLimit)};saldo fiscal anterior:${p.previous ? money(p.previous) : 'Não aplicável'};limite acumulado:${p.accumulatedLimit ? money(p.accumulatedLimit) : 'Não aplicável'};limite partilhado entre todas as parcelas, sem consumo do saldo oficial.`, p.reference, ] as [string, string, string, string], ), ...m.rows.map( (r) => [ 'IRPC normal — L6', (r.rule ? costRules[r.rule][0] : 'Categoria por identificar') + ' — ' + r.document + '/' + r.line, `Estado:${r.status === 'calculated' ? 'Calculado no recorte' : 'Informação insuficiente'};montante identificado:${money(r.amountValue)};parcela aceite/custo fiscal ou reversão:${money(r.accepted)};limite/base ou proveito fiscal:${r.limit ? money(r.limit) : r.status === 'calculated' ? 'Sem limite monetário próprio; ver regra' : 'Em falta/não aplicável à parcela'};ajustamento com sinal:${money(r.adjustment)};${r.reason}`, `${r.ruleSource};${r.reference};origem:${originLabels[r.sourceCode] ?? 'Fora do resultado, documentado'};parâmetros:${Object.entries( r.facts, ) .filter(([k]) => factLabels[k]) .map( ([k, v]) => factLabels[k] + ': ' + (v === 'yes' ? 'Sim' : v === 'no' ? 'Não' : v === 'percentage' ? 'Percentagem de acabamento' : v === 'closing' ? 'Encerramento' : (originLabels[v] ?? (v || 'Em falta'))), ) .join( '; ', )};sem alteração do histórico ou saldo oficial.`, ] as [string, string, string, string], ), ]; }