Files
HotLunches/paypal_checkout_create_order.php
T
2026-10-19 15:22:52 -07:00

146 lines
6.2 KiB
PHP

<?php
/**
* PayPal Checkout - Create Order Endpoint
*
* Called by the PayPal JS SDK when user clicks the PayPal button.
* Creates a PayPal order with amount from session/database (server-side validation).
*
* Returns JSON: { "id": "PAYPAL_ORDER_ID" } or { "error": "message" }
*/
header('Content-Type: application/json');
// Start session if not already started
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
// Include database and required files
// Adjust this path if your db.php is elsewhere
if (file_exists(__DIR__ . '/db.php')) {
require_once __DIR__ . '/db.php';
}
require_once __DIR__ . '/paypal_checkout_api.php';
try {
// =========================================================================
// IMPORTANT: Get amount from SERVER-SIDE (database/session), NOT from client
// This prevents users from tampering with the payment amount
// =========================================================================
// Method 1: If you have school_num and user_num in session (like your existing flow)
// Only use this branch if the db helpers are available in the current app.
if (
isset($_SESSION['UserInfo']['record_num']) &&
isset($_SESSION['SchoolInfo']['record_num']) &&
function_exists('db_getVal') &&
function_exists('db_query') &&
function_exists('db_num_rows') &&
function_exists('db_fetch_array') &&
(function_exists('db_fetch_assoc') || function_exists('db_fetch_array')) &&
function_exists('db_insert_id')
) {
$user_num = intval($_SESSION['UserInfo']['record_num']);
$school_num = intval($_SESSION['SchoolInfo']['record_num']);
// Get balance from database (same query as payment_form.php)
$balance = db_getVal("SELECT SUM(transaction_amount) as balance FROM user_account WHERE school_num = $school_num AND user_num = $user_num AND (deleted != 'Y' OR deleted IS NULL)");
if (!$balance) $balance = 0.00;
// Get school record for PayPal settings
// Some codebases use db_fetch_assoc, others use db_fetch_array
$schoolQuery = db_query("SELECT * FROM schools WHERE record_num = $school_num");
if (function_exists('db_fetch_assoc')) {
$school_record = db_fetch_assoc($schoolQuery);
} else {
$school_record = db_fetch_array($schoolQuery);
}
// Calculate transaction fee (same as payment_form.php)
$trx_fee = intval($balance * $school_record['paypal_percentage']) / 100 + $school_record['paypal_fee'];
$owing = $balance + $trx_fee;
// Get or create TRX number (same logic as payment_form.php)
$now = time();
$trx_time = date("Y-m-d H:i:s", $now);
$query = "SELECT * FROM user_online_payments WHERE school_num = $school_num AND user_num = $user_num AND status = 'Pending'";
$results = db_query($query);
if (db_num_rows($results) > 0) {
$row = db_fetch_array($results);
$trxnum = $row['record_num'];
$query = "UPDATE user_online_payments SET user_account_balance = $balance, transaction_fee = $trx_fee, balance_owing = $owing, transaction_datetime = '$trx_time', transaction_time = $now WHERE school_num = $school_num AND user_num = $user_num AND status = 'Pending'";
db_query($query);
} else {
$query = "INSERT INTO user_online_payments (school_num, user_num, transaction_datetime, transaction_time, user_account_balance, transaction_fee, balance_owing, status) VALUES ($school_num, $user_num, '$trx_time', $now, $balance, $trx_fee, $owing, 'Pending')";
db_query($query);
$trxnum = db_insert_id();
}
$currency = $school_record['paypal_currency'] ?: PAYPAL_CURRENCY;
$description = $school_record['school_name'] . " Order Payment";
}
// Method 2: Fallback - use session variables if set directly
else if (isset($_SESSION['paypal_checkout_amount']) && isset($_SESSION['paypal_checkout_trxnum'])) {
$owing = floatval($_SESSION['paypal_checkout_amount']);
$trxnum = intval($_SESSION['paypal_checkout_trxnum']);
$currency = $_SESSION['paypal_checkout_currency'] ?? PAYPAL_CURRENCY;
$description = $_SESSION['paypal_checkout_description'] ?? 'Order Payment';
}
// Method 3: For testing/demo - use POST data (NOT recommended for production)
else if (isset($_POST['amount']) && isset($_POST['trxnum'])) {
// WARNING: In production, ALWAYS validate this against your database
$owing = floatval($_POST['amount']);
$trxnum = intval($_POST['trxnum']);
$currency = $_POST['currency'] ?? PAYPAL_CURRENCY;
$description = $_POST['description'] ?? 'Order Payment';
// You should validate that this trxnum exists and the amount matches!
// This is just for demo purposes
}
else {
throw new Exception('No payment information found. Please ensure you are logged in.');
}
// Validate amount
if ($owing <= 0) {
throw new Exception('Invalid payment amount: ' . $owing);
}
// Create PayPal order
$paypal = new PayPalCheckoutAPI();
$order = $paypal->createOrder($owing, $currency, $description, strval($trxnum));
// Store order ID in session for verification during capture
$_SESSION['paypal_order_id'] = $order['id'];
$_SESSION['paypal_order_trxnum'] = $trxnum;
$_SESSION['paypal_order_amount'] = $owing;
// Approve link — where the redirect-based button sends the buyer to
// log in to PayPal and approve the payment (not used by the JS SDK
// button flow, which drives approval in its own popup/iframe instead).
$approveUrl = '';
foreach (($order['links'] ?? []) as $link) {
if (($link['rel'] ?? '') === 'approve') {
$approveUrl = $link['href'];
break;
}
}
// Return order ID (used by the PayPal JS SDK button) and approve URL
// (used by the plain themed button's redirect flow)
echo json_encode([
'id' => $order['id'],
'approveUrl' => $approveUrl
]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode([
'error' => $e->getMessage()
]);
}