feat : M5 — Tickets de pesée (ERP-188 → ERP-193) (#144)
Auto Tag Develop / tag (push) Successful in 8s
Auto Tag Develop / tag (push) Successful in 8s
MR unique regroupant tout le module M5 « Tickets de pesée » (remplace les MR empilées #140/#141/#142/#143).
## Périmètre
- **ERP-188** — Page liste des tickets de pesée + export XLSX (colonnes Fournisseur/Client/Autre + Statut).
- **ERP-189** — Écran « Ajouter » (4 champs en haut, 2 blocs de pesée, pesée bascule/manuelle, date+heure horodatée à la validation).
- **ERP-190** — Écran « Modifier » + bouton Imprimer.
- **ERP-191** — i18n + libellés + branchement site courant.
- **ERP-192** — Bon de pesée PDF généré côté back (template Twig → Dompdf), endpoint `GET /api/weighing_tickets/{id}/print.pdf`.
- **ERP-193** — Cycle de vie brouillon/validé (status DRAFT/VALIDATED, numéro attribué à la validation), DSD saisi conservé en pesée manuelle, retours métier design.
## Vérifications
- Back : tests Logistique + architecture verts, php-cs-fixer propre, migrations appliquées (dev + test).
- Front : suite Vitest complète verte, ESLint propre.
Base : `develop` — contient les 16 commits du M5 (rien d'autre).
Reviewed-on: #144
Co-authored-by: tristan <tristan@yuno.malio.fr>
Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #144.
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<template>
|
||||
<!-- Padding vertical piloté par la page (1er bloc sans pt, dernier sans pb). -->
|
||||
<div>
|
||||
<!-- En-tête du bloc : titre + boutons de pesée (bascule / manuelle). -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h2 class="text-[20px] font-semibold text-m-primary">{{ title }}</h2>
|
||||
<div class="flex items-center gap-8">
|
||||
<MalioButton
|
||||
variant="secondary"
|
||||
icon-name="mdi:weight"
|
||||
icon-position="left"
|
||||
:label="t('logistique.weighingTickets.form.weighbridge.auto')"
|
||||
:disabled="disabled"
|
||||
@click="$emit('request-auto')"
|
||||
/>
|
||||
<MalioButton
|
||||
variant="primary"
|
||||
icon-name="mdi:weight"
|
||||
icon-position="left"
|
||||
:label="t('logistique.weighingTickets.form.weighbridge.manual')"
|
||||
:disabled="disabled"
|
||||
@click="$emit('request-manual')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ligne : Date/heure, Poids, DSD. L'immatriculation et « Tout format »
|
||||
vivent désormais dans les 4 champs du haut, hors des blocs (ERP-193). -->
|
||||
<div class="mt-6 grid grid-cols-3 xl:grid-cols-4 gap-x-[44px] gap-y-4">
|
||||
<!-- Date/heure de la pesée — date du jour + heure courante par défaut
|
||||
(RG-5.07), ré-horodatée à la validation de la pesée. -->
|
||||
<MalioDateTime
|
||||
:model-value="block.date"
|
||||
:label="t('logistique.weighingTickets.form.date')"
|
||||
:required="true"
|
||||
:editable="true"
|
||||
:disabled="disabled"
|
||||
:error="errors.date"
|
||||
@update:model-value="(v: string | null) => emitBlock('date', v)"
|
||||
/>
|
||||
|
||||
<!-- Poids : champ texte verrouillé sur les chiffres, toujours désactivé
|
||||
(rempli par la pesée, jamais saisi à la main — RG-5.07). -->
|
||||
<MalioInputText
|
||||
:model-value="weightDisplay"
|
||||
:mask="NUMERIC_MASK"
|
||||
:label="t('logistique.weighingTickets.form.weight')"
|
||||
:required="true"
|
||||
:disabled="true"
|
||||
:error="errors.weight"
|
||||
/>
|
||||
|
||||
<!-- DSD : champ texte verrouillé sur les chiffres, toujours désactivé
|
||||
(rempli par la pesée — RG-5.04 / RG-5.07). -->
|
||||
<MalioInputText
|
||||
:model-value="dsdDisplay"
|
||||
:mask="NUMERIC_MASK"
|
||||
:label="t('logistique.weighingTickets.form.dsd')"
|
||||
:required="true"
|
||||
:disabled="true"
|
||||
:error="errors.dsd"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { WeighingBlockState } from '~/modules/logistique/composables/useWeighingTicketForm'
|
||||
import { NUMERIC_MASK } from '~/modules/logistique/utils/weighingMasks'
|
||||
|
||||
/**
|
||||
* Bloc de pesée (« Poids à vide » ou « Poids à plein ») de l'écran Ticket de pesée.
|
||||
* Champs Date/heure / Poids / DSD + boutons de pesée (bascule / manuelle). Depuis
|
||||
* ERP-193, la contrepartie, l'immatriculation et « Tout format » sont remontés dans
|
||||
* les 4 champs du haut de page (hors blocs). Masque numérique factorisé dans
|
||||
* `utils/weighingMasks`.
|
||||
*/
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
/** Identifiant technique du bloc (pour les `id` de champs uniques). */
|
||||
blockId: string
|
||||
title: string
|
||||
block: WeighingBlockState
|
||||
/** Erreurs 422 par champ (propertyPath → message). */
|
||||
errors?: Record<string, string>
|
||||
disabled?: boolean
|
||||
}>(), {
|
||||
errors: () => ({}),
|
||||
disabled: false,
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
'update:block': [field: keyof WeighingBlockState, value: unknown]
|
||||
'request-auto': []
|
||||
'request-manual': []
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
// Poids / DSD : champs texte → on présente l'entier sous forme de chaîne (vide
|
||||
// tant que la pesée n'a pas rempli la valeur).
|
||||
const weightDisplay = computed(() => (props.block.weight === null ? '' : String(props.block.weight)))
|
||||
const dsdDisplay = computed(() => (props.block.dsd === null ? '' : String(props.block.dsd)))
|
||||
|
||||
/** Remonte la mutation d'un champ du bloc au parent (état des pesées centralisé). */
|
||||
function emitBlock(field: keyof WeighingBlockState, value: unknown): void {
|
||||
emit('update:block', field, value)
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user