koprogo_api/application/use_cases/
unit_use_cases.rs1use crate::application::dto::{
2 CreateUnitDto, PageRequest, UnitFilters, UnitResponseDto, UpdateUnitDto,
3};
4use crate::application::ports::UnitRepository;
5use crate::domain::entities::Unit;
6use std::sync::Arc;
7use uuid::Uuid;
8
9pub struct UnitUseCases {
10 repository: Arc<dyn UnitRepository>,
11}
12
13impl UnitUseCases {
14 pub fn new(repository: Arc<dyn UnitRepository>) -> Self {
15 Self { repository }
16 }
17
18 pub async fn create_unit(&self, dto: CreateUnitDto) -> Result<UnitResponseDto, String> {
19 let organization_id = Uuid::parse_str(&dto.organization_id)
20 .map_err(|_| "Invalid organization_id format".to_string())?;
21 let building_id = Uuid::parse_str(&dto.building_id)
22 .map_err(|_| "Invalid building ID format".to_string())?;
23
24 let unit = Unit::new(
25 organization_id,
26 building_id,
27 dto.unit_number,
28 dto.unit_type,
29 dto.floor,
30 dto.surface_area,
31 dto.quota,
32 )?;
33
34 let created = self.repository.create(&unit).await?;
35 Ok(self.to_response_dto(&created))
36 }
37
38 pub async fn get_unit(&self, id: Uuid) -> Result<Option<UnitResponseDto>, String> {
39 let unit = self.repository.find_by_id(id).await?;
40 Ok(unit.map(|u| self.to_response_dto(&u)))
41 }
42
43 pub async fn list_units_by_building(
44 &self,
45 building_id: Uuid,
46 ) -> Result<Vec<UnitResponseDto>, String> {
47 let units = self.repository.find_by_building(building_id).await?;
48 Ok(units.iter().map(|u| self.to_response_dto(u)).collect())
49 }
50
51 pub async fn list_units_paginated(
52 &self,
53 page_request: &PageRequest,
54 organization_id: Option<Uuid>,
55 ) -> Result<(Vec<UnitResponseDto>, i64), String> {
56 let filters = UnitFilters {
57 organization_id,
58 ..Default::default()
59 };
60
61 let (units, total) = self
62 .repository
63 .find_all_paginated(page_request, &filters)
64 .await?;
65
66 let dtos = units.iter().map(|u| self.to_response_dto(u)).collect();
67 Ok((dtos, total))
68 }
69
70 pub async fn update_unit(
71 &self,
72 id: Uuid,
73 dto: UpdateUnitDto,
74 ) -> Result<UnitResponseDto, String> {
75 let mut unit = self
77 .repository
78 .find_by_id(id)
79 .await?
80 .ok_or("Unit not found".to_string())?;
81
82 unit.unit_number = dto.unit_number;
84 unit.unit_type = dto.unit_type;
85 unit.floor = Some(dto.floor);
86 unit.surface_area = dto.surface_area;
87 unit.quota = dto.quota;
88 unit.updated_at = chrono::Utc::now();
89
90 unit.validate_update()?;
92
93 let updated = self.repository.update(&unit).await?;
95 Ok(self.to_response_dto(&updated))
96 }
97
98 pub async fn assign_owner(
99 &self,
100 unit_id: Uuid,
101 owner_id: Uuid,
102 ) -> Result<UnitResponseDto, String> {
103 let mut unit = self
104 .repository
105 .find_by_id(unit_id)
106 .await?
107 .ok_or_else(|| "Unit not found".to_string())?;
108
109 unit.assign_owner(owner_id);
110
111 let updated = self.repository.update(&unit).await?;
112 Ok(self.to_response_dto(&updated))
113 }
114
115 pub async fn delete_unit(&self, id: Uuid) -> Result<bool, String> {
116 let _unit = self
118 .repository
119 .find_by_id(id)
120 .await?
121 .ok_or("Unit not found".to_string())?;
122
123 self.repository.delete(id).await
125 }
126
127 fn to_response_dto(&self, unit: &Unit) -> UnitResponseDto {
128 UnitResponseDto {
129 id: unit.id.to_string(),
130 building_id: unit.building_id.to_string(),
131 unit_number: unit.unit_number.clone(),
132 unit_type: unit.unit_type.clone(),
133 floor: unit.floor,
134 surface_area: unit.surface_area,
135 quota: unit.quota,
136 owner_id: unit.owner_id.map(|id| id.to_string()),
137 }
138 }
139}