Files
ms1inscription-v5/ajax_inscr_gestion.php
stephan 8933753fe0 MSIN-4417 Update refund context handling in registration management
This commit refines the refund context handling by removing the unnecessary boolean parameter for Super Admin in the `fxRefundComputeContext` function, simplifying the logic. It ensures that refunds are consistently linked to the correct event context across various functions, enhancing authorization checks and calculations. The version code is incremented to 4.72.719 to reflect these changes.
2026-06-30 15:33:40 -04:00

239 lines
11 KiB
PHP

<?php
/**
* Actions AJAX reservees a la fiche de gestion des inscriptions (v2).
* N'altere pas ajax_promoteur.php ni enregistrer.php (legacy promoteur).
*/
session_start();
header('Content-Type: application/json; charset=utf-8');
// Filet de securite : transforme tout fatal (include manquant, fonction
// indefinie, parse error...) en reponse JSON exploitable au lieu d'un 500 muet.
$GLOBALS['__inscr_gestion_done'] = false;
register_shutdown_function(function () {
if (!empty($GLOBALS['__inscr_gestion_done'])) {
return;
}
$err = error_get_last();
$strDetail = ($err && in_array($err['type'], array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR), true))
? ($err['message'] . ' @ ' . $err['file'] . ':' . $err['line'])
: 'fatal inconnu';
error_log('[ajax_inscr_gestion] ' . $strDetail);
if (!headers_sent()) {
http_response_code(200);
}
echo json_encode(array('state' => 'error', 'message' => 'fatal', 'detail' => $strDetail));
});
require_once 'php/inc_fonctions.php';
require_once 'php/inc_fx_promoteur.php';
require_once 'php/inc_fx_inscriptions_gestion.php';
// Necessaire pour fxEveAccesResolveEveIdFromParId() appelee dans le case
// 'par_statut_course' : ce fichier n'est sinon charge que paresseusement
// (fxInscrGestionLoadEveAcces) APRES ce premier appel -> fatal undefined function.
require_once 'php/inc_fx_eve_acces.php';
$intComId = intval($_SESSION['com_id'] ?? 0);
$strAction = trim((string)($_REQUEST['a'] ?? ''));
$strLangue = trim((string)($_REQUEST['lang'] ?? 'fr'));
if ($strLangue === '') {
$strLangue = 'fr';
}
if ($intComId <= 0) {
$GLOBALS['__inscr_gestion_done'] = true;
echo json_encode(array('state' => 'error', 'message' => 'session'));
exit;
}
$tabRetour = array('state' => 'error');
try {
switch ($strAction) {
case 'par_statut_course':
$intParId = intval($_REQUEST['par_id'] ?? 0);
$strStatut = trim((string)($_REQUEST['par_statut_course'] ?? ''));
$intEveId = fxEveAccesResolveEveIdFromParId($intParId);
if ($intEveId <= 0 || !fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.statut_edit')) {
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
break;
}
$tabRetour = fxSetParStatutCourse($intParId, $strStatut, $strLangue);
break;
case 'refund_form':
// Charge le formulaire de remboursement mutualise pour la fiche de gestion (panneau repliable).
$strNoPanier = trim((string)($_REQUEST['no_panier'] ?? ''));
if ($strNoPanier === '') {
$tabRetour = array('state' => 'error', 'message' => 'no_panier_manquant');
break;
}
// Meme source que le Super Admin : la commande vient de inscriptions_panier_acheteurs.
$sqlCmd = "SELECT *, IF(a.com_id <> 0, (SELECT c.com_login FROM inscriptions_comptes c WHERE a.com_id = c.com_id), '') AS usager"
. " FROM inscriptions_panier_acheteurs a, inscriptions_panier_statuts s"
. " WHERE s.sta_id = a.sta_id AND a.no_panier = '" . $objDatabase->fxEscape($strNoPanier) . "'";
$recCommandes = $objDatabase->fxGetRow($sqlCmd);
if (!$recCommandes) {
$tabRetour = array('state' => 'error', 'message' => 'commande_introuvable');
break;
}
// L'eve_id de contexte = evenement de la fiche (participant), pas seulement celui du checkout.
require_once $_SERVER['DOCUMENT_ROOT'] . '/superadm/php/inc_fx_paypal.php';
$intEveContext = intval($_REQUEST['eve_id'] ?? 0);
if ($intEveContext <= 0) {
$intEveContext = intval($recCommandes['eve_id']);
}
if ($intEveContext <= 0 || !fxInscrGestionCanDo($intComId, $intEveContext, 'inscriptions_gestion.refund')) {
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
break;
}
if (!fxRefundPanierLinkedToEvent($recCommandes['no_panier'], $intEveContext, intval($recCommandes['eve_id']))) {
$tabRetour = array('state' => 'error', 'message' => 'panier_evenement_incompatible');
break;
}
$strRefundToken = fxRefundEnsureToken();
$arrRefundCtx = fxRefundComputeContext($recCommandes, $intEveContext);
// Auteur = promoteur connecte (alimente l'encart "Ajoute par" du formulaire).
$strAuteur = trim((string)($_SESSION['com_info']['com_prenom'] ?? '') . ' '
. (string)($_SESSION['com_info']['com_nom'] ?? ''));
// Markup seul (sans <script>, dernier param false) car injecte via innerHTML :
// le comportement (submit AJAX) est gere par le handler delegue dans inc_footer_scripts.php.
// NB : le resume de la transaction n'est plus inclus ici (MSIN) ; il est desormais
// accessible via le bouton "Afficher la transaction" de la barre Gestion (action transaction_resume).
$strDocAside = '';
if (function_exists('fxDocRenderRefundPromoteurAside')) {
global $vPage;
$memPage = $vPage ?? null;
$vPage = 'compte.php';
$strDocAside = fxDocRenderRefundPromoteurAside();
$vPage = $memPage;
}
$strForm = fxRenderRefundForm($recCommandes, $strRefundToken, $arrRefundCtx, $vDomaine, $strAuteur, null, false, $strDocAside);
$tabRetour = array('state' => 'ok', 'html' => $strForm);
break;
case 'bib_duplicate_check':
// Controle "dossard en double" dans l'evenement (avant enregistrement legacy).
// Ne modifie rien : renvoie qui porte deja ce dossard + la politique a appliquer.
$intParId = intval($_REQUEST['par_id'] ?? 0);
$strNoBib = trim((string)($_REQUEST['no_bib'] ?? ''));
$blnTeam = (trim((string)($_REQUEST['type'] ?? '')) === 'no_equipe');
$intEveId = fxEveAccesResolveEveIdFromParId($intParId);
if ($intEveId <= 0 || !fxInscrGestionCanDo($intComId, $intEveId, 'inscriptions_gestion.bib_edit')) {
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
break;
}
$strPolicy = fxInscrGestionBibDuplicatePolicy($intEveId);
if ($strNoBib === '') {
$tabRetour = array('state' => 'ok', 'duplicate' => false, 'policy' => $strPolicy, 'who' => array());
break;
}
// Commande courante a exclure du controle (un participant ne se "double" pas lui-meme).
$intPecOrig = intval($objDatabase->fxGetVar(
'SELECT e.pec_id_original FROM resultats_epreuves_commandees e, resultats_participants p'
. ' WHERE p.par_id = ' . $intParId . ' AND p.pec_id = e.pec_id_original LIMIT 1'
));
$arrDup = fxInscrGestionFindBibDuplicates($intEveId, $strNoBib, $intPecOrig, $blnTeam);
$arrWho = array();
foreach ($arrDup as $rowDup) {
$arrWho[] = array(
'name' => fxInscrGestionEsc(fxUnescape($rowDup['par_nom']) . ', ' . fxUnescape($rowDup['par_prenom'])),
'epreuve' => fxInscrGestionEsc(fxInscrGestionEpreuveLabel($rowDup['epr_id'], $strLangue)),
);
}
$tabRetour = array(
'state' => 'ok',
'duplicate' => count($arrWho) > 0,
'policy' => $strPolicy,
'who' => $arrWho,
);
break;
case 'transaction_resume':
// Resume de la transaction (meme rendu que facture.php cote promoteur) + detail des
// remboursements PayPal, affichable a tout moment via le panneau repliable de la barre Gestion.
$strNoPanier = trim((string)($_REQUEST['no_panier'] ?? ''));
if ($strNoPanier === '') {
$tabRetour = array('state' => 'error', 'message' => 'no_panier_manquant');
break;
}
// Commande complete (meme source que refund_form / Super Admin) : alimente fxRefundComputeContext.
$sqlCmd = "SELECT *, IF(a.com_id <> 0, (SELECT c.com_login FROM inscriptions_comptes c WHERE a.com_id = c.com_id), '') AS usager"
. " FROM inscriptions_panier_acheteurs a, inscriptions_panier_statuts s"
. " WHERE s.sta_id = a.sta_id AND a.no_panier = '" . $objDatabase->fxEscape($strNoPanier) . "'";
$recCommandes = $objDatabase->fxGetRow($sqlCmd);
if (!$recCommandes) {
$tabRetour = array('state' => 'error', 'message' => 'commande_introuvable');
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).
$intEveId = intval($recCommandes['eve_id']);
if ($intEveId <= 0 || !fxInscrGestionCanAccess($intComId, $intEveId)) {
$tabRetour = array('state' => 'error', 'message' => 'unauthorized');
break;
}
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/inc_fx_panier.php';
$strResume = fxShowPanier($strNoPanier, 0, 'web', 1, $strLangue);
// Sommaire des remboursements PayPal (vue compacte, pas la grande table Super Admin).
// N'apparait que s'il existe une capture PayPal exploitable ; sinon rien (les cas
// gratuits/non-PayPal sont deja couverts par la facture ci-dessus).
$strRefunds = '';
require_once $_SERVER['DOCUMENT_ROOT'] . '/superadm/php/inc_fx_paypal.php';
$arrRefundCtx = fxRefundComputeContext($recCommandes);
if (!empty($arrRefundCtx['ok'])) {
// renderPayPalRefundSummaryHtml() renvoie '' s'il n'y a aucun remboursement :
// dans ce cas on n'ajoute meme pas le separateur/encadre (rien a montrer).
$strSummary = renderPayPalRefundSummaryHtml($arrRefundCtx['paypaldetails']);
if (trim($strSummary) !== '') {
$strRefunds = '<div style="margin-top:14px;border-top:1px solid #cfe0ff;padding-top:12px;">'
. $strSummary
. '</div>';
}
}
// Conteneur encadre (sans bascule interne : le bouton de la barre Gestion fait office de toggle).
$strHtml =
'<div class="ms1-transaction-resume"'
. ' style="border:1px solid #2d6cdf;border-radius:10px;background:#f4f7fc;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.12);">'
. '<div style="padding:14px;">' . $strResume . $strRefunds . '</div>'
. '</div>';
$tabRetour = array('state' => 'ok', 'html' => $strHtml);
break;
default:
$tabRetour = array('state' => 'error', 'message' => 'invalid_action');
break;
}
} catch (\Throwable $e) {
error_log('[ajax_inscr_gestion] ' . $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine());
$tabRetour = array(
'state' => 'error',
'message' => 'exception',
'detail' => $e->getMessage() . ' @ ' . $e->getFile() . ':' . $e->getLine(),
);
}
$GLOBALS['__inscr_gestion_done'] = true;
echo json_encode($tabRetour);