19 lines
7.8 KiB
JavaScript
19 lines
7.8 KiB
JavaScript
import {createProjectDossierReport} from '../../resources/js/lib/project-dossier-report.ts';
|
|
import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs';
|
|
import {newIspcEligibilityInput,recordIspcEligibility,saveIspcEligibilityBook} from '../../resources/js/lib/ispc-eligibility.ts';
|
|
import {newIspcQuarterInput,ispcQuarterBook,recordIspcQuarter,saveIspcQuarterBook,ispcQuarterCurrent,ispcQuarterReportRows} from '../../resources/js/lib/ispc-quarter.ts';
|
|
const seed=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-l3e-preserved.json',import.meta.url),'utf8'));
|
|
function fixture(ep={},qp={}){let d={...structuredClone(seed),context_opportunity:'opportunity:375',project_title:'SYNTHETIC QA — L4 ISPC',fiscal_component:'ispc',currency:'MZN',person_type:'collective',fiscal_activity:'SYNTHETIC QA canalização',fiscal_establishments:'1'};const input={...newIspcEligibilityInput(d),activities:['services12'],territory:'yes',basis:'previous_year',referenceYear:'2025',annualReference:'1000000',annualReferenceRef:'SYNTHETIC QA acesso2025',organizedRequired:'no',sharesInIspc:'no',sharesAnonymous:'no',otherActivities:'no',generalRegimeChosen:'no',unlistedServices:'no',...ep};const e=recordIspcEligibility(d,{version:1,input},'2026-10-25T12:00:00Z');d.modelo_a_snapshot=saveIspcEligibilityBook(d,e);const b={version:1,input:{...newIspcQuarterInput(),sales:['100000','','',''],salesRefs:['SYNTHETIC QA T1','','',''],coverage:'all_taxpayer_activity',...qp}};return{d,b};}
|
|
const calc=(ep={},qp={})=>{const{d,b}=fixture(ep,qp);return recordIspcQuarter(d,b,'2026-10-25T12:01:00Z').result;};
|
|
const decimal=x=>Number(x.numerator)/Number(x.denominator);
|
|
test('quarterly services12 andliberal15;highest mixed rate applied to entire quarterly base;no costs or VAT deduction',()=>{assert.equal(decimal(calc().tax),12000);assert.equal(decimal(calc({activities:['commerce','services12']}).tax),12000);assert.equal(decimal(calc({activities:['services12','liberal15'],liberalDaysSameEntity:'100',liberalClientRef:'QA'}).tax),15000);assert.equal(calc().projected,true);});
|
|
test('annual goods tiers applied to quarter without splitting annual limits or using previous-year accessvolume',()=>{for(const[annual,rate]of [['1000000',3],['1000000.000001',4],['2500000',4],['2500000.000001',5],['4000000',5]]){const r=calc({activities:['commerce']},{annualBandVolume:annual,annualBandOrigin:'forecast',annualBandRef:'QAannual2026'});assert.equal(r.status,'calculated',r.reason);assert.equal(r.rate,rate);assert.equal(decimal(r.tax),1000*rate);}assert.equal(calc({activities:['commerce']}).status,'indeterminate');});
|
|
test('20percent only newly crossed excess;prior quarters prevent repeating same excess;no threshold divided byfour',()=>{const q={quarter:'3',sales:['2000000','1900000','200000',''],salesRefs:['QA1','QA2','QA3','']};const r=calc({},q);assert.equal(decimal(r.ordinary),100000);assert.equal(decimal(r.excess),100000);assert.equal(decimal(r.tax),32000);const next=calc({},{...q,quarter:'4',sales:['2000000','1900000','200000','100000'],salesRefs:['QA1','QA2','QA3','QA4']});assert.equal(decimal(next.ordinary),0);assert.equal(decimal(next.tax),20000);});
|
|
test('minimum500:below no payment,declaration stays;exact500 payable;explicitzero distinct from missing',()=>{let r=calc({activities:['liberal15'],liberalDaysSameEntity:'100',liberalClientRef:'QA'},{sales:['3000','','','']});assert.equal(decimal(r.tax),450);assert.equal(decimal(r.payment),0);assert.equal(r.declaration,true);r=calc({activities:['commerce']},{sales:['16666.666667','','',''],annualBandVolume:'1000000',annualBandOrigin:'forecast',annualBandRef:'QA'});assert.ok(decimal(r.payment)>500);r=calc({}, {sales:['0','','','']});assert.equal(r.status,'calculated');assert.equal(decimal(r.tax),0);assert.equal(calc({}, {sales:['','','','']}).status,'indeterminate');const exact=calc({activities:['commerce']},{sales:['12500','','',''],annualBandVolume:'2000000',annualBandOrigin:'forecast',annualBandRef:'QA'});assert.equal(decimal(exact.payment),500);});
|
|
test('effective tax needs recorded option;notopted and incompatible are notapplicable;preparation remains scenario only',()=>{assert.equal(calc({origin:'effective'}).status,'indeterminate');assert.equal(calc({option:'not_opted'}).status,'not_applicable');assert.equal(calc({organizedRequired:'yes'}).status,'not_applicable');const r=calc({origin:'effective',option:'opted',optionDate:'2026-01-01',optionReference:'QA opção'});assert.equal(r.status,'calculated');assert.equal(r.projected,false);assert.equal(calc({origin:'effective',assessmentDate:'2026-10-25',option:'opted',optionDate:'2026-10-01',optionReference:'QA opção'}).status,'indeterminate');});
|
|
test('missing prior quarter,scope,year,source andannual mismatch do not produce zero',()=>{for(const p of [{year:'2025'},{quarter:'5'},{coverage:''},{salesRefs:['','','','']},{quarter:'2',sales:['','1000','','']}])assert.equal(calc({},p).status,'indeterminate');assert.equal(calc({activities:['commerce']},{annualBandVolume:'99999',annualBandOrigin:'forecast',annualBandRef:'QA'}).status,'indeterminate');});
|
|
test('closed-yearannual mustequalallfourquarters;quarter amount is not annual base',()=>{const q={quarter:'4',sales:['100000','200000','300000','400000'],salesRefs:['QA1','QA2','QA3','QA4'],annualBandVolume:'1000000',annualBandOrigin:'closed_year',annualBandRef:'QA2026'};assert.equal(decimal(calc({activities:['commerce']},q).tax),12000);assert.equal(calc({activities:['commerce']},{...q,annualBandVolume:'1000001'}).status,'indeterminate');assert.equal(decimal(calc({activities:['commerce']},{...q,quarter:'1'}).tax),3000);});
|
|
test('eligibility edits invalidate dependent calculation;save recovery freezesinput andretainsotherbooks/history',()=>{let{d,b}=fixture();const old=JSON.parse(d.modelo_a_snapshot);b=recordIspcQuarter(d,b);d.modelo_a_snapshot=saveIspcQuarterBook(d,b);assert.deepEqual(JSON.parse(d.modelo_a_snapshot).books,old.books);assert.equal(ispcQuarterCurrent(d,ispcQuarterBook(d)),true);const recovered=ispcQuarterBook(JSON.parse(JSON.stringify(d)));recovered.input.sales[0]='200000';assert.equal(ispcQuarterCurrent(d,recovered),false);assert.equal(decimal(recovered.result.tax),12000);const next=recordIspcQuarter(d,recovered);assert.equal(decimal(next.result.tax),24000);assert.equal(next.history.length,1);assert.equal(decimal(next.history[0].tax),12000);const s=JSON.parse(d.modelo_a_snapshot);s.ispcEligibility['opportunity:375'].input.activityDescription='edited';d.modelo_a_snapshot=JSON.stringify(s);assert.equal(recordIspcQuarter(d,next).result.status,'indeterminate');});
|
|
test('invalidstoredmaps andambiguouscontext remainpreservederrors',()=>{let{d,b}=fixture();const s=JSON.parse(d.modelo_a_snapshot);s.ispcQuarters=[];assert.throws(()=>ispcQuarterBook({...d,modelo_a_snapshot:JSON.stringify(s)}));assert.throws(()=>saveIspcQuarterBook(d,{...b,input:{...b.input,sales:['1']}}));});
|
|
test('export completeeligibilityoptioncalculationfixture andreport from recovereddata',()=>{let{d,b}=fixture({origin:'effective',assessmentDate:'2026-10-25',option:'opted',optionDate:'2026-01-01',optionReference:'SYNTHETIC QA opção ISPC2026'},{quarter:'2',sales:['100000','200000','',''],salesRefs:['SYNTHETIC QA T1','SYNTHETIC QA T2','','']});b=recordIspcQuarter(d,b,'2026-10-25T12:01:00Z');d.modelo_a_snapshot=saveIspcQuarterBook(d,b);const recovered=JSON.parse(JSON.stringify(d));assert.equal(decimal(ispcQuarterBook(recovered).result.tax),24000);assert.equal(ispcQuarterBook(recovered).result.projected,false);assert.match(JSON.stringify(ispcQuarterReportRows(recovered)),/24000.00/);const report=createProjectDossierReport(recovered,{selectedSections:new Set(['finance']),version:'QA ISPC',generatedAt:'2026-10-25T12:02:00Z'});assert.match(JSON.stringify(report.sections),/24000.00/);assert.match(JSON.stringify(report.sections),/opção ISPC2026/);if(process.env.L4_ISPC_OUTPUT)fs.writeFileSync(process.env.L4_ISPC_OUTPUT,JSON.stringify(recovered,null,2));});
|