From f40957f101d6d700a33214237c00cfcadea492c0 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 2 Aug 2026 23:08:52 +0000 Subject: [PATCH] =?UTF-8?q?B134=20=E2=80=94=20allow=20empty=20rationale=20?= =?UTF-8?q?on=20movimento=20allocation=20decisions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Relax AllocationDecision.rationale required flag; validate in hook - Fix empty-motivo int test to use first movement from null Co-authored-by: Francisco Solla --- src/collections/AllocationDecision.ts | 10 +++++++++- ...campaignMunicipalityEngagementLevel.int.spec.ts | 14 +++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/collections/AllocationDecision.ts b/src/collections/AllocationDecision.ts index ea83bbf0..9cec5aac 100644 --- a/src/collections/AllocationDecision.ts +++ b/src/collections/AllocationDecision.ts @@ -32,6 +32,13 @@ const validateAllocationDecision: CollectionBeforeValidateHook = ({ throw new APIError('Informe a leitura alternativa ao descartar a sugestão.', 400) } + if ( + nextData.outcome !== 'movimento' && + (typeof nextData.rationale !== 'string' || !nextData.rationale.trim()) + ) { + throw new APIError('Informe a justificativa.', 400) + } + try { const serializedSnapshot = JSON.stringify(nextData.snapshot) if ( @@ -116,7 +123,8 @@ export const AllocationDecision: CollectionConfig = { name: 'rationale', type: 'textarea', label: 'Justificativa', - required: true, + // E14 movimento may omit motivo (B134); triage outcomes validate in beforeValidate. + required: false, maxLength: 2000, }, { diff --git a/tests/int/campaignMunicipalityEngagementLevel.int.spec.ts b/tests/int/campaignMunicipalityEngagementLevel.int.spec.ts index 00b1864e..79df08b0 100644 --- a/tests/int/campaignMunicipalityEngagementLevel.int.spec.ts +++ b/tests/int/campaignMunicipalityEngagementLevel.int.spec.ts @@ -71,22 +71,14 @@ describe('municipality engagement level (E14)', () => { const coordinator = await fixtures.createCampaignUser('coordinator') const municipality = await fixtures.getMunicipality() - await payload.update({ - collection: 'municipality', - id: municipality.id, - data: { engagementLevel: 'n1', levelNote: 'Nota anterior.' }, - depth: 0, - }) - fixtures.touchMunicipality(municipality.id) - const updated = await setMunicipalityEngagementLevelRecord(payload, coordinator, { municipality: municipality.id, - level: 'n2', + level: 'n1', note: null, }) fixtures.touchMunicipality(municipality.id) - expect(updated.engagementLevel).toBe('n2') + expect(updated.engagementLevel).toBe('n1') expect(updated.levelNote).toBeNull() const decisions = await findDecisions(municipality.id) @@ -94,7 +86,7 @@ describe('municipality engagement level (E14)', () => { const decision = decisions.docs[0]! fixtures.own('allocationDecision', decision.id) expect(decision.rationale).toBe('') - expect(decision.snapshot).toMatchObject({ from: 'n1', to: 'n2' }) + expect(decision.snapshot).toMatchObject({ from: null, to: 'n1' }) expect(decision.snapshot).not.toHaveProperty('reversalSignals') })