diff --git a/admin/index.php b/admin/index.php index bfcea6d..3092780 100644 --- a/admin/index.php +++ b/admin/index.php @@ -198,7 +198,7 @@ if ($isAjax) { if (!$pid) { echo json_encode(['error'=>'No payment on file']); exit; } $resp = squareApi('POST', "/payments/{$pid}/cancel"); if (($resp['payment']['status'] ?? '') === 'CANCELED') { - db()->prepare("UPDATE bookings SET square_payment_status='CANCELED' WHERE id=?")->execute([$id]); + db()->prepare("UPDATE bookings SET square_payment_status='CANCELED', status='cancelled' WHERE id=?")->execute([$id]); echo json_encode(['ok'=>true,'status'=>'CANCELED']); } else { echo json_encode(['error' => $resp['errors'][0]['detail'] ?? 'Void failed']); @@ -221,7 +221,7 @@ if ($isAjax) { 'reason' => 'Security deposit refund — booking returned in good condition', ]); if (!empty($resp['refund']['id'])) { - db()->prepare("UPDATE bookings SET square_payment_status='REFUNDED', square_refund_id=?, deposit_paid=0 WHERE id=?") + db()->prepare("UPDATE bookings SET square_payment_status='REFUNDED', square_refund_id=?, deposit_paid=0, status='cancelled' WHERE id=?") ->execute([$resp['refund']['id'], $id]); echo json_encode(['ok'=>true,'status'=>'REFUNDED']); } else { @@ -686,12 +686,12 @@ textarea.notes-ta:focus{border-color:#f97316} -
+
-
+
@@ -812,7 +812,29 @@ textarea.notes-ta:focus{border-color:#f97316}
- + +
+
+ +
+
+ Driver's License Verified + + + + +
+ +
+ +
+
+ +
@@ -853,14 +876,18 @@ textarea.notes-ta:focus{border-color:#f97316}
- - + + + + - - + + + +
- -
-
- -
-
- Driver's License Verified - - - - -
- -
- -
-
-
@@ -1010,14 +1015,14 @@ textarea.notes-ta:focus{border-color:#f97316} > Bring proof of insurance - +
+
+
+ +
+
+ Driver's License Verified + + + + +
+ +
+ +
+
+
@@ -1316,9 +1341,9 @@ textarea.notes-ta:focus{border-color:#f97316}
- + - +
-
-
- -
-
- Driver's License Verified - - - - -
- -
- -
-
-
Pre-Departure
@@ -1532,7 +1537,7 @@ function toggleReq(id, field, btn) { const icon = document.getElementById('icon-'+id+'-'+field); if (icon) { icon.className = 'flow-icon ' + (on ? 'done' : 'pending'); - const stepNums = {insurance_verified:'4', deposit_received:'5', license_verified:'6', helmet_provided:'7', safety_course:'8', operational_course:'9'}; + const stepNums = {insurance_verified:'4', license_verified:'5', deposit_received:'6', helmet_provided:'7', safety_course:'8', operational_course:'9'}; icon.textContent = on ? '✓' : (stepNums[field] || '?'); } // Update meta text @@ -1624,8 +1629,8 @@ function squareAction(id, action, btn) { const [orig, working, done] = labels[action]; const confirmMsg = { square_capture: 'Charge the $ deposit hold to this card?', - square_void: 'Void the $ deposit hold? The customer will NOT be charged.', - square_refund: 'Refund the deposit to this card?', + square_void: 'Void the $ deposit hold and CANCEL this booking? The customer will NOT be charged.', + square_refund: 'Refund the $ deposit and CANCEL this booking? This cannot be undone.', }[action]; if (!confirm(confirmMsg)) return; btn.disabled = true; @@ -1650,19 +1655,31 @@ function squareAction(id, action, btn) { if (dot) dot.className='dot dot-done'; // Replace action area with refund button const area = document.getElementById('deposit-actions-'+id); - if (area) area.innerHTML = ''; - } else if (d.status === 'CANCELED') { - if (meta) meta.textContent = 'Hold voided — no charge'; + if (area) area.innerHTML = ''; + } else if (d.status === 'CANCELED' || d.status === 'REFUNDED') { + const t = d.status === 'CANCELED' ? 'Hold voided — booking cancelled' : 'Refunded — booking cancelled'; + if (meta) meta.textContent = t; if (icon) { icon.className='flow-icon skip'; icon.textContent='—'; } if (dot) dot.className='dot dot-skip'; const area = document.getElementById('deposit-actions-'+id); if (area) area.innerHTML = ''; - } else if (d.status === 'REFUNDED') { - if (meta) meta.textContent = 'Refunded — deposit returned'; - if (icon) { icon.className='flow-icon pending'; icon.textContent='↩'; } - if (dot) dot.className='dot dot-skip'; - const area = document.getElementById('deposit-actions-'+id); - if (area) area.innerHTML = ''; + // Update booking status selects and row data-status + document.querySelectorAll('select.status-sel[data-id="'+id+'"]').forEach(sel => { + sel.value = 'cancelled'; + }); + document.querySelectorAll('tr.booking-row, tr.detail-row').forEach(row => { + const s = row.querySelector('select[data-id="'+id+'"]'); + if (s) row.dataset.status = 'cancelled'; + }); + // Update confirmed step icon + ['icon','cv-icon'].forEach(p => { + const el = document.getElementById(p+'-'+id+'-confirmed'); + if (el) { el.className='flow-icon skip'; el.textContent='—'; } + }); + ['meta','cv-meta'].forEach(p => { + const el = document.getElementById(p+'-'+id+'-confirmed'); + if (el) el.textContent = 'Cancelled'; + }); } } else { btn.textContent = orig; @@ -1830,8 +1847,8 @@ function cvSquareAction(bid, action, btn) { const [orig, working] = labels[action]; const confirmMsg = { square_capture: 'Charge the $ deposit hold to this card?', - square_void: 'Void the $ deposit hold? The customer will NOT be charged.', - square_refund: 'Refund the deposit to this card?', + square_void: 'Void the $ deposit hold and CANCEL this booking? The customer will NOT be charged.', + square_refund: 'Refund the $ deposit and CANCEL this booking? This cannot be undone.', }[action]; if (!confirm(confirmMsg)) return; btn.disabled = true; @@ -1853,13 +1870,13 @@ function cvSquareAction(bid, action, btn) { const t = 'Captured — deposit charged'; if (cvMeta) cvMeta.textContent = t; if (cvIcon) { cvIcon.className='flow-icon done'; cvIcon.textContent='✓'; } - if (cvArea) cvArea.innerHTML = ''; + if (cvArea) cvArea.innerHTML = ''; if (meta) meta.textContent = t; if (icon) { icon.className='flow-icon done'; icon.textContent='✓'; } if (dot) dot.className='dot dot-done'; - if (area) area.innerHTML = ''; - } else if (d.status === 'CANCELED') { - const t = 'Hold voided — no charge'; + if (area) area.innerHTML = ''; + } else if (d.status === 'CANCELED' || d.status === 'REFUNDED') { + const t = d.status === 'CANCELED' ? 'Hold voided — booking cancelled' : 'Refunded — booking cancelled'; if (cvMeta) cvMeta.textContent = t; if (cvIcon) { cvIcon.className='flow-icon skip'; cvIcon.textContent='—'; } if (cvArea) cvArea.innerHTML = ''; @@ -1867,15 +1884,23 @@ function cvSquareAction(bid, action, btn) { if (icon) { icon.className='flow-icon skip'; icon.textContent='—'; } if (dot) dot.className='dot dot-skip'; if (area) area.innerHTML = ''; - } else if (d.status === 'REFUNDED') { - const t = 'Refunded — deposit returned'; - if (cvMeta) cvMeta.textContent = t; - if (cvIcon) { cvIcon.className='flow-icon pending'; cvIcon.textContent='↩'; } - if (cvArea) cvArea.innerHTML = ''; - if (meta) meta.textContent = t; - if (icon) { icon.className='flow-icon pending'; icon.textContent='↩'; } - if (dot) dot.className='dot dot-skip'; - if (area) area.innerHTML = ''; + // Update booking status selects and row data-status + document.querySelectorAll('select.status-sel[data-id="'+bid+'"]').forEach(sel => { + sel.value = 'cancelled'; + }); + document.querySelectorAll('tr.booking-row, tr.detail-row').forEach(row => { + const s = row.querySelector('select[data-id="'+bid+'"]'); + if (s) row.dataset.status = 'cancelled'; + }); + // Update confirmed step icon + ['icon','cv-icon'].forEach(p => { + const el = document.getElementById(p+'-'+bid+'-confirmed'); + if (el) { el.className='flow-icon skip'; el.textContent='—'; } + }); + ['meta','cv-meta'].forEach(p => { + const el = document.getElementById(p+'-'+bid+'-confirmed'); + if (el) el.textContent = 'Cancelled'; + }); } } else { btn.textContent = orig;