koprogo_api/application/dto/
budget_dto.rs1use crate::domain::entities::{Budget, BudgetStatus};
2use chrono::{DateTime, Utc};
3use rust_decimal::Decimal;
4use serde::{Deserialize, Serialize};
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct CreateBudgetRequest {
10 #[serde(default)]
11 pub organization_id: Uuid, pub building_id: Uuid,
13 pub fiscal_year: i32,
14 pub ordinary_budget: Decimal,
15 pub extraordinary_budget: Decimal,
16 pub notes: Option<String>,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct UpdateBudgetRequest {
22 pub ordinary_budget: Option<Decimal>,
23 pub extraordinary_budget: Option<Decimal>,
24 pub notes: Option<String>,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct BudgetResponse {
30 pub id: Uuid,
31 pub acp_id: Uuid,
33 pub organization_id: Uuid,
35 pub building_id: Uuid,
36 pub fiscal_year: i32,
37 pub ordinary_budget: Decimal,
38 pub extraordinary_budget: Decimal,
39 pub total_budget: Decimal,
40 pub status: BudgetStatus,
41 pub submitted_date: Option<DateTime<Utc>>,
42 pub approved_date: Option<DateTime<Utc>>,
43 pub approved_by_meeting_id: Option<Uuid>,
44 pub monthly_provision_amount: Decimal,
45 pub notes: Option<String>,
46 pub created_at: DateTime<Utc>,
47 pub updated_at: DateTime<Utc>,
48 pub is_active: bool,
50 pub is_editable: bool,
51}
52
53impl From<Budget> for BudgetResponse {
54 fn from(budget: Budget) -> Self {
55 let is_active = budget.is_active();
56 let is_editable = budget.is_editable();
57
58 Self {
59 id: budget.id,
60 acp_id: budget.acp_id,
61 organization_id: budget.organization_id,
62 building_id: budget.building_id,
63 fiscal_year: budget.fiscal_year,
64 ordinary_budget: budget.ordinary_budget,
65 extraordinary_budget: budget.extraordinary_budget,
66 total_budget: budget.total_budget,
67 status: budget.status,
68 submitted_date: budget.submitted_date,
69 approved_date: budget.approved_date,
70 approved_by_meeting_id: budget.approved_by_meeting_id,
71 monthly_provision_amount: budget.monthly_provision_amount,
72 notes: budget.notes,
73 created_at: budget.created_at,
74 updated_at: budget.updated_at,
75 is_active,
76 is_editable,
77 }
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct BudgetVarianceResponse {
84 pub budget_id: Uuid,
85 pub fiscal_year: i32,
86 pub building_id: Uuid,
87
88 #[serde(with = "rust_decimal::serde::float")]
90 pub budgeted_ordinary: Decimal,
91 #[serde(with = "rust_decimal::serde::float")]
92 pub budgeted_extraordinary: Decimal,
93 #[serde(with = "rust_decimal::serde::float")]
94 pub budgeted_total: Decimal,
95
96 #[serde(with = "rust_decimal::serde::float")]
98 pub actual_ordinary: Decimal,
99 #[serde(with = "rust_decimal::serde::float")]
100 pub actual_extraordinary: Decimal,
101 #[serde(with = "rust_decimal::serde::float")]
102 pub actual_total: Decimal,
103
104 #[serde(with = "rust_decimal::serde::float")]
106 pub variance_ordinary: Decimal,
107 #[serde(with = "rust_decimal::serde::float")]
108 pub variance_extraordinary: Decimal,
109 #[serde(with = "rust_decimal::serde::float")]
110 pub variance_total: Decimal,
111
112 #[serde(with = "rust_decimal::serde::float")]
114 pub variance_ordinary_pct: Decimal,
115 #[serde(with = "rust_decimal::serde::float")]
116 pub variance_extraordinary_pct: Decimal,
117 #[serde(with = "rust_decimal::serde::float")]
118 pub variance_total_pct: Decimal,
119
120 pub has_overruns: bool, pub overrun_categories: Vec<String>, pub months_elapsed: i32, #[serde(with = "rust_decimal::serde::float")]
125 pub projected_year_end_total: Decimal, }
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct BudgetStatsResponse {
131 pub total_budgets: i64,
132 pub draft_count: i64,
133 pub submitted_count: i64,
134 pub approved_count: i64,
135 pub rejected_count: i64,
136 pub archived_count: i64,
137 #[serde(with = "rust_decimal::serde::float")]
139 pub average_total_budget: Decimal,
140 #[serde(with = "rust_decimal::serde::float")]
141 pub average_monthly_provision: Decimal,
142}