feat : cycle de vie brouillon/validé du ticket de pesée (ERP-193)
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.
This commit is contained in:
@@ -16,17 +16,17 @@ describe('useWeighingTicketForm', () => {
|
||||
})
|
||||
|
||||
// ── Omission des requis vides (compact) ──────────────────────────────────
|
||||
it('buildCreatePayload omet les clés null (requis vides absents, pas envoyés à null)', () => {
|
||||
it('buildDraftPayload : brouillon vierge → pas de champ requis ni de bloc non pesé', () => {
|
||||
const form = useWeighingTicketForm()
|
||||
// Formulaire vierge : counterpartyType / immatriculation non remplis.
|
||||
const payload = form.buildCreatePayload()
|
||||
// Absents (et non null) → le back applique NotBlank (message métier) plutôt
|
||||
// qu'une erreur de type opaque (« doit être de type string »).
|
||||
// Formulaire vierge : counterpartyType / immatriculation non remplis, aucune pesée.
|
||||
const payload = form.buildDraftPayload()
|
||||
// Absents (et non null) → le back laisse jouer les contraintes du groupe finalize.
|
||||
expect(payload).not.toHaveProperty('counterpartyType')
|
||||
expect(payload).not.toHaveProperty('immatriculation')
|
||||
// Bloc non pesé → ni poids ni date (on n'envoie pas une date de pesée sans pesée).
|
||||
expect(payload).not.toHaveProperty('emptyWeight')
|
||||
// Les non-null restent : date/heure courante + booléen Tout format.
|
||||
expect(payload.emptyDate).toBe('2026-06-22T08:30:00')
|
||||
expect(payload).not.toHaveProperty('emptyDate')
|
||||
// Seul le booléen « Tout format » reste.
|
||||
expect(payload.plateFreeFormat).toBe(false)
|
||||
})
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('useWeighingTicketForm', () => {
|
||||
expect(form.supplierIri.value).toBeNull()
|
||||
expect(form.otherLabel.value).toBeNull()
|
||||
|
||||
const payload = form.buildCreatePayload()
|
||||
const payload = form.buildDraftPayload()
|
||||
expect(payload.counterpartyType).toBe('CLIENT')
|
||||
expect(payload.client).toBe('/api/clients/629')
|
||||
expect(payload).not.toHaveProperty('supplier')
|
||||
@@ -68,7 +68,7 @@ describe('useWeighingTicketForm', () => {
|
||||
|
||||
expect(form.counterpartyField.value).toBe('supplier')
|
||||
expect(form.clientIri.value).toBeNull()
|
||||
expect(form.buildCreatePayload().supplier).toBe('/api/suppliers/7')
|
||||
expect(form.buildDraftPayload().supplier).toBe('/api/suppliers/7')
|
||||
})
|
||||
|
||||
it('AUTRE : ne conserve que le libellé libre', () => {
|
||||
@@ -79,7 +79,7 @@ describe('useWeighingTicketForm', () => {
|
||||
|
||||
expect(form.counterpartyField.value).toBe('other')
|
||||
expect(form.clientIri.value).toBeNull()
|
||||
expect(form.buildCreatePayload().otherLabel).toBe('Reprise interne')
|
||||
expect(form.buildDraftPayload().otherLabel).toBe('Reprise interne')
|
||||
})
|
||||
|
||||
// ── Immatriculation / « Tout format » partagés entre blocs (RG-5.01) ──────
|
||||
@@ -88,11 +88,11 @@ describe('useWeighingTicketForm', () => {
|
||||
form.immatriculation.value = 'AB-123-CD'
|
||||
form.plateFreeFormat.value = true
|
||||
|
||||
// Les 2 payloads (création + finalisation) reflètent la même valeur.
|
||||
expect(form.buildCreatePayload().immatriculation).toBe('AB-123-CD')
|
||||
expect(form.buildCreatePayload().plateFreeFormat).toBe(true)
|
||||
expect(form.buildFullPayload().immatriculation).toBe('AB-123-CD')
|
||||
expect(form.buildFullPayload().plateFreeFormat).toBe(true)
|
||||
// Les 2 payloads (brouillon + validation) reflètent la même valeur.
|
||||
expect(form.buildDraftPayload().immatriculation).toBe('AB-123-CD')
|
||||
expect(form.buildDraftPayload().plateFreeFormat).toBe(true)
|
||||
expect(form.buildValidatePayload().immatriculation).toBe('AB-123-CD')
|
||||
expect(form.buildValidatePayload().plateFreeFormat).toBe(true)
|
||||
})
|
||||
|
||||
// ── Application d'une lecture de pesée ────────────────────────────────────
|
||||
@@ -113,23 +113,28 @@ describe('useWeighingTicketForm', () => {
|
||||
expect(form.full.manualNumber).toBe('PAP-555')
|
||||
})
|
||||
|
||||
it('buildCreatePayload porte la pesée à vide, buildFullPayload la pesée à plein', () => {
|
||||
it('buildDraftPayload porte les pesées effectuées ; buildValidatePayload les 4 champs du haut', () => {
|
||||
const form = useWeighingTicketForm()
|
||||
form.setCounterpartyType('CLIENT')
|
||||
form.clientIri.value = '/api/clients/1'
|
||||
form.immatriculation.value = 'AB-123-CD'
|
||||
form.applyReading(form.empty, { weight: 7150, dsd: 1, mode: 'AUTO' })
|
||||
form.applyReading(form.full, { weight: 14300, dsd: 2, mode: 'AUTO' })
|
||||
|
||||
const create = form.buildCreatePayload()
|
||||
expect(create.emptyWeight).toBe(7150)
|
||||
expect(create.emptyDsd).toBe(1)
|
||||
expect(create.emptyMode).toBe('AUTO')
|
||||
expect(create).not.toHaveProperty('fullWeight')
|
||||
// Le brouillon porte LES DEUX pesées effectuées.
|
||||
const draft = form.buildDraftPayload()
|
||||
expect(draft.emptyWeight).toBe(7150)
|
||||
expect(draft.emptyMode).toBe('AUTO')
|
||||
expect(draft.fullWeight).toBe(14300)
|
||||
expect(draft.fullMode).toBe('AUTO')
|
||||
|
||||
const full = form.buildFullPayload()
|
||||
expect(full.fullWeight).toBe(14300)
|
||||
expect(full.fullDsd).toBe(2)
|
||||
expect(full.fullMode).toBe('AUTO')
|
||||
// La validation ne porte que les 4 champs du haut (pesées déjà persistées).
|
||||
const validate = form.buildValidatePayload()
|
||||
expect(validate.counterpartyType).toBe('CLIENT')
|
||||
expect(validate.client).toBe('/api/clients/1')
|
||||
expect(validate.immatriculation).toBe('AB-123-CD')
|
||||
expect(validate).not.toHaveProperty('emptyWeight')
|
||||
expect(validate).not.toHaveProperty('fullWeight')
|
||||
})
|
||||
|
||||
// ── Pré-remplissage (écran Modification, ERP-190) ─────────────────────────
|
||||
@@ -174,10 +179,11 @@ describe('useWeighingTicketForm', () => {
|
||||
expect(form.empty.weight).toBeNull()
|
||||
})
|
||||
|
||||
it('buildUpdatePayload fusionne contrepartie + véhicule + les 2 pesées', () => {
|
||||
it('buildDraftPayload après hydrate porte contrepartie + véhicule + les 2 pesées', () => {
|
||||
const form = useWeighingTicketForm()
|
||||
form.hydrate({
|
||||
id: 9,
|
||||
status: 'VALIDATED',
|
||||
counterpartyType: 'CLIENT',
|
||||
client: { '@id': '/api/clients/629' },
|
||||
immatriculation: 'AB-123-CD',
|
||||
@@ -185,7 +191,9 @@ describe('useWeighingTicketForm', () => {
|
||||
fullWeight: 14300, fullDsd: 2, fullMode: 'AUTO',
|
||||
})
|
||||
|
||||
const payload = form.buildUpdatePayload()
|
||||
expect(form.status.value).toBe('VALIDATED')
|
||||
|
||||
const payload = form.buildDraftPayload()
|
||||
expect(payload.counterpartyType).toBe('CLIENT')
|
||||
expect(payload.client).toBe('/api/clients/629')
|
||||
expect(payload.emptyWeight).toBe(7150)
|
||||
|
||||
Reference in New Issue
Block a user