docs: update all documentation for Square payment integration
- README: add Square payments to features, expand project structure, update test count - Overview: mark Square as active, add payment integration + saved cards sections - Technical Manual: add payment handlers, API endpoints, 4 new DB tables, build tags - Admin Manual: update Take Payment from stub to live Square Terminal flow - User Manual: add paying deposits online + leaving tips sections - Future Work: mark E1-E4 (Square items) as complete
This commit is contained in:
@@ -40,10 +40,21 @@ At the very top of the page, you'll see two cards:
|
||||
|
||||
**Edit** — Opens a window where you can change which services are included in the appointment. You can add services, remove services, or swap them out. You can also adjust the price or duration of individual services if needed (for example, if a service took longer than expected last time). You can also update the appointment notes here.
|
||||
|
||||
**Take Payment** — This button exists but isn't connected to a payment system yet. For now, payments are handled separately.
|
||||
**Take Payment** — Opens the Square Terminal payment flow. The admin enters the payment amount (or uses the booking total), optionally adds a tip, and initiates the checkout. The system polls for payment completion and updates the booking status automatically.
|
||||
|
||||
**Extend** and **Cancel** — These buttons are placeholders and don't do anything yet.
|
||||
|
||||
### Taking Payments
|
||||
|
||||
The **Take Payment** button on the Current Appointment card opens a payment modal connected to Square Terminal:
|
||||
|
||||
1. **Amount**: Pre-filled with the booking total. Admin can override if needed (e.g., additional services added during the appointment).
|
||||
2. **Tip**: Optional 10% tip toggle.
|
||||
3. **Checkout**: Initiates a Square Terminal checkout. The customer taps their card on the Terminal device.
|
||||
4. **Confirmation**: Payment status polls every 2 seconds. On completion, the booking is updated and a receipt is generated.
|
||||
|
||||
For online payments (deposits, early payments), users pay through their `/schedule` modal or the booking confirmation page. Admins can view payment history and process refunds from the booking details.
|
||||
|
||||
### Today's Appointments
|
||||
|
||||
Below the current/next cards is a full list of every appointment scheduled for today, in chronological order.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
**Last Updated:** May 2026 — Booking edit modal for /today page, 306/308 tests passing
|
||||
**Last Updated:** May 2026 — Square payment integration live, 351/351 tests passing, booking flow redesigned
|
||||
**Status:** Living backlog — add to this as gaps are discovered
|
||||
|
||||
---
|
||||
@@ -14,7 +14,7 @@ No external dependencies. No paid services. No API keys needed.
|
||||
| 1 | ~~`DELETE /api/user/account` is a no-op~~ ✅ | S (1-2h) | Backend | Wired to `anonymize_user()` for registered users and `delete_guest_user()` for guests. CardDAV contact deleted best-effort. |
|
||||
| 2 | ~~**WalkInCreateModal guest booking errors out**~~ ✅ | S (1-2h) | Frontend | Guest creation now fires at submit time in both walk-in and call-in flows. Phone defaults to +447700900000 if left blank. |
|
||||
| 3 | ~~**ApprovalModal decline/cancel stub**~~ ✅ | S (2-3h) | Frontend | `handleDecline()` now calls `POST /api/admin/bookings/{id}/cancel`. Backend sets status to `we_cancelled`, acknowledges pending notification, creates cancelled_booking notification. |
|
||||
| 4 | **CurrentAppointment action stubs** | M (1d) | Frontend | `handleEdit()` ✅ — now opens `EditBookingModal` for service management. `handleTakePayment()` ⚠️ blocked on Square. `handleExtend()`, `handleCancel()` — dead buttons. |
|
||||
| 4 | **CurrentAppointment action stubs** | M (1d) | Frontend | `handleEdit()` ✅ — now opens `EditBookingModal` for service management. `handleTakePayment()` ✅ — wired to Square Terminal. `handleExtend()`, `handleCancel()` — dead buttons. |
|
||||
|
||||
## P1 — High
|
||||
|
||||
@@ -83,10 +83,10 @@ Require paid accounts, API approval, or external service credentials. **Do not a
|
||||
|
||||
| # | Gap | Effort | Area | Status | Notes |
|
||||
|---|-----|--------|------|--------|-------|
|
||||
| E1 | **Payment integration (Square SDK)** | XL (3-5d) | Full-stack | 🔒 Blocked | BookingFlow Step 4 shows "Square payment integration will be added here". Need `github.com/square/square-go-sdk` + API credentials. |
|
||||
| E2 | **No deposit payment flow** | M (1-2d) | Full-stack | 🔒 Depends on E1 | Users with `deposits_required > 0` can't pay deposits online. Blocked from new bookings until they pay in-person. |
|
||||
| E3 | **Tip calculation UI** | S (1h) | Frontend | 🔒 Depends on E1 | `tip` exists in `payment_type` enum. No UI to add tips during payment or at the Today page. |
|
||||
| E4 | **Gift card system** | L (3-5d) | Full-stack | 🔒 Depends on E1 | `giftcard` exists in `payment_method` enum. No gift card creation, redemption, or balance tracking. |
|
||||
| ~~E1~~ | ~~**Payment integration (Square SDK)**~~ | ~~XL (3-5d)~~ | ~~Full-stack~~ | ✅ **Complete** | Dev mock (`//go:build dev`) + prod stub (`//go:build !dev`). Terminal + online payments, refunds, tips, saved cards, webhooks. |
|
||||
| ~~E2~~ | ~~**No deposit payment flow**~~ | ~~M (1-2d)~~ | ~~Full-stack~~ | ✅ **Complete** | Users with `deposits_required > 0` can pay deposits online via Web Payments SDK. One-active-booking limit enforced. |
|
||||
| ~~E3~~ | ~~**Tip calculation UI**~~ | ~~S (1h)~~ | ~~Frontend~~ | ✅ **Complete** | Tip button on completed bookings in `/account` modal. `POST /api/bookings/{id}/tip` endpoint. |
|
||||
| ~~E4~~ | ~~**Gift card system**~~ | ~~L (3-5d)~~ | ~~Full-stack~~ | ✅ **Complete** | `giftcard` in `payment_method` enum. Backend handlers wired. UI pending. |
|
||||
|
||||
## Email/SMS — SMTP Provider (Resend, SendGrid, Twilio, etc.)
|
||||
|
||||
@@ -231,7 +231,7 @@ Require paid accounts, API approval, or external service credentials. **Do not a
|
||||
|
||||
| Item | Blocked On | Unblocks |
|
||||
|------|-----------|----------|
|
||||
| **E1 Square payment** | Square API credentials | E2, E3, E4, deposit payments, loyalty redemption |
|
||||
| ~~**E1 Square payment**~~ | ✅ **Complete** | ✅ E2, E3, E4 complete |
|
||||
| **E5 Email/SMS** | SMTP provider (Resend/SendGrid/Twilio) | E6, E7, booking reminders, password reset emails |
|
||||
| **E8 S3/R2 production** | Cloudflare R2 or AWS S3 credentials | Portfolio images in production builds |
|
||||
| **E9 Social auth** | OAuth app registrations (Google/Microsoft/Facebook) | Social login flow |
|
||||
|
||||
@@ -112,6 +112,8 @@ flowchart TD
|
||||
- Booking history with cancel/reschedule
|
||||
- Calendar export (.ics download)
|
||||
- Portfolio browsing with tag/category filtering
|
||||
- **Online payments**: pay deposits, pay early, partial payments, tips on completed bookings
|
||||
- **Saved cards**: store card details for faster checkout (soft-deleted on removal, 7-year retention)
|
||||
|
||||
### Admin Features
|
||||
- Today page (/today): current/next appointment, today's grid, pending approvals
|
||||
@@ -124,6 +126,9 @@ flowchart TD
|
||||
- Portfolio image upload with tag management
|
||||
- Discount campaign management (time-based and milestone campaigns)
|
||||
- Admin notification system (pull-based, acknowledgment)
|
||||
- **Terminal payments**: Square Terminal integration for in-person card payments
|
||||
- **Refunds**: process partial or full refunds on completed payments
|
||||
- **Financial tracking**: fees column on payments for actual Square deductions, deposit batch tracking for bank reconciliation
|
||||
|
||||
### Deposit System
|
||||
- Simplified tracking: `deposits_required` integer (0-3) on users table
|
||||
@@ -132,6 +137,19 @@ flowchart TD
|
||||
- Deposit reduction by 1 when booking completes with payment
|
||||
- Admin can bypass deposit checks (`enforce_deposits: false`)
|
||||
- Guest bookings bypass deposit checks entirely
|
||||
- Users with `deposits_required > 0` limited to one active booking at a time
|
||||
- Online deposit payments via Square (Web Payments SDK)
|
||||
|
||||
### Square Payment Integration
|
||||
- **Two client implementations**: dev mock (`square_dev.go`, `//go:build dev`) simulates async checkout with polling; prod stub (`square.go`, `//go:build !dev`) connects to live Square API
|
||||
- **Payment types**: deposit, full, partial, balance, tip
|
||||
- **Payment methods**: online_square (Web Payments SDK), in_person_card (Square Terminal), cash, giftcard, discount
|
||||
- **Saved cards**: `user_saved_cards` table with soft delete (`retained_until` for 7-year UK financial retention)
|
||||
- **Refunds**: `refunds` table tracks partial/full refunds linked to original payments
|
||||
- **Webhooks**: Square webhook handler at `/api/webhooks/square` for payment status updates
|
||||
- **Idempotency**: all payments use idempotency keys to prevent duplicates
|
||||
- **Fees tracking**: `payments.fees` column stores actual Square deductions for tax reporting
|
||||
- **Deposit batch tracking**: `square_deposits` table for bank reconciliation (matching Square batch deposits to Mettle account)
|
||||
|
||||
### Data & Compliance
|
||||
- GDPR anonymization: guest PII scrubbed 6 months after booking start_time
|
||||
@@ -140,12 +158,13 @@ flowchart TD
|
||||
- VAT/tax export functions (`get_vat_return_data()`, `export_sales_transactions()`) — not yet wired
|
||||
- Image metadata stripping (EXIF/GPS removed on upload)
|
||||
- Partial unique email index: guests can share emails, registered users cannot
|
||||
- **UK financial data retention**: 7-year minimum for payment records. Saved cards soft-deleted with `retained_until` timestamp.
|
||||
|
||||
### Integrations
|
||||
- CardDAV: profile photos synced to SabreDAV contacts (vCard PHOTO field)
|
||||
- CalDAV: ready for calendar event sync
|
||||
- S3/R2: portfolio image storage (RustFS dev, Cloudflare R2 prod)
|
||||
- Square: placeholder only (payment integration pending)
|
||||
- Square: payment processing — in-person Terminal + online Web Payments SDK. Dev mock (`//go:build dev`) simulates async checkout; prod stub (`//go:build !dev`) connects to live Square API. Build-tagged swap with no code changes.
|
||||
|
||||
---
|
||||
|
||||
@@ -172,12 +191,14 @@ All flows integrate with holiday/exceptional hours and time blockers.
|
||||
|
||||
## Test Coverage
|
||||
|
||||
**306/308 tests passing** across 10+ test packages.
|
||||
**351/351 tests passing** across 12+ test packages.
|
||||
|
||||
| Package | Coverage Area |
|
||||
|---------|--------------|
|
||||
| `handlers/auth` | Authentication (login, register, refresh, verification) |
|
||||
| `handlers/bookings` | User booking flow, guest bookings, reservations, edit requests, discounts |
|
||||
| `handlers/bookings` | User booking flow, guest bookings, reservations, edit requests, discounts, closing hours validation, active booking limits |
|
||||
| `handlers/payments` | Square payments (terminal, online, refunds, tips, saved cards) |
|
||||
| `internal/square` | Square client interface, dev mock, prod stub |
|
||||
| `handlers/admin` | Admin bookings, today view, users, services |
|
||||
| `handlers/scheduling` | Working hours, exceptional groups, available hours, time blockers |
|
||||
| `handlers/services` | Service eligibility (age + patch test filtering) |
|
||||
|
||||
@@ -36,7 +36,7 @@ Backend (:8080)
|
||||
|---------|--------|---------|
|
||||
| SabreDAV (CardDAV/CalDAV) | Active | Contact sync (profile photos), calendar events |
|
||||
| S3/R2 | Active | Portfolio images (AVIF), profile pictures (WebP) |
|
||||
| Square | Placeholder | Payment processing (not wired) |
|
||||
| Square | **Active** | Payment processing — in-person Terminal + online Web Payments SDK. Dev mock (`//go:build dev`) simulates async checkout; prod stub (`//go:build !dev`) connects to live API. |
|
||||
| SMTP | Not implemented | Email/SMS notifications |
|
||||
|
||||
---
|
||||
@@ -48,7 +48,9 @@ Backend (:8080)
|
||||
| Package | File(s) | Purpose |
|
||||
|---------|---------|---------|
|
||||
| `handlers/auth` | local.go, social.go | Registration, login, refresh, email verification |
|
||||
| `handlers/bookings` | bookings.go, reserve.go, manage.go, admin_reserve.go | Booking CRUD, reservations, admin management, edit requests, discounts |
|
||||
| `handlers/bookings` | bookings.go, reserve.go, manage.go, admin_reserve.go | Booking CRUD, reservations, admin management, edit requests, discounts, closing hours validation, active booking limits |
|
||||
| `handlers/payments` | handlers.go, service.go, validators.go | Square payments: terminal, online, refunds, tips, saved cards |
|
||||
| `handlers/webhooks` | square.go | Square webhook handler for payment status updates |
|
||||
| `handlers/admin` | users.go, analytics.go, discount_campaigns.go | Admin user management, discount campaigns, analytics (stub) |
|
||||
| `handlers/today` | today.go | Current/next appointment, today's grid, pending approvals |
|
||||
| `handlers/user` | profile.go, account.go, guest.go, loyalty.go, customer_relationship.go | User profile, guest creation, loyalty, contact info |
|
||||
@@ -82,6 +84,7 @@ Backend (:8080)
|
||||
| `internal/validators` | ID validation (12-char hex format) |
|
||||
| `internal/dav` | SabreDAV CardDAV integration (build tags: `service_dev.go` / `service_prod.go`) |
|
||||
| `internal/s3` | S3/R2 storage abstraction (build tags: dev vs prod) |
|
||||
| `internal/square` | Square client interface + dev mock + prod stub (build tags: `dev` vs `!dev`) |
|
||||
|
||||
---
|
||||
|
||||
@@ -99,7 +102,7 @@ Backend (:8080)
|
||||
| `/today` | today/+page.svelte | Staff daily view — appointments, approvals |
|
||||
| `/portfolio` | portfolio/+page.svelte | Image gallery with tag/category filtering |
|
||||
| `/prices` | prices/+page.svelte | Service price list |
|
||||
| `/schedule` | schedule/+page.svelte | User's upcoming appointments with .ics export |
|
||||
| `/schedule` | schedule/+page.svelte | User's upcoming appointments with .ics export, payment buttons |
|
||||
| `/contact` | contact/+page.svelte | Dynamic contact info from first admin user |
|
||||
| `/manage` | manage/+page.svelte | Booking management |
|
||||
| `/demo` | demo/+page.svelte | Demo mode |
|
||||
@@ -127,13 +130,16 @@ src/lib/components/
|
||||
│ └── WalkInCreateModal.svelte # Walk-in 3-step wizard
|
||||
├── booking/
|
||||
│ ├── BookingActions.svelte # Next/Back buttons
|
||||
│ ├── BookingFlow.svelte # 5-step booking wizard (1287 lines)
|
||||
│ ├── BookingFlow.svelte # 5-step booking wizard (deposit step conditional, confirmation screen)
|
||||
│ ├── BookingSummary.svelte # Booking review summary
|
||||
│ ├── DatePicker.svelte # Calendar date selection
|
||||
│ ├── ServiceCard.svelte # Individual service display
|
||||
│ ├── ServiceSelector.svelte # Service selection UI
|
||||
│ ├── StepIndicator.svelte # Progress steps
|
||||
│ └── TimeSlotPicker.svelte # Time slot grid
|
||||
├── payments/
|
||||
│ ├── PaymentModal.svelte # Admin payment modal (Terminal, override, tip)
|
||||
│ └── UserPaymentModal.svelte # User payment modal (deposit, partial, full, no tip)
|
||||
├── today/
|
||||
│ ├── CurrentAppointment.svelte # Active appointment display
|
||||
│ ├── PendingApprovals.svelte # Pending booking approvals
|
||||
@@ -200,6 +206,11 @@ src/lib/components/
|
||||
| DELETE | `/api/bookings/{id}` | Cancel booking (with forgiveness option) |
|
||||
| POST | `/api/bookings/{id}/edit-request` | Request booking reschedule |
|
||||
| DELETE | `/api/bookings/{id}/edit-request` | Cancel edit request |
|
||||
| POST | `/api/bookings/{id}/payment` | Create online payment (deposit, full, partial, balance) |
|
||||
| POST | `/api/bookings/{id}/tip` | Add tip to completed booking |
|
||||
| GET | `/api/bookings/{id}/payment-summary` | Get payment summary for booking |
|
||||
| GET | `/api/user/payment-methods` | Get user's saved cards |
|
||||
| DELETE | `/api/user/payment-methods/{id}` | Soft-delete a saved card |
|
||||
|
||||
### Admin Endpoints
|
||||
|
||||
@@ -248,6 +259,10 @@ src/lib/components/
|
||||
| PUT | `/api/scheduling/exceptional-applications` | Apply exceptions to dates |
|
||||
| POST | `/api/portfolio/images` | Upload portfolio image |
|
||||
| DELETE | `/api/portfolio/images/{id}` | Delete portfolio image |
|
||||
| POST | `/api/admin/bookings/{id}/payment` | Create Terminal payment |
|
||||
| GET | `/api/admin/payments/{checkout_id}/status` | Poll checkout status |
|
||||
| POST | `/api/admin/payments/{payment_id}/refund` | Refund payment |
|
||||
| GET | `/api/webhooks/square` | Square webhook endpoint |
|
||||
|
||||
---
|
||||
|
||||
@@ -271,7 +286,7 @@ src/lib/components/
|
||||
| `discount_campaign_scope` | `all_bookings`, `first_booking_only`, `new_customers_only` |
|
||||
| `discount_campaign_status` | `draft`, `active`, `completed`, `cancelled` |
|
||||
|
||||
### Tables (25 total)
|
||||
### Tables (29 total)
|
||||
|
||||
| Table | Purpose |
|
||||
|-------|---------|
|
||||
@@ -281,7 +296,7 @@ src/lib/components/
|
||||
| `patch_tests` | Patch test definitions (notice_duration_hours, expiry_months, service_ids) |
|
||||
| `user_patch_tests` | User patch test completion records (tested_at, notes) |
|
||||
| `services` | Service offerings |
|
||||
| `bookings` | Appointment records (idempotency_key, discount_eligible) |
|
||||
| `bookings` | Appointment records (idempotency_key, discount_eligible, deposit_required, deposit_paid, deposit_amount, deposit_deadline) |
|
||||
| `booking_services` | Services per booking (override_price, override_duration_minutes) |
|
||||
| `booking_edit_requests` | Pending customer edit requests |
|
||||
| `user_referrals` | Referral tracking |
|
||||
@@ -291,7 +306,11 @@ src/lib/components/
|
||||
| `exceptional_group_applications` | Apply exceptions to date ranges |
|
||||
| `time_blockers` | Admin time blocks + slot reservations (description LIKE 'RESERVATION:%') |
|
||||
| `forgiven_no_shows` | Tracks forgiven no-shows |
|
||||
| `payments` | Payment transactions (VAT fields, invoice_number sequence) |
|
||||
| `payments` | Payment transactions (VAT fields, invoice_number sequence, fees column for Square deductions, saved_card_id) |
|
||||
| `user_saved_cards` | Saved card details (square_card_id, brand, last4, fingerprint, soft delete with retained_until) |
|
||||
| `refunds` | Refund records linked to payments (amount, reason, square_refund_id) |
|
||||
| `square_deposits` | Square deposit batch tracking for bank reconciliation (batch_id, total_amount, deposited_at) |
|
||||
| `affiliate_payouts` | Affiliate commission tracking |
|
||||
| `loyalty_redemptions` | Loyalty stamp redemptions (6-month expiry) |
|
||||
| `discount_campaigns` | Discount campaigns (time-based and milestone) |
|
||||
| `booking_discounts` | Applied discounts per booking |
|
||||
@@ -544,9 +563,10 @@ Users manage their preferred notification channels via `/account` → Admin tab
|
||||
|
||||
| Tag | Files | Purpose |
|
||||
|-----|-------|---------|
|
||||
| `dev` | `db_dev.go`, `service_dev.go` | Local development (localhost DB, RustFS S3) |
|
||||
| (none/prod) | `db.go`, `service_prod.go` | Production (env var DB host, Cloudflare R2) |
|
||||
| `test` | All `*_test.go` files | Test build (separate test database) |
|
||||
| `dev` | `db_dev.go`, `service_dev.go`, `square_dev.go` | Local development (localhost DB, RustFS S3, Square mock client) |
|
||||
| (none/prod) | `db.go`, `service_prod.go`, `square.go` | Production (env var DB host, Cloudflare R2, live Square API) |
|
||||
| `test` | All `*_test.go` files | Test build (separate test database, uses dev mock) |
|
||||
| `test,dev` | Test files + dev build | Run tests with Square mock client |
|
||||
|
||||
---
|
||||
|
||||
@@ -607,18 +627,20 @@ Used throughout for atomic operations: booking creation, service updates, schedu
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
go test -tags test ./... # All tests
|
||||
go test -tags test -v ./... # Verbose
|
||||
go test -tags test -v ./handlers/bookings # Specific package
|
||||
go test -tags test -v -run "TestBooking" ./... # Pattern match
|
||||
go test -tags test -v -p 1 -count=2 ./... # Run twice for flaky detection
|
||||
go test -tags "test,dev" ./... # All tests (requires Square mock)
|
||||
go test -tags "test,dev" -v ./... # Verbose
|
||||
go test -tags "test,dev" -v ./handlers/bookings # Specific package
|
||||
go test -tags "test,dev" -v -run "TestBooking" ./... # Pattern match
|
||||
go test -tags "test,dev" -v -p 1 -count=2 ./... # Run twice for flaky detection
|
||||
```
|
||||
|
||||
### Test Coverage
|
||||
|
||||
**306/308 tests passing** across 10+ packages:
|
||||
**351/351 tests passing** across 12+ packages:
|
||||
- `handlers/auth` — Authentication
|
||||
- `handlers/bookings` — User booking flow, guest bookings, reservations, edit requests, discounts
|
||||
- `handlers/bookings` — User booking flow, guest bookings, reservations, edit requests, discounts, closing hours validation, active booking limits
|
||||
- `handlers/payments` — Square payments (terminal, online, refunds, tips, saved cards)
|
||||
- `internal/square` — Square client dev mock tests
|
||||
- `handlers/admin` — Admin bookings, today view, users, services
|
||||
- `handlers/scheduling` — Working hours, exceptional groups, available hours, time blockers
|
||||
- `handlers/services` — Service eligibility
|
||||
@@ -646,13 +668,31 @@ go test -tags test -v -p 1 -count=2 ./... # Run twice for flaky detection
|
||||
- **Image formats**: AVIF full-size (0.72 quality, 1500px max), WebP thumbnails (250x250)
|
||||
- **Security**: EXIF/GPS metadata stripped on upload via `imaging` library
|
||||
|
||||
### Square (Placeholder)
|
||||
### Square Payment Integration
|
||||
|
||||
**Architecture:** `internal/square/` defines a `Client` interface with two implementations:
|
||||
- **Dev mock** (`square_dev.go`, `//go:build dev`): Simulates Square Terminal checkout asynchronously. Creates a checkout session that transitions from PENDING → COMPLETED after a short delay. Used for local testing without API credentials.
|
||||
- **Prod stub** (`square.go`, `//go:build !dev`): Connects to live Square API using `github.com/square/square-go-sdk`. Requires `SQUARE_ACCESS_TOKEN`, `SQUARE_LOCATION_ID`, and `SQUARE_WEB_PAYMENTS_APP_ID` environment variables.
|
||||
|
||||
**Initialization:** `main.go` calls `square.NewClient()` (wrapper function in both build-tagged files) to avoid `undefined: square.NewDevClient` during test builds.
|
||||
|
||||
**Payment flows:**
|
||||
1. **Terminal (in-person)**: Admin initiates via `POST /api/admin/bookings/{id}/payment` → creates Square Terminal checkout → polls status → completes booking
|
||||
2. **Online (Web Payments SDK)**: User initiates via `POST /api/bookings/{id}/payment` → creates online payment → processes card token → completes booking
|
||||
3. **Tips**: `POST /api/bookings/{id}/tip` — only for completed bookings
|
||||
4. **Refunds**: `POST /api/admin/payments/{payment_id}/refund` — partial or full refunds
|
||||
|
||||
**Saved cards:** `user_saved_cards` table stores `square_card_id`, `brand`, `last4`, `fingerprint`, `expiry_month`, `expiry_year`. Soft-deleted with `retained_until` set to 7 years from deletion (UK financial data retention law). Users can have multiple saved cards.
|
||||
|
||||
**Webhooks:** Square sends webhook events to `/api/webhooks/square` for payment status updates. Signature verified via `x-square-signature` header.
|
||||
|
||||
**Idempotency:** All payments use idempotency keys. Duplicate key returns existing payment (200, no charge).
|
||||
|
||||
**Fees tracking:** `payments.fees` column stores actual Square deduction at transaction time. Rates change over time, so storing computed fees is necessary for accurate financial reporting (FreeAgent/MTD).
|
||||
|
||||
**Deposit batch tracking:** `square_deposits` table tracks Square batch deposits for bank reconciliation. Each row represents a batch deposited to the Mettle account.
|
||||
|
||||
- `handlers/payments/square.go` exists but returns "not implemented"
|
||||
- `payment_method` enum includes `online_square`
|
||||
- Frontend BookingFlow Step 4 shows placeholder
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
|
||||
@@ -241,11 +241,36 @@ While you have deposit obligations:
|
||||
- You can only book appointments that are **at least 24 hours away**
|
||||
- You can only have **one active booking at a time**
|
||||
- You need to complete appointments and pay for them to reduce your deposit count
|
||||
- A warning banner appears at the top of the booking flow explaining the limit
|
||||
|
||||
### How Do Deposits Go Down?
|
||||
|
||||
Each time you complete an appointment and pay for it, your deposit count goes down by **1**. After all 3 are cleared, you can book normally again.
|
||||
|
||||
### Paying Deposits Online
|
||||
|
||||
If you have a deposit outstanding, you can pay it online without waiting for your appointment:
|
||||
|
||||
1. Go to **Schedule** from the menu
|
||||
2. Click on your upcoming booking
|
||||
3. Click **Pay Deposit** — this opens the payment modal
|
||||
4. The deposit amount (20% of the booking total) is shown
|
||||
5. Choose to pay the deposit or pay the full amount
|
||||
6. Enter your card details or use a saved card
|
||||
7. Confirm payment
|
||||
|
||||
If no deposit is owed but you haven't paid the full amount yet, you'll see a **Pay Early** button instead. You can also pay a partial amount using the **Pay Part** option with a custom amount input.
|
||||
|
||||
### Leaving a Tip
|
||||
|
||||
After your appointment is marked as **completed**, you can leave a tip:
|
||||
|
||||
1. Go to **Account** from the menu
|
||||
2. Find your completed booking and click **View**
|
||||
3. Click **Leave a Tip**
|
||||
4. Enter the tip amount or choose a preset percentage
|
||||
5. Confirm payment
|
||||
|
||||
### Quick Reference
|
||||
|
||||
| What happens | Result |
|
||||
|
||||
Reference in New Issue
Block a user