1use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "openapi")]
13#[cfg(feature = "openapi")]
14use utoipa::ToSchema;
15
16#[cfg(feature = "validation")]
17use validator::Validate;
18
19use crate::domain::entity::IntegrationEvent;
20use crate::domain::entity::AuditMetadata;
21use crate::domain::entity::IntegrationStatus;
22
23#[derive(Debug, Clone, Deserialize)]
32#[cfg_attr(feature = "openapi", derive(ToSchema))]
33#[cfg_attr(feature = "validation", derive(Validate))]
34#[serde(rename_all = "camelCase")]
35pub struct CreateIntegrationEventDto {
36 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
37 #[serde(alias = "connector_id")]
38 pub connector_id: Uuid,
39 #[cfg_attr(feature = "openapi", schema(example = "example"))]
40 #[serde(alias = "event_type")]
41 pub event_type: String,
42 #[cfg_attr(feature = "openapi", schema(example = "example"))]
43 #[serde(alias = "external_id")]
44 pub external_id: String,
45 #[cfg_attr(feature = "openapi", schema(example = "example"))]
46 #[serde(alias = "business_key")]
47 pub business_key: String,
48 pub status: IntegrationStatus,
49 #[cfg_attr(feature = "openapi", schema(example = "example"))]
50 pub payload: String,
51 #[serde(default, skip_serializing_if = "Option::is_none", alias = "mapped_ref_type")]
52 pub mapped_ref_type: Option<String>,
53 #[serde(default, skip_serializing_if = "Option::is_none", alias = "mapped_ref_id")]
54 pub mapped_ref_id: Option<Uuid>,
55 #[serde(default, skip_serializing_if = "Option::is_none", alias = "error_detail")]
56 pub error_detail: Option<String>,
57}
58
59#[derive(Debug, Clone, Deserialize)]
68#[cfg_attr(feature = "openapi", derive(ToSchema))]
69#[cfg_attr(feature = "validation", derive(Validate))]
70#[serde(rename_all = "camelCase")]
71pub struct UpdateIntegrationEventDto {
72 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
73 #[serde(alias = "connector_id")]
74 pub connector_id: Uuid,
75 #[cfg_attr(feature = "openapi", schema(example = "example"))]
76 #[serde(alias = "event_type")]
77 pub event_type: String,
78 #[cfg_attr(feature = "openapi", schema(example = "example"))]
79 #[serde(alias = "external_id")]
80 pub external_id: String,
81 #[cfg_attr(feature = "openapi", schema(example = "example"))]
82 #[serde(alias = "business_key")]
83 pub business_key: String,
84 pub status: IntegrationStatus,
85 #[cfg_attr(feature = "openapi", schema(example = "example"))]
86 pub payload: String,
87 #[serde(default, skip_serializing_if = "Option::is_none", alias = "mapped_ref_type")]
88 pub mapped_ref_type: Option<String>,
89 #[serde(default, skip_serializing_if = "Option::is_none", alias = "mapped_ref_id")]
90 pub mapped_ref_id: Option<Uuid>,
91 #[serde(default, skip_serializing_if = "Option::is_none", alias = "error_detail")]
92 pub error_detail: Option<String>,
93}
94
95#[derive(Debug, Clone, Default, Deserialize)]
104#[cfg_attr(feature = "openapi", derive(ToSchema))]
105#[cfg_attr(feature = "validation", derive(Validate))]
106#[serde(rename_all = "camelCase")]
107pub struct PatchIntegrationEventDto {
108 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
109 #[serde(skip_serializing_if = "Option::is_none", alias = "connector_id")]
110 pub connector_id: Option<Uuid>,
111 #[cfg_attr(feature = "openapi", schema(example = "example"))]
112 #[serde(skip_serializing_if = "Option::is_none", alias = "event_type")]
113 pub event_type: Option<String>,
114 #[cfg_attr(feature = "openapi", schema(example = "example"))]
115 #[serde(skip_serializing_if = "Option::is_none", alias = "external_id")]
116 pub external_id: Option<String>,
117 #[cfg_attr(feature = "openapi", schema(example = "example"))]
118 #[serde(skip_serializing_if = "Option::is_none", alias = "business_key")]
119 pub business_key: Option<String>,
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub status: Option<IntegrationStatus>,
122 #[cfg_attr(feature = "openapi", schema(example = "example"))]
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub payload: Option<String>,
125 #[serde(skip_serializing_if = "Option::is_none", alias = "mapped_ref_type")]
126 pub mapped_ref_type: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none", alias = "mapped_ref_id")]
128 pub mapped_ref_id: Option<Uuid>,
129 #[serde(skip_serializing_if = "Option::is_none", alias = "error_detail")]
130 pub error_detail: Option<String>,
131}
132
133impl PatchIntegrationEventDto {
134 pub fn has_changes(&self) -> bool {
136 self.connector_id.is_some() || self.event_type.is_some() || self.external_id.is_some() || self.business_key.is_some() || self.status.is_some() || self.payload.is_some() || self.mapped_ref_type.is_some() || self.mapped_ref_id.is_some() || self.error_detail.is_some()
137 }
138}
139
140#[derive(Debug, Clone, Serialize)]
149#[cfg_attr(feature = "openapi", derive(ToSchema))]
150#[serde(rename_all = "camelCase")]
151pub struct IntegrationEventResponseDto {
152 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
153 pub id: Uuid,
154 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
155 pub connector_id: Uuid,
156 #[cfg_attr(feature = "openapi", schema(example = "example"))]
157 pub event_type: String,
158 #[cfg_attr(feature = "openapi", schema(example = "example"))]
159 pub external_id: String,
160 #[cfg_attr(feature = "openapi", schema(example = "example"))]
161 pub business_key: String,
162 pub status: IntegrationStatus,
163 #[cfg_attr(feature = "openapi", schema(example = "example"))]
164 pub payload: String,
165 pub mapped_ref_type: Option<String>,
166 pub mapped_ref_id: Option<Uuid>,
167 pub error_detail: Option<String>,
168 pub metadata: AuditMetadata,
169}
170
171#[derive(Debug, Clone, Serialize)]
180#[cfg_attr(feature = "openapi", derive(ToSchema))]
181#[serde(rename_all = "camelCase")]
182pub struct IntegrationEventListResponseDto {
183 pub items: Vec<IntegrationEventResponseDto>,
185 pub total: u64,
187 pub page: u32,
189 pub per_page: u32,
191 pub total_pages: u32,
193 pub has_next: bool,
195 pub has_prev: bool,
197}
198
199impl IntegrationEventListResponseDto {
200 pub fn new(items: Vec<IntegrationEventResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
202 let total_pages = if per_page > 0 {
203 ((total as f64) / (per_page as f64)).ceil() as u32
204 } else {
205 0
206 };
207 Self {
208 items,
209 total,
210 page,
211 per_page,
212 total_pages,
213 has_next: page < total_pages,
214 has_prev: page > 1,
215 }
216 }
217}
218
219#[derive(Debug, Clone, Serialize)]
221#[cfg_attr(feature = "openapi", derive(ToSchema))]
222#[serde(rename_all = "camelCase")]
223pub struct IntegrationEventSummaryDto {
224 pub id: Uuid,
225 pub connector_id: Uuid,
226 pub event_type: String,
227 pub external_id: String,
228 pub created_at: Option<DateTime<Utc>>,
229}
230
231impl From<IntegrationEvent> for IntegrationEventResponseDto {
236 fn from(entity: IntegrationEvent) -> Self {
237 Self {
238 id: entity.id,
239 connector_id: entity.connector_id,
240 event_type: entity.event_type,
241 external_id: entity.external_id,
242 business_key: entity.business_key,
243 status: entity.status,
244 payload: entity.payload,
245 mapped_ref_type: entity.mapped_ref_type,
246 mapped_ref_id: entity.mapped_ref_id,
247 error_detail: entity.error_detail,
248 metadata: entity.metadata,
249 }
250 }
251}
252
253impl From<IntegrationEvent> for IntegrationEventSummaryDto {
254 fn from(entity: IntegrationEvent) -> Self {
255 let created_at = backbone_core::PersistentEntity::created_at(&entity);
256 Self {
257 id: entity.id,
258 connector_id: entity.connector_id,
259 event_type: entity.event_type,
260 external_id: entity.external_id,
261 created_at,
262 }
263 }
264}
265
266impl From<CreateIntegrationEventDto> for IntegrationEvent {
267 fn from(dto: CreateIntegrationEventDto) -> Self {
268 Self {
269 id: Uuid::new_v4(),
270 connector_id: dto.connector_id,
271 event_type: dto.event_type,
272 external_id: dto.external_id,
273 business_key: dto.business_key,
274 status: dto.status,
275 payload: dto.payload,
276 mapped_ref_type: dto.mapped_ref_type,
277 mapped_ref_id: dto.mapped_ref_id,
278 error_detail: dto.error_detail,
279 metadata: AuditMetadata::default(),
280 }
281 }
282}
283
284impl From<&IntegrationEvent> for IntegrationEventResponseDto {
285 fn from(entity: &IntegrationEvent) -> Self {
286 Self {
287 id: entity.id.clone(),
288 connector_id: entity.connector_id.clone(),
289 event_type: entity.event_type.clone(),
290 external_id: entity.external_id.clone(),
291 business_key: entity.business_key.clone(),
292 status: entity.status.clone(),
293 payload: entity.payload.clone(),
294 mapped_ref_type: entity.mapped_ref_type.clone(),
295 mapped_ref_id: entity.mapped_ref_id.clone(),
296 error_detail: entity.error_detail.clone(),
297 metadata: entity.metadata.clone(),
298 }
299 }
300}
301
302impl backbone_core::FromCreateDto<CreateIntegrationEventDto> for IntegrationEvent {
303 fn from_create_dto(dto: CreateIntegrationEventDto) -> backbone_core::ServiceResult<Self> {
304 Ok(IntegrationEvent::from(dto))
305 }
306}
307
308impl backbone_core::ApplyUpdateDto<UpdateIntegrationEventDto> for IntegrationEvent {
309 fn apply_update(mut self, dto: UpdateIntegrationEventDto) -> backbone_core::ServiceResult<Self> {
310 self.connector_id = dto.connector_id;
311 self.event_type = dto.event_type;
312 self.external_id = dto.external_id;
313 self.business_key = dto.business_key;
314 self.status = dto.status;
315 self.payload = dto.payload;
316 self.mapped_ref_type = dto.mapped_ref_type;
317 self.mapped_ref_id = dto.mapped_ref_id;
318 self.error_detail = dto.error_detail;
319 Ok(self)
320 }
321}
322
323