387 lines
17 KiB
TypeScript
387 lines
17 KiB
TypeScript
import { useState } from 'react';
|
|
import { closureSources } from '@/lib/iva-closure';
|
|
import {
|
|
substitutionBook,
|
|
saveSubstitutionBook,
|
|
newSubstitution,
|
|
previousDeclarations,
|
|
recordSubstitution,
|
|
substitutionReportRows,
|
|
type SubstitutionBook,
|
|
type SubstitutionInput,
|
|
} from '@/lib/iva-substitution';
|
|
export function AcquisitionSubstitution({
|
|
draft,
|
|
onChange,
|
|
}: {
|
|
draft: Record<string, unknown>;
|
|
onChange: (field: string, value: string) => void;
|
|
}) {
|
|
const [error, setError] = useState('');
|
|
let b: SubstitutionBook;
|
|
try {
|
|
b = substitutionBook(draft);
|
|
} catch (e) {
|
|
return <p role="alert">{String(e)}</p>;
|
|
}
|
|
const save = (next: SubstitutionBook) => {
|
|
try {
|
|
onChange('modelo_a_snapshot', saveSubstitutionBook(draft, next));
|
|
setError('');
|
|
} catch (e) {
|
|
setError(String(e));
|
|
}
|
|
};
|
|
const change = (id: string, p: Partial<SubstitutionInput>) =>
|
|
save({
|
|
...b,
|
|
rows: b.rows.map((r) => (r.id === id ? { ...r, ...p } : r)),
|
|
});
|
|
const previous = previousDeclarations(draft, b),
|
|
sources = closureSources(draft);
|
|
return (
|
|
<details className="rounded border p-3">
|
|
<summary>L3-C — substituições e diferencial</summary>
|
|
<p>
|
|
Escolha a declaração anterior e o resultado corrigido do mesmo
|
|
período. Créditos utilizados e pagamentos anteriores
|
|
conservam-se no histórico;registe apenas pagamentos adicionais.
|
|
</p>
|
|
<p>
|
|
O diferencial credor aguarda comunicação dos serviços para
|
|
utilização posterior no campo20. Não compensa automaticamente
|
|
dívida nem cria reporte26. A preparação não submete à
|
|
AT;formulário de substituição e formalidades permanecem fora do
|
|
InvesteMoz.
|
|
</p>
|
|
{error && <p role="alert">{error}</p>}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
save({
|
|
...b,
|
|
rows: [...b.rows, newSubstitution(crypto.randomUUID())],
|
|
})
|
|
}
|
|
>
|
|
Preparar substituição
|
|
</button>
|
|
{b.rows.map((r) => (
|
|
<fieldset className="rounded border p-3" key={r.id}>
|
|
<legend>
|
|
Substituição —{' '}
|
|
{r.prior?.period || 'período por escolher'}
|
|
</legend>
|
|
<label>
|
|
Declaração anterior congelada
|
|
<select
|
|
value={previous.findIndex(
|
|
(p) =>
|
|
JSON.stringify(p) ===
|
|
JSON.stringify(r.prior),
|
|
)}
|
|
onChange={(e) => {
|
|
const p = previous[Number(e.target.value)];
|
|
if (p) {
|
|
const matches = sources.filter(
|
|
(s) => s.period === p.period,
|
|
);
|
|
change(r.id, {
|
|
prior: structuredClone(p),
|
|
...(r.priorDate
|
|
? {}
|
|
: { priorDate: p.declarationDate }),
|
|
...(r.priorReference
|
|
? {}
|
|
: {
|
|
priorReference:
|
|
p.declarationReference,
|
|
}),
|
|
...(r.source === null &&
|
|
matches.length === 1
|
|
? {
|
|
source: structuredClone(
|
|
matches[0],
|
|
),
|
|
}
|
|
: {}),
|
|
});
|
|
}
|
|
}}
|
|
>
|
|
<option value={-1}>
|
|
Escolha a versão anterior
|
|
</option>
|
|
{previous
|
|
.filter((p) => p.id !== r.id)
|
|
.map((p) => (
|
|
<option
|
|
key={JSON.stringify(p)}
|
|
value={previous.indexOf(p)}
|
|
>
|
|
{p.period} — {p.entityRef} — {p.kind}/
|
|
{p.id} — {p.calculatedAt}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
{r.prior && (
|
|
<p>
|
|
Anterior:{r.prior.entityRef};
|
|
{r.prior.origin === 'projected'
|
|
? 'pressuposto de simulação'
|
|
: 'dados efectivos declarados'}
|
|
;pagamentos e reporte conservados na versão
|
|
escolhida.
|
|
</p>
|
|
)}
|
|
<label>
|
|
Resultado L2 corrigido congelado
|
|
<select
|
|
value={sources.findIndex(
|
|
(s) =>
|
|
JSON.stringify(s) ===
|
|
JSON.stringify(r.source),
|
|
)}
|
|
onChange={(e) => {
|
|
const s = sources[Number(e.target.value)];
|
|
if (s)
|
|
change(r.id, {
|
|
source: structuredClone(s),
|
|
});
|
|
}}
|
|
>
|
|
<option value={-1}>
|
|
Escolha a versão corrigida
|
|
</option>
|
|
{sources
|
|
.filter(
|
|
(s) =>
|
|
!r.prior || s.period === r.prior.period,
|
|
)
|
|
.map((s) => (
|
|
<option
|
|
key={JSON.stringify(s)}
|
|
value={sources.indexOf(s)}
|
|
>
|
|
{s.period} — revisão{s.revision} —{' '}
|
|
{s.calculatedAt}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Referência da declaração anterior
|
|
<input
|
|
value={r.priorReference}
|
|
onChange={(e) =>
|
|
change(r.id, { priorReference: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Data da declaração anterior
|
|
<input
|
|
type="date"
|
|
value={r.priorDate}
|
|
onChange={(e) =>
|
|
change(r.id, { priorDate: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Referência da substituição ou preparação
|
|
<input
|
|
value={r.reference}
|
|
onChange={(e) =>
|
|
change(r.id, { reference: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Data da substituição ou prevista
|
|
<input
|
|
type="date"
|
|
value={r.date}
|
|
onChange={(e) =>
|
|
change(r.id, { date: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Motivo da substituição
|
|
<textarea
|
|
value={r.reason}
|
|
onChange={(e) =>
|
|
change(r.id, { reason: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Situação da substituição
|
|
<select
|
|
value={r.stage}
|
|
onChange={(e) =>
|
|
change(r.id, {
|
|
stage: e.target
|
|
.value as SubstitutionInput['stage'],
|
|
})
|
|
}
|
|
>
|
|
<option value="preparation">
|
|
Em preparação — sem submissão
|
|
</option>
|
|
<option value="presented">
|
|
Apresentada fora do InvesteMoz — registo
|
|
declarado
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Juros adicionais23
|
|
<select
|
|
value={r.interest}
|
|
onChange={(e) =>
|
|
change(r.id, {
|
|
interest: e.target
|
|
.value as SubstitutionInput['interest'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por identificar</option>
|
|
<option value="none">
|
|
Sem juros adicionais — motivo identificado
|
|
</option>
|
|
<option value="documented">
|
|
Montante adicional identificado
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{r.interest === 'documented' && (
|
|
<label>
|
|
Montante dos juros adicionais (MZN)
|
|
<input
|
|
value={r.interestAmount}
|
|
onChange={(e) =>
|
|
change(r.id, {
|
|
interestAmount: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
)}
|
|
<label>
|
|
Fonte ou motivo dos juros adicionais
|
|
<input
|
|
value={r.interestRef}
|
|
onChange={(e) =>
|
|
change(r.id, { interestRef: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<h5>Pagamentos adicionais desta substituição</h5>
|
|
{r.payments.map((p) => (
|
|
<fieldset key={p.id}>
|
|
<legend>Pagamento adicional</legend>
|
|
{(['reference', 'date', 'amount'] as const).map(
|
|
(k) => (
|
|
<label key={k}>
|
|
{k === 'reference'
|
|
? 'Referência do pagamento adicional'
|
|
: k === 'date'
|
|
? 'Data do pagamento adicional'
|
|
: 'Montante adicional pago (MZN)'}
|
|
<input
|
|
type={
|
|
k === 'date' ? 'date' : 'text'
|
|
}
|
|
value={p[k]}
|
|
onChange={(e) =>
|
|
change(r.id, {
|
|
payments: r.payments.map(
|
|
(v) =>
|
|
v.id === p.id
|
|
? {
|
|
...v,
|
|
[k]: e
|
|
.target
|
|
.value,
|
|
}
|
|
: v,
|
|
),
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
),
|
|
)}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change(r.id, {
|
|
payments: r.payments.filter(
|
|
(v) => v.id !== p.id,
|
|
),
|
|
})
|
|
}
|
|
>
|
|
Remover pagamento desta preparação
|
|
</button>
|
|
</fieldset>
|
|
))}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change(r.id, {
|
|
payments: [
|
|
...r.payments,
|
|
{
|
|
id: crypto.randomUUID(),
|
|
reference: '',
|
|
date: '',
|
|
amount: '',
|
|
},
|
|
],
|
|
})
|
|
}
|
|
>
|
|
Registar pagamento adicional
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
save({
|
|
...b,
|
|
rows: b.rows.filter((v) => v.id !== r.id),
|
|
})
|
|
}
|
|
>
|
|
Remover substituição desta preparação
|
|
</button>
|
|
</fieldset>
|
|
))}
|
|
{b.rows.length > 0 && (
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
try {
|
|
save(recordSubstitution(draft, b));
|
|
} catch (e) {
|
|
setError(String(e));
|
|
}
|
|
}}
|
|
>
|
|
Calcular e guardar substituições C
|
|
</button>
|
|
)}
|
|
{substitutionReportRows(draft).map((r, i) => (
|
|
<p key={i}>
|
|
<strong>{r[1]}:</strong> {r[2]}
|
|
<br />
|
|
{r[3]}
|
|
</p>
|
|
))}
|
|
</details>
|
|
);
|
|
}
|