#![allow(clippy::missing_panics_doc, reason = "tests are allowed to panic")]
#![allow(clippy::panic, reason = "tests are allowed to panic")]
use rust_decimal_macros::dec;
use crate::{
cdr, json, price,
price::test::UnwrapReport as _,
tariff,
test::{self},
Version,
};
fn simple_cdr_json(
energy_kwh: f64,
total_cost_excl: f64,
total_cost_incl: f64,
total_energy_cost_excl: f64,
total_energy_cost_incl: f64,
) -> String {
serde_json::json!({
"country_code": "NL",
"party_id": "TDR",
"start_date_time": "2022-01-13T10:00:00Z",
"end_date_time": "2022-01-13T11:00:00Z",
"currency": "EUR",
"tariffs": [],
"cdr_location": { "country": "NLD" },
"charging_periods": [
{
"start_date_time": "2022-01-13T10:00:00Z",
"dimensions": [
{ "type": "ENERGY", "volume": energy_kwh }
]
}
],
"total_cost": { "excl_vat": total_cost_excl, "incl_vat": total_cost_incl },
"total_energy_cost": {
"excl_vat": total_energy_cost_excl,
"incl_vat": total_energy_cost_incl
},
"total_time": 1.0,
"total_energy": energy_kwh,
"last_updated": "2022-01-13T00:00:00Z"
})
.to_string()
}
fn tariff_with_min_price_json() -> String {
serde_json::json!({
"id": "T1",
"country_code": "NL",
"party_id": "TDR",
"currency": "EUR",
"min_price": { "excl_vat": 5.00, "incl_vat": 5.50 },
"elements": [
{
"price_components": [
{ "type": "ENERGY", "price": 0.50, "vat": 10.0, "step_size": 1 }
]
}
],
"last_updated": "2022-01-01T00:00:00Z"
})
.to_string()
}
fn tariff_with_max_price_json() -> String {
serde_json::json!({
"id": "T2",
"country_code": "NL",
"party_id": "TDR",
"currency": "EUR",
"max_price": { "excl_vat": 3.00, "incl_vat": 3.30 },
"elements": [
{
"price_components": [
{ "type": "ENERGY", "price": 0.50, "vat": 10.0, "step_size": 1 }
]
}
],
"last_updated": "2022-01-01T00:00:00Z"
})
.to_string()
}
#[test]
fn should_clamp_total_cost_to_min_price() {
test::setup();
let cdr_json = simple_cdr_json(4.0, 2.00, 2.20, 2.00, 2.20);
let tariff_json = tariff_with_min_price_json();
let (cdr, _) = cdr::build(json::parse_object(&cdr_json).unwrap(), Version::V221).into_parts();
let (tariff, _) =
tariff::build(json::parse_object(&tariff_json).unwrap(), Version::V221).into_parts();
let report = cdr::price(
&cdr,
price::TariffSource::Override(vec![tariff]),
chrono_tz::Tz::UTC,
)
.unwrap_report(cdr.as_json_str());
let (report, warnings) = report.into_parts();
let total_cost = report.total_cost.calculated.unwrap();
assert_eq!(total_cost.excl_vat, dec!(5.00).into());
assert_eq!(total_cost.incl_vat, Some(dec!(5.50).into()));
let id_map = warnings.path_id_map();
let has_warning = id_map
.values()
.flatten()
.any(|id| id.as_str() == "total_cost_clamped_to_min");
assert!(
has_warning,
"expected TotalCostClampedToMin warning, got: {id_map:#?}"
);
}
#[test]
fn should_clamp_total_cost_to_max_price() {
test::setup();
let cdr_json = simple_cdr_json(10.0, 5.00, 5.50, 5.00, 5.50);
let tariff_json = tariff_with_max_price_json();
let (cdr, _) = cdr::build(json::parse_object(&cdr_json).unwrap(), Version::V221).into_parts();
let (tariff, _) =
tariff::build(json::parse_object(&tariff_json).unwrap(), Version::V221).into_parts();
let report = cdr::price(
&cdr,
price::TariffSource::Override(vec![tariff]),
chrono_tz::Tz::UTC,
)
.unwrap_report(cdr.as_json_str());
let (report, warnings) = report.into_parts();
let total_cost = report.total_cost.calculated.unwrap();
assert_eq!(total_cost.excl_vat, dec!(3.00).into());
assert_eq!(total_cost.incl_vat, Some(dec!(3.30).into()));
let id_map = warnings.path_id_map();
let has_warning = id_map
.values()
.flatten()
.any(|id| id.as_str() == "total_cost_clamped_to_max");
assert!(
has_warning,
"expected TotalCostClampedToMax warning, got: {id_map:#?}"
);
}
#[test]
fn should_not_clamp_when_cost_within_bounds() {
test::setup();
let cdr_json = simple_cdr_json(8.0, 4.00, 4.40, 4.00, 4.40);
let tariff_json = serde_json::json!({
"id": "T3",
"country_code": "NL",
"party_id": "TDR",
"currency": "EUR",
"min_price": { "excl_vat": 3.00, "incl_vat": 3.30 },
"max_price": { "excl_vat": 6.00, "incl_vat": 6.60 },
"elements": [
{
"price_components": [
{ "type": "ENERGY", "price": 0.50, "vat": 10.0, "step_size": 1 }
]
}
],
"last_updated": "2022-01-01T00:00:00Z"
})
.to_string();
let (cdr, _) = cdr::build(json::parse_object(&cdr_json).unwrap(), Version::V221).into_parts();
let (tariff, _) =
tariff::build(json::parse_object(&tariff_json).unwrap(), Version::V221).into_parts();
let report = cdr::price(
&cdr,
price::TariffSource::Override(vec![tariff]),
chrono_tz::Tz::UTC,
)
.unwrap_report(cdr.as_json_str());
let (report, warnings) = report.into_parts();
let total_cost = report.total_cost.calculated.unwrap();
assert_eq!(total_cost.excl_vat, dec!(4.00).into());
assert_eq!(total_cost.incl_vat, Some(dec!(4.40).into()));
let id_map = warnings.path_id_map();
let has_clamp_warning = id_map.values().flatten().any(|id| {
id.as_str() == "total_cost_clamped_to_min" || id.as_str() == "total_cost_clamped_to_max"
});
assert!(
!has_clamp_warning,
"unexpected clamping warning: {id_map:#?}"
);
}