feat(back) : bon de pesée PDF via template Twig (ERP-192)
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.
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Module\Logistique\Api;
|
||||
|
||||
/**
|
||||
* Tests fonctionnels de l'impression du bon de pesee PDF (M5, spec-back § 2.12 /
|
||||
* § 4.6 — RG-5.08, ERP-192) : operation `GET /api/weighing_tickets/{id}/print.pdf`.
|
||||
*
|
||||
* Couvre la verification du ticket :
|
||||
* - 200 + PDF non vide (Content-Type application/pdf, disposition inline,
|
||||
* signature %PDF) pour un ticket existant et visible ;
|
||||
* - 403 sans la permission `logistique.weighing_tickets.view` ;
|
||||
* - 404 pour un ticket inexistant.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class WeighingTicketPrintApiTest extends AbstractWeighingTicketApiTestCase
|
||||
{
|
||||
public function testPrintReturnsNonEmptyPdfForExistingTicket(): void
|
||||
{
|
||||
$site = $this->firstSite();
|
||||
$http = $this->authManageOnSite($site);
|
||||
$client = $this->seedTestClient('Print');
|
||||
|
||||
$created = $this->postTicket($http, $this->validClientTicketPayload($client));
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
$ticketId = $created->toArray()['id'];
|
||||
|
||||
$response = $http->request('GET', sprintf('/api/weighing_tickets/%d/print.pdf', $ticketId));
|
||||
|
||||
self::assertResponseIsSuccessful();
|
||||
|
||||
$headers = $response->getHeaders(false);
|
||||
self::assertStringContainsString('application/pdf', $headers['content-type'][0] ?? '');
|
||||
self::assertStringContainsString('inline', $headers['content-disposition'][0] ?? '');
|
||||
|
||||
// PDF non vide + signature de fichier PDF (« %PDF-1.x »).
|
||||
$binary = $response->getContent(false);
|
||||
self::assertNotSame('', $binary, 'Le PDF du bon de pesée ne doit pas être vide.');
|
||||
self::assertStringStartsWith('%PDF', $binary);
|
||||
}
|
||||
|
||||
public function testForbiddenWithoutViewPermission(): void
|
||||
{
|
||||
// On seede un ticket reel via un user habilite, puis on tente l'impression
|
||||
// avec un user depourvu de `logistique.weighing_tickets.view`.
|
||||
$site = $this->firstSite();
|
||||
$manager = $this->authManageOnSite($site);
|
||||
$client = $this->seedTestClient('Forbidden');
|
||||
|
||||
$created = $this->postTicket($manager, $this->validClientTicketPayload($client));
|
||||
self::assertResponseStatusCodeSame(201);
|
||||
$ticketId = $created->toArray()['id'];
|
||||
|
||||
$creds = $this->createUserWithPermission('core.users.view');
|
||||
$intrus = $this->authenticatedClient($creds['username'], $creds['password']);
|
||||
|
||||
$intrus->request('GET', sprintf('/api/weighing_tickets/%d/print.pdf', $ticketId));
|
||||
|
||||
self::assertResponseStatusCodeSame(403);
|
||||
}
|
||||
|
||||
public function testNotFoundForUnknownTicket(): void
|
||||
{
|
||||
$http = $this->authManageOnSite($this->firstSite());
|
||||
|
||||
$http->request('GET', '/api/weighing_tickets/99999999/print.pdf');
|
||||
|
||||
self::assertResponseStatusCodeSame(404);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user