#![deny(unsafe_code)]
#![deny(missing_docs)]
#![warn(clippy::pedantic)]
pub mod ack_forward;
pub mod aktivierung;
pub mod router;
pub mod stammdaten;
pub use router::{RedispatchDocumentKind, RedispatchRouter};
use mako_engine::{builder::EngineModule, pid_router::PidRouter, profile::ProfileRequirement};
pub struct RedispatchModule;
impl RedispatchModule {
#[must_use]
pub fn build_router() -> RedispatchRouter {
let mut router = RedispatchRouter::new();
router.register(
RedispatchDocumentKind::Activation,
aktivierung::WORKFLOW_NAME,
);
router.register(
RedispatchDocumentKind::PlannedResourceSchedule,
ack_forward::names::PLANUNGSDATEN,
);
router.register(
RedispatchDocumentKind::Stammdaten,
stammdaten::WORKFLOW_NAME,
);
router.register(
RedispatchDocumentKind::StatusRequest,
ack_forward::names::STATUSANFRAGE,
);
router.register(
RedispatchDocumentKind::Unavailability,
ack_forward::names::VERFUEGBARKEIT,
);
router.register(RedispatchDocumentKind::Kaskade, ack_forward::names::KASKADE);
router.register(
RedispatchDocumentKind::NetworkConstraint,
ack_forward::names::NETZENGPASS,
);
router.register(
RedispatchDocumentKind::Kostenblatt,
ack_forward::names::KOSTENBLATT,
);
router
}
}
impl EngineModule for RedispatchModule {
fn name(&self) -> &'static str {
"redispatch"
}
fn workflow_names(&self) -> &'static [&'static str] {
&[
stammdaten::WORKFLOW_NAME,
aktivierung::WORKFLOW_NAME,
ack_forward::names::VERFUEGBARKEIT,
ack_forward::names::NETZENGPASS,
ack_forward::names::KASKADE,
ack_forward::names::PLANUNGSDATEN,
ack_forward::names::STATUSANFRAGE,
ack_forward::names::KOSTENBLATT,
]
}
fn register_pids(&self, router: &mut PidRouter) {
for &pid in aktivierung::IFTSTA_PIDS {
router.register(pid, aktivierung::WORKFLOW_NAME);
}
for &pid in aktivierung::MSCONS_PIDS {
router.register(pid, aktivierung::WORKFLOW_NAME);
}
for &pid in aktivierung::ORDERS_PIDS {
router.register(pid, aktivierung::WORKFLOW_NAME);
}
for &pid in aktivierung::ORDRSP_PIDS {
router.register(pid, aktivierung::WORKFLOW_NAME);
}
}
fn profile_requirements(&self) -> &'static [ProfileRequirement] {
&[
ProfileRequirement {
message_type: "IFTSTA",
label: "IFTSTA (Redispatch 2.0 Statusmeldungen — PIDs 21035/21036/21037/21038/21040)",
},
ProfileRequirement {
message_type: "MSCONS",
label: "MSCONS Redispatch Ausfallarbeit/EEG (13020–13023, 13026)",
},
ProfileRequirement {
message_type: "ORDERS",
label: "ORDERS Redispatch Ausfallarbeit (17209–17211)",
},
ProfileRequirement {
message_type: "ORDRSP",
label: "ORDRSP Redispatch Abo/Aggregation (19204, 19301–19302)",
},
]
}
fn configure(&self) -> Result<(), String> {
let router = Self::build_router();
for dk in [
RedispatchDocumentKind::Activation,
RedispatchDocumentKind::PlannedResourceSchedule,
RedispatchDocumentKind::Stammdaten,
RedispatchDocumentKind::StatusRequest,
RedispatchDocumentKind::Unavailability,
RedispatchDocumentKind::NetworkConstraint,
RedispatchDocumentKind::Kaskade,
RedispatchDocumentKind::Kostenblatt,
] {
router.route(dk).map_err(|e| format!("redispatch: {e}"))?;
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn build_router_covers_all_primary_doc_types() {
let router = RedispatchModule::build_router();
for dk in [
RedispatchDocumentKind::Activation,
RedispatchDocumentKind::PlannedResourceSchedule,
RedispatchDocumentKind::Stammdaten,
RedispatchDocumentKind::StatusRequest,
RedispatchDocumentKind::Unavailability,
RedispatchDocumentKind::Kaskade,
RedispatchDocumentKind::NetworkConstraint,
RedispatchDocumentKind::Kostenblatt,
] {
assert!(
router.is_registered(dk),
"RedispatchDocumentKind {dk:?} must be registered in RedispatchModule router"
);
}
assert!(
!router.is_registered(RedispatchDocumentKind::Acknowledgement),
"Acknowledgement must not be in the document-kind router"
);
}
#[test]
fn configure_succeeds() {
assert!(RedispatchModule.configure().is_ok());
}
#[test]
fn iftsta_pids_are_correct() {
assert_eq!(aktivierung::IFTSTA_PIDS, &[21_037, 21_038]);
}
#[test]
fn mscons_pids_are_correct() {
assert_eq!(
aktivierung::MSCONS_PIDS,
&[13_020, 13_021, 13_022, 13_023, 13_026]
);
}
#[test]
fn workflow_names_are_non_empty() {
assert!(!RedispatchModule.workflow_names().is_empty());
for name in RedispatchModule.workflow_names() {
assert!(
name.starts_with("redispatch-"),
"workflow name '{name}' must start with 'redispatch-'"
);
}
}
}