Skip to main content

commerce_theory/
workflow.rs

1use crate::dropshipping::*;
2use crate::orders::*;
3
4#[derive(Clone, Copy, Debug, PartialEq, Eq)]
5#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
6pub enum OrderTransitionLabel {
7    CapturePayment,
8    CancelBeforePayment,
9    MarkBackordered,
10    PackPaidOrder,
11    RefundPaidOrder,
12    ShipPackedOrder,
13    ConfirmDelivery,
14    RefundDeliveredOrder,
15    ReceiveBackorderPayment,
16    CancelBackorder,
17}
18
19#[must_use]
20pub const fn order_transition_target(
21    source: OrderStatus,
22    label: OrderTransitionLabel,
23) -> Option<OrderStatus> {
24    match (source, label) {
25        (OrderStatus::New, OrderTransitionLabel::CapturePayment) => Some(OrderStatus::Paid),
26        (OrderStatus::New, OrderTransitionLabel::CancelBeforePayment)
27        | (OrderStatus::Backordered, OrderTransitionLabel::CancelBackorder) => {
28            Some(OrderStatus::Cancelled)
29        }
30        (OrderStatus::New, OrderTransitionLabel::MarkBackordered) => Some(OrderStatus::Backordered),
31        (OrderStatus::Paid, OrderTransitionLabel::PackPaidOrder) => Some(OrderStatus::Packed),
32        (OrderStatus::Paid, OrderTransitionLabel::RefundPaidOrder) => Some(OrderStatus::Refunded),
33        (OrderStatus::Packed, OrderTransitionLabel::ShipPackedOrder) => Some(OrderStatus::Shipped),
34        (OrderStatus::Shipped, OrderTransitionLabel::ConfirmDelivery) => {
35            Some(OrderStatus::Delivered)
36        }
37        (OrderStatus::Delivered, OrderTransitionLabel::RefundDeliveredOrder) => {
38            Some(OrderStatus::Refunded)
39        }
40        (OrderStatus::Backordered, OrderTransitionLabel::ReceiveBackorderPayment) => {
41            Some(OrderStatus::Paid)
42        }
43        _ => None,
44    }
45}
46
47#[must_use]
48pub fn execute_order_trace(
49    start: OrderStatus,
50    trace: &[OrderTransitionLabel],
51) -> Option<Vec<OrderStatus>> {
52    let mut states = vec![start];
53    let mut current = start;
54    for label in trace {
55        current = order_transition_target(current, *label)?;
56        states.push(current);
57    }
58    Some(states)
59}
60
61#[must_use]
62pub fn paid_fulfillment_trace() -> Vec<OrderTransitionLabel> {
63    vec![
64        OrderTransitionLabel::CapturePayment,
65        OrderTransitionLabel::PackPaidOrder,
66        OrderTransitionLabel::ShipPackedOrder,
67        OrderTransitionLabel::ConfirmDelivery,
68    ]
69}
70
71#[must_use]
72pub fn unpaid_cancellation_trace() -> Vec<OrderTransitionLabel> {
73    vec![OrderTransitionLabel::CancelBeforePayment]
74}
75
76#[must_use]
77pub const fn terminal_order_status(status: OrderStatus) -> bool {
78    matches!(
79        status,
80        OrderStatus::Delivered | OrderStatus::Cancelled | OrderStatus::Refunded
81    )
82}
83
84#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
85pub struct OrderStatusLts;
86
87impl OrderStatusLts {
88    #[must_use]
89    pub const fn transition(
90        self,
91        source: OrderStatus,
92        label: OrderTransitionLabel,
93    ) -> Option<OrderStatus> {
94        order_transition_target(source, label)
95    }
96
97    #[must_use]
98    pub fn execute(
99        self,
100        start: OrderStatus,
101        trace: &[OrderTransitionLabel],
102    ) -> Option<Vec<OrderStatus>> {
103        execute_order_trace(start, trace)
104    }
105}
106
107#[must_use]
108pub const fn order_status_lts() -> OrderStatusLts {
109    OrderStatusLts
110}
111
112#[derive(Clone, Copy, Debug, PartialEq, Eq)]
113#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
114pub enum DropshipPOTransitionLabel {
115    Submit,
116    CancelBeforeSubmit,
117    Accept,
118    Reject,
119    CancelSubmitted,
120    ShipAccepted,
121    CancelAccepted,
122    ConfirmDelivery,
123}
124
125#[must_use]
126pub const fn dropship_po_transition_target(
127    source: DropshipPOStatus,
128    label: DropshipPOTransitionLabel,
129) -> Option<DropshipPOStatus> {
130    match (source, label) {
131        (DropshipPOStatus::Created, DropshipPOTransitionLabel::Submit) => {
132            Some(DropshipPOStatus::Submitted)
133        }
134        (DropshipPOStatus::Created, DropshipPOTransitionLabel::CancelBeforeSubmit)
135        | (DropshipPOStatus::Submitted, DropshipPOTransitionLabel::CancelSubmitted)
136        | (DropshipPOStatus::Accepted, DropshipPOTransitionLabel::CancelAccepted) => {
137            Some(DropshipPOStatus::Cancelled)
138        }
139        (DropshipPOStatus::Submitted, DropshipPOTransitionLabel::Accept) => {
140            Some(DropshipPOStatus::Accepted)
141        }
142        (DropshipPOStatus::Submitted, DropshipPOTransitionLabel::Reject) => {
143            Some(DropshipPOStatus::Rejected)
144        }
145        (DropshipPOStatus::Accepted, DropshipPOTransitionLabel::ShipAccepted) => {
146            Some(DropshipPOStatus::Shipped)
147        }
148        (DropshipPOStatus::Shipped, DropshipPOTransitionLabel::ConfirmDelivery) => {
149            Some(DropshipPOStatus::Delivered)
150        }
151        _ => None,
152    }
153}
154
155#[must_use]
156pub fn execute_dropship_po_trace(
157    start: DropshipPOStatus,
158    trace: &[DropshipPOTransitionLabel],
159) -> Option<Vec<DropshipPOStatus>> {
160    let mut states = vec![start];
161    let mut current = start;
162    for label in trace {
163        current = dropship_po_transition_target(current, *label)?;
164        states.push(current);
165    }
166    Some(states)
167}
168
169#[must_use]
170pub fn dropship_po_delivery_trace() -> Vec<DropshipPOTransitionLabel> {
171    vec![
172        DropshipPOTransitionLabel::Submit,
173        DropshipPOTransitionLabel::Accept,
174        DropshipPOTransitionLabel::ShipAccepted,
175        DropshipPOTransitionLabel::ConfirmDelivery,
176    ]
177}
178
179#[must_use]
180pub const fn terminal_dropship_po_status(status: DropshipPOStatus) -> bool {
181    matches!(
182        status,
183        DropshipPOStatus::Delivered | DropshipPOStatus::Cancelled | DropshipPOStatus::Rejected
184    )
185}
186
187#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
188pub struct DropshipPoLts;
189
190impl DropshipPoLts {
191    #[must_use]
192    pub const fn transition(
193        self,
194        source: DropshipPOStatus,
195        label: DropshipPOTransitionLabel,
196    ) -> Option<DropshipPOStatus> {
197        dropship_po_transition_target(source, label)
198    }
199
200    #[must_use]
201    pub fn execute(
202        self,
203        start: DropshipPOStatus,
204        trace: &[DropshipPOTransitionLabel],
205    ) -> Option<Vec<DropshipPOStatus>> {
206        execute_dropship_po_trace(start, trace)
207    }
208}
209
210#[must_use]
211pub const fn dropship_po_lts() -> DropshipPoLts {
212    DropshipPoLts
213}
214
215#[must_use]
216pub const fn dropship_polts() -> DropshipPoLts {
217    DropshipPoLts
218}