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

@@ -232,4 +232,133 @@ When billing_group is null, the rental has its own independent Stripe subscripti
- Final invoice generated for any partial month charges
- If damage found, repair ticket created automatically and linked to rental record
- If damage found, repair ticket created automatically and linked to rental record
# 7. Rental Agreement Contracts
Every rental requires a signed agreement before the instrument leaves the store. Agreements are generated from templates, capture all rental terms, and are stored as signed documents.
## 7.1 rental_agreement_template
Store-configurable contract templates. Most stores have one template per rental type, but can create variations for schools, events, etc.
Column | Type | Notes
id | uuid PK |
company_id | uuid FK | Tenant scoping
name | varchar | e.g. "Standard Month-to-Month", "School RTO Agreement", "Short-Term Event Rental"
rental_type | enum | month_to_month | rent_to_own | short_term | lease_purchase | all
body | text | Contract body with merge fields (see §7.3)
requires_signature | boolean | Default true — some internal/school agreements may waive
requires_guardian_signature | boolean | Default true if member.is_minor
include_insurance_terms | boolean | Whether insurance section is included
include_rto_terms | boolean | Whether rent-to-own buyout terms are included
include_damage_policy | boolean | Whether damage/loss liability section is included
is_default | boolean | Default template for this rental_type
is_active | boolean |
created_at | timestamptz |
updated_at | timestamptz |
## 7.2 rental_agreement
A generated, signed agreement instance linked to a specific rental.
Column | Type | Notes
id | uuid PK |
company_id | uuid FK |
rental_id | uuid FK | The rental this agreement covers
template_id | uuid FK | Template used to generate
account_id | uuid FK |
member_id | uuid FK | Member receiving the instrument
agreement_number | varchar | Human-readable ID (auto-generated)
generated_body | text | Full rendered contract text with all merge fields resolved — immutable after signing
status | enum | draft | pending_signature | signed | voided
signed_at | timestamptz | When signature was captured
signer_name | varchar | Name of person who signed
signer_relationship | varchar | Nullable — e.g. "parent", "guardian", "self"
guardian_signed_at | timestamptz | Nullable — when guardian signed (if minor)
guardian_name | varchar | Nullable
signature_method | enum | in_store_tablet | in_store_paper | email | portal
signature_data | text | Nullable — base64 signature image for tablet/paper capture
document_url | varchar | Nullable — URL to stored PDF in object storage
ip_address | varchar | Nullable — for email/portal signatures
voided_reason | text | Nullable — why agreement was voided
voided_by | uuid FK | Nullable
created_at | timestamptz |
updated_at | timestamptz |
## 7.3 Merge Fields
Templates use merge fields that are resolved at generation time. The generated_body stores the fully resolved text so the agreement is a permanent record even if account details change later.
Field | Resolves To
{{account_name}} | account.name
{{account_email}} | account.email
{{account_phone}} | account.phone
{{account_address}} | account.address (formatted)
{{member_name}} | member.first_name + member.last_name
{{member_is_minor}} | "Yes" / "No"
{{instrument_description}} | product.name + product.brand + product.model
{{instrument_size}} | inventory_unit.instrument_size or product.instrument_size
{{serial_number}} | inventory_unit.serial_number
{{instrument_condition}} | inventory_unit.condition at rental start
{{rental_type}} | Formatted rental type name
{{monthly_rate}} | rental.monthly_rate
{{deposit_amount}} | rental.deposit_amount
{{start_date}} | rental.start_date (formatted)
{{end_date}} | rental.end_date or "Open-ended"
{{rto_purchase_price}} | rental.rto_purchase_price (if RTO)
{{rto_equity_percent}} | rental.rto_equity_percent (if RTO)
{{company_name}} | company.name
{{company_address}} | company.address
{{company_phone}} | company.phone
{{today_date}} | Current date
{{agreement_number}} | rental_agreement.agreement_number
## 7.4 Agreement Workflow
1. Staff creates rental — system selects default template for rental_type (or staff picks one)
2. Agreement generated: merge fields resolved, generated_body populated, status = "draft"
3. Staff reviews agreement on screen — can edit before finalizing if needed
4. Signature capture:
a. **In-store tablet**: customer signs on screen, signature_data captured as base64
b. **In-store paper**: staff prints, customer signs physical copy, staff scans/uploads
c. **Email**: agreement emailed to account email with secure signing link
d. **Portal**: customer signs via self-service portal (if MOD-PORTAL licensed)
5. Agreement status updated to "signed" — PDF generated and stored
6. Rental cannot activate until agreement is signed (unless overridden by manager)
7. Signed agreement PDF available on rental record, account history, and customer portal
## 7.5 Guardian Signatures
- If member.is_minor = true, agreement requires guardian signature in addition to (or instead of) member signature
- Guardian must be an adult member on the same account, or signer_relationship recorded for non-member guardian
- Both signature fields must be completed before agreement is fully signed
- Email/portal signing flow sends to account primary email (assumed to be parent/guardian)
## 7.6 Agreement Delivery
- **Print**: generated as PDF, sent to receipt printer or standard printer
- **Email**: PDF attached to email sent to account.email
- **Portal**: PDF available in customer portal under "My Agreements"
- **All signed agreements**: stored in object storage (S3-compatible), URL recorded on rental_agreement.document_url
## 7.7 Voiding and Re-signing
- Voiding an agreement requires reason and manager approval
- Voiding does not cancel the rental — but rental cannot remain active without a signed agreement
- Common void reasons: incorrect terms, wrong instrument, customer requested change
- After voiding, a new agreement is generated from template (or modified) and signed
- Voided agreements retained for audit — never deleted
## 7.8 Business Rules
- Rental cannot activate without a signed agreement (manager override available with reason logged)
- Agreement text is immutable after signing — edits require void and re-sign
- generated_body is the legal record — template changes do not affect existing agreements
- Signature data retained for the life of the agreement (minimum 7 years per record retention policy)
- Agreement PDF regenerated on demand from generated_body + signature_data — not dependent on template
- Schools with bulk rentals (MOD-BATCH): single master agreement can cover multiple instruments for a school account
- Short-term rentals may use a simplified template with fewer terms
- Agreement history visible on account record — all past and current agreements listed