Skip to main content

coil_commerce/
model.rs

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}