Files
Investidor-V2/resources/js/components/simulation-irpc-carry.tsx
T

432 lines
20 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>
);
}