commerce_types/
lib.rs

1use chrono::{DateTime, NaiveDate, Utc};
2use currency_4217::Money;
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// The full request datatype for a purchase order
8#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
9pub struct OrderRequest {
10    /// Header of the order request
11    ///
12    /// This contains metadata about the order such as the `order_id`,
13    /// the address where the order must be shipped to and additional information.
14    pub header: OrderRequestHeader,
15    /// Items of the order
16    ///
17    /// These are the concrete items that were purchased in this order
18    pub items: Vec<ItemOut>,
19}
20
21/// Header of an order-request
22#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
23pub struct OrderRequestHeader {
24    /// Identifier of this order
25    pub order_id: String,
26    /// Date of the order
27    pub order_date: DateTime<Utc>,
28    /// Specifies weather or not this was a new order, or a modification to an existing one
29    pub order_type: OrderType,
30    /// Sum of all item prices plus shipping cost
31    pub total: Money,
32    /// Shipping Address
33    pub ship_to: Address,
34    /// Billing Address ( may be identical to shipping address )
35    pub bill_to: Address,
36    /// Shipping cost
37    pub shipping: Option<Money>,
38    /// Tax
39    pub tax: Option<Money>,
40    /// Optional comments on this order
41    pub comments: Option<String>,
42}
43
44/// A single item position in the purchase order
45#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
46pub struct ItemOut {
47    /// The line-number in the list of items that are purchased.
48    pub line_number: u32,
49    /// Total quantity of that item
50    pub quantity: u32,
51    /// Optional requested date of delivery, if possible
52    pub requested_delivery_date: Option<NaiveDate>,
53    /// Item that was purchased
54    pub item: Item,
55}
56
57/// Datatype for a single item - bundles item-id and item-detail
58#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
59pub struct Item {
60    /// ID of the requested item
61    pub item_id: ItemID,
62    /// Additional information like unit-price, description, unit of measure etc.
63    pub detail: ItemDetail,
64}
65
66/// Supplier and buyer part/item ID
67#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
68pub struct ItemID {
69    /// If known, the buyer can supply his/her own ID for this item
70    ///
71    /// If specified, this information can be used to map the item into the buyers IT-Systems
72    pub buyer_part_id: Option<String>,
73    /// Item-ID from the supplier
74    pub supplier_part_id: String,
75}
76
77/// Details of a single position in the purchase order
78#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
79pub struct ItemDetail {
80    /// For goods: price per unit
81    pub unit_price: Option<Money>,
82
83    /// Human-readable description
84    pub description: String,
85
86    /// For goods: unit of measure. For services, prefer `unit_rate` (cXML deprecates UnitPrice+UOM for services).
87    pub unit_of_measure: Option<UnitOfMeasure>,
88
89    pub classification: Option<Classification>,
90    pub manufacturer: Option<ManufacturerInfo>,
91    pub extrinsic: Option<HashMap<String, String>>,
92
93    /// Services: cXML-style service pricing (preferred over `unit_price` for services)
94    pub unit_rate: Option<UnitRate>,
95
96    /// Services: detailed info (labor/fee/travel), like in cXML `<SpendDetail>`
97    pub spend_detail: Option<SpendDetail>,
98}
99
100/// Address definition
101#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
102pub struct Address {
103    /// Name of the company / person that resides at the address
104    pub name: String,
105    /// Street information
106    pub street: Vec<String>,
107    /// City
108    pub city: String,
109    /// Postal code as string
110    pub postal_code: String,
111    /// Country string according to ISO 3166
112    pub country_iso: String,
113}
114
115/// Information about the manufacturer
116#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
117pub struct ManufacturerInfo {
118    pub part_id: String,
119    pub name: String,
120}
121
122/// Classification (UNSPSC, ECLASS, …)
123#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
124pub struct Classification {
125    pub domain: ClassificationDomain,
126    pub code: String,
127}
128
129#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
130pub enum ClassificationDomain {
131    UNSPSC,
132    ECLASS,
133    Custom(String),
134}
135
136/// Defines if the order was "new", an "update" or should be "delete"d
137#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
138pub enum OrderType {
139    New,
140    Update,
141    Delete,
142}
143
144/// Service pricing per time/measure unit (cXML `<UnitRate>`)
145#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
146pub struct UnitRate {
147    /// Money amount of the rate
148    pub rate: Money,
149    /// Unit the service is provided in (e.g., hours)
150    pub unit_of_measure: UnitOfMeasure,
151    /// Optional price basis quantity (e.g., rate applies per 8 hours)
152    pub price_basis_quantity: Option<PriceBasisQuantity>,
153    /// Optional rate code/context (e.g., payCode=Overtime)
154    pub term_reference: Option<TermReference>,
155}
156
157/// Quantity + UOM that the price is based on (cXML `<PriceBasisQuantity>`)
158#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
159pub struct PriceBasisQuantity {
160    pub quantity: u32,
161    pub unit_of_measure: UnitOfMeasure,
162}
163
164/// Identifies the meaning of a `UnitRate` (cXML `<TermReference>`)
165#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
166pub struct TermReference {
167    pub term_name: String,
168    pub term: String,
169}
170
171/// Time period for a service (cXML `<Period>`)
172#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
173pub struct Period {
174    pub start_date: DateTime<Utc>,
175    pub end_date: DateTime<Utc>,
176}
177
178/// Mirrors cXML `<SpendDetail>` → may contain Travel, Fee, and/or Labor
179#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
180pub struct SpendDetail {
181    pub travel_detail: Option<TravelDetail>,
182    pub fee_detail: Option<FeeDetail>,
183    pub labor_detail: Option<LaborDetail>,
184    pub extrinsic: Option<HashMap<String, String>>,
185}
186
187/// Labor service details (subset of cXML `<LaborDetail>`)
188#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
189pub struct LaborDetail {
190    /// Supplier quote/proposal reference (cXML `supplierReferenceCode` attribute)
191    pub supplier_reference_code: Option<String>,
192    /// The applicable rate (often required for labor)
193    pub unit_rate: Option<UnitRate>,
194    /// Period the labor occurred
195    pub period: Option<Period>,
196    /// The contractor performing the work
197    pub contractor: Option<Contractor>,
198    /// Free-text description of the job
199    pub job_description: Option<String>,
200    /// Person supervising the contractor
201    pub supervisor: Option<ContactInfo>,
202    /// Where the work is performed
203    pub work_location: Option<Address>,
204    /// Extra machine-readable fields
205    pub extrinsic: Option<HashMap<String, String>>,
206}
207
208/// Optional “fee” style charge
209#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
210pub struct FeeDetail {
211    pub amount: Money,
212    pub description: Option<String>,
213    pub extrinsic: Option<HashMap<String, String>>,
214}
215
216/// Optional “travel” style cost bucket (kept simple; extend as needed)
217#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
218pub struct TravelDetail {
219    pub amount: Option<Money>,
220    pub description: Option<String>,
221    pub period: Option<Period>,
222    pub extrinsic: Option<HashMap<String, String>>,
223}
224
225/// Who did the work (cXML `<Contractor>`)
226#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
227pub struct Contractor {
228    pub identifier: Option<ContractorIdentifier>,
229    pub contact: Option<ContactInfo>,
230}
231
232/// Contractor identifier (cXML `<ContractorIdentifier domain=...>`)
233#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
234pub struct ContractorIdentifier {
235    pub domain: ContractorIdentifierDomain,
236    pub value: String,
237}
238
239#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
240pub enum ContractorIdentifierDomain {
241    /// cXML: "buyerReferenceID"
242    BuyerReferenceID,
243    /// cXML: "supplierReferenceID"
244    SupplierReferenceID,
245    /// Any other agreed domain string
246    Custom(String),
247}
248
249/// Minimal contact info for supervisors/contractors (maps to cXML `<Contact>`)
250#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
251pub struct ContactInfo {
252    pub name: String,
253    pub email: Option<String>,
254    pub phone: Option<String>,
255    pub address: Option<Address>,
256}
257
258/// ISO Units-of-Measure-Codes or a freely defined measure
259#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
260pub enum UnitOfMeasure {
261    /// Each
262    EA,
263    /// Kilogram
264    KG,
265    /// Liter
266    LTR,
267    /// Meter
268    MTR,
269    /// Hour
270    HUR,
271    /// Day
272    DAY,
273    /// Month
274    MON,
275    /// A custom unit
276    Custom(String),
277}
278
279/// A transport service request/tender/booking (A→B or multi-stop)
280#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
281pub struct TransportationRequest {
282    /// Your unique ID (tender/booking)
283    pub request_id: String,
284
285    /// Current lifecycle state
286    pub status: TransportStatus,
287
288    /// Mode and service flavor (e.g., FTL/LTL/Express)
289    pub mode: TransportMode,
290    pub service_level: Option<String>,
291
292    /// Equipment needs (container/truck/trailer etc.)
293    pub equipment: Option<Equipment>,
294
295    /// "Ship-From" / origin
296    pub consignor: Address,
297    /// "Ship-To" / final destination
298    pub consignee: Address,
299
300    /// Optional intermediate stops / milk run
301    pub stops: Vec<LegStop>,
302
303    /// Shipment synopsis
304    pub cargo: CargoSummary,
305
306    /// High-level pickup/delivery lifecycle timings
307    pub pickup: StepTiming,
308    pub delivery: StepTiming,
309
310    /// Extras beyond “drive from A to B” (liftgate, hazardous, temperature control, etc.)
311    pub accessorials: Vec<Accessorial>,
312
313    /// Business references (PO, Delivery, Booking, BOL, SSCC, etc.)
314    pub references: HashMap<String, String>,
315
316    /// Quoted/awarded rate (flat, per hour/km/container — via UnitRate)
317    pub rate: Option<UnitRate>,
318
319    /// Execution updates (optional stream of events)
320    pub events: Vec<TransportEvent>,
321}
322
323/// Where you are in the request→execution flow
324#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
325pub enum TransportStatus {
326    Draft,     // built but not sent
327    RfqSent,   // RFQ/tender sent to providers
328    Awarded,   // provider selected
329    Booked,    // transport order/booking confirmed
330    InTransit, // pickup done and en route
331    Completed, // delivered (actuals available)
332    Cancelled,
333}
334
335/// Road/Air/Ocean/Rail or mixed
336#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
337pub enum TransportMode {
338    Road,
339    Air,
340    Ocean,
341    Rail,
342    Multimodal,
343}
344
345/// Requested vs planned vs estimated vs actual for one step (pickup or delivery)
346#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
347pub struct StepTiming {
348    /// What the shipper/transport user asked for
349    pub requested: Option<TimeWindow>,
350    /// What the carrier committed to after award/booking
351    pub planned: Option<TimeWindow>,
352    /// Rolling ETA during execution (single best estimate)
353    pub estimated: Option<DateTime<Utc>>,
354    /// Final actual timestamp
355    pub actual: Option<DateTime<Utc>>,
356}
357
358/// A time window (site availability / appointment window)
359#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
360pub struct TimeWindow {
361    pub earliest_utc: DateTime<Utc>,
362    pub latest_utc: DateTime<Utc>,
363}
364
365/// An intermediate stop (for multi-pick/drop). Each stop can model both arrival & departure.
366#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
367pub struct LegStop {
368    pub sequence: u32,
369    pub location: Address,
370    /// Arrival lifecycle timings at this stop
371    pub arrival: Option<StepTiming>,
372    /// Departure lifecycle timings at this stop
373    pub departure: Option<StepTiming>,
374    /// Optional notes / instructions specific to this stop
375    pub notes: Option<String>,
376}
377
378/// What you’re moving (high-level)
379#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
380pub struct CargoSummary {
381    /// Number of pieces ( pieces being cartons / pallets / containers / etc. )
382    pub pieces: u32,
383    /// Weight in kilogram
384    pub gross_weight_kg: f32,
385    /// Volume in cubic meters
386    pub volume_m3: Option<f32>,
387    /// Weather or not the cargo contains dangerous goods (ADR/IMDG/etc.)
388    pub dangerous_goods: bool,
389    /// Optional short description
390    pub commodity_description: Option<String>,
391    /// Optional standardized codes (e.g., HS code), free-form map
392    pub codes: Option<HashMap<String, String>>,
393}
394
395/// Equipment / container / trailer requirements
396#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
397pub struct Equipment {
398    /// Examples: "Box Truck 7.5t", "13.6m tautliner", "40HC", "20DV", "Reefer Trailer"
399    pub type_code: String,
400    /// Temperature range if controlled transport is needed (min, max)
401    pub temperature_c: Option<(f32, f32)>,
402    /// Free slots for axle/weight/class, door type, etc.
403    pub extrinsic: Option<HashMap<String, String>>,
404}
405
406/// Accessorial services (used to add cost / constraints on the delivery)
407#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
408pub enum Accessorial {
409    /// Liftgate
410    TailLift,
411    InsidePickup,
412    InsideDelivery,
413    /// Requires time-slot booking
414    Appointment,
415    /// Hazardous material handling
416    Hazardous,
417    /// Temperature managed transport
418    TempControl,
419    /// Brokerage / Clearance service
420    Customs,
421    /// Non-Commercial or limited access
422    Residential,
423    /// Billable waiting time
424    Detention,
425    /// Special handling / installation
426    WhiteGlove,
427    /// Any other option, represented as string
428    Other(String),
429}
430
431/// Execution/visibility event (optional stream)
432#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
433pub struct TransportEvent {
434    pub code: TransportEventCode,
435    pub timestamp: DateTime<Utc>,
436    /// Who reported it (carrier/TSP, telematics, port, visibility provider…)
437    pub source: Option<String>,
438    pub note: Option<String>,
439}
440
441/// A compact event vocabulary
442#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
443pub enum TransportEventCode {
444    PickupPlanned,
445    PickupEtaUpdated,
446    PickupActual,
447    DepartureActual,
448    ArrivalEtaUpdated,
449    ArrivalActual,
450    DeliveryPlanned,
451    DeliveryEtaUpdated,
452    DeliveryActual,
453    ProofOfDeliveryAvailable,
454    Exception,
455}