import { useState } from 'react'; import { ispcEligibilityBook } from '@/lib/ispc-eligibility'; import { ispcWithholdingBook } from '@/lib/ispc-withholding'; import { decimalFraction, addFractions } from '@/lib/fiscal-rational'; import { ispcResidualBook, saveIspcResidualBook, recordIspcResidual, priorOccasionalSettlement, ispcResidualReportRows, ispcFormalPreparationHtml, type ResidualKind, } from '@/lib/ispc-residuals'; export function SimulationIspcResiduals({ draft, onChange, }: { draft: Record; onChange: (field: string, value: string) => void; }) { const [error, setError] = useState(''); if (draft.fiscal_component !== 'ispc') return null; try { const own = ispcResidualBook(draft, 'occasional'), acq = ispcResidualBook(draft, 'acquisitions'), formal = ispcResidualBook(draft, 'formalities'), e = ispcEligibilityBook(draft), w = ispcWithholdingBook(draft); let above = false; try { const sum = addFractions([ decimalFraction(w.input.base), decimalFraction(w.input.priorAnnualPurchases), ]); above = BigInt(sum.numerator) > 2500000n * BigInt(sum.denominator); } catch { /* Unknown is still handled in existing acquisition panel. */ } const book = (k: ResidualKind) => k === 'occasional' ? own : k === 'acquisitions' ? acq : formal; const change = (k: ResidualKind, p: Record) => { const b = book(k); onChange( 'modelo_a_snapshot', saveIspcResidualBook(draft, { ...b, input: { ...b.input, ...p }, }), ); }; const field = ( k: ResidualKind, n: string, label: string, type = 'text', ) => ( ); const select = ( k: ResidualKind, n: string, label: string, options: Array<[string, string]>, ) => ( ); const yesno = (k: ResidualKind, n: string, label: string) => select(k, n, label, [ ['', 'Por esclarecer'], ['yes', 'Sim'], ['no', 'Não'], ]); const save = (k: ResidualKind) => { try { onChange( 'modelo_a_snapshot', saveIspcResidualBook( draft, recordIspcResidual(draft, book(k)), ), ); setError(''); } catch (err) { setError(String(err)); } }; const activities: Array<[string, string]> = [ ['', 'Por identificar'], ['forestry', 'Silvícola'], ['fishery', 'Pesqueira'], ['livestock', 'Pecuária'], ['agriculture', 'Agrícola'], ['poultry', 'Avícola'], ['beekeeping', 'Apícola'], ['other', 'Outra—fora do recorte ocasional'], ]; return (
{error &&

{error}

} {e.input.mode === 'occasional' && (

Operações ocasionais próprias

Percurso do vendedor ocasional, distinto da retenção feita pelo comprador. Uma retenção liberatória comprovada não gera segunda liquidação própria.

{select( 'occasional', 'personType', 'Tipo de pessoa destas operações', [ ['', 'Por identificar'], ['singular', 'Pessoa singular'], ['collective', 'Pessoa colectiva'], ], )} {select('occasional', 'origin', 'Natureza dos dados', [ ['projected', 'Pressupostos de simulação'], ['effective', 'Factos efectivos declarados'], ])} {field('occasional', 'currency', 'Moeda—MZN')} {field( 'occasional', 'operationDate', 'Data das operações', 'date', )} {select('occasional', 'quarter', 'Trimestre2026', [ ['', 'Por identificar'], ['1', '1'], ['2', '2'], ['3', '3'], ['4', '4'], ])} {yesno( 'occasional', 'territory', 'Operação realizada em território nacional', )} {yesno( 'occasional', 'noHabitual', 'Não exerce actividade habitual', )} {yesno( 'occasional', 'sporadic', 'Acto não previsível nem reiterado', )} {select( 'occasional', 'activity', 'Natureza da operação', activities, )} {field( 'occasional', 'reference', 'Documentos ou pressupostos da operação', )} {field( 'occasional', 'amount', 'Volume de todas estas operações do trimestre em MZN', )} {select('occasional', 'settlement', 'Via aplicável', [ ['', 'Por identificar'], ['self', 'Liquidação própria por opção ISPC'], [ 'withheld', 'Retenção liberatória documentada pelo adquirente', ], ])} {own.input.settlement === 'self' && ( <> {yesno( 'occasional', 'allQuarterOperations', 'Inclui todas as operações ocasionais do sujeito passivo no trimestre', )} {field( 'occasional', 'priorYearTurnover', 'Volume de referência2025 para acesso, incluindo zero expresso', )} {field( 'occasional', 'priorYearRef', 'Suporte da referência2025', )} {yesno( 'occasional', 'organizedRequired', 'Obrigado a contabilidade organizada para impostos sobre rendimento', )} {select( 'occasional', 'option', 'Opção para estas operações', [ [ 'preparation', 'Em preparação—apenas cenário', ], ['opted', 'Opção documentada'], ['not_opted', 'Não optou'], ], )} {own.input.option === 'opted' && ( <> {field( 'occasional', 'optionRef', 'Referência da opção', )} {field( 'occasional', 'optionDate', 'Data da opção', 'date', )} )} {field( 'occasional', 'annual2026', 'Volume anual2026 para escalão', )} {select( 'occasional', 'annualOrigin', 'Origem do volume anual2026', [ ['', 'Por identificar'], ['forecast', 'Previsão—cenário'], [ 'closed_year', 'Volume anual encerrado documentado', ], ], )} {field( 'occasional', 'annualRef', 'Suporte ou pressuposto do volume anual2026', )} {field( 'occasional', 'priorInYear', 'Volume de operações anteriores no ano2026', )} {priorOccasionalSettlement(own) && ( <>

Existe retenção liberatória guardada para esta operação. A mudança de via não a apaga nem gera uma segunda prestação.

{yesno( 'occasional', 'withholdingCorrected', 'Retenção anterior corrigida/anulada segundo documento externo', )} {field( 'occasional', 'withholdingCorrectionRef', 'Referência externa da correcção da retenção anterior', )} )} )} {own.input.settlement === 'withheld' && ( <> {yesno( 'occasional', 'buyerIspc', 'Adquirente sujeito passivo ISPC', )} {yesno( 'occasional', 'unregistered', 'Vendedor não inscrito para tributação', )} {field( 'occasional', 'buyerAnnualPurchases', 'Aquisições globais anuais do adquirente, incluindo estas operações', )} {field( 'occasional', 'withheldActual', 'Montante efectivamente retido em MZN', )} {field( 'occasional', 'withheldRef', 'Documento da retenção liberatória', )} )}
)} {(above || acq.result) && (

Aquisições acima do limite global

Reutiliza a aquisição, os seus documentos e o acumulado global guardados acima. A parcela excedente não recebe automaticamente a taxa de 5% nem a taxa de 20% do excesso de vendas ISPC.

{select( 'acquisitions', 'route', 'Tratamento próprio da parcela excedente', [ [ 'unknown', 'Por identificar—mostrar parcelas sem total presumido', ], [ 'ispc_supplier', 'Fornecedor com opção ISPC aplicável', ], [ 'irps_isolated', 'Acto isolado sujeito a IRPS57(2)k', ], ], )} {acq.input.route === 'ispc_supplier' && field( 'acquisitions', 'supplierOptionRef', 'Referência da opção/registo do fornecedor e operações abrangidas', )} {acq.input.route === 'irps_isolated' && ( <> {yesno( 'acquisitions', 'noIspcOnExcess', 'Sem opção ISPC aplicável a esta parcela, segundo documento indicado', )} {yesno( 'acquisitions', 'isolatedAct', 'Acto isolado qualificado pelo artigo8(3h,4)doIRPS', )} {yesno( 'acquisitions', 'incomeInMoz', 'Rendimento obtido em Moçambique', )} {field( 'acquisitions', 'grossExcess', 'Rendimento ilíquido da parcela excedente em MZN—sem dedução de custos ou IVA', )} {field( 'acquisitions', 'grossRef', 'Suporte da base ilíquida', )} {field( 'acquisitions', 'reference', 'Suporte da classificação IRPS desta parcela', )} )}
)}

Formalidades de2026—preparação do B–Geral

O Comunicado AT9/2026indica o B–Geral durante a adaptação do sistema, com pagamentos em Janeiro, Abril, Julho e Outubro. O Modelo30disponível conserva campos antigos; não os aplicamos a2026. Esta preparação não submete nem paga à AT.

{select('formalities', 'sourceKind', 'Cálculo a preparar', [ ['quarter', 'Trimestral habitual'], ['occasional', 'Operações ocasionais próprias'], [ 'acquisitions', 'Retenção da parcela excedente qualificada', ], ])} {formal.input.sourceKind === 'acquisitions' && field( 'formalities', 'retentionFormRef', 'Modelo/código e instrução para entrega das retenções ISPC/IRPS, separados do imposto próprio', )} {field( 'formalities', 'name', 'Nome/designação social—quadro5', )} {field('formalities', 'nuit', 'NUIT—quadro3')} {field( 'formalities', 'fiscalArea', 'Área Fiscal/UGC—quadro3', )} {field( 'formalities', 'address', 'Domicílio fiscal—quadro6', )} {select( 'formalities', 'declaration', 'Tipo de declaração—quadro1', [ ['initial', 'Inicial'], ['substitution', 'Substituição'], ], )} {field( 'formalities', 'formMonth', 'Mês a inscrever no quadro2—não presumido pelo mês de pagamento', )} {field( 'formalities', 'formYear', 'Ano a inscrever no quadro2', )} {field( 'formalities', 'formPeriodRef', 'Instrução/correspondência usada para o período do quadro2', )} {select( 'formalities', 'interestSituation', 'Juros compensatórios—quadro10', [ ['', 'Por esclarecer'], ['none', 'Sem juros, segundo suporte indicado'], ['amount', 'Montante documentado'], ], )} {formal.input.interestSituation === 'amount' && field( 'formalities', 'interestAmount', 'Montante de juros documentado', )} {field( 'formalities', 'interestRef', 'Suporte da situação dos juros', )} {select( 'formalities', 'externalStatus', 'Histórico externo declarado', [ ['preparation', 'Em preparação'], ['submitted', 'Submetido'], ['received', 'Recebido pela AT'], ['paid', 'Pagamento efectuado'], ], )} {formal.input.externalStatus !== 'preparation' && ( <> {field( 'formalities', 'externalRef', 'Referência externa', )} {field( 'formalities', 'externalDate', 'Data do acto externo', 'date', )} )}
{ispcResidualReportRows(draft).map((r, n) => (

{r[1]}: {r[2]} {r[3]}

))}
); } catch (err) { return

{String(err)}

; } }