530 lines
24 KiB
TypeScript
530 lines
24 KiB
TypeScript
import { inputText } from '../lib/input-text.ts';
|
||
import { useState } from 'react';
|
||
import {
|
||
minerBook,
|
||
minerCurrent,
|
||
minerReportRows,
|
||
minerSource,
|
||
minerTreatments,
|
||
minerCommon,
|
||
minerVehicle,
|
||
minerReturn,
|
||
minerNeedsDeadlineExtension,
|
||
minerNeedsStayException,
|
||
newMiner,
|
||
recordMiners,
|
||
saveMinerBook,
|
||
type MinerBook,
|
||
type MinerRow,
|
||
} from '@/lib/iva-miners';
|
||
export function SimulationMiners({
|
||
draft,
|
||
onChange,
|
||
}: {
|
||
draft: Record<string, unknown>;
|
||
onChange: (field: string, value: string) => void;
|
||
}) {
|
||
const [error, setError] = useState('');
|
||
let book: MinerBook;
|
||
try {
|
||
book = minerBook(draft);
|
||
} catch (e) {
|
||
return <p role="alert">{String(e)}</p>;
|
||
}
|
||
const save = (next: MinerBook) => {
|
||
try {
|
||
onChange('modelo_a_snapshot', saveMinerBook(draft, next));
|
||
setError('');
|
||
} catch (e) {
|
||
setError(String(e));
|
||
}
|
||
};
|
||
const change = (id: string, patch: Partial<MinerRow>) =>
|
||
save({
|
||
...book,
|
||
rows: book.rows.map((r) => (r.id === id ? { ...r, ...patch } : r)),
|
||
});
|
||
return (
|
||
<details className="rounded border p-3">
|
||
<summary>
|
||
Importações dos mineiros — regime da África do Sul (P059)
|
||
</summary>
|
||
<p>
|
||
Lei n.º2/2011,artigos1–4:página1 doPDF;artigo5:página2/p110-(8).
|
||
O exemplar reúne vários diplomas;«Lei do Voluntariado» é o nome
|
||
do ficheiro original de uma das ligações,não a base deste
|
||
benefício.
|
||
Regulamento:Decreto3/2011,artigos1–8,páginas2–3/p152–153.
|
||
</p>
|
||
<p>
|
||
Prepare apenas o percurso dos bens desta importação. A redução
|
||
de50% pertence ao veículo separado da bagagem,não a todas as
|
||
importações dos mineiros. O simulador não concede
|
||
autorizações,nem emite declaração aduaneira. Importação
|
||
temporária em férias tem licença/prazos próprios;use o percurso
|
||
aduaneiro existente,não a transforme em isenção definitiva.
|
||
</p>
|
||
{error && <p role="alert">{error}</p>}
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
const next = newMiner(
|
||
crypto.randomUUID(),
|
||
inputText(draft.currency ?? ''),
|
||
);
|
||
const candidates = book.rows.filter(
|
||
(r) =>
|
||
r.beneficiary &&
|
||
r.contractRef &&
|
||
r.origin === next.origin,
|
||
);
|
||
const keys = new Set(
|
||
candidates.map(
|
||
(r) => r.beneficiary + '\u0000' + r.contractRef,
|
||
),
|
||
);
|
||
if (keys.size === 1) {
|
||
const source = candidates[0];
|
||
next.beneficiary = source.beneficiary;
|
||
next.contractRef = source.contractRef;
|
||
for (const k of [
|
||
'national',
|
||
'rsa',
|
||
'contract',
|
||
] as const)
|
||
next.conditions[k] = source.conditions[k];
|
||
}
|
||
save({ ...book, rows: [...book.rows, next] });
|
||
}}
|
||
>
|
||
Acrescentar importação de mineiro
|
||
</button>
|
||
{book.rows.map((row) => {
|
||
const rule = minerTreatments.find(
|
||
(t) => t.id === row.treatment,
|
||
);
|
||
const text = (
|
||
field: Exclude<keyof MinerRow, 'conditions'>,
|
||
label: string,
|
||
type = 'text',
|
||
) => (
|
||
<label key={field} className="block">
|
||
{label}
|
||
<input
|
||
type={type}
|
||
value={row[field]}
|
||
onChange={(e) =>
|
||
change(row.id, { [field]: e.target.value })
|
||
}
|
||
/>
|
||
</label>
|
||
);
|
||
const choice = (
|
||
key: keyof MinerRow['conditions'],
|
||
label: string,
|
||
) => (
|
||
<label key={key} className="block">
|
||
{label}
|
||
<select
|
||
value={row.conditions[key] ?? ''}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
conditions: {
|
||
...row.conditions,
|
||
[key]: e.target.value,
|
||
},
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por esclarecer</option>
|
||
<option value="yes">
|
||
Sim,segundo factos ou pressuposto identificado
|
||
</option>
|
||
<option value="no">Não</option>
|
||
</select>
|
||
</label>
|
||
);
|
||
return (
|
||
<details key={row.id}>
|
||
<summary>
|
||
{row.description ||
|
||
'Importação de mineiro por preparar'}{' '}
|
||
— {row.period || 'período por indicar'}
|
||
</summary>
|
||
<label>
|
||
Percurso dos bens
|
||
<select
|
||
value={row.treatment}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
treatment: e.target.value,
|
||
conditions: Object.fromEntries(
|
||
minerCommon.map(([k]) => [
|
||
k,
|
||
row.conditions[k],
|
||
]),
|
||
),
|
||
})
|
||
}
|
||
>
|
||
<option value="">Escolher percurso</option>
|
||
{minerTreatments.map((t) => (
|
||
<option key={t.id} value={t.id}>
|
||
{t.label}
|
||
</option>
|
||
))}
|
||
</select>
|
||
</label>
|
||
{text('description', 'Bens desta importação')}
|
||
{text('beneficiary', 'Mineiro beneficiário originário')}
|
||
{text(
|
||
'contractRef',
|
||
'Contrato e referência do visto de trabalho',
|
||
)}
|
||
{text('period', 'Período da importação', 'month')}
|
||
{text(
|
||
'importDate',
|
||
'Data da importação ou previsão',
|
||
'date',
|
||
)}
|
||
<label>
|
||
Natureza dos dados
|
||
<select
|
||
value={row.origin}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
origin: e.target
|
||
.value as MinerRow['origin'],
|
||
})
|
||
}
|
||
>
|
||
<option value="projected">
|
||
Pressupostos de projecção
|
||
</option>
|
||
<option value="effective">
|
||
Factos efectivos declarados
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{text(
|
||
'documentRef',
|
||
'Documento disponível ou previsão',
|
||
)}
|
||
{text(
|
||
'documentDate',
|
||
'Data do documento ou previsão',
|
||
'date',
|
||
)}
|
||
{text(
|
||
'scope',
|
||
'Âmbito:bens,operação,período e condições',
|
||
)}
|
||
{text('evidence', 'Factos ou pressupostos expressos')}
|
||
<label>
|
||
Titular do direito
|
||
<select
|
||
value={row.rightHolder}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
rightHolder: e.target
|
||
.value as MinerRow['rightHolder'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por indicar</option>
|
||
<option value="miner">Mineiro</option>
|
||
<option value="heir">
|
||
Herdeiro legal,direito não usado
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{minerCommon.map(([k, label]) => choice(k, label))}
|
||
{rule?.conditions.map(([k, label]) => choice(k, label))}
|
||
{row.rightHolder === 'heir' && (
|
||
<>
|
||
{text(
|
||
'heirRef',
|
||
'Herdeiro e fundamento da transmissão do direito',
|
||
)}
|
||
{text('deathDate', 'Data do óbito', 'date')}
|
||
{text(
|
||
'requestDate',
|
||
'Data do requerimento',
|
||
'date',
|
||
)}
|
||
{choice(
|
||
'heir',
|
||
'Qualidade de herdeiro legal identificada',
|
||
)}
|
||
{choice(
|
||
'unusedRight',
|
||
'Direito não usado pelo beneficiário originário',
|
||
)}
|
||
{choice(
|
||
'acquiredAlive',
|
||
'Bens adquiridos pelo mineiro em vida',
|
||
)}
|
||
</>
|
||
)}
|
||
{['baggage', 'return_baggage', 'monthly'].includes(
|
||
row.treatment,
|
||
) && (
|
||
<label>
|
||
Via dos bens
|
||
<select
|
||
value={row.route}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
route: e.target
|
||
.value as MinerRow['route'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por indicar</option>
|
||
<option value="accompanied">
|
||
Acompanhados pelo mineiro
|
||
</option>
|
||
<option value="company">
|
||
Empresa transportadora/distribuidora
|
||
</option>
|
||
</select>
|
||
</label>
|
||
)}
|
||
{text(
|
||
'customsRef',
|
||
'Referência aduaneira aplicável ou pressuposto da projecção',
|
||
)}
|
||
{text(
|
||
'customsScope',
|
||
'Âmbito do enquadramento aduaneiro nesta importação',
|
||
)}
|
||
{['monthly', 'accumulated'].includes(row.treatment) && (
|
||
<>
|
||
{text('value', 'Valor desta remessa emMZN')}
|
||
{text(
|
||
'periodTotal',
|
||
'Total do âmbito mensal/acumulado,incluindo esta e outras remessas',
|
||
)}
|
||
{text(
|
||
'quotaRef',
|
||
'Registo completo ou pressuposto do saldo,incluindo fora do dossier',
|
||
)}
|
||
<p>
|
||
Cobertura dos exemplares:15.000MZN por mês.
|
||
Revisão do limite2(5) não é presumida. Não
|
||
misturar saldos mensais com meses já
|
||
acumulados.
|
||
</p>
|
||
</>
|
||
)}
|
||
{row.treatment === 'accumulated' && (
|
||
<>
|
||
{text(
|
||
'accumulationStart',
|
||
'Primeiro mês acumulado',
|
||
'month',
|
||
)}
|
||
{text(
|
||
'accumulationMonths',
|
||
'Número de meses acumulados:1a6',
|
||
)}
|
||
</>
|
||
)}
|
||
{row.treatment === 'appliance' &&
|
||
text(
|
||
'kind',
|
||
'Tipo de electrodoméstico para o limite anual',
|
||
)}
|
||
{minerVehicle(row.treatment) && (
|
||
<>
|
||
<label>
|
||
Direito de veículo identificado
|
||
<select
|
||
value={row.kind}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
kind: e.target.value,
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por indicar</option>
|
||
<option value="vehicle">
|
||
Veículo automóvel
|
||
</option>
|
||
<option value="tractor">
|
||
Tractor agrícola e respectivas
|
||
alfaias
|
||
</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
Benefício anterior aplicável a este direito
|
||
<select
|
||
value={row.previousBenefit}
|
||
onChange={(e) =>
|
||
change(row.id, {
|
||
previousBenefit: e.target
|
||
.value as MinerRow['previousBenefit'],
|
||
})
|
||
}
|
||
>
|
||
<option value="">Por esclarecer</option>
|
||
<option value="none">
|
||
Nenhum,segundo histórico
|
||
identificado
|
||
</option>
|
||
<option value="known">
|
||
Sim,data conhecida
|
||
</option>
|
||
</select>
|
||
</label>
|
||
{row.previousBenefit === 'known' &&
|
||
text(
|
||
'previousBenefitDate',
|
||
'Data do benefício anterior aplicável',
|
||
'date',
|
||
)}
|
||
</>
|
||
)}
|
||
{(row.treatment === 'appliance' ||
|
||
minerVehicle(row.treatment)) && (
|
||
<>
|
||
{text(
|
||
'quantity',
|
||
'Quantidade abrangida nesta linha',
|
||
)}
|
||
{text(
|
||
'quotaRef',
|
||
'Histórico do direito,incluindo benefícios fora do dossier',
|
||
)}
|
||
</>
|
||
)}
|
||
{minerReturn(row.treatment) && (
|
||
<>
|
||
{text(
|
||
'arrivalDate',
|
||
'Data da chegada no regresso definitivo',
|
||
'date',
|
||
)}
|
||
{row.rightHolder !== 'heir' &&
|
||
text(
|
||
'requestDate',
|
||
'Data do requerimento do benefício',
|
||
'date',
|
||
)}
|
||
{minerNeedsDeadlineExtension(row) && (
|
||
<>
|
||
{choice(
|
||
'deadlineExtension',
|
||
'Invoca prorrogação excepcional do prazo de90dias,por motivo justificado?',
|
||
)}
|
||
{row.conditions.deadlineExtension ===
|
||
'yes' &&
|
||
text(
|
||
'extensionRef',
|
||
'Prorrogação e motivo justificado,âmbito e prazo concedido ou pressuposto expresso',
|
||
)}
|
||
</>
|
||
)}
|
||
</>
|
||
)}
|
||
{['return_vehicle', 'separate_vehicle'].includes(
|
||
row.treatment,
|
||
) && (
|
||
<>
|
||
{text(
|
||
'stayStart',
|
||
'Início da estadia naRSA',
|
||
'date',
|
||
)}
|
||
{text(
|
||
'stayEnd',
|
||
'Fim da estadia naRSA',
|
||
'date',
|
||
)}
|
||
{minerNeedsStayException(row) && (
|
||
<>
|
||
{choice(
|
||
'stayException',
|
||
'Invoca autorização excepcional6(7) por estadia inferior a um ano?',
|
||
)}
|
||
{row.conditions.stayException ===
|
||
'yes' &&
|
||
text(
|
||
'exceptionRef',
|
||
'Autorização/âmbito da excepção6(7)ou pressuposto expresso',
|
||
)}
|
||
</>
|
||
)}
|
||
</>
|
||
)}
|
||
{row.treatment === 'separate_vehicle' && (
|
||
<>
|
||
{text(
|
||
'normalVat',
|
||
'IVA informado sem o benefício de50%,emMZN',
|
||
)}
|
||
{text(
|
||
'normalVatRef',
|
||
'Referência do IVA normal ou pressuposto expresso',
|
||
)}
|
||
</>
|
||
)}
|
||
<p>
|
||
Trocar percurso conserva os dados ocultos no
|
||
rascunho e limpa as suas confirmações específicas.
|
||
Referências aduaneiras disponíveis podem ser
|
||
reutilizadas;nenhum procedimento específico daKAWENA
|
||
é imposto às outras vias.
|
||
</p>
|
||
</details>
|
||
);
|
||
})}
|
||
{!!book.rows.length && (
|
||
<button
|
||
type="button"
|
||
onClick={() => {
|
||
try {
|
||
save(recordMiners(draft, book));
|
||
} catch (e) {
|
||
setError(String(e));
|
||
}
|
||
}}
|
||
>
|
||
Conferir importações dos mineiros e guardar versão
|
||
</button>
|
||
)}
|
||
{book.result && (
|
||
<>
|
||
<p role="status">
|
||
{minerCurrent(draft, book)
|
||
? 'Resultado corresponde às entradas guardadas.'
|
||
: 'Entradas alteradas;resultado histórico conservado.'}{' '}
|
||
{book.history?.length ?? 0} versões anteriores.Sem
|
||
dedução/campo11 ou declaração aduaneira emitida.
|
||
</p>
|
||
<dl>
|
||
{minerReportRows(draft).map(
|
||
([, label, value, source], i) => (
|
||
<div key={i}>
|
||
<dt>{label}</dt>
|
||
<dd>
|
||
{value}
|
||
<small className="block">
|
||
{source}
|
||
</small>
|
||
</dd>
|
||
</div>
|
||
),
|
||
)}
|
||
</dl>
|
||
</>
|
||
)}
|
||
<details>
|
||
<summary>Fonte e âmbito documental</summary>
|
||
<p>{minerSource}</p>
|
||
</details>
|
||
</details>
|
||
);
|
||
}
|