Files
Investidor-V2/resources/js/components/simulation-goods-allocation.tsx
T

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>
);
}