659 lines
30 KiB
TypeScript
659 lines
30 KiB
TypeScript
import { QualificationFields } from './simulation-irpc-special';
|
|
import { FiscalProofParcelFields } from './fiscal-proof-parcel';
|
|
import {
|
|
prepareInvestmentCredit,
|
|
prepareInvestmentCarry,
|
|
type AnnualBook,
|
|
} from '@/lib/irpc-annual-settlement';
|
|
import {
|
|
investmentCreditSource,
|
|
newInvestmentAsset,
|
|
type InvestmentCredit,
|
|
type InvestmentAsset,
|
|
} from '@/lib/irpc-investment-credit';
|
|
export function SimulationIrpcInvestment({
|
|
draft,
|
|
book,
|
|
save,
|
|
}: {
|
|
draft: Record<string, unknown>;
|
|
book: AnnualBook;
|
|
save: (b: AnnualBook) => void;
|
|
}) {
|
|
const c = book.investmentCredit;
|
|
if (!c)
|
|
return (
|
|
<fieldset className="rounded border p-3">
|
|
<legend>Crédito fiscal por investimento — CBF15</legend>
|
|
<p>
|
|
Prepare o detalhe do investimento efectivo e da qualificação
|
|
do projecto. Substitui neste cálculo o resumo anterior dos
|
|
benefícios, que fica conservado. O recorte cobre
|
|
investimento efectivo de2026 dentro dos cinco exercícios do
|
|
prazo,com colecta integral ou quota residual documental do
|
|
projecto, sem outros benefícios próprios ou transportes
|
|
anteriores.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => save(prepareInvestmentCredit(draft, book))}
|
|
>
|
|
Preparar crédito por investimento
|
|
</button>
|
|
</fieldset>
|
|
);
|
|
const patch = (v: Partial<InvestmentCredit>) =>
|
|
save({ ...book, investmentCredit: { ...c, ...v } });
|
|
const text = (
|
|
key:
|
|
| 'projectReference'
|
|
| 'locationReference'
|
|
| 'startDate'
|
|
| 'startReference'
|
|
| 'recognitionReference'
|
|
| 'noOtherBenefitsReference'
|
|
| 'soleProjectReference',
|
|
label: string,
|
|
) => (
|
|
<label className="block">
|
|
{label}
|
|
<input
|
|
aria-label={'CBF15 — ' + label}
|
|
value={c[key]}
|
|
onChange={(e) => patch({ [key]: e.target.value })}
|
|
/>
|
|
</label>
|
|
);
|
|
const choice = (
|
|
key:
|
|
| 'cbfRequirements'
|
|
| 'genericOnly'
|
|
| 'noOtherBenefits'
|
|
| 'soleProject',
|
|
label: string,
|
|
) => (
|
|
<label className="block">
|
|
{label}
|
|
<select
|
|
aria-label={'CBF15 — ' + label}
|
|
value={c[key]}
|
|
onChange={(e) => patch({ [key]: e.target.value })}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="yes">Sim — documentado</option>
|
|
<option value="no">Não — documentado</option>
|
|
</select>
|
|
</label>
|
|
);
|
|
return (
|
|
<fieldset className="space-y-3 rounded border p-3">
|
|
<legend>Crédito fiscal por investimento — CBF15</legend>
|
|
<p>{investmentCreditSource}</p>
|
|
<p>
|
|
Beneficiário {c.subjectNuit}, exercício {c.year}. Resumo
|
|
anterior conservado:{' '}
|
|
{book.internationalCredits?.benefits.state ||
|
|
'informação em falta'}
|
|
; montante{' '}
|
|
{book.internationalCredits?.benefits.amount || 'não preenchido'}
|
|
. O detalhe aplica apenas o benefício aqui qualificado; não
|
|
volta a deduzir o resumo.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
patch({
|
|
subjectNuit: book.subjectNuit,
|
|
year: book.year,
|
|
assessmentKey: book.assessmentKey,
|
|
})
|
|
}
|
|
>
|
|
Vincular CBF15 à colecta seleccionada
|
|
</button>
|
|
<QualificationFields
|
|
label="CBF15"
|
|
value={c.qualification}
|
|
onChange={(qualification) => patch({ qualification })}
|
|
/>
|
|
{choice(
|
|
'noOtherBenefits',
|
|
'Sem outros benefícios próprios/cumulações neste recorte',
|
|
)}
|
|
{text(
|
|
'noOtherBenefitsReference',
|
|
'Reconciliação dos outros benefícios e tratamentos L6/L7',
|
|
)}
|
|
{c.qualification.state === 'known' && (
|
|
<>
|
|
{text(
|
|
'projectReference',
|
|
'Despacho/termos ou instrumento legal do projecto',
|
|
)}
|
|
{choice(
|
|
'cbfRequirements',
|
|
'Condições CBF3/9 e âmbito do projecto documentados',
|
|
)}
|
|
{choice(
|
|
'genericOnly',
|
|
'Investimento no regime genérico, fora dos benefícios específicos — art.13',
|
|
)}
|
|
<label className="block">
|
|
Reconhecimento — art.10
|
|
<select
|
|
aria-label="CBF15 — Reconhecimento"
|
|
value={c.recognition}
|
|
onChange={(e) =>
|
|
patch({
|
|
recognition: e.target
|
|
.value as InvestmentCredit['recognition'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por corresponder</option>
|
|
<option value="documented">
|
|
Reconhecimento documentado
|
|
</option>
|
|
<option value="not_required">
|
|
Excepção com norma e suporte
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{text(
|
|
'recognitionReference',
|
|
'Suporte do reconhecimento ou norma de excepção',
|
|
)}
|
|
{choice(
|
|
'soleProject',
|
|
'Toda a colecta corrente respeita à actividade do projecto',
|
|
)}
|
|
{c.soleProject === 'yes'
|
|
? text(
|
|
'soleProjectReference',
|
|
'Suporte da correspondência integral da colecta ao projecto',
|
|
)
|
|
: c.soleProject === 'no' && (
|
|
<fieldset className="rounded border p-3">
|
|
<legend>
|
|
Parte da colecta respeitante ao projecto
|
|
</legend>
|
|
<p>
|
|
Indique a colecta residual do projecto
|
|
depois dos créditos
|
|
económicos/internacionais que lhe
|
|
respeitam. Documente a atribuição entre
|
|
actividades; a quota não pode exceder a
|
|
colecta global remanescente. O portal não
|
|
reparte rendimentos, custos ou perdas por
|
|
presunção.
|
|
</p>
|
|
<label className="block">
|
|
Quota residual do projecto — MZN ou n/d
|
|
<input
|
|
aria-label="CBF15 — Quota residual do projecto"
|
|
value={c.projectQuota?.amount ?? ''}
|
|
onChange={(e) =>
|
|
patch({
|
|
projectQuota: {
|
|
amount: e.target.value,
|
|
reference:
|
|
c.projectQuota
|
|
?.reference ?? '',
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Suporte da quota e atribuição dos créditos
|
|
anteriores
|
|
<input
|
|
aria-label="CBF15 — Suporte da quota do projecto"
|
|
value={
|
|
c.projectQuota?.reference ?? ''
|
|
}
|
|
onChange={(e) =>
|
|
patch({
|
|
projectQuota: {
|
|
amount:
|
|
c.projectQuota
|
|
?.amount ?? '',
|
|
reference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
</fieldset>
|
|
)}
|
|
<label className="block">
|
|
Local efectivo do investimento
|
|
<select
|
|
aria-label="CBF15 — Local do investimento"
|
|
value={c.location}
|
|
onChange={(e) =>
|
|
patch({
|
|
location: e.target
|
|
.value as InvestmentCredit['location'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por documentar</option>
|
|
<option value="maputo_city">
|
|
Cidade de Maputo —5%
|
|
</option>
|
|
<option value="other">
|
|
Restantes províncias —10%, incluindo Província
|
|
de Maputo
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{text(
|
|
'locationReference',
|
|
'Suporte da localização do investimento',
|
|
)}
|
|
<label className="block">
|
|
Início do prazo do crédito
|
|
<select
|
|
aria-label="CBF15 — Início"
|
|
value={c.startKind}
|
|
onChange={(e) =>
|
|
patch({
|
|
startKind: e.target
|
|
.value as InvestmentCredit['startKind'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por documentar</option>
|
|
<option value="new">
|
|
Projecto novo — início de exploração
|
|
</option>
|
|
<option value="existing">
|
|
Projecto em funcionamento — início dos
|
|
procedimentos após aprovação
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{text('startDate', 'Data do início aplicável — AAAA-MM-DD')}
|
|
{text(
|
|
'startReference',
|
|
'Suporte do início e contagem dos cinco exercícios',
|
|
)}
|
|
<p>
|
|
Indique investimento efectivamente realizado,
|
|
documentado em MZN, adquirido novo e afecto à exploração
|
|
nacional. Art15(6) exclui edifícios, viaturas ligeiras,
|
|
mobiliário/conforto/decoração, equipamentos sociais,
|
|
tecnologia de ponta e outros bens não directa e
|
|
imprescindivelmente ligados à actividade produtiva. Não
|
|
copiar investimento projectado como realização.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
patch({
|
|
assets: [
|
|
...c.assets,
|
|
newInvestmentAsset(crypto.randomUUID()),
|
|
],
|
|
})
|
|
}
|
|
>
|
|
Acrescentar activo/documento
|
|
</button>
|
|
</>
|
|
)}
|
|
{!c.carryForward ? (
|
|
<button
|
|
type="button"
|
|
onClick={() => save(prepareInvestmentCarry(draft, book))}
|
|
>
|
|
Preparar transporte de crédito de anos anteriores
|
|
</button>
|
|
) : (
|
|
<fieldset className="space-y-2 rounded border p-3">
|
|
<legend>Transporte CBF15 do mesmo projecto</legend>
|
|
<p>
|
|
Declare activos de origem anterior, taxa e qualificação
|
|
históricas. Não copie saldos de simulações como uso
|
|
fiscal. O prazo original de cinco exercícios mantém-se;
|
|
investimentos correntes ficam separados.
|
|
</p>
|
|
<label className="block">
|
|
Correspondência histórica do crédito transportado
|
|
<input
|
|
aria-label="CBF15 transporte — Correspondência"
|
|
value={c.carryForward.reference}
|
|
onChange={(e) =>
|
|
patch({
|
|
carryForward: {
|
|
...c.carryForward!,
|
|
reference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Investimento efectivo de 2026
|
|
<select
|
|
aria-label="CBF15 transporte — Investimento corrente"
|
|
value={c.carryForward.currentState}
|
|
onChange={(e) =>
|
|
patch({
|
|
carryForward: {
|
|
...c.carryForward!,
|
|
currentState: e.target.value as
|
|
| 'known'
|
|
| 'absent'
|
|
| '',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por documentar</option>
|
|
<option value="known">
|
|
Conhecido — activos correntes discriminados
|
|
</option>
|
|
<option value="absent">
|
|
Ausência documentada — apenas origens anteriores
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Suporte do investimento corrente/ausência
|
|
<input
|
|
aria-label="CBF15 transporte — Suporte corrente"
|
|
value={c.carryForward.currentReference}
|
|
onChange={(e) =>
|
|
patch({
|
|
carryForward: {
|
|
...c.carryForward!,
|
|
currentReference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Uso efectivo de todo o crédito reconciliado
|
|
<select
|
|
aria-label="CBF15 transporte — Reconciliação do uso"
|
|
value={c.carryForward.useReconciled}
|
|
onChange={(e) =>
|
|
patch({
|
|
carryForward: {
|
|
...c.carryForward!,
|
|
useReconciled: e.target.value as
|
|
| ''
|
|
| 'yes'
|
|
| 'no',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por documentar</option>
|
|
<option value="yes">
|
|
Sim — inclui as origens anteriores e o crédito
|
|
corrente
|
|
</option>
|
|
<option value="no">Não reconciliado</option>
|
|
</select>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
patch({
|
|
assets: [
|
|
...c.assets,
|
|
{
|
|
...newInvestmentAsset(
|
|
crypto.randomUUID(),
|
|
),
|
|
originYear: '',
|
|
originNuit: '',
|
|
originProject: '',
|
|
originReference: '',
|
|
originRate: '',
|
|
},
|
|
],
|
|
})
|
|
}
|
|
>
|
|
Acrescentar activo de origem anterior
|
|
</button>
|
|
</fieldset>
|
|
)}
|
|
{c.assets.map((r, index) => {
|
|
const change = (v: Partial<InvestmentAsset>) =>
|
|
patch({
|
|
assets: c.assets.map((x) =>
|
|
x.id === r.id ? { ...r, ...v } : x,
|
|
),
|
|
});
|
|
return (
|
|
<fieldset
|
|
key={r.id}
|
|
className="space-y-2 rounded border p-3"
|
|
>
|
|
<legend>Investimento {index + 1}</legend>
|
|
{r.originYear !== undefined && (
|
|
<>
|
|
<p>
|
|
Origem anterior — mantém a data real de
|
|
aquisição e o prazo original do projecto.
|
|
</p>
|
|
{(
|
|
[
|
|
[
|
|
'originYear',
|
|
'Exercício que originou o crédito',
|
|
],
|
|
[
|
|
'originNuit',
|
|
'NUIT do contribuinte de origem',
|
|
],
|
|
[
|
|
'originProject',
|
|
'Referência do projecto de origem',
|
|
],
|
|
[
|
|
'originRate',
|
|
'Taxa original documentada — 5 ou 10',
|
|
],
|
|
[
|
|
'originReference',
|
|
'Suporte da qualificação e crédito de origem,mesmo projecto/local/regime',
|
|
],
|
|
] as const
|
|
).map(([key, label]) => (
|
|
<label key={key} className="block">
|
|
{label}
|
|
<input
|
|
aria-label={
|
|
'CBF15 origem ' +
|
|
(index + 1) +
|
|
' — ' +
|
|
label
|
|
}
|
|
value={r[key] ?? ''}
|
|
onChange={(e) =>
|
|
change({
|
|
[key]: e.target.value,
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
))}
|
|
</>
|
|
)}
|
|
|
|
{(
|
|
[
|
|
['issuer', 'Fornecedor/emitente'],
|
|
['document', 'Factura/documento'],
|
|
[
|
|
'date',
|
|
'Data do investimento efectivo — AAAA-MM-DD',
|
|
],
|
|
[
|
|
'proofAmount',
|
|
'Montante total do documento — MZN',
|
|
],
|
|
[
|
|
'amount',
|
|
'Investimento atribuído a este activo/projecto — MZN',
|
|
],
|
|
['currency', 'Moeda documental (recorte MZN)'],
|
|
[
|
|
'reference',
|
|
'Suporte do activo, valor e realização',
|
|
],
|
|
] as const
|
|
).map(([key, label]) => (
|
|
<label key={key} className="block">
|
|
{label}
|
|
<input
|
|
aria-label={
|
|
'CBF15 activo ' +
|
|
(index + 1) +
|
|
' — ' +
|
|
label
|
|
}
|
|
value={r[key]}
|
|
onChange={(e) =>
|
|
change({ [key]: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
))}
|
|
<FiscalProofParcelFields
|
|
label={'InvestimentoCBF15 ' + (index + 1)}
|
|
value={r}
|
|
change={change}
|
|
/>
|
|
{(
|
|
[
|
|
[
|
|
'realised',
|
|
'Investimento efectivamente realizado',
|
|
],
|
|
[
|
|
'newTangible',
|
|
'Activo imobilizado corpóreo adquirido em estado novo',
|
|
],
|
|
[
|
|
'domesticUse',
|
|
'Afecto à exploração do projecto em território nacional',
|
|
],
|
|
[
|
|
'directProductive',
|
|
'Directa e imprescindivelmente ligado à actividade produtiva',
|
|
],
|
|
[
|
|
'excluded15_6',
|
|
'Abrangido por alguma exclusão15(6) (para deduzir exige Não)',
|
|
],
|
|
] as const
|
|
).map(([key, label]) => (
|
|
<label key={key} className="block">
|
|
{label}
|
|
<select
|
|
aria-label={
|
|
'CBF15 activo ' +
|
|
(index + 1) +
|
|
' — ' +
|
|
label
|
|
}
|
|
value={r[key]}
|
|
onChange={(e) =>
|
|
change({ [key]: e.target.value })
|
|
}
|
|
>
|
|
<option value="">
|
|
Informação em falta
|
|
</option>
|
|
<option value="yes">
|
|
Sim — documentado
|
|
</option>
|
|
<option value="no">
|
|
Não — documentado
|
|
</option>
|
|
</select>
|
|
</label>
|
|
))}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
patch({
|
|
assets: c.assets.filter(
|
|
(x) => x.id !== r.id,
|
|
),
|
|
})
|
|
}
|
|
>
|
|
Retirar activo {index + 1}
|
|
</button>
|
|
</fieldset>
|
|
);
|
|
})}
|
|
<fieldset className="space-y-2 rounded border p-2">
|
|
<legend>Uso anterior efectivo do crédito</legend>
|
|
<select
|
|
aria-label="CBF15 — Uso anterior"
|
|
value={c.previousUse.state}
|
|
onChange={(e) =>
|
|
patch({
|
|
previousUse: {
|
|
...c.previousUse,
|
|
state: e.target
|
|
.value as InvestmentCredit['previousUse']['state'],
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="known">Montante conhecido</option>
|
|
<option value="absent">Ausência documentada</option>
|
|
</select>
|
|
<label className="block">
|
|
Montante anteriormente utilizado em todo o crédito
|
|
discriminado
|
|
<input
|
|
aria-label="CBF15 — Montante de uso anterior"
|
|
value={c.previousUse.amount}
|
|
onChange={(e) =>
|
|
patch({
|
|
previousUse: {
|
|
...c.previousUse,
|
|
amount: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Suporte do uso/ausência
|
|
<input
|
|
aria-label="CBF15 — Suporte do uso anterior"
|
|
value={c.previousUse.reference}
|
|
onChange={(e) =>
|
|
patch({
|
|
previousUse: {
|
|
...c.previousUse,
|
|
reference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
</fieldset>
|
|
<p>
|
|
Calcule e guarde pelo percurso L8 existente. O crédito não
|
|
utilizado fica discriminado; transporte para outros exercícios e
|
|
formalidades oficiais conservam percurso próprio.
|
|
</p>
|
|
</fieldset>
|
|
);
|
|
}
|