use serde::{Deserialize, Serialize};
use uuid::Uuid;
use chrono::{DateTime, Utc};
#[cfg(feature = "openapi")]
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[cfg(feature = "validation")]
use validator::Validate;
use crate::domain::entity::Registration;
use crate::domain::entity::AuditMetadata;
use crate::domain::entity::EventRegistrationState;
use crate::domain::entity::EventSaleOrderState;
use crate::domain::entity::EventSaleStatus;
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct CreateRegistrationDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "event_id")]
pub event_id: Uuid,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_slot_id")]
pub event_slot_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_ticket_id")]
pub event_ticket_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[cfg_attr(feature = "validation", validate(email, length(max = 254)))]
#[cfg_attr(feature = "openapi", schema(example = "user@example.com"))]
pub email: String,
#[cfg_attr(feature = "validation", validate(length(max = 40)))]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[serde(default, skip_serializing_if = "Option::is_none", alias = "company_name")]
pub company_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "partner_id")]
pub partner_id: Option<Uuid>,
pub state: EventRegistrationState,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "date_closed")]
pub date_closed: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_order_id")]
pub sale_order_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_order_state")]
pub sale_order_state: Option<EventSaleOrderState>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_status")]
pub sale_status: Option<EventSaleStatus>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub active: bool,
#[cfg_attr(feature = "validation", validate(length(max = 32)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub barcode: String,
}
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct UpdateRegistrationDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "event_id")]
pub event_id: Uuid,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_slot_id")]
pub event_slot_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "event_ticket_id")]
pub event_ticket_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[cfg_attr(feature = "validation", validate(email, length(max = 254)))]
#[cfg_attr(feature = "openapi", schema(example = "user@example.com"))]
pub email: String,
#[cfg_attr(feature = "validation", validate(length(max = 40)))]
#[serde(default, skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[serde(default, skip_serializing_if = "Option::is_none", alias = "company_name")]
pub company_name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "partner_id")]
pub partner_id: Option<Uuid>,
pub state: EventRegistrationState,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "date_closed")]
pub date_closed: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_order_id")]
pub sale_order_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_order_state")]
pub sale_order_state: Option<EventSaleOrderState>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "sale_status")]
pub sale_status: Option<EventSaleStatus>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub active: bool,
#[cfg_attr(feature = "validation", validate(length(max = 32)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub barcode: String,
}
#[derive(Debug, Clone, Default, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct PatchRegistrationDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "event_id")]
pub event_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "event_slot_id")]
pub event_slot_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "event_ticket_id")]
pub event_ticket_id: Option<Uuid>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[cfg_attr(feature = "validation", validate(email, length(max = 254)))]
#[cfg_attr(feature = "openapi", schema(example = "user@example.com"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[cfg_attr(feature = "validation", validate(length(max = 40)))]
#[serde(skip_serializing_if = "Option::is_none")]
pub phone: Option<String>,
#[cfg_attr(feature = "validation", validate(length(max = 200)))]
#[serde(skip_serializing_if = "Option::is_none", alias = "company_name")]
pub company_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "partner_id")]
pub partner_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<EventRegistrationState>,
#[serde(skip_serializing_if = "Option::is_none", alias = "date_closed")]
pub date_closed: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "sale_order_id")]
pub sale_order_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "sale_order_state")]
pub sale_order_state: Option<EventSaleOrderState>,
#[serde(skip_serializing_if = "Option::is_none", alias = "sale_status")]
pub sale_status: Option<EventSaleStatus>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none")]
pub active: Option<bool>,
#[cfg_attr(feature = "validation", validate(length(max = 32)))]
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub barcode: Option<String>,
}
impl PatchRegistrationDto {
pub fn has_changes(&self) -> bool {
self.event_id.is_some() || self.event_slot_id.is_some() || self.event_ticket_id.is_some() || self.name.is_some() || self.email.is_some() || self.phone.is_some() || self.company_name.is_some() || self.partner_id.is_some() || self.state.is_some() || self.date_closed.is_some() || self.sale_order_id.is_some() || self.sale_order_state.is_some() || self.sale_status.is_some() || self.active.is_some() || self.barcode.is_some()
}
}
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct RegistrationResponseDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub id: Uuid,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub event_id: Uuid,
pub event_slot_id: Option<Uuid>,
pub event_ticket_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[cfg_attr(feature = "openapi", schema(example = "user@example.com"))]
pub email: String,
pub phone: Option<String>,
pub company_name: Option<String>,
pub partner_id: Option<Uuid>,
pub state: EventRegistrationState,
pub date_closed: Option<DateTime<Utc>>,
pub sale_order_id: Option<Uuid>,
pub sale_order_state: Option<EventSaleOrderState>,
pub sale_status: Option<EventSaleStatus>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub active: bool,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub barcode: String,
pub metadata: AuditMetadata,
}
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct RegistrationListResponseDto {
pub items: Vec<RegistrationResponseDto>,
pub total: u64,
pub page: u32,
pub per_page: u32,
pub total_pages: u32,
pub has_next: bool,
pub has_prev: bool,
}
impl RegistrationListResponseDto {
pub fn new(items: Vec<RegistrationResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
let total_pages = if per_page > 0 {
((total as f64) / (per_page as f64)).ceil() as u32
} else {
0
};
Self {
items,
total,
page,
per_page,
total_pages,
has_next: page < total_pages,
has_prev: page > 1,
}
}
}
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct RegistrationSummaryDto {
pub id: Uuid,
pub event_id: Uuid,
pub event_slot_id: Option<Uuid>,
pub event_ticket_id: Option<Uuid>,
pub created_at: Option<DateTime<Utc>>,
}
impl From<Registration> for RegistrationResponseDto {
fn from(entity: Registration) -> Self {
Self {
id: entity.id,
event_id: entity.event_id,
event_slot_id: entity.event_slot_id,
event_ticket_id: entity.event_ticket_id,
name: entity.name,
email: entity.email,
phone: entity.phone,
company_name: entity.company_name,
partner_id: entity.partner_id,
state: entity.state,
date_closed: entity.date_closed,
sale_order_id: entity.sale_order_id,
sale_order_state: entity.sale_order_state,
sale_status: entity.sale_status,
active: entity.active,
barcode: entity.barcode,
metadata: entity.metadata,
}
}
}
impl From<Registration> for RegistrationSummaryDto {
fn from(entity: Registration) -> Self {
let created_at = backbone_core::PersistentEntity::created_at(&entity);
Self {
id: entity.id,
event_id: entity.event_id,
event_slot_id: entity.event_slot_id,
event_ticket_id: entity.event_ticket_id,
created_at,
}
}
}
impl From<CreateRegistrationDto> for Registration {
fn from(dto: CreateRegistrationDto) -> Self {
Self {
id: Uuid::new_v4(),
event_id: dto.event_id,
event_slot_id: dto.event_slot_id,
event_ticket_id: dto.event_ticket_id,
name: dto.name,
email: dto.email,
phone: dto.phone,
company_name: dto.company_name,
partner_id: dto.partner_id,
state: dto.state,
date_closed: dto.date_closed,
sale_order_id: dto.sale_order_id,
sale_order_state: dto.sale_order_state,
sale_status: dto.sale_status,
active: dto.active,
barcode: dto.barcode,
metadata: AuditMetadata::default(),
}
}
}
impl From<&Registration> for RegistrationResponseDto {
fn from(entity: &Registration) -> Self {
Self {
id: entity.id.clone(),
event_id: entity.event_id.clone(),
event_slot_id: entity.event_slot_id.clone(),
event_ticket_id: entity.event_ticket_id.clone(),
name: entity.name.clone(),
email: entity.email.clone(),
phone: entity.phone.clone(),
company_name: entity.company_name.clone(),
partner_id: entity.partner_id.clone(),
state: entity.state.clone(),
date_closed: entity.date_closed.clone(),
sale_order_id: entity.sale_order_id.clone(),
sale_order_state: entity.sale_order_state.clone(),
sale_status: entity.sale_status.clone(),
active: entity.active.clone(),
barcode: entity.barcode.clone(),
metadata: entity.metadata.clone(),
}
}
}
impl backbone_core::FromCreateDto<CreateRegistrationDto> for Registration {
fn from_create_dto(dto: CreateRegistrationDto) -> backbone_core::ServiceResult<Self> {
Ok(Registration::from(dto))
}
}
impl backbone_core::ApplyUpdateDto<UpdateRegistrationDto> for Registration {
fn apply_update(mut self, dto: UpdateRegistrationDto) -> backbone_core::ServiceResult<Self> {
self.event_id = dto.event_id;
self.event_slot_id = dto.event_slot_id;
self.event_ticket_id = dto.event_ticket_id;
self.name = dto.name;
self.email = dto.email;
self.phone = dto.phone;
self.company_name = dto.company_name;
self.partner_id = dto.partner_id;
self.state = dto.state;
self.date_closed = dto.date_closed;
self.sale_order_id = dto.sale_order_id;
self.sale_order_state = dto.sale_order_state;
self.sale_status = dto.sale_status;
self.active = dto.active;
self.barcode = dto.barcode;
Ok(self)
}
}