33 lines
6.8 KiB
JavaScript
33 lines
6.8 KiB
JavaScript
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
|
import {newForeignOperation,evaluateForeignOperation,foreignSources,foreignEvents,recordForeignOperations,saveForeignOperationBook,foreignOperationBook,foreignOperationCurrent,foreignOperationReportRows,switchForeignSource} from '../../resources/js/lib/iva-foreign-operations.ts';
|
|
import {recordGoodsLocations,saveGoodsLocationBook,goodsLocationBook} from '../../resources/js/lib/iva-goods-location.ts';
|
|
import {recordServiceLocations,saveServiceLocationBook} from '../../resources/js/lib/iva-service-location.ts';
|
|
import {recordListedServices,saveListedServiceBook} from '../../resources/js/lib/iva-listed-services.ts';
|
|
import {recordCurrencyEvents,saveCurrencyEventBook} from '../../resources/js/lib/iva-currency-events.ts';
|
|
const frozen=JSON.parse(fs.readFileSync('tests/frontend/fixtures/iva-foreign-operations-preserved.json','utf8')),original=JSON.parse(frozen.modelo_a_snapshot);
|
|
function seed(){const d={...frozen,context_opportunity:'opportunity:358',project_title:'SYNTHETIC QA — Operações no estrangeiro / Manica'};
|
|
for(const[map,record,save]of [['goodsLocations',recordGoodsLocations,saveGoodsLocationBook],['serviceLocations',recordServiceLocations,saveServiceLocationBook],['listedServices',recordListedServices,saveListedServiceBook]]){const rows=structuredClone(Object.values(original[map])[0].rows).map(r=>({...r,operationRef:'SYNTHETIC QA op '+r.id}));if(map==='serviceLocations'){const r=structuredClone(rows.find(x=>x.id==='transport_service-MZ'));rows.push({...r,id:'transport_partial',operationRef:'SYNTHETIC QA op transport_partial',departure:'MZ',arrival:'foreign',nationalDistance:'20',totalDistance:'100'});}d.modelo_a_snapshot=save(d,record(d,{rows}));}
|
|
const event=structuredClone(original.currencyEvents['opportunity:357'].rows.find(r=>r.treatment==='goods_available'));event.operationRef='SYNTHETIC QA op g8a-goods_without_transport';d.modelo_a_snapshot=saveCurrencyEventBook(d,recordCurrencyEvents(d,{rows:[event]}));return d;}
|
|
const draft=seed();
|
|
function row(id,kind,source){return{...newForeignOperation(id),sourceKind:kind,sourceRowId:source,territorialPart:'outside',hypotheticalTaxable:'yes',hypotheticalRef:'SYNTHETIC QA hipótese interna/natureza tributável e19(2),fundamento identificado',excluded19_2:'no',scope:'SYNTHETIC QA conjunto/parcela exterior/período identificado',evidence:'SYNTHETIC QA factos/pressupostos expressos'};}
|
|
const cases=[row('foreign_goods','goods','g8a-goods_without_transport'),row('foreign_services','services','general_service-foreign'),row('foreign_listed','listed','rights_service-outbound'),row('foreign_transport_part','services','transport_partial')];cases[0].eventRowId='goods_available';
|
|
for(const r of cases)test('P002 '+r.id+' reuses delivered territoriality and potential19only',()=>{const v=evaluateForeignOperation(draft,r);assert.equal(v.status,'determined');assert.equal(v.relation19,'potential');assert.equal(v.territory,r.id==='foreign_transport_part'?'outside_portion':'outside');assert.equal(v.deduction,null);assert.equal(v.vat,null);assert.equal(v.baseAmount,null);assert.equal(v.source.id,r.sourceRowId);assert.equal(v.source.current,true);if(r.eventRowId)assert.equal(v.event.eventDate,'2026-12-10');});
|
|
test('P002 unknown/national/partial do not imply foreign or exemption',()=>{
|
|
assert.equal(evaluateForeignOperation(draft,{...cases[0],sourceRowId:''}).status,'indeterminate');assert.equal(evaluateForeignOperation(draft,{...cases[0],sourceRowId:'g8a-goods_with_transport'}).status,'not_applicable');assert.equal(evaluateForeignOperation(draft,{...cases[3],territorialPart:''}).status,'indeterminate');assert.equal(evaluateForeignOperation(draft,{...cases[3],territorialPart:'national'}).status,'not_applicable');
|
|
for(const patch of [{scope:''},{evidence:''},{hypotheticalRef:''},{hypotheticalTaxable:''},{excluded19_2:''}])assert.equal(evaluateForeignOperation(draft,{...cases[0],...patch}).status,'indeterminate');
|
|
const no=evaluateForeignOperation(draft,{...cases[0],hypotheticalTaxable:'no'});assert.equal(no.relation19,'not_demonstrated');assert.equal(no.deduction,null);const excluded=evaluateForeignOperation(draft,{...cases[0],excluded19_2:'yes'});assert.equal(excluded.relation19,'excluded_19_2');assert.equal(excluded.deduction,null);
|
|
});
|
|
test('P002 stale source and event scope mismatch never overwrite prior acceptance',()=>{
|
|
const b=goodsLocationBook(draft),changed={...draft,modelo_a_snapshot:saveGoodsLocationBook(draft,{...b,rows:b.rows.map(r=>r.id===cases[0].sourceRowId?{...r,placeCountry:'MZ'}:r)})};assert.equal(evaluateForeignOperation(changed,cases[0]).status,'indeterminate');
|
|
assert.equal(evaluateForeignOperation({...draft,context_opportunity:'opportunity:359'},cases[0]).status,'indeterminate');assert.equal(evaluateForeignOperation(draft,{...cases[1],eventRowId:'goods_available'}).status,'indeterminate');
|
|
const sw=switchForeignSource(cases[0],'services','general_service-foreign');assert.equal(sw.hypotheticalRef,cases[0].hypotheticalRef);assert.equal(sw.hypotheticalTaxable,'');assert.equal(sw.eventRowId,'');assert.equal(foreignEvents(draft).length,1);assert.equal(foreignSources(draft,'goods').length,3);
|
|
});
|
|
test('P002 dependency changes invalidate new analysis while snapshot/history stay immutable',()=>{
|
|
const a=recordForeignOperations(draft,{rows:cases}),d={...draft,modelo_a_snapshot:saveForeignOperationBook(draft,a)};assert.equal(foreignOperationCurrent(d,a),true);const b=goodsLocationBook(d),changed={...d,modelo_a_snapshot:saveGoodsLocationBook(d,recordGoodsLocations(d,b))};assert.equal(foreignOperationCurrent(changed,a),false);assert.deepEqual(a.result.inputs,cases);assert.equal(foreignOperationReportRows(d).length,4);
|
|
});
|
|
test('P002 private save/recovery/report preserve 120delivered books and P104currency facts',()=>{
|
|
const rows=[...cases,row('national','goods','g8a-goods_with_transport'),{...cases[1],id:'hypothesis_not_taxable',hypotheticalTaxable:'no'},{...cases[2],id:'exclusion19_2',excluded19_2:'yes'}],a=recordForeignOperations(draft,{rows}),d={...draft,modelo_a_snapshot:saveForeignOperationBook(draft,a)},b=recordForeignOperations(d,a);d.modelo_a_snapshot=saveForeignOperationBook(d,b);assert.equal(b.history.length,1);assert.equal(foreignOperationReportRows(d).length,7);
|
|
const store=JSON.parse(d.modelo_a_snapshot);delete store.foreignOperations;for(const name of ['goodsLocations','serviceLocations','listedServices','currencyEvents'])delete store[name]['opportunity:358'];assert.deepEqual(store,original);assert.deepEqual(foreignOperationBook({...d,context_opportunity:'opportunity:359'}),{rows:[]});assert.throws(()=>recordForeignOperations(d,{rows:[rows[0],rows[0]]}));assert.throws(()=>foreignOperationBook({...d,modelo_a_snapshot:JSON.stringify({...store,foreignOperations:[]})}));
|
|
if(process.env.IVA_FOREIGN_OPERATIONS_FIXTURE)fs.writeFileSync(process.env.IVA_FOREIGN_OPERATIONS_FIXTURE,JSON.stringify(d,null,2)+'\n');
|
|
});
|