#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum AggregationRule {
Sum {
source_malo_ids: Vec<String>,
},
Residual {
total_malo_id: String,
subtract_malo_ids: Vec<String>,
},
PvSelfConsumption {
grid_malo_id: String,
generation_malo_id: String,
},
GgvAllocation {
plant_malo_id: String,
tenant_fractions: Vec<(String, rust_decimal::Decimal)>,
},
}
impl AggregationRule {
#[must_use]
pub fn source_malo_ids(&self) -> Vec<&str> {
match self {
Self::Sum { source_malo_ids } => source_malo_ids.iter().map(String::as_str).collect(),
Self::Residual {
total_malo_id,
subtract_malo_ids,
} => {
let mut ids = vec![total_malo_id.as_str()];
ids.extend(subtract_malo_ids.iter().map(String::as_str));
ids
}
Self::PvSelfConsumption {
grid_malo_id,
generation_malo_id,
} => vec![grid_malo_id.as_str(), generation_malo_id.as_str()],
Self::GgvAllocation {
plant_malo_id,
tenant_fractions,
} => {
let mut ids = vec![plant_malo_id.as_str()];
ids.extend(tenant_fractions.iter().map(|(m, _)| m.as_str()));
ids
}
}
}
#[must_use]
pub fn rule_type(&self) -> &'static str {
match self {
Self::Sum { .. } => "Sum",
Self::Residual { .. } => "Residual",
Self::PvSelfConsumption { .. } => "PvSelfConsumption",
Self::GgvAllocation { .. } => "GgvAllocation",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use rust_decimal_macros::dec;
#[test]
fn sum_rule_lists_all_sources() {
let rule = AggregationRule::Sum {
source_malo_ids: vec!["MALO_A".to_owned(), "MALO_B".to_owned()],
};
let sources = rule.source_malo_ids();
assert_eq!(sources, vec!["MALO_A", "MALO_B"]);
assert_eq!(rule.rule_type(), "Sum");
}
#[test]
fn residual_rule_includes_total_and_subtracts() {
let rule = AggregationRule::Residual {
total_malo_id: "TOTAL".to_owned(),
subtract_malo_ids: vec!["PV".to_owned()],
};
let sources = rule.source_malo_ids();
assert!(sources.contains(&"TOTAL"));
assert!(sources.contains(&"PV"));
assert_eq!(rule.rule_type(), "Residual");
}
#[test]
fn ggv_lists_plant_and_tenants() {
let rule = AggregationRule::GgvAllocation {
plant_malo_id: "PLANT".to_owned(),
tenant_fractions: vec![
("TENANT_A".to_owned(), dec!(0.4)),
("TENANT_B".to_owned(), dec!(0.3)),
],
};
let sources = rule.source_malo_ids();
assert_eq!(sources.len(), 3);
assert!(sources.contains(&"PLANT"));
assert!(sources.contains(&"TENANT_A"));
}
}