use mako_engine::types::Pruefidentifikator;
use mako_engine::{
error::WorkflowError,
outbox::PendingOutbox,
types::{MaLo, MarktpartnerCode, MessageRef},
workflow::{CommandPayload, EventPayload, Workflow, WorkflowOutput},
};
pub const WORKFLOW_NAME: &str = "gpke-messwerte";
pub const MSCONS_PIDS: &[u32] = &[
13005, 13006, 13015, 13016, 13017, 13018, 13019, 13025, 13027,
];
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct MesswerteLieferungData {
pub pruefidentifikator: Pruefidentifikator,
pub sender: MarktpartnerCode,
pub location_id: MaLo,
pub document_date: String,
pub message_ref: MessageRef,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum MesswerteLieferungEvent {
MsconsDatenErhalten {
pruefidentifikator: Pruefidentifikator,
sender: MarktpartnerCode,
location_id: MaLo,
document_date: String,
message_ref: MessageRef,
},
ValidationPassed {
message_ref: MessageRef,
},
ValidationFailed {
reason: String,
},
}
impl EventPayload for MesswerteLieferungEvent {
fn event_type(&self) -> &'static str {
match self {
Self::MsconsDatenErhalten { .. } => "MesswerteLieferungErhalten",
Self::ValidationPassed { .. } => "MesswerteLieferungValidationPassed",
Self::ValidationFailed { .. } => "MesswerteLieferungValidationFailed",
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "status", content = "data")]
#[derive(Default)]
pub enum MesswerteLieferungState {
#[default]
New,
DatenErhalten(MesswerteLieferungData),
ValidationPassed(MesswerteLieferungData),
ValidationFailed {
reason: String,
},
}
impl MesswerteLieferungState {
#[must_use]
pub fn label(&self) -> &'static str {
match self {
Self::New => "New",
Self::DatenErhalten(_) => "DatenErhalten",
Self::ValidationPassed(_) => "ValidationPassed",
Self::ValidationFailed { .. } => "ValidationFailed",
}
}
}
#[derive(Clone)]
pub enum MesswerteLieferungCommand {
ReceiveMscons {
pid: Pruefidentifikator,
sender: MarktpartnerCode,
location_id: MaLo,
document_date: String,
message_ref: MessageRef,
validation_passed: bool,
validation_errors: Vec<String>,
},
}
impl CommandPayload for MesswerteLieferungCommand {}
pub struct GpkeMesswerteLieferungWorkflow;
impl Workflow for GpkeMesswerteLieferungWorkflow {
type State = MesswerteLieferungState;
type Event = MesswerteLieferungEvent;
type Command = MesswerteLieferungCommand;
fn apply(state: Self::State, event: &Self::Event) -> Self::State {
match event {
MesswerteLieferungEvent::MsconsDatenErhalten {
pruefidentifikator,
sender,
location_id,
document_date,
message_ref,
} => MesswerteLieferungState::DatenErhalten(MesswerteLieferungData {
pruefidentifikator: *pruefidentifikator,
sender: sender.clone(),
location_id: location_id.clone(),
document_date: document_date.clone(),
message_ref: message_ref.clone(),
}),
MesswerteLieferungEvent::ValidationPassed { .. } => match state {
MesswerteLieferungState::DatenErhalten(data) => {
MesswerteLieferungState::ValidationPassed(data)
}
other => other,
},
MesswerteLieferungEvent::ValidationFailed { reason } => {
MesswerteLieferungState::ValidationFailed {
reason: reason.clone(),
}
}
}
}
fn handle(
state: &Self::State,
command: Self::Command,
) -> Result<WorkflowOutput<Self::Event>, WorkflowError> {
match command {
MesswerteLieferungCommand::ReceiveMscons {
pid,
sender,
location_id,
document_date,
message_ref,
validation_passed,
validation_errors,
} => {
if !matches!(state, MesswerteLieferungState::New) {
return Err(WorkflowError::invalid_state("New", state.label()));
}
if !MSCONS_PIDS.contains(&pid.as_u32()) {
return Err(WorkflowError::rejected(format!(
"PID {pid} is not a handled MSCONS PID",
)));
}
let mut events = vec![MesswerteLieferungEvent::MsconsDatenErhalten {
pruefidentifikator: pid,
sender,
location_id,
document_date,
message_ref: message_ref.clone(),
}];
let outbox = if validation_passed {
events.push(MesswerteLieferungEvent::ValidationPassed { message_ref });
vec![
PendingOutbox::new(
"ProcessCompleted",
"",
serde_json::json!({ "pid": pid.as_u32() }),
)
.caused_by(1),
]
} else {
events.push(MesswerteLieferungEvent::ValidationFailed {
reason: validation_errors.join("; "),
});
vec![]
};
Ok(WorkflowOutput::with_outbox(events, outbox))
}
}
}
}