Contract Terms & Conditions System

Overview

This document outlines the design and implementation plan for a hierarchical contract terms and conditions system that supports:

Business Requirements

Core Needs

  1. 1-3 standard base contracts - Master template agreements
  2. Product-specific terms - Different terms for different product categories (e.g., concrete lowboy vs dumpster)
  3. Vendor customization - Vendors can modify terms in their portal
  4. One-time customer acceptance - Customer accepts once per vendor/product category combination
  5. Optional site-based - Can require acceptance per delivery location
  6. Version tracking - Know when terms change and require re-acceptance

Use Cases

Data Model

1. Contract Templates (Base Agreements)

Table: contract_templates

Master templates that define the base terms and conditions for product categories.

# Fields:
- id (primary key)
- name (string) - e.g., "Standard Dumpster Rental Agreement"
- slug (string) - e.g., "standard-dumpster"
- product_category (string) - e.g., "Dumpster - Trash", "Concrete Equipment", "Portable Toilets"
- content (text) - The actual contract text (supports Markdown/HTML)
- effective_date (date) - When this version becomes active
- expires_at (date, nullable) - When this version expires
- version (integer) - Version number for tracking
- is_active (boolean) - Current active template
- created_at, updated_at (timestamps)

# Indexes:
- product_category
- slug
- is_active

Validations:


2. Vendor Contract Overrides

Table: vendor_contract_templates

Vendor-specific customizations to base templates. Vendors can override terms for their products.

# Fields:
- id (primary key)
- vendor_id (foreign key → vendors)
- base_template_id (foreign key → contract_templates, nullable)
- product_category (string) - Must match a product category
- name (string) - e.g., "ABC Dumpsters Custom Terms"
- custom_terms (text) - Vendor's custom contract text
- pricing_terms (text, nullable) - Special pricing clauses
- liability_clauses (text, nullable) - Liability modifications
- effective_date (date)
- expires_at (date, nullable)
- version (integer) - Vendor's version number
- is_active (boolean)
- approved_by_admin (boolean) - Admin must approve vendor changes
- approved_at (timestamp)
- created_at, updated_at

# Indexes:
- vendor_id
- product_category
- [vendor_id, product_category, is_active] (composite)

Business Rules:


3. Contract Acceptances (Customer Signatures)

Table: contract_acceptances

Records of customer acceptance of terms. Tracks who accepted what, when, and where.

# Fields:
- id (primary key)
- acceptable_type (string) - Polymorphic: "Company" or "Contact"
- acceptable_id (integer) - Company or Contact ID
- vendor_id (foreign key → vendors)
- product_category (string)
- contract_template_id (foreign key → contract_templates, nullable)
- vendor_contract_template_id (foreign key → vendor_contract_templates, nullable)
- address_id (foreign key → addresses, nullable) - Optional site-specific
- accepted_version (integer) - Version number accepted
- accepted_at (timestamp)
- expires_at (timestamp, nullable) - Optional expiration
- ip_address (string) - For legal compliance
- user_agent (text) - Browser info
- signature_data (text, nullable) - E-signature data (if applicable)
- signed_by_name (string) - Name of person who signed
- signed_by_email (string) - Email of person who signed
- order_id (foreign key → orders, nullable) - Order where this was accepted
- created_at, updated_at

# Indexes:
- [acceptable_type, acceptable_id]
- vendor_id
- product_category
- [vendor_id, product_category, acceptable_type, acceptable_id] (composite)
- [address_id, vendor_id, product_category] (for site-specific)

Business Rules:


4. Product Categories (Reference)

Table: product_categories (or use existing product categorization)

Standardized categories for consistent term application.

# Fields:
- id (primary key)
- name (string) - e.g., "Dumpster - Trash"
- slug (string) - e.g., "dumpster-trash"
- description (text)
- requires_terms (boolean, default: true) - Some products may not need special terms
- created_at, updated_at

# Common categories:
- "Dumpster - Trash"
- "Dumpster - Recycling"
- "Concrete Equipment - Lowboy"
- "Concrete Equipment - Mixer"
- "Portable Toilets"
- "Storage Containers"
- "Mobile Offices"

Business Logic Flow

Order Creation Flow

1. Customer selects product
   └─→ Product has product_category

2. Customer selects vendor
   └─→ System checks for applicable terms

3. Determine applicable contract:
   ├─→ Check: Does vendor have custom template for this category?
   │   ├─→ YES: vendor_contract_template_id = vendor's custom template
   │   └─→ NO: contract_template_id = base template for category
   │
   └─→ Get template version number

4. Check customer acceptance:
   └─→ Query: contract_acceptances
       WHERE acceptable = customer
       AND vendor_id = selected_vendor
       AND product_category = product.category
       AND (address_id = delivery_address OR address_id IS NULL) [if site-specific]
       AND accepted_version = current_template_version

   ├─→ FOUND: Customer has accepted current terms
   │   └─→ Proceed with order
   │
   └─→ NOT FOUND: Customer needs to accept terms
       └─→ Present contract for e-signature
           └─→ Create contract_acceptance record
               └─→ Link to order
               └─→ Proceed with order

Version Change Flow

1. Vendor updates terms (or admin updates base template)
   └─→ Old template: is_active = false
   └─→ New template: version += 1, is_active = true

2. Next order with this vendor + category:
   └─→ Check acceptance with new version number
   └─→ No match found (version mismatch)
   └─→ Require re-acceptance
   └─→ Show changes diff (optional)
   └─→ Customer signs new version

Site-Specific Acceptance (Optional)

If site-specific mode enabled for product category:
   └─→ Acceptance required per delivery address
   └─→ contract_acceptance.address_id = delivery_address.id
   └─→ Customer may have multiple acceptances (same vendor, different sites)

Implementation Plan

Phase 1: Foundation (Week 1-2)

Phase 2: Admin Interface (Week 2-3)

Phase 3: Order Integration (Week 3-4)

Phase 4: Vendor Portal (Week 5-6)

Phase 5: Customer Portal (Week 7-8)

Phase 6: Enhancements


Technical Considerations

Security

Performance

Legal Compliance

UI/UX


Database Associations

# ContractTemplate
has_many :vendor_contract_templates
has_many :contract_acceptances

# VendorContractTemplate
belongs_to :vendor
belongs_to :base_template, class_name: 'ContractTemplate', optional: true
has_many :contract_acceptances

# ContractAcceptance
belongs_to :acceptable, polymorphic: true  # Company or Contact
belongs_to :vendor
belongs_to :contract_template, optional: true
belongs_to :vendor_contract_template, optional: true
belongs_to :address, optional: true
belongs_to :order, optional: true

# Vendor
has_many :vendor_contract_templates
has_many :contract_acceptances

# Company / Contact
has_many :contract_acceptances, as: :acceptable

# Product
belongs_to :product_category  # or has category attribute

API Endpoints (Future)

Admin:
GET    /admin/contract_templates
POST   /admin/contract_templates
GET    /admin/contract_templates/:id/edit
PATCH  /admin/contract_templates/:id
DELETE /admin/contract_templates/:id

GET    /admin/vendor_contracts/pending_approval
PATCH  /admin/vendor_contracts/:id/approve
PATCH  /admin/vendor_contracts/:id/reject

Vendor Portal:
GET    /vendor/contracts
POST   /vendor/contracts
GET    /vendor/contracts/:id/edit
PATCH  /vendor/contracts/:id

Customer/Order:
GET    /orders/:order_id/contract
POST   /orders/:order_id/contract/accept
GET    /contracts/history
GET    /contracts/:id/pdf

Example Contract Template Variables

Templates can use placeholders for dynamic content:

## Rental Agreement

**Customer:** {{customer_name}}
**Delivery Address:** {{delivery_address}}
**Product:** {{product_name}}
**Vendor:** {{vendor_name}}
**Rental Period:** {{rental_start_date}} to {{rental_end_date}}

### Terms and Conditions

1. The customer agrees to pay ${{total_amount}} for rental of {{product_name}}.
2. Delivery will occur on {{delivery_date}} between {{delivery_time_window}}.
3. Weight limit: {{weight_limit}} tons. Overages charged at ${{overage_rate}}/ton.

...

**Signature:** _________________________
**Date:** {{signature_date}}

Success Metrics


Future Enhancements

  1. DocuSign Integration - Professional e-signature service
  2. Contract Bundles - Combine multiple terms (rental + insurance + liability)
  3. Multi-language Support - Spanish, etc.
  4. Contract Templates as Code - Store in Git, version control, PR workflow
  5. A/B Testing - Test different term wording for acceptance rates
  6. Integration with Payment - Link payment terms to contract terms
  7. Automatic Renewals - Annual contract renewals with reminder emails
  8. Insurance Verification - Require proof of insurance for certain products

Notes


Questions to Resolve

  1. Expiration policy: Do contract acceptances expire? (e.g., annual renewal)
  2. Site-specific: Always required or toggle per product category?
  3. Signature method: Typed name, drawn signature, both, or third-party service?
  4. Vendor submission: Auto-approve or always require admin review?
  5. Customer notification: Email when vendor changes terms?
  6. Diff view: Show what changed between versions?
  7. PDF generation: Store signed PDFs or generate on-demand?
  8. Multiple signers: Support multiple company representatives?

Related Documentation


Implementation Status

✅ Phase 1: Foundation - COMPLETE

Database Tables:

Models:

Seed Data:

✅ Phase 2: Admin Interface - COMPLETE

Admin Contract Templates Management:

Features:

Vendor Contract Approval:

🔶 Phase 3: Order Integration - PARTIAL

Implemented:

Not Yet Implemented:

🔶 Phase 4: Vendor Portal - PARTIAL

Implemented:

Not Yet Implemented:

❌ Phase 5: Customer Portal - NOT STARTED

Not Yet Implemented:

Partial:

❌ Phase 6: Enhancements - NOT STARTED

Not Yet Implemented:


Current Architecture

Working Features

  1. Admin creates base templates → Store in contract_templates
  2. Admin manages templates → Full CRUD with rich text editor
  3. Version control → Automatic version incrementing and history
  4. Category management → ProductCategory as single source of truth
  5. Vendor overrides → Model and controller ready (UI pending)
  6. Approval workflow → Controller actions ready (UI pending)
  7. Acceptance tracking → Full model with smart version checking

Database State

Routes Available

Admin:

Vendor Portal (vendors subdomain):

Customer Portal (app subdomain):

Order Flow:


Next Steps to Complete

Critical Path (MVP)

  1. Build Vendor Portal Views (High Priority)

  2. Build Admin Approval UI (High Priority)

  3. Integrate into Order Flow (High Priority)

  4. Customer Portal Views (Medium Priority)

Nice to Have

  1. E-signature UI Enhancement

  2. Email Notifications

  3. Analytics Dashboard


Last Updated: October 1, 2025 (Implementation Review) Status: Phase 2 Complete, Phase 3-4 Partial, Phase 5-6 Not Started Next Review: After vendor portal views completed