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 #[serde(default)]
135 pub fingerprint_privacy: FingerprintPrivacyConfig,
136 #[serde(default)]
138 pub quality_gates: QualityGatesSchemaConfig,
139 #[serde(default)]
141 pub compliance: ComplianceSchemaConfig,
142 #[serde(default)]
144 pub webhooks: WebhookSchemaConfig,
145 #[serde(default)]
147 pub llm: LlmSchemaConfig,
148 #[serde(default)]
150 pub diffusion: DiffusionSchemaConfig,
151 #[serde(default)]
153 pub causal: CausalSchemaConfig,
154}
155
156#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct LlmSchemaConfig {
163 #[serde(default)]
165 pub enabled: bool,
166 #[serde(default = "default_llm_provider")]
168 pub provider: String,
169 #[serde(default = "default_llm_model_name")]
171 pub model: String,
172 #[serde(default = "default_llm_batch_size")]
174 pub max_vendor_enrichments: usize,
175}
176
177fn default_llm_provider() -> String {
178 "mock".to_string()
179}
180
181fn default_llm_model_name() -> String {
182 "gpt-4o-mini".to_string()
183}
184
185fn default_llm_batch_size() -> usize {
186 50
187}
188
189impl Default for LlmSchemaConfig {
190 fn default() -> Self {
191 Self {
192 enabled: false,
193 provider: default_llm_provider(),
194 model: default_llm_model_name(),
195 max_vendor_enrichments: default_llm_batch_size(),
196 }
197 }
198}
199
200#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct DiffusionSchemaConfig {
206 #[serde(default)]
208 pub enabled: bool,
209 #[serde(default = "default_diffusion_steps")]
211 pub n_steps: usize,
212 #[serde(default = "default_diffusion_schedule")]
214 pub schedule: String,
215 #[serde(default = "default_diffusion_sample_size")]
217 pub sample_size: usize,
218}
219
220fn default_diffusion_steps() -> usize {
221 100
222}
223
224fn default_diffusion_schedule() -> String {
225 "linear".to_string()
226}
227
228fn default_diffusion_sample_size() -> usize {
229 100
230}
231
232impl Default for DiffusionSchemaConfig {
233 fn default() -> Self {
234 Self {
235 enabled: false,
236 n_steps: default_diffusion_steps(),
237 schedule: default_diffusion_schedule(),
238 sample_size: default_diffusion_sample_size(),
239 }
240 }
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct CausalSchemaConfig {
250 #[serde(default)]
252 pub enabled: bool,
253 #[serde(default = "default_causal_template")]
255 pub template: String,
256 #[serde(default = "default_causal_sample_size")]
258 pub sample_size: usize,
259 #[serde(default = "default_true")]
261 pub validate: bool,
262}
263
264fn default_causal_template() -> String {
265 "fraud_detection".to_string()
266}
267
268fn default_causal_sample_size() -> usize {
269 500
270}
271
272impl Default for CausalSchemaConfig {
273 fn default() -> Self {
274 Self {
275 enabled: false,
276 template: default_causal_template(),
277 sample_size: default_causal_sample_size(),
278 validate: true,
279 }
280 }
281}
282
283#[derive(Debug, Clone, Serialize, Deserialize)]
290pub struct GraphExportConfig {
291 #[serde(default)]
293 pub enabled: bool,
294
295 #[serde(default = "default_graph_types")]
297 pub graph_types: Vec<GraphTypeConfig>,
298
299 #[serde(default = "default_graph_formats")]
301 pub formats: Vec<GraphExportFormat>,
302
303 #[serde(default = "default_train_ratio")]
305 pub train_ratio: f64,
306
307 #[serde(default = "default_val_ratio")]
309 pub validation_ratio: f64,
310
311 #[serde(default)]
313 pub split_seed: Option<u64>,
314
315 #[serde(default = "default_graph_subdir")]
317 pub output_subdirectory: String,
318
319 #[serde(default)]
321 pub hypergraph: HypergraphExportSettings,
322}
323
324fn default_graph_types() -> Vec<GraphTypeConfig> {
325 vec![GraphTypeConfig::default()]
326}
327
328fn default_graph_formats() -> Vec<GraphExportFormat> {
329 vec![GraphExportFormat::PytorchGeometric]
330}
331
332fn default_train_ratio() -> f64 {
333 0.7
334}
335
336fn default_val_ratio() -> f64 {
337 0.15
338}
339
340fn default_graph_subdir() -> String {
341 "graphs".to_string()
342}
343
344impl Default for GraphExportConfig {
345 fn default() -> Self {
346 Self {
347 enabled: false,
348 graph_types: default_graph_types(),
349 formats: default_graph_formats(),
350 train_ratio: 0.7,
351 validation_ratio: 0.15,
352 split_seed: None,
353 output_subdirectory: "graphs".to_string(),
354 hypergraph: HypergraphExportSettings::default(),
355 }
356 }
357}
358
359#[derive(Debug, Clone, Serialize, Deserialize)]
366pub struct HypergraphExportSettings {
367 #[serde(default)]
369 pub enabled: bool,
370
371 #[serde(default = "default_hypergraph_max_nodes")]
373 pub max_nodes: usize,
374
375 #[serde(default = "default_aggregation_strategy")]
377 pub aggregation_strategy: String,
378
379 #[serde(default)]
381 pub governance_layer: GovernanceLayerSettings,
382
383 #[serde(default)]
385 pub process_layer: ProcessLayerSettings,
386
387 #[serde(default)]
389 pub accounting_layer: AccountingLayerSettings,
390
391 #[serde(default)]
393 pub cross_layer: CrossLayerSettings,
394
395 #[serde(default = "default_hypergraph_subdir")]
397 pub output_subdirectory: String,
398
399 #[serde(default = "default_hypergraph_format")]
401 pub output_format: String,
402
403 #[serde(default)]
405 pub stream_target: Option<String>,
406
407 #[serde(default = "default_stream_batch_size")]
409 pub stream_batch_size: usize,
410}
411
412fn default_hypergraph_max_nodes() -> usize {
413 50_000
414}
415
416fn default_aggregation_strategy() -> String {
417 "pool_by_counterparty".to_string()
418}
419
420fn default_hypergraph_subdir() -> String {
421 "hypergraph".to_string()
422}
423
424fn default_hypergraph_format() -> String {
425 "native".to_string()
426}
427
428fn default_stream_batch_size() -> usize {
429 1000
430}
431
432impl Default for HypergraphExportSettings {
433 fn default() -> Self {
434 Self {
435 enabled: false,
436 max_nodes: 50_000,
437 aggregation_strategy: "pool_by_counterparty".to_string(),
438 governance_layer: GovernanceLayerSettings::default(),
439 process_layer: ProcessLayerSettings::default(),
440 accounting_layer: AccountingLayerSettings::default(),
441 cross_layer: CrossLayerSettings::default(),
442 output_subdirectory: "hypergraph".to_string(),
443 output_format: "native".to_string(),
444 stream_target: None,
445 stream_batch_size: 1000,
446 }
447 }
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
452pub struct GovernanceLayerSettings {
453 #[serde(default = "default_true")]
455 pub include_coso: bool,
456 #[serde(default = "default_true")]
458 pub include_controls: bool,
459 #[serde(default = "default_true")]
461 pub include_sox: bool,
462 #[serde(default = "default_true")]
464 pub include_vendors: bool,
465 #[serde(default = "default_true")]
467 pub include_customers: bool,
468 #[serde(default = "default_true")]
470 pub include_employees: bool,
471}
472
473impl Default for GovernanceLayerSettings {
474 fn default() -> Self {
475 Self {
476 include_coso: true,
477 include_controls: true,
478 include_sox: true,
479 include_vendors: true,
480 include_customers: true,
481 include_employees: true,
482 }
483 }
484}
485
486#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct ProcessLayerSettings {
489 #[serde(default = "default_true")]
491 pub include_p2p: bool,
492 #[serde(default = "default_true")]
494 pub include_o2c: bool,
495 #[serde(default = "default_true")]
497 pub events_as_hyperedges: bool,
498 #[serde(default = "default_docs_per_counterparty_threshold")]
500 pub docs_per_counterparty_threshold: usize,
501}
502
503fn default_docs_per_counterparty_threshold() -> usize {
504 20
505}
506
507impl Default for ProcessLayerSettings {
508 fn default() -> Self {
509 Self {
510 include_p2p: true,
511 include_o2c: true,
512 events_as_hyperedges: true,
513 docs_per_counterparty_threshold: 20,
514 }
515 }
516}
517
518#[derive(Debug, Clone, Serialize, Deserialize)]
520pub struct AccountingLayerSettings {
521 #[serde(default = "default_true")]
523 pub include_accounts: bool,
524 #[serde(default = "default_true")]
526 pub je_as_hyperedges: bool,
527}
528
529impl Default for AccountingLayerSettings {
530 fn default() -> Self {
531 Self {
532 include_accounts: true,
533 je_as_hyperedges: true,
534 }
535 }
536}
537
538#[derive(Debug, Clone, Serialize, Deserialize)]
540pub struct CrossLayerSettings {
541 #[serde(default = "default_true")]
543 pub enabled: bool,
544}
545
546impl Default for CrossLayerSettings {
547 fn default() -> Self {
548 Self { enabled: true }
549 }
550}
551
552#[derive(Debug, Clone, Serialize, Deserialize)]
554pub struct GraphTypeConfig {
555 #[serde(default = "default_graph_name")]
557 pub name: String,
558
559 #[serde(default)]
561 pub aggregate_edges: bool,
562
563 #[serde(default)]
565 pub min_edge_weight: f64,
566
567 #[serde(default)]
569 pub include_document_nodes: bool,
570}
571
572fn default_graph_name() -> String {
573 "accounting_network".to_string()
574}
575
576impl Default for GraphTypeConfig {
577 fn default() -> Self {
578 Self {
579 name: "accounting_network".to_string(),
580 aggregate_edges: false,
581 min_edge_weight: 0.0,
582 include_document_nodes: false,
583 }
584 }
585}
586
587#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
589#[serde(rename_all = "snake_case")]
590pub enum GraphExportFormat {
591 PytorchGeometric,
593 Neo4j,
595 Dgl,
597 RustGraph,
599 RustGraphHypergraph,
601}
602
603#[derive(Debug, Clone, Default, Serialize, Deserialize)]
607pub struct ScenarioConfig {
608 #[serde(default)]
611 pub tags: Vec<String>,
612
613 #[serde(default)]
618 pub profile: Option<String>,
619
620 #[serde(default)]
622 pub description: Option<String>,
623
624 #[serde(default)]
626 pub ml_training: bool,
627
628 #[serde(default)]
631 pub target_anomaly_ratio: Option<f64>,
632
633 #[serde(default)]
635 pub metadata: std::collections::HashMap<String, String>,
636}
637
638#[derive(Debug, Clone, Serialize, Deserialize)]
643pub struct TemporalDriftConfig {
644 #[serde(default)]
646 pub enabled: bool,
647
648 #[serde(default = "default_amount_drift")]
651 pub amount_mean_drift: f64,
652
653 #[serde(default)]
656 pub amount_variance_drift: f64,
657
658 #[serde(default)]
661 pub anomaly_rate_drift: f64,
662
663 #[serde(default = "default_concept_drift")]
666 pub concept_drift_rate: f64,
667
668 #[serde(default)]
670 pub sudden_drift_probability: f64,
671
672 #[serde(default = "default_sudden_drift_magnitude")]
674 pub sudden_drift_magnitude: f64,
675
676 #[serde(default)]
678 pub seasonal_drift: bool,
679
680 #[serde(default)]
682 pub drift_start_period: u32,
683
684 #[serde(default = "default_drift_type")]
686 pub drift_type: DriftType,
687}
688
689fn default_amount_drift() -> f64 {
690 0.02
691}
692
693fn default_concept_drift() -> f64 {
694 0.01
695}
696
697fn default_sudden_drift_magnitude() -> f64 {
698 2.0
699}
700
701fn default_drift_type() -> DriftType {
702 DriftType::Gradual
703}
704
705impl Default for TemporalDriftConfig {
706 fn default() -> Self {
707 Self {
708 enabled: false,
709 amount_mean_drift: 0.02,
710 amount_variance_drift: 0.0,
711 anomaly_rate_drift: 0.0,
712 concept_drift_rate: 0.01,
713 sudden_drift_probability: 0.0,
714 sudden_drift_magnitude: 2.0,
715 seasonal_drift: false,
716 drift_start_period: 0,
717 drift_type: DriftType::Gradual,
718 }
719 }
720}
721
722impl TemporalDriftConfig {
723 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
725 datasynth_core::distributions::DriftConfig {
726 enabled: self.enabled,
727 amount_mean_drift: self.amount_mean_drift,
728 amount_variance_drift: self.amount_variance_drift,
729 anomaly_rate_drift: self.anomaly_rate_drift,
730 concept_drift_rate: self.concept_drift_rate,
731 sudden_drift_probability: self.sudden_drift_probability,
732 sudden_drift_magnitude: self.sudden_drift_magnitude,
733 seasonal_drift: self.seasonal_drift,
734 drift_start_period: self.drift_start_period,
735 drift_type: match self.drift_type {
736 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
737 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
738 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
739 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
740 },
741 regime_changes: Vec::new(),
742 economic_cycle: Default::default(),
743 parameter_drifts: Vec::new(),
744 }
745 }
746}
747
748#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
750#[serde(rename_all = "snake_case")]
751pub enum DriftType {
752 #[default]
754 Gradual,
755 Sudden,
757 Recurring,
759 Mixed,
761}
762
763#[derive(Debug, Clone, Serialize, Deserialize)]
769pub struct StreamingSchemaConfig {
770 #[serde(default)]
772 pub enabled: bool,
773 #[serde(default = "default_buffer_size")]
775 pub buffer_size: usize,
776 #[serde(default = "default_true")]
778 pub enable_progress: bool,
779 #[serde(default = "default_progress_interval")]
781 pub progress_interval: u64,
782 #[serde(default)]
784 pub backpressure: BackpressureSchemaStrategy,
785}
786
787fn default_buffer_size() -> usize {
788 1000
789}
790
791fn default_progress_interval() -> u64 {
792 100
793}
794
795impl Default for StreamingSchemaConfig {
796 fn default() -> Self {
797 Self {
798 enabled: false,
799 buffer_size: 1000,
800 enable_progress: true,
801 progress_interval: 100,
802 backpressure: BackpressureSchemaStrategy::Block,
803 }
804 }
805}
806
807#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
809#[serde(rename_all = "snake_case")]
810pub enum BackpressureSchemaStrategy {
811 #[default]
813 Block,
814 DropOldest,
816 DropNewest,
818 Buffer,
820}
821
822#[derive(Debug, Clone, Serialize, Deserialize)]
828pub struct RateLimitSchemaConfig {
829 #[serde(default)]
831 pub enabled: bool,
832 #[serde(default = "default_entities_per_second")]
834 pub entities_per_second: f64,
835 #[serde(default = "default_burst_size")]
837 pub burst_size: u32,
838 #[serde(default)]
840 pub backpressure: RateLimitBackpressureSchema,
841}
842
843fn default_entities_per_second() -> f64 {
844 1000.0
845}
846
847fn default_burst_size() -> u32 {
848 100
849}
850
851impl Default for RateLimitSchemaConfig {
852 fn default() -> Self {
853 Self {
854 enabled: false,
855 entities_per_second: 1000.0,
856 burst_size: 100,
857 backpressure: RateLimitBackpressureSchema::Block,
858 }
859 }
860}
861
862#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
864#[serde(rename_all = "snake_case")]
865pub enum RateLimitBackpressureSchema {
866 #[default]
868 Block,
869 Drop,
871 Buffer,
873}
874
875#[derive(Debug, Clone, Serialize, Deserialize)]
881pub struct TemporalAttributeSchemaConfig {
882 #[serde(default)]
884 pub enabled: bool,
885 #[serde(default)]
887 pub valid_time: ValidTimeSchemaConfig,
888 #[serde(default)]
890 pub transaction_time: TransactionTimeSchemaConfig,
891 #[serde(default)]
893 pub generate_version_chains: bool,
894 #[serde(default = "default_avg_versions")]
896 pub avg_versions_per_entity: f64,
897}
898
899fn default_avg_versions() -> f64 {
900 1.5
901}
902
903impl Default for TemporalAttributeSchemaConfig {
904 fn default() -> Self {
905 Self {
906 enabled: false,
907 valid_time: ValidTimeSchemaConfig::default(),
908 transaction_time: TransactionTimeSchemaConfig::default(),
909 generate_version_chains: false,
910 avg_versions_per_entity: 1.5,
911 }
912 }
913}
914
915#[derive(Debug, Clone, Serialize, Deserialize)]
917pub struct ValidTimeSchemaConfig {
918 #[serde(default = "default_closed_probability")]
920 pub closed_probability: f64,
921 #[serde(default = "default_avg_validity_days")]
923 pub avg_validity_days: u32,
924 #[serde(default = "default_validity_stddev")]
926 pub validity_stddev_days: u32,
927}
928
929fn default_closed_probability() -> f64 {
930 0.1
931}
932
933fn default_avg_validity_days() -> u32 {
934 365
935}
936
937fn default_validity_stddev() -> u32 {
938 90
939}
940
941impl Default for ValidTimeSchemaConfig {
942 fn default() -> Self {
943 Self {
944 closed_probability: 0.1,
945 avg_validity_days: 365,
946 validity_stddev_days: 90,
947 }
948 }
949}
950
951#[derive(Debug, Clone, Serialize, Deserialize)]
953pub struct TransactionTimeSchemaConfig {
954 #[serde(default)]
956 pub avg_recording_delay_seconds: u32,
957 #[serde(default)]
959 pub allow_backdating: bool,
960 #[serde(default = "default_backdating_probability")]
962 pub backdating_probability: f64,
963 #[serde(default = "default_max_backdate_days")]
965 pub max_backdate_days: u32,
966}
967
968fn default_backdating_probability() -> f64 {
969 0.01
970}
971
972fn default_max_backdate_days() -> u32 {
973 30
974}
975
976impl Default for TransactionTimeSchemaConfig {
977 fn default() -> Self {
978 Self {
979 avg_recording_delay_seconds: 0,
980 allow_backdating: false,
981 backdating_probability: 0.01,
982 max_backdate_days: 30,
983 }
984 }
985}
986
987#[derive(Debug, Clone, Serialize, Deserialize)]
993pub struct RelationshipSchemaConfig {
994 #[serde(default)]
996 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
997 #[serde(default = "default_true")]
999 pub allow_orphans: bool,
1000 #[serde(default = "default_orphan_probability")]
1002 pub orphan_probability: f64,
1003 #[serde(default)]
1005 pub allow_circular: bool,
1006 #[serde(default = "default_max_circular_depth")]
1008 pub max_circular_depth: u32,
1009}
1010
1011fn default_orphan_probability() -> f64 {
1012 0.01
1013}
1014
1015fn default_max_circular_depth() -> u32 {
1016 3
1017}
1018
1019impl Default for RelationshipSchemaConfig {
1020 fn default() -> Self {
1021 Self {
1022 relationship_types: Vec::new(),
1023 allow_orphans: true,
1024 orphan_probability: 0.01,
1025 allow_circular: false,
1026 max_circular_depth: 3,
1027 }
1028 }
1029}
1030
1031#[derive(Debug, Clone, Serialize, Deserialize)]
1033pub struct RelationshipTypeSchemaConfig {
1034 pub name: String,
1036 pub source_type: String,
1038 pub target_type: String,
1040 #[serde(default)]
1042 pub cardinality: CardinalitySchemaRule,
1043 #[serde(default = "default_relationship_weight")]
1045 pub weight: f64,
1046 #[serde(default)]
1048 pub required: bool,
1049 #[serde(default = "default_true")]
1051 pub directed: bool,
1052}
1053
1054fn default_relationship_weight() -> f64 {
1055 1.0
1056}
1057
1058impl Default for RelationshipTypeSchemaConfig {
1059 fn default() -> Self {
1060 Self {
1061 name: String::new(),
1062 source_type: String::new(),
1063 target_type: String::new(),
1064 cardinality: CardinalitySchemaRule::default(),
1065 weight: 1.0,
1066 required: false,
1067 directed: true,
1068 }
1069 }
1070}
1071
1072#[derive(Debug, Clone, Serialize, Deserialize)]
1074#[serde(rename_all = "snake_case")]
1075pub enum CardinalitySchemaRule {
1076 OneToOne,
1078 OneToMany {
1080 min: u32,
1082 max: u32,
1084 },
1085 ManyToOne {
1087 min: u32,
1089 max: u32,
1091 },
1092 ManyToMany {
1094 min_per_source: u32,
1096 max_per_source: u32,
1098 },
1099}
1100
1101impl Default for CardinalitySchemaRule {
1102 fn default() -> Self {
1103 Self::OneToMany { min: 1, max: 5 }
1104 }
1105}
1106
1107#[derive(Debug, Clone, Serialize, Deserialize)]
1109pub struct GlobalConfig {
1110 pub seed: Option<u64>,
1112 pub industry: IndustrySector,
1114 pub start_date: String,
1116 pub period_months: u32,
1118 #[serde(default = "default_currency")]
1120 pub group_currency: String,
1121 #[serde(default = "default_true")]
1123 pub parallel: bool,
1124 #[serde(default)]
1126 pub worker_threads: usize,
1127 #[serde(default)]
1129 pub memory_limit_mb: usize,
1130}
1131
1132fn default_currency() -> String {
1133 "USD".to_string()
1134}
1135fn default_true() -> bool {
1136 true
1137}
1138
1139#[derive(Debug, Clone, Serialize, Deserialize)]
1141pub struct CompanyConfig {
1142 pub code: String,
1144 pub name: String,
1146 pub currency: String,
1148 pub country: String,
1150 #[serde(default = "default_fiscal_variant")]
1152 pub fiscal_year_variant: String,
1153 pub annual_transaction_volume: TransactionVolume,
1155 #[serde(default = "default_weight")]
1157 pub volume_weight: f64,
1158}
1159
1160fn default_fiscal_variant() -> String {
1161 "K4".to_string()
1162}
1163fn default_weight() -> f64 {
1164 1.0
1165}
1166
1167#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1169#[serde(rename_all = "snake_case")]
1170pub enum TransactionVolume {
1171 TenK,
1173 HundredK,
1175 OneM,
1177 TenM,
1179 HundredM,
1181 Custom(u64),
1183}
1184
1185impl TransactionVolume {
1186 pub fn count(&self) -> u64 {
1188 match self {
1189 Self::TenK => 10_000,
1190 Self::HundredK => 100_000,
1191 Self::OneM => 1_000_000,
1192 Self::TenM => 10_000_000,
1193 Self::HundredM => 100_000_000,
1194 Self::Custom(n) => *n,
1195 }
1196 }
1197}
1198
1199#[derive(Debug, Clone, Serialize, Deserialize)]
1201pub struct ChartOfAccountsConfig {
1202 pub complexity: CoAComplexity,
1204 #[serde(default = "default_true")]
1206 pub industry_specific: bool,
1207 pub custom_accounts: Option<PathBuf>,
1209 #[serde(default = "default_min_depth")]
1211 pub min_hierarchy_depth: u8,
1212 #[serde(default = "default_max_depth")]
1214 pub max_hierarchy_depth: u8,
1215}
1216
1217fn default_min_depth() -> u8 {
1218 2
1219}
1220fn default_max_depth() -> u8 {
1221 5
1222}
1223
1224impl Default for ChartOfAccountsConfig {
1225 fn default() -> Self {
1226 Self {
1227 complexity: CoAComplexity::Small,
1228 industry_specific: true,
1229 custom_accounts: None,
1230 min_hierarchy_depth: default_min_depth(),
1231 max_hierarchy_depth: default_max_depth(),
1232 }
1233 }
1234}
1235
1236#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1238pub struct TransactionConfig {
1239 #[serde(default)]
1241 pub line_item_distribution: LineItemDistributionConfig,
1242 #[serde(default)]
1244 pub debit_credit_distribution: DebitCreditDistributionConfig,
1245 #[serde(default)]
1247 pub even_odd_distribution: EvenOddDistributionConfig,
1248 #[serde(default)]
1250 pub source_distribution: SourceDistribution,
1251 #[serde(default)]
1253 pub seasonality: SeasonalityConfig,
1254 #[serde(default)]
1256 pub amounts: AmountDistributionConfig,
1257 #[serde(default)]
1259 pub benford: BenfordConfig,
1260}
1261
1262#[derive(Debug, Clone, Serialize, Deserialize)]
1264pub struct BenfordConfig {
1265 #[serde(default = "default_true")]
1267 pub enabled: bool,
1268 #[serde(default = "default_benford_tolerance")]
1270 pub tolerance: f64,
1271 #[serde(default)]
1273 pub exempt_sources: Vec<BenfordExemption>,
1274}
1275
1276fn default_benford_tolerance() -> f64 {
1277 0.05
1278}
1279
1280impl Default for BenfordConfig {
1281 fn default() -> Self {
1282 Self {
1283 enabled: true,
1284 tolerance: default_benford_tolerance(),
1285 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1286 }
1287 }
1288}
1289
1290#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1292#[serde(rename_all = "snake_case")]
1293pub enum BenfordExemption {
1294 Recurring,
1296 Payroll,
1298 FixedFees,
1300 RoundAmounts,
1302}
1303
1304#[derive(Debug, Clone, Serialize, Deserialize)]
1306pub struct SourceDistribution {
1307 pub manual: f64,
1309 pub automated: f64,
1311 pub recurring: f64,
1313 pub adjustment: f64,
1315}
1316
1317impl Default for SourceDistribution {
1318 fn default() -> Self {
1319 Self {
1320 manual: 0.20,
1321 automated: 0.70,
1322 recurring: 0.07,
1323 adjustment: 0.03,
1324 }
1325 }
1326}
1327
1328#[derive(Debug, Clone, Serialize, Deserialize)]
1330pub struct OutputConfig {
1331 #[serde(default)]
1333 pub mode: OutputMode,
1334 pub output_directory: PathBuf,
1336 #[serde(default = "default_formats")]
1338 pub formats: Vec<FileFormat>,
1339 #[serde(default)]
1341 pub compression: CompressionConfig,
1342 #[serde(default = "default_batch_size")]
1344 pub batch_size: usize,
1345 #[serde(default = "default_true")]
1347 pub include_acdoca: bool,
1348 #[serde(default)]
1350 pub include_bseg: bool,
1351 #[serde(default = "default_true")]
1353 pub partition_by_period: bool,
1354 #[serde(default)]
1356 pub partition_by_company: bool,
1357}
1358
1359fn default_formats() -> Vec<FileFormat> {
1360 vec![FileFormat::Parquet]
1361}
1362fn default_batch_size() -> usize {
1363 100_000
1364}
1365
1366impl Default for OutputConfig {
1367 fn default() -> Self {
1368 Self {
1369 mode: OutputMode::FlatFile,
1370 output_directory: PathBuf::from("./output"),
1371 formats: default_formats(),
1372 compression: CompressionConfig::default(),
1373 batch_size: default_batch_size(),
1374 include_acdoca: true,
1375 include_bseg: false,
1376 partition_by_period: true,
1377 partition_by_company: false,
1378 }
1379 }
1380}
1381
1382#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1384#[serde(rename_all = "snake_case")]
1385pub enum OutputMode {
1386 Streaming,
1388 #[default]
1390 FlatFile,
1391 Both,
1393}
1394
1395#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1397#[serde(rename_all = "snake_case")]
1398pub enum FileFormat {
1399 Csv,
1400 Parquet,
1401 Json,
1402 JsonLines,
1403}
1404
1405#[derive(Debug, Clone, Serialize, Deserialize)]
1407pub struct CompressionConfig {
1408 #[serde(default = "default_true")]
1410 pub enabled: bool,
1411 #[serde(default)]
1413 pub algorithm: CompressionAlgorithm,
1414 #[serde(default = "default_compression_level")]
1416 pub level: u8,
1417}
1418
1419fn default_compression_level() -> u8 {
1420 3
1421}
1422
1423impl Default for CompressionConfig {
1424 fn default() -> Self {
1425 Self {
1426 enabled: true,
1427 algorithm: CompressionAlgorithm::default(),
1428 level: default_compression_level(),
1429 }
1430 }
1431}
1432
1433#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1435#[serde(rename_all = "snake_case")]
1436pub enum CompressionAlgorithm {
1437 Gzip,
1438 #[default]
1439 Zstd,
1440 Lz4,
1441 Snappy,
1442}
1443
1444#[derive(Debug, Clone, Serialize, Deserialize)]
1446pub struct FraudConfig {
1447 #[serde(default)]
1449 pub enabled: bool,
1450 #[serde(default = "default_fraud_rate")]
1452 pub fraud_rate: f64,
1453 #[serde(default)]
1455 pub fraud_type_distribution: FraudTypeDistribution,
1456 #[serde(default)]
1458 pub clustering_enabled: bool,
1459 #[serde(default = "default_clustering_factor")]
1461 pub clustering_factor: f64,
1462 #[serde(default = "default_approval_thresholds")]
1464 pub approval_thresholds: Vec<f64>,
1465}
1466
1467fn default_approval_thresholds() -> Vec<f64> {
1468 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1469}
1470
1471fn default_fraud_rate() -> f64 {
1472 0.005
1473}
1474fn default_clustering_factor() -> f64 {
1475 3.0
1476}
1477
1478impl Default for FraudConfig {
1479 fn default() -> Self {
1480 Self {
1481 enabled: false,
1482 fraud_rate: default_fraud_rate(),
1483 fraud_type_distribution: FraudTypeDistribution::default(),
1484 clustering_enabled: false,
1485 clustering_factor: default_clustering_factor(),
1486 approval_thresholds: default_approval_thresholds(),
1487 }
1488 }
1489}
1490
1491#[derive(Debug, Clone, Serialize, Deserialize)]
1493pub struct FraudTypeDistribution {
1494 pub suspense_account_abuse: f64,
1495 pub fictitious_transaction: f64,
1496 pub revenue_manipulation: f64,
1497 pub expense_capitalization: f64,
1498 pub split_transaction: f64,
1499 pub timing_anomaly: f64,
1500 pub unauthorized_access: f64,
1501 pub duplicate_payment: f64,
1502}
1503
1504impl Default for FraudTypeDistribution {
1505 fn default() -> Self {
1506 Self {
1507 suspense_account_abuse: 0.25,
1508 fictitious_transaction: 0.15,
1509 revenue_manipulation: 0.10,
1510 expense_capitalization: 0.10,
1511 split_transaction: 0.15,
1512 timing_anomaly: 0.10,
1513 unauthorized_access: 0.10,
1514 duplicate_payment: 0.05,
1515 }
1516 }
1517}
1518
1519#[derive(Debug, Clone, Serialize, Deserialize)]
1521pub struct InternalControlsConfig {
1522 #[serde(default)]
1524 pub enabled: bool,
1525 #[serde(default = "default_exception_rate")]
1527 pub exception_rate: f64,
1528 #[serde(default = "default_sod_violation_rate")]
1530 pub sod_violation_rate: f64,
1531 #[serde(default = "default_true")]
1533 pub export_control_master_data: bool,
1534 #[serde(default = "default_sox_materiality_threshold")]
1536 pub sox_materiality_threshold: f64,
1537 #[serde(default = "default_true")]
1539 pub coso_enabled: bool,
1540 #[serde(default)]
1542 pub include_entity_level_controls: bool,
1543 #[serde(default = "default_target_maturity_level")]
1546 pub target_maturity_level: String,
1547}
1548
1549fn default_exception_rate() -> f64 {
1550 0.02
1551}
1552
1553fn default_sod_violation_rate() -> f64 {
1554 0.01
1555}
1556
1557fn default_sox_materiality_threshold() -> f64 {
1558 10000.0
1559}
1560
1561fn default_target_maturity_level() -> String {
1562 "mixed".to_string()
1563}
1564
1565impl Default for InternalControlsConfig {
1566 fn default() -> Self {
1567 Self {
1568 enabled: false,
1569 exception_rate: default_exception_rate(),
1570 sod_violation_rate: default_sod_violation_rate(),
1571 export_control_master_data: true,
1572 sox_materiality_threshold: default_sox_materiality_threshold(),
1573 coso_enabled: true,
1574 include_entity_level_controls: false,
1575 target_maturity_level: default_target_maturity_level(),
1576 }
1577 }
1578}
1579
1580#[derive(Debug, Clone, Serialize, Deserialize)]
1582pub struct BusinessProcessConfig {
1583 #[serde(default = "default_o2c")]
1585 pub o2c_weight: f64,
1586 #[serde(default = "default_p2p")]
1588 pub p2p_weight: f64,
1589 #[serde(default = "default_r2r")]
1591 pub r2r_weight: f64,
1592 #[serde(default = "default_h2r")]
1594 pub h2r_weight: f64,
1595 #[serde(default = "default_a2r")]
1597 pub a2r_weight: f64,
1598}
1599
1600fn default_o2c() -> f64 {
1601 0.35
1602}
1603fn default_p2p() -> f64 {
1604 0.30
1605}
1606fn default_r2r() -> f64 {
1607 0.20
1608}
1609fn default_h2r() -> f64 {
1610 0.10
1611}
1612fn default_a2r() -> f64 {
1613 0.05
1614}
1615
1616impl Default for BusinessProcessConfig {
1617 fn default() -> Self {
1618 Self {
1619 o2c_weight: default_o2c(),
1620 p2p_weight: default_p2p(),
1621 r2r_weight: default_r2r(),
1622 h2r_weight: default_h2r(),
1623 a2r_weight: default_a2r(),
1624 }
1625 }
1626}
1627
1628#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1630pub struct UserPersonaConfig {
1631 #[serde(default)]
1633 pub persona_distribution: PersonaDistribution,
1634 #[serde(default)]
1636 pub users_per_persona: UsersPerPersona,
1637}
1638
1639#[derive(Debug, Clone, Serialize, Deserialize)]
1641pub struct PersonaDistribution {
1642 pub junior_accountant: f64,
1643 pub senior_accountant: f64,
1644 pub controller: f64,
1645 pub manager: f64,
1646 pub automated_system: f64,
1647}
1648
1649impl Default for PersonaDistribution {
1650 fn default() -> Self {
1651 Self {
1652 junior_accountant: 0.15,
1653 senior_accountant: 0.15,
1654 controller: 0.05,
1655 manager: 0.05,
1656 automated_system: 0.60,
1657 }
1658 }
1659}
1660
1661#[derive(Debug, Clone, Serialize, Deserialize)]
1663pub struct UsersPerPersona {
1664 pub junior_accountant: usize,
1665 pub senior_accountant: usize,
1666 pub controller: usize,
1667 pub manager: usize,
1668 pub automated_system: usize,
1669}
1670
1671impl Default for UsersPerPersona {
1672 fn default() -> Self {
1673 Self {
1674 junior_accountant: 10,
1675 senior_accountant: 5,
1676 controller: 2,
1677 manager: 3,
1678 automated_system: 20,
1679 }
1680 }
1681}
1682
1683#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1685pub struct TemplateConfig {
1686 #[serde(default)]
1688 pub names: NameTemplateConfig,
1689 #[serde(default)]
1691 pub descriptions: DescriptionTemplateConfig,
1692 #[serde(default)]
1694 pub references: ReferenceTemplateConfig,
1695}
1696
1697#[derive(Debug, Clone, Serialize, Deserialize)]
1699pub struct NameTemplateConfig {
1700 #[serde(default)]
1702 pub culture_distribution: CultureDistribution,
1703 #[serde(default = "default_email_domain")]
1705 pub email_domain: String,
1706 #[serde(default = "default_true")]
1708 pub generate_realistic_names: bool,
1709}
1710
1711fn default_email_domain() -> String {
1712 "company.com".to_string()
1713}
1714
1715impl Default for NameTemplateConfig {
1716 fn default() -> Self {
1717 Self {
1718 culture_distribution: CultureDistribution::default(),
1719 email_domain: default_email_domain(),
1720 generate_realistic_names: true,
1721 }
1722 }
1723}
1724
1725#[derive(Debug, Clone, Serialize, Deserialize)]
1727pub struct CultureDistribution {
1728 pub western_us: f64,
1729 pub hispanic: f64,
1730 pub german: f64,
1731 pub french: f64,
1732 pub chinese: f64,
1733 pub japanese: f64,
1734 pub indian: f64,
1735}
1736
1737impl Default for CultureDistribution {
1738 fn default() -> Self {
1739 Self {
1740 western_us: 0.40,
1741 hispanic: 0.20,
1742 german: 0.10,
1743 french: 0.05,
1744 chinese: 0.10,
1745 japanese: 0.05,
1746 indian: 0.10,
1747 }
1748 }
1749}
1750
1751#[derive(Debug, Clone, Serialize, Deserialize)]
1753pub struct DescriptionTemplateConfig {
1754 #[serde(default = "default_true")]
1756 pub generate_header_text: bool,
1757 #[serde(default = "default_true")]
1759 pub generate_line_text: bool,
1760}
1761
1762impl Default for DescriptionTemplateConfig {
1763 fn default() -> Self {
1764 Self {
1765 generate_header_text: true,
1766 generate_line_text: true,
1767 }
1768 }
1769}
1770
1771#[derive(Debug, Clone, Serialize, Deserialize)]
1773pub struct ReferenceTemplateConfig {
1774 #[serde(default = "default_true")]
1776 pub generate_references: bool,
1777 #[serde(default = "default_invoice_prefix")]
1779 pub invoice_prefix: String,
1780 #[serde(default = "default_po_prefix")]
1782 pub po_prefix: String,
1783 #[serde(default = "default_so_prefix")]
1785 pub so_prefix: String,
1786}
1787
1788fn default_invoice_prefix() -> String {
1789 "INV".to_string()
1790}
1791fn default_po_prefix() -> String {
1792 "PO".to_string()
1793}
1794fn default_so_prefix() -> String {
1795 "SO".to_string()
1796}
1797
1798impl Default for ReferenceTemplateConfig {
1799 fn default() -> Self {
1800 Self {
1801 generate_references: true,
1802 invoice_prefix: default_invoice_prefix(),
1803 po_prefix: default_po_prefix(),
1804 so_prefix: default_so_prefix(),
1805 }
1806 }
1807}
1808
1809#[derive(Debug, Clone, Serialize, Deserialize)]
1811pub struct ApprovalConfig {
1812 #[serde(default)]
1814 pub enabled: bool,
1815 #[serde(default = "default_auto_approve_threshold")]
1817 pub auto_approve_threshold: f64,
1818 #[serde(default = "default_rejection_rate")]
1820 pub rejection_rate: f64,
1821 #[serde(default = "default_revision_rate")]
1823 pub revision_rate: f64,
1824 #[serde(default = "default_approval_delay_hours")]
1826 pub average_approval_delay_hours: f64,
1827 #[serde(default)]
1829 pub thresholds: Vec<ApprovalThresholdConfig>,
1830}
1831
1832fn default_auto_approve_threshold() -> f64 {
1833 1000.0
1834}
1835fn default_rejection_rate() -> f64 {
1836 0.02
1837}
1838fn default_revision_rate() -> f64 {
1839 0.05
1840}
1841fn default_approval_delay_hours() -> f64 {
1842 4.0
1843}
1844
1845impl Default for ApprovalConfig {
1846 fn default() -> Self {
1847 Self {
1848 enabled: false,
1849 auto_approve_threshold: default_auto_approve_threshold(),
1850 rejection_rate: default_rejection_rate(),
1851 revision_rate: default_revision_rate(),
1852 average_approval_delay_hours: default_approval_delay_hours(),
1853 thresholds: vec![
1854 ApprovalThresholdConfig {
1855 amount: 1000.0,
1856 level: 1,
1857 roles: vec!["senior_accountant".to_string()],
1858 },
1859 ApprovalThresholdConfig {
1860 amount: 10000.0,
1861 level: 2,
1862 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1863 },
1864 ApprovalThresholdConfig {
1865 amount: 100000.0,
1866 level: 3,
1867 roles: vec![
1868 "senior_accountant".to_string(),
1869 "controller".to_string(),
1870 "manager".to_string(),
1871 ],
1872 },
1873 ApprovalThresholdConfig {
1874 amount: 500000.0,
1875 level: 4,
1876 roles: vec![
1877 "senior_accountant".to_string(),
1878 "controller".to_string(),
1879 "manager".to_string(),
1880 "executive".to_string(),
1881 ],
1882 },
1883 ],
1884 }
1885 }
1886}
1887
1888#[derive(Debug, Clone, Serialize, Deserialize)]
1890pub struct ApprovalThresholdConfig {
1891 pub amount: f64,
1893 pub level: u8,
1895 pub roles: Vec<String>,
1897}
1898
1899#[derive(Debug, Clone, Serialize, Deserialize)]
1901pub struct DepartmentConfig {
1902 #[serde(default)]
1904 pub enabled: bool,
1905 #[serde(default = "default_headcount_multiplier")]
1907 pub headcount_multiplier: f64,
1908 #[serde(default)]
1910 pub custom_departments: Vec<CustomDepartmentConfig>,
1911}
1912
1913fn default_headcount_multiplier() -> f64 {
1914 1.0
1915}
1916
1917impl Default for DepartmentConfig {
1918 fn default() -> Self {
1919 Self {
1920 enabled: false,
1921 headcount_multiplier: default_headcount_multiplier(),
1922 custom_departments: Vec::new(),
1923 }
1924 }
1925}
1926
1927#[derive(Debug, Clone, Serialize, Deserialize)]
1929pub struct CustomDepartmentConfig {
1930 pub code: String,
1932 pub name: String,
1934 #[serde(default)]
1936 pub cost_center: Option<String>,
1937 #[serde(default)]
1939 pub primary_processes: Vec<String>,
1940 #[serde(default)]
1942 pub parent_code: Option<String>,
1943}
1944
1945#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1951pub struct MasterDataConfig {
1952 #[serde(default)]
1954 pub vendors: VendorMasterConfig,
1955 #[serde(default)]
1957 pub customers: CustomerMasterConfig,
1958 #[serde(default)]
1960 pub materials: MaterialMasterConfig,
1961 #[serde(default)]
1963 pub fixed_assets: FixedAssetMasterConfig,
1964 #[serde(default)]
1966 pub employees: EmployeeMasterConfig,
1967 #[serde(default)]
1969 pub cost_centers: CostCenterMasterConfig,
1970}
1971
1972#[derive(Debug, Clone, Serialize, Deserialize)]
1974pub struct VendorMasterConfig {
1975 #[serde(default = "default_vendor_count")]
1977 pub count: usize,
1978 #[serde(default = "default_intercompany_percent")]
1980 pub intercompany_percent: f64,
1981 #[serde(default)]
1983 pub payment_terms_distribution: PaymentTermsDistribution,
1984 #[serde(default)]
1986 pub behavior_distribution: VendorBehaviorDistribution,
1987 #[serde(default = "default_true")]
1989 pub generate_bank_accounts: bool,
1990 #[serde(default = "default_true")]
1992 pub generate_tax_ids: bool,
1993}
1994
1995fn default_vendor_count() -> usize {
1996 500
1997}
1998
1999fn default_intercompany_percent() -> f64 {
2000 0.05
2001}
2002
2003impl Default for VendorMasterConfig {
2004 fn default() -> Self {
2005 Self {
2006 count: default_vendor_count(),
2007 intercompany_percent: default_intercompany_percent(),
2008 payment_terms_distribution: PaymentTermsDistribution::default(),
2009 behavior_distribution: VendorBehaviorDistribution::default(),
2010 generate_bank_accounts: true,
2011 generate_tax_ids: true,
2012 }
2013 }
2014}
2015
2016#[derive(Debug, Clone, Serialize, Deserialize)]
2018pub struct PaymentTermsDistribution {
2019 pub net_30: f64,
2021 pub net_60: f64,
2023 pub net_90: f64,
2025 pub two_ten_net_30: f64,
2027 pub due_on_receipt: f64,
2029 pub end_of_month: f64,
2031}
2032
2033impl Default for PaymentTermsDistribution {
2034 fn default() -> Self {
2035 Self {
2036 net_30: 0.40,
2037 net_60: 0.20,
2038 net_90: 0.10,
2039 two_ten_net_30: 0.15,
2040 due_on_receipt: 0.05,
2041 end_of_month: 0.10,
2042 }
2043 }
2044}
2045
2046#[derive(Debug, Clone, Serialize, Deserialize)]
2048pub struct VendorBehaviorDistribution {
2049 pub reliable: f64,
2051 pub sometimes_late: f64,
2053 pub inconsistent_quality: f64,
2055 pub premium: f64,
2057 pub budget: f64,
2059}
2060
2061impl Default for VendorBehaviorDistribution {
2062 fn default() -> Self {
2063 Self {
2064 reliable: 0.50,
2065 sometimes_late: 0.20,
2066 inconsistent_quality: 0.10,
2067 premium: 0.10,
2068 budget: 0.10,
2069 }
2070 }
2071}
2072
2073#[derive(Debug, Clone, Serialize, Deserialize)]
2075pub struct CustomerMasterConfig {
2076 #[serde(default = "default_customer_count")]
2078 pub count: usize,
2079 #[serde(default = "default_intercompany_percent")]
2081 pub intercompany_percent: f64,
2082 #[serde(default)]
2084 pub credit_rating_distribution: CreditRatingDistribution,
2085 #[serde(default)]
2087 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2088 #[serde(default = "default_true")]
2090 pub generate_credit_limits: bool,
2091}
2092
2093fn default_customer_count() -> usize {
2094 2000
2095}
2096
2097impl Default for CustomerMasterConfig {
2098 fn default() -> Self {
2099 Self {
2100 count: default_customer_count(),
2101 intercompany_percent: default_intercompany_percent(),
2102 credit_rating_distribution: CreditRatingDistribution::default(),
2103 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2104 generate_credit_limits: true,
2105 }
2106 }
2107}
2108
2109#[derive(Debug, Clone, Serialize, Deserialize)]
2111pub struct CreditRatingDistribution {
2112 pub aaa: f64,
2114 pub aa: f64,
2116 pub a: f64,
2118 pub bbb: f64,
2120 pub bb: f64,
2122 pub b: f64,
2124 pub below_b: f64,
2126}
2127
2128impl Default for CreditRatingDistribution {
2129 fn default() -> Self {
2130 Self {
2131 aaa: 0.05,
2132 aa: 0.10,
2133 a: 0.20,
2134 bbb: 0.30,
2135 bb: 0.20,
2136 b: 0.10,
2137 below_b: 0.05,
2138 }
2139 }
2140}
2141
2142#[derive(Debug, Clone, Serialize, Deserialize)]
2144pub struct PaymentBehaviorDistribution {
2145 pub early_payer: f64,
2147 pub on_time: f64,
2149 pub occasional_late: f64,
2151 pub frequent_late: f64,
2153 pub discount_taker: f64,
2155}
2156
2157impl Default for PaymentBehaviorDistribution {
2158 fn default() -> Self {
2159 Self {
2160 early_payer: 0.10,
2161 on_time: 0.50,
2162 occasional_late: 0.25,
2163 frequent_late: 0.10,
2164 discount_taker: 0.05,
2165 }
2166 }
2167}
2168
2169#[derive(Debug, Clone, Serialize, Deserialize)]
2171pub struct MaterialMasterConfig {
2172 #[serde(default = "default_material_count")]
2174 pub count: usize,
2175 #[serde(default)]
2177 pub type_distribution: MaterialTypeDistribution,
2178 #[serde(default)]
2180 pub valuation_distribution: ValuationMethodDistribution,
2181 #[serde(default = "default_bom_percent")]
2183 pub bom_percent: f64,
2184 #[serde(default = "default_max_bom_depth")]
2186 pub max_bom_depth: u8,
2187}
2188
2189fn default_material_count() -> usize {
2190 5000
2191}
2192
2193fn default_bom_percent() -> f64 {
2194 0.20
2195}
2196
2197fn default_max_bom_depth() -> u8 {
2198 3
2199}
2200
2201impl Default for MaterialMasterConfig {
2202 fn default() -> Self {
2203 Self {
2204 count: default_material_count(),
2205 type_distribution: MaterialTypeDistribution::default(),
2206 valuation_distribution: ValuationMethodDistribution::default(),
2207 bom_percent: default_bom_percent(),
2208 max_bom_depth: default_max_bom_depth(),
2209 }
2210 }
2211}
2212
2213#[derive(Debug, Clone, Serialize, Deserialize)]
2215pub struct MaterialTypeDistribution {
2216 pub raw_material: f64,
2218 pub semi_finished: f64,
2220 pub finished_good: f64,
2222 pub trading_good: f64,
2224 pub operating_supply: f64,
2226 pub service: f64,
2228}
2229
2230impl Default for MaterialTypeDistribution {
2231 fn default() -> Self {
2232 Self {
2233 raw_material: 0.30,
2234 semi_finished: 0.15,
2235 finished_good: 0.25,
2236 trading_good: 0.15,
2237 operating_supply: 0.10,
2238 service: 0.05,
2239 }
2240 }
2241}
2242
2243#[derive(Debug, Clone, Serialize, Deserialize)]
2245pub struct ValuationMethodDistribution {
2246 pub standard_cost: f64,
2248 pub moving_average: f64,
2250 pub fifo: f64,
2252 pub lifo: f64,
2254}
2255
2256impl Default for ValuationMethodDistribution {
2257 fn default() -> Self {
2258 Self {
2259 standard_cost: 0.50,
2260 moving_average: 0.30,
2261 fifo: 0.15,
2262 lifo: 0.05,
2263 }
2264 }
2265}
2266
2267#[derive(Debug, Clone, Serialize, Deserialize)]
2269pub struct FixedAssetMasterConfig {
2270 #[serde(default = "default_asset_count")]
2272 pub count: usize,
2273 #[serde(default)]
2275 pub class_distribution: AssetClassDistribution,
2276 #[serde(default)]
2278 pub depreciation_distribution: DepreciationMethodDistribution,
2279 #[serde(default = "default_fully_depreciated_percent")]
2281 pub fully_depreciated_percent: f64,
2282 #[serde(default = "default_true")]
2284 pub generate_acquisition_history: bool,
2285}
2286
2287fn default_asset_count() -> usize {
2288 800
2289}
2290
2291fn default_fully_depreciated_percent() -> f64 {
2292 0.15
2293}
2294
2295impl Default for FixedAssetMasterConfig {
2296 fn default() -> Self {
2297 Self {
2298 count: default_asset_count(),
2299 class_distribution: AssetClassDistribution::default(),
2300 depreciation_distribution: DepreciationMethodDistribution::default(),
2301 fully_depreciated_percent: default_fully_depreciated_percent(),
2302 generate_acquisition_history: true,
2303 }
2304 }
2305}
2306
2307#[derive(Debug, Clone, Serialize, Deserialize)]
2309pub struct AssetClassDistribution {
2310 pub buildings: f64,
2312 pub machinery: f64,
2314 pub vehicles: f64,
2316 pub it_equipment: f64,
2318 pub furniture: f64,
2320 pub land: f64,
2322 pub leasehold: f64,
2324}
2325
2326impl Default for AssetClassDistribution {
2327 fn default() -> Self {
2328 Self {
2329 buildings: 0.15,
2330 machinery: 0.30,
2331 vehicles: 0.15,
2332 it_equipment: 0.20,
2333 furniture: 0.10,
2334 land: 0.05,
2335 leasehold: 0.05,
2336 }
2337 }
2338}
2339
2340#[derive(Debug, Clone, Serialize, Deserialize)]
2342pub struct DepreciationMethodDistribution {
2343 pub straight_line: f64,
2345 pub declining_balance: f64,
2347 pub double_declining: f64,
2349 pub sum_of_years: f64,
2351 pub units_of_production: f64,
2353}
2354
2355impl Default for DepreciationMethodDistribution {
2356 fn default() -> Self {
2357 Self {
2358 straight_line: 0.60,
2359 declining_balance: 0.20,
2360 double_declining: 0.10,
2361 sum_of_years: 0.05,
2362 units_of_production: 0.05,
2363 }
2364 }
2365}
2366
2367#[derive(Debug, Clone, Serialize, Deserialize)]
2369pub struct EmployeeMasterConfig {
2370 #[serde(default = "default_employee_count")]
2372 pub count: usize,
2373 #[serde(default = "default_true")]
2375 pub generate_hierarchy: bool,
2376 #[serde(default = "default_hierarchy_depth")]
2378 pub max_hierarchy_depth: u8,
2379 #[serde(default = "default_span_of_control")]
2381 pub average_span_of_control: f64,
2382 #[serde(default)]
2384 pub approval_limits: ApprovalLimitDistribution,
2385 #[serde(default)]
2387 pub department_distribution: EmployeeDepartmentDistribution,
2388}
2389
2390fn default_employee_count() -> usize {
2391 1500
2392}
2393
2394fn default_hierarchy_depth() -> u8 {
2395 6
2396}
2397
2398fn default_span_of_control() -> f64 {
2399 5.0
2400}
2401
2402impl Default for EmployeeMasterConfig {
2403 fn default() -> Self {
2404 Self {
2405 count: default_employee_count(),
2406 generate_hierarchy: true,
2407 max_hierarchy_depth: default_hierarchy_depth(),
2408 average_span_of_control: default_span_of_control(),
2409 approval_limits: ApprovalLimitDistribution::default(),
2410 department_distribution: EmployeeDepartmentDistribution::default(),
2411 }
2412 }
2413}
2414
2415#[derive(Debug, Clone, Serialize, Deserialize)]
2417pub struct ApprovalLimitDistribution {
2418 #[serde(default = "default_staff_limit")]
2420 pub staff: f64,
2421 #[serde(default = "default_senior_limit")]
2423 pub senior: f64,
2424 #[serde(default = "default_manager_limit")]
2426 pub manager: f64,
2427 #[serde(default = "default_director_limit")]
2429 pub director: f64,
2430 #[serde(default = "default_vp_limit")]
2432 pub vp: f64,
2433 #[serde(default = "default_executive_limit")]
2435 pub executive: f64,
2436}
2437
2438fn default_staff_limit() -> f64 {
2439 1000.0
2440}
2441fn default_senior_limit() -> f64 {
2442 5000.0
2443}
2444fn default_manager_limit() -> f64 {
2445 25000.0
2446}
2447fn default_director_limit() -> f64 {
2448 100000.0
2449}
2450fn default_vp_limit() -> f64 {
2451 500000.0
2452}
2453fn default_executive_limit() -> f64 {
2454 f64::INFINITY
2455}
2456
2457impl Default for ApprovalLimitDistribution {
2458 fn default() -> Self {
2459 Self {
2460 staff: default_staff_limit(),
2461 senior: default_senior_limit(),
2462 manager: default_manager_limit(),
2463 director: default_director_limit(),
2464 vp: default_vp_limit(),
2465 executive: default_executive_limit(),
2466 }
2467 }
2468}
2469
2470#[derive(Debug, Clone, Serialize, Deserialize)]
2472pub struct EmployeeDepartmentDistribution {
2473 pub finance: f64,
2475 pub procurement: f64,
2477 pub sales: f64,
2479 pub warehouse: f64,
2481 pub it: f64,
2483 pub hr: f64,
2485 pub operations: f64,
2487 pub executive: f64,
2489}
2490
2491impl Default for EmployeeDepartmentDistribution {
2492 fn default() -> Self {
2493 Self {
2494 finance: 0.12,
2495 procurement: 0.10,
2496 sales: 0.25,
2497 warehouse: 0.15,
2498 it: 0.10,
2499 hr: 0.05,
2500 operations: 0.20,
2501 executive: 0.03,
2502 }
2503 }
2504}
2505
2506#[derive(Debug, Clone, Serialize, Deserialize)]
2508pub struct CostCenterMasterConfig {
2509 #[serde(default = "default_cost_center_count")]
2511 pub count: usize,
2512 #[serde(default = "default_true")]
2514 pub generate_hierarchy: bool,
2515 #[serde(default = "default_cc_hierarchy_depth")]
2517 pub max_hierarchy_depth: u8,
2518}
2519
2520fn default_cost_center_count() -> usize {
2521 50
2522}
2523
2524fn default_cc_hierarchy_depth() -> u8 {
2525 3
2526}
2527
2528impl Default for CostCenterMasterConfig {
2529 fn default() -> Self {
2530 Self {
2531 count: default_cost_center_count(),
2532 generate_hierarchy: true,
2533 max_hierarchy_depth: default_cc_hierarchy_depth(),
2534 }
2535 }
2536}
2537
2538#[derive(Debug, Clone, Serialize, Deserialize)]
2544pub struct DocumentFlowConfig {
2545 #[serde(default)]
2547 pub p2p: P2PFlowConfig,
2548 #[serde(default)]
2550 pub o2c: O2CFlowConfig,
2551 #[serde(default = "default_true")]
2553 pub generate_document_references: bool,
2554 #[serde(default)]
2556 pub export_flow_graph: bool,
2557}
2558
2559impl Default for DocumentFlowConfig {
2560 fn default() -> Self {
2561 Self {
2562 p2p: P2PFlowConfig::default(),
2563 o2c: O2CFlowConfig::default(),
2564 generate_document_references: true,
2565 export_flow_graph: false,
2566 }
2567 }
2568}
2569
2570#[derive(Debug, Clone, Serialize, Deserialize)]
2572pub struct P2PFlowConfig {
2573 #[serde(default = "default_true")]
2575 pub enabled: bool,
2576 #[serde(default = "default_three_way_match_rate")]
2578 pub three_way_match_rate: f64,
2579 #[serde(default = "default_partial_delivery_rate")]
2581 pub partial_delivery_rate: f64,
2582 #[serde(default = "default_price_variance_rate")]
2584 pub price_variance_rate: f64,
2585 #[serde(default = "default_max_price_variance")]
2587 pub max_price_variance_percent: f64,
2588 #[serde(default = "default_quantity_variance_rate")]
2590 pub quantity_variance_rate: f64,
2591 #[serde(default = "default_po_to_gr_days")]
2593 pub average_po_to_gr_days: u32,
2594 #[serde(default = "default_gr_to_invoice_days")]
2596 pub average_gr_to_invoice_days: u32,
2597 #[serde(default = "default_invoice_to_payment_days")]
2599 pub average_invoice_to_payment_days: u32,
2600 #[serde(default)]
2602 pub line_count_distribution: DocumentLineCountDistribution,
2603 #[serde(default)]
2605 pub payment_behavior: P2PPaymentBehaviorConfig,
2606}
2607
2608fn default_three_way_match_rate() -> f64 {
2609 0.95
2610}
2611
2612fn default_partial_delivery_rate() -> f64 {
2613 0.15
2614}
2615
2616fn default_price_variance_rate() -> f64 {
2617 0.08
2618}
2619
2620fn default_max_price_variance() -> f64 {
2621 0.05
2622}
2623
2624fn default_quantity_variance_rate() -> f64 {
2625 0.05
2626}
2627
2628fn default_po_to_gr_days() -> u32 {
2629 14
2630}
2631
2632fn default_gr_to_invoice_days() -> u32 {
2633 5
2634}
2635
2636fn default_invoice_to_payment_days() -> u32 {
2637 30
2638}
2639
2640impl Default for P2PFlowConfig {
2641 fn default() -> Self {
2642 Self {
2643 enabled: true,
2644 three_way_match_rate: default_three_way_match_rate(),
2645 partial_delivery_rate: default_partial_delivery_rate(),
2646 price_variance_rate: default_price_variance_rate(),
2647 max_price_variance_percent: default_max_price_variance(),
2648 quantity_variance_rate: default_quantity_variance_rate(),
2649 average_po_to_gr_days: default_po_to_gr_days(),
2650 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2651 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2652 line_count_distribution: DocumentLineCountDistribution::default(),
2653 payment_behavior: P2PPaymentBehaviorConfig::default(),
2654 }
2655 }
2656}
2657
2658#[derive(Debug, Clone, Serialize, Deserialize)]
2664pub struct P2PPaymentBehaviorConfig {
2665 #[serde(default = "default_p2p_late_payment_rate")]
2667 pub late_payment_rate: f64,
2668 #[serde(default)]
2670 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2671 #[serde(default = "default_p2p_partial_payment_rate")]
2673 pub partial_payment_rate: f64,
2674 #[serde(default = "default_p2p_payment_correction_rate")]
2676 pub payment_correction_rate: f64,
2677}
2678
2679fn default_p2p_late_payment_rate() -> f64 {
2680 0.15
2681}
2682
2683fn default_p2p_partial_payment_rate() -> f64 {
2684 0.05
2685}
2686
2687fn default_p2p_payment_correction_rate() -> f64 {
2688 0.02
2689}
2690
2691impl Default for P2PPaymentBehaviorConfig {
2692 fn default() -> Self {
2693 Self {
2694 late_payment_rate: default_p2p_late_payment_rate(),
2695 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2696 partial_payment_rate: default_p2p_partial_payment_rate(),
2697 payment_correction_rate: default_p2p_payment_correction_rate(),
2698 }
2699 }
2700}
2701
2702#[derive(Debug, Clone, Serialize, Deserialize)]
2704pub struct LatePaymentDaysDistribution {
2705 #[serde(default = "default_slightly_late")]
2707 pub slightly_late_1_to_7: f64,
2708 #[serde(default = "default_late_8_14")]
2710 pub late_8_to_14: f64,
2711 #[serde(default = "default_very_late")]
2713 pub very_late_15_to_30: f64,
2714 #[serde(default = "default_severely_late")]
2716 pub severely_late_31_to_60: f64,
2717 #[serde(default = "default_extremely_late")]
2719 pub extremely_late_over_60: f64,
2720}
2721
2722fn default_slightly_late() -> f64 {
2723 0.50
2724}
2725
2726fn default_late_8_14() -> f64 {
2727 0.25
2728}
2729
2730fn default_very_late() -> f64 {
2731 0.15
2732}
2733
2734fn default_severely_late() -> f64 {
2735 0.07
2736}
2737
2738fn default_extremely_late() -> f64 {
2739 0.03
2740}
2741
2742impl Default for LatePaymentDaysDistribution {
2743 fn default() -> Self {
2744 Self {
2745 slightly_late_1_to_7: default_slightly_late(),
2746 late_8_to_14: default_late_8_14(),
2747 very_late_15_to_30: default_very_late(),
2748 severely_late_31_to_60: default_severely_late(),
2749 extremely_late_over_60: default_extremely_late(),
2750 }
2751 }
2752}
2753
2754#[derive(Debug, Clone, Serialize, Deserialize)]
2756pub struct O2CFlowConfig {
2757 #[serde(default = "default_true")]
2759 pub enabled: bool,
2760 #[serde(default = "default_credit_check_failure_rate")]
2762 pub credit_check_failure_rate: f64,
2763 #[serde(default = "default_partial_shipment_rate")]
2765 pub partial_shipment_rate: f64,
2766 #[serde(default = "default_return_rate")]
2768 pub return_rate: f64,
2769 #[serde(default = "default_bad_debt_rate")]
2771 pub bad_debt_rate: f64,
2772 #[serde(default = "default_so_to_delivery_days")]
2774 pub average_so_to_delivery_days: u32,
2775 #[serde(default = "default_delivery_to_invoice_days")]
2777 pub average_delivery_to_invoice_days: u32,
2778 #[serde(default = "default_invoice_to_receipt_days")]
2780 pub average_invoice_to_receipt_days: u32,
2781 #[serde(default)]
2783 pub line_count_distribution: DocumentLineCountDistribution,
2784 #[serde(default)]
2786 pub cash_discount: CashDiscountConfig,
2787 #[serde(default)]
2789 pub payment_behavior: O2CPaymentBehaviorConfig,
2790}
2791
2792fn default_credit_check_failure_rate() -> f64 {
2793 0.02
2794}
2795
2796fn default_partial_shipment_rate() -> f64 {
2797 0.10
2798}
2799
2800fn default_return_rate() -> f64 {
2801 0.03
2802}
2803
2804fn default_bad_debt_rate() -> f64 {
2805 0.01
2806}
2807
2808fn default_so_to_delivery_days() -> u32 {
2809 7
2810}
2811
2812fn default_delivery_to_invoice_days() -> u32 {
2813 1
2814}
2815
2816fn default_invoice_to_receipt_days() -> u32 {
2817 45
2818}
2819
2820impl Default for O2CFlowConfig {
2821 fn default() -> Self {
2822 Self {
2823 enabled: true,
2824 credit_check_failure_rate: default_credit_check_failure_rate(),
2825 partial_shipment_rate: default_partial_shipment_rate(),
2826 return_rate: default_return_rate(),
2827 bad_debt_rate: default_bad_debt_rate(),
2828 average_so_to_delivery_days: default_so_to_delivery_days(),
2829 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2830 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2831 line_count_distribution: DocumentLineCountDistribution::default(),
2832 cash_discount: CashDiscountConfig::default(),
2833 payment_behavior: O2CPaymentBehaviorConfig::default(),
2834 }
2835 }
2836}
2837
2838#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2844pub struct O2CPaymentBehaviorConfig {
2845 #[serde(default)]
2847 pub dunning: DunningConfig,
2848 #[serde(default)]
2850 pub partial_payments: PartialPaymentConfig,
2851 #[serde(default)]
2853 pub short_payments: ShortPaymentConfig,
2854 #[serde(default)]
2856 pub on_account_payments: OnAccountPaymentConfig,
2857 #[serde(default)]
2859 pub payment_corrections: PaymentCorrectionConfig,
2860}
2861
2862#[derive(Debug, Clone, Serialize, Deserialize)]
2864pub struct DunningConfig {
2865 #[serde(default)]
2867 pub enabled: bool,
2868 #[serde(default = "default_dunning_level_1_days")]
2870 pub level_1_days_overdue: u32,
2871 #[serde(default = "default_dunning_level_2_days")]
2873 pub level_2_days_overdue: u32,
2874 #[serde(default = "default_dunning_level_3_days")]
2876 pub level_3_days_overdue: u32,
2877 #[serde(default = "default_collection_days")]
2879 pub collection_days_overdue: u32,
2880 #[serde(default)]
2882 pub payment_after_dunning_rates: DunningPaymentRates,
2883 #[serde(default = "default_dunning_block_rate")]
2885 pub dunning_block_rate: f64,
2886 #[serde(default = "default_dunning_interest_rate")]
2888 pub interest_rate_per_year: f64,
2889 #[serde(default = "default_dunning_charge")]
2891 pub dunning_charge: f64,
2892}
2893
2894fn default_dunning_level_1_days() -> u32 {
2895 14
2896}
2897
2898fn default_dunning_level_2_days() -> u32 {
2899 28
2900}
2901
2902fn default_dunning_level_3_days() -> u32 {
2903 42
2904}
2905
2906fn default_collection_days() -> u32 {
2907 60
2908}
2909
2910fn default_dunning_block_rate() -> f64 {
2911 0.05
2912}
2913
2914fn default_dunning_interest_rate() -> f64 {
2915 0.09
2916}
2917
2918fn default_dunning_charge() -> f64 {
2919 25.0
2920}
2921
2922impl Default for DunningConfig {
2923 fn default() -> Self {
2924 Self {
2925 enabled: false,
2926 level_1_days_overdue: default_dunning_level_1_days(),
2927 level_2_days_overdue: default_dunning_level_2_days(),
2928 level_3_days_overdue: default_dunning_level_3_days(),
2929 collection_days_overdue: default_collection_days(),
2930 payment_after_dunning_rates: DunningPaymentRates::default(),
2931 dunning_block_rate: default_dunning_block_rate(),
2932 interest_rate_per_year: default_dunning_interest_rate(),
2933 dunning_charge: default_dunning_charge(),
2934 }
2935 }
2936}
2937
2938#[derive(Debug, Clone, Serialize, Deserialize)]
2940pub struct DunningPaymentRates {
2941 #[serde(default = "default_after_level_1")]
2943 pub after_level_1: f64,
2944 #[serde(default = "default_after_level_2")]
2946 pub after_level_2: f64,
2947 #[serde(default = "default_after_level_3")]
2949 pub after_level_3: f64,
2950 #[serde(default = "default_during_collection")]
2952 pub during_collection: f64,
2953 #[serde(default = "default_never_pay")]
2955 pub never_pay: f64,
2956}
2957
2958fn default_after_level_1() -> f64 {
2959 0.40
2960}
2961
2962fn default_after_level_2() -> f64 {
2963 0.30
2964}
2965
2966fn default_after_level_3() -> f64 {
2967 0.15
2968}
2969
2970fn default_during_collection() -> f64 {
2971 0.05
2972}
2973
2974fn default_never_pay() -> f64 {
2975 0.10
2976}
2977
2978impl Default for DunningPaymentRates {
2979 fn default() -> Self {
2980 Self {
2981 after_level_1: default_after_level_1(),
2982 after_level_2: default_after_level_2(),
2983 after_level_3: default_after_level_3(),
2984 during_collection: default_during_collection(),
2985 never_pay: default_never_pay(),
2986 }
2987 }
2988}
2989
2990#[derive(Debug, Clone, Serialize, Deserialize)]
2992pub struct PartialPaymentConfig {
2993 #[serde(default = "default_partial_payment_rate")]
2995 pub rate: f64,
2996 #[serde(default)]
2998 pub percentage_distribution: PartialPaymentPercentageDistribution,
2999 #[serde(default = "default_avg_days_until_remainder")]
3001 pub avg_days_until_remainder: u32,
3002}
3003
3004fn default_partial_payment_rate() -> f64 {
3005 0.08
3006}
3007
3008fn default_avg_days_until_remainder() -> u32 {
3009 30
3010}
3011
3012impl Default for PartialPaymentConfig {
3013 fn default() -> Self {
3014 Self {
3015 rate: default_partial_payment_rate(),
3016 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3017 avg_days_until_remainder: default_avg_days_until_remainder(),
3018 }
3019 }
3020}
3021
3022#[derive(Debug, Clone, Serialize, Deserialize)]
3024pub struct PartialPaymentPercentageDistribution {
3025 #[serde(default = "default_partial_25")]
3027 pub pay_25_percent: f64,
3028 #[serde(default = "default_partial_50")]
3030 pub pay_50_percent: f64,
3031 #[serde(default = "default_partial_75")]
3033 pub pay_75_percent: f64,
3034 #[serde(default = "default_partial_random")]
3036 pub pay_random_percent: f64,
3037}
3038
3039fn default_partial_25() -> f64 {
3040 0.15
3041}
3042
3043fn default_partial_50() -> f64 {
3044 0.50
3045}
3046
3047fn default_partial_75() -> f64 {
3048 0.25
3049}
3050
3051fn default_partial_random() -> f64 {
3052 0.10
3053}
3054
3055impl Default for PartialPaymentPercentageDistribution {
3056 fn default() -> Self {
3057 Self {
3058 pay_25_percent: default_partial_25(),
3059 pay_50_percent: default_partial_50(),
3060 pay_75_percent: default_partial_75(),
3061 pay_random_percent: default_partial_random(),
3062 }
3063 }
3064}
3065
3066#[derive(Debug, Clone, Serialize, Deserialize)]
3068pub struct ShortPaymentConfig {
3069 #[serde(default = "default_short_payment_rate")]
3071 pub rate: f64,
3072 #[serde(default)]
3074 pub reason_distribution: ShortPaymentReasonDistribution,
3075 #[serde(default = "default_max_short_percent")]
3077 pub max_short_percent: f64,
3078}
3079
3080fn default_short_payment_rate() -> f64 {
3081 0.03
3082}
3083
3084fn default_max_short_percent() -> f64 {
3085 0.10
3086}
3087
3088impl Default for ShortPaymentConfig {
3089 fn default() -> Self {
3090 Self {
3091 rate: default_short_payment_rate(),
3092 reason_distribution: ShortPaymentReasonDistribution::default(),
3093 max_short_percent: default_max_short_percent(),
3094 }
3095 }
3096}
3097
3098#[derive(Debug, Clone, Serialize, Deserialize)]
3100pub struct ShortPaymentReasonDistribution {
3101 #[serde(default = "default_pricing_dispute")]
3103 pub pricing_dispute: f64,
3104 #[serde(default = "default_quality_issue")]
3106 pub quality_issue: f64,
3107 #[serde(default = "default_quantity_discrepancy")]
3109 pub quantity_discrepancy: f64,
3110 #[serde(default = "default_unauthorized_deduction")]
3112 pub unauthorized_deduction: f64,
3113 #[serde(default = "default_incorrect_discount")]
3115 pub incorrect_discount: f64,
3116}
3117
3118fn default_pricing_dispute() -> f64 {
3119 0.30
3120}
3121
3122fn default_quality_issue() -> f64 {
3123 0.20
3124}
3125
3126fn default_quantity_discrepancy() -> f64 {
3127 0.20
3128}
3129
3130fn default_unauthorized_deduction() -> f64 {
3131 0.15
3132}
3133
3134fn default_incorrect_discount() -> f64 {
3135 0.15
3136}
3137
3138impl Default for ShortPaymentReasonDistribution {
3139 fn default() -> Self {
3140 Self {
3141 pricing_dispute: default_pricing_dispute(),
3142 quality_issue: default_quality_issue(),
3143 quantity_discrepancy: default_quantity_discrepancy(),
3144 unauthorized_deduction: default_unauthorized_deduction(),
3145 incorrect_discount: default_incorrect_discount(),
3146 }
3147 }
3148}
3149
3150#[derive(Debug, Clone, Serialize, Deserialize)]
3152pub struct OnAccountPaymentConfig {
3153 #[serde(default = "default_on_account_rate")]
3155 pub rate: f64,
3156 #[serde(default = "default_avg_days_until_applied")]
3158 pub avg_days_until_applied: u32,
3159}
3160
3161fn default_on_account_rate() -> f64 {
3162 0.02
3163}
3164
3165fn default_avg_days_until_applied() -> u32 {
3166 14
3167}
3168
3169impl Default for OnAccountPaymentConfig {
3170 fn default() -> Self {
3171 Self {
3172 rate: default_on_account_rate(),
3173 avg_days_until_applied: default_avg_days_until_applied(),
3174 }
3175 }
3176}
3177
3178#[derive(Debug, Clone, Serialize, Deserialize)]
3180pub struct PaymentCorrectionConfig {
3181 #[serde(default = "default_payment_correction_rate")]
3183 pub rate: f64,
3184 #[serde(default)]
3186 pub type_distribution: PaymentCorrectionTypeDistribution,
3187}
3188
3189fn default_payment_correction_rate() -> f64 {
3190 0.02
3191}
3192
3193impl Default for PaymentCorrectionConfig {
3194 fn default() -> Self {
3195 Self {
3196 rate: default_payment_correction_rate(),
3197 type_distribution: PaymentCorrectionTypeDistribution::default(),
3198 }
3199 }
3200}
3201
3202#[derive(Debug, Clone, Serialize, Deserialize)]
3204pub struct PaymentCorrectionTypeDistribution {
3205 #[serde(default = "default_nsf_rate")]
3207 pub nsf: f64,
3208 #[serde(default = "default_chargeback_rate")]
3210 pub chargeback: f64,
3211 #[serde(default = "default_wrong_amount_rate")]
3213 pub wrong_amount: f64,
3214 #[serde(default = "default_wrong_customer_rate")]
3216 pub wrong_customer: f64,
3217 #[serde(default = "default_duplicate_payment_rate")]
3219 pub duplicate_payment: f64,
3220}
3221
3222fn default_nsf_rate() -> f64 {
3223 0.30
3224}
3225
3226fn default_chargeback_rate() -> f64 {
3227 0.20
3228}
3229
3230fn default_wrong_amount_rate() -> f64 {
3231 0.20
3232}
3233
3234fn default_wrong_customer_rate() -> f64 {
3235 0.15
3236}
3237
3238fn default_duplicate_payment_rate() -> f64 {
3239 0.15
3240}
3241
3242impl Default for PaymentCorrectionTypeDistribution {
3243 fn default() -> Self {
3244 Self {
3245 nsf: default_nsf_rate(),
3246 chargeback: default_chargeback_rate(),
3247 wrong_amount: default_wrong_amount_rate(),
3248 wrong_customer: default_wrong_customer_rate(),
3249 duplicate_payment: default_duplicate_payment_rate(),
3250 }
3251 }
3252}
3253
3254#[derive(Debug, Clone, Serialize, Deserialize)]
3256pub struct DocumentLineCountDistribution {
3257 #[serde(default = "default_min_lines")]
3259 pub min_lines: u32,
3260 #[serde(default = "default_max_lines")]
3262 pub max_lines: u32,
3263 #[serde(default = "default_mode_lines")]
3265 pub mode_lines: u32,
3266}
3267
3268fn default_min_lines() -> u32 {
3269 1
3270}
3271
3272fn default_max_lines() -> u32 {
3273 20
3274}
3275
3276fn default_mode_lines() -> u32 {
3277 3
3278}
3279
3280impl Default for DocumentLineCountDistribution {
3281 fn default() -> Self {
3282 Self {
3283 min_lines: default_min_lines(),
3284 max_lines: default_max_lines(),
3285 mode_lines: default_mode_lines(),
3286 }
3287 }
3288}
3289
3290#[derive(Debug, Clone, Serialize, Deserialize)]
3292pub struct CashDiscountConfig {
3293 #[serde(default = "default_discount_eligible_rate")]
3295 pub eligible_rate: f64,
3296 #[serde(default = "default_discount_taken_rate")]
3298 pub taken_rate: f64,
3299 #[serde(default = "default_discount_percent")]
3301 pub discount_percent: f64,
3302 #[serde(default = "default_discount_days")]
3304 pub discount_days: u32,
3305}
3306
3307fn default_discount_eligible_rate() -> f64 {
3308 0.30
3309}
3310
3311fn default_discount_taken_rate() -> f64 {
3312 0.60
3313}
3314
3315fn default_discount_percent() -> f64 {
3316 0.02
3317}
3318
3319fn default_discount_days() -> u32 {
3320 10
3321}
3322
3323impl Default for CashDiscountConfig {
3324 fn default() -> Self {
3325 Self {
3326 eligible_rate: default_discount_eligible_rate(),
3327 taken_rate: default_discount_taken_rate(),
3328 discount_percent: default_discount_percent(),
3329 discount_days: default_discount_days(),
3330 }
3331 }
3332}
3333
3334#[derive(Debug, Clone, Serialize, Deserialize)]
3340pub struct IntercompanyConfig {
3341 #[serde(default)]
3343 pub enabled: bool,
3344 #[serde(default = "default_ic_transaction_rate")]
3346 pub ic_transaction_rate: f64,
3347 #[serde(default)]
3349 pub transfer_pricing_method: TransferPricingMethod,
3350 #[serde(default = "default_markup_percent")]
3352 pub markup_percent: f64,
3353 #[serde(default = "default_true")]
3355 pub generate_matched_pairs: bool,
3356 #[serde(default)]
3358 pub transaction_type_distribution: ICTransactionTypeDistribution,
3359 #[serde(default)]
3361 pub generate_eliminations: bool,
3362}
3363
3364fn default_ic_transaction_rate() -> f64 {
3365 0.15
3366}
3367
3368fn default_markup_percent() -> f64 {
3369 0.05
3370}
3371
3372impl Default for IntercompanyConfig {
3373 fn default() -> Self {
3374 Self {
3375 enabled: false,
3376 ic_transaction_rate: default_ic_transaction_rate(),
3377 transfer_pricing_method: TransferPricingMethod::default(),
3378 markup_percent: default_markup_percent(),
3379 generate_matched_pairs: true,
3380 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3381 generate_eliminations: false,
3382 }
3383 }
3384}
3385
3386#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3388#[serde(rename_all = "snake_case")]
3389pub enum TransferPricingMethod {
3390 #[default]
3392 CostPlus,
3393 ComparableUncontrolled,
3395 ResalePrice,
3397 TransactionalNetMargin,
3399 ProfitSplit,
3401}
3402
3403#[derive(Debug, Clone, Serialize, Deserialize)]
3405pub struct ICTransactionTypeDistribution {
3406 pub goods_sale: f64,
3408 pub service_provided: f64,
3410 pub loan: f64,
3412 pub dividend: f64,
3414 pub management_fee: f64,
3416 pub royalty: f64,
3418 pub cost_sharing: f64,
3420}
3421
3422impl Default for ICTransactionTypeDistribution {
3423 fn default() -> Self {
3424 Self {
3425 goods_sale: 0.35,
3426 service_provided: 0.20,
3427 loan: 0.10,
3428 dividend: 0.05,
3429 management_fee: 0.15,
3430 royalty: 0.10,
3431 cost_sharing: 0.05,
3432 }
3433 }
3434}
3435
3436#[derive(Debug, Clone, Serialize, Deserialize)]
3442pub struct BalanceConfig {
3443 #[serde(default)]
3445 pub generate_opening_balances: bool,
3446 #[serde(default = "default_true")]
3448 pub generate_trial_balances: bool,
3449 #[serde(default = "default_gross_margin")]
3451 pub target_gross_margin: f64,
3452 #[serde(default = "default_dso")]
3454 pub target_dso_days: u32,
3455 #[serde(default = "default_dpo")]
3457 pub target_dpo_days: u32,
3458 #[serde(default = "default_current_ratio")]
3460 pub target_current_ratio: f64,
3461 #[serde(default = "default_debt_equity")]
3463 pub target_debt_to_equity: f64,
3464 #[serde(default = "default_true")]
3466 pub validate_balance_equation: bool,
3467 #[serde(default = "default_true")]
3469 pub reconcile_subledgers: bool,
3470}
3471
3472fn default_gross_margin() -> f64 {
3473 0.35
3474}
3475
3476fn default_dso() -> u32 {
3477 45
3478}
3479
3480fn default_dpo() -> u32 {
3481 30
3482}
3483
3484fn default_current_ratio() -> f64 {
3485 1.5
3486}
3487
3488fn default_debt_equity() -> f64 {
3489 0.5
3490}
3491
3492impl Default for BalanceConfig {
3493 fn default() -> Self {
3494 Self {
3495 generate_opening_balances: false,
3496 generate_trial_balances: true,
3497 target_gross_margin: default_gross_margin(),
3498 target_dso_days: default_dso(),
3499 target_dpo_days: default_dpo(),
3500 target_current_ratio: default_current_ratio(),
3501 target_debt_to_equity: default_debt_equity(),
3502 validate_balance_equation: true,
3503 reconcile_subledgers: true,
3504 }
3505 }
3506}
3507
3508#[derive(Debug, Clone, Serialize, Deserialize)]
3517pub struct OcpmConfig {
3518 #[serde(default)]
3520 pub enabled: bool,
3521
3522 #[serde(default = "default_true")]
3524 pub generate_lifecycle_events: bool,
3525
3526 #[serde(default = "default_true")]
3528 pub include_object_relationships: bool,
3529
3530 #[serde(default = "default_true")]
3532 pub compute_variants: bool,
3533
3534 #[serde(default)]
3536 pub max_variants: usize,
3537
3538 #[serde(default)]
3540 pub p2p_process: OcpmProcessConfig,
3541
3542 #[serde(default)]
3544 pub o2c_process: OcpmProcessConfig,
3545
3546 #[serde(default)]
3548 pub output: OcpmOutputConfig,
3549}
3550
3551impl Default for OcpmConfig {
3552 fn default() -> Self {
3553 Self {
3554 enabled: false,
3555 generate_lifecycle_events: true,
3556 include_object_relationships: true,
3557 compute_variants: true,
3558 max_variants: 0,
3559 p2p_process: OcpmProcessConfig::default(),
3560 o2c_process: OcpmProcessConfig::default(),
3561 output: OcpmOutputConfig::default(),
3562 }
3563 }
3564}
3565
3566#[derive(Debug, Clone, Serialize, Deserialize)]
3568pub struct OcpmProcessConfig {
3569 #[serde(default = "default_rework_probability")]
3571 pub rework_probability: f64,
3572
3573 #[serde(default = "default_skip_probability")]
3575 pub skip_step_probability: f64,
3576
3577 #[serde(default = "default_out_of_order_probability")]
3579 pub out_of_order_probability: f64,
3580}
3581
3582fn default_rework_probability() -> f64 {
3583 0.05
3584}
3585
3586fn default_skip_probability() -> f64 {
3587 0.02
3588}
3589
3590fn default_out_of_order_probability() -> f64 {
3591 0.03
3592}
3593
3594impl Default for OcpmProcessConfig {
3595 fn default() -> Self {
3596 Self {
3597 rework_probability: default_rework_probability(),
3598 skip_step_probability: default_skip_probability(),
3599 out_of_order_probability: default_out_of_order_probability(),
3600 }
3601 }
3602}
3603
3604#[derive(Debug, Clone, Serialize, Deserialize)]
3606pub struct OcpmOutputConfig {
3607 #[serde(default = "default_true")]
3609 pub ocel_json: bool,
3610
3611 #[serde(default)]
3613 pub ocel_xml: bool,
3614
3615 #[serde(default)]
3617 pub xes: bool,
3618
3619 #[serde(default = "default_true")]
3621 pub xes_include_lifecycle: bool,
3622
3623 #[serde(default = "default_true")]
3625 pub xes_include_resources: bool,
3626
3627 #[serde(default = "default_true")]
3629 pub flattened_csv: bool,
3630
3631 #[serde(default = "default_true")]
3633 pub event_object_csv: bool,
3634
3635 #[serde(default = "default_true")]
3637 pub object_relationship_csv: bool,
3638
3639 #[serde(default = "default_true")]
3641 pub variants_csv: bool,
3642
3643 #[serde(default)]
3645 pub export_reference_models: bool,
3646}
3647
3648impl Default for OcpmOutputConfig {
3649 fn default() -> Self {
3650 Self {
3651 ocel_json: true,
3652 ocel_xml: false,
3653 xes: false,
3654 xes_include_lifecycle: true,
3655 xes_include_resources: true,
3656 flattened_csv: true,
3657 event_object_csv: true,
3658 object_relationship_csv: true,
3659 variants_csv: true,
3660 export_reference_models: false,
3661 }
3662 }
3663}
3664
3665#[derive(Debug, Clone, Serialize, Deserialize)]
3667pub struct AuditGenerationConfig {
3668 #[serde(default)]
3670 pub enabled: bool,
3671
3672 #[serde(default = "default_true")]
3674 pub generate_workpapers: bool,
3675
3676 #[serde(default)]
3678 pub engagement_types: AuditEngagementTypesConfig,
3679
3680 #[serde(default)]
3682 pub workpapers: WorkpaperConfig,
3683
3684 #[serde(default)]
3686 pub team: AuditTeamConfig,
3687
3688 #[serde(default)]
3690 pub review: ReviewWorkflowConfig,
3691}
3692
3693impl Default for AuditGenerationConfig {
3694 fn default() -> Self {
3695 Self {
3696 enabled: false,
3697 generate_workpapers: true,
3698 engagement_types: AuditEngagementTypesConfig::default(),
3699 workpapers: WorkpaperConfig::default(),
3700 team: AuditTeamConfig::default(),
3701 review: ReviewWorkflowConfig::default(),
3702 }
3703 }
3704}
3705
3706#[derive(Debug, Clone, Serialize, Deserialize)]
3708pub struct AuditEngagementTypesConfig {
3709 #[serde(default = "default_financial_audit_prob")]
3711 pub financial_statement: f64,
3712 #[serde(default = "default_sox_audit_prob")]
3714 pub sox_icfr: f64,
3715 #[serde(default = "default_integrated_audit_prob")]
3717 pub integrated: f64,
3718 #[serde(default = "default_review_prob")]
3720 pub review: f64,
3721 #[serde(default = "default_aup_prob")]
3723 pub agreed_upon_procedures: f64,
3724}
3725
3726fn default_financial_audit_prob() -> f64 {
3727 0.40
3728}
3729fn default_sox_audit_prob() -> f64 {
3730 0.20
3731}
3732fn default_integrated_audit_prob() -> f64 {
3733 0.25
3734}
3735fn default_review_prob() -> f64 {
3736 0.10
3737}
3738fn default_aup_prob() -> f64 {
3739 0.05
3740}
3741
3742impl Default for AuditEngagementTypesConfig {
3743 fn default() -> Self {
3744 Self {
3745 financial_statement: default_financial_audit_prob(),
3746 sox_icfr: default_sox_audit_prob(),
3747 integrated: default_integrated_audit_prob(),
3748 review: default_review_prob(),
3749 agreed_upon_procedures: default_aup_prob(),
3750 }
3751 }
3752}
3753
3754#[derive(Debug, Clone, Serialize, Deserialize)]
3756pub struct WorkpaperConfig {
3757 #[serde(default = "default_workpapers_per_phase")]
3759 pub average_per_phase: usize,
3760
3761 #[serde(default = "default_true")]
3763 pub include_isa_references: bool,
3764
3765 #[serde(default = "default_true")]
3767 pub include_sample_details: bool,
3768
3769 #[serde(default = "default_true")]
3771 pub include_cross_references: bool,
3772
3773 #[serde(default)]
3775 pub sampling: SamplingConfig,
3776}
3777
3778fn default_workpapers_per_phase() -> usize {
3779 5
3780}
3781
3782impl Default for WorkpaperConfig {
3783 fn default() -> Self {
3784 Self {
3785 average_per_phase: default_workpapers_per_phase(),
3786 include_isa_references: true,
3787 include_sample_details: true,
3788 include_cross_references: true,
3789 sampling: SamplingConfig::default(),
3790 }
3791 }
3792}
3793
3794#[derive(Debug, Clone, Serialize, Deserialize)]
3796pub struct SamplingConfig {
3797 #[serde(default = "default_statistical_rate")]
3799 pub statistical_rate: f64,
3800 #[serde(default = "default_judgmental_rate")]
3802 pub judgmental_rate: f64,
3803 #[serde(default = "default_haphazard_rate")]
3805 pub haphazard_rate: f64,
3806 #[serde(default = "default_complete_examination_rate")]
3808 pub complete_examination_rate: f64,
3809}
3810
3811fn default_statistical_rate() -> f64 {
3812 0.40
3813}
3814fn default_judgmental_rate() -> f64 {
3815 0.30
3816}
3817fn default_haphazard_rate() -> f64 {
3818 0.20
3819}
3820fn default_complete_examination_rate() -> f64 {
3821 0.10
3822}
3823
3824impl Default for SamplingConfig {
3825 fn default() -> Self {
3826 Self {
3827 statistical_rate: default_statistical_rate(),
3828 judgmental_rate: default_judgmental_rate(),
3829 haphazard_rate: default_haphazard_rate(),
3830 complete_examination_rate: default_complete_examination_rate(),
3831 }
3832 }
3833}
3834
3835#[derive(Debug, Clone, Serialize, Deserialize)]
3837pub struct AuditTeamConfig {
3838 #[serde(default = "default_min_team_size")]
3840 pub min_team_size: usize,
3841 #[serde(default = "default_max_team_size")]
3843 pub max_team_size: usize,
3844 #[serde(default = "default_specialist_probability")]
3846 pub specialist_probability: f64,
3847}
3848
3849fn default_min_team_size() -> usize {
3850 3
3851}
3852fn default_max_team_size() -> usize {
3853 8
3854}
3855fn default_specialist_probability() -> f64 {
3856 0.30
3857}
3858
3859impl Default for AuditTeamConfig {
3860 fn default() -> Self {
3861 Self {
3862 min_team_size: default_min_team_size(),
3863 max_team_size: default_max_team_size(),
3864 specialist_probability: default_specialist_probability(),
3865 }
3866 }
3867}
3868
3869#[derive(Debug, Clone, Serialize, Deserialize)]
3871pub struct ReviewWorkflowConfig {
3872 #[serde(default = "default_review_delay_days")]
3874 pub average_review_delay_days: u32,
3875 #[serde(default = "default_rework_probability_review")]
3877 pub rework_probability: f64,
3878 #[serde(default = "default_true")]
3880 pub require_partner_signoff: bool,
3881}
3882
3883fn default_review_delay_days() -> u32 {
3884 2
3885}
3886fn default_rework_probability_review() -> f64 {
3887 0.15
3888}
3889
3890impl Default for ReviewWorkflowConfig {
3891 fn default() -> Self {
3892 Self {
3893 average_review_delay_days: default_review_delay_days(),
3894 rework_probability: default_rework_probability_review(),
3895 require_partner_signoff: true,
3896 }
3897 }
3898}
3899
3900#[derive(Debug, Clone, Serialize, Deserialize)]
3906pub struct DataQualitySchemaConfig {
3907 #[serde(default)]
3909 pub enabled: bool,
3910 #[serde(default)]
3912 pub preset: DataQualityPreset,
3913 #[serde(default)]
3915 pub missing_values: MissingValuesSchemaConfig,
3916 #[serde(default)]
3918 pub typos: TypoSchemaConfig,
3919 #[serde(default)]
3921 pub format_variations: FormatVariationSchemaConfig,
3922 #[serde(default)]
3924 pub duplicates: DuplicateSchemaConfig,
3925 #[serde(default)]
3927 pub encoding_issues: EncodingIssueSchemaConfig,
3928 #[serde(default)]
3930 pub generate_labels: bool,
3931 #[serde(default)]
3933 pub sink_profiles: SinkQualityProfiles,
3934}
3935
3936impl Default for DataQualitySchemaConfig {
3937 fn default() -> Self {
3938 Self {
3939 enabled: false,
3940 preset: DataQualityPreset::None,
3941 missing_values: MissingValuesSchemaConfig::default(),
3942 typos: TypoSchemaConfig::default(),
3943 format_variations: FormatVariationSchemaConfig::default(),
3944 duplicates: DuplicateSchemaConfig::default(),
3945 encoding_issues: EncodingIssueSchemaConfig::default(),
3946 generate_labels: true,
3947 sink_profiles: SinkQualityProfiles::default(),
3948 }
3949 }
3950}
3951
3952impl DataQualitySchemaConfig {
3953 pub fn with_preset(preset: DataQualityPreset) -> Self {
3955 let mut config = Self {
3956 preset,
3957 ..Default::default()
3958 };
3959 config.apply_preset();
3960 config
3961 }
3962
3963 pub fn apply_preset(&mut self) {
3966 if !self.preset.overrides_settings() {
3967 return;
3968 }
3969
3970 self.enabled = true;
3971
3972 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3974 self.missing_values.rate = self.preset.missing_rate();
3975
3976 self.typos.enabled = self.preset.typo_rate() > 0.0;
3978 self.typos.char_error_rate = self.preset.typo_rate();
3979
3980 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3982 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3983 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3984 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3985
3986 self.format_variations.enabled = self.preset.format_variations_enabled();
3988
3989 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3991 self.encoding_issues.rate = self.preset.encoding_issue_rate();
3992
3993 if self.preset.ocr_errors_enabled() {
3995 self.typos.type_weights.ocr_errors = 0.3;
3996 }
3997 }
3998
3999 pub fn effective_missing_rate(&self) -> f64 {
4001 if self.preset.overrides_settings() {
4002 self.preset.missing_rate()
4003 } else {
4004 self.missing_values.rate
4005 }
4006 }
4007
4008 pub fn effective_typo_rate(&self) -> f64 {
4010 if self.preset.overrides_settings() {
4011 self.preset.typo_rate()
4012 } else {
4013 self.typos.char_error_rate
4014 }
4015 }
4016
4017 pub fn effective_duplicate_rate(&self) -> f64 {
4019 if self.preset.overrides_settings() {
4020 self.preset.duplicate_rate()
4021 } else {
4022 self.duplicates.exact_duplicate_ratio
4023 + self.duplicates.near_duplicate_ratio
4024 + self.duplicates.fuzzy_duplicate_ratio
4025 }
4026 }
4027
4028 pub fn clean() -> Self {
4030 Self::with_preset(DataQualityPreset::Clean)
4031 }
4032
4033 pub fn noisy() -> Self {
4035 Self::with_preset(DataQualityPreset::Noisy)
4036 }
4037
4038 pub fn legacy() -> Self {
4040 Self::with_preset(DataQualityPreset::Legacy)
4041 }
4042}
4043
4044#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4046#[serde(rename_all = "snake_case")]
4047pub enum DataQualityPreset {
4048 #[default]
4050 None,
4051 Minimal,
4053 Normal,
4055 High,
4057 Custom,
4059
4060 Clean,
4066 Noisy,
4069 Legacy,
4072}
4073
4074impl DataQualityPreset {
4075 pub fn missing_rate(&self) -> f64 {
4077 match self {
4078 DataQualityPreset::None => 0.0,
4079 DataQualityPreset::Minimal => 0.005,
4080 DataQualityPreset::Normal => 0.02,
4081 DataQualityPreset::High => 0.08,
4082 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4084 DataQualityPreset::Noisy => 0.05,
4085 DataQualityPreset::Legacy => 0.10,
4086 }
4087 }
4088
4089 pub fn typo_rate(&self) -> f64 {
4091 match self {
4092 DataQualityPreset::None => 0.0,
4093 DataQualityPreset::Minimal => 0.0005,
4094 DataQualityPreset::Normal => 0.002,
4095 DataQualityPreset::High => 0.01,
4096 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4098 DataQualityPreset::Noisy => 0.02,
4099 DataQualityPreset::Legacy => 0.05,
4100 }
4101 }
4102
4103 pub fn duplicate_rate(&self) -> f64 {
4105 match self {
4106 DataQualityPreset::None => 0.0,
4107 DataQualityPreset::Minimal => 0.001,
4108 DataQualityPreset::Normal => 0.005,
4109 DataQualityPreset::High => 0.02,
4110 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4112 DataQualityPreset::Noisy => 0.01,
4113 DataQualityPreset::Legacy => 0.03,
4114 }
4115 }
4116
4117 pub fn format_variations_enabled(&self) -> bool {
4119 match self {
4120 DataQualityPreset::None | DataQualityPreset::Clean => false,
4121 DataQualityPreset::Minimal => true,
4122 DataQualityPreset::Normal => true,
4123 DataQualityPreset::High => true,
4124 DataQualityPreset::Custom => true,
4125 DataQualityPreset::Noisy => true,
4126 DataQualityPreset::Legacy => true,
4127 }
4128 }
4129
4130 pub fn ocr_errors_enabled(&self) -> bool {
4132 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4133 }
4134
4135 pub fn encoding_issues_enabled(&self) -> bool {
4137 matches!(
4138 self,
4139 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4140 )
4141 }
4142
4143 pub fn encoding_issue_rate(&self) -> f64 {
4145 match self {
4146 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4147 DataQualityPreset::Normal => 0.002,
4148 DataQualityPreset::High => 0.01,
4149 DataQualityPreset::Custom => 0.0,
4150 DataQualityPreset::Noisy => 0.005,
4151 DataQualityPreset::Legacy => 0.02,
4152 }
4153 }
4154
4155 pub fn overrides_settings(&self) -> bool {
4157 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4158 }
4159
4160 pub fn description(&self) -> &'static str {
4162 match self {
4163 DataQualityPreset::None => "No data quality issues (pristine data)",
4164 DataQualityPreset::Minimal => "Very rare data quality issues",
4165 DataQualityPreset::Normal => "Realistic enterprise data quality",
4166 DataQualityPreset::High => "Messy data for stress testing",
4167 DataQualityPreset::Custom => "Custom settings from configuration",
4168 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4169 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4170 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4171 }
4172 }
4173}
4174
4175#[derive(Debug, Clone, Serialize, Deserialize)]
4177pub struct MissingValuesSchemaConfig {
4178 #[serde(default)]
4180 pub enabled: bool,
4181 #[serde(default = "default_missing_rate")]
4183 pub rate: f64,
4184 #[serde(default)]
4186 pub strategy: MissingValueStrategy,
4187 #[serde(default)]
4189 pub field_rates: std::collections::HashMap<String, f64>,
4190 #[serde(default)]
4192 pub protected_fields: Vec<String>,
4193}
4194
4195fn default_missing_rate() -> f64 {
4196 0.01
4197}
4198
4199impl Default for MissingValuesSchemaConfig {
4200 fn default() -> Self {
4201 Self {
4202 enabled: false,
4203 rate: default_missing_rate(),
4204 strategy: MissingValueStrategy::Mcar,
4205 field_rates: std::collections::HashMap::new(),
4206 protected_fields: vec![
4207 "document_id".to_string(),
4208 "company_code".to_string(),
4209 "posting_date".to_string(),
4210 ],
4211 }
4212 }
4213}
4214
4215#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4217#[serde(rename_all = "snake_case")]
4218pub enum MissingValueStrategy {
4219 #[default]
4221 Mcar,
4222 Mar,
4224 Mnar,
4226 Systematic,
4228}
4229
4230#[derive(Debug, Clone, Serialize, Deserialize)]
4232pub struct TypoSchemaConfig {
4233 #[serde(default)]
4235 pub enabled: bool,
4236 #[serde(default = "default_typo_rate")]
4238 pub char_error_rate: f64,
4239 #[serde(default)]
4241 pub type_weights: TypoTypeWeights,
4242 #[serde(default)]
4244 pub protected_fields: Vec<String>,
4245}
4246
4247fn default_typo_rate() -> f64 {
4248 0.001
4249}
4250
4251impl Default for TypoSchemaConfig {
4252 fn default() -> Self {
4253 Self {
4254 enabled: false,
4255 char_error_rate: default_typo_rate(),
4256 type_weights: TypoTypeWeights::default(),
4257 protected_fields: vec![
4258 "document_id".to_string(),
4259 "gl_account".to_string(),
4260 "company_code".to_string(),
4261 ],
4262 }
4263 }
4264}
4265
4266#[derive(Debug, Clone, Serialize, Deserialize)]
4268pub struct TypoTypeWeights {
4269 #[serde(default = "default_substitution_weight")]
4271 pub substitution: f64,
4272 #[serde(default = "default_transposition_weight")]
4274 pub transposition: f64,
4275 #[serde(default = "default_insertion_weight")]
4277 pub insertion: f64,
4278 #[serde(default = "default_deletion_weight")]
4280 pub deletion: f64,
4281 #[serde(default = "default_ocr_weight")]
4283 pub ocr_errors: f64,
4284 #[serde(default = "default_homophone_weight")]
4286 pub homophones: f64,
4287}
4288
4289fn default_substitution_weight() -> f64 {
4290 0.35
4291}
4292fn default_transposition_weight() -> f64 {
4293 0.25
4294}
4295fn default_insertion_weight() -> f64 {
4296 0.10
4297}
4298fn default_deletion_weight() -> f64 {
4299 0.15
4300}
4301fn default_ocr_weight() -> f64 {
4302 0.10
4303}
4304fn default_homophone_weight() -> f64 {
4305 0.05
4306}
4307
4308impl Default for TypoTypeWeights {
4309 fn default() -> Self {
4310 Self {
4311 substitution: default_substitution_weight(),
4312 transposition: default_transposition_weight(),
4313 insertion: default_insertion_weight(),
4314 deletion: default_deletion_weight(),
4315 ocr_errors: default_ocr_weight(),
4316 homophones: default_homophone_weight(),
4317 }
4318 }
4319}
4320
4321#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4323pub struct FormatVariationSchemaConfig {
4324 #[serde(default)]
4326 pub enabled: bool,
4327 #[serde(default)]
4329 pub dates: DateFormatVariationConfig,
4330 #[serde(default)]
4332 pub amounts: AmountFormatVariationConfig,
4333 #[serde(default)]
4335 pub identifiers: IdentifierFormatVariationConfig,
4336}
4337
4338#[derive(Debug, Clone, Serialize, Deserialize)]
4340pub struct DateFormatVariationConfig {
4341 #[serde(default)]
4343 pub enabled: bool,
4344 #[serde(default = "default_date_variation_rate")]
4346 pub rate: f64,
4347 #[serde(default = "default_true")]
4349 pub iso_format: bool,
4350 #[serde(default)]
4352 pub us_format: bool,
4353 #[serde(default)]
4355 pub eu_format: bool,
4356 #[serde(default)]
4358 pub long_format: bool,
4359}
4360
4361fn default_date_variation_rate() -> f64 {
4362 0.05
4363}
4364
4365impl Default for DateFormatVariationConfig {
4366 fn default() -> Self {
4367 Self {
4368 enabled: false,
4369 rate: default_date_variation_rate(),
4370 iso_format: true,
4371 us_format: false,
4372 eu_format: false,
4373 long_format: false,
4374 }
4375 }
4376}
4377
4378#[derive(Debug, Clone, Serialize, Deserialize)]
4380pub struct AmountFormatVariationConfig {
4381 #[serde(default)]
4383 pub enabled: bool,
4384 #[serde(default = "default_amount_variation_rate")]
4386 pub rate: f64,
4387 #[serde(default)]
4389 pub us_comma_format: bool,
4390 #[serde(default)]
4392 pub eu_format: bool,
4393 #[serde(default)]
4395 pub currency_prefix: bool,
4396 #[serde(default)]
4398 pub accounting_format: bool,
4399}
4400
4401fn default_amount_variation_rate() -> f64 {
4402 0.02
4403}
4404
4405impl Default for AmountFormatVariationConfig {
4406 fn default() -> Self {
4407 Self {
4408 enabled: false,
4409 rate: default_amount_variation_rate(),
4410 us_comma_format: false,
4411 eu_format: false,
4412 currency_prefix: false,
4413 accounting_format: false,
4414 }
4415 }
4416}
4417
4418#[derive(Debug, Clone, Serialize, Deserialize)]
4420pub struct IdentifierFormatVariationConfig {
4421 #[serde(default)]
4423 pub enabled: bool,
4424 #[serde(default = "default_identifier_variation_rate")]
4426 pub rate: f64,
4427 #[serde(default)]
4429 pub case_variations: bool,
4430 #[serde(default)]
4432 pub padding_variations: bool,
4433 #[serde(default)]
4435 pub separator_variations: bool,
4436}
4437
4438fn default_identifier_variation_rate() -> f64 {
4439 0.02
4440}
4441
4442impl Default for IdentifierFormatVariationConfig {
4443 fn default() -> Self {
4444 Self {
4445 enabled: false,
4446 rate: default_identifier_variation_rate(),
4447 case_variations: false,
4448 padding_variations: false,
4449 separator_variations: false,
4450 }
4451 }
4452}
4453
4454#[derive(Debug, Clone, Serialize, Deserialize)]
4456pub struct DuplicateSchemaConfig {
4457 #[serde(default)]
4459 pub enabled: bool,
4460 #[serde(default = "default_duplicate_rate")]
4462 pub rate: f64,
4463 #[serde(default = "default_exact_duplicate_ratio")]
4465 pub exact_duplicate_ratio: f64,
4466 #[serde(default = "default_near_duplicate_ratio")]
4468 pub near_duplicate_ratio: f64,
4469 #[serde(default = "default_fuzzy_duplicate_ratio")]
4471 pub fuzzy_duplicate_ratio: f64,
4472 #[serde(default = "default_max_date_offset")]
4474 pub max_date_offset_days: u32,
4475 #[serde(default = "default_max_amount_variance")]
4477 pub max_amount_variance: f64,
4478}
4479
4480fn default_duplicate_rate() -> f64 {
4481 0.005
4482}
4483fn default_exact_duplicate_ratio() -> f64 {
4484 0.4
4485}
4486fn default_near_duplicate_ratio() -> f64 {
4487 0.35
4488}
4489fn default_fuzzy_duplicate_ratio() -> f64 {
4490 0.25
4491}
4492fn default_max_date_offset() -> u32 {
4493 3
4494}
4495fn default_max_amount_variance() -> f64 {
4496 0.01
4497}
4498
4499impl Default for DuplicateSchemaConfig {
4500 fn default() -> Self {
4501 Self {
4502 enabled: false,
4503 rate: default_duplicate_rate(),
4504 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4505 near_duplicate_ratio: default_near_duplicate_ratio(),
4506 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4507 max_date_offset_days: default_max_date_offset(),
4508 max_amount_variance: default_max_amount_variance(),
4509 }
4510 }
4511}
4512
4513#[derive(Debug, Clone, Serialize, Deserialize)]
4515pub struct EncodingIssueSchemaConfig {
4516 #[serde(default)]
4518 pub enabled: bool,
4519 #[serde(default = "default_encoding_rate")]
4521 pub rate: f64,
4522 #[serde(default)]
4524 pub mojibake: bool,
4525 #[serde(default)]
4527 pub html_entities: bool,
4528 #[serde(default)]
4530 pub bom_issues: bool,
4531}
4532
4533fn default_encoding_rate() -> f64 {
4534 0.001
4535}
4536
4537impl Default for EncodingIssueSchemaConfig {
4538 fn default() -> Self {
4539 Self {
4540 enabled: false,
4541 rate: default_encoding_rate(),
4542 mojibake: false,
4543 html_entities: false,
4544 bom_issues: false,
4545 }
4546 }
4547}
4548
4549#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4551pub struct SinkQualityProfiles {
4552 #[serde(default)]
4554 pub csv: Option<SinkQualityOverride>,
4555 #[serde(default)]
4557 pub json: Option<SinkQualityOverride>,
4558 #[serde(default)]
4560 pub parquet: Option<SinkQualityOverride>,
4561}
4562
4563#[derive(Debug, Clone, Serialize, Deserialize)]
4565pub struct SinkQualityOverride {
4566 pub enabled: Option<bool>,
4568 pub missing_rate: Option<f64>,
4570 pub typo_rate: Option<f64>,
4572 pub format_variation_rate: Option<f64>,
4574 pub duplicate_rate: Option<f64>,
4576}
4577
4578#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4590pub struct AccountingStandardsConfig {
4591 #[serde(default)]
4593 pub enabled: bool,
4594
4595 #[serde(default)]
4597 pub framework: AccountingFrameworkConfig,
4598
4599 #[serde(default)]
4601 pub revenue_recognition: RevenueRecognitionConfig,
4602
4603 #[serde(default)]
4605 pub leases: LeaseAccountingConfig,
4606
4607 #[serde(default)]
4609 pub fair_value: FairValueConfig,
4610
4611 #[serde(default)]
4613 pub impairment: ImpairmentConfig,
4614
4615 #[serde(default)]
4617 pub generate_differences: bool,
4618}
4619
4620#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4622#[serde(rename_all = "snake_case")]
4623pub enum AccountingFrameworkConfig {
4624 #[default]
4626 UsGaap,
4627 Ifrs,
4629 DualReporting,
4631}
4632
4633#[derive(Debug, Clone, Serialize, Deserialize)]
4635pub struct RevenueRecognitionConfig {
4636 #[serde(default)]
4638 pub enabled: bool,
4639
4640 #[serde(default = "default_true")]
4642 pub generate_contracts: bool,
4643
4644 #[serde(default = "default_avg_obligations")]
4646 pub avg_obligations_per_contract: f64,
4647
4648 #[serde(default = "default_variable_consideration_rate")]
4650 pub variable_consideration_rate: f64,
4651
4652 #[serde(default = "default_over_time_rate")]
4654 pub over_time_recognition_rate: f64,
4655
4656 #[serde(default = "default_contract_count")]
4658 pub contract_count: usize,
4659}
4660
4661fn default_avg_obligations() -> f64 {
4662 2.0
4663}
4664
4665fn default_variable_consideration_rate() -> f64 {
4666 0.15
4667}
4668
4669fn default_over_time_rate() -> f64 {
4670 0.30
4671}
4672
4673fn default_contract_count() -> usize {
4674 100
4675}
4676
4677impl Default for RevenueRecognitionConfig {
4678 fn default() -> Self {
4679 Self {
4680 enabled: false,
4681 generate_contracts: true,
4682 avg_obligations_per_contract: default_avg_obligations(),
4683 variable_consideration_rate: default_variable_consideration_rate(),
4684 over_time_recognition_rate: default_over_time_rate(),
4685 contract_count: default_contract_count(),
4686 }
4687 }
4688}
4689
4690#[derive(Debug, Clone, Serialize, Deserialize)]
4692pub struct LeaseAccountingConfig {
4693 #[serde(default)]
4695 pub enabled: bool,
4696
4697 #[serde(default = "default_lease_count")]
4699 pub lease_count: usize,
4700
4701 #[serde(default = "default_finance_lease_pct")]
4703 pub finance_lease_percent: f64,
4704
4705 #[serde(default = "default_avg_lease_term")]
4707 pub avg_lease_term_months: u32,
4708
4709 #[serde(default = "default_true")]
4711 pub generate_amortization: bool,
4712
4713 #[serde(default = "default_real_estate_pct")]
4715 pub real_estate_percent: f64,
4716}
4717
4718fn default_lease_count() -> usize {
4719 50
4720}
4721
4722fn default_finance_lease_pct() -> f64 {
4723 0.30
4724}
4725
4726fn default_avg_lease_term() -> u32 {
4727 60
4728}
4729
4730fn default_real_estate_pct() -> f64 {
4731 0.40
4732}
4733
4734impl Default for LeaseAccountingConfig {
4735 fn default() -> Self {
4736 Self {
4737 enabled: false,
4738 lease_count: default_lease_count(),
4739 finance_lease_percent: default_finance_lease_pct(),
4740 avg_lease_term_months: default_avg_lease_term(),
4741 generate_amortization: true,
4742 real_estate_percent: default_real_estate_pct(),
4743 }
4744 }
4745}
4746
4747#[derive(Debug, Clone, Serialize, Deserialize)]
4749pub struct FairValueConfig {
4750 #[serde(default)]
4752 pub enabled: bool,
4753
4754 #[serde(default = "default_fv_count")]
4756 pub measurement_count: usize,
4757
4758 #[serde(default = "default_level1_pct")]
4760 pub level1_percent: f64,
4761
4762 #[serde(default = "default_level2_pct")]
4764 pub level2_percent: f64,
4765
4766 #[serde(default = "default_level3_pct")]
4768 pub level3_percent: f64,
4769
4770 #[serde(default)]
4772 pub include_sensitivity_analysis: bool,
4773}
4774
4775fn default_fv_count() -> usize {
4776 25
4777}
4778
4779fn default_level1_pct() -> f64 {
4780 0.40
4781}
4782
4783fn default_level2_pct() -> f64 {
4784 0.35
4785}
4786
4787fn default_level3_pct() -> f64 {
4788 0.25
4789}
4790
4791impl Default for FairValueConfig {
4792 fn default() -> Self {
4793 Self {
4794 enabled: false,
4795 measurement_count: default_fv_count(),
4796 level1_percent: default_level1_pct(),
4797 level2_percent: default_level2_pct(),
4798 level3_percent: default_level3_pct(),
4799 include_sensitivity_analysis: false,
4800 }
4801 }
4802}
4803
4804#[derive(Debug, Clone, Serialize, Deserialize)]
4806pub struct ImpairmentConfig {
4807 #[serde(default)]
4809 pub enabled: bool,
4810
4811 #[serde(default = "default_impairment_count")]
4813 pub test_count: usize,
4814
4815 #[serde(default = "default_impairment_rate")]
4817 pub impairment_rate: f64,
4818
4819 #[serde(default = "default_true")]
4821 pub generate_projections: bool,
4822
4823 #[serde(default)]
4825 pub include_goodwill: bool,
4826}
4827
4828fn default_impairment_count() -> usize {
4829 15
4830}
4831
4832fn default_impairment_rate() -> f64 {
4833 0.10
4834}
4835
4836impl Default for ImpairmentConfig {
4837 fn default() -> Self {
4838 Self {
4839 enabled: false,
4840 test_count: default_impairment_count(),
4841 impairment_rate: default_impairment_rate(),
4842 generate_projections: true,
4843 include_goodwill: false,
4844 }
4845 }
4846}
4847
4848#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4861pub struct AuditStandardsConfig {
4862 #[serde(default)]
4864 pub enabled: bool,
4865
4866 #[serde(default)]
4868 pub isa_compliance: IsaComplianceConfig,
4869
4870 #[serde(default)]
4872 pub analytical_procedures: AnalyticalProceduresConfig,
4873
4874 #[serde(default)]
4876 pub confirmations: ConfirmationsConfig,
4877
4878 #[serde(default)]
4880 pub opinion: AuditOpinionConfig,
4881
4882 #[serde(default)]
4884 pub generate_audit_trail: bool,
4885
4886 #[serde(default)]
4888 pub sox: SoxComplianceConfig,
4889
4890 #[serde(default)]
4892 pub pcaob: PcaobConfig,
4893}
4894
4895#[derive(Debug, Clone, Serialize, Deserialize)]
4897pub struct IsaComplianceConfig {
4898 #[serde(default)]
4900 pub enabled: bool,
4901
4902 #[serde(default = "default_compliance_level")]
4904 pub compliance_level: String,
4905
4906 #[serde(default = "default_true")]
4908 pub generate_isa_mappings: bool,
4909
4910 #[serde(default = "default_true")]
4912 pub generate_coverage_summary: bool,
4913
4914 #[serde(default)]
4916 pub include_pcaob: bool,
4917
4918 #[serde(default = "default_audit_framework")]
4920 pub framework: String,
4921}
4922
4923fn default_compliance_level() -> String {
4924 "standard".to_string()
4925}
4926
4927fn default_audit_framework() -> String {
4928 "isa".to_string()
4929}
4930
4931impl Default for IsaComplianceConfig {
4932 fn default() -> Self {
4933 Self {
4934 enabled: false,
4935 compliance_level: default_compliance_level(),
4936 generate_isa_mappings: true,
4937 generate_coverage_summary: true,
4938 include_pcaob: false,
4939 framework: default_audit_framework(),
4940 }
4941 }
4942}
4943
4944#[derive(Debug, Clone, Serialize, Deserialize)]
4946pub struct AnalyticalProceduresConfig {
4947 #[serde(default)]
4949 pub enabled: bool,
4950
4951 #[serde(default = "default_procedures_per_account")]
4953 pub procedures_per_account: usize,
4954
4955 #[serde(default = "default_variance_probability")]
4957 pub variance_probability: f64,
4958
4959 #[serde(default = "default_true")]
4961 pub generate_investigations: bool,
4962
4963 #[serde(default = "default_true")]
4965 pub include_ratio_analysis: bool,
4966}
4967
4968fn default_procedures_per_account() -> usize {
4969 3
4970}
4971
4972fn default_variance_probability() -> f64 {
4973 0.20
4974}
4975
4976impl Default for AnalyticalProceduresConfig {
4977 fn default() -> Self {
4978 Self {
4979 enabled: false,
4980 procedures_per_account: default_procedures_per_account(),
4981 variance_probability: default_variance_probability(),
4982 generate_investigations: true,
4983 include_ratio_analysis: true,
4984 }
4985 }
4986}
4987
4988#[derive(Debug, Clone, Serialize, Deserialize)]
4990pub struct ConfirmationsConfig {
4991 #[serde(default)]
4993 pub enabled: bool,
4994
4995 #[serde(default = "default_confirmation_count")]
4997 pub confirmation_count: usize,
4998
4999 #[serde(default = "default_positive_response_rate")]
5001 pub positive_response_rate: f64,
5002
5003 #[serde(default = "default_exception_rate_confirm")]
5005 pub exception_rate: f64,
5006
5007 #[serde(default = "default_non_response_rate")]
5009 pub non_response_rate: f64,
5010
5011 #[serde(default = "default_true")]
5013 pub generate_alternative_procedures: bool,
5014}
5015
5016fn default_confirmation_count() -> usize {
5017 50
5018}
5019
5020fn default_positive_response_rate() -> f64 {
5021 0.85
5022}
5023
5024fn default_exception_rate_confirm() -> f64 {
5025 0.10
5026}
5027
5028fn default_non_response_rate() -> f64 {
5029 0.05
5030}
5031
5032impl Default for ConfirmationsConfig {
5033 fn default() -> Self {
5034 Self {
5035 enabled: false,
5036 confirmation_count: default_confirmation_count(),
5037 positive_response_rate: default_positive_response_rate(),
5038 exception_rate: default_exception_rate_confirm(),
5039 non_response_rate: default_non_response_rate(),
5040 generate_alternative_procedures: true,
5041 }
5042 }
5043}
5044
5045#[derive(Debug, Clone, Serialize, Deserialize)]
5047pub struct AuditOpinionConfig {
5048 #[serde(default)]
5050 pub enabled: bool,
5051
5052 #[serde(default = "default_true")]
5054 pub generate_kam: bool,
5055
5056 #[serde(default = "default_kam_count")]
5058 pub average_kam_count: usize,
5059
5060 #[serde(default = "default_modified_opinion_rate")]
5062 pub modified_opinion_rate: f64,
5063
5064 #[serde(default)]
5066 pub include_emphasis_of_matter: bool,
5067
5068 #[serde(default = "default_true")]
5070 pub include_going_concern: bool,
5071}
5072
5073fn default_kam_count() -> usize {
5074 3
5075}
5076
5077fn default_modified_opinion_rate() -> f64 {
5078 0.05
5079}
5080
5081impl Default for AuditOpinionConfig {
5082 fn default() -> Self {
5083 Self {
5084 enabled: false,
5085 generate_kam: true,
5086 average_kam_count: default_kam_count(),
5087 modified_opinion_rate: default_modified_opinion_rate(),
5088 include_emphasis_of_matter: false,
5089 include_going_concern: true,
5090 }
5091 }
5092}
5093
5094#[derive(Debug, Clone, Serialize, Deserialize)]
5096pub struct SoxComplianceConfig {
5097 #[serde(default)]
5099 pub enabled: bool,
5100
5101 #[serde(default = "default_true")]
5103 pub generate_302_certifications: bool,
5104
5105 #[serde(default = "default_true")]
5107 pub generate_404_assessments: bool,
5108
5109 #[serde(default = "default_sox_materiality_threshold")]
5111 pub materiality_threshold: f64,
5112
5113 #[serde(default = "default_material_weakness_rate")]
5115 pub material_weakness_rate: f64,
5116
5117 #[serde(default = "default_significant_deficiency_rate")]
5119 pub significant_deficiency_rate: f64,
5120}
5121
5122fn default_material_weakness_rate() -> f64 {
5123 0.02
5124}
5125
5126fn default_significant_deficiency_rate() -> f64 {
5127 0.08
5128}
5129
5130impl Default for SoxComplianceConfig {
5131 fn default() -> Self {
5132 Self {
5133 enabled: false,
5134 generate_302_certifications: true,
5135 generate_404_assessments: true,
5136 materiality_threshold: default_sox_materiality_threshold(),
5137 material_weakness_rate: default_material_weakness_rate(),
5138 significant_deficiency_rate: default_significant_deficiency_rate(),
5139 }
5140 }
5141}
5142
5143#[derive(Debug, Clone, Serialize, Deserialize)]
5145pub struct PcaobConfig {
5146 #[serde(default)]
5148 pub enabled: bool,
5149
5150 #[serde(default)]
5152 pub is_pcaob_audit: bool,
5153
5154 #[serde(default = "default_true")]
5156 pub generate_cam: bool,
5157
5158 #[serde(default)]
5160 pub include_icfr_opinion: bool,
5161
5162 #[serde(default)]
5164 pub generate_standard_mappings: bool,
5165}
5166
5167impl Default for PcaobConfig {
5168 fn default() -> Self {
5169 Self {
5170 enabled: false,
5171 is_pcaob_audit: false,
5172 generate_cam: true,
5173 include_icfr_opinion: false,
5174 generate_standard_mappings: false,
5175 }
5176 }
5177}
5178
5179#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5192pub struct AdvancedDistributionConfig {
5193 #[serde(default)]
5195 pub enabled: bool,
5196
5197 #[serde(default)]
5199 pub amounts: MixtureDistributionSchemaConfig,
5200
5201 #[serde(default)]
5203 pub correlations: CorrelationSchemaConfig,
5204
5205 #[serde(default)]
5207 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5208
5209 #[serde(default)]
5211 pub regime_changes: RegimeChangeSchemaConfig,
5212
5213 #[serde(default)]
5215 pub industry_profile: Option<IndustryProfileType>,
5216
5217 #[serde(default)]
5219 pub validation: StatisticalValidationSchemaConfig,
5220}
5221
5222#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5224#[serde(rename_all = "snake_case")]
5225pub enum IndustryProfileType {
5226 Retail,
5228 Manufacturing,
5230 FinancialServices,
5232 Healthcare,
5234 Technology,
5236}
5237
5238#[derive(Debug, Clone, Serialize, Deserialize)]
5240pub struct MixtureDistributionSchemaConfig {
5241 #[serde(default)]
5243 pub enabled: bool,
5244
5245 #[serde(default = "default_mixture_type")]
5247 pub distribution_type: MixtureDistributionType,
5248
5249 #[serde(default)]
5251 pub components: Vec<MixtureComponentConfig>,
5252
5253 #[serde(default = "default_min_amount")]
5255 pub min_value: f64,
5256
5257 #[serde(default)]
5259 pub max_value: Option<f64>,
5260
5261 #[serde(default = "default_decimal_places")]
5263 pub decimal_places: u8,
5264}
5265
5266fn default_mixture_type() -> MixtureDistributionType {
5267 MixtureDistributionType::LogNormal
5268}
5269
5270fn default_min_amount() -> f64 {
5271 0.01
5272}
5273
5274fn default_decimal_places() -> u8 {
5275 2
5276}
5277
5278impl Default for MixtureDistributionSchemaConfig {
5279 fn default() -> Self {
5280 Self {
5281 enabled: false,
5282 distribution_type: MixtureDistributionType::LogNormal,
5283 components: Vec::new(),
5284 min_value: 0.01,
5285 max_value: None,
5286 decimal_places: 2,
5287 }
5288 }
5289}
5290
5291#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5293#[serde(rename_all = "snake_case")]
5294pub enum MixtureDistributionType {
5295 Gaussian,
5297 #[default]
5299 LogNormal,
5300}
5301
5302#[derive(Debug, Clone, Serialize, Deserialize)]
5304pub struct MixtureComponentConfig {
5305 pub weight: f64,
5307
5308 pub mu: f64,
5310
5311 pub sigma: f64,
5313
5314 #[serde(default)]
5316 pub label: Option<String>,
5317}
5318
5319#[derive(Debug, Clone, Serialize, Deserialize)]
5321pub struct CorrelationSchemaConfig {
5322 #[serde(default)]
5324 pub enabled: bool,
5325
5326 #[serde(default)]
5328 pub copula_type: CopulaSchemaType,
5329
5330 #[serde(default)]
5332 pub fields: Vec<CorrelatedFieldConfig>,
5333
5334 #[serde(default)]
5337 pub matrix: Vec<f64>,
5338
5339 #[serde(default)]
5341 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5342}
5343
5344impl Default for CorrelationSchemaConfig {
5345 fn default() -> Self {
5346 Self {
5347 enabled: false,
5348 copula_type: CopulaSchemaType::Gaussian,
5349 fields: Vec::new(),
5350 matrix: Vec::new(),
5351 expected_correlations: Vec::new(),
5352 }
5353 }
5354}
5355
5356#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5358#[serde(rename_all = "snake_case")]
5359pub enum CopulaSchemaType {
5360 #[default]
5362 Gaussian,
5363 Clayton,
5365 Gumbel,
5367 Frank,
5369 StudentT,
5371}
5372
5373#[derive(Debug, Clone, Serialize, Deserialize)]
5375pub struct CorrelatedFieldConfig {
5376 pub name: String,
5378
5379 #[serde(default)]
5381 pub distribution: MarginalDistributionConfig,
5382}
5383
5384#[derive(Debug, Clone, Serialize, Deserialize)]
5386#[serde(tag = "type", rename_all = "snake_case")]
5387pub enum MarginalDistributionConfig {
5388 Normal {
5390 mu: f64,
5392 sigma: f64,
5394 },
5395 LogNormal {
5397 mu: f64,
5399 sigma: f64,
5401 },
5402 Uniform {
5404 min: f64,
5406 max: f64,
5408 },
5409 DiscreteUniform {
5411 min: i32,
5413 max: i32,
5415 },
5416}
5417
5418impl Default for MarginalDistributionConfig {
5419 fn default() -> Self {
5420 Self::Normal {
5421 mu: 0.0,
5422 sigma: 1.0,
5423 }
5424 }
5425}
5426
5427#[derive(Debug, Clone, Serialize, Deserialize)]
5429pub struct ExpectedCorrelationConfig {
5430 pub field1: String,
5432 pub field2: String,
5434 pub expected_r: f64,
5436 #[serde(default = "default_correlation_tolerance")]
5438 pub tolerance: f64,
5439}
5440
5441fn default_correlation_tolerance() -> f64 {
5442 0.10
5443}
5444
5445#[derive(Debug, Clone, Serialize, Deserialize)]
5447pub struct ConditionalDistributionSchemaConfig {
5448 pub output_field: String,
5450
5451 pub input_field: String,
5453
5454 #[serde(default)]
5456 pub breakpoints: Vec<ConditionalBreakpointConfig>,
5457
5458 #[serde(default)]
5460 pub default_distribution: ConditionalDistributionParamsConfig,
5461
5462 #[serde(default)]
5464 pub min_value: Option<f64>,
5465
5466 #[serde(default)]
5468 pub max_value: Option<f64>,
5469
5470 #[serde(default = "default_decimal_places")]
5472 pub decimal_places: u8,
5473}
5474
5475#[derive(Debug, Clone, Serialize, Deserialize)]
5477pub struct ConditionalBreakpointConfig {
5478 pub threshold: f64,
5480
5481 pub distribution: ConditionalDistributionParamsConfig,
5483}
5484
5485#[derive(Debug, Clone, Serialize, Deserialize)]
5487#[serde(tag = "type", rename_all = "snake_case")]
5488pub enum ConditionalDistributionParamsConfig {
5489 Fixed {
5491 value: f64,
5493 },
5494 Normal {
5496 mu: f64,
5498 sigma: f64,
5500 },
5501 LogNormal {
5503 mu: f64,
5505 sigma: f64,
5507 },
5508 Uniform {
5510 min: f64,
5512 max: f64,
5514 },
5515 Beta {
5517 alpha: f64,
5519 beta: f64,
5521 min: f64,
5523 max: f64,
5525 },
5526 Discrete {
5528 values: Vec<f64>,
5530 weights: Vec<f64>,
5532 },
5533}
5534
5535impl Default for ConditionalDistributionParamsConfig {
5536 fn default() -> Self {
5537 Self::Normal {
5538 mu: 0.0,
5539 sigma: 1.0,
5540 }
5541 }
5542}
5543
5544#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5546pub struct RegimeChangeSchemaConfig {
5547 #[serde(default)]
5549 pub enabled: bool,
5550
5551 #[serde(default)]
5553 pub changes: Vec<RegimeChangeEventConfig>,
5554
5555 #[serde(default)]
5557 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5558
5559 #[serde(default)]
5561 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5562}
5563
5564#[derive(Debug, Clone, Serialize, Deserialize)]
5566pub struct RegimeChangeEventConfig {
5567 pub date: String,
5569
5570 pub change_type: RegimeChangeTypeConfig,
5572
5573 #[serde(default)]
5575 pub description: Option<String>,
5576
5577 #[serde(default)]
5579 pub effects: Vec<RegimeEffectConfig>,
5580}
5581
5582#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5584#[serde(rename_all = "snake_case")]
5585pub enum RegimeChangeTypeConfig {
5586 Acquisition,
5588 Divestiture,
5590 PriceIncrease,
5592 PriceDecrease,
5594 ProductLaunch,
5596 ProductDiscontinuation,
5598 PolicyChange,
5600 CompetitorEntry,
5602 Custom,
5604}
5605
5606#[derive(Debug, Clone, Serialize, Deserialize)]
5608pub struct RegimeEffectConfig {
5609 pub field: String,
5611
5612 pub multiplier: f64,
5614}
5615
5616#[derive(Debug, Clone, Serialize, Deserialize)]
5618pub struct EconomicCycleSchemaConfig {
5619 #[serde(default)]
5621 pub enabled: bool,
5622
5623 #[serde(default = "default_cycle_period")]
5625 pub period_months: u32,
5626
5627 #[serde(default = "default_cycle_amplitude")]
5629 pub amplitude: f64,
5630
5631 #[serde(default)]
5633 pub phase_offset: u32,
5634
5635 #[serde(default)]
5637 pub recessions: Vec<RecessionPeriodConfig>,
5638}
5639
5640fn default_cycle_period() -> u32 {
5641 48
5642}
5643
5644fn default_cycle_amplitude() -> f64 {
5645 0.15
5646}
5647
5648impl Default for EconomicCycleSchemaConfig {
5649 fn default() -> Self {
5650 Self {
5651 enabled: false,
5652 period_months: 48,
5653 amplitude: 0.15,
5654 phase_offset: 0,
5655 recessions: Vec::new(),
5656 }
5657 }
5658}
5659
5660#[derive(Debug, Clone, Serialize, Deserialize)]
5662pub struct RecessionPeriodConfig {
5663 pub start_month: u32,
5665
5666 pub duration_months: u32,
5668
5669 #[serde(default = "default_recession_severity")]
5671 pub severity: f64,
5672}
5673
5674fn default_recession_severity() -> f64 {
5675 0.20
5676}
5677
5678#[derive(Debug, Clone, Serialize, Deserialize)]
5680pub struct ParameterDriftSchemaConfig {
5681 pub parameter: String,
5683
5684 pub drift_type: ParameterDriftTypeConfig,
5686
5687 pub start_value: f64,
5689
5690 pub end_value: f64,
5692
5693 #[serde(default)]
5695 pub start_period: u32,
5696
5697 #[serde(default)]
5699 pub end_period: Option<u32>,
5700}
5701
5702#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5704#[serde(rename_all = "snake_case")]
5705pub enum ParameterDriftTypeConfig {
5706 #[default]
5708 Linear,
5709 Exponential,
5711 Logistic,
5713 Step,
5715}
5716
5717#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5719pub struct StatisticalValidationSchemaConfig {
5720 #[serde(default)]
5722 pub enabled: bool,
5723
5724 #[serde(default)]
5726 pub tests: Vec<StatisticalTestConfig>,
5727
5728 #[serde(default)]
5730 pub reporting: ValidationReportingConfig,
5731}
5732
5733#[derive(Debug, Clone, Serialize, Deserialize)]
5735#[serde(tag = "type", rename_all = "snake_case")]
5736pub enum StatisticalTestConfig {
5737 BenfordFirstDigit {
5739 #[serde(default = "default_benford_threshold")]
5741 threshold_mad: f64,
5742 #[serde(default = "default_benford_warning")]
5744 warning_mad: f64,
5745 },
5746 DistributionFit {
5748 target: TargetDistributionConfig,
5750 #[serde(default = "default_ks_significance")]
5752 ks_significance: f64,
5753 #[serde(default)]
5755 method: DistributionFitMethod,
5756 },
5757 CorrelationCheck {
5759 expected_correlations: Vec<ExpectedCorrelationConfig>,
5761 },
5762 ChiSquared {
5764 #[serde(default = "default_chi_squared_bins")]
5766 bins: usize,
5767 #[serde(default = "default_chi_squared_significance")]
5769 significance: f64,
5770 },
5771 AndersonDarling {
5773 target: TargetDistributionConfig,
5775 #[serde(default = "default_ad_significance")]
5777 significance: f64,
5778 },
5779}
5780
5781fn default_benford_threshold() -> f64 {
5782 0.015
5783}
5784
5785fn default_benford_warning() -> f64 {
5786 0.010
5787}
5788
5789fn default_ks_significance() -> f64 {
5790 0.05
5791}
5792
5793fn default_chi_squared_bins() -> usize {
5794 10
5795}
5796
5797fn default_chi_squared_significance() -> f64 {
5798 0.05
5799}
5800
5801fn default_ad_significance() -> f64 {
5802 0.05
5803}
5804
5805#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5807#[serde(rename_all = "snake_case")]
5808pub enum TargetDistributionConfig {
5809 Normal,
5811 #[default]
5813 LogNormal,
5814 Exponential,
5816 Uniform,
5818}
5819
5820#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5822#[serde(rename_all = "snake_case")]
5823pub enum DistributionFitMethod {
5824 #[default]
5826 KolmogorovSmirnov,
5827 AndersonDarling,
5829 ChiSquared,
5831}
5832
5833#[derive(Debug, Clone, Serialize, Deserialize)]
5835pub struct ValidationReportingConfig {
5836 #[serde(default)]
5838 pub output_report: bool,
5839
5840 #[serde(default)]
5842 pub format: ValidationReportFormat,
5843
5844 #[serde(default)]
5846 pub fail_on_error: bool,
5847
5848 #[serde(default = "default_true")]
5850 pub include_details: bool,
5851}
5852
5853impl Default for ValidationReportingConfig {
5854 fn default() -> Self {
5855 Self {
5856 output_report: false,
5857 format: ValidationReportFormat::Json,
5858 fail_on_error: false,
5859 include_details: true,
5860 }
5861 }
5862}
5863
5864#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5866#[serde(rename_all = "snake_case")]
5867pub enum ValidationReportFormat {
5868 #[default]
5870 Json,
5871 Yaml,
5873 Html,
5875}
5876
5877#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5889pub struct TemporalPatternsConfig {
5890 #[serde(default)]
5892 pub enabled: bool,
5893
5894 #[serde(default)]
5896 pub business_days: BusinessDaySchemaConfig,
5897
5898 #[serde(default)]
5900 pub calendars: CalendarSchemaConfig,
5901
5902 #[serde(default)]
5904 pub period_end: PeriodEndSchemaConfig,
5905
5906 #[serde(default)]
5908 pub processing_lags: ProcessingLagSchemaConfig,
5909
5910 #[serde(default)]
5912 pub fiscal_calendar: FiscalCalendarSchemaConfig,
5913
5914 #[serde(default)]
5916 pub intraday: IntraDaySchemaConfig,
5917
5918 #[serde(default)]
5920 pub timezones: TimezoneSchemaConfig,
5921}
5922
5923#[derive(Debug, Clone, Serialize, Deserialize)]
5925pub struct BusinessDaySchemaConfig {
5926 #[serde(default = "default_true")]
5928 pub enabled: bool,
5929
5930 #[serde(default = "default_half_day_policy")]
5932 pub half_day_policy: String,
5933
5934 #[serde(default)]
5936 pub settlement_rules: SettlementRulesSchemaConfig,
5937
5938 #[serde(default = "default_month_end_convention")]
5940 pub month_end_convention: String,
5941
5942 #[serde(default)]
5944 pub weekend_days: Option<Vec<String>>,
5945}
5946
5947fn default_half_day_policy() -> String {
5948 "half_day".to_string()
5949}
5950
5951fn default_month_end_convention() -> String {
5952 "modified_following".to_string()
5953}
5954
5955impl Default for BusinessDaySchemaConfig {
5956 fn default() -> Self {
5957 Self {
5958 enabled: true,
5959 half_day_policy: "half_day".to_string(),
5960 settlement_rules: SettlementRulesSchemaConfig::default(),
5961 month_end_convention: "modified_following".to_string(),
5962 weekend_days: None,
5963 }
5964 }
5965}
5966
5967#[derive(Debug, Clone, Serialize, Deserialize)]
5969pub struct SettlementRulesSchemaConfig {
5970 #[serde(default = "default_settlement_2")]
5972 pub equity_days: i32,
5973
5974 #[serde(default = "default_settlement_1")]
5976 pub government_bonds_days: i32,
5977
5978 #[serde(default = "default_settlement_2")]
5980 pub fx_spot_days: i32,
5981
5982 #[serde(default = "default_settlement_2")]
5984 pub corporate_bonds_days: i32,
5985
5986 #[serde(default = "default_wire_cutoff")]
5988 pub wire_cutoff_time: String,
5989
5990 #[serde(default = "default_settlement_1")]
5992 pub wire_international_days: i32,
5993
5994 #[serde(default = "default_settlement_1")]
5996 pub ach_days: i32,
5997}
5998
5999fn default_settlement_1() -> i32 {
6000 1
6001}
6002
6003fn default_settlement_2() -> i32 {
6004 2
6005}
6006
6007fn default_wire_cutoff() -> String {
6008 "14:00".to_string()
6009}
6010
6011impl Default for SettlementRulesSchemaConfig {
6012 fn default() -> Self {
6013 Self {
6014 equity_days: 2,
6015 government_bonds_days: 1,
6016 fx_spot_days: 2,
6017 corporate_bonds_days: 2,
6018 wire_cutoff_time: "14:00".to_string(),
6019 wire_international_days: 1,
6020 ach_days: 1,
6021 }
6022 }
6023}
6024
6025#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6027pub struct CalendarSchemaConfig {
6028 #[serde(default)]
6030 pub regions: Vec<String>,
6031
6032 #[serde(default)]
6034 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6035}
6036
6037#[derive(Debug, Clone, Serialize, Deserialize)]
6039pub struct CustomHolidaySchemaConfig {
6040 pub name: String,
6042 pub month: u8,
6044 pub day: u8,
6046 #[serde(default = "default_holiday_multiplier")]
6048 pub activity_multiplier: f64,
6049}
6050
6051fn default_holiday_multiplier() -> f64 {
6052 0.05
6053}
6054
6055#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6057pub struct PeriodEndSchemaConfig {
6058 #[serde(default)]
6060 pub model: Option<String>,
6061
6062 #[serde(default)]
6064 pub month_end: Option<PeriodEndModelSchemaConfig>,
6065
6066 #[serde(default)]
6068 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6069
6070 #[serde(default)]
6072 pub year_end: Option<PeriodEndModelSchemaConfig>,
6073}
6074
6075#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6077pub struct PeriodEndModelSchemaConfig {
6078 #[serde(default)]
6080 pub inherit_from: Option<String>,
6081
6082 #[serde(default)]
6084 pub additional_multiplier: Option<f64>,
6085
6086 #[serde(default)]
6088 pub start_day: Option<i32>,
6089
6090 #[serde(default)]
6092 pub base_multiplier: Option<f64>,
6093
6094 #[serde(default)]
6096 pub peak_multiplier: Option<f64>,
6097
6098 #[serde(default)]
6100 pub decay_rate: Option<f64>,
6101
6102 #[serde(default)]
6104 pub sustained_high_days: Option<i32>,
6105}
6106
6107#[derive(Debug, Clone, Serialize, Deserialize)]
6109pub struct ProcessingLagSchemaConfig {
6110 #[serde(default = "default_true")]
6112 pub enabled: bool,
6113
6114 #[serde(default)]
6116 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6117
6118 #[serde(default)]
6120 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6121
6122 #[serde(default)]
6124 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6125
6126 #[serde(default)]
6128 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6129
6130 #[serde(default)]
6132 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6133
6134 #[serde(default)]
6136 pub payment_lag: Option<LagDistributionSchemaConfig>,
6137
6138 #[serde(default)]
6140 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6141
6142 #[serde(default)]
6144 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6145}
6146
6147impl Default for ProcessingLagSchemaConfig {
6148 fn default() -> Self {
6149 Self {
6150 enabled: true,
6151 sales_order_lag: None,
6152 purchase_order_lag: None,
6153 goods_receipt_lag: None,
6154 invoice_receipt_lag: None,
6155 invoice_issue_lag: None,
6156 payment_lag: None,
6157 journal_entry_lag: None,
6158 cross_day_posting: None,
6159 }
6160 }
6161}
6162
6163#[derive(Debug, Clone, Serialize, Deserialize)]
6165pub struct LagDistributionSchemaConfig {
6166 pub mu: f64,
6168 pub sigma: f64,
6170 #[serde(default)]
6172 pub min_hours: Option<f64>,
6173 #[serde(default)]
6175 pub max_hours: Option<f64>,
6176}
6177
6178#[derive(Debug, Clone, Serialize, Deserialize)]
6180pub struct CrossDayPostingSchemaConfig {
6181 #[serde(default = "default_true")]
6183 pub enabled: bool,
6184
6185 #[serde(default)]
6188 pub probability_by_hour: std::collections::HashMap<u8, f64>,
6189}
6190
6191impl Default for CrossDayPostingSchemaConfig {
6192 fn default() -> Self {
6193 let mut probability_by_hour = std::collections::HashMap::new();
6194 probability_by_hour.insert(17, 0.3);
6195 probability_by_hour.insert(18, 0.6);
6196 probability_by_hour.insert(19, 0.8);
6197 probability_by_hour.insert(20, 0.9);
6198 probability_by_hour.insert(21, 0.95);
6199 probability_by_hour.insert(22, 0.99);
6200
6201 Self {
6202 enabled: true,
6203 probability_by_hour,
6204 }
6205 }
6206}
6207
6208#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6217pub struct FiscalCalendarSchemaConfig {
6218 #[serde(default)]
6220 pub enabled: bool,
6221
6222 #[serde(default = "default_fiscal_calendar_type")]
6224 pub calendar_type: String,
6225
6226 #[serde(default)]
6228 pub year_start_month: Option<u8>,
6229
6230 #[serde(default)]
6232 pub year_start_day: Option<u8>,
6233
6234 #[serde(default)]
6236 pub four_four_five: Option<FourFourFiveSchemaConfig>,
6237}
6238
6239fn default_fiscal_calendar_type() -> String {
6240 "calendar_year".to_string()
6241}
6242
6243#[derive(Debug, Clone, Serialize, Deserialize)]
6245pub struct FourFourFiveSchemaConfig {
6246 #[serde(default = "default_week_pattern")]
6248 pub pattern: String,
6249
6250 #[serde(default = "default_anchor_type")]
6252 pub anchor_type: String,
6253
6254 #[serde(default = "default_anchor_month")]
6256 pub anchor_month: u8,
6257
6258 #[serde(default = "default_leap_week_placement")]
6260 pub leap_week_placement: String,
6261}
6262
6263fn default_week_pattern() -> String {
6264 "four_four_five".to_string()
6265}
6266
6267fn default_anchor_type() -> String {
6268 "last_saturday".to_string()
6269}
6270
6271fn default_anchor_month() -> u8 {
6272 1 }
6274
6275fn default_leap_week_placement() -> String {
6276 "q4_period3".to_string()
6277}
6278
6279impl Default for FourFourFiveSchemaConfig {
6280 fn default() -> Self {
6281 Self {
6282 pattern: "four_four_five".to_string(),
6283 anchor_type: "last_saturday".to_string(),
6284 anchor_month: 1,
6285 leap_week_placement: "q4_period3".to_string(),
6286 }
6287 }
6288}
6289
6290#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6299pub struct IntraDaySchemaConfig {
6300 #[serde(default)]
6302 pub enabled: bool,
6303
6304 #[serde(default)]
6306 pub segments: Vec<IntraDaySegmentSchemaConfig>,
6307}
6308
6309#[derive(Debug, Clone, Serialize, Deserialize)]
6311pub struct IntraDaySegmentSchemaConfig {
6312 pub name: String,
6314
6315 pub start: String,
6317
6318 pub end: String,
6320
6321 #[serde(default = "default_multiplier")]
6323 pub multiplier: f64,
6324
6325 #[serde(default = "default_posting_type")]
6327 pub posting_type: String,
6328}
6329
6330fn default_multiplier() -> f64 {
6331 1.0
6332}
6333
6334fn default_posting_type() -> String {
6335 "both".to_string()
6336}
6337
6338#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6344pub struct TimezoneSchemaConfig {
6345 #[serde(default)]
6347 pub enabled: bool,
6348
6349 #[serde(default = "default_timezone")]
6351 pub default_timezone: String,
6352
6353 #[serde(default = "default_consolidation_timezone")]
6355 pub consolidation_timezone: String,
6356
6357 #[serde(default)]
6360 pub entity_mappings: Vec<EntityTimezoneMapping>,
6361}
6362
6363fn default_timezone() -> String {
6364 "America/New_York".to_string()
6365}
6366
6367fn default_consolidation_timezone() -> String {
6368 "UTC".to_string()
6369}
6370
6371#[derive(Debug, Clone, Serialize, Deserialize)]
6373pub struct EntityTimezoneMapping {
6374 pub pattern: String,
6376
6377 pub timezone: String,
6379}
6380
6381#[derive(Debug, Clone, Serialize, Deserialize)]
6387pub struct VendorNetworkSchemaConfig {
6388 #[serde(default)]
6390 pub enabled: bool,
6391
6392 #[serde(default = "default_vendor_tier_depth")]
6394 pub depth: u8,
6395
6396 #[serde(default)]
6398 pub tier1: TierCountSchemaConfig,
6399
6400 #[serde(default)]
6402 pub tier2_per_parent: TierCountSchemaConfig,
6403
6404 #[serde(default)]
6406 pub tier3_per_parent: TierCountSchemaConfig,
6407
6408 #[serde(default)]
6410 pub clusters: VendorClusterSchemaConfig,
6411
6412 #[serde(default)]
6414 pub dependencies: DependencySchemaConfig,
6415}
6416
6417fn default_vendor_tier_depth() -> u8 {
6418 3
6419}
6420
6421impl Default for VendorNetworkSchemaConfig {
6422 fn default() -> Self {
6423 Self {
6424 enabled: false,
6425 depth: 3,
6426 tier1: TierCountSchemaConfig { min: 50, max: 100 },
6427 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6428 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6429 clusters: VendorClusterSchemaConfig::default(),
6430 dependencies: DependencySchemaConfig::default(),
6431 }
6432 }
6433}
6434
6435#[derive(Debug, Clone, Serialize, Deserialize)]
6437pub struct TierCountSchemaConfig {
6438 #[serde(default = "default_tier_min")]
6440 pub min: usize,
6441
6442 #[serde(default = "default_tier_max")]
6444 pub max: usize,
6445}
6446
6447fn default_tier_min() -> usize {
6448 5
6449}
6450
6451fn default_tier_max() -> usize {
6452 20
6453}
6454
6455impl Default for TierCountSchemaConfig {
6456 fn default() -> Self {
6457 Self {
6458 min: default_tier_min(),
6459 max: default_tier_max(),
6460 }
6461 }
6462}
6463
6464#[derive(Debug, Clone, Serialize, Deserialize)]
6466pub struct VendorClusterSchemaConfig {
6467 #[serde(default = "default_reliable_strategic")]
6469 pub reliable_strategic: f64,
6470
6471 #[serde(default = "default_standard_operational")]
6473 pub standard_operational: f64,
6474
6475 #[serde(default = "default_transactional")]
6477 pub transactional: f64,
6478
6479 #[serde(default = "default_problematic")]
6481 pub problematic: f64,
6482}
6483
6484fn default_reliable_strategic() -> f64 {
6485 0.20
6486}
6487
6488fn default_standard_operational() -> f64 {
6489 0.50
6490}
6491
6492fn default_transactional() -> f64 {
6493 0.25
6494}
6495
6496fn default_problematic() -> f64 {
6497 0.05
6498}
6499
6500impl Default for VendorClusterSchemaConfig {
6501 fn default() -> Self {
6502 Self {
6503 reliable_strategic: 0.20,
6504 standard_operational: 0.50,
6505 transactional: 0.25,
6506 problematic: 0.05,
6507 }
6508 }
6509}
6510
6511#[derive(Debug, Clone, Serialize, Deserialize)]
6513pub struct DependencySchemaConfig {
6514 #[serde(default = "default_max_single_vendor")]
6516 pub max_single_vendor_concentration: f64,
6517
6518 #[serde(default = "default_max_top5")]
6520 pub top_5_concentration: f64,
6521
6522 #[serde(default = "default_single_source_percent")]
6524 pub single_source_percent: f64,
6525}
6526
6527fn default_max_single_vendor() -> f64 {
6528 0.15
6529}
6530
6531fn default_max_top5() -> f64 {
6532 0.45
6533}
6534
6535fn default_single_source_percent() -> f64 {
6536 0.05
6537}
6538
6539impl Default for DependencySchemaConfig {
6540 fn default() -> Self {
6541 Self {
6542 max_single_vendor_concentration: 0.15,
6543 top_5_concentration: 0.45,
6544 single_source_percent: 0.05,
6545 }
6546 }
6547}
6548
6549#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6555pub struct CustomerSegmentationSchemaConfig {
6556 #[serde(default)]
6558 pub enabled: bool,
6559
6560 #[serde(default)]
6562 pub value_segments: ValueSegmentsSchemaConfig,
6563
6564 #[serde(default)]
6566 pub lifecycle: LifecycleSchemaConfig,
6567
6568 #[serde(default)]
6570 pub networks: CustomerNetworksSchemaConfig,
6571}
6572
6573#[derive(Debug, Clone, Serialize, Deserialize)]
6575pub struct ValueSegmentsSchemaConfig {
6576 #[serde(default)]
6578 pub enterprise: SegmentDetailSchemaConfig,
6579
6580 #[serde(default)]
6582 pub mid_market: SegmentDetailSchemaConfig,
6583
6584 #[serde(default)]
6586 pub smb: SegmentDetailSchemaConfig,
6587
6588 #[serde(default)]
6590 pub consumer: SegmentDetailSchemaConfig,
6591}
6592
6593impl Default for ValueSegmentsSchemaConfig {
6594 fn default() -> Self {
6595 Self {
6596 enterprise: SegmentDetailSchemaConfig {
6597 revenue_share: 0.40,
6598 customer_share: 0.05,
6599 avg_order_value_range: "50000+".to_string(),
6600 },
6601 mid_market: SegmentDetailSchemaConfig {
6602 revenue_share: 0.35,
6603 customer_share: 0.20,
6604 avg_order_value_range: "5000-50000".to_string(),
6605 },
6606 smb: SegmentDetailSchemaConfig {
6607 revenue_share: 0.20,
6608 customer_share: 0.50,
6609 avg_order_value_range: "500-5000".to_string(),
6610 },
6611 consumer: SegmentDetailSchemaConfig {
6612 revenue_share: 0.05,
6613 customer_share: 0.25,
6614 avg_order_value_range: "50-500".to_string(),
6615 },
6616 }
6617 }
6618}
6619
6620#[derive(Debug, Clone, Serialize, Deserialize)]
6622pub struct SegmentDetailSchemaConfig {
6623 #[serde(default)]
6625 pub revenue_share: f64,
6626
6627 #[serde(default)]
6629 pub customer_share: f64,
6630
6631 #[serde(default)]
6633 pub avg_order_value_range: String,
6634}
6635
6636impl Default for SegmentDetailSchemaConfig {
6637 fn default() -> Self {
6638 Self {
6639 revenue_share: 0.25,
6640 customer_share: 0.25,
6641 avg_order_value_range: "1000-10000".to_string(),
6642 }
6643 }
6644}
6645
6646#[derive(Debug, Clone, Serialize, Deserialize)]
6648pub struct LifecycleSchemaConfig {
6649 #[serde(default)]
6651 pub prospect_rate: f64,
6652
6653 #[serde(default = "default_new_rate")]
6655 pub new_rate: f64,
6656
6657 #[serde(default = "default_growth_rate")]
6659 pub growth_rate: f64,
6660
6661 #[serde(default = "default_mature_rate")]
6663 pub mature_rate: f64,
6664
6665 #[serde(default = "default_at_risk_rate")]
6667 pub at_risk_rate: f64,
6668
6669 #[serde(default = "default_churned_rate")]
6671 pub churned_rate: f64,
6672}
6673
6674fn default_new_rate() -> f64 {
6675 0.10
6676}
6677
6678fn default_growth_rate() -> f64 {
6679 0.15
6680}
6681
6682fn default_mature_rate() -> f64 {
6683 0.60
6684}
6685
6686fn default_at_risk_rate() -> f64 {
6687 0.10
6688}
6689
6690fn default_churned_rate() -> f64 {
6691 0.05
6692}
6693
6694impl Default for LifecycleSchemaConfig {
6695 fn default() -> Self {
6696 Self {
6697 prospect_rate: 0.0,
6698 new_rate: 0.10,
6699 growth_rate: 0.15,
6700 mature_rate: 0.60,
6701 at_risk_rate: 0.10,
6702 churned_rate: 0.05,
6703 }
6704 }
6705}
6706
6707#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6709pub struct CustomerNetworksSchemaConfig {
6710 #[serde(default)]
6712 pub referrals: ReferralSchemaConfig,
6713
6714 #[serde(default)]
6716 pub corporate_hierarchies: HierarchySchemaConfig,
6717}
6718
6719#[derive(Debug, Clone, Serialize, Deserialize)]
6721pub struct ReferralSchemaConfig {
6722 #[serde(default = "default_true")]
6724 pub enabled: bool,
6725
6726 #[serde(default = "default_referral_rate")]
6728 pub referral_rate: f64,
6729}
6730
6731fn default_referral_rate() -> f64 {
6732 0.15
6733}
6734
6735impl Default for ReferralSchemaConfig {
6736 fn default() -> Self {
6737 Self {
6738 enabled: true,
6739 referral_rate: 0.15,
6740 }
6741 }
6742}
6743
6744#[derive(Debug, Clone, Serialize, Deserialize)]
6746pub struct HierarchySchemaConfig {
6747 #[serde(default = "default_true")]
6749 pub enabled: bool,
6750
6751 #[serde(default = "default_hierarchy_rate")]
6753 pub probability: f64,
6754}
6755
6756fn default_hierarchy_rate() -> f64 {
6757 0.30
6758}
6759
6760impl Default for HierarchySchemaConfig {
6761 fn default() -> Self {
6762 Self {
6763 enabled: true,
6764 probability: 0.30,
6765 }
6766 }
6767}
6768
6769#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6775pub struct RelationshipStrengthSchemaConfig {
6776 #[serde(default)]
6778 pub enabled: bool,
6779
6780 #[serde(default)]
6782 pub calculation: StrengthCalculationSchemaConfig,
6783
6784 #[serde(default)]
6786 pub thresholds: StrengthThresholdsSchemaConfig,
6787}
6788
6789#[derive(Debug, Clone, Serialize, Deserialize)]
6791pub struct StrengthCalculationSchemaConfig {
6792 #[serde(default = "default_volume_weight")]
6794 pub transaction_volume_weight: f64,
6795
6796 #[serde(default = "default_count_weight")]
6798 pub transaction_count_weight: f64,
6799
6800 #[serde(default = "default_duration_weight")]
6802 pub relationship_duration_weight: f64,
6803
6804 #[serde(default = "default_recency_weight")]
6806 pub recency_weight: f64,
6807
6808 #[serde(default = "default_mutual_weight")]
6810 pub mutual_connections_weight: f64,
6811
6812 #[serde(default = "default_recency_half_life")]
6814 pub recency_half_life_days: u32,
6815}
6816
6817fn default_volume_weight() -> f64 {
6818 0.30
6819}
6820
6821fn default_count_weight() -> f64 {
6822 0.25
6823}
6824
6825fn default_duration_weight() -> f64 {
6826 0.20
6827}
6828
6829fn default_recency_weight() -> f64 {
6830 0.15
6831}
6832
6833fn default_mutual_weight() -> f64 {
6834 0.10
6835}
6836
6837fn default_recency_half_life() -> u32 {
6838 90
6839}
6840
6841impl Default for StrengthCalculationSchemaConfig {
6842 fn default() -> Self {
6843 Self {
6844 transaction_volume_weight: 0.30,
6845 transaction_count_weight: 0.25,
6846 relationship_duration_weight: 0.20,
6847 recency_weight: 0.15,
6848 mutual_connections_weight: 0.10,
6849 recency_half_life_days: 90,
6850 }
6851 }
6852}
6853
6854#[derive(Debug, Clone, Serialize, Deserialize)]
6856pub struct StrengthThresholdsSchemaConfig {
6857 #[serde(default = "default_strong_threshold")]
6859 pub strong: f64,
6860
6861 #[serde(default = "default_moderate_threshold")]
6863 pub moderate: f64,
6864
6865 #[serde(default = "default_weak_threshold")]
6867 pub weak: f64,
6868}
6869
6870fn default_strong_threshold() -> f64 {
6871 0.7
6872}
6873
6874fn default_moderate_threshold() -> f64 {
6875 0.4
6876}
6877
6878fn default_weak_threshold() -> f64 {
6879 0.1
6880}
6881
6882impl Default for StrengthThresholdsSchemaConfig {
6883 fn default() -> Self {
6884 Self {
6885 strong: 0.7,
6886 moderate: 0.4,
6887 weak: 0.1,
6888 }
6889 }
6890}
6891
6892#[derive(Debug, Clone, Serialize, Deserialize)]
6898pub struct CrossProcessLinksSchemaConfig {
6899 #[serde(default)]
6901 pub enabled: bool,
6902
6903 #[serde(default = "default_true")]
6905 pub inventory_p2p_o2c: bool,
6906
6907 #[serde(default = "default_true")]
6909 pub payment_bank_reconciliation: bool,
6910
6911 #[serde(default = "default_true")]
6913 pub intercompany_bilateral: bool,
6914
6915 #[serde(default = "default_inventory_link_rate")]
6917 pub inventory_link_rate: f64,
6918}
6919
6920fn default_inventory_link_rate() -> f64 {
6921 0.30
6922}
6923
6924impl Default for CrossProcessLinksSchemaConfig {
6925 fn default() -> Self {
6926 Self {
6927 enabled: false,
6928 inventory_p2p_o2c: true,
6929 payment_bank_reconciliation: true,
6930 intercompany_bilateral: true,
6931 inventory_link_rate: 0.30,
6932 }
6933 }
6934}
6935
6936#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6942pub struct OrganizationalEventsSchemaConfig {
6943 #[serde(default)]
6945 pub enabled: bool,
6946
6947 #[serde(default)]
6949 pub effect_blending: EffectBlendingModeConfig,
6950
6951 #[serde(default)]
6953 pub events: Vec<OrganizationalEventSchemaConfig>,
6954
6955 #[serde(default)]
6957 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6958
6959 #[serde(default)]
6961 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6962}
6963
6964#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6966#[serde(rename_all = "snake_case")]
6967pub enum EffectBlendingModeConfig {
6968 #[default]
6970 Multiplicative,
6971 Additive,
6973 Maximum,
6975 Minimum,
6977}
6978
6979#[derive(Debug, Clone, Serialize, Deserialize)]
6981pub struct OrganizationalEventSchemaConfig {
6982 pub id: String,
6984
6985 pub event_type: OrganizationalEventTypeSchemaConfig,
6987
6988 pub effective_date: String,
6990
6991 #[serde(default = "default_org_transition_months")]
6993 pub transition_months: u32,
6994
6995 #[serde(default)]
6997 pub description: Option<String>,
6998}
6999
7000fn default_org_transition_months() -> u32 {
7001 6
7002}
7003
7004#[derive(Debug, Clone, Serialize, Deserialize)]
7006#[serde(tag = "type", rename_all = "snake_case")]
7007pub enum OrganizationalEventTypeSchemaConfig {
7008 Acquisition {
7010 acquired_entity: String,
7012 #[serde(default = "default_acquisition_volume")]
7014 volume_increase: f64,
7015 #[serde(default = "default_acquisition_error")]
7017 integration_error_rate: f64,
7018 #[serde(default = "default_parallel_days")]
7020 parallel_posting_days: u32,
7021 },
7022 Divestiture {
7024 divested_entity: String,
7026 #[serde(default = "default_divestiture_volume")]
7028 volume_reduction: f64,
7029 #[serde(default = "default_true_val")]
7031 remove_entity: bool,
7032 },
7033 Reorganization {
7035 #[serde(default)]
7037 cost_center_remapping: std::collections::HashMap<String, String>,
7038 #[serde(default = "default_reorg_error")]
7040 transition_error_rate: f64,
7041 },
7042 LeadershipChange {
7044 role: String,
7046 #[serde(default)]
7048 policy_changes: Vec<String>,
7049 },
7050 WorkforceReduction {
7052 #[serde(default = "default_workforce_reduction")]
7054 reduction_percent: f64,
7055 #[serde(default = "default_workforce_error")]
7057 error_rate_increase: f64,
7058 },
7059 Merger {
7061 merged_entity: String,
7063 #[serde(default = "default_merger_volume")]
7065 volume_increase: f64,
7066 },
7067}
7068
7069fn default_acquisition_volume() -> f64 {
7070 1.35
7071}
7072
7073fn default_acquisition_error() -> f64 {
7074 0.05
7075}
7076
7077fn default_parallel_days() -> u32 {
7078 30
7079}
7080
7081fn default_divestiture_volume() -> f64 {
7082 0.70
7083}
7084
7085fn default_true_val() -> bool {
7086 true
7087}
7088
7089fn default_reorg_error() -> f64 {
7090 0.04
7091}
7092
7093fn default_workforce_reduction() -> f64 {
7094 0.10
7095}
7096
7097fn default_workforce_error() -> f64 {
7098 0.05
7099}
7100
7101fn default_merger_volume() -> f64 {
7102 1.80
7103}
7104
7105#[derive(Debug, Clone, Serialize, Deserialize)]
7107pub struct ProcessEvolutionSchemaConfig {
7108 pub id: String,
7110
7111 pub event_type: ProcessEvolutionTypeSchemaConfig,
7113
7114 pub effective_date: String,
7116
7117 #[serde(default)]
7119 pub description: Option<String>,
7120}
7121
7122#[derive(Debug, Clone, Serialize, Deserialize)]
7124#[serde(tag = "type", rename_all = "snake_case")]
7125pub enum ProcessEvolutionTypeSchemaConfig {
7126 ProcessAutomation {
7128 process_name: String,
7130 #[serde(default = "default_manual_before")]
7132 manual_rate_before: f64,
7133 #[serde(default = "default_manual_after")]
7135 manual_rate_after: f64,
7136 },
7137 ApprovalWorkflowChange {
7139 description: String,
7141 },
7142 ControlEnhancement {
7144 control_id: String,
7146 #[serde(default = "default_error_reduction")]
7148 error_reduction: f64,
7149 },
7150}
7151
7152fn default_manual_before() -> f64 {
7153 0.80
7154}
7155
7156fn default_manual_after() -> f64 {
7157 0.15
7158}
7159
7160fn default_error_reduction() -> f64 {
7161 0.02
7162}
7163
7164#[derive(Debug, Clone, Serialize, Deserialize)]
7166pub struct TechnologyTransitionSchemaConfig {
7167 pub id: String,
7169
7170 pub event_type: TechnologyTransitionTypeSchemaConfig,
7172
7173 #[serde(default)]
7175 pub description: Option<String>,
7176}
7177
7178#[derive(Debug, Clone, Serialize, Deserialize)]
7180#[serde(tag = "type", rename_all = "snake_case")]
7181pub enum TechnologyTransitionTypeSchemaConfig {
7182 ErpMigration {
7184 source_system: String,
7186 target_system: String,
7188 cutover_date: String,
7190 stabilization_end: String,
7192 #[serde(default = "default_erp_duplicate_rate")]
7194 duplicate_rate: f64,
7195 #[serde(default = "default_format_mismatch")]
7197 format_mismatch_rate: f64,
7198 },
7199 ModuleImplementation {
7201 module_name: String,
7203 go_live_date: String,
7205 },
7206}
7207
7208fn default_erp_duplicate_rate() -> f64 {
7209 0.02
7210}
7211
7212fn default_format_mismatch() -> f64 {
7213 0.03
7214}
7215
7216#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7222pub struct BehavioralDriftSchemaConfig {
7223 #[serde(default)]
7225 pub enabled: bool,
7226
7227 #[serde(default)]
7229 pub vendor_behavior: VendorBehaviorSchemaConfig,
7230
7231 #[serde(default)]
7233 pub customer_behavior: CustomerBehaviorSchemaConfig,
7234
7235 #[serde(default)]
7237 pub employee_behavior: EmployeeBehaviorSchemaConfig,
7238
7239 #[serde(default)]
7241 pub collective: CollectiveBehaviorSchemaConfig,
7242}
7243
7244#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7246pub struct VendorBehaviorSchemaConfig {
7247 #[serde(default)]
7249 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7250
7251 #[serde(default)]
7253 pub quality_drift: QualityDriftSchemaConfig,
7254}
7255
7256#[derive(Debug, Clone, Serialize, Deserialize)]
7258pub struct PaymentTermsDriftSchemaConfig {
7259 #[serde(default = "default_extension_rate")]
7261 pub extension_rate_per_year: f64,
7262
7263 #[serde(default = "default_economic_sensitivity")]
7265 pub economic_sensitivity: f64,
7266}
7267
7268fn default_extension_rate() -> f64 {
7269 2.5
7270}
7271
7272fn default_economic_sensitivity() -> f64 {
7273 1.0
7274}
7275
7276impl Default for PaymentTermsDriftSchemaConfig {
7277 fn default() -> Self {
7278 Self {
7279 extension_rate_per_year: 2.5,
7280 economic_sensitivity: 1.0,
7281 }
7282 }
7283}
7284
7285#[derive(Debug, Clone, Serialize, Deserialize)]
7287pub struct QualityDriftSchemaConfig {
7288 #[serde(default = "default_improvement_rate")]
7290 pub new_vendor_improvement_rate: f64,
7291
7292 #[serde(default = "default_decline_rate")]
7294 pub complacency_decline_rate: f64,
7295}
7296
7297fn default_improvement_rate() -> f64 {
7298 0.02
7299}
7300
7301fn default_decline_rate() -> f64 {
7302 0.01
7303}
7304
7305impl Default for QualityDriftSchemaConfig {
7306 fn default() -> Self {
7307 Self {
7308 new_vendor_improvement_rate: 0.02,
7309 complacency_decline_rate: 0.01,
7310 }
7311 }
7312}
7313
7314#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7316pub struct CustomerBehaviorSchemaConfig {
7317 #[serde(default)]
7319 pub payment_drift: CustomerPaymentDriftSchemaConfig,
7320
7321 #[serde(default)]
7323 pub order_drift: OrderDriftSchemaConfig,
7324}
7325
7326#[derive(Debug, Clone, Serialize, Deserialize)]
7328pub struct CustomerPaymentDriftSchemaConfig {
7329 #[serde(default = "default_downturn_extension")]
7331 pub downturn_days_extension: (u32, u32),
7332
7333 #[serde(default = "default_bad_debt_increase")]
7335 pub downturn_bad_debt_increase: f64,
7336}
7337
7338fn default_downturn_extension() -> (u32, u32) {
7339 (5, 15)
7340}
7341
7342fn default_bad_debt_increase() -> f64 {
7343 0.02
7344}
7345
7346impl Default for CustomerPaymentDriftSchemaConfig {
7347 fn default() -> Self {
7348 Self {
7349 downturn_days_extension: (5, 15),
7350 downturn_bad_debt_increase: 0.02,
7351 }
7352 }
7353}
7354
7355#[derive(Debug, Clone, Serialize, Deserialize)]
7357pub struct OrderDriftSchemaConfig {
7358 #[serde(default = "default_digital_shift")]
7360 pub digital_shift_rate: f64,
7361}
7362
7363fn default_digital_shift() -> f64 {
7364 0.05
7365}
7366
7367impl Default for OrderDriftSchemaConfig {
7368 fn default() -> Self {
7369 Self {
7370 digital_shift_rate: 0.05,
7371 }
7372 }
7373}
7374
7375#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7377pub struct EmployeeBehaviorSchemaConfig {
7378 #[serde(default)]
7380 pub approval_drift: ApprovalDriftSchemaConfig,
7381
7382 #[serde(default)]
7384 pub error_drift: ErrorDriftSchemaConfig,
7385}
7386
7387#[derive(Debug, Clone, Serialize, Deserialize)]
7389pub struct ApprovalDriftSchemaConfig {
7390 #[serde(default = "default_eom_intensity")]
7392 pub eom_intensity_increase_per_year: f64,
7393
7394 #[serde(default = "default_rubber_stamp")]
7396 pub rubber_stamp_volume_threshold: u32,
7397}
7398
7399fn default_eom_intensity() -> f64 {
7400 0.05
7401}
7402
7403fn default_rubber_stamp() -> u32 {
7404 50
7405}
7406
7407impl Default for ApprovalDriftSchemaConfig {
7408 fn default() -> Self {
7409 Self {
7410 eom_intensity_increase_per_year: 0.05,
7411 rubber_stamp_volume_threshold: 50,
7412 }
7413 }
7414}
7415
7416#[derive(Debug, Clone, Serialize, Deserialize)]
7418pub struct ErrorDriftSchemaConfig {
7419 #[serde(default = "default_new_error")]
7421 pub new_employee_error_rate: f64,
7422
7423 #[serde(default = "default_learning_months")]
7425 pub learning_curve_months: u32,
7426}
7427
7428fn default_new_error() -> f64 {
7429 0.08
7430}
7431
7432fn default_learning_months() -> u32 {
7433 6
7434}
7435
7436impl Default for ErrorDriftSchemaConfig {
7437 fn default() -> Self {
7438 Self {
7439 new_employee_error_rate: 0.08,
7440 learning_curve_months: 6,
7441 }
7442 }
7443}
7444
7445#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7447pub struct CollectiveBehaviorSchemaConfig {
7448 #[serde(default)]
7450 pub automation_adoption: AutomationAdoptionSchemaConfig,
7451}
7452
7453#[derive(Debug, Clone, Serialize, Deserialize)]
7455pub struct AutomationAdoptionSchemaConfig {
7456 #[serde(default)]
7458 pub s_curve_enabled: bool,
7459
7460 #[serde(default = "default_midpoint")]
7462 pub adoption_midpoint_months: u32,
7463
7464 #[serde(default = "default_steepness")]
7466 pub steepness: f64,
7467}
7468
7469fn default_midpoint() -> u32 {
7470 24
7471}
7472
7473fn default_steepness() -> f64 {
7474 0.15
7475}
7476
7477impl Default for AutomationAdoptionSchemaConfig {
7478 fn default() -> Self {
7479 Self {
7480 s_curve_enabled: false,
7481 adoption_midpoint_months: 24,
7482 steepness: 0.15,
7483 }
7484 }
7485}
7486
7487#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7493pub struct MarketDriftSchemaConfig {
7494 #[serde(default)]
7496 pub enabled: bool,
7497
7498 #[serde(default)]
7500 pub economic_cycle: MarketEconomicCycleSchemaConfig,
7501
7502 #[serde(default)]
7504 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7505
7506 #[serde(default)]
7508 pub commodities: CommoditiesSchemaConfig,
7509}
7510
7511#[derive(Debug, Clone, Serialize, Deserialize)]
7513pub struct MarketEconomicCycleSchemaConfig {
7514 #[serde(default)]
7516 pub enabled: bool,
7517
7518 #[serde(default)]
7520 pub cycle_type: CycleTypeSchemaConfig,
7521
7522 #[serde(default = "default_market_cycle_period")]
7524 pub period_months: u32,
7525
7526 #[serde(default = "default_market_amplitude")]
7528 pub amplitude: f64,
7529
7530 #[serde(default)]
7532 pub recession: RecessionSchemaConfig,
7533}
7534
7535fn default_market_cycle_period() -> u32 {
7536 48
7537}
7538
7539fn default_market_amplitude() -> f64 {
7540 0.15
7541}
7542
7543impl Default for MarketEconomicCycleSchemaConfig {
7544 fn default() -> Self {
7545 Self {
7546 enabled: false,
7547 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7548 period_months: 48,
7549 amplitude: 0.15,
7550 recession: RecessionSchemaConfig::default(),
7551 }
7552 }
7553}
7554
7555#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7557#[serde(rename_all = "snake_case")]
7558pub enum CycleTypeSchemaConfig {
7559 #[default]
7561 Sinusoidal,
7562 Asymmetric,
7564 MeanReverting,
7566}
7567
7568#[derive(Debug, Clone, Serialize, Deserialize)]
7570pub struct RecessionSchemaConfig {
7571 #[serde(default)]
7573 pub enabled: bool,
7574
7575 #[serde(default = "default_recession_prob")]
7577 pub probability_per_year: f64,
7578
7579 #[serde(default)]
7581 pub severity: RecessionSeveritySchemaConfig,
7582
7583 #[serde(default)]
7585 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7586}
7587
7588fn default_recession_prob() -> f64 {
7589 0.10
7590}
7591
7592impl Default for RecessionSchemaConfig {
7593 fn default() -> Self {
7594 Self {
7595 enabled: false,
7596 probability_per_year: 0.10,
7597 severity: RecessionSeveritySchemaConfig::Moderate,
7598 recession_periods: Vec::new(),
7599 }
7600 }
7601}
7602
7603#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7605#[serde(rename_all = "snake_case")]
7606pub enum RecessionSeveritySchemaConfig {
7607 Mild,
7609 #[default]
7611 Moderate,
7612 Severe,
7614}
7615
7616#[derive(Debug, Clone, Serialize, Deserialize)]
7618pub struct RecessionPeriodSchemaConfig {
7619 pub start_month: u32,
7621 pub duration_months: u32,
7623}
7624
7625#[derive(Debug, Clone, Serialize, Deserialize)]
7627pub struct IndustryCycleSchemaConfig {
7628 #[serde(default = "default_industry_period")]
7630 pub period_months: u32,
7631
7632 #[serde(default = "default_industry_amp")]
7634 pub amplitude: f64,
7635}
7636
7637fn default_industry_period() -> u32 {
7638 36
7639}
7640
7641fn default_industry_amp() -> f64 {
7642 0.20
7643}
7644
7645#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7647pub struct CommoditiesSchemaConfig {
7648 #[serde(default)]
7650 pub enabled: bool,
7651
7652 #[serde(default)]
7654 pub items: Vec<CommodityItemSchemaConfig>,
7655}
7656
7657#[derive(Debug, Clone, Serialize, Deserialize)]
7659pub struct CommodityItemSchemaConfig {
7660 pub name: String,
7662
7663 #[serde(default = "default_volatility")]
7665 pub volatility: f64,
7666
7667 #[serde(default)]
7669 pub cogs_pass_through: f64,
7670
7671 #[serde(default)]
7673 pub overhead_pass_through: f64,
7674}
7675
7676fn default_volatility() -> f64 {
7677 0.20
7678}
7679
7680#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7686pub struct DriftLabelingSchemaConfig {
7687 #[serde(default)]
7689 pub enabled: bool,
7690
7691 #[serde(default)]
7693 pub statistical: StatisticalDriftLabelingSchemaConfig,
7694
7695 #[serde(default)]
7697 pub categorical: CategoricalDriftLabelingSchemaConfig,
7698
7699 #[serde(default)]
7701 pub temporal: TemporalDriftLabelingSchemaConfig,
7702
7703 #[serde(default)]
7705 pub regulatory_calendar_preset: Option<String>,
7706}
7707
7708#[derive(Debug, Clone, Serialize, Deserialize)]
7710pub struct StatisticalDriftLabelingSchemaConfig {
7711 #[serde(default = "default_true_val")]
7713 pub enabled: bool,
7714
7715 #[serde(default = "default_min_magnitude")]
7717 pub min_magnitude_threshold: f64,
7718}
7719
7720fn default_min_magnitude() -> f64 {
7721 0.05
7722}
7723
7724impl Default for StatisticalDriftLabelingSchemaConfig {
7725 fn default() -> Self {
7726 Self {
7727 enabled: true,
7728 min_magnitude_threshold: 0.05,
7729 }
7730 }
7731}
7732
7733#[derive(Debug, Clone, Serialize, Deserialize)]
7735pub struct CategoricalDriftLabelingSchemaConfig {
7736 #[serde(default = "default_true_val")]
7738 pub enabled: bool,
7739}
7740
7741impl Default for CategoricalDriftLabelingSchemaConfig {
7742 fn default() -> Self {
7743 Self { enabled: true }
7744 }
7745}
7746
7747#[derive(Debug, Clone, Serialize, Deserialize)]
7749pub struct TemporalDriftLabelingSchemaConfig {
7750 #[serde(default = "default_true_val")]
7752 pub enabled: bool,
7753}
7754
7755impl Default for TemporalDriftLabelingSchemaConfig {
7756 fn default() -> Self {
7757 Self { enabled: true }
7758 }
7759}
7760
7761#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7774pub struct EnhancedAnomalyConfig {
7775 #[serde(default)]
7777 pub enabled: bool,
7778
7779 #[serde(default)]
7781 pub rates: AnomalyRateConfig,
7782
7783 #[serde(default)]
7785 pub multi_stage_schemes: MultiStageSchemeConfig,
7786
7787 #[serde(default)]
7789 pub correlated_injection: CorrelatedInjectionConfig,
7790
7791 #[serde(default)]
7793 pub near_miss: NearMissConfig,
7794
7795 #[serde(default)]
7797 pub difficulty_classification: DifficultyClassificationConfig,
7798
7799 #[serde(default)]
7801 pub context_aware: ContextAwareConfig,
7802
7803 #[serde(default)]
7805 pub labeling: EnhancedLabelingConfig,
7806}
7807
7808#[derive(Debug, Clone, Serialize, Deserialize)]
7810pub struct AnomalyRateConfig {
7811 #[serde(default = "default_total_anomaly_rate")]
7813 pub total_rate: f64,
7814
7815 #[serde(default = "default_fraud_anomaly_rate")]
7817 pub fraud_rate: f64,
7818
7819 #[serde(default = "default_error_anomaly_rate")]
7821 pub error_rate: f64,
7822
7823 #[serde(default = "default_process_anomaly_rate")]
7825 pub process_rate: f64,
7826}
7827
7828fn default_total_anomaly_rate() -> f64 {
7829 0.03
7830}
7831fn default_fraud_anomaly_rate() -> f64 {
7832 0.01
7833}
7834fn default_error_anomaly_rate() -> f64 {
7835 0.015
7836}
7837fn default_process_anomaly_rate() -> f64 {
7838 0.005
7839}
7840
7841impl Default for AnomalyRateConfig {
7842 fn default() -> Self {
7843 Self {
7844 total_rate: default_total_anomaly_rate(),
7845 fraud_rate: default_fraud_anomaly_rate(),
7846 error_rate: default_error_anomaly_rate(),
7847 process_rate: default_process_anomaly_rate(),
7848 }
7849 }
7850}
7851
7852#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7854pub struct MultiStageSchemeConfig {
7855 #[serde(default)]
7857 pub enabled: bool,
7858
7859 #[serde(default)]
7861 pub embezzlement: EmbezzlementSchemeConfig,
7862
7863 #[serde(default)]
7865 pub revenue_manipulation: RevenueManipulationSchemeConfig,
7866
7867 #[serde(default)]
7869 pub kickback: KickbackSchemeConfig,
7870}
7871
7872#[derive(Debug, Clone, Serialize, Deserialize)]
7874pub struct EmbezzlementSchemeConfig {
7875 #[serde(default = "default_embezzlement_probability")]
7877 pub probability: f64,
7878
7879 #[serde(default)]
7881 pub testing_stage: SchemeStageConfig,
7882
7883 #[serde(default)]
7885 pub escalation_stage: SchemeStageConfig,
7886
7887 #[serde(default)]
7889 pub acceleration_stage: SchemeStageConfig,
7890
7891 #[serde(default)]
7893 pub desperation_stage: SchemeStageConfig,
7894}
7895
7896fn default_embezzlement_probability() -> f64 {
7897 0.02
7898}
7899
7900impl Default for EmbezzlementSchemeConfig {
7901 fn default() -> Self {
7902 Self {
7903 probability: default_embezzlement_probability(),
7904 testing_stage: SchemeStageConfig {
7905 duration_months: 2,
7906 amount_min: 100.0,
7907 amount_max: 500.0,
7908 transaction_count_min: 2,
7909 transaction_count_max: 5,
7910 difficulty: "hard".to_string(),
7911 },
7912 escalation_stage: SchemeStageConfig {
7913 duration_months: 6,
7914 amount_min: 500.0,
7915 amount_max: 2000.0,
7916 transaction_count_min: 3,
7917 transaction_count_max: 8,
7918 difficulty: "moderate".to_string(),
7919 },
7920 acceleration_stage: SchemeStageConfig {
7921 duration_months: 3,
7922 amount_min: 2000.0,
7923 amount_max: 10000.0,
7924 transaction_count_min: 5,
7925 transaction_count_max: 12,
7926 difficulty: "easy".to_string(),
7927 },
7928 desperation_stage: SchemeStageConfig {
7929 duration_months: 1,
7930 amount_min: 10000.0,
7931 amount_max: 50000.0,
7932 transaction_count_min: 3,
7933 transaction_count_max: 6,
7934 difficulty: "trivial".to_string(),
7935 },
7936 }
7937 }
7938}
7939
7940#[derive(Debug, Clone, Serialize, Deserialize)]
7942pub struct RevenueManipulationSchemeConfig {
7943 #[serde(default = "default_revenue_manipulation_probability")]
7945 pub probability: f64,
7946
7947 #[serde(default = "default_early_recognition_target")]
7949 pub early_recognition_target: f64,
7950
7951 #[serde(default = "default_expense_deferral_target")]
7953 pub expense_deferral_target: f64,
7954
7955 #[serde(default = "default_reserve_release_target")]
7957 pub reserve_release_target: f64,
7958
7959 #[serde(default = "default_channel_stuffing_target")]
7961 pub channel_stuffing_target: f64,
7962}
7963
7964fn default_revenue_manipulation_probability() -> f64 {
7965 0.01
7966}
7967fn default_early_recognition_target() -> f64 {
7968 0.02
7969}
7970fn default_expense_deferral_target() -> f64 {
7971 0.03
7972}
7973fn default_reserve_release_target() -> f64 {
7974 0.02
7975}
7976fn default_channel_stuffing_target() -> f64 {
7977 0.05
7978}
7979
7980impl Default for RevenueManipulationSchemeConfig {
7981 fn default() -> Self {
7982 Self {
7983 probability: default_revenue_manipulation_probability(),
7984 early_recognition_target: default_early_recognition_target(),
7985 expense_deferral_target: default_expense_deferral_target(),
7986 reserve_release_target: default_reserve_release_target(),
7987 channel_stuffing_target: default_channel_stuffing_target(),
7988 }
7989 }
7990}
7991
7992#[derive(Debug, Clone, Serialize, Deserialize)]
7994pub struct KickbackSchemeConfig {
7995 #[serde(default = "default_kickback_probability")]
7997 pub probability: f64,
7998
7999 #[serde(default = "default_kickback_inflation_min")]
8001 pub inflation_min: f64,
8002
8003 #[serde(default = "default_kickback_inflation_max")]
8005 pub inflation_max: f64,
8006
8007 #[serde(default = "default_kickback_percent")]
8009 pub kickback_percent: f64,
8010
8011 #[serde(default = "default_kickback_setup_months")]
8013 pub setup_months: u32,
8014
8015 #[serde(default = "default_kickback_operation_months")]
8017 pub operation_months: u32,
8018}
8019
8020fn default_kickback_probability() -> f64 {
8021 0.01
8022}
8023fn default_kickback_inflation_min() -> f64 {
8024 0.10
8025}
8026fn default_kickback_inflation_max() -> f64 {
8027 0.25
8028}
8029fn default_kickback_percent() -> f64 {
8030 0.50
8031}
8032fn default_kickback_setup_months() -> u32 {
8033 3
8034}
8035fn default_kickback_operation_months() -> u32 {
8036 12
8037}
8038
8039impl Default for KickbackSchemeConfig {
8040 fn default() -> Self {
8041 Self {
8042 probability: default_kickback_probability(),
8043 inflation_min: default_kickback_inflation_min(),
8044 inflation_max: default_kickback_inflation_max(),
8045 kickback_percent: default_kickback_percent(),
8046 setup_months: default_kickback_setup_months(),
8047 operation_months: default_kickback_operation_months(),
8048 }
8049 }
8050}
8051
8052#[derive(Debug, Clone, Serialize, Deserialize)]
8054pub struct SchemeStageConfig {
8055 pub duration_months: u32,
8057
8058 pub amount_min: f64,
8060
8061 pub amount_max: f64,
8063
8064 pub transaction_count_min: u32,
8066
8067 pub transaction_count_max: u32,
8069
8070 pub difficulty: String,
8072}
8073
8074impl Default for SchemeStageConfig {
8075 fn default() -> Self {
8076 Self {
8077 duration_months: 3,
8078 amount_min: 100.0,
8079 amount_max: 1000.0,
8080 transaction_count_min: 2,
8081 transaction_count_max: 10,
8082 difficulty: "moderate".to_string(),
8083 }
8084 }
8085}
8086
8087#[derive(Debug, Clone, Serialize, Deserialize)]
8089pub struct CorrelatedInjectionConfig {
8090 #[serde(default)]
8092 pub enabled: bool,
8093
8094 #[serde(default = "default_true_val")]
8096 pub fraud_concealment: bool,
8097
8098 #[serde(default = "default_true_val")]
8100 pub error_cascade: bool,
8101
8102 #[serde(default = "default_true_val")]
8104 pub temporal_clustering: bool,
8105
8106 #[serde(default)]
8108 pub temporal_clustering_config: TemporalClusteringConfig,
8109
8110 #[serde(default)]
8112 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8113}
8114
8115impl Default for CorrelatedInjectionConfig {
8116 fn default() -> Self {
8117 Self {
8118 enabled: false,
8119 fraud_concealment: true,
8120 error_cascade: true,
8121 temporal_clustering: true,
8122 temporal_clustering_config: TemporalClusteringConfig::default(),
8123 co_occurrence_patterns: Vec::new(),
8124 }
8125 }
8126}
8127
8128#[derive(Debug, Clone, Serialize, Deserialize)]
8130pub struct TemporalClusteringConfig {
8131 #[serde(default = "default_period_end_multiplier")]
8133 pub period_end_multiplier: f64,
8134
8135 #[serde(default = "default_period_end_days")]
8137 pub period_end_days: u32,
8138
8139 #[serde(default = "default_quarter_end_multiplier")]
8141 pub quarter_end_multiplier: f64,
8142
8143 #[serde(default = "default_year_end_multiplier")]
8145 pub year_end_multiplier: f64,
8146}
8147
8148fn default_period_end_multiplier() -> f64 {
8149 2.5
8150}
8151fn default_period_end_days() -> u32 {
8152 5
8153}
8154fn default_quarter_end_multiplier() -> f64 {
8155 1.5
8156}
8157fn default_year_end_multiplier() -> f64 {
8158 2.0
8159}
8160
8161impl Default for TemporalClusteringConfig {
8162 fn default() -> Self {
8163 Self {
8164 period_end_multiplier: default_period_end_multiplier(),
8165 period_end_days: default_period_end_days(),
8166 quarter_end_multiplier: default_quarter_end_multiplier(),
8167 year_end_multiplier: default_year_end_multiplier(),
8168 }
8169 }
8170}
8171
8172#[derive(Debug, Clone, Serialize, Deserialize)]
8174pub struct CoOccurrencePatternConfig {
8175 pub name: String,
8177
8178 pub primary_type: String,
8180
8181 pub correlated: Vec<CorrelatedAnomalyConfig>,
8183}
8184
8185#[derive(Debug, Clone, Serialize, Deserialize)]
8187pub struct CorrelatedAnomalyConfig {
8188 pub anomaly_type: String,
8190
8191 pub probability: f64,
8193
8194 pub lag_days_min: i32,
8196
8197 pub lag_days_max: i32,
8199}
8200
8201#[derive(Debug, Clone, Serialize, Deserialize)]
8203pub struct NearMissConfig {
8204 #[serde(default)]
8206 pub enabled: bool,
8207
8208 #[serde(default = "default_near_miss_proportion")]
8210 pub proportion: f64,
8211
8212 #[serde(default = "default_true_val")]
8214 pub near_duplicate: bool,
8215
8216 #[serde(default)]
8218 pub near_duplicate_days: NearDuplicateDaysConfig,
8219
8220 #[serde(default = "default_true_val")]
8222 pub threshold_proximity: bool,
8223
8224 #[serde(default)]
8226 pub threshold_proximity_range: ThresholdProximityRangeConfig,
8227
8228 #[serde(default = "default_true_val")]
8230 pub unusual_legitimate: bool,
8231
8232 #[serde(default = "default_unusual_legitimate_types")]
8234 pub unusual_legitimate_types: Vec<String>,
8235
8236 #[serde(default = "default_true_val")]
8238 pub corrected_errors: bool,
8239
8240 #[serde(default)]
8242 pub corrected_error_lag: CorrectedErrorLagConfig,
8243}
8244
8245fn default_near_miss_proportion() -> f64 {
8246 0.30
8247}
8248
8249fn default_unusual_legitimate_types() -> Vec<String> {
8250 vec![
8251 "year_end_bonus".to_string(),
8252 "contract_prepayment".to_string(),
8253 "insurance_claim".to_string(),
8254 "settlement_payment".to_string(),
8255 ]
8256}
8257
8258impl Default for NearMissConfig {
8259 fn default() -> Self {
8260 Self {
8261 enabled: false,
8262 proportion: default_near_miss_proportion(),
8263 near_duplicate: true,
8264 near_duplicate_days: NearDuplicateDaysConfig::default(),
8265 threshold_proximity: true,
8266 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8267 unusual_legitimate: true,
8268 unusual_legitimate_types: default_unusual_legitimate_types(),
8269 corrected_errors: true,
8270 corrected_error_lag: CorrectedErrorLagConfig::default(),
8271 }
8272 }
8273}
8274
8275#[derive(Debug, Clone, Serialize, Deserialize)]
8277pub struct NearDuplicateDaysConfig {
8278 #[serde(default = "default_near_duplicate_min")]
8280 pub min: u32,
8281
8282 #[serde(default = "default_near_duplicate_max")]
8284 pub max: u32,
8285}
8286
8287fn default_near_duplicate_min() -> u32 {
8288 1
8289}
8290fn default_near_duplicate_max() -> u32 {
8291 3
8292}
8293
8294impl Default for NearDuplicateDaysConfig {
8295 fn default() -> Self {
8296 Self {
8297 min: default_near_duplicate_min(),
8298 max: default_near_duplicate_max(),
8299 }
8300 }
8301}
8302
8303#[derive(Debug, Clone, Serialize, Deserialize)]
8305pub struct ThresholdProximityRangeConfig {
8306 #[serde(default = "default_threshold_proximity_min")]
8308 pub min: f64,
8309
8310 #[serde(default = "default_threshold_proximity_max")]
8312 pub max: f64,
8313}
8314
8315fn default_threshold_proximity_min() -> f64 {
8316 0.90
8317}
8318fn default_threshold_proximity_max() -> f64 {
8319 0.99
8320}
8321
8322impl Default for ThresholdProximityRangeConfig {
8323 fn default() -> Self {
8324 Self {
8325 min: default_threshold_proximity_min(),
8326 max: default_threshold_proximity_max(),
8327 }
8328 }
8329}
8330
8331#[derive(Debug, Clone, Serialize, Deserialize)]
8333pub struct CorrectedErrorLagConfig {
8334 #[serde(default = "default_corrected_error_lag_min")]
8336 pub min: u32,
8337
8338 #[serde(default = "default_corrected_error_lag_max")]
8340 pub max: u32,
8341}
8342
8343fn default_corrected_error_lag_min() -> u32 {
8344 1
8345}
8346fn default_corrected_error_lag_max() -> u32 {
8347 5
8348}
8349
8350impl Default for CorrectedErrorLagConfig {
8351 fn default() -> Self {
8352 Self {
8353 min: default_corrected_error_lag_min(),
8354 max: default_corrected_error_lag_max(),
8355 }
8356 }
8357}
8358
8359#[derive(Debug, Clone, Serialize, Deserialize)]
8361pub struct DifficultyClassificationConfig {
8362 #[serde(default)]
8364 pub enabled: bool,
8365
8366 #[serde(default)]
8368 pub target_distribution: DifficultyDistributionConfig,
8369}
8370
8371impl Default for DifficultyClassificationConfig {
8372 fn default() -> Self {
8373 Self {
8374 enabled: true,
8375 target_distribution: DifficultyDistributionConfig::default(),
8376 }
8377 }
8378}
8379
8380#[derive(Debug, Clone, Serialize, Deserialize)]
8382pub struct DifficultyDistributionConfig {
8383 #[serde(default = "default_difficulty_trivial")]
8385 pub trivial: f64,
8386
8387 #[serde(default = "default_difficulty_easy")]
8389 pub easy: f64,
8390
8391 #[serde(default = "default_difficulty_moderate")]
8393 pub moderate: f64,
8394
8395 #[serde(default = "default_difficulty_hard")]
8397 pub hard: f64,
8398
8399 #[serde(default = "default_difficulty_expert")]
8401 pub expert: f64,
8402}
8403
8404fn default_difficulty_trivial() -> f64 {
8405 0.15
8406}
8407fn default_difficulty_easy() -> f64 {
8408 0.25
8409}
8410fn default_difficulty_moderate() -> f64 {
8411 0.30
8412}
8413fn default_difficulty_hard() -> f64 {
8414 0.20
8415}
8416fn default_difficulty_expert() -> f64 {
8417 0.10
8418}
8419
8420impl Default for DifficultyDistributionConfig {
8421 fn default() -> Self {
8422 Self {
8423 trivial: default_difficulty_trivial(),
8424 easy: default_difficulty_easy(),
8425 moderate: default_difficulty_moderate(),
8426 hard: default_difficulty_hard(),
8427 expert: default_difficulty_expert(),
8428 }
8429 }
8430}
8431
8432#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8434pub struct ContextAwareConfig {
8435 #[serde(default)]
8437 pub enabled: bool,
8438
8439 #[serde(default)]
8441 pub vendor_rules: VendorAnomalyRulesConfig,
8442
8443 #[serde(default)]
8445 pub employee_rules: EmployeeAnomalyRulesConfig,
8446
8447 #[serde(default)]
8449 pub account_rules: AccountAnomalyRulesConfig,
8450
8451 #[serde(default)]
8453 pub behavioral_baseline: BehavioralBaselineConfig,
8454}
8455
8456#[derive(Debug, Clone, Serialize, Deserialize)]
8458pub struct VendorAnomalyRulesConfig {
8459 #[serde(default = "default_new_vendor_multiplier")]
8461 pub new_vendor_error_multiplier: f64,
8462
8463 #[serde(default = "default_new_vendor_threshold")]
8465 pub new_vendor_threshold_days: u32,
8466
8467 #[serde(default = "default_international_multiplier")]
8469 pub international_error_multiplier: f64,
8470
8471 #[serde(default = "default_strategic_vendor_types")]
8473 pub strategic_vendor_anomaly_types: Vec<String>,
8474}
8475
8476fn default_new_vendor_multiplier() -> f64 {
8477 2.5
8478}
8479fn default_new_vendor_threshold() -> u32 {
8480 90
8481}
8482fn default_international_multiplier() -> f64 {
8483 1.5
8484}
8485fn default_strategic_vendor_types() -> Vec<String> {
8486 vec![
8487 "pricing_dispute".to_string(),
8488 "contract_violation".to_string(),
8489 ]
8490}
8491
8492impl Default for VendorAnomalyRulesConfig {
8493 fn default() -> Self {
8494 Self {
8495 new_vendor_error_multiplier: default_new_vendor_multiplier(),
8496 new_vendor_threshold_days: default_new_vendor_threshold(),
8497 international_error_multiplier: default_international_multiplier(),
8498 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8499 }
8500 }
8501}
8502
8503#[derive(Debug, Clone, Serialize, Deserialize)]
8505pub struct EmployeeAnomalyRulesConfig {
8506 #[serde(default = "default_new_employee_rate")]
8508 pub new_employee_error_rate: f64,
8509
8510 #[serde(default = "default_new_employee_threshold")]
8512 pub new_employee_threshold_days: u32,
8513
8514 #[serde(default = "default_volume_fatigue_threshold")]
8516 pub volume_fatigue_threshold: u32,
8517
8518 #[serde(default = "default_coverage_multiplier")]
8520 pub coverage_error_multiplier: f64,
8521}
8522
8523fn default_new_employee_rate() -> f64 {
8524 0.05
8525}
8526fn default_new_employee_threshold() -> u32 {
8527 180
8528}
8529fn default_volume_fatigue_threshold() -> u32 {
8530 50
8531}
8532fn default_coverage_multiplier() -> f64 {
8533 1.8
8534}
8535
8536impl Default for EmployeeAnomalyRulesConfig {
8537 fn default() -> Self {
8538 Self {
8539 new_employee_error_rate: default_new_employee_rate(),
8540 new_employee_threshold_days: default_new_employee_threshold(),
8541 volume_fatigue_threshold: default_volume_fatigue_threshold(),
8542 coverage_error_multiplier: default_coverage_multiplier(),
8543 }
8544 }
8545}
8546
8547#[derive(Debug, Clone, Serialize, Deserialize)]
8549pub struct AccountAnomalyRulesConfig {
8550 #[serde(default = "default_high_risk_multiplier")]
8552 pub high_risk_account_multiplier: f64,
8553
8554 #[serde(default = "default_high_risk_accounts")]
8556 pub high_risk_accounts: Vec<String>,
8557
8558 #[serde(default = "default_suspense_multiplier")]
8560 pub suspense_account_multiplier: f64,
8561
8562 #[serde(default = "default_suspense_accounts")]
8564 pub suspense_accounts: Vec<String>,
8565
8566 #[serde(default = "default_intercompany_multiplier")]
8568 pub intercompany_account_multiplier: f64,
8569}
8570
8571fn default_high_risk_multiplier() -> f64 {
8572 2.0
8573}
8574fn default_high_risk_accounts() -> Vec<String> {
8575 vec![
8576 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
8580}
8581fn default_suspense_multiplier() -> f64 {
8582 3.0
8583}
8584fn default_suspense_accounts() -> Vec<String> {
8585 vec!["9999".to_string(), "9998".to_string()]
8586}
8587fn default_intercompany_multiplier() -> f64 {
8588 1.5
8589}
8590
8591impl Default for AccountAnomalyRulesConfig {
8592 fn default() -> Self {
8593 Self {
8594 high_risk_account_multiplier: default_high_risk_multiplier(),
8595 high_risk_accounts: default_high_risk_accounts(),
8596 suspense_account_multiplier: default_suspense_multiplier(),
8597 suspense_accounts: default_suspense_accounts(),
8598 intercompany_account_multiplier: default_intercompany_multiplier(),
8599 }
8600 }
8601}
8602
8603#[derive(Debug, Clone, Serialize, Deserialize)]
8605pub struct BehavioralBaselineConfig {
8606 #[serde(default)]
8608 pub enabled: bool,
8609
8610 #[serde(default = "default_baseline_period")]
8612 pub baseline_period_days: u32,
8613
8614 #[serde(default = "default_deviation_threshold")]
8616 pub deviation_threshold_std: f64,
8617
8618 #[serde(default = "default_frequency_deviation")]
8620 pub frequency_deviation_threshold: f64,
8621}
8622
8623fn default_baseline_period() -> u32 {
8624 90
8625}
8626fn default_deviation_threshold() -> f64 {
8627 3.0
8628}
8629fn default_frequency_deviation() -> f64 {
8630 2.0
8631}
8632
8633impl Default for BehavioralBaselineConfig {
8634 fn default() -> Self {
8635 Self {
8636 enabled: false,
8637 baseline_period_days: default_baseline_period(),
8638 deviation_threshold_std: default_deviation_threshold(),
8639 frequency_deviation_threshold: default_frequency_deviation(),
8640 }
8641 }
8642}
8643
8644#[derive(Debug, Clone, Serialize, Deserialize)]
8646pub struct EnhancedLabelingConfig {
8647 #[serde(default = "default_true_val")]
8649 pub severity_scoring: bool,
8650
8651 #[serde(default = "default_true_val")]
8653 pub difficulty_classification: bool,
8654
8655 #[serde(default)]
8657 pub materiality_thresholds: MaterialityThresholdsConfig,
8658}
8659
8660impl Default for EnhancedLabelingConfig {
8661 fn default() -> Self {
8662 Self {
8663 severity_scoring: true,
8664 difficulty_classification: true,
8665 materiality_thresholds: MaterialityThresholdsConfig::default(),
8666 }
8667 }
8668}
8669
8670#[derive(Debug, Clone, Serialize, Deserialize)]
8672pub struct MaterialityThresholdsConfig {
8673 #[serde(default = "default_materiality_trivial")]
8675 pub trivial: f64,
8676
8677 #[serde(default = "default_materiality_immaterial")]
8679 pub immaterial: f64,
8680
8681 #[serde(default = "default_materiality_material")]
8683 pub material: f64,
8684
8685 #[serde(default = "default_materiality_highly_material")]
8687 pub highly_material: f64,
8688}
8689
8690fn default_materiality_trivial() -> f64 {
8691 0.001
8692}
8693fn default_materiality_immaterial() -> f64 {
8694 0.01
8695}
8696fn default_materiality_material() -> f64 {
8697 0.05
8698}
8699fn default_materiality_highly_material() -> f64 {
8700 0.10
8701}
8702
8703impl Default for MaterialityThresholdsConfig {
8704 fn default() -> Self {
8705 Self {
8706 trivial: default_materiality_trivial(),
8707 immaterial: default_materiality_immaterial(),
8708 material: default_materiality_material(),
8709 highly_material: default_materiality_highly_material(),
8710 }
8711 }
8712}
8713
8714#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8726pub struct IndustrySpecificConfig {
8727 #[serde(default)]
8729 pub enabled: bool,
8730
8731 #[serde(default)]
8733 pub manufacturing: ManufacturingConfig,
8734
8735 #[serde(default)]
8737 pub retail: RetailConfig,
8738
8739 #[serde(default)]
8741 pub healthcare: HealthcareConfig,
8742
8743 #[serde(default)]
8745 pub technology: TechnologyConfig,
8746
8747 #[serde(default)]
8749 pub financial_services: FinancialServicesConfig,
8750
8751 #[serde(default)]
8753 pub professional_services: ProfessionalServicesConfig,
8754}
8755
8756#[derive(Debug, Clone, Serialize, Deserialize)]
8758pub struct ManufacturingConfig {
8759 #[serde(default)]
8761 pub enabled: bool,
8762
8763 #[serde(default = "default_bom_depth")]
8765 pub bom_depth: u32,
8766
8767 #[serde(default)]
8769 pub just_in_time: bool,
8770
8771 #[serde(default = "default_production_order_types")]
8773 pub production_order_types: Vec<String>,
8774
8775 #[serde(default)]
8777 pub quality_framework: Option<String>,
8778
8779 #[serde(default = "default_supplier_tiers")]
8781 pub supplier_tiers: u32,
8782
8783 #[serde(default = "default_cost_frequency")]
8785 pub standard_cost_frequency: String,
8786
8787 #[serde(default = "default_yield_rate")]
8789 pub target_yield_rate: f64,
8790
8791 #[serde(default = "default_scrap_threshold")]
8793 pub scrap_alert_threshold: f64,
8794
8795 #[serde(default)]
8797 pub anomaly_rates: ManufacturingAnomalyRates,
8798}
8799
8800fn default_bom_depth() -> u32 {
8801 4
8802}
8803
8804fn default_production_order_types() -> Vec<String> {
8805 vec![
8806 "standard".to_string(),
8807 "rework".to_string(),
8808 "prototype".to_string(),
8809 ]
8810}
8811
8812fn default_supplier_tiers() -> u32 {
8813 2
8814}
8815
8816fn default_cost_frequency() -> String {
8817 "quarterly".to_string()
8818}
8819
8820fn default_yield_rate() -> f64 {
8821 0.97
8822}
8823
8824fn default_scrap_threshold() -> f64 {
8825 0.03
8826}
8827
8828impl Default for ManufacturingConfig {
8829 fn default() -> Self {
8830 Self {
8831 enabled: false,
8832 bom_depth: default_bom_depth(),
8833 just_in_time: false,
8834 production_order_types: default_production_order_types(),
8835 quality_framework: Some("ISO_9001".to_string()),
8836 supplier_tiers: default_supplier_tiers(),
8837 standard_cost_frequency: default_cost_frequency(),
8838 target_yield_rate: default_yield_rate(),
8839 scrap_alert_threshold: default_scrap_threshold(),
8840 anomaly_rates: ManufacturingAnomalyRates::default(),
8841 }
8842 }
8843}
8844
8845#[derive(Debug, Clone, Serialize, Deserialize)]
8847pub struct ManufacturingAnomalyRates {
8848 #[serde(default = "default_mfg_yield_rate")]
8850 pub yield_manipulation: f64,
8851
8852 #[serde(default = "default_mfg_labor_rate")]
8854 pub labor_misallocation: f64,
8855
8856 #[serde(default = "default_mfg_phantom_rate")]
8858 pub phantom_production: f64,
8859
8860 #[serde(default = "default_mfg_cost_rate")]
8862 pub standard_cost_manipulation: f64,
8863
8864 #[serde(default = "default_mfg_inventory_rate")]
8866 pub inventory_fraud: f64,
8867}
8868
8869fn default_mfg_yield_rate() -> f64 {
8870 0.015
8871}
8872
8873fn default_mfg_labor_rate() -> f64 {
8874 0.02
8875}
8876
8877fn default_mfg_phantom_rate() -> f64 {
8878 0.005
8879}
8880
8881fn default_mfg_cost_rate() -> f64 {
8882 0.01
8883}
8884
8885fn default_mfg_inventory_rate() -> f64 {
8886 0.008
8887}
8888
8889impl Default for ManufacturingAnomalyRates {
8890 fn default() -> Self {
8891 Self {
8892 yield_manipulation: default_mfg_yield_rate(),
8893 labor_misallocation: default_mfg_labor_rate(),
8894 phantom_production: default_mfg_phantom_rate(),
8895 standard_cost_manipulation: default_mfg_cost_rate(),
8896 inventory_fraud: default_mfg_inventory_rate(),
8897 }
8898 }
8899}
8900
8901#[derive(Debug, Clone, Serialize, Deserialize)]
8903pub struct RetailConfig {
8904 #[serde(default)]
8906 pub enabled: bool,
8907
8908 #[serde(default)]
8910 pub store_types: RetailStoreTypeConfig,
8911
8912 #[serde(default = "default_retail_daily_txns")]
8914 pub avg_daily_transactions: u32,
8915
8916 #[serde(default = "default_true")]
8918 pub loss_prevention: bool,
8919
8920 #[serde(default = "default_shrinkage_rate")]
8922 pub shrinkage_rate: f64,
8923
8924 #[serde(default)]
8926 pub anomaly_rates: RetailAnomalyRates,
8927}
8928
8929fn default_retail_daily_txns() -> u32 {
8930 500
8931}
8932
8933fn default_shrinkage_rate() -> f64 {
8934 0.015
8935}
8936
8937impl Default for RetailConfig {
8938 fn default() -> Self {
8939 Self {
8940 enabled: false,
8941 store_types: RetailStoreTypeConfig::default(),
8942 avg_daily_transactions: default_retail_daily_txns(),
8943 loss_prevention: true,
8944 shrinkage_rate: default_shrinkage_rate(),
8945 anomaly_rates: RetailAnomalyRates::default(),
8946 }
8947 }
8948}
8949
8950#[derive(Debug, Clone, Serialize, Deserialize)]
8952pub struct RetailStoreTypeConfig {
8953 #[serde(default = "default_flagship_pct")]
8955 pub flagship: f64,
8956
8957 #[serde(default = "default_regional_pct")]
8959 pub regional: f64,
8960
8961 #[serde(default = "default_outlet_pct")]
8963 pub outlet: f64,
8964
8965 #[serde(default = "default_ecommerce_pct")]
8967 pub ecommerce: f64,
8968}
8969
8970fn default_flagship_pct() -> f64 {
8971 0.10
8972}
8973
8974fn default_regional_pct() -> f64 {
8975 0.50
8976}
8977
8978fn default_outlet_pct() -> f64 {
8979 0.25
8980}
8981
8982fn default_ecommerce_pct() -> f64 {
8983 0.15
8984}
8985
8986impl Default for RetailStoreTypeConfig {
8987 fn default() -> Self {
8988 Self {
8989 flagship: default_flagship_pct(),
8990 regional: default_regional_pct(),
8991 outlet: default_outlet_pct(),
8992 ecommerce: default_ecommerce_pct(),
8993 }
8994 }
8995}
8996
8997#[derive(Debug, Clone, Serialize, Deserialize)]
8999pub struct RetailAnomalyRates {
9000 #[serde(default = "default_sweethearting_rate")]
9002 pub sweethearting: f64,
9003
9004 #[serde(default = "default_skimming_rate")]
9006 pub skimming: f64,
9007
9008 #[serde(default = "default_refund_fraud_rate")]
9010 pub refund_fraud: f64,
9011
9012 #[serde(default = "default_void_abuse_rate")]
9014 pub void_abuse: f64,
9015
9016 #[serde(default = "default_gift_card_rate")]
9018 pub gift_card_fraud: f64,
9019
9020 #[serde(default = "default_retail_kickback_rate")]
9022 pub vendor_kickback: f64,
9023}
9024
9025fn default_sweethearting_rate() -> f64 {
9026 0.02
9027}
9028
9029fn default_skimming_rate() -> f64 {
9030 0.005
9031}
9032
9033fn default_refund_fraud_rate() -> f64 {
9034 0.015
9035}
9036
9037fn default_void_abuse_rate() -> f64 {
9038 0.01
9039}
9040
9041fn default_gift_card_rate() -> f64 {
9042 0.008
9043}
9044
9045fn default_retail_kickback_rate() -> f64 {
9046 0.003
9047}
9048
9049impl Default for RetailAnomalyRates {
9050 fn default() -> Self {
9051 Self {
9052 sweethearting: default_sweethearting_rate(),
9053 skimming: default_skimming_rate(),
9054 refund_fraud: default_refund_fraud_rate(),
9055 void_abuse: default_void_abuse_rate(),
9056 gift_card_fraud: default_gift_card_rate(),
9057 vendor_kickback: default_retail_kickback_rate(),
9058 }
9059 }
9060}
9061
9062#[derive(Debug, Clone, Serialize, Deserialize)]
9064pub struct HealthcareConfig {
9065 #[serde(default)]
9067 pub enabled: bool,
9068
9069 #[serde(default = "default_facility_type")]
9071 pub facility_type: String,
9072
9073 #[serde(default)]
9075 pub payer_mix: HealthcarePayerMix,
9076
9077 #[serde(default)]
9079 pub coding_systems: HealthcareCodingSystems,
9080
9081 #[serde(default)]
9083 pub compliance: HealthcareComplianceConfig,
9084
9085 #[serde(default = "default_daily_encounters")]
9087 pub avg_daily_encounters: u32,
9088
9089 #[serde(default = "default_charges_per_encounter")]
9091 pub avg_charges_per_encounter: u32,
9092
9093 #[serde(default = "default_hc_denial_rate")]
9095 pub denial_rate: f64,
9096
9097 #[serde(default = "default_hc_bad_debt_rate")]
9099 pub bad_debt_rate: f64,
9100
9101 #[serde(default = "default_hc_charity_care_rate")]
9103 pub charity_care_rate: f64,
9104
9105 #[serde(default)]
9107 pub anomaly_rates: HealthcareAnomalyRates,
9108}
9109
9110fn default_facility_type() -> String {
9111 "hospital".to_string()
9112}
9113
9114fn default_daily_encounters() -> u32 {
9115 150
9116}
9117
9118fn default_charges_per_encounter() -> u32 {
9119 8
9120}
9121
9122fn default_hc_denial_rate() -> f64 {
9123 0.05
9124}
9125
9126fn default_hc_bad_debt_rate() -> f64 {
9127 0.03
9128}
9129
9130fn default_hc_charity_care_rate() -> f64 {
9131 0.02
9132}
9133
9134impl Default for HealthcareConfig {
9135 fn default() -> Self {
9136 Self {
9137 enabled: false,
9138 facility_type: default_facility_type(),
9139 payer_mix: HealthcarePayerMix::default(),
9140 coding_systems: HealthcareCodingSystems::default(),
9141 compliance: HealthcareComplianceConfig::default(),
9142 avg_daily_encounters: default_daily_encounters(),
9143 avg_charges_per_encounter: default_charges_per_encounter(),
9144 denial_rate: default_hc_denial_rate(),
9145 bad_debt_rate: default_hc_bad_debt_rate(),
9146 charity_care_rate: default_hc_charity_care_rate(),
9147 anomaly_rates: HealthcareAnomalyRates::default(),
9148 }
9149 }
9150}
9151
9152#[derive(Debug, Clone, Serialize, Deserialize)]
9154pub struct HealthcarePayerMix {
9155 #[serde(default = "default_medicare_pct")]
9157 pub medicare: f64,
9158
9159 #[serde(default = "default_medicaid_pct")]
9161 pub medicaid: f64,
9162
9163 #[serde(default = "default_commercial_pct")]
9165 pub commercial: f64,
9166
9167 #[serde(default = "default_self_pay_pct")]
9169 pub self_pay: f64,
9170}
9171
9172fn default_medicare_pct() -> f64 {
9173 0.40
9174}
9175
9176fn default_medicaid_pct() -> f64 {
9177 0.20
9178}
9179
9180fn default_commercial_pct() -> f64 {
9181 0.30
9182}
9183
9184fn default_self_pay_pct() -> f64 {
9185 0.10
9186}
9187
9188impl Default for HealthcarePayerMix {
9189 fn default() -> Self {
9190 Self {
9191 medicare: default_medicare_pct(),
9192 medicaid: default_medicaid_pct(),
9193 commercial: default_commercial_pct(),
9194 self_pay: default_self_pay_pct(),
9195 }
9196 }
9197}
9198
9199#[derive(Debug, Clone, Serialize, Deserialize)]
9201pub struct HealthcareCodingSystems {
9202 #[serde(default = "default_true")]
9204 pub icd10: bool,
9205
9206 #[serde(default = "default_true")]
9208 pub cpt: bool,
9209
9210 #[serde(default = "default_true")]
9212 pub drg: bool,
9213
9214 #[serde(default = "default_true")]
9216 pub hcpcs: bool,
9217
9218 #[serde(default = "default_true")]
9220 pub revenue_codes: bool,
9221}
9222
9223impl Default for HealthcareCodingSystems {
9224 fn default() -> Self {
9225 Self {
9226 icd10: true,
9227 cpt: true,
9228 drg: true,
9229 hcpcs: true,
9230 revenue_codes: true,
9231 }
9232 }
9233}
9234
9235#[derive(Debug, Clone, Serialize, Deserialize)]
9237pub struct HealthcareComplianceConfig {
9238 #[serde(default = "default_true")]
9240 pub hipaa: bool,
9241
9242 #[serde(default = "default_true")]
9244 pub stark_law: bool,
9245
9246 #[serde(default = "default_true")]
9248 pub anti_kickback: bool,
9249
9250 #[serde(default = "default_true")]
9252 pub false_claims_act: bool,
9253
9254 #[serde(default = "default_true")]
9256 pub emtala: bool,
9257}
9258
9259impl Default for HealthcareComplianceConfig {
9260 fn default() -> Self {
9261 Self {
9262 hipaa: true,
9263 stark_law: true,
9264 anti_kickback: true,
9265 false_claims_act: true,
9266 emtala: true,
9267 }
9268 }
9269}
9270
9271#[derive(Debug, Clone, Serialize, Deserialize)]
9273pub struct HealthcareAnomalyRates {
9274 #[serde(default = "default_upcoding_rate")]
9276 pub upcoding: f64,
9277
9278 #[serde(default = "default_unbundling_rate")]
9280 pub unbundling: f64,
9281
9282 #[serde(default = "default_phantom_billing_rate")]
9284 pub phantom_billing: f64,
9285
9286 #[serde(default = "default_healthcare_kickback_rate")]
9288 pub kickbacks: f64,
9289
9290 #[serde(default = "default_duplicate_billing_rate")]
9292 pub duplicate_billing: f64,
9293
9294 #[serde(default = "default_med_necessity_rate")]
9296 pub medical_necessity_abuse: f64,
9297}
9298
9299fn default_upcoding_rate() -> f64 {
9300 0.02
9301}
9302
9303fn default_unbundling_rate() -> f64 {
9304 0.015
9305}
9306
9307fn default_phantom_billing_rate() -> f64 {
9308 0.005
9309}
9310
9311fn default_healthcare_kickback_rate() -> f64 {
9312 0.003
9313}
9314
9315fn default_duplicate_billing_rate() -> f64 {
9316 0.008
9317}
9318
9319fn default_med_necessity_rate() -> f64 {
9320 0.01
9321}
9322
9323impl Default for HealthcareAnomalyRates {
9324 fn default() -> Self {
9325 Self {
9326 upcoding: default_upcoding_rate(),
9327 unbundling: default_unbundling_rate(),
9328 phantom_billing: default_phantom_billing_rate(),
9329 kickbacks: default_healthcare_kickback_rate(),
9330 duplicate_billing: default_duplicate_billing_rate(),
9331 medical_necessity_abuse: default_med_necessity_rate(),
9332 }
9333 }
9334}
9335
9336#[derive(Debug, Clone, Serialize, Deserialize)]
9338pub struct TechnologyConfig {
9339 #[serde(default)]
9341 pub enabled: bool,
9342
9343 #[serde(default = "default_revenue_model")]
9345 pub revenue_model: String,
9346
9347 #[serde(default = "default_subscription_pct")]
9349 pub subscription_revenue_pct: f64,
9350
9351 #[serde(default = "default_license_pct")]
9353 pub license_revenue_pct: f64,
9354
9355 #[serde(default = "default_services_pct")]
9357 pub services_revenue_pct: f64,
9358
9359 #[serde(default)]
9361 pub rd_capitalization: RdCapitalizationConfig,
9362
9363 #[serde(default)]
9365 pub anomaly_rates: TechnologyAnomalyRates,
9366}
9367
9368fn default_revenue_model() -> String {
9369 "saas".to_string()
9370}
9371
9372fn default_subscription_pct() -> f64 {
9373 0.60
9374}
9375
9376fn default_license_pct() -> f64 {
9377 0.25
9378}
9379
9380fn default_services_pct() -> f64 {
9381 0.15
9382}
9383
9384impl Default for TechnologyConfig {
9385 fn default() -> Self {
9386 Self {
9387 enabled: false,
9388 revenue_model: default_revenue_model(),
9389 subscription_revenue_pct: default_subscription_pct(),
9390 license_revenue_pct: default_license_pct(),
9391 services_revenue_pct: default_services_pct(),
9392 rd_capitalization: RdCapitalizationConfig::default(),
9393 anomaly_rates: TechnologyAnomalyRates::default(),
9394 }
9395 }
9396}
9397
9398#[derive(Debug, Clone, Serialize, Deserialize)]
9400pub struct RdCapitalizationConfig {
9401 #[serde(default = "default_true")]
9403 pub enabled: bool,
9404
9405 #[serde(default = "default_cap_rate")]
9407 pub capitalization_rate: f64,
9408
9409 #[serde(default = "default_useful_life")]
9411 pub useful_life_years: u32,
9412}
9413
9414fn default_cap_rate() -> f64 {
9415 0.30
9416}
9417
9418fn default_useful_life() -> u32 {
9419 3
9420}
9421
9422impl Default for RdCapitalizationConfig {
9423 fn default() -> Self {
9424 Self {
9425 enabled: true,
9426 capitalization_rate: default_cap_rate(),
9427 useful_life_years: default_useful_life(),
9428 }
9429 }
9430}
9431
9432#[derive(Debug, Clone, Serialize, Deserialize)]
9434pub struct TechnologyAnomalyRates {
9435 #[serde(default = "default_premature_rev_rate")]
9437 pub premature_revenue: f64,
9438
9439 #[serde(default = "default_side_letter_rate")]
9441 pub side_letter_abuse: f64,
9442
9443 #[serde(default = "default_channel_stuffing_rate")]
9445 pub channel_stuffing: f64,
9446
9447 #[serde(default = "default_improper_cap_rate")]
9449 pub improper_capitalization: f64,
9450}
9451
9452fn default_premature_rev_rate() -> f64 {
9453 0.015
9454}
9455
9456fn default_side_letter_rate() -> f64 {
9457 0.008
9458}
9459
9460fn default_channel_stuffing_rate() -> f64 {
9461 0.01
9462}
9463
9464fn default_improper_cap_rate() -> f64 {
9465 0.012
9466}
9467
9468impl Default for TechnologyAnomalyRates {
9469 fn default() -> Self {
9470 Self {
9471 premature_revenue: default_premature_rev_rate(),
9472 side_letter_abuse: default_side_letter_rate(),
9473 channel_stuffing: default_channel_stuffing_rate(),
9474 improper_capitalization: default_improper_cap_rate(),
9475 }
9476 }
9477}
9478
9479#[derive(Debug, Clone, Serialize, Deserialize)]
9481pub struct FinancialServicesConfig {
9482 #[serde(default)]
9484 pub enabled: bool,
9485
9486 #[serde(default = "default_fi_type")]
9488 pub institution_type: String,
9489
9490 #[serde(default = "default_fi_regulatory")]
9492 pub regulatory_framework: String,
9493
9494 #[serde(default)]
9496 pub anomaly_rates: FinancialServicesAnomalyRates,
9497}
9498
9499fn default_fi_type() -> String {
9500 "commercial_bank".to_string()
9501}
9502
9503fn default_fi_regulatory() -> String {
9504 "us_banking".to_string()
9505}
9506
9507impl Default for FinancialServicesConfig {
9508 fn default() -> Self {
9509 Self {
9510 enabled: false,
9511 institution_type: default_fi_type(),
9512 regulatory_framework: default_fi_regulatory(),
9513 anomaly_rates: FinancialServicesAnomalyRates::default(),
9514 }
9515 }
9516}
9517
9518#[derive(Debug, Clone, Serialize, Deserialize)]
9520pub struct FinancialServicesAnomalyRates {
9521 #[serde(default = "default_loan_fraud_rate")]
9523 pub loan_fraud: f64,
9524
9525 #[serde(default = "default_trading_fraud_rate")]
9527 pub trading_fraud: f64,
9528
9529 #[serde(default = "default_insurance_fraud_rate")]
9531 pub insurance_fraud: f64,
9532
9533 #[serde(default = "default_account_manip_rate")]
9535 pub account_manipulation: f64,
9536}
9537
9538fn default_loan_fraud_rate() -> f64 {
9539 0.01
9540}
9541
9542fn default_trading_fraud_rate() -> f64 {
9543 0.008
9544}
9545
9546fn default_insurance_fraud_rate() -> f64 {
9547 0.012
9548}
9549
9550fn default_account_manip_rate() -> f64 {
9551 0.005
9552}
9553
9554impl Default for FinancialServicesAnomalyRates {
9555 fn default() -> Self {
9556 Self {
9557 loan_fraud: default_loan_fraud_rate(),
9558 trading_fraud: default_trading_fraud_rate(),
9559 insurance_fraud: default_insurance_fraud_rate(),
9560 account_manipulation: default_account_manip_rate(),
9561 }
9562 }
9563}
9564
9565#[derive(Debug, Clone, Serialize, Deserialize)]
9567pub struct ProfessionalServicesConfig {
9568 #[serde(default)]
9570 pub enabled: bool,
9571
9572 #[serde(default = "default_firm_type")]
9574 pub firm_type: String,
9575
9576 #[serde(default = "default_billing_model")]
9578 pub billing_model: String,
9579
9580 #[serde(default = "default_hourly_rate")]
9582 pub avg_hourly_rate: f64,
9583
9584 #[serde(default)]
9586 pub trust_accounting: TrustAccountingConfig,
9587
9588 #[serde(default)]
9590 pub anomaly_rates: ProfessionalServicesAnomalyRates,
9591}
9592
9593fn default_firm_type() -> String {
9594 "consulting".to_string()
9595}
9596
9597fn default_billing_model() -> String {
9598 "time_and_materials".to_string()
9599}
9600
9601fn default_hourly_rate() -> f64 {
9602 250.0
9603}
9604
9605impl Default for ProfessionalServicesConfig {
9606 fn default() -> Self {
9607 Self {
9608 enabled: false,
9609 firm_type: default_firm_type(),
9610 billing_model: default_billing_model(),
9611 avg_hourly_rate: default_hourly_rate(),
9612 trust_accounting: TrustAccountingConfig::default(),
9613 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9614 }
9615 }
9616}
9617
9618#[derive(Debug, Clone, Serialize, Deserialize)]
9620pub struct TrustAccountingConfig {
9621 #[serde(default)]
9623 pub enabled: bool,
9624
9625 #[serde(default = "default_true")]
9627 pub require_three_way_reconciliation: bool,
9628}
9629
9630impl Default for TrustAccountingConfig {
9631 fn default() -> Self {
9632 Self {
9633 enabled: false,
9634 require_three_way_reconciliation: true,
9635 }
9636 }
9637}
9638
9639#[derive(Debug, Clone, Serialize, Deserialize)]
9641pub struct ProfessionalServicesAnomalyRates {
9642 #[serde(default = "default_time_fraud_rate")]
9644 pub time_billing_fraud: f64,
9645
9646 #[serde(default = "default_expense_fraud_rate")]
9648 pub expense_fraud: f64,
9649
9650 #[serde(default = "default_trust_misappropriation_rate")]
9652 pub trust_misappropriation: f64,
9653}
9654
9655fn default_time_fraud_rate() -> f64 {
9656 0.02
9657}
9658
9659fn default_expense_fraud_rate() -> f64 {
9660 0.015
9661}
9662
9663fn default_trust_misappropriation_rate() -> f64 {
9664 0.003
9665}
9666
9667impl Default for ProfessionalServicesAnomalyRates {
9668 fn default() -> Self {
9669 Self {
9670 time_billing_fraud: default_time_fraud_rate(),
9671 expense_fraud: default_expense_fraud_rate(),
9672 trust_misappropriation: default_trust_misappropriation_rate(),
9673 }
9674 }
9675}
9676
9677#[derive(Debug, Clone, Serialize, Deserialize)]
9691pub struct FingerprintPrivacyConfig {
9692 #[serde(default)]
9694 pub level: String,
9695 #[serde(default = "default_epsilon")]
9697 pub epsilon: f64,
9698 #[serde(default = "default_delta")]
9700 pub delta: f64,
9701 #[serde(default = "default_k_anonymity")]
9703 pub k_anonymity: u32,
9704 #[serde(default)]
9706 pub composition_method: String,
9707}
9708
9709fn default_epsilon() -> f64 {
9710 1.0
9711}
9712
9713fn default_delta() -> f64 {
9714 1e-5
9715}
9716
9717fn default_k_anonymity() -> u32 {
9718 5
9719}
9720
9721impl Default for FingerprintPrivacyConfig {
9722 fn default() -> Self {
9723 Self {
9724 level: "standard".to_string(),
9725 epsilon: default_epsilon(),
9726 delta: default_delta(),
9727 k_anonymity: default_k_anonymity(),
9728 composition_method: "naive".to_string(),
9729 }
9730 }
9731}
9732
9733#[derive(Debug, Clone, Serialize, Deserialize)]
9747pub struct QualityGatesSchemaConfig {
9748 #[serde(default)]
9750 pub enabled: bool,
9751 #[serde(default = "default_gate_profile_name")]
9753 pub profile: String,
9754 #[serde(default)]
9756 pub fail_on_violation: bool,
9757 #[serde(default)]
9759 pub custom_gates: Vec<QualityGateEntry>,
9760}
9761
9762fn default_gate_profile_name() -> String {
9763 "default".to_string()
9764}
9765
9766impl Default for QualityGatesSchemaConfig {
9767 fn default() -> Self {
9768 Self {
9769 enabled: false,
9770 profile: default_gate_profile_name(),
9771 fail_on_violation: false,
9772 custom_gates: Vec::new(),
9773 }
9774 }
9775}
9776
9777#[derive(Debug, Clone, Serialize, Deserialize)]
9779pub struct QualityGateEntry {
9780 pub name: String,
9782 pub metric: String,
9786 pub threshold: f64,
9788 #[serde(default)]
9790 pub upper_threshold: Option<f64>,
9791 #[serde(default = "default_gate_comparison")]
9793 pub comparison: String,
9794}
9795
9796fn default_gate_comparison() -> String {
9797 "gte".to_string()
9798}
9799
9800#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9810pub struct ComplianceSchemaConfig {
9811 #[serde(default)]
9813 pub content_marking: ContentMarkingSchemaConfig,
9814 #[serde(default)]
9816 pub article10_report: bool,
9817 #[serde(default)]
9819 pub certificates: CertificateSchemaConfig,
9820}
9821
9822#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9824pub struct CertificateSchemaConfig {
9825 #[serde(default)]
9827 pub enabled: bool,
9828 #[serde(default)]
9830 pub signing_key_env: Option<String>,
9831 #[serde(default)]
9833 pub include_quality_metrics: bool,
9834}
9835
9836#[derive(Debug, Clone, Serialize, Deserialize)]
9838pub struct ContentMarkingSchemaConfig {
9839 #[serde(default = "default_true")]
9841 pub enabled: bool,
9842 #[serde(default = "default_marking_format")]
9844 pub format: String,
9845}
9846
9847fn default_marking_format() -> String {
9848 "embedded".to_string()
9849}
9850
9851impl Default for ContentMarkingSchemaConfig {
9852 fn default() -> Self {
9853 Self {
9854 enabled: true,
9855 format: default_marking_format(),
9856 }
9857 }
9858}
9859
9860#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9862pub struct WebhookSchemaConfig {
9863 #[serde(default)]
9865 pub enabled: bool,
9866 #[serde(default)]
9868 pub endpoints: Vec<WebhookEndpointConfig>,
9869}
9870
9871#[derive(Debug, Clone, Serialize, Deserialize)]
9873pub struct WebhookEndpointConfig {
9874 pub url: String,
9876 #[serde(default)]
9878 pub events: Vec<String>,
9879 #[serde(default)]
9881 pub secret: Option<String>,
9882 #[serde(default = "default_webhook_retries")]
9884 pub max_retries: u32,
9885 #[serde(default = "default_webhook_timeout")]
9887 pub timeout_secs: u64,
9888}
9889
9890fn default_webhook_retries() -> u32 {
9891 3
9892}
9893fn default_webhook_timeout() -> u64 {
9894 10
9895}
9896
9897#[cfg(test)]
9898#[allow(clippy::unwrap_used)]
9899mod tests {
9900 use super::*;
9901 use crate::presets::demo_preset;
9902
9903 #[test]
9908 fn test_config_yaml_roundtrip() {
9909 let config = demo_preset();
9910 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9911 let deserialized: GeneratorConfig =
9912 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9913
9914 assert_eq!(
9915 config.global.period_months,
9916 deserialized.global.period_months
9917 );
9918 assert_eq!(config.global.industry, deserialized.global.industry);
9919 assert_eq!(config.companies.len(), deserialized.companies.len());
9920 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9921 }
9922
9923 #[test]
9924 fn test_config_json_roundtrip() {
9925 let mut config = demo_preset();
9927 config.master_data.employees.approval_limits.executive = 1e12;
9929
9930 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9931 let deserialized: GeneratorConfig =
9932 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9933
9934 assert_eq!(
9935 config.global.period_months,
9936 deserialized.global.period_months
9937 );
9938 assert_eq!(config.global.industry, deserialized.global.industry);
9939 assert_eq!(config.companies.len(), deserialized.companies.len());
9940 }
9941
9942 #[test]
9943 fn test_transaction_volume_serialization() {
9944 let volumes = vec![
9946 (TransactionVolume::TenK, "ten_k"),
9947 (TransactionVolume::HundredK, "hundred_k"),
9948 (TransactionVolume::OneM, "one_m"),
9949 (TransactionVolume::TenM, "ten_m"),
9950 (TransactionVolume::HundredM, "hundred_m"),
9951 ];
9952
9953 for (volume, expected_key) in volumes {
9954 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9955 assert!(
9956 json.contains(expected_key),
9957 "Expected {} in JSON: {}",
9958 expected_key,
9959 json
9960 );
9961 }
9962 }
9963
9964 #[test]
9965 fn test_transaction_volume_custom_serialization() {
9966 let volume = TransactionVolume::Custom(12345);
9967 let json = serde_json::to_string(&volume).expect("Failed to serialize");
9968 let deserialized: TransactionVolume =
9969 serde_json::from_str(&json).expect("Failed to deserialize");
9970 assert_eq!(deserialized.count(), 12345);
9971 }
9972
9973 #[test]
9974 fn test_output_mode_serialization() {
9975 let modes = vec![
9976 OutputMode::Streaming,
9977 OutputMode::FlatFile,
9978 OutputMode::Both,
9979 ];
9980
9981 for mode in modes {
9982 let json = serde_json::to_string(&mode).expect("Failed to serialize");
9983 let deserialized: OutputMode =
9984 serde_json::from_str(&json).expect("Failed to deserialize");
9985 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9986 }
9987 }
9988
9989 #[test]
9990 fn test_file_format_serialization() {
9991 let formats = vec![
9992 FileFormat::Csv,
9993 FileFormat::Parquet,
9994 FileFormat::Json,
9995 FileFormat::JsonLines,
9996 ];
9997
9998 for format in formats {
9999 let json = serde_json::to_string(&format).expect("Failed to serialize");
10000 let deserialized: FileFormat =
10001 serde_json::from_str(&json).expect("Failed to deserialize");
10002 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
10003 }
10004 }
10005
10006 #[test]
10007 fn test_compression_algorithm_serialization() {
10008 let algos = vec![
10009 CompressionAlgorithm::Gzip,
10010 CompressionAlgorithm::Zstd,
10011 CompressionAlgorithm::Lz4,
10012 CompressionAlgorithm::Snappy,
10013 ];
10014
10015 for algo in algos {
10016 let json = serde_json::to_string(&algo).expect("Failed to serialize");
10017 let deserialized: CompressionAlgorithm =
10018 serde_json::from_str(&json).expect("Failed to deserialize");
10019 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
10020 }
10021 }
10022
10023 #[test]
10024 fn test_transfer_pricing_method_serialization() {
10025 let methods = vec![
10026 TransferPricingMethod::CostPlus,
10027 TransferPricingMethod::ComparableUncontrolled,
10028 TransferPricingMethod::ResalePrice,
10029 TransferPricingMethod::TransactionalNetMargin,
10030 TransferPricingMethod::ProfitSplit,
10031 ];
10032
10033 for method in methods {
10034 let json = serde_json::to_string(&method).expect("Failed to serialize");
10035 let deserialized: TransferPricingMethod =
10036 serde_json::from_str(&json).expect("Failed to deserialize");
10037 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
10038 }
10039 }
10040
10041 #[test]
10042 fn test_benford_exemption_serialization() {
10043 let exemptions = vec![
10044 BenfordExemption::Recurring,
10045 BenfordExemption::Payroll,
10046 BenfordExemption::FixedFees,
10047 BenfordExemption::RoundAmounts,
10048 ];
10049
10050 for exemption in exemptions {
10051 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
10052 let deserialized: BenfordExemption =
10053 serde_json::from_str(&json).expect("Failed to deserialize");
10054 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
10055 }
10056 }
10057
10058 #[test]
10063 fn test_global_config_defaults() {
10064 let yaml = r#"
10065 industry: manufacturing
10066 start_date: "2024-01-01"
10067 period_months: 6
10068 "#;
10069 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10070 assert_eq!(config.group_currency, "USD");
10071 assert!(config.parallel);
10072 assert_eq!(config.worker_threads, 0);
10073 assert_eq!(config.memory_limit_mb, 0);
10074 }
10075
10076 #[test]
10077 fn test_fraud_config_defaults() {
10078 let config = FraudConfig::default();
10079 assert!(!config.enabled);
10080 assert_eq!(config.fraud_rate, 0.005);
10081 assert!(!config.clustering_enabled);
10082 }
10083
10084 #[test]
10085 fn test_internal_controls_config_defaults() {
10086 let config = InternalControlsConfig::default();
10087 assert!(!config.enabled);
10088 assert_eq!(config.exception_rate, 0.02);
10089 assert_eq!(config.sod_violation_rate, 0.01);
10090 assert!(config.export_control_master_data);
10091 assert_eq!(config.sox_materiality_threshold, 10000.0);
10092 assert!(config.coso_enabled);
10094 assert!(!config.include_entity_level_controls);
10095 assert_eq!(config.target_maturity_level, "mixed");
10096 }
10097
10098 #[test]
10099 fn test_output_config_defaults() {
10100 let config = OutputConfig::default();
10101 assert!(matches!(config.mode, OutputMode::FlatFile));
10102 assert_eq!(config.formats, vec![FileFormat::Parquet]);
10103 assert!(config.compression.enabled);
10104 assert!(matches!(
10105 config.compression.algorithm,
10106 CompressionAlgorithm::Zstd
10107 ));
10108 assert!(config.include_acdoca);
10109 assert!(!config.include_bseg);
10110 assert!(config.partition_by_period);
10111 assert!(!config.partition_by_company);
10112 }
10113
10114 #[test]
10115 fn test_approval_config_defaults() {
10116 let config = ApprovalConfig::default();
10117 assert!(!config.enabled);
10118 assert_eq!(config.auto_approve_threshold, 1000.0);
10119 assert_eq!(config.rejection_rate, 0.02);
10120 assert_eq!(config.revision_rate, 0.05);
10121 assert_eq!(config.average_approval_delay_hours, 4.0);
10122 assert_eq!(config.thresholds.len(), 4);
10123 }
10124
10125 #[test]
10126 fn test_p2p_flow_config_defaults() {
10127 let config = P2PFlowConfig::default();
10128 assert!(config.enabled);
10129 assert_eq!(config.three_way_match_rate, 0.95);
10130 assert_eq!(config.partial_delivery_rate, 0.15);
10131 assert_eq!(config.average_po_to_gr_days, 14);
10132 }
10133
10134 #[test]
10135 fn test_o2c_flow_config_defaults() {
10136 let config = O2CFlowConfig::default();
10137 assert!(config.enabled);
10138 assert_eq!(config.credit_check_failure_rate, 0.02);
10139 assert_eq!(config.return_rate, 0.03);
10140 assert_eq!(config.bad_debt_rate, 0.01);
10141 }
10142
10143 #[test]
10144 fn test_balance_config_defaults() {
10145 let config = BalanceConfig::default();
10146 assert!(!config.generate_opening_balances);
10147 assert!(config.generate_trial_balances);
10148 assert_eq!(config.target_gross_margin, 0.35);
10149 assert!(config.validate_balance_equation);
10150 assert!(config.reconcile_subledgers);
10151 }
10152
10153 #[test]
10158 fn test_partial_config_with_defaults() {
10159 let yaml = r#"
10161 global:
10162 industry: manufacturing
10163 start_date: "2024-01-01"
10164 period_months: 3
10165 companies:
10166 - code: "TEST"
10167 name: "Test Company"
10168 currency: "USD"
10169 country: "US"
10170 annual_transaction_volume: ten_k
10171 chart_of_accounts:
10172 complexity: small
10173 output:
10174 output_directory: "./output"
10175 "#;
10176
10177 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10178 assert_eq!(config.global.period_months, 3);
10179 assert_eq!(config.companies.len(), 1);
10180 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
10183
10184 #[test]
10185 fn test_config_with_fraud_enabled() {
10186 let yaml = r#"
10187 global:
10188 industry: retail
10189 start_date: "2024-01-01"
10190 period_months: 12
10191 companies:
10192 - code: "RETAIL"
10193 name: "Retail Co"
10194 currency: "USD"
10195 country: "US"
10196 annual_transaction_volume: hundred_k
10197 chart_of_accounts:
10198 complexity: medium
10199 output:
10200 output_directory: "./output"
10201 fraud:
10202 enabled: true
10203 fraud_rate: 0.05
10204 clustering_enabled: true
10205 "#;
10206
10207 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10208 assert!(config.fraud.enabled);
10209 assert_eq!(config.fraud.fraud_rate, 0.05);
10210 assert!(config.fraud.clustering_enabled);
10211 }
10212
10213 #[test]
10214 fn test_config_with_multiple_companies() {
10215 let yaml = r#"
10216 global:
10217 industry: manufacturing
10218 start_date: "2024-01-01"
10219 period_months: 6
10220 companies:
10221 - code: "HQ"
10222 name: "Headquarters"
10223 currency: "USD"
10224 country: "US"
10225 annual_transaction_volume: hundred_k
10226 volume_weight: 1.0
10227 - code: "EU"
10228 name: "European Subsidiary"
10229 currency: "EUR"
10230 country: "DE"
10231 annual_transaction_volume: hundred_k
10232 volume_weight: 0.5
10233 - code: "APAC"
10234 name: "Asia Pacific"
10235 currency: "JPY"
10236 country: "JP"
10237 annual_transaction_volume: ten_k
10238 volume_weight: 0.3
10239 chart_of_accounts:
10240 complexity: large
10241 output:
10242 output_directory: "./output"
10243 "#;
10244
10245 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10246 assert_eq!(config.companies.len(), 3);
10247 assert_eq!(config.companies[0].code, "HQ");
10248 assert_eq!(config.companies[1].currency, "EUR");
10249 assert_eq!(config.companies[2].volume_weight, 0.3);
10250 }
10251
10252 #[test]
10253 fn test_intercompany_config() {
10254 let yaml = r#"
10255 enabled: true
10256 ic_transaction_rate: 0.20
10257 transfer_pricing_method: cost_plus
10258 markup_percent: 0.08
10259 generate_matched_pairs: true
10260 generate_eliminations: true
10261 "#;
10262
10263 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10264 assert!(config.enabled);
10265 assert_eq!(config.ic_transaction_rate, 0.20);
10266 assert!(matches!(
10267 config.transfer_pricing_method,
10268 TransferPricingMethod::CostPlus
10269 ));
10270 assert_eq!(config.markup_percent, 0.08);
10271 assert!(config.generate_eliminations);
10272 }
10273
10274 #[test]
10279 fn test_company_config_defaults() {
10280 let yaml = r#"
10281 code: "TEST"
10282 name: "Test Company"
10283 currency: "USD"
10284 country: "US"
10285 annual_transaction_volume: ten_k
10286 "#;
10287
10288 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10289 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
10292
10293 #[test]
10298 fn test_coa_config_defaults() {
10299 let yaml = r#"
10300 complexity: medium
10301 "#;
10302
10303 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10304 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
10306 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
10309
10310 #[test]
10315 fn test_accounting_standards_config_defaults() {
10316 let config = AccountingStandardsConfig::default();
10317 assert!(!config.enabled);
10318 assert!(matches!(
10319 config.framework,
10320 AccountingFrameworkConfig::UsGaap
10321 ));
10322 assert!(!config.revenue_recognition.enabled);
10323 assert!(!config.leases.enabled);
10324 assert!(!config.fair_value.enabled);
10325 assert!(!config.impairment.enabled);
10326 assert!(!config.generate_differences);
10327 }
10328
10329 #[test]
10330 fn test_accounting_standards_config_yaml() {
10331 let yaml = r#"
10332 enabled: true
10333 framework: ifrs
10334 revenue_recognition:
10335 enabled: true
10336 generate_contracts: true
10337 avg_obligations_per_contract: 2.5
10338 variable_consideration_rate: 0.20
10339 over_time_recognition_rate: 0.35
10340 contract_count: 150
10341 leases:
10342 enabled: true
10343 lease_count: 75
10344 finance_lease_percent: 0.25
10345 avg_lease_term_months: 48
10346 generate_differences: true
10347 "#;
10348
10349 let config: AccountingStandardsConfig =
10350 serde_yaml::from_str(yaml).expect("Failed to parse");
10351 assert!(config.enabled);
10352 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
10353 assert!(config.revenue_recognition.enabled);
10354 assert_eq!(config.revenue_recognition.contract_count, 150);
10355 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
10356 assert!(config.leases.enabled);
10357 assert_eq!(config.leases.lease_count, 75);
10358 assert_eq!(config.leases.finance_lease_percent, 0.25);
10359 assert!(config.generate_differences);
10360 }
10361
10362 #[test]
10363 fn test_accounting_framework_serialization() {
10364 let frameworks = [
10365 AccountingFrameworkConfig::UsGaap,
10366 AccountingFrameworkConfig::Ifrs,
10367 AccountingFrameworkConfig::DualReporting,
10368 ];
10369
10370 for framework in frameworks {
10371 let json = serde_json::to_string(&framework).expect("Failed to serialize");
10372 let deserialized: AccountingFrameworkConfig =
10373 serde_json::from_str(&json).expect("Failed to deserialize");
10374 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
10375 }
10376 }
10377
10378 #[test]
10379 fn test_revenue_recognition_config_defaults() {
10380 let config = RevenueRecognitionConfig::default();
10381 assert!(!config.enabled);
10382 assert!(config.generate_contracts);
10383 assert_eq!(config.avg_obligations_per_contract, 2.0);
10384 assert_eq!(config.variable_consideration_rate, 0.15);
10385 assert_eq!(config.over_time_recognition_rate, 0.30);
10386 assert_eq!(config.contract_count, 100);
10387 }
10388
10389 #[test]
10390 fn test_lease_accounting_config_defaults() {
10391 let config = LeaseAccountingConfig::default();
10392 assert!(!config.enabled);
10393 assert_eq!(config.lease_count, 50);
10394 assert_eq!(config.finance_lease_percent, 0.30);
10395 assert_eq!(config.avg_lease_term_months, 60);
10396 assert!(config.generate_amortization);
10397 assert_eq!(config.real_estate_percent, 0.40);
10398 }
10399
10400 #[test]
10401 fn test_fair_value_config_defaults() {
10402 let config = FairValueConfig::default();
10403 assert!(!config.enabled);
10404 assert_eq!(config.measurement_count, 25);
10405 assert_eq!(config.level1_percent, 0.40);
10406 assert_eq!(config.level2_percent, 0.35);
10407 assert_eq!(config.level3_percent, 0.25);
10408 assert!(!config.include_sensitivity_analysis);
10409 }
10410
10411 #[test]
10412 fn test_impairment_config_defaults() {
10413 let config = ImpairmentConfig::default();
10414 assert!(!config.enabled);
10415 assert_eq!(config.test_count, 15);
10416 assert_eq!(config.impairment_rate, 0.10);
10417 assert!(config.generate_projections);
10418 assert!(!config.include_goodwill);
10419 }
10420
10421 #[test]
10426 fn test_audit_standards_config_defaults() {
10427 let config = AuditStandardsConfig::default();
10428 assert!(!config.enabled);
10429 assert!(!config.isa_compliance.enabled);
10430 assert!(!config.analytical_procedures.enabled);
10431 assert!(!config.confirmations.enabled);
10432 assert!(!config.opinion.enabled);
10433 assert!(!config.generate_audit_trail);
10434 assert!(!config.sox.enabled);
10435 assert!(!config.pcaob.enabled);
10436 }
10437
10438 #[test]
10439 fn test_audit_standards_config_yaml() {
10440 let yaml = r#"
10441 enabled: true
10442 isa_compliance:
10443 enabled: true
10444 compliance_level: comprehensive
10445 generate_isa_mappings: true
10446 include_pcaob: true
10447 framework: dual
10448 analytical_procedures:
10449 enabled: true
10450 procedures_per_account: 5
10451 variance_probability: 0.25
10452 confirmations:
10453 enabled: true
10454 confirmation_count: 75
10455 positive_response_rate: 0.90
10456 exception_rate: 0.08
10457 opinion:
10458 enabled: true
10459 generate_kam: true
10460 average_kam_count: 4
10461 sox:
10462 enabled: true
10463 generate_302_certifications: true
10464 generate_404_assessments: true
10465 material_weakness_rate: 0.03
10466 pcaob:
10467 enabled: true
10468 is_pcaob_audit: true
10469 include_icfr_opinion: true
10470 generate_audit_trail: true
10471 "#;
10472
10473 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10474 assert!(config.enabled);
10475 assert!(config.isa_compliance.enabled);
10476 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
10477 assert!(config.isa_compliance.include_pcaob);
10478 assert_eq!(config.isa_compliance.framework, "dual");
10479 assert!(config.analytical_procedures.enabled);
10480 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
10481 assert!(config.confirmations.enabled);
10482 assert_eq!(config.confirmations.confirmation_count, 75);
10483 assert!(config.opinion.enabled);
10484 assert_eq!(config.opinion.average_kam_count, 4);
10485 assert!(config.sox.enabled);
10486 assert!(config.sox.generate_302_certifications);
10487 assert_eq!(config.sox.material_weakness_rate, 0.03);
10488 assert!(config.pcaob.enabled);
10489 assert!(config.pcaob.is_pcaob_audit);
10490 assert!(config.pcaob.include_icfr_opinion);
10491 assert!(config.generate_audit_trail);
10492 }
10493
10494 #[test]
10495 fn test_isa_compliance_config_defaults() {
10496 let config = IsaComplianceConfig::default();
10497 assert!(!config.enabled);
10498 assert_eq!(config.compliance_level, "standard");
10499 assert!(config.generate_isa_mappings);
10500 assert!(config.generate_coverage_summary);
10501 assert!(!config.include_pcaob);
10502 assert_eq!(config.framework, "isa");
10503 }
10504
10505 #[test]
10506 fn test_sox_compliance_config_defaults() {
10507 let config = SoxComplianceConfig::default();
10508 assert!(!config.enabled);
10509 assert!(config.generate_302_certifications);
10510 assert!(config.generate_404_assessments);
10511 assert_eq!(config.materiality_threshold, 10000.0);
10512 assert_eq!(config.material_weakness_rate, 0.02);
10513 assert_eq!(config.significant_deficiency_rate, 0.08);
10514 }
10515
10516 #[test]
10517 fn test_pcaob_config_defaults() {
10518 let config = PcaobConfig::default();
10519 assert!(!config.enabled);
10520 assert!(!config.is_pcaob_audit);
10521 assert!(config.generate_cam);
10522 assert!(!config.include_icfr_opinion);
10523 assert!(!config.generate_standard_mappings);
10524 }
10525
10526 #[test]
10527 fn test_config_with_standards_enabled() {
10528 let yaml = r#"
10529 global:
10530 industry: financial_services
10531 start_date: "2024-01-01"
10532 period_months: 12
10533 companies:
10534 - code: "BANK"
10535 name: "Test Bank"
10536 currency: "USD"
10537 country: "US"
10538 annual_transaction_volume: hundred_k
10539 chart_of_accounts:
10540 complexity: large
10541 output:
10542 output_directory: "./output"
10543 accounting_standards:
10544 enabled: true
10545 framework: us_gaap
10546 revenue_recognition:
10547 enabled: true
10548 leases:
10549 enabled: true
10550 audit_standards:
10551 enabled: true
10552 isa_compliance:
10553 enabled: true
10554 sox:
10555 enabled: true
10556 "#;
10557
10558 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10559 assert!(config.accounting_standards.enabled);
10560 assert!(matches!(
10561 config.accounting_standards.framework,
10562 AccountingFrameworkConfig::UsGaap
10563 ));
10564 assert!(config.accounting_standards.revenue_recognition.enabled);
10565 assert!(config.accounting_standards.leases.enabled);
10566 assert!(config.audit_standards.enabled);
10567 assert!(config.audit_standards.isa_compliance.enabled);
10568 assert!(config.audit_standards.sox.enabled);
10569 }
10570
10571 #[test]
10576 fn test_industry_specific_config_defaults() {
10577 let config = IndustrySpecificConfig::default();
10578 assert!(!config.enabled);
10579 assert!(!config.manufacturing.enabled);
10580 assert!(!config.retail.enabled);
10581 assert!(!config.healthcare.enabled);
10582 assert!(!config.technology.enabled);
10583 assert!(!config.financial_services.enabled);
10584 assert!(!config.professional_services.enabled);
10585 }
10586
10587 #[test]
10588 fn test_manufacturing_config_defaults() {
10589 let config = ManufacturingConfig::default();
10590 assert!(!config.enabled);
10591 assert_eq!(config.bom_depth, 4);
10592 assert!(!config.just_in_time);
10593 assert_eq!(config.supplier_tiers, 2);
10594 assert_eq!(config.target_yield_rate, 0.97);
10595 assert_eq!(config.scrap_alert_threshold, 0.03);
10596 }
10597
10598 #[test]
10599 fn test_retail_config_defaults() {
10600 let config = RetailConfig::default();
10601 assert!(!config.enabled);
10602 assert_eq!(config.avg_daily_transactions, 500);
10603 assert!(config.loss_prevention);
10604 assert_eq!(config.shrinkage_rate, 0.015);
10605 }
10606
10607 #[test]
10608 fn test_healthcare_config_defaults() {
10609 let config = HealthcareConfig::default();
10610 assert!(!config.enabled);
10611 assert_eq!(config.facility_type, "hospital");
10612 assert_eq!(config.avg_daily_encounters, 150);
10613 assert!(config.compliance.hipaa);
10614 assert!(config.compliance.stark_law);
10615 assert!(config.coding_systems.icd10);
10616 assert!(config.coding_systems.cpt);
10617 }
10618
10619 #[test]
10620 fn test_technology_config_defaults() {
10621 let config = TechnologyConfig::default();
10622 assert!(!config.enabled);
10623 assert_eq!(config.revenue_model, "saas");
10624 assert_eq!(config.subscription_revenue_pct, 0.60);
10625 assert!(config.rd_capitalization.enabled);
10626 }
10627
10628 #[test]
10629 fn test_config_with_industry_specific() {
10630 let yaml = r#"
10631 global:
10632 industry: healthcare
10633 start_date: "2024-01-01"
10634 period_months: 12
10635 companies:
10636 - code: "HOSP"
10637 name: "Test Hospital"
10638 currency: "USD"
10639 country: "US"
10640 annual_transaction_volume: hundred_k
10641 chart_of_accounts:
10642 complexity: medium
10643 output:
10644 output_directory: "./output"
10645 industry_specific:
10646 enabled: true
10647 healthcare:
10648 enabled: true
10649 facility_type: hospital
10650 payer_mix:
10651 medicare: 0.45
10652 medicaid: 0.15
10653 commercial: 0.35
10654 self_pay: 0.05
10655 coding_systems:
10656 icd10: true
10657 cpt: true
10658 drg: true
10659 compliance:
10660 hipaa: true
10661 stark_law: true
10662 anomaly_rates:
10663 upcoding: 0.03
10664 unbundling: 0.02
10665 "#;
10666
10667 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10668 assert!(config.industry_specific.enabled);
10669 assert!(config.industry_specific.healthcare.enabled);
10670 assert_eq!(
10671 config.industry_specific.healthcare.facility_type,
10672 "hospital"
10673 );
10674 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10675 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10676 assert!(config.industry_specific.healthcare.coding_systems.icd10);
10677 assert!(config.industry_specific.healthcare.compliance.hipaa);
10678 assert_eq!(
10679 config.industry_specific.healthcare.anomaly_rates.upcoding,
10680 0.03
10681 );
10682 }
10683
10684 #[test]
10685 fn test_config_with_manufacturing_specific() {
10686 let yaml = r#"
10687 global:
10688 industry: manufacturing
10689 start_date: "2024-01-01"
10690 period_months: 12
10691 companies:
10692 - code: "MFG"
10693 name: "Test Manufacturing"
10694 currency: "USD"
10695 country: "US"
10696 annual_transaction_volume: hundred_k
10697 chart_of_accounts:
10698 complexity: medium
10699 output:
10700 output_directory: "./output"
10701 industry_specific:
10702 enabled: true
10703 manufacturing:
10704 enabled: true
10705 bom_depth: 5
10706 just_in_time: true
10707 supplier_tiers: 3
10708 target_yield_rate: 0.98
10709 anomaly_rates:
10710 yield_manipulation: 0.02
10711 phantom_production: 0.01
10712 "#;
10713
10714 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10715 assert!(config.industry_specific.enabled);
10716 assert!(config.industry_specific.manufacturing.enabled);
10717 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10718 assert!(config.industry_specific.manufacturing.just_in_time);
10719 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10720 assert_eq!(
10721 config.industry_specific.manufacturing.target_yield_rate,
10722 0.98
10723 );
10724 assert_eq!(
10725 config
10726 .industry_specific
10727 .manufacturing
10728 .anomaly_rates
10729 .yield_manipulation,
10730 0.02
10731 );
10732 }
10733}