Transactions - POS & Sales Processing
Domain: Transactions
Location: api/nextango/apps/transactions/
Last Updated: 2026-07-08
Overview
The Transactions app handles the complete POS transaction lifecycle from cart creation through payment processing, returns, and cash drawer management. Features immutable line items for audit compliance, inventory reservations, promotional discount integration, store credit management, and an eight-state transaction state machine.
Documentation Quick Links
Core Documentation
| File | Description |
|---|---|
| models.md | SaleTransaction, SaleLineItem, Return, StoreCredit, CashDrawer models |
| serializers.md | Transaction API serializers and validation |
| views.md | All transaction API endpoints and workflows |
| services.md | TransactionService, ReturnService, CashDrawerService |
| signals.md | Transaction lifecycle signals and automation |
| examples.md | Usage examples and patterns |
Key Features
Transaction Processing
- Complete transaction lifecycle - Cart → Items → Payment → Complete
- Immutable line items - Audit-compliant transaction records
- Transaction state machine - Pending → Processing → Completed → Voided
- Transaction locking - Prevent concurrent modifications
- Idempotency support - Safe retry of failed operations
- Multi-terminal support - Multiple POS terminals per store
Line Item Management
- Immutable snapshots - Product data frozen at transaction time
- Quantity tracking - Accurate quantity per line item
- Discount integration - Line-level and transaction-level discounts
- Tax calculation - Automated tax calculation per line
- Price overrides - Manager-approved price adjustments
Inventory Integration
- Inventory reservations - Hold inventory during transaction
- Automatic release - Release on void or timeout
- Stock validation - Prevent overselling
- Zone-based inventory - Track inventory by store zone
Return Processing
- Return transactions - Full and partial returns
- Return line items - Item-level return tracking
- Refund methods - Original payment, store credit, exchange
- Restocking fees - Configurable restocking fees
- Return reasons - Track return reasons for analytics
Store Credit System
- Store credit creation - From returns or promotions
- Balance tracking - Current balance and transaction history
- Expiration dates - Configurable expiration policies
- Partial redemption - Use partial credit amounts
- Credit transfers - Transfer between customers (optional)
Cash Drawer Management
- Cash drawer events - Open, close, reconcile operations
- Cash tracking - Expected vs actual amounts
- Variance reporting - Track cash discrepancies
- Employee accountability - Track who handled cash
- Shift reconciliation - End-of-shift cash verification
Promotional Integration
- Promo code application - Apply discount codes
- Stackable discounts - Multiple promotions per transaction
- BOGO support - Buy one get one promotions
- Discount validation - Automatic eligibility validation
- Promotion tracking - Analytics on promotion usage
Pickup Order Management (Updated December 2025)
- Pickup scheduling - Schedule pickups with time windows via PickupViewSet
- Pickup status tracking - Pending → Ready → Picked Up / Expired / Cancelled
- End-of-day expiration - Unclaimed pickups automatically expire
- Inventory release - Expired/cancelled pickups release reserved inventory
- Store-specific handling - Respects store closing hours and timezone
- Return to inventory - Configurable
returnToInventorybehavior per store - Pickup cancellation - Customer-facing cancellation with reason tracking
- Today's pickups dashboard - Grouped by status with summary counts
Pay-at-Pickup (Added December 2025)
- Payment timing options -
immediateorat_pickuppayment collection - Deferred payment flow - Reserve inventory, pay at store
- Partial payment tracking - Track deposits and remaining balance
- Payment collection at pickup - Complete payment when customer arrives
Customer Cancellation (Added December 2025)
- Order cancellation - Customer-initiated order cancellation
- Cancellation tracking -
cancelledAt,cancellationReason,cancelledByfields - Distinct from void - Customer cancellation vs staff void operations
- Inventory release - Automatic release on cancellation
Receipt & Email Notifications (Added December 2025)
- Receipt email service -
ReceiptEmailServicefor branded HTML/text receipts - Order ready notifications - Async email when pickup is marked ready
- Payment status aware - Shows "Paid in Full" or "Balance Due"
- Dual email provider - Supports Resend and Hostinger SMTP
- Customer notification tracking -
customer_notified_attimestamp on pickups
Pickup Modification (Added December 2025)
- Cart-compatible format - Load pickups for POS modification
- Payment balance tracking - Total paid, balance due in response
- Line item details - Product name, variant name, image URLs
- Verification info - Customer email, phone, name for pickup
API Endpoints
URL mounting: nextango/urls.py:144 mounts this app's urls.py at /transactions/ ahead of the root router, so /transactions/returns/, /transactions/line-items/, /transactions/sale-transactions/, /transactions/fulfillments/, /transactions/shipments/, /transactions/pickup/, and the analytics endpoints below all resolve through that app-local router. The root router additionally registers TransactionViewSet at top-level /transactions/ (list/detail/custom actions), plus top-level /sale-transactions/, /returns/, /return-line-items/, /sale-line-items/, and /cash-drawer/. Full endpoint-by-endpoint detail, including which registration backs each path: views.md.
Transaction Management
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/transactions/ | POST | Create new transaction | views.md |
/transactions/{id}/ | GET | Get transaction details | views.md |
/transactions/{id}/add_item/ | POST | Add line item to transaction | views.md |
/transactions/{id}/remove_item/ | POST | Remove line item | views.md |
/transactions/{id}/update_quantity/ | POST | Update line item quantity | views.md |
Discount & Payment
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/transactions/{id}/apply_promo_code/ | POST | Apply promotional code | views.md |
/transactions/{id}/remove_promo_code/ | POST | Remove promo code | views.md |
/transactions/{id}/process_payment/ | POST | Process payment | views.md |
/transactions/{id}/complete/ | POST | Complete transaction | views.md |
/transactions/{id}/void/ | POST | Void transaction | views.md |
Returns Management
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/returns/ | GET, POST | Return operations (also reachable at /transactions/returns/) | views.md |
/returns/{id}/ | GET, PUT, PATCH | Return details and updates | views.md |
/returns/process_return/ | POST | Process return and refund | views.md |
/returns/{id}/cancel_return/ | POST | Cancel a pending return | views.md |
Store Credit
There is no StoreCredit ViewSet or URL. StoreCredit has a model and serializer, but records are created and read only through ReturnService when a return's refund method is store_credit; there is no /store-credits/ endpoint. See Models and Services.
Cash Drawer
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/cash-drawer/open/ | POST | Open cash drawer | views.md |
/cash-drawer/close/ | POST | Close cash drawer | views.md |
/cash-drawer/add_cash/ | POST | Record cash-in (pay-in) | views.md |
/cash-drawer/remove_cash/ | POST | Record cash-out (pay-out) | views.md |
/cash-drawer/status/ | GET | Current drawer state for a store/register | views.md |
/cash-drawer/till_count/ | POST | Record mid-shift till count | views.md |
Pickup Management
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/transactions/pickup/available-slots/ | GET | Get available pickup time slots | pickup.md |
/transactions/pickup/schedule/ | POST | Create pickup schedule | pickup.md |
/transactions/pickup/{id}/mark-ready/ | POST | Mark order ready for pickup | pickup.md |
/transactions/pickup/{id}/complete/ | POST | Complete pickup handoff | pickup.md |
/transactions/pickup/{id}/cancel/ | POST | Cancel pickup order | pickup.md |
/transactions/pickup/{id}/for-modification/ | GET | Get pickup for cart modification | pickup.md |
/transactions/pickup/store/{store_id}/pending/ | GET | Get store's pending pickups (with date filter) | pickup.md |
/transactions/pickup/store/{store_id}/today/ | GET | Get today's pickups by status | pickup.md |
Analytics (staff only)
| Endpoint | Method | Description |
|---|---|---|
/transactions/analytics/summary/ | GET | Revenue, tax, discount, and order-count summary |
/transactions/analytics/over-time/ | GET | Revenue and order-count time series |
/transactions/analytics/by-source/ | GET | Breakdown by source_system |
/transactions/analytics/by-fulfillment/ | GET | Breakdown by fulfillmentMethod |
/transactions/analytics/by-payment-method/ | GET | Breakdown by payment method |
/transactions/analytics/fulfillment/ | GET | Fulfillment-operations metrics |
/transactions/analytics/returns/ | GET | Return-rate and refund-value metrics |
Receipt & Notifications
| Endpoint | Method | Description | Doc Reference |
|---|---|---|---|
/transactions/{id}/send-receipt/ | POST | Send receipt email to customer | views.md |
Full endpoint documentation: views.md
Architecture Highlights
Transaction State Machine
Transactions flow through a well-defined state machine:
PENDING ──────────────────────────────────────→ COMPLETED
│ ↑ │
│ PARTIALLY_PAID │
│ │ REFUNDED / PARTIALLY_REFUNDED
↓ │ │
CANCELLED (partial payment applied) ↓
or VOIDED
VOIDED
States:
PENDING: Transaction created; no payment applied.PARTIALLY_PAID: Partial payment received; balance outstanding. Set byPaymentService.apply_payment_to_transaction()when payment does not cover the full total. Layaway and pay-at-pickup deposits land here. Abandoned rows are voided by thecleanup_stale_partial_paymentstask.COMPLETED: Fully paid. Set automatically whenpayment_balancereaches zero.VOIDED: Staff-initiated cancellation (may require manager override). Distinct from customer cancellation.CANCELLED: Customer-facing cancellation. Set withcancelledAttimestamp,cancellationReason, andcancelledByFK. Inventory released automatically. Triggered via pickup or order cancellation flow.REFUNDED: Fully refunded after completion.PARTIALLY_REFUNDED: Partial refund applied; remaining amount settled.PAYMENT_REQUIRES_ACTION: Card payment pending 3D Secure / Strong Customer Authentication. Abandoned rows are voided by thecleanup_stale_3ds_paymentstask.
Client note: Clients filtering by status must account for all 8 states. Omitting
partially_paid,cancelled, orpayment_requires_actionwill miss active outstanding orders, cancelled transactions, and payments pending authentication.
Read more: models.md, services.md
Immutable Line Items
Line items are immutable snapshots of product data at transaction time:
- Product name, price, and details frozen
- Prevents historical data inconsistency
- Audit trail compliance
- Accurate reporting regardless of product changes
Read more: models.md
Service Layer Architecture
Transaction logic is centralized in service classes:
- TransactionService - Transaction lifecycle management
- ReturnService - Return processing and refunds
- CashDrawerService - Cash drawer operations
- InventoryReservationService - Inventory hold logic
Read more: services.md
Signal-Based Integration
Signals coordinate cross-domain operations:
- Inventory updates on transaction complete
- Payment processing notifications
- Analytics event tracking
- Sanity CMS synchronization
Read more: signals.md
Getting Started
1. Understand the Models
Start with models.md to understand:
- SaleTransaction (transaction_number, store, terminal, state)
- SaleLineItem (product snapshot, quantity, price, discounts)
- Return (original_transaction, return_reason, refund_method)
- StoreCredit (customer, balance, expiration)
- CashDrawerEvent (event_type, expected_amount, actual_amount)
2. Review Transaction Service
Read services.md to understand:
- Transaction creation workflow
- Line item management
- Payment processing
- Transaction completion
- Void and refund logic
3. Explore Transaction Flows
Check views.md to learn:
- Complete transaction API workflow
- Return processing flow
- Cash drawer reconciliation
- Store credit redemption
4. Study Return Processing
Review services.md for:
- Return creation and validation
- Refund calculation logic
- Inventory restocking
- Store credit generation
Related Domains
- Products - Product data, inventory, pricing
- Payments - Payment processing integration
- Promotions - Discount and promo code application
- Stores - Store and terminal configuration
- Users - Employee and customer references
- POS Gateway - Real-time POS terminal integration
- Integrations - Transaction synchronization
Key Architectural Decisions
- Immutable line items - Audit compliance and data integrity
- State machine pattern - Clear transaction lifecycle management
- Service layer - Business logic centralized, not in views/models
- Inventory reservations - Prevent overselling during checkout
- Transaction locking - Prevent concurrent modification issues
- Flexible returns - Support full, partial, and exchange returns
- Store credit system - Customer retention and refund flexibility
Common Use Cases
- POS sale - Create transaction, add items, apply discounts, process payment
- Return processing - Process return, calculate refund, restock inventory
- Store credit - Issue credit from return, redeem credit in transaction
- Cash drawer - Open drawer, process cash transactions, reconcile at shift end
- Promotional sales - Apply promo codes, calculate discounts, track usage
- Manager overrides - Price adjustments, return approvals, void transactions
- Multi-payment - Split payment across multiple payment methods
- Transaction reporting - Sales analytics, tax reporting, audit trails
Service Methods
TransactionService
Transaction Lifecycle:
create_transaction(store, employee=None, customer=None, source_system=None)- Initialize transactionadd_product_to_transaction(transaction_id, product_variant_id, quantity, unit_price=None)- Add item and recalculate totalsadd_product_to_transaction_without_recalc(transaction_id, product_variant_id, quantity, unit_price=None)- Add item without recalculating (batch creation path)update_line_item_quantity(transaction_id, line_item_id, new_quantity)- Update quantityremove_line_item(transaction_id, line_item_id)- Remove item from cart
Discounts & Payment:
apply_promo_code(transaction_id, promo_code, store_id=None)- Apply promotional discountremove_promo_code(transaction_id, promo_code)- Remove discountapply_line_item_discount(transaction_id, line_item_id, discount_amount, employee=None)- Apply manual line discountcomplete_transaction(transaction_id, payment_method_id=None, amount_paid=None)- Run pre-completion compliance gates and finalize transactionvoid_transaction(transaction_id, reason, employee=None)- Cancel transaction, reverse inventory, and refund succeeded paymentsredeem_loyalty_points(transaction_id, points_to_redeem)- Apply loyalty points as a payment credit
Full detail: services.md.
ReturnService
Return Processing:
create_return(original_transaction_id, line_items, reason)- Create returncalculate_refund_amount(return_id)- Calculate refundprocess_return(return_id, refund_method)- Process return and refundapprove_return(return_id, manager_id)- Manager approvalrestock_inventory(return_id)- Return items to inventory
CashDrawerService
Drawer Operations:
open_drawer(terminal_id, employee_id, starting_cash)- Open drawerclose_drawer(drawer_id, ending_cash)- Close drawerreconcile_drawer(drawer_id, actual_amounts)- Reconcile cashcalculate_variance(drawer_id)- Calculate cash varianceget_drawer_events(terminal_id, date_range)- Get drawer history
PickupService (Added December 2025)
Time Slot Generation:
generate_available_time_slots(store_id, start_date, num_days)- Get available pickup windows
Pickup Lifecycle:
create_pickup_schedule(fulfillment_id, scheduled_time, customer_notes)- Schedule pickupmark_ready_for_pickup(pickup_schedule_id, prepared_by_user)- Mark as readycomplete_pickup(pickup_schedule_id, handed_off_by_user)- Complete handoffcancel_pickup_order(pickup_schedule_id, cancellation_reason, cancelled_by_user)- Cancel pickup
Store Dashboard:
get_pending_pickups_for_store(store_id, scheduled_date)- Get pending pickups (with date filter)get_ready_pickups_for_store(store_id)- Get ready pickupsget_todays_pickups_for_store(store_id)- Get today's pickups grouped by statusget_pickup_for_modification(pickup_schedule_id)- Get pickup in cart-compatible format
ReceiptEmailService (Added December 2025)
Receipt Emails:
send_receipt(transaction, to_email)- Send branded HTML receipt email_build_receipt_html(transaction)- Generate HTML receipt content_build_receipt_text(transaction)- Generate plain text receipt_build_payment_html(transaction)- Payment details section
Email Provider Support:
- Supports
ORDER_EMAIL_PROVIDERenvironment variable - Resend API (default) or Hostinger SMTP
Full documentation: services.md
Next Steps
- Start with models.md - Understand the data structure
- Then services.md - Learn business logic and workflows
- Review views.md - Explore API endpoints
- Check signals.md - See transaction automation
- Study serializers.md - Understand validation and serialization