416 lines
20 KiB
TypeScript
416 lines
20 KiB
TypeScript
import { inputText } from '../lib/input-text.ts';
|
|
import { useState } from 'react';
|
|
import {
|
|
objectiveImportBook,
|
|
objectiveImportCurrent,
|
|
objectiveImportReportRows,
|
|
objectiveImportSource,
|
|
objectiveImportSources,
|
|
objectiveImportTreatments,
|
|
newObjectiveImport,
|
|
reuseObjectiveImport,
|
|
recordObjectiveImports,
|
|
saveObjectiveImportBook,
|
|
type ObjectiveImportBook,
|
|
type ObjectiveImportRow,
|
|
} from '@/lib/iva-objective-imports';
|
|
import { annexIEntries } from '@/lib/iva-annex-i';
|
|
import { pharmaAnnexEntries } from '@/lib/iva-pharma-annex';
|
|
export function SimulationObjectiveImports({
|
|
draft,
|
|
onChange,
|
|
}: {
|
|
draft: Record<string, unknown>;
|
|
onChange: (field: string, value: string) => void;
|
|
}) {
|
|
const [error, setError] = useState('');
|
|
let book: ObjectiveImportBook;
|
|
try {
|
|
book = objectiveImportBook(draft);
|
|
} catch (e) {
|
|
return <p role="alert">{String(e)}</p>;
|
|
}
|
|
const save = (next: ObjectiveImportBook) => {
|
|
try {
|
|
onChange('modelo_a_snapshot', saveObjectiveImportBook(draft, next));
|
|
setError('');
|
|
} catch (e) {
|
|
setError(String(e));
|
|
}
|
|
};
|
|
const change = (id: string, patch: Partial<ObjectiveImportRow>) =>
|
|
save({
|
|
...book,
|
|
rows: book.rows.map((r) => (r.id === id ? { ...r, ...patch } : r)),
|
|
});
|
|
let sources: ReturnType<typeof objectiveImportSources> = [];
|
|
try {
|
|
sources = objectiveImportSources(draft);
|
|
} catch {
|
|
/* Preserve unrecoverable source; direct entry remains independent. */
|
|
}
|
|
return (
|
|
<details className="rounded border p-3">
|
|
<summary>
|
|
Importações definitivas — isenção objectiva interna (P046)
|
|
</summary>
|
|
<p>
|
|
Analise a transmissão interna hipotética dos mesmos bens. Não é
|
|
necessário criar uma venda interna. A enumeração legal é
|
|
exemplificativa; este percurso cobre as correspondências
|
|
expressas implementadas. Outros fundamentos permanecem por
|
|
enquadrar.
|
|
</p>
|
|
<p>{objectiveImportSource}</p>
|
|
{error && <p role="alert">{error}</p>}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
save({
|
|
...book,
|
|
rows: [
|
|
...book.rows,
|
|
newObjectiveImport(
|
|
crypto.randomUUID(),
|
|
inputText(draft.currency ?? ''),
|
|
),
|
|
],
|
|
})
|
|
}
|
|
>
|
|
Acrescentar importação objectiva
|
|
</button>
|
|
{book.rows.map((row) => {
|
|
const rule = objectiveImportTreatments.find(
|
|
(t) => t.id === row.reference.treatment,
|
|
);
|
|
return (
|
|
<details key={row.id}>
|
|
<summary>
|
|
{row.description || 'Importação por preparar'} —{' '}
|
|
{row.period || 'período por indicar'}
|
|
</summary>
|
|
{!!sources.length && (
|
|
<label>
|
|
Preencher campos em falta a partir de bens já
|
|
preparados
|
|
<select
|
|
value=""
|
|
onChange={(e) => {
|
|
const source = sources.find(
|
|
(s) => s.id === e.target.value,
|
|
);
|
|
if (source)
|
|
change(
|
|
row.id,
|
|
reuseObjectiveImport(
|
|
row,
|
|
source,
|
|
),
|
|
);
|
|
}}
|
|
>
|
|
<option value="">
|
|
Escolher origem sem sobrescrever edições
|
|
</option>
|
|
{sources.map((s) => (
|
|
<option key={s.id} value={s.id}>
|
|
{s.description} — {s.period}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)}
|
|
{(
|
|
[
|
|
'description',
|
|
'period',
|
|
'importer',
|
|
'documentRef',
|
|
'documentDate',
|
|
'scope',
|
|
'evidence',
|
|
] as const
|
|
).map((field, i) => (
|
|
<label key={field} className="block">
|
|
{
|
|
[
|
|
'Bens desta importação',
|
|
'Período da importação',
|
|
'Importador',
|
|
'Documento aduaneiro ou previsão',
|
|
'Data do documento ou previsão',
|
|
'Âmbito: bens,operação,período e condições',
|
|
'Factos ou pressupostos expressos',
|
|
][i]
|
|
}
|
|
<input
|
|
type={
|
|
field === 'period'
|
|
? 'month'
|
|
: field === 'documentDate'
|
|
? 'date'
|
|
: 'text'
|
|
}
|
|
value={row[field]}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
[field]: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
))}
|
|
<label>
|
|
Natureza dos dados
|
|
<select
|
|
value={row.origin}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
origin: e.target
|
|
.value as ObjectiveImportRow['origin'],
|
|
})
|
|
}
|
|
>
|
|
<option value="projected">
|
|
Pressupostos de projecção
|
|
</option>
|
|
<option value="effective">
|
|
Factos efectivos declarados
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{(
|
|
[
|
|
'definitive',
|
|
'goods',
|
|
'sameGoods',
|
|
'internalApplicable',
|
|
] as const
|
|
).map((field, i) => (
|
|
<label key={field} className="block">
|
|
{
|
|
[
|
|
'Importação definitiva',
|
|
'A operação importa bens,não um serviço',
|
|
'Correspondência refere-se aos mesmos bens e âmbito desta importação',
|
|
'Isenção objectiva interna aplicável na hipótese destes bens',
|
|
][i]
|
|
}
|
|
<select
|
|
value={row[field]}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
[field]: e.target.value,
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="yes">Sim</option>
|
|
<option value="no">Não</option>
|
|
</select>
|
|
</label>
|
|
))}
|
|
<label>
|
|
Correspondência da isenção interna
|
|
<select
|
|
value={row.reference.treatment}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
reference: {
|
|
...row.reference,
|
|
treatment: e.target.value,
|
|
confirmed: [],
|
|
},
|
|
internalApplicable: '',
|
|
})
|
|
}
|
|
>
|
|
<option value="other">
|
|
Escolher correspondência
|
|
</option>
|
|
{objectiveImportTreatments.map((t) => (
|
|
<option key={t.id} value={t.id}>
|
|
{t.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
{rule && (
|
|
<>
|
|
<p>
|
|
{rule.article}. As condições seguintes
|
|
referem-se à hipótese de transmissão no
|
|
território nacional dos bens identificados;
|
|
não ao fornecedor estrangeiro. Trocar
|
|
correspondência conserva anexos em rascunho
|
|
e limpa confirmações.
|
|
</p>
|
|
{rule.conditions.map((condition, i) => (
|
|
<label className="block" key={i}>
|
|
<input
|
|
type="checkbox"
|
|
checked={row.reference.confirmed.includes(
|
|
i,
|
|
)}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
reference: {
|
|
...row.reference,
|
|
confirmed: e.target
|
|
.checked
|
|
? [
|
|
...row
|
|
.reference
|
|
.confirmed,
|
|
i,
|
|
]
|
|
: row.reference.confirmed.filter(
|
|
(n) =>
|
|
n !== i,
|
|
),
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
{i === 0
|
|
? 'A transmissão interna hipotética estaria localizada em Moçambique; a operação real analisada continua a ser a importação'
|
|
: condition}
|
|
</label>
|
|
))}
|
|
</>
|
|
)}
|
|
{row.reference.treatment === 'annexI_goods' && (
|
|
<>
|
|
<label>
|
|
Posição do Anexo I
|
|
<select
|
|
value={row.reference.annexIItem ?? ''}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
reference: {
|
|
...row.reference,
|
|
annexIItem: e.target.value,
|
|
confirmed: [],
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
{annexIEntries.map((a) => (
|
|
<option key={a.id} value={a.id}>
|
|
{a.code} — {a.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label>
|
|
Após conferir os outros
|
|
tratamentos,corresponde apenas a9(12)h?
|
|
<select
|
|
value={
|
|
row.reference.annexIOnly ===
|
|
undefined
|
|
? ''
|
|
: row.reference.annexIOnly
|
|
? 'yes'
|
|
: 'no'
|
|
}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
reference: {
|
|
...row.reference,
|
|
annexIOnly:
|
|
e.target.value === ''
|
|
? undefined
|
|
: e.target.value ===
|
|
'yes',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="yes">
|
|
Sim,com fundamento nos factos
|
|
indicados
|
|
</option>
|
|
<option value="no">
|
|
Não;escolher correspondência
|
|
específica
|
|
</option>
|
|
</select>
|
|
</label>
|
|
</>
|
|
)}
|
|
{row.reference.treatment ===
|
|
'pharma_manufacturing_inputs' && (
|
|
<label>
|
|
Posição do Anexo III
|
|
<select
|
|
value={row.reference.pharmaAnnexItem ?? ''}
|
|
onChange={(e) =>
|
|
change(row.id, {
|
|
reference: {
|
|
...row.reference,
|
|
pharmaAnnexItem: e.target.value,
|
|
confirmed: [],
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por indicar</option>
|
|
{pharmaAnnexEntries.map((a) => (
|
|
<option key={a.id} value={a.id}>
|
|
{a.code} — {a.label}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
)}
|
|
</details>
|
|
);
|
|
})}
|
|
{!!book.rows.length && (
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
try {
|
|
save(recordObjectiveImports(draft, book));
|
|
} catch (e) {
|
|
setError(String(e));
|
|
}
|
|
}}
|
|
>
|
|
Conferir importações objectivas e guardar versão
|
|
</button>
|
|
)}
|
|
{book.result && (
|
|
<>
|
|
<p role="status">
|
|
{objectiveImportCurrent(draft, book)
|
|
? 'Resultado corresponde às entradas guardadas.'
|
|
: 'Entradas alteradas;resultado histórico conservado.'}{' '}
|
|
{book.history?.length ?? 0} versões anteriores. Sem
|
|
dedução ou soma aos livros internos.
|
|
</p>
|
|
<dl>
|
|
{objectiveImportReportRows(draft).map(
|
|
([, label, value, origin], i) => (
|
|
<div key={i}>
|
|
<dt>{label}</dt>
|
|
<dd>
|
|
{value}
|
|
<small className="block">
|
|
{origin}
|
|
</small>
|
|
</dd>
|
|
</div>
|
|
),
|
|
)}
|
|
</dl>
|
|
</>
|
|
)}
|
|
</details>
|
|
);
|
|
}
|