Skip to main content

datasynth_ocpm/models/
resource.rs

1//! Resource model for OCPM.
2//!
3//! Resources represent users or systems that perform activities in the process.
4
5use serde::{Deserialize, Serialize};
6
7/// Resource (user or system) that performs activities.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Resource {
10    /// Unique resource identifier
11    pub resource_id: String,
12    /// Human-readable name
13    pub name: String,
14    /// Type of resource
15    pub resource_type: ResourceType,
16    /// Department (for users)
17    pub department: Option<String>,
18    /// Role (for users)
19    pub role: Option<String>,
20    /// Is the resource currently active
21    pub is_active: bool,
22    /// Activity types this resource can perform
23    pub capabilities: Vec<String>,
24    /// Cost per hour (for workload analysis)
25    pub cost_per_hour: Option<f64>,
26}
27
28impl Resource {
29    /// Create a new user resource.
30    pub fn user(id: &str, name: &str) -> Self {
31        Self {
32            resource_id: id.into(),
33            name: name.into(),
34            resource_type: ResourceType::User,
35            department: None,
36            role: None,
37            is_active: true,
38            capabilities: Vec::new(),
39            cost_per_hour: None,
40        }
41    }
42
43    /// Create a new system resource.
44    pub fn system(id: &str, name: &str) -> Self {
45        Self {
46            resource_id: id.into(),
47            name: name.into(),
48            resource_type: ResourceType::System,
49            department: None,
50            role: None,
51            is_active: true,
52            capabilities: Vec::new(),
53            cost_per_hour: None,
54        }
55    }
56
57    /// Set the department.
58    pub fn with_department(mut self, department: &str) -> Self {
59        self.department = Some(department.into());
60        self
61    }
62
63    /// Set the role.
64    pub fn with_role(mut self, role: &str) -> Self {
65        self.role = Some(role.into());
66        self
67    }
68
69    /// Add capabilities.
70    pub fn with_capabilities(mut self, capabilities: Vec<&str>) -> Self {
71        self.capabilities = capabilities.into_iter().map(String::from).collect();
72        self
73    }
74
75    /// Set cost per hour.
76    pub fn with_cost(mut self, cost_per_hour: f64) -> Self {
77        self.cost_per_hour = Some(cost_per_hour);
78        self
79    }
80
81    /// Check if this resource can perform an activity.
82    pub fn can_perform(&self, activity_id: &str) -> bool {
83        self.capabilities.is_empty() || self.capabilities.iter().any(|c| c == activity_id)
84    }
85
86    /// Create a standard ERP system resource.
87    pub fn erp_system() -> Self {
88        Self::system("SYS_ERP", "ERP System").with_capabilities(vec![
89            "post_gr",
90            "post_invoice",
91            "execute_payment",
92            "check_credit",
93            "post_customer_invoice",
94            "receive_payment",
95        ])
96    }
97
98    /// Create a standard workflow system resource.
99    pub fn workflow_system() -> Self {
100        Self::system("SYS_WF", "Workflow System")
101            .with_capabilities(vec!["release_po", "release_so"])
102    }
103}
104
105/// Type of resource.
106#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
107#[serde(rename_all = "snake_case")]
108pub enum ResourceType {
109    /// Human user
110    #[default]
111    User,
112    /// Automated system
113    System,
114    /// External service/API
115    ExternalService,
116    /// Bot/RPA
117    Bot,
118}
119
120impl ResourceType {
121    /// Check if this is a human resource.
122    pub fn is_human(&self) -> bool {
123        matches!(self, Self::User)
124    }
125
126    /// Check if this is an automated resource.
127    pub fn is_automated(&self) -> bool {
128        !self.is_human()
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_user_resource() {
138        let user = Resource::user("USR001", "John Doe")
139            .with_department("Finance")
140            .with_role("AP Clerk");
141
142        assert_eq!(user.resource_type, ResourceType::User);
143        assert_eq!(user.department, Some("Finance".into()));
144    }
145
146    #[test]
147    fn test_system_resource() {
148        let system = Resource::erp_system();
149
150        assert_eq!(system.resource_type, ResourceType::System);
151        assert!(system.can_perform("post_invoice"));
152        assert!(!system.can_perform("create_po"));
153    }
154}