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
252fn default_hypergraph_max_nodes() -> usize {
253 50_000
254}
255
256fn default_aggregation_strategy() -> String {
257 "pool_by_counterparty".to_string()
258}
259
260fn default_hypergraph_subdir() -> String {
261 "hypergraph".to_string()
262}
263
264impl Default for HypergraphExportSettings {
265 fn default() -> Self {
266 Self {
267 enabled: false,
268 max_nodes: 50_000,
269 aggregation_strategy: "pool_by_counterparty".to_string(),
270 governance_layer: GovernanceLayerSettings::default(),
271 process_layer: ProcessLayerSettings::default(),
272 accounting_layer: AccountingLayerSettings::default(),
273 cross_layer: CrossLayerSettings::default(),
274 output_subdirectory: "hypergraph".to_string(),
275 }
276 }
277}
278
279#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct GovernanceLayerSettings {
282 #[serde(default = "default_true")]
284 pub include_coso: bool,
285 #[serde(default = "default_true")]
287 pub include_controls: bool,
288 #[serde(default = "default_true")]
290 pub include_sox: bool,
291 #[serde(default = "default_true")]
293 pub include_vendors: bool,
294 #[serde(default = "default_true")]
296 pub include_customers: bool,
297 #[serde(default = "default_true")]
299 pub include_employees: bool,
300}
301
302impl Default for GovernanceLayerSettings {
303 fn default() -> Self {
304 Self {
305 include_coso: true,
306 include_controls: true,
307 include_sox: true,
308 include_vendors: true,
309 include_customers: true,
310 include_employees: true,
311 }
312 }
313}
314
315#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct ProcessLayerSettings {
318 #[serde(default = "default_true")]
320 pub include_p2p: bool,
321 #[serde(default = "default_true")]
323 pub include_o2c: bool,
324 #[serde(default = "default_true")]
326 pub events_as_hyperedges: bool,
327 #[serde(default = "default_docs_per_counterparty_threshold")]
329 pub docs_per_counterparty_threshold: usize,
330}
331
332fn default_docs_per_counterparty_threshold() -> usize {
333 20
334}
335
336impl Default for ProcessLayerSettings {
337 fn default() -> Self {
338 Self {
339 include_p2p: true,
340 include_o2c: true,
341 events_as_hyperedges: true,
342 docs_per_counterparty_threshold: 20,
343 }
344 }
345}
346
347#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct AccountingLayerSettings {
350 #[serde(default = "default_true")]
352 pub include_accounts: bool,
353 #[serde(default = "default_true")]
355 pub je_as_hyperedges: bool,
356}
357
358impl Default for AccountingLayerSettings {
359 fn default() -> Self {
360 Self {
361 include_accounts: true,
362 je_as_hyperedges: true,
363 }
364 }
365}
366
367#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct CrossLayerSettings {
370 #[serde(default = "default_true")]
372 pub enabled: bool,
373}
374
375impl Default for CrossLayerSettings {
376 fn default() -> Self {
377 Self { enabled: true }
378 }
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct GraphTypeConfig {
384 #[serde(default = "default_graph_name")]
386 pub name: String,
387
388 #[serde(default)]
390 pub aggregate_edges: bool,
391
392 #[serde(default)]
394 pub min_edge_weight: f64,
395
396 #[serde(default)]
398 pub include_document_nodes: bool,
399}
400
401fn default_graph_name() -> String {
402 "accounting_network".to_string()
403}
404
405impl Default for GraphTypeConfig {
406 fn default() -> Self {
407 Self {
408 name: "accounting_network".to_string(),
409 aggregate_edges: false,
410 min_edge_weight: 0.0,
411 include_document_nodes: false,
412 }
413 }
414}
415
416#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
418#[serde(rename_all = "snake_case")]
419pub enum GraphExportFormat {
420 PytorchGeometric,
422 Neo4j,
424 Dgl,
426 RustGraph,
428 RustGraphHypergraph,
430}
431
432#[derive(Debug, Clone, Default, Serialize, Deserialize)]
436pub struct ScenarioConfig {
437 #[serde(default)]
440 pub tags: Vec<String>,
441
442 #[serde(default)]
447 pub profile: Option<String>,
448
449 #[serde(default)]
451 pub description: Option<String>,
452
453 #[serde(default)]
455 pub ml_training: bool,
456
457 #[serde(default)]
460 pub target_anomaly_ratio: Option<f64>,
461
462 #[serde(default)]
464 pub metadata: std::collections::HashMap<String, String>,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct TemporalDriftConfig {
473 #[serde(default)]
475 pub enabled: bool,
476
477 #[serde(default = "default_amount_drift")]
480 pub amount_mean_drift: f64,
481
482 #[serde(default)]
485 pub amount_variance_drift: f64,
486
487 #[serde(default)]
490 pub anomaly_rate_drift: f64,
491
492 #[serde(default = "default_concept_drift")]
495 pub concept_drift_rate: f64,
496
497 #[serde(default)]
499 pub sudden_drift_probability: f64,
500
501 #[serde(default = "default_sudden_drift_magnitude")]
503 pub sudden_drift_magnitude: f64,
504
505 #[serde(default)]
507 pub seasonal_drift: bool,
508
509 #[serde(default)]
511 pub drift_start_period: u32,
512
513 #[serde(default = "default_drift_type")]
515 pub drift_type: DriftType,
516}
517
518fn default_amount_drift() -> f64 {
519 0.02
520}
521
522fn default_concept_drift() -> f64 {
523 0.01
524}
525
526fn default_sudden_drift_magnitude() -> f64 {
527 2.0
528}
529
530fn default_drift_type() -> DriftType {
531 DriftType::Gradual
532}
533
534impl Default for TemporalDriftConfig {
535 fn default() -> Self {
536 Self {
537 enabled: false,
538 amount_mean_drift: 0.02,
539 amount_variance_drift: 0.0,
540 anomaly_rate_drift: 0.0,
541 concept_drift_rate: 0.01,
542 sudden_drift_probability: 0.0,
543 sudden_drift_magnitude: 2.0,
544 seasonal_drift: false,
545 drift_start_period: 0,
546 drift_type: DriftType::Gradual,
547 }
548 }
549}
550
551impl TemporalDriftConfig {
552 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
554 datasynth_core::distributions::DriftConfig {
555 enabled: self.enabled,
556 amount_mean_drift: self.amount_mean_drift,
557 amount_variance_drift: self.amount_variance_drift,
558 anomaly_rate_drift: self.anomaly_rate_drift,
559 concept_drift_rate: self.concept_drift_rate,
560 sudden_drift_probability: self.sudden_drift_probability,
561 sudden_drift_magnitude: self.sudden_drift_magnitude,
562 seasonal_drift: self.seasonal_drift,
563 drift_start_period: self.drift_start_period,
564 drift_type: match self.drift_type {
565 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
566 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
567 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
568 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
569 },
570 regime_changes: Vec::new(),
571 economic_cycle: Default::default(),
572 parameter_drifts: Vec::new(),
573 }
574 }
575}
576
577#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
579#[serde(rename_all = "snake_case")]
580pub enum DriftType {
581 #[default]
583 Gradual,
584 Sudden,
586 Recurring,
588 Mixed,
590}
591
592#[derive(Debug, Clone, Serialize, Deserialize)]
598pub struct StreamingSchemaConfig {
599 #[serde(default)]
601 pub enabled: bool,
602 #[serde(default = "default_buffer_size")]
604 pub buffer_size: usize,
605 #[serde(default = "default_true")]
607 pub enable_progress: bool,
608 #[serde(default = "default_progress_interval")]
610 pub progress_interval: u64,
611 #[serde(default)]
613 pub backpressure: BackpressureSchemaStrategy,
614}
615
616fn default_buffer_size() -> usize {
617 1000
618}
619
620fn default_progress_interval() -> u64 {
621 100
622}
623
624impl Default for StreamingSchemaConfig {
625 fn default() -> Self {
626 Self {
627 enabled: false,
628 buffer_size: 1000,
629 enable_progress: true,
630 progress_interval: 100,
631 backpressure: BackpressureSchemaStrategy::Block,
632 }
633 }
634}
635
636#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
638#[serde(rename_all = "snake_case")]
639pub enum BackpressureSchemaStrategy {
640 #[default]
642 Block,
643 DropOldest,
645 DropNewest,
647 Buffer,
649}
650
651#[derive(Debug, Clone, Serialize, Deserialize)]
657pub struct RateLimitSchemaConfig {
658 #[serde(default)]
660 pub enabled: bool,
661 #[serde(default = "default_entities_per_second")]
663 pub entities_per_second: f64,
664 #[serde(default = "default_burst_size")]
666 pub burst_size: u32,
667 #[serde(default)]
669 pub backpressure: RateLimitBackpressureSchema,
670}
671
672fn default_entities_per_second() -> f64 {
673 1000.0
674}
675
676fn default_burst_size() -> u32 {
677 100
678}
679
680impl Default for RateLimitSchemaConfig {
681 fn default() -> Self {
682 Self {
683 enabled: false,
684 entities_per_second: 1000.0,
685 burst_size: 100,
686 backpressure: RateLimitBackpressureSchema::Block,
687 }
688 }
689}
690
691#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
693#[serde(rename_all = "snake_case")]
694pub enum RateLimitBackpressureSchema {
695 #[default]
697 Block,
698 Drop,
700 Buffer,
702}
703
704#[derive(Debug, Clone, Serialize, Deserialize)]
710pub struct TemporalAttributeSchemaConfig {
711 #[serde(default)]
713 pub enabled: bool,
714 #[serde(default)]
716 pub valid_time: ValidTimeSchemaConfig,
717 #[serde(default)]
719 pub transaction_time: TransactionTimeSchemaConfig,
720 #[serde(default)]
722 pub generate_version_chains: bool,
723 #[serde(default = "default_avg_versions")]
725 pub avg_versions_per_entity: f64,
726}
727
728fn default_avg_versions() -> f64 {
729 1.5
730}
731
732impl Default for TemporalAttributeSchemaConfig {
733 fn default() -> Self {
734 Self {
735 enabled: false,
736 valid_time: ValidTimeSchemaConfig::default(),
737 transaction_time: TransactionTimeSchemaConfig::default(),
738 generate_version_chains: false,
739 avg_versions_per_entity: 1.5,
740 }
741 }
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct ValidTimeSchemaConfig {
747 #[serde(default = "default_closed_probability")]
749 pub closed_probability: f64,
750 #[serde(default = "default_avg_validity_days")]
752 pub avg_validity_days: u32,
753 #[serde(default = "default_validity_stddev")]
755 pub validity_stddev_days: u32,
756}
757
758fn default_closed_probability() -> f64 {
759 0.1
760}
761
762fn default_avg_validity_days() -> u32 {
763 365
764}
765
766fn default_validity_stddev() -> u32 {
767 90
768}
769
770impl Default for ValidTimeSchemaConfig {
771 fn default() -> Self {
772 Self {
773 closed_probability: 0.1,
774 avg_validity_days: 365,
775 validity_stddev_days: 90,
776 }
777 }
778}
779
780#[derive(Debug, Clone, Serialize, Deserialize)]
782pub struct TransactionTimeSchemaConfig {
783 #[serde(default)]
785 pub avg_recording_delay_seconds: u32,
786 #[serde(default)]
788 pub allow_backdating: bool,
789 #[serde(default = "default_backdating_probability")]
791 pub backdating_probability: f64,
792 #[serde(default = "default_max_backdate_days")]
794 pub max_backdate_days: u32,
795}
796
797fn default_backdating_probability() -> f64 {
798 0.01
799}
800
801fn default_max_backdate_days() -> u32 {
802 30
803}
804
805impl Default for TransactionTimeSchemaConfig {
806 fn default() -> Self {
807 Self {
808 avg_recording_delay_seconds: 0,
809 allow_backdating: false,
810 backdating_probability: 0.01,
811 max_backdate_days: 30,
812 }
813 }
814}
815
816#[derive(Debug, Clone, Serialize, Deserialize)]
822pub struct RelationshipSchemaConfig {
823 #[serde(default)]
825 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
826 #[serde(default = "default_true")]
828 pub allow_orphans: bool,
829 #[serde(default = "default_orphan_probability")]
831 pub orphan_probability: f64,
832 #[serde(default)]
834 pub allow_circular: bool,
835 #[serde(default = "default_max_circular_depth")]
837 pub max_circular_depth: u32,
838}
839
840fn default_orphan_probability() -> f64 {
841 0.01
842}
843
844fn default_max_circular_depth() -> u32 {
845 3
846}
847
848impl Default for RelationshipSchemaConfig {
849 fn default() -> Self {
850 Self {
851 relationship_types: Vec::new(),
852 allow_orphans: true,
853 orphan_probability: 0.01,
854 allow_circular: false,
855 max_circular_depth: 3,
856 }
857 }
858}
859
860#[derive(Debug, Clone, Serialize, Deserialize)]
862pub struct RelationshipTypeSchemaConfig {
863 pub name: String,
865 pub source_type: String,
867 pub target_type: String,
869 #[serde(default)]
871 pub cardinality: CardinalitySchemaRule,
872 #[serde(default = "default_relationship_weight")]
874 pub weight: f64,
875 #[serde(default)]
877 pub required: bool,
878 #[serde(default = "default_true")]
880 pub directed: bool,
881}
882
883fn default_relationship_weight() -> f64 {
884 1.0
885}
886
887impl Default for RelationshipTypeSchemaConfig {
888 fn default() -> Self {
889 Self {
890 name: String::new(),
891 source_type: String::new(),
892 target_type: String::new(),
893 cardinality: CardinalitySchemaRule::default(),
894 weight: 1.0,
895 required: false,
896 directed: true,
897 }
898 }
899}
900
901#[derive(Debug, Clone, Serialize, Deserialize)]
903#[serde(rename_all = "snake_case")]
904pub enum CardinalitySchemaRule {
905 OneToOne,
907 OneToMany {
909 min: u32,
911 max: u32,
913 },
914 ManyToOne {
916 min: u32,
918 max: u32,
920 },
921 ManyToMany {
923 min_per_source: u32,
925 max_per_source: u32,
927 },
928}
929
930impl Default for CardinalitySchemaRule {
931 fn default() -> Self {
932 Self::OneToMany { min: 1, max: 5 }
933 }
934}
935
936#[derive(Debug, Clone, Serialize, Deserialize)]
938pub struct GlobalConfig {
939 pub seed: Option<u64>,
941 pub industry: IndustrySector,
943 pub start_date: String,
945 pub period_months: u32,
947 #[serde(default = "default_currency")]
949 pub group_currency: String,
950 #[serde(default = "default_true")]
952 pub parallel: bool,
953 #[serde(default)]
955 pub worker_threads: usize,
956 #[serde(default)]
958 pub memory_limit_mb: usize,
959}
960
961fn default_currency() -> String {
962 "USD".to_string()
963}
964fn default_true() -> bool {
965 true
966}
967
968#[derive(Debug, Clone, Serialize, Deserialize)]
970pub struct CompanyConfig {
971 pub code: String,
973 pub name: String,
975 pub currency: String,
977 pub country: String,
979 #[serde(default = "default_fiscal_variant")]
981 pub fiscal_year_variant: String,
982 pub annual_transaction_volume: TransactionVolume,
984 #[serde(default = "default_weight")]
986 pub volume_weight: f64,
987}
988
989fn default_fiscal_variant() -> String {
990 "K4".to_string()
991}
992fn default_weight() -> f64 {
993 1.0
994}
995
996#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
998#[serde(rename_all = "snake_case")]
999pub enum TransactionVolume {
1000 TenK,
1002 HundredK,
1004 OneM,
1006 TenM,
1008 HundredM,
1010 Custom(u64),
1012}
1013
1014impl TransactionVolume {
1015 pub fn count(&self) -> u64 {
1017 match self {
1018 Self::TenK => 10_000,
1019 Self::HundredK => 100_000,
1020 Self::OneM => 1_000_000,
1021 Self::TenM => 10_000_000,
1022 Self::HundredM => 100_000_000,
1023 Self::Custom(n) => *n,
1024 }
1025 }
1026}
1027
1028#[derive(Debug, Clone, Serialize, Deserialize)]
1030pub struct ChartOfAccountsConfig {
1031 pub complexity: CoAComplexity,
1033 #[serde(default = "default_true")]
1035 pub industry_specific: bool,
1036 pub custom_accounts: Option<PathBuf>,
1038 #[serde(default = "default_min_depth")]
1040 pub min_hierarchy_depth: u8,
1041 #[serde(default = "default_max_depth")]
1043 pub max_hierarchy_depth: u8,
1044}
1045
1046fn default_min_depth() -> u8 {
1047 2
1048}
1049fn default_max_depth() -> u8 {
1050 5
1051}
1052
1053impl Default for ChartOfAccountsConfig {
1054 fn default() -> Self {
1055 Self {
1056 complexity: CoAComplexity::Small,
1057 industry_specific: true,
1058 custom_accounts: None,
1059 min_hierarchy_depth: default_min_depth(),
1060 max_hierarchy_depth: default_max_depth(),
1061 }
1062 }
1063}
1064
1065#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1067pub struct TransactionConfig {
1068 #[serde(default)]
1070 pub line_item_distribution: LineItemDistributionConfig,
1071 #[serde(default)]
1073 pub debit_credit_distribution: DebitCreditDistributionConfig,
1074 #[serde(default)]
1076 pub even_odd_distribution: EvenOddDistributionConfig,
1077 #[serde(default)]
1079 pub source_distribution: SourceDistribution,
1080 #[serde(default)]
1082 pub seasonality: SeasonalityConfig,
1083 #[serde(default)]
1085 pub amounts: AmountDistributionConfig,
1086 #[serde(default)]
1088 pub benford: BenfordConfig,
1089}
1090
1091#[derive(Debug, Clone, Serialize, Deserialize)]
1093pub struct BenfordConfig {
1094 #[serde(default = "default_true")]
1096 pub enabled: bool,
1097 #[serde(default = "default_benford_tolerance")]
1099 pub tolerance: f64,
1100 #[serde(default)]
1102 pub exempt_sources: Vec<BenfordExemption>,
1103}
1104
1105fn default_benford_tolerance() -> f64 {
1106 0.05
1107}
1108
1109impl Default for BenfordConfig {
1110 fn default() -> Self {
1111 Self {
1112 enabled: true,
1113 tolerance: default_benford_tolerance(),
1114 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1115 }
1116 }
1117}
1118
1119#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1121#[serde(rename_all = "snake_case")]
1122pub enum BenfordExemption {
1123 Recurring,
1125 Payroll,
1127 FixedFees,
1129 RoundAmounts,
1131}
1132
1133#[derive(Debug, Clone, Serialize, Deserialize)]
1135pub struct SourceDistribution {
1136 pub manual: f64,
1138 pub automated: f64,
1140 pub recurring: f64,
1142 pub adjustment: f64,
1144}
1145
1146impl Default for SourceDistribution {
1147 fn default() -> Self {
1148 Self {
1149 manual: 0.20,
1150 automated: 0.70,
1151 recurring: 0.07,
1152 adjustment: 0.03,
1153 }
1154 }
1155}
1156
1157#[derive(Debug, Clone, Serialize, Deserialize)]
1159pub struct OutputConfig {
1160 #[serde(default)]
1162 pub mode: OutputMode,
1163 pub output_directory: PathBuf,
1165 #[serde(default = "default_formats")]
1167 pub formats: Vec<FileFormat>,
1168 #[serde(default)]
1170 pub compression: CompressionConfig,
1171 #[serde(default = "default_batch_size")]
1173 pub batch_size: usize,
1174 #[serde(default = "default_true")]
1176 pub include_acdoca: bool,
1177 #[serde(default)]
1179 pub include_bseg: bool,
1180 #[serde(default = "default_true")]
1182 pub partition_by_period: bool,
1183 #[serde(default)]
1185 pub partition_by_company: bool,
1186}
1187
1188fn default_formats() -> Vec<FileFormat> {
1189 vec![FileFormat::Parquet]
1190}
1191fn default_batch_size() -> usize {
1192 100_000
1193}
1194
1195impl Default for OutputConfig {
1196 fn default() -> Self {
1197 Self {
1198 mode: OutputMode::FlatFile,
1199 output_directory: PathBuf::from("./output"),
1200 formats: default_formats(),
1201 compression: CompressionConfig::default(),
1202 batch_size: default_batch_size(),
1203 include_acdoca: true,
1204 include_bseg: false,
1205 partition_by_period: true,
1206 partition_by_company: false,
1207 }
1208 }
1209}
1210
1211#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1213#[serde(rename_all = "snake_case")]
1214pub enum OutputMode {
1215 Streaming,
1217 #[default]
1219 FlatFile,
1220 Both,
1222}
1223
1224#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1226#[serde(rename_all = "snake_case")]
1227pub enum FileFormat {
1228 Csv,
1229 Parquet,
1230 Json,
1231 JsonLines,
1232}
1233
1234#[derive(Debug, Clone, Serialize, Deserialize)]
1236pub struct CompressionConfig {
1237 #[serde(default = "default_true")]
1239 pub enabled: bool,
1240 #[serde(default)]
1242 pub algorithm: CompressionAlgorithm,
1243 #[serde(default = "default_compression_level")]
1245 pub level: u8,
1246}
1247
1248fn default_compression_level() -> u8 {
1249 3
1250}
1251
1252impl Default for CompressionConfig {
1253 fn default() -> Self {
1254 Self {
1255 enabled: true,
1256 algorithm: CompressionAlgorithm::default(),
1257 level: default_compression_level(),
1258 }
1259 }
1260}
1261
1262#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1264#[serde(rename_all = "snake_case")]
1265pub enum CompressionAlgorithm {
1266 Gzip,
1267 #[default]
1268 Zstd,
1269 Lz4,
1270 Snappy,
1271}
1272
1273#[derive(Debug, Clone, Serialize, Deserialize)]
1275pub struct FraudConfig {
1276 #[serde(default)]
1278 pub enabled: bool,
1279 #[serde(default = "default_fraud_rate")]
1281 pub fraud_rate: f64,
1282 #[serde(default)]
1284 pub fraud_type_distribution: FraudTypeDistribution,
1285 #[serde(default)]
1287 pub clustering_enabled: bool,
1288 #[serde(default = "default_clustering_factor")]
1290 pub clustering_factor: f64,
1291 #[serde(default = "default_approval_thresholds")]
1293 pub approval_thresholds: Vec<f64>,
1294}
1295
1296fn default_approval_thresholds() -> Vec<f64> {
1297 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1298}
1299
1300fn default_fraud_rate() -> f64 {
1301 0.005
1302}
1303fn default_clustering_factor() -> f64 {
1304 3.0
1305}
1306
1307impl Default for FraudConfig {
1308 fn default() -> Self {
1309 Self {
1310 enabled: false,
1311 fraud_rate: default_fraud_rate(),
1312 fraud_type_distribution: FraudTypeDistribution::default(),
1313 clustering_enabled: false,
1314 clustering_factor: default_clustering_factor(),
1315 approval_thresholds: default_approval_thresholds(),
1316 }
1317 }
1318}
1319
1320#[derive(Debug, Clone, Serialize, Deserialize)]
1322pub struct FraudTypeDistribution {
1323 pub suspense_account_abuse: f64,
1324 pub fictitious_transaction: f64,
1325 pub revenue_manipulation: f64,
1326 pub expense_capitalization: f64,
1327 pub split_transaction: f64,
1328 pub timing_anomaly: f64,
1329 pub unauthorized_access: f64,
1330 pub duplicate_payment: f64,
1331}
1332
1333impl Default for FraudTypeDistribution {
1334 fn default() -> Self {
1335 Self {
1336 suspense_account_abuse: 0.25,
1337 fictitious_transaction: 0.15,
1338 revenue_manipulation: 0.10,
1339 expense_capitalization: 0.10,
1340 split_transaction: 0.15,
1341 timing_anomaly: 0.10,
1342 unauthorized_access: 0.10,
1343 duplicate_payment: 0.05,
1344 }
1345 }
1346}
1347
1348#[derive(Debug, Clone, Serialize, Deserialize)]
1350pub struct InternalControlsConfig {
1351 #[serde(default)]
1353 pub enabled: bool,
1354 #[serde(default = "default_exception_rate")]
1356 pub exception_rate: f64,
1357 #[serde(default = "default_sod_violation_rate")]
1359 pub sod_violation_rate: f64,
1360 #[serde(default = "default_true")]
1362 pub export_control_master_data: bool,
1363 #[serde(default = "default_sox_materiality_threshold")]
1365 pub sox_materiality_threshold: f64,
1366 #[serde(default = "default_true")]
1368 pub coso_enabled: bool,
1369 #[serde(default)]
1371 pub include_entity_level_controls: bool,
1372 #[serde(default = "default_target_maturity_level")]
1375 pub target_maturity_level: String,
1376}
1377
1378fn default_exception_rate() -> f64 {
1379 0.02
1380}
1381
1382fn default_sod_violation_rate() -> f64 {
1383 0.01
1384}
1385
1386fn default_sox_materiality_threshold() -> f64 {
1387 10000.0
1388}
1389
1390fn default_target_maturity_level() -> String {
1391 "mixed".to_string()
1392}
1393
1394impl Default for InternalControlsConfig {
1395 fn default() -> Self {
1396 Self {
1397 enabled: false,
1398 exception_rate: default_exception_rate(),
1399 sod_violation_rate: default_sod_violation_rate(),
1400 export_control_master_data: true,
1401 sox_materiality_threshold: default_sox_materiality_threshold(),
1402 coso_enabled: true,
1403 include_entity_level_controls: false,
1404 target_maturity_level: default_target_maturity_level(),
1405 }
1406 }
1407}
1408
1409#[derive(Debug, Clone, Serialize, Deserialize)]
1411pub struct BusinessProcessConfig {
1412 #[serde(default = "default_o2c")]
1414 pub o2c_weight: f64,
1415 #[serde(default = "default_p2p")]
1417 pub p2p_weight: f64,
1418 #[serde(default = "default_r2r")]
1420 pub r2r_weight: f64,
1421 #[serde(default = "default_h2r")]
1423 pub h2r_weight: f64,
1424 #[serde(default = "default_a2r")]
1426 pub a2r_weight: f64,
1427}
1428
1429fn default_o2c() -> f64 {
1430 0.35
1431}
1432fn default_p2p() -> f64 {
1433 0.30
1434}
1435fn default_r2r() -> f64 {
1436 0.20
1437}
1438fn default_h2r() -> f64 {
1439 0.10
1440}
1441fn default_a2r() -> f64 {
1442 0.05
1443}
1444
1445impl Default for BusinessProcessConfig {
1446 fn default() -> Self {
1447 Self {
1448 o2c_weight: default_o2c(),
1449 p2p_weight: default_p2p(),
1450 r2r_weight: default_r2r(),
1451 h2r_weight: default_h2r(),
1452 a2r_weight: default_a2r(),
1453 }
1454 }
1455}
1456
1457#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1459pub struct UserPersonaConfig {
1460 #[serde(default)]
1462 pub persona_distribution: PersonaDistribution,
1463 #[serde(default)]
1465 pub users_per_persona: UsersPerPersona,
1466}
1467
1468#[derive(Debug, Clone, Serialize, Deserialize)]
1470pub struct PersonaDistribution {
1471 pub junior_accountant: f64,
1472 pub senior_accountant: f64,
1473 pub controller: f64,
1474 pub manager: f64,
1475 pub automated_system: f64,
1476}
1477
1478impl Default for PersonaDistribution {
1479 fn default() -> Self {
1480 Self {
1481 junior_accountant: 0.15,
1482 senior_accountant: 0.15,
1483 controller: 0.05,
1484 manager: 0.05,
1485 automated_system: 0.60,
1486 }
1487 }
1488}
1489
1490#[derive(Debug, Clone, Serialize, Deserialize)]
1492pub struct UsersPerPersona {
1493 pub junior_accountant: usize,
1494 pub senior_accountant: usize,
1495 pub controller: usize,
1496 pub manager: usize,
1497 pub automated_system: usize,
1498}
1499
1500impl Default for UsersPerPersona {
1501 fn default() -> Self {
1502 Self {
1503 junior_accountant: 10,
1504 senior_accountant: 5,
1505 controller: 2,
1506 manager: 3,
1507 automated_system: 20,
1508 }
1509 }
1510}
1511
1512#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1514pub struct TemplateConfig {
1515 #[serde(default)]
1517 pub names: NameTemplateConfig,
1518 #[serde(default)]
1520 pub descriptions: DescriptionTemplateConfig,
1521 #[serde(default)]
1523 pub references: ReferenceTemplateConfig,
1524}
1525
1526#[derive(Debug, Clone, Serialize, Deserialize)]
1528pub struct NameTemplateConfig {
1529 #[serde(default)]
1531 pub culture_distribution: CultureDistribution,
1532 #[serde(default = "default_email_domain")]
1534 pub email_domain: String,
1535 #[serde(default = "default_true")]
1537 pub generate_realistic_names: bool,
1538}
1539
1540fn default_email_domain() -> String {
1541 "company.com".to_string()
1542}
1543
1544impl Default for NameTemplateConfig {
1545 fn default() -> Self {
1546 Self {
1547 culture_distribution: CultureDistribution::default(),
1548 email_domain: default_email_domain(),
1549 generate_realistic_names: true,
1550 }
1551 }
1552}
1553
1554#[derive(Debug, Clone, Serialize, Deserialize)]
1556pub struct CultureDistribution {
1557 pub western_us: f64,
1558 pub hispanic: f64,
1559 pub german: f64,
1560 pub french: f64,
1561 pub chinese: f64,
1562 pub japanese: f64,
1563 pub indian: f64,
1564}
1565
1566impl Default for CultureDistribution {
1567 fn default() -> Self {
1568 Self {
1569 western_us: 0.40,
1570 hispanic: 0.20,
1571 german: 0.10,
1572 french: 0.05,
1573 chinese: 0.10,
1574 japanese: 0.05,
1575 indian: 0.10,
1576 }
1577 }
1578}
1579
1580#[derive(Debug, Clone, Serialize, Deserialize)]
1582pub struct DescriptionTemplateConfig {
1583 #[serde(default = "default_true")]
1585 pub generate_header_text: bool,
1586 #[serde(default = "default_true")]
1588 pub generate_line_text: bool,
1589}
1590
1591impl Default for DescriptionTemplateConfig {
1592 fn default() -> Self {
1593 Self {
1594 generate_header_text: true,
1595 generate_line_text: true,
1596 }
1597 }
1598}
1599
1600#[derive(Debug, Clone, Serialize, Deserialize)]
1602pub struct ReferenceTemplateConfig {
1603 #[serde(default = "default_true")]
1605 pub generate_references: bool,
1606 #[serde(default = "default_invoice_prefix")]
1608 pub invoice_prefix: String,
1609 #[serde(default = "default_po_prefix")]
1611 pub po_prefix: String,
1612 #[serde(default = "default_so_prefix")]
1614 pub so_prefix: String,
1615}
1616
1617fn default_invoice_prefix() -> String {
1618 "INV".to_string()
1619}
1620fn default_po_prefix() -> String {
1621 "PO".to_string()
1622}
1623fn default_so_prefix() -> String {
1624 "SO".to_string()
1625}
1626
1627impl Default for ReferenceTemplateConfig {
1628 fn default() -> Self {
1629 Self {
1630 generate_references: true,
1631 invoice_prefix: default_invoice_prefix(),
1632 po_prefix: default_po_prefix(),
1633 so_prefix: default_so_prefix(),
1634 }
1635 }
1636}
1637
1638#[derive(Debug, Clone, Serialize, Deserialize)]
1640pub struct ApprovalConfig {
1641 #[serde(default)]
1643 pub enabled: bool,
1644 #[serde(default = "default_auto_approve_threshold")]
1646 pub auto_approve_threshold: f64,
1647 #[serde(default = "default_rejection_rate")]
1649 pub rejection_rate: f64,
1650 #[serde(default = "default_revision_rate")]
1652 pub revision_rate: f64,
1653 #[serde(default = "default_approval_delay_hours")]
1655 pub average_approval_delay_hours: f64,
1656 #[serde(default)]
1658 pub thresholds: Vec<ApprovalThresholdConfig>,
1659}
1660
1661fn default_auto_approve_threshold() -> f64 {
1662 1000.0
1663}
1664fn default_rejection_rate() -> f64 {
1665 0.02
1666}
1667fn default_revision_rate() -> f64 {
1668 0.05
1669}
1670fn default_approval_delay_hours() -> f64 {
1671 4.0
1672}
1673
1674impl Default for ApprovalConfig {
1675 fn default() -> Self {
1676 Self {
1677 enabled: false,
1678 auto_approve_threshold: default_auto_approve_threshold(),
1679 rejection_rate: default_rejection_rate(),
1680 revision_rate: default_revision_rate(),
1681 average_approval_delay_hours: default_approval_delay_hours(),
1682 thresholds: vec![
1683 ApprovalThresholdConfig {
1684 amount: 1000.0,
1685 level: 1,
1686 roles: vec!["senior_accountant".to_string()],
1687 },
1688 ApprovalThresholdConfig {
1689 amount: 10000.0,
1690 level: 2,
1691 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1692 },
1693 ApprovalThresholdConfig {
1694 amount: 100000.0,
1695 level: 3,
1696 roles: vec![
1697 "senior_accountant".to_string(),
1698 "controller".to_string(),
1699 "manager".to_string(),
1700 ],
1701 },
1702 ApprovalThresholdConfig {
1703 amount: 500000.0,
1704 level: 4,
1705 roles: vec![
1706 "senior_accountant".to_string(),
1707 "controller".to_string(),
1708 "manager".to_string(),
1709 "executive".to_string(),
1710 ],
1711 },
1712 ],
1713 }
1714 }
1715}
1716
1717#[derive(Debug, Clone, Serialize, Deserialize)]
1719pub struct ApprovalThresholdConfig {
1720 pub amount: f64,
1722 pub level: u8,
1724 pub roles: Vec<String>,
1726}
1727
1728#[derive(Debug, Clone, Serialize, Deserialize)]
1730pub struct DepartmentConfig {
1731 #[serde(default)]
1733 pub enabled: bool,
1734 #[serde(default = "default_headcount_multiplier")]
1736 pub headcount_multiplier: f64,
1737 #[serde(default)]
1739 pub custom_departments: Vec<CustomDepartmentConfig>,
1740}
1741
1742fn default_headcount_multiplier() -> f64 {
1743 1.0
1744}
1745
1746impl Default for DepartmentConfig {
1747 fn default() -> Self {
1748 Self {
1749 enabled: false,
1750 headcount_multiplier: default_headcount_multiplier(),
1751 custom_departments: Vec::new(),
1752 }
1753 }
1754}
1755
1756#[derive(Debug, Clone, Serialize, Deserialize)]
1758pub struct CustomDepartmentConfig {
1759 pub code: String,
1761 pub name: String,
1763 #[serde(default)]
1765 pub cost_center: Option<String>,
1766 #[serde(default)]
1768 pub primary_processes: Vec<String>,
1769 #[serde(default)]
1771 pub parent_code: Option<String>,
1772}
1773
1774#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1780pub struct MasterDataConfig {
1781 #[serde(default)]
1783 pub vendors: VendorMasterConfig,
1784 #[serde(default)]
1786 pub customers: CustomerMasterConfig,
1787 #[serde(default)]
1789 pub materials: MaterialMasterConfig,
1790 #[serde(default)]
1792 pub fixed_assets: FixedAssetMasterConfig,
1793 #[serde(default)]
1795 pub employees: EmployeeMasterConfig,
1796 #[serde(default)]
1798 pub cost_centers: CostCenterMasterConfig,
1799}
1800
1801#[derive(Debug, Clone, Serialize, Deserialize)]
1803pub struct VendorMasterConfig {
1804 #[serde(default = "default_vendor_count")]
1806 pub count: usize,
1807 #[serde(default = "default_intercompany_percent")]
1809 pub intercompany_percent: f64,
1810 #[serde(default)]
1812 pub payment_terms_distribution: PaymentTermsDistribution,
1813 #[serde(default)]
1815 pub behavior_distribution: VendorBehaviorDistribution,
1816 #[serde(default = "default_true")]
1818 pub generate_bank_accounts: bool,
1819 #[serde(default = "default_true")]
1821 pub generate_tax_ids: bool,
1822}
1823
1824fn default_vendor_count() -> usize {
1825 500
1826}
1827
1828fn default_intercompany_percent() -> f64 {
1829 0.05
1830}
1831
1832impl Default for VendorMasterConfig {
1833 fn default() -> Self {
1834 Self {
1835 count: default_vendor_count(),
1836 intercompany_percent: default_intercompany_percent(),
1837 payment_terms_distribution: PaymentTermsDistribution::default(),
1838 behavior_distribution: VendorBehaviorDistribution::default(),
1839 generate_bank_accounts: true,
1840 generate_tax_ids: true,
1841 }
1842 }
1843}
1844
1845#[derive(Debug, Clone, Serialize, Deserialize)]
1847pub struct PaymentTermsDistribution {
1848 pub net_30: f64,
1850 pub net_60: f64,
1852 pub net_90: f64,
1854 pub two_ten_net_30: f64,
1856 pub due_on_receipt: f64,
1858 pub end_of_month: f64,
1860}
1861
1862impl Default for PaymentTermsDistribution {
1863 fn default() -> Self {
1864 Self {
1865 net_30: 0.40,
1866 net_60: 0.20,
1867 net_90: 0.10,
1868 two_ten_net_30: 0.15,
1869 due_on_receipt: 0.05,
1870 end_of_month: 0.10,
1871 }
1872 }
1873}
1874
1875#[derive(Debug, Clone, Serialize, Deserialize)]
1877pub struct VendorBehaviorDistribution {
1878 pub reliable: f64,
1880 pub sometimes_late: f64,
1882 pub inconsistent_quality: f64,
1884 pub premium: f64,
1886 pub budget: f64,
1888}
1889
1890impl Default for VendorBehaviorDistribution {
1891 fn default() -> Self {
1892 Self {
1893 reliable: 0.50,
1894 sometimes_late: 0.20,
1895 inconsistent_quality: 0.10,
1896 premium: 0.10,
1897 budget: 0.10,
1898 }
1899 }
1900}
1901
1902#[derive(Debug, Clone, Serialize, Deserialize)]
1904pub struct CustomerMasterConfig {
1905 #[serde(default = "default_customer_count")]
1907 pub count: usize,
1908 #[serde(default = "default_intercompany_percent")]
1910 pub intercompany_percent: f64,
1911 #[serde(default)]
1913 pub credit_rating_distribution: CreditRatingDistribution,
1914 #[serde(default)]
1916 pub payment_behavior_distribution: PaymentBehaviorDistribution,
1917 #[serde(default = "default_true")]
1919 pub generate_credit_limits: bool,
1920}
1921
1922fn default_customer_count() -> usize {
1923 2000
1924}
1925
1926impl Default for CustomerMasterConfig {
1927 fn default() -> Self {
1928 Self {
1929 count: default_customer_count(),
1930 intercompany_percent: default_intercompany_percent(),
1931 credit_rating_distribution: CreditRatingDistribution::default(),
1932 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
1933 generate_credit_limits: true,
1934 }
1935 }
1936}
1937
1938#[derive(Debug, Clone, Serialize, Deserialize)]
1940pub struct CreditRatingDistribution {
1941 pub aaa: f64,
1943 pub aa: f64,
1945 pub a: f64,
1947 pub bbb: f64,
1949 pub bb: f64,
1951 pub b: f64,
1953 pub below_b: f64,
1955}
1956
1957impl Default for CreditRatingDistribution {
1958 fn default() -> Self {
1959 Self {
1960 aaa: 0.05,
1961 aa: 0.10,
1962 a: 0.20,
1963 bbb: 0.30,
1964 bb: 0.20,
1965 b: 0.10,
1966 below_b: 0.05,
1967 }
1968 }
1969}
1970
1971#[derive(Debug, Clone, Serialize, Deserialize)]
1973pub struct PaymentBehaviorDistribution {
1974 pub early_payer: f64,
1976 pub on_time: f64,
1978 pub occasional_late: f64,
1980 pub frequent_late: f64,
1982 pub discount_taker: f64,
1984}
1985
1986impl Default for PaymentBehaviorDistribution {
1987 fn default() -> Self {
1988 Self {
1989 early_payer: 0.10,
1990 on_time: 0.50,
1991 occasional_late: 0.25,
1992 frequent_late: 0.10,
1993 discount_taker: 0.05,
1994 }
1995 }
1996}
1997
1998#[derive(Debug, Clone, Serialize, Deserialize)]
2000pub struct MaterialMasterConfig {
2001 #[serde(default = "default_material_count")]
2003 pub count: usize,
2004 #[serde(default)]
2006 pub type_distribution: MaterialTypeDistribution,
2007 #[serde(default)]
2009 pub valuation_distribution: ValuationMethodDistribution,
2010 #[serde(default = "default_bom_percent")]
2012 pub bom_percent: f64,
2013 #[serde(default = "default_max_bom_depth")]
2015 pub max_bom_depth: u8,
2016}
2017
2018fn default_material_count() -> usize {
2019 5000
2020}
2021
2022fn default_bom_percent() -> f64 {
2023 0.20
2024}
2025
2026fn default_max_bom_depth() -> u8 {
2027 3
2028}
2029
2030impl Default for MaterialMasterConfig {
2031 fn default() -> Self {
2032 Self {
2033 count: default_material_count(),
2034 type_distribution: MaterialTypeDistribution::default(),
2035 valuation_distribution: ValuationMethodDistribution::default(),
2036 bom_percent: default_bom_percent(),
2037 max_bom_depth: default_max_bom_depth(),
2038 }
2039 }
2040}
2041
2042#[derive(Debug, Clone, Serialize, Deserialize)]
2044pub struct MaterialTypeDistribution {
2045 pub raw_material: f64,
2047 pub semi_finished: f64,
2049 pub finished_good: f64,
2051 pub trading_good: f64,
2053 pub operating_supply: f64,
2055 pub service: f64,
2057}
2058
2059impl Default for MaterialTypeDistribution {
2060 fn default() -> Self {
2061 Self {
2062 raw_material: 0.30,
2063 semi_finished: 0.15,
2064 finished_good: 0.25,
2065 trading_good: 0.15,
2066 operating_supply: 0.10,
2067 service: 0.05,
2068 }
2069 }
2070}
2071
2072#[derive(Debug, Clone, Serialize, Deserialize)]
2074pub struct ValuationMethodDistribution {
2075 pub standard_cost: f64,
2077 pub moving_average: f64,
2079 pub fifo: f64,
2081 pub lifo: f64,
2083}
2084
2085impl Default for ValuationMethodDistribution {
2086 fn default() -> Self {
2087 Self {
2088 standard_cost: 0.50,
2089 moving_average: 0.30,
2090 fifo: 0.15,
2091 lifo: 0.05,
2092 }
2093 }
2094}
2095
2096#[derive(Debug, Clone, Serialize, Deserialize)]
2098pub struct FixedAssetMasterConfig {
2099 #[serde(default = "default_asset_count")]
2101 pub count: usize,
2102 #[serde(default)]
2104 pub class_distribution: AssetClassDistribution,
2105 #[serde(default)]
2107 pub depreciation_distribution: DepreciationMethodDistribution,
2108 #[serde(default = "default_fully_depreciated_percent")]
2110 pub fully_depreciated_percent: f64,
2111 #[serde(default = "default_true")]
2113 pub generate_acquisition_history: bool,
2114}
2115
2116fn default_asset_count() -> usize {
2117 800
2118}
2119
2120fn default_fully_depreciated_percent() -> f64 {
2121 0.15
2122}
2123
2124impl Default for FixedAssetMasterConfig {
2125 fn default() -> Self {
2126 Self {
2127 count: default_asset_count(),
2128 class_distribution: AssetClassDistribution::default(),
2129 depreciation_distribution: DepreciationMethodDistribution::default(),
2130 fully_depreciated_percent: default_fully_depreciated_percent(),
2131 generate_acquisition_history: true,
2132 }
2133 }
2134}
2135
2136#[derive(Debug, Clone, Serialize, Deserialize)]
2138pub struct AssetClassDistribution {
2139 pub buildings: f64,
2141 pub machinery: f64,
2143 pub vehicles: f64,
2145 pub it_equipment: f64,
2147 pub furniture: f64,
2149 pub land: f64,
2151 pub leasehold: f64,
2153}
2154
2155impl Default for AssetClassDistribution {
2156 fn default() -> Self {
2157 Self {
2158 buildings: 0.15,
2159 machinery: 0.30,
2160 vehicles: 0.15,
2161 it_equipment: 0.20,
2162 furniture: 0.10,
2163 land: 0.05,
2164 leasehold: 0.05,
2165 }
2166 }
2167}
2168
2169#[derive(Debug, Clone, Serialize, Deserialize)]
2171pub struct DepreciationMethodDistribution {
2172 pub straight_line: f64,
2174 pub declining_balance: f64,
2176 pub double_declining: f64,
2178 pub sum_of_years: f64,
2180 pub units_of_production: f64,
2182}
2183
2184impl Default for DepreciationMethodDistribution {
2185 fn default() -> Self {
2186 Self {
2187 straight_line: 0.60,
2188 declining_balance: 0.20,
2189 double_declining: 0.10,
2190 sum_of_years: 0.05,
2191 units_of_production: 0.05,
2192 }
2193 }
2194}
2195
2196#[derive(Debug, Clone, Serialize, Deserialize)]
2198pub struct EmployeeMasterConfig {
2199 #[serde(default = "default_employee_count")]
2201 pub count: usize,
2202 #[serde(default = "default_true")]
2204 pub generate_hierarchy: bool,
2205 #[serde(default = "default_hierarchy_depth")]
2207 pub max_hierarchy_depth: u8,
2208 #[serde(default = "default_span_of_control")]
2210 pub average_span_of_control: f64,
2211 #[serde(default)]
2213 pub approval_limits: ApprovalLimitDistribution,
2214 #[serde(default)]
2216 pub department_distribution: EmployeeDepartmentDistribution,
2217}
2218
2219fn default_employee_count() -> usize {
2220 1500
2221}
2222
2223fn default_hierarchy_depth() -> u8 {
2224 6
2225}
2226
2227fn default_span_of_control() -> f64 {
2228 5.0
2229}
2230
2231impl Default for EmployeeMasterConfig {
2232 fn default() -> Self {
2233 Self {
2234 count: default_employee_count(),
2235 generate_hierarchy: true,
2236 max_hierarchy_depth: default_hierarchy_depth(),
2237 average_span_of_control: default_span_of_control(),
2238 approval_limits: ApprovalLimitDistribution::default(),
2239 department_distribution: EmployeeDepartmentDistribution::default(),
2240 }
2241 }
2242}
2243
2244#[derive(Debug, Clone, Serialize, Deserialize)]
2246pub struct ApprovalLimitDistribution {
2247 #[serde(default = "default_staff_limit")]
2249 pub staff: f64,
2250 #[serde(default = "default_senior_limit")]
2252 pub senior: f64,
2253 #[serde(default = "default_manager_limit")]
2255 pub manager: f64,
2256 #[serde(default = "default_director_limit")]
2258 pub director: f64,
2259 #[serde(default = "default_vp_limit")]
2261 pub vp: f64,
2262 #[serde(default = "default_executive_limit")]
2264 pub executive: f64,
2265}
2266
2267fn default_staff_limit() -> f64 {
2268 1000.0
2269}
2270fn default_senior_limit() -> f64 {
2271 5000.0
2272}
2273fn default_manager_limit() -> f64 {
2274 25000.0
2275}
2276fn default_director_limit() -> f64 {
2277 100000.0
2278}
2279fn default_vp_limit() -> f64 {
2280 500000.0
2281}
2282fn default_executive_limit() -> f64 {
2283 f64::INFINITY
2284}
2285
2286impl Default for ApprovalLimitDistribution {
2287 fn default() -> Self {
2288 Self {
2289 staff: default_staff_limit(),
2290 senior: default_senior_limit(),
2291 manager: default_manager_limit(),
2292 director: default_director_limit(),
2293 vp: default_vp_limit(),
2294 executive: default_executive_limit(),
2295 }
2296 }
2297}
2298
2299#[derive(Debug, Clone, Serialize, Deserialize)]
2301pub struct EmployeeDepartmentDistribution {
2302 pub finance: f64,
2304 pub procurement: f64,
2306 pub sales: f64,
2308 pub warehouse: f64,
2310 pub it: f64,
2312 pub hr: f64,
2314 pub operations: f64,
2316 pub executive: f64,
2318}
2319
2320impl Default for EmployeeDepartmentDistribution {
2321 fn default() -> Self {
2322 Self {
2323 finance: 0.12,
2324 procurement: 0.10,
2325 sales: 0.25,
2326 warehouse: 0.15,
2327 it: 0.10,
2328 hr: 0.05,
2329 operations: 0.20,
2330 executive: 0.03,
2331 }
2332 }
2333}
2334
2335#[derive(Debug, Clone, Serialize, Deserialize)]
2337pub struct CostCenterMasterConfig {
2338 #[serde(default = "default_cost_center_count")]
2340 pub count: usize,
2341 #[serde(default = "default_true")]
2343 pub generate_hierarchy: bool,
2344 #[serde(default = "default_cc_hierarchy_depth")]
2346 pub max_hierarchy_depth: u8,
2347}
2348
2349fn default_cost_center_count() -> usize {
2350 50
2351}
2352
2353fn default_cc_hierarchy_depth() -> u8 {
2354 3
2355}
2356
2357impl Default for CostCenterMasterConfig {
2358 fn default() -> Self {
2359 Self {
2360 count: default_cost_center_count(),
2361 generate_hierarchy: true,
2362 max_hierarchy_depth: default_cc_hierarchy_depth(),
2363 }
2364 }
2365}
2366
2367#[derive(Debug, Clone, Serialize, Deserialize)]
2373pub struct DocumentFlowConfig {
2374 #[serde(default)]
2376 pub p2p: P2PFlowConfig,
2377 #[serde(default)]
2379 pub o2c: O2CFlowConfig,
2380 #[serde(default = "default_true")]
2382 pub generate_document_references: bool,
2383 #[serde(default)]
2385 pub export_flow_graph: bool,
2386}
2387
2388impl Default for DocumentFlowConfig {
2389 fn default() -> Self {
2390 Self {
2391 p2p: P2PFlowConfig::default(),
2392 o2c: O2CFlowConfig::default(),
2393 generate_document_references: true,
2394 export_flow_graph: false,
2395 }
2396 }
2397}
2398
2399#[derive(Debug, Clone, Serialize, Deserialize)]
2401pub struct P2PFlowConfig {
2402 #[serde(default = "default_true")]
2404 pub enabled: bool,
2405 #[serde(default = "default_three_way_match_rate")]
2407 pub three_way_match_rate: f64,
2408 #[serde(default = "default_partial_delivery_rate")]
2410 pub partial_delivery_rate: f64,
2411 #[serde(default = "default_price_variance_rate")]
2413 pub price_variance_rate: f64,
2414 #[serde(default = "default_max_price_variance")]
2416 pub max_price_variance_percent: f64,
2417 #[serde(default = "default_quantity_variance_rate")]
2419 pub quantity_variance_rate: f64,
2420 #[serde(default = "default_po_to_gr_days")]
2422 pub average_po_to_gr_days: u32,
2423 #[serde(default = "default_gr_to_invoice_days")]
2425 pub average_gr_to_invoice_days: u32,
2426 #[serde(default = "default_invoice_to_payment_days")]
2428 pub average_invoice_to_payment_days: u32,
2429 #[serde(default)]
2431 pub line_count_distribution: DocumentLineCountDistribution,
2432 #[serde(default)]
2434 pub payment_behavior: P2PPaymentBehaviorConfig,
2435}
2436
2437fn default_three_way_match_rate() -> f64 {
2438 0.95
2439}
2440
2441fn default_partial_delivery_rate() -> f64 {
2442 0.15
2443}
2444
2445fn default_price_variance_rate() -> f64 {
2446 0.08
2447}
2448
2449fn default_max_price_variance() -> f64 {
2450 0.05
2451}
2452
2453fn default_quantity_variance_rate() -> f64 {
2454 0.05
2455}
2456
2457fn default_po_to_gr_days() -> u32 {
2458 14
2459}
2460
2461fn default_gr_to_invoice_days() -> u32 {
2462 5
2463}
2464
2465fn default_invoice_to_payment_days() -> u32 {
2466 30
2467}
2468
2469impl Default for P2PFlowConfig {
2470 fn default() -> Self {
2471 Self {
2472 enabled: true,
2473 three_way_match_rate: default_three_way_match_rate(),
2474 partial_delivery_rate: default_partial_delivery_rate(),
2475 price_variance_rate: default_price_variance_rate(),
2476 max_price_variance_percent: default_max_price_variance(),
2477 quantity_variance_rate: default_quantity_variance_rate(),
2478 average_po_to_gr_days: default_po_to_gr_days(),
2479 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2480 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2481 line_count_distribution: DocumentLineCountDistribution::default(),
2482 payment_behavior: P2PPaymentBehaviorConfig::default(),
2483 }
2484 }
2485}
2486
2487#[derive(Debug, Clone, Serialize, Deserialize)]
2493pub struct P2PPaymentBehaviorConfig {
2494 #[serde(default = "default_p2p_late_payment_rate")]
2496 pub late_payment_rate: f64,
2497 #[serde(default)]
2499 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2500 #[serde(default = "default_p2p_partial_payment_rate")]
2502 pub partial_payment_rate: f64,
2503 #[serde(default = "default_p2p_payment_correction_rate")]
2505 pub payment_correction_rate: f64,
2506}
2507
2508fn default_p2p_late_payment_rate() -> f64 {
2509 0.15
2510}
2511
2512fn default_p2p_partial_payment_rate() -> f64 {
2513 0.05
2514}
2515
2516fn default_p2p_payment_correction_rate() -> f64 {
2517 0.02
2518}
2519
2520impl Default for P2PPaymentBehaviorConfig {
2521 fn default() -> Self {
2522 Self {
2523 late_payment_rate: default_p2p_late_payment_rate(),
2524 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2525 partial_payment_rate: default_p2p_partial_payment_rate(),
2526 payment_correction_rate: default_p2p_payment_correction_rate(),
2527 }
2528 }
2529}
2530
2531#[derive(Debug, Clone, Serialize, Deserialize)]
2533pub struct LatePaymentDaysDistribution {
2534 #[serde(default = "default_slightly_late")]
2536 pub slightly_late_1_to_7: f64,
2537 #[serde(default = "default_late_8_14")]
2539 pub late_8_to_14: f64,
2540 #[serde(default = "default_very_late")]
2542 pub very_late_15_to_30: f64,
2543 #[serde(default = "default_severely_late")]
2545 pub severely_late_31_to_60: f64,
2546 #[serde(default = "default_extremely_late")]
2548 pub extremely_late_over_60: f64,
2549}
2550
2551fn default_slightly_late() -> f64 {
2552 0.50
2553}
2554
2555fn default_late_8_14() -> f64 {
2556 0.25
2557}
2558
2559fn default_very_late() -> f64 {
2560 0.15
2561}
2562
2563fn default_severely_late() -> f64 {
2564 0.07
2565}
2566
2567fn default_extremely_late() -> f64 {
2568 0.03
2569}
2570
2571impl Default for LatePaymentDaysDistribution {
2572 fn default() -> Self {
2573 Self {
2574 slightly_late_1_to_7: default_slightly_late(),
2575 late_8_to_14: default_late_8_14(),
2576 very_late_15_to_30: default_very_late(),
2577 severely_late_31_to_60: default_severely_late(),
2578 extremely_late_over_60: default_extremely_late(),
2579 }
2580 }
2581}
2582
2583#[derive(Debug, Clone, Serialize, Deserialize)]
2585pub struct O2CFlowConfig {
2586 #[serde(default = "default_true")]
2588 pub enabled: bool,
2589 #[serde(default = "default_credit_check_failure_rate")]
2591 pub credit_check_failure_rate: f64,
2592 #[serde(default = "default_partial_shipment_rate")]
2594 pub partial_shipment_rate: f64,
2595 #[serde(default = "default_return_rate")]
2597 pub return_rate: f64,
2598 #[serde(default = "default_bad_debt_rate")]
2600 pub bad_debt_rate: f64,
2601 #[serde(default = "default_so_to_delivery_days")]
2603 pub average_so_to_delivery_days: u32,
2604 #[serde(default = "default_delivery_to_invoice_days")]
2606 pub average_delivery_to_invoice_days: u32,
2607 #[serde(default = "default_invoice_to_receipt_days")]
2609 pub average_invoice_to_receipt_days: u32,
2610 #[serde(default)]
2612 pub line_count_distribution: DocumentLineCountDistribution,
2613 #[serde(default)]
2615 pub cash_discount: CashDiscountConfig,
2616 #[serde(default)]
2618 pub payment_behavior: O2CPaymentBehaviorConfig,
2619}
2620
2621fn default_credit_check_failure_rate() -> f64 {
2622 0.02
2623}
2624
2625fn default_partial_shipment_rate() -> f64 {
2626 0.10
2627}
2628
2629fn default_return_rate() -> f64 {
2630 0.03
2631}
2632
2633fn default_bad_debt_rate() -> f64 {
2634 0.01
2635}
2636
2637fn default_so_to_delivery_days() -> u32 {
2638 7
2639}
2640
2641fn default_delivery_to_invoice_days() -> u32 {
2642 1
2643}
2644
2645fn default_invoice_to_receipt_days() -> u32 {
2646 45
2647}
2648
2649impl Default for O2CFlowConfig {
2650 fn default() -> Self {
2651 Self {
2652 enabled: true,
2653 credit_check_failure_rate: default_credit_check_failure_rate(),
2654 partial_shipment_rate: default_partial_shipment_rate(),
2655 return_rate: default_return_rate(),
2656 bad_debt_rate: default_bad_debt_rate(),
2657 average_so_to_delivery_days: default_so_to_delivery_days(),
2658 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2659 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2660 line_count_distribution: DocumentLineCountDistribution::default(),
2661 cash_discount: CashDiscountConfig::default(),
2662 payment_behavior: O2CPaymentBehaviorConfig::default(),
2663 }
2664 }
2665}
2666
2667#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2673pub struct O2CPaymentBehaviorConfig {
2674 #[serde(default)]
2676 pub dunning: DunningConfig,
2677 #[serde(default)]
2679 pub partial_payments: PartialPaymentConfig,
2680 #[serde(default)]
2682 pub short_payments: ShortPaymentConfig,
2683 #[serde(default)]
2685 pub on_account_payments: OnAccountPaymentConfig,
2686 #[serde(default)]
2688 pub payment_corrections: PaymentCorrectionConfig,
2689}
2690
2691#[derive(Debug, Clone, Serialize, Deserialize)]
2693pub struct DunningConfig {
2694 #[serde(default)]
2696 pub enabled: bool,
2697 #[serde(default = "default_dunning_level_1_days")]
2699 pub level_1_days_overdue: u32,
2700 #[serde(default = "default_dunning_level_2_days")]
2702 pub level_2_days_overdue: u32,
2703 #[serde(default = "default_dunning_level_3_days")]
2705 pub level_3_days_overdue: u32,
2706 #[serde(default = "default_collection_days")]
2708 pub collection_days_overdue: u32,
2709 #[serde(default)]
2711 pub payment_after_dunning_rates: DunningPaymentRates,
2712 #[serde(default = "default_dunning_block_rate")]
2714 pub dunning_block_rate: f64,
2715 #[serde(default = "default_dunning_interest_rate")]
2717 pub interest_rate_per_year: f64,
2718 #[serde(default = "default_dunning_charge")]
2720 pub dunning_charge: f64,
2721}
2722
2723fn default_dunning_level_1_days() -> u32 {
2724 14
2725}
2726
2727fn default_dunning_level_2_days() -> u32 {
2728 28
2729}
2730
2731fn default_dunning_level_3_days() -> u32 {
2732 42
2733}
2734
2735fn default_collection_days() -> u32 {
2736 60
2737}
2738
2739fn default_dunning_block_rate() -> f64 {
2740 0.05
2741}
2742
2743fn default_dunning_interest_rate() -> f64 {
2744 0.09
2745}
2746
2747fn default_dunning_charge() -> f64 {
2748 25.0
2749}
2750
2751impl Default for DunningConfig {
2752 fn default() -> Self {
2753 Self {
2754 enabled: false,
2755 level_1_days_overdue: default_dunning_level_1_days(),
2756 level_2_days_overdue: default_dunning_level_2_days(),
2757 level_3_days_overdue: default_dunning_level_3_days(),
2758 collection_days_overdue: default_collection_days(),
2759 payment_after_dunning_rates: DunningPaymentRates::default(),
2760 dunning_block_rate: default_dunning_block_rate(),
2761 interest_rate_per_year: default_dunning_interest_rate(),
2762 dunning_charge: default_dunning_charge(),
2763 }
2764 }
2765}
2766
2767#[derive(Debug, Clone, Serialize, Deserialize)]
2769pub struct DunningPaymentRates {
2770 #[serde(default = "default_after_level_1")]
2772 pub after_level_1: f64,
2773 #[serde(default = "default_after_level_2")]
2775 pub after_level_2: f64,
2776 #[serde(default = "default_after_level_3")]
2778 pub after_level_3: f64,
2779 #[serde(default = "default_during_collection")]
2781 pub during_collection: f64,
2782 #[serde(default = "default_never_pay")]
2784 pub never_pay: f64,
2785}
2786
2787fn default_after_level_1() -> f64 {
2788 0.40
2789}
2790
2791fn default_after_level_2() -> f64 {
2792 0.30
2793}
2794
2795fn default_after_level_3() -> f64 {
2796 0.15
2797}
2798
2799fn default_during_collection() -> f64 {
2800 0.05
2801}
2802
2803fn default_never_pay() -> f64 {
2804 0.10
2805}
2806
2807impl Default for DunningPaymentRates {
2808 fn default() -> Self {
2809 Self {
2810 after_level_1: default_after_level_1(),
2811 after_level_2: default_after_level_2(),
2812 after_level_3: default_after_level_3(),
2813 during_collection: default_during_collection(),
2814 never_pay: default_never_pay(),
2815 }
2816 }
2817}
2818
2819#[derive(Debug, Clone, Serialize, Deserialize)]
2821pub struct PartialPaymentConfig {
2822 #[serde(default = "default_partial_payment_rate")]
2824 pub rate: f64,
2825 #[serde(default)]
2827 pub percentage_distribution: PartialPaymentPercentageDistribution,
2828 #[serde(default = "default_avg_days_until_remainder")]
2830 pub avg_days_until_remainder: u32,
2831}
2832
2833fn default_partial_payment_rate() -> f64 {
2834 0.08
2835}
2836
2837fn default_avg_days_until_remainder() -> u32 {
2838 30
2839}
2840
2841impl Default for PartialPaymentConfig {
2842 fn default() -> Self {
2843 Self {
2844 rate: default_partial_payment_rate(),
2845 percentage_distribution: PartialPaymentPercentageDistribution::default(),
2846 avg_days_until_remainder: default_avg_days_until_remainder(),
2847 }
2848 }
2849}
2850
2851#[derive(Debug, Clone, Serialize, Deserialize)]
2853pub struct PartialPaymentPercentageDistribution {
2854 #[serde(default = "default_partial_25")]
2856 pub pay_25_percent: f64,
2857 #[serde(default = "default_partial_50")]
2859 pub pay_50_percent: f64,
2860 #[serde(default = "default_partial_75")]
2862 pub pay_75_percent: f64,
2863 #[serde(default = "default_partial_random")]
2865 pub pay_random_percent: f64,
2866}
2867
2868fn default_partial_25() -> f64 {
2869 0.15
2870}
2871
2872fn default_partial_50() -> f64 {
2873 0.50
2874}
2875
2876fn default_partial_75() -> f64 {
2877 0.25
2878}
2879
2880fn default_partial_random() -> f64 {
2881 0.10
2882}
2883
2884impl Default for PartialPaymentPercentageDistribution {
2885 fn default() -> Self {
2886 Self {
2887 pay_25_percent: default_partial_25(),
2888 pay_50_percent: default_partial_50(),
2889 pay_75_percent: default_partial_75(),
2890 pay_random_percent: default_partial_random(),
2891 }
2892 }
2893}
2894
2895#[derive(Debug, Clone, Serialize, Deserialize)]
2897pub struct ShortPaymentConfig {
2898 #[serde(default = "default_short_payment_rate")]
2900 pub rate: f64,
2901 #[serde(default)]
2903 pub reason_distribution: ShortPaymentReasonDistribution,
2904 #[serde(default = "default_max_short_percent")]
2906 pub max_short_percent: f64,
2907}
2908
2909fn default_short_payment_rate() -> f64 {
2910 0.03
2911}
2912
2913fn default_max_short_percent() -> f64 {
2914 0.10
2915}
2916
2917impl Default for ShortPaymentConfig {
2918 fn default() -> Self {
2919 Self {
2920 rate: default_short_payment_rate(),
2921 reason_distribution: ShortPaymentReasonDistribution::default(),
2922 max_short_percent: default_max_short_percent(),
2923 }
2924 }
2925}
2926
2927#[derive(Debug, Clone, Serialize, Deserialize)]
2929pub struct ShortPaymentReasonDistribution {
2930 #[serde(default = "default_pricing_dispute")]
2932 pub pricing_dispute: f64,
2933 #[serde(default = "default_quality_issue")]
2935 pub quality_issue: f64,
2936 #[serde(default = "default_quantity_discrepancy")]
2938 pub quantity_discrepancy: f64,
2939 #[serde(default = "default_unauthorized_deduction")]
2941 pub unauthorized_deduction: f64,
2942 #[serde(default = "default_incorrect_discount")]
2944 pub incorrect_discount: f64,
2945}
2946
2947fn default_pricing_dispute() -> f64 {
2948 0.30
2949}
2950
2951fn default_quality_issue() -> f64 {
2952 0.20
2953}
2954
2955fn default_quantity_discrepancy() -> f64 {
2956 0.20
2957}
2958
2959fn default_unauthorized_deduction() -> f64 {
2960 0.15
2961}
2962
2963fn default_incorrect_discount() -> f64 {
2964 0.15
2965}
2966
2967impl Default for ShortPaymentReasonDistribution {
2968 fn default() -> Self {
2969 Self {
2970 pricing_dispute: default_pricing_dispute(),
2971 quality_issue: default_quality_issue(),
2972 quantity_discrepancy: default_quantity_discrepancy(),
2973 unauthorized_deduction: default_unauthorized_deduction(),
2974 incorrect_discount: default_incorrect_discount(),
2975 }
2976 }
2977}
2978
2979#[derive(Debug, Clone, Serialize, Deserialize)]
2981pub struct OnAccountPaymentConfig {
2982 #[serde(default = "default_on_account_rate")]
2984 pub rate: f64,
2985 #[serde(default = "default_avg_days_until_applied")]
2987 pub avg_days_until_applied: u32,
2988}
2989
2990fn default_on_account_rate() -> f64 {
2991 0.02
2992}
2993
2994fn default_avg_days_until_applied() -> u32 {
2995 14
2996}
2997
2998impl Default for OnAccountPaymentConfig {
2999 fn default() -> Self {
3000 Self {
3001 rate: default_on_account_rate(),
3002 avg_days_until_applied: default_avg_days_until_applied(),
3003 }
3004 }
3005}
3006
3007#[derive(Debug, Clone, Serialize, Deserialize)]
3009pub struct PaymentCorrectionConfig {
3010 #[serde(default = "default_payment_correction_rate")]
3012 pub rate: f64,
3013 #[serde(default)]
3015 pub type_distribution: PaymentCorrectionTypeDistribution,
3016}
3017
3018fn default_payment_correction_rate() -> f64 {
3019 0.02
3020}
3021
3022impl Default for PaymentCorrectionConfig {
3023 fn default() -> Self {
3024 Self {
3025 rate: default_payment_correction_rate(),
3026 type_distribution: PaymentCorrectionTypeDistribution::default(),
3027 }
3028 }
3029}
3030
3031#[derive(Debug, Clone, Serialize, Deserialize)]
3033pub struct PaymentCorrectionTypeDistribution {
3034 #[serde(default = "default_nsf_rate")]
3036 pub nsf: f64,
3037 #[serde(default = "default_chargeback_rate")]
3039 pub chargeback: f64,
3040 #[serde(default = "default_wrong_amount_rate")]
3042 pub wrong_amount: f64,
3043 #[serde(default = "default_wrong_customer_rate")]
3045 pub wrong_customer: f64,
3046 #[serde(default = "default_duplicate_payment_rate")]
3048 pub duplicate_payment: f64,
3049}
3050
3051fn default_nsf_rate() -> f64 {
3052 0.30
3053}
3054
3055fn default_chargeback_rate() -> f64 {
3056 0.20
3057}
3058
3059fn default_wrong_amount_rate() -> f64 {
3060 0.20
3061}
3062
3063fn default_wrong_customer_rate() -> f64 {
3064 0.15
3065}
3066
3067fn default_duplicate_payment_rate() -> f64 {
3068 0.15
3069}
3070
3071impl Default for PaymentCorrectionTypeDistribution {
3072 fn default() -> Self {
3073 Self {
3074 nsf: default_nsf_rate(),
3075 chargeback: default_chargeback_rate(),
3076 wrong_amount: default_wrong_amount_rate(),
3077 wrong_customer: default_wrong_customer_rate(),
3078 duplicate_payment: default_duplicate_payment_rate(),
3079 }
3080 }
3081}
3082
3083#[derive(Debug, Clone, Serialize, Deserialize)]
3085pub struct DocumentLineCountDistribution {
3086 #[serde(default = "default_min_lines")]
3088 pub min_lines: u32,
3089 #[serde(default = "default_max_lines")]
3091 pub max_lines: u32,
3092 #[serde(default = "default_mode_lines")]
3094 pub mode_lines: u32,
3095}
3096
3097fn default_min_lines() -> u32 {
3098 1
3099}
3100
3101fn default_max_lines() -> u32 {
3102 20
3103}
3104
3105fn default_mode_lines() -> u32 {
3106 3
3107}
3108
3109impl Default for DocumentLineCountDistribution {
3110 fn default() -> Self {
3111 Self {
3112 min_lines: default_min_lines(),
3113 max_lines: default_max_lines(),
3114 mode_lines: default_mode_lines(),
3115 }
3116 }
3117}
3118
3119#[derive(Debug, Clone, Serialize, Deserialize)]
3121pub struct CashDiscountConfig {
3122 #[serde(default = "default_discount_eligible_rate")]
3124 pub eligible_rate: f64,
3125 #[serde(default = "default_discount_taken_rate")]
3127 pub taken_rate: f64,
3128 #[serde(default = "default_discount_percent")]
3130 pub discount_percent: f64,
3131 #[serde(default = "default_discount_days")]
3133 pub discount_days: u32,
3134}
3135
3136fn default_discount_eligible_rate() -> f64 {
3137 0.30
3138}
3139
3140fn default_discount_taken_rate() -> f64 {
3141 0.60
3142}
3143
3144fn default_discount_percent() -> f64 {
3145 0.02
3146}
3147
3148fn default_discount_days() -> u32 {
3149 10
3150}
3151
3152impl Default for CashDiscountConfig {
3153 fn default() -> Self {
3154 Self {
3155 eligible_rate: default_discount_eligible_rate(),
3156 taken_rate: default_discount_taken_rate(),
3157 discount_percent: default_discount_percent(),
3158 discount_days: default_discount_days(),
3159 }
3160 }
3161}
3162
3163#[derive(Debug, Clone, Serialize, Deserialize)]
3169pub struct IntercompanyConfig {
3170 #[serde(default)]
3172 pub enabled: bool,
3173 #[serde(default = "default_ic_transaction_rate")]
3175 pub ic_transaction_rate: f64,
3176 #[serde(default)]
3178 pub transfer_pricing_method: TransferPricingMethod,
3179 #[serde(default = "default_markup_percent")]
3181 pub markup_percent: f64,
3182 #[serde(default = "default_true")]
3184 pub generate_matched_pairs: bool,
3185 #[serde(default)]
3187 pub transaction_type_distribution: ICTransactionTypeDistribution,
3188 #[serde(default)]
3190 pub generate_eliminations: bool,
3191}
3192
3193fn default_ic_transaction_rate() -> f64 {
3194 0.15
3195}
3196
3197fn default_markup_percent() -> f64 {
3198 0.05
3199}
3200
3201impl Default for IntercompanyConfig {
3202 fn default() -> Self {
3203 Self {
3204 enabled: false,
3205 ic_transaction_rate: default_ic_transaction_rate(),
3206 transfer_pricing_method: TransferPricingMethod::default(),
3207 markup_percent: default_markup_percent(),
3208 generate_matched_pairs: true,
3209 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3210 generate_eliminations: false,
3211 }
3212 }
3213}
3214
3215#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3217#[serde(rename_all = "snake_case")]
3218pub enum TransferPricingMethod {
3219 #[default]
3221 CostPlus,
3222 ComparableUncontrolled,
3224 ResalePrice,
3226 TransactionalNetMargin,
3228 ProfitSplit,
3230}
3231
3232#[derive(Debug, Clone, Serialize, Deserialize)]
3234pub struct ICTransactionTypeDistribution {
3235 pub goods_sale: f64,
3237 pub service_provided: f64,
3239 pub loan: f64,
3241 pub dividend: f64,
3243 pub management_fee: f64,
3245 pub royalty: f64,
3247 pub cost_sharing: f64,
3249}
3250
3251impl Default for ICTransactionTypeDistribution {
3252 fn default() -> Self {
3253 Self {
3254 goods_sale: 0.35,
3255 service_provided: 0.20,
3256 loan: 0.10,
3257 dividend: 0.05,
3258 management_fee: 0.15,
3259 royalty: 0.10,
3260 cost_sharing: 0.05,
3261 }
3262 }
3263}
3264
3265#[derive(Debug, Clone, Serialize, Deserialize)]
3271pub struct BalanceConfig {
3272 #[serde(default)]
3274 pub generate_opening_balances: bool,
3275 #[serde(default = "default_true")]
3277 pub generate_trial_balances: bool,
3278 #[serde(default = "default_gross_margin")]
3280 pub target_gross_margin: f64,
3281 #[serde(default = "default_dso")]
3283 pub target_dso_days: u32,
3284 #[serde(default = "default_dpo")]
3286 pub target_dpo_days: u32,
3287 #[serde(default = "default_current_ratio")]
3289 pub target_current_ratio: f64,
3290 #[serde(default = "default_debt_equity")]
3292 pub target_debt_to_equity: f64,
3293 #[serde(default = "default_true")]
3295 pub validate_balance_equation: bool,
3296 #[serde(default = "default_true")]
3298 pub reconcile_subledgers: bool,
3299}
3300
3301fn default_gross_margin() -> f64 {
3302 0.35
3303}
3304
3305fn default_dso() -> u32 {
3306 45
3307}
3308
3309fn default_dpo() -> u32 {
3310 30
3311}
3312
3313fn default_current_ratio() -> f64 {
3314 1.5
3315}
3316
3317fn default_debt_equity() -> f64 {
3318 0.5
3319}
3320
3321impl Default for BalanceConfig {
3322 fn default() -> Self {
3323 Self {
3324 generate_opening_balances: false,
3325 generate_trial_balances: true,
3326 target_gross_margin: default_gross_margin(),
3327 target_dso_days: default_dso(),
3328 target_dpo_days: default_dpo(),
3329 target_current_ratio: default_current_ratio(),
3330 target_debt_to_equity: default_debt_equity(),
3331 validate_balance_equation: true,
3332 reconcile_subledgers: true,
3333 }
3334 }
3335}
3336
3337#[derive(Debug, Clone, Serialize, Deserialize)]
3346pub struct OcpmConfig {
3347 #[serde(default)]
3349 pub enabled: bool,
3350
3351 #[serde(default = "default_true")]
3353 pub generate_lifecycle_events: bool,
3354
3355 #[serde(default = "default_true")]
3357 pub include_object_relationships: bool,
3358
3359 #[serde(default = "default_true")]
3361 pub compute_variants: bool,
3362
3363 #[serde(default)]
3365 pub max_variants: usize,
3366
3367 #[serde(default)]
3369 pub p2p_process: OcpmProcessConfig,
3370
3371 #[serde(default)]
3373 pub o2c_process: OcpmProcessConfig,
3374
3375 #[serde(default)]
3377 pub output: OcpmOutputConfig,
3378}
3379
3380impl Default for OcpmConfig {
3381 fn default() -> Self {
3382 Self {
3383 enabled: false,
3384 generate_lifecycle_events: true,
3385 include_object_relationships: true,
3386 compute_variants: true,
3387 max_variants: 0,
3388 p2p_process: OcpmProcessConfig::default(),
3389 o2c_process: OcpmProcessConfig::default(),
3390 output: OcpmOutputConfig::default(),
3391 }
3392 }
3393}
3394
3395#[derive(Debug, Clone, Serialize, Deserialize)]
3397pub struct OcpmProcessConfig {
3398 #[serde(default = "default_rework_probability")]
3400 pub rework_probability: f64,
3401
3402 #[serde(default = "default_skip_probability")]
3404 pub skip_step_probability: f64,
3405
3406 #[serde(default = "default_out_of_order_probability")]
3408 pub out_of_order_probability: f64,
3409}
3410
3411fn default_rework_probability() -> f64 {
3412 0.05
3413}
3414
3415fn default_skip_probability() -> f64 {
3416 0.02
3417}
3418
3419fn default_out_of_order_probability() -> f64 {
3420 0.03
3421}
3422
3423impl Default for OcpmProcessConfig {
3424 fn default() -> Self {
3425 Self {
3426 rework_probability: default_rework_probability(),
3427 skip_step_probability: default_skip_probability(),
3428 out_of_order_probability: default_out_of_order_probability(),
3429 }
3430 }
3431}
3432
3433#[derive(Debug, Clone, Serialize, Deserialize)]
3435pub struct OcpmOutputConfig {
3436 #[serde(default = "default_true")]
3438 pub ocel_json: bool,
3439
3440 #[serde(default)]
3442 pub ocel_xml: bool,
3443
3444 #[serde(default)]
3446 pub xes: bool,
3447
3448 #[serde(default = "default_true")]
3450 pub xes_include_lifecycle: bool,
3451
3452 #[serde(default = "default_true")]
3454 pub xes_include_resources: bool,
3455
3456 #[serde(default = "default_true")]
3458 pub flattened_csv: bool,
3459
3460 #[serde(default = "default_true")]
3462 pub event_object_csv: bool,
3463
3464 #[serde(default = "default_true")]
3466 pub object_relationship_csv: bool,
3467
3468 #[serde(default = "default_true")]
3470 pub variants_csv: bool,
3471
3472 #[serde(default)]
3474 pub export_reference_models: bool,
3475}
3476
3477impl Default for OcpmOutputConfig {
3478 fn default() -> Self {
3479 Self {
3480 ocel_json: true,
3481 ocel_xml: false,
3482 xes: false,
3483 xes_include_lifecycle: true,
3484 xes_include_resources: true,
3485 flattened_csv: true,
3486 event_object_csv: true,
3487 object_relationship_csv: true,
3488 variants_csv: true,
3489 export_reference_models: false,
3490 }
3491 }
3492}
3493
3494#[derive(Debug, Clone, Serialize, Deserialize)]
3496pub struct AuditGenerationConfig {
3497 #[serde(default)]
3499 pub enabled: bool,
3500
3501 #[serde(default = "default_true")]
3503 pub generate_workpapers: bool,
3504
3505 #[serde(default)]
3507 pub engagement_types: AuditEngagementTypesConfig,
3508
3509 #[serde(default)]
3511 pub workpapers: WorkpaperConfig,
3512
3513 #[serde(default)]
3515 pub team: AuditTeamConfig,
3516
3517 #[serde(default)]
3519 pub review: ReviewWorkflowConfig,
3520}
3521
3522impl Default for AuditGenerationConfig {
3523 fn default() -> Self {
3524 Self {
3525 enabled: false,
3526 generate_workpapers: true,
3527 engagement_types: AuditEngagementTypesConfig::default(),
3528 workpapers: WorkpaperConfig::default(),
3529 team: AuditTeamConfig::default(),
3530 review: ReviewWorkflowConfig::default(),
3531 }
3532 }
3533}
3534
3535#[derive(Debug, Clone, Serialize, Deserialize)]
3537pub struct AuditEngagementTypesConfig {
3538 #[serde(default = "default_financial_audit_prob")]
3540 pub financial_statement: f64,
3541 #[serde(default = "default_sox_audit_prob")]
3543 pub sox_icfr: f64,
3544 #[serde(default = "default_integrated_audit_prob")]
3546 pub integrated: f64,
3547 #[serde(default = "default_review_prob")]
3549 pub review: f64,
3550 #[serde(default = "default_aup_prob")]
3552 pub agreed_upon_procedures: f64,
3553}
3554
3555fn default_financial_audit_prob() -> f64 {
3556 0.40
3557}
3558fn default_sox_audit_prob() -> f64 {
3559 0.20
3560}
3561fn default_integrated_audit_prob() -> f64 {
3562 0.25
3563}
3564fn default_review_prob() -> f64 {
3565 0.10
3566}
3567fn default_aup_prob() -> f64 {
3568 0.05
3569}
3570
3571impl Default for AuditEngagementTypesConfig {
3572 fn default() -> Self {
3573 Self {
3574 financial_statement: default_financial_audit_prob(),
3575 sox_icfr: default_sox_audit_prob(),
3576 integrated: default_integrated_audit_prob(),
3577 review: default_review_prob(),
3578 agreed_upon_procedures: default_aup_prob(),
3579 }
3580 }
3581}
3582
3583#[derive(Debug, Clone, Serialize, Deserialize)]
3585pub struct WorkpaperConfig {
3586 #[serde(default = "default_workpapers_per_phase")]
3588 pub average_per_phase: usize,
3589
3590 #[serde(default = "default_true")]
3592 pub include_isa_references: bool,
3593
3594 #[serde(default = "default_true")]
3596 pub include_sample_details: bool,
3597
3598 #[serde(default = "default_true")]
3600 pub include_cross_references: bool,
3601
3602 #[serde(default)]
3604 pub sampling: SamplingConfig,
3605}
3606
3607fn default_workpapers_per_phase() -> usize {
3608 5
3609}
3610
3611impl Default for WorkpaperConfig {
3612 fn default() -> Self {
3613 Self {
3614 average_per_phase: default_workpapers_per_phase(),
3615 include_isa_references: true,
3616 include_sample_details: true,
3617 include_cross_references: true,
3618 sampling: SamplingConfig::default(),
3619 }
3620 }
3621}
3622
3623#[derive(Debug, Clone, Serialize, Deserialize)]
3625pub struct SamplingConfig {
3626 #[serde(default = "default_statistical_rate")]
3628 pub statistical_rate: f64,
3629 #[serde(default = "default_judgmental_rate")]
3631 pub judgmental_rate: f64,
3632 #[serde(default = "default_haphazard_rate")]
3634 pub haphazard_rate: f64,
3635 #[serde(default = "default_complete_examination_rate")]
3637 pub complete_examination_rate: f64,
3638}
3639
3640fn default_statistical_rate() -> f64 {
3641 0.40
3642}
3643fn default_judgmental_rate() -> f64 {
3644 0.30
3645}
3646fn default_haphazard_rate() -> f64 {
3647 0.20
3648}
3649fn default_complete_examination_rate() -> f64 {
3650 0.10
3651}
3652
3653impl Default for SamplingConfig {
3654 fn default() -> Self {
3655 Self {
3656 statistical_rate: default_statistical_rate(),
3657 judgmental_rate: default_judgmental_rate(),
3658 haphazard_rate: default_haphazard_rate(),
3659 complete_examination_rate: default_complete_examination_rate(),
3660 }
3661 }
3662}
3663
3664#[derive(Debug, Clone, Serialize, Deserialize)]
3666pub struct AuditTeamConfig {
3667 #[serde(default = "default_min_team_size")]
3669 pub min_team_size: usize,
3670 #[serde(default = "default_max_team_size")]
3672 pub max_team_size: usize,
3673 #[serde(default = "default_specialist_probability")]
3675 pub specialist_probability: f64,
3676}
3677
3678fn default_min_team_size() -> usize {
3679 3
3680}
3681fn default_max_team_size() -> usize {
3682 8
3683}
3684fn default_specialist_probability() -> f64 {
3685 0.30
3686}
3687
3688impl Default for AuditTeamConfig {
3689 fn default() -> Self {
3690 Self {
3691 min_team_size: default_min_team_size(),
3692 max_team_size: default_max_team_size(),
3693 specialist_probability: default_specialist_probability(),
3694 }
3695 }
3696}
3697
3698#[derive(Debug, Clone, Serialize, Deserialize)]
3700pub struct ReviewWorkflowConfig {
3701 #[serde(default = "default_review_delay_days")]
3703 pub average_review_delay_days: u32,
3704 #[serde(default = "default_rework_probability_review")]
3706 pub rework_probability: f64,
3707 #[serde(default = "default_true")]
3709 pub require_partner_signoff: bool,
3710}
3711
3712fn default_review_delay_days() -> u32 {
3713 2
3714}
3715fn default_rework_probability_review() -> f64 {
3716 0.15
3717}
3718
3719impl Default for ReviewWorkflowConfig {
3720 fn default() -> Self {
3721 Self {
3722 average_review_delay_days: default_review_delay_days(),
3723 rework_probability: default_rework_probability_review(),
3724 require_partner_signoff: true,
3725 }
3726 }
3727}
3728
3729#[derive(Debug, Clone, Serialize, Deserialize)]
3735pub struct DataQualitySchemaConfig {
3736 #[serde(default)]
3738 pub enabled: bool,
3739 #[serde(default)]
3741 pub preset: DataQualityPreset,
3742 #[serde(default)]
3744 pub missing_values: MissingValuesSchemaConfig,
3745 #[serde(default)]
3747 pub typos: TypoSchemaConfig,
3748 #[serde(default)]
3750 pub format_variations: FormatVariationSchemaConfig,
3751 #[serde(default)]
3753 pub duplicates: DuplicateSchemaConfig,
3754 #[serde(default)]
3756 pub encoding_issues: EncodingIssueSchemaConfig,
3757 #[serde(default)]
3759 pub generate_labels: bool,
3760 #[serde(default)]
3762 pub sink_profiles: SinkQualityProfiles,
3763}
3764
3765impl Default for DataQualitySchemaConfig {
3766 fn default() -> Self {
3767 Self {
3768 enabled: false,
3769 preset: DataQualityPreset::None,
3770 missing_values: MissingValuesSchemaConfig::default(),
3771 typos: TypoSchemaConfig::default(),
3772 format_variations: FormatVariationSchemaConfig::default(),
3773 duplicates: DuplicateSchemaConfig::default(),
3774 encoding_issues: EncodingIssueSchemaConfig::default(),
3775 generate_labels: true,
3776 sink_profiles: SinkQualityProfiles::default(),
3777 }
3778 }
3779}
3780
3781impl DataQualitySchemaConfig {
3782 pub fn with_preset(preset: DataQualityPreset) -> Self {
3784 let mut config = Self {
3785 preset,
3786 ..Default::default()
3787 };
3788 config.apply_preset();
3789 config
3790 }
3791
3792 pub fn apply_preset(&mut self) {
3795 if !self.preset.overrides_settings() {
3796 return;
3797 }
3798
3799 self.enabled = true;
3800
3801 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3803 self.missing_values.rate = self.preset.missing_rate();
3804
3805 self.typos.enabled = self.preset.typo_rate() > 0.0;
3807 self.typos.char_error_rate = self.preset.typo_rate();
3808
3809 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3811 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3812 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3813 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3814
3815 self.format_variations.enabled = self.preset.format_variations_enabled();
3817
3818 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3820 self.encoding_issues.rate = self.preset.encoding_issue_rate();
3821
3822 if self.preset.ocr_errors_enabled() {
3824 self.typos.type_weights.ocr_errors = 0.3;
3825 }
3826 }
3827
3828 pub fn effective_missing_rate(&self) -> f64 {
3830 if self.preset.overrides_settings() {
3831 self.preset.missing_rate()
3832 } else {
3833 self.missing_values.rate
3834 }
3835 }
3836
3837 pub fn effective_typo_rate(&self) -> f64 {
3839 if self.preset.overrides_settings() {
3840 self.preset.typo_rate()
3841 } else {
3842 self.typos.char_error_rate
3843 }
3844 }
3845
3846 pub fn effective_duplicate_rate(&self) -> f64 {
3848 if self.preset.overrides_settings() {
3849 self.preset.duplicate_rate()
3850 } else {
3851 self.duplicates.exact_duplicate_ratio
3852 + self.duplicates.near_duplicate_ratio
3853 + self.duplicates.fuzzy_duplicate_ratio
3854 }
3855 }
3856
3857 pub fn clean() -> Self {
3859 Self::with_preset(DataQualityPreset::Clean)
3860 }
3861
3862 pub fn noisy() -> Self {
3864 Self::with_preset(DataQualityPreset::Noisy)
3865 }
3866
3867 pub fn legacy() -> Self {
3869 Self::with_preset(DataQualityPreset::Legacy)
3870 }
3871}
3872
3873#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3875#[serde(rename_all = "snake_case")]
3876pub enum DataQualityPreset {
3877 #[default]
3879 None,
3880 Minimal,
3882 Normal,
3884 High,
3886 Custom,
3888
3889 Clean,
3895 Noisy,
3898 Legacy,
3901}
3902
3903impl DataQualityPreset {
3904 pub fn missing_rate(&self) -> f64 {
3906 match self {
3907 DataQualityPreset::None => 0.0,
3908 DataQualityPreset::Minimal => 0.005,
3909 DataQualityPreset::Normal => 0.02,
3910 DataQualityPreset::High => 0.08,
3911 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
3913 DataQualityPreset::Noisy => 0.05,
3914 DataQualityPreset::Legacy => 0.10,
3915 }
3916 }
3917
3918 pub fn typo_rate(&self) -> f64 {
3920 match self {
3921 DataQualityPreset::None => 0.0,
3922 DataQualityPreset::Minimal => 0.0005,
3923 DataQualityPreset::Normal => 0.002,
3924 DataQualityPreset::High => 0.01,
3925 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
3927 DataQualityPreset::Noisy => 0.02,
3928 DataQualityPreset::Legacy => 0.05,
3929 }
3930 }
3931
3932 pub fn duplicate_rate(&self) -> f64 {
3934 match self {
3935 DataQualityPreset::None => 0.0,
3936 DataQualityPreset::Minimal => 0.001,
3937 DataQualityPreset::Normal => 0.005,
3938 DataQualityPreset::High => 0.02,
3939 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
3941 DataQualityPreset::Noisy => 0.01,
3942 DataQualityPreset::Legacy => 0.03,
3943 }
3944 }
3945
3946 pub fn format_variations_enabled(&self) -> bool {
3948 match self {
3949 DataQualityPreset::None | DataQualityPreset::Clean => false,
3950 DataQualityPreset::Minimal => true,
3951 DataQualityPreset::Normal => true,
3952 DataQualityPreset::High => true,
3953 DataQualityPreset::Custom => true,
3954 DataQualityPreset::Noisy => true,
3955 DataQualityPreset::Legacy => true,
3956 }
3957 }
3958
3959 pub fn ocr_errors_enabled(&self) -> bool {
3961 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
3962 }
3963
3964 pub fn encoding_issues_enabled(&self) -> bool {
3966 matches!(
3967 self,
3968 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
3969 )
3970 }
3971
3972 pub fn encoding_issue_rate(&self) -> f64 {
3974 match self {
3975 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
3976 DataQualityPreset::Normal => 0.002,
3977 DataQualityPreset::High => 0.01,
3978 DataQualityPreset::Custom => 0.0,
3979 DataQualityPreset::Noisy => 0.005,
3980 DataQualityPreset::Legacy => 0.02,
3981 }
3982 }
3983
3984 pub fn overrides_settings(&self) -> bool {
3986 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
3987 }
3988
3989 pub fn description(&self) -> &'static str {
3991 match self {
3992 DataQualityPreset::None => "No data quality issues (pristine data)",
3993 DataQualityPreset::Minimal => "Very rare data quality issues",
3994 DataQualityPreset::Normal => "Realistic enterprise data quality",
3995 DataQualityPreset::High => "Messy data for stress testing",
3996 DataQualityPreset::Custom => "Custom settings from configuration",
3997 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
3998 DataQualityPreset::Noisy => "Typical production data with moderate issues",
3999 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4000 }
4001 }
4002}
4003
4004#[derive(Debug, Clone, Serialize, Deserialize)]
4006pub struct MissingValuesSchemaConfig {
4007 #[serde(default)]
4009 pub enabled: bool,
4010 #[serde(default = "default_missing_rate")]
4012 pub rate: f64,
4013 #[serde(default)]
4015 pub strategy: MissingValueStrategy,
4016 #[serde(default)]
4018 pub field_rates: std::collections::HashMap<String, f64>,
4019 #[serde(default)]
4021 pub protected_fields: Vec<String>,
4022}
4023
4024fn default_missing_rate() -> f64 {
4025 0.01
4026}
4027
4028impl Default for MissingValuesSchemaConfig {
4029 fn default() -> Self {
4030 Self {
4031 enabled: false,
4032 rate: default_missing_rate(),
4033 strategy: MissingValueStrategy::Mcar,
4034 field_rates: std::collections::HashMap::new(),
4035 protected_fields: vec![
4036 "document_id".to_string(),
4037 "company_code".to_string(),
4038 "posting_date".to_string(),
4039 ],
4040 }
4041 }
4042}
4043
4044#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4046#[serde(rename_all = "snake_case")]
4047pub enum MissingValueStrategy {
4048 #[default]
4050 Mcar,
4051 Mar,
4053 Mnar,
4055 Systematic,
4057}
4058
4059#[derive(Debug, Clone, Serialize, Deserialize)]
4061pub struct TypoSchemaConfig {
4062 #[serde(default)]
4064 pub enabled: bool,
4065 #[serde(default = "default_typo_rate")]
4067 pub char_error_rate: f64,
4068 #[serde(default)]
4070 pub type_weights: TypoTypeWeights,
4071 #[serde(default)]
4073 pub protected_fields: Vec<String>,
4074}
4075
4076fn default_typo_rate() -> f64 {
4077 0.001
4078}
4079
4080impl Default for TypoSchemaConfig {
4081 fn default() -> Self {
4082 Self {
4083 enabled: false,
4084 char_error_rate: default_typo_rate(),
4085 type_weights: TypoTypeWeights::default(),
4086 protected_fields: vec![
4087 "document_id".to_string(),
4088 "gl_account".to_string(),
4089 "company_code".to_string(),
4090 ],
4091 }
4092 }
4093}
4094
4095#[derive(Debug, Clone, Serialize, Deserialize)]
4097pub struct TypoTypeWeights {
4098 #[serde(default = "default_substitution_weight")]
4100 pub substitution: f64,
4101 #[serde(default = "default_transposition_weight")]
4103 pub transposition: f64,
4104 #[serde(default = "default_insertion_weight")]
4106 pub insertion: f64,
4107 #[serde(default = "default_deletion_weight")]
4109 pub deletion: f64,
4110 #[serde(default = "default_ocr_weight")]
4112 pub ocr_errors: f64,
4113 #[serde(default = "default_homophone_weight")]
4115 pub homophones: f64,
4116}
4117
4118fn default_substitution_weight() -> f64 {
4119 0.35
4120}
4121fn default_transposition_weight() -> f64 {
4122 0.25
4123}
4124fn default_insertion_weight() -> f64 {
4125 0.10
4126}
4127fn default_deletion_weight() -> f64 {
4128 0.15
4129}
4130fn default_ocr_weight() -> f64 {
4131 0.10
4132}
4133fn default_homophone_weight() -> f64 {
4134 0.05
4135}
4136
4137impl Default for TypoTypeWeights {
4138 fn default() -> Self {
4139 Self {
4140 substitution: default_substitution_weight(),
4141 transposition: default_transposition_weight(),
4142 insertion: default_insertion_weight(),
4143 deletion: default_deletion_weight(),
4144 ocr_errors: default_ocr_weight(),
4145 homophones: default_homophone_weight(),
4146 }
4147 }
4148}
4149
4150#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4152pub struct FormatVariationSchemaConfig {
4153 #[serde(default)]
4155 pub enabled: bool,
4156 #[serde(default)]
4158 pub dates: DateFormatVariationConfig,
4159 #[serde(default)]
4161 pub amounts: AmountFormatVariationConfig,
4162 #[serde(default)]
4164 pub identifiers: IdentifierFormatVariationConfig,
4165}
4166
4167#[derive(Debug, Clone, Serialize, Deserialize)]
4169pub struct DateFormatVariationConfig {
4170 #[serde(default)]
4172 pub enabled: bool,
4173 #[serde(default = "default_date_variation_rate")]
4175 pub rate: f64,
4176 #[serde(default = "default_true")]
4178 pub iso_format: bool,
4179 #[serde(default)]
4181 pub us_format: bool,
4182 #[serde(default)]
4184 pub eu_format: bool,
4185 #[serde(default)]
4187 pub long_format: bool,
4188}
4189
4190fn default_date_variation_rate() -> f64 {
4191 0.05
4192}
4193
4194impl Default for DateFormatVariationConfig {
4195 fn default() -> Self {
4196 Self {
4197 enabled: false,
4198 rate: default_date_variation_rate(),
4199 iso_format: true,
4200 us_format: false,
4201 eu_format: false,
4202 long_format: false,
4203 }
4204 }
4205}
4206
4207#[derive(Debug, Clone, Serialize, Deserialize)]
4209pub struct AmountFormatVariationConfig {
4210 #[serde(default)]
4212 pub enabled: bool,
4213 #[serde(default = "default_amount_variation_rate")]
4215 pub rate: f64,
4216 #[serde(default)]
4218 pub us_comma_format: bool,
4219 #[serde(default)]
4221 pub eu_format: bool,
4222 #[serde(default)]
4224 pub currency_prefix: bool,
4225 #[serde(default)]
4227 pub accounting_format: bool,
4228}
4229
4230fn default_amount_variation_rate() -> f64 {
4231 0.02
4232}
4233
4234impl Default for AmountFormatVariationConfig {
4235 fn default() -> Self {
4236 Self {
4237 enabled: false,
4238 rate: default_amount_variation_rate(),
4239 us_comma_format: false,
4240 eu_format: false,
4241 currency_prefix: false,
4242 accounting_format: false,
4243 }
4244 }
4245}
4246
4247#[derive(Debug, Clone, Serialize, Deserialize)]
4249pub struct IdentifierFormatVariationConfig {
4250 #[serde(default)]
4252 pub enabled: bool,
4253 #[serde(default = "default_identifier_variation_rate")]
4255 pub rate: f64,
4256 #[serde(default)]
4258 pub case_variations: bool,
4259 #[serde(default)]
4261 pub padding_variations: bool,
4262 #[serde(default)]
4264 pub separator_variations: bool,
4265}
4266
4267fn default_identifier_variation_rate() -> f64 {
4268 0.02
4269}
4270
4271impl Default for IdentifierFormatVariationConfig {
4272 fn default() -> Self {
4273 Self {
4274 enabled: false,
4275 rate: default_identifier_variation_rate(),
4276 case_variations: false,
4277 padding_variations: false,
4278 separator_variations: false,
4279 }
4280 }
4281}
4282
4283#[derive(Debug, Clone, Serialize, Deserialize)]
4285pub struct DuplicateSchemaConfig {
4286 #[serde(default)]
4288 pub enabled: bool,
4289 #[serde(default = "default_duplicate_rate")]
4291 pub rate: f64,
4292 #[serde(default = "default_exact_duplicate_ratio")]
4294 pub exact_duplicate_ratio: f64,
4295 #[serde(default = "default_near_duplicate_ratio")]
4297 pub near_duplicate_ratio: f64,
4298 #[serde(default = "default_fuzzy_duplicate_ratio")]
4300 pub fuzzy_duplicate_ratio: f64,
4301 #[serde(default = "default_max_date_offset")]
4303 pub max_date_offset_days: u32,
4304 #[serde(default = "default_max_amount_variance")]
4306 pub max_amount_variance: f64,
4307}
4308
4309fn default_duplicate_rate() -> f64 {
4310 0.005
4311}
4312fn default_exact_duplicate_ratio() -> f64 {
4313 0.4
4314}
4315fn default_near_duplicate_ratio() -> f64 {
4316 0.35
4317}
4318fn default_fuzzy_duplicate_ratio() -> f64 {
4319 0.25
4320}
4321fn default_max_date_offset() -> u32 {
4322 3
4323}
4324fn default_max_amount_variance() -> f64 {
4325 0.01
4326}
4327
4328impl Default for DuplicateSchemaConfig {
4329 fn default() -> Self {
4330 Self {
4331 enabled: false,
4332 rate: default_duplicate_rate(),
4333 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4334 near_duplicate_ratio: default_near_duplicate_ratio(),
4335 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4336 max_date_offset_days: default_max_date_offset(),
4337 max_amount_variance: default_max_amount_variance(),
4338 }
4339 }
4340}
4341
4342#[derive(Debug, Clone, Serialize, Deserialize)]
4344pub struct EncodingIssueSchemaConfig {
4345 #[serde(default)]
4347 pub enabled: bool,
4348 #[serde(default = "default_encoding_rate")]
4350 pub rate: f64,
4351 #[serde(default)]
4353 pub mojibake: bool,
4354 #[serde(default)]
4356 pub html_entities: bool,
4357 #[serde(default)]
4359 pub bom_issues: bool,
4360}
4361
4362fn default_encoding_rate() -> f64 {
4363 0.001
4364}
4365
4366impl Default for EncodingIssueSchemaConfig {
4367 fn default() -> Self {
4368 Self {
4369 enabled: false,
4370 rate: default_encoding_rate(),
4371 mojibake: false,
4372 html_entities: false,
4373 bom_issues: false,
4374 }
4375 }
4376}
4377
4378#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4380pub struct SinkQualityProfiles {
4381 #[serde(default)]
4383 pub csv: Option<SinkQualityOverride>,
4384 #[serde(default)]
4386 pub json: Option<SinkQualityOverride>,
4387 #[serde(default)]
4389 pub parquet: Option<SinkQualityOverride>,
4390}
4391
4392#[derive(Debug, Clone, Serialize, Deserialize)]
4394pub struct SinkQualityOverride {
4395 pub enabled: Option<bool>,
4397 pub missing_rate: Option<f64>,
4399 pub typo_rate: Option<f64>,
4401 pub format_variation_rate: Option<f64>,
4403 pub duplicate_rate: Option<f64>,
4405}
4406
4407#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4419pub struct AccountingStandardsConfig {
4420 #[serde(default)]
4422 pub enabled: bool,
4423
4424 #[serde(default)]
4426 pub framework: AccountingFrameworkConfig,
4427
4428 #[serde(default)]
4430 pub revenue_recognition: RevenueRecognitionConfig,
4431
4432 #[serde(default)]
4434 pub leases: LeaseAccountingConfig,
4435
4436 #[serde(default)]
4438 pub fair_value: FairValueConfig,
4439
4440 #[serde(default)]
4442 pub impairment: ImpairmentConfig,
4443
4444 #[serde(default)]
4446 pub generate_differences: bool,
4447}
4448
4449#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4451#[serde(rename_all = "snake_case")]
4452pub enum AccountingFrameworkConfig {
4453 #[default]
4455 UsGaap,
4456 Ifrs,
4458 DualReporting,
4460}
4461
4462#[derive(Debug, Clone, Serialize, Deserialize)]
4464pub struct RevenueRecognitionConfig {
4465 #[serde(default)]
4467 pub enabled: bool,
4468
4469 #[serde(default = "default_true")]
4471 pub generate_contracts: bool,
4472
4473 #[serde(default = "default_avg_obligations")]
4475 pub avg_obligations_per_contract: f64,
4476
4477 #[serde(default = "default_variable_consideration_rate")]
4479 pub variable_consideration_rate: f64,
4480
4481 #[serde(default = "default_over_time_rate")]
4483 pub over_time_recognition_rate: f64,
4484
4485 #[serde(default = "default_contract_count")]
4487 pub contract_count: usize,
4488}
4489
4490fn default_avg_obligations() -> f64 {
4491 2.0
4492}
4493
4494fn default_variable_consideration_rate() -> f64 {
4495 0.15
4496}
4497
4498fn default_over_time_rate() -> f64 {
4499 0.30
4500}
4501
4502fn default_contract_count() -> usize {
4503 100
4504}
4505
4506impl Default for RevenueRecognitionConfig {
4507 fn default() -> Self {
4508 Self {
4509 enabled: false,
4510 generate_contracts: true,
4511 avg_obligations_per_contract: default_avg_obligations(),
4512 variable_consideration_rate: default_variable_consideration_rate(),
4513 over_time_recognition_rate: default_over_time_rate(),
4514 contract_count: default_contract_count(),
4515 }
4516 }
4517}
4518
4519#[derive(Debug, Clone, Serialize, Deserialize)]
4521pub struct LeaseAccountingConfig {
4522 #[serde(default)]
4524 pub enabled: bool,
4525
4526 #[serde(default = "default_lease_count")]
4528 pub lease_count: usize,
4529
4530 #[serde(default = "default_finance_lease_pct")]
4532 pub finance_lease_percent: f64,
4533
4534 #[serde(default = "default_avg_lease_term")]
4536 pub avg_lease_term_months: u32,
4537
4538 #[serde(default = "default_true")]
4540 pub generate_amortization: bool,
4541
4542 #[serde(default = "default_real_estate_pct")]
4544 pub real_estate_percent: f64,
4545}
4546
4547fn default_lease_count() -> usize {
4548 50
4549}
4550
4551fn default_finance_lease_pct() -> f64 {
4552 0.30
4553}
4554
4555fn default_avg_lease_term() -> u32 {
4556 60
4557}
4558
4559fn default_real_estate_pct() -> f64 {
4560 0.40
4561}
4562
4563impl Default for LeaseAccountingConfig {
4564 fn default() -> Self {
4565 Self {
4566 enabled: false,
4567 lease_count: default_lease_count(),
4568 finance_lease_percent: default_finance_lease_pct(),
4569 avg_lease_term_months: default_avg_lease_term(),
4570 generate_amortization: true,
4571 real_estate_percent: default_real_estate_pct(),
4572 }
4573 }
4574}
4575
4576#[derive(Debug, Clone, Serialize, Deserialize)]
4578pub struct FairValueConfig {
4579 #[serde(default)]
4581 pub enabled: bool,
4582
4583 #[serde(default = "default_fv_count")]
4585 pub measurement_count: usize,
4586
4587 #[serde(default = "default_level1_pct")]
4589 pub level1_percent: f64,
4590
4591 #[serde(default = "default_level2_pct")]
4593 pub level2_percent: f64,
4594
4595 #[serde(default = "default_level3_pct")]
4597 pub level3_percent: f64,
4598
4599 #[serde(default)]
4601 pub include_sensitivity_analysis: bool,
4602}
4603
4604fn default_fv_count() -> usize {
4605 25
4606}
4607
4608fn default_level1_pct() -> f64 {
4609 0.40
4610}
4611
4612fn default_level2_pct() -> f64 {
4613 0.35
4614}
4615
4616fn default_level3_pct() -> f64 {
4617 0.25
4618}
4619
4620impl Default for FairValueConfig {
4621 fn default() -> Self {
4622 Self {
4623 enabled: false,
4624 measurement_count: default_fv_count(),
4625 level1_percent: default_level1_pct(),
4626 level2_percent: default_level2_pct(),
4627 level3_percent: default_level3_pct(),
4628 include_sensitivity_analysis: false,
4629 }
4630 }
4631}
4632
4633#[derive(Debug, Clone, Serialize, Deserialize)]
4635pub struct ImpairmentConfig {
4636 #[serde(default)]
4638 pub enabled: bool,
4639
4640 #[serde(default = "default_impairment_count")]
4642 pub test_count: usize,
4643
4644 #[serde(default = "default_impairment_rate")]
4646 pub impairment_rate: f64,
4647
4648 #[serde(default = "default_true")]
4650 pub generate_projections: bool,
4651
4652 #[serde(default)]
4654 pub include_goodwill: bool,
4655}
4656
4657fn default_impairment_count() -> usize {
4658 15
4659}
4660
4661fn default_impairment_rate() -> f64 {
4662 0.10
4663}
4664
4665impl Default for ImpairmentConfig {
4666 fn default() -> Self {
4667 Self {
4668 enabled: false,
4669 test_count: default_impairment_count(),
4670 impairment_rate: default_impairment_rate(),
4671 generate_projections: true,
4672 include_goodwill: false,
4673 }
4674 }
4675}
4676
4677#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4690pub struct AuditStandardsConfig {
4691 #[serde(default)]
4693 pub enabled: bool,
4694
4695 #[serde(default)]
4697 pub isa_compliance: IsaComplianceConfig,
4698
4699 #[serde(default)]
4701 pub analytical_procedures: AnalyticalProceduresConfig,
4702
4703 #[serde(default)]
4705 pub confirmations: ConfirmationsConfig,
4706
4707 #[serde(default)]
4709 pub opinion: AuditOpinionConfig,
4710
4711 #[serde(default)]
4713 pub generate_audit_trail: bool,
4714
4715 #[serde(default)]
4717 pub sox: SoxComplianceConfig,
4718
4719 #[serde(default)]
4721 pub pcaob: PcaobConfig,
4722}
4723
4724#[derive(Debug, Clone, Serialize, Deserialize)]
4726pub struct IsaComplianceConfig {
4727 #[serde(default)]
4729 pub enabled: bool,
4730
4731 #[serde(default = "default_compliance_level")]
4733 pub compliance_level: String,
4734
4735 #[serde(default = "default_true")]
4737 pub generate_isa_mappings: bool,
4738
4739 #[serde(default = "default_true")]
4741 pub generate_coverage_summary: bool,
4742
4743 #[serde(default)]
4745 pub include_pcaob: bool,
4746
4747 #[serde(default = "default_audit_framework")]
4749 pub framework: String,
4750}
4751
4752fn default_compliance_level() -> String {
4753 "standard".to_string()
4754}
4755
4756fn default_audit_framework() -> String {
4757 "isa".to_string()
4758}
4759
4760impl Default for IsaComplianceConfig {
4761 fn default() -> Self {
4762 Self {
4763 enabled: false,
4764 compliance_level: default_compliance_level(),
4765 generate_isa_mappings: true,
4766 generate_coverage_summary: true,
4767 include_pcaob: false,
4768 framework: default_audit_framework(),
4769 }
4770 }
4771}
4772
4773#[derive(Debug, Clone, Serialize, Deserialize)]
4775pub struct AnalyticalProceduresConfig {
4776 #[serde(default)]
4778 pub enabled: bool,
4779
4780 #[serde(default = "default_procedures_per_account")]
4782 pub procedures_per_account: usize,
4783
4784 #[serde(default = "default_variance_probability")]
4786 pub variance_probability: f64,
4787
4788 #[serde(default = "default_true")]
4790 pub generate_investigations: bool,
4791
4792 #[serde(default = "default_true")]
4794 pub include_ratio_analysis: bool,
4795}
4796
4797fn default_procedures_per_account() -> usize {
4798 3
4799}
4800
4801fn default_variance_probability() -> f64 {
4802 0.20
4803}
4804
4805impl Default for AnalyticalProceduresConfig {
4806 fn default() -> Self {
4807 Self {
4808 enabled: false,
4809 procedures_per_account: default_procedures_per_account(),
4810 variance_probability: default_variance_probability(),
4811 generate_investigations: true,
4812 include_ratio_analysis: true,
4813 }
4814 }
4815}
4816
4817#[derive(Debug, Clone, Serialize, Deserialize)]
4819pub struct ConfirmationsConfig {
4820 #[serde(default)]
4822 pub enabled: bool,
4823
4824 #[serde(default = "default_confirmation_count")]
4826 pub confirmation_count: usize,
4827
4828 #[serde(default = "default_positive_response_rate")]
4830 pub positive_response_rate: f64,
4831
4832 #[serde(default = "default_exception_rate_confirm")]
4834 pub exception_rate: f64,
4835
4836 #[serde(default = "default_non_response_rate")]
4838 pub non_response_rate: f64,
4839
4840 #[serde(default = "default_true")]
4842 pub generate_alternative_procedures: bool,
4843}
4844
4845fn default_confirmation_count() -> usize {
4846 50
4847}
4848
4849fn default_positive_response_rate() -> f64 {
4850 0.85
4851}
4852
4853fn default_exception_rate_confirm() -> f64 {
4854 0.10
4855}
4856
4857fn default_non_response_rate() -> f64 {
4858 0.05
4859}
4860
4861impl Default for ConfirmationsConfig {
4862 fn default() -> Self {
4863 Self {
4864 enabled: false,
4865 confirmation_count: default_confirmation_count(),
4866 positive_response_rate: default_positive_response_rate(),
4867 exception_rate: default_exception_rate_confirm(),
4868 non_response_rate: default_non_response_rate(),
4869 generate_alternative_procedures: true,
4870 }
4871 }
4872}
4873
4874#[derive(Debug, Clone, Serialize, Deserialize)]
4876pub struct AuditOpinionConfig {
4877 #[serde(default)]
4879 pub enabled: bool,
4880
4881 #[serde(default = "default_true")]
4883 pub generate_kam: bool,
4884
4885 #[serde(default = "default_kam_count")]
4887 pub average_kam_count: usize,
4888
4889 #[serde(default = "default_modified_opinion_rate")]
4891 pub modified_opinion_rate: f64,
4892
4893 #[serde(default)]
4895 pub include_emphasis_of_matter: bool,
4896
4897 #[serde(default = "default_true")]
4899 pub include_going_concern: bool,
4900}
4901
4902fn default_kam_count() -> usize {
4903 3
4904}
4905
4906fn default_modified_opinion_rate() -> f64 {
4907 0.05
4908}
4909
4910impl Default for AuditOpinionConfig {
4911 fn default() -> Self {
4912 Self {
4913 enabled: false,
4914 generate_kam: true,
4915 average_kam_count: default_kam_count(),
4916 modified_opinion_rate: default_modified_opinion_rate(),
4917 include_emphasis_of_matter: false,
4918 include_going_concern: true,
4919 }
4920 }
4921}
4922
4923#[derive(Debug, Clone, Serialize, Deserialize)]
4925pub struct SoxComplianceConfig {
4926 #[serde(default)]
4928 pub enabled: bool,
4929
4930 #[serde(default = "default_true")]
4932 pub generate_302_certifications: bool,
4933
4934 #[serde(default = "default_true")]
4936 pub generate_404_assessments: bool,
4937
4938 #[serde(default = "default_sox_materiality_threshold")]
4940 pub materiality_threshold: f64,
4941
4942 #[serde(default = "default_material_weakness_rate")]
4944 pub material_weakness_rate: f64,
4945
4946 #[serde(default = "default_significant_deficiency_rate")]
4948 pub significant_deficiency_rate: f64,
4949}
4950
4951fn default_material_weakness_rate() -> f64 {
4952 0.02
4953}
4954
4955fn default_significant_deficiency_rate() -> f64 {
4956 0.08
4957}
4958
4959impl Default for SoxComplianceConfig {
4960 fn default() -> Self {
4961 Self {
4962 enabled: false,
4963 generate_302_certifications: true,
4964 generate_404_assessments: true,
4965 materiality_threshold: default_sox_materiality_threshold(),
4966 material_weakness_rate: default_material_weakness_rate(),
4967 significant_deficiency_rate: default_significant_deficiency_rate(),
4968 }
4969 }
4970}
4971
4972#[derive(Debug, Clone, Serialize, Deserialize)]
4974pub struct PcaobConfig {
4975 #[serde(default)]
4977 pub enabled: bool,
4978
4979 #[serde(default)]
4981 pub is_pcaob_audit: bool,
4982
4983 #[serde(default = "default_true")]
4985 pub generate_cam: bool,
4986
4987 #[serde(default)]
4989 pub include_icfr_opinion: bool,
4990
4991 #[serde(default)]
4993 pub generate_standard_mappings: bool,
4994}
4995
4996impl Default for PcaobConfig {
4997 fn default() -> Self {
4998 Self {
4999 enabled: false,
5000 is_pcaob_audit: false,
5001 generate_cam: true,
5002 include_icfr_opinion: false,
5003 generate_standard_mappings: false,
5004 }
5005 }
5006}
5007
5008#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5021pub struct AdvancedDistributionConfig {
5022 #[serde(default)]
5024 pub enabled: bool,
5025
5026 #[serde(default)]
5028 pub amounts: MixtureDistributionSchemaConfig,
5029
5030 #[serde(default)]
5032 pub correlations: CorrelationSchemaConfig,
5033
5034 #[serde(default)]
5036 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5037
5038 #[serde(default)]
5040 pub regime_changes: RegimeChangeSchemaConfig,
5041
5042 #[serde(default)]
5044 pub industry_profile: Option<IndustryProfileType>,
5045
5046 #[serde(default)]
5048 pub validation: StatisticalValidationSchemaConfig,
5049}
5050
5051#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5053#[serde(rename_all = "snake_case")]
5054pub enum IndustryProfileType {
5055 Retail,
5057 Manufacturing,
5059 FinancialServices,
5061 Healthcare,
5063 Technology,
5065}
5066
5067#[derive(Debug, Clone, Serialize, Deserialize)]
5069pub struct MixtureDistributionSchemaConfig {
5070 #[serde(default)]
5072 pub enabled: bool,
5073
5074 #[serde(default = "default_mixture_type")]
5076 pub distribution_type: MixtureDistributionType,
5077
5078 #[serde(default)]
5080 pub components: Vec<MixtureComponentConfig>,
5081
5082 #[serde(default = "default_min_amount")]
5084 pub min_value: f64,
5085
5086 #[serde(default)]
5088 pub max_value: Option<f64>,
5089
5090 #[serde(default = "default_decimal_places")]
5092 pub decimal_places: u8,
5093}
5094
5095fn default_mixture_type() -> MixtureDistributionType {
5096 MixtureDistributionType::LogNormal
5097}
5098
5099fn default_min_amount() -> f64 {
5100 0.01
5101}
5102
5103fn default_decimal_places() -> u8 {
5104 2
5105}
5106
5107impl Default for MixtureDistributionSchemaConfig {
5108 fn default() -> Self {
5109 Self {
5110 enabled: false,
5111 distribution_type: MixtureDistributionType::LogNormal,
5112 components: Vec::new(),
5113 min_value: 0.01,
5114 max_value: None,
5115 decimal_places: 2,
5116 }
5117 }
5118}
5119
5120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5122#[serde(rename_all = "snake_case")]
5123pub enum MixtureDistributionType {
5124 Gaussian,
5126 #[default]
5128 LogNormal,
5129}
5130
5131#[derive(Debug, Clone, Serialize, Deserialize)]
5133pub struct MixtureComponentConfig {
5134 pub weight: f64,
5136
5137 pub mu: f64,
5139
5140 pub sigma: f64,
5142
5143 #[serde(default)]
5145 pub label: Option<String>,
5146}
5147
5148#[derive(Debug, Clone, Serialize, Deserialize)]
5150pub struct CorrelationSchemaConfig {
5151 #[serde(default)]
5153 pub enabled: bool,
5154
5155 #[serde(default)]
5157 pub copula_type: CopulaSchemaType,
5158
5159 #[serde(default)]
5161 pub fields: Vec<CorrelatedFieldConfig>,
5162
5163 #[serde(default)]
5166 pub matrix: Vec<f64>,
5167
5168 #[serde(default)]
5170 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5171}
5172
5173impl Default for CorrelationSchemaConfig {
5174 fn default() -> Self {
5175 Self {
5176 enabled: false,
5177 copula_type: CopulaSchemaType::Gaussian,
5178 fields: Vec::new(),
5179 matrix: Vec::new(),
5180 expected_correlations: Vec::new(),
5181 }
5182 }
5183}
5184
5185#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5187#[serde(rename_all = "snake_case")]
5188pub enum CopulaSchemaType {
5189 #[default]
5191 Gaussian,
5192 Clayton,
5194 Gumbel,
5196 Frank,
5198 StudentT,
5200}
5201
5202#[derive(Debug, Clone, Serialize, Deserialize)]
5204pub struct CorrelatedFieldConfig {
5205 pub name: String,
5207
5208 #[serde(default)]
5210 pub distribution: MarginalDistributionConfig,
5211}
5212
5213#[derive(Debug, Clone, Serialize, Deserialize)]
5215#[serde(tag = "type", rename_all = "snake_case")]
5216pub enum MarginalDistributionConfig {
5217 Normal {
5219 mu: f64,
5221 sigma: f64,
5223 },
5224 LogNormal {
5226 mu: f64,
5228 sigma: f64,
5230 },
5231 Uniform {
5233 min: f64,
5235 max: f64,
5237 },
5238 DiscreteUniform {
5240 min: i32,
5242 max: i32,
5244 },
5245}
5246
5247impl Default for MarginalDistributionConfig {
5248 fn default() -> Self {
5249 Self::Normal {
5250 mu: 0.0,
5251 sigma: 1.0,
5252 }
5253 }
5254}
5255
5256#[derive(Debug, Clone, Serialize, Deserialize)]
5258pub struct ExpectedCorrelationConfig {
5259 pub field1: String,
5261 pub field2: String,
5263 pub expected_r: f64,
5265 #[serde(default = "default_correlation_tolerance")]
5267 pub tolerance: f64,
5268}
5269
5270fn default_correlation_tolerance() -> f64 {
5271 0.10
5272}
5273
5274#[derive(Debug, Clone, Serialize, Deserialize)]
5276pub struct ConditionalDistributionSchemaConfig {
5277 pub output_field: String,
5279
5280 pub input_field: String,
5282
5283 #[serde(default)]
5285 pub breakpoints: Vec<ConditionalBreakpointConfig>,
5286
5287 #[serde(default)]
5289 pub default_distribution: ConditionalDistributionParamsConfig,
5290
5291 #[serde(default)]
5293 pub min_value: Option<f64>,
5294
5295 #[serde(default)]
5297 pub max_value: Option<f64>,
5298
5299 #[serde(default = "default_decimal_places")]
5301 pub decimal_places: u8,
5302}
5303
5304#[derive(Debug, Clone, Serialize, Deserialize)]
5306pub struct ConditionalBreakpointConfig {
5307 pub threshold: f64,
5309
5310 pub distribution: ConditionalDistributionParamsConfig,
5312}
5313
5314#[derive(Debug, Clone, Serialize, Deserialize)]
5316#[serde(tag = "type", rename_all = "snake_case")]
5317pub enum ConditionalDistributionParamsConfig {
5318 Fixed {
5320 value: f64,
5322 },
5323 Normal {
5325 mu: f64,
5327 sigma: f64,
5329 },
5330 LogNormal {
5332 mu: f64,
5334 sigma: f64,
5336 },
5337 Uniform {
5339 min: f64,
5341 max: f64,
5343 },
5344 Beta {
5346 alpha: f64,
5348 beta: f64,
5350 min: f64,
5352 max: f64,
5354 },
5355 Discrete {
5357 values: Vec<f64>,
5359 weights: Vec<f64>,
5361 },
5362}
5363
5364impl Default for ConditionalDistributionParamsConfig {
5365 fn default() -> Self {
5366 Self::Normal {
5367 mu: 0.0,
5368 sigma: 1.0,
5369 }
5370 }
5371}
5372
5373#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5375pub struct RegimeChangeSchemaConfig {
5376 #[serde(default)]
5378 pub enabled: bool,
5379
5380 #[serde(default)]
5382 pub changes: Vec<RegimeChangeEventConfig>,
5383
5384 #[serde(default)]
5386 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5387
5388 #[serde(default)]
5390 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5391}
5392
5393#[derive(Debug, Clone, Serialize, Deserialize)]
5395pub struct RegimeChangeEventConfig {
5396 pub date: String,
5398
5399 pub change_type: RegimeChangeTypeConfig,
5401
5402 #[serde(default)]
5404 pub description: Option<String>,
5405
5406 #[serde(default)]
5408 pub effects: Vec<RegimeEffectConfig>,
5409}
5410
5411#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5413#[serde(rename_all = "snake_case")]
5414pub enum RegimeChangeTypeConfig {
5415 Acquisition,
5417 Divestiture,
5419 PriceIncrease,
5421 PriceDecrease,
5423 ProductLaunch,
5425 ProductDiscontinuation,
5427 PolicyChange,
5429 CompetitorEntry,
5431 Custom,
5433}
5434
5435#[derive(Debug, Clone, Serialize, Deserialize)]
5437pub struct RegimeEffectConfig {
5438 pub field: String,
5440
5441 pub multiplier: f64,
5443}
5444
5445#[derive(Debug, Clone, Serialize, Deserialize)]
5447pub struct EconomicCycleSchemaConfig {
5448 #[serde(default)]
5450 pub enabled: bool,
5451
5452 #[serde(default = "default_cycle_period")]
5454 pub period_months: u32,
5455
5456 #[serde(default = "default_cycle_amplitude")]
5458 pub amplitude: f64,
5459
5460 #[serde(default)]
5462 pub phase_offset: u32,
5463
5464 #[serde(default)]
5466 pub recessions: Vec<RecessionPeriodConfig>,
5467}
5468
5469fn default_cycle_period() -> u32 {
5470 48
5471}
5472
5473fn default_cycle_amplitude() -> f64 {
5474 0.15
5475}
5476
5477impl Default for EconomicCycleSchemaConfig {
5478 fn default() -> Self {
5479 Self {
5480 enabled: false,
5481 period_months: 48,
5482 amplitude: 0.15,
5483 phase_offset: 0,
5484 recessions: Vec::new(),
5485 }
5486 }
5487}
5488
5489#[derive(Debug, Clone, Serialize, Deserialize)]
5491pub struct RecessionPeriodConfig {
5492 pub start_month: u32,
5494
5495 pub duration_months: u32,
5497
5498 #[serde(default = "default_recession_severity")]
5500 pub severity: f64,
5501}
5502
5503fn default_recession_severity() -> f64 {
5504 0.20
5505}
5506
5507#[derive(Debug, Clone, Serialize, Deserialize)]
5509pub struct ParameterDriftSchemaConfig {
5510 pub parameter: String,
5512
5513 pub drift_type: ParameterDriftTypeConfig,
5515
5516 pub start_value: f64,
5518
5519 pub end_value: f64,
5521
5522 #[serde(default)]
5524 pub start_period: u32,
5525
5526 #[serde(default)]
5528 pub end_period: Option<u32>,
5529}
5530
5531#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5533#[serde(rename_all = "snake_case")]
5534pub enum ParameterDriftTypeConfig {
5535 #[default]
5537 Linear,
5538 Exponential,
5540 Logistic,
5542 Step,
5544}
5545
5546#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5548pub struct StatisticalValidationSchemaConfig {
5549 #[serde(default)]
5551 pub enabled: bool,
5552
5553 #[serde(default)]
5555 pub tests: Vec<StatisticalTestConfig>,
5556
5557 #[serde(default)]
5559 pub reporting: ValidationReportingConfig,
5560}
5561
5562#[derive(Debug, Clone, Serialize, Deserialize)]
5564#[serde(tag = "type", rename_all = "snake_case")]
5565pub enum StatisticalTestConfig {
5566 BenfordFirstDigit {
5568 #[serde(default = "default_benford_threshold")]
5570 threshold_mad: f64,
5571 #[serde(default = "default_benford_warning")]
5573 warning_mad: f64,
5574 },
5575 DistributionFit {
5577 target: TargetDistributionConfig,
5579 #[serde(default = "default_ks_significance")]
5581 ks_significance: f64,
5582 #[serde(default)]
5584 method: DistributionFitMethod,
5585 },
5586 CorrelationCheck {
5588 expected_correlations: Vec<ExpectedCorrelationConfig>,
5590 },
5591 ChiSquared {
5593 #[serde(default = "default_chi_squared_bins")]
5595 bins: usize,
5596 #[serde(default = "default_chi_squared_significance")]
5598 significance: f64,
5599 },
5600 AndersonDarling {
5602 target: TargetDistributionConfig,
5604 #[serde(default = "default_ad_significance")]
5606 significance: f64,
5607 },
5608}
5609
5610fn default_benford_threshold() -> f64 {
5611 0.015
5612}
5613
5614fn default_benford_warning() -> f64 {
5615 0.010
5616}
5617
5618fn default_ks_significance() -> f64 {
5619 0.05
5620}
5621
5622fn default_chi_squared_bins() -> usize {
5623 10
5624}
5625
5626fn default_chi_squared_significance() -> f64 {
5627 0.05
5628}
5629
5630fn default_ad_significance() -> f64 {
5631 0.05
5632}
5633
5634#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5636#[serde(rename_all = "snake_case")]
5637pub enum TargetDistributionConfig {
5638 Normal,
5640 #[default]
5642 LogNormal,
5643 Exponential,
5645 Uniform,
5647}
5648
5649#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5651#[serde(rename_all = "snake_case")]
5652pub enum DistributionFitMethod {
5653 #[default]
5655 KolmogorovSmirnov,
5656 AndersonDarling,
5658 ChiSquared,
5660}
5661
5662#[derive(Debug, Clone, Serialize, Deserialize)]
5664pub struct ValidationReportingConfig {
5665 #[serde(default)]
5667 pub output_report: bool,
5668
5669 #[serde(default)]
5671 pub format: ValidationReportFormat,
5672
5673 #[serde(default)]
5675 pub fail_on_error: bool,
5676
5677 #[serde(default = "default_true")]
5679 pub include_details: bool,
5680}
5681
5682impl Default for ValidationReportingConfig {
5683 fn default() -> Self {
5684 Self {
5685 output_report: false,
5686 format: ValidationReportFormat::Json,
5687 fail_on_error: false,
5688 include_details: true,
5689 }
5690 }
5691}
5692
5693#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5695#[serde(rename_all = "snake_case")]
5696pub enum ValidationReportFormat {
5697 #[default]
5699 Json,
5700 Yaml,
5702 Html,
5704}
5705
5706#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5718pub struct TemporalPatternsConfig {
5719 #[serde(default)]
5721 pub enabled: bool,
5722
5723 #[serde(default)]
5725 pub business_days: BusinessDaySchemaConfig,
5726
5727 #[serde(default)]
5729 pub calendars: CalendarSchemaConfig,
5730
5731 #[serde(default)]
5733 pub period_end: PeriodEndSchemaConfig,
5734
5735 #[serde(default)]
5737 pub processing_lags: ProcessingLagSchemaConfig,
5738
5739 #[serde(default)]
5741 pub fiscal_calendar: FiscalCalendarSchemaConfig,
5742
5743 #[serde(default)]
5745 pub intraday: IntraDaySchemaConfig,
5746
5747 #[serde(default)]
5749 pub timezones: TimezoneSchemaConfig,
5750}
5751
5752#[derive(Debug, Clone, Serialize, Deserialize)]
5754pub struct BusinessDaySchemaConfig {
5755 #[serde(default = "default_true")]
5757 pub enabled: bool,
5758
5759 #[serde(default = "default_half_day_policy")]
5761 pub half_day_policy: String,
5762
5763 #[serde(default)]
5765 pub settlement_rules: SettlementRulesSchemaConfig,
5766
5767 #[serde(default = "default_month_end_convention")]
5769 pub month_end_convention: String,
5770
5771 #[serde(default)]
5773 pub weekend_days: Option<Vec<String>>,
5774}
5775
5776fn default_half_day_policy() -> String {
5777 "half_day".to_string()
5778}
5779
5780fn default_month_end_convention() -> String {
5781 "modified_following".to_string()
5782}
5783
5784impl Default for BusinessDaySchemaConfig {
5785 fn default() -> Self {
5786 Self {
5787 enabled: true,
5788 half_day_policy: "half_day".to_string(),
5789 settlement_rules: SettlementRulesSchemaConfig::default(),
5790 month_end_convention: "modified_following".to_string(),
5791 weekend_days: None,
5792 }
5793 }
5794}
5795
5796#[derive(Debug, Clone, Serialize, Deserialize)]
5798pub struct SettlementRulesSchemaConfig {
5799 #[serde(default = "default_settlement_2")]
5801 pub equity_days: i32,
5802
5803 #[serde(default = "default_settlement_1")]
5805 pub government_bonds_days: i32,
5806
5807 #[serde(default = "default_settlement_2")]
5809 pub fx_spot_days: i32,
5810
5811 #[serde(default = "default_settlement_2")]
5813 pub corporate_bonds_days: i32,
5814
5815 #[serde(default = "default_wire_cutoff")]
5817 pub wire_cutoff_time: String,
5818
5819 #[serde(default = "default_settlement_1")]
5821 pub wire_international_days: i32,
5822
5823 #[serde(default = "default_settlement_1")]
5825 pub ach_days: i32,
5826}
5827
5828fn default_settlement_1() -> i32 {
5829 1
5830}
5831
5832fn default_settlement_2() -> i32 {
5833 2
5834}
5835
5836fn default_wire_cutoff() -> String {
5837 "14:00".to_string()
5838}
5839
5840impl Default for SettlementRulesSchemaConfig {
5841 fn default() -> Self {
5842 Self {
5843 equity_days: 2,
5844 government_bonds_days: 1,
5845 fx_spot_days: 2,
5846 corporate_bonds_days: 2,
5847 wire_cutoff_time: "14:00".to_string(),
5848 wire_international_days: 1,
5849 ach_days: 1,
5850 }
5851 }
5852}
5853
5854#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5856pub struct CalendarSchemaConfig {
5857 #[serde(default)]
5859 pub regions: Vec<String>,
5860
5861 #[serde(default)]
5863 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
5864}
5865
5866#[derive(Debug, Clone, Serialize, Deserialize)]
5868pub struct CustomHolidaySchemaConfig {
5869 pub name: String,
5871 pub month: u8,
5873 pub day: u8,
5875 #[serde(default = "default_holiday_multiplier")]
5877 pub activity_multiplier: f64,
5878}
5879
5880fn default_holiday_multiplier() -> f64 {
5881 0.05
5882}
5883
5884#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5886pub struct PeriodEndSchemaConfig {
5887 #[serde(default)]
5889 pub model: Option<String>,
5890
5891 #[serde(default)]
5893 pub month_end: Option<PeriodEndModelSchemaConfig>,
5894
5895 #[serde(default)]
5897 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
5898
5899 #[serde(default)]
5901 pub year_end: Option<PeriodEndModelSchemaConfig>,
5902}
5903
5904#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5906pub struct PeriodEndModelSchemaConfig {
5907 #[serde(default)]
5909 pub inherit_from: Option<String>,
5910
5911 #[serde(default)]
5913 pub additional_multiplier: Option<f64>,
5914
5915 #[serde(default)]
5917 pub start_day: Option<i32>,
5918
5919 #[serde(default)]
5921 pub base_multiplier: Option<f64>,
5922
5923 #[serde(default)]
5925 pub peak_multiplier: Option<f64>,
5926
5927 #[serde(default)]
5929 pub decay_rate: Option<f64>,
5930
5931 #[serde(default)]
5933 pub sustained_high_days: Option<i32>,
5934}
5935
5936#[derive(Debug, Clone, Serialize, Deserialize)]
5938pub struct ProcessingLagSchemaConfig {
5939 #[serde(default = "default_true")]
5941 pub enabled: bool,
5942
5943 #[serde(default)]
5945 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
5946
5947 #[serde(default)]
5949 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
5950
5951 #[serde(default)]
5953 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
5954
5955 #[serde(default)]
5957 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
5958
5959 #[serde(default)]
5961 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
5962
5963 #[serde(default)]
5965 pub payment_lag: Option<LagDistributionSchemaConfig>,
5966
5967 #[serde(default)]
5969 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
5970
5971 #[serde(default)]
5973 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
5974}
5975
5976impl Default for ProcessingLagSchemaConfig {
5977 fn default() -> Self {
5978 Self {
5979 enabled: true,
5980 sales_order_lag: None,
5981 purchase_order_lag: None,
5982 goods_receipt_lag: None,
5983 invoice_receipt_lag: None,
5984 invoice_issue_lag: None,
5985 payment_lag: None,
5986 journal_entry_lag: None,
5987 cross_day_posting: None,
5988 }
5989 }
5990}
5991
5992#[derive(Debug, Clone, Serialize, Deserialize)]
5994pub struct LagDistributionSchemaConfig {
5995 pub mu: f64,
5997 pub sigma: f64,
5999 #[serde(default)]
6001 pub min_hours: Option<f64>,
6002 #[serde(default)]
6004 pub max_hours: Option<f64>,
6005}
6006
6007#[derive(Debug, Clone, Serialize, Deserialize)]
6009pub struct CrossDayPostingSchemaConfig {
6010 #[serde(default = "default_true")]
6012 pub enabled: bool,
6013
6014 #[serde(default)]
6017 pub probability_by_hour: std::collections::HashMap<u8, f64>,
6018}
6019
6020impl Default for CrossDayPostingSchemaConfig {
6021 fn default() -> Self {
6022 let mut probability_by_hour = std::collections::HashMap::new();
6023 probability_by_hour.insert(17, 0.3);
6024 probability_by_hour.insert(18, 0.6);
6025 probability_by_hour.insert(19, 0.8);
6026 probability_by_hour.insert(20, 0.9);
6027 probability_by_hour.insert(21, 0.95);
6028 probability_by_hour.insert(22, 0.99);
6029
6030 Self {
6031 enabled: true,
6032 probability_by_hour,
6033 }
6034 }
6035}
6036
6037#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6046pub struct FiscalCalendarSchemaConfig {
6047 #[serde(default)]
6049 pub enabled: bool,
6050
6051 #[serde(default = "default_fiscal_calendar_type")]
6053 pub calendar_type: String,
6054
6055 #[serde(default)]
6057 pub year_start_month: Option<u8>,
6058
6059 #[serde(default)]
6061 pub year_start_day: Option<u8>,
6062
6063 #[serde(default)]
6065 pub four_four_five: Option<FourFourFiveSchemaConfig>,
6066}
6067
6068fn default_fiscal_calendar_type() -> String {
6069 "calendar_year".to_string()
6070}
6071
6072#[derive(Debug, Clone, Serialize, Deserialize)]
6074pub struct FourFourFiveSchemaConfig {
6075 #[serde(default = "default_week_pattern")]
6077 pub pattern: String,
6078
6079 #[serde(default = "default_anchor_type")]
6081 pub anchor_type: String,
6082
6083 #[serde(default = "default_anchor_month")]
6085 pub anchor_month: u8,
6086
6087 #[serde(default = "default_leap_week_placement")]
6089 pub leap_week_placement: String,
6090}
6091
6092fn default_week_pattern() -> String {
6093 "four_four_five".to_string()
6094}
6095
6096fn default_anchor_type() -> String {
6097 "last_saturday".to_string()
6098}
6099
6100fn default_anchor_month() -> u8 {
6101 1 }
6103
6104fn default_leap_week_placement() -> String {
6105 "q4_period3".to_string()
6106}
6107
6108impl Default for FourFourFiveSchemaConfig {
6109 fn default() -> Self {
6110 Self {
6111 pattern: "four_four_five".to_string(),
6112 anchor_type: "last_saturday".to_string(),
6113 anchor_month: 1,
6114 leap_week_placement: "q4_period3".to_string(),
6115 }
6116 }
6117}
6118
6119#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6128pub struct IntraDaySchemaConfig {
6129 #[serde(default)]
6131 pub enabled: bool,
6132
6133 #[serde(default)]
6135 pub segments: Vec<IntraDaySegmentSchemaConfig>,
6136}
6137
6138#[derive(Debug, Clone, Serialize, Deserialize)]
6140pub struct IntraDaySegmentSchemaConfig {
6141 pub name: String,
6143
6144 pub start: String,
6146
6147 pub end: String,
6149
6150 #[serde(default = "default_multiplier")]
6152 pub multiplier: f64,
6153
6154 #[serde(default = "default_posting_type")]
6156 pub posting_type: String,
6157}
6158
6159fn default_multiplier() -> f64 {
6160 1.0
6161}
6162
6163fn default_posting_type() -> String {
6164 "both".to_string()
6165}
6166
6167#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6173pub struct TimezoneSchemaConfig {
6174 #[serde(default)]
6176 pub enabled: bool,
6177
6178 #[serde(default = "default_timezone")]
6180 pub default_timezone: String,
6181
6182 #[serde(default = "default_consolidation_timezone")]
6184 pub consolidation_timezone: String,
6185
6186 #[serde(default)]
6189 pub entity_mappings: Vec<EntityTimezoneMapping>,
6190}
6191
6192fn default_timezone() -> String {
6193 "America/New_York".to_string()
6194}
6195
6196fn default_consolidation_timezone() -> String {
6197 "UTC".to_string()
6198}
6199
6200#[derive(Debug, Clone, Serialize, Deserialize)]
6202pub struct EntityTimezoneMapping {
6203 pub pattern: String,
6205
6206 pub timezone: String,
6208}
6209
6210#[derive(Debug, Clone, Serialize, Deserialize)]
6216pub struct VendorNetworkSchemaConfig {
6217 #[serde(default)]
6219 pub enabled: bool,
6220
6221 #[serde(default = "default_vendor_tier_depth")]
6223 pub depth: u8,
6224
6225 #[serde(default)]
6227 pub tier1: TierCountSchemaConfig,
6228
6229 #[serde(default)]
6231 pub tier2_per_parent: TierCountSchemaConfig,
6232
6233 #[serde(default)]
6235 pub tier3_per_parent: TierCountSchemaConfig,
6236
6237 #[serde(default)]
6239 pub clusters: VendorClusterSchemaConfig,
6240
6241 #[serde(default)]
6243 pub dependencies: DependencySchemaConfig,
6244}
6245
6246fn default_vendor_tier_depth() -> u8 {
6247 3
6248}
6249
6250impl Default for VendorNetworkSchemaConfig {
6251 fn default() -> Self {
6252 Self {
6253 enabled: false,
6254 depth: 3,
6255 tier1: TierCountSchemaConfig { min: 50, max: 100 },
6256 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6257 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6258 clusters: VendorClusterSchemaConfig::default(),
6259 dependencies: DependencySchemaConfig::default(),
6260 }
6261 }
6262}
6263
6264#[derive(Debug, Clone, Serialize, Deserialize)]
6266pub struct TierCountSchemaConfig {
6267 #[serde(default = "default_tier_min")]
6269 pub min: usize,
6270
6271 #[serde(default = "default_tier_max")]
6273 pub max: usize,
6274}
6275
6276fn default_tier_min() -> usize {
6277 5
6278}
6279
6280fn default_tier_max() -> usize {
6281 20
6282}
6283
6284impl Default for TierCountSchemaConfig {
6285 fn default() -> Self {
6286 Self {
6287 min: default_tier_min(),
6288 max: default_tier_max(),
6289 }
6290 }
6291}
6292
6293#[derive(Debug, Clone, Serialize, Deserialize)]
6295pub struct VendorClusterSchemaConfig {
6296 #[serde(default = "default_reliable_strategic")]
6298 pub reliable_strategic: f64,
6299
6300 #[serde(default = "default_standard_operational")]
6302 pub standard_operational: f64,
6303
6304 #[serde(default = "default_transactional")]
6306 pub transactional: f64,
6307
6308 #[serde(default = "default_problematic")]
6310 pub problematic: f64,
6311}
6312
6313fn default_reliable_strategic() -> f64 {
6314 0.20
6315}
6316
6317fn default_standard_operational() -> f64 {
6318 0.50
6319}
6320
6321fn default_transactional() -> f64 {
6322 0.25
6323}
6324
6325fn default_problematic() -> f64 {
6326 0.05
6327}
6328
6329impl Default for VendorClusterSchemaConfig {
6330 fn default() -> Self {
6331 Self {
6332 reliable_strategic: 0.20,
6333 standard_operational: 0.50,
6334 transactional: 0.25,
6335 problematic: 0.05,
6336 }
6337 }
6338}
6339
6340#[derive(Debug, Clone, Serialize, Deserialize)]
6342pub struct DependencySchemaConfig {
6343 #[serde(default = "default_max_single_vendor")]
6345 pub max_single_vendor_concentration: f64,
6346
6347 #[serde(default = "default_max_top5")]
6349 pub top_5_concentration: f64,
6350
6351 #[serde(default = "default_single_source_percent")]
6353 pub single_source_percent: f64,
6354}
6355
6356fn default_max_single_vendor() -> f64 {
6357 0.15
6358}
6359
6360fn default_max_top5() -> f64 {
6361 0.45
6362}
6363
6364fn default_single_source_percent() -> f64 {
6365 0.05
6366}
6367
6368impl Default for DependencySchemaConfig {
6369 fn default() -> Self {
6370 Self {
6371 max_single_vendor_concentration: 0.15,
6372 top_5_concentration: 0.45,
6373 single_source_percent: 0.05,
6374 }
6375 }
6376}
6377
6378#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6384pub struct CustomerSegmentationSchemaConfig {
6385 #[serde(default)]
6387 pub enabled: bool,
6388
6389 #[serde(default)]
6391 pub value_segments: ValueSegmentsSchemaConfig,
6392
6393 #[serde(default)]
6395 pub lifecycle: LifecycleSchemaConfig,
6396
6397 #[serde(default)]
6399 pub networks: CustomerNetworksSchemaConfig,
6400}
6401
6402#[derive(Debug, Clone, Serialize, Deserialize)]
6404pub struct ValueSegmentsSchemaConfig {
6405 #[serde(default)]
6407 pub enterprise: SegmentDetailSchemaConfig,
6408
6409 #[serde(default)]
6411 pub mid_market: SegmentDetailSchemaConfig,
6412
6413 #[serde(default)]
6415 pub smb: SegmentDetailSchemaConfig,
6416
6417 #[serde(default)]
6419 pub consumer: SegmentDetailSchemaConfig,
6420}
6421
6422impl Default for ValueSegmentsSchemaConfig {
6423 fn default() -> Self {
6424 Self {
6425 enterprise: SegmentDetailSchemaConfig {
6426 revenue_share: 0.40,
6427 customer_share: 0.05,
6428 avg_order_value_range: "50000+".to_string(),
6429 },
6430 mid_market: SegmentDetailSchemaConfig {
6431 revenue_share: 0.35,
6432 customer_share: 0.20,
6433 avg_order_value_range: "5000-50000".to_string(),
6434 },
6435 smb: SegmentDetailSchemaConfig {
6436 revenue_share: 0.20,
6437 customer_share: 0.50,
6438 avg_order_value_range: "500-5000".to_string(),
6439 },
6440 consumer: SegmentDetailSchemaConfig {
6441 revenue_share: 0.05,
6442 customer_share: 0.25,
6443 avg_order_value_range: "50-500".to_string(),
6444 },
6445 }
6446 }
6447}
6448
6449#[derive(Debug, Clone, Serialize, Deserialize)]
6451pub struct SegmentDetailSchemaConfig {
6452 #[serde(default)]
6454 pub revenue_share: f64,
6455
6456 #[serde(default)]
6458 pub customer_share: f64,
6459
6460 #[serde(default)]
6462 pub avg_order_value_range: String,
6463}
6464
6465impl Default for SegmentDetailSchemaConfig {
6466 fn default() -> Self {
6467 Self {
6468 revenue_share: 0.25,
6469 customer_share: 0.25,
6470 avg_order_value_range: "1000-10000".to_string(),
6471 }
6472 }
6473}
6474
6475#[derive(Debug, Clone, Serialize, Deserialize)]
6477pub struct LifecycleSchemaConfig {
6478 #[serde(default)]
6480 pub prospect_rate: f64,
6481
6482 #[serde(default = "default_new_rate")]
6484 pub new_rate: f64,
6485
6486 #[serde(default = "default_growth_rate")]
6488 pub growth_rate: f64,
6489
6490 #[serde(default = "default_mature_rate")]
6492 pub mature_rate: f64,
6493
6494 #[serde(default = "default_at_risk_rate")]
6496 pub at_risk_rate: f64,
6497
6498 #[serde(default = "default_churned_rate")]
6500 pub churned_rate: f64,
6501}
6502
6503fn default_new_rate() -> f64 {
6504 0.10
6505}
6506
6507fn default_growth_rate() -> f64 {
6508 0.15
6509}
6510
6511fn default_mature_rate() -> f64 {
6512 0.60
6513}
6514
6515fn default_at_risk_rate() -> f64 {
6516 0.10
6517}
6518
6519fn default_churned_rate() -> f64 {
6520 0.05
6521}
6522
6523impl Default for LifecycleSchemaConfig {
6524 fn default() -> Self {
6525 Self {
6526 prospect_rate: 0.0,
6527 new_rate: 0.10,
6528 growth_rate: 0.15,
6529 mature_rate: 0.60,
6530 at_risk_rate: 0.10,
6531 churned_rate: 0.05,
6532 }
6533 }
6534}
6535
6536#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6538pub struct CustomerNetworksSchemaConfig {
6539 #[serde(default)]
6541 pub referrals: ReferralSchemaConfig,
6542
6543 #[serde(default)]
6545 pub corporate_hierarchies: HierarchySchemaConfig,
6546}
6547
6548#[derive(Debug, Clone, Serialize, Deserialize)]
6550pub struct ReferralSchemaConfig {
6551 #[serde(default = "default_true")]
6553 pub enabled: bool,
6554
6555 #[serde(default = "default_referral_rate")]
6557 pub referral_rate: f64,
6558}
6559
6560fn default_referral_rate() -> f64 {
6561 0.15
6562}
6563
6564impl Default for ReferralSchemaConfig {
6565 fn default() -> Self {
6566 Self {
6567 enabled: true,
6568 referral_rate: 0.15,
6569 }
6570 }
6571}
6572
6573#[derive(Debug, Clone, Serialize, Deserialize)]
6575pub struct HierarchySchemaConfig {
6576 #[serde(default = "default_true")]
6578 pub enabled: bool,
6579
6580 #[serde(default = "default_hierarchy_rate")]
6582 pub probability: f64,
6583}
6584
6585fn default_hierarchy_rate() -> f64 {
6586 0.30
6587}
6588
6589impl Default for HierarchySchemaConfig {
6590 fn default() -> Self {
6591 Self {
6592 enabled: true,
6593 probability: 0.30,
6594 }
6595 }
6596}
6597
6598#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6604pub struct RelationshipStrengthSchemaConfig {
6605 #[serde(default)]
6607 pub enabled: bool,
6608
6609 #[serde(default)]
6611 pub calculation: StrengthCalculationSchemaConfig,
6612
6613 #[serde(default)]
6615 pub thresholds: StrengthThresholdsSchemaConfig,
6616}
6617
6618#[derive(Debug, Clone, Serialize, Deserialize)]
6620pub struct StrengthCalculationSchemaConfig {
6621 #[serde(default = "default_volume_weight")]
6623 pub transaction_volume_weight: f64,
6624
6625 #[serde(default = "default_count_weight")]
6627 pub transaction_count_weight: f64,
6628
6629 #[serde(default = "default_duration_weight")]
6631 pub relationship_duration_weight: f64,
6632
6633 #[serde(default = "default_recency_weight")]
6635 pub recency_weight: f64,
6636
6637 #[serde(default = "default_mutual_weight")]
6639 pub mutual_connections_weight: f64,
6640
6641 #[serde(default = "default_recency_half_life")]
6643 pub recency_half_life_days: u32,
6644}
6645
6646fn default_volume_weight() -> f64 {
6647 0.30
6648}
6649
6650fn default_count_weight() -> f64 {
6651 0.25
6652}
6653
6654fn default_duration_weight() -> f64 {
6655 0.20
6656}
6657
6658fn default_recency_weight() -> f64 {
6659 0.15
6660}
6661
6662fn default_mutual_weight() -> f64 {
6663 0.10
6664}
6665
6666fn default_recency_half_life() -> u32 {
6667 90
6668}
6669
6670impl Default for StrengthCalculationSchemaConfig {
6671 fn default() -> Self {
6672 Self {
6673 transaction_volume_weight: 0.30,
6674 transaction_count_weight: 0.25,
6675 relationship_duration_weight: 0.20,
6676 recency_weight: 0.15,
6677 mutual_connections_weight: 0.10,
6678 recency_half_life_days: 90,
6679 }
6680 }
6681}
6682
6683#[derive(Debug, Clone, Serialize, Deserialize)]
6685pub struct StrengthThresholdsSchemaConfig {
6686 #[serde(default = "default_strong_threshold")]
6688 pub strong: f64,
6689
6690 #[serde(default = "default_moderate_threshold")]
6692 pub moderate: f64,
6693
6694 #[serde(default = "default_weak_threshold")]
6696 pub weak: f64,
6697}
6698
6699fn default_strong_threshold() -> f64 {
6700 0.7
6701}
6702
6703fn default_moderate_threshold() -> f64 {
6704 0.4
6705}
6706
6707fn default_weak_threshold() -> f64 {
6708 0.1
6709}
6710
6711impl Default for StrengthThresholdsSchemaConfig {
6712 fn default() -> Self {
6713 Self {
6714 strong: 0.7,
6715 moderate: 0.4,
6716 weak: 0.1,
6717 }
6718 }
6719}
6720
6721#[derive(Debug, Clone, Serialize, Deserialize)]
6727pub struct CrossProcessLinksSchemaConfig {
6728 #[serde(default)]
6730 pub enabled: bool,
6731
6732 #[serde(default = "default_true")]
6734 pub inventory_p2p_o2c: bool,
6735
6736 #[serde(default = "default_true")]
6738 pub payment_bank_reconciliation: bool,
6739
6740 #[serde(default = "default_true")]
6742 pub intercompany_bilateral: bool,
6743
6744 #[serde(default = "default_inventory_link_rate")]
6746 pub inventory_link_rate: f64,
6747}
6748
6749fn default_inventory_link_rate() -> f64 {
6750 0.30
6751}
6752
6753impl Default for CrossProcessLinksSchemaConfig {
6754 fn default() -> Self {
6755 Self {
6756 enabled: false,
6757 inventory_p2p_o2c: true,
6758 payment_bank_reconciliation: true,
6759 intercompany_bilateral: true,
6760 inventory_link_rate: 0.30,
6761 }
6762 }
6763}
6764
6765#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6771pub struct OrganizationalEventsSchemaConfig {
6772 #[serde(default)]
6774 pub enabled: bool,
6775
6776 #[serde(default)]
6778 pub effect_blending: EffectBlendingModeConfig,
6779
6780 #[serde(default)]
6782 pub events: Vec<OrganizationalEventSchemaConfig>,
6783
6784 #[serde(default)]
6786 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6787
6788 #[serde(default)]
6790 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6791}
6792
6793#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6795#[serde(rename_all = "snake_case")]
6796pub enum EffectBlendingModeConfig {
6797 #[default]
6799 Multiplicative,
6800 Additive,
6802 Maximum,
6804 Minimum,
6806}
6807
6808#[derive(Debug, Clone, Serialize, Deserialize)]
6810pub struct OrganizationalEventSchemaConfig {
6811 pub id: String,
6813
6814 pub event_type: OrganizationalEventTypeSchemaConfig,
6816
6817 pub effective_date: String,
6819
6820 #[serde(default = "default_org_transition_months")]
6822 pub transition_months: u32,
6823
6824 #[serde(default)]
6826 pub description: Option<String>,
6827}
6828
6829fn default_org_transition_months() -> u32 {
6830 6
6831}
6832
6833#[derive(Debug, Clone, Serialize, Deserialize)]
6835#[serde(tag = "type", rename_all = "snake_case")]
6836pub enum OrganizationalEventTypeSchemaConfig {
6837 Acquisition {
6839 acquired_entity: String,
6841 #[serde(default = "default_acquisition_volume")]
6843 volume_increase: f64,
6844 #[serde(default = "default_acquisition_error")]
6846 integration_error_rate: f64,
6847 #[serde(default = "default_parallel_days")]
6849 parallel_posting_days: u32,
6850 },
6851 Divestiture {
6853 divested_entity: String,
6855 #[serde(default = "default_divestiture_volume")]
6857 volume_reduction: f64,
6858 #[serde(default = "default_true_val")]
6860 remove_entity: bool,
6861 },
6862 Reorganization {
6864 #[serde(default)]
6866 cost_center_remapping: std::collections::HashMap<String, String>,
6867 #[serde(default = "default_reorg_error")]
6869 transition_error_rate: f64,
6870 },
6871 LeadershipChange {
6873 role: String,
6875 #[serde(default)]
6877 policy_changes: Vec<String>,
6878 },
6879 WorkforceReduction {
6881 #[serde(default = "default_workforce_reduction")]
6883 reduction_percent: f64,
6884 #[serde(default = "default_workforce_error")]
6886 error_rate_increase: f64,
6887 },
6888 Merger {
6890 merged_entity: String,
6892 #[serde(default = "default_merger_volume")]
6894 volume_increase: f64,
6895 },
6896}
6897
6898fn default_acquisition_volume() -> f64 {
6899 1.35
6900}
6901
6902fn default_acquisition_error() -> f64 {
6903 0.05
6904}
6905
6906fn default_parallel_days() -> u32 {
6907 30
6908}
6909
6910fn default_divestiture_volume() -> f64 {
6911 0.70
6912}
6913
6914fn default_true_val() -> bool {
6915 true
6916}
6917
6918fn default_reorg_error() -> f64 {
6919 0.04
6920}
6921
6922fn default_workforce_reduction() -> f64 {
6923 0.10
6924}
6925
6926fn default_workforce_error() -> f64 {
6927 0.05
6928}
6929
6930fn default_merger_volume() -> f64 {
6931 1.80
6932}
6933
6934#[derive(Debug, Clone, Serialize, Deserialize)]
6936pub struct ProcessEvolutionSchemaConfig {
6937 pub id: String,
6939
6940 pub event_type: ProcessEvolutionTypeSchemaConfig,
6942
6943 pub effective_date: String,
6945
6946 #[serde(default)]
6948 pub description: Option<String>,
6949}
6950
6951#[derive(Debug, Clone, Serialize, Deserialize)]
6953#[serde(tag = "type", rename_all = "snake_case")]
6954pub enum ProcessEvolutionTypeSchemaConfig {
6955 ProcessAutomation {
6957 process_name: String,
6959 #[serde(default = "default_manual_before")]
6961 manual_rate_before: f64,
6962 #[serde(default = "default_manual_after")]
6964 manual_rate_after: f64,
6965 },
6966 ApprovalWorkflowChange {
6968 description: String,
6970 },
6971 ControlEnhancement {
6973 control_id: String,
6975 #[serde(default = "default_error_reduction")]
6977 error_reduction: f64,
6978 },
6979}
6980
6981fn default_manual_before() -> f64 {
6982 0.80
6983}
6984
6985fn default_manual_after() -> f64 {
6986 0.15
6987}
6988
6989fn default_error_reduction() -> f64 {
6990 0.02
6991}
6992
6993#[derive(Debug, Clone, Serialize, Deserialize)]
6995pub struct TechnologyTransitionSchemaConfig {
6996 pub id: String,
6998
6999 pub event_type: TechnologyTransitionTypeSchemaConfig,
7001
7002 #[serde(default)]
7004 pub description: Option<String>,
7005}
7006
7007#[derive(Debug, Clone, Serialize, Deserialize)]
7009#[serde(tag = "type", rename_all = "snake_case")]
7010pub enum TechnologyTransitionTypeSchemaConfig {
7011 ErpMigration {
7013 source_system: String,
7015 target_system: String,
7017 cutover_date: String,
7019 stabilization_end: String,
7021 #[serde(default = "default_erp_duplicate_rate")]
7023 duplicate_rate: f64,
7024 #[serde(default = "default_format_mismatch")]
7026 format_mismatch_rate: f64,
7027 },
7028 ModuleImplementation {
7030 module_name: String,
7032 go_live_date: String,
7034 },
7035}
7036
7037fn default_erp_duplicate_rate() -> f64 {
7038 0.02
7039}
7040
7041fn default_format_mismatch() -> f64 {
7042 0.03
7043}
7044
7045#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7051pub struct BehavioralDriftSchemaConfig {
7052 #[serde(default)]
7054 pub enabled: bool,
7055
7056 #[serde(default)]
7058 pub vendor_behavior: VendorBehaviorSchemaConfig,
7059
7060 #[serde(default)]
7062 pub customer_behavior: CustomerBehaviorSchemaConfig,
7063
7064 #[serde(default)]
7066 pub employee_behavior: EmployeeBehaviorSchemaConfig,
7067
7068 #[serde(default)]
7070 pub collective: CollectiveBehaviorSchemaConfig,
7071}
7072
7073#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7075pub struct VendorBehaviorSchemaConfig {
7076 #[serde(default)]
7078 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7079
7080 #[serde(default)]
7082 pub quality_drift: QualityDriftSchemaConfig,
7083}
7084
7085#[derive(Debug, Clone, Serialize, Deserialize)]
7087pub struct PaymentTermsDriftSchemaConfig {
7088 #[serde(default = "default_extension_rate")]
7090 pub extension_rate_per_year: f64,
7091
7092 #[serde(default = "default_economic_sensitivity")]
7094 pub economic_sensitivity: f64,
7095}
7096
7097fn default_extension_rate() -> f64 {
7098 2.5
7099}
7100
7101fn default_economic_sensitivity() -> f64 {
7102 1.0
7103}
7104
7105impl Default for PaymentTermsDriftSchemaConfig {
7106 fn default() -> Self {
7107 Self {
7108 extension_rate_per_year: 2.5,
7109 economic_sensitivity: 1.0,
7110 }
7111 }
7112}
7113
7114#[derive(Debug, Clone, Serialize, Deserialize)]
7116pub struct QualityDriftSchemaConfig {
7117 #[serde(default = "default_improvement_rate")]
7119 pub new_vendor_improvement_rate: f64,
7120
7121 #[serde(default = "default_decline_rate")]
7123 pub complacency_decline_rate: f64,
7124}
7125
7126fn default_improvement_rate() -> f64 {
7127 0.02
7128}
7129
7130fn default_decline_rate() -> f64 {
7131 0.01
7132}
7133
7134impl Default for QualityDriftSchemaConfig {
7135 fn default() -> Self {
7136 Self {
7137 new_vendor_improvement_rate: 0.02,
7138 complacency_decline_rate: 0.01,
7139 }
7140 }
7141}
7142
7143#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7145pub struct CustomerBehaviorSchemaConfig {
7146 #[serde(default)]
7148 pub payment_drift: CustomerPaymentDriftSchemaConfig,
7149
7150 #[serde(default)]
7152 pub order_drift: OrderDriftSchemaConfig,
7153}
7154
7155#[derive(Debug, Clone, Serialize, Deserialize)]
7157pub struct CustomerPaymentDriftSchemaConfig {
7158 #[serde(default = "default_downturn_extension")]
7160 pub downturn_days_extension: (u32, u32),
7161
7162 #[serde(default = "default_bad_debt_increase")]
7164 pub downturn_bad_debt_increase: f64,
7165}
7166
7167fn default_downturn_extension() -> (u32, u32) {
7168 (5, 15)
7169}
7170
7171fn default_bad_debt_increase() -> f64 {
7172 0.02
7173}
7174
7175impl Default for CustomerPaymentDriftSchemaConfig {
7176 fn default() -> Self {
7177 Self {
7178 downturn_days_extension: (5, 15),
7179 downturn_bad_debt_increase: 0.02,
7180 }
7181 }
7182}
7183
7184#[derive(Debug, Clone, Serialize, Deserialize)]
7186pub struct OrderDriftSchemaConfig {
7187 #[serde(default = "default_digital_shift")]
7189 pub digital_shift_rate: f64,
7190}
7191
7192fn default_digital_shift() -> f64 {
7193 0.05
7194}
7195
7196impl Default for OrderDriftSchemaConfig {
7197 fn default() -> Self {
7198 Self {
7199 digital_shift_rate: 0.05,
7200 }
7201 }
7202}
7203
7204#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7206pub struct EmployeeBehaviorSchemaConfig {
7207 #[serde(default)]
7209 pub approval_drift: ApprovalDriftSchemaConfig,
7210
7211 #[serde(default)]
7213 pub error_drift: ErrorDriftSchemaConfig,
7214}
7215
7216#[derive(Debug, Clone, Serialize, Deserialize)]
7218pub struct ApprovalDriftSchemaConfig {
7219 #[serde(default = "default_eom_intensity")]
7221 pub eom_intensity_increase_per_year: f64,
7222
7223 #[serde(default = "default_rubber_stamp")]
7225 pub rubber_stamp_volume_threshold: u32,
7226}
7227
7228fn default_eom_intensity() -> f64 {
7229 0.05
7230}
7231
7232fn default_rubber_stamp() -> u32 {
7233 50
7234}
7235
7236impl Default for ApprovalDriftSchemaConfig {
7237 fn default() -> Self {
7238 Self {
7239 eom_intensity_increase_per_year: 0.05,
7240 rubber_stamp_volume_threshold: 50,
7241 }
7242 }
7243}
7244
7245#[derive(Debug, Clone, Serialize, Deserialize)]
7247pub struct ErrorDriftSchemaConfig {
7248 #[serde(default = "default_new_error")]
7250 pub new_employee_error_rate: f64,
7251
7252 #[serde(default = "default_learning_months")]
7254 pub learning_curve_months: u32,
7255}
7256
7257fn default_new_error() -> f64 {
7258 0.08
7259}
7260
7261fn default_learning_months() -> u32 {
7262 6
7263}
7264
7265impl Default for ErrorDriftSchemaConfig {
7266 fn default() -> Self {
7267 Self {
7268 new_employee_error_rate: 0.08,
7269 learning_curve_months: 6,
7270 }
7271 }
7272}
7273
7274#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7276pub struct CollectiveBehaviorSchemaConfig {
7277 #[serde(default)]
7279 pub automation_adoption: AutomationAdoptionSchemaConfig,
7280}
7281
7282#[derive(Debug, Clone, Serialize, Deserialize)]
7284pub struct AutomationAdoptionSchemaConfig {
7285 #[serde(default)]
7287 pub s_curve_enabled: bool,
7288
7289 #[serde(default = "default_midpoint")]
7291 pub adoption_midpoint_months: u32,
7292
7293 #[serde(default = "default_steepness")]
7295 pub steepness: f64,
7296}
7297
7298fn default_midpoint() -> u32 {
7299 24
7300}
7301
7302fn default_steepness() -> f64 {
7303 0.15
7304}
7305
7306impl Default for AutomationAdoptionSchemaConfig {
7307 fn default() -> Self {
7308 Self {
7309 s_curve_enabled: false,
7310 adoption_midpoint_months: 24,
7311 steepness: 0.15,
7312 }
7313 }
7314}
7315
7316#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7322pub struct MarketDriftSchemaConfig {
7323 #[serde(default)]
7325 pub enabled: bool,
7326
7327 #[serde(default)]
7329 pub economic_cycle: MarketEconomicCycleSchemaConfig,
7330
7331 #[serde(default)]
7333 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7334
7335 #[serde(default)]
7337 pub commodities: CommoditiesSchemaConfig,
7338}
7339
7340#[derive(Debug, Clone, Serialize, Deserialize)]
7342pub struct MarketEconomicCycleSchemaConfig {
7343 #[serde(default)]
7345 pub enabled: bool,
7346
7347 #[serde(default)]
7349 pub cycle_type: CycleTypeSchemaConfig,
7350
7351 #[serde(default = "default_market_cycle_period")]
7353 pub period_months: u32,
7354
7355 #[serde(default = "default_market_amplitude")]
7357 pub amplitude: f64,
7358
7359 #[serde(default)]
7361 pub recession: RecessionSchemaConfig,
7362}
7363
7364fn default_market_cycle_period() -> u32 {
7365 48
7366}
7367
7368fn default_market_amplitude() -> f64 {
7369 0.15
7370}
7371
7372impl Default for MarketEconomicCycleSchemaConfig {
7373 fn default() -> Self {
7374 Self {
7375 enabled: false,
7376 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7377 period_months: 48,
7378 amplitude: 0.15,
7379 recession: RecessionSchemaConfig::default(),
7380 }
7381 }
7382}
7383
7384#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7386#[serde(rename_all = "snake_case")]
7387pub enum CycleTypeSchemaConfig {
7388 #[default]
7390 Sinusoidal,
7391 Asymmetric,
7393 MeanReverting,
7395}
7396
7397#[derive(Debug, Clone, Serialize, Deserialize)]
7399pub struct RecessionSchemaConfig {
7400 #[serde(default)]
7402 pub enabled: bool,
7403
7404 #[serde(default = "default_recession_prob")]
7406 pub probability_per_year: f64,
7407
7408 #[serde(default)]
7410 pub severity: RecessionSeveritySchemaConfig,
7411
7412 #[serde(default)]
7414 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7415}
7416
7417fn default_recession_prob() -> f64 {
7418 0.10
7419}
7420
7421impl Default for RecessionSchemaConfig {
7422 fn default() -> Self {
7423 Self {
7424 enabled: false,
7425 probability_per_year: 0.10,
7426 severity: RecessionSeveritySchemaConfig::Moderate,
7427 recession_periods: Vec::new(),
7428 }
7429 }
7430}
7431
7432#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7434#[serde(rename_all = "snake_case")]
7435pub enum RecessionSeveritySchemaConfig {
7436 Mild,
7438 #[default]
7440 Moderate,
7441 Severe,
7443}
7444
7445#[derive(Debug, Clone, Serialize, Deserialize)]
7447pub struct RecessionPeriodSchemaConfig {
7448 pub start_month: u32,
7450 pub duration_months: u32,
7452}
7453
7454#[derive(Debug, Clone, Serialize, Deserialize)]
7456pub struct IndustryCycleSchemaConfig {
7457 #[serde(default = "default_industry_period")]
7459 pub period_months: u32,
7460
7461 #[serde(default = "default_industry_amp")]
7463 pub amplitude: f64,
7464}
7465
7466fn default_industry_period() -> u32 {
7467 36
7468}
7469
7470fn default_industry_amp() -> f64 {
7471 0.20
7472}
7473
7474#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7476pub struct CommoditiesSchemaConfig {
7477 #[serde(default)]
7479 pub enabled: bool,
7480
7481 #[serde(default)]
7483 pub items: Vec<CommodityItemSchemaConfig>,
7484}
7485
7486#[derive(Debug, Clone, Serialize, Deserialize)]
7488pub struct CommodityItemSchemaConfig {
7489 pub name: String,
7491
7492 #[serde(default = "default_volatility")]
7494 pub volatility: f64,
7495
7496 #[serde(default)]
7498 pub cogs_pass_through: f64,
7499
7500 #[serde(default)]
7502 pub overhead_pass_through: f64,
7503}
7504
7505fn default_volatility() -> f64 {
7506 0.20
7507}
7508
7509#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7515pub struct DriftLabelingSchemaConfig {
7516 #[serde(default)]
7518 pub enabled: bool,
7519
7520 #[serde(default)]
7522 pub statistical: StatisticalDriftLabelingSchemaConfig,
7523
7524 #[serde(default)]
7526 pub categorical: CategoricalDriftLabelingSchemaConfig,
7527
7528 #[serde(default)]
7530 pub temporal: TemporalDriftLabelingSchemaConfig,
7531
7532 #[serde(default)]
7534 pub regulatory_calendar_preset: Option<String>,
7535}
7536
7537#[derive(Debug, Clone, Serialize, Deserialize)]
7539pub struct StatisticalDriftLabelingSchemaConfig {
7540 #[serde(default = "default_true_val")]
7542 pub enabled: bool,
7543
7544 #[serde(default = "default_min_magnitude")]
7546 pub min_magnitude_threshold: f64,
7547}
7548
7549fn default_min_magnitude() -> f64 {
7550 0.05
7551}
7552
7553impl Default for StatisticalDriftLabelingSchemaConfig {
7554 fn default() -> Self {
7555 Self {
7556 enabled: true,
7557 min_magnitude_threshold: 0.05,
7558 }
7559 }
7560}
7561
7562#[derive(Debug, Clone, Serialize, Deserialize)]
7564pub struct CategoricalDriftLabelingSchemaConfig {
7565 #[serde(default = "default_true_val")]
7567 pub enabled: bool,
7568}
7569
7570impl Default for CategoricalDriftLabelingSchemaConfig {
7571 fn default() -> Self {
7572 Self { enabled: true }
7573 }
7574}
7575
7576#[derive(Debug, Clone, Serialize, Deserialize)]
7578pub struct TemporalDriftLabelingSchemaConfig {
7579 #[serde(default = "default_true_val")]
7581 pub enabled: bool,
7582}
7583
7584impl Default for TemporalDriftLabelingSchemaConfig {
7585 fn default() -> Self {
7586 Self { enabled: true }
7587 }
7588}
7589
7590#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7603pub struct EnhancedAnomalyConfig {
7604 #[serde(default)]
7606 pub enabled: bool,
7607
7608 #[serde(default)]
7610 pub rates: AnomalyRateConfig,
7611
7612 #[serde(default)]
7614 pub multi_stage_schemes: MultiStageSchemeConfig,
7615
7616 #[serde(default)]
7618 pub correlated_injection: CorrelatedInjectionConfig,
7619
7620 #[serde(default)]
7622 pub near_miss: NearMissConfig,
7623
7624 #[serde(default)]
7626 pub difficulty_classification: DifficultyClassificationConfig,
7627
7628 #[serde(default)]
7630 pub context_aware: ContextAwareConfig,
7631
7632 #[serde(default)]
7634 pub labeling: EnhancedLabelingConfig,
7635}
7636
7637#[derive(Debug, Clone, Serialize, Deserialize)]
7639pub struct AnomalyRateConfig {
7640 #[serde(default = "default_total_anomaly_rate")]
7642 pub total_rate: f64,
7643
7644 #[serde(default = "default_fraud_anomaly_rate")]
7646 pub fraud_rate: f64,
7647
7648 #[serde(default = "default_error_anomaly_rate")]
7650 pub error_rate: f64,
7651
7652 #[serde(default = "default_process_anomaly_rate")]
7654 pub process_rate: f64,
7655}
7656
7657fn default_total_anomaly_rate() -> f64 {
7658 0.03
7659}
7660fn default_fraud_anomaly_rate() -> f64 {
7661 0.01
7662}
7663fn default_error_anomaly_rate() -> f64 {
7664 0.015
7665}
7666fn default_process_anomaly_rate() -> f64 {
7667 0.005
7668}
7669
7670impl Default for AnomalyRateConfig {
7671 fn default() -> Self {
7672 Self {
7673 total_rate: default_total_anomaly_rate(),
7674 fraud_rate: default_fraud_anomaly_rate(),
7675 error_rate: default_error_anomaly_rate(),
7676 process_rate: default_process_anomaly_rate(),
7677 }
7678 }
7679}
7680
7681#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7683pub struct MultiStageSchemeConfig {
7684 #[serde(default)]
7686 pub enabled: bool,
7687
7688 #[serde(default)]
7690 pub embezzlement: EmbezzlementSchemeConfig,
7691
7692 #[serde(default)]
7694 pub revenue_manipulation: RevenueManipulationSchemeConfig,
7695
7696 #[serde(default)]
7698 pub kickback: KickbackSchemeConfig,
7699}
7700
7701#[derive(Debug, Clone, Serialize, Deserialize)]
7703pub struct EmbezzlementSchemeConfig {
7704 #[serde(default = "default_embezzlement_probability")]
7706 pub probability: f64,
7707
7708 #[serde(default)]
7710 pub testing_stage: SchemeStageConfig,
7711
7712 #[serde(default)]
7714 pub escalation_stage: SchemeStageConfig,
7715
7716 #[serde(default)]
7718 pub acceleration_stage: SchemeStageConfig,
7719
7720 #[serde(default)]
7722 pub desperation_stage: SchemeStageConfig,
7723}
7724
7725fn default_embezzlement_probability() -> f64 {
7726 0.02
7727}
7728
7729impl Default for EmbezzlementSchemeConfig {
7730 fn default() -> Self {
7731 Self {
7732 probability: default_embezzlement_probability(),
7733 testing_stage: SchemeStageConfig {
7734 duration_months: 2,
7735 amount_min: 100.0,
7736 amount_max: 500.0,
7737 transaction_count_min: 2,
7738 transaction_count_max: 5,
7739 difficulty: "hard".to_string(),
7740 },
7741 escalation_stage: SchemeStageConfig {
7742 duration_months: 6,
7743 amount_min: 500.0,
7744 amount_max: 2000.0,
7745 transaction_count_min: 3,
7746 transaction_count_max: 8,
7747 difficulty: "moderate".to_string(),
7748 },
7749 acceleration_stage: SchemeStageConfig {
7750 duration_months: 3,
7751 amount_min: 2000.0,
7752 amount_max: 10000.0,
7753 transaction_count_min: 5,
7754 transaction_count_max: 12,
7755 difficulty: "easy".to_string(),
7756 },
7757 desperation_stage: SchemeStageConfig {
7758 duration_months: 1,
7759 amount_min: 10000.0,
7760 amount_max: 50000.0,
7761 transaction_count_min: 3,
7762 transaction_count_max: 6,
7763 difficulty: "trivial".to_string(),
7764 },
7765 }
7766 }
7767}
7768
7769#[derive(Debug, Clone, Serialize, Deserialize)]
7771pub struct RevenueManipulationSchemeConfig {
7772 #[serde(default = "default_revenue_manipulation_probability")]
7774 pub probability: f64,
7775
7776 #[serde(default = "default_early_recognition_target")]
7778 pub early_recognition_target: f64,
7779
7780 #[serde(default = "default_expense_deferral_target")]
7782 pub expense_deferral_target: f64,
7783
7784 #[serde(default = "default_reserve_release_target")]
7786 pub reserve_release_target: f64,
7787
7788 #[serde(default = "default_channel_stuffing_target")]
7790 pub channel_stuffing_target: f64,
7791}
7792
7793fn default_revenue_manipulation_probability() -> f64 {
7794 0.01
7795}
7796fn default_early_recognition_target() -> f64 {
7797 0.02
7798}
7799fn default_expense_deferral_target() -> f64 {
7800 0.03
7801}
7802fn default_reserve_release_target() -> f64 {
7803 0.02
7804}
7805fn default_channel_stuffing_target() -> f64 {
7806 0.05
7807}
7808
7809impl Default for RevenueManipulationSchemeConfig {
7810 fn default() -> Self {
7811 Self {
7812 probability: default_revenue_manipulation_probability(),
7813 early_recognition_target: default_early_recognition_target(),
7814 expense_deferral_target: default_expense_deferral_target(),
7815 reserve_release_target: default_reserve_release_target(),
7816 channel_stuffing_target: default_channel_stuffing_target(),
7817 }
7818 }
7819}
7820
7821#[derive(Debug, Clone, Serialize, Deserialize)]
7823pub struct KickbackSchemeConfig {
7824 #[serde(default = "default_kickback_probability")]
7826 pub probability: f64,
7827
7828 #[serde(default = "default_kickback_inflation_min")]
7830 pub inflation_min: f64,
7831
7832 #[serde(default = "default_kickback_inflation_max")]
7834 pub inflation_max: f64,
7835
7836 #[serde(default = "default_kickback_percent")]
7838 pub kickback_percent: f64,
7839
7840 #[serde(default = "default_kickback_setup_months")]
7842 pub setup_months: u32,
7843
7844 #[serde(default = "default_kickback_operation_months")]
7846 pub operation_months: u32,
7847}
7848
7849fn default_kickback_probability() -> f64 {
7850 0.01
7851}
7852fn default_kickback_inflation_min() -> f64 {
7853 0.10
7854}
7855fn default_kickback_inflation_max() -> f64 {
7856 0.25
7857}
7858fn default_kickback_percent() -> f64 {
7859 0.50
7860}
7861fn default_kickback_setup_months() -> u32 {
7862 3
7863}
7864fn default_kickback_operation_months() -> u32 {
7865 12
7866}
7867
7868impl Default for KickbackSchemeConfig {
7869 fn default() -> Self {
7870 Self {
7871 probability: default_kickback_probability(),
7872 inflation_min: default_kickback_inflation_min(),
7873 inflation_max: default_kickback_inflation_max(),
7874 kickback_percent: default_kickback_percent(),
7875 setup_months: default_kickback_setup_months(),
7876 operation_months: default_kickback_operation_months(),
7877 }
7878 }
7879}
7880
7881#[derive(Debug, Clone, Serialize, Deserialize)]
7883pub struct SchemeStageConfig {
7884 pub duration_months: u32,
7886
7887 pub amount_min: f64,
7889
7890 pub amount_max: f64,
7892
7893 pub transaction_count_min: u32,
7895
7896 pub transaction_count_max: u32,
7898
7899 pub difficulty: String,
7901}
7902
7903impl Default for SchemeStageConfig {
7904 fn default() -> Self {
7905 Self {
7906 duration_months: 3,
7907 amount_min: 100.0,
7908 amount_max: 1000.0,
7909 transaction_count_min: 2,
7910 transaction_count_max: 10,
7911 difficulty: "moderate".to_string(),
7912 }
7913 }
7914}
7915
7916#[derive(Debug, Clone, Serialize, Deserialize)]
7918pub struct CorrelatedInjectionConfig {
7919 #[serde(default)]
7921 pub enabled: bool,
7922
7923 #[serde(default = "default_true_val")]
7925 pub fraud_concealment: bool,
7926
7927 #[serde(default = "default_true_val")]
7929 pub error_cascade: bool,
7930
7931 #[serde(default = "default_true_val")]
7933 pub temporal_clustering: bool,
7934
7935 #[serde(default)]
7937 pub temporal_clustering_config: TemporalClusteringConfig,
7938
7939 #[serde(default)]
7941 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
7942}
7943
7944impl Default for CorrelatedInjectionConfig {
7945 fn default() -> Self {
7946 Self {
7947 enabled: false,
7948 fraud_concealment: true,
7949 error_cascade: true,
7950 temporal_clustering: true,
7951 temporal_clustering_config: TemporalClusteringConfig::default(),
7952 co_occurrence_patterns: Vec::new(),
7953 }
7954 }
7955}
7956
7957#[derive(Debug, Clone, Serialize, Deserialize)]
7959pub struct TemporalClusteringConfig {
7960 #[serde(default = "default_period_end_multiplier")]
7962 pub period_end_multiplier: f64,
7963
7964 #[serde(default = "default_period_end_days")]
7966 pub period_end_days: u32,
7967
7968 #[serde(default = "default_quarter_end_multiplier")]
7970 pub quarter_end_multiplier: f64,
7971
7972 #[serde(default = "default_year_end_multiplier")]
7974 pub year_end_multiplier: f64,
7975}
7976
7977fn default_period_end_multiplier() -> f64 {
7978 2.5
7979}
7980fn default_period_end_days() -> u32 {
7981 5
7982}
7983fn default_quarter_end_multiplier() -> f64 {
7984 1.5
7985}
7986fn default_year_end_multiplier() -> f64 {
7987 2.0
7988}
7989
7990impl Default for TemporalClusteringConfig {
7991 fn default() -> Self {
7992 Self {
7993 period_end_multiplier: default_period_end_multiplier(),
7994 period_end_days: default_period_end_days(),
7995 quarter_end_multiplier: default_quarter_end_multiplier(),
7996 year_end_multiplier: default_year_end_multiplier(),
7997 }
7998 }
7999}
8000
8001#[derive(Debug, Clone, Serialize, Deserialize)]
8003pub struct CoOccurrencePatternConfig {
8004 pub name: String,
8006
8007 pub primary_type: String,
8009
8010 pub correlated: Vec<CorrelatedAnomalyConfig>,
8012}
8013
8014#[derive(Debug, Clone, Serialize, Deserialize)]
8016pub struct CorrelatedAnomalyConfig {
8017 pub anomaly_type: String,
8019
8020 pub probability: f64,
8022
8023 pub lag_days_min: i32,
8025
8026 pub lag_days_max: i32,
8028}
8029
8030#[derive(Debug, Clone, Serialize, Deserialize)]
8032pub struct NearMissConfig {
8033 #[serde(default)]
8035 pub enabled: bool,
8036
8037 #[serde(default = "default_near_miss_proportion")]
8039 pub proportion: f64,
8040
8041 #[serde(default = "default_true_val")]
8043 pub near_duplicate: bool,
8044
8045 #[serde(default)]
8047 pub near_duplicate_days: NearDuplicateDaysConfig,
8048
8049 #[serde(default = "default_true_val")]
8051 pub threshold_proximity: bool,
8052
8053 #[serde(default)]
8055 pub threshold_proximity_range: ThresholdProximityRangeConfig,
8056
8057 #[serde(default = "default_true_val")]
8059 pub unusual_legitimate: bool,
8060
8061 #[serde(default = "default_unusual_legitimate_types")]
8063 pub unusual_legitimate_types: Vec<String>,
8064
8065 #[serde(default = "default_true_val")]
8067 pub corrected_errors: bool,
8068
8069 #[serde(default)]
8071 pub corrected_error_lag: CorrectedErrorLagConfig,
8072}
8073
8074fn default_near_miss_proportion() -> f64 {
8075 0.30
8076}
8077
8078fn default_unusual_legitimate_types() -> Vec<String> {
8079 vec![
8080 "year_end_bonus".to_string(),
8081 "contract_prepayment".to_string(),
8082 "insurance_claim".to_string(),
8083 "settlement_payment".to_string(),
8084 ]
8085}
8086
8087impl Default for NearMissConfig {
8088 fn default() -> Self {
8089 Self {
8090 enabled: false,
8091 proportion: default_near_miss_proportion(),
8092 near_duplicate: true,
8093 near_duplicate_days: NearDuplicateDaysConfig::default(),
8094 threshold_proximity: true,
8095 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8096 unusual_legitimate: true,
8097 unusual_legitimate_types: default_unusual_legitimate_types(),
8098 corrected_errors: true,
8099 corrected_error_lag: CorrectedErrorLagConfig::default(),
8100 }
8101 }
8102}
8103
8104#[derive(Debug, Clone, Serialize, Deserialize)]
8106pub struct NearDuplicateDaysConfig {
8107 #[serde(default = "default_near_duplicate_min")]
8109 pub min: u32,
8110
8111 #[serde(default = "default_near_duplicate_max")]
8113 pub max: u32,
8114}
8115
8116fn default_near_duplicate_min() -> u32 {
8117 1
8118}
8119fn default_near_duplicate_max() -> u32 {
8120 3
8121}
8122
8123impl Default for NearDuplicateDaysConfig {
8124 fn default() -> Self {
8125 Self {
8126 min: default_near_duplicate_min(),
8127 max: default_near_duplicate_max(),
8128 }
8129 }
8130}
8131
8132#[derive(Debug, Clone, Serialize, Deserialize)]
8134pub struct ThresholdProximityRangeConfig {
8135 #[serde(default = "default_threshold_proximity_min")]
8137 pub min: f64,
8138
8139 #[serde(default = "default_threshold_proximity_max")]
8141 pub max: f64,
8142}
8143
8144fn default_threshold_proximity_min() -> f64 {
8145 0.90
8146}
8147fn default_threshold_proximity_max() -> f64 {
8148 0.99
8149}
8150
8151impl Default for ThresholdProximityRangeConfig {
8152 fn default() -> Self {
8153 Self {
8154 min: default_threshold_proximity_min(),
8155 max: default_threshold_proximity_max(),
8156 }
8157 }
8158}
8159
8160#[derive(Debug, Clone, Serialize, Deserialize)]
8162pub struct CorrectedErrorLagConfig {
8163 #[serde(default = "default_corrected_error_lag_min")]
8165 pub min: u32,
8166
8167 #[serde(default = "default_corrected_error_lag_max")]
8169 pub max: u32,
8170}
8171
8172fn default_corrected_error_lag_min() -> u32 {
8173 1
8174}
8175fn default_corrected_error_lag_max() -> u32 {
8176 5
8177}
8178
8179impl Default for CorrectedErrorLagConfig {
8180 fn default() -> Self {
8181 Self {
8182 min: default_corrected_error_lag_min(),
8183 max: default_corrected_error_lag_max(),
8184 }
8185 }
8186}
8187
8188#[derive(Debug, Clone, Serialize, Deserialize)]
8190pub struct DifficultyClassificationConfig {
8191 #[serde(default)]
8193 pub enabled: bool,
8194
8195 #[serde(default)]
8197 pub target_distribution: DifficultyDistributionConfig,
8198}
8199
8200impl Default for DifficultyClassificationConfig {
8201 fn default() -> Self {
8202 Self {
8203 enabled: true,
8204 target_distribution: DifficultyDistributionConfig::default(),
8205 }
8206 }
8207}
8208
8209#[derive(Debug, Clone, Serialize, Deserialize)]
8211pub struct DifficultyDistributionConfig {
8212 #[serde(default = "default_difficulty_trivial")]
8214 pub trivial: f64,
8215
8216 #[serde(default = "default_difficulty_easy")]
8218 pub easy: f64,
8219
8220 #[serde(default = "default_difficulty_moderate")]
8222 pub moderate: f64,
8223
8224 #[serde(default = "default_difficulty_hard")]
8226 pub hard: f64,
8227
8228 #[serde(default = "default_difficulty_expert")]
8230 pub expert: f64,
8231}
8232
8233fn default_difficulty_trivial() -> f64 {
8234 0.15
8235}
8236fn default_difficulty_easy() -> f64 {
8237 0.25
8238}
8239fn default_difficulty_moderate() -> f64 {
8240 0.30
8241}
8242fn default_difficulty_hard() -> f64 {
8243 0.20
8244}
8245fn default_difficulty_expert() -> f64 {
8246 0.10
8247}
8248
8249impl Default for DifficultyDistributionConfig {
8250 fn default() -> Self {
8251 Self {
8252 trivial: default_difficulty_trivial(),
8253 easy: default_difficulty_easy(),
8254 moderate: default_difficulty_moderate(),
8255 hard: default_difficulty_hard(),
8256 expert: default_difficulty_expert(),
8257 }
8258 }
8259}
8260
8261#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8263pub struct ContextAwareConfig {
8264 #[serde(default)]
8266 pub enabled: bool,
8267
8268 #[serde(default)]
8270 pub vendor_rules: VendorAnomalyRulesConfig,
8271
8272 #[serde(default)]
8274 pub employee_rules: EmployeeAnomalyRulesConfig,
8275
8276 #[serde(default)]
8278 pub account_rules: AccountAnomalyRulesConfig,
8279
8280 #[serde(default)]
8282 pub behavioral_baseline: BehavioralBaselineConfig,
8283}
8284
8285#[derive(Debug, Clone, Serialize, Deserialize)]
8287pub struct VendorAnomalyRulesConfig {
8288 #[serde(default = "default_new_vendor_multiplier")]
8290 pub new_vendor_error_multiplier: f64,
8291
8292 #[serde(default = "default_new_vendor_threshold")]
8294 pub new_vendor_threshold_days: u32,
8295
8296 #[serde(default = "default_international_multiplier")]
8298 pub international_error_multiplier: f64,
8299
8300 #[serde(default = "default_strategic_vendor_types")]
8302 pub strategic_vendor_anomaly_types: Vec<String>,
8303}
8304
8305fn default_new_vendor_multiplier() -> f64 {
8306 2.5
8307}
8308fn default_new_vendor_threshold() -> u32 {
8309 90
8310}
8311fn default_international_multiplier() -> f64 {
8312 1.5
8313}
8314fn default_strategic_vendor_types() -> Vec<String> {
8315 vec![
8316 "pricing_dispute".to_string(),
8317 "contract_violation".to_string(),
8318 ]
8319}
8320
8321impl Default for VendorAnomalyRulesConfig {
8322 fn default() -> Self {
8323 Self {
8324 new_vendor_error_multiplier: default_new_vendor_multiplier(),
8325 new_vendor_threshold_days: default_new_vendor_threshold(),
8326 international_error_multiplier: default_international_multiplier(),
8327 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8328 }
8329 }
8330}
8331
8332#[derive(Debug, Clone, Serialize, Deserialize)]
8334pub struct EmployeeAnomalyRulesConfig {
8335 #[serde(default = "default_new_employee_rate")]
8337 pub new_employee_error_rate: f64,
8338
8339 #[serde(default = "default_new_employee_threshold")]
8341 pub new_employee_threshold_days: u32,
8342
8343 #[serde(default = "default_volume_fatigue_threshold")]
8345 pub volume_fatigue_threshold: u32,
8346
8347 #[serde(default = "default_coverage_multiplier")]
8349 pub coverage_error_multiplier: f64,
8350}
8351
8352fn default_new_employee_rate() -> f64 {
8353 0.05
8354}
8355fn default_new_employee_threshold() -> u32 {
8356 180
8357}
8358fn default_volume_fatigue_threshold() -> u32 {
8359 50
8360}
8361fn default_coverage_multiplier() -> f64 {
8362 1.8
8363}
8364
8365impl Default for EmployeeAnomalyRulesConfig {
8366 fn default() -> Self {
8367 Self {
8368 new_employee_error_rate: default_new_employee_rate(),
8369 new_employee_threshold_days: default_new_employee_threshold(),
8370 volume_fatigue_threshold: default_volume_fatigue_threshold(),
8371 coverage_error_multiplier: default_coverage_multiplier(),
8372 }
8373 }
8374}
8375
8376#[derive(Debug, Clone, Serialize, Deserialize)]
8378pub struct AccountAnomalyRulesConfig {
8379 #[serde(default = "default_high_risk_multiplier")]
8381 pub high_risk_account_multiplier: f64,
8382
8383 #[serde(default = "default_high_risk_accounts")]
8385 pub high_risk_accounts: Vec<String>,
8386
8387 #[serde(default = "default_suspense_multiplier")]
8389 pub suspense_account_multiplier: f64,
8390
8391 #[serde(default = "default_suspense_accounts")]
8393 pub suspense_accounts: Vec<String>,
8394
8395 #[serde(default = "default_intercompany_multiplier")]
8397 pub intercompany_account_multiplier: f64,
8398}
8399
8400fn default_high_risk_multiplier() -> f64 {
8401 2.0
8402}
8403fn default_high_risk_accounts() -> Vec<String> {
8404 vec![
8405 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
8409}
8410fn default_suspense_multiplier() -> f64 {
8411 3.0
8412}
8413fn default_suspense_accounts() -> Vec<String> {
8414 vec!["9999".to_string(), "9998".to_string()]
8415}
8416fn default_intercompany_multiplier() -> f64 {
8417 1.5
8418}
8419
8420impl Default for AccountAnomalyRulesConfig {
8421 fn default() -> Self {
8422 Self {
8423 high_risk_account_multiplier: default_high_risk_multiplier(),
8424 high_risk_accounts: default_high_risk_accounts(),
8425 suspense_account_multiplier: default_suspense_multiplier(),
8426 suspense_accounts: default_suspense_accounts(),
8427 intercompany_account_multiplier: default_intercompany_multiplier(),
8428 }
8429 }
8430}
8431
8432#[derive(Debug, Clone, Serialize, Deserialize)]
8434pub struct BehavioralBaselineConfig {
8435 #[serde(default)]
8437 pub enabled: bool,
8438
8439 #[serde(default = "default_baseline_period")]
8441 pub baseline_period_days: u32,
8442
8443 #[serde(default = "default_deviation_threshold")]
8445 pub deviation_threshold_std: f64,
8446
8447 #[serde(default = "default_frequency_deviation")]
8449 pub frequency_deviation_threshold: f64,
8450}
8451
8452fn default_baseline_period() -> u32 {
8453 90
8454}
8455fn default_deviation_threshold() -> f64 {
8456 3.0
8457}
8458fn default_frequency_deviation() -> f64 {
8459 2.0
8460}
8461
8462impl Default for BehavioralBaselineConfig {
8463 fn default() -> Self {
8464 Self {
8465 enabled: false,
8466 baseline_period_days: default_baseline_period(),
8467 deviation_threshold_std: default_deviation_threshold(),
8468 frequency_deviation_threshold: default_frequency_deviation(),
8469 }
8470 }
8471}
8472
8473#[derive(Debug, Clone, Serialize, Deserialize)]
8475pub struct EnhancedLabelingConfig {
8476 #[serde(default = "default_true_val")]
8478 pub severity_scoring: bool,
8479
8480 #[serde(default = "default_true_val")]
8482 pub difficulty_classification: bool,
8483
8484 #[serde(default)]
8486 pub materiality_thresholds: MaterialityThresholdsConfig,
8487}
8488
8489impl Default for EnhancedLabelingConfig {
8490 fn default() -> Self {
8491 Self {
8492 severity_scoring: true,
8493 difficulty_classification: true,
8494 materiality_thresholds: MaterialityThresholdsConfig::default(),
8495 }
8496 }
8497}
8498
8499#[derive(Debug, Clone, Serialize, Deserialize)]
8501pub struct MaterialityThresholdsConfig {
8502 #[serde(default = "default_materiality_trivial")]
8504 pub trivial: f64,
8505
8506 #[serde(default = "default_materiality_immaterial")]
8508 pub immaterial: f64,
8509
8510 #[serde(default = "default_materiality_material")]
8512 pub material: f64,
8513
8514 #[serde(default = "default_materiality_highly_material")]
8516 pub highly_material: f64,
8517}
8518
8519fn default_materiality_trivial() -> f64 {
8520 0.001
8521}
8522fn default_materiality_immaterial() -> f64 {
8523 0.01
8524}
8525fn default_materiality_material() -> f64 {
8526 0.05
8527}
8528fn default_materiality_highly_material() -> f64 {
8529 0.10
8530}
8531
8532impl Default for MaterialityThresholdsConfig {
8533 fn default() -> Self {
8534 Self {
8535 trivial: default_materiality_trivial(),
8536 immaterial: default_materiality_immaterial(),
8537 material: default_materiality_material(),
8538 highly_material: default_materiality_highly_material(),
8539 }
8540 }
8541}
8542
8543#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8555pub struct IndustrySpecificConfig {
8556 #[serde(default)]
8558 pub enabled: bool,
8559
8560 #[serde(default)]
8562 pub manufacturing: ManufacturingConfig,
8563
8564 #[serde(default)]
8566 pub retail: RetailConfig,
8567
8568 #[serde(default)]
8570 pub healthcare: HealthcareConfig,
8571
8572 #[serde(default)]
8574 pub technology: TechnologyConfig,
8575
8576 #[serde(default)]
8578 pub financial_services: FinancialServicesConfig,
8579
8580 #[serde(default)]
8582 pub professional_services: ProfessionalServicesConfig,
8583}
8584
8585#[derive(Debug, Clone, Serialize, Deserialize)]
8587pub struct ManufacturingConfig {
8588 #[serde(default)]
8590 pub enabled: bool,
8591
8592 #[serde(default = "default_bom_depth")]
8594 pub bom_depth: u32,
8595
8596 #[serde(default)]
8598 pub just_in_time: bool,
8599
8600 #[serde(default = "default_production_order_types")]
8602 pub production_order_types: Vec<String>,
8603
8604 #[serde(default)]
8606 pub quality_framework: Option<String>,
8607
8608 #[serde(default = "default_supplier_tiers")]
8610 pub supplier_tiers: u32,
8611
8612 #[serde(default = "default_cost_frequency")]
8614 pub standard_cost_frequency: String,
8615
8616 #[serde(default = "default_yield_rate")]
8618 pub target_yield_rate: f64,
8619
8620 #[serde(default = "default_scrap_threshold")]
8622 pub scrap_alert_threshold: f64,
8623
8624 #[serde(default)]
8626 pub anomaly_rates: ManufacturingAnomalyRates,
8627}
8628
8629fn default_bom_depth() -> u32 {
8630 4
8631}
8632
8633fn default_production_order_types() -> Vec<String> {
8634 vec![
8635 "standard".to_string(),
8636 "rework".to_string(),
8637 "prototype".to_string(),
8638 ]
8639}
8640
8641fn default_supplier_tiers() -> u32 {
8642 2
8643}
8644
8645fn default_cost_frequency() -> String {
8646 "quarterly".to_string()
8647}
8648
8649fn default_yield_rate() -> f64 {
8650 0.97
8651}
8652
8653fn default_scrap_threshold() -> f64 {
8654 0.03
8655}
8656
8657impl Default for ManufacturingConfig {
8658 fn default() -> Self {
8659 Self {
8660 enabled: false,
8661 bom_depth: default_bom_depth(),
8662 just_in_time: false,
8663 production_order_types: default_production_order_types(),
8664 quality_framework: Some("ISO_9001".to_string()),
8665 supplier_tiers: default_supplier_tiers(),
8666 standard_cost_frequency: default_cost_frequency(),
8667 target_yield_rate: default_yield_rate(),
8668 scrap_alert_threshold: default_scrap_threshold(),
8669 anomaly_rates: ManufacturingAnomalyRates::default(),
8670 }
8671 }
8672}
8673
8674#[derive(Debug, Clone, Serialize, Deserialize)]
8676pub struct ManufacturingAnomalyRates {
8677 #[serde(default = "default_mfg_yield_rate")]
8679 pub yield_manipulation: f64,
8680
8681 #[serde(default = "default_mfg_labor_rate")]
8683 pub labor_misallocation: f64,
8684
8685 #[serde(default = "default_mfg_phantom_rate")]
8687 pub phantom_production: f64,
8688
8689 #[serde(default = "default_mfg_cost_rate")]
8691 pub standard_cost_manipulation: f64,
8692
8693 #[serde(default = "default_mfg_inventory_rate")]
8695 pub inventory_fraud: f64,
8696}
8697
8698fn default_mfg_yield_rate() -> f64 {
8699 0.015
8700}
8701
8702fn default_mfg_labor_rate() -> f64 {
8703 0.02
8704}
8705
8706fn default_mfg_phantom_rate() -> f64 {
8707 0.005
8708}
8709
8710fn default_mfg_cost_rate() -> f64 {
8711 0.01
8712}
8713
8714fn default_mfg_inventory_rate() -> f64 {
8715 0.008
8716}
8717
8718impl Default for ManufacturingAnomalyRates {
8719 fn default() -> Self {
8720 Self {
8721 yield_manipulation: default_mfg_yield_rate(),
8722 labor_misallocation: default_mfg_labor_rate(),
8723 phantom_production: default_mfg_phantom_rate(),
8724 standard_cost_manipulation: default_mfg_cost_rate(),
8725 inventory_fraud: default_mfg_inventory_rate(),
8726 }
8727 }
8728}
8729
8730#[derive(Debug, Clone, Serialize, Deserialize)]
8732pub struct RetailConfig {
8733 #[serde(default)]
8735 pub enabled: bool,
8736
8737 #[serde(default)]
8739 pub store_types: RetailStoreTypeConfig,
8740
8741 #[serde(default = "default_retail_daily_txns")]
8743 pub avg_daily_transactions: u32,
8744
8745 #[serde(default = "default_true")]
8747 pub loss_prevention: bool,
8748
8749 #[serde(default = "default_shrinkage_rate")]
8751 pub shrinkage_rate: f64,
8752
8753 #[serde(default)]
8755 pub anomaly_rates: RetailAnomalyRates,
8756}
8757
8758fn default_retail_daily_txns() -> u32 {
8759 500
8760}
8761
8762fn default_shrinkage_rate() -> f64 {
8763 0.015
8764}
8765
8766impl Default for RetailConfig {
8767 fn default() -> Self {
8768 Self {
8769 enabled: false,
8770 store_types: RetailStoreTypeConfig::default(),
8771 avg_daily_transactions: default_retail_daily_txns(),
8772 loss_prevention: true,
8773 shrinkage_rate: default_shrinkage_rate(),
8774 anomaly_rates: RetailAnomalyRates::default(),
8775 }
8776 }
8777}
8778
8779#[derive(Debug, Clone, Serialize, Deserialize)]
8781pub struct RetailStoreTypeConfig {
8782 #[serde(default = "default_flagship_pct")]
8784 pub flagship: f64,
8785
8786 #[serde(default = "default_regional_pct")]
8788 pub regional: f64,
8789
8790 #[serde(default = "default_outlet_pct")]
8792 pub outlet: f64,
8793
8794 #[serde(default = "default_ecommerce_pct")]
8796 pub ecommerce: f64,
8797}
8798
8799fn default_flagship_pct() -> f64 {
8800 0.10
8801}
8802
8803fn default_regional_pct() -> f64 {
8804 0.50
8805}
8806
8807fn default_outlet_pct() -> f64 {
8808 0.25
8809}
8810
8811fn default_ecommerce_pct() -> f64 {
8812 0.15
8813}
8814
8815impl Default for RetailStoreTypeConfig {
8816 fn default() -> Self {
8817 Self {
8818 flagship: default_flagship_pct(),
8819 regional: default_regional_pct(),
8820 outlet: default_outlet_pct(),
8821 ecommerce: default_ecommerce_pct(),
8822 }
8823 }
8824}
8825
8826#[derive(Debug, Clone, Serialize, Deserialize)]
8828pub struct RetailAnomalyRates {
8829 #[serde(default = "default_sweethearting_rate")]
8831 pub sweethearting: f64,
8832
8833 #[serde(default = "default_skimming_rate")]
8835 pub skimming: f64,
8836
8837 #[serde(default = "default_refund_fraud_rate")]
8839 pub refund_fraud: f64,
8840
8841 #[serde(default = "default_void_abuse_rate")]
8843 pub void_abuse: f64,
8844
8845 #[serde(default = "default_gift_card_rate")]
8847 pub gift_card_fraud: f64,
8848
8849 #[serde(default = "default_retail_kickback_rate")]
8851 pub vendor_kickback: f64,
8852}
8853
8854fn default_sweethearting_rate() -> f64 {
8855 0.02
8856}
8857
8858fn default_skimming_rate() -> f64 {
8859 0.005
8860}
8861
8862fn default_refund_fraud_rate() -> f64 {
8863 0.015
8864}
8865
8866fn default_void_abuse_rate() -> f64 {
8867 0.01
8868}
8869
8870fn default_gift_card_rate() -> f64 {
8871 0.008
8872}
8873
8874fn default_retail_kickback_rate() -> f64 {
8875 0.003
8876}
8877
8878impl Default for RetailAnomalyRates {
8879 fn default() -> Self {
8880 Self {
8881 sweethearting: default_sweethearting_rate(),
8882 skimming: default_skimming_rate(),
8883 refund_fraud: default_refund_fraud_rate(),
8884 void_abuse: default_void_abuse_rate(),
8885 gift_card_fraud: default_gift_card_rate(),
8886 vendor_kickback: default_retail_kickback_rate(),
8887 }
8888 }
8889}
8890
8891#[derive(Debug, Clone, Serialize, Deserialize)]
8893pub struct HealthcareConfig {
8894 #[serde(default)]
8896 pub enabled: bool,
8897
8898 #[serde(default = "default_facility_type")]
8900 pub facility_type: String,
8901
8902 #[serde(default)]
8904 pub payer_mix: HealthcarePayerMix,
8905
8906 #[serde(default)]
8908 pub coding_systems: HealthcareCodingSystems,
8909
8910 #[serde(default)]
8912 pub compliance: HealthcareComplianceConfig,
8913
8914 #[serde(default = "default_daily_encounters")]
8916 pub avg_daily_encounters: u32,
8917
8918 #[serde(default = "default_charges_per_encounter")]
8920 pub avg_charges_per_encounter: u32,
8921
8922 #[serde(default = "default_hc_denial_rate")]
8924 pub denial_rate: f64,
8925
8926 #[serde(default = "default_hc_bad_debt_rate")]
8928 pub bad_debt_rate: f64,
8929
8930 #[serde(default = "default_hc_charity_care_rate")]
8932 pub charity_care_rate: f64,
8933
8934 #[serde(default)]
8936 pub anomaly_rates: HealthcareAnomalyRates,
8937}
8938
8939fn default_facility_type() -> String {
8940 "hospital".to_string()
8941}
8942
8943fn default_daily_encounters() -> u32 {
8944 150
8945}
8946
8947fn default_charges_per_encounter() -> u32 {
8948 8
8949}
8950
8951fn default_hc_denial_rate() -> f64 {
8952 0.05
8953}
8954
8955fn default_hc_bad_debt_rate() -> f64 {
8956 0.03
8957}
8958
8959fn default_hc_charity_care_rate() -> f64 {
8960 0.02
8961}
8962
8963impl Default for HealthcareConfig {
8964 fn default() -> Self {
8965 Self {
8966 enabled: false,
8967 facility_type: default_facility_type(),
8968 payer_mix: HealthcarePayerMix::default(),
8969 coding_systems: HealthcareCodingSystems::default(),
8970 compliance: HealthcareComplianceConfig::default(),
8971 avg_daily_encounters: default_daily_encounters(),
8972 avg_charges_per_encounter: default_charges_per_encounter(),
8973 denial_rate: default_hc_denial_rate(),
8974 bad_debt_rate: default_hc_bad_debt_rate(),
8975 charity_care_rate: default_hc_charity_care_rate(),
8976 anomaly_rates: HealthcareAnomalyRates::default(),
8977 }
8978 }
8979}
8980
8981#[derive(Debug, Clone, Serialize, Deserialize)]
8983pub struct HealthcarePayerMix {
8984 #[serde(default = "default_medicare_pct")]
8986 pub medicare: f64,
8987
8988 #[serde(default = "default_medicaid_pct")]
8990 pub medicaid: f64,
8991
8992 #[serde(default = "default_commercial_pct")]
8994 pub commercial: f64,
8995
8996 #[serde(default = "default_self_pay_pct")]
8998 pub self_pay: f64,
8999}
9000
9001fn default_medicare_pct() -> f64 {
9002 0.40
9003}
9004
9005fn default_medicaid_pct() -> f64 {
9006 0.20
9007}
9008
9009fn default_commercial_pct() -> f64 {
9010 0.30
9011}
9012
9013fn default_self_pay_pct() -> f64 {
9014 0.10
9015}
9016
9017impl Default for HealthcarePayerMix {
9018 fn default() -> Self {
9019 Self {
9020 medicare: default_medicare_pct(),
9021 medicaid: default_medicaid_pct(),
9022 commercial: default_commercial_pct(),
9023 self_pay: default_self_pay_pct(),
9024 }
9025 }
9026}
9027
9028#[derive(Debug, Clone, Serialize, Deserialize)]
9030pub struct HealthcareCodingSystems {
9031 #[serde(default = "default_true")]
9033 pub icd10: bool,
9034
9035 #[serde(default = "default_true")]
9037 pub cpt: bool,
9038
9039 #[serde(default = "default_true")]
9041 pub drg: bool,
9042
9043 #[serde(default = "default_true")]
9045 pub hcpcs: bool,
9046
9047 #[serde(default = "default_true")]
9049 pub revenue_codes: bool,
9050}
9051
9052impl Default for HealthcareCodingSystems {
9053 fn default() -> Self {
9054 Self {
9055 icd10: true,
9056 cpt: true,
9057 drg: true,
9058 hcpcs: true,
9059 revenue_codes: true,
9060 }
9061 }
9062}
9063
9064#[derive(Debug, Clone, Serialize, Deserialize)]
9066pub struct HealthcareComplianceConfig {
9067 #[serde(default = "default_true")]
9069 pub hipaa: bool,
9070
9071 #[serde(default = "default_true")]
9073 pub stark_law: bool,
9074
9075 #[serde(default = "default_true")]
9077 pub anti_kickback: bool,
9078
9079 #[serde(default = "default_true")]
9081 pub false_claims_act: bool,
9082
9083 #[serde(default = "default_true")]
9085 pub emtala: bool,
9086}
9087
9088impl Default for HealthcareComplianceConfig {
9089 fn default() -> Self {
9090 Self {
9091 hipaa: true,
9092 stark_law: true,
9093 anti_kickback: true,
9094 false_claims_act: true,
9095 emtala: true,
9096 }
9097 }
9098}
9099
9100#[derive(Debug, Clone, Serialize, Deserialize)]
9102pub struct HealthcareAnomalyRates {
9103 #[serde(default = "default_upcoding_rate")]
9105 pub upcoding: f64,
9106
9107 #[serde(default = "default_unbundling_rate")]
9109 pub unbundling: f64,
9110
9111 #[serde(default = "default_phantom_billing_rate")]
9113 pub phantom_billing: f64,
9114
9115 #[serde(default = "default_healthcare_kickback_rate")]
9117 pub kickbacks: f64,
9118
9119 #[serde(default = "default_duplicate_billing_rate")]
9121 pub duplicate_billing: f64,
9122
9123 #[serde(default = "default_med_necessity_rate")]
9125 pub medical_necessity_abuse: f64,
9126}
9127
9128fn default_upcoding_rate() -> f64 {
9129 0.02
9130}
9131
9132fn default_unbundling_rate() -> f64 {
9133 0.015
9134}
9135
9136fn default_phantom_billing_rate() -> f64 {
9137 0.005
9138}
9139
9140fn default_healthcare_kickback_rate() -> f64 {
9141 0.003
9142}
9143
9144fn default_duplicate_billing_rate() -> f64 {
9145 0.008
9146}
9147
9148fn default_med_necessity_rate() -> f64 {
9149 0.01
9150}
9151
9152impl Default for HealthcareAnomalyRates {
9153 fn default() -> Self {
9154 Self {
9155 upcoding: default_upcoding_rate(),
9156 unbundling: default_unbundling_rate(),
9157 phantom_billing: default_phantom_billing_rate(),
9158 kickbacks: default_healthcare_kickback_rate(),
9159 duplicate_billing: default_duplicate_billing_rate(),
9160 medical_necessity_abuse: default_med_necessity_rate(),
9161 }
9162 }
9163}
9164
9165#[derive(Debug, Clone, Serialize, Deserialize)]
9167pub struct TechnologyConfig {
9168 #[serde(default)]
9170 pub enabled: bool,
9171
9172 #[serde(default = "default_revenue_model")]
9174 pub revenue_model: String,
9175
9176 #[serde(default = "default_subscription_pct")]
9178 pub subscription_revenue_pct: f64,
9179
9180 #[serde(default = "default_license_pct")]
9182 pub license_revenue_pct: f64,
9183
9184 #[serde(default = "default_services_pct")]
9186 pub services_revenue_pct: f64,
9187
9188 #[serde(default)]
9190 pub rd_capitalization: RdCapitalizationConfig,
9191
9192 #[serde(default)]
9194 pub anomaly_rates: TechnologyAnomalyRates,
9195}
9196
9197fn default_revenue_model() -> String {
9198 "saas".to_string()
9199}
9200
9201fn default_subscription_pct() -> f64 {
9202 0.60
9203}
9204
9205fn default_license_pct() -> f64 {
9206 0.25
9207}
9208
9209fn default_services_pct() -> f64 {
9210 0.15
9211}
9212
9213impl Default for TechnologyConfig {
9214 fn default() -> Self {
9215 Self {
9216 enabled: false,
9217 revenue_model: default_revenue_model(),
9218 subscription_revenue_pct: default_subscription_pct(),
9219 license_revenue_pct: default_license_pct(),
9220 services_revenue_pct: default_services_pct(),
9221 rd_capitalization: RdCapitalizationConfig::default(),
9222 anomaly_rates: TechnologyAnomalyRates::default(),
9223 }
9224 }
9225}
9226
9227#[derive(Debug, Clone, Serialize, Deserialize)]
9229pub struct RdCapitalizationConfig {
9230 #[serde(default = "default_true")]
9232 pub enabled: bool,
9233
9234 #[serde(default = "default_cap_rate")]
9236 pub capitalization_rate: f64,
9237
9238 #[serde(default = "default_useful_life")]
9240 pub useful_life_years: u32,
9241}
9242
9243fn default_cap_rate() -> f64 {
9244 0.30
9245}
9246
9247fn default_useful_life() -> u32 {
9248 3
9249}
9250
9251impl Default for RdCapitalizationConfig {
9252 fn default() -> Self {
9253 Self {
9254 enabled: true,
9255 capitalization_rate: default_cap_rate(),
9256 useful_life_years: default_useful_life(),
9257 }
9258 }
9259}
9260
9261#[derive(Debug, Clone, Serialize, Deserialize)]
9263pub struct TechnologyAnomalyRates {
9264 #[serde(default = "default_premature_rev_rate")]
9266 pub premature_revenue: f64,
9267
9268 #[serde(default = "default_side_letter_rate")]
9270 pub side_letter_abuse: f64,
9271
9272 #[serde(default = "default_channel_stuffing_rate")]
9274 pub channel_stuffing: f64,
9275
9276 #[serde(default = "default_improper_cap_rate")]
9278 pub improper_capitalization: f64,
9279}
9280
9281fn default_premature_rev_rate() -> f64 {
9282 0.015
9283}
9284
9285fn default_side_letter_rate() -> f64 {
9286 0.008
9287}
9288
9289fn default_channel_stuffing_rate() -> f64 {
9290 0.01
9291}
9292
9293fn default_improper_cap_rate() -> f64 {
9294 0.012
9295}
9296
9297impl Default for TechnologyAnomalyRates {
9298 fn default() -> Self {
9299 Self {
9300 premature_revenue: default_premature_rev_rate(),
9301 side_letter_abuse: default_side_letter_rate(),
9302 channel_stuffing: default_channel_stuffing_rate(),
9303 improper_capitalization: default_improper_cap_rate(),
9304 }
9305 }
9306}
9307
9308#[derive(Debug, Clone, Serialize, Deserialize)]
9310pub struct FinancialServicesConfig {
9311 #[serde(default)]
9313 pub enabled: bool,
9314
9315 #[serde(default = "default_fi_type")]
9317 pub institution_type: String,
9318
9319 #[serde(default = "default_fi_regulatory")]
9321 pub regulatory_framework: String,
9322
9323 #[serde(default)]
9325 pub anomaly_rates: FinancialServicesAnomalyRates,
9326}
9327
9328fn default_fi_type() -> String {
9329 "commercial_bank".to_string()
9330}
9331
9332fn default_fi_regulatory() -> String {
9333 "us_banking".to_string()
9334}
9335
9336impl Default for FinancialServicesConfig {
9337 fn default() -> Self {
9338 Self {
9339 enabled: false,
9340 institution_type: default_fi_type(),
9341 regulatory_framework: default_fi_regulatory(),
9342 anomaly_rates: FinancialServicesAnomalyRates::default(),
9343 }
9344 }
9345}
9346
9347#[derive(Debug, Clone, Serialize, Deserialize)]
9349pub struct FinancialServicesAnomalyRates {
9350 #[serde(default = "default_loan_fraud_rate")]
9352 pub loan_fraud: f64,
9353
9354 #[serde(default = "default_trading_fraud_rate")]
9356 pub trading_fraud: f64,
9357
9358 #[serde(default = "default_insurance_fraud_rate")]
9360 pub insurance_fraud: f64,
9361
9362 #[serde(default = "default_account_manip_rate")]
9364 pub account_manipulation: f64,
9365}
9366
9367fn default_loan_fraud_rate() -> f64 {
9368 0.01
9369}
9370
9371fn default_trading_fraud_rate() -> f64 {
9372 0.008
9373}
9374
9375fn default_insurance_fraud_rate() -> f64 {
9376 0.012
9377}
9378
9379fn default_account_manip_rate() -> f64 {
9380 0.005
9381}
9382
9383impl Default for FinancialServicesAnomalyRates {
9384 fn default() -> Self {
9385 Self {
9386 loan_fraud: default_loan_fraud_rate(),
9387 trading_fraud: default_trading_fraud_rate(),
9388 insurance_fraud: default_insurance_fraud_rate(),
9389 account_manipulation: default_account_manip_rate(),
9390 }
9391 }
9392}
9393
9394#[derive(Debug, Clone, Serialize, Deserialize)]
9396pub struct ProfessionalServicesConfig {
9397 #[serde(default)]
9399 pub enabled: bool,
9400
9401 #[serde(default = "default_firm_type")]
9403 pub firm_type: String,
9404
9405 #[serde(default = "default_billing_model")]
9407 pub billing_model: String,
9408
9409 #[serde(default = "default_hourly_rate")]
9411 pub avg_hourly_rate: f64,
9412
9413 #[serde(default)]
9415 pub trust_accounting: TrustAccountingConfig,
9416
9417 #[serde(default)]
9419 pub anomaly_rates: ProfessionalServicesAnomalyRates,
9420}
9421
9422fn default_firm_type() -> String {
9423 "consulting".to_string()
9424}
9425
9426fn default_billing_model() -> String {
9427 "time_and_materials".to_string()
9428}
9429
9430fn default_hourly_rate() -> f64 {
9431 250.0
9432}
9433
9434impl Default for ProfessionalServicesConfig {
9435 fn default() -> Self {
9436 Self {
9437 enabled: false,
9438 firm_type: default_firm_type(),
9439 billing_model: default_billing_model(),
9440 avg_hourly_rate: default_hourly_rate(),
9441 trust_accounting: TrustAccountingConfig::default(),
9442 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9443 }
9444 }
9445}
9446
9447#[derive(Debug, Clone, Serialize, Deserialize)]
9449pub struct TrustAccountingConfig {
9450 #[serde(default)]
9452 pub enabled: bool,
9453
9454 #[serde(default = "default_true")]
9456 pub require_three_way_reconciliation: bool,
9457}
9458
9459impl Default for TrustAccountingConfig {
9460 fn default() -> Self {
9461 Self {
9462 enabled: false,
9463 require_three_way_reconciliation: true,
9464 }
9465 }
9466}
9467
9468#[derive(Debug, Clone, Serialize, Deserialize)]
9470pub struct ProfessionalServicesAnomalyRates {
9471 #[serde(default = "default_time_fraud_rate")]
9473 pub time_billing_fraud: f64,
9474
9475 #[serde(default = "default_expense_fraud_rate")]
9477 pub expense_fraud: f64,
9478
9479 #[serde(default = "default_trust_misappropriation_rate")]
9481 pub trust_misappropriation: f64,
9482}
9483
9484fn default_time_fraud_rate() -> f64 {
9485 0.02
9486}
9487
9488fn default_expense_fraud_rate() -> f64 {
9489 0.015
9490}
9491
9492fn default_trust_misappropriation_rate() -> f64 {
9493 0.003
9494}
9495
9496impl Default for ProfessionalServicesAnomalyRates {
9497 fn default() -> Self {
9498 Self {
9499 time_billing_fraud: default_time_fraud_rate(),
9500 expense_fraud: default_expense_fraud_rate(),
9501 trust_misappropriation: default_trust_misappropriation_rate(),
9502 }
9503 }
9504}
9505
9506#[cfg(test)]
9507mod tests {
9508 use super::*;
9509 use crate::presets::demo_preset;
9510
9511 #[test]
9516 fn test_config_yaml_roundtrip() {
9517 let config = demo_preset();
9518 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9519 let deserialized: GeneratorConfig =
9520 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9521
9522 assert_eq!(
9523 config.global.period_months,
9524 deserialized.global.period_months
9525 );
9526 assert_eq!(config.global.industry, deserialized.global.industry);
9527 assert_eq!(config.companies.len(), deserialized.companies.len());
9528 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9529 }
9530
9531 #[test]
9532 fn test_config_json_roundtrip() {
9533 let mut config = demo_preset();
9535 config.master_data.employees.approval_limits.executive = 1e12;
9537
9538 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9539 let deserialized: GeneratorConfig =
9540 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9541
9542 assert_eq!(
9543 config.global.period_months,
9544 deserialized.global.period_months
9545 );
9546 assert_eq!(config.global.industry, deserialized.global.industry);
9547 assert_eq!(config.companies.len(), deserialized.companies.len());
9548 }
9549
9550 #[test]
9551 fn test_transaction_volume_serialization() {
9552 let volumes = vec![
9554 (TransactionVolume::TenK, "ten_k"),
9555 (TransactionVolume::HundredK, "hundred_k"),
9556 (TransactionVolume::OneM, "one_m"),
9557 (TransactionVolume::TenM, "ten_m"),
9558 (TransactionVolume::HundredM, "hundred_m"),
9559 ];
9560
9561 for (volume, expected_key) in volumes {
9562 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9563 assert!(
9564 json.contains(expected_key),
9565 "Expected {} in JSON: {}",
9566 expected_key,
9567 json
9568 );
9569 }
9570 }
9571
9572 #[test]
9573 fn test_transaction_volume_custom_serialization() {
9574 let volume = TransactionVolume::Custom(12345);
9575 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9576 let deserialized: TransactionVolume =
9577 serde_json::from_str(&json).expect("Failed to deserialize");
9578 assert_eq!(deserialized.count(), 12345);
9579 }
9580
9581 #[test]
9582 fn test_output_mode_serialization() {
9583 let modes = vec![
9584 OutputMode::Streaming,
9585 OutputMode::FlatFile,
9586 OutputMode::Both,
9587 ];
9588
9589 for mode in modes {
9590 let json = serde_json::to_string(&mode).expect("Failed to serialize");
9591 let deserialized: OutputMode =
9592 serde_json::from_str(&json).expect("Failed to deserialize");
9593 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9594 }
9595 }
9596
9597 #[test]
9598 fn test_file_format_serialization() {
9599 let formats = vec![
9600 FileFormat::Csv,
9601 FileFormat::Parquet,
9602 FileFormat::Json,
9603 FileFormat::JsonLines,
9604 ];
9605
9606 for format in formats {
9607 let json = serde_json::to_string(&format).expect("Failed to serialize");
9608 let deserialized: FileFormat =
9609 serde_json::from_str(&json).expect("Failed to deserialize");
9610 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
9611 }
9612 }
9613
9614 #[test]
9615 fn test_compression_algorithm_serialization() {
9616 let algos = vec![
9617 CompressionAlgorithm::Gzip,
9618 CompressionAlgorithm::Zstd,
9619 CompressionAlgorithm::Lz4,
9620 CompressionAlgorithm::Snappy,
9621 ];
9622
9623 for algo in algos {
9624 let json = serde_json::to_string(&algo).expect("Failed to serialize");
9625 let deserialized: CompressionAlgorithm =
9626 serde_json::from_str(&json).expect("Failed to deserialize");
9627 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
9628 }
9629 }
9630
9631 #[test]
9632 fn test_transfer_pricing_method_serialization() {
9633 let methods = vec![
9634 TransferPricingMethod::CostPlus,
9635 TransferPricingMethod::ComparableUncontrolled,
9636 TransferPricingMethod::ResalePrice,
9637 TransferPricingMethod::TransactionalNetMargin,
9638 TransferPricingMethod::ProfitSplit,
9639 ];
9640
9641 for method in methods {
9642 let json = serde_json::to_string(&method).expect("Failed to serialize");
9643 let deserialized: TransferPricingMethod =
9644 serde_json::from_str(&json).expect("Failed to deserialize");
9645 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
9646 }
9647 }
9648
9649 #[test]
9650 fn test_benford_exemption_serialization() {
9651 let exemptions = vec![
9652 BenfordExemption::Recurring,
9653 BenfordExemption::Payroll,
9654 BenfordExemption::FixedFees,
9655 BenfordExemption::RoundAmounts,
9656 ];
9657
9658 for exemption in exemptions {
9659 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
9660 let deserialized: BenfordExemption =
9661 serde_json::from_str(&json).expect("Failed to deserialize");
9662 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
9663 }
9664 }
9665
9666 #[test]
9671 fn test_global_config_defaults() {
9672 let yaml = r#"
9673 industry: manufacturing
9674 start_date: "2024-01-01"
9675 period_months: 6
9676 "#;
9677 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9678 assert_eq!(config.group_currency, "USD");
9679 assert!(config.parallel);
9680 assert_eq!(config.worker_threads, 0);
9681 assert_eq!(config.memory_limit_mb, 0);
9682 }
9683
9684 #[test]
9685 fn test_fraud_config_defaults() {
9686 let config = FraudConfig::default();
9687 assert!(!config.enabled);
9688 assert_eq!(config.fraud_rate, 0.005);
9689 assert!(!config.clustering_enabled);
9690 }
9691
9692 #[test]
9693 fn test_internal_controls_config_defaults() {
9694 let config = InternalControlsConfig::default();
9695 assert!(!config.enabled);
9696 assert_eq!(config.exception_rate, 0.02);
9697 assert_eq!(config.sod_violation_rate, 0.01);
9698 assert!(config.export_control_master_data);
9699 assert_eq!(config.sox_materiality_threshold, 10000.0);
9700 assert!(config.coso_enabled);
9702 assert!(!config.include_entity_level_controls);
9703 assert_eq!(config.target_maturity_level, "mixed");
9704 }
9705
9706 #[test]
9707 fn test_output_config_defaults() {
9708 let config = OutputConfig::default();
9709 assert!(matches!(config.mode, OutputMode::FlatFile));
9710 assert_eq!(config.formats, vec![FileFormat::Parquet]);
9711 assert!(config.compression.enabled);
9712 assert!(matches!(
9713 config.compression.algorithm,
9714 CompressionAlgorithm::Zstd
9715 ));
9716 assert!(config.include_acdoca);
9717 assert!(!config.include_bseg);
9718 assert!(config.partition_by_period);
9719 assert!(!config.partition_by_company);
9720 }
9721
9722 #[test]
9723 fn test_approval_config_defaults() {
9724 let config = ApprovalConfig::default();
9725 assert!(!config.enabled);
9726 assert_eq!(config.auto_approve_threshold, 1000.0);
9727 assert_eq!(config.rejection_rate, 0.02);
9728 assert_eq!(config.revision_rate, 0.05);
9729 assert_eq!(config.average_approval_delay_hours, 4.0);
9730 assert_eq!(config.thresholds.len(), 4);
9731 }
9732
9733 #[test]
9734 fn test_p2p_flow_config_defaults() {
9735 let config = P2PFlowConfig::default();
9736 assert!(config.enabled);
9737 assert_eq!(config.three_way_match_rate, 0.95);
9738 assert_eq!(config.partial_delivery_rate, 0.15);
9739 assert_eq!(config.average_po_to_gr_days, 14);
9740 }
9741
9742 #[test]
9743 fn test_o2c_flow_config_defaults() {
9744 let config = O2CFlowConfig::default();
9745 assert!(config.enabled);
9746 assert_eq!(config.credit_check_failure_rate, 0.02);
9747 assert_eq!(config.return_rate, 0.03);
9748 assert_eq!(config.bad_debt_rate, 0.01);
9749 }
9750
9751 #[test]
9752 fn test_balance_config_defaults() {
9753 let config = BalanceConfig::default();
9754 assert!(!config.generate_opening_balances);
9755 assert!(config.generate_trial_balances);
9756 assert_eq!(config.target_gross_margin, 0.35);
9757 assert!(config.validate_balance_equation);
9758 assert!(config.reconcile_subledgers);
9759 }
9760
9761 #[test]
9766 fn test_partial_config_with_defaults() {
9767 let yaml = r#"
9769 global:
9770 industry: manufacturing
9771 start_date: "2024-01-01"
9772 period_months: 3
9773 companies:
9774 - code: "TEST"
9775 name: "Test Company"
9776 currency: "USD"
9777 country: "US"
9778 annual_transaction_volume: ten_k
9779 chart_of_accounts:
9780 complexity: small
9781 output:
9782 output_directory: "./output"
9783 "#;
9784
9785 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9786 assert_eq!(config.global.period_months, 3);
9787 assert_eq!(config.companies.len(), 1);
9788 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
9791
9792 #[test]
9793 fn test_config_with_fraud_enabled() {
9794 let yaml = r#"
9795 global:
9796 industry: retail
9797 start_date: "2024-01-01"
9798 period_months: 12
9799 companies:
9800 - code: "RETAIL"
9801 name: "Retail Co"
9802 currency: "USD"
9803 country: "US"
9804 annual_transaction_volume: hundred_k
9805 chart_of_accounts:
9806 complexity: medium
9807 output:
9808 output_directory: "./output"
9809 fraud:
9810 enabled: true
9811 fraud_rate: 0.05
9812 clustering_enabled: true
9813 "#;
9814
9815 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9816 assert!(config.fraud.enabled);
9817 assert_eq!(config.fraud.fraud_rate, 0.05);
9818 assert!(config.fraud.clustering_enabled);
9819 }
9820
9821 #[test]
9822 fn test_config_with_multiple_companies() {
9823 let yaml = r#"
9824 global:
9825 industry: manufacturing
9826 start_date: "2024-01-01"
9827 period_months: 6
9828 companies:
9829 - code: "HQ"
9830 name: "Headquarters"
9831 currency: "USD"
9832 country: "US"
9833 annual_transaction_volume: hundred_k
9834 volume_weight: 1.0
9835 - code: "EU"
9836 name: "European Subsidiary"
9837 currency: "EUR"
9838 country: "DE"
9839 annual_transaction_volume: hundred_k
9840 volume_weight: 0.5
9841 - code: "APAC"
9842 name: "Asia Pacific"
9843 currency: "JPY"
9844 country: "JP"
9845 annual_transaction_volume: ten_k
9846 volume_weight: 0.3
9847 chart_of_accounts:
9848 complexity: large
9849 output:
9850 output_directory: "./output"
9851 "#;
9852
9853 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9854 assert_eq!(config.companies.len(), 3);
9855 assert_eq!(config.companies[0].code, "HQ");
9856 assert_eq!(config.companies[1].currency, "EUR");
9857 assert_eq!(config.companies[2].volume_weight, 0.3);
9858 }
9859
9860 #[test]
9861 fn test_intercompany_config() {
9862 let yaml = r#"
9863 enabled: true
9864 ic_transaction_rate: 0.20
9865 transfer_pricing_method: cost_plus
9866 markup_percent: 0.08
9867 generate_matched_pairs: true
9868 generate_eliminations: true
9869 "#;
9870
9871 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9872 assert!(config.enabled);
9873 assert_eq!(config.ic_transaction_rate, 0.20);
9874 assert!(matches!(
9875 config.transfer_pricing_method,
9876 TransferPricingMethod::CostPlus
9877 ));
9878 assert_eq!(config.markup_percent, 0.08);
9879 assert!(config.generate_eliminations);
9880 }
9881
9882 #[test]
9887 fn test_company_config_defaults() {
9888 let yaml = r#"
9889 code: "TEST"
9890 name: "Test Company"
9891 currency: "USD"
9892 country: "US"
9893 annual_transaction_volume: ten_k
9894 "#;
9895
9896 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9897 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
9900
9901 #[test]
9906 fn test_coa_config_defaults() {
9907 let yaml = r#"
9908 complexity: medium
9909 "#;
9910
9911 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9912 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
9914 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
9917
9918 #[test]
9923 fn test_accounting_standards_config_defaults() {
9924 let config = AccountingStandardsConfig::default();
9925 assert!(!config.enabled);
9926 assert!(matches!(
9927 config.framework,
9928 AccountingFrameworkConfig::UsGaap
9929 ));
9930 assert!(!config.revenue_recognition.enabled);
9931 assert!(!config.leases.enabled);
9932 assert!(!config.fair_value.enabled);
9933 assert!(!config.impairment.enabled);
9934 assert!(!config.generate_differences);
9935 }
9936
9937 #[test]
9938 fn test_accounting_standards_config_yaml() {
9939 let yaml = r#"
9940 enabled: true
9941 framework: ifrs
9942 revenue_recognition:
9943 enabled: true
9944 generate_contracts: true
9945 avg_obligations_per_contract: 2.5
9946 variable_consideration_rate: 0.20
9947 over_time_recognition_rate: 0.35
9948 contract_count: 150
9949 leases:
9950 enabled: true
9951 lease_count: 75
9952 finance_lease_percent: 0.25
9953 avg_lease_term_months: 48
9954 generate_differences: true
9955 "#;
9956
9957 let config: AccountingStandardsConfig =
9958 serde_yaml::from_str(yaml).expect("Failed to parse");
9959 assert!(config.enabled);
9960 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
9961 assert!(config.revenue_recognition.enabled);
9962 assert_eq!(config.revenue_recognition.contract_count, 150);
9963 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
9964 assert!(config.leases.enabled);
9965 assert_eq!(config.leases.lease_count, 75);
9966 assert_eq!(config.leases.finance_lease_percent, 0.25);
9967 assert!(config.generate_differences);
9968 }
9969
9970 #[test]
9971 fn test_accounting_framework_serialization() {
9972 let frameworks = [
9973 AccountingFrameworkConfig::UsGaap,
9974 AccountingFrameworkConfig::Ifrs,
9975 AccountingFrameworkConfig::DualReporting,
9976 ];
9977
9978 for framework in frameworks {
9979 let json = serde_json::to_string(&framework).expect("Failed to serialize");
9980 let deserialized: AccountingFrameworkConfig =
9981 serde_json::from_str(&json).expect("Failed to deserialize");
9982 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
9983 }
9984 }
9985
9986 #[test]
9987 fn test_revenue_recognition_config_defaults() {
9988 let config = RevenueRecognitionConfig::default();
9989 assert!(!config.enabled);
9990 assert!(config.generate_contracts);
9991 assert_eq!(config.avg_obligations_per_contract, 2.0);
9992 assert_eq!(config.variable_consideration_rate, 0.15);
9993 assert_eq!(config.over_time_recognition_rate, 0.30);
9994 assert_eq!(config.contract_count, 100);
9995 }
9996
9997 #[test]
9998 fn test_lease_accounting_config_defaults() {
9999 let config = LeaseAccountingConfig::default();
10000 assert!(!config.enabled);
10001 assert_eq!(config.lease_count, 50);
10002 assert_eq!(config.finance_lease_percent, 0.30);
10003 assert_eq!(config.avg_lease_term_months, 60);
10004 assert!(config.generate_amortization);
10005 assert_eq!(config.real_estate_percent, 0.40);
10006 }
10007
10008 #[test]
10009 fn test_fair_value_config_defaults() {
10010 let config = FairValueConfig::default();
10011 assert!(!config.enabled);
10012 assert_eq!(config.measurement_count, 25);
10013 assert_eq!(config.level1_percent, 0.40);
10014 assert_eq!(config.level2_percent, 0.35);
10015 assert_eq!(config.level3_percent, 0.25);
10016 assert!(!config.include_sensitivity_analysis);
10017 }
10018
10019 #[test]
10020 fn test_impairment_config_defaults() {
10021 let config = ImpairmentConfig::default();
10022 assert!(!config.enabled);
10023 assert_eq!(config.test_count, 15);
10024 assert_eq!(config.impairment_rate, 0.10);
10025 assert!(config.generate_projections);
10026 assert!(!config.include_goodwill);
10027 }
10028
10029 #[test]
10034 fn test_audit_standards_config_defaults() {
10035 let config = AuditStandardsConfig::default();
10036 assert!(!config.enabled);
10037 assert!(!config.isa_compliance.enabled);
10038 assert!(!config.analytical_procedures.enabled);
10039 assert!(!config.confirmations.enabled);
10040 assert!(!config.opinion.enabled);
10041 assert!(!config.generate_audit_trail);
10042 assert!(!config.sox.enabled);
10043 assert!(!config.pcaob.enabled);
10044 }
10045
10046 #[test]
10047 fn test_audit_standards_config_yaml() {
10048 let yaml = r#"
10049 enabled: true
10050 isa_compliance:
10051 enabled: true
10052 compliance_level: comprehensive
10053 generate_isa_mappings: true
10054 include_pcaob: true
10055 framework: dual
10056 analytical_procedures:
10057 enabled: true
10058 procedures_per_account: 5
10059 variance_probability: 0.25
10060 confirmations:
10061 enabled: true
10062 confirmation_count: 75
10063 positive_response_rate: 0.90
10064 exception_rate: 0.08
10065 opinion:
10066 enabled: true
10067 generate_kam: true
10068 average_kam_count: 4
10069 sox:
10070 enabled: true
10071 generate_302_certifications: true
10072 generate_404_assessments: true
10073 material_weakness_rate: 0.03
10074 pcaob:
10075 enabled: true
10076 is_pcaob_audit: true
10077 include_icfr_opinion: true
10078 generate_audit_trail: true
10079 "#;
10080
10081 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10082 assert!(config.enabled);
10083 assert!(config.isa_compliance.enabled);
10084 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
10085 assert!(config.isa_compliance.include_pcaob);
10086 assert_eq!(config.isa_compliance.framework, "dual");
10087 assert!(config.analytical_procedures.enabled);
10088 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
10089 assert!(config.confirmations.enabled);
10090 assert_eq!(config.confirmations.confirmation_count, 75);
10091 assert!(config.opinion.enabled);
10092 assert_eq!(config.opinion.average_kam_count, 4);
10093 assert!(config.sox.enabled);
10094 assert!(config.sox.generate_302_certifications);
10095 assert_eq!(config.sox.material_weakness_rate, 0.03);
10096 assert!(config.pcaob.enabled);
10097 assert!(config.pcaob.is_pcaob_audit);
10098 assert!(config.pcaob.include_icfr_opinion);
10099 assert!(config.generate_audit_trail);
10100 }
10101
10102 #[test]
10103 fn test_isa_compliance_config_defaults() {
10104 let config = IsaComplianceConfig::default();
10105 assert!(!config.enabled);
10106 assert_eq!(config.compliance_level, "standard");
10107 assert!(config.generate_isa_mappings);
10108 assert!(config.generate_coverage_summary);
10109 assert!(!config.include_pcaob);
10110 assert_eq!(config.framework, "isa");
10111 }
10112
10113 #[test]
10114 fn test_sox_compliance_config_defaults() {
10115 let config = SoxComplianceConfig::default();
10116 assert!(!config.enabled);
10117 assert!(config.generate_302_certifications);
10118 assert!(config.generate_404_assessments);
10119 assert_eq!(config.materiality_threshold, 10000.0);
10120 assert_eq!(config.material_weakness_rate, 0.02);
10121 assert_eq!(config.significant_deficiency_rate, 0.08);
10122 }
10123
10124 #[test]
10125 fn test_pcaob_config_defaults() {
10126 let config = PcaobConfig::default();
10127 assert!(!config.enabled);
10128 assert!(!config.is_pcaob_audit);
10129 assert!(config.generate_cam);
10130 assert!(!config.include_icfr_opinion);
10131 assert!(!config.generate_standard_mappings);
10132 }
10133
10134 #[test]
10135 fn test_config_with_standards_enabled() {
10136 let yaml = r#"
10137 global:
10138 industry: financial_services
10139 start_date: "2024-01-01"
10140 period_months: 12
10141 companies:
10142 - code: "BANK"
10143 name: "Test Bank"
10144 currency: "USD"
10145 country: "US"
10146 annual_transaction_volume: hundred_k
10147 chart_of_accounts:
10148 complexity: large
10149 output:
10150 output_directory: "./output"
10151 accounting_standards:
10152 enabled: true
10153 framework: us_gaap
10154 revenue_recognition:
10155 enabled: true
10156 leases:
10157 enabled: true
10158 audit_standards:
10159 enabled: true
10160 isa_compliance:
10161 enabled: true
10162 sox:
10163 enabled: true
10164 "#;
10165
10166 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10167 assert!(config.accounting_standards.enabled);
10168 assert!(matches!(
10169 config.accounting_standards.framework,
10170 AccountingFrameworkConfig::UsGaap
10171 ));
10172 assert!(config.accounting_standards.revenue_recognition.enabled);
10173 assert!(config.accounting_standards.leases.enabled);
10174 assert!(config.audit_standards.enabled);
10175 assert!(config.audit_standards.isa_compliance.enabled);
10176 assert!(config.audit_standards.sox.enabled);
10177 }
10178
10179 #[test]
10184 fn test_industry_specific_config_defaults() {
10185 let config = IndustrySpecificConfig::default();
10186 assert!(!config.enabled);
10187 assert!(!config.manufacturing.enabled);
10188 assert!(!config.retail.enabled);
10189 assert!(!config.healthcare.enabled);
10190 assert!(!config.technology.enabled);
10191 assert!(!config.financial_services.enabled);
10192 assert!(!config.professional_services.enabled);
10193 }
10194
10195 #[test]
10196 fn test_manufacturing_config_defaults() {
10197 let config = ManufacturingConfig::default();
10198 assert!(!config.enabled);
10199 assert_eq!(config.bom_depth, 4);
10200 assert!(!config.just_in_time);
10201 assert_eq!(config.supplier_tiers, 2);
10202 assert_eq!(config.target_yield_rate, 0.97);
10203 assert_eq!(config.scrap_alert_threshold, 0.03);
10204 }
10205
10206 #[test]
10207 fn test_retail_config_defaults() {
10208 let config = RetailConfig::default();
10209 assert!(!config.enabled);
10210 assert_eq!(config.avg_daily_transactions, 500);
10211 assert!(config.loss_prevention);
10212 assert_eq!(config.shrinkage_rate, 0.015);
10213 }
10214
10215 #[test]
10216 fn test_healthcare_config_defaults() {
10217 let config = HealthcareConfig::default();
10218 assert!(!config.enabled);
10219 assert_eq!(config.facility_type, "hospital");
10220 assert_eq!(config.avg_daily_encounters, 150);
10221 assert!(config.compliance.hipaa);
10222 assert!(config.compliance.stark_law);
10223 assert!(config.coding_systems.icd10);
10224 assert!(config.coding_systems.cpt);
10225 }
10226
10227 #[test]
10228 fn test_technology_config_defaults() {
10229 let config = TechnologyConfig::default();
10230 assert!(!config.enabled);
10231 assert_eq!(config.revenue_model, "saas");
10232 assert_eq!(config.subscription_revenue_pct, 0.60);
10233 assert!(config.rd_capitalization.enabled);
10234 }
10235
10236 #[test]
10237 fn test_config_with_industry_specific() {
10238 let yaml = r#"
10239 global:
10240 industry: healthcare
10241 start_date: "2024-01-01"
10242 period_months: 12
10243 companies:
10244 - code: "HOSP"
10245 name: "Test Hospital"
10246 currency: "USD"
10247 country: "US"
10248 annual_transaction_volume: hundred_k
10249 chart_of_accounts:
10250 complexity: medium
10251 output:
10252 output_directory: "./output"
10253 industry_specific:
10254 enabled: true
10255 healthcare:
10256 enabled: true
10257 facility_type: hospital
10258 payer_mix:
10259 medicare: 0.45
10260 medicaid: 0.15
10261 commercial: 0.35
10262 self_pay: 0.05
10263 coding_systems:
10264 icd10: true
10265 cpt: true
10266 drg: true
10267 compliance:
10268 hipaa: true
10269 stark_law: true
10270 anomaly_rates:
10271 upcoding: 0.03
10272 unbundling: 0.02
10273 "#;
10274
10275 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10276 assert!(config.industry_specific.enabled);
10277 assert!(config.industry_specific.healthcare.enabled);
10278 assert_eq!(
10279 config.industry_specific.healthcare.facility_type,
10280 "hospital"
10281 );
10282 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10283 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10284 assert!(config.industry_specific.healthcare.coding_systems.icd10);
10285 assert!(config.industry_specific.healthcare.compliance.hipaa);
10286 assert_eq!(
10287 config.industry_specific.healthcare.anomaly_rates.upcoding,
10288 0.03
10289 );
10290 }
10291
10292 #[test]
10293 fn test_config_with_manufacturing_specific() {
10294 let yaml = r#"
10295 global:
10296 industry: manufacturing
10297 start_date: "2024-01-01"
10298 period_months: 12
10299 companies:
10300 - code: "MFG"
10301 name: "Test Manufacturing"
10302 currency: "USD"
10303 country: "US"
10304 annual_transaction_volume: hundred_k
10305 chart_of_accounts:
10306 complexity: medium
10307 output:
10308 output_directory: "./output"
10309 industry_specific:
10310 enabled: true
10311 manufacturing:
10312 enabled: true
10313 bom_depth: 5
10314 just_in_time: true
10315 supplier_tiers: 3
10316 target_yield_rate: 0.98
10317 anomaly_rates:
10318 yield_manipulation: 0.02
10319 phantom_production: 0.01
10320 "#;
10321
10322 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10323 assert!(config.industry_specific.enabled);
10324 assert!(config.industry_specific.manufacturing.enabled);
10325 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10326 assert!(config.industry_specific.manufacturing.just_in_time);
10327 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10328 assert_eq!(
10329 config.industry_specific.manufacturing.target_yield_rate,
10330 0.98
10331 );
10332 assert_eq!(
10333 config
10334 .industry_specific
10335 .manufacturing
10336 .anomaly_rates
10337 .yield_manipulation,
10338 0.02
10339 );
10340 }
10341}