stateset_core/errors/
order.rs1use super::StateTransitionError;
4use std::fmt;
5use uuid::Uuid;
6
7#[derive(Debug, thiserror::Error)]
23#[non_exhaustive]
24pub enum OrderError {
25 #[error("order not found: {0}")]
27 NotFound(Uuid),
28
29 #[error("order cannot be cancelled in status: {status}")]
31 CannotCancel {
32 status: String,
34 },
35
36 #[error("order cannot be refunded: {reason}")]
38 CannotRefund {
39 reason: String,
41 },
42
43 #[error("{0}")]
45 InvalidTransition(StateTransitionError<OrderStatusLabel>),
46
47 #[error(transparent)]
49 Other(Box<dyn std::error::Error + Send + Sync>),
50}
51
52impl OrderError {
53 #[inline]
55 #[track_caller]
56 #[must_use]
57 pub const fn not_found(id: Uuid) -> Self {
58 Self::NotFound(id)
59 }
60
61 #[track_caller]
63 pub fn cannot_cancel(status: impl fmt::Display) -> Self {
64 Self::CannotCancel { status: status.to_string() }
65 }
66
67 #[track_caller]
69 pub fn cannot_refund(reason: impl Into<String>) -> Self {
70 Self::CannotRefund { reason: reason.into() }
71 }
72
73 #[track_caller]
75 pub fn invalid_transition(from: impl fmt::Display, to: impl fmt::Display) -> Self {
76 Self::InvalidTransition(StateTransitionError::new(
77 OrderStatusLabel(from.to_string()),
78 OrderStatusLabel(to.to_string()),
79 ))
80 }
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
85pub struct OrderStatusLabel(pub String);
86
87impl fmt::Display for OrderStatusLabel {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 f.write_str(&self.0)
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn not_found_display() {
99 let id = Uuid::nil();
100 let err = OrderError::not_found(id);
101 assert!(err.to_string().contains("not found"));
102 assert!(err.to_string().contains(&id.to_string()));
103 }
104
105 #[test]
106 fn cannot_cancel_display() {
107 let err = OrderError::cannot_cancel("shipped");
108 assert!(err.to_string().contains("shipped"));
109 }
110
111 #[test]
112 fn invalid_transition_display() {
113 let err = OrderError::invalid_transition("pending", "delivered");
114 let msg = err.to_string();
115 assert!(msg.contains("pending"));
116 assert!(msg.contains("delivered"));
117 }
118
119 #[test]
120 fn converts_to_commerce_error() {
121 use crate::errors::CommerceError;
122
123 let order_err = OrderError::not_found(Uuid::nil());
124 let commerce_err: CommerceError = order_err.into();
125 assert!(commerce_err.is_not_found());
126 }
127
128 #[test]
129 fn other_variant() {
130 let io_err = std::io::Error::other("disk full");
131 let err = OrderError::Other(Box::new(io_err));
132 assert!(err.to_string().contains("disk full"));
133 }
134}