//! Journal DTOs (Data Transfer Objects)
//!
//! Generated by metaphor-schema. Do not edit manually.
//!
//! DTOs provide a clean separation between domain entities and API
//! representations, with 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;
use crate::domain::entity::Journal;
use crate::domain::entity::AuditMetadata;
use crate::domain::entity::JournalSource;
use crate::domain::entity::JournalStatus;
use crate::domain::entity::JournalType;
// =============================================================================
// Create DTO
// =============================================================================
/// Request DTO for creating a new Journal
///
/// 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))]
#[serde(rename_all = "camelCase")]
pub struct CreateJournalDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(alias = "journal_number")]
pub journal_number: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reference_number")]
pub reference_number: Option<String>,
#[serde(alias = "journal_type")]
pub journal_type: JournalType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "branch_id")]
pub branch_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(alias = "transaction_date")]
pub transaction_date: NaiveDate,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posting_date")]
pub posting_date: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_period_id")]
pub fiscal_period_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_year")]
pub fiscal_year: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_month")]
pub fiscal_month: Option<i32>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub currency: String,
#[serde(alias = "total_debit")]
pub total_debit: Decimal,
#[serde(alias = "total_credit")]
pub total_credit: Decimal,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "line_count")]
pub line_count: i32,
pub source: JournalSource,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_type")]
pub source_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_id")]
pub source_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_reference")]
pub source_reference: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_reversed")]
pub is_reversed: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversed_by_id")]
pub reversed_by_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversed_at")]
pub reversed_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversal_reason")]
pub reversal_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reverses_id")]
pub reverses_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_reversing")]
pub is_reversing: bool,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "auto_reverse")]
pub auto_reverse: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "auto_reverse_date")]
pub auto_reverse_date: Option<NaiveDate>,
pub status: JournalStatus,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "requires_approval")]
pub requires_approval: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approval_threshold")]
pub approval_threshold: Option<Decimal>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "submitted_at")]
pub submitted_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "submitted_by")]
pub submitted_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approved_at")]
pub approved_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approved_by")]
pub approved_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejected_at")]
pub rejected_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejected_by")]
pub rejected_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejection_reason")]
pub rejection_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posted_at")]
pub posted_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posted_by")]
pub posted_by: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_voided")]
pub is_voided: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "voided_at")]
pub voided_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "voided_by")]
pub voided_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "void_reason")]
pub void_reason: Option<String>,
pub attachments: serde_json::Value,
}
// =============================================================================
// Update DTO
// =============================================================================
/// Request DTO for full update of a Journal
///
/// 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))]
#[serde(rename_all = "camelCase")]
pub struct UpdateJournalDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(alias = "journal_number")]
pub journal_number: String,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reference_number")]
pub reference_number: Option<String>,
#[serde(alias = "journal_type")]
pub journal_type: JournalType,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "branch_id")]
pub branch_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(alias = "transaction_date")]
pub transaction_date: NaiveDate,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posting_date")]
pub posting_date: Option<NaiveDate>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_period_id")]
pub fiscal_period_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_year")]
pub fiscal_year: Option<i32>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "fiscal_month")]
pub fiscal_month: Option<i32>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub currency: String,
#[serde(alias = "total_debit")]
pub total_debit: Decimal,
#[serde(alias = "total_credit")]
pub total_credit: Decimal,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(alias = "line_count")]
pub line_count: i32,
pub source: JournalSource,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_type")]
pub source_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_id")]
pub source_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "source_reference")]
pub source_reference: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_reversed")]
pub is_reversed: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversed_by_id")]
pub reversed_by_id: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversed_at")]
pub reversed_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reversal_reason")]
pub reversal_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "reverses_id")]
pub reverses_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_reversing")]
pub is_reversing: bool,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "auto_reverse")]
pub auto_reverse: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "auto_reverse_date")]
pub auto_reverse_date: Option<NaiveDate>,
pub status: JournalStatus,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "requires_approval")]
pub requires_approval: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approval_threshold")]
pub approval_threshold: Option<Decimal>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "submitted_at")]
pub submitted_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "submitted_by")]
pub submitted_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approved_at")]
pub approved_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "approved_by")]
pub approved_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejected_at")]
pub rejected_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejected_by")]
pub rejected_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "rejection_reason")]
pub rejection_reason: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posted_at")]
pub posted_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "posted_by")]
pub posted_by: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(alias = "is_voided")]
pub is_voided: bool,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "voided_at")]
pub voided_at: Option<DateTime<Utc>>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "voided_by")]
pub voided_by: Option<Uuid>,
#[serde(default, skip_serializing_if = "Option::is_none", alias = "void_reason")]
pub void_reason: Option<String>,
pub attachments: serde_json::Value,
}
// =============================================================================
// Patch DTO
// =============================================================================
/// Request DTO for partial update of a Journal
///
/// 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))]
#[serde(rename_all = "camelCase")]
pub struct PatchJournalDto {
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "journal_number")]
pub journal_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "reference_number")]
pub reference_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "journal_type")]
pub journal_type: Option<JournalType>,
#[serde(skip_serializing_if = "Option::is_none", alias = "branch_id")]
pub branch_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
#[serde(skip_serializing_if = "Option::is_none", alias = "transaction_date")]
pub transaction_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none", alias = "posting_date")]
pub posting_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none", alias = "fiscal_period_id")]
pub fiscal_period_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "fiscal_year")]
pub fiscal_year: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none", alias = "fiscal_month")]
pub fiscal_month: Option<i32>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub currency: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "total_debit")]
pub total_debit: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none", alias = "total_credit")]
pub total_credit: Option<Decimal>,
#[cfg_attr(feature = "openapi", schema(example = 42))]
#[serde(skip_serializing_if = "Option::is_none", alias = "line_count")]
pub line_count: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source: Option<JournalSource>,
#[serde(skip_serializing_if = "Option::is_none", alias = "source_type")]
pub source_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "source_id")]
pub source_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "source_reference")]
pub source_reference: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "is_reversed")]
pub is_reversed: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", alias = "reversed_by_id")]
pub reversed_by_id: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "reversed_at")]
pub reversed_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "reversal_reason")]
pub reversal_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "reverses_id")]
pub reverses_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "is_reversing")]
pub is_reversing: Option<bool>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "auto_reverse")]
pub auto_reverse: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", alias = "auto_reverse_date")]
pub auto_reverse_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub status: Option<JournalStatus>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "requires_approval")]
pub requires_approval: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", alias = "approval_threshold")]
pub approval_threshold: Option<Decimal>,
#[serde(skip_serializing_if = "Option::is_none", alias = "submitted_at")]
pub submitted_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "submitted_by")]
pub submitted_by: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "approved_at")]
pub approved_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "approved_by")]
pub approved_by: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "rejected_at")]
pub rejected_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "rejected_by")]
pub rejected_by: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "rejection_reason")]
pub rejection_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", alias = "posted_at")]
pub posted_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "posted_by")]
pub posted_by: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
#[serde(skip_serializing_if = "Option::is_none", alias = "is_voided")]
pub is_voided: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", alias = "voided_at")]
pub voided_at: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none", alias = "voided_by")]
pub voided_by: Option<Uuid>,
#[serde(skip_serializing_if = "Option::is_none", alias = "void_reason")]
pub void_reason: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub attachments: Option<serde_json::Value>,
}
impl PatchJournalDto {
/// Check if any field is set
pub fn has_changes(&self) -> bool {
self.journal_number.is_some() || self.reference_number.is_some() || self.journal_type.is_some() || self.branch_id.is_some() || self.transaction_date.is_some() || self.posting_date.is_some() || self.fiscal_period_id.is_some() || self.fiscal_year.is_some() || self.fiscal_month.is_some() || self.description.is_some() || self.notes.is_some() || self.currency.is_some() || self.total_debit.is_some() || self.total_credit.is_some() || self.line_count.is_some() || self.source.is_some() || self.source_type.is_some() || self.source_id.is_some() || self.source_reference.is_some() || self.is_reversed.is_some() || self.reversed_by_id.is_some() || self.reversed_at.is_some() || self.reversal_reason.is_some() || self.reverses_id.is_some() || self.is_reversing.is_some() || self.auto_reverse.is_some() || self.auto_reverse_date.is_some() || self.status.is_some() || self.requires_approval.is_some() || self.approval_threshold.is_some() || self.submitted_at.is_some() || self.submitted_by.is_some() || self.approved_at.is_some() || self.approved_by.is_some() || self.rejected_at.is_some() || self.rejected_by.is_some() || self.rejection_reason.is_some() || self.posted_at.is_some() || self.posted_by.is_some() || self.is_voided.is_some() || self.voided_at.is_some() || self.voided_by.is_some() || self.void_reason.is_some() || self.attachments.is_some()
}
}
// =============================================================================
// Response DTO
// =============================================================================
/// Response DTO for Journal 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 JournalResponseDto {
#[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
pub id: Uuid,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub journal_number: String,
pub reference_number: Option<String>,
pub journal_type: JournalType,
pub branch_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = "2024-01-01"))]
pub transaction_date: NaiveDate,
pub posting_date: Option<NaiveDate>,
pub fiscal_period_id: Option<Uuid>,
pub fiscal_year: Option<i32>,
pub fiscal_month: Option<i32>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub description: String,
pub notes: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = "example"))]
pub currency: String,
pub total_debit: Decimal,
pub total_credit: Decimal,
#[cfg_attr(feature = "openapi", schema(example = 42))]
pub line_count: i32,
pub source: JournalSource,
pub source_type: Option<String>,
pub source_id: Option<Uuid>,
pub source_reference: Option<String>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub is_reversed: bool,
pub reversed_by_id: Option<Uuid>,
pub reversed_at: Option<DateTime<Utc>>,
pub reversal_reason: Option<String>,
pub reverses_id: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub is_reversing: bool,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub auto_reverse: bool,
pub auto_reverse_date: Option<NaiveDate>,
pub status: JournalStatus,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub requires_approval: bool,
pub approval_threshold: Option<Decimal>,
pub submitted_at: Option<DateTime<Utc>>,
pub submitted_by: Option<Uuid>,
pub approved_at: Option<DateTime<Utc>>,
pub approved_by: Option<Uuid>,
pub rejected_at: Option<DateTime<Utc>>,
pub rejected_by: Option<Uuid>,
pub rejection_reason: Option<String>,
pub posted_at: Option<DateTime<Utc>>,
pub posted_by: Option<Uuid>,
#[cfg_attr(feature = "openapi", schema(example = true))]
pub is_voided: bool,
pub voided_at: Option<DateTime<Utc>>,
pub voided_by: Option<Uuid>,
pub void_reason: Option<String>,
pub attachments: serde_json::Value,
pub metadata: AuditMetadata,
}
// =============================================================================
// List Response DTO
// =============================================================================
/// Paginated list response for Journal 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 JournalListResponseDto {
/// List of items
pub items: Vec<JournalResponseDto>,
/// 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 JournalListResponseDto {
/// Create a new list response from items and pagination info
pub fn new(items: Vec<JournalResponseDto>, 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 JournalSummaryDto {
pub id: Uuid,
pub journal_number: String,
pub reference_number: Option<String>,
pub journal_type: JournalType,
pub created_at: Option<DateTime<Utc>>,
}
// =============================================================================
// Conversions
// =============================================================================
impl From<Journal> for JournalResponseDto {
fn from(entity: Journal) -> Self {
Self {
id: entity.id,
journal_number: entity.journal_number,
reference_number: entity.reference_number,
journal_type: entity.journal_type,
branch_id: entity.branch_id,
transaction_date: entity.transaction_date,
posting_date: entity.posting_date,
fiscal_period_id: entity.fiscal_period_id,
fiscal_year: entity.fiscal_year,
fiscal_month: entity.fiscal_month,
description: entity.description,
notes: entity.notes,
currency: entity.currency,
total_debit: entity.total_debit,
total_credit: entity.total_credit,
line_count: entity.line_count,
source: entity.source,
source_type: entity.source_type,
source_id: entity.source_id,
source_reference: entity.source_reference,
is_reversed: entity.is_reversed,
reversed_by_id: entity.reversed_by_id,
reversed_at: entity.reversed_at,
reversal_reason: entity.reversal_reason,
reverses_id: entity.reverses_id,
is_reversing: entity.is_reversing,
auto_reverse: entity.auto_reverse,
auto_reverse_date: entity.auto_reverse_date,
status: entity.status,
requires_approval: entity.requires_approval,
approval_threshold: entity.approval_threshold,
submitted_at: entity.submitted_at,
submitted_by: entity.submitted_by,
approved_at: entity.approved_at,
approved_by: entity.approved_by,
rejected_at: entity.rejected_at,
rejected_by: entity.rejected_by,
rejection_reason: entity.rejection_reason,
posted_at: entity.posted_at,
posted_by: entity.posted_by,
is_voided: entity.is_voided,
voided_at: entity.voided_at,
voided_by: entity.voided_by,
void_reason: entity.void_reason,
attachments: entity.attachments,
metadata: entity.metadata,
}
}
}
impl From<Journal> for JournalSummaryDto {
fn from(entity: Journal) -> Self {
let created_at = backbone_core::PersistentEntity::created_at(&entity);
Self {
id: entity.id,
journal_number: entity.journal_number,
reference_number: entity.reference_number,
journal_type: entity.journal_type,
created_at,
}
}
}
impl From<CreateJournalDto> for Journal {
fn from(dto: CreateJournalDto) -> Self {
Self {
id: Uuid::new_v4(),
journal_number: dto.journal_number,
reference_number: dto.reference_number,
journal_type: dto.journal_type,
branch_id: dto.branch_id,
transaction_date: dto.transaction_date,
posting_date: dto.posting_date,
fiscal_period_id: dto.fiscal_period_id,
fiscal_year: dto.fiscal_year,
fiscal_month: dto.fiscal_month,
description: dto.description,
notes: dto.notes,
currency: dto.currency,
total_debit: dto.total_debit,
total_credit: dto.total_credit,
line_count: dto.line_count,
source: dto.source,
source_type: dto.source_type,
source_id: dto.source_id,
source_reference: dto.source_reference,
is_reversed: dto.is_reversed,
reversed_by_id: dto.reversed_by_id,
reversed_at: dto.reversed_at,
reversal_reason: dto.reversal_reason,
reverses_id: dto.reverses_id,
is_reversing: dto.is_reversing,
auto_reverse: dto.auto_reverse,
auto_reverse_date: dto.auto_reverse_date,
status: dto.status,
requires_approval: dto.requires_approval,
approval_threshold: dto.approval_threshold,
submitted_at: dto.submitted_at,
submitted_by: dto.submitted_by,
approved_at: dto.approved_at,
approved_by: dto.approved_by,
rejected_at: dto.rejected_at,
rejected_by: dto.rejected_by,
rejection_reason: dto.rejection_reason,
posted_at: dto.posted_at,
posted_by: dto.posted_by,
is_voided: dto.is_voided,
voided_at: dto.voided_at,
voided_by: dto.voided_by,
void_reason: dto.void_reason,
attachments: dto.attachments,
metadata: AuditMetadata::default(),
}
}
}
impl From<&Journal> for JournalResponseDto {
fn from(entity: &Journal) -> Self {
Self {
id: entity.id.clone(),
journal_number: entity.journal_number.clone(),
reference_number: entity.reference_number.clone(),
journal_type: entity.journal_type.clone(),
branch_id: entity.branch_id.clone(),
transaction_date: entity.transaction_date.clone(),
posting_date: entity.posting_date.clone(),
fiscal_period_id: entity.fiscal_period_id.clone(),
fiscal_year: entity.fiscal_year.clone(),
fiscal_month: entity.fiscal_month.clone(),
description: entity.description.clone(),
notes: entity.notes.clone(),
currency: entity.currency.clone(),
total_debit: entity.total_debit.clone(),
total_credit: entity.total_credit.clone(),
line_count: entity.line_count.clone(),
source: entity.source.clone(),
source_type: entity.source_type.clone(),
source_id: entity.source_id.clone(),
source_reference: entity.source_reference.clone(),
is_reversed: entity.is_reversed.clone(),
reversed_by_id: entity.reversed_by_id.clone(),
reversed_at: entity.reversed_at.clone(),
reversal_reason: entity.reversal_reason.clone(),
reverses_id: entity.reverses_id.clone(),
is_reversing: entity.is_reversing.clone(),
auto_reverse: entity.auto_reverse.clone(),
auto_reverse_date: entity.auto_reverse_date.clone(),
status: entity.status.clone(),
requires_approval: entity.requires_approval.clone(),
approval_threshold: entity.approval_threshold.clone(),
submitted_at: entity.submitted_at.clone(),
submitted_by: entity.submitted_by.clone(),
approved_at: entity.approved_at.clone(),
approved_by: entity.approved_by.clone(),
rejected_at: entity.rejected_at.clone(),
rejected_by: entity.rejected_by.clone(),
rejection_reason: entity.rejection_reason.clone(),
posted_at: entity.posted_at.clone(),
posted_by: entity.posted_by.clone(),
is_voided: entity.is_voided.clone(),
voided_at: entity.voided_at.clone(),
voided_by: entity.voided_by.clone(),
void_reason: entity.void_reason.clone(),
attachments: entity.attachments.clone(),
metadata: entity.metadata.clone(),
}
}
}
impl backbone_core::FromCreateDto<CreateJournalDto> for Journal {
fn from_create_dto(dto: CreateJournalDto) -> backbone_core::ServiceResult<Self> {
Ok(Journal::from(dto))
}
}
impl backbone_core::ApplyUpdateDto<UpdateJournalDto> for Journal {
fn apply_update(mut self, dto: UpdateJournalDto) -> backbone_core::ServiceResult<Self> {
self.journal_number = dto.journal_number;
self.reference_number = dto.reference_number;
self.journal_type = dto.journal_type;
self.branch_id = dto.branch_id;
self.transaction_date = dto.transaction_date;
self.posting_date = dto.posting_date;
self.fiscal_period_id = dto.fiscal_period_id;
self.fiscal_year = dto.fiscal_year;
self.fiscal_month = dto.fiscal_month;
self.description = dto.description;
self.notes = dto.notes;
self.currency = dto.currency;
self.total_debit = dto.total_debit;
self.total_credit = dto.total_credit;
self.line_count = dto.line_count;
self.source = dto.source;
self.source_type = dto.source_type;
self.source_id = dto.source_id;
self.source_reference = dto.source_reference;
self.is_reversed = dto.is_reversed;
self.reversed_by_id = dto.reversed_by_id;
self.reversed_at = dto.reversed_at;
self.reversal_reason = dto.reversal_reason;
self.reverses_id = dto.reverses_id;
self.is_reversing = dto.is_reversing;
self.auto_reverse = dto.auto_reverse;
self.auto_reverse_date = dto.auto_reverse_date;
self.status = dto.status;
self.requires_approval = dto.requires_approval;
self.approval_threshold = dto.approval_threshold;
self.submitted_at = dto.submitted_at;
self.submitted_by = dto.submitted_by;
self.approved_at = dto.approved_at;
self.approved_by = dto.approved_by;
self.rejected_at = dto.rejected_at;
self.rejected_by = dto.rejected_by;
self.rejection_reason = dto.rejection_reason;
self.posted_at = dto.posted_at;
self.posted_by = dto.posted_by;
self.is_voided = dto.is_voided;
self.voided_at = dto.voided_at;
self.voided_by = dto.voided_by;
self.void_reason = dto.void_reason;
self.attachments = dto.attachments;
Ok(self)
}
}
// =============================================================================
// Custom DTOs
// =============================================================================
// Add custom DTOs specific to Journal here.
// This section will be preserved during regeneration.
// >>> END CUSTOM DTOs