0) { $course = db()->query("SELECT * FROM courses WHERE id = $courseIdForView")->fetch(); if ($course) { if (!$course['registration_open']) { $msg = current_lang() === 'ar' ? 'التسجيل في هذه الدورة/الدفعة مغلق حالياً.' : 'Registration for this course/batch is currently closed.'; die("

" . $msg . "

" . (current_lang() === 'ar' ? 'العودة' : 'Back') . "
"); } if ($course['max_students'] > 0) { $enrolled = db()->query("SELECT COUNT(*) FROM course_students WHERE course_id = $courseIdForView")->fetchColumn(); if ($enrolled >= $course['max_students']) { $msg = current_lang() === 'ar' ? 'لقد وصلت هذه الدورة إلى الحد الأقصى لعدد الطلاب.' : 'This course has reached its maximum capacity.'; die("

" . $msg . "

" . (current_lang() === 'ar' ? 'العودة' : 'Back') . "
"); } } } else { die('Course not found'); } } $errors = []; $form = [ 'full_name' => trim((string) ($_POST['full_name'] ?? '')), 'email' => trim((string) ($_POST['email'] ?? '')), 'password' => (string) ($_POST['password'] ?? ''), 'whatsapp' => trim((string) ($_POST['whatsapp'] ?? '')), 'preferred_language' => (string) ($_POST['preferred_language'] ?? current_lang()), 'billing_cycle' => $cycle, 'plan_key' => $plan['key'], 'wablas_opt_in' => isset($_POST['wablas_opt_in']) ? 1 : 0, ]; if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($form['full_name'] === '' || strlen($form['full_name']) < 2) { $errors[] = t('Please enter a valid full name.', 'يرجى إدخال اسم كامل صحيح.'); } if (empty($form['password']) || strlen($form['password']) < 6) { $errors[] = t('Password must be at least 6 characters.', 'يجب أن تتكون كلمة المرور من 6 أحرف على الأقل.'); } if (!filter_var($form['email'], FILTER_VALIDATE_EMAIL)) { $errors[] = t('Please enter a valid email address.', 'يرجى إدخال بريد إلكتروني صحيح.'); } if (!preg_match('/^[0-9+\-\s]{8,20}$/', $form['whatsapp'])) { $errors[] = t('Please enter a valid WhatsApp number.', 'يرجى إدخال رقم واتساب صحيح.'); } if (!in_array($form['preferred_language'], ['en', 'ar'], true)) { $errors[] = t('Please select a supported language.', 'يرجى اختيار لغة مدعومة.'); } if (!$errors) { $reference = 'THW-' . date('YmdHis') . '-' . random_int(100, 999); $id = create_subscription([ 'full_name' => $form['full_name'], 'email' => $form['email'], 'password' => password_hash($form['password'], PASSWORD_DEFAULT), 'whatsapp' => $form['whatsapp'], 'preferred_language' => $form['preferred_language'], 'plan_key' => $plan['key'], 'billing_cycle' => $form['billing_cycle'], 'payment_status' => 'active', // MVP: Mark active immediately 'payment_gateway' => 'Thawani', 'thawani_reference' => $reference, 'wablas_opt_in' => $form['wablas_opt_in'], ]); $courseId = (int) ($_GET['course_id'] ?? $_POST['course_id'] ?? 0); if ($courseId > 0) { try { $stmt = db()->prepare('INSERT IGNORE INTO course_students (course_id, student_id) VALUES (?, ?)'); $stmt->execute([$courseId, $id]); } catch (Exception $e) {} } // --- Thawani Integration --- $stmtThawani = db()->query("SELECT thawani_secret_key, thawani_publishable_key, thawani_mode FROM platform_profile WHERE id = 1"); $thawaniConfig = $stmtThawani->fetch(PDO::FETCH_ASSOC); $thawaniRedirect = null; if ($thawaniConfig && !empty($thawaniConfig['thawani_secret_key']) && !empty($thawaniConfig['thawani_publishable_key'])) { $mode = $thawaniConfig['thawani_mode'] ?? 'test'; $baseUrl = $mode === 'live' ? 'https://checkout.thawani.om' : 'https://uatcheckout.thawani.om'; $priceOMR = $course ? (float) $course['price'] : (float) ($cycle === 'yearly' ? $plan['price_yearly'] : $plan['price_monthly']); $priceBaisa = (int) ($priceOMR * 1000); $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://"; if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { $protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'] . "://"; } $host = $_SERVER['HTTP_HOST']; $scriptDir = str_replace('\\', '/', dirname($_SERVER['PHP_SELF'])); $appBaseUrl = $protocol . $host . $scriptDir; $successUrl = $appBaseUrl . '/subscription.php?id=' . $id . '&created=1'; $cancelUrl = $appBaseUrl . '/checkout.php?plan=' . $plan['key'] . '&cycle=' . $cycle; if ($courseId > 0) { $cancelUrl .= '&course_id=' . $courseId; } $productName = $course ? (current_lang() === 'ar' ? $course['name_ar'] : $course['name_en']) : plan_name($plan); $productName = mb_substr($productName, 0, 40); // Thawani character limit if (empty($productName)) $productName = 'Course Enrollment'; $payload = [ 'client_reference_id' => (string) $id, 'mode' => 'payment', 'products' => [ [ 'name' => $productName, 'quantity' => 1, 'unit_amount' => $priceBaisa ] ], 'success_url' => $successUrl, 'cancel_url' => $cancelUrl, 'metadata' => [ "Customer name" => $form["full_name"], "order id" => (string)$id, "contact number" => $form["whatsapp"], "email id" => $form["email"] ] ]; $ch = curl_init("$baseUrl/api/v1/checkout/session"); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, [ "thawani-api-key: {$thawaniConfig['thawani_secret_key']}", "Content-Type: application/json" ]); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); $response = curl_exec($ch); curl_close($ch); if ($response) { $resData = json_decode($response, true); if (isset($resData['success']) && $resData['success'] && isset($resData['data']['session_id'])) { $sessionId = $resData['data']['session_id']; db()->query("UPDATE student_subscriptions SET thawani_reference = " . db()->quote($sessionId) . " WHERE id = " . $id); $thawaniRedirect = "$baseUrl/pay/$sessionId?key={$thawaniConfig['thawani_publishable_key']}"; } else { error_log('Thawani Session Error: ' . $response); } } } if ($thawaniRedirect) { $_SESSION['subscription_id'] = $id; $_SESSION['student_email'] = $form['email']; header('Location: ' . $thawaniRedirect); exit; } else { db()->query("DELETE FROM student_subscriptions WHERE id = " . $id); if ($courseId > 0) { db()->query("DELETE FROM course_students WHERE course_id = " . $courseId . " AND student_id = " . $id); } $errors[] = t('Thawani payment gateway is not fully configured (missing keys) or the API call failed. Please update your API keys in the Teacher Panel > Integrations.', 'بوابة دفع ثواني غير مهيأة بالكامل (المفاتيح مفقودة) أو فشل الاتصال. يرجى تحديث مفاتيحك في لوحة المعلم > التكاملات.'); } } } render_head( t('Checkout', 'الدفع'), t('Capture a student subscription with bilingual preferences, WhatsApp opt-in, and a Thawani-ready payment reference.', 'التقط اشتراك طالب مع تفضيلات ثنائية اللغة وخيار واتساب ومرجع دفع جاهز لثواني.') ); render_nav('pricing.php'); ?>

>