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 #[serde(default)]
266 pub enrich_customers: bool,
267
268 #[serde(default)]
271 pub enrich_materials: bool,
272
273 #[serde(default)]
277 pub enrich_findings: bool,
278
279 #[serde(default = "default_llm_batch_size")]
282 pub max_customer_enrichments: usize,
283
284 #[serde(default = "default_llm_batch_size")]
286 pub max_material_enrichments: usize,
287
288 #[serde(default = "default_llm_batch_size")]
290 pub max_finding_enrichments: usize,
291}
292
293fn default_llm_provider() -> String {
294 "mock".to_string()
295}
296
297fn default_llm_model_name() -> String {
298 "gpt-4o-mini".to_string()
299}
300
301fn default_llm_batch_size() -> usize {
302 50
303}
304
305impl Default for LlmSchemaConfig {
306 fn default() -> Self {
307 Self {
308 enabled: false,
309 provider: default_llm_provider(),
310 model: default_llm_model_name(),
311 max_vendor_enrichments: default_llm_batch_size(),
312 enrich_customers: false,
313 enrich_materials: false,
314 enrich_findings: false,
315 max_customer_enrichments: default_llm_batch_size(),
316 max_material_enrichments: default_llm_batch_size(),
317 max_finding_enrichments: default_llm_batch_size(),
318 }
319 }
320}
321
322#[derive(Debug, Clone, Serialize, Deserialize)]
327pub struct DiffusionSchemaConfig {
328 #[serde(default)]
330 pub enabled: bool,
331 #[serde(default = "default_diffusion_steps")]
333 pub n_steps: usize,
334 #[serde(default = "default_diffusion_schedule")]
336 pub schedule: String,
337 #[serde(default = "default_diffusion_sample_size")]
339 pub sample_size: usize,
340 #[serde(default = "default_diffusion_backend")]
342 pub backend: String,
343 #[serde(default)]
345 pub neural: NeuralDiffusionSchemaConfig,
346}
347
348fn default_diffusion_steps() -> usize {
349 100
350}
351
352fn default_diffusion_schedule() -> String {
353 "linear".to_string()
354}
355
356fn default_diffusion_sample_size() -> usize {
357 100
358}
359
360fn default_diffusion_backend() -> String {
361 "statistical".to_string()
362}
363
364impl Default for DiffusionSchemaConfig {
365 fn default() -> Self {
366 Self {
367 enabled: false,
368 n_steps: default_diffusion_steps(),
369 schedule: default_diffusion_schedule(),
370 sample_size: default_diffusion_sample_size(),
371 backend: default_diffusion_backend(),
372 neural: NeuralDiffusionSchemaConfig::default(),
373 }
374 }
375}
376
377#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct NeuralDiffusionSchemaConfig {
383 #[serde(default = "default_neural_hidden_dims")]
385 pub hidden_dims: Vec<usize>,
386 #[serde(default = "default_neural_timestep_embed_dim")]
388 pub timestep_embed_dim: usize,
389 #[serde(default = "default_neural_learning_rate")]
391 pub learning_rate: f64,
392 #[serde(default = "default_neural_training_epochs")]
394 pub training_epochs: usize,
395 #[serde(default = "default_neural_batch_size")]
397 pub batch_size: usize,
398 #[serde(default = "default_neural_hybrid_weight")]
400 pub hybrid_weight: f64,
401 #[serde(default = "default_neural_hybrid_strategy")]
403 pub hybrid_strategy: String,
404 #[serde(default)]
406 pub neural_columns: Vec<String>,
407}
408
409fn default_neural_hidden_dims() -> Vec<usize> {
410 vec![256, 256, 128]
411}
412
413fn default_neural_timestep_embed_dim() -> usize {
414 64
415}
416
417fn default_neural_learning_rate() -> f64 {
418 0.001
419}
420
421fn default_neural_training_epochs() -> usize {
422 100
423}
424
425fn default_neural_batch_size() -> usize {
426 64
427}
428
429fn default_neural_hybrid_weight() -> f64 {
430 0.5
431}
432
433fn default_neural_hybrid_strategy() -> String {
434 "weighted_average".to_string()
435}
436
437impl Default for NeuralDiffusionSchemaConfig {
438 fn default() -> Self {
439 Self {
440 hidden_dims: default_neural_hidden_dims(),
441 timestep_embed_dim: default_neural_timestep_embed_dim(),
442 learning_rate: default_neural_learning_rate(),
443 training_epochs: default_neural_training_epochs(),
444 batch_size: default_neural_batch_size(),
445 hybrid_weight: default_neural_hybrid_weight(),
446 hybrid_strategy: default_neural_hybrid_strategy(),
447 neural_columns: Vec::new(),
448 }
449 }
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct CausalSchemaConfig {
459 #[serde(default)]
461 pub enabled: bool,
462 #[serde(default = "default_causal_template")]
464 pub template: String,
465 #[serde(default = "default_causal_sample_size")]
467 pub sample_size: usize,
468 #[serde(default = "default_true")]
470 pub validate: bool,
471}
472
473fn default_causal_template() -> String {
474 "fraud_detection".to_string()
475}
476
477fn default_causal_sample_size() -> usize {
478 500
479}
480
481impl Default for CausalSchemaConfig {
482 fn default() -> Self {
483 Self {
484 enabled: false,
485 template: default_causal_template(),
486 sample_size: default_causal_sample_size(),
487 validate: true,
488 }
489 }
490}
491
492#[derive(Debug, Clone, Serialize, Deserialize)]
499pub struct GraphExportConfig {
500 #[serde(default)]
502 pub enabled: bool,
503
504 #[serde(default = "default_graph_types")]
506 pub graph_types: Vec<GraphTypeConfig>,
507
508 #[serde(default = "default_graph_formats")]
510 pub formats: Vec<GraphExportFormat>,
511
512 #[serde(default = "default_train_ratio")]
514 pub train_ratio: f64,
515
516 #[serde(default = "default_val_ratio")]
518 pub validation_ratio: f64,
519
520 #[serde(default)]
522 pub split_seed: Option<u64>,
523
524 #[serde(default = "default_graph_subdir")]
526 pub output_subdirectory: String,
527
528 #[serde(default)]
530 pub hypergraph: HypergraphExportSettings,
531
532 #[serde(default)]
534 pub dgl: DglExportConfig,
535}
536
537fn default_graph_types() -> Vec<GraphTypeConfig> {
538 vec![GraphTypeConfig::default()]
539}
540
541fn default_graph_formats() -> Vec<GraphExportFormat> {
542 vec![GraphExportFormat::PytorchGeometric]
543}
544
545fn default_train_ratio() -> f64 {
546 0.7
547}
548
549fn default_val_ratio() -> f64 {
550 0.15
551}
552
553fn default_graph_subdir() -> String {
554 "graphs".to_string()
555}
556
557impl Default for GraphExportConfig {
558 fn default() -> Self {
559 Self {
560 enabled: false,
561 graph_types: default_graph_types(),
562 formats: default_graph_formats(),
563 train_ratio: 0.7,
564 validation_ratio: 0.15,
565 split_seed: None,
566 output_subdirectory: "graphs".to_string(),
567 hypergraph: HypergraphExportSettings::default(),
568 dgl: DglExportConfig::default(),
569 }
570 }
571}
572
573#[derive(Debug, Clone, Default, Serialize, Deserialize)]
575pub struct DglExportConfig {
576 #[serde(default)]
582 pub heterogeneous: bool,
583}
584
585#[derive(Debug, Clone, Serialize, Deserialize)]
594pub struct HypergraphExportSettings {
595 #[serde(default)]
597 pub enabled: bool,
598
599 #[serde(default = "default_hypergraph_max_nodes")]
601 pub max_nodes: usize,
602
603 #[serde(default = "default_aggregation_strategy")]
605 pub aggregation_strategy: String,
606
607 #[serde(default)]
609 pub governance_layer: GovernanceLayerSettings,
610
611 #[serde(default)]
613 pub process_layer: ProcessLayerSettings,
614
615 #[serde(default)]
617 pub accounting_layer: AccountingLayerSettings,
618
619 #[serde(default)]
621 pub cross_layer: CrossLayerSettings,
622
623 #[serde(default = "default_hypergraph_subdir")]
625 pub output_subdirectory: String,
626
627 #[serde(default = "default_hypergraph_format")]
629 pub output_format: String,
630
631 #[serde(default)]
633 pub stream_target: Option<String>,
634
635 #[serde(default = "default_stream_batch_size")]
637 pub stream_batch_size: usize,
638}
639
640fn default_hypergraph_max_nodes() -> usize {
641 50_000
642}
643
644fn default_aggregation_strategy() -> String {
645 "pool_by_counterparty".to_string()
646}
647
648fn default_hypergraph_subdir() -> String {
649 "hypergraph".to_string()
650}
651
652fn default_hypergraph_format() -> String {
653 "native".to_string()
654}
655
656fn default_stream_batch_size() -> usize {
657 1000
658}
659
660impl Default for HypergraphExportSettings {
661 fn default() -> Self {
662 Self {
663 enabled: false,
664 max_nodes: 50_000,
665 aggregation_strategy: "pool_by_counterparty".to_string(),
666 governance_layer: GovernanceLayerSettings::default(),
667 process_layer: ProcessLayerSettings::default(),
668 accounting_layer: AccountingLayerSettings::default(),
669 cross_layer: CrossLayerSettings::default(),
670 output_subdirectory: "hypergraph".to_string(),
671 output_format: "native".to_string(),
672 stream_target: None,
673 stream_batch_size: 1000,
674 }
675 }
676}
677
678#[derive(Debug, Clone, Serialize, Deserialize)]
680pub struct GovernanceLayerSettings {
681 #[serde(default = "default_true")]
683 pub include_coso: bool,
684 #[serde(default = "default_true")]
686 pub include_controls: bool,
687 #[serde(default = "default_true")]
689 pub include_sox: bool,
690 #[serde(default = "default_true")]
692 pub include_vendors: bool,
693 #[serde(default = "default_true")]
695 pub include_customers: bool,
696 #[serde(default = "default_true")]
698 pub include_employees: bool,
699}
700
701impl Default for GovernanceLayerSettings {
702 fn default() -> Self {
703 Self {
704 include_coso: true,
705 include_controls: true,
706 include_sox: true,
707 include_vendors: true,
708 include_customers: true,
709 include_employees: true,
710 }
711 }
712}
713
714#[derive(Debug, Clone, Serialize, Deserialize)]
716pub struct ProcessLayerSettings {
717 #[serde(default = "default_true")]
719 pub include_p2p: bool,
720 #[serde(default = "default_true")]
722 pub include_o2c: bool,
723 #[serde(default = "default_true")]
725 pub include_s2c: bool,
726 #[serde(default = "default_true")]
728 pub include_h2r: bool,
729 #[serde(default = "default_true")]
731 pub include_mfg: bool,
732 #[serde(default = "default_true")]
734 pub include_bank: bool,
735 #[serde(default = "default_true")]
737 pub include_audit: bool,
738 #[serde(default = "default_true")]
740 pub include_r2r: bool,
741 #[serde(default = "default_true")]
743 pub events_as_hyperedges: bool,
744 #[serde(default = "default_docs_per_counterparty_threshold")]
746 pub docs_per_counterparty_threshold: usize,
747}
748
749fn default_docs_per_counterparty_threshold() -> usize {
750 20
751}
752
753impl Default for ProcessLayerSettings {
754 fn default() -> Self {
755 Self {
756 include_p2p: true,
757 include_o2c: true,
758 include_s2c: true,
759 include_h2r: true,
760 include_mfg: true,
761 include_bank: true,
762 include_audit: true,
763 include_r2r: true,
764 events_as_hyperedges: true,
765 docs_per_counterparty_threshold: 20,
766 }
767 }
768}
769
770#[derive(Debug, Clone, Serialize, Deserialize)]
772pub struct AccountingLayerSettings {
773 #[serde(default = "default_true")]
775 pub include_accounts: bool,
776 #[serde(default = "default_true")]
778 pub je_as_hyperedges: bool,
779}
780
781impl Default for AccountingLayerSettings {
782 fn default() -> Self {
783 Self {
784 include_accounts: true,
785 je_as_hyperedges: true,
786 }
787 }
788}
789
790#[derive(Debug, Clone, Serialize, Deserialize)]
792pub struct CrossLayerSettings {
793 #[serde(default = "default_true")]
795 pub enabled: bool,
796}
797
798impl Default for CrossLayerSettings {
799 fn default() -> Self {
800 Self { enabled: true }
801 }
802}
803
804#[derive(Debug, Clone, Serialize, Deserialize)]
806pub struct GraphTypeConfig {
807 #[serde(default = "default_graph_name")]
809 pub name: String,
810
811 #[serde(default)]
813 pub aggregate_edges: bool,
814
815 #[serde(default)]
817 pub min_edge_weight: f64,
818
819 #[serde(default)]
821 pub include_document_nodes: bool,
822}
823
824fn default_graph_name() -> String {
825 "accounting_network".to_string()
826}
827
828impl Default for GraphTypeConfig {
829 fn default() -> Self {
830 Self {
831 name: "accounting_network".to_string(),
832 aggregate_edges: false,
833 min_edge_weight: 0.0,
834 include_document_nodes: false,
835 }
836 }
837}
838
839#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
841#[serde(rename_all = "snake_case")]
842pub enum GraphExportFormat {
843 PytorchGeometric,
845 Neo4j,
847 Dgl,
849 RustGraph,
851 RustGraphHypergraph,
853}
854
855#[derive(Debug, Clone, Default, Serialize, Deserialize)]
859pub struct ScenarioConfig {
860 #[serde(default)]
863 pub tags: Vec<String>,
864
865 #[serde(default)]
870 pub profile: Option<String>,
871
872 #[serde(default)]
874 pub description: Option<String>,
875
876 #[serde(default)]
878 pub ml_training: bool,
879
880 #[serde(default)]
883 pub target_anomaly_ratio: Option<f64>,
884
885 #[serde(default)]
887 pub metadata: std::collections::HashMap<String, String>,
888}
889
890#[derive(Debug, Clone, Serialize, Deserialize)]
895pub struct TemporalDriftConfig {
896 #[serde(default)]
898 pub enabled: bool,
899
900 #[serde(default = "default_amount_drift")]
903 pub amount_mean_drift: f64,
904
905 #[serde(default)]
908 pub amount_variance_drift: f64,
909
910 #[serde(default)]
913 pub anomaly_rate_drift: f64,
914
915 #[serde(default = "default_concept_drift")]
918 pub concept_drift_rate: f64,
919
920 #[serde(default)]
922 pub sudden_drift_probability: f64,
923
924 #[serde(default = "default_sudden_drift_magnitude")]
926 pub sudden_drift_magnitude: f64,
927
928 #[serde(default)]
930 pub seasonal_drift: bool,
931
932 #[serde(default)]
934 pub drift_start_period: u32,
935
936 #[serde(default = "default_drift_type")]
938 pub drift_type: DriftType,
939}
940
941fn default_amount_drift() -> f64 {
942 0.02
943}
944
945fn default_concept_drift() -> f64 {
946 0.01
947}
948
949fn default_sudden_drift_magnitude() -> f64 {
950 2.0
951}
952
953fn default_drift_type() -> DriftType {
954 DriftType::Gradual
955}
956
957impl Default for TemporalDriftConfig {
958 fn default() -> Self {
959 Self {
960 enabled: false,
961 amount_mean_drift: 0.02,
962 amount_variance_drift: 0.0,
963 anomaly_rate_drift: 0.0,
964 concept_drift_rate: 0.01,
965 sudden_drift_probability: 0.0,
966 sudden_drift_magnitude: 2.0,
967 seasonal_drift: false,
968 drift_start_period: 0,
969 drift_type: DriftType::Gradual,
970 }
971 }
972}
973
974impl TemporalDriftConfig {
975 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
977 datasynth_core::distributions::DriftConfig {
978 enabled: self.enabled,
979 amount_mean_drift: self.amount_mean_drift,
980 amount_variance_drift: self.amount_variance_drift,
981 anomaly_rate_drift: self.anomaly_rate_drift,
982 concept_drift_rate: self.concept_drift_rate,
983 sudden_drift_probability: self.sudden_drift_probability,
984 sudden_drift_magnitude: self.sudden_drift_magnitude,
985 seasonal_drift: self.seasonal_drift,
986 drift_start_period: self.drift_start_period,
987 drift_type: match self.drift_type {
988 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
989 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
990 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
991 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
992 },
993 regime_changes: Vec::new(),
994 economic_cycle: Default::default(),
995 parameter_drifts: Vec::new(),
996 }
997 }
998}
999
1000#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1002#[serde(rename_all = "snake_case")]
1003pub enum DriftType {
1004 #[default]
1006 Gradual,
1007 Sudden,
1009 Recurring,
1011 Mixed,
1013}
1014
1015#[derive(Debug, Clone, Serialize, Deserialize)]
1021pub struct StreamingSchemaConfig {
1022 #[serde(default)]
1024 pub enabled: bool,
1025 #[serde(default)]
1027 pub events_per_second: f64,
1028 #[serde(default = "default_burst_size")]
1030 pub burst_size: u32,
1031 #[serde(default = "default_buffer_size")]
1033 pub buffer_size: usize,
1034 #[serde(default = "default_true")]
1036 pub enable_progress: bool,
1037 #[serde(default = "default_progress_interval")]
1039 pub progress_interval: u64,
1040 #[serde(default)]
1042 pub backpressure: BackpressureSchemaStrategy,
1043}
1044
1045fn default_buffer_size() -> usize {
1046 1000
1047}
1048
1049fn default_progress_interval() -> u64 {
1050 100
1051}
1052
1053impl Default for StreamingSchemaConfig {
1054 fn default() -> Self {
1055 Self {
1056 enabled: false,
1057 events_per_second: 0.0,
1058 burst_size: 100,
1059 buffer_size: 1000,
1060 enable_progress: true,
1061 progress_interval: 100,
1062 backpressure: BackpressureSchemaStrategy::Block,
1063 }
1064 }
1065}
1066
1067#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1069#[serde(rename_all = "snake_case")]
1070pub enum BackpressureSchemaStrategy {
1071 #[default]
1073 Block,
1074 DropOldest,
1076 DropNewest,
1078 Buffer,
1080}
1081
1082#[derive(Debug, Clone, Serialize, Deserialize)]
1088pub struct RateLimitSchemaConfig {
1089 #[serde(default)]
1091 pub enabled: bool,
1092 #[serde(default = "default_entities_per_second")]
1094 pub entities_per_second: f64,
1095 #[serde(default = "default_burst_size")]
1097 pub burst_size: u32,
1098 #[serde(default)]
1100 pub backpressure: RateLimitBackpressureSchema,
1101}
1102
1103fn default_entities_per_second() -> f64 {
1104 1000.0
1105}
1106
1107fn default_burst_size() -> u32 {
1108 100
1109}
1110
1111impl Default for RateLimitSchemaConfig {
1112 fn default() -> Self {
1113 Self {
1114 enabled: false,
1115 entities_per_second: 1000.0,
1116 burst_size: 100,
1117 backpressure: RateLimitBackpressureSchema::Block,
1118 }
1119 }
1120}
1121
1122#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1124#[serde(rename_all = "snake_case")]
1125pub enum RateLimitBackpressureSchema {
1126 #[default]
1128 Block,
1129 Drop,
1131 Buffer,
1133}
1134
1135#[derive(Debug, Clone, Serialize, Deserialize)]
1141pub struct TemporalAttributeSchemaConfig {
1142 #[serde(default)]
1144 pub enabled: bool,
1145 #[serde(default)]
1147 pub valid_time: ValidTimeSchemaConfig,
1148 #[serde(default)]
1150 pub transaction_time: TransactionTimeSchemaConfig,
1151 #[serde(default)]
1153 pub generate_version_chains: bool,
1154 #[serde(default = "default_avg_versions")]
1156 pub avg_versions_per_entity: f64,
1157}
1158
1159fn default_avg_versions() -> f64 {
1160 1.5
1161}
1162
1163impl Default for TemporalAttributeSchemaConfig {
1164 fn default() -> Self {
1165 Self {
1166 enabled: false,
1167 valid_time: ValidTimeSchemaConfig::default(),
1168 transaction_time: TransactionTimeSchemaConfig::default(),
1169 generate_version_chains: false,
1170 avg_versions_per_entity: 1.5,
1171 }
1172 }
1173}
1174
1175#[derive(Debug, Clone, Serialize, Deserialize)]
1177pub struct ValidTimeSchemaConfig {
1178 #[serde(default = "default_closed_probability")]
1180 pub closed_probability: f64,
1181 #[serde(default = "default_avg_validity_days")]
1183 pub avg_validity_days: u32,
1184 #[serde(default = "default_validity_stddev")]
1186 pub validity_stddev_days: u32,
1187}
1188
1189fn default_closed_probability() -> f64 {
1190 0.1
1191}
1192
1193fn default_avg_validity_days() -> u32 {
1194 365
1195}
1196
1197fn default_validity_stddev() -> u32 {
1198 90
1199}
1200
1201impl Default for ValidTimeSchemaConfig {
1202 fn default() -> Self {
1203 Self {
1204 closed_probability: 0.1,
1205 avg_validity_days: 365,
1206 validity_stddev_days: 90,
1207 }
1208 }
1209}
1210
1211#[derive(Debug, Clone, Serialize, Deserialize)]
1213pub struct TransactionTimeSchemaConfig {
1214 #[serde(default)]
1216 pub avg_recording_delay_seconds: u32,
1217 #[serde(default)]
1219 pub allow_backdating: bool,
1220 #[serde(default = "default_backdating_probability")]
1222 pub backdating_probability: f64,
1223 #[serde(default = "default_max_backdate_days")]
1225 pub max_backdate_days: u32,
1226}
1227
1228fn default_backdating_probability() -> f64 {
1229 0.01
1230}
1231
1232fn default_max_backdate_days() -> u32 {
1233 30
1234}
1235
1236impl Default for TransactionTimeSchemaConfig {
1237 fn default() -> Self {
1238 Self {
1239 avg_recording_delay_seconds: 0,
1240 allow_backdating: false,
1241 backdating_probability: 0.01,
1242 max_backdate_days: 30,
1243 }
1244 }
1245}
1246
1247#[derive(Debug, Clone, Serialize, Deserialize)]
1253pub struct RelationshipSchemaConfig {
1254 #[serde(default)]
1256 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
1257 #[serde(default = "default_true")]
1259 pub allow_orphans: bool,
1260 #[serde(default = "default_orphan_probability")]
1262 pub orphan_probability: f64,
1263 #[serde(default)]
1265 pub allow_circular: bool,
1266 #[serde(default = "default_max_circular_depth")]
1268 pub max_circular_depth: u32,
1269}
1270
1271fn default_orphan_probability() -> f64 {
1272 0.01
1273}
1274
1275fn default_max_circular_depth() -> u32 {
1276 3
1277}
1278
1279impl Default for RelationshipSchemaConfig {
1280 fn default() -> Self {
1281 Self {
1282 relationship_types: Vec::new(),
1283 allow_orphans: true,
1284 orphan_probability: 0.01,
1285 allow_circular: false,
1286 max_circular_depth: 3,
1287 }
1288 }
1289}
1290
1291#[derive(Debug, Clone, Serialize, Deserialize)]
1293pub struct RelationshipTypeSchemaConfig {
1294 pub name: String,
1296 pub source_type: String,
1298 pub target_type: String,
1300 #[serde(default)]
1302 pub cardinality: CardinalitySchemaRule,
1303 #[serde(default = "default_relationship_weight")]
1305 pub weight: f64,
1306 #[serde(default)]
1308 pub required: bool,
1309 #[serde(default = "default_true")]
1311 pub directed: bool,
1312}
1313
1314fn default_relationship_weight() -> f64 {
1315 1.0
1316}
1317
1318impl Default for RelationshipTypeSchemaConfig {
1319 fn default() -> Self {
1320 Self {
1321 name: String::new(),
1322 source_type: String::new(),
1323 target_type: String::new(),
1324 cardinality: CardinalitySchemaRule::default(),
1325 weight: 1.0,
1326 required: false,
1327 directed: true,
1328 }
1329 }
1330}
1331
1332#[derive(Debug, Clone, Serialize, Deserialize)]
1334#[serde(rename_all = "snake_case")]
1335pub enum CardinalitySchemaRule {
1336 OneToOne,
1338 OneToMany {
1340 min: u32,
1342 max: u32,
1344 },
1345 ManyToOne {
1347 min: u32,
1349 max: u32,
1351 },
1352 ManyToMany {
1354 min_per_source: u32,
1356 max_per_source: u32,
1358 },
1359}
1360
1361impl Default for CardinalitySchemaRule {
1362 fn default() -> Self {
1363 Self::OneToMany { min: 1, max: 5 }
1364 }
1365}
1366
1367#[derive(Debug, Clone, Serialize, Deserialize)]
1369pub struct GlobalConfig {
1370 pub seed: Option<u64>,
1372 pub industry: IndustrySector,
1374 pub start_date: String,
1376 pub period_months: u32,
1378 #[serde(default = "default_currency")]
1380 pub group_currency: String,
1381 #[serde(default)]
1384 pub presentation_currency: Option<String>,
1385 #[serde(default = "default_true")]
1387 pub parallel: bool,
1388 #[serde(default)]
1390 pub worker_threads: usize,
1391 #[serde(default)]
1393 pub memory_limit_mb: usize,
1394 #[serde(default)]
1397 pub fiscal_year_months: Option<u32>,
1398}
1399
1400fn default_currency() -> String {
1401 "USD".to_string()
1402}
1403fn default_true() -> bool {
1404 true
1405}
1406
1407#[derive(Debug, Clone, Serialize, Deserialize)]
1412pub struct SessionSchemaConfig {
1413 #[serde(default)]
1415 pub enabled: bool,
1416 #[serde(default)]
1418 pub checkpoint_path: Option<String>,
1419 #[serde(default = "default_true")]
1421 pub per_period_output: bool,
1422 #[serde(default = "default_true")]
1424 pub consolidated_output: bool,
1425}
1426
1427impl Default for SessionSchemaConfig {
1428 fn default() -> Self {
1429 Self {
1430 enabled: false,
1431 checkpoint_path: None,
1432 per_period_output: true,
1433 consolidated_output: true,
1434 }
1435 }
1436}
1437
1438#[derive(Debug, Clone, Serialize, Deserialize)]
1440pub struct CompanyConfig {
1441 pub code: String,
1443 pub name: String,
1445 pub currency: String,
1447 #[serde(default)]
1450 pub functional_currency: Option<String>,
1451 pub country: String,
1453 #[serde(default = "default_fiscal_variant")]
1455 pub fiscal_year_variant: String,
1456 pub annual_transaction_volume: TransactionVolume,
1458 #[serde(default = "default_weight")]
1460 pub volume_weight: f64,
1461}
1462
1463fn default_fiscal_variant() -> String {
1464 "K4".to_string()
1465}
1466fn default_weight() -> f64 {
1467 1.0
1468}
1469
1470#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1472#[serde(rename_all = "snake_case")]
1473pub enum TransactionVolume {
1474 TenK,
1476 HundredK,
1478 OneM,
1480 TenM,
1482 HundredM,
1484 Custom(u64),
1486}
1487
1488impl TransactionVolume {
1489 pub fn count(&self) -> u64 {
1491 match self {
1492 Self::TenK => 10_000,
1493 Self::HundredK => 100_000,
1494 Self::OneM => 1_000_000,
1495 Self::TenM => 10_000_000,
1496 Self::HundredM => 100_000_000,
1497 Self::Custom(n) => *n,
1498 }
1499 }
1500}
1501
1502#[derive(Debug, Clone, Serialize, Deserialize)]
1504pub struct ChartOfAccountsConfig {
1505 pub complexity: CoAComplexity,
1507 #[serde(default = "default_true")]
1509 pub industry_specific: bool,
1510 pub custom_accounts: Option<PathBuf>,
1512 #[serde(default = "default_min_depth")]
1514 pub min_hierarchy_depth: u8,
1515 #[serde(default = "default_max_depth")]
1517 pub max_hierarchy_depth: u8,
1518}
1519
1520fn default_min_depth() -> u8 {
1521 2
1522}
1523fn default_max_depth() -> u8 {
1524 5
1525}
1526
1527impl Default for ChartOfAccountsConfig {
1528 fn default() -> Self {
1529 Self {
1530 complexity: CoAComplexity::Small,
1531 industry_specific: true,
1532 custom_accounts: None,
1533 min_hierarchy_depth: default_min_depth(),
1534 max_hierarchy_depth: default_max_depth(),
1535 }
1536 }
1537}
1538
1539#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1541pub struct TransactionConfig {
1542 #[serde(default)]
1544 pub line_item_distribution: LineItemDistributionConfig,
1545 #[serde(default)]
1547 pub debit_credit_distribution: DebitCreditDistributionConfig,
1548 #[serde(default)]
1550 pub even_odd_distribution: EvenOddDistributionConfig,
1551 #[serde(default)]
1553 pub source_distribution: SourceDistribution,
1554 #[serde(default)]
1556 pub seasonality: SeasonalityConfig,
1557 #[serde(default)]
1559 pub amounts: AmountDistributionConfig,
1560 #[serde(default)]
1562 pub benford: BenfordConfig,
1563}
1564
1565#[derive(Debug, Clone, Serialize, Deserialize)]
1567pub struct BenfordConfig {
1568 #[serde(default = "default_true")]
1570 pub enabled: bool,
1571 #[serde(default = "default_benford_tolerance")]
1573 pub tolerance: f64,
1574 #[serde(default)]
1576 pub exempt_sources: Vec<BenfordExemption>,
1577}
1578
1579fn default_benford_tolerance() -> f64 {
1580 0.05
1581}
1582
1583impl Default for BenfordConfig {
1584 fn default() -> Self {
1585 Self {
1586 enabled: true,
1587 tolerance: default_benford_tolerance(),
1588 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1589 }
1590 }
1591}
1592
1593#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1595#[serde(rename_all = "snake_case")]
1596pub enum BenfordExemption {
1597 Recurring,
1599 Payroll,
1601 FixedFees,
1603 RoundAmounts,
1605}
1606
1607#[derive(Debug, Clone, Serialize, Deserialize)]
1609pub struct SourceDistribution {
1610 pub manual: f64,
1612 pub automated: f64,
1614 pub recurring: f64,
1616 pub adjustment: f64,
1618}
1619
1620impl Default for SourceDistribution {
1621 fn default() -> Self {
1622 Self {
1623 manual: 0.20,
1624 automated: 0.70,
1625 recurring: 0.07,
1626 adjustment: 0.03,
1627 }
1628 }
1629}
1630
1631#[derive(Debug, Clone, Serialize, Deserialize)]
1633pub struct OutputConfig {
1634 #[serde(default)]
1636 pub mode: OutputMode,
1637 pub output_directory: PathBuf,
1639 #[serde(default = "default_formats")]
1641 pub formats: Vec<FileFormat>,
1642 #[serde(default)]
1644 pub compression: CompressionConfig,
1645 #[serde(default = "default_batch_size")]
1647 pub batch_size: usize,
1648 #[serde(default = "default_true")]
1650 pub include_acdoca: bool,
1651 #[serde(default)]
1653 pub include_bseg: bool,
1654 #[serde(default = "default_true")]
1656 pub partition_by_period: bool,
1657 #[serde(default)]
1659 pub partition_by_company: bool,
1660 #[serde(default)]
1664 pub numeric_mode: NumericMode,
1665 #[serde(default, alias = "exportLayout")]
1677 pub export_layout: ExportLayout,
1678}
1679
1680fn default_formats() -> Vec<FileFormat> {
1681 vec![FileFormat::Parquet]
1682}
1683fn default_batch_size() -> usize {
1684 100_000
1685}
1686
1687impl Default for OutputConfig {
1688 fn default() -> Self {
1689 Self {
1690 mode: OutputMode::FlatFile,
1691 output_directory: PathBuf::from("./output"),
1692 formats: default_formats(),
1693 compression: CompressionConfig::default(),
1694 batch_size: default_batch_size(),
1695 include_acdoca: true,
1696 include_bseg: false,
1697 partition_by_period: true,
1698 partition_by_company: false,
1699 numeric_mode: NumericMode::default(),
1700 export_layout: ExportLayout::default(),
1701 }
1702 }
1703}
1704
1705#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1707#[serde(rename_all = "snake_case")]
1708pub enum NumericMode {
1709 #[default]
1711 String,
1712 Native,
1714}
1715
1716#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1718#[serde(rename_all = "snake_case")]
1719pub enum ExportLayout {
1720 #[default]
1722 Nested,
1723 Flat,
1725}
1726
1727#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1729#[serde(rename_all = "snake_case")]
1730pub enum OutputMode {
1731 Streaming,
1733 #[default]
1735 FlatFile,
1736 Both,
1738}
1739
1740#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1742#[serde(rename_all = "snake_case")]
1743pub enum FileFormat {
1744 Csv,
1745 Parquet,
1746 Json,
1747 JsonLines,
1748}
1749
1750#[derive(Debug, Clone, Serialize, Deserialize)]
1752pub struct CompressionConfig {
1753 #[serde(default = "default_true")]
1755 pub enabled: bool,
1756 #[serde(default)]
1758 pub algorithm: CompressionAlgorithm,
1759 #[serde(default = "default_compression_level")]
1761 pub level: u8,
1762}
1763
1764fn default_compression_level() -> u8 {
1765 3
1766}
1767
1768impl Default for CompressionConfig {
1769 fn default() -> Self {
1770 Self {
1771 enabled: true,
1772 algorithm: CompressionAlgorithm::default(),
1773 level: default_compression_level(),
1774 }
1775 }
1776}
1777
1778#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1780#[serde(rename_all = "snake_case")]
1781pub enum CompressionAlgorithm {
1782 Gzip,
1783 #[default]
1784 Zstd,
1785 Lz4,
1786 Snappy,
1787}
1788
1789#[derive(Debug, Clone, Serialize, Deserialize)]
1809pub struct FraudConfig {
1810 #[serde(default)]
1812 pub enabled: bool,
1813 #[serde(default = "default_fraud_rate", alias = "fraudRate")]
1831 pub fraud_rate: f64,
1832 #[serde(default, alias = "documentFraudRate")]
1837 pub document_fraud_rate: Option<f64>,
1838 #[serde(default = "default_true", alias = "propagateToLines")]
1843 pub propagate_to_lines: bool,
1844 #[serde(default = "default_true", alias = "propagateToDocument")]
1848 pub propagate_to_document: bool,
1849 #[serde(default)]
1851 pub fraud_type_distribution: FraudTypeDistribution,
1852 #[serde(default)]
1854 pub clustering_enabled: bool,
1855 #[serde(default = "default_clustering_factor")]
1857 pub clustering_factor: f64,
1858 #[serde(default = "default_approval_thresholds")]
1860 pub approval_thresholds: Vec<f64>,
1861}
1862
1863fn default_approval_thresholds() -> Vec<f64> {
1864 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1865}
1866
1867fn default_fraud_rate() -> f64 {
1868 0.005
1869}
1870fn default_clustering_factor() -> f64 {
1871 3.0
1872}
1873
1874impl Default for FraudConfig {
1875 fn default() -> Self {
1876 Self {
1877 enabled: false,
1878 fraud_rate: default_fraud_rate(),
1879 document_fraud_rate: None,
1880 propagate_to_lines: true,
1881 propagate_to_document: true,
1882 fraud_type_distribution: FraudTypeDistribution::default(),
1883 clustering_enabled: false,
1884 clustering_factor: default_clustering_factor(),
1885 approval_thresholds: default_approval_thresholds(),
1886 }
1887 }
1888}
1889
1890#[derive(Debug, Clone, Serialize, Deserialize)]
1892pub struct FraudTypeDistribution {
1893 pub suspense_account_abuse: f64,
1894 pub fictitious_transaction: f64,
1895 pub revenue_manipulation: f64,
1896 pub expense_capitalization: f64,
1897 pub split_transaction: f64,
1898 pub timing_anomaly: f64,
1899 pub unauthorized_access: f64,
1900 pub duplicate_payment: f64,
1901}
1902
1903impl Default for FraudTypeDistribution {
1904 fn default() -> Self {
1905 Self {
1906 suspense_account_abuse: 0.25,
1907 fictitious_transaction: 0.15,
1908 revenue_manipulation: 0.10,
1909 expense_capitalization: 0.10,
1910 split_transaction: 0.15,
1911 timing_anomaly: 0.10,
1912 unauthorized_access: 0.10,
1913 duplicate_payment: 0.05,
1914 }
1915 }
1916}
1917
1918#[derive(Debug, Clone, Serialize, Deserialize)]
1920pub struct InternalControlsConfig {
1921 #[serde(default)]
1923 pub enabled: bool,
1924 #[serde(default = "default_exception_rate")]
1926 pub exception_rate: f64,
1927 #[serde(default = "default_sod_violation_rate")]
1929 pub sod_violation_rate: f64,
1930 #[serde(default = "default_true")]
1932 pub export_control_master_data: bool,
1933 #[serde(default = "default_sox_materiality_threshold")]
1935 pub sox_materiality_threshold: f64,
1936 #[serde(default = "default_true")]
1938 pub coso_enabled: bool,
1939 #[serde(default)]
1941 pub include_entity_level_controls: bool,
1942 #[serde(default = "default_target_maturity_level")]
1945 pub target_maturity_level: String,
1946}
1947
1948fn default_exception_rate() -> f64 {
1949 0.02
1950}
1951
1952fn default_sod_violation_rate() -> f64 {
1953 0.01
1954}
1955
1956fn default_sox_materiality_threshold() -> f64 {
1957 10000.0
1958}
1959
1960fn default_target_maturity_level() -> String {
1961 "mixed".to_string()
1962}
1963
1964impl Default for InternalControlsConfig {
1965 fn default() -> Self {
1966 Self {
1967 enabled: false,
1968 exception_rate: default_exception_rate(),
1969 sod_violation_rate: default_sod_violation_rate(),
1970 export_control_master_data: true,
1971 sox_materiality_threshold: default_sox_materiality_threshold(),
1972 coso_enabled: true,
1973 include_entity_level_controls: false,
1974 target_maturity_level: default_target_maturity_level(),
1975 }
1976 }
1977}
1978
1979#[derive(Debug, Clone, Serialize, Deserialize)]
1981pub struct BusinessProcessConfig {
1982 #[serde(default = "default_o2c")]
1984 pub o2c_weight: f64,
1985 #[serde(default = "default_p2p")]
1987 pub p2p_weight: f64,
1988 #[serde(default = "default_r2r")]
1990 pub r2r_weight: f64,
1991 #[serde(default = "default_h2r")]
1993 pub h2r_weight: f64,
1994 #[serde(default = "default_a2r")]
1996 pub a2r_weight: f64,
1997}
1998
1999fn default_o2c() -> f64 {
2000 0.35
2001}
2002fn default_p2p() -> f64 {
2003 0.30
2004}
2005fn default_r2r() -> f64 {
2006 0.20
2007}
2008fn default_h2r() -> f64 {
2009 0.10
2010}
2011fn default_a2r() -> f64 {
2012 0.05
2013}
2014
2015impl Default for BusinessProcessConfig {
2016 fn default() -> Self {
2017 Self {
2018 o2c_weight: default_o2c(),
2019 p2p_weight: default_p2p(),
2020 r2r_weight: default_r2r(),
2021 h2r_weight: default_h2r(),
2022 a2r_weight: default_a2r(),
2023 }
2024 }
2025}
2026
2027#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2029pub struct UserPersonaConfig {
2030 #[serde(default)]
2032 pub persona_distribution: PersonaDistribution,
2033 #[serde(default)]
2035 pub users_per_persona: UsersPerPersona,
2036}
2037
2038#[derive(Debug, Clone, Serialize, Deserialize)]
2040pub struct PersonaDistribution {
2041 pub junior_accountant: f64,
2042 pub senior_accountant: f64,
2043 pub controller: f64,
2044 pub manager: f64,
2045 pub automated_system: f64,
2046}
2047
2048impl Default for PersonaDistribution {
2049 fn default() -> Self {
2050 Self {
2051 junior_accountant: 0.15,
2052 senior_accountant: 0.15,
2053 controller: 0.05,
2054 manager: 0.05,
2055 automated_system: 0.60,
2056 }
2057 }
2058}
2059
2060#[derive(Debug, Clone, Serialize, Deserialize)]
2062pub struct UsersPerPersona {
2063 pub junior_accountant: usize,
2064 pub senior_accountant: usize,
2065 pub controller: usize,
2066 pub manager: usize,
2067 pub automated_system: usize,
2068}
2069
2070impl Default for UsersPerPersona {
2071 fn default() -> Self {
2072 Self {
2073 junior_accountant: 10,
2074 senior_accountant: 5,
2075 controller: 2,
2076 manager: 3,
2077 automated_system: 20,
2078 }
2079 }
2080}
2081
2082#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2096pub struct TemplateConfig {
2097 #[serde(default)]
2099 pub names: NameTemplateConfig,
2100 #[serde(default)]
2102 pub descriptions: DescriptionTemplateConfig,
2103 #[serde(default)]
2105 pub references: ReferenceTemplateConfig,
2106 #[serde(default, alias = "templatesPath")]
2112 pub path: Option<std::path::PathBuf>,
2113 #[serde(default, alias = "mergeStrategy")]
2122 pub merge_strategy: TemplateMergeStrategy,
2123}
2124
2125#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
2127#[serde(rename_all = "snake_case")]
2128pub enum TemplateMergeStrategy {
2129 #[default]
2131 Extend,
2132 Replace,
2134 MergePreferFile,
2136}
2137
2138#[derive(Debug, Clone, Serialize, Deserialize)]
2140pub struct NameTemplateConfig {
2141 #[serde(default)]
2143 pub culture_distribution: CultureDistribution,
2144 #[serde(default = "default_email_domain")]
2146 pub email_domain: String,
2147 #[serde(default = "default_true")]
2149 pub generate_realistic_names: bool,
2150}
2151
2152fn default_email_domain() -> String {
2153 "company.com".to_string()
2154}
2155
2156impl Default for NameTemplateConfig {
2157 fn default() -> Self {
2158 Self {
2159 culture_distribution: CultureDistribution::default(),
2160 email_domain: default_email_domain(),
2161 generate_realistic_names: true,
2162 }
2163 }
2164}
2165
2166#[derive(Debug, Clone, Serialize, Deserialize)]
2168pub struct CultureDistribution {
2169 pub western_us: f64,
2170 pub hispanic: f64,
2171 pub german: f64,
2172 pub french: f64,
2173 pub chinese: f64,
2174 pub japanese: f64,
2175 pub indian: f64,
2176}
2177
2178impl Default for CultureDistribution {
2179 fn default() -> Self {
2180 Self {
2181 western_us: 0.40,
2182 hispanic: 0.20,
2183 german: 0.10,
2184 french: 0.05,
2185 chinese: 0.10,
2186 japanese: 0.05,
2187 indian: 0.10,
2188 }
2189 }
2190}
2191
2192#[derive(Debug, Clone, Serialize, Deserialize)]
2194pub struct DescriptionTemplateConfig {
2195 #[serde(default = "default_true")]
2197 pub generate_header_text: bool,
2198 #[serde(default = "default_true")]
2200 pub generate_line_text: bool,
2201}
2202
2203impl Default for DescriptionTemplateConfig {
2204 fn default() -> Self {
2205 Self {
2206 generate_header_text: true,
2207 generate_line_text: true,
2208 }
2209 }
2210}
2211
2212#[derive(Debug, Clone, Serialize, Deserialize)]
2214pub struct ReferenceTemplateConfig {
2215 #[serde(default = "default_true")]
2217 pub generate_references: bool,
2218 #[serde(default = "default_invoice_prefix")]
2220 pub invoice_prefix: String,
2221 #[serde(default = "default_po_prefix")]
2223 pub po_prefix: String,
2224 #[serde(default = "default_so_prefix")]
2226 pub so_prefix: String,
2227}
2228
2229fn default_invoice_prefix() -> String {
2230 "INV".to_string()
2231}
2232fn default_po_prefix() -> String {
2233 "PO".to_string()
2234}
2235fn default_so_prefix() -> String {
2236 "SO".to_string()
2237}
2238
2239impl Default for ReferenceTemplateConfig {
2240 fn default() -> Self {
2241 Self {
2242 generate_references: true,
2243 invoice_prefix: default_invoice_prefix(),
2244 po_prefix: default_po_prefix(),
2245 so_prefix: default_so_prefix(),
2246 }
2247 }
2248}
2249
2250#[derive(Debug, Clone, Serialize, Deserialize)]
2252pub struct ApprovalConfig {
2253 #[serde(default)]
2255 pub enabled: bool,
2256 #[serde(default = "default_auto_approve_threshold")]
2258 pub auto_approve_threshold: f64,
2259 #[serde(default = "default_rejection_rate")]
2261 pub rejection_rate: f64,
2262 #[serde(default = "default_revision_rate")]
2264 pub revision_rate: f64,
2265 #[serde(default = "default_approval_delay_hours")]
2267 pub average_approval_delay_hours: f64,
2268 #[serde(default)]
2270 pub thresholds: Vec<ApprovalThresholdConfig>,
2271}
2272
2273fn default_auto_approve_threshold() -> f64 {
2274 1000.0
2275}
2276fn default_rejection_rate() -> f64 {
2277 0.02
2278}
2279fn default_revision_rate() -> f64 {
2280 0.05
2281}
2282fn default_approval_delay_hours() -> f64 {
2283 4.0
2284}
2285
2286impl Default for ApprovalConfig {
2287 fn default() -> Self {
2288 Self {
2289 enabled: false,
2290 auto_approve_threshold: default_auto_approve_threshold(),
2291 rejection_rate: default_rejection_rate(),
2292 revision_rate: default_revision_rate(),
2293 average_approval_delay_hours: default_approval_delay_hours(),
2294 thresholds: vec![
2295 ApprovalThresholdConfig {
2296 amount: 1000.0,
2297 level: 1,
2298 roles: vec!["senior_accountant".to_string()],
2299 },
2300 ApprovalThresholdConfig {
2301 amount: 10000.0,
2302 level: 2,
2303 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2304 },
2305 ApprovalThresholdConfig {
2306 amount: 100000.0,
2307 level: 3,
2308 roles: vec![
2309 "senior_accountant".to_string(),
2310 "controller".to_string(),
2311 "manager".to_string(),
2312 ],
2313 },
2314 ApprovalThresholdConfig {
2315 amount: 500000.0,
2316 level: 4,
2317 roles: vec![
2318 "senior_accountant".to_string(),
2319 "controller".to_string(),
2320 "manager".to_string(),
2321 "executive".to_string(),
2322 ],
2323 },
2324 ],
2325 }
2326 }
2327}
2328
2329#[derive(Debug, Clone, Serialize, Deserialize)]
2331pub struct ApprovalThresholdConfig {
2332 pub amount: f64,
2334 pub level: u8,
2336 pub roles: Vec<String>,
2338}
2339
2340#[derive(Debug, Clone, Serialize, Deserialize)]
2342pub struct DepartmentConfig {
2343 #[serde(default)]
2345 pub enabled: bool,
2346 #[serde(default = "default_headcount_multiplier")]
2348 pub headcount_multiplier: f64,
2349 #[serde(default)]
2351 pub custom_departments: Vec<CustomDepartmentConfig>,
2352}
2353
2354fn default_headcount_multiplier() -> f64 {
2355 1.0
2356}
2357
2358impl Default for DepartmentConfig {
2359 fn default() -> Self {
2360 Self {
2361 enabled: false,
2362 headcount_multiplier: default_headcount_multiplier(),
2363 custom_departments: Vec::new(),
2364 }
2365 }
2366}
2367
2368#[derive(Debug, Clone, Serialize, Deserialize)]
2370pub struct CustomDepartmentConfig {
2371 pub code: String,
2373 pub name: String,
2375 #[serde(default)]
2377 pub cost_center: Option<String>,
2378 #[serde(default)]
2380 pub primary_processes: Vec<String>,
2381 #[serde(default)]
2383 pub parent_code: Option<String>,
2384}
2385
2386#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2392pub struct MasterDataConfig {
2393 #[serde(default)]
2395 pub vendors: VendorMasterConfig,
2396 #[serde(default)]
2398 pub customers: CustomerMasterConfig,
2399 #[serde(default)]
2401 pub materials: MaterialMasterConfig,
2402 #[serde(default)]
2404 pub fixed_assets: FixedAssetMasterConfig,
2405 #[serde(default)]
2407 pub employees: EmployeeMasterConfig,
2408 #[serde(default)]
2410 pub cost_centers: CostCenterMasterConfig,
2411}
2412
2413#[derive(Debug, Clone, Serialize, Deserialize)]
2415pub struct VendorMasterConfig {
2416 #[serde(default = "default_vendor_count")]
2418 pub count: usize,
2419 #[serde(default = "default_intercompany_percent")]
2421 pub intercompany_percent: f64,
2422 #[serde(default)]
2424 pub payment_terms_distribution: PaymentTermsDistribution,
2425 #[serde(default)]
2427 pub behavior_distribution: VendorBehaviorDistribution,
2428 #[serde(default = "default_true")]
2430 pub generate_bank_accounts: bool,
2431 #[serde(default = "default_true")]
2433 pub generate_tax_ids: bool,
2434}
2435
2436fn default_vendor_count() -> usize {
2437 500
2438}
2439
2440fn default_intercompany_percent() -> f64 {
2441 0.05
2442}
2443
2444impl Default for VendorMasterConfig {
2445 fn default() -> Self {
2446 Self {
2447 count: default_vendor_count(),
2448 intercompany_percent: default_intercompany_percent(),
2449 payment_terms_distribution: PaymentTermsDistribution::default(),
2450 behavior_distribution: VendorBehaviorDistribution::default(),
2451 generate_bank_accounts: true,
2452 generate_tax_ids: true,
2453 }
2454 }
2455}
2456
2457#[derive(Debug, Clone, Serialize, Deserialize)]
2459pub struct PaymentTermsDistribution {
2460 pub net_30: f64,
2462 pub net_60: f64,
2464 pub net_90: f64,
2466 pub two_ten_net_30: f64,
2468 pub due_on_receipt: f64,
2470 pub end_of_month: f64,
2472}
2473
2474impl Default for PaymentTermsDistribution {
2475 fn default() -> Self {
2476 Self {
2477 net_30: 0.40,
2478 net_60: 0.20,
2479 net_90: 0.10,
2480 two_ten_net_30: 0.15,
2481 due_on_receipt: 0.05,
2482 end_of_month: 0.10,
2483 }
2484 }
2485}
2486
2487#[derive(Debug, Clone, Serialize, Deserialize)]
2489pub struct VendorBehaviorDistribution {
2490 pub reliable: f64,
2492 pub sometimes_late: f64,
2494 pub inconsistent_quality: f64,
2496 pub premium: f64,
2498 pub budget: f64,
2500}
2501
2502impl Default for VendorBehaviorDistribution {
2503 fn default() -> Self {
2504 Self {
2505 reliable: 0.50,
2506 sometimes_late: 0.20,
2507 inconsistent_quality: 0.10,
2508 premium: 0.10,
2509 budget: 0.10,
2510 }
2511 }
2512}
2513
2514#[derive(Debug, Clone, Serialize, Deserialize)]
2516pub struct CustomerMasterConfig {
2517 #[serde(default = "default_customer_count")]
2519 pub count: usize,
2520 #[serde(default = "default_intercompany_percent")]
2522 pub intercompany_percent: f64,
2523 #[serde(default)]
2525 pub credit_rating_distribution: CreditRatingDistribution,
2526 #[serde(default)]
2528 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2529 #[serde(default = "default_true")]
2531 pub generate_credit_limits: bool,
2532}
2533
2534fn default_customer_count() -> usize {
2535 2000
2536}
2537
2538impl Default for CustomerMasterConfig {
2539 fn default() -> Self {
2540 Self {
2541 count: default_customer_count(),
2542 intercompany_percent: default_intercompany_percent(),
2543 credit_rating_distribution: CreditRatingDistribution::default(),
2544 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2545 generate_credit_limits: true,
2546 }
2547 }
2548}
2549
2550#[derive(Debug, Clone, Serialize, Deserialize)]
2552pub struct CreditRatingDistribution {
2553 pub aaa: f64,
2555 pub aa: f64,
2557 pub a: f64,
2559 pub bbb: f64,
2561 pub bb: f64,
2563 pub b: f64,
2565 pub below_b: f64,
2567}
2568
2569impl Default for CreditRatingDistribution {
2570 fn default() -> Self {
2571 Self {
2572 aaa: 0.05,
2573 aa: 0.10,
2574 a: 0.20,
2575 bbb: 0.30,
2576 bb: 0.20,
2577 b: 0.10,
2578 below_b: 0.05,
2579 }
2580 }
2581}
2582
2583#[derive(Debug, Clone, Serialize, Deserialize)]
2585pub struct PaymentBehaviorDistribution {
2586 pub early_payer: f64,
2588 pub on_time: f64,
2590 pub occasional_late: f64,
2592 pub frequent_late: f64,
2594 pub discount_taker: f64,
2596}
2597
2598impl Default for PaymentBehaviorDistribution {
2599 fn default() -> Self {
2600 Self {
2601 early_payer: 0.10,
2602 on_time: 0.50,
2603 occasional_late: 0.25,
2604 frequent_late: 0.10,
2605 discount_taker: 0.05,
2606 }
2607 }
2608}
2609
2610#[derive(Debug, Clone, Serialize, Deserialize)]
2612pub struct MaterialMasterConfig {
2613 #[serde(default = "default_material_count")]
2615 pub count: usize,
2616 #[serde(default)]
2618 pub type_distribution: MaterialTypeDistribution,
2619 #[serde(default)]
2621 pub valuation_distribution: ValuationMethodDistribution,
2622 #[serde(default = "default_bom_percent")]
2624 pub bom_percent: f64,
2625 #[serde(default = "default_max_bom_depth")]
2627 pub max_bom_depth: u8,
2628}
2629
2630fn default_material_count() -> usize {
2631 5000
2632}
2633
2634fn default_bom_percent() -> f64 {
2635 0.20
2636}
2637
2638fn default_max_bom_depth() -> u8 {
2639 3
2640}
2641
2642impl Default for MaterialMasterConfig {
2643 fn default() -> Self {
2644 Self {
2645 count: default_material_count(),
2646 type_distribution: MaterialTypeDistribution::default(),
2647 valuation_distribution: ValuationMethodDistribution::default(),
2648 bom_percent: default_bom_percent(),
2649 max_bom_depth: default_max_bom_depth(),
2650 }
2651 }
2652}
2653
2654#[derive(Debug, Clone, Serialize, Deserialize)]
2656pub struct MaterialTypeDistribution {
2657 pub raw_material: f64,
2659 pub semi_finished: f64,
2661 pub finished_good: f64,
2663 pub trading_good: f64,
2665 pub operating_supply: f64,
2667 pub service: f64,
2669}
2670
2671impl Default for MaterialTypeDistribution {
2672 fn default() -> Self {
2673 Self {
2674 raw_material: 0.30,
2675 semi_finished: 0.15,
2676 finished_good: 0.25,
2677 trading_good: 0.15,
2678 operating_supply: 0.10,
2679 service: 0.05,
2680 }
2681 }
2682}
2683
2684#[derive(Debug, Clone, Serialize, Deserialize)]
2686pub struct ValuationMethodDistribution {
2687 pub standard_cost: f64,
2689 pub moving_average: f64,
2691 pub fifo: f64,
2693 pub lifo: f64,
2695}
2696
2697impl Default for ValuationMethodDistribution {
2698 fn default() -> Self {
2699 Self {
2700 standard_cost: 0.50,
2701 moving_average: 0.30,
2702 fifo: 0.15,
2703 lifo: 0.05,
2704 }
2705 }
2706}
2707
2708#[derive(Debug, Clone, Serialize, Deserialize)]
2710pub struct FixedAssetMasterConfig {
2711 #[serde(default = "default_asset_count")]
2713 pub count: usize,
2714 #[serde(default)]
2716 pub class_distribution: AssetClassDistribution,
2717 #[serde(default)]
2719 pub depreciation_distribution: DepreciationMethodDistribution,
2720 #[serde(default = "default_fully_depreciated_percent")]
2722 pub fully_depreciated_percent: f64,
2723 #[serde(default = "default_true")]
2725 pub generate_acquisition_history: bool,
2726}
2727
2728fn default_asset_count() -> usize {
2729 800
2730}
2731
2732fn default_fully_depreciated_percent() -> f64 {
2733 0.15
2734}
2735
2736impl Default for FixedAssetMasterConfig {
2737 fn default() -> Self {
2738 Self {
2739 count: default_asset_count(),
2740 class_distribution: AssetClassDistribution::default(),
2741 depreciation_distribution: DepreciationMethodDistribution::default(),
2742 fully_depreciated_percent: default_fully_depreciated_percent(),
2743 generate_acquisition_history: true,
2744 }
2745 }
2746}
2747
2748#[derive(Debug, Clone, Serialize, Deserialize)]
2750pub struct AssetClassDistribution {
2751 pub buildings: f64,
2753 pub machinery: f64,
2755 pub vehicles: f64,
2757 pub it_equipment: f64,
2759 pub furniture: f64,
2761 pub land: f64,
2763 pub leasehold: f64,
2765}
2766
2767impl Default for AssetClassDistribution {
2768 fn default() -> Self {
2769 Self {
2770 buildings: 0.15,
2771 machinery: 0.30,
2772 vehicles: 0.15,
2773 it_equipment: 0.20,
2774 furniture: 0.10,
2775 land: 0.05,
2776 leasehold: 0.05,
2777 }
2778 }
2779}
2780
2781#[derive(Debug, Clone, Serialize, Deserialize)]
2783pub struct DepreciationMethodDistribution {
2784 pub straight_line: f64,
2786 pub declining_balance: f64,
2788 pub double_declining: f64,
2790 pub sum_of_years: f64,
2792 pub units_of_production: f64,
2794}
2795
2796impl Default for DepreciationMethodDistribution {
2797 fn default() -> Self {
2798 Self {
2799 straight_line: 0.60,
2800 declining_balance: 0.20,
2801 double_declining: 0.10,
2802 sum_of_years: 0.05,
2803 units_of_production: 0.05,
2804 }
2805 }
2806}
2807
2808#[derive(Debug, Clone, Serialize, Deserialize)]
2810pub struct EmployeeMasterConfig {
2811 #[serde(default = "default_employee_count")]
2813 pub count: usize,
2814 #[serde(default = "default_true")]
2816 pub generate_hierarchy: bool,
2817 #[serde(default = "default_hierarchy_depth")]
2819 pub max_hierarchy_depth: u8,
2820 #[serde(default = "default_span_of_control")]
2822 pub average_span_of_control: f64,
2823 #[serde(default)]
2825 pub approval_limits: ApprovalLimitDistribution,
2826 #[serde(default)]
2828 pub department_distribution: EmployeeDepartmentDistribution,
2829}
2830
2831fn default_employee_count() -> usize {
2832 1500
2833}
2834
2835fn default_hierarchy_depth() -> u8 {
2836 6
2837}
2838
2839fn default_span_of_control() -> f64 {
2840 5.0
2841}
2842
2843impl Default for EmployeeMasterConfig {
2844 fn default() -> Self {
2845 Self {
2846 count: default_employee_count(),
2847 generate_hierarchy: true,
2848 max_hierarchy_depth: default_hierarchy_depth(),
2849 average_span_of_control: default_span_of_control(),
2850 approval_limits: ApprovalLimitDistribution::default(),
2851 department_distribution: EmployeeDepartmentDistribution::default(),
2852 }
2853 }
2854}
2855
2856#[derive(Debug, Clone, Serialize, Deserialize)]
2858pub struct ApprovalLimitDistribution {
2859 #[serde(default = "default_staff_limit")]
2861 pub staff: f64,
2862 #[serde(default = "default_senior_limit")]
2864 pub senior: f64,
2865 #[serde(default = "default_manager_limit")]
2867 pub manager: f64,
2868 #[serde(default = "default_director_limit")]
2870 pub director: f64,
2871 #[serde(default = "default_vp_limit")]
2873 pub vp: f64,
2874 #[serde(default = "default_executive_limit")]
2876 pub executive: f64,
2877}
2878
2879fn default_staff_limit() -> f64 {
2880 1000.0
2881}
2882fn default_senior_limit() -> f64 {
2883 5000.0
2884}
2885fn default_manager_limit() -> f64 {
2886 25000.0
2887}
2888fn default_director_limit() -> f64 {
2889 100000.0
2890}
2891fn default_vp_limit() -> f64 {
2892 500000.0
2893}
2894fn default_executive_limit() -> f64 {
2895 f64::INFINITY
2896}
2897
2898impl Default for ApprovalLimitDistribution {
2899 fn default() -> Self {
2900 Self {
2901 staff: default_staff_limit(),
2902 senior: default_senior_limit(),
2903 manager: default_manager_limit(),
2904 director: default_director_limit(),
2905 vp: default_vp_limit(),
2906 executive: default_executive_limit(),
2907 }
2908 }
2909}
2910
2911#[derive(Debug, Clone, Serialize, Deserialize)]
2913pub struct EmployeeDepartmentDistribution {
2914 pub finance: f64,
2916 pub procurement: f64,
2918 pub sales: f64,
2920 pub warehouse: f64,
2922 pub it: f64,
2924 pub hr: f64,
2926 pub operations: f64,
2928 pub executive: f64,
2930}
2931
2932impl Default for EmployeeDepartmentDistribution {
2933 fn default() -> Self {
2934 Self {
2935 finance: 0.12,
2936 procurement: 0.10,
2937 sales: 0.25,
2938 warehouse: 0.15,
2939 it: 0.10,
2940 hr: 0.05,
2941 operations: 0.20,
2942 executive: 0.03,
2943 }
2944 }
2945}
2946
2947#[derive(Debug, Clone, Serialize, Deserialize)]
2949pub struct CostCenterMasterConfig {
2950 #[serde(default = "default_cost_center_count")]
2952 pub count: usize,
2953 #[serde(default = "default_true")]
2955 pub generate_hierarchy: bool,
2956 #[serde(default = "default_cc_hierarchy_depth")]
2958 pub max_hierarchy_depth: u8,
2959}
2960
2961fn default_cost_center_count() -> usize {
2962 50
2963}
2964
2965fn default_cc_hierarchy_depth() -> u8 {
2966 3
2967}
2968
2969impl Default for CostCenterMasterConfig {
2970 fn default() -> Self {
2971 Self {
2972 count: default_cost_center_count(),
2973 generate_hierarchy: true,
2974 max_hierarchy_depth: default_cc_hierarchy_depth(),
2975 }
2976 }
2977}
2978
2979#[derive(Debug, Clone, Serialize, Deserialize)]
2985pub struct DocumentFlowConfig {
2986 #[serde(default)]
2988 pub p2p: P2PFlowConfig,
2989 #[serde(default)]
2991 pub o2c: O2CFlowConfig,
2992 #[serde(default = "default_true")]
2994 pub generate_document_references: bool,
2995 #[serde(default)]
2997 pub export_flow_graph: bool,
2998}
2999
3000impl Default for DocumentFlowConfig {
3001 fn default() -> Self {
3002 Self {
3003 p2p: P2PFlowConfig::default(),
3004 o2c: O2CFlowConfig::default(),
3005 generate_document_references: true,
3006 export_flow_graph: false,
3007 }
3008 }
3009}
3010
3011#[derive(Debug, Clone, Serialize, Deserialize)]
3013pub struct P2PFlowConfig {
3014 #[serde(default = "default_true")]
3016 pub enabled: bool,
3017 #[serde(default = "default_three_way_match_rate")]
3019 pub three_way_match_rate: f64,
3020 #[serde(default = "default_partial_delivery_rate")]
3022 pub partial_delivery_rate: f64,
3023 #[serde(default = "default_price_variance_rate")]
3025 pub price_variance_rate: f64,
3026 #[serde(default = "default_max_price_variance")]
3028 pub max_price_variance_percent: f64,
3029 #[serde(default = "default_quantity_variance_rate")]
3031 pub quantity_variance_rate: f64,
3032 #[serde(default = "default_po_to_gr_days")]
3034 pub average_po_to_gr_days: u32,
3035 #[serde(default = "default_gr_to_invoice_days")]
3037 pub average_gr_to_invoice_days: u32,
3038 #[serde(default = "default_invoice_to_payment_days")]
3040 pub average_invoice_to_payment_days: u32,
3041 #[serde(default)]
3043 pub line_count_distribution: DocumentLineCountDistribution,
3044 #[serde(default)]
3046 pub payment_behavior: P2PPaymentBehaviorConfig,
3047 #[serde(default)]
3049 pub over_delivery_rate: Option<f64>,
3050 #[serde(default)]
3052 pub early_payment_discount_rate: Option<f64>,
3053}
3054
3055fn default_three_way_match_rate() -> f64 {
3056 0.95
3057}
3058
3059fn default_partial_delivery_rate() -> f64 {
3060 0.15
3061}
3062
3063fn default_price_variance_rate() -> f64 {
3064 0.08
3065}
3066
3067fn default_max_price_variance() -> f64 {
3068 0.05
3069}
3070
3071fn default_quantity_variance_rate() -> f64 {
3072 0.05
3073}
3074
3075fn default_po_to_gr_days() -> u32 {
3076 14
3077}
3078
3079fn default_gr_to_invoice_days() -> u32 {
3080 5
3081}
3082
3083fn default_invoice_to_payment_days() -> u32 {
3084 30
3085}
3086
3087impl Default for P2PFlowConfig {
3088 fn default() -> Self {
3089 Self {
3090 enabled: true,
3091 three_way_match_rate: default_three_way_match_rate(),
3092 partial_delivery_rate: default_partial_delivery_rate(),
3093 price_variance_rate: default_price_variance_rate(),
3094 max_price_variance_percent: default_max_price_variance(),
3095 quantity_variance_rate: default_quantity_variance_rate(),
3096 average_po_to_gr_days: default_po_to_gr_days(),
3097 average_gr_to_invoice_days: default_gr_to_invoice_days(),
3098 average_invoice_to_payment_days: default_invoice_to_payment_days(),
3099 line_count_distribution: DocumentLineCountDistribution::default(),
3100 payment_behavior: P2PPaymentBehaviorConfig::default(),
3101 over_delivery_rate: None,
3102 early_payment_discount_rate: None,
3103 }
3104 }
3105}
3106
3107#[derive(Debug, Clone, Serialize, Deserialize)]
3113pub struct P2PPaymentBehaviorConfig {
3114 #[serde(default = "default_p2p_late_payment_rate")]
3116 pub late_payment_rate: f64,
3117 #[serde(default)]
3119 pub late_payment_days_distribution: LatePaymentDaysDistribution,
3120 #[serde(default = "default_p2p_partial_payment_rate")]
3122 pub partial_payment_rate: f64,
3123 #[serde(default = "default_p2p_payment_correction_rate")]
3125 pub payment_correction_rate: f64,
3126 #[serde(default = "default_p2p_avg_days_until_remainder")]
3128 pub avg_days_until_remainder: u32,
3129}
3130
3131fn default_p2p_late_payment_rate() -> f64 {
3132 0.15
3133}
3134
3135fn default_p2p_partial_payment_rate() -> f64 {
3136 0.05
3137}
3138
3139fn default_p2p_payment_correction_rate() -> f64 {
3140 0.02
3141}
3142
3143fn default_p2p_avg_days_until_remainder() -> u32 {
3144 30
3145}
3146
3147impl Default for P2PPaymentBehaviorConfig {
3148 fn default() -> Self {
3149 Self {
3150 late_payment_rate: default_p2p_late_payment_rate(),
3151 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3152 partial_payment_rate: default_p2p_partial_payment_rate(),
3153 payment_correction_rate: default_p2p_payment_correction_rate(),
3154 avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3155 }
3156 }
3157}
3158
3159#[derive(Debug, Clone, Serialize, Deserialize)]
3161pub struct LatePaymentDaysDistribution {
3162 #[serde(default = "default_slightly_late")]
3164 pub slightly_late_1_to_7: f64,
3165 #[serde(default = "default_late_8_14")]
3167 pub late_8_to_14: f64,
3168 #[serde(default = "default_very_late")]
3170 pub very_late_15_to_30: f64,
3171 #[serde(default = "default_severely_late")]
3173 pub severely_late_31_to_60: f64,
3174 #[serde(default = "default_extremely_late")]
3176 pub extremely_late_over_60: f64,
3177}
3178
3179fn default_slightly_late() -> f64 {
3180 0.50
3181}
3182
3183fn default_late_8_14() -> f64 {
3184 0.25
3185}
3186
3187fn default_very_late() -> f64 {
3188 0.15
3189}
3190
3191fn default_severely_late() -> f64 {
3192 0.07
3193}
3194
3195fn default_extremely_late() -> f64 {
3196 0.03
3197}
3198
3199impl Default for LatePaymentDaysDistribution {
3200 fn default() -> Self {
3201 Self {
3202 slightly_late_1_to_7: default_slightly_late(),
3203 late_8_to_14: default_late_8_14(),
3204 very_late_15_to_30: default_very_late(),
3205 severely_late_31_to_60: default_severely_late(),
3206 extremely_late_over_60: default_extremely_late(),
3207 }
3208 }
3209}
3210
3211#[derive(Debug, Clone, Serialize, Deserialize)]
3213pub struct O2CFlowConfig {
3214 #[serde(default = "default_true")]
3216 pub enabled: bool,
3217 #[serde(default = "default_credit_check_failure_rate")]
3219 pub credit_check_failure_rate: f64,
3220 #[serde(default = "default_partial_shipment_rate")]
3222 pub partial_shipment_rate: f64,
3223 #[serde(default = "default_return_rate")]
3225 pub return_rate: f64,
3226 #[serde(default = "default_bad_debt_rate")]
3228 pub bad_debt_rate: f64,
3229 #[serde(default = "default_so_to_delivery_days")]
3231 pub average_so_to_delivery_days: u32,
3232 #[serde(default = "default_delivery_to_invoice_days")]
3234 pub average_delivery_to_invoice_days: u32,
3235 #[serde(default = "default_invoice_to_receipt_days")]
3237 pub average_invoice_to_receipt_days: u32,
3238 #[serde(default)]
3240 pub line_count_distribution: DocumentLineCountDistribution,
3241 #[serde(default)]
3243 pub cash_discount: CashDiscountConfig,
3244 #[serde(default)]
3246 pub payment_behavior: O2CPaymentBehaviorConfig,
3247 #[serde(default)]
3249 pub late_payment_rate: Option<f64>,
3250}
3251
3252fn default_credit_check_failure_rate() -> f64 {
3253 0.02
3254}
3255
3256fn default_partial_shipment_rate() -> f64 {
3257 0.10
3258}
3259
3260fn default_return_rate() -> f64 {
3261 0.03
3262}
3263
3264fn default_bad_debt_rate() -> f64 {
3265 0.01
3266}
3267
3268fn default_so_to_delivery_days() -> u32 {
3269 7
3270}
3271
3272fn default_delivery_to_invoice_days() -> u32 {
3273 1
3274}
3275
3276fn default_invoice_to_receipt_days() -> u32 {
3277 45
3278}
3279
3280impl Default for O2CFlowConfig {
3281 fn default() -> Self {
3282 Self {
3283 enabled: true,
3284 credit_check_failure_rate: default_credit_check_failure_rate(),
3285 partial_shipment_rate: default_partial_shipment_rate(),
3286 return_rate: default_return_rate(),
3287 bad_debt_rate: default_bad_debt_rate(),
3288 average_so_to_delivery_days: default_so_to_delivery_days(),
3289 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3290 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3291 line_count_distribution: DocumentLineCountDistribution::default(),
3292 cash_discount: CashDiscountConfig::default(),
3293 payment_behavior: O2CPaymentBehaviorConfig::default(),
3294 late_payment_rate: None,
3295 }
3296 }
3297}
3298
3299#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3305pub struct O2CPaymentBehaviorConfig {
3306 #[serde(default)]
3308 pub dunning: DunningConfig,
3309 #[serde(default)]
3311 pub partial_payments: PartialPaymentConfig,
3312 #[serde(default)]
3314 pub short_payments: ShortPaymentConfig,
3315 #[serde(default)]
3317 pub on_account_payments: OnAccountPaymentConfig,
3318 #[serde(default)]
3320 pub payment_corrections: PaymentCorrectionConfig,
3321}
3322
3323#[derive(Debug, Clone, Serialize, Deserialize)]
3325pub struct DunningConfig {
3326 #[serde(default)]
3328 pub enabled: bool,
3329 #[serde(default = "default_dunning_level_1_days")]
3331 pub level_1_days_overdue: u32,
3332 #[serde(default = "default_dunning_level_2_days")]
3334 pub level_2_days_overdue: u32,
3335 #[serde(default = "default_dunning_level_3_days")]
3337 pub level_3_days_overdue: u32,
3338 #[serde(default = "default_collection_days")]
3340 pub collection_days_overdue: u32,
3341 #[serde(default)]
3343 pub payment_after_dunning_rates: DunningPaymentRates,
3344 #[serde(default = "default_dunning_block_rate")]
3346 pub dunning_block_rate: f64,
3347 #[serde(default = "default_dunning_interest_rate")]
3349 pub interest_rate_per_year: f64,
3350 #[serde(default = "default_dunning_charge")]
3352 pub dunning_charge: f64,
3353}
3354
3355fn default_dunning_level_1_days() -> u32 {
3356 14
3357}
3358
3359fn default_dunning_level_2_days() -> u32 {
3360 28
3361}
3362
3363fn default_dunning_level_3_days() -> u32 {
3364 42
3365}
3366
3367fn default_collection_days() -> u32 {
3368 60
3369}
3370
3371fn default_dunning_block_rate() -> f64 {
3372 0.05
3373}
3374
3375fn default_dunning_interest_rate() -> f64 {
3376 0.09
3377}
3378
3379fn default_dunning_charge() -> f64 {
3380 25.0
3381}
3382
3383impl Default for DunningConfig {
3384 fn default() -> Self {
3385 Self {
3386 enabled: false,
3387 level_1_days_overdue: default_dunning_level_1_days(),
3388 level_2_days_overdue: default_dunning_level_2_days(),
3389 level_3_days_overdue: default_dunning_level_3_days(),
3390 collection_days_overdue: default_collection_days(),
3391 payment_after_dunning_rates: DunningPaymentRates::default(),
3392 dunning_block_rate: default_dunning_block_rate(),
3393 interest_rate_per_year: default_dunning_interest_rate(),
3394 dunning_charge: default_dunning_charge(),
3395 }
3396 }
3397}
3398
3399#[derive(Debug, Clone, Serialize, Deserialize)]
3401pub struct DunningPaymentRates {
3402 #[serde(default = "default_after_level_1")]
3404 pub after_level_1: f64,
3405 #[serde(default = "default_after_level_2")]
3407 pub after_level_2: f64,
3408 #[serde(default = "default_after_level_3")]
3410 pub after_level_3: f64,
3411 #[serde(default = "default_during_collection")]
3413 pub during_collection: f64,
3414 #[serde(default = "default_never_pay")]
3416 pub never_pay: f64,
3417}
3418
3419fn default_after_level_1() -> f64 {
3420 0.40
3421}
3422
3423fn default_after_level_2() -> f64 {
3424 0.30
3425}
3426
3427fn default_after_level_3() -> f64 {
3428 0.15
3429}
3430
3431fn default_during_collection() -> f64 {
3432 0.05
3433}
3434
3435fn default_never_pay() -> f64 {
3436 0.10
3437}
3438
3439impl Default for DunningPaymentRates {
3440 fn default() -> Self {
3441 Self {
3442 after_level_1: default_after_level_1(),
3443 after_level_2: default_after_level_2(),
3444 after_level_3: default_after_level_3(),
3445 during_collection: default_during_collection(),
3446 never_pay: default_never_pay(),
3447 }
3448 }
3449}
3450
3451#[derive(Debug, Clone, Serialize, Deserialize)]
3453pub struct PartialPaymentConfig {
3454 #[serde(default = "default_partial_payment_rate")]
3456 pub rate: f64,
3457 #[serde(default)]
3459 pub percentage_distribution: PartialPaymentPercentageDistribution,
3460 #[serde(default = "default_avg_days_until_remainder")]
3462 pub avg_days_until_remainder: u32,
3463}
3464
3465fn default_partial_payment_rate() -> f64 {
3466 0.08
3467}
3468
3469fn default_avg_days_until_remainder() -> u32 {
3470 30
3471}
3472
3473impl Default for PartialPaymentConfig {
3474 fn default() -> Self {
3475 Self {
3476 rate: default_partial_payment_rate(),
3477 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3478 avg_days_until_remainder: default_avg_days_until_remainder(),
3479 }
3480 }
3481}
3482
3483#[derive(Debug, Clone, Serialize, Deserialize)]
3485pub struct PartialPaymentPercentageDistribution {
3486 #[serde(default = "default_partial_25")]
3488 pub pay_25_percent: f64,
3489 #[serde(default = "default_partial_50")]
3491 pub pay_50_percent: f64,
3492 #[serde(default = "default_partial_75")]
3494 pub pay_75_percent: f64,
3495 #[serde(default = "default_partial_random")]
3497 pub pay_random_percent: f64,
3498}
3499
3500fn default_partial_25() -> f64 {
3501 0.15
3502}
3503
3504fn default_partial_50() -> f64 {
3505 0.50
3506}
3507
3508fn default_partial_75() -> f64 {
3509 0.25
3510}
3511
3512fn default_partial_random() -> f64 {
3513 0.10
3514}
3515
3516impl Default for PartialPaymentPercentageDistribution {
3517 fn default() -> Self {
3518 Self {
3519 pay_25_percent: default_partial_25(),
3520 pay_50_percent: default_partial_50(),
3521 pay_75_percent: default_partial_75(),
3522 pay_random_percent: default_partial_random(),
3523 }
3524 }
3525}
3526
3527#[derive(Debug, Clone, Serialize, Deserialize)]
3529pub struct ShortPaymentConfig {
3530 #[serde(default = "default_short_payment_rate")]
3532 pub rate: f64,
3533 #[serde(default)]
3535 pub reason_distribution: ShortPaymentReasonDistribution,
3536 #[serde(default = "default_max_short_percent")]
3538 pub max_short_percent: f64,
3539}
3540
3541fn default_short_payment_rate() -> f64 {
3542 0.03
3543}
3544
3545fn default_max_short_percent() -> f64 {
3546 0.10
3547}
3548
3549impl Default for ShortPaymentConfig {
3550 fn default() -> Self {
3551 Self {
3552 rate: default_short_payment_rate(),
3553 reason_distribution: ShortPaymentReasonDistribution::default(),
3554 max_short_percent: default_max_short_percent(),
3555 }
3556 }
3557}
3558
3559#[derive(Debug, Clone, Serialize, Deserialize)]
3561pub struct ShortPaymentReasonDistribution {
3562 #[serde(default = "default_pricing_dispute")]
3564 pub pricing_dispute: f64,
3565 #[serde(default = "default_quality_issue")]
3567 pub quality_issue: f64,
3568 #[serde(default = "default_quantity_discrepancy")]
3570 pub quantity_discrepancy: f64,
3571 #[serde(default = "default_unauthorized_deduction")]
3573 pub unauthorized_deduction: f64,
3574 #[serde(default = "default_incorrect_discount")]
3576 pub incorrect_discount: f64,
3577}
3578
3579fn default_pricing_dispute() -> f64 {
3580 0.30
3581}
3582
3583fn default_quality_issue() -> f64 {
3584 0.20
3585}
3586
3587fn default_quantity_discrepancy() -> f64 {
3588 0.20
3589}
3590
3591fn default_unauthorized_deduction() -> f64 {
3592 0.15
3593}
3594
3595fn default_incorrect_discount() -> f64 {
3596 0.15
3597}
3598
3599impl Default for ShortPaymentReasonDistribution {
3600 fn default() -> Self {
3601 Self {
3602 pricing_dispute: default_pricing_dispute(),
3603 quality_issue: default_quality_issue(),
3604 quantity_discrepancy: default_quantity_discrepancy(),
3605 unauthorized_deduction: default_unauthorized_deduction(),
3606 incorrect_discount: default_incorrect_discount(),
3607 }
3608 }
3609}
3610
3611#[derive(Debug, Clone, Serialize, Deserialize)]
3613pub struct OnAccountPaymentConfig {
3614 #[serde(default = "default_on_account_rate")]
3616 pub rate: f64,
3617 #[serde(default = "default_avg_days_until_applied")]
3619 pub avg_days_until_applied: u32,
3620}
3621
3622fn default_on_account_rate() -> f64 {
3623 0.02
3624}
3625
3626fn default_avg_days_until_applied() -> u32 {
3627 14
3628}
3629
3630impl Default for OnAccountPaymentConfig {
3631 fn default() -> Self {
3632 Self {
3633 rate: default_on_account_rate(),
3634 avg_days_until_applied: default_avg_days_until_applied(),
3635 }
3636 }
3637}
3638
3639#[derive(Debug, Clone, Serialize, Deserialize)]
3641pub struct PaymentCorrectionConfig {
3642 #[serde(default = "default_payment_correction_rate")]
3644 pub rate: f64,
3645 #[serde(default)]
3647 pub type_distribution: PaymentCorrectionTypeDistribution,
3648}
3649
3650fn default_payment_correction_rate() -> f64 {
3651 0.02
3652}
3653
3654impl Default for PaymentCorrectionConfig {
3655 fn default() -> Self {
3656 Self {
3657 rate: default_payment_correction_rate(),
3658 type_distribution: PaymentCorrectionTypeDistribution::default(),
3659 }
3660 }
3661}
3662
3663#[derive(Debug, Clone, Serialize, Deserialize)]
3665pub struct PaymentCorrectionTypeDistribution {
3666 #[serde(default = "default_nsf_rate")]
3668 pub nsf: f64,
3669 #[serde(default = "default_chargeback_rate")]
3671 pub chargeback: f64,
3672 #[serde(default = "default_wrong_amount_rate")]
3674 pub wrong_amount: f64,
3675 #[serde(default = "default_wrong_customer_rate")]
3677 pub wrong_customer: f64,
3678 #[serde(default = "default_duplicate_payment_rate")]
3680 pub duplicate_payment: f64,
3681}
3682
3683fn default_nsf_rate() -> f64 {
3684 0.30
3685}
3686
3687fn default_chargeback_rate() -> f64 {
3688 0.20
3689}
3690
3691fn default_wrong_amount_rate() -> f64 {
3692 0.20
3693}
3694
3695fn default_wrong_customer_rate() -> f64 {
3696 0.15
3697}
3698
3699fn default_duplicate_payment_rate() -> f64 {
3700 0.15
3701}
3702
3703impl Default for PaymentCorrectionTypeDistribution {
3704 fn default() -> Self {
3705 Self {
3706 nsf: default_nsf_rate(),
3707 chargeback: default_chargeback_rate(),
3708 wrong_amount: default_wrong_amount_rate(),
3709 wrong_customer: default_wrong_customer_rate(),
3710 duplicate_payment: default_duplicate_payment_rate(),
3711 }
3712 }
3713}
3714
3715#[derive(Debug, Clone, Serialize, Deserialize)]
3717pub struct DocumentLineCountDistribution {
3718 #[serde(default = "default_min_lines")]
3720 pub min_lines: u32,
3721 #[serde(default = "default_max_lines")]
3723 pub max_lines: u32,
3724 #[serde(default = "default_mode_lines")]
3726 pub mode_lines: u32,
3727}
3728
3729fn default_min_lines() -> u32 {
3730 1
3731}
3732
3733fn default_max_lines() -> u32 {
3734 20
3735}
3736
3737fn default_mode_lines() -> u32 {
3738 3
3739}
3740
3741impl Default for DocumentLineCountDistribution {
3742 fn default() -> Self {
3743 Self {
3744 min_lines: default_min_lines(),
3745 max_lines: default_max_lines(),
3746 mode_lines: default_mode_lines(),
3747 }
3748 }
3749}
3750
3751#[derive(Debug, Clone, Serialize, Deserialize)]
3753pub struct CashDiscountConfig {
3754 #[serde(default = "default_discount_eligible_rate")]
3756 pub eligible_rate: f64,
3757 #[serde(default = "default_discount_taken_rate")]
3759 pub taken_rate: f64,
3760 #[serde(default = "default_discount_percent")]
3762 pub discount_percent: f64,
3763 #[serde(default = "default_discount_days")]
3765 pub discount_days: u32,
3766}
3767
3768fn default_discount_eligible_rate() -> f64 {
3769 0.30
3770}
3771
3772fn default_discount_taken_rate() -> f64 {
3773 0.60
3774}
3775
3776fn default_discount_percent() -> f64 {
3777 0.02
3778}
3779
3780fn default_discount_days() -> u32 {
3781 10
3782}
3783
3784impl Default for CashDiscountConfig {
3785 fn default() -> Self {
3786 Self {
3787 eligible_rate: default_discount_eligible_rate(),
3788 taken_rate: default_discount_taken_rate(),
3789 discount_percent: default_discount_percent(),
3790 discount_days: default_discount_days(),
3791 }
3792 }
3793}
3794
3795#[derive(Debug, Clone, Serialize, Deserialize)]
3801pub struct IntercompanyConfig {
3802 #[serde(default)]
3804 pub enabled: bool,
3805 #[serde(default = "default_ic_transaction_rate")]
3807 pub ic_transaction_rate: f64,
3808 #[serde(default)]
3810 pub transfer_pricing_method: TransferPricingMethod,
3811 #[serde(default = "default_markup_percent")]
3813 pub markup_percent: f64,
3814 #[serde(default = "default_true")]
3816 pub generate_matched_pairs: bool,
3817 #[serde(default)]
3819 pub transaction_type_distribution: ICTransactionTypeDistribution,
3820 #[serde(default)]
3822 pub generate_eliminations: bool,
3823}
3824
3825fn default_ic_transaction_rate() -> f64 {
3826 0.15
3827}
3828
3829fn default_markup_percent() -> f64 {
3830 0.05
3831}
3832
3833impl Default for IntercompanyConfig {
3834 fn default() -> Self {
3835 Self {
3836 enabled: false,
3837 ic_transaction_rate: default_ic_transaction_rate(),
3838 transfer_pricing_method: TransferPricingMethod::default(),
3839 markup_percent: default_markup_percent(),
3840 generate_matched_pairs: true,
3841 transaction_type_distribution: ICTransactionTypeDistribution::default(),
3842 generate_eliminations: false,
3843 }
3844 }
3845}
3846
3847#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3849#[serde(rename_all = "snake_case")]
3850pub enum TransferPricingMethod {
3851 #[default]
3853 CostPlus,
3854 ComparableUncontrolled,
3856 ResalePrice,
3858 TransactionalNetMargin,
3860 ProfitSplit,
3862}
3863
3864#[derive(Debug, Clone, Serialize, Deserialize)]
3866pub struct ICTransactionTypeDistribution {
3867 pub goods_sale: f64,
3869 pub service_provided: f64,
3871 pub loan: f64,
3873 pub dividend: f64,
3875 pub management_fee: f64,
3877 pub royalty: f64,
3879 pub cost_sharing: f64,
3881}
3882
3883impl Default for ICTransactionTypeDistribution {
3884 fn default() -> Self {
3885 Self {
3886 goods_sale: 0.35,
3887 service_provided: 0.20,
3888 loan: 0.10,
3889 dividend: 0.05,
3890 management_fee: 0.15,
3891 royalty: 0.10,
3892 cost_sharing: 0.05,
3893 }
3894 }
3895}
3896
3897#[derive(Debug, Clone, Serialize, Deserialize)]
3903pub struct BalanceConfig {
3904 #[serde(default)]
3906 pub generate_opening_balances: bool,
3907 #[serde(default = "default_true")]
3909 pub generate_trial_balances: bool,
3910 #[serde(default = "default_gross_margin")]
3912 pub target_gross_margin: f64,
3913 #[serde(default = "default_dso")]
3915 pub target_dso_days: u32,
3916 #[serde(default = "default_dpo")]
3918 pub target_dpo_days: u32,
3919 #[serde(default = "default_current_ratio")]
3921 pub target_current_ratio: f64,
3922 #[serde(default = "default_debt_equity")]
3924 pub target_debt_to_equity: f64,
3925 #[serde(default = "default_true")]
3927 pub validate_balance_equation: bool,
3928 #[serde(default = "default_true")]
3930 pub reconcile_subledgers: bool,
3931}
3932
3933fn default_gross_margin() -> f64 {
3934 0.35
3935}
3936
3937fn default_dso() -> u32 {
3938 45
3939}
3940
3941fn default_dpo() -> u32 {
3942 30
3943}
3944
3945fn default_current_ratio() -> f64 {
3946 1.5
3947}
3948
3949fn default_debt_equity() -> f64 {
3950 0.5
3951}
3952
3953impl Default for BalanceConfig {
3954 fn default() -> Self {
3955 Self {
3956 generate_opening_balances: false,
3957 generate_trial_balances: true,
3958 target_gross_margin: default_gross_margin(),
3959 target_dso_days: default_dso(),
3960 target_dpo_days: default_dpo(),
3961 target_current_ratio: default_current_ratio(),
3962 target_debt_to_equity: default_debt_equity(),
3963 validate_balance_equation: true,
3964 reconcile_subledgers: true,
3965 }
3966 }
3967}
3968
3969#[derive(Debug, Clone, Serialize, Deserialize)]
3978pub struct OcpmConfig {
3979 #[serde(default)]
3981 pub enabled: bool,
3982
3983 #[serde(default = "default_true")]
3985 pub generate_lifecycle_events: bool,
3986
3987 #[serde(default = "default_true")]
3989 pub include_object_relationships: bool,
3990
3991 #[serde(default = "default_true")]
3993 pub compute_variants: bool,
3994
3995 #[serde(default)]
3997 pub max_variants: usize,
3998
3999 #[serde(default)]
4001 pub p2p_process: OcpmProcessConfig,
4002
4003 #[serde(default)]
4005 pub o2c_process: OcpmProcessConfig,
4006
4007 #[serde(default)]
4009 pub output: OcpmOutputConfig,
4010}
4011
4012impl Default for OcpmConfig {
4013 fn default() -> Self {
4014 Self {
4015 enabled: false,
4016 generate_lifecycle_events: true,
4017 include_object_relationships: true,
4018 compute_variants: true,
4019 max_variants: 0,
4020 p2p_process: OcpmProcessConfig::default(),
4021 o2c_process: OcpmProcessConfig::default(),
4022 output: OcpmOutputConfig::default(),
4023 }
4024 }
4025}
4026
4027#[derive(Debug, Clone, Serialize, Deserialize)]
4029pub struct OcpmProcessConfig {
4030 #[serde(default = "default_rework_probability")]
4032 pub rework_probability: f64,
4033
4034 #[serde(default = "default_skip_probability")]
4036 pub skip_step_probability: f64,
4037
4038 #[serde(default = "default_out_of_order_probability")]
4040 pub out_of_order_probability: f64,
4041}
4042
4043fn default_rework_probability() -> f64 {
4047 0.15
4048}
4049
4050fn default_skip_probability() -> f64 {
4051 0.10
4052}
4053
4054fn default_out_of_order_probability() -> f64 {
4055 0.08
4056}
4057
4058impl Default for OcpmProcessConfig {
4059 fn default() -> Self {
4060 Self {
4061 rework_probability: default_rework_probability(),
4062 skip_step_probability: default_skip_probability(),
4063 out_of_order_probability: default_out_of_order_probability(),
4064 }
4065 }
4066}
4067
4068#[derive(Debug, Clone, Serialize, Deserialize)]
4070pub struct OcpmOutputConfig {
4071 #[serde(default = "default_true")]
4073 pub ocel_json: bool,
4074
4075 #[serde(default)]
4077 pub ocel_xml: bool,
4078
4079 #[serde(default)]
4081 pub xes: bool,
4082
4083 #[serde(default = "default_true")]
4085 pub xes_include_lifecycle: bool,
4086
4087 #[serde(default = "default_true")]
4089 pub xes_include_resources: bool,
4090
4091 #[serde(default = "default_true")]
4093 pub flattened_csv: bool,
4094
4095 #[serde(default = "default_true")]
4097 pub event_object_csv: bool,
4098
4099 #[serde(default = "default_true")]
4101 pub object_relationship_csv: bool,
4102
4103 #[serde(default = "default_true")]
4105 pub variants_csv: bool,
4106
4107 #[serde(default)]
4109 pub export_reference_models: bool,
4110}
4111
4112impl Default for OcpmOutputConfig {
4113 fn default() -> Self {
4114 Self {
4115 ocel_json: true,
4116 ocel_xml: false,
4117 xes: false,
4118 xes_include_lifecycle: true,
4119 xes_include_resources: true,
4120 flattened_csv: true,
4121 event_object_csv: true,
4122 object_relationship_csv: true,
4123 variants_csv: true,
4124 export_reference_models: false,
4125 }
4126 }
4127}
4128
4129#[derive(Debug, Clone, Serialize, Deserialize)]
4131pub struct AuditGenerationConfig {
4132 #[serde(default)]
4134 pub enabled: bool,
4135
4136 #[serde(default = "default_true")]
4140 pub generate_workpapers: bool,
4141
4142 #[serde(default)]
4145 pub engagement_types: AuditEngagementTypesConfig,
4146
4147 #[serde(default)]
4152 pub workpapers: WorkpaperConfig,
4153
4154 #[serde(default)]
4160 pub team: AuditTeamConfig,
4161
4162 #[serde(default)]
4169 pub review: ReviewWorkflowConfig,
4170
4171 #[serde(default)]
4173 pub fsm: Option<AuditFsmConfig>,
4174
4175 #[serde(default)]
4181 pub it_controls: ItControlsConfig,
4182}
4183
4184#[derive(Debug, Clone, Serialize, Deserialize)]
4186pub struct ItControlsConfig {
4187 #[serde(default)]
4190 pub enabled: bool,
4191 #[serde(default = "default_access_log_count")]
4194 pub access_logs_per_engagement: usize,
4195 #[serde(default = "default_change_record_count")]
4197 pub change_records_per_engagement: usize,
4198}
4199
4200fn default_access_log_count() -> usize {
4201 500
4202}
4203fn default_change_record_count() -> usize {
4204 50
4205}
4206
4207impl Default for ItControlsConfig {
4208 fn default() -> Self {
4209 Self {
4210 enabled: false,
4211 access_logs_per_engagement: default_access_log_count(),
4212 change_records_per_engagement: default_change_record_count(),
4213 }
4214 }
4215}
4216
4217impl Default for AuditGenerationConfig {
4218 fn default() -> Self {
4219 Self {
4220 enabled: false,
4221 generate_workpapers: true,
4222 engagement_types: AuditEngagementTypesConfig::default(),
4223 workpapers: WorkpaperConfig::default(),
4224 team: AuditTeamConfig::default(),
4225 review: ReviewWorkflowConfig::default(),
4226 fsm: None,
4227 it_controls: ItControlsConfig::default(),
4228 }
4229 }
4230}
4231
4232#[derive(Debug, Clone, Serialize, Deserialize)]
4234pub struct AuditFsmConfig {
4235 #[serde(default)]
4237 pub enabled: bool,
4238
4239 #[serde(default = "default_audit_fsm_blueprint")]
4241 pub blueprint: String,
4242
4243 #[serde(default = "default_audit_fsm_overlay")]
4245 pub overlay: String,
4246
4247 #[serde(default)]
4249 pub depth: Option<String>,
4250
4251 #[serde(default)]
4253 pub discriminators: std::collections::HashMap<String, Vec<String>>,
4254
4255 #[serde(default)]
4257 pub event_trail: AuditEventTrailConfig,
4258
4259 #[serde(default)]
4261 pub seed: Option<u64>,
4262}
4263
4264impl Default for AuditFsmConfig {
4265 fn default() -> Self {
4266 Self {
4267 enabled: false,
4268 blueprint: default_audit_fsm_blueprint(),
4269 overlay: default_audit_fsm_overlay(),
4270 depth: None,
4271 discriminators: std::collections::HashMap::new(),
4272 event_trail: AuditEventTrailConfig::default(),
4273 seed: None,
4274 }
4275 }
4276}
4277
4278fn default_audit_fsm_blueprint() -> String {
4279 "builtin:fsa".to_string()
4280}
4281
4282fn default_audit_fsm_overlay() -> String {
4283 "builtin:default".to_string()
4284}
4285
4286#[derive(Debug, Clone, Serialize, Deserialize)]
4288pub struct AuditEventTrailConfig {
4289 #[serde(default = "default_true")]
4291 pub flat_log: bool,
4292 #[serde(default)]
4294 pub ocel_projection: bool,
4295}
4296
4297impl Default for AuditEventTrailConfig {
4298 fn default() -> Self {
4299 Self {
4300 flat_log: true,
4301 ocel_projection: false,
4302 }
4303 }
4304}
4305
4306#[derive(Debug, Clone, Serialize, Deserialize)]
4308pub struct AuditEngagementTypesConfig {
4309 #[serde(default = "default_financial_audit_prob")]
4311 pub financial_statement: f64,
4312 #[serde(default = "default_sox_audit_prob")]
4314 pub sox_icfr: f64,
4315 #[serde(default = "default_integrated_audit_prob")]
4317 pub integrated: f64,
4318 #[serde(default = "default_review_prob")]
4320 pub review: f64,
4321 #[serde(default = "default_aup_prob")]
4323 pub agreed_upon_procedures: f64,
4324}
4325
4326fn default_financial_audit_prob() -> f64 {
4327 0.40
4328}
4329fn default_sox_audit_prob() -> f64 {
4330 0.20
4331}
4332fn default_integrated_audit_prob() -> f64 {
4333 0.25
4334}
4335fn default_review_prob() -> f64 {
4336 0.10
4337}
4338fn default_aup_prob() -> f64 {
4339 0.05
4340}
4341
4342impl Default for AuditEngagementTypesConfig {
4343 fn default() -> Self {
4344 Self {
4345 financial_statement: default_financial_audit_prob(),
4346 sox_icfr: default_sox_audit_prob(),
4347 integrated: default_integrated_audit_prob(),
4348 review: default_review_prob(),
4349 agreed_upon_procedures: default_aup_prob(),
4350 }
4351 }
4352}
4353
4354#[derive(Debug, Clone, Serialize, Deserialize)]
4356pub struct WorkpaperConfig {
4357 #[serde(default = "default_workpapers_per_phase")]
4359 pub average_per_phase: usize,
4360
4361 #[serde(default = "default_true")]
4363 pub include_isa_references: bool,
4364
4365 #[serde(default = "default_true")]
4367 pub include_sample_details: bool,
4368
4369 #[serde(default = "default_true")]
4371 pub include_cross_references: bool,
4372
4373 #[serde(default)]
4375 pub sampling: SamplingConfig,
4376}
4377
4378fn default_workpapers_per_phase() -> usize {
4379 5
4380}
4381
4382impl Default for WorkpaperConfig {
4383 fn default() -> Self {
4384 Self {
4385 average_per_phase: default_workpapers_per_phase(),
4386 include_isa_references: true,
4387 include_sample_details: true,
4388 include_cross_references: true,
4389 sampling: SamplingConfig::default(),
4390 }
4391 }
4392}
4393
4394#[derive(Debug, Clone, Serialize, Deserialize)]
4396pub struct SamplingConfig {
4397 #[serde(default = "default_statistical_rate")]
4399 pub statistical_rate: f64,
4400 #[serde(default = "default_judgmental_rate")]
4402 pub judgmental_rate: f64,
4403 #[serde(default = "default_haphazard_rate")]
4405 pub haphazard_rate: f64,
4406 #[serde(default = "default_complete_examination_rate")]
4408 pub complete_examination_rate: f64,
4409}
4410
4411fn default_statistical_rate() -> f64 {
4412 0.40
4413}
4414fn default_judgmental_rate() -> f64 {
4415 0.30
4416}
4417fn default_haphazard_rate() -> f64 {
4418 0.20
4419}
4420fn default_complete_examination_rate() -> f64 {
4421 0.10
4422}
4423
4424impl Default for SamplingConfig {
4425 fn default() -> Self {
4426 Self {
4427 statistical_rate: default_statistical_rate(),
4428 judgmental_rate: default_judgmental_rate(),
4429 haphazard_rate: default_haphazard_rate(),
4430 complete_examination_rate: default_complete_examination_rate(),
4431 }
4432 }
4433}
4434
4435#[derive(Debug, Clone, Serialize, Deserialize)]
4437pub struct AuditTeamConfig {
4438 #[serde(default = "default_min_team_size")]
4440 pub min_team_size: usize,
4441 #[serde(default = "default_max_team_size")]
4443 pub max_team_size: usize,
4444 #[serde(default = "default_specialist_probability")]
4446 pub specialist_probability: f64,
4447}
4448
4449fn default_min_team_size() -> usize {
4450 3
4451}
4452fn default_max_team_size() -> usize {
4453 8
4454}
4455fn default_specialist_probability() -> f64 {
4456 0.30
4457}
4458
4459impl Default for AuditTeamConfig {
4460 fn default() -> Self {
4461 Self {
4462 min_team_size: default_min_team_size(),
4463 max_team_size: default_max_team_size(),
4464 specialist_probability: default_specialist_probability(),
4465 }
4466 }
4467}
4468
4469#[derive(Debug, Clone, Serialize, Deserialize)]
4471pub struct ReviewWorkflowConfig {
4472 #[serde(default = "default_review_delay_days")]
4474 pub average_review_delay_days: u32,
4475 #[serde(default = "default_rework_probability_review")]
4477 pub rework_probability: f64,
4478 #[serde(default = "default_true")]
4480 pub require_partner_signoff: bool,
4481}
4482
4483fn default_review_delay_days() -> u32 {
4484 2
4485}
4486fn default_rework_probability_review() -> f64 {
4487 0.15
4488}
4489
4490impl Default for ReviewWorkflowConfig {
4491 fn default() -> Self {
4492 Self {
4493 average_review_delay_days: default_review_delay_days(),
4494 rework_probability: default_rework_probability_review(),
4495 require_partner_signoff: true,
4496 }
4497 }
4498}
4499
4500#[derive(Debug, Clone, Serialize, Deserialize)]
4506pub struct DataQualitySchemaConfig {
4507 #[serde(default)]
4509 pub enabled: bool,
4510 #[serde(default)]
4512 pub preset: DataQualityPreset,
4513 #[serde(default)]
4515 pub missing_values: MissingValuesSchemaConfig,
4516 #[serde(default)]
4518 pub typos: TypoSchemaConfig,
4519 #[serde(default)]
4521 pub format_variations: FormatVariationSchemaConfig,
4522 #[serde(default)]
4524 pub duplicates: DuplicateSchemaConfig,
4525 #[serde(default)]
4527 pub encoding_issues: EncodingIssueSchemaConfig,
4528 #[serde(default)]
4530 pub generate_labels: bool,
4531 #[serde(default)]
4533 pub sink_profiles: SinkQualityProfiles,
4534}
4535
4536impl Default for DataQualitySchemaConfig {
4537 fn default() -> Self {
4538 Self {
4539 enabled: false,
4540 preset: DataQualityPreset::None,
4541 missing_values: MissingValuesSchemaConfig::default(),
4542 typos: TypoSchemaConfig::default(),
4543 format_variations: FormatVariationSchemaConfig::default(),
4544 duplicates: DuplicateSchemaConfig::default(),
4545 encoding_issues: EncodingIssueSchemaConfig::default(),
4546 generate_labels: true,
4547 sink_profiles: SinkQualityProfiles::default(),
4548 }
4549 }
4550}
4551
4552impl DataQualitySchemaConfig {
4553 pub fn with_preset(preset: DataQualityPreset) -> Self {
4555 let mut config = Self {
4556 preset,
4557 ..Default::default()
4558 };
4559 config.apply_preset();
4560 config
4561 }
4562
4563 pub fn apply_preset(&mut self) {
4566 if !self.preset.overrides_settings() {
4567 return;
4568 }
4569
4570 self.enabled = true;
4571
4572 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4574 self.missing_values.rate = self.preset.missing_rate();
4575
4576 self.typos.enabled = self.preset.typo_rate() > 0.0;
4578 self.typos.char_error_rate = self.preset.typo_rate();
4579
4580 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4582 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4583 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4584 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4585
4586 self.format_variations.enabled = self.preset.format_variations_enabled();
4588
4589 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4591 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4592
4593 if self.preset.ocr_errors_enabled() {
4595 self.typos.type_weights.ocr_errors = 0.3;
4596 }
4597 }
4598
4599 pub fn effective_missing_rate(&self) -> f64 {
4601 if self.preset.overrides_settings() {
4602 self.preset.missing_rate()
4603 } else {
4604 self.missing_values.rate
4605 }
4606 }
4607
4608 pub fn effective_typo_rate(&self) -> f64 {
4610 if self.preset.overrides_settings() {
4611 self.preset.typo_rate()
4612 } else {
4613 self.typos.char_error_rate
4614 }
4615 }
4616
4617 pub fn effective_duplicate_rate(&self) -> f64 {
4619 if self.preset.overrides_settings() {
4620 self.preset.duplicate_rate()
4621 } else {
4622 self.duplicates.exact_duplicate_ratio
4623 + self.duplicates.near_duplicate_ratio
4624 + self.duplicates.fuzzy_duplicate_ratio
4625 }
4626 }
4627
4628 pub fn clean() -> Self {
4630 Self::with_preset(DataQualityPreset::Clean)
4631 }
4632
4633 pub fn noisy() -> Self {
4635 Self::with_preset(DataQualityPreset::Noisy)
4636 }
4637
4638 pub fn legacy() -> Self {
4640 Self::with_preset(DataQualityPreset::Legacy)
4641 }
4642}
4643
4644#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4646#[serde(rename_all = "snake_case")]
4647pub enum DataQualityPreset {
4648 #[default]
4650 None,
4651 Minimal,
4653 Normal,
4655 High,
4657 Custom,
4659
4660 Clean,
4666 Noisy,
4669 Legacy,
4672}
4673
4674impl DataQualityPreset {
4675 pub fn missing_rate(&self) -> f64 {
4677 match self {
4678 DataQualityPreset::None => 0.0,
4679 DataQualityPreset::Minimal => 0.005,
4680 DataQualityPreset::Normal => 0.02,
4681 DataQualityPreset::High => 0.08,
4682 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4684 DataQualityPreset::Noisy => 0.05,
4685 DataQualityPreset::Legacy => 0.10,
4686 }
4687 }
4688
4689 pub fn typo_rate(&self) -> f64 {
4691 match self {
4692 DataQualityPreset::None => 0.0,
4693 DataQualityPreset::Minimal => 0.0005,
4694 DataQualityPreset::Normal => 0.002,
4695 DataQualityPreset::High => 0.01,
4696 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4698 DataQualityPreset::Noisy => 0.02,
4699 DataQualityPreset::Legacy => 0.05,
4700 }
4701 }
4702
4703 pub fn duplicate_rate(&self) -> f64 {
4705 match self {
4706 DataQualityPreset::None => 0.0,
4707 DataQualityPreset::Minimal => 0.001,
4708 DataQualityPreset::Normal => 0.005,
4709 DataQualityPreset::High => 0.02,
4710 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4712 DataQualityPreset::Noisy => 0.01,
4713 DataQualityPreset::Legacy => 0.03,
4714 }
4715 }
4716
4717 pub fn format_variations_enabled(&self) -> bool {
4719 match self {
4720 DataQualityPreset::None | DataQualityPreset::Clean => false,
4721 DataQualityPreset::Minimal => true,
4722 DataQualityPreset::Normal => true,
4723 DataQualityPreset::High => true,
4724 DataQualityPreset::Custom => true,
4725 DataQualityPreset::Noisy => true,
4726 DataQualityPreset::Legacy => true,
4727 }
4728 }
4729
4730 pub fn ocr_errors_enabled(&self) -> bool {
4732 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4733 }
4734
4735 pub fn encoding_issues_enabled(&self) -> bool {
4737 matches!(
4738 self,
4739 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4740 )
4741 }
4742
4743 pub fn encoding_issue_rate(&self) -> f64 {
4745 match self {
4746 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4747 DataQualityPreset::Normal => 0.002,
4748 DataQualityPreset::High => 0.01,
4749 DataQualityPreset::Custom => 0.0,
4750 DataQualityPreset::Noisy => 0.005,
4751 DataQualityPreset::Legacy => 0.02,
4752 }
4753 }
4754
4755 pub fn overrides_settings(&self) -> bool {
4757 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4758 }
4759
4760 pub fn description(&self) -> &'static str {
4762 match self {
4763 DataQualityPreset::None => "No data quality issues (pristine data)",
4764 DataQualityPreset::Minimal => "Very rare data quality issues",
4765 DataQualityPreset::Normal => "Realistic enterprise data quality",
4766 DataQualityPreset::High => "Messy data for stress testing",
4767 DataQualityPreset::Custom => "Custom settings from configuration",
4768 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4769 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4770 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4771 }
4772 }
4773}
4774
4775#[derive(Debug, Clone, Serialize, Deserialize)]
4777pub struct MissingValuesSchemaConfig {
4778 #[serde(default)]
4780 pub enabled: bool,
4781 #[serde(default = "default_missing_rate")]
4783 pub rate: f64,
4784 #[serde(default)]
4786 pub strategy: MissingValueStrategy,
4787 #[serde(default)]
4789 pub field_rates: std::collections::HashMap<String, f64>,
4790 #[serde(default)]
4792 pub protected_fields: Vec<String>,
4793}
4794
4795fn default_missing_rate() -> f64 {
4796 0.01
4797}
4798
4799impl Default for MissingValuesSchemaConfig {
4800 fn default() -> Self {
4801 Self {
4802 enabled: false,
4803 rate: default_missing_rate(),
4804 strategy: MissingValueStrategy::Mcar,
4805 field_rates: std::collections::HashMap::new(),
4806 protected_fields: vec![
4807 "document_id".to_string(),
4808 "company_code".to_string(),
4809 "posting_date".to_string(),
4810 ],
4811 }
4812 }
4813}
4814
4815#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4817#[serde(rename_all = "snake_case")]
4818pub enum MissingValueStrategy {
4819 #[default]
4821 Mcar,
4822 Mar,
4824 Mnar,
4826 Systematic,
4828}
4829
4830#[derive(Debug, Clone, Serialize, Deserialize)]
4832pub struct TypoSchemaConfig {
4833 #[serde(default)]
4835 pub enabled: bool,
4836 #[serde(default = "default_typo_rate")]
4838 pub char_error_rate: f64,
4839 #[serde(default)]
4841 pub type_weights: TypoTypeWeights,
4842 #[serde(default)]
4844 pub protected_fields: Vec<String>,
4845}
4846
4847fn default_typo_rate() -> f64 {
4848 0.001
4849}
4850
4851impl Default for TypoSchemaConfig {
4852 fn default() -> Self {
4853 Self {
4854 enabled: false,
4855 char_error_rate: default_typo_rate(),
4856 type_weights: TypoTypeWeights::default(),
4857 protected_fields: vec![
4858 "document_id".to_string(),
4859 "gl_account".to_string(),
4860 "company_code".to_string(),
4861 ],
4862 }
4863 }
4864}
4865
4866#[derive(Debug, Clone, Serialize, Deserialize)]
4868pub struct TypoTypeWeights {
4869 #[serde(default = "default_substitution_weight")]
4871 pub substitution: f64,
4872 #[serde(default = "default_transposition_weight")]
4874 pub transposition: f64,
4875 #[serde(default = "default_insertion_weight")]
4877 pub insertion: f64,
4878 #[serde(default = "default_deletion_weight")]
4880 pub deletion: f64,
4881 #[serde(default = "default_ocr_weight")]
4883 pub ocr_errors: f64,
4884 #[serde(default = "default_homophone_weight")]
4886 pub homophones: f64,
4887}
4888
4889fn default_substitution_weight() -> f64 {
4890 0.35
4891}
4892fn default_transposition_weight() -> f64 {
4893 0.25
4894}
4895fn default_insertion_weight() -> f64 {
4896 0.10
4897}
4898fn default_deletion_weight() -> f64 {
4899 0.15
4900}
4901fn default_ocr_weight() -> f64 {
4902 0.10
4903}
4904fn default_homophone_weight() -> f64 {
4905 0.05
4906}
4907
4908impl Default for TypoTypeWeights {
4909 fn default() -> Self {
4910 Self {
4911 substitution: default_substitution_weight(),
4912 transposition: default_transposition_weight(),
4913 insertion: default_insertion_weight(),
4914 deletion: default_deletion_weight(),
4915 ocr_errors: default_ocr_weight(),
4916 homophones: default_homophone_weight(),
4917 }
4918 }
4919}
4920
4921#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4923pub struct FormatVariationSchemaConfig {
4924 #[serde(default)]
4926 pub enabled: bool,
4927 #[serde(default)]
4929 pub dates: DateFormatVariationConfig,
4930 #[serde(default)]
4932 pub amounts: AmountFormatVariationConfig,
4933 #[serde(default)]
4935 pub identifiers: IdentifierFormatVariationConfig,
4936}
4937
4938#[derive(Debug, Clone, Serialize, Deserialize)]
4940pub struct DateFormatVariationConfig {
4941 #[serde(default)]
4943 pub enabled: bool,
4944 #[serde(default = "default_date_variation_rate")]
4946 pub rate: f64,
4947 #[serde(default = "default_true")]
4949 pub iso_format: bool,
4950 #[serde(default)]
4952 pub us_format: bool,
4953 #[serde(default)]
4955 pub eu_format: bool,
4956 #[serde(default)]
4958 pub long_format: bool,
4959}
4960
4961fn default_date_variation_rate() -> f64 {
4962 0.05
4963}
4964
4965impl Default for DateFormatVariationConfig {
4966 fn default() -> Self {
4967 Self {
4968 enabled: false,
4969 rate: default_date_variation_rate(),
4970 iso_format: true,
4971 us_format: false,
4972 eu_format: false,
4973 long_format: false,
4974 }
4975 }
4976}
4977
4978#[derive(Debug, Clone, Serialize, Deserialize)]
4980pub struct AmountFormatVariationConfig {
4981 #[serde(default)]
4983 pub enabled: bool,
4984 #[serde(default = "default_amount_variation_rate")]
4986 pub rate: f64,
4987 #[serde(default)]
4989 pub us_comma_format: bool,
4990 #[serde(default)]
4992 pub eu_format: bool,
4993 #[serde(default)]
4995 pub currency_prefix: bool,
4996 #[serde(default)]
4998 pub accounting_format: bool,
4999}
5000
5001fn default_amount_variation_rate() -> f64 {
5002 0.02
5003}
5004
5005impl Default for AmountFormatVariationConfig {
5006 fn default() -> Self {
5007 Self {
5008 enabled: false,
5009 rate: default_amount_variation_rate(),
5010 us_comma_format: false,
5011 eu_format: false,
5012 currency_prefix: false,
5013 accounting_format: false,
5014 }
5015 }
5016}
5017
5018#[derive(Debug, Clone, Serialize, Deserialize)]
5020pub struct IdentifierFormatVariationConfig {
5021 #[serde(default)]
5023 pub enabled: bool,
5024 #[serde(default = "default_identifier_variation_rate")]
5026 pub rate: f64,
5027 #[serde(default)]
5029 pub case_variations: bool,
5030 #[serde(default)]
5032 pub padding_variations: bool,
5033 #[serde(default)]
5035 pub separator_variations: bool,
5036}
5037
5038fn default_identifier_variation_rate() -> f64 {
5039 0.02
5040}
5041
5042impl Default for IdentifierFormatVariationConfig {
5043 fn default() -> Self {
5044 Self {
5045 enabled: false,
5046 rate: default_identifier_variation_rate(),
5047 case_variations: false,
5048 padding_variations: false,
5049 separator_variations: false,
5050 }
5051 }
5052}
5053
5054#[derive(Debug, Clone, Serialize, Deserialize)]
5056pub struct DuplicateSchemaConfig {
5057 #[serde(default)]
5059 pub enabled: bool,
5060 #[serde(default = "default_duplicate_rate")]
5062 pub rate: f64,
5063 #[serde(default = "default_exact_duplicate_ratio")]
5065 pub exact_duplicate_ratio: f64,
5066 #[serde(default = "default_near_duplicate_ratio")]
5068 pub near_duplicate_ratio: f64,
5069 #[serde(default = "default_fuzzy_duplicate_ratio")]
5071 pub fuzzy_duplicate_ratio: f64,
5072 #[serde(default = "default_max_date_offset")]
5074 pub max_date_offset_days: u32,
5075 #[serde(default = "default_max_amount_variance")]
5077 pub max_amount_variance: f64,
5078}
5079
5080fn default_duplicate_rate() -> f64 {
5081 0.005
5082}
5083fn default_exact_duplicate_ratio() -> f64 {
5084 0.4
5085}
5086fn default_near_duplicate_ratio() -> f64 {
5087 0.35
5088}
5089fn default_fuzzy_duplicate_ratio() -> f64 {
5090 0.25
5091}
5092fn default_max_date_offset() -> u32 {
5093 3
5094}
5095fn default_max_amount_variance() -> f64 {
5096 0.01
5097}
5098
5099impl Default for DuplicateSchemaConfig {
5100 fn default() -> Self {
5101 Self {
5102 enabled: false,
5103 rate: default_duplicate_rate(),
5104 exact_duplicate_ratio: default_exact_duplicate_ratio(),
5105 near_duplicate_ratio: default_near_duplicate_ratio(),
5106 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
5107 max_date_offset_days: default_max_date_offset(),
5108 max_amount_variance: default_max_amount_variance(),
5109 }
5110 }
5111}
5112
5113#[derive(Debug, Clone, Serialize, Deserialize)]
5115pub struct EncodingIssueSchemaConfig {
5116 #[serde(default)]
5118 pub enabled: bool,
5119 #[serde(default = "default_encoding_rate")]
5121 pub rate: f64,
5122 #[serde(default)]
5124 pub mojibake: bool,
5125 #[serde(default)]
5127 pub html_entities: bool,
5128 #[serde(default)]
5130 pub bom_issues: bool,
5131}
5132
5133fn default_encoding_rate() -> f64 {
5134 0.001
5135}
5136
5137impl Default for EncodingIssueSchemaConfig {
5138 fn default() -> Self {
5139 Self {
5140 enabled: false,
5141 rate: default_encoding_rate(),
5142 mojibake: false,
5143 html_entities: false,
5144 bom_issues: false,
5145 }
5146 }
5147}
5148
5149#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5151pub struct SinkQualityProfiles {
5152 #[serde(default)]
5154 pub csv: Option<SinkQualityOverride>,
5155 #[serde(default)]
5157 pub json: Option<SinkQualityOverride>,
5158 #[serde(default)]
5160 pub parquet: Option<SinkQualityOverride>,
5161}
5162
5163#[derive(Debug, Clone, Serialize, Deserialize)]
5165pub struct SinkQualityOverride {
5166 pub enabled: Option<bool>,
5168 pub missing_rate: Option<f64>,
5170 pub typo_rate: Option<f64>,
5172 pub format_variation_rate: Option<f64>,
5174 pub duplicate_rate: Option<f64>,
5176}
5177
5178#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5190pub struct AccountingStandardsConfig {
5191 #[serde(default)]
5193 pub enabled: bool,
5194
5195 #[serde(default, skip_serializing_if = "Option::is_none")]
5199 pub framework: Option<AccountingFrameworkConfig>,
5200
5201 #[serde(default)]
5203 pub revenue_recognition: RevenueRecognitionConfig,
5204
5205 #[serde(default)]
5207 pub leases: LeaseAccountingConfig,
5208
5209 #[serde(default)]
5211 pub fair_value: FairValueConfig,
5212
5213 #[serde(default)]
5215 pub impairment: ImpairmentConfig,
5216
5217 #[serde(default)]
5219 pub business_combinations: BusinessCombinationsConfig,
5220
5221 #[serde(default)]
5223 pub expected_credit_loss: EclConfig,
5224
5225 #[serde(default)]
5227 pub generate_differences: bool,
5228}
5229
5230#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5232#[serde(rename_all = "snake_case")]
5233pub enum AccountingFrameworkConfig {
5234 #[default]
5236 UsGaap,
5237 Ifrs,
5239 DualReporting,
5241 FrenchGaap,
5243 GermanGaap,
5245}
5246
5247#[derive(Debug, Clone, Serialize, Deserialize)]
5249pub struct RevenueRecognitionConfig {
5250 #[serde(default)]
5252 pub enabled: bool,
5253
5254 #[serde(default = "default_true")]
5256 pub generate_contracts: bool,
5257
5258 #[serde(default = "default_avg_obligations")]
5260 pub avg_obligations_per_contract: f64,
5261
5262 #[serde(default = "default_variable_consideration_rate")]
5264 pub variable_consideration_rate: f64,
5265
5266 #[serde(default = "default_over_time_rate")]
5268 pub over_time_recognition_rate: f64,
5269
5270 #[serde(default = "default_contract_count")]
5272 pub contract_count: usize,
5273}
5274
5275fn default_avg_obligations() -> f64 {
5276 2.0
5277}
5278
5279fn default_variable_consideration_rate() -> f64 {
5280 0.15
5281}
5282
5283fn default_over_time_rate() -> f64 {
5284 0.30
5285}
5286
5287fn default_contract_count() -> usize {
5288 100
5289}
5290
5291impl Default for RevenueRecognitionConfig {
5292 fn default() -> Self {
5293 Self {
5294 enabled: false,
5295 generate_contracts: true,
5296 avg_obligations_per_contract: default_avg_obligations(),
5297 variable_consideration_rate: default_variable_consideration_rate(),
5298 over_time_recognition_rate: default_over_time_rate(),
5299 contract_count: default_contract_count(),
5300 }
5301 }
5302}
5303
5304#[derive(Debug, Clone, Serialize, Deserialize)]
5306pub struct LeaseAccountingConfig {
5307 #[serde(default)]
5309 pub enabled: bool,
5310
5311 #[serde(default = "default_lease_count")]
5313 pub lease_count: usize,
5314
5315 #[serde(default = "default_finance_lease_pct")]
5317 pub finance_lease_percent: f64,
5318
5319 #[serde(default = "default_avg_lease_term")]
5321 pub avg_lease_term_months: u32,
5322
5323 #[serde(default = "default_true")]
5325 pub generate_amortization: bool,
5326
5327 #[serde(default = "default_real_estate_pct")]
5329 pub real_estate_percent: f64,
5330}
5331
5332fn default_lease_count() -> usize {
5333 50
5334}
5335
5336fn default_finance_lease_pct() -> f64 {
5337 0.30
5338}
5339
5340fn default_avg_lease_term() -> u32 {
5341 60
5342}
5343
5344fn default_real_estate_pct() -> f64 {
5345 0.40
5346}
5347
5348impl Default for LeaseAccountingConfig {
5349 fn default() -> Self {
5350 Self {
5351 enabled: false,
5352 lease_count: default_lease_count(),
5353 finance_lease_percent: default_finance_lease_pct(),
5354 avg_lease_term_months: default_avg_lease_term(),
5355 generate_amortization: true,
5356 real_estate_percent: default_real_estate_pct(),
5357 }
5358 }
5359}
5360
5361#[derive(Debug, Clone, Serialize, Deserialize)]
5363pub struct FairValueConfig {
5364 #[serde(default)]
5366 pub enabled: bool,
5367
5368 #[serde(default = "default_fv_count")]
5370 pub measurement_count: usize,
5371
5372 #[serde(default = "default_level1_pct")]
5374 pub level1_percent: f64,
5375
5376 #[serde(default = "default_level2_pct")]
5378 pub level2_percent: f64,
5379
5380 #[serde(default = "default_level3_pct")]
5382 pub level3_percent: f64,
5383
5384 #[serde(default)]
5386 pub include_sensitivity_analysis: bool,
5387}
5388
5389fn default_fv_count() -> usize {
5390 25
5391}
5392
5393fn default_level1_pct() -> f64 {
5394 0.40
5395}
5396
5397fn default_level2_pct() -> f64 {
5398 0.35
5399}
5400
5401fn default_level3_pct() -> f64 {
5402 0.25
5403}
5404
5405impl Default for FairValueConfig {
5406 fn default() -> Self {
5407 Self {
5408 enabled: false,
5409 measurement_count: default_fv_count(),
5410 level1_percent: default_level1_pct(),
5411 level2_percent: default_level2_pct(),
5412 level3_percent: default_level3_pct(),
5413 include_sensitivity_analysis: false,
5414 }
5415 }
5416}
5417
5418#[derive(Debug, Clone, Serialize, Deserialize)]
5420pub struct ImpairmentConfig {
5421 #[serde(default)]
5423 pub enabled: bool,
5424
5425 #[serde(default = "default_impairment_count")]
5427 pub test_count: usize,
5428
5429 #[serde(default = "default_impairment_rate")]
5431 pub impairment_rate: f64,
5432
5433 #[serde(default = "default_true")]
5435 pub generate_projections: bool,
5436
5437 #[serde(default)]
5439 pub include_goodwill: bool,
5440}
5441
5442fn default_impairment_count() -> usize {
5443 15
5444}
5445
5446fn default_impairment_rate() -> f64 {
5447 0.10
5448}
5449
5450impl Default for ImpairmentConfig {
5451 fn default() -> Self {
5452 Self {
5453 enabled: false,
5454 test_count: default_impairment_count(),
5455 impairment_rate: default_impairment_rate(),
5456 generate_projections: true,
5457 include_goodwill: false,
5458 }
5459 }
5460}
5461
5462#[derive(Debug, Clone, Serialize, Deserialize)]
5468pub struct BusinessCombinationsConfig {
5469 #[serde(default)]
5471 pub enabled: bool,
5472
5473 #[serde(default = "default_bc_acquisition_count")]
5475 pub acquisition_count: usize,
5476}
5477
5478fn default_bc_acquisition_count() -> usize {
5479 2
5480}
5481
5482impl Default for BusinessCombinationsConfig {
5483 fn default() -> Self {
5484 Self {
5485 enabled: false,
5486 acquisition_count: default_bc_acquisition_count(),
5487 }
5488 }
5489}
5490
5491#[derive(Debug, Clone, Serialize, Deserialize)]
5497pub struct EclConfig {
5498 #[serde(default)]
5500 pub enabled: bool,
5501
5502 #[serde(default = "default_ecl_base_weight")]
5504 pub base_scenario_weight: f64,
5505
5506 #[serde(default = "default_ecl_base_multiplier")]
5508 pub base_scenario_multiplier: f64,
5509
5510 #[serde(default = "default_ecl_optimistic_weight")]
5512 pub optimistic_scenario_weight: f64,
5513
5514 #[serde(default = "default_ecl_optimistic_multiplier")]
5516 pub optimistic_scenario_multiplier: f64,
5517
5518 #[serde(default = "default_ecl_pessimistic_weight")]
5520 pub pessimistic_scenario_weight: f64,
5521
5522 #[serde(default = "default_ecl_pessimistic_multiplier")]
5524 pub pessimistic_scenario_multiplier: f64,
5525}
5526
5527fn default_ecl_base_weight() -> f64 {
5528 0.50
5529}
5530fn default_ecl_base_multiplier() -> f64 {
5531 1.0
5532}
5533fn default_ecl_optimistic_weight() -> f64 {
5534 0.30
5535}
5536fn default_ecl_optimistic_multiplier() -> f64 {
5537 0.8
5538}
5539fn default_ecl_pessimistic_weight() -> f64 {
5540 0.20
5541}
5542fn default_ecl_pessimistic_multiplier() -> f64 {
5543 1.4
5544}
5545
5546impl Default for EclConfig {
5547 fn default() -> Self {
5548 Self {
5549 enabled: false,
5550 base_scenario_weight: default_ecl_base_weight(),
5551 base_scenario_multiplier: default_ecl_base_multiplier(),
5552 optimistic_scenario_weight: default_ecl_optimistic_weight(),
5553 optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5554 pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5555 pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5556 }
5557 }
5558}
5559
5560#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5573pub struct AuditStandardsConfig {
5574 #[serde(default)]
5576 pub enabled: bool,
5577
5578 #[serde(default)]
5580 pub isa_compliance: IsaComplianceConfig,
5581
5582 #[serde(default)]
5584 pub analytical_procedures: AnalyticalProceduresConfig,
5585
5586 #[serde(default)]
5588 pub confirmations: ConfirmationsConfig,
5589
5590 #[serde(default)]
5592 pub opinion: AuditOpinionConfig,
5593
5594 #[serde(default)]
5596 pub generate_audit_trail: bool,
5597
5598 #[serde(default)]
5600 pub sox: SoxComplianceConfig,
5601
5602 #[serde(default)]
5604 pub pcaob: PcaobConfig,
5605}
5606
5607#[derive(Debug, Clone, Serialize, Deserialize)]
5609pub struct IsaComplianceConfig {
5610 #[serde(default)]
5612 pub enabled: bool,
5613
5614 #[serde(default = "default_compliance_level")]
5616 pub compliance_level: String,
5617
5618 #[serde(default = "default_true")]
5620 pub generate_isa_mappings: bool,
5621
5622 #[serde(default = "default_true")]
5624 pub generate_coverage_summary: bool,
5625
5626 #[serde(default)]
5628 pub include_pcaob: bool,
5629
5630 #[serde(default = "default_audit_framework")]
5632 pub framework: String,
5633}
5634
5635fn default_compliance_level() -> String {
5636 "standard".to_string()
5637}
5638
5639fn default_audit_framework() -> String {
5640 "isa".to_string()
5641}
5642
5643impl Default for IsaComplianceConfig {
5644 fn default() -> Self {
5645 Self {
5646 enabled: false,
5647 compliance_level: default_compliance_level(),
5648 generate_isa_mappings: true,
5649 generate_coverage_summary: true,
5650 include_pcaob: false,
5651 framework: default_audit_framework(),
5652 }
5653 }
5654}
5655
5656#[derive(Debug, Clone, Serialize, Deserialize)]
5658pub struct AnalyticalProceduresConfig {
5659 #[serde(default)]
5661 pub enabled: bool,
5662
5663 #[serde(default = "default_procedures_per_account")]
5665 pub procedures_per_account: usize,
5666
5667 #[serde(default = "default_variance_probability")]
5669 pub variance_probability: f64,
5670
5671 #[serde(default = "default_true")]
5673 pub generate_investigations: bool,
5674
5675 #[serde(default = "default_true")]
5677 pub include_ratio_analysis: bool,
5678}
5679
5680fn default_procedures_per_account() -> usize {
5681 3
5682}
5683
5684fn default_variance_probability() -> f64 {
5685 0.20
5686}
5687
5688impl Default for AnalyticalProceduresConfig {
5689 fn default() -> Self {
5690 Self {
5691 enabled: false,
5692 procedures_per_account: default_procedures_per_account(),
5693 variance_probability: default_variance_probability(),
5694 generate_investigations: true,
5695 include_ratio_analysis: true,
5696 }
5697 }
5698}
5699
5700#[derive(Debug, Clone, Serialize, Deserialize)]
5702pub struct ConfirmationsConfig {
5703 #[serde(default)]
5705 pub enabled: bool,
5706
5707 #[serde(default = "default_confirmation_count")]
5709 pub confirmation_count: usize,
5710
5711 #[serde(default = "default_positive_response_rate")]
5713 pub positive_response_rate: f64,
5714
5715 #[serde(default = "default_exception_rate_confirm")]
5717 pub exception_rate: f64,
5718
5719 #[serde(default = "default_non_response_rate")]
5721 pub non_response_rate: f64,
5722
5723 #[serde(default = "default_true")]
5725 pub generate_alternative_procedures: bool,
5726}
5727
5728fn default_confirmation_count() -> usize {
5729 50
5730}
5731
5732fn default_positive_response_rate() -> f64 {
5733 0.85
5734}
5735
5736fn default_exception_rate_confirm() -> f64 {
5737 0.10
5738}
5739
5740fn default_non_response_rate() -> f64 {
5741 0.05
5742}
5743
5744impl Default for ConfirmationsConfig {
5745 fn default() -> Self {
5746 Self {
5747 enabled: false,
5748 confirmation_count: default_confirmation_count(),
5749 positive_response_rate: default_positive_response_rate(),
5750 exception_rate: default_exception_rate_confirm(),
5751 non_response_rate: default_non_response_rate(),
5752 generate_alternative_procedures: true,
5753 }
5754 }
5755}
5756
5757#[derive(Debug, Clone, Serialize, Deserialize)]
5759pub struct AuditOpinionConfig {
5760 #[serde(default)]
5762 pub enabled: bool,
5763
5764 #[serde(default = "default_true")]
5766 pub generate_kam: bool,
5767
5768 #[serde(default = "default_kam_count")]
5770 pub average_kam_count: usize,
5771
5772 #[serde(default = "default_modified_opinion_rate")]
5774 pub modified_opinion_rate: f64,
5775
5776 #[serde(default)]
5778 pub include_emphasis_of_matter: bool,
5779
5780 #[serde(default = "default_true")]
5782 pub include_going_concern: bool,
5783}
5784
5785fn default_kam_count() -> usize {
5786 3
5787}
5788
5789fn default_modified_opinion_rate() -> f64 {
5790 0.05
5791}
5792
5793impl Default for AuditOpinionConfig {
5794 fn default() -> Self {
5795 Self {
5796 enabled: false,
5797 generate_kam: true,
5798 average_kam_count: default_kam_count(),
5799 modified_opinion_rate: default_modified_opinion_rate(),
5800 include_emphasis_of_matter: false,
5801 include_going_concern: true,
5802 }
5803 }
5804}
5805
5806#[derive(Debug, Clone, Serialize, Deserialize)]
5808pub struct SoxComplianceConfig {
5809 #[serde(default)]
5811 pub enabled: bool,
5812
5813 #[serde(default = "default_true")]
5815 pub generate_302_certifications: bool,
5816
5817 #[serde(default = "default_true")]
5819 pub generate_404_assessments: bool,
5820
5821 #[serde(default = "default_sox_materiality_threshold")]
5823 pub materiality_threshold: f64,
5824
5825 #[serde(default = "default_material_weakness_rate")]
5827 pub material_weakness_rate: f64,
5828
5829 #[serde(default = "default_significant_deficiency_rate")]
5831 pub significant_deficiency_rate: f64,
5832}
5833
5834fn default_material_weakness_rate() -> f64 {
5835 0.02
5836}
5837
5838fn default_significant_deficiency_rate() -> f64 {
5839 0.08
5840}
5841
5842impl Default for SoxComplianceConfig {
5843 fn default() -> Self {
5844 Self {
5845 enabled: false,
5846 generate_302_certifications: true,
5847 generate_404_assessments: true,
5848 materiality_threshold: default_sox_materiality_threshold(),
5849 material_weakness_rate: default_material_weakness_rate(),
5850 significant_deficiency_rate: default_significant_deficiency_rate(),
5851 }
5852 }
5853}
5854
5855#[derive(Debug, Clone, Serialize, Deserialize)]
5857pub struct PcaobConfig {
5858 #[serde(default)]
5860 pub enabled: bool,
5861
5862 #[serde(default)]
5864 pub is_pcaob_audit: bool,
5865
5866 #[serde(default = "default_true")]
5868 pub generate_cam: bool,
5869
5870 #[serde(default)]
5872 pub include_icfr_opinion: bool,
5873
5874 #[serde(default)]
5876 pub generate_standard_mappings: bool,
5877}
5878
5879impl Default for PcaobConfig {
5880 fn default() -> Self {
5881 Self {
5882 enabled: false,
5883 is_pcaob_audit: false,
5884 generate_cam: true,
5885 include_icfr_opinion: false,
5886 generate_standard_mappings: false,
5887 }
5888 }
5889}
5890
5891#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5904pub struct AdvancedDistributionConfig {
5905 #[serde(default)]
5907 pub enabled: bool,
5908
5909 #[serde(default)]
5911 pub amounts: MixtureDistributionSchemaConfig,
5912
5913 #[serde(default)]
5915 pub correlations: CorrelationSchemaConfig,
5916
5917 #[serde(default)]
5919 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5920
5921 #[serde(default)]
5923 pub regime_changes: RegimeChangeSchemaConfig,
5924
5925 #[serde(default)]
5927 pub industry_profile: Option<IndustryProfileType>,
5928
5929 #[serde(default)]
5931 pub validation: StatisticalValidationSchemaConfig,
5932
5933 #[serde(default)]
5939 pub pareto: Option<ParetoSchemaConfig>,
5940}
5941
5942#[derive(Debug, Clone, Serialize, Deserialize)]
5947pub struct ParetoSchemaConfig {
5948 #[serde(default)]
5951 pub enabled: bool,
5952
5953 #[serde(default = "default_pareto_alpha")]
5956 pub alpha: f64,
5957
5958 #[serde(default = "default_pareto_x_min")]
5961 pub x_min: f64,
5962
5963 #[serde(default)]
5966 pub max_value: Option<f64>,
5967
5968 #[serde(default = "default_pareto_decimal_places")]
5970 pub decimal_places: u8,
5971}
5972
5973fn default_pareto_alpha() -> f64 {
5974 2.0
5975}
5976
5977fn default_pareto_x_min() -> f64 {
5978 100.0
5979}
5980
5981fn default_pareto_decimal_places() -> u8 {
5982 2
5983}
5984
5985impl Default for ParetoSchemaConfig {
5986 fn default() -> Self {
5987 Self {
5988 enabled: false,
5989 alpha: default_pareto_alpha(),
5990 x_min: default_pareto_x_min(),
5991 max_value: None,
5992 decimal_places: default_pareto_decimal_places(),
5993 }
5994 }
5995}
5996
5997impl ParetoSchemaConfig {
5998 pub fn to_core_config(&self) -> datasynth_core::distributions::ParetoConfig {
6000 datasynth_core::distributions::ParetoConfig {
6001 alpha: self.alpha,
6002 x_min: self.x_min,
6003 max_value: self.max_value,
6004 decimal_places: self.decimal_places,
6005 }
6006 }
6007}
6008
6009#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6011#[serde(rename_all = "snake_case")]
6012pub enum IndustryProfileType {
6013 Retail,
6015 Manufacturing,
6017 FinancialServices,
6019 Healthcare,
6021 Technology,
6023}
6024
6025#[derive(Debug, Clone, Serialize, Deserialize)]
6027pub struct MixtureDistributionSchemaConfig {
6028 #[serde(default)]
6030 pub enabled: bool,
6031
6032 #[serde(default = "default_mixture_type")]
6034 pub distribution_type: MixtureDistributionType,
6035
6036 #[serde(default)]
6038 pub components: Vec<MixtureComponentConfig>,
6039
6040 #[serde(default = "default_min_amount")]
6042 pub min_value: f64,
6043
6044 #[serde(default)]
6046 pub max_value: Option<f64>,
6047
6048 #[serde(default = "default_decimal_places")]
6050 pub decimal_places: u8,
6051}
6052
6053fn default_mixture_type() -> MixtureDistributionType {
6054 MixtureDistributionType::LogNormal
6055}
6056
6057fn default_min_amount() -> f64 {
6058 0.01
6059}
6060
6061fn default_decimal_places() -> u8 {
6062 2
6063}
6064
6065impl Default for MixtureDistributionSchemaConfig {
6066 fn default() -> Self {
6067 Self {
6068 enabled: false,
6069 distribution_type: MixtureDistributionType::LogNormal,
6070 components: Vec::new(),
6071 min_value: 0.01,
6072 max_value: None,
6073 decimal_places: 2,
6074 }
6075 }
6076}
6077
6078impl MixtureDistributionSchemaConfig {
6079 pub fn to_log_normal_config(
6086 &self,
6087 ) -> Option<datasynth_core::distributions::LogNormalMixtureConfig> {
6088 if self.components.is_empty() {
6089 return None;
6090 }
6091 Some(datasynth_core::distributions::LogNormalMixtureConfig {
6092 components: self
6093 .components
6094 .iter()
6095 .map(|c| match &c.label {
6096 Some(lbl) => datasynth_core::distributions::LogNormalComponent::with_label(
6097 c.weight,
6098 c.mu,
6099 c.sigma,
6100 lbl.clone(),
6101 ),
6102 None => datasynth_core::distributions::LogNormalComponent::new(
6103 c.weight, c.mu, c.sigma,
6104 ),
6105 })
6106 .collect(),
6107 min_value: self.min_value,
6108 max_value: self.max_value,
6109 decimal_places: self.decimal_places,
6110 })
6111 }
6112
6113 pub fn to_gaussian_config(
6116 &self,
6117 ) -> Option<datasynth_core::distributions::GaussianMixtureConfig> {
6118 if self.components.is_empty() {
6119 return None;
6120 }
6121 Some(datasynth_core::distributions::GaussianMixtureConfig {
6122 components: self
6123 .components
6124 .iter()
6125 .map(|c| {
6126 datasynth_core::distributions::GaussianComponent::new(c.weight, c.mu, c.sigma)
6127 })
6128 .collect(),
6129 allow_negative: true,
6130 min_value: Some(self.min_value),
6131 max_value: self.max_value,
6132 })
6133 }
6134}
6135
6136#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6138#[serde(rename_all = "snake_case")]
6139pub enum MixtureDistributionType {
6140 Gaussian,
6142 #[default]
6144 LogNormal,
6145}
6146
6147#[derive(Debug, Clone, Serialize, Deserialize)]
6149pub struct MixtureComponentConfig {
6150 pub weight: f64,
6152
6153 pub mu: f64,
6155
6156 pub sigma: f64,
6158
6159 #[serde(default)]
6161 pub label: Option<String>,
6162}
6163
6164#[derive(Debug, Clone, Serialize, Deserialize)]
6166pub struct CorrelationSchemaConfig {
6167 #[serde(default)]
6169 pub enabled: bool,
6170
6171 #[serde(default)]
6173 pub copula_type: CopulaSchemaType,
6174
6175 #[serde(default)]
6177 pub fields: Vec<CorrelatedFieldConfig>,
6178
6179 #[serde(default)]
6182 pub matrix: Vec<f64>,
6183
6184 #[serde(default)]
6186 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
6187}
6188
6189impl Default for CorrelationSchemaConfig {
6190 fn default() -> Self {
6191 Self {
6192 enabled: false,
6193 copula_type: CopulaSchemaType::Gaussian,
6194 fields: Vec::new(),
6195 matrix: Vec::new(),
6196 expected_correlations: Vec::new(),
6197 }
6198 }
6199}
6200
6201impl CorrelationSchemaConfig {
6202 pub fn correlation_between(&self, field_a: &str, field_b: &str) -> Option<f64> {
6208 let idx_a = self.fields.iter().position(|f| f.name == field_a)?;
6209 let idx_b = self.fields.iter().position(|f| f.name == field_b)?;
6210 if idx_a == idx_b {
6211 return Some(1.0);
6212 }
6213 let (i, j) = if idx_a < idx_b {
6214 (idx_a, idx_b)
6215 } else {
6216 (idx_b, idx_a)
6217 };
6218 let n = self.fields.len();
6219 if self.matrix.len() == n * n {
6221 return self.matrix.get(idx_a * n + idx_b).copied();
6222 }
6223 let expected_tri = n * (n - 1) / 2;
6225 if self.matrix.len() == expected_tri {
6226 let flat = i * (n - 1) - i * (i.saturating_sub(1)) / 2 + (j - i - 1);
6230 return self.matrix.get(flat).copied();
6231 }
6232 None
6233 }
6234
6235 pub fn to_core_config_for_pair(
6240 &self,
6241 field_a: &str,
6242 field_b: &str,
6243 ) -> Option<datasynth_core::distributions::CopulaConfig> {
6244 if !self.enabled {
6245 return None;
6246 }
6247 let rho = self.correlation_between(field_a, field_b)?;
6248 use datasynth_core::distributions::{CopulaConfig, CopulaType};
6249 let copula_type = match self.copula_type {
6250 CopulaSchemaType::Gaussian => CopulaType::Gaussian,
6251 CopulaSchemaType::Clayton => CopulaType::Clayton,
6252 CopulaSchemaType::Gumbel => CopulaType::Gumbel,
6253 CopulaSchemaType::Frank => CopulaType::Frank,
6254 CopulaSchemaType::StudentT => CopulaType::StudentT,
6255 };
6256 let theta = rho.clamp(-0.999, 0.999);
6261 Some(CopulaConfig {
6262 copula_type,
6263 theta,
6264 degrees_of_freedom: 4.0,
6265 })
6266 }
6267}
6268
6269#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6271#[serde(rename_all = "snake_case")]
6272pub enum CopulaSchemaType {
6273 #[default]
6275 Gaussian,
6276 Clayton,
6278 Gumbel,
6280 Frank,
6282 StudentT,
6284}
6285
6286#[derive(Debug, Clone, Serialize, Deserialize)]
6288pub struct CorrelatedFieldConfig {
6289 pub name: String,
6291
6292 #[serde(default)]
6294 pub distribution: MarginalDistributionConfig,
6295}
6296
6297#[derive(Debug, Clone, Serialize, Deserialize)]
6299#[serde(tag = "type", rename_all = "snake_case")]
6300pub enum MarginalDistributionConfig {
6301 Normal {
6303 mu: f64,
6305 sigma: f64,
6307 },
6308 LogNormal {
6310 mu: f64,
6312 sigma: f64,
6314 },
6315 Uniform {
6317 min: f64,
6319 max: f64,
6321 },
6322 DiscreteUniform {
6324 min: i32,
6326 max: i32,
6328 },
6329}
6330
6331impl Default for MarginalDistributionConfig {
6332 fn default() -> Self {
6333 Self::Normal {
6334 mu: 0.0,
6335 sigma: 1.0,
6336 }
6337 }
6338}
6339
6340#[derive(Debug, Clone, Serialize, Deserialize)]
6342pub struct ExpectedCorrelationConfig {
6343 pub field1: String,
6345 pub field2: String,
6347 pub expected_r: f64,
6349 #[serde(default = "default_correlation_tolerance")]
6351 pub tolerance: f64,
6352}
6353
6354fn default_correlation_tolerance() -> f64 {
6355 0.10
6356}
6357
6358#[derive(Debug, Clone, Serialize, Deserialize)]
6360pub struct ConditionalDistributionSchemaConfig {
6361 pub output_field: String,
6363
6364 pub input_field: String,
6366
6367 #[serde(default)]
6369 pub breakpoints: Vec<ConditionalBreakpointConfig>,
6370
6371 #[serde(default)]
6373 pub default_distribution: ConditionalDistributionParamsConfig,
6374
6375 #[serde(default)]
6377 pub min_value: Option<f64>,
6378
6379 #[serde(default)]
6381 pub max_value: Option<f64>,
6382
6383 #[serde(default = "default_decimal_places")]
6385 pub decimal_places: u8,
6386}
6387
6388#[derive(Debug, Clone, Serialize, Deserialize)]
6390pub struct ConditionalBreakpointConfig {
6391 pub threshold: f64,
6393
6394 pub distribution: ConditionalDistributionParamsConfig,
6396}
6397
6398impl ConditionalDistributionSchemaConfig {
6399 pub fn to_core_config(&self) -> datasynth_core::distributions::ConditionalDistributionConfig {
6403 use datasynth_core::distributions::{
6404 Breakpoint, ConditionalDistributionConfig, ConditionalDistributionParams,
6405 };
6406
6407 let default_distribution = convert_conditional_params(&self.default_distribution);
6408 let breakpoints: Vec<Breakpoint> = self
6409 .breakpoints
6410 .iter()
6411 .map(|bp| Breakpoint {
6412 threshold: bp.threshold,
6413 distribution: convert_conditional_params(&bp.distribution),
6414 })
6415 .collect();
6416
6417 let final_default = if breakpoints.is_empty() {
6422 default_distribution
6423 } else {
6424 match default_distribution {
6425 ConditionalDistributionParams::Fixed { value: 0.0 } => {
6426 breakpoints[0].distribution.clone()
6429 }
6430 other => other,
6431 }
6432 };
6433
6434 ConditionalDistributionConfig {
6435 output_field: self.output_field.clone(),
6436 input_field: self.input_field.clone(),
6437 breakpoints,
6438 default_distribution: final_default,
6439 min_value: self.min_value,
6440 max_value: self.max_value,
6441 decimal_places: self.decimal_places,
6442 }
6443 }
6444}
6445
6446fn convert_conditional_params(
6447 p: &ConditionalDistributionParamsConfig,
6448) -> datasynth_core::distributions::ConditionalDistributionParams {
6449 use datasynth_core::distributions::ConditionalDistributionParams as Core;
6450 match p {
6451 ConditionalDistributionParamsConfig::Fixed { value } => Core::Fixed { value: *value },
6452 ConditionalDistributionParamsConfig::Normal { mu, sigma } => Core::Normal {
6453 mu: *mu,
6454 sigma: *sigma,
6455 },
6456 ConditionalDistributionParamsConfig::LogNormal { mu, sigma } => Core::LogNormal {
6457 mu: *mu,
6458 sigma: *sigma,
6459 },
6460 ConditionalDistributionParamsConfig::Uniform { min, max } => Core::Uniform {
6461 min: *min,
6462 max: *max,
6463 },
6464 ConditionalDistributionParamsConfig::Beta {
6465 alpha,
6466 beta,
6467 min,
6468 max,
6469 } => Core::Beta {
6470 alpha: *alpha,
6471 beta: *beta,
6472 min: *min,
6473 max: *max,
6474 },
6475 ConditionalDistributionParamsConfig::Discrete { values, weights } => Core::Discrete {
6476 values: values.clone(),
6477 weights: weights.clone(),
6478 },
6479 }
6480}
6481
6482#[derive(Debug, Clone, Serialize, Deserialize)]
6484#[serde(tag = "type", rename_all = "snake_case")]
6485pub enum ConditionalDistributionParamsConfig {
6486 Fixed {
6488 value: f64,
6490 },
6491 Normal {
6493 mu: f64,
6495 sigma: f64,
6497 },
6498 LogNormal {
6500 mu: f64,
6502 sigma: f64,
6504 },
6505 Uniform {
6507 min: f64,
6509 max: f64,
6511 },
6512 Beta {
6514 alpha: f64,
6516 beta: f64,
6518 min: f64,
6520 max: f64,
6522 },
6523 Discrete {
6525 values: Vec<f64>,
6527 weights: Vec<f64>,
6529 },
6530}
6531
6532impl Default for ConditionalDistributionParamsConfig {
6533 fn default() -> Self {
6534 Self::Normal {
6535 mu: 0.0,
6536 sigma: 1.0,
6537 }
6538 }
6539}
6540
6541#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6543pub struct RegimeChangeSchemaConfig {
6544 #[serde(default)]
6546 pub enabled: bool,
6547
6548 #[serde(default)]
6550 pub changes: Vec<RegimeChangeEventConfig>,
6551
6552 #[serde(default)]
6554 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6555
6556 #[serde(default)]
6558 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6559}
6560
6561#[derive(Debug, Clone, Serialize, Deserialize)]
6563pub struct RegimeChangeEventConfig {
6564 pub date: String,
6566
6567 pub change_type: RegimeChangeTypeConfig,
6569
6570 #[serde(default)]
6572 pub description: Option<String>,
6573
6574 #[serde(default)]
6576 pub effects: Vec<RegimeEffectConfig>,
6577}
6578
6579#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6581#[serde(rename_all = "snake_case")]
6582pub enum RegimeChangeTypeConfig {
6583 Acquisition,
6585 Divestiture,
6587 PriceIncrease,
6589 PriceDecrease,
6591 ProductLaunch,
6593 ProductDiscontinuation,
6595 PolicyChange,
6597 CompetitorEntry,
6599 Custom,
6601}
6602
6603#[derive(Debug, Clone, Serialize, Deserialize)]
6605pub struct RegimeEffectConfig {
6606 pub field: String,
6608
6609 pub multiplier: f64,
6611}
6612
6613#[derive(Debug, Clone, Serialize, Deserialize)]
6615pub struct EconomicCycleSchemaConfig {
6616 #[serde(default)]
6618 pub enabled: bool,
6619
6620 #[serde(default = "default_cycle_period")]
6622 pub period_months: u32,
6623
6624 #[serde(default = "default_cycle_amplitude")]
6626 pub amplitude: f64,
6627
6628 #[serde(default)]
6630 pub phase_offset: u32,
6631
6632 #[serde(default)]
6634 pub recessions: Vec<RecessionPeriodConfig>,
6635}
6636
6637fn default_cycle_period() -> u32 {
6638 48
6639}
6640
6641fn default_cycle_amplitude() -> f64 {
6642 0.15
6643}
6644
6645impl Default for EconomicCycleSchemaConfig {
6646 fn default() -> Self {
6647 Self {
6648 enabled: false,
6649 period_months: 48,
6650 amplitude: 0.15,
6651 phase_offset: 0,
6652 recessions: Vec::new(),
6653 }
6654 }
6655}
6656
6657#[derive(Debug, Clone, Serialize, Deserialize)]
6659pub struct RecessionPeriodConfig {
6660 pub start_month: u32,
6662
6663 pub duration_months: u32,
6665
6666 #[serde(default = "default_recession_severity")]
6668 pub severity: f64,
6669}
6670
6671impl RegimeChangeSchemaConfig {
6672 pub fn apply_to(
6680 &self,
6681 drift: &mut datasynth_core::distributions::DriftConfig,
6682 generation_start: chrono::NaiveDate,
6683 ) {
6684 if !self.enabled {
6685 return;
6686 }
6687
6688 drift.enabled = true;
6690
6691 for event in &self.changes {
6693 let period = match chrono::NaiveDate::parse_from_str(&event.date, "%Y-%m-%d") {
6694 Ok(d) => {
6695 let days = (d - generation_start).num_days();
6696 if days < 0 {
6697 continue;
6698 }
6699 (days as f64 / 30.4).round() as u32
6702 }
6703 Err(_) => continue,
6704 };
6705 let change_type = convert_regime_change_type(event.change_type);
6706 let core_effects = event
6707 .effects
6708 .iter()
6709 .map(|e| datasynth_core::distributions::RegimeEffect {
6710 field: e.field.clone(),
6711 multiplier: e.multiplier,
6712 })
6713 .collect();
6714 drift
6715 .regime_changes
6716 .push(datasynth_core::distributions::RegimeChange {
6717 period,
6718 change_type,
6719 description: event.description.clone(),
6720 effects: core_effects,
6721 transition_periods: 0,
6722 });
6723 }
6724
6725 if let Some(ec) = &self.economic_cycle {
6727 if ec.enabled {
6728 let recession_periods: Vec<u32> = ec
6729 .recessions
6730 .iter()
6731 .flat_map(|r| r.start_month..r.start_month + r.duration_months)
6732 .collect();
6733 let severity = ec
6736 .recessions
6737 .iter()
6738 .map(|r| 1.0 - r.severity)
6739 .fold(0.75f64, f64::min);
6740 drift.economic_cycle = datasynth_core::distributions::EconomicCycleConfig {
6741 enabled: true,
6742 cycle_length: ec.period_months,
6743 amplitude: ec.amplitude,
6744 phase_offset: ec.phase_offset,
6745 recession_periods,
6746 recession_severity: severity,
6747 };
6748 drift.drift_type = datasynth_core::distributions::DriftType::Mixed;
6749 }
6750 }
6751
6752 for pd in &self.parameter_drifts {
6754 let drift_type = match pd.drift_type {
6755 ParameterDriftTypeConfig::Linear => {
6756 datasynth_core::distributions::ParameterDriftType::Linear
6757 }
6758 ParameterDriftTypeConfig::Exponential => {
6759 datasynth_core::distributions::ParameterDriftType::Exponential
6760 }
6761 ParameterDriftTypeConfig::Logistic => {
6762 datasynth_core::distributions::ParameterDriftType::Logistic
6763 }
6764 ParameterDriftTypeConfig::Step => {
6765 datasynth_core::distributions::ParameterDriftType::Step
6766 }
6767 };
6768 drift
6769 .parameter_drifts
6770 .push(datasynth_core::distributions::ParameterDrift {
6771 parameter: pd.parameter.clone(),
6772 drift_type,
6773 initial_value: pd.start_value,
6774 target_or_rate: pd.end_value,
6775 start_period: pd.start_period,
6776 end_period: pd.end_period,
6777 steepness: 1.0,
6778 });
6779 }
6780 }
6781}
6782
6783fn convert_regime_change_type(
6784 t: RegimeChangeTypeConfig,
6785) -> datasynth_core::distributions::RegimeChangeType {
6786 use datasynth_core::distributions::RegimeChangeType as Core;
6787 match t {
6788 RegimeChangeTypeConfig::Acquisition => Core::Acquisition,
6789 RegimeChangeTypeConfig::Divestiture => Core::Divestiture,
6790 RegimeChangeTypeConfig::PriceIncrease => Core::PriceIncrease,
6791 RegimeChangeTypeConfig::PriceDecrease => Core::PriceDecrease,
6792 RegimeChangeTypeConfig::ProductLaunch => Core::ProductLaunch,
6793 RegimeChangeTypeConfig::ProductDiscontinuation => Core::ProductDiscontinuation,
6794 RegimeChangeTypeConfig::PolicyChange => Core::PolicyChange,
6795 RegimeChangeTypeConfig::CompetitorEntry => Core::CompetitorEntry,
6796 RegimeChangeTypeConfig::Custom => Core::Custom,
6797 }
6798}
6799
6800fn default_recession_severity() -> f64 {
6801 0.20
6802}
6803
6804#[derive(Debug, Clone, Serialize, Deserialize)]
6806pub struct ParameterDriftSchemaConfig {
6807 pub parameter: String,
6809
6810 pub drift_type: ParameterDriftTypeConfig,
6812
6813 pub start_value: f64,
6815
6816 pub end_value: f64,
6818
6819 #[serde(default)]
6821 pub start_period: u32,
6822
6823 #[serde(default)]
6825 pub end_period: Option<u32>,
6826}
6827
6828#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6830#[serde(rename_all = "snake_case")]
6831pub enum ParameterDriftTypeConfig {
6832 #[default]
6834 Linear,
6835 Exponential,
6837 Logistic,
6839 Step,
6841}
6842
6843#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6845pub struct StatisticalValidationSchemaConfig {
6846 #[serde(default)]
6848 pub enabled: bool,
6849
6850 #[serde(default)]
6852 pub tests: Vec<StatisticalTestConfig>,
6853
6854 #[serde(default)]
6856 pub reporting: ValidationReportingConfig,
6857}
6858
6859#[derive(Debug, Clone, Serialize, Deserialize)]
6861#[serde(tag = "type", rename_all = "snake_case")]
6862pub enum StatisticalTestConfig {
6863 BenfordFirstDigit {
6865 #[serde(default = "default_benford_threshold")]
6867 threshold_mad: f64,
6868 #[serde(default = "default_benford_warning")]
6870 warning_mad: f64,
6871 },
6872 DistributionFit {
6874 target: TargetDistributionConfig,
6876 #[serde(default = "default_ks_significance")]
6878 ks_significance: f64,
6879 #[serde(default)]
6881 method: DistributionFitMethod,
6882 },
6883 CorrelationCheck {
6885 expected_correlations: Vec<ExpectedCorrelationConfig>,
6887 },
6888 ChiSquared {
6890 #[serde(default = "default_chi_squared_bins")]
6892 bins: usize,
6893 #[serde(default = "default_chi_squared_significance")]
6895 significance: f64,
6896 },
6897 AndersonDarling {
6899 target: TargetDistributionConfig,
6901 #[serde(default = "default_ad_significance")]
6903 significance: f64,
6904 },
6905}
6906
6907fn default_benford_threshold() -> f64 {
6908 0.015
6909}
6910
6911fn default_benford_warning() -> f64 {
6912 0.010
6913}
6914
6915fn default_ks_significance() -> f64 {
6916 0.05
6917}
6918
6919fn default_chi_squared_bins() -> usize {
6920 10
6921}
6922
6923fn default_chi_squared_significance() -> f64 {
6924 0.05
6925}
6926
6927fn default_ad_significance() -> f64 {
6928 0.05
6929}
6930
6931#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6933#[serde(rename_all = "snake_case")]
6934pub enum TargetDistributionConfig {
6935 Normal,
6937 #[default]
6939 LogNormal,
6940 Exponential,
6942 Uniform,
6944}
6945
6946#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6948#[serde(rename_all = "snake_case")]
6949pub enum DistributionFitMethod {
6950 #[default]
6952 KolmogorovSmirnov,
6953 AndersonDarling,
6955 ChiSquared,
6957}
6958
6959#[derive(Debug, Clone, Serialize, Deserialize)]
6961pub struct ValidationReportingConfig {
6962 #[serde(default)]
6964 pub output_report: bool,
6965
6966 #[serde(default)]
6968 pub format: ValidationReportFormat,
6969
6970 #[serde(default)]
6972 pub fail_on_error: bool,
6973
6974 #[serde(default = "default_true")]
6976 pub include_details: bool,
6977}
6978
6979impl Default for ValidationReportingConfig {
6980 fn default() -> Self {
6981 Self {
6982 output_report: false,
6983 format: ValidationReportFormat::Json,
6984 fail_on_error: false,
6985 include_details: true,
6986 }
6987 }
6988}
6989
6990#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6992#[serde(rename_all = "snake_case")]
6993pub enum ValidationReportFormat {
6994 #[default]
6996 Json,
6997 Yaml,
6999 Html,
7001}
7002
7003#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7015pub struct TemporalPatternsConfig {
7016 #[serde(default)]
7018 pub enabled: bool,
7019
7020 #[serde(default)]
7022 pub business_days: BusinessDaySchemaConfig,
7023
7024 #[serde(default)]
7026 pub calendars: CalendarSchemaConfig,
7027
7028 #[serde(default)]
7030 pub period_end: PeriodEndSchemaConfig,
7031
7032 #[serde(default)]
7034 pub processing_lags: ProcessingLagSchemaConfig,
7035
7036 #[serde(default)]
7038 pub fiscal_calendar: FiscalCalendarSchemaConfig,
7039
7040 #[serde(default)]
7042 pub intraday: IntraDaySchemaConfig,
7043
7044 #[serde(default)]
7046 pub timezones: TimezoneSchemaConfig,
7047}
7048
7049#[derive(Debug, Clone, Serialize, Deserialize)]
7051pub struct BusinessDaySchemaConfig {
7052 #[serde(default = "default_true")]
7054 pub enabled: bool,
7055
7056 #[serde(default = "default_half_day_policy")]
7058 pub half_day_policy: String,
7059
7060 #[serde(default)]
7062 pub settlement_rules: SettlementRulesSchemaConfig,
7063
7064 #[serde(default = "default_month_end_convention")]
7066 pub month_end_convention: String,
7067
7068 #[serde(default)]
7070 pub weekend_days: Option<Vec<String>>,
7071}
7072
7073fn default_half_day_policy() -> String {
7074 "half_day".to_string()
7075}
7076
7077fn default_month_end_convention() -> String {
7078 "modified_following".to_string()
7079}
7080
7081impl Default for BusinessDaySchemaConfig {
7082 fn default() -> Self {
7083 Self {
7084 enabled: true,
7085 half_day_policy: "half_day".to_string(),
7086 settlement_rules: SettlementRulesSchemaConfig::default(),
7087 month_end_convention: "modified_following".to_string(),
7088 weekend_days: None,
7089 }
7090 }
7091}
7092
7093#[derive(Debug, Clone, Serialize, Deserialize)]
7095pub struct SettlementRulesSchemaConfig {
7096 #[serde(default = "default_settlement_2")]
7098 pub equity_days: i32,
7099
7100 #[serde(default = "default_settlement_1")]
7102 pub government_bonds_days: i32,
7103
7104 #[serde(default = "default_settlement_2")]
7106 pub fx_spot_days: i32,
7107
7108 #[serde(default = "default_settlement_2")]
7110 pub corporate_bonds_days: i32,
7111
7112 #[serde(default = "default_wire_cutoff")]
7114 pub wire_cutoff_time: String,
7115
7116 #[serde(default = "default_settlement_1")]
7118 pub wire_international_days: i32,
7119
7120 #[serde(default = "default_settlement_1")]
7122 pub ach_days: i32,
7123}
7124
7125fn default_settlement_1() -> i32 {
7126 1
7127}
7128
7129fn default_settlement_2() -> i32 {
7130 2
7131}
7132
7133fn default_wire_cutoff() -> String {
7134 "14:00".to_string()
7135}
7136
7137impl Default for SettlementRulesSchemaConfig {
7138 fn default() -> Self {
7139 Self {
7140 equity_days: 2,
7141 government_bonds_days: 1,
7142 fx_spot_days: 2,
7143 corporate_bonds_days: 2,
7144 wire_cutoff_time: "14:00".to_string(),
7145 wire_international_days: 1,
7146 ach_days: 1,
7147 }
7148 }
7149}
7150
7151#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7153pub struct CalendarSchemaConfig {
7154 #[serde(default)]
7156 pub regions: Vec<String>,
7157
7158 #[serde(default)]
7160 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
7161}
7162
7163#[derive(Debug, Clone, Serialize, Deserialize)]
7165pub struct CustomHolidaySchemaConfig {
7166 pub name: String,
7168 pub month: u8,
7170 pub day: u8,
7172 #[serde(default = "default_holiday_multiplier")]
7174 pub activity_multiplier: f64,
7175}
7176
7177fn default_holiday_multiplier() -> f64 {
7178 0.05
7179}
7180
7181#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7183pub struct PeriodEndSchemaConfig {
7184 #[serde(default)]
7186 pub model: Option<String>,
7187
7188 #[serde(default)]
7190 pub month_end: Option<PeriodEndModelSchemaConfig>,
7191
7192 #[serde(default)]
7194 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
7195
7196 #[serde(default)]
7198 pub year_end: Option<PeriodEndModelSchemaConfig>,
7199}
7200
7201#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7203pub struct PeriodEndModelSchemaConfig {
7204 #[serde(default)]
7206 pub inherit_from: Option<String>,
7207
7208 #[serde(default)]
7210 pub additional_multiplier: Option<f64>,
7211
7212 #[serde(default)]
7214 pub start_day: Option<i32>,
7215
7216 #[serde(default)]
7218 pub base_multiplier: Option<f64>,
7219
7220 #[serde(default)]
7222 pub peak_multiplier: Option<f64>,
7223
7224 #[serde(default)]
7226 pub decay_rate: Option<f64>,
7227
7228 #[serde(default)]
7230 pub sustained_high_days: Option<i32>,
7231}
7232
7233#[derive(Debug, Clone, Serialize, Deserialize)]
7235pub struct ProcessingLagSchemaConfig {
7236 #[serde(default = "default_true")]
7238 pub enabled: bool,
7239
7240 #[serde(default)]
7242 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
7243
7244 #[serde(default)]
7246 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
7247
7248 #[serde(default)]
7250 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
7251
7252 #[serde(default)]
7254 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
7255
7256 #[serde(default)]
7258 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
7259
7260 #[serde(default)]
7262 pub payment_lag: Option<LagDistributionSchemaConfig>,
7263
7264 #[serde(default)]
7266 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
7267
7268 #[serde(default)]
7270 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
7271}
7272
7273impl Default for ProcessingLagSchemaConfig {
7274 fn default() -> Self {
7275 Self {
7276 enabled: true,
7277 sales_order_lag: None,
7278 purchase_order_lag: None,
7279 goods_receipt_lag: None,
7280 invoice_receipt_lag: None,
7281 invoice_issue_lag: None,
7282 payment_lag: None,
7283 journal_entry_lag: None,
7284 cross_day_posting: None,
7285 }
7286 }
7287}
7288
7289#[derive(Debug, Clone, Serialize, Deserialize)]
7291pub struct LagDistributionSchemaConfig {
7292 pub mu: f64,
7294 pub sigma: f64,
7296 #[serde(default)]
7298 pub min_hours: Option<f64>,
7299 #[serde(default)]
7301 pub max_hours: Option<f64>,
7302}
7303
7304#[derive(Debug, Clone, Serialize, Deserialize)]
7306pub struct CrossDayPostingSchemaConfig {
7307 #[serde(default = "default_true")]
7309 pub enabled: bool,
7310
7311 #[serde(default)]
7314 pub probability_by_hour: std::collections::HashMap<u8, f64>,
7315}
7316
7317impl Default for CrossDayPostingSchemaConfig {
7318 fn default() -> Self {
7319 let mut probability_by_hour = std::collections::HashMap::new();
7320 probability_by_hour.insert(17, 0.3);
7321 probability_by_hour.insert(18, 0.6);
7322 probability_by_hour.insert(19, 0.8);
7323 probability_by_hour.insert(20, 0.9);
7324 probability_by_hour.insert(21, 0.95);
7325 probability_by_hour.insert(22, 0.99);
7326
7327 Self {
7328 enabled: true,
7329 probability_by_hour,
7330 }
7331 }
7332}
7333
7334#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7343pub struct FiscalCalendarSchemaConfig {
7344 #[serde(default)]
7346 pub enabled: bool,
7347
7348 #[serde(default = "default_fiscal_calendar_type")]
7350 pub calendar_type: String,
7351
7352 #[serde(default)]
7354 pub year_start_month: Option<u8>,
7355
7356 #[serde(default)]
7358 pub year_start_day: Option<u8>,
7359
7360 #[serde(default)]
7362 pub four_four_five: Option<FourFourFiveSchemaConfig>,
7363}
7364
7365fn default_fiscal_calendar_type() -> String {
7366 "calendar_year".to_string()
7367}
7368
7369#[derive(Debug, Clone, Serialize, Deserialize)]
7371pub struct FourFourFiveSchemaConfig {
7372 #[serde(default = "default_week_pattern")]
7374 pub pattern: String,
7375
7376 #[serde(default = "default_anchor_type")]
7378 pub anchor_type: String,
7379
7380 #[serde(default = "default_anchor_month")]
7382 pub anchor_month: u8,
7383
7384 #[serde(default = "default_leap_week_placement")]
7386 pub leap_week_placement: String,
7387}
7388
7389fn default_week_pattern() -> String {
7390 "four_four_five".to_string()
7391}
7392
7393fn default_anchor_type() -> String {
7394 "last_saturday".to_string()
7395}
7396
7397fn default_anchor_month() -> u8 {
7398 1 }
7400
7401fn default_leap_week_placement() -> String {
7402 "q4_period3".to_string()
7403}
7404
7405impl Default for FourFourFiveSchemaConfig {
7406 fn default() -> Self {
7407 Self {
7408 pattern: "four_four_five".to_string(),
7409 anchor_type: "last_saturday".to_string(),
7410 anchor_month: 1,
7411 leap_week_placement: "q4_period3".to_string(),
7412 }
7413 }
7414}
7415
7416#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7425pub struct IntraDaySchemaConfig {
7426 #[serde(default)]
7428 pub enabled: bool,
7429
7430 #[serde(default)]
7432 pub segments: Vec<IntraDaySegmentSchemaConfig>,
7433}
7434
7435#[derive(Debug, Clone, Serialize, Deserialize)]
7437pub struct IntraDaySegmentSchemaConfig {
7438 pub name: String,
7440
7441 pub start: String,
7443
7444 pub end: String,
7446
7447 #[serde(default = "default_multiplier")]
7449 pub multiplier: f64,
7450
7451 #[serde(default = "default_posting_type")]
7453 pub posting_type: String,
7454}
7455
7456fn default_multiplier() -> f64 {
7457 1.0
7458}
7459
7460fn default_posting_type() -> String {
7461 "both".to_string()
7462}
7463
7464#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7470pub struct TimezoneSchemaConfig {
7471 #[serde(default)]
7473 pub enabled: bool,
7474
7475 #[serde(default = "default_timezone")]
7477 pub default_timezone: String,
7478
7479 #[serde(default = "default_consolidation_timezone")]
7481 pub consolidation_timezone: String,
7482
7483 #[serde(default)]
7486 pub entity_mappings: Vec<EntityTimezoneMapping>,
7487}
7488
7489fn default_timezone() -> String {
7490 "America/New_York".to_string()
7491}
7492
7493fn default_consolidation_timezone() -> String {
7494 "UTC".to_string()
7495}
7496
7497#[derive(Debug, Clone, Serialize, Deserialize)]
7499pub struct EntityTimezoneMapping {
7500 pub pattern: String,
7502
7503 pub timezone: String,
7505}
7506
7507#[derive(Debug, Clone, Serialize, Deserialize)]
7513pub struct VendorNetworkSchemaConfig {
7514 #[serde(default)]
7516 pub enabled: bool,
7517
7518 #[serde(default = "default_vendor_tier_depth")]
7520 pub depth: u8,
7521
7522 #[serde(default)]
7524 pub tier1: TierCountSchemaConfig,
7525
7526 #[serde(default)]
7528 pub tier2_per_parent: TierCountSchemaConfig,
7529
7530 #[serde(default)]
7532 pub tier3_per_parent: TierCountSchemaConfig,
7533
7534 #[serde(default)]
7536 pub clusters: VendorClusterSchemaConfig,
7537
7538 #[serde(default)]
7540 pub dependencies: DependencySchemaConfig,
7541}
7542
7543fn default_vendor_tier_depth() -> u8 {
7544 3
7545}
7546
7547impl Default for VendorNetworkSchemaConfig {
7548 fn default() -> Self {
7549 Self {
7550 enabled: false,
7551 depth: 3,
7552 tier1: TierCountSchemaConfig { min: 50, max: 100 },
7553 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
7554 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
7555 clusters: VendorClusterSchemaConfig::default(),
7556 dependencies: DependencySchemaConfig::default(),
7557 }
7558 }
7559}
7560
7561#[derive(Debug, Clone, Serialize, Deserialize)]
7563pub struct TierCountSchemaConfig {
7564 #[serde(default = "default_tier_min")]
7566 pub min: usize,
7567
7568 #[serde(default = "default_tier_max")]
7570 pub max: usize,
7571}
7572
7573fn default_tier_min() -> usize {
7574 5
7575}
7576
7577fn default_tier_max() -> usize {
7578 20
7579}
7580
7581impl Default for TierCountSchemaConfig {
7582 fn default() -> Self {
7583 Self {
7584 min: default_tier_min(),
7585 max: default_tier_max(),
7586 }
7587 }
7588}
7589
7590#[derive(Debug, Clone, Serialize, Deserialize)]
7592pub struct VendorClusterSchemaConfig {
7593 #[serde(default = "default_reliable_strategic")]
7595 pub reliable_strategic: f64,
7596
7597 #[serde(default = "default_standard_operational")]
7599 pub standard_operational: f64,
7600
7601 #[serde(default = "default_transactional")]
7603 pub transactional: f64,
7604
7605 #[serde(default = "default_problematic")]
7607 pub problematic: f64,
7608}
7609
7610fn default_reliable_strategic() -> f64 {
7611 0.20
7612}
7613
7614fn default_standard_operational() -> f64 {
7615 0.50
7616}
7617
7618fn default_transactional() -> f64 {
7619 0.25
7620}
7621
7622fn default_problematic() -> f64 {
7623 0.05
7624}
7625
7626impl Default for VendorClusterSchemaConfig {
7627 fn default() -> Self {
7628 Self {
7629 reliable_strategic: 0.20,
7630 standard_operational: 0.50,
7631 transactional: 0.25,
7632 problematic: 0.05,
7633 }
7634 }
7635}
7636
7637#[derive(Debug, Clone, Serialize, Deserialize)]
7639pub struct DependencySchemaConfig {
7640 #[serde(default = "default_max_single_vendor")]
7642 pub max_single_vendor_concentration: f64,
7643
7644 #[serde(default = "default_max_top5")]
7646 pub top_5_concentration: f64,
7647
7648 #[serde(default = "default_single_source_percent")]
7650 pub single_source_percent: f64,
7651}
7652
7653fn default_max_single_vendor() -> f64 {
7654 0.15
7655}
7656
7657fn default_max_top5() -> f64 {
7658 0.45
7659}
7660
7661fn default_single_source_percent() -> f64 {
7662 0.05
7663}
7664
7665impl Default for DependencySchemaConfig {
7666 fn default() -> Self {
7667 Self {
7668 max_single_vendor_concentration: 0.15,
7669 top_5_concentration: 0.45,
7670 single_source_percent: 0.05,
7671 }
7672 }
7673}
7674
7675#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7681pub struct CustomerSegmentationSchemaConfig {
7682 #[serde(default)]
7684 pub enabled: bool,
7685
7686 #[serde(default)]
7688 pub value_segments: ValueSegmentsSchemaConfig,
7689
7690 #[serde(default)]
7692 pub lifecycle: LifecycleSchemaConfig,
7693
7694 #[serde(default)]
7696 pub networks: CustomerNetworksSchemaConfig,
7697}
7698
7699#[derive(Debug, Clone, Serialize, Deserialize)]
7701pub struct ValueSegmentsSchemaConfig {
7702 #[serde(default)]
7704 pub enterprise: SegmentDetailSchemaConfig,
7705
7706 #[serde(default)]
7708 pub mid_market: SegmentDetailSchemaConfig,
7709
7710 #[serde(default)]
7712 pub smb: SegmentDetailSchemaConfig,
7713
7714 #[serde(default)]
7716 pub consumer: SegmentDetailSchemaConfig,
7717}
7718
7719impl Default for ValueSegmentsSchemaConfig {
7720 fn default() -> Self {
7721 Self {
7722 enterprise: SegmentDetailSchemaConfig {
7723 revenue_share: 0.40,
7724 customer_share: 0.05,
7725 avg_order_value_range: "50000+".to_string(),
7726 },
7727 mid_market: SegmentDetailSchemaConfig {
7728 revenue_share: 0.35,
7729 customer_share: 0.20,
7730 avg_order_value_range: "5000-50000".to_string(),
7731 },
7732 smb: SegmentDetailSchemaConfig {
7733 revenue_share: 0.20,
7734 customer_share: 0.50,
7735 avg_order_value_range: "500-5000".to_string(),
7736 },
7737 consumer: SegmentDetailSchemaConfig {
7738 revenue_share: 0.05,
7739 customer_share: 0.25,
7740 avg_order_value_range: "50-500".to_string(),
7741 },
7742 }
7743 }
7744}
7745
7746#[derive(Debug, Clone, Serialize, Deserialize)]
7748pub struct SegmentDetailSchemaConfig {
7749 #[serde(default)]
7751 pub revenue_share: f64,
7752
7753 #[serde(default)]
7755 pub customer_share: f64,
7756
7757 #[serde(default)]
7759 pub avg_order_value_range: String,
7760}
7761
7762impl Default for SegmentDetailSchemaConfig {
7763 fn default() -> Self {
7764 Self {
7765 revenue_share: 0.25,
7766 customer_share: 0.25,
7767 avg_order_value_range: "1000-10000".to_string(),
7768 }
7769 }
7770}
7771
7772#[derive(Debug, Clone, Serialize, Deserialize)]
7774pub struct LifecycleSchemaConfig {
7775 #[serde(default)]
7777 pub prospect_rate: f64,
7778
7779 #[serde(default = "default_new_rate")]
7781 pub new_rate: f64,
7782
7783 #[serde(default = "default_growth_rate")]
7785 pub growth_rate: f64,
7786
7787 #[serde(default = "default_mature_rate")]
7789 pub mature_rate: f64,
7790
7791 #[serde(default = "default_at_risk_rate")]
7793 pub at_risk_rate: f64,
7794
7795 #[serde(default = "default_churned_rate")]
7797 pub churned_rate: f64,
7798
7799 #[serde(default)]
7801 pub won_back_rate: f64,
7802}
7803
7804fn default_new_rate() -> f64 {
7805 0.10
7806}
7807
7808fn default_growth_rate() -> f64 {
7809 0.15
7810}
7811
7812fn default_mature_rate() -> f64 {
7813 0.60
7814}
7815
7816fn default_at_risk_rate() -> f64 {
7817 0.10
7818}
7819
7820fn default_churned_rate() -> f64 {
7821 0.05
7822}
7823
7824impl Default for LifecycleSchemaConfig {
7825 fn default() -> Self {
7826 Self {
7827 prospect_rate: 0.0,
7828 new_rate: 0.10,
7829 growth_rate: 0.15,
7830 mature_rate: 0.60,
7831 at_risk_rate: 0.10,
7832 churned_rate: 0.05,
7833 won_back_rate: 0.0,
7834 }
7835 }
7836}
7837
7838#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7840pub struct CustomerNetworksSchemaConfig {
7841 #[serde(default)]
7843 pub referrals: ReferralSchemaConfig,
7844
7845 #[serde(default)]
7847 pub corporate_hierarchies: HierarchySchemaConfig,
7848}
7849
7850#[derive(Debug, Clone, Serialize, Deserialize)]
7852pub struct ReferralSchemaConfig {
7853 #[serde(default = "default_true")]
7855 pub enabled: bool,
7856
7857 #[serde(default = "default_referral_rate")]
7859 pub referral_rate: f64,
7860}
7861
7862fn default_referral_rate() -> f64 {
7863 0.15
7864}
7865
7866impl Default for ReferralSchemaConfig {
7867 fn default() -> Self {
7868 Self {
7869 enabled: true,
7870 referral_rate: 0.15,
7871 }
7872 }
7873}
7874
7875#[derive(Debug, Clone, Serialize, Deserialize)]
7877pub struct HierarchySchemaConfig {
7878 #[serde(default = "default_true")]
7880 pub enabled: bool,
7881
7882 #[serde(default = "default_hierarchy_rate")]
7884 pub probability: f64,
7885}
7886
7887fn default_hierarchy_rate() -> f64 {
7888 0.30
7889}
7890
7891impl Default for HierarchySchemaConfig {
7892 fn default() -> Self {
7893 Self {
7894 enabled: true,
7895 probability: 0.30,
7896 }
7897 }
7898}
7899
7900#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7906pub struct RelationshipStrengthSchemaConfig {
7907 #[serde(default)]
7909 pub enabled: bool,
7910
7911 #[serde(default)]
7913 pub calculation: StrengthCalculationSchemaConfig,
7914
7915 #[serde(default)]
7917 pub thresholds: StrengthThresholdsSchemaConfig,
7918}
7919
7920#[derive(Debug, Clone, Serialize, Deserialize)]
7922pub struct StrengthCalculationSchemaConfig {
7923 #[serde(default = "default_volume_weight")]
7925 pub transaction_volume_weight: f64,
7926
7927 #[serde(default = "default_count_weight")]
7929 pub transaction_count_weight: f64,
7930
7931 #[serde(default = "default_duration_weight")]
7933 pub relationship_duration_weight: f64,
7934
7935 #[serde(default = "default_recency_weight")]
7937 pub recency_weight: f64,
7938
7939 #[serde(default = "default_mutual_weight")]
7941 pub mutual_connections_weight: f64,
7942
7943 #[serde(default = "default_recency_half_life")]
7945 pub recency_half_life_days: u32,
7946}
7947
7948fn default_volume_weight() -> f64 {
7949 0.30
7950}
7951
7952fn default_count_weight() -> f64 {
7953 0.25
7954}
7955
7956fn default_duration_weight() -> f64 {
7957 0.20
7958}
7959
7960fn default_recency_weight() -> f64 {
7961 0.15
7962}
7963
7964fn default_mutual_weight() -> f64 {
7965 0.10
7966}
7967
7968fn default_recency_half_life() -> u32 {
7969 90
7970}
7971
7972impl Default for StrengthCalculationSchemaConfig {
7973 fn default() -> Self {
7974 Self {
7975 transaction_volume_weight: 0.30,
7976 transaction_count_weight: 0.25,
7977 relationship_duration_weight: 0.20,
7978 recency_weight: 0.15,
7979 mutual_connections_weight: 0.10,
7980 recency_half_life_days: 90,
7981 }
7982 }
7983}
7984
7985#[derive(Debug, Clone, Serialize, Deserialize)]
7987pub struct StrengthThresholdsSchemaConfig {
7988 #[serde(default = "default_strong_threshold")]
7990 pub strong: f64,
7991
7992 #[serde(default = "default_moderate_threshold")]
7994 pub moderate: f64,
7995
7996 #[serde(default = "default_weak_threshold")]
7998 pub weak: f64,
7999}
8000
8001fn default_strong_threshold() -> f64 {
8002 0.7
8003}
8004
8005fn default_moderate_threshold() -> f64 {
8006 0.4
8007}
8008
8009fn default_weak_threshold() -> f64 {
8010 0.1
8011}
8012
8013impl Default for StrengthThresholdsSchemaConfig {
8014 fn default() -> Self {
8015 Self {
8016 strong: 0.7,
8017 moderate: 0.4,
8018 weak: 0.1,
8019 }
8020 }
8021}
8022
8023#[derive(Debug, Clone, Serialize, Deserialize)]
8029pub struct CrossProcessLinksSchemaConfig {
8030 #[serde(default)]
8032 pub enabled: bool,
8033
8034 #[serde(default = "default_true")]
8036 pub inventory_p2p_o2c: bool,
8037
8038 #[serde(default = "default_true")]
8040 pub payment_bank_reconciliation: bool,
8041
8042 #[serde(default = "default_true")]
8044 pub intercompany_bilateral: bool,
8045
8046 #[serde(default = "default_inventory_link_rate")]
8048 pub inventory_link_rate: f64,
8049}
8050
8051fn default_inventory_link_rate() -> f64 {
8052 0.30
8053}
8054
8055impl Default for CrossProcessLinksSchemaConfig {
8056 fn default() -> Self {
8057 Self {
8058 enabled: false,
8059 inventory_p2p_o2c: true,
8060 payment_bank_reconciliation: true,
8061 intercompany_bilateral: true,
8062 inventory_link_rate: 0.30,
8063 }
8064 }
8065}
8066
8067#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8073pub struct OrganizationalEventsSchemaConfig {
8074 #[serde(default)]
8076 pub enabled: bool,
8077
8078 #[serde(default)]
8080 pub effect_blending: EffectBlendingModeConfig,
8081
8082 #[serde(default)]
8084 pub events: Vec<OrganizationalEventSchemaConfig>,
8085
8086 #[serde(default)]
8088 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
8089
8090 #[serde(default)]
8092 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
8093}
8094
8095#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8097#[serde(rename_all = "snake_case")]
8098pub enum EffectBlendingModeConfig {
8099 #[default]
8101 Multiplicative,
8102 Additive,
8104 Maximum,
8106 Minimum,
8108}
8109
8110#[derive(Debug, Clone, Serialize, Deserialize)]
8112pub struct OrganizationalEventSchemaConfig {
8113 pub id: String,
8115
8116 pub event_type: OrganizationalEventTypeSchemaConfig,
8118
8119 pub effective_date: String,
8121
8122 #[serde(default = "default_org_transition_months")]
8124 pub transition_months: u32,
8125
8126 #[serde(default)]
8128 pub description: Option<String>,
8129}
8130
8131fn default_org_transition_months() -> u32 {
8132 6
8133}
8134
8135#[derive(Debug, Clone, Serialize, Deserialize)]
8137#[serde(tag = "type", rename_all = "snake_case")]
8138pub enum OrganizationalEventTypeSchemaConfig {
8139 Acquisition {
8141 acquired_entity: String,
8143 #[serde(default = "default_acquisition_volume")]
8145 volume_increase: f64,
8146 #[serde(default = "default_acquisition_error")]
8148 integration_error_rate: f64,
8149 #[serde(default = "default_parallel_days")]
8151 parallel_posting_days: u32,
8152 },
8153 Divestiture {
8155 divested_entity: String,
8157 #[serde(default = "default_divestiture_volume")]
8159 volume_reduction: f64,
8160 #[serde(default = "default_true_val")]
8162 remove_entity: bool,
8163 },
8164 Reorganization {
8166 #[serde(default)]
8168 cost_center_remapping: std::collections::HashMap<String, String>,
8169 #[serde(default = "default_reorg_error")]
8171 transition_error_rate: f64,
8172 },
8173 LeadershipChange {
8175 role: String,
8177 #[serde(default)]
8179 policy_changes: Vec<String>,
8180 },
8181 WorkforceReduction {
8183 #[serde(default = "default_workforce_reduction")]
8185 reduction_percent: f64,
8186 #[serde(default = "default_workforce_error")]
8188 error_rate_increase: f64,
8189 },
8190 Merger {
8192 merged_entity: String,
8194 #[serde(default = "default_merger_volume")]
8196 volume_increase: f64,
8197 },
8198}
8199
8200fn default_acquisition_volume() -> f64 {
8201 1.35
8202}
8203
8204fn default_acquisition_error() -> f64 {
8205 0.05
8206}
8207
8208fn default_parallel_days() -> u32 {
8209 30
8210}
8211
8212fn default_divestiture_volume() -> f64 {
8213 0.70
8214}
8215
8216fn default_true_val() -> bool {
8217 true
8218}
8219
8220fn default_reorg_error() -> f64 {
8221 0.04
8222}
8223
8224fn default_workforce_reduction() -> f64 {
8225 0.10
8226}
8227
8228fn default_workforce_error() -> f64 {
8229 0.05
8230}
8231
8232fn default_merger_volume() -> f64 {
8233 1.80
8234}
8235
8236#[derive(Debug, Clone, Serialize, Deserialize)]
8238pub struct ProcessEvolutionSchemaConfig {
8239 pub id: String,
8241
8242 pub event_type: ProcessEvolutionTypeSchemaConfig,
8244
8245 pub effective_date: String,
8247
8248 #[serde(default)]
8250 pub description: Option<String>,
8251}
8252
8253#[derive(Debug, Clone, Serialize, Deserialize)]
8255#[serde(tag = "type", rename_all = "snake_case")]
8256pub enum ProcessEvolutionTypeSchemaConfig {
8257 ProcessAutomation {
8259 process_name: String,
8261 #[serde(default = "default_manual_before")]
8263 manual_rate_before: f64,
8264 #[serde(default = "default_manual_after")]
8266 manual_rate_after: f64,
8267 },
8268 ApprovalWorkflowChange {
8270 description: String,
8272 },
8273 ControlEnhancement {
8275 control_id: String,
8277 #[serde(default = "default_error_reduction")]
8279 error_reduction: f64,
8280 },
8281}
8282
8283fn default_manual_before() -> f64 {
8284 0.80
8285}
8286
8287fn default_manual_after() -> f64 {
8288 0.15
8289}
8290
8291fn default_error_reduction() -> f64 {
8292 0.02
8293}
8294
8295#[derive(Debug, Clone, Serialize, Deserialize)]
8297pub struct TechnologyTransitionSchemaConfig {
8298 pub id: String,
8300
8301 pub event_type: TechnologyTransitionTypeSchemaConfig,
8303
8304 #[serde(default)]
8306 pub description: Option<String>,
8307}
8308
8309#[derive(Debug, Clone, Serialize, Deserialize)]
8311#[serde(tag = "type", rename_all = "snake_case")]
8312pub enum TechnologyTransitionTypeSchemaConfig {
8313 ErpMigration {
8315 source_system: String,
8317 target_system: String,
8319 cutover_date: String,
8321 stabilization_end: String,
8323 #[serde(default = "default_erp_duplicate_rate")]
8325 duplicate_rate: f64,
8326 #[serde(default = "default_format_mismatch")]
8328 format_mismatch_rate: f64,
8329 },
8330 ModuleImplementation {
8332 module_name: String,
8334 go_live_date: String,
8336 },
8337}
8338
8339fn default_erp_duplicate_rate() -> f64 {
8340 0.02
8341}
8342
8343fn default_format_mismatch() -> f64 {
8344 0.03
8345}
8346
8347#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8362pub struct BehavioralDriftSchemaConfig {
8363 #[serde(default)]
8365 pub enabled: bool,
8366
8367 #[serde(default)]
8369 pub vendor_behavior: VendorBehaviorSchemaConfig,
8370
8371 #[serde(default)]
8373 pub customer_behavior: CustomerBehaviorSchemaConfig,
8374
8375 #[serde(default)]
8377 pub employee_behavior: EmployeeBehaviorSchemaConfig,
8378
8379 #[serde(default)]
8381 pub collective: CollectiveBehaviorSchemaConfig,
8382}
8383
8384#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8386pub struct VendorBehaviorSchemaConfig {
8387 #[serde(default)]
8389 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
8390
8391 #[serde(default)]
8393 pub quality_drift: QualityDriftSchemaConfig,
8394}
8395
8396#[derive(Debug, Clone, Serialize, Deserialize)]
8398pub struct PaymentTermsDriftSchemaConfig {
8399 #[serde(default = "default_extension_rate")]
8401 pub extension_rate_per_year: f64,
8402
8403 #[serde(default = "default_economic_sensitivity")]
8405 pub economic_sensitivity: f64,
8406}
8407
8408fn default_extension_rate() -> f64 {
8409 2.5
8410}
8411
8412fn default_economic_sensitivity() -> f64 {
8413 1.0
8414}
8415
8416impl Default for PaymentTermsDriftSchemaConfig {
8417 fn default() -> Self {
8418 Self {
8419 extension_rate_per_year: 2.5,
8420 economic_sensitivity: 1.0,
8421 }
8422 }
8423}
8424
8425#[derive(Debug, Clone, Serialize, Deserialize)]
8427pub struct QualityDriftSchemaConfig {
8428 #[serde(default = "default_improvement_rate")]
8430 pub new_vendor_improvement_rate: f64,
8431
8432 #[serde(default = "default_decline_rate")]
8434 pub complacency_decline_rate: f64,
8435}
8436
8437fn default_improvement_rate() -> f64 {
8438 0.02
8439}
8440
8441fn default_decline_rate() -> f64 {
8442 0.01
8443}
8444
8445impl Default for QualityDriftSchemaConfig {
8446 fn default() -> Self {
8447 Self {
8448 new_vendor_improvement_rate: 0.02,
8449 complacency_decline_rate: 0.01,
8450 }
8451 }
8452}
8453
8454#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8456pub struct CustomerBehaviorSchemaConfig {
8457 #[serde(default)]
8459 pub payment_drift: CustomerPaymentDriftSchemaConfig,
8460
8461 #[serde(default)]
8463 pub order_drift: OrderDriftSchemaConfig,
8464}
8465
8466#[derive(Debug, Clone, Serialize, Deserialize)]
8468pub struct CustomerPaymentDriftSchemaConfig {
8469 #[serde(default = "default_downturn_extension")]
8471 pub downturn_days_extension: (u32, u32),
8472
8473 #[serde(default = "default_bad_debt_increase")]
8475 pub downturn_bad_debt_increase: f64,
8476}
8477
8478fn default_downturn_extension() -> (u32, u32) {
8479 (5, 15)
8480}
8481
8482fn default_bad_debt_increase() -> f64 {
8483 0.02
8484}
8485
8486impl Default for CustomerPaymentDriftSchemaConfig {
8487 fn default() -> Self {
8488 Self {
8489 downturn_days_extension: (5, 15),
8490 downturn_bad_debt_increase: 0.02,
8491 }
8492 }
8493}
8494
8495#[derive(Debug, Clone, Serialize, Deserialize)]
8497pub struct OrderDriftSchemaConfig {
8498 #[serde(default = "default_digital_shift")]
8500 pub digital_shift_rate: f64,
8501}
8502
8503fn default_digital_shift() -> f64 {
8504 0.05
8505}
8506
8507impl Default for OrderDriftSchemaConfig {
8508 fn default() -> Self {
8509 Self {
8510 digital_shift_rate: 0.05,
8511 }
8512 }
8513}
8514
8515#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8517pub struct EmployeeBehaviorSchemaConfig {
8518 #[serde(default)]
8520 pub approval_drift: ApprovalDriftSchemaConfig,
8521
8522 #[serde(default)]
8524 pub error_drift: ErrorDriftSchemaConfig,
8525}
8526
8527#[derive(Debug, Clone, Serialize, Deserialize)]
8529pub struct ApprovalDriftSchemaConfig {
8530 #[serde(default = "default_eom_intensity")]
8532 pub eom_intensity_increase_per_year: f64,
8533
8534 #[serde(default = "default_rubber_stamp")]
8536 pub rubber_stamp_volume_threshold: u32,
8537}
8538
8539fn default_eom_intensity() -> f64 {
8540 0.05
8541}
8542
8543fn default_rubber_stamp() -> u32 {
8544 50
8545}
8546
8547impl Default for ApprovalDriftSchemaConfig {
8548 fn default() -> Self {
8549 Self {
8550 eom_intensity_increase_per_year: 0.05,
8551 rubber_stamp_volume_threshold: 50,
8552 }
8553 }
8554}
8555
8556#[derive(Debug, Clone, Serialize, Deserialize)]
8558pub struct ErrorDriftSchemaConfig {
8559 #[serde(default = "default_new_error")]
8561 pub new_employee_error_rate: f64,
8562
8563 #[serde(default = "default_learning_months")]
8565 pub learning_curve_months: u32,
8566}
8567
8568fn default_new_error() -> f64 {
8569 0.08
8570}
8571
8572fn default_learning_months() -> u32 {
8573 6
8574}
8575
8576impl Default for ErrorDriftSchemaConfig {
8577 fn default() -> Self {
8578 Self {
8579 new_employee_error_rate: 0.08,
8580 learning_curve_months: 6,
8581 }
8582 }
8583}
8584
8585#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8587pub struct CollectiveBehaviorSchemaConfig {
8588 #[serde(default)]
8590 pub automation_adoption: AutomationAdoptionSchemaConfig,
8591}
8592
8593#[derive(Debug, Clone, Serialize, Deserialize)]
8595pub struct AutomationAdoptionSchemaConfig {
8596 #[serde(default)]
8598 pub s_curve_enabled: bool,
8599
8600 #[serde(default = "default_midpoint")]
8602 pub adoption_midpoint_months: u32,
8603
8604 #[serde(default = "default_steepness")]
8606 pub steepness: f64,
8607}
8608
8609fn default_midpoint() -> u32 {
8610 24
8611}
8612
8613fn default_steepness() -> f64 {
8614 0.15
8615}
8616
8617impl Default for AutomationAdoptionSchemaConfig {
8618 fn default() -> Self {
8619 Self {
8620 s_curve_enabled: false,
8621 adoption_midpoint_months: 24,
8622 steepness: 0.15,
8623 }
8624 }
8625}
8626
8627#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8640pub struct MarketDriftSchemaConfig {
8641 #[serde(default)]
8643 pub enabled: bool,
8644
8645 #[serde(default)]
8647 pub economic_cycle: MarketEconomicCycleSchemaConfig,
8648
8649 #[serde(default)]
8651 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8652
8653 #[serde(default)]
8655 pub commodities: CommoditiesSchemaConfig,
8656}
8657
8658#[derive(Debug, Clone, Serialize, Deserialize)]
8660pub struct MarketEconomicCycleSchemaConfig {
8661 #[serde(default)]
8663 pub enabled: bool,
8664
8665 #[serde(default)]
8667 pub cycle_type: CycleTypeSchemaConfig,
8668
8669 #[serde(default = "default_market_cycle_period")]
8671 pub period_months: u32,
8672
8673 #[serde(default = "default_market_amplitude")]
8675 pub amplitude: f64,
8676
8677 #[serde(default)]
8679 pub recession: RecessionSchemaConfig,
8680}
8681
8682fn default_market_cycle_period() -> u32 {
8683 48
8684}
8685
8686fn default_market_amplitude() -> f64 {
8687 0.15
8688}
8689
8690impl Default for MarketEconomicCycleSchemaConfig {
8691 fn default() -> Self {
8692 Self {
8693 enabled: false,
8694 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8695 period_months: 48,
8696 amplitude: 0.15,
8697 recession: RecessionSchemaConfig::default(),
8698 }
8699 }
8700}
8701
8702#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8704#[serde(rename_all = "snake_case")]
8705pub enum CycleTypeSchemaConfig {
8706 #[default]
8708 Sinusoidal,
8709 Asymmetric,
8711 MeanReverting,
8713}
8714
8715#[derive(Debug, Clone, Serialize, Deserialize)]
8717pub struct RecessionSchemaConfig {
8718 #[serde(default)]
8720 pub enabled: bool,
8721
8722 #[serde(default = "default_recession_prob")]
8724 pub probability_per_year: f64,
8725
8726 #[serde(default)]
8728 pub severity: RecessionSeveritySchemaConfig,
8729
8730 #[serde(default)]
8732 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8733}
8734
8735fn default_recession_prob() -> f64 {
8736 0.10
8737}
8738
8739impl Default for RecessionSchemaConfig {
8740 fn default() -> Self {
8741 Self {
8742 enabled: false,
8743 probability_per_year: 0.10,
8744 severity: RecessionSeveritySchemaConfig::Moderate,
8745 recession_periods: Vec::new(),
8746 }
8747 }
8748}
8749
8750#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8752#[serde(rename_all = "snake_case")]
8753pub enum RecessionSeveritySchemaConfig {
8754 Mild,
8756 #[default]
8758 Moderate,
8759 Severe,
8761}
8762
8763#[derive(Debug, Clone, Serialize, Deserialize)]
8765pub struct RecessionPeriodSchemaConfig {
8766 pub start_month: u32,
8768 pub duration_months: u32,
8770}
8771
8772#[derive(Debug, Clone, Serialize, Deserialize)]
8774pub struct IndustryCycleSchemaConfig {
8775 #[serde(default = "default_industry_period")]
8777 pub period_months: u32,
8778
8779 #[serde(default = "default_industry_amp")]
8781 pub amplitude: f64,
8782}
8783
8784fn default_industry_period() -> u32 {
8785 36
8786}
8787
8788fn default_industry_amp() -> f64 {
8789 0.20
8790}
8791
8792#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8794pub struct CommoditiesSchemaConfig {
8795 #[serde(default)]
8797 pub enabled: bool,
8798
8799 #[serde(default)]
8801 pub items: Vec<CommodityItemSchemaConfig>,
8802}
8803
8804#[derive(Debug, Clone, Serialize, Deserialize)]
8806pub struct CommodityItemSchemaConfig {
8807 pub name: String,
8809
8810 #[serde(default = "default_volatility")]
8812 pub volatility: f64,
8813
8814 #[serde(default)]
8816 pub cogs_pass_through: f64,
8817
8818 #[serde(default)]
8820 pub overhead_pass_through: f64,
8821}
8822
8823fn default_volatility() -> f64 {
8824 0.20
8825}
8826
8827#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8840pub struct DriftLabelingSchemaConfig {
8841 #[serde(default)]
8843 pub enabled: bool,
8844
8845 #[serde(default)]
8847 pub statistical: StatisticalDriftLabelingSchemaConfig,
8848
8849 #[serde(default)]
8851 pub categorical: CategoricalDriftLabelingSchemaConfig,
8852
8853 #[serde(default)]
8855 pub temporal: TemporalDriftLabelingSchemaConfig,
8856
8857 #[serde(default)]
8859 pub regulatory_calendar_preset: Option<String>,
8860}
8861
8862#[derive(Debug, Clone, Serialize, Deserialize)]
8864pub struct StatisticalDriftLabelingSchemaConfig {
8865 #[serde(default = "default_true_val")]
8867 pub enabled: bool,
8868
8869 #[serde(default = "default_min_magnitude")]
8871 pub min_magnitude_threshold: f64,
8872}
8873
8874fn default_min_magnitude() -> f64 {
8875 0.05
8876}
8877
8878impl Default for StatisticalDriftLabelingSchemaConfig {
8879 fn default() -> Self {
8880 Self {
8881 enabled: true,
8882 min_magnitude_threshold: 0.05,
8883 }
8884 }
8885}
8886
8887#[derive(Debug, Clone, Serialize, Deserialize)]
8889pub struct CategoricalDriftLabelingSchemaConfig {
8890 #[serde(default = "default_true_val")]
8892 pub enabled: bool,
8893}
8894
8895impl Default for CategoricalDriftLabelingSchemaConfig {
8896 fn default() -> Self {
8897 Self { enabled: true }
8898 }
8899}
8900
8901#[derive(Debug, Clone, Serialize, Deserialize)]
8903pub struct TemporalDriftLabelingSchemaConfig {
8904 #[serde(default = "default_true_val")]
8906 pub enabled: bool,
8907}
8908
8909impl Default for TemporalDriftLabelingSchemaConfig {
8910 fn default() -> Self {
8911 Self { enabled: true }
8912 }
8913}
8914
8915#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8928pub struct EnhancedAnomalyConfig {
8929 #[serde(default)]
8931 pub enabled: bool,
8932
8933 #[serde(default)]
8935 pub rates: AnomalyRateConfig,
8936
8937 #[serde(default)]
8939 pub multi_stage_schemes: MultiStageSchemeConfig,
8940
8941 #[serde(default)]
8943 pub correlated_injection: CorrelatedInjectionConfig,
8944
8945 #[serde(default)]
8947 pub near_miss: NearMissConfig,
8948
8949 #[serde(default)]
8951 pub difficulty_classification: DifficultyClassificationConfig,
8952
8953 #[serde(default)]
8955 pub context_aware: ContextAwareConfig,
8956
8957 #[serde(default)]
8959 pub labeling: EnhancedLabelingConfig,
8960}
8961
8962#[derive(Debug, Clone, Serialize, Deserialize)]
8964pub struct AnomalyRateConfig {
8965 #[serde(default = "default_total_anomaly_rate")]
8967 pub total_rate: f64,
8968
8969 #[serde(default = "default_fraud_anomaly_rate")]
8971 pub fraud_rate: f64,
8972
8973 #[serde(default = "default_error_anomaly_rate")]
8975 pub error_rate: f64,
8976
8977 #[serde(default = "default_process_anomaly_rate")]
8979 pub process_rate: f64,
8980}
8981
8982fn default_total_anomaly_rate() -> f64 {
8983 0.03
8984}
8985fn default_fraud_anomaly_rate() -> f64 {
8986 0.01
8987}
8988fn default_error_anomaly_rate() -> f64 {
8989 0.015
8990}
8991fn default_process_anomaly_rate() -> f64 {
8992 0.005
8993}
8994
8995impl Default for AnomalyRateConfig {
8996 fn default() -> Self {
8997 Self {
8998 total_rate: default_total_anomaly_rate(),
8999 fraud_rate: default_fraud_anomaly_rate(),
9000 error_rate: default_error_anomaly_rate(),
9001 process_rate: default_process_anomaly_rate(),
9002 }
9003 }
9004}
9005
9006#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9008pub struct MultiStageSchemeConfig {
9009 #[serde(default)]
9011 pub enabled: bool,
9012
9013 #[serde(default)]
9015 pub embezzlement: EmbezzlementSchemeConfig,
9016
9017 #[serde(default)]
9019 pub revenue_manipulation: RevenueManipulationSchemeConfig,
9020
9021 #[serde(default)]
9023 pub kickback: KickbackSchemeConfig,
9024}
9025
9026#[derive(Debug, Clone, Serialize, Deserialize)]
9028pub struct EmbezzlementSchemeConfig {
9029 #[serde(default = "default_embezzlement_probability")]
9031 pub probability: f64,
9032
9033 #[serde(default)]
9035 pub testing_stage: SchemeStageConfig,
9036
9037 #[serde(default)]
9039 pub escalation_stage: SchemeStageConfig,
9040
9041 #[serde(default)]
9043 pub acceleration_stage: SchemeStageConfig,
9044
9045 #[serde(default)]
9047 pub desperation_stage: SchemeStageConfig,
9048}
9049
9050fn default_embezzlement_probability() -> f64 {
9051 0.02
9052}
9053
9054impl Default for EmbezzlementSchemeConfig {
9055 fn default() -> Self {
9056 Self {
9057 probability: default_embezzlement_probability(),
9058 testing_stage: SchemeStageConfig {
9059 duration_months: 2,
9060 amount_min: 100.0,
9061 amount_max: 500.0,
9062 transaction_count_min: 2,
9063 transaction_count_max: 5,
9064 difficulty: "hard".to_string(),
9065 },
9066 escalation_stage: SchemeStageConfig {
9067 duration_months: 6,
9068 amount_min: 500.0,
9069 amount_max: 2000.0,
9070 transaction_count_min: 3,
9071 transaction_count_max: 8,
9072 difficulty: "moderate".to_string(),
9073 },
9074 acceleration_stage: SchemeStageConfig {
9075 duration_months: 3,
9076 amount_min: 2000.0,
9077 amount_max: 10000.0,
9078 transaction_count_min: 5,
9079 transaction_count_max: 12,
9080 difficulty: "easy".to_string(),
9081 },
9082 desperation_stage: SchemeStageConfig {
9083 duration_months: 1,
9084 amount_min: 10000.0,
9085 amount_max: 50000.0,
9086 transaction_count_min: 3,
9087 transaction_count_max: 6,
9088 difficulty: "trivial".to_string(),
9089 },
9090 }
9091 }
9092}
9093
9094#[derive(Debug, Clone, Serialize, Deserialize)]
9096pub struct RevenueManipulationSchemeConfig {
9097 #[serde(default = "default_revenue_manipulation_probability")]
9099 pub probability: f64,
9100
9101 #[serde(default = "default_early_recognition_target")]
9103 pub early_recognition_target: f64,
9104
9105 #[serde(default = "default_expense_deferral_target")]
9107 pub expense_deferral_target: f64,
9108
9109 #[serde(default = "default_reserve_release_target")]
9111 pub reserve_release_target: f64,
9112
9113 #[serde(default = "default_channel_stuffing_target")]
9115 pub channel_stuffing_target: f64,
9116}
9117
9118fn default_revenue_manipulation_probability() -> f64 {
9119 0.01
9120}
9121fn default_early_recognition_target() -> f64 {
9122 0.02
9123}
9124fn default_expense_deferral_target() -> f64 {
9125 0.03
9126}
9127fn default_reserve_release_target() -> f64 {
9128 0.02
9129}
9130fn default_channel_stuffing_target() -> f64 {
9131 0.05
9132}
9133
9134impl Default for RevenueManipulationSchemeConfig {
9135 fn default() -> Self {
9136 Self {
9137 probability: default_revenue_manipulation_probability(),
9138 early_recognition_target: default_early_recognition_target(),
9139 expense_deferral_target: default_expense_deferral_target(),
9140 reserve_release_target: default_reserve_release_target(),
9141 channel_stuffing_target: default_channel_stuffing_target(),
9142 }
9143 }
9144}
9145
9146#[derive(Debug, Clone, Serialize, Deserialize)]
9148pub struct KickbackSchemeConfig {
9149 #[serde(default = "default_kickback_probability")]
9151 pub probability: f64,
9152
9153 #[serde(default = "default_kickback_inflation_min")]
9155 pub inflation_min: f64,
9156
9157 #[serde(default = "default_kickback_inflation_max")]
9159 pub inflation_max: f64,
9160
9161 #[serde(default = "default_kickback_percent")]
9163 pub kickback_percent: f64,
9164
9165 #[serde(default = "default_kickback_setup_months")]
9167 pub setup_months: u32,
9168
9169 #[serde(default = "default_kickback_operation_months")]
9171 pub operation_months: u32,
9172}
9173
9174fn default_kickback_probability() -> f64 {
9175 0.01
9176}
9177fn default_kickback_inflation_min() -> f64 {
9178 0.10
9179}
9180fn default_kickback_inflation_max() -> f64 {
9181 0.25
9182}
9183fn default_kickback_percent() -> f64 {
9184 0.50
9185}
9186fn default_kickback_setup_months() -> u32 {
9187 3
9188}
9189fn default_kickback_operation_months() -> u32 {
9190 12
9191}
9192
9193impl Default for KickbackSchemeConfig {
9194 fn default() -> Self {
9195 Self {
9196 probability: default_kickback_probability(),
9197 inflation_min: default_kickback_inflation_min(),
9198 inflation_max: default_kickback_inflation_max(),
9199 kickback_percent: default_kickback_percent(),
9200 setup_months: default_kickback_setup_months(),
9201 operation_months: default_kickback_operation_months(),
9202 }
9203 }
9204}
9205
9206#[derive(Debug, Clone, Serialize, Deserialize)]
9208pub struct SchemeStageConfig {
9209 pub duration_months: u32,
9211
9212 pub amount_min: f64,
9214
9215 pub amount_max: f64,
9217
9218 pub transaction_count_min: u32,
9220
9221 pub transaction_count_max: u32,
9223
9224 pub difficulty: String,
9226}
9227
9228impl Default for SchemeStageConfig {
9229 fn default() -> Self {
9230 Self {
9231 duration_months: 3,
9232 amount_min: 100.0,
9233 amount_max: 1000.0,
9234 transaction_count_min: 2,
9235 transaction_count_max: 10,
9236 difficulty: "moderate".to_string(),
9237 }
9238 }
9239}
9240
9241#[derive(Debug, Clone, Serialize, Deserialize)]
9243pub struct CorrelatedInjectionConfig {
9244 #[serde(default)]
9246 pub enabled: bool,
9247
9248 #[serde(default = "default_true_val")]
9250 pub fraud_concealment: bool,
9251
9252 #[serde(default = "default_true_val")]
9254 pub error_cascade: bool,
9255
9256 #[serde(default = "default_true_val")]
9258 pub temporal_clustering: bool,
9259
9260 #[serde(default)]
9262 pub temporal_clustering_config: TemporalClusteringConfig,
9263
9264 #[serde(default)]
9266 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
9267}
9268
9269impl Default for CorrelatedInjectionConfig {
9270 fn default() -> Self {
9271 Self {
9272 enabled: false,
9273 fraud_concealment: true,
9274 error_cascade: true,
9275 temporal_clustering: true,
9276 temporal_clustering_config: TemporalClusteringConfig::default(),
9277 co_occurrence_patterns: Vec::new(),
9278 }
9279 }
9280}
9281
9282#[derive(Debug, Clone, Serialize, Deserialize)]
9284pub struct TemporalClusteringConfig {
9285 #[serde(default = "default_period_end_multiplier")]
9287 pub period_end_multiplier: f64,
9288
9289 #[serde(default = "default_period_end_days")]
9291 pub period_end_days: u32,
9292
9293 #[serde(default = "default_quarter_end_multiplier")]
9295 pub quarter_end_multiplier: f64,
9296
9297 #[serde(default = "default_year_end_multiplier")]
9299 pub year_end_multiplier: f64,
9300}
9301
9302fn default_period_end_multiplier() -> f64 {
9303 2.5
9304}
9305fn default_period_end_days() -> u32 {
9306 5
9307}
9308fn default_quarter_end_multiplier() -> f64 {
9309 1.5
9310}
9311fn default_year_end_multiplier() -> f64 {
9312 2.0
9313}
9314
9315impl Default for TemporalClusteringConfig {
9316 fn default() -> Self {
9317 Self {
9318 period_end_multiplier: default_period_end_multiplier(),
9319 period_end_days: default_period_end_days(),
9320 quarter_end_multiplier: default_quarter_end_multiplier(),
9321 year_end_multiplier: default_year_end_multiplier(),
9322 }
9323 }
9324}
9325
9326#[derive(Debug, Clone, Serialize, Deserialize)]
9328pub struct CoOccurrencePatternConfig {
9329 pub name: String,
9331
9332 pub primary_type: String,
9334
9335 pub correlated: Vec<CorrelatedAnomalyConfig>,
9337}
9338
9339#[derive(Debug, Clone, Serialize, Deserialize)]
9341pub struct CorrelatedAnomalyConfig {
9342 pub anomaly_type: String,
9344
9345 pub probability: f64,
9347
9348 pub lag_days_min: i32,
9350
9351 pub lag_days_max: i32,
9353}
9354
9355#[derive(Debug, Clone, Serialize, Deserialize)]
9357pub struct NearMissConfig {
9358 #[serde(default)]
9360 pub enabled: bool,
9361
9362 #[serde(default = "default_near_miss_proportion")]
9364 pub proportion: f64,
9365
9366 #[serde(default = "default_true_val")]
9368 pub near_duplicate: bool,
9369
9370 #[serde(default)]
9372 pub near_duplicate_days: NearDuplicateDaysConfig,
9373
9374 #[serde(default = "default_true_val")]
9376 pub threshold_proximity: bool,
9377
9378 #[serde(default)]
9380 pub threshold_proximity_range: ThresholdProximityRangeConfig,
9381
9382 #[serde(default = "default_true_val")]
9384 pub unusual_legitimate: bool,
9385
9386 #[serde(default = "default_unusual_legitimate_types")]
9388 pub unusual_legitimate_types: Vec<String>,
9389
9390 #[serde(default = "default_true_val")]
9392 pub corrected_errors: bool,
9393
9394 #[serde(default)]
9396 pub corrected_error_lag: CorrectedErrorLagConfig,
9397}
9398
9399fn default_near_miss_proportion() -> f64 {
9400 0.30
9401}
9402
9403fn default_unusual_legitimate_types() -> Vec<String> {
9404 vec![
9405 "year_end_bonus".to_string(),
9406 "contract_prepayment".to_string(),
9407 "insurance_claim".to_string(),
9408 "settlement_payment".to_string(),
9409 ]
9410}
9411
9412impl Default for NearMissConfig {
9413 fn default() -> Self {
9414 Self {
9415 enabled: false,
9416 proportion: default_near_miss_proportion(),
9417 near_duplicate: true,
9418 near_duplicate_days: NearDuplicateDaysConfig::default(),
9419 threshold_proximity: true,
9420 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
9421 unusual_legitimate: true,
9422 unusual_legitimate_types: default_unusual_legitimate_types(),
9423 corrected_errors: true,
9424 corrected_error_lag: CorrectedErrorLagConfig::default(),
9425 }
9426 }
9427}
9428
9429#[derive(Debug, Clone, Serialize, Deserialize)]
9431pub struct NearDuplicateDaysConfig {
9432 #[serde(default = "default_near_duplicate_min")]
9434 pub min: u32,
9435
9436 #[serde(default = "default_near_duplicate_max")]
9438 pub max: u32,
9439}
9440
9441fn default_near_duplicate_min() -> u32 {
9442 1
9443}
9444fn default_near_duplicate_max() -> u32 {
9445 3
9446}
9447
9448impl Default for NearDuplicateDaysConfig {
9449 fn default() -> Self {
9450 Self {
9451 min: default_near_duplicate_min(),
9452 max: default_near_duplicate_max(),
9453 }
9454 }
9455}
9456
9457#[derive(Debug, Clone, Serialize, Deserialize)]
9459pub struct ThresholdProximityRangeConfig {
9460 #[serde(default = "default_threshold_proximity_min")]
9462 pub min: f64,
9463
9464 #[serde(default = "default_threshold_proximity_max")]
9466 pub max: f64,
9467}
9468
9469fn default_threshold_proximity_min() -> f64 {
9470 0.90
9471}
9472fn default_threshold_proximity_max() -> f64 {
9473 0.99
9474}
9475
9476impl Default for ThresholdProximityRangeConfig {
9477 fn default() -> Self {
9478 Self {
9479 min: default_threshold_proximity_min(),
9480 max: default_threshold_proximity_max(),
9481 }
9482 }
9483}
9484
9485#[derive(Debug, Clone, Serialize, Deserialize)]
9487pub struct CorrectedErrorLagConfig {
9488 #[serde(default = "default_corrected_error_lag_min")]
9490 pub min: u32,
9491
9492 #[serde(default = "default_corrected_error_lag_max")]
9494 pub max: u32,
9495}
9496
9497fn default_corrected_error_lag_min() -> u32 {
9498 1
9499}
9500fn default_corrected_error_lag_max() -> u32 {
9501 5
9502}
9503
9504impl Default for CorrectedErrorLagConfig {
9505 fn default() -> Self {
9506 Self {
9507 min: default_corrected_error_lag_min(),
9508 max: default_corrected_error_lag_max(),
9509 }
9510 }
9511}
9512
9513#[derive(Debug, Clone, Serialize, Deserialize)]
9515pub struct DifficultyClassificationConfig {
9516 #[serde(default)]
9518 pub enabled: bool,
9519
9520 #[serde(default)]
9522 pub target_distribution: DifficultyDistributionConfig,
9523}
9524
9525impl Default for DifficultyClassificationConfig {
9526 fn default() -> Self {
9527 Self {
9528 enabled: true,
9529 target_distribution: DifficultyDistributionConfig::default(),
9530 }
9531 }
9532}
9533
9534#[derive(Debug, Clone, Serialize, Deserialize)]
9536pub struct DifficultyDistributionConfig {
9537 #[serde(default = "default_difficulty_trivial")]
9539 pub trivial: f64,
9540
9541 #[serde(default = "default_difficulty_easy")]
9543 pub easy: f64,
9544
9545 #[serde(default = "default_difficulty_moderate")]
9547 pub moderate: f64,
9548
9549 #[serde(default = "default_difficulty_hard")]
9551 pub hard: f64,
9552
9553 #[serde(default = "default_difficulty_expert")]
9555 pub expert: f64,
9556}
9557
9558fn default_difficulty_trivial() -> f64 {
9559 0.15
9560}
9561fn default_difficulty_easy() -> f64 {
9562 0.25
9563}
9564fn default_difficulty_moderate() -> f64 {
9565 0.30
9566}
9567fn default_difficulty_hard() -> f64 {
9568 0.20
9569}
9570fn default_difficulty_expert() -> f64 {
9571 0.10
9572}
9573
9574impl Default for DifficultyDistributionConfig {
9575 fn default() -> Self {
9576 Self {
9577 trivial: default_difficulty_trivial(),
9578 easy: default_difficulty_easy(),
9579 moderate: default_difficulty_moderate(),
9580 hard: default_difficulty_hard(),
9581 expert: default_difficulty_expert(),
9582 }
9583 }
9584}
9585
9586#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9588pub struct ContextAwareConfig {
9589 #[serde(default)]
9591 pub enabled: bool,
9592
9593 #[serde(default)]
9595 pub vendor_rules: VendorAnomalyRulesConfig,
9596
9597 #[serde(default)]
9599 pub employee_rules: EmployeeAnomalyRulesConfig,
9600
9601 #[serde(default)]
9603 pub account_rules: AccountAnomalyRulesConfig,
9604
9605 #[serde(default)]
9607 pub behavioral_baseline: BehavioralBaselineConfig,
9608}
9609
9610#[derive(Debug, Clone, Serialize, Deserialize)]
9612pub struct VendorAnomalyRulesConfig {
9613 #[serde(default = "default_new_vendor_multiplier")]
9615 pub new_vendor_error_multiplier: f64,
9616
9617 #[serde(default = "default_new_vendor_threshold")]
9619 pub new_vendor_threshold_days: u32,
9620
9621 #[serde(default = "default_international_multiplier")]
9623 pub international_error_multiplier: f64,
9624
9625 #[serde(default = "default_strategic_vendor_types")]
9627 pub strategic_vendor_anomaly_types: Vec<String>,
9628}
9629
9630fn default_new_vendor_multiplier() -> f64 {
9631 2.5
9632}
9633fn default_new_vendor_threshold() -> u32 {
9634 90
9635}
9636fn default_international_multiplier() -> f64 {
9637 1.5
9638}
9639fn default_strategic_vendor_types() -> Vec<String> {
9640 vec![
9641 "pricing_dispute".to_string(),
9642 "contract_violation".to_string(),
9643 ]
9644}
9645
9646impl Default for VendorAnomalyRulesConfig {
9647 fn default() -> Self {
9648 Self {
9649 new_vendor_error_multiplier: default_new_vendor_multiplier(),
9650 new_vendor_threshold_days: default_new_vendor_threshold(),
9651 international_error_multiplier: default_international_multiplier(),
9652 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9653 }
9654 }
9655}
9656
9657#[derive(Debug, Clone, Serialize, Deserialize)]
9659pub struct EmployeeAnomalyRulesConfig {
9660 #[serde(default = "default_new_employee_rate")]
9662 pub new_employee_error_rate: f64,
9663
9664 #[serde(default = "default_new_employee_threshold")]
9666 pub new_employee_threshold_days: u32,
9667
9668 #[serde(default = "default_volume_fatigue_threshold")]
9670 pub volume_fatigue_threshold: u32,
9671
9672 #[serde(default = "default_coverage_multiplier")]
9674 pub coverage_error_multiplier: f64,
9675}
9676
9677fn default_new_employee_rate() -> f64 {
9678 0.05
9679}
9680fn default_new_employee_threshold() -> u32 {
9681 180
9682}
9683fn default_volume_fatigue_threshold() -> u32 {
9684 50
9685}
9686fn default_coverage_multiplier() -> f64 {
9687 1.8
9688}
9689
9690impl Default for EmployeeAnomalyRulesConfig {
9691 fn default() -> Self {
9692 Self {
9693 new_employee_error_rate: default_new_employee_rate(),
9694 new_employee_threshold_days: default_new_employee_threshold(),
9695 volume_fatigue_threshold: default_volume_fatigue_threshold(),
9696 coverage_error_multiplier: default_coverage_multiplier(),
9697 }
9698 }
9699}
9700
9701#[derive(Debug, Clone, Serialize, Deserialize)]
9703pub struct AccountAnomalyRulesConfig {
9704 #[serde(default = "default_high_risk_multiplier")]
9706 pub high_risk_account_multiplier: f64,
9707
9708 #[serde(default = "default_high_risk_accounts")]
9710 pub high_risk_accounts: Vec<String>,
9711
9712 #[serde(default = "default_suspense_multiplier")]
9714 pub suspense_account_multiplier: f64,
9715
9716 #[serde(default = "default_suspense_accounts")]
9718 pub suspense_accounts: Vec<String>,
9719
9720 #[serde(default = "default_intercompany_multiplier")]
9722 pub intercompany_account_multiplier: f64,
9723}
9724
9725fn default_high_risk_multiplier() -> f64 {
9726 2.0
9727}
9728fn default_high_risk_accounts() -> Vec<String> {
9729 vec![
9730 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
9734}
9735fn default_suspense_multiplier() -> f64 {
9736 3.0
9737}
9738fn default_suspense_accounts() -> Vec<String> {
9739 vec!["9999".to_string(), "9998".to_string()]
9740}
9741fn default_intercompany_multiplier() -> f64 {
9742 1.5
9743}
9744
9745impl Default for AccountAnomalyRulesConfig {
9746 fn default() -> Self {
9747 Self {
9748 high_risk_account_multiplier: default_high_risk_multiplier(),
9749 high_risk_accounts: default_high_risk_accounts(),
9750 suspense_account_multiplier: default_suspense_multiplier(),
9751 suspense_accounts: default_suspense_accounts(),
9752 intercompany_account_multiplier: default_intercompany_multiplier(),
9753 }
9754 }
9755}
9756
9757#[derive(Debug, Clone, Serialize, Deserialize)]
9759pub struct BehavioralBaselineConfig {
9760 #[serde(default)]
9762 pub enabled: bool,
9763
9764 #[serde(default = "default_baseline_period")]
9766 pub baseline_period_days: u32,
9767
9768 #[serde(default = "default_deviation_threshold")]
9770 pub deviation_threshold_std: f64,
9771
9772 #[serde(default = "default_frequency_deviation")]
9774 pub frequency_deviation_threshold: f64,
9775}
9776
9777fn default_baseline_period() -> u32 {
9778 90
9779}
9780fn default_deviation_threshold() -> f64 {
9781 3.0
9782}
9783fn default_frequency_deviation() -> f64 {
9784 2.0
9785}
9786
9787impl Default for BehavioralBaselineConfig {
9788 fn default() -> Self {
9789 Self {
9790 enabled: false,
9791 baseline_period_days: default_baseline_period(),
9792 deviation_threshold_std: default_deviation_threshold(),
9793 frequency_deviation_threshold: default_frequency_deviation(),
9794 }
9795 }
9796}
9797
9798#[derive(Debug, Clone, Serialize, Deserialize)]
9800pub struct EnhancedLabelingConfig {
9801 #[serde(default = "default_true_val")]
9803 pub severity_scoring: bool,
9804
9805 #[serde(default = "default_true_val")]
9807 pub difficulty_classification: bool,
9808
9809 #[serde(default)]
9811 pub materiality_thresholds: MaterialityThresholdsConfig,
9812}
9813
9814impl Default for EnhancedLabelingConfig {
9815 fn default() -> Self {
9816 Self {
9817 severity_scoring: true,
9818 difficulty_classification: true,
9819 materiality_thresholds: MaterialityThresholdsConfig::default(),
9820 }
9821 }
9822}
9823
9824#[derive(Debug, Clone, Serialize, Deserialize)]
9826pub struct MaterialityThresholdsConfig {
9827 #[serde(default = "default_materiality_trivial")]
9829 pub trivial: f64,
9830
9831 #[serde(default = "default_materiality_immaterial")]
9833 pub immaterial: f64,
9834
9835 #[serde(default = "default_materiality_material")]
9837 pub material: f64,
9838
9839 #[serde(default = "default_materiality_highly_material")]
9841 pub highly_material: f64,
9842}
9843
9844fn default_materiality_trivial() -> f64 {
9845 0.001
9846}
9847fn default_materiality_immaterial() -> f64 {
9848 0.01
9849}
9850fn default_materiality_material() -> f64 {
9851 0.05
9852}
9853fn default_materiality_highly_material() -> f64 {
9854 0.10
9855}
9856
9857impl Default for MaterialityThresholdsConfig {
9858 fn default() -> Self {
9859 Self {
9860 trivial: default_materiality_trivial(),
9861 immaterial: default_materiality_immaterial(),
9862 material: default_materiality_material(),
9863 highly_material: default_materiality_highly_material(),
9864 }
9865 }
9866}
9867
9868#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9880pub struct IndustrySpecificConfig {
9881 #[serde(default)]
9883 pub enabled: bool,
9884
9885 #[serde(default)]
9887 pub manufacturing: ManufacturingConfig,
9888
9889 #[serde(default)]
9891 pub retail: RetailConfig,
9892
9893 #[serde(default)]
9895 pub healthcare: HealthcareConfig,
9896
9897 #[serde(default)]
9899 pub technology: TechnologyConfig,
9900
9901 #[serde(default)]
9903 pub financial_services: FinancialServicesConfig,
9904
9905 #[serde(default)]
9907 pub professional_services: ProfessionalServicesConfig,
9908}
9909
9910#[derive(Debug, Clone, Serialize, Deserialize)]
9912pub struct ManufacturingConfig {
9913 #[serde(default)]
9915 pub enabled: bool,
9916
9917 #[serde(default = "default_bom_depth")]
9919 pub bom_depth: u32,
9920
9921 #[serde(default)]
9923 pub just_in_time: bool,
9924
9925 #[serde(default = "default_production_order_types")]
9927 pub production_order_types: Vec<String>,
9928
9929 #[serde(default)]
9931 pub quality_framework: Option<String>,
9932
9933 #[serde(default = "default_supplier_tiers")]
9935 pub supplier_tiers: u32,
9936
9937 #[serde(default = "default_cost_frequency")]
9939 pub standard_cost_frequency: String,
9940
9941 #[serde(default = "default_yield_rate")]
9943 pub target_yield_rate: f64,
9944
9945 #[serde(default = "default_scrap_threshold")]
9947 pub scrap_alert_threshold: f64,
9948
9949 #[serde(default)]
9951 pub anomaly_rates: ManufacturingAnomalyRates,
9952
9953 #[serde(default)]
9955 pub cost_accounting: ManufacturingCostAccountingConfig,
9956}
9957
9958#[derive(Debug, Clone, Serialize, Deserialize)]
9960pub struct ManufacturingCostAccountingConfig {
9961 #[serde(default = "default_true")]
9963 pub enabled: bool,
9964
9965 #[serde(default = "default_true")]
9967 pub variance_accounts_enabled: bool,
9968
9969 #[serde(default = "default_true")]
9971 pub warranty_provisions_enabled: bool,
9972
9973 #[serde(default = "default_warranty_defect_threshold")]
9975 pub warranty_defect_threshold: f64,
9976}
9977
9978fn default_warranty_defect_threshold() -> f64 {
9979 0.01
9980}
9981
9982impl Default for ManufacturingCostAccountingConfig {
9983 fn default() -> Self {
9984 Self {
9985 enabled: true,
9986 variance_accounts_enabled: true,
9987 warranty_provisions_enabled: true,
9988 warranty_defect_threshold: 0.01,
9989 }
9990 }
9991}
9992
9993fn default_bom_depth() -> u32 {
9994 4
9995}
9996
9997fn default_production_order_types() -> Vec<String> {
9998 vec![
9999 "standard".to_string(),
10000 "rework".to_string(),
10001 "prototype".to_string(),
10002 ]
10003}
10004
10005fn default_supplier_tiers() -> u32 {
10006 2
10007}
10008
10009fn default_cost_frequency() -> String {
10010 "quarterly".to_string()
10011}
10012
10013fn default_yield_rate() -> f64 {
10014 0.97
10015}
10016
10017fn default_scrap_threshold() -> f64 {
10018 0.03
10019}
10020
10021impl Default for ManufacturingConfig {
10022 fn default() -> Self {
10023 Self {
10024 enabled: false,
10025 bom_depth: default_bom_depth(),
10026 just_in_time: false,
10027 production_order_types: default_production_order_types(),
10028 quality_framework: Some("ISO_9001".to_string()),
10029 supplier_tiers: default_supplier_tiers(),
10030 standard_cost_frequency: default_cost_frequency(),
10031 target_yield_rate: default_yield_rate(),
10032 scrap_alert_threshold: default_scrap_threshold(),
10033 anomaly_rates: ManufacturingAnomalyRates::default(),
10034 cost_accounting: ManufacturingCostAccountingConfig::default(),
10035 }
10036 }
10037}
10038
10039#[derive(Debug, Clone, Serialize, Deserialize)]
10041pub struct ManufacturingAnomalyRates {
10042 #[serde(default = "default_mfg_yield_rate")]
10044 pub yield_manipulation: f64,
10045
10046 #[serde(default = "default_mfg_labor_rate")]
10048 pub labor_misallocation: f64,
10049
10050 #[serde(default = "default_mfg_phantom_rate")]
10052 pub phantom_production: f64,
10053
10054 #[serde(default = "default_mfg_cost_rate")]
10056 pub standard_cost_manipulation: f64,
10057
10058 #[serde(default = "default_mfg_inventory_rate")]
10060 pub inventory_fraud: f64,
10061}
10062
10063fn default_mfg_yield_rate() -> f64 {
10064 0.015
10065}
10066
10067fn default_mfg_labor_rate() -> f64 {
10068 0.02
10069}
10070
10071fn default_mfg_phantom_rate() -> f64 {
10072 0.005
10073}
10074
10075fn default_mfg_cost_rate() -> f64 {
10076 0.01
10077}
10078
10079fn default_mfg_inventory_rate() -> f64 {
10080 0.008
10081}
10082
10083impl Default for ManufacturingAnomalyRates {
10084 fn default() -> Self {
10085 Self {
10086 yield_manipulation: default_mfg_yield_rate(),
10087 labor_misallocation: default_mfg_labor_rate(),
10088 phantom_production: default_mfg_phantom_rate(),
10089 standard_cost_manipulation: default_mfg_cost_rate(),
10090 inventory_fraud: default_mfg_inventory_rate(),
10091 }
10092 }
10093}
10094
10095#[derive(Debug, Clone, Serialize, Deserialize)]
10097pub struct RetailConfig {
10098 #[serde(default)]
10100 pub enabled: bool,
10101
10102 #[serde(default)]
10104 pub store_types: RetailStoreTypeConfig,
10105
10106 #[serde(default = "default_retail_daily_txns")]
10108 pub avg_daily_transactions: u32,
10109
10110 #[serde(default = "default_true")]
10112 pub loss_prevention: bool,
10113
10114 #[serde(default = "default_shrinkage_rate")]
10116 pub shrinkage_rate: f64,
10117
10118 #[serde(default)]
10120 pub anomaly_rates: RetailAnomalyRates,
10121}
10122
10123fn default_retail_daily_txns() -> u32 {
10124 500
10125}
10126
10127fn default_shrinkage_rate() -> f64 {
10128 0.015
10129}
10130
10131impl Default for RetailConfig {
10132 fn default() -> Self {
10133 Self {
10134 enabled: false,
10135 store_types: RetailStoreTypeConfig::default(),
10136 avg_daily_transactions: default_retail_daily_txns(),
10137 loss_prevention: true,
10138 shrinkage_rate: default_shrinkage_rate(),
10139 anomaly_rates: RetailAnomalyRates::default(),
10140 }
10141 }
10142}
10143
10144#[derive(Debug, Clone, Serialize, Deserialize)]
10146pub struct RetailStoreTypeConfig {
10147 #[serde(default = "default_flagship_pct")]
10149 pub flagship: f64,
10150
10151 #[serde(default = "default_regional_pct")]
10153 pub regional: f64,
10154
10155 #[serde(default = "default_outlet_pct")]
10157 pub outlet: f64,
10158
10159 #[serde(default = "default_ecommerce_pct")]
10161 pub ecommerce: f64,
10162}
10163
10164fn default_flagship_pct() -> f64 {
10165 0.10
10166}
10167
10168fn default_regional_pct() -> f64 {
10169 0.50
10170}
10171
10172fn default_outlet_pct() -> f64 {
10173 0.25
10174}
10175
10176fn default_ecommerce_pct() -> f64 {
10177 0.15
10178}
10179
10180impl Default for RetailStoreTypeConfig {
10181 fn default() -> Self {
10182 Self {
10183 flagship: default_flagship_pct(),
10184 regional: default_regional_pct(),
10185 outlet: default_outlet_pct(),
10186 ecommerce: default_ecommerce_pct(),
10187 }
10188 }
10189}
10190
10191#[derive(Debug, Clone, Serialize, Deserialize)]
10193pub struct RetailAnomalyRates {
10194 #[serde(default = "default_sweethearting_rate")]
10196 pub sweethearting: f64,
10197
10198 #[serde(default = "default_skimming_rate")]
10200 pub skimming: f64,
10201
10202 #[serde(default = "default_refund_fraud_rate")]
10204 pub refund_fraud: f64,
10205
10206 #[serde(default = "default_void_abuse_rate")]
10208 pub void_abuse: f64,
10209
10210 #[serde(default = "default_gift_card_rate")]
10212 pub gift_card_fraud: f64,
10213
10214 #[serde(default = "default_retail_kickback_rate")]
10216 pub vendor_kickback: f64,
10217}
10218
10219fn default_sweethearting_rate() -> f64 {
10220 0.02
10221}
10222
10223fn default_skimming_rate() -> f64 {
10224 0.005
10225}
10226
10227fn default_refund_fraud_rate() -> f64 {
10228 0.015
10229}
10230
10231fn default_void_abuse_rate() -> f64 {
10232 0.01
10233}
10234
10235fn default_gift_card_rate() -> f64 {
10236 0.008
10237}
10238
10239fn default_retail_kickback_rate() -> f64 {
10240 0.003
10241}
10242
10243impl Default for RetailAnomalyRates {
10244 fn default() -> Self {
10245 Self {
10246 sweethearting: default_sweethearting_rate(),
10247 skimming: default_skimming_rate(),
10248 refund_fraud: default_refund_fraud_rate(),
10249 void_abuse: default_void_abuse_rate(),
10250 gift_card_fraud: default_gift_card_rate(),
10251 vendor_kickback: default_retail_kickback_rate(),
10252 }
10253 }
10254}
10255
10256#[derive(Debug, Clone, Serialize, Deserialize)]
10258pub struct HealthcareConfig {
10259 #[serde(default)]
10261 pub enabled: bool,
10262
10263 #[serde(default = "default_facility_type")]
10265 pub facility_type: String,
10266
10267 #[serde(default)]
10269 pub payer_mix: HealthcarePayerMix,
10270
10271 #[serde(default)]
10273 pub coding_systems: HealthcareCodingSystems,
10274
10275 #[serde(default)]
10277 pub compliance: HealthcareComplianceConfig,
10278
10279 #[serde(default = "default_daily_encounters")]
10281 pub avg_daily_encounters: u32,
10282
10283 #[serde(default = "default_charges_per_encounter")]
10285 pub avg_charges_per_encounter: u32,
10286
10287 #[serde(default = "default_hc_denial_rate")]
10289 pub denial_rate: f64,
10290
10291 #[serde(default = "default_hc_bad_debt_rate")]
10293 pub bad_debt_rate: f64,
10294
10295 #[serde(default = "default_hc_charity_care_rate")]
10297 pub charity_care_rate: f64,
10298
10299 #[serde(default)]
10301 pub anomaly_rates: HealthcareAnomalyRates,
10302}
10303
10304fn default_facility_type() -> String {
10305 "hospital".to_string()
10306}
10307
10308fn default_daily_encounters() -> u32 {
10309 150
10310}
10311
10312fn default_charges_per_encounter() -> u32 {
10313 8
10314}
10315
10316fn default_hc_denial_rate() -> f64 {
10317 0.05
10318}
10319
10320fn default_hc_bad_debt_rate() -> f64 {
10321 0.03
10322}
10323
10324fn default_hc_charity_care_rate() -> f64 {
10325 0.02
10326}
10327
10328impl Default for HealthcareConfig {
10329 fn default() -> Self {
10330 Self {
10331 enabled: false,
10332 facility_type: default_facility_type(),
10333 payer_mix: HealthcarePayerMix::default(),
10334 coding_systems: HealthcareCodingSystems::default(),
10335 compliance: HealthcareComplianceConfig::default(),
10336 avg_daily_encounters: default_daily_encounters(),
10337 avg_charges_per_encounter: default_charges_per_encounter(),
10338 denial_rate: default_hc_denial_rate(),
10339 bad_debt_rate: default_hc_bad_debt_rate(),
10340 charity_care_rate: default_hc_charity_care_rate(),
10341 anomaly_rates: HealthcareAnomalyRates::default(),
10342 }
10343 }
10344}
10345
10346#[derive(Debug, Clone, Serialize, Deserialize)]
10348pub struct HealthcarePayerMix {
10349 #[serde(default = "default_medicare_pct")]
10351 pub medicare: f64,
10352
10353 #[serde(default = "default_medicaid_pct")]
10355 pub medicaid: f64,
10356
10357 #[serde(default = "default_commercial_pct")]
10359 pub commercial: f64,
10360
10361 #[serde(default = "default_self_pay_pct")]
10363 pub self_pay: f64,
10364}
10365
10366fn default_medicare_pct() -> f64 {
10367 0.40
10368}
10369
10370fn default_medicaid_pct() -> f64 {
10371 0.20
10372}
10373
10374fn default_commercial_pct() -> f64 {
10375 0.30
10376}
10377
10378fn default_self_pay_pct() -> f64 {
10379 0.10
10380}
10381
10382impl Default for HealthcarePayerMix {
10383 fn default() -> Self {
10384 Self {
10385 medicare: default_medicare_pct(),
10386 medicaid: default_medicaid_pct(),
10387 commercial: default_commercial_pct(),
10388 self_pay: default_self_pay_pct(),
10389 }
10390 }
10391}
10392
10393#[derive(Debug, Clone, Serialize, Deserialize)]
10395pub struct HealthcareCodingSystems {
10396 #[serde(default = "default_true")]
10398 pub icd10: bool,
10399
10400 #[serde(default = "default_true")]
10402 pub cpt: bool,
10403
10404 #[serde(default = "default_true")]
10406 pub drg: bool,
10407
10408 #[serde(default = "default_true")]
10410 pub hcpcs: bool,
10411
10412 #[serde(default = "default_true")]
10414 pub revenue_codes: bool,
10415}
10416
10417impl Default for HealthcareCodingSystems {
10418 fn default() -> Self {
10419 Self {
10420 icd10: true,
10421 cpt: true,
10422 drg: true,
10423 hcpcs: true,
10424 revenue_codes: true,
10425 }
10426 }
10427}
10428
10429#[derive(Debug, Clone, Serialize, Deserialize)]
10431pub struct HealthcareComplianceConfig {
10432 #[serde(default = "default_true")]
10434 pub hipaa: bool,
10435
10436 #[serde(default = "default_true")]
10438 pub stark_law: bool,
10439
10440 #[serde(default = "default_true")]
10442 pub anti_kickback: bool,
10443
10444 #[serde(default = "default_true")]
10446 pub false_claims_act: bool,
10447
10448 #[serde(default = "default_true")]
10450 pub emtala: bool,
10451}
10452
10453impl Default for HealthcareComplianceConfig {
10454 fn default() -> Self {
10455 Self {
10456 hipaa: true,
10457 stark_law: true,
10458 anti_kickback: true,
10459 false_claims_act: true,
10460 emtala: true,
10461 }
10462 }
10463}
10464
10465#[derive(Debug, Clone, Serialize, Deserialize)]
10467pub struct HealthcareAnomalyRates {
10468 #[serde(default = "default_upcoding_rate")]
10470 pub upcoding: f64,
10471
10472 #[serde(default = "default_unbundling_rate")]
10474 pub unbundling: f64,
10475
10476 #[serde(default = "default_phantom_billing_rate")]
10478 pub phantom_billing: f64,
10479
10480 #[serde(default = "default_healthcare_kickback_rate")]
10482 pub kickbacks: f64,
10483
10484 #[serde(default = "default_duplicate_billing_rate")]
10486 pub duplicate_billing: f64,
10487
10488 #[serde(default = "default_med_necessity_rate")]
10490 pub medical_necessity_abuse: f64,
10491}
10492
10493fn default_upcoding_rate() -> f64 {
10494 0.02
10495}
10496
10497fn default_unbundling_rate() -> f64 {
10498 0.015
10499}
10500
10501fn default_phantom_billing_rate() -> f64 {
10502 0.005
10503}
10504
10505fn default_healthcare_kickback_rate() -> f64 {
10506 0.003
10507}
10508
10509fn default_duplicate_billing_rate() -> f64 {
10510 0.008
10511}
10512
10513fn default_med_necessity_rate() -> f64 {
10514 0.01
10515}
10516
10517impl Default for HealthcareAnomalyRates {
10518 fn default() -> Self {
10519 Self {
10520 upcoding: default_upcoding_rate(),
10521 unbundling: default_unbundling_rate(),
10522 phantom_billing: default_phantom_billing_rate(),
10523 kickbacks: default_healthcare_kickback_rate(),
10524 duplicate_billing: default_duplicate_billing_rate(),
10525 medical_necessity_abuse: default_med_necessity_rate(),
10526 }
10527 }
10528}
10529
10530#[derive(Debug, Clone, Serialize, Deserialize)]
10532pub struct TechnologyConfig {
10533 #[serde(default)]
10535 pub enabled: bool,
10536
10537 #[serde(default = "default_revenue_model")]
10539 pub revenue_model: String,
10540
10541 #[serde(default = "default_subscription_pct")]
10543 pub subscription_revenue_pct: f64,
10544
10545 #[serde(default = "default_license_pct")]
10547 pub license_revenue_pct: f64,
10548
10549 #[serde(default = "default_services_pct")]
10551 pub services_revenue_pct: f64,
10552
10553 #[serde(default)]
10555 pub rd_capitalization: RdCapitalizationConfig,
10556
10557 #[serde(default)]
10559 pub anomaly_rates: TechnologyAnomalyRates,
10560}
10561
10562fn default_revenue_model() -> String {
10563 "saas".to_string()
10564}
10565
10566fn default_subscription_pct() -> f64 {
10567 0.60
10568}
10569
10570fn default_license_pct() -> f64 {
10571 0.25
10572}
10573
10574fn default_services_pct() -> f64 {
10575 0.15
10576}
10577
10578impl Default for TechnologyConfig {
10579 fn default() -> Self {
10580 Self {
10581 enabled: false,
10582 revenue_model: default_revenue_model(),
10583 subscription_revenue_pct: default_subscription_pct(),
10584 license_revenue_pct: default_license_pct(),
10585 services_revenue_pct: default_services_pct(),
10586 rd_capitalization: RdCapitalizationConfig::default(),
10587 anomaly_rates: TechnologyAnomalyRates::default(),
10588 }
10589 }
10590}
10591
10592#[derive(Debug, Clone, Serialize, Deserialize)]
10594pub struct RdCapitalizationConfig {
10595 #[serde(default = "default_true")]
10597 pub enabled: bool,
10598
10599 #[serde(default = "default_cap_rate")]
10601 pub capitalization_rate: f64,
10602
10603 #[serde(default = "default_useful_life")]
10605 pub useful_life_years: u32,
10606}
10607
10608fn default_cap_rate() -> f64 {
10609 0.30
10610}
10611
10612fn default_useful_life() -> u32 {
10613 3
10614}
10615
10616impl Default for RdCapitalizationConfig {
10617 fn default() -> Self {
10618 Self {
10619 enabled: true,
10620 capitalization_rate: default_cap_rate(),
10621 useful_life_years: default_useful_life(),
10622 }
10623 }
10624}
10625
10626#[derive(Debug, Clone, Serialize, Deserialize)]
10628pub struct TechnologyAnomalyRates {
10629 #[serde(default = "default_premature_rev_rate")]
10631 pub premature_revenue: f64,
10632
10633 #[serde(default = "default_side_letter_rate")]
10635 pub side_letter_abuse: f64,
10636
10637 #[serde(default = "default_channel_stuffing_rate")]
10639 pub channel_stuffing: f64,
10640
10641 #[serde(default = "default_improper_cap_rate")]
10643 pub improper_capitalization: f64,
10644}
10645
10646fn default_premature_rev_rate() -> f64 {
10647 0.015
10648}
10649
10650fn default_side_letter_rate() -> f64 {
10651 0.008
10652}
10653
10654fn default_channel_stuffing_rate() -> f64 {
10655 0.01
10656}
10657
10658fn default_improper_cap_rate() -> f64 {
10659 0.012
10660}
10661
10662impl Default for TechnologyAnomalyRates {
10663 fn default() -> Self {
10664 Self {
10665 premature_revenue: default_premature_rev_rate(),
10666 side_letter_abuse: default_side_letter_rate(),
10667 channel_stuffing: default_channel_stuffing_rate(),
10668 improper_capitalization: default_improper_cap_rate(),
10669 }
10670 }
10671}
10672
10673#[derive(Debug, Clone, Serialize, Deserialize)]
10675pub struct FinancialServicesConfig {
10676 #[serde(default)]
10678 pub enabled: bool,
10679
10680 #[serde(default = "default_fi_type")]
10682 pub institution_type: String,
10683
10684 #[serde(default = "default_fi_regulatory")]
10686 pub regulatory_framework: String,
10687
10688 #[serde(default)]
10690 pub anomaly_rates: FinancialServicesAnomalyRates,
10691}
10692
10693fn default_fi_type() -> String {
10694 "commercial_bank".to_string()
10695}
10696
10697fn default_fi_regulatory() -> String {
10698 "us_banking".to_string()
10699}
10700
10701impl Default for FinancialServicesConfig {
10702 fn default() -> Self {
10703 Self {
10704 enabled: false,
10705 institution_type: default_fi_type(),
10706 regulatory_framework: default_fi_regulatory(),
10707 anomaly_rates: FinancialServicesAnomalyRates::default(),
10708 }
10709 }
10710}
10711
10712#[derive(Debug, Clone, Serialize, Deserialize)]
10714pub struct FinancialServicesAnomalyRates {
10715 #[serde(default = "default_loan_fraud_rate")]
10717 pub loan_fraud: f64,
10718
10719 #[serde(default = "default_trading_fraud_rate")]
10721 pub trading_fraud: f64,
10722
10723 #[serde(default = "default_insurance_fraud_rate")]
10725 pub insurance_fraud: f64,
10726
10727 #[serde(default = "default_account_manip_rate")]
10729 pub account_manipulation: f64,
10730}
10731
10732fn default_loan_fraud_rate() -> f64 {
10733 0.01
10734}
10735
10736fn default_trading_fraud_rate() -> f64 {
10737 0.008
10738}
10739
10740fn default_insurance_fraud_rate() -> f64 {
10741 0.012
10742}
10743
10744fn default_account_manip_rate() -> f64 {
10745 0.005
10746}
10747
10748impl Default for FinancialServicesAnomalyRates {
10749 fn default() -> Self {
10750 Self {
10751 loan_fraud: default_loan_fraud_rate(),
10752 trading_fraud: default_trading_fraud_rate(),
10753 insurance_fraud: default_insurance_fraud_rate(),
10754 account_manipulation: default_account_manip_rate(),
10755 }
10756 }
10757}
10758
10759#[derive(Debug, Clone, Serialize, Deserialize)]
10761pub struct ProfessionalServicesConfig {
10762 #[serde(default)]
10764 pub enabled: bool,
10765
10766 #[serde(default = "default_firm_type")]
10768 pub firm_type: String,
10769
10770 #[serde(default = "default_billing_model")]
10772 pub billing_model: String,
10773
10774 #[serde(default = "default_hourly_rate")]
10776 pub avg_hourly_rate: f64,
10777
10778 #[serde(default)]
10780 pub trust_accounting: TrustAccountingConfig,
10781
10782 #[serde(default)]
10784 pub anomaly_rates: ProfessionalServicesAnomalyRates,
10785}
10786
10787fn default_firm_type() -> String {
10788 "consulting".to_string()
10789}
10790
10791fn default_billing_model() -> String {
10792 "time_and_materials".to_string()
10793}
10794
10795fn default_hourly_rate() -> f64 {
10796 250.0
10797}
10798
10799impl Default for ProfessionalServicesConfig {
10800 fn default() -> Self {
10801 Self {
10802 enabled: false,
10803 firm_type: default_firm_type(),
10804 billing_model: default_billing_model(),
10805 avg_hourly_rate: default_hourly_rate(),
10806 trust_accounting: TrustAccountingConfig::default(),
10807 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
10808 }
10809 }
10810}
10811
10812#[derive(Debug, Clone, Serialize, Deserialize)]
10814pub struct TrustAccountingConfig {
10815 #[serde(default)]
10817 pub enabled: bool,
10818
10819 #[serde(default = "default_true")]
10821 pub require_three_way_reconciliation: bool,
10822}
10823
10824impl Default for TrustAccountingConfig {
10825 fn default() -> Self {
10826 Self {
10827 enabled: false,
10828 require_three_way_reconciliation: true,
10829 }
10830 }
10831}
10832
10833#[derive(Debug, Clone, Serialize, Deserialize)]
10835pub struct ProfessionalServicesAnomalyRates {
10836 #[serde(default = "default_time_fraud_rate")]
10838 pub time_billing_fraud: f64,
10839
10840 #[serde(default = "default_expense_fraud_rate")]
10842 pub expense_fraud: f64,
10843
10844 #[serde(default = "default_trust_misappropriation_rate")]
10846 pub trust_misappropriation: f64,
10847}
10848
10849fn default_time_fraud_rate() -> f64 {
10850 0.02
10851}
10852
10853fn default_expense_fraud_rate() -> f64 {
10854 0.015
10855}
10856
10857fn default_trust_misappropriation_rate() -> f64 {
10858 0.003
10859}
10860
10861impl Default for ProfessionalServicesAnomalyRates {
10862 fn default() -> Self {
10863 Self {
10864 time_billing_fraud: default_time_fraud_rate(),
10865 expense_fraud: default_expense_fraud_rate(),
10866 trust_misappropriation: default_trust_misappropriation_rate(),
10867 }
10868 }
10869}
10870
10871#[derive(Debug, Clone, Serialize, Deserialize)]
10885pub struct FingerprintPrivacyConfig {
10886 #[serde(default)]
10888 pub level: String,
10889 #[serde(default = "default_epsilon")]
10891 pub epsilon: f64,
10892 #[serde(default = "default_delta")]
10894 pub delta: f64,
10895 #[serde(default = "default_k_anonymity")]
10897 pub k_anonymity: u32,
10898 #[serde(default)]
10900 pub composition_method: String,
10901}
10902
10903fn default_epsilon() -> f64 {
10904 1.0
10905}
10906
10907fn default_delta() -> f64 {
10908 1e-5
10909}
10910
10911fn default_k_anonymity() -> u32 {
10912 5
10913}
10914
10915impl Default for FingerprintPrivacyConfig {
10916 fn default() -> Self {
10917 Self {
10918 level: "standard".to_string(),
10919 epsilon: default_epsilon(),
10920 delta: default_delta(),
10921 k_anonymity: default_k_anonymity(),
10922 composition_method: "naive".to_string(),
10923 }
10924 }
10925}
10926
10927#[derive(Debug, Clone, Serialize, Deserialize)]
10941pub struct QualityGatesSchemaConfig {
10942 #[serde(default)]
10944 pub enabled: bool,
10945 #[serde(default = "default_gate_profile_name")]
10947 pub profile: String,
10948 #[serde(default)]
10950 pub fail_on_violation: bool,
10951 #[serde(default)]
10953 pub custom_gates: Vec<QualityGateEntry>,
10954}
10955
10956fn default_gate_profile_name() -> String {
10957 "default".to_string()
10958}
10959
10960impl Default for QualityGatesSchemaConfig {
10961 fn default() -> Self {
10962 Self {
10963 enabled: false,
10964 profile: default_gate_profile_name(),
10965 fail_on_violation: false,
10966 custom_gates: Vec::new(),
10967 }
10968 }
10969}
10970
10971#[derive(Debug, Clone, Serialize, Deserialize)]
10973pub struct QualityGateEntry {
10974 pub name: String,
10976 pub metric: String,
10980 pub threshold: f64,
10982 #[serde(default)]
10984 pub upper_threshold: Option<f64>,
10985 #[serde(default = "default_gate_comparison")]
10987 pub comparison: String,
10988}
10989
10990fn default_gate_comparison() -> String {
10991 "gte".to_string()
10992}
10993
10994#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11004pub struct ComplianceSchemaConfig {
11005 #[serde(default)]
11007 pub content_marking: ContentMarkingSchemaConfig,
11008 #[serde(default)]
11010 pub article10_report: bool,
11011 #[serde(default)]
11013 pub certificates: CertificateSchemaConfig,
11014}
11015
11016#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11018pub struct CertificateSchemaConfig {
11019 #[serde(default)]
11021 pub enabled: bool,
11022 #[serde(default)]
11024 pub signing_key_env: Option<String>,
11025 #[serde(default)]
11027 pub include_quality_metrics: bool,
11028}
11029
11030#[derive(Debug, Clone, Serialize, Deserialize)]
11032pub struct ContentMarkingSchemaConfig {
11033 #[serde(default = "default_true")]
11035 pub enabled: bool,
11036 #[serde(default = "default_marking_format")]
11038 pub format: String,
11039}
11040
11041fn default_marking_format() -> String {
11042 "embedded".to_string()
11043}
11044
11045impl Default for ContentMarkingSchemaConfig {
11046 fn default() -> Self {
11047 Self {
11048 enabled: true,
11049 format: default_marking_format(),
11050 }
11051 }
11052}
11053
11054#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11056pub struct WebhookSchemaConfig {
11057 #[serde(default)]
11059 pub enabled: bool,
11060 #[serde(default)]
11062 pub endpoints: Vec<WebhookEndpointConfig>,
11063}
11064
11065#[derive(Debug, Clone, Serialize, Deserialize)]
11067pub struct WebhookEndpointConfig {
11068 pub url: String,
11070 #[serde(default)]
11072 pub events: Vec<String>,
11073 #[serde(default)]
11075 pub secret: Option<String>,
11076 #[serde(default = "default_webhook_retries")]
11078 pub max_retries: u32,
11079 #[serde(default = "default_webhook_timeout")]
11081 pub timeout_secs: u64,
11082}
11083
11084fn default_webhook_retries() -> u32 {
11085 3
11086}
11087fn default_webhook_timeout() -> u64 {
11088 10
11089}
11090
11091#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11097pub struct SourceToPayConfig {
11098 #[serde(default)]
11100 pub enabled: bool,
11101 #[serde(default)]
11103 pub spend_analysis: SpendAnalysisConfig,
11104 #[serde(default)]
11106 pub sourcing: SourcingConfig,
11107 #[serde(default)]
11109 pub qualification: QualificationConfig,
11110 #[serde(default)]
11112 pub rfx: RfxConfig,
11113 #[serde(default)]
11115 pub contracts: ContractConfig,
11116 #[serde(default)]
11118 pub catalog: CatalogConfig,
11119 #[serde(default)]
11121 pub scorecards: ScorecardConfig,
11122 #[serde(default)]
11124 pub p2p_integration: P2PIntegrationConfig,
11125}
11126
11127#[derive(Debug, Clone, Serialize, Deserialize)]
11129pub struct SpendAnalysisConfig {
11130 #[serde(default = "default_hhi_threshold")]
11132 pub hhi_threshold: f64,
11133 #[serde(default = "default_contract_coverage_target")]
11135 pub contract_coverage_target: f64,
11136}
11137
11138impl Default for SpendAnalysisConfig {
11139 fn default() -> Self {
11140 Self {
11141 hhi_threshold: default_hhi_threshold(),
11142 contract_coverage_target: default_contract_coverage_target(),
11143 }
11144 }
11145}
11146
11147fn default_hhi_threshold() -> f64 {
11148 2500.0
11149}
11150fn default_contract_coverage_target() -> f64 {
11151 0.80
11152}
11153
11154#[derive(Debug, Clone, Serialize, Deserialize)]
11156pub struct SourcingConfig {
11157 #[serde(default = "default_sourcing_projects_per_year")]
11159 pub projects_per_year: u32,
11160 #[serde(default = "default_renewal_horizon_months")]
11162 pub renewal_horizon_months: u32,
11163 #[serde(default = "default_project_duration_months")]
11165 pub project_duration_months: u32,
11166}
11167
11168impl Default for SourcingConfig {
11169 fn default() -> Self {
11170 Self {
11171 projects_per_year: default_sourcing_projects_per_year(),
11172 renewal_horizon_months: default_renewal_horizon_months(),
11173 project_duration_months: default_project_duration_months(),
11174 }
11175 }
11176}
11177
11178fn default_sourcing_projects_per_year() -> u32 {
11179 10
11180}
11181fn default_renewal_horizon_months() -> u32 {
11182 3
11183}
11184fn default_project_duration_months() -> u32 {
11185 4
11186}
11187
11188#[derive(Debug, Clone, Serialize, Deserialize)]
11190pub struct QualificationConfig {
11191 #[serde(default = "default_qualification_pass_rate")]
11193 pub pass_rate: f64,
11194 #[serde(default = "default_qualification_validity_days")]
11196 pub validity_days: u32,
11197 #[serde(default = "default_financial_weight")]
11199 pub financial_weight: f64,
11200 #[serde(default = "default_quality_weight")]
11202 pub quality_weight: f64,
11203 #[serde(default = "default_delivery_weight")]
11205 pub delivery_weight: f64,
11206 #[serde(default = "default_compliance_weight")]
11208 pub compliance_weight: f64,
11209}
11210
11211impl Default for QualificationConfig {
11212 fn default() -> Self {
11213 Self {
11214 pass_rate: default_qualification_pass_rate(),
11215 validity_days: default_qualification_validity_days(),
11216 financial_weight: default_financial_weight(),
11217 quality_weight: default_quality_weight(),
11218 delivery_weight: default_delivery_weight(),
11219 compliance_weight: default_compliance_weight(),
11220 }
11221 }
11222}
11223
11224fn default_qualification_pass_rate() -> f64 {
11225 0.75
11226}
11227fn default_qualification_validity_days() -> u32 {
11228 365
11229}
11230fn default_financial_weight() -> f64 {
11231 0.25
11232}
11233fn default_quality_weight() -> f64 {
11234 0.30
11235}
11236fn default_delivery_weight() -> f64 {
11237 0.25
11238}
11239fn default_compliance_weight() -> f64 {
11240 0.20
11241}
11242
11243#[derive(Debug, Clone, Serialize, Deserialize)]
11245pub struct RfxConfig {
11246 #[serde(default = "default_rfi_threshold")]
11248 pub rfi_threshold: f64,
11249 #[serde(default = "default_min_invited_vendors")]
11251 pub min_invited_vendors: u32,
11252 #[serde(default = "default_max_invited_vendors")]
11254 pub max_invited_vendors: u32,
11255 #[serde(default = "default_response_rate")]
11257 pub response_rate: f64,
11258 #[serde(default = "default_price_weight")]
11260 pub default_price_weight: f64,
11261 #[serde(default = "default_rfx_quality_weight")]
11263 pub default_quality_weight: f64,
11264 #[serde(default = "default_rfx_delivery_weight")]
11266 pub default_delivery_weight: f64,
11267}
11268
11269impl Default for RfxConfig {
11270 fn default() -> Self {
11271 Self {
11272 rfi_threshold: default_rfi_threshold(),
11273 min_invited_vendors: default_min_invited_vendors(),
11274 max_invited_vendors: default_max_invited_vendors(),
11275 response_rate: default_response_rate(),
11276 default_price_weight: default_price_weight(),
11277 default_quality_weight: default_rfx_quality_weight(),
11278 default_delivery_weight: default_rfx_delivery_weight(),
11279 }
11280 }
11281}
11282
11283fn default_rfi_threshold() -> f64 {
11284 100_000.0
11285}
11286fn default_min_invited_vendors() -> u32 {
11287 3
11288}
11289fn default_max_invited_vendors() -> u32 {
11290 8
11291}
11292fn default_response_rate() -> f64 {
11293 0.70
11294}
11295fn default_price_weight() -> f64 {
11296 0.40
11297}
11298fn default_rfx_quality_weight() -> f64 {
11299 0.35
11300}
11301fn default_rfx_delivery_weight() -> f64 {
11302 0.25
11303}
11304
11305#[derive(Debug, Clone, Serialize, Deserialize)]
11307pub struct ContractConfig {
11308 #[serde(default = "default_min_contract_months")]
11310 pub min_duration_months: u32,
11311 #[serde(default = "default_max_contract_months")]
11313 pub max_duration_months: u32,
11314 #[serde(default = "default_auto_renewal_rate")]
11316 pub auto_renewal_rate: f64,
11317 #[serde(default = "default_amendment_rate")]
11319 pub amendment_rate: f64,
11320 #[serde(default)]
11322 pub type_distribution: ContractTypeDistribution,
11323}
11324
11325impl Default for ContractConfig {
11326 fn default() -> Self {
11327 Self {
11328 min_duration_months: default_min_contract_months(),
11329 max_duration_months: default_max_contract_months(),
11330 auto_renewal_rate: default_auto_renewal_rate(),
11331 amendment_rate: default_amendment_rate(),
11332 type_distribution: ContractTypeDistribution::default(),
11333 }
11334 }
11335}
11336
11337fn default_min_contract_months() -> u32 {
11338 12
11339}
11340fn default_max_contract_months() -> u32 {
11341 36
11342}
11343fn default_auto_renewal_rate() -> f64 {
11344 0.40
11345}
11346fn default_amendment_rate() -> f64 {
11347 0.20
11348}
11349
11350#[derive(Debug, Clone, Serialize, Deserialize)]
11352pub struct ContractTypeDistribution {
11353 #[serde(default = "default_fixed_price_pct")]
11355 pub fixed_price: f64,
11356 #[serde(default = "default_blanket_pct")]
11358 pub blanket: f64,
11359 #[serde(default = "default_time_materials_pct")]
11361 pub time_and_materials: f64,
11362 #[serde(default = "default_service_agreement_pct")]
11364 pub service_agreement: f64,
11365}
11366
11367impl Default for ContractTypeDistribution {
11368 fn default() -> Self {
11369 Self {
11370 fixed_price: default_fixed_price_pct(),
11371 blanket: default_blanket_pct(),
11372 time_and_materials: default_time_materials_pct(),
11373 service_agreement: default_service_agreement_pct(),
11374 }
11375 }
11376}
11377
11378fn default_fixed_price_pct() -> f64 {
11379 0.40
11380}
11381fn default_blanket_pct() -> f64 {
11382 0.30
11383}
11384fn default_time_materials_pct() -> f64 {
11385 0.15
11386}
11387fn default_service_agreement_pct() -> f64 {
11388 0.15
11389}
11390
11391#[derive(Debug, Clone, Serialize, Deserialize)]
11393pub struct CatalogConfig {
11394 #[serde(default = "default_preferred_vendor_flag_rate")]
11396 pub preferred_vendor_flag_rate: f64,
11397 #[serde(default = "default_multi_source_rate")]
11399 pub multi_source_rate: f64,
11400}
11401
11402impl Default for CatalogConfig {
11403 fn default() -> Self {
11404 Self {
11405 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
11406 multi_source_rate: default_multi_source_rate(),
11407 }
11408 }
11409}
11410
11411fn default_preferred_vendor_flag_rate() -> f64 {
11412 0.70
11413}
11414fn default_multi_source_rate() -> f64 {
11415 0.25
11416}
11417
11418#[derive(Debug, Clone, Serialize, Deserialize)]
11420pub struct ScorecardConfig {
11421 #[serde(default = "default_scorecard_frequency")]
11423 pub frequency: String,
11424 #[serde(default = "default_otd_weight")]
11426 pub on_time_delivery_weight: f64,
11427 #[serde(default = "default_quality_score_weight")]
11429 pub quality_weight: f64,
11430 #[serde(default = "default_price_score_weight")]
11432 pub price_weight: f64,
11433 #[serde(default = "default_responsiveness_weight")]
11435 pub responsiveness_weight: f64,
11436 #[serde(default = "default_grade_a_threshold")]
11438 pub grade_a_threshold: f64,
11439 #[serde(default = "default_grade_b_threshold")]
11441 pub grade_b_threshold: f64,
11442 #[serde(default = "default_grade_c_threshold")]
11444 pub grade_c_threshold: f64,
11445}
11446
11447impl Default for ScorecardConfig {
11448 fn default() -> Self {
11449 Self {
11450 frequency: default_scorecard_frequency(),
11451 on_time_delivery_weight: default_otd_weight(),
11452 quality_weight: default_quality_score_weight(),
11453 price_weight: default_price_score_weight(),
11454 responsiveness_weight: default_responsiveness_weight(),
11455 grade_a_threshold: default_grade_a_threshold(),
11456 grade_b_threshold: default_grade_b_threshold(),
11457 grade_c_threshold: default_grade_c_threshold(),
11458 }
11459 }
11460}
11461
11462fn default_scorecard_frequency() -> String {
11463 "quarterly".to_string()
11464}
11465fn default_otd_weight() -> f64 {
11466 0.30
11467}
11468fn default_quality_score_weight() -> f64 {
11469 0.30
11470}
11471fn default_price_score_weight() -> f64 {
11472 0.25
11473}
11474fn default_responsiveness_weight() -> f64 {
11475 0.15
11476}
11477fn default_grade_a_threshold() -> f64 {
11478 90.0
11479}
11480fn default_grade_b_threshold() -> f64 {
11481 75.0
11482}
11483fn default_grade_c_threshold() -> f64 {
11484 60.0
11485}
11486
11487#[derive(Debug, Clone, Serialize, Deserialize)]
11489pub struct P2PIntegrationConfig {
11490 #[serde(default = "default_off_contract_rate")]
11492 pub off_contract_rate: f64,
11493 #[serde(default = "default_price_tolerance")]
11495 pub price_tolerance: f64,
11496 #[serde(default)]
11498 pub catalog_enforcement: bool,
11499}
11500
11501impl Default for P2PIntegrationConfig {
11502 fn default() -> Self {
11503 Self {
11504 off_contract_rate: default_off_contract_rate(),
11505 price_tolerance: default_price_tolerance(),
11506 catalog_enforcement: false,
11507 }
11508 }
11509}
11510
11511fn default_off_contract_rate() -> f64 {
11512 0.15
11513}
11514fn default_price_tolerance() -> f64 {
11515 0.02
11516}
11517
11518#[derive(Debug, Clone, Serialize, Deserialize)]
11522pub struct FinancialReportingConfig {
11523 #[serde(default)]
11525 pub enabled: bool,
11526 #[serde(default = "default_true")]
11528 pub generate_balance_sheet: bool,
11529 #[serde(default = "default_true")]
11531 pub generate_income_statement: bool,
11532 #[serde(default = "default_true")]
11534 pub generate_cash_flow: bool,
11535 #[serde(default = "default_true")]
11537 pub generate_changes_in_equity: bool,
11538 #[serde(default = "default_comparative_periods")]
11540 pub comparative_periods: u32,
11541 #[serde(default)]
11543 pub management_kpis: ManagementKpisConfig,
11544 #[serde(default)]
11546 pub budgets: BudgetConfig,
11547}
11548
11549impl Default for FinancialReportingConfig {
11550 fn default() -> Self {
11551 Self {
11552 enabled: false,
11553 generate_balance_sheet: true,
11554 generate_income_statement: true,
11555 generate_cash_flow: true,
11556 generate_changes_in_equity: true,
11557 comparative_periods: default_comparative_periods(),
11558 management_kpis: ManagementKpisConfig::default(),
11559 budgets: BudgetConfig::default(),
11560 }
11561 }
11562}
11563
11564fn default_comparative_periods() -> u32 {
11565 1
11566}
11567
11568#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11570pub struct ManagementKpisConfig {
11571 #[serde(default)]
11573 pub enabled: bool,
11574 #[serde(default = "default_kpi_frequency")]
11576 pub frequency: String,
11577}
11578
11579fn default_kpi_frequency() -> String {
11580 "monthly".to_string()
11581}
11582
11583#[derive(Debug, Clone, Serialize, Deserialize)]
11585pub struct BudgetConfig {
11586 #[serde(default)]
11588 pub enabled: bool,
11589 #[serde(default = "default_revenue_growth_rate")]
11591 pub revenue_growth_rate: f64,
11592 #[serde(default = "default_expense_inflation_rate")]
11594 pub expense_inflation_rate: f64,
11595 #[serde(default = "default_variance_noise")]
11597 pub variance_noise: f64,
11598}
11599
11600impl Default for BudgetConfig {
11601 fn default() -> Self {
11602 Self {
11603 enabled: false,
11604 revenue_growth_rate: default_revenue_growth_rate(),
11605 expense_inflation_rate: default_expense_inflation_rate(),
11606 variance_noise: default_variance_noise(),
11607 }
11608 }
11609}
11610
11611fn default_revenue_growth_rate() -> f64 {
11612 0.05
11613}
11614fn default_expense_inflation_rate() -> f64 {
11615 0.03
11616}
11617fn default_variance_noise() -> f64 {
11618 0.10
11619}
11620
11621#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11625pub struct HrConfig {
11626 #[serde(default)]
11628 pub enabled: bool,
11629 #[serde(default)]
11631 pub payroll: PayrollConfig,
11632 #[serde(default)]
11634 pub time_attendance: TimeAttendanceConfig,
11635 #[serde(default)]
11637 pub expenses: ExpenseConfig,
11638}
11639
11640#[derive(Debug, Clone, Serialize, Deserialize)]
11642pub struct PayrollConfig {
11643 #[serde(default = "default_true")]
11645 pub enabled: bool,
11646 #[serde(default = "default_pay_frequency")]
11648 pub pay_frequency: String,
11649 #[serde(default)]
11651 pub salary_ranges: PayrollSalaryRanges,
11652 #[serde(default)]
11654 pub tax_rates: PayrollTaxRates,
11655 #[serde(default = "default_benefits_enrollment_rate")]
11657 pub benefits_enrollment_rate: f64,
11658 #[serde(default = "default_retirement_participation_rate")]
11660 pub retirement_participation_rate: f64,
11661}
11662
11663impl Default for PayrollConfig {
11664 fn default() -> Self {
11665 Self {
11666 enabled: true,
11667 pay_frequency: default_pay_frequency(),
11668 salary_ranges: PayrollSalaryRanges::default(),
11669 tax_rates: PayrollTaxRates::default(),
11670 benefits_enrollment_rate: default_benefits_enrollment_rate(),
11671 retirement_participation_rate: default_retirement_participation_rate(),
11672 }
11673 }
11674}
11675
11676fn default_pay_frequency() -> String {
11677 "monthly".to_string()
11678}
11679fn default_benefits_enrollment_rate() -> f64 {
11680 0.60
11681}
11682fn default_retirement_participation_rate() -> f64 {
11683 0.45
11684}
11685
11686#[derive(Debug, Clone, Serialize, Deserialize)]
11688pub struct PayrollSalaryRanges {
11689 #[serde(default = "default_staff_min")]
11691 pub staff_min: f64,
11692 #[serde(default = "default_staff_max")]
11693 pub staff_max: f64,
11694 #[serde(default = "default_manager_min")]
11696 pub manager_min: f64,
11697 #[serde(default = "default_manager_max")]
11698 pub manager_max: f64,
11699 #[serde(default = "default_director_min")]
11701 pub director_min: f64,
11702 #[serde(default = "default_director_max")]
11703 pub director_max: f64,
11704 #[serde(default = "default_executive_min")]
11706 pub executive_min: f64,
11707 #[serde(default = "default_executive_max")]
11708 pub executive_max: f64,
11709}
11710
11711impl Default for PayrollSalaryRanges {
11712 fn default() -> Self {
11713 Self {
11714 staff_min: default_staff_min(),
11715 staff_max: default_staff_max(),
11716 manager_min: default_manager_min(),
11717 manager_max: default_manager_max(),
11718 director_min: default_director_min(),
11719 director_max: default_director_max(),
11720 executive_min: default_executive_min(),
11721 executive_max: default_executive_max(),
11722 }
11723 }
11724}
11725
11726fn default_staff_min() -> f64 {
11727 50_000.0
11728}
11729fn default_staff_max() -> f64 {
11730 70_000.0
11731}
11732fn default_manager_min() -> f64 {
11733 80_000.0
11734}
11735fn default_manager_max() -> f64 {
11736 120_000.0
11737}
11738fn default_director_min() -> f64 {
11739 120_000.0
11740}
11741fn default_director_max() -> f64 {
11742 180_000.0
11743}
11744fn default_executive_min() -> f64 {
11745 180_000.0
11746}
11747fn default_executive_max() -> f64 {
11748 350_000.0
11749}
11750
11751#[derive(Debug, Clone, Serialize, Deserialize)]
11753pub struct PayrollTaxRates {
11754 #[serde(default = "default_federal_rate")]
11756 pub federal_effective: f64,
11757 #[serde(default = "default_state_rate")]
11759 pub state_effective: f64,
11760 #[serde(default = "default_fica_rate")]
11762 pub fica: f64,
11763}
11764
11765impl Default for PayrollTaxRates {
11766 fn default() -> Self {
11767 Self {
11768 federal_effective: default_federal_rate(),
11769 state_effective: default_state_rate(),
11770 fica: default_fica_rate(),
11771 }
11772 }
11773}
11774
11775fn default_federal_rate() -> f64 {
11776 0.22
11777}
11778fn default_state_rate() -> f64 {
11779 0.05
11780}
11781fn default_fica_rate() -> f64 {
11782 0.0765
11783}
11784
11785#[derive(Debug, Clone, Serialize, Deserialize)]
11787pub struct TimeAttendanceConfig {
11788 #[serde(default = "default_true")]
11790 pub enabled: bool,
11791 #[serde(default = "default_overtime_rate")]
11793 pub overtime_rate: f64,
11794}
11795
11796impl Default for TimeAttendanceConfig {
11797 fn default() -> Self {
11798 Self {
11799 enabled: true,
11800 overtime_rate: default_overtime_rate(),
11801 }
11802 }
11803}
11804
11805fn default_overtime_rate() -> f64 {
11806 0.10
11807}
11808
11809#[derive(Debug, Clone, Serialize, Deserialize)]
11811pub struct ExpenseConfig {
11812 #[serde(default = "default_true")]
11814 pub enabled: bool,
11815 #[serde(default = "default_expense_submission_rate")]
11817 pub submission_rate: f64,
11818 #[serde(default = "default_policy_violation_rate")]
11820 pub policy_violation_rate: f64,
11821}
11822
11823impl Default for ExpenseConfig {
11824 fn default() -> Self {
11825 Self {
11826 enabled: true,
11827 submission_rate: default_expense_submission_rate(),
11828 policy_violation_rate: default_policy_violation_rate(),
11829 }
11830 }
11831}
11832
11833fn default_expense_submission_rate() -> f64 {
11834 0.30
11835}
11836fn default_policy_violation_rate() -> f64 {
11837 0.08
11838}
11839
11840#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11844pub struct ManufacturingProcessConfig {
11845 #[serde(default)]
11847 pub enabled: bool,
11848 #[serde(default)]
11850 pub production_orders: ProductionOrderConfig,
11851 #[serde(default)]
11853 pub costing: ManufacturingCostingConfig,
11854 #[serde(default)]
11856 pub routing: RoutingConfig,
11857}
11858
11859#[derive(Debug, Clone, Serialize, Deserialize)]
11861pub struct ProductionOrderConfig {
11862 #[serde(default = "default_prod_orders_per_month")]
11864 pub orders_per_month: u32,
11865 #[serde(default = "default_prod_avg_batch_size")]
11867 pub avg_batch_size: u32,
11868 #[serde(default = "default_prod_yield_rate")]
11870 pub yield_rate: f64,
11871 #[serde(default = "default_prod_make_to_order_rate")]
11873 pub make_to_order_rate: f64,
11874 #[serde(default = "default_prod_rework_rate")]
11876 pub rework_rate: f64,
11877}
11878
11879impl Default for ProductionOrderConfig {
11880 fn default() -> Self {
11881 Self {
11882 orders_per_month: default_prod_orders_per_month(),
11883 avg_batch_size: default_prod_avg_batch_size(),
11884 yield_rate: default_prod_yield_rate(),
11885 make_to_order_rate: default_prod_make_to_order_rate(),
11886 rework_rate: default_prod_rework_rate(),
11887 }
11888 }
11889}
11890
11891fn default_prod_orders_per_month() -> u32 {
11892 50
11893}
11894fn default_prod_avg_batch_size() -> u32 {
11895 100
11896}
11897fn default_prod_yield_rate() -> f64 {
11898 0.97
11899}
11900fn default_prod_make_to_order_rate() -> f64 {
11901 0.20
11902}
11903fn default_prod_rework_rate() -> f64 {
11904 0.03
11905}
11906
11907#[derive(Debug, Clone, Serialize, Deserialize)]
11909pub struct ManufacturingCostingConfig {
11910 #[serde(default = "default_labor_rate")]
11912 pub labor_rate_per_hour: f64,
11913 #[serde(default = "default_overhead_rate")]
11915 pub overhead_rate: f64,
11916 #[serde(default = "default_cost_update_frequency")]
11918 pub standard_cost_update_frequency: String,
11919}
11920
11921impl Default for ManufacturingCostingConfig {
11922 fn default() -> Self {
11923 Self {
11924 labor_rate_per_hour: default_labor_rate(),
11925 overhead_rate: default_overhead_rate(),
11926 standard_cost_update_frequency: default_cost_update_frequency(),
11927 }
11928 }
11929}
11930
11931fn default_labor_rate() -> f64 {
11932 35.0
11933}
11934fn default_overhead_rate() -> f64 {
11935 1.50
11936}
11937fn default_cost_update_frequency() -> String {
11938 "quarterly".to_string()
11939}
11940
11941#[derive(Debug, Clone, Serialize, Deserialize)]
11943pub struct RoutingConfig {
11944 #[serde(default = "default_avg_operations")]
11946 pub avg_operations: u32,
11947 #[serde(default = "default_setup_time")]
11949 pub setup_time_hours: f64,
11950 #[serde(default = "default_run_time_variation")]
11952 pub run_time_variation: f64,
11953}
11954
11955impl Default for RoutingConfig {
11956 fn default() -> Self {
11957 Self {
11958 avg_operations: default_avg_operations(),
11959 setup_time_hours: default_setup_time(),
11960 run_time_variation: default_run_time_variation(),
11961 }
11962 }
11963}
11964
11965fn default_avg_operations() -> u32 {
11966 4
11967}
11968fn default_setup_time() -> f64 {
11969 1.5
11970}
11971fn default_run_time_variation() -> f64 {
11972 0.15
11973}
11974
11975#[derive(Debug, Clone, Serialize, Deserialize)]
11979pub struct SalesQuoteConfig {
11980 #[serde(default)]
11982 pub enabled: bool,
11983 #[serde(default = "default_quotes_per_month")]
11985 pub quotes_per_month: u32,
11986 #[serde(default = "default_quote_win_rate")]
11988 pub win_rate: f64,
11989 #[serde(default = "default_quote_validity_days")]
11991 pub validity_days: u32,
11992}
11993
11994impl Default for SalesQuoteConfig {
11995 fn default() -> Self {
11996 Self {
11997 enabled: false,
11998 quotes_per_month: default_quotes_per_month(),
11999 win_rate: default_quote_win_rate(),
12000 validity_days: default_quote_validity_days(),
12001 }
12002 }
12003}
12004
12005fn default_quotes_per_month() -> u32 {
12006 30
12007}
12008fn default_quote_win_rate() -> f64 {
12009 0.35
12010}
12011fn default_quote_validity_days() -> u32 {
12012 30
12013}
12014
12015#[derive(Debug, Clone, Serialize, Deserialize)]
12024pub struct TaxConfig {
12025 #[serde(default)]
12027 pub enabled: bool,
12028 #[serde(default)]
12030 pub jurisdictions: TaxJurisdictionConfig,
12031 #[serde(default)]
12033 pub vat_gst: VatGstConfig,
12034 #[serde(default)]
12036 pub sales_tax: SalesTaxConfig,
12037 #[serde(default)]
12039 pub withholding: WithholdingTaxSchemaConfig,
12040 #[serde(default)]
12042 pub provisions: TaxProvisionSchemaConfig,
12043 #[serde(default)]
12045 pub payroll_tax: PayrollTaxSchemaConfig,
12046 #[serde(default = "default_tax_anomaly_rate")]
12048 pub anomaly_rate: f64,
12049}
12050
12051fn default_tax_anomaly_rate() -> f64 {
12052 0.03
12053}
12054
12055impl Default for TaxConfig {
12056 fn default() -> Self {
12057 Self {
12058 enabled: false,
12059 jurisdictions: TaxJurisdictionConfig::default(),
12060 vat_gst: VatGstConfig::default(),
12061 sales_tax: SalesTaxConfig::default(),
12062 withholding: WithholdingTaxSchemaConfig::default(),
12063 provisions: TaxProvisionSchemaConfig::default(),
12064 payroll_tax: PayrollTaxSchemaConfig::default(),
12065 anomaly_rate: default_tax_anomaly_rate(),
12066 }
12067 }
12068}
12069
12070#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12075pub struct TaxJurisdictionConfig {
12076 #[serde(default)]
12078 pub countries: Vec<String>,
12079 #[serde(default)]
12081 pub include_subnational: bool,
12082}
12083
12084#[derive(Debug, Clone, Serialize, Deserialize)]
12089pub struct VatGstConfig {
12090 #[serde(default)]
12092 pub enabled: bool,
12093 #[serde(default)]
12095 pub standard_rates: std::collections::HashMap<String, f64>,
12096 #[serde(default)]
12098 pub reduced_rates: std::collections::HashMap<String, f64>,
12099 #[serde(default)]
12101 pub exempt_categories: Vec<String>,
12102 #[serde(default = "default_true")]
12104 pub reverse_charge: bool,
12105}
12106
12107impl Default for VatGstConfig {
12108 fn default() -> Self {
12109 Self {
12110 enabled: false,
12111 standard_rates: std::collections::HashMap::new(),
12112 reduced_rates: std::collections::HashMap::new(),
12113 exempt_categories: Vec::new(),
12114 reverse_charge: true,
12115 }
12116 }
12117}
12118
12119#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12123pub struct SalesTaxConfig {
12124 #[serde(default)]
12126 pub enabled: bool,
12127 #[serde(default)]
12129 pub nexus_states: Vec<String>,
12130}
12131
12132#[derive(Debug, Clone, Serialize, Deserialize)]
12137pub struct WithholdingTaxSchemaConfig {
12138 #[serde(default)]
12140 pub enabled: bool,
12141 #[serde(default = "default_true")]
12143 pub treaty_network: bool,
12144 #[serde(default = "default_withholding_rate")]
12146 pub default_rate: f64,
12147 #[serde(default = "default_treaty_reduced_rate")]
12149 pub treaty_reduced_rate: f64,
12150}
12151
12152fn default_withholding_rate() -> f64 {
12153 0.30
12154}
12155
12156fn default_treaty_reduced_rate() -> f64 {
12157 0.15
12158}
12159
12160impl Default for WithholdingTaxSchemaConfig {
12161 fn default() -> Self {
12162 Self {
12163 enabled: false,
12164 treaty_network: true,
12165 default_rate: default_withholding_rate(),
12166 treaty_reduced_rate: default_treaty_reduced_rate(),
12167 }
12168 }
12169}
12170
12171#[derive(Debug, Clone, Serialize, Deserialize)]
12176pub struct TaxProvisionSchemaConfig {
12177 #[serde(default = "default_true")]
12180 pub enabled: bool,
12181 #[serde(default = "default_statutory_rate")]
12183 pub statutory_rate: f64,
12184 #[serde(default = "default_true")]
12186 pub uncertain_positions: bool,
12187}
12188
12189fn default_statutory_rate() -> f64 {
12190 0.21
12191}
12192
12193impl Default for TaxProvisionSchemaConfig {
12194 fn default() -> Self {
12195 Self {
12196 enabled: true,
12197 statutory_rate: default_statutory_rate(),
12198 uncertain_positions: true,
12199 }
12200 }
12201}
12202
12203#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12208pub struct PayrollTaxSchemaConfig {
12209 #[serde(default)]
12211 pub enabled: bool,
12212}
12213
12214#[derive(Debug, Clone, Serialize, Deserialize)]
12224pub struct TreasuryConfig {
12225 #[serde(default)]
12227 pub enabled: bool,
12228 #[serde(default)]
12230 pub cash_positioning: CashPositioningConfig,
12231 #[serde(default)]
12233 pub cash_forecasting: CashForecastingConfig,
12234 #[serde(default)]
12236 pub cash_pooling: CashPoolingConfig,
12237 #[serde(default)]
12239 pub hedging: HedgingSchemaConfig,
12240 #[serde(default)]
12242 pub debt: DebtSchemaConfig,
12243 #[serde(default)]
12245 pub netting: NettingSchemaConfig,
12246 #[serde(default)]
12248 pub bank_guarantees: BankGuaranteeSchemaConfig,
12249 #[serde(default = "default_treasury_anomaly_rate")]
12251 pub anomaly_rate: f64,
12252}
12253
12254fn default_treasury_anomaly_rate() -> f64 {
12255 0.02
12256}
12257
12258impl Default for TreasuryConfig {
12259 fn default() -> Self {
12260 Self {
12261 enabled: false,
12262 cash_positioning: CashPositioningConfig::default(),
12263 cash_forecasting: CashForecastingConfig::default(),
12264 cash_pooling: CashPoolingConfig::default(),
12265 hedging: HedgingSchemaConfig::default(),
12266 debt: DebtSchemaConfig::default(),
12267 netting: NettingSchemaConfig::default(),
12268 bank_guarantees: BankGuaranteeSchemaConfig::default(),
12269 anomaly_rate: default_treasury_anomaly_rate(),
12270 }
12271 }
12272}
12273
12274#[derive(Debug, Clone, Serialize, Deserialize)]
12278pub struct CashPositioningConfig {
12279 #[serde(default = "default_true")]
12281 pub enabled: bool,
12282 #[serde(default = "default_cash_frequency")]
12284 pub frequency: String,
12285 #[serde(default = "default_minimum_balance_policy")]
12287 pub minimum_balance_policy: f64,
12288}
12289
12290fn default_cash_frequency() -> String {
12291 "daily".to_string()
12292}
12293
12294fn default_minimum_balance_policy() -> f64 {
12295 100_000.0
12296}
12297
12298impl Default for CashPositioningConfig {
12299 fn default() -> Self {
12300 Self {
12301 enabled: true,
12302 frequency: default_cash_frequency(),
12303 minimum_balance_policy: default_minimum_balance_policy(),
12304 }
12305 }
12306}
12307
12308#[derive(Debug, Clone, Serialize, Deserialize)]
12312pub struct CashForecastingConfig {
12313 #[serde(default = "default_true")]
12315 pub enabled: bool,
12316 #[serde(default = "default_horizon_days")]
12318 pub horizon_days: u32,
12319 #[serde(default = "default_ar_probability_curve")]
12321 pub ar_collection_probability_curve: String,
12322 #[serde(default = "default_confidence_interval")]
12324 pub confidence_interval: f64,
12325}
12326
12327fn default_horizon_days() -> u32 {
12328 90
12329}
12330
12331fn default_ar_probability_curve() -> String {
12332 "aging".to_string()
12333}
12334
12335fn default_confidence_interval() -> f64 {
12336 0.90
12337}
12338
12339impl Default for CashForecastingConfig {
12340 fn default() -> Self {
12341 Self {
12342 enabled: true,
12343 horizon_days: default_horizon_days(),
12344 ar_collection_probability_curve: default_ar_probability_curve(),
12345 confidence_interval: default_confidence_interval(),
12346 }
12347 }
12348}
12349
12350#[derive(Debug, Clone, Serialize, Deserialize)]
12354pub struct CashPoolingConfig {
12355 #[serde(default)]
12357 pub enabled: bool,
12358 #[serde(default = "default_pool_type")]
12360 pub pool_type: String,
12361 #[serde(default = "default_sweep_time")]
12363 pub sweep_time: String,
12364}
12365
12366fn default_pool_type() -> String {
12367 "zero_balancing".to_string()
12368}
12369
12370fn default_sweep_time() -> String {
12371 "16:00".to_string()
12372}
12373
12374impl Default for CashPoolingConfig {
12375 fn default() -> Self {
12376 Self {
12377 enabled: false,
12378 pool_type: default_pool_type(),
12379 sweep_time: default_sweep_time(),
12380 }
12381 }
12382}
12383
12384#[derive(Debug, Clone, Serialize, Deserialize)]
12389pub struct HedgingSchemaConfig {
12390 #[serde(default)]
12392 pub enabled: bool,
12393 #[serde(default = "default_hedge_ratio")]
12395 pub hedge_ratio: f64,
12396 #[serde(default = "default_hedge_instruments")]
12398 pub instruments: Vec<String>,
12399 #[serde(default = "default_true")]
12401 pub hedge_accounting: bool,
12402 #[serde(default = "default_effectiveness_method")]
12404 pub effectiveness_method: String,
12405}
12406
12407fn default_hedge_ratio() -> f64 {
12408 0.75
12409}
12410
12411fn default_hedge_instruments() -> Vec<String> {
12412 vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
12413}
12414
12415fn default_effectiveness_method() -> String {
12416 "regression".to_string()
12417}
12418
12419impl Default for HedgingSchemaConfig {
12420 fn default() -> Self {
12421 Self {
12422 enabled: false,
12423 hedge_ratio: default_hedge_ratio(),
12424 instruments: default_hedge_instruments(),
12425 hedge_accounting: true,
12426 effectiveness_method: default_effectiveness_method(),
12427 }
12428 }
12429}
12430
12431#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12436pub struct DebtSchemaConfig {
12437 #[serde(default)]
12439 pub enabled: bool,
12440 #[serde(default)]
12442 pub instruments: Vec<DebtInstrumentDef>,
12443 #[serde(default)]
12445 pub covenants: Vec<CovenantDef>,
12446}
12447
12448#[derive(Debug, Clone, Serialize, Deserialize)]
12450pub struct DebtInstrumentDef {
12451 #[serde(rename = "type")]
12453 pub instrument_type: String,
12454 #[serde(default)]
12456 pub principal: Option<f64>,
12457 #[serde(default)]
12459 pub rate: Option<f64>,
12460 #[serde(default)]
12462 pub maturity_months: Option<u32>,
12463 #[serde(default)]
12465 pub facility: Option<f64>,
12466}
12467
12468#[derive(Debug, Clone, Serialize, Deserialize)]
12470pub struct CovenantDef {
12471 #[serde(rename = "type")]
12474 pub covenant_type: String,
12475 pub threshold: f64,
12477}
12478
12479#[derive(Debug, Clone, Serialize, Deserialize)]
12483pub struct NettingSchemaConfig {
12484 #[serde(default)]
12486 pub enabled: bool,
12487 #[serde(default = "default_netting_cycle")]
12489 pub cycle: String,
12490}
12491
12492fn default_netting_cycle() -> String {
12493 "monthly".to_string()
12494}
12495
12496impl Default for NettingSchemaConfig {
12497 fn default() -> Self {
12498 Self {
12499 enabled: false,
12500 cycle: default_netting_cycle(),
12501 }
12502 }
12503}
12504
12505#[derive(Debug, Clone, Serialize, Deserialize)]
12509pub struct BankGuaranteeSchemaConfig {
12510 #[serde(default)]
12512 pub enabled: bool,
12513 #[serde(default = "default_guarantee_count")]
12515 pub count: u32,
12516}
12517
12518fn default_guarantee_count() -> u32 {
12519 5
12520}
12521
12522impl Default for BankGuaranteeSchemaConfig {
12523 fn default() -> Self {
12524 Self {
12525 enabled: false,
12526 count: default_guarantee_count(),
12527 }
12528 }
12529}
12530
12531#[derive(Debug, Clone, Serialize, Deserialize)]
12540pub struct ProjectAccountingConfig {
12541 #[serde(default)]
12543 pub enabled: bool,
12544 #[serde(default = "default_project_count")]
12546 pub project_count: u32,
12547 #[serde(default)]
12549 pub project_types: ProjectTypeDistribution,
12550 #[serde(default)]
12552 pub wbs: WbsSchemaConfig,
12553 #[serde(default)]
12555 pub cost_allocation: CostAllocationConfig,
12556 #[serde(default)]
12558 pub revenue_recognition: ProjectRevenueRecognitionConfig,
12559 #[serde(default)]
12561 pub milestones: MilestoneSchemaConfig,
12562 #[serde(default)]
12564 pub change_orders: ChangeOrderSchemaConfig,
12565 #[serde(default)]
12567 pub retainage: RetainageSchemaConfig,
12568 #[serde(default)]
12570 pub earned_value: EarnedValueSchemaConfig,
12571 #[serde(default = "default_project_anomaly_rate")]
12573 pub anomaly_rate: f64,
12574}
12575
12576fn default_project_count() -> u32 {
12577 10
12578}
12579
12580fn default_project_anomaly_rate() -> f64 {
12581 0.03
12582}
12583
12584impl Default for ProjectAccountingConfig {
12585 fn default() -> Self {
12586 Self {
12587 enabled: false,
12588 project_count: default_project_count(),
12589 project_types: ProjectTypeDistribution::default(),
12590 wbs: WbsSchemaConfig::default(),
12591 cost_allocation: CostAllocationConfig::default(),
12592 revenue_recognition: ProjectRevenueRecognitionConfig::default(),
12593 milestones: MilestoneSchemaConfig::default(),
12594 change_orders: ChangeOrderSchemaConfig::default(),
12595 retainage: RetainageSchemaConfig::default(),
12596 earned_value: EarnedValueSchemaConfig::default(),
12597 anomaly_rate: default_project_anomaly_rate(),
12598 }
12599 }
12600}
12601
12602#[derive(Debug, Clone, Serialize, Deserialize)]
12604pub struct ProjectTypeDistribution {
12605 #[serde(default = "default_capital_weight")]
12607 pub capital: f64,
12608 #[serde(default = "default_internal_weight")]
12610 pub internal: f64,
12611 #[serde(default = "default_customer_weight")]
12613 pub customer: f64,
12614 #[serde(default = "default_rnd_weight")]
12616 pub r_and_d: f64,
12617 #[serde(default = "default_maintenance_weight")]
12619 pub maintenance: f64,
12620 #[serde(default = "default_technology_weight")]
12622 pub technology: f64,
12623}
12624
12625fn default_capital_weight() -> f64 {
12626 0.25
12627}
12628fn default_internal_weight() -> f64 {
12629 0.20
12630}
12631fn default_customer_weight() -> f64 {
12632 0.30
12633}
12634fn default_rnd_weight() -> f64 {
12635 0.10
12636}
12637fn default_maintenance_weight() -> f64 {
12638 0.10
12639}
12640fn default_technology_weight() -> f64 {
12641 0.05
12642}
12643
12644impl Default for ProjectTypeDistribution {
12645 fn default() -> Self {
12646 Self {
12647 capital: default_capital_weight(),
12648 internal: default_internal_weight(),
12649 customer: default_customer_weight(),
12650 r_and_d: default_rnd_weight(),
12651 maintenance: default_maintenance_weight(),
12652 technology: default_technology_weight(),
12653 }
12654 }
12655}
12656
12657#[derive(Debug, Clone, Serialize, Deserialize)]
12659pub struct WbsSchemaConfig {
12660 #[serde(default = "default_wbs_max_depth")]
12662 pub max_depth: u32,
12663 #[serde(default = "default_wbs_min_elements")]
12665 pub min_elements_per_level: u32,
12666 #[serde(default = "default_wbs_max_elements")]
12668 pub max_elements_per_level: u32,
12669}
12670
12671fn default_wbs_max_depth() -> u32 {
12672 3
12673}
12674fn default_wbs_min_elements() -> u32 {
12675 2
12676}
12677fn default_wbs_max_elements() -> u32 {
12678 6
12679}
12680
12681impl Default for WbsSchemaConfig {
12682 fn default() -> Self {
12683 Self {
12684 max_depth: default_wbs_max_depth(),
12685 min_elements_per_level: default_wbs_min_elements(),
12686 max_elements_per_level: default_wbs_max_elements(),
12687 }
12688 }
12689}
12690
12691#[derive(Debug, Clone, Serialize, Deserialize)]
12693pub struct CostAllocationConfig {
12694 #[serde(default = "default_time_entry_rate")]
12696 pub time_entry_project_rate: f64,
12697 #[serde(default = "default_expense_rate")]
12699 pub expense_project_rate: f64,
12700 #[serde(default = "default_po_rate")]
12702 pub purchase_order_project_rate: f64,
12703 #[serde(default = "default_vi_rate")]
12705 pub vendor_invoice_project_rate: f64,
12706}
12707
12708fn default_time_entry_rate() -> f64 {
12709 0.60
12710}
12711fn default_expense_rate() -> f64 {
12712 0.30
12713}
12714fn default_po_rate() -> f64 {
12715 0.40
12716}
12717fn default_vi_rate() -> f64 {
12718 0.35
12719}
12720
12721impl Default for CostAllocationConfig {
12722 fn default() -> Self {
12723 Self {
12724 time_entry_project_rate: default_time_entry_rate(),
12725 expense_project_rate: default_expense_rate(),
12726 purchase_order_project_rate: default_po_rate(),
12727 vendor_invoice_project_rate: default_vi_rate(),
12728 }
12729 }
12730}
12731
12732#[derive(Debug, Clone, Serialize, Deserialize)]
12734pub struct ProjectRevenueRecognitionConfig {
12735 #[serde(default = "default_true")]
12737 pub enabled: bool,
12738 #[serde(default = "default_revenue_method")]
12740 pub method: String,
12741 #[serde(default = "default_completion_measure")]
12743 pub completion_measure: String,
12744 #[serde(default = "default_avg_contract_value")]
12746 pub avg_contract_value: f64,
12747}
12748
12749fn default_revenue_method() -> String {
12750 "percentage_of_completion".to_string()
12751}
12752fn default_completion_measure() -> String {
12753 "cost_to_cost".to_string()
12754}
12755fn default_avg_contract_value() -> f64 {
12756 500_000.0
12757}
12758
12759impl Default for ProjectRevenueRecognitionConfig {
12760 fn default() -> Self {
12761 Self {
12762 enabled: true,
12763 method: default_revenue_method(),
12764 completion_measure: default_completion_measure(),
12765 avg_contract_value: default_avg_contract_value(),
12766 }
12767 }
12768}
12769
12770#[derive(Debug, Clone, Serialize, Deserialize)]
12772pub struct MilestoneSchemaConfig {
12773 #[serde(default = "default_true")]
12775 pub enabled: bool,
12776 #[serde(default = "default_milestones_per_project")]
12778 pub avg_per_project: u32,
12779 #[serde(default = "default_payment_milestone_rate")]
12781 pub payment_milestone_rate: f64,
12782}
12783
12784fn default_milestones_per_project() -> u32 {
12785 4
12786}
12787fn default_payment_milestone_rate() -> f64 {
12788 0.50
12789}
12790
12791impl Default for MilestoneSchemaConfig {
12792 fn default() -> Self {
12793 Self {
12794 enabled: true,
12795 avg_per_project: default_milestones_per_project(),
12796 payment_milestone_rate: default_payment_milestone_rate(),
12797 }
12798 }
12799}
12800
12801#[derive(Debug, Clone, Serialize, Deserialize)]
12803pub struct ChangeOrderSchemaConfig {
12804 #[serde(default = "default_true")]
12806 pub enabled: bool,
12807 #[serde(default = "default_change_order_probability")]
12809 pub probability: f64,
12810 #[serde(default = "default_max_change_orders")]
12812 pub max_per_project: u32,
12813 #[serde(default = "default_change_order_approval_rate")]
12815 pub approval_rate: f64,
12816}
12817
12818fn default_change_order_probability() -> f64 {
12819 0.40
12820}
12821fn default_max_change_orders() -> u32 {
12822 3
12823}
12824fn default_change_order_approval_rate() -> f64 {
12825 0.75
12826}
12827
12828impl Default for ChangeOrderSchemaConfig {
12829 fn default() -> Self {
12830 Self {
12831 enabled: true,
12832 probability: default_change_order_probability(),
12833 max_per_project: default_max_change_orders(),
12834 approval_rate: default_change_order_approval_rate(),
12835 }
12836 }
12837}
12838
12839#[derive(Debug, Clone, Serialize, Deserialize)]
12841pub struct RetainageSchemaConfig {
12842 #[serde(default)]
12844 pub enabled: bool,
12845 #[serde(default = "default_retainage_pct")]
12847 pub default_percentage: f64,
12848}
12849
12850fn default_retainage_pct() -> f64 {
12851 0.10
12852}
12853
12854impl Default for RetainageSchemaConfig {
12855 fn default() -> Self {
12856 Self {
12857 enabled: false,
12858 default_percentage: default_retainage_pct(),
12859 }
12860 }
12861}
12862
12863#[derive(Debug, Clone, Serialize, Deserialize)]
12865pub struct EarnedValueSchemaConfig {
12866 #[serde(default = "default_true")]
12868 pub enabled: bool,
12869 #[serde(default = "default_evm_frequency")]
12871 pub frequency: String,
12872}
12873
12874fn default_evm_frequency() -> String {
12875 "monthly".to_string()
12876}
12877
12878impl Default for EarnedValueSchemaConfig {
12879 fn default() -> Self {
12880 Self {
12881 enabled: true,
12882 frequency: default_evm_frequency(),
12883 }
12884 }
12885}
12886
12887#[derive(Debug, Clone, Serialize, Deserialize)]
12893pub struct EsgConfig {
12894 #[serde(default)]
12896 pub enabled: bool,
12897 #[serde(default)]
12899 pub environmental: EnvironmentalConfig,
12900 #[serde(default)]
12902 pub social: SocialConfig,
12903 #[serde(default)]
12905 pub governance: GovernanceSchemaConfig,
12906 #[serde(default)]
12908 pub supply_chain_esg: SupplyChainEsgConfig,
12909 #[serde(default)]
12911 pub reporting: EsgReportingConfig,
12912 #[serde(default)]
12914 pub climate_scenarios: ClimateScenarioConfig,
12915 #[serde(default = "default_esg_anomaly_rate")]
12917 pub anomaly_rate: f64,
12918}
12919
12920fn default_esg_anomaly_rate() -> f64 {
12921 0.02
12922}
12923
12924impl Default for EsgConfig {
12925 fn default() -> Self {
12926 Self {
12927 enabled: false,
12928 environmental: EnvironmentalConfig::default(),
12929 social: SocialConfig::default(),
12930 governance: GovernanceSchemaConfig::default(),
12931 supply_chain_esg: SupplyChainEsgConfig::default(),
12932 reporting: EsgReportingConfig::default(),
12933 climate_scenarios: ClimateScenarioConfig::default(),
12934 anomaly_rate: default_esg_anomaly_rate(),
12935 }
12936 }
12937}
12938
12939#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12944pub struct CountryPacksSchemaConfig {
12945 #[serde(default)]
12947 pub external_dir: Option<PathBuf>,
12948 #[serde(default)]
12952 pub overrides: std::collections::HashMap<String, serde_json::Value>,
12953}
12954
12955#[derive(Debug, Clone, Serialize, Deserialize)]
12957pub struct EnvironmentalConfig {
12958 #[serde(default = "default_true")]
12960 pub enabled: bool,
12961 #[serde(default)]
12963 pub scope1: EmissionScopeConfig,
12964 #[serde(default)]
12966 pub scope2: EmissionScopeConfig,
12967 #[serde(default)]
12969 pub scope3: Scope3Config,
12970 #[serde(default)]
12972 pub energy: EnergySchemaConfig,
12973 #[serde(default)]
12975 pub water: WaterSchemaConfig,
12976 #[serde(default)]
12978 pub waste: WasteSchemaConfig,
12979}
12980
12981impl Default for EnvironmentalConfig {
12982 fn default() -> Self {
12983 Self {
12984 enabled: true,
12985 scope1: EmissionScopeConfig::default(),
12986 scope2: EmissionScopeConfig::default(),
12987 scope3: Scope3Config::default(),
12988 energy: EnergySchemaConfig::default(),
12989 water: WaterSchemaConfig::default(),
12990 waste: WasteSchemaConfig::default(),
12991 }
12992 }
12993}
12994
12995#[derive(Debug, Clone, Serialize, Deserialize)]
12997pub struct EmissionScopeConfig {
12998 #[serde(default = "default_true")]
13000 pub enabled: bool,
13001 #[serde(default = "default_emission_region")]
13003 pub factor_region: String,
13004}
13005
13006fn default_emission_region() -> String {
13007 "US".to_string()
13008}
13009
13010impl Default for EmissionScopeConfig {
13011 fn default() -> Self {
13012 Self {
13013 enabled: true,
13014 factor_region: default_emission_region(),
13015 }
13016 }
13017}
13018
13019#[derive(Debug, Clone, Serialize, Deserialize)]
13021pub struct Scope3Config {
13022 #[serde(default = "default_true")]
13024 pub enabled: bool,
13025 #[serde(default = "default_scope3_categories")]
13027 pub categories: Vec<String>,
13028 #[serde(default = "default_spend_intensity")]
13030 pub default_spend_intensity_kg_per_usd: f64,
13031}
13032
13033fn default_scope3_categories() -> Vec<String> {
13034 vec![
13035 "purchased_goods".to_string(),
13036 "business_travel".to_string(),
13037 "employee_commuting".to_string(),
13038 ]
13039}
13040
13041fn default_spend_intensity() -> f64 {
13042 0.5
13043}
13044
13045impl Default for Scope3Config {
13046 fn default() -> Self {
13047 Self {
13048 enabled: true,
13049 categories: default_scope3_categories(),
13050 default_spend_intensity_kg_per_usd: default_spend_intensity(),
13051 }
13052 }
13053}
13054
13055#[derive(Debug, Clone, Serialize, Deserialize)]
13057pub struct EnergySchemaConfig {
13058 #[serde(default = "default_true")]
13060 pub enabled: bool,
13061 #[serde(default = "default_facility_count")]
13063 pub facility_count: u32,
13064 #[serde(default = "default_renewable_target")]
13066 pub renewable_target: f64,
13067}
13068
13069fn default_facility_count() -> u32 {
13070 5
13071}
13072
13073fn default_renewable_target() -> f64 {
13074 0.30
13075}
13076
13077impl Default for EnergySchemaConfig {
13078 fn default() -> Self {
13079 Self {
13080 enabled: true,
13081 facility_count: default_facility_count(),
13082 renewable_target: default_renewable_target(),
13083 }
13084 }
13085}
13086
13087#[derive(Debug, Clone, Serialize, Deserialize)]
13089pub struct WaterSchemaConfig {
13090 #[serde(default = "default_true")]
13092 pub enabled: bool,
13093 #[serde(default = "default_water_facility_count")]
13095 pub facility_count: u32,
13096}
13097
13098fn default_water_facility_count() -> u32 {
13099 3
13100}
13101
13102impl Default for WaterSchemaConfig {
13103 fn default() -> Self {
13104 Self {
13105 enabled: true,
13106 facility_count: default_water_facility_count(),
13107 }
13108 }
13109}
13110
13111#[derive(Debug, Clone, Serialize, Deserialize)]
13113pub struct WasteSchemaConfig {
13114 #[serde(default = "default_true")]
13116 pub enabled: bool,
13117 #[serde(default = "default_diversion_target")]
13119 pub diversion_target: f64,
13120}
13121
13122fn default_diversion_target() -> f64 {
13123 0.50
13124}
13125
13126impl Default for WasteSchemaConfig {
13127 fn default() -> Self {
13128 Self {
13129 enabled: true,
13130 diversion_target: default_diversion_target(),
13131 }
13132 }
13133}
13134
13135#[derive(Debug, Clone, Serialize, Deserialize)]
13137pub struct SocialConfig {
13138 #[serde(default = "default_true")]
13140 pub enabled: bool,
13141 #[serde(default)]
13143 pub diversity: DiversitySchemaConfig,
13144 #[serde(default)]
13146 pub pay_equity: PayEquitySchemaConfig,
13147 #[serde(default)]
13149 pub safety: SafetySchemaConfig,
13150}
13151
13152impl Default for SocialConfig {
13153 fn default() -> Self {
13154 Self {
13155 enabled: true,
13156 diversity: DiversitySchemaConfig::default(),
13157 pay_equity: PayEquitySchemaConfig::default(),
13158 safety: SafetySchemaConfig::default(),
13159 }
13160 }
13161}
13162
13163#[derive(Debug, Clone, Serialize, Deserialize)]
13165pub struct DiversitySchemaConfig {
13166 #[serde(default = "default_true")]
13168 pub enabled: bool,
13169 #[serde(default = "default_diversity_dimensions")]
13171 pub dimensions: Vec<String>,
13172}
13173
13174fn default_diversity_dimensions() -> Vec<String> {
13175 vec![
13176 "gender".to_string(),
13177 "ethnicity".to_string(),
13178 "age_group".to_string(),
13179 ]
13180}
13181
13182impl Default for DiversitySchemaConfig {
13183 fn default() -> Self {
13184 Self {
13185 enabled: true,
13186 dimensions: default_diversity_dimensions(),
13187 }
13188 }
13189}
13190
13191#[derive(Debug, Clone, Serialize, Deserialize)]
13193pub struct PayEquitySchemaConfig {
13194 #[serde(default = "default_true")]
13196 pub enabled: bool,
13197 #[serde(default = "default_pay_gap_threshold")]
13199 pub gap_threshold: f64,
13200}
13201
13202fn default_pay_gap_threshold() -> f64 {
13203 0.05
13204}
13205
13206impl Default for PayEquitySchemaConfig {
13207 fn default() -> Self {
13208 Self {
13209 enabled: true,
13210 gap_threshold: default_pay_gap_threshold(),
13211 }
13212 }
13213}
13214
13215#[derive(Debug, Clone, Serialize, Deserialize)]
13217pub struct SafetySchemaConfig {
13218 #[serde(default = "default_true")]
13220 pub enabled: bool,
13221 #[serde(default = "default_trir_target")]
13223 pub target_trir: f64,
13224 #[serde(default = "default_incident_count")]
13226 pub incident_count: u32,
13227}
13228
13229fn default_trir_target() -> f64 {
13230 2.5
13231}
13232
13233fn default_incident_count() -> u32 {
13234 20
13235}
13236
13237impl Default for SafetySchemaConfig {
13238 fn default() -> Self {
13239 Self {
13240 enabled: true,
13241 target_trir: default_trir_target(),
13242 incident_count: default_incident_count(),
13243 }
13244 }
13245}
13246
13247#[derive(Debug, Clone, Serialize, Deserialize)]
13249pub struct GovernanceSchemaConfig {
13250 #[serde(default = "default_true")]
13252 pub enabled: bool,
13253 #[serde(default = "default_board_size")]
13255 pub board_size: u32,
13256 #[serde(default = "default_independence_target")]
13258 pub independence_target: f64,
13259}
13260
13261fn default_board_size() -> u32 {
13262 11
13263}
13264
13265fn default_independence_target() -> f64 {
13266 0.67
13267}
13268
13269impl Default for GovernanceSchemaConfig {
13270 fn default() -> Self {
13271 Self {
13272 enabled: true,
13273 board_size: default_board_size(),
13274 independence_target: default_independence_target(),
13275 }
13276 }
13277}
13278
13279#[derive(Debug, Clone, Serialize, Deserialize)]
13281pub struct SupplyChainEsgConfig {
13282 #[serde(default = "default_true")]
13284 pub enabled: bool,
13285 #[serde(default = "default_assessment_coverage")]
13287 pub assessment_coverage: f64,
13288 #[serde(default = "default_high_risk_countries")]
13290 pub high_risk_countries: Vec<String>,
13291}
13292
13293fn default_assessment_coverage() -> f64 {
13294 0.80
13295}
13296
13297fn default_high_risk_countries() -> Vec<String> {
13298 vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
13299}
13300
13301impl Default for SupplyChainEsgConfig {
13302 fn default() -> Self {
13303 Self {
13304 enabled: true,
13305 assessment_coverage: default_assessment_coverage(),
13306 high_risk_countries: default_high_risk_countries(),
13307 }
13308 }
13309}
13310
13311#[derive(Debug, Clone, Serialize, Deserialize)]
13313pub struct EsgReportingConfig {
13314 #[serde(default = "default_true")]
13316 pub enabled: bool,
13317 #[serde(default = "default_esg_frameworks")]
13319 pub frameworks: Vec<String>,
13320 #[serde(default = "default_true")]
13322 pub materiality_assessment: bool,
13323 #[serde(default = "default_materiality_threshold")]
13325 pub impact_threshold: f64,
13326 #[serde(default = "default_materiality_threshold")]
13328 pub financial_threshold: f64,
13329}
13330
13331fn default_esg_frameworks() -> Vec<String> {
13332 vec!["GRI".to_string(), "ESRS".to_string()]
13333}
13334
13335fn default_materiality_threshold() -> f64 {
13336 0.6
13337}
13338
13339impl Default for EsgReportingConfig {
13340 fn default() -> Self {
13341 Self {
13342 enabled: true,
13343 frameworks: default_esg_frameworks(),
13344 materiality_assessment: true,
13345 impact_threshold: default_materiality_threshold(),
13346 financial_threshold: default_materiality_threshold(),
13347 }
13348 }
13349}
13350
13351#[derive(Debug, Clone, Serialize, Deserialize)]
13353pub struct ClimateScenarioConfig {
13354 #[serde(default)]
13356 pub enabled: bool,
13357 #[serde(default = "default_climate_scenarios")]
13359 pub scenarios: Vec<String>,
13360 #[serde(default = "default_time_horizons")]
13362 pub time_horizons: Vec<u32>,
13363}
13364
13365fn default_climate_scenarios() -> Vec<String> {
13366 vec![
13367 "net_zero_2050".to_string(),
13368 "stated_policies".to_string(),
13369 "current_trajectory".to_string(),
13370 ]
13371}
13372
13373fn default_time_horizons() -> Vec<u32> {
13374 vec![5, 10, 30]
13375}
13376
13377impl Default for ClimateScenarioConfig {
13378 fn default() -> Self {
13379 Self {
13380 enabled: false,
13381 scenarios: default_climate_scenarios(),
13382 time_horizons: default_time_horizons(),
13383 }
13384 }
13385}
13386
13387#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13391pub struct ScenariosConfig {
13392 #[serde(default)]
13394 pub enabled: bool,
13395 #[serde(default)]
13397 pub scenarios: Vec<ScenarioSchemaConfig>,
13398 #[serde(default)]
13400 pub causal_model: CausalModelSchemaConfig,
13401 #[serde(default)]
13403 pub defaults: ScenarioDefaultsConfig,
13404 #[serde(default)]
13407 pub generate_counterfactuals: bool,
13408}
13409
13410#[derive(Debug, Clone, Serialize, Deserialize)]
13412pub struct ScenarioSchemaConfig {
13413 pub name: String,
13415 #[serde(default)]
13417 pub description: String,
13418 #[serde(default)]
13420 pub tags: Vec<String>,
13421 pub base: Option<String>,
13423 pub probability_weight: Option<f64>,
13425 #[serde(default)]
13427 pub interventions: Vec<InterventionSchemaConfig>,
13428 #[serde(default)]
13430 pub constraints: ScenarioConstraintsSchemaConfig,
13431 #[serde(default)]
13433 pub output: ScenarioOutputSchemaConfig,
13434 #[serde(default)]
13436 pub metadata: std::collections::HashMap<String, String>,
13437}
13438
13439#[derive(Debug, Clone, Serialize, Deserialize)]
13441pub struct InterventionSchemaConfig {
13442 #[serde(flatten)]
13444 pub intervention_type: serde_json::Value,
13445 #[serde(default)]
13447 pub timing: InterventionTimingSchemaConfig,
13448 pub label: Option<String>,
13450 #[serde(default)]
13452 pub priority: u32,
13453}
13454
13455#[derive(Debug, Clone, Serialize, Deserialize)]
13457pub struct InterventionTimingSchemaConfig {
13458 #[serde(default = "default_start_month")]
13460 pub start_month: u32,
13461 pub duration_months: Option<u32>,
13463 #[serde(default = "default_onset")]
13465 pub onset: String,
13466 pub ramp_months: Option<u32>,
13468}
13469
13470fn default_start_month() -> u32 {
13471 1
13472}
13473
13474fn default_onset() -> String {
13475 "sudden".to_string()
13476}
13477
13478impl Default for InterventionTimingSchemaConfig {
13479 fn default() -> Self {
13480 Self {
13481 start_month: 1,
13482 duration_months: None,
13483 onset: "sudden".to_string(),
13484 ramp_months: None,
13485 }
13486 }
13487}
13488
13489#[derive(Debug, Clone, Serialize, Deserialize)]
13491pub struct ScenarioConstraintsSchemaConfig {
13492 #[serde(default = "default_true")]
13493 pub preserve_accounting_identity: bool,
13494 #[serde(default = "default_true")]
13495 pub preserve_document_chains: bool,
13496 #[serde(default = "default_true")]
13497 pub preserve_period_close: bool,
13498 #[serde(default = "default_true")]
13499 pub preserve_balance_coherence: bool,
13500 #[serde(default)]
13501 pub custom: Vec<CustomConstraintSchemaConfig>,
13502}
13503
13504impl Default for ScenarioConstraintsSchemaConfig {
13505 fn default() -> Self {
13506 Self {
13507 preserve_accounting_identity: true,
13508 preserve_document_chains: true,
13509 preserve_period_close: true,
13510 preserve_balance_coherence: true,
13511 custom: Vec::new(),
13512 }
13513 }
13514}
13515
13516#[derive(Debug, Clone, Serialize, Deserialize)]
13518pub struct CustomConstraintSchemaConfig {
13519 pub config_path: String,
13520 pub min: Option<f64>,
13521 pub max: Option<f64>,
13522 #[serde(default)]
13523 pub description: String,
13524}
13525
13526#[derive(Debug, Clone, Serialize, Deserialize)]
13528pub struct ScenarioOutputSchemaConfig {
13529 #[serde(default = "default_true")]
13530 pub paired: bool,
13531 #[serde(default = "default_diff_formats_schema")]
13532 pub diff_formats: Vec<String>,
13533 #[serde(default)]
13534 pub diff_scope: Vec<String>,
13535}
13536
13537fn default_diff_formats_schema() -> Vec<String> {
13538 vec!["summary".to_string(), "aggregate".to_string()]
13539}
13540
13541impl Default for ScenarioOutputSchemaConfig {
13542 fn default() -> Self {
13543 Self {
13544 paired: true,
13545 diff_formats: default_diff_formats_schema(),
13546 diff_scope: Vec::new(),
13547 }
13548 }
13549}
13550
13551#[derive(Debug, Clone, Serialize, Deserialize)]
13553pub struct CausalModelSchemaConfig {
13554 #[serde(default = "default_causal_preset")]
13556 pub preset: String,
13557 #[serde(default)]
13559 pub nodes: Vec<serde_json::Value>,
13560 #[serde(default)]
13562 pub edges: Vec<serde_json::Value>,
13563}
13564
13565fn default_causal_preset() -> String {
13566 "default".to_string()
13567}
13568
13569impl Default for CausalModelSchemaConfig {
13570 fn default() -> Self {
13571 Self {
13572 preset: "default".to_string(),
13573 nodes: Vec::new(),
13574 edges: Vec::new(),
13575 }
13576 }
13577}
13578
13579#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13581pub struct ScenarioDefaultsConfig {
13582 #[serde(default)]
13583 pub constraints: ScenarioConstraintsSchemaConfig,
13584 #[serde(default)]
13585 pub output: ScenarioOutputSchemaConfig,
13586}
13587
13588#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13621pub struct ComplianceRegulationsConfig {
13622 #[serde(default)]
13624 pub enabled: bool,
13625 #[serde(default)]
13628 pub jurisdictions: Vec<String>,
13629 #[serde(default)]
13632 pub reference_date: Option<String>,
13633 #[serde(default)]
13635 pub standards_selection: StandardsSelectionConfig,
13636 #[serde(default)]
13638 pub audit_procedures: AuditProcedureGenConfig,
13639 #[serde(default)]
13641 pub findings: ComplianceFindingGenConfig,
13642 #[serde(default)]
13644 pub filings: ComplianceFilingGenConfig,
13645 #[serde(default)]
13647 pub graph: ComplianceGraphConfig,
13648 #[serde(default)]
13650 pub output: ComplianceOutputConfig,
13651 #[serde(default)]
13656 pub legal_documents: LegalDocumentsConfig,
13657}
13658
13659#[derive(Debug, Clone, Serialize, Deserialize)]
13664pub struct LegalDocumentsConfig {
13665 #[serde(default)]
13667 pub enabled: bool,
13668 #[serde(default = "default_legal_opinion_probability")]
13670 pub legal_opinion_probability: f64,
13671}
13672
13673fn default_legal_opinion_probability() -> f64 {
13674 0.40
13675}
13676
13677impl Default for LegalDocumentsConfig {
13678 fn default() -> Self {
13679 Self {
13680 enabled: false,
13681 legal_opinion_probability: default_legal_opinion_probability(),
13682 }
13683 }
13684}
13685
13686#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13688pub struct StandardsSelectionConfig {
13689 #[serde(default)]
13692 pub categories: Vec<String>,
13693 #[serde(default)]
13696 pub include: Vec<String>,
13697 #[serde(default)]
13699 pub exclude: Vec<String>,
13700 #[serde(default)]
13702 pub include_superseded: bool,
13703}
13704
13705#[derive(Debug, Clone, Serialize, Deserialize)]
13707pub struct AuditProcedureGenConfig {
13708 #[serde(default)]
13710 pub enabled: bool,
13711 #[serde(default = "default_procedures_per_standard")]
13713 pub procedures_per_standard: usize,
13714 #[serde(default = "default_sampling_method")]
13716 pub sampling_method: String,
13717 #[serde(default = "default_confidence_level")]
13719 pub confidence_level: f64,
13720 #[serde(default = "default_tolerable_misstatement")]
13722 pub tolerable_misstatement: f64,
13723}
13724
13725fn default_procedures_per_standard() -> usize {
13726 3
13727}
13728
13729fn default_sampling_method() -> String {
13730 "statistical".to_string()
13731}
13732
13733fn default_confidence_level() -> f64 {
13734 0.95
13735}
13736
13737fn default_tolerable_misstatement() -> f64 {
13738 0.05
13739}
13740
13741impl Default for AuditProcedureGenConfig {
13742 fn default() -> Self {
13743 Self {
13744 enabled: false,
13745 procedures_per_standard: default_procedures_per_standard(),
13746 sampling_method: default_sampling_method(),
13747 confidence_level: default_confidence_level(),
13748 tolerable_misstatement: default_tolerable_misstatement(),
13749 }
13750 }
13751}
13752
13753#[derive(Debug, Clone, Serialize, Deserialize)]
13755pub struct ComplianceFindingGenConfig {
13756 #[serde(default)]
13758 pub enabled: bool,
13759 #[serde(default = "default_finding_rate")]
13761 pub finding_rate: f64,
13762 #[serde(default = "default_cr_material_weakness_rate")]
13764 pub material_weakness_rate: f64,
13765 #[serde(default = "default_cr_significant_deficiency_rate")]
13767 pub significant_deficiency_rate: f64,
13768 #[serde(default = "default_true")]
13770 pub generate_remediation: bool,
13771}
13772
13773fn default_finding_rate() -> f64 {
13774 0.05
13775}
13776
13777fn default_cr_material_weakness_rate() -> f64 {
13778 0.02
13779}
13780
13781fn default_cr_significant_deficiency_rate() -> f64 {
13782 0.08
13783}
13784
13785impl Default for ComplianceFindingGenConfig {
13786 fn default() -> Self {
13787 Self {
13788 enabled: false,
13789 finding_rate: default_finding_rate(),
13790 material_weakness_rate: default_cr_material_weakness_rate(),
13791 significant_deficiency_rate: default_cr_significant_deficiency_rate(),
13792 generate_remediation: true,
13793 }
13794 }
13795}
13796
13797#[derive(Debug, Clone, Serialize, Deserialize)]
13799pub struct ComplianceFilingGenConfig {
13800 #[serde(default)]
13802 pub enabled: bool,
13803 #[serde(default)]
13806 pub filing_types: Vec<String>,
13807 #[serde(default = "default_true")]
13809 pub generate_status_progression: bool,
13810}
13811
13812impl Default for ComplianceFilingGenConfig {
13813 fn default() -> Self {
13814 Self {
13815 enabled: false,
13816 filing_types: Vec::new(),
13817 generate_status_progression: true,
13818 }
13819 }
13820}
13821
13822#[derive(Debug, Clone, Serialize, Deserialize)]
13824pub struct ComplianceGraphConfig {
13825 #[serde(default)]
13827 pub enabled: bool,
13828 #[serde(default = "default_true")]
13830 pub include_compliance_nodes: bool,
13831 #[serde(default = "default_true")]
13833 pub include_compliance_edges: bool,
13834 #[serde(default = "default_true")]
13836 pub include_cross_references: bool,
13837 #[serde(default)]
13839 pub include_supersession_edges: bool,
13840 #[serde(default = "default_true")]
13842 pub include_account_links: bool,
13843 #[serde(default = "default_true")]
13845 pub include_control_links: bool,
13846 #[serde(default = "default_true")]
13848 pub include_company_links: bool,
13849}
13850
13851impl Default for ComplianceGraphConfig {
13852 fn default() -> Self {
13853 Self {
13854 enabled: false,
13855 include_compliance_nodes: true,
13856 include_compliance_edges: true,
13857 include_cross_references: true,
13858 include_supersession_edges: false,
13859 include_account_links: true,
13860 include_control_links: true,
13861 include_company_links: true,
13862 }
13863 }
13864}
13865
13866#[derive(Debug, Clone, Serialize, Deserialize)]
13868pub struct ComplianceOutputConfig {
13869 #[serde(default = "default_true")]
13871 pub export_registry: bool,
13872 #[serde(default = "default_true")]
13874 pub export_jurisdictions: bool,
13875 #[serde(default = "default_true")]
13877 pub export_cross_references: bool,
13878 #[serde(default)]
13880 pub export_version_history: bool,
13881}
13882
13883impl Default for ComplianceOutputConfig {
13884 fn default() -> Self {
13885 Self {
13886 export_registry: true,
13887 export_jurisdictions: true,
13888 export_cross_references: true,
13889 export_version_history: false,
13890 }
13891 }
13892}
13893
13894#[cfg(test)]
13895#[allow(clippy::unwrap_used)]
13896mod tests {
13897 use super::*;
13898 use crate::presets::demo_preset;
13899
13900 #[test]
13905 fn test_config_yaml_roundtrip() {
13906 let config = demo_preset();
13907 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
13908 let deserialized: GeneratorConfig =
13909 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
13910
13911 assert_eq!(
13912 config.global.period_months,
13913 deserialized.global.period_months
13914 );
13915 assert_eq!(config.global.industry, deserialized.global.industry);
13916 assert_eq!(config.companies.len(), deserialized.companies.len());
13917 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
13918 }
13919
13920 #[test]
13921 fn test_config_json_roundtrip() {
13922 let mut config = demo_preset();
13924 config.master_data.employees.approval_limits.executive = 1e12;
13926
13927 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
13928 let deserialized: GeneratorConfig =
13929 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
13930
13931 assert_eq!(
13932 config.global.period_months,
13933 deserialized.global.period_months
13934 );
13935 assert_eq!(config.global.industry, deserialized.global.industry);
13936 assert_eq!(config.companies.len(), deserialized.companies.len());
13937 }
13938
13939 #[test]
13940 fn test_transaction_volume_serialization() {
13941 let volumes = vec![
13943 (TransactionVolume::TenK, "ten_k"),
13944 (TransactionVolume::HundredK, "hundred_k"),
13945 (TransactionVolume::OneM, "one_m"),
13946 (TransactionVolume::TenM, "ten_m"),
13947 (TransactionVolume::HundredM, "hundred_m"),
13948 ];
13949
13950 for (volume, expected_key) in volumes {
13951 let json = serde_json::to_string(&volume).expect("Failed to serialize");
13952 assert!(
13953 json.contains(expected_key),
13954 "Expected {} in JSON: {}",
13955 expected_key,
13956 json
13957 );
13958 }
13959 }
13960
13961 #[test]
13962 fn test_transaction_volume_custom_serialization() {
13963 let volume = TransactionVolume::Custom(12345);
13964 let json = serde_json::to_string(&volume).expect("Failed to serialize");
13965 let deserialized: TransactionVolume =
13966 serde_json::from_str(&json).expect("Failed to deserialize");
13967 assert_eq!(deserialized.count(), 12345);
13968 }
13969
13970 #[test]
13971 fn test_output_mode_serialization() {
13972 let modes = vec![
13973 OutputMode::Streaming,
13974 OutputMode::FlatFile,
13975 OutputMode::Both,
13976 ];
13977
13978 for mode in modes {
13979 let json = serde_json::to_string(&mode).expect("Failed to serialize");
13980 let deserialized: OutputMode =
13981 serde_json::from_str(&json).expect("Failed to deserialize");
13982 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
13983 }
13984 }
13985
13986 #[test]
13987 fn test_file_format_serialization() {
13988 let formats = vec![
13989 FileFormat::Csv,
13990 FileFormat::Parquet,
13991 FileFormat::Json,
13992 FileFormat::JsonLines,
13993 ];
13994
13995 for format in formats {
13996 let json = serde_json::to_string(&format).expect("Failed to serialize");
13997 let deserialized: FileFormat =
13998 serde_json::from_str(&json).expect("Failed to deserialize");
13999 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
14000 }
14001 }
14002
14003 #[test]
14004 fn test_compression_algorithm_serialization() {
14005 let algos = vec![
14006 CompressionAlgorithm::Gzip,
14007 CompressionAlgorithm::Zstd,
14008 CompressionAlgorithm::Lz4,
14009 CompressionAlgorithm::Snappy,
14010 ];
14011
14012 for algo in algos {
14013 let json = serde_json::to_string(&algo).expect("Failed to serialize");
14014 let deserialized: CompressionAlgorithm =
14015 serde_json::from_str(&json).expect("Failed to deserialize");
14016 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
14017 }
14018 }
14019
14020 #[test]
14021 fn test_transfer_pricing_method_serialization() {
14022 let methods = vec![
14023 TransferPricingMethod::CostPlus,
14024 TransferPricingMethod::ComparableUncontrolled,
14025 TransferPricingMethod::ResalePrice,
14026 TransferPricingMethod::TransactionalNetMargin,
14027 TransferPricingMethod::ProfitSplit,
14028 ];
14029
14030 for method in methods {
14031 let json = serde_json::to_string(&method).expect("Failed to serialize");
14032 let deserialized: TransferPricingMethod =
14033 serde_json::from_str(&json).expect("Failed to deserialize");
14034 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
14035 }
14036 }
14037
14038 #[test]
14039 fn test_benford_exemption_serialization() {
14040 let exemptions = vec![
14041 BenfordExemption::Recurring,
14042 BenfordExemption::Payroll,
14043 BenfordExemption::FixedFees,
14044 BenfordExemption::RoundAmounts,
14045 ];
14046
14047 for exemption in exemptions {
14048 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
14049 let deserialized: BenfordExemption =
14050 serde_json::from_str(&json).expect("Failed to deserialize");
14051 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
14052 }
14053 }
14054
14055 #[test]
14060 fn test_global_config_defaults() {
14061 let yaml = r#"
14062 industry: manufacturing
14063 start_date: "2024-01-01"
14064 period_months: 6
14065 "#;
14066 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14067 assert_eq!(config.group_currency, "USD");
14068 assert!(config.parallel);
14069 assert_eq!(config.worker_threads, 0);
14070 assert_eq!(config.memory_limit_mb, 0);
14071 }
14072
14073 #[test]
14074 fn test_fraud_config_defaults() {
14075 let config = FraudConfig::default();
14076 assert!(!config.enabled);
14077 assert_eq!(config.fraud_rate, 0.005);
14078 assert!(!config.clustering_enabled);
14079 }
14080
14081 #[test]
14082 fn test_internal_controls_config_defaults() {
14083 let config = InternalControlsConfig::default();
14084 assert!(!config.enabled);
14085 assert_eq!(config.exception_rate, 0.02);
14086 assert_eq!(config.sod_violation_rate, 0.01);
14087 assert!(config.export_control_master_data);
14088 assert_eq!(config.sox_materiality_threshold, 10000.0);
14089 assert!(config.coso_enabled);
14091 assert!(!config.include_entity_level_controls);
14092 assert_eq!(config.target_maturity_level, "mixed");
14093 }
14094
14095 #[test]
14096 fn test_output_config_defaults() {
14097 let config = OutputConfig::default();
14098 assert!(matches!(config.mode, OutputMode::FlatFile));
14099 assert_eq!(config.formats, vec![FileFormat::Parquet]);
14100 assert!(config.compression.enabled);
14101 assert!(matches!(
14102 config.compression.algorithm,
14103 CompressionAlgorithm::Zstd
14104 ));
14105 assert!(config.include_acdoca);
14106 assert!(!config.include_bseg);
14107 assert!(config.partition_by_period);
14108 assert!(!config.partition_by_company);
14109 }
14110
14111 #[test]
14112 fn test_approval_config_defaults() {
14113 let config = ApprovalConfig::default();
14114 assert!(!config.enabled);
14115 assert_eq!(config.auto_approve_threshold, 1000.0);
14116 assert_eq!(config.rejection_rate, 0.02);
14117 assert_eq!(config.revision_rate, 0.05);
14118 assert_eq!(config.average_approval_delay_hours, 4.0);
14119 assert_eq!(config.thresholds.len(), 4);
14120 }
14121
14122 #[test]
14123 fn test_p2p_flow_config_defaults() {
14124 let config = P2PFlowConfig::default();
14125 assert!(config.enabled);
14126 assert_eq!(config.three_way_match_rate, 0.95);
14127 assert_eq!(config.partial_delivery_rate, 0.15);
14128 assert_eq!(config.average_po_to_gr_days, 14);
14129 }
14130
14131 #[test]
14132 fn test_o2c_flow_config_defaults() {
14133 let config = O2CFlowConfig::default();
14134 assert!(config.enabled);
14135 assert_eq!(config.credit_check_failure_rate, 0.02);
14136 assert_eq!(config.return_rate, 0.03);
14137 assert_eq!(config.bad_debt_rate, 0.01);
14138 }
14139
14140 #[test]
14141 fn test_balance_config_defaults() {
14142 let config = BalanceConfig::default();
14143 assert!(!config.generate_opening_balances);
14144 assert!(config.generate_trial_balances);
14145 assert_eq!(config.target_gross_margin, 0.35);
14146 assert!(config.validate_balance_equation);
14147 assert!(config.reconcile_subledgers);
14148 }
14149
14150 #[test]
14155 fn test_partial_config_with_defaults() {
14156 let yaml = r#"
14158 global:
14159 industry: manufacturing
14160 start_date: "2024-01-01"
14161 period_months: 3
14162 companies:
14163 - code: "TEST"
14164 name: "Test Company"
14165 currency: "USD"
14166 country: "US"
14167 annual_transaction_volume: ten_k
14168 chart_of_accounts:
14169 complexity: small
14170 output:
14171 output_directory: "./output"
14172 "#;
14173
14174 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14175 assert_eq!(config.global.period_months, 3);
14176 assert_eq!(config.companies.len(), 1);
14177 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
14180
14181 #[test]
14182 fn test_config_with_fraud_enabled() {
14183 let yaml = r#"
14184 global:
14185 industry: retail
14186 start_date: "2024-01-01"
14187 period_months: 12
14188 companies:
14189 - code: "RETAIL"
14190 name: "Retail Co"
14191 currency: "USD"
14192 country: "US"
14193 annual_transaction_volume: hundred_k
14194 chart_of_accounts:
14195 complexity: medium
14196 output:
14197 output_directory: "./output"
14198 fraud:
14199 enabled: true
14200 fraud_rate: 0.05
14201 clustering_enabled: true
14202 "#;
14203
14204 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14205 assert!(config.fraud.enabled);
14206 assert_eq!(config.fraud.fraud_rate, 0.05);
14207 assert!(config.fraud.clustering_enabled);
14208 }
14209
14210 #[test]
14211 fn test_config_with_multiple_companies() {
14212 let yaml = r#"
14213 global:
14214 industry: manufacturing
14215 start_date: "2024-01-01"
14216 period_months: 6
14217 companies:
14218 - code: "HQ"
14219 name: "Headquarters"
14220 currency: "USD"
14221 country: "US"
14222 annual_transaction_volume: hundred_k
14223 volume_weight: 1.0
14224 - code: "EU"
14225 name: "European Subsidiary"
14226 currency: "EUR"
14227 country: "DE"
14228 annual_transaction_volume: hundred_k
14229 volume_weight: 0.5
14230 - code: "APAC"
14231 name: "Asia Pacific"
14232 currency: "JPY"
14233 country: "JP"
14234 annual_transaction_volume: ten_k
14235 volume_weight: 0.3
14236 chart_of_accounts:
14237 complexity: large
14238 output:
14239 output_directory: "./output"
14240 "#;
14241
14242 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14243 assert_eq!(config.companies.len(), 3);
14244 assert_eq!(config.companies[0].code, "HQ");
14245 assert_eq!(config.companies[1].currency, "EUR");
14246 assert_eq!(config.companies[2].volume_weight, 0.3);
14247 }
14248
14249 #[test]
14250 fn test_intercompany_config() {
14251 let yaml = r#"
14252 enabled: true
14253 ic_transaction_rate: 0.20
14254 transfer_pricing_method: cost_plus
14255 markup_percent: 0.08
14256 generate_matched_pairs: true
14257 generate_eliminations: true
14258 "#;
14259
14260 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14261 assert!(config.enabled);
14262 assert_eq!(config.ic_transaction_rate, 0.20);
14263 assert!(matches!(
14264 config.transfer_pricing_method,
14265 TransferPricingMethod::CostPlus
14266 ));
14267 assert_eq!(config.markup_percent, 0.08);
14268 assert!(config.generate_eliminations);
14269 }
14270
14271 #[test]
14276 fn test_company_config_defaults() {
14277 let yaml = r#"
14278 code: "TEST"
14279 name: "Test Company"
14280 currency: "USD"
14281 country: "US"
14282 annual_transaction_volume: ten_k
14283 "#;
14284
14285 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14286 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
14289
14290 #[test]
14295 fn test_coa_config_defaults() {
14296 let yaml = r#"
14297 complexity: medium
14298 "#;
14299
14300 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14301 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
14303 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
14306
14307 #[test]
14312 fn test_accounting_standards_config_defaults() {
14313 let config = AccountingStandardsConfig::default();
14314 assert!(!config.enabled);
14315 assert!(config.framework.is_none());
14316 assert!(!config.revenue_recognition.enabled);
14317 assert!(!config.leases.enabled);
14318 assert!(!config.fair_value.enabled);
14319 assert!(!config.impairment.enabled);
14320 assert!(!config.generate_differences);
14321 }
14322
14323 #[test]
14324 fn test_accounting_standards_config_yaml() {
14325 let yaml = r#"
14326 enabled: true
14327 framework: ifrs
14328 revenue_recognition:
14329 enabled: true
14330 generate_contracts: true
14331 avg_obligations_per_contract: 2.5
14332 variable_consideration_rate: 0.20
14333 over_time_recognition_rate: 0.35
14334 contract_count: 150
14335 leases:
14336 enabled: true
14337 lease_count: 75
14338 finance_lease_percent: 0.25
14339 avg_lease_term_months: 48
14340 generate_differences: true
14341 "#;
14342
14343 let config: AccountingStandardsConfig =
14344 serde_yaml::from_str(yaml).expect("Failed to parse");
14345 assert!(config.enabled);
14346 assert!(matches!(
14347 config.framework,
14348 Some(AccountingFrameworkConfig::Ifrs)
14349 ));
14350 assert!(config.revenue_recognition.enabled);
14351 assert_eq!(config.revenue_recognition.contract_count, 150);
14352 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
14353 assert!(config.leases.enabled);
14354 assert_eq!(config.leases.lease_count, 75);
14355 assert_eq!(config.leases.finance_lease_percent, 0.25);
14356 assert!(config.generate_differences);
14357 }
14358
14359 #[test]
14360 fn test_accounting_framework_serialization() {
14361 let frameworks = [
14362 AccountingFrameworkConfig::UsGaap,
14363 AccountingFrameworkConfig::Ifrs,
14364 AccountingFrameworkConfig::DualReporting,
14365 AccountingFrameworkConfig::FrenchGaap,
14366 AccountingFrameworkConfig::GermanGaap,
14367 ];
14368
14369 for framework in frameworks {
14370 let json = serde_json::to_string(&framework).expect("Failed to serialize");
14371 let deserialized: AccountingFrameworkConfig =
14372 serde_json::from_str(&json).expect("Failed to deserialize");
14373 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
14374 }
14375 }
14376
14377 #[test]
14378 fn test_revenue_recognition_config_defaults() {
14379 let config = RevenueRecognitionConfig::default();
14380 assert!(!config.enabled);
14381 assert!(config.generate_contracts);
14382 assert_eq!(config.avg_obligations_per_contract, 2.0);
14383 assert_eq!(config.variable_consideration_rate, 0.15);
14384 assert_eq!(config.over_time_recognition_rate, 0.30);
14385 assert_eq!(config.contract_count, 100);
14386 }
14387
14388 #[test]
14389 fn test_lease_accounting_config_defaults() {
14390 let config = LeaseAccountingConfig::default();
14391 assert!(!config.enabled);
14392 assert_eq!(config.lease_count, 50);
14393 assert_eq!(config.finance_lease_percent, 0.30);
14394 assert_eq!(config.avg_lease_term_months, 60);
14395 assert!(config.generate_amortization);
14396 assert_eq!(config.real_estate_percent, 0.40);
14397 }
14398
14399 #[test]
14400 fn test_fair_value_config_defaults() {
14401 let config = FairValueConfig::default();
14402 assert!(!config.enabled);
14403 assert_eq!(config.measurement_count, 25);
14404 assert_eq!(config.level1_percent, 0.40);
14405 assert_eq!(config.level2_percent, 0.35);
14406 assert_eq!(config.level3_percent, 0.25);
14407 assert!(!config.include_sensitivity_analysis);
14408 }
14409
14410 #[test]
14411 fn test_impairment_config_defaults() {
14412 let config = ImpairmentConfig::default();
14413 assert!(!config.enabled);
14414 assert_eq!(config.test_count, 15);
14415 assert_eq!(config.impairment_rate, 0.10);
14416 assert!(config.generate_projections);
14417 assert!(!config.include_goodwill);
14418 }
14419
14420 #[test]
14425 fn test_audit_standards_config_defaults() {
14426 let config = AuditStandardsConfig::default();
14427 assert!(!config.enabled);
14428 assert!(!config.isa_compliance.enabled);
14429 assert!(!config.analytical_procedures.enabled);
14430 assert!(!config.confirmations.enabled);
14431 assert!(!config.opinion.enabled);
14432 assert!(!config.generate_audit_trail);
14433 assert!(!config.sox.enabled);
14434 assert!(!config.pcaob.enabled);
14435 }
14436
14437 #[test]
14438 fn test_audit_standards_config_yaml() {
14439 let yaml = r#"
14440 enabled: true
14441 isa_compliance:
14442 enabled: true
14443 compliance_level: comprehensive
14444 generate_isa_mappings: true
14445 include_pcaob: true
14446 framework: dual
14447 analytical_procedures:
14448 enabled: true
14449 procedures_per_account: 5
14450 variance_probability: 0.25
14451 confirmations:
14452 enabled: true
14453 confirmation_count: 75
14454 positive_response_rate: 0.90
14455 exception_rate: 0.08
14456 opinion:
14457 enabled: true
14458 generate_kam: true
14459 average_kam_count: 4
14460 sox:
14461 enabled: true
14462 generate_302_certifications: true
14463 generate_404_assessments: true
14464 material_weakness_rate: 0.03
14465 pcaob:
14466 enabled: true
14467 is_pcaob_audit: true
14468 include_icfr_opinion: true
14469 generate_audit_trail: true
14470 "#;
14471
14472 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14473 assert!(config.enabled);
14474 assert!(config.isa_compliance.enabled);
14475 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
14476 assert!(config.isa_compliance.include_pcaob);
14477 assert_eq!(config.isa_compliance.framework, "dual");
14478 assert!(config.analytical_procedures.enabled);
14479 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
14480 assert!(config.confirmations.enabled);
14481 assert_eq!(config.confirmations.confirmation_count, 75);
14482 assert!(config.opinion.enabled);
14483 assert_eq!(config.opinion.average_kam_count, 4);
14484 assert!(config.sox.enabled);
14485 assert!(config.sox.generate_302_certifications);
14486 assert_eq!(config.sox.material_weakness_rate, 0.03);
14487 assert!(config.pcaob.enabled);
14488 assert!(config.pcaob.is_pcaob_audit);
14489 assert!(config.pcaob.include_icfr_opinion);
14490 assert!(config.generate_audit_trail);
14491 }
14492
14493 #[test]
14494 fn test_isa_compliance_config_defaults() {
14495 let config = IsaComplianceConfig::default();
14496 assert!(!config.enabled);
14497 assert_eq!(config.compliance_level, "standard");
14498 assert!(config.generate_isa_mappings);
14499 assert!(config.generate_coverage_summary);
14500 assert!(!config.include_pcaob);
14501 assert_eq!(config.framework, "isa");
14502 }
14503
14504 #[test]
14505 fn test_sox_compliance_config_defaults() {
14506 let config = SoxComplianceConfig::default();
14507 assert!(!config.enabled);
14508 assert!(config.generate_302_certifications);
14509 assert!(config.generate_404_assessments);
14510 assert_eq!(config.materiality_threshold, 10000.0);
14511 assert_eq!(config.material_weakness_rate, 0.02);
14512 assert_eq!(config.significant_deficiency_rate, 0.08);
14513 }
14514
14515 #[test]
14516 fn test_pcaob_config_defaults() {
14517 let config = PcaobConfig::default();
14518 assert!(!config.enabled);
14519 assert!(!config.is_pcaob_audit);
14520 assert!(config.generate_cam);
14521 assert!(!config.include_icfr_opinion);
14522 assert!(!config.generate_standard_mappings);
14523 }
14524
14525 #[test]
14526 fn test_config_with_standards_enabled() {
14527 let yaml = r#"
14528 global:
14529 industry: financial_services
14530 start_date: "2024-01-01"
14531 period_months: 12
14532 companies:
14533 - code: "BANK"
14534 name: "Test Bank"
14535 currency: "USD"
14536 country: "US"
14537 annual_transaction_volume: hundred_k
14538 chart_of_accounts:
14539 complexity: large
14540 output:
14541 output_directory: "./output"
14542 accounting_standards:
14543 enabled: true
14544 framework: us_gaap
14545 revenue_recognition:
14546 enabled: true
14547 leases:
14548 enabled: true
14549 audit_standards:
14550 enabled: true
14551 isa_compliance:
14552 enabled: true
14553 sox:
14554 enabled: true
14555 "#;
14556
14557 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14558 assert!(config.accounting_standards.enabled);
14559 assert!(matches!(
14560 config.accounting_standards.framework,
14561 Some(AccountingFrameworkConfig::UsGaap)
14562 ));
14563 assert!(config.accounting_standards.revenue_recognition.enabled);
14564 assert!(config.accounting_standards.leases.enabled);
14565 assert!(config.audit_standards.enabled);
14566 assert!(config.audit_standards.isa_compliance.enabled);
14567 assert!(config.audit_standards.sox.enabled);
14568 }
14569
14570 #[test]
14575 fn test_industry_specific_config_defaults() {
14576 let config = IndustrySpecificConfig::default();
14577 assert!(!config.enabled);
14578 assert!(!config.manufacturing.enabled);
14579 assert!(!config.retail.enabled);
14580 assert!(!config.healthcare.enabled);
14581 assert!(!config.technology.enabled);
14582 assert!(!config.financial_services.enabled);
14583 assert!(!config.professional_services.enabled);
14584 }
14585
14586 #[test]
14587 fn test_manufacturing_config_defaults() {
14588 let config = ManufacturingConfig::default();
14589 assert!(!config.enabled);
14590 assert_eq!(config.bom_depth, 4);
14591 assert!(!config.just_in_time);
14592 assert_eq!(config.supplier_tiers, 2);
14593 assert_eq!(config.target_yield_rate, 0.97);
14594 assert_eq!(config.scrap_alert_threshold, 0.03);
14595 }
14596
14597 #[test]
14598 fn test_retail_config_defaults() {
14599 let config = RetailConfig::default();
14600 assert!(!config.enabled);
14601 assert_eq!(config.avg_daily_transactions, 500);
14602 assert!(config.loss_prevention);
14603 assert_eq!(config.shrinkage_rate, 0.015);
14604 }
14605
14606 #[test]
14607 fn test_healthcare_config_defaults() {
14608 let config = HealthcareConfig::default();
14609 assert!(!config.enabled);
14610 assert_eq!(config.facility_type, "hospital");
14611 assert_eq!(config.avg_daily_encounters, 150);
14612 assert!(config.compliance.hipaa);
14613 assert!(config.compliance.stark_law);
14614 assert!(config.coding_systems.icd10);
14615 assert!(config.coding_systems.cpt);
14616 }
14617
14618 #[test]
14619 fn test_technology_config_defaults() {
14620 let config = TechnologyConfig::default();
14621 assert!(!config.enabled);
14622 assert_eq!(config.revenue_model, "saas");
14623 assert_eq!(config.subscription_revenue_pct, 0.60);
14624 assert!(config.rd_capitalization.enabled);
14625 }
14626
14627 #[test]
14628 fn test_config_with_industry_specific() {
14629 let yaml = r#"
14630 global:
14631 industry: healthcare
14632 start_date: "2024-01-01"
14633 period_months: 12
14634 companies:
14635 - code: "HOSP"
14636 name: "Test Hospital"
14637 currency: "USD"
14638 country: "US"
14639 annual_transaction_volume: hundred_k
14640 chart_of_accounts:
14641 complexity: medium
14642 output:
14643 output_directory: "./output"
14644 industry_specific:
14645 enabled: true
14646 healthcare:
14647 enabled: true
14648 facility_type: hospital
14649 payer_mix:
14650 medicare: 0.45
14651 medicaid: 0.15
14652 commercial: 0.35
14653 self_pay: 0.05
14654 coding_systems:
14655 icd10: true
14656 cpt: true
14657 drg: true
14658 compliance:
14659 hipaa: true
14660 stark_law: true
14661 anomaly_rates:
14662 upcoding: 0.03
14663 unbundling: 0.02
14664 "#;
14665
14666 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14667 assert!(config.industry_specific.enabled);
14668 assert!(config.industry_specific.healthcare.enabled);
14669 assert_eq!(
14670 config.industry_specific.healthcare.facility_type,
14671 "hospital"
14672 );
14673 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14674 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14675 assert!(config.industry_specific.healthcare.coding_systems.icd10);
14676 assert!(config.industry_specific.healthcare.compliance.hipaa);
14677 assert_eq!(
14678 config.industry_specific.healthcare.anomaly_rates.upcoding,
14679 0.03
14680 );
14681 }
14682
14683 #[test]
14684 fn test_config_with_manufacturing_specific() {
14685 let yaml = r#"
14686 global:
14687 industry: manufacturing
14688 start_date: "2024-01-01"
14689 period_months: 12
14690 companies:
14691 - code: "MFG"
14692 name: "Test Manufacturing"
14693 currency: "USD"
14694 country: "US"
14695 annual_transaction_volume: hundred_k
14696 chart_of_accounts:
14697 complexity: medium
14698 output:
14699 output_directory: "./output"
14700 industry_specific:
14701 enabled: true
14702 manufacturing:
14703 enabled: true
14704 bom_depth: 5
14705 just_in_time: true
14706 supplier_tiers: 3
14707 target_yield_rate: 0.98
14708 anomaly_rates:
14709 yield_manipulation: 0.02
14710 phantom_production: 0.01
14711 "#;
14712
14713 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14714 assert!(config.industry_specific.enabled);
14715 assert!(config.industry_specific.manufacturing.enabled);
14716 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14717 assert!(config.industry_specific.manufacturing.just_in_time);
14718 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14719 assert_eq!(
14720 config.industry_specific.manufacturing.target_yield_rate,
14721 0.98
14722 );
14723 assert_eq!(
14724 config
14725 .industry_specific
14726 .manufacturing
14727 .anomaly_rates
14728 .yield_manipulation,
14729 0.02
14730 );
14731 }
14732
14733 #[test]
14738 fn test_tax_config_defaults() {
14739 let tax = TaxConfig::default();
14740 assert!(!tax.enabled);
14741 assert!(tax.jurisdictions.countries.is_empty());
14742 assert!(!tax.jurisdictions.include_subnational);
14743 assert!(!tax.vat_gst.enabled);
14744 assert!(tax.vat_gst.standard_rates.is_empty());
14745 assert!(tax.vat_gst.reduced_rates.is_empty());
14746 assert!(tax.vat_gst.exempt_categories.is_empty());
14747 assert!(tax.vat_gst.reverse_charge);
14748 assert!(!tax.sales_tax.enabled);
14749 assert!(tax.sales_tax.nexus_states.is_empty());
14750 assert!(!tax.withholding.enabled);
14751 assert!(tax.withholding.treaty_network);
14752 assert_eq!(tax.withholding.default_rate, 0.30);
14753 assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14754 assert!(tax.provisions.enabled);
14755 assert_eq!(tax.provisions.statutory_rate, 0.21);
14756 assert!(tax.provisions.uncertain_positions);
14757 assert!(!tax.payroll_tax.enabled);
14758 assert_eq!(tax.anomaly_rate, 0.03);
14759 }
14760
14761 #[test]
14762 fn test_tax_config_from_yaml() {
14763 let yaml = r#"
14764 global:
14765 seed: 42
14766 start_date: "2024-01-01"
14767 period_months: 12
14768 industry: retail
14769 companies:
14770 - code: C001
14771 name: Test Corp
14772 currency: USD
14773 country: US
14774 annual_transaction_volume: ten_k
14775 chart_of_accounts:
14776 complexity: small
14777 output:
14778 output_directory: ./output
14779 tax:
14780 enabled: true
14781 anomaly_rate: 0.05
14782 jurisdictions:
14783 countries: ["US", "DE", "GB"]
14784 include_subnational: true
14785 vat_gst:
14786 enabled: true
14787 standard_rates:
14788 DE: 0.19
14789 GB: 0.20
14790 reduced_rates:
14791 DE: 0.07
14792 GB: 0.05
14793 exempt_categories:
14794 - financial_services
14795 - healthcare
14796 reverse_charge: false
14797 sales_tax:
14798 enabled: true
14799 nexus_states: ["CA", "NY", "TX"]
14800 withholding:
14801 enabled: true
14802 treaty_network: false
14803 default_rate: 0.25
14804 treaty_reduced_rate: 0.10
14805 provisions:
14806 enabled: false
14807 statutory_rate: 0.28
14808 uncertain_positions: false
14809 payroll_tax:
14810 enabled: true
14811 "#;
14812
14813 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14814 assert!(config.tax.enabled);
14815 assert_eq!(config.tax.anomaly_rate, 0.05);
14816
14817 assert_eq!(config.tax.jurisdictions.countries.len(), 3);
14819 assert!(config
14820 .tax
14821 .jurisdictions
14822 .countries
14823 .contains(&"DE".to_string()));
14824 assert!(config.tax.jurisdictions.include_subnational);
14825
14826 assert!(config.tax.vat_gst.enabled);
14828 assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
14829 assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
14830 assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
14831 assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
14832 assert!(!config.tax.vat_gst.reverse_charge);
14833
14834 assert!(config.tax.sales_tax.enabled);
14836 assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
14837 assert!(config
14838 .tax
14839 .sales_tax
14840 .nexus_states
14841 .contains(&"CA".to_string()));
14842
14843 assert!(config.tax.withholding.enabled);
14845 assert!(!config.tax.withholding.treaty_network);
14846 assert_eq!(config.tax.withholding.default_rate, 0.25);
14847 assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
14848
14849 assert!(!config.tax.provisions.enabled);
14851 assert_eq!(config.tax.provisions.statutory_rate, 0.28);
14852 assert!(!config.tax.provisions.uncertain_positions);
14853
14854 assert!(config.tax.payroll_tax.enabled);
14856 }
14857
14858 #[test]
14859 fn test_generator_config_with_tax_default() {
14860 let yaml = r#"
14861 global:
14862 seed: 42
14863 start_date: "2024-01-01"
14864 period_months: 12
14865 industry: retail
14866 companies:
14867 - code: C001
14868 name: Test Corp
14869 currency: USD
14870 country: US
14871 annual_transaction_volume: ten_k
14872 chart_of_accounts:
14873 complexity: small
14874 output:
14875 output_directory: ./output
14876 "#;
14877
14878 let config: GeneratorConfig =
14879 serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
14880 assert!(!config.tax.enabled);
14882 assert!(config.tax.jurisdictions.countries.is_empty());
14883 assert_eq!(config.tax.anomaly_rate, 0.03);
14884 assert!(config.tax.provisions.enabled); assert_eq!(config.tax.provisions.statutory_rate, 0.21);
14886 }
14887
14888 #[test]
14893 fn test_session_config_default_disabled() {
14894 let yaml = "{}";
14895 let config: SessionSchemaConfig =
14896 serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
14897 assert!(!config.enabled);
14898 assert!(config.checkpoint_path.is_none());
14899 assert!(config.per_period_output);
14900 assert!(config.consolidated_output);
14901 }
14902
14903 #[test]
14904 fn test_config_backward_compatible_without_session() {
14905 let yaml = r#"
14906 global:
14907 seed: 42
14908 start_date: "2024-01-01"
14909 period_months: 12
14910 industry: retail
14911 companies:
14912 - code: C001
14913 name: Test Corp
14914 currency: USD
14915 country: US
14916 annual_transaction_volume: ten_k
14917 chart_of_accounts:
14918 complexity: small
14919 output:
14920 output_directory: ./output
14921 "#;
14922
14923 let config: GeneratorConfig =
14924 serde_yaml::from_str(yaml).expect("Failed to parse config without session");
14925 assert!(!config.session.enabled);
14927 assert!(config.session.per_period_output);
14928 assert!(config.session.consolidated_output);
14929 assert!(config.global.fiscal_year_months.is_none());
14931 }
14932
14933 #[test]
14934 fn test_fiscal_year_months_parsed() {
14935 let yaml = r#"
14936 global:
14937 seed: 42
14938 start_date: "2024-01-01"
14939 period_months: 24
14940 industry: retail
14941 fiscal_year_months: 12
14942 companies:
14943 - code: C001
14944 name: Test Corp
14945 currency: USD
14946 country: US
14947 annual_transaction_volume: ten_k
14948 chart_of_accounts:
14949 complexity: small
14950 output:
14951 output_directory: ./output
14952 session:
14953 enabled: true
14954 checkpoint_path: /tmp/checkpoints
14955 per_period_output: true
14956 consolidated_output: false
14957 "#;
14958
14959 let config: GeneratorConfig =
14960 serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
14961 assert_eq!(config.global.fiscal_year_months, Some(12));
14962 assert!(config.session.enabled);
14963 assert_eq!(
14964 config.session.checkpoint_path,
14965 Some("/tmp/checkpoints".to_string())
14966 );
14967 assert!(config.session.per_period_output);
14968 assert!(!config.session.consolidated_output);
14969 }
14970}