koprogo_api/application/ports/
payment_reminder_repository.rs

1use crate::domain::entities::{PaymentReminder, ReminderLevel, ReminderStatus};
2use async_trait::async_trait;
3use chrono::{DateTime, Utc};
4use uuid::Uuid;
5
6/// Repository trait for payment reminder persistence operations
7#[async_trait]
8pub trait PaymentReminderRepository: Send + Sync {
9    /// Create a new payment reminder
10    async fn create(&self, reminder: &PaymentReminder) -> Result<PaymentReminder, String>;
11
12    /// Find a reminder by ID
13    async fn find_by_id(&self, id: Uuid) -> Result<Option<PaymentReminder>, String>;
14
15    /// Find all reminders for a specific expense
16    async fn find_by_expense(&self, expense_id: Uuid) -> Result<Vec<PaymentReminder>, String>;
17
18    /// Find all reminders for a specific owner
19    async fn find_by_owner(&self, owner_id: Uuid) -> Result<Vec<PaymentReminder>, String>;
20
21    /// Find all reminders for an organization
22    async fn find_by_organization(
23        &self,
24        organization_id: Uuid,
25    ) -> Result<Vec<PaymentReminder>, String>;
26
27    /// Find all reminders with a specific status
28    async fn find_by_status(&self, status: ReminderStatus) -> Result<Vec<PaymentReminder>, String>;
29
30    /// Find all reminders with a specific status for an organization
31    async fn find_by_organization_and_status(
32        &self,
33        organization_id: Uuid,
34        status: ReminderStatus,
35    ) -> Result<Vec<PaymentReminder>, String>;
36
37    /// Find all pending reminders that should be sent (status = Pending)
38    async fn find_pending_reminders(&self) -> Result<Vec<PaymentReminder>, String>;
39
40    /// Find all sent reminders that need escalation (sent > 15 days ago)
41    async fn find_reminders_needing_escalation(
42        &self,
43        cutoff_date: DateTime<Utc>,
44    ) -> Result<Vec<PaymentReminder>, String>;
45
46    /// Find the latest reminder for a specific expense
47    async fn find_latest_by_expense(
48        &self,
49        expense_id: Uuid,
50    ) -> Result<Option<PaymentReminder>, String>;
51
52    /// Find all active (non-paid, non-cancelled) reminders for an owner
53    async fn find_active_by_owner(&self, owner_id: Uuid) -> Result<Vec<PaymentReminder>, String>;
54
55    /// Get statistics: count reminders by status for an organization
56    async fn count_by_status(
57        &self,
58        organization_id: Uuid,
59    ) -> Result<Vec<(ReminderStatus, i64)>, String>;
60
61    /// Get statistics: total amount owed by organization
62    async fn get_total_owed_by_organization(&self, organization_id: Uuid) -> Result<f64, String>;
63
64    /// Get statistics: total penalties by organization
65    async fn get_total_penalties_by_organization(
66        &self,
67        organization_id: Uuid,
68    ) -> Result<f64, String>;
69
70    /// Get overdue expenses without reminders (for automated detection)
71    /// Returns list of (expense_id, owner_id, days_overdue, amount)
72    async fn find_overdue_expenses_without_reminders(
73        &self,
74        organization_id: Uuid,
75        min_days_overdue: i64,
76    ) -> Result<Vec<(Uuid, Uuid, i64, f64)>, String>;
77
78    /// Update a reminder
79    async fn update(&self, reminder: &PaymentReminder) -> Result<PaymentReminder, String>;
80
81    /// Delete a reminder
82    async fn delete(&self, id: Uuid) -> Result<bool, String>;
83
84    /// Get payment recovery dashboard data for an organization
85    /// Returns: (total_owed, total_penalties, reminder_count_by_level)
86    async fn get_dashboard_stats(
87        &self,
88        organization_id: Uuid,
89    ) -> Result<(f64, f64, Vec<(ReminderLevel, i64)>), String>;
90}