datasynth_core/models/sourcing/
sourcing_project.rs1use chrono::NaiveDate;
4use rust_decimal::Decimal;
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8use super::super::graph_properties::{GraphPropertyValue, ToNodeProperties};
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
12#[serde(rename_all = "snake_case")]
13pub enum SourcingProjectType {
14 #[default]
16 NewSourcing,
17 Renewal,
19 Consolidation,
21 Emergency,
23 StrategicPartnership,
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
29#[serde(rename_all = "snake_case")]
30pub enum SourcingProjectStatus {
31 #[default]
33 Draft,
34 SpendAnalysis,
36 Qualification,
38 RfxActive,
40 Evaluation,
42 Negotiation,
44 Awarded,
46 Completed,
48 Cancelled,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct SourcingProject {
55 pub project_id: String,
57 pub project_name: String,
59 pub company_code: String,
61 pub project_type: SourcingProjectType,
63 pub status: SourcingProjectStatus,
65 pub category_id: String,
67 #[serde(with = "rust_decimal::serde::str")]
69 pub estimated_annual_spend: Decimal,
70 pub target_savings_pct: f64,
72 pub owner_id: String,
74 pub start_date: NaiveDate,
76 pub target_end_date: NaiveDate,
78 pub actual_end_date: Option<NaiveDate>,
80 pub spend_analysis_id: Option<String>,
82 pub rfx_ids: Vec<String>,
84 pub contract_id: Option<String>,
86 pub actual_savings_pct: Option<f64>,
88}
89
90impl ToNodeProperties for SourcingProject {
91 fn node_type_name(&self) -> &'static str {
92 "sourcing_project"
93 }
94 fn node_type_code(&self) -> u16 {
95 320
96 }
97 fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
98 let mut p = HashMap::new();
99 p.insert(
100 "projectId".into(),
101 GraphPropertyValue::String(self.project_id.clone()),
102 );
103 p.insert(
104 "projectName".into(),
105 GraphPropertyValue::String(self.project_name.clone()),
106 );
107 p.insert(
108 "entityCode".into(),
109 GraphPropertyValue::String(self.company_code.clone()),
110 );
111 p.insert(
112 "projectType".into(),
113 GraphPropertyValue::String(format!("{:?}", self.project_type)),
114 );
115 p.insert(
116 "status".into(),
117 GraphPropertyValue::String(format!("{:?}", self.status)),
118 );
119 p.insert(
120 "estimatedValue".into(),
121 GraphPropertyValue::Decimal(self.estimated_annual_spend),
122 );
123 p.insert(
124 "targetSavingsPct".into(),
125 GraphPropertyValue::Float(self.target_savings_pct),
126 );
127 p.insert(
128 "owner".into(),
129 GraphPropertyValue::String(self.owner_id.clone()),
130 );
131 p.insert(
132 "startDate".into(),
133 GraphPropertyValue::Date(self.start_date),
134 );
135 p.insert(
136 "targetEndDate".into(),
137 GraphPropertyValue::Date(self.target_end_date),
138 );
139 p.insert(
140 "bidCount".into(),
141 GraphPropertyValue::Int(self.rfx_ids.len() as i64),
142 );
143 p.insert(
144 "isComplete".into(),
145 GraphPropertyValue::Bool(matches!(
146 self.status,
147 SourcingProjectStatus::Completed | SourcingProjectStatus::Awarded
148 )),
149 );
150 p
151 }
152}