1use crate::error::CommerceModelError;
2use crate::identifiers::CurrencyCode;
3use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum ProductKind {
7 Physical,
8 Digital,
9 Service,
10 Membership {
11 entitlement_key: crate::EntitlementKey,
12 },
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum ProductStatus {
17 Draft,
18 Active,
19 Archived,
20}
21
22impl fmt::Display for ProductStatus {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 match self {
25 Self::Draft => f.write_str("draft"),
26 Self::Active => f.write_str("active"),
27 Self::Archived => f.write_str("archived"),
28 }
29 }
30}
31
32#[derive(Debug, Clone, Copy, PartialEq, Eq)]
33pub enum CheckoutStatus {
34 Draft,
35 ReadyForPayment,
36 AwaitingPayment,
37 Paid,
38 Completed,
39 Cancelled,
40}
41
42impl fmt::Display for CheckoutStatus {
43 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44 match self {
45 Self::Draft => f.write_str("draft"),
46 Self::ReadyForPayment => f.write_str("ready_for_payment"),
47 Self::AwaitingPayment => f.write_str("awaiting_payment"),
48 Self::Paid => f.write_str("paid"),
49 Self::Completed => f.write_str("completed"),
50 Self::Cancelled => f.write_str("cancelled"),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56pub enum OrderStatus {
57 PendingPayment,
58 Paid,
59 Fulfilled,
60 PartiallyRefunded,
61 Refunded,
62 Cancelled,
63}
64
65impl fmt::Display for OrderStatus {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 match self {
68 Self::PendingPayment => f.write_str("pending_payment"),
69 Self::Paid => f.write_str("paid"),
70 Self::Fulfilled => f.write_str("fulfilled"),
71 Self::PartiallyRefunded => f.write_str("partially_refunded"),
72 Self::Refunded => f.write_str("refunded"),
73 Self::Cancelled => f.write_str("cancelled"),
74 }
75 }
76}
77
78#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum AdjustmentKind {
80 Promotion,
81 Voucher,
82 MembershipBenefit,
83 Shipping,
84 Tax,
85 Manual,
86}
87
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89pub enum AdjustmentDirection {
90 Discount,
91 Surcharge,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub struct Money {
96 currency: CurrencyCode,
97 amount_minor: i64,
98}
99
100impl Money {
101 pub fn new(currency: CurrencyCode, amount_minor: i64) -> Result<Self, CommerceModelError> {
102 if amount_minor < 0 {
103 return Err(CommerceModelError::NegativeAmount {
104 field: "amount_minor",
105 amount_minor,
106 });
107 }
108
109 Ok(Self {
110 currency,
111 amount_minor,
112 })
113 }
114
115 pub fn zero(currency: CurrencyCode) -> Self {
116 Self {
117 currency,
118 amount_minor: 0,
119 }
120 }
121
122 pub fn currency(&self) -> &CurrencyCode {
123 &self.currency
124 }
125
126 pub fn amount_minor(&self) -> i64 {
127 self.amount_minor
128 }
129
130 pub fn checked_add(&self, other: &Self) -> Result<Self, CommerceModelError> {
131 crate::pricing::ensure_same_currency(&self.currency, &other.currency)?;
132 let amount = self.amount_minor.checked_add(other.amount_minor).ok_or(
133 CommerceModelError::AmountOverflow {
134 field: "money_addition",
135 },
136 )?;
137 Self::new(self.currency.clone(), amount)
138 }
139
140 pub fn checked_mul(&self, quantity: u32) -> Result<Self, CommerceModelError> {
141 let amount = self.amount_minor.checked_mul(i64::from(quantity)).ok_or(
142 CommerceModelError::AmountOverflow {
143 field: "money_multiplication",
144 },
145 )?;
146 Self::new(self.currency.clone(), amount)
147 }
148}