Une pesée (bascule ou manuelle) s'enregistre désormais dès la validation de sa
modale, sans exiger la contrepartie ni l'immatriculation : le ticket naît
« brouillon » (status DRAFT, sans numéro). Le bouton « Valider » finalise quand
les 3 champs du haut (contrepartie + champ associé + immatriculation) ET les 2
pesées sont renseignés : attribution du numéro {siteCode}-TP-{NNNN} et passage
en VALIDATED, puis ouverture du bon de pesée PDF.
Back : counterparty_type/immatriculation/number nullables + colonne status
(migration racine), contraintes strictes déplacées en groupe de validation
finalize, opération PATCH /weighing_tickets/{id}/validate, numéro attribué à la
validation. Front : 4 champs en haut hors blocs, persistance immédiate des
pesées, écrans Ajouter/Modifier refondus, colonne Statut dans la liste, form à
plat pleine largeur. Tests back (lifecycle brouillon/validate) + front à jour.
Endpoint API Platform GET /api/weighing_tickets/{id}/print.pdf (provider
renvoyant un binaire, pas de controller) sécurisé par
logistique.weighing_tickets.view. Rendu d'un template Twig hydraté avec le
ticket converti en PDF via Dompdf. Reproduit le modèle fourni : en-tête fixe
(logo + identité société, indépendant du site), pesées à vide/plein avec le
numéro de pesée affiché comme un DSD, poids net = plein − vide.
Endpoint GET /api/weighing_tickets/export.xlsx — controller custom (priority: 1)
calque sur les exports M2/M3/M4, delegue la generation au SpreadsheetExporter
partage. Rejoue la selection du WeighingTicketProvider (recherche ?search, tri
?order[displayDate], cloisonnement par site courant) SANS pagination : export
complet de la liste (§ 4.5).
Colonnes : Numero, Type contrepartie, Contrepartie (nom Client/Fournisseur/
Autre), Date, Immatriculation, Poids vide, Poids plein, Poids net, DSD vide,
DSD plein. Securite logistique.weighing_tickets.view.
Tests fonctionnels : 200 + en-tetes/Content-Disposition, mapping des colonnes
avec net = plein - vide (RG-5.05), cloisonnement par site (non-admin), 403, 401.