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

174 lines
6.3 KiB
TypeScript

import type { AdvanceFiscalPeriod } from '@/lib/irpc-ppc-obligation';
import {
newPpcObligation,
calculatePpcObligation,
ppcObligationSource,
type PpcObligation,
} from '@/lib/irpc-ppc-obligation';
import { fractionPresentation } from '@/lib/fiscal-rational';
import type { AnnualBook } from '@/lib/irpc-annual-settlement';
export function SimulationIrpcPpcObligation({
book,
period,
onChange,
}: {
book: AnnualBook;
period?: AdvanceFiscalPeriod;
onChange: (value: PpcObligation) => void;
}) {
const p = book.ppcObligation;
if (!p)
return (
<section className="rounded border p-3">
<h5>Estimativa PPC</h5>
<p>
Preparar a estimativa e os meses previstos não regista
pagamentos nem cria deduções na liquidação.
</p>
<button
type="button"
onClick={() =>
onChange(newPpcObligation(book.subjectNuit, book.year))
}
>
Simular PPC
</button>
</section>
);
const m = calculatePpcObligation(
p,
book.subjectNuit,
book.year,
book.assessment,
period,
);
const patch = (changes: Partial<PpcObligation>) =>
onChange({ ...p, ...changes });
const field = (
key:
| 'subjectNuit'
| 'year'
| 'previousYear'
| 'previousTax'
| 'previousWithholdings'
| 'assessmentReference'
| 'withholdingReference',
label: string,
) => (
<label className="block">
{label}
<input
aria-label={label}
value={p[key]}
onChange={(e) => patch({ [key]: e.target.value })}
/>
</label>
);
return (
<section
aria-label="Preparação da estimativa PPC"
className="rounded border p-3"
>
<h5>Estimativa PPC — exercício anterior</h5>
<p>
Reutiliza o titular e exercício ao iniciar. Complete a
liquidação anterior e as retenções documentadas; campos vazios
não equivalem a zero.
</p>
<label className="block">
Enquadramento PPC
<select
aria-label="Enquadramento PPC"
value={p.scope}
onChange={(e) =>
patch({
scope: e.target.value as PpcObligation['scope'],
})
}
>
<option value="">Por confirmar</option>
<option value="ordinary_resident">
Residente geral — actividade comercial, industrial ou
agrícola, período documentado
</option>
<option value="other">
Outro enquadramento — cálculo separado
</option>
</select>
</label>
{p.scope === 'ordinary_resident' && (
<>
{field('subjectNuit', 'NUIT — estimativa PPC')}
{field('year', 'Exercício — estimativa PPC')}
{field('previousYear', 'Exercício anterior — PPC')}
<label className="block">
Exercício anterior civil completo
<select
aria-label="Exercício anterior civil completo"
value={p.previousFullCalendarYear}
onChange={(e) =>
patch({
previousFullCalendarYear: e.target
.value as PpcObligation['previousFullCalendarYear'],
})
}
>
<option value="">Por confirmar</option>
<option value="yes">Sim</option>
<option value="no">
Não — anualização/período especial separado
</option>
</select>
</label>
{field(
'previousTax',
'Imposto liquidado anterior21(1) — MZN',
)}
{field(
'assessmentReference',
'Fonte da liquidação anterior — PPC',
)}
{field(
'previousWithholdings',
'Retenções na fonte anteriores — MZN',
)}
{field(
'withholdingReference',
'Fonte das retenções anteriores — PPC',
)}
</>
)}
{m.pending.length ? (
<p role="status">{m.pending.join(' ')}</p>
) : (
<>
<p>
80% antes de arredondar:{' '}
{fractionPresentation(m.annualBeforeRounding!).decimal}{' '}
MZN. Total das três prestações arredondadas:{' '}
{fractionPresentation(m.total!).decimal} MZN.
</p>
<ul>
{m.schedule.map((s) => (
<li key={s.month}>
{s.month}:{' '}
{fractionPresentation(s.amount).decimal} MZN
</li>
))}
</ul>
</>
)}
<p>
Guardar o rascunho conserva esta preparação; calcular o fecho
anual inclui-a no relatório. Só comprovativos efectivos podem
alimentar as deduções PPC abaixo. Não executa pagamento,
dispensa, guia ou juros.
</p>
<details>
<summary>Fonte e limites</summary>
<p>{ppcObligationSource}</p>
</details>
</section>
);
}