Add Square deposit payment integration

- Square Web Payments SDK card element in booking form
- Delayed-capture hold ($100) on booking submit — not charged until confirmed
- Live payment status field: Verifying card → Authorizing → Confirmed w/ hold ID
- Admin: Capture / Void / Refund actions for each booking
- square_payment_id returned in API response for frontend confirmation display

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-22 18:33:16 +00:00
parent 8f5362aa95
commit cca3129f6e
4 changed files with 324 additions and 35 deletions
+52 -7
View File
@@ -10,12 +10,13 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); echo json_
$input = json_decode(file_get_contents('php://input'), true) ?: $_POST;
$name = trim(strip_tags($input['name'] ?? ''));
$email = trim(strip_tags($input['email'] ?? ''));
$phone = trim(strip_tags($input['phone'] ?? ''));
$package = trim(strip_tags($input['package'] ?? ''));
$date = trim(strip_tags($input['date'] ?? ''));
$message = trim(strip_tags($input['message'] ?? ''));
$name = trim(strip_tags($input['name'] ?? ''));
$email = trim(strip_tags($input['email'] ?? ''));
$phone = trim(strip_tags($input['phone'] ?? ''));
$package = trim(strip_tags($input['package'] ?? ''));
$date = trim(strip_tags($input['date'] ?? ''));
$message = trim(strip_tags($input['message'] ?? ''));
$squareToken = trim($input['square_token'] ?? '');
if (!$name || !$email || !$package || !$date) {
http_response_code(400);
@@ -113,7 +114,51 @@ $confirmHtml = "<div style='max-width:600px;margin:0 auto;font-family:Arial,sans
</div>
</div>";
// Square deposit authorization (delayed capture — hold only, not charged yet)
$depositStatus = null;
if ($squareToken) {
$sqResp = squareApi('POST', '/payments', [
'source_id' => $squareToken,
'idempotency_key' => $ref . '-dep-' . time(),
'amount_money' => ['amount' => (int)(DEPOSIT_AMOUNT * 100), 'currency' => 'USD'],
'autocomplete' => false, // hold only — capture when confirmed
'location_id' => SQUARE_LOCATION_ID,
'note' => "Deposit hold — booking {$ref}",
'reference_id' => $ref,
'buyer_email_address' => $email,
]);
if (!empty($sqResp['payment']['id'])) {
$sqId = $sqResp['payment']['id'];
$sqSts = $sqResp['payment']['status']; // APPROVED
db()->prepare("UPDATE bookings SET square_payment_id=?, square_payment_status=? WHERE booking_ref=?")
->execute([$sqId, $sqSts, $ref]);
$depositStatus = $sqSts;
}
}
$depositLine = $depositStatus
? "<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Deposit Hold:</strong> \$" . number_format(DEPOSIT_AMOUNT, 2) . " authorized (not charged — released if booking is declined)</p>"
: '';
// Inject deposit line into confirmation email
$confirmHtml = str_replace(
"<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Total:</strong> {$amountLabel}</p>",
"<p style='margin:4px 0;font-size:14px;color:#374151'><strong>Total:</strong> {$amountLabel}</p>{$depositLine}",
$confirmHtml
);
// Add deposit note to admin email if applicable
if ($depositStatus) {
$adminHtml = str_replace(
"<p style='margin-top:16px;font-size:13px;color:#9ca3af'>",
"<p style='margin-top:8px;font-size:13px;color:#16a34a;font-weight:700'>✓ \$" . number_format(DEPOSIT_AMOUNT, 2) . " deposit hold authorized (Square — not yet captured)</p><p style='margin-top:8px;font-size:13px;color:#9ca3af'>",
$adminHtml
);
}
sendEmail(ADMIN_EMAIL, 'Parker Slingshot Admin', "New Booking {$ref}: {$name}{$pkgLabel} on {$dateLabel}", $adminHtml);
sendEmail($email, $name, "Booking Request {$ref} — Parker County Slingshot Rentals", $confirmHtml);
echo json_encode(['success'=>true,'ref'=>$ref,'message'=>"Booking request received! Your reference is {$ref}. We'll be in touch shortly."]);
$msg = "Booking request received! Your reference is {$ref}. We'll be in touch shortly.";
if ($depositStatus) $msg .= " A \$" . number_format(DEPOSIT_AMOUNT, 2) . " refundable deposit hold has been placed on your card.";
echo json_encode(['success'=>true,'ref'=>$ref,'deposit_held'=>(bool)$depositStatus,'square_payment_id'=>$sqId??null,'message'=>$msg]);