Skip to main content

koprogo_api/application/ports/
unit_owner_repository.rs

1use crate::domain::entities::{LotHolder, UnitOwner};
2use async_trait::async_trait;
3use rust_decimal::Decimal;
4use uuid::Uuid;
5
6#[async_trait]
7pub trait UnitOwnerRepository: Send + Sync {
8    /// Create a new unit-owner relationship
9    async fn create(&self, unit_owner: &UnitOwner) -> Result<UnitOwner, String>;
10
11    /// Find a unit-owner relationship by ID
12    async fn find_by_id(&self, id: Uuid) -> Result<Option<UnitOwner>, String>;
13
14    /// Get all current owners of a unit (end_date IS NULL)
15    async fn find_current_owners_by_unit(&self, unit_id: Uuid) -> Result<Vec<UnitOwner>, String>;
16
17    /// Get all current units of an owner (end_date IS NULL)
18    async fn find_current_units_by_owner(&self, owner_id: Uuid) -> Result<Vec<UnitOwner>, String>;
19
20    /// Get ownership history of a unit (including past owners)
21    async fn find_all_owners_by_unit(&self, unit_id: Uuid) -> Result<Vec<UnitOwner>, String>;
22
23    /// Get ownership history of an owner (including past units)
24    async fn find_all_units_by_owner(&self, owner_id: Uuid) -> Result<Vec<UnitOwner>, String>;
25
26    /// Update a unit-owner relationship
27    async fn update(&self, unit_owner: &UnitOwner) -> Result<UnitOwner, String>;
28
29    /// Delete a unit-owner relationship
30    async fn delete(&self, id: Uuid) -> Result<(), String>;
31
32    /// Check if a unit has any active owners
33    async fn has_active_owners(&self, unit_id: Uuid) -> Result<bool, String>;
34
35    /// Get the total ownership percentage for a unit (should be <= 1.0)
36    async fn get_total_ownership_percentage(&self, unit_id: Uuid) -> Result<Decimal, String>;
37
38    /// Find active unit-owner relationship by unit and owner IDs
39    async fn find_active_by_unit_and_owner(
40        &self,
41        unit_id: Uuid,
42        owner_id: Uuid,
43    ) -> Result<Option<UnitOwner>, String>;
44
45    /// Get all active unit-owner relationships for a building
46    /// Returns tuples of (unit_id, owner_id, ownership_percentage)
47    /// Useful for calculating charge distributions
48    /// Détentions actives d'un immeuble, avec le pourcentage BRUT de détention
49    /// dans le lot (`unit_owners.ownership_percentage`).
50    ///
51    /// ⚠️ Ce pourcentage n'est PAS une quote-part de charge. Un propriétaire
52    /// unique d'un lot vaut 1.0 quel que soit le poids de son lot dans
53    /// l'immeuble. Ne l'utiliser que pour identifier QUI détient quoi
54    /// (autorisations, éligibilité au vote), jamais pour répartir un montant :
55    /// voir `find_active_quota_shares_by_building`.
56    async fn find_active_by_building(
57        &self,
58        building_id: Uuid,
59    ) -> Result<Vec<(Uuid, Uuid, Decimal)>, String>;
60
61    /// Quotes-parts de CHARGE des détenteurs actifs d'un immeuble.
62    ///
63    /// Renvoie `(unit_id, owner_id, part)` où `part` est la fraction `[0, 1]` du
64    /// montant total qui incombe à ce copropriétaire :
65    ///
66    /// ```text
67    /// part = (unit.quota / building.total_tantiemes) × ownership_percentage
68    /// ```
69    ///
70    /// C'est la formule de l'Art. 3.84 CC, déjà implémentée et testée par
71    /// `ChargeDistribution::resolve_owner_quota`. La somme des parts d'un
72    /// immeuble conforme vaut 1.
73    async fn find_active_quota_shares_by_building(
74        &self,
75        building_id: Uuid,
76    ) -> Result<Vec<(Uuid, Uuid, Decimal)>, String>;
77
78    /// Story H17 (Art. 3.87 §1 CC) — titularités actives d'un lot réduites aux
79    /// attributs pertinents pour le calcul du droit de vote (`ownership_type`
80    /// + `is_voting_representative`). Consommé par le gate vote (`cast_vote`)
81    /// pour rejeter les lots démembrés/indivis sans représentant unique désigné
82    /// (`VOTING_RIGHT_SUSPENDED`).
83    async fn find_voting_holders_by_unit(&self, unit_id: Uuid) -> Result<Vec<LotHolder>, String>;
84
85    /// Story #848 (Art. 3.87 §1 CC) — la ligne `unit_owners` identifiée
86    /// porte-t-elle déjà la désignation de représentant de vote ? Sert à
87    /// rendre la désignation idempotente : redésigner le représentant déjà en
88    /// place ne doit pas se heurter à la règle du représentant unique contre
89    /// elle-même (`assert_single_voting_representative`).
90    async fn is_voting_representative(&self, unit_owner_id: Uuid) -> Result<bool, String>;
91
92    /// Story #848 (Art. 3.87 §1 CC) — écrit la désignation du représentant de
93    /// vote pour une ligne `unit_owners` précise. L'appelant DOIT avoir validé
94    /// `assert_single_voting_representative` sur l'état prospectif AVANT
95    /// d'appeler cette méthode : elle écrit, elle ne contrôle rien (cf.
96    /// `UnitOwnerUseCases::designate_voting_representative`).
97    async fn set_voting_representative(&self, unit_owner_id: Uuid) -> Result<(), String>;
98}