Skip to main content

stateset_embedded/
loyalty.rs

1//! Loyalty program operations for points, accounts, and rewards
2//!
3//! Manages loyalty programs, customer enrollment, point adjustments,
4//! and a reward catalog for point redemption.
5//!
6//! # Example
7//!
8//! ```rust,ignore
9//! use stateset_embedded::{Commerce, CreateLoyaltyProgram};
10//!
11//! let commerce = Commerce::new("./store.db")?;
12//!
13//! let program = commerce.loyalty().create_program(CreateLoyaltyProgram {
14//!     name: "Gold Rewards".into(),
15//!     points_per_dollar: Some(10),
16//!     ..Default::default()
17//! })?;
18//!
19//! println!("Program created: {}", program.name);
20//! # Ok::<(), stateset_embedded::CommerceError>(())
21//! ```
22
23use stateset_core::{
24    AdjustPoints, CreateLoyaltyProgram, CreateReward, CustomerId, EnrollCustomer, LoyaltyAccount,
25    LoyaltyAccountFilter, LoyaltyAccountId, LoyaltyProgram, LoyaltyProgramId, LoyaltyTransaction,
26    Result, Reward, RewardFilter, RewardId,
27};
28use stateset_db::{Database, DatabaseCapability};
29use std::sync::Arc;
30
31/// Loyalty program operations for points, accounts, and rewards.
32pub struct Loyalty {
33    db: Arc<dyn Database>,
34}
35
36impl std::fmt::Debug for Loyalty {
37    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38        f.debug_struct("Loyalty").finish_non_exhaustive()
39    }
40}
41
42impl Loyalty {
43    pub(crate) fn new(db: Arc<dyn Database>) -> Self {
44        Self { db }
45    }
46
47    /// Whether loyalty programs and rewards are supported by the active backend.
48    #[must_use]
49    pub fn is_supported(&self) -> bool {
50        self.db.supports_capability(DatabaseCapability::LoyaltyPrograms)
51            && self.db.supports_capability(DatabaseCapability::Rewards)
52    }
53
54    fn ensure_programs_supported(&self) -> Result<()> {
55        self.db.ensure_capability(DatabaseCapability::LoyaltyPrograms)
56    }
57
58    fn ensure_rewards_supported(&self) -> Result<()> {
59        self.db.ensure_capability(DatabaseCapability::Rewards)
60    }
61
62    // ========================================================================
63    // Program Operations
64    // ========================================================================
65
66    /// Create a new loyalty program.
67    ///
68    /// # Example
69    ///
70    /// ```rust,ignore
71    /// use stateset_embedded::{Commerce, CreateLoyaltyProgram};
72    ///
73    /// let commerce = Commerce::new("./store.db")?;
74    ///
75    /// let program = commerce.loyalty().create_program(CreateLoyaltyProgram {
76    ///     name: "Platinum Plus".into(),
77    ///     points_per_dollar: Some(15),
78    ///     ..Default::default()
79    /// })?;
80    /// # Ok::<(), stateset_embedded::CommerceError>(())
81    /// ```
82    pub fn create_program(&self, input: CreateLoyaltyProgram) -> Result<LoyaltyProgram> {
83        self.ensure_programs_supported()?;
84        self.db.loyalty_programs().create(input)
85    }
86
87    /// Get a loyalty program by ID.
88    pub fn get_program(&self, id: LoyaltyProgramId) -> Result<Option<LoyaltyProgram>> {
89        self.ensure_programs_supported()?;
90        self.db.loyalty_programs().get(id)
91    }
92
93    /// List all loyalty programs.
94    pub fn list_programs(&self) -> Result<Vec<LoyaltyProgram>> {
95        self.ensure_programs_supported()?;
96        self.db.loyalty_programs().list()
97    }
98
99    // ========================================================================
100    // Account Operations
101    // ========================================================================
102
103    /// Enroll a customer in a loyalty program.
104    pub fn enroll(&self, input: EnrollCustomer) -> Result<LoyaltyAccount> {
105        self.ensure_programs_supported()?;
106        self.db.loyalty_programs().enroll(input)
107    }
108
109    /// Get a loyalty account by ID.
110    pub fn get_account(&self, id: LoyaltyAccountId) -> Result<Option<LoyaltyAccount>> {
111        self.ensure_programs_supported()?;
112        self.db.loyalty_programs().get_account(id)
113    }
114
115    /// Get a loyalty account by customer and program.
116    pub fn get_account_by_customer(
117        &self,
118        customer_id: CustomerId,
119        program_id: LoyaltyProgramId,
120    ) -> Result<Option<LoyaltyAccount>> {
121        self.ensure_programs_supported()?;
122        self.db.loyalty_programs().get_account_by_customer(customer_id, program_id)
123    }
124
125    /// List loyalty accounts with optional filtering.
126    pub fn list_accounts(&self, filter: LoyaltyAccountFilter) -> Result<Vec<LoyaltyAccount>> {
127        self.ensure_programs_supported()?;
128        self.db.loyalty_programs().list_accounts(filter)
129    }
130
131    // ========================================================================
132    // Points Operations
133    // ========================================================================
134
135    /// Adjust points on an account (earn, redeem, expire, etc.).
136    pub fn adjust_points(&self, input: AdjustPoints) -> Result<LoyaltyTransaction> {
137        self.ensure_programs_supported()?;
138        self.db.loyalty_programs().adjust_points(input)
139    }
140
141    /// Get transaction history for an account.
142    pub fn get_transactions(
143        &self,
144        account_id: LoyaltyAccountId,
145        limit: Option<u32>,
146    ) -> Result<Vec<LoyaltyTransaction>> {
147        self.ensure_programs_supported()?;
148        self.db.loyalty_programs().get_transactions(account_id, limit)
149    }
150
151    // ========================================================================
152    // Reward Catalog Operations
153    // ========================================================================
154
155    /// Create a new reward in the catalog.
156    pub fn create_reward(&self, input: CreateReward) -> Result<Reward> {
157        self.ensure_rewards_supported()?;
158        self.db.rewards().create(input)
159    }
160
161    /// Get a reward by ID.
162    pub fn get_reward(&self, id: RewardId) -> Result<Option<Reward>> {
163        self.ensure_rewards_supported()?;
164        self.db.rewards().get(id)
165    }
166
167    /// List rewards with optional filtering.
168    pub fn list_rewards(&self, filter: RewardFilter) -> Result<Vec<Reward>> {
169        self.ensure_rewards_supported()?;
170        self.db.rewards().list(filter)
171    }
172
173    /// Delete a reward from the catalog.
174    pub fn delete_reward(&self, id: RewardId) -> Result<()> {
175        self.ensure_rewards_supported()?;
176        self.db.rewards().delete(id)
177    }
178}