koprogo_api/application/dto/
convocation_recipient_dto.rs1use crate::domain::entities::{AttendanceStatus, ConvocationRecipient};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6#[derive(Debug, Serialize, Deserialize, Clone)]
7pub struct ConvocationRecipientResponse {
8 pub id: Uuid,
9 pub convocation_id: Uuid,
10 pub owner_id: Uuid,
11 pub email: String,
12
13 pub email_sent_at: Option<DateTime<Utc>>,
15 pub email_opened_at: Option<DateTime<Utc>>,
16 pub email_failed: bool,
17 pub email_failure_reason: Option<String>,
18
19 pub reminder_sent_at: Option<DateTime<Utc>>,
21 pub reminder_opened_at: Option<DateTime<Utc>>,
22
23 pub attendance_status: AttendanceStatus,
25 pub attendance_updated_at: Option<DateTime<Utc>>,
26
27 pub proxy_owner_id: Option<Uuid>,
29
30 pub has_opened_email: bool,
32 pub has_opened_reminder: bool,
33 pub needs_reminder: bool,
34 pub has_confirmed_attendance: bool,
35
36 pub created_at: DateTime<Utc>,
38 pub updated_at: DateTime<Utc>,
39}
40
41impl From<ConvocationRecipient> for ConvocationRecipientResponse {
42 fn from(recipient: ConvocationRecipient) -> Self {
43 let has_opened_email = recipient.has_opened_email();
44 let has_opened_reminder = recipient.has_opened_reminder();
45 let needs_reminder = recipient.needs_reminder();
46 let has_confirmed_attendance = recipient.has_confirmed_attendance();
47
48 Self {
49 id: recipient.id,
50 convocation_id: recipient.convocation_id,
51 owner_id: recipient.owner_id,
52 email: recipient.email,
53 email_sent_at: recipient.email_sent_at,
54 email_opened_at: recipient.email_opened_at,
55 email_failed: recipient.email_failed,
56 email_failure_reason: recipient.email_failure_reason,
57 reminder_sent_at: recipient.reminder_sent_at,
58 reminder_opened_at: recipient.reminder_opened_at,
59 attendance_status: recipient.attendance_status,
60 attendance_updated_at: recipient.attendance_updated_at,
61 proxy_owner_id: recipient.proxy_owner_id,
62 has_opened_email,
63 has_opened_reminder,
64 needs_reminder,
65 has_confirmed_attendance,
66 created_at: recipient.created_at,
67 updated_at: recipient.updated_at,
68 }
69 }
70}
71
72#[derive(Debug, Deserialize)]
73pub struct UpdateAttendanceRequest {
74 pub attendance_status: AttendanceStatus,
75}
76
77#[derive(Debug, Deserialize)]
78pub struct SetProxyRequest {
79 pub proxy_owner_id: Uuid,
80}
81
82#[derive(Debug, Serialize)]
83pub struct RecipientSummaryResponse {
84 pub id: Uuid,
85 pub owner_id: Uuid,
86 pub email: String,
87 pub email_opened: bool,
88 pub attendance_status: AttendanceStatus,
89}
90
91impl From<ConvocationRecipient> for RecipientSummaryResponse {
92 fn from(recipient: ConvocationRecipient) -> Self {
93 Self {
94 id: recipient.id,
95 owner_id: recipient.owner_id,
96 email: recipient.email.clone(),
97 email_opened: recipient.has_opened_email(),
98 attendance_status: recipient.attendance_status.clone(),
99 }
100 }
101}
102
103#[derive(Debug, Serialize, Deserialize, Clone)]
104pub struct RecipientTrackingSummaryResponse {
105 pub total_count: i64,
106 pub opened_count: i64,
107 pub will_attend_count: i64,
108 pub will_not_attend_count: i64,
109 pub attended_count: i64,
110 pub did_not_attend_count: i64,
111 pub pending_count: i64,
112 pub failed_email_count: i64,
113
114 pub opening_rate: f64,
116 pub attendance_rate: f64,
117}
118
119impl RecipientTrackingSummaryResponse {
120 pub fn new(
121 total_count: i64,
122 opened_count: i64,
123 will_attend_count: i64,
124 will_not_attend_count: i64,
125 attended_count: i64,
126 did_not_attend_count: i64,
127 pending_count: i64,
128 failed_email_count: i64,
129 ) -> Self {
130 let opening_rate = if total_count > 0 {
131 (opened_count as f64 / total_count as f64) * 100.0
132 } else {
133 0.0
134 };
135
136 let attendance_rate = if total_count > 0 {
137 (will_attend_count as f64 / total_count as f64) * 100.0
138 } else {
139 0.0
140 };
141
142 Self {
143 total_count,
144 opened_count,
145 will_attend_count,
146 will_not_attend_count,
147 attended_count,
148 did_not_attend_count,
149 pending_count,
150 failed_email_count,
151 opening_rate,
152 attendance_rate,
153 }
154 }
155}