Procurement Domain - Serializers Documentation

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


Overview

The procurement serializers handle two distinct input paths:

  1. API requests: snake_case fields, direct FK IDs
  2. Sanity webhooks: camelCase fields, _ref Sanity references instead of DB IDs

Both paths are handled by overriding to_internal_value() in each serializer. The serializers detect camelCase keys and transform them to snake_case, and resolve Sanity _ref objects to Django PKs.


SupplierSerializer

Source: serializers.py:16-71 Model: Supplier

Fields

All model fields are included. Read-only fields: id, sanity_id, created_at, updated_at.

FieldWritableNotes
idNoAuto UUID
sanity_idNoSet by webhook handler
nameYes
supplier_codeYes
tax_identificationYes
is_activeYes
notesYes
addressYesJSON object
contactsYesJSON array
payment_termsYes
account_numberYes
minimum_order_amountYes
lead_time_daysYes
return_policyYes
supplied_product_typesYesJSON array
supplied_productsYesJSON array
documentsYesJSON array
created_atNo
updated_atNo

camelCase → snake_case Mappings

to_internal_value() handles these transformations automatically for Sanity webhook payloads:

Sanity (camelCase)Django (snake_case)
supplierCodesupplier_code
taxIdentificationtax_identification
isActiveis_active
paymentTermspayment_terms
accountNumberaccount_number
minimumOrderAmountminimum_order_amount
leadTimeDayslead_time_days
returnPolicyreturn_policy
suppliedProductTypessupplied_product_types
suppliedProductssupplied_products

Fields name, address, contacts, documents, notes pass through unchanged (same name in both systems).


PurchaseOrderLineItemSerializer

Source: serializers.py:74-89 Model: PurchaseOrderLineItem

Read-only serializer used for nested display within PurchaseOrderSerializer. Not used directly for write operations.

Fields

FieldNotes
idRead-only
sanity_keySanity _key identifier
inventory_levelFK ID
inventory_level_sanity_refRaw Sanity ref
variant_skuFrom inventory_level.variant_sku
variant_nameFrom inventory_level.variant_name
product_nameFrom inventory_level.product.name
store_nameFrom inventory_level.store.name
quantity
unit_cost

variant_sku, variant_name, product_name, store_name are read_only=True fields sourced through the inventory_level relation (inventory_level.variant_sku, inventory_level.product.name, and so on), each defaulting to an empty string when unresolved.


PurchaseOrderSerializer

Source: serializers.py:92-164 Model: PurchaseOrder

Fields

FieldWritableNotes
idNoAuto UUID
sanity_idNoSet by webhook handler
po_numberYesUnique
supplierYesFK ID (write)
supplier_nameNoFrom supplier.name
supplier_codeNoFrom supplier.supplier_code
expected_dateYes
statusYes
itemsYesRaw Sanity JSON array
total_costYes
received_dateYes
compliance_verificationYesJSON object
notesYes
line_itemsNoNested PurchaseOrderLineItemSerializer (read-only)
created_atNo
updated_atNo

camelCase → snake_case Mappings

Sanity (camelCase)Django (snake_case)
poNumberpo_number
expectedDateexpected_date
totalCosttotal_cost
receivedDatereceived_date
complianceVerificationcompliance_verification

Supplier Reference Resolution

to_internal_value() resolves the Sanity supplier reference to a Django FK:

# Webhook payload:
{ "supplier": { "_ref": "some-sanity-supplier-id" } }
# or
{ "supplier": "some-sanity-supplier-id" }

# Resolved to:
{ "supplier": <Supplier.pk> }

If the supplier is not found by sanity_id, a warning is logged and the field is skipped: the dependency fetcher may resolve it asynchronously.

Was this page helpful?