fix(logistique) : bon de pesée — cartouche tiers + filtrage des listes contrepartie par site (ERP-208) (#155)
Auto Tag Develop / tag (push) Successful in 14s

## ERP-208 — Fix ticket de pesée

### Bon de pesée (PDF)
Ajout d'un **cartouche bordé en haut à droite** du bon de pesée, contenant le **type de contrepartie** (Client / Fournisseur / Autre, en gras au-dessus) et le **nom du tiers**.
- `WeighingTicket::getCounterpartyName()` + `getCounterpartyTypeLabel()` (testés).
- En-tête du template passé en table 2 colonnes (contrainte Dompdf CSS 2.1).

### Écran de saisie (Ajouter / Modifier)
Les listes **Client / Fournisseur** sont **filtrées sur le site courant** (un tiers est rattaché à un site via les sites de ses adresses) et **rechargées au changement de site**.
- Réutilise le filtre back existant `?siteId[]=` de /clients et /suppliers (aucun changement back sur le filtre).
- Au switch de site : le tiers sélectionné est réinitialisé **uniquement** s'il sort du périmètre du nouveau site.
- Portée limitée au ticket de pesée : les répertoires M1/M2 ne changent pas.

### Tests
- Back : test unitaire `WeighingTicketCounterpartyNameTest` (nom + libellé) ; test PDF existant inchangé.
- Front : specs référentiels + écrans Ajouter/Modifier (673/673).
- Pas de migration, pas de RBAC, pas d'E2E.

### À vérifier en recette
En **modification**, si le tiers d'un ticket n'a pas d'adresse sur le site courant, le select peut s'afficher vide (valeur conservée mais option filtrée).

Reviewed-on: #155
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #155.
This commit is contained in:
2026-06-25 13:02:31 +00:00
committed by Autin
parent f6c556ca1b
commit 086be7b4f0
11 changed files with 718 additions and 23 deletions
@@ -8,12 +8,13 @@ const mockFetchTicket = vi.hoisted(() => vi.fn())
const mockPatch = vi.hoisted(() => vi.fn())
const mockPush = vi.hoisted(() => vi.fn())
const mockOpen = vi.hoisted(() => vi.fn())
const mockRefLoad = vi.hoisted(() => vi.fn())
vi.mock('~/modules/logistique/composables/useWeighingTicket', () => ({
useWeighingTicket: () => ({ fetchTicket: mockFetchTicket }),
}))
vi.mock('~/modules/logistique/composables/useWeighingTicketReferentials', () => ({
useWeighingTicketReferentials: () => ({ clients: ref([]), suppliers: ref([]), load: vi.fn().mockResolvedValue(undefined) }),
useWeighingTicketReferentials: () => ({ clients: ref([]), suppliers: ref([]), load: mockRefLoad }),
}))
vi.mock('~/modules/logistique/composables/useWeighbridge', () => ({
useWeighbridge: () => ({ triggerAuto: vi.fn(), triggerManual: vi.fn(), extractWeighbridgeError: () => 'err' }),
@@ -100,6 +101,7 @@ describe('Écran Modification ticket de pesée (page /weighing-tickets/{id}/edit
mockPatch.mockReset().mockResolvedValue({})
mockPush.mockReset()
mockOpen.mockReset()
mockRefLoad.mockReset().mockResolvedValue(undefined)
})
it('charge le ticket au montage (pré-remplissage via hydrate)', async () => {
@@ -107,6 +109,12 @@ describe('Écran Modification ticket de pesée (page /weighing-tickets/{id}/edit
expect(mockFetchTicket).toHaveBeenCalledWith('9')
})
it('filtre les référentiels sur le SITE DU TICKET, pas le site courant (ERP-208)', async () => {
await mountPage()
// DETAIL.site.id = 1 → les listes sont chargées pour le site du ticket (immuable).
expect(mockRefLoad).toHaveBeenCalledWith(1)
})
it('ticket validé : action principale « Enregistrer » + « Imprimer » (pas « Valider »)', async () => {
const wrapper = await mountPage()
// DETAIL.status = VALIDATED → l'action principale s'intitule « Enregistrer ».
@@ -7,9 +7,10 @@ const mockPost = vi.hoisted(() => vi.fn())
const mockPatch = vi.hoisted(() => vi.fn())
const mockPush = vi.hoisted(() => vi.fn())
const mockOpen = vi.hoisted(() => vi.fn())
const mockRefLoad = vi.hoisted(() => vi.fn())
vi.mock('~/modules/logistique/composables/useWeighingTicketReferentials', () => ({
useWeighingTicketReferentials: () => ({ clients: ref([]), suppliers: ref([]), load: vi.fn().mockResolvedValue(undefined) }),
useWeighingTicketReferentials: () => ({ clients: ref([]), suppliers: ref([]), load: mockRefLoad }),
}))
vi.mock('~/modules/logistique/composables/useWeighbridge', () => ({
useWeighbridge: () => ({ triggerAuto: vi.fn(), triggerManual: vi.fn(), extractWeighbridgeError: () => 'err' }),
@@ -23,6 +24,8 @@ vi.stubGlobal('useRouter', () => ({ push: mockPush }))
vi.stubGlobal('usePermissions', () => ({ can: () => true }))
vi.stubGlobal('navigateTo', vi.fn())
vi.stubGlobal('useFormErrors', () => ({ errors: reactive({}), setError: vi.fn(), clearErrors: vi.fn(), handleApiError: vi.fn() }))
// Site courant (ERP-208) : id 7 → les référentiels doivent être chargés filtrés sur ce site.
vi.stubGlobal('useCurrentSite', () => ({ currentSite: ref({ id: 7, name: 'Site 7', color: '#000000' }) }))
globalThis.open = mockOpen
const NewPage = (await import('../weighing-tickets/new.vue')).default
@@ -70,6 +73,12 @@ describe('Écran Ajouter ticket de pesée (page /weighing-tickets/new)', () => {
mockPatch.mockReset().mockResolvedValue({})
mockPush.mockReset()
mockOpen.mockReset()
mockRefLoad.mockReset().mockResolvedValue(undefined)
})
it('charge les référentiels filtrés sur le site courant au montage (ERP-208)', async () => {
await mountPage()
expect(mockRefLoad).toHaveBeenCalledWith(7)
})
it('un seul bouton « Valider » (pas de « Enregistrer » séparé)', async () => {