Fix multi-day full-day pricing: add days selector, multiply amount by rental days

This commit is contained in:
2026-05-26 13:00:46 +00:00
parent 4fc5b77214
commit 6a1d2358ec
2 changed files with 52 additions and 18 deletions
+12 -6
View File
@@ -35,9 +35,13 @@ if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date) || strtotime($date) < strtotime(
echo json_encode(['success'=>false,'error'=>'Invalid or past date.']); exit; echo json_encode(['success'=>false,'error'=>'Invalid or past date.']); exit;
} }
$pkg = PACKAGES[$package]; $pkg = PACKAGES[$package];
$rentalDays = ($package === 'full-day') ? max(1, min(3, (int)($input['rental_days'] ?? 1))) : 1;
$rentalDate = $date; $rentalDate = $date;
$endDate = date('Y-m-d', strtotime($date . ' +' . $pkg['days'] . ' days')); $endDate = ($package === 'full-day')
? date('Y-m-d', strtotime($date . ' +' . ($rentalDays - 1) . ' days'))
: date('Y-m-d', strtotime($date . ' +' . $pkg['days'] . ' days'));
$totalAmount = ($package === 'full-day') ? $pkg['amount'] * $rentalDays : $pkg['amount'];
// Check availability // Check availability
$conflict = db()->prepare( $conflict = db()->prepare(
@@ -57,10 +61,12 @@ if ($blockedCheck->fetch()) {
$ref = generateRef(); $ref = generateRef();
$dateLabel = date('F j, Y', strtotime($rentalDate)); $dateLabel = date('F j, Y', strtotime($rentalDate));
$pkgLabel = $pkg['label']; $pkgLabel = ($package === 'full-day' && $rentalDays > 1)
$amountLabel = '$' . number_format($pkg['amount'], 2); ? $pkg['label'] . ' × ' . $rentalDays . ' days'
: $pkg['label'];
$amountLabel = '$' . number_format($totalAmount, 2);
$depositLabel = '$' . number_format(DEPOSIT_AMOUNT, 2); $depositLabel = '$' . number_format(DEPOSIT_AMOUNT, 2);
$balance = $pkg['amount'] - DEPOSIT_AMOUNT; $balance = $totalAmount - DEPOSIT_AMOUNT;
$balanceLabel = '$' . number_format($balance, 2); $balanceLabel = '$' . number_format($balance, 2);
// ── Square: create customer + card on file + deposit hold ───────────────────── // ── Square: create customer + card on file + deposit hold ─────────────────────
@@ -143,7 +149,7 @@ $stmt = db()->prepare(
VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
); );
$stmt->execute([ $stmt->execute([
$ref, $name, $email, $phone, $package, $rentalDate, $endDate, $pkg['amount'], $message, $ref, $name, $email, $phone, $package, $rentalDate, $endDate, $totalAmount, $message,
$sqCustomerId, $sqCardId, $sqCardLast4, $sqCardBrand, $sqCustomerId, $sqCardId, $sqCardLast4, $sqCardBrand,
$sqPaymentId, $sqPaymentStatus, $sqPaymentId, $sqPaymentStatus,
]); ]);
+40 -12
View File
@@ -35,7 +35,7 @@
"name": "Parker County Slingshot Rentals", "name": "Parker County Slingshot Rentals",
"description": "Polaris Slingshot rentals in Parker County, Texas. Daily and weekend rentals available for thrill-seekers near Weatherford and the DFW metroplex.", "description": "Polaris Slingshot rentals in Parker County, Texas. Daily and weekend rentals available for thrill-seekers near Weatherford and the DFW metroplex.",
"url": "https://parkerslingshotrentals.com", "url": "https://parkerslingshotrentals.com",
"telephone": "+1-817-555-0199", "telephone": "+1-817-266-2022",
"email": "info@parkerslingshotrentals.com", "email": "info@parkerslingshotrentals.com",
"priceRange": "$$", "priceRange": "$$",
"currenciesAccepted": "USD", "currenciesAccepted": "USD",
@@ -768,7 +768,7 @@
</div> </div>
<div class="contact-detail"> <div class="contact-detail">
<span>📞</span> <span>📞</span>
<a href="tel:+18175550199" style="color:inherit;text-decoration:none;">(817) 555-0199</a> <a href="tel:+18172662022" style="color:inherit;text-decoration:none;">(817) 266-2022</a>
</div> </div>
<div class="contact-detail"> <div class="contact-detail">
<span>✉️</span> <span>✉️</span>
@@ -808,9 +808,16 @@
<select name="package" required> <select name="package" required>
<option value="">Select Rental Package</option> <option value="">Select Rental Package</option>
<option value="half-day">Half Day — $80</option> <option value="half-day">Half Day — $80</option>
<option value="full-day">Full Day — $150</option> <option value="full-day">Full Day — $150/day</option>
<option value="weekend">3 Day Adventure — $449</option> <option value="weekend">3 Day Adventure — $449</option>
</select> </select>
<div id="rental-days-row" style="display:none">
<select name="rental_days" id="rentalDaysSelect">
<option value="1">1 Day — $150</option>
<option value="2">2 Days — $300</option>
<option value="3">3 Days — $450</option>
</select>
</div>
<input type="date" name="date" required /> <input type="date" name="date" required />
<div id="date-unavail-msg" style="display:none;color:#f87171;font-size:.82rem;margin-top:.25rem">That date is already booked or unavailable. Please choose another.</div> <div id="date-unavail-msg" style="display:none;color:#f87171;font-size:.82rem;margin-top:.25rem">That date is already booked or unavailable. Please choose another.</div>
<textarea name="message" placeholder="Anything else we should know? (optional)"></textarea> <textarea name="message" placeholder="Anything else we should know? (optional)"></textarea>
@@ -1069,14 +1076,35 @@
// ── Balance-due display ─────────────────────────────────────────────────────── // ── Balance-due display ───────────────────────────────────────────────────────
const PACKAGE_PRICES = { 'half-day': 80, 'full-day': 150, 'weekend': 449 }; const PACKAGE_PRICES = { 'half-day': 80, 'full-day': 150, 'weekend': 449 };
const DEPOSIT = 45; const DEPOSIT = 45;
const pkgSelect = document.querySelector('select[name="package"]'); const pkgSelect = document.querySelector('select[name="package"]');
const rentalDaysSelect = document.getElementById('rentalDaysSelect');
const rentalDaysRow = document.getElementById('rental-days-row');
const balLabel = document.getElementById('balance-due-label'); const balLabel = document.getElementById('balance-due-label');
const balAmt = document.getElementById('balance-due-amount'); const balAmt = document.getElementById('balance-due-amount');
function calcTotal(pkg, days) {
const base = PACKAGE_PRICES[pkg];
if (!base) return null;
return pkg === 'full-day' ? base * days : base;
}
function updateBalance() {
const pkg = pkgSelect ? pkgSelect.value : '';
const days = rentalDaysSelect ? parseInt(rentalDaysSelect.value) || 1 : 1;
const total = calcTotal(pkg, days);
if (total && balLabel && balAmt) {
balAmt.textContent = '$' + (total - DEPOSIT).toFixed(2).replace(/\.00$/, '');
balLabel.style.display = '';
} else if (balLabel) {
balLabel.style.display = 'none';
}
}
if (pkgSelect) { selectedPackage = pkgSelect.value || 'half-day'; } if (pkgSelect) { selectedPackage = pkgSelect.value || 'half-day'; }
if (pkgSelect) { if (pkgSelect) {
pkgSelect.addEventListener('change', function() { pkgSelect.addEventListener('change', function() {
selectedPackage = this.value; selectedPackage = this.value;
updateLegend(); updateLegend();
if (rentalDaysRow) rentalDaysRow.style.display = this.value === 'full-day' ? '' : 'none';
if (selectedDates.size > 0) { if (selectedDates.size > 0) {
Promise.all([...selectedDates].map(d => hasRangeConflict(d, selectedPackage).then(c => c ? d : null))) Promise.all([...selectedDates].map(d => hasRangeConflict(d, selectedPackage).then(c => c ? d : null)))
.then(conflicts => { .then(conflicts => {
@@ -1087,15 +1115,12 @@
renderCalendar(calMonth, calYear); renderCalendar(calMonth, calYear);
}); });
} else { renderCalendar(calMonth, calYear); } } else { renderCalendar(calMonth, calYear); }
const price = PACKAGE_PRICES[this.value]; updateBalance();
if (price && balLabel && balAmt) {
balAmt.textContent = '$' + (price - DEPOSIT).toFixed(2).replace(/\.00$/, '');
balLabel.style.display = '';
} else if (balLabel) {
balLabel.style.display = 'none';
}
}); });
} }
if (rentalDaysSelect) {
rentalDaysSelect.addEventListener('change', updateBalance);
}
// ── Square Web Payments ─────────────────────────────────────────────────────── // ── Square Web Payments ───────────────────────────────────────────────────────
let squareCard = null; let squareCard = null;
@@ -1166,11 +1191,14 @@
setDepStatus('Card verified — authorizing $45 deposit hold…', 'processing'); setDepStatus('Card verified — authorizing $45 deposit hold…', 'processing');
} }
const pkgVal = form.querySelector('[name="package"]').value;
const daysVal = pkgVal === 'full-day' ? (parseInt(form.querySelector('[name="rental_days"]')?.value) || 1) : 1;
const data = { const data = {
name: form.querySelector('[name="name"]').value, name: form.querySelector('[name="name"]').value,
email: form.querySelector('[name="email"]').value, email: form.querySelector('[name="email"]').value,
phone: form.querySelector('[name="phone"]').value, phone: form.querySelector('[name="phone"]').value,
package: form.querySelector('[name="package"]').value, package: pkgVal,
rental_days: daysVal,
date: form.querySelector('[name="date"]').value, date: form.querySelector('[name="date"]').value,
message: form.querySelector('[name="message"]').value, message: form.querySelector('[name="message"]').value,
square_token: squareToken, square_token: squareToken,