diff --git a/ajax_inscr_gestion.php b/ajax_inscr_gestion.php
index ef098dc..561ca1b 100644
--- a/ajax_inscr_gestion.php
+++ b/ajax_inscr_gestion.php
@@ -243,10 +243,9 @@ switch ($strAction) {
break;
}
- // L'eve_id fait foi cote serveur (jamais le client). Acces = acces a la fiche :
- // qui peut voir la transaction peut voir ses remboursements (decision produit).
+ // L'eve_id fait foi cote serveur (jamais le client). Droit granulaire transaction.
$intEveId = intval($recCommandes['eve_id']);
- if ($intEveId <= 0 || !fxInscrGestionCanAccess($intComId, $intEveId)) {
+ if ($intEveId <= 0 || !fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.transaction')) {
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
break;
}
diff --git a/css/style.css b/css/style.css
index 4ecccb2..748f10d 100644
--- a/css/style.css
+++ b/css/style.css
@@ -4137,12 +4137,31 @@ a.ms1-trad-link.btn-aide-trad{
flex-wrap:wrap;
gap:8px;
padding:0;
+ align-items:center;
}
.inscr-gestion-gestion-actions .btn{
margin:0;
}
+/* MSIN-4401 — Bouton + cadenas colle a droite (jamais orphelin a gauche). */
+.inscr-gestion-action-item{
+ display:inline-flex;
+ flex-wrap:wrap;
+ align-items:center;
+ gap:4px 6px;
+ max-width:100%;
+}
+
+.inscr-gestion-action-item .ms1-perm-inspect-badge,
+.inscr-gestion-action-item .ms1-perm-inspect-slot{
+ margin:0;
+}
+
+.inscr-gestion-action-item--inspect-only{
+ opacity:.92;
+}
+
/* Remboursement PayPal — fiche gestion promoteur (formulaire + panneau doc) */
.ms1-refund-wrap{
width:100%;
diff --git a/php/inc_fx_inscriptions_gestion.php b/php/inc_fx_inscriptions_gestion.php
index 894e388..d974399 100644
--- a/php/inc_fx_inscriptions_gestion.php
+++ b/php/inc_fx_inscriptions_gestion.php
@@ -100,7 +100,7 @@ function fxInscrGestionPermInspectEcho($strPermKey) {
return;
}
fxInscrGestionLoadEveAcces();
- echo ' ' . fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion');
+ echo fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion');
}
/** Badge + libelle pour un controle masque par les droits (mode inspecteur). */
@@ -112,7 +112,19 @@ function fxInscrGestionPermInspectEchoHidden($strPermKey, $strLabel) {
echo '';
echo fxEveAccesPermInspectBadge($strPermKey, 'inscr_gestion');
echo ' ' . fxInscrGestionEsc($strLabel) . '';
- echo ' ';
+ echo '';
+}
+
+/** MSIN-4401 — Enveloppe action + cadenas (toujours a droite du controle). */
+function fxInscrGestionActionItemOpen($strExtraClass = '') {
+ $strExtra = trim((string)$strExtraClass);
+ echo '';
}
function fxInscrGestionLoadEveAcces() {
@@ -2099,8 +2111,13 @@ function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq,
$blnCanRestore = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.restore');
// Droit de remboursement PayPal (etape remboursement) : controle l'affichage du bouton + panneau.
$blnCanRefund = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.refund');
+ // MSIN-4401 — granularite facture / transaction / renvoi (plus d'acces implicite sans droit).
+ $blnCanInvoice = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.invoice');
+ $blnCanTransaction = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.transaction');
+ $blnCanRenvoi = fxInscrGestionCanDo($intComId, $intRowEveId, 'inscriptions_gestion.renvoi');
$blnHasEditable = ($blnCanStatut || $blnCanBib || $blnCanRemis);
- $blnHasGestion = ($blnCanEdit || $blnCanCancel || $blnCanRestore || $blnCanRefund);
+ $blnHasGestion = ($blnCanEdit || $blnCanCancel || $blnCanRestore || $blnCanRefund
+ || $blnCanInvoice || $blnCanTransaction || $blnCanRenvoi);
$blnInspect = function_exists('fxAdminPermInspectModeActive') && fxAdminPermInspectModeActive();
$strBackUrl = fxInscrGestionResolveBackUrl($strBaseUrl, $intEveId, $arrReq);
@@ -2183,61 +2200,101 @@ function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq,
$blnForceSectionsOpen
);
echo '
';
- // Libelle devant le bouton facture (numero de commande) — invite a afficher la facture.
- echo '
' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_invoice')) . '';
- echo '
' . fxInscrGestionEsc($arrRow['no_commande']) . '';
- // Bascule "Afficher la transaction" (MSIN) : place entre le numero de transaction et Modifier.
- // Charge le resume de la commande en AJAX (action transaction_resume) dans le panneau ci-dessous.
- echo '
';
- if ($blnCanEdit) {
- echo '
';
- fxInscrGestionPermInspectEcho('inscriptions_gestion.edit');
+ // MSIN-4401 — Chaque action = wrap [controle][cadenas a droite] (evite badge orphelin a gauche).
+ if ($blnCanInvoice) {
+ fxInscrGestionActionItemOpen();
+ echo '
' . fxInscrGestionEsc(fxInscrGestionT('inscr_gestion_show_invoice')) . '';
+ echo '
' . fxInscrGestionEsc($arrRow['no_commande']) . '';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.invoice');
+ fxInscrGestionActionItemClose();
} elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
+ fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.invoice', fxInscrGestionT('inscr_gestion_show_invoice'));
+ fxInscrGestionActionItemClose();
+ }
+ if ($blnCanTransaction) {
+ fxInscrGestionActionItemOpen();
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.transaction');
+ fxInscrGestionActionItemClose();
+ } elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
+ fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.transaction', fxInscrGestionT('inscr_gestion_show_transaction'));
+ fxInscrGestionActionItemClose();
+ }
+ if ($blnCanEdit) {
+ // d-none sur le wrap entier (pas seulement le bouton) pour ne pas laisser le cadenas orphelin.
+ fxInscrGestionActionItemOpen(trim($strStyleEdit));
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.edit');
+ fxInscrGestionActionItemClose();
+ } elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.edit', fxInscrGestionT('inscr_gestion_modifier_participant'));
+ fxInscrGestionActionItemClose();
}
if ($blnCanRefund) {
- // Bouton bascule : ouvre/ferme le panneau de remboursement et declenche le chargement AJAX du formulaire.
- echo '
';
- fxInscrGestionPermInspectEcho('inscriptions_gestion.refund');
+ fxInscrGestionActionItemOpen();
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.refund');
+ fxInscrGestionActionItemClose();
} elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.refund', fxInscrGestionT('inscr_gestion_remboursement'));
+ fxInscrGestionActionItemClose();
}
if ($blnCanCancel) {
- echo '
';
- fxInscrGestionPermInspectEcho('inscriptions_gestion.cancel');
+ fxInscrGestionActionItemOpen(trim($strStyleCancel));
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.cancel');
+ fxInscrGestionActionItemClose();
} elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.cancel', fxInscrGestionT('btn_annulerinscriptions'));
+ fxInscrGestionActionItemClose();
}
if ($blnCanRestore) {
- echo '
';
- fxInscrGestionPermInspectEcho('inscriptions_gestion.restore');
+ fxInscrGestionActionItemOpen(trim($strStyleRetablir));
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.restore');
+ fxInscrGestionActionItemClose();
} elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.restore', fxInscrGestionT('btn_retablirinscriptions'));
+ fxInscrGestionActionItemClose();
+ }
+ if ($blnCanRenvoi) {
+ fxInscrGestionActionItemOpen();
+ echo '
';
+ fxInscrGestionPermInspectEcho('inscriptions_gestion.renvoi');
+ fxInscrGestionActionItemClose();
+ } elseif ($blnInspect) {
+ fxInscrGestionActionItemOpen('inscr-gestion-action-item--inspect-only');
+ fxInscrGestionPermInspectEchoHidden('inscriptions_gestion.renvoi', $strRenvoi);
+ fxInscrGestionActionItemClose();
}
- // RENVOI place en dernier (MSIN-4403) : retourne la confirmation au participant.
- echo '
';
echo '
';
if ($blnCanRefund) {
// Panneau de remboursement : vide au depart, rempli en AJAX a la 1ere ouverture (action=refund_form).
@@ -2249,9 +2306,11 @@ function fxInscrGestionRenderFiche($intEveId, $strLangue, $strBaseUrl, $arrReq,
}
// Panneau de transaction : vide au depart, rempli en AJAX a la 1ere ouverture (action=transaction_resume).
// Sous les boutons, repliable, accessible a tout moment (independant du remboursement).
+ if ($blnCanTransaction) {
echo '';
+ }
fxInscrGestionRenderFicheSectionEnd();
}
diff --git a/php/inc_settings.php b/php/inc_settings.php
index 76055a2..038fd55 100644
--- a/php/inc_settings.php
+++ b/php/inc_settings.php
@@ -7,7 +7,7 @@
* Constantes *
*
**************/
-define('_VERSION_CODE', '4.72.815');
+define('_VERSION_CODE', '4.72.816');
define('_DATE_CODE', '2026-07-13');
//MSIN-4290
define('QR_SECRET_KEY', 'ms1_qr_2026_cle_secrete_longue_et_fixe');
diff --git a/sql/MSIN-4401-inscr-gestion-actions-perm.sql b/sql/MSIN-4401-inscr-gestion-actions-perm.sql
new file mode 100644
index 0000000..6c14c0d
--- /dev/null
+++ b/sql/MSIN-4401-inscr-gestion-actions-perm.sql
@@ -0,0 +1,59 @@
+-- MSIN-4401 — Droits granulaires fiche Gestion : facture, transaction, renvoi
+-- Prérequis : MSIN-eve-acces-v2-phase2-multi-granular.sql (perms base)
+-- Idempotent. Safe pilote.
+--
+-- Note : kit propriétaire (role_grants_all) n'a PAS besoin de ces lignes.
+
+SET NAMES utf8mb4;
+
+INSERT INTO `inscriptions_eve_permissions`
+ (`perm_key`, `perm_group`, `perm_scope`, `perm_label_fr`, `perm_label_en`,
+ `perm_description_fr`, `perm_description_en`, `perm_phase`, `perm_actif`, `perm_tri`)
+VALUES
+ ('inscriptions_gestion.invoice', 'inscriptions', 'action',
+ 'Gestion inscription : facture', 'Registration mgmt: invoice',
+ 'Afficher la facture (numero de commande) depuis la fiche',
+ 'Show invoice (order number) from the sheet',
+ 2, 1, 138),
+ ('inscriptions_gestion.transaction', 'inscriptions', 'action',
+ 'Gestion inscription : transaction', 'Registration mgmt: transaction',
+ 'Afficher le resume de transaction depuis la fiche',
+ 'Show transaction summary from the sheet',
+ 2, 1, 139),
+ ('inscriptions_gestion.renvoi', 'inscriptions', 'action',
+ 'Gestion inscription : renvoyer confirmation', 'Registration mgmt: resend confirmation',
+ 'Renvoyer la confirmation au participant depuis la fiche',
+ 'Resend confirmation to the participant from the sheet',
+ 2, 1, 140)
+ON DUPLICATE KEY UPDATE
+ `perm_group` = VALUES(`perm_group`),
+ `perm_scope` = VALUES(`perm_scope`),
+ `perm_label_fr` = VALUES(`perm_label_fr`),
+ `perm_label_en` = VALUES(`perm_label_en`),
+ `perm_description_fr` = VALUES(`perm_description_fr`),
+ `perm_description_en` = VALUES(`perm_description_en`),
+ `perm_phase` = VALUES(`perm_phase`),
+ `perm_actif` = 1,
+ `perm_tri` = VALUES(`perm_tri`);
+
+/* Kits terrain : ops = les 3 ; readonly = lecture facture+transaction */
+INSERT INTO inscriptions_eve_role_permissions (role_id, perm_key)
+SELECT r.role_id, p.perm_key
+FROM inscriptions_eve_roles r
+CROSS JOIN (
+ SELECT 'inscriptions_gestion.invoice' AS perm_key
+ UNION ALL SELECT 'inscriptions_gestion.transaction'
+ UNION ALL SELECT 'inscriptions_gestion.renvoi'
+) p
+WHERE r.role_code = 'gestion_ops'
+ON DUPLICATE KEY UPDATE perm_key = VALUES(perm_key);
+
+INSERT INTO inscriptions_eve_role_permissions (role_id, perm_key)
+SELECT r.role_id, p.perm_key
+FROM inscriptions_eve_roles r
+CROSS JOIN (
+ SELECT 'inscriptions_gestion.invoice' AS perm_key
+ UNION ALL SELECT 'inscriptions_gestion.transaction'
+) p
+WHERE r.role_code IN ('gestion_readonly', 'gestion_statut')
+ON DUPLICATE KEY UPDATE perm_key = VALUES(perm_key);