First Commit
This commit is contained in:
1 parent
5eb9dd037d
commit
2e62c0e60b
11877 files changed
+2035312
No files matched your search
@@ -0,0 +1,120 @@
|
||||
<?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>
|
||||
Reference in new issue
Block a user