Skip to main content

ringkernel_procint/fabric/
process_models.rs

1//! Reference process models for conformance checking.
2//!
3//! Provides pre-defined BPMN and DFG models for each sector.
4
5use crate::models::{ActivityId, ProcessModel, ProcessModelType};
6
7/// Reference model repository for sectors.
8#[derive(Debug, Clone)]
9pub struct ReferenceModelRepository {
10    models: Vec<ProcessModel>,
11}
12
13impl Default for ReferenceModelRepository {
14    fn default() -> Self {
15        Self::new()
16    }
17}
18
19impl ReferenceModelRepository {
20    /// Create a new repository with default models.
21    pub fn new() -> Self {
22        let mut repo = Self { models: Vec::new() };
23        repo.add_healthcare_models();
24        repo.add_manufacturing_models();
25        repo.add_finance_models();
26        repo.add_it_models();
27        repo
28    }
29
30    /// Get model by ID.
31    pub fn get(&self, id: u32) -> Option<&ProcessModel> {
32        self.models.iter().find(|m| m.id == id)
33    }
34
35    /// Get models by sector name.
36    pub fn get_by_sector(&self, sector: &str) -> Vec<&ProcessModel> {
37        self.models
38            .iter()
39            .filter(|m| m.name.starts_with(sector))
40            .collect()
41    }
42
43    /// Get all models.
44    pub fn all(&self) -> &[ProcessModel] {
45        &self.models
46    }
47
48    fn add_healthcare_models(&mut self) {
49        // Healthcare DFG Model
50        let mut model = ProcessModel::new(1, "Healthcare-DFG", ProcessModelType::DFG);
51        model.start_activities = vec![1]; // Registration
52        model.end_activities = vec![6]; // Discharge
53
54        // Valid transitions (based on SectorTemplate::Healthcare)
55        model.add_transition(1, 2); // Registration -> Triage
56        model.add_transition(2, 3); // Triage -> Examination
57        model.add_transition(3, 4); // Examination -> Diagnosis
58        model.add_transition(4, 5); // Diagnosis -> Treatment
59        model.add_transition(5, 6); // Treatment -> Discharge
60                                    // Alternative paths
61        model.add_transition(2, 4); // Triage -> Diagnosis (urgent)
62        model.add_transition(5, 3); // Treatment -> Examination (follow-up)
63
64        self.models.push(model);
65
66        // Healthcare Petri Net Model
67        let mut petri = ProcessModel::new(2, "Healthcare-PetriNet", ProcessModelType::PetriNet);
68        petri.start_activities = vec![1];
69        petri.end_activities = vec![6];
70        petri.transitions = vec![(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)];
71        self.models.push(petri);
72    }
73
74    fn add_manufacturing_models(&mut self) {
75        let mut model = ProcessModel::new(10, "Manufacturing-DFG", ProcessModelType::DFG);
76        model.start_activities = vec![11]; // Order
77        model.end_activities = vec![16]; // Ship
78
79        model.add_transition(11, 12); // Order -> Plan
80        model.add_transition(12, 13); // Plan -> Produce
81        model.add_transition(13, 14); // Produce -> QualityCheck
82        model.add_transition(14, 15); // QualityCheck -> Package
83        model.add_transition(15, 16); // Package -> Ship
84                                      // Rework loop
85        model.add_transition(14, 13); // QualityCheck -> Produce (rework)
86
87        self.models.push(model);
88    }
89
90    fn add_finance_models(&mut self) {
91        let mut model = ProcessModel::new(20, "Finance-DFG", ProcessModelType::DFG);
92        model.start_activities = vec![21]; // Application
93        model.end_activities = vec![25]; // Disbursement
94
95        model.add_transition(21, 22); // Application -> Verification
96        model.add_transition(22, 23); // Verification -> CreditCheck
97        model.add_transition(23, 24); // CreditCheck -> Approval
98        model.add_transition(24, 25); // Approval -> Disbursement
99                                      // Review loop
100        model.add_transition(23, 22); // CreditCheck -> Verification (review)
101
102        self.models.push(model);
103    }
104
105    fn add_it_models(&mut self) {
106        let mut model = ProcessModel::new(30, "IT-IncidentManagement-DFG", ProcessModelType::DFG);
107        model.start_activities = vec![31]; // Report
108        model.end_activities = vec![36]; // Close
109
110        model.add_transition(31, 32); // Report -> Classify
111        model.add_transition(32, 33); // Classify -> Assign
112        model.add_transition(33, 34); // Assign -> Investigate
113        model.add_transition(34, 35); // Investigate -> Resolve
114        model.add_transition(35, 36); // Resolve -> Close
115                                      // Escalation
116        model.add_transition(34, 33); // Investigate -> Assign (reassign)
117        model.add_transition(35, 34); // Resolve -> Investigate (reopen)
118
119        self.models.push(model);
120    }
121}
122
123/// Model builder for creating custom process models.
124#[derive(Debug)]
125pub struct ProcessModelBuilder {
126    id: u32,
127    name: String,
128    model_type: ProcessModelType,
129    start_activities: Vec<ActivityId>,
130    end_activities: Vec<ActivityId>,
131    transitions: Vec<(ActivityId, ActivityId)>,
132}
133
134impl ProcessModelBuilder {
135    /// Create a new builder.
136    pub fn new(id: u32, name: impl Into<String>) -> Self {
137        Self {
138            id,
139            name: name.into(),
140            model_type: ProcessModelType::DFG,
141            start_activities: Vec::new(),
142            end_activities: Vec::new(),
143            transitions: Vec::new(),
144        }
145    }
146
147    /// Set model type.
148    pub fn with_type(mut self, model_type: ProcessModelType) -> Self {
149        self.model_type = model_type;
150        self
151    }
152
153    /// Add start activity.
154    pub fn with_start(mut self, activity: ActivityId) -> Self {
155        self.start_activities.push(activity);
156        self
157    }
158
159    /// Add end activity.
160    pub fn with_end(mut self, activity: ActivityId) -> Self {
161        self.end_activities.push(activity);
162        self
163    }
164
165    /// Add transition.
166    pub fn with_transition(mut self, source: ActivityId, target: ActivityId) -> Self {
167        self.transitions.push((source, target));
168        self
169    }
170
171    /// Build the process model.
172    pub fn build(self) -> ProcessModel {
173        ProcessModel {
174            id: self.id,
175            name: self.name,
176            model_type: self.model_type,
177            start_activities: self.start_activities,
178            end_activities: self.end_activities,
179            transitions: self.transitions,
180        }
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187
188    #[test]
189    fn test_repository_creation() {
190        let repo = ReferenceModelRepository::new();
191        assert!(!repo.all().is_empty());
192    }
193
194    #[test]
195    fn test_get_model() {
196        let repo = ReferenceModelRepository::new();
197        let model = repo.get(1);
198        assert!(model.is_some());
199        assert_eq!(model.unwrap().name, "Healthcare-DFG");
200    }
201
202    #[test]
203    fn test_builder() {
204        let model = ProcessModelBuilder::new(100, "Test")
205            .with_type(ProcessModelType::DFG)
206            .with_start(1)
207            .with_end(5)
208            .with_transition(1, 2)
209            .with_transition(2, 5)
210            .build();
211
212        assert_eq!(model.id, 100);
213        assert_eq!(model.start_activities, vec![1]);
214        assert_eq!(model.end_activities, vec![5]);
215        assert!(model.has_transition(1, 2));
216    }
217}