1149 lines
57 KiB
TypeScript
1149 lines
57 KiB
TypeScript
import { inputText } from '../lib/input-text.ts';
|
|
import {
|
|
newSpecialCombinations,
|
|
specialCombinationsSource,
|
|
} from '@/lib/irpc-special-combinations';
|
|
import type { NormalBook } from '@/lib/irpc-normal';
|
|
import {
|
|
newSpecialInput,
|
|
newSpecialExpense,
|
|
newAcceleratedAsset,
|
|
specialAccelerationSource,
|
|
specialCessationPriorSource,
|
|
specialStartPeriodSource,
|
|
specialMonthlySource,
|
|
specialSources,
|
|
type SpecialInput,
|
|
type Qualification,
|
|
} from '@/lib/irpc-special';
|
|
|
|
type Props = {
|
|
draft: Record<string, unknown>;
|
|
book: NormalBook;
|
|
save: (b: NormalBook) => void;
|
|
};
|
|
const states = [
|
|
['', 'Informação em falta'],
|
|
['known', 'Tratamento conhecido — qualificar condições'],
|
|
['absent', 'Ausência declarada com suporte'],
|
|
['not_applicable', 'Tratamento não aplicável — justificar'],
|
|
] as const;
|
|
export function QualificationFields({
|
|
label,
|
|
value,
|
|
onChange,
|
|
}: {
|
|
label: string;
|
|
value: Qualification;
|
|
onChange: (v: Qualification) => void;
|
|
}) {
|
|
const field = (
|
|
key: 'from' | 'to' | 'reference' | 'periodReference',
|
|
text: string,
|
|
) => (
|
|
<label className="block">
|
|
{text}
|
|
<input
|
|
aria-label={label + ' — ' + text}
|
|
value={value[key]}
|
|
onChange={(e) => onChange({ ...value, [key]: e.target.value })}
|
|
/>
|
|
</label>
|
|
);
|
|
return (
|
|
<div className="space-y-2">
|
|
<label className="block">
|
|
Estado — {label}
|
|
<select
|
|
aria-label={'Estado — ' + label}
|
|
value={value.state}
|
|
onChange={(e) =>
|
|
onChange({
|
|
...value,
|
|
state: e.target.value as Qualification['state'],
|
|
eligible: '',
|
|
})
|
|
}
|
|
>
|
|
{states.map(([v, t]) => (
|
|
<option key={v} value={v}>
|
|
{t}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
{value.state === 'known' && (
|
|
<label className="block">
|
|
Condições — {label}
|
|
<select
|
|
aria-label={'Condições — ' + label}
|
|
value={value.eligible}
|
|
onChange={(e) =>
|
|
onChange({
|
|
...value,
|
|
eligible: e.target
|
|
.value as Qualification['eligible'],
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por esclarecer</option>
|
|
<option value="yes">
|
|
Sim — condições documentadas
|
|
</option>
|
|
<option value="no">
|
|
Não — condição negativa documentada
|
|
</option>
|
|
</select>
|
|
</label>
|
|
)}
|
|
{field(
|
|
'reference',
|
|
'Prova das condições, ausência ou não aplicação',
|
|
)}
|
|
{field('from', 'Período — início (AAAA-MM-DD)')}
|
|
{field('to', 'Período — termo (AAAA-MM-DD)')}
|
|
{field(
|
|
'periodReference',
|
|
'Suporte do período e da vigência aplicável',
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
export function SimulationIrpcSpecial({ draft, book: b, save }: Props) {
|
|
const i = b.special;
|
|
const start = () => {
|
|
const next = newSpecialInput(),
|
|
p = b.periodsFx ?? b.schedules?.period;
|
|
for (const part of [next.expenses, next.cooperative, next.acceleration])
|
|
Object.assign(part.qualification, {
|
|
from: p?.from ?? b.year + '-01-01',
|
|
to: p?.to ?? b.year + '-12-31',
|
|
});
|
|
save({ ...b, special: next });
|
|
};
|
|
if (!i)
|
|
return (
|
|
<section className="rounded border p-3">
|
|
<h5>L7 — benefícios e casos especiais</h5>
|
|
<p>
|
|
Preparação opcional e separada do percursoL6 já entregue.
|
|
Localização e sector não activam benefícios. A liquidação
|
|
final permanece emL8.
|
|
</p>
|
|
<button type="button" onClick={start}>
|
|
Preparar qualificação L7
|
|
</button>
|
|
</section>
|
|
);
|
|
const change = (patch: Partial<SpecialInput>) =>
|
|
save({ ...b, special: { ...i, ...patch } });
|
|
const yesno = (
|
|
label: string,
|
|
value: string,
|
|
onChange: (v: '' | 'yes' | 'no') => void,
|
|
) => (
|
|
<label className="block">
|
|
{label}
|
|
<select
|
|
aria-label={label}
|
|
value={value}
|
|
onChange={(e) => onChange(e.target.value as '' | 'yes' | 'no')}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="yes">Sim — documentado</option>
|
|
<option value="no">Não — documentado</option>
|
|
</select>
|
|
</label>
|
|
);
|
|
return (
|
|
<section
|
|
aria-label="L7 — qualificação e tratamentos"
|
|
className="space-y-3 rounded border p-3"
|
|
>
|
|
<h5>L7 — qualificação comum e tratamentos documentados</h5>
|
|
<p>
|
|
Reutiliza sujeito, NUIT, período, despesas e activos L6.
|
|
Contexto herdado:sector{' '}
|
|
{inputText(draft.sector_id ?? 'por identificar')};província{' '}
|
|
{inputText(draft.province_id ?? 'por identificar')}. A
|
|
localização, por si só, não concede benefícios. Os valores L6
|
|
continuam como referência;os efeitosL7 são apresentados
|
|
separadamente. Saldo final a pagar/recuperar:âmbitoL8.
|
|
</p>
|
|
{!i.combinations ? (
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({ combinations: newSpecialCombinations() })
|
|
}
|
|
>
|
|
Preparar cumulações dos tratamentos L7 registados
|
|
</button>
|
|
) : (
|
|
<fieldset
|
|
aria-label="Cumulações L7"
|
|
className="space-y-2 rounded border p-3"
|
|
>
|
|
<legend>
|
|
Cumulações — tratamentos, incompatibilidades e limites
|
|
</legend>
|
|
<p>
|
|
{specialCombinationsSource} Reutiliza a cooperativa,os
|
|
activos,as despesas e os períodos já declarados abaixo.
|
|
Esta preparação discrimina os benefícios em vez da
|
|
confirmação global de ausência de outros
|
|
benefícios;conserva os valores anteriores e não altera
|
|
automaticamente qualificações ou activos.
|
|
</p>
|
|
<label className="block">
|
|
Suporte da combinação no sujeito/projecto/período
|
|
<input
|
|
aria-label="Suporte da combinação L7"
|
|
value={i.combinations.reference}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
reference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Benefícios específicosCBF
|
|
<select
|
|
aria-label="Benefícios específicos CBF na combinação"
|
|
value={i.combinations.specificState}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
specificState: e.target.value as
|
|
| ''
|
|
| 'absent'
|
|
| 'known',
|
|
specificException: '',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="absent">
|
|
Ausência declarada com suporte
|
|
</option>
|
|
<option value="known">
|
|
Existem — identificar artigo e âmbito
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Suporte da presença ou ausência de benefícios
|
|
específicos
|
|
<input
|
|
aria-label="Suporte dos benefícios específicos CBF"
|
|
value={i.combinations.specificReference}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
specificReference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
{i.combinations.specificState === 'known' && (
|
|
<label className="block">
|
|
Excepção expressa à não cumulação
|
|
<select
|
|
aria-label="Excepção de cumulação CBF"
|
|
value={i.combinations.specificException}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
specificException: e.target
|
|
.value as
|
|
| ''
|
|
| 'absent'
|
|
| 'claimed',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="absent">
|
|
Ausência documentada — combinação
|
|
incompatível
|
|
</option>
|
|
<option value="claimed">
|
|
Excepção invocada — correspondência própria
|
|
em falta
|
|
</option>
|
|
</select>
|
|
</label>
|
|
)}
|
|
<label className="block">
|
|
Outros benefícios além dos tratamentos registados
|
|
<select
|
|
aria-label="Outros benefícios na combinação L7"
|
|
value={i.combinations.otherState}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
otherState: e.target.value as
|
|
| ''
|
|
| 'absent'
|
|
| 'known',
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="absent">
|
|
Ausência declarada com suporte
|
|
</option>
|
|
<option value="known">
|
|
Existem — tratamento próprio por corresponder
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Suporte dos outros benefícios ou ausência
|
|
<input
|
|
aria-label="Suporte dos outros benefícios L7"
|
|
value={i.combinations.otherReference}
|
|
onChange={(e) =>
|
|
change({
|
|
combinations: {
|
|
...i.combinations!,
|
|
otherReference: e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<p>
|
|
Não somar de novo a amortização contabilística ou a
|
|
parcela anterior recuperada. A redução cooperativa
|
|
afecta só a colecta sobre a base elegível;o imposto
|
|
autónomo continua separado. Uma incompatibilidade não
|
|
escolhe o benefício a conservar nem apaga o declarado.
|
|
Outros benefícios/excepções sem regra correspondida
|
|
mantêm o totalL7 indeterminado.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const next = { ...i };
|
|
delete next.combinations;
|
|
save({ ...b, special: next });
|
|
}}
|
|
>
|
|
Manter tratamentos sem preparar cumulação
|
|
</button>
|
|
</fieldset>
|
|
)}
|
|
<fieldset className="space-y-2 rounded border p-3">
|
|
<legend>Despesas — tributação autónoma61(4)</legend>
|
|
<p>{specialSources.expenses}</p>
|
|
<QualificationFields
|
|
label="Despesas autónomas"
|
|
value={i.expenses.qualification}
|
|
onChange={(qualification) =>
|
|
change({ expenses: { ...i.expenses, qualification } })
|
|
}
|
|
/>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
expenses: {
|
|
...i.expenses,
|
|
rows: [
|
|
...i.expenses.rows,
|
|
...(b.schedules?.rows ?? [])
|
|
.filter(
|
|
(r) =>
|
|
r.rule === 'undocumented' &&
|
|
!i.expenses.rows.some(
|
|
(x) =>
|
|
x.scheduleId === r.id,
|
|
),
|
|
)
|
|
.map((r) => ({
|
|
...newSpecialExpense(
|
|
'expense-' + r.id,
|
|
),
|
|
scheduleId: r.id,
|
|
})),
|
|
],
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Reutilizar despesas36g de L6 para qualificar
|
|
</button>
|
|
{i.expenses.rows.map((r, index) => {
|
|
const origin = b.schedules?.rows.find(
|
|
(x) => x.id === r.scheduleId,
|
|
),
|
|
patch = (p: Partial<typeof r>) =>
|
|
change({
|
|
expenses: {
|
|
...i.expenses,
|
|
rows: i.expenses.rows.map((x) =>
|
|
x.id === r.id ? { ...x, ...p } : x,
|
|
),
|
|
},
|
|
});
|
|
return (
|
|
<fieldset key={r.id} className="rounded border p-2">
|
|
<legend>
|
|
{origin
|
|
? origin.document + '/' + origin.line
|
|
: 'Parcela por corresponder'}{' '}
|
|
— {origin?.amount ?? 'Indeterminado'} MZN
|
|
</legend>
|
|
<p>
|
|
O acréscimo36g já pertence aL6;esta linha só
|
|
apura o eventual imposto autónomo.
|
|
</p>
|
|
<label className="block">
|
|
Natureza legal da despesa
|
|
<select
|
|
aria-label={
|
|
'Natureza da despesa ' + (index + 1)
|
|
}
|
|
value={r.nature}
|
|
onChange={(e) =>
|
|
patch({
|
|
nature: e.target
|
|
.value as typeof r.nature,
|
|
})
|
|
}
|
|
>
|
|
<option value="">
|
|
Informação em falta
|
|
</option>
|
|
<option value="undocumented">
|
|
Encargo não devidamente documentado
|
|
</option>
|
|
<option value="confidential">
|
|
Despesa confidencial
|
|
</option>
|
|
<option value="illicit">
|
|
Despesa ilícita
|
|
</option>
|
|
<option value="other">
|
|
Outra natureza — correspondência própria
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{yesno(
|
|
'Incidência61(4) — parcela ' + (index + 1),
|
|
r.eligible,
|
|
(eligible) => patch({ eligible }),
|
|
)}
|
|
<label className="block">
|
|
Suporte da classificação e incidência
|
|
<input
|
|
aria-label={
|
|
'Suporte da despesa ' + (index + 1)
|
|
}
|
|
value={r.reference}
|
|
onChange={(e) =>
|
|
patch({ reference: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
expenses: {
|
|
...i.expenses,
|
|
rows: i.expenses.rows.filter(
|
|
(x) => x.id !== r.id,
|
|
),
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Retirar qualificação da parcela {index + 1}
|
|
</button>
|
|
</fieldset>
|
|
);
|
|
})}
|
|
</fieldset>
|
|
<fieldset className="space-y-2 rounded border p-3">
|
|
<legend>Cooperativas abrangidas — artigo12</legend>
|
|
<p>
|
|
{specialSources.cooperative} Este incremento exige base
|
|
integralmente elegível;parcelas mistas continuam explícitas.
|
|
</p>
|
|
<QualificationFields
|
|
label="Cooperativa"
|
|
value={i.cooperative.qualification}
|
|
onChange={(qualification) =>
|
|
change({
|
|
cooperative: { ...i.cooperative, qualification },
|
|
})
|
|
}
|
|
/>
|
|
{(i.cooperative.qualification.state === 'known' ||
|
|
i.cooperative.kind !== '' ||
|
|
i.cooperative.allIncomeEligible !== '' ||
|
|
i.cooperative.withheldIncome !== '') && (
|
|
<>
|
|
<label className="block">
|
|
Tipo de cooperativa documentado
|
|
<select
|
|
value={i.cooperative.kind}
|
|
onChange={(e) =>
|
|
change({
|
|
cooperative: {
|
|
...i.cooperative,
|
|
kind: e.target
|
|
.value as typeof i.cooperative.kind,
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por identificar</option>
|
|
<option value="agrarian">Agrária</option>
|
|
<option value="craft">Artesanato</option>
|
|
<option value="cultural">Cultural</option>
|
|
<option value="other">
|
|
Outra — não correspondida
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{yesno(
|
|
'Base ordinária integralmente elegível',
|
|
i.cooperative.allIncomeEligible,
|
|
(allIncomeEligible) =>
|
|
change({
|
|
cooperative: {
|
|
...i.cooperative,
|
|
allIncomeEligible,
|
|
},
|
|
}),
|
|
)}
|
|
<label className="block">
|
|
Rendimentos sujeitos a retenção
|
|
<select
|
|
value={i.cooperative.withheldIncome}
|
|
onChange={(e) =>
|
|
change({
|
|
cooperative: {
|
|
...i.cooperative,
|
|
withheldIncome: e.target
|
|
.value as typeof i.cooperative.withheldIncome,
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="absent">
|
|
Ausência documentada
|
|
</option>
|
|
<option value="known">
|
|
Existem — segregação própria em falta
|
|
</option>
|
|
</select>
|
|
</label>
|
|
</>
|
|
)}
|
|
</fieldset>
|
|
<fieldset className="space-y-2 rounded border p-3">
|
|
<legend>Amortizações aceleradas — CBF16</legend>
|
|
<p>
|
|
{i.combinations
|
|
? specialAccelerationSource(i)
|
|
: i.acceleration.monthly?.continuation
|
|
? specialCessationPriorSource
|
|
: i.acceleration.monthly?.startPeriod
|
|
? specialStartPeriodSource
|
|
: specialSources.acceleration}{' '}
|
|
Apenas activos já suportados e método constante;prepare
|
|
explicitamente o recorte anual ou de início de actividade.
|
|
</p>
|
|
<QualificationFields
|
|
label="Amortização acelerada"
|
|
value={i.acceleration.qualification}
|
|
onChange={(qualification) =>
|
|
change({
|
|
acceleration: { ...i.acceleration, qualification },
|
|
})
|
|
}
|
|
/>
|
|
{i.acceleration.qualification.state === 'known' && (
|
|
<>
|
|
{yesno(
|
|
'EnquadramentoCBF3 e pressupostos9 documentados',
|
|
i.acceleration.cbfRequirements,
|
|
(cbfRequirements) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
cbfRequirements,
|
|
},
|
|
}),
|
|
)}
|
|
<label className="block">
|
|
ReconhecimentoCBF10
|
|
<select
|
|
value={i.acceleration.recognition}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
recognition: e.target
|
|
.value as typeof i.acceleration.recognition,
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">Informação em falta</option>
|
|
<option value="documented">
|
|
Instrumento/reconhecimento documentado
|
|
</option>
|
|
<option value="not_required">
|
|
Excepção prevista — identificar norma e
|
|
suporte
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Instrumento ou norma da excepção
|
|
<input
|
|
value={i.acceleration.recognitionReference}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
recognitionReference:
|
|
e.target.value,
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
{!i.combinations &&
|
|
yesno(
|
|
'Ausência documentada de outros benefícios a cumular',
|
|
i.acceleration.noOtherBenefits,
|
|
(noOtherBenefits) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
noOtherBenefits,
|
|
},
|
|
}),
|
|
)}
|
|
</>
|
|
)}
|
|
{!i.acceleration.monthly ? (
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: { version: 1, reference: '' },
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Preparar CBF16 com duodécimos
|
|
</button>
|
|
) : (
|
|
<fieldset
|
|
aria-label="CBF16 por duodécimos"
|
|
className="space-y-2 rounded border p-2"
|
|
>
|
|
<legend>CBF16 — reutilizar duodécimos L6</legend>
|
|
<p>
|
|
{i.combinations
|
|
? specialAccelerationSource(i)
|
|
: i.acceleration.monthly.continuation
|
|
? specialCessationPriorSource
|
|
: i.acceleration.monthly.startPeriod
|
|
? specialStartPeriodSource
|
|
: specialMonthlySource}{' '}
|
|
Conserva datas,opção mensal e valores do activo
|
|
existente;preencha no mapaL6 apenas o que falta ou
|
|
precisa de correcção.
|
|
</p>
|
|
<label className="block">
|
|
Suporte da reutilização dos duodécimos L6
|
|
<input
|
|
aria-label="Suporte dos duodécimos CBF16"
|
|
value={i.acceleration.monthly.reference}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration.monthly!,
|
|
reference: e.target.value,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
{!i.acceleration.monthly.continuation &&
|
|
(!i.acceleration.monthly.startPeriod ? (
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration.monthly!,
|
|
startPeriod: {
|
|
version: 1,
|
|
reference: '',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Preparar CBF16 para início de actividade
|
|
</button>
|
|
) : (
|
|
<fieldset
|
|
aria-label="CBF16 no início de actividade"
|
|
className="rounded border p-2"
|
|
>
|
|
<legend>
|
|
CBF16 — período curto de início de
|
|
actividade
|
|
</legend>
|
|
<p>
|
|
Período L6:
|
|
{b.periodsFx?.from ||
|
|
'Por identificar'}{' '}
|
|
a {b.periodsFx?.to || 'Por identificar'}
|
|
;tipo:
|
|
{b.periodsFx?.kind || 'Por identificar'}
|
|
. Reutiliza o período declarado;esta
|
|
opção não altera datas,activos ou
|
|
enquadramento.
|
|
</p>
|
|
<label className="block">
|
|
Suporte do início de actividade
|
|
<input
|
|
aria-label="Suporte do início de actividade CBF16"
|
|
value={
|
|
i.acceleration.monthly
|
|
.startPeriod.reference
|
|
}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
startPeriod: {
|
|
version: 1,
|
|
reference:
|
|
e.target
|
|
.value,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
disabled={
|
|
b.periodsFx?.kind !== 'start' ||
|
|
!b.periodsFx.reference.trim()
|
|
}
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
startPeriod: {
|
|
version: 1,
|
|
reference:
|
|
b.periodsFx!
|
|
.reference,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Reutilizar suporte do início de
|
|
actividade L6
|
|
</button>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const monthly = {
|
|
...i.acceleration.monthly!,
|
|
};
|
|
delete monthly.startPeriod;
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly,
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
Manter duodécimos no exercício anual
|
|
</button>
|
|
</fieldset>
|
|
))}
|
|
{!i.acceleration.monthly.startPeriod &&
|
|
(!i.acceleration.monthly.continuation ? (
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration.monthly!,
|
|
continuation: {
|
|
version: 1,
|
|
period: '',
|
|
reference: '',
|
|
historyReference: '',
|
|
monthlyFromStart: '',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Preparar CBF16 para cessação e quotas
|
|
anteriores
|
|
</button>
|
|
) : (
|
|
<fieldset
|
|
aria-label="CBF16 cessação e quotas anteriores"
|
|
className="rounded border p-2"
|
|
>
|
|
<legend>
|
|
CBF16 — cessação e quotas anteriores
|
|
</legend>
|
|
<p>
|
|
{specialCessationPriorSource} Reutiliza
|
|
o mapaL6;nenhum saldo declarado ou
|
|
histórico é alterado. PeríodoL6:
|
|
{b.periodsFx?.from ||
|
|
b.year + '-01-01'}{' '}
|
|
a {b.periodsFx?.to || b.year + '-12-31'}
|
|
;tipo:{b.periodsFx?.kind || 'anual'}.
|
|
Corrija dados de origem nos mapasL6
|
|
quando necessário.
|
|
</p>
|
|
<label className="block">
|
|
Período a qualificar
|
|
<select
|
|
aria-label="Período CBF16 cessação e quotas anteriores"
|
|
value={
|
|
i.acceleration.monthly
|
|
.continuation.period
|
|
}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
continuation: {
|
|
...i
|
|
.acceleration
|
|
.monthly!
|
|
.continuation!,
|
|
period: e.target
|
|
.value as
|
|
| 'annual'
|
|
| 'cessation'
|
|
| '',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
>
|
|
<option value="">
|
|
Informação em falta
|
|
</option>
|
|
<option value="annual">
|
|
Ano civil2026 — activo e quotas
|
|
anteriores
|
|
</option>
|
|
<option value="cessation">
|
|
Cessação da actividade em2026 —
|
|
período curtoL6
|
|
</option>
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Suporte do período e condiçõesCBF16
|
|
<input
|
|
aria-label="Suporte CBF16 cessação"
|
|
value={
|
|
i.acceleration.monthly
|
|
.continuation.reference
|
|
}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
continuation: {
|
|
...i
|
|
.acceleration
|
|
.monthly!
|
|
.continuation!,
|
|
reference:
|
|
e.target
|
|
.value,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
<label className="block">
|
|
Suporte das quotas anteriores ou
|
|
ausência e da aplicaçãoCBF16
|
|
<input
|
|
aria-label="Suporte das quotas anteriores CBF16"
|
|
value={
|
|
i.acceleration.monthly
|
|
.continuation
|
|
.historyReference
|
|
}
|
|
onChange={(e) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
continuation: {
|
|
...i
|
|
.acceleration
|
|
.monthly!
|
|
.continuation!,
|
|
historyReference:
|
|
e.target
|
|
.value,
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</label>
|
|
{yesno(
|
|
'Duodécimos desde a entrada emuso documentados',
|
|
i.acceleration.monthly.continuation
|
|
.monthlyFromStart,
|
|
(monthlyFromStart) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly: {
|
|
...i.acceleration
|
|
.monthly!,
|
|
continuation: {
|
|
...i.acceleration
|
|
.monthly!
|
|
.continuation!,
|
|
monthlyFromStart,
|
|
},
|
|
},
|
|
},
|
|
}),
|
|
)}
|
|
<p>
|
|
Cessação da actividade e saída do activo
|
|
são eventos distintos. Só a saída
|
|
documentada emL6 exclui o mês do evento.
|
|
A recuperação de quotas anteriores é
|
|
aritmética para esta simulação;saldo
|
|
oficial não é consumido.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const monthly = {
|
|
...i.acceleration.monthly!,
|
|
};
|
|
delete monthly.continuation;
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
monthly,
|
|
},
|
|
});
|
|
}}
|
|
>
|
|
Manter recorte anual sem quotas
|
|
anteriores
|
|
</button>
|
|
</fieldset>
|
|
))}
|
|
<p>
|
|
Não altera automaticamente o activo nem transforma
|
|
ausência de documentos em elegibilidade. A versão
|
|
anterior permanece no histórico depois de calcular e
|
|
guardar.
|
|
</p>
|
|
<button
|
|
type="button"
|
|
onClick={() => {
|
|
const acceleration = { ...i.acceleration };
|
|
delete acceleration.monthly;
|
|
change({ acceleration });
|
|
}}
|
|
>
|
|
Manter preparação anual CBF16
|
|
</button>
|
|
</fieldset>
|
|
)}
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
rows: [
|
|
...i.acceleration.rows,
|
|
newAcceleratedAsset(crypto.randomUUID()),
|
|
],
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Qualificar activo existente paraCBF16
|
|
</button>
|
|
{i.acceleration.rows.map((r, index) => {
|
|
const patch = (p: Partial<typeof r>) =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
rows: i.acceleration.rows.map((x) =>
|
|
x.id === r.id ? { ...x, ...p } : x,
|
|
),
|
|
},
|
|
});
|
|
return (
|
|
<fieldset key={r.id} className="rounded border p-2">
|
|
<legend>Activo qualificado {index + 1}</legend>
|
|
<label className="block">
|
|
Activo do mapaL6
|
|
<select
|
|
value={r.assetId}
|
|
onChange={(e) =>
|
|
patch({ assetId: e.target.value })
|
|
}
|
|
>
|
|
<option value="">
|
|
Seleccione activo existente
|
|
</option>
|
|
{b.depreciation?.assets.map((a) => (
|
|
<option key={a.id} value={a.id}>
|
|
{a.description} — {a.assetKey}
|
|
</option>
|
|
))}
|
|
</select>
|
|
</label>
|
|
<label className="block">
|
|
Afectação documentada
|
|
<select
|
|
value={r.kind}
|
|
onChange={(e) =>
|
|
patch({
|
|
kind: e.target
|
|
.value as typeof r.kind,
|
|
})
|
|
}
|
|
>
|
|
<option value="">Por identificar</option>
|
|
<option value="new_project_building">
|
|
Imóvel novo utilizado no projecto
|
|
</option>
|
|
<option value="rehabilitated_project_building">
|
|
Imóvel reabilitado — regra ainda por
|
|
corresponder
|
|
</option>
|
|
<option value="industrial_equipment">
|
|
Máquina/equipamento industrial
|
|
</option>
|
|
<option value="agroindustrial_equipment">
|
|
Máquina/equipamento agro-industrial
|
|
</option>
|
|
<option value="other">
|
|
Outro — correspondência própria
|
|
</option>
|
|
</select>
|
|
</label>
|
|
{yesno(
|
|
'Condições do activoCBF16 — ' + (index + 1),
|
|
r.eligible,
|
|
(eligible) => patch({ eligible }),
|
|
)}
|
|
<label className="block">
|
|
Prova da afectação e condições do activo
|
|
<input
|
|
value={r.reference}
|
|
onChange={(e) =>
|
|
patch({ reference: e.target.value })
|
|
}
|
|
/>
|
|
</label>
|
|
<button
|
|
type="button"
|
|
onClick={() =>
|
|
change({
|
|
acceleration: {
|
|
...i.acceleration,
|
|
rows: i.acceleration.rows.filter(
|
|
(x) => x.id !== r.id,
|
|
),
|
|
},
|
|
})
|
|
}
|
|
>
|
|
Retirar tratamento do activo {index + 1}
|
|
</button>
|
|
</fieldset>
|
|
);
|
|
})}
|
|
</fieldset>
|
|
<p>
|
|
Use «Calcular e guardar» abaixo para gravar uma nova versão e
|
|
apresentar os efeitos. Os históricos anteriores são conservados.
|
|
M20/M22 mantém apenas correspondências demonstradas;camposL7 não
|
|
são preenchidos por aproximação.
|
|
</p>
|
|
</section>
|
|
);
|
|
}
|