false,'error'=>'Method not allowed']); exit; } $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'] ?? '')); $squareToken = trim($input['square_token'] ?? ''); if (!$name || !$email || !$package || !$date) { http_response_code(400); echo json_encode(['success'=>false,'error'=>'Name, email, package, and date are required.']); exit; } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { http_response_code(400); echo json_encode(['success'=>false,'error'=>'Invalid email address.']); exit; } if (!isset(PACKAGES[$package])) { http_response_code(400); echo json_encode(['success'=>false,'error'=>'Invalid package.']); exit; } if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) || strtotime($date) < strtotime('today')) { http_response_code(400); echo json_encode(['success'=>false,'error'=>'Invalid or past date.']); exit; } $pkg = PACKAGES[$package]; $rentalDate = $date; $endDate = date('Y-m-d', strtotime($date . ' +' . $pkg['days'] . ' days')); // Check availability $conflict = db()->prepare( "SELECT id FROM bookings WHERE status IN ('pending','confirmed') AND rental_date <= ? AND end_date >= ?" ); $conflict->execute([$endDate, $rentalDate]); if ($conflict->fetch()) { echo json_encode(['success'=>false,'error'=>'Sorry, that date is already booked. Please choose another date.']); exit; } $blockedCheck = db()->prepare("SELECT id FROM blocked_dates WHERE block_date BETWEEN ? AND ?"); $blockedCheck->execute([$rentalDate, $endDate]); if ($blockedCheck->fetch()) { echo json_encode(['success'=>false,'error'=>'That date is unavailable. Please choose another date.']); exit; } // Create booking $ref = generateRef(); $stmt = db()->prepare( "INSERT INTO bookings (booking_ref, name, email, phone, package, rental_date, end_date, amount, notes) VALUES (?,?,?,?,?,?,?,?,?)" ); $stmt->execute([$ref, $name, $email, $phone, $package, $rentalDate, $endDate, $pkg['amount'], $message]); $dateLabel = date('F j, Y', strtotime($rentalDate)); $pkgLabel = $pkg['label']; $amountLabel = '$' . number_format($pkg['amount'], 2); $depositLabel = '$' . number_format(DEPOSIT_AMOUNT, 2); $balance = $pkg['amount'] - DEPOSIT_AMOUNT; $balanceLabel = '$' . number_format($balance, 2); // Admin email $adminHtml = "

New Booking Request — {$ref}

Ref{$ref}
Name" . htmlspecialchars($name) . "
Email" . htmlspecialchars($email) . "
Phone" . htmlspecialchars($phone ?: '—') . "
Package{$pkgLabel} — {$amountLabel}
Date{$dateLabel}
Deposit Hold{$depositLabel} (card held — not charged yet)
Balance Due{$balanceLabel} at pickup
" . ($message ? "
" . nl2br(htmlspecialchars($message)) . "
" : "") . "

Submitted " . date('F j, Y g:i A') . " CT

"; // Customer confirmation email $confirmHtml = "

Parker County Slingshot Rentals

Booking Request Received!

Hey " . htmlspecialchars($name) . ", your request is in. We'll confirm availability and reach out within a few hours.

Booking Reference

{$ref}

Package: {$pkgLabel}

Requested Date: {$dateLabel}

Total: {$amountLabel}

Deposit (card hold today): {$depositLabel} — not charged until confirmed

Balance due at pickup: {$balanceLabel}

Next Step: Sign Your Rental Agreement

Once your booking is confirmed you'll sign our digital waiver online — no printer needed. Your link:

Sign Rental Agreement →

Questions? Call or text (817) 266-2022 or reply to this email.

Ride on,
The Parker County Slingshot Team

© " . date('Y') . " Parker County Slingshot Rentals — Weatherford, TX

"; // 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; } } // Add Square authorization badge to customer email if hold was placed if ($depositStatus) { $confirmHtml = str_replace( "

Deposit (card hold today): {$depositLabel}", "

Deposit (card hold today): {$depositLabel} ✓ Authorized", $confirmHtml ); } // Add deposit note to admin email if applicable if ($depositStatus) { $adminHtml = str_replace( "

", "

✓ \$" . number_format(DEPOSIT_AMOUNT, 2) . " deposit hold authorized (Square — not yet captured)

", $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); $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]);