ringkernel_accnet/fabric/
company.rs

1//! Company archetypes for realistic synthetic data generation.
2//!
3//! Each archetype represents a distinct business model with unique
4//! financial characteristics, transaction patterns, and seasonality.
5
6use std::ops::Range;
7
8/// Industry classification for company archetypes.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum Industry {
11    /// Retail: High volume, low margins, seasonal peaks
12    Retail,
13    /// SaaS: Subscription revenue, deferred recognition
14    SaaS,
15    /// Manufacturing: Complex supply chain, WIP inventory
16    Manufacturing,
17    /// Professional Services: Time-based billing
18    ProfessionalServices,
19    /// Financial Services: Complex instruments
20    FinancialServices,
21    /// Healthcare: Insurance billing, regulatory compliance
22    Healthcare,
23    /// Construction: Project-based, progress billing
24    Construction,
25    /// Education: Tuition cycles, grant accounting
26    Education,
27}
28
29/// Company size classification.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub enum CompanySize {
32    /// Small: <$10M revenue, <50 employees
33    Small,
34    /// Medium: $10M-$100M revenue, 50-500 employees
35    Medium,
36    /// Large: $100M-$1B revenue, 500-5000 employees
37    Large,
38    /// Enterprise: >$1B revenue, >5000 employees
39    Enterprise,
40}
41
42impl CompanySize {
43    /// Typical account count for this size.
44    pub fn typical_account_count(&self) -> Range<usize> {
45        match self {
46            CompanySize::Small => 50..100,
47            CompanySize::Medium => 100..200,
48            CompanySize::Large => 200..400,
49            CompanySize::Enterprise => 400..800,
50        }
51    }
52
53    /// Typical daily transaction volume.
54    pub fn typical_daily_transactions(&self) -> Range<u32> {
55        match self {
56            CompanySize::Small => 10..100,
57            CompanySize::Medium => 100..500,
58            CompanySize::Large => 500..2000,
59            CompanySize::Enterprise => 2000..10000,
60        }
61    }
62}
63
64/// A company archetype defining financial behavior patterns.
65#[derive(Debug, Clone)]
66pub enum CompanyArchetype {
67    /// Retail business with physical/online stores.
68    Retail(RetailConfig),
69
70    /// Software-as-a-Service subscription business.
71    SaaS(SaaSConfig),
72
73    /// Manufacturing with supply chain and inventory.
74    Manufacturing(ManufacturingConfig),
75
76    /// Professional services (consulting, legal, accounting).
77    ProfessionalServices(ProfServicesConfig),
78
79    /// Financial services (banking, investment, insurance).
80    FinancialServices(FinServicesConfig),
81}
82
83/// Configuration for retail company archetype.
84#[derive(Debug, Clone)]
85pub struct RetailConfig {
86    /// Number of store locations
87    pub store_count: u32,
88    /// Average transaction value
89    pub avg_transaction: f64,
90    /// Months with seasonal peaks (1-12)
91    pub seasonal_peaks: Vec<u8>,
92    /// Online vs physical split (0.0 - 1.0 = % online)
93    pub online_ratio: f64,
94    /// Inventory turnover rate (times per year)
95    pub inventory_turnover: f64,
96    /// Gross margin percentage
97    pub gross_margin: f64,
98    /// Company size
99    pub size: CompanySize,
100}
101
102impl Default for RetailConfig {
103    fn default() -> Self {
104        Self {
105            store_count: 5,
106            avg_transaction: 75.0,
107            seasonal_peaks: vec![11, 12], // Nov-Dec holiday season
108            online_ratio: 0.3,
109            inventory_turnover: 6.0,
110            gross_margin: 0.35,
111            size: CompanySize::Medium,
112        }
113    }
114}
115
116/// Configuration for SaaS company archetype.
117#[derive(Debug, Clone)]
118pub struct SaaSConfig {
119    /// Monthly recurring revenue
120    pub mrr: f64,
121    /// Annual churn rate
122    pub churn_rate: f64,
123    /// Average contract length in months
124    pub contract_length_months: u32,
125    /// Mix of monthly vs annual contracts
126    pub annual_contract_ratio: f64,
127    /// Revenue recognition: point-in-time vs over-time
128    pub deferred_revenue_ratio: f64,
129    /// Company size
130    pub size: CompanySize,
131}
132
133impl Default for SaaSConfig {
134    fn default() -> Self {
135        Self {
136            mrr: 500_000.0,
137            churn_rate: 0.05,
138            contract_length_months: 12,
139            annual_contract_ratio: 0.6,
140            deferred_revenue_ratio: 0.8,
141            size: CompanySize::Medium,
142        }
143    }
144}
145
146/// Configuration for manufacturing company archetype.
147#[derive(Debug, Clone)]
148pub struct ManufacturingConfig {
149    /// Number of product lines
150    pub product_lines: u32,
151    /// Number of suppliers
152    pub supplier_count: u32,
153    /// Production cycles per month
154    pub production_cycles_per_month: u32,
155    /// Work-in-progress as % of inventory
156    pub wip_ratio: f64,
157    /// Raw materials lead time (days)
158    pub lead_time_days: u32,
159    /// Company size
160    pub size: CompanySize,
161}
162
163impl Default for ManufacturingConfig {
164    fn default() -> Self {
165        Self {
166            product_lines: 3,
167            supplier_count: 25,
168            production_cycles_per_month: 4,
169            wip_ratio: 0.3,
170            lead_time_days: 30,
171            size: CompanySize::Large,
172        }
173    }
174}
175
176/// Configuration for professional services archetype.
177#[derive(Debug, Clone)]
178pub struct ProfServicesConfig {
179    /// Number of billable employees
180    pub billable_headcount: u32,
181    /// Average hourly billing rate
182    pub avg_hourly_rate: f64,
183    /// Target utilization rate
184    pub utilization_target: f64,
185    /// Average project duration (days)
186    pub avg_project_duration: u32,
187    /// % of work billed on completion vs progress
188    pub completion_billing_ratio: f64,
189    /// Company size
190    pub size: CompanySize,
191}
192
193impl Default for ProfServicesConfig {
194    fn default() -> Self {
195        Self {
196            billable_headcount: 50,
197            avg_hourly_rate: 200.0,
198            utilization_target: 0.75,
199            avg_project_duration: 45,
200            completion_billing_ratio: 0.4,
201            size: CompanySize::Medium,
202        }
203    }
204}
205
206/// Configuration for financial services archetype.
207#[derive(Debug, Clone)]
208pub struct FinServicesConfig {
209    /// Assets under management
210    pub aum: f64,
211    /// Number of product types
212    pub product_type_count: u32,
213    /// Intercompany transaction ratio
214    pub intercompany_ratio: f64,
215    /// Regulatory capital ratio
216    pub capital_ratio: f64,
217    /// Company size
218    pub size: CompanySize,
219}
220
221impl Default for FinServicesConfig {
222    fn default() -> Self {
223        Self {
224            aum: 1_000_000_000.0,
225            product_type_count: 5,
226            intercompany_ratio: 0.15,
227            capital_ratio: 0.12,
228            size: CompanySize::Large,
229        }
230    }
231}
232
233impl CompanyArchetype {
234    /// Create a standard retail company.
235    pub fn retail_standard() -> Self {
236        Self::Retail(RetailConfig::default())
237    }
238
239    /// Create a small retail company.
240    pub fn retail_small() -> Self {
241        Self::Retail(RetailConfig {
242            store_count: 1,
243            avg_transaction: 50.0,
244            size: CompanySize::Small,
245            ..Default::default()
246        })
247    }
248
249    /// Create a standard SaaS company.
250    pub fn saas_standard() -> Self {
251        Self::SaaS(SaaSConfig::default())
252    }
253
254    /// Create a startup SaaS company.
255    pub fn saas_startup() -> Self {
256        Self::SaaS(SaaSConfig {
257            mrr: 50_000.0,
258            churn_rate: 0.08,
259            size: CompanySize::Small,
260            ..Default::default()
261        })
262    }
263
264    /// Create a standard manufacturing company.
265    pub fn manufacturing_standard() -> Self {
266        Self::Manufacturing(ManufacturingConfig::default())
267    }
268
269    /// Create a standard professional services company.
270    pub fn professional_services_standard() -> Self {
271        Self::ProfessionalServices(ProfServicesConfig::default())
272    }
273
274    /// Create a standard financial services company.
275    pub fn financial_services_standard() -> Self {
276        Self::FinancialServices(FinServicesConfig::default())
277    }
278
279    /// Get the industry for this archetype.
280    pub fn industry(&self) -> Industry {
281        match self {
282            CompanyArchetype::Retail(_) => Industry::Retail,
283            CompanyArchetype::SaaS(_) => Industry::SaaS,
284            CompanyArchetype::Manufacturing(_) => Industry::Manufacturing,
285            CompanyArchetype::ProfessionalServices(_) => Industry::ProfessionalServices,
286            CompanyArchetype::FinancialServices(_) => Industry::FinancialServices,
287        }
288    }
289
290    /// Get the company size.
291    pub fn size(&self) -> CompanySize {
292        match self {
293            CompanyArchetype::Retail(c) => c.size,
294            CompanyArchetype::SaaS(c) => c.size,
295            CompanyArchetype::Manufacturing(c) => c.size,
296            CompanyArchetype::ProfessionalServices(c) => c.size,
297            CompanyArchetype::FinancialServices(c) => c.size,
298        }
299    }
300
301    /// Get display name for this archetype.
302    pub fn display_name(&self) -> &'static str {
303        match self {
304            CompanyArchetype::Retail(_) => "Retail",
305            CompanyArchetype::SaaS(_) => "SaaS",
306            CompanyArchetype::Manufacturing(_) => "Manufacturing",
307            CompanyArchetype::ProfessionalServices(_) => "Professional Services",
308            CompanyArchetype::FinancialServices(_) => "Financial Services",
309        }
310    }
311
312    /// Get a brief description.
313    pub fn description(&self) -> &'static str {
314        match self {
315            CompanyArchetype::Retail(_) => {
316                "High-volume retail with inventory management and seasonal patterns"
317            }
318            CompanyArchetype::SaaS(_) => {
319                "Subscription software with deferred revenue and monthly billing cycles"
320            }
321            CompanyArchetype::Manufacturing(_) => {
322                "Manufacturing with supply chain, WIP inventory, and production cycles"
323            }
324            CompanyArchetype::ProfessionalServices(_) => {
325                "Time-based billing with utilization tracking and project accounting"
326            }
327            CompanyArchetype::FinancialServices(_) => {
328                "Complex financial instruments with intercompany transactions"
329            }
330        }
331    }
332
333    /// Get typical transaction patterns for this archetype.
334    pub fn transaction_patterns(&self) -> Vec<TransactionPattern> {
335        match self {
336            CompanyArchetype::Retail(_) => vec![
337                TransactionPattern::new("Sales", 0.40, 50.0..500.0),
338                TransactionPattern::new("Inventory Purchase", 0.25, 500.0..10000.0),
339                TransactionPattern::new("Payroll", 0.10, 5000.0..50000.0),
340                TransactionPattern::new("Rent", 0.05, 2000.0..20000.0),
341                TransactionPattern::new("Utilities", 0.05, 200.0..2000.0),
342                TransactionPattern::new("Marketing", 0.05, 100.0..5000.0),
343                TransactionPattern::new("Returns", 0.05, 20.0..200.0),
344                TransactionPattern::new("Other", 0.05, 50.0..1000.0),
345            ],
346            CompanyArchetype::SaaS(_) => vec![
347                TransactionPattern::new("Subscription Revenue", 0.30, 50.0..5000.0),
348                TransactionPattern::new("Deferred Revenue Recog", 0.25, 100.0..10000.0),
349                TransactionPattern::new("Payroll", 0.20, 10000.0..100000.0),
350                TransactionPattern::new("Cloud Infrastructure", 0.10, 1000.0..50000.0),
351                TransactionPattern::new("Marketing", 0.08, 500.0..20000.0),
352                TransactionPattern::new("Refunds", 0.02, 50.0..500.0),
353                TransactionPattern::new("Other", 0.05, 100.0..2000.0),
354            ],
355            CompanyArchetype::Manufacturing(_) => vec![
356                TransactionPattern::new("Raw Materials", 0.30, 1000.0..100000.0),
357                TransactionPattern::new("WIP Transfer", 0.20, 500.0..50000.0),
358                TransactionPattern::new("Finished Goods Sale", 0.15, 1000.0..50000.0),
359                TransactionPattern::new("Payroll", 0.15, 20000.0..200000.0),
360                TransactionPattern::new("Equipment Depreciation", 0.05, 1000.0..20000.0),
361                TransactionPattern::new("Utilities", 0.05, 5000.0..30000.0),
362                TransactionPattern::new("Maintenance", 0.05, 500.0..10000.0),
363                TransactionPattern::new("Other", 0.05, 200.0..5000.0),
364            ],
365            CompanyArchetype::ProfessionalServices(_) => vec![
366                TransactionPattern::new("Time Billing", 0.35, 500.0..50000.0),
367                TransactionPattern::new("Expense Reimbursement", 0.15, 100.0..5000.0),
368                TransactionPattern::new("Payroll", 0.25, 15000.0..150000.0),
369                TransactionPattern::new("Rent", 0.08, 5000.0..50000.0),
370                TransactionPattern::new("Professional Development", 0.05, 200.0..5000.0),
371                TransactionPattern::new("Insurance", 0.05, 1000.0..10000.0),
372                TransactionPattern::new("Other", 0.07, 100.0..2000.0),
373            ],
374            CompanyArchetype::FinancialServices(_) => vec![
375                TransactionPattern::new("Investment Transaction", 0.25, 10000.0..1000000.0),
376                TransactionPattern::new("Fee Revenue", 0.15, 100.0..50000.0),
377                TransactionPattern::new("Interest Income", 0.15, 1000.0..100000.0),
378                TransactionPattern::new("Intercompany Transfer", 0.15, 50000.0..5000000.0),
379                TransactionPattern::new("Payroll", 0.10, 50000.0..500000.0),
380                TransactionPattern::new("Regulatory Reserve", 0.10, 10000.0..500000.0),
381                TransactionPattern::new("Other", 0.10, 500.0..10000.0),
382            ],
383        }
384    }
385
386    /// Get seasonal multipliers by month (1-12).
387    pub fn seasonal_multipliers(&self) -> [f64; 12] {
388        match self {
389            CompanyArchetype::Retail(config) => {
390                let mut mults = [1.0; 12];
391                // Apply peaks
392                for &peak_month in &config.seasonal_peaks {
393                    if (1..=12).contains(&peak_month) {
394                        mults[(peak_month - 1) as usize] = 2.5;
395                        // Adjacent months get smaller boost
396                        if peak_month > 1 {
397                            mults[(peak_month - 2) as usize] *= 1.5;
398                        }
399                    }
400                }
401                // January typically slow after holidays
402                mults[0] = 0.7;
403                mults
404            }
405            CompanyArchetype::SaaS(_) => {
406                // Relatively flat with Q4 push and year-end renewals
407                [1.0, 1.0, 1.1, 1.0, 1.0, 1.1, 1.0, 1.0, 1.1, 1.0, 1.1, 1.3]
408            }
409            CompanyArchetype::Manufacturing(_) => {
410                // Production cycles, quieter in summer
411                [1.0, 1.1, 1.2, 1.1, 1.0, 0.9, 0.8, 0.8, 1.0, 1.1, 1.2, 1.0]
412            }
413            CompanyArchetype::ProfessionalServices(_) => {
414                // Busy in Q1 (audits), slower in summer
415                [1.3, 1.2, 1.1, 1.0, 1.0, 0.9, 0.8, 0.8, 1.0, 1.0, 1.0, 0.9]
416            }
417            CompanyArchetype::FinancialServices(_) => {
418                // Quarter-end spikes
419                [1.0, 1.0, 1.4, 1.0, 1.0, 1.4, 1.0, 1.0, 1.4, 1.0, 1.0, 1.5]
420            }
421        }
422    }
423}
424
425/// A transaction pattern with frequency and amount range.
426#[derive(Debug, Clone)]
427pub struct TransactionPattern {
428    /// Pattern name
429    pub name: String,
430    /// Relative frequency (0.0 - 1.0, should sum to 1.0)
431    pub frequency: f64,
432    /// Amount range
433    pub amount_range: Range<f64>,
434}
435
436impl TransactionPattern {
437    /// Create a new transaction pattern.
438    pub fn new(name: impl Into<String>, frequency: f64, amount_range: Range<f64>) -> Self {
439        Self {
440            name: name.into(),
441            frequency,
442            amount_range,
443        }
444    }
445}
446
447#[cfg(test)]
448mod tests {
449    use super::*;
450
451    #[test]
452    fn test_retail_archetype() {
453        let retail = CompanyArchetype::retail_standard();
454        assert_eq!(retail.industry(), Industry::Retail);
455        assert_eq!(retail.size(), CompanySize::Medium);
456
457        let patterns = retail.transaction_patterns();
458        let total_freq: f64 = patterns.iter().map(|p| p.frequency).sum();
459        assert!((total_freq - 1.0).abs() < 0.01);
460    }
461
462    #[test]
463    fn test_seasonal_multipliers() {
464        let retail = CompanyArchetype::retail_standard();
465        let mults = retail.seasonal_multipliers();
466
467        // November and December should be peaks
468        assert!(mults[10] > 1.5); // November
469        assert!(mults[11] > 2.0); // December
470                                  // January should be low
471        assert!(mults[0] < 1.0);
472    }
473
474    #[test]
475    fn test_company_sizes() {
476        assert!(CompanySize::Small.typical_account_count().start < 100);
477        assert!(CompanySize::Enterprise.typical_daily_transactions().end >= 10000);
478    }
479}