Files
Starseed/tests/Module/Logistique/Api/WeighingTicketLifecycleTest.php
T
tristan 819ac5e608 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.
2026-06-24 15:13:12 +02:00

93 lines
3.4 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Tests\Module\Logistique\Api;
/**
* Cycle de vie brouillon -> valide du ticket de pesee (ERP-193, spec-back § 2.14).
*
* Couvre :
* - une pesee peut etre enregistree SANS contrepartie ni immatriculation : le POST
* cree un BROUILLON (status DRAFT, pas de numero) ;
* - la validation (PATCH /validate) exige les 3 champs du haut (type + champ
* contrepartie + immatriculation) ET les 2 pesees (groupe `finalize`) ;
* - une validation complete attribue le numero {siteCode}-TP-{NNNN} et passe le
* ticket en VALIDATED.
*
* @internal
*/
final class WeighingTicketLifecycleTest extends AbstractWeighingTicketApiTestCase
{
public function testWeighingOnlyCreatesDraftWithoutNumber(): void
{
$http = $this->authManageOnSite($this->siteByCode('86'));
// Pesee a vide seule : ni contrepartie, ni immatriculation.
$body = $this->postTicket($http, [
'emptyDate' => '2026-06-17T09:00:00+02:00',
'emptyWeight' => 7150,
'emptyMode' => 'AUTO',
])->toArray();
self::assertResponseStatusCodeSame(201);
self::assertSame('DRAFT', $body['status']);
self::assertArrayNotHasKey('number', $body, 'Un brouillon n\'a pas encore de numero (skip_null_values).');
self::assertSame(7150, $body['emptyWeight']);
}
public function testValidateRequiresCounterparty(): void
{
$http = $this->authManageOnSite($this->siteByCode('86'));
// Brouillon complet cote pesees + immatriculation, mais SANS contrepartie.
$id = (int) $this->postTicket($http, [
'immatriculation' => 'AB-123-CD',
'emptyDate' => '2026-06-17T09:00:00+02:00',
'emptyWeight' => 7150,
'emptyMode' => 'AUTO',
'fullDate' => '2026-06-17T09:12:00+02:00',
'fullWeight' => 14300,
'fullMode' => 'AUTO',
])->toArray()['id'];
$response = $this->validateTicket($http, $id);
self::assertResponseStatusCodeSame(422);
self::assertViolationOnPath($response, 'counterpartyType');
}
public function testValidateRequiresBothWeighings(): void
{
$http = $this->authManageOnSite($this->siteByCode('86'));
$client = $this->seedTestClient('Lifecycle');
// Brouillon avec contrepartie + immat + UNE seule pesee (a vide).
$id = (int) $this->postTicket($http, [
'counterpartyType' => 'CLIENT',
'client' => $this->clientIri($client),
'immatriculation' => 'AB-123-CD',
'emptyDate' => '2026-06-17T09:00:00+02:00',
'emptyWeight' => 7150,
'emptyMode' => 'AUTO',
])->toArray()['id'];
$response = $this->validateTicket($http, $id);
self::assertResponseStatusCodeSame(422);
self::assertViolationOnPath($response, 'fullWeight');
}
public function testValidateAssignsNumberAndStatus(): void
{
$http = $this->authManageOnSite($this->siteByCode('86'));
$client = $this->seedTestClient('LifecycleOk');
$validated = $this->createValidatedTicket($http, $this->validClientTicketPayload($client));
self::assertSame('VALIDATED', $validated['status']);
self::assertMatchesRegularExpression('/^86-TP-\d{4}$/', (string) $validated['number']);
self::assertSame(7150, $validated['netWeight']);
}
}