#[cfg(test)]
mod test_from_schema;
use chrono::{Duration, NaiveDate, NaiveTime, TimeDelta};
use rust_decimal::Decimal;
use super::{v221, Warning};
use crate::{
currency,
duration::Seconds,
energy::{Kw, Kwh},
money::VatOrigin,
number::FromDecimal as _,
schema, string,
tariff::v2x,
warning::{self, GatherWarnings as _, IntoCaveat as _, IntoInfallible as _},
FromSchema, Money, Verdict, Weekday,
};
#[derive(Debug)]
pub(crate) struct Tariff<'buf> {
pub id: string::CiMaxLen<'buf, 36>,
pub currency: currency::Code,
pub elements: Vec<Element>,
}
#[derive(Debug)]
pub(crate) struct Element {
pub price_components: Vec<PriceComponent>,
pub restrictions: Option<Restrictions>,
}
#[derive(Debug)]
pub(crate) struct PriceComponent {
pub dimension_type: v2x::DimensionType,
pub price: Money,
pub step_size: u64,
}
#[derive(Debug)]
pub(crate) struct Restrictions {
start_time: Option<NaiveTime>,
end_time: Option<NaiveTime>,
start_date: Option<NaiveDate>,
end_date: Option<NaiveDate>,
min_kwh: Option<Kwh>,
max_kwh: Option<Kwh>,
min_power: Option<Kw>,
max_power: Option<Kw>,
min_duration: Option<Duration>,
max_duration: Option<Duration>,
day_of_week: Option<Vec<Weekday>>,
}
impl<'a> From<Tariff<'a>> for v221::Tariff<'a> {
fn from(tariff: Tariff<'a>) -> Self {
let Tariff {
id,
currency,
elements,
} = tariff;
let elements = elements.into_iter().map(v221::Element::from).collect();
v221::Tariff {
party_id: None,
id,
currency,
min_price: None,
max_price: None,
start_date_time: None,
end_date_time: None,
elements,
}
}
}
impl From<Element> for v221::Element {
fn from(element: Element) -> Self {
let Element {
price_components,
restrictions,
} = element;
v221::Element {
price_components: price_components
.into_iter()
.map(v221::PriceComponent::from)
.collect(),
restrictions: restrictions.map(v221::Restrictions::from),
}
}
}
impl From<PriceComponent> for v221::PriceComponent {
fn from(value: PriceComponent) -> Self {
let PriceComponent {
dimension_type,
price,
step_size,
} = value;
v221::PriceComponent {
dimension_type,
vat: VatOrigin::Unknown,
price,
step_size,
}
}
}
impl From<Restrictions> for v221::Restrictions {
fn from(restrictions: Restrictions) -> Self {
let Restrictions {
start_time,
end_time,
start_date,
end_date,
min_kwh,
max_kwh,
min_power,
max_power,
min_duration,
max_duration,
day_of_week,
} = restrictions;
v221::Restrictions {
start_time,
end_time,
start_date,
end_date,
min_kwh,
max_kwh,
min_current: None,
max_current: None,
min_power,
max_power,
min_duration,
max_duration,
day_of_week,
reservation: None,
}
}
}
impl<'buf> FromSchema<'buf, schema::v211::Tariff<'buf>> for Tariff<'buf> {
type Warning = Warning;
fn from_schema(source: &schema::v211::Tariff<'buf>) -> Verdict<Self, Self::Warning> {
let mut warnings = warning::Set::new();
let currency = warnings.ok_or_bail(&source.currency)?;
let currency = currency::Code::from_schema(currency)?.gather_warnings_into(&mut warnings);
let id = warnings.ok_or_bail(&source.id)?;
let id = string::CiMaxLen::<'_, 36>::from_schema(id)?.gather_warnings_into(&mut warnings);
let elements = warnings.ok_or_bail(&source.elements)?;
let mut lowered = Vec::with_capacity(elements.len());
for element in elements {
let element = warnings.ok_or_bail(element)?;
lowered.push(Element::from_schema(element)?.gather_warnings_into(&mut warnings));
}
let tariff = Tariff {
currency,
id,
elements: lowered,
};
Ok(tariff.into_caveat(warnings))
}
}
impl<'buf> FromSchema<'buf, schema::v211::Element<'buf>> for Element {
type Warning = Warning;
fn from_schema(source: &schema::v211::Element<'buf>) -> Verdict<Self, Self::Warning> {
let mut warnings = warning::Set::new();
let components = warnings.ok_or_bail(&source.price_components)?;
let mut price_components = Vec::with_capacity(components.len());
for component in components {
let component = warnings.ok_or_bail(component)?;
let component = Option::<PriceComponent>::from_schema(component)?
.gather_warnings_into(&mut warnings);
if let Some(component) = component {
price_components.push(component);
}
}
let restrictions = warnings.ok_or_bail(&source.restrictions)?;
let restrictions = restrictions
.as_ref()
.map(Restrictions::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let elem = Element {
price_components,
restrictions,
};
Ok(elem.into_caveat(warnings))
}
}
impl<'buf> FromSchema<'buf, schema::v211::PriceComponent<'buf>> for Option<PriceComponent> {
type Warning = Warning;
fn from_schema(source: &schema::v211::PriceComponent<'buf>) -> Verdict<Self, Self::Warning> {
let mut warnings = warning::Set::new();
if let schema::Integrity::Err(_) = &source.dimension_type {
return Ok(None.into_caveat(warnings));
}
let dimension_type = warnings.ok_or_bail(&source.dimension_type)?;
let dimension_type =
v2x::DimensionType::from_schema(&dimension_type.value()).into_infallible();
let price = warnings.ok_or_bail(&source.price)?;
let price = Decimal::from_schema(price)?.gather_warnings_into(&mut warnings);
let step_size = warnings.ok_or_bail(&source.step_size)?;
let step_size = u64::from_schema(step_size)?.gather_warnings_into(&mut warnings);
let comp = PriceComponent {
dimension_type,
price: Money::from_decimal(price),
step_size,
};
Ok(Some(comp).into_caveat(warnings))
}
}
impl<'buf> FromSchema<'buf, schema::v211::Restrictions<'buf>> for Restrictions {
type Warning = Warning;
fn from_schema(source: &schema::v211::Restrictions<'buf>) -> Verdict<Self, Self::Warning> {
let mut warnings = warning::Set::new();
let start_time = warnings.ok_or_bail(&source.start_time)?;
let start_time = start_time
.as_ref()
.map(NaiveTime::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let end_time = warnings.ok_or_bail(&source.end_time)?;
let end_time = end_time
.as_ref()
.map(NaiveTime::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let start_date = warnings.ok_or_bail(&source.start_date)?;
let start_date = start_date
.as_ref()
.map(NaiveDate::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let end_date = warnings.ok_or_bail(&source.end_date)?;
let end_date = end_date
.as_ref()
.map(NaiveDate::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let min_kwh = warnings.ok_or_bail(&source.min_kwh)?;
let min_kwh = min_kwh
.as_ref()
.map(Kwh::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let max_kwh = warnings.ok_or_bail(&source.max_kwh)?;
let max_kwh = max_kwh
.as_ref()
.map(Kwh::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let min_power = warnings.ok_or_bail(&source.min_power)?;
let min_power = min_power
.as_ref()
.map(Kw::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let max_power = warnings.ok_or_bail(&source.max_power)?;
let max_power = max_power
.as_ref()
.map(Kw::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings);
let min_duration = warnings.ok_or_bail(&source.min_duration)?;
let min_duration = min_duration
.as_ref()
.map(Seconds::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings)
.map(TimeDelta::from);
let max_duration = warnings.ok_or_bail(&source.max_duration)?;
let max_duration = max_duration
.as_ref()
.map(Seconds::from_schema)
.transpose()?
.gather_warnings_into(&mut warnings)
.map(TimeDelta::from);
let day_of_week = warnings.ok_or_bail(&source.day_of_week)?;
let day_of_week = match day_of_week {
Some(days) => {
let mut weekdays = Vec::with_capacity(days.len());
for day in days {
let day = warnings.ok_or_bail(day)?;
weekdays.push(Weekday::from_schema(&day.value()).into_infallible());
}
Some(weekdays)
}
None => None,
};
let res = Restrictions {
start_time,
end_time,
start_date,
end_date,
min_kwh,
max_kwh,
min_power,
max_power,
min_duration,
max_duration,
day_of_week,
};
Ok(res.into_caveat(warnings))
}
}