use mako_engine::types::Pruefidentifikator;
use mako_engine::{
error::WorkflowError,
types::{BillingPeriod, MarktpartnerCode, MessageRef},
workflow::{CommandPayload, EventPayload, Workflow, WorkflowOutput},
};
pub const CLEARINGLISTE_PIDS: &[u32] = &[55067, 55069, 55070, 55073];
pub const WORKFLOW_NAME: &str = "mabis-clearingliste";
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ClearinglisteKind {
Bilanzkreiszuordnungsliste,
ClearinglisteDzr,
ClearinglisteBas,
Profildefinitionen,
}
impl ClearinglisteKind {
#[must_use]
pub fn from_pid(pid: u32) -> Option<Self> {
match pid {
55067 => Some(Self::Bilanzkreiszuordnungsliste),
55069 => Some(Self::ClearinglisteDzr),
55070 => Some(Self::ClearinglisteBas),
55073 => Some(Self::Profildefinitionen),
_ => None,
}
}
#[must_use]
pub fn process_name(self) -> &'static str {
match self {
Self::Bilanzkreiszuordnungsliste => "Bilanzkreiszuordnungsliste",
Self::ClearinglisteDzr => "Clearingliste DZR",
Self::ClearinglisteBas => "Clearingliste BAS",
Self::Profildefinitionen => "Liste der Profildefinitionen",
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct ClearinglisteData {
pub pruefidentifikator: Pruefidentifikator,
pub kind: ClearinglisteKind,
pub sender: MarktpartnerCode,
pub receiver: MarktpartnerCode,
pub billing_period: BillingPeriod,
pub document_date: String,
pub message_ref: MessageRef,
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", content = "data")]
pub enum ClearinglisteEvent {
ClearinglisteErhalten {
pruefidentifikator: Pruefidentifikator,
kind: ClearinglisteKind,
sender: MarktpartnerCode,
receiver: MarktpartnerCode,
billing_period: BillingPeriod,
document_date: String,
message_ref: MessageRef,
},
ValidationPassed {
message_ref: MessageRef,
},
ValidationFailed {
reason: String,
},
}
impl EventPayload for ClearinglisteEvent {
fn event_type(&self) -> &'static str {
match self {
Self::ClearinglisteErhalten { .. } => "MabisClearinglisteErhalten",
Self::ValidationPassed { .. } => "MabisClearinglisteValidationPassed",
Self::ValidationFailed { .. } => "MabisClearinglisteValidationFailed",
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(tag = "status", content = "data")]
#[derive(Default)]
pub enum ClearinglisteState {
#[default]
New,
Erhalten(ClearinglisteData),
ValidationPassed(ClearinglisteData),
ValidationFailed {
reason: String,
},
}
impl ClearinglisteState {
#[must_use]
pub fn label(&self) -> &'static str {
match self {
Self::New => "New",
Self::Erhalten(_) => "Erhalten",
Self::ValidationPassed(_) => "ValidationPassed",
Self::ValidationFailed { .. } => "ValidationFailed",
}
}
}
#[derive(Clone)]
pub enum ClearinglisteCommand {
ReceiveClearingliste {
pid: Pruefidentifikator,
sender: MarktpartnerCode,
receiver: MarktpartnerCode,
billing_period: BillingPeriod,
document_date: String,
message_ref: MessageRef,
validation_passed: bool,
validation_errors: Vec<String>,
},
}
impl CommandPayload for ClearinglisteCommand {}
pub struct MabisClearinglisteWorkflow;
impl Workflow for MabisClearinglisteWorkflow {
type State = ClearinglisteState;
type Event = ClearinglisteEvent;
type Command = ClearinglisteCommand;
fn apply(state: Self::State, event: &Self::Event) -> Self::State {
match event {
ClearinglisteEvent::ClearinglisteErhalten {
pruefidentifikator,
kind,
sender,
receiver,
billing_period,
document_date,
message_ref,
} => ClearinglisteState::Erhalten(ClearinglisteData {
pruefidentifikator: *pruefidentifikator,
kind: *kind,
sender: sender.clone(),
receiver: receiver.clone(),
billing_period: billing_period.clone(),
document_date: document_date.clone(),
message_ref: message_ref.clone(),
}),
ClearinglisteEvent::ValidationPassed { .. } => match state {
ClearinglisteState::Erhalten(data) => ClearinglisteState::ValidationPassed(data),
other => other,
},
ClearinglisteEvent::ValidationFailed { reason } => {
ClearinglisteState::ValidationFailed {
reason: reason.clone(),
}
}
}
}
fn handle(
state: &Self::State,
command: Self::Command,
) -> Result<WorkflowOutput<Self::Event>, WorkflowError> {
match command {
ClearinglisteCommand::ReceiveClearingliste {
pid,
sender,
receiver,
billing_period,
document_date,
message_ref,
validation_passed,
validation_errors,
} => {
if !matches!(state, ClearinglisteState::New) {
return Err(WorkflowError::invalid_state("New", state.label()));
}
let kind = ClearinglisteKind::from_pid(pid.as_u32()).ok_or_else(|| {
WorkflowError::rejected(format!(
"PID {pid} is not a handled Clearingliste PID \
(erwartet 55067, 55069, 55070 oder 55073; \
55065 gehört zu mabis-listenabgleich)"
))
})?;
let mut events = vec![ClearinglisteEvent::ClearinglisteErhalten {
pruefidentifikator: pid,
kind,
sender,
receiver,
billing_period,
document_date,
message_ref: message_ref.clone(),
}];
if validation_passed {
events.push(ClearinglisteEvent::ValidationPassed { message_ref });
} else {
events.push(ClearinglisteEvent::ValidationFailed {
reason: validation_errors.join("; "),
});
}
Ok(events.into())
}
}
}
}