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 #[serde(default)]
158 pub source_to_pay: SourceToPayConfig,
159 #[serde(default)]
161 pub financial_reporting: FinancialReportingConfig,
162 #[serde(default)]
164 pub hr: HrConfig,
165 #[serde(default)]
167 pub manufacturing: ManufacturingProcessConfig,
168 #[serde(default)]
170 pub sales_quotes: SalesQuoteConfig,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
179pub struct LlmSchemaConfig {
180 #[serde(default)]
182 pub enabled: bool,
183 #[serde(default = "default_llm_provider")]
185 pub provider: String,
186 #[serde(default = "default_llm_model_name")]
188 pub model: String,
189 #[serde(default = "default_llm_batch_size")]
191 pub max_vendor_enrichments: usize,
192}
193
194fn default_llm_provider() -> String {
195 "mock".to_string()
196}
197
198fn default_llm_model_name() -> String {
199 "gpt-4o-mini".to_string()
200}
201
202fn default_llm_batch_size() -> usize {
203 50
204}
205
206impl Default for LlmSchemaConfig {
207 fn default() -> Self {
208 Self {
209 enabled: false,
210 provider: default_llm_provider(),
211 model: default_llm_model_name(),
212 max_vendor_enrichments: default_llm_batch_size(),
213 }
214 }
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize)]
222pub struct DiffusionSchemaConfig {
223 #[serde(default)]
225 pub enabled: bool,
226 #[serde(default = "default_diffusion_steps")]
228 pub n_steps: usize,
229 #[serde(default = "default_diffusion_schedule")]
231 pub schedule: String,
232 #[serde(default = "default_diffusion_sample_size")]
234 pub sample_size: usize,
235}
236
237fn default_diffusion_steps() -> usize {
238 100
239}
240
241fn default_diffusion_schedule() -> String {
242 "linear".to_string()
243}
244
245fn default_diffusion_sample_size() -> usize {
246 100
247}
248
249impl Default for DiffusionSchemaConfig {
250 fn default() -> Self {
251 Self {
252 enabled: false,
253 n_steps: default_diffusion_steps(),
254 schedule: default_diffusion_schedule(),
255 sample_size: default_diffusion_sample_size(),
256 }
257 }
258}
259
260#[derive(Debug, Clone, Serialize, Deserialize)]
266pub struct CausalSchemaConfig {
267 #[serde(default)]
269 pub enabled: bool,
270 #[serde(default = "default_causal_template")]
272 pub template: String,
273 #[serde(default = "default_causal_sample_size")]
275 pub sample_size: usize,
276 #[serde(default = "default_true")]
278 pub validate: bool,
279}
280
281fn default_causal_template() -> String {
282 "fraud_detection".to_string()
283}
284
285fn default_causal_sample_size() -> usize {
286 500
287}
288
289impl Default for CausalSchemaConfig {
290 fn default() -> Self {
291 Self {
292 enabled: false,
293 template: default_causal_template(),
294 sample_size: default_causal_sample_size(),
295 validate: true,
296 }
297 }
298}
299
300#[derive(Debug, Clone, Serialize, Deserialize)]
307pub struct GraphExportConfig {
308 #[serde(default)]
310 pub enabled: bool,
311
312 #[serde(default = "default_graph_types")]
314 pub graph_types: Vec<GraphTypeConfig>,
315
316 #[serde(default = "default_graph_formats")]
318 pub formats: Vec<GraphExportFormat>,
319
320 #[serde(default = "default_train_ratio")]
322 pub train_ratio: f64,
323
324 #[serde(default = "default_val_ratio")]
326 pub validation_ratio: f64,
327
328 #[serde(default)]
330 pub split_seed: Option<u64>,
331
332 #[serde(default = "default_graph_subdir")]
334 pub output_subdirectory: String,
335
336 #[serde(default)]
338 pub hypergraph: HypergraphExportSettings,
339}
340
341fn default_graph_types() -> Vec<GraphTypeConfig> {
342 vec![GraphTypeConfig::default()]
343}
344
345fn default_graph_formats() -> Vec<GraphExportFormat> {
346 vec![GraphExportFormat::PytorchGeometric]
347}
348
349fn default_train_ratio() -> f64 {
350 0.7
351}
352
353fn default_val_ratio() -> f64 {
354 0.15
355}
356
357fn default_graph_subdir() -> String {
358 "graphs".to_string()
359}
360
361impl Default for GraphExportConfig {
362 fn default() -> Self {
363 Self {
364 enabled: false,
365 graph_types: default_graph_types(),
366 formats: default_graph_formats(),
367 train_ratio: 0.7,
368 validation_ratio: 0.15,
369 split_seed: None,
370 output_subdirectory: "graphs".to_string(),
371 hypergraph: HypergraphExportSettings::default(),
372 }
373 }
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct HypergraphExportSettings {
384 #[serde(default)]
386 pub enabled: bool,
387
388 #[serde(default = "default_hypergraph_max_nodes")]
390 pub max_nodes: usize,
391
392 #[serde(default = "default_aggregation_strategy")]
394 pub aggregation_strategy: String,
395
396 #[serde(default)]
398 pub governance_layer: GovernanceLayerSettings,
399
400 #[serde(default)]
402 pub process_layer: ProcessLayerSettings,
403
404 #[serde(default)]
406 pub accounting_layer: AccountingLayerSettings,
407
408 #[serde(default)]
410 pub cross_layer: CrossLayerSettings,
411
412 #[serde(default = "default_hypergraph_subdir")]
414 pub output_subdirectory: String,
415
416 #[serde(default = "default_hypergraph_format")]
418 pub output_format: String,
419
420 #[serde(default)]
422 pub stream_target: Option<String>,
423
424 #[serde(default = "default_stream_batch_size")]
426 pub stream_batch_size: usize,
427}
428
429fn default_hypergraph_max_nodes() -> usize {
430 50_000
431}
432
433fn default_aggregation_strategy() -> String {
434 "pool_by_counterparty".to_string()
435}
436
437fn default_hypergraph_subdir() -> String {
438 "hypergraph".to_string()
439}
440
441fn default_hypergraph_format() -> String {
442 "native".to_string()
443}
444
445fn default_stream_batch_size() -> usize {
446 1000
447}
448
449impl Default for HypergraphExportSettings {
450 fn default() -> Self {
451 Self {
452 enabled: false,
453 max_nodes: 50_000,
454 aggregation_strategy: "pool_by_counterparty".to_string(),
455 governance_layer: GovernanceLayerSettings::default(),
456 process_layer: ProcessLayerSettings::default(),
457 accounting_layer: AccountingLayerSettings::default(),
458 cross_layer: CrossLayerSettings::default(),
459 output_subdirectory: "hypergraph".to_string(),
460 output_format: "native".to_string(),
461 stream_target: None,
462 stream_batch_size: 1000,
463 }
464 }
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
469pub struct GovernanceLayerSettings {
470 #[serde(default = "default_true")]
472 pub include_coso: bool,
473 #[serde(default = "default_true")]
475 pub include_controls: bool,
476 #[serde(default = "default_true")]
478 pub include_sox: bool,
479 #[serde(default = "default_true")]
481 pub include_vendors: bool,
482 #[serde(default = "default_true")]
484 pub include_customers: bool,
485 #[serde(default = "default_true")]
487 pub include_employees: bool,
488}
489
490impl Default for GovernanceLayerSettings {
491 fn default() -> Self {
492 Self {
493 include_coso: true,
494 include_controls: true,
495 include_sox: true,
496 include_vendors: true,
497 include_customers: true,
498 include_employees: true,
499 }
500 }
501}
502
503#[derive(Debug, Clone, Serialize, Deserialize)]
505pub struct ProcessLayerSettings {
506 #[serde(default = "default_true")]
508 pub include_p2p: bool,
509 #[serde(default = "default_true")]
511 pub include_o2c: bool,
512 #[serde(default = "default_true")]
514 pub events_as_hyperedges: bool,
515 #[serde(default = "default_docs_per_counterparty_threshold")]
517 pub docs_per_counterparty_threshold: usize,
518}
519
520fn default_docs_per_counterparty_threshold() -> usize {
521 20
522}
523
524impl Default for ProcessLayerSettings {
525 fn default() -> Self {
526 Self {
527 include_p2p: true,
528 include_o2c: true,
529 events_as_hyperedges: true,
530 docs_per_counterparty_threshold: 20,
531 }
532 }
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
537pub struct AccountingLayerSettings {
538 #[serde(default = "default_true")]
540 pub include_accounts: bool,
541 #[serde(default = "default_true")]
543 pub je_as_hyperedges: bool,
544}
545
546impl Default for AccountingLayerSettings {
547 fn default() -> Self {
548 Self {
549 include_accounts: true,
550 je_as_hyperedges: true,
551 }
552 }
553}
554
555#[derive(Debug, Clone, Serialize, Deserialize)]
557pub struct CrossLayerSettings {
558 #[serde(default = "default_true")]
560 pub enabled: bool,
561}
562
563impl Default for CrossLayerSettings {
564 fn default() -> Self {
565 Self { enabled: true }
566 }
567}
568
569#[derive(Debug, Clone, Serialize, Deserialize)]
571pub struct GraphTypeConfig {
572 #[serde(default = "default_graph_name")]
574 pub name: String,
575
576 #[serde(default)]
578 pub aggregate_edges: bool,
579
580 #[serde(default)]
582 pub min_edge_weight: f64,
583
584 #[serde(default)]
586 pub include_document_nodes: bool,
587}
588
589fn default_graph_name() -> String {
590 "accounting_network".to_string()
591}
592
593impl Default for GraphTypeConfig {
594 fn default() -> Self {
595 Self {
596 name: "accounting_network".to_string(),
597 aggregate_edges: false,
598 min_edge_weight: 0.0,
599 include_document_nodes: false,
600 }
601 }
602}
603
604#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
606#[serde(rename_all = "snake_case")]
607pub enum GraphExportFormat {
608 PytorchGeometric,
610 Neo4j,
612 Dgl,
614 RustGraph,
616 RustGraphHypergraph,
618}
619
620#[derive(Debug, Clone, Default, Serialize, Deserialize)]
624pub struct ScenarioConfig {
625 #[serde(default)]
628 pub tags: Vec<String>,
629
630 #[serde(default)]
635 pub profile: Option<String>,
636
637 #[serde(default)]
639 pub description: Option<String>,
640
641 #[serde(default)]
643 pub ml_training: bool,
644
645 #[serde(default)]
648 pub target_anomaly_ratio: Option<f64>,
649
650 #[serde(default)]
652 pub metadata: std::collections::HashMap<String, String>,
653}
654
655#[derive(Debug, Clone, Serialize, Deserialize)]
660pub struct TemporalDriftConfig {
661 #[serde(default)]
663 pub enabled: bool,
664
665 #[serde(default = "default_amount_drift")]
668 pub amount_mean_drift: f64,
669
670 #[serde(default)]
673 pub amount_variance_drift: f64,
674
675 #[serde(default)]
678 pub anomaly_rate_drift: f64,
679
680 #[serde(default = "default_concept_drift")]
683 pub concept_drift_rate: f64,
684
685 #[serde(default)]
687 pub sudden_drift_probability: f64,
688
689 #[serde(default = "default_sudden_drift_magnitude")]
691 pub sudden_drift_magnitude: f64,
692
693 #[serde(default)]
695 pub seasonal_drift: bool,
696
697 #[serde(default)]
699 pub drift_start_period: u32,
700
701 #[serde(default = "default_drift_type")]
703 pub drift_type: DriftType,
704}
705
706fn default_amount_drift() -> f64 {
707 0.02
708}
709
710fn default_concept_drift() -> f64 {
711 0.01
712}
713
714fn default_sudden_drift_magnitude() -> f64 {
715 2.0
716}
717
718fn default_drift_type() -> DriftType {
719 DriftType::Gradual
720}
721
722impl Default for TemporalDriftConfig {
723 fn default() -> Self {
724 Self {
725 enabled: false,
726 amount_mean_drift: 0.02,
727 amount_variance_drift: 0.0,
728 anomaly_rate_drift: 0.0,
729 concept_drift_rate: 0.01,
730 sudden_drift_probability: 0.0,
731 sudden_drift_magnitude: 2.0,
732 seasonal_drift: false,
733 drift_start_period: 0,
734 drift_type: DriftType::Gradual,
735 }
736 }
737}
738
739impl TemporalDriftConfig {
740 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
742 datasynth_core::distributions::DriftConfig {
743 enabled: self.enabled,
744 amount_mean_drift: self.amount_mean_drift,
745 amount_variance_drift: self.amount_variance_drift,
746 anomaly_rate_drift: self.anomaly_rate_drift,
747 concept_drift_rate: self.concept_drift_rate,
748 sudden_drift_probability: self.sudden_drift_probability,
749 sudden_drift_magnitude: self.sudden_drift_magnitude,
750 seasonal_drift: self.seasonal_drift,
751 drift_start_period: self.drift_start_period,
752 drift_type: match self.drift_type {
753 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
754 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
755 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
756 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
757 },
758 regime_changes: Vec::new(),
759 economic_cycle: Default::default(),
760 parameter_drifts: Vec::new(),
761 }
762 }
763}
764
765#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
767#[serde(rename_all = "snake_case")]
768pub enum DriftType {
769 #[default]
771 Gradual,
772 Sudden,
774 Recurring,
776 Mixed,
778}
779
780#[derive(Debug, Clone, Serialize, Deserialize)]
786pub struct StreamingSchemaConfig {
787 #[serde(default)]
789 pub enabled: bool,
790 #[serde(default = "default_buffer_size")]
792 pub buffer_size: usize,
793 #[serde(default = "default_true")]
795 pub enable_progress: bool,
796 #[serde(default = "default_progress_interval")]
798 pub progress_interval: u64,
799 #[serde(default)]
801 pub backpressure: BackpressureSchemaStrategy,
802}
803
804fn default_buffer_size() -> usize {
805 1000
806}
807
808fn default_progress_interval() -> u64 {
809 100
810}
811
812impl Default for StreamingSchemaConfig {
813 fn default() -> Self {
814 Self {
815 enabled: false,
816 buffer_size: 1000,
817 enable_progress: true,
818 progress_interval: 100,
819 backpressure: BackpressureSchemaStrategy::Block,
820 }
821 }
822}
823
824#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
826#[serde(rename_all = "snake_case")]
827pub enum BackpressureSchemaStrategy {
828 #[default]
830 Block,
831 DropOldest,
833 DropNewest,
835 Buffer,
837}
838
839#[derive(Debug, Clone, Serialize, Deserialize)]
845pub struct RateLimitSchemaConfig {
846 #[serde(default)]
848 pub enabled: bool,
849 #[serde(default = "default_entities_per_second")]
851 pub entities_per_second: f64,
852 #[serde(default = "default_burst_size")]
854 pub burst_size: u32,
855 #[serde(default)]
857 pub backpressure: RateLimitBackpressureSchema,
858}
859
860fn default_entities_per_second() -> f64 {
861 1000.0
862}
863
864fn default_burst_size() -> u32 {
865 100
866}
867
868impl Default for RateLimitSchemaConfig {
869 fn default() -> Self {
870 Self {
871 enabled: false,
872 entities_per_second: 1000.0,
873 burst_size: 100,
874 backpressure: RateLimitBackpressureSchema::Block,
875 }
876 }
877}
878
879#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
881#[serde(rename_all = "snake_case")]
882pub enum RateLimitBackpressureSchema {
883 #[default]
885 Block,
886 Drop,
888 Buffer,
890}
891
892#[derive(Debug, Clone, Serialize, Deserialize)]
898pub struct TemporalAttributeSchemaConfig {
899 #[serde(default)]
901 pub enabled: bool,
902 #[serde(default)]
904 pub valid_time: ValidTimeSchemaConfig,
905 #[serde(default)]
907 pub transaction_time: TransactionTimeSchemaConfig,
908 #[serde(default)]
910 pub generate_version_chains: bool,
911 #[serde(default = "default_avg_versions")]
913 pub avg_versions_per_entity: f64,
914}
915
916fn default_avg_versions() -> f64 {
917 1.5
918}
919
920impl Default for TemporalAttributeSchemaConfig {
921 fn default() -> Self {
922 Self {
923 enabled: false,
924 valid_time: ValidTimeSchemaConfig::default(),
925 transaction_time: TransactionTimeSchemaConfig::default(),
926 generate_version_chains: false,
927 avg_versions_per_entity: 1.5,
928 }
929 }
930}
931
932#[derive(Debug, Clone, Serialize, Deserialize)]
934pub struct ValidTimeSchemaConfig {
935 #[serde(default = "default_closed_probability")]
937 pub closed_probability: f64,
938 #[serde(default = "default_avg_validity_days")]
940 pub avg_validity_days: u32,
941 #[serde(default = "default_validity_stddev")]
943 pub validity_stddev_days: u32,
944}
945
946fn default_closed_probability() -> f64 {
947 0.1
948}
949
950fn default_avg_validity_days() -> u32 {
951 365
952}
953
954fn default_validity_stddev() -> u32 {
955 90
956}
957
958impl Default for ValidTimeSchemaConfig {
959 fn default() -> Self {
960 Self {
961 closed_probability: 0.1,
962 avg_validity_days: 365,
963 validity_stddev_days: 90,
964 }
965 }
966}
967
968#[derive(Debug, Clone, Serialize, Deserialize)]
970pub struct TransactionTimeSchemaConfig {
971 #[serde(default)]
973 pub avg_recording_delay_seconds: u32,
974 #[serde(default)]
976 pub allow_backdating: bool,
977 #[serde(default = "default_backdating_probability")]
979 pub backdating_probability: f64,
980 #[serde(default = "default_max_backdate_days")]
982 pub max_backdate_days: u32,
983}
984
985fn default_backdating_probability() -> f64 {
986 0.01
987}
988
989fn default_max_backdate_days() -> u32 {
990 30
991}
992
993impl Default for TransactionTimeSchemaConfig {
994 fn default() -> Self {
995 Self {
996 avg_recording_delay_seconds: 0,
997 allow_backdating: false,
998 backdating_probability: 0.01,
999 max_backdate_days: 30,
1000 }
1001 }
1002}
1003
1004#[derive(Debug, Clone, Serialize, Deserialize)]
1010pub struct RelationshipSchemaConfig {
1011 #[serde(default)]
1013 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
1014 #[serde(default = "default_true")]
1016 pub allow_orphans: bool,
1017 #[serde(default = "default_orphan_probability")]
1019 pub orphan_probability: f64,
1020 #[serde(default)]
1022 pub allow_circular: bool,
1023 #[serde(default = "default_max_circular_depth")]
1025 pub max_circular_depth: u32,
1026}
1027
1028fn default_orphan_probability() -> f64 {
1029 0.01
1030}
1031
1032fn default_max_circular_depth() -> u32 {
1033 3
1034}
1035
1036impl Default for RelationshipSchemaConfig {
1037 fn default() -> Self {
1038 Self {
1039 relationship_types: Vec::new(),
1040 allow_orphans: true,
1041 orphan_probability: 0.01,
1042 allow_circular: false,
1043 max_circular_depth: 3,
1044 }
1045 }
1046}
1047
1048#[derive(Debug, Clone, Serialize, Deserialize)]
1050pub struct RelationshipTypeSchemaConfig {
1051 pub name: String,
1053 pub source_type: String,
1055 pub target_type: String,
1057 #[serde(default)]
1059 pub cardinality: CardinalitySchemaRule,
1060 #[serde(default = "default_relationship_weight")]
1062 pub weight: f64,
1063 #[serde(default)]
1065 pub required: bool,
1066 #[serde(default = "default_true")]
1068 pub directed: bool,
1069}
1070
1071fn default_relationship_weight() -> f64 {
1072 1.0
1073}
1074
1075impl Default for RelationshipTypeSchemaConfig {
1076 fn default() -> Self {
1077 Self {
1078 name: String::new(),
1079 source_type: String::new(),
1080 target_type: String::new(),
1081 cardinality: CardinalitySchemaRule::default(),
1082 weight: 1.0,
1083 required: false,
1084 directed: true,
1085 }
1086 }
1087}
1088
1089#[derive(Debug, Clone, Serialize, Deserialize)]
1091#[serde(rename_all = "snake_case")]
1092pub enum CardinalitySchemaRule {
1093 OneToOne,
1095 OneToMany {
1097 min: u32,
1099 max: u32,
1101 },
1102 ManyToOne {
1104 min: u32,
1106 max: u32,
1108 },
1109 ManyToMany {
1111 min_per_source: u32,
1113 max_per_source: u32,
1115 },
1116}
1117
1118impl Default for CardinalitySchemaRule {
1119 fn default() -> Self {
1120 Self::OneToMany { min: 1, max: 5 }
1121 }
1122}
1123
1124#[derive(Debug, Clone, Serialize, Deserialize)]
1126pub struct GlobalConfig {
1127 pub seed: Option<u64>,
1129 pub industry: IndustrySector,
1131 pub start_date: String,
1133 pub period_months: u32,
1135 #[serde(default = "default_currency")]
1137 pub group_currency: String,
1138 #[serde(default = "default_true")]
1140 pub parallel: bool,
1141 #[serde(default)]
1143 pub worker_threads: usize,
1144 #[serde(default)]
1146 pub memory_limit_mb: usize,
1147}
1148
1149fn default_currency() -> String {
1150 "USD".to_string()
1151}
1152fn default_true() -> bool {
1153 true
1154}
1155
1156#[derive(Debug, Clone, Serialize, Deserialize)]
1158pub struct CompanyConfig {
1159 pub code: String,
1161 pub name: String,
1163 pub currency: String,
1165 pub country: String,
1167 #[serde(default = "default_fiscal_variant")]
1169 pub fiscal_year_variant: String,
1170 pub annual_transaction_volume: TransactionVolume,
1172 #[serde(default = "default_weight")]
1174 pub volume_weight: f64,
1175}
1176
1177fn default_fiscal_variant() -> String {
1178 "K4".to_string()
1179}
1180fn default_weight() -> f64 {
1181 1.0
1182}
1183
1184#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1186#[serde(rename_all = "snake_case")]
1187pub enum TransactionVolume {
1188 TenK,
1190 HundredK,
1192 OneM,
1194 TenM,
1196 HundredM,
1198 Custom(u64),
1200}
1201
1202impl TransactionVolume {
1203 pub fn count(&self) -> u64 {
1205 match self {
1206 Self::TenK => 10_000,
1207 Self::HundredK => 100_000,
1208 Self::OneM => 1_000_000,
1209 Self::TenM => 10_000_000,
1210 Self::HundredM => 100_000_000,
1211 Self::Custom(n) => *n,
1212 }
1213 }
1214}
1215
1216#[derive(Debug, Clone, Serialize, Deserialize)]
1218pub struct ChartOfAccountsConfig {
1219 pub complexity: CoAComplexity,
1221 #[serde(default = "default_true")]
1223 pub industry_specific: bool,
1224 pub custom_accounts: Option<PathBuf>,
1226 #[serde(default = "default_min_depth")]
1228 pub min_hierarchy_depth: u8,
1229 #[serde(default = "default_max_depth")]
1231 pub max_hierarchy_depth: u8,
1232}
1233
1234fn default_min_depth() -> u8 {
1235 2
1236}
1237fn default_max_depth() -> u8 {
1238 5
1239}
1240
1241impl Default for ChartOfAccountsConfig {
1242 fn default() -> Self {
1243 Self {
1244 complexity: CoAComplexity::Small,
1245 industry_specific: true,
1246 custom_accounts: None,
1247 min_hierarchy_depth: default_min_depth(),
1248 max_hierarchy_depth: default_max_depth(),
1249 }
1250 }
1251}
1252
1253#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1255pub struct TransactionConfig {
1256 #[serde(default)]
1258 pub line_item_distribution: LineItemDistributionConfig,
1259 #[serde(default)]
1261 pub debit_credit_distribution: DebitCreditDistributionConfig,
1262 #[serde(default)]
1264 pub even_odd_distribution: EvenOddDistributionConfig,
1265 #[serde(default)]
1267 pub source_distribution: SourceDistribution,
1268 #[serde(default)]
1270 pub seasonality: SeasonalityConfig,
1271 #[serde(default)]
1273 pub amounts: AmountDistributionConfig,
1274 #[serde(default)]
1276 pub benford: BenfordConfig,
1277}
1278
1279#[derive(Debug, Clone, Serialize, Deserialize)]
1281pub struct BenfordConfig {
1282 #[serde(default = "default_true")]
1284 pub enabled: bool,
1285 #[serde(default = "default_benford_tolerance")]
1287 pub tolerance: f64,
1288 #[serde(default)]
1290 pub exempt_sources: Vec<BenfordExemption>,
1291}
1292
1293fn default_benford_tolerance() -> f64 {
1294 0.05
1295}
1296
1297impl Default for BenfordConfig {
1298 fn default() -> Self {
1299 Self {
1300 enabled: true,
1301 tolerance: default_benford_tolerance(),
1302 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1303 }
1304 }
1305}
1306
1307#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1309#[serde(rename_all = "snake_case")]
1310pub enum BenfordExemption {
1311 Recurring,
1313 Payroll,
1315 FixedFees,
1317 RoundAmounts,
1319}
1320
1321#[derive(Debug, Clone, Serialize, Deserialize)]
1323pub struct SourceDistribution {
1324 pub manual: f64,
1326 pub automated: f64,
1328 pub recurring: f64,
1330 pub adjustment: f64,
1332}
1333
1334impl Default for SourceDistribution {
1335 fn default() -> Self {
1336 Self {
1337 manual: 0.20,
1338 automated: 0.70,
1339 recurring: 0.07,
1340 adjustment: 0.03,
1341 }
1342 }
1343}
1344
1345#[derive(Debug, Clone, Serialize, Deserialize)]
1347pub struct OutputConfig {
1348 #[serde(default)]
1350 pub mode: OutputMode,
1351 pub output_directory: PathBuf,
1353 #[serde(default = "default_formats")]
1355 pub formats: Vec<FileFormat>,
1356 #[serde(default)]
1358 pub compression: CompressionConfig,
1359 #[serde(default = "default_batch_size")]
1361 pub batch_size: usize,
1362 #[serde(default = "default_true")]
1364 pub include_acdoca: bool,
1365 #[serde(default)]
1367 pub include_bseg: bool,
1368 #[serde(default = "default_true")]
1370 pub partition_by_period: bool,
1371 #[serde(default)]
1373 pub partition_by_company: bool,
1374}
1375
1376fn default_formats() -> Vec<FileFormat> {
1377 vec![FileFormat::Parquet]
1378}
1379fn default_batch_size() -> usize {
1380 100_000
1381}
1382
1383impl Default for OutputConfig {
1384 fn default() -> Self {
1385 Self {
1386 mode: OutputMode::FlatFile,
1387 output_directory: PathBuf::from("./output"),
1388 formats: default_formats(),
1389 compression: CompressionConfig::default(),
1390 batch_size: default_batch_size(),
1391 include_acdoca: true,
1392 include_bseg: false,
1393 partition_by_period: true,
1394 partition_by_company: false,
1395 }
1396 }
1397}
1398
1399#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1401#[serde(rename_all = "snake_case")]
1402pub enum OutputMode {
1403 Streaming,
1405 #[default]
1407 FlatFile,
1408 Both,
1410}
1411
1412#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1414#[serde(rename_all = "snake_case")]
1415pub enum FileFormat {
1416 Csv,
1417 Parquet,
1418 Json,
1419 JsonLines,
1420}
1421
1422#[derive(Debug, Clone, Serialize, Deserialize)]
1424pub struct CompressionConfig {
1425 #[serde(default = "default_true")]
1427 pub enabled: bool,
1428 #[serde(default)]
1430 pub algorithm: CompressionAlgorithm,
1431 #[serde(default = "default_compression_level")]
1433 pub level: u8,
1434}
1435
1436fn default_compression_level() -> u8 {
1437 3
1438}
1439
1440impl Default for CompressionConfig {
1441 fn default() -> Self {
1442 Self {
1443 enabled: true,
1444 algorithm: CompressionAlgorithm::default(),
1445 level: default_compression_level(),
1446 }
1447 }
1448}
1449
1450#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1452#[serde(rename_all = "snake_case")]
1453pub enum CompressionAlgorithm {
1454 Gzip,
1455 #[default]
1456 Zstd,
1457 Lz4,
1458 Snappy,
1459}
1460
1461#[derive(Debug, Clone, Serialize, Deserialize)]
1463pub struct FraudConfig {
1464 #[serde(default)]
1466 pub enabled: bool,
1467 #[serde(default = "default_fraud_rate")]
1469 pub fraud_rate: f64,
1470 #[serde(default)]
1472 pub fraud_type_distribution: FraudTypeDistribution,
1473 #[serde(default)]
1475 pub clustering_enabled: bool,
1476 #[serde(default = "default_clustering_factor")]
1478 pub clustering_factor: f64,
1479 #[serde(default = "default_approval_thresholds")]
1481 pub approval_thresholds: Vec<f64>,
1482}
1483
1484fn default_approval_thresholds() -> Vec<f64> {
1485 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1486}
1487
1488fn default_fraud_rate() -> f64 {
1489 0.005
1490}
1491fn default_clustering_factor() -> f64 {
1492 3.0
1493}
1494
1495impl Default for FraudConfig {
1496 fn default() -> Self {
1497 Self {
1498 enabled: false,
1499 fraud_rate: default_fraud_rate(),
1500 fraud_type_distribution: FraudTypeDistribution::default(),
1501 clustering_enabled: false,
1502 clustering_factor: default_clustering_factor(),
1503 approval_thresholds: default_approval_thresholds(),
1504 }
1505 }
1506}
1507
1508#[derive(Debug, Clone, Serialize, Deserialize)]
1510pub struct FraudTypeDistribution {
1511 pub suspense_account_abuse: f64,
1512 pub fictitious_transaction: f64,
1513 pub revenue_manipulation: f64,
1514 pub expense_capitalization: f64,
1515 pub split_transaction: f64,
1516 pub timing_anomaly: f64,
1517 pub unauthorized_access: f64,
1518 pub duplicate_payment: f64,
1519}
1520
1521impl Default for FraudTypeDistribution {
1522 fn default() -> Self {
1523 Self {
1524 suspense_account_abuse: 0.25,
1525 fictitious_transaction: 0.15,
1526 revenue_manipulation: 0.10,
1527 expense_capitalization: 0.10,
1528 split_transaction: 0.15,
1529 timing_anomaly: 0.10,
1530 unauthorized_access: 0.10,
1531 duplicate_payment: 0.05,
1532 }
1533 }
1534}
1535
1536#[derive(Debug, Clone, Serialize, Deserialize)]
1538pub struct InternalControlsConfig {
1539 #[serde(default)]
1541 pub enabled: bool,
1542 #[serde(default = "default_exception_rate")]
1544 pub exception_rate: f64,
1545 #[serde(default = "default_sod_violation_rate")]
1547 pub sod_violation_rate: f64,
1548 #[serde(default = "default_true")]
1550 pub export_control_master_data: bool,
1551 #[serde(default = "default_sox_materiality_threshold")]
1553 pub sox_materiality_threshold: f64,
1554 #[serde(default = "default_true")]
1556 pub coso_enabled: bool,
1557 #[serde(default)]
1559 pub include_entity_level_controls: bool,
1560 #[serde(default = "default_target_maturity_level")]
1563 pub target_maturity_level: String,
1564}
1565
1566fn default_exception_rate() -> f64 {
1567 0.02
1568}
1569
1570fn default_sod_violation_rate() -> f64 {
1571 0.01
1572}
1573
1574fn default_sox_materiality_threshold() -> f64 {
1575 10000.0
1576}
1577
1578fn default_target_maturity_level() -> String {
1579 "mixed".to_string()
1580}
1581
1582impl Default for InternalControlsConfig {
1583 fn default() -> Self {
1584 Self {
1585 enabled: false,
1586 exception_rate: default_exception_rate(),
1587 sod_violation_rate: default_sod_violation_rate(),
1588 export_control_master_data: true,
1589 sox_materiality_threshold: default_sox_materiality_threshold(),
1590 coso_enabled: true,
1591 include_entity_level_controls: false,
1592 target_maturity_level: default_target_maturity_level(),
1593 }
1594 }
1595}
1596
1597#[derive(Debug, Clone, Serialize, Deserialize)]
1599pub struct BusinessProcessConfig {
1600 #[serde(default = "default_o2c")]
1602 pub o2c_weight: f64,
1603 #[serde(default = "default_p2p")]
1605 pub p2p_weight: f64,
1606 #[serde(default = "default_r2r")]
1608 pub r2r_weight: f64,
1609 #[serde(default = "default_h2r")]
1611 pub h2r_weight: f64,
1612 #[serde(default = "default_a2r")]
1614 pub a2r_weight: f64,
1615}
1616
1617fn default_o2c() -> f64 {
1618 0.35
1619}
1620fn default_p2p() -> f64 {
1621 0.30
1622}
1623fn default_r2r() -> f64 {
1624 0.20
1625}
1626fn default_h2r() -> f64 {
1627 0.10
1628}
1629fn default_a2r() -> f64 {
1630 0.05
1631}
1632
1633impl Default for BusinessProcessConfig {
1634 fn default() -> Self {
1635 Self {
1636 o2c_weight: default_o2c(),
1637 p2p_weight: default_p2p(),
1638 r2r_weight: default_r2r(),
1639 h2r_weight: default_h2r(),
1640 a2r_weight: default_a2r(),
1641 }
1642 }
1643}
1644
1645#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1647pub struct UserPersonaConfig {
1648 #[serde(default)]
1650 pub persona_distribution: PersonaDistribution,
1651 #[serde(default)]
1653 pub users_per_persona: UsersPerPersona,
1654}
1655
1656#[derive(Debug, Clone, Serialize, Deserialize)]
1658pub struct PersonaDistribution {
1659 pub junior_accountant: f64,
1660 pub senior_accountant: f64,
1661 pub controller: f64,
1662 pub manager: f64,
1663 pub automated_system: f64,
1664}
1665
1666impl Default for PersonaDistribution {
1667 fn default() -> Self {
1668 Self {
1669 junior_accountant: 0.15,
1670 senior_accountant: 0.15,
1671 controller: 0.05,
1672 manager: 0.05,
1673 automated_system: 0.60,
1674 }
1675 }
1676}
1677
1678#[derive(Debug, Clone, Serialize, Deserialize)]
1680pub struct UsersPerPersona {
1681 pub junior_accountant: usize,
1682 pub senior_accountant: usize,
1683 pub controller: usize,
1684 pub manager: usize,
1685 pub automated_system: usize,
1686}
1687
1688impl Default for UsersPerPersona {
1689 fn default() -> Self {
1690 Self {
1691 junior_accountant: 10,
1692 senior_accountant: 5,
1693 controller: 2,
1694 manager: 3,
1695 automated_system: 20,
1696 }
1697 }
1698}
1699
1700#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1702pub struct TemplateConfig {
1703 #[serde(default)]
1705 pub names: NameTemplateConfig,
1706 #[serde(default)]
1708 pub descriptions: DescriptionTemplateConfig,
1709 #[serde(default)]
1711 pub references: ReferenceTemplateConfig,
1712}
1713
1714#[derive(Debug, Clone, Serialize, Deserialize)]
1716pub struct NameTemplateConfig {
1717 #[serde(default)]
1719 pub culture_distribution: CultureDistribution,
1720 #[serde(default = "default_email_domain")]
1722 pub email_domain: String,
1723 #[serde(default = "default_true")]
1725 pub generate_realistic_names: bool,
1726}
1727
1728fn default_email_domain() -> String {
1729 "company.com".to_string()
1730}
1731
1732impl Default for NameTemplateConfig {
1733 fn default() -> Self {
1734 Self {
1735 culture_distribution: CultureDistribution::default(),
1736 email_domain: default_email_domain(),
1737 generate_realistic_names: true,
1738 }
1739 }
1740}
1741
1742#[derive(Debug, Clone, Serialize, Deserialize)]
1744pub struct CultureDistribution {
1745 pub western_us: f64,
1746 pub hispanic: f64,
1747 pub german: f64,
1748 pub french: f64,
1749 pub chinese: f64,
1750 pub japanese: f64,
1751 pub indian: f64,
1752}
1753
1754impl Default for CultureDistribution {
1755 fn default() -> Self {
1756 Self {
1757 western_us: 0.40,
1758 hispanic: 0.20,
1759 german: 0.10,
1760 french: 0.05,
1761 chinese: 0.10,
1762 japanese: 0.05,
1763 indian: 0.10,
1764 }
1765 }
1766}
1767
1768#[derive(Debug, Clone, Serialize, Deserialize)]
1770pub struct DescriptionTemplateConfig {
1771 #[serde(default = "default_true")]
1773 pub generate_header_text: bool,
1774 #[serde(default = "default_true")]
1776 pub generate_line_text: bool,
1777}
1778
1779impl Default for DescriptionTemplateConfig {
1780 fn default() -> Self {
1781 Self {
1782 generate_header_text: true,
1783 generate_line_text: true,
1784 }
1785 }
1786}
1787
1788#[derive(Debug, Clone, Serialize, Deserialize)]
1790pub struct ReferenceTemplateConfig {
1791 #[serde(default = "default_true")]
1793 pub generate_references: bool,
1794 #[serde(default = "default_invoice_prefix")]
1796 pub invoice_prefix: String,
1797 #[serde(default = "default_po_prefix")]
1799 pub po_prefix: String,
1800 #[serde(default = "default_so_prefix")]
1802 pub so_prefix: String,
1803}
1804
1805fn default_invoice_prefix() -> String {
1806 "INV".to_string()
1807}
1808fn default_po_prefix() -> String {
1809 "PO".to_string()
1810}
1811fn default_so_prefix() -> String {
1812 "SO".to_string()
1813}
1814
1815impl Default for ReferenceTemplateConfig {
1816 fn default() -> Self {
1817 Self {
1818 generate_references: true,
1819 invoice_prefix: default_invoice_prefix(),
1820 po_prefix: default_po_prefix(),
1821 so_prefix: default_so_prefix(),
1822 }
1823 }
1824}
1825
1826#[derive(Debug, Clone, Serialize, Deserialize)]
1828pub struct ApprovalConfig {
1829 #[serde(default)]
1831 pub enabled: bool,
1832 #[serde(default = "default_auto_approve_threshold")]
1834 pub auto_approve_threshold: f64,
1835 #[serde(default = "default_rejection_rate")]
1837 pub rejection_rate: f64,
1838 #[serde(default = "default_revision_rate")]
1840 pub revision_rate: f64,
1841 #[serde(default = "default_approval_delay_hours")]
1843 pub average_approval_delay_hours: f64,
1844 #[serde(default)]
1846 pub thresholds: Vec<ApprovalThresholdConfig>,
1847}
1848
1849fn default_auto_approve_threshold() -> f64 {
1850 1000.0
1851}
1852fn default_rejection_rate() -> f64 {
1853 0.02
1854}
1855fn default_revision_rate() -> f64 {
1856 0.05
1857}
1858fn default_approval_delay_hours() -> f64 {
1859 4.0
1860}
1861
1862impl Default for ApprovalConfig {
1863 fn default() -> Self {
1864 Self {
1865 enabled: false,
1866 auto_approve_threshold: default_auto_approve_threshold(),
1867 rejection_rate: default_rejection_rate(),
1868 revision_rate: default_revision_rate(),
1869 average_approval_delay_hours: default_approval_delay_hours(),
1870 thresholds: vec![
1871 ApprovalThresholdConfig {
1872 amount: 1000.0,
1873 level: 1,
1874 roles: vec!["senior_accountant".to_string()],
1875 },
1876 ApprovalThresholdConfig {
1877 amount: 10000.0,
1878 level: 2,
1879 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1880 },
1881 ApprovalThresholdConfig {
1882 amount: 100000.0,
1883 level: 3,
1884 roles: vec![
1885 "senior_accountant".to_string(),
1886 "controller".to_string(),
1887 "manager".to_string(),
1888 ],
1889 },
1890 ApprovalThresholdConfig {
1891 amount: 500000.0,
1892 level: 4,
1893 roles: vec![
1894 "senior_accountant".to_string(),
1895 "controller".to_string(),
1896 "manager".to_string(),
1897 "executive".to_string(),
1898 ],
1899 },
1900 ],
1901 }
1902 }
1903}
1904
1905#[derive(Debug, Clone, Serialize, Deserialize)]
1907pub struct ApprovalThresholdConfig {
1908 pub amount: f64,
1910 pub level: u8,
1912 pub roles: Vec<String>,
1914}
1915
1916#[derive(Debug, Clone, Serialize, Deserialize)]
1918pub struct DepartmentConfig {
1919 #[serde(default)]
1921 pub enabled: bool,
1922 #[serde(default = "default_headcount_multiplier")]
1924 pub headcount_multiplier: f64,
1925 #[serde(default)]
1927 pub custom_departments: Vec<CustomDepartmentConfig>,
1928}
1929
1930fn default_headcount_multiplier() -> f64 {
1931 1.0
1932}
1933
1934impl Default for DepartmentConfig {
1935 fn default() -> Self {
1936 Self {
1937 enabled: false,
1938 headcount_multiplier: default_headcount_multiplier(),
1939 custom_departments: Vec::new(),
1940 }
1941 }
1942}
1943
1944#[derive(Debug, Clone, Serialize, Deserialize)]
1946pub struct CustomDepartmentConfig {
1947 pub code: String,
1949 pub name: String,
1951 #[serde(default)]
1953 pub cost_center: Option<String>,
1954 #[serde(default)]
1956 pub primary_processes: Vec<String>,
1957 #[serde(default)]
1959 pub parent_code: Option<String>,
1960}
1961
1962#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1968pub struct MasterDataConfig {
1969 #[serde(default)]
1971 pub vendors: VendorMasterConfig,
1972 #[serde(default)]
1974 pub customers: CustomerMasterConfig,
1975 #[serde(default)]
1977 pub materials: MaterialMasterConfig,
1978 #[serde(default)]
1980 pub fixed_assets: FixedAssetMasterConfig,
1981 #[serde(default)]
1983 pub employees: EmployeeMasterConfig,
1984 #[serde(default)]
1986 pub cost_centers: CostCenterMasterConfig,
1987}
1988
1989#[derive(Debug, Clone, Serialize, Deserialize)]
1991pub struct VendorMasterConfig {
1992 #[serde(default = "default_vendor_count")]
1994 pub count: usize,
1995 #[serde(default = "default_intercompany_percent")]
1997 pub intercompany_percent: f64,
1998 #[serde(default)]
2000 pub payment_terms_distribution: PaymentTermsDistribution,
2001 #[serde(default)]
2003 pub behavior_distribution: VendorBehaviorDistribution,
2004 #[serde(default = "default_true")]
2006 pub generate_bank_accounts: bool,
2007 #[serde(default = "default_true")]
2009 pub generate_tax_ids: bool,
2010}
2011
2012fn default_vendor_count() -> usize {
2013 500
2014}
2015
2016fn default_intercompany_percent() -> f64 {
2017 0.05
2018}
2019
2020impl Default for VendorMasterConfig {
2021 fn default() -> Self {
2022 Self {
2023 count: default_vendor_count(),
2024 intercompany_percent: default_intercompany_percent(),
2025 payment_terms_distribution: PaymentTermsDistribution::default(),
2026 behavior_distribution: VendorBehaviorDistribution::default(),
2027 generate_bank_accounts: true,
2028 generate_tax_ids: true,
2029 }
2030 }
2031}
2032
2033#[derive(Debug, Clone, Serialize, Deserialize)]
2035pub struct PaymentTermsDistribution {
2036 pub net_30: f64,
2038 pub net_60: f64,
2040 pub net_90: f64,
2042 pub two_ten_net_30: f64,
2044 pub due_on_receipt: f64,
2046 pub end_of_month: f64,
2048}
2049
2050impl Default for PaymentTermsDistribution {
2051 fn default() -> Self {
2052 Self {
2053 net_30: 0.40,
2054 net_60: 0.20,
2055 net_90: 0.10,
2056 two_ten_net_30: 0.15,
2057 due_on_receipt: 0.05,
2058 end_of_month: 0.10,
2059 }
2060 }
2061}
2062
2063#[derive(Debug, Clone, Serialize, Deserialize)]
2065pub struct VendorBehaviorDistribution {
2066 pub reliable: f64,
2068 pub sometimes_late: f64,
2070 pub inconsistent_quality: f64,
2072 pub premium: f64,
2074 pub budget: f64,
2076}
2077
2078impl Default for VendorBehaviorDistribution {
2079 fn default() -> Self {
2080 Self {
2081 reliable: 0.50,
2082 sometimes_late: 0.20,
2083 inconsistent_quality: 0.10,
2084 premium: 0.10,
2085 budget: 0.10,
2086 }
2087 }
2088}
2089
2090#[derive(Debug, Clone, Serialize, Deserialize)]
2092pub struct CustomerMasterConfig {
2093 #[serde(default = "default_customer_count")]
2095 pub count: usize,
2096 #[serde(default = "default_intercompany_percent")]
2098 pub intercompany_percent: f64,
2099 #[serde(default)]
2101 pub credit_rating_distribution: CreditRatingDistribution,
2102 #[serde(default)]
2104 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2105 #[serde(default = "default_true")]
2107 pub generate_credit_limits: bool,
2108}
2109
2110fn default_customer_count() -> usize {
2111 2000
2112}
2113
2114impl Default for CustomerMasterConfig {
2115 fn default() -> Self {
2116 Self {
2117 count: default_customer_count(),
2118 intercompany_percent: default_intercompany_percent(),
2119 credit_rating_distribution: CreditRatingDistribution::default(),
2120 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2121 generate_credit_limits: true,
2122 }
2123 }
2124}
2125
2126#[derive(Debug, Clone, Serialize, Deserialize)]
2128pub struct CreditRatingDistribution {
2129 pub aaa: f64,
2131 pub aa: f64,
2133 pub a: f64,
2135 pub bbb: f64,
2137 pub bb: f64,
2139 pub b: f64,
2141 pub below_b: f64,
2143}
2144
2145impl Default for CreditRatingDistribution {
2146 fn default() -> Self {
2147 Self {
2148 aaa: 0.05,
2149 aa: 0.10,
2150 a: 0.20,
2151 bbb: 0.30,
2152 bb: 0.20,
2153 b: 0.10,
2154 below_b: 0.05,
2155 }
2156 }
2157}
2158
2159#[derive(Debug, Clone, Serialize, Deserialize)]
2161pub struct PaymentBehaviorDistribution {
2162 pub early_payer: f64,
2164 pub on_time: f64,
2166 pub occasional_late: f64,
2168 pub frequent_late: f64,
2170 pub discount_taker: f64,
2172}
2173
2174impl Default for PaymentBehaviorDistribution {
2175 fn default() -> Self {
2176 Self {
2177 early_payer: 0.10,
2178 on_time: 0.50,
2179 occasional_late: 0.25,
2180 frequent_late: 0.10,
2181 discount_taker: 0.05,
2182 }
2183 }
2184}
2185
2186#[derive(Debug, Clone, Serialize, Deserialize)]
2188pub struct MaterialMasterConfig {
2189 #[serde(default = "default_material_count")]
2191 pub count: usize,
2192 #[serde(default)]
2194 pub type_distribution: MaterialTypeDistribution,
2195 #[serde(default)]
2197 pub valuation_distribution: ValuationMethodDistribution,
2198 #[serde(default = "default_bom_percent")]
2200 pub bom_percent: f64,
2201 #[serde(default = "default_max_bom_depth")]
2203 pub max_bom_depth: u8,
2204}
2205
2206fn default_material_count() -> usize {
2207 5000
2208}
2209
2210fn default_bom_percent() -> f64 {
2211 0.20
2212}
2213
2214fn default_max_bom_depth() -> u8 {
2215 3
2216}
2217
2218impl Default for MaterialMasterConfig {
2219 fn default() -> Self {
2220 Self {
2221 count: default_material_count(),
2222 type_distribution: MaterialTypeDistribution::default(),
2223 valuation_distribution: ValuationMethodDistribution::default(),
2224 bom_percent: default_bom_percent(),
2225 max_bom_depth: default_max_bom_depth(),
2226 }
2227 }
2228}
2229
2230#[derive(Debug, Clone, Serialize, Deserialize)]
2232pub struct MaterialTypeDistribution {
2233 pub raw_material: f64,
2235 pub semi_finished: f64,
2237 pub finished_good: f64,
2239 pub trading_good: f64,
2241 pub operating_supply: f64,
2243 pub service: f64,
2245}
2246
2247impl Default for MaterialTypeDistribution {
2248 fn default() -> Self {
2249 Self {
2250 raw_material: 0.30,
2251 semi_finished: 0.15,
2252 finished_good: 0.25,
2253 trading_good: 0.15,
2254 operating_supply: 0.10,
2255 service: 0.05,
2256 }
2257 }
2258}
2259
2260#[derive(Debug, Clone, Serialize, Deserialize)]
2262pub struct ValuationMethodDistribution {
2263 pub standard_cost: f64,
2265 pub moving_average: f64,
2267 pub fifo: f64,
2269 pub lifo: f64,
2271}
2272
2273impl Default for ValuationMethodDistribution {
2274 fn default() -> Self {
2275 Self {
2276 standard_cost: 0.50,
2277 moving_average: 0.30,
2278 fifo: 0.15,
2279 lifo: 0.05,
2280 }
2281 }
2282}
2283
2284#[derive(Debug, Clone, Serialize, Deserialize)]
2286pub struct FixedAssetMasterConfig {
2287 #[serde(default = "default_asset_count")]
2289 pub count: usize,
2290 #[serde(default)]
2292 pub class_distribution: AssetClassDistribution,
2293 #[serde(default)]
2295 pub depreciation_distribution: DepreciationMethodDistribution,
2296 #[serde(default = "default_fully_depreciated_percent")]
2298 pub fully_depreciated_percent: f64,
2299 #[serde(default = "default_true")]
2301 pub generate_acquisition_history: bool,
2302}
2303
2304fn default_asset_count() -> usize {
2305 800
2306}
2307
2308fn default_fully_depreciated_percent() -> f64 {
2309 0.15
2310}
2311
2312impl Default for FixedAssetMasterConfig {
2313 fn default() -> Self {
2314 Self {
2315 count: default_asset_count(),
2316 class_distribution: AssetClassDistribution::default(),
2317 depreciation_distribution: DepreciationMethodDistribution::default(),
2318 fully_depreciated_percent: default_fully_depreciated_percent(),
2319 generate_acquisition_history: true,
2320 }
2321 }
2322}
2323
2324#[derive(Debug, Clone, Serialize, Deserialize)]
2326pub struct AssetClassDistribution {
2327 pub buildings: f64,
2329 pub machinery: f64,
2331 pub vehicles: f64,
2333 pub it_equipment: f64,
2335 pub furniture: f64,
2337 pub land: f64,
2339 pub leasehold: f64,
2341}
2342
2343impl Default for AssetClassDistribution {
2344 fn default() -> Self {
2345 Self {
2346 buildings: 0.15,
2347 machinery: 0.30,
2348 vehicles: 0.15,
2349 it_equipment: 0.20,
2350 furniture: 0.10,
2351 land: 0.05,
2352 leasehold: 0.05,
2353 }
2354 }
2355}
2356
2357#[derive(Debug, Clone, Serialize, Deserialize)]
2359pub struct DepreciationMethodDistribution {
2360 pub straight_line: f64,
2362 pub declining_balance: f64,
2364 pub double_declining: f64,
2366 pub sum_of_years: f64,
2368 pub units_of_production: f64,
2370}
2371
2372impl Default for DepreciationMethodDistribution {
2373 fn default() -> Self {
2374 Self {
2375 straight_line: 0.60,
2376 declining_balance: 0.20,
2377 double_declining: 0.10,
2378 sum_of_years: 0.05,
2379 units_of_production: 0.05,
2380 }
2381 }
2382}
2383
2384#[derive(Debug, Clone, Serialize, Deserialize)]
2386pub struct EmployeeMasterConfig {
2387 #[serde(default = "default_employee_count")]
2389 pub count: usize,
2390 #[serde(default = "default_true")]
2392 pub generate_hierarchy: bool,
2393 #[serde(default = "default_hierarchy_depth")]
2395 pub max_hierarchy_depth: u8,
2396 #[serde(default = "default_span_of_control")]
2398 pub average_span_of_control: f64,
2399 #[serde(default)]
2401 pub approval_limits: ApprovalLimitDistribution,
2402 #[serde(default)]
2404 pub department_distribution: EmployeeDepartmentDistribution,
2405}
2406
2407fn default_employee_count() -> usize {
2408 1500
2409}
2410
2411fn default_hierarchy_depth() -> u8 {
2412 6
2413}
2414
2415fn default_span_of_control() -> f64 {
2416 5.0
2417}
2418
2419impl Default for EmployeeMasterConfig {
2420 fn default() -> Self {
2421 Self {
2422 count: default_employee_count(),
2423 generate_hierarchy: true,
2424 max_hierarchy_depth: default_hierarchy_depth(),
2425 average_span_of_control: default_span_of_control(),
2426 approval_limits: ApprovalLimitDistribution::default(),
2427 department_distribution: EmployeeDepartmentDistribution::default(),
2428 }
2429 }
2430}
2431
2432#[derive(Debug, Clone, Serialize, Deserialize)]
2434pub struct ApprovalLimitDistribution {
2435 #[serde(default = "default_staff_limit")]
2437 pub staff: f64,
2438 #[serde(default = "default_senior_limit")]
2440 pub senior: f64,
2441 #[serde(default = "default_manager_limit")]
2443 pub manager: f64,
2444 #[serde(default = "default_director_limit")]
2446 pub director: f64,
2447 #[serde(default = "default_vp_limit")]
2449 pub vp: f64,
2450 #[serde(default = "default_executive_limit")]
2452 pub executive: f64,
2453}
2454
2455fn default_staff_limit() -> f64 {
2456 1000.0
2457}
2458fn default_senior_limit() -> f64 {
2459 5000.0
2460}
2461fn default_manager_limit() -> f64 {
2462 25000.0
2463}
2464fn default_director_limit() -> f64 {
2465 100000.0
2466}
2467fn default_vp_limit() -> f64 {
2468 500000.0
2469}
2470fn default_executive_limit() -> f64 {
2471 f64::INFINITY
2472}
2473
2474impl Default for ApprovalLimitDistribution {
2475 fn default() -> Self {
2476 Self {
2477 staff: default_staff_limit(),
2478 senior: default_senior_limit(),
2479 manager: default_manager_limit(),
2480 director: default_director_limit(),
2481 vp: default_vp_limit(),
2482 executive: default_executive_limit(),
2483 }
2484 }
2485}
2486
2487#[derive(Debug, Clone, Serialize, Deserialize)]
2489pub struct EmployeeDepartmentDistribution {
2490 pub finance: f64,
2492 pub procurement: f64,
2494 pub sales: f64,
2496 pub warehouse: f64,
2498 pub it: f64,
2500 pub hr: f64,
2502 pub operations: f64,
2504 pub executive: f64,
2506}
2507
2508impl Default for EmployeeDepartmentDistribution {
2509 fn default() -> Self {
2510 Self {
2511 finance: 0.12,
2512 procurement: 0.10,
2513 sales: 0.25,
2514 warehouse: 0.15,
2515 it: 0.10,
2516 hr: 0.05,
2517 operations: 0.20,
2518 executive: 0.03,
2519 }
2520 }
2521}
2522
2523#[derive(Debug, Clone, Serialize, Deserialize)]
2525pub struct CostCenterMasterConfig {
2526 #[serde(default = "default_cost_center_count")]
2528 pub count: usize,
2529 #[serde(default = "default_true")]
2531 pub generate_hierarchy: bool,
2532 #[serde(default = "default_cc_hierarchy_depth")]
2534 pub max_hierarchy_depth: u8,
2535}
2536
2537fn default_cost_center_count() -> usize {
2538 50
2539}
2540
2541fn default_cc_hierarchy_depth() -> u8 {
2542 3
2543}
2544
2545impl Default for CostCenterMasterConfig {
2546 fn default() -> Self {
2547 Self {
2548 count: default_cost_center_count(),
2549 generate_hierarchy: true,
2550 max_hierarchy_depth: default_cc_hierarchy_depth(),
2551 }
2552 }
2553}
2554
2555#[derive(Debug, Clone, Serialize, Deserialize)]
2561pub struct DocumentFlowConfig {
2562 #[serde(default)]
2564 pub p2p: P2PFlowConfig,
2565 #[serde(default)]
2567 pub o2c: O2CFlowConfig,
2568 #[serde(default = "default_true")]
2570 pub generate_document_references: bool,
2571 #[serde(default)]
2573 pub export_flow_graph: bool,
2574}
2575
2576impl Default for DocumentFlowConfig {
2577 fn default() -> Self {
2578 Self {
2579 p2p: P2PFlowConfig::default(),
2580 o2c: O2CFlowConfig::default(),
2581 generate_document_references: true,
2582 export_flow_graph: false,
2583 }
2584 }
2585}
2586
2587#[derive(Debug, Clone, Serialize, Deserialize)]
2589pub struct P2PFlowConfig {
2590 #[serde(default = "default_true")]
2592 pub enabled: bool,
2593 #[serde(default = "default_three_way_match_rate")]
2595 pub three_way_match_rate: f64,
2596 #[serde(default = "default_partial_delivery_rate")]
2598 pub partial_delivery_rate: f64,
2599 #[serde(default = "default_price_variance_rate")]
2601 pub price_variance_rate: f64,
2602 #[serde(default = "default_max_price_variance")]
2604 pub max_price_variance_percent: f64,
2605 #[serde(default = "default_quantity_variance_rate")]
2607 pub quantity_variance_rate: f64,
2608 #[serde(default = "default_po_to_gr_days")]
2610 pub average_po_to_gr_days: u32,
2611 #[serde(default = "default_gr_to_invoice_days")]
2613 pub average_gr_to_invoice_days: u32,
2614 #[serde(default = "default_invoice_to_payment_days")]
2616 pub average_invoice_to_payment_days: u32,
2617 #[serde(default)]
2619 pub line_count_distribution: DocumentLineCountDistribution,
2620 #[serde(default)]
2622 pub payment_behavior: P2PPaymentBehaviorConfig,
2623}
2624
2625fn default_three_way_match_rate() -> f64 {
2626 0.95
2627}
2628
2629fn default_partial_delivery_rate() -> f64 {
2630 0.15
2631}
2632
2633fn default_price_variance_rate() -> f64 {
2634 0.08
2635}
2636
2637fn default_max_price_variance() -> f64 {
2638 0.05
2639}
2640
2641fn default_quantity_variance_rate() -> f64 {
2642 0.05
2643}
2644
2645fn default_po_to_gr_days() -> u32 {
2646 14
2647}
2648
2649fn default_gr_to_invoice_days() -> u32 {
2650 5
2651}
2652
2653fn default_invoice_to_payment_days() -> u32 {
2654 30
2655}
2656
2657impl Default for P2PFlowConfig {
2658 fn default() -> Self {
2659 Self {
2660 enabled: true,
2661 three_way_match_rate: default_three_way_match_rate(),
2662 partial_delivery_rate: default_partial_delivery_rate(),
2663 price_variance_rate: default_price_variance_rate(),
2664 max_price_variance_percent: default_max_price_variance(),
2665 quantity_variance_rate: default_quantity_variance_rate(),
2666 average_po_to_gr_days: default_po_to_gr_days(),
2667 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2668 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2669 line_count_distribution: DocumentLineCountDistribution::default(),
2670 payment_behavior: P2PPaymentBehaviorConfig::default(),
2671 }
2672 }
2673}
2674
2675#[derive(Debug, Clone, Serialize, Deserialize)]
2681pub struct P2PPaymentBehaviorConfig {
2682 #[serde(default = "default_p2p_late_payment_rate")]
2684 pub late_payment_rate: f64,
2685 #[serde(default)]
2687 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2688 #[serde(default = "default_p2p_partial_payment_rate")]
2690 pub partial_payment_rate: f64,
2691 #[serde(default = "default_p2p_payment_correction_rate")]
2693 pub payment_correction_rate: f64,
2694}
2695
2696fn default_p2p_late_payment_rate() -> f64 {
2697 0.15
2698}
2699
2700fn default_p2p_partial_payment_rate() -> f64 {
2701 0.05
2702}
2703
2704fn default_p2p_payment_correction_rate() -> f64 {
2705 0.02
2706}
2707
2708impl Default for P2PPaymentBehaviorConfig {
2709 fn default() -> Self {
2710 Self {
2711 late_payment_rate: default_p2p_late_payment_rate(),
2712 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2713 partial_payment_rate: default_p2p_partial_payment_rate(),
2714 payment_correction_rate: default_p2p_payment_correction_rate(),
2715 }
2716 }
2717}
2718
2719#[derive(Debug, Clone, Serialize, Deserialize)]
2721pub struct LatePaymentDaysDistribution {
2722 #[serde(default = "default_slightly_late")]
2724 pub slightly_late_1_to_7: f64,
2725 #[serde(default = "default_late_8_14")]
2727 pub late_8_to_14: f64,
2728 #[serde(default = "default_very_late")]
2730 pub very_late_15_to_30: f64,
2731 #[serde(default = "default_severely_late")]
2733 pub severely_late_31_to_60: f64,
2734 #[serde(default = "default_extremely_late")]
2736 pub extremely_late_over_60: f64,
2737}
2738
2739fn default_slightly_late() -> f64 {
2740 0.50
2741}
2742
2743fn default_late_8_14() -> f64 {
2744 0.25
2745}
2746
2747fn default_very_late() -> f64 {
2748 0.15
2749}
2750
2751fn default_severely_late() -> f64 {
2752 0.07
2753}
2754
2755fn default_extremely_late() -> f64 {
2756 0.03
2757}
2758
2759impl Default for LatePaymentDaysDistribution {
2760 fn default() -> Self {
2761 Self {
2762 slightly_late_1_to_7: default_slightly_late(),
2763 late_8_to_14: default_late_8_14(),
2764 very_late_15_to_30: default_very_late(),
2765 severely_late_31_to_60: default_severely_late(),
2766 extremely_late_over_60: default_extremely_late(),
2767 }
2768 }
2769}
2770
2771#[derive(Debug, Clone, Serialize, Deserialize)]
2773pub struct O2CFlowConfig {
2774 #[serde(default = "default_true")]
2776 pub enabled: bool,
2777 #[serde(default = "default_credit_check_failure_rate")]
2779 pub credit_check_failure_rate: f64,
2780 #[serde(default = "default_partial_shipment_rate")]
2782 pub partial_shipment_rate: f64,
2783 #[serde(default = "default_return_rate")]
2785 pub return_rate: f64,
2786 #[serde(default = "default_bad_debt_rate")]
2788 pub bad_debt_rate: f64,
2789 #[serde(default = "default_so_to_delivery_days")]
2791 pub average_so_to_delivery_days: u32,
2792 #[serde(default = "default_delivery_to_invoice_days")]
2794 pub average_delivery_to_invoice_days: u32,
2795 #[serde(default = "default_invoice_to_receipt_days")]
2797 pub average_invoice_to_receipt_days: u32,
2798 #[serde(default)]
2800 pub line_count_distribution: DocumentLineCountDistribution,
2801 #[serde(default)]
2803 pub cash_discount: CashDiscountConfig,
2804 #[serde(default)]
2806 pub payment_behavior: O2CPaymentBehaviorConfig,
2807}
2808
2809fn default_credit_check_failure_rate() -> f64 {
2810 0.02
2811}
2812
2813fn default_partial_shipment_rate() -> f64 {
2814 0.10
2815}
2816
2817fn default_return_rate() -> f64 {
2818 0.03
2819}
2820
2821fn default_bad_debt_rate() -> f64 {
2822 0.01
2823}
2824
2825fn default_so_to_delivery_days() -> u32 {
2826 7
2827}
2828
2829fn default_delivery_to_invoice_days() -> u32 {
2830 1
2831}
2832
2833fn default_invoice_to_receipt_days() -> u32 {
2834 45
2835}
2836
2837impl Default for O2CFlowConfig {
2838 fn default() -> Self {
2839 Self {
2840 enabled: true,
2841 credit_check_failure_rate: default_credit_check_failure_rate(),
2842 partial_shipment_rate: default_partial_shipment_rate(),
2843 return_rate: default_return_rate(),
2844 bad_debt_rate: default_bad_debt_rate(),
2845 average_so_to_delivery_days: default_so_to_delivery_days(),
2846 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2847 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2848 line_count_distribution: DocumentLineCountDistribution::default(),
2849 cash_discount: CashDiscountConfig::default(),
2850 payment_behavior: O2CPaymentBehaviorConfig::default(),
2851 }
2852 }
2853}
2854
2855#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2861pub struct O2CPaymentBehaviorConfig {
2862 #[serde(default)]
2864 pub dunning: DunningConfig,
2865 #[serde(default)]
2867 pub partial_payments: PartialPaymentConfig,
2868 #[serde(default)]
2870 pub short_payments: ShortPaymentConfig,
2871 #[serde(default)]
2873 pub on_account_payments: OnAccountPaymentConfig,
2874 #[serde(default)]
2876 pub payment_corrections: PaymentCorrectionConfig,
2877}
2878
2879#[derive(Debug, Clone, Serialize, Deserialize)]
2881pub struct DunningConfig {
2882 #[serde(default)]
2884 pub enabled: bool,
2885 #[serde(default = "default_dunning_level_1_days")]
2887 pub level_1_days_overdue: u32,
2888 #[serde(default = "default_dunning_level_2_days")]
2890 pub level_2_days_overdue: u32,
2891 #[serde(default = "default_dunning_level_3_days")]
2893 pub level_3_days_overdue: u32,
2894 #[serde(default = "default_collection_days")]
2896 pub collection_days_overdue: u32,
2897 #[serde(default)]
2899 pub payment_after_dunning_rates: DunningPaymentRates,
2900 #[serde(default = "default_dunning_block_rate")]
2902 pub dunning_block_rate: f64,
2903 #[serde(default = "default_dunning_interest_rate")]
2905 pub interest_rate_per_year: f64,
2906 #[serde(default = "default_dunning_charge")]
2908 pub dunning_charge: f64,
2909}
2910
2911fn default_dunning_level_1_days() -> u32 {
2912 14
2913}
2914
2915fn default_dunning_level_2_days() -> u32 {
2916 28
2917}
2918
2919fn default_dunning_level_3_days() -> u32 {
2920 42
2921}
2922
2923fn default_collection_days() -> u32 {
2924 60
2925}
2926
2927fn default_dunning_block_rate() -> f64 {
2928 0.05
2929}
2930
2931fn default_dunning_interest_rate() -> f64 {
2932 0.09
2933}
2934
2935fn default_dunning_charge() -> f64 {
2936 25.0
2937}
2938
2939impl Default for DunningConfig {
2940 fn default() -> Self {
2941 Self {
2942 enabled: false,
2943 level_1_days_overdue: default_dunning_level_1_days(),
2944 level_2_days_overdue: default_dunning_level_2_days(),
2945 level_3_days_overdue: default_dunning_level_3_days(),
2946 collection_days_overdue: default_collection_days(),
2947 payment_after_dunning_rates: DunningPaymentRates::default(),
2948 dunning_block_rate: default_dunning_block_rate(),
2949 interest_rate_per_year: default_dunning_interest_rate(),
2950 dunning_charge: default_dunning_charge(),
2951 }
2952 }
2953}
2954
2955#[derive(Debug, Clone, Serialize, Deserialize)]
2957pub struct DunningPaymentRates {
2958 #[serde(default = "default_after_level_1")]
2960 pub after_level_1: f64,
2961 #[serde(default = "default_after_level_2")]
2963 pub after_level_2: f64,
2964 #[serde(default = "default_after_level_3")]
2966 pub after_level_3: f64,
2967 #[serde(default = "default_during_collection")]
2969 pub during_collection: f64,
2970 #[serde(default = "default_never_pay")]
2972 pub never_pay: f64,
2973}
2974
2975fn default_after_level_1() -> f64 {
2976 0.40
2977}
2978
2979fn default_after_level_2() -> f64 {
2980 0.30
2981}
2982
2983fn default_after_level_3() -> f64 {
2984 0.15
2985}
2986
2987fn default_during_collection() -> f64 {
2988 0.05
2989}
2990
2991fn default_never_pay() -> f64 {
2992 0.10
2993}
2994
2995impl Default for DunningPaymentRates {
2996 fn default() -> Self {
2997 Self {
2998 after_level_1: default_after_level_1(),
2999 after_level_2: default_after_level_2(),
3000 after_level_3: default_after_level_3(),
3001 during_collection: default_during_collection(),
3002 never_pay: default_never_pay(),
3003 }
3004 }
3005}
3006
3007#[derive(Debug, Clone, Serialize, Deserialize)]
3009pub struct PartialPaymentConfig {
3010 #[serde(default = "default_partial_payment_rate")]
3012 pub rate: f64,
3013 #[serde(default)]
3015 pub percentage_distribution: PartialPaymentPercentageDistribution,
3016 #[serde(default = "default_avg_days_until_remainder")]
3018 pub avg_days_until_remainder: u32,
3019}
3020
3021fn default_partial_payment_rate() -> f64 {
3022 0.08
3023}
3024
3025fn default_avg_days_until_remainder() -> u32 {
3026 30
3027}
3028
3029impl Default for PartialPaymentConfig {
3030 fn default() -> Self {
3031 Self {
3032 rate: default_partial_payment_rate(),
3033 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3034 avg_days_until_remainder: default_avg_days_until_remainder(),
3035 }
3036 }
3037}
3038
3039#[derive(Debug, Clone, Serialize, Deserialize)]
3041pub struct PartialPaymentPercentageDistribution {
3042 #[serde(default = "default_partial_25")]
3044 pub pay_25_percent: f64,
3045 #[serde(default = "default_partial_50")]
3047 pub pay_50_percent: f64,
3048 #[serde(default = "default_partial_75")]
3050 pub pay_75_percent: f64,
3051 #[serde(default = "default_partial_random")]
3053 pub pay_random_percent: f64,
3054}
3055
3056fn default_partial_25() -> f64 {
3057 0.15
3058}
3059
3060fn default_partial_50() -> f64 {
3061 0.50
3062}
3063
3064fn default_partial_75() -> f64 {
3065 0.25
3066}
3067
3068fn default_partial_random() -> f64 {
3069 0.10
3070}
3071
3072impl Default for PartialPaymentPercentageDistribution {
3073 fn default() -> Self {
3074 Self {
3075 pay_25_percent: default_partial_25(),
3076 pay_50_percent: default_partial_50(),
3077 pay_75_percent: default_partial_75(),
3078 pay_random_percent: default_partial_random(),
3079 }
3080 }
3081}
3082
3083#[derive(Debug, Clone, Serialize, Deserialize)]
3085pub struct ShortPaymentConfig {
3086 #[serde(default = "default_short_payment_rate")]
3088 pub rate: f64,
3089 #[serde(default)]
3091 pub reason_distribution: ShortPaymentReasonDistribution,
3092 #[serde(default = "default_max_short_percent")]
3094 pub max_short_percent: f64,
3095}
3096
3097fn default_short_payment_rate() -> f64 {
3098 0.03
3099}
3100
3101fn default_max_short_percent() -> f64 {
3102 0.10
3103}
3104
3105impl Default for ShortPaymentConfig {
3106 fn default() -> Self {
3107 Self {
3108 rate: default_short_payment_rate(),
3109 reason_distribution: ShortPaymentReasonDistribution::default(),
3110 max_short_percent: default_max_short_percent(),
3111 }
3112 }
3113}
3114
3115#[derive(Debug, Clone, Serialize, Deserialize)]
3117pub struct ShortPaymentReasonDistribution {
3118 #[serde(default = "default_pricing_dispute")]
3120 pub pricing_dispute: f64,
3121 #[serde(default = "default_quality_issue")]
3123 pub quality_issue: f64,
3124 #[serde(default = "default_quantity_discrepancy")]
3126 pub quantity_discrepancy: f64,
3127 #[serde(default = "default_unauthorized_deduction")]
3129 pub unauthorized_deduction: f64,
3130 #[serde(default = "default_incorrect_discount")]
3132 pub incorrect_discount: f64,
3133}
3134
3135fn default_pricing_dispute() -> f64 {
3136 0.30
3137}
3138
3139fn default_quality_issue() -> f64 {
3140 0.20
3141}
3142
3143fn default_quantity_discrepancy() -> f64 {
3144 0.20
3145}
3146
3147fn default_unauthorized_deduction() -> f64 {
3148 0.15
3149}
3150
3151fn default_incorrect_discount() -> f64 {
3152 0.15
3153}
3154
3155impl Default for ShortPaymentReasonDistribution {
3156 fn default() -> Self {
3157 Self {
3158 pricing_dispute: default_pricing_dispute(),
3159 quality_issue: default_quality_issue(),
3160 quantity_discrepancy: default_quantity_discrepancy(),
3161 unauthorized_deduction: default_unauthorized_deduction(),
3162 incorrect_discount: default_incorrect_discount(),
3163 }
3164 }
3165}
3166
3167#[derive(Debug, Clone, Serialize, Deserialize)]
3169pub struct OnAccountPaymentConfig {
3170 #[serde(default = "default_on_account_rate")]
3172 pub rate: f64,
3173 #[serde(default = "default_avg_days_until_applied")]
3175 pub avg_days_until_applied: u32,
3176}
3177
3178fn default_on_account_rate() -> f64 {
3179 0.02
3180}
3181
3182fn default_avg_days_until_applied() -> u32 {
3183 14
3184}
3185
3186impl Default for OnAccountPaymentConfig {
3187 fn default() -> Self {
3188 Self {
3189 rate: default_on_account_rate(),
3190 avg_days_until_applied: default_avg_days_until_applied(),
3191 }
3192 }
3193}
3194
3195#[derive(Debug, Clone, Serialize, Deserialize)]
3197pub struct PaymentCorrectionConfig {
3198 #[serde(default = "default_payment_correction_rate")]
3200 pub rate: f64,
3201 #[serde(default)]
3203 pub type_distribution: PaymentCorrectionTypeDistribution,
3204}
3205
3206fn default_payment_correction_rate() -> f64 {
3207 0.02
3208}
3209
3210impl Default for PaymentCorrectionConfig {
3211 fn default() -> Self {
3212 Self {
3213 rate: default_payment_correction_rate(),
3214 type_distribution: PaymentCorrectionTypeDistribution::default(),
3215 }
3216 }
3217}
3218
3219#[derive(Debug, Clone, Serialize, Deserialize)]
3221pub struct PaymentCorrectionTypeDistribution {
3222 #[serde(default = "default_nsf_rate")]
3224 pub nsf: f64,
3225 #[serde(default = "default_chargeback_rate")]
3227 pub chargeback: f64,
3228 #[serde(default = "default_wrong_amount_rate")]
3230 pub wrong_amount: f64,
3231 #[serde(default = "default_wrong_customer_rate")]
3233 pub wrong_customer: f64,
3234 #[serde(default = "default_duplicate_payment_rate")]
3236 pub duplicate_payment: f64,
3237}
3238
3239fn default_nsf_rate() -> f64 {
3240 0.30
3241}
3242
3243fn default_chargeback_rate() -> f64 {
3244 0.20
3245}
3246
3247fn default_wrong_amount_rate() -> f64 {
3248 0.20
3249}
3250
3251fn default_wrong_customer_rate() -> f64 {
3252 0.15
3253}
3254
3255fn default_duplicate_payment_rate() -> f64 {
3256 0.15
3257}
3258
3259impl Default for PaymentCorrectionTypeDistribution {
3260 fn default() -> Self {
3261 Self {
3262 nsf: default_nsf_rate(),
3263 chargeback: default_chargeback_rate(),
3264 wrong_amount: default_wrong_amount_rate(),
3265 wrong_customer: default_wrong_customer_rate(),
3266 duplicate_payment: default_duplicate_payment_rate(),
3267 }
3268 }
3269}
3270
3271#[derive(Debug, Clone, Serialize, Deserialize)]
3273pub struct DocumentLineCountDistribution {
3274 #[serde(default = "default_min_lines")]
3276 pub min_lines: u32,
3277 #[serde(default = "default_max_lines")]
3279 pub max_lines: u32,
3280 #[serde(default = "default_mode_lines")]
3282 pub mode_lines: u32,
3283}
3284
3285fn default_min_lines() -> u32 {
3286 1
3287}
3288
3289fn default_max_lines() -> u32 {
3290 20
3291}
3292
3293fn default_mode_lines() -> u32 {
3294 3
3295}
3296
3297impl Default for DocumentLineCountDistribution {
3298 fn default() -> Self {
3299 Self {
3300 min_lines: default_min_lines(),
3301 max_lines: default_max_lines(),
3302 mode_lines: default_mode_lines(),
3303 }
3304 }
3305}
3306
3307#[derive(Debug, Clone, Serialize, Deserialize)]
3309pub struct CashDiscountConfig {
3310 #[serde(default = "default_discount_eligible_rate")]
3312 pub eligible_rate: f64,
3313 #[serde(default = "default_discount_taken_rate")]
3315 pub taken_rate: f64,
3316 #[serde(default = "default_discount_percent")]
3318 pub discount_percent: f64,
3319 #[serde(default = "default_discount_days")]
3321 pub discount_days: u32,
3322}
3323
3324fn default_discount_eligible_rate() -> f64 {
3325 0.30
3326}
3327
3328fn default_discount_taken_rate() -> f64 {
3329 0.60
3330}
3331
3332fn default_discount_percent() -> f64 {
3333 0.02
3334}
3335
3336fn default_discount_days() -> u32 {
3337 10
3338}
3339
3340impl Default for CashDiscountConfig {
3341 fn default() -> Self {
3342 Self {
3343 eligible_rate: default_discount_eligible_rate(),
3344 taken_rate: default_discount_taken_rate(),
3345 discount_percent: default_discount_percent(),
3346 discount_days: default_discount_days(),
3347 }
3348 }
3349}
3350
3351#[derive(Debug, Clone, Serialize, Deserialize)]
3357pub struct IntercompanyConfig {
3358 #[serde(default)]
3360 pub enabled: bool,
3361 #[serde(default = "default_ic_transaction_rate")]
3363 pub ic_transaction_rate: f64,
3364 #[serde(default)]
3366 pub transfer_pricing_method: TransferPricingMethod,
3367 #[serde(default = "default_markup_percent")]
3369 pub markup_percent: f64,
3370 #[serde(default = "default_true")]
3372 pub generate_matched_pairs: bool,
3373 #[serde(default)]
3375 pub transaction_type_distribution: ICTransactionTypeDistribution,
3376 #[serde(default)]
3378 pub generate_eliminations: bool,
3379}
3380
3381fn default_ic_transaction_rate() -> f64 {
3382 0.15
3383}
3384
3385fn default_markup_percent() -> f64 {
3386 0.05
3387}
3388
3389impl Default for IntercompanyConfig {
3390 fn default() -> Self {
3391 Self {
3392 enabled: false,
3393 ic_transaction_rate: default_ic_transaction_rate(),
3394 transfer_pricing_method: TransferPricingMethod::default(),
3395 markup_percent: default_markup_percent(),
3396 generate_matched_pairs: true,
3397 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3398 generate_eliminations: false,
3399 }
3400 }
3401}
3402
3403#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3405#[serde(rename_all = "snake_case")]
3406pub enum TransferPricingMethod {
3407 #[default]
3409 CostPlus,
3410 ComparableUncontrolled,
3412 ResalePrice,
3414 TransactionalNetMargin,
3416 ProfitSplit,
3418}
3419
3420#[derive(Debug, Clone, Serialize, Deserialize)]
3422pub struct ICTransactionTypeDistribution {
3423 pub goods_sale: f64,
3425 pub service_provided: f64,
3427 pub loan: f64,
3429 pub dividend: f64,
3431 pub management_fee: f64,
3433 pub royalty: f64,
3435 pub cost_sharing: f64,
3437}
3438
3439impl Default for ICTransactionTypeDistribution {
3440 fn default() -> Self {
3441 Self {
3442 goods_sale: 0.35,
3443 service_provided: 0.20,
3444 loan: 0.10,
3445 dividend: 0.05,
3446 management_fee: 0.15,
3447 royalty: 0.10,
3448 cost_sharing: 0.05,
3449 }
3450 }
3451}
3452
3453#[derive(Debug, Clone, Serialize, Deserialize)]
3459pub struct BalanceConfig {
3460 #[serde(default)]
3462 pub generate_opening_balances: bool,
3463 #[serde(default = "default_true")]
3465 pub generate_trial_balances: bool,
3466 #[serde(default = "default_gross_margin")]
3468 pub target_gross_margin: f64,
3469 #[serde(default = "default_dso")]
3471 pub target_dso_days: u32,
3472 #[serde(default = "default_dpo")]
3474 pub target_dpo_days: u32,
3475 #[serde(default = "default_current_ratio")]
3477 pub target_current_ratio: f64,
3478 #[serde(default = "default_debt_equity")]
3480 pub target_debt_to_equity: f64,
3481 #[serde(default = "default_true")]
3483 pub validate_balance_equation: bool,
3484 #[serde(default = "default_true")]
3486 pub reconcile_subledgers: bool,
3487}
3488
3489fn default_gross_margin() -> f64 {
3490 0.35
3491}
3492
3493fn default_dso() -> u32 {
3494 45
3495}
3496
3497fn default_dpo() -> u32 {
3498 30
3499}
3500
3501fn default_current_ratio() -> f64 {
3502 1.5
3503}
3504
3505fn default_debt_equity() -> f64 {
3506 0.5
3507}
3508
3509impl Default for BalanceConfig {
3510 fn default() -> Self {
3511 Self {
3512 generate_opening_balances: false,
3513 generate_trial_balances: true,
3514 target_gross_margin: default_gross_margin(),
3515 target_dso_days: default_dso(),
3516 target_dpo_days: default_dpo(),
3517 target_current_ratio: default_current_ratio(),
3518 target_debt_to_equity: default_debt_equity(),
3519 validate_balance_equation: true,
3520 reconcile_subledgers: true,
3521 }
3522 }
3523}
3524
3525#[derive(Debug, Clone, Serialize, Deserialize)]
3534pub struct OcpmConfig {
3535 #[serde(default)]
3537 pub enabled: bool,
3538
3539 #[serde(default = "default_true")]
3541 pub generate_lifecycle_events: bool,
3542
3543 #[serde(default = "default_true")]
3545 pub include_object_relationships: bool,
3546
3547 #[serde(default = "default_true")]
3549 pub compute_variants: bool,
3550
3551 #[serde(default)]
3553 pub max_variants: usize,
3554
3555 #[serde(default)]
3557 pub p2p_process: OcpmProcessConfig,
3558
3559 #[serde(default)]
3561 pub o2c_process: OcpmProcessConfig,
3562
3563 #[serde(default)]
3565 pub output: OcpmOutputConfig,
3566}
3567
3568impl Default for OcpmConfig {
3569 fn default() -> Self {
3570 Self {
3571 enabled: false,
3572 generate_lifecycle_events: true,
3573 include_object_relationships: true,
3574 compute_variants: true,
3575 max_variants: 0,
3576 p2p_process: OcpmProcessConfig::default(),
3577 o2c_process: OcpmProcessConfig::default(),
3578 output: OcpmOutputConfig::default(),
3579 }
3580 }
3581}
3582
3583#[derive(Debug, Clone, Serialize, Deserialize)]
3585pub struct OcpmProcessConfig {
3586 #[serde(default = "default_rework_probability")]
3588 pub rework_probability: f64,
3589
3590 #[serde(default = "default_skip_probability")]
3592 pub skip_step_probability: f64,
3593
3594 #[serde(default = "default_out_of_order_probability")]
3596 pub out_of_order_probability: f64,
3597}
3598
3599fn default_rework_probability() -> f64 {
3600 0.05
3601}
3602
3603fn default_skip_probability() -> f64 {
3604 0.02
3605}
3606
3607fn default_out_of_order_probability() -> f64 {
3608 0.03
3609}
3610
3611impl Default for OcpmProcessConfig {
3612 fn default() -> Self {
3613 Self {
3614 rework_probability: default_rework_probability(),
3615 skip_step_probability: default_skip_probability(),
3616 out_of_order_probability: default_out_of_order_probability(),
3617 }
3618 }
3619}
3620
3621#[derive(Debug, Clone, Serialize, Deserialize)]
3623pub struct OcpmOutputConfig {
3624 #[serde(default = "default_true")]
3626 pub ocel_json: bool,
3627
3628 #[serde(default)]
3630 pub ocel_xml: bool,
3631
3632 #[serde(default)]
3634 pub xes: bool,
3635
3636 #[serde(default = "default_true")]
3638 pub xes_include_lifecycle: bool,
3639
3640 #[serde(default = "default_true")]
3642 pub xes_include_resources: bool,
3643
3644 #[serde(default = "default_true")]
3646 pub flattened_csv: bool,
3647
3648 #[serde(default = "default_true")]
3650 pub event_object_csv: bool,
3651
3652 #[serde(default = "default_true")]
3654 pub object_relationship_csv: bool,
3655
3656 #[serde(default = "default_true")]
3658 pub variants_csv: bool,
3659
3660 #[serde(default)]
3662 pub export_reference_models: bool,
3663}
3664
3665impl Default for OcpmOutputConfig {
3666 fn default() -> Self {
3667 Self {
3668 ocel_json: true,
3669 ocel_xml: false,
3670 xes: false,
3671 xes_include_lifecycle: true,
3672 xes_include_resources: true,
3673 flattened_csv: true,
3674 event_object_csv: true,
3675 object_relationship_csv: true,
3676 variants_csv: true,
3677 export_reference_models: false,
3678 }
3679 }
3680}
3681
3682#[derive(Debug, Clone, Serialize, Deserialize)]
3684pub struct AuditGenerationConfig {
3685 #[serde(default)]
3687 pub enabled: bool,
3688
3689 #[serde(default = "default_true")]
3691 pub generate_workpapers: bool,
3692
3693 #[serde(default)]
3695 pub engagement_types: AuditEngagementTypesConfig,
3696
3697 #[serde(default)]
3699 pub workpapers: WorkpaperConfig,
3700
3701 #[serde(default)]
3703 pub team: AuditTeamConfig,
3704
3705 #[serde(default)]
3707 pub review: ReviewWorkflowConfig,
3708}
3709
3710impl Default for AuditGenerationConfig {
3711 fn default() -> Self {
3712 Self {
3713 enabled: false,
3714 generate_workpapers: true,
3715 engagement_types: AuditEngagementTypesConfig::default(),
3716 workpapers: WorkpaperConfig::default(),
3717 team: AuditTeamConfig::default(),
3718 review: ReviewWorkflowConfig::default(),
3719 }
3720 }
3721}
3722
3723#[derive(Debug, Clone, Serialize, Deserialize)]
3725pub struct AuditEngagementTypesConfig {
3726 #[serde(default = "default_financial_audit_prob")]
3728 pub financial_statement: f64,
3729 #[serde(default = "default_sox_audit_prob")]
3731 pub sox_icfr: f64,
3732 #[serde(default = "default_integrated_audit_prob")]
3734 pub integrated: f64,
3735 #[serde(default = "default_review_prob")]
3737 pub review: f64,
3738 #[serde(default = "default_aup_prob")]
3740 pub agreed_upon_procedures: f64,
3741}
3742
3743fn default_financial_audit_prob() -> f64 {
3744 0.40
3745}
3746fn default_sox_audit_prob() -> f64 {
3747 0.20
3748}
3749fn default_integrated_audit_prob() -> f64 {
3750 0.25
3751}
3752fn default_review_prob() -> f64 {
3753 0.10
3754}
3755fn default_aup_prob() -> f64 {
3756 0.05
3757}
3758
3759impl Default for AuditEngagementTypesConfig {
3760 fn default() -> Self {
3761 Self {
3762 financial_statement: default_financial_audit_prob(),
3763 sox_icfr: default_sox_audit_prob(),
3764 integrated: default_integrated_audit_prob(),
3765 review: default_review_prob(),
3766 agreed_upon_procedures: default_aup_prob(),
3767 }
3768 }
3769}
3770
3771#[derive(Debug, Clone, Serialize, Deserialize)]
3773pub struct WorkpaperConfig {
3774 #[serde(default = "default_workpapers_per_phase")]
3776 pub average_per_phase: usize,
3777
3778 #[serde(default = "default_true")]
3780 pub include_isa_references: bool,
3781
3782 #[serde(default = "default_true")]
3784 pub include_sample_details: bool,
3785
3786 #[serde(default = "default_true")]
3788 pub include_cross_references: bool,
3789
3790 #[serde(default)]
3792 pub sampling: SamplingConfig,
3793}
3794
3795fn default_workpapers_per_phase() -> usize {
3796 5
3797}
3798
3799impl Default for WorkpaperConfig {
3800 fn default() -> Self {
3801 Self {
3802 average_per_phase: default_workpapers_per_phase(),
3803 include_isa_references: true,
3804 include_sample_details: true,
3805 include_cross_references: true,
3806 sampling: SamplingConfig::default(),
3807 }
3808 }
3809}
3810
3811#[derive(Debug, Clone, Serialize, Deserialize)]
3813pub struct SamplingConfig {
3814 #[serde(default = "default_statistical_rate")]
3816 pub statistical_rate: f64,
3817 #[serde(default = "default_judgmental_rate")]
3819 pub judgmental_rate: f64,
3820 #[serde(default = "default_haphazard_rate")]
3822 pub haphazard_rate: f64,
3823 #[serde(default = "default_complete_examination_rate")]
3825 pub complete_examination_rate: f64,
3826}
3827
3828fn default_statistical_rate() -> f64 {
3829 0.40
3830}
3831fn default_judgmental_rate() -> f64 {
3832 0.30
3833}
3834fn default_haphazard_rate() -> f64 {
3835 0.20
3836}
3837fn default_complete_examination_rate() -> f64 {
3838 0.10
3839}
3840
3841impl Default for SamplingConfig {
3842 fn default() -> Self {
3843 Self {
3844 statistical_rate: default_statistical_rate(),
3845 judgmental_rate: default_judgmental_rate(),
3846 haphazard_rate: default_haphazard_rate(),
3847 complete_examination_rate: default_complete_examination_rate(),
3848 }
3849 }
3850}
3851
3852#[derive(Debug, Clone, Serialize, Deserialize)]
3854pub struct AuditTeamConfig {
3855 #[serde(default = "default_min_team_size")]
3857 pub min_team_size: usize,
3858 #[serde(default = "default_max_team_size")]
3860 pub max_team_size: usize,
3861 #[serde(default = "default_specialist_probability")]
3863 pub specialist_probability: f64,
3864}
3865
3866fn default_min_team_size() -> usize {
3867 3
3868}
3869fn default_max_team_size() -> usize {
3870 8
3871}
3872fn default_specialist_probability() -> f64 {
3873 0.30
3874}
3875
3876impl Default for AuditTeamConfig {
3877 fn default() -> Self {
3878 Self {
3879 min_team_size: default_min_team_size(),
3880 max_team_size: default_max_team_size(),
3881 specialist_probability: default_specialist_probability(),
3882 }
3883 }
3884}
3885
3886#[derive(Debug, Clone, Serialize, Deserialize)]
3888pub struct ReviewWorkflowConfig {
3889 #[serde(default = "default_review_delay_days")]
3891 pub average_review_delay_days: u32,
3892 #[serde(default = "default_rework_probability_review")]
3894 pub rework_probability: f64,
3895 #[serde(default = "default_true")]
3897 pub require_partner_signoff: bool,
3898}
3899
3900fn default_review_delay_days() -> u32 {
3901 2
3902}
3903fn default_rework_probability_review() -> f64 {
3904 0.15
3905}
3906
3907impl Default for ReviewWorkflowConfig {
3908 fn default() -> Self {
3909 Self {
3910 average_review_delay_days: default_review_delay_days(),
3911 rework_probability: default_rework_probability_review(),
3912 require_partner_signoff: true,
3913 }
3914 }
3915}
3916
3917#[derive(Debug, Clone, Serialize, Deserialize)]
3923pub struct DataQualitySchemaConfig {
3924 #[serde(default)]
3926 pub enabled: bool,
3927 #[serde(default)]
3929 pub preset: DataQualityPreset,
3930 #[serde(default)]
3932 pub missing_values: MissingValuesSchemaConfig,
3933 #[serde(default)]
3935 pub typos: TypoSchemaConfig,
3936 #[serde(default)]
3938 pub format_variations: FormatVariationSchemaConfig,
3939 #[serde(default)]
3941 pub duplicates: DuplicateSchemaConfig,
3942 #[serde(default)]
3944 pub encoding_issues: EncodingIssueSchemaConfig,
3945 #[serde(default)]
3947 pub generate_labels: bool,
3948 #[serde(default)]
3950 pub sink_profiles: SinkQualityProfiles,
3951}
3952
3953impl Default for DataQualitySchemaConfig {
3954 fn default() -> Self {
3955 Self {
3956 enabled: false,
3957 preset: DataQualityPreset::None,
3958 missing_values: MissingValuesSchemaConfig::default(),
3959 typos: TypoSchemaConfig::default(),
3960 format_variations: FormatVariationSchemaConfig::default(),
3961 duplicates: DuplicateSchemaConfig::default(),
3962 encoding_issues: EncodingIssueSchemaConfig::default(),
3963 generate_labels: true,
3964 sink_profiles: SinkQualityProfiles::default(),
3965 }
3966 }
3967}
3968
3969impl DataQualitySchemaConfig {
3970 pub fn with_preset(preset: DataQualityPreset) -> Self {
3972 let mut config = Self {
3973 preset,
3974 ..Default::default()
3975 };
3976 config.apply_preset();
3977 config
3978 }
3979
3980 pub fn apply_preset(&mut self) {
3983 if !self.preset.overrides_settings() {
3984 return;
3985 }
3986
3987 self.enabled = true;
3988
3989 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3991 self.missing_values.rate = self.preset.missing_rate();
3992
3993 self.typos.enabled = self.preset.typo_rate() > 0.0;
3995 self.typos.char_error_rate = self.preset.typo_rate();
3996
3997 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3999 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4000 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4001 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4002
4003 self.format_variations.enabled = self.preset.format_variations_enabled();
4005
4006 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4008 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4009
4010 if self.preset.ocr_errors_enabled() {
4012 self.typos.type_weights.ocr_errors = 0.3;
4013 }
4014 }
4015
4016 pub fn effective_missing_rate(&self) -> f64 {
4018 if self.preset.overrides_settings() {
4019 self.preset.missing_rate()
4020 } else {
4021 self.missing_values.rate
4022 }
4023 }
4024
4025 pub fn effective_typo_rate(&self) -> f64 {
4027 if self.preset.overrides_settings() {
4028 self.preset.typo_rate()
4029 } else {
4030 self.typos.char_error_rate
4031 }
4032 }
4033
4034 pub fn effective_duplicate_rate(&self) -> f64 {
4036 if self.preset.overrides_settings() {
4037 self.preset.duplicate_rate()
4038 } else {
4039 self.duplicates.exact_duplicate_ratio
4040 + self.duplicates.near_duplicate_ratio
4041 + self.duplicates.fuzzy_duplicate_ratio
4042 }
4043 }
4044
4045 pub fn clean() -> Self {
4047 Self::with_preset(DataQualityPreset::Clean)
4048 }
4049
4050 pub fn noisy() -> Self {
4052 Self::with_preset(DataQualityPreset::Noisy)
4053 }
4054
4055 pub fn legacy() -> Self {
4057 Self::with_preset(DataQualityPreset::Legacy)
4058 }
4059}
4060
4061#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4063#[serde(rename_all = "snake_case")]
4064pub enum DataQualityPreset {
4065 #[default]
4067 None,
4068 Minimal,
4070 Normal,
4072 High,
4074 Custom,
4076
4077 Clean,
4083 Noisy,
4086 Legacy,
4089}
4090
4091impl DataQualityPreset {
4092 pub fn missing_rate(&self) -> f64 {
4094 match self {
4095 DataQualityPreset::None => 0.0,
4096 DataQualityPreset::Minimal => 0.005,
4097 DataQualityPreset::Normal => 0.02,
4098 DataQualityPreset::High => 0.08,
4099 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4101 DataQualityPreset::Noisy => 0.05,
4102 DataQualityPreset::Legacy => 0.10,
4103 }
4104 }
4105
4106 pub fn typo_rate(&self) -> f64 {
4108 match self {
4109 DataQualityPreset::None => 0.0,
4110 DataQualityPreset::Minimal => 0.0005,
4111 DataQualityPreset::Normal => 0.002,
4112 DataQualityPreset::High => 0.01,
4113 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4115 DataQualityPreset::Noisy => 0.02,
4116 DataQualityPreset::Legacy => 0.05,
4117 }
4118 }
4119
4120 pub fn duplicate_rate(&self) -> f64 {
4122 match self {
4123 DataQualityPreset::None => 0.0,
4124 DataQualityPreset::Minimal => 0.001,
4125 DataQualityPreset::Normal => 0.005,
4126 DataQualityPreset::High => 0.02,
4127 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4129 DataQualityPreset::Noisy => 0.01,
4130 DataQualityPreset::Legacy => 0.03,
4131 }
4132 }
4133
4134 pub fn format_variations_enabled(&self) -> bool {
4136 match self {
4137 DataQualityPreset::None | DataQualityPreset::Clean => false,
4138 DataQualityPreset::Minimal => true,
4139 DataQualityPreset::Normal => true,
4140 DataQualityPreset::High => true,
4141 DataQualityPreset::Custom => true,
4142 DataQualityPreset::Noisy => true,
4143 DataQualityPreset::Legacy => true,
4144 }
4145 }
4146
4147 pub fn ocr_errors_enabled(&self) -> bool {
4149 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4150 }
4151
4152 pub fn encoding_issues_enabled(&self) -> bool {
4154 matches!(
4155 self,
4156 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4157 )
4158 }
4159
4160 pub fn encoding_issue_rate(&self) -> f64 {
4162 match self {
4163 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4164 DataQualityPreset::Normal => 0.002,
4165 DataQualityPreset::High => 0.01,
4166 DataQualityPreset::Custom => 0.0,
4167 DataQualityPreset::Noisy => 0.005,
4168 DataQualityPreset::Legacy => 0.02,
4169 }
4170 }
4171
4172 pub fn overrides_settings(&self) -> bool {
4174 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4175 }
4176
4177 pub fn description(&self) -> &'static str {
4179 match self {
4180 DataQualityPreset::None => "No data quality issues (pristine data)",
4181 DataQualityPreset::Minimal => "Very rare data quality issues",
4182 DataQualityPreset::Normal => "Realistic enterprise data quality",
4183 DataQualityPreset::High => "Messy data for stress testing",
4184 DataQualityPreset::Custom => "Custom settings from configuration",
4185 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4186 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4187 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4188 }
4189 }
4190}
4191
4192#[derive(Debug, Clone, Serialize, Deserialize)]
4194pub struct MissingValuesSchemaConfig {
4195 #[serde(default)]
4197 pub enabled: bool,
4198 #[serde(default = "default_missing_rate")]
4200 pub rate: f64,
4201 #[serde(default)]
4203 pub strategy: MissingValueStrategy,
4204 #[serde(default)]
4206 pub field_rates: std::collections::HashMap<String, f64>,
4207 #[serde(default)]
4209 pub protected_fields: Vec<String>,
4210}
4211
4212fn default_missing_rate() -> f64 {
4213 0.01
4214}
4215
4216impl Default for MissingValuesSchemaConfig {
4217 fn default() -> Self {
4218 Self {
4219 enabled: false,
4220 rate: default_missing_rate(),
4221 strategy: MissingValueStrategy::Mcar,
4222 field_rates: std::collections::HashMap::new(),
4223 protected_fields: vec![
4224 "document_id".to_string(),
4225 "company_code".to_string(),
4226 "posting_date".to_string(),
4227 ],
4228 }
4229 }
4230}
4231
4232#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4234#[serde(rename_all = "snake_case")]
4235pub enum MissingValueStrategy {
4236 #[default]
4238 Mcar,
4239 Mar,
4241 Mnar,
4243 Systematic,
4245}
4246
4247#[derive(Debug, Clone, Serialize, Deserialize)]
4249pub struct TypoSchemaConfig {
4250 #[serde(default)]
4252 pub enabled: bool,
4253 #[serde(default = "default_typo_rate")]
4255 pub char_error_rate: f64,
4256 #[serde(default)]
4258 pub type_weights: TypoTypeWeights,
4259 #[serde(default)]
4261 pub protected_fields: Vec<String>,
4262}
4263
4264fn default_typo_rate() -> f64 {
4265 0.001
4266}
4267
4268impl Default for TypoSchemaConfig {
4269 fn default() -> Self {
4270 Self {
4271 enabled: false,
4272 char_error_rate: default_typo_rate(),
4273 type_weights: TypoTypeWeights::default(),
4274 protected_fields: vec![
4275 "document_id".to_string(),
4276 "gl_account".to_string(),
4277 "company_code".to_string(),
4278 ],
4279 }
4280 }
4281}
4282
4283#[derive(Debug, Clone, Serialize, Deserialize)]
4285pub struct TypoTypeWeights {
4286 #[serde(default = "default_substitution_weight")]
4288 pub substitution: f64,
4289 #[serde(default = "default_transposition_weight")]
4291 pub transposition: f64,
4292 #[serde(default = "default_insertion_weight")]
4294 pub insertion: f64,
4295 #[serde(default = "default_deletion_weight")]
4297 pub deletion: f64,
4298 #[serde(default = "default_ocr_weight")]
4300 pub ocr_errors: f64,
4301 #[serde(default = "default_homophone_weight")]
4303 pub homophones: f64,
4304}
4305
4306fn default_substitution_weight() -> f64 {
4307 0.35
4308}
4309fn default_transposition_weight() -> f64 {
4310 0.25
4311}
4312fn default_insertion_weight() -> f64 {
4313 0.10
4314}
4315fn default_deletion_weight() -> f64 {
4316 0.15
4317}
4318fn default_ocr_weight() -> f64 {
4319 0.10
4320}
4321fn default_homophone_weight() -> f64 {
4322 0.05
4323}
4324
4325impl Default for TypoTypeWeights {
4326 fn default() -> Self {
4327 Self {
4328 substitution: default_substitution_weight(),
4329 transposition: default_transposition_weight(),
4330 insertion: default_insertion_weight(),
4331 deletion: default_deletion_weight(),
4332 ocr_errors: default_ocr_weight(),
4333 homophones: default_homophone_weight(),
4334 }
4335 }
4336}
4337
4338#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4340pub struct FormatVariationSchemaConfig {
4341 #[serde(default)]
4343 pub enabled: bool,
4344 #[serde(default)]
4346 pub dates: DateFormatVariationConfig,
4347 #[serde(default)]
4349 pub amounts: AmountFormatVariationConfig,
4350 #[serde(default)]
4352 pub identifiers: IdentifierFormatVariationConfig,
4353}
4354
4355#[derive(Debug, Clone, Serialize, Deserialize)]
4357pub struct DateFormatVariationConfig {
4358 #[serde(default)]
4360 pub enabled: bool,
4361 #[serde(default = "default_date_variation_rate")]
4363 pub rate: f64,
4364 #[serde(default = "default_true")]
4366 pub iso_format: bool,
4367 #[serde(default)]
4369 pub us_format: bool,
4370 #[serde(default)]
4372 pub eu_format: bool,
4373 #[serde(default)]
4375 pub long_format: bool,
4376}
4377
4378fn default_date_variation_rate() -> f64 {
4379 0.05
4380}
4381
4382impl Default for DateFormatVariationConfig {
4383 fn default() -> Self {
4384 Self {
4385 enabled: false,
4386 rate: default_date_variation_rate(),
4387 iso_format: true,
4388 us_format: false,
4389 eu_format: false,
4390 long_format: false,
4391 }
4392 }
4393}
4394
4395#[derive(Debug, Clone, Serialize, Deserialize)]
4397pub struct AmountFormatVariationConfig {
4398 #[serde(default)]
4400 pub enabled: bool,
4401 #[serde(default = "default_amount_variation_rate")]
4403 pub rate: f64,
4404 #[serde(default)]
4406 pub us_comma_format: bool,
4407 #[serde(default)]
4409 pub eu_format: bool,
4410 #[serde(default)]
4412 pub currency_prefix: bool,
4413 #[serde(default)]
4415 pub accounting_format: bool,
4416}
4417
4418fn default_amount_variation_rate() -> f64 {
4419 0.02
4420}
4421
4422impl Default for AmountFormatVariationConfig {
4423 fn default() -> Self {
4424 Self {
4425 enabled: false,
4426 rate: default_amount_variation_rate(),
4427 us_comma_format: false,
4428 eu_format: false,
4429 currency_prefix: false,
4430 accounting_format: false,
4431 }
4432 }
4433}
4434
4435#[derive(Debug, Clone, Serialize, Deserialize)]
4437pub struct IdentifierFormatVariationConfig {
4438 #[serde(default)]
4440 pub enabled: bool,
4441 #[serde(default = "default_identifier_variation_rate")]
4443 pub rate: f64,
4444 #[serde(default)]
4446 pub case_variations: bool,
4447 #[serde(default)]
4449 pub padding_variations: bool,
4450 #[serde(default)]
4452 pub separator_variations: bool,
4453}
4454
4455fn default_identifier_variation_rate() -> f64 {
4456 0.02
4457}
4458
4459impl Default for IdentifierFormatVariationConfig {
4460 fn default() -> Self {
4461 Self {
4462 enabled: false,
4463 rate: default_identifier_variation_rate(),
4464 case_variations: false,
4465 padding_variations: false,
4466 separator_variations: false,
4467 }
4468 }
4469}
4470
4471#[derive(Debug, Clone, Serialize, Deserialize)]
4473pub struct DuplicateSchemaConfig {
4474 #[serde(default)]
4476 pub enabled: bool,
4477 #[serde(default = "default_duplicate_rate")]
4479 pub rate: f64,
4480 #[serde(default = "default_exact_duplicate_ratio")]
4482 pub exact_duplicate_ratio: f64,
4483 #[serde(default = "default_near_duplicate_ratio")]
4485 pub near_duplicate_ratio: f64,
4486 #[serde(default = "default_fuzzy_duplicate_ratio")]
4488 pub fuzzy_duplicate_ratio: f64,
4489 #[serde(default = "default_max_date_offset")]
4491 pub max_date_offset_days: u32,
4492 #[serde(default = "default_max_amount_variance")]
4494 pub max_amount_variance: f64,
4495}
4496
4497fn default_duplicate_rate() -> f64 {
4498 0.005
4499}
4500fn default_exact_duplicate_ratio() -> f64 {
4501 0.4
4502}
4503fn default_near_duplicate_ratio() -> f64 {
4504 0.35
4505}
4506fn default_fuzzy_duplicate_ratio() -> f64 {
4507 0.25
4508}
4509fn default_max_date_offset() -> u32 {
4510 3
4511}
4512fn default_max_amount_variance() -> f64 {
4513 0.01
4514}
4515
4516impl Default for DuplicateSchemaConfig {
4517 fn default() -> Self {
4518 Self {
4519 enabled: false,
4520 rate: default_duplicate_rate(),
4521 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4522 near_duplicate_ratio: default_near_duplicate_ratio(),
4523 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4524 max_date_offset_days: default_max_date_offset(),
4525 max_amount_variance: default_max_amount_variance(),
4526 }
4527 }
4528}
4529
4530#[derive(Debug, Clone, Serialize, Deserialize)]
4532pub struct EncodingIssueSchemaConfig {
4533 #[serde(default)]
4535 pub enabled: bool,
4536 #[serde(default = "default_encoding_rate")]
4538 pub rate: f64,
4539 #[serde(default)]
4541 pub mojibake: bool,
4542 #[serde(default)]
4544 pub html_entities: bool,
4545 #[serde(default)]
4547 pub bom_issues: bool,
4548}
4549
4550fn default_encoding_rate() -> f64 {
4551 0.001
4552}
4553
4554impl Default for EncodingIssueSchemaConfig {
4555 fn default() -> Self {
4556 Self {
4557 enabled: false,
4558 rate: default_encoding_rate(),
4559 mojibake: false,
4560 html_entities: false,
4561 bom_issues: false,
4562 }
4563 }
4564}
4565
4566#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4568pub struct SinkQualityProfiles {
4569 #[serde(default)]
4571 pub csv: Option<SinkQualityOverride>,
4572 #[serde(default)]
4574 pub json: Option<SinkQualityOverride>,
4575 #[serde(default)]
4577 pub parquet: Option<SinkQualityOverride>,
4578}
4579
4580#[derive(Debug, Clone, Serialize, Deserialize)]
4582pub struct SinkQualityOverride {
4583 pub enabled: Option<bool>,
4585 pub missing_rate: Option<f64>,
4587 pub typo_rate: Option<f64>,
4589 pub format_variation_rate: Option<f64>,
4591 pub duplicate_rate: Option<f64>,
4593}
4594
4595#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4607pub struct AccountingStandardsConfig {
4608 #[serde(default)]
4610 pub enabled: bool,
4611
4612 #[serde(default)]
4614 pub framework: AccountingFrameworkConfig,
4615
4616 #[serde(default)]
4618 pub revenue_recognition: RevenueRecognitionConfig,
4619
4620 #[serde(default)]
4622 pub leases: LeaseAccountingConfig,
4623
4624 #[serde(default)]
4626 pub fair_value: FairValueConfig,
4627
4628 #[serde(default)]
4630 pub impairment: ImpairmentConfig,
4631
4632 #[serde(default)]
4634 pub generate_differences: bool,
4635}
4636
4637#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4639#[serde(rename_all = "snake_case")]
4640pub enum AccountingFrameworkConfig {
4641 #[default]
4643 UsGaap,
4644 Ifrs,
4646 DualReporting,
4648}
4649
4650#[derive(Debug, Clone, Serialize, Deserialize)]
4652pub struct RevenueRecognitionConfig {
4653 #[serde(default)]
4655 pub enabled: bool,
4656
4657 #[serde(default = "default_true")]
4659 pub generate_contracts: bool,
4660
4661 #[serde(default = "default_avg_obligations")]
4663 pub avg_obligations_per_contract: f64,
4664
4665 #[serde(default = "default_variable_consideration_rate")]
4667 pub variable_consideration_rate: f64,
4668
4669 #[serde(default = "default_over_time_rate")]
4671 pub over_time_recognition_rate: f64,
4672
4673 #[serde(default = "default_contract_count")]
4675 pub contract_count: usize,
4676}
4677
4678fn default_avg_obligations() -> f64 {
4679 2.0
4680}
4681
4682fn default_variable_consideration_rate() -> f64 {
4683 0.15
4684}
4685
4686fn default_over_time_rate() -> f64 {
4687 0.30
4688}
4689
4690fn default_contract_count() -> usize {
4691 100
4692}
4693
4694impl Default for RevenueRecognitionConfig {
4695 fn default() -> Self {
4696 Self {
4697 enabled: false,
4698 generate_contracts: true,
4699 avg_obligations_per_contract: default_avg_obligations(),
4700 variable_consideration_rate: default_variable_consideration_rate(),
4701 over_time_recognition_rate: default_over_time_rate(),
4702 contract_count: default_contract_count(),
4703 }
4704 }
4705}
4706
4707#[derive(Debug, Clone, Serialize, Deserialize)]
4709pub struct LeaseAccountingConfig {
4710 #[serde(default)]
4712 pub enabled: bool,
4713
4714 #[serde(default = "default_lease_count")]
4716 pub lease_count: usize,
4717
4718 #[serde(default = "default_finance_lease_pct")]
4720 pub finance_lease_percent: f64,
4721
4722 #[serde(default = "default_avg_lease_term")]
4724 pub avg_lease_term_months: u32,
4725
4726 #[serde(default = "default_true")]
4728 pub generate_amortization: bool,
4729
4730 #[serde(default = "default_real_estate_pct")]
4732 pub real_estate_percent: f64,
4733}
4734
4735fn default_lease_count() -> usize {
4736 50
4737}
4738
4739fn default_finance_lease_pct() -> f64 {
4740 0.30
4741}
4742
4743fn default_avg_lease_term() -> u32 {
4744 60
4745}
4746
4747fn default_real_estate_pct() -> f64 {
4748 0.40
4749}
4750
4751impl Default for LeaseAccountingConfig {
4752 fn default() -> Self {
4753 Self {
4754 enabled: false,
4755 lease_count: default_lease_count(),
4756 finance_lease_percent: default_finance_lease_pct(),
4757 avg_lease_term_months: default_avg_lease_term(),
4758 generate_amortization: true,
4759 real_estate_percent: default_real_estate_pct(),
4760 }
4761 }
4762}
4763
4764#[derive(Debug, Clone, Serialize, Deserialize)]
4766pub struct FairValueConfig {
4767 #[serde(default)]
4769 pub enabled: bool,
4770
4771 #[serde(default = "default_fv_count")]
4773 pub measurement_count: usize,
4774
4775 #[serde(default = "default_level1_pct")]
4777 pub level1_percent: f64,
4778
4779 #[serde(default = "default_level2_pct")]
4781 pub level2_percent: f64,
4782
4783 #[serde(default = "default_level3_pct")]
4785 pub level3_percent: f64,
4786
4787 #[serde(default)]
4789 pub include_sensitivity_analysis: bool,
4790}
4791
4792fn default_fv_count() -> usize {
4793 25
4794}
4795
4796fn default_level1_pct() -> f64 {
4797 0.40
4798}
4799
4800fn default_level2_pct() -> f64 {
4801 0.35
4802}
4803
4804fn default_level3_pct() -> f64 {
4805 0.25
4806}
4807
4808impl Default for FairValueConfig {
4809 fn default() -> Self {
4810 Self {
4811 enabled: false,
4812 measurement_count: default_fv_count(),
4813 level1_percent: default_level1_pct(),
4814 level2_percent: default_level2_pct(),
4815 level3_percent: default_level3_pct(),
4816 include_sensitivity_analysis: false,
4817 }
4818 }
4819}
4820
4821#[derive(Debug, Clone, Serialize, Deserialize)]
4823pub struct ImpairmentConfig {
4824 #[serde(default)]
4826 pub enabled: bool,
4827
4828 #[serde(default = "default_impairment_count")]
4830 pub test_count: usize,
4831
4832 #[serde(default = "default_impairment_rate")]
4834 pub impairment_rate: f64,
4835
4836 #[serde(default = "default_true")]
4838 pub generate_projections: bool,
4839
4840 #[serde(default)]
4842 pub include_goodwill: bool,
4843}
4844
4845fn default_impairment_count() -> usize {
4846 15
4847}
4848
4849fn default_impairment_rate() -> f64 {
4850 0.10
4851}
4852
4853impl Default for ImpairmentConfig {
4854 fn default() -> Self {
4855 Self {
4856 enabled: false,
4857 test_count: default_impairment_count(),
4858 impairment_rate: default_impairment_rate(),
4859 generate_projections: true,
4860 include_goodwill: false,
4861 }
4862 }
4863}
4864
4865#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4878pub struct AuditStandardsConfig {
4879 #[serde(default)]
4881 pub enabled: bool,
4882
4883 #[serde(default)]
4885 pub isa_compliance: IsaComplianceConfig,
4886
4887 #[serde(default)]
4889 pub analytical_procedures: AnalyticalProceduresConfig,
4890
4891 #[serde(default)]
4893 pub confirmations: ConfirmationsConfig,
4894
4895 #[serde(default)]
4897 pub opinion: AuditOpinionConfig,
4898
4899 #[serde(default)]
4901 pub generate_audit_trail: bool,
4902
4903 #[serde(default)]
4905 pub sox: SoxComplianceConfig,
4906
4907 #[serde(default)]
4909 pub pcaob: PcaobConfig,
4910}
4911
4912#[derive(Debug, Clone, Serialize, Deserialize)]
4914pub struct IsaComplianceConfig {
4915 #[serde(default)]
4917 pub enabled: bool,
4918
4919 #[serde(default = "default_compliance_level")]
4921 pub compliance_level: String,
4922
4923 #[serde(default = "default_true")]
4925 pub generate_isa_mappings: bool,
4926
4927 #[serde(default = "default_true")]
4929 pub generate_coverage_summary: bool,
4930
4931 #[serde(default)]
4933 pub include_pcaob: bool,
4934
4935 #[serde(default = "default_audit_framework")]
4937 pub framework: String,
4938}
4939
4940fn default_compliance_level() -> String {
4941 "standard".to_string()
4942}
4943
4944fn default_audit_framework() -> String {
4945 "isa".to_string()
4946}
4947
4948impl Default for IsaComplianceConfig {
4949 fn default() -> Self {
4950 Self {
4951 enabled: false,
4952 compliance_level: default_compliance_level(),
4953 generate_isa_mappings: true,
4954 generate_coverage_summary: true,
4955 include_pcaob: false,
4956 framework: default_audit_framework(),
4957 }
4958 }
4959}
4960
4961#[derive(Debug, Clone, Serialize, Deserialize)]
4963pub struct AnalyticalProceduresConfig {
4964 #[serde(default)]
4966 pub enabled: bool,
4967
4968 #[serde(default = "default_procedures_per_account")]
4970 pub procedures_per_account: usize,
4971
4972 #[serde(default = "default_variance_probability")]
4974 pub variance_probability: f64,
4975
4976 #[serde(default = "default_true")]
4978 pub generate_investigations: bool,
4979
4980 #[serde(default = "default_true")]
4982 pub include_ratio_analysis: bool,
4983}
4984
4985fn default_procedures_per_account() -> usize {
4986 3
4987}
4988
4989fn default_variance_probability() -> f64 {
4990 0.20
4991}
4992
4993impl Default for AnalyticalProceduresConfig {
4994 fn default() -> Self {
4995 Self {
4996 enabled: false,
4997 procedures_per_account: default_procedures_per_account(),
4998 variance_probability: default_variance_probability(),
4999 generate_investigations: true,
5000 include_ratio_analysis: true,
5001 }
5002 }
5003}
5004
5005#[derive(Debug, Clone, Serialize, Deserialize)]
5007pub struct ConfirmationsConfig {
5008 #[serde(default)]
5010 pub enabled: bool,
5011
5012 #[serde(default = "default_confirmation_count")]
5014 pub confirmation_count: usize,
5015
5016 #[serde(default = "default_positive_response_rate")]
5018 pub positive_response_rate: f64,
5019
5020 #[serde(default = "default_exception_rate_confirm")]
5022 pub exception_rate: f64,
5023
5024 #[serde(default = "default_non_response_rate")]
5026 pub non_response_rate: f64,
5027
5028 #[serde(default = "default_true")]
5030 pub generate_alternative_procedures: bool,
5031}
5032
5033fn default_confirmation_count() -> usize {
5034 50
5035}
5036
5037fn default_positive_response_rate() -> f64 {
5038 0.85
5039}
5040
5041fn default_exception_rate_confirm() -> f64 {
5042 0.10
5043}
5044
5045fn default_non_response_rate() -> f64 {
5046 0.05
5047}
5048
5049impl Default for ConfirmationsConfig {
5050 fn default() -> Self {
5051 Self {
5052 enabled: false,
5053 confirmation_count: default_confirmation_count(),
5054 positive_response_rate: default_positive_response_rate(),
5055 exception_rate: default_exception_rate_confirm(),
5056 non_response_rate: default_non_response_rate(),
5057 generate_alternative_procedures: true,
5058 }
5059 }
5060}
5061
5062#[derive(Debug, Clone, Serialize, Deserialize)]
5064pub struct AuditOpinionConfig {
5065 #[serde(default)]
5067 pub enabled: bool,
5068
5069 #[serde(default = "default_true")]
5071 pub generate_kam: bool,
5072
5073 #[serde(default = "default_kam_count")]
5075 pub average_kam_count: usize,
5076
5077 #[serde(default = "default_modified_opinion_rate")]
5079 pub modified_opinion_rate: f64,
5080
5081 #[serde(default)]
5083 pub include_emphasis_of_matter: bool,
5084
5085 #[serde(default = "default_true")]
5087 pub include_going_concern: bool,
5088}
5089
5090fn default_kam_count() -> usize {
5091 3
5092}
5093
5094fn default_modified_opinion_rate() -> f64 {
5095 0.05
5096}
5097
5098impl Default for AuditOpinionConfig {
5099 fn default() -> Self {
5100 Self {
5101 enabled: false,
5102 generate_kam: true,
5103 average_kam_count: default_kam_count(),
5104 modified_opinion_rate: default_modified_opinion_rate(),
5105 include_emphasis_of_matter: false,
5106 include_going_concern: true,
5107 }
5108 }
5109}
5110
5111#[derive(Debug, Clone, Serialize, Deserialize)]
5113pub struct SoxComplianceConfig {
5114 #[serde(default)]
5116 pub enabled: bool,
5117
5118 #[serde(default = "default_true")]
5120 pub generate_302_certifications: bool,
5121
5122 #[serde(default = "default_true")]
5124 pub generate_404_assessments: bool,
5125
5126 #[serde(default = "default_sox_materiality_threshold")]
5128 pub materiality_threshold: f64,
5129
5130 #[serde(default = "default_material_weakness_rate")]
5132 pub material_weakness_rate: f64,
5133
5134 #[serde(default = "default_significant_deficiency_rate")]
5136 pub significant_deficiency_rate: f64,
5137}
5138
5139fn default_material_weakness_rate() -> f64 {
5140 0.02
5141}
5142
5143fn default_significant_deficiency_rate() -> f64 {
5144 0.08
5145}
5146
5147impl Default for SoxComplianceConfig {
5148 fn default() -> Self {
5149 Self {
5150 enabled: false,
5151 generate_302_certifications: true,
5152 generate_404_assessments: true,
5153 materiality_threshold: default_sox_materiality_threshold(),
5154 material_weakness_rate: default_material_weakness_rate(),
5155 significant_deficiency_rate: default_significant_deficiency_rate(),
5156 }
5157 }
5158}
5159
5160#[derive(Debug, Clone, Serialize, Deserialize)]
5162pub struct PcaobConfig {
5163 #[serde(default)]
5165 pub enabled: bool,
5166
5167 #[serde(default)]
5169 pub is_pcaob_audit: bool,
5170
5171 #[serde(default = "default_true")]
5173 pub generate_cam: bool,
5174
5175 #[serde(default)]
5177 pub include_icfr_opinion: bool,
5178
5179 #[serde(default)]
5181 pub generate_standard_mappings: bool,
5182}
5183
5184impl Default for PcaobConfig {
5185 fn default() -> Self {
5186 Self {
5187 enabled: false,
5188 is_pcaob_audit: false,
5189 generate_cam: true,
5190 include_icfr_opinion: false,
5191 generate_standard_mappings: false,
5192 }
5193 }
5194}
5195
5196#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5209pub struct AdvancedDistributionConfig {
5210 #[serde(default)]
5212 pub enabled: bool,
5213
5214 #[serde(default)]
5216 pub amounts: MixtureDistributionSchemaConfig,
5217
5218 #[serde(default)]
5220 pub correlations: CorrelationSchemaConfig,
5221
5222 #[serde(default)]
5224 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5225
5226 #[serde(default)]
5228 pub regime_changes: RegimeChangeSchemaConfig,
5229
5230 #[serde(default)]
5232 pub industry_profile: Option<IndustryProfileType>,
5233
5234 #[serde(default)]
5236 pub validation: StatisticalValidationSchemaConfig,
5237}
5238
5239#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5241#[serde(rename_all = "snake_case")]
5242pub enum IndustryProfileType {
5243 Retail,
5245 Manufacturing,
5247 FinancialServices,
5249 Healthcare,
5251 Technology,
5253}
5254
5255#[derive(Debug, Clone, Serialize, Deserialize)]
5257pub struct MixtureDistributionSchemaConfig {
5258 #[serde(default)]
5260 pub enabled: bool,
5261
5262 #[serde(default = "default_mixture_type")]
5264 pub distribution_type: MixtureDistributionType,
5265
5266 #[serde(default)]
5268 pub components: Vec<MixtureComponentConfig>,
5269
5270 #[serde(default = "default_min_amount")]
5272 pub min_value: f64,
5273
5274 #[serde(default)]
5276 pub max_value: Option<f64>,
5277
5278 #[serde(default = "default_decimal_places")]
5280 pub decimal_places: u8,
5281}
5282
5283fn default_mixture_type() -> MixtureDistributionType {
5284 MixtureDistributionType::LogNormal
5285}
5286
5287fn default_min_amount() -> f64 {
5288 0.01
5289}
5290
5291fn default_decimal_places() -> u8 {
5292 2
5293}
5294
5295impl Default for MixtureDistributionSchemaConfig {
5296 fn default() -> Self {
5297 Self {
5298 enabled: false,
5299 distribution_type: MixtureDistributionType::LogNormal,
5300 components: Vec::new(),
5301 min_value: 0.01,
5302 max_value: None,
5303 decimal_places: 2,
5304 }
5305 }
5306}
5307
5308#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5310#[serde(rename_all = "snake_case")]
5311pub enum MixtureDistributionType {
5312 Gaussian,
5314 #[default]
5316 LogNormal,
5317}
5318
5319#[derive(Debug, Clone, Serialize, Deserialize)]
5321pub struct MixtureComponentConfig {
5322 pub weight: f64,
5324
5325 pub mu: f64,
5327
5328 pub sigma: f64,
5330
5331 #[serde(default)]
5333 pub label: Option<String>,
5334}
5335
5336#[derive(Debug, Clone, Serialize, Deserialize)]
5338pub struct CorrelationSchemaConfig {
5339 #[serde(default)]
5341 pub enabled: bool,
5342
5343 #[serde(default)]
5345 pub copula_type: CopulaSchemaType,
5346
5347 #[serde(default)]
5349 pub fields: Vec<CorrelatedFieldConfig>,
5350
5351 #[serde(default)]
5354 pub matrix: Vec<f64>,
5355
5356 #[serde(default)]
5358 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5359}
5360
5361impl Default for CorrelationSchemaConfig {
5362 fn default() -> Self {
5363 Self {
5364 enabled: false,
5365 copula_type: CopulaSchemaType::Gaussian,
5366 fields: Vec::new(),
5367 matrix: Vec::new(),
5368 expected_correlations: Vec::new(),
5369 }
5370 }
5371}
5372
5373#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5375#[serde(rename_all = "snake_case")]
5376pub enum CopulaSchemaType {
5377 #[default]
5379 Gaussian,
5380 Clayton,
5382 Gumbel,
5384 Frank,
5386 StudentT,
5388}
5389
5390#[derive(Debug, Clone, Serialize, Deserialize)]
5392pub struct CorrelatedFieldConfig {
5393 pub name: String,
5395
5396 #[serde(default)]
5398 pub distribution: MarginalDistributionConfig,
5399}
5400
5401#[derive(Debug, Clone, Serialize, Deserialize)]
5403#[serde(tag = "type", rename_all = "snake_case")]
5404pub enum MarginalDistributionConfig {
5405 Normal {
5407 mu: f64,
5409 sigma: f64,
5411 },
5412 LogNormal {
5414 mu: f64,
5416 sigma: f64,
5418 },
5419 Uniform {
5421 min: f64,
5423 max: f64,
5425 },
5426 DiscreteUniform {
5428 min: i32,
5430 max: i32,
5432 },
5433}
5434
5435impl Default for MarginalDistributionConfig {
5436 fn default() -> Self {
5437 Self::Normal {
5438 mu: 0.0,
5439 sigma: 1.0,
5440 }
5441 }
5442}
5443
5444#[derive(Debug, Clone, Serialize, Deserialize)]
5446pub struct ExpectedCorrelationConfig {
5447 pub field1: String,
5449 pub field2: String,
5451 pub expected_r: f64,
5453 #[serde(default = "default_correlation_tolerance")]
5455 pub tolerance: f64,
5456}
5457
5458fn default_correlation_tolerance() -> f64 {
5459 0.10
5460}
5461
5462#[derive(Debug, Clone, Serialize, Deserialize)]
5464pub struct ConditionalDistributionSchemaConfig {
5465 pub output_field: String,
5467
5468 pub input_field: String,
5470
5471 #[serde(default)]
5473 pub breakpoints: Vec<ConditionalBreakpointConfig>,
5474
5475 #[serde(default)]
5477 pub default_distribution: ConditionalDistributionParamsConfig,
5478
5479 #[serde(default)]
5481 pub min_value: Option<f64>,
5482
5483 #[serde(default)]
5485 pub max_value: Option<f64>,
5486
5487 #[serde(default = "default_decimal_places")]
5489 pub decimal_places: u8,
5490}
5491
5492#[derive(Debug, Clone, Serialize, Deserialize)]
5494pub struct ConditionalBreakpointConfig {
5495 pub threshold: f64,
5497
5498 pub distribution: ConditionalDistributionParamsConfig,
5500}
5501
5502#[derive(Debug, Clone, Serialize, Deserialize)]
5504#[serde(tag = "type", rename_all = "snake_case")]
5505pub enum ConditionalDistributionParamsConfig {
5506 Fixed {
5508 value: f64,
5510 },
5511 Normal {
5513 mu: f64,
5515 sigma: f64,
5517 },
5518 LogNormal {
5520 mu: f64,
5522 sigma: f64,
5524 },
5525 Uniform {
5527 min: f64,
5529 max: f64,
5531 },
5532 Beta {
5534 alpha: f64,
5536 beta: f64,
5538 min: f64,
5540 max: f64,
5542 },
5543 Discrete {
5545 values: Vec<f64>,
5547 weights: Vec<f64>,
5549 },
5550}
5551
5552impl Default for ConditionalDistributionParamsConfig {
5553 fn default() -> Self {
5554 Self::Normal {
5555 mu: 0.0,
5556 sigma: 1.0,
5557 }
5558 }
5559}
5560
5561#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5563pub struct RegimeChangeSchemaConfig {
5564 #[serde(default)]
5566 pub enabled: bool,
5567
5568 #[serde(default)]
5570 pub changes: Vec<RegimeChangeEventConfig>,
5571
5572 #[serde(default)]
5574 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5575
5576 #[serde(default)]
5578 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5579}
5580
5581#[derive(Debug, Clone, Serialize, Deserialize)]
5583pub struct RegimeChangeEventConfig {
5584 pub date: String,
5586
5587 pub change_type: RegimeChangeTypeConfig,
5589
5590 #[serde(default)]
5592 pub description: Option<String>,
5593
5594 #[serde(default)]
5596 pub effects: Vec<RegimeEffectConfig>,
5597}
5598
5599#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5601#[serde(rename_all = "snake_case")]
5602pub enum RegimeChangeTypeConfig {
5603 Acquisition,
5605 Divestiture,
5607 PriceIncrease,
5609 PriceDecrease,
5611 ProductLaunch,
5613 ProductDiscontinuation,
5615 PolicyChange,
5617 CompetitorEntry,
5619 Custom,
5621}
5622
5623#[derive(Debug, Clone, Serialize, Deserialize)]
5625pub struct RegimeEffectConfig {
5626 pub field: String,
5628
5629 pub multiplier: f64,
5631}
5632
5633#[derive(Debug, Clone, Serialize, Deserialize)]
5635pub struct EconomicCycleSchemaConfig {
5636 #[serde(default)]
5638 pub enabled: bool,
5639
5640 #[serde(default = "default_cycle_period")]
5642 pub period_months: u32,
5643
5644 #[serde(default = "default_cycle_amplitude")]
5646 pub amplitude: f64,
5647
5648 #[serde(default)]
5650 pub phase_offset: u32,
5651
5652 #[serde(default)]
5654 pub recessions: Vec<RecessionPeriodConfig>,
5655}
5656
5657fn default_cycle_period() -> u32 {
5658 48
5659}
5660
5661fn default_cycle_amplitude() -> f64 {
5662 0.15
5663}
5664
5665impl Default for EconomicCycleSchemaConfig {
5666 fn default() -> Self {
5667 Self {
5668 enabled: false,
5669 period_months: 48,
5670 amplitude: 0.15,
5671 phase_offset: 0,
5672 recessions: Vec::new(),
5673 }
5674 }
5675}
5676
5677#[derive(Debug, Clone, Serialize, Deserialize)]
5679pub struct RecessionPeriodConfig {
5680 pub start_month: u32,
5682
5683 pub duration_months: u32,
5685
5686 #[serde(default = "default_recession_severity")]
5688 pub severity: f64,
5689}
5690
5691fn default_recession_severity() -> f64 {
5692 0.20
5693}
5694
5695#[derive(Debug, Clone, Serialize, Deserialize)]
5697pub struct ParameterDriftSchemaConfig {
5698 pub parameter: String,
5700
5701 pub drift_type: ParameterDriftTypeConfig,
5703
5704 pub start_value: f64,
5706
5707 pub end_value: f64,
5709
5710 #[serde(default)]
5712 pub start_period: u32,
5713
5714 #[serde(default)]
5716 pub end_period: Option<u32>,
5717}
5718
5719#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5721#[serde(rename_all = "snake_case")]
5722pub enum ParameterDriftTypeConfig {
5723 #[default]
5725 Linear,
5726 Exponential,
5728 Logistic,
5730 Step,
5732}
5733
5734#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5736pub struct StatisticalValidationSchemaConfig {
5737 #[serde(default)]
5739 pub enabled: bool,
5740
5741 #[serde(default)]
5743 pub tests: Vec<StatisticalTestConfig>,
5744
5745 #[serde(default)]
5747 pub reporting: ValidationReportingConfig,
5748}
5749
5750#[derive(Debug, Clone, Serialize, Deserialize)]
5752#[serde(tag = "type", rename_all = "snake_case")]
5753pub enum StatisticalTestConfig {
5754 BenfordFirstDigit {
5756 #[serde(default = "default_benford_threshold")]
5758 threshold_mad: f64,
5759 #[serde(default = "default_benford_warning")]
5761 warning_mad: f64,
5762 },
5763 DistributionFit {
5765 target: TargetDistributionConfig,
5767 #[serde(default = "default_ks_significance")]
5769 ks_significance: f64,
5770 #[serde(default)]
5772 method: DistributionFitMethod,
5773 },
5774 CorrelationCheck {
5776 expected_correlations: Vec<ExpectedCorrelationConfig>,
5778 },
5779 ChiSquared {
5781 #[serde(default = "default_chi_squared_bins")]
5783 bins: usize,
5784 #[serde(default = "default_chi_squared_significance")]
5786 significance: f64,
5787 },
5788 AndersonDarling {
5790 target: TargetDistributionConfig,
5792 #[serde(default = "default_ad_significance")]
5794 significance: f64,
5795 },
5796}
5797
5798fn default_benford_threshold() -> f64 {
5799 0.015
5800}
5801
5802fn default_benford_warning() -> f64 {
5803 0.010
5804}
5805
5806fn default_ks_significance() -> f64 {
5807 0.05
5808}
5809
5810fn default_chi_squared_bins() -> usize {
5811 10
5812}
5813
5814fn default_chi_squared_significance() -> f64 {
5815 0.05
5816}
5817
5818fn default_ad_significance() -> f64 {
5819 0.05
5820}
5821
5822#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5824#[serde(rename_all = "snake_case")]
5825pub enum TargetDistributionConfig {
5826 Normal,
5828 #[default]
5830 LogNormal,
5831 Exponential,
5833 Uniform,
5835}
5836
5837#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5839#[serde(rename_all = "snake_case")]
5840pub enum DistributionFitMethod {
5841 #[default]
5843 KolmogorovSmirnov,
5844 AndersonDarling,
5846 ChiSquared,
5848}
5849
5850#[derive(Debug, Clone, Serialize, Deserialize)]
5852pub struct ValidationReportingConfig {
5853 #[serde(default)]
5855 pub output_report: bool,
5856
5857 #[serde(default)]
5859 pub format: ValidationReportFormat,
5860
5861 #[serde(default)]
5863 pub fail_on_error: bool,
5864
5865 #[serde(default = "default_true")]
5867 pub include_details: bool,
5868}
5869
5870impl Default for ValidationReportingConfig {
5871 fn default() -> Self {
5872 Self {
5873 output_report: false,
5874 format: ValidationReportFormat::Json,
5875 fail_on_error: false,
5876 include_details: true,
5877 }
5878 }
5879}
5880
5881#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5883#[serde(rename_all = "snake_case")]
5884pub enum ValidationReportFormat {
5885 #[default]
5887 Json,
5888 Yaml,
5890 Html,
5892}
5893
5894#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5906pub struct TemporalPatternsConfig {
5907 #[serde(default)]
5909 pub enabled: bool,
5910
5911 #[serde(default)]
5913 pub business_days: BusinessDaySchemaConfig,
5914
5915 #[serde(default)]
5917 pub calendars: CalendarSchemaConfig,
5918
5919 #[serde(default)]
5921 pub period_end: PeriodEndSchemaConfig,
5922
5923 #[serde(default)]
5925 pub processing_lags: ProcessingLagSchemaConfig,
5926
5927 #[serde(default)]
5929 pub fiscal_calendar: FiscalCalendarSchemaConfig,
5930
5931 #[serde(default)]
5933 pub intraday: IntraDaySchemaConfig,
5934
5935 #[serde(default)]
5937 pub timezones: TimezoneSchemaConfig,
5938}
5939
5940#[derive(Debug, Clone, Serialize, Deserialize)]
5942pub struct BusinessDaySchemaConfig {
5943 #[serde(default = "default_true")]
5945 pub enabled: bool,
5946
5947 #[serde(default = "default_half_day_policy")]
5949 pub half_day_policy: String,
5950
5951 #[serde(default)]
5953 pub settlement_rules: SettlementRulesSchemaConfig,
5954
5955 #[serde(default = "default_month_end_convention")]
5957 pub month_end_convention: String,
5958
5959 #[serde(default)]
5961 pub weekend_days: Option<Vec<String>>,
5962}
5963
5964fn default_half_day_policy() -> String {
5965 "half_day".to_string()
5966}
5967
5968fn default_month_end_convention() -> String {
5969 "modified_following".to_string()
5970}
5971
5972impl Default for BusinessDaySchemaConfig {
5973 fn default() -> Self {
5974 Self {
5975 enabled: true,
5976 half_day_policy: "half_day".to_string(),
5977 settlement_rules: SettlementRulesSchemaConfig::default(),
5978 month_end_convention: "modified_following".to_string(),
5979 weekend_days: None,
5980 }
5981 }
5982}
5983
5984#[derive(Debug, Clone, Serialize, Deserialize)]
5986pub struct SettlementRulesSchemaConfig {
5987 #[serde(default = "default_settlement_2")]
5989 pub equity_days: i32,
5990
5991 #[serde(default = "default_settlement_1")]
5993 pub government_bonds_days: i32,
5994
5995 #[serde(default = "default_settlement_2")]
5997 pub fx_spot_days: i32,
5998
5999 #[serde(default = "default_settlement_2")]
6001 pub corporate_bonds_days: i32,
6002
6003 #[serde(default = "default_wire_cutoff")]
6005 pub wire_cutoff_time: String,
6006
6007 #[serde(default = "default_settlement_1")]
6009 pub wire_international_days: i32,
6010
6011 #[serde(default = "default_settlement_1")]
6013 pub ach_days: i32,
6014}
6015
6016fn default_settlement_1() -> i32 {
6017 1
6018}
6019
6020fn default_settlement_2() -> i32 {
6021 2
6022}
6023
6024fn default_wire_cutoff() -> String {
6025 "14:00".to_string()
6026}
6027
6028impl Default for SettlementRulesSchemaConfig {
6029 fn default() -> Self {
6030 Self {
6031 equity_days: 2,
6032 government_bonds_days: 1,
6033 fx_spot_days: 2,
6034 corporate_bonds_days: 2,
6035 wire_cutoff_time: "14:00".to_string(),
6036 wire_international_days: 1,
6037 ach_days: 1,
6038 }
6039 }
6040}
6041
6042#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6044pub struct CalendarSchemaConfig {
6045 #[serde(default)]
6047 pub regions: Vec<String>,
6048
6049 #[serde(default)]
6051 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6052}
6053
6054#[derive(Debug, Clone, Serialize, Deserialize)]
6056pub struct CustomHolidaySchemaConfig {
6057 pub name: String,
6059 pub month: u8,
6061 pub day: u8,
6063 #[serde(default = "default_holiday_multiplier")]
6065 pub activity_multiplier: f64,
6066}
6067
6068fn default_holiday_multiplier() -> f64 {
6069 0.05
6070}
6071
6072#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6074pub struct PeriodEndSchemaConfig {
6075 #[serde(default)]
6077 pub model: Option<String>,
6078
6079 #[serde(default)]
6081 pub month_end: Option<PeriodEndModelSchemaConfig>,
6082
6083 #[serde(default)]
6085 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6086
6087 #[serde(default)]
6089 pub year_end: Option<PeriodEndModelSchemaConfig>,
6090}
6091
6092#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6094pub struct PeriodEndModelSchemaConfig {
6095 #[serde(default)]
6097 pub inherit_from: Option<String>,
6098
6099 #[serde(default)]
6101 pub additional_multiplier: Option<f64>,
6102
6103 #[serde(default)]
6105 pub start_day: Option<i32>,
6106
6107 #[serde(default)]
6109 pub base_multiplier: Option<f64>,
6110
6111 #[serde(default)]
6113 pub peak_multiplier: Option<f64>,
6114
6115 #[serde(default)]
6117 pub decay_rate: Option<f64>,
6118
6119 #[serde(default)]
6121 pub sustained_high_days: Option<i32>,
6122}
6123
6124#[derive(Debug, Clone, Serialize, Deserialize)]
6126pub struct ProcessingLagSchemaConfig {
6127 #[serde(default = "default_true")]
6129 pub enabled: bool,
6130
6131 #[serde(default)]
6133 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6134
6135 #[serde(default)]
6137 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6138
6139 #[serde(default)]
6141 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6142
6143 #[serde(default)]
6145 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6146
6147 #[serde(default)]
6149 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6150
6151 #[serde(default)]
6153 pub payment_lag: Option<LagDistributionSchemaConfig>,
6154
6155 #[serde(default)]
6157 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6158
6159 #[serde(default)]
6161 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6162}
6163
6164impl Default for ProcessingLagSchemaConfig {
6165 fn default() -> Self {
6166 Self {
6167 enabled: true,
6168 sales_order_lag: None,
6169 purchase_order_lag: None,
6170 goods_receipt_lag: None,
6171 invoice_receipt_lag: None,
6172 invoice_issue_lag: None,
6173 payment_lag: None,
6174 journal_entry_lag: None,
6175 cross_day_posting: None,
6176 }
6177 }
6178}
6179
6180#[derive(Debug, Clone, Serialize, Deserialize)]
6182pub struct LagDistributionSchemaConfig {
6183 pub mu: f64,
6185 pub sigma: f64,
6187 #[serde(default)]
6189 pub min_hours: Option<f64>,
6190 #[serde(default)]
6192 pub max_hours: Option<f64>,
6193}
6194
6195#[derive(Debug, Clone, Serialize, Deserialize)]
6197pub struct CrossDayPostingSchemaConfig {
6198 #[serde(default = "default_true")]
6200 pub enabled: bool,
6201
6202 #[serde(default)]
6205 pub probability_by_hour: std::collections::HashMap<u8, f64>,
6206}
6207
6208impl Default for CrossDayPostingSchemaConfig {
6209 fn default() -> Self {
6210 let mut probability_by_hour = std::collections::HashMap::new();
6211 probability_by_hour.insert(17, 0.3);
6212 probability_by_hour.insert(18, 0.6);
6213 probability_by_hour.insert(19, 0.8);
6214 probability_by_hour.insert(20, 0.9);
6215 probability_by_hour.insert(21, 0.95);
6216 probability_by_hour.insert(22, 0.99);
6217
6218 Self {
6219 enabled: true,
6220 probability_by_hour,
6221 }
6222 }
6223}
6224
6225#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6234pub struct FiscalCalendarSchemaConfig {
6235 #[serde(default)]
6237 pub enabled: bool,
6238
6239 #[serde(default = "default_fiscal_calendar_type")]
6241 pub calendar_type: String,
6242
6243 #[serde(default)]
6245 pub year_start_month: Option<u8>,
6246
6247 #[serde(default)]
6249 pub year_start_day: Option<u8>,
6250
6251 #[serde(default)]
6253 pub four_four_five: Option<FourFourFiveSchemaConfig>,
6254}
6255
6256fn default_fiscal_calendar_type() -> String {
6257 "calendar_year".to_string()
6258}
6259
6260#[derive(Debug, Clone, Serialize, Deserialize)]
6262pub struct FourFourFiveSchemaConfig {
6263 #[serde(default = "default_week_pattern")]
6265 pub pattern: String,
6266
6267 #[serde(default = "default_anchor_type")]
6269 pub anchor_type: String,
6270
6271 #[serde(default = "default_anchor_month")]
6273 pub anchor_month: u8,
6274
6275 #[serde(default = "default_leap_week_placement")]
6277 pub leap_week_placement: String,
6278}
6279
6280fn default_week_pattern() -> String {
6281 "four_four_five".to_string()
6282}
6283
6284fn default_anchor_type() -> String {
6285 "last_saturday".to_string()
6286}
6287
6288fn default_anchor_month() -> u8 {
6289 1 }
6291
6292fn default_leap_week_placement() -> String {
6293 "q4_period3".to_string()
6294}
6295
6296impl Default for FourFourFiveSchemaConfig {
6297 fn default() -> Self {
6298 Self {
6299 pattern: "four_four_five".to_string(),
6300 anchor_type: "last_saturday".to_string(),
6301 anchor_month: 1,
6302 leap_week_placement: "q4_period3".to_string(),
6303 }
6304 }
6305}
6306
6307#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6316pub struct IntraDaySchemaConfig {
6317 #[serde(default)]
6319 pub enabled: bool,
6320
6321 #[serde(default)]
6323 pub segments: Vec<IntraDaySegmentSchemaConfig>,
6324}
6325
6326#[derive(Debug, Clone, Serialize, Deserialize)]
6328pub struct IntraDaySegmentSchemaConfig {
6329 pub name: String,
6331
6332 pub start: String,
6334
6335 pub end: String,
6337
6338 #[serde(default = "default_multiplier")]
6340 pub multiplier: f64,
6341
6342 #[serde(default = "default_posting_type")]
6344 pub posting_type: String,
6345}
6346
6347fn default_multiplier() -> f64 {
6348 1.0
6349}
6350
6351fn default_posting_type() -> String {
6352 "both".to_string()
6353}
6354
6355#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6361pub struct TimezoneSchemaConfig {
6362 #[serde(default)]
6364 pub enabled: bool,
6365
6366 #[serde(default = "default_timezone")]
6368 pub default_timezone: String,
6369
6370 #[serde(default = "default_consolidation_timezone")]
6372 pub consolidation_timezone: String,
6373
6374 #[serde(default)]
6377 pub entity_mappings: Vec<EntityTimezoneMapping>,
6378}
6379
6380fn default_timezone() -> String {
6381 "America/New_York".to_string()
6382}
6383
6384fn default_consolidation_timezone() -> String {
6385 "UTC".to_string()
6386}
6387
6388#[derive(Debug, Clone, Serialize, Deserialize)]
6390pub struct EntityTimezoneMapping {
6391 pub pattern: String,
6393
6394 pub timezone: String,
6396}
6397
6398#[derive(Debug, Clone, Serialize, Deserialize)]
6404pub struct VendorNetworkSchemaConfig {
6405 #[serde(default)]
6407 pub enabled: bool,
6408
6409 #[serde(default = "default_vendor_tier_depth")]
6411 pub depth: u8,
6412
6413 #[serde(default)]
6415 pub tier1: TierCountSchemaConfig,
6416
6417 #[serde(default)]
6419 pub tier2_per_parent: TierCountSchemaConfig,
6420
6421 #[serde(default)]
6423 pub tier3_per_parent: TierCountSchemaConfig,
6424
6425 #[serde(default)]
6427 pub clusters: VendorClusterSchemaConfig,
6428
6429 #[serde(default)]
6431 pub dependencies: DependencySchemaConfig,
6432}
6433
6434fn default_vendor_tier_depth() -> u8 {
6435 3
6436}
6437
6438impl Default for VendorNetworkSchemaConfig {
6439 fn default() -> Self {
6440 Self {
6441 enabled: false,
6442 depth: 3,
6443 tier1: TierCountSchemaConfig { min: 50, max: 100 },
6444 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6445 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6446 clusters: VendorClusterSchemaConfig::default(),
6447 dependencies: DependencySchemaConfig::default(),
6448 }
6449 }
6450}
6451
6452#[derive(Debug, Clone, Serialize, Deserialize)]
6454pub struct TierCountSchemaConfig {
6455 #[serde(default = "default_tier_min")]
6457 pub min: usize,
6458
6459 #[serde(default = "default_tier_max")]
6461 pub max: usize,
6462}
6463
6464fn default_tier_min() -> usize {
6465 5
6466}
6467
6468fn default_tier_max() -> usize {
6469 20
6470}
6471
6472impl Default for TierCountSchemaConfig {
6473 fn default() -> Self {
6474 Self {
6475 min: default_tier_min(),
6476 max: default_tier_max(),
6477 }
6478 }
6479}
6480
6481#[derive(Debug, Clone, Serialize, Deserialize)]
6483pub struct VendorClusterSchemaConfig {
6484 #[serde(default = "default_reliable_strategic")]
6486 pub reliable_strategic: f64,
6487
6488 #[serde(default = "default_standard_operational")]
6490 pub standard_operational: f64,
6491
6492 #[serde(default = "default_transactional")]
6494 pub transactional: f64,
6495
6496 #[serde(default = "default_problematic")]
6498 pub problematic: f64,
6499}
6500
6501fn default_reliable_strategic() -> f64 {
6502 0.20
6503}
6504
6505fn default_standard_operational() -> f64 {
6506 0.50
6507}
6508
6509fn default_transactional() -> f64 {
6510 0.25
6511}
6512
6513fn default_problematic() -> f64 {
6514 0.05
6515}
6516
6517impl Default for VendorClusterSchemaConfig {
6518 fn default() -> Self {
6519 Self {
6520 reliable_strategic: 0.20,
6521 standard_operational: 0.50,
6522 transactional: 0.25,
6523 problematic: 0.05,
6524 }
6525 }
6526}
6527
6528#[derive(Debug, Clone, Serialize, Deserialize)]
6530pub struct DependencySchemaConfig {
6531 #[serde(default = "default_max_single_vendor")]
6533 pub max_single_vendor_concentration: f64,
6534
6535 #[serde(default = "default_max_top5")]
6537 pub top_5_concentration: f64,
6538
6539 #[serde(default = "default_single_source_percent")]
6541 pub single_source_percent: f64,
6542}
6543
6544fn default_max_single_vendor() -> f64 {
6545 0.15
6546}
6547
6548fn default_max_top5() -> f64 {
6549 0.45
6550}
6551
6552fn default_single_source_percent() -> f64 {
6553 0.05
6554}
6555
6556impl Default for DependencySchemaConfig {
6557 fn default() -> Self {
6558 Self {
6559 max_single_vendor_concentration: 0.15,
6560 top_5_concentration: 0.45,
6561 single_source_percent: 0.05,
6562 }
6563 }
6564}
6565
6566#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6572pub struct CustomerSegmentationSchemaConfig {
6573 #[serde(default)]
6575 pub enabled: bool,
6576
6577 #[serde(default)]
6579 pub value_segments: ValueSegmentsSchemaConfig,
6580
6581 #[serde(default)]
6583 pub lifecycle: LifecycleSchemaConfig,
6584
6585 #[serde(default)]
6587 pub networks: CustomerNetworksSchemaConfig,
6588}
6589
6590#[derive(Debug, Clone, Serialize, Deserialize)]
6592pub struct ValueSegmentsSchemaConfig {
6593 #[serde(default)]
6595 pub enterprise: SegmentDetailSchemaConfig,
6596
6597 #[serde(default)]
6599 pub mid_market: SegmentDetailSchemaConfig,
6600
6601 #[serde(default)]
6603 pub smb: SegmentDetailSchemaConfig,
6604
6605 #[serde(default)]
6607 pub consumer: SegmentDetailSchemaConfig,
6608}
6609
6610impl Default for ValueSegmentsSchemaConfig {
6611 fn default() -> Self {
6612 Self {
6613 enterprise: SegmentDetailSchemaConfig {
6614 revenue_share: 0.40,
6615 customer_share: 0.05,
6616 avg_order_value_range: "50000+".to_string(),
6617 },
6618 mid_market: SegmentDetailSchemaConfig {
6619 revenue_share: 0.35,
6620 customer_share: 0.20,
6621 avg_order_value_range: "5000-50000".to_string(),
6622 },
6623 smb: SegmentDetailSchemaConfig {
6624 revenue_share: 0.20,
6625 customer_share: 0.50,
6626 avg_order_value_range: "500-5000".to_string(),
6627 },
6628 consumer: SegmentDetailSchemaConfig {
6629 revenue_share: 0.05,
6630 customer_share: 0.25,
6631 avg_order_value_range: "50-500".to_string(),
6632 },
6633 }
6634 }
6635}
6636
6637#[derive(Debug, Clone, Serialize, Deserialize)]
6639pub struct SegmentDetailSchemaConfig {
6640 #[serde(default)]
6642 pub revenue_share: f64,
6643
6644 #[serde(default)]
6646 pub customer_share: f64,
6647
6648 #[serde(default)]
6650 pub avg_order_value_range: String,
6651}
6652
6653impl Default for SegmentDetailSchemaConfig {
6654 fn default() -> Self {
6655 Self {
6656 revenue_share: 0.25,
6657 customer_share: 0.25,
6658 avg_order_value_range: "1000-10000".to_string(),
6659 }
6660 }
6661}
6662
6663#[derive(Debug, Clone, Serialize, Deserialize)]
6665pub struct LifecycleSchemaConfig {
6666 #[serde(default)]
6668 pub prospect_rate: f64,
6669
6670 #[serde(default = "default_new_rate")]
6672 pub new_rate: f64,
6673
6674 #[serde(default = "default_growth_rate")]
6676 pub growth_rate: f64,
6677
6678 #[serde(default = "default_mature_rate")]
6680 pub mature_rate: f64,
6681
6682 #[serde(default = "default_at_risk_rate")]
6684 pub at_risk_rate: f64,
6685
6686 #[serde(default = "default_churned_rate")]
6688 pub churned_rate: f64,
6689}
6690
6691fn default_new_rate() -> f64 {
6692 0.10
6693}
6694
6695fn default_growth_rate() -> f64 {
6696 0.15
6697}
6698
6699fn default_mature_rate() -> f64 {
6700 0.60
6701}
6702
6703fn default_at_risk_rate() -> f64 {
6704 0.10
6705}
6706
6707fn default_churned_rate() -> f64 {
6708 0.05
6709}
6710
6711impl Default for LifecycleSchemaConfig {
6712 fn default() -> Self {
6713 Self {
6714 prospect_rate: 0.0,
6715 new_rate: 0.10,
6716 growth_rate: 0.15,
6717 mature_rate: 0.60,
6718 at_risk_rate: 0.10,
6719 churned_rate: 0.05,
6720 }
6721 }
6722}
6723
6724#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6726pub struct CustomerNetworksSchemaConfig {
6727 #[serde(default)]
6729 pub referrals: ReferralSchemaConfig,
6730
6731 #[serde(default)]
6733 pub corporate_hierarchies: HierarchySchemaConfig,
6734}
6735
6736#[derive(Debug, Clone, Serialize, Deserialize)]
6738pub struct ReferralSchemaConfig {
6739 #[serde(default = "default_true")]
6741 pub enabled: bool,
6742
6743 #[serde(default = "default_referral_rate")]
6745 pub referral_rate: f64,
6746}
6747
6748fn default_referral_rate() -> f64 {
6749 0.15
6750}
6751
6752impl Default for ReferralSchemaConfig {
6753 fn default() -> Self {
6754 Self {
6755 enabled: true,
6756 referral_rate: 0.15,
6757 }
6758 }
6759}
6760
6761#[derive(Debug, Clone, Serialize, Deserialize)]
6763pub struct HierarchySchemaConfig {
6764 #[serde(default = "default_true")]
6766 pub enabled: bool,
6767
6768 #[serde(default = "default_hierarchy_rate")]
6770 pub probability: f64,
6771}
6772
6773fn default_hierarchy_rate() -> f64 {
6774 0.30
6775}
6776
6777impl Default for HierarchySchemaConfig {
6778 fn default() -> Self {
6779 Self {
6780 enabled: true,
6781 probability: 0.30,
6782 }
6783 }
6784}
6785
6786#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6792pub struct RelationshipStrengthSchemaConfig {
6793 #[serde(default)]
6795 pub enabled: bool,
6796
6797 #[serde(default)]
6799 pub calculation: StrengthCalculationSchemaConfig,
6800
6801 #[serde(default)]
6803 pub thresholds: StrengthThresholdsSchemaConfig,
6804}
6805
6806#[derive(Debug, Clone, Serialize, Deserialize)]
6808pub struct StrengthCalculationSchemaConfig {
6809 #[serde(default = "default_volume_weight")]
6811 pub transaction_volume_weight: f64,
6812
6813 #[serde(default = "default_count_weight")]
6815 pub transaction_count_weight: f64,
6816
6817 #[serde(default = "default_duration_weight")]
6819 pub relationship_duration_weight: f64,
6820
6821 #[serde(default = "default_recency_weight")]
6823 pub recency_weight: f64,
6824
6825 #[serde(default = "default_mutual_weight")]
6827 pub mutual_connections_weight: f64,
6828
6829 #[serde(default = "default_recency_half_life")]
6831 pub recency_half_life_days: u32,
6832}
6833
6834fn default_volume_weight() -> f64 {
6835 0.30
6836}
6837
6838fn default_count_weight() -> f64 {
6839 0.25
6840}
6841
6842fn default_duration_weight() -> f64 {
6843 0.20
6844}
6845
6846fn default_recency_weight() -> f64 {
6847 0.15
6848}
6849
6850fn default_mutual_weight() -> f64 {
6851 0.10
6852}
6853
6854fn default_recency_half_life() -> u32 {
6855 90
6856}
6857
6858impl Default for StrengthCalculationSchemaConfig {
6859 fn default() -> Self {
6860 Self {
6861 transaction_volume_weight: 0.30,
6862 transaction_count_weight: 0.25,
6863 relationship_duration_weight: 0.20,
6864 recency_weight: 0.15,
6865 mutual_connections_weight: 0.10,
6866 recency_half_life_days: 90,
6867 }
6868 }
6869}
6870
6871#[derive(Debug, Clone, Serialize, Deserialize)]
6873pub struct StrengthThresholdsSchemaConfig {
6874 #[serde(default = "default_strong_threshold")]
6876 pub strong: f64,
6877
6878 #[serde(default = "default_moderate_threshold")]
6880 pub moderate: f64,
6881
6882 #[serde(default = "default_weak_threshold")]
6884 pub weak: f64,
6885}
6886
6887fn default_strong_threshold() -> f64 {
6888 0.7
6889}
6890
6891fn default_moderate_threshold() -> f64 {
6892 0.4
6893}
6894
6895fn default_weak_threshold() -> f64 {
6896 0.1
6897}
6898
6899impl Default for StrengthThresholdsSchemaConfig {
6900 fn default() -> Self {
6901 Self {
6902 strong: 0.7,
6903 moderate: 0.4,
6904 weak: 0.1,
6905 }
6906 }
6907}
6908
6909#[derive(Debug, Clone, Serialize, Deserialize)]
6915pub struct CrossProcessLinksSchemaConfig {
6916 #[serde(default)]
6918 pub enabled: bool,
6919
6920 #[serde(default = "default_true")]
6922 pub inventory_p2p_o2c: bool,
6923
6924 #[serde(default = "default_true")]
6926 pub payment_bank_reconciliation: bool,
6927
6928 #[serde(default = "default_true")]
6930 pub intercompany_bilateral: bool,
6931
6932 #[serde(default = "default_inventory_link_rate")]
6934 pub inventory_link_rate: f64,
6935}
6936
6937fn default_inventory_link_rate() -> f64 {
6938 0.30
6939}
6940
6941impl Default for CrossProcessLinksSchemaConfig {
6942 fn default() -> Self {
6943 Self {
6944 enabled: false,
6945 inventory_p2p_o2c: true,
6946 payment_bank_reconciliation: true,
6947 intercompany_bilateral: true,
6948 inventory_link_rate: 0.30,
6949 }
6950 }
6951}
6952
6953#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6959pub struct OrganizationalEventsSchemaConfig {
6960 #[serde(default)]
6962 pub enabled: bool,
6963
6964 #[serde(default)]
6966 pub effect_blending: EffectBlendingModeConfig,
6967
6968 #[serde(default)]
6970 pub events: Vec<OrganizationalEventSchemaConfig>,
6971
6972 #[serde(default)]
6974 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6975
6976 #[serde(default)]
6978 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6979}
6980
6981#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6983#[serde(rename_all = "snake_case")]
6984pub enum EffectBlendingModeConfig {
6985 #[default]
6987 Multiplicative,
6988 Additive,
6990 Maximum,
6992 Minimum,
6994}
6995
6996#[derive(Debug, Clone, Serialize, Deserialize)]
6998pub struct OrganizationalEventSchemaConfig {
6999 pub id: String,
7001
7002 pub event_type: OrganizationalEventTypeSchemaConfig,
7004
7005 pub effective_date: String,
7007
7008 #[serde(default = "default_org_transition_months")]
7010 pub transition_months: u32,
7011
7012 #[serde(default)]
7014 pub description: Option<String>,
7015}
7016
7017fn default_org_transition_months() -> u32 {
7018 6
7019}
7020
7021#[derive(Debug, Clone, Serialize, Deserialize)]
7023#[serde(tag = "type", rename_all = "snake_case")]
7024pub enum OrganizationalEventTypeSchemaConfig {
7025 Acquisition {
7027 acquired_entity: String,
7029 #[serde(default = "default_acquisition_volume")]
7031 volume_increase: f64,
7032 #[serde(default = "default_acquisition_error")]
7034 integration_error_rate: f64,
7035 #[serde(default = "default_parallel_days")]
7037 parallel_posting_days: u32,
7038 },
7039 Divestiture {
7041 divested_entity: String,
7043 #[serde(default = "default_divestiture_volume")]
7045 volume_reduction: f64,
7046 #[serde(default = "default_true_val")]
7048 remove_entity: bool,
7049 },
7050 Reorganization {
7052 #[serde(default)]
7054 cost_center_remapping: std::collections::HashMap<String, String>,
7055 #[serde(default = "default_reorg_error")]
7057 transition_error_rate: f64,
7058 },
7059 LeadershipChange {
7061 role: String,
7063 #[serde(default)]
7065 policy_changes: Vec<String>,
7066 },
7067 WorkforceReduction {
7069 #[serde(default = "default_workforce_reduction")]
7071 reduction_percent: f64,
7072 #[serde(default = "default_workforce_error")]
7074 error_rate_increase: f64,
7075 },
7076 Merger {
7078 merged_entity: String,
7080 #[serde(default = "default_merger_volume")]
7082 volume_increase: f64,
7083 },
7084}
7085
7086fn default_acquisition_volume() -> f64 {
7087 1.35
7088}
7089
7090fn default_acquisition_error() -> f64 {
7091 0.05
7092}
7093
7094fn default_parallel_days() -> u32 {
7095 30
7096}
7097
7098fn default_divestiture_volume() -> f64 {
7099 0.70
7100}
7101
7102fn default_true_val() -> bool {
7103 true
7104}
7105
7106fn default_reorg_error() -> f64 {
7107 0.04
7108}
7109
7110fn default_workforce_reduction() -> f64 {
7111 0.10
7112}
7113
7114fn default_workforce_error() -> f64 {
7115 0.05
7116}
7117
7118fn default_merger_volume() -> f64 {
7119 1.80
7120}
7121
7122#[derive(Debug, Clone, Serialize, Deserialize)]
7124pub struct ProcessEvolutionSchemaConfig {
7125 pub id: String,
7127
7128 pub event_type: ProcessEvolutionTypeSchemaConfig,
7130
7131 pub effective_date: String,
7133
7134 #[serde(default)]
7136 pub description: Option<String>,
7137}
7138
7139#[derive(Debug, Clone, Serialize, Deserialize)]
7141#[serde(tag = "type", rename_all = "snake_case")]
7142pub enum ProcessEvolutionTypeSchemaConfig {
7143 ProcessAutomation {
7145 process_name: String,
7147 #[serde(default = "default_manual_before")]
7149 manual_rate_before: f64,
7150 #[serde(default = "default_manual_after")]
7152 manual_rate_after: f64,
7153 },
7154 ApprovalWorkflowChange {
7156 description: String,
7158 },
7159 ControlEnhancement {
7161 control_id: String,
7163 #[serde(default = "default_error_reduction")]
7165 error_reduction: f64,
7166 },
7167}
7168
7169fn default_manual_before() -> f64 {
7170 0.80
7171}
7172
7173fn default_manual_after() -> f64 {
7174 0.15
7175}
7176
7177fn default_error_reduction() -> f64 {
7178 0.02
7179}
7180
7181#[derive(Debug, Clone, Serialize, Deserialize)]
7183pub struct TechnologyTransitionSchemaConfig {
7184 pub id: String,
7186
7187 pub event_type: TechnologyTransitionTypeSchemaConfig,
7189
7190 #[serde(default)]
7192 pub description: Option<String>,
7193}
7194
7195#[derive(Debug, Clone, Serialize, Deserialize)]
7197#[serde(tag = "type", rename_all = "snake_case")]
7198pub enum TechnologyTransitionTypeSchemaConfig {
7199 ErpMigration {
7201 source_system: String,
7203 target_system: String,
7205 cutover_date: String,
7207 stabilization_end: String,
7209 #[serde(default = "default_erp_duplicate_rate")]
7211 duplicate_rate: f64,
7212 #[serde(default = "default_format_mismatch")]
7214 format_mismatch_rate: f64,
7215 },
7216 ModuleImplementation {
7218 module_name: String,
7220 go_live_date: String,
7222 },
7223}
7224
7225fn default_erp_duplicate_rate() -> f64 {
7226 0.02
7227}
7228
7229fn default_format_mismatch() -> f64 {
7230 0.03
7231}
7232
7233#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7239pub struct BehavioralDriftSchemaConfig {
7240 #[serde(default)]
7242 pub enabled: bool,
7243
7244 #[serde(default)]
7246 pub vendor_behavior: VendorBehaviorSchemaConfig,
7247
7248 #[serde(default)]
7250 pub customer_behavior: CustomerBehaviorSchemaConfig,
7251
7252 #[serde(default)]
7254 pub employee_behavior: EmployeeBehaviorSchemaConfig,
7255
7256 #[serde(default)]
7258 pub collective: CollectiveBehaviorSchemaConfig,
7259}
7260
7261#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7263pub struct VendorBehaviorSchemaConfig {
7264 #[serde(default)]
7266 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7267
7268 #[serde(default)]
7270 pub quality_drift: QualityDriftSchemaConfig,
7271}
7272
7273#[derive(Debug, Clone, Serialize, Deserialize)]
7275pub struct PaymentTermsDriftSchemaConfig {
7276 #[serde(default = "default_extension_rate")]
7278 pub extension_rate_per_year: f64,
7279
7280 #[serde(default = "default_economic_sensitivity")]
7282 pub economic_sensitivity: f64,
7283}
7284
7285fn default_extension_rate() -> f64 {
7286 2.5
7287}
7288
7289fn default_economic_sensitivity() -> f64 {
7290 1.0
7291}
7292
7293impl Default for PaymentTermsDriftSchemaConfig {
7294 fn default() -> Self {
7295 Self {
7296 extension_rate_per_year: 2.5,
7297 economic_sensitivity: 1.0,
7298 }
7299 }
7300}
7301
7302#[derive(Debug, Clone, Serialize, Deserialize)]
7304pub struct QualityDriftSchemaConfig {
7305 #[serde(default = "default_improvement_rate")]
7307 pub new_vendor_improvement_rate: f64,
7308
7309 #[serde(default = "default_decline_rate")]
7311 pub complacency_decline_rate: f64,
7312}
7313
7314fn default_improvement_rate() -> f64 {
7315 0.02
7316}
7317
7318fn default_decline_rate() -> f64 {
7319 0.01
7320}
7321
7322impl Default for QualityDriftSchemaConfig {
7323 fn default() -> Self {
7324 Self {
7325 new_vendor_improvement_rate: 0.02,
7326 complacency_decline_rate: 0.01,
7327 }
7328 }
7329}
7330
7331#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7333pub struct CustomerBehaviorSchemaConfig {
7334 #[serde(default)]
7336 pub payment_drift: CustomerPaymentDriftSchemaConfig,
7337
7338 #[serde(default)]
7340 pub order_drift: OrderDriftSchemaConfig,
7341}
7342
7343#[derive(Debug, Clone, Serialize, Deserialize)]
7345pub struct CustomerPaymentDriftSchemaConfig {
7346 #[serde(default = "default_downturn_extension")]
7348 pub downturn_days_extension: (u32, u32),
7349
7350 #[serde(default = "default_bad_debt_increase")]
7352 pub downturn_bad_debt_increase: f64,
7353}
7354
7355fn default_downturn_extension() -> (u32, u32) {
7356 (5, 15)
7357}
7358
7359fn default_bad_debt_increase() -> f64 {
7360 0.02
7361}
7362
7363impl Default for CustomerPaymentDriftSchemaConfig {
7364 fn default() -> Self {
7365 Self {
7366 downturn_days_extension: (5, 15),
7367 downturn_bad_debt_increase: 0.02,
7368 }
7369 }
7370}
7371
7372#[derive(Debug, Clone, Serialize, Deserialize)]
7374pub struct OrderDriftSchemaConfig {
7375 #[serde(default = "default_digital_shift")]
7377 pub digital_shift_rate: f64,
7378}
7379
7380fn default_digital_shift() -> f64 {
7381 0.05
7382}
7383
7384impl Default for OrderDriftSchemaConfig {
7385 fn default() -> Self {
7386 Self {
7387 digital_shift_rate: 0.05,
7388 }
7389 }
7390}
7391
7392#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7394pub struct EmployeeBehaviorSchemaConfig {
7395 #[serde(default)]
7397 pub approval_drift: ApprovalDriftSchemaConfig,
7398
7399 #[serde(default)]
7401 pub error_drift: ErrorDriftSchemaConfig,
7402}
7403
7404#[derive(Debug, Clone, Serialize, Deserialize)]
7406pub struct ApprovalDriftSchemaConfig {
7407 #[serde(default = "default_eom_intensity")]
7409 pub eom_intensity_increase_per_year: f64,
7410
7411 #[serde(default = "default_rubber_stamp")]
7413 pub rubber_stamp_volume_threshold: u32,
7414}
7415
7416fn default_eom_intensity() -> f64 {
7417 0.05
7418}
7419
7420fn default_rubber_stamp() -> u32 {
7421 50
7422}
7423
7424impl Default for ApprovalDriftSchemaConfig {
7425 fn default() -> Self {
7426 Self {
7427 eom_intensity_increase_per_year: 0.05,
7428 rubber_stamp_volume_threshold: 50,
7429 }
7430 }
7431}
7432
7433#[derive(Debug, Clone, Serialize, Deserialize)]
7435pub struct ErrorDriftSchemaConfig {
7436 #[serde(default = "default_new_error")]
7438 pub new_employee_error_rate: f64,
7439
7440 #[serde(default = "default_learning_months")]
7442 pub learning_curve_months: u32,
7443}
7444
7445fn default_new_error() -> f64 {
7446 0.08
7447}
7448
7449fn default_learning_months() -> u32 {
7450 6
7451}
7452
7453impl Default for ErrorDriftSchemaConfig {
7454 fn default() -> Self {
7455 Self {
7456 new_employee_error_rate: 0.08,
7457 learning_curve_months: 6,
7458 }
7459 }
7460}
7461
7462#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7464pub struct CollectiveBehaviorSchemaConfig {
7465 #[serde(default)]
7467 pub automation_adoption: AutomationAdoptionSchemaConfig,
7468}
7469
7470#[derive(Debug, Clone, Serialize, Deserialize)]
7472pub struct AutomationAdoptionSchemaConfig {
7473 #[serde(default)]
7475 pub s_curve_enabled: bool,
7476
7477 #[serde(default = "default_midpoint")]
7479 pub adoption_midpoint_months: u32,
7480
7481 #[serde(default = "default_steepness")]
7483 pub steepness: f64,
7484}
7485
7486fn default_midpoint() -> u32 {
7487 24
7488}
7489
7490fn default_steepness() -> f64 {
7491 0.15
7492}
7493
7494impl Default for AutomationAdoptionSchemaConfig {
7495 fn default() -> Self {
7496 Self {
7497 s_curve_enabled: false,
7498 adoption_midpoint_months: 24,
7499 steepness: 0.15,
7500 }
7501 }
7502}
7503
7504#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7510pub struct MarketDriftSchemaConfig {
7511 #[serde(default)]
7513 pub enabled: bool,
7514
7515 #[serde(default)]
7517 pub economic_cycle: MarketEconomicCycleSchemaConfig,
7518
7519 #[serde(default)]
7521 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7522
7523 #[serde(default)]
7525 pub commodities: CommoditiesSchemaConfig,
7526}
7527
7528#[derive(Debug, Clone, Serialize, Deserialize)]
7530pub struct MarketEconomicCycleSchemaConfig {
7531 #[serde(default)]
7533 pub enabled: bool,
7534
7535 #[serde(default)]
7537 pub cycle_type: CycleTypeSchemaConfig,
7538
7539 #[serde(default = "default_market_cycle_period")]
7541 pub period_months: u32,
7542
7543 #[serde(default = "default_market_amplitude")]
7545 pub amplitude: f64,
7546
7547 #[serde(default)]
7549 pub recession: RecessionSchemaConfig,
7550}
7551
7552fn default_market_cycle_period() -> u32 {
7553 48
7554}
7555
7556fn default_market_amplitude() -> f64 {
7557 0.15
7558}
7559
7560impl Default for MarketEconomicCycleSchemaConfig {
7561 fn default() -> Self {
7562 Self {
7563 enabled: false,
7564 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7565 period_months: 48,
7566 amplitude: 0.15,
7567 recession: RecessionSchemaConfig::default(),
7568 }
7569 }
7570}
7571
7572#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7574#[serde(rename_all = "snake_case")]
7575pub enum CycleTypeSchemaConfig {
7576 #[default]
7578 Sinusoidal,
7579 Asymmetric,
7581 MeanReverting,
7583}
7584
7585#[derive(Debug, Clone, Serialize, Deserialize)]
7587pub struct RecessionSchemaConfig {
7588 #[serde(default)]
7590 pub enabled: bool,
7591
7592 #[serde(default = "default_recession_prob")]
7594 pub probability_per_year: f64,
7595
7596 #[serde(default)]
7598 pub severity: RecessionSeveritySchemaConfig,
7599
7600 #[serde(default)]
7602 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7603}
7604
7605fn default_recession_prob() -> f64 {
7606 0.10
7607}
7608
7609impl Default for RecessionSchemaConfig {
7610 fn default() -> Self {
7611 Self {
7612 enabled: false,
7613 probability_per_year: 0.10,
7614 severity: RecessionSeveritySchemaConfig::Moderate,
7615 recession_periods: Vec::new(),
7616 }
7617 }
7618}
7619
7620#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7622#[serde(rename_all = "snake_case")]
7623pub enum RecessionSeveritySchemaConfig {
7624 Mild,
7626 #[default]
7628 Moderate,
7629 Severe,
7631}
7632
7633#[derive(Debug, Clone, Serialize, Deserialize)]
7635pub struct RecessionPeriodSchemaConfig {
7636 pub start_month: u32,
7638 pub duration_months: u32,
7640}
7641
7642#[derive(Debug, Clone, Serialize, Deserialize)]
7644pub struct IndustryCycleSchemaConfig {
7645 #[serde(default = "default_industry_period")]
7647 pub period_months: u32,
7648
7649 #[serde(default = "default_industry_amp")]
7651 pub amplitude: f64,
7652}
7653
7654fn default_industry_period() -> u32 {
7655 36
7656}
7657
7658fn default_industry_amp() -> f64 {
7659 0.20
7660}
7661
7662#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7664pub struct CommoditiesSchemaConfig {
7665 #[serde(default)]
7667 pub enabled: bool,
7668
7669 #[serde(default)]
7671 pub items: Vec<CommodityItemSchemaConfig>,
7672}
7673
7674#[derive(Debug, Clone, Serialize, Deserialize)]
7676pub struct CommodityItemSchemaConfig {
7677 pub name: String,
7679
7680 #[serde(default = "default_volatility")]
7682 pub volatility: f64,
7683
7684 #[serde(default)]
7686 pub cogs_pass_through: f64,
7687
7688 #[serde(default)]
7690 pub overhead_pass_through: f64,
7691}
7692
7693fn default_volatility() -> f64 {
7694 0.20
7695}
7696
7697#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7703pub struct DriftLabelingSchemaConfig {
7704 #[serde(default)]
7706 pub enabled: bool,
7707
7708 #[serde(default)]
7710 pub statistical: StatisticalDriftLabelingSchemaConfig,
7711
7712 #[serde(default)]
7714 pub categorical: CategoricalDriftLabelingSchemaConfig,
7715
7716 #[serde(default)]
7718 pub temporal: TemporalDriftLabelingSchemaConfig,
7719
7720 #[serde(default)]
7722 pub regulatory_calendar_preset: Option<String>,
7723}
7724
7725#[derive(Debug, Clone, Serialize, Deserialize)]
7727pub struct StatisticalDriftLabelingSchemaConfig {
7728 #[serde(default = "default_true_val")]
7730 pub enabled: bool,
7731
7732 #[serde(default = "default_min_magnitude")]
7734 pub min_magnitude_threshold: f64,
7735}
7736
7737fn default_min_magnitude() -> f64 {
7738 0.05
7739}
7740
7741impl Default for StatisticalDriftLabelingSchemaConfig {
7742 fn default() -> Self {
7743 Self {
7744 enabled: true,
7745 min_magnitude_threshold: 0.05,
7746 }
7747 }
7748}
7749
7750#[derive(Debug, Clone, Serialize, Deserialize)]
7752pub struct CategoricalDriftLabelingSchemaConfig {
7753 #[serde(default = "default_true_val")]
7755 pub enabled: bool,
7756}
7757
7758impl Default for CategoricalDriftLabelingSchemaConfig {
7759 fn default() -> Self {
7760 Self { enabled: true }
7761 }
7762}
7763
7764#[derive(Debug, Clone, Serialize, Deserialize)]
7766pub struct TemporalDriftLabelingSchemaConfig {
7767 #[serde(default = "default_true_val")]
7769 pub enabled: bool,
7770}
7771
7772impl Default for TemporalDriftLabelingSchemaConfig {
7773 fn default() -> Self {
7774 Self { enabled: true }
7775 }
7776}
7777
7778#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7791pub struct EnhancedAnomalyConfig {
7792 #[serde(default)]
7794 pub enabled: bool,
7795
7796 #[serde(default)]
7798 pub rates: AnomalyRateConfig,
7799
7800 #[serde(default)]
7802 pub multi_stage_schemes: MultiStageSchemeConfig,
7803
7804 #[serde(default)]
7806 pub correlated_injection: CorrelatedInjectionConfig,
7807
7808 #[serde(default)]
7810 pub near_miss: NearMissConfig,
7811
7812 #[serde(default)]
7814 pub difficulty_classification: DifficultyClassificationConfig,
7815
7816 #[serde(default)]
7818 pub context_aware: ContextAwareConfig,
7819
7820 #[serde(default)]
7822 pub labeling: EnhancedLabelingConfig,
7823}
7824
7825#[derive(Debug, Clone, Serialize, Deserialize)]
7827pub struct AnomalyRateConfig {
7828 #[serde(default = "default_total_anomaly_rate")]
7830 pub total_rate: f64,
7831
7832 #[serde(default = "default_fraud_anomaly_rate")]
7834 pub fraud_rate: f64,
7835
7836 #[serde(default = "default_error_anomaly_rate")]
7838 pub error_rate: f64,
7839
7840 #[serde(default = "default_process_anomaly_rate")]
7842 pub process_rate: f64,
7843}
7844
7845fn default_total_anomaly_rate() -> f64 {
7846 0.03
7847}
7848fn default_fraud_anomaly_rate() -> f64 {
7849 0.01
7850}
7851fn default_error_anomaly_rate() -> f64 {
7852 0.015
7853}
7854fn default_process_anomaly_rate() -> f64 {
7855 0.005
7856}
7857
7858impl Default for AnomalyRateConfig {
7859 fn default() -> Self {
7860 Self {
7861 total_rate: default_total_anomaly_rate(),
7862 fraud_rate: default_fraud_anomaly_rate(),
7863 error_rate: default_error_anomaly_rate(),
7864 process_rate: default_process_anomaly_rate(),
7865 }
7866 }
7867}
7868
7869#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7871pub struct MultiStageSchemeConfig {
7872 #[serde(default)]
7874 pub enabled: bool,
7875
7876 #[serde(default)]
7878 pub embezzlement: EmbezzlementSchemeConfig,
7879
7880 #[serde(default)]
7882 pub revenue_manipulation: RevenueManipulationSchemeConfig,
7883
7884 #[serde(default)]
7886 pub kickback: KickbackSchemeConfig,
7887}
7888
7889#[derive(Debug, Clone, Serialize, Deserialize)]
7891pub struct EmbezzlementSchemeConfig {
7892 #[serde(default = "default_embezzlement_probability")]
7894 pub probability: f64,
7895
7896 #[serde(default)]
7898 pub testing_stage: SchemeStageConfig,
7899
7900 #[serde(default)]
7902 pub escalation_stage: SchemeStageConfig,
7903
7904 #[serde(default)]
7906 pub acceleration_stage: SchemeStageConfig,
7907
7908 #[serde(default)]
7910 pub desperation_stage: SchemeStageConfig,
7911}
7912
7913fn default_embezzlement_probability() -> f64 {
7914 0.02
7915}
7916
7917impl Default for EmbezzlementSchemeConfig {
7918 fn default() -> Self {
7919 Self {
7920 probability: default_embezzlement_probability(),
7921 testing_stage: SchemeStageConfig {
7922 duration_months: 2,
7923 amount_min: 100.0,
7924 amount_max: 500.0,
7925 transaction_count_min: 2,
7926 transaction_count_max: 5,
7927 difficulty: "hard".to_string(),
7928 },
7929 escalation_stage: SchemeStageConfig {
7930 duration_months: 6,
7931 amount_min: 500.0,
7932 amount_max: 2000.0,
7933 transaction_count_min: 3,
7934 transaction_count_max: 8,
7935 difficulty: "moderate".to_string(),
7936 },
7937 acceleration_stage: SchemeStageConfig {
7938 duration_months: 3,
7939 amount_min: 2000.0,
7940 amount_max: 10000.0,
7941 transaction_count_min: 5,
7942 transaction_count_max: 12,
7943 difficulty: "easy".to_string(),
7944 },
7945 desperation_stage: SchemeStageConfig {
7946 duration_months: 1,
7947 amount_min: 10000.0,
7948 amount_max: 50000.0,
7949 transaction_count_min: 3,
7950 transaction_count_max: 6,
7951 difficulty: "trivial".to_string(),
7952 },
7953 }
7954 }
7955}
7956
7957#[derive(Debug, Clone, Serialize, Deserialize)]
7959pub struct RevenueManipulationSchemeConfig {
7960 #[serde(default = "default_revenue_manipulation_probability")]
7962 pub probability: f64,
7963
7964 #[serde(default = "default_early_recognition_target")]
7966 pub early_recognition_target: f64,
7967
7968 #[serde(default = "default_expense_deferral_target")]
7970 pub expense_deferral_target: f64,
7971
7972 #[serde(default = "default_reserve_release_target")]
7974 pub reserve_release_target: f64,
7975
7976 #[serde(default = "default_channel_stuffing_target")]
7978 pub channel_stuffing_target: f64,
7979}
7980
7981fn default_revenue_manipulation_probability() -> f64 {
7982 0.01
7983}
7984fn default_early_recognition_target() -> f64 {
7985 0.02
7986}
7987fn default_expense_deferral_target() -> f64 {
7988 0.03
7989}
7990fn default_reserve_release_target() -> f64 {
7991 0.02
7992}
7993fn default_channel_stuffing_target() -> f64 {
7994 0.05
7995}
7996
7997impl Default for RevenueManipulationSchemeConfig {
7998 fn default() -> Self {
7999 Self {
8000 probability: default_revenue_manipulation_probability(),
8001 early_recognition_target: default_early_recognition_target(),
8002 expense_deferral_target: default_expense_deferral_target(),
8003 reserve_release_target: default_reserve_release_target(),
8004 channel_stuffing_target: default_channel_stuffing_target(),
8005 }
8006 }
8007}
8008
8009#[derive(Debug, Clone, Serialize, Deserialize)]
8011pub struct KickbackSchemeConfig {
8012 #[serde(default = "default_kickback_probability")]
8014 pub probability: f64,
8015
8016 #[serde(default = "default_kickback_inflation_min")]
8018 pub inflation_min: f64,
8019
8020 #[serde(default = "default_kickback_inflation_max")]
8022 pub inflation_max: f64,
8023
8024 #[serde(default = "default_kickback_percent")]
8026 pub kickback_percent: f64,
8027
8028 #[serde(default = "default_kickback_setup_months")]
8030 pub setup_months: u32,
8031
8032 #[serde(default = "default_kickback_operation_months")]
8034 pub operation_months: u32,
8035}
8036
8037fn default_kickback_probability() -> f64 {
8038 0.01
8039}
8040fn default_kickback_inflation_min() -> f64 {
8041 0.10
8042}
8043fn default_kickback_inflation_max() -> f64 {
8044 0.25
8045}
8046fn default_kickback_percent() -> f64 {
8047 0.50
8048}
8049fn default_kickback_setup_months() -> u32 {
8050 3
8051}
8052fn default_kickback_operation_months() -> u32 {
8053 12
8054}
8055
8056impl Default for KickbackSchemeConfig {
8057 fn default() -> Self {
8058 Self {
8059 probability: default_kickback_probability(),
8060 inflation_min: default_kickback_inflation_min(),
8061 inflation_max: default_kickback_inflation_max(),
8062 kickback_percent: default_kickback_percent(),
8063 setup_months: default_kickback_setup_months(),
8064 operation_months: default_kickback_operation_months(),
8065 }
8066 }
8067}
8068
8069#[derive(Debug, Clone, Serialize, Deserialize)]
8071pub struct SchemeStageConfig {
8072 pub duration_months: u32,
8074
8075 pub amount_min: f64,
8077
8078 pub amount_max: f64,
8080
8081 pub transaction_count_min: u32,
8083
8084 pub transaction_count_max: u32,
8086
8087 pub difficulty: String,
8089}
8090
8091impl Default for SchemeStageConfig {
8092 fn default() -> Self {
8093 Self {
8094 duration_months: 3,
8095 amount_min: 100.0,
8096 amount_max: 1000.0,
8097 transaction_count_min: 2,
8098 transaction_count_max: 10,
8099 difficulty: "moderate".to_string(),
8100 }
8101 }
8102}
8103
8104#[derive(Debug, Clone, Serialize, Deserialize)]
8106pub struct CorrelatedInjectionConfig {
8107 #[serde(default)]
8109 pub enabled: bool,
8110
8111 #[serde(default = "default_true_val")]
8113 pub fraud_concealment: bool,
8114
8115 #[serde(default = "default_true_val")]
8117 pub error_cascade: bool,
8118
8119 #[serde(default = "default_true_val")]
8121 pub temporal_clustering: bool,
8122
8123 #[serde(default)]
8125 pub temporal_clustering_config: TemporalClusteringConfig,
8126
8127 #[serde(default)]
8129 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8130}
8131
8132impl Default for CorrelatedInjectionConfig {
8133 fn default() -> Self {
8134 Self {
8135 enabled: false,
8136 fraud_concealment: true,
8137 error_cascade: true,
8138 temporal_clustering: true,
8139 temporal_clustering_config: TemporalClusteringConfig::default(),
8140 co_occurrence_patterns: Vec::new(),
8141 }
8142 }
8143}
8144
8145#[derive(Debug, Clone, Serialize, Deserialize)]
8147pub struct TemporalClusteringConfig {
8148 #[serde(default = "default_period_end_multiplier")]
8150 pub period_end_multiplier: f64,
8151
8152 #[serde(default = "default_period_end_days")]
8154 pub period_end_days: u32,
8155
8156 #[serde(default = "default_quarter_end_multiplier")]
8158 pub quarter_end_multiplier: f64,
8159
8160 #[serde(default = "default_year_end_multiplier")]
8162 pub year_end_multiplier: f64,
8163}
8164
8165fn default_period_end_multiplier() -> f64 {
8166 2.5
8167}
8168fn default_period_end_days() -> u32 {
8169 5
8170}
8171fn default_quarter_end_multiplier() -> f64 {
8172 1.5
8173}
8174fn default_year_end_multiplier() -> f64 {
8175 2.0
8176}
8177
8178impl Default for TemporalClusteringConfig {
8179 fn default() -> Self {
8180 Self {
8181 period_end_multiplier: default_period_end_multiplier(),
8182 period_end_days: default_period_end_days(),
8183 quarter_end_multiplier: default_quarter_end_multiplier(),
8184 year_end_multiplier: default_year_end_multiplier(),
8185 }
8186 }
8187}
8188
8189#[derive(Debug, Clone, Serialize, Deserialize)]
8191pub struct CoOccurrencePatternConfig {
8192 pub name: String,
8194
8195 pub primary_type: String,
8197
8198 pub correlated: Vec<CorrelatedAnomalyConfig>,
8200}
8201
8202#[derive(Debug, Clone, Serialize, Deserialize)]
8204pub struct CorrelatedAnomalyConfig {
8205 pub anomaly_type: String,
8207
8208 pub probability: f64,
8210
8211 pub lag_days_min: i32,
8213
8214 pub lag_days_max: i32,
8216}
8217
8218#[derive(Debug, Clone, Serialize, Deserialize)]
8220pub struct NearMissConfig {
8221 #[serde(default)]
8223 pub enabled: bool,
8224
8225 #[serde(default = "default_near_miss_proportion")]
8227 pub proportion: f64,
8228
8229 #[serde(default = "default_true_val")]
8231 pub near_duplicate: bool,
8232
8233 #[serde(default)]
8235 pub near_duplicate_days: NearDuplicateDaysConfig,
8236
8237 #[serde(default = "default_true_val")]
8239 pub threshold_proximity: bool,
8240
8241 #[serde(default)]
8243 pub threshold_proximity_range: ThresholdProximityRangeConfig,
8244
8245 #[serde(default = "default_true_val")]
8247 pub unusual_legitimate: bool,
8248
8249 #[serde(default = "default_unusual_legitimate_types")]
8251 pub unusual_legitimate_types: Vec<String>,
8252
8253 #[serde(default = "default_true_val")]
8255 pub corrected_errors: bool,
8256
8257 #[serde(default)]
8259 pub corrected_error_lag: CorrectedErrorLagConfig,
8260}
8261
8262fn default_near_miss_proportion() -> f64 {
8263 0.30
8264}
8265
8266fn default_unusual_legitimate_types() -> Vec<String> {
8267 vec![
8268 "year_end_bonus".to_string(),
8269 "contract_prepayment".to_string(),
8270 "insurance_claim".to_string(),
8271 "settlement_payment".to_string(),
8272 ]
8273}
8274
8275impl Default for NearMissConfig {
8276 fn default() -> Self {
8277 Self {
8278 enabled: false,
8279 proportion: default_near_miss_proportion(),
8280 near_duplicate: true,
8281 near_duplicate_days: NearDuplicateDaysConfig::default(),
8282 threshold_proximity: true,
8283 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8284 unusual_legitimate: true,
8285 unusual_legitimate_types: default_unusual_legitimate_types(),
8286 corrected_errors: true,
8287 corrected_error_lag: CorrectedErrorLagConfig::default(),
8288 }
8289 }
8290}
8291
8292#[derive(Debug, Clone, Serialize, Deserialize)]
8294pub struct NearDuplicateDaysConfig {
8295 #[serde(default = "default_near_duplicate_min")]
8297 pub min: u32,
8298
8299 #[serde(default = "default_near_duplicate_max")]
8301 pub max: u32,
8302}
8303
8304fn default_near_duplicate_min() -> u32 {
8305 1
8306}
8307fn default_near_duplicate_max() -> u32 {
8308 3
8309}
8310
8311impl Default for NearDuplicateDaysConfig {
8312 fn default() -> Self {
8313 Self {
8314 min: default_near_duplicate_min(),
8315 max: default_near_duplicate_max(),
8316 }
8317 }
8318}
8319
8320#[derive(Debug, Clone, Serialize, Deserialize)]
8322pub struct ThresholdProximityRangeConfig {
8323 #[serde(default = "default_threshold_proximity_min")]
8325 pub min: f64,
8326
8327 #[serde(default = "default_threshold_proximity_max")]
8329 pub max: f64,
8330}
8331
8332fn default_threshold_proximity_min() -> f64 {
8333 0.90
8334}
8335fn default_threshold_proximity_max() -> f64 {
8336 0.99
8337}
8338
8339impl Default for ThresholdProximityRangeConfig {
8340 fn default() -> Self {
8341 Self {
8342 min: default_threshold_proximity_min(),
8343 max: default_threshold_proximity_max(),
8344 }
8345 }
8346}
8347
8348#[derive(Debug, Clone, Serialize, Deserialize)]
8350pub struct CorrectedErrorLagConfig {
8351 #[serde(default = "default_corrected_error_lag_min")]
8353 pub min: u32,
8354
8355 #[serde(default = "default_corrected_error_lag_max")]
8357 pub max: u32,
8358}
8359
8360fn default_corrected_error_lag_min() -> u32 {
8361 1
8362}
8363fn default_corrected_error_lag_max() -> u32 {
8364 5
8365}
8366
8367impl Default for CorrectedErrorLagConfig {
8368 fn default() -> Self {
8369 Self {
8370 min: default_corrected_error_lag_min(),
8371 max: default_corrected_error_lag_max(),
8372 }
8373 }
8374}
8375
8376#[derive(Debug, Clone, Serialize, Deserialize)]
8378pub struct DifficultyClassificationConfig {
8379 #[serde(default)]
8381 pub enabled: bool,
8382
8383 #[serde(default)]
8385 pub target_distribution: DifficultyDistributionConfig,
8386}
8387
8388impl Default for DifficultyClassificationConfig {
8389 fn default() -> Self {
8390 Self {
8391 enabled: true,
8392 target_distribution: DifficultyDistributionConfig::default(),
8393 }
8394 }
8395}
8396
8397#[derive(Debug, Clone, Serialize, Deserialize)]
8399pub struct DifficultyDistributionConfig {
8400 #[serde(default = "default_difficulty_trivial")]
8402 pub trivial: f64,
8403
8404 #[serde(default = "default_difficulty_easy")]
8406 pub easy: f64,
8407
8408 #[serde(default = "default_difficulty_moderate")]
8410 pub moderate: f64,
8411
8412 #[serde(default = "default_difficulty_hard")]
8414 pub hard: f64,
8415
8416 #[serde(default = "default_difficulty_expert")]
8418 pub expert: f64,
8419}
8420
8421fn default_difficulty_trivial() -> f64 {
8422 0.15
8423}
8424fn default_difficulty_easy() -> f64 {
8425 0.25
8426}
8427fn default_difficulty_moderate() -> f64 {
8428 0.30
8429}
8430fn default_difficulty_hard() -> f64 {
8431 0.20
8432}
8433fn default_difficulty_expert() -> f64 {
8434 0.10
8435}
8436
8437impl Default for DifficultyDistributionConfig {
8438 fn default() -> Self {
8439 Self {
8440 trivial: default_difficulty_trivial(),
8441 easy: default_difficulty_easy(),
8442 moderate: default_difficulty_moderate(),
8443 hard: default_difficulty_hard(),
8444 expert: default_difficulty_expert(),
8445 }
8446 }
8447}
8448
8449#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8451pub struct ContextAwareConfig {
8452 #[serde(default)]
8454 pub enabled: bool,
8455
8456 #[serde(default)]
8458 pub vendor_rules: VendorAnomalyRulesConfig,
8459
8460 #[serde(default)]
8462 pub employee_rules: EmployeeAnomalyRulesConfig,
8463
8464 #[serde(default)]
8466 pub account_rules: AccountAnomalyRulesConfig,
8467
8468 #[serde(default)]
8470 pub behavioral_baseline: BehavioralBaselineConfig,
8471}
8472
8473#[derive(Debug, Clone, Serialize, Deserialize)]
8475pub struct VendorAnomalyRulesConfig {
8476 #[serde(default = "default_new_vendor_multiplier")]
8478 pub new_vendor_error_multiplier: f64,
8479
8480 #[serde(default = "default_new_vendor_threshold")]
8482 pub new_vendor_threshold_days: u32,
8483
8484 #[serde(default = "default_international_multiplier")]
8486 pub international_error_multiplier: f64,
8487
8488 #[serde(default = "default_strategic_vendor_types")]
8490 pub strategic_vendor_anomaly_types: Vec<String>,
8491}
8492
8493fn default_new_vendor_multiplier() -> f64 {
8494 2.5
8495}
8496fn default_new_vendor_threshold() -> u32 {
8497 90
8498}
8499fn default_international_multiplier() -> f64 {
8500 1.5
8501}
8502fn default_strategic_vendor_types() -> Vec<String> {
8503 vec![
8504 "pricing_dispute".to_string(),
8505 "contract_violation".to_string(),
8506 ]
8507}
8508
8509impl Default for VendorAnomalyRulesConfig {
8510 fn default() -> Self {
8511 Self {
8512 new_vendor_error_multiplier: default_new_vendor_multiplier(),
8513 new_vendor_threshold_days: default_new_vendor_threshold(),
8514 international_error_multiplier: default_international_multiplier(),
8515 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8516 }
8517 }
8518}
8519
8520#[derive(Debug, Clone, Serialize, Deserialize)]
8522pub struct EmployeeAnomalyRulesConfig {
8523 #[serde(default = "default_new_employee_rate")]
8525 pub new_employee_error_rate: f64,
8526
8527 #[serde(default = "default_new_employee_threshold")]
8529 pub new_employee_threshold_days: u32,
8530
8531 #[serde(default = "default_volume_fatigue_threshold")]
8533 pub volume_fatigue_threshold: u32,
8534
8535 #[serde(default = "default_coverage_multiplier")]
8537 pub coverage_error_multiplier: f64,
8538}
8539
8540fn default_new_employee_rate() -> f64 {
8541 0.05
8542}
8543fn default_new_employee_threshold() -> u32 {
8544 180
8545}
8546fn default_volume_fatigue_threshold() -> u32 {
8547 50
8548}
8549fn default_coverage_multiplier() -> f64 {
8550 1.8
8551}
8552
8553impl Default for EmployeeAnomalyRulesConfig {
8554 fn default() -> Self {
8555 Self {
8556 new_employee_error_rate: default_new_employee_rate(),
8557 new_employee_threshold_days: default_new_employee_threshold(),
8558 volume_fatigue_threshold: default_volume_fatigue_threshold(),
8559 coverage_error_multiplier: default_coverage_multiplier(),
8560 }
8561 }
8562}
8563
8564#[derive(Debug, Clone, Serialize, Deserialize)]
8566pub struct AccountAnomalyRulesConfig {
8567 #[serde(default = "default_high_risk_multiplier")]
8569 pub high_risk_account_multiplier: f64,
8570
8571 #[serde(default = "default_high_risk_accounts")]
8573 pub high_risk_accounts: Vec<String>,
8574
8575 #[serde(default = "default_suspense_multiplier")]
8577 pub suspense_account_multiplier: f64,
8578
8579 #[serde(default = "default_suspense_accounts")]
8581 pub suspense_accounts: Vec<String>,
8582
8583 #[serde(default = "default_intercompany_multiplier")]
8585 pub intercompany_account_multiplier: f64,
8586}
8587
8588fn default_high_risk_multiplier() -> f64 {
8589 2.0
8590}
8591fn default_high_risk_accounts() -> Vec<String> {
8592 vec![
8593 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
8597}
8598fn default_suspense_multiplier() -> f64 {
8599 3.0
8600}
8601fn default_suspense_accounts() -> Vec<String> {
8602 vec!["9999".to_string(), "9998".to_string()]
8603}
8604fn default_intercompany_multiplier() -> f64 {
8605 1.5
8606}
8607
8608impl Default for AccountAnomalyRulesConfig {
8609 fn default() -> Self {
8610 Self {
8611 high_risk_account_multiplier: default_high_risk_multiplier(),
8612 high_risk_accounts: default_high_risk_accounts(),
8613 suspense_account_multiplier: default_suspense_multiplier(),
8614 suspense_accounts: default_suspense_accounts(),
8615 intercompany_account_multiplier: default_intercompany_multiplier(),
8616 }
8617 }
8618}
8619
8620#[derive(Debug, Clone, Serialize, Deserialize)]
8622pub struct BehavioralBaselineConfig {
8623 #[serde(default)]
8625 pub enabled: bool,
8626
8627 #[serde(default = "default_baseline_period")]
8629 pub baseline_period_days: u32,
8630
8631 #[serde(default = "default_deviation_threshold")]
8633 pub deviation_threshold_std: f64,
8634
8635 #[serde(default = "default_frequency_deviation")]
8637 pub frequency_deviation_threshold: f64,
8638}
8639
8640fn default_baseline_period() -> u32 {
8641 90
8642}
8643fn default_deviation_threshold() -> f64 {
8644 3.0
8645}
8646fn default_frequency_deviation() -> f64 {
8647 2.0
8648}
8649
8650impl Default for BehavioralBaselineConfig {
8651 fn default() -> Self {
8652 Self {
8653 enabled: false,
8654 baseline_period_days: default_baseline_period(),
8655 deviation_threshold_std: default_deviation_threshold(),
8656 frequency_deviation_threshold: default_frequency_deviation(),
8657 }
8658 }
8659}
8660
8661#[derive(Debug, Clone, Serialize, Deserialize)]
8663pub struct EnhancedLabelingConfig {
8664 #[serde(default = "default_true_val")]
8666 pub severity_scoring: bool,
8667
8668 #[serde(default = "default_true_val")]
8670 pub difficulty_classification: bool,
8671
8672 #[serde(default)]
8674 pub materiality_thresholds: MaterialityThresholdsConfig,
8675}
8676
8677impl Default for EnhancedLabelingConfig {
8678 fn default() -> Self {
8679 Self {
8680 severity_scoring: true,
8681 difficulty_classification: true,
8682 materiality_thresholds: MaterialityThresholdsConfig::default(),
8683 }
8684 }
8685}
8686
8687#[derive(Debug, Clone, Serialize, Deserialize)]
8689pub struct MaterialityThresholdsConfig {
8690 #[serde(default = "default_materiality_trivial")]
8692 pub trivial: f64,
8693
8694 #[serde(default = "default_materiality_immaterial")]
8696 pub immaterial: f64,
8697
8698 #[serde(default = "default_materiality_material")]
8700 pub material: f64,
8701
8702 #[serde(default = "default_materiality_highly_material")]
8704 pub highly_material: f64,
8705}
8706
8707fn default_materiality_trivial() -> f64 {
8708 0.001
8709}
8710fn default_materiality_immaterial() -> f64 {
8711 0.01
8712}
8713fn default_materiality_material() -> f64 {
8714 0.05
8715}
8716fn default_materiality_highly_material() -> f64 {
8717 0.10
8718}
8719
8720impl Default for MaterialityThresholdsConfig {
8721 fn default() -> Self {
8722 Self {
8723 trivial: default_materiality_trivial(),
8724 immaterial: default_materiality_immaterial(),
8725 material: default_materiality_material(),
8726 highly_material: default_materiality_highly_material(),
8727 }
8728 }
8729}
8730
8731#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8743pub struct IndustrySpecificConfig {
8744 #[serde(default)]
8746 pub enabled: bool,
8747
8748 #[serde(default)]
8750 pub manufacturing: ManufacturingConfig,
8751
8752 #[serde(default)]
8754 pub retail: RetailConfig,
8755
8756 #[serde(default)]
8758 pub healthcare: HealthcareConfig,
8759
8760 #[serde(default)]
8762 pub technology: TechnologyConfig,
8763
8764 #[serde(default)]
8766 pub financial_services: FinancialServicesConfig,
8767
8768 #[serde(default)]
8770 pub professional_services: ProfessionalServicesConfig,
8771}
8772
8773#[derive(Debug, Clone, Serialize, Deserialize)]
8775pub struct ManufacturingConfig {
8776 #[serde(default)]
8778 pub enabled: bool,
8779
8780 #[serde(default = "default_bom_depth")]
8782 pub bom_depth: u32,
8783
8784 #[serde(default)]
8786 pub just_in_time: bool,
8787
8788 #[serde(default = "default_production_order_types")]
8790 pub production_order_types: Vec<String>,
8791
8792 #[serde(default)]
8794 pub quality_framework: Option<String>,
8795
8796 #[serde(default = "default_supplier_tiers")]
8798 pub supplier_tiers: u32,
8799
8800 #[serde(default = "default_cost_frequency")]
8802 pub standard_cost_frequency: String,
8803
8804 #[serde(default = "default_yield_rate")]
8806 pub target_yield_rate: f64,
8807
8808 #[serde(default = "default_scrap_threshold")]
8810 pub scrap_alert_threshold: f64,
8811
8812 #[serde(default)]
8814 pub anomaly_rates: ManufacturingAnomalyRates,
8815}
8816
8817fn default_bom_depth() -> u32 {
8818 4
8819}
8820
8821fn default_production_order_types() -> Vec<String> {
8822 vec![
8823 "standard".to_string(),
8824 "rework".to_string(),
8825 "prototype".to_string(),
8826 ]
8827}
8828
8829fn default_supplier_tiers() -> u32 {
8830 2
8831}
8832
8833fn default_cost_frequency() -> String {
8834 "quarterly".to_string()
8835}
8836
8837fn default_yield_rate() -> f64 {
8838 0.97
8839}
8840
8841fn default_scrap_threshold() -> f64 {
8842 0.03
8843}
8844
8845impl Default for ManufacturingConfig {
8846 fn default() -> Self {
8847 Self {
8848 enabled: false,
8849 bom_depth: default_bom_depth(),
8850 just_in_time: false,
8851 production_order_types: default_production_order_types(),
8852 quality_framework: Some("ISO_9001".to_string()),
8853 supplier_tiers: default_supplier_tiers(),
8854 standard_cost_frequency: default_cost_frequency(),
8855 target_yield_rate: default_yield_rate(),
8856 scrap_alert_threshold: default_scrap_threshold(),
8857 anomaly_rates: ManufacturingAnomalyRates::default(),
8858 }
8859 }
8860}
8861
8862#[derive(Debug, Clone, Serialize, Deserialize)]
8864pub struct ManufacturingAnomalyRates {
8865 #[serde(default = "default_mfg_yield_rate")]
8867 pub yield_manipulation: f64,
8868
8869 #[serde(default = "default_mfg_labor_rate")]
8871 pub labor_misallocation: f64,
8872
8873 #[serde(default = "default_mfg_phantom_rate")]
8875 pub phantom_production: f64,
8876
8877 #[serde(default = "default_mfg_cost_rate")]
8879 pub standard_cost_manipulation: f64,
8880
8881 #[serde(default = "default_mfg_inventory_rate")]
8883 pub inventory_fraud: f64,
8884}
8885
8886fn default_mfg_yield_rate() -> f64 {
8887 0.015
8888}
8889
8890fn default_mfg_labor_rate() -> f64 {
8891 0.02
8892}
8893
8894fn default_mfg_phantom_rate() -> f64 {
8895 0.005
8896}
8897
8898fn default_mfg_cost_rate() -> f64 {
8899 0.01
8900}
8901
8902fn default_mfg_inventory_rate() -> f64 {
8903 0.008
8904}
8905
8906impl Default for ManufacturingAnomalyRates {
8907 fn default() -> Self {
8908 Self {
8909 yield_manipulation: default_mfg_yield_rate(),
8910 labor_misallocation: default_mfg_labor_rate(),
8911 phantom_production: default_mfg_phantom_rate(),
8912 standard_cost_manipulation: default_mfg_cost_rate(),
8913 inventory_fraud: default_mfg_inventory_rate(),
8914 }
8915 }
8916}
8917
8918#[derive(Debug, Clone, Serialize, Deserialize)]
8920pub struct RetailConfig {
8921 #[serde(default)]
8923 pub enabled: bool,
8924
8925 #[serde(default)]
8927 pub store_types: RetailStoreTypeConfig,
8928
8929 #[serde(default = "default_retail_daily_txns")]
8931 pub avg_daily_transactions: u32,
8932
8933 #[serde(default = "default_true")]
8935 pub loss_prevention: bool,
8936
8937 #[serde(default = "default_shrinkage_rate")]
8939 pub shrinkage_rate: f64,
8940
8941 #[serde(default)]
8943 pub anomaly_rates: RetailAnomalyRates,
8944}
8945
8946fn default_retail_daily_txns() -> u32 {
8947 500
8948}
8949
8950fn default_shrinkage_rate() -> f64 {
8951 0.015
8952}
8953
8954impl Default for RetailConfig {
8955 fn default() -> Self {
8956 Self {
8957 enabled: false,
8958 store_types: RetailStoreTypeConfig::default(),
8959 avg_daily_transactions: default_retail_daily_txns(),
8960 loss_prevention: true,
8961 shrinkage_rate: default_shrinkage_rate(),
8962 anomaly_rates: RetailAnomalyRates::default(),
8963 }
8964 }
8965}
8966
8967#[derive(Debug, Clone, Serialize, Deserialize)]
8969pub struct RetailStoreTypeConfig {
8970 #[serde(default = "default_flagship_pct")]
8972 pub flagship: f64,
8973
8974 #[serde(default = "default_regional_pct")]
8976 pub regional: f64,
8977
8978 #[serde(default = "default_outlet_pct")]
8980 pub outlet: f64,
8981
8982 #[serde(default = "default_ecommerce_pct")]
8984 pub ecommerce: f64,
8985}
8986
8987fn default_flagship_pct() -> f64 {
8988 0.10
8989}
8990
8991fn default_regional_pct() -> f64 {
8992 0.50
8993}
8994
8995fn default_outlet_pct() -> f64 {
8996 0.25
8997}
8998
8999fn default_ecommerce_pct() -> f64 {
9000 0.15
9001}
9002
9003impl Default for RetailStoreTypeConfig {
9004 fn default() -> Self {
9005 Self {
9006 flagship: default_flagship_pct(),
9007 regional: default_regional_pct(),
9008 outlet: default_outlet_pct(),
9009 ecommerce: default_ecommerce_pct(),
9010 }
9011 }
9012}
9013
9014#[derive(Debug, Clone, Serialize, Deserialize)]
9016pub struct RetailAnomalyRates {
9017 #[serde(default = "default_sweethearting_rate")]
9019 pub sweethearting: f64,
9020
9021 #[serde(default = "default_skimming_rate")]
9023 pub skimming: f64,
9024
9025 #[serde(default = "default_refund_fraud_rate")]
9027 pub refund_fraud: f64,
9028
9029 #[serde(default = "default_void_abuse_rate")]
9031 pub void_abuse: f64,
9032
9033 #[serde(default = "default_gift_card_rate")]
9035 pub gift_card_fraud: f64,
9036
9037 #[serde(default = "default_retail_kickback_rate")]
9039 pub vendor_kickback: f64,
9040}
9041
9042fn default_sweethearting_rate() -> f64 {
9043 0.02
9044}
9045
9046fn default_skimming_rate() -> f64 {
9047 0.005
9048}
9049
9050fn default_refund_fraud_rate() -> f64 {
9051 0.015
9052}
9053
9054fn default_void_abuse_rate() -> f64 {
9055 0.01
9056}
9057
9058fn default_gift_card_rate() -> f64 {
9059 0.008
9060}
9061
9062fn default_retail_kickback_rate() -> f64 {
9063 0.003
9064}
9065
9066impl Default for RetailAnomalyRates {
9067 fn default() -> Self {
9068 Self {
9069 sweethearting: default_sweethearting_rate(),
9070 skimming: default_skimming_rate(),
9071 refund_fraud: default_refund_fraud_rate(),
9072 void_abuse: default_void_abuse_rate(),
9073 gift_card_fraud: default_gift_card_rate(),
9074 vendor_kickback: default_retail_kickback_rate(),
9075 }
9076 }
9077}
9078
9079#[derive(Debug, Clone, Serialize, Deserialize)]
9081pub struct HealthcareConfig {
9082 #[serde(default)]
9084 pub enabled: bool,
9085
9086 #[serde(default = "default_facility_type")]
9088 pub facility_type: String,
9089
9090 #[serde(default)]
9092 pub payer_mix: HealthcarePayerMix,
9093
9094 #[serde(default)]
9096 pub coding_systems: HealthcareCodingSystems,
9097
9098 #[serde(default)]
9100 pub compliance: HealthcareComplianceConfig,
9101
9102 #[serde(default = "default_daily_encounters")]
9104 pub avg_daily_encounters: u32,
9105
9106 #[serde(default = "default_charges_per_encounter")]
9108 pub avg_charges_per_encounter: u32,
9109
9110 #[serde(default = "default_hc_denial_rate")]
9112 pub denial_rate: f64,
9113
9114 #[serde(default = "default_hc_bad_debt_rate")]
9116 pub bad_debt_rate: f64,
9117
9118 #[serde(default = "default_hc_charity_care_rate")]
9120 pub charity_care_rate: f64,
9121
9122 #[serde(default)]
9124 pub anomaly_rates: HealthcareAnomalyRates,
9125}
9126
9127fn default_facility_type() -> String {
9128 "hospital".to_string()
9129}
9130
9131fn default_daily_encounters() -> u32 {
9132 150
9133}
9134
9135fn default_charges_per_encounter() -> u32 {
9136 8
9137}
9138
9139fn default_hc_denial_rate() -> f64 {
9140 0.05
9141}
9142
9143fn default_hc_bad_debt_rate() -> f64 {
9144 0.03
9145}
9146
9147fn default_hc_charity_care_rate() -> f64 {
9148 0.02
9149}
9150
9151impl Default for HealthcareConfig {
9152 fn default() -> Self {
9153 Self {
9154 enabled: false,
9155 facility_type: default_facility_type(),
9156 payer_mix: HealthcarePayerMix::default(),
9157 coding_systems: HealthcareCodingSystems::default(),
9158 compliance: HealthcareComplianceConfig::default(),
9159 avg_daily_encounters: default_daily_encounters(),
9160 avg_charges_per_encounter: default_charges_per_encounter(),
9161 denial_rate: default_hc_denial_rate(),
9162 bad_debt_rate: default_hc_bad_debt_rate(),
9163 charity_care_rate: default_hc_charity_care_rate(),
9164 anomaly_rates: HealthcareAnomalyRates::default(),
9165 }
9166 }
9167}
9168
9169#[derive(Debug, Clone, Serialize, Deserialize)]
9171pub struct HealthcarePayerMix {
9172 #[serde(default = "default_medicare_pct")]
9174 pub medicare: f64,
9175
9176 #[serde(default = "default_medicaid_pct")]
9178 pub medicaid: f64,
9179
9180 #[serde(default = "default_commercial_pct")]
9182 pub commercial: f64,
9183
9184 #[serde(default = "default_self_pay_pct")]
9186 pub self_pay: f64,
9187}
9188
9189fn default_medicare_pct() -> f64 {
9190 0.40
9191}
9192
9193fn default_medicaid_pct() -> f64 {
9194 0.20
9195}
9196
9197fn default_commercial_pct() -> f64 {
9198 0.30
9199}
9200
9201fn default_self_pay_pct() -> f64 {
9202 0.10
9203}
9204
9205impl Default for HealthcarePayerMix {
9206 fn default() -> Self {
9207 Self {
9208 medicare: default_medicare_pct(),
9209 medicaid: default_medicaid_pct(),
9210 commercial: default_commercial_pct(),
9211 self_pay: default_self_pay_pct(),
9212 }
9213 }
9214}
9215
9216#[derive(Debug, Clone, Serialize, Deserialize)]
9218pub struct HealthcareCodingSystems {
9219 #[serde(default = "default_true")]
9221 pub icd10: bool,
9222
9223 #[serde(default = "default_true")]
9225 pub cpt: bool,
9226
9227 #[serde(default = "default_true")]
9229 pub drg: bool,
9230
9231 #[serde(default = "default_true")]
9233 pub hcpcs: bool,
9234
9235 #[serde(default = "default_true")]
9237 pub revenue_codes: bool,
9238}
9239
9240impl Default for HealthcareCodingSystems {
9241 fn default() -> Self {
9242 Self {
9243 icd10: true,
9244 cpt: true,
9245 drg: true,
9246 hcpcs: true,
9247 revenue_codes: true,
9248 }
9249 }
9250}
9251
9252#[derive(Debug, Clone, Serialize, Deserialize)]
9254pub struct HealthcareComplianceConfig {
9255 #[serde(default = "default_true")]
9257 pub hipaa: bool,
9258
9259 #[serde(default = "default_true")]
9261 pub stark_law: bool,
9262
9263 #[serde(default = "default_true")]
9265 pub anti_kickback: bool,
9266
9267 #[serde(default = "default_true")]
9269 pub false_claims_act: bool,
9270
9271 #[serde(default = "default_true")]
9273 pub emtala: bool,
9274}
9275
9276impl Default for HealthcareComplianceConfig {
9277 fn default() -> Self {
9278 Self {
9279 hipaa: true,
9280 stark_law: true,
9281 anti_kickback: true,
9282 false_claims_act: true,
9283 emtala: true,
9284 }
9285 }
9286}
9287
9288#[derive(Debug, Clone, Serialize, Deserialize)]
9290pub struct HealthcareAnomalyRates {
9291 #[serde(default = "default_upcoding_rate")]
9293 pub upcoding: f64,
9294
9295 #[serde(default = "default_unbundling_rate")]
9297 pub unbundling: f64,
9298
9299 #[serde(default = "default_phantom_billing_rate")]
9301 pub phantom_billing: f64,
9302
9303 #[serde(default = "default_healthcare_kickback_rate")]
9305 pub kickbacks: f64,
9306
9307 #[serde(default = "default_duplicate_billing_rate")]
9309 pub duplicate_billing: f64,
9310
9311 #[serde(default = "default_med_necessity_rate")]
9313 pub medical_necessity_abuse: f64,
9314}
9315
9316fn default_upcoding_rate() -> f64 {
9317 0.02
9318}
9319
9320fn default_unbundling_rate() -> f64 {
9321 0.015
9322}
9323
9324fn default_phantom_billing_rate() -> f64 {
9325 0.005
9326}
9327
9328fn default_healthcare_kickback_rate() -> f64 {
9329 0.003
9330}
9331
9332fn default_duplicate_billing_rate() -> f64 {
9333 0.008
9334}
9335
9336fn default_med_necessity_rate() -> f64 {
9337 0.01
9338}
9339
9340impl Default for HealthcareAnomalyRates {
9341 fn default() -> Self {
9342 Self {
9343 upcoding: default_upcoding_rate(),
9344 unbundling: default_unbundling_rate(),
9345 phantom_billing: default_phantom_billing_rate(),
9346 kickbacks: default_healthcare_kickback_rate(),
9347 duplicate_billing: default_duplicate_billing_rate(),
9348 medical_necessity_abuse: default_med_necessity_rate(),
9349 }
9350 }
9351}
9352
9353#[derive(Debug, Clone, Serialize, Deserialize)]
9355pub struct TechnologyConfig {
9356 #[serde(default)]
9358 pub enabled: bool,
9359
9360 #[serde(default = "default_revenue_model")]
9362 pub revenue_model: String,
9363
9364 #[serde(default = "default_subscription_pct")]
9366 pub subscription_revenue_pct: f64,
9367
9368 #[serde(default = "default_license_pct")]
9370 pub license_revenue_pct: f64,
9371
9372 #[serde(default = "default_services_pct")]
9374 pub services_revenue_pct: f64,
9375
9376 #[serde(default)]
9378 pub rd_capitalization: RdCapitalizationConfig,
9379
9380 #[serde(default)]
9382 pub anomaly_rates: TechnologyAnomalyRates,
9383}
9384
9385fn default_revenue_model() -> String {
9386 "saas".to_string()
9387}
9388
9389fn default_subscription_pct() -> f64 {
9390 0.60
9391}
9392
9393fn default_license_pct() -> f64 {
9394 0.25
9395}
9396
9397fn default_services_pct() -> f64 {
9398 0.15
9399}
9400
9401impl Default for TechnologyConfig {
9402 fn default() -> Self {
9403 Self {
9404 enabled: false,
9405 revenue_model: default_revenue_model(),
9406 subscription_revenue_pct: default_subscription_pct(),
9407 license_revenue_pct: default_license_pct(),
9408 services_revenue_pct: default_services_pct(),
9409 rd_capitalization: RdCapitalizationConfig::default(),
9410 anomaly_rates: TechnologyAnomalyRates::default(),
9411 }
9412 }
9413}
9414
9415#[derive(Debug, Clone, Serialize, Deserialize)]
9417pub struct RdCapitalizationConfig {
9418 #[serde(default = "default_true")]
9420 pub enabled: bool,
9421
9422 #[serde(default = "default_cap_rate")]
9424 pub capitalization_rate: f64,
9425
9426 #[serde(default = "default_useful_life")]
9428 pub useful_life_years: u32,
9429}
9430
9431fn default_cap_rate() -> f64 {
9432 0.30
9433}
9434
9435fn default_useful_life() -> u32 {
9436 3
9437}
9438
9439impl Default for RdCapitalizationConfig {
9440 fn default() -> Self {
9441 Self {
9442 enabled: true,
9443 capitalization_rate: default_cap_rate(),
9444 useful_life_years: default_useful_life(),
9445 }
9446 }
9447}
9448
9449#[derive(Debug, Clone, Serialize, Deserialize)]
9451pub struct TechnologyAnomalyRates {
9452 #[serde(default = "default_premature_rev_rate")]
9454 pub premature_revenue: f64,
9455
9456 #[serde(default = "default_side_letter_rate")]
9458 pub side_letter_abuse: f64,
9459
9460 #[serde(default = "default_channel_stuffing_rate")]
9462 pub channel_stuffing: f64,
9463
9464 #[serde(default = "default_improper_cap_rate")]
9466 pub improper_capitalization: f64,
9467}
9468
9469fn default_premature_rev_rate() -> f64 {
9470 0.015
9471}
9472
9473fn default_side_letter_rate() -> f64 {
9474 0.008
9475}
9476
9477fn default_channel_stuffing_rate() -> f64 {
9478 0.01
9479}
9480
9481fn default_improper_cap_rate() -> f64 {
9482 0.012
9483}
9484
9485impl Default for TechnologyAnomalyRates {
9486 fn default() -> Self {
9487 Self {
9488 premature_revenue: default_premature_rev_rate(),
9489 side_letter_abuse: default_side_letter_rate(),
9490 channel_stuffing: default_channel_stuffing_rate(),
9491 improper_capitalization: default_improper_cap_rate(),
9492 }
9493 }
9494}
9495
9496#[derive(Debug, Clone, Serialize, Deserialize)]
9498pub struct FinancialServicesConfig {
9499 #[serde(default)]
9501 pub enabled: bool,
9502
9503 #[serde(default = "default_fi_type")]
9505 pub institution_type: String,
9506
9507 #[serde(default = "default_fi_regulatory")]
9509 pub regulatory_framework: String,
9510
9511 #[serde(default)]
9513 pub anomaly_rates: FinancialServicesAnomalyRates,
9514}
9515
9516fn default_fi_type() -> String {
9517 "commercial_bank".to_string()
9518}
9519
9520fn default_fi_regulatory() -> String {
9521 "us_banking".to_string()
9522}
9523
9524impl Default for FinancialServicesConfig {
9525 fn default() -> Self {
9526 Self {
9527 enabled: false,
9528 institution_type: default_fi_type(),
9529 regulatory_framework: default_fi_regulatory(),
9530 anomaly_rates: FinancialServicesAnomalyRates::default(),
9531 }
9532 }
9533}
9534
9535#[derive(Debug, Clone, Serialize, Deserialize)]
9537pub struct FinancialServicesAnomalyRates {
9538 #[serde(default = "default_loan_fraud_rate")]
9540 pub loan_fraud: f64,
9541
9542 #[serde(default = "default_trading_fraud_rate")]
9544 pub trading_fraud: f64,
9545
9546 #[serde(default = "default_insurance_fraud_rate")]
9548 pub insurance_fraud: f64,
9549
9550 #[serde(default = "default_account_manip_rate")]
9552 pub account_manipulation: f64,
9553}
9554
9555fn default_loan_fraud_rate() -> f64 {
9556 0.01
9557}
9558
9559fn default_trading_fraud_rate() -> f64 {
9560 0.008
9561}
9562
9563fn default_insurance_fraud_rate() -> f64 {
9564 0.012
9565}
9566
9567fn default_account_manip_rate() -> f64 {
9568 0.005
9569}
9570
9571impl Default for FinancialServicesAnomalyRates {
9572 fn default() -> Self {
9573 Self {
9574 loan_fraud: default_loan_fraud_rate(),
9575 trading_fraud: default_trading_fraud_rate(),
9576 insurance_fraud: default_insurance_fraud_rate(),
9577 account_manipulation: default_account_manip_rate(),
9578 }
9579 }
9580}
9581
9582#[derive(Debug, Clone, Serialize, Deserialize)]
9584pub struct ProfessionalServicesConfig {
9585 #[serde(default)]
9587 pub enabled: bool,
9588
9589 #[serde(default = "default_firm_type")]
9591 pub firm_type: String,
9592
9593 #[serde(default = "default_billing_model")]
9595 pub billing_model: String,
9596
9597 #[serde(default = "default_hourly_rate")]
9599 pub avg_hourly_rate: f64,
9600
9601 #[serde(default)]
9603 pub trust_accounting: TrustAccountingConfig,
9604
9605 #[serde(default)]
9607 pub anomaly_rates: ProfessionalServicesAnomalyRates,
9608}
9609
9610fn default_firm_type() -> String {
9611 "consulting".to_string()
9612}
9613
9614fn default_billing_model() -> String {
9615 "time_and_materials".to_string()
9616}
9617
9618fn default_hourly_rate() -> f64 {
9619 250.0
9620}
9621
9622impl Default for ProfessionalServicesConfig {
9623 fn default() -> Self {
9624 Self {
9625 enabled: false,
9626 firm_type: default_firm_type(),
9627 billing_model: default_billing_model(),
9628 avg_hourly_rate: default_hourly_rate(),
9629 trust_accounting: TrustAccountingConfig::default(),
9630 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9631 }
9632 }
9633}
9634
9635#[derive(Debug, Clone, Serialize, Deserialize)]
9637pub struct TrustAccountingConfig {
9638 #[serde(default)]
9640 pub enabled: bool,
9641
9642 #[serde(default = "default_true")]
9644 pub require_three_way_reconciliation: bool,
9645}
9646
9647impl Default for TrustAccountingConfig {
9648 fn default() -> Self {
9649 Self {
9650 enabled: false,
9651 require_three_way_reconciliation: true,
9652 }
9653 }
9654}
9655
9656#[derive(Debug, Clone, Serialize, Deserialize)]
9658pub struct ProfessionalServicesAnomalyRates {
9659 #[serde(default = "default_time_fraud_rate")]
9661 pub time_billing_fraud: f64,
9662
9663 #[serde(default = "default_expense_fraud_rate")]
9665 pub expense_fraud: f64,
9666
9667 #[serde(default = "default_trust_misappropriation_rate")]
9669 pub trust_misappropriation: f64,
9670}
9671
9672fn default_time_fraud_rate() -> f64 {
9673 0.02
9674}
9675
9676fn default_expense_fraud_rate() -> f64 {
9677 0.015
9678}
9679
9680fn default_trust_misappropriation_rate() -> f64 {
9681 0.003
9682}
9683
9684impl Default for ProfessionalServicesAnomalyRates {
9685 fn default() -> Self {
9686 Self {
9687 time_billing_fraud: default_time_fraud_rate(),
9688 expense_fraud: default_expense_fraud_rate(),
9689 trust_misappropriation: default_trust_misappropriation_rate(),
9690 }
9691 }
9692}
9693
9694#[derive(Debug, Clone, Serialize, Deserialize)]
9708pub struct FingerprintPrivacyConfig {
9709 #[serde(default)]
9711 pub level: String,
9712 #[serde(default = "default_epsilon")]
9714 pub epsilon: f64,
9715 #[serde(default = "default_delta")]
9717 pub delta: f64,
9718 #[serde(default = "default_k_anonymity")]
9720 pub k_anonymity: u32,
9721 #[serde(default)]
9723 pub composition_method: String,
9724}
9725
9726fn default_epsilon() -> f64 {
9727 1.0
9728}
9729
9730fn default_delta() -> f64 {
9731 1e-5
9732}
9733
9734fn default_k_anonymity() -> u32 {
9735 5
9736}
9737
9738impl Default for FingerprintPrivacyConfig {
9739 fn default() -> Self {
9740 Self {
9741 level: "standard".to_string(),
9742 epsilon: default_epsilon(),
9743 delta: default_delta(),
9744 k_anonymity: default_k_anonymity(),
9745 composition_method: "naive".to_string(),
9746 }
9747 }
9748}
9749
9750#[derive(Debug, Clone, Serialize, Deserialize)]
9764pub struct QualityGatesSchemaConfig {
9765 #[serde(default)]
9767 pub enabled: bool,
9768 #[serde(default = "default_gate_profile_name")]
9770 pub profile: String,
9771 #[serde(default)]
9773 pub fail_on_violation: bool,
9774 #[serde(default)]
9776 pub custom_gates: Vec<QualityGateEntry>,
9777}
9778
9779fn default_gate_profile_name() -> String {
9780 "default".to_string()
9781}
9782
9783impl Default for QualityGatesSchemaConfig {
9784 fn default() -> Self {
9785 Self {
9786 enabled: false,
9787 profile: default_gate_profile_name(),
9788 fail_on_violation: false,
9789 custom_gates: Vec::new(),
9790 }
9791 }
9792}
9793
9794#[derive(Debug, Clone, Serialize, Deserialize)]
9796pub struct QualityGateEntry {
9797 pub name: String,
9799 pub metric: String,
9803 pub threshold: f64,
9805 #[serde(default)]
9807 pub upper_threshold: Option<f64>,
9808 #[serde(default = "default_gate_comparison")]
9810 pub comparison: String,
9811}
9812
9813fn default_gate_comparison() -> String {
9814 "gte".to_string()
9815}
9816
9817#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9827pub struct ComplianceSchemaConfig {
9828 #[serde(default)]
9830 pub content_marking: ContentMarkingSchemaConfig,
9831 #[serde(default)]
9833 pub article10_report: bool,
9834 #[serde(default)]
9836 pub certificates: CertificateSchemaConfig,
9837}
9838
9839#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9841pub struct CertificateSchemaConfig {
9842 #[serde(default)]
9844 pub enabled: bool,
9845 #[serde(default)]
9847 pub signing_key_env: Option<String>,
9848 #[serde(default)]
9850 pub include_quality_metrics: bool,
9851}
9852
9853#[derive(Debug, Clone, Serialize, Deserialize)]
9855pub struct ContentMarkingSchemaConfig {
9856 #[serde(default = "default_true")]
9858 pub enabled: bool,
9859 #[serde(default = "default_marking_format")]
9861 pub format: String,
9862}
9863
9864fn default_marking_format() -> String {
9865 "embedded".to_string()
9866}
9867
9868impl Default for ContentMarkingSchemaConfig {
9869 fn default() -> Self {
9870 Self {
9871 enabled: true,
9872 format: default_marking_format(),
9873 }
9874 }
9875}
9876
9877#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9879pub struct WebhookSchemaConfig {
9880 #[serde(default)]
9882 pub enabled: bool,
9883 #[serde(default)]
9885 pub endpoints: Vec<WebhookEndpointConfig>,
9886}
9887
9888#[derive(Debug, Clone, Serialize, Deserialize)]
9890pub struct WebhookEndpointConfig {
9891 pub url: String,
9893 #[serde(default)]
9895 pub events: Vec<String>,
9896 #[serde(default)]
9898 pub secret: Option<String>,
9899 #[serde(default = "default_webhook_retries")]
9901 pub max_retries: u32,
9902 #[serde(default = "default_webhook_timeout")]
9904 pub timeout_secs: u64,
9905}
9906
9907fn default_webhook_retries() -> u32 {
9908 3
9909}
9910fn default_webhook_timeout() -> u64 {
9911 10
9912}
9913
9914#[derive(Debug, Clone, Default, Serialize, Deserialize)]
9920pub struct SourceToPayConfig {
9921 #[serde(default)]
9923 pub enabled: bool,
9924 #[serde(default)]
9926 pub spend_analysis: SpendAnalysisConfig,
9927 #[serde(default)]
9929 pub sourcing: SourcingConfig,
9930 #[serde(default)]
9932 pub qualification: QualificationConfig,
9933 #[serde(default)]
9935 pub rfx: RfxConfig,
9936 #[serde(default)]
9938 pub contracts: ContractConfig,
9939 #[serde(default)]
9941 pub catalog: CatalogConfig,
9942 #[serde(default)]
9944 pub scorecards: ScorecardConfig,
9945 #[serde(default)]
9947 pub p2p_integration: P2PIntegrationConfig,
9948}
9949
9950#[derive(Debug, Clone, Serialize, Deserialize)]
9952pub struct SpendAnalysisConfig {
9953 #[serde(default = "default_hhi_threshold")]
9955 pub hhi_threshold: f64,
9956 #[serde(default = "default_contract_coverage_target")]
9958 pub contract_coverage_target: f64,
9959}
9960
9961impl Default for SpendAnalysisConfig {
9962 fn default() -> Self {
9963 Self {
9964 hhi_threshold: default_hhi_threshold(),
9965 contract_coverage_target: default_contract_coverage_target(),
9966 }
9967 }
9968}
9969
9970fn default_hhi_threshold() -> f64 {
9971 2500.0
9972}
9973fn default_contract_coverage_target() -> f64 {
9974 0.80
9975}
9976
9977#[derive(Debug, Clone, Serialize, Deserialize)]
9979pub struct SourcingConfig {
9980 #[serde(default = "default_sourcing_projects_per_year")]
9982 pub projects_per_year: u32,
9983 #[serde(default = "default_renewal_horizon_months")]
9985 pub renewal_horizon_months: u32,
9986 #[serde(default = "default_project_duration_months")]
9988 pub project_duration_months: u32,
9989}
9990
9991impl Default for SourcingConfig {
9992 fn default() -> Self {
9993 Self {
9994 projects_per_year: default_sourcing_projects_per_year(),
9995 renewal_horizon_months: default_renewal_horizon_months(),
9996 project_duration_months: default_project_duration_months(),
9997 }
9998 }
9999}
10000
10001fn default_sourcing_projects_per_year() -> u32 {
10002 10
10003}
10004fn default_renewal_horizon_months() -> u32 {
10005 3
10006}
10007fn default_project_duration_months() -> u32 {
10008 4
10009}
10010
10011#[derive(Debug, Clone, Serialize, Deserialize)]
10013pub struct QualificationConfig {
10014 #[serde(default = "default_qualification_pass_rate")]
10016 pub pass_rate: f64,
10017 #[serde(default = "default_qualification_validity_days")]
10019 pub validity_days: u32,
10020 #[serde(default = "default_financial_weight")]
10022 pub financial_weight: f64,
10023 #[serde(default = "default_quality_weight")]
10025 pub quality_weight: f64,
10026 #[serde(default = "default_delivery_weight")]
10028 pub delivery_weight: f64,
10029 #[serde(default = "default_compliance_weight")]
10031 pub compliance_weight: f64,
10032}
10033
10034impl Default for QualificationConfig {
10035 fn default() -> Self {
10036 Self {
10037 pass_rate: default_qualification_pass_rate(),
10038 validity_days: default_qualification_validity_days(),
10039 financial_weight: default_financial_weight(),
10040 quality_weight: default_quality_weight(),
10041 delivery_weight: default_delivery_weight(),
10042 compliance_weight: default_compliance_weight(),
10043 }
10044 }
10045}
10046
10047fn default_qualification_pass_rate() -> f64 {
10048 0.75
10049}
10050fn default_qualification_validity_days() -> u32 {
10051 365
10052}
10053fn default_financial_weight() -> f64 {
10054 0.25
10055}
10056fn default_quality_weight() -> f64 {
10057 0.30
10058}
10059fn default_delivery_weight() -> f64 {
10060 0.25
10061}
10062fn default_compliance_weight() -> f64 {
10063 0.20
10064}
10065
10066#[derive(Debug, Clone, Serialize, Deserialize)]
10068pub struct RfxConfig {
10069 #[serde(default = "default_rfi_threshold")]
10071 pub rfi_threshold: f64,
10072 #[serde(default = "default_min_invited_vendors")]
10074 pub min_invited_vendors: u32,
10075 #[serde(default = "default_max_invited_vendors")]
10077 pub max_invited_vendors: u32,
10078 #[serde(default = "default_response_rate")]
10080 pub response_rate: f64,
10081 #[serde(default = "default_price_weight")]
10083 pub default_price_weight: f64,
10084 #[serde(default = "default_rfx_quality_weight")]
10086 pub default_quality_weight: f64,
10087 #[serde(default = "default_rfx_delivery_weight")]
10089 pub default_delivery_weight: f64,
10090}
10091
10092impl Default for RfxConfig {
10093 fn default() -> Self {
10094 Self {
10095 rfi_threshold: default_rfi_threshold(),
10096 min_invited_vendors: default_min_invited_vendors(),
10097 max_invited_vendors: default_max_invited_vendors(),
10098 response_rate: default_response_rate(),
10099 default_price_weight: default_price_weight(),
10100 default_quality_weight: default_rfx_quality_weight(),
10101 default_delivery_weight: default_rfx_delivery_weight(),
10102 }
10103 }
10104}
10105
10106fn default_rfi_threshold() -> f64 {
10107 100_000.0
10108}
10109fn default_min_invited_vendors() -> u32 {
10110 3
10111}
10112fn default_max_invited_vendors() -> u32 {
10113 8
10114}
10115fn default_response_rate() -> f64 {
10116 0.70
10117}
10118fn default_price_weight() -> f64 {
10119 0.40
10120}
10121fn default_rfx_quality_weight() -> f64 {
10122 0.35
10123}
10124fn default_rfx_delivery_weight() -> f64 {
10125 0.25
10126}
10127
10128#[derive(Debug, Clone, Serialize, Deserialize)]
10130pub struct ContractConfig {
10131 #[serde(default = "default_min_contract_months")]
10133 pub min_duration_months: u32,
10134 #[serde(default = "default_max_contract_months")]
10136 pub max_duration_months: u32,
10137 #[serde(default = "default_auto_renewal_rate")]
10139 pub auto_renewal_rate: f64,
10140 #[serde(default = "default_amendment_rate")]
10142 pub amendment_rate: f64,
10143 #[serde(default)]
10145 pub type_distribution: ContractTypeDistribution,
10146}
10147
10148impl Default for ContractConfig {
10149 fn default() -> Self {
10150 Self {
10151 min_duration_months: default_min_contract_months(),
10152 max_duration_months: default_max_contract_months(),
10153 auto_renewal_rate: default_auto_renewal_rate(),
10154 amendment_rate: default_amendment_rate(),
10155 type_distribution: ContractTypeDistribution::default(),
10156 }
10157 }
10158}
10159
10160fn default_min_contract_months() -> u32 {
10161 12
10162}
10163fn default_max_contract_months() -> u32 {
10164 36
10165}
10166fn default_auto_renewal_rate() -> f64 {
10167 0.40
10168}
10169fn default_amendment_rate() -> f64 {
10170 0.20
10171}
10172
10173#[derive(Debug, Clone, Serialize, Deserialize)]
10175pub struct ContractTypeDistribution {
10176 #[serde(default = "default_fixed_price_pct")]
10178 pub fixed_price: f64,
10179 #[serde(default = "default_blanket_pct")]
10181 pub blanket: f64,
10182 #[serde(default = "default_time_materials_pct")]
10184 pub time_and_materials: f64,
10185 #[serde(default = "default_service_agreement_pct")]
10187 pub service_agreement: f64,
10188}
10189
10190impl Default for ContractTypeDistribution {
10191 fn default() -> Self {
10192 Self {
10193 fixed_price: default_fixed_price_pct(),
10194 blanket: default_blanket_pct(),
10195 time_and_materials: default_time_materials_pct(),
10196 service_agreement: default_service_agreement_pct(),
10197 }
10198 }
10199}
10200
10201fn default_fixed_price_pct() -> f64 {
10202 0.40
10203}
10204fn default_blanket_pct() -> f64 {
10205 0.30
10206}
10207fn default_time_materials_pct() -> f64 {
10208 0.15
10209}
10210fn default_service_agreement_pct() -> f64 {
10211 0.15
10212}
10213
10214#[derive(Debug, Clone, Serialize, Deserialize)]
10216pub struct CatalogConfig {
10217 #[serde(default = "default_preferred_vendor_flag_rate")]
10219 pub preferred_vendor_flag_rate: f64,
10220 #[serde(default = "default_multi_source_rate")]
10222 pub multi_source_rate: f64,
10223}
10224
10225impl Default for CatalogConfig {
10226 fn default() -> Self {
10227 Self {
10228 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
10229 multi_source_rate: default_multi_source_rate(),
10230 }
10231 }
10232}
10233
10234fn default_preferred_vendor_flag_rate() -> f64 {
10235 0.70
10236}
10237fn default_multi_source_rate() -> f64 {
10238 0.25
10239}
10240
10241#[derive(Debug, Clone, Serialize, Deserialize)]
10243pub struct ScorecardConfig {
10244 #[serde(default = "default_scorecard_frequency")]
10246 pub frequency: String,
10247 #[serde(default = "default_otd_weight")]
10249 pub on_time_delivery_weight: f64,
10250 #[serde(default = "default_quality_score_weight")]
10252 pub quality_weight: f64,
10253 #[serde(default = "default_price_score_weight")]
10255 pub price_weight: f64,
10256 #[serde(default = "default_responsiveness_weight")]
10258 pub responsiveness_weight: f64,
10259 #[serde(default = "default_grade_a_threshold")]
10261 pub grade_a_threshold: f64,
10262 #[serde(default = "default_grade_b_threshold")]
10264 pub grade_b_threshold: f64,
10265 #[serde(default = "default_grade_c_threshold")]
10267 pub grade_c_threshold: f64,
10268}
10269
10270impl Default for ScorecardConfig {
10271 fn default() -> Self {
10272 Self {
10273 frequency: default_scorecard_frequency(),
10274 on_time_delivery_weight: default_otd_weight(),
10275 quality_weight: default_quality_score_weight(),
10276 price_weight: default_price_score_weight(),
10277 responsiveness_weight: default_responsiveness_weight(),
10278 grade_a_threshold: default_grade_a_threshold(),
10279 grade_b_threshold: default_grade_b_threshold(),
10280 grade_c_threshold: default_grade_c_threshold(),
10281 }
10282 }
10283}
10284
10285fn default_scorecard_frequency() -> String {
10286 "quarterly".to_string()
10287}
10288fn default_otd_weight() -> f64 {
10289 0.30
10290}
10291fn default_quality_score_weight() -> f64 {
10292 0.30
10293}
10294fn default_price_score_weight() -> f64 {
10295 0.25
10296}
10297fn default_responsiveness_weight() -> f64 {
10298 0.15
10299}
10300fn default_grade_a_threshold() -> f64 {
10301 90.0
10302}
10303fn default_grade_b_threshold() -> f64 {
10304 75.0
10305}
10306fn default_grade_c_threshold() -> f64 {
10307 60.0
10308}
10309
10310#[derive(Debug, Clone, Serialize, Deserialize)]
10312pub struct P2PIntegrationConfig {
10313 #[serde(default = "default_off_contract_rate")]
10315 pub off_contract_rate: f64,
10316 #[serde(default = "default_price_tolerance")]
10318 pub price_tolerance: f64,
10319 #[serde(default)]
10321 pub catalog_enforcement: bool,
10322}
10323
10324impl Default for P2PIntegrationConfig {
10325 fn default() -> Self {
10326 Self {
10327 off_contract_rate: default_off_contract_rate(),
10328 price_tolerance: default_price_tolerance(),
10329 catalog_enforcement: false,
10330 }
10331 }
10332}
10333
10334fn default_off_contract_rate() -> f64 {
10335 0.15
10336}
10337fn default_price_tolerance() -> f64 {
10338 0.02
10339}
10340
10341#[derive(Debug, Clone, Serialize, Deserialize)]
10345pub struct FinancialReportingConfig {
10346 #[serde(default)]
10348 pub enabled: bool,
10349 #[serde(default = "default_true")]
10351 pub generate_balance_sheet: bool,
10352 #[serde(default = "default_true")]
10354 pub generate_income_statement: bool,
10355 #[serde(default = "default_true")]
10357 pub generate_cash_flow: bool,
10358 #[serde(default = "default_true")]
10360 pub generate_changes_in_equity: bool,
10361 #[serde(default = "default_comparative_periods")]
10363 pub comparative_periods: u32,
10364 #[serde(default)]
10366 pub management_kpis: ManagementKpisConfig,
10367 #[serde(default)]
10369 pub budgets: BudgetConfig,
10370}
10371
10372impl Default for FinancialReportingConfig {
10373 fn default() -> Self {
10374 Self {
10375 enabled: false,
10376 generate_balance_sheet: true,
10377 generate_income_statement: true,
10378 generate_cash_flow: true,
10379 generate_changes_in_equity: true,
10380 comparative_periods: default_comparative_periods(),
10381 management_kpis: ManagementKpisConfig::default(),
10382 budgets: BudgetConfig::default(),
10383 }
10384 }
10385}
10386
10387fn default_comparative_periods() -> u32 {
10388 1
10389}
10390
10391#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10393pub struct ManagementKpisConfig {
10394 #[serde(default)]
10396 pub enabled: bool,
10397 #[serde(default = "default_kpi_frequency")]
10399 pub frequency: String,
10400}
10401
10402fn default_kpi_frequency() -> String {
10403 "monthly".to_string()
10404}
10405
10406#[derive(Debug, Clone, Serialize, Deserialize)]
10408pub struct BudgetConfig {
10409 #[serde(default)]
10411 pub enabled: bool,
10412 #[serde(default = "default_revenue_growth_rate")]
10414 pub revenue_growth_rate: f64,
10415 #[serde(default = "default_expense_inflation_rate")]
10417 pub expense_inflation_rate: f64,
10418 #[serde(default = "default_variance_noise")]
10420 pub variance_noise: f64,
10421}
10422
10423impl Default for BudgetConfig {
10424 fn default() -> Self {
10425 Self {
10426 enabled: false,
10427 revenue_growth_rate: default_revenue_growth_rate(),
10428 expense_inflation_rate: default_expense_inflation_rate(),
10429 variance_noise: default_variance_noise(),
10430 }
10431 }
10432}
10433
10434fn default_revenue_growth_rate() -> f64 {
10435 0.05
10436}
10437fn default_expense_inflation_rate() -> f64 {
10438 0.03
10439}
10440fn default_variance_noise() -> f64 {
10441 0.10
10442}
10443
10444#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10448pub struct HrConfig {
10449 #[serde(default)]
10451 pub enabled: bool,
10452 #[serde(default)]
10454 pub payroll: PayrollConfig,
10455 #[serde(default)]
10457 pub time_attendance: TimeAttendanceConfig,
10458 #[serde(default)]
10460 pub expenses: ExpenseConfig,
10461}
10462
10463#[derive(Debug, Clone, Serialize, Deserialize)]
10465pub struct PayrollConfig {
10466 #[serde(default = "default_true")]
10468 pub enabled: bool,
10469 #[serde(default = "default_pay_frequency")]
10471 pub pay_frequency: String,
10472 #[serde(default)]
10474 pub salary_ranges: PayrollSalaryRanges,
10475 #[serde(default)]
10477 pub tax_rates: PayrollTaxRates,
10478 #[serde(default = "default_benefits_enrollment_rate")]
10480 pub benefits_enrollment_rate: f64,
10481 #[serde(default = "default_retirement_participation_rate")]
10483 pub retirement_participation_rate: f64,
10484}
10485
10486impl Default for PayrollConfig {
10487 fn default() -> Self {
10488 Self {
10489 enabled: true,
10490 pay_frequency: default_pay_frequency(),
10491 salary_ranges: PayrollSalaryRanges::default(),
10492 tax_rates: PayrollTaxRates::default(),
10493 benefits_enrollment_rate: default_benefits_enrollment_rate(),
10494 retirement_participation_rate: default_retirement_participation_rate(),
10495 }
10496 }
10497}
10498
10499fn default_pay_frequency() -> String {
10500 "monthly".to_string()
10501}
10502fn default_benefits_enrollment_rate() -> f64 {
10503 0.60
10504}
10505fn default_retirement_participation_rate() -> f64 {
10506 0.45
10507}
10508
10509#[derive(Debug, Clone, Serialize, Deserialize)]
10511pub struct PayrollSalaryRanges {
10512 #[serde(default = "default_staff_min")]
10514 pub staff_min: f64,
10515 #[serde(default = "default_staff_max")]
10516 pub staff_max: f64,
10517 #[serde(default = "default_manager_min")]
10519 pub manager_min: f64,
10520 #[serde(default = "default_manager_max")]
10521 pub manager_max: f64,
10522 #[serde(default = "default_director_min")]
10524 pub director_min: f64,
10525 #[serde(default = "default_director_max")]
10526 pub director_max: f64,
10527 #[serde(default = "default_executive_min")]
10529 pub executive_min: f64,
10530 #[serde(default = "default_executive_max")]
10531 pub executive_max: f64,
10532}
10533
10534impl Default for PayrollSalaryRanges {
10535 fn default() -> Self {
10536 Self {
10537 staff_min: default_staff_min(),
10538 staff_max: default_staff_max(),
10539 manager_min: default_manager_min(),
10540 manager_max: default_manager_max(),
10541 director_min: default_director_min(),
10542 director_max: default_director_max(),
10543 executive_min: default_executive_min(),
10544 executive_max: default_executive_max(),
10545 }
10546 }
10547}
10548
10549fn default_staff_min() -> f64 {
10550 50_000.0
10551}
10552fn default_staff_max() -> f64 {
10553 70_000.0
10554}
10555fn default_manager_min() -> f64 {
10556 80_000.0
10557}
10558fn default_manager_max() -> f64 {
10559 120_000.0
10560}
10561fn default_director_min() -> f64 {
10562 120_000.0
10563}
10564fn default_director_max() -> f64 {
10565 180_000.0
10566}
10567fn default_executive_min() -> f64 {
10568 180_000.0
10569}
10570fn default_executive_max() -> f64 {
10571 350_000.0
10572}
10573
10574#[derive(Debug, Clone, Serialize, Deserialize)]
10576pub struct PayrollTaxRates {
10577 #[serde(default = "default_federal_rate")]
10579 pub federal_effective: f64,
10580 #[serde(default = "default_state_rate")]
10582 pub state_effective: f64,
10583 #[serde(default = "default_fica_rate")]
10585 pub fica: f64,
10586}
10587
10588impl Default for PayrollTaxRates {
10589 fn default() -> Self {
10590 Self {
10591 federal_effective: default_federal_rate(),
10592 state_effective: default_state_rate(),
10593 fica: default_fica_rate(),
10594 }
10595 }
10596}
10597
10598fn default_federal_rate() -> f64 {
10599 0.22
10600}
10601fn default_state_rate() -> f64 {
10602 0.05
10603}
10604fn default_fica_rate() -> f64 {
10605 0.0765
10606}
10607
10608#[derive(Debug, Clone, Serialize, Deserialize)]
10610pub struct TimeAttendanceConfig {
10611 #[serde(default = "default_true")]
10613 pub enabled: bool,
10614 #[serde(default = "default_overtime_rate")]
10616 pub overtime_rate: f64,
10617}
10618
10619impl Default for TimeAttendanceConfig {
10620 fn default() -> Self {
10621 Self {
10622 enabled: true,
10623 overtime_rate: default_overtime_rate(),
10624 }
10625 }
10626}
10627
10628fn default_overtime_rate() -> f64 {
10629 0.10
10630}
10631
10632#[derive(Debug, Clone, Serialize, Deserialize)]
10634pub struct ExpenseConfig {
10635 #[serde(default = "default_true")]
10637 pub enabled: bool,
10638 #[serde(default = "default_expense_submission_rate")]
10640 pub submission_rate: f64,
10641 #[serde(default = "default_policy_violation_rate")]
10643 pub policy_violation_rate: f64,
10644}
10645
10646impl Default for ExpenseConfig {
10647 fn default() -> Self {
10648 Self {
10649 enabled: true,
10650 submission_rate: default_expense_submission_rate(),
10651 policy_violation_rate: default_policy_violation_rate(),
10652 }
10653 }
10654}
10655
10656fn default_expense_submission_rate() -> f64 {
10657 0.30
10658}
10659fn default_policy_violation_rate() -> f64 {
10660 0.08
10661}
10662
10663#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10667pub struct ManufacturingProcessConfig {
10668 #[serde(default)]
10670 pub enabled: bool,
10671 #[serde(default)]
10673 pub production_orders: ProductionOrderConfig,
10674 #[serde(default)]
10676 pub costing: ManufacturingCostingConfig,
10677 #[serde(default)]
10679 pub routing: RoutingConfig,
10680}
10681
10682#[derive(Debug, Clone, Serialize, Deserialize)]
10684pub struct ProductionOrderConfig {
10685 #[serde(default = "default_prod_orders_per_month")]
10687 pub orders_per_month: u32,
10688 #[serde(default = "default_prod_avg_batch_size")]
10690 pub avg_batch_size: u32,
10691 #[serde(default = "default_prod_yield_rate")]
10693 pub yield_rate: f64,
10694 #[serde(default = "default_prod_make_to_order_rate")]
10696 pub make_to_order_rate: f64,
10697 #[serde(default = "default_prod_rework_rate")]
10699 pub rework_rate: f64,
10700}
10701
10702impl Default for ProductionOrderConfig {
10703 fn default() -> Self {
10704 Self {
10705 orders_per_month: default_prod_orders_per_month(),
10706 avg_batch_size: default_prod_avg_batch_size(),
10707 yield_rate: default_prod_yield_rate(),
10708 make_to_order_rate: default_prod_make_to_order_rate(),
10709 rework_rate: default_prod_rework_rate(),
10710 }
10711 }
10712}
10713
10714fn default_prod_orders_per_month() -> u32 {
10715 50
10716}
10717fn default_prod_avg_batch_size() -> u32 {
10718 100
10719}
10720fn default_prod_yield_rate() -> f64 {
10721 0.97
10722}
10723fn default_prod_make_to_order_rate() -> f64 {
10724 0.20
10725}
10726fn default_prod_rework_rate() -> f64 {
10727 0.03
10728}
10729
10730#[derive(Debug, Clone, Serialize, Deserialize)]
10732pub struct ManufacturingCostingConfig {
10733 #[serde(default = "default_labor_rate")]
10735 pub labor_rate_per_hour: f64,
10736 #[serde(default = "default_overhead_rate")]
10738 pub overhead_rate: f64,
10739 #[serde(default = "default_cost_update_frequency")]
10741 pub standard_cost_update_frequency: String,
10742}
10743
10744impl Default for ManufacturingCostingConfig {
10745 fn default() -> Self {
10746 Self {
10747 labor_rate_per_hour: default_labor_rate(),
10748 overhead_rate: default_overhead_rate(),
10749 standard_cost_update_frequency: default_cost_update_frequency(),
10750 }
10751 }
10752}
10753
10754fn default_labor_rate() -> f64 {
10755 35.0
10756}
10757fn default_overhead_rate() -> f64 {
10758 1.50
10759}
10760fn default_cost_update_frequency() -> String {
10761 "quarterly".to_string()
10762}
10763
10764#[derive(Debug, Clone, Serialize, Deserialize)]
10766pub struct RoutingConfig {
10767 #[serde(default = "default_avg_operations")]
10769 pub avg_operations: u32,
10770 #[serde(default = "default_setup_time")]
10772 pub setup_time_hours: f64,
10773 #[serde(default = "default_run_time_variation")]
10775 pub run_time_variation: f64,
10776}
10777
10778impl Default for RoutingConfig {
10779 fn default() -> Self {
10780 Self {
10781 avg_operations: default_avg_operations(),
10782 setup_time_hours: default_setup_time(),
10783 run_time_variation: default_run_time_variation(),
10784 }
10785 }
10786}
10787
10788fn default_avg_operations() -> u32 {
10789 4
10790}
10791fn default_setup_time() -> f64 {
10792 1.5
10793}
10794fn default_run_time_variation() -> f64 {
10795 0.15
10796}
10797
10798#[derive(Debug, Clone, Serialize, Deserialize)]
10802pub struct SalesQuoteConfig {
10803 #[serde(default)]
10805 pub enabled: bool,
10806 #[serde(default = "default_quotes_per_month")]
10808 pub quotes_per_month: u32,
10809 #[serde(default = "default_quote_win_rate")]
10811 pub win_rate: f64,
10812 #[serde(default = "default_quote_validity_days")]
10814 pub validity_days: u32,
10815}
10816
10817impl Default for SalesQuoteConfig {
10818 fn default() -> Self {
10819 Self {
10820 enabled: false,
10821 quotes_per_month: default_quotes_per_month(),
10822 win_rate: default_quote_win_rate(),
10823 validity_days: default_quote_validity_days(),
10824 }
10825 }
10826}
10827
10828fn default_quotes_per_month() -> u32 {
10829 30
10830}
10831fn default_quote_win_rate() -> f64 {
10832 0.35
10833}
10834fn default_quote_validity_days() -> u32 {
10835 30
10836}
10837
10838#[cfg(test)]
10839#[allow(clippy::unwrap_used)]
10840mod tests {
10841 use super::*;
10842 use crate::presets::demo_preset;
10843
10844 #[test]
10849 fn test_config_yaml_roundtrip() {
10850 let config = demo_preset();
10851 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
10852 let deserialized: GeneratorConfig =
10853 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
10854
10855 assert_eq!(
10856 config.global.period_months,
10857 deserialized.global.period_months
10858 );
10859 assert_eq!(config.global.industry, deserialized.global.industry);
10860 assert_eq!(config.companies.len(), deserialized.companies.len());
10861 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
10862 }
10863
10864 #[test]
10865 fn test_config_json_roundtrip() {
10866 let mut config = demo_preset();
10868 config.master_data.employees.approval_limits.executive = 1e12;
10870
10871 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
10872 let deserialized: GeneratorConfig =
10873 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
10874
10875 assert_eq!(
10876 config.global.period_months,
10877 deserialized.global.period_months
10878 );
10879 assert_eq!(config.global.industry, deserialized.global.industry);
10880 assert_eq!(config.companies.len(), deserialized.companies.len());
10881 }
10882
10883 #[test]
10884 fn test_transaction_volume_serialization() {
10885 let volumes = vec![
10887 (TransactionVolume::TenK, "ten_k"),
10888 (TransactionVolume::HundredK, "hundred_k"),
10889 (TransactionVolume::OneM, "one_m"),
10890 (TransactionVolume::TenM, "ten_m"),
10891 (TransactionVolume::HundredM, "hundred_m"),
10892 ];
10893
10894 for (volume, expected_key) in volumes {
10895 let json = serde_json::to_string(&volume).expect("Failed to serialize");
10896 assert!(
10897 json.contains(expected_key),
10898 "Expected {} in JSON: {}",
10899 expected_key,
10900 json
10901 );
10902 }
10903 }
10904
10905 #[test]
10906 fn test_transaction_volume_custom_serialization() {
10907 let volume = TransactionVolume::Custom(12345);
10908 let json = serde_json::to_string(&volume).expect("Failed to serialize");
10909 let deserialized: TransactionVolume =
10910 serde_json::from_str(&json).expect("Failed to deserialize");
10911 assert_eq!(deserialized.count(), 12345);
10912 }
10913
10914 #[test]
10915 fn test_output_mode_serialization() {
10916 let modes = vec![
10917 OutputMode::Streaming,
10918 OutputMode::FlatFile,
10919 OutputMode::Both,
10920 ];
10921
10922 for mode in modes {
10923 let json = serde_json::to_string(&mode).expect("Failed to serialize");
10924 let deserialized: OutputMode =
10925 serde_json::from_str(&json).expect("Failed to deserialize");
10926 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
10927 }
10928 }
10929
10930 #[test]
10931 fn test_file_format_serialization() {
10932 let formats = vec![
10933 FileFormat::Csv,
10934 FileFormat::Parquet,
10935 FileFormat::Json,
10936 FileFormat::JsonLines,
10937 ];
10938
10939 for format in formats {
10940 let json = serde_json::to_string(&format).expect("Failed to serialize");
10941 let deserialized: FileFormat =
10942 serde_json::from_str(&json).expect("Failed to deserialize");
10943 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
10944 }
10945 }
10946
10947 #[test]
10948 fn test_compression_algorithm_serialization() {
10949 let algos = vec![
10950 CompressionAlgorithm::Gzip,
10951 CompressionAlgorithm::Zstd,
10952 CompressionAlgorithm::Lz4,
10953 CompressionAlgorithm::Snappy,
10954 ];
10955
10956 for algo in algos {
10957 let json = serde_json::to_string(&algo).expect("Failed to serialize");
10958 let deserialized: CompressionAlgorithm =
10959 serde_json::from_str(&json).expect("Failed to deserialize");
10960 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
10961 }
10962 }
10963
10964 #[test]
10965 fn test_transfer_pricing_method_serialization() {
10966 let methods = vec![
10967 TransferPricingMethod::CostPlus,
10968 TransferPricingMethod::ComparableUncontrolled,
10969 TransferPricingMethod::ResalePrice,
10970 TransferPricingMethod::TransactionalNetMargin,
10971 TransferPricingMethod::ProfitSplit,
10972 ];
10973
10974 for method in methods {
10975 let json = serde_json::to_string(&method).expect("Failed to serialize");
10976 let deserialized: TransferPricingMethod =
10977 serde_json::from_str(&json).expect("Failed to deserialize");
10978 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
10979 }
10980 }
10981
10982 #[test]
10983 fn test_benford_exemption_serialization() {
10984 let exemptions = vec![
10985 BenfordExemption::Recurring,
10986 BenfordExemption::Payroll,
10987 BenfordExemption::FixedFees,
10988 BenfordExemption::RoundAmounts,
10989 ];
10990
10991 for exemption in exemptions {
10992 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
10993 let deserialized: BenfordExemption =
10994 serde_json::from_str(&json).expect("Failed to deserialize");
10995 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
10996 }
10997 }
10998
10999 #[test]
11004 fn test_global_config_defaults() {
11005 let yaml = r#"
11006 industry: manufacturing
11007 start_date: "2024-01-01"
11008 period_months: 6
11009 "#;
11010 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11011 assert_eq!(config.group_currency, "USD");
11012 assert!(config.parallel);
11013 assert_eq!(config.worker_threads, 0);
11014 assert_eq!(config.memory_limit_mb, 0);
11015 }
11016
11017 #[test]
11018 fn test_fraud_config_defaults() {
11019 let config = FraudConfig::default();
11020 assert!(!config.enabled);
11021 assert_eq!(config.fraud_rate, 0.005);
11022 assert!(!config.clustering_enabled);
11023 }
11024
11025 #[test]
11026 fn test_internal_controls_config_defaults() {
11027 let config = InternalControlsConfig::default();
11028 assert!(!config.enabled);
11029 assert_eq!(config.exception_rate, 0.02);
11030 assert_eq!(config.sod_violation_rate, 0.01);
11031 assert!(config.export_control_master_data);
11032 assert_eq!(config.sox_materiality_threshold, 10000.0);
11033 assert!(config.coso_enabled);
11035 assert!(!config.include_entity_level_controls);
11036 assert_eq!(config.target_maturity_level, "mixed");
11037 }
11038
11039 #[test]
11040 fn test_output_config_defaults() {
11041 let config = OutputConfig::default();
11042 assert!(matches!(config.mode, OutputMode::FlatFile));
11043 assert_eq!(config.formats, vec![FileFormat::Parquet]);
11044 assert!(config.compression.enabled);
11045 assert!(matches!(
11046 config.compression.algorithm,
11047 CompressionAlgorithm::Zstd
11048 ));
11049 assert!(config.include_acdoca);
11050 assert!(!config.include_bseg);
11051 assert!(config.partition_by_period);
11052 assert!(!config.partition_by_company);
11053 }
11054
11055 #[test]
11056 fn test_approval_config_defaults() {
11057 let config = ApprovalConfig::default();
11058 assert!(!config.enabled);
11059 assert_eq!(config.auto_approve_threshold, 1000.0);
11060 assert_eq!(config.rejection_rate, 0.02);
11061 assert_eq!(config.revision_rate, 0.05);
11062 assert_eq!(config.average_approval_delay_hours, 4.0);
11063 assert_eq!(config.thresholds.len(), 4);
11064 }
11065
11066 #[test]
11067 fn test_p2p_flow_config_defaults() {
11068 let config = P2PFlowConfig::default();
11069 assert!(config.enabled);
11070 assert_eq!(config.three_way_match_rate, 0.95);
11071 assert_eq!(config.partial_delivery_rate, 0.15);
11072 assert_eq!(config.average_po_to_gr_days, 14);
11073 }
11074
11075 #[test]
11076 fn test_o2c_flow_config_defaults() {
11077 let config = O2CFlowConfig::default();
11078 assert!(config.enabled);
11079 assert_eq!(config.credit_check_failure_rate, 0.02);
11080 assert_eq!(config.return_rate, 0.03);
11081 assert_eq!(config.bad_debt_rate, 0.01);
11082 }
11083
11084 #[test]
11085 fn test_balance_config_defaults() {
11086 let config = BalanceConfig::default();
11087 assert!(!config.generate_opening_balances);
11088 assert!(config.generate_trial_balances);
11089 assert_eq!(config.target_gross_margin, 0.35);
11090 assert!(config.validate_balance_equation);
11091 assert!(config.reconcile_subledgers);
11092 }
11093
11094 #[test]
11099 fn test_partial_config_with_defaults() {
11100 let yaml = r#"
11102 global:
11103 industry: manufacturing
11104 start_date: "2024-01-01"
11105 period_months: 3
11106 companies:
11107 - code: "TEST"
11108 name: "Test Company"
11109 currency: "USD"
11110 country: "US"
11111 annual_transaction_volume: ten_k
11112 chart_of_accounts:
11113 complexity: small
11114 output:
11115 output_directory: "./output"
11116 "#;
11117
11118 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11119 assert_eq!(config.global.period_months, 3);
11120 assert_eq!(config.companies.len(), 1);
11121 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
11124
11125 #[test]
11126 fn test_config_with_fraud_enabled() {
11127 let yaml = r#"
11128 global:
11129 industry: retail
11130 start_date: "2024-01-01"
11131 period_months: 12
11132 companies:
11133 - code: "RETAIL"
11134 name: "Retail Co"
11135 currency: "USD"
11136 country: "US"
11137 annual_transaction_volume: hundred_k
11138 chart_of_accounts:
11139 complexity: medium
11140 output:
11141 output_directory: "./output"
11142 fraud:
11143 enabled: true
11144 fraud_rate: 0.05
11145 clustering_enabled: true
11146 "#;
11147
11148 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11149 assert!(config.fraud.enabled);
11150 assert_eq!(config.fraud.fraud_rate, 0.05);
11151 assert!(config.fraud.clustering_enabled);
11152 }
11153
11154 #[test]
11155 fn test_config_with_multiple_companies() {
11156 let yaml = r#"
11157 global:
11158 industry: manufacturing
11159 start_date: "2024-01-01"
11160 period_months: 6
11161 companies:
11162 - code: "HQ"
11163 name: "Headquarters"
11164 currency: "USD"
11165 country: "US"
11166 annual_transaction_volume: hundred_k
11167 volume_weight: 1.0
11168 - code: "EU"
11169 name: "European Subsidiary"
11170 currency: "EUR"
11171 country: "DE"
11172 annual_transaction_volume: hundred_k
11173 volume_weight: 0.5
11174 - code: "APAC"
11175 name: "Asia Pacific"
11176 currency: "JPY"
11177 country: "JP"
11178 annual_transaction_volume: ten_k
11179 volume_weight: 0.3
11180 chart_of_accounts:
11181 complexity: large
11182 output:
11183 output_directory: "./output"
11184 "#;
11185
11186 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11187 assert_eq!(config.companies.len(), 3);
11188 assert_eq!(config.companies[0].code, "HQ");
11189 assert_eq!(config.companies[1].currency, "EUR");
11190 assert_eq!(config.companies[2].volume_weight, 0.3);
11191 }
11192
11193 #[test]
11194 fn test_intercompany_config() {
11195 let yaml = r#"
11196 enabled: true
11197 ic_transaction_rate: 0.20
11198 transfer_pricing_method: cost_plus
11199 markup_percent: 0.08
11200 generate_matched_pairs: true
11201 generate_eliminations: true
11202 "#;
11203
11204 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11205 assert!(config.enabled);
11206 assert_eq!(config.ic_transaction_rate, 0.20);
11207 assert!(matches!(
11208 config.transfer_pricing_method,
11209 TransferPricingMethod::CostPlus
11210 ));
11211 assert_eq!(config.markup_percent, 0.08);
11212 assert!(config.generate_eliminations);
11213 }
11214
11215 #[test]
11220 fn test_company_config_defaults() {
11221 let yaml = r#"
11222 code: "TEST"
11223 name: "Test Company"
11224 currency: "USD"
11225 country: "US"
11226 annual_transaction_volume: ten_k
11227 "#;
11228
11229 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11230 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
11233
11234 #[test]
11239 fn test_coa_config_defaults() {
11240 let yaml = r#"
11241 complexity: medium
11242 "#;
11243
11244 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11245 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
11247 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
11250
11251 #[test]
11256 fn test_accounting_standards_config_defaults() {
11257 let config = AccountingStandardsConfig::default();
11258 assert!(!config.enabled);
11259 assert!(matches!(
11260 config.framework,
11261 AccountingFrameworkConfig::UsGaap
11262 ));
11263 assert!(!config.revenue_recognition.enabled);
11264 assert!(!config.leases.enabled);
11265 assert!(!config.fair_value.enabled);
11266 assert!(!config.impairment.enabled);
11267 assert!(!config.generate_differences);
11268 }
11269
11270 #[test]
11271 fn test_accounting_standards_config_yaml() {
11272 let yaml = r#"
11273 enabled: true
11274 framework: ifrs
11275 revenue_recognition:
11276 enabled: true
11277 generate_contracts: true
11278 avg_obligations_per_contract: 2.5
11279 variable_consideration_rate: 0.20
11280 over_time_recognition_rate: 0.35
11281 contract_count: 150
11282 leases:
11283 enabled: true
11284 lease_count: 75
11285 finance_lease_percent: 0.25
11286 avg_lease_term_months: 48
11287 generate_differences: true
11288 "#;
11289
11290 let config: AccountingStandardsConfig =
11291 serde_yaml::from_str(yaml).expect("Failed to parse");
11292 assert!(config.enabled);
11293 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
11294 assert!(config.revenue_recognition.enabled);
11295 assert_eq!(config.revenue_recognition.contract_count, 150);
11296 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
11297 assert!(config.leases.enabled);
11298 assert_eq!(config.leases.lease_count, 75);
11299 assert_eq!(config.leases.finance_lease_percent, 0.25);
11300 assert!(config.generate_differences);
11301 }
11302
11303 #[test]
11304 fn test_accounting_framework_serialization() {
11305 let frameworks = [
11306 AccountingFrameworkConfig::UsGaap,
11307 AccountingFrameworkConfig::Ifrs,
11308 AccountingFrameworkConfig::DualReporting,
11309 ];
11310
11311 for framework in frameworks {
11312 let json = serde_json::to_string(&framework).expect("Failed to serialize");
11313 let deserialized: AccountingFrameworkConfig =
11314 serde_json::from_str(&json).expect("Failed to deserialize");
11315 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
11316 }
11317 }
11318
11319 #[test]
11320 fn test_revenue_recognition_config_defaults() {
11321 let config = RevenueRecognitionConfig::default();
11322 assert!(!config.enabled);
11323 assert!(config.generate_contracts);
11324 assert_eq!(config.avg_obligations_per_contract, 2.0);
11325 assert_eq!(config.variable_consideration_rate, 0.15);
11326 assert_eq!(config.over_time_recognition_rate, 0.30);
11327 assert_eq!(config.contract_count, 100);
11328 }
11329
11330 #[test]
11331 fn test_lease_accounting_config_defaults() {
11332 let config = LeaseAccountingConfig::default();
11333 assert!(!config.enabled);
11334 assert_eq!(config.lease_count, 50);
11335 assert_eq!(config.finance_lease_percent, 0.30);
11336 assert_eq!(config.avg_lease_term_months, 60);
11337 assert!(config.generate_amortization);
11338 assert_eq!(config.real_estate_percent, 0.40);
11339 }
11340
11341 #[test]
11342 fn test_fair_value_config_defaults() {
11343 let config = FairValueConfig::default();
11344 assert!(!config.enabled);
11345 assert_eq!(config.measurement_count, 25);
11346 assert_eq!(config.level1_percent, 0.40);
11347 assert_eq!(config.level2_percent, 0.35);
11348 assert_eq!(config.level3_percent, 0.25);
11349 assert!(!config.include_sensitivity_analysis);
11350 }
11351
11352 #[test]
11353 fn test_impairment_config_defaults() {
11354 let config = ImpairmentConfig::default();
11355 assert!(!config.enabled);
11356 assert_eq!(config.test_count, 15);
11357 assert_eq!(config.impairment_rate, 0.10);
11358 assert!(config.generate_projections);
11359 assert!(!config.include_goodwill);
11360 }
11361
11362 #[test]
11367 fn test_audit_standards_config_defaults() {
11368 let config = AuditStandardsConfig::default();
11369 assert!(!config.enabled);
11370 assert!(!config.isa_compliance.enabled);
11371 assert!(!config.analytical_procedures.enabled);
11372 assert!(!config.confirmations.enabled);
11373 assert!(!config.opinion.enabled);
11374 assert!(!config.generate_audit_trail);
11375 assert!(!config.sox.enabled);
11376 assert!(!config.pcaob.enabled);
11377 }
11378
11379 #[test]
11380 fn test_audit_standards_config_yaml() {
11381 let yaml = r#"
11382 enabled: true
11383 isa_compliance:
11384 enabled: true
11385 compliance_level: comprehensive
11386 generate_isa_mappings: true
11387 include_pcaob: true
11388 framework: dual
11389 analytical_procedures:
11390 enabled: true
11391 procedures_per_account: 5
11392 variance_probability: 0.25
11393 confirmations:
11394 enabled: true
11395 confirmation_count: 75
11396 positive_response_rate: 0.90
11397 exception_rate: 0.08
11398 opinion:
11399 enabled: true
11400 generate_kam: true
11401 average_kam_count: 4
11402 sox:
11403 enabled: true
11404 generate_302_certifications: true
11405 generate_404_assessments: true
11406 material_weakness_rate: 0.03
11407 pcaob:
11408 enabled: true
11409 is_pcaob_audit: true
11410 include_icfr_opinion: true
11411 generate_audit_trail: true
11412 "#;
11413
11414 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11415 assert!(config.enabled);
11416 assert!(config.isa_compliance.enabled);
11417 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
11418 assert!(config.isa_compliance.include_pcaob);
11419 assert_eq!(config.isa_compliance.framework, "dual");
11420 assert!(config.analytical_procedures.enabled);
11421 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
11422 assert!(config.confirmations.enabled);
11423 assert_eq!(config.confirmations.confirmation_count, 75);
11424 assert!(config.opinion.enabled);
11425 assert_eq!(config.opinion.average_kam_count, 4);
11426 assert!(config.sox.enabled);
11427 assert!(config.sox.generate_302_certifications);
11428 assert_eq!(config.sox.material_weakness_rate, 0.03);
11429 assert!(config.pcaob.enabled);
11430 assert!(config.pcaob.is_pcaob_audit);
11431 assert!(config.pcaob.include_icfr_opinion);
11432 assert!(config.generate_audit_trail);
11433 }
11434
11435 #[test]
11436 fn test_isa_compliance_config_defaults() {
11437 let config = IsaComplianceConfig::default();
11438 assert!(!config.enabled);
11439 assert_eq!(config.compliance_level, "standard");
11440 assert!(config.generate_isa_mappings);
11441 assert!(config.generate_coverage_summary);
11442 assert!(!config.include_pcaob);
11443 assert_eq!(config.framework, "isa");
11444 }
11445
11446 #[test]
11447 fn test_sox_compliance_config_defaults() {
11448 let config = SoxComplianceConfig::default();
11449 assert!(!config.enabled);
11450 assert!(config.generate_302_certifications);
11451 assert!(config.generate_404_assessments);
11452 assert_eq!(config.materiality_threshold, 10000.0);
11453 assert_eq!(config.material_weakness_rate, 0.02);
11454 assert_eq!(config.significant_deficiency_rate, 0.08);
11455 }
11456
11457 #[test]
11458 fn test_pcaob_config_defaults() {
11459 let config = PcaobConfig::default();
11460 assert!(!config.enabled);
11461 assert!(!config.is_pcaob_audit);
11462 assert!(config.generate_cam);
11463 assert!(!config.include_icfr_opinion);
11464 assert!(!config.generate_standard_mappings);
11465 }
11466
11467 #[test]
11468 fn test_config_with_standards_enabled() {
11469 let yaml = r#"
11470 global:
11471 industry: financial_services
11472 start_date: "2024-01-01"
11473 period_months: 12
11474 companies:
11475 - code: "BANK"
11476 name: "Test Bank"
11477 currency: "USD"
11478 country: "US"
11479 annual_transaction_volume: hundred_k
11480 chart_of_accounts:
11481 complexity: large
11482 output:
11483 output_directory: "./output"
11484 accounting_standards:
11485 enabled: true
11486 framework: us_gaap
11487 revenue_recognition:
11488 enabled: true
11489 leases:
11490 enabled: true
11491 audit_standards:
11492 enabled: true
11493 isa_compliance:
11494 enabled: true
11495 sox:
11496 enabled: true
11497 "#;
11498
11499 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11500 assert!(config.accounting_standards.enabled);
11501 assert!(matches!(
11502 config.accounting_standards.framework,
11503 AccountingFrameworkConfig::UsGaap
11504 ));
11505 assert!(config.accounting_standards.revenue_recognition.enabled);
11506 assert!(config.accounting_standards.leases.enabled);
11507 assert!(config.audit_standards.enabled);
11508 assert!(config.audit_standards.isa_compliance.enabled);
11509 assert!(config.audit_standards.sox.enabled);
11510 }
11511
11512 #[test]
11517 fn test_industry_specific_config_defaults() {
11518 let config = IndustrySpecificConfig::default();
11519 assert!(!config.enabled);
11520 assert!(!config.manufacturing.enabled);
11521 assert!(!config.retail.enabled);
11522 assert!(!config.healthcare.enabled);
11523 assert!(!config.technology.enabled);
11524 assert!(!config.financial_services.enabled);
11525 assert!(!config.professional_services.enabled);
11526 }
11527
11528 #[test]
11529 fn test_manufacturing_config_defaults() {
11530 let config = ManufacturingConfig::default();
11531 assert!(!config.enabled);
11532 assert_eq!(config.bom_depth, 4);
11533 assert!(!config.just_in_time);
11534 assert_eq!(config.supplier_tiers, 2);
11535 assert_eq!(config.target_yield_rate, 0.97);
11536 assert_eq!(config.scrap_alert_threshold, 0.03);
11537 }
11538
11539 #[test]
11540 fn test_retail_config_defaults() {
11541 let config = RetailConfig::default();
11542 assert!(!config.enabled);
11543 assert_eq!(config.avg_daily_transactions, 500);
11544 assert!(config.loss_prevention);
11545 assert_eq!(config.shrinkage_rate, 0.015);
11546 }
11547
11548 #[test]
11549 fn test_healthcare_config_defaults() {
11550 let config = HealthcareConfig::default();
11551 assert!(!config.enabled);
11552 assert_eq!(config.facility_type, "hospital");
11553 assert_eq!(config.avg_daily_encounters, 150);
11554 assert!(config.compliance.hipaa);
11555 assert!(config.compliance.stark_law);
11556 assert!(config.coding_systems.icd10);
11557 assert!(config.coding_systems.cpt);
11558 }
11559
11560 #[test]
11561 fn test_technology_config_defaults() {
11562 let config = TechnologyConfig::default();
11563 assert!(!config.enabled);
11564 assert_eq!(config.revenue_model, "saas");
11565 assert_eq!(config.subscription_revenue_pct, 0.60);
11566 assert!(config.rd_capitalization.enabled);
11567 }
11568
11569 #[test]
11570 fn test_config_with_industry_specific() {
11571 let yaml = r#"
11572 global:
11573 industry: healthcare
11574 start_date: "2024-01-01"
11575 period_months: 12
11576 companies:
11577 - code: "HOSP"
11578 name: "Test Hospital"
11579 currency: "USD"
11580 country: "US"
11581 annual_transaction_volume: hundred_k
11582 chart_of_accounts:
11583 complexity: medium
11584 output:
11585 output_directory: "./output"
11586 industry_specific:
11587 enabled: true
11588 healthcare:
11589 enabled: true
11590 facility_type: hospital
11591 payer_mix:
11592 medicare: 0.45
11593 medicaid: 0.15
11594 commercial: 0.35
11595 self_pay: 0.05
11596 coding_systems:
11597 icd10: true
11598 cpt: true
11599 drg: true
11600 compliance:
11601 hipaa: true
11602 stark_law: true
11603 anomaly_rates:
11604 upcoding: 0.03
11605 unbundling: 0.02
11606 "#;
11607
11608 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11609 assert!(config.industry_specific.enabled);
11610 assert!(config.industry_specific.healthcare.enabled);
11611 assert_eq!(
11612 config.industry_specific.healthcare.facility_type,
11613 "hospital"
11614 );
11615 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
11616 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
11617 assert!(config.industry_specific.healthcare.coding_systems.icd10);
11618 assert!(config.industry_specific.healthcare.compliance.hipaa);
11619 assert_eq!(
11620 config.industry_specific.healthcare.anomaly_rates.upcoding,
11621 0.03
11622 );
11623 }
11624
11625 #[test]
11626 fn test_config_with_manufacturing_specific() {
11627 let yaml = r#"
11628 global:
11629 industry: manufacturing
11630 start_date: "2024-01-01"
11631 period_months: 12
11632 companies:
11633 - code: "MFG"
11634 name: "Test Manufacturing"
11635 currency: "USD"
11636 country: "US"
11637 annual_transaction_volume: hundred_k
11638 chart_of_accounts:
11639 complexity: medium
11640 output:
11641 output_directory: "./output"
11642 industry_specific:
11643 enabled: true
11644 manufacturing:
11645 enabled: true
11646 bom_depth: 5
11647 just_in_time: true
11648 supplier_tiers: 3
11649 target_yield_rate: 0.98
11650 anomaly_rates:
11651 yield_manipulation: 0.02
11652 phantom_production: 0.01
11653 "#;
11654
11655 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
11656 assert!(config.industry_specific.enabled);
11657 assert!(config.industry_specific.manufacturing.enabled);
11658 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
11659 assert!(config.industry_specific.manufacturing.just_in_time);
11660 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
11661 assert_eq!(
11662 config.industry_specific.manufacturing.target_yield_rate,
11663 0.98
11664 );
11665 assert_eq!(
11666 config
11667 .industry_specific
11668 .manufacturing
11669 .anomaly_rates
11670 .yield_manipulation,
11671 0.02
11672 );
11673 }
11674}