927 lines
44 KiB
TypeScript
927 lines
44 KiB
TypeScript
import { inputText } from '../lib/input-text.ts';
|
||
import { FiscalCalculationGaps } from './fiscal-calculation-gaps';
|
||
import { FiscalL3Preparation } from './fiscal-l3-preparation';
|
||
import { useState } from 'react';
|
||
import { AcquisitionClosure } from './acquisition-closure';
|
||
import { AcquisitionSubstitution } from './acquisition-substitution';
|
||
import { AcquisitionRefund } from './acquisition-refund';
|
||
import { AcquisitionBeverageRestitution } from './acquisition-beverage-restitution';
|
||
import { AcquisitionRegularizations } from './acquisition-regularizations';
|
||
import { AcquisitionOperationLink } from './acquisition-operation-link';
|
||
import { AcquisitionImportsExclusions } from './acquisition-imports-exclusions';
|
||
import { AcquisitionAllocationEditor } from './acquisition-allocation';
|
||
import { acquisitionRightVersion } from '@/lib/iva-acquisition-right';
|
||
import {
|
||
acquisitionBook,
|
||
acquisitionCurrent,
|
||
acquisitionExcludedFields,
|
||
acquisitionPlanReferences,
|
||
acquisitionReportRows,
|
||
recordAcquisitions,
|
||
newAcquisition,
|
||
reuseAcquisitions,
|
||
saveAcquisitionBook,
|
||
type Acquisition,
|
||
type AcquisitionBook,
|
||
} from '@/lib/iva-acquisitions';
|
||
import {
|
||
acquisitionTreatmentIssue,
|
||
continueWithoutFormerExploration,
|
||
formerExplorationSource,
|
||
type AcquisitionTreatment,
|
||
} from '@/lib/iva-acquisition-continuity';
|
||
|
||
export function SimulationAcquisitions({
|
||
draft,
|
||
onChange,
|
||
}: {
|
||
draft: Record<string, unknown>;
|
||
onChange: (field: string, value: string) => void;
|
||
}) {
|
||
const [error, setError] = useState('');
|
||
const [manualPeriod, setManualPeriod] = useState('');
|
||
let book: AcquisitionBook;
|
||
try {
|
||
book = acquisitionBook(draft);
|
||
} catch (cause) {
|
||
return <p role="alert">{String(cause)}</p>;
|
||
}
|
||
const save = (next: AcquisitionBook) => {
|
||
try {
|
||
onChange('modelo_a_snapshot', saveAcquisitionBook(draft, next));
|
||
setError('');
|
||
} catch (cause) {
|
||
setError(String(cause));
|
||
}
|
||
};
|
||
const change = (id: string, patch: Partial<Acquisition>) =>
|
||
save({
|
||
...book,
|
||
...('deductionLink' in patch
|
||
? { rightVersion: acquisitionRightVersion }
|
||
: {}),
|
||
rows: book.rows.map((row) =>
|
||
row.id === id ? { ...row, ...patch } : row,
|
||
),
|
||
});
|
||
const run = (action: () => void) => {
|
||
try {
|
||
action();
|
||
setError('');
|
||
} catch (cause) {
|
||
setError(cause instanceof Error ? cause.message : String(cause));
|
||
}
|
||
};
|
||
let references: ReturnType<typeof acquisitionPlanReferences> = [];
|
||
try {
|
||
references = acquisitionPlanReferences(draft);
|
||
} catch {
|
||
/* The action reports the concrete currency/source error without replacing saved values. */
|
||
}
|
||
const labels: Record<string, string> = {
|
||
'03': 'Base à taxa reduzida',
|
||
'04': 'IVA à taxa reduzida',
|
||
'05': 'Isentas com direito à dedução',
|
||
'06': 'Operações art.18(1)(b)',
|
||
'07': 'Isentas sem direito',
|
||
'11': 'Importações',
|
||
'12': 'Regularizações a favor do sujeito passivo',
|
||
'13': 'Regularizações a favor do Estado',
|
||
};
|
||
const select = (
|
||
row: Acquisition,
|
||
key: keyof Acquisition,
|
||
label: string,
|
||
options: Array<[string, string]>,
|
||
) => (
|
||
<label className="block" key={key}>
|
||
{label}
|
||
<select
|
||
className="block rounded border p-2"
|
||
value={inputText(row[key] ?? '')}
|
||
onChange={(e) => change(row.id, { [key]: e.target.value })}
|
||
>
|
||
<option value="">Por indicar</option>
|
||
{options.map(([value, text]) => (
|
||
<option key={value} value={value}>
|
||
{text}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</label>
|
||
);
|
||
const yesNo: Array<[string, string]> = [
|
||
['yes', 'Sim'],
|
||
['no', 'Não'],
|
||
];
|
||
return (
|
||
<section
|
||
aria-label="Aquisições e apuramento parcial Modelo A"
|
||
className="space-y-4 rounded border p-3"
|
||
>
|
||
<h4 className="font-semibold">
|
||
Compras e apuramento parcial do Modelo A
|
||
</h4>
|
||
<p>
|
||
Oportunidade em tratamento:{' '}
|
||
{inputText(draft.context_opportunity || 'entrada geral')}. Moeda
|
||
de origem: {book.currency || 'por indicar'}. A compra registada
|
||
não gera automaticamente IVA dedutível.
|
||
</p>
|
||
{book.currency && draft.currency !== book.currency && (
|
||
<p role="alert">
|
||
As compras conservam {book.currency}; o projecto está em{' '}
|
||
{inputText(draft.currency || 'moeda por indicar')}. Reveja a
|
||
moeda no projecto. Os montantes e o resultado anterior não
|
||
foram convertidos ou reinterpretados.
|
||
</p>
|
||
)}
|
||
{!book.currency && !!draft.currency && (
|
||
<button
|
||
type="button"
|
||
className="underline"
|
||
onClick={() =>
|
||
save({
|
||
...book,
|
||
currency: String(draft.currency),
|
||
rows: book.rows.map((row) =>
|
||
row.sourceCurrency
|
||
? row
|
||
: {
|
||
...row,
|
||
sourceCurrency: String(
|
||
draft.currency,
|
||
),
|
||
},
|
||
),
|
||
})
|
||
}
|
||
>
|
||
Confirmar explicitamente {inputText(draft.currency)} como
|
||
moeda de origem dos valores sem moeda, conservando os
|
||
montantes
|
||
</button>
|
||
)}
|
||
<p>
|
||
Aquisições em MZN/2026,ligadas à operação de destino:com
|
||
direito,sem direito ou indeterminadas. A/B/C/D distinguem
|
||
compras internas,importações de bens,exclusões/excepções e
|
||
afectação/proporções. Documento e dedução no mesmo mês;afectação
|
||
mista,proporções18(6),dedução posterior e regularizações
|
||
conservam percursos próprios. Nas projecções,cada confirmação é
|
||
um pressuposto. Compras internas:indique dois valores entre
|
||
líquido,IVA e bruto. Importações:IVA expressamente identificado
|
||
no bilhete;custos líquido/bruto são opcionais,sem calcular
|
||
direitos ou presumir taxa.
|
||
</p>
|
||
<label className="block">
|
||
Adquirente sujeito passivo de IVA no regime normal (efectivo ou
|
||
pressuposto da projecção)
|
||
<select
|
||
className="block rounded border p-2"
|
||
value={book.taxpayerRegistered ?? ''}
|
||
onChange={(e) =>
|
||
save({
|
||
...book,
|
||
taxpayerRegistered: e.target
|
||
.value as AcquisitionBook['taxpayerRegistered'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por confirmar</option>
|
||
<option value="yes">Sim</option>
|
||
<option value="no">
|
||
Não / outro enquadramento — fora deste lote
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{error && <p role="alert">{error}</p>}
|
||
<details className="rounded border p-2">
|
||
<summary>
|
||
Indicar mês da aquisição pelo documento ou pressuposto da
|
||
projecção
|
||
</summary>
|
||
<p>
|
||
Para compras introduzidas directamente, indique o mês
|
||
aplicável sem depender de ter vendas nesse mês. A
|
||
reutilização de valores do orçamento mantém a conferência da
|
||
origem.
|
||
</p>
|
||
<label>
|
||
Mês da aquisição
|
||
<input
|
||
type="month"
|
||
min="2026-01"
|
||
max="2026-12"
|
||
value={manualPeriod}
|
||
onChange={(e) => setManualPeriod(e.target.value)}
|
||
/>
|
||
</label>
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
run(() => {
|
||
if (!/^2026-(0[1-9]|1[0-2])$/.test(manualPeriod))
|
||
throw new Error(
|
||
'Indique um mês válido de2026.',
|
||
);
|
||
if (
|
||
book.periods.some(
|
||
(p) => p.period === manualPeriod,
|
||
)
|
||
)
|
||
throw new Error(
|
||
'Esse mês já consta da cobertura; valores conservados.',
|
||
);
|
||
save({
|
||
...book,
|
||
periods: [
|
||
...book.periods,
|
||
{
|
||
period: manualPeriod,
|
||
complete: false,
|
||
absent: [],
|
||
},
|
||
],
|
||
});
|
||
})
|
||
}
|
||
>
|
||
Acrescentar mês indicado
|
||
</button>
|
||
</details>
|
||
<button
|
||
type="button"
|
||
className="underline"
|
||
onClick={() => run(() => save(reuseAcquisitions(draft, book)))}
|
||
>
|
||
Reutilizar compras e períodos existentes
|
||
</button>
|
||
<button
|
||
type="button"
|
||
className="ml-3 underline"
|
||
disabled={!book.periods.length}
|
||
onClick={() =>
|
||
save({
|
||
...book,
|
||
rightVersion: acquisitionRightVersion,
|
||
rows: [
|
||
...book.rows,
|
||
newAcquisition(
|
||
crypto.randomUUID(),
|
||
book.periods[0]?.period ?? '',
|
||
book.currency,
|
||
),
|
||
],
|
||
})
|
||
}
|
||
>
|
||
Acrescentar aquisição em falta
|
||
</button>
|
||
{book.rows.map((row) => (
|
||
<details key={row.id} className="rounded border p-3">
|
||
<summary>
|
||
{row.description || 'Aquisição adicional'} —{' '}
|
||
{row.period} — campo{row.field}
|
||
</summary>
|
||
<AcquisitionAllocationEditor
|
||
draft={draft}
|
||
row={row}
|
||
onChange={(patch) => change(row.id, patch)}
|
||
/>
|
||
{!row.d?.method && (
|
||
<AcquisitionOperationLink
|
||
draft={draft}
|
||
row={row}
|
||
onChange={(patch) => change(row.id, patch)}
|
||
/>
|
||
)}
|
||
<AcquisitionImportsExclusions
|
||
draft={draft}
|
||
row={row}
|
||
onChange={(patch) => change(row.id, patch)}
|
||
/>
|
||
<details className="rounded border p-2">
|
||
<summary>
|
||
Enquadramento especial da aquisição / referência
|
||
anterior
|
||
</summary>
|
||
<label>
|
||
Tratamento da aquisição
|
||
<select
|
||
value={row.acquisitionTreatment ?? ''}
|
||
onChange={(e) =>
|
||
row.acquisitionTreatment ===
|
||
'former_exploration_exemption' &&
|
||
e.target.value !==
|
||
'former_exploration_exemption'
|
||
? run(() =>
|
||
save({
|
||
...book,
|
||
rows: book.rows.map((item) =>
|
||
item.id === row.id
|
||
? continueWithoutFormerExploration(
|
||
item,
|
||
)
|
||
: item,
|
||
),
|
||
}),
|
||
)
|
||
: change(row.id, {
|
||
acquisitionTreatment: e.target
|
||
.value as AcquisitionTreatment,
|
||
})
|
||
}
|
||
>
|
||
<option value="">
|
||
Enquadramento normal; sem benefício especial
|
||
indicado
|
||
</option>
|
||
<option value="former_exploration_exemption">
|
||
Antiga isenção de prospecção/pesquisa
|
||
—14(2)(c),eliminada
|
||
</option>
|
||
<option value="normal">
|
||
Continuidade pelo enquadramento normal
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{acquisitionTreatmentIssue(
|
||
row.acquisitionTreatment,
|
||
) && (
|
||
<p role="status">
|
||
{acquisitionTreatmentIssue(
|
||
row.acquisitionTreatment,
|
||
)}
|
||
</p>
|
||
)}
|
||
{row.acquisitionTreatment ===
|
||
'former_exploration_exemption' && (
|
||
<>
|
||
<p>{formerExplorationSource}</p>
|
||
<p>
|
||
A continuidade conserva
|
||
montantes,moeda,mês,documento e respostas
|
||
existentes. Não introduz taxa nem altera o
|
||
IVA declarado; reveja as condições antes de
|
||
calcular.
|
||
</p>
|
||
<button
|
||
type="button"
|
||
onClick={() =>
|
||
run(() =>
|
||
save({
|
||
...book,
|
||
rows: book.rows.map((item) =>
|
||
item.id === row.id
|
||
? continueWithoutFormerExploration(
|
||
item,
|
||
)
|
||
: item,
|
||
),
|
||
}),
|
||
)
|
||
}
|
||
>
|
||
Continuar aquisição sem esta isenção e rever
|
||
condições
|
||
</button>
|
||
</>
|
||
)}
|
||
{row.acquisitionTreatmentOrigin && (
|
||
<p>
|
||
Origem conservada: antiga
|
||
referência14(2)(c),eliminada.{' '}
|
||
{row.acquisitionTreatment ===
|
||
'former_exploration_exemption'
|
||
? 'A continuidade normal foi escolhida numa versão anterior; a referência antiga está agora seleccionada para análise.'
|
||
: 'Continuidade normal escolhida expressamente; não é nova concessão de isenção.'}
|
||
</p>
|
||
)}
|
||
</details>
|
||
<p>
|
||
Origem:{' '}
|
||
{row.sourceMonth === null
|
||
? 'Introdução directa'
|
||
: `Plano, mês ${row.sourceMonth} (${row.sourcePeriod ?? 'por indicar'}): ${row.sourceAmount ?? 'sem informação'} ${row.sourceCurrency}`}
|
||
. O mês da encomenda/orçamento não determina a data do
|
||
documento ou a dedução. Alterações não substituem o
|
||
resultado anterior.
|
||
</p>
|
||
<div className="grid gap-3 md:grid-cols-2">
|
||
<label>
|
||
Descrição
|
||
<input
|
||
className="block rounded border p-2"
|
||
value={row.description}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
description: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
{row.sourceMonth === null && (
|
||
<label>
|
||
Reutilizar valor existente, sem presumir que o
|
||
orçamento é uma factura
|
||
<select
|
||
className="block rounded border p-2"
|
||
value=""
|
||
onChange={(e) =>
|
||
run(() => {
|
||
const ref = references.find(
|
||
(r) => r.key === e.target.value,
|
||
);
|
||
if (ref)
|
||
change(row.id, {
|
||
sourceMonth: ref.month,
|
||
sourcePeriod: ref.period,
|
||
sourceField: ref.kind,
|
||
sourceAmount: ref.amount,
|
||
sourceCurrency:
|
||
ref.currency,
|
||
...(ref.kind === 'asset'
|
||
? {}
|
||
: {
|
||
period: ref.period,
|
||
}),
|
||
});
|
||
})
|
||
}
|
||
>
|
||
<option value="">
|
||
Escolher apenas se corresponde a esta
|
||
aquisição
|
||
</option>
|
||
{references
|
||
.filter(
|
||
(ref) =>
|
||
ref.kind ===
|
||
(row.field === '08'
|
||
? 'asset'
|
||
: row.field === '10'
|
||
? 'operating'
|
||
: 'inventory'),
|
||
)
|
||
.map((ref) => (
|
||
<option
|
||
key={ref.key}
|
||
value={ref.key}
|
||
>
|
||
{ref.label}:{' '}
|
||
{ref.amount ?? 'sem informação'}{' '}
|
||
{ref.currency}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</label>
|
||
)}
|
||
{select(row, 'field', 'Categoria', [
|
||
['08', '08 — Imobilizado'],
|
||
['09', '09 — Existências'],
|
||
['10', '10 — Outros bens e serviços'],
|
||
...(row.bc
|
||
? [
|
||
['11', '11 — Importações de bens'] as [
|
||
string,
|
||
string,
|
||
],
|
||
]
|
||
: []),
|
||
])}
|
||
{row.field === '11' && (
|
||
<label>
|
||
<input
|
||
type="checkbox"
|
||
checked={row.investmentAsset ?? false}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
investmentAsset: e.target.checked,
|
||
})
|
||
}
|
||
/>
|
||
Bem de investimento importado — incluir no
|
||
controlo de activos;conserva campo11 e condições
|
||
próprias da importação.
|
||
</label>
|
||
)}
|
||
{select(row, 'origin', 'Natureza dos dados', [
|
||
['projected', 'Projectados / pressupostos'],
|
||
['effective', 'Efectivos declarados'],
|
||
])}
|
||
<label>
|
||
Período de dedução
|
||
<input
|
||
className="block rounded border p-2"
|
||
type="month"
|
||
value={row.period}
|
||
onChange={(e) =>
|
||
change(row.id, { period: e.target.value })
|
||
}
|
||
/>
|
||
</label>
|
||
{row.sourceMonth !== null && (
|
||
<label>
|
||
O valor de origem corresponde a
|
||
<select
|
||
className="block rounded border p-2"
|
||
value={row.sourceBasis}
|
||
onChange={(e) => {
|
||
const basis = e.target
|
||
.value as Acquisition['sourceBasis'];
|
||
change(row.id, {
|
||
sourceBasis: basis,
|
||
...(basis === 'net' && !row.net
|
||
? {
|
||
net:
|
||
row.sourceAmount ??
|
||
'',
|
||
}
|
||
: basis === 'gross' &&
|
||
!row.gross
|
||
? {
|
||
gross:
|
||
row.sourceAmount ??
|
||
'',
|
||
}
|
||
: {}),
|
||
});
|
||
}}
|
||
>
|
||
<option value="">Por classificar</option>
|
||
<option value="net">Valor sem IVA</option>
|
||
<option value="gross">Valor com IVA</option>
|
||
</select>
|
||
</label>
|
||
)}
|
||
{(['net', 'vat', 'gross'] as const).map(
|
||
(field, index) => (
|
||
<label key={field}>
|
||
{
|
||
[
|
||
'Valor líquido',
|
||
'IVA indicado',
|
||
'Valor bruto',
|
||
][index]
|
||
}{' '}
|
||
({row.sourceCurrency})
|
||
<input
|
||
className="block rounded border p-2"
|
||
inputMode="decimal"
|
||
value={row[field]}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
[field]: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
),
|
||
)}
|
||
{select(
|
||
row,
|
||
'documentType',
|
||
'Tipo de documento',
|
||
row.domestic === 'no' && row.bc
|
||
? [
|
||
[
|
||
'customs',
|
||
'Bilhete de despacho de importação',
|
||
],
|
||
]
|
||
: [
|
||
['invoice', 'Factura'],
|
||
['equivalent', 'Documento equivalente'],
|
||
],
|
||
)}
|
||
<label>
|
||
Referência do documento / previsão
|
||
<input
|
||
className="block rounded border p-2"
|
||
value={row.documentRef}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
documentRef: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
<label>
|
||
Linha do documento, se discriminado em várias
|
||
aquisições
|
||
<input
|
||
className="block rounded border p-2"
|
||
value={row.documentLine}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
documentLine: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
<label>
|
||
Data do documento / prevista
|
||
<input
|
||
className="block rounded border p-2"
|
||
type="date"
|
||
value={row.documentDate}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
documentDate: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
{!(row.bc && row.domestic === 'no') && (
|
||
<label>
|
||
Fornecedor / previsto
|
||
<input
|
||
className="block rounded border p-2"
|
||
value={row.supplier}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
supplier: e.target.value,
|
||
})
|
||
}
|
||
/>
|
||
</label>
|
||
)}
|
||
{select(row, 'domestic', 'Aquisição interna', yesNo)}
|
||
{row.acquisitionTreatment !==
|
||
'former_exploration_exemption' && (
|
||
<>
|
||
{!(row.bc && row.domestic === 'no') &&
|
||
select(
|
||
row,
|
||
'supplierRegistered',
|
||
'Fornecedor inscrito no IVA',
|
||
yesNo,
|
||
)}
|
||
{select(
|
||
row,
|
||
'legalDocument',
|
||
'Documento emitido em forma legal',
|
||
yesNo,
|
||
)}
|
||
{select(
|
||
row,
|
||
'held',
|
||
'Documento na posse do adquirente / previsto na projecção',
|
||
yesNo,
|
||
)}
|
||
{select(row, 'allocation', 'Afectação', [
|
||
[
|
||
'taxable_only',
|
||
row.d?.method === 'reduced'
|
||
? 'Exclusiva à origem18(6)'
|
||
: row.deductionLink
|
||
? 'Exclusiva à operação ligada'
|
||
: 'Exclusiva a operações tributadas',
|
||
],
|
||
[
|
||
'mixed',
|
||
row.d
|
||
? 'Mista / parcial — métodoD'
|
||
: 'Mista / parcial — preparar métodoD',
|
||
],
|
||
[
|
||
'no_right',
|
||
'Operações sem direito à dedução',
|
||
],
|
||
])}
|
||
{select(
|
||
row,
|
||
'exclusion',
|
||
'Exclusões de dedução',
|
||
[
|
||
[
|
||
'none',
|
||
'Sem exclusões ou casos especiais dos arts.18–20',
|
||
],
|
||
['excluded', 'Despesa excluída'],
|
||
[
|
||
'special',
|
||
'Veículos, combustível, viagens, alojamento, comunicações, luxo ou outra situação especial — por enquadrar',
|
||
],
|
||
],
|
||
)}
|
||
{select(
|
||
row,
|
||
'integrity',
|
||
'Operação real / pressuposto regular, sem simulação, margem de segunda mão ou impedimentos do art.18(3–5)',
|
||
yesNo,
|
||
)}
|
||
</>
|
||
)}
|
||
</div>
|
||
<p>
|
||
Fundamento:CIVA18–21,fontes e versão no resultado.{' '}
|
||
{row.d
|
||
? 'MétodoD aplicado apenas à parcela elegível pelas condiçõesB/C;fracções exactas,sem regularização anual automática ou restituiçãoL3.'
|
||
: row.bc
|
||
? 'Aplicam-se apenas as exclusões/excepções documentadas escolhidas;gasóleo50% conserva fracção exacta. Sem pro rata,proporções18(6) ou regularização neste incremento.'
|
||
: 'Afectação parcial,despesa especial e dedução posterior exigem percurso próprio;use a análiseC quando aplicável.'}
|
||
</p>
|
||
{row.sourceMonth === null && (
|
||
<button
|
||
type="button"
|
||
className="mr-3 underline"
|
||
onClick={() =>
|
||
save({
|
||
...book,
|
||
rows: book.rows.filter(
|
||
(r) => r.id !== row.id,
|
||
),
|
||
})
|
||
}
|
||
>
|
||
Remover esta aquisição introduzida directamente
|
||
</button>
|
||
)}
|
||
{row.sourceMonth !== null && (
|
||
<button
|
||
type="button"
|
||
className="underline"
|
||
onClick={() =>
|
||
run(() => {
|
||
const ref = acquisitionPlanReferences(
|
||
draft,
|
||
).find(
|
||
(r) =>
|
||
r.month === row.sourceMonth &&
|
||
r.kind ===
|
||
(row.sourceField ??
|
||
'inventory'),
|
||
);
|
||
if (!ref)
|
||
throw new Error(
|
||
'Origem não disponível; conserve o registo e reveja o plano.',
|
||
);
|
||
if (draft.currency !== row.sourceCurrency)
|
||
throw new Error(
|
||
'Moeda divergente; não adoptar montantes de outra moeda.',
|
||
);
|
||
change(row.id, {
|
||
sourceAmount: ref.amount,
|
||
sourcePeriod: ref.period,
|
||
...(row.sourceBasis === 'net'
|
||
? {
|
||
net: ref.amount ?? '',
|
||
gross: '',
|
||
}
|
||
: row.sourceBasis === 'gross'
|
||
? {
|
||
gross: ref.amount ?? '',
|
||
net: '',
|
||
}
|
||
: {}),
|
||
});
|
||
})
|
||
}
|
||
>
|
||
Adoptar explicitamente o valor actual do plano
|
||
(conserva histórico)
|
||
</button>
|
||
)}
|
||
</details>
|
||
))}
|
||
<AcquisitionRegularizations draft={draft} onChange={onChange} />
|
||
{book.periods.map((period) => (
|
||
<details key={period.period} className="rounded border p-3">
|
||
<summary>
|
||
{period.period} — cobertura das parcelas —{' '}
|
||
{period.complete &&
|
||
period.absent.length ===
|
||
acquisitionExcludedFields.length
|
||
? 'confirmada'
|
||
: 'por completar'}
|
||
</summary>
|
||
{book.rows.some((r) => r.bc) && (
|
||
<label className="block">
|
||
<input
|
||
type="checkbox"
|
||
checked={period.importsComplete ?? false}
|
||
onChange={(e) =>
|
||
save({
|
||
...book,
|
||
periods: book.periods.map((p) =>
|
||
p.period === period.period
|
||
? {
|
||
...p,
|
||
importsComplete:
|
||
e.target.checked,
|
||
}
|
||
: p,
|
||
),
|
||
})
|
||
}
|
||
/>{' '}
|
||
Incluí todas as importações de bens/campo11 deste
|
||
período,mesmo isentas ou sem direito;sem somar
|
||
novamente IVA de serviços incluídos na base.
|
||
</label>
|
||
)}
|
||
<label className="block">
|
||
<input
|
||
type="checkbox"
|
||
checked={period.complete}
|
||
onChange={(e) =>
|
||
save({
|
||
...book,
|
||
periods: book.periods.map((p) =>
|
||
p.period === period.period
|
||
? {
|
||
...p,
|
||
complete: e.target.checked,
|
||
}
|
||
: p,
|
||
),
|
||
})
|
||
}
|
||
/>{' '}
|
||
Incluí todas as aquisições08–10 deste período, incluindo
|
||
as sem direito à dedução; uma lista vazia significa que
|
||
não houve essas aquisições.
|
||
</label>
|
||
<p>
|
||
Campos fora deste lote: assinale apenas quando não
|
||
existiram as respectivas operações. Uma parcela não
|
||
assinalada permanece indeterminada.
|
||
</p>
|
||
{acquisitionExcludedFields.map((field) => (
|
||
<label className="block" key={field}>
|
||
<input
|
||
type="checkbox"
|
||
checked={period.absent.includes(field)}
|
||
onChange={(e) =>
|
||
save({
|
||
...book,
|
||
periods: book.periods.map((p) =>
|
||
p.period === period.period
|
||
? {
|
||
...p,
|
||
absent: e.target.checked
|
||
? [...p.absent, field]
|
||
: p.absent.filter(
|
||
(f) =>
|
||
f !== field,
|
||
),
|
||
}
|
||
: p,
|
||
),
|
||
})
|
||
}
|
||
/>{' '}
|
||
Sem operações no campo{field} — {labels[field]}
|
||
</label>
|
||
))}
|
||
</details>
|
||
))}
|
||
<button
|
||
type="button"
|
||
disabled={!book.periods.length}
|
||
className="rounded bg-emerald-800 p-2 text-white disabled:opacity-50"
|
||
onClick={() => run(() => save(recordAcquisitions(draft, book)))}
|
||
>
|
||
Calcular e guardar versão do apuramento parcial
|
||
</button>
|
||
<p>
|
||
O apuramento01–18 conserva o seu resultado antes dos créditos. O
|
||
fechoA/B abaixo reutiliza a versão congelada,sem ordem de
|
||
pagamento,submissãoAT ou promessa de reembolso.
|
||
</p>
|
||
<AcquisitionClosure draft={draft} onChange={onChange} />
|
||
<AcquisitionSubstitution draft={draft} onChange={onChange} />
|
||
<AcquisitionRefund draft={draft} onChange={onChange} />
|
||
<AcquisitionBeverageRestitution draft={draft} onChange={onChange} />
|
||
<FiscalCalculationGaps draft={draft} />
|
||
<FiscalL3Preparation draft={draft} />
|
||
{book.result && (
|
||
<>
|
||
<p role="status">
|
||
{acquisitionCurrent(draft, book)
|
||
? 'Resultado correspondente às entradas guardadas.'
|
||
: 'Entradas ou origem alteradas: resultado histórico preservado; actualizar o cálculo.'}
|
||
</p>
|
||
<dl>
|
||
{acquisitionReportRows(draft).map(
|
||
([, label, value, origin], i) => (
|
||
<div key={i}>
|
||
<dt className="font-semibold">{label}</dt>
|
||
<dd>
|
||
{value}
|
||
<small className="block">
|
||
{origin}
|
||
</small>
|
||
</dd>
|
||
</div>
|
||
),
|
||
)}
|
||
</dl>
|
||
</>
|
||
)}
|
||
</section>
|
||
);
|
||
}
|