ringkernel_txmon/factory/
accounts.rs1use crate::types::{CustomerRiskLevel, CustomerRiskProfile};
4use rand::prelude::*;
5use rand::rngs::SmallRng;
6
7pub struct AccountGenerator {
9 rng: SmallRng,
10 next_id: u64,
11}
12
13impl AccountGenerator {
14 pub fn new(seed: u64) -> Self {
16 Self {
17 rng: SmallRng::seed_from_u64(seed),
18 next_id: 1,
19 }
20 }
21
22 pub fn generate_customers(&mut self, count: u32) -> Vec<CustomerRiskProfile> {
24 (0..count).map(|_| self.generate_customer()).collect()
25 }
26
27 pub fn generate_customer(&mut self) -> CustomerRiskProfile {
29 let customer_id = self.next_id;
30 self.next_id += 1;
31
32 let country_code = self.random_country();
34
35 let mut profile = CustomerRiskProfile::new(customer_id, country_code);
36
37 let risk_roll: f32 = self.rng.gen();
39 profile.risk_level = if risk_roll < 0.70 {
40 CustomerRiskLevel::Low as u8
41 } else if risk_roll < 0.90 {
42 CustomerRiskLevel::Medium as u8
43 } else if risk_roll < 0.98 {
44 CustomerRiskLevel::High as u8
45 } else {
46 CustomerRiskLevel::Prohibited as u8
47 };
48
49 profile.risk_score = match CustomerRiskLevel::from_u8(profile.risk_level).unwrap() {
51 CustomerRiskLevel::Low => self.rng.gen_range(5..30),
52 CustomerRiskLevel::Medium => self.rng.gen_range(30..60),
53 CustomerRiskLevel::High => self.rng.gen_range(60..85),
54 CustomerRiskLevel::Prohibited => self.rng.gen_range(85..100),
55 };
56
57 profile.is_pep = 0; let edd_chance = if profile.risk_level >= CustomerRiskLevel::High as u8 {
63 0.30
64 } else {
65 0.05
66 };
67 profile.requires_edd = if self.rng.gen::<f32>() < edd_chance {
68 1
69 } else {
70 0
71 };
72
73 profile.has_adverse_media = if self.rng.gen::<f32>() < 0.02 { 1 } else { 0 };
75
76 profile.geographic_risk = self.rng.gen_range(5..50);
78 profile.business_risk = self.rng.gen_range(5..50);
79 profile.behavioral_risk = self.rng.gen_range(5..50);
80
81 if self.rng.gen::<f32>() < 0.1 {
83 profile.amount_threshold = self.rng.gen_range(500_000..5_000_000);
85 }
86 if self.rng.gen::<f32>() < 0.1 {
87 profile.velocity_threshold = self.rng.gen_range(5..50);
89 }
90
91 profile.allowed_destinations = !0; profile.avg_monthly_volume = self.rng.gen_range(100_000..50_000_000);
98
99 let now_ms = std::time::SystemTime::now()
101 .duration_since(std::time::UNIX_EPOCH)
102 .unwrap()
103 .as_millis() as u64;
104 let one_year_ms = 365 * 24 * 60 * 60 * 1000;
105 profile.created_ts = now_ms - self.rng.gen_range(0..one_year_ms);
106
107 profile
108 }
109
110 fn random_country(&mut self) -> u16 {
112 let roll: f32 = self.rng.gen();
114 if roll < 0.60 {
115 1 } else if roll < 0.70 {
117 2 } else {
119 self.rng.gen_range(3..16)
121 }
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128
129 #[test]
130 fn test_generate_customers() {
131 let mut gen = AccountGenerator::new(42);
132 let customers = gen.generate_customers(100);
133
134 assert_eq!(customers.len(), 100);
135
136 for (i, c) in customers.iter().enumerate() {
138 assert_eq!(c.customer_id, (i + 1) as u64);
139 }
140
141 let low_count = customers
143 .iter()
144 .filter(|c| c.risk_level == CustomerRiskLevel::Low as u8)
145 .count();
146 assert!(low_count > 50); }
148
149 #[test]
150 fn test_pep_disabled_by_default() {
151 let mut gen = AccountGenerator::new(42);
152 let customers = gen.generate_customers(1000);
153
154 let pep_count = customers.iter().filter(|c| c.is_pep != 0).count();
155 assert_eq!(pep_count, 0);
157 }
158}