stateset_embedded/store_credits.rs
1//! Store credit operations for managing customer store credit balances
2//!
3//! # Example
4//!
5//! ```rust,ignore
6//! use stateset_embedded::{Commerce, CreateStoreCredit, CustomerId, StoreCreditReason};
7//! use rust_decimal_macros::dec;
8//!
9//! let commerce = Commerce::new("./store.db")?;
10//!
11//! let credit = commerce.store_credits().create(CreateStoreCredit {
12//! customer_id: CustomerId::new(),
13//! initial_balance: dec!(25.00),
14//! reason: StoreCreditReason::ReturnRefund,
15//! ..Default::default()
16//! })?;
17//!
18//! println!("Store credit balance: ${}", credit.current_balance);
19//! # Ok::<(), stateset_embedded::CommerceError>(())
20//! ```
21
22use rust_decimal::Decimal;
23use stateset_core::{
24 AdjustStoreCredit, CreateStoreCredit, Result, StoreCredit, StoreCreditFilter, StoreCreditId,
25 StoreCreditTransaction,
26};
27use stateset_db::{Database, DatabaseCapability};
28use std::sync::Arc;
29
30/// Store credit operations for managing customer balances.
31pub struct StoreCredits {
32 db: Arc<dyn Database>,
33}
34
35impl std::fmt::Debug for StoreCredits {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 f.debug_struct("StoreCredits").finish_non_exhaustive()
38 }
39}
40
41impl StoreCredits {
42 pub(crate) fn new(db: Arc<dyn Database>) -> Self {
43 Self { db }
44 }
45
46 /// Whether store credits are supported by the active backend.
47 #[must_use]
48 pub fn is_supported(&self) -> bool {
49 self.db.supports_capability(DatabaseCapability::StoreCredits)
50 }
51
52 fn ensure_supported(&self) -> Result<()> {
53 self.db.ensure_capability(DatabaseCapability::StoreCredits)
54 }
55
56 /// Create a new store credit.
57 ///
58 /// # Example
59 ///
60 /// ```rust,ignore
61 /// use stateset_embedded::{Commerce, CreateStoreCredit, CustomerId, StoreCreditReason};
62 /// use rust_decimal_macros::dec;
63 ///
64 /// let commerce = Commerce::new("./store.db")?;
65 ///
66 /// let credit = commerce.store_credits().create(CreateStoreCredit {
67 /// customer_id: CustomerId::new(),
68 /// initial_balance: dec!(50.00),
69 /// reason: StoreCreditReason::GoodwillCredit,
70 /// ..Default::default()
71 /// })?;
72 /// # Ok::<(), stateset_embedded::CommerceError>(())
73 /// ```
74 pub fn create(&self, input: CreateStoreCredit) -> Result<StoreCredit> {
75 self.ensure_supported()?;
76 self.db.store_credits().create(input)
77 }
78
79 /// Get a store credit by ID.
80 pub fn get(&self, id: StoreCreditId) -> Result<Option<StoreCredit>> {
81 self.ensure_supported()?;
82 self.db.store_credits().get(id)
83 }
84
85 /// List store credits with optional filtering.
86 pub fn list(&self, filter: StoreCreditFilter) -> Result<Vec<StoreCredit>> {
87 self.ensure_supported()?;
88 self.db.store_credits().list(filter)
89 }
90
91 /// Adjust a store credit balance.
92 ///
93 /// Can increase or decrease the balance with a reason for the adjustment.
94 pub fn adjust(&self, id: StoreCreditId, input: AdjustStoreCredit) -> Result<StoreCredit> {
95 self.ensure_supported()?;
96 self.db.store_credits().adjust(id, input)
97 }
98
99 /// Apply store credit to an order (debit).
100 ///
101 /// Reduces the store credit balance by the specified amount.
102 pub fn apply(
103 &self,
104 id: StoreCreditId,
105 amount: Decimal,
106 reference_id: Option<String>,
107 ) -> Result<StoreCreditTransaction> {
108 self.ensure_supported()?;
109 self.db.store_credits().apply(id, amount, reference_id)
110 }
111
112 /// Get transaction history for a store credit.
113 pub fn get_transactions(
114 &self,
115 store_credit_id: StoreCreditId,
116 ) -> Result<Vec<StoreCreditTransaction>> {
117 self.ensure_supported()?;
118 self.db.store_credits().get_transactions(store_credit_id)
119 }
120}