477 lines
22 KiB
TypeScript
477 lines
22 KiB
TypeScript
import { inputText } from '../lib/input-text.ts';
|
|
import { useState } from 'react';
|
|
import {
|
|
newGoodsAllocation,
|
|
switchAllocationTreatment,
|
|
switchAllocationValuation,
|
|
goodsAllocationBook,
|
|
goodsAllocationConditions,
|
|
allocationSpecificConditions,
|
|
goodsAllocationCurrent,
|
|
goodsAllocationReportRows,
|
|
goodsAllocationSource,
|
|
goodsAllocationTreatments,
|
|
recordGoodsAllocations,
|
|
saveGoodsAllocationBook,
|
|
type GoodsAllocationBook,
|
|
type GoodsAllocationRow,
|
|
} from '@/lib/iva-goods-allocation';
|
|
|
|
export function SimulationGoodsAllocation({
|
|
draft,
|
|
onChange,
|
|
}: {
|
|
draft: Record<string, unknown>;
|
|
onChange: (field: string, value: string) => void;
|
|
}) {
|
|
const [error, setError] = useState('');
|
|
let book: GoodsAllocationBook;
|
|
try {
|
|
book = goodsAllocationBook(draft);
|
|
} catch (cause) {
|
|
return <p role="alert">{String(cause)}</p>;
|
|
}
|
|
const save = (next: GoodsAllocationBook) => {
|
|
try {
|
|
onChange('modelo_a_snapshot', saveGoodsAllocationBook(draft, next));
|
|
setError('');
|
|
} catch (cause) {
|
|
setError(String(cause));
|
|
}
|
|
};
|
|
const change = (id: string, patch: Partial<GoodsAllocationRow>) =>
|
|
save({
|
|
...book,
|
|
rows: book.rows.map((row) =>
|
|
row.id === id ? { ...row, ...patch } : row,
|
|
),
|
|
});
|
|
return (
|
|
<details className="space-y-3 rounded border p-3">
|
|
<summary>
|
|
Afectação de bens — classificação ebase de aquisição/custo
|
|
</summary>
|
|
<p>
|
|
Oportunidade:{' '}
|
|
{inputText(draft.context_opportunity || 'entrada geral')}.
|
|
P124identifica a transmissão assimilada;P088determina a base.
|
|
Uma operação conserva a sua identidade nos dois requisitos,não
|
|
se soma duas vezes. Uso temporário de bens como serviçoP089segue
|
|
o seu percurso.
|
|
</p>
|
|
<p>
|
|
A dedução anterior total/parcial é um facto histórico dos bens
|
|
ou elementos;não é calculada nem concedida aqui. A base usa
|
|
preço de aquisição reportado ao momento da operação ou,na sua
|
|
falta demonstrada,preço de custo.Não substituir um preço
|
|
desconhecido por zero ou por custo automaticamente.
|
|
</p>
|
|
<p>{goodsAllocationSource}</p>
|
|
{error && <p role="alert">{error}</p>}
|
|
<button
|
|
type="button"
|
|
className="underline"
|
|
onClick={() =>
|
|
save({
|
|
...book,
|
|
rows: [
|
|
...book.rows,
|
|
newGoodsAllocation(
|
|
crypto.randomUUID(),
|
|
inputText(draft.currency ?? ''),
|
|
),
|
|
],
|
|
})
|
|
}
|
|
>
|
|
Acrescentar afectação ou transmissão gratuita
|
|
</button>
|
|
{book.rows.map((row) => (
|
|
<details key={row.id} className="rounded border p-3">
|
|
<summary>
|
|
{row.description || 'Operação por identificar'} —{' '}
|
|
{row.period || 'mês por indicar'}
|
|
</summary>
|
|
<div className="grid gap-3 md:grid-cols-2">
|
|
<label>
|
|
Percurso de afectação dos bens
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={row.treatment}
|
|
onChange={(e) =>
|
|
change(
|
|
row.id,
|
|
switchAllocationTreatment(
|
|
row,
|
|
e.target.value,
|
|
),
|
|
)
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
{goodsAllocationTreatments.map((t) => (
|
|
<option key={t.id} value={t.id}>
|
|
{t.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Natureza dos dados
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={row.origin}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
origin: e.target
|
|
.value as GoodsAllocationRow['origin'],
|
|
})
|
|
}
|
|
>
|
|
<option value="projected">
|
|
Projectados / pressupostos
|
|
</option>
|
|
<option value="effective">
|
|
Efectivos declarados
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{(
|
|
[
|
|
['description', 'Operação identificada'],
|
|
[
|
|
'operationRef',
|
|
'Referência da operação / pressuposto',
|
|
],
|
|
['currency', 'Moeda da base'],
|
|
[
|
|
'operationDate',
|
|
'Data da operação / prevista',
|
|
],
|
|
['period', 'Mês da operação'],
|
|
[
|
|
'documentRef',
|
|
'Documento / referência da previsão',
|
|
],
|
|
[
|
|
'documentDate',
|
|
'Data do documento / prevista',
|
|
],
|
|
[
|
|
'goodsRef',
|
|
'Bens/elementos e identificação do conjunto afectado',
|
|
],
|
|
[
|
|
'deductionRef',
|
|
'Referência da dedução anterior total ou parcial',
|
|
],
|
|
[
|
|
'destinationRef',
|
|
'Destino,finalidade ou sector eâmbito',
|
|
],
|
|
[
|
|
'evidence',
|
|
'Fundamento factual / pressupostos',
|
|
],
|
|
] as const
|
|
).map(([field, label]) => (
|
|
<label key={field}>
|
|
{label}
|
|
<input
|
|
className="block rounded border p-2"
|
|
type={
|
|
[
|
|
'operationDate',
|
|
'documentDate',
|
|
].includes(field)
|
|
? 'date'
|
|
: field === 'period'
|
|
? 'month'
|
|
: 'text'
|
|
}
|
|
value={row[field]}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
[field]: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
))}
|
|
{[
|
|
'permanent_private_goods',
|
|
'free_goods_transfer',
|
|
].includes(row.treatment) && (
|
|
<label>
|
|
Factos/referência sobre excepção de
|
|
amostras/ofertas de pequeno valor
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.exceptionRef}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
exceptionRef: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
)}
|
|
{row.treatment === 'fixed_asset_20a' && (
|
|
<label>
|
|
Enquadramento dos bens20(1)a eafectação ao
|
|
activo imobilizado
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.asset20aRef}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
asset20aRef: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
)}
|
|
<label>
|
|
Modo de determinação da base15(2)b
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={row.valuationMode}
|
|
onChange={(e) =>
|
|
change(
|
|
row.id,
|
|
switchAllocationValuation(
|
|
row,
|
|
e.target.value,
|
|
),
|
|
)
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="acquisition">
|
|
Preço de aquisição reportado ao momento da
|
|
operação
|
|
</option>
|
|
<option value="cost">
|
|
Preço de custo,na falta demonstrada de preço
|
|
de aquisição
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{row.valuationMode === 'acquisition' && (
|
|
<>
|
|
<label>
|
|
Preço de aquisição para o conjunto
|
|
identificado,sem próprioIVA
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.acquisitionPrice}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
acquisitionPrice:
|
|
e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Referência do preço de aquisição reportado
|
|
ao momento
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.acquisitionRef}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
acquisitionRef: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
</>
|
|
)}
|
|
{row.valuationMode === 'cost' && (
|
|
<>
|
|
<label>
|
|
Preço de custo para o conjunto
|
|
identificado,sem próprioIVA
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.currentCost}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
currentCost: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Referência do custo reportado ao momento
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.costRef}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
costRef: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Falta de preço de aquisição demonstrada para
|
|
esta operação
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={
|
|
row.conditions
|
|
.acquisitionUnavailable ?? ''
|
|
}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
conditions: {
|
|
...row.conditions,
|
|
acquisitionUnavailable: e
|
|
.target.value as
|
|
| ''
|
|
| 'yes'
|
|
| 'no',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="yes">Sim</option>
|
|
<option value="no">Não</option>
|
|
</select>
|
|
</label>
|
|
</>
|
|
)}
|
|
<label>
|
|
Momento a que o preço de aquisição/custo é reportado
|
|
<input
|
|
type="date"
|
|
className="block rounded border p-2"
|
|
value={row.valuationDate}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
valuationDate: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Âmbito ecomposição da base,bens/elementos abrangidos
|
|
<input
|
|
className="block rounded border p-2"
|
|
value={row.valuationScope}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
valuationScope: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label>
|
|
Base reportada ao momento desta operação,sem
|
|
próprioIVA ecom âmbito correspondente
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={row.conditions.valuationConfirmed ?? ''}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
conditions: {
|
|
...row.conditions,
|
|
valuationConfirmed: e.target
|
|
.value as '' | 'yes' | 'no',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="yes">Sim</option>
|
|
<option value="no">Não</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
<p>
|
|
Mudar percurso/modo conserva referências e valores
|
|
ocultos,mas exige rever confirmações próprias. Não se
|
|
presume limiar de oferta,custo histórico actualizado ou
|
|
nova dedução.
|
|
</p>
|
|
<fieldset>
|
|
<legend>Factos próprios da operação</legend>
|
|
{[
|
|
...goodsAllocationConditions,
|
|
...allocationSpecificConditions(row.treatment),
|
|
].map(([key, label]) => (
|
|
<label className="block" key={key}>
|
|
{label}
|
|
<select
|
|
className="block rounded border p-2"
|
|
value={row.conditions[key] ?? ''}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
conditions: {
|
|
...row.conditions,
|
|
[key]: e.target.value as
|
|
| ''
|
|
| 'yes'
|
|
| 'no',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
<option value="yes">Sim</option>
|
|
<option value="no">Não</option>
|
|
</select>
|
|
</label>
|
|
))}
|
|
</fieldset>
|
|
</details>
|
|
))}
|
|
{!!book.rows.length && (
|
|
<button
|
|
type="button"
|
|
className="rounded bg-emerald-800 p-2 text-white"
|
|
onClick={() => {
|
|
try {
|
|
save(recordGoodsAllocations(draft, book));
|
|
} catch (cause) {
|
|
setError(String(cause));
|
|
}
|
|
}}
|
|
>
|
|
Classificar afectações,determinar base eguardar versão
|
|
</button>
|
|
)}
|
|
{book.result && (
|
|
<>
|
|
<p role="status">
|
|
{goodsAllocationCurrent(draft, book)
|
|
? 'Classificações/bases correspondentes às entradas guardadas.'
|
|
: 'Entradas alteradas;resultados históricos conservados. Reveja e determine novamente.'}{' '}
|
|
{book.history?.length ?? 0} versões anteriores. Dedução
|
|
histórica não é nova dedução/campo11;sem IVA ou
|
|
regularização calculados.
|
|
</p>
|
|
<dl>
|
|
{goodsAllocationReportRows(draft).map(
|
|
([, label, value, origin], index) => (
|
|
<div key={index}>
|
|
<dt className="font-semibold">{label}</dt>
|
|
<dd>
|
|
{value}
|
|
<small className="block">
|
|
{origin}
|
|
</small>
|
|
</dd>
|
|
</div>
|
|
),
|
|
)}
|
|
</dl>
|
|
</>
|
|
)}
|
|
</details>
|
|
);
|
|
}
|