//! MaintenanceRequest DTOs (Data Transfer Objects)
//!
//! Generated by metaphor-schema. Do not edit manually.
//!
//! DTOs provide a clean separation between domain entities and API
//! representations, with validation and OpenAPI documentation support.
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use chrono::{DateTime, Utc, NaiveDate};
use rust_decimal::Decimal;
#[cfg(feature = "openapi")]
#[cfg(feature = "openapi")]
use utoipa::ToSchema;
#[cfg(feature = "validation")]
use validator::Validate;
use crate::domain::entity::MaintenanceRequest;
use crate::domain::entity::AuditMetadata;
use crate::domain::entity::MaintenanceType;
use crate::domain::entity::RepeatType;
use crate::domain::entity::RepeatUnit;
use crate::domain::entity::RequestKanbanState;
use crate::domain::entity::RequestPriority;
// =============================================================================
// Create DTO
// =============================================================================
/// Request DTO for creating a new MaintenanceRequest
///
/// Used in POST requests to create new entities.
/// Excludes auto-generated fields (id, created_at, updated_at, deleted_at).
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct CreateMaintenanceRequestDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(alias = "request_date")]
pub request_date: NaiveDate,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "schedule_date")]
pub schedule_date: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "schedule_end")]
pub schedule_end: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "close_date")]
pub close_date: Option<NaiveDate>,
pub duration: Decimal,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "owner_user_id")]
pub owner_user_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "asset_id")]
pub asset_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "stage_id")]
pub stage_id: Uuid,
#[serde(alias = "kanban_state")]
pub kanban_state: RequestKanbanState,
pub priority: RequestPriority,
#[serde(alias = "maintenance_type")]
pub maintenance_type: MaintenanceType,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub recurring: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "repeat_interval")]
pub repeat_interval: i32,
#[serde(alias = "repeat_unit")]
pub repeat_unit: RepeatUnit,
#[serde(alias = "repeat_type")]
pub repeat_type: RepeatType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "repeat_until")]
pub repeat_until: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "successor_request_id")]
pub successor_request_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "successor_of_request_id")]
pub successor_of_request_id: Option<Uuid>,
}
// =============================================================================
// Update DTO
// =============================================================================
/// Request DTO for full update of a MaintenanceRequest
///
/// Used in PUT requests for full entity replacement.
/// All fields are required (except auto-generated ones).
#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct UpdateMaintenanceRequestDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(alias = "request_date")]
pub request_date: NaiveDate,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "schedule_date")]
pub schedule_date: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "schedule_end")]
pub schedule_end: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "close_date")]
pub close_date: Option<NaiveDate>,
pub duration: Decimal,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "owner_user_id")]
pub owner_user_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "asset_id")]
pub asset_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(alias = "stage_id")]
pub stage_id: Uuid,
#[serde(alias = "kanban_state")]
pub kanban_state: RequestKanbanState,
pub priority: RequestPriority,
#[serde(alias = "maintenance_type")]
pub maintenance_type: MaintenanceType,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub recurring: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "repeat_interval")]
pub repeat_interval: i32,
#[serde(alias = "repeat_unit")]
pub repeat_unit: RepeatUnit,
#[serde(alias = "repeat_type")]
pub repeat_type: RepeatType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "repeat_until")]
pub repeat_until: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "successor_request_id")]
pub successor_request_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "successor_of_request_id")]
pub successor_of_request_id: Option<Uuid>,
}
// =============================================================================
// Patch DTO
// =============================================================================
/// Request DTO for partial update of a MaintenanceRequest
///
/// Used in PATCH requests for partial updates.
/// All fields are optional - only provided fields will be updated.
#[derive(Debug, Clone, Default, Deserialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[cfg_attr(feature = "validation", derive(Validate))]
#[serde(rename_all = "camelCase")]
pub struct PatchMaintenanceRequestDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "request_date")]
pub request_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none", alias = "schedule_date")]
pub schedule_date: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "schedule_end")]
pub schedule_end: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "close_date")]
pub close_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none", alias = "owner_user_id")]
pub owner_user_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "user_id")]
pub user_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "asset_id")]
pub asset_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "stage_id")]
pub stage_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "kanban_state")]
pub kanban_state: Option<RequestKanbanState>,
#[serde(skip_serializing_if = "Option::is_none")]
pub priority: Option<RequestPriority>,
#[serde(skip_serializing_if = "Option::is_none", alias = "maintenance_type")]
pub maintenance_type: Option<MaintenanceType>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none")]
pub recurring: Option<bool>,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(skip_serializing_if = "Option::is_none", alias = "repeat_interval")]
pub repeat_interval: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none", alias = "repeat_unit")]
pub repeat_unit: Option<RepeatUnit>,
#[serde(skip_serializing_if = "Option::is_none", alias = "repeat_type")]
pub repeat_type: Option<RepeatType>,
#[serde(skip_serializing_if = "Option::is_none", alias = "repeat_until")]
pub repeat_until: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none", alias = "successor_request_id")]
pub successor_request_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "successor_of_request_id")]
pub successor_of_request_id: Option<Uuid>,
}
impl PatchMaintenanceRequestDto {
/// Check if any field is set
pub fn has_changes(&self) -> bool {
self.name.is_some() || self.description.is_some() || self.request_date.is_some() || self.schedule_date.is_some() || self.schedule_end.is_some() || self.close_date.is_some() || self.duration.is_some() || self.owner_user_id.is_some() || self.user_id.is_some() || self.asset_id.is_some() || self.stage_id.is_some() || self.kanban_state.is_some() || self.priority.is_some() || self.maintenance_type.is_some() || self.recurring.is_some() || self.repeat_interval.is_some() || self.repeat_unit.is_some() || self.repeat_type.is_some() || self.repeat_until.is_some() || self.successor_request_id.is_some() || self.successor_of_request_id.is_some()
}
}
// =============================================================================
// Response DTO
// =============================================================================
/// Response DTO for MaintenanceRequest entity
///
/// Used in API responses for single entity.
/// Includes all fields including metadata.
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct MaintenanceRequestResponseDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub id: Uuid,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub name: String,
pub description: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
pub request_date: NaiveDate,
pub schedule_date: Option<DateTime<Utc>>,
pub schedule_end: Option<DateTime<Utc>>,
pub close_date: Option<NaiveDate>,
pub duration: Decimal,
pub owner_user_id: Option<Uuid>,
pub user_id: Option<Uuid>,
pub asset_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub stage_id: Uuid,
pub kanban_state: RequestKanbanState,
pub priority: RequestPriority,
pub maintenance_type: MaintenanceType,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub recurring: bool,
#[cfg_attr(feature = "openapi", schema(example = 42))]
pub repeat_interval: i32,
pub repeat_unit: RepeatUnit,
pub repeat_type: RepeatType,
pub repeat_until: Option<NaiveDate>,
pub successor_request_id: Option<Uuid>,
pub successor_of_request_id: Option<Uuid>,
pub metadata: AuditMetadata,
}
// =============================================================================
// List Response DTO
// =============================================================================
/// Paginated list response for MaintenanceRequest entities
///
/// Used in API responses for list endpoints.
/// Includes pagination metadata.
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct MaintenanceRequestListResponseDto {
/// List of items
pub items: Vec<MaintenanceRequestResponseDto>,
/// Total number of items (across all pages)
pub total: u64,
/// Current page number (1-indexed)
pub page: u32,
/// Number of items per page
pub per_page: u32,
/// Total number of pages
pub total_pages: u32,
/// Whether there is a next page
pub has_next: bool,
/// Whether there is a previous page
pub has_prev: bool,
}
impl MaintenanceRequestListResponseDto {
/// Create a new list response from items and pagination info
pub fn new(items: Vec<MaintenanceRequestResponseDto>, 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,
}
}
}
/// Summary DTO for list views (compact version)
#[derive(Debug, Clone, Serialize)]
#[cfg_attr(feature = "openapi", derive(ToSchema))]
#[serde(rename_all = "camelCase")]
pub struct MaintenanceRequestSummaryDto {
pub id: Uuid,
pub name: String,
pub description: Option<String>,
pub request_date: NaiveDate,
pub created_at: Option<DateTime<Utc>>,
}
// =============================================================================
// Conversions
// =============================================================================
impl From<MaintenanceRequest> for MaintenanceRequestResponseDto {
fn from(entity: MaintenanceRequest) -> Self {
Self {
id: entity.id,
name: entity.name,
description: entity.description,
request_date: entity.request_date,
schedule_date: entity.schedule_date,
schedule_end: entity.schedule_end,
close_date: entity.close_date,
duration: entity.duration,
owner_user_id: entity.owner_user_id,
user_id: entity.user_id,
asset_id: entity.asset_id,
stage_id: entity.stage_id,
kanban_state: entity.kanban_state,
priority: entity.priority,
maintenance_type: entity.maintenance_type,
recurring: entity.recurring,
repeat_interval: entity.repeat_interval,
repeat_unit: entity.repeat_unit,
repeat_type: entity.repeat_type,
repeat_until: entity.repeat_until,
successor_request_id: entity.successor_request_id,
successor_of_request_id: entity.successor_of_request_id,
metadata: entity.metadata,
}
}
}
impl From<MaintenanceRequest> for MaintenanceRequestSummaryDto {
fn from(entity: MaintenanceRequest) -> Self {
let created_at = backbone_core::PersistentEntity::created_at(&entity);
Self {
id: entity.id,
name: entity.name,
description: entity.description,
request_date: entity.request_date,
created_at,
}
}
}
impl From<CreateMaintenanceRequestDto> for MaintenanceRequest {
fn from(dto: CreateMaintenanceRequestDto) -> Self {
Self {
id: Uuid::new_v4(),
name: dto.name,
description: dto.description,
request_date: dto.request_date,
schedule_date: dto.schedule_date,
schedule_end: dto.schedule_end,
close_date: dto.close_date,
duration: dto.duration,
owner_user_id: dto.owner_user_id,
user_id: dto.user_id,
asset_id: dto.asset_id,
stage_id: dto.stage_id,
kanban_state: dto.kanban_state,
priority: dto.priority,
maintenance_type: dto.maintenance_type,
recurring: dto.recurring,
repeat_interval: dto.repeat_interval,
repeat_unit: dto.repeat_unit,
repeat_type: dto.repeat_type,
repeat_until: dto.repeat_until,
successor_request_id: dto.successor_request_id,
successor_of_request_id: dto.successor_of_request_id,
metadata: AuditMetadata::default(),
}
}
}
impl From<&MaintenanceRequest> for MaintenanceRequestResponseDto {
fn from(entity: &MaintenanceRequest) -> Self {
Self {
id: entity.id.clone(),
name: entity.name.clone(),
description: entity.description.clone(),
request_date: entity.request_date.clone(),
schedule_date: entity.schedule_date.clone(),
schedule_end: entity.schedule_end.clone(),
close_date: entity.close_date.clone(),
duration: entity.duration.clone(),
owner_user_id: entity.owner_user_id.clone(),
user_id: entity.user_id.clone(),
asset_id: entity.asset_id.clone(),
stage_id: entity.stage_id.clone(),
kanban_state: entity.kanban_state.clone(),
priority: entity.priority.clone(),
maintenance_type: entity.maintenance_type.clone(),
recurring: entity.recurring.clone(),
repeat_interval: entity.repeat_interval.clone(),
repeat_unit: entity.repeat_unit.clone(),
repeat_type: entity.repeat_type.clone(),
repeat_until: entity.repeat_until.clone(),
successor_request_id: entity.successor_request_id.clone(),
successor_of_request_id: entity.successor_of_request_id.clone(),
metadata: entity.metadata.clone(),
}
}
}
impl backbone_core::FromCreateDto<CreateMaintenanceRequestDto> for MaintenanceRequest {
fn from_create_dto(dto: CreateMaintenanceRequestDto) -> backbone_core::ServiceResult<Self> {
Ok(MaintenanceRequest::from(dto))
}
}
impl backbone_core::ApplyUpdateDto<UpdateMaintenanceRequestDto> for MaintenanceRequest {
fn apply_update(mut self, dto: UpdateMaintenanceRequestDto) -> backbone_core::ServiceResult<Self> {
self.name = dto.name;
self.description = dto.description;
self.request_date = dto.request_date;
self.schedule_date = dto.schedule_date;
self.schedule_end = dto.schedule_end;
self.close_date = dto.close_date;
self.duration = dto.duration;
self.owner_user_id = dto.owner_user_id;
self.user_id = dto.user_id;
self.asset_id = dto.asset_id;
self.stage_id = dto.stage_id;
self.kanban_state = dto.kanban_state;
self.priority = dto.priority;
self.maintenance_type = dto.maintenance_type;
self.recurring = dto.recurring;
self.repeat_interval = dto.repeat_interval;
self.repeat_unit = dto.repeat_unit;
self.repeat_type = dto.repeat_type;
self.repeat_until = dto.repeat_until;
self.successor_request_id = dto.successor_request_id;
self.successor_of_request_id = dto.successor_of_request_id;
Ok(self)
}
}
// =============================================================================
// Custom DTOs
// =============================================================================
// <<< CUSTOM DTOs
// Add custom DTOs specific to MaintenanceRequest here.
// This section will be preserved during regeneration.
// >>> END CUSTOM DTOs