use serde::{Deserialize, Serialize};
use super::binding::InstrumentBinding;
use super::currency::CurrencyCheck;
use super::kind::InstrumentKind;
use super::obligation::PassportObligation;
use super::status::InstrumentStatus;
use crate::catalog::granularity::Granularity;
use crate::catalog::retention::RetentionBasis;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Instrument {
pub id: String,
pub title: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub celex: Option<String>,
pub kind: InstrumentKind,
pub status: InstrumentStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub currency: Option<CurrencyCheck>,
pub passport: PassportObligation,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retention_years: Option<u32>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub retention_years_basis: Option<RetentionBasis>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub granularity: Option<Granularity>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub parent: Option<String>,
#[serde(default)]
pub product_groups: Vec<InstrumentBinding>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub notes: Option<String>,
}
impl Instrument {
#[must_use]
pub fn is_current_law(&self) -> bool {
self.status == InstrumentStatus::Adopted
&& self.currency.as_ref().is_some_and(|c| c.state.is_law())
}
#[must_use]
pub fn binding(&self, product_group: &str) -> Option<&InstrumentBinding> {
self.product_groups
.iter()
.find(|b| b.product_group == product_group)
}
#[must_use]
pub fn requires_passport_for(&self, product_group: &str) -> bool {
self.binding(product_group)
.is_some_and(|b| b.requires_passport(&self.passport))
}
#[must_use]
pub fn passport_for(&self, product_group: &str) -> Option<&PassportObligation> {
self.binding(product_group)
.map(|b| b.passport.as_ref().unwrap_or(&self.passport))
}
#[must_use]
pub fn retention_for(&self, product_group: &str) -> Option<(u32, RetentionBasis)> {
let binding = self.binding(product_group)?;
let years = binding.retention_years.or(self.retention_years)?;
let basis = if binding.retention_years.is_some() {
binding.retention_years_basis
} else {
self.retention_years_basis
};
Some((years, basis.unwrap_or(RetentionBasis::Assumed)))
}
#[must_use]
pub fn granularity_for(&self, product_group: &str) -> Option<Granularity> {
let binding = self.binding(product_group)?;
binding.granularity.or(self.granularity)
}
}