koprogo_api/application/use_cases/
payment_method_use_cases.rs

1use crate::application::dto::{
2    CreatePaymentMethodRequest, PaymentMethodResponse, UpdatePaymentMethodRequest,
3};
4use crate::application::ports::PaymentMethodRepository;
5use crate::domain::entities::payment_method::{PaymentMethod, PaymentMethodType};
6use std::sync::Arc;
7use uuid::Uuid;
8
9pub struct PaymentMethodUseCases {
10    payment_method_repository: Arc<dyn PaymentMethodRepository>,
11}
12
13impl PaymentMethodUseCases {
14    pub fn new(payment_method_repository: Arc<dyn PaymentMethodRepository>) -> Self {
15        Self {
16            payment_method_repository,
17        }
18    }
19
20    /// Create a new payment method
21    ///
22    /// If is_default is true, automatically unsets other default payment methods for the owner.
23    pub async fn create_payment_method(
24        &self,
25        organization_id: Uuid,
26        request: CreatePaymentMethodRequest,
27    ) -> Result<PaymentMethodResponse, String> {
28        let payment_method = PaymentMethod::new(
29            organization_id,
30            request.owner_id,
31            request.method_type,
32            request.stripe_payment_method_id,
33            request.stripe_customer_id,
34            request.display_label,
35            request.is_default,
36        )?;
37
38        // Set metadata if provided
39        let mut payment_method = payment_method;
40        if let Some(metadata) = request.metadata {
41            payment_method.set_metadata(metadata);
42        }
43
44        // Set expiry if provided (cards only)
45        if let Some(expires_at) = request.expires_at {
46            payment_method.set_expiry(expires_at)?;
47        }
48
49        let created = self
50            .payment_method_repository
51            .create(&payment_method)
52            .await?;
53
54        // If set as default, ensure it's the only default for this owner
55        if created.is_default {
56            let _ = self
57                .payment_method_repository
58                .set_as_default(created.id, created.owner_id)
59                .await?;
60        }
61
62        Ok(PaymentMethodResponse::from(created))
63    }
64
65    /// Get payment method by ID
66    pub async fn get_payment_method(
67        &self,
68        id: Uuid,
69    ) -> Result<Option<PaymentMethodResponse>, String> {
70        match self.payment_method_repository.find_by_id(id).await? {
71            Some(method) => Ok(Some(PaymentMethodResponse::from(method))),
72            None => Ok(None),
73        }
74    }
75
76    /// Get payment method by Stripe payment method ID
77    pub async fn get_payment_method_by_stripe_id(
78        &self,
79        stripe_payment_method_id: &str,
80    ) -> Result<Option<PaymentMethodResponse>, String> {
81        match self
82            .payment_method_repository
83            .find_by_stripe_payment_method_id(stripe_payment_method_id)
84            .await?
85        {
86            Some(method) => Ok(Some(PaymentMethodResponse::from(method))),
87            None => Ok(None),
88        }
89    }
90
91    /// List payment methods for an owner
92    pub async fn list_owner_payment_methods(
93        &self,
94        owner_id: Uuid,
95    ) -> Result<Vec<PaymentMethodResponse>, String> {
96        let methods = self
97            .payment_method_repository
98            .find_by_owner(owner_id)
99            .await?;
100        Ok(methods
101            .into_iter()
102            .map(PaymentMethodResponse::from)
103            .collect())
104    }
105
106    /// List active payment methods for an owner
107    pub async fn list_active_owner_payment_methods(
108        &self,
109        owner_id: Uuid,
110    ) -> Result<Vec<PaymentMethodResponse>, String> {
111        let methods = self
112            .payment_method_repository
113            .find_active_by_owner(owner_id)
114            .await?;
115        Ok(methods
116            .into_iter()
117            .map(PaymentMethodResponse::from)
118            .collect())
119    }
120
121    /// Get default payment method for an owner
122    pub async fn get_default_payment_method(
123        &self,
124        owner_id: Uuid,
125    ) -> Result<Option<PaymentMethodResponse>, String> {
126        match self
127            .payment_method_repository
128            .find_default_by_owner(owner_id)
129            .await?
130        {
131            Some(method) => Ok(Some(PaymentMethodResponse::from(method))),
132            None => Ok(None),
133        }
134    }
135
136    /// List payment methods for an organization
137    pub async fn list_organization_payment_methods(
138        &self,
139        organization_id: Uuid,
140    ) -> Result<Vec<PaymentMethodResponse>, String> {
141        let methods = self
142            .payment_method_repository
143            .find_by_organization(organization_id)
144            .await?;
145        Ok(methods
146            .into_iter()
147            .map(PaymentMethodResponse::from)
148            .collect())
149    }
150
151    /// List payment methods by owner and type
152    pub async fn list_payment_methods_by_type(
153        &self,
154        owner_id: Uuid,
155        method_type: PaymentMethodType,
156    ) -> Result<Vec<PaymentMethodResponse>, String> {
157        let methods = self
158            .payment_method_repository
159            .find_by_owner_and_type(owner_id, method_type)
160            .await?;
161        Ok(methods
162            .into_iter()
163            .map(PaymentMethodResponse::from)
164            .collect())
165    }
166
167    /// Update payment method
168    pub async fn update_payment_method(
169        &self,
170        id: Uuid,
171        request: UpdatePaymentMethodRequest,
172    ) -> Result<PaymentMethodResponse, String> {
173        let mut payment_method = self
174            .payment_method_repository
175            .find_by_id(id)
176            .await?
177            .ok_or_else(|| "Payment method not found".to_string())?;
178
179        // Update display label if provided
180        if let Some(display_label) = request.display_label {
181            if display_label.trim().is_empty() {
182                return Err("Display label cannot be empty".to_string());
183            }
184            payment_method.display_label = display_label;
185            payment_method.updated_at = chrono::Utc::now();
186        }
187
188        // Update metadata if provided
189        if let Some(metadata) = request.metadata {
190            payment_method.set_metadata(metadata);
191        }
192
193        // Update default status if provided
194        if let Some(is_default) = request.is_default {
195            if is_default && !payment_method.is_default {
196                // Set as default (will unset other defaults)
197                return Ok(PaymentMethodResponse::from(
198                    self.payment_method_repository
199                        .set_as_default(id, payment_method.owner_id)
200                        .await?,
201                ));
202            } else if !is_default && payment_method.is_default {
203                // Unset default
204                payment_method.unset_default();
205            }
206        }
207
208        let updated = self
209            .payment_method_repository
210            .update(&payment_method)
211            .await?;
212        Ok(PaymentMethodResponse::from(updated))
213    }
214
215    /// Set payment method as default
216    pub async fn set_as_default(
217        &self,
218        id: Uuid,
219        owner_id: Uuid,
220    ) -> Result<PaymentMethodResponse, String> {
221        let payment_method = self
222            .payment_method_repository
223            .set_as_default(id, owner_id)
224            .await?;
225        Ok(PaymentMethodResponse::from(payment_method))
226    }
227
228    /// Deactivate payment method
229    pub async fn deactivate_payment_method(
230        &self,
231        id: Uuid,
232    ) -> Result<PaymentMethodResponse, String> {
233        let mut payment_method = self
234            .payment_method_repository
235            .find_by_id(id)
236            .await?
237            .ok_or_else(|| "Payment method not found".to_string())?;
238
239        payment_method.deactivate()?;
240
241        let updated = self
242            .payment_method_repository
243            .update(&payment_method)
244            .await?;
245        Ok(PaymentMethodResponse::from(updated))
246    }
247
248    /// Reactivate payment method
249    pub async fn reactivate_payment_method(
250        &self,
251        id: Uuid,
252    ) -> Result<PaymentMethodResponse, String> {
253        let mut payment_method = self
254            .payment_method_repository
255            .find_by_id(id)
256            .await?
257            .ok_or_else(|| "Payment method not found".to_string())?;
258
259        payment_method.reactivate()?;
260
261        let updated = self
262            .payment_method_repository
263            .update(&payment_method)
264            .await?;
265        Ok(PaymentMethodResponse::from(updated))
266    }
267
268    /// Delete payment method
269    pub async fn delete_payment_method(&self, id: Uuid) -> Result<bool, String> {
270        self.payment_method_repository.delete(id).await
271    }
272
273    /// Count active payment methods for owner
274    pub async fn count_active_payment_methods(&self, owner_id: Uuid) -> Result<i64, String> {
275        self.payment_method_repository
276            .count_active_by_owner(owner_id)
277            .await
278    }
279
280    /// Check if owner has any active payment methods
281    pub async fn has_active_payment_methods(&self, owner_id: Uuid) -> Result<bool, String> {
282        self.payment_method_repository
283            .has_active_payment_methods(owner_id)
284            .await
285    }
286}