From 2623b6257303616563f8297d9067ba86213e56a3 Mon Sep 17 00:00:00 2001 From: Stephen Adamson Date: Sat, 7 Mar 2026 17:41:03 +0000 Subject: [PATCH] docs: update README with comprehensive deposit system documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add new '💰 Deposit System' section with full business logic - Document 24-hour late cancellation rule - Explain optional forgive_no_show boolean for admin forgiveness - Explain optional enforce_deposits boolean for admin booking override - Document no-show accumulation (2+ in 6 months = 3 deposits) - Document deposit reduction on payment - Add API examples and implementation files reference - Update payment_type enum to include all types (deposit, full, tip, balance, partial) - Add deposit examples showing different scenarios - Update Simplified Deposits status line with current behavior - Remove outdated 48h notice reference --- README.md | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 145 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index abb6f2f..9e854bd 100644 --- a/README.md +++ b/README.md @@ -319,7 +319,7 @@ docker compose exec backend sh | Image Metadata Stripping | ✅ | ❌ | EXIF/GPS stripped on upload via `imaging` library | | Profile Pictures | ✅ | ✅ | Upload to separate bucket, cropper, circular display, CalDAV sync | | Auto-Booking Status | ✅ | ✅ | Auto-transition: confirmed → in_progress → completed based on time | -| Simplified Deposits | ✅ | ⚠️ | `deposits_required` INT on users table (3 default), 48h notice, reduces on payment | +|| Simplified Deposits | ✅ | ⚠️ | **24h late cancellation rule**: < 24h = no-show (+3 deposits, optional forgiveness), ≥ 24h = normal cancellation. Admin can bypass checks. Reduces by 1 per payment on completed booking. | Contact Page | ✅ | ✅ | Dynamic data from first admin user via `/api/contact` endpoint | | Email Verification | ✅ | ❌ | Verification codes, generate/check endpoints | | Calendar Export | ✅ | ⚠️ | ICS download endpoint, Add to Calendar button (backend complete) | @@ -373,6 +373,147 @@ All three flows integrate with the **holiday/exceptional hours** system to preve --- +## 💰 Deposit System + +### Overview + +The deposit system is a **simplified user-level tracking mechanism** that enforces a 3-deposit requirement before new bookings are allowed. It's designed to reduce booking abandonment and protect against chronic no-shows. + +**Key Concepts**: +- `deposits_required`: Integer (0-3) on users table tracking outstanding deposit obligations +- `deposit_required`: Boolean on bookings table, snapshotted at creation time +- `deposit_amount`: Calculated as 20% of booking total for display +- `deposit_paid`: True when pre-start payments cover the deposit amount + +### Cancellation Rules (Late = < 24 Hours) + +| Scenario | Time Until Start | Forgiveness | Result Status | Penalty | User Blocked? | +|----------|------------------|-------------|---------------|---------|---------------| +| **Late cancellation (normal)** | < 24h | No/Omitted | `no_show` | +3 deposits (resets to 3, not +=) | Yes* | +| **Late cancellation (forgiven)** | < 24h | Yes | `client_cancelled` | None | No | +| **Normal cancellation** | ≥ 24h | Any | `client_cancelled` | None | No | +| **Pending cancellation** | Any | Any | Deleted | None | No | + +*Assuming `deposits_required` > 0 after penalty + +### API: User Cancellation + +**Endpoint**: `PUT /api/bookings/{id}/cancel` + +**Request**: +```json +{ + "reason": "no_show", + "forgive_no_show": true // Optional: true = forgive penalty, false/omitted = enforce penalty +} +``` + +**Behavior**: +- `< 24h` without forgiveness → `status = no_show`, `deposits_required = 3` +- `< 24h` with forgiveness → `status = client_cancelled`, no penalty +- `≥ 24h` → `status = client_cancelled`, no penalty (always) + +### Admin Booking Creation with Deposit Control + +**Endpoint**: `POST /api/admin/bookings` + +**Request**: +```json +{ + "user_id": "USR123", + "start_time": "2026-03-10T10:00:00Z", + "service_ids": ["SVC1"], + "enforce_deposits": false // Optional: true (default) = enforce checks, false = bypass checks +} +``` + +**Behavior**: +- `enforce_deposits = true` (default): Apply one-active-booking limit if `deposits_required > 0` +- `enforce_deposits = false`: Bypass all deposit checks, allow multiple active bookings + +**Use Cases**: +- `true`: Standard workflow, ensure users clear deposits before booking again +- `false`: Emergency/special cases where admin needs to override deposit restrictions + +### No-Show Accumulation + +**Rule**: 2+ unforgiven no-shows in rolling 6 months → `deposits_required = 3` + +**Trigger**: Automatic via `ApplyDepositsIfNeeded()` when: +1. User has status = `no_show` (without forgiveness flag) +2. Booking occurred within last 6 months +3. Not yet marked as "forgiven" in `forgiven_no_shows` table +4. Count ≥ 2 + +**Consequence**: User blocked from new bookings (one-active-booking limit enforced) + +### Deposit Reduction + +**Rule**: When booking transitions to `completed` with ≥ 1 payment → `deposits_required -= 1` + +**Logic**: +- Minimum: 0 (never negative) +- Reduction happens once per booking (not per payment) +- User must complete bookings with payments to clear all 3 deposits + +### Deposit Fields in Booking API Response + +```json +{ + "id": "BK123", + "deposit_required": true, // Snapshot: was deposit required at booking time? + "deposit_amount": 24.50, // 20% of total_amount + "deposit_paid": false, // Sum of pre-start payments >= deposit_amount? + "deposit_deadline": "2026-03-09T10:00:00Z", // start_time - 24 hours + "total_amount": 122.50, + "amount_paid": 0.00, + "amount_due": 122.50 +} +``` + +### Implementation Files + +| File | Changes | Details | +|------|---------|----------| +| `backend/handlers/bookings/bookings.go` | Cancellation logic | 24h threshold, optional `forgive_no_show` boolean | +| `backend/handlers/bookings/manage.go` | Admin booking creation | Optional `enforce_deposits` boolean, deposit checks | +| `backend/handlers/bookings/manage.go` | Removed function | `ForgiveNoShowsForUser()` (now per-cancellation) | + +### Database Schema + +| Table | Column | Type | Purpose | +|-------|--------|------|----------| +| `users` | `deposits_required` | INT | Outstanding deposit count (0-3) | +| `bookings` | `deposit_required` | BOOLEAN | Snapshot of requirement at booking time | +| `payments` | `payment_type` | ENUM | Includes `deposit`, `full`, `tip`, `balance`, `partial` | +| `forgiven_no_shows` | `booking_id` | CHAR(12) | Tracks forgiven no-shows for 6-month accumulation | + +### Deposit Examples + +**Example 1: New User Books** +``` +User: deposits_required = 0 +→ Booking: deposit_required = false +→ Response: deposit_amount shown, but deposit_paid always false +``` + +**Example 2: User with Deposits Late Cancels** +``` +User: deposits_required = 1 +Cancels < 24h without forgiveness +→ Result: deposits_required = 3 (reset, not incremented) +→ User blocked from new bookings +``` + +**Example 3: Admin Overrides Deposits** +``` +Admin creates booking with enforce_deposits = false +User has deposits_required = 2 + active booking +→ Result: Booking created successfully +→ Deposit check bypassed +``` +--- + ## 🔍 Helpful Greps ### All Three Booking Flows @@ -498,9 +639,9 @@ grep -rn "console\.log" frontend/src/ --include="*.svelte" --include="*.ts" |------|--------| | `account_role` | `user`, `admin` | | `account_type` | `standard`, `vip`, `guest` | -| `booking_status` | `pending`, `confirmed`, `in_progress`, `completed`, `client_cancelled`, `we_cancelled`, `re-schedule`, `no_show`, `no_deposit` | -| `payment_type` | `deposit`, `full`, `refund` | -| `payment_method` | `cash`, `card`, `bank_transfer`, `square` | +|| `booking_status` | `pending`, `confirmed`, `in_progress`, `completed`, `client_cancelled`, `we_cancelled`, `re-schedule`, `no_show`, `no_deposit` | +|| `payment_type` | `deposit`, `full`, `tip`, `balance`, `partial` | +|| `payment_method` | `online_square`, `in_person_card`, `cash`, `giftcard`, `discount` | | `payment_status` | `pending`, `completed`, `failed`, `refunded` | | `admin_notification_reason` | `pending_booking`, `cancelled_booking`, `rescheduled_booking`, `1_week_no_pay`, `1_month_no_pay`, `affiliate_claim`, `late_cancellation`, `no_deposit`, `deposit_paid` |