Skip to main content

datasynth_core/models/
quality_inspection.rs

1//! Quality inspection models for manufacturing processes.
2//!
3//! These models represent quality inspections performed on materials
4//! during incoming receipt, in-process production, and final output.
5
6use chrono::NaiveDate;
7use rust_decimal::Decimal;
8use serde::{Deserialize, Serialize};
9use smallvec::SmallVec;
10use std::collections::HashMap;
11
12use super::graph_properties::{GraphPropertyValue, ToNodeProperties};
13
14/// Result of a quality inspection.
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
16#[serde(rename_all = "snake_case")]
17pub enum InspectionResult {
18    /// Material accepted without conditions
19    #[default]
20    Accepted,
21    /// Material rejected
22    Rejected,
23    /// Material accepted with conditions or concessions
24    Conditionally,
25    /// Inspection not yet completed
26    Pending,
27}
28
29/// Type of quality inspection.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
31#[serde(rename_all = "snake_case")]
32pub enum InspectionType {
33    /// Inspection of incoming materials from vendors
34    #[default]
35    Incoming,
36    /// Inspection during production process
37    InProcess,
38    /// Final inspection before delivery or storage
39    Final,
40    /// Random sampling inspection
41    Random,
42    /// Scheduled periodic inspection
43    Periodic,
44}
45
46/// A quality inspection record for a material lot.
47#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct QualityInspection {
49    /// Unique inspection identifier
50    pub inspection_id: String,
51    /// Company code this inspection belongs to
52    pub company_code: String,
53    /// Type of reference document (e.g., "production_order", "goods_receipt")
54    pub reference_type: String,
55    /// Identifier of the reference document
56    pub reference_id: String,
57    /// Material being inspected
58    pub material_id: String,
59    /// Description of the material being inspected
60    pub material_description: String,
61    /// Type of inspection performed
62    pub inspection_type: InspectionType,
63    /// Date the inspection was performed
64    pub inspection_date: NaiveDate,
65    /// Inspector who performed the inspection
66    pub inspector_id: Option<String>,
67    /// Total lot size under inspection
68    #[serde(with = "rust_decimal::serde::str")]
69    pub lot_size: Decimal,
70    /// Sample size drawn for inspection
71    #[serde(with = "rust_decimal::serde::str")]
72    pub sample_size: Decimal,
73    /// Number of defects found
74    pub defect_count: u32,
75    /// Defect rate (defect_count / sample_size)
76    pub defect_rate: f64,
77    /// Overall inspection result
78    pub result: InspectionResult,
79    /// Individual inspection characteristics measured
80    pub characteristics: SmallVec<[InspectionCharacteristic; 4]>,
81    /// Disposition action (e.g., "use_as_is", "return_to_vendor", "scrap")
82    pub disposition: Option<String>,
83    /// Additional notes or observations
84    pub notes: Option<String>,
85}
86
87impl ToNodeProperties for QualityInspection {
88    fn node_type_name(&self) -> &'static str {
89        "quality_inspection"
90    }
91    fn node_type_code(&self) -> u16 {
92        341
93    }
94    fn to_node_properties(&self) -> HashMap<String, GraphPropertyValue> {
95        let mut p = HashMap::new();
96        p.insert(
97            "inspectionId".into(),
98            GraphPropertyValue::String(self.inspection_id.clone()),
99        );
100        p.insert(
101            "entityCode".into(),
102            GraphPropertyValue::String(self.company_code.clone()),
103        );
104        p.insert(
105            "referenceType".into(),
106            GraphPropertyValue::String(self.reference_type.clone()),
107        );
108        p.insert(
109            "referenceId".into(),
110            GraphPropertyValue::String(self.reference_id.clone()),
111        );
112        p.insert(
113            "materialId".into(),
114            GraphPropertyValue::String(self.material_id.clone()),
115        );
116        p.insert(
117            "materialDescription".into(),
118            GraphPropertyValue::String(self.material_description.clone()),
119        );
120        p.insert(
121            "inspectionType".into(),
122            GraphPropertyValue::String(format!("{:?}", self.inspection_type)),
123        );
124        p.insert(
125            "inspectionDate".into(),
126            GraphPropertyValue::Date(self.inspection_date),
127        );
128        p.insert("lotSize".into(), GraphPropertyValue::Decimal(self.lot_size));
129        p.insert(
130            "inspectedQuantity".into(),
131            GraphPropertyValue::Decimal(self.sample_size),
132        );
133        p.insert(
134            "defectQuantity".into(),
135            GraphPropertyValue::Int(self.defect_count as i64),
136        );
137        p.insert(
138            "defectRate".into(),
139            GraphPropertyValue::Float(self.defect_rate),
140        );
141        p.insert(
142            "result".into(),
143            GraphPropertyValue::String(format!("{:?}", self.result)),
144        );
145        p.insert(
146            "isPassed".into(),
147            GraphPropertyValue::Bool(matches!(
148                self.result,
149                InspectionResult::Accepted | InspectionResult::Conditionally
150            )),
151        );
152        p
153    }
154}
155
156/// A single measured characteristic within a quality inspection.
157#[derive(Debug, Clone, Serialize, Deserialize)]
158pub struct InspectionCharacteristic {
159    /// Name of the characteristic (e.g., "diameter", "weight", "tensile_strength")
160    pub name: String,
161    /// Target specification value
162    pub target_value: f64,
163    /// Actual measured value
164    pub actual_value: f64,
165    /// Lower specification limit
166    pub lower_limit: f64,
167    /// Upper specification limit
168    pub upper_limit: f64,
169    /// Whether this characteristic passed inspection
170    pub passed: bool,
171}