164 lines
7.7 KiB
PHP
164 lines
7.7 KiB
PHP
<?php
|
|
/**
|
|
* Square Checkout — order details page
|
|
* Opened by square_button.php. Amounts come from $_SESSION['sq_checkout'],
|
|
* never the URL. After a successful charge, order-api.php books the payment
|
|
* into user_account and money settles in the school's Square account.
|
|
*/
|
|
|
|
if (session_status() !== PHP_SESSION_ACTIVE) {
|
|
@session_name('hotlunch');
|
|
@session_start();
|
|
}
|
|
|
|
$ctx = $_SESSION['sq_checkout'] ?? null;
|
|
|
|
$ctxValid = is_array($ctx)
|
|
&& (float)($ctx['total_amount'] ?? 0) > 0
|
|
&& (int)($ctx['school_num'] ?? 0) > 0
|
|
&& (time() - (int)($ctx['created_at'] ?? 0)) < 3600;
|
|
|
|
$schoolReady = false;
|
|
$schoolName = '';
|
|
$returnUrl = is_array($ctx) ? (string)($ctx['return_url'] ?? '/') : '/';
|
|
$readyIssues = [];
|
|
|
|
if ($ctxValid) {
|
|
require_once __DIR__ . '/lib/MerchantStore.php';
|
|
require_once __DIR__ . '/lib/SquareClient.php';
|
|
$cfg = require __DIR__ . '/config.php';
|
|
$store = new MerchantStore($cfg);
|
|
$client = new SquareClient($cfg);
|
|
$num = (int)$ctx['school_num'];
|
|
$meta = $store->getMetaByNum($num);
|
|
$schoolName = (string)($ctx['school_name'] ?: ($store->schoolNameByNum($num) ?? ''));
|
|
$readyIssues = is_array($meta['status_issues'] ?? null) ? $meta['status_issues'] : [];
|
|
|
|
// Same rule as the button: only an onboarded school can be paid.
|
|
$schoolReady = $store->isOnboarded($num, $client);
|
|
if (!$schoolReady) {
|
|
$meta = $store->getMetaByNum($num);
|
|
$readyIssues = is_array($meta['status_issues'] ?? null) ? $meta['status_issues'] : [];
|
|
}
|
|
|
|
$symbol = (string)($ctx['currency_symbol'] ?? '$');
|
|
$baseAmount = (string)$ctx['base_amount'];
|
|
$total = (string)$ctx['total_amount'];
|
|
$baseLabel = (string)($ctx['base_label'] ?? 'Account balance');
|
|
$buyerEmail = (string)($ctx['buyer_email'] ?? '');
|
|
$currency = strtoupper((string)($ctx['currency'] ?? ($meta['currency'] ?? 'CAD')));
|
|
if (!preg_match('/^[A-Z]{3}$/', $currency)) $currency = 'CAD';
|
|
|
|
$sqCheckout = [
|
|
'school_name' => $schoolName,
|
|
'school_num' => $num,
|
|
'user_num' => (int)($ctx['user_num'] ?? 0),
|
|
// First-party checkout is bound to the session; never fall back to the
|
|
// public embed key, or a paid checkout could be resubmitted as an embed.
|
|
'merchant_key' => '',
|
|
'amount' => $total,
|
|
'currency' => $currency,
|
|
'buyer_email' => $buyerEmail,
|
|
'order_api_url' => './order-api.php',
|
|
'success_url' => $returnUrl,
|
|
];
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title><?= $ctxValid ? 'Checkout — ' . htmlspecialchars($schoolName) : 'Checkout' ?></title>
|
|
<style>
|
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f7f8fa; color: #1a202c; min-height: 100vh; }
|
|
a { color: #006aff; }
|
|
.topbar { background: #fff; border-bottom: 1px solid #e2e8f0; padding: 14px 24px; display: flex; align-items: center; gap: 10px; }
|
|
.topbar-school { font-weight: 700; font-size: 16px; color: #006aff; }
|
|
.topbar-secure { margin-left: auto; font-size: 12px; color: #718096; }
|
|
.page { max-width: 920px; margin: 36px auto 48px; padding: 0 20px; }
|
|
.page-head { margin-bottom: 26px; }
|
|
.page-head h1 { font-size: 24px; font-weight: 700; margin-bottom: 6px; }
|
|
.page-head p { font-size: 14px; color: #718096; }
|
|
.cols { display: grid; grid-template-columns: 380px 1fr; gap: 28px; align-items: start; }
|
|
@media (max-width: 760px) { .cols { grid-template-columns: 1fr; } }
|
|
.card { background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 24px; }
|
|
.card h2 { font-size: 15px; font-weight: 700; margin-bottom: 4px; }
|
|
.card .card-sub { font-size: 13px; color: #718096; margin-bottom: 18px; line-height: 1.5; }
|
|
.sum-row { display: flex; justify-content: space-between; gap: 12px; padding: 9px 0; font-size: 14px; color: #4a5568; border-bottom: 1px solid #f0f2f5; }
|
|
.sum-total { display: flex; justify-content: space-between; padding: 14px 0 2px; font-size: 16px; font-weight: 700; }
|
|
.sum-total .amt { font-size: 22px; }
|
|
.sum-note { margin-top: 16px; padding: 12px 14px; background: #f5f7fa; border-radius: 8px; font-size: 12.5px; color: #4a5568; line-height: 1.55; }
|
|
.sum-account { margin-top: 14px; font-size: 12.5px; color: #718096; }
|
|
.back-link { display: inline-block; margin-top: 12px; font-size: 13.5px; }
|
|
.notice { max-width: 480px; margin: 70px auto; background: #fff; border: 1px solid #e2e8f0; border-radius: 12px; padding: 34px 30px; text-align: center; }
|
|
.notice h1 { font-size: 19px; margin-bottom: 10px; }
|
|
.notice p { font-size: 14px; color: #718096; line-height: 1.6; margin-bottom: 22px; }
|
|
.notice a.btn-back { display: inline-block; background: #006aff; color: #fff; text-decoration: none; font-size: 14px; font-weight: 600; padding: 11px 26px; border-radius: 8px; }
|
|
.foot { text-align: center; font-size: 12px; color: #a0aec0; margin-top: 34px; line-height: 1.6; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<?php if (!$ctxValid): ?>
|
|
<div class="notice">
|
|
<h1>This checkout link has expired</h1>
|
|
<p>For your security, checkout sessions only stay open for a short while.
|
|
Head back to your account page and click <strong>Pay with Square</strong> again.</p>
|
|
<a class="btn-back" href="<?= htmlspecialchars($returnUrl) ?>">Back to my account</a>
|
|
</div>
|
|
<?php elseif (!$schoolReady): ?>
|
|
<div class="notice">
|
|
<h1>Online payment isn't available right now</h1>
|
|
<p><?= htmlspecialchars($schoolName) ?> can't accept Square payments at the moment.
|
|
Please go back and choose another payment method, or contact the school office.</p>
|
|
<?php if (!empty($readyIssues)): ?>
|
|
<p style="text-align:left;font-size:13px;color:#4a5568;margin-top:8px;">
|
|
<?= htmlspecialchars(implode(' ', array_map('strval', $readyIssues))) ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
<a class="btn-back" href="<?= htmlspecialchars($returnUrl) ?>">Back to my account</a>
|
|
</div>
|
|
<?php else: ?>
|
|
<nav class="topbar">
|
|
<span class="topbar-school"><?= htmlspecialchars($schoolName) ?></span>
|
|
<span class="topbar-secure">Secure checkout</span>
|
|
</nav>
|
|
<div class="page">
|
|
<div class="page-head">
|
|
<h1>Review & pay</h1>
|
|
<p>You're paying <?= htmlspecialchars($schoolName) ?> through Square. Funds go to the school's Square account.</p>
|
|
</div>
|
|
<div class="cols">
|
|
<div class="card">
|
|
<h2>Order summary</h2>
|
|
<p class="card-sub">Payment to <?= htmlspecialchars($schoolName) ?></p>
|
|
<div class="sum-row">
|
|
<span><?= htmlspecialchars($baseLabel) ?></span>
|
|
<span class="amt"><?= htmlspecialchars($symbol . number_format((float)$baseAmount, 2)) ?></span>
|
|
</div>
|
|
<div class="sum-total">
|
|
<span>Total</span>
|
|
<span class="amt"><?= htmlspecialchars($symbol . number_format((float)$total, 2)) ?></span>
|
|
</div>
|
|
<div class="sum-note">
|
|
Your payment goes directly to the school's Square account and is credited
|
|
to your family account as soon as Square confirms it.
|
|
</div>
|
|
<?php if ($buyerEmail !== ''): ?>
|
|
<p class="sum-account">Paying as <?= htmlspecialchars($buyerEmail) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="card">
|
|
<h2>Payment method</h2>
|
|
<p class="card-sub">Card details are tokenized by Square and never touch our servers.</p>
|
|
<?php require __DIR__ . '/square-checkout-widget.php'; ?>
|
|
<a class="back-link" href="<?= htmlspecialchars($returnUrl) ?>">← Go back and choose a different payment method</a>
|
|
</div>
|
|
</div>
|
|
<p class="foot">Questions about a charge? Contact the school office at <?= htmlspecialchars($schoolName) ?>.</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
</body>
|
|
</html>
|