25 lines
6.0 KiB
TypeScript
25 lines
6.0 KiB
TypeScript
import {ispcEligibilityBook,ispcEligibilityCurrent} from './ispc-eligibility.ts';
|
||
import {acquisitionScope} from './iva-acquisitions.ts';
|
||
import {addFractions,decimalFraction,fraction,fractionPresentation,type FiscalFraction} from './fiscal-rational.ts';
|
||
export type IspcWithholdingInput={applicable:''|'no'|'yes';quarter:string;base:string;priorAnnualPurchases:string;naturalOccasional:''|'yes'|'no';unregistered:''|'yes'|'no';related:''|'yes'|'no';activity:''|'forestry'|'fishery'|'livestock'|'agriculture'|'poultry'|'beekeeping'|'other';reference:string;};
|
||
export type IspcWithholdingResult={input:IspcWithholdingInput;key:string;status:'calculated'|'indeterminate'|'not_applicable';reason:string;withheld:FiscalFraction|null;calculatedAt:string;source:string};
|
||
export type IspcWithholdingBook={version:1;input:IspcWithholdingInput;result?:IspcWithholdingResult;history?:IspcWithholdingResult[]};
|
||
export const ispcWithholdingSource='Lei9/2025,republicaçãoISPC,arts3(3–4),12(3–4);PDF10–11/p2180(10–11). Retenção liberatória5% sobre aquisição a pessoa singular ocasional não inscrita, ligada à actividade, até limite global anual2.500.000MZN; factura por conta do fornecedor e entrega trimestral em modelo próprio. Não é crédito contra o imposto próprio nem se aplica o mínimo500 desta prestação à retenção.';
|
||
const blank=():IspcWithholdingInput=>({applicable:'',quarter:'1',base:'',priorAnnualPurchases:'',naturalOccasional:'',unregistered:'',related:'',activity:'',reference:''});
|
||
function snapshot(d:Record<string,unknown>){const s=JSON.parse(String(d.modelo_a_snapshot||'{"version":1,"books":{}}'));if(s.version!==1||!s.books||typeof s.books!=='object'||Array.isArray(s.books))throw Error('Livros não recuperáveis; originais preservados.');return s;}
|
||
function validate(b:IspcWithholdingBook){if(!b||b.version!==1||!b.input||Object.keys(blank()).some(k=>typeof b.input[k as keyof IspcWithholdingInput]!=='string')||['applicable','naturalOccasional','unregistered','related'].some(k=>!['','yes','no'].includes(b.input[k as keyof IspcWithholdingInput]))||!['','forestry','fishery','livestock','agriculture','poultry','beekeeping','other'].includes(b.input.activity)||b.history!==undefined&&!Array.isArray(b.history))throw Error('RetençõesISPC não recuperáveis; originais preservados.');}
|
||
function map(d:Record<string,unknown>):Record<string,IspcWithholdingBook>{const v=snapshot(d).ispcWithholdings;if(v===undefined)return{};if(!v||typeof v!=='object'||Array.isArray(v))throw Error('Mapa de retençõesISPC inválido.');return v;}
|
||
export function ispcWithholdingBook(d:Record<string,unknown>):IspcWithholdingBook{const b=map(d)[acquisitionScope(d)]??{version:1,input:blank()};validate(b);return b;}
|
||
export function saveIspcWithholdingBook(d:Record<string,unknown>,b:IspcWithholdingBook):string{validate(b);return JSON.stringify({...snapshot(d),ispcWithholdings:{...map(d),[acquisitionScope(d)]:b}});}
|
||
export function recordIspcWithholding(d:Record<string,unknown>,b:IspcWithholdingBook,now=new Date().toISOString()):IspcWithholdingBook{validate(b);const i=b.input,e=ispcEligibilityBook(d),r:IspcWithholdingResult={input:structuredClone(i),key:JSON.stringify([acquisitionScope(d),i]),status:'indeterminate',reason:'Identifique se existem aquisições abrangidas; não presumir retenção zero.',withheld:null,calculatedAt:now,source:ispcWithholdingSource};
|
||
if(i.applicable==='no'){r.status='not_applicable';r.reason='Sem aquisições abrangidas, segundo declaração expressa; entradas anteriores preservadas.';}
|
||
else if(i.applicable==='yes'&&(!ispcEligibilityCurrent(d,e)||e.result?.status!=='compatible'||e.result.optionStatus==='not_opted'||e.result.optionStatus==='indeterminate'||e.input.origin==='effective'&&e.result.optionStatus!=='recorded')){r.reason='Guarde o enquadramento e a opção aplicáveis do adquirenteISPC antes de calcular retenção efectiva; sem inferir adesão.';}
|
||
else if(i.applicable==='yes'){
|
||
if(i.naturalOccasional==='no'||i.unregistered==='no'||i.related==='no'||i.activity==='other'){r.status='not_applicable';r.reason='Aquisição fora do recorte12(3–4) declarado; outros regimes de retenção mantêm análise própria,sem presumir isenção.';}
|
||
else if(i.naturalOccasional==='yes'&&i.unregistered==='yes'&&i.related==='yes'&&i.activity&&i.reference.trim()&&['1','2','3','4'].includes(i.quarter)){
|
||
try{const base=decimalFraction(i.base),prior=decimalFraction(i.priorAnnualPurchases),total=addFractions([base,prior]);if(BigInt(total.numerator)>2500000n*BigInt(total.denominator))r.reason='Total global anual superior2.500.000MZN: tratamento da aquisição acima do limite por corresponder; não reter automaticamente5% nem truncar a base.';else{r.status='calculated';r.withheld=fraction(BigInt(base.numerator)*5n,BigInt(base.denominator)*100n);r.reason='Retenção5% calculada separadamente do imposto próprio; emitir factura por conta do fornecedor e preparar entrega trimestral em modelo próprio. Sem deduzir esta retenção da prestaçãoISPC.';}}catch{r.reason='Base e aquisições globais anteriores do ano necessários,incluindo zero expresso; não presumir montantes.';}
|
||
}else r.reason='Identifique pessoa singular ocasional3(3–4),actividade abrangida,não inscrição,ligação à actividade,trimestre e suporte; dados desconhecidos não viram não aplicáveis.';
|
||
}
|
||
return{...b,...(b.result?{history:[...(b.history??[]),structuredClone(b.result)]}:{}),result:r};}
|
||
export function ispcWithholdingReportRows(d:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=ispcWithholdingBook(d),r=b.result;if(!r)return[];return[['ISPC','Retenção em aquisições ocasionais',`${r.status}; ${r.withheld?fractionPresentation(r.withheld).decimal+' MZN':'Indeterminado/não aplicado'}; ${r.reason}`,`2026/T${r.input.quarter}; base:${r.input.base}; anteriores globais:${r.input.priorAnnualPurchases}; suporte:${r.input.reference}; ${r.key===JSON.stringify([acquisitionScope(d),b.input])?'Entradas correspondentes':'Histórico preservado;rever entradas'}; ${r.calculatedAt}; ${r.source}`]];}catch(e){return[['ISPC','Retenção não recuperável',String(e),'Originais preservados.']];}}
|