koprogo_api/application/use_cases/
unit_use_cases.rs

1use 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        // Get existing unit
76        let mut unit = self
77            .repository
78            .find_by_id(id)
79            .await?
80            .ok_or("Unit not found".to_string())?;
81
82        // Update unit fields
83        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        // Validate the updated unit
91        unit.validate_update()?;
92
93        // Save updated unit
94        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        // Check if unit exists
117        let _unit = self
118            .repository
119            .find_by_id(id)
120            .await?
121            .ok_or("Unit not found".to_string())?;
122
123        // Delete the unit
124        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}