import { inputText } from '../lib/input-text.ts'; import { newSpecialCombinations, specialCombinationsSource, } from '@/lib/irpc-special-combinations'; import type { NormalBook } from '@/lib/irpc-normal'; import { newSpecialInput, newSpecialExpense, newAcceleratedAsset, specialAccelerationSource, specialCessationPriorSource, specialStartPeriodSource, specialMonthlySource, specialSources, type SpecialInput, type Qualification, } from '@/lib/irpc-special'; type Props = { draft: Record; book: NormalBook; save: (b: NormalBook) => void; }; const states = [ ['', 'Informação em falta'], ['known', 'Tratamento conhecido — qualificar condições'], ['absent', 'Ausência declarada com suporte'], ['not_applicable', 'Tratamento não aplicável — justificar'], ] as const; export function QualificationFields({ label, value, onChange, }: { label: string; value: Qualification; onChange: (v: Qualification) => void; }) { const field = ( key: 'from' | 'to' | 'reference' | 'periodReference', text: string, ) => ( ); return (
{value.state === 'known' && ( )} {field( 'reference', 'Prova das condições, ausência ou não aplicação', )} {field('from', 'Período — início (AAAA-MM-DD)')} {field('to', 'Período — termo (AAAA-MM-DD)')} {field( 'periodReference', 'Suporte do período e da vigência aplicável', )}
); } export function SimulationIrpcSpecial({ draft, book: b, save }: Props) { const i = b.special; const start = () => { const next = newSpecialInput(), p = b.periodsFx ?? b.schedules?.period; for (const part of [next.expenses, next.cooperative, next.acceleration]) Object.assign(part.qualification, { from: p?.from ?? b.year + '-01-01', to: p?.to ?? b.year + '-12-31', }); save({ ...b, special: next }); }; if (!i) return (
L7 — benefícios e casos especiais

Preparação opcional e separada do percursoL6 já entregue. Localização e sector não activam benefícios. A liquidação final permanece emL8.

); const change = (patch: Partial) => save({ ...b, special: { ...i, ...patch } }); const yesno = ( label: string, value: string, onChange: (v: '' | 'yes' | 'no') => void, ) => ( ); return (
L7 — qualificação comum e tratamentos documentados

Reutiliza sujeito, NUIT, período, despesas e activos L6. Contexto herdado:sector{' '} {inputText(draft.sector_id ?? 'por identificar')};província{' '} {inputText(draft.province_id ?? 'por identificar')}. A localização, por si só, não concede benefícios. Os valores L6 continuam como referência;os efeitosL7 são apresentados separadamente. Saldo final a pagar/recuperar:âmbitoL8.

{!i.combinations ? ( ) : (
Cumulações — tratamentos, incompatibilidades e limites

{specialCombinationsSource} Reutiliza a cooperativa,os activos,as despesas e os períodos já declarados abaixo. Esta preparação discrimina os benefícios em vez da confirmação global de ausência de outros benefícios;conserva os valores anteriores e não altera automaticamente qualificações ou activos.

{i.combinations.specificState === 'known' && ( )}

Não somar de novo a amortização contabilística ou a parcela anterior recuperada. A redução cooperativa afecta só a colecta sobre a base elegível;o imposto autónomo continua separado. Uma incompatibilidade não escolhe o benefício a conservar nem apaga o declarado. Outros benefícios/excepções sem regra correspondida mantêm o totalL7 indeterminado.

)}
Despesas — tributação autónoma61(4)

{specialSources.expenses}

change({ expenses: { ...i.expenses, qualification } }) } /> {i.expenses.rows.map((r, index) => { const origin = b.schedules?.rows.find( (x) => x.id === r.scheduleId, ), patch = (p: Partial) => change({ expenses: { ...i.expenses, rows: i.expenses.rows.map((x) => x.id === r.id ? { ...x, ...p } : x, ), }, }); return (
{origin ? origin.document + '/' + origin.line : 'Parcela por corresponder'}{' '} — {origin?.amount ?? 'Indeterminado'} MZN

O acréscimo36g já pertence aL6;esta linha só apura o eventual imposto autónomo.

{yesno( 'Incidência61(4) — parcela ' + (index + 1), r.eligible, (eligible) => patch({ eligible }), )}
); })}
Cooperativas abrangidas — artigo12

{specialSources.cooperative} Este incremento exige base integralmente elegível;parcelas mistas continuam explícitas.

change({ cooperative: { ...i.cooperative, qualification }, }) } /> {(i.cooperative.qualification.state === 'known' || i.cooperative.kind !== '' || i.cooperative.allIncomeEligible !== '' || i.cooperative.withheldIncome !== '') && ( <> {yesno( 'Base ordinária integralmente elegível', i.cooperative.allIncomeEligible, (allIncomeEligible) => change({ cooperative: { ...i.cooperative, allIncomeEligible, }, }), )} )}
Amortizações aceleradas — CBF16

{i.combinations ? specialAccelerationSource(i) : i.acceleration.monthly?.continuation ? specialCessationPriorSource : i.acceleration.monthly?.startPeriod ? specialStartPeriodSource : specialSources.acceleration}{' '} Apenas activos já suportados e método constante;prepare explicitamente o recorte anual ou de início de actividade.

change({ acceleration: { ...i.acceleration, qualification }, }) } /> {i.acceleration.qualification.state === 'known' && ( <> {yesno( 'EnquadramentoCBF3 e pressupostos9 documentados', i.acceleration.cbfRequirements, (cbfRequirements) => change({ acceleration: { ...i.acceleration, cbfRequirements, }, }), )} {!i.combinations && yesno( 'Ausência documentada de outros benefícios a cumular', i.acceleration.noOtherBenefits, (noOtherBenefits) => change({ acceleration: { ...i.acceleration, noOtherBenefits, }, }), )} )} {!i.acceleration.monthly ? ( ) : (
CBF16 — reutilizar duodécimos L6

{i.combinations ? specialAccelerationSource(i) : i.acceleration.monthly.continuation ? specialCessationPriorSource : i.acceleration.monthly.startPeriod ? specialStartPeriodSource : specialMonthlySource}{' '} Conserva datas,opção mensal e valores do activo existente;preencha no mapaL6 apenas o que falta ou precisa de correcção.

{!i.acceleration.monthly.continuation && (!i.acceleration.monthly.startPeriod ? ( ) : (
CBF16 — período curto de início de actividade

Período L6: {b.periodsFx?.from || 'Por identificar'}{' '} a {b.periodsFx?.to || 'Por identificar'} ;tipo: {b.periodsFx?.kind || 'Por identificar'} . Reutiliza o período declarado;esta opção não altera datas,activos ou enquadramento.

))} {!i.acceleration.monthly.startPeriod && (!i.acceleration.monthly.continuation ? ( ) : (
CBF16 — cessação e quotas anteriores

{specialCessationPriorSource} Reutiliza o mapaL6;nenhum saldo declarado ou histórico é alterado. PeríodoL6: {b.periodsFx?.from || b.year + '-01-01'}{' '} a {b.periodsFx?.to || b.year + '-12-31'} ;tipo:{b.periodsFx?.kind || 'anual'}. Corrija dados de origem nos mapasL6 quando necessário.

{yesno( 'Duodécimos desde a entrada emuso documentados', i.acceleration.monthly.continuation .monthlyFromStart, (monthlyFromStart) => change({ acceleration: { ...i.acceleration, monthly: { ...i.acceleration .monthly!, continuation: { ...i.acceleration .monthly! .continuation!, monthlyFromStart, }, }, }, }), )}

Cessação da actividade e saída do activo são eventos distintos. Só a saída documentada emL6 exclui o mês do evento. A recuperação de quotas anteriores é aritmética para esta simulação;saldo oficial não é consumido.

))}

Não altera automaticamente o activo nem transforma ausência de documentos em elegibilidade. A versão anterior permanece no histórico depois de calcular e guardar.

)} {i.acceleration.rows.map((r, index) => { const patch = (p: Partial) => change({ acceleration: { ...i.acceleration, rows: i.acceleration.rows.map((x) => x.id === r.id ? { ...x, ...p } : x, ), }, }); return (
Activo qualificado {index + 1} {yesno( 'Condições do activoCBF16 — ' + (index + 1), r.eligible, (eligible) => patch({ eligible }), )}
); })}

Use «Calcular e guardar» abaixo para gravar uma nova versão e apresentar os efeitos. Os históricos anteriores são conservados. M20/M22 mantém apenas correspondências demonstradas;camposL7 não são preenchidos por aproximação.

); }