import { describe, it, expect, vi, beforeEach } from 'vitest'; // Mock the database module vi.mock('./db', () => ({ getRequestById: vi.fn(), updateRequest: vi.fn(), createRequestHistory: vi.fn(), createAuditLog: vi.fn(), })); import * as db from './db'; describe('DSU (Direction des Services aux Usagers) - Cadre réservé', () => { beforeEach(() => { vi.clearAllMocks(); }); describe('Merging DSU data into formData', () => { it('should merge DSU data into existing formData for demande_salle', () => { const existingFormData = { nomAssociation: 'Association Test', sallesSelectionnees: ['Salle TOUCAN'], dateReservation: '2026-04-15', motifReservation: 'Réunion annuelle', formulaireType: 'reservation_salle_mjs', }; const dsuData = { dateReception: '2026-03-10', avisDSU: 'favorable' as const, conditionsParticulieres: 'Nettoyage obligatoire', cautionRequise: true, montantCaution: '500', assuranceRequise: true, horairesImposes: '8h00 - 22h00', responsableDSU: 'Jean Dupont', dateDecision: '2026-03-11', observationsDSU: 'RAS', }; // Simulate the merge logic from routers.ts const merged = { ...existingFormData }; (merged as any).cadreDSU = { ...dsuData, rempliPar: 1, dateRemplissage: new Date().toISOString(), }; const result = JSON.parse(JSON.stringify(merged)); // Verify original data is preserved expect(result.nomAssociation).toBe('Association Test'); expect(result.sallesSelectionnees).toEqual(['Salle TOUCAN']); expect(result.dateReservation).toBe('2026-04-15'); expect(result.motifReservation).toBe('Réunion annuelle'); // Verify DSU data is added expect(result.cadreDSU).toBeDefined(); expect(result.cadreDSU.avisDSU).toBe('favorable'); expect(result.cadreDSU.dateReception).toBe('2026-03-10'); expect(result.cadreDSU.conditionsParticulieres).toBe('Nettoyage obligatoire'); expect(result.cadreDSU.cautionRequise).toBe(true); expect(result.cadreDSU.montantCaution).toBe('500'); expect(result.cadreDSU.assuranceRequise).toBe(true); expect(result.cadreDSU.horairesImposes).toBe('8h00 - 22h00'); expect(result.cadreDSU.responsableDSU).toBe('Jean Dupont'); expect(result.cadreDSU.dateDecision).toBe('2026-03-11'); expect(result.cadreDSU.observationsDSU).toBe('RAS'); expect(result.cadreDSU.rempliPar).toBe(1); expect(result.cadreDSU.dateRemplissage).toBeDefined(); }); it('should not add DSU data for non-salle request types', () => { const requestType = 'subvention_fonctionnement'; const dsuData = { avisDSU: 'favorable' as const, responsableDSU: 'Jean Dupont', }; // Simulate the condition check from routers.ts const shouldAddDsu = requestType === 'demande_salle'; expect(shouldAddDsu).toBe(false); }); it('should handle empty existing formData gracefully', () => { const existingFormData = null; const dsuData = { avisDSU: 'defavorable' as const, responsableDSU: 'Marie Martin', observationsDSU: 'Salle non disponible', }; // Simulate the merge logic const parsed = existingFormData ? JSON.parse(existingFormData) : {}; parsed.cadreDSU = { ...dsuData, rempliPar: 2, dateRemplissage: new Date().toISOString(), }; const result = JSON.parse(JSON.stringify(parsed)); expect(result.cadreDSU).toBeDefined(); expect(result.cadreDSU.avisDSU).toBe('defavorable'); expect(result.cadreDSU.responsableDSU).toBe('Marie Martin'); }); it('should handle favorable_avec_reserves avis correctly', () => { const existingFormData = { nomAssociation: 'Test' }; const dsuData = { avisDSU: 'favorable_avec_reserves' as const, conditionsParticulieres: 'Sous réserve de présentation de l\'attestation d\'assurance', cautionRequise: true, montantCaution: '1000', }; const merged = { ...existingFormData, cadreDSU: { ...dsuData, rempliPar: 1, dateRemplissage: new Date().toISOString() } }; const result = JSON.parse(JSON.stringify(merged)); expect(result.cadreDSU.avisDSU).toBe('favorable_avec_reserves'); expect(result.cadreDSU.conditionsParticulieres).toContain('attestation d\'assurance'); expect(result.cadreDSU.cautionRequise).toBe(true); expect(result.cadreDSU.montantCaution).toBe('1000'); }); it('should merge financial decision into an existing salle request dossier', () => { const existingFormData = { nomAssociation: 'Association Test', sallesSelectionnees: ['Salle TOUCAN'], dateReservation: '2026-06-20', cadreDSU: { responsableDSU: 'Agent DSU', }, }; const financialDecision = { financialMode: 'location_payante' as const, depositRequired: true, depositAmountCents: 45000, rentalAmountCents: 12500, pricingNotes: 'Facturation exceptionnelle pour occupation prolongée', contractStatus: 'a_generer' as const, }; const merged = structuredClone(existingFormData) as any; merged.cadreDSU = { ...merged.cadreDSU, cautionRequise: financialDecision.depositRequired, montantCaution: String(financialDecision.depositAmountCents / 100), materielEvent: { financialDecision, }, }; expect(merged.cadreDSU.cautionRequise).toBe(true); expect(merged.cadreDSU.montantCaution).toBe('450'); expect(merged.cadreDSU.materielEvent.financialDecision.financialMode).toBe('location_payante'); expect(merged.cadreDSU.materielEvent.financialDecision.rentalAmountCents).toBe(12500); }); it('should merge material financial decision into the existing material request data', () => { const existingFormData = { commune: 'Kourou', service: 'Vie associative', quantitesDemandees: { tente3x3: '2' }, cadreDSU: { dateReception: '2026-05-10', materielEvent: { itemsAccordes: { tente3x3: true }, quantitesAccordees: { tente3x3: '2' }, }, }, }; const financialDecision = { financialMode: 'location_payante' as const, depositRequired: true, depositAmountCents: 25000, rentalAmountCents: 9500, pricingNotes: 'Tarif exceptionnel pour événement intercommunal', contractStatus: 'a_generer' as const, }; const merged = structuredClone(existingFormData) as any; merged.cadreDSU = { ...merged.cadreDSU, responsableDSU: 'Admin Logistique', materielEvent: { ...merged.cadreDSU.materielEvent, financialDecision, }, }; expect(merged.cadreDSU.materielEvent.itemsAccordes.tente3x3).toBe(true); expect(merged.cadreDSU.materielEvent.quantitesAccordees.tente3x3).toBe('2'); expect(merged.cadreDSU.materielEvent.financialDecision.financialMode).toBe('location_payante'); expect(merged.cadreDSU.materielEvent.financialDecision.depositRequired).toBe(true); expect(merged.cadreDSU.materielEvent.financialDecision.depositAmountCents).toBe(25000); expect(merged.cadreDSU.materielEvent.financialDecision.rentalAmountCents).toBe(9500); expect(merged.cadreDSU.materielEvent.financialDecision.pricingNotes).toContain('Tarif exceptionnel'); }); }); describe('DSU avis labels mapping', () => { const avisDSULabels: Record = { favorable: { label: 'Favorable', className: 'bg-green-100 text-green-800 border-green-200' }, defavorable: { label: 'Défavorable', className: 'bg-red-100 text-red-800 border-red-200' }, favorable_avec_reserves: { label: 'Favorable avec réserves', className: 'bg-amber-100 text-amber-800 border-amber-200' }, }; it('should have correct labels for all avis types', () => { expect(avisDSULabels.favorable.label).toBe('Favorable'); expect(avisDSULabels.defavorable.label).toBe('Défavorable'); expect(avisDSULabels.favorable_avec_reserves.label).toBe('Favorable avec réserves'); }); it('should have appropriate CSS classes for visual distinction', () => { expect(avisDSULabels.favorable.className).toContain('green'); expect(avisDSULabels.defavorable.className).toContain('red'); expect(avisDSULabels.favorable_avec_reserves.className).toContain('amber'); }); }); describe('Process mutation with DSU data', () => { it('should call updateRequest with merged formData when DSU data is provided', async () => { const mockRequest = { id: 1, type: 'demande_salle', status: 'soumise', formData: JSON.stringify({ nomAssociation: 'Test Asso', sallesSelectionnees: ['Salle TOUCAN'], }), }; (db.getRequestById as any).mockResolvedValue(mockRequest); (db.updateRequest as any).mockResolvedValue(undefined); (db.createRequestHistory as any).mockResolvedValue(undefined); (db.createAuditLog as any).mockResolvedValue(undefined); const dsuData = { avisDSU: 'favorable' as const, responsableDSU: 'Admin Test', dateReception: '2026-03-10', dateDecision: '2026-03-11', }; // Simulate the process logic const existingFormData = JSON.parse(mockRequest.formData); existingFormData.cadreDSU = { ...dsuData, rempliPar: 1, dateRemplissage: new Date().toISOString(), }; const updatedFormData = JSON.stringify(existingFormData); await db.updateRequest(mockRequest.id, { status: 'validee' as any, commentaireAdmin: 'Approuvé', traitePar: 1, dateTraitement: new Date(), formData: updatedFormData, }); expect(db.updateRequest).toHaveBeenCalledWith( 1, expect.objectContaining({ status: 'validee', formData: expect.stringContaining('cadreDSU'), }) ); // Verify the formData contains the DSU data const callArgs = (db.updateRequest as any).mock.calls[0][1]; const parsedFormData = JSON.parse(callArgs.formData); expect(parsedFormData.cadreDSU.avisDSU).toBe('favorable'); expect(parsedFormData.cadreDSU.responsableDSU).toBe('Admin Test'); expect(parsedFormData.nomAssociation).toBe('Test Asso'); }); }); });