datasynth_core/models/compliance/
jurisdiction.rs1use std::collections::HashMap;
4
5use serde::{Deserialize, Serialize};
6
7use super::standard_id::StandardId;
8use crate::models::graph_properties::{GraphPropertyValue, ToNodeProperties};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "snake_case")]
13pub enum SupranationalBody {
14 Eu,
16 Eea,
18 Eurozone,
20 Asean,
22 Gcc,
24 Mercosur,
26}
27
28impl std::fmt::Display for SupranationalBody {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Self::Eu => write!(f, "EU"),
32 Self::Eea => write!(f, "EEA"),
33 Self::Eurozone => write!(f, "Eurozone"),
34 Self::Asean => write!(f, "ASEAN"),
35 Self::Gcc => write!(f, "GCC"),
36 Self::Mercosur => write!(f, "Mercosur"),
37 }
38 }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
43#[serde(rename_all = "snake_case")]
44pub enum JurisdictionAccountingFramework {
45 UsGaap,
47 Ifrs,
49 IfrsConverged,
51 LocalGaapWithIfrs,
53 LocalGaap,
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59#[serde(rename_all = "snake_case")]
60pub enum AuditFramework {
61 Isa,
63 IsaLocal,
65 Pcaob,
67 LocalIsaBased,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
73#[serde(rename_all = "snake_case")]
74pub enum EntityType {
75 SecRegistrant,
77 AcceleratedFiler,
79 LargeAcceleratedFiler,
81 PublicInterestEntity,
83 ListedEntity,
85 LargeEntity,
87 Sme,
89 MicroEntity,
91 FinancialInstitution,
93}
94
95impl std::fmt::Display for EntityType {
96 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97 match self {
98 Self::SecRegistrant => write!(f, "SEC Registrant"),
99 Self::AcceleratedFiler => write!(f, "Accelerated Filer"),
100 Self::LargeAcceleratedFiler => write!(f, "Large Accelerated Filer"),
101 Self::PublicInterestEntity => write!(f, "Public Interest Entity"),
102 Self::ListedEntity => write!(f, "Listed Entity"),
103 Self::LargeEntity => write!(f, "Large Entity"),
104 Self::Sme => write!(f, "SME"),
105 Self::MicroEntity => write!(f, "Micro Entity"),
106 Self::FinancialInstitution => write!(f, "Financial Institution"),
107 }
108 }
109}
110
111#[derive(Debug, Clone, Serialize, Deserialize)]
113pub struct JurisdictionStandard {
114 pub standard_id: StandardId,
116 pub local_effective_date: Option<String>,
118 pub local_designation: Option<String>,
120 pub applicability: Vec<EntityType>,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct JurisdictionProfile {
127 pub country_code: String,
129 pub country_name: String,
131 pub memberships: Vec<SupranationalBody>,
133 pub accounting_framework: JurisdictionAccountingFramework,
135 pub audit_framework: AuditFramework,
137 pub accounting_standards_body: String,
139 pub audit_oversight_body: String,
141 pub securities_regulator: Option<String>,
143 pub stock_exchanges: Vec<String>,
145 pub mandatory_standards: Vec<JurisdictionStandard>,
147 pub corporate_tax_rate: Option<f64>,
149 pub currency: String,
151 pub ifrs_required_for_listed: bool,
153 pub e_invoicing_mandatory: bool,
155 pub audit_export_format: Option<String>,
157}
158
159impl JurisdictionProfile {
160 pub fn new(
162 country_code: impl Into<String>,
163 country_name: impl Into<String>,
164 accounting_framework: JurisdictionAccountingFramework,
165 audit_framework: AuditFramework,
166 currency: impl Into<String>,
167 ) -> Self {
168 Self {
169 country_code: country_code.into(),
170 country_name: country_name.into(),
171 memberships: Vec::new(),
172 accounting_framework,
173 audit_framework,
174 accounting_standards_body: String::new(),
175 audit_oversight_body: String::new(),
176 securities_regulator: None,
177 stock_exchanges: Vec::new(),
178 mandatory_standards: Vec::new(),
179 corporate_tax_rate: None,
180 currency: currency.into(),
181 ifrs_required_for_listed: false,
182 e_invoicing_mandatory: false,
183 audit_export_format: None,
184 }
185 }
186
187 pub fn is_eu_member(&self) -> bool {
189 self.memberships.contains(&SupranationalBody::Eu)
190 }
191
192 pub fn is_eurozone(&self) -> bool {
194 self.memberships.contains(&SupranationalBody::Eurozone)
195 }
196
197 pub fn with_membership(mut self, body: SupranationalBody) -> Self {
199 self.memberships.push(body);
200 self
201 }
202
203 pub fn with_mandatory_standard(mut self, js: JurisdictionStandard) -> Self {
205 self.mandatory_standards.push(js);
206 self
207 }
208}
209
210impl ToNodeProperties for JurisdictionProfile {
211 fn node_type_name(&self) -> &'static str {
212 "jurisdiction_profile"
213 }
214 fn node_type_code(&self) -> u16 {
215 513
216 }
217 fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
218 let mut p = HashMap::new();
219 p.insert(
220 "countryCode".into(),
221 GraphPropertyValue::String(self.country_code.clone()),
222 );
223 p.insert(
224 "countryName".into(),
225 GraphPropertyValue::String(self.country_name.clone()),
226 );
227 p.insert(
228 "accountingFramework".into(),
229 GraphPropertyValue::String(format!("{:?}", self.accounting_framework)),
230 );
231 p.insert(
232 "auditFramework".into(),
233 GraphPropertyValue::String(format!("{:?}", self.audit_framework)),
234 );
235 p.insert(
236 "currency".into(),
237 GraphPropertyValue::String(self.currency.clone()),
238 );
239 if let Some(rate) = self.corporate_tax_rate {
240 p.insert("corporateTaxRate".into(), GraphPropertyValue::Float(rate));
241 }
242 p.insert(
243 "mandatoryStandardCount".into(),
244 GraphPropertyValue::Int(self.mandatory_standards.len() as i64),
245 );
246 p.insert(
247 "isEuMember".into(),
248 GraphPropertyValue::Bool(self.is_eu_member()),
249 );
250 p.insert(
251 "ifrsRequiredForListed".into(),
252 GraphPropertyValue::Bool(self.ifrs_required_for_listed),
253 );
254 if !self.memberships.is_empty() {
255 p.insert(
256 "memberships".into(),
257 GraphPropertyValue::StringList(
258 self.memberships.iter().map(|m| m.to_string()).collect(),
259 ),
260 );
261 }
262 if !self.stock_exchanges.is_empty() {
263 p.insert(
264 "stockExchanges".into(),
265 GraphPropertyValue::StringList(self.stock_exchanges.clone()),
266 );
267 }
268 p
269 }
270}
271
272#[cfg(test)]
273mod tests {
274 use super::*;
275
276 #[test]
277 fn test_jurisdiction_profile_creation() {
278 let profile = JurisdictionProfile::new(
279 "DE",
280 "Federal Republic of Germany",
281 JurisdictionAccountingFramework::LocalGaapWithIfrs,
282 AuditFramework::IsaLocal,
283 "EUR",
284 )
285 .with_membership(SupranationalBody::Eu)
286 .with_membership(SupranationalBody::Eurozone);
287
288 assert!(profile.is_eu_member());
289 assert!(profile.is_eurozone());
290 assert_eq!(profile.country_code, "DE");
291 }
292}