Files
Investidor-V2/resources/js/lib/iva-objective-imports.ts
T

43 lines
9.6 KiB
TypeScript

import {acquisitionScope,readAcquisitionStore} from './iva-acquisitions.ts';
import {operationTreatments,newSalesOperation,evaluateSalesOperation,salesBook,type SalesOperation} from './iva-operations.ts';
export const objectiveImportVersion='objective-imports/1';
export const objectiveImportSource='CIVA12(1)a,Lei10/2025,BR248-I/suplemento,PDF12/p2180(12),efeitos01/01/2026:importações definitivas de bens cuja transmissão interna beneficie de isenção objectiva;enumeração exemplificativa. Correspondências9(1)b/c/e/f/g,9(9)b,9(10),9(11),9(12)g/h/i;catálogo interno e anexosLei22/2022 já conferidos. Sem dedução/campo11,direitos ou alteração dos livros internos.';
const fixed=['health_assistive','human_materials','mosquito_nets','medicines','pharma_manufacturing_inputs','cultural_publications','official_military_supplies','industrial_feed_inputs','annexI_goods','veterinary_goods'];
export const objectiveImportTreatments=operationTreatments.filter(t=>fixed.includes(t.id)||t.id.startsWith('listed_'));
type Choice=''|'yes'|'no';
export type ObjectiveImportRow={id:string;description:string;period:string;currency:string;origin:'projected'|'effective';importer:string;documentRef:string;documentDate:string;scope:string;evidence:string;definitive:Choice;goods:Choice;sameGoods:Choice;internalApplicable:Choice;reference:SalesOperation;reusedFrom:string};
type Line={id:string;status:'exempt'|'not_applicable'|'indeterminate';importVat:string|null;deduction:null;source:string;reason:string};
export type ObjectiveImportCalculation={version:string;revision:number;calculatedAt:string;opportunity:string;sourceKey:string;source:string;inputs:ObjectiveImportRow[];rows:Line[]};
export type ObjectiveImportBook={rows:ObjectiveImportRow[];result?:ObjectiveImportCalculation;history?:ObjectiveImportCalculation[]};
type Store=ReturnType<typeof readAcquisitionStore>&{objectiveImports?:Record<string,ObjectiveImportBook>};
export function newObjectiveImport(id:string,currency:string):ObjectiveImportRow{return{id,description:'',period:'',currency,origin:'projected',importer:'',documentRef:'',documentDate:'',scope:'',evidence:'',definitive:'',goods:'',sameGoods:'',internalApplicable:'',reference:newSalesOperation(id+'-reference','',currency),reusedFrom:''};}
export function objectiveImportSources(draft:Record<string,unknown>):SalesOperation[]{return salesBook(draft).rows.filter(r=>objectiveImportTreatments.some(t=>t.id===r.treatment));}
export function reuseObjectiveImport(row:ObjectiveImportRow,source:SalesOperation):ObjectiveImportRow{
const reference={...row.reference};
// This explicit action fills missing values only; confirmations belong to this import.
if(!reference.treatment||reference.treatment==='other')reference.treatment=source.treatment;
if(reference.treatment===source.treatment){reference.annexIItem ||= source.annexIItem;reference.pharmaAnnexItem ||= source.pharmaAnnexItem;reference.annexIOnly ??= source.annexIOnly;}
return{...row,description:row.description||source.description,period:row.period||source.period,evidence:row.evidence||source.evidence,reference,reusedFrom:source.id};
}
function readStore(draft:Record<string,unknown>):Store{const s=readAcquisitionStore(draft.modelo_a_snapshot) as Store;const books=s.objectiveImports;if(books!==undefined&&(!books||typeof books!=='object'||Array.isArray(books)))throw new Error('Importações objectivas não recuperáveis;originais preservados.');const fields=Object.keys(newObjectiveImport('','MZN')).filter(k=>k!=='reference');for(const b of Object.values(books??{}))if(!b||!Array.isArray(b.rows)||(b.history!==undefined&&!Array.isArray(b.history))||b.rows.some(r=>!r||fields.some(k=>typeof r[k as keyof ObjectiveImportRow]!=='string')||!r.reference||typeof r.reference.treatment!=='string'||!Array.isArray(r.reference.confirmed)))throw new Error('Linhas de importação objectiva não recuperáveis;sem substituição por lista vazia.');return s;}
export function objectiveImportBook(draft:Record<string,unknown>):ObjectiveImportBook{return readStore(draft).objectiveImports?.[acquisitionScope(draft)]??{rows:[]};}
export function saveObjectiveImportBook(draft:Record<string,unknown>,book:ObjectiveImportBook):string{const s=readStore(draft),encoded=JSON.stringify({...s,objectiveImports:{...s.objectiveImports,[acquisitionScope(draft)]:book}});readStore({...draft,modelo_a_snapshot:encoded});return encoded;}
function date(value:string):boolean{const d=new Date(value+'T00:00:00Z');return /^\d{4}-\d{2}-\d{2}$/.test(value)&&Number.isFinite(d.getTime())&&d.toISOString().slice(0,10)===value;}
export function evaluateObjectiveImport(row:ObjectiveImportRow,currency:unknown):Line{
const rule=objectiveImportTreatments.find(t=>t.id===row.reference.treatment),result:Line={id:row.id,status:'indeterminate',importVat:null,deduction:null,source:objectiveImportSource+(rule?';'+rule.source:''),reason:''};const stop=(reason:string,status:Line['status']='indeterminate')=>({...result,status,reason});
if(currency!=='MZN'||row.currency!==currency||!/^2026-(0[1-9]|1[0-2])$/.test(row.period))return stop('Indique período2026 e moedaMZN coerente com o projecto;sem conversão presumida.');
if(!['projected','effective'].includes(row.origin)||![row.description,row.importer,row.documentRef,row.scope,row.evidence].every(v=>!!v.trim())||!date(row.documentDate))return stop('Identifique bens,importador,documento/previsão,data,âmbito e factos/pressupostos.Reutilize os elementos disponíveis.');
if([row.definitive,row.goods,row.sameGoods,row.internalApplicable].some(v=>v==='no'))return stop('Este fundamento12(1)a não se aplica aos factos indicados;IVA fora deste fundamento permanece por enquadrar,sem taxa presumida.','not_applicable');
if([row.definitive,row.goods,row.sameGoods,row.internalApplicable].some(v=>v!=='yes'))return stop('Confirme importação definitiva de bens,a correspondência dos mesmos bens e a aplicabilidade da isenção objectiva interna.Desconhecido não significa IVA zero.');
if(!rule)return stop('Escolha correspondência interna documentada.A lista implementada cobre as remissões expressas12(1)a;é exemplificativa e não declara excluídos outros fundamentos.Não basta descrição,isenção de serviços,exportação,taxa reduzida ou benefício terminado.');
// Evaluate the legal hypothetical domestic transmission, never create a domestic sale or use its amount/totals.
const reference={...row.reference,id:row.id+'-reference',description:row.description,period:row.period,sourcePeriod:row.period,sourceCurrency:row.currency,sourceAmount:null,establishment:row.importer,amount:'0',basis:'net' as const,evidence:row.evidence};
const v=evaluateSalesOperation(reference,row.currency);result.source=objectiveImportSource+';'+v.source;
if(v.status!=='exempt')return stop('Correspondência interna ainda não demonstrada: '+v.reason);
return{...result,status:'exempt',importVat:'0.00',reason:`Isenção12(1)a por correspondência a${rule.article},nas condições ${row.origin==='projected'?'expressamente assumidas da projecção':'efectivas declaradas'}. IVA na importação:0.00MZN. Hipótese de transmissão interna,não venda criada nem montante somado.Sem direitos,base aduaneira,dedução/campo11 ou concessão administrativa automática.`};
}
function key(draft:Record<string,unknown>,book:ObjectiveImportBook):string{return JSON.stringify({version:objectiveImportVersion,catalog:objectiveImportTreatments,scope:acquisitionScope(draft),currency:draft.currency,location:draft.selection_labels??{},rows:book.rows});}
export function objectiveImportCurrent(draft:Record<string,unknown>,book:ObjectiveImportBook):boolean{return!!book.result&&book.result.sourceKey===key(draft,book);}
export function recordObjectiveImports(draft:Record<string,unknown>,book:ObjectiveImportBook):ObjectiveImportBook{if(!book.rows.length||new Set(book.rows.map(r=>r.id)).size!==book.rows.length)throw new Error('Indique linhas com identidades distintas;originais conservados.');const result:ObjectiveImportCalculation={version:objectiveImportVersion,revision:(book.result?.revision??0)+1,calculatedAt:new Date().toISOString(),opportunity:acquisitionScope(draft),sourceKey:key(draft,book),source:objectiveImportSource,inputs:structuredClone(book.rows),rows:book.rows.map(r=>evaluateObjectiveImport(r,draft.currency))};const next={...book,result,history:[...(book.history??[]),...(book.result?[book.result]:[])]};saveObjectiveImportBook(draft,next);return next;}
export function objectiveImportReportRows(draft:Record<string,unknown>):Array<[string,string,string,string]>{try{const b=objectiveImportBook(draft),r=b.result;if(!r)return[];return r.inputs.map((row,i)=>['IVA mensal',`P046 — ${row.period} — ${row.id}`,`${row.description};${r.rows[i].reason};IVA importação:${r.rows[i].importVat??'Indeterminado'};dedução:Não apurada`,`${r.opportunity};${objectiveImportCurrent(draft,b)?'Resultado actual':'Entradas alteradas;resultado histórico conservado'};versão${r.revision};${r.calculatedAt};${row.origin};importador${row.importer};documento${row.documentRef},${row.documentDate};âmbito${row.scope};factos${row.evidence};reutilização${row.reusedFrom||'Introdução directa'};correspondência${row.reference.treatment};condições internas confirmadas${row.reference.confirmed.join(',')}${row.reference.treatment==='annexI_goods'?`;AnexoI${row.reference.annexIItem??''},apenasAnexoI${String(row.reference.annexIOnly??'Por esclarecer')}`:row.reference.treatment==='pharma_manufacturing_inputs'?`;AnexoIII${row.reference.pharmaAnnexItem??''}`:''};${r.rows[i].source};sem alteração dos livros internos,ModeloA,campo11 ou totais.`]);}catch{return[['IVA mensal','P046','Dados não recuperáveis','Originais preservados;sem classificação por defeito.']];}}