328 lines
13 KiB
TypeScript
328 lines
13 KiB
TypeScript
import { normalFinancialSource, type NormalBook } from '@/lib/irpc-normal';
|
||
import {
|
||
m20Accounts,
|
||
newNormalFormPreparation,
|
||
newFormAllocation,
|
||
reuseDirectFormAllocations,
|
||
normalFormAccountsFor,
|
||
type NormalFormPreparationInput,
|
||
type FormAllocation,
|
||
} from '@/lib/irpc-normal-form-preparation';
|
||
export function SimulationIrpcFormPreparation({
|
||
draft,
|
||
book,
|
||
save,
|
||
}: {
|
||
draft: Record<string, unknown>;
|
||
book: NormalBook;
|
||
save: (b: NormalBook) => void;
|
||
}) {
|
||
const i = book.forms,
|
||
source = normalFinancialSource(draft);
|
||
if (!i)
|
||
return (
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
save({ ...book, forms: newNormalFormPreparation() })
|
||
}
|
||
>
|
||
Preparar representação dos valores e campos M20/M22
|
||
</button>
|
||
);
|
||
const patch = (p: Partial<NormalFormPreparationInput>) =>
|
||
save({ ...book, forms: { ...i, ...p } }),
|
||
row = (id: string, p: Partial<FormAllocation>) =>
|
||
patch({
|
||
allocations: i.allocations.map((a) =>
|
||
a.id === id ? { ...a, ...p } : a,
|
||
),
|
||
});
|
||
return (
|
||
<fieldset
|
||
aria-label="Preparação de valores M20 M22"
|
||
className="space-y-3 rounded border p-3"
|
||
>
|
||
<legend>Representação dos valores e correspondência M20/M22</legend>
|
||
<p>
|
||
Reutiliza os valores exactos do cálculo e do período/moeda já
|
||
documentados. A preparação dos campos não altera lucro
|
||
tributável,matéria colectável ou colecta. M20A.1 exige meticais
|
||
sem centavos;fracções conservam o valor exacto e ficam pendentes
|
||
de regra de representação. O transporte201/quadro8
|
||
versus200/quadro10 continua identificado,só no resultado
|
||
afectado. Não gera declaração oficial nem saldo finalL8.
|
||
</p>
|
||
<label className="block">
|
||
Exemplares de preparação
|
||
<select
|
||
value={i.edition}
|
||
onChange={(e) =>
|
||
patch({
|
||
edition: e.target
|
||
.value as NormalFormPreparationInput['edition'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por identificar</option>
|
||
<option value="accepted_pdf_and_m20a1">
|
||
PDF M22 quadros10–12 e M20A.1 inventariados — edições
|
||
distintas
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label className="block">
|
||
Suporte da edição e do período
|
||
<input
|
||
value={i.reference}
|
||
onChange={(e) => patch({ reference: e.target.value })}
|
||
/>
|
||
</label>
|
||
<label className="block">
|
||
Completude das contas e discriminação das linhas do plano
|
||
<input
|
||
value={i.completenessReference}
|
||
onChange={(e) =>
|
||
patch({ completenessReference: e.target.value })
|
||
}
|
||
/>
|
||
</label>
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
patch({
|
||
allocations: [
|
||
...i.allocations,
|
||
...reuseDirectFormAllocations(source).filter(
|
||
(a) =>
|
||
!i.allocations.some(
|
||
(r) => r.sourceCode === a.sourceCode,
|
||
),
|
||
),
|
||
],
|
||
})
|
||
}
|
||
>
|
||
Reutilizar contas directas ainda não discriminadas
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
patch({
|
||
allocations: [
|
||
...i.allocations,
|
||
newFormAllocation(crypto.randomUUID()),
|
||
],
|
||
})
|
||
}
|
||
>
|
||
Acrescentar parcela contabilística M20
|
||
</button>
|
||
{i.allocations.map((a, n) => (
|
||
<fieldset key={a.id} className="rounded border p-2">
|
||
<legend>Parcela M20 {n + 1}</legend>
|
||
<label className="block">
|
||
Linha de origem
|
||
<select
|
||
aria-label={'Origem M20 ' + (n + 1)}
|
||
value={a.sourceCode}
|
||
onChange={(e) =>
|
||
row(a.id, { sourceCode: e.target.value })
|
||
}
|
||
>
|
||
<option value="">Seleccione</option>
|
||
{source?.accountingLines.map((l) => (
|
||
<option key={l.code} value={l.code}>
|
||
{l.origin}: {l.total} MZN
|
||
</option>
|
||
))}
|
||
</select>
|
||
</label>
|
||
<label className="block">
|
||
Conta M20A.1
|
||
<select
|
||
aria-label={'Conta M20 ' + (n + 1)}
|
||
value={a.account}
|
||
onChange={(e) =>
|
||
row(a.id, {
|
||
account: e.target
|
||
.value as FormAllocation['account'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por corresponder</option>
|
||
{Object.entries(m20Accounts)
|
||
.filter(
|
||
([k]) =>
|
||
normalFormAccountsFor(
|
||
a.sourceCode,
|
||
).includes(k) || k === a.account,
|
||
)
|
||
.map(([k, v]) => (
|
||
<option key={k} value={k}>
|
||
{k} — {v}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</label>
|
||
<label className="block">
|
||
Montante MZN
|
||
<input
|
||
aria-label={'Montante M20 ' + (n + 1)}
|
||
value={a.amount}
|
||
onChange={(e) =>
|
||
row(a.id, { amount: e.target.value })
|
||
}
|
||
/>
|
||
</label>
|
||
<label className="block">
|
||
Suporte da classificação
|
||
<input
|
||
aria-label={'Suporte M20 ' + (n + 1)}
|
||
value={a.reference}
|
||
onChange={(e) =>
|
||
row(a.id, { reference: e.target.value })
|
||
}
|
||
/>
|
||
</label>
|
||
</fieldset>
|
||
))}
|
||
<fieldset className="rounded border p-2">
|
||
<legend>Imposto contabilizado e resultado líquido</legend>
|
||
<p>
|
||
Colecta e saldo a pagar não são usados como gasto
|
||
contabilístico presumido. Indique imposto reconhecido e se
|
||
já está incluído numa linha do plano,para evitar subtracção
|
||
duplicada.
|
||
</p>
|
||
<label className="block">
|
||
Estado do imposto contabilizado
|
||
<select
|
||
aria-label="Estado do imposto contabilizado"
|
||
value={i.incomeTax.state}
|
||
onChange={(e) =>
|
||
patch({
|
||
incomeTax: {
|
||
...i.incomeTax,
|
||
state: e.target.value as
|
||
| ''
|
||
| 'known'
|
||
| 'absent',
|
||
},
|
||
})
|
||
}
|
||
>
|
||
<option value="">Informação em falta</option>
|
||
<option value="known">Valor conhecido</option>
|
||
<option value="absent">
|
||
Ausência declarada com suporte
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{(i.incomeTax.state === 'known' ||
|
||
i.incomeTax.amount !== '' ||
|
||
i.incomeTax.placement !== '') && (
|
||
<>
|
||
<label className="block">
|
||
Imposto contabilizado em MZN
|
||
<input
|
||
value={i.incomeTax.amount}
|
||
onChange={(e) =>
|
||
patch({
|
||
incomeTax: {
|
||
...i.incomeTax,
|
||
amount: e.target.value,
|
||
},
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
<label className="block">
|
||
Localização do imposto contabilizado
|
||
<select
|
||
value={i.incomeTax.placement}
|
||
onChange={(e) =>
|
||
patch({
|
||
incomeTax: {
|
||
...i.incomeTax,
|
||
placement: e.target.value as
|
||
| ''
|
||
| 'included'
|
||
| 'outside',
|
||
},
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por identificar</option>
|
||
<option value="included">
|
||
Já incluído no resultado do plano —
|
||
discriminado na conta8.5
|
||
</option>
|
||
<option value="outside">
|
||
Exterior ao resultado antes de imposto do
|
||
plano
|
||
</option>
|
||
</select>
|
||
</label>
|
||
</>
|
||
)}
|
||
<label className="block">
|
||
Suporte do imposto contabilizado
|
||
<input
|
||
value={i.incomeTax.reference}
|
||
onChange={(e) =>
|
||
patch({
|
||
incomeTax: {
|
||
...i.incomeTax,
|
||
reference: e.target.value,
|
||
},
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
</fieldset>
|
||
<label className="block">
|
||
Parcela de taxa reduzida para a colecta total302
|
||
<select
|
||
aria-label="Parcela de taxa reduzida para a colecta total302"
|
||
value={i.reducedRate.state}
|
||
onChange={(e) =>
|
||
patch({
|
||
reducedRate: {
|
||
...i.reducedRate,
|
||
state: e.target.value as
|
||
| ''
|
||
| 'known'
|
||
| 'absent',
|
||
},
|
||
})
|
||
}
|
||
>
|
||
<option value="">Informação em falta</option>
|
||
<option value="absent">
|
||
Ausência declarada — sem parcela reduzida neste
|
||
sujeito/período
|
||
</option>
|
||
<option value="known">
|
||
Situação conhecida — âmbitoL7 por tratar
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label className="block">
|
||
Suporte da situação da taxa reduzida
|
||
<input
|
||
value={i.reducedRate.reference}
|
||
onChange={(e) =>
|
||
patch({
|
||
reducedRate: {
|
||
...i.reducedRate,
|
||
reference: e.target.value,
|
||
},
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
</fieldset>
|
||
);
|
||
}
|