POS Gateway - Models
Location: api/nextango/apps/pos_gateway/models.py
Last Updated: 2026-07-09
Overview
POS Gateway models track real-time terminal sessions, temporary inventory holds, manager approval workflows, and gateway performance data. None of these models sync to Sanity. They are born from operational events at the terminal (a login, a scan, an approval request), not authored in the CMS, so Django owns them outright.
TerminalSession
An active POS terminal session, created on employee PIN login and updated on every heartbeat and logout.
Base class: AuditableMixin, SoftDeleteMixin
| Field | Type | Description |
|---|---|---|
terminal_id | CharField, unique | Unique terminal identifier (e.g. STORE001-POS02) |
user | ForeignKey to User | Employee currently logged into the terminal |
store | ForeignKey to Store | Store the terminal belongs to |
status | CharField (choices) | active, inactive, suspended, expired |
login_time | DateTimeField | When the session started |
last_activity | DateTimeField | Last API call or WebSocket message |
logout_time | DateTimeField, nullable | When the user logged out |
auth_token | TextField | JWT access token for this session |
refresh_token | TextField, nullable | Reserved for a future refresh flow; not currently issued or read anywhere in the gateway |
expires_at | DateTimeField | When auth_token expires |
capabilities | JSONField | Terminal hardware/software capabilities, set to an empty dict at session creation |
configuration | JSONField | Terminal-specific settings, set to an empty dict at session creation |
transaction_count | PositiveIntegerField | Number of transactions created through this session |
avg_response_time | FloatField, nullable | Reserved for a future performance metric; not currently written by any gateway code path |
last_heartbeat | DateTimeField | Last WebSocket heartbeat or session refresh |
is_active() returns True when status is active, expires_at is in the future, and the row is not soft-deleted. update_activity() bumps last_activity to now.
A row is created (or refreshed via update_or_create) by PosGatewayAuthenticationClient._create_terminal_session on login. See Authentication and Serializers for the TerminalLoginSerializer that validates the login request, and Services for TransactionGatewayService, which increments transaction_count.
InventoryReservation
Model for a temporary hold on inventory while a customer checks out, intended to prevent two terminals from selling the last unit of a SKU at the same time.
Base class: AuditableMixin, SoftDeleteMixin
| Field | Type | Description |
|---|---|---|
reservation_id | CharField, unique | Unique reservation identifier |
terminal_session | ForeignKey to TerminalSession | Terminal that created the reservation |
product_variant_id | CharField | Product variant identifier |
sku | CharField | Product SKU |
quantity | PositiveIntegerField | Units reserved |
status | CharField (choices) | reserved, committed, released, expired |
reserved_at | DateTimeField | When the reservation was created |
expires_at | DateTimeField | When the reservation auto-expires |
committed_at | DateTimeField, nullable | When inventory was actually deducted |
released_at | DateTimeField, nullable | When the reservation was released back to inventory |
transaction_id | CharField, nullable | Associated SaleTransaction ID once payment completes |
is_active() returns True when status is reserved, expires_at is in the future, and the row is not soft-deleted.
No code path in the current gateway creates InventoryReservation rows. Inventory holds for POS sales are handled by the transactions app's own reservation and adjustment services when line items are created, not by this model. The class remains defined and admin-registered but unwritten; treat any reservation UI or reporting built against this table as forward-looking, not live.
ManagerApprovalRequest
A request for manager sign-off on a sensitive terminal action (discount, void, return, price override, cash drawer access, refund).
Base class: AuditableMixin, SoftDeleteMixin
| Field | Type | Description |
|---|---|---|
request_id | CharField, unique | Unique approval request identifier |
terminal_session | ForeignKey to TerminalSession | Terminal that raised the request |
request_type | CharField (choices) | discount, void, return, price_override, cash_drawer, refund |
status | CharField (choices) | pending, approved, denied, expired, cancelled |
amount | DecimalField, nullable | Dollar amount for financial approval types |
reason | TextField | Cashier's explanation for the request |
details | JSONField | Additional request-type-specific context |
requested_at | DateTimeField | When the request was created |
expires_at | DateTimeField | When the request auto-expires (10 minutes after creation) |
approved_by | ForeignKey to User, nullable, SET_NULL | Manager who approved or denied the request |
approved_at | DateTimeField, nullable | When the manager responded |
approval_reason | TextField, blank | Manager's explanation, required when denying |
requested_by | ForeignKey to User, nullable, SET_NULL | Cashier who raised the request: the terminal session's authenticated user at request time, recorded explicitly so the requester survives independent of terminal_session.user changing later |
transaction_id | CharField, nullable | Associated SaleTransaction ID, null for non-transaction requests such as cash drawer access |
is_pending() returns True when status is pending, expires_at is in the future, and the row is not soft-deleted.
Created by ManagerApprovalGatewayService.request_approval(), which populates both terminal_session and requested_by from the same session. See Services and Consumers for the WebSocket-driven approval flow, and Serializers for ManagerApprovalRequestSerializer.
GatewayPerformanceMetric
A time-series row for gateway performance data (response time, transaction count, error rate, cache hit rate, WebSocket connection count).
Base class: AuditableMixin
| Field | Type | Description |
|---|---|---|
terminal_session | ForeignKey to TerminalSession, nullable | Terminal the metric applies to, if any |
store | ForeignKey to Store | Store the metric applies to |
metric_type | CharField (choices) | response_time, transaction_count, error_rate, cache_hit_rate, websocket_connections |
value | FloatField | Metric value |
timestamp | DateTimeField | When the metric was recorded |
endpoint | CharField, blank | Endpoint the metric was captured against |
operation | CharField, blank | Operation name |
metadata | JSONField | Additional context |
No code path in the current gateway writes GatewayPerformanceMetric rows. HealthCheckView returns cache hit rate and average response time as static placeholder values rather than querying this table. The model is defined and admin-registered but has no writer anywhere in the codebase; treat it as scaffolded for a metrics pipeline that has not been built yet.
Related Documentation
- Authentication: JWT terminal login and session validation
- Serializers: request/response validation for these models
- Services: business logic that creates and updates these rows
- Views: REST endpoints backed by these models
- Consumers: WebSocket handling of
TerminalSessionandManagerApprovalRequeststate