use crate::error::{
require_id, require_non_empty, require_non_empty_slice, require_schema_version,
EffectRuntimeValidationError, EffectValidationResult,
};
use crate::v25::V25ConstitutionCitation;
use crate::vocab::{CompensationClassV1, ExecutionStateV1};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use stack_ids::{CompensationExecutionReceiptId, CompensationPlanId, EffectIntentId};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompensationPlanV1 {
pub schema_version: String,
pub compensation_plan_id: CompensationPlanId,
pub effect_intent_id: EffectIntentId,
#[serde(flatten)]
pub citation: V25ConstitutionCitation,
pub compensation_required: bool,
pub compensation_class: CompensationClassV1,
pub compensation_steps: Vec<String>,
pub success_criteria: Vec<String>,
pub owner_ref: String,
pub latest_start: String,
pub advisory_only: bool,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CompensationExecutionReceiptV1 {
pub schema_version: String,
pub compensation_execution_receipt_id: CompensationExecutionReceiptId,
pub compensation_plan_id: CompensationPlanId,
#[serde(flatten)]
pub citation: V25ConstitutionCitation,
pub execution_state: ExecutionStateV1,
pub completed_steps: Vec<String>,
pub failed_steps: Vec<String>,
pub residual_risk_summary: String,
pub generated_at: String,
}
impl CompensationPlanV1 {
pub const SCHEMA_VERSION: &'static str = "CompensationPlanV1";
#[allow(clippy::too_many_arguments)]
pub fn builder(
compensation_plan_id: CompensationPlanId,
effect_intent_id: EffectIntentId,
citation: V25ConstitutionCitation,
compensation_required: bool,
compensation_class: CompensationClassV1,
compensation_steps: Vec<String>,
success_criteria: Vec<String>,
owner_ref: impl Into<String>,
latest_start: impl Into<String>,
advisory_only: bool,
) -> CompensationPlanV1Builder {
CompensationPlanV1Builder::new(
compensation_plan_id,
effect_intent_id,
citation,
compensation_required,
compensation_class,
compensation_steps,
success_criteria,
owner_ref,
latest_start,
advisory_only,
)
}
pub fn validate(&self) -> EffectValidationResult {
require_schema_version(
"CompensationPlanV1",
Self::SCHEMA_VERSION,
&self.schema_version,
)?;
require_id(&self.compensation_plan_id, "compensation_plan_id")?;
require_id(&self.effect_intent_id, "effect_intent_id")?;
require_non_empty_slice(&self.success_criteria, "success_criteria")?;
require_non_empty(&self.owner_ref, "owner_ref")?;
require_non_empty(&self.latest_start, "latest_start")?;
if self.compensation_required {
require_non_empty_slice(&self.compensation_steps, "compensation_steps")?;
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct CompensationPlanV1Builder {
compensation_plan_id: CompensationPlanId,
effect_intent_id: EffectIntentId,
citation: V25ConstitutionCitation,
compensation_required: bool,
compensation_class: CompensationClassV1,
compensation_steps: Vec<String>,
success_criteria: Vec<String>,
owner_ref: String,
latest_start: String,
advisory_only: bool,
}
impl CompensationPlanV1Builder {
#[allow(clippy::too_many_arguments)]
pub fn new(
compensation_plan_id: CompensationPlanId,
effect_intent_id: EffectIntentId,
citation: V25ConstitutionCitation,
compensation_required: bool,
compensation_class: CompensationClassV1,
compensation_steps: Vec<String>,
success_criteria: Vec<String>,
owner_ref: impl Into<String>,
latest_start: impl Into<String>,
advisory_only: bool,
) -> Self {
Self {
compensation_plan_id,
effect_intent_id,
citation,
compensation_required,
compensation_class,
compensation_steps,
success_criteria,
owner_ref: owner_ref.into(),
latest_start: latest_start.into(),
advisory_only,
}
}
pub fn build(self) -> Result<CompensationPlanV1, EffectRuntimeValidationError> {
let value = CompensationPlanV1 {
schema_version: CompensationPlanV1::SCHEMA_VERSION.to_string(),
compensation_plan_id: self.compensation_plan_id,
effect_intent_id: self.effect_intent_id,
citation: self.citation,
compensation_required: self.compensation_required,
compensation_class: self.compensation_class,
compensation_steps: self.compensation_steps,
success_criteria: self.success_criteria,
owner_ref: self.owner_ref,
latest_start: self.latest_start,
advisory_only: self.advisory_only,
};
value.validate()?;
Ok(value)
}
}
impl CompensationExecutionReceiptV1 {
pub const SCHEMA_VERSION: &'static str = "CompensationExecutionReceiptV1";
#[allow(clippy::too_many_arguments)]
pub fn builder(
compensation_execution_receipt_id: CompensationExecutionReceiptId,
compensation_plan_id: CompensationPlanId,
citation: V25ConstitutionCitation,
execution_state: ExecutionStateV1,
completed_steps: Vec<String>,
failed_steps: Vec<String>,
residual_risk_summary: impl Into<String>,
generated_at: impl Into<String>,
) -> CompensationExecutionReceiptV1Builder {
CompensationExecutionReceiptV1Builder::new(
compensation_execution_receipt_id,
compensation_plan_id,
citation,
execution_state,
completed_steps,
failed_steps,
residual_risk_summary,
generated_at,
)
}
pub fn validate(&self) -> EffectValidationResult {
require_schema_version(
"CompensationExecutionReceiptV1",
Self::SCHEMA_VERSION,
&self.schema_version,
)?;
require_id(
&self.compensation_execution_receipt_id,
"compensation_execution_receipt_id",
)?;
require_id(&self.compensation_plan_id, "compensation_plan_id")?;
require_non_empty(&self.residual_risk_summary, "residual_risk_summary")?;
require_non_empty(&self.generated_at, "generated_at")?;
if matches!(self.execution_state, ExecutionStateV1::Completed)
&& !self.failed_steps.is_empty()
{
return Err(EffectRuntimeValidationError::InvalidState(
"completed compensation receipts must not list failed_steps",
));
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub struct CompensationExecutionReceiptV1Builder {
compensation_execution_receipt_id: CompensationExecutionReceiptId,
compensation_plan_id: CompensationPlanId,
citation: V25ConstitutionCitation,
execution_state: ExecutionStateV1,
completed_steps: Vec<String>,
failed_steps: Vec<String>,
residual_risk_summary: String,
generated_at: String,
}
impl CompensationExecutionReceiptV1Builder {
#[allow(clippy::too_many_arguments)]
pub fn new(
compensation_execution_receipt_id: CompensationExecutionReceiptId,
compensation_plan_id: CompensationPlanId,
citation: V25ConstitutionCitation,
execution_state: ExecutionStateV1,
completed_steps: Vec<String>,
failed_steps: Vec<String>,
residual_risk_summary: impl Into<String>,
generated_at: impl Into<String>,
) -> Self {
Self {
compensation_execution_receipt_id,
compensation_plan_id,
citation,
execution_state,
completed_steps,
failed_steps,
residual_risk_summary: residual_risk_summary.into(),
generated_at: generated_at.into(),
}
}
pub fn build(self) -> Result<CompensationExecutionReceiptV1, EffectRuntimeValidationError> {
let value = CompensationExecutionReceiptV1 {
schema_version: CompensationExecutionReceiptV1::SCHEMA_VERSION.to_string(),
compensation_execution_receipt_id: self.compensation_execution_receipt_id,
compensation_plan_id: self.compensation_plan_id,
citation: self.citation,
execution_state: self.execution_state,
completed_steps: self.completed_steps,
failed_steps: self.failed_steps,
residual_risk_summary: self.residual_risk_summary,
generated_at: self.generated_at,
};
value.validate()?;
Ok(value)
}
}