koprogo_api/application/dto/
payment_reminder_dto.rs1use crate::domain::entities::{DeliveryMethod, PaymentReminder, ReminderLevel, ReminderStatus};
2use serde::{Deserialize, Serialize};
3use validator::Validate;
4
5#[derive(Debug, Deserialize, Validate, Clone)]
7pub struct CreatePaymentReminderDto {
8 pub organization_id: String,
9 pub expense_id: String,
10 pub owner_id: String,
11 pub level: ReminderLevel,
12
13 #[validate(range(min = 0.01))]
14 pub amount_owed: f64,
15
16 pub due_date: String, #[validate(range(min = 0))]
19 pub days_overdue: i64,
20}
21
22#[derive(Debug, Serialize, Clone)]
24pub struct PaymentReminderResponseDto {
25 pub id: String,
26 pub organization_id: String,
27 pub expense_id: String,
28 pub owner_id: String,
29 pub owner_name: Option<String>, pub owner_email: Option<String>, pub level: ReminderLevel,
32 pub status: ReminderStatus,
33 pub amount_owed: f64,
34 pub penalty_amount: f64,
35 pub total_amount: f64,
36 pub due_date: String,
37 pub days_overdue: i64,
38 pub delivery_method: DeliveryMethod,
39 pub sent_date: Option<String>,
40 pub opened_date: Option<String>,
41 pub pdf_path: Option<String>,
42 pub tracking_number: Option<String>,
43 pub notes: Option<String>,
44 pub created_at: String,
45 pub updated_at: String,
46}
47
48impl From<PaymentReminder> for PaymentReminderResponseDto {
49 fn from(reminder: PaymentReminder) -> Self {
50 Self {
51 id: reminder.id.to_string(),
52 organization_id: reminder.organization_id.to_string(),
53 expense_id: reminder.expense_id.to_string(),
54 owner_id: reminder.owner_id.to_string(),
55 owner_name: None, owner_email: None, level: reminder.level,
58 status: reminder.status,
59 amount_owed: reminder.amount_owed,
60 penalty_amount: reminder.penalty_amount,
61 total_amount: reminder.total_amount,
62 due_date: reminder.due_date.to_rfc3339(),
63 days_overdue: reminder.days_overdue,
64 delivery_method: reminder.delivery_method,
65 sent_date: reminder.sent_date.map(|d| d.to_rfc3339()),
66 opened_date: reminder.opened_date.map(|d| d.to_rfc3339()),
67 pdf_path: reminder.pdf_path,
68 tracking_number: reminder.tracking_number,
69 notes: reminder.notes,
70 created_at: reminder.created_at.to_rfc3339(),
71 updated_at: reminder.updated_at.to_rfc3339(),
72 }
73 }
74}
75
76#[derive(Debug, Deserialize, Validate, Clone)]
78pub struct MarkReminderSentDto {
79 pub pdf_path: Option<String>,
80}
81
82#[derive(Debug, Deserialize, Clone)]
84pub struct EscalateReminderDto {
85 pub reason: Option<String>,
86}
87
88#[derive(Debug, Deserialize, Validate, Clone)]
90pub struct CancelReminderDto {
91 #[validate(length(min = 1))]
92 pub reason: String,
93}
94
95#[derive(Debug, Deserialize, Validate, Clone)]
97pub struct AddTrackingNumberDto {
98 #[validate(length(min = 1))]
99 pub tracking_number: String,
100}
101
102#[derive(Debug, Serialize, Clone)]
104pub struct PaymentRecoveryStatsDto {
105 pub total_owed: f64,
106 pub total_penalties: f64,
107 pub reminder_counts: Vec<ReminderLevelCountDto>,
108 pub status_counts: Vec<ReminderStatusCountDto>,
109}
110
111#[derive(Debug, Serialize, Clone)]
112pub struct ReminderLevelCountDto {
113 pub level: ReminderLevel,
114 pub count: i64,
115}
116
117#[derive(Debug, Serialize, Clone)]
118pub struct ReminderStatusCountDto {
119 pub status: ReminderStatus,
120 pub count: i64,
121}
122
123#[derive(Debug, Serialize, Clone)]
125pub struct OverdueExpenseDto {
126 pub expense_id: String,
127 pub owner_id: String,
128 pub days_overdue: i64,
129 pub amount: f64,
130 pub recommended_level: ReminderLevel,
131}
132
133impl OverdueExpenseDto {
134 pub fn new(expense_id: String, owner_id: String, days_overdue: i64, amount: f64) -> Self {
136 let recommended_level = if days_overdue >= 60 {
137 ReminderLevel::FormalNotice
138 } else if days_overdue >= 30 {
139 ReminderLevel::SecondReminder
140 } else {
141 ReminderLevel::FirstReminder
142 };
143
144 Self {
145 expense_id,
146 owner_id,
147 days_overdue,
148 amount,
149 recommended_level,
150 }
151 }
152}
153
154#[derive(Debug, Deserialize, Validate, Clone)]
156pub struct BulkCreateRemindersDto {
157 #[serde(default)]
158 pub organization_id: String,
159
160 #[validate(range(min = 15))]
161 pub min_days_overdue: i64,
162}
163
164#[derive(Debug, Serialize, Clone)]
166pub struct BulkCreateRemindersResponseDto {
167 pub created_count: i32,
168 pub skipped_count: i32,
169 pub errors: Vec<String>,
170 pub created_reminders: Vec<PaymentReminderResponseDto>,
171}