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_NULL for 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

FieldTypeDescription
session_idUUIDField (primary key)Auto-generated identifier
web_sessionFK(web_auth.WebSession, SET_NULL)Web auth session context
customerFK(users.Customer, SET_NULL)Customer if authenticated
is_guestBooleanFieldTrue for guest checkout (default: True)
guest_emailEmailFieldEmail supplied for guest checkout
cartFK(transactions.Cart, SET_NULL)Shopping cart being checked out
transactionFK(transactions.SaleTransaction, SET_NULL)Set once the transaction is created on completion
storeFK(stores.Store, PROTECT)Target store
statusCharField(30), indexedCurrent session status
fulfillment_methodCharField(20)ship, pickup, or digital
payment_timingCharField(20)immediate (pay now) or at_pickup (pay at store); default immediate
pickup_scheduled_timeDateTimeFieldSelected pickup time, for pickup fulfillment
shipping_addressJSONFieldShipping address details
billing_addressJSONFieldBilling address details
fulfillment_dataJSONFieldResolved 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_atDateTimeField (auto_now_add)Session creation time
last_activityDateTimeField (auto_now)Updated on every save
completed_atDateTimeFieldSet when checkout completes
expires_atDateTimeFieldSession expiry time
user_agentTextFieldBrowser user agent
ip_addressGenericIPAddressFieldClient IP address
utm_paramsJSONFieldMarketing 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(): sets expires_at to 30 minutes from now if not already set (models.py:162-167).
  • is_expired(): returns True if timezone.now() > expires_at.
  • extend_expiry(minutes=30): pushes expires_at forward 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

FieldTypeDescription
context_idUUIDField (primary key)Auto-generated identifier
checkout_sessionFK(CheckoutSession, CASCADE)Parent checkout session
inventory_levelFK(products.InventoryLevel, CASCADE)Inventory record being reserved
stock_reservedPositiveIntegerFieldQuantity reserved by this context
statusCharField(20), indexedReservation status
reserved_atDateTimeField (auto_now_add)When the reservation was created
expires_atDateTimeFieldReservation expiry, mirrors the parent checkout session's expires_at
committed_atDateTimeFieldSet when committed
released_atDateTimeFieldSet when released

Indexes

(checkout_session, status), (inventory_level, status), (status, expires_at) (models.py:227-231). Default ordering is -reserved_at.

Methods

  • is_expired(): returns True if timezone.now() > expires_at.
  • commit(): sets status to committed and stamps committed_at.
  • release(): sets status to released and stamps released_at.
  • expire(): sets status to expired.

Cross-links: exposed by CheckoutReservationContextSerializer (see Serializers); created and released by ReservationService (see Services).


Was this page helpful?