b036c72615
Couverture des règles de gestion du M5 (tickets de pesée) et capture de la
réponse JSON réelle (DoD § 4.0.bis) avant les écrans front.
Tests unitaires (Processor/Normalizer/Callback, sans BDD ni HTTP) :
- NetWeightTest (RG-5.05) : net = plein − vide, null si pesée manquante, recalcul PATCH.
- CounterpartyValidationTest (RG-5.03) : présence par branche (propertyPath) + exclusivité.
- ImmatriculationNormalizationTest (RG-5.01/5.10) : masque XX-000-XX, « Tout format », 422.
Tests fonctionnels (API réelle) :
- WeighingTicketNumberingTest (RG-5.02/5.09) : format {siteCode}-TP-{NNNN}, séquence
par site, isolation inter-sites, immuabilité numéro/site au PATCH.
- WeighingTicketSerializationContractTest (DoD § 4.0.bis) : 4 pièges (client embarqué,
plateFreeFormat présent, number formaté, netWeight = full − empty) + dump JSON.
- WeighingTicketRBACMatrixTest (§ 5.2) : admin/bureau/usine OK, compta/commerciale 403,
anonyme 401.
DSD/stub/reading déjà couverts (ERP-184/185). spec-back.md § 4.0.bis : JSON réel collé.
122 lines
3.9 KiB
PHP
122 lines
3.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Module\Logistique\Api;
|
|
|
|
use App\Module\Core\Infrastructure\DataFixtures\RbacDemoFixtures;
|
|
use Symfony\Bundle\FrameworkBundle\Console\Application;
|
|
use Symfony\Component\Console\Input\ArrayInput;
|
|
use Symfony\Component\Console\Output\NullOutput;
|
|
|
|
/**
|
|
* Matrice RBAC du ticket de pesee par role metier (spec-back M5 § 5.2). Jumeau de
|
|
* {@see \App\Tests\Module\Transport\Api\CarrierRBACMatrixTest}.
|
|
*
|
|
* Matrice § 5.2 (V0.2) :
|
|
* - admin / bureau / usine : view + manage (200 lecture, 201 creation)
|
|
* - compta / commerciale : AUCUN acces (403 sur view ET manage)
|
|
* - anonyme : 401
|
|
*
|
|
* La creation (POST -> 201) suppose un site courant (numerotation + cloisonnement,
|
|
* § 2.3) : on le positionne pour chaque role autorise a ecrire.
|
|
*
|
|
* @internal
|
|
*/
|
|
final class WeighingTicketRBACMatrixTest extends AbstractWeighingTicketApiTestCase
|
|
{
|
|
private const string PWD = RbacDemoFixtures::DEMO_PASSWORD;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Seed idempotent des roles metier + matrice § 5.2 + comptes demo (meme
|
|
// chemin qu'en recette).
|
|
self::bootKernel();
|
|
$application = new Application(self::$kernel);
|
|
$application->setAutoExit(false);
|
|
$exit = $application->run(
|
|
new ArrayInput([
|
|
'command' => 'app:seed-rbac',
|
|
'--with-demo-users' => true,
|
|
'--password' => self::PWD,
|
|
]),
|
|
new NullOutput(),
|
|
);
|
|
self::assertSame(
|
|
0,
|
|
$exit,
|
|
'app:seed-rbac a echoue : les permissions logistique.weighing_tickets.* sont-elles synchronisees (app:sync-permissions) ?',
|
|
);
|
|
|
|
self::ensureKernelShutdown();
|
|
}
|
|
|
|
public function testAdminCanViewAndManage(): void
|
|
{
|
|
$this->assertCanViewAndManage('admin', 'admin');
|
|
}
|
|
|
|
public function testBureauCanViewAndManage(): void
|
|
{
|
|
$this->assertCanViewAndManage('bureau', self::PWD);
|
|
}
|
|
|
|
public function testUsineCanViewAndManage(): void
|
|
{
|
|
$this->assertCanViewAndManage('usine', self::PWD);
|
|
}
|
|
|
|
public function testComptaHasNoAccess(): void
|
|
{
|
|
$this->assertHasNoAccess('compta');
|
|
}
|
|
|
|
public function testCommercialeHasNoAccess(): void
|
|
{
|
|
$this->assertHasNoAccess('commerciale');
|
|
}
|
|
|
|
public function testAnonymousIsUnauthorized(): void
|
|
{
|
|
$client = self::createClient();
|
|
$client->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
|
self::assertResponseStatusCodeSame(401);
|
|
}
|
|
|
|
/**
|
|
* Role autorise : GET 200 (view) + POST 201 (manage). Le site courant est
|
|
* positionne avant le POST pour permettre la numerotation.
|
|
*/
|
|
private function assertCanViewAndManage(string $username, string $password): void
|
|
{
|
|
$site = $this->firstSite();
|
|
$this->setCurrentSite($username, $site);
|
|
|
|
$clientEntity = $this->seedTestClient('Rbac '.$username);
|
|
$http = $this->authenticatedClient($username, $password);
|
|
|
|
$http->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
|
self::assertResponseStatusCodeSame(200);
|
|
|
|
$this->postTicket($http, $this->validClientTicketPayload($clientEntity));
|
|
self::assertResponseStatusCodeSame(201);
|
|
}
|
|
|
|
/**
|
|
* Role sans acces : 403 en lecture (view absent) ET en ecriture (manage absent).
|
|
*/
|
|
private function assertHasNoAccess(string $username): void
|
|
{
|
|
$clientEntity = $this->seedTestClient('Rbac '.$username);
|
|
$http = $this->authenticatedClient($username, self::PWD);
|
|
|
|
$http->request('GET', '/api/weighing_tickets', ['headers' => ['Accept' => self::LD]]);
|
|
self::assertResponseStatusCodeSame(403);
|
|
|
|
$this->postTicket($http, $this->validClientTicketPayload($clientEntity));
|
|
self::assertResponseStatusCodeSame(403);
|
|
}
|
|
}
|