use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use super::standard_id::StandardId;
use crate::models::graph_properties::{GraphPropertyValue, ToNodeProperties};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SupranationalBody {
Eu,
Eea,
Eurozone,
Asean,
Gcc,
Mercosur,
}
impl std::fmt::Display for SupranationalBody {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Eu => write!(f, "EU"),
Self::Eea => write!(f, "EEA"),
Self::Eurozone => write!(f, "Eurozone"),
Self::Asean => write!(f, "ASEAN"),
Self::Gcc => write!(f, "GCC"),
Self::Mercosur => write!(f, "Mercosur"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum JurisdictionAccountingFramework {
UsGaap,
Ifrs,
IfrsConverged,
LocalGaapWithIfrs,
LocalGaap,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AuditFramework {
Isa,
IsaLocal,
Pcaob,
LocalIsaBased,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum EntityType {
SecRegistrant,
AcceleratedFiler,
LargeAcceleratedFiler,
PublicInterestEntity,
ListedEntity,
LargeEntity,
Sme,
MicroEntity,
FinancialInstitution,
}
impl std::fmt::Display for EntityType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::SecRegistrant => write!(f, "SEC Registrant"),
Self::AcceleratedFiler => write!(f, "Accelerated Filer"),
Self::LargeAcceleratedFiler => write!(f, "Large Accelerated Filer"),
Self::PublicInterestEntity => write!(f, "Public Interest Entity"),
Self::ListedEntity => write!(f, "Listed Entity"),
Self::LargeEntity => write!(f, "Large Entity"),
Self::Sme => write!(f, "SME"),
Self::MicroEntity => write!(f, "Micro Entity"),
Self::FinancialInstitution => write!(f, "Financial Institution"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JurisdictionStandard {
pub standard_id: StandardId,
pub local_effective_date: Option<String>,
pub local_designation: Option<String>,
pub applicability: Vec<EntityType>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JurisdictionProfile {
pub country_code: String,
pub country_name: String,
pub memberships: Vec<SupranationalBody>,
pub accounting_framework: JurisdictionAccountingFramework,
pub audit_framework: AuditFramework,
pub accounting_standards_body: String,
pub audit_oversight_body: String,
pub securities_regulator: Option<String>,
pub stock_exchanges: Vec<String>,
pub mandatory_standards: Vec<JurisdictionStandard>,
pub corporate_tax_rate: Option<f64>,
pub currency: String,
pub ifrs_required_for_listed: bool,
pub e_invoicing_mandatory: bool,
pub audit_export_format: Option<String>,
}
impl JurisdictionProfile {
pub fn new(
country_code: impl Into<String>,
country_name: impl Into<String>,
accounting_framework: JurisdictionAccountingFramework,
audit_framework: AuditFramework,
currency: impl Into<String>,
) -> Self {
Self {
country_code: country_code.into(),
country_name: country_name.into(),
memberships: Vec::new(),
accounting_framework,
audit_framework,
accounting_standards_body: String::new(),
audit_oversight_body: String::new(),
securities_regulator: None,
stock_exchanges: Vec::new(),
mandatory_standards: Vec::new(),
corporate_tax_rate: None,
currency: currency.into(),
ifrs_required_for_listed: false,
e_invoicing_mandatory: false,
audit_export_format: None,
}
}
pub fn is_eu_member(&self) -> bool {
self.memberships.contains(&SupranationalBody::Eu)
}
pub fn is_eurozone(&self) -> bool {
self.memberships.contains(&SupranationalBody::Eurozone)
}
pub fn with_membership(mut self, body: SupranationalBody) -> Self {
self.memberships.push(body);
self
}
pub fn with_mandatory_standard(mut self, js: JurisdictionStandard) -> Self {
self.mandatory_standards.push(js);
self
}
}
impl ToNodeProperties for JurisdictionProfile {
fn node_type_name(&self) -> &'static str {
"jurisdiction_profile"
}
fn node_type_code(&self) -> u16 {
513
}
fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
let mut p = HashMap::new();
p.insert(
"countryCode".into(),
GraphPropertyValue::String(self.country_code.clone()),
);
p.insert(
"countryName".into(),
GraphPropertyValue::String(self.country_name.clone()),
);
p.insert(
"accountingFramework".into(),
GraphPropertyValue::String(format!("{:?}", self.accounting_framework)),
);
p.insert(
"auditFramework".into(),
GraphPropertyValue::String(format!("{:?}", self.audit_framework)),
);
p.insert(
"currency".into(),
GraphPropertyValue::String(self.currency.clone()),
);
if let Some(rate) = self.corporate_tax_rate {
p.insert("corporateTaxRate".into(), GraphPropertyValue::Float(rate));
}
p.insert(
"mandatoryStandardCount".into(),
GraphPropertyValue::Int(self.mandatory_standards.len() as i64),
);
p.insert(
"isEuMember".into(),
GraphPropertyValue::Bool(self.is_eu_member()),
);
p.insert(
"ifrsRequiredForListed".into(),
GraphPropertyValue::Bool(self.ifrs_required_for_listed),
);
if !self.memberships.is_empty() {
p.insert(
"memberships".into(),
GraphPropertyValue::StringList(
self.memberships.iter().map(|m| m.to_string()).collect(),
),
);
}
if !self.stock_exchanges.is_empty() {
p.insert(
"stockExchanges".into(),
GraphPropertyValue::StringList(self.stock_exchanges.clone()),
);
}
p
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_jurisdiction_profile_creation() {
let profile = JurisdictionProfile::new(
"DE",
"Federal Republic of Germany",
JurisdictionAccountingFramework::LocalGaapWithIfrs,
AuditFramework::IsaLocal,
"EUR",
)
.with_membership(SupranationalBody::Eu)
.with_membership(SupranationalBody::Eurozone);
assert!(profile.is_eu_member());
assert!(profile.is_eurozone());
assert_eq!(profile.country_code, "DE");
}
}