feat(transport) : permissions carriers + sidebar (ERP-153)
Socle RBAC du module Transport (M4 § 5) :
- TransportModule::permissions() declare transport.carriers.{view,manage,archive}
- RbacSeeder::MATRIX (§ 5.2) : Bureau (view+manage), Commerciale (view) ;
Compta/Usine aucun acces ; archive admin seul
- config/sidebar.php : section Transport + item /carriers (gate transport.carriers.view)
- i18n sidebar.transport.{section,carriers}
- 3 miroirs RBAC alignes : sidebar.php, personas.ts (user-full), SeedE2ECommand.php
- TransportModuleTest : garde-fou sur le jeu de permissions
This commit is contained in:
@@ -78,6 +78,23 @@ return [
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
// Section "Transport" (M4, ERP-153) : pole logistique, porte le repertoire
|
||||||
|
// transporteurs. L'item est gate par `transport.carriers.view` ; la section
|
||||||
|
// disparait automatiquement (SidebarProvider) si le module `transport` est
|
||||||
|
// desactive ou si l'user n'a pas la permission (Compta / Usine).
|
||||||
|
[
|
||||||
|
'label' => 'sidebar.transport.section',
|
||||||
|
'icon' => 'mdi:truck-outline',
|
||||||
|
'items' => [
|
||||||
|
[
|
||||||
|
'label' => 'sidebar.transport.carriers',
|
||||||
|
'to' => '/carriers',
|
||||||
|
'icon' => 'mdi:truck-outline',
|
||||||
|
'module' => 'transport',
|
||||||
|
'permission' => 'transport.carriers.view',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
// Section "Administration" : regroupe toutes les pages de configuration
|
// Section "Administration" : regroupe toutes les pages de configuration
|
||||||
// applicative (RBAC, users, sites, audit log).
|
// applicative (RBAC, users, sites, audit log).
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -35,6 +35,10 @@
|
|||||||
"section": "Technique",
|
"section": "Technique",
|
||||||
"providers": "Répertoire prestataires"
|
"providers": "Répertoire prestataires"
|
||||||
},
|
},
|
||||||
|
"transport": {
|
||||||
|
"section": "Transport",
|
||||||
|
"carriers": "Répertoire transporteurs"
|
||||||
|
},
|
||||||
"core": {
|
"core": {
|
||||||
"roles": "Gestion des rôles",
|
"roles": "Gestion des rôles",
|
||||||
"users": "Utilisateurs",
|
"users": "Utilisateurs",
|
||||||
|
|||||||
@@ -95,6 +95,13 @@ export const personas: Record<PersonaKey, Persona> = {
|
|||||||
'technique.providers.accounting.view',
|
'technique.providers.accounting.view',
|
||||||
'technique.providers.accounting.manage',
|
'technique.providers.accounting.manage',
|
||||||
'technique.providers.archive',
|
'technique.providers.archive',
|
||||||
|
// Transport — Repertoire transporteurs (M4, ERP-153). Meme logique :
|
||||||
|
// mappe sur le persona "tout", pas de nouveau persona (regle ABSOLUE
|
||||||
|
// n°7). transport.carriers.view n'ajoute pas de lien dans la section
|
||||||
|
// Administration, donc expectedAdminLinks reste inchange.
|
||||||
|
'transport.carriers.view',
|
||||||
|
'transport.carriers.manage',
|
||||||
|
'transport.carriers.archive',
|
||||||
],
|
],
|
||||||
expectedAdminLinks: ['users', 'roles', 'sites', 'categories', 'audit-log'],
|
expectedAdminLinks: ['users', 'roles', 'sites', 'categories', 'audit-log'],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ final class RbacSeeder
|
|||||||
* Definition unique des 4 roles + matrice § 2.7. La cle est le code du role,
|
* Definition unique des 4 roles + matrice § 2.7. La cle est le code du role,
|
||||||
* `label` le libelle FR affichable, `permissions` la liste des codes RBAC a
|
* `label` le libelle FR affichable, `permissions` la liste des codes RBAC a
|
||||||
* attacher (admin n'apparait pas car il bypass tout via isAdmin ;
|
* attacher (admin n'apparait pas car il bypass tout via isAdmin ;
|
||||||
* `commercial.clients.archive`, `commercial.suppliers.archive` et
|
* `commercial.clients.archive`, `commercial.suppliers.archive`,
|
||||||
* `technique.providers.archive` ne sont attaches a aucun role metier —
|
* `technique.providers.archive` et `transport.carriers.archive` ne sont
|
||||||
* admin seul).
|
* attaches a aucun role metier — admin seul).
|
||||||
*
|
*
|
||||||
* Cloisonnement par site des prestataires (M3 § 2.13) : la permission
|
* Cloisonnement par site des prestataires (M3 § 2.13) : la permission
|
||||||
* `sites.bypass_scope` est attribuee par defaut a Bureau / Compta /
|
* `sites.bypass_scope` est attribuee par defaut a Bureau / Compta /
|
||||||
@@ -77,6 +77,9 @@ final class RbacSeeder
|
|||||||
// Prestataires (M3 § 2.9, ERP-138) : view + manage (hors Comptabilite).
|
// Prestataires (M3 § 2.9, ERP-138) : view + manage (hors Comptabilite).
|
||||||
'technique.providers.view',
|
'technique.providers.view',
|
||||||
'technique.providers.manage',
|
'technique.providers.manage',
|
||||||
|
// Transporteurs (M4 § 5.2, ERP-153) : view + manage (PAS archive -> admin seul).
|
||||||
|
'transport.carriers.view',
|
||||||
|
'transport.carriers.manage',
|
||||||
// Visibilite multi-site des prestataires (M3 § 2.13) : voit tous les sites.
|
// Visibilite multi-site des prestataires (M3 § 2.13) : voit tous les sites.
|
||||||
'sites.bypass_scope',
|
'sites.bypass_scope',
|
||||||
// Lecture des referentiels transverses pour les selects client (ERP-102).
|
// Lecture des referentiels transverses pour les selects client (ERP-102).
|
||||||
@@ -120,6 +123,9 @@ final class RbacSeeder
|
|||||||
// (onglet Comptabilite masque/filtre pour la Commerciale).
|
// (onglet Comptabilite masque/filtre pour la Commerciale).
|
||||||
'technique.providers.view',
|
'technique.providers.view',
|
||||||
'technique.providers.manage',
|
'technique.providers.manage',
|
||||||
|
// Transporteurs (M4 § 5.2, ERP-153) : view seul (consultation « Tout »,
|
||||||
|
// ni manage ni archive pour la Commerciale).
|
||||||
|
'transport.carriers.view',
|
||||||
// Visibilite multi-site des prestataires (M3 § 2.13) : voit tous les sites.
|
// Visibilite multi-site des prestataires (M3 § 2.13) : voit tous les sites.
|
||||||
'sites.bypass_scope',
|
'sites.bypass_scope',
|
||||||
// Lecture des referentiels transverses pour les selects client (ERP-102).
|
// Lecture des referentiels transverses pour les selects client (ERP-102).
|
||||||
|
|||||||
@@ -212,6 +212,11 @@ final class SeedE2ECommand extends Command
|
|||||||
'technique.providers.accounting.view',
|
'technique.providers.accounting.view',
|
||||||
'technique.providers.accounting.manage',
|
'technique.providers.accounting.manage',
|
||||||
'technique.providers.archive',
|
'technique.providers.archive',
|
||||||
|
// Transport — Repertoire transporteurs (M4, ERP-153). Meme
|
||||||
|
// logique : mappe sur le persona "tout". Miroir de personas.ts.
|
||||||
|
'transport.carriers.view',
|
||||||
|
'transport.carriers.manage',
|
||||||
|
'transport.carriers.archive',
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -13,17 +13,22 @@ final class TransportModule
|
|||||||
/**
|
/**
|
||||||
* Liste declarative des permissions RBAC exposees par le module Transport.
|
* Liste declarative des permissions RBAC exposees par le module Transport.
|
||||||
*
|
*
|
||||||
* Vide a ce stade : le module ne porte que des referentiels externes
|
* Socle du repertoire transporteurs (M4 § 5.1, ERP-153) :
|
||||||
* synchronises par commandes console (codes IDTF - ERP-149, transporteurs
|
* - `view` : consultation de la liste / fiche transporteur ;
|
||||||
* QUALIMAT - ERP-39), sans ecran ni action protegee. Les permissions seront
|
* - `manage` : creation / modification (hors archivage) ;
|
||||||
* ajoutees quand une page de consultation sera exposee.
|
* - `archive` : archivage / restauration (admin seul, cf. matrice § 5.2).
|
||||||
*
|
*
|
||||||
* Consommee par `app:sync-permissions` (un tableau vide est valide).
|
* Consommee par `app:sync-permissions`. Matrice role -> permissions dans
|
||||||
|
* `RbacSeeder::MATRIX` (§ 5.2).
|
||||||
*
|
*
|
||||||
* @return array<int, array{code: string, label: string}>
|
* @return array<int, array{code: string, label: string}>
|
||||||
*/
|
*/
|
||||||
public static function permissions(): array
|
public static function permissions(): array
|
||||||
{
|
{
|
||||||
return [];
|
return [
|
||||||
|
['code' => 'transport.carriers.view', 'label' => 'Voir les transporteurs'],
|
||||||
|
['code' => 'transport.carriers.manage', 'label' => 'Créer / modifier les transporteurs'],
|
||||||
|
['code' => 'transport.carriers.archive', 'label' => 'Archiver / restaurer un transporteur'],
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Tests\Module\Transport;
|
||||||
|
|
||||||
|
use App\Module\Transport\TransportModule;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests structurels du module Transport (M4) : identite et contrat
|
||||||
|
* `permissions()` (socle RBAC, ERP-153).
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final class TransportModuleTest extends TestCase
|
||||||
|
{
|
||||||
|
public function testModuleIdentity(): void
|
||||||
|
{
|
||||||
|
self::assertSame('transport', TransportModule::ID);
|
||||||
|
self::assertSame('Transport', TransportModule::LABEL);
|
||||||
|
self::assertFalse(TransportModule::REQUIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPermissionsSetContainsExactlyThreeCodes(): void
|
||||||
|
{
|
||||||
|
// Garde-fou : le jeu de permissions du module est fige par ce test. Si
|
||||||
|
// quelqu'un ajoute / retire une permission sans ajuster la spec (§ 5.1)
|
||||||
|
// ni la matrice RBAC (§ 5.2), le test casse explicitement.
|
||||||
|
$codes = array_column(TransportModule::permissions(), 'code');
|
||||||
|
sort($codes);
|
||||||
|
|
||||||
|
self::assertSame(
|
||||||
|
[
|
||||||
|
'transport.carriers.archive',
|
||||||
|
'transport.carriers.manage',
|
||||||
|
'transport.carriers.view',
|
||||||
|
],
|
||||||
|
$codes,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEveryPermissionCodeIsPrefixedByModuleId(): void
|
||||||
|
{
|
||||||
|
// Convention de nommage `module.resource[.sub].action` : le prefixe doit
|
||||||
|
// correspondre exactement a l'ID du module (verifie aussi par
|
||||||
|
// app:sync-permissions).
|
||||||
|
foreach (TransportModule::permissions() as $permission) {
|
||||||
|
self::assertStringStartsWith(
|
||||||
|
TransportModule::ID.'.',
|
||||||
|
$permission['code'],
|
||||||
|
'Chaque code de permission doit etre prefixe par l\'ID du module.',
|
||||||
|
);
|
||||||
|
self::assertNotSame('', $permission['label'], 'Chaque permission doit porter un label.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user