backbone_pos/presentation/dto/
pos_opening_entry_dto.rs1use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10use chrono::{DateTime, Utc};
11
12#[cfg(feature = "openapi")]
13#[cfg(feature = "openapi")]
14use utoipa::ToSchema;
15
16use crate::domain::entity::PosOpeningEntry;
17use crate::domain::entity::AuditMetadata;
18use crate::domain::entity::PosSessionStatus;
19
20#[derive(Debug, Clone, Deserialize)]
29#[cfg_attr(feature = "openapi", derive(ToSchema))]
30#[serde(rename_all = "camelCase")]
31pub struct CreatePosOpeningEntryDto {
32 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
33 #[serde(alias = "pos_profile_id")]
34 pub pos_profile_id: Uuid,
35 #[serde(default, skip_serializing_if = "Option::is_none", alias = "branch_id")]
36 pub branch_id: Option<Uuid>,
37 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
38 #[serde(alias = "cashier_party_id")]
39 pub cashier_party_id: Uuid,
40 #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
41 #[serde(alias = "opened_at")]
42 pub opened_at: DateTime<Utc>,
43 #[serde(default, skip_serializing_if = "Option::is_none", alias = "opening_balances")]
44 pub opening_balances: Option<serde_json::Value>,
45 pub status: PosSessionStatus,
46}
47
48#[derive(Debug, Clone, Deserialize)]
57#[cfg_attr(feature = "openapi", derive(ToSchema))]
58#[serde(rename_all = "camelCase")]
59pub struct UpdatePosOpeningEntryDto {
60 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
61 #[serde(alias = "pos_profile_id")]
62 pub pos_profile_id: Uuid,
63 #[serde(default, skip_serializing_if = "Option::is_none", alias = "branch_id")]
64 pub branch_id: Option<Uuid>,
65 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
66 #[serde(alias = "cashier_party_id")]
67 pub cashier_party_id: Uuid,
68 #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
69 #[serde(alias = "opened_at")]
70 pub opened_at: DateTime<Utc>,
71 #[serde(default, skip_serializing_if = "Option::is_none", alias = "opening_balances")]
72 pub opening_balances: Option<serde_json::Value>,
73 pub status: PosSessionStatus,
74}
75
76#[derive(Debug, Clone, Default, Deserialize)]
85#[cfg_attr(feature = "openapi", derive(ToSchema))]
86#[serde(rename_all = "camelCase")]
87pub struct PatchPosOpeningEntryDto {
88 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
89 #[serde(skip_serializing_if = "Option::is_none", alias = "pos_profile_id")]
90 pub pos_profile_id: Option<Uuid>,
91 #[serde(skip_serializing_if = "Option::is_none", alias = "branch_id")]
92 pub branch_id: Option<Uuid>,
93 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
94 #[serde(skip_serializing_if = "Option::is_none", alias = "cashier_party_id")]
95 pub cashier_party_id: Option<Uuid>,
96 #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
97 #[serde(skip_serializing_if = "Option::is_none", alias = "opened_at")]
98 pub opened_at: Option<DateTime<Utc>>,
99 #[serde(skip_serializing_if = "Option::is_none", alias = "opening_balances")]
100 pub opening_balances: Option<serde_json::Value>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub status: Option<PosSessionStatus>,
103}
104
105impl PatchPosOpeningEntryDto {
106 pub fn has_changes(&self) -> bool {
108 self.pos_profile_id.is_some() || self.branch_id.is_some() || self.cashier_party_id.is_some() || self.opened_at.is_some() || self.opening_balances.is_some() || self.status.is_some()
109 }
110}
111
112#[derive(Debug, Clone, Serialize)]
121#[cfg_attr(feature = "openapi", derive(ToSchema))]
122#[serde(rename_all = "camelCase")]
123pub struct PosOpeningEntryResponseDto {
124 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
125 pub id: Uuid,
126 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
127 pub pos_profile_id: Uuid,
128 pub branch_id: Option<Uuid>,
129 #[cfg_attr(feature = "openapi", schema(example = "550e8400-e29b-41d4-a716-446655440000"))]
130 pub cashier_party_id: Uuid,
131 #[cfg_attr(feature = "openapi", schema(example = "2024-01-01T00:00:00Z"))]
132 pub opened_at: DateTime<Utc>,
133 pub opening_balances: Option<serde_json::Value>,
134 pub status: PosSessionStatus,
135 pub metadata: AuditMetadata,
136}
137
138#[derive(Debug, Clone, Serialize)]
147#[cfg_attr(feature = "openapi", derive(ToSchema))]
148#[serde(rename_all = "camelCase")]
149pub struct PosOpeningEntryListResponseDto {
150 pub items: Vec<PosOpeningEntryResponseDto>,
152 pub total: u64,
154 pub page: u32,
156 pub per_page: u32,
158 pub total_pages: u32,
160 pub has_next: bool,
162 pub has_prev: bool,
164}
165
166impl PosOpeningEntryListResponseDto {
167 pub fn new(items: Vec<PosOpeningEntryResponseDto>, total: u64, page: u32, per_page: u32) -> Self {
169 let total_pages = if per_page > 0 {
170 ((total as f64) / (per_page as f64)).ceil() as u32
171 } else {
172 0
173 };
174 Self {
175 items,
176 total,
177 page,
178 per_page,
179 total_pages,
180 has_next: page < total_pages,
181 has_prev: page > 1,
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize)]
188#[cfg_attr(feature = "openapi", derive(ToSchema))]
189#[serde(rename_all = "camelCase")]
190pub struct PosOpeningEntrySummaryDto {
191 pub id: Uuid,
192 pub pos_profile_id: Uuid,
193 pub branch_id: Option<Uuid>,
194 pub cashier_party_id: Uuid,
195 pub created_at: Option<DateTime<Utc>>,
196}
197
198impl From<PosOpeningEntry> for PosOpeningEntryResponseDto {
203 fn from(entity: PosOpeningEntry) -> Self {
204 Self {
205 id: entity.id,
206 pos_profile_id: entity.pos_profile_id,
207 branch_id: entity.branch_id,
208 cashier_party_id: entity.cashier_party_id,
209 opened_at: entity.opened_at,
210 opening_balances: entity.opening_balances,
211 status: entity.status,
212 metadata: entity.metadata,
213 }
214 }
215}
216
217impl From<PosOpeningEntry> for PosOpeningEntrySummaryDto {
218 fn from(entity: PosOpeningEntry) -> Self {
219 let created_at = backbone_core::PersistentEntity::created_at(&entity);
220 Self {
221 id: entity.id,
222 pos_profile_id: entity.pos_profile_id,
223 branch_id: entity.branch_id,
224 cashier_party_id: entity.cashier_party_id,
225 created_at,
226 }
227 }
228}
229
230impl From<CreatePosOpeningEntryDto> for PosOpeningEntry {
231 fn from(dto: CreatePosOpeningEntryDto) -> Self {
232 Self {
233 id: Uuid::new_v4(),
234 pos_profile_id: dto.pos_profile_id,
235 branch_id: dto.branch_id,
236 cashier_party_id: dto.cashier_party_id,
237 opened_at: dto.opened_at,
238 opening_balances: dto.opening_balances,
239 status: dto.status,
240 metadata: AuditMetadata::default(),
241 }
242 }
243}
244
245impl From<&PosOpeningEntry> for PosOpeningEntryResponseDto {
246 fn from(entity: &PosOpeningEntry) -> Self {
247 Self {
248 id: entity.id.clone(),
249 pos_profile_id: entity.pos_profile_id.clone(),
250 branch_id: entity.branch_id.clone(),
251 cashier_party_id: entity.cashier_party_id.clone(),
252 opened_at: entity.opened_at.clone(),
253 opening_balances: entity.opening_balances.clone(),
254 status: entity.status.clone(),
255 metadata: entity.metadata.clone(),
256 }
257 }
258}
259
260impl backbone_core::FromCreateDto<CreatePosOpeningEntryDto> for PosOpeningEntry {
261 fn from_create_dto(dto: CreatePosOpeningEntryDto) -> backbone_core::ServiceResult<Self> {
262 Ok(PosOpeningEntry::from(dto))
263 }
264}
265
266impl backbone_core::ApplyUpdateDto<UpdatePosOpeningEntryDto> for PosOpeningEntry {
267 fn apply_update(mut self, dto: UpdatePosOpeningEntryDto) -> backbone_core::ServiceResult<Self> {
268 self.pos_profile_id = dto.pos_profile_id;
269 self.branch_id = dto.branch_id;
270 self.cashier_party_id = dto.cashier_party_id;
271 self.opened_at = dto.opened_at;
272 self.opening_balances = dto.opening_balances;
273 self.status = dto.status;
274 Ok(self)
275 }
276}
277
278