use std::ops::Range;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Industry {
Retail,
SaaS,
Manufacturing,
ProfessionalServices,
FinancialServices,
Healthcare,
Construction,
Education,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CompanySize {
Small,
Medium,
Large,
Enterprise,
}
impl CompanySize {
pub fn typical_account_count(&self) -> Range<usize> {
match self {
CompanySize::Small => 50..100,
CompanySize::Medium => 100..200,
CompanySize::Large => 200..400,
CompanySize::Enterprise => 400..800,
}
}
pub fn typical_daily_transactions(&self) -> Range<u32> {
match self {
CompanySize::Small => 10..100,
CompanySize::Medium => 100..500,
CompanySize::Large => 500..2000,
CompanySize::Enterprise => 2000..10000,
}
}
}
#[derive(Debug, Clone)]
pub enum CompanyArchetype {
Retail(RetailConfig),
SaaS(SaaSConfig),
Manufacturing(ManufacturingConfig),
ProfessionalServices(ProfServicesConfig),
FinancialServices(FinServicesConfig),
}
#[derive(Debug, Clone)]
pub struct RetailConfig {
pub store_count: u32,
pub avg_transaction: f64,
pub seasonal_peaks: Vec<u8>,
pub online_ratio: f64,
pub inventory_turnover: f64,
pub gross_margin: f64,
pub size: CompanySize,
}
impl Default for RetailConfig {
fn default() -> Self {
Self {
store_count: 5,
avg_transaction: 75.0,
seasonal_peaks: vec![11, 12], online_ratio: 0.3,
inventory_turnover: 6.0,
gross_margin: 0.35,
size: CompanySize::Medium,
}
}
}
#[derive(Debug, Clone)]
pub struct SaaSConfig {
pub mrr: f64,
pub churn_rate: f64,
pub contract_length_months: u32,
pub annual_contract_ratio: f64,
pub deferred_revenue_ratio: f64,
pub size: CompanySize,
}
impl Default for SaaSConfig {
fn default() -> Self {
Self {
mrr: 500_000.0,
churn_rate: 0.05,
contract_length_months: 12,
annual_contract_ratio: 0.6,
deferred_revenue_ratio: 0.8,
size: CompanySize::Medium,
}
}
}
#[derive(Debug, Clone)]
pub struct ManufacturingConfig {
pub product_lines: u32,
pub supplier_count: u32,
pub production_cycles_per_month: u32,
pub wip_ratio: f64,
pub lead_time_days: u32,
pub size: CompanySize,
}
impl Default for ManufacturingConfig {
fn default() -> Self {
Self {
product_lines: 3,
supplier_count: 25,
production_cycles_per_month: 4,
wip_ratio: 0.3,
lead_time_days: 30,
size: CompanySize::Large,
}
}
}
#[derive(Debug, Clone)]
pub struct ProfServicesConfig {
pub billable_headcount: u32,
pub avg_hourly_rate: f64,
pub utilization_target: f64,
pub avg_project_duration: u32,
pub completion_billing_ratio: f64,
pub size: CompanySize,
}
impl Default for ProfServicesConfig {
fn default() -> Self {
Self {
billable_headcount: 50,
avg_hourly_rate: 200.0,
utilization_target: 0.75,
avg_project_duration: 45,
completion_billing_ratio: 0.4,
size: CompanySize::Medium,
}
}
}
#[derive(Debug, Clone)]
pub struct FinServicesConfig {
pub aum: f64,
pub product_type_count: u32,
pub intercompany_ratio: f64,
pub capital_ratio: f64,
pub size: CompanySize,
}
impl Default for FinServicesConfig {
fn default() -> Self {
Self {
aum: 1_000_000_000.0,
product_type_count: 5,
intercompany_ratio: 0.15,
capital_ratio: 0.12,
size: CompanySize::Large,
}
}
}
impl CompanyArchetype {
pub fn retail_standard() -> Self {
Self::Retail(RetailConfig::default())
}
pub fn retail_small() -> Self {
Self::Retail(RetailConfig {
store_count: 1,
avg_transaction: 50.0,
size: CompanySize::Small,
..Default::default()
})
}
pub fn saas_standard() -> Self {
Self::SaaS(SaaSConfig::default())
}
pub fn saas_startup() -> Self {
Self::SaaS(SaaSConfig {
mrr: 50_000.0,
churn_rate: 0.08,
size: CompanySize::Small,
..Default::default()
})
}
pub fn manufacturing_standard() -> Self {
Self::Manufacturing(ManufacturingConfig::default())
}
pub fn professional_services_standard() -> Self {
Self::ProfessionalServices(ProfServicesConfig::default())
}
pub fn financial_services_standard() -> Self {
Self::FinancialServices(FinServicesConfig::default())
}
pub fn industry(&self) -> Industry {
match self {
CompanyArchetype::Retail(_) => Industry::Retail,
CompanyArchetype::SaaS(_) => Industry::SaaS,
CompanyArchetype::Manufacturing(_) => Industry::Manufacturing,
CompanyArchetype::ProfessionalServices(_) => Industry::ProfessionalServices,
CompanyArchetype::FinancialServices(_) => Industry::FinancialServices,
}
}
pub fn size(&self) -> CompanySize {
match self {
CompanyArchetype::Retail(c) => c.size,
CompanyArchetype::SaaS(c) => c.size,
CompanyArchetype::Manufacturing(c) => c.size,
CompanyArchetype::ProfessionalServices(c) => c.size,
CompanyArchetype::FinancialServices(c) => c.size,
}
}
pub fn display_name(&self) -> &'static str {
match self {
CompanyArchetype::Retail(_) => "Retail",
CompanyArchetype::SaaS(_) => "SaaS",
CompanyArchetype::Manufacturing(_) => "Manufacturing",
CompanyArchetype::ProfessionalServices(_) => "Professional Services",
CompanyArchetype::FinancialServices(_) => "Financial Services",
}
}
pub fn description(&self) -> &'static str {
match self {
CompanyArchetype::Retail(_) => {
"High-volume retail with inventory management and seasonal patterns"
}
CompanyArchetype::SaaS(_) => {
"Subscription software with deferred revenue and monthly billing cycles"
}
CompanyArchetype::Manufacturing(_) => {
"Manufacturing with supply chain, WIP inventory, and production cycles"
}
CompanyArchetype::ProfessionalServices(_) => {
"Time-based billing with utilization tracking and project accounting"
}
CompanyArchetype::FinancialServices(_) => {
"Complex financial instruments with intercompany transactions"
}
}
}
pub fn transaction_patterns(&self) -> Vec<TransactionPattern> {
match self {
CompanyArchetype::Retail(_) => vec![
TransactionPattern::new("Sales", 0.40, 50.0..500.0),
TransactionPattern::new("Inventory Purchase", 0.25, 500.0..10000.0),
TransactionPattern::new("Payroll", 0.10, 5000.0..50000.0),
TransactionPattern::new("Rent", 0.05, 2000.0..20000.0),
TransactionPattern::new("Utilities", 0.05, 200.0..2000.0),
TransactionPattern::new("Marketing", 0.05, 100.0..5000.0),
TransactionPattern::new("Returns", 0.05, 20.0..200.0),
TransactionPattern::new("Other", 0.05, 50.0..1000.0),
],
CompanyArchetype::SaaS(_) => vec![
TransactionPattern::new("Subscription Revenue", 0.30, 50.0..5000.0),
TransactionPattern::new("Deferred Revenue Recog", 0.25, 100.0..10000.0),
TransactionPattern::new("Payroll", 0.20, 10000.0..100000.0),
TransactionPattern::new("Cloud Infrastructure", 0.10, 1000.0..50000.0),
TransactionPattern::new("Marketing", 0.08, 500.0..20000.0),
TransactionPattern::new("Refunds", 0.02, 50.0..500.0),
TransactionPattern::new("Other", 0.05, 100.0..2000.0),
],
CompanyArchetype::Manufacturing(_) => vec![
TransactionPattern::new("Raw Materials", 0.30, 1000.0..100000.0),
TransactionPattern::new("WIP Transfer", 0.20, 500.0..50000.0),
TransactionPattern::new("Finished Goods Sale", 0.15, 1000.0..50000.0),
TransactionPattern::new("Payroll", 0.15, 20000.0..200000.0),
TransactionPattern::new("Equipment Depreciation", 0.05, 1000.0..20000.0),
TransactionPattern::new("Utilities", 0.05, 5000.0..30000.0),
TransactionPattern::new("Maintenance", 0.05, 500.0..10000.0),
TransactionPattern::new("Other", 0.05, 200.0..5000.0),
],
CompanyArchetype::ProfessionalServices(_) => vec![
TransactionPattern::new("Time Billing", 0.35, 500.0..50000.0),
TransactionPattern::new("Expense Reimbursement", 0.15, 100.0..5000.0),
TransactionPattern::new("Payroll", 0.25, 15000.0..150000.0),
TransactionPattern::new("Rent", 0.08, 5000.0..50000.0),
TransactionPattern::new("Professional Development", 0.05, 200.0..5000.0),
TransactionPattern::new("Insurance", 0.05, 1000.0..10000.0),
TransactionPattern::new("Other", 0.07, 100.0..2000.0),
],
CompanyArchetype::FinancialServices(_) => vec![
TransactionPattern::new("Investment Transaction", 0.25, 10000.0..1000000.0),
TransactionPattern::new("Fee Revenue", 0.15, 100.0..50000.0),
TransactionPattern::new("Interest Income", 0.15, 1000.0..100000.0),
TransactionPattern::new("Intercompany Transfer", 0.15, 50000.0..5000000.0),
TransactionPattern::new("Payroll", 0.10, 50000.0..500000.0),
TransactionPattern::new("Regulatory Reserve", 0.10, 10000.0..500000.0),
TransactionPattern::new("Other", 0.10, 500.0..10000.0),
],
}
}
pub fn seasonal_multipliers(&self) -> [f64; 12] {
match self {
CompanyArchetype::Retail(config) => {
let mut mults = [1.0; 12];
for &peak_month in &config.seasonal_peaks {
if (1..=12).contains(&peak_month) {
mults[(peak_month - 1) as usize] = 2.5;
if peak_month > 1 {
mults[(peak_month - 2) as usize] *= 1.5;
}
}
}
mults[0] = 0.7;
mults
}
CompanyArchetype::SaaS(_) => {
[1.0, 1.0, 1.1, 1.0, 1.0, 1.1, 1.0, 1.0, 1.1, 1.0, 1.1, 1.3]
}
CompanyArchetype::Manufacturing(_) => {
[1.0, 1.1, 1.2, 1.1, 1.0, 0.9, 0.8, 0.8, 1.0, 1.1, 1.2, 1.0]
}
CompanyArchetype::ProfessionalServices(_) => {
[1.3, 1.2, 1.1, 1.0, 1.0, 0.9, 0.8, 0.8, 1.0, 1.0, 1.0, 0.9]
}
CompanyArchetype::FinancialServices(_) => {
[1.0, 1.0, 1.4, 1.0, 1.0, 1.4, 1.0, 1.0, 1.4, 1.0, 1.0, 1.5]
}
}
}
}
#[derive(Debug, Clone)]
pub struct TransactionPattern {
pub name: String,
pub frequency: f64,
pub amount_range: Range<f64>,
}
impl TransactionPattern {
pub fn new(name: impl Into<String>, frequency: f64, amount_range: Range<f64>) -> Self {
Self {
name: name.into(),
frequency,
amount_range,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_retail_archetype() {
let retail = CompanyArchetype::retail_standard();
assert_eq!(retail.industry(), Industry::Retail);
assert_eq!(retail.size(), CompanySize::Medium);
let patterns = retail.transaction_patterns();
let total_freq: f64 = patterns.iter().map(|p| p.frequency).sum();
assert!((total_freq - 1.0).abs() < 0.01);
}
#[test]
fn test_seasonal_multipliers() {
let retail = CompanyArchetype::retail_standard();
let mults = retail.seasonal_multipliers();
assert!(mults[10] > 1.5); assert!(mults[11] > 2.0); assert!(mults[0] < 1.0);
}
#[test]
fn test_company_sizes() {
assert!(CompanySize::Small.typical_account_count().start < 100);
assert!(CompanySize::Enterprise.typical_daily_transactions().end >= 10000);
}
}