use crate::MoneyV1;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SavingsAttribution {
pub customer_id: String,
pub period: String,
pub baseline_cost: MoneyV1,
pub treatment_cost: MoneyV1,
pub proven_savings: MoneyV1,
pub share_percentage: u16,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SettlementStatus {
NoSettlement,
Pending,
Settled,
Disputed,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct SettlementRecord {
pub attribution: SavingsAttribution,
pub invoice_amount: MoneyV1,
pub settlement_status: SettlementStatus,
}
pub trait ValueShareContract {
fn calculate_share(&self, attribution: SavingsAttribution) -> SettlementRecord;
}
#[derive(Debug, Default, Clone, Copy)]
pub struct LocalValueShare;
impl ValueShareContract for LocalValueShare {
fn calculate_share(&self, attribution: SavingsAttribution) -> SettlementRecord {
let invoice_amount = MoneyV1 {
currency: attribution.proven_savings.currency.clone(),
coefficient: 0,
scale: attribution.proven_savings.scale,
};
SettlementRecord {
attribution,
invoice_amount,
settlement_status: SettlementStatus::NoSettlement,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
fn attribution() -> SavingsAttribution {
SavingsAttribution {
customer_id: "customer-1".to_owned(),
period: "2026-08".to_owned(),
baseline_cost: MoneyV1 {
currency: "USD".to_owned(),
coefficient: 10_000,
scale: 4,
},
treatment_cost: MoneyV1 {
currency: "USD".to_owned(),
coefficient: 5_000,
scale: 4,
},
proven_savings: MoneyV1 {
currency: "USD".to_owned(),
coefficient: 5_000,
scale: 4,
},
share_percentage: 200,
}
}
#[test]
fn local_value_share_returns_zero_settlement() {
let settlement = LocalValueShare.calculate_share(attribution());
assert_eq!(settlement.invoice_amount.coefficient, 0);
assert_eq!(settlement.settlement_status, SettlementStatus::NoSettlement);
}
#[test]
fn contract_is_object_safe() {
let value_share: &dyn ValueShareContract = &LocalValueShare;
assert_eq!(
value_share
.calculate_share(attribution())
.invoice_amount
.coefficient,
0
);
}
}