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

667 lines
35 KiB
TypeScript

import { useState } from 'react';
import {
digitalBook,
digitalConditions,
digitalCurrent,
digitalReportRows,
digitalSource,
digitalTreatments,
newDigitalRow,
recordDigital,
saveDigitalBook,
switchDigitalKind,
switchDigitalTreatment,
type DigitalBook,
type DigitalRow,
} from '@/lib/iva-digital';
export function SimulationDigital({
draft,
onChange,
}: {
draft: Record<string, unknown>;
onChange: (field: string, value: string) => void;
}) {
const [error, setError] = useState('');
let book: DigitalBook;
try {
book = digitalBook(draft);
} catch (e) {
return <p role="alert">{String(e)}</p>;
}
const save = (next: DigitalBook) => {
try {
onChange('modelo_a_snapshot', saveDigitalBook(draft, next));
setError('');
} catch (e) {
setError(String(e));
}
};
const change = (id: string, patch: Partial<DigitalRow>) =>
save({
...book,
rows: book.rows.map((r) => (r.id === id ? { ...r, ...patch } : r)),
});
return (
<details className="space-y-3 rounded border p-3">
<summary>
Bens e serviços digitais — natureza, localização e obrigações
</summary>
<p>
Distinga o activo transmitido da funcionalidade prestada. O nome
comercial, a moeda, a nacionalidade ou um servidor não
determinam sozinhos o tratamento. Reutilize as referências da
operação e os documentos disponíveis.
</p>
<p>
Localização não concede isenção nem calcula IVA ou dedução. A
identificação do responsável não apresenta uma declaração nem
inicia pagamento. As formalidades remetidas para regulamentação
ficam assinaladas.
</p>
<p>
<strong>Cobertura digital deste incremento:</strong>{' '}
identificação da natureza, localização, responsável, rascunho,
histórico e relatório. As formalidades regulamentares ainda não
cotejadas — modelos da declaração e do mapa de retenções,
procedimentos de entrega e pagamento — não estão automatizadas.
Não representa cobertura digital integral nem calcula imposto ou
dedução.
</p>
<p>{digitalSource}</p>
{error && <p role="alert">{error}</p>}
<button
type="button"
className="underline"
onClick={() =>
save({
...book,
rows: [
...book.rows,
newDigitalRow(crypto.randomUUID()),
],
})
}
>
Acrescentar operação digital
</button>
{book.rows.map((row) => (
<details key={row.id} className="rounded border p-3">
<summary>
{row.description || 'Operação digital por identificar'}{' '}
— {row.period || 'mês por indicar'}
</summary>
<div className="grid gap-3 md:grid-cols-2">
<label>
Natureza da operação digital
<select
value={row.kind}
onChange={(e) =>
change(
row.id,
switchDigitalKind(row, e.target.value),
)
}
>
<option value="">Por esclarecer</option>
<option value="goods">
P130 — Transmissão de bem digital
</option>
<option value="service">
P121 — Prestação de serviço digital
</option>
</select>
</label>
{row.kind && (
<label>
Tratamento digital
<select
value={row.treatment}
onChange={(e) =>
change(
row.id,
switchDigitalTreatment(
row,
e.target.value,
),
)
}
>
<option value="">Por indicar</option>
{digitalTreatments
.filter((t) => t.kind === row.kind)
.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 DigitalRow['origin'],
})
}
>
<option value="projected">
Projectados / pressupostos
</option>
<option value="effective">
Efectivos declarados
</option>
</select>
</label>
{(
[
[
'description',
'Operação digital identificada',
],
[
'operationRef',
'Referência da operação / pressuposto',
],
[
'operationDate',
'Data da operação / prevista',
],
['period', 'Mês da operação'],
[
'subjectRef',
'Objecto, direitos transmitidos ou funcionalidade prestada',
],
[
'natureRef',
'Fundamento da distinção bem/serviço e natureza digital',
],
[
'useRef',
'Destinatário e utilização / pressuposto',
],
[
'documentRef',
'Documento existente / referência da previsão',
],
[
'documentDate',
'Data do documento / prevista',
],
[
'scope',
'Âmbito: operação, bens/serviços, período e condições',
],
[
'evidence',
'Factos disponíveis / pressupostos expressos',
],
[
'buyerPlace',
'Estabelecimento ou domicílio do adquirente',
],
[
'buyerRef',
'Referência do estabelecimento ou domicílio adquirente',
],
] as const
).map(([field, label]) => (
<label key={field}>
{label}
<input
type={
[
'operationDate',
'documentDate',
].includes(field)
? 'date'
: field === 'period'
? 'month'
: 'text'
}
value={row[field]}
onChange={(e) =>
change(row.id, {
[field]: e.target.value,
})
}
/>
</label>
))}
<label>
País do estabelecimento ou domicílio adquirente
<select
value={row.buyerCountry}
onChange={(e) =>
change(row.id, {
buyerCountry: e.target.value,
})
}
>
<option value="">Por esclarecer</option>
<option value="MZ">Moçambique</option>
<option value="foreign">Estrangeiro</option>
</select>
</label>
{row.buyerCountry !== 'foreign' && (
<>
<label>
Sede, EP ou domicílio a partir do qual o
fornecedor opera
<input
value={row.providerPlace}
onChange={(e) =>
change(row.id, {
providerPlace: e.target.value,
})
}
/>
</label>
<label>
Referência desse estabelecimento fornecedor
<input
value={row.providerRef}
onChange={(e) =>
change(row.id, {
providerRef: e.target.value,
})
}
/>
</label>
<label>
País do estabelecimento fornecedor
<select
value={row.providerCountry}
onChange={(e) =>
change(row.id, {
providerCountry: e.target.value,
})
}
>
<option value="">Por esclarecer</option>
<option value="MZ">Moçambique</option>
<option value="foreign">
Estrangeiro
</option>
</select>
</label>
</>
)}
{row.buyerCountry === 'MZ' &&
row.providerCountry === 'foreign' && (
<>
<label>
Adquirente sujeito passivo nacional
—26(4)
<select
value={row.buyerTaxable}
onChange={(e) =>
change(row.id, {
buyerTaxable:
e.target.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">Sim</option>
<option value="no">Não</option>
</select>
</label>
<label>
Fundamento da qualidade fiscal do
adquirente
<input
value={row.buyerTaxRef}
onChange={(e) =>
change(row.id, {
buyerTaxRef: e.target.value,
})
}
/>
</label>
<p>
A qualidade fiscal serve para
identificar o responsável; a sua falta
não transforma a localização nacional em
operação estrangeira.
</p>
{row.buyerTaxable === 'no' && (
<>
<label>
Fornecedor não residente sujeito
passivo
<select
value={row.providerTaxable}
onChange={(e) =>
change(row.id, {
providerTaxable:
e.target.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">
Sim
</option>
<option value="no">
Não
</option>
</select>
</label>
<label>
Fundamento da qualidade fiscal
do fornecedor não residente
<input
value={row.providerTaxRef}
onChange={(e) =>
change(row.id, {
providerTaxRef:
e.target.value,
})
}
/>
</label>
<label>
Representante residente nomeado
—26(1)
<select
value={row.representative}
onChange={(e) =>
change(row.id, {
representative:
e.target.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">
Sim
</option>
<option value="no">
Não
</option>
</select>
</label>
{row.representative === 'yes' && (
<>
<label>
Representante e
referência da
procuração/poderes
<input
value={
row.representativeRef
}
onChange={(e) =>
change(row.id, {
representativeRef:
e.target
.value,
})
}
/>
</label>
<label>
Nomeação comunicada à
contraparte antes da
operação —26(2)
<select
value={
row.communicationPrior
}
onChange={(e) =>
change(row.id, {
communicationPrior:
e.target
.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">
Sim
</option>
<option value="no">
Não
</option>
</select>
</label>
<label>
Referência da
comunicação
<input
value={
row.communicationRef
}
onChange={(e) =>
change(row.id, {
communicationRef:
e.target
.value,
})
}
/>
</label>
</>
)}
{row.representative === 'no' && (
<>
<label>
Aquisição no exercício
de actividade comercial,
industrial ou
profissional —26(3)
<select
value={
row.businessUse
}
onChange={(e) =>
change(row.id, {
businessUse:
e.target
.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">
Sim
</option>
<option value="no">
Não
</option>
</select>
</label>
<label>
Referência dessa
actividade e aquisição
<input
value={
row.businessRef
}
onChange={(e) =>
change(row.id, {
businessRef:
e.target
.value,
})
}
/>
</label>
</>
)}
</>
)}
</>
)}
{row.buyerCountry === 'MZ' &&
row.providerCountry === 'MZ' && (
<>
<label>
Fornecedor sujeito passivo nacional
<select
value={row.providerTaxable}
onChange={(e) =>
change(row.id, {
providerTaxable:
e.target.value,
})
}
>
<option value="">
Por esclarecer
</option>
<option value="yes">Sim</option>
<option value="no">Não</option>
</select>
</label>
<label>
Fundamento da qualidade fiscal do
fornecedor
<input
value={row.providerTaxRef}
onChange={(e) =>
change(row.id, {
providerTaxRef:
e.target.value,
})
}
/>
</label>
{row.kind === 'goods' && (
<>
<label>
Local do bem na colocação à
disposição —6(1)
<select
value={row.goodsPlace}
onChange={(e) =>
change(row.id, {
goodsPlace:
e.target.value,
})
}
>
<option value="">
Por demonstrar
</option>
<option value="MZ">
Moçambique, segundo
fundamento identificado
</option>
<option value="foreign">
Estrangeiro, segundo
fundamento identificado
</option>
</select>
</label>
<label>
Fundamento do local do bem
digital — sem inferência pelo
servidor
<input
value={row.goodsPlaceRef}
onChange={(e) =>
change(row.id, {
goodsPlaceRef:
e.target.value,
})
}
/>
</label>
</>
)}
</>
)}
</div>
<fieldset>
<legend>Factos próprios da natureza escolhida</legend>
{digitalConditions(row.kind).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 esclarecer</option>
<option value="yes">Sim</option>
<option value="no">Não</option>
</select>
</label>
))}
</fieldset>
<p>
Mudar natureza ou tratamento conserva referências e
campos ocultos; reveja as confirmações próprias. Os
dados não são copiados de outra oportunidade.
</p>
</details>
))}
{!!book.rows.length && (
<button
type="button"
onClick={() => {
try {
save(recordDigital(draft, book));
} catch (e) {
setError(String(e));
}
}}
>
Classificar operações digitais e guardar versão
</button>
)}
{book.result && (
<>
<p role="status">
{digitalCurrent(draft, book)
? 'Resultados correspondem às entradas guardadas.'
: 'Entradas alteradas; resultados históricos conservados. Reveja o delta afectado.'}{' '}
{book.history?.length ?? 0} versões anteriores. Sem
cálculo de IVA ou dedução.
</p>
<dl>
{digitalReportRows(draft).map(
([, label, value, origin], i) => (
<div key={i}>
<dt>{label}</dt>
<dd>
{value}
<small className="block">
{origin}
</small>
</dd>
</div>
),
)}
</dl>
</>
)}
</details>
);
}