setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); $praticien_id = (int)($_SESSION['reference_id'] ?? 0); if ($praticien_id <= 0) { header('Location: /public/login.php'); exit; } // ---- Helper: colonne existe ? (évite de casser selon schéma) ---- function colExists(PDO $pdo, string $table, string $col): bool { static $cache = []; $k = $table.'.'.$col; if (array_key_exists($k, $cache)) return $cache[$k]; $st = $pdo->prepare(" SELECT 1 FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND COLUMN_NAME = ? LIMIT 1 "); $st->execute([$table, $col]); $cache[$k] = (bool)$st->fetchColumn(); return $cache[$k]; } try { // 🔎 Récupération du billing le plus récent "utile" // On vise l’entrée la plus récente; si elle est déjà canceled, ça reste idempotent. $stmt = $pdo->prepare(" SELECT id, billing_mode, provider, provider_subscription_id, current_period_end, status FROM billing_subscriptions WHERE praticien_id = ? ORDER BY id DESC LIMIT 1 "); $stmt->execute([$praticien_id]); $billing = $stmt->fetch(PDO::FETCH_ASSOC) ?: null; // ========================== // 1) Appel Stripe (si auto) // ========================== if ($billing) { $isAutoStripe = ( (string)($billing['billing_mode'] ?? '') === 'auto' && (string)($billing['provider'] ?? '') === 'stripe' && !empty($billing['provider_subscription_id']) ); if ($isAutoStripe) { require_once __DIR__ . '/../../plata/lib/stripe_client.php'; // $stripe try { // Résiliation à fin de période $stripe->subscriptions->update( (string)$billing['provider_subscription_id'], ['cancel_at_period_end' => true] ); } catch (Throwable $e) { // On ne bloque pas la résiliation locale si Stripe échoue @file_put_contents( '/tmp/stripe_resiliation.log', '['.date('c').'] '.$e->getMessage()."\n", FILE_APPEND ); } } } // ========================== // 2) Mise à jour locale (TX) // ========================== $pdo->beginTransaction(); // 2.1) billing_subscriptions -> canceled (+ flags si colonnes existent) if ($billing && !empty($billing['id'])) { $sets = ["status = 'canceled'"]; $vals = []; if (colExists($pdo, 'billing_subscriptions', 'cancel_at_period_end')) { $sets[] = "cancel_at_period_end = 1"; } if (colExists($pdo, 'billing_subscriptions', 'canceled_at')) { $sets[] = "canceled_at = NOW()"; } $sql = "UPDATE billing_subscriptions SET ".implode(', ', $sets)." WHERE id = ?"; $vals[] = (int)$billing['id']; $pdo->prepare($sql)->execute($vals); } // 2.2) praticien -> abonnement_id NULL (NE PAS toucher date_expiration) if (colExists($pdo, 'praticien', 'abonnement_id')) { $pdo->prepare("UPDATE praticien SET abonnement_id = NULL WHERE id = ?") ->execute([$praticien_id]); } $pdo->commit(); } catch (Throwable $e) { if ($pdo->inTransaction()) $pdo->rollBack(); @file_put_contents( '/tmp/resiliation_error.log', '['.date('c').'] '.$e->getMessage()."\n", FILE_APPEND ); } // Redirection finale header('Location: /public/praticien/resiliation.php?ok=1'); exit;