import test from 'node:test';import assert from 'node:assert/strict';import fs from 'node:fs'; import {newSecondhand,switchSecondhandTreatment,switchSecondhandCategory,secondhandConditions,secondhandCategoryConditions,secondhandTreatments,secondhandCategories,evaluateSecondhand,recordSecondhands,saveSecondhandBook,secondhandBook,secondhandCurrent,secondhandReportRows} from '../../resources/js/lib/iva-secondhand.ts'; const frozen=JSON.parse(fs.readFileSync('tests/frontend/fixtures/iva-secondhand-preserved.json','utf8'));const draft={...frozen,currency:'MZN',context_opportunity:'opportunity:354',project_title:'SYNTHETIC QA — Segunda mão / Manica'}; function row(t,c){return{...newSecondhand(t+'-'+c,'MZN'),treatment:t,category:c,description:'SYNTHETIC QA '+t+'/'+c,period:'2026-12',origin:'projected',operationDate:'2026-12-12',operationRef:'SYNTHETIC QA operação',documentRef:'SYNTHETIC QA documento/pressuposto',documentDate:'2026-12-12',goodsRef:'SYNTHETIC QA bem individual '+t+c,operatorRef:'SYNTHETIC QA estatuto operador',categoryRef:'SYNTHETIC QA características/definição3(6)',artSubtype:'print',editionCount:'200',ceramicUniqueSigned:'yes',collectionSubtype:'postal',postalNotCirculating:'yes',ageYears:'101',sourceType:'private',sourceRef:'SYNTHETIC QA origem particular nacional',domesticPurchase:'yes',regimeChoice:'margin',domesticTaxable:'yes',grossSale:'1160',purchasePrice:'1000',purchaseRef:'SYNTHETIC QA preço compra justificado',grossInvoice:'1300',hammerPrice:'1000',principalCommission:'100',auctionRef:'SYNTHETIC QA organizador emnome próprio/contrato comissão/leilão',principalRef:'SYNTHETIC QA comitente/líquido',ownVat:'55.17',ownVatRef:'SYNTHETIC QA IVApróprio transmissão identificado',scope:'SYNTHETIC QA bem/partes/operação/período',evidence:'SYNTHETIC QA pressupostos expressos',conditions:{...Object.fromEntries([...secondhandConditions,...secondhandCategoryConditions(c)].map(([k])=>[k,'yes'])),regimeConfirmed:'yes',compositionConfirmed:'yes'}};} for(const t of secondhandTreatments)for(const c of secondhandCategories)test(t.branch+'/P125 '+c.id+' ownfacts,eligibleorigin and specificformula',()=>{ const r=row(t.id,c.id),result=evaluateSecondhand(r,'MZN');assert.equal(result.status,'determined');assert.equal(result.classification,'qualified_goods');assert.equal(result.baseAmount,t.id==='reseller_margin'?'138.00':'344.83');assert.equal(result.vat,null);assert.equal(result.rate,null); for(const [k] of [...secondhandConditions,...secondhandCategoryConditions(c.id)]){const missing=structuredClone(r);delete missing.conditions[k];assert.equal(evaluateSecondhand(missing,'MZN').classification,'indeterminate');missing.conditions[k]='no';assert.equal(evaluateSecondhand(missing,'MZN').classification,'not_applicable');assert.equal(evaluateSecondhand(missing,'MZN').baseAmount,null);} for(const field of ['description','operationRef','documentRef','goodsRef','operatorRef','categoryRef','scope','evidence'])assert.equal(evaluateSecondhand({...r,[field]:''},'MZN').classification,'indeterminate',field); for(const patch of [{period:'2025-12'},{operationDate:'2026-11-12'},{documentDate:'2026-02-30'},{currency:'USD'},{sourceType:'legacy_35_42'},{sourceType:'other'},{sourceRef:''},{domesticPurchase:''},{domesticTaxable:''}])assert.equal(evaluateSecondhand({...r,...patch},'MZN').baseAmount,null); assert.equal(evaluateSecondhand({...r,sourceType:'margin_reseller'},'MZN').status,'determined');assert.equal(evaluateSecondhand({...r,sourceType:'exempt_9_12_e'},'MZN').status,'determined'); if(t.id==='reseller_margin'){assert.equal(evaluateSecondhand({...r,regimeChoice:'general'},'MZN').baseAmount,null);for(const field of ['grossSale','purchasePrice','purchaseRef'])assert.equal(evaluateSecondhand({...r,[field]:''},'MZN').baseAmount,null);} else{for(const field of ['grossInvoice','hammerPrice','principalCommission','ownVat','ownVatRef','auctionRef','principalRef'])assert.equal(evaluateSecondhand({...r,[field]:''},'MZN').baseAmount,null);assert.equal(evaluateSecondhand({...r,principalCommission:'1001'},'MZN').baseAmount,null);assert.equal(evaluateSecondhand({...r,ownVat:'401'},'MZN').baseAmount,null);} }); test('P092 rounding towholeunit,zero vsunknown and negative individualmargin no compensation',()=>{ const r=row('reseller_margin','used_goods');assert.equal(evaluateSecondhand({...r,grossSale:'1000.58'},'MZN').baseAmount,'1.00');assert.equal(evaluateSecondhand({...r,grossSale:'1000.579999'},'MZN').baseAmount,'0.00');assert.equal(evaluateSecondhand({...r,grossSale:'1000'},'MZN').baseAmount,'0.00'); const loss=evaluateSecondhand({...r,grossSale:'900'},'MZN');assert.equal(loss.grossMargin,'-100.00');assert.equal(loss.baseAmount,'0.00');assert.match(loss.reason,/sem compensar/);assert.equal(evaluateSecondhand({...r,purchasePrice:''},'MZN').baseAmount,null); const positive=evaluateSecondhand(r,'MZN');assert.equal(positive.baseAmount,'138.00');assert.equal(positive.baseDivisorRate,'16%');assert.equal(positive.vat,null); }); test('P125 boundaries and both switches preserve hidden values withoutautomaticregime',()=>{ const art=row('reseller_margin','art');assert.equal(evaluateSecondhand({...art,editionCount:'201'},'MZN').classification,'not_applicable');assert.equal(evaluateSecondhand({...art,editionCount:''},'MZN').classification,'indeterminate');assert.equal(evaluateSecondhand({...art,artSubtype:'ceramic',ceramicUniqueSigned:''},'MZN').baseAmount,null); const antique=row('reseller_margin','antique');assert.equal(evaluateSecondhand({...antique,ageYears:'100'},'MZN').classification,'not_applicable');assert.equal(evaluateSecondhand({...antique,ageYears:'100.1'},'MZN').classification,'qualified_goods'); const changed=switchSecondhandTreatment(art,'auction_margin');assert.equal(changed.grossSale,art.grossSale);assert.equal(changed.ownVat,art.ownVat);assert.equal(changed.conditions.compositionConfirmed,'');assert.equal(evaluateSecondhand(changed,'MZN').baseAmount,null);const cat=switchSecondhandCategory(art,'collection');assert.equal(cat.editionCount,'200');assert.equal(cat.conditions.collectionNature,undefined); }); test('All8individualgoods persistwithhistory/report;all priorbooks preserved,noaggregateoffset',()=>{ const rows=secondhandTreatments.flatMap(t=>secondhandCategories.map(c=>row(t.id,c.id)));let book=recordSecondhands(draft,{rows});book=recordSecondhands(draft,book);assert.equal(book.history.length,1);const next={...draft,modelo_a_snapshot:saveSecondhandBook(draft,book)};assert.deepEqual(secondhandBook(next),book);assert.ok(secondhandCurrent(next,book));assert.equal(secondhandCurrent({...next,currency:'USD'},book),false);assert.equal(secondhandReportRows(next).length,8); const store=JSON.parse(next.modelo_a_snapshot);delete store.regulatedSecondhands;assert.deepEqual(store,JSON.parse(frozen.modelo_a_snapshot));assert.throws(()=>recordSecondhands(next,{rows:[rows[0],rows[0]]}));assert.throws(()=>secondhandBook({...next,modelo_a_snapshot:JSON.stringify({...JSON.parse(next.modelo_a_snapshot),regulatedSecondhands:[]})}));if(process.env.IVA_SECONDHAND_FIXTURE)fs.writeFileSync(process.env.IVA_SECONDHAND_FIXTURE,JSON.stringify(next,null,2)+'\n'); });