Web Commerce Domain - Models Documentation
Location: api/nextango/apps/web_commerce/models.py
Last Updated: 2026-07-08
Overview
The Web Commerce models manage web checkout sessions and inventory reservations for the storefront. Unlike POS, which uses heartbeat-based TerminalSession, web commerce uses TTL-based CheckoutSession with an explicit expiry time.
Model Categories:
- CheckoutSession: tracks checkout progress, cart state, and reservation lifecycle
- CheckoutReservationContext: audit trail for inventory reservations
Key Architectural Patterns:
- TTL-based sessions: sessions expire after a configurable time (default 30 minutes)
- Guest/authenticated hybrid: supports both guest checkout and authenticated customers
- Soft links: uses FKs with
SET_NULLfor graceful degradation when a related record is deleted
CheckoutSession
Purpose: Web checkout session, analogous to TerminalSession for POS. Tracks checkout progress, cart state, and the reservation lifecycle from checkout initiation through completion, cancellation, or expiry.
Source: models.py:11-176
Base class: AuditableMixin, SoftDeleteMixin
Session status choices
cart, checkout_initiated, payment_pending, payment_processing, completed, abandoned, expired (models.py:17-24).
Fulfillment method choices
ship, pickup, digital (models.py:26-29).
Fields
| Field | Type | Description |
|---|---|---|
session_id | UUIDField (primary key) | Auto-generated identifier |
web_session | FK(web_auth.WebSession, SET_NULL) | Web auth session context |
customer | FK(users.Customer, SET_NULL) | Customer if authenticated |
is_guest | BooleanField | True for guest checkout (default: True) |
guest_email | EmailField | Email supplied for guest checkout |
cart | FK(transactions.Cart, SET_NULL) | Shopping cart being checked out |
transaction | FK(transactions.SaleTransaction, SET_NULL) | Set once the transaction is created on completion |
store | FK(stores.Store, PROTECT) | Target store |
status | CharField(30), indexed | Current session status |
fulfillment_method | CharField(20) | ship, pickup, or digital |
payment_timing | CharField(20) | immediate (pay now) or at_pickup (pay at store); default immediate |
pickup_scheduled_time | DateTimeField | Selected pickup time, for pickup fulfillment |
shipping_address | JSONField | Shipping address details |
billing_address | JSONField | Billing address details |
fulfillment_data | JSONField | Resolved fulfillment snapshot, written only on a 3DS requires_action early return so the confirmation view and the webhook backstop can create Fulfillment records once 3DS completes (models.py:120-129) |
initiated_at | DateTimeField (auto_now_add) | Session creation time |
last_activity | DateTimeField (auto_now) | Updated on every save |
completed_at | DateTimeField | Set when checkout completes |
expires_at | DateTimeField | Session expiry time |
user_agent | TextField | Browser user agent |
ip_address | GenericIPAddressField | Client IP address |
utm_params | JSONField | Marketing attribution parameters |
Indexes
(status, expires_at), (customer, status), (guest_email, status), (last_activity,), (store, status) (models.py:148-154). Default ordering is -initiated_at.
Methods
save(): setsexpires_atto 30 minutes from now if not already set (models.py:162-167).is_expired(): returnsTrueiftimezone.now() > expires_at.extend_expiry(minutes=30): pushesexpires_atforward and saves only that field.
Cross-links: exposed by CheckoutSessionSerializer (see Serializers); operated on primarily by CheckoutService (see Services).
CheckoutReservationContext
Purpose: Audit trail for web checkout inventory reservations. Tracks the reservation lifecycle without duplicating InventoryLevel.stock_reserved as the source of truth.
Source: models.py:179-256
Base class: AuditableMixin, SoftDeleteMixin
Note: POS uses InventoryReservation with an FK to TerminalSession. Web commerce uses this separate audit model because checkout sessions have a fundamentally different lifecycle (TTL-based rather than heartbeat-based).
Reservation status choices
active, committed, expired, released (models.py:189-193).
Fields
| Field | Type | Description |
|---|---|---|
context_id | UUIDField (primary key) | Auto-generated identifier |
checkout_session | FK(CheckoutSession, CASCADE) | Parent checkout session |
inventory_level | FK(products.InventoryLevel, CASCADE) | Inventory record being reserved |
stock_reserved | PositiveIntegerField | Quantity reserved by this context |
status | CharField(20), indexed | Reservation status |
reserved_at | DateTimeField (auto_now_add) | When the reservation was created |
expires_at | DateTimeField | Reservation expiry, mirrors the parent checkout session's expires_at |
committed_at | DateTimeField | Set when committed |
released_at | DateTimeField | Set when released |
Indexes
(checkout_session, status), (inventory_level, status), (status, expires_at) (models.py:227-231). Default ordering is -reserved_at.
Methods
is_expired(): returnsTrueiftimezone.now() > expires_at.commit(): setsstatustocommittedand stampscommitted_at.release(): setsstatustoreleasedand stampsreleased_at.expire(): setsstatustoexpired.
Cross-links: exposed by CheckoutReservationContextSerializer (see Serializers); created and released by ReservationService (see Services).
Related Documentation
- Services:
CartService,CheckoutService,ReservationService - Views: API endpoints
- Transactions Models:
Cart,SaleTransaction - Products Models:
InventoryLevel