Order
Introduction
The Order entity is one of the most critical aggregate roots in CXTMS, representing shipments, quotes, warehouse bookings, and various other order types. As an aggregate root, Order controls all related child entities including commodities, charges, tracking events, documents, and entity relationships (shipper, consignee, carriers).
Orders serve as the primary operational unit in the TMS, tracking the entire lifecycle of freight movements from quotation through delivery. They integrate with the Job entity for multi-order consolidation, the accounting system for invoicing, and the workflow engine for automated business processes.
Entity Structure
Properties
| Property Name | Type | Required | Description |
|---|---|---|---|
| OrderId | int | Yes | Unique identifier for the order (primary key) |
| OrderNumber | string | Yes | Human-readable order number (unique within organization) |
| OrganizationId | int | Yes | Organization owning this order (multi-tenancy) |
| DivisionId | int | Yes | Division within organization for data partitioning |
| OrderType | OrderTypes | Yes | Type of order (see OrderTypes enum below) |
| OrderStatusId | int | Yes | Current status of the order |
| OrderStatus | OrderStatus | No | Navigation property to status definition |
| BillToContactId | int? | No | Contact to bill for this order |
| BillToContact | Contact | No | Navigation property to billing contact |
| EmployeeContactId | int? | No | Employee responsible for this order |
| EmployeeContact | Contact | No | Navigation property to employee |
| SalespersonContactId | int? | No | Salesperson who sold this order |
| SalespersonContact | Contact | No | Navigation property to salesperson |
| EquipmentTypeId | int? | No | Deprecated - Equipment type for this order |
| EquipmentType | EquipmentType | No | Navigation property to equipment type |
| TrackingNumber | string? | No | Primary tracking number for the shipment |
| IsDraft | bool | Yes | Whether order is in draft state (default: false) |
| LastOrderStatusModified | DateTime? | No | Timestamp when status was last changed |
| CustomValues | Dictionary<string, object?> | No | Extensible custom properties dictionary |
| SearchVector | NpgsqlTsVector | No | Full-text search vector (PostgreSQL) |
| ThirdPartyContactBilling | Contact | No | Third-party billing contact (not mapped) |
| Created | DateTime | Yes | Creation timestamp (inherited from AuditableEntity) |
| CreatedBy | string | Yes | User ID who created the order (inherited) |
| LastModified | DateTime | Yes | Last modification timestamp (inherited) |
| LastModifiedBy | string | Yes | User ID who last modified (inherited) |
Relationships (Navigation Properties)
| Relationship | Type | Description |
|---|---|---|
| OrderCommodities | ICollection<OrderCommodity> | Junction to commodities on this order |
| OrderCharges | ICollection<OrderCharges> | Junction to charges applied to this order |
| OrderEntities | ICollection<OrderEntity> | Dynamic entities (shipper, consignee, notify party, etc.) |
| OrderCarriers | ICollection<OrderCarrier> | Deprecated - Junction to carrier contacts (use OrderEntities instead) |
| OrderDocuments | ICollection<OrderDocument> | Documents attached to this order |
| OrderEvents | ICollection<OrderEvents> | Order event history |
| OrderTags | ICollection<OrderTag> | Tags assigned to this order |
| TrackingEvents | ICollection<TrackingEvent> | Shipment tracking events |
| Jobs | ICollection<Job> | Jobs that include this order |
| Organization | Organization | Parent organization |
| Division | Division | Parent division |
| Charges | ICollection<Charge> | Direct charges collection |
| Carriers | ICollection<Contact> | Deprecated - Carrier contacts collection (use OrderEntities instead) |
| AllTags | ICollection<OrderAllTagsView> | View of all tags (flattened) |
| AllRelatedOrders | ICollection<OrderRelatedOrdersView> | View of related orders |
OrderTypes Enum
The OrderTypes enum defines the various order classifications:
| Value | Name | Description |
|---|---|---|
| 0 | Order | Generic order type |
| 1 | Quote | Quotation/rate request |
| 2 | WarehouseReceipt | Warehouse order/receipt |
| 3 | Purchase | Pickup order (purchase) |
| 4 | ParcelShipment | Parcel/small package shipment |
| 5 | AirShipmentOrder | Air freight shipment |
| 6 | OceanShipmentOrder | Ocean freight shipment |
| 7 | CargoMovement | Cargo movement operation |
| 8 | EntityType | Entity type-driven order |
| 9 | PickupOrder | Pickup order |
| 10 | LoadOrder | Loading operation |
| 11 | BookingOrder | Booking request |
| 12 | Freight | General freight order |
| 13 | DeliveryOrder | Delivery operation |
YAML Configuration
Creating an Order
# Create a new ocean shipment order
- task: Order/Create@1
name: createOceanShipment
inputs:
organizationId: ${organizationId}
order:
orderNumber: "OCN-2025-00123"
orderType: OceanShipmentOrder
divisionId: ${divisionId}
billToContactId: ${customerId}
employeeContactId: ${employeeId}
salespersonContactId: ${salespersonId}
orderStatusId: ${newStatusId}
trackingNumber: "MAEU12345678"
isDraft: false
customValues:
customerReference: "PO-98765"
specialInstructions: "Temperature controlled"
incoterms: "FOB"
serviceLevel: "Express"
outputs:
- order: newOrder
Adding Commodities to Order
# Create order
- task: Order/Create@1
name: createAirShipment
inputs:
organizationId: ${organizationId}
order:
orderNumber: "AIR-2025-00456"
orderType: AirShipmentOrder
billToContactId: ${customerId}
divisionId: ${divisionId}
orderStatusId: ${activeStatusId}
outputs:
- order: order
# Add first commodity to order
- task: OrderCommodity/Create
name: addCommodity1
inputs:
organizationId: ${organizationId}
orderCommodity:
orderId: ${order.orderId}
commodityId: ${commodity1Id}
customValues:
sequence: 1
handling: "Fragile"
# Add second commodity to order
- task: OrderCommodity/Create
name: addCommodity2
inputs:
organizationId: ${organizationId}
orderCommodity:
orderId: ${order.orderId}
commodityId: ${commodity2Id}
customValues:
sequence: 2
handling: "Standard"
Setting Order Entities (Shipper/Consignee)
# Update order with shipper, consignee, and notify party
- task: Order/Update@1
name: setOrderEntities
inputs:
organizationId: ${organizationId}
orderId: ${orderId}
order:
orderEntities:
- entityType: "Shipper"
contactId: ${shipperContactId}
contactAddressId: ${shipperAddressId}
orderEntitySequence: 1
- entityType: "Consignee"
contactId: ${consigneeContactId}
contactAddressId: ${consigneeAddressId}
orderEntitySequence: 2
- entityType: "NotifyParty"
contactId: ${notifyContactId}
orderEntitySequence: 3
- entityType: "ForwardingAgent"
nonContactName: "Local Customs Broker"
customValues:
phone: "+1-555-0123"
email: "[email protected]"
orderEntitySequence: 4
Querying Order with Relationships
# Query order with all related data using GraphQL
- task: Query/GraphQL
name: getFullOrder
inputs:
organizationId: ${organizationId}
query: |
query GetOrder($orderId: Int!) {
order(id: $orderId) {
orderId
orderNumber
orderType
orderCommodities {
commodity {
commodityId
description
commodityType { name }
commodityTrackingNumbers { trackingNumber }
}
}
orderCharges {
charge {
chargeId
description
amount
accountingItem { code name }
}
}
orderEntities {
entityType
contact {
name
contactAddresses { address1 city state }
}
}
orderCarriers { contact { name } }
orderDocuments { fileName fileUrl }
orderTags { tag { name } }
trackingEvents {
eventDate
eventDefinition { name }
}
billToContact { name }
employeeContact { name }
salespersonContact { name }
orderStatus { statusName }
division { divisionName }
}
}
variables:
orderId: ${orderId}
outputs:
- response.order: fullOrder
Updating Order Status
# Change order status (triggers OrderStatusChangedEvent)
- task: Order/Update@1
name: updateOrderStatus
inputs:
organizationId: ${organizationId}
orderId: ${orderId}
order:
orderStatusId: ${deliveredStatusId}
Working with Custom Values
# Add/update custom values on an order
- task: Order/Update@1
name: updateCustomValues
inputs:
organizationId: ${organizationId}
orderId: ${orderId}
order:
customValues:
customerPO: "PO-2025-ABC"
projectCode: "PROJ-789"
specialHandling: true
requiredDeliveryDate: "2025-02-15"
insuranceValue: 50000
temperatureRange: "-20°C to -18°C"
Cloning an Order
# Clone an existing order as a new quote
# Note: Clone method needs to be wrapped in Order/Update or custom workflow task
- task: Order/Get
name: getOriginalOrder
inputs:
organizationId: ${organizationId}
orderId: ${originalOrderId}
outputs:
- order: originalOrder
- task: Order/Create@1
name: createClonedOrder
inputs:
organizationId: ${organizationId}
order:
orderNumber: "QUOTE-${timestamp}"
orderType: Quote
# Copy relevant fields from originalOrder
billToContactId: ${originalOrder.billToContactId}
divisionId: ${originalOrder.divisionId}
customValues: ${originalOrder.customValues}
outputs:
- order: clonedOrder
Domain Events
The Order entity publishes the following domain events:
OrderStatusChangedEvent
Published when ChangeOrderStatusId() or ChangeOrderStatus() methods detect a status change.
Event Data:
- Order entity with updated status
- Previous status (implicit - not in current event)
- New status (OrderStatusId, OrderStatus)
- Timestamp (LastOrderStatusModified)
Use Cases:
- Trigger email notifications on status changes
- Update external systems when order reaches specific statuses
- Log status history for audit trail
- Initiate downstream workflows (e.g., invoicing on "Delivered")
Example Workflow Trigger:
trigger: DomainEvent
eventType: OrderStatusChangedEvent
tasks:
- task: Email/Send
name: sendDeliveryNotification
conditions: ${event.order.orderStatus.name == "Delivered"}
inputs:
to: ${event.order.billToContact.email}
subject: "Shipment Delivered - ${event.order.orderNumber}"
templateId: ${orderDeliveredTemplateId}
variables:
order: ${event.order}
deliveryDate: ${event.order.lastOrderStatusModified}
Key Methods
The Order entity provides rich business logic through encapsulated methods:
Commodity Management
ChangeOrderCommodities(IEnumerable<OrderCommodity>)- Replace commodity list with intelligent mergingAppendOrderCommodities(IEnumerable<OrderCommodity>)- Add commodities without removing existingChangeCommodities(IEnumerable<Commodity>)- Update commodities directlyChangeOrderCommoditiesCustomValues(IEnumerable<OrderCommodity>)- Update custom values onlyAddCommodity(Commodity)- Add single commodity to order
Entity Roles Management
ChangeOrderEntities(IEnumerable<Dictionary<string, object>>)- Update from dictionariesSetOrderEntities(IEnumerable<OrderEntity>)- Set entities with intelligent mergingAddOrderEntity(OrderEntity)- Add single entity role
Charge Management
ChangeOrderCharges(IEnumerable<OrderCharges>)- Update charges with mergingAddCharge(Charge)- Add single charge to order
Carrier Management (Deprecated - Use OrderEntity instead)
ChangeOrderCarriers(IEnumerable<OrderCarrier>)- Deprecated - Update carrier assignmentsChangeCarriers(IEnumerable<Contact>)- Deprecated - Set carrier contacts directly
Tracking Management
ChangeEvents(IEnumerable<TrackingEvent>)- Update tracking events with mergingAddTrackingEvent(TrackingEvent)- Add single tracking event
Tag Management
ChangeOrderTags(List<int>)- Update tags by tag IDsChangeOrderTags(List<Tag>)- Update tags using Tag entities (supports unsaved tags)
Status Management
ChangeOrderStatusId(int)- Update status by ID (publishes domain event)ChangeOrderStatus(OrderStatus)- Update status by entity (publishes domain event)
Property Updates
ChangeOrderNumber(string)ChangeOrderType(OrderTypes)ChangeBillToContactId(int?)ChangeEmployeeContactId(int?)ChangeSalespersonContactId(int?)ChangeDivisionId(int)ChangeTrackingNumber(string?)ChangeIsDraft(bool)ChangeCustomValues(Dictionary<string, object?>)
Utility Methods
Clone(OrderTypes)- Create a copy of the order with new type
Aggregate Boundary
As an aggregate root, Order enforces the following boundaries:
Direct Children (managed by Order):
- OrderCommodity - Must be added/removed through Order methods
- OrderCharge - Managed through Order's charge methods
- OrderEntity - Controlled via Order's entity methods
- OrderCarrier - Deprecated - Updated through Order's carrier methods (use OrderEntity instead)
- OrderDocument - Managed through Order
- OrderTag - Controlled via tag methods
External References (independent entities):
- Contact (BillTo, Employee, Salesperson) - Referenced but not owned
- Commodity - Referenced through OrderCommodity junction
- Charge - Referenced through OrderCharges junction
- OrderStatus - Reference data
- Division, Organization - Organizational structure
Consistency Rules:
- Always modify child entities through Order's methods, not directly
- Status changes must go through
ChangeOrderStatusId()to trigger events - Use
SetOrderEntities()for intelligent merging of entity roles - Tags support both saved (TagId > 0) and unsaved (Tag entity) scenarios
Examples
Complete Order Creation Workflow
# Step 1: Create draft order
- task: Order/Create@1
name: createDraftOrder
inputs:
organizationId: ${organizationId}
order:
orderNumber: "ORD-2025-${sequenceNumber}"
orderType: OceanShipmentOrder
divisionId: ${divisionId}
billToContactId: ${customerId}
employeeContactId: ${currentUserId}
orderStatusId: ${draftStatusId}
isDraft: true
customValues:
origin: "Shanghai, China"
destination: "Los Angeles, USA"
estimatedShipDate: "2025-02-01"
outputs:
- order: newOrder
# Step 2: Add shipper and consignee
- task: Order/Update@1
name: setShipperConsignee
inputs:
organizationId: ${organizationId}
orderId: ${newOrder.orderId}
order:
orderEntities:
- entityType: "Shipper"
contactId: ${shipperContactId}
contactAddressId: ${shipperAddressId}
- entityType: "Consignee"
contactId: ${consigneeContactId}
contactAddressId: ${consigneeAddressId}
# Step 3: Add commodities to order
- task: OrderCommodity/Create
name: linkCommodities
collection: ${commodityList}
inputs:
organizationId: ${organizationId}
orderCommodity:
orderId: ${newOrder.orderId}
commodityId: ${item.commodityId}
# Step 4: Add carrier
- task: Order/Update@1
name: assignCarrier
inputs:
organizationId: ${organizationId}
orderId: ${newOrder.orderId}
order:
orderCarriers:
- carrierId: ${mainCarrierId}
# Step 5: Finalize order and activate
- task: Order/Update@1
name: finalizeOrder
inputs:
organizationId: ${organizationId}
orderId: ${newOrder.orderId}
order:
isDraft: false
orderStatusId: ${activeStatusId}
Order with Quote-to-Order Conversion
# Step 1: Create initial quote
- task: Order/Create@1
name: createQuote
inputs:
organizationId: ${organizationId}
order:
orderNumber: "QTE-${sequenceNumber}"
orderType: Quote
billToContactId: ${prospectId}
divisionId: ${divisionId}
orderStatusId: ${quoteStatusId}
customValues:
validUntil: "2025-02-28"
quotedRate: 2500
outputs:
- order: quote
# Step 2: Later, retrieve quote for conversion
- task: Order/Get
name: getQuote
inputs:
organizationId: ${organizationId}
orderId: ${quote.orderId}
outputs:
- order: quoteData
# Step 3: Create new shipment order from quote
- task: Order/Create@1
name: convertToShipment
inputs:
organizationId: ${organizationId}
order:
orderNumber: "ORD-${sequenceNumber}"
orderType: OceanShipmentOrder
billToContactId: ${quoteData.billToContactId}
divisionId: ${quoteData.divisionId}
orderStatusId: ${newOrderStatusId}
customValues:
convertedFromQuote: ${quoteData.orderNumber}
quotedRate: ${quoteData.customValues.quotedRate}
bookingNumber: "BKG-123456"
vesselName: "MAERSK ESSEX"
voyageNumber: "V2025-01"
outputs:
- order: shipmentOrder
Best Practices
1. Use Appropriate Order Types
- Use Quote for rate requests and quotations
- Use OceanShipmentOrder or AirShipmentOrder for actual shipments
- Use WarehouseReceipt for warehouse operations
- Use generic Order type sparingly - prefer specific types
2. Leverage Custom Values
- Store customer-specific data (PO numbers, project codes) in
customValues - Use custom values for flexible properties that vary by customer or order type
- Avoid custom values for data requiring indexing or complex queries
3. Manage Aggregate Boundaries
- Always add/update commodities through Order's methods (
ChangeOrderCommodities()) - Don't create OrderCommodity entities directly - use Order as entry point
- Use
SetOrderEntities()for intelligent merging of entity roles
4. Handle Draft Orders
- Create orders with
isDraft: truewhile collecting information - Finalize with
ChangeIsDraft(false)before activating - Draft orders can be partially complete without validation errors
5. Status Change Events
- Subscribe to
OrderStatusChangedEventfor workflow automation - Use events for email notifications, external system updates, and audit logging
- Status timestamp is automatically maintained in
LastOrderStatusModified
6. Tracking Numbers
- Use Order's
TrackingNumberfor primary/master tracking number - Use
CommodityTrackingNumberentities for house bills and multiple tracking numbers - Update tracking numbers through
ChangeTrackingNumber()for trim/validation
7. Entity Roles (Shipper/Consignee/Carrier)
- Use
OrderEntityfor all party roles including shipper, consignee, notify party, and carriers - Avoid deprecated
OrderCarrier- useOrderEntitywith appropriateEntityTypeinstead - Support non-contact entities using
NonContactNamefor adhoc parties - Maintain sequence with
OrderEntitySequencefor display order SetOrderEntities()provides intelligent merging and update logic
8. Performance Optimization
- Use selective
includeto load only needed relationships - Avoid loading
AllTagsandAllRelatedOrdersviews unless necessary - Query with filters on indexed fields (OrderNumber, OrganizationId, DivisionId)
9. Multi-Tenancy
- Always set
OrganizationId- required for data isolation - Use
DivisionIdfor sub-organizational partitioning - Queries automatically filter by organization context
10. Cloning Orders
- Use
Clone()for quote-to-order conversion - Clone method copies core properties and relationships
- Update type-specific properties after cloning
Related Topics
- OrderCommodity Entity - Junction table for order-commodity relationships
- OrderCharge Entity - Junction table for order-charge associations
- OrderEntity Entity - Dynamic entity roles (shipper, consignee, etc.)
- OrderCarrier Entity - Deprecated - Carrier assignments (use OrderEntity instead)
- OrderDocument Entity - Documents and document templates attached to orders
- OrderStatus Entity - Status definitions and lifecycle
- OrderTypes Reference - Order type classifications
- Job Entity - Multi-order aggregation
- Commodity Entity - Freight items
- Charge Entity - Charges and fees
- TrackingEvent Entity - Shipment tracking
- Contact Entity - Customers, vendors, carriers
- Division Entity - Organizational structure
- Workflow System - Order workflow automation