use mako_engine::types::Pruefidentifikator;
use mako_engine::{
error::WorkflowError,
types::{MarktpartnerCode, MessageRef},
workflow::{CommandPayload, EventPayload, Workflow, WorkflowOutput},
};
pub const WORKFLOW_NAME: &str = "gpke-partin";
pub const PARTIN_STROM_PIDS: &[u32] = &[37000, 37001, 37002, 37003, 37004, 37005, 37006];
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct KommunikationsdatenData {
pub pruefidentifikator: Pruefidentifikator,
pub sender: MarktpartnerCode,
pub document_date: String,
pub message_ref: MessageRef,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum KommunikationsdatenEvent {
PartinErhalten {
pruefidentifikator: Pruefidentifikator,
sender: MarktpartnerCode,
document_date: String,
message_ref: MessageRef,
},
ValidationPassed {
message_ref: MessageRef,
},
ValidationFailed {
reason: String,
},
}
impl EventPayload for KommunikationsdatenEvent {
fn event_type(&self) -> &'static str {
match self {
Self::PartinErhalten { .. } => "KommunikationsdatenPartinErhalten",
Self::ValidationPassed { .. } => "KommunikationsdatenValidationPassed",
Self::ValidationFailed { .. } => "KommunikationsdatenValidationFailed",
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "status", content = "data")]
#[derive(Default)]
pub enum KommunikationsdatenState {
#[default]
New,
PartinErhalten(KommunikationsdatenData),
ValidationPassed(KommunikationsdatenData),
ValidationFailed {
reason: String,
},
}
impl KommunikationsdatenState {
#[must_use]
pub fn label(&self) -> &'static str {
match self {
Self::New => "New",
Self::PartinErhalten(_) => "PartinErhalten",
Self::ValidationPassed(_) => "ValidationPassed",
Self::ValidationFailed { .. } => "ValidationFailed",
}
}
}
#[derive(Clone)]
pub enum KommunikationsdatenCommand {
ReceivePartin {
pid: Pruefidentifikator,
sender: MarktpartnerCode,
document_date: String,
message_ref: MessageRef,
validation_passed: bool,
validation_errors: Vec<String>,
},
}
impl CommandPayload for KommunikationsdatenCommand {}
pub struct GpkePartinWorkflow;
impl Workflow for GpkePartinWorkflow {
type State = KommunikationsdatenState;
type Event = KommunikationsdatenEvent;
type Command = KommunikationsdatenCommand;
fn apply(state: Self::State, event: &Self::Event) -> Self::State {
match event {
KommunikationsdatenEvent::PartinErhalten {
pruefidentifikator,
sender,
document_date,
message_ref,
} => KommunikationsdatenState::PartinErhalten(KommunikationsdatenData {
pruefidentifikator: *pruefidentifikator,
sender: sender.clone(),
document_date: document_date.clone(),
message_ref: message_ref.clone(),
}),
KommunikationsdatenEvent::ValidationPassed { .. } => match state {
KommunikationsdatenState::PartinErhalten(data) => {
KommunikationsdatenState::ValidationPassed(data)
}
other => other,
},
KommunikationsdatenEvent::ValidationFailed { reason } => {
KommunikationsdatenState::ValidationFailed {
reason: reason.clone(),
}
}
}
}
fn handle(
state: &Self::State,
command: Self::Command,
) -> Result<WorkflowOutput<Self::Event>, WorkflowError> {
match command {
KommunikationsdatenCommand::ReceivePartin {
pid,
sender,
document_date,
message_ref,
validation_passed,
validation_errors,
} => {
if !matches!(state, KommunikationsdatenState::New) {
return Err(WorkflowError::invalid_state("New", state.label()));
}
if !PARTIN_STROM_PIDS.contains(&pid.as_u32()) {
return Err(WorkflowError::rejected(format!(
"PID {pid} is not a Strom PARTIN PID (37000–37006); Gas PARTIN (37008–37014) is handled by mako-geli-gas",
)));
}
let mut events = vec![KommunikationsdatenEvent::PartinErhalten {
pruefidentifikator: pid,
sender,
document_date,
message_ref: message_ref.clone(),
}];
if validation_passed {
events.push(KommunikationsdatenEvent::ValidationPassed { message_ref });
} else {
events.push(KommunikationsdatenEvent::ValidationFailed {
reason: validation_errors.join("; "),
});
}
Ok(events.into())
}
}
}
}