use chrono::{DateTime, NaiveDate, Utc};
use serde::{Deserialize, Serialize};
use crate::domain::gtin::Gtin;
use crate::domain::sector::enums::{
BatteryChemistry, BatteryStatus, BatteryType, CarbonFootprintClass,
};
use super::shared::CriticalRawMaterial;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct BatteryData {
pub gtin: Gtin,
pub battery_chemistry: BatteryChemistry,
pub nominal_voltage_v: f64,
pub nominal_capacity_ah: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_lifetime_cycles: Option<u32>,
pub co2e_per_unit_kg: f64,
pub recycled_content_cobalt_pct: Option<f64>,
pub recycled_content_lithium_pct: Option<f64>,
pub recycled_content_nickel_pct: Option<f64>,
pub state_of_health_pct: Option<f64>,
pub rated_capacity_kwh: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub carbon_footprint_class: Option<CarbonFootprintClass>,
#[serde(skip_serializing_if = "Option::is_none")]
pub carbon_footprint_class_ruleset_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub carbon_footprint_class_ruleset_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub due_diligence_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cathode_material: Option<Vec<MaterialComposition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub anode_material: Option<Vec<MaterialComposition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub electrolyte_material: Option<Vec<MaterialComposition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub critical_raw_materials: Option<Vec<CriticalRawMaterial>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub disassembly_instructions_url: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub soh_methodology: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operating_temp_min_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operating_temp_max_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rated_energy_wh: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recycled_content_lead_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub battery_weight_kg: Option<f64>,
pub battery_type: BatteryType,
#[serde(skip_serializing_if = "Option::is_none")]
pub initial_round_trip_efficiency_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub round_trip_efficiency_at_half_cycle_life_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub round_trip_efficiency_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal_resistance_mohm: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal_cell_resistance_mohm: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal_pack_resistance_mohm: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub placed_on_market_date: Option<NaiveDate>,
#[serde(skip_serializing_if = "Option::is_none")]
pub manufacturing_date: Option<DateTime<Utc>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub manufacturing_place: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub battery_model_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub battery_passport_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_lifetime: Option<Box<ExpectedLifetime>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub recycled_content_reporting_year: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state_of_health: Option<Box<StateOfHealth>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hazardous_substances: Option<Vec<HazardousSubstance>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usable_extinguishing_agent: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub renewable_content_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub minimal_voltage_v: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub maximum_voltage_v: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub voltage_temperature_range: Option<TemperatureRange>,
#[serde(skip_serializing_if = "Option::is_none")]
pub original_power_capability_w: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub power_limit_min_w: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub power_limit_max_w: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub power_temperature_range: Option<TemperatureRange>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_lifetime_reference_test: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capacity_threshold_for_exhaustion_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub not_in_use_temperature_range: Option<TemperatureRange>,
#[serde(skip_serializing_if = "Option::is_none")]
pub not_in_use_temperature_reference_test: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub commercial_warranty_period_months: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cycle_life_test_c_rate: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub marking_information: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hazard_symbol: Option<HazardSymbol>,
#[serde(skip_serializing_if = "Option::is_none")]
pub eu_declaration_of_conformity: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub waste_battery_information: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub component_part_numbers: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub spare_parts_contacts: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub safety_measures: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub test_report_results: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dynamic_performance: Option<Box<DynamicPerformance>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub battery_status: Option<BatteryStatus>,
#[serde(skip_serializing_if = "Option::is_none")]
pub usage_history: Option<Box<UsageHistory>>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct TemperatureRange {
pub min_c: f64,
pub max_c: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct HazardousSubstance {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub cas_number: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub concentration_pct: Option<f64>,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "kebab-case")]
#[non_exhaustive]
pub enum HazardSymbol {
Cadmium,
Lead,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct DynamicPerformance {
#[serde(skip_serializing_if = "Option::is_none")]
pub rated_capacity_ah: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub capacity_fade_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub power_w: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub power_fade_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal_resistance_mohm: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub internal_resistance_increase_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub round_trip_efficiency_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub round_trip_efficiency_fade_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_lifetime_cycles: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub expected_lifetime_years: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct UsageHistory {
#[serde(skip_serializing_if = "Option::is_none")]
pub charge_discharge_cycles: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub negative_events: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub operating_conditions: Option<Vec<EnvironmentalReading>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state_of_charge: Option<Vec<StateOfChargeReading>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct EnvironmentalReading {
pub recorded_at: DateTime<Utc>,
#[serde(skip_serializing_if = "Option::is_none")]
pub temperature_c: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
#[non_exhaustive]
pub struct StateOfChargeReading {
pub recorded_at: DateTime<Utc>,
pub state_of_charge_pct: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(tag = "parameterSet", rename_all = "camelCase")]
pub enum StateOfHealth {
#[serde(rename_all = "camelCase")]
ElectricVehicle {
soce_pct: f64,
},
#[serde(rename_all = "camelCase")]
StationaryOrLmt {
remaining_capacity_pct: f64,
#[serde(skip_serializing_if = "Option::is_none")]
remaining_power_capability_pct: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
remaining_round_trip_efficiency_pct: Option<f64>,
self_discharge_rate_pct_per_month: f64,
#[serde(skip_serializing_if = "Option::is_none")]
ohmic_resistance_mohm: Option<f64>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
#[serde(rename_all = "camelCase")]
pub struct HarmfulEvents {
#[serde(skip_serializing_if = "Option::is_none")]
pub deep_discharge_events: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hours_in_extreme_temperature: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hours_charging_in_extreme_temperature: Option<f64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ExpectedLifetime {
#[serde(skip_serializing_if = "Option::is_none")]
pub put_into_service_date: Option<NaiveDate>,
pub energy_throughput_kwh: f64,
pub capacity_throughput_ah: f64,
pub harmful_events: HarmfulEvents,
pub full_equivalent_cycles: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct MaterialComposition {
pub name: String,
pub weight_pct: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub cas_number: Option<String>,
}