Files
Investidor-V2/resources/js/components/acquisition-refund.tsx
T

417 lines
17 KiB
TypeScript

import { useState } from 'react';
import {
refundBook,
refundSources,
newRefund,
saveRefundBook,
recordRefund,
refundReportRows,
type RefundBook,
type RefundInput,
} from '@/lib/iva-refund';
export function AcquisitionRefund({
draft,
onChange,
}: {
draft: Record<string, unknown>;
onChange: (field: string, value: string) => void;
}) {
const [error, setError] = useState('');
let b: RefundBook;
try {
b = refundBook(draft);
} catch (e) {
return <p role="alert">{String(e)}</p>;
}
const save = (book: RefundBook) => {
try {
onChange('modelo_a_snapshot', saveRefundBook(draft, book));
setError('');
} catch (e) {
setError(String(e));
}
};
const change = (id: string, p: Partial<RefundInput>) =>
save({
...b,
rows: b.rows.map((r) => (r.id === id ? { ...r, ...p } : r)),
}),
sources = refundSources(draft);
const choice = (
r: RefundInput,
k: 'factsConfirmed' | 'oldestFirst',
label: string,
) => (
<label>
{label}
<select
value={r[k]}
onChange={(e) => change(r.id, { [k]: e.target.value })}
>
<option value="">Por confirmar</option>
<option value="yes">
Sim — documentado ou pressuposto explícito
</option>
<option value="no">Não</option>
</select>
</label>
);
return (
<details className="rounded border p-3">
<summary>L3-D — pedido,decisão e recebimento do reembolso</summary>
<p>
Primeiro,no fecho do período,escolha a parcela destinada ao
pedido27 e calcule a afectação:25=26+27. Apenas26 continua em
reporte. Reutilize a afectação abaixo;crédito já transportado
não é uma nova parcela disponível.
</p>
<p>
Preparar ou apresentar o pedido não é deferimento;deferimento
não é recebimento. Submissão,formulários
regulamentares,suspensões e pagamentos bancários ocorrem fora
doInvesteMoz. O prazo legal não é previsão de caixa. Não se
aplica a antiga obrigação50%/12meses,revogada em2026.
</p>
{error && <p role="alert">{error}</p>}
<button
type="button"
onClick={() =>
save({
...b,
rows: [
...b.rows,
newRefund(
crypto.randomUUID(),
sources.length === 1 ? sources[0] : null,
),
],
})
}
>
Preparar pedido de reembolso geral
</button>
{b.rows.map((r) => (
<fieldset className="rounded border p-3" key={r.id}>
<legend>
Pedido de reembolso —{' '}
{r.source?.period || 'período por escolher'}
</legend>
<label>
Afectação congelada do crédito27
<select
value={sources.findIndex(
(s) =>
s.allocationKey === r.source?.allocationKey,
)}
onChange={(e) => {
const s = sources[Number(e.target.value)];
if (s)
change(r.id, {
source: structuredClone(s),
});
}}
>
<option value={-1}>Escolha a parcela actual</option>
{sources.map((s, i) => (
<option key={s.allocationKey} value={i}>
{s.period} — {s.entityRef} — fecho
{s.closureId}
</option>
))}
</select>
</label>
<label>
Fundamento do pedido
<select
value={r.ground}
onChange={(e) =>
change(r.id, {
ground: e.target
.value as RefundInput['ground'],
})
}
>
<option value="">Por identificar</option>
<option value="four_months">
21(6) — quatro meses e crédito superior100000MZN
</option>
<option value="high_credit">
21(7a) — crédito superior500000MZN
</option>
<option value="cessation">
21(7b) — cessação de actividade
</option>
</select>
</label>
<label>
Período de início do excesso de crédito
<input
type="month"
value={r.originPeriod}
onChange={(e) =>
change(r.id, { originPeriod: e.target.value })
}
/>
</label>
<label>
Data de nascimento do direito à dedução
<input
type="date"
value={r.entitlementDate}
onChange={(e) =>
change(r.id, {
entitlementDate: e.target.value,
})
}
/>
</label>
{r.ground === 'cessation' && (
<label>
Data da cessação de actividade
<input
type="date"
value={r.cessationDate}
onChange={(e) =>
change(r.id, {
cessationDate: e.target.value,
})
}
/>
</label>
)}
<label>
Suporte dos factos e origem do crédito
<textarea
value={r.groundRef}
onChange={(e) =>
change(r.id, { groundRef: e.target.value })
}
/>
</label>
{choice(
r,
'factsConfirmed',
'Factos do fundamento identificados no suporte',
)}
{choice(
r,
'oldestFirst',
'Considerei sequencialmente os créditos mais antigos',
)}
<label>
Referência do pedido ou preparação
<input
value={r.requestReference}
onChange={(e) =>
change(r.id, {
requestReference: e.target.value,
})
}
/>
</label>
<label>
Data do pedido ou prevista
<input
type="date"
value={r.requestDate}
onChange={(e) =>
change(r.id, { requestDate: e.target.value })
}
/>
</label>
<label>
Situação do pedido
<select
value={r.stage}
onChange={(e) =>
change(r.id, {
stage: e.target
.value as RefundInput['stage'],
})
}
>
<option value="preparation">
Em preparação — sem submissão
</option>
<option value="submitted">
Apresentado fora doInvesteMoz — registo
declarado
</option>
</select>
</label>
<label>
Decisão recebida
<select
value={r.decision}
onChange={(e) =>
change(r.id, {
decision: e.target
.value as RefundInput['decision'],
})
}
>
<option value="pending">
Ainda não identificada
</option>
<option value="approved">
Deferimento integral
</option>
<option value="partial">Deferimento parcial</option>
<option value="rejected">Indeferimento</option>
</select>
</label>
{r.decision !== 'pending' && (
<>
<label>
Número ou referência da decisão
<input
value={r.decisionReference}
onChange={(e) =>
change(r.id, {
decisionReference: e.target.value,
})
}
/>
</label>
<label>
Data da decisão
<input
type="date"
value={r.decisionDate}
onChange={(e) =>
change(r.id, {
decisionDate: e.target.value,
})
}
/>
</label>
<label>
Entidade emitente da decisão
<input
value={r.decisionIssuer}
onChange={(e) =>
change(r.id, {
decisionIssuer: e.target.value,
})
}
/>
</label>
<label>
Montante reconhecido na decisão (MZN)
<input
value={r.approvedAmount}
onChange={(e) =>
change(r.id, {
approvedAmount: e.target.value,
})
}
/>
</label>
</>
)}
<h5>Recebimentos registados</h5>
{r.receipts.map((p) => (
<fieldset key={p.id}>
<legend>Recebimento de reembolso</legend>
{(['reference', 'date', 'amount'] as const).map(
(k) => (
<label key={k}>
{k === 'reference'
? 'Referência do recebimento'
: k === 'date'
? 'Data do recebimento'
: 'Montante recebido (MZN)'}
<input
type={
k === 'date' ? 'date' : 'text'
}
value={p[k]}
onChange={(e) =>
change(r.id, {
receipts: r.receipts.map(
(v) =>
v.id === p.id
? {
...v,
[k]: e
.target
.value,
}
: v,
),
})
}
/>
</label>
),
)}
<button
type="button"
onClick={() =>
change(r.id, {
receipts: r.receipts.filter(
(v) => v.id !== p.id,
),
})
}
>
Remover recebimento desta preparação
</button>
</fieldset>
))}
<button
type="button"
onClick={() =>
change(r.id, {
receipts: [
...r.receipts,
{
id: crypto.randomUUID(),
reference: '',
date: '',
amount: '',
},
],
})
}
>
Registar recebimento identificado
</button>
<button
type="button"
onClick={() =>
save({
...b,
rows: b.rows.filter((v) => v.id !== r.id),
})
}
>
Remover pedido desta preparação
</button>
</fieldset>
))}
{b.rows.length > 0 && (
<button
type="button"
onClick={() => {
try {
save(recordRefund(draft, b));
} catch (e) {
setError(String(e));
}
}}
>
Calcular e guardar acompanhamento D
</button>
)}
{refundReportRows(draft).map((r, i) => (
<p key={i}>
<strong>{r[1]}:</strong> {r[2]}
<br />
{r[3]}
</p>
))}
</details>
);
}