Add planning docs for trade-ins, returns, tax exemptions, cycle counts, POs, bundles, backorders, barcode labels, instrument sizing, warranties, maintenance schedules, gift cards, layaway, rental agreements, and in-home trials

This commit is contained in:
Ryan Moon
2026-03-27 20:53:01 -05:00
parent 750dcf4046
commit e7853f59f2
8 changed files with 1107 additions and 27 deletions

View File

@@ -198,4 +198,183 @@ The billing service checks `store.payment_processor` to determine the flow:
id, event_id (Stripe's ID), event_type, payload (jsonb),processed_at, status (received|processed|failed), error_message, created_at
All incoming webhook events are stored before processing. This enables replay if processing fails.
All incoming webhook events are stored before processing. This enables replay if processing fails.
# 8. Gift Cards & Store Credits (MOD-GIFTCARD)
Gift cards and store credits are a premium module. Gift cards are purchasable/redeemable stored-value instruments. Store credits are system-issued balances (from returns, trade-ins, or adjustments).
## 8.1 gift_card
Column | Type | Notes
id | uuid PK |
company_id | uuid FK | Tenant scoping
card_number | varchar | Unique card identifier (printed on physical card or emailed)
pin | varchar | Nullable — optional PIN for security (hashed)
type | enum | physical | digital
initial_balance | numeric(10,2) | Original loaded amount
current_balance | numeric(10,2) | Remaining balance
status | enum | active | redeemed | expired | disabled
purchased_by_account_id | uuid FK | Nullable — who bought it
recipient_email | varchar | Nullable — for digital cards
recipient_name | varchar | Nullable
purchase_transaction_id | uuid FK | The sale transaction where card was purchased
expiry_date | date | Nullable — some jurisdictions prohibit expiry
is_reloadable | boolean | Default false
created_at | timestamptz |
updated_at | timestamptz |
## 8.2 gift_card_transaction
Append-only ledger of all balance changes on a gift card.
Column | Type | Notes
id | uuid PK |
gift_card_id | uuid FK |
transaction_type | enum | purchase | reload | redemption | refund | adjustment | expiry
amount | numeric(10,2) | Positive for loads, negative for redemptions
balance_after | numeric(10,2) | Running balance after this transaction
related_transaction_id | uuid FK | Nullable — the POS transaction where redeemed/purchased
performed_by | uuid FK | Employee
notes | text |
created_at | timestamptz |
## 8.3 store_credit
Store credits are account-level balances issued by the system, not purchasable products.
Column | Type | Notes
id | uuid PK |
company_id | uuid FK |
account_id | uuid FK | Account that holds the credit
reason | enum | return | trade_in | adjustment | promotion | gift_card_conversion
original_amount | numeric(10,2) |
remaining_balance | numeric(10,2) |
issued_by | uuid FK | Employee who issued
related_return_id | uuid FK | Nullable — if from a return
related_trade_in_id | uuid FK | Nullable — if from a trade-in
expires_at | timestamptz | Nullable — configurable expiry
status | enum | active | depleted | expired | voided
created_at | timestamptz |
updated_at | timestamptz |
## 8.4 store_credit_transaction
Append-only ledger for store credit balance changes.
Column | Type | Notes
id | uuid PK |
store_credit_id | uuid FK |
transaction_type | enum | issued | applied | adjustment | expired | voided
amount | numeric(10,2) |
balance_after | numeric(10,2) |
related_transaction_id | uuid FK | Nullable
performed_by | uuid FK |
created_at | timestamptz |
## 8.5 POS Integration
- Gift card sold as a product at POS — triggers gift_card creation with initial balance
- Gift card redemption is a payment method: customer presents card, balance checked, amount deducted
- Partial redemption supported — remaining balance stays on card
- Split tender: gift card covers part, remaining on card/cash
- Store credit auto-applied: when account has credit balance, POS prompts "Apply $X.XX store credit?"
- Both gift card and store credit balances visible on account summary
## 8.6 Business Rules
- Gift card numbers generated with check digit to prevent typos
- Physical cards activated at POS — not active until purchased (prevents theft of unactivated cards)
- Digital cards emailed immediately with card number and optional message
- Gift card balance inquiries available at POS and customer portal
- Expiry rules vary by jurisdiction — configurable per company, default: no expiry
- Store credits cannot be cashed out — applied to purchases only
- All balance changes are append-only ledger entries — no direct balance edits
- Gift card liability tracked for accounting: total outstanding balances reported as liability
- Reloadable gift cards allow additional value to be added after purchase
# 9. Layaway & Payment Plans (MOD-LAYAWAY)
Layaway allows a customer to reserve an item with a deposit and pay it off over time. The item is held (not available for sale) until fully paid.
## 9.1 layaway
Column | Type | Notes
id | uuid PK |
company_id | uuid FK | Tenant scoping
location_id | uuid FK |
layaway_number | varchar | Human-readable ID (auto-generated)
account_id | uuid FK |
status | enum | active | completed | defaulted | cancelled
total_price | numeric(10,2) | Full price of items on layaway
deposit_amount | numeric(10,2) | Initial deposit collected
amount_paid | numeric(10,2) | Total paid to date (including deposit)
balance_remaining | numeric(10,2) | total_price - amount_paid
payment_frequency | enum | weekly | biweekly | monthly
next_payment_date | date | Next scheduled payment
payment_amount | numeric(10,2) | Scheduled payment amount per period
max_duration_days | integer | Maximum days to complete layaway (e.g. 90)
expires_at | date | Deposit date + max_duration_days
cancellation_fee | numeric(10,2) | Fee charged if customer cancels (configurable)
notes | text |
created_by | uuid FK |
created_at | timestamptz |
updated_at | timestamptz |
## 9.2 layaway_item
Column | Type | Notes
id | uuid PK |
layaway_id | uuid FK |
product_id | uuid FK |
inventory_unit_id | uuid FK | Nullable — for serialized items, unit is reserved
description | varchar |
qty | integer |
unit_price | numeric(10,2) |
line_total | numeric(10,2) |
created_at | timestamptz |
## 9.3 layaway_payment
Column | Type | Notes
id | uuid PK |
layaway_id | uuid FK |
transaction_id | uuid FK | The POS transaction for this payment
amount | numeric(10,2) |
balance_after | numeric(10,2) | Remaining balance after payment
payment_number | integer | 1, 2, 3... sequential
is_deposit | boolean | True for initial deposit
paid_at | timestamptz |
created_at | timestamptz |
## 9.4 Layaway Workflow
1. Customer selects items — staff creates layaway with deposit (minimum deposit configurable, e.g. 20%)
2. Serialized items: inventory_unit.status set to "layaway" (held, not available for sale)
3. Non-serialized items: qty reserved (decremented from available)
4. Customer makes scheduled payments at POS — each payment recorded as layaway_payment
5. When balance reaches $0: layaway completed, items released to customer, standard sale transaction created
6. Missed payments: system sends reminders at configurable intervals
7. Default: after configurable missed payments or past expiry — manager reviews for cancellation
## 9.5 Cancellation
- Customer-initiated cancellation: deposit refunded minus cancellation fee, items returned to available inventory
- Default cancellation (non-payment): same as above, but store may retain more of deposit per policy
- Cancellation fee configurable per company — can be fixed amount or percentage of amount paid
- All payments refunded via original payment method or store credit (store's choice per policy)
## 9.6 Business Rules
- Minimum deposit enforced (configurable — default 20% of total)
- Items on layaway are held — not available for sale to other customers
- Price locked at layaway creation — price changes don't affect existing layaways
- Payment reminders sent before due date (configurable: 3 days before default)
- Overdue payments flagged on dashboard — staff follows up
- Layaway report: active layaways, total held value, upcoming payments, overdue accounts
- Maximum layaway duration configurable per company (default 90 days)
- Layaway items can be exchanged (size swap) with manager approval — price difference adjusted