54 lines
8.8 KiB
TypeScript
54 lines
8.8 KiB
TypeScript
import {prepareCreditCarry, type AnnualBook} from '@/lib/irpc-annual-settlement';
|
|
import {carrySource, newCarryLot, newCarryUse, type CarryLot, type CreditCarry} from '@/lib/irpc-credit-carry';
|
|
import CountrySelect, {type Country} from '@/components/country-select';
|
|
import {countryIsoCodes} from '@/lib/country-iso-codes';
|
|
|
|
const pt = new Intl.DisplayNames(['pt'], {type: 'region'});
|
|
const en = new Intl.DisplayNames(['en'], {type: 'region'});
|
|
const countries: Country[] = countryIsoCodes.filter(code => code !== 'MZ').map(code => ({code, name: pt.of(code) ?? code, name_en: en.of(code) ?? code})).sort((a, b) => a.name.localeCompare(b.name, 'pt'));
|
|
|
|
export function SimulationIrpcCarry({book, save}: {book: AnnualBook; save: (book: AnnualBook) => void}) {
|
|
const c = book.creditCarry;
|
|
if (!c) return <fieldset className="rounded border p-3"><legend>Saldos de exercícios anteriores</legend><p>Se dispõe de remanescentes documentados de crédito internacional ou PEC, prepare a origem e as utilizações efectivas. Os resultados anteriores ficam conservados.</p><button type="button" onClick={() => save(prepareCreditCarry(book))}>Preparar saldos anteriores</button></fieldset>;
|
|
const update = (value: CreditCarry) => save({...book, creditCarry: value});
|
|
const lotChange = (r: CarryLot) => update({...c, lots: c.lots.map(x => x.id === r.id ? r : x)});
|
|
return <fieldset className="space-y-3 rounded border p-3"><legend>Crédito internacional e PEC — exercícios anteriores</legend>
|
|
<p>{carrySource}</p>
|
|
<label className="block">Inventário de saldos anteriores<select aria-label="Estado dos saldos anteriores L8" value={c.state} onChange={e => update({...c, state: e.target.value as CreditCarry['state']})}><option value="">Informação em falta</option><option value="known">Saldos conhecidos</option><option value="absent">Ausência documentada</option></select></label>
|
|
<label className="block">Suporte do inventário<input aria-label="Suporte dos saldos anteriores L8" value={c.reference} onChange={e => update({...c, reference: e.target.value})}/></label>
|
|
{(c.state === 'known' || c.lots.length > 0) && <>
|
|
<p>Consolide uma origem por natureza, país e exercício. Transcreva o montante elegível apurado e o deduzido na origem, com o suporte da regra desse exercício. Imposto estrangeiro acima dos limites de elegibilidade não é remanescente por insuficiência de colecta. Só se aplica aqui o prazo ordinário a exercícios anuais; situações transitórias ou especiais exigem correspondência própria.</p>
|
|
<button type="button" onClick={() => update({...c, lots: [...c.lots, {...newCarryLot(crypto.randomUUID()), subjectNuit: book.subjectNuit}]})}>Registar origem de saldo anterior</button>
|
|
</>}
|
|
{c.lots.map((r, i) => {
|
|
const patch = (v: Partial<CarryLot>) => lotChange({...r, ...v});
|
|
const prefix = 'Saldo anterior ' + (i + 1) + ' — ';
|
|
return <fieldset key={r.id} className="space-y-2 rounded border p-3"><legend>Origem {i + 1}</legend>
|
|
<label className="block">Natureza<select aria-label={prefix + 'Natureza'} value={r.kind} onChange={e => patch({kind: e.target.value as CarryLot['kind']})}><option value="">Por identificar</option><option value="international">Crédito por dupla tributação internacional</option><option value="pec">PEC efectivamente pago</option></select></label>
|
|
{(r.kind === 'international' || r.country) && <CountrySelect countries={countries} label={prefix + 'País estrangeiro'} value={r.country} onChange={country => patch({country})} allowLegacyValue/>}
|
|
{r.kind === 'pec' && <p>O PEC não tem país estrangeiro. A escolha da natureza conserva os valores introduzidos; reconcilie qualquer país anterior.</p>}
|
|
{([['subjectNuit', 'NUIT titular'], ['year', 'Exercício de origem'], ['currency', 'Moeda comprovada'], ['originDocument', 'Declaração/apuramento de origem'], ['originReference', 'Suporte da origem e insuficiência de colecta'], ['ruleReference', 'Regra e período aplicáveis na origem'], ['eligible', 'Montante elegível na origem — MZN'], ['originDeducted', 'Deduzido na origem — MZN'], ['selected', 'Parcela escolhida para este fecho — MZN']] as const).map(([key, label]) => <label key={key} className="block">{label}<input aria-label={prefix + label} value={r[key]} onChange={e => patch({[key]: e.target.value})}/></label>)}
|
|
<label className="block">Exercício de origem anual ordinário<select aria-label={prefix + 'Período ordinário'} value={r.ordinary} onChange={e => patch({ordinary: e.target.value as CarryLot['ordinary']})}><option value="">Informação em falta</option><option value="yes">Sim — documentado</option><option value="no">Não — regra específica por corresponder</option></select></label>
|
|
<label className="block">Remanescente por insuficiência de colecta<select aria-label={prefix + 'Insuficiência de colecta'} value={r.insufficient} onChange={e => patch({insufficient: e.target.value as CarryLot['insufficient']})}><option value="">Informação em falta</option><option value="yes">Sim — documentado</option><option value="no">Não — não é saldo elegível neste percurso</option></select></label>
|
|
<label className="block">Utilizações efectivas posteriores à origem<select aria-label={prefix + 'Estado dos usos'} value={r.usesState} onChange={e => patch({usesState: e.target.value as CarryLot['usesState']})}><option value="">Informação em falta</option><option value="known">Utilizações conhecidas</option><option value="absent">Ausência documentada</option></select></label>
|
|
<label className="block">Suporte do inventário de utilizações<input aria-label={prefix + 'Suporte dos usos'} value={r.usesReference} onChange={e => patch({usesReference: e.target.value})}/></label>
|
|
<p>Inclua utilizações efectivas já ocorridas neste exercício antes desta parcela. Não registe simulações históricas como utilizações fiscais. Crédito internacional admite fracção exacta n/d; não é aplicado arredondamento fiscal.</p>
|
|
{r.usesState === 'known' && <button type="button" onClick={() => patch({uses: [...r.uses, newCarryUse(crypto.randomUUID())]})}>Registar utilização efectiva da origem {i + 1}</button>}
|
|
{r.uses.map((u, j) => <fieldset key={u.id} className="rounded border p-2"><legend>Utilização {i + 1}.{j + 1}</legend>
|
|
{([['year', 'Exercício'], ['amount', 'Montante MZN'], ['document', 'Documento de utilização'], ['reference', 'Suporte']] as const).map(([key, label]) => <label key={key} className="block">{label}<input aria-label={prefix + 'Uso ' + (j + 1) + ' — ' + label} value={u[key]} onChange={e => patch({uses: r.uses.map(x => x.id === u.id ? {...x, [key]: e.target.value} : x)})}/></label>)}
|
|
<button type="button" onClick={() => patch({uses: r.uses.filter(x => x.id !== u.id)})}>Retirar utilização {i + 1}.{j + 1}</button>
|
|
</fieldset>)}
|
|
<button type="button" onClick={() => update({...c, lots: c.lots.filter(x => x.id !== r.id)})}>Retirar origem {i + 1}</button>
|
|
</fieldset>;
|
|
})}
|
|
{(c.state === 'known' || c.currentInternational || c.currentPec || c.allocationReference) && <fieldset className="space-y-2 rounded border p-3"><legend>Escolha das parcelas entre exercícios</legend>
|
|
<p>Escolha quanto deduzir dos créditos correntes e de cada origem anterior. Os créditos internacionais precedem o PEC; a soma fica limitada à colecta. Não se presume prioridade entre exercícios e nenhuma parcela é reduzida automaticamente. Valores não escolhidos ficam identificados, sem criação de transporte oficial.</p>
|
|
<label className="block">Crédito internacional corrente a deduzir — MZN<input aria-label="Parcela corrente internacional L8" value={c.currentInternational} onChange={e => update({...c, currentInternational: e.target.value})}/></label>
|
|
<label className="block">PEC corrente a deduzir — MZN<input aria-label="Parcela corrente PEC L8" value={c.currentPec} onChange={e => update({...c, currentPec: e.target.value})}/></label>
|
|
<label className="block">Suporte da escolha e seus impactos<input aria-label="Suporte da afectação entre exercícios L8" value={c.allocationReference} onChange={e => update({...c, allocationReference: e.target.value})}/></label>
|
|
<button type="button" onClick={() => update({...c, assessmentKey: book.assessmentKey})}>Confirmar afectação à colecta seleccionada</button>
|
|
<p>{c.assessmentKey && c.assessmentKey === book.assessmentKey ? 'Escolha vinculada à colecta seleccionada; o cálculo verifica disponibilidade e limites.' : 'Falta confirmar a escolha na colecta seleccionada. Valores conservados.'}</p>
|
|
</fieldset>}
|
|
</fieldset>;
|
|
}
|