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 #[serde(default)]
173 pub tax: TaxConfig,
174 #[serde(default)]
176 pub treasury: TreasuryConfig,
177 #[serde(default)]
179 pub project_accounting: ProjectAccountingConfig,
180 #[serde(default)]
182 pub esg: EsgConfig,
183 #[serde(default)]
185 pub country_packs: Option<CountryPacksSchemaConfig>,
186 #[serde(default)]
188 pub scenarios: ScenariosConfig,
189 #[serde(default)]
191 pub session: SessionSchemaConfig,
192 #[serde(default)]
194 pub compliance_regulations: ComplianceRegulationsConfig,
195 #[serde(default)]
199 pub analytics_metadata: AnalyticsMetadataConfig,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct AnalyticsMetadataConfig {
212 #[serde(default)]
214 pub enabled: bool,
215 #[serde(default = "default_true")]
218 pub prior_year: bool,
219 #[serde(default = "default_true")]
221 pub industry_benchmark: bool,
222 #[serde(default = "default_true")]
224 pub management_reports: bool,
225 #[serde(default = "default_true")]
228 pub drift_events: bool,
229}
230
231impl Default for AnalyticsMetadataConfig {
232 fn default() -> Self {
233 Self {
234 enabled: false,
235 prior_year: true,
236 industry_benchmark: true,
237 management_reports: true,
238 drift_events: true,
239 }
240 }
241}
242
243#[derive(Debug, Clone, Serialize, Deserialize)]
249pub struct LlmSchemaConfig {
250 #[serde(default)]
252 pub enabled: bool,
253 #[serde(default = "default_llm_provider")]
255 pub provider: String,
256 #[serde(default = "default_llm_model_name")]
258 pub model: String,
259 #[serde(default = "default_llm_batch_size")]
261 pub max_vendor_enrichments: usize,
262}
263
264fn default_llm_provider() -> String {
265 "mock".to_string()
266}
267
268fn default_llm_model_name() -> String {
269 "gpt-4o-mini".to_string()
270}
271
272fn default_llm_batch_size() -> usize {
273 50
274}
275
276impl Default for LlmSchemaConfig {
277 fn default() -> Self {
278 Self {
279 enabled: false,
280 provider: default_llm_provider(),
281 model: default_llm_model_name(),
282 max_vendor_enrichments: default_llm_batch_size(),
283 }
284 }
285}
286
287#[derive(Debug, Clone, Serialize, Deserialize)]
292pub struct DiffusionSchemaConfig {
293 #[serde(default)]
295 pub enabled: bool,
296 #[serde(default = "default_diffusion_steps")]
298 pub n_steps: usize,
299 #[serde(default = "default_diffusion_schedule")]
301 pub schedule: String,
302 #[serde(default = "default_diffusion_sample_size")]
304 pub sample_size: usize,
305 #[serde(default = "default_diffusion_backend")]
307 pub backend: String,
308 #[serde(default)]
310 pub neural: NeuralDiffusionSchemaConfig,
311}
312
313fn default_diffusion_steps() -> usize {
314 100
315}
316
317fn default_diffusion_schedule() -> String {
318 "linear".to_string()
319}
320
321fn default_diffusion_sample_size() -> usize {
322 100
323}
324
325fn default_diffusion_backend() -> String {
326 "statistical".to_string()
327}
328
329impl Default for DiffusionSchemaConfig {
330 fn default() -> Self {
331 Self {
332 enabled: false,
333 n_steps: default_diffusion_steps(),
334 schedule: default_diffusion_schedule(),
335 sample_size: default_diffusion_sample_size(),
336 backend: default_diffusion_backend(),
337 neural: NeuralDiffusionSchemaConfig::default(),
338 }
339 }
340}
341
342#[derive(Debug, Clone, Serialize, Deserialize)]
347pub struct NeuralDiffusionSchemaConfig {
348 #[serde(default = "default_neural_hidden_dims")]
350 pub hidden_dims: Vec<usize>,
351 #[serde(default = "default_neural_timestep_embed_dim")]
353 pub timestep_embed_dim: usize,
354 #[serde(default = "default_neural_learning_rate")]
356 pub learning_rate: f64,
357 #[serde(default = "default_neural_training_epochs")]
359 pub training_epochs: usize,
360 #[serde(default = "default_neural_batch_size")]
362 pub batch_size: usize,
363 #[serde(default = "default_neural_hybrid_weight")]
365 pub hybrid_weight: f64,
366 #[serde(default = "default_neural_hybrid_strategy")]
368 pub hybrid_strategy: String,
369 #[serde(default)]
371 pub neural_columns: Vec<String>,
372}
373
374fn default_neural_hidden_dims() -> Vec<usize> {
375 vec![256, 256, 128]
376}
377
378fn default_neural_timestep_embed_dim() -> usize {
379 64
380}
381
382fn default_neural_learning_rate() -> f64 {
383 0.001
384}
385
386fn default_neural_training_epochs() -> usize {
387 100
388}
389
390fn default_neural_batch_size() -> usize {
391 64
392}
393
394fn default_neural_hybrid_weight() -> f64 {
395 0.5
396}
397
398fn default_neural_hybrid_strategy() -> String {
399 "weighted_average".to_string()
400}
401
402impl Default for NeuralDiffusionSchemaConfig {
403 fn default() -> Self {
404 Self {
405 hidden_dims: default_neural_hidden_dims(),
406 timestep_embed_dim: default_neural_timestep_embed_dim(),
407 learning_rate: default_neural_learning_rate(),
408 training_epochs: default_neural_training_epochs(),
409 batch_size: default_neural_batch_size(),
410 hybrid_weight: default_neural_hybrid_weight(),
411 hybrid_strategy: default_neural_hybrid_strategy(),
412 neural_columns: Vec::new(),
413 }
414 }
415}
416
417#[derive(Debug, Clone, Serialize, Deserialize)]
423pub struct CausalSchemaConfig {
424 #[serde(default)]
426 pub enabled: bool,
427 #[serde(default = "default_causal_template")]
429 pub template: String,
430 #[serde(default = "default_causal_sample_size")]
432 pub sample_size: usize,
433 #[serde(default = "default_true")]
435 pub validate: bool,
436}
437
438fn default_causal_template() -> String {
439 "fraud_detection".to_string()
440}
441
442fn default_causal_sample_size() -> usize {
443 500
444}
445
446impl Default for CausalSchemaConfig {
447 fn default() -> Self {
448 Self {
449 enabled: false,
450 template: default_causal_template(),
451 sample_size: default_causal_sample_size(),
452 validate: true,
453 }
454 }
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
464pub struct GraphExportConfig {
465 #[serde(default)]
467 pub enabled: bool,
468
469 #[serde(default = "default_graph_types")]
471 pub graph_types: Vec<GraphTypeConfig>,
472
473 #[serde(default = "default_graph_formats")]
475 pub formats: Vec<GraphExportFormat>,
476
477 #[serde(default = "default_train_ratio")]
479 pub train_ratio: f64,
480
481 #[serde(default = "default_val_ratio")]
483 pub validation_ratio: f64,
484
485 #[serde(default)]
487 pub split_seed: Option<u64>,
488
489 #[serde(default = "default_graph_subdir")]
491 pub output_subdirectory: String,
492
493 #[serde(default)]
495 pub hypergraph: HypergraphExportSettings,
496
497 #[serde(default)]
499 pub dgl: DglExportConfig,
500}
501
502fn default_graph_types() -> Vec<GraphTypeConfig> {
503 vec![GraphTypeConfig::default()]
504}
505
506fn default_graph_formats() -> Vec<GraphExportFormat> {
507 vec![GraphExportFormat::PytorchGeometric]
508}
509
510fn default_train_ratio() -> f64 {
511 0.7
512}
513
514fn default_val_ratio() -> f64 {
515 0.15
516}
517
518fn default_graph_subdir() -> String {
519 "graphs".to_string()
520}
521
522impl Default for GraphExportConfig {
523 fn default() -> Self {
524 Self {
525 enabled: false,
526 graph_types: default_graph_types(),
527 formats: default_graph_formats(),
528 train_ratio: 0.7,
529 validation_ratio: 0.15,
530 split_seed: None,
531 output_subdirectory: "graphs".to_string(),
532 hypergraph: HypergraphExportSettings::default(),
533 dgl: DglExportConfig::default(),
534 }
535 }
536}
537
538#[derive(Debug, Clone, Default, Serialize, Deserialize)]
540pub struct DglExportConfig {
541 #[serde(default)]
547 pub heterogeneous: bool,
548}
549
550#[derive(Debug, Clone, Serialize, Deserialize)]
559pub struct HypergraphExportSettings {
560 #[serde(default)]
562 pub enabled: bool,
563
564 #[serde(default = "default_hypergraph_max_nodes")]
566 pub max_nodes: usize,
567
568 #[serde(default = "default_aggregation_strategy")]
570 pub aggregation_strategy: String,
571
572 #[serde(default)]
574 pub governance_layer: GovernanceLayerSettings,
575
576 #[serde(default)]
578 pub process_layer: ProcessLayerSettings,
579
580 #[serde(default)]
582 pub accounting_layer: AccountingLayerSettings,
583
584 #[serde(default)]
586 pub cross_layer: CrossLayerSettings,
587
588 #[serde(default = "default_hypergraph_subdir")]
590 pub output_subdirectory: String,
591
592 #[serde(default = "default_hypergraph_format")]
594 pub output_format: String,
595
596 #[serde(default)]
598 pub stream_target: Option<String>,
599
600 #[serde(default = "default_stream_batch_size")]
602 pub stream_batch_size: usize,
603}
604
605fn default_hypergraph_max_nodes() -> usize {
606 50_000
607}
608
609fn default_aggregation_strategy() -> String {
610 "pool_by_counterparty".to_string()
611}
612
613fn default_hypergraph_subdir() -> String {
614 "hypergraph".to_string()
615}
616
617fn default_hypergraph_format() -> String {
618 "native".to_string()
619}
620
621fn default_stream_batch_size() -> usize {
622 1000
623}
624
625impl Default for HypergraphExportSettings {
626 fn default() -> Self {
627 Self {
628 enabled: false,
629 max_nodes: 50_000,
630 aggregation_strategy: "pool_by_counterparty".to_string(),
631 governance_layer: GovernanceLayerSettings::default(),
632 process_layer: ProcessLayerSettings::default(),
633 accounting_layer: AccountingLayerSettings::default(),
634 cross_layer: CrossLayerSettings::default(),
635 output_subdirectory: "hypergraph".to_string(),
636 output_format: "native".to_string(),
637 stream_target: None,
638 stream_batch_size: 1000,
639 }
640 }
641}
642
643#[derive(Debug, Clone, Serialize, Deserialize)]
645pub struct GovernanceLayerSettings {
646 #[serde(default = "default_true")]
648 pub include_coso: bool,
649 #[serde(default = "default_true")]
651 pub include_controls: bool,
652 #[serde(default = "default_true")]
654 pub include_sox: bool,
655 #[serde(default = "default_true")]
657 pub include_vendors: bool,
658 #[serde(default = "default_true")]
660 pub include_customers: bool,
661 #[serde(default = "default_true")]
663 pub include_employees: bool,
664}
665
666impl Default for GovernanceLayerSettings {
667 fn default() -> Self {
668 Self {
669 include_coso: true,
670 include_controls: true,
671 include_sox: true,
672 include_vendors: true,
673 include_customers: true,
674 include_employees: true,
675 }
676 }
677}
678
679#[derive(Debug, Clone, Serialize, Deserialize)]
681pub struct ProcessLayerSettings {
682 #[serde(default = "default_true")]
684 pub include_p2p: bool,
685 #[serde(default = "default_true")]
687 pub include_o2c: bool,
688 #[serde(default = "default_true")]
690 pub include_s2c: bool,
691 #[serde(default = "default_true")]
693 pub include_h2r: bool,
694 #[serde(default = "default_true")]
696 pub include_mfg: bool,
697 #[serde(default = "default_true")]
699 pub include_bank: bool,
700 #[serde(default = "default_true")]
702 pub include_audit: bool,
703 #[serde(default = "default_true")]
705 pub include_r2r: bool,
706 #[serde(default = "default_true")]
708 pub events_as_hyperedges: bool,
709 #[serde(default = "default_docs_per_counterparty_threshold")]
711 pub docs_per_counterparty_threshold: usize,
712}
713
714fn default_docs_per_counterparty_threshold() -> usize {
715 20
716}
717
718impl Default for ProcessLayerSettings {
719 fn default() -> Self {
720 Self {
721 include_p2p: true,
722 include_o2c: true,
723 include_s2c: true,
724 include_h2r: true,
725 include_mfg: true,
726 include_bank: true,
727 include_audit: true,
728 include_r2r: true,
729 events_as_hyperedges: true,
730 docs_per_counterparty_threshold: 20,
731 }
732 }
733}
734
735#[derive(Debug, Clone, Serialize, Deserialize)]
737pub struct AccountingLayerSettings {
738 #[serde(default = "default_true")]
740 pub include_accounts: bool,
741 #[serde(default = "default_true")]
743 pub je_as_hyperedges: bool,
744}
745
746impl Default for AccountingLayerSettings {
747 fn default() -> Self {
748 Self {
749 include_accounts: true,
750 je_as_hyperedges: true,
751 }
752 }
753}
754
755#[derive(Debug, Clone, Serialize, Deserialize)]
757pub struct CrossLayerSettings {
758 #[serde(default = "default_true")]
760 pub enabled: bool,
761}
762
763impl Default for CrossLayerSettings {
764 fn default() -> Self {
765 Self { enabled: true }
766 }
767}
768
769#[derive(Debug, Clone, Serialize, Deserialize)]
771pub struct GraphTypeConfig {
772 #[serde(default = "default_graph_name")]
774 pub name: String,
775
776 #[serde(default)]
778 pub aggregate_edges: bool,
779
780 #[serde(default)]
782 pub min_edge_weight: f64,
783
784 #[serde(default)]
786 pub include_document_nodes: bool,
787}
788
789fn default_graph_name() -> String {
790 "accounting_network".to_string()
791}
792
793impl Default for GraphTypeConfig {
794 fn default() -> Self {
795 Self {
796 name: "accounting_network".to_string(),
797 aggregate_edges: false,
798 min_edge_weight: 0.0,
799 include_document_nodes: false,
800 }
801 }
802}
803
804#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
806#[serde(rename_all = "snake_case")]
807pub enum GraphExportFormat {
808 PytorchGeometric,
810 Neo4j,
812 Dgl,
814 RustGraph,
816 RustGraphHypergraph,
818}
819
820#[derive(Debug, Clone, Default, Serialize, Deserialize)]
824pub struct ScenarioConfig {
825 #[serde(default)]
828 pub tags: Vec<String>,
829
830 #[serde(default)]
835 pub profile: Option<String>,
836
837 #[serde(default)]
839 pub description: Option<String>,
840
841 #[serde(default)]
843 pub ml_training: bool,
844
845 #[serde(default)]
848 pub target_anomaly_ratio: Option<f64>,
849
850 #[serde(default)]
852 pub metadata: std::collections::HashMap<String, String>,
853}
854
855#[derive(Debug, Clone, Serialize, Deserialize)]
860pub struct TemporalDriftConfig {
861 #[serde(default)]
863 pub enabled: bool,
864
865 #[serde(default = "default_amount_drift")]
868 pub amount_mean_drift: f64,
869
870 #[serde(default)]
873 pub amount_variance_drift: f64,
874
875 #[serde(default)]
878 pub anomaly_rate_drift: f64,
879
880 #[serde(default = "default_concept_drift")]
883 pub concept_drift_rate: f64,
884
885 #[serde(default)]
887 pub sudden_drift_probability: f64,
888
889 #[serde(default = "default_sudden_drift_magnitude")]
891 pub sudden_drift_magnitude: f64,
892
893 #[serde(default)]
895 pub seasonal_drift: bool,
896
897 #[serde(default)]
899 pub drift_start_period: u32,
900
901 #[serde(default = "default_drift_type")]
903 pub drift_type: DriftType,
904}
905
906fn default_amount_drift() -> f64 {
907 0.02
908}
909
910fn default_concept_drift() -> f64 {
911 0.01
912}
913
914fn default_sudden_drift_magnitude() -> f64 {
915 2.0
916}
917
918fn default_drift_type() -> DriftType {
919 DriftType::Gradual
920}
921
922impl Default for TemporalDriftConfig {
923 fn default() -> Self {
924 Self {
925 enabled: false,
926 amount_mean_drift: 0.02,
927 amount_variance_drift: 0.0,
928 anomaly_rate_drift: 0.0,
929 concept_drift_rate: 0.01,
930 sudden_drift_probability: 0.0,
931 sudden_drift_magnitude: 2.0,
932 seasonal_drift: false,
933 drift_start_period: 0,
934 drift_type: DriftType::Gradual,
935 }
936 }
937}
938
939impl TemporalDriftConfig {
940 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
942 datasynth_core::distributions::DriftConfig {
943 enabled: self.enabled,
944 amount_mean_drift: self.amount_mean_drift,
945 amount_variance_drift: self.amount_variance_drift,
946 anomaly_rate_drift: self.anomaly_rate_drift,
947 concept_drift_rate: self.concept_drift_rate,
948 sudden_drift_probability: self.sudden_drift_probability,
949 sudden_drift_magnitude: self.sudden_drift_magnitude,
950 seasonal_drift: self.seasonal_drift,
951 drift_start_period: self.drift_start_period,
952 drift_type: match self.drift_type {
953 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
954 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
955 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
956 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
957 },
958 regime_changes: Vec::new(),
959 economic_cycle: Default::default(),
960 parameter_drifts: Vec::new(),
961 }
962 }
963}
964
965#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
967#[serde(rename_all = "snake_case")]
968pub enum DriftType {
969 #[default]
971 Gradual,
972 Sudden,
974 Recurring,
976 Mixed,
978}
979
980#[derive(Debug, Clone, Serialize, Deserialize)]
986pub struct StreamingSchemaConfig {
987 #[serde(default)]
989 pub enabled: bool,
990 #[serde(default)]
992 pub events_per_second: f64,
993 #[serde(default = "default_burst_size")]
995 pub burst_size: u32,
996 #[serde(default = "default_buffer_size")]
998 pub buffer_size: usize,
999 #[serde(default = "default_true")]
1001 pub enable_progress: bool,
1002 #[serde(default = "default_progress_interval")]
1004 pub progress_interval: u64,
1005 #[serde(default)]
1007 pub backpressure: BackpressureSchemaStrategy,
1008}
1009
1010fn default_buffer_size() -> usize {
1011 1000
1012}
1013
1014fn default_progress_interval() -> u64 {
1015 100
1016}
1017
1018impl Default for StreamingSchemaConfig {
1019 fn default() -> Self {
1020 Self {
1021 enabled: false,
1022 events_per_second: 0.0,
1023 burst_size: 100,
1024 buffer_size: 1000,
1025 enable_progress: true,
1026 progress_interval: 100,
1027 backpressure: BackpressureSchemaStrategy::Block,
1028 }
1029 }
1030}
1031
1032#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1034#[serde(rename_all = "snake_case")]
1035pub enum BackpressureSchemaStrategy {
1036 #[default]
1038 Block,
1039 DropOldest,
1041 DropNewest,
1043 Buffer,
1045}
1046
1047#[derive(Debug, Clone, Serialize, Deserialize)]
1053pub struct RateLimitSchemaConfig {
1054 #[serde(default)]
1056 pub enabled: bool,
1057 #[serde(default = "default_entities_per_second")]
1059 pub entities_per_second: f64,
1060 #[serde(default = "default_burst_size")]
1062 pub burst_size: u32,
1063 #[serde(default)]
1065 pub backpressure: RateLimitBackpressureSchema,
1066}
1067
1068fn default_entities_per_second() -> f64 {
1069 1000.0
1070}
1071
1072fn default_burst_size() -> u32 {
1073 100
1074}
1075
1076impl Default for RateLimitSchemaConfig {
1077 fn default() -> Self {
1078 Self {
1079 enabled: false,
1080 entities_per_second: 1000.0,
1081 burst_size: 100,
1082 backpressure: RateLimitBackpressureSchema::Block,
1083 }
1084 }
1085}
1086
1087#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1089#[serde(rename_all = "snake_case")]
1090pub enum RateLimitBackpressureSchema {
1091 #[default]
1093 Block,
1094 Drop,
1096 Buffer,
1098}
1099
1100#[derive(Debug, Clone, Serialize, Deserialize)]
1106pub struct TemporalAttributeSchemaConfig {
1107 #[serde(default)]
1109 pub enabled: bool,
1110 #[serde(default)]
1112 pub valid_time: ValidTimeSchemaConfig,
1113 #[serde(default)]
1115 pub transaction_time: TransactionTimeSchemaConfig,
1116 #[serde(default)]
1118 pub generate_version_chains: bool,
1119 #[serde(default = "default_avg_versions")]
1121 pub avg_versions_per_entity: f64,
1122}
1123
1124fn default_avg_versions() -> f64 {
1125 1.5
1126}
1127
1128impl Default for TemporalAttributeSchemaConfig {
1129 fn default() -> Self {
1130 Self {
1131 enabled: false,
1132 valid_time: ValidTimeSchemaConfig::default(),
1133 transaction_time: TransactionTimeSchemaConfig::default(),
1134 generate_version_chains: false,
1135 avg_versions_per_entity: 1.5,
1136 }
1137 }
1138}
1139
1140#[derive(Debug, Clone, Serialize, Deserialize)]
1142pub struct ValidTimeSchemaConfig {
1143 #[serde(default = "default_closed_probability")]
1145 pub closed_probability: f64,
1146 #[serde(default = "default_avg_validity_days")]
1148 pub avg_validity_days: u32,
1149 #[serde(default = "default_validity_stddev")]
1151 pub validity_stddev_days: u32,
1152}
1153
1154fn default_closed_probability() -> f64 {
1155 0.1
1156}
1157
1158fn default_avg_validity_days() -> u32 {
1159 365
1160}
1161
1162fn default_validity_stddev() -> u32 {
1163 90
1164}
1165
1166impl Default for ValidTimeSchemaConfig {
1167 fn default() -> Self {
1168 Self {
1169 closed_probability: 0.1,
1170 avg_validity_days: 365,
1171 validity_stddev_days: 90,
1172 }
1173 }
1174}
1175
1176#[derive(Debug, Clone, Serialize, Deserialize)]
1178pub struct TransactionTimeSchemaConfig {
1179 #[serde(default)]
1181 pub avg_recording_delay_seconds: u32,
1182 #[serde(default)]
1184 pub allow_backdating: bool,
1185 #[serde(default = "default_backdating_probability")]
1187 pub backdating_probability: f64,
1188 #[serde(default = "default_max_backdate_days")]
1190 pub max_backdate_days: u32,
1191}
1192
1193fn default_backdating_probability() -> f64 {
1194 0.01
1195}
1196
1197fn default_max_backdate_days() -> u32 {
1198 30
1199}
1200
1201impl Default for TransactionTimeSchemaConfig {
1202 fn default() -> Self {
1203 Self {
1204 avg_recording_delay_seconds: 0,
1205 allow_backdating: false,
1206 backdating_probability: 0.01,
1207 max_backdate_days: 30,
1208 }
1209 }
1210}
1211
1212#[derive(Debug, Clone, Serialize, Deserialize)]
1218pub struct RelationshipSchemaConfig {
1219 #[serde(default)]
1221 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
1222 #[serde(default = "default_true")]
1224 pub allow_orphans: bool,
1225 #[serde(default = "default_orphan_probability")]
1227 pub orphan_probability: f64,
1228 #[serde(default)]
1230 pub allow_circular: bool,
1231 #[serde(default = "default_max_circular_depth")]
1233 pub max_circular_depth: u32,
1234}
1235
1236fn default_orphan_probability() -> f64 {
1237 0.01
1238}
1239
1240fn default_max_circular_depth() -> u32 {
1241 3
1242}
1243
1244impl Default for RelationshipSchemaConfig {
1245 fn default() -> Self {
1246 Self {
1247 relationship_types: Vec::new(),
1248 allow_orphans: true,
1249 orphan_probability: 0.01,
1250 allow_circular: false,
1251 max_circular_depth: 3,
1252 }
1253 }
1254}
1255
1256#[derive(Debug, Clone, Serialize, Deserialize)]
1258pub struct RelationshipTypeSchemaConfig {
1259 pub name: String,
1261 pub source_type: String,
1263 pub target_type: String,
1265 #[serde(default)]
1267 pub cardinality: CardinalitySchemaRule,
1268 #[serde(default = "default_relationship_weight")]
1270 pub weight: f64,
1271 #[serde(default)]
1273 pub required: bool,
1274 #[serde(default = "default_true")]
1276 pub directed: bool,
1277}
1278
1279fn default_relationship_weight() -> f64 {
1280 1.0
1281}
1282
1283impl Default for RelationshipTypeSchemaConfig {
1284 fn default() -> Self {
1285 Self {
1286 name: String::new(),
1287 source_type: String::new(),
1288 target_type: String::new(),
1289 cardinality: CardinalitySchemaRule::default(),
1290 weight: 1.0,
1291 required: false,
1292 directed: true,
1293 }
1294 }
1295}
1296
1297#[derive(Debug, Clone, Serialize, Deserialize)]
1299#[serde(rename_all = "snake_case")]
1300pub enum CardinalitySchemaRule {
1301 OneToOne,
1303 OneToMany {
1305 min: u32,
1307 max: u32,
1309 },
1310 ManyToOne {
1312 min: u32,
1314 max: u32,
1316 },
1317 ManyToMany {
1319 min_per_source: u32,
1321 max_per_source: u32,
1323 },
1324}
1325
1326impl Default for CardinalitySchemaRule {
1327 fn default() -> Self {
1328 Self::OneToMany { min: 1, max: 5 }
1329 }
1330}
1331
1332#[derive(Debug, Clone, Serialize, Deserialize)]
1334pub struct GlobalConfig {
1335 pub seed: Option<u64>,
1337 pub industry: IndustrySector,
1339 pub start_date: String,
1341 pub period_months: u32,
1343 #[serde(default = "default_currency")]
1345 pub group_currency: String,
1346 #[serde(default)]
1349 pub presentation_currency: Option<String>,
1350 #[serde(default = "default_true")]
1352 pub parallel: bool,
1353 #[serde(default)]
1355 pub worker_threads: usize,
1356 #[serde(default)]
1358 pub memory_limit_mb: usize,
1359 #[serde(default)]
1362 pub fiscal_year_months: Option<u32>,
1363}
1364
1365fn default_currency() -> String {
1366 "USD".to_string()
1367}
1368fn default_true() -> bool {
1369 true
1370}
1371
1372#[derive(Debug, Clone, Serialize, Deserialize)]
1377pub struct SessionSchemaConfig {
1378 #[serde(default)]
1380 pub enabled: bool,
1381 #[serde(default)]
1383 pub checkpoint_path: Option<String>,
1384 #[serde(default = "default_true")]
1386 pub per_period_output: bool,
1387 #[serde(default = "default_true")]
1389 pub consolidated_output: bool,
1390}
1391
1392impl Default for SessionSchemaConfig {
1393 fn default() -> Self {
1394 Self {
1395 enabled: false,
1396 checkpoint_path: None,
1397 per_period_output: true,
1398 consolidated_output: true,
1399 }
1400 }
1401}
1402
1403#[derive(Debug, Clone, Serialize, Deserialize)]
1405pub struct CompanyConfig {
1406 pub code: String,
1408 pub name: String,
1410 pub currency: String,
1412 #[serde(default)]
1415 pub functional_currency: Option<String>,
1416 pub country: String,
1418 #[serde(default = "default_fiscal_variant")]
1420 pub fiscal_year_variant: String,
1421 pub annual_transaction_volume: TransactionVolume,
1423 #[serde(default = "default_weight")]
1425 pub volume_weight: f64,
1426}
1427
1428fn default_fiscal_variant() -> String {
1429 "K4".to_string()
1430}
1431fn default_weight() -> f64 {
1432 1.0
1433}
1434
1435#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1437#[serde(rename_all = "snake_case")]
1438pub enum TransactionVolume {
1439 TenK,
1441 HundredK,
1443 OneM,
1445 TenM,
1447 HundredM,
1449 Custom(u64),
1451}
1452
1453impl TransactionVolume {
1454 pub fn count(&self) -> u64 {
1456 match self {
1457 Self::TenK => 10_000,
1458 Self::HundredK => 100_000,
1459 Self::OneM => 1_000_000,
1460 Self::TenM => 10_000_000,
1461 Self::HundredM => 100_000_000,
1462 Self::Custom(n) => *n,
1463 }
1464 }
1465}
1466
1467#[derive(Debug, Clone, Serialize, Deserialize)]
1469pub struct ChartOfAccountsConfig {
1470 pub complexity: CoAComplexity,
1472 #[serde(default = "default_true")]
1474 pub industry_specific: bool,
1475 pub custom_accounts: Option<PathBuf>,
1477 #[serde(default = "default_min_depth")]
1479 pub min_hierarchy_depth: u8,
1480 #[serde(default = "default_max_depth")]
1482 pub max_hierarchy_depth: u8,
1483}
1484
1485fn default_min_depth() -> u8 {
1486 2
1487}
1488fn default_max_depth() -> u8 {
1489 5
1490}
1491
1492impl Default for ChartOfAccountsConfig {
1493 fn default() -> Self {
1494 Self {
1495 complexity: CoAComplexity::Small,
1496 industry_specific: true,
1497 custom_accounts: None,
1498 min_hierarchy_depth: default_min_depth(),
1499 max_hierarchy_depth: default_max_depth(),
1500 }
1501 }
1502}
1503
1504#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1506pub struct TransactionConfig {
1507 #[serde(default)]
1509 pub line_item_distribution: LineItemDistributionConfig,
1510 #[serde(default)]
1512 pub debit_credit_distribution: DebitCreditDistributionConfig,
1513 #[serde(default)]
1515 pub even_odd_distribution: EvenOddDistributionConfig,
1516 #[serde(default)]
1518 pub source_distribution: SourceDistribution,
1519 #[serde(default)]
1521 pub seasonality: SeasonalityConfig,
1522 #[serde(default)]
1524 pub amounts: AmountDistributionConfig,
1525 #[serde(default)]
1527 pub benford: BenfordConfig,
1528}
1529
1530#[derive(Debug, Clone, Serialize, Deserialize)]
1532pub struct BenfordConfig {
1533 #[serde(default = "default_true")]
1535 pub enabled: bool,
1536 #[serde(default = "default_benford_tolerance")]
1538 pub tolerance: f64,
1539 #[serde(default)]
1541 pub exempt_sources: Vec<BenfordExemption>,
1542}
1543
1544fn default_benford_tolerance() -> f64 {
1545 0.05
1546}
1547
1548impl Default for BenfordConfig {
1549 fn default() -> Self {
1550 Self {
1551 enabled: true,
1552 tolerance: default_benford_tolerance(),
1553 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1554 }
1555 }
1556}
1557
1558#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1560#[serde(rename_all = "snake_case")]
1561pub enum BenfordExemption {
1562 Recurring,
1564 Payroll,
1566 FixedFees,
1568 RoundAmounts,
1570}
1571
1572#[derive(Debug, Clone, Serialize, Deserialize)]
1574pub struct SourceDistribution {
1575 pub manual: f64,
1577 pub automated: f64,
1579 pub recurring: f64,
1581 pub adjustment: f64,
1583}
1584
1585impl Default for SourceDistribution {
1586 fn default() -> Self {
1587 Self {
1588 manual: 0.20,
1589 automated: 0.70,
1590 recurring: 0.07,
1591 adjustment: 0.03,
1592 }
1593 }
1594}
1595
1596#[derive(Debug, Clone, Serialize, Deserialize)]
1598pub struct OutputConfig {
1599 #[serde(default)]
1601 pub mode: OutputMode,
1602 pub output_directory: PathBuf,
1604 #[serde(default = "default_formats")]
1606 pub formats: Vec<FileFormat>,
1607 #[serde(default)]
1609 pub compression: CompressionConfig,
1610 #[serde(default = "default_batch_size")]
1612 pub batch_size: usize,
1613 #[serde(default = "default_true")]
1615 pub include_acdoca: bool,
1616 #[serde(default)]
1618 pub include_bseg: bool,
1619 #[serde(default = "default_true")]
1621 pub partition_by_period: bool,
1622 #[serde(default)]
1624 pub partition_by_company: bool,
1625 #[serde(default)]
1629 pub numeric_mode: NumericMode,
1630 #[serde(default, alias = "exportLayout")]
1642 pub export_layout: ExportLayout,
1643}
1644
1645fn default_formats() -> Vec<FileFormat> {
1646 vec![FileFormat::Parquet]
1647}
1648fn default_batch_size() -> usize {
1649 100_000
1650}
1651
1652impl Default for OutputConfig {
1653 fn default() -> Self {
1654 Self {
1655 mode: OutputMode::FlatFile,
1656 output_directory: PathBuf::from("./output"),
1657 formats: default_formats(),
1658 compression: CompressionConfig::default(),
1659 batch_size: default_batch_size(),
1660 include_acdoca: true,
1661 include_bseg: false,
1662 partition_by_period: true,
1663 partition_by_company: false,
1664 numeric_mode: NumericMode::default(),
1665 export_layout: ExportLayout::default(),
1666 }
1667 }
1668}
1669
1670#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1672#[serde(rename_all = "snake_case")]
1673pub enum NumericMode {
1674 #[default]
1676 String,
1677 Native,
1679}
1680
1681#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1683#[serde(rename_all = "snake_case")]
1684pub enum ExportLayout {
1685 #[default]
1687 Nested,
1688 Flat,
1690}
1691
1692#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1694#[serde(rename_all = "snake_case")]
1695pub enum OutputMode {
1696 Streaming,
1698 #[default]
1700 FlatFile,
1701 Both,
1703}
1704
1705#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1707#[serde(rename_all = "snake_case")]
1708pub enum FileFormat {
1709 Csv,
1710 Parquet,
1711 Json,
1712 JsonLines,
1713}
1714
1715#[derive(Debug, Clone, Serialize, Deserialize)]
1717pub struct CompressionConfig {
1718 #[serde(default = "default_true")]
1720 pub enabled: bool,
1721 #[serde(default)]
1723 pub algorithm: CompressionAlgorithm,
1724 #[serde(default = "default_compression_level")]
1726 pub level: u8,
1727}
1728
1729fn default_compression_level() -> u8 {
1730 3
1731}
1732
1733impl Default for CompressionConfig {
1734 fn default() -> Self {
1735 Self {
1736 enabled: true,
1737 algorithm: CompressionAlgorithm::default(),
1738 level: default_compression_level(),
1739 }
1740 }
1741}
1742
1743#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1745#[serde(rename_all = "snake_case")]
1746pub enum CompressionAlgorithm {
1747 Gzip,
1748 #[default]
1749 Zstd,
1750 Lz4,
1751 Snappy,
1752}
1753
1754#[derive(Debug, Clone, Serialize, Deserialize)]
1774pub struct FraudConfig {
1775 #[serde(default)]
1777 pub enabled: bool,
1778 #[serde(default = "default_fraud_rate", alias = "fraudRate")]
1796 pub fraud_rate: f64,
1797 #[serde(default, alias = "documentFraudRate")]
1802 pub document_fraud_rate: Option<f64>,
1803 #[serde(default = "default_true", alias = "propagateToLines")]
1808 pub propagate_to_lines: bool,
1809 #[serde(default = "default_true", alias = "propagateToDocument")]
1813 pub propagate_to_document: bool,
1814 #[serde(default)]
1816 pub fraud_type_distribution: FraudTypeDistribution,
1817 #[serde(default)]
1819 pub clustering_enabled: bool,
1820 #[serde(default = "default_clustering_factor")]
1822 pub clustering_factor: f64,
1823 #[serde(default = "default_approval_thresholds")]
1825 pub approval_thresholds: Vec<f64>,
1826}
1827
1828fn default_approval_thresholds() -> Vec<f64> {
1829 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1830}
1831
1832fn default_fraud_rate() -> f64 {
1833 0.005
1834}
1835fn default_clustering_factor() -> f64 {
1836 3.0
1837}
1838
1839impl Default for FraudConfig {
1840 fn default() -> Self {
1841 Self {
1842 enabled: false,
1843 fraud_rate: default_fraud_rate(),
1844 document_fraud_rate: None,
1845 propagate_to_lines: true,
1846 propagate_to_document: true,
1847 fraud_type_distribution: FraudTypeDistribution::default(),
1848 clustering_enabled: false,
1849 clustering_factor: default_clustering_factor(),
1850 approval_thresholds: default_approval_thresholds(),
1851 }
1852 }
1853}
1854
1855#[derive(Debug, Clone, Serialize, Deserialize)]
1857pub struct FraudTypeDistribution {
1858 pub suspense_account_abuse: f64,
1859 pub fictitious_transaction: f64,
1860 pub revenue_manipulation: f64,
1861 pub expense_capitalization: f64,
1862 pub split_transaction: f64,
1863 pub timing_anomaly: f64,
1864 pub unauthorized_access: f64,
1865 pub duplicate_payment: f64,
1866}
1867
1868impl Default for FraudTypeDistribution {
1869 fn default() -> Self {
1870 Self {
1871 suspense_account_abuse: 0.25,
1872 fictitious_transaction: 0.15,
1873 revenue_manipulation: 0.10,
1874 expense_capitalization: 0.10,
1875 split_transaction: 0.15,
1876 timing_anomaly: 0.10,
1877 unauthorized_access: 0.10,
1878 duplicate_payment: 0.05,
1879 }
1880 }
1881}
1882
1883#[derive(Debug, Clone, Serialize, Deserialize)]
1885pub struct InternalControlsConfig {
1886 #[serde(default)]
1888 pub enabled: bool,
1889 #[serde(default = "default_exception_rate")]
1891 pub exception_rate: f64,
1892 #[serde(default = "default_sod_violation_rate")]
1894 pub sod_violation_rate: f64,
1895 #[serde(default = "default_true")]
1897 pub export_control_master_data: bool,
1898 #[serde(default = "default_sox_materiality_threshold")]
1900 pub sox_materiality_threshold: f64,
1901 #[serde(default = "default_true")]
1903 pub coso_enabled: bool,
1904 #[serde(default)]
1906 pub include_entity_level_controls: bool,
1907 #[serde(default = "default_target_maturity_level")]
1910 pub target_maturity_level: String,
1911}
1912
1913fn default_exception_rate() -> f64 {
1914 0.02
1915}
1916
1917fn default_sod_violation_rate() -> f64 {
1918 0.01
1919}
1920
1921fn default_sox_materiality_threshold() -> f64 {
1922 10000.0
1923}
1924
1925fn default_target_maturity_level() -> String {
1926 "mixed".to_string()
1927}
1928
1929impl Default for InternalControlsConfig {
1930 fn default() -> Self {
1931 Self {
1932 enabled: false,
1933 exception_rate: default_exception_rate(),
1934 sod_violation_rate: default_sod_violation_rate(),
1935 export_control_master_data: true,
1936 sox_materiality_threshold: default_sox_materiality_threshold(),
1937 coso_enabled: true,
1938 include_entity_level_controls: false,
1939 target_maturity_level: default_target_maturity_level(),
1940 }
1941 }
1942}
1943
1944#[derive(Debug, Clone, Serialize, Deserialize)]
1946pub struct BusinessProcessConfig {
1947 #[serde(default = "default_o2c")]
1949 pub o2c_weight: f64,
1950 #[serde(default = "default_p2p")]
1952 pub p2p_weight: f64,
1953 #[serde(default = "default_r2r")]
1955 pub r2r_weight: f64,
1956 #[serde(default = "default_h2r")]
1958 pub h2r_weight: f64,
1959 #[serde(default = "default_a2r")]
1961 pub a2r_weight: f64,
1962}
1963
1964fn default_o2c() -> f64 {
1965 0.35
1966}
1967fn default_p2p() -> f64 {
1968 0.30
1969}
1970fn default_r2r() -> f64 {
1971 0.20
1972}
1973fn default_h2r() -> f64 {
1974 0.10
1975}
1976fn default_a2r() -> f64 {
1977 0.05
1978}
1979
1980impl Default for BusinessProcessConfig {
1981 fn default() -> Self {
1982 Self {
1983 o2c_weight: default_o2c(),
1984 p2p_weight: default_p2p(),
1985 r2r_weight: default_r2r(),
1986 h2r_weight: default_h2r(),
1987 a2r_weight: default_a2r(),
1988 }
1989 }
1990}
1991
1992#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1994pub struct UserPersonaConfig {
1995 #[serde(default)]
1997 pub persona_distribution: PersonaDistribution,
1998 #[serde(default)]
2000 pub users_per_persona: UsersPerPersona,
2001}
2002
2003#[derive(Debug, Clone, Serialize, Deserialize)]
2005pub struct PersonaDistribution {
2006 pub junior_accountant: f64,
2007 pub senior_accountant: f64,
2008 pub controller: f64,
2009 pub manager: f64,
2010 pub automated_system: f64,
2011}
2012
2013impl Default for PersonaDistribution {
2014 fn default() -> Self {
2015 Self {
2016 junior_accountant: 0.15,
2017 senior_accountant: 0.15,
2018 controller: 0.05,
2019 manager: 0.05,
2020 automated_system: 0.60,
2021 }
2022 }
2023}
2024
2025#[derive(Debug, Clone, Serialize, Deserialize)]
2027pub struct UsersPerPersona {
2028 pub junior_accountant: usize,
2029 pub senior_accountant: usize,
2030 pub controller: usize,
2031 pub manager: usize,
2032 pub automated_system: usize,
2033}
2034
2035impl Default for UsersPerPersona {
2036 fn default() -> Self {
2037 Self {
2038 junior_accountant: 10,
2039 senior_accountant: 5,
2040 controller: 2,
2041 manager: 3,
2042 automated_system: 20,
2043 }
2044 }
2045}
2046
2047#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2061pub struct TemplateConfig {
2062 #[serde(default)]
2064 pub names: NameTemplateConfig,
2065 #[serde(default)]
2067 pub descriptions: DescriptionTemplateConfig,
2068 #[serde(default)]
2070 pub references: ReferenceTemplateConfig,
2071 #[serde(default, alias = "templatesPath")]
2077 pub path: Option<std::path::PathBuf>,
2078 #[serde(default, alias = "mergeStrategy")]
2087 pub merge_strategy: TemplateMergeStrategy,
2088}
2089
2090#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
2092#[serde(rename_all = "snake_case")]
2093pub enum TemplateMergeStrategy {
2094 #[default]
2096 Extend,
2097 Replace,
2099 MergePreferFile,
2101}
2102
2103#[derive(Debug, Clone, Serialize, Deserialize)]
2105pub struct NameTemplateConfig {
2106 #[serde(default)]
2108 pub culture_distribution: CultureDistribution,
2109 #[serde(default = "default_email_domain")]
2111 pub email_domain: String,
2112 #[serde(default = "default_true")]
2114 pub generate_realistic_names: bool,
2115}
2116
2117fn default_email_domain() -> String {
2118 "company.com".to_string()
2119}
2120
2121impl Default for NameTemplateConfig {
2122 fn default() -> Self {
2123 Self {
2124 culture_distribution: CultureDistribution::default(),
2125 email_domain: default_email_domain(),
2126 generate_realistic_names: true,
2127 }
2128 }
2129}
2130
2131#[derive(Debug, Clone, Serialize, Deserialize)]
2133pub struct CultureDistribution {
2134 pub western_us: f64,
2135 pub hispanic: f64,
2136 pub german: f64,
2137 pub french: f64,
2138 pub chinese: f64,
2139 pub japanese: f64,
2140 pub indian: f64,
2141}
2142
2143impl Default for CultureDistribution {
2144 fn default() -> Self {
2145 Self {
2146 western_us: 0.40,
2147 hispanic: 0.20,
2148 german: 0.10,
2149 french: 0.05,
2150 chinese: 0.10,
2151 japanese: 0.05,
2152 indian: 0.10,
2153 }
2154 }
2155}
2156
2157#[derive(Debug, Clone, Serialize, Deserialize)]
2159pub struct DescriptionTemplateConfig {
2160 #[serde(default = "default_true")]
2162 pub generate_header_text: bool,
2163 #[serde(default = "default_true")]
2165 pub generate_line_text: bool,
2166}
2167
2168impl Default for DescriptionTemplateConfig {
2169 fn default() -> Self {
2170 Self {
2171 generate_header_text: true,
2172 generate_line_text: true,
2173 }
2174 }
2175}
2176
2177#[derive(Debug, Clone, Serialize, Deserialize)]
2179pub struct ReferenceTemplateConfig {
2180 #[serde(default = "default_true")]
2182 pub generate_references: bool,
2183 #[serde(default = "default_invoice_prefix")]
2185 pub invoice_prefix: String,
2186 #[serde(default = "default_po_prefix")]
2188 pub po_prefix: String,
2189 #[serde(default = "default_so_prefix")]
2191 pub so_prefix: String,
2192}
2193
2194fn default_invoice_prefix() -> String {
2195 "INV".to_string()
2196}
2197fn default_po_prefix() -> String {
2198 "PO".to_string()
2199}
2200fn default_so_prefix() -> String {
2201 "SO".to_string()
2202}
2203
2204impl Default for ReferenceTemplateConfig {
2205 fn default() -> Self {
2206 Self {
2207 generate_references: true,
2208 invoice_prefix: default_invoice_prefix(),
2209 po_prefix: default_po_prefix(),
2210 so_prefix: default_so_prefix(),
2211 }
2212 }
2213}
2214
2215#[derive(Debug, Clone, Serialize, Deserialize)]
2217pub struct ApprovalConfig {
2218 #[serde(default)]
2220 pub enabled: bool,
2221 #[serde(default = "default_auto_approve_threshold")]
2223 pub auto_approve_threshold: f64,
2224 #[serde(default = "default_rejection_rate")]
2226 pub rejection_rate: f64,
2227 #[serde(default = "default_revision_rate")]
2229 pub revision_rate: f64,
2230 #[serde(default = "default_approval_delay_hours")]
2232 pub average_approval_delay_hours: f64,
2233 #[serde(default)]
2235 pub thresholds: Vec<ApprovalThresholdConfig>,
2236}
2237
2238fn default_auto_approve_threshold() -> f64 {
2239 1000.0
2240}
2241fn default_rejection_rate() -> f64 {
2242 0.02
2243}
2244fn default_revision_rate() -> f64 {
2245 0.05
2246}
2247fn default_approval_delay_hours() -> f64 {
2248 4.0
2249}
2250
2251impl Default for ApprovalConfig {
2252 fn default() -> Self {
2253 Self {
2254 enabled: false,
2255 auto_approve_threshold: default_auto_approve_threshold(),
2256 rejection_rate: default_rejection_rate(),
2257 revision_rate: default_revision_rate(),
2258 average_approval_delay_hours: default_approval_delay_hours(),
2259 thresholds: vec![
2260 ApprovalThresholdConfig {
2261 amount: 1000.0,
2262 level: 1,
2263 roles: vec!["senior_accountant".to_string()],
2264 },
2265 ApprovalThresholdConfig {
2266 amount: 10000.0,
2267 level: 2,
2268 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2269 },
2270 ApprovalThresholdConfig {
2271 amount: 100000.0,
2272 level: 3,
2273 roles: vec![
2274 "senior_accountant".to_string(),
2275 "controller".to_string(),
2276 "manager".to_string(),
2277 ],
2278 },
2279 ApprovalThresholdConfig {
2280 amount: 500000.0,
2281 level: 4,
2282 roles: vec![
2283 "senior_accountant".to_string(),
2284 "controller".to_string(),
2285 "manager".to_string(),
2286 "executive".to_string(),
2287 ],
2288 },
2289 ],
2290 }
2291 }
2292}
2293
2294#[derive(Debug, Clone, Serialize, Deserialize)]
2296pub struct ApprovalThresholdConfig {
2297 pub amount: f64,
2299 pub level: u8,
2301 pub roles: Vec<String>,
2303}
2304
2305#[derive(Debug, Clone, Serialize, Deserialize)]
2307pub struct DepartmentConfig {
2308 #[serde(default)]
2310 pub enabled: bool,
2311 #[serde(default = "default_headcount_multiplier")]
2313 pub headcount_multiplier: f64,
2314 #[serde(default)]
2316 pub custom_departments: Vec<CustomDepartmentConfig>,
2317}
2318
2319fn default_headcount_multiplier() -> f64 {
2320 1.0
2321}
2322
2323impl Default for DepartmentConfig {
2324 fn default() -> Self {
2325 Self {
2326 enabled: false,
2327 headcount_multiplier: default_headcount_multiplier(),
2328 custom_departments: Vec::new(),
2329 }
2330 }
2331}
2332
2333#[derive(Debug, Clone, Serialize, Deserialize)]
2335pub struct CustomDepartmentConfig {
2336 pub code: String,
2338 pub name: String,
2340 #[serde(default)]
2342 pub cost_center: Option<String>,
2343 #[serde(default)]
2345 pub primary_processes: Vec<String>,
2346 #[serde(default)]
2348 pub parent_code: Option<String>,
2349}
2350
2351#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2357pub struct MasterDataConfig {
2358 #[serde(default)]
2360 pub vendors: VendorMasterConfig,
2361 #[serde(default)]
2363 pub customers: CustomerMasterConfig,
2364 #[serde(default)]
2366 pub materials: MaterialMasterConfig,
2367 #[serde(default)]
2369 pub fixed_assets: FixedAssetMasterConfig,
2370 #[serde(default)]
2372 pub employees: EmployeeMasterConfig,
2373 #[serde(default)]
2375 pub cost_centers: CostCenterMasterConfig,
2376}
2377
2378#[derive(Debug, Clone, Serialize, Deserialize)]
2380pub struct VendorMasterConfig {
2381 #[serde(default = "default_vendor_count")]
2383 pub count: usize,
2384 #[serde(default = "default_intercompany_percent")]
2386 pub intercompany_percent: f64,
2387 #[serde(default)]
2389 pub payment_terms_distribution: PaymentTermsDistribution,
2390 #[serde(default)]
2392 pub behavior_distribution: VendorBehaviorDistribution,
2393 #[serde(default = "default_true")]
2395 pub generate_bank_accounts: bool,
2396 #[serde(default = "default_true")]
2398 pub generate_tax_ids: bool,
2399}
2400
2401fn default_vendor_count() -> usize {
2402 500
2403}
2404
2405fn default_intercompany_percent() -> f64 {
2406 0.05
2407}
2408
2409impl Default for VendorMasterConfig {
2410 fn default() -> Self {
2411 Self {
2412 count: default_vendor_count(),
2413 intercompany_percent: default_intercompany_percent(),
2414 payment_terms_distribution: PaymentTermsDistribution::default(),
2415 behavior_distribution: VendorBehaviorDistribution::default(),
2416 generate_bank_accounts: true,
2417 generate_tax_ids: true,
2418 }
2419 }
2420}
2421
2422#[derive(Debug, Clone, Serialize, Deserialize)]
2424pub struct PaymentTermsDistribution {
2425 pub net_30: f64,
2427 pub net_60: f64,
2429 pub net_90: f64,
2431 pub two_ten_net_30: f64,
2433 pub due_on_receipt: f64,
2435 pub end_of_month: f64,
2437}
2438
2439impl Default for PaymentTermsDistribution {
2440 fn default() -> Self {
2441 Self {
2442 net_30: 0.40,
2443 net_60: 0.20,
2444 net_90: 0.10,
2445 two_ten_net_30: 0.15,
2446 due_on_receipt: 0.05,
2447 end_of_month: 0.10,
2448 }
2449 }
2450}
2451
2452#[derive(Debug, Clone, Serialize, Deserialize)]
2454pub struct VendorBehaviorDistribution {
2455 pub reliable: f64,
2457 pub sometimes_late: f64,
2459 pub inconsistent_quality: f64,
2461 pub premium: f64,
2463 pub budget: f64,
2465}
2466
2467impl Default for VendorBehaviorDistribution {
2468 fn default() -> Self {
2469 Self {
2470 reliable: 0.50,
2471 sometimes_late: 0.20,
2472 inconsistent_quality: 0.10,
2473 premium: 0.10,
2474 budget: 0.10,
2475 }
2476 }
2477}
2478
2479#[derive(Debug, Clone, Serialize, Deserialize)]
2481pub struct CustomerMasterConfig {
2482 #[serde(default = "default_customer_count")]
2484 pub count: usize,
2485 #[serde(default = "default_intercompany_percent")]
2487 pub intercompany_percent: f64,
2488 #[serde(default)]
2490 pub credit_rating_distribution: CreditRatingDistribution,
2491 #[serde(default)]
2493 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2494 #[serde(default = "default_true")]
2496 pub generate_credit_limits: bool,
2497}
2498
2499fn default_customer_count() -> usize {
2500 2000
2501}
2502
2503impl Default for CustomerMasterConfig {
2504 fn default() -> Self {
2505 Self {
2506 count: default_customer_count(),
2507 intercompany_percent: default_intercompany_percent(),
2508 credit_rating_distribution: CreditRatingDistribution::default(),
2509 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2510 generate_credit_limits: true,
2511 }
2512 }
2513}
2514
2515#[derive(Debug, Clone, Serialize, Deserialize)]
2517pub struct CreditRatingDistribution {
2518 pub aaa: f64,
2520 pub aa: f64,
2522 pub a: f64,
2524 pub bbb: f64,
2526 pub bb: f64,
2528 pub b: f64,
2530 pub below_b: f64,
2532}
2533
2534impl Default for CreditRatingDistribution {
2535 fn default() -> Self {
2536 Self {
2537 aaa: 0.05,
2538 aa: 0.10,
2539 a: 0.20,
2540 bbb: 0.30,
2541 bb: 0.20,
2542 b: 0.10,
2543 below_b: 0.05,
2544 }
2545 }
2546}
2547
2548#[derive(Debug, Clone, Serialize, Deserialize)]
2550pub struct PaymentBehaviorDistribution {
2551 pub early_payer: f64,
2553 pub on_time: f64,
2555 pub occasional_late: f64,
2557 pub frequent_late: f64,
2559 pub discount_taker: f64,
2561}
2562
2563impl Default for PaymentBehaviorDistribution {
2564 fn default() -> Self {
2565 Self {
2566 early_payer: 0.10,
2567 on_time: 0.50,
2568 occasional_late: 0.25,
2569 frequent_late: 0.10,
2570 discount_taker: 0.05,
2571 }
2572 }
2573}
2574
2575#[derive(Debug, Clone, Serialize, Deserialize)]
2577pub struct MaterialMasterConfig {
2578 #[serde(default = "default_material_count")]
2580 pub count: usize,
2581 #[serde(default)]
2583 pub type_distribution: MaterialTypeDistribution,
2584 #[serde(default)]
2586 pub valuation_distribution: ValuationMethodDistribution,
2587 #[serde(default = "default_bom_percent")]
2589 pub bom_percent: f64,
2590 #[serde(default = "default_max_bom_depth")]
2592 pub max_bom_depth: u8,
2593}
2594
2595fn default_material_count() -> usize {
2596 5000
2597}
2598
2599fn default_bom_percent() -> f64 {
2600 0.20
2601}
2602
2603fn default_max_bom_depth() -> u8 {
2604 3
2605}
2606
2607impl Default for MaterialMasterConfig {
2608 fn default() -> Self {
2609 Self {
2610 count: default_material_count(),
2611 type_distribution: MaterialTypeDistribution::default(),
2612 valuation_distribution: ValuationMethodDistribution::default(),
2613 bom_percent: default_bom_percent(),
2614 max_bom_depth: default_max_bom_depth(),
2615 }
2616 }
2617}
2618
2619#[derive(Debug, Clone, Serialize, Deserialize)]
2621pub struct MaterialTypeDistribution {
2622 pub raw_material: f64,
2624 pub semi_finished: f64,
2626 pub finished_good: f64,
2628 pub trading_good: f64,
2630 pub operating_supply: f64,
2632 pub service: f64,
2634}
2635
2636impl Default for MaterialTypeDistribution {
2637 fn default() -> Self {
2638 Self {
2639 raw_material: 0.30,
2640 semi_finished: 0.15,
2641 finished_good: 0.25,
2642 trading_good: 0.15,
2643 operating_supply: 0.10,
2644 service: 0.05,
2645 }
2646 }
2647}
2648
2649#[derive(Debug, Clone, Serialize, Deserialize)]
2651pub struct ValuationMethodDistribution {
2652 pub standard_cost: f64,
2654 pub moving_average: f64,
2656 pub fifo: f64,
2658 pub lifo: f64,
2660}
2661
2662impl Default for ValuationMethodDistribution {
2663 fn default() -> Self {
2664 Self {
2665 standard_cost: 0.50,
2666 moving_average: 0.30,
2667 fifo: 0.15,
2668 lifo: 0.05,
2669 }
2670 }
2671}
2672
2673#[derive(Debug, Clone, Serialize, Deserialize)]
2675pub struct FixedAssetMasterConfig {
2676 #[serde(default = "default_asset_count")]
2678 pub count: usize,
2679 #[serde(default)]
2681 pub class_distribution: AssetClassDistribution,
2682 #[serde(default)]
2684 pub depreciation_distribution: DepreciationMethodDistribution,
2685 #[serde(default = "default_fully_depreciated_percent")]
2687 pub fully_depreciated_percent: f64,
2688 #[serde(default = "default_true")]
2690 pub generate_acquisition_history: bool,
2691}
2692
2693fn default_asset_count() -> usize {
2694 800
2695}
2696
2697fn default_fully_depreciated_percent() -> f64 {
2698 0.15
2699}
2700
2701impl Default for FixedAssetMasterConfig {
2702 fn default() -> Self {
2703 Self {
2704 count: default_asset_count(),
2705 class_distribution: AssetClassDistribution::default(),
2706 depreciation_distribution: DepreciationMethodDistribution::default(),
2707 fully_depreciated_percent: default_fully_depreciated_percent(),
2708 generate_acquisition_history: true,
2709 }
2710 }
2711}
2712
2713#[derive(Debug, Clone, Serialize, Deserialize)]
2715pub struct AssetClassDistribution {
2716 pub buildings: f64,
2718 pub machinery: f64,
2720 pub vehicles: f64,
2722 pub it_equipment: f64,
2724 pub furniture: f64,
2726 pub land: f64,
2728 pub leasehold: f64,
2730}
2731
2732impl Default for AssetClassDistribution {
2733 fn default() -> Self {
2734 Self {
2735 buildings: 0.15,
2736 machinery: 0.30,
2737 vehicles: 0.15,
2738 it_equipment: 0.20,
2739 furniture: 0.10,
2740 land: 0.05,
2741 leasehold: 0.05,
2742 }
2743 }
2744}
2745
2746#[derive(Debug, Clone, Serialize, Deserialize)]
2748pub struct DepreciationMethodDistribution {
2749 pub straight_line: f64,
2751 pub declining_balance: f64,
2753 pub double_declining: f64,
2755 pub sum_of_years: f64,
2757 pub units_of_production: f64,
2759}
2760
2761impl Default for DepreciationMethodDistribution {
2762 fn default() -> Self {
2763 Self {
2764 straight_line: 0.60,
2765 declining_balance: 0.20,
2766 double_declining: 0.10,
2767 sum_of_years: 0.05,
2768 units_of_production: 0.05,
2769 }
2770 }
2771}
2772
2773#[derive(Debug, Clone, Serialize, Deserialize)]
2775pub struct EmployeeMasterConfig {
2776 #[serde(default = "default_employee_count")]
2778 pub count: usize,
2779 #[serde(default = "default_true")]
2781 pub generate_hierarchy: bool,
2782 #[serde(default = "default_hierarchy_depth")]
2784 pub max_hierarchy_depth: u8,
2785 #[serde(default = "default_span_of_control")]
2787 pub average_span_of_control: f64,
2788 #[serde(default)]
2790 pub approval_limits: ApprovalLimitDistribution,
2791 #[serde(default)]
2793 pub department_distribution: EmployeeDepartmentDistribution,
2794}
2795
2796fn default_employee_count() -> usize {
2797 1500
2798}
2799
2800fn default_hierarchy_depth() -> u8 {
2801 6
2802}
2803
2804fn default_span_of_control() -> f64 {
2805 5.0
2806}
2807
2808impl Default for EmployeeMasterConfig {
2809 fn default() -> Self {
2810 Self {
2811 count: default_employee_count(),
2812 generate_hierarchy: true,
2813 max_hierarchy_depth: default_hierarchy_depth(),
2814 average_span_of_control: default_span_of_control(),
2815 approval_limits: ApprovalLimitDistribution::default(),
2816 department_distribution: EmployeeDepartmentDistribution::default(),
2817 }
2818 }
2819}
2820
2821#[derive(Debug, Clone, Serialize, Deserialize)]
2823pub struct ApprovalLimitDistribution {
2824 #[serde(default = "default_staff_limit")]
2826 pub staff: f64,
2827 #[serde(default = "default_senior_limit")]
2829 pub senior: f64,
2830 #[serde(default = "default_manager_limit")]
2832 pub manager: f64,
2833 #[serde(default = "default_director_limit")]
2835 pub director: f64,
2836 #[serde(default = "default_vp_limit")]
2838 pub vp: f64,
2839 #[serde(default = "default_executive_limit")]
2841 pub executive: f64,
2842}
2843
2844fn default_staff_limit() -> f64 {
2845 1000.0
2846}
2847fn default_senior_limit() -> f64 {
2848 5000.0
2849}
2850fn default_manager_limit() -> f64 {
2851 25000.0
2852}
2853fn default_director_limit() -> f64 {
2854 100000.0
2855}
2856fn default_vp_limit() -> f64 {
2857 500000.0
2858}
2859fn default_executive_limit() -> f64 {
2860 f64::INFINITY
2861}
2862
2863impl Default for ApprovalLimitDistribution {
2864 fn default() -> Self {
2865 Self {
2866 staff: default_staff_limit(),
2867 senior: default_senior_limit(),
2868 manager: default_manager_limit(),
2869 director: default_director_limit(),
2870 vp: default_vp_limit(),
2871 executive: default_executive_limit(),
2872 }
2873 }
2874}
2875
2876#[derive(Debug, Clone, Serialize, Deserialize)]
2878pub struct EmployeeDepartmentDistribution {
2879 pub finance: f64,
2881 pub procurement: f64,
2883 pub sales: f64,
2885 pub warehouse: f64,
2887 pub it: f64,
2889 pub hr: f64,
2891 pub operations: f64,
2893 pub executive: f64,
2895}
2896
2897impl Default for EmployeeDepartmentDistribution {
2898 fn default() -> Self {
2899 Self {
2900 finance: 0.12,
2901 procurement: 0.10,
2902 sales: 0.25,
2903 warehouse: 0.15,
2904 it: 0.10,
2905 hr: 0.05,
2906 operations: 0.20,
2907 executive: 0.03,
2908 }
2909 }
2910}
2911
2912#[derive(Debug, Clone, Serialize, Deserialize)]
2914pub struct CostCenterMasterConfig {
2915 #[serde(default = "default_cost_center_count")]
2917 pub count: usize,
2918 #[serde(default = "default_true")]
2920 pub generate_hierarchy: bool,
2921 #[serde(default = "default_cc_hierarchy_depth")]
2923 pub max_hierarchy_depth: u8,
2924}
2925
2926fn default_cost_center_count() -> usize {
2927 50
2928}
2929
2930fn default_cc_hierarchy_depth() -> u8 {
2931 3
2932}
2933
2934impl Default for CostCenterMasterConfig {
2935 fn default() -> Self {
2936 Self {
2937 count: default_cost_center_count(),
2938 generate_hierarchy: true,
2939 max_hierarchy_depth: default_cc_hierarchy_depth(),
2940 }
2941 }
2942}
2943
2944#[derive(Debug, Clone, Serialize, Deserialize)]
2950pub struct DocumentFlowConfig {
2951 #[serde(default)]
2953 pub p2p: P2PFlowConfig,
2954 #[serde(default)]
2956 pub o2c: O2CFlowConfig,
2957 #[serde(default = "default_true")]
2959 pub generate_document_references: bool,
2960 #[serde(default)]
2962 pub export_flow_graph: bool,
2963}
2964
2965impl Default for DocumentFlowConfig {
2966 fn default() -> Self {
2967 Self {
2968 p2p: P2PFlowConfig::default(),
2969 o2c: O2CFlowConfig::default(),
2970 generate_document_references: true,
2971 export_flow_graph: false,
2972 }
2973 }
2974}
2975
2976#[derive(Debug, Clone, Serialize, Deserialize)]
2978pub struct P2PFlowConfig {
2979 #[serde(default = "default_true")]
2981 pub enabled: bool,
2982 #[serde(default = "default_three_way_match_rate")]
2984 pub three_way_match_rate: f64,
2985 #[serde(default = "default_partial_delivery_rate")]
2987 pub partial_delivery_rate: f64,
2988 #[serde(default = "default_price_variance_rate")]
2990 pub price_variance_rate: f64,
2991 #[serde(default = "default_max_price_variance")]
2993 pub max_price_variance_percent: f64,
2994 #[serde(default = "default_quantity_variance_rate")]
2996 pub quantity_variance_rate: f64,
2997 #[serde(default = "default_po_to_gr_days")]
2999 pub average_po_to_gr_days: u32,
3000 #[serde(default = "default_gr_to_invoice_days")]
3002 pub average_gr_to_invoice_days: u32,
3003 #[serde(default = "default_invoice_to_payment_days")]
3005 pub average_invoice_to_payment_days: u32,
3006 #[serde(default)]
3008 pub line_count_distribution: DocumentLineCountDistribution,
3009 #[serde(default)]
3011 pub payment_behavior: P2PPaymentBehaviorConfig,
3012 #[serde(default)]
3014 pub over_delivery_rate: Option<f64>,
3015 #[serde(default)]
3017 pub early_payment_discount_rate: Option<f64>,
3018}
3019
3020fn default_three_way_match_rate() -> f64 {
3021 0.95
3022}
3023
3024fn default_partial_delivery_rate() -> f64 {
3025 0.15
3026}
3027
3028fn default_price_variance_rate() -> f64 {
3029 0.08
3030}
3031
3032fn default_max_price_variance() -> f64 {
3033 0.05
3034}
3035
3036fn default_quantity_variance_rate() -> f64 {
3037 0.05
3038}
3039
3040fn default_po_to_gr_days() -> u32 {
3041 14
3042}
3043
3044fn default_gr_to_invoice_days() -> u32 {
3045 5
3046}
3047
3048fn default_invoice_to_payment_days() -> u32 {
3049 30
3050}
3051
3052impl Default for P2PFlowConfig {
3053 fn default() -> Self {
3054 Self {
3055 enabled: true,
3056 three_way_match_rate: default_three_way_match_rate(),
3057 partial_delivery_rate: default_partial_delivery_rate(),
3058 price_variance_rate: default_price_variance_rate(),
3059 max_price_variance_percent: default_max_price_variance(),
3060 quantity_variance_rate: default_quantity_variance_rate(),
3061 average_po_to_gr_days: default_po_to_gr_days(),
3062 average_gr_to_invoice_days: default_gr_to_invoice_days(),
3063 average_invoice_to_payment_days: default_invoice_to_payment_days(),
3064 line_count_distribution: DocumentLineCountDistribution::default(),
3065 payment_behavior: P2PPaymentBehaviorConfig::default(),
3066 over_delivery_rate: None,
3067 early_payment_discount_rate: None,
3068 }
3069 }
3070}
3071
3072#[derive(Debug, Clone, Serialize, Deserialize)]
3078pub struct P2PPaymentBehaviorConfig {
3079 #[serde(default = "default_p2p_late_payment_rate")]
3081 pub late_payment_rate: f64,
3082 #[serde(default)]
3084 pub late_payment_days_distribution: LatePaymentDaysDistribution,
3085 #[serde(default = "default_p2p_partial_payment_rate")]
3087 pub partial_payment_rate: f64,
3088 #[serde(default = "default_p2p_payment_correction_rate")]
3090 pub payment_correction_rate: f64,
3091 #[serde(default = "default_p2p_avg_days_until_remainder")]
3093 pub avg_days_until_remainder: u32,
3094}
3095
3096fn default_p2p_late_payment_rate() -> f64 {
3097 0.15
3098}
3099
3100fn default_p2p_partial_payment_rate() -> f64 {
3101 0.05
3102}
3103
3104fn default_p2p_payment_correction_rate() -> f64 {
3105 0.02
3106}
3107
3108fn default_p2p_avg_days_until_remainder() -> u32 {
3109 30
3110}
3111
3112impl Default for P2PPaymentBehaviorConfig {
3113 fn default() -> Self {
3114 Self {
3115 late_payment_rate: default_p2p_late_payment_rate(),
3116 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3117 partial_payment_rate: default_p2p_partial_payment_rate(),
3118 payment_correction_rate: default_p2p_payment_correction_rate(),
3119 avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3120 }
3121 }
3122}
3123
3124#[derive(Debug, Clone, Serialize, Deserialize)]
3126pub struct LatePaymentDaysDistribution {
3127 #[serde(default = "default_slightly_late")]
3129 pub slightly_late_1_to_7: f64,
3130 #[serde(default = "default_late_8_14")]
3132 pub late_8_to_14: f64,
3133 #[serde(default = "default_very_late")]
3135 pub very_late_15_to_30: f64,
3136 #[serde(default = "default_severely_late")]
3138 pub severely_late_31_to_60: f64,
3139 #[serde(default = "default_extremely_late")]
3141 pub extremely_late_over_60: f64,
3142}
3143
3144fn default_slightly_late() -> f64 {
3145 0.50
3146}
3147
3148fn default_late_8_14() -> f64 {
3149 0.25
3150}
3151
3152fn default_very_late() -> f64 {
3153 0.15
3154}
3155
3156fn default_severely_late() -> f64 {
3157 0.07
3158}
3159
3160fn default_extremely_late() -> f64 {
3161 0.03
3162}
3163
3164impl Default for LatePaymentDaysDistribution {
3165 fn default() -> Self {
3166 Self {
3167 slightly_late_1_to_7: default_slightly_late(),
3168 late_8_to_14: default_late_8_14(),
3169 very_late_15_to_30: default_very_late(),
3170 severely_late_31_to_60: default_severely_late(),
3171 extremely_late_over_60: default_extremely_late(),
3172 }
3173 }
3174}
3175
3176#[derive(Debug, Clone, Serialize, Deserialize)]
3178pub struct O2CFlowConfig {
3179 #[serde(default = "default_true")]
3181 pub enabled: bool,
3182 #[serde(default = "default_credit_check_failure_rate")]
3184 pub credit_check_failure_rate: f64,
3185 #[serde(default = "default_partial_shipment_rate")]
3187 pub partial_shipment_rate: f64,
3188 #[serde(default = "default_return_rate")]
3190 pub return_rate: f64,
3191 #[serde(default = "default_bad_debt_rate")]
3193 pub bad_debt_rate: f64,
3194 #[serde(default = "default_so_to_delivery_days")]
3196 pub average_so_to_delivery_days: u32,
3197 #[serde(default = "default_delivery_to_invoice_days")]
3199 pub average_delivery_to_invoice_days: u32,
3200 #[serde(default = "default_invoice_to_receipt_days")]
3202 pub average_invoice_to_receipt_days: u32,
3203 #[serde(default)]
3205 pub line_count_distribution: DocumentLineCountDistribution,
3206 #[serde(default)]
3208 pub cash_discount: CashDiscountConfig,
3209 #[serde(default)]
3211 pub payment_behavior: O2CPaymentBehaviorConfig,
3212 #[serde(default)]
3214 pub late_payment_rate: Option<f64>,
3215}
3216
3217fn default_credit_check_failure_rate() -> f64 {
3218 0.02
3219}
3220
3221fn default_partial_shipment_rate() -> f64 {
3222 0.10
3223}
3224
3225fn default_return_rate() -> f64 {
3226 0.03
3227}
3228
3229fn default_bad_debt_rate() -> f64 {
3230 0.01
3231}
3232
3233fn default_so_to_delivery_days() -> u32 {
3234 7
3235}
3236
3237fn default_delivery_to_invoice_days() -> u32 {
3238 1
3239}
3240
3241fn default_invoice_to_receipt_days() -> u32 {
3242 45
3243}
3244
3245impl Default for O2CFlowConfig {
3246 fn default() -> Self {
3247 Self {
3248 enabled: true,
3249 credit_check_failure_rate: default_credit_check_failure_rate(),
3250 partial_shipment_rate: default_partial_shipment_rate(),
3251 return_rate: default_return_rate(),
3252 bad_debt_rate: default_bad_debt_rate(),
3253 average_so_to_delivery_days: default_so_to_delivery_days(),
3254 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3255 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3256 line_count_distribution: DocumentLineCountDistribution::default(),
3257 cash_discount: CashDiscountConfig::default(),
3258 payment_behavior: O2CPaymentBehaviorConfig::default(),
3259 late_payment_rate: None,
3260 }
3261 }
3262}
3263
3264#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3270pub struct O2CPaymentBehaviorConfig {
3271 #[serde(default)]
3273 pub dunning: DunningConfig,
3274 #[serde(default)]
3276 pub partial_payments: PartialPaymentConfig,
3277 #[serde(default)]
3279 pub short_payments: ShortPaymentConfig,
3280 #[serde(default)]
3282 pub on_account_payments: OnAccountPaymentConfig,
3283 #[serde(default)]
3285 pub payment_corrections: PaymentCorrectionConfig,
3286}
3287
3288#[derive(Debug, Clone, Serialize, Deserialize)]
3290pub struct DunningConfig {
3291 #[serde(default)]
3293 pub enabled: bool,
3294 #[serde(default = "default_dunning_level_1_days")]
3296 pub level_1_days_overdue: u32,
3297 #[serde(default = "default_dunning_level_2_days")]
3299 pub level_2_days_overdue: u32,
3300 #[serde(default = "default_dunning_level_3_days")]
3302 pub level_3_days_overdue: u32,
3303 #[serde(default = "default_collection_days")]
3305 pub collection_days_overdue: u32,
3306 #[serde(default)]
3308 pub payment_after_dunning_rates: DunningPaymentRates,
3309 #[serde(default = "default_dunning_block_rate")]
3311 pub dunning_block_rate: f64,
3312 #[serde(default = "default_dunning_interest_rate")]
3314 pub interest_rate_per_year: f64,
3315 #[serde(default = "default_dunning_charge")]
3317 pub dunning_charge: f64,
3318}
3319
3320fn default_dunning_level_1_days() -> u32 {
3321 14
3322}
3323
3324fn default_dunning_level_2_days() -> u32 {
3325 28
3326}
3327
3328fn default_dunning_level_3_days() -> u32 {
3329 42
3330}
3331
3332fn default_collection_days() -> u32 {
3333 60
3334}
3335
3336fn default_dunning_block_rate() -> f64 {
3337 0.05
3338}
3339
3340fn default_dunning_interest_rate() -> f64 {
3341 0.09
3342}
3343
3344fn default_dunning_charge() -> f64 {
3345 25.0
3346}
3347
3348impl Default for DunningConfig {
3349 fn default() -> Self {
3350 Self {
3351 enabled: false,
3352 level_1_days_overdue: default_dunning_level_1_days(),
3353 level_2_days_overdue: default_dunning_level_2_days(),
3354 level_3_days_overdue: default_dunning_level_3_days(),
3355 collection_days_overdue: default_collection_days(),
3356 payment_after_dunning_rates: DunningPaymentRates::default(),
3357 dunning_block_rate: default_dunning_block_rate(),
3358 interest_rate_per_year: default_dunning_interest_rate(),
3359 dunning_charge: default_dunning_charge(),
3360 }
3361 }
3362}
3363
3364#[derive(Debug, Clone, Serialize, Deserialize)]
3366pub struct DunningPaymentRates {
3367 #[serde(default = "default_after_level_1")]
3369 pub after_level_1: f64,
3370 #[serde(default = "default_after_level_2")]
3372 pub after_level_2: f64,
3373 #[serde(default = "default_after_level_3")]
3375 pub after_level_3: f64,
3376 #[serde(default = "default_during_collection")]
3378 pub during_collection: f64,
3379 #[serde(default = "default_never_pay")]
3381 pub never_pay: f64,
3382}
3383
3384fn default_after_level_1() -> f64 {
3385 0.40
3386}
3387
3388fn default_after_level_2() -> f64 {
3389 0.30
3390}
3391
3392fn default_after_level_3() -> f64 {
3393 0.15
3394}
3395
3396fn default_during_collection() -> f64 {
3397 0.05
3398}
3399
3400fn default_never_pay() -> f64 {
3401 0.10
3402}
3403
3404impl Default for DunningPaymentRates {
3405 fn default() -> Self {
3406 Self {
3407 after_level_1: default_after_level_1(),
3408 after_level_2: default_after_level_2(),
3409 after_level_3: default_after_level_3(),
3410 during_collection: default_during_collection(),
3411 never_pay: default_never_pay(),
3412 }
3413 }
3414}
3415
3416#[derive(Debug, Clone, Serialize, Deserialize)]
3418pub struct PartialPaymentConfig {
3419 #[serde(default = "default_partial_payment_rate")]
3421 pub rate: f64,
3422 #[serde(default)]
3424 pub percentage_distribution: PartialPaymentPercentageDistribution,
3425 #[serde(default = "default_avg_days_until_remainder")]
3427 pub avg_days_until_remainder: u32,
3428}
3429
3430fn default_partial_payment_rate() -> f64 {
3431 0.08
3432}
3433
3434fn default_avg_days_until_remainder() -> u32 {
3435 30
3436}
3437
3438impl Default for PartialPaymentConfig {
3439 fn default() -> Self {
3440 Self {
3441 rate: default_partial_payment_rate(),
3442 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3443 avg_days_until_remainder: default_avg_days_until_remainder(),
3444 }
3445 }
3446}
3447
3448#[derive(Debug, Clone, Serialize, Deserialize)]
3450pub struct PartialPaymentPercentageDistribution {
3451 #[serde(default = "default_partial_25")]
3453 pub pay_25_percent: f64,
3454 #[serde(default = "default_partial_50")]
3456 pub pay_50_percent: f64,
3457 #[serde(default = "default_partial_75")]
3459 pub pay_75_percent: f64,
3460 #[serde(default = "default_partial_random")]
3462 pub pay_random_percent: f64,
3463}
3464
3465fn default_partial_25() -> f64 {
3466 0.15
3467}
3468
3469fn default_partial_50() -> f64 {
3470 0.50
3471}
3472
3473fn default_partial_75() -> f64 {
3474 0.25
3475}
3476
3477fn default_partial_random() -> f64 {
3478 0.10
3479}
3480
3481impl Default for PartialPaymentPercentageDistribution {
3482 fn default() -> Self {
3483 Self {
3484 pay_25_percent: default_partial_25(),
3485 pay_50_percent: default_partial_50(),
3486 pay_75_percent: default_partial_75(),
3487 pay_random_percent: default_partial_random(),
3488 }
3489 }
3490}
3491
3492#[derive(Debug, Clone, Serialize, Deserialize)]
3494pub struct ShortPaymentConfig {
3495 #[serde(default = "default_short_payment_rate")]
3497 pub rate: f64,
3498 #[serde(default)]
3500 pub reason_distribution: ShortPaymentReasonDistribution,
3501 #[serde(default = "default_max_short_percent")]
3503 pub max_short_percent: f64,
3504}
3505
3506fn default_short_payment_rate() -> f64 {
3507 0.03
3508}
3509
3510fn default_max_short_percent() -> f64 {
3511 0.10
3512}
3513
3514impl Default for ShortPaymentConfig {
3515 fn default() -> Self {
3516 Self {
3517 rate: default_short_payment_rate(),
3518 reason_distribution: ShortPaymentReasonDistribution::default(),
3519 max_short_percent: default_max_short_percent(),
3520 }
3521 }
3522}
3523
3524#[derive(Debug, Clone, Serialize, Deserialize)]
3526pub struct ShortPaymentReasonDistribution {
3527 #[serde(default = "default_pricing_dispute")]
3529 pub pricing_dispute: f64,
3530 #[serde(default = "default_quality_issue")]
3532 pub quality_issue: f64,
3533 #[serde(default = "default_quantity_discrepancy")]
3535 pub quantity_discrepancy: f64,
3536 #[serde(default = "default_unauthorized_deduction")]
3538 pub unauthorized_deduction: f64,
3539 #[serde(default = "default_incorrect_discount")]
3541 pub incorrect_discount: f64,
3542}
3543
3544fn default_pricing_dispute() -> f64 {
3545 0.30
3546}
3547
3548fn default_quality_issue() -> f64 {
3549 0.20
3550}
3551
3552fn default_quantity_discrepancy() -> f64 {
3553 0.20
3554}
3555
3556fn default_unauthorized_deduction() -> f64 {
3557 0.15
3558}
3559
3560fn default_incorrect_discount() -> f64 {
3561 0.15
3562}
3563
3564impl Default for ShortPaymentReasonDistribution {
3565 fn default() -> Self {
3566 Self {
3567 pricing_dispute: default_pricing_dispute(),
3568 quality_issue: default_quality_issue(),
3569 quantity_discrepancy: default_quantity_discrepancy(),
3570 unauthorized_deduction: default_unauthorized_deduction(),
3571 incorrect_discount: default_incorrect_discount(),
3572 }
3573 }
3574}
3575
3576#[derive(Debug, Clone, Serialize, Deserialize)]
3578pub struct OnAccountPaymentConfig {
3579 #[serde(default = "default_on_account_rate")]
3581 pub rate: f64,
3582 #[serde(default = "default_avg_days_until_applied")]
3584 pub avg_days_until_applied: u32,
3585}
3586
3587fn default_on_account_rate() -> f64 {
3588 0.02
3589}
3590
3591fn default_avg_days_until_applied() -> u32 {
3592 14
3593}
3594
3595impl Default for OnAccountPaymentConfig {
3596 fn default() -> Self {
3597 Self {
3598 rate: default_on_account_rate(),
3599 avg_days_until_applied: default_avg_days_until_applied(),
3600 }
3601 }
3602}
3603
3604#[derive(Debug, Clone, Serialize, Deserialize)]
3606pub struct PaymentCorrectionConfig {
3607 #[serde(default = "default_payment_correction_rate")]
3609 pub rate: f64,
3610 #[serde(default)]
3612 pub type_distribution: PaymentCorrectionTypeDistribution,
3613}
3614
3615fn default_payment_correction_rate() -> f64 {
3616 0.02
3617}
3618
3619impl Default for PaymentCorrectionConfig {
3620 fn default() -> Self {
3621 Self {
3622 rate: default_payment_correction_rate(),
3623 type_distribution: PaymentCorrectionTypeDistribution::default(),
3624 }
3625 }
3626}
3627
3628#[derive(Debug, Clone, Serialize, Deserialize)]
3630pub struct PaymentCorrectionTypeDistribution {
3631 #[serde(default = "default_nsf_rate")]
3633 pub nsf: f64,
3634 #[serde(default = "default_chargeback_rate")]
3636 pub chargeback: f64,
3637 #[serde(default = "default_wrong_amount_rate")]
3639 pub wrong_amount: f64,
3640 #[serde(default = "default_wrong_customer_rate")]
3642 pub wrong_customer: f64,
3643 #[serde(default = "default_duplicate_payment_rate")]
3645 pub duplicate_payment: f64,
3646}
3647
3648fn default_nsf_rate() -> f64 {
3649 0.30
3650}
3651
3652fn default_chargeback_rate() -> f64 {
3653 0.20
3654}
3655
3656fn default_wrong_amount_rate() -> f64 {
3657 0.20
3658}
3659
3660fn default_wrong_customer_rate() -> f64 {
3661 0.15
3662}
3663
3664fn default_duplicate_payment_rate() -> f64 {
3665 0.15
3666}
3667
3668impl Default for PaymentCorrectionTypeDistribution {
3669 fn default() -> Self {
3670 Self {
3671 nsf: default_nsf_rate(),
3672 chargeback: default_chargeback_rate(),
3673 wrong_amount: default_wrong_amount_rate(),
3674 wrong_customer: default_wrong_customer_rate(),
3675 duplicate_payment: default_duplicate_payment_rate(),
3676 }
3677 }
3678}
3679
3680#[derive(Debug, Clone, Serialize, Deserialize)]
3682pub struct DocumentLineCountDistribution {
3683 #[serde(default = "default_min_lines")]
3685 pub min_lines: u32,
3686 #[serde(default = "default_max_lines")]
3688 pub max_lines: u32,
3689 #[serde(default = "default_mode_lines")]
3691 pub mode_lines: u32,
3692}
3693
3694fn default_min_lines() -> u32 {
3695 1
3696}
3697
3698fn default_max_lines() -> u32 {
3699 20
3700}
3701
3702fn default_mode_lines() -> u32 {
3703 3
3704}
3705
3706impl Default for DocumentLineCountDistribution {
3707 fn default() -> Self {
3708 Self {
3709 min_lines: default_min_lines(),
3710 max_lines: default_max_lines(),
3711 mode_lines: default_mode_lines(),
3712 }
3713 }
3714}
3715
3716#[derive(Debug, Clone, Serialize, Deserialize)]
3718pub struct CashDiscountConfig {
3719 #[serde(default = "default_discount_eligible_rate")]
3721 pub eligible_rate: f64,
3722 #[serde(default = "default_discount_taken_rate")]
3724 pub taken_rate: f64,
3725 #[serde(default = "default_discount_percent")]
3727 pub discount_percent: f64,
3728 #[serde(default = "default_discount_days")]
3730 pub discount_days: u32,
3731}
3732
3733fn default_discount_eligible_rate() -> f64 {
3734 0.30
3735}
3736
3737fn default_discount_taken_rate() -> f64 {
3738 0.60
3739}
3740
3741fn default_discount_percent() -> f64 {
3742 0.02
3743}
3744
3745fn default_discount_days() -> u32 {
3746 10
3747}
3748
3749impl Default for CashDiscountConfig {
3750 fn default() -> Self {
3751 Self {
3752 eligible_rate: default_discount_eligible_rate(),
3753 taken_rate: default_discount_taken_rate(),
3754 discount_percent: default_discount_percent(),
3755 discount_days: default_discount_days(),
3756 }
3757 }
3758}
3759
3760#[derive(Debug, Clone, Serialize, Deserialize)]
3766pub struct IntercompanyConfig {
3767 #[serde(default)]
3769 pub enabled: bool,
3770 #[serde(default = "default_ic_transaction_rate")]
3772 pub ic_transaction_rate: f64,
3773 #[serde(default)]
3775 pub transfer_pricing_method: TransferPricingMethod,
3776 #[serde(default = "default_markup_percent")]
3778 pub markup_percent: f64,
3779 #[serde(default = "default_true")]
3781 pub generate_matched_pairs: bool,
3782 #[serde(default)]
3784 pub transaction_type_distribution: ICTransactionTypeDistribution,
3785 #[serde(default)]
3787 pub generate_eliminations: bool,
3788}
3789
3790fn default_ic_transaction_rate() -> f64 {
3791 0.15
3792}
3793
3794fn default_markup_percent() -> f64 {
3795 0.05
3796}
3797
3798impl Default for IntercompanyConfig {
3799 fn default() -> Self {
3800 Self {
3801 enabled: false,
3802 ic_transaction_rate: default_ic_transaction_rate(),
3803 transfer_pricing_method: TransferPricingMethod::default(),
3804 markup_percent: default_markup_percent(),
3805 generate_matched_pairs: true,
3806 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3807 generate_eliminations: false,
3808 }
3809 }
3810}
3811
3812#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3814#[serde(rename_all = "snake_case")]
3815pub enum TransferPricingMethod {
3816 #[default]
3818 CostPlus,
3819 ComparableUncontrolled,
3821 ResalePrice,
3823 TransactionalNetMargin,
3825 ProfitSplit,
3827}
3828
3829#[derive(Debug, Clone, Serialize, Deserialize)]
3831pub struct ICTransactionTypeDistribution {
3832 pub goods_sale: f64,
3834 pub service_provided: f64,
3836 pub loan: f64,
3838 pub dividend: f64,
3840 pub management_fee: f64,
3842 pub royalty: f64,
3844 pub cost_sharing: f64,
3846}
3847
3848impl Default for ICTransactionTypeDistribution {
3849 fn default() -> Self {
3850 Self {
3851 goods_sale: 0.35,
3852 service_provided: 0.20,
3853 loan: 0.10,
3854 dividend: 0.05,
3855 management_fee: 0.15,
3856 royalty: 0.10,
3857 cost_sharing: 0.05,
3858 }
3859 }
3860}
3861
3862#[derive(Debug, Clone, Serialize, Deserialize)]
3868pub struct BalanceConfig {
3869 #[serde(default)]
3871 pub generate_opening_balances: bool,
3872 #[serde(default = "default_true")]
3874 pub generate_trial_balances: bool,
3875 #[serde(default = "default_gross_margin")]
3877 pub target_gross_margin: f64,
3878 #[serde(default = "default_dso")]
3880 pub target_dso_days: u32,
3881 #[serde(default = "default_dpo")]
3883 pub target_dpo_days: u32,
3884 #[serde(default = "default_current_ratio")]
3886 pub target_current_ratio: f64,
3887 #[serde(default = "default_debt_equity")]
3889 pub target_debt_to_equity: f64,
3890 #[serde(default = "default_true")]
3892 pub validate_balance_equation: bool,
3893 #[serde(default = "default_true")]
3895 pub reconcile_subledgers: bool,
3896}
3897
3898fn default_gross_margin() -> f64 {
3899 0.35
3900}
3901
3902fn default_dso() -> u32 {
3903 45
3904}
3905
3906fn default_dpo() -> u32 {
3907 30
3908}
3909
3910fn default_current_ratio() -> f64 {
3911 1.5
3912}
3913
3914fn default_debt_equity() -> f64 {
3915 0.5
3916}
3917
3918impl Default for BalanceConfig {
3919 fn default() -> Self {
3920 Self {
3921 generate_opening_balances: false,
3922 generate_trial_balances: true,
3923 target_gross_margin: default_gross_margin(),
3924 target_dso_days: default_dso(),
3925 target_dpo_days: default_dpo(),
3926 target_current_ratio: default_current_ratio(),
3927 target_debt_to_equity: default_debt_equity(),
3928 validate_balance_equation: true,
3929 reconcile_subledgers: true,
3930 }
3931 }
3932}
3933
3934#[derive(Debug, Clone, Serialize, Deserialize)]
3943pub struct OcpmConfig {
3944 #[serde(default)]
3946 pub enabled: bool,
3947
3948 #[serde(default = "default_true")]
3950 pub generate_lifecycle_events: bool,
3951
3952 #[serde(default = "default_true")]
3954 pub include_object_relationships: bool,
3955
3956 #[serde(default = "default_true")]
3958 pub compute_variants: bool,
3959
3960 #[serde(default)]
3962 pub max_variants: usize,
3963
3964 #[serde(default)]
3966 pub p2p_process: OcpmProcessConfig,
3967
3968 #[serde(default)]
3970 pub o2c_process: OcpmProcessConfig,
3971
3972 #[serde(default)]
3974 pub output: OcpmOutputConfig,
3975}
3976
3977impl Default for OcpmConfig {
3978 fn default() -> Self {
3979 Self {
3980 enabled: false,
3981 generate_lifecycle_events: true,
3982 include_object_relationships: true,
3983 compute_variants: true,
3984 max_variants: 0,
3985 p2p_process: OcpmProcessConfig::default(),
3986 o2c_process: OcpmProcessConfig::default(),
3987 output: OcpmOutputConfig::default(),
3988 }
3989 }
3990}
3991
3992#[derive(Debug, Clone, Serialize, Deserialize)]
3994pub struct OcpmProcessConfig {
3995 #[serde(default = "default_rework_probability")]
3997 pub rework_probability: f64,
3998
3999 #[serde(default = "default_skip_probability")]
4001 pub skip_step_probability: f64,
4002
4003 #[serde(default = "default_out_of_order_probability")]
4005 pub out_of_order_probability: f64,
4006}
4007
4008fn default_rework_probability() -> f64 {
4012 0.15
4013}
4014
4015fn default_skip_probability() -> f64 {
4016 0.10
4017}
4018
4019fn default_out_of_order_probability() -> f64 {
4020 0.08
4021}
4022
4023impl Default for OcpmProcessConfig {
4024 fn default() -> Self {
4025 Self {
4026 rework_probability: default_rework_probability(),
4027 skip_step_probability: default_skip_probability(),
4028 out_of_order_probability: default_out_of_order_probability(),
4029 }
4030 }
4031}
4032
4033#[derive(Debug, Clone, Serialize, Deserialize)]
4035pub struct OcpmOutputConfig {
4036 #[serde(default = "default_true")]
4038 pub ocel_json: bool,
4039
4040 #[serde(default)]
4042 pub ocel_xml: bool,
4043
4044 #[serde(default)]
4046 pub xes: bool,
4047
4048 #[serde(default = "default_true")]
4050 pub xes_include_lifecycle: bool,
4051
4052 #[serde(default = "default_true")]
4054 pub xes_include_resources: bool,
4055
4056 #[serde(default = "default_true")]
4058 pub flattened_csv: bool,
4059
4060 #[serde(default = "default_true")]
4062 pub event_object_csv: bool,
4063
4064 #[serde(default = "default_true")]
4066 pub object_relationship_csv: bool,
4067
4068 #[serde(default = "default_true")]
4070 pub variants_csv: bool,
4071
4072 #[serde(default)]
4074 pub export_reference_models: bool,
4075}
4076
4077impl Default for OcpmOutputConfig {
4078 fn default() -> Self {
4079 Self {
4080 ocel_json: true,
4081 ocel_xml: false,
4082 xes: false,
4083 xes_include_lifecycle: true,
4084 xes_include_resources: true,
4085 flattened_csv: true,
4086 event_object_csv: true,
4087 object_relationship_csv: true,
4088 variants_csv: true,
4089 export_reference_models: false,
4090 }
4091 }
4092}
4093
4094#[derive(Debug, Clone, Serialize, Deserialize)]
4096pub struct AuditGenerationConfig {
4097 #[serde(default)]
4099 pub enabled: bool,
4100
4101 #[serde(default = "default_true")]
4105 pub generate_workpapers: bool,
4106
4107 #[serde(default)]
4110 pub engagement_types: AuditEngagementTypesConfig,
4111
4112 #[serde(default)]
4117 pub workpapers: WorkpaperConfig,
4118
4119 #[serde(default)]
4125 pub team: AuditTeamConfig,
4126
4127 #[serde(default)]
4134 pub review: ReviewWorkflowConfig,
4135
4136 #[serde(default)]
4138 pub fsm: Option<AuditFsmConfig>,
4139
4140 #[serde(default)]
4146 pub it_controls: ItControlsConfig,
4147}
4148
4149#[derive(Debug, Clone, Serialize, Deserialize)]
4151pub struct ItControlsConfig {
4152 #[serde(default)]
4155 pub enabled: bool,
4156 #[serde(default = "default_access_log_count")]
4159 pub access_logs_per_engagement: usize,
4160 #[serde(default = "default_change_record_count")]
4162 pub change_records_per_engagement: usize,
4163}
4164
4165fn default_access_log_count() -> usize {
4166 500
4167}
4168fn default_change_record_count() -> usize {
4169 50
4170}
4171
4172impl Default for ItControlsConfig {
4173 fn default() -> Self {
4174 Self {
4175 enabled: false,
4176 access_logs_per_engagement: default_access_log_count(),
4177 change_records_per_engagement: default_change_record_count(),
4178 }
4179 }
4180}
4181
4182impl Default for AuditGenerationConfig {
4183 fn default() -> Self {
4184 Self {
4185 enabled: false,
4186 generate_workpapers: true,
4187 engagement_types: AuditEngagementTypesConfig::default(),
4188 workpapers: WorkpaperConfig::default(),
4189 team: AuditTeamConfig::default(),
4190 review: ReviewWorkflowConfig::default(),
4191 fsm: None,
4192 it_controls: ItControlsConfig::default(),
4193 }
4194 }
4195}
4196
4197#[derive(Debug, Clone, Serialize, Deserialize)]
4199pub struct AuditFsmConfig {
4200 #[serde(default)]
4202 pub enabled: bool,
4203
4204 #[serde(default = "default_audit_fsm_blueprint")]
4206 pub blueprint: String,
4207
4208 #[serde(default = "default_audit_fsm_overlay")]
4210 pub overlay: String,
4211
4212 #[serde(default)]
4214 pub depth: Option<String>,
4215
4216 #[serde(default)]
4218 pub discriminators: std::collections::HashMap<String, Vec<String>>,
4219
4220 #[serde(default)]
4222 pub event_trail: AuditEventTrailConfig,
4223
4224 #[serde(default)]
4226 pub seed: Option<u64>,
4227}
4228
4229impl Default for AuditFsmConfig {
4230 fn default() -> Self {
4231 Self {
4232 enabled: false,
4233 blueprint: default_audit_fsm_blueprint(),
4234 overlay: default_audit_fsm_overlay(),
4235 depth: None,
4236 discriminators: std::collections::HashMap::new(),
4237 event_trail: AuditEventTrailConfig::default(),
4238 seed: None,
4239 }
4240 }
4241}
4242
4243fn default_audit_fsm_blueprint() -> String {
4244 "builtin:fsa".to_string()
4245}
4246
4247fn default_audit_fsm_overlay() -> String {
4248 "builtin:default".to_string()
4249}
4250
4251#[derive(Debug, Clone, Serialize, Deserialize)]
4253pub struct AuditEventTrailConfig {
4254 #[serde(default = "default_true")]
4256 pub flat_log: bool,
4257 #[serde(default)]
4259 pub ocel_projection: bool,
4260}
4261
4262impl Default for AuditEventTrailConfig {
4263 fn default() -> Self {
4264 Self {
4265 flat_log: true,
4266 ocel_projection: false,
4267 }
4268 }
4269}
4270
4271#[derive(Debug, Clone, Serialize, Deserialize)]
4273pub struct AuditEngagementTypesConfig {
4274 #[serde(default = "default_financial_audit_prob")]
4276 pub financial_statement: f64,
4277 #[serde(default = "default_sox_audit_prob")]
4279 pub sox_icfr: f64,
4280 #[serde(default = "default_integrated_audit_prob")]
4282 pub integrated: f64,
4283 #[serde(default = "default_review_prob")]
4285 pub review: f64,
4286 #[serde(default = "default_aup_prob")]
4288 pub agreed_upon_procedures: f64,
4289}
4290
4291fn default_financial_audit_prob() -> f64 {
4292 0.40
4293}
4294fn default_sox_audit_prob() -> f64 {
4295 0.20
4296}
4297fn default_integrated_audit_prob() -> f64 {
4298 0.25
4299}
4300fn default_review_prob() -> f64 {
4301 0.10
4302}
4303fn default_aup_prob() -> f64 {
4304 0.05
4305}
4306
4307impl Default for AuditEngagementTypesConfig {
4308 fn default() -> Self {
4309 Self {
4310 financial_statement: default_financial_audit_prob(),
4311 sox_icfr: default_sox_audit_prob(),
4312 integrated: default_integrated_audit_prob(),
4313 review: default_review_prob(),
4314 agreed_upon_procedures: default_aup_prob(),
4315 }
4316 }
4317}
4318
4319#[derive(Debug, Clone, Serialize, Deserialize)]
4321pub struct WorkpaperConfig {
4322 #[serde(default = "default_workpapers_per_phase")]
4324 pub average_per_phase: usize,
4325
4326 #[serde(default = "default_true")]
4328 pub include_isa_references: bool,
4329
4330 #[serde(default = "default_true")]
4332 pub include_sample_details: bool,
4333
4334 #[serde(default = "default_true")]
4336 pub include_cross_references: bool,
4337
4338 #[serde(default)]
4340 pub sampling: SamplingConfig,
4341}
4342
4343fn default_workpapers_per_phase() -> usize {
4344 5
4345}
4346
4347impl Default for WorkpaperConfig {
4348 fn default() -> Self {
4349 Self {
4350 average_per_phase: default_workpapers_per_phase(),
4351 include_isa_references: true,
4352 include_sample_details: true,
4353 include_cross_references: true,
4354 sampling: SamplingConfig::default(),
4355 }
4356 }
4357}
4358
4359#[derive(Debug, Clone, Serialize, Deserialize)]
4361pub struct SamplingConfig {
4362 #[serde(default = "default_statistical_rate")]
4364 pub statistical_rate: f64,
4365 #[serde(default = "default_judgmental_rate")]
4367 pub judgmental_rate: f64,
4368 #[serde(default = "default_haphazard_rate")]
4370 pub haphazard_rate: f64,
4371 #[serde(default = "default_complete_examination_rate")]
4373 pub complete_examination_rate: f64,
4374}
4375
4376fn default_statistical_rate() -> f64 {
4377 0.40
4378}
4379fn default_judgmental_rate() -> f64 {
4380 0.30
4381}
4382fn default_haphazard_rate() -> f64 {
4383 0.20
4384}
4385fn default_complete_examination_rate() -> f64 {
4386 0.10
4387}
4388
4389impl Default for SamplingConfig {
4390 fn default() -> Self {
4391 Self {
4392 statistical_rate: default_statistical_rate(),
4393 judgmental_rate: default_judgmental_rate(),
4394 haphazard_rate: default_haphazard_rate(),
4395 complete_examination_rate: default_complete_examination_rate(),
4396 }
4397 }
4398}
4399
4400#[derive(Debug, Clone, Serialize, Deserialize)]
4402pub struct AuditTeamConfig {
4403 #[serde(default = "default_min_team_size")]
4405 pub min_team_size: usize,
4406 #[serde(default = "default_max_team_size")]
4408 pub max_team_size: usize,
4409 #[serde(default = "default_specialist_probability")]
4411 pub specialist_probability: f64,
4412}
4413
4414fn default_min_team_size() -> usize {
4415 3
4416}
4417fn default_max_team_size() -> usize {
4418 8
4419}
4420fn default_specialist_probability() -> f64 {
4421 0.30
4422}
4423
4424impl Default for AuditTeamConfig {
4425 fn default() -> Self {
4426 Self {
4427 min_team_size: default_min_team_size(),
4428 max_team_size: default_max_team_size(),
4429 specialist_probability: default_specialist_probability(),
4430 }
4431 }
4432}
4433
4434#[derive(Debug, Clone, Serialize, Deserialize)]
4436pub struct ReviewWorkflowConfig {
4437 #[serde(default = "default_review_delay_days")]
4439 pub average_review_delay_days: u32,
4440 #[serde(default = "default_rework_probability_review")]
4442 pub rework_probability: f64,
4443 #[serde(default = "default_true")]
4445 pub require_partner_signoff: bool,
4446}
4447
4448fn default_review_delay_days() -> u32 {
4449 2
4450}
4451fn default_rework_probability_review() -> f64 {
4452 0.15
4453}
4454
4455impl Default for ReviewWorkflowConfig {
4456 fn default() -> Self {
4457 Self {
4458 average_review_delay_days: default_review_delay_days(),
4459 rework_probability: default_rework_probability_review(),
4460 require_partner_signoff: true,
4461 }
4462 }
4463}
4464
4465#[derive(Debug, Clone, Serialize, Deserialize)]
4471pub struct DataQualitySchemaConfig {
4472 #[serde(default)]
4474 pub enabled: bool,
4475 #[serde(default)]
4477 pub preset: DataQualityPreset,
4478 #[serde(default)]
4480 pub missing_values: MissingValuesSchemaConfig,
4481 #[serde(default)]
4483 pub typos: TypoSchemaConfig,
4484 #[serde(default)]
4486 pub format_variations: FormatVariationSchemaConfig,
4487 #[serde(default)]
4489 pub duplicates: DuplicateSchemaConfig,
4490 #[serde(default)]
4492 pub encoding_issues: EncodingIssueSchemaConfig,
4493 #[serde(default)]
4495 pub generate_labels: bool,
4496 #[serde(default)]
4498 pub sink_profiles: SinkQualityProfiles,
4499}
4500
4501impl Default for DataQualitySchemaConfig {
4502 fn default() -> Self {
4503 Self {
4504 enabled: false,
4505 preset: DataQualityPreset::None,
4506 missing_values: MissingValuesSchemaConfig::default(),
4507 typos: TypoSchemaConfig::default(),
4508 format_variations: FormatVariationSchemaConfig::default(),
4509 duplicates: DuplicateSchemaConfig::default(),
4510 encoding_issues: EncodingIssueSchemaConfig::default(),
4511 generate_labels: true,
4512 sink_profiles: SinkQualityProfiles::default(),
4513 }
4514 }
4515}
4516
4517impl DataQualitySchemaConfig {
4518 pub fn with_preset(preset: DataQualityPreset) -> Self {
4520 let mut config = Self {
4521 preset,
4522 ..Default::default()
4523 };
4524 config.apply_preset();
4525 config
4526 }
4527
4528 pub fn apply_preset(&mut self) {
4531 if !self.preset.overrides_settings() {
4532 return;
4533 }
4534
4535 self.enabled = true;
4536
4537 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4539 self.missing_values.rate = self.preset.missing_rate();
4540
4541 self.typos.enabled = self.preset.typo_rate() > 0.0;
4543 self.typos.char_error_rate = self.preset.typo_rate();
4544
4545 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4547 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4548 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4549 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4550
4551 self.format_variations.enabled = self.preset.format_variations_enabled();
4553
4554 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4556 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4557
4558 if self.preset.ocr_errors_enabled() {
4560 self.typos.type_weights.ocr_errors = 0.3;
4561 }
4562 }
4563
4564 pub fn effective_missing_rate(&self) -> f64 {
4566 if self.preset.overrides_settings() {
4567 self.preset.missing_rate()
4568 } else {
4569 self.missing_values.rate
4570 }
4571 }
4572
4573 pub fn effective_typo_rate(&self) -> f64 {
4575 if self.preset.overrides_settings() {
4576 self.preset.typo_rate()
4577 } else {
4578 self.typos.char_error_rate
4579 }
4580 }
4581
4582 pub fn effective_duplicate_rate(&self) -> f64 {
4584 if self.preset.overrides_settings() {
4585 self.preset.duplicate_rate()
4586 } else {
4587 self.duplicates.exact_duplicate_ratio
4588 + self.duplicates.near_duplicate_ratio
4589 + self.duplicates.fuzzy_duplicate_ratio
4590 }
4591 }
4592
4593 pub fn clean() -> Self {
4595 Self::with_preset(DataQualityPreset::Clean)
4596 }
4597
4598 pub fn noisy() -> Self {
4600 Self::with_preset(DataQualityPreset::Noisy)
4601 }
4602
4603 pub fn legacy() -> Self {
4605 Self::with_preset(DataQualityPreset::Legacy)
4606 }
4607}
4608
4609#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4611#[serde(rename_all = "snake_case")]
4612pub enum DataQualityPreset {
4613 #[default]
4615 None,
4616 Minimal,
4618 Normal,
4620 High,
4622 Custom,
4624
4625 Clean,
4631 Noisy,
4634 Legacy,
4637}
4638
4639impl DataQualityPreset {
4640 pub fn missing_rate(&self) -> f64 {
4642 match self {
4643 DataQualityPreset::None => 0.0,
4644 DataQualityPreset::Minimal => 0.005,
4645 DataQualityPreset::Normal => 0.02,
4646 DataQualityPreset::High => 0.08,
4647 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4649 DataQualityPreset::Noisy => 0.05,
4650 DataQualityPreset::Legacy => 0.10,
4651 }
4652 }
4653
4654 pub fn typo_rate(&self) -> f64 {
4656 match self {
4657 DataQualityPreset::None => 0.0,
4658 DataQualityPreset::Minimal => 0.0005,
4659 DataQualityPreset::Normal => 0.002,
4660 DataQualityPreset::High => 0.01,
4661 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4663 DataQualityPreset::Noisy => 0.02,
4664 DataQualityPreset::Legacy => 0.05,
4665 }
4666 }
4667
4668 pub fn duplicate_rate(&self) -> f64 {
4670 match self {
4671 DataQualityPreset::None => 0.0,
4672 DataQualityPreset::Minimal => 0.001,
4673 DataQualityPreset::Normal => 0.005,
4674 DataQualityPreset::High => 0.02,
4675 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4677 DataQualityPreset::Noisy => 0.01,
4678 DataQualityPreset::Legacy => 0.03,
4679 }
4680 }
4681
4682 pub fn format_variations_enabled(&self) -> bool {
4684 match self {
4685 DataQualityPreset::None | DataQualityPreset::Clean => false,
4686 DataQualityPreset::Minimal => true,
4687 DataQualityPreset::Normal => true,
4688 DataQualityPreset::High => true,
4689 DataQualityPreset::Custom => true,
4690 DataQualityPreset::Noisy => true,
4691 DataQualityPreset::Legacy => true,
4692 }
4693 }
4694
4695 pub fn ocr_errors_enabled(&self) -> bool {
4697 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4698 }
4699
4700 pub fn encoding_issues_enabled(&self) -> bool {
4702 matches!(
4703 self,
4704 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4705 )
4706 }
4707
4708 pub fn encoding_issue_rate(&self) -> f64 {
4710 match self {
4711 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4712 DataQualityPreset::Normal => 0.002,
4713 DataQualityPreset::High => 0.01,
4714 DataQualityPreset::Custom => 0.0,
4715 DataQualityPreset::Noisy => 0.005,
4716 DataQualityPreset::Legacy => 0.02,
4717 }
4718 }
4719
4720 pub fn overrides_settings(&self) -> bool {
4722 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4723 }
4724
4725 pub fn description(&self) -> &'static str {
4727 match self {
4728 DataQualityPreset::None => "No data quality issues (pristine data)",
4729 DataQualityPreset::Minimal => "Very rare data quality issues",
4730 DataQualityPreset::Normal => "Realistic enterprise data quality",
4731 DataQualityPreset::High => "Messy data for stress testing",
4732 DataQualityPreset::Custom => "Custom settings from configuration",
4733 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4734 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4735 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4736 }
4737 }
4738}
4739
4740#[derive(Debug, Clone, Serialize, Deserialize)]
4742pub struct MissingValuesSchemaConfig {
4743 #[serde(default)]
4745 pub enabled: bool,
4746 #[serde(default = "default_missing_rate")]
4748 pub rate: f64,
4749 #[serde(default)]
4751 pub strategy: MissingValueStrategy,
4752 #[serde(default)]
4754 pub field_rates: std::collections::HashMap<String, f64>,
4755 #[serde(default)]
4757 pub protected_fields: Vec<String>,
4758}
4759
4760fn default_missing_rate() -> f64 {
4761 0.01
4762}
4763
4764impl Default for MissingValuesSchemaConfig {
4765 fn default() -> Self {
4766 Self {
4767 enabled: false,
4768 rate: default_missing_rate(),
4769 strategy: MissingValueStrategy::Mcar,
4770 field_rates: std::collections::HashMap::new(),
4771 protected_fields: vec![
4772 "document_id".to_string(),
4773 "company_code".to_string(),
4774 "posting_date".to_string(),
4775 ],
4776 }
4777 }
4778}
4779
4780#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4782#[serde(rename_all = "snake_case")]
4783pub enum MissingValueStrategy {
4784 #[default]
4786 Mcar,
4787 Mar,
4789 Mnar,
4791 Systematic,
4793}
4794
4795#[derive(Debug, Clone, Serialize, Deserialize)]
4797pub struct TypoSchemaConfig {
4798 #[serde(default)]
4800 pub enabled: bool,
4801 #[serde(default = "default_typo_rate")]
4803 pub char_error_rate: f64,
4804 #[serde(default)]
4806 pub type_weights: TypoTypeWeights,
4807 #[serde(default)]
4809 pub protected_fields: Vec<String>,
4810}
4811
4812fn default_typo_rate() -> f64 {
4813 0.001
4814}
4815
4816impl Default for TypoSchemaConfig {
4817 fn default() -> Self {
4818 Self {
4819 enabled: false,
4820 char_error_rate: default_typo_rate(),
4821 type_weights: TypoTypeWeights::default(),
4822 protected_fields: vec![
4823 "document_id".to_string(),
4824 "gl_account".to_string(),
4825 "company_code".to_string(),
4826 ],
4827 }
4828 }
4829}
4830
4831#[derive(Debug, Clone, Serialize, Deserialize)]
4833pub struct TypoTypeWeights {
4834 #[serde(default = "default_substitution_weight")]
4836 pub substitution: f64,
4837 #[serde(default = "default_transposition_weight")]
4839 pub transposition: f64,
4840 #[serde(default = "default_insertion_weight")]
4842 pub insertion: f64,
4843 #[serde(default = "default_deletion_weight")]
4845 pub deletion: f64,
4846 #[serde(default = "default_ocr_weight")]
4848 pub ocr_errors: f64,
4849 #[serde(default = "default_homophone_weight")]
4851 pub homophones: f64,
4852}
4853
4854fn default_substitution_weight() -> f64 {
4855 0.35
4856}
4857fn default_transposition_weight() -> f64 {
4858 0.25
4859}
4860fn default_insertion_weight() -> f64 {
4861 0.10
4862}
4863fn default_deletion_weight() -> f64 {
4864 0.15
4865}
4866fn default_ocr_weight() -> f64 {
4867 0.10
4868}
4869fn default_homophone_weight() -> f64 {
4870 0.05
4871}
4872
4873impl Default for TypoTypeWeights {
4874 fn default() -> Self {
4875 Self {
4876 substitution: default_substitution_weight(),
4877 transposition: default_transposition_weight(),
4878 insertion: default_insertion_weight(),
4879 deletion: default_deletion_weight(),
4880 ocr_errors: default_ocr_weight(),
4881 homophones: default_homophone_weight(),
4882 }
4883 }
4884}
4885
4886#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4888pub struct FormatVariationSchemaConfig {
4889 #[serde(default)]
4891 pub enabled: bool,
4892 #[serde(default)]
4894 pub dates: DateFormatVariationConfig,
4895 #[serde(default)]
4897 pub amounts: AmountFormatVariationConfig,
4898 #[serde(default)]
4900 pub identifiers: IdentifierFormatVariationConfig,
4901}
4902
4903#[derive(Debug, Clone, Serialize, Deserialize)]
4905pub struct DateFormatVariationConfig {
4906 #[serde(default)]
4908 pub enabled: bool,
4909 #[serde(default = "default_date_variation_rate")]
4911 pub rate: f64,
4912 #[serde(default = "default_true")]
4914 pub iso_format: bool,
4915 #[serde(default)]
4917 pub us_format: bool,
4918 #[serde(default)]
4920 pub eu_format: bool,
4921 #[serde(default)]
4923 pub long_format: bool,
4924}
4925
4926fn default_date_variation_rate() -> f64 {
4927 0.05
4928}
4929
4930impl Default for DateFormatVariationConfig {
4931 fn default() -> Self {
4932 Self {
4933 enabled: false,
4934 rate: default_date_variation_rate(),
4935 iso_format: true,
4936 us_format: false,
4937 eu_format: false,
4938 long_format: false,
4939 }
4940 }
4941}
4942
4943#[derive(Debug, Clone, Serialize, Deserialize)]
4945pub struct AmountFormatVariationConfig {
4946 #[serde(default)]
4948 pub enabled: bool,
4949 #[serde(default = "default_amount_variation_rate")]
4951 pub rate: f64,
4952 #[serde(default)]
4954 pub us_comma_format: bool,
4955 #[serde(default)]
4957 pub eu_format: bool,
4958 #[serde(default)]
4960 pub currency_prefix: bool,
4961 #[serde(default)]
4963 pub accounting_format: bool,
4964}
4965
4966fn default_amount_variation_rate() -> f64 {
4967 0.02
4968}
4969
4970impl Default for AmountFormatVariationConfig {
4971 fn default() -> Self {
4972 Self {
4973 enabled: false,
4974 rate: default_amount_variation_rate(),
4975 us_comma_format: false,
4976 eu_format: false,
4977 currency_prefix: false,
4978 accounting_format: false,
4979 }
4980 }
4981}
4982
4983#[derive(Debug, Clone, Serialize, Deserialize)]
4985pub struct IdentifierFormatVariationConfig {
4986 #[serde(default)]
4988 pub enabled: bool,
4989 #[serde(default = "default_identifier_variation_rate")]
4991 pub rate: f64,
4992 #[serde(default)]
4994 pub case_variations: bool,
4995 #[serde(default)]
4997 pub padding_variations: bool,
4998 #[serde(default)]
5000 pub separator_variations: bool,
5001}
5002
5003fn default_identifier_variation_rate() -> f64 {
5004 0.02
5005}
5006
5007impl Default for IdentifierFormatVariationConfig {
5008 fn default() -> Self {
5009 Self {
5010 enabled: false,
5011 rate: default_identifier_variation_rate(),
5012 case_variations: false,
5013 padding_variations: false,
5014 separator_variations: false,
5015 }
5016 }
5017}
5018
5019#[derive(Debug, Clone, Serialize, Deserialize)]
5021pub struct DuplicateSchemaConfig {
5022 #[serde(default)]
5024 pub enabled: bool,
5025 #[serde(default = "default_duplicate_rate")]
5027 pub rate: f64,
5028 #[serde(default = "default_exact_duplicate_ratio")]
5030 pub exact_duplicate_ratio: f64,
5031 #[serde(default = "default_near_duplicate_ratio")]
5033 pub near_duplicate_ratio: f64,
5034 #[serde(default = "default_fuzzy_duplicate_ratio")]
5036 pub fuzzy_duplicate_ratio: f64,
5037 #[serde(default = "default_max_date_offset")]
5039 pub max_date_offset_days: u32,
5040 #[serde(default = "default_max_amount_variance")]
5042 pub max_amount_variance: f64,
5043}
5044
5045fn default_duplicate_rate() -> f64 {
5046 0.005
5047}
5048fn default_exact_duplicate_ratio() -> f64 {
5049 0.4
5050}
5051fn default_near_duplicate_ratio() -> f64 {
5052 0.35
5053}
5054fn default_fuzzy_duplicate_ratio() -> f64 {
5055 0.25
5056}
5057fn default_max_date_offset() -> u32 {
5058 3
5059}
5060fn default_max_amount_variance() -> f64 {
5061 0.01
5062}
5063
5064impl Default for DuplicateSchemaConfig {
5065 fn default() -> Self {
5066 Self {
5067 enabled: false,
5068 rate: default_duplicate_rate(),
5069 exact_duplicate_ratio: default_exact_duplicate_ratio(),
5070 near_duplicate_ratio: default_near_duplicate_ratio(),
5071 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
5072 max_date_offset_days: default_max_date_offset(),
5073 max_amount_variance: default_max_amount_variance(),
5074 }
5075 }
5076}
5077
5078#[derive(Debug, Clone, Serialize, Deserialize)]
5080pub struct EncodingIssueSchemaConfig {
5081 #[serde(default)]
5083 pub enabled: bool,
5084 #[serde(default = "default_encoding_rate")]
5086 pub rate: f64,
5087 #[serde(default)]
5089 pub mojibake: bool,
5090 #[serde(default)]
5092 pub html_entities: bool,
5093 #[serde(default)]
5095 pub bom_issues: bool,
5096}
5097
5098fn default_encoding_rate() -> f64 {
5099 0.001
5100}
5101
5102impl Default for EncodingIssueSchemaConfig {
5103 fn default() -> Self {
5104 Self {
5105 enabled: false,
5106 rate: default_encoding_rate(),
5107 mojibake: false,
5108 html_entities: false,
5109 bom_issues: false,
5110 }
5111 }
5112}
5113
5114#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5116pub struct SinkQualityProfiles {
5117 #[serde(default)]
5119 pub csv: Option<SinkQualityOverride>,
5120 #[serde(default)]
5122 pub json: Option<SinkQualityOverride>,
5123 #[serde(default)]
5125 pub parquet: Option<SinkQualityOverride>,
5126}
5127
5128#[derive(Debug, Clone, Serialize, Deserialize)]
5130pub struct SinkQualityOverride {
5131 pub enabled: Option<bool>,
5133 pub missing_rate: Option<f64>,
5135 pub typo_rate: Option<f64>,
5137 pub format_variation_rate: Option<f64>,
5139 pub duplicate_rate: Option<f64>,
5141}
5142
5143#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5155pub struct AccountingStandardsConfig {
5156 #[serde(default)]
5158 pub enabled: bool,
5159
5160 #[serde(default, skip_serializing_if = "Option::is_none")]
5164 pub framework: Option<AccountingFrameworkConfig>,
5165
5166 #[serde(default)]
5168 pub revenue_recognition: RevenueRecognitionConfig,
5169
5170 #[serde(default)]
5172 pub leases: LeaseAccountingConfig,
5173
5174 #[serde(default)]
5176 pub fair_value: FairValueConfig,
5177
5178 #[serde(default)]
5180 pub impairment: ImpairmentConfig,
5181
5182 #[serde(default)]
5184 pub business_combinations: BusinessCombinationsConfig,
5185
5186 #[serde(default)]
5188 pub expected_credit_loss: EclConfig,
5189
5190 #[serde(default)]
5192 pub generate_differences: bool,
5193}
5194
5195#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5197#[serde(rename_all = "snake_case")]
5198pub enum AccountingFrameworkConfig {
5199 #[default]
5201 UsGaap,
5202 Ifrs,
5204 DualReporting,
5206 FrenchGaap,
5208 GermanGaap,
5210}
5211
5212#[derive(Debug, Clone, Serialize, Deserialize)]
5214pub struct RevenueRecognitionConfig {
5215 #[serde(default)]
5217 pub enabled: bool,
5218
5219 #[serde(default = "default_true")]
5221 pub generate_contracts: bool,
5222
5223 #[serde(default = "default_avg_obligations")]
5225 pub avg_obligations_per_contract: f64,
5226
5227 #[serde(default = "default_variable_consideration_rate")]
5229 pub variable_consideration_rate: f64,
5230
5231 #[serde(default = "default_over_time_rate")]
5233 pub over_time_recognition_rate: f64,
5234
5235 #[serde(default = "default_contract_count")]
5237 pub contract_count: usize,
5238}
5239
5240fn default_avg_obligations() -> f64 {
5241 2.0
5242}
5243
5244fn default_variable_consideration_rate() -> f64 {
5245 0.15
5246}
5247
5248fn default_over_time_rate() -> f64 {
5249 0.30
5250}
5251
5252fn default_contract_count() -> usize {
5253 100
5254}
5255
5256impl Default for RevenueRecognitionConfig {
5257 fn default() -> Self {
5258 Self {
5259 enabled: false,
5260 generate_contracts: true,
5261 avg_obligations_per_contract: default_avg_obligations(),
5262 variable_consideration_rate: default_variable_consideration_rate(),
5263 over_time_recognition_rate: default_over_time_rate(),
5264 contract_count: default_contract_count(),
5265 }
5266 }
5267}
5268
5269#[derive(Debug, Clone, Serialize, Deserialize)]
5271pub struct LeaseAccountingConfig {
5272 #[serde(default)]
5274 pub enabled: bool,
5275
5276 #[serde(default = "default_lease_count")]
5278 pub lease_count: usize,
5279
5280 #[serde(default = "default_finance_lease_pct")]
5282 pub finance_lease_percent: f64,
5283
5284 #[serde(default = "default_avg_lease_term")]
5286 pub avg_lease_term_months: u32,
5287
5288 #[serde(default = "default_true")]
5290 pub generate_amortization: bool,
5291
5292 #[serde(default = "default_real_estate_pct")]
5294 pub real_estate_percent: f64,
5295}
5296
5297fn default_lease_count() -> usize {
5298 50
5299}
5300
5301fn default_finance_lease_pct() -> f64 {
5302 0.30
5303}
5304
5305fn default_avg_lease_term() -> u32 {
5306 60
5307}
5308
5309fn default_real_estate_pct() -> f64 {
5310 0.40
5311}
5312
5313impl Default for LeaseAccountingConfig {
5314 fn default() -> Self {
5315 Self {
5316 enabled: false,
5317 lease_count: default_lease_count(),
5318 finance_lease_percent: default_finance_lease_pct(),
5319 avg_lease_term_months: default_avg_lease_term(),
5320 generate_amortization: true,
5321 real_estate_percent: default_real_estate_pct(),
5322 }
5323 }
5324}
5325
5326#[derive(Debug, Clone, Serialize, Deserialize)]
5328pub struct FairValueConfig {
5329 #[serde(default)]
5331 pub enabled: bool,
5332
5333 #[serde(default = "default_fv_count")]
5335 pub measurement_count: usize,
5336
5337 #[serde(default = "default_level1_pct")]
5339 pub level1_percent: f64,
5340
5341 #[serde(default = "default_level2_pct")]
5343 pub level2_percent: f64,
5344
5345 #[serde(default = "default_level3_pct")]
5347 pub level3_percent: f64,
5348
5349 #[serde(default)]
5351 pub include_sensitivity_analysis: bool,
5352}
5353
5354fn default_fv_count() -> usize {
5355 25
5356}
5357
5358fn default_level1_pct() -> f64 {
5359 0.40
5360}
5361
5362fn default_level2_pct() -> f64 {
5363 0.35
5364}
5365
5366fn default_level3_pct() -> f64 {
5367 0.25
5368}
5369
5370impl Default for FairValueConfig {
5371 fn default() -> Self {
5372 Self {
5373 enabled: false,
5374 measurement_count: default_fv_count(),
5375 level1_percent: default_level1_pct(),
5376 level2_percent: default_level2_pct(),
5377 level3_percent: default_level3_pct(),
5378 include_sensitivity_analysis: false,
5379 }
5380 }
5381}
5382
5383#[derive(Debug, Clone, Serialize, Deserialize)]
5385pub struct ImpairmentConfig {
5386 #[serde(default)]
5388 pub enabled: bool,
5389
5390 #[serde(default = "default_impairment_count")]
5392 pub test_count: usize,
5393
5394 #[serde(default = "default_impairment_rate")]
5396 pub impairment_rate: f64,
5397
5398 #[serde(default = "default_true")]
5400 pub generate_projections: bool,
5401
5402 #[serde(default)]
5404 pub include_goodwill: bool,
5405}
5406
5407fn default_impairment_count() -> usize {
5408 15
5409}
5410
5411fn default_impairment_rate() -> f64 {
5412 0.10
5413}
5414
5415impl Default for ImpairmentConfig {
5416 fn default() -> Self {
5417 Self {
5418 enabled: false,
5419 test_count: default_impairment_count(),
5420 impairment_rate: default_impairment_rate(),
5421 generate_projections: true,
5422 include_goodwill: false,
5423 }
5424 }
5425}
5426
5427#[derive(Debug, Clone, Serialize, Deserialize)]
5433pub struct BusinessCombinationsConfig {
5434 #[serde(default)]
5436 pub enabled: bool,
5437
5438 #[serde(default = "default_bc_acquisition_count")]
5440 pub acquisition_count: usize,
5441}
5442
5443fn default_bc_acquisition_count() -> usize {
5444 2
5445}
5446
5447impl Default for BusinessCombinationsConfig {
5448 fn default() -> Self {
5449 Self {
5450 enabled: false,
5451 acquisition_count: default_bc_acquisition_count(),
5452 }
5453 }
5454}
5455
5456#[derive(Debug, Clone, Serialize, Deserialize)]
5462pub struct EclConfig {
5463 #[serde(default)]
5465 pub enabled: bool,
5466
5467 #[serde(default = "default_ecl_base_weight")]
5469 pub base_scenario_weight: f64,
5470
5471 #[serde(default = "default_ecl_base_multiplier")]
5473 pub base_scenario_multiplier: f64,
5474
5475 #[serde(default = "default_ecl_optimistic_weight")]
5477 pub optimistic_scenario_weight: f64,
5478
5479 #[serde(default = "default_ecl_optimistic_multiplier")]
5481 pub optimistic_scenario_multiplier: f64,
5482
5483 #[serde(default = "default_ecl_pessimistic_weight")]
5485 pub pessimistic_scenario_weight: f64,
5486
5487 #[serde(default = "default_ecl_pessimistic_multiplier")]
5489 pub pessimistic_scenario_multiplier: f64,
5490}
5491
5492fn default_ecl_base_weight() -> f64 {
5493 0.50
5494}
5495fn default_ecl_base_multiplier() -> f64 {
5496 1.0
5497}
5498fn default_ecl_optimistic_weight() -> f64 {
5499 0.30
5500}
5501fn default_ecl_optimistic_multiplier() -> f64 {
5502 0.8
5503}
5504fn default_ecl_pessimistic_weight() -> f64 {
5505 0.20
5506}
5507fn default_ecl_pessimistic_multiplier() -> f64 {
5508 1.4
5509}
5510
5511impl Default for EclConfig {
5512 fn default() -> Self {
5513 Self {
5514 enabled: false,
5515 base_scenario_weight: default_ecl_base_weight(),
5516 base_scenario_multiplier: default_ecl_base_multiplier(),
5517 optimistic_scenario_weight: default_ecl_optimistic_weight(),
5518 optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5519 pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5520 pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5521 }
5522 }
5523}
5524
5525#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5538pub struct AuditStandardsConfig {
5539 #[serde(default)]
5541 pub enabled: bool,
5542
5543 #[serde(default)]
5545 pub isa_compliance: IsaComplianceConfig,
5546
5547 #[serde(default)]
5549 pub analytical_procedures: AnalyticalProceduresConfig,
5550
5551 #[serde(default)]
5553 pub confirmations: ConfirmationsConfig,
5554
5555 #[serde(default)]
5557 pub opinion: AuditOpinionConfig,
5558
5559 #[serde(default)]
5561 pub generate_audit_trail: bool,
5562
5563 #[serde(default)]
5565 pub sox: SoxComplianceConfig,
5566
5567 #[serde(default)]
5569 pub pcaob: PcaobConfig,
5570}
5571
5572#[derive(Debug, Clone, Serialize, Deserialize)]
5574pub struct IsaComplianceConfig {
5575 #[serde(default)]
5577 pub enabled: bool,
5578
5579 #[serde(default = "default_compliance_level")]
5581 pub compliance_level: String,
5582
5583 #[serde(default = "default_true")]
5585 pub generate_isa_mappings: bool,
5586
5587 #[serde(default = "default_true")]
5589 pub generate_coverage_summary: bool,
5590
5591 #[serde(default)]
5593 pub include_pcaob: bool,
5594
5595 #[serde(default = "default_audit_framework")]
5597 pub framework: String,
5598}
5599
5600fn default_compliance_level() -> String {
5601 "standard".to_string()
5602}
5603
5604fn default_audit_framework() -> String {
5605 "isa".to_string()
5606}
5607
5608impl Default for IsaComplianceConfig {
5609 fn default() -> Self {
5610 Self {
5611 enabled: false,
5612 compliance_level: default_compliance_level(),
5613 generate_isa_mappings: true,
5614 generate_coverage_summary: true,
5615 include_pcaob: false,
5616 framework: default_audit_framework(),
5617 }
5618 }
5619}
5620
5621#[derive(Debug, Clone, Serialize, Deserialize)]
5623pub struct AnalyticalProceduresConfig {
5624 #[serde(default)]
5626 pub enabled: bool,
5627
5628 #[serde(default = "default_procedures_per_account")]
5630 pub procedures_per_account: usize,
5631
5632 #[serde(default = "default_variance_probability")]
5634 pub variance_probability: f64,
5635
5636 #[serde(default = "default_true")]
5638 pub generate_investigations: bool,
5639
5640 #[serde(default = "default_true")]
5642 pub include_ratio_analysis: bool,
5643}
5644
5645fn default_procedures_per_account() -> usize {
5646 3
5647}
5648
5649fn default_variance_probability() -> f64 {
5650 0.20
5651}
5652
5653impl Default for AnalyticalProceduresConfig {
5654 fn default() -> Self {
5655 Self {
5656 enabled: false,
5657 procedures_per_account: default_procedures_per_account(),
5658 variance_probability: default_variance_probability(),
5659 generate_investigations: true,
5660 include_ratio_analysis: true,
5661 }
5662 }
5663}
5664
5665#[derive(Debug, Clone, Serialize, Deserialize)]
5667pub struct ConfirmationsConfig {
5668 #[serde(default)]
5670 pub enabled: bool,
5671
5672 #[serde(default = "default_confirmation_count")]
5674 pub confirmation_count: usize,
5675
5676 #[serde(default = "default_positive_response_rate")]
5678 pub positive_response_rate: f64,
5679
5680 #[serde(default = "default_exception_rate_confirm")]
5682 pub exception_rate: f64,
5683
5684 #[serde(default = "default_non_response_rate")]
5686 pub non_response_rate: f64,
5687
5688 #[serde(default = "default_true")]
5690 pub generate_alternative_procedures: bool,
5691}
5692
5693fn default_confirmation_count() -> usize {
5694 50
5695}
5696
5697fn default_positive_response_rate() -> f64 {
5698 0.85
5699}
5700
5701fn default_exception_rate_confirm() -> f64 {
5702 0.10
5703}
5704
5705fn default_non_response_rate() -> f64 {
5706 0.05
5707}
5708
5709impl Default for ConfirmationsConfig {
5710 fn default() -> Self {
5711 Self {
5712 enabled: false,
5713 confirmation_count: default_confirmation_count(),
5714 positive_response_rate: default_positive_response_rate(),
5715 exception_rate: default_exception_rate_confirm(),
5716 non_response_rate: default_non_response_rate(),
5717 generate_alternative_procedures: true,
5718 }
5719 }
5720}
5721
5722#[derive(Debug, Clone, Serialize, Deserialize)]
5724pub struct AuditOpinionConfig {
5725 #[serde(default)]
5727 pub enabled: bool,
5728
5729 #[serde(default = "default_true")]
5731 pub generate_kam: bool,
5732
5733 #[serde(default = "default_kam_count")]
5735 pub average_kam_count: usize,
5736
5737 #[serde(default = "default_modified_opinion_rate")]
5739 pub modified_opinion_rate: f64,
5740
5741 #[serde(default)]
5743 pub include_emphasis_of_matter: bool,
5744
5745 #[serde(default = "default_true")]
5747 pub include_going_concern: bool,
5748}
5749
5750fn default_kam_count() -> usize {
5751 3
5752}
5753
5754fn default_modified_opinion_rate() -> f64 {
5755 0.05
5756}
5757
5758impl Default for AuditOpinionConfig {
5759 fn default() -> Self {
5760 Self {
5761 enabled: false,
5762 generate_kam: true,
5763 average_kam_count: default_kam_count(),
5764 modified_opinion_rate: default_modified_opinion_rate(),
5765 include_emphasis_of_matter: false,
5766 include_going_concern: true,
5767 }
5768 }
5769}
5770
5771#[derive(Debug, Clone, Serialize, Deserialize)]
5773pub struct SoxComplianceConfig {
5774 #[serde(default)]
5776 pub enabled: bool,
5777
5778 #[serde(default = "default_true")]
5780 pub generate_302_certifications: bool,
5781
5782 #[serde(default = "default_true")]
5784 pub generate_404_assessments: bool,
5785
5786 #[serde(default = "default_sox_materiality_threshold")]
5788 pub materiality_threshold: f64,
5789
5790 #[serde(default = "default_material_weakness_rate")]
5792 pub material_weakness_rate: f64,
5793
5794 #[serde(default = "default_significant_deficiency_rate")]
5796 pub significant_deficiency_rate: f64,
5797}
5798
5799fn default_material_weakness_rate() -> f64 {
5800 0.02
5801}
5802
5803fn default_significant_deficiency_rate() -> f64 {
5804 0.08
5805}
5806
5807impl Default for SoxComplianceConfig {
5808 fn default() -> Self {
5809 Self {
5810 enabled: false,
5811 generate_302_certifications: true,
5812 generate_404_assessments: true,
5813 materiality_threshold: default_sox_materiality_threshold(),
5814 material_weakness_rate: default_material_weakness_rate(),
5815 significant_deficiency_rate: default_significant_deficiency_rate(),
5816 }
5817 }
5818}
5819
5820#[derive(Debug, Clone, Serialize, Deserialize)]
5822pub struct PcaobConfig {
5823 #[serde(default)]
5825 pub enabled: bool,
5826
5827 #[serde(default)]
5829 pub is_pcaob_audit: bool,
5830
5831 #[serde(default = "default_true")]
5833 pub generate_cam: bool,
5834
5835 #[serde(default)]
5837 pub include_icfr_opinion: bool,
5838
5839 #[serde(default)]
5841 pub generate_standard_mappings: bool,
5842}
5843
5844impl Default for PcaobConfig {
5845 fn default() -> Self {
5846 Self {
5847 enabled: false,
5848 is_pcaob_audit: false,
5849 generate_cam: true,
5850 include_icfr_opinion: false,
5851 generate_standard_mappings: false,
5852 }
5853 }
5854}
5855
5856#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5869pub struct AdvancedDistributionConfig {
5870 #[serde(default)]
5872 pub enabled: bool,
5873
5874 #[serde(default)]
5876 pub amounts: MixtureDistributionSchemaConfig,
5877
5878 #[serde(default)]
5880 pub correlations: CorrelationSchemaConfig,
5881
5882 #[serde(default)]
5884 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5885
5886 #[serde(default)]
5888 pub regime_changes: RegimeChangeSchemaConfig,
5889
5890 #[serde(default)]
5892 pub industry_profile: Option<IndustryProfileType>,
5893
5894 #[serde(default)]
5896 pub validation: StatisticalValidationSchemaConfig,
5897
5898 #[serde(default)]
5904 pub pareto: Option<ParetoSchemaConfig>,
5905}
5906
5907#[derive(Debug, Clone, Serialize, Deserialize)]
5912pub struct ParetoSchemaConfig {
5913 #[serde(default)]
5916 pub enabled: bool,
5917
5918 #[serde(default = "default_pareto_alpha")]
5921 pub alpha: f64,
5922
5923 #[serde(default = "default_pareto_x_min")]
5926 pub x_min: f64,
5927
5928 #[serde(default)]
5931 pub max_value: Option<f64>,
5932
5933 #[serde(default = "default_pareto_decimal_places")]
5935 pub decimal_places: u8,
5936}
5937
5938fn default_pareto_alpha() -> f64 {
5939 2.0
5940}
5941
5942fn default_pareto_x_min() -> f64 {
5943 100.0
5944}
5945
5946fn default_pareto_decimal_places() -> u8 {
5947 2
5948}
5949
5950impl Default for ParetoSchemaConfig {
5951 fn default() -> Self {
5952 Self {
5953 enabled: false,
5954 alpha: default_pareto_alpha(),
5955 x_min: default_pareto_x_min(),
5956 max_value: None,
5957 decimal_places: default_pareto_decimal_places(),
5958 }
5959 }
5960}
5961
5962impl ParetoSchemaConfig {
5963 pub fn to_core_config(&self) -> datasynth_core::distributions::ParetoConfig {
5965 datasynth_core::distributions::ParetoConfig {
5966 alpha: self.alpha,
5967 x_min: self.x_min,
5968 max_value: self.max_value,
5969 decimal_places: self.decimal_places,
5970 }
5971 }
5972}
5973
5974#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5976#[serde(rename_all = "snake_case")]
5977pub enum IndustryProfileType {
5978 Retail,
5980 Manufacturing,
5982 FinancialServices,
5984 Healthcare,
5986 Technology,
5988}
5989
5990#[derive(Debug, Clone, Serialize, Deserialize)]
5992pub struct MixtureDistributionSchemaConfig {
5993 #[serde(default)]
5995 pub enabled: bool,
5996
5997 #[serde(default = "default_mixture_type")]
5999 pub distribution_type: MixtureDistributionType,
6000
6001 #[serde(default)]
6003 pub components: Vec<MixtureComponentConfig>,
6004
6005 #[serde(default = "default_min_amount")]
6007 pub min_value: f64,
6008
6009 #[serde(default)]
6011 pub max_value: Option<f64>,
6012
6013 #[serde(default = "default_decimal_places")]
6015 pub decimal_places: u8,
6016}
6017
6018fn default_mixture_type() -> MixtureDistributionType {
6019 MixtureDistributionType::LogNormal
6020}
6021
6022fn default_min_amount() -> f64 {
6023 0.01
6024}
6025
6026fn default_decimal_places() -> u8 {
6027 2
6028}
6029
6030impl Default for MixtureDistributionSchemaConfig {
6031 fn default() -> Self {
6032 Self {
6033 enabled: false,
6034 distribution_type: MixtureDistributionType::LogNormal,
6035 components: Vec::new(),
6036 min_value: 0.01,
6037 max_value: None,
6038 decimal_places: 2,
6039 }
6040 }
6041}
6042
6043impl MixtureDistributionSchemaConfig {
6044 pub fn to_log_normal_config(
6051 &self,
6052 ) -> Option<datasynth_core::distributions::LogNormalMixtureConfig> {
6053 if self.components.is_empty() {
6054 return None;
6055 }
6056 Some(datasynth_core::distributions::LogNormalMixtureConfig {
6057 components: self
6058 .components
6059 .iter()
6060 .map(|c| match &c.label {
6061 Some(lbl) => datasynth_core::distributions::LogNormalComponent::with_label(
6062 c.weight,
6063 c.mu,
6064 c.sigma,
6065 lbl.clone(),
6066 ),
6067 None => datasynth_core::distributions::LogNormalComponent::new(
6068 c.weight, c.mu, c.sigma,
6069 ),
6070 })
6071 .collect(),
6072 min_value: self.min_value,
6073 max_value: self.max_value,
6074 decimal_places: self.decimal_places,
6075 })
6076 }
6077
6078 pub fn to_gaussian_config(
6081 &self,
6082 ) -> Option<datasynth_core::distributions::GaussianMixtureConfig> {
6083 if self.components.is_empty() {
6084 return None;
6085 }
6086 Some(datasynth_core::distributions::GaussianMixtureConfig {
6087 components: self
6088 .components
6089 .iter()
6090 .map(|c| {
6091 datasynth_core::distributions::GaussianComponent::new(c.weight, c.mu, c.sigma)
6092 })
6093 .collect(),
6094 allow_negative: true,
6095 min_value: Some(self.min_value),
6096 max_value: self.max_value,
6097 })
6098 }
6099}
6100
6101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6103#[serde(rename_all = "snake_case")]
6104pub enum MixtureDistributionType {
6105 Gaussian,
6107 #[default]
6109 LogNormal,
6110}
6111
6112#[derive(Debug, Clone, Serialize, Deserialize)]
6114pub struct MixtureComponentConfig {
6115 pub weight: f64,
6117
6118 pub mu: f64,
6120
6121 pub sigma: f64,
6123
6124 #[serde(default)]
6126 pub label: Option<String>,
6127}
6128
6129#[derive(Debug, Clone, Serialize, Deserialize)]
6131pub struct CorrelationSchemaConfig {
6132 #[serde(default)]
6134 pub enabled: bool,
6135
6136 #[serde(default)]
6138 pub copula_type: CopulaSchemaType,
6139
6140 #[serde(default)]
6142 pub fields: Vec<CorrelatedFieldConfig>,
6143
6144 #[serde(default)]
6147 pub matrix: Vec<f64>,
6148
6149 #[serde(default)]
6151 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
6152}
6153
6154impl Default for CorrelationSchemaConfig {
6155 fn default() -> Self {
6156 Self {
6157 enabled: false,
6158 copula_type: CopulaSchemaType::Gaussian,
6159 fields: Vec::new(),
6160 matrix: Vec::new(),
6161 expected_correlations: Vec::new(),
6162 }
6163 }
6164}
6165
6166impl CorrelationSchemaConfig {
6167 pub fn correlation_between(&self, field_a: &str, field_b: &str) -> Option<f64> {
6173 let idx_a = self.fields.iter().position(|f| f.name == field_a)?;
6174 let idx_b = self.fields.iter().position(|f| f.name == field_b)?;
6175 if idx_a == idx_b {
6176 return Some(1.0);
6177 }
6178 let (i, j) = if idx_a < idx_b {
6179 (idx_a, idx_b)
6180 } else {
6181 (idx_b, idx_a)
6182 };
6183 let n = self.fields.len();
6184 if self.matrix.len() == n * n {
6186 return self.matrix.get(idx_a * n + idx_b).copied();
6187 }
6188 let expected_tri = n * (n - 1) / 2;
6190 if self.matrix.len() == expected_tri {
6191 let flat = i * (n - 1) - i * (i.saturating_sub(1)) / 2 + (j - i - 1);
6195 return self.matrix.get(flat).copied();
6196 }
6197 None
6198 }
6199
6200 pub fn to_core_config_for_pair(
6205 &self,
6206 field_a: &str,
6207 field_b: &str,
6208 ) -> Option<datasynth_core::distributions::CopulaConfig> {
6209 if !self.enabled {
6210 return None;
6211 }
6212 let rho = self.correlation_between(field_a, field_b)?;
6213 use datasynth_core::distributions::{CopulaConfig, CopulaType};
6214 let copula_type = match self.copula_type {
6215 CopulaSchemaType::Gaussian => CopulaType::Gaussian,
6216 CopulaSchemaType::Clayton => CopulaType::Clayton,
6217 CopulaSchemaType::Gumbel => CopulaType::Gumbel,
6218 CopulaSchemaType::Frank => CopulaType::Frank,
6219 CopulaSchemaType::StudentT => CopulaType::StudentT,
6220 };
6221 let theta = rho.clamp(-0.999, 0.999);
6226 Some(CopulaConfig {
6227 copula_type,
6228 theta,
6229 degrees_of_freedom: 4.0,
6230 })
6231 }
6232}
6233
6234#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6236#[serde(rename_all = "snake_case")]
6237pub enum CopulaSchemaType {
6238 #[default]
6240 Gaussian,
6241 Clayton,
6243 Gumbel,
6245 Frank,
6247 StudentT,
6249}
6250
6251#[derive(Debug, Clone, Serialize, Deserialize)]
6253pub struct CorrelatedFieldConfig {
6254 pub name: String,
6256
6257 #[serde(default)]
6259 pub distribution: MarginalDistributionConfig,
6260}
6261
6262#[derive(Debug, Clone, Serialize, Deserialize)]
6264#[serde(tag = "type", rename_all = "snake_case")]
6265pub enum MarginalDistributionConfig {
6266 Normal {
6268 mu: f64,
6270 sigma: f64,
6272 },
6273 LogNormal {
6275 mu: f64,
6277 sigma: f64,
6279 },
6280 Uniform {
6282 min: f64,
6284 max: f64,
6286 },
6287 DiscreteUniform {
6289 min: i32,
6291 max: i32,
6293 },
6294}
6295
6296impl Default for MarginalDistributionConfig {
6297 fn default() -> Self {
6298 Self::Normal {
6299 mu: 0.0,
6300 sigma: 1.0,
6301 }
6302 }
6303}
6304
6305#[derive(Debug, Clone, Serialize, Deserialize)]
6307pub struct ExpectedCorrelationConfig {
6308 pub field1: String,
6310 pub field2: String,
6312 pub expected_r: f64,
6314 #[serde(default = "default_correlation_tolerance")]
6316 pub tolerance: f64,
6317}
6318
6319fn default_correlation_tolerance() -> f64 {
6320 0.10
6321}
6322
6323#[derive(Debug, Clone, Serialize, Deserialize)]
6325pub struct ConditionalDistributionSchemaConfig {
6326 pub output_field: String,
6328
6329 pub input_field: String,
6331
6332 #[serde(default)]
6334 pub breakpoints: Vec<ConditionalBreakpointConfig>,
6335
6336 #[serde(default)]
6338 pub default_distribution: ConditionalDistributionParamsConfig,
6339
6340 #[serde(default)]
6342 pub min_value: Option<f64>,
6343
6344 #[serde(default)]
6346 pub max_value: Option<f64>,
6347
6348 #[serde(default = "default_decimal_places")]
6350 pub decimal_places: u8,
6351}
6352
6353#[derive(Debug, Clone, Serialize, Deserialize)]
6355pub struct ConditionalBreakpointConfig {
6356 pub threshold: f64,
6358
6359 pub distribution: ConditionalDistributionParamsConfig,
6361}
6362
6363impl ConditionalDistributionSchemaConfig {
6364 pub fn to_core_config(&self) -> datasynth_core::distributions::ConditionalDistributionConfig {
6368 use datasynth_core::distributions::{
6369 Breakpoint, ConditionalDistributionConfig, ConditionalDistributionParams,
6370 };
6371
6372 let default_distribution = convert_conditional_params(&self.default_distribution);
6373 let breakpoints: Vec<Breakpoint> = self
6374 .breakpoints
6375 .iter()
6376 .map(|bp| Breakpoint {
6377 threshold: bp.threshold,
6378 distribution: convert_conditional_params(&bp.distribution),
6379 })
6380 .collect();
6381
6382 let final_default = if breakpoints.is_empty() {
6387 default_distribution
6388 } else {
6389 match default_distribution {
6390 ConditionalDistributionParams::Fixed { value: 0.0 } => {
6391 breakpoints[0].distribution.clone()
6394 }
6395 other => other,
6396 }
6397 };
6398
6399 ConditionalDistributionConfig {
6400 output_field: self.output_field.clone(),
6401 input_field: self.input_field.clone(),
6402 breakpoints,
6403 default_distribution: final_default,
6404 min_value: self.min_value,
6405 max_value: self.max_value,
6406 decimal_places: self.decimal_places,
6407 }
6408 }
6409}
6410
6411fn convert_conditional_params(
6412 p: &ConditionalDistributionParamsConfig,
6413) -> datasynth_core::distributions::ConditionalDistributionParams {
6414 use datasynth_core::distributions::ConditionalDistributionParams as Core;
6415 match p {
6416 ConditionalDistributionParamsConfig::Fixed { value } => Core::Fixed { value: *value },
6417 ConditionalDistributionParamsConfig::Normal { mu, sigma } => Core::Normal {
6418 mu: *mu,
6419 sigma: *sigma,
6420 },
6421 ConditionalDistributionParamsConfig::LogNormal { mu, sigma } => Core::LogNormal {
6422 mu: *mu,
6423 sigma: *sigma,
6424 },
6425 ConditionalDistributionParamsConfig::Uniform { min, max } => Core::Uniform {
6426 min: *min,
6427 max: *max,
6428 },
6429 ConditionalDistributionParamsConfig::Beta {
6430 alpha,
6431 beta,
6432 min,
6433 max,
6434 } => Core::Beta {
6435 alpha: *alpha,
6436 beta: *beta,
6437 min: *min,
6438 max: *max,
6439 },
6440 ConditionalDistributionParamsConfig::Discrete { values, weights } => Core::Discrete {
6441 values: values.clone(),
6442 weights: weights.clone(),
6443 },
6444 }
6445}
6446
6447#[derive(Debug, Clone, Serialize, Deserialize)]
6449#[serde(tag = "type", rename_all = "snake_case")]
6450pub enum ConditionalDistributionParamsConfig {
6451 Fixed {
6453 value: f64,
6455 },
6456 Normal {
6458 mu: f64,
6460 sigma: f64,
6462 },
6463 LogNormal {
6465 mu: f64,
6467 sigma: f64,
6469 },
6470 Uniform {
6472 min: f64,
6474 max: f64,
6476 },
6477 Beta {
6479 alpha: f64,
6481 beta: f64,
6483 min: f64,
6485 max: f64,
6487 },
6488 Discrete {
6490 values: Vec<f64>,
6492 weights: Vec<f64>,
6494 },
6495}
6496
6497impl Default for ConditionalDistributionParamsConfig {
6498 fn default() -> Self {
6499 Self::Normal {
6500 mu: 0.0,
6501 sigma: 1.0,
6502 }
6503 }
6504}
6505
6506#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6508pub struct RegimeChangeSchemaConfig {
6509 #[serde(default)]
6511 pub enabled: bool,
6512
6513 #[serde(default)]
6515 pub changes: Vec<RegimeChangeEventConfig>,
6516
6517 #[serde(default)]
6519 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6520
6521 #[serde(default)]
6523 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6524}
6525
6526#[derive(Debug, Clone, Serialize, Deserialize)]
6528pub struct RegimeChangeEventConfig {
6529 pub date: String,
6531
6532 pub change_type: RegimeChangeTypeConfig,
6534
6535 #[serde(default)]
6537 pub description: Option<String>,
6538
6539 #[serde(default)]
6541 pub effects: Vec<RegimeEffectConfig>,
6542}
6543
6544#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6546#[serde(rename_all = "snake_case")]
6547pub enum RegimeChangeTypeConfig {
6548 Acquisition,
6550 Divestiture,
6552 PriceIncrease,
6554 PriceDecrease,
6556 ProductLaunch,
6558 ProductDiscontinuation,
6560 PolicyChange,
6562 CompetitorEntry,
6564 Custom,
6566}
6567
6568#[derive(Debug, Clone, Serialize, Deserialize)]
6570pub struct RegimeEffectConfig {
6571 pub field: String,
6573
6574 pub multiplier: f64,
6576}
6577
6578#[derive(Debug, Clone, Serialize, Deserialize)]
6580pub struct EconomicCycleSchemaConfig {
6581 #[serde(default)]
6583 pub enabled: bool,
6584
6585 #[serde(default = "default_cycle_period")]
6587 pub period_months: u32,
6588
6589 #[serde(default = "default_cycle_amplitude")]
6591 pub amplitude: f64,
6592
6593 #[serde(default)]
6595 pub phase_offset: u32,
6596
6597 #[serde(default)]
6599 pub recessions: Vec<RecessionPeriodConfig>,
6600}
6601
6602fn default_cycle_period() -> u32 {
6603 48
6604}
6605
6606fn default_cycle_amplitude() -> f64 {
6607 0.15
6608}
6609
6610impl Default for EconomicCycleSchemaConfig {
6611 fn default() -> Self {
6612 Self {
6613 enabled: false,
6614 period_months: 48,
6615 amplitude: 0.15,
6616 phase_offset: 0,
6617 recessions: Vec::new(),
6618 }
6619 }
6620}
6621
6622#[derive(Debug, Clone, Serialize, Deserialize)]
6624pub struct RecessionPeriodConfig {
6625 pub start_month: u32,
6627
6628 pub duration_months: u32,
6630
6631 #[serde(default = "default_recession_severity")]
6633 pub severity: f64,
6634}
6635
6636impl RegimeChangeSchemaConfig {
6637 pub fn apply_to(
6645 &self,
6646 drift: &mut datasynth_core::distributions::DriftConfig,
6647 generation_start: chrono::NaiveDate,
6648 ) {
6649 if !self.enabled {
6650 return;
6651 }
6652
6653 drift.enabled = true;
6655
6656 for event in &self.changes {
6658 let period = match chrono::NaiveDate::parse_from_str(&event.date, "%Y-%m-%d") {
6659 Ok(d) => {
6660 let days = (d - generation_start).num_days();
6661 if days < 0 {
6662 continue;
6663 }
6664 (days as f64 / 30.4).round() as u32
6667 }
6668 Err(_) => continue,
6669 };
6670 let change_type = convert_regime_change_type(event.change_type);
6671 let core_effects = event
6672 .effects
6673 .iter()
6674 .map(|e| datasynth_core::distributions::RegimeEffect {
6675 field: e.field.clone(),
6676 multiplier: e.multiplier,
6677 })
6678 .collect();
6679 drift
6680 .regime_changes
6681 .push(datasynth_core::distributions::RegimeChange {
6682 period,
6683 change_type,
6684 description: event.description.clone(),
6685 effects: core_effects,
6686 transition_periods: 0,
6687 });
6688 }
6689
6690 if let Some(ec) = &self.economic_cycle {
6692 if ec.enabled {
6693 let recession_periods: Vec<u32> = ec
6694 .recessions
6695 .iter()
6696 .flat_map(|r| r.start_month..r.start_month + r.duration_months)
6697 .collect();
6698 let severity = ec
6701 .recessions
6702 .iter()
6703 .map(|r| 1.0 - r.severity)
6704 .fold(0.75f64, f64::min);
6705 drift.economic_cycle = datasynth_core::distributions::EconomicCycleConfig {
6706 enabled: true,
6707 cycle_length: ec.period_months,
6708 amplitude: ec.amplitude,
6709 phase_offset: ec.phase_offset,
6710 recession_periods,
6711 recession_severity: severity,
6712 };
6713 drift.drift_type = datasynth_core::distributions::DriftType::Mixed;
6714 }
6715 }
6716
6717 for pd in &self.parameter_drifts {
6719 let drift_type = match pd.drift_type {
6720 ParameterDriftTypeConfig::Linear => {
6721 datasynth_core::distributions::ParameterDriftType::Linear
6722 }
6723 ParameterDriftTypeConfig::Exponential => {
6724 datasynth_core::distributions::ParameterDriftType::Exponential
6725 }
6726 ParameterDriftTypeConfig::Logistic => {
6727 datasynth_core::distributions::ParameterDriftType::Logistic
6728 }
6729 ParameterDriftTypeConfig::Step => {
6730 datasynth_core::distributions::ParameterDriftType::Step
6731 }
6732 };
6733 drift
6734 .parameter_drifts
6735 .push(datasynth_core::distributions::ParameterDrift {
6736 parameter: pd.parameter.clone(),
6737 drift_type,
6738 initial_value: pd.start_value,
6739 target_or_rate: pd.end_value,
6740 start_period: pd.start_period,
6741 end_period: pd.end_period,
6742 steepness: 1.0,
6743 });
6744 }
6745 }
6746}
6747
6748fn convert_regime_change_type(
6749 t: RegimeChangeTypeConfig,
6750) -> datasynth_core::distributions::RegimeChangeType {
6751 use datasynth_core::distributions::RegimeChangeType as Core;
6752 match t {
6753 RegimeChangeTypeConfig::Acquisition => Core::Acquisition,
6754 RegimeChangeTypeConfig::Divestiture => Core::Divestiture,
6755 RegimeChangeTypeConfig::PriceIncrease => Core::PriceIncrease,
6756 RegimeChangeTypeConfig::PriceDecrease => Core::PriceDecrease,
6757 RegimeChangeTypeConfig::ProductLaunch => Core::ProductLaunch,
6758 RegimeChangeTypeConfig::ProductDiscontinuation => Core::ProductDiscontinuation,
6759 RegimeChangeTypeConfig::PolicyChange => Core::PolicyChange,
6760 RegimeChangeTypeConfig::CompetitorEntry => Core::CompetitorEntry,
6761 RegimeChangeTypeConfig::Custom => Core::Custom,
6762 }
6763}
6764
6765fn default_recession_severity() -> f64 {
6766 0.20
6767}
6768
6769#[derive(Debug, Clone, Serialize, Deserialize)]
6771pub struct ParameterDriftSchemaConfig {
6772 pub parameter: String,
6774
6775 pub drift_type: ParameterDriftTypeConfig,
6777
6778 pub start_value: f64,
6780
6781 pub end_value: f64,
6783
6784 #[serde(default)]
6786 pub start_period: u32,
6787
6788 #[serde(default)]
6790 pub end_period: Option<u32>,
6791}
6792
6793#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6795#[serde(rename_all = "snake_case")]
6796pub enum ParameterDriftTypeConfig {
6797 #[default]
6799 Linear,
6800 Exponential,
6802 Logistic,
6804 Step,
6806}
6807
6808#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6810pub struct StatisticalValidationSchemaConfig {
6811 #[serde(default)]
6813 pub enabled: bool,
6814
6815 #[serde(default)]
6817 pub tests: Vec<StatisticalTestConfig>,
6818
6819 #[serde(default)]
6821 pub reporting: ValidationReportingConfig,
6822}
6823
6824#[derive(Debug, Clone, Serialize, Deserialize)]
6826#[serde(tag = "type", rename_all = "snake_case")]
6827pub enum StatisticalTestConfig {
6828 BenfordFirstDigit {
6830 #[serde(default = "default_benford_threshold")]
6832 threshold_mad: f64,
6833 #[serde(default = "default_benford_warning")]
6835 warning_mad: f64,
6836 },
6837 DistributionFit {
6839 target: TargetDistributionConfig,
6841 #[serde(default = "default_ks_significance")]
6843 ks_significance: f64,
6844 #[serde(default)]
6846 method: DistributionFitMethod,
6847 },
6848 CorrelationCheck {
6850 expected_correlations: Vec<ExpectedCorrelationConfig>,
6852 },
6853 ChiSquared {
6855 #[serde(default = "default_chi_squared_bins")]
6857 bins: usize,
6858 #[serde(default = "default_chi_squared_significance")]
6860 significance: f64,
6861 },
6862 AndersonDarling {
6864 target: TargetDistributionConfig,
6866 #[serde(default = "default_ad_significance")]
6868 significance: f64,
6869 },
6870}
6871
6872fn default_benford_threshold() -> f64 {
6873 0.015
6874}
6875
6876fn default_benford_warning() -> f64 {
6877 0.010
6878}
6879
6880fn default_ks_significance() -> f64 {
6881 0.05
6882}
6883
6884fn default_chi_squared_bins() -> usize {
6885 10
6886}
6887
6888fn default_chi_squared_significance() -> f64 {
6889 0.05
6890}
6891
6892fn default_ad_significance() -> f64 {
6893 0.05
6894}
6895
6896#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6898#[serde(rename_all = "snake_case")]
6899pub enum TargetDistributionConfig {
6900 Normal,
6902 #[default]
6904 LogNormal,
6905 Exponential,
6907 Uniform,
6909}
6910
6911#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6913#[serde(rename_all = "snake_case")]
6914pub enum DistributionFitMethod {
6915 #[default]
6917 KolmogorovSmirnov,
6918 AndersonDarling,
6920 ChiSquared,
6922}
6923
6924#[derive(Debug, Clone, Serialize, Deserialize)]
6926pub struct ValidationReportingConfig {
6927 #[serde(default)]
6929 pub output_report: bool,
6930
6931 #[serde(default)]
6933 pub format: ValidationReportFormat,
6934
6935 #[serde(default)]
6937 pub fail_on_error: bool,
6938
6939 #[serde(default = "default_true")]
6941 pub include_details: bool,
6942}
6943
6944impl Default for ValidationReportingConfig {
6945 fn default() -> Self {
6946 Self {
6947 output_report: false,
6948 format: ValidationReportFormat::Json,
6949 fail_on_error: false,
6950 include_details: true,
6951 }
6952 }
6953}
6954
6955#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6957#[serde(rename_all = "snake_case")]
6958pub enum ValidationReportFormat {
6959 #[default]
6961 Json,
6962 Yaml,
6964 Html,
6966}
6967
6968#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6980pub struct TemporalPatternsConfig {
6981 #[serde(default)]
6983 pub enabled: bool,
6984
6985 #[serde(default)]
6987 pub business_days: BusinessDaySchemaConfig,
6988
6989 #[serde(default)]
6991 pub calendars: CalendarSchemaConfig,
6992
6993 #[serde(default)]
6995 pub period_end: PeriodEndSchemaConfig,
6996
6997 #[serde(default)]
6999 pub processing_lags: ProcessingLagSchemaConfig,
7000
7001 #[serde(default)]
7003 pub fiscal_calendar: FiscalCalendarSchemaConfig,
7004
7005 #[serde(default)]
7007 pub intraday: IntraDaySchemaConfig,
7008
7009 #[serde(default)]
7011 pub timezones: TimezoneSchemaConfig,
7012}
7013
7014#[derive(Debug, Clone, Serialize, Deserialize)]
7016pub struct BusinessDaySchemaConfig {
7017 #[serde(default = "default_true")]
7019 pub enabled: bool,
7020
7021 #[serde(default = "default_half_day_policy")]
7023 pub half_day_policy: String,
7024
7025 #[serde(default)]
7027 pub settlement_rules: SettlementRulesSchemaConfig,
7028
7029 #[serde(default = "default_month_end_convention")]
7031 pub month_end_convention: String,
7032
7033 #[serde(default)]
7035 pub weekend_days: Option<Vec<String>>,
7036}
7037
7038fn default_half_day_policy() -> String {
7039 "half_day".to_string()
7040}
7041
7042fn default_month_end_convention() -> String {
7043 "modified_following".to_string()
7044}
7045
7046impl Default for BusinessDaySchemaConfig {
7047 fn default() -> Self {
7048 Self {
7049 enabled: true,
7050 half_day_policy: "half_day".to_string(),
7051 settlement_rules: SettlementRulesSchemaConfig::default(),
7052 month_end_convention: "modified_following".to_string(),
7053 weekend_days: None,
7054 }
7055 }
7056}
7057
7058#[derive(Debug, Clone, Serialize, Deserialize)]
7060pub struct SettlementRulesSchemaConfig {
7061 #[serde(default = "default_settlement_2")]
7063 pub equity_days: i32,
7064
7065 #[serde(default = "default_settlement_1")]
7067 pub government_bonds_days: i32,
7068
7069 #[serde(default = "default_settlement_2")]
7071 pub fx_spot_days: i32,
7072
7073 #[serde(default = "default_settlement_2")]
7075 pub corporate_bonds_days: i32,
7076
7077 #[serde(default = "default_wire_cutoff")]
7079 pub wire_cutoff_time: String,
7080
7081 #[serde(default = "default_settlement_1")]
7083 pub wire_international_days: i32,
7084
7085 #[serde(default = "default_settlement_1")]
7087 pub ach_days: i32,
7088}
7089
7090fn default_settlement_1() -> i32 {
7091 1
7092}
7093
7094fn default_settlement_2() -> i32 {
7095 2
7096}
7097
7098fn default_wire_cutoff() -> String {
7099 "14:00".to_string()
7100}
7101
7102impl Default for SettlementRulesSchemaConfig {
7103 fn default() -> Self {
7104 Self {
7105 equity_days: 2,
7106 government_bonds_days: 1,
7107 fx_spot_days: 2,
7108 corporate_bonds_days: 2,
7109 wire_cutoff_time: "14:00".to_string(),
7110 wire_international_days: 1,
7111 ach_days: 1,
7112 }
7113 }
7114}
7115
7116#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7118pub struct CalendarSchemaConfig {
7119 #[serde(default)]
7121 pub regions: Vec<String>,
7122
7123 #[serde(default)]
7125 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
7126}
7127
7128#[derive(Debug, Clone, Serialize, Deserialize)]
7130pub struct CustomHolidaySchemaConfig {
7131 pub name: String,
7133 pub month: u8,
7135 pub day: u8,
7137 #[serde(default = "default_holiday_multiplier")]
7139 pub activity_multiplier: f64,
7140}
7141
7142fn default_holiday_multiplier() -> f64 {
7143 0.05
7144}
7145
7146#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7148pub struct PeriodEndSchemaConfig {
7149 #[serde(default)]
7151 pub model: Option<String>,
7152
7153 #[serde(default)]
7155 pub month_end: Option<PeriodEndModelSchemaConfig>,
7156
7157 #[serde(default)]
7159 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
7160
7161 #[serde(default)]
7163 pub year_end: Option<PeriodEndModelSchemaConfig>,
7164}
7165
7166#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7168pub struct PeriodEndModelSchemaConfig {
7169 #[serde(default)]
7171 pub inherit_from: Option<String>,
7172
7173 #[serde(default)]
7175 pub additional_multiplier: Option<f64>,
7176
7177 #[serde(default)]
7179 pub start_day: Option<i32>,
7180
7181 #[serde(default)]
7183 pub base_multiplier: Option<f64>,
7184
7185 #[serde(default)]
7187 pub peak_multiplier: Option<f64>,
7188
7189 #[serde(default)]
7191 pub decay_rate: Option<f64>,
7192
7193 #[serde(default)]
7195 pub sustained_high_days: Option<i32>,
7196}
7197
7198#[derive(Debug, Clone, Serialize, Deserialize)]
7200pub struct ProcessingLagSchemaConfig {
7201 #[serde(default = "default_true")]
7203 pub enabled: bool,
7204
7205 #[serde(default)]
7207 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
7208
7209 #[serde(default)]
7211 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
7212
7213 #[serde(default)]
7215 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
7216
7217 #[serde(default)]
7219 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
7220
7221 #[serde(default)]
7223 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
7224
7225 #[serde(default)]
7227 pub payment_lag: Option<LagDistributionSchemaConfig>,
7228
7229 #[serde(default)]
7231 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
7232
7233 #[serde(default)]
7235 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
7236}
7237
7238impl Default for ProcessingLagSchemaConfig {
7239 fn default() -> Self {
7240 Self {
7241 enabled: true,
7242 sales_order_lag: None,
7243 purchase_order_lag: None,
7244 goods_receipt_lag: None,
7245 invoice_receipt_lag: None,
7246 invoice_issue_lag: None,
7247 payment_lag: None,
7248 journal_entry_lag: None,
7249 cross_day_posting: None,
7250 }
7251 }
7252}
7253
7254#[derive(Debug, Clone, Serialize, Deserialize)]
7256pub struct LagDistributionSchemaConfig {
7257 pub mu: f64,
7259 pub sigma: f64,
7261 #[serde(default)]
7263 pub min_hours: Option<f64>,
7264 #[serde(default)]
7266 pub max_hours: Option<f64>,
7267}
7268
7269#[derive(Debug, Clone, Serialize, Deserialize)]
7271pub struct CrossDayPostingSchemaConfig {
7272 #[serde(default = "default_true")]
7274 pub enabled: bool,
7275
7276 #[serde(default)]
7279 pub probability_by_hour: std::collections::HashMap<u8, f64>,
7280}
7281
7282impl Default for CrossDayPostingSchemaConfig {
7283 fn default() -> Self {
7284 let mut probability_by_hour = std::collections::HashMap::new();
7285 probability_by_hour.insert(17, 0.3);
7286 probability_by_hour.insert(18, 0.6);
7287 probability_by_hour.insert(19, 0.8);
7288 probability_by_hour.insert(20, 0.9);
7289 probability_by_hour.insert(21, 0.95);
7290 probability_by_hour.insert(22, 0.99);
7291
7292 Self {
7293 enabled: true,
7294 probability_by_hour,
7295 }
7296 }
7297}
7298
7299#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7308pub struct FiscalCalendarSchemaConfig {
7309 #[serde(default)]
7311 pub enabled: bool,
7312
7313 #[serde(default = "default_fiscal_calendar_type")]
7315 pub calendar_type: String,
7316
7317 #[serde(default)]
7319 pub year_start_month: Option<u8>,
7320
7321 #[serde(default)]
7323 pub year_start_day: Option<u8>,
7324
7325 #[serde(default)]
7327 pub four_four_five: Option<FourFourFiveSchemaConfig>,
7328}
7329
7330fn default_fiscal_calendar_type() -> String {
7331 "calendar_year".to_string()
7332}
7333
7334#[derive(Debug, Clone, Serialize, Deserialize)]
7336pub struct FourFourFiveSchemaConfig {
7337 #[serde(default = "default_week_pattern")]
7339 pub pattern: String,
7340
7341 #[serde(default = "default_anchor_type")]
7343 pub anchor_type: String,
7344
7345 #[serde(default = "default_anchor_month")]
7347 pub anchor_month: u8,
7348
7349 #[serde(default = "default_leap_week_placement")]
7351 pub leap_week_placement: String,
7352}
7353
7354fn default_week_pattern() -> String {
7355 "four_four_five".to_string()
7356}
7357
7358fn default_anchor_type() -> String {
7359 "last_saturday".to_string()
7360}
7361
7362fn default_anchor_month() -> u8 {
7363 1 }
7365
7366fn default_leap_week_placement() -> String {
7367 "q4_period3".to_string()
7368}
7369
7370impl Default for FourFourFiveSchemaConfig {
7371 fn default() -> Self {
7372 Self {
7373 pattern: "four_four_five".to_string(),
7374 anchor_type: "last_saturday".to_string(),
7375 anchor_month: 1,
7376 leap_week_placement: "q4_period3".to_string(),
7377 }
7378 }
7379}
7380
7381#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7390pub struct IntraDaySchemaConfig {
7391 #[serde(default)]
7393 pub enabled: bool,
7394
7395 #[serde(default)]
7397 pub segments: Vec<IntraDaySegmentSchemaConfig>,
7398}
7399
7400#[derive(Debug, Clone, Serialize, Deserialize)]
7402pub struct IntraDaySegmentSchemaConfig {
7403 pub name: String,
7405
7406 pub start: String,
7408
7409 pub end: String,
7411
7412 #[serde(default = "default_multiplier")]
7414 pub multiplier: f64,
7415
7416 #[serde(default = "default_posting_type")]
7418 pub posting_type: String,
7419}
7420
7421fn default_multiplier() -> f64 {
7422 1.0
7423}
7424
7425fn default_posting_type() -> String {
7426 "both".to_string()
7427}
7428
7429#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7435pub struct TimezoneSchemaConfig {
7436 #[serde(default)]
7438 pub enabled: bool,
7439
7440 #[serde(default = "default_timezone")]
7442 pub default_timezone: String,
7443
7444 #[serde(default = "default_consolidation_timezone")]
7446 pub consolidation_timezone: String,
7447
7448 #[serde(default)]
7451 pub entity_mappings: Vec<EntityTimezoneMapping>,
7452}
7453
7454fn default_timezone() -> String {
7455 "America/New_York".to_string()
7456}
7457
7458fn default_consolidation_timezone() -> String {
7459 "UTC".to_string()
7460}
7461
7462#[derive(Debug, Clone, Serialize, Deserialize)]
7464pub struct EntityTimezoneMapping {
7465 pub pattern: String,
7467
7468 pub timezone: String,
7470}
7471
7472#[derive(Debug, Clone, Serialize, Deserialize)]
7478pub struct VendorNetworkSchemaConfig {
7479 #[serde(default)]
7481 pub enabled: bool,
7482
7483 #[serde(default = "default_vendor_tier_depth")]
7485 pub depth: u8,
7486
7487 #[serde(default)]
7489 pub tier1: TierCountSchemaConfig,
7490
7491 #[serde(default)]
7493 pub tier2_per_parent: TierCountSchemaConfig,
7494
7495 #[serde(default)]
7497 pub tier3_per_parent: TierCountSchemaConfig,
7498
7499 #[serde(default)]
7501 pub clusters: VendorClusterSchemaConfig,
7502
7503 #[serde(default)]
7505 pub dependencies: DependencySchemaConfig,
7506}
7507
7508fn default_vendor_tier_depth() -> u8 {
7509 3
7510}
7511
7512impl Default for VendorNetworkSchemaConfig {
7513 fn default() -> Self {
7514 Self {
7515 enabled: false,
7516 depth: 3,
7517 tier1: TierCountSchemaConfig { min: 50, max: 100 },
7518 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
7519 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
7520 clusters: VendorClusterSchemaConfig::default(),
7521 dependencies: DependencySchemaConfig::default(),
7522 }
7523 }
7524}
7525
7526#[derive(Debug, Clone, Serialize, Deserialize)]
7528pub struct TierCountSchemaConfig {
7529 #[serde(default = "default_tier_min")]
7531 pub min: usize,
7532
7533 #[serde(default = "default_tier_max")]
7535 pub max: usize,
7536}
7537
7538fn default_tier_min() -> usize {
7539 5
7540}
7541
7542fn default_tier_max() -> usize {
7543 20
7544}
7545
7546impl Default for TierCountSchemaConfig {
7547 fn default() -> Self {
7548 Self {
7549 min: default_tier_min(),
7550 max: default_tier_max(),
7551 }
7552 }
7553}
7554
7555#[derive(Debug, Clone, Serialize, Deserialize)]
7557pub struct VendorClusterSchemaConfig {
7558 #[serde(default = "default_reliable_strategic")]
7560 pub reliable_strategic: f64,
7561
7562 #[serde(default = "default_standard_operational")]
7564 pub standard_operational: f64,
7565
7566 #[serde(default = "default_transactional")]
7568 pub transactional: f64,
7569
7570 #[serde(default = "default_problematic")]
7572 pub problematic: f64,
7573}
7574
7575fn default_reliable_strategic() -> f64 {
7576 0.20
7577}
7578
7579fn default_standard_operational() -> f64 {
7580 0.50
7581}
7582
7583fn default_transactional() -> f64 {
7584 0.25
7585}
7586
7587fn default_problematic() -> f64 {
7588 0.05
7589}
7590
7591impl Default for VendorClusterSchemaConfig {
7592 fn default() -> Self {
7593 Self {
7594 reliable_strategic: 0.20,
7595 standard_operational: 0.50,
7596 transactional: 0.25,
7597 problematic: 0.05,
7598 }
7599 }
7600}
7601
7602#[derive(Debug, Clone, Serialize, Deserialize)]
7604pub struct DependencySchemaConfig {
7605 #[serde(default = "default_max_single_vendor")]
7607 pub max_single_vendor_concentration: f64,
7608
7609 #[serde(default = "default_max_top5")]
7611 pub top_5_concentration: f64,
7612
7613 #[serde(default = "default_single_source_percent")]
7615 pub single_source_percent: f64,
7616}
7617
7618fn default_max_single_vendor() -> f64 {
7619 0.15
7620}
7621
7622fn default_max_top5() -> f64 {
7623 0.45
7624}
7625
7626fn default_single_source_percent() -> f64 {
7627 0.05
7628}
7629
7630impl Default for DependencySchemaConfig {
7631 fn default() -> Self {
7632 Self {
7633 max_single_vendor_concentration: 0.15,
7634 top_5_concentration: 0.45,
7635 single_source_percent: 0.05,
7636 }
7637 }
7638}
7639
7640#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7646pub struct CustomerSegmentationSchemaConfig {
7647 #[serde(default)]
7649 pub enabled: bool,
7650
7651 #[serde(default)]
7653 pub value_segments: ValueSegmentsSchemaConfig,
7654
7655 #[serde(default)]
7657 pub lifecycle: LifecycleSchemaConfig,
7658
7659 #[serde(default)]
7661 pub networks: CustomerNetworksSchemaConfig,
7662}
7663
7664#[derive(Debug, Clone, Serialize, Deserialize)]
7666pub struct ValueSegmentsSchemaConfig {
7667 #[serde(default)]
7669 pub enterprise: SegmentDetailSchemaConfig,
7670
7671 #[serde(default)]
7673 pub mid_market: SegmentDetailSchemaConfig,
7674
7675 #[serde(default)]
7677 pub smb: SegmentDetailSchemaConfig,
7678
7679 #[serde(default)]
7681 pub consumer: SegmentDetailSchemaConfig,
7682}
7683
7684impl Default for ValueSegmentsSchemaConfig {
7685 fn default() -> Self {
7686 Self {
7687 enterprise: SegmentDetailSchemaConfig {
7688 revenue_share: 0.40,
7689 customer_share: 0.05,
7690 avg_order_value_range: "50000+".to_string(),
7691 },
7692 mid_market: SegmentDetailSchemaConfig {
7693 revenue_share: 0.35,
7694 customer_share: 0.20,
7695 avg_order_value_range: "5000-50000".to_string(),
7696 },
7697 smb: SegmentDetailSchemaConfig {
7698 revenue_share: 0.20,
7699 customer_share: 0.50,
7700 avg_order_value_range: "500-5000".to_string(),
7701 },
7702 consumer: SegmentDetailSchemaConfig {
7703 revenue_share: 0.05,
7704 customer_share: 0.25,
7705 avg_order_value_range: "50-500".to_string(),
7706 },
7707 }
7708 }
7709}
7710
7711#[derive(Debug, Clone, Serialize, Deserialize)]
7713pub struct SegmentDetailSchemaConfig {
7714 #[serde(default)]
7716 pub revenue_share: f64,
7717
7718 #[serde(default)]
7720 pub customer_share: f64,
7721
7722 #[serde(default)]
7724 pub avg_order_value_range: String,
7725}
7726
7727impl Default for SegmentDetailSchemaConfig {
7728 fn default() -> Self {
7729 Self {
7730 revenue_share: 0.25,
7731 customer_share: 0.25,
7732 avg_order_value_range: "1000-10000".to_string(),
7733 }
7734 }
7735}
7736
7737#[derive(Debug, Clone, Serialize, Deserialize)]
7739pub struct LifecycleSchemaConfig {
7740 #[serde(default)]
7742 pub prospect_rate: f64,
7743
7744 #[serde(default = "default_new_rate")]
7746 pub new_rate: f64,
7747
7748 #[serde(default = "default_growth_rate")]
7750 pub growth_rate: f64,
7751
7752 #[serde(default = "default_mature_rate")]
7754 pub mature_rate: f64,
7755
7756 #[serde(default = "default_at_risk_rate")]
7758 pub at_risk_rate: f64,
7759
7760 #[serde(default = "default_churned_rate")]
7762 pub churned_rate: f64,
7763
7764 #[serde(default)]
7766 pub won_back_rate: f64,
7767}
7768
7769fn default_new_rate() -> f64 {
7770 0.10
7771}
7772
7773fn default_growth_rate() -> f64 {
7774 0.15
7775}
7776
7777fn default_mature_rate() -> f64 {
7778 0.60
7779}
7780
7781fn default_at_risk_rate() -> f64 {
7782 0.10
7783}
7784
7785fn default_churned_rate() -> f64 {
7786 0.05
7787}
7788
7789impl Default for LifecycleSchemaConfig {
7790 fn default() -> Self {
7791 Self {
7792 prospect_rate: 0.0,
7793 new_rate: 0.10,
7794 growth_rate: 0.15,
7795 mature_rate: 0.60,
7796 at_risk_rate: 0.10,
7797 churned_rate: 0.05,
7798 won_back_rate: 0.0,
7799 }
7800 }
7801}
7802
7803#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7805pub struct CustomerNetworksSchemaConfig {
7806 #[serde(default)]
7808 pub referrals: ReferralSchemaConfig,
7809
7810 #[serde(default)]
7812 pub corporate_hierarchies: HierarchySchemaConfig,
7813}
7814
7815#[derive(Debug, Clone, Serialize, Deserialize)]
7817pub struct ReferralSchemaConfig {
7818 #[serde(default = "default_true")]
7820 pub enabled: bool,
7821
7822 #[serde(default = "default_referral_rate")]
7824 pub referral_rate: f64,
7825}
7826
7827fn default_referral_rate() -> f64 {
7828 0.15
7829}
7830
7831impl Default for ReferralSchemaConfig {
7832 fn default() -> Self {
7833 Self {
7834 enabled: true,
7835 referral_rate: 0.15,
7836 }
7837 }
7838}
7839
7840#[derive(Debug, Clone, Serialize, Deserialize)]
7842pub struct HierarchySchemaConfig {
7843 #[serde(default = "default_true")]
7845 pub enabled: bool,
7846
7847 #[serde(default = "default_hierarchy_rate")]
7849 pub probability: f64,
7850}
7851
7852fn default_hierarchy_rate() -> f64 {
7853 0.30
7854}
7855
7856impl Default for HierarchySchemaConfig {
7857 fn default() -> Self {
7858 Self {
7859 enabled: true,
7860 probability: 0.30,
7861 }
7862 }
7863}
7864
7865#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7871pub struct RelationshipStrengthSchemaConfig {
7872 #[serde(default)]
7874 pub enabled: bool,
7875
7876 #[serde(default)]
7878 pub calculation: StrengthCalculationSchemaConfig,
7879
7880 #[serde(default)]
7882 pub thresholds: StrengthThresholdsSchemaConfig,
7883}
7884
7885#[derive(Debug, Clone, Serialize, Deserialize)]
7887pub struct StrengthCalculationSchemaConfig {
7888 #[serde(default = "default_volume_weight")]
7890 pub transaction_volume_weight: f64,
7891
7892 #[serde(default = "default_count_weight")]
7894 pub transaction_count_weight: f64,
7895
7896 #[serde(default = "default_duration_weight")]
7898 pub relationship_duration_weight: f64,
7899
7900 #[serde(default = "default_recency_weight")]
7902 pub recency_weight: f64,
7903
7904 #[serde(default = "default_mutual_weight")]
7906 pub mutual_connections_weight: f64,
7907
7908 #[serde(default = "default_recency_half_life")]
7910 pub recency_half_life_days: u32,
7911}
7912
7913fn default_volume_weight() -> f64 {
7914 0.30
7915}
7916
7917fn default_count_weight() -> f64 {
7918 0.25
7919}
7920
7921fn default_duration_weight() -> f64 {
7922 0.20
7923}
7924
7925fn default_recency_weight() -> f64 {
7926 0.15
7927}
7928
7929fn default_mutual_weight() -> f64 {
7930 0.10
7931}
7932
7933fn default_recency_half_life() -> u32 {
7934 90
7935}
7936
7937impl Default for StrengthCalculationSchemaConfig {
7938 fn default() -> Self {
7939 Self {
7940 transaction_volume_weight: 0.30,
7941 transaction_count_weight: 0.25,
7942 relationship_duration_weight: 0.20,
7943 recency_weight: 0.15,
7944 mutual_connections_weight: 0.10,
7945 recency_half_life_days: 90,
7946 }
7947 }
7948}
7949
7950#[derive(Debug, Clone, Serialize, Deserialize)]
7952pub struct StrengthThresholdsSchemaConfig {
7953 #[serde(default = "default_strong_threshold")]
7955 pub strong: f64,
7956
7957 #[serde(default = "default_moderate_threshold")]
7959 pub moderate: f64,
7960
7961 #[serde(default = "default_weak_threshold")]
7963 pub weak: f64,
7964}
7965
7966fn default_strong_threshold() -> f64 {
7967 0.7
7968}
7969
7970fn default_moderate_threshold() -> f64 {
7971 0.4
7972}
7973
7974fn default_weak_threshold() -> f64 {
7975 0.1
7976}
7977
7978impl Default for StrengthThresholdsSchemaConfig {
7979 fn default() -> Self {
7980 Self {
7981 strong: 0.7,
7982 moderate: 0.4,
7983 weak: 0.1,
7984 }
7985 }
7986}
7987
7988#[derive(Debug, Clone, Serialize, Deserialize)]
7994pub struct CrossProcessLinksSchemaConfig {
7995 #[serde(default)]
7997 pub enabled: bool,
7998
7999 #[serde(default = "default_true")]
8001 pub inventory_p2p_o2c: bool,
8002
8003 #[serde(default = "default_true")]
8005 pub payment_bank_reconciliation: bool,
8006
8007 #[serde(default = "default_true")]
8009 pub intercompany_bilateral: bool,
8010
8011 #[serde(default = "default_inventory_link_rate")]
8013 pub inventory_link_rate: f64,
8014}
8015
8016fn default_inventory_link_rate() -> f64 {
8017 0.30
8018}
8019
8020impl Default for CrossProcessLinksSchemaConfig {
8021 fn default() -> Self {
8022 Self {
8023 enabled: false,
8024 inventory_p2p_o2c: true,
8025 payment_bank_reconciliation: true,
8026 intercompany_bilateral: true,
8027 inventory_link_rate: 0.30,
8028 }
8029 }
8030}
8031
8032#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8038pub struct OrganizationalEventsSchemaConfig {
8039 #[serde(default)]
8041 pub enabled: bool,
8042
8043 #[serde(default)]
8045 pub effect_blending: EffectBlendingModeConfig,
8046
8047 #[serde(default)]
8049 pub events: Vec<OrganizationalEventSchemaConfig>,
8050
8051 #[serde(default)]
8053 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
8054
8055 #[serde(default)]
8057 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
8058}
8059
8060#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8062#[serde(rename_all = "snake_case")]
8063pub enum EffectBlendingModeConfig {
8064 #[default]
8066 Multiplicative,
8067 Additive,
8069 Maximum,
8071 Minimum,
8073}
8074
8075#[derive(Debug, Clone, Serialize, Deserialize)]
8077pub struct OrganizationalEventSchemaConfig {
8078 pub id: String,
8080
8081 pub event_type: OrganizationalEventTypeSchemaConfig,
8083
8084 pub effective_date: String,
8086
8087 #[serde(default = "default_org_transition_months")]
8089 pub transition_months: u32,
8090
8091 #[serde(default)]
8093 pub description: Option<String>,
8094}
8095
8096fn default_org_transition_months() -> u32 {
8097 6
8098}
8099
8100#[derive(Debug, Clone, Serialize, Deserialize)]
8102#[serde(tag = "type", rename_all = "snake_case")]
8103pub enum OrganizationalEventTypeSchemaConfig {
8104 Acquisition {
8106 acquired_entity: String,
8108 #[serde(default = "default_acquisition_volume")]
8110 volume_increase: f64,
8111 #[serde(default = "default_acquisition_error")]
8113 integration_error_rate: f64,
8114 #[serde(default = "default_parallel_days")]
8116 parallel_posting_days: u32,
8117 },
8118 Divestiture {
8120 divested_entity: String,
8122 #[serde(default = "default_divestiture_volume")]
8124 volume_reduction: f64,
8125 #[serde(default = "default_true_val")]
8127 remove_entity: bool,
8128 },
8129 Reorganization {
8131 #[serde(default)]
8133 cost_center_remapping: std::collections::HashMap<String, String>,
8134 #[serde(default = "default_reorg_error")]
8136 transition_error_rate: f64,
8137 },
8138 LeadershipChange {
8140 role: String,
8142 #[serde(default)]
8144 policy_changes: Vec<String>,
8145 },
8146 WorkforceReduction {
8148 #[serde(default = "default_workforce_reduction")]
8150 reduction_percent: f64,
8151 #[serde(default = "default_workforce_error")]
8153 error_rate_increase: f64,
8154 },
8155 Merger {
8157 merged_entity: String,
8159 #[serde(default = "default_merger_volume")]
8161 volume_increase: f64,
8162 },
8163}
8164
8165fn default_acquisition_volume() -> f64 {
8166 1.35
8167}
8168
8169fn default_acquisition_error() -> f64 {
8170 0.05
8171}
8172
8173fn default_parallel_days() -> u32 {
8174 30
8175}
8176
8177fn default_divestiture_volume() -> f64 {
8178 0.70
8179}
8180
8181fn default_true_val() -> bool {
8182 true
8183}
8184
8185fn default_reorg_error() -> f64 {
8186 0.04
8187}
8188
8189fn default_workforce_reduction() -> f64 {
8190 0.10
8191}
8192
8193fn default_workforce_error() -> f64 {
8194 0.05
8195}
8196
8197fn default_merger_volume() -> f64 {
8198 1.80
8199}
8200
8201#[derive(Debug, Clone, Serialize, Deserialize)]
8203pub struct ProcessEvolutionSchemaConfig {
8204 pub id: String,
8206
8207 pub event_type: ProcessEvolutionTypeSchemaConfig,
8209
8210 pub effective_date: String,
8212
8213 #[serde(default)]
8215 pub description: Option<String>,
8216}
8217
8218#[derive(Debug, Clone, Serialize, Deserialize)]
8220#[serde(tag = "type", rename_all = "snake_case")]
8221pub enum ProcessEvolutionTypeSchemaConfig {
8222 ProcessAutomation {
8224 process_name: String,
8226 #[serde(default = "default_manual_before")]
8228 manual_rate_before: f64,
8229 #[serde(default = "default_manual_after")]
8231 manual_rate_after: f64,
8232 },
8233 ApprovalWorkflowChange {
8235 description: String,
8237 },
8238 ControlEnhancement {
8240 control_id: String,
8242 #[serde(default = "default_error_reduction")]
8244 error_reduction: f64,
8245 },
8246}
8247
8248fn default_manual_before() -> f64 {
8249 0.80
8250}
8251
8252fn default_manual_after() -> f64 {
8253 0.15
8254}
8255
8256fn default_error_reduction() -> f64 {
8257 0.02
8258}
8259
8260#[derive(Debug, Clone, Serialize, Deserialize)]
8262pub struct TechnologyTransitionSchemaConfig {
8263 pub id: String,
8265
8266 pub event_type: TechnologyTransitionTypeSchemaConfig,
8268
8269 #[serde(default)]
8271 pub description: Option<String>,
8272}
8273
8274#[derive(Debug, Clone, Serialize, Deserialize)]
8276#[serde(tag = "type", rename_all = "snake_case")]
8277pub enum TechnologyTransitionTypeSchemaConfig {
8278 ErpMigration {
8280 source_system: String,
8282 target_system: String,
8284 cutover_date: String,
8286 stabilization_end: String,
8288 #[serde(default = "default_erp_duplicate_rate")]
8290 duplicate_rate: f64,
8291 #[serde(default = "default_format_mismatch")]
8293 format_mismatch_rate: f64,
8294 },
8295 ModuleImplementation {
8297 module_name: String,
8299 go_live_date: String,
8301 },
8302}
8303
8304fn default_erp_duplicate_rate() -> f64 {
8305 0.02
8306}
8307
8308fn default_format_mismatch() -> f64 {
8309 0.03
8310}
8311
8312#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8318pub struct BehavioralDriftSchemaConfig {
8319 #[serde(default)]
8321 pub enabled: bool,
8322
8323 #[serde(default)]
8325 pub vendor_behavior: VendorBehaviorSchemaConfig,
8326
8327 #[serde(default)]
8329 pub customer_behavior: CustomerBehaviorSchemaConfig,
8330
8331 #[serde(default)]
8333 pub employee_behavior: EmployeeBehaviorSchemaConfig,
8334
8335 #[serde(default)]
8337 pub collective: CollectiveBehaviorSchemaConfig,
8338}
8339
8340#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8342pub struct VendorBehaviorSchemaConfig {
8343 #[serde(default)]
8345 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
8346
8347 #[serde(default)]
8349 pub quality_drift: QualityDriftSchemaConfig,
8350}
8351
8352#[derive(Debug, Clone, Serialize, Deserialize)]
8354pub struct PaymentTermsDriftSchemaConfig {
8355 #[serde(default = "default_extension_rate")]
8357 pub extension_rate_per_year: f64,
8358
8359 #[serde(default = "default_economic_sensitivity")]
8361 pub economic_sensitivity: f64,
8362}
8363
8364fn default_extension_rate() -> f64 {
8365 2.5
8366}
8367
8368fn default_economic_sensitivity() -> f64 {
8369 1.0
8370}
8371
8372impl Default for PaymentTermsDriftSchemaConfig {
8373 fn default() -> Self {
8374 Self {
8375 extension_rate_per_year: 2.5,
8376 economic_sensitivity: 1.0,
8377 }
8378 }
8379}
8380
8381#[derive(Debug, Clone, Serialize, Deserialize)]
8383pub struct QualityDriftSchemaConfig {
8384 #[serde(default = "default_improvement_rate")]
8386 pub new_vendor_improvement_rate: f64,
8387
8388 #[serde(default = "default_decline_rate")]
8390 pub complacency_decline_rate: f64,
8391}
8392
8393fn default_improvement_rate() -> f64 {
8394 0.02
8395}
8396
8397fn default_decline_rate() -> f64 {
8398 0.01
8399}
8400
8401impl Default for QualityDriftSchemaConfig {
8402 fn default() -> Self {
8403 Self {
8404 new_vendor_improvement_rate: 0.02,
8405 complacency_decline_rate: 0.01,
8406 }
8407 }
8408}
8409
8410#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8412pub struct CustomerBehaviorSchemaConfig {
8413 #[serde(default)]
8415 pub payment_drift: CustomerPaymentDriftSchemaConfig,
8416
8417 #[serde(default)]
8419 pub order_drift: OrderDriftSchemaConfig,
8420}
8421
8422#[derive(Debug, Clone, Serialize, Deserialize)]
8424pub struct CustomerPaymentDriftSchemaConfig {
8425 #[serde(default = "default_downturn_extension")]
8427 pub downturn_days_extension: (u32, u32),
8428
8429 #[serde(default = "default_bad_debt_increase")]
8431 pub downturn_bad_debt_increase: f64,
8432}
8433
8434fn default_downturn_extension() -> (u32, u32) {
8435 (5, 15)
8436}
8437
8438fn default_bad_debt_increase() -> f64 {
8439 0.02
8440}
8441
8442impl Default for CustomerPaymentDriftSchemaConfig {
8443 fn default() -> Self {
8444 Self {
8445 downturn_days_extension: (5, 15),
8446 downturn_bad_debt_increase: 0.02,
8447 }
8448 }
8449}
8450
8451#[derive(Debug, Clone, Serialize, Deserialize)]
8453pub struct OrderDriftSchemaConfig {
8454 #[serde(default = "default_digital_shift")]
8456 pub digital_shift_rate: f64,
8457}
8458
8459fn default_digital_shift() -> f64 {
8460 0.05
8461}
8462
8463impl Default for OrderDriftSchemaConfig {
8464 fn default() -> Self {
8465 Self {
8466 digital_shift_rate: 0.05,
8467 }
8468 }
8469}
8470
8471#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8473pub struct EmployeeBehaviorSchemaConfig {
8474 #[serde(default)]
8476 pub approval_drift: ApprovalDriftSchemaConfig,
8477
8478 #[serde(default)]
8480 pub error_drift: ErrorDriftSchemaConfig,
8481}
8482
8483#[derive(Debug, Clone, Serialize, Deserialize)]
8485pub struct ApprovalDriftSchemaConfig {
8486 #[serde(default = "default_eom_intensity")]
8488 pub eom_intensity_increase_per_year: f64,
8489
8490 #[serde(default = "default_rubber_stamp")]
8492 pub rubber_stamp_volume_threshold: u32,
8493}
8494
8495fn default_eom_intensity() -> f64 {
8496 0.05
8497}
8498
8499fn default_rubber_stamp() -> u32 {
8500 50
8501}
8502
8503impl Default for ApprovalDriftSchemaConfig {
8504 fn default() -> Self {
8505 Self {
8506 eom_intensity_increase_per_year: 0.05,
8507 rubber_stamp_volume_threshold: 50,
8508 }
8509 }
8510}
8511
8512#[derive(Debug, Clone, Serialize, Deserialize)]
8514pub struct ErrorDriftSchemaConfig {
8515 #[serde(default = "default_new_error")]
8517 pub new_employee_error_rate: f64,
8518
8519 #[serde(default = "default_learning_months")]
8521 pub learning_curve_months: u32,
8522}
8523
8524fn default_new_error() -> f64 {
8525 0.08
8526}
8527
8528fn default_learning_months() -> u32 {
8529 6
8530}
8531
8532impl Default for ErrorDriftSchemaConfig {
8533 fn default() -> Self {
8534 Self {
8535 new_employee_error_rate: 0.08,
8536 learning_curve_months: 6,
8537 }
8538 }
8539}
8540
8541#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8543pub struct CollectiveBehaviorSchemaConfig {
8544 #[serde(default)]
8546 pub automation_adoption: AutomationAdoptionSchemaConfig,
8547}
8548
8549#[derive(Debug, Clone, Serialize, Deserialize)]
8551pub struct AutomationAdoptionSchemaConfig {
8552 #[serde(default)]
8554 pub s_curve_enabled: bool,
8555
8556 #[serde(default = "default_midpoint")]
8558 pub adoption_midpoint_months: u32,
8559
8560 #[serde(default = "default_steepness")]
8562 pub steepness: f64,
8563}
8564
8565fn default_midpoint() -> u32 {
8566 24
8567}
8568
8569fn default_steepness() -> f64 {
8570 0.15
8571}
8572
8573impl Default for AutomationAdoptionSchemaConfig {
8574 fn default() -> Self {
8575 Self {
8576 s_curve_enabled: false,
8577 adoption_midpoint_months: 24,
8578 steepness: 0.15,
8579 }
8580 }
8581}
8582
8583#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8589pub struct MarketDriftSchemaConfig {
8590 #[serde(default)]
8592 pub enabled: bool,
8593
8594 #[serde(default)]
8596 pub economic_cycle: MarketEconomicCycleSchemaConfig,
8597
8598 #[serde(default)]
8600 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8601
8602 #[serde(default)]
8604 pub commodities: CommoditiesSchemaConfig,
8605}
8606
8607#[derive(Debug, Clone, Serialize, Deserialize)]
8609pub struct MarketEconomicCycleSchemaConfig {
8610 #[serde(default)]
8612 pub enabled: bool,
8613
8614 #[serde(default)]
8616 pub cycle_type: CycleTypeSchemaConfig,
8617
8618 #[serde(default = "default_market_cycle_period")]
8620 pub period_months: u32,
8621
8622 #[serde(default = "default_market_amplitude")]
8624 pub amplitude: f64,
8625
8626 #[serde(default)]
8628 pub recession: RecessionSchemaConfig,
8629}
8630
8631fn default_market_cycle_period() -> u32 {
8632 48
8633}
8634
8635fn default_market_amplitude() -> f64 {
8636 0.15
8637}
8638
8639impl Default for MarketEconomicCycleSchemaConfig {
8640 fn default() -> Self {
8641 Self {
8642 enabled: false,
8643 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8644 period_months: 48,
8645 amplitude: 0.15,
8646 recession: RecessionSchemaConfig::default(),
8647 }
8648 }
8649}
8650
8651#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8653#[serde(rename_all = "snake_case")]
8654pub enum CycleTypeSchemaConfig {
8655 #[default]
8657 Sinusoidal,
8658 Asymmetric,
8660 MeanReverting,
8662}
8663
8664#[derive(Debug, Clone, Serialize, Deserialize)]
8666pub struct RecessionSchemaConfig {
8667 #[serde(default)]
8669 pub enabled: bool,
8670
8671 #[serde(default = "default_recession_prob")]
8673 pub probability_per_year: f64,
8674
8675 #[serde(default)]
8677 pub severity: RecessionSeveritySchemaConfig,
8678
8679 #[serde(default)]
8681 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8682}
8683
8684fn default_recession_prob() -> f64 {
8685 0.10
8686}
8687
8688impl Default for RecessionSchemaConfig {
8689 fn default() -> Self {
8690 Self {
8691 enabled: false,
8692 probability_per_year: 0.10,
8693 severity: RecessionSeveritySchemaConfig::Moderate,
8694 recession_periods: Vec::new(),
8695 }
8696 }
8697}
8698
8699#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8701#[serde(rename_all = "snake_case")]
8702pub enum RecessionSeveritySchemaConfig {
8703 Mild,
8705 #[default]
8707 Moderate,
8708 Severe,
8710}
8711
8712#[derive(Debug, Clone, Serialize, Deserialize)]
8714pub struct RecessionPeriodSchemaConfig {
8715 pub start_month: u32,
8717 pub duration_months: u32,
8719}
8720
8721#[derive(Debug, Clone, Serialize, Deserialize)]
8723pub struct IndustryCycleSchemaConfig {
8724 #[serde(default = "default_industry_period")]
8726 pub period_months: u32,
8727
8728 #[serde(default = "default_industry_amp")]
8730 pub amplitude: f64,
8731}
8732
8733fn default_industry_period() -> u32 {
8734 36
8735}
8736
8737fn default_industry_amp() -> f64 {
8738 0.20
8739}
8740
8741#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8743pub struct CommoditiesSchemaConfig {
8744 #[serde(default)]
8746 pub enabled: bool,
8747
8748 #[serde(default)]
8750 pub items: Vec<CommodityItemSchemaConfig>,
8751}
8752
8753#[derive(Debug, Clone, Serialize, Deserialize)]
8755pub struct CommodityItemSchemaConfig {
8756 pub name: String,
8758
8759 #[serde(default = "default_volatility")]
8761 pub volatility: f64,
8762
8763 #[serde(default)]
8765 pub cogs_pass_through: f64,
8766
8767 #[serde(default)]
8769 pub overhead_pass_through: f64,
8770}
8771
8772fn default_volatility() -> f64 {
8773 0.20
8774}
8775
8776#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8782pub struct DriftLabelingSchemaConfig {
8783 #[serde(default)]
8785 pub enabled: bool,
8786
8787 #[serde(default)]
8789 pub statistical: StatisticalDriftLabelingSchemaConfig,
8790
8791 #[serde(default)]
8793 pub categorical: CategoricalDriftLabelingSchemaConfig,
8794
8795 #[serde(default)]
8797 pub temporal: TemporalDriftLabelingSchemaConfig,
8798
8799 #[serde(default)]
8801 pub regulatory_calendar_preset: Option<String>,
8802}
8803
8804#[derive(Debug, Clone, Serialize, Deserialize)]
8806pub struct StatisticalDriftLabelingSchemaConfig {
8807 #[serde(default = "default_true_val")]
8809 pub enabled: bool,
8810
8811 #[serde(default = "default_min_magnitude")]
8813 pub min_magnitude_threshold: f64,
8814}
8815
8816fn default_min_magnitude() -> f64 {
8817 0.05
8818}
8819
8820impl Default for StatisticalDriftLabelingSchemaConfig {
8821 fn default() -> Self {
8822 Self {
8823 enabled: true,
8824 min_magnitude_threshold: 0.05,
8825 }
8826 }
8827}
8828
8829#[derive(Debug, Clone, Serialize, Deserialize)]
8831pub struct CategoricalDriftLabelingSchemaConfig {
8832 #[serde(default = "default_true_val")]
8834 pub enabled: bool,
8835}
8836
8837impl Default for CategoricalDriftLabelingSchemaConfig {
8838 fn default() -> Self {
8839 Self { enabled: true }
8840 }
8841}
8842
8843#[derive(Debug, Clone, Serialize, Deserialize)]
8845pub struct TemporalDriftLabelingSchemaConfig {
8846 #[serde(default = "default_true_val")]
8848 pub enabled: bool,
8849}
8850
8851impl Default for TemporalDriftLabelingSchemaConfig {
8852 fn default() -> Self {
8853 Self { enabled: true }
8854 }
8855}
8856
8857#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8870pub struct EnhancedAnomalyConfig {
8871 #[serde(default)]
8873 pub enabled: bool,
8874
8875 #[serde(default)]
8877 pub rates: AnomalyRateConfig,
8878
8879 #[serde(default)]
8881 pub multi_stage_schemes: MultiStageSchemeConfig,
8882
8883 #[serde(default)]
8885 pub correlated_injection: CorrelatedInjectionConfig,
8886
8887 #[serde(default)]
8889 pub near_miss: NearMissConfig,
8890
8891 #[serde(default)]
8893 pub difficulty_classification: DifficultyClassificationConfig,
8894
8895 #[serde(default)]
8897 pub context_aware: ContextAwareConfig,
8898
8899 #[serde(default)]
8901 pub labeling: EnhancedLabelingConfig,
8902}
8903
8904#[derive(Debug, Clone, Serialize, Deserialize)]
8906pub struct AnomalyRateConfig {
8907 #[serde(default = "default_total_anomaly_rate")]
8909 pub total_rate: f64,
8910
8911 #[serde(default = "default_fraud_anomaly_rate")]
8913 pub fraud_rate: f64,
8914
8915 #[serde(default = "default_error_anomaly_rate")]
8917 pub error_rate: f64,
8918
8919 #[serde(default = "default_process_anomaly_rate")]
8921 pub process_rate: f64,
8922}
8923
8924fn default_total_anomaly_rate() -> f64 {
8925 0.03
8926}
8927fn default_fraud_anomaly_rate() -> f64 {
8928 0.01
8929}
8930fn default_error_anomaly_rate() -> f64 {
8931 0.015
8932}
8933fn default_process_anomaly_rate() -> f64 {
8934 0.005
8935}
8936
8937impl Default for AnomalyRateConfig {
8938 fn default() -> Self {
8939 Self {
8940 total_rate: default_total_anomaly_rate(),
8941 fraud_rate: default_fraud_anomaly_rate(),
8942 error_rate: default_error_anomaly_rate(),
8943 process_rate: default_process_anomaly_rate(),
8944 }
8945 }
8946}
8947
8948#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8950pub struct MultiStageSchemeConfig {
8951 #[serde(default)]
8953 pub enabled: bool,
8954
8955 #[serde(default)]
8957 pub embezzlement: EmbezzlementSchemeConfig,
8958
8959 #[serde(default)]
8961 pub revenue_manipulation: RevenueManipulationSchemeConfig,
8962
8963 #[serde(default)]
8965 pub kickback: KickbackSchemeConfig,
8966}
8967
8968#[derive(Debug, Clone, Serialize, Deserialize)]
8970pub struct EmbezzlementSchemeConfig {
8971 #[serde(default = "default_embezzlement_probability")]
8973 pub probability: f64,
8974
8975 #[serde(default)]
8977 pub testing_stage: SchemeStageConfig,
8978
8979 #[serde(default)]
8981 pub escalation_stage: SchemeStageConfig,
8982
8983 #[serde(default)]
8985 pub acceleration_stage: SchemeStageConfig,
8986
8987 #[serde(default)]
8989 pub desperation_stage: SchemeStageConfig,
8990}
8991
8992fn default_embezzlement_probability() -> f64 {
8993 0.02
8994}
8995
8996impl Default for EmbezzlementSchemeConfig {
8997 fn default() -> Self {
8998 Self {
8999 probability: default_embezzlement_probability(),
9000 testing_stage: SchemeStageConfig {
9001 duration_months: 2,
9002 amount_min: 100.0,
9003 amount_max: 500.0,
9004 transaction_count_min: 2,
9005 transaction_count_max: 5,
9006 difficulty: "hard".to_string(),
9007 },
9008 escalation_stage: SchemeStageConfig {
9009 duration_months: 6,
9010 amount_min: 500.0,
9011 amount_max: 2000.0,
9012 transaction_count_min: 3,
9013 transaction_count_max: 8,
9014 difficulty: "moderate".to_string(),
9015 },
9016 acceleration_stage: SchemeStageConfig {
9017 duration_months: 3,
9018 amount_min: 2000.0,
9019 amount_max: 10000.0,
9020 transaction_count_min: 5,
9021 transaction_count_max: 12,
9022 difficulty: "easy".to_string(),
9023 },
9024 desperation_stage: SchemeStageConfig {
9025 duration_months: 1,
9026 amount_min: 10000.0,
9027 amount_max: 50000.0,
9028 transaction_count_min: 3,
9029 transaction_count_max: 6,
9030 difficulty: "trivial".to_string(),
9031 },
9032 }
9033 }
9034}
9035
9036#[derive(Debug, Clone, Serialize, Deserialize)]
9038pub struct RevenueManipulationSchemeConfig {
9039 #[serde(default = "default_revenue_manipulation_probability")]
9041 pub probability: f64,
9042
9043 #[serde(default = "default_early_recognition_target")]
9045 pub early_recognition_target: f64,
9046
9047 #[serde(default = "default_expense_deferral_target")]
9049 pub expense_deferral_target: f64,
9050
9051 #[serde(default = "default_reserve_release_target")]
9053 pub reserve_release_target: f64,
9054
9055 #[serde(default = "default_channel_stuffing_target")]
9057 pub channel_stuffing_target: f64,
9058}
9059
9060fn default_revenue_manipulation_probability() -> f64 {
9061 0.01
9062}
9063fn default_early_recognition_target() -> f64 {
9064 0.02
9065}
9066fn default_expense_deferral_target() -> f64 {
9067 0.03
9068}
9069fn default_reserve_release_target() -> f64 {
9070 0.02
9071}
9072fn default_channel_stuffing_target() -> f64 {
9073 0.05
9074}
9075
9076impl Default for RevenueManipulationSchemeConfig {
9077 fn default() -> Self {
9078 Self {
9079 probability: default_revenue_manipulation_probability(),
9080 early_recognition_target: default_early_recognition_target(),
9081 expense_deferral_target: default_expense_deferral_target(),
9082 reserve_release_target: default_reserve_release_target(),
9083 channel_stuffing_target: default_channel_stuffing_target(),
9084 }
9085 }
9086}
9087
9088#[derive(Debug, Clone, Serialize, Deserialize)]
9090pub struct KickbackSchemeConfig {
9091 #[serde(default = "default_kickback_probability")]
9093 pub probability: f64,
9094
9095 #[serde(default = "default_kickback_inflation_min")]
9097 pub inflation_min: f64,
9098
9099 #[serde(default = "default_kickback_inflation_max")]
9101 pub inflation_max: f64,
9102
9103 #[serde(default = "default_kickback_percent")]
9105 pub kickback_percent: f64,
9106
9107 #[serde(default = "default_kickback_setup_months")]
9109 pub setup_months: u32,
9110
9111 #[serde(default = "default_kickback_operation_months")]
9113 pub operation_months: u32,
9114}
9115
9116fn default_kickback_probability() -> f64 {
9117 0.01
9118}
9119fn default_kickback_inflation_min() -> f64 {
9120 0.10
9121}
9122fn default_kickback_inflation_max() -> f64 {
9123 0.25
9124}
9125fn default_kickback_percent() -> f64 {
9126 0.50
9127}
9128fn default_kickback_setup_months() -> u32 {
9129 3
9130}
9131fn default_kickback_operation_months() -> u32 {
9132 12
9133}
9134
9135impl Default for KickbackSchemeConfig {
9136 fn default() -> Self {
9137 Self {
9138 probability: default_kickback_probability(),
9139 inflation_min: default_kickback_inflation_min(),
9140 inflation_max: default_kickback_inflation_max(),
9141 kickback_percent: default_kickback_percent(),
9142 setup_months: default_kickback_setup_months(),
9143 operation_months: default_kickback_operation_months(),
9144 }
9145 }
9146}
9147
9148#[derive(Debug, Clone, Serialize, Deserialize)]
9150pub struct SchemeStageConfig {
9151 pub duration_months: u32,
9153
9154 pub amount_min: f64,
9156
9157 pub amount_max: f64,
9159
9160 pub transaction_count_min: u32,
9162
9163 pub transaction_count_max: u32,
9165
9166 pub difficulty: String,
9168}
9169
9170impl Default for SchemeStageConfig {
9171 fn default() -> Self {
9172 Self {
9173 duration_months: 3,
9174 amount_min: 100.0,
9175 amount_max: 1000.0,
9176 transaction_count_min: 2,
9177 transaction_count_max: 10,
9178 difficulty: "moderate".to_string(),
9179 }
9180 }
9181}
9182
9183#[derive(Debug, Clone, Serialize, Deserialize)]
9185pub struct CorrelatedInjectionConfig {
9186 #[serde(default)]
9188 pub enabled: bool,
9189
9190 #[serde(default = "default_true_val")]
9192 pub fraud_concealment: bool,
9193
9194 #[serde(default = "default_true_val")]
9196 pub error_cascade: bool,
9197
9198 #[serde(default = "default_true_val")]
9200 pub temporal_clustering: bool,
9201
9202 #[serde(default)]
9204 pub temporal_clustering_config: TemporalClusteringConfig,
9205
9206 #[serde(default)]
9208 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
9209}
9210
9211impl Default for CorrelatedInjectionConfig {
9212 fn default() -> Self {
9213 Self {
9214 enabled: false,
9215 fraud_concealment: true,
9216 error_cascade: true,
9217 temporal_clustering: true,
9218 temporal_clustering_config: TemporalClusteringConfig::default(),
9219 co_occurrence_patterns: Vec::new(),
9220 }
9221 }
9222}
9223
9224#[derive(Debug, Clone, Serialize, Deserialize)]
9226pub struct TemporalClusteringConfig {
9227 #[serde(default = "default_period_end_multiplier")]
9229 pub period_end_multiplier: f64,
9230
9231 #[serde(default = "default_period_end_days")]
9233 pub period_end_days: u32,
9234
9235 #[serde(default = "default_quarter_end_multiplier")]
9237 pub quarter_end_multiplier: f64,
9238
9239 #[serde(default = "default_year_end_multiplier")]
9241 pub year_end_multiplier: f64,
9242}
9243
9244fn default_period_end_multiplier() -> f64 {
9245 2.5
9246}
9247fn default_period_end_days() -> u32 {
9248 5
9249}
9250fn default_quarter_end_multiplier() -> f64 {
9251 1.5
9252}
9253fn default_year_end_multiplier() -> f64 {
9254 2.0
9255}
9256
9257impl Default for TemporalClusteringConfig {
9258 fn default() -> Self {
9259 Self {
9260 period_end_multiplier: default_period_end_multiplier(),
9261 period_end_days: default_period_end_days(),
9262 quarter_end_multiplier: default_quarter_end_multiplier(),
9263 year_end_multiplier: default_year_end_multiplier(),
9264 }
9265 }
9266}
9267
9268#[derive(Debug, Clone, Serialize, Deserialize)]
9270pub struct CoOccurrencePatternConfig {
9271 pub name: String,
9273
9274 pub primary_type: String,
9276
9277 pub correlated: Vec<CorrelatedAnomalyConfig>,
9279}
9280
9281#[derive(Debug, Clone, Serialize, Deserialize)]
9283pub struct CorrelatedAnomalyConfig {
9284 pub anomaly_type: String,
9286
9287 pub probability: f64,
9289
9290 pub lag_days_min: i32,
9292
9293 pub lag_days_max: i32,
9295}
9296
9297#[derive(Debug, Clone, Serialize, Deserialize)]
9299pub struct NearMissConfig {
9300 #[serde(default)]
9302 pub enabled: bool,
9303
9304 #[serde(default = "default_near_miss_proportion")]
9306 pub proportion: f64,
9307
9308 #[serde(default = "default_true_val")]
9310 pub near_duplicate: bool,
9311
9312 #[serde(default)]
9314 pub near_duplicate_days: NearDuplicateDaysConfig,
9315
9316 #[serde(default = "default_true_val")]
9318 pub threshold_proximity: bool,
9319
9320 #[serde(default)]
9322 pub threshold_proximity_range: ThresholdProximityRangeConfig,
9323
9324 #[serde(default = "default_true_val")]
9326 pub unusual_legitimate: bool,
9327
9328 #[serde(default = "default_unusual_legitimate_types")]
9330 pub unusual_legitimate_types: Vec<String>,
9331
9332 #[serde(default = "default_true_val")]
9334 pub corrected_errors: bool,
9335
9336 #[serde(default)]
9338 pub corrected_error_lag: CorrectedErrorLagConfig,
9339}
9340
9341fn default_near_miss_proportion() -> f64 {
9342 0.30
9343}
9344
9345fn default_unusual_legitimate_types() -> Vec<String> {
9346 vec![
9347 "year_end_bonus".to_string(),
9348 "contract_prepayment".to_string(),
9349 "insurance_claim".to_string(),
9350 "settlement_payment".to_string(),
9351 ]
9352}
9353
9354impl Default for NearMissConfig {
9355 fn default() -> Self {
9356 Self {
9357 enabled: false,
9358 proportion: default_near_miss_proportion(),
9359 near_duplicate: true,
9360 near_duplicate_days: NearDuplicateDaysConfig::default(),
9361 threshold_proximity: true,
9362 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
9363 unusual_legitimate: true,
9364 unusual_legitimate_types: default_unusual_legitimate_types(),
9365 corrected_errors: true,
9366 corrected_error_lag: CorrectedErrorLagConfig::default(),
9367 }
9368 }
9369}
9370
9371#[derive(Debug, Clone, Serialize, Deserialize)]
9373pub struct NearDuplicateDaysConfig {
9374 #[serde(default = "default_near_duplicate_min")]
9376 pub min: u32,
9377
9378 #[serde(default = "default_near_duplicate_max")]
9380 pub max: u32,
9381}
9382
9383fn default_near_duplicate_min() -> u32 {
9384 1
9385}
9386fn default_near_duplicate_max() -> u32 {
9387 3
9388}
9389
9390impl Default for NearDuplicateDaysConfig {
9391 fn default() -> Self {
9392 Self {
9393 min: default_near_duplicate_min(),
9394 max: default_near_duplicate_max(),
9395 }
9396 }
9397}
9398
9399#[derive(Debug, Clone, Serialize, Deserialize)]
9401pub struct ThresholdProximityRangeConfig {
9402 #[serde(default = "default_threshold_proximity_min")]
9404 pub min: f64,
9405
9406 #[serde(default = "default_threshold_proximity_max")]
9408 pub max: f64,
9409}
9410
9411fn default_threshold_proximity_min() -> f64 {
9412 0.90
9413}
9414fn default_threshold_proximity_max() -> f64 {
9415 0.99
9416}
9417
9418impl Default for ThresholdProximityRangeConfig {
9419 fn default() -> Self {
9420 Self {
9421 min: default_threshold_proximity_min(),
9422 max: default_threshold_proximity_max(),
9423 }
9424 }
9425}
9426
9427#[derive(Debug, Clone, Serialize, Deserialize)]
9429pub struct CorrectedErrorLagConfig {
9430 #[serde(default = "default_corrected_error_lag_min")]
9432 pub min: u32,
9433
9434 #[serde(default = "default_corrected_error_lag_max")]
9436 pub max: u32,
9437}
9438
9439fn default_corrected_error_lag_min() -> u32 {
9440 1
9441}
9442fn default_corrected_error_lag_max() -> u32 {
9443 5
9444}
9445
9446impl Default for CorrectedErrorLagConfig {
9447 fn default() -> Self {
9448 Self {
9449 min: default_corrected_error_lag_min(),
9450 max: default_corrected_error_lag_max(),
9451 }
9452 }
9453}
9454
9455#[derive(Debug, Clone, Serialize, Deserialize)]
9457pub struct DifficultyClassificationConfig {
9458 #[serde(default)]
9460 pub enabled: bool,
9461
9462 #[serde(default)]
9464 pub target_distribution: DifficultyDistributionConfig,
9465}
9466
9467impl Default for DifficultyClassificationConfig {
9468 fn default() -> Self {
9469 Self {
9470 enabled: true,
9471 target_distribution: DifficultyDistributionConfig::default(),
9472 }
9473 }
9474}
9475
9476#[derive(Debug, Clone, Serialize, Deserialize)]
9478pub struct DifficultyDistributionConfig {
9479 #[serde(default = "default_difficulty_trivial")]
9481 pub trivial: f64,
9482
9483 #[serde(default = "default_difficulty_easy")]
9485 pub easy: f64,
9486
9487 #[serde(default = "default_difficulty_moderate")]
9489 pub moderate: f64,
9490
9491 #[serde(default = "default_difficulty_hard")]
9493 pub hard: f64,
9494
9495 #[serde(default = "default_difficulty_expert")]
9497 pub expert: f64,
9498}
9499
9500fn default_difficulty_trivial() -> f64 {
9501 0.15
9502}
9503fn default_difficulty_easy() -> f64 {
9504 0.25
9505}
9506fn default_difficulty_moderate() -> f64 {
9507 0.30
9508}
9509fn default_difficulty_hard() -> f64 {
9510 0.20
9511}
9512fn default_difficulty_expert() -> f64 {
9513 0.10
9514}
9515
9516impl Default for DifficultyDistributionConfig {
9517 fn default() -> Self {
9518 Self {
9519 trivial: default_difficulty_trivial(),
9520 easy: default_difficulty_easy(),
9521 moderate: default_difficulty_moderate(),
9522 hard: default_difficulty_hard(),
9523 expert: default_difficulty_expert(),
9524 }
9525 }
9526}
9527
9528#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9530pub struct ContextAwareConfig {
9531 #[serde(default)]
9533 pub enabled: bool,
9534
9535 #[serde(default)]
9537 pub vendor_rules: VendorAnomalyRulesConfig,
9538
9539 #[serde(default)]
9541 pub employee_rules: EmployeeAnomalyRulesConfig,
9542
9543 #[serde(default)]
9545 pub account_rules: AccountAnomalyRulesConfig,
9546
9547 #[serde(default)]
9549 pub behavioral_baseline: BehavioralBaselineConfig,
9550}
9551
9552#[derive(Debug, Clone, Serialize, Deserialize)]
9554pub struct VendorAnomalyRulesConfig {
9555 #[serde(default = "default_new_vendor_multiplier")]
9557 pub new_vendor_error_multiplier: f64,
9558
9559 #[serde(default = "default_new_vendor_threshold")]
9561 pub new_vendor_threshold_days: u32,
9562
9563 #[serde(default = "default_international_multiplier")]
9565 pub international_error_multiplier: f64,
9566
9567 #[serde(default = "default_strategic_vendor_types")]
9569 pub strategic_vendor_anomaly_types: Vec<String>,
9570}
9571
9572fn default_new_vendor_multiplier() -> f64 {
9573 2.5
9574}
9575fn default_new_vendor_threshold() -> u32 {
9576 90
9577}
9578fn default_international_multiplier() -> f64 {
9579 1.5
9580}
9581fn default_strategic_vendor_types() -> Vec<String> {
9582 vec![
9583 "pricing_dispute".to_string(),
9584 "contract_violation".to_string(),
9585 ]
9586}
9587
9588impl Default for VendorAnomalyRulesConfig {
9589 fn default() -> Self {
9590 Self {
9591 new_vendor_error_multiplier: default_new_vendor_multiplier(),
9592 new_vendor_threshold_days: default_new_vendor_threshold(),
9593 international_error_multiplier: default_international_multiplier(),
9594 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9595 }
9596 }
9597}
9598
9599#[derive(Debug, Clone, Serialize, Deserialize)]
9601pub struct EmployeeAnomalyRulesConfig {
9602 #[serde(default = "default_new_employee_rate")]
9604 pub new_employee_error_rate: f64,
9605
9606 #[serde(default = "default_new_employee_threshold")]
9608 pub new_employee_threshold_days: u32,
9609
9610 #[serde(default = "default_volume_fatigue_threshold")]
9612 pub volume_fatigue_threshold: u32,
9613
9614 #[serde(default = "default_coverage_multiplier")]
9616 pub coverage_error_multiplier: f64,
9617}
9618
9619fn default_new_employee_rate() -> f64 {
9620 0.05
9621}
9622fn default_new_employee_threshold() -> u32 {
9623 180
9624}
9625fn default_volume_fatigue_threshold() -> u32 {
9626 50
9627}
9628fn default_coverage_multiplier() -> f64 {
9629 1.8
9630}
9631
9632impl Default for EmployeeAnomalyRulesConfig {
9633 fn default() -> Self {
9634 Self {
9635 new_employee_error_rate: default_new_employee_rate(),
9636 new_employee_threshold_days: default_new_employee_threshold(),
9637 volume_fatigue_threshold: default_volume_fatigue_threshold(),
9638 coverage_error_multiplier: default_coverage_multiplier(),
9639 }
9640 }
9641}
9642
9643#[derive(Debug, Clone, Serialize, Deserialize)]
9645pub struct AccountAnomalyRulesConfig {
9646 #[serde(default = "default_high_risk_multiplier")]
9648 pub high_risk_account_multiplier: f64,
9649
9650 #[serde(default = "default_high_risk_accounts")]
9652 pub high_risk_accounts: Vec<String>,
9653
9654 #[serde(default = "default_suspense_multiplier")]
9656 pub suspense_account_multiplier: f64,
9657
9658 #[serde(default = "default_suspense_accounts")]
9660 pub suspense_accounts: Vec<String>,
9661
9662 #[serde(default = "default_intercompany_multiplier")]
9664 pub intercompany_account_multiplier: f64,
9665}
9666
9667fn default_high_risk_multiplier() -> f64 {
9668 2.0
9669}
9670fn default_high_risk_accounts() -> Vec<String> {
9671 vec![
9672 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
9676}
9677fn default_suspense_multiplier() -> f64 {
9678 3.0
9679}
9680fn default_suspense_accounts() -> Vec<String> {
9681 vec!["9999".to_string(), "9998".to_string()]
9682}
9683fn default_intercompany_multiplier() -> f64 {
9684 1.5
9685}
9686
9687impl Default for AccountAnomalyRulesConfig {
9688 fn default() -> Self {
9689 Self {
9690 high_risk_account_multiplier: default_high_risk_multiplier(),
9691 high_risk_accounts: default_high_risk_accounts(),
9692 suspense_account_multiplier: default_suspense_multiplier(),
9693 suspense_accounts: default_suspense_accounts(),
9694 intercompany_account_multiplier: default_intercompany_multiplier(),
9695 }
9696 }
9697}
9698
9699#[derive(Debug, Clone, Serialize, Deserialize)]
9701pub struct BehavioralBaselineConfig {
9702 #[serde(default)]
9704 pub enabled: bool,
9705
9706 #[serde(default = "default_baseline_period")]
9708 pub baseline_period_days: u32,
9709
9710 #[serde(default = "default_deviation_threshold")]
9712 pub deviation_threshold_std: f64,
9713
9714 #[serde(default = "default_frequency_deviation")]
9716 pub frequency_deviation_threshold: f64,
9717}
9718
9719fn default_baseline_period() -> u32 {
9720 90
9721}
9722fn default_deviation_threshold() -> f64 {
9723 3.0
9724}
9725fn default_frequency_deviation() -> f64 {
9726 2.0
9727}
9728
9729impl Default for BehavioralBaselineConfig {
9730 fn default() -> Self {
9731 Self {
9732 enabled: false,
9733 baseline_period_days: default_baseline_period(),
9734 deviation_threshold_std: default_deviation_threshold(),
9735 frequency_deviation_threshold: default_frequency_deviation(),
9736 }
9737 }
9738}
9739
9740#[derive(Debug, Clone, Serialize, Deserialize)]
9742pub struct EnhancedLabelingConfig {
9743 #[serde(default = "default_true_val")]
9745 pub severity_scoring: bool,
9746
9747 #[serde(default = "default_true_val")]
9749 pub difficulty_classification: bool,
9750
9751 #[serde(default)]
9753 pub materiality_thresholds: MaterialityThresholdsConfig,
9754}
9755
9756impl Default for EnhancedLabelingConfig {
9757 fn default() -> Self {
9758 Self {
9759 severity_scoring: true,
9760 difficulty_classification: true,
9761 materiality_thresholds: MaterialityThresholdsConfig::default(),
9762 }
9763 }
9764}
9765
9766#[derive(Debug, Clone, Serialize, Deserialize)]
9768pub struct MaterialityThresholdsConfig {
9769 #[serde(default = "default_materiality_trivial")]
9771 pub trivial: f64,
9772
9773 #[serde(default = "default_materiality_immaterial")]
9775 pub immaterial: f64,
9776
9777 #[serde(default = "default_materiality_material")]
9779 pub material: f64,
9780
9781 #[serde(default = "default_materiality_highly_material")]
9783 pub highly_material: f64,
9784}
9785
9786fn default_materiality_trivial() -> f64 {
9787 0.001
9788}
9789fn default_materiality_immaterial() -> f64 {
9790 0.01
9791}
9792fn default_materiality_material() -> f64 {
9793 0.05
9794}
9795fn default_materiality_highly_material() -> f64 {
9796 0.10
9797}
9798
9799impl Default for MaterialityThresholdsConfig {
9800 fn default() -> Self {
9801 Self {
9802 trivial: default_materiality_trivial(),
9803 immaterial: default_materiality_immaterial(),
9804 material: default_materiality_material(),
9805 highly_material: default_materiality_highly_material(),
9806 }
9807 }
9808}
9809
9810#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9822pub struct IndustrySpecificConfig {
9823 #[serde(default)]
9825 pub enabled: bool,
9826
9827 #[serde(default)]
9829 pub manufacturing: ManufacturingConfig,
9830
9831 #[serde(default)]
9833 pub retail: RetailConfig,
9834
9835 #[serde(default)]
9837 pub healthcare: HealthcareConfig,
9838
9839 #[serde(default)]
9841 pub technology: TechnologyConfig,
9842
9843 #[serde(default)]
9845 pub financial_services: FinancialServicesConfig,
9846
9847 #[serde(default)]
9849 pub professional_services: ProfessionalServicesConfig,
9850}
9851
9852#[derive(Debug, Clone, Serialize, Deserialize)]
9854pub struct ManufacturingConfig {
9855 #[serde(default)]
9857 pub enabled: bool,
9858
9859 #[serde(default = "default_bom_depth")]
9861 pub bom_depth: u32,
9862
9863 #[serde(default)]
9865 pub just_in_time: bool,
9866
9867 #[serde(default = "default_production_order_types")]
9869 pub production_order_types: Vec<String>,
9870
9871 #[serde(default)]
9873 pub quality_framework: Option<String>,
9874
9875 #[serde(default = "default_supplier_tiers")]
9877 pub supplier_tiers: u32,
9878
9879 #[serde(default = "default_cost_frequency")]
9881 pub standard_cost_frequency: String,
9882
9883 #[serde(default = "default_yield_rate")]
9885 pub target_yield_rate: f64,
9886
9887 #[serde(default = "default_scrap_threshold")]
9889 pub scrap_alert_threshold: f64,
9890
9891 #[serde(default)]
9893 pub anomaly_rates: ManufacturingAnomalyRates,
9894
9895 #[serde(default)]
9897 pub cost_accounting: ManufacturingCostAccountingConfig,
9898}
9899
9900#[derive(Debug, Clone, Serialize, Deserialize)]
9902pub struct ManufacturingCostAccountingConfig {
9903 #[serde(default = "default_true")]
9905 pub enabled: bool,
9906
9907 #[serde(default = "default_true")]
9909 pub variance_accounts_enabled: bool,
9910
9911 #[serde(default = "default_true")]
9913 pub warranty_provisions_enabled: bool,
9914
9915 #[serde(default = "default_warranty_defect_threshold")]
9917 pub warranty_defect_threshold: f64,
9918}
9919
9920fn default_warranty_defect_threshold() -> f64 {
9921 0.01
9922}
9923
9924impl Default for ManufacturingCostAccountingConfig {
9925 fn default() -> Self {
9926 Self {
9927 enabled: true,
9928 variance_accounts_enabled: true,
9929 warranty_provisions_enabled: true,
9930 warranty_defect_threshold: 0.01,
9931 }
9932 }
9933}
9934
9935fn default_bom_depth() -> u32 {
9936 4
9937}
9938
9939fn default_production_order_types() -> Vec<String> {
9940 vec![
9941 "standard".to_string(),
9942 "rework".to_string(),
9943 "prototype".to_string(),
9944 ]
9945}
9946
9947fn default_supplier_tiers() -> u32 {
9948 2
9949}
9950
9951fn default_cost_frequency() -> String {
9952 "quarterly".to_string()
9953}
9954
9955fn default_yield_rate() -> f64 {
9956 0.97
9957}
9958
9959fn default_scrap_threshold() -> f64 {
9960 0.03
9961}
9962
9963impl Default for ManufacturingConfig {
9964 fn default() -> Self {
9965 Self {
9966 enabled: false,
9967 bom_depth: default_bom_depth(),
9968 just_in_time: false,
9969 production_order_types: default_production_order_types(),
9970 quality_framework: Some("ISO_9001".to_string()),
9971 supplier_tiers: default_supplier_tiers(),
9972 standard_cost_frequency: default_cost_frequency(),
9973 target_yield_rate: default_yield_rate(),
9974 scrap_alert_threshold: default_scrap_threshold(),
9975 anomaly_rates: ManufacturingAnomalyRates::default(),
9976 cost_accounting: ManufacturingCostAccountingConfig::default(),
9977 }
9978 }
9979}
9980
9981#[derive(Debug, Clone, Serialize, Deserialize)]
9983pub struct ManufacturingAnomalyRates {
9984 #[serde(default = "default_mfg_yield_rate")]
9986 pub yield_manipulation: f64,
9987
9988 #[serde(default = "default_mfg_labor_rate")]
9990 pub labor_misallocation: f64,
9991
9992 #[serde(default = "default_mfg_phantom_rate")]
9994 pub phantom_production: f64,
9995
9996 #[serde(default = "default_mfg_cost_rate")]
9998 pub standard_cost_manipulation: f64,
9999
10000 #[serde(default = "default_mfg_inventory_rate")]
10002 pub inventory_fraud: f64,
10003}
10004
10005fn default_mfg_yield_rate() -> f64 {
10006 0.015
10007}
10008
10009fn default_mfg_labor_rate() -> f64 {
10010 0.02
10011}
10012
10013fn default_mfg_phantom_rate() -> f64 {
10014 0.005
10015}
10016
10017fn default_mfg_cost_rate() -> f64 {
10018 0.01
10019}
10020
10021fn default_mfg_inventory_rate() -> f64 {
10022 0.008
10023}
10024
10025impl Default for ManufacturingAnomalyRates {
10026 fn default() -> Self {
10027 Self {
10028 yield_manipulation: default_mfg_yield_rate(),
10029 labor_misallocation: default_mfg_labor_rate(),
10030 phantom_production: default_mfg_phantom_rate(),
10031 standard_cost_manipulation: default_mfg_cost_rate(),
10032 inventory_fraud: default_mfg_inventory_rate(),
10033 }
10034 }
10035}
10036
10037#[derive(Debug, Clone, Serialize, Deserialize)]
10039pub struct RetailConfig {
10040 #[serde(default)]
10042 pub enabled: bool,
10043
10044 #[serde(default)]
10046 pub store_types: RetailStoreTypeConfig,
10047
10048 #[serde(default = "default_retail_daily_txns")]
10050 pub avg_daily_transactions: u32,
10051
10052 #[serde(default = "default_true")]
10054 pub loss_prevention: bool,
10055
10056 #[serde(default = "default_shrinkage_rate")]
10058 pub shrinkage_rate: f64,
10059
10060 #[serde(default)]
10062 pub anomaly_rates: RetailAnomalyRates,
10063}
10064
10065fn default_retail_daily_txns() -> u32 {
10066 500
10067}
10068
10069fn default_shrinkage_rate() -> f64 {
10070 0.015
10071}
10072
10073impl Default for RetailConfig {
10074 fn default() -> Self {
10075 Self {
10076 enabled: false,
10077 store_types: RetailStoreTypeConfig::default(),
10078 avg_daily_transactions: default_retail_daily_txns(),
10079 loss_prevention: true,
10080 shrinkage_rate: default_shrinkage_rate(),
10081 anomaly_rates: RetailAnomalyRates::default(),
10082 }
10083 }
10084}
10085
10086#[derive(Debug, Clone, Serialize, Deserialize)]
10088pub struct RetailStoreTypeConfig {
10089 #[serde(default = "default_flagship_pct")]
10091 pub flagship: f64,
10092
10093 #[serde(default = "default_regional_pct")]
10095 pub regional: f64,
10096
10097 #[serde(default = "default_outlet_pct")]
10099 pub outlet: f64,
10100
10101 #[serde(default = "default_ecommerce_pct")]
10103 pub ecommerce: f64,
10104}
10105
10106fn default_flagship_pct() -> f64 {
10107 0.10
10108}
10109
10110fn default_regional_pct() -> f64 {
10111 0.50
10112}
10113
10114fn default_outlet_pct() -> f64 {
10115 0.25
10116}
10117
10118fn default_ecommerce_pct() -> f64 {
10119 0.15
10120}
10121
10122impl Default for RetailStoreTypeConfig {
10123 fn default() -> Self {
10124 Self {
10125 flagship: default_flagship_pct(),
10126 regional: default_regional_pct(),
10127 outlet: default_outlet_pct(),
10128 ecommerce: default_ecommerce_pct(),
10129 }
10130 }
10131}
10132
10133#[derive(Debug, Clone, Serialize, Deserialize)]
10135pub struct RetailAnomalyRates {
10136 #[serde(default = "default_sweethearting_rate")]
10138 pub sweethearting: f64,
10139
10140 #[serde(default = "default_skimming_rate")]
10142 pub skimming: f64,
10143
10144 #[serde(default = "default_refund_fraud_rate")]
10146 pub refund_fraud: f64,
10147
10148 #[serde(default = "default_void_abuse_rate")]
10150 pub void_abuse: f64,
10151
10152 #[serde(default = "default_gift_card_rate")]
10154 pub gift_card_fraud: f64,
10155
10156 #[serde(default = "default_retail_kickback_rate")]
10158 pub vendor_kickback: f64,
10159}
10160
10161fn default_sweethearting_rate() -> f64 {
10162 0.02
10163}
10164
10165fn default_skimming_rate() -> f64 {
10166 0.005
10167}
10168
10169fn default_refund_fraud_rate() -> f64 {
10170 0.015
10171}
10172
10173fn default_void_abuse_rate() -> f64 {
10174 0.01
10175}
10176
10177fn default_gift_card_rate() -> f64 {
10178 0.008
10179}
10180
10181fn default_retail_kickback_rate() -> f64 {
10182 0.003
10183}
10184
10185impl Default for RetailAnomalyRates {
10186 fn default() -> Self {
10187 Self {
10188 sweethearting: default_sweethearting_rate(),
10189 skimming: default_skimming_rate(),
10190 refund_fraud: default_refund_fraud_rate(),
10191 void_abuse: default_void_abuse_rate(),
10192 gift_card_fraud: default_gift_card_rate(),
10193 vendor_kickback: default_retail_kickback_rate(),
10194 }
10195 }
10196}
10197
10198#[derive(Debug, Clone, Serialize, Deserialize)]
10200pub struct HealthcareConfig {
10201 #[serde(default)]
10203 pub enabled: bool,
10204
10205 #[serde(default = "default_facility_type")]
10207 pub facility_type: String,
10208
10209 #[serde(default)]
10211 pub payer_mix: HealthcarePayerMix,
10212
10213 #[serde(default)]
10215 pub coding_systems: HealthcareCodingSystems,
10216
10217 #[serde(default)]
10219 pub compliance: HealthcareComplianceConfig,
10220
10221 #[serde(default = "default_daily_encounters")]
10223 pub avg_daily_encounters: u32,
10224
10225 #[serde(default = "default_charges_per_encounter")]
10227 pub avg_charges_per_encounter: u32,
10228
10229 #[serde(default = "default_hc_denial_rate")]
10231 pub denial_rate: f64,
10232
10233 #[serde(default = "default_hc_bad_debt_rate")]
10235 pub bad_debt_rate: f64,
10236
10237 #[serde(default = "default_hc_charity_care_rate")]
10239 pub charity_care_rate: f64,
10240
10241 #[serde(default)]
10243 pub anomaly_rates: HealthcareAnomalyRates,
10244}
10245
10246fn default_facility_type() -> String {
10247 "hospital".to_string()
10248}
10249
10250fn default_daily_encounters() -> u32 {
10251 150
10252}
10253
10254fn default_charges_per_encounter() -> u32 {
10255 8
10256}
10257
10258fn default_hc_denial_rate() -> f64 {
10259 0.05
10260}
10261
10262fn default_hc_bad_debt_rate() -> f64 {
10263 0.03
10264}
10265
10266fn default_hc_charity_care_rate() -> f64 {
10267 0.02
10268}
10269
10270impl Default for HealthcareConfig {
10271 fn default() -> Self {
10272 Self {
10273 enabled: false,
10274 facility_type: default_facility_type(),
10275 payer_mix: HealthcarePayerMix::default(),
10276 coding_systems: HealthcareCodingSystems::default(),
10277 compliance: HealthcareComplianceConfig::default(),
10278 avg_daily_encounters: default_daily_encounters(),
10279 avg_charges_per_encounter: default_charges_per_encounter(),
10280 denial_rate: default_hc_denial_rate(),
10281 bad_debt_rate: default_hc_bad_debt_rate(),
10282 charity_care_rate: default_hc_charity_care_rate(),
10283 anomaly_rates: HealthcareAnomalyRates::default(),
10284 }
10285 }
10286}
10287
10288#[derive(Debug, Clone, Serialize, Deserialize)]
10290pub struct HealthcarePayerMix {
10291 #[serde(default = "default_medicare_pct")]
10293 pub medicare: f64,
10294
10295 #[serde(default = "default_medicaid_pct")]
10297 pub medicaid: f64,
10298
10299 #[serde(default = "default_commercial_pct")]
10301 pub commercial: f64,
10302
10303 #[serde(default = "default_self_pay_pct")]
10305 pub self_pay: f64,
10306}
10307
10308fn default_medicare_pct() -> f64 {
10309 0.40
10310}
10311
10312fn default_medicaid_pct() -> f64 {
10313 0.20
10314}
10315
10316fn default_commercial_pct() -> f64 {
10317 0.30
10318}
10319
10320fn default_self_pay_pct() -> f64 {
10321 0.10
10322}
10323
10324impl Default for HealthcarePayerMix {
10325 fn default() -> Self {
10326 Self {
10327 medicare: default_medicare_pct(),
10328 medicaid: default_medicaid_pct(),
10329 commercial: default_commercial_pct(),
10330 self_pay: default_self_pay_pct(),
10331 }
10332 }
10333}
10334
10335#[derive(Debug, Clone, Serialize, Deserialize)]
10337pub struct HealthcareCodingSystems {
10338 #[serde(default = "default_true")]
10340 pub icd10: bool,
10341
10342 #[serde(default = "default_true")]
10344 pub cpt: bool,
10345
10346 #[serde(default = "default_true")]
10348 pub drg: bool,
10349
10350 #[serde(default = "default_true")]
10352 pub hcpcs: bool,
10353
10354 #[serde(default = "default_true")]
10356 pub revenue_codes: bool,
10357}
10358
10359impl Default for HealthcareCodingSystems {
10360 fn default() -> Self {
10361 Self {
10362 icd10: true,
10363 cpt: true,
10364 drg: true,
10365 hcpcs: true,
10366 revenue_codes: true,
10367 }
10368 }
10369}
10370
10371#[derive(Debug, Clone, Serialize, Deserialize)]
10373pub struct HealthcareComplianceConfig {
10374 #[serde(default = "default_true")]
10376 pub hipaa: bool,
10377
10378 #[serde(default = "default_true")]
10380 pub stark_law: bool,
10381
10382 #[serde(default = "default_true")]
10384 pub anti_kickback: bool,
10385
10386 #[serde(default = "default_true")]
10388 pub false_claims_act: bool,
10389
10390 #[serde(default = "default_true")]
10392 pub emtala: bool,
10393}
10394
10395impl Default for HealthcareComplianceConfig {
10396 fn default() -> Self {
10397 Self {
10398 hipaa: true,
10399 stark_law: true,
10400 anti_kickback: true,
10401 false_claims_act: true,
10402 emtala: true,
10403 }
10404 }
10405}
10406
10407#[derive(Debug, Clone, Serialize, Deserialize)]
10409pub struct HealthcareAnomalyRates {
10410 #[serde(default = "default_upcoding_rate")]
10412 pub upcoding: f64,
10413
10414 #[serde(default = "default_unbundling_rate")]
10416 pub unbundling: f64,
10417
10418 #[serde(default = "default_phantom_billing_rate")]
10420 pub phantom_billing: f64,
10421
10422 #[serde(default = "default_healthcare_kickback_rate")]
10424 pub kickbacks: f64,
10425
10426 #[serde(default = "default_duplicate_billing_rate")]
10428 pub duplicate_billing: f64,
10429
10430 #[serde(default = "default_med_necessity_rate")]
10432 pub medical_necessity_abuse: f64,
10433}
10434
10435fn default_upcoding_rate() -> f64 {
10436 0.02
10437}
10438
10439fn default_unbundling_rate() -> f64 {
10440 0.015
10441}
10442
10443fn default_phantom_billing_rate() -> f64 {
10444 0.005
10445}
10446
10447fn default_healthcare_kickback_rate() -> f64 {
10448 0.003
10449}
10450
10451fn default_duplicate_billing_rate() -> f64 {
10452 0.008
10453}
10454
10455fn default_med_necessity_rate() -> f64 {
10456 0.01
10457}
10458
10459impl Default for HealthcareAnomalyRates {
10460 fn default() -> Self {
10461 Self {
10462 upcoding: default_upcoding_rate(),
10463 unbundling: default_unbundling_rate(),
10464 phantom_billing: default_phantom_billing_rate(),
10465 kickbacks: default_healthcare_kickback_rate(),
10466 duplicate_billing: default_duplicate_billing_rate(),
10467 medical_necessity_abuse: default_med_necessity_rate(),
10468 }
10469 }
10470}
10471
10472#[derive(Debug, Clone, Serialize, Deserialize)]
10474pub struct TechnologyConfig {
10475 #[serde(default)]
10477 pub enabled: bool,
10478
10479 #[serde(default = "default_revenue_model")]
10481 pub revenue_model: String,
10482
10483 #[serde(default = "default_subscription_pct")]
10485 pub subscription_revenue_pct: f64,
10486
10487 #[serde(default = "default_license_pct")]
10489 pub license_revenue_pct: f64,
10490
10491 #[serde(default = "default_services_pct")]
10493 pub services_revenue_pct: f64,
10494
10495 #[serde(default)]
10497 pub rd_capitalization: RdCapitalizationConfig,
10498
10499 #[serde(default)]
10501 pub anomaly_rates: TechnologyAnomalyRates,
10502}
10503
10504fn default_revenue_model() -> String {
10505 "saas".to_string()
10506}
10507
10508fn default_subscription_pct() -> f64 {
10509 0.60
10510}
10511
10512fn default_license_pct() -> f64 {
10513 0.25
10514}
10515
10516fn default_services_pct() -> f64 {
10517 0.15
10518}
10519
10520impl Default for TechnologyConfig {
10521 fn default() -> Self {
10522 Self {
10523 enabled: false,
10524 revenue_model: default_revenue_model(),
10525 subscription_revenue_pct: default_subscription_pct(),
10526 license_revenue_pct: default_license_pct(),
10527 services_revenue_pct: default_services_pct(),
10528 rd_capitalization: RdCapitalizationConfig::default(),
10529 anomaly_rates: TechnologyAnomalyRates::default(),
10530 }
10531 }
10532}
10533
10534#[derive(Debug, Clone, Serialize, Deserialize)]
10536pub struct RdCapitalizationConfig {
10537 #[serde(default = "default_true")]
10539 pub enabled: bool,
10540
10541 #[serde(default = "default_cap_rate")]
10543 pub capitalization_rate: f64,
10544
10545 #[serde(default = "default_useful_life")]
10547 pub useful_life_years: u32,
10548}
10549
10550fn default_cap_rate() -> f64 {
10551 0.30
10552}
10553
10554fn default_useful_life() -> u32 {
10555 3
10556}
10557
10558impl Default for RdCapitalizationConfig {
10559 fn default() -> Self {
10560 Self {
10561 enabled: true,
10562 capitalization_rate: default_cap_rate(),
10563 useful_life_years: default_useful_life(),
10564 }
10565 }
10566}
10567
10568#[derive(Debug, Clone, Serialize, Deserialize)]
10570pub struct TechnologyAnomalyRates {
10571 #[serde(default = "default_premature_rev_rate")]
10573 pub premature_revenue: f64,
10574
10575 #[serde(default = "default_side_letter_rate")]
10577 pub side_letter_abuse: f64,
10578
10579 #[serde(default = "default_channel_stuffing_rate")]
10581 pub channel_stuffing: f64,
10582
10583 #[serde(default = "default_improper_cap_rate")]
10585 pub improper_capitalization: f64,
10586}
10587
10588fn default_premature_rev_rate() -> f64 {
10589 0.015
10590}
10591
10592fn default_side_letter_rate() -> f64 {
10593 0.008
10594}
10595
10596fn default_channel_stuffing_rate() -> f64 {
10597 0.01
10598}
10599
10600fn default_improper_cap_rate() -> f64 {
10601 0.012
10602}
10603
10604impl Default for TechnologyAnomalyRates {
10605 fn default() -> Self {
10606 Self {
10607 premature_revenue: default_premature_rev_rate(),
10608 side_letter_abuse: default_side_letter_rate(),
10609 channel_stuffing: default_channel_stuffing_rate(),
10610 improper_capitalization: default_improper_cap_rate(),
10611 }
10612 }
10613}
10614
10615#[derive(Debug, Clone, Serialize, Deserialize)]
10617pub struct FinancialServicesConfig {
10618 #[serde(default)]
10620 pub enabled: bool,
10621
10622 #[serde(default = "default_fi_type")]
10624 pub institution_type: String,
10625
10626 #[serde(default = "default_fi_regulatory")]
10628 pub regulatory_framework: String,
10629
10630 #[serde(default)]
10632 pub anomaly_rates: FinancialServicesAnomalyRates,
10633}
10634
10635fn default_fi_type() -> String {
10636 "commercial_bank".to_string()
10637}
10638
10639fn default_fi_regulatory() -> String {
10640 "us_banking".to_string()
10641}
10642
10643impl Default for FinancialServicesConfig {
10644 fn default() -> Self {
10645 Self {
10646 enabled: false,
10647 institution_type: default_fi_type(),
10648 regulatory_framework: default_fi_regulatory(),
10649 anomaly_rates: FinancialServicesAnomalyRates::default(),
10650 }
10651 }
10652}
10653
10654#[derive(Debug, Clone, Serialize, Deserialize)]
10656pub struct FinancialServicesAnomalyRates {
10657 #[serde(default = "default_loan_fraud_rate")]
10659 pub loan_fraud: f64,
10660
10661 #[serde(default = "default_trading_fraud_rate")]
10663 pub trading_fraud: f64,
10664
10665 #[serde(default = "default_insurance_fraud_rate")]
10667 pub insurance_fraud: f64,
10668
10669 #[serde(default = "default_account_manip_rate")]
10671 pub account_manipulation: f64,
10672}
10673
10674fn default_loan_fraud_rate() -> f64 {
10675 0.01
10676}
10677
10678fn default_trading_fraud_rate() -> f64 {
10679 0.008
10680}
10681
10682fn default_insurance_fraud_rate() -> f64 {
10683 0.012
10684}
10685
10686fn default_account_manip_rate() -> f64 {
10687 0.005
10688}
10689
10690impl Default for FinancialServicesAnomalyRates {
10691 fn default() -> Self {
10692 Self {
10693 loan_fraud: default_loan_fraud_rate(),
10694 trading_fraud: default_trading_fraud_rate(),
10695 insurance_fraud: default_insurance_fraud_rate(),
10696 account_manipulation: default_account_manip_rate(),
10697 }
10698 }
10699}
10700
10701#[derive(Debug, Clone, Serialize, Deserialize)]
10703pub struct ProfessionalServicesConfig {
10704 #[serde(default)]
10706 pub enabled: bool,
10707
10708 #[serde(default = "default_firm_type")]
10710 pub firm_type: String,
10711
10712 #[serde(default = "default_billing_model")]
10714 pub billing_model: String,
10715
10716 #[serde(default = "default_hourly_rate")]
10718 pub avg_hourly_rate: f64,
10719
10720 #[serde(default)]
10722 pub trust_accounting: TrustAccountingConfig,
10723
10724 #[serde(default)]
10726 pub anomaly_rates: ProfessionalServicesAnomalyRates,
10727}
10728
10729fn default_firm_type() -> String {
10730 "consulting".to_string()
10731}
10732
10733fn default_billing_model() -> String {
10734 "time_and_materials".to_string()
10735}
10736
10737fn default_hourly_rate() -> f64 {
10738 250.0
10739}
10740
10741impl Default for ProfessionalServicesConfig {
10742 fn default() -> Self {
10743 Self {
10744 enabled: false,
10745 firm_type: default_firm_type(),
10746 billing_model: default_billing_model(),
10747 avg_hourly_rate: default_hourly_rate(),
10748 trust_accounting: TrustAccountingConfig::default(),
10749 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
10750 }
10751 }
10752}
10753
10754#[derive(Debug, Clone, Serialize, Deserialize)]
10756pub struct TrustAccountingConfig {
10757 #[serde(default)]
10759 pub enabled: bool,
10760
10761 #[serde(default = "default_true")]
10763 pub require_three_way_reconciliation: bool,
10764}
10765
10766impl Default for TrustAccountingConfig {
10767 fn default() -> Self {
10768 Self {
10769 enabled: false,
10770 require_three_way_reconciliation: true,
10771 }
10772 }
10773}
10774
10775#[derive(Debug, Clone, Serialize, Deserialize)]
10777pub struct ProfessionalServicesAnomalyRates {
10778 #[serde(default = "default_time_fraud_rate")]
10780 pub time_billing_fraud: f64,
10781
10782 #[serde(default = "default_expense_fraud_rate")]
10784 pub expense_fraud: f64,
10785
10786 #[serde(default = "default_trust_misappropriation_rate")]
10788 pub trust_misappropriation: f64,
10789}
10790
10791fn default_time_fraud_rate() -> f64 {
10792 0.02
10793}
10794
10795fn default_expense_fraud_rate() -> f64 {
10796 0.015
10797}
10798
10799fn default_trust_misappropriation_rate() -> f64 {
10800 0.003
10801}
10802
10803impl Default for ProfessionalServicesAnomalyRates {
10804 fn default() -> Self {
10805 Self {
10806 time_billing_fraud: default_time_fraud_rate(),
10807 expense_fraud: default_expense_fraud_rate(),
10808 trust_misappropriation: default_trust_misappropriation_rate(),
10809 }
10810 }
10811}
10812
10813#[derive(Debug, Clone, Serialize, Deserialize)]
10827pub struct FingerprintPrivacyConfig {
10828 #[serde(default)]
10830 pub level: String,
10831 #[serde(default = "default_epsilon")]
10833 pub epsilon: f64,
10834 #[serde(default = "default_delta")]
10836 pub delta: f64,
10837 #[serde(default = "default_k_anonymity")]
10839 pub k_anonymity: u32,
10840 #[serde(default)]
10842 pub composition_method: String,
10843}
10844
10845fn default_epsilon() -> f64 {
10846 1.0
10847}
10848
10849fn default_delta() -> f64 {
10850 1e-5
10851}
10852
10853fn default_k_anonymity() -> u32 {
10854 5
10855}
10856
10857impl Default for FingerprintPrivacyConfig {
10858 fn default() -> Self {
10859 Self {
10860 level: "standard".to_string(),
10861 epsilon: default_epsilon(),
10862 delta: default_delta(),
10863 k_anonymity: default_k_anonymity(),
10864 composition_method: "naive".to_string(),
10865 }
10866 }
10867}
10868
10869#[derive(Debug, Clone, Serialize, Deserialize)]
10883pub struct QualityGatesSchemaConfig {
10884 #[serde(default)]
10886 pub enabled: bool,
10887 #[serde(default = "default_gate_profile_name")]
10889 pub profile: String,
10890 #[serde(default)]
10892 pub fail_on_violation: bool,
10893 #[serde(default)]
10895 pub custom_gates: Vec<QualityGateEntry>,
10896}
10897
10898fn default_gate_profile_name() -> String {
10899 "default".to_string()
10900}
10901
10902impl Default for QualityGatesSchemaConfig {
10903 fn default() -> Self {
10904 Self {
10905 enabled: false,
10906 profile: default_gate_profile_name(),
10907 fail_on_violation: false,
10908 custom_gates: Vec::new(),
10909 }
10910 }
10911}
10912
10913#[derive(Debug, Clone, Serialize, Deserialize)]
10915pub struct QualityGateEntry {
10916 pub name: String,
10918 pub metric: String,
10922 pub threshold: f64,
10924 #[serde(default)]
10926 pub upper_threshold: Option<f64>,
10927 #[serde(default = "default_gate_comparison")]
10929 pub comparison: String,
10930}
10931
10932fn default_gate_comparison() -> String {
10933 "gte".to_string()
10934}
10935
10936#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10946pub struct ComplianceSchemaConfig {
10947 #[serde(default)]
10949 pub content_marking: ContentMarkingSchemaConfig,
10950 #[serde(default)]
10952 pub article10_report: bool,
10953 #[serde(default)]
10955 pub certificates: CertificateSchemaConfig,
10956}
10957
10958#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10960pub struct CertificateSchemaConfig {
10961 #[serde(default)]
10963 pub enabled: bool,
10964 #[serde(default)]
10966 pub signing_key_env: Option<String>,
10967 #[serde(default)]
10969 pub include_quality_metrics: bool,
10970}
10971
10972#[derive(Debug, Clone, Serialize, Deserialize)]
10974pub struct ContentMarkingSchemaConfig {
10975 #[serde(default = "default_true")]
10977 pub enabled: bool,
10978 #[serde(default = "default_marking_format")]
10980 pub format: String,
10981}
10982
10983fn default_marking_format() -> String {
10984 "embedded".to_string()
10985}
10986
10987impl Default for ContentMarkingSchemaConfig {
10988 fn default() -> Self {
10989 Self {
10990 enabled: true,
10991 format: default_marking_format(),
10992 }
10993 }
10994}
10995
10996#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10998pub struct WebhookSchemaConfig {
10999 #[serde(default)]
11001 pub enabled: bool,
11002 #[serde(default)]
11004 pub endpoints: Vec<WebhookEndpointConfig>,
11005}
11006
11007#[derive(Debug, Clone, Serialize, Deserialize)]
11009pub struct WebhookEndpointConfig {
11010 pub url: String,
11012 #[serde(default)]
11014 pub events: Vec<String>,
11015 #[serde(default)]
11017 pub secret: Option<String>,
11018 #[serde(default = "default_webhook_retries")]
11020 pub max_retries: u32,
11021 #[serde(default = "default_webhook_timeout")]
11023 pub timeout_secs: u64,
11024}
11025
11026fn default_webhook_retries() -> u32 {
11027 3
11028}
11029fn default_webhook_timeout() -> u64 {
11030 10
11031}
11032
11033#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11039pub struct SourceToPayConfig {
11040 #[serde(default)]
11042 pub enabled: bool,
11043 #[serde(default)]
11045 pub spend_analysis: SpendAnalysisConfig,
11046 #[serde(default)]
11048 pub sourcing: SourcingConfig,
11049 #[serde(default)]
11051 pub qualification: QualificationConfig,
11052 #[serde(default)]
11054 pub rfx: RfxConfig,
11055 #[serde(default)]
11057 pub contracts: ContractConfig,
11058 #[serde(default)]
11060 pub catalog: CatalogConfig,
11061 #[serde(default)]
11063 pub scorecards: ScorecardConfig,
11064 #[serde(default)]
11066 pub p2p_integration: P2PIntegrationConfig,
11067}
11068
11069#[derive(Debug, Clone, Serialize, Deserialize)]
11071pub struct SpendAnalysisConfig {
11072 #[serde(default = "default_hhi_threshold")]
11074 pub hhi_threshold: f64,
11075 #[serde(default = "default_contract_coverage_target")]
11077 pub contract_coverage_target: f64,
11078}
11079
11080impl Default for SpendAnalysisConfig {
11081 fn default() -> Self {
11082 Self {
11083 hhi_threshold: default_hhi_threshold(),
11084 contract_coverage_target: default_contract_coverage_target(),
11085 }
11086 }
11087}
11088
11089fn default_hhi_threshold() -> f64 {
11090 2500.0
11091}
11092fn default_contract_coverage_target() -> f64 {
11093 0.80
11094}
11095
11096#[derive(Debug, Clone, Serialize, Deserialize)]
11098pub struct SourcingConfig {
11099 #[serde(default = "default_sourcing_projects_per_year")]
11101 pub projects_per_year: u32,
11102 #[serde(default = "default_renewal_horizon_months")]
11104 pub renewal_horizon_months: u32,
11105 #[serde(default = "default_project_duration_months")]
11107 pub project_duration_months: u32,
11108}
11109
11110impl Default for SourcingConfig {
11111 fn default() -> Self {
11112 Self {
11113 projects_per_year: default_sourcing_projects_per_year(),
11114 renewal_horizon_months: default_renewal_horizon_months(),
11115 project_duration_months: default_project_duration_months(),
11116 }
11117 }
11118}
11119
11120fn default_sourcing_projects_per_year() -> u32 {
11121 10
11122}
11123fn default_renewal_horizon_months() -> u32 {
11124 3
11125}
11126fn default_project_duration_months() -> u32 {
11127 4
11128}
11129
11130#[derive(Debug, Clone, Serialize, Deserialize)]
11132pub struct QualificationConfig {
11133 #[serde(default = "default_qualification_pass_rate")]
11135 pub pass_rate: f64,
11136 #[serde(default = "default_qualification_validity_days")]
11138 pub validity_days: u32,
11139 #[serde(default = "default_financial_weight")]
11141 pub financial_weight: f64,
11142 #[serde(default = "default_quality_weight")]
11144 pub quality_weight: f64,
11145 #[serde(default = "default_delivery_weight")]
11147 pub delivery_weight: f64,
11148 #[serde(default = "default_compliance_weight")]
11150 pub compliance_weight: f64,
11151}
11152
11153impl Default for QualificationConfig {
11154 fn default() -> Self {
11155 Self {
11156 pass_rate: default_qualification_pass_rate(),
11157 validity_days: default_qualification_validity_days(),
11158 financial_weight: default_financial_weight(),
11159 quality_weight: default_quality_weight(),
11160 delivery_weight: default_delivery_weight(),
11161 compliance_weight: default_compliance_weight(),
11162 }
11163 }
11164}
11165
11166fn default_qualification_pass_rate() -> f64 {
11167 0.75
11168}
11169fn default_qualification_validity_days() -> u32 {
11170 365
11171}
11172fn default_financial_weight() -> f64 {
11173 0.25
11174}
11175fn default_quality_weight() -> f64 {
11176 0.30
11177}
11178fn default_delivery_weight() -> f64 {
11179 0.25
11180}
11181fn default_compliance_weight() -> f64 {
11182 0.20
11183}
11184
11185#[derive(Debug, Clone, Serialize, Deserialize)]
11187pub struct RfxConfig {
11188 #[serde(default = "default_rfi_threshold")]
11190 pub rfi_threshold: f64,
11191 #[serde(default = "default_min_invited_vendors")]
11193 pub min_invited_vendors: u32,
11194 #[serde(default = "default_max_invited_vendors")]
11196 pub max_invited_vendors: u32,
11197 #[serde(default = "default_response_rate")]
11199 pub response_rate: f64,
11200 #[serde(default = "default_price_weight")]
11202 pub default_price_weight: f64,
11203 #[serde(default = "default_rfx_quality_weight")]
11205 pub default_quality_weight: f64,
11206 #[serde(default = "default_rfx_delivery_weight")]
11208 pub default_delivery_weight: f64,
11209}
11210
11211impl Default for RfxConfig {
11212 fn default() -> Self {
11213 Self {
11214 rfi_threshold: default_rfi_threshold(),
11215 min_invited_vendors: default_min_invited_vendors(),
11216 max_invited_vendors: default_max_invited_vendors(),
11217 response_rate: default_response_rate(),
11218 default_price_weight: default_price_weight(),
11219 default_quality_weight: default_rfx_quality_weight(),
11220 default_delivery_weight: default_rfx_delivery_weight(),
11221 }
11222 }
11223}
11224
11225fn default_rfi_threshold() -> f64 {
11226 100_000.0
11227}
11228fn default_min_invited_vendors() -> u32 {
11229 3
11230}
11231fn default_max_invited_vendors() -> u32 {
11232 8
11233}
11234fn default_response_rate() -> f64 {
11235 0.70
11236}
11237fn default_price_weight() -> f64 {
11238 0.40
11239}
11240fn default_rfx_quality_weight() -> f64 {
11241 0.35
11242}
11243fn default_rfx_delivery_weight() -> f64 {
11244 0.25
11245}
11246
11247#[derive(Debug, Clone, Serialize, Deserialize)]
11249pub struct ContractConfig {
11250 #[serde(default = "default_min_contract_months")]
11252 pub min_duration_months: u32,
11253 #[serde(default = "default_max_contract_months")]
11255 pub max_duration_months: u32,
11256 #[serde(default = "default_auto_renewal_rate")]
11258 pub auto_renewal_rate: f64,
11259 #[serde(default = "default_amendment_rate")]
11261 pub amendment_rate: f64,
11262 #[serde(default)]
11264 pub type_distribution: ContractTypeDistribution,
11265}
11266
11267impl Default for ContractConfig {
11268 fn default() -> Self {
11269 Self {
11270 min_duration_months: default_min_contract_months(),
11271 max_duration_months: default_max_contract_months(),
11272 auto_renewal_rate: default_auto_renewal_rate(),
11273 amendment_rate: default_amendment_rate(),
11274 type_distribution: ContractTypeDistribution::default(),
11275 }
11276 }
11277}
11278
11279fn default_min_contract_months() -> u32 {
11280 12
11281}
11282fn default_max_contract_months() -> u32 {
11283 36
11284}
11285fn default_auto_renewal_rate() -> f64 {
11286 0.40
11287}
11288fn default_amendment_rate() -> f64 {
11289 0.20
11290}
11291
11292#[derive(Debug, Clone, Serialize, Deserialize)]
11294pub struct ContractTypeDistribution {
11295 #[serde(default = "default_fixed_price_pct")]
11297 pub fixed_price: f64,
11298 #[serde(default = "default_blanket_pct")]
11300 pub blanket: f64,
11301 #[serde(default = "default_time_materials_pct")]
11303 pub time_and_materials: f64,
11304 #[serde(default = "default_service_agreement_pct")]
11306 pub service_agreement: f64,
11307}
11308
11309impl Default for ContractTypeDistribution {
11310 fn default() -> Self {
11311 Self {
11312 fixed_price: default_fixed_price_pct(),
11313 blanket: default_blanket_pct(),
11314 time_and_materials: default_time_materials_pct(),
11315 service_agreement: default_service_agreement_pct(),
11316 }
11317 }
11318}
11319
11320fn default_fixed_price_pct() -> f64 {
11321 0.40
11322}
11323fn default_blanket_pct() -> f64 {
11324 0.30
11325}
11326fn default_time_materials_pct() -> f64 {
11327 0.15
11328}
11329fn default_service_agreement_pct() -> f64 {
11330 0.15
11331}
11332
11333#[derive(Debug, Clone, Serialize, Deserialize)]
11335pub struct CatalogConfig {
11336 #[serde(default = "default_preferred_vendor_flag_rate")]
11338 pub preferred_vendor_flag_rate: f64,
11339 #[serde(default = "default_multi_source_rate")]
11341 pub multi_source_rate: f64,
11342}
11343
11344impl Default for CatalogConfig {
11345 fn default() -> Self {
11346 Self {
11347 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
11348 multi_source_rate: default_multi_source_rate(),
11349 }
11350 }
11351}
11352
11353fn default_preferred_vendor_flag_rate() -> f64 {
11354 0.70
11355}
11356fn default_multi_source_rate() -> f64 {
11357 0.25
11358}
11359
11360#[derive(Debug, Clone, Serialize, Deserialize)]
11362pub struct ScorecardConfig {
11363 #[serde(default = "default_scorecard_frequency")]
11365 pub frequency: String,
11366 #[serde(default = "default_otd_weight")]
11368 pub on_time_delivery_weight: f64,
11369 #[serde(default = "default_quality_score_weight")]
11371 pub quality_weight: f64,
11372 #[serde(default = "default_price_score_weight")]
11374 pub price_weight: f64,
11375 #[serde(default = "default_responsiveness_weight")]
11377 pub responsiveness_weight: f64,
11378 #[serde(default = "default_grade_a_threshold")]
11380 pub grade_a_threshold: f64,
11381 #[serde(default = "default_grade_b_threshold")]
11383 pub grade_b_threshold: f64,
11384 #[serde(default = "default_grade_c_threshold")]
11386 pub grade_c_threshold: f64,
11387}
11388
11389impl Default for ScorecardConfig {
11390 fn default() -> Self {
11391 Self {
11392 frequency: default_scorecard_frequency(),
11393 on_time_delivery_weight: default_otd_weight(),
11394 quality_weight: default_quality_score_weight(),
11395 price_weight: default_price_score_weight(),
11396 responsiveness_weight: default_responsiveness_weight(),
11397 grade_a_threshold: default_grade_a_threshold(),
11398 grade_b_threshold: default_grade_b_threshold(),
11399 grade_c_threshold: default_grade_c_threshold(),
11400 }
11401 }
11402}
11403
11404fn default_scorecard_frequency() -> String {
11405 "quarterly".to_string()
11406}
11407fn default_otd_weight() -> f64 {
11408 0.30
11409}
11410fn default_quality_score_weight() -> f64 {
11411 0.30
11412}
11413fn default_price_score_weight() -> f64 {
11414 0.25
11415}
11416fn default_responsiveness_weight() -> f64 {
11417 0.15
11418}
11419fn default_grade_a_threshold() -> f64 {
11420 90.0
11421}
11422fn default_grade_b_threshold() -> f64 {
11423 75.0
11424}
11425fn default_grade_c_threshold() -> f64 {
11426 60.0
11427}
11428
11429#[derive(Debug, Clone, Serialize, Deserialize)]
11431pub struct P2PIntegrationConfig {
11432 #[serde(default = "default_off_contract_rate")]
11434 pub off_contract_rate: f64,
11435 #[serde(default = "default_price_tolerance")]
11437 pub price_tolerance: f64,
11438 #[serde(default)]
11440 pub catalog_enforcement: bool,
11441}
11442
11443impl Default for P2PIntegrationConfig {
11444 fn default() -> Self {
11445 Self {
11446 off_contract_rate: default_off_contract_rate(),
11447 price_tolerance: default_price_tolerance(),
11448 catalog_enforcement: false,
11449 }
11450 }
11451}
11452
11453fn default_off_contract_rate() -> f64 {
11454 0.15
11455}
11456fn default_price_tolerance() -> f64 {
11457 0.02
11458}
11459
11460#[derive(Debug, Clone, Serialize, Deserialize)]
11464pub struct FinancialReportingConfig {
11465 #[serde(default)]
11467 pub enabled: bool,
11468 #[serde(default = "default_true")]
11470 pub generate_balance_sheet: bool,
11471 #[serde(default = "default_true")]
11473 pub generate_income_statement: bool,
11474 #[serde(default = "default_true")]
11476 pub generate_cash_flow: bool,
11477 #[serde(default = "default_true")]
11479 pub generate_changes_in_equity: bool,
11480 #[serde(default = "default_comparative_periods")]
11482 pub comparative_periods: u32,
11483 #[serde(default)]
11485 pub management_kpis: ManagementKpisConfig,
11486 #[serde(default)]
11488 pub budgets: BudgetConfig,
11489}
11490
11491impl Default for FinancialReportingConfig {
11492 fn default() -> Self {
11493 Self {
11494 enabled: false,
11495 generate_balance_sheet: true,
11496 generate_income_statement: true,
11497 generate_cash_flow: true,
11498 generate_changes_in_equity: true,
11499 comparative_periods: default_comparative_periods(),
11500 management_kpis: ManagementKpisConfig::default(),
11501 budgets: BudgetConfig::default(),
11502 }
11503 }
11504}
11505
11506fn default_comparative_periods() -> u32 {
11507 1
11508}
11509
11510#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11512pub struct ManagementKpisConfig {
11513 #[serde(default)]
11515 pub enabled: bool,
11516 #[serde(default = "default_kpi_frequency")]
11518 pub frequency: String,
11519}
11520
11521fn default_kpi_frequency() -> String {
11522 "monthly".to_string()
11523}
11524
11525#[derive(Debug, Clone, Serialize, Deserialize)]
11527pub struct BudgetConfig {
11528 #[serde(default)]
11530 pub enabled: bool,
11531 #[serde(default = "default_revenue_growth_rate")]
11533 pub revenue_growth_rate: f64,
11534 #[serde(default = "default_expense_inflation_rate")]
11536 pub expense_inflation_rate: f64,
11537 #[serde(default = "default_variance_noise")]
11539 pub variance_noise: f64,
11540}
11541
11542impl Default for BudgetConfig {
11543 fn default() -> Self {
11544 Self {
11545 enabled: false,
11546 revenue_growth_rate: default_revenue_growth_rate(),
11547 expense_inflation_rate: default_expense_inflation_rate(),
11548 variance_noise: default_variance_noise(),
11549 }
11550 }
11551}
11552
11553fn default_revenue_growth_rate() -> f64 {
11554 0.05
11555}
11556fn default_expense_inflation_rate() -> f64 {
11557 0.03
11558}
11559fn default_variance_noise() -> f64 {
11560 0.10
11561}
11562
11563#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11567pub struct HrConfig {
11568 #[serde(default)]
11570 pub enabled: bool,
11571 #[serde(default)]
11573 pub payroll: PayrollConfig,
11574 #[serde(default)]
11576 pub time_attendance: TimeAttendanceConfig,
11577 #[serde(default)]
11579 pub expenses: ExpenseConfig,
11580}
11581
11582#[derive(Debug, Clone, Serialize, Deserialize)]
11584pub struct PayrollConfig {
11585 #[serde(default = "default_true")]
11587 pub enabled: bool,
11588 #[serde(default = "default_pay_frequency")]
11590 pub pay_frequency: String,
11591 #[serde(default)]
11593 pub salary_ranges: PayrollSalaryRanges,
11594 #[serde(default)]
11596 pub tax_rates: PayrollTaxRates,
11597 #[serde(default = "default_benefits_enrollment_rate")]
11599 pub benefits_enrollment_rate: f64,
11600 #[serde(default = "default_retirement_participation_rate")]
11602 pub retirement_participation_rate: f64,
11603}
11604
11605impl Default for PayrollConfig {
11606 fn default() -> Self {
11607 Self {
11608 enabled: true,
11609 pay_frequency: default_pay_frequency(),
11610 salary_ranges: PayrollSalaryRanges::default(),
11611 tax_rates: PayrollTaxRates::default(),
11612 benefits_enrollment_rate: default_benefits_enrollment_rate(),
11613 retirement_participation_rate: default_retirement_participation_rate(),
11614 }
11615 }
11616}
11617
11618fn default_pay_frequency() -> String {
11619 "monthly".to_string()
11620}
11621fn default_benefits_enrollment_rate() -> f64 {
11622 0.60
11623}
11624fn default_retirement_participation_rate() -> f64 {
11625 0.45
11626}
11627
11628#[derive(Debug, Clone, Serialize, Deserialize)]
11630pub struct PayrollSalaryRanges {
11631 #[serde(default = "default_staff_min")]
11633 pub staff_min: f64,
11634 #[serde(default = "default_staff_max")]
11635 pub staff_max: f64,
11636 #[serde(default = "default_manager_min")]
11638 pub manager_min: f64,
11639 #[serde(default = "default_manager_max")]
11640 pub manager_max: f64,
11641 #[serde(default = "default_director_min")]
11643 pub director_min: f64,
11644 #[serde(default = "default_director_max")]
11645 pub director_max: f64,
11646 #[serde(default = "default_executive_min")]
11648 pub executive_min: f64,
11649 #[serde(default = "default_executive_max")]
11650 pub executive_max: f64,
11651}
11652
11653impl Default for PayrollSalaryRanges {
11654 fn default() -> Self {
11655 Self {
11656 staff_min: default_staff_min(),
11657 staff_max: default_staff_max(),
11658 manager_min: default_manager_min(),
11659 manager_max: default_manager_max(),
11660 director_min: default_director_min(),
11661 director_max: default_director_max(),
11662 executive_min: default_executive_min(),
11663 executive_max: default_executive_max(),
11664 }
11665 }
11666}
11667
11668fn default_staff_min() -> f64 {
11669 50_000.0
11670}
11671fn default_staff_max() -> f64 {
11672 70_000.0
11673}
11674fn default_manager_min() -> f64 {
11675 80_000.0
11676}
11677fn default_manager_max() -> f64 {
11678 120_000.0
11679}
11680fn default_director_min() -> f64 {
11681 120_000.0
11682}
11683fn default_director_max() -> f64 {
11684 180_000.0
11685}
11686fn default_executive_min() -> f64 {
11687 180_000.0
11688}
11689fn default_executive_max() -> f64 {
11690 350_000.0
11691}
11692
11693#[derive(Debug, Clone, Serialize, Deserialize)]
11695pub struct PayrollTaxRates {
11696 #[serde(default = "default_federal_rate")]
11698 pub federal_effective: f64,
11699 #[serde(default = "default_state_rate")]
11701 pub state_effective: f64,
11702 #[serde(default = "default_fica_rate")]
11704 pub fica: f64,
11705}
11706
11707impl Default for PayrollTaxRates {
11708 fn default() -> Self {
11709 Self {
11710 federal_effective: default_federal_rate(),
11711 state_effective: default_state_rate(),
11712 fica: default_fica_rate(),
11713 }
11714 }
11715}
11716
11717fn default_federal_rate() -> f64 {
11718 0.22
11719}
11720fn default_state_rate() -> f64 {
11721 0.05
11722}
11723fn default_fica_rate() -> f64 {
11724 0.0765
11725}
11726
11727#[derive(Debug, Clone, Serialize, Deserialize)]
11729pub struct TimeAttendanceConfig {
11730 #[serde(default = "default_true")]
11732 pub enabled: bool,
11733 #[serde(default = "default_overtime_rate")]
11735 pub overtime_rate: f64,
11736}
11737
11738impl Default for TimeAttendanceConfig {
11739 fn default() -> Self {
11740 Self {
11741 enabled: true,
11742 overtime_rate: default_overtime_rate(),
11743 }
11744 }
11745}
11746
11747fn default_overtime_rate() -> f64 {
11748 0.10
11749}
11750
11751#[derive(Debug, Clone, Serialize, Deserialize)]
11753pub struct ExpenseConfig {
11754 #[serde(default = "default_true")]
11756 pub enabled: bool,
11757 #[serde(default = "default_expense_submission_rate")]
11759 pub submission_rate: f64,
11760 #[serde(default = "default_policy_violation_rate")]
11762 pub policy_violation_rate: f64,
11763}
11764
11765impl Default for ExpenseConfig {
11766 fn default() -> Self {
11767 Self {
11768 enabled: true,
11769 submission_rate: default_expense_submission_rate(),
11770 policy_violation_rate: default_policy_violation_rate(),
11771 }
11772 }
11773}
11774
11775fn default_expense_submission_rate() -> f64 {
11776 0.30
11777}
11778fn default_policy_violation_rate() -> f64 {
11779 0.08
11780}
11781
11782#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11786pub struct ManufacturingProcessConfig {
11787 #[serde(default)]
11789 pub enabled: bool,
11790 #[serde(default)]
11792 pub production_orders: ProductionOrderConfig,
11793 #[serde(default)]
11795 pub costing: ManufacturingCostingConfig,
11796 #[serde(default)]
11798 pub routing: RoutingConfig,
11799}
11800
11801#[derive(Debug, Clone, Serialize, Deserialize)]
11803pub struct ProductionOrderConfig {
11804 #[serde(default = "default_prod_orders_per_month")]
11806 pub orders_per_month: u32,
11807 #[serde(default = "default_prod_avg_batch_size")]
11809 pub avg_batch_size: u32,
11810 #[serde(default = "default_prod_yield_rate")]
11812 pub yield_rate: f64,
11813 #[serde(default = "default_prod_make_to_order_rate")]
11815 pub make_to_order_rate: f64,
11816 #[serde(default = "default_prod_rework_rate")]
11818 pub rework_rate: f64,
11819}
11820
11821impl Default for ProductionOrderConfig {
11822 fn default() -> Self {
11823 Self {
11824 orders_per_month: default_prod_orders_per_month(),
11825 avg_batch_size: default_prod_avg_batch_size(),
11826 yield_rate: default_prod_yield_rate(),
11827 make_to_order_rate: default_prod_make_to_order_rate(),
11828 rework_rate: default_prod_rework_rate(),
11829 }
11830 }
11831}
11832
11833fn default_prod_orders_per_month() -> u32 {
11834 50
11835}
11836fn default_prod_avg_batch_size() -> u32 {
11837 100
11838}
11839fn default_prod_yield_rate() -> f64 {
11840 0.97
11841}
11842fn default_prod_make_to_order_rate() -> f64 {
11843 0.20
11844}
11845fn default_prod_rework_rate() -> f64 {
11846 0.03
11847}
11848
11849#[derive(Debug, Clone, Serialize, Deserialize)]
11851pub struct ManufacturingCostingConfig {
11852 #[serde(default = "default_labor_rate")]
11854 pub labor_rate_per_hour: f64,
11855 #[serde(default = "default_overhead_rate")]
11857 pub overhead_rate: f64,
11858 #[serde(default = "default_cost_update_frequency")]
11860 pub standard_cost_update_frequency: String,
11861}
11862
11863impl Default for ManufacturingCostingConfig {
11864 fn default() -> Self {
11865 Self {
11866 labor_rate_per_hour: default_labor_rate(),
11867 overhead_rate: default_overhead_rate(),
11868 standard_cost_update_frequency: default_cost_update_frequency(),
11869 }
11870 }
11871}
11872
11873fn default_labor_rate() -> f64 {
11874 35.0
11875}
11876fn default_overhead_rate() -> f64 {
11877 1.50
11878}
11879fn default_cost_update_frequency() -> String {
11880 "quarterly".to_string()
11881}
11882
11883#[derive(Debug, Clone, Serialize, Deserialize)]
11885pub struct RoutingConfig {
11886 #[serde(default = "default_avg_operations")]
11888 pub avg_operations: u32,
11889 #[serde(default = "default_setup_time")]
11891 pub setup_time_hours: f64,
11892 #[serde(default = "default_run_time_variation")]
11894 pub run_time_variation: f64,
11895}
11896
11897impl Default for RoutingConfig {
11898 fn default() -> Self {
11899 Self {
11900 avg_operations: default_avg_operations(),
11901 setup_time_hours: default_setup_time(),
11902 run_time_variation: default_run_time_variation(),
11903 }
11904 }
11905}
11906
11907fn default_avg_operations() -> u32 {
11908 4
11909}
11910fn default_setup_time() -> f64 {
11911 1.5
11912}
11913fn default_run_time_variation() -> f64 {
11914 0.15
11915}
11916
11917#[derive(Debug, Clone, Serialize, Deserialize)]
11921pub struct SalesQuoteConfig {
11922 #[serde(default)]
11924 pub enabled: bool,
11925 #[serde(default = "default_quotes_per_month")]
11927 pub quotes_per_month: u32,
11928 #[serde(default = "default_quote_win_rate")]
11930 pub win_rate: f64,
11931 #[serde(default = "default_quote_validity_days")]
11933 pub validity_days: u32,
11934}
11935
11936impl Default for SalesQuoteConfig {
11937 fn default() -> Self {
11938 Self {
11939 enabled: false,
11940 quotes_per_month: default_quotes_per_month(),
11941 win_rate: default_quote_win_rate(),
11942 validity_days: default_quote_validity_days(),
11943 }
11944 }
11945}
11946
11947fn default_quotes_per_month() -> u32 {
11948 30
11949}
11950fn default_quote_win_rate() -> f64 {
11951 0.35
11952}
11953fn default_quote_validity_days() -> u32 {
11954 30
11955}
11956
11957#[derive(Debug, Clone, Serialize, Deserialize)]
11966pub struct TaxConfig {
11967 #[serde(default)]
11969 pub enabled: bool,
11970 #[serde(default)]
11972 pub jurisdictions: TaxJurisdictionConfig,
11973 #[serde(default)]
11975 pub vat_gst: VatGstConfig,
11976 #[serde(default)]
11978 pub sales_tax: SalesTaxConfig,
11979 #[serde(default)]
11981 pub withholding: WithholdingTaxSchemaConfig,
11982 #[serde(default)]
11984 pub provisions: TaxProvisionSchemaConfig,
11985 #[serde(default)]
11987 pub payroll_tax: PayrollTaxSchemaConfig,
11988 #[serde(default = "default_tax_anomaly_rate")]
11990 pub anomaly_rate: f64,
11991}
11992
11993fn default_tax_anomaly_rate() -> f64 {
11994 0.03
11995}
11996
11997impl Default for TaxConfig {
11998 fn default() -> Self {
11999 Self {
12000 enabled: false,
12001 jurisdictions: TaxJurisdictionConfig::default(),
12002 vat_gst: VatGstConfig::default(),
12003 sales_tax: SalesTaxConfig::default(),
12004 withholding: WithholdingTaxSchemaConfig::default(),
12005 provisions: TaxProvisionSchemaConfig::default(),
12006 payroll_tax: PayrollTaxSchemaConfig::default(),
12007 anomaly_rate: default_tax_anomaly_rate(),
12008 }
12009 }
12010}
12011
12012#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12017pub struct TaxJurisdictionConfig {
12018 #[serde(default)]
12020 pub countries: Vec<String>,
12021 #[serde(default)]
12023 pub include_subnational: bool,
12024}
12025
12026#[derive(Debug, Clone, Serialize, Deserialize)]
12031pub struct VatGstConfig {
12032 #[serde(default)]
12034 pub enabled: bool,
12035 #[serde(default)]
12037 pub standard_rates: std::collections::HashMap<String, f64>,
12038 #[serde(default)]
12040 pub reduced_rates: std::collections::HashMap<String, f64>,
12041 #[serde(default)]
12043 pub exempt_categories: Vec<String>,
12044 #[serde(default = "default_true")]
12046 pub reverse_charge: bool,
12047}
12048
12049impl Default for VatGstConfig {
12050 fn default() -> Self {
12051 Self {
12052 enabled: false,
12053 standard_rates: std::collections::HashMap::new(),
12054 reduced_rates: std::collections::HashMap::new(),
12055 exempt_categories: Vec::new(),
12056 reverse_charge: true,
12057 }
12058 }
12059}
12060
12061#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12065pub struct SalesTaxConfig {
12066 #[serde(default)]
12068 pub enabled: bool,
12069 #[serde(default)]
12071 pub nexus_states: Vec<String>,
12072}
12073
12074#[derive(Debug, Clone, Serialize, Deserialize)]
12079pub struct WithholdingTaxSchemaConfig {
12080 #[serde(default)]
12082 pub enabled: bool,
12083 #[serde(default = "default_true")]
12085 pub treaty_network: bool,
12086 #[serde(default = "default_withholding_rate")]
12088 pub default_rate: f64,
12089 #[serde(default = "default_treaty_reduced_rate")]
12091 pub treaty_reduced_rate: f64,
12092}
12093
12094fn default_withholding_rate() -> f64 {
12095 0.30
12096}
12097
12098fn default_treaty_reduced_rate() -> f64 {
12099 0.15
12100}
12101
12102impl Default for WithholdingTaxSchemaConfig {
12103 fn default() -> Self {
12104 Self {
12105 enabled: false,
12106 treaty_network: true,
12107 default_rate: default_withholding_rate(),
12108 treaty_reduced_rate: default_treaty_reduced_rate(),
12109 }
12110 }
12111}
12112
12113#[derive(Debug, Clone, Serialize, Deserialize)]
12118pub struct TaxProvisionSchemaConfig {
12119 #[serde(default = "default_true")]
12122 pub enabled: bool,
12123 #[serde(default = "default_statutory_rate")]
12125 pub statutory_rate: f64,
12126 #[serde(default = "default_true")]
12128 pub uncertain_positions: bool,
12129}
12130
12131fn default_statutory_rate() -> f64 {
12132 0.21
12133}
12134
12135impl Default for TaxProvisionSchemaConfig {
12136 fn default() -> Self {
12137 Self {
12138 enabled: true,
12139 statutory_rate: default_statutory_rate(),
12140 uncertain_positions: true,
12141 }
12142 }
12143}
12144
12145#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12150pub struct PayrollTaxSchemaConfig {
12151 #[serde(default)]
12153 pub enabled: bool,
12154}
12155
12156#[derive(Debug, Clone, Serialize, Deserialize)]
12166pub struct TreasuryConfig {
12167 #[serde(default)]
12169 pub enabled: bool,
12170 #[serde(default)]
12172 pub cash_positioning: CashPositioningConfig,
12173 #[serde(default)]
12175 pub cash_forecasting: CashForecastingConfig,
12176 #[serde(default)]
12178 pub cash_pooling: CashPoolingConfig,
12179 #[serde(default)]
12181 pub hedging: HedgingSchemaConfig,
12182 #[serde(default)]
12184 pub debt: DebtSchemaConfig,
12185 #[serde(default)]
12187 pub netting: NettingSchemaConfig,
12188 #[serde(default)]
12190 pub bank_guarantees: BankGuaranteeSchemaConfig,
12191 #[serde(default = "default_treasury_anomaly_rate")]
12193 pub anomaly_rate: f64,
12194}
12195
12196fn default_treasury_anomaly_rate() -> f64 {
12197 0.02
12198}
12199
12200impl Default for TreasuryConfig {
12201 fn default() -> Self {
12202 Self {
12203 enabled: false,
12204 cash_positioning: CashPositioningConfig::default(),
12205 cash_forecasting: CashForecastingConfig::default(),
12206 cash_pooling: CashPoolingConfig::default(),
12207 hedging: HedgingSchemaConfig::default(),
12208 debt: DebtSchemaConfig::default(),
12209 netting: NettingSchemaConfig::default(),
12210 bank_guarantees: BankGuaranteeSchemaConfig::default(),
12211 anomaly_rate: default_treasury_anomaly_rate(),
12212 }
12213 }
12214}
12215
12216#[derive(Debug, Clone, Serialize, Deserialize)]
12220pub struct CashPositioningConfig {
12221 #[serde(default = "default_true")]
12223 pub enabled: bool,
12224 #[serde(default = "default_cash_frequency")]
12226 pub frequency: String,
12227 #[serde(default = "default_minimum_balance_policy")]
12229 pub minimum_balance_policy: f64,
12230}
12231
12232fn default_cash_frequency() -> String {
12233 "daily".to_string()
12234}
12235
12236fn default_minimum_balance_policy() -> f64 {
12237 100_000.0
12238}
12239
12240impl Default for CashPositioningConfig {
12241 fn default() -> Self {
12242 Self {
12243 enabled: true,
12244 frequency: default_cash_frequency(),
12245 minimum_balance_policy: default_minimum_balance_policy(),
12246 }
12247 }
12248}
12249
12250#[derive(Debug, Clone, Serialize, Deserialize)]
12254pub struct CashForecastingConfig {
12255 #[serde(default = "default_true")]
12257 pub enabled: bool,
12258 #[serde(default = "default_horizon_days")]
12260 pub horizon_days: u32,
12261 #[serde(default = "default_ar_probability_curve")]
12263 pub ar_collection_probability_curve: String,
12264 #[serde(default = "default_confidence_interval")]
12266 pub confidence_interval: f64,
12267}
12268
12269fn default_horizon_days() -> u32 {
12270 90
12271}
12272
12273fn default_ar_probability_curve() -> String {
12274 "aging".to_string()
12275}
12276
12277fn default_confidence_interval() -> f64 {
12278 0.90
12279}
12280
12281impl Default for CashForecastingConfig {
12282 fn default() -> Self {
12283 Self {
12284 enabled: true,
12285 horizon_days: default_horizon_days(),
12286 ar_collection_probability_curve: default_ar_probability_curve(),
12287 confidence_interval: default_confidence_interval(),
12288 }
12289 }
12290}
12291
12292#[derive(Debug, Clone, Serialize, Deserialize)]
12296pub struct CashPoolingConfig {
12297 #[serde(default)]
12299 pub enabled: bool,
12300 #[serde(default = "default_pool_type")]
12302 pub pool_type: String,
12303 #[serde(default = "default_sweep_time")]
12305 pub sweep_time: String,
12306}
12307
12308fn default_pool_type() -> String {
12309 "zero_balancing".to_string()
12310}
12311
12312fn default_sweep_time() -> String {
12313 "16:00".to_string()
12314}
12315
12316impl Default for CashPoolingConfig {
12317 fn default() -> Self {
12318 Self {
12319 enabled: false,
12320 pool_type: default_pool_type(),
12321 sweep_time: default_sweep_time(),
12322 }
12323 }
12324}
12325
12326#[derive(Debug, Clone, Serialize, Deserialize)]
12331pub struct HedgingSchemaConfig {
12332 #[serde(default)]
12334 pub enabled: bool,
12335 #[serde(default = "default_hedge_ratio")]
12337 pub hedge_ratio: f64,
12338 #[serde(default = "default_hedge_instruments")]
12340 pub instruments: Vec<String>,
12341 #[serde(default = "default_true")]
12343 pub hedge_accounting: bool,
12344 #[serde(default = "default_effectiveness_method")]
12346 pub effectiveness_method: String,
12347}
12348
12349fn default_hedge_ratio() -> f64 {
12350 0.75
12351}
12352
12353fn default_hedge_instruments() -> Vec<String> {
12354 vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
12355}
12356
12357fn default_effectiveness_method() -> String {
12358 "regression".to_string()
12359}
12360
12361impl Default for HedgingSchemaConfig {
12362 fn default() -> Self {
12363 Self {
12364 enabled: false,
12365 hedge_ratio: default_hedge_ratio(),
12366 instruments: default_hedge_instruments(),
12367 hedge_accounting: true,
12368 effectiveness_method: default_effectiveness_method(),
12369 }
12370 }
12371}
12372
12373#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12378pub struct DebtSchemaConfig {
12379 #[serde(default)]
12381 pub enabled: bool,
12382 #[serde(default)]
12384 pub instruments: Vec<DebtInstrumentDef>,
12385 #[serde(default)]
12387 pub covenants: Vec<CovenantDef>,
12388}
12389
12390#[derive(Debug, Clone, Serialize, Deserialize)]
12392pub struct DebtInstrumentDef {
12393 #[serde(rename = "type")]
12395 pub instrument_type: String,
12396 #[serde(default)]
12398 pub principal: Option<f64>,
12399 #[serde(default)]
12401 pub rate: Option<f64>,
12402 #[serde(default)]
12404 pub maturity_months: Option<u32>,
12405 #[serde(default)]
12407 pub facility: Option<f64>,
12408}
12409
12410#[derive(Debug, Clone, Serialize, Deserialize)]
12412pub struct CovenantDef {
12413 #[serde(rename = "type")]
12416 pub covenant_type: String,
12417 pub threshold: f64,
12419}
12420
12421#[derive(Debug, Clone, Serialize, Deserialize)]
12425pub struct NettingSchemaConfig {
12426 #[serde(default)]
12428 pub enabled: bool,
12429 #[serde(default = "default_netting_cycle")]
12431 pub cycle: String,
12432}
12433
12434fn default_netting_cycle() -> String {
12435 "monthly".to_string()
12436}
12437
12438impl Default for NettingSchemaConfig {
12439 fn default() -> Self {
12440 Self {
12441 enabled: false,
12442 cycle: default_netting_cycle(),
12443 }
12444 }
12445}
12446
12447#[derive(Debug, Clone, Serialize, Deserialize)]
12451pub struct BankGuaranteeSchemaConfig {
12452 #[serde(default)]
12454 pub enabled: bool,
12455 #[serde(default = "default_guarantee_count")]
12457 pub count: u32,
12458}
12459
12460fn default_guarantee_count() -> u32 {
12461 5
12462}
12463
12464impl Default for BankGuaranteeSchemaConfig {
12465 fn default() -> Self {
12466 Self {
12467 enabled: false,
12468 count: default_guarantee_count(),
12469 }
12470 }
12471}
12472
12473#[derive(Debug, Clone, Serialize, Deserialize)]
12482pub struct ProjectAccountingConfig {
12483 #[serde(default)]
12485 pub enabled: bool,
12486 #[serde(default = "default_project_count")]
12488 pub project_count: u32,
12489 #[serde(default)]
12491 pub project_types: ProjectTypeDistribution,
12492 #[serde(default)]
12494 pub wbs: WbsSchemaConfig,
12495 #[serde(default)]
12497 pub cost_allocation: CostAllocationConfig,
12498 #[serde(default)]
12500 pub revenue_recognition: ProjectRevenueRecognitionConfig,
12501 #[serde(default)]
12503 pub milestones: MilestoneSchemaConfig,
12504 #[serde(default)]
12506 pub change_orders: ChangeOrderSchemaConfig,
12507 #[serde(default)]
12509 pub retainage: RetainageSchemaConfig,
12510 #[serde(default)]
12512 pub earned_value: EarnedValueSchemaConfig,
12513 #[serde(default = "default_project_anomaly_rate")]
12515 pub anomaly_rate: f64,
12516}
12517
12518fn default_project_count() -> u32 {
12519 10
12520}
12521
12522fn default_project_anomaly_rate() -> f64 {
12523 0.03
12524}
12525
12526impl Default for ProjectAccountingConfig {
12527 fn default() -> Self {
12528 Self {
12529 enabled: false,
12530 project_count: default_project_count(),
12531 project_types: ProjectTypeDistribution::default(),
12532 wbs: WbsSchemaConfig::default(),
12533 cost_allocation: CostAllocationConfig::default(),
12534 revenue_recognition: ProjectRevenueRecognitionConfig::default(),
12535 milestones: MilestoneSchemaConfig::default(),
12536 change_orders: ChangeOrderSchemaConfig::default(),
12537 retainage: RetainageSchemaConfig::default(),
12538 earned_value: EarnedValueSchemaConfig::default(),
12539 anomaly_rate: default_project_anomaly_rate(),
12540 }
12541 }
12542}
12543
12544#[derive(Debug, Clone, Serialize, Deserialize)]
12546pub struct ProjectTypeDistribution {
12547 #[serde(default = "default_capital_weight")]
12549 pub capital: f64,
12550 #[serde(default = "default_internal_weight")]
12552 pub internal: f64,
12553 #[serde(default = "default_customer_weight")]
12555 pub customer: f64,
12556 #[serde(default = "default_rnd_weight")]
12558 pub r_and_d: f64,
12559 #[serde(default = "default_maintenance_weight")]
12561 pub maintenance: f64,
12562 #[serde(default = "default_technology_weight")]
12564 pub technology: f64,
12565}
12566
12567fn default_capital_weight() -> f64 {
12568 0.25
12569}
12570fn default_internal_weight() -> f64 {
12571 0.20
12572}
12573fn default_customer_weight() -> f64 {
12574 0.30
12575}
12576fn default_rnd_weight() -> f64 {
12577 0.10
12578}
12579fn default_maintenance_weight() -> f64 {
12580 0.10
12581}
12582fn default_technology_weight() -> f64 {
12583 0.05
12584}
12585
12586impl Default for ProjectTypeDistribution {
12587 fn default() -> Self {
12588 Self {
12589 capital: default_capital_weight(),
12590 internal: default_internal_weight(),
12591 customer: default_customer_weight(),
12592 r_and_d: default_rnd_weight(),
12593 maintenance: default_maintenance_weight(),
12594 technology: default_technology_weight(),
12595 }
12596 }
12597}
12598
12599#[derive(Debug, Clone, Serialize, Deserialize)]
12601pub struct WbsSchemaConfig {
12602 #[serde(default = "default_wbs_max_depth")]
12604 pub max_depth: u32,
12605 #[serde(default = "default_wbs_min_elements")]
12607 pub min_elements_per_level: u32,
12608 #[serde(default = "default_wbs_max_elements")]
12610 pub max_elements_per_level: u32,
12611}
12612
12613fn default_wbs_max_depth() -> u32 {
12614 3
12615}
12616fn default_wbs_min_elements() -> u32 {
12617 2
12618}
12619fn default_wbs_max_elements() -> u32 {
12620 6
12621}
12622
12623impl Default for WbsSchemaConfig {
12624 fn default() -> Self {
12625 Self {
12626 max_depth: default_wbs_max_depth(),
12627 min_elements_per_level: default_wbs_min_elements(),
12628 max_elements_per_level: default_wbs_max_elements(),
12629 }
12630 }
12631}
12632
12633#[derive(Debug, Clone, Serialize, Deserialize)]
12635pub struct CostAllocationConfig {
12636 #[serde(default = "default_time_entry_rate")]
12638 pub time_entry_project_rate: f64,
12639 #[serde(default = "default_expense_rate")]
12641 pub expense_project_rate: f64,
12642 #[serde(default = "default_po_rate")]
12644 pub purchase_order_project_rate: f64,
12645 #[serde(default = "default_vi_rate")]
12647 pub vendor_invoice_project_rate: f64,
12648}
12649
12650fn default_time_entry_rate() -> f64 {
12651 0.60
12652}
12653fn default_expense_rate() -> f64 {
12654 0.30
12655}
12656fn default_po_rate() -> f64 {
12657 0.40
12658}
12659fn default_vi_rate() -> f64 {
12660 0.35
12661}
12662
12663impl Default for CostAllocationConfig {
12664 fn default() -> Self {
12665 Self {
12666 time_entry_project_rate: default_time_entry_rate(),
12667 expense_project_rate: default_expense_rate(),
12668 purchase_order_project_rate: default_po_rate(),
12669 vendor_invoice_project_rate: default_vi_rate(),
12670 }
12671 }
12672}
12673
12674#[derive(Debug, Clone, Serialize, Deserialize)]
12676pub struct ProjectRevenueRecognitionConfig {
12677 #[serde(default = "default_true")]
12679 pub enabled: bool,
12680 #[serde(default = "default_revenue_method")]
12682 pub method: String,
12683 #[serde(default = "default_completion_measure")]
12685 pub completion_measure: String,
12686 #[serde(default = "default_avg_contract_value")]
12688 pub avg_contract_value: f64,
12689}
12690
12691fn default_revenue_method() -> String {
12692 "percentage_of_completion".to_string()
12693}
12694fn default_completion_measure() -> String {
12695 "cost_to_cost".to_string()
12696}
12697fn default_avg_contract_value() -> f64 {
12698 500_000.0
12699}
12700
12701impl Default for ProjectRevenueRecognitionConfig {
12702 fn default() -> Self {
12703 Self {
12704 enabled: true,
12705 method: default_revenue_method(),
12706 completion_measure: default_completion_measure(),
12707 avg_contract_value: default_avg_contract_value(),
12708 }
12709 }
12710}
12711
12712#[derive(Debug, Clone, Serialize, Deserialize)]
12714pub struct MilestoneSchemaConfig {
12715 #[serde(default = "default_true")]
12717 pub enabled: bool,
12718 #[serde(default = "default_milestones_per_project")]
12720 pub avg_per_project: u32,
12721 #[serde(default = "default_payment_milestone_rate")]
12723 pub payment_milestone_rate: f64,
12724}
12725
12726fn default_milestones_per_project() -> u32 {
12727 4
12728}
12729fn default_payment_milestone_rate() -> f64 {
12730 0.50
12731}
12732
12733impl Default for MilestoneSchemaConfig {
12734 fn default() -> Self {
12735 Self {
12736 enabled: true,
12737 avg_per_project: default_milestones_per_project(),
12738 payment_milestone_rate: default_payment_milestone_rate(),
12739 }
12740 }
12741}
12742
12743#[derive(Debug, Clone, Serialize, Deserialize)]
12745pub struct ChangeOrderSchemaConfig {
12746 #[serde(default = "default_true")]
12748 pub enabled: bool,
12749 #[serde(default = "default_change_order_probability")]
12751 pub probability: f64,
12752 #[serde(default = "default_max_change_orders")]
12754 pub max_per_project: u32,
12755 #[serde(default = "default_change_order_approval_rate")]
12757 pub approval_rate: f64,
12758}
12759
12760fn default_change_order_probability() -> f64 {
12761 0.40
12762}
12763fn default_max_change_orders() -> u32 {
12764 3
12765}
12766fn default_change_order_approval_rate() -> f64 {
12767 0.75
12768}
12769
12770impl Default for ChangeOrderSchemaConfig {
12771 fn default() -> Self {
12772 Self {
12773 enabled: true,
12774 probability: default_change_order_probability(),
12775 max_per_project: default_max_change_orders(),
12776 approval_rate: default_change_order_approval_rate(),
12777 }
12778 }
12779}
12780
12781#[derive(Debug, Clone, Serialize, Deserialize)]
12783pub struct RetainageSchemaConfig {
12784 #[serde(default)]
12786 pub enabled: bool,
12787 #[serde(default = "default_retainage_pct")]
12789 pub default_percentage: f64,
12790}
12791
12792fn default_retainage_pct() -> f64 {
12793 0.10
12794}
12795
12796impl Default for RetainageSchemaConfig {
12797 fn default() -> Self {
12798 Self {
12799 enabled: false,
12800 default_percentage: default_retainage_pct(),
12801 }
12802 }
12803}
12804
12805#[derive(Debug, Clone, Serialize, Deserialize)]
12807pub struct EarnedValueSchemaConfig {
12808 #[serde(default = "default_true")]
12810 pub enabled: bool,
12811 #[serde(default = "default_evm_frequency")]
12813 pub frequency: String,
12814}
12815
12816fn default_evm_frequency() -> String {
12817 "monthly".to_string()
12818}
12819
12820impl Default for EarnedValueSchemaConfig {
12821 fn default() -> Self {
12822 Self {
12823 enabled: true,
12824 frequency: default_evm_frequency(),
12825 }
12826 }
12827}
12828
12829#[derive(Debug, Clone, Serialize, Deserialize)]
12835pub struct EsgConfig {
12836 #[serde(default)]
12838 pub enabled: bool,
12839 #[serde(default)]
12841 pub environmental: EnvironmentalConfig,
12842 #[serde(default)]
12844 pub social: SocialConfig,
12845 #[serde(default)]
12847 pub governance: GovernanceSchemaConfig,
12848 #[serde(default)]
12850 pub supply_chain_esg: SupplyChainEsgConfig,
12851 #[serde(default)]
12853 pub reporting: EsgReportingConfig,
12854 #[serde(default)]
12856 pub climate_scenarios: ClimateScenarioConfig,
12857 #[serde(default = "default_esg_anomaly_rate")]
12859 pub anomaly_rate: f64,
12860}
12861
12862fn default_esg_anomaly_rate() -> f64 {
12863 0.02
12864}
12865
12866impl Default for EsgConfig {
12867 fn default() -> Self {
12868 Self {
12869 enabled: false,
12870 environmental: EnvironmentalConfig::default(),
12871 social: SocialConfig::default(),
12872 governance: GovernanceSchemaConfig::default(),
12873 supply_chain_esg: SupplyChainEsgConfig::default(),
12874 reporting: EsgReportingConfig::default(),
12875 climate_scenarios: ClimateScenarioConfig::default(),
12876 anomaly_rate: default_esg_anomaly_rate(),
12877 }
12878 }
12879}
12880
12881#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12886pub struct CountryPacksSchemaConfig {
12887 #[serde(default)]
12889 pub external_dir: Option<PathBuf>,
12890 #[serde(default)]
12894 pub overrides: std::collections::HashMap<String, serde_json::Value>,
12895}
12896
12897#[derive(Debug, Clone, Serialize, Deserialize)]
12899pub struct EnvironmentalConfig {
12900 #[serde(default = "default_true")]
12902 pub enabled: bool,
12903 #[serde(default)]
12905 pub scope1: EmissionScopeConfig,
12906 #[serde(default)]
12908 pub scope2: EmissionScopeConfig,
12909 #[serde(default)]
12911 pub scope3: Scope3Config,
12912 #[serde(default)]
12914 pub energy: EnergySchemaConfig,
12915 #[serde(default)]
12917 pub water: WaterSchemaConfig,
12918 #[serde(default)]
12920 pub waste: WasteSchemaConfig,
12921}
12922
12923impl Default for EnvironmentalConfig {
12924 fn default() -> Self {
12925 Self {
12926 enabled: true,
12927 scope1: EmissionScopeConfig::default(),
12928 scope2: EmissionScopeConfig::default(),
12929 scope3: Scope3Config::default(),
12930 energy: EnergySchemaConfig::default(),
12931 water: WaterSchemaConfig::default(),
12932 waste: WasteSchemaConfig::default(),
12933 }
12934 }
12935}
12936
12937#[derive(Debug, Clone, Serialize, Deserialize)]
12939pub struct EmissionScopeConfig {
12940 #[serde(default = "default_true")]
12942 pub enabled: bool,
12943 #[serde(default = "default_emission_region")]
12945 pub factor_region: String,
12946}
12947
12948fn default_emission_region() -> String {
12949 "US".to_string()
12950}
12951
12952impl Default for EmissionScopeConfig {
12953 fn default() -> Self {
12954 Self {
12955 enabled: true,
12956 factor_region: default_emission_region(),
12957 }
12958 }
12959}
12960
12961#[derive(Debug, Clone, Serialize, Deserialize)]
12963pub struct Scope3Config {
12964 #[serde(default = "default_true")]
12966 pub enabled: bool,
12967 #[serde(default = "default_scope3_categories")]
12969 pub categories: Vec<String>,
12970 #[serde(default = "default_spend_intensity")]
12972 pub default_spend_intensity_kg_per_usd: f64,
12973}
12974
12975fn default_scope3_categories() -> Vec<String> {
12976 vec![
12977 "purchased_goods".to_string(),
12978 "business_travel".to_string(),
12979 "employee_commuting".to_string(),
12980 ]
12981}
12982
12983fn default_spend_intensity() -> f64 {
12984 0.5
12985}
12986
12987impl Default for Scope3Config {
12988 fn default() -> Self {
12989 Self {
12990 enabled: true,
12991 categories: default_scope3_categories(),
12992 default_spend_intensity_kg_per_usd: default_spend_intensity(),
12993 }
12994 }
12995}
12996
12997#[derive(Debug, Clone, Serialize, Deserialize)]
12999pub struct EnergySchemaConfig {
13000 #[serde(default = "default_true")]
13002 pub enabled: bool,
13003 #[serde(default = "default_facility_count")]
13005 pub facility_count: u32,
13006 #[serde(default = "default_renewable_target")]
13008 pub renewable_target: f64,
13009}
13010
13011fn default_facility_count() -> u32 {
13012 5
13013}
13014
13015fn default_renewable_target() -> f64 {
13016 0.30
13017}
13018
13019impl Default for EnergySchemaConfig {
13020 fn default() -> Self {
13021 Self {
13022 enabled: true,
13023 facility_count: default_facility_count(),
13024 renewable_target: default_renewable_target(),
13025 }
13026 }
13027}
13028
13029#[derive(Debug, Clone, Serialize, Deserialize)]
13031pub struct WaterSchemaConfig {
13032 #[serde(default = "default_true")]
13034 pub enabled: bool,
13035 #[serde(default = "default_water_facility_count")]
13037 pub facility_count: u32,
13038}
13039
13040fn default_water_facility_count() -> u32 {
13041 3
13042}
13043
13044impl Default for WaterSchemaConfig {
13045 fn default() -> Self {
13046 Self {
13047 enabled: true,
13048 facility_count: default_water_facility_count(),
13049 }
13050 }
13051}
13052
13053#[derive(Debug, Clone, Serialize, Deserialize)]
13055pub struct WasteSchemaConfig {
13056 #[serde(default = "default_true")]
13058 pub enabled: bool,
13059 #[serde(default = "default_diversion_target")]
13061 pub diversion_target: f64,
13062}
13063
13064fn default_diversion_target() -> f64 {
13065 0.50
13066}
13067
13068impl Default for WasteSchemaConfig {
13069 fn default() -> Self {
13070 Self {
13071 enabled: true,
13072 diversion_target: default_diversion_target(),
13073 }
13074 }
13075}
13076
13077#[derive(Debug, Clone, Serialize, Deserialize)]
13079pub struct SocialConfig {
13080 #[serde(default = "default_true")]
13082 pub enabled: bool,
13083 #[serde(default)]
13085 pub diversity: DiversitySchemaConfig,
13086 #[serde(default)]
13088 pub pay_equity: PayEquitySchemaConfig,
13089 #[serde(default)]
13091 pub safety: SafetySchemaConfig,
13092}
13093
13094impl Default for SocialConfig {
13095 fn default() -> Self {
13096 Self {
13097 enabled: true,
13098 diversity: DiversitySchemaConfig::default(),
13099 pay_equity: PayEquitySchemaConfig::default(),
13100 safety: SafetySchemaConfig::default(),
13101 }
13102 }
13103}
13104
13105#[derive(Debug, Clone, Serialize, Deserialize)]
13107pub struct DiversitySchemaConfig {
13108 #[serde(default = "default_true")]
13110 pub enabled: bool,
13111 #[serde(default = "default_diversity_dimensions")]
13113 pub dimensions: Vec<String>,
13114}
13115
13116fn default_diversity_dimensions() -> Vec<String> {
13117 vec![
13118 "gender".to_string(),
13119 "ethnicity".to_string(),
13120 "age_group".to_string(),
13121 ]
13122}
13123
13124impl Default for DiversitySchemaConfig {
13125 fn default() -> Self {
13126 Self {
13127 enabled: true,
13128 dimensions: default_diversity_dimensions(),
13129 }
13130 }
13131}
13132
13133#[derive(Debug, Clone, Serialize, Deserialize)]
13135pub struct PayEquitySchemaConfig {
13136 #[serde(default = "default_true")]
13138 pub enabled: bool,
13139 #[serde(default = "default_pay_gap_threshold")]
13141 pub gap_threshold: f64,
13142}
13143
13144fn default_pay_gap_threshold() -> f64 {
13145 0.05
13146}
13147
13148impl Default for PayEquitySchemaConfig {
13149 fn default() -> Self {
13150 Self {
13151 enabled: true,
13152 gap_threshold: default_pay_gap_threshold(),
13153 }
13154 }
13155}
13156
13157#[derive(Debug, Clone, Serialize, Deserialize)]
13159pub struct SafetySchemaConfig {
13160 #[serde(default = "default_true")]
13162 pub enabled: bool,
13163 #[serde(default = "default_trir_target")]
13165 pub target_trir: f64,
13166 #[serde(default = "default_incident_count")]
13168 pub incident_count: u32,
13169}
13170
13171fn default_trir_target() -> f64 {
13172 2.5
13173}
13174
13175fn default_incident_count() -> u32 {
13176 20
13177}
13178
13179impl Default for SafetySchemaConfig {
13180 fn default() -> Self {
13181 Self {
13182 enabled: true,
13183 target_trir: default_trir_target(),
13184 incident_count: default_incident_count(),
13185 }
13186 }
13187}
13188
13189#[derive(Debug, Clone, Serialize, Deserialize)]
13191pub struct GovernanceSchemaConfig {
13192 #[serde(default = "default_true")]
13194 pub enabled: bool,
13195 #[serde(default = "default_board_size")]
13197 pub board_size: u32,
13198 #[serde(default = "default_independence_target")]
13200 pub independence_target: f64,
13201}
13202
13203fn default_board_size() -> u32 {
13204 11
13205}
13206
13207fn default_independence_target() -> f64 {
13208 0.67
13209}
13210
13211impl Default for GovernanceSchemaConfig {
13212 fn default() -> Self {
13213 Self {
13214 enabled: true,
13215 board_size: default_board_size(),
13216 independence_target: default_independence_target(),
13217 }
13218 }
13219}
13220
13221#[derive(Debug, Clone, Serialize, Deserialize)]
13223pub struct SupplyChainEsgConfig {
13224 #[serde(default = "default_true")]
13226 pub enabled: bool,
13227 #[serde(default = "default_assessment_coverage")]
13229 pub assessment_coverage: f64,
13230 #[serde(default = "default_high_risk_countries")]
13232 pub high_risk_countries: Vec<String>,
13233}
13234
13235fn default_assessment_coverage() -> f64 {
13236 0.80
13237}
13238
13239fn default_high_risk_countries() -> Vec<String> {
13240 vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
13241}
13242
13243impl Default for SupplyChainEsgConfig {
13244 fn default() -> Self {
13245 Self {
13246 enabled: true,
13247 assessment_coverage: default_assessment_coverage(),
13248 high_risk_countries: default_high_risk_countries(),
13249 }
13250 }
13251}
13252
13253#[derive(Debug, Clone, Serialize, Deserialize)]
13255pub struct EsgReportingConfig {
13256 #[serde(default = "default_true")]
13258 pub enabled: bool,
13259 #[serde(default = "default_esg_frameworks")]
13261 pub frameworks: Vec<String>,
13262 #[serde(default = "default_true")]
13264 pub materiality_assessment: bool,
13265 #[serde(default = "default_materiality_threshold")]
13267 pub impact_threshold: f64,
13268 #[serde(default = "default_materiality_threshold")]
13270 pub financial_threshold: f64,
13271}
13272
13273fn default_esg_frameworks() -> Vec<String> {
13274 vec!["GRI".to_string(), "ESRS".to_string()]
13275}
13276
13277fn default_materiality_threshold() -> f64 {
13278 0.6
13279}
13280
13281impl Default for EsgReportingConfig {
13282 fn default() -> Self {
13283 Self {
13284 enabled: true,
13285 frameworks: default_esg_frameworks(),
13286 materiality_assessment: true,
13287 impact_threshold: default_materiality_threshold(),
13288 financial_threshold: default_materiality_threshold(),
13289 }
13290 }
13291}
13292
13293#[derive(Debug, Clone, Serialize, Deserialize)]
13295pub struct ClimateScenarioConfig {
13296 #[serde(default)]
13298 pub enabled: bool,
13299 #[serde(default = "default_climate_scenarios")]
13301 pub scenarios: Vec<String>,
13302 #[serde(default = "default_time_horizons")]
13304 pub time_horizons: Vec<u32>,
13305}
13306
13307fn default_climate_scenarios() -> Vec<String> {
13308 vec![
13309 "net_zero_2050".to_string(),
13310 "stated_policies".to_string(),
13311 "current_trajectory".to_string(),
13312 ]
13313}
13314
13315fn default_time_horizons() -> Vec<u32> {
13316 vec![5, 10, 30]
13317}
13318
13319impl Default for ClimateScenarioConfig {
13320 fn default() -> Self {
13321 Self {
13322 enabled: false,
13323 scenarios: default_climate_scenarios(),
13324 time_horizons: default_time_horizons(),
13325 }
13326 }
13327}
13328
13329#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13333pub struct ScenariosConfig {
13334 #[serde(default)]
13336 pub enabled: bool,
13337 #[serde(default)]
13339 pub scenarios: Vec<ScenarioSchemaConfig>,
13340 #[serde(default)]
13342 pub causal_model: CausalModelSchemaConfig,
13343 #[serde(default)]
13345 pub defaults: ScenarioDefaultsConfig,
13346 #[serde(default)]
13349 pub generate_counterfactuals: bool,
13350}
13351
13352#[derive(Debug, Clone, Serialize, Deserialize)]
13354pub struct ScenarioSchemaConfig {
13355 pub name: String,
13357 #[serde(default)]
13359 pub description: String,
13360 #[serde(default)]
13362 pub tags: Vec<String>,
13363 pub base: Option<String>,
13365 pub probability_weight: Option<f64>,
13367 #[serde(default)]
13369 pub interventions: Vec<InterventionSchemaConfig>,
13370 #[serde(default)]
13372 pub constraints: ScenarioConstraintsSchemaConfig,
13373 #[serde(default)]
13375 pub output: ScenarioOutputSchemaConfig,
13376 #[serde(default)]
13378 pub metadata: std::collections::HashMap<String, String>,
13379}
13380
13381#[derive(Debug, Clone, Serialize, Deserialize)]
13383pub struct InterventionSchemaConfig {
13384 #[serde(flatten)]
13386 pub intervention_type: serde_json::Value,
13387 #[serde(default)]
13389 pub timing: InterventionTimingSchemaConfig,
13390 pub label: Option<String>,
13392 #[serde(default)]
13394 pub priority: u32,
13395}
13396
13397#[derive(Debug, Clone, Serialize, Deserialize)]
13399pub struct InterventionTimingSchemaConfig {
13400 #[serde(default = "default_start_month")]
13402 pub start_month: u32,
13403 pub duration_months: Option<u32>,
13405 #[serde(default = "default_onset")]
13407 pub onset: String,
13408 pub ramp_months: Option<u32>,
13410}
13411
13412fn default_start_month() -> u32 {
13413 1
13414}
13415
13416fn default_onset() -> String {
13417 "sudden".to_string()
13418}
13419
13420impl Default for InterventionTimingSchemaConfig {
13421 fn default() -> Self {
13422 Self {
13423 start_month: 1,
13424 duration_months: None,
13425 onset: "sudden".to_string(),
13426 ramp_months: None,
13427 }
13428 }
13429}
13430
13431#[derive(Debug, Clone, Serialize, Deserialize)]
13433pub struct ScenarioConstraintsSchemaConfig {
13434 #[serde(default = "default_true")]
13435 pub preserve_accounting_identity: bool,
13436 #[serde(default = "default_true")]
13437 pub preserve_document_chains: bool,
13438 #[serde(default = "default_true")]
13439 pub preserve_period_close: bool,
13440 #[serde(default = "default_true")]
13441 pub preserve_balance_coherence: bool,
13442 #[serde(default)]
13443 pub custom: Vec<CustomConstraintSchemaConfig>,
13444}
13445
13446impl Default for ScenarioConstraintsSchemaConfig {
13447 fn default() -> Self {
13448 Self {
13449 preserve_accounting_identity: true,
13450 preserve_document_chains: true,
13451 preserve_period_close: true,
13452 preserve_balance_coherence: true,
13453 custom: Vec::new(),
13454 }
13455 }
13456}
13457
13458#[derive(Debug, Clone, Serialize, Deserialize)]
13460pub struct CustomConstraintSchemaConfig {
13461 pub config_path: String,
13462 pub min: Option<f64>,
13463 pub max: Option<f64>,
13464 #[serde(default)]
13465 pub description: String,
13466}
13467
13468#[derive(Debug, Clone, Serialize, Deserialize)]
13470pub struct ScenarioOutputSchemaConfig {
13471 #[serde(default = "default_true")]
13472 pub paired: bool,
13473 #[serde(default = "default_diff_formats_schema")]
13474 pub diff_formats: Vec<String>,
13475 #[serde(default)]
13476 pub diff_scope: Vec<String>,
13477}
13478
13479fn default_diff_formats_schema() -> Vec<String> {
13480 vec!["summary".to_string(), "aggregate".to_string()]
13481}
13482
13483impl Default for ScenarioOutputSchemaConfig {
13484 fn default() -> Self {
13485 Self {
13486 paired: true,
13487 diff_formats: default_diff_formats_schema(),
13488 diff_scope: Vec::new(),
13489 }
13490 }
13491}
13492
13493#[derive(Debug, Clone, Serialize, Deserialize)]
13495pub struct CausalModelSchemaConfig {
13496 #[serde(default = "default_causal_preset")]
13498 pub preset: String,
13499 #[serde(default)]
13501 pub nodes: Vec<serde_json::Value>,
13502 #[serde(default)]
13504 pub edges: Vec<serde_json::Value>,
13505}
13506
13507fn default_causal_preset() -> String {
13508 "default".to_string()
13509}
13510
13511impl Default for CausalModelSchemaConfig {
13512 fn default() -> Self {
13513 Self {
13514 preset: "default".to_string(),
13515 nodes: Vec::new(),
13516 edges: Vec::new(),
13517 }
13518 }
13519}
13520
13521#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13523pub struct ScenarioDefaultsConfig {
13524 #[serde(default)]
13525 pub constraints: ScenarioConstraintsSchemaConfig,
13526 #[serde(default)]
13527 pub output: ScenarioOutputSchemaConfig,
13528}
13529
13530#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13563pub struct ComplianceRegulationsConfig {
13564 #[serde(default)]
13566 pub enabled: bool,
13567 #[serde(default)]
13570 pub jurisdictions: Vec<String>,
13571 #[serde(default)]
13574 pub reference_date: Option<String>,
13575 #[serde(default)]
13577 pub standards_selection: StandardsSelectionConfig,
13578 #[serde(default)]
13580 pub audit_procedures: AuditProcedureGenConfig,
13581 #[serde(default)]
13583 pub findings: ComplianceFindingGenConfig,
13584 #[serde(default)]
13586 pub filings: ComplianceFilingGenConfig,
13587 #[serde(default)]
13589 pub graph: ComplianceGraphConfig,
13590 #[serde(default)]
13592 pub output: ComplianceOutputConfig,
13593 #[serde(default)]
13598 pub legal_documents: LegalDocumentsConfig,
13599}
13600
13601#[derive(Debug, Clone, Serialize, Deserialize)]
13606pub struct LegalDocumentsConfig {
13607 #[serde(default)]
13609 pub enabled: bool,
13610 #[serde(default = "default_legal_opinion_probability")]
13612 pub legal_opinion_probability: f64,
13613}
13614
13615fn default_legal_opinion_probability() -> f64 {
13616 0.40
13617}
13618
13619impl Default for LegalDocumentsConfig {
13620 fn default() -> Self {
13621 Self {
13622 enabled: false,
13623 legal_opinion_probability: default_legal_opinion_probability(),
13624 }
13625 }
13626}
13627
13628#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13630pub struct StandardsSelectionConfig {
13631 #[serde(default)]
13634 pub categories: Vec<String>,
13635 #[serde(default)]
13638 pub include: Vec<String>,
13639 #[serde(default)]
13641 pub exclude: Vec<String>,
13642 #[serde(default)]
13644 pub include_superseded: bool,
13645}
13646
13647#[derive(Debug, Clone, Serialize, Deserialize)]
13649pub struct AuditProcedureGenConfig {
13650 #[serde(default)]
13652 pub enabled: bool,
13653 #[serde(default = "default_procedures_per_standard")]
13655 pub procedures_per_standard: usize,
13656 #[serde(default = "default_sampling_method")]
13658 pub sampling_method: String,
13659 #[serde(default = "default_confidence_level")]
13661 pub confidence_level: f64,
13662 #[serde(default = "default_tolerable_misstatement")]
13664 pub tolerable_misstatement: f64,
13665}
13666
13667fn default_procedures_per_standard() -> usize {
13668 3
13669}
13670
13671fn default_sampling_method() -> String {
13672 "statistical".to_string()
13673}
13674
13675fn default_confidence_level() -> f64 {
13676 0.95
13677}
13678
13679fn default_tolerable_misstatement() -> f64 {
13680 0.05
13681}
13682
13683impl Default for AuditProcedureGenConfig {
13684 fn default() -> Self {
13685 Self {
13686 enabled: false,
13687 procedures_per_standard: default_procedures_per_standard(),
13688 sampling_method: default_sampling_method(),
13689 confidence_level: default_confidence_level(),
13690 tolerable_misstatement: default_tolerable_misstatement(),
13691 }
13692 }
13693}
13694
13695#[derive(Debug, Clone, Serialize, Deserialize)]
13697pub struct ComplianceFindingGenConfig {
13698 #[serde(default)]
13700 pub enabled: bool,
13701 #[serde(default = "default_finding_rate")]
13703 pub finding_rate: f64,
13704 #[serde(default = "default_cr_material_weakness_rate")]
13706 pub material_weakness_rate: f64,
13707 #[serde(default = "default_cr_significant_deficiency_rate")]
13709 pub significant_deficiency_rate: f64,
13710 #[serde(default = "default_true")]
13712 pub generate_remediation: bool,
13713}
13714
13715fn default_finding_rate() -> f64 {
13716 0.05
13717}
13718
13719fn default_cr_material_weakness_rate() -> f64 {
13720 0.02
13721}
13722
13723fn default_cr_significant_deficiency_rate() -> f64 {
13724 0.08
13725}
13726
13727impl Default for ComplianceFindingGenConfig {
13728 fn default() -> Self {
13729 Self {
13730 enabled: false,
13731 finding_rate: default_finding_rate(),
13732 material_weakness_rate: default_cr_material_weakness_rate(),
13733 significant_deficiency_rate: default_cr_significant_deficiency_rate(),
13734 generate_remediation: true,
13735 }
13736 }
13737}
13738
13739#[derive(Debug, Clone, Serialize, Deserialize)]
13741pub struct ComplianceFilingGenConfig {
13742 #[serde(default)]
13744 pub enabled: bool,
13745 #[serde(default)]
13748 pub filing_types: Vec<String>,
13749 #[serde(default = "default_true")]
13751 pub generate_status_progression: bool,
13752}
13753
13754impl Default for ComplianceFilingGenConfig {
13755 fn default() -> Self {
13756 Self {
13757 enabled: false,
13758 filing_types: Vec::new(),
13759 generate_status_progression: true,
13760 }
13761 }
13762}
13763
13764#[derive(Debug, Clone, Serialize, Deserialize)]
13766pub struct ComplianceGraphConfig {
13767 #[serde(default)]
13769 pub enabled: bool,
13770 #[serde(default = "default_true")]
13772 pub include_compliance_nodes: bool,
13773 #[serde(default = "default_true")]
13775 pub include_compliance_edges: bool,
13776 #[serde(default = "default_true")]
13778 pub include_cross_references: bool,
13779 #[serde(default)]
13781 pub include_supersession_edges: bool,
13782 #[serde(default = "default_true")]
13784 pub include_account_links: bool,
13785 #[serde(default = "default_true")]
13787 pub include_control_links: bool,
13788 #[serde(default = "default_true")]
13790 pub include_company_links: bool,
13791}
13792
13793impl Default for ComplianceGraphConfig {
13794 fn default() -> Self {
13795 Self {
13796 enabled: false,
13797 include_compliance_nodes: true,
13798 include_compliance_edges: true,
13799 include_cross_references: true,
13800 include_supersession_edges: false,
13801 include_account_links: true,
13802 include_control_links: true,
13803 include_company_links: true,
13804 }
13805 }
13806}
13807
13808#[derive(Debug, Clone, Serialize, Deserialize)]
13810pub struct ComplianceOutputConfig {
13811 #[serde(default = "default_true")]
13813 pub export_registry: bool,
13814 #[serde(default = "default_true")]
13816 pub export_jurisdictions: bool,
13817 #[serde(default = "default_true")]
13819 pub export_cross_references: bool,
13820 #[serde(default)]
13822 pub export_version_history: bool,
13823}
13824
13825impl Default for ComplianceOutputConfig {
13826 fn default() -> Self {
13827 Self {
13828 export_registry: true,
13829 export_jurisdictions: true,
13830 export_cross_references: true,
13831 export_version_history: false,
13832 }
13833 }
13834}
13835
13836#[cfg(test)]
13837#[allow(clippy::unwrap_used)]
13838mod tests {
13839 use super::*;
13840 use crate::presets::demo_preset;
13841
13842 #[test]
13847 fn test_config_yaml_roundtrip() {
13848 let config = demo_preset();
13849 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
13850 let deserialized: GeneratorConfig =
13851 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
13852
13853 assert_eq!(
13854 config.global.period_months,
13855 deserialized.global.period_months
13856 );
13857 assert_eq!(config.global.industry, deserialized.global.industry);
13858 assert_eq!(config.companies.len(), deserialized.companies.len());
13859 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
13860 }
13861
13862 #[test]
13863 fn test_config_json_roundtrip() {
13864 let mut config = demo_preset();
13866 config.master_data.employees.approval_limits.executive = 1e12;
13868
13869 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
13870 let deserialized: GeneratorConfig =
13871 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
13872
13873 assert_eq!(
13874 config.global.period_months,
13875 deserialized.global.period_months
13876 );
13877 assert_eq!(config.global.industry, deserialized.global.industry);
13878 assert_eq!(config.companies.len(), deserialized.companies.len());
13879 }
13880
13881 #[test]
13882 fn test_transaction_volume_serialization() {
13883 let volumes = vec![
13885 (TransactionVolume::TenK, "ten_k"),
13886 (TransactionVolume::HundredK, "hundred_k"),
13887 (TransactionVolume::OneM, "one_m"),
13888 (TransactionVolume::TenM, "ten_m"),
13889 (TransactionVolume::HundredM, "hundred_m"),
13890 ];
13891
13892 for (volume, expected_key) in volumes {
13893 let json = serde_json::to_string(&volume).expect("Failed to serialize");
13894 assert!(
13895 json.contains(expected_key),
13896 "Expected {} in JSON: {}",
13897 expected_key,
13898 json
13899 );
13900 }
13901 }
13902
13903 #[test]
13904 fn test_transaction_volume_custom_serialization() {
13905 let volume = TransactionVolume::Custom(12345);
13906 let json = serde_json::to_string(&volume).expect("Failed to serialize");
13907 let deserialized: TransactionVolume =
13908 serde_json::from_str(&json).expect("Failed to deserialize");
13909 assert_eq!(deserialized.count(), 12345);
13910 }
13911
13912 #[test]
13913 fn test_output_mode_serialization() {
13914 let modes = vec![
13915 OutputMode::Streaming,
13916 OutputMode::FlatFile,
13917 OutputMode::Both,
13918 ];
13919
13920 for mode in modes {
13921 let json = serde_json::to_string(&mode).expect("Failed to serialize");
13922 let deserialized: OutputMode =
13923 serde_json::from_str(&json).expect("Failed to deserialize");
13924 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
13925 }
13926 }
13927
13928 #[test]
13929 fn test_file_format_serialization() {
13930 let formats = vec![
13931 FileFormat::Csv,
13932 FileFormat::Parquet,
13933 FileFormat::Json,
13934 FileFormat::JsonLines,
13935 ];
13936
13937 for format in formats {
13938 let json = serde_json::to_string(&format).expect("Failed to serialize");
13939 let deserialized: FileFormat =
13940 serde_json::from_str(&json).expect("Failed to deserialize");
13941 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
13942 }
13943 }
13944
13945 #[test]
13946 fn test_compression_algorithm_serialization() {
13947 let algos = vec![
13948 CompressionAlgorithm::Gzip,
13949 CompressionAlgorithm::Zstd,
13950 CompressionAlgorithm::Lz4,
13951 CompressionAlgorithm::Snappy,
13952 ];
13953
13954 for algo in algos {
13955 let json = serde_json::to_string(&algo).expect("Failed to serialize");
13956 let deserialized: CompressionAlgorithm =
13957 serde_json::from_str(&json).expect("Failed to deserialize");
13958 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
13959 }
13960 }
13961
13962 #[test]
13963 fn test_transfer_pricing_method_serialization() {
13964 let methods = vec![
13965 TransferPricingMethod::CostPlus,
13966 TransferPricingMethod::ComparableUncontrolled,
13967 TransferPricingMethod::ResalePrice,
13968 TransferPricingMethod::TransactionalNetMargin,
13969 TransferPricingMethod::ProfitSplit,
13970 ];
13971
13972 for method in methods {
13973 let json = serde_json::to_string(&method).expect("Failed to serialize");
13974 let deserialized: TransferPricingMethod =
13975 serde_json::from_str(&json).expect("Failed to deserialize");
13976 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
13977 }
13978 }
13979
13980 #[test]
13981 fn test_benford_exemption_serialization() {
13982 let exemptions = vec![
13983 BenfordExemption::Recurring,
13984 BenfordExemption::Payroll,
13985 BenfordExemption::FixedFees,
13986 BenfordExemption::RoundAmounts,
13987 ];
13988
13989 for exemption in exemptions {
13990 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
13991 let deserialized: BenfordExemption =
13992 serde_json::from_str(&json).expect("Failed to deserialize");
13993 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
13994 }
13995 }
13996
13997 #[test]
14002 fn test_global_config_defaults() {
14003 let yaml = r#"
14004 industry: manufacturing
14005 start_date: "2024-01-01"
14006 period_months: 6
14007 "#;
14008 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14009 assert_eq!(config.group_currency, "USD");
14010 assert!(config.parallel);
14011 assert_eq!(config.worker_threads, 0);
14012 assert_eq!(config.memory_limit_mb, 0);
14013 }
14014
14015 #[test]
14016 fn test_fraud_config_defaults() {
14017 let config = FraudConfig::default();
14018 assert!(!config.enabled);
14019 assert_eq!(config.fraud_rate, 0.005);
14020 assert!(!config.clustering_enabled);
14021 }
14022
14023 #[test]
14024 fn test_internal_controls_config_defaults() {
14025 let config = InternalControlsConfig::default();
14026 assert!(!config.enabled);
14027 assert_eq!(config.exception_rate, 0.02);
14028 assert_eq!(config.sod_violation_rate, 0.01);
14029 assert!(config.export_control_master_data);
14030 assert_eq!(config.sox_materiality_threshold, 10000.0);
14031 assert!(config.coso_enabled);
14033 assert!(!config.include_entity_level_controls);
14034 assert_eq!(config.target_maturity_level, "mixed");
14035 }
14036
14037 #[test]
14038 fn test_output_config_defaults() {
14039 let config = OutputConfig::default();
14040 assert!(matches!(config.mode, OutputMode::FlatFile));
14041 assert_eq!(config.formats, vec![FileFormat::Parquet]);
14042 assert!(config.compression.enabled);
14043 assert!(matches!(
14044 config.compression.algorithm,
14045 CompressionAlgorithm::Zstd
14046 ));
14047 assert!(config.include_acdoca);
14048 assert!(!config.include_bseg);
14049 assert!(config.partition_by_period);
14050 assert!(!config.partition_by_company);
14051 }
14052
14053 #[test]
14054 fn test_approval_config_defaults() {
14055 let config = ApprovalConfig::default();
14056 assert!(!config.enabled);
14057 assert_eq!(config.auto_approve_threshold, 1000.0);
14058 assert_eq!(config.rejection_rate, 0.02);
14059 assert_eq!(config.revision_rate, 0.05);
14060 assert_eq!(config.average_approval_delay_hours, 4.0);
14061 assert_eq!(config.thresholds.len(), 4);
14062 }
14063
14064 #[test]
14065 fn test_p2p_flow_config_defaults() {
14066 let config = P2PFlowConfig::default();
14067 assert!(config.enabled);
14068 assert_eq!(config.three_way_match_rate, 0.95);
14069 assert_eq!(config.partial_delivery_rate, 0.15);
14070 assert_eq!(config.average_po_to_gr_days, 14);
14071 }
14072
14073 #[test]
14074 fn test_o2c_flow_config_defaults() {
14075 let config = O2CFlowConfig::default();
14076 assert!(config.enabled);
14077 assert_eq!(config.credit_check_failure_rate, 0.02);
14078 assert_eq!(config.return_rate, 0.03);
14079 assert_eq!(config.bad_debt_rate, 0.01);
14080 }
14081
14082 #[test]
14083 fn test_balance_config_defaults() {
14084 let config = BalanceConfig::default();
14085 assert!(!config.generate_opening_balances);
14086 assert!(config.generate_trial_balances);
14087 assert_eq!(config.target_gross_margin, 0.35);
14088 assert!(config.validate_balance_equation);
14089 assert!(config.reconcile_subledgers);
14090 }
14091
14092 #[test]
14097 fn test_partial_config_with_defaults() {
14098 let yaml = r#"
14100 global:
14101 industry: manufacturing
14102 start_date: "2024-01-01"
14103 period_months: 3
14104 companies:
14105 - code: "TEST"
14106 name: "Test Company"
14107 currency: "USD"
14108 country: "US"
14109 annual_transaction_volume: ten_k
14110 chart_of_accounts:
14111 complexity: small
14112 output:
14113 output_directory: "./output"
14114 "#;
14115
14116 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14117 assert_eq!(config.global.period_months, 3);
14118 assert_eq!(config.companies.len(), 1);
14119 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
14122
14123 #[test]
14124 fn test_config_with_fraud_enabled() {
14125 let yaml = r#"
14126 global:
14127 industry: retail
14128 start_date: "2024-01-01"
14129 period_months: 12
14130 companies:
14131 - code: "RETAIL"
14132 name: "Retail Co"
14133 currency: "USD"
14134 country: "US"
14135 annual_transaction_volume: hundred_k
14136 chart_of_accounts:
14137 complexity: medium
14138 output:
14139 output_directory: "./output"
14140 fraud:
14141 enabled: true
14142 fraud_rate: 0.05
14143 clustering_enabled: true
14144 "#;
14145
14146 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14147 assert!(config.fraud.enabled);
14148 assert_eq!(config.fraud.fraud_rate, 0.05);
14149 assert!(config.fraud.clustering_enabled);
14150 }
14151
14152 #[test]
14153 fn test_config_with_multiple_companies() {
14154 let yaml = r#"
14155 global:
14156 industry: manufacturing
14157 start_date: "2024-01-01"
14158 period_months: 6
14159 companies:
14160 - code: "HQ"
14161 name: "Headquarters"
14162 currency: "USD"
14163 country: "US"
14164 annual_transaction_volume: hundred_k
14165 volume_weight: 1.0
14166 - code: "EU"
14167 name: "European Subsidiary"
14168 currency: "EUR"
14169 country: "DE"
14170 annual_transaction_volume: hundred_k
14171 volume_weight: 0.5
14172 - code: "APAC"
14173 name: "Asia Pacific"
14174 currency: "JPY"
14175 country: "JP"
14176 annual_transaction_volume: ten_k
14177 volume_weight: 0.3
14178 chart_of_accounts:
14179 complexity: large
14180 output:
14181 output_directory: "./output"
14182 "#;
14183
14184 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14185 assert_eq!(config.companies.len(), 3);
14186 assert_eq!(config.companies[0].code, "HQ");
14187 assert_eq!(config.companies[1].currency, "EUR");
14188 assert_eq!(config.companies[2].volume_weight, 0.3);
14189 }
14190
14191 #[test]
14192 fn test_intercompany_config() {
14193 let yaml = r#"
14194 enabled: true
14195 ic_transaction_rate: 0.20
14196 transfer_pricing_method: cost_plus
14197 markup_percent: 0.08
14198 generate_matched_pairs: true
14199 generate_eliminations: true
14200 "#;
14201
14202 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14203 assert!(config.enabled);
14204 assert_eq!(config.ic_transaction_rate, 0.20);
14205 assert!(matches!(
14206 config.transfer_pricing_method,
14207 TransferPricingMethod::CostPlus
14208 ));
14209 assert_eq!(config.markup_percent, 0.08);
14210 assert!(config.generate_eliminations);
14211 }
14212
14213 #[test]
14218 fn test_company_config_defaults() {
14219 let yaml = r#"
14220 code: "TEST"
14221 name: "Test Company"
14222 currency: "USD"
14223 country: "US"
14224 annual_transaction_volume: ten_k
14225 "#;
14226
14227 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14228 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
14231
14232 #[test]
14237 fn test_coa_config_defaults() {
14238 let yaml = r#"
14239 complexity: medium
14240 "#;
14241
14242 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14243 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
14245 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
14248
14249 #[test]
14254 fn test_accounting_standards_config_defaults() {
14255 let config = AccountingStandardsConfig::default();
14256 assert!(!config.enabled);
14257 assert!(config.framework.is_none());
14258 assert!(!config.revenue_recognition.enabled);
14259 assert!(!config.leases.enabled);
14260 assert!(!config.fair_value.enabled);
14261 assert!(!config.impairment.enabled);
14262 assert!(!config.generate_differences);
14263 }
14264
14265 #[test]
14266 fn test_accounting_standards_config_yaml() {
14267 let yaml = r#"
14268 enabled: true
14269 framework: ifrs
14270 revenue_recognition:
14271 enabled: true
14272 generate_contracts: true
14273 avg_obligations_per_contract: 2.5
14274 variable_consideration_rate: 0.20
14275 over_time_recognition_rate: 0.35
14276 contract_count: 150
14277 leases:
14278 enabled: true
14279 lease_count: 75
14280 finance_lease_percent: 0.25
14281 avg_lease_term_months: 48
14282 generate_differences: true
14283 "#;
14284
14285 let config: AccountingStandardsConfig =
14286 serde_yaml::from_str(yaml).expect("Failed to parse");
14287 assert!(config.enabled);
14288 assert!(matches!(
14289 config.framework,
14290 Some(AccountingFrameworkConfig::Ifrs)
14291 ));
14292 assert!(config.revenue_recognition.enabled);
14293 assert_eq!(config.revenue_recognition.contract_count, 150);
14294 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
14295 assert!(config.leases.enabled);
14296 assert_eq!(config.leases.lease_count, 75);
14297 assert_eq!(config.leases.finance_lease_percent, 0.25);
14298 assert!(config.generate_differences);
14299 }
14300
14301 #[test]
14302 fn test_accounting_framework_serialization() {
14303 let frameworks = [
14304 AccountingFrameworkConfig::UsGaap,
14305 AccountingFrameworkConfig::Ifrs,
14306 AccountingFrameworkConfig::DualReporting,
14307 AccountingFrameworkConfig::FrenchGaap,
14308 AccountingFrameworkConfig::GermanGaap,
14309 ];
14310
14311 for framework in frameworks {
14312 let json = serde_json::to_string(&framework).expect("Failed to serialize");
14313 let deserialized: AccountingFrameworkConfig =
14314 serde_json::from_str(&json).expect("Failed to deserialize");
14315 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
14316 }
14317 }
14318
14319 #[test]
14320 fn test_revenue_recognition_config_defaults() {
14321 let config = RevenueRecognitionConfig::default();
14322 assert!(!config.enabled);
14323 assert!(config.generate_contracts);
14324 assert_eq!(config.avg_obligations_per_contract, 2.0);
14325 assert_eq!(config.variable_consideration_rate, 0.15);
14326 assert_eq!(config.over_time_recognition_rate, 0.30);
14327 assert_eq!(config.contract_count, 100);
14328 }
14329
14330 #[test]
14331 fn test_lease_accounting_config_defaults() {
14332 let config = LeaseAccountingConfig::default();
14333 assert!(!config.enabled);
14334 assert_eq!(config.lease_count, 50);
14335 assert_eq!(config.finance_lease_percent, 0.30);
14336 assert_eq!(config.avg_lease_term_months, 60);
14337 assert!(config.generate_amortization);
14338 assert_eq!(config.real_estate_percent, 0.40);
14339 }
14340
14341 #[test]
14342 fn test_fair_value_config_defaults() {
14343 let config = FairValueConfig::default();
14344 assert!(!config.enabled);
14345 assert_eq!(config.measurement_count, 25);
14346 assert_eq!(config.level1_percent, 0.40);
14347 assert_eq!(config.level2_percent, 0.35);
14348 assert_eq!(config.level3_percent, 0.25);
14349 assert!(!config.include_sensitivity_analysis);
14350 }
14351
14352 #[test]
14353 fn test_impairment_config_defaults() {
14354 let config = ImpairmentConfig::default();
14355 assert!(!config.enabled);
14356 assert_eq!(config.test_count, 15);
14357 assert_eq!(config.impairment_rate, 0.10);
14358 assert!(config.generate_projections);
14359 assert!(!config.include_goodwill);
14360 }
14361
14362 #[test]
14367 fn test_audit_standards_config_defaults() {
14368 let config = AuditStandardsConfig::default();
14369 assert!(!config.enabled);
14370 assert!(!config.isa_compliance.enabled);
14371 assert!(!config.analytical_procedures.enabled);
14372 assert!(!config.confirmations.enabled);
14373 assert!(!config.opinion.enabled);
14374 assert!(!config.generate_audit_trail);
14375 assert!(!config.sox.enabled);
14376 assert!(!config.pcaob.enabled);
14377 }
14378
14379 #[test]
14380 fn test_audit_standards_config_yaml() {
14381 let yaml = r#"
14382 enabled: true
14383 isa_compliance:
14384 enabled: true
14385 compliance_level: comprehensive
14386 generate_isa_mappings: true
14387 include_pcaob: true
14388 framework: dual
14389 analytical_procedures:
14390 enabled: true
14391 procedures_per_account: 5
14392 variance_probability: 0.25
14393 confirmations:
14394 enabled: true
14395 confirmation_count: 75
14396 positive_response_rate: 0.90
14397 exception_rate: 0.08
14398 opinion:
14399 enabled: true
14400 generate_kam: true
14401 average_kam_count: 4
14402 sox:
14403 enabled: true
14404 generate_302_certifications: true
14405 generate_404_assessments: true
14406 material_weakness_rate: 0.03
14407 pcaob:
14408 enabled: true
14409 is_pcaob_audit: true
14410 include_icfr_opinion: true
14411 generate_audit_trail: true
14412 "#;
14413
14414 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14415 assert!(config.enabled);
14416 assert!(config.isa_compliance.enabled);
14417 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
14418 assert!(config.isa_compliance.include_pcaob);
14419 assert_eq!(config.isa_compliance.framework, "dual");
14420 assert!(config.analytical_procedures.enabled);
14421 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
14422 assert!(config.confirmations.enabled);
14423 assert_eq!(config.confirmations.confirmation_count, 75);
14424 assert!(config.opinion.enabled);
14425 assert_eq!(config.opinion.average_kam_count, 4);
14426 assert!(config.sox.enabled);
14427 assert!(config.sox.generate_302_certifications);
14428 assert_eq!(config.sox.material_weakness_rate, 0.03);
14429 assert!(config.pcaob.enabled);
14430 assert!(config.pcaob.is_pcaob_audit);
14431 assert!(config.pcaob.include_icfr_opinion);
14432 assert!(config.generate_audit_trail);
14433 }
14434
14435 #[test]
14436 fn test_isa_compliance_config_defaults() {
14437 let config = IsaComplianceConfig::default();
14438 assert!(!config.enabled);
14439 assert_eq!(config.compliance_level, "standard");
14440 assert!(config.generate_isa_mappings);
14441 assert!(config.generate_coverage_summary);
14442 assert!(!config.include_pcaob);
14443 assert_eq!(config.framework, "isa");
14444 }
14445
14446 #[test]
14447 fn test_sox_compliance_config_defaults() {
14448 let config = SoxComplianceConfig::default();
14449 assert!(!config.enabled);
14450 assert!(config.generate_302_certifications);
14451 assert!(config.generate_404_assessments);
14452 assert_eq!(config.materiality_threshold, 10000.0);
14453 assert_eq!(config.material_weakness_rate, 0.02);
14454 assert_eq!(config.significant_deficiency_rate, 0.08);
14455 }
14456
14457 #[test]
14458 fn test_pcaob_config_defaults() {
14459 let config = PcaobConfig::default();
14460 assert!(!config.enabled);
14461 assert!(!config.is_pcaob_audit);
14462 assert!(config.generate_cam);
14463 assert!(!config.include_icfr_opinion);
14464 assert!(!config.generate_standard_mappings);
14465 }
14466
14467 #[test]
14468 fn test_config_with_standards_enabled() {
14469 let yaml = r#"
14470 global:
14471 industry: financial_services
14472 start_date: "2024-01-01"
14473 period_months: 12
14474 companies:
14475 - code: "BANK"
14476 name: "Test Bank"
14477 currency: "USD"
14478 country: "US"
14479 annual_transaction_volume: hundred_k
14480 chart_of_accounts:
14481 complexity: large
14482 output:
14483 output_directory: "./output"
14484 accounting_standards:
14485 enabled: true
14486 framework: us_gaap
14487 revenue_recognition:
14488 enabled: true
14489 leases:
14490 enabled: true
14491 audit_standards:
14492 enabled: true
14493 isa_compliance:
14494 enabled: true
14495 sox:
14496 enabled: true
14497 "#;
14498
14499 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14500 assert!(config.accounting_standards.enabled);
14501 assert!(matches!(
14502 config.accounting_standards.framework,
14503 Some(AccountingFrameworkConfig::UsGaap)
14504 ));
14505 assert!(config.accounting_standards.revenue_recognition.enabled);
14506 assert!(config.accounting_standards.leases.enabled);
14507 assert!(config.audit_standards.enabled);
14508 assert!(config.audit_standards.isa_compliance.enabled);
14509 assert!(config.audit_standards.sox.enabled);
14510 }
14511
14512 #[test]
14517 fn test_industry_specific_config_defaults() {
14518 let config = IndustrySpecificConfig::default();
14519 assert!(!config.enabled);
14520 assert!(!config.manufacturing.enabled);
14521 assert!(!config.retail.enabled);
14522 assert!(!config.healthcare.enabled);
14523 assert!(!config.technology.enabled);
14524 assert!(!config.financial_services.enabled);
14525 assert!(!config.professional_services.enabled);
14526 }
14527
14528 #[test]
14529 fn test_manufacturing_config_defaults() {
14530 let config = ManufacturingConfig::default();
14531 assert!(!config.enabled);
14532 assert_eq!(config.bom_depth, 4);
14533 assert!(!config.just_in_time);
14534 assert_eq!(config.supplier_tiers, 2);
14535 assert_eq!(config.target_yield_rate, 0.97);
14536 assert_eq!(config.scrap_alert_threshold, 0.03);
14537 }
14538
14539 #[test]
14540 fn test_retail_config_defaults() {
14541 let config = RetailConfig::default();
14542 assert!(!config.enabled);
14543 assert_eq!(config.avg_daily_transactions, 500);
14544 assert!(config.loss_prevention);
14545 assert_eq!(config.shrinkage_rate, 0.015);
14546 }
14547
14548 #[test]
14549 fn test_healthcare_config_defaults() {
14550 let config = HealthcareConfig::default();
14551 assert!(!config.enabled);
14552 assert_eq!(config.facility_type, "hospital");
14553 assert_eq!(config.avg_daily_encounters, 150);
14554 assert!(config.compliance.hipaa);
14555 assert!(config.compliance.stark_law);
14556 assert!(config.coding_systems.icd10);
14557 assert!(config.coding_systems.cpt);
14558 }
14559
14560 #[test]
14561 fn test_technology_config_defaults() {
14562 let config = TechnologyConfig::default();
14563 assert!(!config.enabled);
14564 assert_eq!(config.revenue_model, "saas");
14565 assert_eq!(config.subscription_revenue_pct, 0.60);
14566 assert!(config.rd_capitalization.enabled);
14567 }
14568
14569 #[test]
14570 fn test_config_with_industry_specific() {
14571 let yaml = r#"
14572 global:
14573 industry: healthcare
14574 start_date: "2024-01-01"
14575 period_months: 12
14576 companies:
14577 - code: "HOSP"
14578 name: "Test Hospital"
14579 currency: "USD"
14580 country: "US"
14581 annual_transaction_volume: hundred_k
14582 chart_of_accounts:
14583 complexity: medium
14584 output:
14585 output_directory: "./output"
14586 industry_specific:
14587 enabled: true
14588 healthcare:
14589 enabled: true
14590 facility_type: hospital
14591 payer_mix:
14592 medicare: 0.45
14593 medicaid: 0.15
14594 commercial: 0.35
14595 self_pay: 0.05
14596 coding_systems:
14597 icd10: true
14598 cpt: true
14599 drg: true
14600 compliance:
14601 hipaa: true
14602 stark_law: true
14603 anomaly_rates:
14604 upcoding: 0.03
14605 unbundling: 0.02
14606 "#;
14607
14608 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14609 assert!(config.industry_specific.enabled);
14610 assert!(config.industry_specific.healthcare.enabled);
14611 assert_eq!(
14612 config.industry_specific.healthcare.facility_type,
14613 "hospital"
14614 );
14615 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14616 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14617 assert!(config.industry_specific.healthcare.coding_systems.icd10);
14618 assert!(config.industry_specific.healthcare.compliance.hipaa);
14619 assert_eq!(
14620 config.industry_specific.healthcare.anomaly_rates.upcoding,
14621 0.03
14622 );
14623 }
14624
14625 #[test]
14626 fn test_config_with_manufacturing_specific() {
14627 let yaml = r#"
14628 global:
14629 industry: manufacturing
14630 start_date: "2024-01-01"
14631 period_months: 12
14632 companies:
14633 - code: "MFG"
14634 name: "Test Manufacturing"
14635 currency: "USD"
14636 country: "US"
14637 annual_transaction_volume: hundred_k
14638 chart_of_accounts:
14639 complexity: medium
14640 output:
14641 output_directory: "./output"
14642 industry_specific:
14643 enabled: true
14644 manufacturing:
14645 enabled: true
14646 bom_depth: 5
14647 just_in_time: true
14648 supplier_tiers: 3
14649 target_yield_rate: 0.98
14650 anomaly_rates:
14651 yield_manipulation: 0.02
14652 phantom_production: 0.01
14653 "#;
14654
14655 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14656 assert!(config.industry_specific.enabled);
14657 assert!(config.industry_specific.manufacturing.enabled);
14658 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14659 assert!(config.industry_specific.manufacturing.just_in_time);
14660 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14661 assert_eq!(
14662 config.industry_specific.manufacturing.target_yield_rate,
14663 0.98
14664 );
14665 assert_eq!(
14666 config
14667 .industry_specific
14668 .manufacturing
14669 .anomaly_rates
14670 .yield_manipulation,
14671 0.02
14672 );
14673 }
14674
14675 #[test]
14680 fn test_tax_config_defaults() {
14681 let tax = TaxConfig::default();
14682 assert!(!tax.enabled);
14683 assert!(tax.jurisdictions.countries.is_empty());
14684 assert!(!tax.jurisdictions.include_subnational);
14685 assert!(!tax.vat_gst.enabled);
14686 assert!(tax.vat_gst.standard_rates.is_empty());
14687 assert!(tax.vat_gst.reduced_rates.is_empty());
14688 assert!(tax.vat_gst.exempt_categories.is_empty());
14689 assert!(tax.vat_gst.reverse_charge);
14690 assert!(!tax.sales_tax.enabled);
14691 assert!(tax.sales_tax.nexus_states.is_empty());
14692 assert!(!tax.withholding.enabled);
14693 assert!(tax.withholding.treaty_network);
14694 assert_eq!(tax.withholding.default_rate, 0.30);
14695 assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14696 assert!(tax.provisions.enabled);
14697 assert_eq!(tax.provisions.statutory_rate, 0.21);
14698 assert!(tax.provisions.uncertain_positions);
14699 assert!(!tax.payroll_tax.enabled);
14700 assert_eq!(tax.anomaly_rate, 0.03);
14701 }
14702
14703 #[test]
14704 fn test_tax_config_from_yaml() {
14705 let yaml = r#"
14706 global:
14707 seed: 42
14708 start_date: "2024-01-01"
14709 period_months: 12
14710 industry: retail
14711 companies:
14712 - code: C001
14713 name: Test Corp
14714 currency: USD
14715 country: US
14716 annual_transaction_volume: ten_k
14717 chart_of_accounts:
14718 complexity: small
14719 output:
14720 output_directory: ./output
14721 tax:
14722 enabled: true
14723 anomaly_rate: 0.05
14724 jurisdictions:
14725 countries: ["US", "DE", "GB"]
14726 include_subnational: true
14727 vat_gst:
14728 enabled: true
14729 standard_rates:
14730 DE: 0.19
14731 GB: 0.20
14732 reduced_rates:
14733 DE: 0.07
14734 GB: 0.05
14735 exempt_categories:
14736 - financial_services
14737 - healthcare
14738 reverse_charge: false
14739 sales_tax:
14740 enabled: true
14741 nexus_states: ["CA", "NY", "TX"]
14742 withholding:
14743 enabled: true
14744 treaty_network: false
14745 default_rate: 0.25
14746 treaty_reduced_rate: 0.10
14747 provisions:
14748 enabled: false
14749 statutory_rate: 0.28
14750 uncertain_positions: false
14751 payroll_tax:
14752 enabled: true
14753 "#;
14754
14755 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14756 assert!(config.tax.enabled);
14757 assert_eq!(config.tax.anomaly_rate, 0.05);
14758
14759 assert_eq!(config.tax.jurisdictions.countries.len(), 3);
14761 assert!(config
14762 .tax
14763 .jurisdictions
14764 .countries
14765 .contains(&"DE".to_string()));
14766 assert!(config.tax.jurisdictions.include_subnational);
14767
14768 assert!(config.tax.vat_gst.enabled);
14770 assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
14771 assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
14772 assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
14773 assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
14774 assert!(!config.tax.vat_gst.reverse_charge);
14775
14776 assert!(config.tax.sales_tax.enabled);
14778 assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
14779 assert!(config
14780 .tax
14781 .sales_tax
14782 .nexus_states
14783 .contains(&"CA".to_string()));
14784
14785 assert!(config.tax.withholding.enabled);
14787 assert!(!config.tax.withholding.treaty_network);
14788 assert_eq!(config.tax.withholding.default_rate, 0.25);
14789 assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
14790
14791 assert!(!config.tax.provisions.enabled);
14793 assert_eq!(config.tax.provisions.statutory_rate, 0.28);
14794 assert!(!config.tax.provisions.uncertain_positions);
14795
14796 assert!(config.tax.payroll_tax.enabled);
14798 }
14799
14800 #[test]
14801 fn test_generator_config_with_tax_default() {
14802 let yaml = r#"
14803 global:
14804 seed: 42
14805 start_date: "2024-01-01"
14806 period_months: 12
14807 industry: retail
14808 companies:
14809 - code: C001
14810 name: Test Corp
14811 currency: USD
14812 country: US
14813 annual_transaction_volume: ten_k
14814 chart_of_accounts:
14815 complexity: small
14816 output:
14817 output_directory: ./output
14818 "#;
14819
14820 let config: GeneratorConfig =
14821 serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
14822 assert!(!config.tax.enabled);
14824 assert!(config.tax.jurisdictions.countries.is_empty());
14825 assert_eq!(config.tax.anomaly_rate, 0.03);
14826 assert!(config.tax.provisions.enabled); assert_eq!(config.tax.provisions.statutory_rate, 0.21);
14828 }
14829
14830 #[test]
14835 fn test_session_config_default_disabled() {
14836 let yaml = "{}";
14837 let config: SessionSchemaConfig =
14838 serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
14839 assert!(!config.enabled);
14840 assert!(config.checkpoint_path.is_none());
14841 assert!(config.per_period_output);
14842 assert!(config.consolidated_output);
14843 }
14844
14845 #[test]
14846 fn test_config_backward_compatible_without_session() {
14847 let yaml = r#"
14848 global:
14849 seed: 42
14850 start_date: "2024-01-01"
14851 period_months: 12
14852 industry: retail
14853 companies:
14854 - code: C001
14855 name: Test Corp
14856 currency: USD
14857 country: US
14858 annual_transaction_volume: ten_k
14859 chart_of_accounts:
14860 complexity: small
14861 output:
14862 output_directory: ./output
14863 "#;
14864
14865 let config: GeneratorConfig =
14866 serde_yaml::from_str(yaml).expect("Failed to parse config without session");
14867 assert!(!config.session.enabled);
14869 assert!(config.session.per_period_output);
14870 assert!(config.session.consolidated_output);
14871 assert!(config.global.fiscal_year_months.is_none());
14873 }
14874
14875 #[test]
14876 fn test_fiscal_year_months_parsed() {
14877 let yaml = r#"
14878 global:
14879 seed: 42
14880 start_date: "2024-01-01"
14881 period_months: 24
14882 industry: retail
14883 fiscal_year_months: 12
14884 companies:
14885 - code: C001
14886 name: Test Corp
14887 currency: USD
14888 country: US
14889 annual_transaction_volume: ten_k
14890 chart_of_accounts:
14891 complexity: small
14892 output:
14893 output_directory: ./output
14894 session:
14895 enabled: true
14896 checkpoint_path: /tmp/checkpoints
14897 per_period_output: true
14898 consolidated_output: false
14899 "#;
14900
14901 let config: GeneratorConfig =
14902 serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
14903 assert_eq!(config.global.fiscal_year_months, Some(12));
14904 assert!(config.session.enabled);
14905 assert_eq!(
14906 config.session.checkpoint_path,
14907 Some("/tmp/checkpoints".to_string())
14908 );
14909 assert!(config.session.per_period_output);
14910 assert!(!config.session.consolidated_output);
14911 }
14912}