konduto/types/delivery/
details.rs1use crate::types::delivery::delivery_company::DeliveryCompany;
2use crate::types::delivery::delivery_method::DeliveryMethod;
3use crate::types::shared::date_iso_8601::DateIso8601;
4use crate::types::validation_errors::ValidationError;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
9pub struct Delivery {
10 #[serde(skip_serializing_if = "Option::is_none")]
12 pub delivery_company: Option<DeliveryCompany>,
13
14 #[serde(skip_serializing_if = "Option::is_none")]
16 pub delivery_method: Option<DeliveryMethod>,
17
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub estimated_shipping_date: Option<DateIso8601>,
21
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub estimated_delivery_date: Option<DateIso8601>,
25}
26
27impl Delivery {
28 pub fn builder() -> DeliveryBuilder {
30 DeliveryBuilder::default()
31 }
32}
33
34#[derive(Default, Debug)]
36pub struct DeliveryBuilder {
37 delivery: Delivery,
38}
39
40impl DeliveryBuilder {
41 pub fn delivery_company(mut self, company: DeliveryCompany) -> Self {
43 self.delivery.delivery_company = Some(company);
44 self
45 }
46
47 pub fn delivery_company_str(
49 mut self,
50 company: impl Into<String>,
51 ) -> Result<Self, ValidationError> {
52 self.delivery.delivery_company = Some(DeliveryCompany::try_new(company)?);
53 Ok(self)
54 }
55
56 pub fn delivery_method(mut self, method: DeliveryMethod) -> Self {
58 self.delivery.delivery_method = Some(method);
59 self
60 }
61
62 pub fn delivery_method_str(
64 mut self,
65 method: impl Into<String>,
66 ) -> Result<Self, ValidationError> {
67 self.delivery.delivery_method = Some(DeliveryMethod::try_new(method)?);
68 Ok(self)
69 }
70
71 pub fn estimated_shipping_date(mut self, date: DateIso8601) -> Self {
73 self.delivery.estimated_shipping_date = Some(date);
74 self
75 }
76
77 pub fn estimated_shipping_date_str(
79 mut self,
80 date: impl Into<String>,
81 ) -> Result<Self, ValidationError> {
82 self.delivery.estimated_shipping_date = Some(DateIso8601::new(date)?);
83 Ok(self)
84 }
85
86 pub fn estimated_delivery_date(mut self, date: DateIso8601) -> Self {
88 self.delivery.estimated_delivery_date = Some(date);
89 self
90 }
91
92 pub fn estimated_delivery_date_str(
94 mut self,
95 date: impl Into<String>,
96 ) -> Result<Self, ValidationError> {
97 self.delivery.estimated_delivery_date = Some(DateIso8601::new(date)?);
98 Ok(self)
99 }
100
101 pub fn build(self) -> Delivery {
103 self.delivery
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn test_delivery_builder_all_fields() {
113 let delivery = Delivery::builder()
114 .delivery_company_str("Correios")
115 .unwrap()
116 .delivery_method_str("SEDEX")
117 .unwrap()
118 .estimated_shipping_date_str("2025-12-01")
119 .unwrap()
120 .estimated_delivery_date_str("2025-12-05")
121 .unwrap()
122 .build();
123
124 assert!(delivery.delivery_company.is_some());
125 assert_eq!(delivery.delivery_company.unwrap().as_str(), "Correios");
126 assert!(delivery.delivery_method.is_some());
127 assert!(delivery.estimated_shipping_date.is_some());
128 assert!(delivery.estimated_delivery_date.is_some());
129 }
130
131 #[test]
132 fn test_delivery_builder_with_typed_values() {
133 let company = DeliveryCompany::try_new("FedEx").unwrap();
134 let method = DeliveryMethod::try_new("Express").unwrap();
135 let ship_date = DateIso8601::new("2025-11-20").unwrap();
136 let delivery_date = DateIso8601::new("2025-11-22").unwrap();
137
138 let delivery = Delivery::builder()
139 .delivery_company(company)
140 .delivery_method(method)
141 .estimated_shipping_date(ship_date)
142 .estimated_delivery_date(delivery_date)
143 .build();
144
145 assert!(delivery.delivery_company.is_some());
146 assert_eq!(
147 delivery.delivery_company.as_ref().unwrap().as_str(),
148 "FedEx"
149 );
150 assert_eq!(
151 delivery.delivery_method.as_ref().unwrap().as_str(),
152 "Express"
153 );
154 }
155
156 #[test]
157 fn test_delivery_builder_partial_fields() {
158 let delivery = Delivery::builder()
159 .delivery_company_str("DHL")
160 .unwrap()
161 .estimated_delivery_date_str("2025-12-10")
162 .unwrap()
163 .build();
164
165 assert!(delivery.delivery_company.is_some());
166 assert!(delivery.delivery_method.is_none());
167 assert!(delivery.estimated_shipping_date.is_none());
168 assert!(delivery.estimated_delivery_date.is_some());
169 }
170
171 #[test]
172 fn test_delivery_default() {
173 let delivery = Delivery::default();
174
175 assert!(delivery.delivery_company.is_none());
176 assert!(delivery.delivery_method.is_none());
177 assert!(delivery.estimated_shipping_date.is_none());
178 assert!(delivery.estimated_delivery_date.is_none());
179 }
180
181 #[test]
182 fn test_delivery_empty_builder() {
183 let delivery = Delivery::builder().build();
184
185 assert!(delivery.delivery_company.is_none());
186 assert!(delivery.delivery_method.is_none());
187 assert!(delivery.estimated_shipping_date.is_none());
188 assert!(delivery.estimated_delivery_date.is_none());
189 }
190
191 #[test]
192 fn test_delivery_company_validation() {
193 let result = Delivery::builder().delivery_company_str("").unwrap_err();
194
195 assert!(matches!(result, ValidationError::Generic(_) | ValidationError::EmptyField(_)));
197 }
198
199 #[test]
200 fn test_delivery_company_too_long() {
201 let long_company = "a".repeat(101);
202 let result = Delivery::builder()
203 .delivery_company_str(long_company)
204 .unwrap_err();
205
206 assert!(matches!(result, ValidationError::Generic(_) | ValidationError::TooLong { .. }));
208 }
209
210 #[test]
211 fn test_delivery_method_validation() {
212 let result = Delivery::builder().delivery_method_str("").unwrap_err();
213
214 assert!(matches!(result, ValidationError::Generic(_) | ValidationError::EmptyField(_)));
216 }
217
218 #[test]
219 fn test_delivery_method_too_long() {
220 let long_method = "a".repeat(101);
221 let result = Delivery::builder()
222 .delivery_method_str(long_method)
223 .unwrap_err();
224
225 assert!(matches!(result, ValidationError::Generic(_) | ValidationError::TooLong { .. }));
227 }
228
229 #[test]
230 fn test_invalid_shipping_date_format() {
231 let result = Delivery::builder()
232 .estimated_shipping_date_str("2025/12/01")
233 .unwrap_err();
234
235 assert!(matches!(result, ValidationError::InvalidFormat { .. }));
236 }
237
238 #[test]
239 fn test_invalid_delivery_date_format() {
240 let result = Delivery::builder()
241 .estimated_delivery_date_str("01-12-2025")
242 .unwrap_err();
243
244 assert!(matches!(result, ValidationError::InvalidFormat { .. }));
245 }
246
247 #[test]
248 fn test_invalid_date_values() {
249 let result = Delivery::builder()
250 .estimated_shipping_date_str("2025-13-01")
251 .unwrap_err();
252
253 assert!(matches!(result, ValidationError::InvalidFormat { .. }));
254 }
255
256 #[test]
257 fn test_delivery_serialization() {
258 let delivery = Delivery::builder()
259 .delivery_company_str("Correios")
260 .unwrap()
261 .delivery_method_str("PAC")
262 .unwrap()
263 .estimated_shipping_date_str("2025-11-25")
264 .unwrap()
265 .estimated_delivery_date_str("2025-11-30")
266 .unwrap()
267 .build();
268
269 let json = serde_json::to_string(&delivery).unwrap();
270
271 assert!(json.contains("Correios"));
272 assert!(json.contains("PAC"));
273 assert!(json.contains("2025-11-25"));
274 assert!(json.contains("2025-11-30"));
275 }
276
277 #[test]
278 fn test_delivery_deserialization() {
279 let json = r#"{
280 "delivery_company": "UPS",
281 "delivery_method": "Ground",
282 "estimated_shipping_date": "2025-12-01",
283 "estimated_delivery_date": "2025-12-05"
284 }"#;
285
286 let delivery: Delivery = serde_json::from_str(json).unwrap();
287
288 assert_eq!(delivery.delivery_company.unwrap().as_str(), "UPS");
289 assert_eq!(delivery.delivery_method.unwrap().as_str(), "Ground");
290 assert_eq!(
291 delivery.estimated_shipping_date.unwrap().as_str(),
292 "2025-12-01"
293 );
294 assert_eq!(
295 delivery.estimated_delivery_date.unwrap().as_str(),
296 "2025-12-05"
297 );
298 }
299
300 #[test]
301 fn test_delivery_deserialization_partial() {
302 let json = r#"{
303 "delivery_company": "DHL"
304 }"#;
305
306 let delivery: Delivery = serde_json::from_str(json).unwrap();
307
308 assert!(delivery.delivery_company.is_some());
309 assert!(delivery.delivery_method.is_none());
310 assert!(delivery.estimated_shipping_date.is_none());
311 assert!(delivery.estimated_delivery_date.is_none());
312 }
313
314 #[test]
315 fn test_delivery_serialization_skip_none() {
316 let delivery = Delivery::builder()
317 .delivery_company_str("FedEx")
318 .unwrap()
319 .build();
320
321 let json = serde_json::to_string(&delivery).unwrap();
322
323 assert!(json.contains("delivery_company"));
324 assert!(!json.contains("delivery_method"));
325 assert!(!json.contains("estimated_shipping_date"));
326 assert!(!json.contains("estimated_delivery_date"));
327 }
328
329 #[test]
330 fn test_delivery_roundtrip() {
331 let original = Delivery::builder()
332 .delivery_company_str("Correios")
333 .unwrap()
334 .delivery_method_str("SEDEX")
335 .unwrap()
336 .estimated_shipping_date_str("2025-11-20")
337 .unwrap()
338 .estimated_delivery_date_str("2025-11-25")
339 .unwrap()
340 .build();
341
342 let json = serde_json::to_string(&original).unwrap();
343 let deserialized: Delivery = serde_json::from_str(&json).unwrap();
344
345 assert_eq!(original, deserialized);
346 }
347
348 #[test]
349 fn test_delivery_clone() {
350 let delivery1 = Delivery::builder()
351 .delivery_company_str("DHL")
352 .unwrap()
353 .build();
354
355 let delivery2 = delivery1.clone();
356
357 assert_eq!(delivery1, delivery2);
358 }
359
360 #[test]
361 fn test_delivery_equality() {
362 let delivery1 = Delivery::builder()
363 .delivery_company_str("FedEx")
364 .unwrap()
365 .delivery_method_str("Express")
366 .unwrap()
367 .build();
368
369 let delivery2 = Delivery::builder()
370 .delivery_company_str("FedEx")
371 .unwrap()
372 .delivery_method_str("Express")
373 .unwrap()
374 .build();
375
376 assert_eq!(delivery1, delivery2);
377 }
378
379 #[test]
380 fn test_delivery_inequality() {
381 let delivery1 = Delivery::builder()
382 .delivery_company_str("FedEx")
383 .unwrap()
384 .build();
385
386 let delivery2 = Delivery::builder()
387 .delivery_company_str("UPS")
388 .unwrap()
389 .build();
390
391 assert_ne!(delivery1, delivery2);
392 }
393
394 #[test]
395 fn test_delivery_debug() {
396 let delivery = Delivery::builder()
397 .delivery_company_str("Correios")
398 .unwrap()
399 .build();
400
401 let debug_str = format!("{:?}", delivery);
402 assert!(debug_str.contains("Delivery"));
403 }
404
405 #[test]
406 fn test_common_brazilian_companies() {
407 let companies = vec!["Correios", "Jadlog", "Loggi", "Total Express"];
408
409 for company_name in companies {
410 let delivery = Delivery::builder()
411 .delivery_company_str(company_name)
412 .unwrap()
413 .build();
414
415 assert_eq!(delivery.delivery_company.unwrap().as_str(), company_name);
416 }
417 }
418
419 #[test]
420 fn test_common_delivery_methods() {
421 let methods = vec!["SEDEX", "PAC", "Express", "Ground", "Standard"];
422
423 for method_name in methods {
424 let delivery = Delivery::builder()
425 .delivery_method_str(method_name)
426 .unwrap()
427 .build();
428
429 assert_eq!(delivery.delivery_method.unwrap().as_str(), method_name);
430 }
431 }
432
433 #[test]
434 fn test_delivery_with_same_date() {
435 let delivery = Delivery::builder()
436 .estimated_shipping_date_str("2025-12-01")
437 .unwrap()
438 .estimated_delivery_date_str("2025-12-01")
439 .unwrap()
440 .build();
441
442 assert_eq!(
443 delivery.estimated_shipping_date.unwrap().as_str(),
444 delivery.estimated_delivery_date.unwrap().as_str()
445 );
446 }
447
448 #[test]
449 fn test_delivery_date_validation_edge_cases() {
450 let delivery = Delivery::builder()
452 .estimated_shipping_date_str("2025-01-31")
453 .unwrap()
454 .build();
455 assert!(delivery.estimated_shipping_date.is_some());
456
457 let delivery = Delivery::builder()
459 .estimated_shipping_date_str("2025-02-28")
460 .unwrap()
461 .build();
462 assert!(delivery.estimated_shipping_date.is_some());
463
464 let delivery = Delivery::builder()
466 .estimated_shipping_date_str("2024-02-29")
467 .unwrap()
468 .build();
469 assert!(delivery.estimated_shipping_date.is_some());
470 }
471
472 #[test]
473 fn test_delivery_invalid_february_29_non_leap_year() {
474 let result = Delivery::builder()
475 .estimated_shipping_date_str("2025-02-29")
476 .unwrap_err();
477
478 assert!(matches!(result, ValidationError::InvalidFormat { .. }));
479 }
480
481 #[test]
482 fn test_delivery_company_with_special_chars() {
483 let delivery = Delivery::builder()
484 .delivery_company_str("DHL Express (Brasil)")
485 .unwrap()
486 .build();
487
488 assert_eq!(
489 delivery.delivery_company.unwrap().as_str(),
490 "DHL Express (Brasil)"
491 );
492 }
493
494 #[test]
495 fn test_delivery_method_with_special_chars() {
496 let delivery = Delivery::builder()
497 .delivery_method_str("Next-Day Air")
498 .unwrap()
499 .build();
500
501 assert_eq!(delivery.delivery_method.unwrap().as_str(), "Next-Day Air");
502 }
503}