The procurement module in src/cluster_erp/modules/procurement/ covers buying. It holds the supplier facet of a party, purchase requests, purchasing RFQs with vendor quotations and scoring, purchase orders with goods receipt, purchase contracts, and purchasing info records. It also runs material requirements planning (MRP) and keeps critical materials and substitution groups. This page is the overview; each sub-module has its own reference page, and MRP has an explanation page.
At a glance¶
| Item | Value | Source |
|---|---|---|
| Package | src/cluster_erp/modules/procurement/ |
folder |
| Module class | Module |
src/cluster_erp/modules/procurement/module.py:18 |
name / version |
procurement / 0.1.0 |
src/cluster_erp/modules/procurement/module.py:20-25 |
| API prefix | /api/v1/procurement (ModuleBase.api_prefix) |
src/cluster_erp/core/module_base.py:37-38 |
| Sub-modules | 9: suppliers, purchase_requests, purchase_rfqs, purchase_orders, purchase_contracts, info_records, critical_materials, substitution_groups, mrp |
folder listing |
| Tables | 27 | __tablename__ in the nine models.py files |
| Entities in metadata | 22 keys in entities |
src/cluster_erp/modules/procurement/module.py:1419-1442 |
| Routes | 155 route decorators in the package | grep for @...router.get/post/put/patch/delete |
| Actions | 21 ActionMeta entries |
grep "ActionMeta(" in the package |
| Migrations | 47 files | files in migrations/versions/ whose text contains one of the 27 table names |
| Web app presence | Catalogue app procurement; eight custom widgets from a gated bundle |
src/cluster_erp/modules/app_store/catalog.json (entry procurement), gated_apps/procurement/app.js:1647-1656 |
| Desktop presence | src/cluster_erp/desktop/modules/procurement/mrp/ (dashboard, exception workbench, planned orders, stock requirements, time-phased, pegging) |
folder |
What the module does¶
- Keeps a supplier facet per party, with identity fields derived from the party (
src/cluster_erp/modules/procurement/suppliers/services.py:80-145). - Collects material needs in purchase requests that move through approval to an order (
src/cluster_erp/modules/procurement/purchase_requests/services.py:76-83). - Sends purchasing RFQs to several vendors, records and scores their quotations, and awards lines, which creates one purchase order per awarded vendor (
src/cluster_erp/modules/procurement/purchase_rfqs/services.py:1215-1292). - Places purchase orders, receives goods per line, and posts the receipt to inventory (
src/cluster_erp/modules/procurement/purchase_orders/services.py:695-837). - Keeps quantity and value contracts and a price master per vendor and product breakdown (
src/cluster_erp/modules/procurement/purchase_contracts/models.py:23-109,src/cluster_erp/modules/procurement/info_records/models.py:25-121). - Runs MRP in seven phases and turns its proposals into requests or orders (
src/cluster_erp/modules/procurement/mrp/engine.py:1-19). - Flags critical materials and groups materials that can replace each other (
src/cluster_erp/modules/procurement/critical_materials/models.py:12-65,src/cluster_erp/modules/procurement/substitution_groups/models.py:24-127).
Sub-modules¶
| Sub-module | Purpose | Main entities | Router | Source |
|---|---|---|---|---|
suppliers |
Supplier facet of a party | Supplier |
/suppliers |
src/cluster_erp/modules/procurement/suppliers/routes.py:28-37 |
purchase_requests |
Purchase requests and items | PurchaseRequest, PurchaseRequestItem |
/purchase-requests |
src/cluster_erp/modules/procurement/purchase_requests/routes.py:33 |
purchase_rfqs |
Purchasing RFQs, vendors, quotations, criteria, scores, vendor portal | PurchaseRfq and six child entities |
/purchase-rfqs, /portal/rfqs |
src/cluster_erp/modules/procurement/purchase_rfqs/routes.py:44-45, src/cluster_erp/modules/procurement/purchase_rfqs/portal_routes.py:26-27 |
purchase_orders |
Purchase orders, items, receipt | PurchaseOrder, PurchaseOrderItem |
/purchase-orders |
src/cluster_erp/modules/procurement/purchase_orders/routes.py:35 |
purchase_contracts |
Outline agreements | PurchaseContract, PurchaseContractItem |
/purchase-contracts |
src/cluster_erp/modules/procurement/purchase_contracts/routes.py:33-34 |
info_records |
Vendor price master and price history | PurchasingInfoRecord, PurchasingInfoRecordPrice |
/info-records |
src/cluster_erp/modules/procurement/info_records/routes.py:24-25 |
critical_materials |
Materials that must not run short | CriticalMaterial |
/critical-materials |
src/cluster_erp/modules/procurement/critical_materials/routes.py:24 |
substitution_groups |
Interchangeable materials | MaterialSubstitutionGroup, MaterialSubstitutionMember |
/substitution-groups |
src/cluster_erp/modules/procurement/substitution_groups/routes.py:27 |
mrp |
Planning runs, run items, PIRs, safety time, quotas, netting groups, ATP | MrpRun, MrpRunItem and five more |
/mrp |
src/cluster_erp/modules/procurement/mrp/routes.py:54 |
All routers are mounted under the module prefix with require_app("procurement") (src/cluster_erp/modules/procurement/module.py:70-82). The shared helper delivery_address.py resolves the structured delivery address of orders and RFQs through GetAddressById and stores a text snapshot (src/cluster_erp/modules/procurement/delivery_address.py:1-13, src/cluster_erp/modules/procurement/delivery_address.py:78).
Data model¶
Each sub-module page lists its fields. All material lines carry product_id, product_model_id, and product_version_id; order lines may also be text items without a product (src/cluster_erp/modules/procurement/purchase_orders/schemas.py:20-37). Money columns are Numeric, for example the order total Numeric(19, 4) and the unit price Numeric(18, 4) (src/cluster_erp/modules/procurement/purchase_orders/models.py:81-82, src/cluster_erp/modules/procurement/purchase_orders/models.py:195-200). Line totals are rounded with ROUND_HALF_EVEN before storage (src/cluster_erp/modules/procurement/purchase_orders/services.py:307-312).
Screens and metadata¶
get_metadata declares a sidebar group Procurement (Turkish Satın Alma) with 19 sections (src/cluster_erp/modules/procurement/module.py:1072-1418). Seven sections are custom widgets of the gated bundle: MRP Dashboard, Exception Workbench, Planned Orders, Stock Requirements, Segmentation (XYZ), DDMRP Buffers, and ATP/CTP. The others are lists: Forecast (PIR), MRP Runs, Safety Time Periods, Quota Arrangements, Purchase Requests, Purchasing RFQs, Purchase Orders, Purchase Contracts, Info Records, Critical Materials, and Substitution Groups. The RFQ comparison is the eighth widget, purchase_rfq_comparison (gated_apps/procurement/app.js:1647-1656). See gated app bundles and desktop module screens.
Status and actions¶
Statuses and actions are listed on each sub-module page. The diagram shows the main path from a requirement to stock.
flowchart LR MRP["MrpRun items"] --> PR["PurchaseRequest"] PR --> RFQ["PurchaseRfq"] RFQ --> Q["PurchaseRfqQuotation"] Q --> AW["award"] AW --> PO["PurchaseOrder"] PR --> PO PO --> GR["receive_item"] GR --> INV["PostGoodsReceipt to inventory"] AW --> IR["PurchasingInfoRecord via SupplierQuotationAwarded"]
In prose: an MRP run creates purchase requests from its items (src/cluster_erp/modules/procurement/mrp/services.py:331). A request can go to an RFQ through purchase_request_id (src/cluster_erp/modules/procurement/purchase_rfqs/models.py:49), or straight to an order with POST /purchase-orders/from-pr/{pr_id} once approved (src/cluster_erp/modules/procurement/purchase_orders/services.py:349-413). Awarding RFQ lines creates one order per awarded vendor (src/cluster_erp/modules/procurement/purchase_rfqs/services.py:1281-1286). Receiving an order line posts a goods receipt to inventory with PostGoodsReceipt (src/cluster_erp/modules/procurement/purchase_orders/services.py:799-836). An award of a supplier quotation in the purchasing_quotations module updates the info records (src/cluster_erp/modules/procurement/module.py:813-862).
Business rules¶
The rules of each sub-module are on its page. Two rules apply across the module:
- Every material line is checked with
ensure_product_breakdownthrough the EventBus (src/cluster_erp/modules/procurement/purchase_orders/services.py:279,src/cluster_erp/modules/procurement/purchase_requests/services.py:233). - Documents use yearly sequences:
supplier,purchase_request,purchase_order,purchase_contract,info_record,substitution_group, andmrp_pir(src/cluster_erp/modules/procurement/suppliers/services.py:130,src/cluster_erp/modules/procurement/purchase_requests/services.py:208,src/cluster_erp/modules/procurement/purchase_orders/services.py:245).
Events and queries¶
The module consumes 31 contracts and produces 48, counted as on the parties module page. The full list is on the contracts reference.
| Direction | Contract class | Handler or emitter | Source |
|---|---|---|---|
| emits | PrCreated, PrApproved, PrCancelled |
purchase request service | src/cluster_erp/modules/procurement/purchase_requests/services.py:279, src/cluster_erp/modules/procurement/purchase_requests/services.py:522, src/cluster_erp/modules/procurement/purchase_requests/services.py:547 |
| emits | PoCreated, PoSent, PoAcknowledged, PoReceivedFull, PoReceivedPartial, PoCancelled |
purchase order service | src/cluster_erp/modules/procurement/purchase_orders/services.py:338, src/cluster_erp/modules/procurement/purchase_orders/services.py:648-921 |
| emits | PartyRoleSet |
supplier create and delete | src/cluster_erp/modules/procurement/suppliers/services.py:138, src/cluster_erp/modules/procurement/suppliers/services.py:195 |
| emits | MrpRunCompleted, CriticalMaterialAlert |
MRP engine | src/cluster_erp/modules/procurement/mrp/engine.py:4073, src/cluster_erp/modules/procurement/mrp/engine.py:4106 |
| answers query | GetPurchaseOrderById, GetPurchaseRequestById, GetOpenPosForProduct, GetOpenPoLinesForReceipt, GetPlannedOrdersForCapacity, GetBulkOpenPos, GetCriticalMaterials, GetSubstitutesForProduct, GetPurchaseRfqQuotations, CreateFollowOnFromSupplierQuotation, ReconcilePoReceiptReversal |
handlers in module.py |
src/cluster_erp/modules/procurement/module.py:139-202 |
| subscribes | PartyUpdated, PartyDeleted |
supplier facet sync | src/cluster_erp/modules/procurement/module.py:122-125 |
| subscribes | SalesOrderOpened, ProductionOrderCreated, BomActivated, GoodsReceived, GoodsIssued, StockTransferred, StockAdjusted, GoodsMovementReversed, StockCategoryTransferred, ProductionOrderCompleted, BomItemAdded, BomItemChanged, ProductUpdated |
MRP staleness and planning file | src/cluster_erp/modules/procurement/module.py:182-207 |
| subscribes | SupplierQuotationAwarded |
info record upsert | src/cluster_erp/modules/procurement/module.py:208 |
| subscribes | CollectSubjectData, AnonymiseSubject, DescribeAnalyticsFacts, DescribeFieldConsumers |
privacy, analytics, tenant fields | src/cluster_erp/modules/procurement/module.py:88, src/cluster_erp/modules/procurement/module.py:136-137, src/cluster_erp/modules/procurement/module.py:218-219 |
Permissions¶
Each sub-module page lists its keys. The module checks the families supplier.*, purchase_request.*, purchase_rfq.*, purchase_order.*, purchase_contract.*, info_record.*, critical_material.*, substitution_group.*, and mrp_run.* with require_permission in the route files.
Privacy, retention, and history¶
privacy_handlers.py answers data-subject requests for supplier facets of individual parties: CollectSubjectData returns the rows, and AnonymiseSubject overwrites the identifying values and deactivates the rows (src/cluster_erp/modules/procurement/privacy_handlers.py:1-11). Deletes set deleted_at (src/cluster_erp/modules/procurement/suppliers/services.py:185-191). See privacy and data-subject requests and change history.
Analytics facts¶
analytics_facts.py contributes two fact sets. purchase_order over procurement_purchase_orders has the measures order_count, total_amount, average_amount, and median_amount, with currency as the currency field. purchase_request over procurement_purchase_requests has request_count and total_estimated_cost (src/cluster_erp/modules/procurement/analytics_facts.py:19-179). See analytics facts.
Settings and reference data¶
The module has no settings section. MRP reads lot-sizing defaults per ABC class from Settings (src/cluster_erp/modules/procurement/mrp/engine.py:3037-3048); see settings reference.
Tests¶
Found by a grep for modules.procurement in tests/ and for the path /procurement/ in web-client/_e2e_*.mjs.
| Kind | File | Covers |
|---|---|---|
| pytest | tests/test_procurement_descriptions.py |
action descriptions in procurement metadata |
| pytest | tests/test_data_map_package3.py, tests/test_party_form_contract.py |
supplier facet and party form contracts |
| e2e | web-client/_e2e_procurement_app.mjs |
the procurement app |
| e2e | web-client/_e2e_procurement_audit_high.mjs, _medium, _low, _deferred |
audit findings across requests, RFQs, and orders |
| e2e | web-client/_e2e_procurement_gr.mjs |
goods receipt |
| e2e | web-client/_e2e_rfq_portal_token.mjs |
the vendor portal |
| e2e | web-client/_e2e_mrp_hygiene_faz0.mjs to web-client/_e2e_mrp_atp_faz8.mjs (nine suites) |
MRP |
Discrepancies¶
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| supplier facet | Supplier |
The supplier role record of a party, with commercial defaults. | Tedarikçi rolü | src/cluster_erp/modules/procurement/suppliers/models.py:13 |
| delivery snapshot | resolve_delivery_snapshot |
The address text copied onto an order or RFQ when it is set. | Teslimat adresi anlık görüntüsü | src/cluster_erp/modules/procurement/delivery_address.py:78 |
Related pages¶
- Modules index
- Suppliers
- Purchase requests
- Purchasing RFQs
- Purchase orders
- Purchase contracts and info records
- Material requirements planning
- Critical materials and substitution
- Purchasing quotations module
- Inventory module
- API reference for this module
Verified against commit 92f8051 on 2026-11-13.