koprogo_api/domain/copropriete/
acp_enabled_module.rs1use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use uuid::Uuid;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, utoipa::ToSchema)]
23#[serde(rename_all = "snake_case")]
24pub enum Module {
25 Identity,
28 Community,
29 Ticketing,
30 Accounting,
31 Governance,
32 Maintenance,
33 Portfolio,
34}
35
36impl Module {
37 pub const ALL: [Module; 7] = [
39 Module::Identity,
40 Module::Community,
41 Module::Ticketing,
42 Module::Accounting,
43 Module::Governance,
44 Module::Maintenance,
45 Module::Portfolio,
46 ];
47
48 pub fn as_str(&self) -> &'static str {
50 match self {
51 Module::Identity => "identity",
52 Module::Community => "community",
53 Module::Ticketing => "ticketing",
54 Module::Accounting => "accounting",
55 Module::Governance => "governance",
56 Module::Maintenance => "maintenance",
57 Module::Portfolio => "portfolio",
58 }
59 }
60
61 pub fn est_toujours_actif(&self) -> bool {
67 matches!(self, Module::Identity)
68 }
69
70 pub fn depuis_nom(nom: &str) -> Option<Module> {
77 Module::ALL.into_iter().find(|m| m.as_str() == nom)
78 }
79}
80
81impl std::fmt::Display for Module {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 f.write_str(self.as_str())
84 }
85}
86
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94pub struct AcpEnabledModule {
95 pub id: Uuid,
96 pub acp_id: Uuid,
97 pub module: Module,
98 pub enabled_at: DateTime<Utc>,
99 pub archived_at: Option<DateTime<Utc>>,
100}
101
102impl AcpEnabledModule {
103 pub fn est_actif(&self) -> bool {
104 self.archived_at.is_none()
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn negative_un_nom_inconnu_nest_pas_un_module() {
114 assert_eq!(Module::depuis_nom("foobar"), None);
115 assert_eq!(Module::depuis_nom(""), None);
116 }
117
118 #[test]
119 fn edge_la_casse_nest_pas_rattrapee() {
120 assert_eq!(Module::depuis_nom("Accounting"), None);
123 assert_eq!(Module::depuis_nom("accounting"), Some(Module::Accounting));
124 }
125
126 #[test]
127 fn happy_chaque_variante_fait_laller_retour_par_son_nom() {
128 for module in Module::ALL {
129 assert_eq!(Module::depuis_nom(module.as_str()), Some(module));
130 }
131 }
132
133 #[test]
134 fn happy_identity_est_le_seul_module_toujours_actif() {
135 let toujours_actifs: Vec<&str> = Module::ALL
136 .into_iter()
137 .filter(|m| m.est_toujours_actif())
138 .map(|m| m.as_str())
139 .collect();
140 assert_eq!(toujours_actifs, vec!["identity"]);
141 }
142
143 #[test]
144 fn happy_archived_at_est_la_seule_lecture_de_letat() {
145 let mut m = AcpEnabledModule {
146 id: Uuid::new_v4(),
147 acp_id: Uuid::new_v4(),
148 module: Module::Community,
149 enabled_at: Utc::now(),
150 archived_at: None,
151 };
152 assert!(m.est_actif());
153 m.archived_at = Some(Utc::now());
154 assert!(!m.est_actif());
155 }
156}