1use datasynth_core::models::BusinessProcess;
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ObjectType {
13 pub type_id: String,
15 pub name: String,
17 pub business_process: BusinessProcess,
19 pub lifecycle_states: Vec<ObjectLifecycleState>,
21 pub relationships: Vec<ObjectRelationshipType>,
23 pub allowed_activities: Vec<String>,
25 pub attributes: HashMap<String, AttributeType>,
27}
28
29impl ObjectType {
30 pub fn purchase_order() -> Self {
32 Self {
33 type_id: "purchase_order".into(),
34 name: "Purchase Order".into(),
35 business_process: BusinessProcess::P2P,
36 lifecycle_states: vec![
37 ObjectLifecycleState::new("created", "Created", true, false),
38 ObjectLifecycleState::new("approved", "Approved", false, false),
39 ObjectLifecycleState::new("released", "Released", false, false),
40 ObjectLifecycleState::new("received", "Goods Received", false, false),
41 ObjectLifecycleState::new("invoiced", "Invoiced", false, false),
42 ObjectLifecycleState::new("paid", "Paid", false, true),
43 ObjectLifecycleState::new("cancelled", "Cancelled", false, true),
44 ],
45 relationships: vec![
46 ObjectRelationshipType::new(
47 "contains",
48 "Contains",
49 "order_line",
50 Cardinality::OneToMany,
51 false,
52 ),
53 ObjectRelationshipType::new(
54 "fulfilled_by",
55 "Fulfilled By",
56 "goods_receipt",
57 Cardinality::OneToMany,
58 false,
59 ),
60 ObjectRelationshipType::new(
61 "invoiced_by",
62 "Invoiced By",
63 "vendor_invoice",
64 Cardinality::OneToMany,
65 false,
66 ),
67 ],
68 allowed_activities: vec![
69 "create_po".into(),
70 "approve_po".into(),
71 "release_po".into(),
72 "change_po".into(),
73 "cancel_po".into(),
74 ],
75 attributes: HashMap::from([
76 ("po_number".into(), AttributeType::String),
77 ("vendor_id".into(), AttributeType::String),
78 ("total_amount".into(), AttributeType::Decimal),
79 ("currency".into(), AttributeType::String),
80 ("created_date".into(), AttributeType::Date),
81 ]),
82 }
83 }
84
85 pub fn goods_receipt() -> Self {
87 Self {
88 type_id: "goods_receipt".into(),
89 name: "Goods Receipt".into(),
90 business_process: BusinessProcess::P2P,
91 lifecycle_states: vec![
92 ObjectLifecycleState::new("created", "Created", true, false),
93 ObjectLifecycleState::new("posted", "Posted", false, true),
94 ObjectLifecycleState::new("reversed", "Reversed", false, true),
95 ],
96 relationships: vec![
97 ObjectRelationshipType::new(
98 "references",
99 "References",
100 "purchase_order",
101 Cardinality::ManyToOne,
102 true,
103 ),
104 ObjectRelationshipType::new(
105 "contains",
106 "Contains",
107 "material",
108 Cardinality::OneToMany,
109 true,
110 ),
111 ],
112 allowed_activities: vec!["create_gr".into(), "post_gr".into(), "reverse_gr".into()],
113 attributes: HashMap::from([
114 ("gr_number".into(), AttributeType::String),
115 ("po_number".into(), AttributeType::String),
116 ("receipt_date".into(), AttributeType::Date),
117 ("quantity".into(), AttributeType::Decimal),
118 ]),
119 }
120 }
121
122 pub fn vendor_invoice() -> Self {
124 Self {
125 type_id: "vendor_invoice".into(),
126 name: "Vendor Invoice".into(),
127 business_process: BusinessProcess::P2P,
128 lifecycle_states: vec![
129 ObjectLifecycleState::new("received", "Received", true, false),
130 ObjectLifecycleState::new("verified", "Verified", false, false),
131 ObjectLifecycleState::new("posted", "Posted", false, false),
132 ObjectLifecycleState::new("paid", "Paid", false, true),
133 ObjectLifecycleState::new("rejected", "Rejected", false, true),
134 ],
135 relationships: vec![
136 ObjectRelationshipType::new(
137 "references_po",
138 "References PO",
139 "purchase_order",
140 Cardinality::ManyToOne,
141 false,
142 ),
143 ObjectRelationshipType::new(
144 "references_gr",
145 "References GR",
146 "goods_receipt",
147 Cardinality::ManyToMany,
148 false,
149 ),
150 ],
151 allowed_activities: vec![
152 "receive_invoice".into(),
153 "verify_invoice".into(),
154 "post_invoice".into(),
155 "reject_invoice".into(),
156 ],
157 attributes: HashMap::from([
158 ("invoice_number".into(), AttributeType::String),
159 ("vendor_id".into(), AttributeType::String),
160 ("invoice_amount".into(), AttributeType::Decimal),
161 ("invoice_date".into(), AttributeType::Date),
162 ]),
163 }
164 }
165
166 pub fn sales_order() -> Self {
168 Self {
169 type_id: "sales_order".into(),
170 name: "Sales Order".into(),
171 business_process: BusinessProcess::O2C,
172 lifecycle_states: vec![
173 ObjectLifecycleState::new("created", "Created", true, false),
174 ObjectLifecycleState::new("credit_checked", "Credit Checked", false, false),
175 ObjectLifecycleState::new("released", "Released", false, false),
176 ObjectLifecycleState::new("delivered", "Delivered", false, false),
177 ObjectLifecycleState::new("invoiced", "Invoiced", false, false),
178 ObjectLifecycleState::new("paid", "Paid", false, true),
179 ObjectLifecycleState::new("cancelled", "Cancelled", false, true),
180 ],
181 relationships: vec![
182 ObjectRelationshipType::new(
183 "contains",
184 "Contains",
185 "order_line",
186 Cardinality::OneToMany,
187 false,
188 ),
189 ObjectRelationshipType::new(
190 "fulfilled_by",
191 "Fulfilled By",
192 "delivery",
193 Cardinality::OneToMany,
194 false,
195 ),
196 ],
197 allowed_activities: vec![
198 "create_so".into(),
199 "check_credit".into(),
200 "release_so".into(),
201 "change_so".into(),
202 "cancel_so".into(),
203 ],
204 attributes: HashMap::from([
205 ("so_number".into(), AttributeType::String),
206 ("customer_id".into(), AttributeType::String),
207 ("total_amount".into(), AttributeType::Decimal),
208 ("currency".into(), AttributeType::String),
209 ]),
210 }
211 }
212
213 pub fn delivery() -> Self {
215 Self {
216 type_id: "delivery".into(),
217 name: "Delivery".into(),
218 business_process: BusinessProcess::O2C,
219 lifecycle_states: vec![
220 ObjectLifecycleState::new("created", "Created", true, false),
221 ObjectLifecycleState::new("picked", "Picked", false, false),
222 ObjectLifecycleState::new("packed", "Packed", false, false),
223 ObjectLifecycleState::new("shipped", "Shipped", false, true),
224 ObjectLifecycleState::new("cancelled", "Cancelled", false, true),
225 ],
226 relationships: vec![ObjectRelationshipType::new(
227 "fulfills",
228 "Fulfills",
229 "sales_order",
230 Cardinality::ManyToOne,
231 true,
232 )],
233 allowed_activities: vec![
234 "create_delivery".into(),
235 "pick".into(),
236 "pack".into(),
237 "ship".into(),
238 ],
239 attributes: HashMap::from([
240 ("delivery_number".into(), AttributeType::String),
241 ("so_number".into(), AttributeType::String),
242 ("ship_date".into(), AttributeType::Date),
243 ]),
244 }
245 }
246
247 pub fn customer_invoice() -> Self {
249 Self {
250 type_id: "customer_invoice".into(),
251 name: "Customer Invoice".into(),
252 business_process: BusinessProcess::O2C,
253 lifecycle_states: vec![
254 ObjectLifecycleState::new("created", "Created", true, false),
255 ObjectLifecycleState::new("posted", "Posted", false, false),
256 ObjectLifecycleState::new("sent", "Sent", false, false),
257 ObjectLifecycleState::new("paid", "Paid", false, true),
258 ObjectLifecycleState::new("written_off", "Written Off", false, true),
259 ],
260 relationships: vec![
261 ObjectRelationshipType::new(
262 "references_so",
263 "References SO",
264 "sales_order",
265 Cardinality::ManyToOne,
266 false,
267 ),
268 ObjectRelationshipType::new(
269 "references_delivery",
270 "References Delivery",
271 "delivery",
272 Cardinality::ManyToMany,
273 false,
274 ),
275 ],
276 allowed_activities: vec![
277 "create_invoice".into(),
278 "post_invoice".into(),
279 "send_invoice".into(),
280 ],
281 attributes: HashMap::from([
282 ("invoice_number".into(), AttributeType::String),
283 ("customer_id".into(), AttributeType::String),
284 ("invoice_amount".into(), AttributeType::Decimal),
285 ]),
286 }
287 }
288
289 pub fn p2p_types() -> Vec<Self> {
291 vec![
292 Self::purchase_order(),
293 Self::goods_receipt(),
294 Self::vendor_invoice(),
295 ]
296 }
297
298 pub fn o2c_types() -> Vec<Self> {
300 vec![
301 Self::sales_order(),
302 Self::delivery(),
303 Self::customer_invoice(),
304 ]
305 }
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
310pub struct ObjectLifecycleState {
311 pub state_id: String,
313 pub name: String,
315 pub is_initial: bool,
317 pub is_terminal: bool,
319 pub valid_transitions: Vec<String>,
321}
322
323impl ObjectLifecycleState {
324 pub fn new(state_id: &str, name: &str, is_initial: bool, is_terminal: bool) -> Self {
326 Self {
327 state_id: state_id.into(),
328 name: name.into(),
329 is_initial,
330 is_terminal,
331 valid_transitions: Vec::new(),
332 }
333 }
334
335 pub fn with_transitions(mut self, transitions: Vec<&str>) -> Self {
337 self.valid_transitions = transitions.into_iter().map(String::from).collect();
338 self
339 }
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize)]
344pub struct ObjectRelationshipType {
345 pub relationship_id: String,
347 pub name: String,
349 pub target_type_id: String,
351 pub cardinality: Cardinality,
353 pub is_mandatory: bool,
355}
356
357impl ObjectRelationshipType {
358 pub fn new(
360 relationship_id: &str,
361 name: &str,
362 target_type_id: &str,
363 cardinality: Cardinality,
364 is_mandatory: bool,
365 ) -> Self {
366 Self {
367 relationship_id: relationship_id.into(),
368 name: name.into(),
369 target_type_id: target_type_id.into(),
370 cardinality,
371 is_mandatory,
372 }
373 }
374}
375
376#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
378#[serde(rename_all = "snake_case")]
379pub enum Cardinality {
380 OneToOne,
382 OneToMany,
384 ManyToOne,
386 ManyToMany,
388}
389
390#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
392#[serde(rename_all = "snake_case")]
393pub enum AttributeType {
394 String,
396 Integer,
398 Decimal,
400 Date,
402 DateTime,
404 Boolean,
406 Reference(String),
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413
414 #[test]
415 fn test_purchase_order_type() {
416 let po_type = ObjectType::purchase_order();
417 assert_eq!(po_type.type_id, "purchase_order");
418 assert_eq!(po_type.business_process, BusinessProcess::P2P);
419 assert!(!po_type.lifecycle_states.is_empty());
420 assert!(!po_type.relationships.is_empty());
421 }
422
423 #[test]
424 fn test_p2p_types() {
425 let types = ObjectType::p2p_types();
426 assert_eq!(types.len(), 3);
427 }
428
429 #[test]
430 fn test_o2c_types() {
431 let types = ObjectType::o2c_types();
432 assert_eq!(types.len(), 3);
433 }
434}