datasynth_core/models/
cycle_count.rs1use chrono::NaiveDate;
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10
11use super::graph_properties::{GraphPropertyValue, ToNodeProperties};
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
15#[serde(rename_all = "snake_case")]
16pub enum CycleCountStatus {
17 #[default]
19 Planned,
20 InProgress,
22 Counted,
24 Reconciled,
26 Closed,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
32#[serde(rename_all = "snake_case")]
33pub enum CountVarianceType {
34 #[default]
36 None,
37 Minor,
39 Major,
41 Critical,
43}
44
45#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct CycleCount {
48 pub count_id: String,
50 pub company_code: String,
52 pub warehouse_id: String,
54 pub count_date: NaiveDate,
56 pub status: CycleCountStatus,
58 pub counter_id: Option<String>,
60 pub supervisor_id: Option<String>,
62 pub items: Vec<CycleCountItem>,
64 pub total_items_counted: u32,
66 pub total_variances: u32,
68 pub variance_rate: f64,
70}
71
72impl ToNodeProperties for CycleCount {
73 fn node_type_name(&self) -> &'static str {
74 "cycle_count"
75 }
76 fn node_type_code(&self) -> u16 {
77 342
78 }
79 fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
80 let mut p = HashMap::new();
81 p.insert(
82 "countId".into(),
83 GraphPropertyValue::String(self.count_id.clone()),
84 );
85 p.insert(
86 "entityCode".into(),
87 GraphPropertyValue::String(self.company_code.clone()),
88 );
89 p.insert(
90 "warehouseId".into(),
91 GraphPropertyValue::String(self.warehouse_id.clone()),
92 );
93 p.insert(
94 "countDate".into(),
95 GraphPropertyValue::Date(self.count_date),
96 );
97 p.insert(
98 "status".into(),
99 GraphPropertyValue::String(format!("{:?}", self.status)),
100 );
101 p.insert(
102 "totalItemsCounted".into(),
103 GraphPropertyValue::Int(self.total_items_counted as i64),
104 );
105 p.insert(
106 "totalVariances".into(),
107 GraphPropertyValue::Int(self.total_variances as i64),
108 );
109 p.insert(
110 "varianceRate".into(),
111 GraphPropertyValue::Float(self.variance_rate),
112 );
113 p.insert(
114 "isReconciled".into(),
115 GraphPropertyValue::Bool(matches!(
116 self.status,
117 CycleCountStatus::Reconciled | CycleCountStatus::Closed
118 )),
119 );
120 p
121 }
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct CycleCountItem {
127 pub material_id: String,
129 #[serde(default, skip_serializing_if = "Option::is_none")]
131 pub material_description: Option<String>,
132 pub storage_location: String,
134 #[serde(with = "rust_decimal::serde::str")]
136 pub book_quantity: Decimal,
137 #[serde(with = "rust_decimal::serde::str")]
139 pub counted_quantity: Decimal,
140 #[serde(with = "rust_decimal::serde::str")]
142 pub variance_quantity: Decimal,
143 #[serde(with = "rust_decimal::serde::str")]
145 pub unit_cost: Decimal,
146 #[serde(with = "rust_decimal::serde::str")]
148 pub variance_value: Decimal,
149 pub variance_type: CountVarianceType,
151 pub adjusted: bool,
153 pub adjustment_reason: Option<String>,
155}