Phase 03: Supply Chain & Orders
Duration: 1 week Goal: Implement order flow from Outlets to Distribution Centers to Suppliers
1. Outlet Material Demand
Section titled β1. Outlet Material Demandβ1.1 Material Request DocType
Section titled β1.1 Material Request DocTypeβclass MaterialRequest(BaseDocType): """Outlet request for goods from Distribution Center."""
# Identity request_no: str = Field(max_length=50, unique=True)
# Type request_type: str = "Material Request" # Material Request, Transfer
# Parties outlet: str # FK to Outlet (requesting) distribution_center: str # FK to Distribution Center (fulfilling)
# Dates request_date: date required_by_date: date | None = None
# Status status: str = "Draft" # Draft, Pending, Approved, Fulfilled, Rejected docstatus: int = 0
# Items items: list["MaterialRequestItem"] = []
class Meta: table_name = "material_request" indexes = ["outlet", "distribution_center", "status"]1.2 Material Request Item
Section titled β1.2 Material Request Itemβclass MaterialRequestItem(BaseDocType): """Line item in Material Request."""
parent: str # FK to MaterialRequest item: str # FK to Item item_name: str
qty: Decimal uom: str = "Nos"
# Fulfillment tracking ordered_qty: Decimal = Decimal("0") received_qty: Decimal = Decimal("0")
class Meta: table_name = "material_request_item"1.3 Tasks
Section titled β1.3 Tasksβ- Create
MaterialRequestDocType - Create
MaterialRequestItemchild - Outlet submission workflow
- Distribution Center approval workflow
- Fulfillment tracking
2. Purchase Order (Distribution Center β Supplier)
Section titled β2. Purchase Order (Distribution Center β Supplier)β2.1 Purchase Order DocType
Section titled β2.1 Purchase Order DocTypeβclass PurchaseOrder(BaseDocType): """Order placed with Supplier by Distribution Center."""
# Identity po_no: str = Field(max_length=50, unique=True)
# Parties supplier: str # FK to Supplier distribution_center: str # FK to Distribution Center (receiving)
# Dates order_date: date expected_delivery_date: date | None = None
# Reference material_request: str | None = None # FK if created from MR
# Totals total_qty: Decimal = Decimal("0") total_amount: Decimal = Decimal("0")
# Status status: str = "Draft" # Draft, Submitted, Partially Received, Completed, Cancelled docstatus: int = 0
# Items items: list["PurchaseOrderItem"] = []
class Meta: table_name = "purchase_order" indexes = ["supplier", "distribution_center", "status"]2.2 Purchase Order Item
Section titled β2.2 Purchase Order Itemβclass PurchaseOrderItem(BaseDocType): """Line item in Purchase Order."""
parent: str item: str item_name: str
qty: Decimal uom: str = "Nos" rate: Decimal amount: Decimal
# Receipt tracking received_qty: Decimal = Decimal("0")
# Warehouse target_warehouse: str
class Meta: table_name = "purchase_order_item"2.3 Tasks
Section titled β2.3 Tasksβ- Create
PurchaseOrderDocType - Create from Material Request
- Supplier notification (webhook/email)
- PO approval workflow
3. Goods Receipt Note (GRN)
Section titled β3. Goods Receipt Note (GRN)β3.1 Purchase Receipt DocType
Section titled β3.1 Purchase Receipt DocTypeβclass PurchaseReceipt(BaseDocType): """Receipt of goods from Supplier."""
# Identity receipt_no: str = Field(max_length=50, unique=True)
# Reference purchase_order: str # FK to PurchaseOrder supplier: str
# Warehouse warehouse: str # Where goods are received
# Dates posting_date: date posting_time: time | None = None
# Totals total_qty: Decimal = Decimal("0") total_amount: Decimal = Decimal("0")
# Status docstatus: int = 0
# Items items: list["PurchaseReceiptItem"] = []
class Meta: table_name = "purchase_receipt"3.2 Purchase Receipt Controller
Section titled β3.2 Purchase Receipt Controllerβclass PurchaseReceiptController(BaseController[PurchaseReceipt]):
async def on_submit(self, doc: PurchaseReceipt) -> None: """Create Stock Entry on GRN submission.""" stock_entry = await self.create_stock_entry( entry_type="Receipt", target_warehouse=doc.warehouse, items=doc.items, reference_doc_type="PurchaseReceipt", reference_doc_id=doc.id ) await stock_entry.submit()
# Update PO received quantities await self.update_purchase_order(doc)3.3 Tasks
Section titled β3.3 Tasksβ- Create
PurchaseReceiptDocType - Auto-create Stock Entry on submit
- Update PO received quantities
- Quality check integration (optional)
4. Distribution Center β Outlet Delivery
Section titled β4. Distribution Center β Outlet Deliveryβ4.1 Delivery Note DocType
Section titled β4.1 Delivery Note DocTypeβclass DeliveryNote(BaseDocType): """Goods delivered from Distribution Center to Outlet."""
# Identity delivery_no: str = Field(max_length=50, unique=True)
# Parties distribution_center: str outlet: str
# Reference material_request: str | None = None
# Warehouse source_warehouse: str
# Dates posting_date: date
# Transport vehicle_no: str | None = None driver_name: str | None = None
# Status status: str = "Draft" # Draft, Dispatched, Delivered docstatus: int = 0
items: list["DeliveryNoteItem"] = []
class Meta: table_name = "delivery_note"4.2 Delivery Note Controller
Section titled β4.2 Delivery Note Controllerβclass DeliveryNoteController(BaseController[DeliveryNote]):
async def on_submit(self, doc: DeliveryNote) -> None: """Create Stock Issue on delivery.""" stock_entry = await self.create_stock_entry( entry_type="Issue", source_warehouse=doc.source_warehouse, items=doc.items, reference_doc_type="DeliveryNote", reference_doc_id=doc.id ) await stock_entry.submit()4.3 Tasks
Section titled β4.3 Tasksβ- Create
DeliveryNoteDocType - Auto-create Stock Issue on submit
- Update Material Request fulfilled qty
- Delivery confirmation from URC
5. Demand Aggregation
Section titled β5. Demand Aggregationβ5.1 Demand Generation Service
Section titled β5.1 Demand Generation Serviceβclass DemandGenerationService: """Aggregate Outlet demands for Distribution Center ordering."""
async def generate_distribution_center_demand( self, distribution_center: str, from_date: date, to_date: date ) -> list[dict]: """ Aggregate all pending Material Requests for a Distribution Center. Returns consolidated item-wise demand. """ requests = await self.get_pending_requests(distribution_center, from_date, to_date)
demand = defaultdict(Decimal) for req in requests: for item in req.items: demand[item.item] += item.qty - item.ordered_qty
return [ {"item": item, "total_demand": qty} for item, qty in demand.items() ]5.2 Tasks
Section titled β5.2 Tasksβ- Implement demand aggregation service
- Create consolidated PO from demand
- Dashboard for demand visibility
6. Order Flow Diagram
Section titled β6. Order Flow Diagramβββββββββββββ ββββββββββββββββββββββββ βββββββββββββββββββββ Outlet β ββMRβββΆ β Distribution Center β ββPOβββΆ β Supplier βββββββββββββ ββββββββββββββββββββββββ ββββββββββββββββββββ β² β β β β β β βΌ β β ββββββββββββββββββββββββ β ββββDeliveryββ β DC Warehouse β βββGRNβββββββ β ββββββββββββββββββββββββ β β β βΌ β ββββββββββββββββββββ βββββββββββββββββ Stock Ledger β ββββββββββββββββββββ7. Verification Checklist
Section titled β7. Verification Checklistβ- Outlet can submit Material Request
- Distribution Center can approve/reject MR
- Distribution Center can create PO from MR
- Supplier receives PO notification
- GRN creates stock receipt
- Delivery Note creates stock issue
- Full flow from MR β PO β GRN β Delivery works
- Stock balances accurate after full cycle
Phase 03.1: Model Baking & Compliance Audit
Section titled βPhase 03.1: Model Baking & Compliance AuditβGoal: Verify that the domain models are correctly augmented by the MetadataDecoratorRegistry during the bootstrap cycle.
- Verify Model Baking: Ensure
StockEntryandDeliveryNoteare baked with the required regional mixins at startup. - Refactor Delivery Compliance: Implement the transition from local dispatch to
RegionalComplianceRegistry.register_transaction. - Verify Persistence: Confirm that regional fields are correctly routed to the overflow JSON column or dedicated SQL columns as configured in the Registry.