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

340 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useState } from 'react';
import {
newRegularization,
regularizationBook,
regularizationSources,
saveRegularizationBook,
recordRegularizations,
regularizationReportRows,
frozenAssetRows,
type RegularizationEvent,
type RegularizationBook,
} from '@/lib/iva-regularizations';
export function AcquisitionRegularizations({
draft,
onChange,
}: {
draft: Record<string, unknown>;
onChange: (field: string, value: string) => void;
}) {
const [error, setError] = useState('');
let b: RegularizationBook;
try {
b = regularizationBook(draft);
} catch (cause) {
return <p role="alert">{String(cause)}</p>;
}
const save = (next: RegularizationBook) => {
try {
onChange('modelo_a_snapshot', saveRegularizationBook(draft, next));
setError('');
} catch (cause) {
setError(String(cause));
}
};
const change = (id: string, patch: Partial<RegularizationEvent>) =>
save({
...b,
events: b.events.map((e) => (e.id === id ? { ...e, ...patch } : e)),
});
const sources = regularizationSources(draft);
const add = (kind: RegularizationEvent['kind']) =>
save({
...b,
events: [
...b.events,
newRegularization(
crypto.randomUUID(),
kind,
sources.at(-1) ?? null,
),
],
});
const labels = {
scope: 'As parcelas e o âmbito correspondem ao evento,sem estender o direito a outros bens/operações',
recorded:
'O valor original foi deduzido ou é pressuposto explicitamente assumido nesta simulação',
annual: 'Bases finais do ano completo22(4),semIVA,incluindo operações fora de campo',
exclusions:
'Excluí vendas de activo usado e operações imobiliárias/financeiras acessórias22(5)',
supplierCorrection:
'O fornecedor anulou/reduziu a operação e emitiu o documento rectificativo',
rightUnchanged:
'O documento conserva o âmbito e as condições de dedução;sem alteração de direito',
};
return (
<details className="rounded border p-3">
<summary>E — activos e regularizações por evento</summary>
<p>
Reutiliza resultados congelados de D e documentos existentes. O
acerto anual usa o IVA elegível antes de D, já limitado por C, e
compara com o deduzido. Uma rectificação da compra tem documento
e prazo próprios. Guardar E não altera as deduções originais;
depois actualize expressamente o apuramento parcial para
conferir F.
</p>
<p>
18.º(6) com afectação mista continua pendente. Não existe
regularização plurianual genérica de activos,correcção de erros
ou incobráveis automatizada neste percurso. Submissão fiscal
fora do InvesteMoz;19–27/restituição em L3.
</p>
{error && <p role="alert">{error}</p>}
<button type="button" onClick={() => add('annual')}>
Preparar acerto anual do pro rata
</button>{' '}
<button type="button" onClick={() => add('purchase_correction')}>
Preparar rectificação da dedução pelo adquirente
</button>
{b.events.map((e, index) => (
<fieldset className="rounded border p-3" key={e.id}>
<legend>
{index + 1}.{' '}
{e.kind === 'annual'
? 'Acerto anual22(6)'
: 'Rectificação51(4)'}
</legend>
<label>
Resultado original congelado
<select
value={sources.findIndex(
(s) =>
JSON.stringify(s) ===
JSON.stringify(e.source),
)}
onChange={(event) => {
const source =
sources[Number(event.target.value)];
if (source)
change(e.id, {
source: structuredClone(source),
rowIds: source.inputs
.filter(
(r) =>
e.kind !== 'annual' ||
r.d?.method === 'pro_rata',
)
.map((r) => r.id),
});
}}
>
<option value={-1}>Seleccione uma versão</option>
{sources.map((s, i) => (
<option key={i} value={i}>
Revisão{s.revision} — {s.calculatedAt}
</option>
))}
</select>
</label>
<p>
Escolher outra versão adopta expressamente as parcelas
dessa versão,conservando os outros dados do evento.
Desmarque parcelas fora do âmbito;não pode regularizar a
mesma aquisição duas vezes.
</p>
{e.source?.inputs.map((r) => (
<label className="block" key={r.id}>
<input
type="checkbox"
checked={e.rowIds.includes(r.id)}
onChange={(event) =>
change(e.id, {
rowIds: event.target.checked
? [...e.rowIds, r.id]
: e.rowIds.filter(
(id) => id !== r.id,
),
})
}
/>
{r.description || r.id} — {r.documentRef} —{' '}
{r.period} —{' '}
{r.origin === 'projected'
? 'Pressuposto de simulação'
: 'Efectivo declarado'}
</label>
))}
<label>
Período da regularização
<input
type="month"
value={e.period}
min="2026-01"
max="2026-12"
onChange={(v) =>
change(e.id, { period: v.target.value })
}
/>
</label>
<label>
Documento/fonte do evento
<input
value={e.reference}
onChange={(v) =>
change(e.id, { reference: v.target.value })
}
/>
</label>
<label>
Motivo e âmbito do evento
<input
value={e.reason}
onChange={(v) =>
change(e.id, { reason: v.target.value })
}
/>
</label>
{e.kind === 'annual' ? (
<>
<label>
Operações anuais finais com direito — sem IVA
(MZN)
<input
value={e.numerator}
onChange={(v) =>
change(e.id, {
numerator: v.target.value,
})
}
/>
</label>
<label>
Total anual final22(4–5) — sem IVA (MZN)
<input
value={e.denominator}
onChange={(v) =>
change(e.id, {
denominator: v.target.value,
})
}
/>
</label>
</>
) : (
<>
<label>
Data de recepção do documento rectificativo
<input
type="date"
value={e.receivedDate}
onChange={(v) =>
change(e.id, {
receivedDate: v.target.value,
})
}
/>
</label>
<label>
Dedução corrigida documentada (MZN)
<input
value={e.correctedDeductible}
onChange={(v) =>
change(e.id, {
correctedDeductible: v.target.value,
})
}
/>
</label>
</>
)}
{Object.entries(labels)
.filter(([k]) =>
[
'scope',
'recorded',
...(e.kind === 'annual'
? ['annual', 'exclusions']
: ['supplierCorrection', 'rightUnchanged']),
].includes(k),
)
.map(([k, label]) => (
<label className="block" key={k}>
{label}
<select
value={e.facts[k] ?? ''}
onChange={(v) =>
change(e.id, {
facts: {
...e.facts,
[k]: v.target.value as
| ''
| 'yes'
| 'no',
},
})
}
>
<option value="">Por confirmar</option>
<option value="yes">Sim</option>
<option value="no">Não</option>
</select>
</label>
))}
<button
type="button"
onClick={() =>
save({
...b,
events: b.events.filter(
(row) => row.id !== e.id,
),
})
}
>
Remover evento em preparação (histórico conservado)
</button>
</fieldset>
))}
{[...new Set(b.events.map((e) => e.period))]
.filter(Boolean)
.map((period) => (
<label className="block" key={period}>
<input
type="checkbox"
checked={b.completePeriods.includes(period)}
onChange={(e) =>
save({
...b,
completePeriods: e.target.checked
? [...b.completePeriods, period]
: b.completePeriods.filter(
(p) => p !== period,
),
})
}
/>
Reconciliei todas as regularizações deste período —{' '}
{period};os outros motivos não automatizados foram
conferidos.
</label>
))}
<p>
Quando existirem eventos E, retire as declarações «Sem
operações» nos campos12/13 desse período. Uma cobertura
incompleta mantém os totais afectados indeterminados.
</p>
<button
type="button"
onClick={() => {
try {
save(recordRegularizations(draft, b));
} catch (cause) {
setError(String(cause));
}
}}
>
Calcular e guardar regularizações E
</button>
{[
...regularizationReportRows(draft),
...frozenAssetRows(draft),
].map(([, label, value, source], i) => (
<p key={i}>
<strong>{label}</strong>: {value}
<small className="block">{source}</small>
</p>
))}
</details>
);
}