This page describes the trade_documents sub-module of src/cluster_erp/modules/sales_orders/. A trade document (TradeDocument) is a packing list or a delivery note for one shipment. Generation freezes the shipment's data as a JSON snapshot, renders HTML from it in the document language, prints a PDF, and stores the PDF as an attachment of the record. The shipment itself is described on shipments.
Scope and source¶
- Defined in:
trade_documents/models.py(TradeDocument,DOCUMENT_TYPES),services.py(TradeDocumentService,compose_number),builder.py(SnapshotBuilder),render.py(RENDERERS),i18n/__init__.pywithi18n/en.jsonandi18n/tr.json,templates/document.css,routes.py, andmetadata.py. - Count: 1 table, 4 routes (
@router.decorators), 2 document types.
Document fields¶
| Name | Meaning | Source |
|---|---|---|
shipment_id, sales_order_id |
The shipment and its order | src/cluster_erp/modules/sales_orders/trade_documents/models.py:40-48 |
doc_type |
packing_list or delivery_note |
src/cluster_erp/modules/sales_orders/trade_documents/models.py:16, src/cluster_erp/modules/sales_orders/trade_documents/models.py:49 |
number, version_no |
Document number and version; unique per type among live rows | src/cluster_erp/modules/sales_orders/trade_documents/models.py:28-38, src/cluster_erp/modules/sales_orders/trade_documents/models.py:50-51 |
language |
Language code of the labels | src/cluster_erp/modules/sales_orders/trade_documents/models.py:52 |
snapshot |
Everything the PDF printed, money as strings | src/cluster_erp/modules/sales_orders/trade_documents/models.py:53-54 |
attachment_id |
The rendered PDF in core attachments | src/cluster_erp/modules/sales_orders/trade_documents/models.py:55-56 |
stale, superseded_by_id |
Source changed after generation; newer version | src/cluster_erp/modules/sales_orders/trade_documents/models.py:57-67 |
generated_at, generated_by |
Generation record | src/cluster_erp/modules/sales_orders/trade_documents/models.py:68-69 |
Document routes¶
| Method and path | Permission | Source |
|---|---|---|
GET /sales-orders/trade-documents/ |
trade_document.read |
src/cluster_erp/modules/sales_orders/trade_documents/routes.py:37 |
GET /sales-orders/trade-documents/{document_id} |
trade_document.read |
src/cluster_erp/modules/sales_orders/trade_documents/routes.py:68 |
GET /sales-orders/trade-documents/{document_id}/download |
trade_document.read |
src/cluster_erp/modules/sales_orders/trade_documents/routes.py:84 |
POST /sales-orders/shipments/{shipment_id}/generate-documents |
trade_document.create |
src/cluster_erp/modules/sales_orders/trade_documents/routes.py:102 |
Generation¶
The diagram shows one generation call.
flowchart TD G["TradeDocumentService.generate"] --> C["checks at level export"] C --> L["doc_labels for document_language"] L --> S["SnapshotBuilder.build over the EventBus"] S --> N["compose_number from the settings template"] N --> R["RENDERERS: HTML from snapshot and labels"] R --> P["PDF renderer"] P --> A["AttachmentService.create"] A --> V["previous version superseded_by_id set"] V --> E["shipment event"]
In prose: generation locks the shipment and runs the dispatch checks at the export level, whatever the tenant's dispatch level; any error refuses the whole call (src/cluster_erp/modules/sales_orders/trade_documents/services.py:169-200). It loads the labels of the setting document_language and builds one snapshot for all documents. The builder reads parties, addresses, products, units of measure, countries, and the project through EventBus queries (src/cluster_erp/modules/sales_orders/trade_documents/builder.py:1-30, src/cluster_erp/modules/sales_orders/trade_documents/services.py:201-205). The packing list is rendered first so that the delivery note can quote its number (src/cluster_erp/modules/sales_orders/trade_documents/services.py:209-210, src/cluster_erp/modules/sales_orders/trade_documents/services.py:264-265). For each type the service composes the number, renders HTML, prints the PDF with a footer, saves the record and the attachment, and marks the previous version superseded (src/cluster_erp/modules/sales_orders/trade_documents/services.py:211-263). Last, it writes a shipment event (src/cluster_erp/modules/sales_orders/trade_documents/services.py:267-278).
Numbering¶
The number comes from the settings templates packing_list_no_template (default PL-{shipment_code}) and delivery_note_no_template (default DN-{shipment_code}) (src/cluster_erp/modules/sales_orders/settings/models.py:37-44, src/cluster_erp/modules/sales_orders/trade_documents/services.py:145-152). The placeholders are {shipment_code}, {order_no}, {customer_po_no}, {project_no}, {year}, and {seq}. {seq} takes the next value of a sequence per document type. A placeholder with an empty value refuses the generation instead of printing a blank (src/cluster_erp/modules/sales_orders/trade_documents/services.py:42-85, src/cluster_erp/modules/sales_orders/trade_documents/services.py:213-226).
Languages and templates¶
The labels are JSON dictionaries, one file per language in trade_documents/i18n/. A file names itself under _language; adding a language is adding a file. An unknown code falls back to en (src/cluster_erp/modules/sales_orders/trade_documents/i18n/__init__.py:1-53). The renderers are pure functions that build HTML from the snapshot and the labels, with the stylesheet templates/document.css and the core font CSS (src/cluster_erp/modules/sales_orders/trade_documents/render.py:1-20, src/cluster_erp/modules/sales_orders/trade_documents/render.py:302-375). The PDF engine is described on PDF and system mail.
Constraints and validation¶
- A document never changes after issue; a fix is made on the source record and the document regenerated as the next version (
src/cluster_erp/modules/sales_orders/trade_documents/models.py:19-26). - Order changes such as a PO revision or a bill-to change mark every live, current document of the order stale (
src/cluster_erp/modules/sales_orders/trade_documents/services.py:279-295,src/cluster_erp/modules/sales_orders/orders/services.py:965-980). - Download returns the filed PDF; a document without a rendered file returns 404 (
src/cluster_erp/modules/sales_orders/trade_documents/services.py:130-142). - Only the two types in
DOCUMENT_TYPESare produced; a request without a known type is refused (src/cluster_erp/modules/sales_orders/trade_documents/services.py:183-185).
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| packing list | packing_list |
The document that lists packages, weights, and contents of a shipment. | Çeki listesi | src/cluster_erp/modules/sales_orders/trade_documents/metadata.py:20 |
| delivery note | delivery_note |
The document that accompanies the goods to the receiver. | Sevk irsaliyesi | src/cluster_erp/modules/sales_orders/trade_documents/metadata.py:21 |
| document snapshot | snapshot |
The frozen JSON data a document printed. | Belge anlık görüntüsü | src/cluster_erp/modules/sales_orders/trade_documents/models.py:53-54 |
| stale document | stale |
A document whose source data changed after it was generated. | Bayat belge | src/cluster_erp/modules/sales_orders/trade_documents/models.py:57-61 |
Related pages¶
Verified against commit 92f8051 on 2026-11-13.