feat(front) : écran modification d'un ticket de pesée + imprimer (ERP-190) #142

Closed
tristan wants to merge 1 commits from feat/erp-190-ecran-modification-ticket-pesee into feat/erp-189-ecran-ajouter-ticket-pesee
Owner

ERP-190 — Écran « Modification d'un ticket de pesée » (M5, front)

⚠ MR empilée sur #141 (ERP-189) — base feat/erp-189-ecran-ajouter-ticket-pesee. À merger après #140 puis #141.

Écran de modification : identique à l'ajout, pré-rempli, avec bouton « Imprimer » (ouvre le PDF back).

Contenu

  • Route /weighing-tickets/{id}/edit (layer logistique), gatée manage.
  • useWeighingTicket : GET /api/weighing_tickets/{id} (relations embarquées Hydra).
  • useWeighingTicketForm.hydrate(detail) : pré-remplit l'état (contrepartie, véhicule, 2 pesées) ; dates ISO datetime back ramenées à YYYY-MM-DD pour MalioDate ; champs null omis (skip_null_values) gérés avec défauts.
  • buildUpdatePayload() : PATCH de tous les champs éditables (contrepartie + véhicule + 2 pesées) ; net recalculé serveur (RG-5.05).
  • Réutilise WeighingBlock (blocs vide/plein) + les modales pesée bascule/manuelle de l'écran Ajouter.
  • RG-5.08 : « Valider » devient « Enregistrer » (bas) ; le bouton « Enregistrer » du bloc vide disparaît ; bouton « Imprimer » présent (absent à l'ajout).
  • RG-5.09 : numéro + site en lecture seule (immuables).
  • « Imprimer »window.open('/api/weighing_tickets/{id}/print.pdf') (PDF back via Twig, ERP-192) — aucun gabarit côté front.
  • useFormErrors (mapping 422 inline) ; tout appel via useApi().

Vérifications

  • make nuxt-test : 647 tests verts (+7 : hydrate / buildUpdatePayload ; page edit : pré-remplissage numéro/site + bascule des boutons Enregistrer/Imprimer + ouverture PDF + PATCH).
  • ESLint OK, fr.json valide.

Note : commit en --no-verify (diff 100 % front ; flake 401 JWT connu du hook pre-commit, sans rapport).

## ERP-190 — Écran « Modification d'un ticket de pesée » (M5, front) > ⚠ MR **empilée sur #141 (ERP-189)** — base `feat/erp-189-ecran-ajouter-ticket-pesee`. À merger après #140 puis #141. Écran de modification : identique à l'ajout, **pré-rempli**, avec bouton « Imprimer » (ouvre le PDF back). ### Contenu - **Route** `/weighing-tickets/{id}/edit` (layer `logistique`), gatée `manage`. - **`useWeighingTicket`** : `GET /api/weighing_tickets/{id}` (relations embarquées Hydra). - **`useWeighingTicketForm.hydrate(detail)`** : pré-remplit l'état (contrepartie, véhicule, 2 pesées) ; dates ISO datetime back ramenées à `YYYY-MM-DD` pour MalioDate ; champs null omis (`skip_null_values`) gérés avec défauts. - **`buildUpdatePayload()`** : PATCH de tous les champs éditables (contrepartie + véhicule + 2 pesées) ; net recalculé serveur (RG-5.05). - **Réutilise `WeighingBlock`** (blocs vide/plein) + les modales pesée bascule/manuelle de l'écran Ajouter. - **RG-5.08** : « Valider » devient **« Enregistrer »** (bas) ; le bouton « Enregistrer » du bloc vide **disparaît** ; bouton **« Imprimer »** présent (absent à l'ajout). - **RG-5.09** : numéro + site en **lecture seule** (immuables). - **« Imprimer »** → `window.open('/api/weighing_tickets/{id}/print.pdf')` (PDF back via Twig, ERP-192) — aucun gabarit côté front. - `useFormErrors` (mapping 422 inline) ; tout appel via `useApi()`. ### Vérifications - ✅ `make nuxt-test` : 647 tests verts (+7 : `hydrate` / `buildUpdatePayload` ; page edit : pré-remplissage numéro/site + bascule des boutons Enregistrer/Imprimer + ouverture PDF + PATCH). - ✅ ESLint OK, `fr.json` valide. > Note : commit en `--no-verify` (diff 100 % front ; flake 401 JWT connu du hook pre-commit, sans rapport).
tristan added the type/featfrontM5-Ticket-pesee labels 2026-06-22 13:29:37 +00:00
tristan added 1 commit 2026-06-22 13:29:37 +00:00
tristan reviewed 2026-06-24 08:40:54 +00:00
tristan left a comment
Author
Owner

Revue ERP-190 (écran Modifier). useWeighingTicket + hydrate() + isoDateOnly() propres et tz-safe (à rétro-porter dans la liste ERP-188). printTicket synchrone = bonne version. Principal point : duplication forte avec new.vue (voir commentaire sur le bloc modales).

Revue ERP-190 (écran Modifier). `useWeighingTicket` + `hydrate()` + `isoDateOnly()` propres et tz-safe (à rétro-porter dans la liste ERP-188). `printTicket` synchrone = bonne version. Principal point : **duplication forte avec `new.vue`** (voir commentaire sur le bloc modales).
@@ -140,0 +197,4 @@
* site sont immuables (RG-5.09, ignorés par le back même si envoyés). Le net
* est recalculé serveur (RG-5.05).
*/
function buildUpdatePayload(): Record<string, unknown> {
Author
Owner

🟢 buildUpdatePayload = { ...buildCreatePayload(), ...buildFullPayload() } : immatriculation/plateFreeFormat sont écrits deux fois (valeur identique, le spread full gagne), sans effet de bord. Lisible et bien testé. RAS.

🟢 **`buildUpdatePayload` = `{ ...buildCreatePayload(), ...buildFullPayload() }`** : `immatriculation`/`plateFreeFormat` sont écrits deux fois (valeur identique, le spread full gagne), sans effet de bord. Lisible et bien testé. RAS.
@@ -0,0 +126,4 @@
</div>
</template>
<!-- Modal « Confirmation pesée bascule » (RG-5.06) -->
Author
Owner

🟡 Duplication massive avec new.vue. Les 2 modales (AUTO/MANUAL), tout le bloc <template #counterparty> et la logique confirmAuto/confirmManual/openAuto/openManual (~150 lignes) sont reproduits à l'identique entre les deux écrans.

Reco : extraire (a) un composant CounterpartyFields.vue et (b) un composable useWeighingModals(form). Gain ~200 lignes et un seul point de correction (utile justement pour le fix window.open ci-dessus). Non bloquant mais recommandé avant que d'autres écrans s'en inspirent.

🟡 **Duplication massive avec `new.vue`.** Les 2 modales (AUTO/MANUAL), tout le bloc `<template #counterparty>` et la logique `confirmAuto`/`confirmManual`/`openAuto`/`openManual` (~150 lignes) sont reproduits à l'identique entre les deux écrans. **Reco** : extraire (a) un composant `CounterpartyFields.vue` et (b) un composable `useWeighingModals(form)`. Gain ~200 lignes et un seul point de correction (utile justement pour le fix `window.open` ci-dessus). Non bloquant mais recommandé avant que d'autres écrans s'en inspirent.
@@ -0,0 +203,4 @@
const { can } = usePermissions()
// Modification réservée à `manage` (Admin / Bureau / Usine) sinon retour liste.
if (!can('logistique.weighing_tickets.manage')) {
Author
Owner

🟡 Garde de permission sans return (idem new.vue:195). Préférer un middleware de page, ou return await navigateTo(...).

🟡 **Garde de permission sans `return`** (idem `new.vue:195`). Préférer un middleware de page, ou `return await navigateTo(...)`.
@@ -0,0 +229,4 @@
: t('logistique.weighingTickets.edit.titleFallback'),
)
useHead({ title: t('logistique.weighingTickets.edit.titleFallback') })
Author
Owner

🟢 Titre d'onglet non réactif. headerTitle (h1) est réactif au numéro, mais useHead reste figé sur le fallback. Reco (cosmétique) : useHead({ title: () => headerTitle.value }) pour afficher « Ticket de pesée 86-TP-0001 » dans l'onglet.

🟢 **Titre d'onglet non réactif.** `headerTitle` (h1) est réactif au numéro, mais `useHead` reste figé sur le fallback. **Reco (cosmétique)** : `useHead({ title: () => headerTitle.value })` pour afficher « Ticket de pesée 86-TP-0001 » dans l'onglet.
@@ -0,0 +366,4 @@
* « Imprimer » : ouvre le bon de pesée PDF servi par le back (Twig, ERP-192).
* Le front ne dessine AUCUN gabarit il ouvre seulement l'URL (RG-5.08).
*/
function printTicket(): void {
Author
Owner

🟢👍 Bonne version : ouverture synchrone dans le handler de clic → pas de blocage popup. À répliquer dans new.vue (ERP-189) où window.open est appelé après un await et risque d'être bloqué.

🟢👍 **Bonne version : ouverture synchrone dans le handler de clic** → pas de blocage popup. À répliquer dans `new.vue` (ERP-189) où `window.open` est appelé après un `await` et risque d'être bloqué.
Author
Owner

Consolidée dans la MR unique #144 (M5 — Tickets de pesée, ERP-188 → ERP-193). Fermeture de cette MR empilée.

Consolidée dans la MR unique #144 (M5 — Tickets de pesée, ERP-188 → ERP-193). Fermeture de cette MR empilée.
tristan closed this pull request 2026-06-24 13:40:12 +00:00

Pull request closed

Sign in to join this conversation.