konduto/types/events/
ticket.rs

1use crate::types::validation_errors::ValidationError;
2use serde::{Deserialize, Serialize};
3
4use super::{Attendee, TicketCategory, TicketId, TicketSection};
5
6/// Dados do ingresso do evento
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Ticket {
9    /// ID único do ticket (opcional)
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub id: Option<TicketId>,
12
13    /// Categoria do ticket (obrigatório)
14    pub category: TicketCategory,
15
16    /// Seção do ticket (opcional)
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub section: Option<TicketSection>,
19
20    /// Indicador de ticket premium (obrigatório)
21    pub premium: bool,
22
23    /// Dados do participante (obrigatório)
24    pub attendee: Attendee,
25}
26
27impl Ticket {
28    /// Cria um builder para construir um ingresso
29    pub fn builder() -> TicketBuilder {
30        TicketBuilder::default()
31    }
32}
33
34/// Builder para criar ingressos
35#[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