koprogo_api/application/dto/
resource_booking_dto.rs1use crate::domain::entities::{BookingStatus, RecurringPattern, ResourceBooking, ResourceType};
2use chrono::{DateTime, Utc};
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6#[derive(Debug, Serialize, Deserialize, Clone)]
8pub struct CreateResourceBookingDto {
9 pub building_id: Uuid,
10 pub resource_type: ResourceType,
11 pub resource_name: String, pub start_time: DateTime<Utc>,
13 pub end_time: DateTime<Utc>,
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub notes: Option<String>,
16 #[serde(default)]
17 pub recurring_pattern: RecurringPattern, #[serde(skip_serializing_if = "Option::is_none")]
19 pub recurrence_end_date: Option<DateTime<Utc>>,
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub max_duration_hours: Option<i64>,
23 #[serde(skip_serializing_if = "Option::is_none")]
25 pub max_advance_days: Option<i64>,
26}
27
28#[derive(Debug, Serialize, Deserialize, Clone)]
32pub struct UpdateResourceBookingDto {
33 #[serde(skip_serializing_if = "Option::is_none")]
34 pub resource_name: Option<String>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 pub notes: Option<String>,
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone)]
41pub struct ResourceBookingResponseDto {
42 pub id: Uuid,
43 pub building_id: Uuid,
44 pub resource_type: ResourceType,
45 pub resource_name: String,
46 pub booked_by: Uuid,
47 pub booked_by_name: String, pub start_time: DateTime<Utc>,
49 pub end_time: DateTime<Utc>,
50 pub status: BookingStatus,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub notes: Option<String>,
53 pub recurring_pattern: RecurringPattern,
54 #[serde(skip_serializing_if = "Option::is_none")]
55 pub recurrence_end_date: Option<DateTime<Utc>>,
56 pub created_at: DateTime<Utc>,
57 pub updated_at: DateTime<Utc>,
58 pub duration_hours: f64,
60 pub is_active: bool,
61 pub is_past: bool,
62 pub is_future: bool,
63 pub is_modifiable: bool,
64 pub is_recurring: bool,
65}
66
67impl ResourceBookingResponseDto {
68 pub fn from_entity(booking: ResourceBooking, booked_by_name: String) -> Self {
70 Self {
71 id: booking.id,
72 building_id: booking.building_id,
73 resource_type: booking.resource_type.clone(),
74 resource_name: booking.resource_name.clone(),
75 booked_by: booking.booked_by,
76 booked_by_name,
77 start_time: booking.start_time,
78 end_time: booking.end_time,
79 status: booking.status.clone(),
80 notes: booking.notes.clone(),
81 recurring_pattern: booking.recurring_pattern.clone(),
82 recurrence_end_date: booking.recurrence_end_date,
83 created_at: booking.created_at,
84 updated_at: booking.updated_at,
85 duration_hours: booking.duration_hours(),
87 is_active: booking.is_active(),
88 is_past: booking.is_past(),
89 is_future: booking.is_future(),
90 is_modifiable: booking.is_modifiable(),
91 is_recurring: booking.is_recurring(),
92 }
93 }
94}
95
96#[derive(Debug, Serialize, Deserialize, Clone)]
98pub struct BookingStatisticsDto {
99 pub building_id: Uuid,
100 pub total_bookings: i64,
101 pub confirmed_bookings: i64,
102 pub pending_bookings: i64,
103 pub completed_bookings: i64,
104 pub cancelled_bookings: i64,
105 pub no_show_bookings: i64,
106 pub active_bookings: i64, pub upcoming_bookings: i64, pub total_hours_booked: f64, pub most_popular_resource: Option<String>, }
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115
116 #[test]
117 fn test_create_dto_serialization() {
118 let dto = CreateResourceBookingDto {
119 building_id: Uuid::new_v4(),
120 resource_type: ResourceType::MeetingRoom,
121 resource_name: "Meeting Room A".to_string(),
122 start_time: Utc::now() + chrono::Duration::hours(2),
123 end_time: Utc::now() + chrono::Duration::hours(4),
124 notes: Some("Team meeting".to_string()),
125 recurring_pattern: RecurringPattern::None,
126 recurrence_end_date: None,
127 max_duration_hours: None,
128 max_advance_days: None,
129 };
130
131 let json = serde_json::to_string(&dto).unwrap();
132 assert!(json.contains("Meeting Room A"));
133 }
134
135 #[test]
136 fn test_response_dto_from_entity() {
137 let building_id = Uuid::new_v4();
138 let booked_by = Uuid::new_v4();
139 let start_time = Utc::now() + chrono::Duration::hours(2);
140 let end_time = start_time + chrono::Duration::hours(2);
141
142 let booking = ResourceBooking::new(
143 building_id,
144 ResourceType::MeetingRoom,
145 "Meeting Room A".to_string(),
146 booked_by,
147 start_time,
148 end_time,
149 Some("Team meeting".to_string()),
150 RecurringPattern::None,
151 None,
152 None,
153 None,
154 )
155 .unwrap();
156
157 let dto = ResourceBookingResponseDto::from_entity(booking, "John Doe".to_string());
158
159 assert_eq!(dto.resource_name, "Meeting Room A");
160 assert_eq!(dto.booked_by_name, "John Doe");
161 assert_eq!(dto.duration_hours, 2.0);
162 assert!(dto.is_future);
163 assert!(!dto.is_past);
164 assert!(dto.is_modifiable);
165 }
166}