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

386 lines
18 KiB
TypeScript

import { inputText } from '../lib/input-text.ts';
import { useState } from 'react';
import {
goodsPresumptionBook,
goodsPresumptionCurrent,
goodsPresumptionReportRows,
goodsPresumptionSource,
goodsPresumptionTreatments,
newGoodsPresumption,
presumptionConditions,
recordGoodsPresumptions,
saveGoodsPresumptionBook,
switchPresumptionTreatment,
type GoodsPresumptionBook,
type GoodsPresumptionRow,
} from '@/lib/iva-goods-presumptions';
export function SimulationGoodsPresumptions({
draft,
onChange,
}: {
draft: Record<string, unknown>;
onChange: (field: string, value: string) => void;
}) {
const [error, setError] = useState('');
let book: GoodsPresumptionBook;
try {
book = goodsPresumptionBook(draft);
} catch (cause) {
return <p role="alert">{String(cause)}</p>;
}
const save = (next: GoodsPresumptionBook) => {
try {
onChange(
'modelo_a_snapshot',
saveGoodsPresumptionBook(draft, next),
);
setError('');
} catch (cause) {
setError(String(cause));
}
};
const change = (id: string, patch: Partial<GoodsPresumptionRow>) =>
save({
...book,
rows: book.rows.map((r) => (r.id === id ? { ...r, ...patch } : r)),
});
return (
<details className="rounded border p-3">
<summary>Consignação e presunções de bens</summary>
<p>
Uma linha por conjunto identificado. Na consignação,180dias
contam da entrega ao destinatário. As presunções admitem prova
em contrário. Classificação não concede isenção,dedução ou
elegibilidade para margem.
</p>
<p>
Oportunidade:{' '}
{inputText(draft.context_opportunity ?? 'projecto')}. A data de
conferência situa o cenário; este percurso não determina a
exigibilidade,base ou IVA.
</p>
<p className="text-sm">{goodsPresumptionSource}</p>
{error && <p role="alert">{error}</p>}
<button
type="button"
onClick={() =>
save({
...book,
rows: [
...book.rows,
newGoodsPresumption(crypto.randomUUID()),
],
})
}
>
Acrescentar conjunto de bens
</button>
{book.rows.map((row) => (
<details key={row.id} className="rounded border p-3">
<summary>
{row.description || 'Conjunto por identificar'} —{' '}
{row.period || 'mês por indicar'}
</summary>
<div className="grid gap-3 md:grid-cols-2">
<label>
Percurso de consignação/presunção
<select
value={row.treatment}
onChange={(e) =>
change(
row.id,
switchPresumptionTreatment(
row,
e.target.value,
),
)
}
>
<option value="">Por indicar</option>
{goodsPresumptionTreatments.map((t) => (
<option key={t.id} value={t.id}>
{t.label}
</option>
))}
</select>
</label>
<label>
Natureza dos dados
<select
value={row.origin}
onChange={(e) =>
change(row.id, {
origin: e.target
.value as GoodsPresumptionRow['origin'],
})
}
>
<option value="projected">
Projectados / pressupostos
</option>
<option value="effective">
Efectivos declarados
</option>
</select>
</label>
{(
[
[
'description',
'Conjunto/operação identificados',
],
[
'operationRef',
'Referência da operação / pressuposto',
],
[
'operationDate',
'Data de conferência / prevista',
],
['period', 'Mês da conferência'],
[
'documentRef',
'Documento / referência da previsão',
],
[
'documentDate',
'Data do documento / prevista',
],
['goodsRef', 'Bens e elementos identificados'],
[
'scope',
'Âmbito:conjunto,estabelecimentos,operação e período',
],
[
'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>
))}
{row.treatment === 'consignment_180' ? (
<>
<label>
Data da entrega ao destinatário
<input
type="date"
value={row.deliveryDate}
onChange={(e) =>
change(row.id, {
deliveryDate: e.target.value,
})
}
/>
</label>
<label>
Destinatário e referência da entrega
<input
value={row.recipientRef}
onChange={(e) =>
change(row.id, {
recipientRef: e.target.value,
})
}
/>
</label>
<p>
Identifique apenas o conjunto não devolvido.
Separe devoluções parciais por conjunto; uma
devolução posterior não apaga o cenário
anteriormente guardado.
</p>
</>
) : (
row.treatment && (
<>
<label>
Levantamento/inventário e
estabelecimentos abrangidos
<input
value={row.inventoryRef}
onChange={(e) =>
change(row.id, {
inventoryRef:
e.target.value,
})
}
/>
</label>
{row.treatment === 'excess_consumption' && (
<>
{(
[
[
'quantity',
'Quantidade consumida',
],
[
'quantityUnit',
'Unidade da quantidade',
],
[
'productionRef',
'Volume de produção e comparação que fundamenta o excesso',
],
] as const
).map(([field, label]) => (
<label key={field}>
{label}
<input
value={row[field]}
onChange={(e) =>
change(row.id, {
[field]:
e.target
.value,
})
}
/>
</label>
))}
<p>
Sem percentagem ou limiar de
consumo por defeito.
</p>
</>
)}
<label>
Existe prova em contrário para o âmbito
declarado?
<select
value={row.contraryProof}
onChange={(e) =>
change(row.id, {
contraryProof: e.target
.value as GoodsPresumptionRow['contraryProof'],
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">Sim</option>
<option value="no">Não</option>
</select>
</label>
{row.contraryProof === 'yes' && (
<label>
Referência e âmbito da prova em
contrário
<input
value={row.contraryProofRef}
onChange={(e) =>
change(row.id, {
contraryProofRef:
e.target.value,
})
}
/>
</label>
)}
</>
)
)}
</div>
<fieldset>
<legend>Factos próprios do percurso</legend>
{presumptionConditions(row.treatment).map(
([key, label]) => (
<label className="block" key={key}>
{label}
<select
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>
<p>
Trocar percurso conserva dados/referências ocultos;
reveja as confirmações aplicáveis. Prova em contrário
afasta a presunção no seu âmbito,sem transformar o
resultado em isenção.
</p>
</details>
))}
{!!book.rows.length && (
<button
type="button"
onClick={() => {
try {
save(recordGoodsPresumptions(draft, book));
} catch (cause) {
setError(String(cause));
}
}}
>
Conferir consignação/presunções e guardar versão
</button>
)}
{book.result && (
<>
<p role="status">
{goodsPresumptionCurrent(draft, book)
? 'Classificações correspondentes às entradas guardadas.'
: 'Entradas alteradas;resultado histórico conservado.Reveja e confira novamente.'}{' '}
{book.history?.length ?? 0} versões anteriores.Sem
IVA,base,dedução ou margem calculados.
</p>
<dl>
{goodsPresumptionReportRows(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>
</>
)}
</details>
);
}