From 2856240cf4badbbffb7e11849d03726c4ba1f00f Mon Sep 17 00:00:00 2001 From: nala Date: Fri, 23 Oct 2026 18:34:39 +0200 Subject: [PATCH] fix: print selected requirements and translated opportunity stage states --- resources/js/lib/project-dossier-report.ts | 9 ++++++++- tests/frontend/native-pdf-scope.test.mjs | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/frontend/native-pdf-scope.test.mjs diff --git a/resources/js/lib/project-dossier-report.ts b/resources/js/lib/project-dossier-report.ts index 55c7b5e5..022d463a 100644 --- a/resources/js/lib/project-dossier-report.ts +++ b/resources/js/lib/project-dossier-report.ts @@ -1,5 +1,6 @@ import { displayValue } from './display-value.ts'; import { fiscalQaRows } from './fiscal-qa-preview.ts'; +import { pathStates } from './investor-path.ts'; import { buildProjectDossierRows, type ProjectDossierRow, @@ -287,7 +288,13 @@ function makeSections( if (context.consumer_opportunity) section?.rows.push({field:'Oportunidade em tratamento', value:context.consumer_opportunity, origin:context.opportunity_choices?.[0]?.opportunity?.title ?? 'Escolha guardada no dossier', classification:'Âmbito desta análise'}); for (const step of context.path?.steps ?? []) { if (step.applicability === 'not_needed_for_preparation') section?.paragraphs.push(`${step.code} — preparação não necessária neste âmbito: ${step.reason || 'Decisão guardada do promotor'}. Histórico conservado; não constitui dispensa legal.`); - else section?.rows.push({field:`Etapa ${step.code}: ${step.title}`,value:step.applicability === 'undetermined' ? 'Aplicabilidade por determinar' : step.state,origin:context.consumer_opportunity ?? 'Contexto comum do dossier',classification:'Preparação no âmbito seleccionado'}); + else section?.rows.push({field:`Etapa ${step.code}: ${step.title}`,value:step.applicability === 'undetermined' ? 'Aplicabilidade por determinar' : pathStates[step.state] ?? 'Estado por determinar',origin:context.consumer_opportunity ?? 'Contexto comum do dossier',classification:'Preparação no âmbito seleccionado'}); + } + const dispensed = new Set((context.path?.steps ?? []).filter((step: {applicability:string})=>step.applicability === 'not_needed_for_preparation').map((step: {code:string})=>step.code)); + const requirementStates: Record = {selected:'Localização escolhida; direito não inferido',missing:'Informação em falta',conditional:'Conforme as condições do projecto',declared:'Actividades declaradas; enquadrar modalidade',undetermined:'Procedimento por determinar'}; + for (const requirement of context.requirements_assessment?.requirements ?? []) { + if (requirement.opportunity_key !== context.consumer_opportunity || dispensed.has(requirement.step)) continue; + section?.rows.push({field:`Requisito: ${requirement.title}`,value:`${requirementStates[requirement.state] ?? 'Por determinar'}. ${(requirement.documents ?? []).join('; ')}`,origin:`${requirement.opportunity_title}; ${requirement.opportunity_key}; ${requirement.basis ?? ''} ${requirement.source_url ?? ''}`,classification:'Preparação específica; não constitui licença ou aprovação'}); } const zone = context.zone; section?.rows.push({ diff --git a/tests/frontend/native-pdf-scope.test.mjs b/tests/frontend/native-pdf-scope.test.mjs new file mode 100644 index 00000000..ac376f1e --- /dev/null +++ b/tests/frontend/native-pdf-scope.test.mjs @@ -0,0 +1,19 @@ +import test from 'node:test'; +import assert from 'node:assert/strict'; +import {createProjectDossierReport,createProjectDossierPrintHtml} from '../../resources/js/lib/project-dossier-report.ts'; + +test('native print source includes only selected applicable requirements and human stage states',async()=>{ + const context={version:1,consumer_opportunity:'opportunity:309',context_revision:1, + opportunity_choices:[{opportunity:{key:'opportunity:309',title:'Segunda oportunidade Manica'}}], + path:{steps:[{code:'S10',title:'Terra',state:'not_started',applicability:'applicable'},{code:'S13',title:'Financiamento',applicability:'not_needed_for_preparation',reason:'Sem financiamento externo'}]}, + requirements_assessment:{requirements:[ + {opportunity_key:'opportunity:309',opportunity_title:'Segunda oportunidade Manica',step:'S10',title:'Acesso à terra e DUAT',state:'conditional',documents:['Planta do local'],basis:'Fonte documentada',source_url:'/documentos/fonte'}, + {opportunity_key:'opportunity:286',step:'S10',title:'Requisito da primeira Sofala',documents:[]}, + {opportunity_key:'opportunity:309',step:'S13',title:'Documento de financiamento dispensado',documents:[]}, + ]}}; + const report=createProjectDossierReport({project_title:'QA PDF Manica',context_applicability_snapshot:JSON.stringify(context)},{selectedSections:new Set(['sources'])}); + const html=await createProjectDossierPrintHtml(report,[],false); + assert.match(html,/Por iniciar/);assert.doesNotMatch(html,/not_started/); + assert.match(html,/Acesso à terra e DUAT/);assert.match(html,/Planta do local/);assert.match(html,/Fonte documentada/); + assert.doesNotMatch(html,/Requisito da primeira Sofala|Documento de financiamento dispensado/); +});