From 29e708ba2dca2450eaff8eff6f5e19079ffc7f8e Mon Sep 17 00:00:00 2001 From: nala Date: Sat, 24 Oct 2026 20:39:54 +0200 Subject: [PATCH] fix(iva): exclude import-linked services from goods gift references --- resources/js/lib/iva-offer-preparations.ts | 4 ++-- tests/frontend/iva-import-services.test.mjs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/resources/js/lib/iva-offer-preparations.ts b/resources/js/lib/iva-offer-preparations.ts index 835a472f..75d5f737 100644 --- a/resources/js/lib/iva-offer-preparations.ts +++ b/resources/js/lib/iva-offer-preparations.ts @@ -1,5 +1,5 @@ import { acquisitionBook, acquisitionScope } from './iva-acquisitions.ts'; -import { importExemptionBook } from './iva-import-exemptions.ts'; +import { importExemptionBook,isImportService } from './iva-import-exemptions.ts'; type Choice = ''|'yes'|'no'; export const offerPreparationSource='CIVA,Lei13/2016,14(2)(a/b) e14(3),PDF13/p.1426(271). Preparação de dados; procedimento regulamentar de aplicação ainda em pesquisa. Não concede isenção nem preenche dedução/campo11.'; @@ -34,7 +34,7 @@ export function recordOfferPreparations(book:OfferPreparationBook):OfferPreparat export type OfferReusable={key:string;label:string;operation:'acquisition'|'import';values:Partial}; export function offerReusableData(draft:Record):OfferReusable[]{ const purchases=acquisitionBook(draft).rows.map(row=>({key:'acquisition:'+row.id,label:'Aquisição: '+(row.description||row.documentRef||row.id),operation:'acquisition' as const,values:{description:row.description,period:row.period,currency:row.sourceCurrency,amount:row.net,documentRef:row.documentRef,documentDate:row.documentDate,counterparty:row.supplier}})); - const imports=importExemptionBook(draft).rows.map(row=>({key:'import:'+row.id,label:'Importação: '+(row.description||row.documentRef||row.id),operation:'import' as const,values:{description:row.description,period:row.period,currency:row.currency,amount:row.declaredValue,documentRef:row.documentRef,documentDate:row.documentDate,counterparty:row.importer}})); + const imports=importExemptionBook(draft).rows.filter(row=>!isImportService(row.treatment)).map(row=>({key:'import:'+row.id,label:'Importação: '+(row.description||row.documentRef||row.id),operation:'import' as const,values:{description:row.description,period:row.period,currency:row.currency,amount:row.declaredValue,documentRef:row.documentRef,documentDate:row.documentDate,counterparty:row.importer}})); return [...purchases,...imports]; } export function reuseOfferData(row:OfferPreparation,source:OfferReusable):OfferPreparation { diff --git a/tests/frontend/iva-import-services.test.mjs b/tests/frontend/iva-import-services.test.mjs index eafdd834..2400ae5e 100644 --- a/tests/frontend/iva-import-services.test.mjs +++ b/tests/frontend/iva-import-services.test.mjs @@ -3,6 +3,7 @@ import assert from 'node:assert/strict'; import fs from 'node:fs'; import { newImportExemption,evaluateImportExemption,recordImportExemptions,saveImportExemptionBook,importExemptionBook,importExemptionCurrent,importExemptionRules,importServiceSource } from '../../resources/js/lib/iva-import-exemptions.ts'; import { createProjectDossierReport } from '../../resources/js/lib/project-dossier-report.ts'; +import { offerReusableData } from '../../resources/js/lib/iva-offer-preparations.ts'; const frozen=JSON.parse(fs.readFileSync(new URL('./fixtures/iva-offer-paths-inputs.json',import.meta.url),'utf8')); const rules=importExemptionRules.filter(r=>r.branch==='P050'); const row=rule=>({...newImportExemption('g6f-'+rule.id,'MZN'),treatment:rule.id,description:'SYNTHETIC QA '+rule.label,period:'2026-12',declaredValue:'5000',importer:'SYNTHETIC QA importador destinatário',documentRef:'SYNTHETIC QA G6F '+rule.id,documentDate:'2026-11-14',evidence:'SYNTHETIC QA serviço e montante integral incluídos na base identificada, conforme artigo16; pressuposto expresso, não documento real',serviceImportRef:'SYNTHETIC QA importação DU-A,2026-12',serviceBaseRef:'SYNTHETIC QA base DU-A,linha serviço5000MZN',serviceProvider:'SYNTHETIC QA prestador',...(rule.id==='accessory_service_first_destination'?{serviceFirstDestination:'SYNTHETIC QA Manica,primeiro destino no documento de transporte'}:{}),conditions:Object.fromEntries(rule.conditions.map(([key])=>[key,'yes']))}); @@ -25,4 +26,5 @@ test('save/recovery/report preserve27fiscalbooks and946fc089scenarios/requests/h test('old goods rows keep own tax representation and malformed optional service references cannot overwrite saved originals',()=>{ const d=draft(),prior=JSON.parse(d.modelo_a_snapshot);for(const book of Object.values(prior.importExemptions))assert.ok(book.result.rows.every(row=>!Object.hasOwn(row,'serviceVat'))); assert.throws(()=>saveImportExemptionBook(d,{rows:[{...row(rules[0]),serviceBaseRef:42}]}),/Referências do serviço/); + const serviceOnly={...d,context_opportunity:'opportunity:336'};serviceOnly.modelo_a_snapshot=saveImportExemptionBook(serviceOnly,{rows:rules.map(row)});assert.equal(offerReusableData(serviceOnly).length,0,'P050 services cannot be reused as imported goods in P084'); });