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
172fn default_graph_types() -> Vec<GraphTypeConfig> {
173 vec![GraphTypeConfig::default()]
174}
175
176fn default_graph_formats() -> Vec<GraphExportFormat> {
177 vec![GraphExportFormat::PytorchGeometric]
178}
179
180fn default_train_ratio() -> f64 {
181 0.7
182}
183
184fn default_val_ratio() -> f64 {
185 0.15
186}
187
188fn default_graph_subdir() -> String {
189 "graphs".to_string()
190}
191
192impl Default for GraphExportConfig {
193 fn default() -> Self {
194 Self {
195 enabled: false,
196 graph_types: default_graph_types(),
197 formats: default_graph_formats(),
198 train_ratio: 0.7,
199 validation_ratio: 0.15,
200 split_seed: None,
201 output_subdirectory: "graphs".to_string(),
202 }
203 }
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct GraphTypeConfig {
209 #[serde(default = "default_graph_name")]
211 pub name: String,
212
213 #[serde(default)]
215 pub aggregate_edges: bool,
216
217 #[serde(default)]
219 pub min_edge_weight: f64,
220
221 #[serde(default)]
223 pub include_document_nodes: bool,
224}
225
226fn default_graph_name() -> String {
227 "accounting_network".to_string()
228}
229
230impl Default for GraphTypeConfig {
231 fn default() -> Self {
232 Self {
233 name: "accounting_network".to_string(),
234 aggregate_edges: false,
235 min_edge_weight: 0.0,
236 include_document_nodes: false,
237 }
238 }
239}
240
241#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
243#[serde(rename_all = "snake_case")]
244pub enum GraphExportFormat {
245 PytorchGeometric,
247 Neo4j,
249 Dgl,
251 RustGraph,
253}
254
255#[derive(Debug, Clone, Default, Serialize, Deserialize)]
259pub struct ScenarioConfig {
260 #[serde(default)]
263 pub tags: Vec<String>,
264
265 #[serde(default)]
270 pub profile: Option<String>,
271
272 #[serde(default)]
274 pub description: Option<String>,
275
276 #[serde(default)]
278 pub ml_training: bool,
279
280 #[serde(default)]
283 pub target_anomaly_ratio: Option<f64>,
284
285 #[serde(default)]
287 pub metadata: std::collections::HashMap<String, String>,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct TemporalDriftConfig {
296 #[serde(default)]
298 pub enabled: bool,
299
300 #[serde(default = "default_amount_drift")]
303 pub amount_mean_drift: f64,
304
305 #[serde(default)]
308 pub amount_variance_drift: f64,
309
310 #[serde(default)]
313 pub anomaly_rate_drift: f64,
314
315 #[serde(default = "default_concept_drift")]
318 pub concept_drift_rate: f64,
319
320 #[serde(default)]
322 pub sudden_drift_probability: f64,
323
324 #[serde(default = "default_sudden_drift_magnitude")]
326 pub sudden_drift_magnitude: f64,
327
328 #[serde(default)]
330 pub seasonal_drift: bool,
331
332 #[serde(default)]
334 pub drift_start_period: u32,
335
336 #[serde(default = "default_drift_type")]
338 pub drift_type: DriftType,
339}
340
341fn default_amount_drift() -> f64 {
342 0.02
343}
344
345fn default_concept_drift() -> f64 {
346 0.01
347}
348
349fn default_sudden_drift_magnitude() -> f64 {
350 2.0
351}
352
353fn default_drift_type() -> DriftType {
354 DriftType::Gradual
355}
356
357impl Default for TemporalDriftConfig {
358 fn default() -> Self {
359 Self {
360 enabled: false,
361 amount_mean_drift: 0.02,
362 amount_variance_drift: 0.0,
363 anomaly_rate_drift: 0.0,
364 concept_drift_rate: 0.01,
365 sudden_drift_probability: 0.0,
366 sudden_drift_magnitude: 2.0,
367 seasonal_drift: false,
368 drift_start_period: 0,
369 drift_type: DriftType::Gradual,
370 }
371 }
372}
373
374impl TemporalDriftConfig {
375 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
377 datasynth_core::distributions::DriftConfig {
378 enabled: self.enabled,
379 amount_mean_drift: self.amount_mean_drift,
380 amount_variance_drift: self.amount_variance_drift,
381 anomaly_rate_drift: self.anomaly_rate_drift,
382 concept_drift_rate: self.concept_drift_rate,
383 sudden_drift_probability: self.sudden_drift_probability,
384 sudden_drift_magnitude: self.sudden_drift_magnitude,
385 seasonal_drift: self.seasonal_drift,
386 drift_start_period: self.drift_start_period,
387 drift_type: match self.drift_type {
388 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
389 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
390 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
391 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
392 },
393 regime_changes: Vec::new(),
394 economic_cycle: Default::default(),
395 parameter_drifts: Vec::new(),
396 }
397 }
398}
399
400#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
402#[serde(rename_all = "snake_case")]
403pub enum DriftType {
404 #[default]
406 Gradual,
407 Sudden,
409 Recurring,
411 Mixed,
413}
414
415#[derive(Debug, Clone, Serialize, Deserialize)]
421pub struct StreamingSchemaConfig {
422 #[serde(default)]
424 pub enabled: bool,
425 #[serde(default = "default_buffer_size")]
427 pub buffer_size: usize,
428 #[serde(default = "default_true")]
430 pub enable_progress: bool,
431 #[serde(default = "default_progress_interval")]
433 pub progress_interval: u64,
434 #[serde(default)]
436 pub backpressure: BackpressureSchemaStrategy,
437}
438
439fn default_buffer_size() -> usize {
440 1000
441}
442
443fn default_progress_interval() -> u64 {
444 100
445}
446
447impl Default for StreamingSchemaConfig {
448 fn default() -> Self {
449 Self {
450 enabled: false,
451 buffer_size: 1000,
452 enable_progress: true,
453 progress_interval: 100,
454 backpressure: BackpressureSchemaStrategy::Block,
455 }
456 }
457}
458
459#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
461#[serde(rename_all = "snake_case")]
462pub enum BackpressureSchemaStrategy {
463 #[default]
465 Block,
466 DropOldest,
468 DropNewest,
470 Buffer,
472}
473
474#[derive(Debug, Clone, Serialize, Deserialize)]
480pub struct RateLimitSchemaConfig {
481 #[serde(default)]
483 pub enabled: bool,
484 #[serde(default = "default_entities_per_second")]
486 pub entities_per_second: f64,
487 #[serde(default = "default_burst_size")]
489 pub burst_size: u32,
490 #[serde(default)]
492 pub backpressure: RateLimitBackpressureSchema,
493}
494
495fn default_entities_per_second() -> f64 {
496 1000.0
497}
498
499fn default_burst_size() -> u32 {
500 100
501}
502
503impl Default for RateLimitSchemaConfig {
504 fn default() -> Self {
505 Self {
506 enabled: false,
507 entities_per_second: 1000.0,
508 burst_size: 100,
509 backpressure: RateLimitBackpressureSchema::Block,
510 }
511 }
512}
513
514#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
516#[serde(rename_all = "snake_case")]
517pub enum RateLimitBackpressureSchema {
518 #[default]
520 Block,
521 Drop,
523 Buffer,
525}
526
527#[derive(Debug, Clone, Serialize, Deserialize)]
533pub struct TemporalAttributeSchemaConfig {
534 #[serde(default)]
536 pub enabled: bool,
537 #[serde(default)]
539 pub valid_time: ValidTimeSchemaConfig,
540 #[serde(default)]
542 pub transaction_time: TransactionTimeSchemaConfig,
543 #[serde(default)]
545 pub generate_version_chains: bool,
546 #[serde(default = "default_avg_versions")]
548 pub avg_versions_per_entity: f64,
549}
550
551fn default_avg_versions() -> f64 {
552 1.5
553}
554
555impl Default for TemporalAttributeSchemaConfig {
556 fn default() -> Self {
557 Self {
558 enabled: false,
559 valid_time: ValidTimeSchemaConfig::default(),
560 transaction_time: TransactionTimeSchemaConfig::default(),
561 generate_version_chains: false,
562 avg_versions_per_entity: 1.5,
563 }
564 }
565}
566
567#[derive(Debug, Clone, Serialize, Deserialize)]
569pub struct ValidTimeSchemaConfig {
570 #[serde(default = "default_closed_probability")]
572 pub closed_probability: f64,
573 #[serde(default = "default_avg_validity_days")]
575 pub avg_validity_days: u32,
576 #[serde(default = "default_validity_stddev")]
578 pub validity_stddev_days: u32,
579}
580
581fn default_closed_probability() -> f64 {
582 0.1
583}
584
585fn default_avg_validity_days() -> u32 {
586 365
587}
588
589fn default_validity_stddev() -> u32 {
590 90
591}
592
593impl Default for ValidTimeSchemaConfig {
594 fn default() -> Self {
595 Self {
596 closed_probability: 0.1,
597 avg_validity_days: 365,
598 validity_stddev_days: 90,
599 }
600 }
601}
602
603#[derive(Debug, Clone, Serialize, Deserialize)]
605pub struct TransactionTimeSchemaConfig {
606 #[serde(default)]
608 pub avg_recording_delay_seconds: u32,
609 #[serde(default)]
611 pub allow_backdating: bool,
612 #[serde(default = "default_backdating_probability")]
614 pub backdating_probability: f64,
615 #[serde(default = "default_max_backdate_days")]
617 pub max_backdate_days: u32,
618}
619
620fn default_backdating_probability() -> f64 {
621 0.01
622}
623
624fn default_max_backdate_days() -> u32 {
625 30
626}
627
628impl Default for TransactionTimeSchemaConfig {
629 fn default() -> Self {
630 Self {
631 avg_recording_delay_seconds: 0,
632 allow_backdating: false,
633 backdating_probability: 0.01,
634 max_backdate_days: 30,
635 }
636 }
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize)]
645pub struct RelationshipSchemaConfig {
646 #[serde(default)]
648 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
649 #[serde(default = "default_true")]
651 pub allow_orphans: bool,
652 #[serde(default = "default_orphan_probability")]
654 pub orphan_probability: f64,
655 #[serde(default)]
657 pub allow_circular: bool,
658 #[serde(default = "default_max_circular_depth")]
660 pub max_circular_depth: u32,
661}
662
663fn default_orphan_probability() -> f64 {
664 0.01
665}
666
667fn default_max_circular_depth() -> u32 {
668 3
669}
670
671impl Default for RelationshipSchemaConfig {
672 fn default() -> Self {
673 Self {
674 relationship_types: Vec::new(),
675 allow_orphans: true,
676 orphan_probability: 0.01,
677 allow_circular: false,
678 max_circular_depth: 3,
679 }
680 }
681}
682
683#[derive(Debug, Clone, Serialize, Deserialize)]
685pub struct RelationshipTypeSchemaConfig {
686 pub name: String,
688 pub source_type: String,
690 pub target_type: String,
692 #[serde(default)]
694 pub cardinality: CardinalitySchemaRule,
695 #[serde(default = "default_relationship_weight")]
697 pub weight: f64,
698 #[serde(default)]
700 pub required: bool,
701 #[serde(default = "default_true")]
703 pub directed: bool,
704}
705
706fn default_relationship_weight() -> f64 {
707 1.0
708}
709
710impl Default for RelationshipTypeSchemaConfig {
711 fn default() -> Self {
712 Self {
713 name: String::new(),
714 source_type: String::new(),
715 target_type: String::new(),
716 cardinality: CardinalitySchemaRule::default(),
717 weight: 1.0,
718 required: false,
719 directed: true,
720 }
721 }
722}
723
724#[derive(Debug, Clone, Serialize, Deserialize)]
726#[serde(rename_all = "snake_case")]
727pub enum CardinalitySchemaRule {
728 OneToOne,
730 OneToMany {
732 min: u32,
734 max: u32,
736 },
737 ManyToOne {
739 min: u32,
741 max: u32,
743 },
744 ManyToMany {
746 min_per_source: u32,
748 max_per_source: u32,
750 },
751}
752
753impl Default for CardinalitySchemaRule {
754 fn default() -> Self {
755 Self::OneToMany { min: 1, max: 5 }
756 }
757}
758
759#[derive(Debug, Clone, Serialize, Deserialize)]
761pub struct GlobalConfig {
762 pub seed: Option<u64>,
764 pub industry: IndustrySector,
766 pub start_date: String,
768 pub period_months: u32,
770 #[serde(default = "default_currency")]
772 pub group_currency: String,
773 #[serde(default = "default_true")]
775 pub parallel: bool,
776 #[serde(default)]
778 pub worker_threads: usize,
779 #[serde(default)]
781 pub memory_limit_mb: usize,
782}
783
784fn default_currency() -> String {
785 "USD".to_string()
786}
787fn default_true() -> bool {
788 true
789}
790
791#[derive(Debug, Clone, Serialize, Deserialize)]
793pub struct CompanyConfig {
794 pub code: String,
796 pub name: String,
798 pub currency: String,
800 pub country: String,
802 #[serde(default = "default_fiscal_variant")]
804 pub fiscal_year_variant: String,
805 pub annual_transaction_volume: TransactionVolume,
807 #[serde(default = "default_weight")]
809 pub volume_weight: f64,
810}
811
812fn default_fiscal_variant() -> String {
813 "K4".to_string()
814}
815fn default_weight() -> f64 {
816 1.0
817}
818
819#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
821#[serde(rename_all = "snake_case")]
822pub enum TransactionVolume {
823 TenK,
825 HundredK,
827 OneM,
829 TenM,
831 HundredM,
833 Custom(u64),
835}
836
837impl TransactionVolume {
838 pub fn count(&self) -> u64 {
840 match self {
841 Self::TenK => 10_000,
842 Self::HundredK => 100_000,
843 Self::OneM => 1_000_000,
844 Self::TenM => 10_000_000,
845 Self::HundredM => 100_000_000,
846 Self::Custom(n) => *n,
847 }
848 }
849}
850
851#[derive(Debug, Clone, Serialize, Deserialize)]
853pub struct ChartOfAccountsConfig {
854 pub complexity: CoAComplexity,
856 #[serde(default = "default_true")]
858 pub industry_specific: bool,
859 pub custom_accounts: Option<PathBuf>,
861 #[serde(default = "default_min_depth")]
863 pub min_hierarchy_depth: u8,
864 #[serde(default = "default_max_depth")]
866 pub max_hierarchy_depth: u8,
867}
868
869fn default_min_depth() -> u8 {
870 2
871}
872fn default_max_depth() -> u8 {
873 5
874}
875
876impl Default for ChartOfAccountsConfig {
877 fn default() -> Self {
878 Self {
879 complexity: CoAComplexity::Small,
880 industry_specific: true,
881 custom_accounts: None,
882 min_hierarchy_depth: default_min_depth(),
883 max_hierarchy_depth: default_max_depth(),
884 }
885 }
886}
887
888#[derive(Debug, Clone, Serialize, Deserialize, Default)]
890pub struct TransactionConfig {
891 #[serde(default)]
893 pub line_item_distribution: LineItemDistributionConfig,
894 #[serde(default)]
896 pub debit_credit_distribution: DebitCreditDistributionConfig,
897 #[serde(default)]
899 pub even_odd_distribution: EvenOddDistributionConfig,
900 #[serde(default)]
902 pub source_distribution: SourceDistribution,
903 #[serde(default)]
905 pub seasonality: SeasonalityConfig,
906 #[serde(default)]
908 pub amounts: AmountDistributionConfig,
909 #[serde(default)]
911 pub benford: BenfordConfig,
912}
913
914#[derive(Debug, Clone, Serialize, Deserialize)]
916pub struct BenfordConfig {
917 #[serde(default = "default_true")]
919 pub enabled: bool,
920 #[serde(default = "default_benford_tolerance")]
922 pub tolerance: f64,
923 #[serde(default)]
925 pub exempt_sources: Vec<BenfordExemption>,
926}
927
928fn default_benford_tolerance() -> f64 {
929 0.05
930}
931
932impl Default for BenfordConfig {
933 fn default() -> Self {
934 Self {
935 enabled: true,
936 tolerance: default_benford_tolerance(),
937 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
938 }
939 }
940}
941
942#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
944#[serde(rename_all = "snake_case")]
945pub enum BenfordExemption {
946 Recurring,
948 Payroll,
950 FixedFees,
952 RoundAmounts,
954}
955
956#[derive(Debug, Clone, Serialize, Deserialize)]
958pub struct SourceDistribution {
959 pub manual: f64,
961 pub automated: f64,
963 pub recurring: f64,
965 pub adjustment: f64,
967}
968
969impl Default for SourceDistribution {
970 fn default() -> Self {
971 Self {
972 manual: 0.20,
973 automated: 0.70,
974 recurring: 0.07,
975 adjustment: 0.03,
976 }
977 }
978}
979
980#[derive(Debug, Clone, Serialize, Deserialize)]
982pub struct OutputConfig {
983 #[serde(default)]
985 pub mode: OutputMode,
986 pub output_directory: PathBuf,
988 #[serde(default = "default_formats")]
990 pub formats: Vec<FileFormat>,
991 #[serde(default)]
993 pub compression: CompressionConfig,
994 #[serde(default = "default_batch_size")]
996 pub batch_size: usize,
997 #[serde(default = "default_true")]
999 pub include_acdoca: bool,
1000 #[serde(default)]
1002 pub include_bseg: bool,
1003 #[serde(default = "default_true")]
1005 pub partition_by_period: bool,
1006 #[serde(default)]
1008 pub partition_by_company: bool,
1009}
1010
1011fn default_formats() -> Vec<FileFormat> {
1012 vec![FileFormat::Parquet]
1013}
1014fn default_batch_size() -> usize {
1015 100_000
1016}
1017
1018impl Default for OutputConfig {
1019 fn default() -> Self {
1020 Self {
1021 mode: OutputMode::FlatFile,
1022 output_directory: PathBuf::from("./output"),
1023 formats: default_formats(),
1024 compression: CompressionConfig::default(),
1025 batch_size: default_batch_size(),
1026 include_acdoca: true,
1027 include_bseg: false,
1028 partition_by_period: true,
1029 partition_by_company: false,
1030 }
1031 }
1032}
1033
1034#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1036#[serde(rename_all = "snake_case")]
1037pub enum OutputMode {
1038 Streaming,
1040 #[default]
1042 FlatFile,
1043 Both,
1045}
1046
1047#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1049#[serde(rename_all = "snake_case")]
1050pub enum FileFormat {
1051 Csv,
1052 Parquet,
1053 Json,
1054 JsonLines,
1055}
1056
1057#[derive(Debug, Clone, Serialize, Deserialize)]
1059pub struct CompressionConfig {
1060 #[serde(default = "default_true")]
1062 pub enabled: bool,
1063 #[serde(default)]
1065 pub algorithm: CompressionAlgorithm,
1066 #[serde(default = "default_compression_level")]
1068 pub level: u8,
1069}
1070
1071fn default_compression_level() -> u8 {
1072 3
1073}
1074
1075impl Default for CompressionConfig {
1076 fn default() -> Self {
1077 Self {
1078 enabled: true,
1079 algorithm: CompressionAlgorithm::default(),
1080 level: default_compression_level(),
1081 }
1082 }
1083}
1084
1085#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1087#[serde(rename_all = "snake_case")]
1088pub enum CompressionAlgorithm {
1089 Gzip,
1090 #[default]
1091 Zstd,
1092 Lz4,
1093 Snappy,
1094}
1095
1096#[derive(Debug, Clone, Serialize, Deserialize)]
1098pub struct FraudConfig {
1099 #[serde(default)]
1101 pub enabled: bool,
1102 #[serde(default = "default_fraud_rate")]
1104 pub fraud_rate: f64,
1105 #[serde(default)]
1107 pub fraud_type_distribution: FraudTypeDistribution,
1108 #[serde(default)]
1110 pub clustering_enabled: bool,
1111 #[serde(default = "default_clustering_factor")]
1113 pub clustering_factor: f64,
1114 #[serde(default = "default_approval_thresholds")]
1116 pub approval_thresholds: Vec<f64>,
1117}
1118
1119fn default_approval_thresholds() -> Vec<f64> {
1120 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1121}
1122
1123fn default_fraud_rate() -> f64 {
1124 0.005
1125}
1126fn default_clustering_factor() -> f64 {
1127 3.0
1128}
1129
1130impl Default for FraudConfig {
1131 fn default() -> Self {
1132 Self {
1133 enabled: false,
1134 fraud_rate: default_fraud_rate(),
1135 fraud_type_distribution: FraudTypeDistribution::default(),
1136 clustering_enabled: false,
1137 clustering_factor: default_clustering_factor(),
1138 approval_thresholds: default_approval_thresholds(),
1139 }
1140 }
1141}
1142
1143#[derive(Debug, Clone, Serialize, Deserialize)]
1145pub struct FraudTypeDistribution {
1146 pub suspense_account_abuse: f64,
1147 pub fictitious_transaction: f64,
1148 pub revenue_manipulation: f64,
1149 pub expense_capitalization: f64,
1150 pub split_transaction: f64,
1151 pub timing_anomaly: f64,
1152 pub unauthorized_access: f64,
1153 pub duplicate_payment: f64,
1154}
1155
1156impl Default for FraudTypeDistribution {
1157 fn default() -> Self {
1158 Self {
1159 suspense_account_abuse: 0.25,
1160 fictitious_transaction: 0.15,
1161 revenue_manipulation: 0.10,
1162 expense_capitalization: 0.10,
1163 split_transaction: 0.15,
1164 timing_anomaly: 0.10,
1165 unauthorized_access: 0.10,
1166 duplicate_payment: 0.05,
1167 }
1168 }
1169}
1170
1171#[derive(Debug, Clone, Serialize, Deserialize)]
1173pub struct InternalControlsConfig {
1174 #[serde(default)]
1176 pub enabled: bool,
1177 #[serde(default = "default_exception_rate")]
1179 pub exception_rate: f64,
1180 #[serde(default = "default_sod_violation_rate")]
1182 pub sod_violation_rate: f64,
1183 #[serde(default = "default_true")]
1185 pub export_control_master_data: bool,
1186 #[serde(default = "default_sox_materiality_threshold")]
1188 pub sox_materiality_threshold: f64,
1189 #[serde(default = "default_true")]
1191 pub coso_enabled: bool,
1192 #[serde(default)]
1194 pub include_entity_level_controls: bool,
1195 #[serde(default = "default_target_maturity_level")]
1198 pub target_maturity_level: String,
1199}
1200
1201fn default_exception_rate() -> f64 {
1202 0.02
1203}
1204
1205fn default_sod_violation_rate() -> f64 {
1206 0.01
1207}
1208
1209fn default_sox_materiality_threshold() -> f64 {
1210 10000.0
1211}
1212
1213fn default_target_maturity_level() -> String {
1214 "mixed".to_string()
1215}
1216
1217impl Default for InternalControlsConfig {
1218 fn default() -> Self {
1219 Self {
1220 enabled: false,
1221 exception_rate: default_exception_rate(),
1222 sod_violation_rate: default_sod_violation_rate(),
1223 export_control_master_data: true,
1224 sox_materiality_threshold: default_sox_materiality_threshold(),
1225 coso_enabled: true,
1226 include_entity_level_controls: false,
1227 target_maturity_level: default_target_maturity_level(),
1228 }
1229 }
1230}
1231
1232#[derive(Debug, Clone, Serialize, Deserialize)]
1234pub struct BusinessProcessConfig {
1235 #[serde(default = "default_o2c")]
1237 pub o2c_weight: f64,
1238 #[serde(default = "default_p2p")]
1240 pub p2p_weight: f64,
1241 #[serde(default = "default_r2r")]
1243 pub r2r_weight: f64,
1244 #[serde(default = "default_h2r")]
1246 pub h2r_weight: f64,
1247 #[serde(default = "default_a2r")]
1249 pub a2r_weight: f64,
1250}
1251
1252fn default_o2c() -> f64 {
1253 0.35
1254}
1255fn default_p2p() -> f64 {
1256 0.30
1257}
1258fn default_r2r() -> f64 {
1259 0.20
1260}
1261fn default_h2r() -> f64 {
1262 0.10
1263}
1264fn default_a2r() -> f64 {
1265 0.05
1266}
1267
1268impl Default for BusinessProcessConfig {
1269 fn default() -> Self {
1270 Self {
1271 o2c_weight: default_o2c(),
1272 p2p_weight: default_p2p(),
1273 r2r_weight: default_r2r(),
1274 h2r_weight: default_h2r(),
1275 a2r_weight: default_a2r(),
1276 }
1277 }
1278}
1279
1280#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1282pub struct UserPersonaConfig {
1283 #[serde(default)]
1285 pub persona_distribution: PersonaDistribution,
1286 #[serde(default)]
1288 pub users_per_persona: UsersPerPersona,
1289}
1290
1291#[derive(Debug, Clone, Serialize, Deserialize)]
1293pub struct PersonaDistribution {
1294 pub junior_accountant: f64,
1295 pub senior_accountant: f64,
1296 pub controller: f64,
1297 pub manager: f64,
1298 pub automated_system: f64,
1299}
1300
1301impl Default for PersonaDistribution {
1302 fn default() -> Self {
1303 Self {
1304 junior_accountant: 0.15,
1305 senior_accountant: 0.15,
1306 controller: 0.05,
1307 manager: 0.05,
1308 automated_system: 0.60,
1309 }
1310 }
1311}
1312
1313#[derive(Debug, Clone, Serialize, Deserialize)]
1315pub struct UsersPerPersona {
1316 pub junior_accountant: usize,
1317 pub senior_accountant: usize,
1318 pub controller: usize,
1319 pub manager: usize,
1320 pub automated_system: usize,
1321}
1322
1323impl Default for UsersPerPersona {
1324 fn default() -> Self {
1325 Self {
1326 junior_accountant: 10,
1327 senior_accountant: 5,
1328 controller: 2,
1329 manager: 3,
1330 automated_system: 20,
1331 }
1332 }
1333}
1334
1335#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1337pub struct TemplateConfig {
1338 #[serde(default)]
1340 pub names: NameTemplateConfig,
1341 #[serde(default)]
1343 pub descriptions: DescriptionTemplateConfig,
1344 #[serde(default)]
1346 pub references: ReferenceTemplateConfig,
1347}
1348
1349#[derive(Debug, Clone, Serialize, Deserialize)]
1351pub struct NameTemplateConfig {
1352 #[serde(default)]
1354 pub culture_distribution: CultureDistribution,
1355 #[serde(default = "default_email_domain")]
1357 pub email_domain: String,
1358 #[serde(default = "default_true")]
1360 pub generate_realistic_names: bool,
1361}
1362
1363fn default_email_domain() -> String {
1364 "company.com".to_string()
1365}
1366
1367impl Default for NameTemplateConfig {
1368 fn default() -> Self {
1369 Self {
1370 culture_distribution: CultureDistribution::default(),
1371 email_domain: default_email_domain(),
1372 generate_realistic_names: true,
1373 }
1374 }
1375}
1376
1377#[derive(Debug, Clone, Serialize, Deserialize)]
1379pub struct CultureDistribution {
1380 pub western_us: f64,
1381 pub hispanic: f64,
1382 pub german: f64,
1383 pub french: f64,
1384 pub chinese: f64,
1385 pub japanese: f64,
1386 pub indian: f64,
1387}
1388
1389impl Default for CultureDistribution {
1390 fn default() -> Self {
1391 Self {
1392 western_us: 0.40,
1393 hispanic: 0.20,
1394 german: 0.10,
1395 french: 0.05,
1396 chinese: 0.10,
1397 japanese: 0.05,
1398 indian: 0.10,
1399 }
1400 }
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize)]
1405pub struct DescriptionTemplateConfig {
1406 #[serde(default = "default_true")]
1408 pub generate_header_text: bool,
1409 #[serde(default = "default_true")]
1411 pub generate_line_text: bool,
1412}
1413
1414impl Default for DescriptionTemplateConfig {
1415 fn default() -> Self {
1416 Self {
1417 generate_header_text: true,
1418 generate_line_text: true,
1419 }
1420 }
1421}
1422
1423#[derive(Debug, Clone, Serialize, Deserialize)]
1425pub struct ReferenceTemplateConfig {
1426 #[serde(default = "default_true")]
1428 pub generate_references: bool,
1429 #[serde(default = "default_invoice_prefix")]
1431 pub invoice_prefix: String,
1432 #[serde(default = "default_po_prefix")]
1434 pub po_prefix: String,
1435 #[serde(default = "default_so_prefix")]
1437 pub so_prefix: String,
1438}
1439
1440fn default_invoice_prefix() -> String {
1441 "INV".to_string()
1442}
1443fn default_po_prefix() -> String {
1444 "PO".to_string()
1445}
1446fn default_so_prefix() -> String {
1447 "SO".to_string()
1448}
1449
1450impl Default for ReferenceTemplateConfig {
1451 fn default() -> Self {
1452 Self {
1453 generate_references: true,
1454 invoice_prefix: default_invoice_prefix(),
1455 po_prefix: default_po_prefix(),
1456 so_prefix: default_so_prefix(),
1457 }
1458 }
1459}
1460
1461#[derive(Debug, Clone, Serialize, Deserialize)]
1463pub struct ApprovalConfig {
1464 #[serde(default)]
1466 pub enabled: bool,
1467 #[serde(default = "default_auto_approve_threshold")]
1469 pub auto_approve_threshold: f64,
1470 #[serde(default = "default_rejection_rate")]
1472 pub rejection_rate: f64,
1473 #[serde(default = "default_revision_rate")]
1475 pub revision_rate: f64,
1476 #[serde(default = "default_approval_delay_hours")]
1478 pub average_approval_delay_hours: f64,
1479 #[serde(default)]
1481 pub thresholds: Vec<ApprovalThresholdConfig>,
1482}
1483
1484fn default_auto_approve_threshold() -> f64 {
1485 1000.0
1486}
1487fn default_rejection_rate() -> f64 {
1488 0.02
1489}
1490fn default_revision_rate() -> f64 {
1491 0.05
1492}
1493fn default_approval_delay_hours() -> f64 {
1494 4.0
1495}
1496
1497impl Default for ApprovalConfig {
1498 fn default() -> Self {
1499 Self {
1500 enabled: false,
1501 auto_approve_threshold: default_auto_approve_threshold(),
1502 rejection_rate: default_rejection_rate(),
1503 revision_rate: default_revision_rate(),
1504 average_approval_delay_hours: default_approval_delay_hours(),
1505 thresholds: vec![
1506 ApprovalThresholdConfig {
1507 amount: 1000.0,
1508 level: 1,
1509 roles: vec!["senior_accountant".to_string()],
1510 },
1511 ApprovalThresholdConfig {
1512 amount: 10000.0,
1513 level: 2,
1514 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1515 },
1516 ApprovalThresholdConfig {
1517 amount: 100000.0,
1518 level: 3,
1519 roles: vec![
1520 "senior_accountant".to_string(),
1521 "controller".to_string(),
1522 "manager".to_string(),
1523 ],
1524 },
1525 ApprovalThresholdConfig {
1526 amount: 500000.0,
1527 level: 4,
1528 roles: vec![
1529 "senior_accountant".to_string(),
1530 "controller".to_string(),
1531 "manager".to_string(),
1532 "executive".to_string(),
1533 ],
1534 },
1535 ],
1536 }
1537 }
1538}
1539
1540#[derive(Debug, Clone, Serialize, Deserialize)]
1542pub struct ApprovalThresholdConfig {
1543 pub amount: f64,
1545 pub level: u8,
1547 pub roles: Vec<String>,
1549}
1550
1551#[derive(Debug, Clone, Serialize, Deserialize)]
1553pub struct DepartmentConfig {
1554 #[serde(default)]
1556 pub enabled: bool,
1557 #[serde(default = "default_headcount_multiplier")]
1559 pub headcount_multiplier: f64,
1560 #[serde(default)]
1562 pub custom_departments: Vec<CustomDepartmentConfig>,
1563}
1564
1565fn default_headcount_multiplier() -> f64 {
1566 1.0
1567}
1568
1569impl Default for DepartmentConfig {
1570 fn default() -> Self {
1571 Self {
1572 enabled: false,
1573 headcount_multiplier: default_headcount_multiplier(),
1574 custom_departments: Vec::new(),
1575 }
1576 }
1577}
1578
1579#[derive(Debug, Clone, Serialize, Deserialize)]
1581pub struct CustomDepartmentConfig {
1582 pub code: String,
1584 pub name: String,
1586 #[serde(default)]
1588 pub cost_center: Option<String>,
1589 #[serde(default)]
1591 pub primary_processes: Vec<String>,
1592 #[serde(default)]
1594 pub parent_code: Option<String>,
1595}
1596
1597#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1603pub struct MasterDataConfig {
1604 #[serde(default)]
1606 pub vendors: VendorMasterConfig,
1607 #[serde(default)]
1609 pub customers: CustomerMasterConfig,
1610 #[serde(default)]
1612 pub materials: MaterialMasterConfig,
1613 #[serde(default)]
1615 pub fixed_assets: FixedAssetMasterConfig,
1616 #[serde(default)]
1618 pub employees: EmployeeMasterConfig,
1619 #[serde(default)]
1621 pub cost_centers: CostCenterMasterConfig,
1622}
1623
1624#[derive(Debug, Clone, Serialize, Deserialize)]
1626pub struct VendorMasterConfig {
1627 #[serde(default = "default_vendor_count")]
1629 pub count: usize,
1630 #[serde(default = "default_intercompany_percent")]
1632 pub intercompany_percent: f64,
1633 #[serde(default)]
1635 pub payment_terms_distribution: PaymentTermsDistribution,
1636 #[serde(default)]
1638 pub behavior_distribution: VendorBehaviorDistribution,
1639 #[serde(default = "default_true")]
1641 pub generate_bank_accounts: bool,
1642 #[serde(default = "default_true")]
1644 pub generate_tax_ids: bool,
1645}
1646
1647fn default_vendor_count() -> usize {
1648 500
1649}
1650
1651fn default_intercompany_percent() -> f64 {
1652 0.05
1653}
1654
1655impl Default for VendorMasterConfig {
1656 fn default() -> Self {
1657 Self {
1658 count: default_vendor_count(),
1659 intercompany_percent: default_intercompany_percent(),
1660 payment_terms_distribution: PaymentTermsDistribution::default(),
1661 behavior_distribution: VendorBehaviorDistribution::default(),
1662 generate_bank_accounts: true,
1663 generate_tax_ids: true,
1664 }
1665 }
1666}
1667
1668#[derive(Debug, Clone, Serialize, Deserialize)]
1670pub struct PaymentTermsDistribution {
1671 pub net_30: f64,
1673 pub net_60: f64,
1675 pub net_90: f64,
1677 pub two_ten_net_30: f64,
1679 pub due_on_receipt: f64,
1681 pub end_of_month: f64,
1683}
1684
1685impl Default for PaymentTermsDistribution {
1686 fn default() -> Self {
1687 Self {
1688 net_30: 0.40,
1689 net_60: 0.20,
1690 net_90: 0.10,
1691 two_ten_net_30: 0.15,
1692 due_on_receipt: 0.05,
1693 end_of_month: 0.10,
1694 }
1695 }
1696}
1697
1698#[derive(Debug, Clone, Serialize, Deserialize)]
1700pub struct VendorBehaviorDistribution {
1701 pub reliable: f64,
1703 pub sometimes_late: f64,
1705 pub inconsistent_quality: f64,
1707 pub premium: f64,
1709 pub budget: f64,
1711}
1712
1713impl Default for VendorBehaviorDistribution {
1714 fn default() -> Self {
1715 Self {
1716 reliable: 0.50,
1717 sometimes_late: 0.20,
1718 inconsistent_quality: 0.10,
1719 premium: 0.10,
1720 budget: 0.10,
1721 }
1722 }
1723}
1724
1725#[derive(Debug, Clone, Serialize, Deserialize)]
1727pub struct CustomerMasterConfig {
1728 #[serde(default = "default_customer_count")]
1730 pub count: usize,
1731 #[serde(default = "default_intercompany_percent")]
1733 pub intercompany_percent: f64,
1734 #[serde(default)]
1736 pub credit_rating_distribution: CreditRatingDistribution,
1737 #[serde(default)]
1739 pub payment_behavior_distribution: PaymentBehaviorDistribution,
1740 #[serde(default = "default_true")]
1742 pub generate_credit_limits: bool,
1743}
1744
1745fn default_customer_count() -> usize {
1746 2000
1747}
1748
1749impl Default for CustomerMasterConfig {
1750 fn default() -> Self {
1751 Self {
1752 count: default_customer_count(),
1753 intercompany_percent: default_intercompany_percent(),
1754 credit_rating_distribution: CreditRatingDistribution::default(),
1755 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
1756 generate_credit_limits: true,
1757 }
1758 }
1759}
1760
1761#[derive(Debug, Clone, Serialize, Deserialize)]
1763pub struct CreditRatingDistribution {
1764 pub aaa: f64,
1766 pub aa: f64,
1768 pub a: f64,
1770 pub bbb: f64,
1772 pub bb: f64,
1774 pub b: f64,
1776 pub below_b: f64,
1778}
1779
1780impl Default for CreditRatingDistribution {
1781 fn default() -> Self {
1782 Self {
1783 aaa: 0.05,
1784 aa: 0.10,
1785 a: 0.20,
1786 bbb: 0.30,
1787 bb: 0.20,
1788 b: 0.10,
1789 below_b: 0.05,
1790 }
1791 }
1792}
1793
1794#[derive(Debug, Clone, Serialize, Deserialize)]
1796pub struct PaymentBehaviorDistribution {
1797 pub early_payer: f64,
1799 pub on_time: f64,
1801 pub occasional_late: f64,
1803 pub frequent_late: f64,
1805 pub discount_taker: f64,
1807}
1808
1809impl Default for PaymentBehaviorDistribution {
1810 fn default() -> Self {
1811 Self {
1812 early_payer: 0.10,
1813 on_time: 0.50,
1814 occasional_late: 0.25,
1815 frequent_late: 0.10,
1816 discount_taker: 0.05,
1817 }
1818 }
1819}
1820
1821#[derive(Debug, Clone, Serialize, Deserialize)]
1823pub struct MaterialMasterConfig {
1824 #[serde(default = "default_material_count")]
1826 pub count: usize,
1827 #[serde(default)]
1829 pub type_distribution: MaterialTypeDistribution,
1830 #[serde(default)]
1832 pub valuation_distribution: ValuationMethodDistribution,
1833 #[serde(default = "default_bom_percent")]
1835 pub bom_percent: f64,
1836 #[serde(default = "default_max_bom_depth")]
1838 pub max_bom_depth: u8,
1839}
1840
1841fn default_material_count() -> usize {
1842 5000
1843}
1844
1845fn default_bom_percent() -> f64 {
1846 0.20
1847}
1848
1849fn default_max_bom_depth() -> u8 {
1850 3
1851}
1852
1853impl Default for MaterialMasterConfig {
1854 fn default() -> Self {
1855 Self {
1856 count: default_material_count(),
1857 type_distribution: MaterialTypeDistribution::default(),
1858 valuation_distribution: ValuationMethodDistribution::default(),
1859 bom_percent: default_bom_percent(),
1860 max_bom_depth: default_max_bom_depth(),
1861 }
1862 }
1863}
1864
1865#[derive(Debug, Clone, Serialize, Deserialize)]
1867pub struct MaterialTypeDistribution {
1868 pub raw_material: f64,
1870 pub semi_finished: f64,
1872 pub finished_good: f64,
1874 pub trading_good: f64,
1876 pub operating_supply: f64,
1878 pub service: f64,
1880}
1881
1882impl Default for MaterialTypeDistribution {
1883 fn default() -> Self {
1884 Self {
1885 raw_material: 0.30,
1886 semi_finished: 0.15,
1887 finished_good: 0.25,
1888 trading_good: 0.15,
1889 operating_supply: 0.10,
1890 service: 0.05,
1891 }
1892 }
1893}
1894
1895#[derive(Debug, Clone, Serialize, Deserialize)]
1897pub struct ValuationMethodDistribution {
1898 pub standard_cost: f64,
1900 pub moving_average: f64,
1902 pub fifo: f64,
1904 pub lifo: f64,
1906}
1907
1908impl Default for ValuationMethodDistribution {
1909 fn default() -> Self {
1910 Self {
1911 standard_cost: 0.50,
1912 moving_average: 0.30,
1913 fifo: 0.15,
1914 lifo: 0.05,
1915 }
1916 }
1917}
1918
1919#[derive(Debug, Clone, Serialize, Deserialize)]
1921pub struct FixedAssetMasterConfig {
1922 #[serde(default = "default_asset_count")]
1924 pub count: usize,
1925 #[serde(default)]
1927 pub class_distribution: AssetClassDistribution,
1928 #[serde(default)]
1930 pub depreciation_distribution: DepreciationMethodDistribution,
1931 #[serde(default = "default_fully_depreciated_percent")]
1933 pub fully_depreciated_percent: f64,
1934 #[serde(default = "default_true")]
1936 pub generate_acquisition_history: bool,
1937}
1938
1939fn default_asset_count() -> usize {
1940 800
1941}
1942
1943fn default_fully_depreciated_percent() -> f64 {
1944 0.15
1945}
1946
1947impl Default for FixedAssetMasterConfig {
1948 fn default() -> Self {
1949 Self {
1950 count: default_asset_count(),
1951 class_distribution: AssetClassDistribution::default(),
1952 depreciation_distribution: DepreciationMethodDistribution::default(),
1953 fully_depreciated_percent: default_fully_depreciated_percent(),
1954 generate_acquisition_history: true,
1955 }
1956 }
1957}
1958
1959#[derive(Debug, Clone, Serialize, Deserialize)]
1961pub struct AssetClassDistribution {
1962 pub buildings: f64,
1964 pub machinery: f64,
1966 pub vehicles: f64,
1968 pub it_equipment: f64,
1970 pub furniture: f64,
1972 pub land: f64,
1974 pub leasehold: f64,
1976}
1977
1978impl Default for AssetClassDistribution {
1979 fn default() -> Self {
1980 Self {
1981 buildings: 0.15,
1982 machinery: 0.30,
1983 vehicles: 0.15,
1984 it_equipment: 0.20,
1985 furniture: 0.10,
1986 land: 0.05,
1987 leasehold: 0.05,
1988 }
1989 }
1990}
1991
1992#[derive(Debug, Clone, Serialize, Deserialize)]
1994pub struct DepreciationMethodDistribution {
1995 pub straight_line: f64,
1997 pub declining_balance: f64,
1999 pub double_declining: f64,
2001 pub sum_of_years: f64,
2003 pub units_of_production: f64,
2005}
2006
2007impl Default for DepreciationMethodDistribution {
2008 fn default() -> Self {
2009 Self {
2010 straight_line: 0.60,
2011 declining_balance: 0.20,
2012 double_declining: 0.10,
2013 sum_of_years: 0.05,
2014 units_of_production: 0.05,
2015 }
2016 }
2017}
2018
2019#[derive(Debug, Clone, Serialize, Deserialize)]
2021pub struct EmployeeMasterConfig {
2022 #[serde(default = "default_employee_count")]
2024 pub count: usize,
2025 #[serde(default = "default_true")]
2027 pub generate_hierarchy: bool,
2028 #[serde(default = "default_hierarchy_depth")]
2030 pub max_hierarchy_depth: u8,
2031 #[serde(default = "default_span_of_control")]
2033 pub average_span_of_control: f64,
2034 #[serde(default)]
2036 pub approval_limits: ApprovalLimitDistribution,
2037 #[serde(default)]
2039 pub department_distribution: EmployeeDepartmentDistribution,
2040}
2041
2042fn default_employee_count() -> usize {
2043 1500
2044}
2045
2046fn default_hierarchy_depth() -> u8 {
2047 6
2048}
2049
2050fn default_span_of_control() -> f64 {
2051 5.0
2052}
2053
2054impl Default for EmployeeMasterConfig {
2055 fn default() -> Self {
2056 Self {
2057 count: default_employee_count(),
2058 generate_hierarchy: true,
2059 max_hierarchy_depth: default_hierarchy_depth(),
2060 average_span_of_control: default_span_of_control(),
2061 approval_limits: ApprovalLimitDistribution::default(),
2062 department_distribution: EmployeeDepartmentDistribution::default(),
2063 }
2064 }
2065}
2066
2067#[derive(Debug, Clone, Serialize, Deserialize)]
2069pub struct ApprovalLimitDistribution {
2070 #[serde(default = "default_staff_limit")]
2072 pub staff: f64,
2073 #[serde(default = "default_senior_limit")]
2075 pub senior: f64,
2076 #[serde(default = "default_manager_limit")]
2078 pub manager: f64,
2079 #[serde(default = "default_director_limit")]
2081 pub director: f64,
2082 #[serde(default = "default_vp_limit")]
2084 pub vp: f64,
2085 #[serde(default = "default_executive_limit")]
2087 pub executive: f64,
2088}
2089
2090fn default_staff_limit() -> f64 {
2091 1000.0
2092}
2093fn default_senior_limit() -> f64 {
2094 5000.0
2095}
2096fn default_manager_limit() -> f64 {
2097 25000.0
2098}
2099fn default_director_limit() -> f64 {
2100 100000.0
2101}
2102fn default_vp_limit() -> f64 {
2103 500000.0
2104}
2105fn default_executive_limit() -> f64 {
2106 f64::INFINITY
2107}
2108
2109impl Default for ApprovalLimitDistribution {
2110 fn default() -> Self {
2111 Self {
2112 staff: default_staff_limit(),
2113 senior: default_senior_limit(),
2114 manager: default_manager_limit(),
2115 director: default_director_limit(),
2116 vp: default_vp_limit(),
2117 executive: default_executive_limit(),
2118 }
2119 }
2120}
2121
2122#[derive(Debug, Clone, Serialize, Deserialize)]
2124pub struct EmployeeDepartmentDistribution {
2125 pub finance: f64,
2127 pub procurement: f64,
2129 pub sales: f64,
2131 pub warehouse: f64,
2133 pub it: f64,
2135 pub hr: f64,
2137 pub operations: f64,
2139 pub executive: f64,
2141}
2142
2143impl Default for EmployeeDepartmentDistribution {
2144 fn default() -> Self {
2145 Self {
2146 finance: 0.12,
2147 procurement: 0.10,
2148 sales: 0.25,
2149 warehouse: 0.15,
2150 it: 0.10,
2151 hr: 0.05,
2152 operations: 0.20,
2153 executive: 0.03,
2154 }
2155 }
2156}
2157
2158#[derive(Debug, Clone, Serialize, Deserialize)]
2160pub struct CostCenterMasterConfig {
2161 #[serde(default = "default_cost_center_count")]
2163 pub count: usize,
2164 #[serde(default = "default_true")]
2166 pub generate_hierarchy: bool,
2167 #[serde(default = "default_cc_hierarchy_depth")]
2169 pub max_hierarchy_depth: u8,
2170}
2171
2172fn default_cost_center_count() -> usize {
2173 50
2174}
2175
2176fn default_cc_hierarchy_depth() -> u8 {
2177 3
2178}
2179
2180impl Default for CostCenterMasterConfig {
2181 fn default() -> Self {
2182 Self {
2183 count: default_cost_center_count(),
2184 generate_hierarchy: true,
2185 max_hierarchy_depth: default_cc_hierarchy_depth(),
2186 }
2187 }
2188}
2189
2190#[derive(Debug, Clone, Serialize, Deserialize)]
2196pub struct DocumentFlowConfig {
2197 #[serde(default)]
2199 pub p2p: P2PFlowConfig,
2200 #[serde(default)]
2202 pub o2c: O2CFlowConfig,
2203 #[serde(default = "default_true")]
2205 pub generate_document_references: bool,
2206 #[serde(default)]
2208 pub export_flow_graph: bool,
2209}
2210
2211impl Default for DocumentFlowConfig {
2212 fn default() -> Self {
2213 Self {
2214 p2p: P2PFlowConfig::default(),
2215 o2c: O2CFlowConfig::default(),
2216 generate_document_references: true,
2217 export_flow_graph: false,
2218 }
2219 }
2220}
2221
2222#[derive(Debug, Clone, Serialize, Deserialize)]
2224pub struct P2PFlowConfig {
2225 #[serde(default = "default_true")]
2227 pub enabled: bool,
2228 #[serde(default = "default_three_way_match_rate")]
2230 pub three_way_match_rate: f64,
2231 #[serde(default = "default_partial_delivery_rate")]
2233 pub partial_delivery_rate: f64,
2234 #[serde(default = "default_price_variance_rate")]
2236 pub price_variance_rate: f64,
2237 #[serde(default = "default_max_price_variance")]
2239 pub max_price_variance_percent: f64,
2240 #[serde(default = "default_quantity_variance_rate")]
2242 pub quantity_variance_rate: f64,
2243 #[serde(default = "default_po_to_gr_days")]
2245 pub average_po_to_gr_days: u32,
2246 #[serde(default = "default_gr_to_invoice_days")]
2248 pub average_gr_to_invoice_days: u32,
2249 #[serde(default = "default_invoice_to_payment_days")]
2251 pub average_invoice_to_payment_days: u32,
2252 #[serde(default)]
2254 pub line_count_distribution: DocumentLineCountDistribution,
2255 #[serde(default)]
2257 pub payment_behavior: P2PPaymentBehaviorConfig,
2258}
2259
2260fn default_three_way_match_rate() -> f64 {
2261 0.95
2262}
2263
2264fn default_partial_delivery_rate() -> f64 {
2265 0.15
2266}
2267
2268fn default_price_variance_rate() -> f64 {
2269 0.08
2270}
2271
2272fn default_max_price_variance() -> f64 {
2273 0.05
2274}
2275
2276fn default_quantity_variance_rate() -> f64 {
2277 0.05
2278}
2279
2280fn default_po_to_gr_days() -> u32 {
2281 14
2282}
2283
2284fn default_gr_to_invoice_days() -> u32 {
2285 5
2286}
2287
2288fn default_invoice_to_payment_days() -> u32 {
2289 30
2290}
2291
2292impl Default for P2PFlowConfig {
2293 fn default() -> Self {
2294 Self {
2295 enabled: true,
2296 three_way_match_rate: default_three_way_match_rate(),
2297 partial_delivery_rate: default_partial_delivery_rate(),
2298 price_variance_rate: default_price_variance_rate(),
2299 max_price_variance_percent: default_max_price_variance(),
2300 quantity_variance_rate: default_quantity_variance_rate(),
2301 average_po_to_gr_days: default_po_to_gr_days(),
2302 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2303 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2304 line_count_distribution: DocumentLineCountDistribution::default(),
2305 payment_behavior: P2PPaymentBehaviorConfig::default(),
2306 }
2307 }
2308}
2309
2310#[derive(Debug, Clone, Serialize, Deserialize)]
2316pub struct P2PPaymentBehaviorConfig {
2317 #[serde(default = "default_p2p_late_payment_rate")]
2319 pub late_payment_rate: f64,
2320 #[serde(default)]
2322 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2323 #[serde(default = "default_p2p_partial_payment_rate")]
2325 pub partial_payment_rate: f64,
2326 #[serde(default = "default_p2p_payment_correction_rate")]
2328 pub payment_correction_rate: f64,
2329}
2330
2331fn default_p2p_late_payment_rate() -> f64 {
2332 0.15
2333}
2334
2335fn default_p2p_partial_payment_rate() -> f64 {
2336 0.05
2337}
2338
2339fn default_p2p_payment_correction_rate() -> f64 {
2340 0.02
2341}
2342
2343impl Default for P2PPaymentBehaviorConfig {
2344 fn default() -> Self {
2345 Self {
2346 late_payment_rate: default_p2p_late_payment_rate(),
2347 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2348 partial_payment_rate: default_p2p_partial_payment_rate(),
2349 payment_correction_rate: default_p2p_payment_correction_rate(),
2350 }
2351 }
2352}
2353
2354#[derive(Debug, Clone, Serialize, Deserialize)]
2356pub struct LatePaymentDaysDistribution {
2357 #[serde(default = "default_slightly_late")]
2359 pub slightly_late_1_to_7: f64,
2360 #[serde(default = "default_late_8_14")]
2362 pub late_8_to_14: f64,
2363 #[serde(default = "default_very_late")]
2365 pub very_late_15_to_30: f64,
2366 #[serde(default = "default_severely_late")]
2368 pub severely_late_31_to_60: f64,
2369 #[serde(default = "default_extremely_late")]
2371 pub extremely_late_over_60: f64,
2372}
2373
2374fn default_slightly_late() -> f64 {
2375 0.50
2376}
2377
2378fn default_late_8_14() -> f64 {
2379 0.25
2380}
2381
2382fn default_very_late() -> f64 {
2383 0.15
2384}
2385
2386fn default_severely_late() -> f64 {
2387 0.07
2388}
2389
2390fn default_extremely_late() -> f64 {
2391 0.03
2392}
2393
2394impl Default for LatePaymentDaysDistribution {
2395 fn default() -> Self {
2396 Self {
2397 slightly_late_1_to_7: default_slightly_late(),
2398 late_8_to_14: default_late_8_14(),
2399 very_late_15_to_30: default_very_late(),
2400 severely_late_31_to_60: default_severely_late(),
2401 extremely_late_over_60: default_extremely_late(),
2402 }
2403 }
2404}
2405
2406#[derive(Debug, Clone, Serialize, Deserialize)]
2408pub struct O2CFlowConfig {
2409 #[serde(default = "default_true")]
2411 pub enabled: bool,
2412 #[serde(default = "default_credit_check_failure_rate")]
2414 pub credit_check_failure_rate: f64,
2415 #[serde(default = "default_partial_shipment_rate")]
2417 pub partial_shipment_rate: f64,
2418 #[serde(default = "default_return_rate")]
2420 pub return_rate: f64,
2421 #[serde(default = "default_bad_debt_rate")]
2423 pub bad_debt_rate: f64,
2424 #[serde(default = "default_so_to_delivery_days")]
2426 pub average_so_to_delivery_days: u32,
2427 #[serde(default = "default_delivery_to_invoice_days")]
2429 pub average_delivery_to_invoice_days: u32,
2430 #[serde(default = "default_invoice_to_receipt_days")]
2432 pub average_invoice_to_receipt_days: u32,
2433 #[serde(default)]
2435 pub line_count_distribution: DocumentLineCountDistribution,
2436 #[serde(default)]
2438 pub cash_discount: CashDiscountConfig,
2439 #[serde(default)]
2441 pub payment_behavior: O2CPaymentBehaviorConfig,
2442}
2443
2444fn default_credit_check_failure_rate() -> f64 {
2445 0.02
2446}
2447
2448fn default_partial_shipment_rate() -> f64 {
2449 0.10
2450}
2451
2452fn default_return_rate() -> f64 {
2453 0.03
2454}
2455
2456fn default_bad_debt_rate() -> f64 {
2457 0.01
2458}
2459
2460fn default_so_to_delivery_days() -> u32 {
2461 7
2462}
2463
2464fn default_delivery_to_invoice_days() -> u32 {
2465 1
2466}
2467
2468fn default_invoice_to_receipt_days() -> u32 {
2469 45
2470}
2471
2472impl Default for O2CFlowConfig {
2473 fn default() -> Self {
2474 Self {
2475 enabled: true,
2476 credit_check_failure_rate: default_credit_check_failure_rate(),
2477 partial_shipment_rate: default_partial_shipment_rate(),
2478 return_rate: default_return_rate(),
2479 bad_debt_rate: default_bad_debt_rate(),
2480 average_so_to_delivery_days: default_so_to_delivery_days(),
2481 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2482 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2483 line_count_distribution: DocumentLineCountDistribution::default(),
2484 cash_discount: CashDiscountConfig::default(),
2485 payment_behavior: O2CPaymentBehaviorConfig::default(),
2486 }
2487 }
2488}
2489
2490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2496pub struct O2CPaymentBehaviorConfig {
2497 #[serde(default)]
2499 pub dunning: DunningConfig,
2500 #[serde(default)]
2502 pub partial_payments: PartialPaymentConfig,
2503 #[serde(default)]
2505 pub short_payments: ShortPaymentConfig,
2506 #[serde(default)]
2508 pub on_account_payments: OnAccountPaymentConfig,
2509 #[serde(default)]
2511 pub payment_corrections: PaymentCorrectionConfig,
2512}
2513
2514#[derive(Debug, Clone, Serialize, Deserialize)]
2516pub struct DunningConfig {
2517 #[serde(default)]
2519 pub enabled: bool,
2520 #[serde(default = "default_dunning_level_1_days")]
2522 pub level_1_days_overdue: u32,
2523 #[serde(default = "default_dunning_level_2_days")]
2525 pub level_2_days_overdue: u32,
2526 #[serde(default = "default_dunning_level_3_days")]
2528 pub level_3_days_overdue: u32,
2529 #[serde(default = "default_collection_days")]
2531 pub collection_days_overdue: u32,
2532 #[serde(default)]
2534 pub payment_after_dunning_rates: DunningPaymentRates,
2535 #[serde(default = "default_dunning_block_rate")]
2537 pub dunning_block_rate: f64,
2538 #[serde(default = "default_dunning_interest_rate")]
2540 pub interest_rate_per_year: f64,
2541 #[serde(default = "default_dunning_charge")]
2543 pub dunning_charge: f64,
2544}
2545
2546fn default_dunning_level_1_days() -> u32 {
2547 14
2548}
2549
2550fn default_dunning_level_2_days() -> u32 {
2551 28
2552}
2553
2554fn default_dunning_level_3_days() -> u32 {
2555 42
2556}
2557
2558fn default_collection_days() -> u32 {
2559 60
2560}
2561
2562fn default_dunning_block_rate() -> f64 {
2563 0.05
2564}
2565
2566fn default_dunning_interest_rate() -> f64 {
2567 0.09
2568}
2569
2570fn default_dunning_charge() -> f64 {
2571 25.0
2572}
2573
2574impl Default for DunningConfig {
2575 fn default() -> Self {
2576 Self {
2577 enabled: false,
2578 level_1_days_overdue: default_dunning_level_1_days(),
2579 level_2_days_overdue: default_dunning_level_2_days(),
2580 level_3_days_overdue: default_dunning_level_3_days(),
2581 collection_days_overdue: default_collection_days(),
2582 payment_after_dunning_rates: DunningPaymentRates::default(),
2583 dunning_block_rate: default_dunning_block_rate(),
2584 interest_rate_per_year: default_dunning_interest_rate(),
2585 dunning_charge: default_dunning_charge(),
2586 }
2587 }
2588}
2589
2590#[derive(Debug, Clone, Serialize, Deserialize)]
2592pub struct DunningPaymentRates {
2593 #[serde(default = "default_after_level_1")]
2595 pub after_level_1: f64,
2596 #[serde(default = "default_after_level_2")]
2598 pub after_level_2: f64,
2599 #[serde(default = "default_after_level_3")]
2601 pub after_level_3: f64,
2602 #[serde(default = "default_during_collection")]
2604 pub during_collection: f64,
2605 #[serde(default = "default_never_pay")]
2607 pub never_pay: f64,
2608}
2609
2610fn default_after_level_1() -> f64 {
2611 0.40
2612}
2613
2614fn default_after_level_2() -> f64 {
2615 0.30
2616}
2617
2618fn default_after_level_3() -> f64 {
2619 0.15
2620}
2621
2622fn default_during_collection() -> f64 {
2623 0.05
2624}
2625
2626fn default_never_pay() -> f64 {
2627 0.10
2628}
2629
2630impl Default for DunningPaymentRates {
2631 fn default() -> Self {
2632 Self {
2633 after_level_1: default_after_level_1(),
2634 after_level_2: default_after_level_2(),
2635 after_level_3: default_after_level_3(),
2636 during_collection: default_during_collection(),
2637 never_pay: default_never_pay(),
2638 }
2639 }
2640}
2641
2642#[derive(Debug, Clone, Serialize, Deserialize)]
2644pub struct PartialPaymentConfig {
2645 #[serde(default = "default_partial_payment_rate")]
2647 pub rate: f64,
2648 #[serde(default)]
2650 pub percentage_distribution: PartialPaymentPercentageDistribution,
2651 #[serde(default = "default_avg_days_until_remainder")]
2653 pub avg_days_until_remainder: u32,
2654}
2655
2656fn default_partial_payment_rate() -> f64 {
2657 0.08
2658}
2659
2660fn default_avg_days_until_remainder() -> u32 {
2661 30
2662}
2663
2664impl Default for PartialPaymentConfig {
2665 fn default() -> Self {
2666 Self {
2667 rate: default_partial_payment_rate(),
2668 percentage_distribution: PartialPaymentPercentageDistribution::default(),
2669 avg_days_until_remainder: default_avg_days_until_remainder(),
2670 }
2671 }
2672}
2673
2674#[derive(Debug, Clone, Serialize, Deserialize)]
2676pub struct PartialPaymentPercentageDistribution {
2677 #[serde(default = "default_partial_25")]
2679 pub pay_25_percent: f64,
2680 #[serde(default = "default_partial_50")]
2682 pub pay_50_percent: f64,
2683 #[serde(default = "default_partial_75")]
2685 pub pay_75_percent: f64,
2686 #[serde(default = "default_partial_random")]
2688 pub pay_random_percent: f64,
2689}
2690
2691fn default_partial_25() -> f64 {
2692 0.15
2693}
2694
2695fn default_partial_50() -> f64 {
2696 0.50
2697}
2698
2699fn default_partial_75() -> f64 {
2700 0.25
2701}
2702
2703fn default_partial_random() -> f64 {
2704 0.10
2705}
2706
2707impl Default for PartialPaymentPercentageDistribution {
2708 fn default() -> Self {
2709 Self {
2710 pay_25_percent: default_partial_25(),
2711 pay_50_percent: default_partial_50(),
2712 pay_75_percent: default_partial_75(),
2713 pay_random_percent: default_partial_random(),
2714 }
2715 }
2716}
2717
2718#[derive(Debug, Clone, Serialize, Deserialize)]
2720pub struct ShortPaymentConfig {
2721 #[serde(default = "default_short_payment_rate")]
2723 pub rate: f64,
2724 #[serde(default)]
2726 pub reason_distribution: ShortPaymentReasonDistribution,
2727 #[serde(default = "default_max_short_percent")]
2729 pub max_short_percent: f64,
2730}
2731
2732fn default_short_payment_rate() -> f64 {
2733 0.03
2734}
2735
2736fn default_max_short_percent() -> f64 {
2737 0.10
2738}
2739
2740impl Default for ShortPaymentConfig {
2741 fn default() -> Self {
2742 Self {
2743 rate: default_short_payment_rate(),
2744 reason_distribution: ShortPaymentReasonDistribution::default(),
2745 max_short_percent: default_max_short_percent(),
2746 }
2747 }
2748}
2749
2750#[derive(Debug, Clone, Serialize, Deserialize)]
2752pub struct ShortPaymentReasonDistribution {
2753 #[serde(default = "default_pricing_dispute")]
2755 pub pricing_dispute: f64,
2756 #[serde(default = "default_quality_issue")]
2758 pub quality_issue: f64,
2759 #[serde(default = "default_quantity_discrepancy")]
2761 pub quantity_discrepancy: f64,
2762 #[serde(default = "default_unauthorized_deduction")]
2764 pub unauthorized_deduction: f64,
2765 #[serde(default = "default_incorrect_discount")]
2767 pub incorrect_discount: f64,
2768}
2769
2770fn default_pricing_dispute() -> f64 {
2771 0.30
2772}
2773
2774fn default_quality_issue() -> f64 {
2775 0.20
2776}
2777
2778fn default_quantity_discrepancy() -> f64 {
2779 0.20
2780}
2781
2782fn default_unauthorized_deduction() -> f64 {
2783 0.15
2784}
2785
2786fn default_incorrect_discount() -> f64 {
2787 0.15
2788}
2789
2790impl Default for ShortPaymentReasonDistribution {
2791 fn default() -> Self {
2792 Self {
2793 pricing_dispute: default_pricing_dispute(),
2794 quality_issue: default_quality_issue(),
2795 quantity_discrepancy: default_quantity_discrepancy(),
2796 unauthorized_deduction: default_unauthorized_deduction(),
2797 incorrect_discount: default_incorrect_discount(),
2798 }
2799 }
2800}
2801
2802#[derive(Debug, Clone, Serialize, Deserialize)]
2804pub struct OnAccountPaymentConfig {
2805 #[serde(default = "default_on_account_rate")]
2807 pub rate: f64,
2808 #[serde(default = "default_avg_days_until_applied")]
2810 pub avg_days_until_applied: u32,
2811}
2812
2813fn default_on_account_rate() -> f64 {
2814 0.02
2815}
2816
2817fn default_avg_days_until_applied() -> u32 {
2818 14
2819}
2820
2821impl Default for OnAccountPaymentConfig {
2822 fn default() -> Self {
2823 Self {
2824 rate: default_on_account_rate(),
2825 avg_days_until_applied: default_avg_days_until_applied(),
2826 }
2827 }
2828}
2829
2830#[derive(Debug, Clone, Serialize, Deserialize)]
2832pub struct PaymentCorrectionConfig {
2833 #[serde(default = "default_payment_correction_rate")]
2835 pub rate: f64,
2836 #[serde(default)]
2838 pub type_distribution: PaymentCorrectionTypeDistribution,
2839}
2840
2841fn default_payment_correction_rate() -> f64 {
2842 0.02
2843}
2844
2845impl Default for PaymentCorrectionConfig {
2846 fn default() -> Self {
2847 Self {
2848 rate: default_payment_correction_rate(),
2849 type_distribution: PaymentCorrectionTypeDistribution::default(),
2850 }
2851 }
2852}
2853
2854#[derive(Debug, Clone, Serialize, Deserialize)]
2856pub struct PaymentCorrectionTypeDistribution {
2857 #[serde(default = "default_nsf_rate")]
2859 pub nsf: f64,
2860 #[serde(default = "default_chargeback_rate")]
2862 pub chargeback: f64,
2863 #[serde(default = "default_wrong_amount_rate")]
2865 pub wrong_amount: f64,
2866 #[serde(default = "default_wrong_customer_rate")]
2868 pub wrong_customer: f64,
2869 #[serde(default = "default_duplicate_payment_rate")]
2871 pub duplicate_payment: f64,
2872}
2873
2874fn default_nsf_rate() -> f64 {
2875 0.30
2876}
2877
2878fn default_chargeback_rate() -> f64 {
2879 0.20
2880}
2881
2882fn default_wrong_amount_rate() -> f64 {
2883 0.20
2884}
2885
2886fn default_wrong_customer_rate() -> f64 {
2887 0.15
2888}
2889
2890fn default_duplicate_payment_rate() -> f64 {
2891 0.15
2892}
2893
2894impl Default for PaymentCorrectionTypeDistribution {
2895 fn default() -> Self {
2896 Self {
2897 nsf: default_nsf_rate(),
2898 chargeback: default_chargeback_rate(),
2899 wrong_amount: default_wrong_amount_rate(),
2900 wrong_customer: default_wrong_customer_rate(),
2901 duplicate_payment: default_duplicate_payment_rate(),
2902 }
2903 }
2904}
2905
2906#[derive(Debug, Clone, Serialize, Deserialize)]
2908pub struct DocumentLineCountDistribution {
2909 #[serde(default = "default_min_lines")]
2911 pub min_lines: u32,
2912 #[serde(default = "default_max_lines")]
2914 pub max_lines: u32,
2915 #[serde(default = "default_mode_lines")]
2917 pub mode_lines: u32,
2918}
2919
2920fn default_min_lines() -> u32 {
2921 1
2922}
2923
2924fn default_max_lines() -> u32 {
2925 20
2926}
2927
2928fn default_mode_lines() -> u32 {
2929 3
2930}
2931
2932impl Default for DocumentLineCountDistribution {
2933 fn default() -> Self {
2934 Self {
2935 min_lines: default_min_lines(),
2936 max_lines: default_max_lines(),
2937 mode_lines: default_mode_lines(),
2938 }
2939 }
2940}
2941
2942#[derive(Debug, Clone, Serialize, Deserialize)]
2944pub struct CashDiscountConfig {
2945 #[serde(default = "default_discount_eligible_rate")]
2947 pub eligible_rate: f64,
2948 #[serde(default = "default_discount_taken_rate")]
2950 pub taken_rate: f64,
2951 #[serde(default = "default_discount_percent")]
2953 pub discount_percent: f64,
2954 #[serde(default = "default_discount_days")]
2956 pub discount_days: u32,
2957}
2958
2959fn default_discount_eligible_rate() -> f64 {
2960 0.30
2961}
2962
2963fn default_discount_taken_rate() -> f64 {
2964 0.60
2965}
2966
2967fn default_discount_percent() -> f64 {
2968 0.02
2969}
2970
2971fn default_discount_days() -> u32 {
2972 10
2973}
2974
2975impl Default for CashDiscountConfig {
2976 fn default() -> Self {
2977 Self {
2978 eligible_rate: default_discount_eligible_rate(),
2979 taken_rate: default_discount_taken_rate(),
2980 discount_percent: default_discount_percent(),
2981 discount_days: default_discount_days(),
2982 }
2983 }
2984}
2985
2986#[derive(Debug, Clone, Serialize, Deserialize)]
2992pub struct IntercompanyConfig {
2993 #[serde(default)]
2995 pub enabled: bool,
2996 #[serde(default = "default_ic_transaction_rate")]
2998 pub ic_transaction_rate: f64,
2999 #[serde(default)]
3001 pub transfer_pricing_method: TransferPricingMethod,
3002 #[serde(default = "default_markup_percent")]
3004 pub markup_percent: f64,
3005 #[serde(default = "default_true")]
3007 pub generate_matched_pairs: bool,
3008 #[serde(default)]
3010 pub transaction_type_distribution: ICTransactionTypeDistribution,
3011 #[serde(default)]
3013 pub generate_eliminations: bool,
3014}
3015
3016fn default_ic_transaction_rate() -> f64 {
3017 0.15
3018}
3019
3020fn default_markup_percent() -> f64 {
3021 0.05
3022}
3023
3024impl Default for IntercompanyConfig {
3025 fn default() -> Self {
3026 Self {
3027 enabled: false,
3028 ic_transaction_rate: default_ic_transaction_rate(),
3029 transfer_pricing_method: TransferPricingMethod::default(),
3030 markup_percent: default_markup_percent(),
3031 generate_matched_pairs: true,
3032 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3033 generate_eliminations: false,
3034 }
3035 }
3036}
3037
3038#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3040#[serde(rename_all = "snake_case")]
3041pub enum TransferPricingMethod {
3042 #[default]
3044 CostPlus,
3045 ComparableUncontrolled,
3047 ResalePrice,
3049 TransactionalNetMargin,
3051 ProfitSplit,
3053}
3054
3055#[derive(Debug, Clone, Serialize, Deserialize)]
3057pub struct ICTransactionTypeDistribution {
3058 pub goods_sale: f64,
3060 pub service_provided: f64,
3062 pub loan: f64,
3064 pub dividend: f64,
3066 pub management_fee: f64,
3068 pub royalty: f64,
3070 pub cost_sharing: f64,
3072}
3073
3074impl Default for ICTransactionTypeDistribution {
3075 fn default() -> Self {
3076 Self {
3077 goods_sale: 0.35,
3078 service_provided: 0.20,
3079 loan: 0.10,
3080 dividend: 0.05,
3081 management_fee: 0.15,
3082 royalty: 0.10,
3083 cost_sharing: 0.05,
3084 }
3085 }
3086}
3087
3088#[derive(Debug, Clone, Serialize, Deserialize)]
3094pub struct BalanceConfig {
3095 #[serde(default)]
3097 pub generate_opening_balances: bool,
3098 #[serde(default = "default_true")]
3100 pub generate_trial_balances: bool,
3101 #[serde(default = "default_gross_margin")]
3103 pub target_gross_margin: f64,
3104 #[serde(default = "default_dso")]
3106 pub target_dso_days: u32,
3107 #[serde(default = "default_dpo")]
3109 pub target_dpo_days: u32,
3110 #[serde(default = "default_current_ratio")]
3112 pub target_current_ratio: f64,
3113 #[serde(default = "default_debt_equity")]
3115 pub target_debt_to_equity: f64,
3116 #[serde(default = "default_true")]
3118 pub validate_balance_equation: bool,
3119 #[serde(default = "default_true")]
3121 pub reconcile_subledgers: bool,
3122}
3123
3124fn default_gross_margin() -> f64 {
3125 0.35
3126}
3127
3128fn default_dso() -> u32 {
3129 45
3130}
3131
3132fn default_dpo() -> u32 {
3133 30
3134}
3135
3136fn default_current_ratio() -> f64 {
3137 1.5
3138}
3139
3140fn default_debt_equity() -> f64 {
3141 0.5
3142}
3143
3144impl Default for BalanceConfig {
3145 fn default() -> Self {
3146 Self {
3147 generate_opening_balances: false,
3148 generate_trial_balances: true,
3149 target_gross_margin: default_gross_margin(),
3150 target_dso_days: default_dso(),
3151 target_dpo_days: default_dpo(),
3152 target_current_ratio: default_current_ratio(),
3153 target_debt_to_equity: default_debt_equity(),
3154 validate_balance_equation: true,
3155 reconcile_subledgers: true,
3156 }
3157 }
3158}
3159
3160#[derive(Debug, Clone, Serialize, Deserialize)]
3169pub struct OcpmConfig {
3170 #[serde(default)]
3172 pub enabled: bool,
3173
3174 #[serde(default = "default_true")]
3176 pub generate_lifecycle_events: bool,
3177
3178 #[serde(default = "default_true")]
3180 pub include_object_relationships: bool,
3181
3182 #[serde(default = "default_true")]
3184 pub compute_variants: bool,
3185
3186 #[serde(default)]
3188 pub max_variants: usize,
3189
3190 #[serde(default)]
3192 pub p2p_process: OcpmProcessConfig,
3193
3194 #[serde(default)]
3196 pub o2c_process: OcpmProcessConfig,
3197
3198 #[serde(default)]
3200 pub output: OcpmOutputConfig,
3201}
3202
3203impl Default for OcpmConfig {
3204 fn default() -> Self {
3205 Self {
3206 enabled: false,
3207 generate_lifecycle_events: true,
3208 include_object_relationships: true,
3209 compute_variants: true,
3210 max_variants: 0,
3211 p2p_process: OcpmProcessConfig::default(),
3212 o2c_process: OcpmProcessConfig::default(),
3213 output: OcpmOutputConfig::default(),
3214 }
3215 }
3216}
3217
3218#[derive(Debug, Clone, Serialize, Deserialize)]
3220pub struct OcpmProcessConfig {
3221 #[serde(default = "default_rework_probability")]
3223 pub rework_probability: f64,
3224
3225 #[serde(default = "default_skip_probability")]
3227 pub skip_step_probability: f64,
3228
3229 #[serde(default = "default_out_of_order_probability")]
3231 pub out_of_order_probability: f64,
3232}
3233
3234fn default_rework_probability() -> f64 {
3235 0.05
3236}
3237
3238fn default_skip_probability() -> f64 {
3239 0.02
3240}
3241
3242fn default_out_of_order_probability() -> f64 {
3243 0.03
3244}
3245
3246impl Default for OcpmProcessConfig {
3247 fn default() -> Self {
3248 Self {
3249 rework_probability: default_rework_probability(),
3250 skip_step_probability: default_skip_probability(),
3251 out_of_order_probability: default_out_of_order_probability(),
3252 }
3253 }
3254}
3255
3256#[derive(Debug, Clone, Serialize, Deserialize)]
3258pub struct OcpmOutputConfig {
3259 #[serde(default = "default_true")]
3261 pub ocel_json: bool,
3262
3263 #[serde(default)]
3265 pub ocel_xml: bool,
3266
3267 #[serde(default)]
3269 pub xes: bool,
3270
3271 #[serde(default = "default_true")]
3273 pub xes_include_lifecycle: bool,
3274
3275 #[serde(default = "default_true")]
3277 pub xes_include_resources: bool,
3278
3279 #[serde(default = "default_true")]
3281 pub flattened_csv: bool,
3282
3283 #[serde(default = "default_true")]
3285 pub event_object_csv: bool,
3286
3287 #[serde(default = "default_true")]
3289 pub object_relationship_csv: bool,
3290
3291 #[serde(default = "default_true")]
3293 pub variants_csv: bool,
3294
3295 #[serde(default)]
3297 pub export_reference_models: bool,
3298}
3299
3300impl Default for OcpmOutputConfig {
3301 fn default() -> Self {
3302 Self {
3303 ocel_json: true,
3304 ocel_xml: false,
3305 xes: false,
3306 xes_include_lifecycle: true,
3307 xes_include_resources: true,
3308 flattened_csv: true,
3309 event_object_csv: true,
3310 object_relationship_csv: true,
3311 variants_csv: true,
3312 export_reference_models: false,
3313 }
3314 }
3315}
3316
3317#[derive(Debug, Clone, Serialize, Deserialize)]
3319pub struct AuditGenerationConfig {
3320 #[serde(default)]
3322 pub enabled: bool,
3323
3324 #[serde(default = "default_true")]
3326 pub generate_workpapers: bool,
3327
3328 #[serde(default)]
3330 pub engagement_types: AuditEngagementTypesConfig,
3331
3332 #[serde(default)]
3334 pub workpapers: WorkpaperConfig,
3335
3336 #[serde(default)]
3338 pub team: AuditTeamConfig,
3339
3340 #[serde(default)]
3342 pub review: ReviewWorkflowConfig,
3343}
3344
3345impl Default for AuditGenerationConfig {
3346 fn default() -> Self {
3347 Self {
3348 enabled: false,
3349 generate_workpapers: true,
3350 engagement_types: AuditEngagementTypesConfig::default(),
3351 workpapers: WorkpaperConfig::default(),
3352 team: AuditTeamConfig::default(),
3353 review: ReviewWorkflowConfig::default(),
3354 }
3355 }
3356}
3357
3358#[derive(Debug, Clone, Serialize, Deserialize)]
3360pub struct AuditEngagementTypesConfig {
3361 #[serde(default = "default_financial_audit_prob")]
3363 pub financial_statement: f64,
3364 #[serde(default = "default_sox_audit_prob")]
3366 pub sox_icfr: f64,
3367 #[serde(default = "default_integrated_audit_prob")]
3369 pub integrated: f64,
3370 #[serde(default = "default_review_prob")]
3372 pub review: f64,
3373 #[serde(default = "default_aup_prob")]
3375 pub agreed_upon_procedures: f64,
3376}
3377
3378fn default_financial_audit_prob() -> f64 {
3379 0.40
3380}
3381fn default_sox_audit_prob() -> f64 {
3382 0.20
3383}
3384fn default_integrated_audit_prob() -> f64 {
3385 0.25
3386}
3387fn default_review_prob() -> f64 {
3388 0.10
3389}
3390fn default_aup_prob() -> f64 {
3391 0.05
3392}
3393
3394impl Default for AuditEngagementTypesConfig {
3395 fn default() -> Self {
3396 Self {
3397 financial_statement: default_financial_audit_prob(),
3398 sox_icfr: default_sox_audit_prob(),
3399 integrated: default_integrated_audit_prob(),
3400 review: default_review_prob(),
3401 agreed_upon_procedures: default_aup_prob(),
3402 }
3403 }
3404}
3405
3406#[derive(Debug, Clone, Serialize, Deserialize)]
3408pub struct WorkpaperConfig {
3409 #[serde(default = "default_workpapers_per_phase")]
3411 pub average_per_phase: usize,
3412
3413 #[serde(default = "default_true")]
3415 pub include_isa_references: bool,
3416
3417 #[serde(default = "default_true")]
3419 pub include_sample_details: bool,
3420
3421 #[serde(default = "default_true")]
3423 pub include_cross_references: bool,
3424
3425 #[serde(default)]
3427 pub sampling: SamplingConfig,
3428}
3429
3430fn default_workpapers_per_phase() -> usize {
3431 5
3432}
3433
3434impl Default for WorkpaperConfig {
3435 fn default() -> Self {
3436 Self {
3437 average_per_phase: default_workpapers_per_phase(),
3438 include_isa_references: true,
3439 include_sample_details: true,
3440 include_cross_references: true,
3441 sampling: SamplingConfig::default(),
3442 }
3443 }
3444}
3445
3446#[derive(Debug, Clone, Serialize, Deserialize)]
3448pub struct SamplingConfig {
3449 #[serde(default = "default_statistical_rate")]
3451 pub statistical_rate: f64,
3452 #[serde(default = "default_judgmental_rate")]
3454 pub judgmental_rate: f64,
3455 #[serde(default = "default_haphazard_rate")]
3457 pub haphazard_rate: f64,
3458 #[serde(default = "default_complete_examination_rate")]
3460 pub complete_examination_rate: f64,
3461}
3462
3463fn default_statistical_rate() -> f64 {
3464 0.40
3465}
3466fn default_judgmental_rate() -> f64 {
3467 0.30
3468}
3469fn default_haphazard_rate() -> f64 {
3470 0.20
3471}
3472fn default_complete_examination_rate() -> f64 {
3473 0.10
3474}
3475
3476impl Default for SamplingConfig {
3477 fn default() -> Self {
3478 Self {
3479 statistical_rate: default_statistical_rate(),
3480 judgmental_rate: default_judgmental_rate(),
3481 haphazard_rate: default_haphazard_rate(),
3482 complete_examination_rate: default_complete_examination_rate(),
3483 }
3484 }
3485}
3486
3487#[derive(Debug, Clone, Serialize, Deserialize)]
3489pub struct AuditTeamConfig {
3490 #[serde(default = "default_min_team_size")]
3492 pub min_team_size: usize,
3493 #[serde(default = "default_max_team_size")]
3495 pub max_team_size: usize,
3496 #[serde(default = "default_specialist_probability")]
3498 pub specialist_probability: f64,
3499}
3500
3501fn default_min_team_size() -> usize {
3502 3
3503}
3504fn default_max_team_size() -> usize {
3505 8
3506}
3507fn default_specialist_probability() -> f64 {
3508 0.30
3509}
3510
3511impl Default for AuditTeamConfig {
3512 fn default() -> Self {
3513 Self {
3514 min_team_size: default_min_team_size(),
3515 max_team_size: default_max_team_size(),
3516 specialist_probability: default_specialist_probability(),
3517 }
3518 }
3519}
3520
3521#[derive(Debug, Clone, Serialize, Deserialize)]
3523pub struct ReviewWorkflowConfig {
3524 #[serde(default = "default_review_delay_days")]
3526 pub average_review_delay_days: u32,
3527 #[serde(default = "default_rework_probability_review")]
3529 pub rework_probability: f64,
3530 #[serde(default = "default_true")]
3532 pub require_partner_signoff: bool,
3533}
3534
3535fn default_review_delay_days() -> u32 {
3536 2
3537}
3538fn default_rework_probability_review() -> f64 {
3539 0.15
3540}
3541
3542impl Default for ReviewWorkflowConfig {
3543 fn default() -> Self {
3544 Self {
3545 average_review_delay_days: default_review_delay_days(),
3546 rework_probability: default_rework_probability_review(),
3547 require_partner_signoff: true,
3548 }
3549 }
3550}
3551
3552#[derive(Debug, Clone, Serialize, Deserialize)]
3558pub struct DataQualitySchemaConfig {
3559 #[serde(default)]
3561 pub enabled: bool,
3562 #[serde(default)]
3564 pub preset: DataQualityPreset,
3565 #[serde(default)]
3567 pub missing_values: MissingValuesSchemaConfig,
3568 #[serde(default)]
3570 pub typos: TypoSchemaConfig,
3571 #[serde(default)]
3573 pub format_variations: FormatVariationSchemaConfig,
3574 #[serde(default)]
3576 pub duplicates: DuplicateSchemaConfig,
3577 #[serde(default)]
3579 pub encoding_issues: EncodingIssueSchemaConfig,
3580 #[serde(default)]
3582 pub generate_labels: bool,
3583 #[serde(default)]
3585 pub sink_profiles: SinkQualityProfiles,
3586}
3587
3588impl Default for DataQualitySchemaConfig {
3589 fn default() -> Self {
3590 Self {
3591 enabled: false,
3592 preset: DataQualityPreset::None,
3593 missing_values: MissingValuesSchemaConfig::default(),
3594 typos: TypoSchemaConfig::default(),
3595 format_variations: FormatVariationSchemaConfig::default(),
3596 duplicates: DuplicateSchemaConfig::default(),
3597 encoding_issues: EncodingIssueSchemaConfig::default(),
3598 generate_labels: true,
3599 sink_profiles: SinkQualityProfiles::default(),
3600 }
3601 }
3602}
3603
3604impl DataQualitySchemaConfig {
3605 pub fn with_preset(preset: DataQualityPreset) -> Self {
3607 let mut config = Self {
3608 preset,
3609 ..Default::default()
3610 };
3611 config.apply_preset();
3612 config
3613 }
3614
3615 pub fn apply_preset(&mut self) {
3618 if !self.preset.overrides_settings() {
3619 return;
3620 }
3621
3622 self.enabled = true;
3623
3624 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3626 self.missing_values.rate = self.preset.missing_rate();
3627
3628 self.typos.enabled = self.preset.typo_rate() > 0.0;
3630 self.typos.char_error_rate = self.preset.typo_rate();
3631
3632 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3634 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3635 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3636 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3637
3638 self.format_variations.enabled = self.preset.format_variations_enabled();
3640
3641 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3643 self.encoding_issues.rate = self.preset.encoding_issue_rate();
3644
3645 if self.preset.ocr_errors_enabled() {
3647 self.typos.type_weights.ocr_errors = 0.3;
3648 }
3649 }
3650
3651 pub fn effective_missing_rate(&self) -> f64 {
3653 if self.preset.overrides_settings() {
3654 self.preset.missing_rate()
3655 } else {
3656 self.missing_values.rate
3657 }
3658 }
3659
3660 pub fn effective_typo_rate(&self) -> f64 {
3662 if self.preset.overrides_settings() {
3663 self.preset.typo_rate()
3664 } else {
3665 self.typos.char_error_rate
3666 }
3667 }
3668
3669 pub fn effective_duplicate_rate(&self) -> f64 {
3671 if self.preset.overrides_settings() {
3672 self.preset.duplicate_rate()
3673 } else {
3674 self.duplicates.exact_duplicate_ratio
3675 + self.duplicates.near_duplicate_ratio
3676 + self.duplicates.fuzzy_duplicate_ratio
3677 }
3678 }
3679
3680 pub fn clean() -> Self {
3682 Self::with_preset(DataQualityPreset::Clean)
3683 }
3684
3685 pub fn noisy() -> Self {
3687 Self::with_preset(DataQualityPreset::Noisy)
3688 }
3689
3690 pub fn legacy() -> Self {
3692 Self::with_preset(DataQualityPreset::Legacy)
3693 }
3694}
3695
3696#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3698#[serde(rename_all = "snake_case")]
3699pub enum DataQualityPreset {
3700 #[default]
3702 None,
3703 Minimal,
3705 Normal,
3707 High,
3709 Custom,
3711
3712 Clean,
3718 Noisy,
3721 Legacy,
3724}
3725
3726impl DataQualityPreset {
3727 pub fn missing_rate(&self) -> f64 {
3729 match self {
3730 DataQualityPreset::None => 0.0,
3731 DataQualityPreset::Minimal => 0.005,
3732 DataQualityPreset::Normal => 0.02,
3733 DataQualityPreset::High => 0.08,
3734 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
3736 DataQualityPreset::Noisy => 0.05,
3737 DataQualityPreset::Legacy => 0.10,
3738 }
3739 }
3740
3741 pub fn typo_rate(&self) -> f64 {
3743 match self {
3744 DataQualityPreset::None => 0.0,
3745 DataQualityPreset::Minimal => 0.0005,
3746 DataQualityPreset::Normal => 0.002,
3747 DataQualityPreset::High => 0.01,
3748 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
3750 DataQualityPreset::Noisy => 0.02,
3751 DataQualityPreset::Legacy => 0.05,
3752 }
3753 }
3754
3755 pub fn duplicate_rate(&self) -> f64 {
3757 match self {
3758 DataQualityPreset::None => 0.0,
3759 DataQualityPreset::Minimal => 0.001,
3760 DataQualityPreset::Normal => 0.005,
3761 DataQualityPreset::High => 0.02,
3762 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
3764 DataQualityPreset::Noisy => 0.01,
3765 DataQualityPreset::Legacy => 0.03,
3766 }
3767 }
3768
3769 pub fn format_variations_enabled(&self) -> bool {
3771 match self {
3772 DataQualityPreset::None | DataQualityPreset::Clean => false,
3773 DataQualityPreset::Minimal => true,
3774 DataQualityPreset::Normal => true,
3775 DataQualityPreset::High => true,
3776 DataQualityPreset::Custom => true,
3777 DataQualityPreset::Noisy => true,
3778 DataQualityPreset::Legacy => true,
3779 }
3780 }
3781
3782 pub fn ocr_errors_enabled(&self) -> bool {
3784 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
3785 }
3786
3787 pub fn encoding_issues_enabled(&self) -> bool {
3789 matches!(
3790 self,
3791 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
3792 )
3793 }
3794
3795 pub fn encoding_issue_rate(&self) -> f64 {
3797 match self {
3798 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
3799 DataQualityPreset::Normal => 0.002,
3800 DataQualityPreset::High => 0.01,
3801 DataQualityPreset::Custom => 0.0,
3802 DataQualityPreset::Noisy => 0.005,
3803 DataQualityPreset::Legacy => 0.02,
3804 }
3805 }
3806
3807 pub fn overrides_settings(&self) -> bool {
3809 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
3810 }
3811
3812 pub fn description(&self) -> &'static str {
3814 match self {
3815 DataQualityPreset::None => "No data quality issues (pristine data)",
3816 DataQualityPreset::Minimal => "Very rare data quality issues",
3817 DataQualityPreset::Normal => "Realistic enterprise data quality",
3818 DataQualityPreset::High => "Messy data for stress testing",
3819 DataQualityPreset::Custom => "Custom settings from configuration",
3820 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
3821 DataQualityPreset::Noisy => "Typical production data with moderate issues",
3822 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
3823 }
3824 }
3825}
3826
3827#[derive(Debug, Clone, Serialize, Deserialize)]
3829pub struct MissingValuesSchemaConfig {
3830 #[serde(default)]
3832 pub enabled: bool,
3833 #[serde(default = "default_missing_rate")]
3835 pub rate: f64,
3836 #[serde(default)]
3838 pub strategy: MissingValueStrategy,
3839 #[serde(default)]
3841 pub field_rates: std::collections::HashMap<String, f64>,
3842 #[serde(default)]
3844 pub protected_fields: Vec<String>,
3845}
3846
3847fn default_missing_rate() -> f64 {
3848 0.01
3849}
3850
3851impl Default for MissingValuesSchemaConfig {
3852 fn default() -> Self {
3853 Self {
3854 enabled: false,
3855 rate: default_missing_rate(),
3856 strategy: MissingValueStrategy::Mcar,
3857 field_rates: std::collections::HashMap::new(),
3858 protected_fields: vec![
3859 "document_id".to_string(),
3860 "company_code".to_string(),
3861 "posting_date".to_string(),
3862 ],
3863 }
3864 }
3865}
3866
3867#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3869#[serde(rename_all = "snake_case")]
3870pub enum MissingValueStrategy {
3871 #[default]
3873 Mcar,
3874 Mar,
3876 Mnar,
3878 Systematic,
3880}
3881
3882#[derive(Debug, Clone, Serialize, Deserialize)]
3884pub struct TypoSchemaConfig {
3885 #[serde(default)]
3887 pub enabled: bool,
3888 #[serde(default = "default_typo_rate")]
3890 pub char_error_rate: f64,
3891 #[serde(default)]
3893 pub type_weights: TypoTypeWeights,
3894 #[serde(default)]
3896 pub protected_fields: Vec<String>,
3897}
3898
3899fn default_typo_rate() -> f64 {
3900 0.001
3901}
3902
3903impl Default for TypoSchemaConfig {
3904 fn default() -> Self {
3905 Self {
3906 enabled: false,
3907 char_error_rate: default_typo_rate(),
3908 type_weights: TypoTypeWeights::default(),
3909 protected_fields: vec![
3910 "document_id".to_string(),
3911 "gl_account".to_string(),
3912 "company_code".to_string(),
3913 ],
3914 }
3915 }
3916}
3917
3918#[derive(Debug, Clone, Serialize, Deserialize)]
3920pub struct TypoTypeWeights {
3921 #[serde(default = "default_substitution_weight")]
3923 pub substitution: f64,
3924 #[serde(default = "default_transposition_weight")]
3926 pub transposition: f64,
3927 #[serde(default = "default_insertion_weight")]
3929 pub insertion: f64,
3930 #[serde(default = "default_deletion_weight")]
3932 pub deletion: f64,
3933 #[serde(default = "default_ocr_weight")]
3935 pub ocr_errors: f64,
3936 #[serde(default = "default_homophone_weight")]
3938 pub homophones: f64,
3939}
3940
3941fn default_substitution_weight() -> f64 {
3942 0.35
3943}
3944fn default_transposition_weight() -> f64 {
3945 0.25
3946}
3947fn default_insertion_weight() -> f64 {
3948 0.10
3949}
3950fn default_deletion_weight() -> f64 {
3951 0.15
3952}
3953fn default_ocr_weight() -> f64 {
3954 0.10
3955}
3956fn default_homophone_weight() -> f64 {
3957 0.05
3958}
3959
3960impl Default for TypoTypeWeights {
3961 fn default() -> Self {
3962 Self {
3963 substitution: default_substitution_weight(),
3964 transposition: default_transposition_weight(),
3965 insertion: default_insertion_weight(),
3966 deletion: default_deletion_weight(),
3967 ocr_errors: default_ocr_weight(),
3968 homophones: default_homophone_weight(),
3969 }
3970 }
3971}
3972
3973#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3975pub struct FormatVariationSchemaConfig {
3976 #[serde(default)]
3978 pub enabled: bool,
3979 #[serde(default)]
3981 pub dates: DateFormatVariationConfig,
3982 #[serde(default)]
3984 pub amounts: AmountFormatVariationConfig,
3985 #[serde(default)]
3987 pub identifiers: IdentifierFormatVariationConfig,
3988}
3989
3990#[derive(Debug, Clone, Serialize, Deserialize)]
3992pub struct DateFormatVariationConfig {
3993 #[serde(default)]
3995 pub enabled: bool,
3996 #[serde(default = "default_date_variation_rate")]
3998 pub rate: f64,
3999 #[serde(default = "default_true")]
4001 pub iso_format: bool,
4002 #[serde(default)]
4004 pub us_format: bool,
4005 #[serde(default)]
4007 pub eu_format: bool,
4008 #[serde(default)]
4010 pub long_format: bool,
4011}
4012
4013fn default_date_variation_rate() -> f64 {
4014 0.05
4015}
4016
4017impl Default for DateFormatVariationConfig {
4018 fn default() -> Self {
4019 Self {
4020 enabled: false,
4021 rate: default_date_variation_rate(),
4022 iso_format: true,
4023 us_format: false,
4024 eu_format: false,
4025 long_format: false,
4026 }
4027 }
4028}
4029
4030#[derive(Debug, Clone, Serialize, Deserialize)]
4032pub struct AmountFormatVariationConfig {
4033 #[serde(default)]
4035 pub enabled: bool,
4036 #[serde(default = "default_amount_variation_rate")]
4038 pub rate: f64,
4039 #[serde(default)]
4041 pub us_comma_format: bool,
4042 #[serde(default)]
4044 pub eu_format: bool,
4045 #[serde(default)]
4047 pub currency_prefix: bool,
4048 #[serde(default)]
4050 pub accounting_format: bool,
4051}
4052
4053fn default_amount_variation_rate() -> f64 {
4054 0.02
4055}
4056
4057impl Default for AmountFormatVariationConfig {
4058 fn default() -> Self {
4059 Self {
4060 enabled: false,
4061 rate: default_amount_variation_rate(),
4062 us_comma_format: false,
4063 eu_format: false,
4064 currency_prefix: false,
4065 accounting_format: false,
4066 }
4067 }
4068}
4069
4070#[derive(Debug, Clone, Serialize, Deserialize)]
4072pub struct IdentifierFormatVariationConfig {
4073 #[serde(default)]
4075 pub enabled: bool,
4076 #[serde(default = "default_identifier_variation_rate")]
4078 pub rate: f64,
4079 #[serde(default)]
4081 pub case_variations: bool,
4082 #[serde(default)]
4084 pub padding_variations: bool,
4085 #[serde(default)]
4087 pub separator_variations: bool,
4088}
4089
4090fn default_identifier_variation_rate() -> f64 {
4091 0.02
4092}
4093
4094impl Default for IdentifierFormatVariationConfig {
4095 fn default() -> Self {
4096 Self {
4097 enabled: false,
4098 rate: default_identifier_variation_rate(),
4099 case_variations: false,
4100 padding_variations: false,
4101 separator_variations: false,
4102 }
4103 }
4104}
4105
4106#[derive(Debug, Clone, Serialize, Deserialize)]
4108pub struct DuplicateSchemaConfig {
4109 #[serde(default)]
4111 pub enabled: bool,
4112 #[serde(default = "default_duplicate_rate")]
4114 pub rate: f64,
4115 #[serde(default = "default_exact_duplicate_ratio")]
4117 pub exact_duplicate_ratio: f64,
4118 #[serde(default = "default_near_duplicate_ratio")]
4120 pub near_duplicate_ratio: f64,
4121 #[serde(default = "default_fuzzy_duplicate_ratio")]
4123 pub fuzzy_duplicate_ratio: f64,
4124 #[serde(default = "default_max_date_offset")]
4126 pub max_date_offset_days: u32,
4127 #[serde(default = "default_max_amount_variance")]
4129 pub max_amount_variance: f64,
4130}
4131
4132fn default_duplicate_rate() -> f64 {
4133 0.005
4134}
4135fn default_exact_duplicate_ratio() -> f64 {
4136 0.4
4137}
4138fn default_near_duplicate_ratio() -> f64 {
4139 0.35
4140}
4141fn default_fuzzy_duplicate_ratio() -> f64 {
4142 0.25
4143}
4144fn default_max_date_offset() -> u32 {
4145 3
4146}
4147fn default_max_amount_variance() -> f64 {
4148 0.01
4149}
4150
4151impl Default for DuplicateSchemaConfig {
4152 fn default() -> Self {
4153 Self {
4154 enabled: false,
4155 rate: default_duplicate_rate(),
4156 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4157 near_duplicate_ratio: default_near_duplicate_ratio(),
4158 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4159 max_date_offset_days: default_max_date_offset(),
4160 max_amount_variance: default_max_amount_variance(),
4161 }
4162 }
4163}
4164
4165#[derive(Debug, Clone, Serialize, Deserialize)]
4167pub struct EncodingIssueSchemaConfig {
4168 #[serde(default)]
4170 pub enabled: bool,
4171 #[serde(default = "default_encoding_rate")]
4173 pub rate: f64,
4174 #[serde(default)]
4176 pub mojibake: bool,
4177 #[serde(default)]
4179 pub html_entities: bool,
4180 #[serde(default)]
4182 pub bom_issues: bool,
4183}
4184
4185fn default_encoding_rate() -> f64 {
4186 0.001
4187}
4188
4189impl Default for EncodingIssueSchemaConfig {
4190 fn default() -> Self {
4191 Self {
4192 enabled: false,
4193 rate: default_encoding_rate(),
4194 mojibake: false,
4195 html_entities: false,
4196 bom_issues: false,
4197 }
4198 }
4199}
4200
4201#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4203pub struct SinkQualityProfiles {
4204 #[serde(default)]
4206 pub csv: Option<SinkQualityOverride>,
4207 #[serde(default)]
4209 pub json: Option<SinkQualityOverride>,
4210 #[serde(default)]
4212 pub parquet: Option<SinkQualityOverride>,
4213}
4214
4215#[derive(Debug, Clone, Serialize, Deserialize)]
4217pub struct SinkQualityOverride {
4218 pub enabled: Option<bool>,
4220 pub missing_rate: Option<f64>,
4222 pub typo_rate: Option<f64>,
4224 pub format_variation_rate: Option<f64>,
4226 pub duplicate_rate: Option<f64>,
4228}
4229
4230#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4242pub struct AccountingStandardsConfig {
4243 #[serde(default)]
4245 pub enabled: bool,
4246
4247 #[serde(default)]
4249 pub framework: AccountingFrameworkConfig,
4250
4251 #[serde(default)]
4253 pub revenue_recognition: RevenueRecognitionConfig,
4254
4255 #[serde(default)]
4257 pub leases: LeaseAccountingConfig,
4258
4259 #[serde(default)]
4261 pub fair_value: FairValueConfig,
4262
4263 #[serde(default)]
4265 pub impairment: ImpairmentConfig,
4266
4267 #[serde(default)]
4269 pub generate_differences: bool,
4270}
4271
4272#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4274#[serde(rename_all = "snake_case")]
4275pub enum AccountingFrameworkConfig {
4276 #[default]
4278 UsGaap,
4279 Ifrs,
4281 DualReporting,
4283}
4284
4285#[derive(Debug, Clone, Serialize, Deserialize)]
4287pub struct RevenueRecognitionConfig {
4288 #[serde(default)]
4290 pub enabled: bool,
4291
4292 #[serde(default = "default_true")]
4294 pub generate_contracts: bool,
4295
4296 #[serde(default = "default_avg_obligations")]
4298 pub avg_obligations_per_contract: f64,
4299
4300 #[serde(default = "default_variable_consideration_rate")]
4302 pub variable_consideration_rate: f64,
4303
4304 #[serde(default = "default_over_time_rate")]
4306 pub over_time_recognition_rate: f64,
4307
4308 #[serde(default = "default_contract_count")]
4310 pub contract_count: usize,
4311}
4312
4313fn default_avg_obligations() -> f64 {
4314 2.0
4315}
4316
4317fn default_variable_consideration_rate() -> f64 {
4318 0.15
4319}
4320
4321fn default_over_time_rate() -> f64 {
4322 0.30
4323}
4324
4325fn default_contract_count() -> usize {
4326 100
4327}
4328
4329impl Default for RevenueRecognitionConfig {
4330 fn default() -> Self {
4331 Self {
4332 enabled: false,
4333 generate_contracts: true,
4334 avg_obligations_per_contract: default_avg_obligations(),
4335 variable_consideration_rate: default_variable_consideration_rate(),
4336 over_time_recognition_rate: default_over_time_rate(),
4337 contract_count: default_contract_count(),
4338 }
4339 }
4340}
4341
4342#[derive(Debug, Clone, Serialize, Deserialize)]
4344pub struct LeaseAccountingConfig {
4345 #[serde(default)]
4347 pub enabled: bool,
4348
4349 #[serde(default = "default_lease_count")]
4351 pub lease_count: usize,
4352
4353 #[serde(default = "default_finance_lease_pct")]
4355 pub finance_lease_percent: f64,
4356
4357 #[serde(default = "default_avg_lease_term")]
4359 pub avg_lease_term_months: u32,
4360
4361 #[serde(default = "default_true")]
4363 pub generate_amortization: bool,
4364
4365 #[serde(default = "default_real_estate_pct")]
4367 pub real_estate_percent: f64,
4368}
4369
4370fn default_lease_count() -> usize {
4371 50
4372}
4373
4374fn default_finance_lease_pct() -> f64 {
4375 0.30
4376}
4377
4378fn default_avg_lease_term() -> u32 {
4379 60
4380}
4381
4382fn default_real_estate_pct() -> f64 {
4383 0.40
4384}
4385
4386impl Default for LeaseAccountingConfig {
4387 fn default() -> Self {
4388 Self {
4389 enabled: false,
4390 lease_count: default_lease_count(),
4391 finance_lease_percent: default_finance_lease_pct(),
4392 avg_lease_term_months: default_avg_lease_term(),
4393 generate_amortization: true,
4394 real_estate_percent: default_real_estate_pct(),
4395 }
4396 }
4397}
4398
4399#[derive(Debug, Clone, Serialize, Deserialize)]
4401pub struct FairValueConfig {
4402 #[serde(default)]
4404 pub enabled: bool,
4405
4406 #[serde(default = "default_fv_count")]
4408 pub measurement_count: usize,
4409
4410 #[serde(default = "default_level1_pct")]
4412 pub level1_percent: f64,
4413
4414 #[serde(default = "default_level2_pct")]
4416 pub level2_percent: f64,
4417
4418 #[serde(default = "default_level3_pct")]
4420 pub level3_percent: f64,
4421
4422 #[serde(default)]
4424 pub include_sensitivity_analysis: bool,
4425}
4426
4427fn default_fv_count() -> usize {
4428 25
4429}
4430
4431fn default_level1_pct() -> f64 {
4432 0.40
4433}
4434
4435fn default_level2_pct() -> f64 {
4436 0.35
4437}
4438
4439fn default_level3_pct() -> f64 {
4440 0.25
4441}
4442
4443impl Default for FairValueConfig {
4444 fn default() -> Self {
4445 Self {
4446 enabled: false,
4447 measurement_count: default_fv_count(),
4448 level1_percent: default_level1_pct(),
4449 level2_percent: default_level2_pct(),
4450 level3_percent: default_level3_pct(),
4451 include_sensitivity_analysis: false,
4452 }
4453 }
4454}
4455
4456#[derive(Debug, Clone, Serialize, Deserialize)]
4458pub struct ImpairmentConfig {
4459 #[serde(default)]
4461 pub enabled: bool,
4462
4463 #[serde(default = "default_impairment_count")]
4465 pub test_count: usize,
4466
4467 #[serde(default = "default_impairment_rate")]
4469 pub impairment_rate: f64,
4470
4471 #[serde(default = "default_true")]
4473 pub generate_projections: bool,
4474
4475 #[serde(default)]
4477 pub include_goodwill: bool,
4478}
4479
4480fn default_impairment_count() -> usize {
4481 15
4482}
4483
4484fn default_impairment_rate() -> f64 {
4485 0.10
4486}
4487
4488impl Default for ImpairmentConfig {
4489 fn default() -> Self {
4490 Self {
4491 enabled: false,
4492 test_count: default_impairment_count(),
4493 impairment_rate: default_impairment_rate(),
4494 generate_projections: true,
4495 include_goodwill: false,
4496 }
4497 }
4498}
4499
4500#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4513pub struct AuditStandardsConfig {
4514 #[serde(default)]
4516 pub enabled: bool,
4517
4518 #[serde(default)]
4520 pub isa_compliance: IsaComplianceConfig,
4521
4522 #[serde(default)]
4524 pub analytical_procedures: AnalyticalProceduresConfig,
4525
4526 #[serde(default)]
4528 pub confirmations: ConfirmationsConfig,
4529
4530 #[serde(default)]
4532 pub opinion: AuditOpinionConfig,
4533
4534 #[serde(default)]
4536 pub generate_audit_trail: bool,
4537
4538 #[serde(default)]
4540 pub sox: SoxComplianceConfig,
4541
4542 #[serde(default)]
4544 pub pcaob: PcaobConfig,
4545}
4546
4547#[derive(Debug, Clone, Serialize, Deserialize)]
4549pub struct IsaComplianceConfig {
4550 #[serde(default)]
4552 pub enabled: bool,
4553
4554 #[serde(default = "default_compliance_level")]
4556 pub compliance_level: String,
4557
4558 #[serde(default = "default_true")]
4560 pub generate_isa_mappings: bool,
4561
4562 #[serde(default = "default_true")]
4564 pub generate_coverage_summary: bool,
4565
4566 #[serde(default)]
4568 pub include_pcaob: bool,
4569
4570 #[serde(default = "default_audit_framework")]
4572 pub framework: String,
4573}
4574
4575fn default_compliance_level() -> String {
4576 "standard".to_string()
4577}
4578
4579fn default_audit_framework() -> String {
4580 "isa".to_string()
4581}
4582
4583impl Default for IsaComplianceConfig {
4584 fn default() -> Self {
4585 Self {
4586 enabled: false,
4587 compliance_level: default_compliance_level(),
4588 generate_isa_mappings: true,
4589 generate_coverage_summary: true,
4590 include_pcaob: false,
4591 framework: default_audit_framework(),
4592 }
4593 }
4594}
4595
4596#[derive(Debug, Clone, Serialize, Deserialize)]
4598pub struct AnalyticalProceduresConfig {
4599 #[serde(default)]
4601 pub enabled: bool,
4602
4603 #[serde(default = "default_procedures_per_account")]
4605 pub procedures_per_account: usize,
4606
4607 #[serde(default = "default_variance_probability")]
4609 pub variance_probability: f64,
4610
4611 #[serde(default = "default_true")]
4613 pub generate_investigations: bool,
4614
4615 #[serde(default = "default_true")]
4617 pub include_ratio_analysis: bool,
4618}
4619
4620fn default_procedures_per_account() -> usize {
4621 3
4622}
4623
4624fn default_variance_probability() -> f64 {
4625 0.20
4626}
4627
4628impl Default for AnalyticalProceduresConfig {
4629 fn default() -> Self {
4630 Self {
4631 enabled: false,
4632 procedures_per_account: default_procedures_per_account(),
4633 variance_probability: default_variance_probability(),
4634 generate_investigations: true,
4635 include_ratio_analysis: true,
4636 }
4637 }
4638}
4639
4640#[derive(Debug, Clone, Serialize, Deserialize)]
4642pub struct ConfirmationsConfig {
4643 #[serde(default)]
4645 pub enabled: bool,
4646
4647 #[serde(default = "default_confirmation_count")]
4649 pub confirmation_count: usize,
4650
4651 #[serde(default = "default_positive_response_rate")]
4653 pub positive_response_rate: f64,
4654
4655 #[serde(default = "default_exception_rate_confirm")]
4657 pub exception_rate: f64,
4658
4659 #[serde(default = "default_non_response_rate")]
4661 pub non_response_rate: f64,
4662
4663 #[serde(default = "default_true")]
4665 pub generate_alternative_procedures: bool,
4666}
4667
4668fn default_confirmation_count() -> usize {
4669 50
4670}
4671
4672fn default_positive_response_rate() -> f64 {
4673 0.85
4674}
4675
4676fn default_exception_rate_confirm() -> f64 {
4677 0.10
4678}
4679
4680fn default_non_response_rate() -> f64 {
4681 0.05
4682}
4683
4684impl Default for ConfirmationsConfig {
4685 fn default() -> Self {
4686 Self {
4687 enabled: false,
4688 confirmation_count: default_confirmation_count(),
4689 positive_response_rate: default_positive_response_rate(),
4690 exception_rate: default_exception_rate_confirm(),
4691 non_response_rate: default_non_response_rate(),
4692 generate_alternative_procedures: true,
4693 }
4694 }
4695}
4696
4697#[derive(Debug, Clone, Serialize, Deserialize)]
4699pub struct AuditOpinionConfig {
4700 #[serde(default)]
4702 pub enabled: bool,
4703
4704 #[serde(default = "default_true")]
4706 pub generate_kam: bool,
4707
4708 #[serde(default = "default_kam_count")]
4710 pub average_kam_count: usize,
4711
4712 #[serde(default = "default_modified_opinion_rate")]
4714 pub modified_opinion_rate: f64,
4715
4716 #[serde(default)]
4718 pub include_emphasis_of_matter: bool,
4719
4720 #[serde(default = "default_true")]
4722 pub include_going_concern: bool,
4723}
4724
4725fn default_kam_count() -> usize {
4726 3
4727}
4728
4729fn default_modified_opinion_rate() -> f64 {
4730 0.05
4731}
4732
4733impl Default for AuditOpinionConfig {
4734 fn default() -> Self {
4735 Self {
4736 enabled: false,
4737 generate_kam: true,
4738 average_kam_count: default_kam_count(),
4739 modified_opinion_rate: default_modified_opinion_rate(),
4740 include_emphasis_of_matter: false,
4741 include_going_concern: true,
4742 }
4743 }
4744}
4745
4746#[derive(Debug, Clone, Serialize, Deserialize)]
4748pub struct SoxComplianceConfig {
4749 #[serde(default)]
4751 pub enabled: bool,
4752
4753 #[serde(default = "default_true")]
4755 pub generate_302_certifications: bool,
4756
4757 #[serde(default = "default_true")]
4759 pub generate_404_assessments: bool,
4760
4761 #[serde(default = "default_sox_materiality_threshold")]
4763 pub materiality_threshold: f64,
4764
4765 #[serde(default = "default_material_weakness_rate")]
4767 pub material_weakness_rate: f64,
4768
4769 #[serde(default = "default_significant_deficiency_rate")]
4771 pub significant_deficiency_rate: f64,
4772}
4773
4774fn default_material_weakness_rate() -> f64 {
4775 0.02
4776}
4777
4778fn default_significant_deficiency_rate() -> f64 {
4779 0.08
4780}
4781
4782impl Default for SoxComplianceConfig {
4783 fn default() -> Self {
4784 Self {
4785 enabled: false,
4786 generate_302_certifications: true,
4787 generate_404_assessments: true,
4788 materiality_threshold: default_sox_materiality_threshold(),
4789 material_weakness_rate: default_material_weakness_rate(),
4790 significant_deficiency_rate: default_significant_deficiency_rate(),
4791 }
4792 }
4793}
4794
4795#[derive(Debug, Clone, Serialize, Deserialize)]
4797pub struct PcaobConfig {
4798 #[serde(default)]
4800 pub enabled: bool,
4801
4802 #[serde(default)]
4804 pub is_pcaob_audit: bool,
4805
4806 #[serde(default = "default_true")]
4808 pub generate_cam: bool,
4809
4810 #[serde(default)]
4812 pub include_icfr_opinion: bool,
4813
4814 #[serde(default)]
4816 pub generate_standard_mappings: bool,
4817}
4818
4819impl Default for PcaobConfig {
4820 fn default() -> Self {
4821 Self {
4822 enabled: false,
4823 is_pcaob_audit: false,
4824 generate_cam: true,
4825 include_icfr_opinion: false,
4826 generate_standard_mappings: false,
4827 }
4828 }
4829}
4830
4831#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4844pub struct AdvancedDistributionConfig {
4845 #[serde(default)]
4847 pub enabled: bool,
4848
4849 #[serde(default)]
4851 pub amounts: MixtureDistributionSchemaConfig,
4852
4853 #[serde(default)]
4855 pub correlations: CorrelationSchemaConfig,
4856
4857 #[serde(default)]
4859 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
4860
4861 #[serde(default)]
4863 pub regime_changes: RegimeChangeSchemaConfig,
4864
4865 #[serde(default)]
4867 pub industry_profile: Option<IndustryProfileType>,
4868
4869 #[serde(default)]
4871 pub validation: StatisticalValidationSchemaConfig,
4872}
4873
4874#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
4876#[serde(rename_all = "snake_case")]
4877pub enum IndustryProfileType {
4878 Retail,
4880 Manufacturing,
4882 FinancialServices,
4884 Healthcare,
4886 Technology,
4888}
4889
4890#[derive(Debug, Clone, Serialize, Deserialize)]
4892pub struct MixtureDistributionSchemaConfig {
4893 #[serde(default)]
4895 pub enabled: bool,
4896
4897 #[serde(default = "default_mixture_type")]
4899 pub distribution_type: MixtureDistributionType,
4900
4901 #[serde(default)]
4903 pub components: Vec<MixtureComponentConfig>,
4904
4905 #[serde(default = "default_min_amount")]
4907 pub min_value: f64,
4908
4909 #[serde(default)]
4911 pub max_value: Option<f64>,
4912
4913 #[serde(default = "default_decimal_places")]
4915 pub decimal_places: u8,
4916}
4917
4918fn default_mixture_type() -> MixtureDistributionType {
4919 MixtureDistributionType::LogNormal
4920}
4921
4922fn default_min_amount() -> f64 {
4923 0.01
4924}
4925
4926fn default_decimal_places() -> u8 {
4927 2
4928}
4929
4930impl Default for MixtureDistributionSchemaConfig {
4931 fn default() -> Self {
4932 Self {
4933 enabled: false,
4934 distribution_type: MixtureDistributionType::LogNormal,
4935 components: Vec::new(),
4936 min_value: 0.01,
4937 max_value: None,
4938 decimal_places: 2,
4939 }
4940 }
4941}
4942
4943#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4945#[serde(rename_all = "snake_case")]
4946pub enum MixtureDistributionType {
4947 Gaussian,
4949 #[default]
4951 LogNormal,
4952}
4953
4954#[derive(Debug, Clone, Serialize, Deserialize)]
4956pub struct MixtureComponentConfig {
4957 pub weight: f64,
4959
4960 pub mu: f64,
4962
4963 pub sigma: f64,
4965
4966 #[serde(default)]
4968 pub label: Option<String>,
4969}
4970
4971#[derive(Debug, Clone, Serialize, Deserialize)]
4973pub struct CorrelationSchemaConfig {
4974 #[serde(default)]
4976 pub enabled: bool,
4977
4978 #[serde(default)]
4980 pub copula_type: CopulaSchemaType,
4981
4982 #[serde(default)]
4984 pub fields: Vec<CorrelatedFieldConfig>,
4985
4986 #[serde(default)]
4989 pub matrix: Vec<f64>,
4990
4991 #[serde(default)]
4993 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
4994}
4995
4996impl Default for CorrelationSchemaConfig {
4997 fn default() -> Self {
4998 Self {
4999 enabled: false,
5000 copula_type: CopulaSchemaType::Gaussian,
5001 fields: Vec::new(),
5002 matrix: Vec::new(),
5003 expected_correlations: Vec::new(),
5004 }
5005 }
5006}
5007
5008#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5010#[serde(rename_all = "snake_case")]
5011pub enum CopulaSchemaType {
5012 #[default]
5014 Gaussian,
5015 Clayton,
5017 Gumbel,
5019 Frank,
5021 StudentT,
5023}
5024
5025#[derive(Debug, Clone, Serialize, Deserialize)]
5027pub struct CorrelatedFieldConfig {
5028 pub name: String,
5030
5031 #[serde(default)]
5033 pub distribution: MarginalDistributionConfig,
5034}
5035
5036#[derive(Debug, Clone, Serialize, Deserialize)]
5038#[serde(tag = "type", rename_all = "snake_case")]
5039pub enum MarginalDistributionConfig {
5040 Normal {
5042 mu: f64,
5044 sigma: f64,
5046 },
5047 LogNormal {
5049 mu: f64,
5051 sigma: f64,
5053 },
5054 Uniform {
5056 min: f64,
5058 max: f64,
5060 },
5061 DiscreteUniform {
5063 min: i32,
5065 max: i32,
5067 },
5068}
5069
5070impl Default for MarginalDistributionConfig {
5071 fn default() -> Self {
5072 Self::Normal {
5073 mu: 0.0,
5074 sigma: 1.0,
5075 }
5076 }
5077}
5078
5079#[derive(Debug, Clone, Serialize, Deserialize)]
5081pub struct ExpectedCorrelationConfig {
5082 pub field1: String,
5084 pub field2: String,
5086 pub expected_r: f64,
5088 #[serde(default = "default_correlation_tolerance")]
5090 pub tolerance: f64,
5091}
5092
5093fn default_correlation_tolerance() -> f64 {
5094 0.10
5095}
5096
5097#[derive(Debug, Clone, Serialize, Deserialize)]
5099pub struct ConditionalDistributionSchemaConfig {
5100 pub output_field: String,
5102
5103 pub input_field: String,
5105
5106 #[serde(default)]
5108 pub breakpoints: Vec<ConditionalBreakpointConfig>,
5109
5110 #[serde(default)]
5112 pub default_distribution: ConditionalDistributionParamsConfig,
5113
5114 #[serde(default)]
5116 pub min_value: Option<f64>,
5117
5118 #[serde(default)]
5120 pub max_value: Option<f64>,
5121
5122 #[serde(default = "default_decimal_places")]
5124 pub decimal_places: u8,
5125}
5126
5127#[derive(Debug, Clone, Serialize, Deserialize)]
5129pub struct ConditionalBreakpointConfig {
5130 pub threshold: f64,
5132
5133 pub distribution: ConditionalDistributionParamsConfig,
5135}
5136
5137#[derive(Debug, Clone, Serialize, Deserialize)]
5139#[serde(tag = "type", rename_all = "snake_case")]
5140pub enum ConditionalDistributionParamsConfig {
5141 Fixed {
5143 value: f64,
5145 },
5146 Normal {
5148 mu: f64,
5150 sigma: f64,
5152 },
5153 LogNormal {
5155 mu: f64,
5157 sigma: f64,
5159 },
5160 Uniform {
5162 min: f64,
5164 max: f64,
5166 },
5167 Beta {
5169 alpha: f64,
5171 beta: f64,
5173 min: f64,
5175 max: f64,
5177 },
5178 Discrete {
5180 values: Vec<f64>,
5182 weights: Vec<f64>,
5184 },
5185}
5186
5187impl Default for ConditionalDistributionParamsConfig {
5188 fn default() -> Self {
5189 Self::Normal {
5190 mu: 0.0,
5191 sigma: 1.0,
5192 }
5193 }
5194}
5195
5196#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5198pub struct RegimeChangeSchemaConfig {
5199 #[serde(default)]
5201 pub enabled: bool,
5202
5203 #[serde(default)]
5205 pub changes: Vec<RegimeChangeEventConfig>,
5206
5207 #[serde(default)]
5209 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5210
5211 #[serde(default)]
5213 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5214}
5215
5216#[derive(Debug, Clone, Serialize, Deserialize)]
5218pub struct RegimeChangeEventConfig {
5219 pub date: String,
5221
5222 pub change_type: RegimeChangeTypeConfig,
5224
5225 #[serde(default)]
5227 pub description: Option<String>,
5228
5229 #[serde(default)]
5231 pub effects: Vec<RegimeEffectConfig>,
5232}
5233
5234#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5236#[serde(rename_all = "snake_case")]
5237pub enum RegimeChangeTypeConfig {
5238 Acquisition,
5240 Divestiture,
5242 PriceIncrease,
5244 PriceDecrease,
5246 ProductLaunch,
5248 ProductDiscontinuation,
5250 PolicyChange,
5252 CompetitorEntry,
5254 Custom,
5256}
5257
5258#[derive(Debug, Clone, Serialize, Deserialize)]
5260pub struct RegimeEffectConfig {
5261 pub field: String,
5263
5264 pub multiplier: f64,
5266}
5267
5268#[derive(Debug, Clone, Serialize, Deserialize)]
5270pub struct EconomicCycleSchemaConfig {
5271 #[serde(default)]
5273 pub enabled: bool,
5274
5275 #[serde(default = "default_cycle_period")]
5277 pub period_months: u32,
5278
5279 #[serde(default = "default_cycle_amplitude")]
5281 pub amplitude: f64,
5282
5283 #[serde(default)]
5285 pub phase_offset: u32,
5286
5287 #[serde(default)]
5289 pub recessions: Vec<RecessionPeriodConfig>,
5290}
5291
5292fn default_cycle_period() -> u32 {
5293 48
5294}
5295
5296fn default_cycle_amplitude() -> f64 {
5297 0.15
5298}
5299
5300impl Default for EconomicCycleSchemaConfig {
5301 fn default() -> Self {
5302 Self {
5303 enabled: false,
5304 period_months: 48,
5305 amplitude: 0.15,
5306 phase_offset: 0,
5307 recessions: Vec::new(),
5308 }
5309 }
5310}
5311
5312#[derive(Debug, Clone, Serialize, Deserialize)]
5314pub struct RecessionPeriodConfig {
5315 pub start_month: u32,
5317
5318 pub duration_months: u32,
5320
5321 #[serde(default = "default_recession_severity")]
5323 pub severity: f64,
5324}
5325
5326fn default_recession_severity() -> f64 {
5327 0.20
5328}
5329
5330#[derive(Debug, Clone, Serialize, Deserialize)]
5332pub struct ParameterDriftSchemaConfig {
5333 pub parameter: String,
5335
5336 pub drift_type: ParameterDriftTypeConfig,
5338
5339 pub start_value: f64,
5341
5342 pub end_value: f64,
5344
5345 #[serde(default)]
5347 pub start_period: u32,
5348
5349 #[serde(default)]
5351 pub end_period: Option<u32>,
5352}
5353
5354#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5356#[serde(rename_all = "snake_case")]
5357pub enum ParameterDriftTypeConfig {
5358 #[default]
5360 Linear,
5361 Exponential,
5363 Logistic,
5365 Step,
5367}
5368
5369#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5371pub struct StatisticalValidationSchemaConfig {
5372 #[serde(default)]
5374 pub enabled: bool,
5375
5376 #[serde(default)]
5378 pub tests: Vec<StatisticalTestConfig>,
5379
5380 #[serde(default)]
5382 pub reporting: ValidationReportingConfig,
5383}
5384
5385#[derive(Debug, Clone, Serialize, Deserialize)]
5387#[serde(tag = "type", rename_all = "snake_case")]
5388pub enum StatisticalTestConfig {
5389 BenfordFirstDigit {
5391 #[serde(default = "default_benford_threshold")]
5393 threshold_mad: f64,
5394 #[serde(default = "default_benford_warning")]
5396 warning_mad: f64,
5397 },
5398 DistributionFit {
5400 target: TargetDistributionConfig,
5402 #[serde(default = "default_ks_significance")]
5404 ks_significance: f64,
5405 #[serde(default)]
5407 method: DistributionFitMethod,
5408 },
5409 CorrelationCheck {
5411 expected_correlations: Vec<ExpectedCorrelationConfig>,
5413 },
5414 ChiSquared {
5416 #[serde(default = "default_chi_squared_bins")]
5418 bins: usize,
5419 #[serde(default = "default_chi_squared_significance")]
5421 significance: f64,
5422 },
5423 AndersonDarling {
5425 target: TargetDistributionConfig,
5427 #[serde(default = "default_ad_significance")]
5429 significance: f64,
5430 },
5431}
5432
5433fn default_benford_threshold() -> f64 {
5434 0.015
5435}
5436
5437fn default_benford_warning() -> f64 {
5438 0.010
5439}
5440
5441fn default_ks_significance() -> f64 {
5442 0.05
5443}
5444
5445fn default_chi_squared_bins() -> usize {
5446 10
5447}
5448
5449fn default_chi_squared_significance() -> f64 {
5450 0.05
5451}
5452
5453fn default_ad_significance() -> f64 {
5454 0.05
5455}
5456
5457#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5459#[serde(rename_all = "snake_case")]
5460pub enum TargetDistributionConfig {
5461 Normal,
5463 #[default]
5465 LogNormal,
5466 Exponential,
5468 Uniform,
5470}
5471
5472#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5474#[serde(rename_all = "snake_case")]
5475pub enum DistributionFitMethod {
5476 #[default]
5478 KolmogorovSmirnov,
5479 AndersonDarling,
5481 ChiSquared,
5483}
5484
5485#[derive(Debug, Clone, Serialize, Deserialize)]
5487pub struct ValidationReportingConfig {
5488 #[serde(default)]
5490 pub output_report: bool,
5491
5492 #[serde(default)]
5494 pub format: ValidationReportFormat,
5495
5496 #[serde(default)]
5498 pub fail_on_error: bool,
5499
5500 #[serde(default = "default_true")]
5502 pub include_details: bool,
5503}
5504
5505impl Default for ValidationReportingConfig {
5506 fn default() -> Self {
5507 Self {
5508 output_report: false,
5509 format: ValidationReportFormat::Json,
5510 fail_on_error: false,
5511 include_details: true,
5512 }
5513 }
5514}
5515
5516#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5518#[serde(rename_all = "snake_case")]
5519pub enum ValidationReportFormat {
5520 #[default]
5522 Json,
5523 Yaml,
5525 Html,
5527}
5528
5529#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5541pub struct TemporalPatternsConfig {
5542 #[serde(default)]
5544 pub enabled: bool,
5545
5546 #[serde(default)]
5548 pub business_days: BusinessDaySchemaConfig,
5549
5550 #[serde(default)]
5552 pub calendars: CalendarSchemaConfig,
5553
5554 #[serde(default)]
5556 pub period_end: PeriodEndSchemaConfig,
5557
5558 #[serde(default)]
5560 pub processing_lags: ProcessingLagSchemaConfig,
5561
5562 #[serde(default)]
5564 pub fiscal_calendar: FiscalCalendarSchemaConfig,
5565
5566 #[serde(default)]
5568 pub intraday: IntraDaySchemaConfig,
5569
5570 #[serde(default)]
5572 pub timezones: TimezoneSchemaConfig,
5573}
5574
5575#[derive(Debug, Clone, Serialize, Deserialize)]
5577pub struct BusinessDaySchemaConfig {
5578 #[serde(default = "default_true")]
5580 pub enabled: bool,
5581
5582 #[serde(default = "default_half_day_policy")]
5584 pub half_day_policy: String,
5585
5586 #[serde(default)]
5588 pub settlement_rules: SettlementRulesSchemaConfig,
5589
5590 #[serde(default = "default_month_end_convention")]
5592 pub month_end_convention: String,
5593
5594 #[serde(default)]
5596 pub weekend_days: Option<Vec<String>>,
5597}
5598
5599fn default_half_day_policy() -> String {
5600 "half_day".to_string()
5601}
5602
5603fn default_month_end_convention() -> String {
5604 "modified_following".to_string()
5605}
5606
5607impl Default for BusinessDaySchemaConfig {
5608 fn default() -> Self {
5609 Self {
5610 enabled: true,
5611 half_day_policy: "half_day".to_string(),
5612 settlement_rules: SettlementRulesSchemaConfig::default(),
5613 month_end_convention: "modified_following".to_string(),
5614 weekend_days: None,
5615 }
5616 }
5617}
5618
5619#[derive(Debug, Clone, Serialize, Deserialize)]
5621pub struct SettlementRulesSchemaConfig {
5622 #[serde(default = "default_settlement_2")]
5624 pub equity_days: i32,
5625
5626 #[serde(default = "default_settlement_1")]
5628 pub government_bonds_days: i32,
5629
5630 #[serde(default = "default_settlement_2")]
5632 pub fx_spot_days: i32,
5633
5634 #[serde(default = "default_settlement_2")]
5636 pub corporate_bonds_days: i32,
5637
5638 #[serde(default = "default_wire_cutoff")]
5640 pub wire_cutoff_time: String,
5641
5642 #[serde(default = "default_settlement_1")]
5644 pub wire_international_days: i32,
5645
5646 #[serde(default = "default_settlement_1")]
5648 pub ach_days: i32,
5649}
5650
5651fn default_settlement_1() -> i32 {
5652 1
5653}
5654
5655fn default_settlement_2() -> i32 {
5656 2
5657}
5658
5659fn default_wire_cutoff() -> String {
5660 "14:00".to_string()
5661}
5662
5663impl Default for SettlementRulesSchemaConfig {
5664 fn default() -> Self {
5665 Self {
5666 equity_days: 2,
5667 government_bonds_days: 1,
5668 fx_spot_days: 2,
5669 corporate_bonds_days: 2,
5670 wire_cutoff_time: "14:00".to_string(),
5671 wire_international_days: 1,
5672 ach_days: 1,
5673 }
5674 }
5675}
5676
5677#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5679pub struct CalendarSchemaConfig {
5680 #[serde(default)]
5682 pub regions: Vec<String>,
5683
5684 #[serde(default)]
5686 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
5687}
5688
5689#[derive(Debug, Clone, Serialize, Deserialize)]
5691pub struct CustomHolidaySchemaConfig {
5692 pub name: String,
5694 pub month: u8,
5696 pub day: u8,
5698 #[serde(default = "default_holiday_multiplier")]
5700 pub activity_multiplier: f64,
5701}
5702
5703fn default_holiday_multiplier() -> f64 {
5704 0.05
5705}
5706
5707#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5709pub struct PeriodEndSchemaConfig {
5710 #[serde(default)]
5712 pub model: Option<String>,
5713
5714 #[serde(default)]
5716 pub month_end: Option<PeriodEndModelSchemaConfig>,
5717
5718 #[serde(default)]
5720 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
5721
5722 #[serde(default)]
5724 pub year_end: Option<PeriodEndModelSchemaConfig>,
5725}
5726
5727#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5729pub struct PeriodEndModelSchemaConfig {
5730 #[serde(default)]
5732 pub inherit_from: Option<String>,
5733
5734 #[serde(default)]
5736 pub additional_multiplier: Option<f64>,
5737
5738 #[serde(default)]
5740 pub start_day: Option<i32>,
5741
5742 #[serde(default)]
5744 pub base_multiplier: Option<f64>,
5745
5746 #[serde(default)]
5748 pub peak_multiplier: Option<f64>,
5749
5750 #[serde(default)]
5752 pub decay_rate: Option<f64>,
5753
5754 #[serde(default)]
5756 pub sustained_high_days: Option<i32>,
5757}
5758
5759#[derive(Debug, Clone, Serialize, Deserialize)]
5761pub struct ProcessingLagSchemaConfig {
5762 #[serde(default = "default_true")]
5764 pub enabled: bool,
5765
5766 #[serde(default)]
5768 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
5769
5770 #[serde(default)]
5772 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
5773
5774 #[serde(default)]
5776 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
5777
5778 #[serde(default)]
5780 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
5781
5782 #[serde(default)]
5784 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
5785
5786 #[serde(default)]
5788 pub payment_lag: Option<LagDistributionSchemaConfig>,
5789
5790 #[serde(default)]
5792 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
5793
5794 #[serde(default)]
5796 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
5797}
5798
5799impl Default for ProcessingLagSchemaConfig {
5800 fn default() -> Self {
5801 Self {
5802 enabled: true,
5803 sales_order_lag: None,
5804 purchase_order_lag: None,
5805 goods_receipt_lag: None,
5806 invoice_receipt_lag: None,
5807 invoice_issue_lag: None,
5808 payment_lag: None,
5809 journal_entry_lag: None,
5810 cross_day_posting: None,
5811 }
5812 }
5813}
5814
5815#[derive(Debug, Clone, Serialize, Deserialize)]
5817pub struct LagDistributionSchemaConfig {
5818 pub mu: f64,
5820 pub sigma: f64,
5822 #[serde(default)]
5824 pub min_hours: Option<f64>,
5825 #[serde(default)]
5827 pub max_hours: Option<f64>,
5828}
5829
5830#[derive(Debug, Clone, Serialize, Deserialize)]
5832pub struct CrossDayPostingSchemaConfig {
5833 #[serde(default = "default_true")]
5835 pub enabled: bool,
5836
5837 #[serde(default)]
5840 pub probability_by_hour: std::collections::HashMap<u8, f64>,
5841}
5842
5843impl Default for CrossDayPostingSchemaConfig {
5844 fn default() -> Self {
5845 let mut probability_by_hour = std::collections::HashMap::new();
5846 probability_by_hour.insert(17, 0.3);
5847 probability_by_hour.insert(18, 0.6);
5848 probability_by_hour.insert(19, 0.8);
5849 probability_by_hour.insert(20, 0.9);
5850 probability_by_hour.insert(21, 0.95);
5851 probability_by_hour.insert(22, 0.99);
5852
5853 Self {
5854 enabled: true,
5855 probability_by_hour,
5856 }
5857 }
5858}
5859
5860#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5869pub struct FiscalCalendarSchemaConfig {
5870 #[serde(default)]
5872 pub enabled: bool,
5873
5874 #[serde(default = "default_fiscal_calendar_type")]
5876 pub calendar_type: String,
5877
5878 #[serde(default)]
5880 pub year_start_month: Option<u8>,
5881
5882 #[serde(default)]
5884 pub year_start_day: Option<u8>,
5885
5886 #[serde(default)]
5888 pub four_four_five: Option<FourFourFiveSchemaConfig>,
5889}
5890
5891fn default_fiscal_calendar_type() -> String {
5892 "calendar_year".to_string()
5893}
5894
5895#[derive(Debug, Clone, Serialize, Deserialize)]
5897pub struct FourFourFiveSchemaConfig {
5898 #[serde(default = "default_week_pattern")]
5900 pub pattern: String,
5901
5902 #[serde(default = "default_anchor_type")]
5904 pub anchor_type: String,
5905
5906 #[serde(default = "default_anchor_month")]
5908 pub anchor_month: u8,
5909
5910 #[serde(default = "default_leap_week_placement")]
5912 pub leap_week_placement: String,
5913}
5914
5915fn default_week_pattern() -> String {
5916 "four_four_five".to_string()
5917}
5918
5919fn default_anchor_type() -> String {
5920 "last_saturday".to_string()
5921}
5922
5923fn default_anchor_month() -> u8 {
5924 1 }
5926
5927fn default_leap_week_placement() -> String {
5928 "q4_period3".to_string()
5929}
5930
5931impl Default for FourFourFiveSchemaConfig {
5932 fn default() -> Self {
5933 Self {
5934 pattern: "four_four_five".to_string(),
5935 anchor_type: "last_saturday".to_string(),
5936 anchor_month: 1,
5937 leap_week_placement: "q4_period3".to_string(),
5938 }
5939 }
5940}
5941
5942#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5951pub struct IntraDaySchemaConfig {
5952 #[serde(default)]
5954 pub enabled: bool,
5955
5956 #[serde(default)]
5958 pub segments: Vec<IntraDaySegmentSchemaConfig>,
5959}
5960
5961#[derive(Debug, Clone, Serialize, Deserialize)]
5963pub struct IntraDaySegmentSchemaConfig {
5964 pub name: String,
5966
5967 pub start: String,
5969
5970 pub end: String,
5972
5973 #[serde(default = "default_multiplier")]
5975 pub multiplier: f64,
5976
5977 #[serde(default = "default_posting_type")]
5979 pub posting_type: String,
5980}
5981
5982fn default_multiplier() -> f64 {
5983 1.0
5984}
5985
5986fn default_posting_type() -> String {
5987 "both".to_string()
5988}
5989
5990#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5996pub struct TimezoneSchemaConfig {
5997 #[serde(default)]
5999 pub enabled: bool,
6000
6001 #[serde(default = "default_timezone")]
6003 pub default_timezone: String,
6004
6005 #[serde(default = "default_consolidation_timezone")]
6007 pub consolidation_timezone: String,
6008
6009 #[serde(default)]
6012 pub entity_mappings: Vec<EntityTimezoneMapping>,
6013}
6014
6015fn default_timezone() -> String {
6016 "America/New_York".to_string()
6017}
6018
6019fn default_consolidation_timezone() -> String {
6020 "UTC".to_string()
6021}
6022
6023#[derive(Debug, Clone, Serialize, Deserialize)]
6025pub struct EntityTimezoneMapping {
6026 pub pattern: String,
6028
6029 pub timezone: String,
6031}
6032
6033#[derive(Debug, Clone, Serialize, Deserialize)]
6039pub struct VendorNetworkSchemaConfig {
6040 #[serde(default)]
6042 pub enabled: bool,
6043
6044 #[serde(default = "default_vendor_tier_depth")]
6046 pub depth: u8,
6047
6048 #[serde(default)]
6050 pub tier1: TierCountSchemaConfig,
6051
6052 #[serde(default)]
6054 pub tier2_per_parent: TierCountSchemaConfig,
6055
6056 #[serde(default)]
6058 pub tier3_per_parent: TierCountSchemaConfig,
6059
6060 #[serde(default)]
6062 pub clusters: VendorClusterSchemaConfig,
6063
6064 #[serde(default)]
6066 pub dependencies: DependencySchemaConfig,
6067}
6068
6069fn default_vendor_tier_depth() -> u8 {
6070 3
6071}
6072
6073impl Default for VendorNetworkSchemaConfig {
6074 fn default() -> Self {
6075 Self {
6076 enabled: false,
6077 depth: 3,
6078 tier1: TierCountSchemaConfig { min: 50, max: 100 },
6079 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6080 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6081 clusters: VendorClusterSchemaConfig::default(),
6082 dependencies: DependencySchemaConfig::default(),
6083 }
6084 }
6085}
6086
6087#[derive(Debug, Clone, Serialize, Deserialize)]
6089pub struct TierCountSchemaConfig {
6090 #[serde(default = "default_tier_min")]
6092 pub min: usize,
6093
6094 #[serde(default = "default_tier_max")]
6096 pub max: usize,
6097}
6098
6099fn default_tier_min() -> usize {
6100 5
6101}
6102
6103fn default_tier_max() -> usize {
6104 20
6105}
6106
6107impl Default for TierCountSchemaConfig {
6108 fn default() -> Self {
6109 Self {
6110 min: default_tier_min(),
6111 max: default_tier_max(),
6112 }
6113 }
6114}
6115
6116#[derive(Debug, Clone, Serialize, Deserialize)]
6118pub struct VendorClusterSchemaConfig {
6119 #[serde(default = "default_reliable_strategic")]
6121 pub reliable_strategic: f64,
6122
6123 #[serde(default = "default_standard_operational")]
6125 pub standard_operational: f64,
6126
6127 #[serde(default = "default_transactional")]
6129 pub transactional: f64,
6130
6131 #[serde(default = "default_problematic")]
6133 pub problematic: f64,
6134}
6135
6136fn default_reliable_strategic() -> f64 {
6137 0.20
6138}
6139
6140fn default_standard_operational() -> f64 {
6141 0.50
6142}
6143
6144fn default_transactional() -> f64 {
6145 0.25
6146}
6147
6148fn default_problematic() -> f64 {
6149 0.05
6150}
6151
6152impl Default for VendorClusterSchemaConfig {
6153 fn default() -> Self {
6154 Self {
6155 reliable_strategic: 0.20,
6156 standard_operational: 0.50,
6157 transactional: 0.25,
6158 problematic: 0.05,
6159 }
6160 }
6161}
6162
6163#[derive(Debug, Clone, Serialize, Deserialize)]
6165pub struct DependencySchemaConfig {
6166 #[serde(default = "default_max_single_vendor")]
6168 pub max_single_vendor_concentration: f64,
6169
6170 #[serde(default = "default_max_top5")]
6172 pub top_5_concentration: f64,
6173
6174 #[serde(default = "default_single_source_percent")]
6176 pub single_source_percent: f64,
6177}
6178
6179fn default_max_single_vendor() -> f64 {
6180 0.15
6181}
6182
6183fn default_max_top5() -> f64 {
6184 0.45
6185}
6186
6187fn default_single_source_percent() -> f64 {
6188 0.05
6189}
6190
6191impl Default for DependencySchemaConfig {
6192 fn default() -> Self {
6193 Self {
6194 max_single_vendor_concentration: 0.15,
6195 top_5_concentration: 0.45,
6196 single_source_percent: 0.05,
6197 }
6198 }
6199}
6200
6201#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6207pub struct CustomerSegmentationSchemaConfig {
6208 #[serde(default)]
6210 pub enabled: bool,
6211
6212 #[serde(default)]
6214 pub value_segments: ValueSegmentsSchemaConfig,
6215
6216 #[serde(default)]
6218 pub lifecycle: LifecycleSchemaConfig,
6219
6220 #[serde(default)]
6222 pub networks: CustomerNetworksSchemaConfig,
6223}
6224
6225#[derive(Debug, Clone, Serialize, Deserialize)]
6227pub struct ValueSegmentsSchemaConfig {
6228 #[serde(default)]
6230 pub enterprise: SegmentDetailSchemaConfig,
6231
6232 #[serde(default)]
6234 pub mid_market: SegmentDetailSchemaConfig,
6235
6236 #[serde(default)]
6238 pub smb: SegmentDetailSchemaConfig,
6239
6240 #[serde(default)]
6242 pub consumer: SegmentDetailSchemaConfig,
6243}
6244
6245impl Default for ValueSegmentsSchemaConfig {
6246 fn default() -> Self {
6247 Self {
6248 enterprise: SegmentDetailSchemaConfig {
6249 revenue_share: 0.40,
6250 customer_share: 0.05,
6251 avg_order_value_range: "50000+".to_string(),
6252 },
6253 mid_market: SegmentDetailSchemaConfig {
6254 revenue_share: 0.35,
6255 customer_share: 0.20,
6256 avg_order_value_range: "5000-50000".to_string(),
6257 },
6258 smb: SegmentDetailSchemaConfig {
6259 revenue_share: 0.20,
6260 customer_share: 0.50,
6261 avg_order_value_range: "500-5000".to_string(),
6262 },
6263 consumer: SegmentDetailSchemaConfig {
6264 revenue_share: 0.05,
6265 customer_share: 0.25,
6266 avg_order_value_range: "50-500".to_string(),
6267 },
6268 }
6269 }
6270}
6271
6272#[derive(Debug, Clone, Serialize, Deserialize)]
6274pub struct SegmentDetailSchemaConfig {
6275 #[serde(default)]
6277 pub revenue_share: f64,
6278
6279 #[serde(default)]
6281 pub customer_share: f64,
6282
6283 #[serde(default)]
6285 pub avg_order_value_range: String,
6286}
6287
6288impl Default for SegmentDetailSchemaConfig {
6289 fn default() -> Self {
6290 Self {
6291 revenue_share: 0.25,
6292 customer_share: 0.25,
6293 avg_order_value_range: "1000-10000".to_string(),
6294 }
6295 }
6296}
6297
6298#[derive(Debug, Clone, Serialize, Deserialize)]
6300pub struct LifecycleSchemaConfig {
6301 #[serde(default)]
6303 pub prospect_rate: f64,
6304
6305 #[serde(default = "default_new_rate")]
6307 pub new_rate: f64,
6308
6309 #[serde(default = "default_growth_rate")]
6311 pub growth_rate: f64,
6312
6313 #[serde(default = "default_mature_rate")]
6315 pub mature_rate: f64,
6316
6317 #[serde(default = "default_at_risk_rate")]
6319 pub at_risk_rate: f64,
6320
6321 #[serde(default = "default_churned_rate")]
6323 pub churned_rate: f64,
6324}
6325
6326fn default_new_rate() -> f64 {
6327 0.10
6328}
6329
6330fn default_growth_rate() -> f64 {
6331 0.15
6332}
6333
6334fn default_mature_rate() -> f64 {
6335 0.60
6336}
6337
6338fn default_at_risk_rate() -> f64 {
6339 0.10
6340}
6341
6342fn default_churned_rate() -> f64 {
6343 0.05
6344}
6345
6346impl Default for LifecycleSchemaConfig {
6347 fn default() -> Self {
6348 Self {
6349 prospect_rate: 0.0,
6350 new_rate: 0.10,
6351 growth_rate: 0.15,
6352 mature_rate: 0.60,
6353 at_risk_rate: 0.10,
6354 churned_rate: 0.05,
6355 }
6356 }
6357}
6358
6359#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6361pub struct CustomerNetworksSchemaConfig {
6362 #[serde(default)]
6364 pub referrals: ReferralSchemaConfig,
6365
6366 #[serde(default)]
6368 pub corporate_hierarchies: HierarchySchemaConfig,
6369}
6370
6371#[derive(Debug, Clone, Serialize, Deserialize)]
6373pub struct ReferralSchemaConfig {
6374 #[serde(default = "default_true")]
6376 pub enabled: bool,
6377
6378 #[serde(default = "default_referral_rate")]
6380 pub referral_rate: f64,
6381}
6382
6383fn default_referral_rate() -> f64 {
6384 0.15
6385}
6386
6387impl Default for ReferralSchemaConfig {
6388 fn default() -> Self {
6389 Self {
6390 enabled: true,
6391 referral_rate: 0.15,
6392 }
6393 }
6394}
6395
6396#[derive(Debug, Clone, Serialize, Deserialize)]
6398pub struct HierarchySchemaConfig {
6399 #[serde(default = "default_true")]
6401 pub enabled: bool,
6402
6403 #[serde(default = "default_hierarchy_rate")]
6405 pub probability: f64,
6406}
6407
6408fn default_hierarchy_rate() -> f64 {
6409 0.30
6410}
6411
6412impl Default for HierarchySchemaConfig {
6413 fn default() -> Self {
6414 Self {
6415 enabled: true,
6416 probability: 0.30,
6417 }
6418 }
6419}
6420
6421#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6427pub struct RelationshipStrengthSchemaConfig {
6428 #[serde(default)]
6430 pub enabled: bool,
6431
6432 #[serde(default)]
6434 pub calculation: StrengthCalculationSchemaConfig,
6435
6436 #[serde(default)]
6438 pub thresholds: StrengthThresholdsSchemaConfig,
6439}
6440
6441#[derive(Debug, Clone, Serialize, Deserialize)]
6443pub struct StrengthCalculationSchemaConfig {
6444 #[serde(default = "default_volume_weight")]
6446 pub transaction_volume_weight: f64,
6447
6448 #[serde(default = "default_count_weight")]
6450 pub transaction_count_weight: f64,
6451
6452 #[serde(default = "default_duration_weight")]
6454 pub relationship_duration_weight: f64,
6455
6456 #[serde(default = "default_recency_weight")]
6458 pub recency_weight: f64,
6459
6460 #[serde(default = "default_mutual_weight")]
6462 pub mutual_connections_weight: f64,
6463
6464 #[serde(default = "default_recency_half_life")]
6466 pub recency_half_life_days: u32,
6467}
6468
6469fn default_volume_weight() -> f64 {
6470 0.30
6471}
6472
6473fn default_count_weight() -> f64 {
6474 0.25
6475}
6476
6477fn default_duration_weight() -> f64 {
6478 0.20
6479}
6480
6481fn default_recency_weight() -> f64 {
6482 0.15
6483}
6484
6485fn default_mutual_weight() -> f64 {
6486 0.10
6487}
6488
6489fn default_recency_half_life() -> u32 {
6490 90
6491}
6492
6493impl Default for StrengthCalculationSchemaConfig {
6494 fn default() -> Self {
6495 Self {
6496 transaction_volume_weight: 0.30,
6497 transaction_count_weight: 0.25,
6498 relationship_duration_weight: 0.20,
6499 recency_weight: 0.15,
6500 mutual_connections_weight: 0.10,
6501 recency_half_life_days: 90,
6502 }
6503 }
6504}
6505
6506#[derive(Debug, Clone, Serialize, Deserialize)]
6508pub struct StrengthThresholdsSchemaConfig {
6509 #[serde(default = "default_strong_threshold")]
6511 pub strong: f64,
6512
6513 #[serde(default = "default_moderate_threshold")]
6515 pub moderate: f64,
6516
6517 #[serde(default = "default_weak_threshold")]
6519 pub weak: f64,
6520}
6521
6522fn default_strong_threshold() -> f64 {
6523 0.7
6524}
6525
6526fn default_moderate_threshold() -> f64 {
6527 0.4
6528}
6529
6530fn default_weak_threshold() -> f64 {
6531 0.1
6532}
6533
6534impl Default for StrengthThresholdsSchemaConfig {
6535 fn default() -> Self {
6536 Self {
6537 strong: 0.7,
6538 moderate: 0.4,
6539 weak: 0.1,
6540 }
6541 }
6542}
6543
6544#[derive(Debug, Clone, Serialize, Deserialize)]
6550pub struct CrossProcessLinksSchemaConfig {
6551 #[serde(default)]
6553 pub enabled: bool,
6554
6555 #[serde(default = "default_true")]
6557 pub inventory_p2p_o2c: bool,
6558
6559 #[serde(default = "default_true")]
6561 pub payment_bank_reconciliation: bool,
6562
6563 #[serde(default = "default_true")]
6565 pub intercompany_bilateral: bool,
6566
6567 #[serde(default = "default_inventory_link_rate")]
6569 pub inventory_link_rate: f64,
6570}
6571
6572fn default_inventory_link_rate() -> f64 {
6573 0.30
6574}
6575
6576impl Default for CrossProcessLinksSchemaConfig {
6577 fn default() -> Self {
6578 Self {
6579 enabled: false,
6580 inventory_p2p_o2c: true,
6581 payment_bank_reconciliation: true,
6582 intercompany_bilateral: true,
6583 inventory_link_rate: 0.30,
6584 }
6585 }
6586}
6587
6588#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6594pub struct OrganizationalEventsSchemaConfig {
6595 #[serde(default)]
6597 pub enabled: bool,
6598
6599 #[serde(default)]
6601 pub effect_blending: EffectBlendingModeConfig,
6602
6603 #[serde(default)]
6605 pub events: Vec<OrganizationalEventSchemaConfig>,
6606
6607 #[serde(default)]
6609 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6610
6611 #[serde(default)]
6613 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6614}
6615
6616#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6618#[serde(rename_all = "snake_case")]
6619pub enum EffectBlendingModeConfig {
6620 #[default]
6622 Multiplicative,
6623 Additive,
6625 Maximum,
6627 Minimum,
6629}
6630
6631#[derive(Debug, Clone, Serialize, Deserialize)]
6633pub struct OrganizationalEventSchemaConfig {
6634 pub id: String,
6636
6637 pub event_type: OrganizationalEventTypeSchemaConfig,
6639
6640 pub effective_date: String,
6642
6643 #[serde(default = "default_org_transition_months")]
6645 pub transition_months: u32,
6646
6647 #[serde(default)]
6649 pub description: Option<String>,
6650}
6651
6652fn default_org_transition_months() -> u32 {
6653 6
6654}
6655
6656#[derive(Debug, Clone, Serialize, Deserialize)]
6658#[serde(tag = "type", rename_all = "snake_case")]
6659pub enum OrganizationalEventTypeSchemaConfig {
6660 Acquisition {
6662 acquired_entity: String,
6664 #[serde(default = "default_acquisition_volume")]
6666 volume_increase: f64,
6667 #[serde(default = "default_acquisition_error")]
6669 integration_error_rate: f64,
6670 #[serde(default = "default_parallel_days")]
6672 parallel_posting_days: u32,
6673 },
6674 Divestiture {
6676 divested_entity: String,
6678 #[serde(default = "default_divestiture_volume")]
6680 volume_reduction: f64,
6681 #[serde(default = "default_true_val")]
6683 remove_entity: bool,
6684 },
6685 Reorganization {
6687 #[serde(default)]
6689 cost_center_remapping: std::collections::HashMap<String, String>,
6690 #[serde(default = "default_reorg_error")]
6692 transition_error_rate: f64,
6693 },
6694 LeadershipChange {
6696 role: String,
6698 #[serde(default)]
6700 policy_changes: Vec<String>,
6701 },
6702 WorkforceReduction {
6704 #[serde(default = "default_workforce_reduction")]
6706 reduction_percent: f64,
6707 #[serde(default = "default_workforce_error")]
6709 error_rate_increase: f64,
6710 },
6711 Merger {
6713 merged_entity: String,
6715 #[serde(default = "default_merger_volume")]
6717 volume_increase: f64,
6718 },
6719}
6720
6721fn default_acquisition_volume() -> f64 {
6722 1.35
6723}
6724
6725fn default_acquisition_error() -> f64 {
6726 0.05
6727}
6728
6729fn default_parallel_days() -> u32 {
6730 30
6731}
6732
6733fn default_divestiture_volume() -> f64 {
6734 0.70
6735}
6736
6737fn default_true_val() -> bool {
6738 true
6739}
6740
6741fn default_reorg_error() -> f64 {
6742 0.04
6743}
6744
6745fn default_workforce_reduction() -> f64 {
6746 0.10
6747}
6748
6749fn default_workforce_error() -> f64 {
6750 0.05
6751}
6752
6753fn default_merger_volume() -> f64 {
6754 1.80
6755}
6756
6757#[derive(Debug, Clone, Serialize, Deserialize)]
6759pub struct ProcessEvolutionSchemaConfig {
6760 pub id: String,
6762
6763 pub event_type: ProcessEvolutionTypeSchemaConfig,
6765
6766 pub effective_date: String,
6768
6769 #[serde(default)]
6771 pub description: Option<String>,
6772}
6773
6774#[derive(Debug, Clone, Serialize, Deserialize)]
6776#[serde(tag = "type", rename_all = "snake_case")]
6777pub enum ProcessEvolutionTypeSchemaConfig {
6778 ProcessAutomation {
6780 process_name: String,
6782 #[serde(default = "default_manual_before")]
6784 manual_rate_before: f64,
6785 #[serde(default = "default_manual_after")]
6787 manual_rate_after: f64,
6788 },
6789 ApprovalWorkflowChange {
6791 description: String,
6793 },
6794 ControlEnhancement {
6796 control_id: String,
6798 #[serde(default = "default_error_reduction")]
6800 error_reduction: f64,
6801 },
6802}
6803
6804fn default_manual_before() -> f64 {
6805 0.80
6806}
6807
6808fn default_manual_after() -> f64 {
6809 0.15
6810}
6811
6812fn default_error_reduction() -> f64 {
6813 0.02
6814}
6815
6816#[derive(Debug, Clone, Serialize, Deserialize)]
6818pub struct TechnologyTransitionSchemaConfig {
6819 pub id: String,
6821
6822 pub event_type: TechnologyTransitionTypeSchemaConfig,
6824
6825 #[serde(default)]
6827 pub description: Option<String>,
6828}
6829
6830#[derive(Debug, Clone, Serialize, Deserialize)]
6832#[serde(tag = "type", rename_all = "snake_case")]
6833pub enum TechnologyTransitionTypeSchemaConfig {
6834 ErpMigration {
6836 source_system: String,
6838 target_system: String,
6840 cutover_date: String,
6842 stabilization_end: String,
6844 #[serde(default = "default_erp_duplicate_rate")]
6846 duplicate_rate: f64,
6847 #[serde(default = "default_format_mismatch")]
6849 format_mismatch_rate: f64,
6850 },
6851 ModuleImplementation {
6853 module_name: String,
6855 go_live_date: String,
6857 },
6858}
6859
6860fn default_erp_duplicate_rate() -> f64 {
6861 0.02
6862}
6863
6864fn default_format_mismatch() -> f64 {
6865 0.03
6866}
6867
6868#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6874pub struct BehavioralDriftSchemaConfig {
6875 #[serde(default)]
6877 pub enabled: bool,
6878
6879 #[serde(default)]
6881 pub vendor_behavior: VendorBehaviorSchemaConfig,
6882
6883 #[serde(default)]
6885 pub customer_behavior: CustomerBehaviorSchemaConfig,
6886
6887 #[serde(default)]
6889 pub employee_behavior: EmployeeBehaviorSchemaConfig,
6890
6891 #[serde(default)]
6893 pub collective: CollectiveBehaviorSchemaConfig,
6894}
6895
6896#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6898pub struct VendorBehaviorSchemaConfig {
6899 #[serde(default)]
6901 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
6902
6903 #[serde(default)]
6905 pub quality_drift: QualityDriftSchemaConfig,
6906}
6907
6908#[derive(Debug, Clone, Serialize, Deserialize)]
6910pub struct PaymentTermsDriftSchemaConfig {
6911 #[serde(default = "default_extension_rate")]
6913 pub extension_rate_per_year: f64,
6914
6915 #[serde(default = "default_economic_sensitivity")]
6917 pub economic_sensitivity: f64,
6918}
6919
6920fn default_extension_rate() -> f64 {
6921 2.5
6922}
6923
6924fn default_economic_sensitivity() -> f64 {
6925 1.0
6926}
6927
6928impl Default for PaymentTermsDriftSchemaConfig {
6929 fn default() -> Self {
6930 Self {
6931 extension_rate_per_year: 2.5,
6932 economic_sensitivity: 1.0,
6933 }
6934 }
6935}
6936
6937#[derive(Debug, Clone, Serialize, Deserialize)]
6939pub struct QualityDriftSchemaConfig {
6940 #[serde(default = "default_improvement_rate")]
6942 pub new_vendor_improvement_rate: f64,
6943
6944 #[serde(default = "default_decline_rate")]
6946 pub complacency_decline_rate: f64,
6947}
6948
6949fn default_improvement_rate() -> f64 {
6950 0.02
6951}
6952
6953fn default_decline_rate() -> f64 {
6954 0.01
6955}
6956
6957impl Default for QualityDriftSchemaConfig {
6958 fn default() -> Self {
6959 Self {
6960 new_vendor_improvement_rate: 0.02,
6961 complacency_decline_rate: 0.01,
6962 }
6963 }
6964}
6965
6966#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6968pub struct CustomerBehaviorSchemaConfig {
6969 #[serde(default)]
6971 pub payment_drift: CustomerPaymentDriftSchemaConfig,
6972
6973 #[serde(default)]
6975 pub order_drift: OrderDriftSchemaConfig,
6976}
6977
6978#[derive(Debug, Clone, Serialize, Deserialize)]
6980pub struct CustomerPaymentDriftSchemaConfig {
6981 #[serde(default = "default_downturn_extension")]
6983 pub downturn_days_extension: (u32, u32),
6984
6985 #[serde(default = "default_bad_debt_increase")]
6987 pub downturn_bad_debt_increase: f64,
6988}
6989
6990fn default_downturn_extension() -> (u32, u32) {
6991 (5, 15)
6992}
6993
6994fn default_bad_debt_increase() -> f64 {
6995 0.02
6996}
6997
6998impl Default for CustomerPaymentDriftSchemaConfig {
6999 fn default() -> Self {
7000 Self {
7001 downturn_days_extension: (5, 15),
7002 downturn_bad_debt_increase: 0.02,
7003 }
7004 }
7005}
7006
7007#[derive(Debug, Clone, Serialize, Deserialize)]
7009pub struct OrderDriftSchemaConfig {
7010 #[serde(default = "default_digital_shift")]
7012 pub digital_shift_rate: f64,
7013}
7014
7015fn default_digital_shift() -> f64 {
7016 0.05
7017}
7018
7019impl Default for OrderDriftSchemaConfig {
7020 fn default() -> Self {
7021 Self {
7022 digital_shift_rate: 0.05,
7023 }
7024 }
7025}
7026
7027#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7029pub struct EmployeeBehaviorSchemaConfig {
7030 #[serde(default)]
7032 pub approval_drift: ApprovalDriftSchemaConfig,
7033
7034 #[serde(default)]
7036 pub error_drift: ErrorDriftSchemaConfig,
7037}
7038
7039#[derive(Debug, Clone, Serialize, Deserialize)]
7041pub struct ApprovalDriftSchemaConfig {
7042 #[serde(default = "default_eom_intensity")]
7044 pub eom_intensity_increase_per_year: f64,
7045
7046 #[serde(default = "default_rubber_stamp")]
7048 pub rubber_stamp_volume_threshold: u32,
7049}
7050
7051fn default_eom_intensity() -> f64 {
7052 0.05
7053}
7054
7055fn default_rubber_stamp() -> u32 {
7056 50
7057}
7058
7059impl Default for ApprovalDriftSchemaConfig {
7060 fn default() -> Self {
7061 Self {
7062 eom_intensity_increase_per_year: 0.05,
7063 rubber_stamp_volume_threshold: 50,
7064 }
7065 }
7066}
7067
7068#[derive(Debug, Clone, Serialize, Deserialize)]
7070pub struct ErrorDriftSchemaConfig {
7071 #[serde(default = "default_new_error")]
7073 pub new_employee_error_rate: f64,
7074
7075 #[serde(default = "default_learning_months")]
7077 pub learning_curve_months: u32,
7078}
7079
7080fn default_new_error() -> f64 {
7081 0.08
7082}
7083
7084fn default_learning_months() -> u32 {
7085 6
7086}
7087
7088impl Default for ErrorDriftSchemaConfig {
7089 fn default() -> Self {
7090 Self {
7091 new_employee_error_rate: 0.08,
7092 learning_curve_months: 6,
7093 }
7094 }
7095}
7096
7097#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7099pub struct CollectiveBehaviorSchemaConfig {
7100 #[serde(default)]
7102 pub automation_adoption: AutomationAdoptionSchemaConfig,
7103}
7104
7105#[derive(Debug, Clone, Serialize, Deserialize)]
7107pub struct AutomationAdoptionSchemaConfig {
7108 #[serde(default)]
7110 pub s_curve_enabled: bool,
7111
7112 #[serde(default = "default_midpoint")]
7114 pub adoption_midpoint_months: u32,
7115
7116 #[serde(default = "default_steepness")]
7118 pub steepness: f64,
7119}
7120
7121fn default_midpoint() -> u32 {
7122 24
7123}
7124
7125fn default_steepness() -> f64 {
7126 0.15
7127}
7128
7129impl Default for AutomationAdoptionSchemaConfig {
7130 fn default() -> Self {
7131 Self {
7132 s_curve_enabled: false,
7133 adoption_midpoint_months: 24,
7134 steepness: 0.15,
7135 }
7136 }
7137}
7138
7139#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7145pub struct MarketDriftSchemaConfig {
7146 #[serde(default)]
7148 pub enabled: bool,
7149
7150 #[serde(default)]
7152 pub economic_cycle: MarketEconomicCycleSchemaConfig,
7153
7154 #[serde(default)]
7156 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7157
7158 #[serde(default)]
7160 pub commodities: CommoditiesSchemaConfig,
7161}
7162
7163#[derive(Debug, Clone, Serialize, Deserialize)]
7165pub struct MarketEconomicCycleSchemaConfig {
7166 #[serde(default)]
7168 pub enabled: bool,
7169
7170 #[serde(default)]
7172 pub cycle_type: CycleTypeSchemaConfig,
7173
7174 #[serde(default = "default_market_cycle_period")]
7176 pub period_months: u32,
7177
7178 #[serde(default = "default_market_amplitude")]
7180 pub amplitude: f64,
7181
7182 #[serde(default)]
7184 pub recession: RecessionSchemaConfig,
7185}
7186
7187fn default_market_cycle_period() -> u32 {
7188 48
7189}
7190
7191fn default_market_amplitude() -> f64 {
7192 0.15
7193}
7194
7195impl Default for MarketEconomicCycleSchemaConfig {
7196 fn default() -> Self {
7197 Self {
7198 enabled: false,
7199 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7200 period_months: 48,
7201 amplitude: 0.15,
7202 recession: RecessionSchemaConfig::default(),
7203 }
7204 }
7205}
7206
7207#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7209#[serde(rename_all = "snake_case")]
7210pub enum CycleTypeSchemaConfig {
7211 #[default]
7213 Sinusoidal,
7214 Asymmetric,
7216 MeanReverting,
7218}
7219
7220#[derive(Debug, Clone, Serialize, Deserialize)]
7222pub struct RecessionSchemaConfig {
7223 #[serde(default)]
7225 pub enabled: bool,
7226
7227 #[serde(default = "default_recession_prob")]
7229 pub probability_per_year: f64,
7230
7231 #[serde(default)]
7233 pub severity: RecessionSeveritySchemaConfig,
7234
7235 #[serde(default)]
7237 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7238}
7239
7240fn default_recession_prob() -> f64 {
7241 0.10
7242}
7243
7244impl Default for RecessionSchemaConfig {
7245 fn default() -> Self {
7246 Self {
7247 enabled: false,
7248 probability_per_year: 0.10,
7249 severity: RecessionSeveritySchemaConfig::Moderate,
7250 recession_periods: Vec::new(),
7251 }
7252 }
7253}
7254
7255#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7257#[serde(rename_all = "snake_case")]
7258pub enum RecessionSeveritySchemaConfig {
7259 Mild,
7261 #[default]
7263 Moderate,
7264 Severe,
7266}
7267
7268#[derive(Debug, Clone, Serialize, Deserialize)]
7270pub struct RecessionPeriodSchemaConfig {
7271 pub start_month: u32,
7273 pub duration_months: u32,
7275}
7276
7277#[derive(Debug, Clone, Serialize, Deserialize)]
7279pub struct IndustryCycleSchemaConfig {
7280 #[serde(default = "default_industry_period")]
7282 pub period_months: u32,
7283
7284 #[serde(default = "default_industry_amp")]
7286 pub amplitude: f64,
7287}
7288
7289fn default_industry_period() -> u32 {
7290 36
7291}
7292
7293fn default_industry_amp() -> f64 {
7294 0.20
7295}
7296
7297#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7299pub struct CommoditiesSchemaConfig {
7300 #[serde(default)]
7302 pub enabled: bool,
7303
7304 #[serde(default)]
7306 pub items: Vec<CommodityItemSchemaConfig>,
7307}
7308
7309#[derive(Debug, Clone, Serialize, Deserialize)]
7311pub struct CommodityItemSchemaConfig {
7312 pub name: String,
7314
7315 #[serde(default = "default_volatility")]
7317 pub volatility: f64,
7318
7319 #[serde(default)]
7321 pub cogs_pass_through: f64,
7322
7323 #[serde(default)]
7325 pub overhead_pass_through: f64,
7326}
7327
7328fn default_volatility() -> f64 {
7329 0.20
7330}
7331
7332#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7338pub struct DriftLabelingSchemaConfig {
7339 #[serde(default)]
7341 pub enabled: bool,
7342
7343 #[serde(default)]
7345 pub statistical: StatisticalDriftLabelingSchemaConfig,
7346
7347 #[serde(default)]
7349 pub categorical: CategoricalDriftLabelingSchemaConfig,
7350
7351 #[serde(default)]
7353 pub temporal: TemporalDriftLabelingSchemaConfig,
7354
7355 #[serde(default)]
7357 pub regulatory_calendar_preset: Option<String>,
7358}
7359
7360#[derive(Debug, Clone, Serialize, Deserialize)]
7362pub struct StatisticalDriftLabelingSchemaConfig {
7363 #[serde(default = "default_true_val")]
7365 pub enabled: bool,
7366
7367 #[serde(default = "default_min_magnitude")]
7369 pub min_magnitude_threshold: f64,
7370}
7371
7372fn default_min_magnitude() -> f64 {
7373 0.05
7374}
7375
7376impl Default for StatisticalDriftLabelingSchemaConfig {
7377 fn default() -> Self {
7378 Self {
7379 enabled: true,
7380 min_magnitude_threshold: 0.05,
7381 }
7382 }
7383}
7384
7385#[derive(Debug, Clone, Serialize, Deserialize)]
7387pub struct CategoricalDriftLabelingSchemaConfig {
7388 #[serde(default = "default_true_val")]
7390 pub enabled: bool,
7391}
7392
7393impl Default for CategoricalDriftLabelingSchemaConfig {
7394 fn default() -> Self {
7395 Self { enabled: true }
7396 }
7397}
7398
7399#[derive(Debug, Clone, Serialize, Deserialize)]
7401pub struct TemporalDriftLabelingSchemaConfig {
7402 #[serde(default = "default_true_val")]
7404 pub enabled: bool,
7405}
7406
7407impl Default for TemporalDriftLabelingSchemaConfig {
7408 fn default() -> Self {
7409 Self { enabled: true }
7410 }
7411}
7412
7413#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7426pub struct EnhancedAnomalyConfig {
7427 #[serde(default)]
7429 pub enabled: bool,
7430
7431 #[serde(default)]
7433 pub rates: AnomalyRateConfig,
7434
7435 #[serde(default)]
7437 pub multi_stage_schemes: MultiStageSchemeConfig,
7438
7439 #[serde(default)]
7441 pub correlated_injection: CorrelatedInjectionConfig,
7442
7443 #[serde(default)]
7445 pub near_miss: NearMissConfig,
7446
7447 #[serde(default)]
7449 pub difficulty_classification: DifficultyClassificationConfig,
7450
7451 #[serde(default)]
7453 pub context_aware: ContextAwareConfig,
7454
7455 #[serde(default)]
7457 pub labeling: EnhancedLabelingConfig,
7458}
7459
7460#[derive(Debug, Clone, Serialize, Deserialize)]
7462pub struct AnomalyRateConfig {
7463 #[serde(default = "default_total_anomaly_rate")]
7465 pub total_rate: f64,
7466
7467 #[serde(default = "default_fraud_anomaly_rate")]
7469 pub fraud_rate: f64,
7470
7471 #[serde(default = "default_error_anomaly_rate")]
7473 pub error_rate: f64,
7474
7475 #[serde(default = "default_process_anomaly_rate")]
7477 pub process_rate: f64,
7478}
7479
7480fn default_total_anomaly_rate() -> f64 {
7481 0.03
7482}
7483fn default_fraud_anomaly_rate() -> f64 {
7484 0.01
7485}
7486fn default_error_anomaly_rate() -> f64 {
7487 0.015
7488}
7489fn default_process_anomaly_rate() -> f64 {
7490 0.005
7491}
7492
7493impl Default for AnomalyRateConfig {
7494 fn default() -> Self {
7495 Self {
7496 total_rate: default_total_anomaly_rate(),
7497 fraud_rate: default_fraud_anomaly_rate(),
7498 error_rate: default_error_anomaly_rate(),
7499 process_rate: default_process_anomaly_rate(),
7500 }
7501 }
7502}
7503
7504#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7506pub struct MultiStageSchemeConfig {
7507 #[serde(default)]
7509 pub enabled: bool,
7510
7511 #[serde(default)]
7513 pub embezzlement: EmbezzlementSchemeConfig,
7514
7515 #[serde(default)]
7517 pub revenue_manipulation: RevenueManipulationSchemeConfig,
7518
7519 #[serde(default)]
7521 pub kickback: KickbackSchemeConfig,
7522}
7523
7524#[derive(Debug, Clone, Serialize, Deserialize)]
7526pub struct EmbezzlementSchemeConfig {
7527 #[serde(default = "default_embezzlement_probability")]
7529 pub probability: f64,
7530
7531 #[serde(default)]
7533 pub testing_stage: SchemeStageConfig,
7534
7535 #[serde(default)]
7537 pub escalation_stage: SchemeStageConfig,
7538
7539 #[serde(default)]
7541 pub acceleration_stage: SchemeStageConfig,
7542
7543 #[serde(default)]
7545 pub desperation_stage: SchemeStageConfig,
7546}
7547
7548fn default_embezzlement_probability() -> f64 {
7549 0.02
7550}
7551
7552impl Default for EmbezzlementSchemeConfig {
7553 fn default() -> Self {
7554 Self {
7555 probability: default_embezzlement_probability(),
7556 testing_stage: SchemeStageConfig {
7557 duration_months: 2,
7558 amount_min: 100.0,
7559 amount_max: 500.0,
7560 transaction_count_min: 2,
7561 transaction_count_max: 5,
7562 difficulty: "hard".to_string(),
7563 },
7564 escalation_stage: SchemeStageConfig {
7565 duration_months: 6,
7566 amount_min: 500.0,
7567 amount_max: 2000.0,
7568 transaction_count_min: 3,
7569 transaction_count_max: 8,
7570 difficulty: "moderate".to_string(),
7571 },
7572 acceleration_stage: SchemeStageConfig {
7573 duration_months: 3,
7574 amount_min: 2000.0,
7575 amount_max: 10000.0,
7576 transaction_count_min: 5,
7577 transaction_count_max: 12,
7578 difficulty: "easy".to_string(),
7579 },
7580 desperation_stage: SchemeStageConfig {
7581 duration_months: 1,
7582 amount_min: 10000.0,
7583 amount_max: 50000.0,
7584 transaction_count_min: 3,
7585 transaction_count_max: 6,
7586 difficulty: "trivial".to_string(),
7587 },
7588 }
7589 }
7590}
7591
7592#[derive(Debug, Clone, Serialize, Deserialize)]
7594pub struct RevenueManipulationSchemeConfig {
7595 #[serde(default = "default_revenue_manipulation_probability")]
7597 pub probability: f64,
7598
7599 #[serde(default = "default_early_recognition_target")]
7601 pub early_recognition_target: f64,
7602
7603 #[serde(default = "default_expense_deferral_target")]
7605 pub expense_deferral_target: f64,
7606
7607 #[serde(default = "default_reserve_release_target")]
7609 pub reserve_release_target: f64,
7610
7611 #[serde(default = "default_channel_stuffing_target")]
7613 pub channel_stuffing_target: f64,
7614}
7615
7616fn default_revenue_manipulation_probability() -> f64 {
7617 0.01
7618}
7619fn default_early_recognition_target() -> f64 {
7620 0.02
7621}
7622fn default_expense_deferral_target() -> f64 {
7623 0.03
7624}
7625fn default_reserve_release_target() -> f64 {
7626 0.02
7627}
7628fn default_channel_stuffing_target() -> f64 {
7629 0.05
7630}
7631
7632impl Default for RevenueManipulationSchemeConfig {
7633 fn default() -> Self {
7634 Self {
7635 probability: default_revenue_manipulation_probability(),
7636 early_recognition_target: default_early_recognition_target(),
7637 expense_deferral_target: default_expense_deferral_target(),
7638 reserve_release_target: default_reserve_release_target(),
7639 channel_stuffing_target: default_channel_stuffing_target(),
7640 }
7641 }
7642}
7643
7644#[derive(Debug, Clone, Serialize, Deserialize)]
7646pub struct KickbackSchemeConfig {
7647 #[serde(default = "default_kickback_probability")]
7649 pub probability: f64,
7650
7651 #[serde(default = "default_kickback_inflation_min")]
7653 pub inflation_min: f64,
7654
7655 #[serde(default = "default_kickback_inflation_max")]
7657 pub inflation_max: f64,
7658
7659 #[serde(default = "default_kickback_percent")]
7661 pub kickback_percent: f64,
7662
7663 #[serde(default = "default_kickback_setup_months")]
7665 pub setup_months: u32,
7666
7667 #[serde(default = "default_kickback_operation_months")]
7669 pub operation_months: u32,
7670}
7671
7672fn default_kickback_probability() -> f64 {
7673 0.01
7674}
7675fn default_kickback_inflation_min() -> f64 {
7676 0.10
7677}
7678fn default_kickback_inflation_max() -> f64 {
7679 0.25
7680}
7681fn default_kickback_percent() -> f64 {
7682 0.50
7683}
7684fn default_kickback_setup_months() -> u32 {
7685 3
7686}
7687fn default_kickback_operation_months() -> u32 {
7688 12
7689}
7690
7691impl Default for KickbackSchemeConfig {
7692 fn default() -> Self {
7693 Self {
7694 probability: default_kickback_probability(),
7695 inflation_min: default_kickback_inflation_min(),
7696 inflation_max: default_kickback_inflation_max(),
7697 kickback_percent: default_kickback_percent(),
7698 setup_months: default_kickback_setup_months(),
7699 operation_months: default_kickback_operation_months(),
7700 }
7701 }
7702}
7703
7704#[derive(Debug, Clone, Serialize, Deserialize)]
7706pub struct SchemeStageConfig {
7707 pub duration_months: u32,
7709
7710 pub amount_min: f64,
7712
7713 pub amount_max: f64,
7715
7716 pub transaction_count_min: u32,
7718
7719 pub transaction_count_max: u32,
7721
7722 pub difficulty: String,
7724}
7725
7726impl Default for SchemeStageConfig {
7727 fn default() -> Self {
7728 Self {
7729 duration_months: 3,
7730 amount_min: 100.0,
7731 amount_max: 1000.0,
7732 transaction_count_min: 2,
7733 transaction_count_max: 10,
7734 difficulty: "moderate".to_string(),
7735 }
7736 }
7737}
7738
7739#[derive(Debug, Clone, Serialize, Deserialize)]
7741pub struct CorrelatedInjectionConfig {
7742 #[serde(default)]
7744 pub enabled: bool,
7745
7746 #[serde(default = "default_true_val")]
7748 pub fraud_concealment: bool,
7749
7750 #[serde(default = "default_true_val")]
7752 pub error_cascade: bool,
7753
7754 #[serde(default = "default_true_val")]
7756 pub temporal_clustering: bool,
7757
7758 #[serde(default)]
7760 pub temporal_clustering_config: TemporalClusteringConfig,
7761
7762 #[serde(default)]
7764 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
7765}
7766
7767impl Default for CorrelatedInjectionConfig {
7768 fn default() -> Self {
7769 Self {
7770 enabled: false,
7771 fraud_concealment: true,
7772 error_cascade: true,
7773 temporal_clustering: true,
7774 temporal_clustering_config: TemporalClusteringConfig::default(),
7775 co_occurrence_patterns: Vec::new(),
7776 }
7777 }
7778}
7779
7780#[derive(Debug, Clone, Serialize, Deserialize)]
7782pub struct TemporalClusteringConfig {
7783 #[serde(default = "default_period_end_multiplier")]
7785 pub period_end_multiplier: f64,
7786
7787 #[serde(default = "default_period_end_days")]
7789 pub period_end_days: u32,
7790
7791 #[serde(default = "default_quarter_end_multiplier")]
7793 pub quarter_end_multiplier: f64,
7794
7795 #[serde(default = "default_year_end_multiplier")]
7797 pub year_end_multiplier: f64,
7798}
7799
7800fn default_period_end_multiplier() -> f64 {
7801 2.5
7802}
7803fn default_period_end_days() -> u32 {
7804 5
7805}
7806fn default_quarter_end_multiplier() -> f64 {
7807 1.5
7808}
7809fn default_year_end_multiplier() -> f64 {
7810 2.0
7811}
7812
7813impl Default for TemporalClusteringConfig {
7814 fn default() -> Self {
7815 Self {
7816 period_end_multiplier: default_period_end_multiplier(),
7817 period_end_days: default_period_end_days(),
7818 quarter_end_multiplier: default_quarter_end_multiplier(),
7819 year_end_multiplier: default_year_end_multiplier(),
7820 }
7821 }
7822}
7823
7824#[derive(Debug, Clone, Serialize, Deserialize)]
7826pub struct CoOccurrencePatternConfig {
7827 pub name: String,
7829
7830 pub primary_type: String,
7832
7833 pub correlated: Vec<CorrelatedAnomalyConfig>,
7835}
7836
7837#[derive(Debug, Clone, Serialize, Deserialize)]
7839pub struct CorrelatedAnomalyConfig {
7840 pub anomaly_type: String,
7842
7843 pub probability: f64,
7845
7846 pub lag_days_min: i32,
7848
7849 pub lag_days_max: i32,
7851}
7852
7853#[derive(Debug, Clone, Serialize, Deserialize)]
7855pub struct NearMissConfig {
7856 #[serde(default)]
7858 pub enabled: bool,
7859
7860 #[serde(default = "default_near_miss_proportion")]
7862 pub proportion: f64,
7863
7864 #[serde(default = "default_true_val")]
7866 pub near_duplicate: bool,
7867
7868 #[serde(default)]
7870 pub near_duplicate_days: NearDuplicateDaysConfig,
7871
7872 #[serde(default = "default_true_val")]
7874 pub threshold_proximity: bool,
7875
7876 #[serde(default)]
7878 pub threshold_proximity_range: ThresholdProximityRangeConfig,
7879
7880 #[serde(default = "default_true_val")]
7882 pub unusual_legitimate: bool,
7883
7884 #[serde(default = "default_unusual_legitimate_types")]
7886 pub unusual_legitimate_types: Vec<String>,
7887
7888 #[serde(default = "default_true_val")]
7890 pub corrected_errors: bool,
7891
7892 #[serde(default)]
7894 pub corrected_error_lag: CorrectedErrorLagConfig,
7895}
7896
7897fn default_near_miss_proportion() -> f64 {
7898 0.30
7899}
7900
7901fn default_unusual_legitimate_types() -> Vec<String> {
7902 vec![
7903 "year_end_bonus".to_string(),
7904 "contract_prepayment".to_string(),
7905 "insurance_claim".to_string(),
7906 "settlement_payment".to_string(),
7907 ]
7908}
7909
7910impl Default for NearMissConfig {
7911 fn default() -> Self {
7912 Self {
7913 enabled: false,
7914 proportion: default_near_miss_proportion(),
7915 near_duplicate: true,
7916 near_duplicate_days: NearDuplicateDaysConfig::default(),
7917 threshold_proximity: true,
7918 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
7919 unusual_legitimate: true,
7920 unusual_legitimate_types: default_unusual_legitimate_types(),
7921 corrected_errors: true,
7922 corrected_error_lag: CorrectedErrorLagConfig::default(),
7923 }
7924 }
7925}
7926
7927#[derive(Debug, Clone, Serialize, Deserialize)]
7929pub struct NearDuplicateDaysConfig {
7930 #[serde(default = "default_near_duplicate_min")]
7932 pub min: u32,
7933
7934 #[serde(default = "default_near_duplicate_max")]
7936 pub max: u32,
7937}
7938
7939fn default_near_duplicate_min() -> u32 {
7940 1
7941}
7942fn default_near_duplicate_max() -> u32 {
7943 3
7944}
7945
7946impl Default for NearDuplicateDaysConfig {
7947 fn default() -> Self {
7948 Self {
7949 min: default_near_duplicate_min(),
7950 max: default_near_duplicate_max(),
7951 }
7952 }
7953}
7954
7955#[derive(Debug, Clone, Serialize, Deserialize)]
7957pub struct ThresholdProximityRangeConfig {
7958 #[serde(default = "default_threshold_proximity_min")]
7960 pub min: f64,
7961
7962 #[serde(default = "default_threshold_proximity_max")]
7964 pub max: f64,
7965}
7966
7967fn default_threshold_proximity_min() -> f64 {
7968 0.90
7969}
7970fn default_threshold_proximity_max() -> f64 {
7971 0.99
7972}
7973
7974impl Default for ThresholdProximityRangeConfig {
7975 fn default() -> Self {
7976 Self {
7977 min: default_threshold_proximity_min(),
7978 max: default_threshold_proximity_max(),
7979 }
7980 }
7981}
7982
7983#[derive(Debug, Clone, Serialize, Deserialize)]
7985pub struct CorrectedErrorLagConfig {
7986 #[serde(default = "default_corrected_error_lag_min")]
7988 pub min: u32,
7989
7990 #[serde(default = "default_corrected_error_lag_max")]
7992 pub max: u32,
7993}
7994
7995fn default_corrected_error_lag_min() -> u32 {
7996 1
7997}
7998fn default_corrected_error_lag_max() -> u32 {
7999 5
8000}
8001
8002impl Default for CorrectedErrorLagConfig {
8003 fn default() -> Self {
8004 Self {
8005 min: default_corrected_error_lag_min(),
8006 max: default_corrected_error_lag_max(),
8007 }
8008 }
8009}
8010
8011#[derive(Debug, Clone, Serialize, Deserialize)]
8013pub struct DifficultyClassificationConfig {
8014 #[serde(default)]
8016 pub enabled: bool,
8017
8018 #[serde(default)]
8020 pub target_distribution: DifficultyDistributionConfig,
8021}
8022
8023impl Default for DifficultyClassificationConfig {
8024 fn default() -> Self {
8025 Self {
8026 enabled: true,
8027 target_distribution: DifficultyDistributionConfig::default(),
8028 }
8029 }
8030}
8031
8032#[derive(Debug, Clone, Serialize, Deserialize)]
8034pub struct DifficultyDistributionConfig {
8035 #[serde(default = "default_difficulty_trivial")]
8037 pub trivial: f64,
8038
8039 #[serde(default = "default_difficulty_easy")]
8041 pub easy: f64,
8042
8043 #[serde(default = "default_difficulty_moderate")]
8045 pub moderate: f64,
8046
8047 #[serde(default = "default_difficulty_hard")]
8049 pub hard: f64,
8050
8051 #[serde(default = "default_difficulty_expert")]
8053 pub expert: f64,
8054}
8055
8056fn default_difficulty_trivial() -> f64 {
8057 0.15
8058}
8059fn default_difficulty_easy() -> f64 {
8060 0.25
8061}
8062fn default_difficulty_moderate() -> f64 {
8063 0.30
8064}
8065fn default_difficulty_hard() -> f64 {
8066 0.20
8067}
8068fn default_difficulty_expert() -> f64 {
8069 0.10
8070}
8071
8072impl Default for DifficultyDistributionConfig {
8073 fn default() -> Self {
8074 Self {
8075 trivial: default_difficulty_trivial(),
8076 easy: default_difficulty_easy(),
8077 moderate: default_difficulty_moderate(),
8078 hard: default_difficulty_hard(),
8079 expert: default_difficulty_expert(),
8080 }
8081 }
8082}
8083
8084#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8086pub struct ContextAwareConfig {
8087 #[serde(default)]
8089 pub enabled: bool,
8090
8091 #[serde(default)]
8093 pub vendor_rules: VendorAnomalyRulesConfig,
8094
8095 #[serde(default)]
8097 pub employee_rules: EmployeeAnomalyRulesConfig,
8098
8099 #[serde(default)]
8101 pub account_rules: AccountAnomalyRulesConfig,
8102
8103 #[serde(default)]
8105 pub behavioral_baseline: BehavioralBaselineConfig,
8106}
8107
8108#[derive(Debug, Clone, Serialize, Deserialize)]
8110pub struct VendorAnomalyRulesConfig {
8111 #[serde(default = "default_new_vendor_multiplier")]
8113 pub new_vendor_error_multiplier: f64,
8114
8115 #[serde(default = "default_new_vendor_threshold")]
8117 pub new_vendor_threshold_days: u32,
8118
8119 #[serde(default = "default_international_multiplier")]
8121 pub international_error_multiplier: f64,
8122
8123 #[serde(default = "default_strategic_vendor_types")]
8125 pub strategic_vendor_anomaly_types: Vec<String>,
8126}
8127
8128fn default_new_vendor_multiplier() -> f64 {
8129 2.5
8130}
8131fn default_new_vendor_threshold() -> u32 {
8132 90
8133}
8134fn default_international_multiplier() -> f64 {
8135 1.5
8136}
8137fn default_strategic_vendor_types() -> Vec<String> {
8138 vec![
8139 "pricing_dispute".to_string(),
8140 "contract_violation".to_string(),
8141 ]
8142}
8143
8144impl Default for VendorAnomalyRulesConfig {
8145 fn default() -> Self {
8146 Self {
8147 new_vendor_error_multiplier: default_new_vendor_multiplier(),
8148 new_vendor_threshold_days: default_new_vendor_threshold(),
8149 international_error_multiplier: default_international_multiplier(),
8150 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8151 }
8152 }
8153}
8154
8155#[derive(Debug, Clone, Serialize, Deserialize)]
8157pub struct EmployeeAnomalyRulesConfig {
8158 #[serde(default = "default_new_employee_rate")]
8160 pub new_employee_error_rate: f64,
8161
8162 #[serde(default = "default_new_employee_threshold")]
8164 pub new_employee_threshold_days: u32,
8165
8166 #[serde(default = "default_volume_fatigue_threshold")]
8168 pub volume_fatigue_threshold: u32,
8169
8170 #[serde(default = "default_coverage_multiplier")]
8172 pub coverage_error_multiplier: f64,
8173}
8174
8175fn default_new_employee_rate() -> f64 {
8176 0.05
8177}
8178fn default_new_employee_threshold() -> u32 {
8179 180
8180}
8181fn default_volume_fatigue_threshold() -> u32 {
8182 50
8183}
8184fn default_coverage_multiplier() -> f64 {
8185 1.8
8186}
8187
8188impl Default for EmployeeAnomalyRulesConfig {
8189 fn default() -> Self {
8190 Self {
8191 new_employee_error_rate: default_new_employee_rate(),
8192 new_employee_threshold_days: default_new_employee_threshold(),
8193 volume_fatigue_threshold: default_volume_fatigue_threshold(),
8194 coverage_error_multiplier: default_coverage_multiplier(),
8195 }
8196 }
8197}
8198
8199#[derive(Debug, Clone, Serialize, Deserialize)]
8201pub struct AccountAnomalyRulesConfig {
8202 #[serde(default = "default_high_risk_multiplier")]
8204 pub high_risk_account_multiplier: f64,
8205
8206 #[serde(default = "default_high_risk_accounts")]
8208 pub high_risk_accounts: Vec<String>,
8209
8210 #[serde(default = "default_suspense_multiplier")]
8212 pub suspense_account_multiplier: f64,
8213
8214 #[serde(default = "default_suspense_accounts")]
8216 pub suspense_accounts: Vec<String>,
8217
8218 #[serde(default = "default_intercompany_multiplier")]
8220 pub intercompany_account_multiplier: f64,
8221}
8222
8223fn default_high_risk_multiplier() -> f64 {
8224 2.0
8225}
8226fn default_high_risk_accounts() -> Vec<String> {
8227 vec![
8228 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
8232}
8233fn default_suspense_multiplier() -> f64 {
8234 3.0
8235}
8236fn default_suspense_accounts() -> Vec<String> {
8237 vec!["9999".to_string(), "9998".to_string()]
8238}
8239fn default_intercompany_multiplier() -> f64 {
8240 1.5
8241}
8242
8243impl Default for AccountAnomalyRulesConfig {
8244 fn default() -> Self {
8245 Self {
8246 high_risk_account_multiplier: default_high_risk_multiplier(),
8247 high_risk_accounts: default_high_risk_accounts(),
8248 suspense_account_multiplier: default_suspense_multiplier(),
8249 suspense_accounts: default_suspense_accounts(),
8250 intercompany_account_multiplier: default_intercompany_multiplier(),
8251 }
8252 }
8253}
8254
8255#[derive(Debug, Clone, Serialize, Deserialize)]
8257pub struct BehavioralBaselineConfig {
8258 #[serde(default)]
8260 pub enabled: bool,
8261
8262 #[serde(default = "default_baseline_period")]
8264 pub baseline_period_days: u32,
8265
8266 #[serde(default = "default_deviation_threshold")]
8268 pub deviation_threshold_std: f64,
8269
8270 #[serde(default = "default_frequency_deviation")]
8272 pub frequency_deviation_threshold: f64,
8273}
8274
8275fn default_baseline_period() -> u32 {
8276 90
8277}
8278fn default_deviation_threshold() -> f64 {
8279 3.0
8280}
8281fn default_frequency_deviation() -> f64 {
8282 2.0
8283}
8284
8285impl Default for BehavioralBaselineConfig {
8286 fn default() -> Self {
8287 Self {
8288 enabled: false,
8289 baseline_period_days: default_baseline_period(),
8290 deviation_threshold_std: default_deviation_threshold(),
8291 frequency_deviation_threshold: default_frequency_deviation(),
8292 }
8293 }
8294}
8295
8296#[derive(Debug, Clone, Serialize, Deserialize)]
8298pub struct EnhancedLabelingConfig {
8299 #[serde(default = "default_true_val")]
8301 pub severity_scoring: bool,
8302
8303 #[serde(default = "default_true_val")]
8305 pub difficulty_classification: bool,
8306
8307 #[serde(default)]
8309 pub materiality_thresholds: MaterialityThresholdsConfig,
8310}
8311
8312impl Default for EnhancedLabelingConfig {
8313 fn default() -> Self {
8314 Self {
8315 severity_scoring: true,
8316 difficulty_classification: true,
8317 materiality_thresholds: MaterialityThresholdsConfig::default(),
8318 }
8319 }
8320}
8321
8322#[derive(Debug, Clone, Serialize, Deserialize)]
8324pub struct MaterialityThresholdsConfig {
8325 #[serde(default = "default_materiality_trivial")]
8327 pub trivial: f64,
8328
8329 #[serde(default = "default_materiality_immaterial")]
8331 pub immaterial: f64,
8332
8333 #[serde(default = "default_materiality_material")]
8335 pub material: f64,
8336
8337 #[serde(default = "default_materiality_highly_material")]
8339 pub highly_material: f64,
8340}
8341
8342fn default_materiality_trivial() -> f64 {
8343 0.001
8344}
8345fn default_materiality_immaterial() -> f64 {
8346 0.01
8347}
8348fn default_materiality_material() -> f64 {
8349 0.05
8350}
8351fn default_materiality_highly_material() -> f64 {
8352 0.10
8353}
8354
8355impl Default for MaterialityThresholdsConfig {
8356 fn default() -> Self {
8357 Self {
8358 trivial: default_materiality_trivial(),
8359 immaterial: default_materiality_immaterial(),
8360 material: default_materiality_material(),
8361 highly_material: default_materiality_highly_material(),
8362 }
8363 }
8364}
8365
8366#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8378pub struct IndustrySpecificConfig {
8379 #[serde(default)]
8381 pub enabled: bool,
8382
8383 #[serde(default)]
8385 pub manufacturing: ManufacturingConfig,
8386
8387 #[serde(default)]
8389 pub retail: RetailConfig,
8390
8391 #[serde(default)]
8393 pub healthcare: HealthcareConfig,
8394
8395 #[serde(default)]
8397 pub technology: TechnologyConfig,
8398
8399 #[serde(default)]
8401 pub financial_services: FinancialServicesConfig,
8402
8403 #[serde(default)]
8405 pub professional_services: ProfessionalServicesConfig,
8406}
8407
8408#[derive(Debug, Clone, Serialize, Deserialize)]
8410pub struct ManufacturingConfig {
8411 #[serde(default)]
8413 pub enabled: bool,
8414
8415 #[serde(default = "default_bom_depth")]
8417 pub bom_depth: u32,
8418
8419 #[serde(default)]
8421 pub just_in_time: bool,
8422
8423 #[serde(default = "default_production_order_types")]
8425 pub production_order_types: Vec<String>,
8426
8427 #[serde(default)]
8429 pub quality_framework: Option<String>,
8430
8431 #[serde(default = "default_supplier_tiers")]
8433 pub supplier_tiers: u32,
8434
8435 #[serde(default = "default_cost_frequency")]
8437 pub standard_cost_frequency: String,
8438
8439 #[serde(default = "default_yield_rate")]
8441 pub target_yield_rate: f64,
8442
8443 #[serde(default = "default_scrap_threshold")]
8445 pub scrap_alert_threshold: f64,
8446
8447 #[serde(default)]
8449 pub anomaly_rates: ManufacturingAnomalyRates,
8450}
8451
8452fn default_bom_depth() -> u32 {
8453 4
8454}
8455
8456fn default_production_order_types() -> Vec<String> {
8457 vec![
8458 "standard".to_string(),
8459 "rework".to_string(),
8460 "prototype".to_string(),
8461 ]
8462}
8463
8464fn default_supplier_tiers() -> u32 {
8465 2
8466}
8467
8468fn default_cost_frequency() -> String {
8469 "quarterly".to_string()
8470}
8471
8472fn default_yield_rate() -> f64 {
8473 0.97
8474}
8475
8476fn default_scrap_threshold() -> f64 {
8477 0.03
8478}
8479
8480impl Default for ManufacturingConfig {
8481 fn default() -> Self {
8482 Self {
8483 enabled: false,
8484 bom_depth: default_bom_depth(),
8485 just_in_time: false,
8486 production_order_types: default_production_order_types(),
8487 quality_framework: Some("ISO_9001".to_string()),
8488 supplier_tiers: default_supplier_tiers(),
8489 standard_cost_frequency: default_cost_frequency(),
8490 target_yield_rate: default_yield_rate(),
8491 scrap_alert_threshold: default_scrap_threshold(),
8492 anomaly_rates: ManufacturingAnomalyRates::default(),
8493 }
8494 }
8495}
8496
8497#[derive(Debug, Clone, Serialize, Deserialize)]
8499pub struct ManufacturingAnomalyRates {
8500 #[serde(default = "default_mfg_yield_rate")]
8502 pub yield_manipulation: f64,
8503
8504 #[serde(default = "default_mfg_labor_rate")]
8506 pub labor_misallocation: f64,
8507
8508 #[serde(default = "default_mfg_phantom_rate")]
8510 pub phantom_production: f64,
8511
8512 #[serde(default = "default_mfg_cost_rate")]
8514 pub standard_cost_manipulation: f64,
8515
8516 #[serde(default = "default_mfg_inventory_rate")]
8518 pub inventory_fraud: f64,
8519}
8520
8521fn default_mfg_yield_rate() -> f64 {
8522 0.015
8523}
8524
8525fn default_mfg_labor_rate() -> f64 {
8526 0.02
8527}
8528
8529fn default_mfg_phantom_rate() -> f64 {
8530 0.005
8531}
8532
8533fn default_mfg_cost_rate() -> f64 {
8534 0.01
8535}
8536
8537fn default_mfg_inventory_rate() -> f64 {
8538 0.008
8539}
8540
8541impl Default for ManufacturingAnomalyRates {
8542 fn default() -> Self {
8543 Self {
8544 yield_manipulation: default_mfg_yield_rate(),
8545 labor_misallocation: default_mfg_labor_rate(),
8546 phantom_production: default_mfg_phantom_rate(),
8547 standard_cost_manipulation: default_mfg_cost_rate(),
8548 inventory_fraud: default_mfg_inventory_rate(),
8549 }
8550 }
8551}
8552
8553#[derive(Debug, Clone, Serialize, Deserialize)]
8555pub struct RetailConfig {
8556 #[serde(default)]
8558 pub enabled: bool,
8559
8560 #[serde(default)]
8562 pub store_types: RetailStoreTypeConfig,
8563
8564 #[serde(default = "default_retail_daily_txns")]
8566 pub avg_daily_transactions: u32,
8567
8568 #[serde(default = "default_true")]
8570 pub loss_prevention: bool,
8571
8572 #[serde(default = "default_shrinkage_rate")]
8574 pub shrinkage_rate: f64,
8575
8576 #[serde(default)]
8578 pub anomaly_rates: RetailAnomalyRates,
8579}
8580
8581fn default_retail_daily_txns() -> u32 {
8582 500
8583}
8584
8585fn default_shrinkage_rate() -> f64 {
8586 0.015
8587}
8588
8589impl Default for RetailConfig {
8590 fn default() -> Self {
8591 Self {
8592 enabled: false,
8593 store_types: RetailStoreTypeConfig::default(),
8594 avg_daily_transactions: default_retail_daily_txns(),
8595 loss_prevention: true,
8596 shrinkage_rate: default_shrinkage_rate(),
8597 anomaly_rates: RetailAnomalyRates::default(),
8598 }
8599 }
8600}
8601
8602#[derive(Debug, Clone, Serialize, Deserialize)]
8604pub struct RetailStoreTypeConfig {
8605 #[serde(default = "default_flagship_pct")]
8607 pub flagship: f64,
8608
8609 #[serde(default = "default_regional_pct")]
8611 pub regional: f64,
8612
8613 #[serde(default = "default_outlet_pct")]
8615 pub outlet: f64,
8616
8617 #[serde(default = "default_ecommerce_pct")]
8619 pub ecommerce: f64,
8620}
8621
8622fn default_flagship_pct() -> f64 {
8623 0.10
8624}
8625
8626fn default_regional_pct() -> f64 {
8627 0.50
8628}
8629
8630fn default_outlet_pct() -> f64 {
8631 0.25
8632}
8633
8634fn default_ecommerce_pct() -> f64 {
8635 0.15
8636}
8637
8638impl Default for RetailStoreTypeConfig {
8639 fn default() -> Self {
8640 Self {
8641 flagship: default_flagship_pct(),
8642 regional: default_regional_pct(),
8643 outlet: default_outlet_pct(),
8644 ecommerce: default_ecommerce_pct(),
8645 }
8646 }
8647}
8648
8649#[derive(Debug, Clone, Serialize, Deserialize)]
8651pub struct RetailAnomalyRates {
8652 #[serde(default = "default_sweethearting_rate")]
8654 pub sweethearting: f64,
8655
8656 #[serde(default = "default_skimming_rate")]
8658 pub skimming: f64,
8659
8660 #[serde(default = "default_refund_fraud_rate")]
8662 pub refund_fraud: f64,
8663
8664 #[serde(default = "default_void_abuse_rate")]
8666 pub void_abuse: f64,
8667
8668 #[serde(default = "default_gift_card_rate")]
8670 pub gift_card_fraud: f64,
8671
8672 #[serde(default = "default_retail_kickback_rate")]
8674 pub vendor_kickback: f64,
8675}
8676
8677fn default_sweethearting_rate() -> f64 {
8678 0.02
8679}
8680
8681fn default_skimming_rate() -> f64 {
8682 0.005
8683}
8684
8685fn default_refund_fraud_rate() -> f64 {
8686 0.015
8687}
8688
8689fn default_void_abuse_rate() -> f64 {
8690 0.01
8691}
8692
8693fn default_gift_card_rate() -> f64 {
8694 0.008
8695}
8696
8697fn default_retail_kickback_rate() -> f64 {
8698 0.003
8699}
8700
8701impl Default for RetailAnomalyRates {
8702 fn default() -> Self {
8703 Self {
8704 sweethearting: default_sweethearting_rate(),
8705 skimming: default_skimming_rate(),
8706 refund_fraud: default_refund_fraud_rate(),
8707 void_abuse: default_void_abuse_rate(),
8708 gift_card_fraud: default_gift_card_rate(),
8709 vendor_kickback: default_retail_kickback_rate(),
8710 }
8711 }
8712}
8713
8714#[derive(Debug, Clone, Serialize, Deserialize)]
8716pub struct HealthcareConfig {
8717 #[serde(default)]
8719 pub enabled: bool,
8720
8721 #[serde(default = "default_facility_type")]
8723 pub facility_type: String,
8724
8725 #[serde(default)]
8727 pub payer_mix: HealthcarePayerMix,
8728
8729 #[serde(default)]
8731 pub coding_systems: HealthcareCodingSystems,
8732
8733 #[serde(default)]
8735 pub compliance: HealthcareComplianceConfig,
8736
8737 #[serde(default = "default_daily_encounters")]
8739 pub avg_daily_encounters: u32,
8740
8741 #[serde(default = "default_charges_per_encounter")]
8743 pub avg_charges_per_encounter: u32,
8744
8745 #[serde(default = "default_hc_denial_rate")]
8747 pub denial_rate: f64,
8748
8749 #[serde(default = "default_hc_bad_debt_rate")]
8751 pub bad_debt_rate: f64,
8752
8753 #[serde(default = "default_hc_charity_care_rate")]
8755 pub charity_care_rate: f64,
8756
8757 #[serde(default)]
8759 pub anomaly_rates: HealthcareAnomalyRates,
8760}
8761
8762fn default_facility_type() -> String {
8763 "hospital".to_string()
8764}
8765
8766fn default_daily_encounters() -> u32 {
8767 150
8768}
8769
8770fn default_charges_per_encounter() -> u32 {
8771 8
8772}
8773
8774fn default_hc_denial_rate() -> f64 {
8775 0.05
8776}
8777
8778fn default_hc_bad_debt_rate() -> f64 {
8779 0.03
8780}
8781
8782fn default_hc_charity_care_rate() -> f64 {
8783 0.02
8784}
8785
8786impl Default for HealthcareConfig {
8787 fn default() -> Self {
8788 Self {
8789 enabled: false,
8790 facility_type: default_facility_type(),
8791 payer_mix: HealthcarePayerMix::default(),
8792 coding_systems: HealthcareCodingSystems::default(),
8793 compliance: HealthcareComplianceConfig::default(),
8794 avg_daily_encounters: default_daily_encounters(),
8795 avg_charges_per_encounter: default_charges_per_encounter(),
8796 denial_rate: default_hc_denial_rate(),
8797 bad_debt_rate: default_hc_bad_debt_rate(),
8798 charity_care_rate: default_hc_charity_care_rate(),
8799 anomaly_rates: HealthcareAnomalyRates::default(),
8800 }
8801 }
8802}
8803
8804#[derive(Debug, Clone, Serialize, Deserialize)]
8806pub struct HealthcarePayerMix {
8807 #[serde(default = "default_medicare_pct")]
8809 pub medicare: f64,
8810
8811 #[serde(default = "default_medicaid_pct")]
8813 pub medicaid: f64,
8814
8815 #[serde(default = "default_commercial_pct")]
8817 pub commercial: f64,
8818
8819 #[serde(default = "default_self_pay_pct")]
8821 pub self_pay: f64,
8822}
8823
8824fn default_medicare_pct() -> f64 {
8825 0.40
8826}
8827
8828fn default_medicaid_pct() -> f64 {
8829 0.20
8830}
8831
8832fn default_commercial_pct() -> f64 {
8833 0.30
8834}
8835
8836fn default_self_pay_pct() -> f64 {
8837 0.10
8838}
8839
8840impl Default for HealthcarePayerMix {
8841 fn default() -> Self {
8842 Self {
8843 medicare: default_medicare_pct(),
8844 medicaid: default_medicaid_pct(),
8845 commercial: default_commercial_pct(),
8846 self_pay: default_self_pay_pct(),
8847 }
8848 }
8849}
8850
8851#[derive(Debug, Clone, Serialize, Deserialize)]
8853pub struct HealthcareCodingSystems {
8854 #[serde(default = "default_true")]
8856 pub icd10: bool,
8857
8858 #[serde(default = "default_true")]
8860 pub cpt: bool,
8861
8862 #[serde(default = "default_true")]
8864 pub drg: bool,
8865
8866 #[serde(default = "default_true")]
8868 pub hcpcs: bool,
8869
8870 #[serde(default = "default_true")]
8872 pub revenue_codes: bool,
8873}
8874
8875impl Default for HealthcareCodingSystems {
8876 fn default() -> Self {
8877 Self {
8878 icd10: true,
8879 cpt: true,
8880 drg: true,
8881 hcpcs: true,
8882 revenue_codes: true,
8883 }
8884 }
8885}
8886
8887#[derive(Debug, Clone, Serialize, Deserialize)]
8889pub struct HealthcareComplianceConfig {
8890 #[serde(default = "default_true")]
8892 pub hipaa: bool,
8893
8894 #[serde(default = "default_true")]
8896 pub stark_law: bool,
8897
8898 #[serde(default = "default_true")]
8900 pub anti_kickback: bool,
8901
8902 #[serde(default = "default_true")]
8904 pub false_claims_act: bool,
8905
8906 #[serde(default = "default_true")]
8908 pub emtala: bool,
8909}
8910
8911impl Default for HealthcareComplianceConfig {
8912 fn default() -> Self {
8913 Self {
8914 hipaa: true,
8915 stark_law: true,
8916 anti_kickback: true,
8917 false_claims_act: true,
8918 emtala: true,
8919 }
8920 }
8921}
8922
8923#[derive(Debug, Clone, Serialize, Deserialize)]
8925pub struct HealthcareAnomalyRates {
8926 #[serde(default = "default_upcoding_rate")]
8928 pub upcoding: f64,
8929
8930 #[serde(default = "default_unbundling_rate")]
8932 pub unbundling: f64,
8933
8934 #[serde(default = "default_phantom_billing_rate")]
8936 pub phantom_billing: f64,
8937
8938 #[serde(default = "default_healthcare_kickback_rate")]
8940 pub kickbacks: f64,
8941
8942 #[serde(default = "default_duplicate_billing_rate")]
8944 pub duplicate_billing: f64,
8945
8946 #[serde(default = "default_med_necessity_rate")]
8948 pub medical_necessity_abuse: f64,
8949}
8950
8951fn default_upcoding_rate() -> f64 {
8952 0.02
8953}
8954
8955fn default_unbundling_rate() -> f64 {
8956 0.015
8957}
8958
8959fn default_phantom_billing_rate() -> f64 {
8960 0.005
8961}
8962
8963fn default_healthcare_kickback_rate() -> f64 {
8964 0.003
8965}
8966
8967fn default_duplicate_billing_rate() -> f64 {
8968 0.008
8969}
8970
8971fn default_med_necessity_rate() -> f64 {
8972 0.01
8973}
8974
8975impl Default for HealthcareAnomalyRates {
8976 fn default() -> Self {
8977 Self {
8978 upcoding: default_upcoding_rate(),
8979 unbundling: default_unbundling_rate(),
8980 phantom_billing: default_phantom_billing_rate(),
8981 kickbacks: default_healthcare_kickback_rate(),
8982 duplicate_billing: default_duplicate_billing_rate(),
8983 medical_necessity_abuse: default_med_necessity_rate(),
8984 }
8985 }
8986}
8987
8988#[derive(Debug, Clone, Serialize, Deserialize)]
8990pub struct TechnologyConfig {
8991 #[serde(default)]
8993 pub enabled: bool,
8994
8995 #[serde(default = "default_revenue_model")]
8997 pub revenue_model: String,
8998
8999 #[serde(default = "default_subscription_pct")]
9001 pub subscription_revenue_pct: f64,
9002
9003 #[serde(default = "default_license_pct")]
9005 pub license_revenue_pct: f64,
9006
9007 #[serde(default = "default_services_pct")]
9009 pub services_revenue_pct: f64,
9010
9011 #[serde(default)]
9013 pub rd_capitalization: RdCapitalizationConfig,
9014
9015 #[serde(default)]
9017 pub anomaly_rates: TechnologyAnomalyRates,
9018}
9019
9020fn default_revenue_model() -> String {
9021 "saas".to_string()
9022}
9023
9024fn default_subscription_pct() -> f64 {
9025 0.60
9026}
9027
9028fn default_license_pct() -> f64 {
9029 0.25
9030}
9031
9032fn default_services_pct() -> f64 {
9033 0.15
9034}
9035
9036impl Default for TechnologyConfig {
9037 fn default() -> Self {
9038 Self {
9039 enabled: false,
9040 revenue_model: default_revenue_model(),
9041 subscription_revenue_pct: default_subscription_pct(),
9042 license_revenue_pct: default_license_pct(),
9043 services_revenue_pct: default_services_pct(),
9044 rd_capitalization: RdCapitalizationConfig::default(),
9045 anomaly_rates: TechnologyAnomalyRates::default(),
9046 }
9047 }
9048}
9049
9050#[derive(Debug, Clone, Serialize, Deserialize)]
9052pub struct RdCapitalizationConfig {
9053 #[serde(default = "default_true")]
9055 pub enabled: bool,
9056
9057 #[serde(default = "default_cap_rate")]
9059 pub capitalization_rate: f64,
9060
9061 #[serde(default = "default_useful_life")]
9063 pub useful_life_years: u32,
9064}
9065
9066fn default_cap_rate() -> f64 {
9067 0.30
9068}
9069
9070fn default_useful_life() -> u32 {
9071 3
9072}
9073
9074impl Default for RdCapitalizationConfig {
9075 fn default() -> Self {
9076 Self {
9077 enabled: true,
9078 capitalization_rate: default_cap_rate(),
9079 useful_life_years: default_useful_life(),
9080 }
9081 }
9082}
9083
9084#[derive(Debug, Clone, Serialize, Deserialize)]
9086pub struct TechnologyAnomalyRates {
9087 #[serde(default = "default_premature_rev_rate")]
9089 pub premature_revenue: f64,
9090
9091 #[serde(default = "default_side_letter_rate")]
9093 pub side_letter_abuse: f64,
9094
9095 #[serde(default = "default_channel_stuffing_rate")]
9097 pub channel_stuffing: f64,
9098
9099 #[serde(default = "default_improper_cap_rate")]
9101 pub improper_capitalization: f64,
9102}
9103
9104fn default_premature_rev_rate() -> f64 {
9105 0.015
9106}
9107
9108fn default_side_letter_rate() -> f64 {
9109 0.008
9110}
9111
9112fn default_channel_stuffing_rate() -> f64 {
9113 0.01
9114}
9115
9116fn default_improper_cap_rate() -> f64 {
9117 0.012
9118}
9119
9120impl Default for TechnologyAnomalyRates {
9121 fn default() -> Self {
9122 Self {
9123 premature_revenue: default_premature_rev_rate(),
9124 side_letter_abuse: default_side_letter_rate(),
9125 channel_stuffing: default_channel_stuffing_rate(),
9126 improper_capitalization: default_improper_cap_rate(),
9127 }
9128 }
9129}
9130
9131#[derive(Debug, Clone, Serialize, Deserialize)]
9133pub struct FinancialServicesConfig {
9134 #[serde(default)]
9136 pub enabled: bool,
9137
9138 #[serde(default = "default_fi_type")]
9140 pub institution_type: String,
9141
9142 #[serde(default = "default_fi_regulatory")]
9144 pub regulatory_framework: String,
9145
9146 #[serde(default)]
9148 pub anomaly_rates: FinancialServicesAnomalyRates,
9149}
9150
9151fn default_fi_type() -> String {
9152 "commercial_bank".to_string()
9153}
9154
9155fn default_fi_regulatory() -> String {
9156 "us_banking".to_string()
9157}
9158
9159impl Default for FinancialServicesConfig {
9160 fn default() -> Self {
9161 Self {
9162 enabled: false,
9163 institution_type: default_fi_type(),
9164 regulatory_framework: default_fi_regulatory(),
9165 anomaly_rates: FinancialServicesAnomalyRates::default(),
9166 }
9167 }
9168}
9169
9170#[derive(Debug, Clone, Serialize, Deserialize)]
9172pub struct FinancialServicesAnomalyRates {
9173 #[serde(default = "default_loan_fraud_rate")]
9175 pub loan_fraud: f64,
9176
9177 #[serde(default = "default_trading_fraud_rate")]
9179 pub trading_fraud: f64,
9180
9181 #[serde(default = "default_insurance_fraud_rate")]
9183 pub insurance_fraud: f64,
9184
9185 #[serde(default = "default_account_manip_rate")]
9187 pub account_manipulation: f64,
9188}
9189
9190fn default_loan_fraud_rate() -> f64 {
9191 0.01
9192}
9193
9194fn default_trading_fraud_rate() -> f64 {
9195 0.008
9196}
9197
9198fn default_insurance_fraud_rate() -> f64 {
9199 0.012
9200}
9201
9202fn default_account_manip_rate() -> f64 {
9203 0.005
9204}
9205
9206impl Default for FinancialServicesAnomalyRates {
9207 fn default() -> Self {
9208 Self {
9209 loan_fraud: default_loan_fraud_rate(),
9210 trading_fraud: default_trading_fraud_rate(),
9211 insurance_fraud: default_insurance_fraud_rate(),
9212 account_manipulation: default_account_manip_rate(),
9213 }
9214 }
9215}
9216
9217#[derive(Debug, Clone, Serialize, Deserialize)]
9219pub struct ProfessionalServicesConfig {
9220 #[serde(default)]
9222 pub enabled: bool,
9223
9224 #[serde(default = "default_firm_type")]
9226 pub firm_type: String,
9227
9228 #[serde(default = "default_billing_model")]
9230 pub billing_model: String,
9231
9232 #[serde(default = "default_hourly_rate")]
9234 pub avg_hourly_rate: f64,
9235
9236 #[serde(default)]
9238 pub trust_accounting: TrustAccountingConfig,
9239
9240 #[serde(default)]
9242 pub anomaly_rates: ProfessionalServicesAnomalyRates,
9243}
9244
9245fn default_firm_type() -> String {
9246 "consulting".to_string()
9247}
9248
9249fn default_billing_model() -> String {
9250 "time_and_materials".to_string()
9251}
9252
9253fn default_hourly_rate() -> f64 {
9254 250.0
9255}
9256
9257impl Default for ProfessionalServicesConfig {
9258 fn default() -> Self {
9259 Self {
9260 enabled: false,
9261 firm_type: default_firm_type(),
9262 billing_model: default_billing_model(),
9263 avg_hourly_rate: default_hourly_rate(),
9264 trust_accounting: TrustAccountingConfig::default(),
9265 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9266 }
9267 }
9268}
9269
9270#[derive(Debug, Clone, Serialize, Deserialize)]
9272pub struct TrustAccountingConfig {
9273 #[serde(default)]
9275 pub enabled: bool,
9276
9277 #[serde(default = "default_true")]
9279 pub require_three_way_reconciliation: bool,
9280}
9281
9282impl Default for TrustAccountingConfig {
9283 fn default() -> Self {
9284 Self {
9285 enabled: false,
9286 require_three_way_reconciliation: true,
9287 }
9288 }
9289}
9290
9291#[derive(Debug, Clone, Serialize, Deserialize)]
9293pub struct ProfessionalServicesAnomalyRates {
9294 #[serde(default = "default_time_fraud_rate")]
9296 pub time_billing_fraud: f64,
9297
9298 #[serde(default = "default_expense_fraud_rate")]
9300 pub expense_fraud: f64,
9301
9302 #[serde(default = "default_trust_misappropriation_rate")]
9304 pub trust_misappropriation: f64,
9305}
9306
9307fn default_time_fraud_rate() -> f64 {
9308 0.02
9309}
9310
9311fn default_expense_fraud_rate() -> f64 {
9312 0.015
9313}
9314
9315fn default_trust_misappropriation_rate() -> f64 {
9316 0.003
9317}
9318
9319impl Default for ProfessionalServicesAnomalyRates {
9320 fn default() -> Self {
9321 Self {
9322 time_billing_fraud: default_time_fraud_rate(),
9323 expense_fraud: default_expense_fraud_rate(),
9324 trust_misappropriation: default_trust_misappropriation_rate(),
9325 }
9326 }
9327}
9328
9329#[cfg(test)]
9330mod tests {
9331 use super::*;
9332 use crate::presets::demo_preset;
9333
9334 #[test]
9339 fn test_config_yaml_roundtrip() {
9340 let config = demo_preset();
9341 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9342 let deserialized: GeneratorConfig =
9343 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9344
9345 assert_eq!(
9346 config.global.period_months,
9347 deserialized.global.period_months
9348 );
9349 assert_eq!(config.global.industry, deserialized.global.industry);
9350 assert_eq!(config.companies.len(), deserialized.companies.len());
9351 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9352 }
9353
9354 #[test]
9355 fn test_config_json_roundtrip() {
9356 let mut config = demo_preset();
9358 config.master_data.employees.approval_limits.executive = 1e12;
9360
9361 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9362 let deserialized: GeneratorConfig =
9363 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9364
9365 assert_eq!(
9366 config.global.period_months,
9367 deserialized.global.period_months
9368 );
9369 assert_eq!(config.global.industry, deserialized.global.industry);
9370 assert_eq!(config.companies.len(), deserialized.companies.len());
9371 }
9372
9373 #[test]
9374 fn test_transaction_volume_serialization() {
9375 let volumes = vec![
9377 (TransactionVolume::TenK, "ten_k"),
9378 (TransactionVolume::HundredK, "hundred_k"),
9379 (TransactionVolume::OneM, "one_m"),
9380 (TransactionVolume::TenM, "ten_m"),
9381 (TransactionVolume::HundredM, "hundred_m"),
9382 ];
9383
9384 for (volume, expected_key) in volumes {
9385 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9386 assert!(
9387 json.contains(expected_key),
9388 "Expected {} in JSON: {}",
9389 expected_key,
9390 json
9391 );
9392 }
9393 }
9394
9395 #[test]
9396 fn test_transaction_volume_custom_serialization() {
9397 let volume = TransactionVolume::Custom(12345);
9398 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9399 let deserialized: TransactionVolume =
9400 serde_json::from_str(&json).expect("Failed to deserialize");
9401 assert_eq!(deserialized.count(), 12345);
9402 }
9403
9404 #[test]
9405 fn test_output_mode_serialization() {
9406 let modes = vec![
9407 OutputMode::Streaming,
9408 OutputMode::FlatFile,
9409 OutputMode::Both,
9410 ];
9411
9412 for mode in modes {
9413 let json = serde_json::to_string(&mode).expect("Failed to serialize");
9414 let deserialized: OutputMode =
9415 serde_json::from_str(&json).expect("Failed to deserialize");
9416 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9417 }
9418 }
9419
9420 #[test]
9421 fn test_file_format_serialization() {
9422 let formats = vec![
9423 FileFormat::Csv,
9424 FileFormat::Parquet,
9425 FileFormat::Json,
9426 FileFormat::JsonLines,
9427 ];
9428
9429 for format in formats {
9430 let json = serde_json::to_string(&format).expect("Failed to serialize");
9431 let deserialized: FileFormat =
9432 serde_json::from_str(&json).expect("Failed to deserialize");
9433 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
9434 }
9435 }
9436
9437 #[test]
9438 fn test_compression_algorithm_serialization() {
9439 let algos = vec![
9440 CompressionAlgorithm::Gzip,
9441 CompressionAlgorithm::Zstd,
9442 CompressionAlgorithm::Lz4,
9443 CompressionAlgorithm::Snappy,
9444 ];
9445
9446 for algo in algos {
9447 let json = serde_json::to_string(&algo).expect("Failed to serialize");
9448 let deserialized: CompressionAlgorithm =
9449 serde_json::from_str(&json).expect("Failed to deserialize");
9450 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
9451 }
9452 }
9453
9454 #[test]
9455 fn test_transfer_pricing_method_serialization() {
9456 let methods = vec![
9457 TransferPricingMethod::CostPlus,
9458 TransferPricingMethod::ComparableUncontrolled,
9459 TransferPricingMethod::ResalePrice,
9460 TransferPricingMethod::TransactionalNetMargin,
9461 TransferPricingMethod::ProfitSplit,
9462 ];
9463
9464 for method in methods {
9465 let json = serde_json::to_string(&method).expect("Failed to serialize");
9466 let deserialized: TransferPricingMethod =
9467 serde_json::from_str(&json).expect("Failed to deserialize");
9468 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
9469 }
9470 }
9471
9472 #[test]
9473 fn test_benford_exemption_serialization() {
9474 let exemptions = vec![
9475 BenfordExemption::Recurring,
9476 BenfordExemption::Payroll,
9477 BenfordExemption::FixedFees,
9478 BenfordExemption::RoundAmounts,
9479 ];
9480
9481 for exemption in exemptions {
9482 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
9483 let deserialized: BenfordExemption =
9484 serde_json::from_str(&json).expect("Failed to deserialize");
9485 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
9486 }
9487 }
9488
9489 #[test]
9494 fn test_global_config_defaults() {
9495 let yaml = r#"
9496 industry: manufacturing
9497 start_date: "2024-01-01"
9498 period_months: 6
9499 "#;
9500 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9501 assert_eq!(config.group_currency, "USD");
9502 assert!(config.parallel);
9503 assert_eq!(config.worker_threads, 0);
9504 assert_eq!(config.memory_limit_mb, 0);
9505 }
9506
9507 #[test]
9508 fn test_fraud_config_defaults() {
9509 let config = FraudConfig::default();
9510 assert!(!config.enabled);
9511 assert_eq!(config.fraud_rate, 0.005);
9512 assert!(!config.clustering_enabled);
9513 }
9514
9515 #[test]
9516 fn test_internal_controls_config_defaults() {
9517 let config = InternalControlsConfig::default();
9518 assert!(!config.enabled);
9519 assert_eq!(config.exception_rate, 0.02);
9520 assert_eq!(config.sod_violation_rate, 0.01);
9521 assert!(config.export_control_master_data);
9522 assert_eq!(config.sox_materiality_threshold, 10000.0);
9523 assert!(config.coso_enabled);
9525 assert!(!config.include_entity_level_controls);
9526 assert_eq!(config.target_maturity_level, "mixed");
9527 }
9528
9529 #[test]
9530 fn test_output_config_defaults() {
9531 let config = OutputConfig::default();
9532 assert!(matches!(config.mode, OutputMode::FlatFile));
9533 assert_eq!(config.formats, vec![FileFormat::Parquet]);
9534 assert!(config.compression.enabled);
9535 assert!(matches!(
9536 config.compression.algorithm,
9537 CompressionAlgorithm::Zstd
9538 ));
9539 assert!(config.include_acdoca);
9540 assert!(!config.include_bseg);
9541 assert!(config.partition_by_period);
9542 assert!(!config.partition_by_company);
9543 }
9544
9545 #[test]
9546 fn test_approval_config_defaults() {
9547 let config = ApprovalConfig::default();
9548 assert!(!config.enabled);
9549 assert_eq!(config.auto_approve_threshold, 1000.0);
9550 assert_eq!(config.rejection_rate, 0.02);
9551 assert_eq!(config.revision_rate, 0.05);
9552 assert_eq!(config.average_approval_delay_hours, 4.0);
9553 assert_eq!(config.thresholds.len(), 4);
9554 }
9555
9556 #[test]
9557 fn test_p2p_flow_config_defaults() {
9558 let config = P2PFlowConfig::default();
9559 assert!(config.enabled);
9560 assert_eq!(config.three_way_match_rate, 0.95);
9561 assert_eq!(config.partial_delivery_rate, 0.15);
9562 assert_eq!(config.average_po_to_gr_days, 14);
9563 }
9564
9565 #[test]
9566 fn test_o2c_flow_config_defaults() {
9567 let config = O2CFlowConfig::default();
9568 assert!(config.enabled);
9569 assert_eq!(config.credit_check_failure_rate, 0.02);
9570 assert_eq!(config.return_rate, 0.03);
9571 assert_eq!(config.bad_debt_rate, 0.01);
9572 }
9573
9574 #[test]
9575 fn test_balance_config_defaults() {
9576 let config = BalanceConfig::default();
9577 assert!(!config.generate_opening_balances);
9578 assert!(config.generate_trial_balances);
9579 assert_eq!(config.target_gross_margin, 0.35);
9580 assert!(config.validate_balance_equation);
9581 assert!(config.reconcile_subledgers);
9582 }
9583
9584 #[test]
9589 fn test_partial_config_with_defaults() {
9590 let yaml = r#"
9592 global:
9593 industry: manufacturing
9594 start_date: "2024-01-01"
9595 period_months: 3
9596 companies:
9597 - code: "TEST"
9598 name: "Test Company"
9599 currency: "USD"
9600 country: "US"
9601 annual_transaction_volume: ten_k
9602 chart_of_accounts:
9603 complexity: small
9604 output:
9605 output_directory: "./output"
9606 "#;
9607
9608 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9609 assert_eq!(config.global.period_months, 3);
9610 assert_eq!(config.companies.len(), 1);
9611 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
9614
9615 #[test]
9616 fn test_config_with_fraud_enabled() {
9617 let yaml = r#"
9618 global:
9619 industry: retail
9620 start_date: "2024-01-01"
9621 period_months: 12
9622 companies:
9623 - code: "RETAIL"
9624 name: "Retail Co"
9625 currency: "USD"
9626 country: "US"
9627 annual_transaction_volume: hundred_k
9628 chart_of_accounts:
9629 complexity: medium
9630 output:
9631 output_directory: "./output"
9632 fraud:
9633 enabled: true
9634 fraud_rate: 0.05
9635 clustering_enabled: true
9636 "#;
9637
9638 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9639 assert!(config.fraud.enabled);
9640 assert_eq!(config.fraud.fraud_rate, 0.05);
9641 assert!(config.fraud.clustering_enabled);
9642 }
9643
9644 #[test]
9645 fn test_config_with_multiple_companies() {
9646 let yaml = r#"
9647 global:
9648 industry: manufacturing
9649 start_date: "2024-01-01"
9650 period_months: 6
9651 companies:
9652 - code: "HQ"
9653 name: "Headquarters"
9654 currency: "USD"
9655 country: "US"
9656 annual_transaction_volume: hundred_k
9657 volume_weight: 1.0
9658 - code: "EU"
9659 name: "European Subsidiary"
9660 currency: "EUR"
9661 country: "DE"
9662 annual_transaction_volume: hundred_k
9663 volume_weight: 0.5
9664 - code: "APAC"
9665 name: "Asia Pacific"
9666 currency: "JPY"
9667 country: "JP"
9668 annual_transaction_volume: ten_k
9669 volume_weight: 0.3
9670 chart_of_accounts:
9671 complexity: large
9672 output:
9673 output_directory: "./output"
9674 "#;
9675
9676 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9677 assert_eq!(config.companies.len(), 3);
9678 assert_eq!(config.companies[0].code, "HQ");
9679 assert_eq!(config.companies[1].currency, "EUR");
9680 assert_eq!(config.companies[2].volume_weight, 0.3);
9681 }
9682
9683 #[test]
9684 fn test_intercompany_config() {
9685 let yaml = r#"
9686 enabled: true
9687 ic_transaction_rate: 0.20
9688 transfer_pricing_method: cost_plus
9689 markup_percent: 0.08
9690 generate_matched_pairs: true
9691 generate_eliminations: true
9692 "#;
9693
9694 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9695 assert!(config.enabled);
9696 assert_eq!(config.ic_transaction_rate, 0.20);
9697 assert!(matches!(
9698 config.transfer_pricing_method,
9699 TransferPricingMethod::CostPlus
9700 ));
9701 assert_eq!(config.markup_percent, 0.08);
9702 assert!(config.generate_eliminations);
9703 }
9704
9705 #[test]
9710 fn test_company_config_defaults() {
9711 let yaml = r#"
9712 code: "TEST"
9713 name: "Test Company"
9714 currency: "USD"
9715 country: "US"
9716 annual_transaction_volume: ten_k
9717 "#;
9718
9719 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9720 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
9723
9724 #[test]
9729 fn test_coa_config_defaults() {
9730 let yaml = r#"
9731 complexity: medium
9732 "#;
9733
9734 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9735 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
9737 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
9740
9741 #[test]
9746 fn test_accounting_standards_config_defaults() {
9747 let config = AccountingStandardsConfig::default();
9748 assert!(!config.enabled);
9749 assert!(matches!(
9750 config.framework,
9751 AccountingFrameworkConfig::UsGaap
9752 ));
9753 assert!(!config.revenue_recognition.enabled);
9754 assert!(!config.leases.enabled);
9755 assert!(!config.fair_value.enabled);
9756 assert!(!config.impairment.enabled);
9757 assert!(!config.generate_differences);
9758 }
9759
9760 #[test]
9761 fn test_accounting_standards_config_yaml() {
9762 let yaml = r#"
9763 enabled: true
9764 framework: ifrs
9765 revenue_recognition:
9766 enabled: true
9767 generate_contracts: true
9768 avg_obligations_per_contract: 2.5
9769 variable_consideration_rate: 0.20
9770 over_time_recognition_rate: 0.35
9771 contract_count: 150
9772 leases:
9773 enabled: true
9774 lease_count: 75
9775 finance_lease_percent: 0.25
9776 avg_lease_term_months: 48
9777 generate_differences: true
9778 "#;
9779
9780 let config: AccountingStandardsConfig =
9781 serde_yaml::from_str(yaml).expect("Failed to parse");
9782 assert!(config.enabled);
9783 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
9784 assert!(config.revenue_recognition.enabled);
9785 assert_eq!(config.revenue_recognition.contract_count, 150);
9786 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
9787 assert!(config.leases.enabled);
9788 assert_eq!(config.leases.lease_count, 75);
9789 assert_eq!(config.leases.finance_lease_percent, 0.25);
9790 assert!(config.generate_differences);
9791 }
9792
9793 #[test]
9794 fn test_accounting_framework_serialization() {
9795 let frameworks = [
9796 AccountingFrameworkConfig::UsGaap,
9797 AccountingFrameworkConfig::Ifrs,
9798 AccountingFrameworkConfig::DualReporting,
9799 ];
9800
9801 for framework in frameworks {
9802 let json = serde_json::to_string(&framework).expect("Failed to serialize");
9803 let deserialized: AccountingFrameworkConfig =
9804 serde_json::from_str(&json).expect("Failed to deserialize");
9805 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
9806 }
9807 }
9808
9809 #[test]
9810 fn test_revenue_recognition_config_defaults() {
9811 let config = RevenueRecognitionConfig::default();
9812 assert!(!config.enabled);
9813 assert!(config.generate_contracts);
9814 assert_eq!(config.avg_obligations_per_contract, 2.0);
9815 assert_eq!(config.variable_consideration_rate, 0.15);
9816 assert_eq!(config.over_time_recognition_rate, 0.30);
9817 assert_eq!(config.contract_count, 100);
9818 }
9819
9820 #[test]
9821 fn test_lease_accounting_config_defaults() {
9822 let config = LeaseAccountingConfig::default();
9823 assert!(!config.enabled);
9824 assert_eq!(config.lease_count, 50);
9825 assert_eq!(config.finance_lease_percent, 0.30);
9826 assert_eq!(config.avg_lease_term_months, 60);
9827 assert!(config.generate_amortization);
9828 assert_eq!(config.real_estate_percent, 0.40);
9829 }
9830
9831 #[test]
9832 fn test_fair_value_config_defaults() {
9833 let config = FairValueConfig::default();
9834 assert!(!config.enabled);
9835 assert_eq!(config.measurement_count, 25);
9836 assert_eq!(config.level1_percent, 0.40);
9837 assert_eq!(config.level2_percent, 0.35);
9838 assert_eq!(config.level3_percent, 0.25);
9839 assert!(!config.include_sensitivity_analysis);
9840 }
9841
9842 #[test]
9843 fn test_impairment_config_defaults() {
9844 let config = ImpairmentConfig::default();
9845 assert!(!config.enabled);
9846 assert_eq!(config.test_count, 15);
9847 assert_eq!(config.impairment_rate, 0.10);
9848 assert!(config.generate_projections);
9849 assert!(!config.include_goodwill);
9850 }
9851
9852 #[test]
9857 fn test_audit_standards_config_defaults() {
9858 let config = AuditStandardsConfig::default();
9859 assert!(!config.enabled);
9860 assert!(!config.isa_compliance.enabled);
9861 assert!(!config.analytical_procedures.enabled);
9862 assert!(!config.confirmations.enabled);
9863 assert!(!config.opinion.enabled);
9864 assert!(!config.generate_audit_trail);
9865 assert!(!config.sox.enabled);
9866 assert!(!config.pcaob.enabled);
9867 }
9868
9869 #[test]
9870 fn test_audit_standards_config_yaml() {
9871 let yaml = r#"
9872 enabled: true
9873 isa_compliance:
9874 enabled: true
9875 compliance_level: comprehensive
9876 generate_isa_mappings: true
9877 include_pcaob: true
9878 framework: dual
9879 analytical_procedures:
9880 enabled: true
9881 procedures_per_account: 5
9882 variance_probability: 0.25
9883 confirmations:
9884 enabled: true
9885 confirmation_count: 75
9886 positive_response_rate: 0.90
9887 exception_rate: 0.08
9888 opinion:
9889 enabled: true
9890 generate_kam: true
9891 average_kam_count: 4
9892 sox:
9893 enabled: true
9894 generate_302_certifications: true
9895 generate_404_assessments: true
9896 material_weakness_rate: 0.03
9897 pcaob:
9898 enabled: true
9899 is_pcaob_audit: true
9900 include_icfr_opinion: true
9901 generate_audit_trail: true
9902 "#;
9903
9904 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9905 assert!(config.enabled);
9906 assert!(config.isa_compliance.enabled);
9907 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
9908 assert!(config.isa_compliance.include_pcaob);
9909 assert_eq!(config.isa_compliance.framework, "dual");
9910 assert!(config.analytical_procedures.enabled);
9911 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
9912 assert!(config.confirmations.enabled);
9913 assert_eq!(config.confirmations.confirmation_count, 75);
9914 assert!(config.opinion.enabled);
9915 assert_eq!(config.opinion.average_kam_count, 4);
9916 assert!(config.sox.enabled);
9917 assert!(config.sox.generate_302_certifications);
9918 assert_eq!(config.sox.material_weakness_rate, 0.03);
9919 assert!(config.pcaob.enabled);
9920 assert!(config.pcaob.is_pcaob_audit);
9921 assert!(config.pcaob.include_icfr_opinion);
9922 assert!(config.generate_audit_trail);
9923 }
9924
9925 #[test]
9926 fn test_isa_compliance_config_defaults() {
9927 let config = IsaComplianceConfig::default();
9928 assert!(!config.enabled);
9929 assert_eq!(config.compliance_level, "standard");
9930 assert!(config.generate_isa_mappings);
9931 assert!(config.generate_coverage_summary);
9932 assert!(!config.include_pcaob);
9933 assert_eq!(config.framework, "isa");
9934 }
9935
9936 #[test]
9937 fn test_sox_compliance_config_defaults() {
9938 let config = SoxComplianceConfig::default();
9939 assert!(!config.enabled);
9940 assert!(config.generate_302_certifications);
9941 assert!(config.generate_404_assessments);
9942 assert_eq!(config.materiality_threshold, 10000.0);
9943 assert_eq!(config.material_weakness_rate, 0.02);
9944 assert_eq!(config.significant_deficiency_rate, 0.08);
9945 }
9946
9947 #[test]
9948 fn test_pcaob_config_defaults() {
9949 let config = PcaobConfig::default();
9950 assert!(!config.enabled);
9951 assert!(!config.is_pcaob_audit);
9952 assert!(config.generate_cam);
9953 assert!(!config.include_icfr_opinion);
9954 assert!(!config.generate_standard_mappings);
9955 }
9956
9957 #[test]
9958 fn test_config_with_standards_enabled() {
9959 let yaml = r#"
9960 global:
9961 industry: financial_services
9962 start_date: "2024-01-01"
9963 period_months: 12
9964 companies:
9965 - code: "BANK"
9966 name: "Test Bank"
9967 currency: "USD"
9968 country: "US"
9969 annual_transaction_volume: hundred_k
9970 chart_of_accounts:
9971 complexity: large
9972 output:
9973 output_directory: "./output"
9974 accounting_standards:
9975 enabled: true
9976 framework: us_gaap
9977 revenue_recognition:
9978 enabled: true
9979 leases:
9980 enabled: true
9981 audit_standards:
9982 enabled: true
9983 isa_compliance:
9984 enabled: true
9985 sox:
9986 enabled: true
9987 "#;
9988
9989 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9990 assert!(config.accounting_standards.enabled);
9991 assert!(matches!(
9992 config.accounting_standards.framework,
9993 AccountingFrameworkConfig::UsGaap
9994 ));
9995 assert!(config.accounting_standards.revenue_recognition.enabled);
9996 assert!(config.accounting_standards.leases.enabled);
9997 assert!(config.audit_standards.enabled);
9998 assert!(config.audit_standards.isa_compliance.enabled);
9999 assert!(config.audit_standards.sox.enabled);
10000 }
10001
10002 #[test]
10007 fn test_industry_specific_config_defaults() {
10008 let config = IndustrySpecificConfig::default();
10009 assert!(!config.enabled);
10010 assert!(!config.manufacturing.enabled);
10011 assert!(!config.retail.enabled);
10012 assert!(!config.healthcare.enabled);
10013 assert!(!config.technology.enabled);
10014 assert!(!config.financial_services.enabled);
10015 assert!(!config.professional_services.enabled);
10016 }
10017
10018 #[test]
10019 fn test_manufacturing_config_defaults() {
10020 let config = ManufacturingConfig::default();
10021 assert!(!config.enabled);
10022 assert_eq!(config.bom_depth, 4);
10023 assert!(!config.just_in_time);
10024 assert_eq!(config.supplier_tiers, 2);
10025 assert_eq!(config.target_yield_rate, 0.97);
10026 assert_eq!(config.scrap_alert_threshold, 0.03);
10027 }
10028
10029 #[test]
10030 fn test_retail_config_defaults() {
10031 let config = RetailConfig::default();
10032 assert!(!config.enabled);
10033 assert_eq!(config.avg_daily_transactions, 500);
10034 assert!(config.loss_prevention);
10035 assert_eq!(config.shrinkage_rate, 0.015);
10036 }
10037
10038 #[test]
10039 fn test_healthcare_config_defaults() {
10040 let config = HealthcareConfig::default();
10041 assert!(!config.enabled);
10042 assert_eq!(config.facility_type, "hospital");
10043 assert_eq!(config.avg_daily_encounters, 150);
10044 assert!(config.compliance.hipaa);
10045 assert!(config.compliance.stark_law);
10046 assert!(config.coding_systems.icd10);
10047 assert!(config.coding_systems.cpt);
10048 }
10049
10050 #[test]
10051 fn test_technology_config_defaults() {
10052 let config = TechnologyConfig::default();
10053 assert!(!config.enabled);
10054 assert_eq!(config.revenue_model, "saas");
10055 assert_eq!(config.subscription_revenue_pct, 0.60);
10056 assert!(config.rd_capitalization.enabled);
10057 }
10058
10059 #[test]
10060 fn test_config_with_industry_specific() {
10061 let yaml = r#"
10062 global:
10063 industry: healthcare
10064 start_date: "2024-01-01"
10065 period_months: 12
10066 companies:
10067 - code: "HOSP"
10068 name: "Test Hospital"
10069 currency: "USD"
10070 country: "US"
10071 annual_transaction_volume: hundred_k
10072 chart_of_accounts:
10073 complexity: medium
10074 output:
10075 output_directory: "./output"
10076 industry_specific:
10077 enabled: true
10078 healthcare:
10079 enabled: true
10080 facility_type: hospital
10081 payer_mix:
10082 medicare: 0.45
10083 medicaid: 0.15
10084 commercial: 0.35
10085 self_pay: 0.05
10086 coding_systems:
10087 icd10: true
10088 cpt: true
10089 drg: true
10090 compliance:
10091 hipaa: true
10092 stark_law: true
10093 anomaly_rates:
10094 upcoding: 0.03
10095 unbundling: 0.02
10096 "#;
10097
10098 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10099 assert!(config.industry_specific.enabled);
10100 assert!(config.industry_specific.healthcare.enabled);
10101 assert_eq!(
10102 config.industry_specific.healthcare.facility_type,
10103 "hospital"
10104 );
10105 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10106 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10107 assert!(config.industry_specific.healthcare.coding_systems.icd10);
10108 assert!(config.industry_specific.healthcare.compliance.hipaa);
10109 assert_eq!(
10110 config.industry_specific.healthcare.anomaly_rates.upcoding,
10111 0.03
10112 );
10113 }
10114
10115 #[test]
10116 fn test_config_with_manufacturing_specific() {
10117 let yaml = r#"
10118 global:
10119 industry: manufacturing
10120 start_date: "2024-01-01"
10121 period_months: 12
10122 companies:
10123 - code: "MFG"
10124 name: "Test Manufacturing"
10125 currency: "USD"
10126 country: "US"
10127 annual_transaction_volume: hundred_k
10128 chart_of_accounts:
10129 complexity: medium
10130 output:
10131 output_directory: "./output"
10132 industry_specific:
10133 enabled: true
10134 manufacturing:
10135 enabled: true
10136 bom_depth: 5
10137 just_in_time: true
10138 supplier_tiers: 3
10139 target_yield_rate: 0.98
10140 anomaly_rates:
10141 yield_manipulation: 0.02
10142 phantom_production: 0.01
10143 "#;
10144
10145 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10146 assert!(config.industry_specific.enabled);
10147 assert!(config.industry_specific.manufacturing.enabled);
10148 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10149 assert!(config.industry_specific.manufacturing.just_in_time);
10150 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10151 assert_eq!(
10152 config.industry_specific.manufacturing.target_yield_rate,
10153 0.98
10154 );
10155 assert_eq!(
10156 config
10157 .industry_specific
10158 .manufacturing
10159 .anomaly_rates
10160 .yield_manipulation,
10161 0.02
10162 );
10163 }
10164}