stateset_core/errors/
inventory.rs1use uuid::Uuid;
4
5#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum InventoryError {
18 #[error("inventory item not found: {0}")]
20 ItemNotFound(String),
21
22 #[error("insufficient stock for {sku}: requested {requested}, available {available}")]
24 InsufficientStock {
25 sku: String,
27 requested: String,
29 available: String,
31 },
32
33 #[error("reservation not found: {0}")]
35 ReservationNotFound(Uuid),
36
37 #[error("reservation expired: {0}")]
39 ReservationExpired(Uuid),
40
41 #[error("duplicate SKU: {0}")]
43 DuplicateSku(String),
44
45 #[error(transparent)]
47 Other(Box<dyn std::error::Error + Send + Sync>),
48}
49
50impl InventoryError {
51 #[track_caller]
53 pub fn item_not_found(id: impl Into<String>) -> Self {
54 Self::ItemNotFound(id.into())
55 }
56
57 #[track_caller]
59 pub fn insufficient_stock(
60 sku: impl Into<String>,
61 requested: impl Into<String>,
62 available: impl Into<String>,
63 ) -> Self {
64 Self::InsufficientStock {
65 sku: sku.into(),
66 requested: requested.into(),
67 available: available.into(),
68 }
69 }
70
71 #[inline]
73 #[track_caller]
74 #[must_use]
75 pub const fn reservation_not_found(id: Uuid) -> Self {
76 Self::ReservationNotFound(id)
77 }
78
79 #[inline]
81 #[track_caller]
82 #[must_use]
83 pub const fn reservation_expired(id: Uuid) -> Self {
84 Self::ReservationExpired(id)
85 }
86
87 #[track_caller]
89 pub fn duplicate_sku(sku: impl Into<String>) -> Self {
90 Self::DuplicateSku(sku.into())
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn item_not_found_display() {
100 let err = InventoryError::item_not_found("SKU-999");
101 assert_eq!(err.to_string(), "inventory item not found: SKU-999");
102 }
103
104 #[test]
105 fn insufficient_stock_display() {
106 let err = InventoryError::insufficient_stock("WIDGET", "10", "3");
107 let msg = err.to_string();
108 assert!(msg.contains("WIDGET"));
109 assert!(msg.contains("10"));
110 assert!(msg.contains("3"));
111 }
112
113 #[test]
114 fn reservation_not_found_display() {
115 let id = Uuid::nil();
116 let err = InventoryError::reservation_not_found(id);
117 assert!(err.to_string().contains(&id.to_string()));
118 }
119
120 #[test]
121 fn converts_to_commerce_error() {
122 use crate::errors::CommerceError;
123
124 let inv_err = InventoryError::item_not_found("SKU-001");
125 let commerce_err: CommerceError = inv_err.into();
126 assert!(commerce_err.is_not_found());
127 }
128
129 #[test]
130 fn duplicate_sku_display() {
131 let err = InventoryError::duplicate_sku("DUPE-001");
132 assert_eq!(err.to_string(), "duplicate SKU: DUPE-001");
133 }
134}