1use datasynth_core::distributions::{
4 AmountDistributionConfig, DebitCreditDistributionConfig, EvenOddDistributionConfig,
5 LineItemDistributionConfig, SeasonalityConfig,
6};
7use datasynth_core::models::{CoAComplexity, IndustrySector};
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct GeneratorConfig {
14 pub global: GlobalConfig,
16 pub companies: Vec<CompanyConfig>,
18 pub chart_of_accounts: ChartOfAccountsConfig,
20 #[serde(default)]
22 pub transactions: TransactionConfig,
23 pub output: OutputConfig,
25 #[serde(default)]
27 pub fraud: FraudConfig,
28 #[serde(default)]
30 pub data_quality: DataQualitySchemaConfig,
31 #[serde(default)]
33 pub internal_controls: InternalControlsConfig,
34 #[serde(default)]
36 pub business_processes: BusinessProcessConfig,
37 #[serde(default)]
39 pub user_personas: UserPersonaConfig,
40 #[serde(default)]
42 pub templates: TemplateConfig,
43 #[serde(default)]
45 pub approval: ApprovalConfig,
46 #[serde(default)]
48 pub departments: DepartmentConfig,
49 #[serde(default)]
51 pub master_data: MasterDataConfig,
52 #[serde(default)]
54 pub document_flows: DocumentFlowConfig,
55 #[serde(default)]
57 pub intercompany: IntercompanyConfig,
58 #[serde(default)]
60 pub balance: BalanceConfig,
61 #[serde(default)]
63 pub ocpm: OcpmConfig,
64 #[serde(default)]
66 pub audit: AuditGenerationConfig,
67 #[serde(default)]
69 pub banking: datasynth_banking::BankingConfig,
70 #[serde(default)]
72 pub scenario: ScenarioConfig,
73 #[serde(default)]
75 pub temporal: TemporalDriftConfig,
76 #[serde(default)]
78 pub graph_export: GraphExportConfig,
79 #[serde(default)]
81 pub streaming: StreamingSchemaConfig,
82 #[serde(default)]
84 pub rate_limit: RateLimitSchemaConfig,
85 #[serde(default)]
87 pub temporal_attributes: TemporalAttributeSchemaConfig,
88 #[serde(default)]
90 pub relationships: RelationshipSchemaConfig,
91 #[serde(default)]
93 pub accounting_standards: AccountingStandardsConfig,
94 #[serde(default)]
96 pub audit_standards: AuditStandardsConfig,
97 #[serde(default)]
99 pub distributions: AdvancedDistributionConfig,
100 #[serde(default)]
102 pub temporal_patterns: TemporalPatternsConfig,
103 #[serde(default)]
105 pub vendor_network: VendorNetworkSchemaConfig,
106 #[serde(default)]
108 pub customer_segmentation: CustomerSegmentationSchemaConfig,
109 #[serde(default)]
111 pub relationship_strength: RelationshipStrengthSchemaConfig,
112 #[serde(default)]
114 pub cross_process_links: CrossProcessLinksSchemaConfig,
115 #[serde(default)]
117 pub organizational_events: OrganizationalEventsSchemaConfig,
118 #[serde(default)]
120 pub behavioral_drift: BehavioralDriftSchemaConfig,
121 #[serde(default)]
123 pub market_drift: MarketDriftSchemaConfig,
124 #[serde(default)]
126 pub drift_labeling: DriftLabelingSchemaConfig,
127 #[serde(default)]
129 pub anomaly_injection: EnhancedAnomalyConfig,
130 #[serde(default)]
132 pub industry_specific: IndustrySpecificConfig,
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct GraphExportConfig {
143 #[serde(default)]
145 pub enabled: bool,
146
147 #[serde(default = "default_graph_types")]
149 pub graph_types: Vec<GraphTypeConfig>,
150
151 #[serde(default = "default_graph_formats")]
153 pub formats: Vec<GraphExportFormat>,
154
155 #[serde(default = "default_train_ratio")]
157 pub train_ratio: f64,
158
159 #[serde(default = "default_val_ratio")]
161 pub validation_ratio: f64,
162
163 #[serde(default)]
165 pub split_seed: Option<u64>,
166
167 #[serde(default = "default_graph_subdir")]
169 pub output_subdirectory: String,
170
171 #[serde(default)]
173 pub hypergraph: HypergraphExportSettings,
174}
175
176fn default_graph_types() -> Vec<GraphTypeConfig> {
177 vec![GraphTypeConfig::default()]
178}
179
180fn default_graph_formats() -> Vec<GraphExportFormat> {
181 vec![GraphExportFormat::PytorchGeometric]
182}
183
184fn default_train_ratio() -> f64 {
185 0.7
186}
187
188fn default_val_ratio() -> f64 {
189 0.15
190}
191
192fn default_graph_subdir() -> String {
193 "graphs".to_string()
194}
195
196impl Default for GraphExportConfig {
197 fn default() -> Self {
198 Self {
199 enabled: false,
200 graph_types: default_graph_types(),
201 formats: default_graph_formats(),
202 train_ratio: 0.7,
203 validation_ratio: 0.15,
204 split_seed: None,
205 output_subdirectory: "graphs".to_string(),
206 hypergraph: HypergraphExportSettings::default(),
207 }
208 }
209}
210
211#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct HypergraphExportSettings {
219 #[serde(default)]
221 pub enabled: bool,
222
223 #[serde(default = "default_hypergraph_max_nodes")]
225 pub max_nodes: usize,
226
227 #[serde(default = "default_aggregation_strategy")]
229 pub aggregation_strategy: String,
230
231 #[serde(default)]
233 pub governance_layer: GovernanceLayerSettings,
234
235 #[serde(default)]
237 pub process_layer: ProcessLayerSettings,
238
239 #[serde(default)]
241 pub accounting_layer: AccountingLayerSettings,
242
243 #[serde(default)]
245 pub cross_layer: CrossLayerSettings,
246
247 #[serde(default = "default_hypergraph_subdir")]
249 pub output_subdirectory: String,
250
251 #[serde(default = "default_hypergraph_format")]
253 pub output_format: String,
254
255 #[serde(default)]
257 pub stream_target: Option<String>,
258
259 #[serde(default = "default_stream_batch_size")]
261 pub stream_batch_size: usize,
262}
263
264fn default_hypergraph_max_nodes() -> usize {
265 50_000
266}
267
268fn default_aggregation_strategy() -> String {
269 "pool_by_counterparty".to_string()
270}
271
272fn default_hypergraph_subdir() -> String {
273 "hypergraph".to_string()
274}
275
276fn default_hypergraph_format() -> String {
277 "native".to_string()
278}
279
280fn default_stream_batch_size() -> usize {
281 1000
282}
283
284impl Default for HypergraphExportSettings {
285 fn default() -> Self {
286 Self {
287 enabled: false,
288 max_nodes: 50_000,
289 aggregation_strategy: "pool_by_counterparty".to_string(),
290 governance_layer: GovernanceLayerSettings::default(),
291 process_layer: ProcessLayerSettings::default(),
292 accounting_layer: AccountingLayerSettings::default(),
293 cross_layer: CrossLayerSettings::default(),
294 output_subdirectory: "hypergraph".to_string(),
295 output_format: "native".to_string(),
296 stream_target: None,
297 stream_batch_size: 1000,
298 }
299 }
300}
301
302#[derive(Debug, Clone, Serialize, Deserialize)]
304pub struct GovernanceLayerSettings {
305 #[serde(default = "default_true")]
307 pub include_coso: bool,
308 #[serde(default = "default_true")]
310 pub include_controls: bool,
311 #[serde(default = "default_true")]
313 pub include_sox: bool,
314 #[serde(default = "default_true")]
316 pub include_vendors: bool,
317 #[serde(default = "default_true")]
319 pub include_customers: bool,
320 #[serde(default = "default_true")]
322 pub include_employees: bool,
323}
324
325impl Default for GovernanceLayerSettings {
326 fn default() -> Self {
327 Self {
328 include_coso: true,
329 include_controls: true,
330 include_sox: true,
331 include_vendors: true,
332 include_customers: true,
333 include_employees: true,
334 }
335 }
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
340pub struct ProcessLayerSettings {
341 #[serde(default = "default_true")]
343 pub include_p2p: bool,
344 #[serde(default = "default_true")]
346 pub include_o2c: bool,
347 #[serde(default = "default_true")]
349 pub events_as_hyperedges: bool,
350 #[serde(default = "default_docs_per_counterparty_threshold")]
352 pub docs_per_counterparty_threshold: usize,
353}
354
355fn default_docs_per_counterparty_threshold() -> usize {
356 20
357}
358
359impl Default for ProcessLayerSettings {
360 fn default() -> Self {
361 Self {
362 include_p2p: true,
363 include_o2c: true,
364 events_as_hyperedges: true,
365 docs_per_counterparty_threshold: 20,
366 }
367 }
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
372pub struct AccountingLayerSettings {
373 #[serde(default = "default_true")]
375 pub include_accounts: bool,
376 #[serde(default = "default_true")]
378 pub je_as_hyperedges: bool,
379}
380
381impl Default for AccountingLayerSettings {
382 fn default() -> Self {
383 Self {
384 include_accounts: true,
385 je_as_hyperedges: true,
386 }
387 }
388}
389
390#[derive(Debug, Clone, Serialize, Deserialize)]
392pub struct CrossLayerSettings {
393 #[serde(default = "default_true")]
395 pub enabled: bool,
396}
397
398impl Default for CrossLayerSettings {
399 fn default() -> Self {
400 Self { enabled: true }
401 }
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
406pub struct GraphTypeConfig {
407 #[serde(default = "default_graph_name")]
409 pub name: String,
410
411 #[serde(default)]
413 pub aggregate_edges: bool,
414
415 #[serde(default)]
417 pub min_edge_weight: f64,
418
419 #[serde(default)]
421 pub include_document_nodes: bool,
422}
423
424fn default_graph_name() -> String {
425 "accounting_network".to_string()
426}
427
428impl Default for GraphTypeConfig {
429 fn default() -> Self {
430 Self {
431 name: "accounting_network".to_string(),
432 aggregate_edges: false,
433 min_edge_weight: 0.0,
434 include_document_nodes: false,
435 }
436 }
437}
438
439#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
441#[serde(rename_all = "snake_case")]
442pub enum GraphExportFormat {
443 PytorchGeometric,
445 Neo4j,
447 Dgl,
449 RustGraph,
451 RustGraphHypergraph,
453}
454
455#[derive(Debug, Clone, Default, Serialize, Deserialize)]
459pub struct ScenarioConfig {
460 #[serde(default)]
463 pub tags: Vec<String>,
464
465 #[serde(default)]
470 pub profile: Option<String>,
471
472 #[serde(default)]
474 pub description: Option<String>,
475
476 #[serde(default)]
478 pub ml_training: bool,
479
480 #[serde(default)]
483 pub target_anomaly_ratio: Option<f64>,
484
485 #[serde(default)]
487 pub metadata: std::collections::HashMap<String, String>,
488}
489
490#[derive(Debug, Clone, Serialize, Deserialize)]
495pub struct TemporalDriftConfig {
496 #[serde(default)]
498 pub enabled: bool,
499
500 #[serde(default = "default_amount_drift")]
503 pub amount_mean_drift: f64,
504
505 #[serde(default)]
508 pub amount_variance_drift: f64,
509
510 #[serde(default)]
513 pub anomaly_rate_drift: f64,
514
515 #[serde(default = "default_concept_drift")]
518 pub concept_drift_rate: f64,
519
520 #[serde(default)]
522 pub sudden_drift_probability: f64,
523
524 #[serde(default = "default_sudden_drift_magnitude")]
526 pub sudden_drift_magnitude: f64,
527
528 #[serde(default)]
530 pub seasonal_drift: bool,
531
532 #[serde(default)]
534 pub drift_start_period: u32,
535
536 #[serde(default = "default_drift_type")]
538 pub drift_type: DriftType,
539}
540
541fn default_amount_drift() -> f64 {
542 0.02
543}
544
545fn default_concept_drift() -> f64 {
546 0.01
547}
548
549fn default_sudden_drift_magnitude() -> f64 {
550 2.0
551}
552
553fn default_drift_type() -> DriftType {
554 DriftType::Gradual
555}
556
557impl Default for TemporalDriftConfig {
558 fn default() -> Self {
559 Self {
560 enabled: false,
561 amount_mean_drift: 0.02,
562 amount_variance_drift: 0.0,
563 anomaly_rate_drift: 0.0,
564 concept_drift_rate: 0.01,
565 sudden_drift_probability: 0.0,
566 sudden_drift_magnitude: 2.0,
567 seasonal_drift: false,
568 drift_start_period: 0,
569 drift_type: DriftType::Gradual,
570 }
571 }
572}
573
574impl TemporalDriftConfig {
575 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
577 datasynth_core::distributions::DriftConfig {
578 enabled: self.enabled,
579 amount_mean_drift: self.amount_mean_drift,
580 amount_variance_drift: self.amount_variance_drift,
581 anomaly_rate_drift: self.anomaly_rate_drift,
582 concept_drift_rate: self.concept_drift_rate,
583 sudden_drift_probability: self.sudden_drift_probability,
584 sudden_drift_magnitude: self.sudden_drift_magnitude,
585 seasonal_drift: self.seasonal_drift,
586 drift_start_period: self.drift_start_period,
587 drift_type: match self.drift_type {
588 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
589 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
590 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
591 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
592 },
593 regime_changes: Vec::new(),
594 economic_cycle: Default::default(),
595 parameter_drifts: Vec::new(),
596 }
597 }
598}
599
600#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
602#[serde(rename_all = "snake_case")]
603pub enum DriftType {
604 #[default]
606 Gradual,
607 Sudden,
609 Recurring,
611 Mixed,
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize)]
621pub struct StreamingSchemaConfig {
622 #[serde(default)]
624 pub enabled: bool,
625 #[serde(default = "default_buffer_size")]
627 pub buffer_size: usize,
628 #[serde(default = "default_true")]
630 pub enable_progress: bool,
631 #[serde(default = "default_progress_interval")]
633 pub progress_interval: u64,
634 #[serde(default)]
636 pub backpressure: BackpressureSchemaStrategy,
637}
638
639fn default_buffer_size() -> usize {
640 1000
641}
642
643fn default_progress_interval() -> u64 {
644 100
645}
646
647impl Default for StreamingSchemaConfig {
648 fn default() -> Self {
649 Self {
650 enabled: false,
651 buffer_size: 1000,
652 enable_progress: true,
653 progress_interval: 100,
654 backpressure: BackpressureSchemaStrategy::Block,
655 }
656 }
657}
658
659#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
661#[serde(rename_all = "snake_case")]
662pub enum BackpressureSchemaStrategy {
663 #[default]
665 Block,
666 DropOldest,
668 DropNewest,
670 Buffer,
672}
673
674#[derive(Debug, Clone, Serialize, Deserialize)]
680pub struct RateLimitSchemaConfig {
681 #[serde(default)]
683 pub enabled: bool,
684 #[serde(default = "default_entities_per_second")]
686 pub entities_per_second: f64,
687 #[serde(default = "default_burst_size")]
689 pub burst_size: u32,
690 #[serde(default)]
692 pub backpressure: RateLimitBackpressureSchema,
693}
694
695fn default_entities_per_second() -> f64 {
696 1000.0
697}
698
699fn default_burst_size() -> u32 {
700 100
701}
702
703impl Default for RateLimitSchemaConfig {
704 fn default() -> Self {
705 Self {
706 enabled: false,
707 entities_per_second: 1000.0,
708 burst_size: 100,
709 backpressure: RateLimitBackpressureSchema::Block,
710 }
711 }
712}
713
714#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
716#[serde(rename_all = "snake_case")]
717pub enum RateLimitBackpressureSchema {
718 #[default]
720 Block,
721 Drop,
723 Buffer,
725}
726
727#[derive(Debug, Clone, Serialize, Deserialize)]
733pub struct TemporalAttributeSchemaConfig {
734 #[serde(default)]
736 pub enabled: bool,
737 #[serde(default)]
739 pub valid_time: ValidTimeSchemaConfig,
740 #[serde(default)]
742 pub transaction_time: TransactionTimeSchemaConfig,
743 #[serde(default)]
745 pub generate_version_chains: bool,
746 #[serde(default = "default_avg_versions")]
748 pub avg_versions_per_entity: f64,
749}
750
751fn default_avg_versions() -> f64 {
752 1.5
753}
754
755impl Default for TemporalAttributeSchemaConfig {
756 fn default() -> Self {
757 Self {
758 enabled: false,
759 valid_time: ValidTimeSchemaConfig::default(),
760 transaction_time: TransactionTimeSchemaConfig::default(),
761 generate_version_chains: false,
762 avg_versions_per_entity: 1.5,
763 }
764 }
765}
766
767#[derive(Debug, Clone, Serialize, Deserialize)]
769pub struct ValidTimeSchemaConfig {
770 #[serde(default = "default_closed_probability")]
772 pub closed_probability: f64,
773 #[serde(default = "default_avg_validity_days")]
775 pub avg_validity_days: u32,
776 #[serde(default = "default_validity_stddev")]
778 pub validity_stddev_days: u32,
779}
780
781fn default_closed_probability() -> f64 {
782 0.1
783}
784
785fn default_avg_validity_days() -> u32 {
786 365
787}
788
789fn default_validity_stddev() -> u32 {
790 90
791}
792
793impl Default for ValidTimeSchemaConfig {
794 fn default() -> Self {
795 Self {
796 closed_probability: 0.1,
797 avg_validity_days: 365,
798 validity_stddev_days: 90,
799 }
800 }
801}
802
803#[derive(Debug, Clone, Serialize, Deserialize)]
805pub struct TransactionTimeSchemaConfig {
806 #[serde(default)]
808 pub avg_recording_delay_seconds: u32,
809 #[serde(default)]
811 pub allow_backdating: bool,
812 #[serde(default = "default_backdating_probability")]
814 pub backdating_probability: f64,
815 #[serde(default = "default_max_backdate_days")]
817 pub max_backdate_days: u32,
818}
819
820fn default_backdating_probability() -> f64 {
821 0.01
822}
823
824fn default_max_backdate_days() -> u32 {
825 30
826}
827
828impl Default for TransactionTimeSchemaConfig {
829 fn default() -> Self {
830 Self {
831 avg_recording_delay_seconds: 0,
832 allow_backdating: false,
833 backdating_probability: 0.01,
834 max_backdate_days: 30,
835 }
836 }
837}
838
839#[derive(Debug, Clone, Serialize, Deserialize)]
845pub struct RelationshipSchemaConfig {
846 #[serde(default)]
848 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
849 #[serde(default = "default_true")]
851 pub allow_orphans: bool,
852 #[serde(default = "default_orphan_probability")]
854 pub orphan_probability: f64,
855 #[serde(default)]
857 pub allow_circular: bool,
858 #[serde(default = "default_max_circular_depth")]
860 pub max_circular_depth: u32,
861}
862
863fn default_orphan_probability() -> f64 {
864 0.01
865}
866
867fn default_max_circular_depth() -> u32 {
868 3
869}
870
871impl Default for RelationshipSchemaConfig {
872 fn default() -> Self {
873 Self {
874 relationship_types: Vec::new(),
875 allow_orphans: true,
876 orphan_probability: 0.01,
877 allow_circular: false,
878 max_circular_depth: 3,
879 }
880 }
881}
882
883#[derive(Debug, Clone, Serialize, Deserialize)]
885pub struct RelationshipTypeSchemaConfig {
886 pub name: String,
888 pub source_type: String,
890 pub target_type: String,
892 #[serde(default)]
894 pub cardinality: CardinalitySchemaRule,
895 #[serde(default = "default_relationship_weight")]
897 pub weight: f64,
898 #[serde(default)]
900 pub required: bool,
901 #[serde(default = "default_true")]
903 pub directed: bool,
904}
905
906fn default_relationship_weight() -> f64 {
907 1.0
908}
909
910impl Default for RelationshipTypeSchemaConfig {
911 fn default() -> Self {
912 Self {
913 name: String::new(),
914 source_type: String::new(),
915 target_type: String::new(),
916 cardinality: CardinalitySchemaRule::default(),
917 weight: 1.0,
918 required: false,
919 directed: true,
920 }
921 }
922}
923
924#[derive(Debug, Clone, Serialize, Deserialize)]
926#[serde(rename_all = "snake_case")]
927pub enum CardinalitySchemaRule {
928 OneToOne,
930 OneToMany {
932 min: u32,
934 max: u32,
936 },
937 ManyToOne {
939 min: u32,
941 max: u32,
943 },
944 ManyToMany {
946 min_per_source: u32,
948 max_per_source: u32,
950 },
951}
952
953impl Default for CardinalitySchemaRule {
954 fn default() -> Self {
955 Self::OneToMany { min: 1, max: 5 }
956 }
957}
958
959#[derive(Debug, Clone, Serialize, Deserialize)]
961pub struct GlobalConfig {
962 pub seed: Option<u64>,
964 pub industry: IndustrySector,
966 pub start_date: String,
968 pub period_months: u32,
970 #[serde(default = "default_currency")]
972 pub group_currency: String,
973 #[serde(default = "default_true")]
975 pub parallel: bool,
976 #[serde(default)]
978 pub worker_threads: usize,
979 #[serde(default)]
981 pub memory_limit_mb: usize,
982}
983
984fn default_currency() -> String {
985 "USD".to_string()
986}
987fn default_true() -> bool {
988 true
989}
990
991#[derive(Debug, Clone, Serialize, Deserialize)]
993pub struct CompanyConfig {
994 pub code: String,
996 pub name: String,
998 pub currency: String,
1000 pub country: String,
1002 #[serde(default = "default_fiscal_variant")]
1004 pub fiscal_year_variant: String,
1005 pub annual_transaction_volume: TransactionVolume,
1007 #[serde(default = "default_weight")]
1009 pub volume_weight: f64,
1010}
1011
1012fn default_fiscal_variant() -> String {
1013 "K4".to_string()
1014}
1015fn default_weight() -> f64 {
1016 1.0
1017}
1018
1019#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1021#[serde(rename_all = "snake_case")]
1022pub enum TransactionVolume {
1023 TenK,
1025 HundredK,
1027 OneM,
1029 TenM,
1031 HundredM,
1033 Custom(u64),
1035}
1036
1037impl TransactionVolume {
1038 pub fn count(&self) -> u64 {
1040 match self {
1041 Self::TenK => 10_000,
1042 Self::HundredK => 100_000,
1043 Self::OneM => 1_000_000,
1044 Self::TenM => 10_000_000,
1045 Self::HundredM => 100_000_000,
1046 Self::Custom(n) => *n,
1047 }
1048 }
1049}
1050
1051#[derive(Debug, Clone, Serialize, Deserialize)]
1053pub struct ChartOfAccountsConfig {
1054 pub complexity: CoAComplexity,
1056 #[serde(default = "default_true")]
1058 pub industry_specific: bool,
1059 pub custom_accounts: Option<PathBuf>,
1061 #[serde(default = "default_min_depth")]
1063 pub min_hierarchy_depth: u8,
1064 #[serde(default = "default_max_depth")]
1066 pub max_hierarchy_depth: u8,
1067}
1068
1069fn default_min_depth() -> u8 {
1070 2
1071}
1072fn default_max_depth() -> u8 {
1073 5
1074}
1075
1076impl Default for ChartOfAccountsConfig {
1077 fn default() -> Self {
1078 Self {
1079 complexity: CoAComplexity::Small,
1080 industry_specific: true,
1081 custom_accounts: None,
1082 min_hierarchy_depth: default_min_depth(),
1083 max_hierarchy_depth: default_max_depth(),
1084 }
1085 }
1086}
1087
1088#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1090pub struct TransactionConfig {
1091 #[serde(default)]
1093 pub line_item_distribution: LineItemDistributionConfig,
1094 #[serde(default)]
1096 pub debit_credit_distribution: DebitCreditDistributionConfig,
1097 #[serde(default)]
1099 pub even_odd_distribution: EvenOddDistributionConfig,
1100 #[serde(default)]
1102 pub source_distribution: SourceDistribution,
1103 #[serde(default)]
1105 pub seasonality: SeasonalityConfig,
1106 #[serde(default)]
1108 pub amounts: AmountDistributionConfig,
1109 #[serde(default)]
1111 pub benford: BenfordConfig,
1112}
1113
1114#[derive(Debug, Clone, Serialize, Deserialize)]
1116pub struct BenfordConfig {
1117 #[serde(default = "default_true")]
1119 pub enabled: bool,
1120 #[serde(default = "default_benford_tolerance")]
1122 pub tolerance: f64,
1123 #[serde(default)]
1125 pub exempt_sources: Vec<BenfordExemption>,
1126}
1127
1128fn default_benford_tolerance() -> f64 {
1129 0.05
1130}
1131
1132impl Default for BenfordConfig {
1133 fn default() -> Self {
1134 Self {
1135 enabled: true,
1136 tolerance: default_benford_tolerance(),
1137 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1138 }
1139 }
1140}
1141
1142#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1144#[serde(rename_all = "snake_case")]
1145pub enum BenfordExemption {
1146 Recurring,
1148 Payroll,
1150 FixedFees,
1152 RoundAmounts,
1154}
1155
1156#[derive(Debug, Clone, Serialize, Deserialize)]
1158pub struct SourceDistribution {
1159 pub manual: f64,
1161 pub automated: f64,
1163 pub recurring: f64,
1165 pub adjustment: f64,
1167}
1168
1169impl Default for SourceDistribution {
1170 fn default() -> Self {
1171 Self {
1172 manual: 0.20,
1173 automated: 0.70,
1174 recurring: 0.07,
1175 adjustment: 0.03,
1176 }
1177 }
1178}
1179
1180#[derive(Debug, Clone, Serialize, Deserialize)]
1182pub struct OutputConfig {
1183 #[serde(default)]
1185 pub mode: OutputMode,
1186 pub output_directory: PathBuf,
1188 #[serde(default = "default_formats")]
1190 pub formats: Vec<FileFormat>,
1191 #[serde(default)]
1193 pub compression: CompressionConfig,
1194 #[serde(default = "default_batch_size")]
1196 pub batch_size: usize,
1197 #[serde(default = "default_true")]
1199 pub include_acdoca: bool,
1200 #[serde(default)]
1202 pub include_bseg: bool,
1203 #[serde(default = "default_true")]
1205 pub partition_by_period: bool,
1206 #[serde(default)]
1208 pub partition_by_company: bool,
1209}
1210
1211fn default_formats() -> Vec<FileFormat> {
1212 vec![FileFormat::Parquet]
1213}
1214fn default_batch_size() -> usize {
1215 100_000
1216}
1217
1218impl Default for OutputConfig {
1219 fn default() -> Self {
1220 Self {
1221 mode: OutputMode::FlatFile,
1222 output_directory: PathBuf::from("./output"),
1223 formats: default_formats(),
1224 compression: CompressionConfig::default(),
1225 batch_size: default_batch_size(),
1226 include_acdoca: true,
1227 include_bseg: false,
1228 partition_by_period: true,
1229 partition_by_company: false,
1230 }
1231 }
1232}
1233
1234#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1236#[serde(rename_all = "snake_case")]
1237pub enum OutputMode {
1238 Streaming,
1240 #[default]
1242 FlatFile,
1243 Both,
1245}
1246
1247#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1249#[serde(rename_all = "snake_case")]
1250pub enum FileFormat {
1251 Csv,
1252 Parquet,
1253 Json,
1254 JsonLines,
1255}
1256
1257#[derive(Debug, Clone, Serialize, Deserialize)]
1259pub struct CompressionConfig {
1260 #[serde(default = "default_true")]
1262 pub enabled: bool,
1263 #[serde(default)]
1265 pub algorithm: CompressionAlgorithm,
1266 #[serde(default = "default_compression_level")]
1268 pub level: u8,
1269}
1270
1271fn default_compression_level() -> u8 {
1272 3
1273}
1274
1275impl Default for CompressionConfig {
1276 fn default() -> Self {
1277 Self {
1278 enabled: true,
1279 algorithm: CompressionAlgorithm::default(),
1280 level: default_compression_level(),
1281 }
1282 }
1283}
1284
1285#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1287#[serde(rename_all = "snake_case")]
1288pub enum CompressionAlgorithm {
1289 Gzip,
1290 #[default]
1291 Zstd,
1292 Lz4,
1293 Snappy,
1294}
1295
1296#[derive(Debug, Clone, Serialize, Deserialize)]
1298pub struct FraudConfig {
1299 #[serde(default)]
1301 pub enabled: bool,
1302 #[serde(default = "default_fraud_rate")]
1304 pub fraud_rate: f64,
1305 #[serde(default)]
1307 pub fraud_type_distribution: FraudTypeDistribution,
1308 #[serde(default)]
1310 pub clustering_enabled: bool,
1311 #[serde(default = "default_clustering_factor")]
1313 pub clustering_factor: f64,
1314 #[serde(default = "default_approval_thresholds")]
1316 pub approval_thresholds: Vec<f64>,
1317}
1318
1319fn default_approval_thresholds() -> Vec<f64> {
1320 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1321}
1322
1323fn default_fraud_rate() -> f64 {
1324 0.005
1325}
1326fn default_clustering_factor() -> f64 {
1327 3.0
1328}
1329
1330impl Default for FraudConfig {
1331 fn default() -> Self {
1332 Self {
1333 enabled: false,
1334 fraud_rate: default_fraud_rate(),
1335 fraud_type_distribution: FraudTypeDistribution::default(),
1336 clustering_enabled: false,
1337 clustering_factor: default_clustering_factor(),
1338 approval_thresholds: default_approval_thresholds(),
1339 }
1340 }
1341}
1342
1343#[derive(Debug, Clone, Serialize, Deserialize)]
1345pub struct FraudTypeDistribution {
1346 pub suspense_account_abuse: f64,
1347 pub fictitious_transaction: f64,
1348 pub revenue_manipulation: f64,
1349 pub expense_capitalization: f64,
1350 pub split_transaction: f64,
1351 pub timing_anomaly: f64,
1352 pub unauthorized_access: f64,
1353 pub duplicate_payment: f64,
1354}
1355
1356impl Default for FraudTypeDistribution {
1357 fn default() -> Self {
1358 Self {
1359 suspense_account_abuse: 0.25,
1360 fictitious_transaction: 0.15,
1361 revenue_manipulation: 0.10,
1362 expense_capitalization: 0.10,
1363 split_transaction: 0.15,
1364 timing_anomaly: 0.10,
1365 unauthorized_access: 0.10,
1366 duplicate_payment: 0.05,
1367 }
1368 }
1369}
1370
1371#[derive(Debug, Clone, Serialize, Deserialize)]
1373pub struct InternalControlsConfig {
1374 #[serde(default)]
1376 pub enabled: bool,
1377 #[serde(default = "default_exception_rate")]
1379 pub exception_rate: f64,
1380 #[serde(default = "default_sod_violation_rate")]
1382 pub sod_violation_rate: f64,
1383 #[serde(default = "default_true")]
1385 pub export_control_master_data: bool,
1386 #[serde(default = "default_sox_materiality_threshold")]
1388 pub sox_materiality_threshold: f64,
1389 #[serde(default = "default_true")]
1391 pub coso_enabled: bool,
1392 #[serde(default)]
1394 pub include_entity_level_controls: bool,
1395 #[serde(default = "default_target_maturity_level")]
1398 pub target_maturity_level: String,
1399}
1400
1401fn default_exception_rate() -> f64 {
1402 0.02
1403}
1404
1405fn default_sod_violation_rate() -> f64 {
1406 0.01
1407}
1408
1409fn default_sox_materiality_threshold() -> f64 {
1410 10000.0
1411}
1412
1413fn default_target_maturity_level() -> String {
1414 "mixed".to_string()
1415}
1416
1417impl Default for InternalControlsConfig {
1418 fn default() -> Self {
1419 Self {
1420 enabled: false,
1421 exception_rate: default_exception_rate(),
1422 sod_violation_rate: default_sod_violation_rate(),
1423 export_control_master_data: true,
1424 sox_materiality_threshold: default_sox_materiality_threshold(),
1425 coso_enabled: true,
1426 include_entity_level_controls: false,
1427 target_maturity_level: default_target_maturity_level(),
1428 }
1429 }
1430}
1431
1432#[derive(Debug, Clone, Serialize, Deserialize)]
1434pub struct BusinessProcessConfig {
1435 #[serde(default = "default_o2c")]
1437 pub o2c_weight: f64,
1438 #[serde(default = "default_p2p")]
1440 pub p2p_weight: f64,
1441 #[serde(default = "default_r2r")]
1443 pub r2r_weight: f64,
1444 #[serde(default = "default_h2r")]
1446 pub h2r_weight: f64,
1447 #[serde(default = "default_a2r")]
1449 pub a2r_weight: f64,
1450}
1451
1452fn default_o2c() -> f64 {
1453 0.35
1454}
1455fn default_p2p() -> f64 {
1456 0.30
1457}
1458fn default_r2r() -> f64 {
1459 0.20
1460}
1461fn default_h2r() -> f64 {
1462 0.10
1463}
1464fn default_a2r() -> f64 {
1465 0.05
1466}
1467
1468impl Default for BusinessProcessConfig {
1469 fn default() -> Self {
1470 Self {
1471 o2c_weight: default_o2c(),
1472 p2p_weight: default_p2p(),
1473 r2r_weight: default_r2r(),
1474 h2r_weight: default_h2r(),
1475 a2r_weight: default_a2r(),
1476 }
1477 }
1478}
1479
1480#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1482pub struct UserPersonaConfig {
1483 #[serde(default)]
1485 pub persona_distribution: PersonaDistribution,
1486 #[serde(default)]
1488 pub users_per_persona: UsersPerPersona,
1489}
1490
1491#[derive(Debug, Clone, Serialize, Deserialize)]
1493pub struct PersonaDistribution {
1494 pub junior_accountant: f64,
1495 pub senior_accountant: f64,
1496 pub controller: f64,
1497 pub manager: f64,
1498 pub automated_system: f64,
1499}
1500
1501impl Default for PersonaDistribution {
1502 fn default() -> Self {
1503 Self {
1504 junior_accountant: 0.15,
1505 senior_accountant: 0.15,
1506 controller: 0.05,
1507 manager: 0.05,
1508 automated_system: 0.60,
1509 }
1510 }
1511}
1512
1513#[derive(Debug, Clone, Serialize, Deserialize)]
1515pub struct UsersPerPersona {
1516 pub junior_accountant: usize,
1517 pub senior_accountant: usize,
1518 pub controller: usize,
1519 pub manager: usize,
1520 pub automated_system: usize,
1521}
1522
1523impl Default for UsersPerPersona {
1524 fn default() -> Self {
1525 Self {
1526 junior_accountant: 10,
1527 senior_accountant: 5,
1528 controller: 2,
1529 manager: 3,
1530 automated_system: 20,
1531 }
1532 }
1533}
1534
1535#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1537pub struct TemplateConfig {
1538 #[serde(default)]
1540 pub names: NameTemplateConfig,
1541 #[serde(default)]
1543 pub descriptions: DescriptionTemplateConfig,
1544 #[serde(default)]
1546 pub references: ReferenceTemplateConfig,
1547}
1548
1549#[derive(Debug, Clone, Serialize, Deserialize)]
1551pub struct NameTemplateConfig {
1552 #[serde(default)]
1554 pub culture_distribution: CultureDistribution,
1555 #[serde(default = "default_email_domain")]
1557 pub email_domain: String,
1558 #[serde(default = "default_true")]
1560 pub generate_realistic_names: bool,
1561}
1562
1563fn default_email_domain() -> String {
1564 "company.com".to_string()
1565}
1566
1567impl Default for NameTemplateConfig {
1568 fn default() -> Self {
1569 Self {
1570 culture_distribution: CultureDistribution::default(),
1571 email_domain: default_email_domain(),
1572 generate_realistic_names: true,
1573 }
1574 }
1575}
1576
1577#[derive(Debug, Clone, Serialize, Deserialize)]
1579pub struct CultureDistribution {
1580 pub western_us: f64,
1581 pub hispanic: f64,
1582 pub german: f64,
1583 pub french: f64,
1584 pub chinese: f64,
1585 pub japanese: f64,
1586 pub indian: f64,
1587}
1588
1589impl Default for CultureDistribution {
1590 fn default() -> Self {
1591 Self {
1592 western_us: 0.40,
1593 hispanic: 0.20,
1594 german: 0.10,
1595 french: 0.05,
1596 chinese: 0.10,
1597 japanese: 0.05,
1598 indian: 0.10,
1599 }
1600 }
1601}
1602
1603#[derive(Debug, Clone, Serialize, Deserialize)]
1605pub struct DescriptionTemplateConfig {
1606 #[serde(default = "default_true")]
1608 pub generate_header_text: bool,
1609 #[serde(default = "default_true")]
1611 pub generate_line_text: bool,
1612}
1613
1614impl Default for DescriptionTemplateConfig {
1615 fn default() -> Self {
1616 Self {
1617 generate_header_text: true,
1618 generate_line_text: true,
1619 }
1620 }
1621}
1622
1623#[derive(Debug, Clone, Serialize, Deserialize)]
1625pub struct ReferenceTemplateConfig {
1626 #[serde(default = "default_true")]
1628 pub generate_references: bool,
1629 #[serde(default = "default_invoice_prefix")]
1631 pub invoice_prefix: String,
1632 #[serde(default = "default_po_prefix")]
1634 pub po_prefix: String,
1635 #[serde(default = "default_so_prefix")]
1637 pub so_prefix: String,
1638}
1639
1640fn default_invoice_prefix() -> String {
1641 "INV".to_string()
1642}
1643fn default_po_prefix() -> String {
1644 "PO".to_string()
1645}
1646fn default_so_prefix() -> String {
1647 "SO".to_string()
1648}
1649
1650impl Default for ReferenceTemplateConfig {
1651 fn default() -> Self {
1652 Self {
1653 generate_references: true,
1654 invoice_prefix: default_invoice_prefix(),
1655 po_prefix: default_po_prefix(),
1656 so_prefix: default_so_prefix(),
1657 }
1658 }
1659}
1660
1661#[derive(Debug, Clone, Serialize, Deserialize)]
1663pub struct ApprovalConfig {
1664 #[serde(default)]
1666 pub enabled: bool,
1667 #[serde(default = "default_auto_approve_threshold")]
1669 pub auto_approve_threshold: f64,
1670 #[serde(default = "default_rejection_rate")]
1672 pub rejection_rate: f64,
1673 #[serde(default = "default_revision_rate")]
1675 pub revision_rate: f64,
1676 #[serde(default = "default_approval_delay_hours")]
1678 pub average_approval_delay_hours: f64,
1679 #[serde(default)]
1681 pub thresholds: Vec<ApprovalThresholdConfig>,
1682}
1683
1684fn default_auto_approve_threshold() -> f64 {
1685 1000.0
1686}
1687fn default_rejection_rate() -> f64 {
1688 0.02
1689}
1690fn default_revision_rate() -> f64 {
1691 0.05
1692}
1693fn default_approval_delay_hours() -> f64 {
1694 4.0
1695}
1696
1697impl Default for ApprovalConfig {
1698 fn default() -> Self {
1699 Self {
1700 enabled: false,
1701 auto_approve_threshold: default_auto_approve_threshold(),
1702 rejection_rate: default_rejection_rate(),
1703 revision_rate: default_revision_rate(),
1704 average_approval_delay_hours: default_approval_delay_hours(),
1705 thresholds: vec![
1706 ApprovalThresholdConfig {
1707 amount: 1000.0,
1708 level: 1,
1709 roles: vec!["senior_accountant".to_string()],
1710 },
1711 ApprovalThresholdConfig {
1712 amount: 10000.0,
1713 level: 2,
1714 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1715 },
1716 ApprovalThresholdConfig {
1717 amount: 100000.0,
1718 level: 3,
1719 roles: vec![
1720 "senior_accountant".to_string(),
1721 "controller".to_string(),
1722 "manager".to_string(),
1723 ],
1724 },
1725 ApprovalThresholdConfig {
1726 amount: 500000.0,
1727 level: 4,
1728 roles: vec![
1729 "senior_accountant".to_string(),
1730 "controller".to_string(),
1731 "manager".to_string(),
1732 "executive".to_string(),
1733 ],
1734 },
1735 ],
1736 }
1737 }
1738}
1739
1740#[derive(Debug, Clone, Serialize, Deserialize)]
1742pub struct ApprovalThresholdConfig {
1743 pub amount: f64,
1745 pub level: u8,
1747 pub roles: Vec<String>,
1749}
1750
1751#[derive(Debug, Clone, Serialize, Deserialize)]
1753pub struct DepartmentConfig {
1754 #[serde(default)]
1756 pub enabled: bool,
1757 #[serde(default = "default_headcount_multiplier")]
1759 pub headcount_multiplier: f64,
1760 #[serde(default)]
1762 pub custom_departments: Vec<CustomDepartmentConfig>,
1763}
1764
1765fn default_headcount_multiplier() -> f64 {
1766 1.0
1767}
1768
1769impl Default for DepartmentConfig {
1770 fn default() -> Self {
1771 Self {
1772 enabled: false,
1773 headcount_multiplier: default_headcount_multiplier(),
1774 custom_departments: Vec::new(),
1775 }
1776 }
1777}
1778
1779#[derive(Debug, Clone, Serialize, Deserialize)]
1781pub struct CustomDepartmentConfig {
1782 pub code: String,
1784 pub name: String,
1786 #[serde(default)]
1788 pub cost_center: Option<String>,
1789 #[serde(default)]
1791 pub primary_processes: Vec<String>,
1792 #[serde(default)]
1794 pub parent_code: Option<String>,
1795}
1796
1797#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1803pub struct MasterDataConfig {
1804 #[serde(default)]
1806 pub vendors: VendorMasterConfig,
1807 #[serde(default)]
1809 pub customers: CustomerMasterConfig,
1810 #[serde(default)]
1812 pub materials: MaterialMasterConfig,
1813 #[serde(default)]
1815 pub fixed_assets: FixedAssetMasterConfig,
1816 #[serde(default)]
1818 pub employees: EmployeeMasterConfig,
1819 #[serde(default)]
1821 pub cost_centers: CostCenterMasterConfig,
1822}
1823
1824#[derive(Debug, Clone, Serialize, Deserialize)]
1826pub struct VendorMasterConfig {
1827 #[serde(default = "default_vendor_count")]
1829 pub count: usize,
1830 #[serde(default = "default_intercompany_percent")]
1832 pub intercompany_percent: f64,
1833 #[serde(default)]
1835 pub payment_terms_distribution: PaymentTermsDistribution,
1836 #[serde(default)]
1838 pub behavior_distribution: VendorBehaviorDistribution,
1839 #[serde(default = "default_true")]
1841 pub generate_bank_accounts: bool,
1842 #[serde(default = "default_true")]
1844 pub generate_tax_ids: bool,
1845}
1846
1847fn default_vendor_count() -> usize {
1848 500
1849}
1850
1851fn default_intercompany_percent() -> f64 {
1852 0.05
1853}
1854
1855impl Default for VendorMasterConfig {
1856 fn default() -> Self {
1857 Self {
1858 count: default_vendor_count(),
1859 intercompany_percent: default_intercompany_percent(),
1860 payment_terms_distribution: PaymentTermsDistribution::default(),
1861 behavior_distribution: VendorBehaviorDistribution::default(),
1862 generate_bank_accounts: true,
1863 generate_tax_ids: true,
1864 }
1865 }
1866}
1867
1868#[derive(Debug, Clone, Serialize, Deserialize)]
1870pub struct PaymentTermsDistribution {
1871 pub net_30: f64,
1873 pub net_60: f64,
1875 pub net_90: f64,
1877 pub two_ten_net_30: f64,
1879 pub due_on_receipt: f64,
1881 pub end_of_month: f64,
1883}
1884
1885impl Default for PaymentTermsDistribution {
1886 fn default() -> Self {
1887 Self {
1888 net_30: 0.40,
1889 net_60: 0.20,
1890 net_90: 0.10,
1891 two_ten_net_30: 0.15,
1892 due_on_receipt: 0.05,
1893 end_of_month: 0.10,
1894 }
1895 }
1896}
1897
1898#[derive(Debug, Clone, Serialize, Deserialize)]
1900pub struct VendorBehaviorDistribution {
1901 pub reliable: f64,
1903 pub sometimes_late: f64,
1905 pub inconsistent_quality: f64,
1907 pub premium: f64,
1909 pub budget: f64,
1911}
1912
1913impl Default for VendorBehaviorDistribution {
1914 fn default() -> Self {
1915 Self {
1916 reliable: 0.50,
1917 sometimes_late: 0.20,
1918 inconsistent_quality: 0.10,
1919 premium: 0.10,
1920 budget: 0.10,
1921 }
1922 }
1923}
1924
1925#[derive(Debug, Clone, Serialize, Deserialize)]
1927pub struct CustomerMasterConfig {
1928 #[serde(default = "default_customer_count")]
1930 pub count: usize,
1931 #[serde(default = "default_intercompany_percent")]
1933 pub intercompany_percent: f64,
1934 #[serde(default)]
1936 pub credit_rating_distribution: CreditRatingDistribution,
1937 #[serde(default)]
1939 pub payment_behavior_distribution: PaymentBehaviorDistribution,
1940 #[serde(default = "default_true")]
1942 pub generate_credit_limits: bool,
1943}
1944
1945fn default_customer_count() -> usize {
1946 2000
1947}
1948
1949impl Default for CustomerMasterConfig {
1950 fn default() -> Self {
1951 Self {
1952 count: default_customer_count(),
1953 intercompany_percent: default_intercompany_percent(),
1954 credit_rating_distribution: CreditRatingDistribution::default(),
1955 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
1956 generate_credit_limits: true,
1957 }
1958 }
1959}
1960
1961#[derive(Debug, Clone, Serialize, Deserialize)]
1963pub struct CreditRatingDistribution {
1964 pub aaa: f64,
1966 pub aa: f64,
1968 pub a: f64,
1970 pub bbb: f64,
1972 pub bb: f64,
1974 pub b: f64,
1976 pub below_b: f64,
1978}
1979
1980impl Default for CreditRatingDistribution {
1981 fn default() -> Self {
1982 Self {
1983 aaa: 0.05,
1984 aa: 0.10,
1985 a: 0.20,
1986 bbb: 0.30,
1987 bb: 0.20,
1988 b: 0.10,
1989 below_b: 0.05,
1990 }
1991 }
1992}
1993
1994#[derive(Debug, Clone, Serialize, Deserialize)]
1996pub struct PaymentBehaviorDistribution {
1997 pub early_payer: f64,
1999 pub on_time: f64,
2001 pub occasional_late: f64,
2003 pub frequent_late: f64,
2005 pub discount_taker: f64,
2007}
2008
2009impl Default for PaymentBehaviorDistribution {
2010 fn default() -> Self {
2011 Self {
2012 early_payer: 0.10,
2013 on_time: 0.50,
2014 occasional_late: 0.25,
2015 frequent_late: 0.10,
2016 discount_taker: 0.05,
2017 }
2018 }
2019}
2020
2021#[derive(Debug, Clone, Serialize, Deserialize)]
2023pub struct MaterialMasterConfig {
2024 #[serde(default = "default_material_count")]
2026 pub count: usize,
2027 #[serde(default)]
2029 pub type_distribution: MaterialTypeDistribution,
2030 #[serde(default)]
2032 pub valuation_distribution: ValuationMethodDistribution,
2033 #[serde(default = "default_bom_percent")]
2035 pub bom_percent: f64,
2036 #[serde(default = "default_max_bom_depth")]
2038 pub max_bom_depth: u8,
2039}
2040
2041fn default_material_count() -> usize {
2042 5000
2043}
2044
2045fn default_bom_percent() -> f64 {
2046 0.20
2047}
2048
2049fn default_max_bom_depth() -> u8 {
2050 3
2051}
2052
2053impl Default for MaterialMasterConfig {
2054 fn default() -> Self {
2055 Self {
2056 count: default_material_count(),
2057 type_distribution: MaterialTypeDistribution::default(),
2058 valuation_distribution: ValuationMethodDistribution::default(),
2059 bom_percent: default_bom_percent(),
2060 max_bom_depth: default_max_bom_depth(),
2061 }
2062 }
2063}
2064
2065#[derive(Debug, Clone, Serialize, Deserialize)]
2067pub struct MaterialTypeDistribution {
2068 pub raw_material: f64,
2070 pub semi_finished: f64,
2072 pub finished_good: f64,
2074 pub trading_good: f64,
2076 pub operating_supply: f64,
2078 pub service: f64,
2080}
2081
2082impl Default for MaterialTypeDistribution {
2083 fn default() -> Self {
2084 Self {
2085 raw_material: 0.30,
2086 semi_finished: 0.15,
2087 finished_good: 0.25,
2088 trading_good: 0.15,
2089 operating_supply: 0.10,
2090 service: 0.05,
2091 }
2092 }
2093}
2094
2095#[derive(Debug, Clone, Serialize, Deserialize)]
2097pub struct ValuationMethodDistribution {
2098 pub standard_cost: f64,
2100 pub moving_average: f64,
2102 pub fifo: f64,
2104 pub lifo: f64,
2106}
2107
2108impl Default for ValuationMethodDistribution {
2109 fn default() -> Self {
2110 Self {
2111 standard_cost: 0.50,
2112 moving_average: 0.30,
2113 fifo: 0.15,
2114 lifo: 0.05,
2115 }
2116 }
2117}
2118
2119#[derive(Debug, Clone, Serialize, Deserialize)]
2121pub struct FixedAssetMasterConfig {
2122 #[serde(default = "default_asset_count")]
2124 pub count: usize,
2125 #[serde(default)]
2127 pub class_distribution: AssetClassDistribution,
2128 #[serde(default)]
2130 pub depreciation_distribution: DepreciationMethodDistribution,
2131 #[serde(default = "default_fully_depreciated_percent")]
2133 pub fully_depreciated_percent: f64,
2134 #[serde(default = "default_true")]
2136 pub generate_acquisition_history: bool,
2137}
2138
2139fn default_asset_count() -> usize {
2140 800
2141}
2142
2143fn default_fully_depreciated_percent() -> f64 {
2144 0.15
2145}
2146
2147impl Default for FixedAssetMasterConfig {
2148 fn default() -> Self {
2149 Self {
2150 count: default_asset_count(),
2151 class_distribution: AssetClassDistribution::default(),
2152 depreciation_distribution: DepreciationMethodDistribution::default(),
2153 fully_depreciated_percent: default_fully_depreciated_percent(),
2154 generate_acquisition_history: true,
2155 }
2156 }
2157}
2158
2159#[derive(Debug, Clone, Serialize, Deserialize)]
2161pub struct AssetClassDistribution {
2162 pub buildings: f64,
2164 pub machinery: f64,
2166 pub vehicles: f64,
2168 pub it_equipment: f64,
2170 pub furniture: f64,
2172 pub land: f64,
2174 pub leasehold: f64,
2176}
2177
2178impl Default for AssetClassDistribution {
2179 fn default() -> Self {
2180 Self {
2181 buildings: 0.15,
2182 machinery: 0.30,
2183 vehicles: 0.15,
2184 it_equipment: 0.20,
2185 furniture: 0.10,
2186 land: 0.05,
2187 leasehold: 0.05,
2188 }
2189 }
2190}
2191
2192#[derive(Debug, Clone, Serialize, Deserialize)]
2194pub struct DepreciationMethodDistribution {
2195 pub straight_line: f64,
2197 pub declining_balance: f64,
2199 pub double_declining: f64,
2201 pub sum_of_years: f64,
2203 pub units_of_production: f64,
2205}
2206
2207impl Default for DepreciationMethodDistribution {
2208 fn default() -> Self {
2209 Self {
2210 straight_line: 0.60,
2211 declining_balance: 0.20,
2212 double_declining: 0.10,
2213 sum_of_years: 0.05,
2214 units_of_production: 0.05,
2215 }
2216 }
2217}
2218
2219#[derive(Debug, Clone, Serialize, Deserialize)]
2221pub struct EmployeeMasterConfig {
2222 #[serde(default = "default_employee_count")]
2224 pub count: usize,
2225 #[serde(default = "default_true")]
2227 pub generate_hierarchy: bool,
2228 #[serde(default = "default_hierarchy_depth")]
2230 pub max_hierarchy_depth: u8,
2231 #[serde(default = "default_span_of_control")]
2233 pub average_span_of_control: f64,
2234 #[serde(default)]
2236 pub approval_limits: ApprovalLimitDistribution,
2237 #[serde(default)]
2239 pub department_distribution: EmployeeDepartmentDistribution,
2240}
2241
2242fn default_employee_count() -> usize {
2243 1500
2244}
2245
2246fn default_hierarchy_depth() -> u8 {
2247 6
2248}
2249
2250fn default_span_of_control() -> f64 {
2251 5.0
2252}
2253
2254impl Default for EmployeeMasterConfig {
2255 fn default() -> Self {
2256 Self {
2257 count: default_employee_count(),
2258 generate_hierarchy: true,
2259 max_hierarchy_depth: default_hierarchy_depth(),
2260 average_span_of_control: default_span_of_control(),
2261 approval_limits: ApprovalLimitDistribution::default(),
2262 department_distribution: EmployeeDepartmentDistribution::default(),
2263 }
2264 }
2265}
2266
2267#[derive(Debug, Clone, Serialize, Deserialize)]
2269pub struct ApprovalLimitDistribution {
2270 #[serde(default = "default_staff_limit")]
2272 pub staff: f64,
2273 #[serde(default = "default_senior_limit")]
2275 pub senior: f64,
2276 #[serde(default = "default_manager_limit")]
2278 pub manager: f64,
2279 #[serde(default = "default_director_limit")]
2281 pub director: f64,
2282 #[serde(default = "default_vp_limit")]
2284 pub vp: f64,
2285 #[serde(default = "default_executive_limit")]
2287 pub executive: f64,
2288}
2289
2290fn default_staff_limit() -> f64 {
2291 1000.0
2292}
2293fn default_senior_limit() -> f64 {
2294 5000.0
2295}
2296fn default_manager_limit() -> f64 {
2297 25000.0
2298}
2299fn default_director_limit() -> f64 {
2300 100000.0
2301}
2302fn default_vp_limit() -> f64 {
2303 500000.0
2304}
2305fn default_executive_limit() -> f64 {
2306 f64::INFINITY
2307}
2308
2309impl Default for ApprovalLimitDistribution {
2310 fn default() -> Self {
2311 Self {
2312 staff: default_staff_limit(),
2313 senior: default_senior_limit(),
2314 manager: default_manager_limit(),
2315 director: default_director_limit(),
2316 vp: default_vp_limit(),
2317 executive: default_executive_limit(),
2318 }
2319 }
2320}
2321
2322#[derive(Debug, Clone, Serialize, Deserialize)]
2324pub struct EmployeeDepartmentDistribution {
2325 pub finance: f64,
2327 pub procurement: f64,
2329 pub sales: f64,
2331 pub warehouse: f64,
2333 pub it: f64,
2335 pub hr: f64,
2337 pub operations: f64,
2339 pub executive: f64,
2341}
2342
2343impl Default for EmployeeDepartmentDistribution {
2344 fn default() -> Self {
2345 Self {
2346 finance: 0.12,
2347 procurement: 0.10,
2348 sales: 0.25,
2349 warehouse: 0.15,
2350 it: 0.10,
2351 hr: 0.05,
2352 operations: 0.20,
2353 executive: 0.03,
2354 }
2355 }
2356}
2357
2358#[derive(Debug, Clone, Serialize, Deserialize)]
2360pub struct CostCenterMasterConfig {
2361 #[serde(default = "default_cost_center_count")]
2363 pub count: usize,
2364 #[serde(default = "default_true")]
2366 pub generate_hierarchy: bool,
2367 #[serde(default = "default_cc_hierarchy_depth")]
2369 pub max_hierarchy_depth: u8,
2370}
2371
2372fn default_cost_center_count() -> usize {
2373 50
2374}
2375
2376fn default_cc_hierarchy_depth() -> u8 {
2377 3
2378}
2379
2380impl Default for CostCenterMasterConfig {
2381 fn default() -> Self {
2382 Self {
2383 count: default_cost_center_count(),
2384 generate_hierarchy: true,
2385 max_hierarchy_depth: default_cc_hierarchy_depth(),
2386 }
2387 }
2388}
2389
2390#[derive(Debug, Clone, Serialize, Deserialize)]
2396pub struct DocumentFlowConfig {
2397 #[serde(default)]
2399 pub p2p: P2PFlowConfig,
2400 #[serde(default)]
2402 pub o2c: O2CFlowConfig,
2403 #[serde(default = "default_true")]
2405 pub generate_document_references: bool,
2406 #[serde(default)]
2408 pub export_flow_graph: bool,
2409}
2410
2411impl Default for DocumentFlowConfig {
2412 fn default() -> Self {
2413 Self {
2414 p2p: P2PFlowConfig::default(),
2415 o2c: O2CFlowConfig::default(),
2416 generate_document_references: true,
2417 export_flow_graph: false,
2418 }
2419 }
2420}
2421
2422#[derive(Debug, Clone, Serialize, Deserialize)]
2424pub struct P2PFlowConfig {
2425 #[serde(default = "default_true")]
2427 pub enabled: bool,
2428 #[serde(default = "default_three_way_match_rate")]
2430 pub three_way_match_rate: f64,
2431 #[serde(default = "default_partial_delivery_rate")]
2433 pub partial_delivery_rate: f64,
2434 #[serde(default = "default_price_variance_rate")]
2436 pub price_variance_rate: f64,
2437 #[serde(default = "default_max_price_variance")]
2439 pub max_price_variance_percent: f64,
2440 #[serde(default = "default_quantity_variance_rate")]
2442 pub quantity_variance_rate: f64,
2443 #[serde(default = "default_po_to_gr_days")]
2445 pub average_po_to_gr_days: u32,
2446 #[serde(default = "default_gr_to_invoice_days")]
2448 pub average_gr_to_invoice_days: u32,
2449 #[serde(default = "default_invoice_to_payment_days")]
2451 pub average_invoice_to_payment_days: u32,
2452 #[serde(default)]
2454 pub line_count_distribution: DocumentLineCountDistribution,
2455 #[serde(default)]
2457 pub payment_behavior: P2PPaymentBehaviorConfig,
2458}
2459
2460fn default_three_way_match_rate() -> f64 {
2461 0.95
2462}
2463
2464fn default_partial_delivery_rate() -> f64 {
2465 0.15
2466}
2467
2468fn default_price_variance_rate() -> f64 {
2469 0.08
2470}
2471
2472fn default_max_price_variance() -> f64 {
2473 0.05
2474}
2475
2476fn default_quantity_variance_rate() -> f64 {
2477 0.05
2478}
2479
2480fn default_po_to_gr_days() -> u32 {
2481 14
2482}
2483
2484fn default_gr_to_invoice_days() -> u32 {
2485 5
2486}
2487
2488fn default_invoice_to_payment_days() -> u32 {
2489 30
2490}
2491
2492impl Default for P2PFlowConfig {
2493 fn default() -> Self {
2494 Self {
2495 enabled: true,
2496 three_way_match_rate: default_three_way_match_rate(),
2497 partial_delivery_rate: default_partial_delivery_rate(),
2498 price_variance_rate: default_price_variance_rate(),
2499 max_price_variance_percent: default_max_price_variance(),
2500 quantity_variance_rate: default_quantity_variance_rate(),
2501 average_po_to_gr_days: default_po_to_gr_days(),
2502 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2503 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2504 line_count_distribution: DocumentLineCountDistribution::default(),
2505 payment_behavior: P2PPaymentBehaviorConfig::default(),
2506 }
2507 }
2508}
2509
2510#[derive(Debug, Clone, Serialize, Deserialize)]
2516pub struct P2PPaymentBehaviorConfig {
2517 #[serde(default = "default_p2p_late_payment_rate")]
2519 pub late_payment_rate: f64,
2520 #[serde(default)]
2522 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2523 #[serde(default = "default_p2p_partial_payment_rate")]
2525 pub partial_payment_rate: f64,
2526 #[serde(default = "default_p2p_payment_correction_rate")]
2528 pub payment_correction_rate: f64,
2529}
2530
2531fn default_p2p_late_payment_rate() -> f64 {
2532 0.15
2533}
2534
2535fn default_p2p_partial_payment_rate() -> f64 {
2536 0.05
2537}
2538
2539fn default_p2p_payment_correction_rate() -> f64 {
2540 0.02
2541}
2542
2543impl Default for P2PPaymentBehaviorConfig {
2544 fn default() -> Self {
2545 Self {
2546 late_payment_rate: default_p2p_late_payment_rate(),
2547 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2548 partial_payment_rate: default_p2p_partial_payment_rate(),
2549 payment_correction_rate: default_p2p_payment_correction_rate(),
2550 }
2551 }
2552}
2553
2554#[derive(Debug, Clone, Serialize, Deserialize)]
2556pub struct LatePaymentDaysDistribution {
2557 #[serde(default = "default_slightly_late")]
2559 pub slightly_late_1_to_7: f64,
2560 #[serde(default = "default_late_8_14")]
2562 pub late_8_to_14: f64,
2563 #[serde(default = "default_very_late")]
2565 pub very_late_15_to_30: f64,
2566 #[serde(default = "default_severely_late")]
2568 pub severely_late_31_to_60: f64,
2569 #[serde(default = "default_extremely_late")]
2571 pub extremely_late_over_60: f64,
2572}
2573
2574fn default_slightly_late() -> f64 {
2575 0.50
2576}
2577
2578fn default_late_8_14() -> f64 {
2579 0.25
2580}
2581
2582fn default_very_late() -> f64 {
2583 0.15
2584}
2585
2586fn default_severely_late() -> f64 {
2587 0.07
2588}
2589
2590fn default_extremely_late() -> f64 {
2591 0.03
2592}
2593
2594impl Default for LatePaymentDaysDistribution {
2595 fn default() -> Self {
2596 Self {
2597 slightly_late_1_to_7: default_slightly_late(),
2598 late_8_to_14: default_late_8_14(),
2599 very_late_15_to_30: default_very_late(),
2600 severely_late_31_to_60: default_severely_late(),
2601 extremely_late_over_60: default_extremely_late(),
2602 }
2603 }
2604}
2605
2606#[derive(Debug, Clone, Serialize, Deserialize)]
2608pub struct O2CFlowConfig {
2609 #[serde(default = "default_true")]
2611 pub enabled: bool,
2612 #[serde(default = "default_credit_check_failure_rate")]
2614 pub credit_check_failure_rate: f64,
2615 #[serde(default = "default_partial_shipment_rate")]
2617 pub partial_shipment_rate: f64,
2618 #[serde(default = "default_return_rate")]
2620 pub return_rate: f64,
2621 #[serde(default = "default_bad_debt_rate")]
2623 pub bad_debt_rate: f64,
2624 #[serde(default = "default_so_to_delivery_days")]
2626 pub average_so_to_delivery_days: u32,
2627 #[serde(default = "default_delivery_to_invoice_days")]
2629 pub average_delivery_to_invoice_days: u32,
2630 #[serde(default = "default_invoice_to_receipt_days")]
2632 pub average_invoice_to_receipt_days: u32,
2633 #[serde(default)]
2635 pub line_count_distribution: DocumentLineCountDistribution,
2636 #[serde(default)]
2638 pub cash_discount: CashDiscountConfig,
2639 #[serde(default)]
2641 pub payment_behavior: O2CPaymentBehaviorConfig,
2642}
2643
2644fn default_credit_check_failure_rate() -> f64 {
2645 0.02
2646}
2647
2648fn default_partial_shipment_rate() -> f64 {
2649 0.10
2650}
2651
2652fn default_return_rate() -> f64 {
2653 0.03
2654}
2655
2656fn default_bad_debt_rate() -> f64 {
2657 0.01
2658}
2659
2660fn default_so_to_delivery_days() -> u32 {
2661 7
2662}
2663
2664fn default_delivery_to_invoice_days() -> u32 {
2665 1
2666}
2667
2668fn default_invoice_to_receipt_days() -> u32 {
2669 45
2670}
2671
2672impl Default for O2CFlowConfig {
2673 fn default() -> Self {
2674 Self {
2675 enabled: true,
2676 credit_check_failure_rate: default_credit_check_failure_rate(),
2677 partial_shipment_rate: default_partial_shipment_rate(),
2678 return_rate: default_return_rate(),
2679 bad_debt_rate: default_bad_debt_rate(),
2680 average_so_to_delivery_days: default_so_to_delivery_days(),
2681 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2682 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2683 line_count_distribution: DocumentLineCountDistribution::default(),
2684 cash_discount: CashDiscountConfig::default(),
2685 payment_behavior: O2CPaymentBehaviorConfig::default(),
2686 }
2687 }
2688}
2689
2690#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2696pub struct O2CPaymentBehaviorConfig {
2697 #[serde(default)]
2699 pub dunning: DunningConfig,
2700 #[serde(default)]
2702 pub partial_payments: PartialPaymentConfig,
2703 #[serde(default)]
2705 pub short_payments: ShortPaymentConfig,
2706 #[serde(default)]
2708 pub on_account_payments: OnAccountPaymentConfig,
2709 #[serde(default)]
2711 pub payment_corrections: PaymentCorrectionConfig,
2712}
2713
2714#[derive(Debug, Clone, Serialize, Deserialize)]
2716pub struct DunningConfig {
2717 #[serde(default)]
2719 pub enabled: bool,
2720 #[serde(default = "default_dunning_level_1_days")]
2722 pub level_1_days_overdue: u32,
2723 #[serde(default = "default_dunning_level_2_days")]
2725 pub level_2_days_overdue: u32,
2726 #[serde(default = "default_dunning_level_3_days")]
2728 pub level_3_days_overdue: u32,
2729 #[serde(default = "default_collection_days")]
2731 pub collection_days_overdue: u32,
2732 #[serde(default)]
2734 pub payment_after_dunning_rates: DunningPaymentRates,
2735 #[serde(default = "default_dunning_block_rate")]
2737 pub dunning_block_rate: f64,
2738 #[serde(default = "default_dunning_interest_rate")]
2740 pub interest_rate_per_year: f64,
2741 #[serde(default = "default_dunning_charge")]
2743 pub dunning_charge: f64,
2744}
2745
2746fn default_dunning_level_1_days() -> u32 {
2747 14
2748}
2749
2750fn default_dunning_level_2_days() -> u32 {
2751 28
2752}
2753
2754fn default_dunning_level_3_days() -> u32 {
2755 42
2756}
2757
2758fn default_collection_days() -> u32 {
2759 60
2760}
2761
2762fn default_dunning_block_rate() -> f64 {
2763 0.05
2764}
2765
2766fn default_dunning_interest_rate() -> f64 {
2767 0.09
2768}
2769
2770fn default_dunning_charge() -> f64 {
2771 25.0
2772}
2773
2774impl Default for DunningConfig {
2775 fn default() -> Self {
2776 Self {
2777 enabled: false,
2778 level_1_days_overdue: default_dunning_level_1_days(),
2779 level_2_days_overdue: default_dunning_level_2_days(),
2780 level_3_days_overdue: default_dunning_level_3_days(),
2781 collection_days_overdue: default_collection_days(),
2782 payment_after_dunning_rates: DunningPaymentRates::default(),
2783 dunning_block_rate: default_dunning_block_rate(),
2784 interest_rate_per_year: default_dunning_interest_rate(),
2785 dunning_charge: default_dunning_charge(),
2786 }
2787 }
2788}
2789
2790#[derive(Debug, Clone, Serialize, Deserialize)]
2792pub struct DunningPaymentRates {
2793 #[serde(default = "default_after_level_1")]
2795 pub after_level_1: f64,
2796 #[serde(default = "default_after_level_2")]
2798 pub after_level_2: f64,
2799 #[serde(default = "default_after_level_3")]
2801 pub after_level_3: f64,
2802 #[serde(default = "default_during_collection")]
2804 pub during_collection: f64,
2805 #[serde(default = "default_never_pay")]
2807 pub never_pay: f64,
2808}
2809
2810fn default_after_level_1() -> f64 {
2811 0.40
2812}
2813
2814fn default_after_level_2() -> f64 {
2815 0.30
2816}
2817
2818fn default_after_level_3() -> f64 {
2819 0.15
2820}
2821
2822fn default_during_collection() -> f64 {
2823 0.05
2824}
2825
2826fn default_never_pay() -> f64 {
2827 0.10
2828}
2829
2830impl Default for DunningPaymentRates {
2831 fn default() -> Self {
2832 Self {
2833 after_level_1: default_after_level_1(),
2834 after_level_2: default_after_level_2(),
2835 after_level_3: default_after_level_3(),
2836 during_collection: default_during_collection(),
2837 never_pay: default_never_pay(),
2838 }
2839 }
2840}
2841
2842#[derive(Debug, Clone, Serialize, Deserialize)]
2844pub struct PartialPaymentConfig {
2845 #[serde(default = "default_partial_payment_rate")]
2847 pub rate: f64,
2848 #[serde(default)]
2850 pub percentage_distribution: PartialPaymentPercentageDistribution,
2851 #[serde(default = "default_avg_days_until_remainder")]
2853 pub avg_days_until_remainder: u32,
2854}
2855
2856fn default_partial_payment_rate() -> f64 {
2857 0.08
2858}
2859
2860fn default_avg_days_until_remainder() -> u32 {
2861 30
2862}
2863
2864impl Default for PartialPaymentConfig {
2865 fn default() -> Self {
2866 Self {
2867 rate: default_partial_payment_rate(),
2868 percentage_distribution: PartialPaymentPercentageDistribution::default(),
2869 avg_days_until_remainder: default_avg_days_until_remainder(),
2870 }
2871 }
2872}
2873
2874#[derive(Debug, Clone, Serialize, Deserialize)]
2876pub struct PartialPaymentPercentageDistribution {
2877 #[serde(default = "default_partial_25")]
2879 pub pay_25_percent: f64,
2880 #[serde(default = "default_partial_50")]
2882 pub pay_50_percent: f64,
2883 #[serde(default = "default_partial_75")]
2885 pub pay_75_percent: f64,
2886 #[serde(default = "default_partial_random")]
2888 pub pay_random_percent: f64,
2889}
2890
2891fn default_partial_25() -> f64 {
2892 0.15
2893}
2894
2895fn default_partial_50() -> f64 {
2896 0.50
2897}
2898
2899fn default_partial_75() -> f64 {
2900 0.25
2901}
2902
2903fn default_partial_random() -> f64 {
2904 0.10
2905}
2906
2907impl Default for PartialPaymentPercentageDistribution {
2908 fn default() -> Self {
2909 Self {
2910 pay_25_percent: default_partial_25(),
2911 pay_50_percent: default_partial_50(),
2912 pay_75_percent: default_partial_75(),
2913 pay_random_percent: default_partial_random(),
2914 }
2915 }
2916}
2917
2918#[derive(Debug, Clone, Serialize, Deserialize)]
2920pub struct ShortPaymentConfig {
2921 #[serde(default = "default_short_payment_rate")]
2923 pub rate: f64,
2924 #[serde(default)]
2926 pub reason_distribution: ShortPaymentReasonDistribution,
2927 #[serde(default = "default_max_short_percent")]
2929 pub max_short_percent: f64,
2930}
2931
2932fn default_short_payment_rate() -> f64 {
2933 0.03
2934}
2935
2936fn default_max_short_percent() -> f64 {
2937 0.10
2938}
2939
2940impl Default for ShortPaymentConfig {
2941 fn default() -> Self {
2942 Self {
2943 rate: default_short_payment_rate(),
2944 reason_distribution: ShortPaymentReasonDistribution::default(),
2945 max_short_percent: default_max_short_percent(),
2946 }
2947 }
2948}
2949
2950#[derive(Debug, Clone, Serialize, Deserialize)]
2952pub struct ShortPaymentReasonDistribution {
2953 #[serde(default = "default_pricing_dispute")]
2955 pub pricing_dispute: f64,
2956 #[serde(default = "default_quality_issue")]
2958 pub quality_issue: f64,
2959 #[serde(default = "default_quantity_discrepancy")]
2961 pub quantity_discrepancy: f64,
2962 #[serde(default = "default_unauthorized_deduction")]
2964 pub unauthorized_deduction: f64,
2965 #[serde(default = "default_incorrect_discount")]
2967 pub incorrect_discount: f64,
2968}
2969
2970fn default_pricing_dispute() -> f64 {
2971 0.30
2972}
2973
2974fn default_quality_issue() -> f64 {
2975 0.20
2976}
2977
2978fn default_quantity_discrepancy() -> f64 {
2979 0.20
2980}
2981
2982fn default_unauthorized_deduction() -> f64 {
2983 0.15
2984}
2985
2986fn default_incorrect_discount() -> f64 {
2987 0.15
2988}
2989
2990impl Default for ShortPaymentReasonDistribution {
2991 fn default() -> Self {
2992 Self {
2993 pricing_dispute: default_pricing_dispute(),
2994 quality_issue: default_quality_issue(),
2995 quantity_discrepancy: default_quantity_discrepancy(),
2996 unauthorized_deduction: default_unauthorized_deduction(),
2997 incorrect_discount: default_incorrect_discount(),
2998 }
2999 }
3000}
3001
3002#[derive(Debug, Clone, Serialize, Deserialize)]
3004pub struct OnAccountPaymentConfig {
3005 #[serde(default = "default_on_account_rate")]
3007 pub rate: f64,
3008 #[serde(default = "default_avg_days_until_applied")]
3010 pub avg_days_until_applied: u32,
3011}
3012
3013fn default_on_account_rate() -> f64 {
3014 0.02
3015}
3016
3017fn default_avg_days_until_applied() -> u32 {
3018 14
3019}
3020
3021impl Default for OnAccountPaymentConfig {
3022 fn default() -> Self {
3023 Self {
3024 rate: default_on_account_rate(),
3025 avg_days_until_applied: default_avg_days_until_applied(),
3026 }
3027 }
3028}
3029
3030#[derive(Debug, Clone, Serialize, Deserialize)]
3032pub struct PaymentCorrectionConfig {
3033 #[serde(default = "default_payment_correction_rate")]
3035 pub rate: f64,
3036 #[serde(default)]
3038 pub type_distribution: PaymentCorrectionTypeDistribution,
3039}
3040
3041fn default_payment_correction_rate() -> f64 {
3042 0.02
3043}
3044
3045impl Default for PaymentCorrectionConfig {
3046 fn default() -> Self {
3047 Self {
3048 rate: default_payment_correction_rate(),
3049 type_distribution: PaymentCorrectionTypeDistribution::default(),
3050 }
3051 }
3052}
3053
3054#[derive(Debug, Clone, Serialize, Deserialize)]
3056pub struct PaymentCorrectionTypeDistribution {
3057 #[serde(default = "default_nsf_rate")]
3059 pub nsf: f64,
3060 #[serde(default = "default_chargeback_rate")]
3062 pub chargeback: f64,
3063 #[serde(default = "default_wrong_amount_rate")]
3065 pub wrong_amount: f64,
3066 #[serde(default = "default_wrong_customer_rate")]
3068 pub wrong_customer: f64,
3069 #[serde(default = "default_duplicate_payment_rate")]
3071 pub duplicate_payment: f64,
3072}
3073
3074fn default_nsf_rate() -> f64 {
3075 0.30
3076}
3077
3078fn default_chargeback_rate() -> f64 {
3079 0.20
3080}
3081
3082fn default_wrong_amount_rate() -> f64 {
3083 0.20
3084}
3085
3086fn default_wrong_customer_rate() -> f64 {
3087 0.15
3088}
3089
3090fn default_duplicate_payment_rate() -> f64 {
3091 0.15
3092}
3093
3094impl Default for PaymentCorrectionTypeDistribution {
3095 fn default() -> Self {
3096 Self {
3097 nsf: default_nsf_rate(),
3098 chargeback: default_chargeback_rate(),
3099 wrong_amount: default_wrong_amount_rate(),
3100 wrong_customer: default_wrong_customer_rate(),
3101 duplicate_payment: default_duplicate_payment_rate(),
3102 }
3103 }
3104}
3105
3106#[derive(Debug, Clone, Serialize, Deserialize)]
3108pub struct DocumentLineCountDistribution {
3109 #[serde(default = "default_min_lines")]
3111 pub min_lines: u32,
3112 #[serde(default = "default_max_lines")]
3114 pub max_lines: u32,
3115 #[serde(default = "default_mode_lines")]
3117 pub mode_lines: u32,
3118}
3119
3120fn default_min_lines() -> u32 {
3121 1
3122}
3123
3124fn default_max_lines() -> u32 {
3125 20
3126}
3127
3128fn default_mode_lines() -> u32 {
3129 3
3130}
3131
3132impl Default for DocumentLineCountDistribution {
3133 fn default() -> Self {
3134 Self {
3135 min_lines: default_min_lines(),
3136 max_lines: default_max_lines(),
3137 mode_lines: default_mode_lines(),
3138 }
3139 }
3140}
3141
3142#[derive(Debug, Clone, Serialize, Deserialize)]
3144pub struct CashDiscountConfig {
3145 #[serde(default = "default_discount_eligible_rate")]
3147 pub eligible_rate: f64,
3148 #[serde(default = "default_discount_taken_rate")]
3150 pub taken_rate: f64,
3151 #[serde(default = "default_discount_percent")]
3153 pub discount_percent: f64,
3154 #[serde(default = "default_discount_days")]
3156 pub discount_days: u32,
3157}
3158
3159fn default_discount_eligible_rate() -> f64 {
3160 0.30
3161}
3162
3163fn default_discount_taken_rate() -> f64 {
3164 0.60
3165}
3166
3167fn default_discount_percent() -> f64 {
3168 0.02
3169}
3170
3171fn default_discount_days() -> u32 {
3172 10
3173}
3174
3175impl Default for CashDiscountConfig {
3176 fn default() -> Self {
3177 Self {
3178 eligible_rate: default_discount_eligible_rate(),
3179 taken_rate: default_discount_taken_rate(),
3180 discount_percent: default_discount_percent(),
3181 discount_days: default_discount_days(),
3182 }
3183 }
3184}
3185
3186#[derive(Debug, Clone, Serialize, Deserialize)]
3192pub struct IntercompanyConfig {
3193 #[serde(default)]
3195 pub enabled: bool,
3196 #[serde(default = "default_ic_transaction_rate")]
3198 pub ic_transaction_rate: f64,
3199 #[serde(default)]
3201 pub transfer_pricing_method: TransferPricingMethod,
3202 #[serde(default = "default_markup_percent")]
3204 pub markup_percent: f64,
3205 #[serde(default = "default_true")]
3207 pub generate_matched_pairs: bool,
3208 #[serde(default)]
3210 pub transaction_type_distribution: ICTransactionTypeDistribution,
3211 #[serde(default)]
3213 pub generate_eliminations: bool,
3214}
3215
3216fn default_ic_transaction_rate() -> f64 {
3217 0.15
3218}
3219
3220fn default_markup_percent() -> f64 {
3221 0.05
3222}
3223
3224impl Default for IntercompanyConfig {
3225 fn default() -> Self {
3226 Self {
3227 enabled: false,
3228 ic_transaction_rate: default_ic_transaction_rate(),
3229 transfer_pricing_method: TransferPricingMethod::default(),
3230 markup_percent: default_markup_percent(),
3231 generate_matched_pairs: true,
3232 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3233 generate_eliminations: false,
3234 }
3235 }
3236}
3237
3238#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3240#[serde(rename_all = "snake_case")]
3241pub enum TransferPricingMethod {
3242 #[default]
3244 CostPlus,
3245 ComparableUncontrolled,
3247 ResalePrice,
3249 TransactionalNetMargin,
3251 ProfitSplit,
3253}
3254
3255#[derive(Debug, Clone, Serialize, Deserialize)]
3257pub struct ICTransactionTypeDistribution {
3258 pub goods_sale: f64,
3260 pub service_provided: f64,
3262 pub loan: f64,
3264 pub dividend: f64,
3266 pub management_fee: f64,
3268 pub royalty: f64,
3270 pub cost_sharing: f64,
3272}
3273
3274impl Default for ICTransactionTypeDistribution {
3275 fn default() -> Self {
3276 Self {
3277 goods_sale: 0.35,
3278 service_provided: 0.20,
3279 loan: 0.10,
3280 dividend: 0.05,
3281 management_fee: 0.15,
3282 royalty: 0.10,
3283 cost_sharing: 0.05,
3284 }
3285 }
3286}
3287
3288#[derive(Debug, Clone, Serialize, Deserialize)]
3294pub struct BalanceConfig {
3295 #[serde(default)]
3297 pub generate_opening_balances: bool,
3298 #[serde(default = "default_true")]
3300 pub generate_trial_balances: bool,
3301 #[serde(default = "default_gross_margin")]
3303 pub target_gross_margin: f64,
3304 #[serde(default = "default_dso")]
3306 pub target_dso_days: u32,
3307 #[serde(default = "default_dpo")]
3309 pub target_dpo_days: u32,
3310 #[serde(default = "default_current_ratio")]
3312 pub target_current_ratio: f64,
3313 #[serde(default = "default_debt_equity")]
3315 pub target_debt_to_equity: f64,
3316 #[serde(default = "default_true")]
3318 pub validate_balance_equation: bool,
3319 #[serde(default = "default_true")]
3321 pub reconcile_subledgers: bool,
3322}
3323
3324fn default_gross_margin() -> f64 {
3325 0.35
3326}
3327
3328fn default_dso() -> u32 {
3329 45
3330}
3331
3332fn default_dpo() -> u32 {
3333 30
3334}
3335
3336fn default_current_ratio() -> f64 {
3337 1.5
3338}
3339
3340fn default_debt_equity() -> f64 {
3341 0.5
3342}
3343
3344impl Default for BalanceConfig {
3345 fn default() -> Self {
3346 Self {
3347 generate_opening_balances: false,
3348 generate_trial_balances: true,
3349 target_gross_margin: default_gross_margin(),
3350 target_dso_days: default_dso(),
3351 target_dpo_days: default_dpo(),
3352 target_current_ratio: default_current_ratio(),
3353 target_debt_to_equity: default_debt_equity(),
3354 validate_balance_equation: true,
3355 reconcile_subledgers: true,
3356 }
3357 }
3358}
3359
3360#[derive(Debug, Clone, Serialize, Deserialize)]
3369pub struct OcpmConfig {
3370 #[serde(default)]
3372 pub enabled: bool,
3373
3374 #[serde(default = "default_true")]
3376 pub generate_lifecycle_events: bool,
3377
3378 #[serde(default = "default_true")]
3380 pub include_object_relationships: bool,
3381
3382 #[serde(default = "default_true")]
3384 pub compute_variants: bool,
3385
3386 #[serde(default)]
3388 pub max_variants: usize,
3389
3390 #[serde(default)]
3392 pub p2p_process: OcpmProcessConfig,
3393
3394 #[serde(default)]
3396 pub o2c_process: OcpmProcessConfig,
3397
3398 #[serde(default)]
3400 pub output: OcpmOutputConfig,
3401}
3402
3403impl Default for OcpmConfig {
3404 fn default() -> Self {
3405 Self {
3406 enabled: false,
3407 generate_lifecycle_events: true,
3408 include_object_relationships: true,
3409 compute_variants: true,
3410 max_variants: 0,
3411 p2p_process: OcpmProcessConfig::default(),
3412 o2c_process: OcpmProcessConfig::default(),
3413 output: OcpmOutputConfig::default(),
3414 }
3415 }
3416}
3417
3418#[derive(Debug, Clone, Serialize, Deserialize)]
3420pub struct OcpmProcessConfig {
3421 #[serde(default = "default_rework_probability")]
3423 pub rework_probability: f64,
3424
3425 #[serde(default = "default_skip_probability")]
3427 pub skip_step_probability: f64,
3428
3429 #[serde(default = "default_out_of_order_probability")]
3431 pub out_of_order_probability: f64,
3432}
3433
3434fn default_rework_probability() -> f64 {
3435 0.05
3436}
3437
3438fn default_skip_probability() -> f64 {
3439 0.02
3440}
3441
3442fn default_out_of_order_probability() -> f64 {
3443 0.03
3444}
3445
3446impl Default for OcpmProcessConfig {
3447 fn default() -> Self {
3448 Self {
3449 rework_probability: default_rework_probability(),
3450 skip_step_probability: default_skip_probability(),
3451 out_of_order_probability: default_out_of_order_probability(),
3452 }
3453 }
3454}
3455
3456#[derive(Debug, Clone, Serialize, Deserialize)]
3458pub struct OcpmOutputConfig {
3459 #[serde(default = "default_true")]
3461 pub ocel_json: bool,
3462
3463 #[serde(default)]
3465 pub ocel_xml: bool,
3466
3467 #[serde(default)]
3469 pub xes: bool,
3470
3471 #[serde(default = "default_true")]
3473 pub xes_include_lifecycle: bool,
3474
3475 #[serde(default = "default_true")]
3477 pub xes_include_resources: bool,
3478
3479 #[serde(default = "default_true")]
3481 pub flattened_csv: bool,
3482
3483 #[serde(default = "default_true")]
3485 pub event_object_csv: bool,
3486
3487 #[serde(default = "default_true")]
3489 pub object_relationship_csv: bool,
3490
3491 #[serde(default = "default_true")]
3493 pub variants_csv: bool,
3494
3495 #[serde(default)]
3497 pub export_reference_models: bool,
3498}
3499
3500impl Default for OcpmOutputConfig {
3501 fn default() -> Self {
3502 Self {
3503 ocel_json: true,
3504 ocel_xml: false,
3505 xes: false,
3506 xes_include_lifecycle: true,
3507 xes_include_resources: true,
3508 flattened_csv: true,
3509 event_object_csv: true,
3510 object_relationship_csv: true,
3511 variants_csv: true,
3512 export_reference_models: false,
3513 }
3514 }
3515}
3516
3517#[derive(Debug, Clone, Serialize, Deserialize)]
3519pub struct AuditGenerationConfig {
3520 #[serde(default)]
3522 pub enabled: bool,
3523
3524 #[serde(default = "default_true")]
3526 pub generate_workpapers: bool,
3527
3528 #[serde(default)]
3530 pub engagement_types: AuditEngagementTypesConfig,
3531
3532 #[serde(default)]
3534 pub workpapers: WorkpaperConfig,
3535
3536 #[serde(default)]
3538 pub team: AuditTeamConfig,
3539
3540 #[serde(default)]
3542 pub review: ReviewWorkflowConfig,
3543}
3544
3545impl Default for AuditGenerationConfig {
3546 fn default() -> Self {
3547 Self {
3548 enabled: false,
3549 generate_workpapers: true,
3550 engagement_types: AuditEngagementTypesConfig::default(),
3551 workpapers: WorkpaperConfig::default(),
3552 team: AuditTeamConfig::default(),
3553 review: ReviewWorkflowConfig::default(),
3554 }
3555 }
3556}
3557
3558#[derive(Debug, Clone, Serialize, Deserialize)]
3560pub struct AuditEngagementTypesConfig {
3561 #[serde(default = "default_financial_audit_prob")]
3563 pub financial_statement: f64,
3564 #[serde(default = "default_sox_audit_prob")]
3566 pub sox_icfr: f64,
3567 #[serde(default = "default_integrated_audit_prob")]
3569 pub integrated: f64,
3570 #[serde(default = "default_review_prob")]
3572 pub review: f64,
3573 #[serde(default = "default_aup_prob")]
3575 pub agreed_upon_procedures: f64,
3576}
3577
3578fn default_financial_audit_prob() -> f64 {
3579 0.40
3580}
3581fn default_sox_audit_prob() -> f64 {
3582 0.20
3583}
3584fn default_integrated_audit_prob() -> f64 {
3585 0.25
3586}
3587fn default_review_prob() -> f64 {
3588 0.10
3589}
3590fn default_aup_prob() -> f64 {
3591 0.05
3592}
3593
3594impl Default for AuditEngagementTypesConfig {
3595 fn default() -> Self {
3596 Self {
3597 financial_statement: default_financial_audit_prob(),
3598 sox_icfr: default_sox_audit_prob(),
3599 integrated: default_integrated_audit_prob(),
3600 review: default_review_prob(),
3601 agreed_upon_procedures: default_aup_prob(),
3602 }
3603 }
3604}
3605
3606#[derive(Debug, Clone, Serialize, Deserialize)]
3608pub struct WorkpaperConfig {
3609 #[serde(default = "default_workpapers_per_phase")]
3611 pub average_per_phase: usize,
3612
3613 #[serde(default = "default_true")]
3615 pub include_isa_references: bool,
3616
3617 #[serde(default = "default_true")]
3619 pub include_sample_details: bool,
3620
3621 #[serde(default = "default_true")]
3623 pub include_cross_references: bool,
3624
3625 #[serde(default)]
3627 pub sampling: SamplingConfig,
3628}
3629
3630fn default_workpapers_per_phase() -> usize {
3631 5
3632}
3633
3634impl Default for WorkpaperConfig {
3635 fn default() -> Self {
3636 Self {
3637 average_per_phase: default_workpapers_per_phase(),
3638 include_isa_references: true,
3639 include_sample_details: true,
3640 include_cross_references: true,
3641 sampling: SamplingConfig::default(),
3642 }
3643 }
3644}
3645
3646#[derive(Debug, Clone, Serialize, Deserialize)]
3648pub struct SamplingConfig {
3649 #[serde(default = "default_statistical_rate")]
3651 pub statistical_rate: f64,
3652 #[serde(default = "default_judgmental_rate")]
3654 pub judgmental_rate: f64,
3655 #[serde(default = "default_haphazard_rate")]
3657 pub haphazard_rate: f64,
3658 #[serde(default = "default_complete_examination_rate")]
3660 pub complete_examination_rate: f64,
3661}
3662
3663fn default_statistical_rate() -> f64 {
3664 0.40
3665}
3666fn default_judgmental_rate() -> f64 {
3667 0.30
3668}
3669fn default_haphazard_rate() -> f64 {
3670 0.20
3671}
3672fn default_complete_examination_rate() -> f64 {
3673 0.10
3674}
3675
3676impl Default for SamplingConfig {
3677 fn default() -> Self {
3678 Self {
3679 statistical_rate: default_statistical_rate(),
3680 judgmental_rate: default_judgmental_rate(),
3681 haphazard_rate: default_haphazard_rate(),
3682 complete_examination_rate: default_complete_examination_rate(),
3683 }
3684 }
3685}
3686
3687#[derive(Debug, Clone, Serialize, Deserialize)]
3689pub struct AuditTeamConfig {
3690 #[serde(default = "default_min_team_size")]
3692 pub min_team_size: usize,
3693 #[serde(default = "default_max_team_size")]
3695 pub max_team_size: usize,
3696 #[serde(default = "default_specialist_probability")]
3698 pub specialist_probability: f64,
3699}
3700
3701fn default_min_team_size() -> usize {
3702 3
3703}
3704fn default_max_team_size() -> usize {
3705 8
3706}
3707fn default_specialist_probability() -> f64 {
3708 0.30
3709}
3710
3711impl Default for AuditTeamConfig {
3712 fn default() -> Self {
3713 Self {
3714 min_team_size: default_min_team_size(),
3715 max_team_size: default_max_team_size(),
3716 specialist_probability: default_specialist_probability(),
3717 }
3718 }
3719}
3720
3721#[derive(Debug, Clone, Serialize, Deserialize)]
3723pub struct ReviewWorkflowConfig {
3724 #[serde(default = "default_review_delay_days")]
3726 pub average_review_delay_days: u32,
3727 #[serde(default = "default_rework_probability_review")]
3729 pub rework_probability: f64,
3730 #[serde(default = "default_true")]
3732 pub require_partner_signoff: bool,
3733}
3734
3735fn default_review_delay_days() -> u32 {
3736 2
3737}
3738fn default_rework_probability_review() -> f64 {
3739 0.15
3740}
3741
3742impl Default for ReviewWorkflowConfig {
3743 fn default() -> Self {
3744 Self {
3745 average_review_delay_days: default_review_delay_days(),
3746 rework_probability: default_rework_probability_review(),
3747 require_partner_signoff: true,
3748 }
3749 }
3750}
3751
3752#[derive(Debug, Clone, Serialize, Deserialize)]
3758pub struct DataQualitySchemaConfig {
3759 #[serde(default)]
3761 pub enabled: bool,
3762 #[serde(default)]
3764 pub preset: DataQualityPreset,
3765 #[serde(default)]
3767 pub missing_values: MissingValuesSchemaConfig,
3768 #[serde(default)]
3770 pub typos: TypoSchemaConfig,
3771 #[serde(default)]
3773 pub format_variations: FormatVariationSchemaConfig,
3774 #[serde(default)]
3776 pub duplicates: DuplicateSchemaConfig,
3777 #[serde(default)]
3779 pub encoding_issues: EncodingIssueSchemaConfig,
3780 #[serde(default)]
3782 pub generate_labels: bool,
3783 #[serde(default)]
3785 pub sink_profiles: SinkQualityProfiles,
3786}
3787
3788impl Default for DataQualitySchemaConfig {
3789 fn default() -> Self {
3790 Self {
3791 enabled: false,
3792 preset: DataQualityPreset::None,
3793 missing_values: MissingValuesSchemaConfig::default(),
3794 typos: TypoSchemaConfig::default(),
3795 format_variations: FormatVariationSchemaConfig::default(),
3796 duplicates: DuplicateSchemaConfig::default(),
3797 encoding_issues: EncodingIssueSchemaConfig::default(),
3798 generate_labels: true,
3799 sink_profiles: SinkQualityProfiles::default(),
3800 }
3801 }
3802}
3803
3804impl DataQualitySchemaConfig {
3805 pub fn with_preset(preset: DataQualityPreset) -> Self {
3807 let mut config = Self {
3808 preset,
3809 ..Default::default()
3810 };
3811 config.apply_preset();
3812 config
3813 }
3814
3815 pub fn apply_preset(&mut self) {
3818 if !self.preset.overrides_settings() {
3819 return;
3820 }
3821
3822 self.enabled = true;
3823
3824 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3826 self.missing_values.rate = self.preset.missing_rate();
3827
3828 self.typos.enabled = self.preset.typo_rate() > 0.0;
3830 self.typos.char_error_rate = self.preset.typo_rate();
3831
3832 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3834 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3835 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3836 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3837
3838 self.format_variations.enabled = self.preset.format_variations_enabled();
3840
3841 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3843 self.encoding_issues.rate = self.preset.encoding_issue_rate();
3844
3845 if self.preset.ocr_errors_enabled() {
3847 self.typos.type_weights.ocr_errors = 0.3;
3848 }
3849 }
3850
3851 pub fn effective_missing_rate(&self) -> f64 {
3853 if self.preset.overrides_settings() {
3854 self.preset.missing_rate()
3855 } else {
3856 self.missing_values.rate
3857 }
3858 }
3859
3860 pub fn effective_typo_rate(&self) -> f64 {
3862 if self.preset.overrides_settings() {
3863 self.preset.typo_rate()
3864 } else {
3865 self.typos.char_error_rate
3866 }
3867 }
3868
3869 pub fn effective_duplicate_rate(&self) -> f64 {
3871 if self.preset.overrides_settings() {
3872 self.preset.duplicate_rate()
3873 } else {
3874 self.duplicates.exact_duplicate_ratio
3875 + self.duplicates.near_duplicate_ratio
3876 + self.duplicates.fuzzy_duplicate_ratio
3877 }
3878 }
3879
3880 pub fn clean() -> Self {
3882 Self::with_preset(DataQualityPreset::Clean)
3883 }
3884
3885 pub fn noisy() -> Self {
3887 Self::with_preset(DataQualityPreset::Noisy)
3888 }
3889
3890 pub fn legacy() -> Self {
3892 Self::with_preset(DataQualityPreset::Legacy)
3893 }
3894}
3895
3896#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3898#[serde(rename_all = "snake_case")]
3899pub enum DataQualityPreset {
3900 #[default]
3902 None,
3903 Minimal,
3905 Normal,
3907 High,
3909 Custom,
3911
3912 Clean,
3918 Noisy,
3921 Legacy,
3924}
3925
3926impl DataQualityPreset {
3927 pub fn missing_rate(&self) -> f64 {
3929 match self {
3930 DataQualityPreset::None => 0.0,
3931 DataQualityPreset::Minimal => 0.005,
3932 DataQualityPreset::Normal => 0.02,
3933 DataQualityPreset::High => 0.08,
3934 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
3936 DataQualityPreset::Noisy => 0.05,
3937 DataQualityPreset::Legacy => 0.10,
3938 }
3939 }
3940
3941 pub fn typo_rate(&self) -> f64 {
3943 match self {
3944 DataQualityPreset::None => 0.0,
3945 DataQualityPreset::Minimal => 0.0005,
3946 DataQualityPreset::Normal => 0.002,
3947 DataQualityPreset::High => 0.01,
3948 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
3950 DataQualityPreset::Noisy => 0.02,
3951 DataQualityPreset::Legacy => 0.05,
3952 }
3953 }
3954
3955 pub fn duplicate_rate(&self) -> f64 {
3957 match self {
3958 DataQualityPreset::None => 0.0,
3959 DataQualityPreset::Minimal => 0.001,
3960 DataQualityPreset::Normal => 0.005,
3961 DataQualityPreset::High => 0.02,
3962 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
3964 DataQualityPreset::Noisy => 0.01,
3965 DataQualityPreset::Legacy => 0.03,
3966 }
3967 }
3968
3969 pub fn format_variations_enabled(&self) -> bool {
3971 match self {
3972 DataQualityPreset::None | DataQualityPreset::Clean => false,
3973 DataQualityPreset::Minimal => true,
3974 DataQualityPreset::Normal => true,
3975 DataQualityPreset::High => true,
3976 DataQualityPreset::Custom => true,
3977 DataQualityPreset::Noisy => true,
3978 DataQualityPreset::Legacy => true,
3979 }
3980 }
3981
3982 pub fn ocr_errors_enabled(&self) -> bool {
3984 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
3985 }
3986
3987 pub fn encoding_issues_enabled(&self) -> bool {
3989 matches!(
3990 self,
3991 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
3992 )
3993 }
3994
3995 pub fn encoding_issue_rate(&self) -> f64 {
3997 match self {
3998 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
3999 DataQualityPreset::Normal => 0.002,
4000 DataQualityPreset::High => 0.01,
4001 DataQualityPreset::Custom => 0.0,
4002 DataQualityPreset::Noisy => 0.005,
4003 DataQualityPreset::Legacy => 0.02,
4004 }
4005 }
4006
4007 pub fn overrides_settings(&self) -> bool {
4009 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4010 }
4011
4012 pub fn description(&self) -> &'static str {
4014 match self {
4015 DataQualityPreset::None => "No data quality issues (pristine data)",
4016 DataQualityPreset::Minimal => "Very rare data quality issues",
4017 DataQualityPreset::Normal => "Realistic enterprise data quality",
4018 DataQualityPreset::High => "Messy data for stress testing",
4019 DataQualityPreset::Custom => "Custom settings from configuration",
4020 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4021 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4022 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4023 }
4024 }
4025}
4026
4027#[derive(Debug, Clone, Serialize, Deserialize)]
4029pub struct MissingValuesSchemaConfig {
4030 #[serde(default)]
4032 pub enabled: bool,
4033 #[serde(default = "default_missing_rate")]
4035 pub rate: f64,
4036 #[serde(default)]
4038 pub strategy: MissingValueStrategy,
4039 #[serde(default)]
4041 pub field_rates: std::collections::HashMap<String, f64>,
4042 #[serde(default)]
4044 pub protected_fields: Vec<String>,
4045}
4046
4047fn default_missing_rate() -> f64 {
4048 0.01
4049}
4050
4051impl Default for MissingValuesSchemaConfig {
4052 fn default() -> Self {
4053 Self {
4054 enabled: false,
4055 rate: default_missing_rate(),
4056 strategy: MissingValueStrategy::Mcar,
4057 field_rates: std::collections::HashMap::new(),
4058 protected_fields: vec![
4059 "document_id".to_string(),
4060 "company_code".to_string(),
4061 "posting_date".to_string(),
4062 ],
4063 }
4064 }
4065}
4066
4067#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4069#[serde(rename_all = "snake_case")]
4070pub enum MissingValueStrategy {
4071 #[default]
4073 Mcar,
4074 Mar,
4076 Mnar,
4078 Systematic,
4080}
4081
4082#[derive(Debug, Clone, Serialize, Deserialize)]
4084pub struct TypoSchemaConfig {
4085 #[serde(default)]
4087 pub enabled: bool,
4088 #[serde(default = "default_typo_rate")]
4090 pub char_error_rate: f64,
4091 #[serde(default)]
4093 pub type_weights: TypoTypeWeights,
4094 #[serde(default)]
4096 pub protected_fields: Vec<String>,
4097}
4098
4099fn default_typo_rate() -> f64 {
4100 0.001
4101}
4102
4103impl Default for TypoSchemaConfig {
4104 fn default() -> Self {
4105 Self {
4106 enabled: false,
4107 char_error_rate: default_typo_rate(),
4108 type_weights: TypoTypeWeights::default(),
4109 protected_fields: vec![
4110 "document_id".to_string(),
4111 "gl_account".to_string(),
4112 "company_code".to_string(),
4113 ],
4114 }
4115 }
4116}
4117
4118#[derive(Debug, Clone, Serialize, Deserialize)]
4120pub struct TypoTypeWeights {
4121 #[serde(default = "default_substitution_weight")]
4123 pub substitution: f64,
4124 #[serde(default = "default_transposition_weight")]
4126 pub transposition: f64,
4127 #[serde(default = "default_insertion_weight")]
4129 pub insertion: f64,
4130 #[serde(default = "default_deletion_weight")]
4132 pub deletion: f64,
4133 #[serde(default = "default_ocr_weight")]
4135 pub ocr_errors: f64,
4136 #[serde(default = "default_homophone_weight")]
4138 pub homophones: f64,
4139}
4140
4141fn default_substitution_weight() -> f64 {
4142 0.35
4143}
4144fn default_transposition_weight() -> f64 {
4145 0.25
4146}
4147fn default_insertion_weight() -> f64 {
4148 0.10
4149}
4150fn default_deletion_weight() -> f64 {
4151 0.15
4152}
4153fn default_ocr_weight() -> f64 {
4154 0.10
4155}
4156fn default_homophone_weight() -> f64 {
4157 0.05
4158}
4159
4160impl Default for TypoTypeWeights {
4161 fn default() -> Self {
4162 Self {
4163 substitution: default_substitution_weight(),
4164 transposition: default_transposition_weight(),
4165 insertion: default_insertion_weight(),
4166 deletion: default_deletion_weight(),
4167 ocr_errors: default_ocr_weight(),
4168 homophones: default_homophone_weight(),
4169 }
4170 }
4171}
4172
4173#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4175pub struct FormatVariationSchemaConfig {
4176 #[serde(default)]
4178 pub enabled: bool,
4179 #[serde(default)]
4181 pub dates: DateFormatVariationConfig,
4182 #[serde(default)]
4184 pub amounts: AmountFormatVariationConfig,
4185 #[serde(default)]
4187 pub identifiers: IdentifierFormatVariationConfig,
4188}
4189
4190#[derive(Debug, Clone, Serialize, Deserialize)]
4192pub struct DateFormatVariationConfig {
4193 #[serde(default)]
4195 pub enabled: bool,
4196 #[serde(default = "default_date_variation_rate")]
4198 pub rate: f64,
4199 #[serde(default = "default_true")]
4201 pub iso_format: bool,
4202 #[serde(default)]
4204 pub us_format: bool,
4205 #[serde(default)]
4207 pub eu_format: bool,
4208 #[serde(default)]
4210 pub long_format: bool,
4211}
4212
4213fn default_date_variation_rate() -> f64 {
4214 0.05
4215}
4216
4217impl Default for DateFormatVariationConfig {
4218 fn default() -> Self {
4219 Self {
4220 enabled: false,
4221 rate: default_date_variation_rate(),
4222 iso_format: true,
4223 us_format: false,
4224 eu_format: false,
4225 long_format: false,
4226 }
4227 }
4228}
4229
4230#[derive(Debug, Clone, Serialize, Deserialize)]
4232pub struct AmountFormatVariationConfig {
4233 #[serde(default)]
4235 pub enabled: bool,
4236 #[serde(default = "default_amount_variation_rate")]
4238 pub rate: f64,
4239 #[serde(default)]
4241 pub us_comma_format: bool,
4242 #[serde(default)]
4244 pub eu_format: bool,
4245 #[serde(default)]
4247 pub currency_prefix: bool,
4248 #[serde(default)]
4250 pub accounting_format: bool,
4251}
4252
4253fn default_amount_variation_rate() -> f64 {
4254 0.02
4255}
4256
4257impl Default for AmountFormatVariationConfig {
4258 fn default() -> Self {
4259 Self {
4260 enabled: false,
4261 rate: default_amount_variation_rate(),
4262 us_comma_format: false,
4263 eu_format: false,
4264 currency_prefix: false,
4265 accounting_format: false,
4266 }
4267 }
4268}
4269
4270#[derive(Debug, Clone, Serialize, Deserialize)]
4272pub struct IdentifierFormatVariationConfig {
4273 #[serde(default)]
4275 pub enabled: bool,
4276 #[serde(default = "default_identifier_variation_rate")]
4278 pub rate: f64,
4279 #[serde(default)]
4281 pub case_variations: bool,
4282 #[serde(default)]
4284 pub padding_variations: bool,
4285 #[serde(default)]
4287 pub separator_variations: bool,
4288}
4289
4290fn default_identifier_variation_rate() -> f64 {
4291 0.02
4292}
4293
4294impl Default for IdentifierFormatVariationConfig {
4295 fn default() -> Self {
4296 Self {
4297 enabled: false,
4298 rate: default_identifier_variation_rate(),
4299 case_variations: false,
4300 padding_variations: false,
4301 separator_variations: false,
4302 }
4303 }
4304}
4305
4306#[derive(Debug, Clone, Serialize, Deserialize)]
4308pub struct DuplicateSchemaConfig {
4309 #[serde(default)]
4311 pub enabled: bool,
4312 #[serde(default = "default_duplicate_rate")]
4314 pub rate: f64,
4315 #[serde(default = "default_exact_duplicate_ratio")]
4317 pub exact_duplicate_ratio: f64,
4318 #[serde(default = "default_near_duplicate_ratio")]
4320 pub near_duplicate_ratio: f64,
4321 #[serde(default = "default_fuzzy_duplicate_ratio")]
4323 pub fuzzy_duplicate_ratio: f64,
4324 #[serde(default = "default_max_date_offset")]
4326 pub max_date_offset_days: u32,
4327 #[serde(default = "default_max_amount_variance")]
4329 pub max_amount_variance: f64,
4330}
4331
4332fn default_duplicate_rate() -> f64 {
4333 0.005
4334}
4335fn default_exact_duplicate_ratio() -> f64 {
4336 0.4
4337}
4338fn default_near_duplicate_ratio() -> f64 {
4339 0.35
4340}
4341fn default_fuzzy_duplicate_ratio() -> f64 {
4342 0.25
4343}
4344fn default_max_date_offset() -> u32 {
4345 3
4346}
4347fn default_max_amount_variance() -> f64 {
4348 0.01
4349}
4350
4351impl Default for DuplicateSchemaConfig {
4352 fn default() -> Self {
4353 Self {
4354 enabled: false,
4355 rate: default_duplicate_rate(),
4356 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4357 near_duplicate_ratio: default_near_duplicate_ratio(),
4358 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4359 max_date_offset_days: default_max_date_offset(),
4360 max_amount_variance: default_max_amount_variance(),
4361 }
4362 }
4363}
4364
4365#[derive(Debug, Clone, Serialize, Deserialize)]
4367pub struct EncodingIssueSchemaConfig {
4368 #[serde(default)]
4370 pub enabled: bool,
4371 #[serde(default = "default_encoding_rate")]
4373 pub rate: f64,
4374 #[serde(default)]
4376 pub mojibake: bool,
4377 #[serde(default)]
4379 pub html_entities: bool,
4380 #[serde(default)]
4382 pub bom_issues: bool,
4383}
4384
4385fn default_encoding_rate() -> f64 {
4386 0.001
4387}
4388
4389impl Default for EncodingIssueSchemaConfig {
4390 fn default() -> Self {
4391 Self {
4392 enabled: false,
4393 rate: default_encoding_rate(),
4394 mojibake: false,
4395 html_entities: false,
4396 bom_issues: false,
4397 }
4398 }
4399}
4400
4401#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4403pub struct SinkQualityProfiles {
4404 #[serde(default)]
4406 pub csv: Option<SinkQualityOverride>,
4407 #[serde(default)]
4409 pub json: Option<SinkQualityOverride>,
4410 #[serde(default)]
4412 pub parquet: Option<SinkQualityOverride>,
4413}
4414
4415#[derive(Debug, Clone, Serialize, Deserialize)]
4417pub struct SinkQualityOverride {
4418 pub enabled: Option<bool>,
4420 pub missing_rate: Option<f64>,
4422 pub typo_rate: Option<f64>,
4424 pub format_variation_rate: Option<f64>,
4426 pub duplicate_rate: Option<f64>,
4428}
4429
4430#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4442pub struct AccountingStandardsConfig {
4443 #[serde(default)]
4445 pub enabled: bool,
4446
4447 #[serde(default)]
4449 pub framework: AccountingFrameworkConfig,
4450
4451 #[serde(default)]
4453 pub revenue_recognition: RevenueRecognitionConfig,
4454
4455 #[serde(default)]
4457 pub leases: LeaseAccountingConfig,
4458
4459 #[serde(default)]
4461 pub fair_value: FairValueConfig,
4462
4463 #[serde(default)]
4465 pub impairment: ImpairmentConfig,
4466
4467 #[serde(default)]
4469 pub generate_differences: bool,
4470}
4471
4472#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4474#[serde(rename_all = "snake_case")]
4475pub enum AccountingFrameworkConfig {
4476 #[default]
4478 UsGaap,
4479 Ifrs,
4481 DualReporting,
4483}
4484
4485#[derive(Debug, Clone, Serialize, Deserialize)]
4487pub struct RevenueRecognitionConfig {
4488 #[serde(default)]
4490 pub enabled: bool,
4491
4492 #[serde(default = "default_true")]
4494 pub generate_contracts: bool,
4495
4496 #[serde(default = "default_avg_obligations")]
4498 pub avg_obligations_per_contract: f64,
4499
4500 #[serde(default = "default_variable_consideration_rate")]
4502 pub variable_consideration_rate: f64,
4503
4504 #[serde(default = "default_over_time_rate")]
4506 pub over_time_recognition_rate: f64,
4507
4508 #[serde(default = "default_contract_count")]
4510 pub contract_count: usize,
4511}
4512
4513fn default_avg_obligations() -> f64 {
4514 2.0
4515}
4516
4517fn default_variable_consideration_rate() -> f64 {
4518 0.15
4519}
4520
4521fn default_over_time_rate() -> f64 {
4522 0.30
4523}
4524
4525fn default_contract_count() -> usize {
4526 100
4527}
4528
4529impl Default for RevenueRecognitionConfig {
4530 fn default() -> Self {
4531 Self {
4532 enabled: false,
4533 generate_contracts: true,
4534 avg_obligations_per_contract: default_avg_obligations(),
4535 variable_consideration_rate: default_variable_consideration_rate(),
4536 over_time_recognition_rate: default_over_time_rate(),
4537 contract_count: default_contract_count(),
4538 }
4539 }
4540}
4541
4542#[derive(Debug, Clone, Serialize, Deserialize)]
4544pub struct LeaseAccountingConfig {
4545 #[serde(default)]
4547 pub enabled: bool,
4548
4549 #[serde(default = "default_lease_count")]
4551 pub lease_count: usize,
4552
4553 #[serde(default = "default_finance_lease_pct")]
4555 pub finance_lease_percent: f64,
4556
4557 #[serde(default = "default_avg_lease_term")]
4559 pub avg_lease_term_months: u32,
4560
4561 #[serde(default = "default_true")]
4563 pub generate_amortization: bool,
4564
4565 #[serde(default = "default_real_estate_pct")]
4567 pub real_estate_percent: f64,
4568}
4569
4570fn default_lease_count() -> usize {
4571 50
4572}
4573
4574fn default_finance_lease_pct() -> f64 {
4575 0.30
4576}
4577
4578fn default_avg_lease_term() -> u32 {
4579 60
4580}
4581
4582fn default_real_estate_pct() -> f64 {
4583 0.40
4584}
4585
4586impl Default for LeaseAccountingConfig {
4587 fn default() -> Self {
4588 Self {
4589 enabled: false,
4590 lease_count: default_lease_count(),
4591 finance_lease_percent: default_finance_lease_pct(),
4592 avg_lease_term_months: default_avg_lease_term(),
4593 generate_amortization: true,
4594 real_estate_percent: default_real_estate_pct(),
4595 }
4596 }
4597}
4598
4599#[derive(Debug, Clone, Serialize, Deserialize)]
4601pub struct FairValueConfig {
4602 #[serde(default)]
4604 pub enabled: bool,
4605
4606 #[serde(default = "default_fv_count")]
4608 pub measurement_count: usize,
4609
4610 #[serde(default = "default_level1_pct")]
4612 pub level1_percent: f64,
4613
4614 #[serde(default = "default_level2_pct")]
4616 pub level2_percent: f64,
4617
4618 #[serde(default = "default_level3_pct")]
4620 pub level3_percent: f64,
4621
4622 #[serde(default)]
4624 pub include_sensitivity_analysis: bool,
4625}
4626
4627fn default_fv_count() -> usize {
4628 25
4629}
4630
4631fn default_level1_pct() -> f64 {
4632 0.40
4633}
4634
4635fn default_level2_pct() -> f64 {
4636 0.35
4637}
4638
4639fn default_level3_pct() -> f64 {
4640 0.25
4641}
4642
4643impl Default for FairValueConfig {
4644 fn default() -> Self {
4645 Self {
4646 enabled: false,
4647 measurement_count: default_fv_count(),
4648 level1_percent: default_level1_pct(),
4649 level2_percent: default_level2_pct(),
4650 level3_percent: default_level3_pct(),
4651 include_sensitivity_analysis: false,
4652 }
4653 }
4654}
4655
4656#[derive(Debug, Clone, Serialize, Deserialize)]
4658pub struct ImpairmentConfig {
4659 #[serde(default)]
4661 pub enabled: bool,
4662
4663 #[serde(default = "default_impairment_count")]
4665 pub test_count: usize,
4666
4667 #[serde(default = "default_impairment_rate")]
4669 pub impairment_rate: f64,
4670
4671 #[serde(default = "default_true")]
4673 pub generate_projections: bool,
4674
4675 #[serde(default)]
4677 pub include_goodwill: bool,
4678}
4679
4680fn default_impairment_count() -> usize {
4681 15
4682}
4683
4684fn default_impairment_rate() -> f64 {
4685 0.10
4686}
4687
4688impl Default for ImpairmentConfig {
4689 fn default() -> Self {
4690 Self {
4691 enabled: false,
4692 test_count: default_impairment_count(),
4693 impairment_rate: default_impairment_rate(),
4694 generate_projections: true,
4695 include_goodwill: false,
4696 }
4697 }
4698}
4699
4700#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4713pub struct AuditStandardsConfig {
4714 #[serde(default)]
4716 pub enabled: bool,
4717
4718 #[serde(default)]
4720 pub isa_compliance: IsaComplianceConfig,
4721
4722 #[serde(default)]
4724 pub analytical_procedures: AnalyticalProceduresConfig,
4725
4726 #[serde(default)]
4728 pub confirmations: ConfirmationsConfig,
4729
4730 #[serde(default)]
4732 pub opinion: AuditOpinionConfig,
4733
4734 #[serde(default)]
4736 pub generate_audit_trail: bool,
4737
4738 #[serde(default)]
4740 pub sox: SoxComplianceConfig,
4741
4742 #[serde(default)]
4744 pub pcaob: PcaobConfig,
4745}
4746
4747#[derive(Debug, Clone, Serialize, Deserialize)]
4749pub struct IsaComplianceConfig {
4750 #[serde(default)]
4752 pub enabled: bool,
4753
4754 #[serde(default = "default_compliance_level")]
4756 pub compliance_level: String,
4757
4758 #[serde(default = "default_true")]
4760 pub generate_isa_mappings: bool,
4761
4762 #[serde(default = "default_true")]
4764 pub generate_coverage_summary: bool,
4765
4766 #[serde(default)]
4768 pub include_pcaob: bool,
4769
4770 #[serde(default = "default_audit_framework")]
4772 pub framework: String,
4773}
4774
4775fn default_compliance_level() -> String {
4776 "standard".to_string()
4777}
4778
4779fn default_audit_framework() -> String {
4780 "isa".to_string()
4781}
4782
4783impl Default for IsaComplianceConfig {
4784 fn default() -> Self {
4785 Self {
4786 enabled: false,
4787 compliance_level: default_compliance_level(),
4788 generate_isa_mappings: true,
4789 generate_coverage_summary: true,
4790 include_pcaob: false,
4791 framework: default_audit_framework(),
4792 }
4793 }
4794}
4795
4796#[derive(Debug, Clone, Serialize, Deserialize)]
4798pub struct AnalyticalProceduresConfig {
4799 #[serde(default)]
4801 pub enabled: bool,
4802
4803 #[serde(default = "default_procedures_per_account")]
4805 pub procedures_per_account: usize,
4806
4807 #[serde(default = "default_variance_probability")]
4809 pub variance_probability: f64,
4810
4811 #[serde(default = "default_true")]
4813 pub generate_investigations: bool,
4814
4815 #[serde(default = "default_true")]
4817 pub include_ratio_analysis: bool,
4818}
4819
4820fn default_procedures_per_account() -> usize {
4821 3
4822}
4823
4824fn default_variance_probability() -> f64 {
4825 0.20
4826}
4827
4828impl Default for AnalyticalProceduresConfig {
4829 fn default() -> Self {
4830 Self {
4831 enabled: false,
4832 procedures_per_account: default_procedures_per_account(),
4833 variance_probability: default_variance_probability(),
4834 generate_investigations: true,
4835 include_ratio_analysis: true,
4836 }
4837 }
4838}
4839
4840#[derive(Debug, Clone, Serialize, Deserialize)]
4842pub struct ConfirmationsConfig {
4843 #[serde(default)]
4845 pub enabled: bool,
4846
4847 #[serde(default = "default_confirmation_count")]
4849 pub confirmation_count: usize,
4850
4851 #[serde(default = "default_positive_response_rate")]
4853 pub positive_response_rate: f64,
4854
4855 #[serde(default = "default_exception_rate_confirm")]
4857 pub exception_rate: f64,
4858
4859 #[serde(default = "default_non_response_rate")]
4861 pub non_response_rate: f64,
4862
4863 #[serde(default = "default_true")]
4865 pub generate_alternative_procedures: bool,
4866}
4867
4868fn default_confirmation_count() -> usize {
4869 50
4870}
4871
4872fn default_positive_response_rate() -> f64 {
4873 0.85
4874}
4875
4876fn default_exception_rate_confirm() -> f64 {
4877 0.10
4878}
4879
4880fn default_non_response_rate() -> f64 {
4881 0.05
4882}
4883
4884impl Default for ConfirmationsConfig {
4885 fn default() -> Self {
4886 Self {
4887 enabled: false,
4888 confirmation_count: default_confirmation_count(),
4889 positive_response_rate: default_positive_response_rate(),
4890 exception_rate: default_exception_rate_confirm(),
4891 non_response_rate: default_non_response_rate(),
4892 generate_alternative_procedures: true,
4893 }
4894 }
4895}
4896
4897#[derive(Debug, Clone, Serialize, Deserialize)]
4899pub struct AuditOpinionConfig {
4900 #[serde(default)]
4902 pub enabled: bool,
4903
4904 #[serde(default = "default_true")]
4906 pub generate_kam: bool,
4907
4908 #[serde(default = "default_kam_count")]
4910 pub average_kam_count: usize,
4911
4912 #[serde(default = "default_modified_opinion_rate")]
4914 pub modified_opinion_rate: f64,
4915
4916 #[serde(default)]
4918 pub include_emphasis_of_matter: bool,
4919
4920 #[serde(default = "default_true")]
4922 pub include_going_concern: bool,
4923}
4924
4925fn default_kam_count() -> usize {
4926 3
4927}
4928
4929fn default_modified_opinion_rate() -> f64 {
4930 0.05
4931}
4932
4933impl Default for AuditOpinionConfig {
4934 fn default() -> Self {
4935 Self {
4936 enabled: false,
4937 generate_kam: true,
4938 average_kam_count: default_kam_count(),
4939 modified_opinion_rate: default_modified_opinion_rate(),
4940 include_emphasis_of_matter: false,
4941 include_going_concern: true,
4942 }
4943 }
4944}
4945
4946#[derive(Debug, Clone, Serialize, Deserialize)]
4948pub struct SoxComplianceConfig {
4949 #[serde(default)]
4951 pub enabled: bool,
4952
4953 #[serde(default = "default_true")]
4955 pub generate_302_certifications: bool,
4956
4957 #[serde(default = "default_true")]
4959 pub generate_404_assessments: bool,
4960
4961 #[serde(default = "default_sox_materiality_threshold")]
4963 pub materiality_threshold: f64,
4964
4965 #[serde(default = "default_material_weakness_rate")]
4967 pub material_weakness_rate: f64,
4968
4969 #[serde(default = "default_significant_deficiency_rate")]
4971 pub significant_deficiency_rate: f64,
4972}
4973
4974fn default_material_weakness_rate() -> f64 {
4975 0.02
4976}
4977
4978fn default_significant_deficiency_rate() -> f64 {
4979 0.08
4980}
4981
4982impl Default for SoxComplianceConfig {
4983 fn default() -> Self {
4984 Self {
4985 enabled: false,
4986 generate_302_certifications: true,
4987 generate_404_assessments: true,
4988 materiality_threshold: default_sox_materiality_threshold(),
4989 material_weakness_rate: default_material_weakness_rate(),
4990 significant_deficiency_rate: default_significant_deficiency_rate(),
4991 }
4992 }
4993}
4994
4995#[derive(Debug, Clone, Serialize, Deserialize)]
4997pub struct PcaobConfig {
4998 #[serde(default)]
5000 pub enabled: bool,
5001
5002 #[serde(default)]
5004 pub is_pcaob_audit: bool,
5005
5006 #[serde(default = "default_true")]
5008 pub generate_cam: bool,
5009
5010 #[serde(default)]
5012 pub include_icfr_opinion: bool,
5013
5014 #[serde(default)]
5016 pub generate_standard_mappings: bool,
5017}
5018
5019impl Default for PcaobConfig {
5020 fn default() -> Self {
5021 Self {
5022 enabled: false,
5023 is_pcaob_audit: false,
5024 generate_cam: true,
5025 include_icfr_opinion: false,
5026 generate_standard_mappings: false,
5027 }
5028 }
5029}
5030
5031#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5044pub struct AdvancedDistributionConfig {
5045 #[serde(default)]
5047 pub enabled: bool,
5048
5049 #[serde(default)]
5051 pub amounts: MixtureDistributionSchemaConfig,
5052
5053 #[serde(default)]
5055 pub correlations: CorrelationSchemaConfig,
5056
5057 #[serde(default)]
5059 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5060
5061 #[serde(default)]
5063 pub regime_changes: RegimeChangeSchemaConfig,
5064
5065 #[serde(default)]
5067 pub industry_profile: Option<IndustryProfileType>,
5068
5069 #[serde(default)]
5071 pub validation: StatisticalValidationSchemaConfig,
5072}
5073
5074#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5076#[serde(rename_all = "snake_case")]
5077pub enum IndustryProfileType {
5078 Retail,
5080 Manufacturing,
5082 FinancialServices,
5084 Healthcare,
5086 Technology,
5088}
5089
5090#[derive(Debug, Clone, Serialize, Deserialize)]
5092pub struct MixtureDistributionSchemaConfig {
5093 #[serde(default)]
5095 pub enabled: bool,
5096
5097 #[serde(default = "default_mixture_type")]
5099 pub distribution_type: MixtureDistributionType,
5100
5101 #[serde(default)]
5103 pub components: Vec<MixtureComponentConfig>,
5104
5105 #[serde(default = "default_min_amount")]
5107 pub min_value: f64,
5108
5109 #[serde(default)]
5111 pub max_value: Option<f64>,
5112
5113 #[serde(default = "default_decimal_places")]
5115 pub decimal_places: u8,
5116}
5117
5118fn default_mixture_type() -> MixtureDistributionType {
5119 MixtureDistributionType::LogNormal
5120}
5121
5122fn default_min_amount() -> f64 {
5123 0.01
5124}
5125
5126fn default_decimal_places() -> u8 {
5127 2
5128}
5129
5130impl Default for MixtureDistributionSchemaConfig {
5131 fn default() -> Self {
5132 Self {
5133 enabled: false,
5134 distribution_type: MixtureDistributionType::LogNormal,
5135 components: Vec::new(),
5136 min_value: 0.01,
5137 max_value: None,
5138 decimal_places: 2,
5139 }
5140 }
5141}
5142
5143#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5145#[serde(rename_all = "snake_case")]
5146pub enum MixtureDistributionType {
5147 Gaussian,
5149 #[default]
5151 LogNormal,
5152}
5153
5154#[derive(Debug, Clone, Serialize, Deserialize)]
5156pub struct MixtureComponentConfig {
5157 pub weight: f64,
5159
5160 pub mu: f64,
5162
5163 pub sigma: f64,
5165
5166 #[serde(default)]
5168 pub label: Option<String>,
5169}
5170
5171#[derive(Debug, Clone, Serialize, Deserialize)]
5173pub struct CorrelationSchemaConfig {
5174 #[serde(default)]
5176 pub enabled: bool,
5177
5178 #[serde(default)]
5180 pub copula_type: CopulaSchemaType,
5181
5182 #[serde(default)]
5184 pub fields: Vec<CorrelatedFieldConfig>,
5185
5186 #[serde(default)]
5189 pub matrix: Vec<f64>,
5190
5191 #[serde(default)]
5193 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5194}
5195
5196impl Default for CorrelationSchemaConfig {
5197 fn default() -> Self {
5198 Self {
5199 enabled: false,
5200 copula_type: CopulaSchemaType::Gaussian,
5201 fields: Vec::new(),
5202 matrix: Vec::new(),
5203 expected_correlations: Vec::new(),
5204 }
5205 }
5206}
5207
5208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5210#[serde(rename_all = "snake_case")]
5211pub enum CopulaSchemaType {
5212 #[default]
5214 Gaussian,
5215 Clayton,
5217 Gumbel,
5219 Frank,
5221 StudentT,
5223}
5224
5225#[derive(Debug, Clone, Serialize, Deserialize)]
5227pub struct CorrelatedFieldConfig {
5228 pub name: String,
5230
5231 #[serde(default)]
5233 pub distribution: MarginalDistributionConfig,
5234}
5235
5236#[derive(Debug, Clone, Serialize, Deserialize)]
5238#[serde(tag = "type", rename_all = "snake_case")]
5239pub enum MarginalDistributionConfig {
5240 Normal {
5242 mu: f64,
5244 sigma: f64,
5246 },
5247 LogNormal {
5249 mu: f64,
5251 sigma: f64,
5253 },
5254 Uniform {
5256 min: f64,
5258 max: f64,
5260 },
5261 DiscreteUniform {
5263 min: i32,
5265 max: i32,
5267 },
5268}
5269
5270impl Default for MarginalDistributionConfig {
5271 fn default() -> Self {
5272 Self::Normal {
5273 mu: 0.0,
5274 sigma: 1.0,
5275 }
5276 }
5277}
5278
5279#[derive(Debug, Clone, Serialize, Deserialize)]
5281pub struct ExpectedCorrelationConfig {
5282 pub field1: String,
5284 pub field2: String,
5286 pub expected_r: f64,
5288 #[serde(default = "default_correlation_tolerance")]
5290 pub tolerance: f64,
5291}
5292
5293fn default_correlation_tolerance() -> f64 {
5294 0.10
5295}
5296
5297#[derive(Debug, Clone, Serialize, Deserialize)]
5299pub struct ConditionalDistributionSchemaConfig {
5300 pub output_field: String,
5302
5303 pub input_field: String,
5305
5306 #[serde(default)]
5308 pub breakpoints: Vec<ConditionalBreakpointConfig>,
5309
5310 #[serde(default)]
5312 pub default_distribution: ConditionalDistributionParamsConfig,
5313
5314 #[serde(default)]
5316 pub min_value: Option<f64>,
5317
5318 #[serde(default)]
5320 pub max_value: Option<f64>,
5321
5322 #[serde(default = "default_decimal_places")]
5324 pub decimal_places: u8,
5325}
5326
5327#[derive(Debug, Clone, Serialize, Deserialize)]
5329pub struct ConditionalBreakpointConfig {
5330 pub threshold: f64,
5332
5333 pub distribution: ConditionalDistributionParamsConfig,
5335}
5336
5337#[derive(Debug, Clone, Serialize, Deserialize)]
5339#[serde(tag = "type", rename_all = "snake_case")]
5340pub enum ConditionalDistributionParamsConfig {
5341 Fixed {
5343 value: f64,
5345 },
5346 Normal {
5348 mu: f64,
5350 sigma: f64,
5352 },
5353 LogNormal {
5355 mu: f64,
5357 sigma: f64,
5359 },
5360 Uniform {
5362 min: f64,
5364 max: f64,
5366 },
5367 Beta {
5369 alpha: f64,
5371 beta: f64,
5373 min: f64,
5375 max: f64,
5377 },
5378 Discrete {
5380 values: Vec<f64>,
5382 weights: Vec<f64>,
5384 },
5385}
5386
5387impl Default for ConditionalDistributionParamsConfig {
5388 fn default() -> Self {
5389 Self::Normal {
5390 mu: 0.0,
5391 sigma: 1.0,
5392 }
5393 }
5394}
5395
5396#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5398pub struct RegimeChangeSchemaConfig {
5399 #[serde(default)]
5401 pub enabled: bool,
5402
5403 #[serde(default)]
5405 pub changes: Vec<RegimeChangeEventConfig>,
5406
5407 #[serde(default)]
5409 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5410
5411 #[serde(default)]
5413 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5414}
5415
5416#[derive(Debug, Clone, Serialize, Deserialize)]
5418pub struct RegimeChangeEventConfig {
5419 pub date: String,
5421
5422 pub change_type: RegimeChangeTypeConfig,
5424
5425 #[serde(default)]
5427 pub description: Option<String>,
5428
5429 #[serde(default)]
5431 pub effects: Vec<RegimeEffectConfig>,
5432}
5433
5434#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5436#[serde(rename_all = "snake_case")]
5437pub enum RegimeChangeTypeConfig {
5438 Acquisition,
5440 Divestiture,
5442 PriceIncrease,
5444 PriceDecrease,
5446 ProductLaunch,
5448 ProductDiscontinuation,
5450 PolicyChange,
5452 CompetitorEntry,
5454 Custom,
5456}
5457
5458#[derive(Debug, Clone, Serialize, Deserialize)]
5460pub struct RegimeEffectConfig {
5461 pub field: String,
5463
5464 pub multiplier: f64,
5466}
5467
5468#[derive(Debug, Clone, Serialize, Deserialize)]
5470pub struct EconomicCycleSchemaConfig {
5471 #[serde(default)]
5473 pub enabled: bool,
5474
5475 #[serde(default = "default_cycle_period")]
5477 pub period_months: u32,
5478
5479 #[serde(default = "default_cycle_amplitude")]
5481 pub amplitude: f64,
5482
5483 #[serde(default)]
5485 pub phase_offset: u32,
5486
5487 #[serde(default)]
5489 pub recessions: Vec<RecessionPeriodConfig>,
5490}
5491
5492fn default_cycle_period() -> u32 {
5493 48
5494}
5495
5496fn default_cycle_amplitude() -> f64 {
5497 0.15
5498}
5499
5500impl Default for EconomicCycleSchemaConfig {
5501 fn default() -> Self {
5502 Self {
5503 enabled: false,
5504 period_months: 48,
5505 amplitude: 0.15,
5506 phase_offset: 0,
5507 recessions: Vec::new(),
5508 }
5509 }
5510}
5511
5512#[derive(Debug, Clone, Serialize, Deserialize)]
5514pub struct RecessionPeriodConfig {
5515 pub start_month: u32,
5517
5518 pub duration_months: u32,
5520
5521 #[serde(default = "default_recession_severity")]
5523 pub severity: f64,
5524}
5525
5526fn default_recession_severity() -> f64 {
5527 0.20
5528}
5529
5530#[derive(Debug, Clone, Serialize, Deserialize)]
5532pub struct ParameterDriftSchemaConfig {
5533 pub parameter: String,
5535
5536 pub drift_type: ParameterDriftTypeConfig,
5538
5539 pub start_value: f64,
5541
5542 pub end_value: f64,
5544
5545 #[serde(default)]
5547 pub start_period: u32,
5548
5549 #[serde(default)]
5551 pub end_period: Option<u32>,
5552}
5553
5554#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5556#[serde(rename_all = "snake_case")]
5557pub enum ParameterDriftTypeConfig {
5558 #[default]
5560 Linear,
5561 Exponential,
5563 Logistic,
5565 Step,
5567}
5568
5569#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5571pub struct StatisticalValidationSchemaConfig {
5572 #[serde(default)]
5574 pub enabled: bool,
5575
5576 #[serde(default)]
5578 pub tests: Vec<StatisticalTestConfig>,
5579
5580 #[serde(default)]
5582 pub reporting: ValidationReportingConfig,
5583}
5584
5585#[derive(Debug, Clone, Serialize, Deserialize)]
5587#[serde(tag = "type", rename_all = "snake_case")]
5588pub enum StatisticalTestConfig {
5589 BenfordFirstDigit {
5591 #[serde(default = "default_benford_threshold")]
5593 threshold_mad: f64,
5594 #[serde(default = "default_benford_warning")]
5596 warning_mad: f64,
5597 },
5598 DistributionFit {
5600 target: TargetDistributionConfig,
5602 #[serde(default = "default_ks_significance")]
5604 ks_significance: f64,
5605 #[serde(default)]
5607 method: DistributionFitMethod,
5608 },
5609 CorrelationCheck {
5611 expected_correlations: Vec<ExpectedCorrelationConfig>,
5613 },
5614 ChiSquared {
5616 #[serde(default = "default_chi_squared_bins")]
5618 bins: usize,
5619 #[serde(default = "default_chi_squared_significance")]
5621 significance: f64,
5622 },
5623 AndersonDarling {
5625 target: TargetDistributionConfig,
5627 #[serde(default = "default_ad_significance")]
5629 significance: f64,
5630 },
5631}
5632
5633fn default_benford_threshold() -> f64 {
5634 0.015
5635}
5636
5637fn default_benford_warning() -> f64 {
5638 0.010
5639}
5640
5641fn default_ks_significance() -> f64 {
5642 0.05
5643}
5644
5645fn default_chi_squared_bins() -> usize {
5646 10
5647}
5648
5649fn default_chi_squared_significance() -> f64 {
5650 0.05
5651}
5652
5653fn default_ad_significance() -> f64 {
5654 0.05
5655}
5656
5657#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5659#[serde(rename_all = "snake_case")]
5660pub enum TargetDistributionConfig {
5661 Normal,
5663 #[default]
5665 LogNormal,
5666 Exponential,
5668 Uniform,
5670}
5671
5672#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5674#[serde(rename_all = "snake_case")]
5675pub enum DistributionFitMethod {
5676 #[default]
5678 KolmogorovSmirnov,
5679 AndersonDarling,
5681 ChiSquared,
5683}
5684
5685#[derive(Debug, Clone, Serialize, Deserialize)]
5687pub struct ValidationReportingConfig {
5688 #[serde(default)]
5690 pub output_report: bool,
5691
5692 #[serde(default)]
5694 pub format: ValidationReportFormat,
5695
5696 #[serde(default)]
5698 pub fail_on_error: bool,
5699
5700 #[serde(default = "default_true")]
5702 pub include_details: bool,
5703}
5704
5705impl Default for ValidationReportingConfig {
5706 fn default() -> Self {
5707 Self {
5708 output_report: false,
5709 format: ValidationReportFormat::Json,
5710 fail_on_error: false,
5711 include_details: true,
5712 }
5713 }
5714}
5715
5716#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5718#[serde(rename_all = "snake_case")]
5719pub enum ValidationReportFormat {
5720 #[default]
5722 Json,
5723 Yaml,
5725 Html,
5727}
5728
5729#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5741pub struct TemporalPatternsConfig {
5742 #[serde(default)]
5744 pub enabled: bool,
5745
5746 #[serde(default)]
5748 pub business_days: BusinessDaySchemaConfig,
5749
5750 #[serde(default)]
5752 pub calendars: CalendarSchemaConfig,
5753
5754 #[serde(default)]
5756 pub period_end: PeriodEndSchemaConfig,
5757
5758 #[serde(default)]
5760 pub processing_lags: ProcessingLagSchemaConfig,
5761
5762 #[serde(default)]
5764 pub fiscal_calendar: FiscalCalendarSchemaConfig,
5765
5766 #[serde(default)]
5768 pub intraday: IntraDaySchemaConfig,
5769
5770 #[serde(default)]
5772 pub timezones: TimezoneSchemaConfig,
5773}
5774
5775#[derive(Debug, Clone, Serialize, Deserialize)]
5777pub struct BusinessDaySchemaConfig {
5778 #[serde(default = "default_true")]
5780 pub enabled: bool,
5781
5782 #[serde(default = "default_half_day_policy")]
5784 pub half_day_policy: String,
5785
5786 #[serde(default)]
5788 pub settlement_rules: SettlementRulesSchemaConfig,
5789
5790 #[serde(default = "default_month_end_convention")]
5792 pub month_end_convention: String,
5793
5794 #[serde(default)]
5796 pub weekend_days: Option<Vec<String>>,
5797}
5798
5799fn default_half_day_policy() -> String {
5800 "half_day".to_string()
5801}
5802
5803fn default_month_end_convention() -> String {
5804 "modified_following".to_string()
5805}
5806
5807impl Default for BusinessDaySchemaConfig {
5808 fn default() -> Self {
5809 Self {
5810 enabled: true,
5811 half_day_policy: "half_day".to_string(),
5812 settlement_rules: SettlementRulesSchemaConfig::default(),
5813 month_end_convention: "modified_following".to_string(),
5814 weekend_days: None,
5815 }
5816 }
5817}
5818
5819#[derive(Debug, Clone, Serialize, Deserialize)]
5821pub struct SettlementRulesSchemaConfig {
5822 #[serde(default = "default_settlement_2")]
5824 pub equity_days: i32,
5825
5826 #[serde(default = "default_settlement_1")]
5828 pub government_bonds_days: i32,
5829
5830 #[serde(default = "default_settlement_2")]
5832 pub fx_spot_days: i32,
5833
5834 #[serde(default = "default_settlement_2")]
5836 pub corporate_bonds_days: i32,
5837
5838 #[serde(default = "default_wire_cutoff")]
5840 pub wire_cutoff_time: String,
5841
5842 #[serde(default = "default_settlement_1")]
5844 pub wire_international_days: i32,
5845
5846 #[serde(default = "default_settlement_1")]
5848 pub ach_days: i32,
5849}
5850
5851fn default_settlement_1() -> i32 {
5852 1
5853}
5854
5855fn default_settlement_2() -> i32 {
5856 2
5857}
5858
5859fn default_wire_cutoff() -> String {
5860 "14:00".to_string()
5861}
5862
5863impl Default for SettlementRulesSchemaConfig {
5864 fn default() -> Self {
5865 Self {
5866 equity_days: 2,
5867 government_bonds_days: 1,
5868 fx_spot_days: 2,
5869 corporate_bonds_days: 2,
5870 wire_cutoff_time: "14:00".to_string(),
5871 wire_international_days: 1,
5872 ach_days: 1,
5873 }
5874 }
5875}
5876
5877#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5879pub struct CalendarSchemaConfig {
5880 #[serde(default)]
5882 pub regions: Vec<String>,
5883
5884 #[serde(default)]
5886 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
5887}
5888
5889#[derive(Debug, Clone, Serialize, Deserialize)]
5891pub struct CustomHolidaySchemaConfig {
5892 pub name: String,
5894 pub month: u8,
5896 pub day: u8,
5898 #[serde(default = "default_holiday_multiplier")]
5900 pub activity_multiplier: f64,
5901}
5902
5903fn default_holiday_multiplier() -> f64 {
5904 0.05
5905}
5906
5907#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5909pub struct PeriodEndSchemaConfig {
5910 #[serde(default)]
5912 pub model: Option<String>,
5913
5914 #[serde(default)]
5916 pub month_end: Option<PeriodEndModelSchemaConfig>,
5917
5918 #[serde(default)]
5920 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
5921
5922 #[serde(default)]
5924 pub year_end: Option<PeriodEndModelSchemaConfig>,
5925}
5926
5927#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5929pub struct PeriodEndModelSchemaConfig {
5930 #[serde(default)]
5932 pub inherit_from: Option<String>,
5933
5934 #[serde(default)]
5936 pub additional_multiplier: Option<f64>,
5937
5938 #[serde(default)]
5940 pub start_day: Option<i32>,
5941
5942 #[serde(default)]
5944 pub base_multiplier: Option<f64>,
5945
5946 #[serde(default)]
5948 pub peak_multiplier: Option<f64>,
5949
5950 #[serde(default)]
5952 pub decay_rate: Option<f64>,
5953
5954 #[serde(default)]
5956 pub sustained_high_days: Option<i32>,
5957}
5958
5959#[derive(Debug, Clone, Serialize, Deserialize)]
5961pub struct ProcessingLagSchemaConfig {
5962 #[serde(default = "default_true")]
5964 pub enabled: bool,
5965
5966 #[serde(default)]
5968 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
5969
5970 #[serde(default)]
5972 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
5973
5974 #[serde(default)]
5976 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
5977
5978 #[serde(default)]
5980 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
5981
5982 #[serde(default)]
5984 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
5985
5986 #[serde(default)]
5988 pub payment_lag: Option<LagDistributionSchemaConfig>,
5989
5990 #[serde(default)]
5992 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
5993
5994 #[serde(default)]
5996 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
5997}
5998
5999impl Default for ProcessingLagSchemaConfig {
6000 fn default() -> Self {
6001 Self {
6002 enabled: true,
6003 sales_order_lag: None,
6004 purchase_order_lag: None,
6005 goods_receipt_lag: None,
6006 invoice_receipt_lag: None,
6007 invoice_issue_lag: None,
6008 payment_lag: None,
6009 journal_entry_lag: None,
6010 cross_day_posting: None,
6011 }
6012 }
6013}
6014
6015#[derive(Debug, Clone, Serialize, Deserialize)]
6017pub struct LagDistributionSchemaConfig {
6018 pub mu: f64,
6020 pub sigma: f64,
6022 #[serde(default)]
6024 pub min_hours: Option<f64>,
6025 #[serde(default)]
6027 pub max_hours: Option<f64>,
6028}
6029
6030#[derive(Debug, Clone, Serialize, Deserialize)]
6032pub struct CrossDayPostingSchemaConfig {
6033 #[serde(default = "default_true")]
6035 pub enabled: bool,
6036
6037 #[serde(default)]
6040 pub probability_by_hour: std::collections::HashMap<u8, f64>,
6041}
6042
6043impl Default for CrossDayPostingSchemaConfig {
6044 fn default() -> Self {
6045 let mut probability_by_hour = std::collections::HashMap::new();
6046 probability_by_hour.insert(17, 0.3);
6047 probability_by_hour.insert(18, 0.6);
6048 probability_by_hour.insert(19, 0.8);
6049 probability_by_hour.insert(20, 0.9);
6050 probability_by_hour.insert(21, 0.95);
6051 probability_by_hour.insert(22, 0.99);
6052
6053 Self {
6054 enabled: true,
6055 probability_by_hour,
6056 }
6057 }
6058}
6059
6060#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6069pub struct FiscalCalendarSchemaConfig {
6070 #[serde(default)]
6072 pub enabled: bool,
6073
6074 #[serde(default = "default_fiscal_calendar_type")]
6076 pub calendar_type: String,
6077
6078 #[serde(default)]
6080 pub year_start_month: Option<u8>,
6081
6082 #[serde(default)]
6084 pub year_start_day: Option<u8>,
6085
6086 #[serde(default)]
6088 pub four_four_five: Option<FourFourFiveSchemaConfig>,
6089}
6090
6091fn default_fiscal_calendar_type() -> String {
6092 "calendar_year".to_string()
6093}
6094
6095#[derive(Debug, Clone, Serialize, Deserialize)]
6097pub struct FourFourFiveSchemaConfig {
6098 #[serde(default = "default_week_pattern")]
6100 pub pattern: String,
6101
6102 #[serde(default = "default_anchor_type")]
6104 pub anchor_type: String,
6105
6106 #[serde(default = "default_anchor_month")]
6108 pub anchor_month: u8,
6109
6110 #[serde(default = "default_leap_week_placement")]
6112 pub leap_week_placement: String,
6113}
6114
6115fn default_week_pattern() -> String {
6116 "four_four_five".to_string()
6117}
6118
6119fn default_anchor_type() -> String {
6120 "last_saturday".to_string()
6121}
6122
6123fn default_anchor_month() -> u8 {
6124 1 }
6126
6127fn default_leap_week_placement() -> String {
6128 "q4_period3".to_string()
6129}
6130
6131impl Default for FourFourFiveSchemaConfig {
6132 fn default() -> Self {
6133 Self {
6134 pattern: "four_four_five".to_string(),
6135 anchor_type: "last_saturday".to_string(),
6136 anchor_month: 1,
6137 leap_week_placement: "q4_period3".to_string(),
6138 }
6139 }
6140}
6141
6142#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6151pub struct IntraDaySchemaConfig {
6152 #[serde(default)]
6154 pub enabled: bool,
6155
6156 #[serde(default)]
6158 pub segments: Vec<IntraDaySegmentSchemaConfig>,
6159}
6160
6161#[derive(Debug, Clone, Serialize, Deserialize)]
6163pub struct IntraDaySegmentSchemaConfig {
6164 pub name: String,
6166
6167 pub start: String,
6169
6170 pub end: String,
6172
6173 #[serde(default = "default_multiplier")]
6175 pub multiplier: f64,
6176
6177 #[serde(default = "default_posting_type")]
6179 pub posting_type: String,
6180}
6181
6182fn default_multiplier() -> f64 {
6183 1.0
6184}
6185
6186fn default_posting_type() -> String {
6187 "both".to_string()
6188}
6189
6190#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6196pub struct TimezoneSchemaConfig {
6197 #[serde(default)]
6199 pub enabled: bool,
6200
6201 #[serde(default = "default_timezone")]
6203 pub default_timezone: String,
6204
6205 #[serde(default = "default_consolidation_timezone")]
6207 pub consolidation_timezone: String,
6208
6209 #[serde(default)]
6212 pub entity_mappings: Vec<EntityTimezoneMapping>,
6213}
6214
6215fn default_timezone() -> String {
6216 "America/New_York".to_string()
6217}
6218
6219fn default_consolidation_timezone() -> String {
6220 "UTC".to_string()
6221}
6222
6223#[derive(Debug, Clone, Serialize, Deserialize)]
6225pub struct EntityTimezoneMapping {
6226 pub pattern: String,
6228
6229 pub timezone: String,
6231}
6232
6233#[derive(Debug, Clone, Serialize, Deserialize)]
6239pub struct VendorNetworkSchemaConfig {
6240 #[serde(default)]
6242 pub enabled: bool,
6243
6244 #[serde(default = "default_vendor_tier_depth")]
6246 pub depth: u8,
6247
6248 #[serde(default)]
6250 pub tier1: TierCountSchemaConfig,
6251
6252 #[serde(default)]
6254 pub tier2_per_parent: TierCountSchemaConfig,
6255
6256 #[serde(default)]
6258 pub tier3_per_parent: TierCountSchemaConfig,
6259
6260 #[serde(default)]
6262 pub clusters: VendorClusterSchemaConfig,
6263
6264 #[serde(default)]
6266 pub dependencies: DependencySchemaConfig,
6267}
6268
6269fn default_vendor_tier_depth() -> u8 {
6270 3
6271}
6272
6273impl Default for VendorNetworkSchemaConfig {
6274 fn default() -> Self {
6275 Self {
6276 enabled: false,
6277 depth: 3,
6278 tier1: TierCountSchemaConfig { min: 50, max: 100 },
6279 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6280 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6281 clusters: VendorClusterSchemaConfig::default(),
6282 dependencies: DependencySchemaConfig::default(),
6283 }
6284 }
6285}
6286
6287#[derive(Debug, Clone, Serialize, Deserialize)]
6289pub struct TierCountSchemaConfig {
6290 #[serde(default = "default_tier_min")]
6292 pub min: usize,
6293
6294 #[serde(default = "default_tier_max")]
6296 pub max: usize,
6297}
6298
6299fn default_tier_min() -> usize {
6300 5
6301}
6302
6303fn default_tier_max() -> usize {
6304 20
6305}
6306
6307impl Default for TierCountSchemaConfig {
6308 fn default() -> Self {
6309 Self {
6310 min: default_tier_min(),
6311 max: default_tier_max(),
6312 }
6313 }
6314}
6315
6316#[derive(Debug, Clone, Serialize, Deserialize)]
6318pub struct VendorClusterSchemaConfig {
6319 #[serde(default = "default_reliable_strategic")]
6321 pub reliable_strategic: f64,
6322
6323 #[serde(default = "default_standard_operational")]
6325 pub standard_operational: f64,
6326
6327 #[serde(default = "default_transactional")]
6329 pub transactional: f64,
6330
6331 #[serde(default = "default_problematic")]
6333 pub problematic: f64,
6334}
6335
6336fn default_reliable_strategic() -> f64 {
6337 0.20
6338}
6339
6340fn default_standard_operational() -> f64 {
6341 0.50
6342}
6343
6344fn default_transactional() -> f64 {
6345 0.25
6346}
6347
6348fn default_problematic() -> f64 {
6349 0.05
6350}
6351
6352impl Default for VendorClusterSchemaConfig {
6353 fn default() -> Self {
6354 Self {
6355 reliable_strategic: 0.20,
6356 standard_operational: 0.50,
6357 transactional: 0.25,
6358 problematic: 0.05,
6359 }
6360 }
6361}
6362
6363#[derive(Debug, Clone, Serialize, Deserialize)]
6365pub struct DependencySchemaConfig {
6366 #[serde(default = "default_max_single_vendor")]
6368 pub max_single_vendor_concentration: f64,
6369
6370 #[serde(default = "default_max_top5")]
6372 pub top_5_concentration: f64,
6373
6374 #[serde(default = "default_single_source_percent")]
6376 pub single_source_percent: f64,
6377}
6378
6379fn default_max_single_vendor() -> f64 {
6380 0.15
6381}
6382
6383fn default_max_top5() -> f64 {
6384 0.45
6385}
6386
6387fn default_single_source_percent() -> f64 {
6388 0.05
6389}
6390
6391impl Default for DependencySchemaConfig {
6392 fn default() -> Self {
6393 Self {
6394 max_single_vendor_concentration: 0.15,
6395 top_5_concentration: 0.45,
6396 single_source_percent: 0.05,
6397 }
6398 }
6399}
6400
6401#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6407pub struct CustomerSegmentationSchemaConfig {
6408 #[serde(default)]
6410 pub enabled: bool,
6411
6412 #[serde(default)]
6414 pub value_segments: ValueSegmentsSchemaConfig,
6415
6416 #[serde(default)]
6418 pub lifecycle: LifecycleSchemaConfig,
6419
6420 #[serde(default)]
6422 pub networks: CustomerNetworksSchemaConfig,
6423}
6424
6425#[derive(Debug, Clone, Serialize, Deserialize)]
6427pub struct ValueSegmentsSchemaConfig {
6428 #[serde(default)]
6430 pub enterprise: SegmentDetailSchemaConfig,
6431
6432 #[serde(default)]
6434 pub mid_market: SegmentDetailSchemaConfig,
6435
6436 #[serde(default)]
6438 pub smb: SegmentDetailSchemaConfig,
6439
6440 #[serde(default)]
6442 pub consumer: SegmentDetailSchemaConfig,
6443}
6444
6445impl Default for ValueSegmentsSchemaConfig {
6446 fn default() -> Self {
6447 Self {
6448 enterprise: SegmentDetailSchemaConfig {
6449 revenue_share: 0.40,
6450 customer_share: 0.05,
6451 avg_order_value_range: "50000+".to_string(),
6452 },
6453 mid_market: SegmentDetailSchemaConfig {
6454 revenue_share: 0.35,
6455 customer_share: 0.20,
6456 avg_order_value_range: "5000-50000".to_string(),
6457 },
6458 smb: SegmentDetailSchemaConfig {
6459 revenue_share: 0.20,
6460 customer_share: 0.50,
6461 avg_order_value_range: "500-5000".to_string(),
6462 },
6463 consumer: SegmentDetailSchemaConfig {
6464 revenue_share: 0.05,
6465 customer_share: 0.25,
6466 avg_order_value_range: "50-500".to_string(),
6467 },
6468 }
6469 }
6470}
6471
6472#[derive(Debug, Clone, Serialize, Deserialize)]
6474pub struct SegmentDetailSchemaConfig {
6475 #[serde(default)]
6477 pub revenue_share: f64,
6478
6479 #[serde(default)]
6481 pub customer_share: f64,
6482
6483 #[serde(default)]
6485 pub avg_order_value_range: String,
6486}
6487
6488impl Default for SegmentDetailSchemaConfig {
6489 fn default() -> Self {
6490 Self {
6491 revenue_share: 0.25,
6492 customer_share: 0.25,
6493 avg_order_value_range: "1000-10000".to_string(),
6494 }
6495 }
6496}
6497
6498#[derive(Debug, Clone, Serialize, Deserialize)]
6500pub struct LifecycleSchemaConfig {
6501 #[serde(default)]
6503 pub prospect_rate: f64,
6504
6505 #[serde(default = "default_new_rate")]
6507 pub new_rate: f64,
6508
6509 #[serde(default = "default_growth_rate")]
6511 pub growth_rate: f64,
6512
6513 #[serde(default = "default_mature_rate")]
6515 pub mature_rate: f64,
6516
6517 #[serde(default = "default_at_risk_rate")]
6519 pub at_risk_rate: f64,
6520
6521 #[serde(default = "default_churned_rate")]
6523 pub churned_rate: f64,
6524}
6525
6526fn default_new_rate() -> f64 {
6527 0.10
6528}
6529
6530fn default_growth_rate() -> f64 {
6531 0.15
6532}
6533
6534fn default_mature_rate() -> f64 {
6535 0.60
6536}
6537
6538fn default_at_risk_rate() -> f64 {
6539 0.10
6540}
6541
6542fn default_churned_rate() -> f64 {
6543 0.05
6544}
6545
6546impl Default for LifecycleSchemaConfig {
6547 fn default() -> Self {
6548 Self {
6549 prospect_rate: 0.0,
6550 new_rate: 0.10,
6551 growth_rate: 0.15,
6552 mature_rate: 0.60,
6553 at_risk_rate: 0.10,
6554 churned_rate: 0.05,
6555 }
6556 }
6557}
6558
6559#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6561pub struct CustomerNetworksSchemaConfig {
6562 #[serde(default)]
6564 pub referrals: ReferralSchemaConfig,
6565
6566 #[serde(default)]
6568 pub corporate_hierarchies: HierarchySchemaConfig,
6569}
6570
6571#[derive(Debug, Clone, Serialize, Deserialize)]
6573pub struct ReferralSchemaConfig {
6574 #[serde(default = "default_true")]
6576 pub enabled: bool,
6577
6578 #[serde(default = "default_referral_rate")]
6580 pub referral_rate: f64,
6581}
6582
6583fn default_referral_rate() -> f64 {
6584 0.15
6585}
6586
6587impl Default for ReferralSchemaConfig {
6588 fn default() -> Self {
6589 Self {
6590 enabled: true,
6591 referral_rate: 0.15,
6592 }
6593 }
6594}
6595
6596#[derive(Debug, Clone, Serialize, Deserialize)]
6598pub struct HierarchySchemaConfig {
6599 #[serde(default = "default_true")]
6601 pub enabled: bool,
6602
6603 #[serde(default = "default_hierarchy_rate")]
6605 pub probability: f64,
6606}
6607
6608fn default_hierarchy_rate() -> f64 {
6609 0.30
6610}
6611
6612impl Default for HierarchySchemaConfig {
6613 fn default() -> Self {
6614 Self {
6615 enabled: true,
6616 probability: 0.30,
6617 }
6618 }
6619}
6620
6621#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6627pub struct RelationshipStrengthSchemaConfig {
6628 #[serde(default)]
6630 pub enabled: bool,
6631
6632 #[serde(default)]
6634 pub calculation: StrengthCalculationSchemaConfig,
6635
6636 #[serde(default)]
6638 pub thresholds: StrengthThresholdsSchemaConfig,
6639}
6640
6641#[derive(Debug, Clone, Serialize, Deserialize)]
6643pub struct StrengthCalculationSchemaConfig {
6644 #[serde(default = "default_volume_weight")]
6646 pub transaction_volume_weight: f64,
6647
6648 #[serde(default = "default_count_weight")]
6650 pub transaction_count_weight: f64,
6651
6652 #[serde(default = "default_duration_weight")]
6654 pub relationship_duration_weight: f64,
6655
6656 #[serde(default = "default_recency_weight")]
6658 pub recency_weight: f64,
6659
6660 #[serde(default = "default_mutual_weight")]
6662 pub mutual_connections_weight: f64,
6663
6664 #[serde(default = "default_recency_half_life")]
6666 pub recency_half_life_days: u32,
6667}
6668
6669fn default_volume_weight() -> f64 {
6670 0.30
6671}
6672
6673fn default_count_weight() -> f64 {
6674 0.25
6675}
6676
6677fn default_duration_weight() -> f64 {
6678 0.20
6679}
6680
6681fn default_recency_weight() -> f64 {
6682 0.15
6683}
6684
6685fn default_mutual_weight() -> f64 {
6686 0.10
6687}
6688
6689fn default_recency_half_life() -> u32 {
6690 90
6691}
6692
6693impl Default for StrengthCalculationSchemaConfig {
6694 fn default() -> Self {
6695 Self {
6696 transaction_volume_weight: 0.30,
6697 transaction_count_weight: 0.25,
6698 relationship_duration_weight: 0.20,
6699 recency_weight: 0.15,
6700 mutual_connections_weight: 0.10,
6701 recency_half_life_days: 90,
6702 }
6703 }
6704}
6705
6706#[derive(Debug, Clone, Serialize, Deserialize)]
6708pub struct StrengthThresholdsSchemaConfig {
6709 #[serde(default = "default_strong_threshold")]
6711 pub strong: f64,
6712
6713 #[serde(default = "default_moderate_threshold")]
6715 pub moderate: f64,
6716
6717 #[serde(default = "default_weak_threshold")]
6719 pub weak: f64,
6720}
6721
6722fn default_strong_threshold() -> f64 {
6723 0.7
6724}
6725
6726fn default_moderate_threshold() -> f64 {
6727 0.4
6728}
6729
6730fn default_weak_threshold() -> f64 {
6731 0.1
6732}
6733
6734impl Default for StrengthThresholdsSchemaConfig {
6735 fn default() -> Self {
6736 Self {
6737 strong: 0.7,
6738 moderate: 0.4,
6739 weak: 0.1,
6740 }
6741 }
6742}
6743
6744#[derive(Debug, Clone, Serialize, Deserialize)]
6750pub struct CrossProcessLinksSchemaConfig {
6751 #[serde(default)]
6753 pub enabled: bool,
6754
6755 #[serde(default = "default_true")]
6757 pub inventory_p2p_o2c: bool,
6758
6759 #[serde(default = "default_true")]
6761 pub payment_bank_reconciliation: bool,
6762
6763 #[serde(default = "default_true")]
6765 pub intercompany_bilateral: bool,
6766
6767 #[serde(default = "default_inventory_link_rate")]
6769 pub inventory_link_rate: f64,
6770}
6771
6772fn default_inventory_link_rate() -> f64 {
6773 0.30
6774}
6775
6776impl Default for CrossProcessLinksSchemaConfig {
6777 fn default() -> Self {
6778 Self {
6779 enabled: false,
6780 inventory_p2p_o2c: true,
6781 payment_bank_reconciliation: true,
6782 intercompany_bilateral: true,
6783 inventory_link_rate: 0.30,
6784 }
6785 }
6786}
6787
6788#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6794pub struct OrganizationalEventsSchemaConfig {
6795 #[serde(default)]
6797 pub enabled: bool,
6798
6799 #[serde(default)]
6801 pub effect_blending: EffectBlendingModeConfig,
6802
6803 #[serde(default)]
6805 pub events: Vec<OrganizationalEventSchemaConfig>,
6806
6807 #[serde(default)]
6809 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6810
6811 #[serde(default)]
6813 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6814}
6815
6816#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6818#[serde(rename_all = "snake_case")]
6819pub enum EffectBlendingModeConfig {
6820 #[default]
6822 Multiplicative,
6823 Additive,
6825 Maximum,
6827 Minimum,
6829}
6830
6831#[derive(Debug, Clone, Serialize, Deserialize)]
6833pub struct OrganizationalEventSchemaConfig {
6834 pub id: String,
6836
6837 pub event_type: OrganizationalEventTypeSchemaConfig,
6839
6840 pub effective_date: String,
6842
6843 #[serde(default = "default_org_transition_months")]
6845 pub transition_months: u32,
6846
6847 #[serde(default)]
6849 pub description: Option<String>,
6850}
6851
6852fn default_org_transition_months() -> u32 {
6853 6
6854}
6855
6856#[derive(Debug, Clone, Serialize, Deserialize)]
6858#[serde(tag = "type", rename_all = "snake_case")]
6859pub enum OrganizationalEventTypeSchemaConfig {
6860 Acquisition {
6862 acquired_entity: String,
6864 #[serde(default = "default_acquisition_volume")]
6866 volume_increase: f64,
6867 #[serde(default = "default_acquisition_error")]
6869 integration_error_rate: f64,
6870 #[serde(default = "default_parallel_days")]
6872 parallel_posting_days: u32,
6873 },
6874 Divestiture {
6876 divested_entity: String,
6878 #[serde(default = "default_divestiture_volume")]
6880 volume_reduction: f64,
6881 #[serde(default = "default_true_val")]
6883 remove_entity: bool,
6884 },
6885 Reorganization {
6887 #[serde(default)]
6889 cost_center_remapping: std::collections::HashMap<String, String>,
6890 #[serde(default = "default_reorg_error")]
6892 transition_error_rate: f64,
6893 },
6894 LeadershipChange {
6896 role: String,
6898 #[serde(default)]
6900 policy_changes: Vec<String>,
6901 },
6902 WorkforceReduction {
6904 #[serde(default = "default_workforce_reduction")]
6906 reduction_percent: f64,
6907 #[serde(default = "default_workforce_error")]
6909 error_rate_increase: f64,
6910 },
6911 Merger {
6913 merged_entity: String,
6915 #[serde(default = "default_merger_volume")]
6917 volume_increase: f64,
6918 },
6919}
6920
6921fn default_acquisition_volume() -> f64 {
6922 1.35
6923}
6924
6925fn default_acquisition_error() -> f64 {
6926 0.05
6927}
6928
6929fn default_parallel_days() -> u32 {
6930 30
6931}
6932
6933fn default_divestiture_volume() -> f64 {
6934 0.70
6935}
6936
6937fn default_true_val() -> bool {
6938 true
6939}
6940
6941fn default_reorg_error() -> f64 {
6942 0.04
6943}
6944
6945fn default_workforce_reduction() -> f64 {
6946 0.10
6947}
6948
6949fn default_workforce_error() -> f64 {
6950 0.05
6951}
6952
6953fn default_merger_volume() -> f64 {
6954 1.80
6955}
6956
6957#[derive(Debug, Clone, Serialize, Deserialize)]
6959pub struct ProcessEvolutionSchemaConfig {
6960 pub id: String,
6962
6963 pub event_type: ProcessEvolutionTypeSchemaConfig,
6965
6966 pub effective_date: String,
6968
6969 #[serde(default)]
6971 pub description: Option<String>,
6972}
6973
6974#[derive(Debug, Clone, Serialize, Deserialize)]
6976#[serde(tag = "type", rename_all = "snake_case")]
6977pub enum ProcessEvolutionTypeSchemaConfig {
6978 ProcessAutomation {
6980 process_name: String,
6982 #[serde(default = "default_manual_before")]
6984 manual_rate_before: f64,
6985 #[serde(default = "default_manual_after")]
6987 manual_rate_after: f64,
6988 },
6989 ApprovalWorkflowChange {
6991 description: String,
6993 },
6994 ControlEnhancement {
6996 control_id: String,
6998 #[serde(default = "default_error_reduction")]
7000 error_reduction: f64,
7001 },
7002}
7003
7004fn default_manual_before() -> f64 {
7005 0.80
7006}
7007
7008fn default_manual_after() -> f64 {
7009 0.15
7010}
7011
7012fn default_error_reduction() -> f64 {
7013 0.02
7014}
7015
7016#[derive(Debug, Clone, Serialize, Deserialize)]
7018pub struct TechnologyTransitionSchemaConfig {
7019 pub id: String,
7021
7022 pub event_type: TechnologyTransitionTypeSchemaConfig,
7024
7025 #[serde(default)]
7027 pub description: Option<String>,
7028}
7029
7030#[derive(Debug, Clone, Serialize, Deserialize)]
7032#[serde(tag = "type", rename_all = "snake_case")]
7033pub enum TechnologyTransitionTypeSchemaConfig {
7034 ErpMigration {
7036 source_system: String,
7038 target_system: String,
7040 cutover_date: String,
7042 stabilization_end: String,
7044 #[serde(default = "default_erp_duplicate_rate")]
7046 duplicate_rate: f64,
7047 #[serde(default = "default_format_mismatch")]
7049 format_mismatch_rate: f64,
7050 },
7051 ModuleImplementation {
7053 module_name: String,
7055 go_live_date: String,
7057 },
7058}
7059
7060fn default_erp_duplicate_rate() -> f64 {
7061 0.02
7062}
7063
7064fn default_format_mismatch() -> f64 {
7065 0.03
7066}
7067
7068#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7074pub struct BehavioralDriftSchemaConfig {
7075 #[serde(default)]
7077 pub enabled: bool,
7078
7079 #[serde(default)]
7081 pub vendor_behavior: VendorBehaviorSchemaConfig,
7082
7083 #[serde(default)]
7085 pub customer_behavior: CustomerBehaviorSchemaConfig,
7086
7087 #[serde(default)]
7089 pub employee_behavior: EmployeeBehaviorSchemaConfig,
7090
7091 #[serde(default)]
7093 pub collective: CollectiveBehaviorSchemaConfig,
7094}
7095
7096#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7098pub struct VendorBehaviorSchemaConfig {
7099 #[serde(default)]
7101 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7102
7103 #[serde(default)]
7105 pub quality_drift: QualityDriftSchemaConfig,
7106}
7107
7108#[derive(Debug, Clone, Serialize, Deserialize)]
7110pub struct PaymentTermsDriftSchemaConfig {
7111 #[serde(default = "default_extension_rate")]
7113 pub extension_rate_per_year: f64,
7114
7115 #[serde(default = "default_economic_sensitivity")]
7117 pub economic_sensitivity: f64,
7118}
7119
7120fn default_extension_rate() -> f64 {
7121 2.5
7122}
7123
7124fn default_economic_sensitivity() -> f64 {
7125 1.0
7126}
7127
7128impl Default for PaymentTermsDriftSchemaConfig {
7129 fn default() -> Self {
7130 Self {
7131 extension_rate_per_year: 2.5,
7132 economic_sensitivity: 1.0,
7133 }
7134 }
7135}
7136
7137#[derive(Debug, Clone, Serialize, Deserialize)]
7139pub struct QualityDriftSchemaConfig {
7140 #[serde(default = "default_improvement_rate")]
7142 pub new_vendor_improvement_rate: f64,
7143
7144 #[serde(default = "default_decline_rate")]
7146 pub complacency_decline_rate: f64,
7147}
7148
7149fn default_improvement_rate() -> f64 {
7150 0.02
7151}
7152
7153fn default_decline_rate() -> f64 {
7154 0.01
7155}
7156
7157impl Default for QualityDriftSchemaConfig {
7158 fn default() -> Self {
7159 Self {
7160 new_vendor_improvement_rate: 0.02,
7161 complacency_decline_rate: 0.01,
7162 }
7163 }
7164}
7165
7166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7168pub struct CustomerBehaviorSchemaConfig {
7169 #[serde(default)]
7171 pub payment_drift: CustomerPaymentDriftSchemaConfig,
7172
7173 #[serde(default)]
7175 pub order_drift: OrderDriftSchemaConfig,
7176}
7177
7178#[derive(Debug, Clone, Serialize, Deserialize)]
7180pub struct CustomerPaymentDriftSchemaConfig {
7181 #[serde(default = "default_downturn_extension")]
7183 pub downturn_days_extension: (u32, u32),
7184
7185 #[serde(default = "default_bad_debt_increase")]
7187 pub downturn_bad_debt_increase: f64,
7188}
7189
7190fn default_downturn_extension() -> (u32, u32) {
7191 (5, 15)
7192}
7193
7194fn default_bad_debt_increase() -> f64 {
7195 0.02
7196}
7197
7198impl Default for CustomerPaymentDriftSchemaConfig {
7199 fn default() -> Self {
7200 Self {
7201 downturn_days_extension: (5, 15),
7202 downturn_bad_debt_increase: 0.02,
7203 }
7204 }
7205}
7206
7207#[derive(Debug, Clone, Serialize, Deserialize)]
7209pub struct OrderDriftSchemaConfig {
7210 #[serde(default = "default_digital_shift")]
7212 pub digital_shift_rate: f64,
7213}
7214
7215fn default_digital_shift() -> f64 {
7216 0.05
7217}
7218
7219impl Default for OrderDriftSchemaConfig {
7220 fn default() -> Self {
7221 Self {
7222 digital_shift_rate: 0.05,
7223 }
7224 }
7225}
7226
7227#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7229pub struct EmployeeBehaviorSchemaConfig {
7230 #[serde(default)]
7232 pub approval_drift: ApprovalDriftSchemaConfig,
7233
7234 #[serde(default)]
7236 pub error_drift: ErrorDriftSchemaConfig,
7237}
7238
7239#[derive(Debug, Clone, Serialize, Deserialize)]
7241pub struct ApprovalDriftSchemaConfig {
7242 #[serde(default = "default_eom_intensity")]
7244 pub eom_intensity_increase_per_year: f64,
7245
7246 #[serde(default = "default_rubber_stamp")]
7248 pub rubber_stamp_volume_threshold: u32,
7249}
7250
7251fn default_eom_intensity() -> f64 {
7252 0.05
7253}
7254
7255fn default_rubber_stamp() -> u32 {
7256 50
7257}
7258
7259impl Default for ApprovalDriftSchemaConfig {
7260 fn default() -> Self {
7261 Self {
7262 eom_intensity_increase_per_year: 0.05,
7263 rubber_stamp_volume_threshold: 50,
7264 }
7265 }
7266}
7267
7268#[derive(Debug, Clone, Serialize, Deserialize)]
7270pub struct ErrorDriftSchemaConfig {
7271 #[serde(default = "default_new_error")]
7273 pub new_employee_error_rate: f64,
7274
7275 #[serde(default = "default_learning_months")]
7277 pub learning_curve_months: u32,
7278}
7279
7280fn default_new_error() -> f64 {
7281 0.08
7282}
7283
7284fn default_learning_months() -> u32 {
7285 6
7286}
7287
7288impl Default for ErrorDriftSchemaConfig {
7289 fn default() -> Self {
7290 Self {
7291 new_employee_error_rate: 0.08,
7292 learning_curve_months: 6,
7293 }
7294 }
7295}
7296
7297#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7299pub struct CollectiveBehaviorSchemaConfig {
7300 #[serde(default)]
7302 pub automation_adoption: AutomationAdoptionSchemaConfig,
7303}
7304
7305#[derive(Debug, Clone, Serialize, Deserialize)]
7307pub struct AutomationAdoptionSchemaConfig {
7308 #[serde(default)]
7310 pub s_curve_enabled: bool,
7311
7312 #[serde(default = "default_midpoint")]
7314 pub adoption_midpoint_months: u32,
7315
7316 #[serde(default = "default_steepness")]
7318 pub steepness: f64,
7319}
7320
7321fn default_midpoint() -> u32 {
7322 24
7323}
7324
7325fn default_steepness() -> f64 {
7326 0.15
7327}
7328
7329impl Default for AutomationAdoptionSchemaConfig {
7330 fn default() -> Self {
7331 Self {
7332 s_curve_enabled: false,
7333 adoption_midpoint_months: 24,
7334 steepness: 0.15,
7335 }
7336 }
7337}
7338
7339#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7345pub struct MarketDriftSchemaConfig {
7346 #[serde(default)]
7348 pub enabled: bool,
7349
7350 #[serde(default)]
7352 pub economic_cycle: MarketEconomicCycleSchemaConfig,
7353
7354 #[serde(default)]
7356 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7357
7358 #[serde(default)]
7360 pub commodities: CommoditiesSchemaConfig,
7361}
7362
7363#[derive(Debug, Clone, Serialize, Deserialize)]
7365pub struct MarketEconomicCycleSchemaConfig {
7366 #[serde(default)]
7368 pub enabled: bool,
7369
7370 #[serde(default)]
7372 pub cycle_type: CycleTypeSchemaConfig,
7373
7374 #[serde(default = "default_market_cycle_period")]
7376 pub period_months: u32,
7377
7378 #[serde(default = "default_market_amplitude")]
7380 pub amplitude: f64,
7381
7382 #[serde(default)]
7384 pub recession: RecessionSchemaConfig,
7385}
7386
7387fn default_market_cycle_period() -> u32 {
7388 48
7389}
7390
7391fn default_market_amplitude() -> f64 {
7392 0.15
7393}
7394
7395impl Default for MarketEconomicCycleSchemaConfig {
7396 fn default() -> Self {
7397 Self {
7398 enabled: false,
7399 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7400 period_months: 48,
7401 amplitude: 0.15,
7402 recession: RecessionSchemaConfig::default(),
7403 }
7404 }
7405}
7406
7407#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7409#[serde(rename_all = "snake_case")]
7410pub enum CycleTypeSchemaConfig {
7411 #[default]
7413 Sinusoidal,
7414 Asymmetric,
7416 MeanReverting,
7418}
7419
7420#[derive(Debug, Clone, Serialize, Deserialize)]
7422pub struct RecessionSchemaConfig {
7423 #[serde(default)]
7425 pub enabled: bool,
7426
7427 #[serde(default = "default_recession_prob")]
7429 pub probability_per_year: f64,
7430
7431 #[serde(default)]
7433 pub severity: RecessionSeveritySchemaConfig,
7434
7435 #[serde(default)]
7437 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7438}
7439
7440fn default_recession_prob() -> f64 {
7441 0.10
7442}
7443
7444impl Default for RecessionSchemaConfig {
7445 fn default() -> Self {
7446 Self {
7447 enabled: false,
7448 probability_per_year: 0.10,
7449 severity: RecessionSeveritySchemaConfig::Moderate,
7450 recession_periods: Vec::new(),
7451 }
7452 }
7453}
7454
7455#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7457#[serde(rename_all = "snake_case")]
7458pub enum RecessionSeveritySchemaConfig {
7459 Mild,
7461 #[default]
7463 Moderate,
7464 Severe,
7466}
7467
7468#[derive(Debug, Clone, Serialize, Deserialize)]
7470pub struct RecessionPeriodSchemaConfig {
7471 pub start_month: u32,
7473 pub duration_months: u32,
7475}
7476
7477#[derive(Debug, Clone, Serialize, Deserialize)]
7479pub struct IndustryCycleSchemaConfig {
7480 #[serde(default = "default_industry_period")]
7482 pub period_months: u32,
7483
7484 #[serde(default = "default_industry_amp")]
7486 pub amplitude: f64,
7487}
7488
7489fn default_industry_period() -> u32 {
7490 36
7491}
7492
7493fn default_industry_amp() -> f64 {
7494 0.20
7495}
7496
7497#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7499pub struct CommoditiesSchemaConfig {
7500 #[serde(default)]
7502 pub enabled: bool,
7503
7504 #[serde(default)]
7506 pub items: Vec<CommodityItemSchemaConfig>,
7507}
7508
7509#[derive(Debug, Clone, Serialize, Deserialize)]
7511pub struct CommodityItemSchemaConfig {
7512 pub name: String,
7514
7515 #[serde(default = "default_volatility")]
7517 pub volatility: f64,
7518
7519 #[serde(default)]
7521 pub cogs_pass_through: f64,
7522
7523 #[serde(default)]
7525 pub overhead_pass_through: f64,
7526}
7527
7528fn default_volatility() -> f64 {
7529 0.20
7530}
7531
7532#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7538pub struct DriftLabelingSchemaConfig {
7539 #[serde(default)]
7541 pub enabled: bool,
7542
7543 #[serde(default)]
7545 pub statistical: StatisticalDriftLabelingSchemaConfig,
7546
7547 #[serde(default)]
7549 pub categorical: CategoricalDriftLabelingSchemaConfig,
7550
7551 #[serde(default)]
7553 pub temporal: TemporalDriftLabelingSchemaConfig,
7554
7555 #[serde(default)]
7557 pub regulatory_calendar_preset: Option<String>,
7558}
7559
7560#[derive(Debug, Clone, Serialize, Deserialize)]
7562pub struct StatisticalDriftLabelingSchemaConfig {
7563 #[serde(default = "default_true_val")]
7565 pub enabled: bool,
7566
7567 #[serde(default = "default_min_magnitude")]
7569 pub min_magnitude_threshold: f64,
7570}
7571
7572fn default_min_magnitude() -> f64 {
7573 0.05
7574}
7575
7576impl Default for StatisticalDriftLabelingSchemaConfig {
7577 fn default() -> Self {
7578 Self {
7579 enabled: true,
7580 min_magnitude_threshold: 0.05,
7581 }
7582 }
7583}
7584
7585#[derive(Debug, Clone, Serialize, Deserialize)]
7587pub struct CategoricalDriftLabelingSchemaConfig {
7588 #[serde(default = "default_true_val")]
7590 pub enabled: bool,
7591}
7592
7593impl Default for CategoricalDriftLabelingSchemaConfig {
7594 fn default() -> Self {
7595 Self { enabled: true }
7596 }
7597}
7598
7599#[derive(Debug, Clone, Serialize, Deserialize)]
7601pub struct TemporalDriftLabelingSchemaConfig {
7602 #[serde(default = "default_true_val")]
7604 pub enabled: bool,
7605}
7606
7607impl Default for TemporalDriftLabelingSchemaConfig {
7608 fn default() -> Self {
7609 Self { enabled: true }
7610 }
7611}
7612
7613#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7626pub struct EnhancedAnomalyConfig {
7627 #[serde(default)]
7629 pub enabled: bool,
7630
7631 #[serde(default)]
7633 pub rates: AnomalyRateConfig,
7634
7635 #[serde(default)]
7637 pub multi_stage_schemes: MultiStageSchemeConfig,
7638
7639 #[serde(default)]
7641 pub correlated_injection: CorrelatedInjectionConfig,
7642
7643 #[serde(default)]
7645 pub near_miss: NearMissConfig,
7646
7647 #[serde(default)]
7649 pub difficulty_classification: DifficultyClassificationConfig,
7650
7651 #[serde(default)]
7653 pub context_aware: ContextAwareConfig,
7654
7655 #[serde(default)]
7657 pub labeling: EnhancedLabelingConfig,
7658}
7659
7660#[derive(Debug, Clone, Serialize, Deserialize)]
7662pub struct AnomalyRateConfig {
7663 #[serde(default = "default_total_anomaly_rate")]
7665 pub total_rate: f64,
7666
7667 #[serde(default = "default_fraud_anomaly_rate")]
7669 pub fraud_rate: f64,
7670
7671 #[serde(default = "default_error_anomaly_rate")]
7673 pub error_rate: f64,
7674
7675 #[serde(default = "default_process_anomaly_rate")]
7677 pub process_rate: f64,
7678}
7679
7680fn default_total_anomaly_rate() -> f64 {
7681 0.03
7682}
7683fn default_fraud_anomaly_rate() -> f64 {
7684 0.01
7685}
7686fn default_error_anomaly_rate() -> f64 {
7687 0.015
7688}
7689fn default_process_anomaly_rate() -> f64 {
7690 0.005
7691}
7692
7693impl Default for AnomalyRateConfig {
7694 fn default() -> Self {
7695 Self {
7696 total_rate: default_total_anomaly_rate(),
7697 fraud_rate: default_fraud_anomaly_rate(),
7698 error_rate: default_error_anomaly_rate(),
7699 process_rate: default_process_anomaly_rate(),
7700 }
7701 }
7702}
7703
7704#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7706pub struct MultiStageSchemeConfig {
7707 #[serde(default)]
7709 pub enabled: bool,
7710
7711 #[serde(default)]
7713 pub embezzlement: EmbezzlementSchemeConfig,
7714
7715 #[serde(default)]
7717 pub revenue_manipulation: RevenueManipulationSchemeConfig,
7718
7719 #[serde(default)]
7721 pub kickback: KickbackSchemeConfig,
7722}
7723
7724#[derive(Debug, Clone, Serialize, Deserialize)]
7726pub struct EmbezzlementSchemeConfig {
7727 #[serde(default = "default_embezzlement_probability")]
7729 pub probability: f64,
7730
7731 #[serde(default)]
7733 pub testing_stage: SchemeStageConfig,
7734
7735 #[serde(default)]
7737 pub escalation_stage: SchemeStageConfig,
7738
7739 #[serde(default)]
7741 pub acceleration_stage: SchemeStageConfig,
7742
7743 #[serde(default)]
7745 pub desperation_stage: SchemeStageConfig,
7746}
7747
7748fn default_embezzlement_probability() -> f64 {
7749 0.02
7750}
7751
7752impl Default for EmbezzlementSchemeConfig {
7753 fn default() -> Self {
7754 Self {
7755 probability: default_embezzlement_probability(),
7756 testing_stage: SchemeStageConfig {
7757 duration_months: 2,
7758 amount_min: 100.0,
7759 amount_max: 500.0,
7760 transaction_count_min: 2,
7761 transaction_count_max: 5,
7762 difficulty: "hard".to_string(),
7763 },
7764 escalation_stage: SchemeStageConfig {
7765 duration_months: 6,
7766 amount_min: 500.0,
7767 amount_max: 2000.0,
7768 transaction_count_min: 3,
7769 transaction_count_max: 8,
7770 difficulty: "moderate".to_string(),
7771 },
7772 acceleration_stage: SchemeStageConfig {
7773 duration_months: 3,
7774 amount_min: 2000.0,
7775 amount_max: 10000.0,
7776 transaction_count_min: 5,
7777 transaction_count_max: 12,
7778 difficulty: "easy".to_string(),
7779 },
7780 desperation_stage: SchemeStageConfig {
7781 duration_months: 1,
7782 amount_min: 10000.0,
7783 amount_max: 50000.0,
7784 transaction_count_min: 3,
7785 transaction_count_max: 6,
7786 difficulty: "trivial".to_string(),
7787 },
7788 }
7789 }
7790}
7791
7792#[derive(Debug, Clone, Serialize, Deserialize)]
7794pub struct RevenueManipulationSchemeConfig {
7795 #[serde(default = "default_revenue_manipulation_probability")]
7797 pub probability: f64,
7798
7799 #[serde(default = "default_early_recognition_target")]
7801 pub early_recognition_target: f64,
7802
7803 #[serde(default = "default_expense_deferral_target")]
7805 pub expense_deferral_target: f64,
7806
7807 #[serde(default = "default_reserve_release_target")]
7809 pub reserve_release_target: f64,
7810
7811 #[serde(default = "default_channel_stuffing_target")]
7813 pub channel_stuffing_target: f64,
7814}
7815
7816fn default_revenue_manipulation_probability() -> f64 {
7817 0.01
7818}
7819fn default_early_recognition_target() -> f64 {
7820 0.02
7821}
7822fn default_expense_deferral_target() -> f64 {
7823 0.03
7824}
7825fn default_reserve_release_target() -> f64 {
7826 0.02
7827}
7828fn default_channel_stuffing_target() -> f64 {
7829 0.05
7830}
7831
7832impl Default for RevenueManipulationSchemeConfig {
7833 fn default() -> Self {
7834 Self {
7835 probability: default_revenue_manipulation_probability(),
7836 early_recognition_target: default_early_recognition_target(),
7837 expense_deferral_target: default_expense_deferral_target(),
7838 reserve_release_target: default_reserve_release_target(),
7839 channel_stuffing_target: default_channel_stuffing_target(),
7840 }
7841 }
7842}
7843
7844#[derive(Debug, Clone, Serialize, Deserialize)]
7846pub struct KickbackSchemeConfig {
7847 #[serde(default = "default_kickback_probability")]
7849 pub probability: f64,
7850
7851 #[serde(default = "default_kickback_inflation_min")]
7853 pub inflation_min: f64,
7854
7855 #[serde(default = "default_kickback_inflation_max")]
7857 pub inflation_max: f64,
7858
7859 #[serde(default = "default_kickback_percent")]
7861 pub kickback_percent: f64,
7862
7863 #[serde(default = "default_kickback_setup_months")]
7865 pub setup_months: u32,
7866
7867 #[serde(default = "default_kickback_operation_months")]
7869 pub operation_months: u32,
7870}
7871
7872fn default_kickback_probability() -> f64 {
7873 0.01
7874}
7875fn default_kickback_inflation_min() -> f64 {
7876 0.10
7877}
7878fn default_kickback_inflation_max() -> f64 {
7879 0.25
7880}
7881fn default_kickback_percent() -> f64 {
7882 0.50
7883}
7884fn default_kickback_setup_months() -> u32 {
7885 3
7886}
7887fn default_kickback_operation_months() -> u32 {
7888 12
7889}
7890
7891impl Default for KickbackSchemeConfig {
7892 fn default() -> Self {
7893 Self {
7894 probability: default_kickback_probability(),
7895 inflation_min: default_kickback_inflation_min(),
7896 inflation_max: default_kickback_inflation_max(),
7897 kickback_percent: default_kickback_percent(),
7898 setup_months: default_kickback_setup_months(),
7899 operation_months: default_kickback_operation_months(),
7900 }
7901 }
7902}
7903
7904#[derive(Debug, Clone, Serialize, Deserialize)]
7906pub struct SchemeStageConfig {
7907 pub duration_months: u32,
7909
7910 pub amount_min: f64,
7912
7913 pub amount_max: f64,
7915
7916 pub transaction_count_min: u32,
7918
7919 pub transaction_count_max: u32,
7921
7922 pub difficulty: String,
7924}
7925
7926impl Default for SchemeStageConfig {
7927 fn default() -> Self {
7928 Self {
7929 duration_months: 3,
7930 amount_min: 100.0,
7931 amount_max: 1000.0,
7932 transaction_count_min: 2,
7933 transaction_count_max: 10,
7934 difficulty: "moderate".to_string(),
7935 }
7936 }
7937}
7938
7939#[derive(Debug, Clone, Serialize, Deserialize)]
7941pub struct CorrelatedInjectionConfig {
7942 #[serde(default)]
7944 pub enabled: bool,
7945
7946 #[serde(default = "default_true_val")]
7948 pub fraud_concealment: bool,
7949
7950 #[serde(default = "default_true_val")]
7952 pub error_cascade: bool,
7953
7954 #[serde(default = "default_true_val")]
7956 pub temporal_clustering: bool,
7957
7958 #[serde(default)]
7960 pub temporal_clustering_config: TemporalClusteringConfig,
7961
7962 #[serde(default)]
7964 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
7965}
7966
7967impl Default for CorrelatedInjectionConfig {
7968 fn default() -> Self {
7969 Self {
7970 enabled: false,
7971 fraud_concealment: true,
7972 error_cascade: true,
7973 temporal_clustering: true,
7974 temporal_clustering_config: TemporalClusteringConfig::default(),
7975 co_occurrence_patterns: Vec::new(),
7976 }
7977 }
7978}
7979
7980#[derive(Debug, Clone, Serialize, Deserialize)]
7982pub struct TemporalClusteringConfig {
7983 #[serde(default = "default_period_end_multiplier")]
7985 pub period_end_multiplier: f64,
7986
7987 #[serde(default = "default_period_end_days")]
7989 pub period_end_days: u32,
7990
7991 #[serde(default = "default_quarter_end_multiplier")]
7993 pub quarter_end_multiplier: f64,
7994
7995 #[serde(default = "default_year_end_multiplier")]
7997 pub year_end_multiplier: f64,
7998}
7999
8000fn default_period_end_multiplier() -> f64 {
8001 2.5
8002}
8003fn default_period_end_days() -> u32 {
8004 5
8005}
8006fn default_quarter_end_multiplier() -> f64 {
8007 1.5
8008}
8009fn default_year_end_multiplier() -> f64 {
8010 2.0
8011}
8012
8013impl Default for TemporalClusteringConfig {
8014 fn default() -> Self {
8015 Self {
8016 period_end_multiplier: default_period_end_multiplier(),
8017 period_end_days: default_period_end_days(),
8018 quarter_end_multiplier: default_quarter_end_multiplier(),
8019 year_end_multiplier: default_year_end_multiplier(),
8020 }
8021 }
8022}
8023
8024#[derive(Debug, Clone, Serialize, Deserialize)]
8026pub struct CoOccurrencePatternConfig {
8027 pub name: String,
8029
8030 pub primary_type: String,
8032
8033 pub correlated: Vec<CorrelatedAnomalyConfig>,
8035}
8036
8037#[derive(Debug, Clone, Serialize, Deserialize)]
8039pub struct CorrelatedAnomalyConfig {
8040 pub anomaly_type: String,
8042
8043 pub probability: f64,
8045
8046 pub lag_days_min: i32,
8048
8049 pub lag_days_max: i32,
8051}
8052
8053#[derive(Debug, Clone, Serialize, Deserialize)]
8055pub struct NearMissConfig {
8056 #[serde(default)]
8058 pub enabled: bool,
8059
8060 #[serde(default = "default_near_miss_proportion")]
8062 pub proportion: f64,
8063
8064 #[serde(default = "default_true_val")]
8066 pub near_duplicate: bool,
8067
8068 #[serde(default)]
8070 pub near_duplicate_days: NearDuplicateDaysConfig,
8071
8072 #[serde(default = "default_true_val")]
8074 pub threshold_proximity: bool,
8075
8076 #[serde(default)]
8078 pub threshold_proximity_range: ThresholdProximityRangeConfig,
8079
8080 #[serde(default = "default_true_val")]
8082 pub unusual_legitimate: bool,
8083
8084 #[serde(default = "default_unusual_legitimate_types")]
8086 pub unusual_legitimate_types: Vec<String>,
8087
8088 #[serde(default = "default_true_val")]
8090 pub corrected_errors: bool,
8091
8092 #[serde(default)]
8094 pub corrected_error_lag: CorrectedErrorLagConfig,
8095}
8096
8097fn default_near_miss_proportion() -> f64 {
8098 0.30
8099}
8100
8101fn default_unusual_legitimate_types() -> Vec<String> {
8102 vec![
8103 "year_end_bonus".to_string(),
8104 "contract_prepayment".to_string(),
8105 "insurance_claim".to_string(),
8106 "settlement_payment".to_string(),
8107 ]
8108}
8109
8110impl Default for NearMissConfig {
8111 fn default() -> Self {
8112 Self {
8113 enabled: false,
8114 proportion: default_near_miss_proportion(),
8115 near_duplicate: true,
8116 near_duplicate_days: NearDuplicateDaysConfig::default(),
8117 threshold_proximity: true,
8118 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8119 unusual_legitimate: true,
8120 unusual_legitimate_types: default_unusual_legitimate_types(),
8121 corrected_errors: true,
8122 corrected_error_lag: CorrectedErrorLagConfig::default(),
8123 }
8124 }
8125}
8126
8127#[derive(Debug, Clone, Serialize, Deserialize)]
8129pub struct NearDuplicateDaysConfig {
8130 #[serde(default = "default_near_duplicate_min")]
8132 pub min: u32,
8133
8134 #[serde(default = "default_near_duplicate_max")]
8136 pub max: u32,
8137}
8138
8139fn default_near_duplicate_min() -> u32 {
8140 1
8141}
8142fn default_near_duplicate_max() -> u32 {
8143 3
8144}
8145
8146impl Default for NearDuplicateDaysConfig {
8147 fn default() -> Self {
8148 Self {
8149 min: default_near_duplicate_min(),
8150 max: default_near_duplicate_max(),
8151 }
8152 }
8153}
8154
8155#[derive(Debug, Clone, Serialize, Deserialize)]
8157pub struct ThresholdProximityRangeConfig {
8158 #[serde(default = "default_threshold_proximity_min")]
8160 pub min: f64,
8161
8162 #[serde(default = "default_threshold_proximity_max")]
8164 pub max: f64,
8165}
8166
8167fn default_threshold_proximity_min() -> f64 {
8168 0.90
8169}
8170fn default_threshold_proximity_max() -> f64 {
8171 0.99
8172}
8173
8174impl Default for ThresholdProximityRangeConfig {
8175 fn default() -> Self {
8176 Self {
8177 min: default_threshold_proximity_min(),
8178 max: default_threshold_proximity_max(),
8179 }
8180 }
8181}
8182
8183#[derive(Debug, Clone, Serialize, Deserialize)]
8185pub struct CorrectedErrorLagConfig {
8186 #[serde(default = "default_corrected_error_lag_min")]
8188 pub min: u32,
8189
8190 #[serde(default = "default_corrected_error_lag_max")]
8192 pub max: u32,
8193}
8194
8195fn default_corrected_error_lag_min() -> u32 {
8196 1
8197}
8198fn default_corrected_error_lag_max() -> u32 {
8199 5
8200}
8201
8202impl Default for CorrectedErrorLagConfig {
8203 fn default() -> Self {
8204 Self {
8205 min: default_corrected_error_lag_min(),
8206 max: default_corrected_error_lag_max(),
8207 }
8208 }
8209}
8210
8211#[derive(Debug, Clone, Serialize, Deserialize)]
8213pub struct DifficultyClassificationConfig {
8214 #[serde(default)]
8216 pub enabled: bool,
8217
8218 #[serde(default)]
8220 pub target_distribution: DifficultyDistributionConfig,
8221}
8222
8223impl Default for DifficultyClassificationConfig {
8224 fn default() -> Self {
8225 Self {
8226 enabled: true,
8227 target_distribution: DifficultyDistributionConfig::default(),
8228 }
8229 }
8230}
8231
8232#[derive(Debug, Clone, Serialize, Deserialize)]
8234pub struct DifficultyDistributionConfig {
8235 #[serde(default = "default_difficulty_trivial")]
8237 pub trivial: f64,
8238
8239 #[serde(default = "default_difficulty_easy")]
8241 pub easy: f64,
8242
8243 #[serde(default = "default_difficulty_moderate")]
8245 pub moderate: f64,
8246
8247 #[serde(default = "default_difficulty_hard")]
8249 pub hard: f64,
8250
8251 #[serde(default = "default_difficulty_expert")]
8253 pub expert: f64,
8254}
8255
8256fn default_difficulty_trivial() -> f64 {
8257 0.15
8258}
8259fn default_difficulty_easy() -> f64 {
8260 0.25
8261}
8262fn default_difficulty_moderate() -> f64 {
8263 0.30
8264}
8265fn default_difficulty_hard() -> f64 {
8266 0.20
8267}
8268fn default_difficulty_expert() -> f64 {
8269 0.10
8270}
8271
8272impl Default for DifficultyDistributionConfig {
8273 fn default() -> Self {
8274 Self {
8275 trivial: default_difficulty_trivial(),
8276 easy: default_difficulty_easy(),
8277 moderate: default_difficulty_moderate(),
8278 hard: default_difficulty_hard(),
8279 expert: default_difficulty_expert(),
8280 }
8281 }
8282}
8283
8284#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8286pub struct ContextAwareConfig {
8287 #[serde(default)]
8289 pub enabled: bool,
8290
8291 #[serde(default)]
8293 pub vendor_rules: VendorAnomalyRulesConfig,
8294
8295 #[serde(default)]
8297 pub employee_rules: EmployeeAnomalyRulesConfig,
8298
8299 #[serde(default)]
8301 pub account_rules: AccountAnomalyRulesConfig,
8302
8303 #[serde(default)]
8305 pub behavioral_baseline: BehavioralBaselineConfig,
8306}
8307
8308#[derive(Debug, Clone, Serialize, Deserialize)]
8310pub struct VendorAnomalyRulesConfig {
8311 #[serde(default = "default_new_vendor_multiplier")]
8313 pub new_vendor_error_multiplier: f64,
8314
8315 #[serde(default = "default_new_vendor_threshold")]
8317 pub new_vendor_threshold_days: u32,
8318
8319 #[serde(default = "default_international_multiplier")]
8321 pub international_error_multiplier: f64,
8322
8323 #[serde(default = "default_strategic_vendor_types")]
8325 pub strategic_vendor_anomaly_types: Vec<String>,
8326}
8327
8328fn default_new_vendor_multiplier() -> f64 {
8329 2.5
8330}
8331fn default_new_vendor_threshold() -> u32 {
8332 90
8333}
8334fn default_international_multiplier() -> f64 {
8335 1.5
8336}
8337fn default_strategic_vendor_types() -> Vec<String> {
8338 vec![
8339 "pricing_dispute".to_string(),
8340 "contract_violation".to_string(),
8341 ]
8342}
8343
8344impl Default for VendorAnomalyRulesConfig {
8345 fn default() -> Self {
8346 Self {
8347 new_vendor_error_multiplier: default_new_vendor_multiplier(),
8348 new_vendor_threshold_days: default_new_vendor_threshold(),
8349 international_error_multiplier: default_international_multiplier(),
8350 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8351 }
8352 }
8353}
8354
8355#[derive(Debug, Clone, Serialize, Deserialize)]
8357pub struct EmployeeAnomalyRulesConfig {
8358 #[serde(default = "default_new_employee_rate")]
8360 pub new_employee_error_rate: f64,
8361
8362 #[serde(default = "default_new_employee_threshold")]
8364 pub new_employee_threshold_days: u32,
8365
8366 #[serde(default = "default_volume_fatigue_threshold")]
8368 pub volume_fatigue_threshold: u32,
8369
8370 #[serde(default = "default_coverage_multiplier")]
8372 pub coverage_error_multiplier: f64,
8373}
8374
8375fn default_new_employee_rate() -> f64 {
8376 0.05
8377}
8378fn default_new_employee_threshold() -> u32 {
8379 180
8380}
8381fn default_volume_fatigue_threshold() -> u32 {
8382 50
8383}
8384fn default_coverage_multiplier() -> f64 {
8385 1.8
8386}
8387
8388impl Default for EmployeeAnomalyRulesConfig {
8389 fn default() -> Self {
8390 Self {
8391 new_employee_error_rate: default_new_employee_rate(),
8392 new_employee_threshold_days: default_new_employee_threshold(),
8393 volume_fatigue_threshold: default_volume_fatigue_threshold(),
8394 coverage_error_multiplier: default_coverage_multiplier(),
8395 }
8396 }
8397}
8398
8399#[derive(Debug, Clone, Serialize, Deserialize)]
8401pub struct AccountAnomalyRulesConfig {
8402 #[serde(default = "default_high_risk_multiplier")]
8404 pub high_risk_account_multiplier: f64,
8405
8406 #[serde(default = "default_high_risk_accounts")]
8408 pub high_risk_accounts: Vec<String>,
8409
8410 #[serde(default = "default_suspense_multiplier")]
8412 pub suspense_account_multiplier: f64,
8413
8414 #[serde(default = "default_suspense_accounts")]
8416 pub suspense_accounts: Vec<String>,
8417
8418 #[serde(default = "default_intercompany_multiplier")]
8420 pub intercompany_account_multiplier: f64,
8421}
8422
8423fn default_high_risk_multiplier() -> f64 {
8424 2.0
8425}
8426fn default_high_risk_accounts() -> Vec<String> {
8427 vec![
8428 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
8432}
8433fn default_suspense_multiplier() -> f64 {
8434 3.0
8435}
8436fn default_suspense_accounts() -> Vec<String> {
8437 vec!["9999".to_string(), "9998".to_string()]
8438}
8439fn default_intercompany_multiplier() -> f64 {
8440 1.5
8441}
8442
8443impl Default for AccountAnomalyRulesConfig {
8444 fn default() -> Self {
8445 Self {
8446 high_risk_account_multiplier: default_high_risk_multiplier(),
8447 high_risk_accounts: default_high_risk_accounts(),
8448 suspense_account_multiplier: default_suspense_multiplier(),
8449 suspense_accounts: default_suspense_accounts(),
8450 intercompany_account_multiplier: default_intercompany_multiplier(),
8451 }
8452 }
8453}
8454
8455#[derive(Debug, Clone, Serialize, Deserialize)]
8457pub struct BehavioralBaselineConfig {
8458 #[serde(default)]
8460 pub enabled: bool,
8461
8462 #[serde(default = "default_baseline_period")]
8464 pub baseline_period_days: u32,
8465
8466 #[serde(default = "default_deviation_threshold")]
8468 pub deviation_threshold_std: f64,
8469
8470 #[serde(default = "default_frequency_deviation")]
8472 pub frequency_deviation_threshold: f64,
8473}
8474
8475fn default_baseline_period() -> u32 {
8476 90
8477}
8478fn default_deviation_threshold() -> f64 {
8479 3.0
8480}
8481fn default_frequency_deviation() -> f64 {
8482 2.0
8483}
8484
8485impl Default for BehavioralBaselineConfig {
8486 fn default() -> Self {
8487 Self {
8488 enabled: false,
8489 baseline_period_days: default_baseline_period(),
8490 deviation_threshold_std: default_deviation_threshold(),
8491 frequency_deviation_threshold: default_frequency_deviation(),
8492 }
8493 }
8494}
8495
8496#[derive(Debug, Clone, Serialize, Deserialize)]
8498pub struct EnhancedLabelingConfig {
8499 #[serde(default = "default_true_val")]
8501 pub severity_scoring: bool,
8502
8503 #[serde(default = "default_true_val")]
8505 pub difficulty_classification: bool,
8506
8507 #[serde(default)]
8509 pub materiality_thresholds: MaterialityThresholdsConfig,
8510}
8511
8512impl Default for EnhancedLabelingConfig {
8513 fn default() -> Self {
8514 Self {
8515 severity_scoring: true,
8516 difficulty_classification: true,
8517 materiality_thresholds: MaterialityThresholdsConfig::default(),
8518 }
8519 }
8520}
8521
8522#[derive(Debug, Clone, Serialize, Deserialize)]
8524pub struct MaterialityThresholdsConfig {
8525 #[serde(default = "default_materiality_trivial")]
8527 pub trivial: f64,
8528
8529 #[serde(default = "default_materiality_immaterial")]
8531 pub immaterial: f64,
8532
8533 #[serde(default = "default_materiality_material")]
8535 pub material: f64,
8536
8537 #[serde(default = "default_materiality_highly_material")]
8539 pub highly_material: f64,
8540}
8541
8542fn default_materiality_trivial() -> f64 {
8543 0.001
8544}
8545fn default_materiality_immaterial() -> f64 {
8546 0.01
8547}
8548fn default_materiality_material() -> f64 {
8549 0.05
8550}
8551fn default_materiality_highly_material() -> f64 {
8552 0.10
8553}
8554
8555impl Default for MaterialityThresholdsConfig {
8556 fn default() -> Self {
8557 Self {
8558 trivial: default_materiality_trivial(),
8559 immaterial: default_materiality_immaterial(),
8560 material: default_materiality_material(),
8561 highly_material: default_materiality_highly_material(),
8562 }
8563 }
8564}
8565
8566#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8578pub struct IndustrySpecificConfig {
8579 #[serde(default)]
8581 pub enabled: bool,
8582
8583 #[serde(default)]
8585 pub manufacturing: ManufacturingConfig,
8586
8587 #[serde(default)]
8589 pub retail: RetailConfig,
8590
8591 #[serde(default)]
8593 pub healthcare: HealthcareConfig,
8594
8595 #[serde(default)]
8597 pub technology: TechnologyConfig,
8598
8599 #[serde(default)]
8601 pub financial_services: FinancialServicesConfig,
8602
8603 #[serde(default)]
8605 pub professional_services: ProfessionalServicesConfig,
8606}
8607
8608#[derive(Debug, Clone, Serialize, Deserialize)]
8610pub struct ManufacturingConfig {
8611 #[serde(default)]
8613 pub enabled: bool,
8614
8615 #[serde(default = "default_bom_depth")]
8617 pub bom_depth: u32,
8618
8619 #[serde(default)]
8621 pub just_in_time: bool,
8622
8623 #[serde(default = "default_production_order_types")]
8625 pub production_order_types: Vec<String>,
8626
8627 #[serde(default)]
8629 pub quality_framework: Option<String>,
8630
8631 #[serde(default = "default_supplier_tiers")]
8633 pub supplier_tiers: u32,
8634
8635 #[serde(default = "default_cost_frequency")]
8637 pub standard_cost_frequency: String,
8638
8639 #[serde(default = "default_yield_rate")]
8641 pub target_yield_rate: f64,
8642
8643 #[serde(default = "default_scrap_threshold")]
8645 pub scrap_alert_threshold: f64,
8646
8647 #[serde(default)]
8649 pub anomaly_rates: ManufacturingAnomalyRates,
8650}
8651
8652fn default_bom_depth() -> u32 {
8653 4
8654}
8655
8656fn default_production_order_types() -> Vec<String> {
8657 vec![
8658 "standard".to_string(),
8659 "rework".to_string(),
8660 "prototype".to_string(),
8661 ]
8662}
8663
8664fn default_supplier_tiers() -> u32 {
8665 2
8666}
8667
8668fn default_cost_frequency() -> String {
8669 "quarterly".to_string()
8670}
8671
8672fn default_yield_rate() -> f64 {
8673 0.97
8674}
8675
8676fn default_scrap_threshold() -> f64 {
8677 0.03
8678}
8679
8680impl Default for ManufacturingConfig {
8681 fn default() -> Self {
8682 Self {
8683 enabled: false,
8684 bom_depth: default_bom_depth(),
8685 just_in_time: false,
8686 production_order_types: default_production_order_types(),
8687 quality_framework: Some("ISO_9001".to_string()),
8688 supplier_tiers: default_supplier_tiers(),
8689 standard_cost_frequency: default_cost_frequency(),
8690 target_yield_rate: default_yield_rate(),
8691 scrap_alert_threshold: default_scrap_threshold(),
8692 anomaly_rates: ManufacturingAnomalyRates::default(),
8693 }
8694 }
8695}
8696
8697#[derive(Debug, Clone, Serialize, Deserialize)]
8699pub struct ManufacturingAnomalyRates {
8700 #[serde(default = "default_mfg_yield_rate")]
8702 pub yield_manipulation: f64,
8703
8704 #[serde(default = "default_mfg_labor_rate")]
8706 pub labor_misallocation: f64,
8707
8708 #[serde(default = "default_mfg_phantom_rate")]
8710 pub phantom_production: f64,
8711
8712 #[serde(default = "default_mfg_cost_rate")]
8714 pub standard_cost_manipulation: f64,
8715
8716 #[serde(default = "default_mfg_inventory_rate")]
8718 pub inventory_fraud: f64,
8719}
8720
8721fn default_mfg_yield_rate() -> f64 {
8722 0.015
8723}
8724
8725fn default_mfg_labor_rate() -> f64 {
8726 0.02
8727}
8728
8729fn default_mfg_phantom_rate() -> f64 {
8730 0.005
8731}
8732
8733fn default_mfg_cost_rate() -> f64 {
8734 0.01
8735}
8736
8737fn default_mfg_inventory_rate() -> f64 {
8738 0.008
8739}
8740
8741impl Default for ManufacturingAnomalyRates {
8742 fn default() -> Self {
8743 Self {
8744 yield_manipulation: default_mfg_yield_rate(),
8745 labor_misallocation: default_mfg_labor_rate(),
8746 phantom_production: default_mfg_phantom_rate(),
8747 standard_cost_manipulation: default_mfg_cost_rate(),
8748 inventory_fraud: default_mfg_inventory_rate(),
8749 }
8750 }
8751}
8752
8753#[derive(Debug, Clone, Serialize, Deserialize)]
8755pub struct RetailConfig {
8756 #[serde(default)]
8758 pub enabled: bool,
8759
8760 #[serde(default)]
8762 pub store_types: RetailStoreTypeConfig,
8763
8764 #[serde(default = "default_retail_daily_txns")]
8766 pub avg_daily_transactions: u32,
8767
8768 #[serde(default = "default_true")]
8770 pub loss_prevention: bool,
8771
8772 #[serde(default = "default_shrinkage_rate")]
8774 pub shrinkage_rate: f64,
8775
8776 #[serde(default)]
8778 pub anomaly_rates: RetailAnomalyRates,
8779}
8780
8781fn default_retail_daily_txns() -> u32 {
8782 500
8783}
8784
8785fn default_shrinkage_rate() -> f64 {
8786 0.015
8787}
8788
8789impl Default for RetailConfig {
8790 fn default() -> Self {
8791 Self {
8792 enabled: false,
8793 store_types: RetailStoreTypeConfig::default(),
8794 avg_daily_transactions: default_retail_daily_txns(),
8795 loss_prevention: true,
8796 shrinkage_rate: default_shrinkage_rate(),
8797 anomaly_rates: RetailAnomalyRates::default(),
8798 }
8799 }
8800}
8801
8802#[derive(Debug, Clone, Serialize, Deserialize)]
8804pub struct RetailStoreTypeConfig {
8805 #[serde(default = "default_flagship_pct")]
8807 pub flagship: f64,
8808
8809 #[serde(default = "default_regional_pct")]
8811 pub regional: f64,
8812
8813 #[serde(default = "default_outlet_pct")]
8815 pub outlet: f64,
8816
8817 #[serde(default = "default_ecommerce_pct")]
8819 pub ecommerce: f64,
8820}
8821
8822fn default_flagship_pct() -> f64 {
8823 0.10
8824}
8825
8826fn default_regional_pct() -> f64 {
8827 0.50
8828}
8829
8830fn default_outlet_pct() -> f64 {
8831 0.25
8832}
8833
8834fn default_ecommerce_pct() -> f64 {
8835 0.15
8836}
8837
8838impl Default for RetailStoreTypeConfig {
8839 fn default() -> Self {
8840 Self {
8841 flagship: default_flagship_pct(),
8842 regional: default_regional_pct(),
8843 outlet: default_outlet_pct(),
8844 ecommerce: default_ecommerce_pct(),
8845 }
8846 }
8847}
8848
8849#[derive(Debug, Clone, Serialize, Deserialize)]
8851pub struct RetailAnomalyRates {
8852 #[serde(default = "default_sweethearting_rate")]
8854 pub sweethearting: f64,
8855
8856 #[serde(default = "default_skimming_rate")]
8858 pub skimming: f64,
8859
8860 #[serde(default = "default_refund_fraud_rate")]
8862 pub refund_fraud: f64,
8863
8864 #[serde(default = "default_void_abuse_rate")]
8866 pub void_abuse: f64,
8867
8868 #[serde(default = "default_gift_card_rate")]
8870 pub gift_card_fraud: f64,
8871
8872 #[serde(default = "default_retail_kickback_rate")]
8874 pub vendor_kickback: f64,
8875}
8876
8877fn default_sweethearting_rate() -> f64 {
8878 0.02
8879}
8880
8881fn default_skimming_rate() -> f64 {
8882 0.005
8883}
8884
8885fn default_refund_fraud_rate() -> f64 {
8886 0.015
8887}
8888
8889fn default_void_abuse_rate() -> f64 {
8890 0.01
8891}
8892
8893fn default_gift_card_rate() -> f64 {
8894 0.008
8895}
8896
8897fn default_retail_kickback_rate() -> f64 {
8898 0.003
8899}
8900
8901impl Default for RetailAnomalyRates {
8902 fn default() -> Self {
8903 Self {
8904 sweethearting: default_sweethearting_rate(),
8905 skimming: default_skimming_rate(),
8906 refund_fraud: default_refund_fraud_rate(),
8907 void_abuse: default_void_abuse_rate(),
8908 gift_card_fraud: default_gift_card_rate(),
8909 vendor_kickback: default_retail_kickback_rate(),
8910 }
8911 }
8912}
8913
8914#[derive(Debug, Clone, Serialize, Deserialize)]
8916pub struct HealthcareConfig {
8917 #[serde(default)]
8919 pub enabled: bool,
8920
8921 #[serde(default = "default_facility_type")]
8923 pub facility_type: String,
8924
8925 #[serde(default)]
8927 pub payer_mix: HealthcarePayerMix,
8928
8929 #[serde(default)]
8931 pub coding_systems: HealthcareCodingSystems,
8932
8933 #[serde(default)]
8935 pub compliance: HealthcareComplianceConfig,
8936
8937 #[serde(default = "default_daily_encounters")]
8939 pub avg_daily_encounters: u32,
8940
8941 #[serde(default = "default_charges_per_encounter")]
8943 pub avg_charges_per_encounter: u32,
8944
8945 #[serde(default = "default_hc_denial_rate")]
8947 pub denial_rate: f64,
8948
8949 #[serde(default = "default_hc_bad_debt_rate")]
8951 pub bad_debt_rate: f64,
8952
8953 #[serde(default = "default_hc_charity_care_rate")]
8955 pub charity_care_rate: f64,
8956
8957 #[serde(default)]
8959 pub anomaly_rates: HealthcareAnomalyRates,
8960}
8961
8962fn default_facility_type() -> String {
8963 "hospital".to_string()
8964}
8965
8966fn default_daily_encounters() -> u32 {
8967 150
8968}
8969
8970fn default_charges_per_encounter() -> u32 {
8971 8
8972}
8973
8974fn default_hc_denial_rate() -> f64 {
8975 0.05
8976}
8977
8978fn default_hc_bad_debt_rate() -> f64 {
8979 0.03
8980}
8981
8982fn default_hc_charity_care_rate() -> f64 {
8983 0.02
8984}
8985
8986impl Default for HealthcareConfig {
8987 fn default() -> Self {
8988 Self {
8989 enabled: false,
8990 facility_type: default_facility_type(),
8991 payer_mix: HealthcarePayerMix::default(),
8992 coding_systems: HealthcareCodingSystems::default(),
8993 compliance: HealthcareComplianceConfig::default(),
8994 avg_daily_encounters: default_daily_encounters(),
8995 avg_charges_per_encounter: default_charges_per_encounter(),
8996 denial_rate: default_hc_denial_rate(),
8997 bad_debt_rate: default_hc_bad_debt_rate(),
8998 charity_care_rate: default_hc_charity_care_rate(),
8999 anomaly_rates: HealthcareAnomalyRates::default(),
9000 }
9001 }
9002}
9003
9004#[derive(Debug, Clone, Serialize, Deserialize)]
9006pub struct HealthcarePayerMix {
9007 #[serde(default = "default_medicare_pct")]
9009 pub medicare: f64,
9010
9011 #[serde(default = "default_medicaid_pct")]
9013 pub medicaid: f64,
9014
9015 #[serde(default = "default_commercial_pct")]
9017 pub commercial: f64,
9018
9019 #[serde(default = "default_self_pay_pct")]
9021 pub self_pay: f64,
9022}
9023
9024fn default_medicare_pct() -> f64 {
9025 0.40
9026}
9027
9028fn default_medicaid_pct() -> f64 {
9029 0.20
9030}
9031
9032fn default_commercial_pct() -> f64 {
9033 0.30
9034}
9035
9036fn default_self_pay_pct() -> f64 {
9037 0.10
9038}
9039
9040impl Default for HealthcarePayerMix {
9041 fn default() -> Self {
9042 Self {
9043 medicare: default_medicare_pct(),
9044 medicaid: default_medicaid_pct(),
9045 commercial: default_commercial_pct(),
9046 self_pay: default_self_pay_pct(),
9047 }
9048 }
9049}
9050
9051#[derive(Debug, Clone, Serialize, Deserialize)]
9053pub struct HealthcareCodingSystems {
9054 #[serde(default = "default_true")]
9056 pub icd10: bool,
9057
9058 #[serde(default = "default_true")]
9060 pub cpt: bool,
9061
9062 #[serde(default = "default_true")]
9064 pub drg: bool,
9065
9066 #[serde(default = "default_true")]
9068 pub hcpcs: bool,
9069
9070 #[serde(default = "default_true")]
9072 pub revenue_codes: bool,
9073}
9074
9075impl Default for HealthcareCodingSystems {
9076 fn default() -> Self {
9077 Self {
9078 icd10: true,
9079 cpt: true,
9080 drg: true,
9081 hcpcs: true,
9082 revenue_codes: true,
9083 }
9084 }
9085}
9086
9087#[derive(Debug, Clone, Serialize, Deserialize)]
9089pub struct HealthcareComplianceConfig {
9090 #[serde(default = "default_true")]
9092 pub hipaa: bool,
9093
9094 #[serde(default = "default_true")]
9096 pub stark_law: bool,
9097
9098 #[serde(default = "default_true")]
9100 pub anti_kickback: bool,
9101
9102 #[serde(default = "default_true")]
9104 pub false_claims_act: bool,
9105
9106 #[serde(default = "default_true")]
9108 pub emtala: bool,
9109}
9110
9111impl Default for HealthcareComplianceConfig {
9112 fn default() -> Self {
9113 Self {
9114 hipaa: true,
9115 stark_law: true,
9116 anti_kickback: true,
9117 false_claims_act: true,
9118 emtala: true,
9119 }
9120 }
9121}
9122
9123#[derive(Debug, Clone, Serialize, Deserialize)]
9125pub struct HealthcareAnomalyRates {
9126 #[serde(default = "default_upcoding_rate")]
9128 pub upcoding: f64,
9129
9130 #[serde(default = "default_unbundling_rate")]
9132 pub unbundling: f64,
9133
9134 #[serde(default = "default_phantom_billing_rate")]
9136 pub phantom_billing: f64,
9137
9138 #[serde(default = "default_healthcare_kickback_rate")]
9140 pub kickbacks: f64,
9141
9142 #[serde(default = "default_duplicate_billing_rate")]
9144 pub duplicate_billing: f64,
9145
9146 #[serde(default = "default_med_necessity_rate")]
9148 pub medical_necessity_abuse: f64,
9149}
9150
9151fn default_upcoding_rate() -> f64 {
9152 0.02
9153}
9154
9155fn default_unbundling_rate() -> f64 {
9156 0.015
9157}
9158
9159fn default_phantom_billing_rate() -> f64 {
9160 0.005
9161}
9162
9163fn default_healthcare_kickback_rate() -> f64 {
9164 0.003
9165}
9166
9167fn default_duplicate_billing_rate() -> f64 {
9168 0.008
9169}
9170
9171fn default_med_necessity_rate() -> f64 {
9172 0.01
9173}
9174
9175impl Default for HealthcareAnomalyRates {
9176 fn default() -> Self {
9177 Self {
9178 upcoding: default_upcoding_rate(),
9179 unbundling: default_unbundling_rate(),
9180 phantom_billing: default_phantom_billing_rate(),
9181 kickbacks: default_healthcare_kickback_rate(),
9182 duplicate_billing: default_duplicate_billing_rate(),
9183 medical_necessity_abuse: default_med_necessity_rate(),
9184 }
9185 }
9186}
9187
9188#[derive(Debug, Clone, Serialize, Deserialize)]
9190pub struct TechnologyConfig {
9191 #[serde(default)]
9193 pub enabled: bool,
9194
9195 #[serde(default = "default_revenue_model")]
9197 pub revenue_model: String,
9198
9199 #[serde(default = "default_subscription_pct")]
9201 pub subscription_revenue_pct: f64,
9202
9203 #[serde(default = "default_license_pct")]
9205 pub license_revenue_pct: f64,
9206
9207 #[serde(default = "default_services_pct")]
9209 pub services_revenue_pct: f64,
9210
9211 #[serde(default)]
9213 pub rd_capitalization: RdCapitalizationConfig,
9214
9215 #[serde(default)]
9217 pub anomaly_rates: TechnologyAnomalyRates,
9218}
9219
9220fn default_revenue_model() -> String {
9221 "saas".to_string()
9222}
9223
9224fn default_subscription_pct() -> f64 {
9225 0.60
9226}
9227
9228fn default_license_pct() -> f64 {
9229 0.25
9230}
9231
9232fn default_services_pct() -> f64 {
9233 0.15
9234}
9235
9236impl Default for TechnologyConfig {
9237 fn default() -> Self {
9238 Self {
9239 enabled: false,
9240 revenue_model: default_revenue_model(),
9241 subscription_revenue_pct: default_subscription_pct(),
9242 license_revenue_pct: default_license_pct(),
9243 services_revenue_pct: default_services_pct(),
9244 rd_capitalization: RdCapitalizationConfig::default(),
9245 anomaly_rates: TechnologyAnomalyRates::default(),
9246 }
9247 }
9248}
9249
9250#[derive(Debug, Clone, Serialize, Deserialize)]
9252pub struct RdCapitalizationConfig {
9253 #[serde(default = "default_true")]
9255 pub enabled: bool,
9256
9257 #[serde(default = "default_cap_rate")]
9259 pub capitalization_rate: f64,
9260
9261 #[serde(default = "default_useful_life")]
9263 pub useful_life_years: u32,
9264}
9265
9266fn default_cap_rate() -> f64 {
9267 0.30
9268}
9269
9270fn default_useful_life() -> u32 {
9271 3
9272}
9273
9274impl Default for RdCapitalizationConfig {
9275 fn default() -> Self {
9276 Self {
9277 enabled: true,
9278 capitalization_rate: default_cap_rate(),
9279 useful_life_years: default_useful_life(),
9280 }
9281 }
9282}
9283
9284#[derive(Debug, Clone, Serialize, Deserialize)]
9286pub struct TechnologyAnomalyRates {
9287 #[serde(default = "default_premature_rev_rate")]
9289 pub premature_revenue: f64,
9290
9291 #[serde(default = "default_side_letter_rate")]
9293 pub side_letter_abuse: f64,
9294
9295 #[serde(default = "default_channel_stuffing_rate")]
9297 pub channel_stuffing: f64,
9298
9299 #[serde(default = "default_improper_cap_rate")]
9301 pub improper_capitalization: f64,
9302}
9303
9304fn default_premature_rev_rate() -> f64 {
9305 0.015
9306}
9307
9308fn default_side_letter_rate() -> f64 {
9309 0.008
9310}
9311
9312fn default_channel_stuffing_rate() -> f64 {
9313 0.01
9314}
9315
9316fn default_improper_cap_rate() -> f64 {
9317 0.012
9318}
9319
9320impl Default for TechnologyAnomalyRates {
9321 fn default() -> Self {
9322 Self {
9323 premature_revenue: default_premature_rev_rate(),
9324 side_letter_abuse: default_side_letter_rate(),
9325 channel_stuffing: default_channel_stuffing_rate(),
9326 improper_capitalization: default_improper_cap_rate(),
9327 }
9328 }
9329}
9330
9331#[derive(Debug, Clone, Serialize, Deserialize)]
9333pub struct FinancialServicesConfig {
9334 #[serde(default)]
9336 pub enabled: bool,
9337
9338 #[serde(default = "default_fi_type")]
9340 pub institution_type: String,
9341
9342 #[serde(default = "default_fi_regulatory")]
9344 pub regulatory_framework: String,
9345
9346 #[serde(default)]
9348 pub anomaly_rates: FinancialServicesAnomalyRates,
9349}
9350
9351fn default_fi_type() -> String {
9352 "commercial_bank".to_string()
9353}
9354
9355fn default_fi_regulatory() -> String {
9356 "us_banking".to_string()
9357}
9358
9359impl Default for FinancialServicesConfig {
9360 fn default() -> Self {
9361 Self {
9362 enabled: false,
9363 institution_type: default_fi_type(),
9364 regulatory_framework: default_fi_regulatory(),
9365 anomaly_rates: FinancialServicesAnomalyRates::default(),
9366 }
9367 }
9368}
9369
9370#[derive(Debug, Clone, Serialize, Deserialize)]
9372pub struct FinancialServicesAnomalyRates {
9373 #[serde(default = "default_loan_fraud_rate")]
9375 pub loan_fraud: f64,
9376
9377 #[serde(default = "default_trading_fraud_rate")]
9379 pub trading_fraud: f64,
9380
9381 #[serde(default = "default_insurance_fraud_rate")]
9383 pub insurance_fraud: f64,
9384
9385 #[serde(default = "default_account_manip_rate")]
9387 pub account_manipulation: f64,
9388}
9389
9390fn default_loan_fraud_rate() -> f64 {
9391 0.01
9392}
9393
9394fn default_trading_fraud_rate() -> f64 {
9395 0.008
9396}
9397
9398fn default_insurance_fraud_rate() -> f64 {
9399 0.012
9400}
9401
9402fn default_account_manip_rate() -> f64 {
9403 0.005
9404}
9405
9406impl Default for FinancialServicesAnomalyRates {
9407 fn default() -> Self {
9408 Self {
9409 loan_fraud: default_loan_fraud_rate(),
9410 trading_fraud: default_trading_fraud_rate(),
9411 insurance_fraud: default_insurance_fraud_rate(),
9412 account_manipulation: default_account_manip_rate(),
9413 }
9414 }
9415}
9416
9417#[derive(Debug, Clone, Serialize, Deserialize)]
9419pub struct ProfessionalServicesConfig {
9420 #[serde(default)]
9422 pub enabled: bool,
9423
9424 #[serde(default = "default_firm_type")]
9426 pub firm_type: String,
9427
9428 #[serde(default = "default_billing_model")]
9430 pub billing_model: String,
9431
9432 #[serde(default = "default_hourly_rate")]
9434 pub avg_hourly_rate: f64,
9435
9436 #[serde(default)]
9438 pub trust_accounting: TrustAccountingConfig,
9439
9440 #[serde(default)]
9442 pub anomaly_rates: ProfessionalServicesAnomalyRates,
9443}
9444
9445fn default_firm_type() -> String {
9446 "consulting".to_string()
9447}
9448
9449fn default_billing_model() -> String {
9450 "time_and_materials".to_string()
9451}
9452
9453fn default_hourly_rate() -> f64 {
9454 250.0
9455}
9456
9457impl Default for ProfessionalServicesConfig {
9458 fn default() -> Self {
9459 Self {
9460 enabled: false,
9461 firm_type: default_firm_type(),
9462 billing_model: default_billing_model(),
9463 avg_hourly_rate: default_hourly_rate(),
9464 trust_accounting: TrustAccountingConfig::default(),
9465 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9466 }
9467 }
9468}
9469
9470#[derive(Debug, Clone, Serialize, Deserialize)]
9472pub struct TrustAccountingConfig {
9473 #[serde(default)]
9475 pub enabled: bool,
9476
9477 #[serde(default = "default_true")]
9479 pub require_three_way_reconciliation: bool,
9480}
9481
9482impl Default for TrustAccountingConfig {
9483 fn default() -> Self {
9484 Self {
9485 enabled: false,
9486 require_three_way_reconciliation: true,
9487 }
9488 }
9489}
9490
9491#[derive(Debug, Clone, Serialize, Deserialize)]
9493pub struct ProfessionalServicesAnomalyRates {
9494 #[serde(default = "default_time_fraud_rate")]
9496 pub time_billing_fraud: f64,
9497
9498 #[serde(default = "default_expense_fraud_rate")]
9500 pub expense_fraud: f64,
9501
9502 #[serde(default = "default_trust_misappropriation_rate")]
9504 pub trust_misappropriation: f64,
9505}
9506
9507fn default_time_fraud_rate() -> f64 {
9508 0.02
9509}
9510
9511fn default_expense_fraud_rate() -> f64 {
9512 0.015
9513}
9514
9515fn default_trust_misappropriation_rate() -> f64 {
9516 0.003
9517}
9518
9519impl Default for ProfessionalServicesAnomalyRates {
9520 fn default() -> Self {
9521 Self {
9522 time_billing_fraud: default_time_fraud_rate(),
9523 expense_fraud: default_expense_fraud_rate(),
9524 trust_misappropriation: default_trust_misappropriation_rate(),
9525 }
9526 }
9527}
9528
9529#[cfg(test)]
9530mod tests {
9531 use super::*;
9532 use crate::presets::demo_preset;
9533
9534 #[test]
9539 fn test_config_yaml_roundtrip() {
9540 let config = demo_preset();
9541 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9542 let deserialized: GeneratorConfig =
9543 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9544
9545 assert_eq!(
9546 config.global.period_months,
9547 deserialized.global.period_months
9548 );
9549 assert_eq!(config.global.industry, deserialized.global.industry);
9550 assert_eq!(config.companies.len(), deserialized.companies.len());
9551 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9552 }
9553
9554 #[test]
9555 fn test_config_json_roundtrip() {
9556 let mut config = demo_preset();
9558 config.master_data.employees.approval_limits.executive = 1e12;
9560
9561 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9562 let deserialized: GeneratorConfig =
9563 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9564
9565 assert_eq!(
9566 config.global.period_months,
9567 deserialized.global.period_months
9568 );
9569 assert_eq!(config.global.industry, deserialized.global.industry);
9570 assert_eq!(config.companies.len(), deserialized.companies.len());
9571 }
9572
9573 #[test]
9574 fn test_transaction_volume_serialization() {
9575 let volumes = vec![
9577 (TransactionVolume::TenK, "ten_k"),
9578 (TransactionVolume::HundredK, "hundred_k"),
9579 (TransactionVolume::OneM, "one_m"),
9580 (TransactionVolume::TenM, "ten_m"),
9581 (TransactionVolume::HundredM, "hundred_m"),
9582 ];
9583
9584 for (volume, expected_key) in volumes {
9585 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9586 assert!(
9587 json.contains(expected_key),
9588 "Expected {} in JSON: {}",
9589 expected_key,
9590 json
9591 );
9592 }
9593 }
9594
9595 #[test]
9596 fn test_transaction_volume_custom_serialization() {
9597 let volume = TransactionVolume::Custom(12345);
9598 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9599 let deserialized: TransactionVolume =
9600 serde_json::from_str(&json).expect("Failed to deserialize");
9601 assert_eq!(deserialized.count(), 12345);
9602 }
9603
9604 #[test]
9605 fn test_output_mode_serialization() {
9606 let modes = vec![
9607 OutputMode::Streaming,
9608 OutputMode::FlatFile,
9609 OutputMode::Both,
9610 ];
9611
9612 for mode in modes {
9613 let json = serde_json::to_string(&mode).expect("Failed to serialize");
9614 let deserialized: OutputMode =
9615 serde_json::from_str(&json).expect("Failed to deserialize");
9616 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9617 }
9618 }
9619
9620 #[test]
9621 fn test_file_format_serialization() {
9622 let formats = vec![
9623 FileFormat::Csv,
9624 FileFormat::Parquet,
9625 FileFormat::Json,
9626 FileFormat::JsonLines,
9627 ];
9628
9629 for format in formats {
9630 let json = serde_json::to_string(&format).expect("Failed to serialize");
9631 let deserialized: FileFormat =
9632 serde_json::from_str(&json).expect("Failed to deserialize");
9633 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
9634 }
9635 }
9636
9637 #[test]
9638 fn test_compression_algorithm_serialization() {
9639 let algos = vec![
9640 CompressionAlgorithm::Gzip,
9641 CompressionAlgorithm::Zstd,
9642 CompressionAlgorithm::Lz4,
9643 CompressionAlgorithm::Snappy,
9644 ];
9645
9646 for algo in algos {
9647 let json = serde_json::to_string(&algo).expect("Failed to serialize");
9648 let deserialized: CompressionAlgorithm =
9649 serde_json::from_str(&json).expect("Failed to deserialize");
9650 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
9651 }
9652 }
9653
9654 #[test]
9655 fn test_transfer_pricing_method_serialization() {
9656 let methods = vec![
9657 TransferPricingMethod::CostPlus,
9658 TransferPricingMethod::ComparableUncontrolled,
9659 TransferPricingMethod::ResalePrice,
9660 TransferPricingMethod::TransactionalNetMargin,
9661 TransferPricingMethod::ProfitSplit,
9662 ];
9663
9664 for method in methods {
9665 let json = serde_json::to_string(&method).expect("Failed to serialize");
9666 let deserialized: TransferPricingMethod =
9667 serde_json::from_str(&json).expect("Failed to deserialize");
9668 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
9669 }
9670 }
9671
9672 #[test]
9673 fn test_benford_exemption_serialization() {
9674 let exemptions = vec![
9675 BenfordExemption::Recurring,
9676 BenfordExemption::Payroll,
9677 BenfordExemption::FixedFees,
9678 BenfordExemption::RoundAmounts,
9679 ];
9680
9681 for exemption in exemptions {
9682 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
9683 let deserialized: BenfordExemption =
9684 serde_json::from_str(&json).expect("Failed to deserialize");
9685 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
9686 }
9687 }
9688
9689 #[test]
9694 fn test_global_config_defaults() {
9695 let yaml = r#"
9696 industry: manufacturing
9697 start_date: "2024-01-01"
9698 period_months: 6
9699 "#;
9700 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9701 assert_eq!(config.group_currency, "USD");
9702 assert!(config.parallel);
9703 assert_eq!(config.worker_threads, 0);
9704 assert_eq!(config.memory_limit_mb, 0);
9705 }
9706
9707 #[test]
9708 fn test_fraud_config_defaults() {
9709 let config = FraudConfig::default();
9710 assert!(!config.enabled);
9711 assert_eq!(config.fraud_rate, 0.005);
9712 assert!(!config.clustering_enabled);
9713 }
9714
9715 #[test]
9716 fn test_internal_controls_config_defaults() {
9717 let config = InternalControlsConfig::default();
9718 assert!(!config.enabled);
9719 assert_eq!(config.exception_rate, 0.02);
9720 assert_eq!(config.sod_violation_rate, 0.01);
9721 assert!(config.export_control_master_data);
9722 assert_eq!(config.sox_materiality_threshold, 10000.0);
9723 assert!(config.coso_enabled);
9725 assert!(!config.include_entity_level_controls);
9726 assert_eq!(config.target_maturity_level, "mixed");
9727 }
9728
9729 #[test]
9730 fn test_output_config_defaults() {
9731 let config = OutputConfig::default();
9732 assert!(matches!(config.mode, OutputMode::FlatFile));
9733 assert_eq!(config.formats, vec![FileFormat::Parquet]);
9734 assert!(config.compression.enabled);
9735 assert!(matches!(
9736 config.compression.algorithm,
9737 CompressionAlgorithm::Zstd
9738 ));
9739 assert!(config.include_acdoca);
9740 assert!(!config.include_bseg);
9741 assert!(config.partition_by_period);
9742 assert!(!config.partition_by_company);
9743 }
9744
9745 #[test]
9746 fn test_approval_config_defaults() {
9747 let config = ApprovalConfig::default();
9748 assert!(!config.enabled);
9749 assert_eq!(config.auto_approve_threshold, 1000.0);
9750 assert_eq!(config.rejection_rate, 0.02);
9751 assert_eq!(config.revision_rate, 0.05);
9752 assert_eq!(config.average_approval_delay_hours, 4.0);
9753 assert_eq!(config.thresholds.len(), 4);
9754 }
9755
9756 #[test]
9757 fn test_p2p_flow_config_defaults() {
9758 let config = P2PFlowConfig::default();
9759 assert!(config.enabled);
9760 assert_eq!(config.three_way_match_rate, 0.95);
9761 assert_eq!(config.partial_delivery_rate, 0.15);
9762 assert_eq!(config.average_po_to_gr_days, 14);
9763 }
9764
9765 #[test]
9766 fn test_o2c_flow_config_defaults() {
9767 let config = O2CFlowConfig::default();
9768 assert!(config.enabled);
9769 assert_eq!(config.credit_check_failure_rate, 0.02);
9770 assert_eq!(config.return_rate, 0.03);
9771 assert_eq!(config.bad_debt_rate, 0.01);
9772 }
9773
9774 #[test]
9775 fn test_balance_config_defaults() {
9776 let config = BalanceConfig::default();
9777 assert!(!config.generate_opening_balances);
9778 assert!(config.generate_trial_balances);
9779 assert_eq!(config.target_gross_margin, 0.35);
9780 assert!(config.validate_balance_equation);
9781 assert!(config.reconcile_subledgers);
9782 }
9783
9784 #[test]
9789 fn test_partial_config_with_defaults() {
9790 let yaml = r#"
9792 global:
9793 industry: manufacturing
9794 start_date: "2024-01-01"
9795 period_months: 3
9796 companies:
9797 - code: "TEST"
9798 name: "Test Company"
9799 currency: "USD"
9800 country: "US"
9801 annual_transaction_volume: ten_k
9802 chart_of_accounts:
9803 complexity: small
9804 output:
9805 output_directory: "./output"
9806 "#;
9807
9808 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9809 assert_eq!(config.global.period_months, 3);
9810 assert_eq!(config.companies.len(), 1);
9811 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
9814
9815 #[test]
9816 fn test_config_with_fraud_enabled() {
9817 let yaml = r#"
9818 global:
9819 industry: retail
9820 start_date: "2024-01-01"
9821 period_months: 12
9822 companies:
9823 - code: "RETAIL"
9824 name: "Retail Co"
9825 currency: "USD"
9826 country: "US"
9827 annual_transaction_volume: hundred_k
9828 chart_of_accounts:
9829 complexity: medium
9830 output:
9831 output_directory: "./output"
9832 fraud:
9833 enabled: true
9834 fraud_rate: 0.05
9835 clustering_enabled: true
9836 "#;
9837
9838 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9839 assert!(config.fraud.enabled);
9840 assert_eq!(config.fraud.fraud_rate, 0.05);
9841 assert!(config.fraud.clustering_enabled);
9842 }
9843
9844 #[test]
9845 fn test_config_with_multiple_companies() {
9846 let yaml = r#"
9847 global:
9848 industry: manufacturing
9849 start_date: "2024-01-01"
9850 period_months: 6
9851 companies:
9852 - code: "HQ"
9853 name: "Headquarters"
9854 currency: "USD"
9855 country: "US"
9856 annual_transaction_volume: hundred_k
9857 volume_weight: 1.0
9858 - code: "EU"
9859 name: "European Subsidiary"
9860 currency: "EUR"
9861 country: "DE"
9862 annual_transaction_volume: hundred_k
9863 volume_weight: 0.5
9864 - code: "APAC"
9865 name: "Asia Pacific"
9866 currency: "JPY"
9867 country: "JP"
9868 annual_transaction_volume: ten_k
9869 volume_weight: 0.3
9870 chart_of_accounts:
9871 complexity: large
9872 output:
9873 output_directory: "./output"
9874 "#;
9875
9876 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9877 assert_eq!(config.companies.len(), 3);
9878 assert_eq!(config.companies[0].code, "HQ");
9879 assert_eq!(config.companies[1].currency, "EUR");
9880 assert_eq!(config.companies[2].volume_weight, 0.3);
9881 }
9882
9883 #[test]
9884 fn test_intercompany_config() {
9885 let yaml = r#"
9886 enabled: true
9887 ic_transaction_rate: 0.20
9888 transfer_pricing_method: cost_plus
9889 markup_percent: 0.08
9890 generate_matched_pairs: true
9891 generate_eliminations: true
9892 "#;
9893
9894 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9895 assert!(config.enabled);
9896 assert_eq!(config.ic_transaction_rate, 0.20);
9897 assert!(matches!(
9898 config.transfer_pricing_method,
9899 TransferPricingMethod::CostPlus
9900 ));
9901 assert_eq!(config.markup_percent, 0.08);
9902 assert!(config.generate_eliminations);
9903 }
9904
9905 #[test]
9910 fn test_company_config_defaults() {
9911 let yaml = r#"
9912 code: "TEST"
9913 name: "Test Company"
9914 currency: "USD"
9915 country: "US"
9916 annual_transaction_volume: ten_k
9917 "#;
9918
9919 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9920 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
9923
9924 #[test]
9929 fn test_coa_config_defaults() {
9930 let yaml = r#"
9931 complexity: medium
9932 "#;
9933
9934 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9935 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
9937 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
9940
9941 #[test]
9946 fn test_accounting_standards_config_defaults() {
9947 let config = AccountingStandardsConfig::default();
9948 assert!(!config.enabled);
9949 assert!(matches!(
9950 config.framework,
9951 AccountingFrameworkConfig::UsGaap
9952 ));
9953 assert!(!config.revenue_recognition.enabled);
9954 assert!(!config.leases.enabled);
9955 assert!(!config.fair_value.enabled);
9956 assert!(!config.impairment.enabled);
9957 assert!(!config.generate_differences);
9958 }
9959
9960 #[test]
9961 fn test_accounting_standards_config_yaml() {
9962 let yaml = r#"
9963 enabled: true
9964 framework: ifrs
9965 revenue_recognition:
9966 enabled: true
9967 generate_contracts: true
9968 avg_obligations_per_contract: 2.5
9969 variable_consideration_rate: 0.20
9970 over_time_recognition_rate: 0.35
9971 contract_count: 150
9972 leases:
9973 enabled: true
9974 lease_count: 75
9975 finance_lease_percent: 0.25
9976 avg_lease_term_months: 48
9977 generate_differences: true
9978 "#;
9979
9980 let config: AccountingStandardsConfig =
9981 serde_yaml::from_str(yaml).expect("Failed to parse");
9982 assert!(config.enabled);
9983 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
9984 assert!(config.revenue_recognition.enabled);
9985 assert_eq!(config.revenue_recognition.contract_count, 150);
9986 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
9987 assert!(config.leases.enabled);
9988 assert_eq!(config.leases.lease_count, 75);
9989 assert_eq!(config.leases.finance_lease_percent, 0.25);
9990 assert!(config.generate_differences);
9991 }
9992
9993 #[test]
9994 fn test_accounting_framework_serialization() {
9995 let frameworks = [
9996 AccountingFrameworkConfig::UsGaap,
9997 AccountingFrameworkConfig::Ifrs,
9998 AccountingFrameworkConfig::DualReporting,
9999 ];
10000
10001 for framework in frameworks {
10002 let json = serde_json::to_string(&framework).expect("Failed to serialize");
10003 let deserialized: AccountingFrameworkConfig =
10004 serde_json::from_str(&json).expect("Failed to deserialize");
10005 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
10006 }
10007 }
10008
10009 #[test]
10010 fn test_revenue_recognition_config_defaults() {
10011 let config = RevenueRecognitionConfig::default();
10012 assert!(!config.enabled);
10013 assert!(config.generate_contracts);
10014 assert_eq!(config.avg_obligations_per_contract, 2.0);
10015 assert_eq!(config.variable_consideration_rate, 0.15);
10016 assert_eq!(config.over_time_recognition_rate, 0.30);
10017 assert_eq!(config.contract_count, 100);
10018 }
10019
10020 #[test]
10021 fn test_lease_accounting_config_defaults() {
10022 let config = LeaseAccountingConfig::default();
10023 assert!(!config.enabled);
10024 assert_eq!(config.lease_count, 50);
10025 assert_eq!(config.finance_lease_percent, 0.30);
10026 assert_eq!(config.avg_lease_term_months, 60);
10027 assert!(config.generate_amortization);
10028 assert_eq!(config.real_estate_percent, 0.40);
10029 }
10030
10031 #[test]
10032 fn test_fair_value_config_defaults() {
10033 let config = FairValueConfig::default();
10034 assert!(!config.enabled);
10035 assert_eq!(config.measurement_count, 25);
10036 assert_eq!(config.level1_percent, 0.40);
10037 assert_eq!(config.level2_percent, 0.35);
10038 assert_eq!(config.level3_percent, 0.25);
10039 assert!(!config.include_sensitivity_analysis);
10040 }
10041
10042 #[test]
10043 fn test_impairment_config_defaults() {
10044 let config = ImpairmentConfig::default();
10045 assert!(!config.enabled);
10046 assert_eq!(config.test_count, 15);
10047 assert_eq!(config.impairment_rate, 0.10);
10048 assert!(config.generate_projections);
10049 assert!(!config.include_goodwill);
10050 }
10051
10052 #[test]
10057 fn test_audit_standards_config_defaults() {
10058 let config = AuditStandardsConfig::default();
10059 assert!(!config.enabled);
10060 assert!(!config.isa_compliance.enabled);
10061 assert!(!config.analytical_procedures.enabled);
10062 assert!(!config.confirmations.enabled);
10063 assert!(!config.opinion.enabled);
10064 assert!(!config.generate_audit_trail);
10065 assert!(!config.sox.enabled);
10066 assert!(!config.pcaob.enabled);
10067 }
10068
10069 #[test]
10070 fn test_audit_standards_config_yaml() {
10071 let yaml = r#"
10072 enabled: true
10073 isa_compliance:
10074 enabled: true
10075 compliance_level: comprehensive
10076 generate_isa_mappings: true
10077 include_pcaob: true
10078 framework: dual
10079 analytical_procedures:
10080 enabled: true
10081 procedures_per_account: 5
10082 variance_probability: 0.25
10083 confirmations:
10084 enabled: true
10085 confirmation_count: 75
10086 positive_response_rate: 0.90
10087 exception_rate: 0.08
10088 opinion:
10089 enabled: true
10090 generate_kam: true
10091 average_kam_count: 4
10092 sox:
10093 enabled: true
10094 generate_302_certifications: true
10095 generate_404_assessments: true
10096 material_weakness_rate: 0.03
10097 pcaob:
10098 enabled: true
10099 is_pcaob_audit: true
10100 include_icfr_opinion: true
10101 generate_audit_trail: true
10102 "#;
10103
10104 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10105 assert!(config.enabled);
10106 assert!(config.isa_compliance.enabled);
10107 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
10108 assert!(config.isa_compliance.include_pcaob);
10109 assert_eq!(config.isa_compliance.framework, "dual");
10110 assert!(config.analytical_procedures.enabled);
10111 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
10112 assert!(config.confirmations.enabled);
10113 assert_eq!(config.confirmations.confirmation_count, 75);
10114 assert!(config.opinion.enabled);
10115 assert_eq!(config.opinion.average_kam_count, 4);
10116 assert!(config.sox.enabled);
10117 assert!(config.sox.generate_302_certifications);
10118 assert_eq!(config.sox.material_weakness_rate, 0.03);
10119 assert!(config.pcaob.enabled);
10120 assert!(config.pcaob.is_pcaob_audit);
10121 assert!(config.pcaob.include_icfr_opinion);
10122 assert!(config.generate_audit_trail);
10123 }
10124
10125 #[test]
10126 fn test_isa_compliance_config_defaults() {
10127 let config = IsaComplianceConfig::default();
10128 assert!(!config.enabled);
10129 assert_eq!(config.compliance_level, "standard");
10130 assert!(config.generate_isa_mappings);
10131 assert!(config.generate_coverage_summary);
10132 assert!(!config.include_pcaob);
10133 assert_eq!(config.framework, "isa");
10134 }
10135
10136 #[test]
10137 fn test_sox_compliance_config_defaults() {
10138 let config = SoxComplianceConfig::default();
10139 assert!(!config.enabled);
10140 assert!(config.generate_302_certifications);
10141 assert!(config.generate_404_assessments);
10142 assert_eq!(config.materiality_threshold, 10000.0);
10143 assert_eq!(config.material_weakness_rate, 0.02);
10144 assert_eq!(config.significant_deficiency_rate, 0.08);
10145 }
10146
10147 #[test]
10148 fn test_pcaob_config_defaults() {
10149 let config = PcaobConfig::default();
10150 assert!(!config.enabled);
10151 assert!(!config.is_pcaob_audit);
10152 assert!(config.generate_cam);
10153 assert!(!config.include_icfr_opinion);
10154 assert!(!config.generate_standard_mappings);
10155 }
10156
10157 #[test]
10158 fn test_config_with_standards_enabled() {
10159 let yaml = r#"
10160 global:
10161 industry: financial_services
10162 start_date: "2024-01-01"
10163 period_months: 12
10164 companies:
10165 - code: "BANK"
10166 name: "Test Bank"
10167 currency: "USD"
10168 country: "US"
10169 annual_transaction_volume: hundred_k
10170 chart_of_accounts:
10171 complexity: large
10172 output:
10173 output_directory: "./output"
10174 accounting_standards:
10175 enabled: true
10176 framework: us_gaap
10177 revenue_recognition:
10178 enabled: true
10179 leases:
10180 enabled: true
10181 audit_standards:
10182 enabled: true
10183 isa_compliance:
10184 enabled: true
10185 sox:
10186 enabled: true
10187 "#;
10188
10189 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10190 assert!(config.accounting_standards.enabled);
10191 assert!(matches!(
10192 config.accounting_standards.framework,
10193 AccountingFrameworkConfig::UsGaap
10194 ));
10195 assert!(config.accounting_standards.revenue_recognition.enabled);
10196 assert!(config.accounting_standards.leases.enabled);
10197 assert!(config.audit_standards.enabled);
10198 assert!(config.audit_standards.isa_compliance.enabled);
10199 assert!(config.audit_standards.sox.enabled);
10200 }
10201
10202 #[test]
10207 fn test_industry_specific_config_defaults() {
10208 let config = IndustrySpecificConfig::default();
10209 assert!(!config.enabled);
10210 assert!(!config.manufacturing.enabled);
10211 assert!(!config.retail.enabled);
10212 assert!(!config.healthcare.enabled);
10213 assert!(!config.technology.enabled);
10214 assert!(!config.financial_services.enabled);
10215 assert!(!config.professional_services.enabled);
10216 }
10217
10218 #[test]
10219 fn test_manufacturing_config_defaults() {
10220 let config = ManufacturingConfig::default();
10221 assert!(!config.enabled);
10222 assert_eq!(config.bom_depth, 4);
10223 assert!(!config.just_in_time);
10224 assert_eq!(config.supplier_tiers, 2);
10225 assert_eq!(config.target_yield_rate, 0.97);
10226 assert_eq!(config.scrap_alert_threshold, 0.03);
10227 }
10228
10229 #[test]
10230 fn test_retail_config_defaults() {
10231 let config = RetailConfig::default();
10232 assert!(!config.enabled);
10233 assert_eq!(config.avg_daily_transactions, 500);
10234 assert!(config.loss_prevention);
10235 assert_eq!(config.shrinkage_rate, 0.015);
10236 }
10237
10238 #[test]
10239 fn test_healthcare_config_defaults() {
10240 let config = HealthcareConfig::default();
10241 assert!(!config.enabled);
10242 assert_eq!(config.facility_type, "hospital");
10243 assert_eq!(config.avg_daily_encounters, 150);
10244 assert!(config.compliance.hipaa);
10245 assert!(config.compliance.stark_law);
10246 assert!(config.coding_systems.icd10);
10247 assert!(config.coding_systems.cpt);
10248 }
10249
10250 #[test]
10251 fn test_technology_config_defaults() {
10252 let config = TechnologyConfig::default();
10253 assert!(!config.enabled);
10254 assert_eq!(config.revenue_model, "saas");
10255 assert_eq!(config.subscription_revenue_pct, 0.60);
10256 assert!(config.rd_capitalization.enabled);
10257 }
10258
10259 #[test]
10260 fn test_config_with_industry_specific() {
10261 let yaml = r#"
10262 global:
10263 industry: healthcare
10264 start_date: "2024-01-01"
10265 period_months: 12
10266 companies:
10267 - code: "HOSP"
10268 name: "Test Hospital"
10269 currency: "USD"
10270 country: "US"
10271 annual_transaction_volume: hundred_k
10272 chart_of_accounts:
10273 complexity: medium
10274 output:
10275 output_directory: "./output"
10276 industry_specific:
10277 enabled: true
10278 healthcare:
10279 enabled: true
10280 facility_type: hospital
10281 payer_mix:
10282 medicare: 0.45
10283 medicaid: 0.15
10284 commercial: 0.35
10285 self_pay: 0.05
10286 coding_systems:
10287 icd10: true
10288 cpt: true
10289 drg: true
10290 compliance:
10291 hipaa: true
10292 stark_law: true
10293 anomaly_rates:
10294 upcoding: 0.03
10295 unbundling: 0.02
10296 "#;
10297
10298 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10299 assert!(config.industry_specific.enabled);
10300 assert!(config.industry_specific.healthcare.enabled);
10301 assert_eq!(
10302 config.industry_specific.healthcare.facility_type,
10303 "hospital"
10304 );
10305 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10306 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10307 assert!(config.industry_specific.healthcare.coding_systems.icd10);
10308 assert!(config.industry_specific.healthcare.compliance.hipaa);
10309 assert_eq!(
10310 config.industry_specific.healthcare.anomaly_rates.upcoding,
10311 0.03
10312 );
10313 }
10314
10315 #[test]
10316 fn test_config_with_manufacturing_specific() {
10317 let yaml = r#"
10318 global:
10319 industry: manufacturing
10320 start_date: "2024-01-01"
10321 period_months: 12
10322 companies:
10323 - code: "MFG"
10324 name: "Test Manufacturing"
10325 currency: "USD"
10326 country: "US"
10327 annual_transaction_volume: hundred_k
10328 chart_of_accounts:
10329 complexity: medium
10330 output:
10331 output_directory: "./output"
10332 industry_specific:
10333 enabled: true
10334 manufacturing:
10335 enabled: true
10336 bom_depth: 5
10337 just_in_time: true
10338 supplier_tiers: 3
10339 target_yield_rate: 0.98
10340 anomaly_rates:
10341 yield_manipulation: 0.02
10342 phantom_production: 0.01
10343 "#;
10344
10345 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10346 assert!(config.industry_specific.enabled);
10347 assert!(config.industry_specific.manufacturing.enabled);
10348 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10349 assert!(config.industry_specific.manufacturing.just_in_time);
10350 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10351 assert_eq!(
10352 config.industry_specific.manufacturing.target_yield_rate,
10353 0.98
10354 );
10355 assert_eq!(
10356 config
10357 .industry_specific
10358 .manufacturing
10359 .anomaly_rates
10360 .yield_manipulation,
10361 0.02
10362 );
10363 }
10364}