Commodity
Introduction
The Commodity entity represents individual freight items, packages, or cargo pieces in the TMS. As an aggregate root, Commodity supports sophisticated features including hierarchical container structures (commodities containing other commodities), multiple tracking numbers, warehouse location tracking, and automatic charge recalculation triggers.
Commodities are highly flexible, supporting various measurement systems (imperial/metric), package types, inventory integration, and custom values for extensibility. The entity automatically maintains calculated totals for weight, volume, and value, cascading changes to parent containers when nested items are modified.
Entity Structure
Properties
| Property Name | Type | Required | Description |
|---|---|---|---|
| CommodityId | int | Yes | Unique identifier for the commodity (primary key) |
| OrganizationId | int | Yes | Organization owning this commodity (multi-tenancy) |
| Description | string | Yes | Commodity description/name |
| Pieces | int | Yes | Number of pieces/packages |
| CommodityTypeId | int? | No | Type classification (e.g., Electronics, Textiles) |
| CommodityType | CommodityType | No | Navigation to type definition |
| CommodityStatusId | int? | No | Current status (e.g., In Warehouse, Shipped) |
| CommodityStatus | CommodityStatus | No | Navigation to status definition |
| PackageTypeId | int? | No | Package type (carton, pallet, crate, etc.) |
| PackageType | PackageType | No | Navigation to package type |
| ContainerCommodityId | int? | No | Parent container ID for hierarchical nesting |
| ContainerCommodity | Commodity | No | Parent container (self-reference) |
| ContainerCommodities | ICollection<Commodity> | No | Child commodities in this container |
| Length | decimal? | No | Length dimension |
| Width | decimal? | No | Width dimension |
| Height | decimal? | No | Height dimension |
| DimensionsUnit | DimensionsUnit | Yes | Unit for dimensions (Inch, Centimeter, Meter) |
| Weight | decimal? | No | Weight per piece (or total if WeightByTotal=true) |
| WeightTotal | decimal? | No | Total weight (auto-calculated: Weight × Pieces) |
| WeightByTotal | bool | Yes | If true, Weight field is total (not per piece) |
| WeightUnit | WeightUnit | Yes | Unit for weight (Pound, Kilogram, Ton) |
| VolumePiece | decimal? | No | Volume per piece (auto-calculated from dimensions) |
| VolumeTotal | decimal? | No | Total volume (auto-calculated: VolumePiece × Pieces) |
| VolumeUnit | VolumeUnit | Yes | Unit for volume (CubicFoot, CubicMeter, Liter) |
| Quantity | int? | No | Quantity (distinct from Pieces - e.g., units within packages) |
| Unit | string? | No | Unit of measure for Quantity (e.g., "EA", "BOX") |
| UnitaryValue | decimal? | No | Value per unit |
| UnitaryValueTotal | decimal? | No | Total value (auto-calculated) |
| ValueByTotal | bool | Yes | If true, UnitaryValue is total value |
| BillToContactId | int? | No | Contact to bill for this commodity (charge filtering) |
| BillToContact | Contact | No | Navigation to billing contact |
| WarehouseLocationId | int? | No | Current warehouse location |
| WarehouseLocation | WarehouseLocation | No | Navigation to warehouse location |
| JobId | Guid? | No | Associated job |
| Job | Job | No | Navigation to job |
| InventoryItemId | int? | No | Linked inventory/SKU item |
| InventoryItem | InventoryItem | No | Navigation to inventory item |
| SerialNumber | string? | No | Serial number for the commodity |
| Note | string? | No | Additional notes/comments |
| IsDeleted | bool? | No | Soft delete flag (default: false) |
| CustomValues | Dictionary<string, object?> | No | Extensible custom properties dictionary |
| SearchVector | NpgsqlTsVector | No | Full-text search vector (PostgreSQL) |
| Created | DateTime | Yes | Creation timestamp (inherited from AuditableEntity) |
| CreatedBy | string | Yes | User ID who created (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 orders containing this commodity |
| CommodityTrackingNumbers | ICollection<CommodityTrackingNumber> | Multiple tracking numbers |
| CommodityTags | ICollection<CommodityTag> | Tags assigned to this commodity |
| AllTags | ICollection<CommodityAllTagsView> | View of all tags (flattened) |
| ContainerCommodity | Commodity | Parent container (self-reference) |
| ContainerCommodities | ICollection<Commodity> | Child commodities in this container |
| Organization | Organization | Parent organization |
| CommodityType | CommodityType | Type classification |
| CommodityStatus | CommodityStatus | Current status |
| PackageType | PackageType | Package classification |
| WarehouseLocation | WarehouseLocation | Current warehouse location |
| Job | Job | Associated job |
| InventoryItem | InventoryItem | Linked inventory SKU |
| BillToContact | Contact | Billing contact for charge filtering |
Enumerations
DimensionsUnit:
Inch(0)Centimeter(1)Meter(2)
WeightUnit:
Pound(0)Kilogram(1)Ton(2)
VolumeUnit:
CubicFoot(0)CubicMeter(1)Liter(2)
Key Concepts
1. Hierarchical Container System
Commodities can contain other commodities through the ContainerCommodityId relationship:
Container Commodity (ContainerCommodityId = null)
├── Commodity 1 (ContainerCommodityId = Container.CommodityId)
├── Commodity 2 (ContainerCommodityId = Container.CommodityId)
└── Commodity 3 (ContainerCommodityId = Container.CommodityId)
Use Cases:
- Palletized shipments (pallet contains cartons)
- Containerized cargo (container contains packages)
- Consolidated shipments (master package contains individual items)
2. Automatic Totals Calculation
The entity automatically calculates and maintains totals:
- VolumeTotal = VolumePiece × Pieces
- WeightTotal = Weight × Pieces (unless WeightByTotal=true)
- UnitaryValueTotal = UnitaryValue × Pieces/Quantity (unless ValueByTotal=true)
Totals are refreshed automatically when dimensions, weight, pieces, or container contents change.
3. Charge Recalculation Tracking
An internal flag (_requireChargeRecalculation) tracks when properties affecting charges change:
- Weight, dimensions, pieces, quantity
- Package type, commodity type
- BillToContactId (charge filtering)
Use RequiresChargeRecalculation() to check the flag and ResetChargeRecalculationFlag() after recalculating.
4. Warehouse Location Cascading
When a container's warehouse location changes, the change automatically cascades to all nested commodities:
Container.ChangeWarehouseLocationId(newLocationId);
// All ContainerCommodities automatically updated to same location