121 lines
4.8 KiB
PHP
121 lines
4.8 KiB
PHP
<?php
|
|
/**
|
|
* "Pay with Square" button — production bridge to Square checkout
|
|
* ────────────────────────────────────────────────────────────────
|
|
* Include from payment_form.php AFTER $balance is known. Same contract as
|
|
* paypal_ppcp_button.php: stores the amount in the hotlunch session, then
|
|
* links to /square/checkout.php so the parent cannot change the total.
|
|
*
|
|
* The button renders ONLY when this school is onboarded with Square
|
|
* (MerchantStore::isOnboarded: connected, not revoked, token present, active
|
|
* location). Otherwise nothing is shown. The charge is made with THIS school's
|
|
* own Square token, so the money settles in this school's Square account.
|
|
* Hidden-return leaves an HTML comment explaining why (View Source).
|
|
*/
|
|
|
|
$sqWhy = function (string $reason): void {
|
|
echo "\n<!-- sq-button hidden: " . htmlspecialchars($reason, ENT_QUOTES) . " -->\n";
|
|
};
|
|
|
|
if (!defined('SQ_WEB_BASE')) {
|
|
// Production layout: payment_form.php at /, this file at /square/square_button.php
|
|
define('SQ_WEB_BASE', '/square');
|
|
}
|
|
|
|
// The unique school id (names are not unique, so never resolve by name here).
|
|
$sqSchoolNum = (int)($school_num ?? ($school_record['record_num'] ?? 0));
|
|
if ($sqSchoolNum <= 0) {
|
|
$sqWhy('no school on this page');
|
|
return;
|
|
}
|
|
|
|
require_once __DIR__ . '/lib/SquareClient.php';
|
|
require_once __DIR__ . '/lib/MerchantStore.php';
|
|
$sqCfg = require __DIR__ . '/config.php';
|
|
$sqStore = new MerchantStore($sqCfg);
|
|
|
|
// Always read the live state from the DB (a cached $school_record could predate
|
|
// a connect / disconnect / revoke).
|
|
if (!$sqStore->isOnboarded($sqSchoolNum, new SquareClient($sqCfg))) {
|
|
$sqWhy('school is not onboarded with Square');
|
|
return;
|
|
}
|
|
$sqMeta = $sqStore->getMetaByNum($sqSchoolNum);
|
|
$sqSchoolName = trim((string)($school_record['school_name'] ?? ''));
|
|
if ($sqSchoolName === '') {
|
|
$sqSchoolName = (string)($sqStore->schoolNameByNum($sqSchoolNum) ?? '');
|
|
}
|
|
|
|
$sqBase = 0.0;
|
|
if (function_exists('db_getVal') && isset($user_num)) {
|
|
$sqBase = (float)db_getVal(
|
|
"select sum(transaction_amount) as balance from user_account
|
|
where school_num = " . $sqSchoolNum . " and user_num = " . (int)$user_num . "
|
|
AND (deleted != 'Y' OR deleted IS NULL)"
|
|
);
|
|
}
|
|
if ($sqBase <= 0 && isset($balance)) {
|
|
$sqBase = (float)$balance;
|
|
}
|
|
if (isset($selected_amount) && (float)$selected_amount > 0) {
|
|
$sqBase = (float)$selected_amount;
|
|
}
|
|
$sqBase = round($sqBase, 2);
|
|
if ($sqBase <= 0) {
|
|
$sqWhy('nothing to charge (total ' . number_format($sqBase, 2) . ')');
|
|
return;
|
|
}
|
|
|
|
// Charge in the currency of the school's Square location (Square rejects a
|
|
// currency that doesn't match the location).
|
|
$sqCurrency = strtoupper(trim((string)($sqMeta['currency'] ?? '')));
|
|
if (!preg_match('/^[A-Z]{3}$/', $sqCurrency)) {
|
|
$sqCurrency = 'CAD';
|
|
}
|
|
|
|
$sqIsDeposit = isset($selected_amount) && (float)$selected_amount > 0;
|
|
|
|
if (session_status() !== PHP_SESSION_ACTIVE) {
|
|
@session_name('hotlunch');
|
|
@session_start();
|
|
}
|
|
|
|
$_SESSION['sq_checkout'] = [
|
|
'school_num' => $sqSchoolNum,
|
|
'school_name' => $sqSchoolName,
|
|
'user_num' => (int)($user_num ?? ($_SESSION['UserInfo']['record_num'] ?? 0)),
|
|
'buyer_email' => (string)($_SESSION['UserInfo']['email'] ?? ''),
|
|
'base_amount' => number_format($sqBase, 2, '.', ''),
|
|
'fee_amount' => '0.00',
|
|
'total_amount' => number_format($sqBase, 2, '.', ''),
|
|
'base_label' => $sqIsDeposit ? 'Deposit amount' : 'Account balance',
|
|
'fee_label' => '',
|
|
'currency' => $sqCurrency,
|
|
'currency_symbol' => (string)($currencySymbol ?? '$'),
|
|
'return_url' => (string)($FormTarget ?? '/'),
|
|
// One Square idempotency key per checkout: a repeated click, retry or second
|
|
// tab for the same checkout can never charge the parent twice.
|
|
'idempotency_key' => 'hl-' . bin2hex(random_bytes(16)),
|
|
'created_at' => time(),
|
|
];
|
|
|
|
$sqCheckoutUrl = SQ_WEB_BASE . '/checkout.php';
|
|
?>
|
|
<div class="sq-pay-wrap">
|
|
<a href="<?php echo htmlspecialchars($sqCheckoutUrl); ?>" class="sq-pay-btn">
|
|
Pay with Square
|
|
</a>
|
|
</div>
|
|
<style>
|
|
.sq-pay-wrap { max-width: 340px; margin: 0 auto 8px; text-align: center; }
|
|
.sq-pay-btn {
|
|
display: flex; align-items: center; justify-content: center;
|
|
width: 100%; min-height: 48px; padding: 12px 24px; box-sizing: border-box;
|
|
background: linear-gradient(135deg, #006aff 0%, #003a8c 100%);
|
|
border: none; border-radius: 8px;
|
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
font-size: 16px; font-weight: 600; color: #fff; text-decoration: none; cursor: pointer;
|
|
}
|
|
.sq-pay-btn:hover, .sq-pay-btn:focus { color: #fff; text-decoration: none; box-shadow: 0 8px 18px rgba(0,106,255,.28); }
|
|
</style>
|