Wire grounded private investment preparation into QA dossier path
This commit is contained in:
@@ -1,24 +1,232 @@
|
||||
import {
|
||||
PreparationSummary,
|
||||
type Preparation,
|
||||
} from '@/components/private-investment-preparation';
|
||||
import { Link } from '@inertiajs/react';
|
||||
|
||||
type Snapshot = {context_revision:number;path?:{definition_version:number;steps:Array<{code:string;title:string;applicability:string;reason:string;state:string;context_review_required?:boolean}>}; zone?:{title:string;href:string;version:number|string;fields?:Record<string,string>;analysis?:{conditions?:Array<{id:string;label:string;knowledge:string;source_reference?:string;valid_from?:string;valid_until?:string}>;source?:{title:string;url:string;diploma?:string;article?:string;valid_from?:string;valid_until?:string}|null}}|null;fields?:Record<string,string>};
|
||||
export function InvestmentContextAssessment({raw,contextId}:{raw:unknown;contextId?:string|null}) {
|
||||
let snapshot:Snapshot|null=null;
|
||||
try {const value=JSON.parse(String(raw ?? ''));if(value.version===1) snapshot=value;} catch { /* Missing context remains explicit. */ }
|
||||
if(!snapshot) return null;
|
||||
const fields=snapshot.fields ?? {};const zone=snapshot.zone;
|
||||
const regime=zone?.fields?.investment_regime ?? fields.investment_regime;
|
||||
const names:Record<string,string>={zee:'ZEE',zfi:'ZFI',industrial_park:'Parque industrial'};
|
||||
return <section className="space-y-2 rounded border border-amber-400 p-3" aria-label="Aplicabilidade ao investimento">
|
||||
<h3 className="font-semibold">Aplicabilidade ao investimento · contexto v{snapshot.context_revision}</h3>
|
||||
<p>Origem do investidor: {{national:'nacional',foreign:'estrangeiro',mixed:'misto'}[fields.investor_origin] ?? 'informação em falta'}. Residência fiscal declarada: {fields.tax_residency_country || 'informação em falta'}. Estas condições são distintas; uma não determina a outra.</p>
|
||||
{zone ? <><p><strong>Potencialmente aplicável — análise específica de {names[regime ?? ''] ?? 'zona seleccionada'}.</strong> <Link className="underline" href={zone.href}>{zone.title} · versão {zone.version} · consultar ficha e fundamentos</Link>.</p>
|
||||
<p>A selecção identifica a referência consultada; não confirma o reconhecimento da entidade, actividade autorizada, licença ou acesso a benefícios. Consulte as condições documentadas na ficha e reúna a autorização ou evidência correspondente no dossier.</p>
|
||||
{zone.analysis?.source && <p>Fundamento cadastrado: <a className="underline" href={zone.analysis.source.url}>{zone.analysis.source.diploma || zone.analysis.source.title} {zone.analysis.source.article}</a>. Período cadastrado: {zone.analysis.source.valid_from || 'início por indicar'} a {zone.analysis.source.valid_until || 'sem termo indicado'}. A cobertura do investimento exige correspondência com estas condições.</p>}
|
||||
{zone.analysis?.conditions?.length ? <ul className="list-disc pl-5">{zone.analysis.conditions.map(condition=><li key={condition.id}><strong>{condition.label}</strong>: {condition.knowledge==='documented'?'condição documentada; cumprimento pelo investimento por confirmar':condition.knowledge==='disputed'?'condição com informação divergente':'informação em falta'}. {condition.source_reference && <>Fundamento: {condition.source_reference}.</>} {condition.valid_from && <>Desde {condition.valid_from}.</>} {condition.valid_until && <>Até {condition.valid_until}.</>}</li>)}</ul> : <p>Condições específicas: informação estruturada em falta nesta referência. A ficha e os documentos continuam consultáveis; não se presume cumprimento.</p>}
|
||||
<p role="status">Benefício fiscal deste enquadramento: indeterminado. Não existe neste consumidor uma regra executável ligada ao reconhecimento e condições da zona. No simulador, o IVA disponível corresponde apenas ao cenário geral sem benefício, sobre vendas declaradas compatíveis; não simula o regime especial. O cenário com benefício e o apuramento final estão indisponíveis.</p></>
|
||||
: <p>Enquadramento geral de preparação: sem ZEE, ZFI ou parque seleccionado. Isso não confirma a elegibilidade para uma operação fiscal. O cálculo mantém o âmbito e as exclusões da versão publicada.</p>}
|
||||
<p>Confirmado neste quadro significa apenas dado recuperado do dossier; declarações e referências não são decisões jurídicas. Requisitos específicos não documentados permanecem indeterminados.</p>
|
||||
{snapshot.path && <details><summary>Passos adaptados pelo percurso existente · versão {snapshot.path.definition_version}</summary><ul className="list-disc pl-5">{snapshot.path.steps.map(step=><li key={step.code}>{step.code} — {step.title}: {step.context_review_required?'informação alterada; rever fundamento':step.applicability==='not_needed_for_preparation'?'não aplicável à preparação declarada':step.applicability==='undetermined'?'informação em falta':['completed','approved'].includes(step.state)?'preparação confirmada no percurso; não é decisão fiscal':'potencialmente aplicável'}. {step.reason}</li>)}</ul></details>}
|
||||
{contextId && <Link className="underline" href={`/investimentos/${contextId}/contexto/editar`}>Alterar contexto e comparar impacto antes de guardar</Link>}
|
||||
</section>;
|
||||
type Snapshot = {
|
||||
preparation?: Preparation | null;
|
||||
context_revision: number;
|
||||
path?: {
|
||||
definition_version: number;
|
||||
steps: Array<{
|
||||
code: string;
|
||||
title: string;
|
||||
applicability: string;
|
||||
reason: string;
|
||||
state: string;
|
||||
context_review_required?: boolean;
|
||||
}>;
|
||||
};
|
||||
zone?: {
|
||||
title: string;
|
||||
href: string;
|
||||
version: number | string;
|
||||
fields?: Record<string, string>;
|
||||
analysis?: {
|
||||
conditions?: Array<{
|
||||
id: string;
|
||||
label: string;
|
||||
knowledge: string;
|
||||
source_reference?: string;
|
||||
valid_from?: string;
|
||||
valid_until?: string;
|
||||
}>;
|
||||
source?: {
|
||||
title: string;
|
||||
url: string;
|
||||
diploma?: string;
|
||||
article?: string;
|
||||
valid_from?: string;
|
||||
valid_until?: string;
|
||||
} | null;
|
||||
};
|
||||
} | null;
|
||||
fields?: Record<string, string>;
|
||||
};
|
||||
export function InvestmentContextAssessment({
|
||||
raw,
|
||||
contextId,
|
||||
}: {
|
||||
raw: unknown;
|
||||
contextId?: string | null;
|
||||
}) {
|
||||
let snapshot: Snapshot | null = null;
|
||||
try {
|
||||
const value = JSON.parse(String(raw ?? ''));
|
||||
if (value.version === 1) snapshot = value;
|
||||
} catch {
|
||||
/* Missing context remains explicit. */
|
||||
}
|
||||
if (!snapshot) return null;
|
||||
const fields = snapshot.fields ?? {};
|
||||
const zone = snapshot.zone;
|
||||
const regime = zone?.fields?.investment_regime ?? fields.investment_regime;
|
||||
const names: Record<string, string> = {
|
||||
zee: 'ZEE',
|
||||
zfi: 'ZFI',
|
||||
industrial_park: 'Parque industrial',
|
||||
};
|
||||
return (
|
||||
<section
|
||||
className="space-y-2 rounded border border-amber-400 p-3"
|
||||
aria-label="Aplicabilidade ao investimento"
|
||||
>
|
||||
<h3 className="font-semibold">
|
||||
Aplicabilidade ao investimento · contexto v
|
||||
{snapshot.context_revision}
|
||||
</h3>
|
||||
<p>
|
||||
Origem do investidor:{' '}
|
||||
{{
|
||||
national: 'nacional',
|
||||
foreign: 'estrangeiro',
|
||||
mixed: 'misto',
|
||||
}[fields.investor_origin] ?? 'informação em falta'}
|
||||
. Residência fiscal declarada:{' '}
|
||||
{fields.tax_residency_country || 'informação em falta'}. Estas
|
||||
condições são distintas; uma não determina a outra.
|
||||
</p>
|
||||
{zone ? (
|
||||
<>
|
||||
<p>
|
||||
<strong>
|
||||
Potencialmente aplicável — análise específica de{' '}
|
||||
{names[regime ?? ''] ?? 'zona seleccionada'}.
|
||||
</strong>{' '}
|
||||
<Link className="underline" href={zone.href}>
|
||||
{zone.title} · versão {zone.version} · consultar
|
||||
ficha e fundamentos
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
<p>
|
||||
A selecção identifica a referência consultada; não
|
||||
confirma o reconhecimento da entidade, actividade
|
||||
autorizada, licença ou acesso a benefícios. Consulte as
|
||||
condições documentadas na ficha e reúna a autorização ou
|
||||
evidência correspondente no dossier.
|
||||
</p>
|
||||
{zone.analysis?.source && (
|
||||
<p>
|
||||
Fundamento cadastrado:{' '}
|
||||
<a
|
||||
className="underline"
|
||||
href={zone.analysis.source.url}
|
||||
>
|
||||
{zone.analysis.source.diploma ||
|
||||
zone.analysis.source.title}{' '}
|
||||
{zone.analysis.source.article}
|
||||
</a>
|
||||
. Período cadastrado:{' '}
|
||||
{zone.analysis.source.valid_from ||
|
||||
'início por indicar'}{' '}
|
||||
a{' '}
|
||||
{zone.analysis.source.valid_until ||
|
||||
'sem termo indicado'}
|
||||
. A cobertura do investimento exige correspondência
|
||||
com estas condições.
|
||||
</p>
|
||||
)}
|
||||
{zone.analysis?.conditions?.length ? (
|
||||
<ul className="list-disc pl-5">
|
||||
{zone.analysis.conditions.map((condition) => (
|
||||
<li key={condition.id}>
|
||||
<strong>{condition.label}</strong>:{' '}
|
||||
{condition.knowledge === 'documented'
|
||||
? 'condição documentada; cumprimento pelo investimento por confirmar'
|
||||
: condition.knowledge === 'disputed'
|
||||
? 'condição com informação divergente'
|
||||
: 'informação em falta'}
|
||||
.{' '}
|
||||
{condition.source_reference && (
|
||||
<>
|
||||
Fundamento:{' '}
|
||||
{condition.source_reference}.
|
||||
</>
|
||||
)}{' '}
|
||||
{condition.valid_from && (
|
||||
<>Desde {condition.valid_from}.</>
|
||||
)}{' '}
|
||||
{condition.valid_until && (
|
||||
<>Até {condition.valid_until}.</>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>
|
||||
Condições específicas: informação estruturada em
|
||||
falta nesta referência. A ficha e os documentos
|
||||
continuam consultáveis; não se presume cumprimento.
|
||||
</p>
|
||||
)}
|
||||
<p role="status">
|
||||
Benefício fiscal deste enquadramento: indeterminado. Não
|
||||
existe neste consumidor uma regra executável ligada ao
|
||||
reconhecimento e condições da zona. No simulador, o IVA
|
||||
disponível corresponde apenas ao cenário geral sem
|
||||
benefício, sobre vendas declaradas compatíveis; não
|
||||
simula o regime especial. O cenário com benefício e o
|
||||
apuramento final estão indisponíveis.
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<p>
|
||||
Enquadramento geral de preparação: sem ZEE, ZFI ou parque
|
||||
seleccionado. Isso não confirma a elegibilidade para uma
|
||||
operação fiscal. O cálculo mantém o âmbito e as exclusões da
|
||||
versão publicada.
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
Confirmado neste quadro significa apenas dado recuperado do
|
||||
dossier; declarações e referências não são decisões jurídicas.
|
||||
Requisitos específicos não documentados permanecem
|
||||
indeterminados.
|
||||
</p>
|
||||
{snapshot.path && (
|
||||
<details>
|
||||
<summary>
|
||||
Passos adaptados pelo percurso existente · versão{' '}
|
||||
{snapshot.path.definition_version}
|
||||
</summary>
|
||||
<ul className="list-disc pl-5">
|
||||
{snapshot.path.steps.map((step) => (
|
||||
<li key={step.code}>
|
||||
{step.code} — {step.title}:{' '}
|
||||
{step.context_review_required
|
||||
? 'informação alterada; rever fundamento'
|
||||
: step.applicability ===
|
||||
'not_needed_for_preparation'
|
||||
? 'não aplicável à preparação declarada'
|
||||
: step.applicability === 'undetermined'
|
||||
? 'informação em falta'
|
||||
: ['completed', 'approved'].includes(
|
||||
step.state,
|
||||
)
|
||||
? 'preparação confirmada no percurso; não é decisão fiscal'
|
||||
: 'potencialmente aplicável'}
|
||||
. {step.reason}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
)}
|
||||
{snapshot.preparation?.enabled && (
|
||||
<PreparationSummary
|
||||
data={snapshot.preparation}
|
||||
caseId={contextId ?? undefined}
|
||||
/>
|
||||
)}
|
||||
{contextId && (
|
||||
<Link
|
||||
className="underline"
|
||||
href={`/investimentos/${contextId}/contexto/editar`}
|
||||
>
|
||||
Alterar contexto e comparar impacto antes de guardar
|
||||
</Link>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,457 @@
|
||||
import { Link } from '@inertiajs/react';
|
||||
import { card, input } from '@/pages/investment/shared';
|
||||
|
||||
export type PreparationDocument = {
|
||||
document_id: string;
|
||||
file_name: string;
|
||||
status: string;
|
||||
malware_scan_status: string;
|
||||
};
|
||||
export type Preparation = {
|
||||
version: string;
|
||||
enabled: boolean;
|
||||
mode: string;
|
||||
period_covered: boolean;
|
||||
scope_covered: boolean;
|
||||
reason: string[];
|
||||
missing_fields: string[];
|
||||
missing_labels?: string[];
|
||||
authority: string;
|
||||
next: string;
|
||||
calculation_notice: string;
|
||||
notice: string;
|
||||
source: { url: string; sha256: string };
|
||||
authority_source: { reference: string; url: string };
|
||||
questions: Array<{
|
||||
key: string;
|
||||
label: string;
|
||||
type?: string;
|
||||
options?: Record<string, string>;
|
||||
when?: { field: string; equals: string };
|
||||
source: string;
|
||||
help?: string;
|
||||
}>;
|
||||
requirements: Array<{
|
||||
key: string;
|
||||
label: string;
|
||||
state: string;
|
||||
required: boolean;
|
||||
document_id: string | null;
|
||||
document: PreparationDocument | null;
|
||||
stage: string;
|
||||
reason: string;
|
||||
source: { reference: string; url: string; period: string };
|
||||
}>;
|
||||
};
|
||||
const states: Record<string, string> = {
|
||||
not_applicable: 'Não aplicável neste contexto',
|
||||
indeterminate: 'Informação em falta para decidir',
|
||||
missing: 'Documento por associar',
|
||||
associated: 'Documento associado — conteúdo por conferir',
|
||||
};
|
||||
export const preparationMode = (mode: string) =>
|
||||
({
|
||||
authorization: 'Pedido de autorização',
|
||||
registration: 'Pedido de mero registo',
|
||||
indeterminate: 'Enquadramento por determinar',
|
||||
})[mode] ?? mode;
|
||||
|
||||
export function PreparationSummary({
|
||||
data,
|
||||
caseId,
|
||||
}: {
|
||||
data: Preparation | null | undefined;
|
||||
caseId?: string;
|
||||
}) {
|
||||
if (!data) return null;
|
||||
return (
|
||||
<section
|
||||
id="private-investment-preparation"
|
||||
className={card + ' space-y-3'}
|
||||
aria-label="Preparação adaptada do investimento privado"
|
||||
>
|
||||
<h2 className="text-xl font-bold">
|
||||
Preparar o pedido de investimento privado
|
||||
</h2>
|
||||
{!data.enabled ? (
|
||||
<p>
|
||||
Use os dados deste dossier para identificar o pedido e os
|
||||
documentos aplicáveis. A preparação é opcional e não atribui
|
||||
benefícios.
|
||||
</p>
|
||||
) : (
|
||||
<>
|
||||
<p>
|
||||
<strong>{preparationMode(data.mode)}</strong> · recorte
|
||||
de 2026 ·{' '}
|
||||
{data.version.replace(
|
||||
'private-investment-preparation-',
|
||||
'',
|
||||
)}
|
||||
</p>
|
||||
<p>{data.next}</p>
|
||||
{data.missing_fields.length > 0 && (
|
||||
<p>
|
||||
Informação em falta:{' '}
|
||||
{(
|
||||
data.missing_labels ??
|
||||
data.missing_fields.map(
|
||||
(key) =>
|
||||
data.questions?.find(
|
||||
(q) => q.key === key,
|
||||
)?.label ??
|
||||
(
|
||||
{
|
||||
currency: 'Moeda do projecto',
|
||||
expected_start_date:
|
||||
'Data prevista de início',
|
||||
entity_stage:
|
||||
'Situação da entidade',
|
||||
} as Record<string, string>
|
||||
)[key] ??
|
||||
key,
|
||||
)
|
||||
).join('; ')}
|
||||
.
|
||||
</p>
|
||||
)}
|
||||
{!data.period_covered && (
|
||||
<p>
|
||||
Este incremento cobre pedidos com início previsto em
|
||||
2026. Uma data em falta ou fora desse recorte não
|
||||
permite determinar o pedido por este lote; os
|
||||
restantes trabalhos do dossier continuam
|
||||
disponíveis.
|
||||
</p>
|
||||
)}
|
||||
{!data.scope_covered && (
|
||||
<p>
|
||||
Declare a actividade efectiva. Prospecção,
|
||||
pesquisa/produção extractiva e investimento público
|
||||
ou exclusivamente social/sem fins lucrativos seguem
|
||||
enquadramentos próprios, fora deste lote.
|
||||
</p>
|
||||
)}
|
||||
{data.reason.map((reason) => (
|
||||
<p key={reason}>{reason}</p>
|
||||
))}
|
||||
<p>
|
||||
Encaminhamento indicativo: {data.authority}.{' '}
|
||||
<a
|
||||
className="underline"
|
||||
href={data.authority_source.url}
|
||||
>
|
||||
{data.authority_source.reference}
|
||||
</a>
|
||||
</p>
|
||||
<ul className="space-y-3">
|
||||
{data.requirements
|
||||
.filter((r) => r.state !== 'not_applicable')
|
||||
.map((r) => (
|
||||
<li key={r.key} className="rounded border p-3">
|
||||
<strong>{r.label}</strong> —{' '}
|
||||
{states[r.state]}.{' '}
|
||||
{r.document?.file_name && (
|
||||
<span>
|
||||
Ficheiro: {r.document.file_name}
|
||||
.{' '}
|
||||
</span>
|
||||
)}
|
||||
<p>
|
||||
{r.reason}{' '}
|
||||
<a
|
||||
className="underline"
|
||||
href={r.source.url}
|
||||
>
|
||||
Ver fundamento: {r.source.reference}
|
||||
</a>{' '}
|
||||
· {r.source.period}.
|
||||
</p>
|
||||
{caseId && (
|
||||
<Link
|
||||
className="underline"
|
||||
href={`/investimentos/${caseId}/contexto/editar#preparation-documents`}
|
||||
>
|
||||
Rever dados ou associar documento do
|
||||
dossier
|
||||
</Link>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<details>
|
||||
<summary>
|
||||
Exigências que não se aplicam — histórico preservado
|
||||
</summary>
|
||||
{data.requirements
|
||||
.filter((r) => r.state === 'not_applicable')
|
||||
.map((r) => (
|
||||
<p key={r.key}>
|
||||
{r.label}: {r.reason}{' '}
|
||||
{r.document_id && (
|
||||
<>
|
||||
Associação anterior mantida
|
||||
{r.document?.file_name
|
||||
? `: ${r.document.file_name}`
|
||||
: ''}
|
||||
.
|
||||
</>
|
||||
)}{' '}
|
||||
<a
|
||||
className="underline"
|
||||
href={r.source.url}
|
||||
>
|
||||
{r.source.reference}
|
||||
</a>
|
||||
</p>
|
||||
))}
|
||||
</details>
|
||||
<p>{data.calculation_notice}</p>
|
||||
<p>{data.notice}</p>
|
||||
</>
|
||||
)}
|
||||
<a className="underline" href={data.source.url}>
|
||||
Consultar o exemplar oficial e os fundamentos
|
||||
</a>
|
||||
{caseId && (
|
||||
<p>
|
||||
<Link
|
||||
className="underline"
|
||||
href={`/investimentos/${caseId}/contexto/editar#preparation-questions`}
|
||||
>
|
||||
Completar apenas os dados em falta ou editar declarações
|
||||
</Link>
|
||||
</p>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function PreparationEditor({
|
||||
data,
|
||||
fields,
|
||||
changes,
|
||||
documents,
|
||||
links,
|
||||
onChange,
|
||||
onLink,
|
||||
disabled,
|
||||
}: {
|
||||
data: Preparation;
|
||||
fields: Record<string, string>;
|
||||
changes: Record<string, string>;
|
||||
documents: PreparationDocument[];
|
||||
links: Record<string, string | null>;
|
||||
onChange: (key: string, value: string) => void;
|
||||
onLink: (key: string, value: string | null) => void;
|
||||
disabled: boolean;
|
||||
}) {
|
||||
const values = { ...fields, ...changes };
|
||||
const active = values.investment_preparation === 'yes';
|
||||
const excluded = ['extractive', 'public_nonprofit'].includes(
|
||||
values.investment_activity_scope,
|
||||
);
|
||||
const applicable = (q: Preparation['questions'][number]) =>
|
||||
!q.when || values[q.when.field] === q.when.equals;
|
||||
// Keep a field in place while the user edits it; collapse only recovered answers.
|
||||
const known = (q: Preparation['questions'][number]) =>
|
||||
!!fields[q.key] && fields[q.key] !== 'unknown';
|
||||
const render = (q: Preparation['questions'][number]) => (
|
||||
<label className="grid gap-1" key={q.key} htmlFor={'prep-' + q.key}>
|
||||
{q.label}
|
||||
{q.options ? (
|
||||
<select
|
||||
id={'prep-' + q.key}
|
||||
className={input}
|
||||
disabled={disabled}
|
||||
value={values[q.key] ?? ''}
|
||||
onChange={(e) => onChange(q.key, e.target.value)}
|
||||
>
|
||||
<option value="">Por indicar</option>
|
||||
{Object.entries(q.options).map(([value, text]) => (
|
||||
<option key={value} value={value}>
|
||||
{text}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<input
|
||||
id={'prep-' + q.key}
|
||||
className={input}
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
value={values[q.key] ?? ''}
|
||||
onChange={(e) => onChange(q.key, e.target.value)}
|
||||
/>
|
||||
)}
|
||||
<span className="text-sm">
|
||||
{q.help} Fundamento: {q.source}.
|
||||
</span>
|
||||
</label>
|
||||
);
|
||||
const questions = data.questions.filter(
|
||||
(q) =>
|
||||
q.key !== 'investment_preparation' &&
|
||||
applicable(q) &&
|
||||
(!excluded || q.key === 'investment_activity_scope'),
|
||||
);
|
||||
const needed = questions.filter(
|
||||
(q) =>
|
||||
!known(q) &&
|
||||
(!data.enabled ||
|
||||
data.mode !== 'authorization' ||
|
||||
data.missing_fields.includes(q.key)),
|
||||
);
|
||||
return (
|
||||
<section
|
||||
id="preparation-questions"
|
||||
className={card + ' space-y-4'}
|
||||
aria-label="Dados do pedido de investimento privado"
|
||||
>
|
||||
<h2 className="text-xl font-bold">
|
||||
Dados em falta para preparar o pedido
|
||||
</h2>
|
||||
<p>
|
||||
Valores conhecidos são reutilizados. As alterações só são
|
||||
gravadas depois da comparação de impacto. Nacionalidade e
|
||||
residência não determinam a origem do capital nem a modalidade
|
||||
da empresa.
|
||||
</p>
|
||||
{render(data.questions[0])}
|
||||
{active && (
|
||||
<>
|
||||
{needed.map(render)}
|
||||
<details>
|
||||
<summary>
|
||||
Dados já declarados — consultar ou alterar
|
||||
</summary>
|
||||
<div className="space-y-3">
|
||||
{questions.filter(known).map(render)}
|
||||
</div>
|
||||
</details>
|
||||
<p>
|
||||
Data, moeda e situação da entidade usam as declarações
|
||||
acima.{' '}
|
||||
{data.missing_fields.filter((k) =>
|
||||
[
|
||||
'currency',
|
||||
'expected_start_date',
|
||||
'entity_stage',
|
||||
].includes(k),
|
||||
).length > 0 &&
|
||||
'Complete esses campos em falta antes de comparar.'}
|
||||
</p>
|
||||
<div id="preparation-documents" className="space-y-3">
|
||||
<h3 className="font-bold">
|
||||
Associar documentos já existentes no dossier
|
||||
</h3>
|
||||
<p>
|
||||
Carregue documentos pelo Balcão Virtual do mesmo
|
||||
dossier. A associação não aprova o conteúdo nem
|
||||
substitui a análise do pedido.
|
||||
</p>
|
||||
{data.requirements
|
||||
.filter((r) => r.required)
|
||||
.map((r) => (
|
||||
<label className="grid gap-1" key={r.key}>
|
||||
{r.label}
|
||||
<select
|
||||
className={input}
|
||||
disabled={disabled}
|
||||
value={
|
||||
Object.hasOwn(links, r.key)
|
||||
? (links[r.key] ?? '')
|
||||
: (r.document_id ?? '')
|
||||
}
|
||||
onChange={(e) =>
|
||||
onLink(
|
||||
r.key,
|
||||
e.target.value || null,
|
||||
)
|
||||
}
|
||||
>
|
||||
<option value="">Por associar</option>
|
||||
{documents.map((doc) => (
|
||||
<option
|
||||
key={doc.document_id}
|
||||
value={doc.document_id}
|
||||
>
|
||||
{doc.file_name} ·{' '}
|
||||
{{
|
||||
quarantined:
|
||||
'Em quarentena',
|
||||
active: 'Disponível',
|
||||
deleted: 'Removido',
|
||||
}[doc.status] ??
|
||||
'Estado por conferir'}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<span>
|
||||
{r.reason}{' '}
|
||||
<a
|
||||
className="underline"
|
||||
href={r.source.url}
|
||||
>
|
||||
{r.source.reference}
|
||||
</a>
|
||||
</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
<p>
|
||||
Compare o impacto para actualizar o enquadramento, as perguntas
|
||||
e as exigências. Uma exigência que deixe de ser aplicável
|
||||
conserva o documento anterior no histórico.
|
||||
</p>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
export function PreparationImpact({
|
||||
before,
|
||||
after,
|
||||
}: {
|
||||
before: Preparation;
|
||||
after: Preparation;
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className="space-y-2 rounded border border-amber-400 p-3"
|
||||
aria-label="Impacto no pedido de investimento"
|
||||
>
|
||||
<h3 className="font-bold">Impacto no pedido e nos documentos</h3>
|
||||
<p>
|
||||
{preparationMode(before.mode)} → {preparationMode(after.mode)}.
|
||||
</p>
|
||||
<p>Próximo passo: {after.next}.</p>
|
||||
<ul className="list-disc pl-5">
|
||||
{after.requirements
|
||||
.filter(
|
||||
(r) =>
|
||||
before.requirements.find((b) => b.key === r.key)
|
||||
?.state !== r.state,
|
||||
)
|
||||
.map((r) => (
|
||||
<li key={r.key}>
|
||||
{r.label}:{' '}
|
||||
{
|
||||
states[
|
||||
before.requirements.find(
|
||||
(b) => b.key === r.key,
|
||||
)?.state ?? 'indeterminate'
|
||||
]
|
||||
}{' '}
|
||||
→ {states[r.state]}.{' '}
|
||||
{r.document_id && 'Vínculo documental preservado.'}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<p>{after.calculation_notice}</p>
|
||||
<PreparationSummary data={after} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user