Procurement Domain - Models Documentation

Source: api/nextango/apps/procurement/models.py Last Updated: 2026-07-09


Table of Contents

  1. Overview
  2. Supplier
  3. PurchaseOrder
  4. PurchaseOrderLineItem
  5. Model Relationships

Overview

The Procurement models define the supplier and purchase order management layer. All three models use SanityIntegratedModel as their base, which provides a sanity_id field for Sanity CMS synchronization.

ModelDB TablePurpose
SuppliersupplierVendor/supplier directory
PurchaseOrderpurchase_orderPurchase order header
PurchaseOrderLineItempurchase_order_line_itemRelational PO line items

Supplier

File: models.py:16-89 DB table: supplier Inherits: SanityIntegratedModel Mirrors: studio/schemaTypes/documents/supplier.js

Fields

FieldTypeConstraintsDescription
nameCharField(255)requiredSupplier display name
supplier_codeCharField(20)unique, indexedShort internal reference code (e.g., SUP-001)
tax_identificationCharField(50)optionalBusiness tax ID number
is_activeBooleanFielddefault=True, indexedInactive suppliers cannot receive new POs
notesTextFieldoptionalInternal notes
addressJSONFielddefault={}Address object (mirrors Sanity address object)
contactsJSONFielddefault=[]Array of contact objects (mirrors supplierContact array)
payment_termsCharField(30)choices, optionalSee payment terms choices below
account_numberCharField(100)optionalYour account number with this supplier
minimum_order_amountDecimalField(10,2)null/blankMinimum PO value this supplier accepts
lead_time_daysPositiveIntegerFieldnull/blankAverage days from order to delivery
return_policyTextFieldoptionalSupplier return policy
supplied_product_typesJSONFielddefault=[]Array of Sanity product type references
supplied_productsJSONFielddefault=[]Array of Sanity product references
documentsJSONFielddefault=[]Array of supplier document objects

Payment Terms Choices

ValueDisplay
due_on_receiptDue on Receipt
net_15Net 15
net_30Net 30
net_60Net 60
net_90Net 90
prepaidPrepaid

Ordering

Default ordering: ['name'] (alphabetical)

__str__

Returns "<name> (<supplier_code>)" if supplier_code is set, otherwise just "<name>".


PurchaseOrder

File: models.py:92-154 DB table: purchase_order Inherits: SanityIntegratedModel Mirrors: studio/schemaTypes/documents/purchaseOrder.js

Fields

FieldTypeConstraintsDescription
po_numberCharField(50)unique, indexedPurchase order number
supplierForeignKey(Supplier)PROTECT, related_name='purchase_orders'Linked supplier
expected_dateDateFieldnull/blankEstimated delivery date
statusCharField(35)choices, default=Pending, indexedPO lifecycle status
itemsJSONFielddefault=[]Raw Sanity purchaseOrderItem array
total_costDecimalField(12,2)default=0.00Total PO cost. Kept in sync with the sum of line item costs automatically on every line-item save or delete (see signals.md)
received_dateDateFieldnull/blankActual delivery date. Set automatically when the PO status transitions to Received; a manually-set value is overwritten when that transition fires. See signals.md
compliance_verificationJSONFielddefault={}Compliance verification data for this order (verifiedAt, verifiedBy, packageIds). A swappable slot populated by a compliance integration or a compliance manager
notesTextFieldoptionalInternal notes

Status Choices

Status values are capitalized strings matching the Sanity schema exactly. The field does not enforce transition order.

ValueDisplay
PendingPending
SubmittedSubmitted
Partially ReceivedPartially Received
Awaiting Compliance VerificationAwaiting Compliance Verification
ReceivedReceived
CancelledCancelled

Open statuses (for analytics): Pending, Submitted, Partially Received

Indexes

  • po_status_expected_idx on (status, expected_date): supports filtering open POs by expected delivery

Ordering

Default ordering: ['-created_at'] (newest first)

__str__

Returns "PO <po_number>".


PurchaseOrderLineItem

File: models.py:157-205 DB table: purchase_order_line_item Inherits: SanityIntegratedModel

Relational line item providing Django-side queryability of PO items. Counterpart to the purchaseOrderItem Sanity object type stored in PurchaseOrder.items.

Fields

FieldTypeConstraintsDescription
purchase_orderForeignKey(PurchaseOrder)CASCADE, related_name='line_items'Parent PO
sanity_keyCharField(255)indexed, optionalSanity _key within the PO items array
inventory_levelForeignKey(products.InventoryLevel)PROTECT, null/blank, related_name='purchase_order_lines'The inventory item being ordered
inventory_level_sanity_refCharField(255)optionalRaw Sanity _ref for unresolved inventory references
quantityPositiveIntegerFielddefault=1Units ordered
unit_costDecimalField(10,2)requiredCost per unit
quantity_receivedPositiveIntegerFieldnull, blankActual units received against this line. null indicates the line has not yet been received. Enables partial-receipt workflows and reconciliation against quantity

Constraints

  • unique_together = [('purchase_order', 'sanity_key')]: prevents duplicate Sanity items per PO

__str__

Returns "<quantity>x <variant_name_or_sku> @ <unit_cost>". Falls back to inventory_level_sanity_ref or 'Unknown' if inventory is unresolved.


Model Relationships

Supplier
  └─ purchase_orders (reverse FK) → PurchaseOrder (many)
       └─ line_items (reverse FK) → PurchaseOrderLineItem (many)
            └─ inventory_level → products.InventoryLevel

Cascade rules:

  • Deleting a Supplier is blocked (PROTECT) if it has purchase orders
  • Deleting a PurchaseOrder cascades to its PurchaseOrderLineItem records
  • Deleting an InventoryLevel is blocked (PROTECT) if referenced by line items

Was this page helpful?