konduto/types/events/
ticket.rs1use crate::types::validation_errors::ValidationError;
2use serde::{Deserialize, Serialize};
3
4use super::{Attendee, TicketCategory, TicketId, TicketSection};
5
6#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Ticket {
9 #[serde(skip_serializing_if = "Option::is_none")]
11 pub id: Option<TicketId>,
12
13 pub category: TicketCategory,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub section: Option<TicketSection>,
19
20 pub premium: bool,
22
23 pub attendee: Attendee,
25}
26
27impl Ticket {
28 pub fn builder() -> TicketBuilder {
30 TicketBuilder::default()
31 }
32}
33
34#[derive(Default)]
36pub struct TicketBuilder {
37 id: Option<TicketId>,
38 category: Option<TicketCategory>,
39 section: Option<TicketSection>,
40 premium: Option<bool>,
41 attendee: Option<Attendee>,
42}
43
44impl TicketBuilder {
45 pub fn id(mut self, id: TicketId) -> Self {
46 self.id = Some(id);
47 self
48 }
49
50 pub fn id_str(mut self, id: impl Into<String>) -> Result<Self, ValidationError> {
51 self.id = Some(TicketId::try_new(id)?);
52 Ok(self)
53 }
54
55 pub fn category(mut self, category: TicketCategory) -> Self {
56 self.category = Some(category);
57 self
58 }
59
60 pub fn section(mut self, section: TicketSection) -> Self {
61 self.section = Some(section);
62 self
63 }
64
65 pub fn section_str(mut self, section: impl Into<String>) -> Result<Self, ValidationError> {
66 self.section = Some(TicketSection::try_new(section)?);
67 Ok(self)
68 }
69
70 pub fn premium(mut self, premium: bool) -> Self {
71 self.premium = Some(premium);
72 self
73 }
74
75 pub fn attendee(mut self, attendee: Attendee) -> Self {
76 self.attendee = Some(attendee);
77 self
78 }
79
80 pub fn build(self) -> Result<Ticket, ValidationError> {
81 Ok(Ticket {
82 id: self.id,
83 category: self
84 .category
85 .ok_or_else(|| ValidationError::EmptyField("ticket_category".to_string()))?,
86 section: self.section,
87 premium: self
88 .premium
89 .ok_or_else(|| ValidationError::EmptyField("ticket_premium".to_string()))?,
90 attendee: self
91 .attendee
92 .ok_or_else(|| ValidationError::EmptyField("ticket_attendee".to_string()))?,
93 })
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::types::events::AttendeeDocumentType;
101
102 #[test]
103 fn test_ticket_complete() {
104 let attendee = Attendee::builder()
105 .name_str("João Silva")
106 .unwrap()
107 .document_str("12345678900")
108 .unwrap()
109 .document_type(AttendeeDocumentType::Cpf)
110 .build()
111 .unwrap();
112
113 let ticket = Ticket::builder()
114 .id_str("TICKET123")
115 .unwrap()
116 .category(TicketCategory::Student)
117 .section_str("A")
118 .unwrap()
119 .premium(false)
120 .attendee(attendee)
121 .build()
122 .unwrap();
123
124 assert_eq!(ticket.id.as_ref().unwrap().as_str(), "TICKET123");
125 assert_eq!(ticket.category, TicketCategory::Student);
126 assert_eq!(ticket.section.as_ref().unwrap().as_str(), "A");
127 assert!(!ticket.premium);
128 }
129
130 #[test]
131 fn test_ticket_minimal() {
132 let attendee = Attendee::builder()
133 .document_str("123")
134 .unwrap()
135 .build()
136 .unwrap();
137
138 let ticket = Ticket::builder()
139 .category(TicketCategory::Regular)
140 .premium(false)
141 .attendee(attendee)
142 .build()
143 .unwrap();
144
145 assert!(ticket.id.is_none());
146 assert!(ticket.section.is_none());
147 assert_eq!(ticket.category, TicketCategory::Regular);
148 }
149
150 #[test]
151 fn test_ticket_premium() {
152 let attendee = Attendee::builder()
153 .document_str("123")
154 .unwrap()
155 .build()
156 .unwrap();
157
158 let ticket = Ticket::builder()
159 .category(TicketCategory::Regular)
160 .premium(true)
161 .attendee(attendee)
162 .build()
163 .unwrap();
164
165 assert!(ticket.premium);
166 }
167
168 #[test]
169 fn test_ticket_missing_category() {
170 let attendee = Attendee::builder()
171 .document_str("123")
172 .unwrap()
173 .build()
174 .unwrap();
175
176 let result = Ticket::builder().premium(false).attendee(attendee).build();
177
178 assert!(result.is_err());
179 }
180
181 #[test]
182 fn test_ticket_missing_attendee() {
183 let result = Ticket::builder()
184 .category(TicketCategory::Regular)
185 .premium(false)
186 .build();
187
188 assert!(result.is_err());
189 }
190
191 #[test]
192 fn test_ticket_serialization() {
193 let attendee = Attendee::builder()
194 .name_str("Test")
195 .unwrap()
196 .document_str("123")
197 .unwrap()
198 .build()
199 .unwrap();
200
201 let ticket = Ticket::builder()
202 .id_str("T001")
203 .unwrap()
204 .category(TicketCategory::Student)
205 .section_str("VIP")
206 .unwrap()
207 .premium(true)
208 .attendee(attendee)
209 .build()
210 .unwrap();
211
212 let json = serde_json::to_string(&ticket).unwrap();
213 assert!(json.contains("T001"));
214 assert!(json.contains("student"));
215 assert!(json.contains("VIP"));
216 assert!(json.contains("true"));
217 }
218}
219