Refactor refund process by removing the inc_tableau_remboursement.php file and updating the refund handling logic in ajax_refund.php and inc_fx_paypal.php. The changes include enhanced authorization checks for promoters, improved session management for refund tokens, and better integration of user information in refund records. This update streamlines the refund workflow and enhances security and maintainability.
This commit is contained in:
@ -716,14 +716,6 @@ require_once("inc_header.php");
|
|||||||
$footer_script = true;
|
$footer_script = true;
|
||||||
include("inc_tableau_rabais.php");
|
include("inc_tableau_rabais.php");
|
||||||
break;
|
break;
|
||||||
// MSIN-3679
|
|
||||||
case 'compte_inc_tableau_remboursement':
|
|
||||||
$blnBoutonRetour = false;
|
|
||||||
$footer_script = true;
|
|
||||||
|
|
||||||
include("inc_tableau_remboursement.php");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'compte_inc_tableau_inscriptions':
|
case 'compte_inc_tableau_inscriptions':
|
||||||
$blnBoutonRetour = false;
|
$blnBoutonRetour = false;
|
||||||
$footer_script = true;
|
$footer_script = true;
|
||||||
|
|||||||
@ -1255,6 +1255,50 @@ if ($strLangue == 'fr') {
|
|||||||
// ===== Remboursement PayPal (fiche de gestion) =====
|
// ===== Remboursement PayPal (fiche de gestion) =====
|
||||||
// Bouton bascule : ouvre/ferme le panneau repliable et charge le formulaire en AJAX a la 1ere ouverture.
|
// Bouton bascule : ouvre/ferme le panneau repliable et charge le formulaire en AJAX a la 1ere ouverture.
|
||||||
(function () {
|
(function () {
|
||||||
|
// Texte explicatif affiche apres un remboursement reussi (oriente vers le bouton Annuler).
|
||||||
|
var refundCancelHint = <?php echo json_encode($strLangue === 'en'
|
||||||
|
? 'Your transaction has been refunded. If you also want to cancel it in the registration system, click "Cancel".'
|
||||||
|
: "Votre transaction a été remboursée. Si vous voulez aussi l'annuler dans le système d'inscription, cliquez sur « Annuler ».", JSON_UNESCAPED_UNICODE); ?>;
|
||||||
|
|
||||||
|
// Comportement post-succes : recalcul du restant, re-emission du jeton, mise en evidence du bouton Annuler.
|
||||||
|
function onRefundSuccess(form, json) {
|
||||||
|
var $form = $(form);
|
||||||
|
|
||||||
|
// 1) Re-emission du jeton anti double-clic (le serveur l'a consomme) -> autorise un 2e remboursement partiel.
|
||||||
|
if (json && json.new_token) {
|
||||||
|
$form.find('input[name="refund_token"]').val(json.new_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Recalcul du montant restant (remboursement partiel) cote client : ancien max - montant rembourse.
|
||||||
|
var amount = parseFloat($form.find('input[name="refund_amount"]').val()) || 0;
|
||||||
|
var $max = $('#pp_ref_max');
|
||||||
|
var oldMax = parseFloat(String($max.text() || '0').replace(',', '.')) || 0;
|
||||||
|
var newMax = Math.max(0, oldMax - amount);
|
||||||
|
$max.text(newMax.toFixed(2));
|
||||||
|
|
||||||
|
var $amountInput = $('#pp_ref_amount');
|
||||||
|
$amountInput.attr('max', newMax.toFixed(2));
|
||||||
|
if (newMax <= 0) {
|
||||||
|
// Plus rien a rembourser : on verrouille le formulaire (le solde affiche reste a 0).
|
||||||
|
$amountInput.val('0.00').prop('disabled', true);
|
||||||
|
$form.find('button[type="submit"]').prop('disabled', true);
|
||||||
|
} else {
|
||||||
|
$amountInput.val(newMax.toFixed(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3) Mise en evidence du bouton Annuler + texte explicatif (uniquement si le bouton est visible).
|
||||||
|
var $cancelBtn = $('#annuler_fiche');
|
||||||
|
if ($cancelBtn.length && $cancelBtn.is(':visible')) {
|
||||||
|
$cancelBtn.removeClass('btn-secondary').addClass('btn-danger')
|
||||||
|
.css('box-shadow', '0 0 0 3px rgba(220,53,69,.35)');
|
||||||
|
if (!$('#inscr-mobile-refund-cancel-hint').length) {
|
||||||
|
$('<div id="inscr-mobile-refund-cancel-hint" style="margin-top:8px;padding:10px;border:1px solid #ffe1a6;background:#fff8e6;border-radius:8px;font-size:13px;"></div>')
|
||||||
|
.text(refundCancelHint)
|
||||||
|
.insertAfter($('#inscr-mobile-refund-panel'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$(document).on('click', '.btn_refund_toggle', function () {
|
$(document).on('click', '.btn_refund_toggle', function () {
|
||||||
var $btn = $(this);
|
var $btn = $(this);
|
||||||
var $panel = $($btn.attr('data-refund-target') || '#inscr-mobile-refund-panel');
|
var $panel = $($btn.attr('data-refund-target') || '#inscr-mobile-refund-panel');
|
||||||
@ -1316,6 +1360,7 @@ if ($strLangue == 'fr') {
|
|||||||
.then(function (json) {
|
.then(function (json) {
|
||||||
if (json && json.success) {
|
if (json && json.success) {
|
||||||
showMsg('\u2705 ' + (json.message || 'Remboursement effectue.'), true);
|
showMsg('\u2705 ' + (json.message || 'Remboursement effectue.'), true);
|
||||||
|
onRefundSuccess(form, json);
|
||||||
} else {
|
} else {
|
||||||
showMsg('\u26a0\ufe0f ' + ((json && json.message) || 'Erreur remboursement.'), false);
|
showMsg('\u26a0\ufe0f ' + ((json && json.message) || 'Erreur remboursement.'), false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,294 +0,0 @@
|
|||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
// MSIN-3679 nouveau tableau
|
|
||||||
|
|
||||||
ini_set('display_errors', true);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
require_once $_SERVER["DOCUMENT_ROOT"] . "/superadm/php/inc_fx_paypal.php";
|
|
||||||
global $objDatabase, $vDomaine, $strLangue;
|
|
||||||
$intEveId = 0;
|
|
||||||
$blnDon = false;
|
|
||||||
|
|
||||||
if ($strLangue == 'fr') {
|
|
||||||
$strPage = '/compte';
|
|
||||||
} else {
|
|
||||||
$strPage = '/account';
|
|
||||||
}
|
|
||||||
if($strLangue == 'fr')
|
|
||||||
$strCode = 'compte/';
|
|
||||||
else
|
|
||||||
$strCode = 'account/';
|
|
||||||
|
|
||||||
$strBibCode = $strCode;
|
|
||||||
|
|
||||||
if (!empty($_GET['code'])) {
|
|
||||||
$code = $_GET['code'];
|
|
||||||
} else {
|
|
||||||
$code = 'bib_assignment';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_GET['promoteur_eve_id'])) {
|
|
||||||
$intEveId = base64_decode(urldecode($_GET['promoteur_eve_id']));
|
|
||||||
$arrEvenement = fxGetEvenementsId($intEveId);
|
|
||||||
//$tabEvenement['general'] = $arrEvenement;
|
|
||||||
}
|
|
||||||
// a metre dimamique
|
|
||||||
|
|
||||||
$sqlCommandes = "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 = '" . $_GET['no_panier']."'";
|
|
||||||
$recCommandes = $objDatabase->fxGetRow($sqlCommandes);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
|
||||||
<a class="btn btn-primary rounded-pill" id="link_back" href="<?php echo $vDomaine . $strPage . "/inc_tableau_inscriptions?promoteur_eve_id=" . urlencode(base64_encode($intEveId)); ?>">
|
|
||||||
<i class="fa fa-chevron-left mr-2" aria-hidden="true"></i>
|
|
||||||
<?php afficheTexte('promoteur_back'); ?>
|
|
||||||
</a>
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<h3><img src="images_blue/ico_commandes_big.png" alt="">Détails de la commande</h3>
|
|
||||||
<?php echo fxShowPanier($recCommandes['no_panier'], 0, 'web', 1, 'fr'); ?>
|
|
||||||
<p> </p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
|
|
||||||
<h3><img src="images_blue/ico_commandes_big.png" alt="">PAYPAL</h3>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
// ************************************************ rembourcement
|
|
||||||
|
|
||||||
/****************************************************
|
|
||||||
* Page: remboursement.php
|
|
||||||
* Rôle : affiche le formulaire de remboursement + prépare
|
|
||||||
* les variables serveur nécessaires au front (AJAX).
|
|
||||||
****************************************************/
|
|
||||||
|
|
||||||
// Démarrer la session
|
|
||||||
//session_start();
|
|
||||||
|
|
||||||
// Jeton anti double clic / re-soumission
|
|
||||||
if (empty($_SESSION['refund_token'])) {
|
|
||||||
$_SESSION['refund_token'] = bin2hex(random_bytes(16));
|
|
||||||
}
|
|
||||||
$refundToken = $_SESSION['refund_token'];
|
|
||||||
|
|
||||||
// Récupération des infos commande (présentes dans ton contexte)
|
|
||||||
$CAPTURE_ID = $recCommandes["TransactionID"] ?? null;
|
|
||||||
|
|
||||||
if (!isset($CAPTURE_ID) || !is_string($CAPTURE_ID) || $CAPTURE_ID === '') {
|
|
||||||
//echo '<div style="background:#feecec;border:1px solid #f2b8b5;padding:10px;border-radius:8px;">
|
|
||||||
// ⚠️ CAPTURE_ID non fourni côté serveur.
|
|
||||||
// </div>';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Charger ta classe PayPal
|
|
||||||
require_once $_SERVER["DOCUMENT_ROOT"] . "/paypal_advanced/PaypalCheckout.class.php";
|
|
||||||
$paypal = new PayPalCheckout(); // adapte si nécessaire
|
|
||||||
|
|
||||||
// Préparation
|
|
||||||
$errors = [];
|
|
||||||
$successMsg = null;
|
|
||||||
|
|
||||||
// Devise par défaut si jamais les détails PayPal n’en donnent pas
|
|
||||||
$currencyUI = 'CAD';
|
|
||||||
|
|
||||||
// ====== Calculs initiaux côté serveur ======
|
|
||||||
|
|
||||||
// Solde dispo promoteur (ton helper existant)
|
|
||||||
$solde_dispo_ms1 = statut_payement($recCommandes["eve_id"]);
|
|
||||||
|
|
||||||
// Récupérer les détails PayPal de la capture
|
|
||||||
$paypaldetails = $paypal->paypaldetails($CAPTURE_ID);
|
|
||||||
|
|
||||||
// Harmoniser avec tes remboursements locaux si besoin
|
|
||||||
$paypaldetails = reconcileRefundsWithLocal($paypaldetails);
|
|
||||||
|
|
||||||
// Déterminer le max remboursable PayPal
|
|
||||||
$max_remboursement_paypal = 0.0;
|
|
||||||
|
|
||||||
// Cas habituel : clé remaining
|
|
||||||
if (!empty($paypaldetails['refunds']['totals']['remaining'])) {
|
|
||||||
$max_remboursement_paypal = (float)$paypaldetails['refunds']['totals']['remaining'];
|
|
||||||
}
|
|
||||||
// Fallback : montant total capturé (certains retours utilisent "details", d’autres ont eu une coquille "delails")
|
|
||||||
elseif (!empty($paypaldetails['details']['amount']['value'])) {
|
|
||||||
$max_remboursement_paypal = (float)$paypaldetails['details']['amount']['value'];
|
|
||||||
} elseif (!empty($paypaldetails['delails']['amount']['value'])) { // compat. si ton code historique renvoie "delails"
|
|
||||||
$max_remboursement_paypal = (float)$paypaldetails['delails']['amount']['value'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Déterminer la devise d’affichage si fournie par PayPal
|
|
||||||
if (!empty($paypaldetails['refunds']['totals']['currency'])) {
|
|
||||||
$currencyUI = (string)$paypaldetails['refunds']['totals']['currency'];
|
|
||||||
} elseif (!empty($paypaldetails['details']['amount']['currency_code'])) {
|
|
||||||
$currencyUI = (string)$paypaldetails['details']['amount']['currency_code'];
|
|
||||||
} elseif (!empty($paypaldetails['delails']['amount']['currency_code'])) {
|
|
||||||
$currencyUI = (string)$paypaldetails['delails']['amount']['currency_code'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Frais MS1 (selon ta structure)
|
|
||||||
$frais_ms1 = (float)($recCommandes['fra_total'] ?? 0);
|
|
||||||
|
|
||||||
// Max remboursable à l’écran (ta logique actuelle)
|
|
||||||
$maxUI = $max_remboursement_paypal - $frais_ms1;
|
|
||||||
|
|
||||||
// maxblock = limite stricte d’input côté front, selon ton choix actuel
|
|
||||||
if ($max_remboursement_paypal < $solde_dispo_ms1) {
|
|
||||||
$maxblock = $max_remboursement_paypal;
|
|
||||||
} else {
|
|
||||||
$maxblock = 0;
|
|
||||||
$maxUI = 0;
|
|
||||||
}
|
|
||||||
// ******************** variable info
|
|
||||||
//print_rsl($recCommandes);
|
|
||||||
echosl( "no_commande : ".$recCommandes["no_commande"]);
|
|
||||||
// echosl( "rem_ajoute_par : ".$_SESSION["usa_info"]["com_prenom"]." ".$_SESSION["usa_info"]["com_nom"]);
|
|
||||||
echosl( "eve_id : ".$recCommandes["eve_id"]) ;
|
|
||||||
echosl( "Montant remboursable : " . number_format($max_remboursement_paypal, 2) . " " . ($result['refunds']['totals']['currency'] ?? $result['delails']['amount']['currency_code'] ?? ''));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
echo("solde dispo ms1 :");
|
|
||||||
echosl($solde_dispo_ms1);
|
|
||||||
echo("frais ms1 :");
|
|
||||||
$frais_ms1=$recCommandes['fra_total'];
|
|
||||||
echosl($frais_ms1);
|
|
||||||
echo("max Remboursement :");
|
|
||||||
|
|
||||||
// $maxUI le max Remboursement
|
|
||||||
$maxUI=$max_remboursement_paypal-$frais_ms1;
|
|
||||||
echosl($maxUI);
|
|
||||||
?>
|
|
||||||
<!doctype html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>Remboursement PayPal</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
||||||
</head>
|
|
||||||
<body style="font-family:system-ui,Arial,Helvetica;">
|
|
||||||
|
|
||||||
<div style="max-width:560px;border:1px solid #ddd;border-radius:10px;padding:14px;">
|
|
||||||
<div style="font-weight:700;font-size:16px;margin-bottom:8px;">Remboursement PayPal (Checkout)</div>
|
|
||||||
|
|
||||||
<!-- Zone messages AJAX -->
|
|
||||||
<div id="refund-msg" style="margin-bottom:10px;display:none;padding:10px;border-radius:8px;"></div>
|
|
||||||
|
|
||||||
<?php if ($maxUI > 0): ?>
|
|
||||||
<div style="background:#f9fbff;border:1px solid #dbe7ff;padding:10px;border-radius:8px;margin-bottom:10px;">
|
|
||||||
<div><strong>Capture:</strong> <?= h($CAPTURE_ID) ?></div>
|
|
||||||
<div><strong>Max remboursable (affiché):</strong> <span id="pp_ref_max"><?= h(money2($maxUI)) ?></span> <?= h($currencyUI) ?></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<form id="refund-form" method="post" style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
|
|
||||||
<input type="hidden" name="refund_token" value="<?= h($refundToken) ?>">
|
|
||||||
<input type="hidden" name="capture_id" value="<?= h($CAPTURE_ID) ?>">
|
|
||||||
<input type="hidden" name="currency" value="<?= h($currencyUI) ?>">
|
|
||||||
<input type="hidden" name="eve_id" value="<?= h($recCommandes["eve_id"]) ?>">
|
|
||||||
<input type="hidden" name="no_commande" value="<?= h($recCommandes["no_commande"]) ?>">
|
|
||||||
|
|
||||||
<div style="grid-column:1/2;">
|
|
||||||
<label style="display:block;font-size:12px;color:#333;margin-bottom:4px;">
|
|
||||||
Montant à rembourser (<?= h($currencyUI) ?>)
|
|
||||||
</label>
|
|
||||||
<input id="pp_ref_amount" type="number" name="refund_amount" step="0.01" min="0.01"
|
|
||||||
max="<?= h(money2($maxblock)) ?>"
|
|
||||||
value="<?= h(money2($maxUI)) ?>"
|
|
||||||
style="width:100%;padding:8px;border:1px solid #ccc;border-radius:8px;">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="grid-column:2/3;">
|
|
||||||
<label style="display:block;font-size:12px;color:#333;margin-bottom:4px;">Note (optionnelle)</label>
|
|
||||||
<input type="text" name="refund_note" placeholder="Raison du remboursement"
|
|
||||||
style="width:100%;padding:8px;border:1px solid #ccc;border-radius:8px;">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style="grid-column:1/3;text-align:right;margin-top:6px;">
|
|
||||||
<button type="submit"
|
|
||||||
style="padding:10px 14px;border:1px solid #2d6cdf;border-radius:8px;background:#2d6cdf;color:#fff;cursor:pointer;">
|
|
||||||
Rembourser
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<?php else: ?>
|
|
||||||
<div style="background:#fff8e6;border:1px solid #ffe1a6;padding:10px;border-radius:8px;">
|
|
||||||
Aucun montant remboursable pour cette capture.
|
|
||||||
</div>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Petit helper visuel
|
|
||||||
function showMsg(text, ok) {
|
|
||||||
const box = document.getElementById('refund-msg');
|
|
||||||
box.style.display = 'block';
|
|
||||||
box.style.background = ok ? '#e9f8ef' : '#feecec';
|
|
||||||
box.style.border = ok ? '1px solid #b8e3c5' : '1px solid #f2b8b5';
|
|
||||||
box.innerText = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
document.getElementById('refund-form')?.addEventListener('submit', async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
showMsg('⏳ Traitement en cours...', false);
|
|
||||||
|
|
||||||
const data = new FormData(e.target);
|
|
||||||
const res = await fetch( '<?php echo $vDomaine; ?>/superadm/ajax_refund.php', { method: 'POST', body: data });
|
|
||||||
|
|
||||||
|
|
||||||
// Défensif
|
|
||||||
if (!res.ok) {
|
|
||||||
showMsg('⚠️ Erreur réseau pendant le remboursement.', false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let json;
|
|
||||||
try { json = await res.json(); } catch (_) {
|
|
||||||
showMsg('⚠️ Réponse invalide du serveur.', false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.success) {
|
|
||||||
showMsg('✅ ' + (json.message || 'Remboursement effectué.'), true);
|
|
||||||
|
|
||||||
// 👉 Ici, tu peux déclencher des actions UI :
|
|
||||||
// - recharger une grille des remboursements
|
|
||||||
// - rafraîchir un solde
|
|
||||||
// - etc.
|
|
||||||
// refreshTableRemboursements();
|
|
||||||
} else {
|
|
||||||
showMsg('⚠️ ' + (json.message || 'Erreur remboursement.'), false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<h3><img src="images_blue/ico_commandes_big.png" alt="">Détails PAYPAL</h3>
|
|
||||||
|
|
||||||
<?php
|
|
||||||
|
|
||||||
|
|
||||||
// $sortie=paypaldetails($recCommandes["TransactionID"]);
|
|
||||||
|
|
||||||
|
|
||||||
echo(renderPayPalCaptureHtml($paypaldetails));
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
?>
|
|
||||||
<a class="btn btn-primary rounded-pill" id="link_back" href="<?php echo $vDomaine . $strPage . "/inc_tableau_promoteur?promoteur_eve_id=" . urlencode(base64_encode($intEveId)); ?>">
|
|
||||||
<i class="fa fa-chevron-left mr-2" aria-hidden="true"></i>
|
|
||||||
<?php afficheTexte('promoteur_back'); ?>
|
|
||||||
</a>
|
|
||||||
<?php
|
|
||||||
@ -21,6 +21,31 @@ if (session_status() !== PHP_SESSION_ACTIVE) {
|
|||||||
|
|
||||||
$response = ['success' => false, 'message' => 'Erreur inconnue'];
|
$response = ['success' => false, 'message' => 'Erreur inconnue'];
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// AUTHENTIFICATION : qui appelle cet endpoint ?
|
||||||
|
// - Super Admin (usa_info) -> bypass total (comportement historique, aucun droit granulaire)
|
||||||
|
// - Promoteur (com_info) -> soumis a inscriptions_gestion.refund + ownership de l'evenement
|
||||||
|
// - Personne -> refus
|
||||||
|
// L'autorisation fine du promoteur (ownership) se fait plus bas, une fois la commande relue en DB.
|
||||||
|
// ============================================================
|
||||||
|
$blnIsSuperAdmin = !empty($_SESSION['usa_info']);
|
||||||
|
$intComId = intval($_SESSION['com_info']['com_id'] ?? 0);
|
||||||
|
|
||||||
|
if ($blnIsSuperAdmin) {
|
||||||
|
$strAjoutePar = trim(($_SESSION['usa_info']['com_prenom'] ?? '') . ' ' . ($_SESSION['usa_info']['com_nom'] ?? ''));
|
||||||
|
} else {
|
||||||
|
$strAjoutePar = trim(($_SESSION['com_info']['com_prenom'] ?? '') . ' ' . ($_SESSION['com_info']['com_nom'] ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$blnIsSuperAdmin && $intComId <= 0) {
|
||||||
|
// Aucun acteur authentifie : on refuse avant tout traitement.
|
||||||
|
echo json_encode(
|
||||||
|
['success' => false, 'message' => 'Session expirée ou accès refusé.'],
|
||||||
|
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
|
||||||
|
);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// --- 1) Anti double clic / re-soumission ---
|
// --- 1) Anti double clic / re-soumission ---
|
||||||
$postedToken = $_POST['refund_token'] ?? '';
|
$postedToken = $_POST['refund_token'] ?? '';
|
||||||
@ -50,6 +75,33 @@ try {
|
|||||||
throw new Exception("Le montant doit être > 0.");
|
throw new Exception("Le montant doit être > 0.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- 2bis) AUTORISATION du promoteur (le Super Admin est en bypass) ---
|
||||||
|
if (!$blnIsSuperAdmin) {
|
||||||
|
// L'evenement de reference est RELU en DB depuis la commande (jamais fourni par le client).
|
||||||
|
require_once $_SERVER["DOCUMENT_ROOT"] . "/php/inc_fx_eve_acces.php";
|
||||||
|
|
||||||
|
$sqlOwner = "SELECT eve_id, TransactionID FROM inscriptions_panier_acheteurs"
|
||||||
|
. " WHERE no_commande = '" . $db->fxEscape($no_commande) . "' LIMIT 1";
|
||||||
|
$rowOwner = $db->fxGetRow($sqlOwner);
|
||||||
|
if (!$rowOwner) {
|
||||||
|
throw new Exception("Commande introuvable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Defense : la capture postee doit correspondre a la commande reclamee.
|
||||||
|
if ((string)$rowOwner['TransactionID'] !== (string)$CAPTURE_ID) {
|
||||||
|
throw new Exception("Incohérence commande / capture.");
|
||||||
|
}
|
||||||
|
|
||||||
|
$intEveIdReel = intval($rowOwner['eve_id']);
|
||||||
|
// inscriptions_gestion.refund implique aussi l'acces du promoteur a cet evenement.
|
||||||
|
if ($intEveIdReel <= 0 || !fxEveAccesHasPermission($intComId, $intEveIdReel, 'inscriptions_gestion.refund')) {
|
||||||
|
throw new Exception("Accès refusé à cet événement.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// On force l'eve_id reel pour la suite (journalisation du remboursement).
|
||||||
|
$eve_id = $intEveIdReel;
|
||||||
|
}
|
||||||
|
|
||||||
// --- 3) Appel PayPal ---
|
// --- 3) Appel PayPal ---
|
||||||
require_once $_SERVER["DOCUMENT_ROOT"] .'/paypal_advanced/PaypalCheckout.class.php';
|
require_once $_SERVER["DOCUMENT_ROOT"] .'/paypal_advanced/PaypalCheckout.class.php';
|
||||||
$paypal = new PayPalCheckout(); // adapte si nécessaire
|
$paypal = new PayPalCheckout(); // adapte si nécessaire
|
||||||
@ -66,7 +118,7 @@ try {
|
|||||||
// --- 4) Post-traitement maison (tables locales, logs, etc.) ---
|
// --- 4) Post-traitement maison (tables locales, logs, etc.) ---
|
||||||
// Implémente ici ta logique (mise à jour des tables, etc.)
|
// Implémente ici ta logique (mise à jour des tables, etc.)
|
||||||
try {
|
try {
|
||||||
postRefundSuccess($CAPTURE_ID, $amount, $currencyUI, $note, $res,$eve_id,$no_commande);
|
postRefundSuccess($CAPTURE_ID, $amount, $currencyUI, $note, $res, $eve_id, $no_commande, $strAjoutePar);
|
||||||
} catch (Throwable $inner) {
|
} catch (Throwable $inner) {
|
||||||
// On n’échoue pas le remboursement pour autant : on renvoie un warning dans le message si tu veux.
|
// On n’échoue pas le remboursement pour autant : on renvoie un warning dans le message si tu veux.
|
||||||
// $response['post_warning'] = $inner->getMessage();
|
// $response['post_warning'] = $inner->getMessage();
|
||||||
@ -97,6 +149,12 @@ try {
|
|||||||
$response['message'] = "Erreur remboursement: " . $msg;
|
$response['message'] = "Erreur remboursement: " . $msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Re-emission d'un jeton anti double-clic frais (l'ancien a ete consomme plus haut).
|
||||||
|
// Permet un 2e remboursement partiel ou une nouvelle tentative apres erreur, sans recharger.
|
||||||
|
// Le front (handler delegue) met a jour le champ cache refund_token avec cette valeur.
|
||||||
|
$_SESSION['refund_token'] = bin2hex(random_bytes(16));
|
||||||
|
$response['new_token'] = $_SESSION['refund_token'];
|
||||||
|
|
||||||
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
echo json_encode($response, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -778,11 +778,23 @@ $out['refunds'] = $sectionOut;
|
|||||||
|
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
function postRefundSuccess(string $capture_id, float $amount, string $currency, string $note, array $paypalResponse = [],int $eve_id,string $no_commande): void
|
function postRefundSuccess(string $capture_id, float $amount, string $currency, string $note, array $paypalResponse = [],int $eve_id = 0,string $no_commande = '', string $strAjoutePar = ''): void
|
||||||
{
|
{
|
||||||
$sqlInsert = "INSERT INTO remboursements SET no_commande='".$no_commande."', paypal_capture='".$capture_id."',rem_date=now(),rem_date_pour=now(),rem_details = '" . $note . "',eve_id=".$eve_id.",mr_id=6,tr_id=2,rem_montant=".$amount.",rem_ajoute_par='".$_SESSION["usa_info"]["com_prenom"]." ".$_SESSION["usa_info"]["com_nom"]."'" ;
|
// Auteur du remboursement : fourni par l'appelant (Super Admin OU promoteur).
|
||||||
$qryInsert = $GLOBALS['db']->fxQuery($sqlInsert); // $stmt->execute([$capture_id, json_encode($paypalResponse, JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES)]);
|
// Fallback legacy sur la session Super Admin si l'appelant ne fournit rien.
|
||||||
|
if ($strAjoutePar === '') {
|
||||||
|
$strAjoutePar = trim(($_SESSION["usa_info"]["com_prenom"] ?? '') . ' ' . ($_SESSION["usa_info"]["com_nom"] ?? ''));
|
||||||
|
}
|
||||||
|
|
||||||
|
$db = $GLOBALS['db'];
|
||||||
|
// Echappement defensif (les valeurs peuvent venir d'un POST promoteur).
|
||||||
|
$strNoCmdSql = $db->fxEscape($no_commande);
|
||||||
|
$strCaptureSql = $db->fxEscape($capture_id);
|
||||||
|
$strNoteSql = $db->fxEscape($note);
|
||||||
|
$strAuteurSql = $db->fxEscape($strAjoutePar);
|
||||||
|
|
||||||
|
$sqlInsert = "INSERT INTO remboursements SET no_commande='".$strNoCmdSql."', paypal_capture='".$strCaptureSql."',rem_date=now(),rem_date_pour=now(),rem_details = '".$strNoteSql."',eve_id=".intval($eve_id).",mr_id=6,tr_id=2,rem_montant=".(float)$amount.",rem_ajoute_par='".$strAuteurSql."'" ;
|
||||||
|
$db->fxQuery($sqlInsert);
|
||||||
}
|
}
|
||||||
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
|
function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user