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)]
28pub struct GeneratorConfig {
29 pub global: GlobalConfig,
31 pub companies: Vec<CompanyConfig>,
33 #[serde(alias = "chartOfAccounts")]
35 pub chart_of_accounts: ChartOfAccountsConfig,
36 #[serde(default)]
38 pub transactions: TransactionConfig,
39 pub output: OutputConfig,
41 #[serde(default)]
43 pub fraud: FraudConfig,
44 #[serde(default, alias = "dataQuality")]
46 pub data_quality: DataQualitySchemaConfig,
47 #[serde(default, alias = "internalControls")]
49 pub internal_controls: InternalControlsConfig,
50 #[serde(default, alias = "businessProcesses")]
52 pub business_processes: BusinessProcessConfig,
53 #[serde(default, alias = "userPersonas")]
55 pub user_personas: UserPersonaConfig,
56 #[serde(default)]
58 pub templates: TemplateConfig,
59 #[serde(default)]
61 pub approval: ApprovalConfig,
62 #[serde(default)]
64 pub departments: DepartmentConfig,
65 #[serde(default, alias = "masterData")]
67 pub master_data: MasterDataConfig,
68 #[serde(default, alias = "documentFlows")]
70 pub document_flows: DocumentFlowConfig,
71 #[serde(default)]
73 pub intercompany: IntercompanyConfig,
74 #[serde(default)]
76 pub balance: BalanceConfig,
77 #[serde(default)]
79 pub ocpm: OcpmConfig,
80 #[serde(default)]
82 pub audit: AuditGenerationConfig,
83 #[serde(default)]
85 pub banking: datasynth_banking::BankingConfig,
86 #[serde(default)]
88 pub scenario: ScenarioConfig,
89 #[serde(default)]
91 pub temporal: TemporalDriftConfig,
92 #[serde(default, alias = "graphExport")]
94 pub graph_export: GraphExportConfig,
95 #[serde(default)]
97 pub streaming: StreamingSchemaConfig,
98 #[serde(default, alias = "rateLimit")]
100 pub rate_limit: RateLimitSchemaConfig,
101 #[serde(default, alias = "temporalAttributes")]
103 pub temporal_attributes: TemporalAttributeSchemaConfig,
104 #[serde(default)]
106 pub relationships: RelationshipSchemaConfig,
107 #[serde(default, alias = "accountingStandards")]
109 pub accounting_standards: AccountingStandardsConfig,
110 #[serde(default, alias = "auditStandards")]
112 pub audit_standards: AuditStandardsConfig,
113 #[serde(default)]
115 pub distributions: AdvancedDistributionConfig,
116 #[serde(default, alias = "temporalPatterns")]
118 pub temporal_patterns: TemporalPatternsConfig,
119 #[serde(default, alias = "vendorNetwork")]
121 pub vendor_network: VendorNetworkSchemaConfig,
122 #[serde(default, alias = "customerSegmentation")]
124 pub customer_segmentation: CustomerSegmentationSchemaConfig,
125 #[serde(default, alias = "relationshipStrength")]
127 pub relationship_strength: RelationshipStrengthSchemaConfig,
128 #[serde(default, alias = "crossProcessLinks")]
130 pub cross_process_links: CrossProcessLinksSchemaConfig,
131 #[serde(default, alias = "organizationalEvents")]
133 pub organizational_events: OrganizationalEventsSchemaConfig,
134 #[serde(default, alias = "behavioralDrift")]
136 pub behavioral_drift: BehavioralDriftSchemaConfig,
137 #[serde(default, alias = "marketDrift")]
139 pub market_drift: MarketDriftSchemaConfig,
140 #[serde(default, alias = "driftLabeling")]
142 pub drift_labeling: DriftLabelingSchemaConfig,
143 #[serde(default, alias = "anomalyInjection")]
145 pub anomaly_injection: EnhancedAnomalyConfig,
146 #[serde(default, alias = "industrySpecific")]
148 pub industry_specific: IndustrySpecificConfig,
149 #[serde(default, alias = "fingerprintPrivacy")]
151 pub fingerprint_privacy: FingerprintPrivacyConfig,
152 #[serde(default, alias = "qualityGates")]
154 pub quality_gates: QualityGatesSchemaConfig,
155 #[serde(default)]
157 pub compliance: ComplianceSchemaConfig,
158 #[serde(default)]
160 pub webhooks: WebhookSchemaConfig,
161 #[serde(default)]
163 pub llm: LlmSchemaConfig,
164 #[serde(default)]
166 pub diffusion: DiffusionSchemaConfig,
167 #[serde(default)]
169 pub causal: CausalSchemaConfig,
170
171 #[serde(default, alias = "sourceToPay")]
174 pub source_to_pay: SourceToPayConfig,
175 #[serde(default, alias = "financialReporting")]
177 pub financial_reporting: FinancialReportingConfig,
178 #[serde(default)]
180 pub hr: HrConfig,
181 #[serde(default)]
183 pub manufacturing: ManufacturingProcessConfig,
184 #[serde(default, alias = "salesQuotes")]
186 pub sales_quotes: SalesQuoteConfig,
187 #[serde(default)]
189 pub tax: TaxConfig,
190 #[serde(default)]
192 pub treasury: TreasuryConfig,
193 #[serde(default, alias = "projectAccounting")]
195 pub project_accounting: ProjectAccountingConfig,
196 #[serde(default)]
198 pub esg: EsgConfig,
199 #[serde(default, alias = "countryPacks")]
201 pub country_packs: Option<CountryPacksSchemaConfig>,
202 #[serde(default)]
204 pub scenarios: ScenariosConfig,
205 #[serde(default)]
207 pub session: SessionSchemaConfig,
208 #[serde(default, alias = "complianceRegulations")]
210 pub compliance_regulations: ComplianceRegulationsConfig,
211 #[serde(default, alias = "analyticsMetadata")]
215 pub analytics_metadata: AnalyticsMetadataConfig,
216}
217
218#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct AnalyticsMetadataConfig {
228 #[serde(default)]
230 pub enabled: bool,
231 #[serde(default = "default_true")]
234 pub prior_year: bool,
235 #[serde(default = "default_true")]
237 pub industry_benchmark: bool,
238 #[serde(default = "default_true")]
240 pub management_reports: bool,
241 #[serde(default = "default_true")]
244 pub drift_events: bool,
245}
246
247impl Default for AnalyticsMetadataConfig {
248 fn default() -> Self {
249 Self {
250 enabled: false,
251 prior_year: true,
252 industry_benchmark: true,
253 management_reports: true,
254 drift_events: true,
255 }
256 }
257}
258
259#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct LlmSchemaConfig {
266 #[serde(default)]
268 pub enabled: bool,
269 #[serde(default = "default_llm_provider")]
271 pub provider: String,
272 #[serde(default = "default_llm_model_name")]
274 pub model: String,
275 #[serde(default = "default_llm_batch_size")]
277 pub max_vendor_enrichments: usize,
278
279 #[serde(default)]
282 pub enrich_customers: bool,
283
284 #[serde(default)]
287 pub enrich_materials: bool,
288
289 #[serde(default)]
293 pub enrich_findings: bool,
294
295 #[serde(default = "default_llm_batch_size")]
298 pub max_customer_enrichments: usize,
299
300 #[serde(default = "default_llm_batch_size")]
302 pub max_material_enrichments: usize,
303
304 #[serde(default = "default_llm_batch_size")]
306 pub max_finding_enrichments: usize,
307}
308
309fn default_llm_provider() -> String {
310 "mock".to_string()
311}
312
313fn default_llm_model_name() -> String {
314 "gpt-4o-mini".to_string()
315}
316
317fn default_llm_batch_size() -> usize {
318 50
319}
320
321impl Default for LlmSchemaConfig {
322 fn default() -> Self {
323 Self {
324 enabled: false,
325 provider: default_llm_provider(),
326 model: default_llm_model_name(),
327 max_vendor_enrichments: default_llm_batch_size(),
328 enrich_customers: false,
329 enrich_materials: false,
330 enrich_findings: false,
331 max_customer_enrichments: default_llm_batch_size(),
332 max_material_enrichments: default_llm_batch_size(),
333 max_finding_enrichments: default_llm_batch_size(),
334 }
335 }
336}
337
338#[derive(Debug, Clone, Serialize, Deserialize)]
343pub struct DiffusionSchemaConfig {
344 #[serde(default)]
346 pub enabled: bool,
347 #[serde(default = "default_diffusion_steps")]
349 pub n_steps: usize,
350 #[serde(default = "default_diffusion_schedule")]
352 pub schedule: String,
353 #[serde(default = "default_diffusion_sample_size")]
355 pub sample_size: usize,
356 #[serde(default = "default_diffusion_backend")]
358 pub backend: String,
359 #[serde(default)]
361 pub neural: NeuralDiffusionSchemaConfig,
362}
363
364fn default_diffusion_steps() -> usize {
365 100
366}
367
368fn default_diffusion_schedule() -> String {
369 "linear".to_string()
370}
371
372fn default_diffusion_sample_size() -> usize {
373 100
374}
375
376fn default_diffusion_backend() -> String {
377 "statistical".to_string()
378}
379
380impl Default for DiffusionSchemaConfig {
381 fn default() -> Self {
382 Self {
383 enabled: false,
384 n_steps: default_diffusion_steps(),
385 schedule: default_diffusion_schedule(),
386 sample_size: default_diffusion_sample_size(),
387 backend: default_diffusion_backend(),
388 neural: NeuralDiffusionSchemaConfig::default(),
389 }
390 }
391}
392
393#[derive(Debug, Clone, Serialize, Deserialize)]
398pub struct NeuralDiffusionSchemaConfig {
399 #[serde(default = "default_neural_hidden_dims")]
401 pub hidden_dims: Vec<usize>,
402 #[serde(default = "default_neural_timestep_embed_dim")]
404 pub timestep_embed_dim: usize,
405 #[serde(default = "default_neural_learning_rate")]
407 pub learning_rate: f64,
408 #[serde(default = "default_neural_training_epochs")]
410 pub training_epochs: usize,
411 #[serde(default = "default_neural_batch_size")]
413 pub batch_size: usize,
414 #[serde(default = "default_neural_hybrid_weight")]
416 pub hybrid_weight: f64,
417 #[serde(default = "default_neural_hybrid_strategy")]
419 pub hybrid_strategy: String,
420 #[serde(default)]
422 pub neural_columns: Vec<String>,
423 #[serde(default, skip_serializing_if = "Option::is_none")]
430 pub checkpoint_path: Option<String>,
431}
432
433fn default_neural_hidden_dims() -> Vec<usize> {
434 vec![256, 256, 128]
435}
436
437fn default_neural_timestep_embed_dim() -> usize {
438 64
439}
440
441fn default_neural_learning_rate() -> f64 {
442 0.001
443}
444
445fn default_neural_training_epochs() -> usize {
446 100
447}
448
449fn default_neural_batch_size() -> usize {
450 64
451}
452
453fn default_neural_hybrid_weight() -> f64 {
454 0.5
455}
456
457fn default_neural_hybrid_strategy() -> String {
458 "weighted_average".to_string()
459}
460
461impl Default for NeuralDiffusionSchemaConfig {
462 fn default() -> Self {
463 Self {
464 hidden_dims: default_neural_hidden_dims(),
465 timestep_embed_dim: default_neural_timestep_embed_dim(),
466 learning_rate: default_neural_learning_rate(),
467 training_epochs: default_neural_training_epochs(),
468 batch_size: default_neural_batch_size(),
469 hybrid_weight: default_neural_hybrid_weight(),
470 hybrid_strategy: default_neural_hybrid_strategy(),
471 neural_columns: Vec::new(),
472 checkpoint_path: None,
473 }
474 }
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize)]
483pub struct CausalSchemaConfig {
484 #[serde(default)]
486 pub enabled: bool,
487 #[serde(default = "default_causal_template")]
489 pub template: String,
490 #[serde(default = "default_causal_sample_size")]
492 pub sample_size: usize,
493 #[serde(default = "default_true")]
495 pub validate: bool,
496}
497
498fn default_causal_template() -> String {
499 "fraud_detection".to_string()
500}
501
502fn default_causal_sample_size() -> usize {
503 500
504}
505
506impl Default for CausalSchemaConfig {
507 fn default() -> Self {
508 Self {
509 enabled: false,
510 template: default_causal_template(),
511 sample_size: default_causal_sample_size(),
512 validate: true,
513 }
514 }
515}
516
517#[derive(Debug, Clone, Serialize, Deserialize)]
524pub struct GraphExportConfig {
525 #[serde(default)]
527 pub enabled: bool,
528
529 #[serde(default = "default_graph_types")]
531 pub graph_types: Vec<GraphTypeConfig>,
532
533 #[serde(default = "default_graph_formats")]
535 pub formats: Vec<GraphExportFormat>,
536
537 #[serde(default = "default_train_ratio")]
539 pub train_ratio: f64,
540
541 #[serde(default = "default_val_ratio")]
543 pub validation_ratio: f64,
544
545 #[serde(default)]
547 pub split_seed: Option<u64>,
548
549 #[serde(default = "default_graph_subdir")]
551 pub output_subdirectory: String,
552
553 #[serde(default)]
555 pub hypergraph: HypergraphExportSettings,
556
557 #[serde(default)]
559 pub dgl: DglExportConfig,
560}
561
562fn default_graph_types() -> Vec<GraphTypeConfig> {
563 vec![GraphTypeConfig::default()]
564}
565
566fn default_graph_formats() -> Vec<GraphExportFormat> {
567 vec![GraphExportFormat::PytorchGeometric]
568}
569
570fn default_train_ratio() -> f64 {
571 0.7
572}
573
574fn default_val_ratio() -> f64 {
575 0.15
576}
577
578fn default_graph_subdir() -> String {
579 "graphs".to_string()
580}
581
582impl Default for GraphExportConfig {
583 fn default() -> Self {
584 Self {
585 enabled: false,
586 graph_types: default_graph_types(),
587 formats: default_graph_formats(),
588 train_ratio: 0.7,
589 validation_ratio: 0.15,
590 split_seed: None,
591 output_subdirectory: "graphs".to_string(),
592 hypergraph: HypergraphExportSettings::default(),
593 dgl: DglExportConfig::default(),
594 }
595 }
596}
597
598#[derive(Debug, Clone, Default, Serialize, Deserialize)]
600pub struct DglExportConfig {
601 #[serde(default)]
607 pub heterogeneous: bool,
608}
609
610#[derive(Debug, Clone, Serialize, Deserialize)]
619pub struct HypergraphExportSettings {
620 #[serde(default)]
622 pub enabled: bool,
623
624 #[serde(default = "default_hypergraph_max_nodes")]
626 pub max_nodes: usize,
627
628 #[serde(default = "default_aggregation_strategy")]
630 pub aggregation_strategy: String,
631
632 #[serde(default)]
634 pub governance_layer: GovernanceLayerSettings,
635
636 #[serde(default)]
638 pub process_layer: ProcessLayerSettings,
639
640 #[serde(default)]
642 pub accounting_layer: AccountingLayerSettings,
643
644 #[serde(default)]
646 pub cross_layer: CrossLayerSettings,
647
648 #[serde(default = "default_hypergraph_subdir")]
650 pub output_subdirectory: String,
651
652 #[serde(default = "default_hypergraph_format")]
654 pub output_format: String,
655
656 #[serde(default)]
658 pub stream_target: Option<String>,
659
660 #[serde(default = "default_stream_batch_size")]
662 pub stream_batch_size: usize,
663}
664
665fn default_hypergraph_max_nodes() -> usize {
666 50_000
667}
668
669fn default_aggregation_strategy() -> String {
670 "pool_by_counterparty".to_string()
671}
672
673fn default_hypergraph_subdir() -> String {
674 "hypergraph".to_string()
675}
676
677fn default_hypergraph_format() -> String {
678 "native".to_string()
679}
680
681fn default_stream_batch_size() -> usize {
682 1000
683}
684
685impl Default for HypergraphExportSettings {
686 fn default() -> Self {
687 Self {
688 enabled: false,
689 max_nodes: 50_000,
690 aggregation_strategy: "pool_by_counterparty".to_string(),
691 governance_layer: GovernanceLayerSettings::default(),
692 process_layer: ProcessLayerSettings::default(),
693 accounting_layer: AccountingLayerSettings::default(),
694 cross_layer: CrossLayerSettings::default(),
695 output_subdirectory: "hypergraph".to_string(),
696 output_format: "native".to_string(),
697 stream_target: None,
698 stream_batch_size: 1000,
699 }
700 }
701}
702
703#[derive(Debug, Clone, Serialize, Deserialize)]
705pub struct GovernanceLayerSettings {
706 #[serde(default = "default_true")]
708 pub include_coso: bool,
709 #[serde(default = "default_true")]
711 pub include_controls: bool,
712 #[serde(default = "default_true")]
714 pub include_sox: bool,
715 #[serde(default = "default_true")]
717 pub include_vendors: bool,
718 #[serde(default = "default_true")]
720 pub include_customers: bool,
721 #[serde(default = "default_true")]
723 pub include_employees: bool,
724}
725
726impl Default for GovernanceLayerSettings {
727 fn default() -> Self {
728 Self {
729 include_coso: true,
730 include_controls: true,
731 include_sox: true,
732 include_vendors: true,
733 include_customers: true,
734 include_employees: true,
735 }
736 }
737}
738
739#[derive(Debug, Clone, Serialize, Deserialize)]
741pub struct ProcessLayerSettings {
742 #[serde(default = "default_true")]
744 pub include_p2p: bool,
745 #[serde(default = "default_true")]
747 pub include_o2c: bool,
748 #[serde(default = "default_true")]
750 pub include_s2c: bool,
751 #[serde(default = "default_true")]
753 pub include_h2r: bool,
754 #[serde(default = "default_true")]
756 pub include_mfg: bool,
757 #[serde(default = "default_true")]
759 pub include_bank: bool,
760 #[serde(default = "default_true")]
762 pub include_audit: bool,
763 #[serde(default = "default_true")]
765 pub include_r2r: bool,
766 #[serde(default = "default_true")]
768 pub events_as_hyperedges: bool,
769 #[serde(default = "default_docs_per_counterparty_threshold")]
771 pub docs_per_counterparty_threshold: usize,
772}
773
774fn default_docs_per_counterparty_threshold() -> usize {
775 20
776}
777
778impl Default for ProcessLayerSettings {
779 fn default() -> Self {
780 Self {
781 include_p2p: true,
782 include_o2c: true,
783 include_s2c: true,
784 include_h2r: true,
785 include_mfg: true,
786 include_bank: true,
787 include_audit: true,
788 include_r2r: true,
789 events_as_hyperedges: true,
790 docs_per_counterparty_threshold: 20,
791 }
792 }
793}
794
795#[derive(Debug, Clone, Serialize, Deserialize)]
797pub struct AccountingLayerSettings {
798 #[serde(default = "default_true")]
800 pub include_accounts: bool,
801 #[serde(default = "default_true")]
803 pub je_as_hyperedges: bool,
804}
805
806impl Default for AccountingLayerSettings {
807 fn default() -> Self {
808 Self {
809 include_accounts: true,
810 je_as_hyperedges: true,
811 }
812 }
813}
814
815#[derive(Debug, Clone, Serialize, Deserialize)]
817pub struct CrossLayerSettings {
818 #[serde(default = "default_true")]
820 pub enabled: bool,
821}
822
823impl Default for CrossLayerSettings {
824 fn default() -> Self {
825 Self { enabled: true }
826 }
827}
828
829#[derive(Debug, Clone, Serialize, Deserialize)]
831pub struct GraphTypeConfig {
832 #[serde(default = "default_graph_name")]
834 pub name: String,
835
836 #[serde(default)]
838 pub aggregate_edges: bool,
839
840 #[serde(default)]
842 pub min_edge_weight: f64,
843
844 #[serde(default)]
846 pub include_document_nodes: bool,
847}
848
849fn default_graph_name() -> String {
850 "accounting_network".to_string()
851}
852
853impl Default for GraphTypeConfig {
854 fn default() -> Self {
855 Self {
856 name: "accounting_network".to_string(),
857 aggregate_edges: false,
858 min_edge_weight: 0.0,
859 include_document_nodes: false,
860 }
861 }
862}
863
864#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
866#[serde(rename_all = "snake_case")]
867pub enum GraphExportFormat {
868 PytorchGeometric,
870 Neo4j,
872 Dgl,
874 RustGraph,
876 RustGraphHypergraph,
878}
879
880#[derive(Debug, Clone, Default, Serialize, Deserialize)]
884pub struct ScenarioConfig {
885 #[serde(default)]
888 pub tags: Vec<String>,
889
890 #[serde(default)]
895 pub profile: Option<String>,
896
897 #[serde(default)]
899 pub description: Option<String>,
900
901 #[serde(default)]
903 pub ml_training: bool,
904
905 #[serde(default)]
908 pub target_anomaly_ratio: Option<f64>,
909
910 #[serde(default)]
912 pub metadata: std::collections::HashMap<String, String>,
913}
914
915#[derive(Debug, Clone, Serialize, Deserialize)]
920pub struct TemporalDriftConfig {
921 #[serde(default)]
923 pub enabled: bool,
924
925 #[serde(default = "default_amount_drift")]
928 pub amount_mean_drift: f64,
929
930 #[serde(default)]
933 pub amount_variance_drift: f64,
934
935 #[serde(default)]
938 pub anomaly_rate_drift: f64,
939
940 #[serde(default = "default_concept_drift")]
943 pub concept_drift_rate: f64,
944
945 #[serde(default)]
947 pub sudden_drift_probability: f64,
948
949 #[serde(default = "default_sudden_drift_magnitude")]
951 pub sudden_drift_magnitude: f64,
952
953 #[serde(default)]
955 pub seasonal_drift: bool,
956
957 #[serde(default)]
959 pub drift_start_period: u32,
960
961 #[serde(default = "default_drift_type")]
963 pub drift_type: DriftType,
964}
965
966fn default_amount_drift() -> f64 {
967 0.02
968}
969
970fn default_concept_drift() -> f64 {
971 0.01
972}
973
974fn default_sudden_drift_magnitude() -> f64 {
975 2.0
976}
977
978fn default_drift_type() -> DriftType {
979 DriftType::Gradual
980}
981
982impl Default for TemporalDriftConfig {
983 fn default() -> Self {
984 Self {
985 enabled: false,
986 amount_mean_drift: 0.02,
987 amount_variance_drift: 0.0,
988 anomaly_rate_drift: 0.0,
989 concept_drift_rate: 0.01,
990 sudden_drift_probability: 0.0,
991 sudden_drift_magnitude: 2.0,
992 seasonal_drift: false,
993 drift_start_period: 0,
994 drift_type: DriftType::Gradual,
995 }
996 }
997}
998
999impl TemporalDriftConfig {
1000 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
1002 datasynth_core::distributions::DriftConfig {
1003 enabled: self.enabled,
1004 amount_mean_drift: self.amount_mean_drift,
1005 amount_variance_drift: self.amount_variance_drift,
1006 anomaly_rate_drift: self.anomaly_rate_drift,
1007 concept_drift_rate: self.concept_drift_rate,
1008 sudden_drift_probability: self.sudden_drift_probability,
1009 sudden_drift_magnitude: self.sudden_drift_magnitude,
1010 seasonal_drift: self.seasonal_drift,
1011 drift_start_period: self.drift_start_period,
1012 drift_type: match self.drift_type {
1013 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
1014 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
1015 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
1016 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
1017 },
1018 regime_changes: Vec::new(),
1019 economic_cycle: Default::default(),
1020 parameter_drifts: Vec::new(),
1021 }
1022 }
1023}
1024
1025#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1027#[serde(rename_all = "snake_case")]
1028pub enum DriftType {
1029 #[default]
1031 Gradual,
1032 Sudden,
1034 Recurring,
1036 Mixed,
1038}
1039
1040#[derive(Debug, Clone, Serialize, Deserialize)]
1046pub struct StreamingSchemaConfig {
1047 #[serde(default)]
1049 pub enabled: bool,
1050 #[serde(default)]
1052 pub events_per_second: f64,
1053 #[serde(default = "default_burst_size")]
1055 pub burst_size: u32,
1056 #[serde(default = "default_buffer_size")]
1058 pub buffer_size: usize,
1059 #[serde(default = "default_true")]
1061 pub enable_progress: bool,
1062 #[serde(default = "default_progress_interval")]
1064 pub progress_interval: u64,
1065 #[serde(default)]
1067 pub backpressure: BackpressureSchemaStrategy,
1068}
1069
1070fn default_buffer_size() -> usize {
1071 1000
1072}
1073
1074fn default_progress_interval() -> u64 {
1075 100
1076}
1077
1078impl Default for StreamingSchemaConfig {
1079 fn default() -> Self {
1080 Self {
1081 enabled: false,
1082 events_per_second: 0.0,
1083 burst_size: 100,
1084 buffer_size: 1000,
1085 enable_progress: true,
1086 progress_interval: 100,
1087 backpressure: BackpressureSchemaStrategy::Block,
1088 }
1089 }
1090}
1091
1092#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1094#[serde(rename_all = "snake_case")]
1095pub enum BackpressureSchemaStrategy {
1096 #[default]
1098 Block,
1099 DropOldest,
1101 DropNewest,
1103 Buffer,
1105}
1106
1107#[derive(Debug, Clone, Serialize, Deserialize)]
1113pub struct RateLimitSchemaConfig {
1114 #[serde(default)]
1116 pub enabled: bool,
1117 #[serde(default = "default_entities_per_second")]
1119 pub entities_per_second: f64,
1120 #[serde(default = "default_burst_size")]
1122 pub burst_size: u32,
1123 #[serde(default)]
1125 pub backpressure: RateLimitBackpressureSchema,
1126}
1127
1128fn default_entities_per_second() -> f64 {
1129 1000.0
1130}
1131
1132fn default_burst_size() -> u32 {
1133 100
1134}
1135
1136impl Default for RateLimitSchemaConfig {
1137 fn default() -> Self {
1138 Self {
1139 enabled: false,
1140 entities_per_second: 1000.0,
1141 burst_size: 100,
1142 backpressure: RateLimitBackpressureSchema::Block,
1143 }
1144 }
1145}
1146
1147#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
1149#[serde(rename_all = "snake_case")]
1150pub enum RateLimitBackpressureSchema {
1151 #[default]
1153 Block,
1154 Drop,
1156 Buffer,
1158}
1159
1160#[derive(Debug, Clone, Serialize, Deserialize)]
1166pub struct TemporalAttributeSchemaConfig {
1167 #[serde(default)]
1169 pub enabled: bool,
1170 #[serde(default)]
1172 pub valid_time: ValidTimeSchemaConfig,
1173 #[serde(default)]
1175 pub transaction_time: TransactionTimeSchemaConfig,
1176 #[serde(default)]
1178 pub generate_version_chains: bool,
1179 #[serde(default = "default_avg_versions")]
1181 pub avg_versions_per_entity: f64,
1182}
1183
1184fn default_avg_versions() -> f64 {
1185 1.5
1186}
1187
1188impl Default for TemporalAttributeSchemaConfig {
1189 fn default() -> Self {
1190 Self {
1191 enabled: false,
1192 valid_time: ValidTimeSchemaConfig::default(),
1193 transaction_time: TransactionTimeSchemaConfig::default(),
1194 generate_version_chains: false,
1195 avg_versions_per_entity: 1.5,
1196 }
1197 }
1198}
1199
1200#[derive(Debug, Clone, Serialize, Deserialize)]
1202pub struct ValidTimeSchemaConfig {
1203 #[serde(default = "default_closed_probability")]
1205 pub closed_probability: f64,
1206 #[serde(default = "default_avg_validity_days")]
1208 pub avg_validity_days: u32,
1209 #[serde(default = "default_validity_stddev")]
1211 pub validity_stddev_days: u32,
1212}
1213
1214fn default_closed_probability() -> f64 {
1215 0.1
1216}
1217
1218fn default_avg_validity_days() -> u32 {
1219 365
1220}
1221
1222fn default_validity_stddev() -> u32 {
1223 90
1224}
1225
1226impl Default for ValidTimeSchemaConfig {
1227 fn default() -> Self {
1228 Self {
1229 closed_probability: 0.1,
1230 avg_validity_days: 365,
1231 validity_stddev_days: 90,
1232 }
1233 }
1234}
1235
1236#[derive(Debug, Clone, Serialize, Deserialize)]
1238pub struct TransactionTimeSchemaConfig {
1239 #[serde(default)]
1241 pub avg_recording_delay_seconds: u32,
1242 #[serde(default)]
1244 pub allow_backdating: bool,
1245 #[serde(default = "default_backdating_probability")]
1247 pub backdating_probability: f64,
1248 #[serde(default = "default_max_backdate_days")]
1250 pub max_backdate_days: u32,
1251}
1252
1253fn default_backdating_probability() -> f64 {
1254 0.01
1255}
1256
1257fn default_max_backdate_days() -> u32 {
1258 30
1259}
1260
1261impl Default for TransactionTimeSchemaConfig {
1262 fn default() -> Self {
1263 Self {
1264 avg_recording_delay_seconds: 0,
1265 allow_backdating: false,
1266 backdating_probability: 0.01,
1267 max_backdate_days: 30,
1268 }
1269 }
1270}
1271
1272#[derive(Debug, Clone, Serialize, Deserialize)]
1278pub struct RelationshipSchemaConfig {
1279 #[serde(default)]
1281 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
1282 #[serde(default = "default_true")]
1284 pub allow_orphans: bool,
1285 #[serde(default = "default_orphan_probability")]
1287 pub orphan_probability: f64,
1288 #[serde(default)]
1290 pub allow_circular: bool,
1291 #[serde(default = "default_max_circular_depth")]
1293 pub max_circular_depth: u32,
1294}
1295
1296fn default_orphan_probability() -> f64 {
1297 0.01
1298}
1299
1300fn default_max_circular_depth() -> u32 {
1301 3
1302}
1303
1304impl Default for RelationshipSchemaConfig {
1305 fn default() -> Self {
1306 Self {
1307 relationship_types: Vec::new(),
1308 allow_orphans: true,
1309 orphan_probability: 0.01,
1310 allow_circular: false,
1311 max_circular_depth: 3,
1312 }
1313 }
1314}
1315
1316#[derive(Debug, Clone, Serialize, Deserialize)]
1318pub struct RelationshipTypeSchemaConfig {
1319 pub name: String,
1321 pub source_type: String,
1323 pub target_type: String,
1325 #[serde(default)]
1327 pub cardinality: CardinalitySchemaRule,
1328 #[serde(default = "default_relationship_weight")]
1330 pub weight: f64,
1331 #[serde(default)]
1333 pub required: bool,
1334 #[serde(default = "default_true")]
1336 pub directed: bool,
1337}
1338
1339fn default_relationship_weight() -> f64 {
1340 1.0
1341}
1342
1343impl Default for RelationshipTypeSchemaConfig {
1344 fn default() -> Self {
1345 Self {
1346 name: String::new(),
1347 source_type: String::new(),
1348 target_type: String::new(),
1349 cardinality: CardinalitySchemaRule::default(),
1350 weight: 1.0,
1351 required: false,
1352 directed: true,
1353 }
1354 }
1355}
1356
1357#[derive(Debug, Clone, Serialize, Deserialize)]
1359#[serde(rename_all = "snake_case")]
1360pub enum CardinalitySchemaRule {
1361 OneToOne,
1363 OneToMany {
1365 min: u32,
1367 max: u32,
1369 },
1370 ManyToOne {
1372 min: u32,
1374 max: u32,
1376 },
1377 ManyToMany {
1379 min_per_source: u32,
1381 max_per_source: u32,
1383 },
1384}
1385
1386impl Default for CardinalitySchemaRule {
1387 fn default() -> Self {
1388 Self::OneToMany { min: 1, max: 5 }
1389 }
1390}
1391
1392#[derive(Debug, Clone, Serialize, Deserialize)]
1394pub struct GlobalConfig {
1395 pub seed: Option<u64>,
1397 pub industry: IndustrySector,
1399 #[serde(alias = "startDate")]
1401 pub start_date: String,
1402 #[serde(alias = "periodMonths")]
1404 pub period_months: u32,
1405 #[serde(default = "default_currency", alias = "groupCurrency")]
1407 pub group_currency: String,
1408 #[serde(default, alias = "presentationCurrency")]
1411 pub presentation_currency: Option<String>,
1412 #[serde(default = "default_true")]
1414 pub parallel: bool,
1415 #[serde(default, alias = "workerThreads")]
1417 pub worker_threads: usize,
1418 #[serde(default, alias = "memoryLimitMb")]
1420 pub memory_limit_mb: usize,
1421 #[serde(default, alias = "fiscalYearMonths")]
1424 pub fiscal_year_months: Option<u32>,
1425}
1426
1427fn default_currency() -> String {
1428 "USD".to_string()
1429}
1430fn default_true() -> bool {
1431 true
1432}
1433
1434#[derive(Debug, Clone, Serialize, Deserialize)]
1439pub struct SessionSchemaConfig {
1440 #[serde(default)]
1442 pub enabled: bool,
1443 #[serde(default)]
1445 pub checkpoint_path: Option<String>,
1446 #[serde(default = "default_true")]
1448 pub per_period_output: bool,
1449 #[serde(default = "default_true")]
1451 pub consolidated_output: bool,
1452}
1453
1454impl Default for SessionSchemaConfig {
1455 fn default() -> Self {
1456 Self {
1457 enabled: false,
1458 checkpoint_path: None,
1459 per_period_output: true,
1460 consolidated_output: true,
1461 }
1462 }
1463}
1464
1465#[derive(Debug, Clone, Serialize, Deserialize)]
1467pub struct CompanyConfig {
1468 pub code: String,
1470 pub name: String,
1472 pub currency: String,
1474 #[serde(default, alias = "functionalCurrency")]
1477 pub functional_currency: Option<String>,
1478 pub country: String,
1480 #[serde(default = "default_fiscal_variant", alias = "fiscalYearVariant")]
1482 pub fiscal_year_variant: String,
1483 #[serde(alias = "annualTransactionVolume")]
1485 pub annual_transaction_volume: TransactionVolume,
1486 #[serde(default = "default_weight", alias = "volumeWeight")]
1488 pub volume_weight: f64,
1489}
1490
1491fn default_fiscal_variant() -> String {
1492 "K4".to_string()
1493}
1494fn default_weight() -> f64 {
1495 1.0
1496}
1497
1498#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
1500#[serde(rename_all = "snake_case")]
1501pub enum TransactionVolume {
1502 TenK,
1504 FiftyK,
1506 HundredK,
1508 OneM,
1510 TenM,
1512 HundredM,
1514 Custom(u64),
1516}
1517
1518impl TransactionVolume {
1519 pub fn count(&self) -> u64 {
1521 match self {
1522 Self::TenK => 10_000,
1523 Self::FiftyK => 50_000,
1524 Self::HundredK => 100_000,
1525 Self::OneM => 1_000_000,
1526 Self::TenM => 10_000_000,
1527 Self::HundredM => 100_000_000,
1528 Self::Custom(n) => *n,
1529 }
1530 }
1531}
1532
1533#[derive(Debug, Clone, Serialize, Deserialize)]
1535pub struct ChartOfAccountsConfig {
1536 pub complexity: CoAComplexity,
1538 #[serde(default = "default_true")]
1540 pub industry_specific: bool,
1541 pub custom_accounts: Option<PathBuf>,
1543 #[serde(default = "default_min_depth")]
1545 pub min_hierarchy_depth: u8,
1546 #[serde(default = "default_max_depth")]
1548 pub max_hierarchy_depth: u8,
1549 #[serde(default, alias = "expandIndustrySubaccounts")]
1567 pub expand_industry_subaccounts: bool,
1568}
1569
1570fn default_min_depth() -> u8 {
1571 2
1572}
1573fn default_max_depth() -> u8 {
1574 5
1575}
1576
1577impl Default for ChartOfAccountsConfig {
1578 fn default() -> Self {
1579 Self {
1580 complexity: CoAComplexity::Small,
1581 industry_specific: true,
1582 custom_accounts: None,
1583 min_hierarchy_depth: default_min_depth(),
1584 max_hierarchy_depth: default_max_depth(),
1585 expand_industry_subaccounts: false,
1586 }
1587 }
1588}
1589
1590#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1592pub struct TransactionConfig {
1593 #[serde(default)]
1595 pub line_item_distribution: LineItemDistributionConfig,
1596 #[serde(default)]
1598 pub debit_credit_distribution: DebitCreditDistributionConfig,
1599 #[serde(default)]
1601 pub even_odd_distribution: EvenOddDistributionConfig,
1602 #[serde(default)]
1604 pub source_distribution: SourceDistribution,
1605 #[serde(default)]
1607 pub seasonality: SeasonalityConfig,
1608 #[serde(default)]
1610 pub amounts: AmountDistributionConfig,
1611 #[serde(default)]
1613 pub benford: BenfordConfig,
1614}
1615
1616#[derive(Debug, Clone, Serialize, Deserialize)]
1618pub struct BenfordConfig {
1619 #[serde(default = "default_true")]
1621 pub enabled: bool,
1622 #[serde(default = "default_benford_tolerance")]
1624 pub tolerance: f64,
1625 #[serde(default)]
1627 pub exempt_sources: Vec<BenfordExemption>,
1628}
1629
1630fn default_benford_tolerance() -> f64 {
1631 0.05
1632}
1633
1634impl Default for BenfordConfig {
1635 fn default() -> Self {
1636 Self {
1637 enabled: true,
1638 tolerance: default_benford_tolerance(),
1639 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1640 }
1641 }
1642}
1643
1644#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1646#[serde(rename_all = "snake_case")]
1647pub enum BenfordExemption {
1648 Recurring,
1650 Payroll,
1652 FixedFees,
1654 RoundAmounts,
1656}
1657
1658#[derive(Debug, Clone, Serialize, Deserialize)]
1660pub struct SourceDistribution {
1661 pub manual: f64,
1663 pub automated: f64,
1665 pub recurring: f64,
1667 pub adjustment: f64,
1669}
1670
1671impl Default for SourceDistribution {
1672 fn default() -> Self {
1673 Self {
1674 manual: 0.20,
1675 automated: 0.70,
1676 recurring: 0.07,
1677 adjustment: 0.03,
1678 }
1679 }
1680}
1681
1682#[derive(Debug, Clone, Serialize, Deserialize)]
1684pub struct OutputConfig {
1685 #[serde(default)]
1687 pub mode: OutputMode,
1688 #[serde(alias = "outputDirectory")]
1690 pub output_directory: PathBuf,
1691 #[serde(
1699 default = "default_formats",
1700 alias = "exportFormats",
1701 alias = "exportFormat",
1702 deserialize_with = "one_or_many_formats"
1703 )]
1704 pub formats: Vec<FileFormat>,
1705 #[serde(default)]
1707 pub compression: CompressionConfig,
1708 #[serde(default = "default_batch_size", alias = "batchSize")]
1710 pub batch_size: usize,
1711 #[serde(default = "default_true", alias = "includeAcdoca")]
1713 pub include_acdoca: bool,
1714 #[serde(default, alias = "includeBseg")]
1716 pub include_bseg: bool,
1717 #[serde(default = "default_true", alias = "partitionByPeriod")]
1719 pub partition_by_period: bool,
1720 #[serde(default, alias = "partitionByCompany")]
1722 pub partition_by_company: bool,
1723 #[serde(default, alias = "numericMode")]
1727 pub numeric_mode: NumericMode,
1728 #[serde(default, alias = "exportLayout")]
1740 pub export_layout: ExportLayout,
1741 #[serde(default, alias = "sapExport")]
1746 pub sap: SapExportSettings,
1747 #[serde(default, alias = "saftExport")]
1753 pub saft: SaftExportSettings,
1754}
1755
1756#[derive(Debug, Clone, Serialize, Deserialize)]
1763pub struct SapExportSettings {
1764 #[serde(default = "default_sap_client")]
1766 pub client: String,
1767 #[serde(default = "default_sap_ledger")]
1769 pub ledger: String,
1770 #[serde(default = "default_sap_source_system")]
1773 pub source_system: String,
1774 #[serde(default = "default_sap_currency")]
1776 pub local_currency: String,
1777 #[serde(default, skip_serializing_if = "Option::is_none")]
1779 pub group_currency: Option<String>,
1780 #[serde(default)]
1782 pub tables: Vec<String>,
1783 #[serde(default = "default_true")]
1785 pub include_extension_fields: bool,
1786 #[serde(default)]
1788 pub dialect: SapDialectSetting,
1789 #[serde(default = "default_true")]
1792 pub use_sap_date_format: bool,
1793}
1794
1795impl Default for SapExportSettings {
1796 fn default() -> Self {
1797 Self {
1798 client: default_sap_client(),
1799 ledger: default_sap_ledger(),
1800 source_system: default_sap_source_system(),
1801 local_currency: default_sap_currency(),
1802 group_currency: None,
1803 tables: Vec::new(),
1804 include_extension_fields: true,
1805 dialect: SapDialectSetting::default(),
1806 use_sap_date_format: true,
1807 }
1808 }
1809}
1810
1811fn default_sap_client() -> String {
1812 "100".to_string()
1813}
1814fn default_sap_ledger() -> String {
1815 "0L".to_string()
1816}
1817fn default_sap_source_system() -> String {
1818 "SYNTH".to_string()
1819}
1820fn default_sap_currency() -> String {
1821 "USD".to_string()
1822}
1823
1824#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
1827#[serde(rename_all = "snake_case")]
1828pub enum SapDialectSetting {
1829 #[default]
1831 Classic,
1832 Hana,
1834}
1835
1836#[derive(Debug, Clone, Serialize, Deserialize)]
1838pub struct SaftExportSettings {
1839 #[serde(default = "default_saft_jurisdiction")]
1842 pub jurisdiction: String,
1843 #[serde(default)]
1847 pub company_tax_id: String,
1848 #[serde(default)]
1851 pub company_name: String,
1852}
1853
1854impl Default for SaftExportSettings {
1855 fn default() -> Self {
1856 Self {
1857 jurisdiction: default_saft_jurisdiction(),
1858 company_tax_id: String::new(),
1859 company_name: String::new(),
1860 }
1861 }
1862}
1863
1864fn default_saft_jurisdiction() -> String {
1865 "pt".to_string()
1866}
1867
1868fn default_formats() -> Vec<FileFormat> {
1869 vec![FileFormat::Parquet]
1870}
1871fn default_batch_size() -> usize {
1872 100_000
1873}
1874
1875fn one_or_many_formats<'de, D>(deserializer: D) -> Result<Vec<FileFormat>, D::Error>
1881where
1882 D: serde::Deserializer<'de>,
1883{
1884 #[derive(Deserialize)]
1885 #[serde(untagged)]
1886 enum OneOrMany {
1887 One(FileFormat),
1888 Many(Vec<FileFormat>),
1889 }
1890 match OneOrMany::deserialize(deserializer)? {
1891 OneOrMany::One(f) => Ok(vec![f]),
1892 OneOrMany::Many(v) => Ok(v),
1893 }
1894}
1895
1896impl Default for OutputConfig {
1897 fn default() -> Self {
1898 Self {
1899 mode: OutputMode::FlatFile,
1900 output_directory: PathBuf::from("./output"),
1901 formats: default_formats(),
1902 compression: CompressionConfig::default(),
1903 batch_size: default_batch_size(),
1904 include_acdoca: true,
1905 include_bseg: false,
1906 partition_by_period: true,
1907 partition_by_company: false,
1908 numeric_mode: NumericMode::default(),
1909 export_layout: ExportLayout::default(),
1910 sap: SapExportSettings::default(),
1911 saft: SaftExportSettings::default(),
1912 }
1913 }
1914}
1915
1916#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1918#[serde(rename_all = "snake_case")]
1919pub enum NumericMode {
1920 #[default]
1922 String,
1923 Native,
1925}
1926
1927#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1929#[serde(rename_all = "snake_case")]
1930pub enum ExportLayout {
1931 #[default]
1933 Nested,
1934 Flat,
1936}
1937
1938#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1940#[serde(rename_all = "snake_case")]
1941pub enum OutputMode {
1942 Streaming,
1944 #[default]
1946 FlatFile,
1947 Both,
1949}
1950
1951#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1953#[serde(rename_all = "snake_case")]
1954pub enum FileFormat {
1955 Csv,
1956 Parquet,
1957 Json,
1958 JsonLines,
1959}
1960
1961#[derive(Debug, Clone, Serialize, Deserialize)]
1963pub struct CompressionConfig {
1964 #[serde(default = "default_true")]
1966 pub enabled: bool,
1967 #[serde(default)]
1969 pub algorithm: CompressionAlgorithm,
1970 #[serde(default = "default_compression_level")]
1972 pub level: u8,
1973}
1974
1975fn default_compression_level() -> u8 {
1976 3
1977}
1978
1979impl Default for CompressionConfig {
1980 fn default() -> Self {
1981 Self {
1982 enabled: true,
1983 algorithm: CompressionAlgorithm::default(),
1984 level: default_compression_level(),
1985 }
1986 }
1987}
1988
1989#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1991#[serde(rename_all = "snake_case")]
1992pub enum CompressionAlgorithm {
1993 Gzip,
1994 #[default]
1995 Zstd,
1996 Lz4,
1997 Snappy,
1998}
1999
2000#[derive(Debug, Clone, Serialize, Deserialize)]
2020pub struct FraudConfig {
2021 #[serde(default)]
2023 pub enabled: bool,
2024 #[serde(default = "default_fraud_rate", alias = "fraudRate")]
2042 pub fraud_rate: f64,
2043 #[serde(default = "default_document_fraud_rate", alias = "documentFraudRate")]
2056 pub document_fraud_rate: Option<f64>,
2057 #[serde(default = "default_true", alias = "propagateToLines")]
2062 pub propagate_to_lines: bool,
2063 #[serde(default = "default_true", alias = "propagateToDocument")]
2067 pub propagate_to_document: bool,
2068 #[serde(default)]
2070 pub fraud_type_distribution: FraudTypeDistribution,
2071 #[serde(default)]
2073 pub clustering_enabled: bool,
2074 #[serde(default = "default_clustering_factor")]
2076 pub clustering_factor: f64,
2077 #[serde(default = "default_approval_thresholds")]
2079 pub approval_thresholds: Vec<f64>,
2080}
2081
2082fn default_approval_thresholds() -> Vec<f64> {
2083 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
2084}
2085
2086fn default_fraud_rate() -> f64 {
2087 0.005
2088}
2089fn default_document_fraud_rate() -> Option<f64> {
2090 Some(0.05)
2100}
2101fn default_clustering_factor() -> f64 {
2102 3.0
2103}
2104
2105impl Default for FraudConfig {
2106 fn default() -> Self {
2107 Self {
2108 enabled: false,
2109 fraud_rate: default_fraud_rate(),
2110 document_fraud_rate: default_document_fraud_rate(),
2111 propagate_to_lines: true,
2112 propagate_to_document: true,
2113 fraud_type_distribution: FraudTypeDistribution::default(),
2114 clustering_enabled: false,
2115 clustering_factor: default_clustering_factor(),
2116 approval_thresholds: default_approval_thresholds(),
2117 }
2118 }
2119}
2120
2121#[derive(Debug, Clone, Serialize, Deserialize)]
2127#[serde(deny_unknown_fields)]
2128pub struct FraudTypeDistribution {
2129 #[serde(default)]
2130 pub suspense_account_abuse: f64,
2131 #[serde(default)]
2132 pub fictitious_transaction: f64,
2133 #[serde(default)]
2134 pub revenue_manipulation: f64,
2135 #[serde(default)]
2136 pub expense_capitalization: f64,
2137 #[serde(default)]
2138 pub split_transaction: f64,
2139 #[serde(default)]
2140 pub timing_anomaly: f64,
2141 #[serde(default)]
2142 pub unauthorized_access: f64,
2143 #[serde(default)]
2144 pub duplicate_payment: f64,
2145 #[serde(default)]
2147 pub kickback_scheme: f64,
2148 #[serde(default)]
2150 pub round_tripping: f64,
2151 #[serde(default)]
2153 pub unauthorized_discount: f64,
2154}
2155
2156impl Default for FraudTypeDistribution {
2157 fn default() -> Self {
2158 Self {
2166 suspense_account_abuse: 0.25,
2167 fictitious_transaction: 0.15,
2168 revenue_manipulation: 0.10,
2169 expense_capitalization: 0.10,
2170 split_transaction: 0.15,
2171 timing_anomaly: 0.10,
2172 unauthorized_access: 0.10,
2173 duplicate_payment: 0.05,
2174 kickback_scheme: 0.0,
2175 round_tripping: 0.0,
2176 unauthorized_discount: 0.0,
2177 }
2178 }
2179}
2180
2181#[derive(Debug, Clone, Serialize, Deserialize)]
2183pub struct InternalControlsConfig {
2184 #[serde(default)]
2186 pub enabled: bool,
2187 #[serde(default = "default_exception_rate")]
2189 pub exception_rate: f64,
2190 #[serde(default = "default_sod_violation_rate")]
2192 pub sod_violation_rate: f64,
2193 #[serde(default = "default_true")]
2195 pub export_control_master_data: bool,
2196 #[serde(default = "default_sox_materiality_threshold")]
2198 pub sox_materiality_threshold: f64,
2199 #[serde(default = "default_true")]
2201 pub coso_enabled: bool,
2202 #[serde(default)]
2204 pub include_entity_level_controls: bool,
2205 #[serde(default = "default_target_maturity_level")]
2208 pub target_maturity_level: String,
2209}
2210
2211fn default_exception_rate() -> f64 {
2212 0.02
2213}
2214
2215fn default_sod_violation_rate() -> f64 {
2216 0.01
2217}
2218
2219fn default_sox_materiality_threshold() -> f64 {
2220 10000.0
2221}
2222
2223fn default_target_maturity_level() -> String {
2224 "mixed".to_string()
2225}
2226
2227impl Default for InternalControlsConfig {
2228 fn default() -> Self {
2229 Self {
2230 enabled: false,
2231 exception_rate: default_exception_rate(),
2232 sod_violation_rate: default_sod_violation_rate(),
2233 export_control_master_data: true,
2234 sox_materiality_threshold: default_sox_materiality_threshold(),
2235 coso_enabled: true,
2236 include_entity_level_controls: false,
2237 target_maturity_level: default_target_maturity_level(),
2238 }
2239 }
2240}
2241
2242#[derive(Debug, Clone, Serialize, Deserialize)]
2244pub struct BusinessProcessConfig {
2245 #[serde(default = "default_o2c")]
2247 pub o2c_weight: f64,
2248 #[serde(default = "default_p2p")]
2250 pub p2p_weight: f64,
2251 #[serde(default = "default_r2r")]
2253 pub r2r_weight: f64,
2254 #[serde(default = "default_h2r")]
2256 pub h2r_weight: f64,
2257 #[serde(default = "default_a2r")]
2259 pub a2r_weight: f64,
2260}
2261
2262fn default_o2c() -> f64 {
2263 0.35
2264}
2265fn default_p2p() -> f64 {
2266 0.30
2267}
2268fn default_r2r() -> f64 {
2269 0.20
2270}
2271fn default_h2r() -> f64 {
2272 0.10
2273}
2274fn default_a2r() -> f64 {
2275 0.05
2276}
2277
2278impl Default for BusinessProcessConfig {
2279 fn default() -> Self {
2280 Self {
2281 o2c_weight: default_o2c(),
2282 p2p_weight: default_p2p(),
2283 r2r_weight: default_r2r(),
2284 h2r_weight: default_h2r(),
2285 a2r_weight: default_a2r(),
2286 }
2287 }
2288}
2289
2290#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2292pub struct UserPersonaConfig {
2293 #[serde(default)]
2295 pub persona_distribution: PersonaDistribution,
2296 #[serde(default)]
2298 pub users_per_persona: UsersPerPersona,
2299}
2300
2301#[derive(Debug, Clone, Serialize, Deserialize)]
2303pub struct PersonaDistribution {
2304 pub junior_accountant: f64,
2305 pub senior_accountant: f64,
2306 pub controller: f64,
2307 pub manager: f64,
2308 pub automated_system: f64,
2309}
2310
2311impl Default for PersonaDistribution {
2312 fn default() -> Self {
2313 Self {
2314 junior_accountant: 0.15,
2315 senior_accountant: 0.15,
2316 controller: 0.05,
2317 manager: 0.05,
2318 automated_system: 0.60,
2319 }
2320 }
2321}
2322
2323#[derive(Debug, Clone, Serialize, Deserialize)]
2325pub struct UsersPerPersona {
2326 pub junior_accountant: usize,
2327 pub senior_accountant: usize,
2328 pub controller: usize,
2329 pub manager: usize,
2330 pub automated_system: usize,
2331}
2332
2333impl Default for UsersPerPersona {
2334 fn default() -> Self {
2335 Self {
2336 junior_accountant: 10,
2337 senior_accountant: 5,
2338 controller: 2,
2339 manager: 3,
2340 automated_system: 20,
2341 }
2342 }
2343}
2344
2345#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2359pub struct TemplateConfig {
2360 #[serde(default)]
2362 pub names: NameTemplateConfig,
2363 #[serde(default)]
2365 pub descriptions: DescriptionTemplateConfig,
2366 #[serde(default)]
2368 pub references: ReferenceTemplateConfig,
2369 #[serde(default, alias = "templatesPath")]
2375 pub path: Option<std::path::PathBuf>,
2376 #[serde(default, alias = "mergeStrategy")]
2385 pub merge_strategy: TemplateMergeStrategy,
2386}
2387
2388#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
2390#[serde(rename_all = "snake_case")]
2391pub enum TemplateMergeStrategy {
2392 #[default]
2394 Extend,
2395 Replace,
2397 MergePreferFile,
2399}
2400
2401#[derive(Debug, Clone, Serialize, Deserialize)]
2403pub struct NameTemplateConfig {
2404 #[serde(default)]
2406 pub culture_distribution: CultureDistribution,
2407 #[serde(default = "default_email_domain")]
2409 pub email_domain: String,
2410 #[serde(default = "default_true")]
2412 pub generate_realistic_names: bool,
2413}
2414
2415fn default_email_domain() -> String {
2416 "company.com".to_string()
2417}
2418
2419impl Default for NameTemplateConfig {
2420 fn default() -> Self {
2421 Self {
2422 culture_distribution: CultureDistribution::default(),
2423 email_domain: default_email_domain(),
2424 generate_realistic_names: true,
2425 }
2426 }
2427}
2428
2429#[derive(Debug, Clone, Serialize, Deserialize)]
2431pub struct CultureDistribution {
2432 pub western_us: f64,
2433 pub hispanic: f64,
2434 pub german: f64,
2435 pub french: f64,
2436 pub chinese: f64,
2437 pub japanese: f64,
2438 pub indian: f64,
2439}
2440
2441impl Default for CultureDistribution {
2442 fn default() -> Self {
2443 Self {
2444 western_us: 0.40,
2445 hispanic: 0.20,
2446 german: 0.10,
2447 french: 0.05,
2448 chinese: 0.10,
2449 japanese: 0.05,
2450 indian: 0.10,
2451 }
2452 }
2453}
2454
2455#[derive(Debug, Clone, Serialize, Deserialize)]
2457pub struct DescriptionTemplateConfig {
2458 #[serde(default = "default_true")]
2460 pub generate_header_text: bool,
2461 #[serde(default = "default_true")]
2463 pub generate_line_text: bool,
2464}
2465
2466impl Default for DescriptionTemplateConfig {
2467 fn default() -> Self {
2468 Self {
2469 generate_header_text: true,
2470 generate_line_text: true,
2471 }
2472 }
2473}
2474
2475#[derive(Debug, Clone, Serialize, Deserialize)]
2477pub struct ReferenceTemplateConfig {
2478 #[serde(default = "default_true")]
2480 pub generate_references: bool,
2481 #[serde(default = "default_invoice_prefix")]
2483 pub invoice_prefix: String,
2484 #[serde(default = "default_po_prefix")]
2486 pub po_prefix: String,
2487 #[serde(default = "default_so_prefix")]
2489 pub so_prefix: String,
2490}
2491
2492fn default_invoice_prefix() -> String {
2493 "INV".to_string()
2494}
2495fn default_po_prefix() -> String {
2496 "PO".to_string()
2497}
2498fn default_so_prefix() -> String {
2499 "SO".to_string()
2500}
2501
2502impl Default for ReferenceTemplateConfig {
2503 fn default() -> Self {
2504 Self {
2505 generate_references: true,
2506 invoice_prefix: default_invoice_prefix(),
2507 po_prefix: default_po_prefix(),
2508 so_prefix: default_so_prefix(),
2509 }
2510 }
2511}
2512
2513#[derive(Debug, Clone, Serialize, Deserialize)]
2515pub struct ApprovalConfig {
2516 #[serde(default)]
2518 pub enabled: bool,
2519 #[serde(default = "default_auto_approve_threshold")]
2521 pub auto_approve_threshold: f64,
2522 #[serde(default = "default_rejection_rate")]
2524 pub rejection_rate: f64,
2525 #[serde(default = "default_revision_rate")]
2527 pub revision_rate: f64,
2528 #[serde(default = "default_approval_delay_hours")]
2530 pub average_approval_delay_hours: f64,
2531 #[serde(default)]
2533 pub thresholds: Vec<ApprovalThresholdConfig>,
2534}
2535
2536fn default_auto_approve_threshold() -> f64 {
2537 1000.0
2538}
2539fn default_rejection_rate() -> f64 {
2540 0.02
2541}
2542fn default_revision_rate() -> f64 {
2543 0.05
2544}
2545fn default_approval_delay_hours() -> f64 {
2546 4.0
2547}
2548
2549impl Default for ApprovalConfig {
2550 fn default() -> Self {
2551 Self {
2552 enabled: false,
2553 auto_approve_threshold: default_auto_approve_threshold(),
2554 rejection_rate: default_rejection_rate(),
2555 revision_rate: default_revision_rate(),
2556 average_approval_delay_hours: default_approval_delay_hours(),
2557 thresholds: vec![
2558 ApprovalThresholdConfig {
2559 amount: 1000.0,
2560 level: 1,
2561 roles: vec!["senior_accountant".to_string()],
2562 },
2563 ApprovalThresholdConfig {
2564 amount: 10000.0,
2565 level: 2,
2566 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2567 },
2568 ApprovalThresholdConfig {
2569 amount: 100000.0,
2570 level: 3,
2571 roles: vec![
2572 "senior_accountant".to_string(),
2573 "controller".to_string(),
2574 "manager".to_string(),
2575 ],
2576 },
2577 ApprovalThresholdConfig {
2578 amount: 500000.0,
2579 level: 4,
2580 roles: vec![
2581 "senior_accountant".to_string(),
2582 "controller".to_string(),
2583 "manager".to_string(),
2584 "executive".to_string(),
2585 ],
2586 },
2587 ],
2588 }
2589 }
2590}
2591
2592#[derive(Debug, Clone, Serialize, Deserialize)]
2594pub struct ApprovalThresholdConfig {
2595 pub amount: f64,
2597 pub level: u8,
2599 pub roles: Vec<String>,
2601}
2602
2603#[derive(Debug, Clone, Serialize, Deserialize)]
2605pub struct DepartmentConfig {
2606 #[serde(default)]
2608 pub enabled: bool,
2609 #[serde(default = "default_headcount_multiplier")]
2611 pub headcount_multiplier: f64,
2612 #[serde(default)]
2614 pub custom_departments: Vec<CustomDepartmentConfig>,
2615}
2616
2617fn default_headcount_multiplier() -> f64 {
2618 1.0
2619}
2620
2621impl Default for DepartmentConfig {
2622 fn default() -> Self {
2623 Self {
2624 enabled: false,
2625 headcount_multiplier: default_headcount_multiplier(),
2626 custom_departments: Vec::new(),
2627 }
2628 }
2629}
2630
2631#[derive(Debug, Clone, Serialize, Deserialize)]
2633pub struct CustomDepartmentConfig {
2634 pub code: String,
2636 pub name: String,
2638 #[serde(default)]
2640 pub cost_center: Option<String>,
2641 #[serde(default)]
2643 pub primary_processes: Vec<String>,
2644 #[serde(default)]
2646 pub parent_code: Option<String>,
2647}
2648
2649#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2655pub struct MasterDataConfig {
2656 #[serde(default)]
2658 pub vendors: VendorMasterConfig,
2659 #[serde(default)]
2661 pub customers: CustomerMasterConfig,
2662 #[serde(default)]
2664 pub materials: MaterialMasterConfig,
2665 #[serde(default)]
2667 pub fixed_assets: FixedAssetMasterConfig,
2668 #[serde(default)]
2670 pub employees: EmployeeMasterConfig,
2671 #[serde(default)]
2673 pub cost_centers: CostCenterMasterConfig,
2674}
2675
2676#[derive(Debug, Clone, Serialize, Deserialize)]
2678pub struct VendorMasterConfig {
2679 #[serde(default = "default_vendor_count")]
2681 pub count: usize,
2682 #[serde(default = "default_intercompany_percent")]
2684 pub intercompany_percent: f64,
2685 #[serde(default)]
2687 pub payment_terms_distribution: PaymentTermsDistribution,
2688 #[serde(default)]
2690 pub behavior_distribution: VendorBehaviorDistribution,
2691 #[serde(default = "default_true")]
2693 pub generate_bank_accounts: bool,
2694 #[serde(default = "default_true")]
2696 pub generate_tax_ids: bool,
2697}
2698
2699fn default_vendor_count() -> usize {
2700 500
2701}
2702
2703fn default_intercompany_percent() -> f64 {
2704 0.05
2705}
2706
2707impl Default for VendorMasterConfig {
2708 fn default() -> Self {
2709 Self {
2710 count: default_vendor_count(),
2711 intercompany_percent: default_intercompany_percent(),
2712 payment_terms_distribution: PaymentTermsDistribution::default(),
2713 behavior_distribution: VendorBehaviorDistribution::default(),
2714 generate_bank_accounts: true,
2715 generate_tax_ids: true,
2716 }
2717 }
2718}
2719
2720#[derive(Debug, Clone, Serialize, Deserialize)]
2722pub struct PaymentTermsDistribution {
2723 pub net_30: f64,
2725 pub net_60: f64,
2727 pub net_90: f64,
2729 pub two_ten_net_30: f64,
2731 pub due_on_receipt: f64,
2733 pub end_of_month: f64,
2735}
2736
2737impl Default for PaymentTermsDistribution {
2738 fn default() -> Self {
2739 Self {
2740 net_30: 0.40,
2741 net_60: 0.20,
2742 net_90: 0.10,
2743 two_ten_net_30: 0.15,
2744 due_on_receipt: 0.05,
2745 end_of_month: 0.10,
2746 }
2747 }
2748}
2749
2750#[derive(Debug, Clone, Serialize, Deserialize)]
2756#[serde(deny_unknown_fields)]
2757pub struct VendorBehaviorDistribution {
2758 #[serde(default)]
2760 pub reliable: f64,
2761 #[serde(default)]
2763 pub sometimes_late: f64,
2764 #[serde(default)]
2766 pub inconsistent_quality: f64,
2767 #[serde(default)]
2769 pub premium: f64,
2770 #[serde(default)]
2772 pub budget: f64,
2773 #[serde(default)]
2775 pub erratic: f64,
2776 #[serde(default)]
2778 pub problematic: f64,
2779}
2780
2781impl Default for VendorBehaviorDistribution {
2782 fn default() -> Self {
2783 Self {
2788 reliable: 0.50,
2789 sometimes_late: 0.20,
2790 inconsistent_quality: 0.10,
2791 premium: 0.10,
2792 budget: 0.10,
2793 erratic: 0.0,
2794 problematic: 0.0,
2795 }
2796 }
2797}
2798
2799#[derive(Debug, Clone, Serialize, Deserialize)]
2801pub struct CustomerMasterConfig {
2802 #[serde(default = "default_customer_count")]
2804 pub count: usize,
2805 #[serde(default = "default_intercompany_percent")]
2807 pub intercompany_percent: f64,
2808 #[serde(default)]
2810 pub credit_rating_distribution: CreditRatingDistribution,
2811 #[serde(default)]
2813 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2814 #[serde(default = "default_true")]
2816 pub generate_credit_limits: bool,
2817}
2818
2819fn default_customer_count() -> usize {
2820 2000
2821}
2822
2823impl Default for CustomerMasterConfig {
2824 fn default() -> Self {
2825 Self {
2826 count: default_customer_count(),
2827 intercompany_percent: default_intercompany_percent(),
2828 credit_rating_distribution: CreditRatingDistribution::default(),
2829 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2830 generate_credit_limits: true,
2831 }
2832 }
2833}
2834
2835#[derive(Debug, Clone, Serialize, Deserialize)]
2844#[serde(deny_unknown_fields)]
2845pub struct CreditRatingDistribution {
2846 #[serde(default)]
2848 pub aaa: f64,
2849 #[serde(default)]
2851 pub aa: f64,
2852 #[serde(default)]
2854 pub a: f64,
2855 #[serde(default)]
2857 pub bbb: f64,
2858 #[serde(default)]
2860 pub bb: f64,
2861 #[serde(default)]
2863 pub b: f64,
2864 #[serde(default)]
2866 pub below_b: f64,
2867 #[serde(default)]
2869 pub excellent: f64,
2870 #[serde(default)]
2872 pub good: f64,
2873 #[serde(default)]
2875 pub fair: f64,
2876 #[serde(default)]
2878 pub poor: f64,
2879}
2880
2881impl Default for CreditRatingDistribution {
2882 fn default() -> Self {
2883 Self {
2884 aaa: 0.05,
2885 aa: 0.10,
2886 a: 0.20,
2887 bbb: 0.30,
2888 bb: 0.20,
2889 b: 0.10,
2890 below_b: 0.05,
2891 excellent: 0.0,
2892 good: 0.0,
2893 fair: 0.0,
2894 poor: 0.0,
2895 }
2896 }
2897}
2898
2899#[derive(Debug, Clone, Serialize, Deserialize)]
2904#[serde(deny_unknown_fields)]
2905pub struct PaymentBehaviorDistribution {
2906 #[serde(default)]
2908 pub early_payer: f64,
2909 #[serde(default)]
2911 pub on_time: f64,
2912 #[serde(default)]
2914 pub occasional_late: f64,
2915 #[serde(default)]
2917 pub frequent_late: f64,
2918 #[serde(default)]
2920 pub discount_taker: f64,
2921}
2922
2923impl Default for PaymentBehaviorDistribution {
2924 fn default() -> Self {
2925 Self {
2926 early_payer: 0.10,
2927 on_time: 0.50,
2928 occasional_late: 0.25,
2929 frequent_late: 0.10,
2930 discount_taker: 0.05,
2931 }
2932 }
2933}
2934
2935#[derive(Debug, Clone, Serialize, Deserialize)]
2937pub struct MaterialMasterConfig {
2938 #[serde(default = "default_material_count")]
2940 pub count: usize,
2941 #[serde(default)]
2943 pub type_distribution: MaterialTypeDistribution,
2944 #[serde(default)]
2946 pub valuation_distribution: ValuationMethodDistribution,
2947 #[serde(default = "default_bom_percent")]
2949 pub bom_percent: f64,
2950 #[serde(default = "default_max_bom_depth")]
2952 pub max_bom_depth: u8,
2953}
2954
2955fn default_material_count() -> usize {
2956 5000
2957}
2958
2959fn default_bom_percent() -> f64 {
2960 0.20
2961}
2962
2963fn default_max_bom_depth() -> u8 {
2964 3
2965}
2966
2967impl Default for MaterialMasterConfig {
2968 fn default() -> Self {
2969 Self {
2970 count: default_material_count(),
2971 type_distribution: MaterialTypeDistribution::default(),
2972 valuation_distribution: ValuationMethodDistribution::default(),
2973 bom_percent: default_bom_percent(),
2974 max_bom_depth: default_max_bom_depth(),
2975 }
2976 }
2977}
2978
2979#[derive(Debug, Clone, Serialize, Deserialize)]
2981pub struct MaterialTypeDistribution {
2982 pub raw_material: f64,
2984 pub semi_finished: f64,
2986 pub finished_good: f64,
2988 pub trading_good: f64,
2990 pub operating_supply: f64,
2992 pub service: f64,
2994}
2995
2996impl Default for MaterialTypeDistribution {
2997 fn default() -> Self {
2998 Self {
2999 raw_material: 0.30,
3000 semi_finished: 0.15,
3001 finished_good: 0.25,
3002 trading_good: 0.15,
3003 operating_supply: 0.10,
3004 service: 0.05,
3005 }
3006 }
3007}
3008
3009#[derive(Debug, Clone, Serialize, Deserialize)]
3011pub struct ValuationMethodDistribution {
3012 pub standard_cost: f64,
3014 pub moving_average: f64,
3016 pub fifo: f64,
3018 pub lifo: f64,
3020}
3021
3022impl Default for ValuationMethodDistribution {
3023 fn default() -> Self {
3024 Self {
3025 standard_cost: 0.50,
3026 moving_average: 0.30,
3027 fifo: 0.15,
3028 lifo: 0.05,
3029 }
3030 }
3031}
3032
3033#[derive(Debug, Clone, Serialize, Deserialize)]
3035pub struct FixedAssetMasterConfig {
3036 #[serde(default = "default_asset_count")]
3038 pub count: usize,
3039 #[serde(default)]
3041 pub class_distribution: AssetClassDistribution,
3042 #[serde(default)]
3044 pub depreciation_distribution: DepreciationMethodDistribution,
3045 #[serde(default = "default_fully_depreciated_percent")]
3047 pub fully_depreciated_percent: f64,
3048 #[serde(default = "default_true")]
3050 pub generate_acquisition_history: bool,
3051}
3052
3053fn default_asset_count() -> usize {
3054 800
3055}
3056
3057fn default_fully_depreciated_percent() -> f64 {
3058 0.15
3059}
3060
3061impl Default for FixedAssetMasterConfig {
3062 fn default() -> Self {
3063 Self {
3064 count: default_asset_count(),
3065 class_distribution: AssetClassDistribution::default(),
3066 depreciation_distribution: DepreciationMethodDistribution::default(),
3067 fully_depreciated_percent: default_fully_depreciated_percent(),
3068 generate_acquisition_history: true,
3069 }
3070 }
3071}
3072
3073#[derive(Debug, Clone, Serialize, Deserialize)]
3075pub struct AssetClassDistribution {
3076 pub buildings: f64,
3078 pub machinery: f64,
3080 pub vehicles: f64,
3082 pub it_equipment: f64,
3084 pub furniture: f64,
3086 pub land: f64,
3088 pub leasehold: f64,
3090}
3091
3092impl Default for AssetClassDistribution {
3093 fn default() -> Self {
3094 Self {
3095 buildings: 0.15,
3096 machinery: 0.30,
3097 vehicles: 0.15,
3098 it_equipment: 0.20,
3099 furniture: 0.10,
3100 land: 0.05,
3101 leasehold: 0.05,
3102 }
3103 }
3104}
3105
3106#[derive(Debug, Clone, Serialize, Deserialize)]
3108pub struct DepreciationMethodDistribution {
3109 pub straight_line: f64,
3111 pub declining_balance: f64,
3113 pub double_declining: f64,
3115 pub sum_of_years: f64,
3117 pub units_of_production: f64,
3119}
3120
3121impl Default for DepreciationMethodDistribution {
3122 fn default() -> Self {
3123 Self {
3124 straight_line: 0.60,
3125 declining_balance: 0.20,
3126 double_declining: 0.10,
3127 sum_of_years: 0.05,
3128 units_of_production: 0.05,
3129 }
3130 }
3131}
3132
3133#[derive(Debug, Clone, Serialize, Deserialize)]
3135pub struct EmployeeMasterConfig {
3136 #[serde(default = "default_employee_count")]
3138 pub count: usize,
3139 #[serde(default = "default_true")]
3141 pub generate_hierarchy: bool,
3142 #[serde(default = "default_hierarchy_depth")]
3144 pub max_hierarchy_depth: u8,
3145 #[serde(default = "default_span_of_control")]
3147 pub average_span_of_control: f64,
3148 #[serde(default)]
3150 pub approval_limits: ApprovalLimitDistribution,
3151 #[serde(default)]
3153 pub department_distribution: EmployeeDepartmentDistribution,
3154}
3155
3156fn default_employee_count() -> usize {
3157 1500
3158}
3159
3160fn default_hierarchy_depth() -> u8 {
3161 6
3162}
3163
3164fn default_span_of_control() -> f64 {
3165 5.0
3166}
3167
3168impl Default for EmployeeMasterConfig {
3169 fn default() -> Self {
3170 Self {
3171 count: default_employee_count(),
3172 generate_hierarchy: true,
3173 max_hierarchy_depth: default_hierarchy_depth(),
3174 average_span_of_control: default_span_of_control(),
3175 approval_limits: ApprovalLimitDistribution::default(),
3176 department_distribution: EmployeeDepartmentDistribution::default(),
3177 }
3178 }
3179}
3180
3181#[derive(Debug, Clone, Serialize, Deserialize)]
3183pub struct ApprovalLimitDistribution {
3184 #[serde(default = "default_staff_limit")]
3186 pub staff: f64,
3187 #[serde(default = "default_senior_limit")]
3189 pub senior: f64,
3190 #[serde(default = "default_manager_limit")]
3192 pub manager: f64,
3193 #[serde(default = "default_director_limit")]
3195 pub director: f64,
3196 #[serde(default = "default_vp_limit")]
3198 pub vp: f64,
3199 #[serde(default = "default_executive_limit")]
3201 pub executive: f64,
3202}
3203
3204fn default_staff_limit() -> f64 {
3205 1000.0
3206}
3207fn default_senior_limit() -> f64 {
3208 5000.0
3209}
3210fn default_manager_limit() -> f64 {
3211 25000.0
3212}
3213fn default_director_limit() -> f64 {
3214 100000.0
3215}
3216fn default_vp_limit() -> f64 {
3217 500000.0
3218}
3219fn default_executive_limit() -> f64 {
3220 f64::INFINITY
3221}
3222
3223impl Default for ApprovalLimitDistribution {
3224 fn default() -> Self {
3225 Self {
3226 staff: default_staff_limit(),
3227 senior: default_senior_limit(),
3228 manager: default_manager_limit(),
3229 director: default_director_limit(),
3230 vp: default_vp_limit(),
3231 executive: default_executive_limit(),
3232 }
3233 }
3234}
3235
3236#[derive(Debug, Clone, Serialize, Deserialize)]
3238pub struct EmployeeDepartmentDistribution {
3239 pub finance: f64,
3241 pub procurement: f64,
3243 pub sales: f64,
3245 pub warehouse: f64,
3247 pub it: f64,
3249 pub hr: f64,
3251 pub operations: f64,
3253 pub executive: f64,
3255}
3256
3257impl Default for EmployeeDepartmentDistribution {
3258 fn default() -> Self {
3259 Self {
3260 finance: 0.12,
3261 procurement: 0.10,
3262 sales: 0.25,
3263 warehouse: 0.15,
3264 it: 0.10,
3265 hr: 0.05,
3266 operations: 0.20,
3267 executive: 0.03,
3268 }
3269 }
3270}
3271
3272#[derive(Debug, Clone, Serialize, Deserialize)]
3274pub struct CostCenterMasterConfig {
3275 #[serde(default = "default_cost_center_count")]
3277 pub count: usize,
3278 #[serde(default = "default_true")]
3280 pub generate_hierarchy: bool,
3281 #[serde(default = "default_cc_hierarchy_depth")]
3283 pub max_hierarchy_depth: u8,
3284}
3285
3286fn default_cost_center_count() -> usize {
3287 50
3288}
3289
3290fn default_cc_hierarchy_depth() -> u8 {
3291 3
3292}
3293
3294impl Default for CostCenterMasterConfig {
3295 fn default() -> Self {
3296 Self {
3297 count: default_cost_center_count(),
3298 generate_hierarchy: true,
3299 max_hierarchy_depth: default_cc_hierarchy_depth(),
3300 }
3301 }
3302}
3303
3304#[derive(Debug, Clone, Serialize, Deserialize)]
3310pub struct DocumentFlowConfig {
3311 #[serde(default)]
3313 pub p2p: P2PFlowConfig,
3314 #[serde(default)]
3316 pub o2c: O2CFlowConfig,
3317 #[serde(default = "default_true")]
3319 pub generate_document_references: bool,
3320 #[serde(default)]
3322 pub export_flow_graph: bool,
3323}
3324
3325impl Default for DocumentFlowConfig {
3326 fn default() -> Self {
3327 Self {
3328 p2p: P2PFlowConfig::default(),
3329 o2c: O2CFlowConfig::default(),
3330 generate_document_references: true,
3331 export_flow_graph: false,
3332 }
3333 }
3334}
3335
3336#[derive(Debug, Clone, Serialize, Deserialize)]
3338pub struct P2PFlowConfig {
3339 #[serde(default = "default_true")]
3341 pub enabled: bool,
3342 #[serde(default = "default_three_way_match_rate")]
3344 pub three_way_match_rate: f64,
3345 #[serde(default = "default_partial_delivery_rate")]
3347 pub partial_delivery_rate: f64,
3348 #[serde(default = "default_price_variance_rate")]
3350 pub price_variance_rate: f64,
3351 #[serde(default = "default_max_price_variance")]
3353 pub max_price_variance_percent: f64,
3354 #[serde(default = "default_quantity_variance_rate")]
3356 pub quantity_variance_rate: f64,
3357 #[serde(default = "default_po_to_gr_days")]
3359 pub average_po_to_gr_days: u32,
3360 #[serde(default = "default_gr_to_invoice_days")]
3362 pub average_gr_to_invoice_days: u32,
3363 #[serde(default = "default_invoice_to_payment_days")]
3365 pub average_invoice_to_payment_days: u32,
3366 #[serde(default)]
3368 pub line_count_distribution: DocumentLineCountDistribution,
3369 #[serde(default)]
3371 pub payment_behavior: P2PPaymentBehaviorConfig,
3372 #[serde(default)]
3374 pub over_delivery_rate: Option<f64>,
3375 #[serde(default)]
3377 pub early_payment_discount_rate: Option<f64>,
3378}
3379
3380fn default_three_way_match_rate() -> f64 {
3381 0.95
3382}
3383
3384fn default_partial_delivery_rate() -> f64 {
3385 0.15
3386}
3387
3388fn default_price_variance_rate() -> f64 {
3389 0.08
3390}
3391
3392fn default_max_price_variance() -> f64 {
3393 0.05
3394}
3395
3396fn default_quantity_variance_rate() -> f64 {
3397 0.05
3398}
3399
3400fn default_po_to_gr_days() -> u32 {
3401 14
3402}
3403
3404fn default_gr_to_invoice_days() -> u32 {
3405 5
3406}
3407
3408fn default_invoice_to_payment_days() -> u32 {
3409 30
3410}
3411
3412impl Default for P2PFlowConfig {
3413 fn default() -> Self {
3414 Self {
3415 enabled: true,
3416 three_way_match_rate: default_three_way_match_rate(),
3417 partial_delivery_rate: default_partial_delivery_rate(),
3418 price_variance_rate: default_price_variance_rate(),
3419 max_price_variance_percent: default_max_price_variance(),
3420 quantity_variance_rate: default_quantity_variance_rate(),
3421 average_po_to_gr_days: default_po_to_gr_days(),
3422 average_gr_to_invoice_days: default_gr_to_invoice_days(),
3423 average_invoice_to_payment_days: default_invoice_to_payment_days(),
3424 line_count_distribution: DocumentLineCountDistribution::default(),
3425 payment_behavior: P2PPaymentBehaviorConfig::default(),
3426 over_delivery_rate: None,
3427 early_payment_discount_rate: None,
3428 }
3429 }
3430}
3431
3432#[derive(Debug, Clone, Serialize, Deserialize)]
3438pub struct P2PPaymentBehaviorConfig {
3439 #[serde(default = "default_p2p_late_payment_rate")]
3441 pub late_payment_rate: f64,
3442 #[serde(default)]
3444 pub late_payment_days_distribution: LatePaymentDaysDistribution,
3445 #[serde(default = "default_p2p_partial_payment_rate")]
3447 pub partial_payment_rate: f64,
3448 #[serde(default = "default_p2p_payment_correction_rate")]
3450 pub payment_correction_rate: f64,
3451 #[serde(default = "default_p2p_avg_days_until_remainder")]
3453 pub avg_days_until_remainder: u32,
3454}
3455
3456fn default_p2p_late_payment_rate() -> f64 {
3457 0.15
3458}
3459
3460fn default_p2p_partial_payment_rate() -> f64 {
3461 0.05
3462}
3463
3464fn default_p2p_payment_correction_rate() -> f64 {
3465 0.02
3466}
3467
3468fn default_p2p_avg_days_until_remainder() -> u32 {
3469 30
3470}
3471
3472impl Default for P2PPaymentBehaviorConfig {
3473 fn default() -> Self {
3474 Self {
3475 late_payment_rate: default_p2p_late_payment_rate(),
3476 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3477 partial_payment_rate: default_p2p_partial_payment_rate(),
3478 payment_correction_rate: default_p2p_payment_correction_rate(),
3479 avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3480 }
3481 }
3482}
3483
3484#[derive(Debug, Clone, Serialize, Deserialize)]
3486pub struct LatePaymentDaysDistribution {
3487 #[serde(default = "default_slightly_late")]
3489 pub slightly_late_1_to_7: f64,
3490 #[serde(default = "default_late_8_14")]
3492 pub late_8_to_14: f64,
3493 #[serde(default = "default_very_late")]
3495 pub very_late_15_to_30: f64,
3496 #[serde(default = "default_severely_late")]
3498 pub severely_late_31_to_60: f64,
3499 #[serde(default = "default_extremely_late")]
3501 pub extremely_late_over_60: f64,
3502}
3503
3504fn default_slightly_late() -> f64 {
3505 0.50
3506}
3507
3508fn default_late_8_14() -> f64 {
3509 0.25
3510}
3511
3512fn default_very_late() -> f64 {
3513 0.15
3514}
3515
3516fn default_severely_late() -> f64 {
3517 0.07
3518}
3519
3520fn default_extremely_late() -> f64 {
3521 0.03
3522}
3523
3524impl Default for LatePaymentDaysDistribution {
3525 fn default() -> Self {
3526 Self {
3527 slightly_late_1_to_7: default_slightly_late(),
3528 late_8_to_14: default_late_8_14(),
3529 very_late_15_to_30: default_very_late(),
3530 severely_late_31_to_60: default_severely_late(),
3531 extremely_late_over_60: default_extremely_late(),
3532 }
3533 }
3534}
3535
3536#[derive(Debug, Clone, Serialize, Deserialize)]
3538pub struct O2CFlowConfig {
3539 #[serde(default = "default_true")]
3541 pub enabled: bool,
3542 #[serde(default = "default_credit_check_failure_rate")]
3544 pub credit_check_failure_rate: f64,
3545 #[serde(default = "default_partial_shipment_rate")]
3547 pub partial_shipment_rate: f64,
3548 #[serde(default = "default_return_rate")]
3550 pub return_rate: f64,
3551 #[serde(default = "default_bad_debt_rate")]
3553 pub bad_debt_rate: f64,
3554 #[serde(default = "default_so_to_delivery_days")]
3556 pub average_so_to_delivery_days: u32,
3557 #[serde(default = "default_delivery_to_invoice_days")]
3559 pub average_delivery_to_invoice_days: u32,
3560 #[serde(default = "default_invoice_to_receipt_days")]
3562 pub average_invoice_to_receipt_days: u32,
3563 #[serde(default)]
3565 pub line_count_distribution: DocumentLineCountDistribution,
3566 #[serde(default)]
3568 pub cash_discount: CashDiscountConfig,
3569 #[serde(default)]
3571 pub payment_behavior: O2CPaymentBehaviorConfig,
3572 #[serde(default)]
3574 pub late_payment_rate: Option<f64>,
3575}
3576
3577fn default_credit_check_failure_rate() -> f64 {
3578 0.02
3579}
3580
3581fn default_partial_shipment_rate() -> f64 {
3582 0.10
3583}
3584
3585fn default_return_rate() -> f64 {
3586 0.03
3587}
3588
3589fn default_bad_debt_rate() -> f64 {
3590 0.01
3591}
3592
3593fn default_so_to_delivery_days() -> u32 {
3594 7
3595}
3596
3597fn default_delivery_to_invoice_days() -> u32 {
3598 1
3599}
3600
3601fn default_invoice_to_receipt_days() -> u32 {
3602 45
3603}
3604
3605impl Default for O2CFlowConfig {
3606 fn default() -> Self {
3607 Self {
3608 enabled: true,
3609 credit_check_failure_rate: default_credit_check_failure_rate(),
3610 partial_shipment_rate: default_partial_shipment_rate(),
3611 return_rate: default_return_rate(),
3612 bad_debt_rate: default_bad_debt_rate(),
3613 average_so_to_delivery_days: default_so_to_delivery_days(),
3614 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3615 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3616 line_count_distribution: DocumentLineCountDistribution::default(),
3617 cash_discount: CashDiscountConfig::default(),
3618 payment_behavior: O2CPaymentBehaviorConfig::default(),
3619 late_payment_rate: None,
3620 }
3621 }
3622}
3623
3624#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3630pub struct O2CPaymentBehaviorConfig {
3631 #[serde(default)]
3633 pub dunning: DunningConfig,
3634 #[serde(default)]
3636 pub partial_payments: PartialPaymentConfig,
3637 #[serde(default)]
3639 pub short_payments: ShortPaymentConfig,
3640 #[serde(default)]
3642 pub on_account_payments: OnAccountPaymentConfig,
3643 #[serde(default)]
3645 pub payment_corrections: PaymentCorrectionConfig,
3646}
3647
3648#[derive(Debug, Clone, Serialize, Deserialize)]
3650pub struct DunningConfig {
3651 #[serde(default)]
3653 pub enabled: bool,
3654 #[serde(default = "default_dunning_level_1_days")]
3656 pub level_1_days_overdue: u32,
3657 #[serde(default = "default_dunning_level_2_days")]
3659 pub level_2_days_overdue: u32,
3660 #[serde(default = "default_dunning_level_3_days")]
3662 pub level_3_days_overdue: u32,
3663 #[serde(default = "default_collection_days")]
3665 pub collection_days_overdue: u32,
3666 #[serde(default)]
3668 pub payment_after_dunning_rates: DunningPaymentRates,
3669 #[serde(default = "default_dunning_block_rate")]
3671 pub dunning_block_rate: f64,
3672 #[serde(default = "default_dunning_interest_rate")]
3674 pub interest_rate_per_year: f64,
3675 #[serde(default = "default_dunning_charge")]
3677 pub dunning_charge: f64,
3678}
3679
3680fn default_dunning_level_1_days() -> u32 {
3681 14
3682}
3683
3684fn default_dunning_level_2_days() -> u32 {
3685 28
3686}
3687
3688fn default_dunning_level_3_days() -> u32 {
3689 42
3690}
3691
3692fn default_collection_days() -> u32 {
3693 60
3694}
3695
3696fn default_dunning_block_rate() -> f64 {
3697 0.05
3698}
3699
3700fn default_dunning_interest_rate() -> f64 {
3701 0.09
3702}
3703
3704fn default_dunning_charge() -> f64 {
3705 25.0
3706}
3707
3708impl Default for DunningConfig {
3709 fn default() -> Self {
3710 Self {
3711 enabled: false,
3712 level_1_days_overdue: default_dunning_level_1_days(),
3713 level_2_days_overdue: default_dunning_level_2_days(),
3714 level_3_days_overdue: default_dunning_level_3_days(),
3715 collection_days_overdue: default_collection_days(),
3716 payment_after_dunning_rates: DunningPaymentRates::default(),
3717 dunning_block_rate: default_dunning_block_rate(),
3718 interest_rate_per_year: default_dunning_interest_rate(),
3719 dunning_charge: default_dunning_charge(),
3720 }
3721 }
3722}
3723
3724#[derive(Debug, Clone, Serialize, Deserialize)]
3726pub struct DunningPaymentRates {
3727 #[serde(default = "default_after_level_1")]
3729 pub after_level_1: f64,
3730 #[serde(default = "default_after_level_2")]
3732 pub after_level_2: f64,
3733 #[serde(default = "default_after_level_3")]
3735 pub after_level_3: f64,
3736 #[serde(default = "default_during_collection")]
3738 pub during_collection: f64,
3739 #[serde(default = "default_never_pay")]
3741 pub never_pay: f64,
3742}
3743
3744fn default_after_level_1() -> f64 {
3745 0.40
3746}
3747
3748fn default_after_level_2() -> f64 {
3749 0.30
3750}
3751
3752fn default_after_level_3() -> f64 {
3753 0.15
3754}
3755
3756fn default_during_collection() -> f64 {
3757 0.05
3758}
3759
3760fn default_never_pay() -> f64 {
3761 0.10
3762}
3763
3764impl Default for DunningPaymentRates {
3765 fn default() -> Self {
3766 Self {
3767 after_level_1: default_after_level_1(),
3768 after_level_2: default_after_level_2(),
3769 after_level_3: default_after_level_3(),
3770 during_collection: default_during_collection(),
3771 never_pay: default_never_pay(),
3772 }
3773 }
3774}
3775
3776#[derive(Debug, Clone, Serialize, Deserialize)]
3778pub struct PartialPaymentConfig {
3779 #[serde(default = "default_partial_payment_rate")]
3781 pub rate: f64,
3782 #[serde(default)]
3784 pub percentage_distribution: PartialPaymentPercentageDistribution,
3785 #[serde(default = "default_avg_days_until_remainder")]
3787 pub avg_days_until_remainder: u32,
3788}
3789
3790fn default_partial_payment_rate() -> f64 {
3791 0.08
3792}
3793
3794fn default_avg_days_until_remainder() -> u32 {
3795 30
3796}
3797
3798impl Default for PartialPaymentConfig {
3799 fn default() -> Self {
3800 Self {
3801 rate: default_partial_payment_rate(),
3802 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3803 avg_days_until_remainder: default_avg_days_until_remainder(),
3804 }
3805 }
3806}
3807
3808#[derive(Debug, Clone, Serialize, Deserialize)]
3810pub struct PartialPaymentPercentageDistribution {
3811 #[serde(default = "default_partial_25")]
3813 pub pay_25_percent: f64,
3814 #[serde(default = "default_partial_50")]
3816 pub pay_50_percent: f64,
3817 #[serde(default = "default_partial_75")]
3819 pub pay_75_percent: f64,
3820 #[serde(default = "default_partial_random")]
3822 pub pay_random_percent: f64,
3823}
3824
3825fn default_partial_25() -> f64 {
3826 0.15
3827}
3828
3829fn default_partial_50() -> f64 {
3830 0.50
3831}
3832
3833fn default_partial_75() -> f64 {
3834 0.25
3835}
3836
3837fn default_partial_random() -> f64 {
3838 0.10
3839}
3840
3841impl Default for PartialPaymentPercentageDistribution {
3842 fn default() -> Self {
3843 Self {
3844 pay_25_percent: default_partial_25(),
3845 pay_50_percent: default_partial_50(),
3846 pay_75_percent: default_partial_75(),
3847 pay_random_percent: default_partial_random(),
3848 }
3849 }
3850}
3851
3852#[derive(Debug, Clone, Serialize, Deserialize)]
3854pub struct ShortPaymentConfig {
3855 #[serde(default = "default_short_payment_rate")]
3857 pub rate: f64,
3858 #[serde(default)]
3860 pub reason_distribution: ShortPaymentReasonDistribution,
3861 #[serde(default = "default_max_short_percent")]
3863 pub max_short_percent: f64,
3864}
3865
3866fn default_short_payment_rate() -> f64 {
3867 0.03
3868}
3869
3870fn default_max_short_percent() -> f64 {
3871 0.10
3872}
3873
3874impl Default for ShortPaymentConfig {
3875 fn default() -> Self {
3876 Self {
3877 rate: default_short_payment_rate(),
3878 reason_distribution: ShortPaymentReasonDistribution::default(),
3879 max_short_percent: default_max_short_percent(),
3880 }
3881 }
3882}
3883
3884#[derive(Debug, Clone, Serialize, Deserialize)]
3886pub struct ShortPaymentReasonDistribution {
3887 #[serde(default = "default_pricing_dispute")]
3889 pub pricing_dispute: f64,
3890 #[serde(default = "default_quality_issue")]
3892 pub quality_issue: f64,
3893 #[serde(default = "default_quantity_discrepancy")]
3895 pub quantity_discrepancy: f64,
3896 #[serde(default = "default_unauthorized_deduction")]
3898 pub unauthorized_deduction: f64,
3899 #[serde(default = "default_incorrect_discount")]
3901 pub incorrect_discount: f64,
3902}
3903
3904fn default_pricing_dispute() -> f64 {
3905 0.30
3906}
3907
3908fn default_quality_issue() -> f64 {
3909 0.20
3910}
3911
3912fn default_quantity_discrepancy() -> f64 {
3913 0.20
3914}
3915
3916fn default_unauthorized_deduction() -> f64 {
3917 0.15
3918}
3919
3920fn default_incorrect_discount() -> f64 {
3921 0.15
3922}
3923
3924impl Default for ShortPaymentReasonDistribution {
3925 fn default() -> Self {
3926 Self {
3927 pricing_dispute: default_pricing_dispute(),
3928 quality_issue: default_quality_issue(),
3929 quantity_discrepancy: default_quantity_discrepancy(),
3930 unauthorized_deduction: default_unauthorized_deduction(),
3931 incorrect_discount: default_incorrect_discount(),
3932 }
3933 }
3934}
3935
3936#[derive(Debug, Clone, Serialize, Deserialize)]
3938pub struct OnAccountPaymentConfig {
3939 #[serde(default = "default_on_account_rate")]
3941 pub rate: f64,
3942 #[serde(default = "default_avg_days_until_applied")]
3944 pub avg_days_until_applied: u32,
3945}
3946
3947fn default_on_account_rate() -> f64 {
3948 0.02
3949}
3950
3951fn default_avg_days_until_applied() -> u32 {
3952 14
3953}
3954
3955impl Default for OnAccountPaymentConfig {
3956 fn default() -> Self {
3957 Self {
3958 rate: default_on_account_rate(),
3959 avg_days_until_applied: default_avg_days_until_applied(),
3960 }
3961 }
3962}
3963
3964#[derive(Debug, Clone, Serialize, Deserialize)]
3966pub struct PaymentCorrectionConfig {
3967 #[serde(default = "default_payment_correction_rate")]
3969 pub rate: f64,
3970 #[serde(default)]
3972 pub type_distribution: PaymentCorrectionTypeDistribution,
3973}
3974
3975fn default_payment_correction_rate() -> f64 {
3976 0.02
3977}
3978
3979impl Default for PaymentCorrectionConfig {
3980 fn default() -> Self {
3981 Self {
3982 rate: default_payment_correction_rate(),
3983 type_distribution: PaymentCorrectionTypeDistribution::default(),
3984 }
3985 }
3986}
3987
3988#[derive(Debug, Clone, Serialize, Deserialize)]
3990pub struct PaymentCorrectionTypeDistribution {
3991 #[serde(default = "default_nsf_rate")]
3993 pub nsf: f64,
3994 #[serde(default = "default_chargeback_rate")]
3996 pub chargeback: f64,
3997 #[serde(default = "default_wrong_amount_rate")]
3999 pub wrong_amount: f64,
4000 #[serde(default = "default_wrong_customer_rate")]
4002 pub wrong_customer: f64,
4003 #[serde(default = "default_duplicate_payment_rate")]
4005 pub duplicate_payment: f64,
4006}
4007
4008fn default_nsf_rate() -> f64 {
4009 0.30
4010}
4011
4012fn default_chargeback_rate() -> f64 {
4013 0.20
4014}
4015
4016fn default_wrong_amount_rate() -> f64 {
4017 0.20
4018}
4019
4020fn default_wrong_customer_rate() -> f64 {
4021 0.15
4022}
4023
4024fn default_duplicate_payment_rate() -> f64 {
4025 0.15
4026}
4027
4028impl Default for PaymentCorrectionTypeDistribution {
4029 fn default() -> Self {
4030 Self {
4031 nsf: default_nsf_rate(),
4032 chargeback: default_chargeback_rate(),
4033 wrong_amount: default_wrong_amount_rate(),
4034 wrong_customer: default_wrong_customer_rate(),
4035 duplicate_payment: default_duplicate_payment_rate(),
4036 }
4037 }
4038}
4039
4040#[derive(Debug, Clone, Serialize, Deserialize)]
4042pub struct DocumentLineCountDistribution {
4043 #[serde(default = "default_min_lines")]
4045 pub min_lines: u32,
4046 #[serde(default = "default_max_lines")]
4048 pub max_lines: u32,
4049 #[serde(default = "default_mode_lines")]
4051 pub mode_lines: u32,
4052}
4053
4054fn default_min_lines() -> u32 {
4055 1
4056}
4057
4058fn default_max_lines() -> u32 {
4059 20
4060}
4061
4062fn default_mode_lines() -> u32 {
4063 3
4064}
4065
4066impl Default for DocumentLineCountDistribution {
4067 fn default() -> Self {
4068 Self {
4069 min_lines: default_min_lines(),
4070 max_lines: default_max_lines(),
4071 mode_lines: default_mode_lines(),
4072 }
4073 }
4074}
4075
4076#[derive(Debug, Clone, Serialize, Deserialize)]
4078pub struct CashDiscountConfig {
4079 #[serde(default = "default_discount_eligible_rate")]
4081 pub eligible_rate: f64,
4082 #[serde(default = "default_discount_taken_rate")]
4084 pub taken_rate: f64,
4085 #[serde(default = "default_discount_percent")]
4087 pub discount_percent: f64,
4088 #[serde(default = "default_discount_days")]
4090 pub discount_days: u32,
4091}
4092
4093fn default_discount_eligible_rate() -> f64 {
4094 0.30
4095}
4096
4097fn default_discount_taken_rate() -> f64 {
4098 0.60
4099}
4100
4101fn default_discount_percent() -> f64 {
4102 0.02
4103}
4104
4105fn default_discount_days() -> u32 {
4106 10
4107}
4108
4109impl Default for CashDiscountConfig {
4110 fn default() -> Self {
4111 Self {
4112 eligible_rate: default_discount_eligible_rate(),
4113 taken_rate: default_discount_taken_rate(),
4114 discount_percent: default_discount_percent(),
4115 discount_days: default_discount_days(),
4116 }
4117 }
4118}
4119
4120#[derive(Debug, Clone, Serialize, Deserialize)]
4126pub struct IntercompanyConfig {
4127 #[serde(default)]
4129 pub enabled: bool,
4130 #[serde(default = "default_ic_transaction_rate")]
4132 pub ic_transaction_rate: f64,
4133 #[serde(default)]
4135 pub transfer_pricing_method: TransferPricingMethod,
4136 #[serde(default = "default_markup_percent")]
4138 pub markup_percent: f64,
4139 #[serde(default = "default_true")]
4141 pub generate_matched_pairs: bool,
4142 #[serde(default)]
4144 pub transaction_type_distribution: ICTransactionTypeDistribution,
4145 #[serde(default)]
4147 pub generate_eliminations: bool,
4148}
4149
4150fn default_ic_transaction_rate() -> f64 {
4151 0.15
4152}
4153
4154fn default_markup_percent() -> f64 {
4155 0.05
4156}
4157
4158impl Default for IntercompanyConfig {
4159 fn default() -> Self {
4160 Self {
4161 enabled: false,
4162 ic_transaction_rate: default_ic_transaction_rate(),
4163 transfer_pricing_method: TransferPricingMethod::default(),
4164 markup_percent: default_markup_percent(),
4165 generate_matched_pairs: true,
4166 transaction_type_distribution: ICTransactionTypeDistribution::default(),
4167 generate_eliminations: false,
4168 }
4169 }
4170}
4171
4172#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
4174#[serde(rename_all = "snake_case")]
4175pub enum TransferPricingMethod {
4176 #[default]
4178 CostPlus,
4179 ComparableUncontrolled,
4181 ResalePrice,
4183 TransactionalNetMargin,
4185 ProfitSplit,
4187}
4188
4189#[derive(Debug, Clone, Serialize, Deserialize)]
4191pub struct ICTransactionTypeDistribution {
4192 pub goods_sale: f64,
4194 pub service_provided: f64,
4196 pub loan: f64,
4198 pub dividend: f64,
4200 pub management_fee: f64,
4202 pub royalty: f64,
4204 pub cost_sharing: f64,
4206}
4207
4208impl Default for ICTransactionTypeDistribution {
4209 fn default() -> Self {
4210 Self {
4211 goods_sale: 0.35,
4212 service_provided: 0.20,
4213 loan: 0.10,
4214 dividend: 0.05,
4215 management_fee: 0.15,
4216 royalty: 0.10,
4217 cost_sharing: 0.05,
4218 }
4219 }
4220}
4221
4222#[derive(Debug, Clone, Serialize, Deserialize)]
4228pub struct BalanceConfig {
4229 #[serde(default)]
4231 pub generate_opening_balances: bool,
4232 #[serde(default = "default_true")]
4234 pub generate_trial_balances: bool,
4235 #[serde(default = "default_gross_margin")]
4237 pub target_gross_margin: f64,
4238 #[serde(default = "default_dso")]
4240 pub target_dso_days: u32,
4241 #[serde(default = "default_dpo")]
4243 pub target_dpo_days: u32,
4244 #[serde(default = "default_current_ratio")]
4246 pub target_current_ratio: f64,
4247 #[serde(default = "default_debt_equity")]
4249 pub target_debt_to_equity: f64,
4250 #[serde(default = "default_true")]
4252 pub validate_balance_equation: bool,
4253 #[serde(default = "default_true")]
4255 pub reconcile_subledgers: bool,
4256}
4257
4258fn default_gross_margin() -> f64 {
4259 0.35
4260}
4261
4262fn default_dso() -> u32 {
4263 45
4264}
4265
4266fn default_dpo() -> u32 {
4267 30
4268}
4269
4270fn default_current_ratio() -> f64 {
4271 1.5
4272}
4273
4274fn default_debt_equity() -> f64 {
4275 0.5
4276}
4277
4278impl Default for BalanceConfig {
4279 fn default() -> Self {
4280 Self {
4281 generate_opening_balances: false,
4282 generate_trial_balances: true,
4283 target_gross_margin: default_gross_margin(),
4284 target_dso_days: default_dso(),
4285 target_dpo_days: default_dpo(),
4286 target_current_ratio: default_current_ratio(),
4287 target_debt_to_equity: default_debt_equity(),
4288 validate_balance_equation: true,
4289 reconcile_subledgers: true,
4290 }
4291 }
4292}
4293
4294#[derive(Debug, Clone, Serialize, Deserialize)]
4303pub struct OcpmConfig {
4304 #[serde(default)]
4306 pub enabled: bool,
4307
4308 #[serde(default = "default_true")]
4310 pub generate_lifecycle_events: bool,
4311
4312 #[serde(default = "default_true")]
4314 pub include_object_relationships: bool,
4315
4316 #[serde(default = "default_true")]
4318 pub compute_variants: bool,
4319
4320 #[serde(default)]
4322 pub max_variants: usize,
4323
4324 #[serde(default)]
4326 pub p2p_process: OcpmProcessConfig,
4327
4328 #[serde(default)]
4330 pub o2c_process: OcpmProcessConfig,
4331
4332 #[serde(default)]
4334 pub output: OcpmOutputConfig,
4335}
4336
4337impl Default for OcpmConfig {
4338 fn default() -> Self {
4339 Self {
4340 enabled: false,
4341 generate_lifecycle_events: true,
4342 include_object_relationships: true,
4343 compute_variants: true,
4344 max_variants: 0,
4345 p2p_process: OcpmProcessConfig::default(),
4346 o2c_process: OcpmProcessConfig::default(),
4347 output: OcpmOutputConfig::default(),
4348 }
4349 }
4350}
4351
4352#[derive(Debug, Clone, Serialize, Deserialize)]
4354pub struct OcpmProcessConfig {
4355 #[serde(default = "default_rework_probability")]
4357 pub rework_probability: f64,
4358
4359 #[serde(default = "default_skip_probability")]
4361 pub skip_step_probability: f64,
4362
4363 #[serde(default = "default_out_of_order_probability")]
4365 pub out_of_order_probability: f64,
4366}
4367
4368fn default_rework_probability() -> f64 {
4372 0.15
4373}
4374
4375fn default_skip_probability() -> f64 {
4376 0.10
4377}
4378
4379fn default_out_of_order_probability() -> f64 {
4380 0.08
4381}
4382
4383impl Default for OcpmProcessConfig {
4384 fn default() -> Self {
4385 Self {
4386 rework_probability: default_rework_probability(),
4387 skip_step_probability: default_skip_probability(),
4388 out_of_order_probability: default_out_of_order_probability(),
4389 }
4390 }
4391}
4392
4393#[derive(Debug, Clone, Serialize, Deserialize)]
4395pub struct OcpmOutputConfig {
4396 #[serde(default = "default_true")]
4398 pub ocel_json: bool,
4399
4400 #[serde(default)]
4402 pub ocel_xml: bool,
4403
4404 #[serde(default)]
4406 pub xes: bool,
4407
4408 #[serde(default = "default_true")]
4410 pub xes_include_lifecycle: bool,
4411
4412 #[serde(default = "default_true")]
4414 pub xes_include_resources: bool,
4415
4416 #[serde(default = "default_true")]
4418 pub flattened_csv: bool,
4419
4420 #[serde(default = "default_true")]
4422 pub event_object_csv: bool,
4423
4424 #[serde(default = "default_true")]
4426 pub object_relationship_csv: bool,
4427
4428 #[serde(default = "default_true")]
4430 pub variants_csv: bool,
4431
4432 #[serde(default)]
4434 pub export_reference_models: bool,
4435}
4436
4437impl Default for OcpmOutputConfig {
4438 fn default() -> Self {
4439 Self {
4440 ocel_json: true,
4441 ocel_xml: false,
4442 xes: false,
4443 xes_include_lifecycle: true,
4444 xes_include_resources: true,
4445 flattened_csv: true,
4446 event_object_csv: true,
4447 object_relationship_csv: true,
4448 variants_csv: true,
4449 export_reference_models: false,
4450 }
4451 }
4452}
4453
4454#[derive(Debug, Clone, Serialize, Deserialize)]
4456pub struct AuditGenerationConfig {
4457 #[serde(default)]
4459 pub enabled: bool,
4460
4461 #[serde(default = "default_true")]
4465 pub generate_workpapers: bool,
4466
4467 #[serde(default)]
4470 pub engagement_types: AuditEngagementTypesConfig,
4471
4472 #[serde(default)]
4477 pub workpapers: WorkpaperConfig,
4478
4479 #[serde(default)]
4485 pub team: AuditTeamConfig,
4486
4487 #[serde(default)]
4494 pub review: ReviewWorkflowConfig,
4495
4496 #[serde(default)]
4498 pub fsm: Option<AuditFsmConfig>,
4499
4500 #[serde(default)]
4506 pub it_controls: ItControlsConfig,
4507}
4508
4509#[derive(Debug, Clone, Serialize, Deserialize)]
4511pub struct ItControlsConfig {
4512 #[serde(default)]
4515 pub enabled: bool,
4516 #[serde(default = "default_access_log_count")]
4519 pub access_logs_per_engagement: usize,
4520 #[serde(default = "default_change_record_count")]
4522 pub change_records_per_engagement: usize,
4523}
4524
4525fn default_access_log_count() -> usize {
4526 500
4527}
4528fn default_change_record_count() -> usize {
4529 50
4530}
4531
4532impl Default for ItControlsConfig {
4533 fn default() -> Self {
4534 Self {
4535 enabled: false,
4536 access_logs_per_engagement: default_access_log_count(),
4537 change_records_per_engagement: default_change_record_count(),
4538 }
4539 }
4540}
4541
4542impl Default for AuditGenerationConfig {
4543 fn default() -> Self {
4544 Self {
4545 enabled: false,
4546 generate_workpapers: true,
4547 engagement_types: AuditEngagementTypesConfig::default(),
4548 workpapers: WorkpaperConfig::default(),
4549 team: AuditTeamConfig::default(),
4550 review: ReviewWorkflowConfig::default(),
4551 fsm: None,
4552 it_controls: ItControlsConfig::default(),
4553 }
4554 }
4555}
4556
4557#[derive(Debug, Clone, Serialize, Deserialize)]
4559pub struct AuditFsmConfig {
4560 #[serde(default)]
4562 pub enabled: bool,
4563
4564 #[serde(default = "default_audit_fsm_blueprint")]
4566 pub blueprint: String,
4567
4568 #[serde(default = "default_audit_fsm_overlay")]
4570 pub overlay: String,
4571
4572 #[serde(default)]
4574 pub depth: Option<String>,
4575
4576 #[serde(default)]
4578 pub discriminators: std::collections::HashMap<String, Vec<String>>,
4579
4580 #[serde(default)]
4582 pub event_trail: AuditEventTrailConfig,
4583
4584 #[serde(default)]
4586 pub seed: Option<u64>,
4587}
4588
4589impl Default for AuditFsmConfig {
4590 fn default() -> Self {
4591 Self {
4592 enabled: false,
4593 blueprint: default_audit_fsm_blueprint(),
4594 overlay: default_audit_fsm_overlay(),
4595 depth: None,
4596 discriminators: std::collections::HashMap::new(),
4597 event_trail: AuditEventTrailConfig::default(),
4598 seed: None,
4599 }
4600 }
4601}
4602
4603fn default_audit_fsm_blueprint() -> String {
4604 "builtin:fsa".to_string()
4605}
4606
4607fn default_audit_fsm_overlay() -> String {
4608 "builtin:default".to_string()
4609}
4610
4611#[derive(Debug, Clone, Serialize, Deserialize)]
4613pub struct AuditEventTrailConfig {
4614 #[serde(default = "default_true")]
4616 pub flat_log: bool,
4617 #[serde(default)]
4619 pub ocel_projection: bool,
4620}
4621
4622impl Default for AuditEventTrailConfig {
4623 fn default() -> Self {
4624 Self {
4625 flat_log: true,
4626 ocel_projection: false,
4627 }
4628 }
4629}
4630
4631#[derive(Debug, Clone, Serialize, Deserialize)]
4633pub struct AuditEngagementTypesConfig {
4634 #[serde(default = "default_financial_audit_prob")]
4636 pub financial_statement: f64,
4637 #[serde(default = "default_sox_audit_prob")]
4639 pub sox_icfr: f64,
4640 #[serde(default = "default_integrated_audit_prob")]
4642 pub integrated: f64,
4643 #[serde(default = "default_review_prob")]
4645 pub review: f64,
4646 #[serde(default = "default_aup_prob")]
4648 pub agreed_upon_procedures: f64,
4649}
4650
4651fn default_financial_audit_prob() -> f64 {
4652 0.40
4653}
4654fn default_sox_audit_prob() -> f64 {
4655 0.20
4656}
4657fn default_integrated_audit_prob() -> f64 {
4658 0.25
4659}
4660fn default_review_prob() -> f64 {
4661 0.10
4662}
4663fn default_aup_prob() -> f64 {
4664 0.05
4665}
4666
4667impl Default for AuditEngagementTypesConfig {
4668 fn default() -> Self {
4669 Self {
4670 financial_statement: default_financial_audit_prob(),
4671 sox_icfr: default_sox_audit_prob(),
4672 integrated: default_integrated_audit_prob(),
4673 review: default_review_prob(),
4674 agreed_upon_procedures: default_aup_prob(),
4675 }
4676 }
4677}
4678
4679#[derive(Debug, Clone, Serialize, Deserialize)]
4681pub struct WorkpaperConfig {
4682 #[serde(default = "default_workpapers_per_phase")]
4684 pub average_per_phase: usize,
4685
4686 #[serde(default = "default_true")]
4688 pub include_isa_references: bool,
4689
4690 #[serde(default = "default_true")]
4692 pub include_sample_details: bool,
4693
4694 #[serde(default = "default_true")]
4696 pub include_cross_references: bool,
4697
4698 #[serde(default)]
4700 pub sampling: SamplingConfig,
4701}
4702
4703fn default_workpapers_per_phase() -> usize {
4704 5
4705}
4706
4707impl Default for WorkpaperConfig {
4708 fn default() -> Self {
4709 Self {
4710 average_per_phase: default_workpapers_per_phase(),
4711 include_isa_references: true,
4712 include_sample_details: true,
4713 include_cross_references: true,
4714 sampling: SamplingConfig::default(),
4715 }
4716 }
4717}
4718
4719#[derive(Debug, Clone, Serialize, Deserialize)]
4721pub struct SamplingConfig {
4722 #[serde(default = "default_statistical_rate")]
4724 pub statistical_rate: f64,
4725 #[serde(default = "default_judgmental_rate")]
4727 pub judgmental_rate: f64,
4728 #[serde(default = "default_haphazard_rate")]
4730 pub haphazard_rate: f64,
4731 #[serde(default = "default_complete_examination_rate")]
4733 pub complete_examination_rate: f64,
4734}
4735
4736fn default_statistical_rate() -> f64 {
4737 0.40
4738}
4739fn default_judgmental_rate() -> f64 {
4740 0.30
4741}
4742fn default_haphazard_rate() -> f64 {
4743 0.20
4744}
4745fn default_complete_examination_rate() -> f64 {
4746 0.10
4747}
4748
4749impl Default for SamplingConfig {
4750 fn default() -> Self {
4751 Self {
4752 statistical_rate: default_statistical_rate(),
4753 judgmental_rate: default_judgmental_rate(),
4754 haphazard_rate: default_haphazard_rate(),
4755 complete_examination_rate: default_complete_examination_rate(),
4756 }
4757 }
4758}
4759
4760#[derive(Debug, Clone, Serialize, Deserialize)]
4762pub struct AuditTeamConfig {
4763 #[serde(default = "default_min_team_size")]
4765 pub min_team_size: usize,
4766 #[serde(default = "default_max_team_size")]
4768 pub max_team_size: usize,
4769 #[serde(default = "default_specialist_probability")]
4771 pub specialist_probability: f64,
4772}
4773
4774fn default_min_team_size() -> usize {
4775 3
4776}
4777fn default_max_team_size() -> usize {
4778 8
4779}
4780fn default_specialist_probability() -> f64 {
4781 0.30
4782}
4783
4784impl Default for AuditTeamConfig {
4785 fn default() -> Self {
4786 Self {
4787 min_team_size: default_min_team_size(),
4788 max_team_size: default_max_team_size(),
4789 specialist_probability: default_specialist_probability(),
4790 }
4791 }
4792}
4793
4794#[derive(Debug, Clone, Serialize, Deserialize)]
4796pub struct ReviewWorkflowConfig {
4797 #[serde(default = "default_review_delay_days")]
4799 pub average_review_delay_days: u32,
4800 #[serde(default = "default_rework_probability_review")]
4802 pub rework_probability: f64,
4803 #[serde(default = "default_true")]
4805 pub require_partner_signoff: bool,
4806}
4807
4808fn default_review_delay_days() -> u32 {
4809 2
4810}
4811fn default_rework_probability_review() -> f64 {
4812 0.15
4813}
4814
4815impl Default for ReviewWorkflowConfig {
4816 fn default() -> Self {
4817 Self {
4818 average_review_delay_days: default_review_delay_days(),
4819 rework_probability: default_rework_probability_review(),
4820 require_partner_signoff: true,
4821 }
4822 }
4823}
4824
4825#[derive(Debug, Clone, Serialize, Deserialize)]
4831pub struct DataQualitySchemaConfig {
4832 #[serde(default)]
4834 pub enabled: bool,
4835 #[serde(default)]
4837 pub preset: DataQualityPreset,
4838 #[serde(default)]
4840 pub missing_values: MissingValuesSchemaConfig,
4841 #[serde(default)]
4843 pub typos: TypoSchemaConfig,
4844 #[serde(default)]
4846 pub format_variations: FormatVariationSchemaConfig,
4847 #[serde(default)]
4849 pub duplicates: DuplicateSchemaConfig,
4850 #[serde(default)]
4852 pub encoding_issues: EncodingIssueSchemaConfig,
4853 #[serde(default)]
4855 pub generate_labels: bool,
4856 #[serde(default)]
4858 pub sink_profiles: SinkQualityProfiles,
4859}
4860
4861impl Default for DataQualitySchemaConfig {
4862 fn default() -> Self {
4863 Self {
4864 enabled: false,
4865 preset: DataQualityPreset::None,
4866 missing_values: MissingValuesSchemaConfig::default(),
4867 typos: TypoSchemaConfig::default(),
4868 format_variations: FormatVariationSchemaConfig::default(),
4869 duplicates: DuplicateSchemaConfig::default(),
4870 encoding_issues: EncodingIssueSchemaConfig::default(),
4871 generate_labels: true,
4872 sink_profiles: SinkQualityProfiles::default(),
4873 }
4874 }
4875}
4876
4877impl DataQualitySchemaConfig {
4878 pub fn with_preset(preset: DataQualityPreset) -> Self {
4880 let mut config = Self {
4881 preset,
4882 ..Default::default()
4883 };
4884 config.apply_preset();
4885 config
4886 }
4887
4888 pub fn apply_preset(&mut self) {
4891 if !self.preset.overrides_settings() {
4892 return;
4893 }
4894
4895 self.enabled = true;
4896
4897 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4899 self.missing_values.rate = self.preset.missing_rate();
4900
4901 self.typos.enabled = self.preset.typo_rate() > 0.0;
4903 self.typos.char_error_rate = self.preset.typo_rate();
4904
4905 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4907 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4908 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4909 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4910
4911 self.format_variations.enabled = self.preset.format_variations_enabled();
4913
4914 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4916 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4917
4918 if self.preset.ocr_errors_enabled() {
4920 self.typos.type_weights.ocr_errors = 0.3;
4921 }
4922 }
4923
4924 pub fn effective_missing_rate(&self) -> f64 {
4926 if self.preset.overrides_settings() {
4927 self.preset.missing_rate()
4928 } else {
4929 self.missing_values.rate
4930 }
4931 }
4932
4933 pub fn effective_typo_rate(&self) -> f64 {
4935 if self.preset.overrides_settings() {
4936 self.preset.typo_rate()
4937 } else {
4938 self.typos.char_error_rate
4939 }
4940 }
4941
4942 pub fn effective_duplicate_rate(&self) -> f64 {
4944 if self.preset.overrides_settings() {
4945 self.preset.duplicate_rate()
4946 } else {
4947 self.duplicates.exact_duplicate_ratio
4948 + self.duplicates.near_duplicate_ratio
4949 + self.duplicates.fuzzy_duplicate_ratio
4950 }
4951 }
4952
4953 pub fn clean() -> Self {
4955 Self::with_preset(DataQualityPreset::Clean)
4956 }
4957
4958 pub fn noisy() -> Self {
4960 Self::with_preset(DataQualityPreset::Noisy)
4961 }
4962
4963 pub fn legacy() -> Self {
4965 Self::with_preset(DataQualityPreset::Legacy)
4966 }
4967}
4968
4969#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4971#[serde(rename_all = "snake_case")]
4972pub enum DataQualityPreset {
4973 #[default]
4975 None,
4976 Minimal,
4978 Normal,
4980 High,
4982 Custom,
4984
4985 Clean,
4991 Noisy,
4994 Legacy,
4997}
4998
4999impl DataQualityPreset {
5000 pub fn missing_rate(&self) -> f64 {
5002 match self {
5003 DataQualityPreset::None => 0.0,
5004 DataQualityPreset::Minimal => 0.005,
5005 DataQualityPreset::Normal => 0.02,
5006 DataQualityPreset::High => 0.08,
5007 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
5009 DataQualityPreset::Noisy => 0.05,
5010 DataQualityPreset::Legacy => 0.10,
5011 }
5012 }
5013
5014 pub fn typo_rate(&self) -> f64 {
5016 match self {
5017 DataQualityPreset::None => 0.0,
5018 DataQualityPreset::Minimal => 0.0005,
5019 DataQualityPreset::Normal => 0.002,
5020 DataQualityPreset::High => 0.01,
5021 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
5023 DataQualityPreset::Noisy => 0.02,
5024 DataQualityPreset::Legacy => 0.05,
5025 }
5026 }
5027
5028 pub fn duplicate_rate(&self) -> f64 {
5030 match self {
5031 DataQualityPreset::None => 0.0,
5032 DataQualityPreset::Minimal => 0.001,
5033 DataQualityPreset::Normal => 0.005,
5034 DataQualityPreset::High => 0.02,
5035 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
5037 DataQualityPreset::Noisy => 0.01,
5038 DataQualityPreset::Legacy => 0.03,
5039 }
5040 }
5041
5042 pub fn format_variations_enabled(&self) -> bool {
5044 match self {
5045 DataQualityPreset::None | DataQualityPreset::Clean => false,
5046 DataQualityPreset::Minimal => true,
5047 DataQualityPreset::Normal => true,
5048 DataQualityPreset::High => true,
5049 DataQualityPreset::Custom => true,
5050 DataQualityPreset::Noisy => true,
5051 DataQualityPreset::Legacy => true,
5052 }
5053 }
5054
5055 pub fn ocr_errors_enabled(&self) -> bool {
5057 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
5058 }
5059
5060 pub fn encoding_issues_enabled(&self) -> bool {
5062 matches!(
5063 self,
5064 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
5065 )
5066 }
5067
5068 pub fn encoding_issue_rate(&self) -> f64 {
5070 match self {
5071 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
5072 DataQualityPreset::Normal => 0.002,
5073 DataQualityPreset::High => 0.01,
5074 DataQualityPreset::Custom => 0.0,
5075 DataQualityPreset::Noisy => 0.005,
5076 DataQualityPreset::Legacy => 0.02,
5077 }
5078 }
5079
5080 pub fn overrides_settings(&self) -> bool {
5082 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
5083 }
5084
5085 pub fn description(&self) -> &'static str {
5087 match self {
5088 DataQualityPreset::None => "No data quality issues (pristine data)",
5089 DataQualityPreset::Minimal => "Very rare data quality issues",
5090 DataQualityPreset::Normal => "Realistic enterprise data quality",
5091 DataQualityPreset::High => "Messy data for stress testing",
5092 DataQualityPreset::Custom => "Custom settings from configuration",
5093 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
5094 DataQualityPreset::Noisy => "Typical production data with moderate issues",
5095 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
5096 }
5097 }
5098}
5099
5100#[derive(Debug, Clone, Serialize, Deserialize)]
5102pub struct MissingValuesSchemaConfig {
5103 #[serde(default)]
5105 pub enabled: bool,
5106 #[serde(default = "default_missing_rate")]
5108 pub rate: f64,
5109 #[serde(default)]
5111 pub strategy: MissingValueStrategy,
5112 #[serde(default)]
5114 pub field_rates: std::collections::HashMap<String, f64>,
5115 #[serde(default)]
5117 pub protected_fields: Vec<String>,
5118}
5119
5120fn default_missing_rate() -> f64 {
5121 0.01
5122}
5123
5124impl Default for MissingValuesSchemaConfig {
5125 fn default() -> Self {
5126 Self {
5127 enabled: false,
5128 rate: default_missing_rate(),
5129 strategy: MissingValueStrategy::Mcar,
5130 field_rates: std::collections::HashMap::new(),
5131 protected_fields: vec![
5132 "document_id".to_string(),
5133 "company_code".to_string(),
5134 "posting_date".to_string(),
5135 ],
5136 }
5137 }
5138}
5139
5140#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5142#[serde(rename_all = "snake_case")]
5143pub enum MissingValueStrategy {
5144 #[default]
5146 Mcar,
5147 Mar,
5149 Mnar,
5151 Systematic,
5153}
5154
5155#[derive(Debug, Clone, Serialize, Deserialize)]
5157pub struct TypoSchemaConfig {
5158 #[serde(default)]
5160 pub enabled: bool,
5161 #[serde(default = "default_typo_rate")]
5163 pub char_error_rate: f64,
5164 #[serde(default)]
5166 pub type_weights: TypoTypeWeights,
5167 #[serde(default)]
5169 pub protected_fields: Vec<String>,
5170}
5171
5172fn default_typo_rate() -> f64 {
5173 0.001
5174}
5175
5176impl Default for TypoSchemaConfig {
5177 fn default() -> Self {
5178 Self {
5179 enabled: false,
5180 char_error_rate: default_typo_rate(),
5181 type_weights: TypoTypeWeights::default(),
5182 protected_fields: vec![
5183 "document_id".to_string(),
5184 "gl_account".to_string(),
5185 "company_code".to_string(),
5186 ],
5187 }
5188 }
5189}
5190
5191#[derive(Debug, Clone, Serialize, Deserialize)]
5193pub struct TypoTypeWeights {
5194 #[serde(default = "default_substitution_weight")]
5196 pub substitution: f64,
5197 #[serde(default = "default_transposition_weight")]
5199 pub transposition: f64,
5200 #[serde(default = "default_insertion_weight")]
5202 pub insertion: f64,
5203 #[serde(default = "default_deletion_weight")]
5205 pub deletion: f64,
5206 #[serde(default = "default_ocr_weight")]
5208 pub ocr_errors: f64,
5209 #[serde(default = "default_homophone_weight")]
5211 pub homophones: f64,
5212}
5213
5214fn default_substitution_weight() -> f64 {
5215 0.35
5216}
5217fn default_transposition_weight() -> f64 {
5218 0.25
5219}
5220fn default_insertion_weight() -> f64 {
5221 0.10
5222}
5223fn default_deletion_weight() -> f64 {
5224 0.15
5225}
5226fn default_ocr_weight() -> f64 {
5227 0.10
5228}
5229fn default_homophone_weight() -> f64 {
5230 0.05
5231}
5232
5233impl Default for TypoTypeWeights {
5234 fn default() -> Self {
5235 Self {
5236 substitution: default_substitution_weight(),
5237 transposition: default_transposition_weight(),
5238 insertion: default_insertion_weight(),
5239 deletion: default_deletion_weight(),
5240 ocr_errors: default_ocr_weight(),
5241 homophones: default_homophone_weight(),
5242 }
5243 }
5244}
5245
5246#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5248pub struct FormatVariationSchemaConfig {
5249 #[serde(default)]
5251 pub enabled: bool,
5252 #[serde(default)]
5254 pub dates: DateFormatVariationConfig,
5255 #[serde(default)]
5257 pub amounts: AmountFormatVariationConfig,
5258 #[serde(default)]
5260 pub identifiers: IdentifierFormatVariationConfig,
5261}
5262
5263#[derive(Debug, Clone, Serialize, Deserialize)]
5265pub struct DateFormatVariationConfig {
5266 #[serde(default)]
5268 pub enabled: bool,
5269 #[serde(default = "default_date_variation_rate")]
5271 pub rate: f64,
5272 #[serde(default = "default_true")]
5274 pub iso_format: bool,
5275 #[serde(default)]
5277 pub us_format: bool,
5278 #[serde(default)]
5280 pub eu_format: bool,
5281 #[serde(default)]
5283 pub long_format: bool,
5284}
5285
5286fn default_date_variation_rate() -> f64 {
5287 0.05
5288}
5289
5290impl Default for DateFormatVariationConfig {
5291 fn default() -> Self {
5292 Self {
5293 enabled: false,
5294 rate: default_date_variation_rate(),
5295 iso_format: true,
5296 us_format: false,
5297 eu_format: false,
5298 long_format: false,
5299 }
5300 }
5301}
5302
5303#[derive(Debug, Clone, Serialize, Deserialize)]
5305pub struct AmountFormatVariationConfig {
5306 #[serde(default)]
5308 pub enabled: bool,
5309 #[serde(default = "default_amount_variation_rate")]
5311 pub rate: f64,
5312 #[serde(default)]
5314 pub us_comma_format: bool,
5315 #[serde(default)]
5317 pub eu_format: bool,
5318 #[serde(default)]
5320 pub currency_prefix: bool,
5321 #[serde(default)]
5323 pub accounting_format: bool,
5324}
5325
5326fn default_amount_variation_rate() -> f64 {
5327 0.02
5328}
5329
5330impl Default for AmountFormatVariationConfig {
5331 fn default() -> Self {
5332 Self {
5333 enabled: false,
5334 rate: default_amount_variation_rate(),
5335 us_comma_format: false,
5336 eu_format: false,
5337 currency_prefix: false,
5338 accounting_format: false,
5339 }
5340 }
5341}
5342
5343#[derive(Debug, Clone, Serialize, Deserialize)]
5345pub struct IdentifierFormatVariationConfig {
5346 #[serde(default)]
5348 pub enabled: bool,
5349 #[serde(default = "default_identifier_variation_rate")]
5351 pub rate: f64,
5352 #[serde(default)]
5354 pub case_variations: bool,
5355 #[serde(default)]
5357 pub padding_variations: bool,
5358 #[serde(default)]
5360 pub separator_variations: bool,
5361}
5362
5363fn default_identifier_variation_rate() -> f64 {
5364 0.02
5365}
5366
5367impl Default for IdentifierFormatVariationConfig {
5368 fn default() -> Self {
5369 Self {
5370 enabled: false,
5371 rate: default_identifier_variation_rate(),
5372 case_variations: false,
5373 padding_variations: false,
5374 separator_variations: false,
5375 }
5376 }
5377}
5378
5379#[derive(Debug, Clone, Serialize, Deserialize)]
5381pub struct DuplicateSchemaConfig {
5382 #[serde(default)]
5384 pub enabled: bool,
5385 #[serde(default = "default_duplicate_rate")]
5387 pub rate: f64,
5388 #[serde(default = "default_exact_duplicate_ratio")]
5390 pub exact_duplicate_ratio: f64,
5391 #[serde(default = "default_near_duplicate_ratio")]
5393 pub near_duplicate_ratio: f64,
5394 #[serde(default = "default_fuzzy_duplicate_ratio")]
5396 pub fuzzy_duplicate_ratio: f64,
5397 #[serde(default = "default_max_date_offset")]
5399 pub max_date_offset_days: u32,
5400 #[serde(default = "default_max_amount_variance")]
5402 pub max_amount_variance: f64,
5403}
5404
5405fn default_duplicate_rate() -> f64 {
5406 0.005
5407}
5408fn default_exact_duplicate_ratio() -> f64 {
5409 0.4
5410}
5411fn default_near_duplicate_ratio() -> f64 {
5412 0.35
5413}
5414fn default_fuzzy_duplicate_ratio() -> f64 {
5415 0.25
5416}
5417fn default_max_date_offset() -> u32 {
5418 3
5419}
5420fn default_max_amount_variance() -> f64 {
5421 0.01
5422}
5423
5424impl Default for DuplicateSchemaConfig {
5425 fn default() -> Self {
5426 Self {
5427 enabled: false,
5428 rate: default_duplicate_rate(),
5429 exact_duplicate_ratio: default_exact_duplicate_ratio(),
5430 near_duplicate_ratio: default_near_duplicate_ratio(),
5431 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
5432 max_date_offset_days: default_max_date_offset(),
5433 max_amount_variance: default_max_amount_variance(),
5434 }
5435 }
5436}
5437
5438#[derive(Debug, Clone, Serialize, Deserialize)]
5440pub struct EncodingIssueSchemaConfig {
5441 #[serde(default)]
5443 pub enabled: bool,
5444 #[serde(default = "default_encoding_rate")]
5446 pub rate: f64,
5447 #[serde(default)]
5449 pub mojibake: bool,
5450 #[serde(default)]
5452 pub html_entities: bool,
5453 #[serde(default)]
5455 pub bom_issues: bool,
5456}
5457
5458fn default_encoding_rate() -> f64 {
5459 0.001
5460}
5461
5462impl Default for EncodingIssueSchemaConfig {
5463 fn default() -> Self {
5464 Self {
5465 enabled: false,
5466 rate: default_encoding_rate(),
5467 mojibake: false,
5468 html_entities: false,
5469 bom_issues: false,
5470 }
5471 }
5472}
5473
5474#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5476pub struct SinkQualityProfiles {
5477 #[serde(default)]
5479 pub csv: Option<SinkQualityOverride>,
5480 #[serde(default)]
5482 pub json: Option<SinkQualityOverride>,
5483 #[serde(default)]
5485 pub parquet: Option<SinkQualityOverride>,
5486}
5487
5488#[derive(Debug, Clone, Serialize, Deserialize)]
5490pub struct SinkQualityOverride {
5491 pub enabled: Option<bool>,
5493 pub missing_rate: Option<f64>,
5495 pub typo_rate: Option<f64>,
5497 pub format_variation_rate: Option<f64>,
5499 pub duplicate_rate: Option<f64>,
5501}
5502
5503#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5515pub struct AccountingStandardsConfig {
5516 #[serde(default)]
5518 pub enabled: bool,
5519
5520 #[serde(default, skip_serializing_if = "Option::is_none")]
5524 pub framework: Option<AccountingFrameworkConfig>,
5525
5526 #[serde(default)]
5528 pub revenue_recognition: RevenueRecognitionConfig,
5529
5530 #[serde(default)]
5532 pub leases: LeaseAccountingConfig,
5533
5534 #[serde(default)]
5536 pub fair_value: FairValueConfig,
5537
5538 #[serde(default)]
5540 pub impairment: ImpairmentConfig,
5541
5542 #[serde(default)]
5544 pub business_combinations: BusinessCombinationsConfig,
5545
5546 #[serde(default)]
5548 pub expected_credit_loss: EclConfig,
5549
5550 #[serde(default)]
5552 pub generate_differences: bool,
5553}
5554
5555#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5557#[serde(rename_all = "snake_case")]
5558pub enum AccountingFrameworkConfig {
5559 #[default]
5561 UsGaap,
5562 Ifrs,
5564 DualReporting,
5566 FrenchGaap,
5568 GermanGaap,
5570}
5571
5572#[derive(Debug, Clone, Serialize, Deserialize)]
5574pub struct RevenueRecognitionConfig {
5575 #[serde(default)]
5577 pub enabled: bool,
5578
5579 #[serde(default = "default_true")]
5581 pub generate_contracts: bool,
5582
5583 #[serde(default = "default_avg_obligations")]
5585 pub avg_obligations_per_contract: f64,
5586
5587 #[serde(default = "default_variable_consideration_rate")]
5589 pub variable_consideration_rate: f64,
5590
5591 #[serde(default = "default_over_time_rate")]
5593 pub over_time_recognition_rate: f64,
5594
5595 #[serde(default = "default_contract_count")]
5597 pub contract_count: usize,
5598}
5599
5600fn default_avg_obligations() -> f64 {
5601 2.0
5602}
5603
5604fn default_variable_consideration_rate() -> f64 {
5605 0.15
5606}
5607
5608fn default_over_time_rate() -> f64 {
5609 0.30
5610}
5611
5612fn default_contract_count() -> usize {
5613 100
5614}
5615
5616impl Default for RevenueRecognitionConfig {
5617 fn default() -> Self {
5618 Self {
5619 enabled: false,
5620 generate_contracts: true,
5621 avg_obligations_per_contract: default_avg_obligations(),
5622 variable_consideration_rate: default_variable_consideration_rate(),
5623 over_time_recognition_rate: default_over_time_rate(),
5624 contract_count: default_contract_count(),
5625 }
5626 }
5627}
5628
5629#[derive(Debug, Clone, Serialize, Deserialize)]
5631pub struct LeaseAccountingConfig {
5632 #[serde(default)]
5634 pub enabled: bool,
5635
5636 #[serde(default = "default_lease_count")]
5638 pub lease_count: usize,
5639
5640 #[serde(default = "default_finance_lease_pct")]
5642 pub finance_lease_percent: f64,
5643
5644 #[serde(default = "default_avg_lease_term")]
5646 pub avg_lease_term_months: u32,
5647
5648 #[serde(default = "default_true")]
5650 pub generate_amortization: bool,
5651
5652 #[serde(default = "default_real_estate_pct")]
5654 pub real_estate_percent: f64,
5655}
5656
5657fn default_lease_count() -> usize {
5658 50
5659}
5660
5661fn default_finance_lease_pct() -> f64 {
5662 0.30
5663}
5664
5665fn default_avg_lease_term() -> u32 {
5666 60
5667}
5668
5669fn default_real_estate_pct() -> f64 {
5670 0.40
5671}
5672
5673impl Default for LeaseAccountingConfig {
5674 fn default() -> Self {
5675 Self {
5676 enabled: false,
5677 lease_count: default_lease_count(),
5678 finance_lease_percent: default_finance_lease_pct(),
5679 avg_lease_term_months: default_avg_lease_term(),
5680 generate_amortization: true,
5681 real_estate_percent: default_real_estate_pct(),
5682 }
5683 }
5684}
5685
5686#[derive(Debug, Clone, Serialize, Deserialize)]
5688pub struct FairValueConfig {
5689 #[serde(default)]
5691 pub enabled: bool,
5692
5693 #[serde(default = "default_fv_count")]
5695 pub measurement_count: usize,
5696
5697 #[serde(default = "default_level1_pct")]
5699 pub level1_percent: f64,
5700
5701 #[serde(default = "default_level2_pct")]
5703 pub level2_percent: f64,
5704
5705 #[serde(default = "default_level3_pct")]
5707 pub level3_percent: f64,
5708
5709 #[serde(default)]
5711 pub include_sensitivity_analysis: bool,
5712}
5713
5714fn default_fv_count() -> usize {
5715 25
5716}
5717
5718fn default_level1_pct() -> f64 {
5719 0.40
5720}
5721
5722fn default_level2_pct() -> f64 {
5723 0.35
5724}
5725
5726fn default_level3_pct() -> f64 {
5727 0.25
5728}
5729
5730impl Default for FairValueConfig {
5731 fn default() -> Self {
5732 Self {
5733 enabled: false,
5734 measurement_count: default_fv_count(),
5735 level1_percent: default_level1_pct(),
5736 level2_percent: default_level2_pct(),
5737 level3_percent: default_level3_pct(),
5738 include_sensitivity_analysis: false,
5739 }
5740 }
5741}
5742
5743#[derive(Debug, Clone, Serialize, Deserialize)]
5745pub struct ImpairmentConfig {
5746 #[serde(default)]
5748 pub enabled: bool,
5749
5750 #[serde(default = "default_impairment_count")]
5752 pub test_count: usize,
5753
5754 #[serde(default = "default_impairment_rate")]
5756 pub impairment_rate: f64,
5757
5758 #[serde(default = "default_true")]
5760 pub generate_projections: bool,
5761
5762 #[serde(default)]
5764 pub include_goodwill: bool,
5765}
5766
5767fn default_impairment_count() -> usize {
5768 15
5769}
5770
5771fn default_impairment_rate() -> f64 {
5772 0.10
5773}
5774
5775impl Default for ImpairmentConfig {
5776 fn default() -> Self {
5777 Self {
5778 enabled: false,
5779 test_count: default_impairment_count(),
5780 impairment_rate: default_impairment_rate(),
5781 generate_projections: true,
5782 include_goodwill: false,
5783 }
5784 }
5785}
5786
5787#[derive(Debug, Clone, Serialize, Deserialize)]
5793pub struct BusinessCombinationsConfig {
5794 #[serde(default)]
5796 pub enabled: bool,
5797
5798 #[serde(default = "default_bc_acquisition_count")]
5800 pub acquisition_count: usize,
5801}
5802
5803fn default_bc_acquisition_count() -> usize {
5804 2
5805}
5806
5807impl Default for BusinessCombinationsConfig {
5808 fn default() -> Self {
5809 Self {
5810 enabled: false,
5811 acquisition_count: default_bc_acquisition_count(),
5812 }
5813 }
5814}
5815
5816#[derive(Debug, Clone, Serialize, Deserialize)]
5822pub struct EclConfig {
5823 #[serde(default)]
5825 pub enabled: bool,
5826
5827 #[serde(default = "default_ecl_base_weight")]
5829 pub base_scenario_weight: f64,
5830
5831 #[serde(default = "default_ecl_base_multiplier")]
5833 pub base_scenario_multiplier: f64,
5834
5835 #[serde(default = "default_ecl_optimistic_weight")]
5837 pub optimistic_scenario_weight: f64,
5838
5839 #[serde(default = "default_ecl_optimistic_multiplier")]
5841 pub optimistic_scenario_multiplier: f64,
5842
5843 #[serde(default = "default_ecl_pessimistic_weight")]
5845 pub pessimistic_scenario_weight: f64,
5846
5847 #[serde(default = "default_ecl_pessimistic_multiplier")]
5849 pub pessimistic_scenario_multiplier: f64,
5850}
5851
5852fn default_ecl_base_weight() -> f64 {
5853 0.50
5854}
5855fn default_ecl_base_multiplier() -> f64 {
5856 1.0
5857}
5858fn default_ecl_optimistic_weight() -> f64 {
5859 0.30
5860}
5861fn default_ecl_optimistic_multiplier() -> f64 {
5862 0.8
5863}
5864fn default_ecl_pessimistic_weight() -> f64 {
5865 0.20
5866}
5867fn default_ecl_pessimistic_multiplier() -> f64 {
5868 1.4
5869}
5870
5871impl Default for EclConfig {
5872 fn default() -> Self {
5873 Self {
5874 enabled: false,
5875 base_scenario_weight: default_ecl_base_weight(),
5876 base_scenario_multiplier: default_ecl_base_multiplier(),
5877 optimistic_scenario_weight: default_ecl_optimistic_weight(),
5878 optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5879 pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5880 pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5881 }
5882 }
5883}
5884
5885#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5898pub struct AuditStandardsConfig {
5899 #[serde(default)]
5901 pub enabled: bool,
5902
5903 #[serde(default)]
5905 pub isa_compliance: IsaComplianceConfig,
5906
5907 #[serde(default)]
5909 pub analytical_procedures: AnalyticalProceduresConfig,
5910
5911 #[serde(default)]
5913 pub confirmations: ConfirmationsConfig,
5914
5915 #[serde(default)]
5917 pub opinion: AuditOpinionConfig,
5918
5919 #[serde(default)]
5921 pub generate_audit_trail: bool,
5922
5923 #[serde(default)]
5925 pub sox: SoxComplianceConfig,
5926
5927 #[serde(default)]
5929 pub pcaob: PcaobConfig,
5930}
5931
5932#[derive(Debug, Clone, Serialize, Deserialize)]
5934pub struct IsaComplianceConfig {
5935 #[serde(default)]
5937 pub enabled: bool,
5938
5939 #[serde(default = "default_compliance_level")]
5941 pub compliance_level: String,
5942
5943 #[serde(default = "default_true")]
5945 pub generate_isa_mappings: bool,
5946
5947 #[serde(default = "default_true")]
5949 pub generate_coverage_summary: bool,
5950
5951 #[serde(default)]
5953 pub include_pcaob: bool,
5954
5955 #[serde(default = "default_audit_framework")]
5957 pub framework: String,
5958}
5959
5960fn default_compliance_level() -> String {
5961 "standard".to_string()
5962}
5963
5964fn default_audit_framework() -> String {
5965 "isa".to_string()
5966}
5967
5968impl Default for IsaComplianceConfig {
5969 fn default() -> Self {
5970 Self {
5971 enabled: false,
5972 compliance_level: default_compliance_level(),
5973 generate_isa_mappings: true,
5974 generate_coverage_summary: true,
5975 include_pcaob: false,
5976 framework: default_audit_framework(),
5977 }
5978 }
5979}
5980
5981#[derive(Debug, Clone, Serialize, Deserialize)]
5983pub struct AnalyticalProceduresConfig {
5984 #[serde(default)]
5986 pub enabled: bool,
5987
5988 #[serde(default = "default_procedures_per_account")]
5990 pub procedures_per_account: usize,
5991
5992 #[serde(default = "default_variance_probability")]
5994 pub variance_probability: f64,
5995
5996 #[serde(default = "default_true")]
5998 pub generate_investigations: bool,
5999
6000 #[serde(default = "default_true")]
6002 pub include_ratio_analysis: bool,
6003}
6004
6005fn default_procedures_per_account() -> usize {
6006 3
6007}
6008
6009fn default_variance_probability() -> f64 {
6010 0.20
6011}
6012
6013impl Default for AnalyticalProceduresConfig {
6014 fn default() -> Self {
6015 Self {
6016 enabled: false,
6017 procedures_per_account: default_procedures_per_account(),
6018 variance_probability: default_variance_probability(),
6019 generate_investigations: true,
6020 include_ratio_analysis: true,
6021 }
6022 }
6023}
6024
6025#[derive(Debug, Clone, Serialize, Deserialize)]
6027pub struct ConfirmationsConfig {
6028 #[serde(default)]
6030 pub enabled: bool,
6031
6032 #[serde(default = "default_confirmation_count")]
6034 pub confirmation_count: usize,
6035
6036 #[serde(default = "default_positive_response_rate")]
6038 pub positive_response_rate: f64,
6039
6040 #[serde(default = "default_exception_rate_confirm")]
6042 pub exception_rate: f64,
6043
6044 #[serde(default = "default_non_response_rate")]
6046 pub non_response_rate: f64,
6047
6048 #[serde(default = "default_true")]
6050 pub generate_alternative_procedures: bool,
6051}
6052
6053fn default_confirmation_count() -> usize {
6054 50
6055}
6056
6057fn default_positive_response_rate() -> f64 {
6058 0.85
6059}
6060
6061fn default_exception_rate_confirm() -> f64 {
6062 0.10
6063}
6064
6065fn default_non_response_rate() -> f64 {
6066 0.05
6067}
6068
6069impl Default for ConfirmationsConfig {
6070 fn default() -> Self {
6071 Self {
6072 enabled: false,
6073 confirmation_count: default_confirmation_count(),
6074 positive_response_rate: default_positive_response_rate(),
6075 exception_rate: default_exception_rate_confirm(),
6076 non_response_rate: default_non_response_rate(),
6077 generate_alternative_procedures: true,
6078 }
6079 }
6080}
6081
6082#[derive(Debug, Clone, Serialize, Deserialize)]
6084pub struct AuditOpinionConfig {
6085 #[serde(default)]
6087 pub enabled: bool,
6088
6089 #[serde(default = "default_true")]
6091 pub generate_kam: bool,
6092
6093 #[serde(default = "default_kam_count")]
6095 pub average_kam_count: usize,
6096
6097 #[serde(default = "default_modified_opinion_rate")]
6099 pub modified_opinion_rate: f64,
6100
6101 #[serde(default)]
6103 pub include_emphasis_of_matter: bool,
6104
6105 #[serde(default = "default_true")]
6107 pub include_going_concern: bool,
6108}
6109
6110fn default_kam_count() -> usize {
6111 3
6112}
6113
6114fn default_modified_opinion_rate() -> f64 {
6115 0.05
6116}
6117
6118impl Default for AuditOpinionConfig {
6119 fn default() -> Self {
6120 Self {
6121 enabled: false,
6122 generate_kam: true,
6123 average_kam_count: default_kam_count(),
6124 modified_opinion_rate: default_modified_opinion_rate(),
6125 include_emphasis_of_matter: false,
6126 include_going_concern: true,
6127 }
6128 }
6129}
6130
6131#[derive(Debug, Clone, Serialize, Deserialize)]
6133pub struct SoxComplianceConfig {
6134 #[serde(default)]
6136 pub enabled: bool,
6137
6138 #[serde(default = "default_true")]
6140 pub generate_302_certifications: bool,
6141
6142 #[serde(default = "default_true")]
6144 pub generate_404_assessments: bool,
6145
6146 #[serde(default = "default_sox_materiality_threshold")]
6148 pub materiality_threshold: f64,
6149
6150 #[serde(default = "default_material_weakness_rate")]
6152 pub material_weakness_rate: f64,
6153
6154 #[serde(default = "default_significant_deficiency_rate")]
6156 pub significant_deficiency_rate: f64,
6157}
6158
6159fn default_material_weakness_rate() -> f64 {
6160 0.02
6161}
6162
6163fn default_significant_deficiency_rate() -> f64 {
6164 0.08
6165}
6166
6167impl Default for SoxComplianceConfig {
6168 fn default() -> Self {
6169 Self {
6170 enabled: false,
6171 generate_302_certifications: true,
6172 generate_404_assessments: true,
6173 materiality_threshold: default_sox_materiality_threshold(),
6174 material_weakness_rate: default_material_weakness_rate(),
6175 significant_deficiency_rate: default_significant_deficiency_rate(),
6176 }
6177 }
6178}
6179
6180#[derive(Debug, Clone, Serialize, Deserialize)]
6182pub struct PcaobConfig {
6183 #[serde(default)]
6185 pub enabled: bool,
6186
6187 #[serde(default)]
6189 pub is_pcaob_audit: bool,
6190
6191 #[serde(default = "default_true")]
6193 pub generate_cam: bool,
6194
6195 #[serde(default)]
6197 pub include_icfr_opinion: bool,
6198
6199 #[serde(default)]
6201 pub generate_standard_mappings: bool,
6202}
6203
6204impl Default for PcaobConfig {
6205 fn default() -> Self {
6206 Self {
6207 enabled: false,
6208 is_pcaob_audit: false,
6209 generate_cam: true,
6210 include_icfr_opinion: false,
6211 generate_standard_mappings: false,
6212 }
6213 }
6214}
6215
6216#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6229pub struct AdvancedDistributionConfig {
6230 #[serde(default)]
6232 pub enabled: bool,
6233
6234 #[serde(default)]
6236 pub amounts: MixtureDistributionSchemaConfig,
6237
6238 #[serde(default)]
6240 pub correlations: CorrelationSchemaConfig,
6241
6242 #[serde(default)]
6244 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
6245
6246 #[serde(default)]
6248 pub regime_changes: RegimeChangeSchemaConfig,
6249
6250 #[serde(default)]
6252 pub industry_profile: Option<IndustryProfileType>,
6253
6254 #[serde(default)]
6256 pub validation: StatisticalValidationSchemaConfig,
6257
6258 #[serde(default)]
6264 pub pareto: Option<ParetoSchemaConfig>,
6265}
6266
6267#[derive(Debug, Clone, Serialize, Deserialize)]
6272pub struct ParetoSchemaConfig {
6273 #[serde(default)]
6276 pub enabled: bool,
6277
6278 #[serde(default = "default_pareto_alpha")]
6281 pub alpha: f64,
6282
6283 #[serde(default = "default_pareto_x_min")]
6286 pub x_min: f64,
6287
6288 #[serde(default)]
6291 pub max_value: Option<f64>,
6292
6293 #[serde(default = "default_pareto_decimal_places")]
6295 pub decimal_places: u8,
6296}
6297
6298fn default_pareto_alpha() -> f64 {
6299 2.0
6300}
6301
6302fn default_pareto_x_min() -> f64 {
6303 100.0
6304}
6305
6306fn default_pareto_decimal_places() -> u8 {
6307 2
6308}
6309
6310impl Default for ParetoSchemaConfig {
6311 fn default() -> Self {
6312 Self {
6313 enabled: false,
6314 alpha: default_pareto_alpha(),
6315 x_min: default_pareto_x_min(),
6316 max_value: None,
6317 decimal_places: default_pareto_decimal_places(),
6318 }
6319 }
6320}
6321
6322impl ParetoSchemaConfig {
6323 pub fn to_core_config(&self) -> datasynth_core::distributions::ParetoConfig {
6325 datasynth_core::distributions::ParetoConfig {
6326 alpha: self.alpha,
6327 x_min: self.x_min,
6328 max_value: self.max_value,
6329 decimal_places: self.decimal_places,
6330 }
6331 }
6332}
6333
6334#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6336#[serde(rename_all = "snake_case")]
6337pub enum IndustryProfileType {
6338 Retail,
6340 Manufacturing,
6342 FinancialServices,
6344 Healthcare,
6346 Technology,
6348}
6349
6350#[derive(Debug, Clone, Serialize, Deserialize)]
6352pub struct MixtureDistributionSchemaConfig {
6353 #[serde(default)]
6355 pub enabled: bool,
6356
6357 #[serde(default = "default_mixture_type")]
6359 pub distribution_type: MixtureDistributionType,
6360
6361 #[serde(default)]
6363 pub components: Vec<MixtureComponentConfig>,
6364
6365 #[serde(default = "default_min_amount")]
6367 pub min_value: f64,
6368
6369 #[serde(default)]
6371 pub max_value: Option<f64>,
6372
6373 #[serde(default = "default_decimal_places")]
6375 pub decimal_places: u8,
6376}
6377
6378fn default_mixture_type() -> MixtureDistributionType {
6379 MixtureDistributionType::LogNormal
6380}
6381
6382fn default_min_amount() -> f64 {
6383 0.01
6384}
6385
6386fn default_decimal_places() -> u8 {
6387 2
6388}
6389
6390impl Default for MixtureDistributionSchemaConfig {
6391 fn default() -> Self {
6392 Self {
6393 enabled: false,
6394 distribution_type: MixtureDistributionType::LogNormal,
6395 components: Vec::new(),
6396 min_value: 0.01,
6397 max_value: None,
6398 decimal_places: 2,
6399 }
6400 }
6401}
6402
6403impl MixtureDistributionSchemaConfig {
6404 pub fn to_log_normal_config(
6411 &self,
6412 ) -> Option<datasynth_core::distributions::LogNormalMixtureConfig> {
6413 if self.components.is_empty() {
6414 return None;
6415 }
6416 Some(datasynth_core::distributions::LogNormalMixtureConfig {
6417 components: self
6418 .components
6419 .iter()
6420 .map(|c| match &c.label {
6421 Some(lbl) => datasynth_core::distributions::LogNormalComponent::with_label(
6422 c.weight,
6423 c.mu,
6424 c.sigma,
6425 lbl.clone(),
6426 ),
6427 None => datasynth_core::distributions::LogNormalComponent::new(
6428 c.weight, c.mu, c.sigma,
6429 ),
6430 })
6431 .collect(),
6432 min_value: self.min_value,
6433 max_value: self.max_value,
6434 decimal_places: self.decimal_places,
6435 })
6436 }
6437
6438 pub fn to_gaussian_config(
6441 &self,
6442 ) -> Option<datasynth_core::distributions::GaussianMixtureConfig> {
6443 if self.components.is_empty() {
6444 return None;
6445 }
6446 Some(datasynth_core::distributions::GaussianMixtureConfig {
6447 components: self
6448 .components
6449 .iter()
6450 .map(|c| {
6451 datasynth_core::distributions::GaussianComponent::new(c.weight, c.mu, c.sigma)
6452 })
6453 .collect(),
6454 allow_negative: true,
6455 min_value: Some(self.min_value),
6456 max_value: self.max_value,
6457 })
6458 }
6459}
6460
6461#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6463#[serde(rename_all = "snake_case")]
6464pub enum MixtureDistributionType {
6465 Gaussian,
6467 #[default]
6469 LogNormal,
6470}
6471
6472#[derive(Debug, Clone, Serialize, Deserialize)]
6474pub struct MixtureComponentConfig {
6475 pub weight: f64,
6477
6478 pub mu: f64,
6480
6481 pub sigma: f64,
6483
6484 #[serde(default)]
6486 pub label: Option<String>,
6487}
6488
6489#[derive(Debug, Clone, Serialize, Deserialize)]
6491pub struct CorrelationSchemaConfig {
6492 #[serde(default)]
6494 pub enabled: bool,
6495
6496 #[serde(default)]
6498 pub copula_type: CopulaSchemaType,
6499
6500 #[serde(default)]
6502 pub fields: Vec<CorrelatedFieldConfig>,
6503
6504 #[serde(default)]
6507 pub matrix: Vec<f64>,
6508
6509 #[serde(default)]
6511 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
6512}
6513
6514impl Default for CorrelationSchemaConfig {
6515 fn default() -> Self {
6516 Self {
6517 enabled: false,
6518 copula_type: CopulaSchemaType::Gaussian,
6519 fields: Vec::new(),
6520 matrix: Vec::new(),
6521 expected_correlations: Vec::new(),
6522 }
6523 }
6524}
6525
6526impl CorrelationSchemaConfig {
6527 pub fn correlation_between(&self, field_a: &str, field_b: &str) -> Option<f64> {
6533 let idx_a = self.fields.iter().position(|f| f.name == field_a)?;
6534 let idx_b = self.fields.iter().position(|f| f.name == field_b)?;
6535 if idx_a == idx_b {
6536 return Some(1.0);
6537 }
6538 let (i, j) = if idx_a < idx_b {
6539 (idx_a, idx_b)
6540 } else {
6541 (idx_b, idx_a)
6542 };
6543 let n = self.fields.len();
6544 if self.matrix.len() == n * n {
6546 return self.matrix.get(idx_a * n + idx_b).copied();
6547 }
6548 let expected_tri = n * (n - 1) / 2;
6550 if self.matrix.len() == expected_tri {
6551 let flat = i * (n - 1) - i * (i.saturating_sub(1)) / 2 + (j - i - 1);
6555 return self.matrix.get(flat).copied();
6556 }
6557 None
6558 }
6559
6560 pub fn to_core_config_for_pair(
6565 &self,
6566 field_a: &str,
6567 field_b: &str,
6568 ) -> Option<datasynth_core::distributions::CopulaConfig> {
6569 if !self.enabled {
6570 return None;
6571 }
6572 let rho = self.correlation_between(field_a, field_b)?;
6573 use datasynth_core::distributions::{CopulaConfig, CopulaType};
6574 let copula_type = match self.copula_type {
6575 CopulaSchemaType::Gaussian => CopulaType::Gaussian,
6576 CopulaSchemaType::Clayton => CopulaType::Clayton,
6577 CopulaSchemaType::Gumbel => CopulaType::Gumbel,
6578 CopulaSchemaType::Frank => CopulaType::Frank,
6579 CopulaSchemaType::StudentT => CopulaType::StudentT,
6580 };
6581 let theta = rho.clamp(-0.999, 0.999);
6586 Some(CopulaConfig {
6587 copula_type,
6588 theta,
6589 degrees_of_freedom: 4.0,
6590 })
6591 }
6592}
6593
6594#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6596#[serde(rename_all = "snake_case")]
6597pub enum CopulaSchemaType {
6598 #[default]
6600 Gaussian,
6601 Clayton,
6603 Gumbel,
6605 Frank,
6607 StudentT,
6609}
6610
6611#[derive(Debug, Clone, Serialize, Deserialize)]
6613pub struct CorrelatedFieldConfig {
6614 pub name: String,
6616
6617 #[serde(default)]
6619 pub distribution: MarginalDistributionConfig,
6620}
6621
6622#[derive(Debug, Clone, Serialize, Deserialize)]
6624#[serde(tag = "type", rename_all = "snake_case")]
6625pub enum MarginalDistributionConfig {
6626 Normal {
6628 mu: f64,
6630 sigma: f64,
6632 },
6633 LogNormal {
6635 mu: f64,
6637 sigma: f64,
6639 },
6640 Uniform {
6642 min: f64,
6644 max: f64,
6646 },
6647 DiscreteUniform {
6649 min: i32,
6651 max: i32,
6653 },
6654}
6655
6656impl Default for MarginalDistributionConfig {
6657 fn default() -> Self {
6658 Self::Normal {
6659 mu: 0.0,
6660 sigma: 1.0,
6661 }
6662 }
6663}
6664
6665#[derive(Debug, Clone, Serialize, Deserialize)]
6667pub struct ExpectedCorrelationConfig {
6668 pub field1: String,
6670 pub field2: String,
6672 pub expected_r: f64,
6674 #[serde(default = "default_correlation_tolerance")]
6676 pub tolerance: f64,
6677}
6678
6679fn default_correlation_tolerance() -> f64 {
6680 0.10
6681}
6682
6683#[derive(Debug, Clone, Serialize, Deserialize)]
6685pub struct ConditionalDistributionSchemaConfig {
6686 pub output_field: String,
6688
6689 pub input_field: String,
6691
6692 #[serde(default)]
6694 pub breakpoints: Vec<ConditionalBreakpointConfig>,
6695
6696 #[serde(default)]
6698 pub default_distribution: ConditionalDistributionParamsConfig,
6699
6700 #[serde(default)]
6702 pub min_value: Option<f64>,
6703
6704 #[serde(default)]
6706 pub max_value: Option<f64>,
6707
6708 #[serde(default = "default_decimal_places")]
6710 pub decimal_places: u8,
6711}
6712
6713#[derive(Debug, Clone, Serialize, Deserialize)]
6715pub struct ConditionalBreakpointConfig {
6716 pub threshold: f64,
6718
6719 pub distribution: ConditionalDistributionParamsConfig,
6721}
6722
6723impl ConditionalDistributionSchemaConfig {
6724 pub fn to_core_config(&self) -> datasynth_core::distributions::ConditionalDistributionConfig {
6728 use datasynth_core::distributions::{
6729 Breakpoint, ConditionalDistributionConfig, ConditionalDistributionParams,
6730 };
6731
6732 let default_distribution = convert_conditional_params(&self.default_distribution);
6733 let breakpoints: Vec<Breakpoint> = self
6734 .breakpoints
6735 .iter()
6736 .map(|bp| Breakpoint {
6737 threshold: bp.threshold,
6738 distribution: convert_conditional_params(&bp.distribution),
6739 })
6740 .collect();
6741
6742 let final_default = if breakpoints.is_empty() {
6747 default_distribution
6748 } else {
6749 match default_distribution {
6750 ConditionalDistributionParams::Fixed { value: 0.0 } => {
6751 breakpoints[0].distribution.clone()
6754 }
6755 other => other,
6756 }
6757 };
6758
6759 ConditionalDistributionConfig {
6760 output_field: self.output_field.clone(),
6761 input_field: self.input_field.clone(),
6762 breakpoints,
6763 default_distribution: final_default,
6764 min_value: self.min_value,
6765 max_value: self.max_value,
6766 decimal_places: self.decimal_places,
6767 }
6768 }
6769}
6770
6771fn convert_conditional_params(
6772 p: &ConditionalDistributionParamsConfig,
6773) -> datasynth_core::distributions::ConditionalDistributionParams {
6774 use datasynth_core::distributions::ConditionalDistributionParams as Core;
6775 match p {
6776 ConditionalDistributionParamsConfig::Fixed { value } => Core::Fixed { value: *value },
6777 ConditionalDistributionParamsConfig::Normal { mu, sigma } => Core::Normal {
6778 mu: *mu,
6779 sigma: *sigma,
6780 },
6781 ConditionalDistributionParamsConfig::LogNormal { mu, sigma } => Core::LogNormal {
6782 mu: *mu,
6783 sigma: *sigma,
6784 },
6785 ConditionalDistributionParamsConfig::Uniform { min, max } => Core::Uniform {
6786 min: *min,
6787 max: *max,
6788 },
6789 ConditionalDistributionParamsConfig::Beta {
6790 alpha,
6791 beta,
6792 min,
6793 max,
6794 } => Core::Beta {
6795 alpha: *alpha,
6796 beta: *beta,
6797 min: *min,
6798 max: *max,
6799 },
6800 ConditionalDistributionParamsConfig::Discrete { values, weights } => Core::Discrete {
6801 values: values.clone(),
6802 weights: weights.clone(),
6803 },
6804 }
6805}
6806
6807#[derive(Debug, Clone, Serialize, Deserialize)]
6809#[serde(tag = "type", rename_all = "snake_case")]
6810pub enum ConditionalDistributionParamsConfig {
6811 Fixed {
6813 value: f64,
6815 },
6816 Normal {
6818 mu: f64,
6820 sigma: f64,
6822 },
6823 LogNormal {
6825 mu: f64,
6827 sigma: f64,
6829 },
6830 Uniform {
6832 min: f64,
6834 max: f64,
6836 },
6837 Beta {
6839 alpha: f64,
6841 beta: f64,
6843 min: f64,
6845 max: f64,
6847 },
6848 Discrete {
6850 values: Vec<f64>,
6852 weights: Vec<f64>,
6854 },
6855}
6856
6857impl Default for ConditionalDistributionParamsConfig {
6858 fn default() -> Self {
6859 Self::Normal {
6860 mu: 0.0,
6861 sigma: 1.0,
6862 }
6863 }
6864}
6865
6866#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6868pub struct RegimeChangeSchemaConfig {
6869 #[serde(default)]
6871 pub enabled: bool,
6872
6873 #[serde(default)]
6875 pub changes: Vec<RegimeChangeEventConfig>,
6876
6877 #[serde(default)]
6879 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6880
6881 #[serde(default)]
6883 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6884}
6885
6886#[derive(Debug, Clone, Serialize, Deserialize)]
6888pub struct RegimeChangeEventConfig {
6889 pub date: String,
6891
6892 pub change_type: RegimeChangeTypeConfig,
6894
6895 #[serde(default)]
6897 pub description: Option<String>,
6898
6899 #[serde(default)]
6901 pub effects: Vec<RegimeEffectConfig>,
6902}
6903
6904#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6906#[serde(rename_all = "snake_case")]
6907pub enum RegimeChangeTypeConfig {
6908 Acquisition,
6910 Divestiture,
6912 PriceIncrease,
6914 PriceDecrease,
6916 ProductLaunch,
6918 ProductDiscontinuation,
6920 PolicyChange,
6922 CompetitorEntry,
6924 Custom,
6926}
6927
6928#[derive(Debug, Clone, Serialize, Deserialize)]
6930pub struct RegimeEffectConfig {
6931 pub field: String,
6933
6934 pub multiplier: f64,
6936}
6937
6938#[derive(Debug, Clone, Serialize, Deserialize)]
6940pub struct EconomicCycleSchemaConfig {
6941 #[serde(default)]
6943 pub enabled: bool,
6944
6945 #[serde(default = "default_cycle_period")]
6947 pub period_months: u32,
6948
6949 #[serde(default = "default_cycle_amplitude")]
6951 pub amplitude: f64,
6952
6953 #[serde(default)]
6955 pub phase_offset: u32,
6956
6957 #[serde(default)]
6959 pub recessions: Vec<RecessionPeriodConfig>,
6960}
6961
6962fn default_cycle_period() -> u32 {
6963 48
6964}
6965
6966fn default_cycle_amplitude() -> f64 {
6967 0.15
6968}
6969
6970impl Default for EconomicCycleSchemaConfig {
6971 fn default() -> Self {
6972 Self {
6973 enabled: false,
6974 period_months: 48,
6975 amplitude: 0.15,
6976 phase_offset: 0,
6977 recessions: Vec::new(),
6978 }
6979 }
6980}
6981
6982#[derive(Debug, Clone, Serialize, Deserialize)]
6984pub struct RecessionPeriodConfig {
6985 pub start_month: u32,
6987
6988 pub duration_months: u32,
6990
6991 #[serde(default = "default_recession_severity")]
6993 pub severity: f64,
6994}
6995
6996impl RegimeChangeSchemaConfig {
6997 pub fn apply_to(
7005 &self,
7006 drift: &mut datasynth_core::distributions::DriftConfig,
7007 generation_start: chrono::NaiveDate,
7008 ) {
7009 if !self.enabled {
7010 return;
7011 }
7012
7013 drift.enabled = true;
7015
7016 for event in &self.changes {
7018 let period = match chrono::NaiveDate::parse_from_str(&event.date, "%Y-%m-%d") {
7019 Ok(d) => {
7020 let days = (d - generation_start).num_days();
7021 if days < 0 {
7022 continue;
7023 }
7024 (days as f64 / 30.4).round() as u32
7027 }
7028 Err(_) => continue,
7029 };
7030 let change_type = convert_regime_change_type(event.change_type);
7031 let core_effects = event
7032 .effects
7033 .iter()
7034 .map(|e| datasynth_core::distributions::RegimeEffect {
7035 field: e.field.clone(),
7036 multiplier: e.multiplier,
7037 })
7038 .collect();
7039 drift
7040 .regime_changes
7041 .push(datasynth_core::distributions::RegimeChange {
7042 period,
7043 change_type,
7044 description: event.description.clone(),
7045 effects: core_effects,
7046 transition_periods: 0,
7047 });
7048 }
7049
7050 if let Some(ec) = &self.economic_cycle {
7052 if ec.enabled {
7053 let recession_periods: Vec<u32> = ec
7054 .recessions
7055 .iter()
7056 .flat_map(|r| r.start_month..r.start_month + r.duration_months)
7057 .collect();
7058 let severity = ec
7061 .recessions
7062 .iter()
7063 .map(|r| 1.0 - r.severity)
7064 .fold(0.75f64, f64::min);
7065 drift.economic_cycle = datasynth_core::distributions::EconomicCycleConfig {
7066 enabled: true,
7067 cycle_length: ec.period_months,
7068 amplitude: ec.amplitude,
7069 phase_offset: ec.phase_offset,
7070 recession_periods,
7071 recession_severity: severity,
7072 };
7073 drift.drift_type = datasynth_core::distributions::DriftType::Mixed;
7074 }
7075 }
7076
7077 for pd in &self.parameter_drifts {
7079 let drift_type = match pd.drift_type {
7080 ParameterDriftTypeConfig::Linear => {
7081 datasynth_core::distributions::ParameterDriftType::Linear
7082 }
7083 ParameterDriftTypeConfig::Exponential => {
7084 datasynth_core::distributions::ParameterDriftType::Exponential
7085 }
7086 ParameterDriftTypeConfig::Logistic => {
7087 datasynth_core::distributions::ParameterDriftType::Logistic
7088 }
7089 ParameterDriftTypeConfig::Step => {
7090 datasynth_core::distributions::ParameterDriftType::Step
7091 }
7092 };
7093 drift
7094 .parameter_drifts
7095 .push(datasynth_core::distributions::ParameterDrift {
7096 parameter: pd.parameter.clone(),
7097 drift_type,
7098 initial_value: pd.start_value,
7099 target_or_rate: pd.end_value,
7100 start_period: pd.start_period,
7101 end_period: pd.end_period,
7102 steepness: 1.0,
7103 });
7104 }
7105 }
7106}
7107
7108fn convert_regime_change_type(
7109 t: RegimeChangeTypeConfig,
7110) -> datasynth_core::distributions::RegimeChangeType {
7111 use datasynth_core::distributions::RegimeChangeType as Core;
7112 match t {
7113 RegimeChangeTypeConfig::Acquisition => Core::Acquisition,
7114 RegimeChangeTypeConfig::Divestiture => Core::Divestiture,
7115 RegimeChangeTypeConfig::PriceIncrease => Core::PriceIncrease,
7116 RegimeChangeTypeConfig::PriceDecrease => Core::PriceDecrease,
7117 RegimeChangeTypeConfig::ProductLaunch => Core::ProductLaunch,
7118 RegimeChangeTypeConfig::ProductDiscontinuation => Core::ProductDiscontinuation,
7119 RegimeChangeTypeConfig::PolicyChange => Core::PolicyChange,
7120 RegimeChangeTypeConfig::CompetitorEntry => Core::CompetitorEntry,
7121 RegimeChangeTypeConfig::Custom => Core::Custom,
7122 }
7123}
7124
7125fn default_recession_severity() -> f64 {
7126 0.20
7127}
7128
7129#[derive(Debug, Clone, Serialize, Deserialize)]
7131pub struct ParameterDriftSchemaConfig {
7132 pub parameter: String,
7134
7135 pub drift_type: ParameterDriftTypeConfig,
7137
7138 pub start_value: f64,
7140
7141 pub end_value: f64,
7143
7144 #[serde(default)]
7146 pub start_period: u32,
7147
7148 #[serde(default)]
7150 pub end_period: Option<u32>,
7151}
7152
7153#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7155#[serde(rename_all = "snake_case")]
7156pub enum ParameterDriftTypeConfig {
7157 #[default]
7159 Linear,
7160 Exponential,
7162 Logistic,
7164 Step,
7166}
7167
7168#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7170pub struct StatisticalValidationSchemaConfig {
7171 #[serde(default)]
7173 pub enabled: bool,
7174
7175 #[serde(default)]
7177 pub tests: Vec<StatisticalTestConfig>,
7178
7179 #[serde(default)]
7181 pub reporting: ValidationReportingConfig,
7182}
7183
7184#[derive(Debug, Clone, Serialize, Deserialize)]
7186#[serde(tag = "type", rename_all = "snake_case")]
7187pub enum StatisticalTestConfig {
7188 BenfordFirstDigit {
7190 #[serde(default = "default_benford_threshold")]
7192 threshold_mad: f64,
7193 #[serde(default = "default_benford_warning")]
7195 warning_mad: f64,
7196 },
7197 DistributionFit {
7199 target: TargetDistributionConfig,
7201 #[serde(default = "default_ks_significance")]
7203 ks_significance: f64,
7204 #[serde(default)]
7206 method: DistributionFitMethod,
7207 },
7208 CorrelationCheck {
7210 expected_correlations: Vec<ExpectedCorrelationConfig>,
7212 },
7213 ChiSquared {
7215 #[serde(default = "default_chi_squared_bins")]
7217 bins: usize,
7218 #[serde(default = "default_chi_squared_significance")]
7220 significance: f64,
7221 },
7222 AndersonDarling {
7224 target: TargetDistributionConfig,
7226 #[serde(default = "default_ad_significance")]
7228 significance: f64,
7229 },
7230}
7231
7232fn default_benford_threshold() -> f64 {
7233 0.015
7234}
7235
7236fn default_benford_warning() -> f64 {
7237 0.010
7238}
7239
7240fn default_ks_significance() -> f64 {
7241 0.05
7242}
7243
7244fn default_chi_squared_bins() -> usize {
7245 10
7246}
7247
7248fn default_chi_squared_significance() -> f64 {
7249 0.05
7250}
7251
7252fn default_ad_significance() -> f64 {
7253 0.05
7254}
7255
7256#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7258#[serde(rename_all = "snake_case")]
7259pub enum TargetDistributionConfig {
7260 Normal,
7262 #[default]
7264 LogNormal,
7265 Exponential,
7267 Uniform,
7269}
7270
7271#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7273#[serde(rename_all = "snake_case")]
7274pub enum DistributionFitMethod {
7275 #[default]
7277 KolmogorovSmirnov,
7278 AndersonDarling,
7280 ChiSquared,
7282}
7283
7284#[derive(Debug, Clone, Serialize, Deserialize)]
7286pub struct ValidationReportingConfig {
7287 #[serde(default)]
7289 pub output_report: bool,
7290
7291 #[serde(default)]
7293 pub format: ValidationReportFormat,
7294
7295 #[serde(default)]
7297 pub fail_on_error: bool,
7298
7299 #[serde(default = "default_true")]
7301 pub include_details: bool,
7302}
7303
7304impl Default for ValidationReportingConfig {
7305 fn default() -> Self {
7306 Self {
7307 output_report: false,
7308 format: ValidationReportFormat::Json,
7309 fail_on_error: false,
7310 include_details: true,
7311 }
7312 }
7313}
7314
7315#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7317#[serde(rename_all = "snake_case")]
7318pub enum ValidationReportFormat {
7319 #[default]
7321 Json,
7322 Yaml,
7324 Html,
7326}
7327
7328#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7340pub struct TemporalPatternsConfig {
7341 #[serde(default)]
7343 pub enabled: bool,
7344
7345 #[serde(default)]
7347 pub business_days: BusinessDaySchemaConfig,
7348
7349 #[serde(default)]
7351 pub calendars: CalendarSchemaConfig,
7352
7353 #[serde(default)]
7355 pub period_end: PeriodEndSchemaConfig,
7356
7357 #[serde(default)]
7359 pub processing_lags: ProcessingLagSchemaConfig,
7360
7361 #[serde(default)]
7363 pub fiscal_calendar: FiscalCalendarSchemaConfig,
7364
7365 #[serde(default)]
7367 pub intraday: IntraDaySchemaConfig,
7368
7369 #[serde(default)]
7371 pub timezones: TimezoneSchemaConfig,
7372}
7373
7374#[derive(Debug, Clone, Serialize, Deserialize)]
7376pub struct BusinessDaySchemaConfig {
7377 #[serde(default = "default_true")]
7379 pub enabled: bool,
7380
7381 #[serde(default = "default_half_day_policy")]
7383 pub half_day_policy: String,
7384
7385 #[serde(default)]
7387 pub settlement_rules: SettlementRulesSchemaConfig,
7388
7389 #[serde(default = "default_month_end_convention")]
7391 pub month_end_convention: String,
7392
7393 #[serde(default)]
7395 pub weekend_days: Option<Vec<String>>,
7396}
7397
7398fn default_half_day_policy() -> String {
7399 "half_day".to_string()
7400}
7401
7402fn default_month_end_convention() -> String {
7403 "modified_following".to_string()
7404}
7405
7406impl Default for BusinessDaySchemaConfig {
7407 fn default() -> Self {
7408 Self {
7409 enabled: true,
7410 half_day_policy: "half_day".to_string(),
7411 settlement_rules: SettlementRulesSchemaConfig::default(),
7412 month_end_convention: "modified_following".to_string(),
7413 weekend_days: None,
7414 }
7415 }
7416}
7417
7418#[derive(Debug, Clone, Serialize, Deserialize)]
7420pub struct SettlementRulesSchemaConfig {
7421 #[serde(default = "default_settlement_2")]
7423 pub equity_days: i32,
7424
7425 #[serde(default = "default_settlement_1")]
7427 pub government_bonds_days: i32,
7428
7429 #[serde(default = "default_settlement_2")]
7431 pub fx_spot_days: i32,
7432
7433 #[serde(default = "default_settlement_2")]
7435 pub corporate_bonds_days: i32,
7436
7437 #[serde(default = "default_wire_cutoff")]
7439 pub wire_cutoff_time: String,
7440
7441 #[serde(default = "default_settlement_1")]
7443 pub wire_international_days: i32,
7444
7445 #[serde(default = "default_settlement_1")]
7447 pub ach_days: i32,
7448}
7449
7450fn default_settlement_1() -> i32 {
7451 1
7452}
7453
7454fn default_settlement_2() -> i32 {
7455 2
7456}
7457
7458fn default_wire_cutoff() -> String {
7459 "14:00".to_string()
7460}
7461
7462impl Default for SettlementRulesSchemaConfig {
7463 fn default() -> Self {
7464 Self {
7465 equity_days: 2,
7466 government_bonds_days: 1,
7467 fx_spot_days: 2,
7468 corporate_bonds_days: 2,
7469 wire_cutoff_time: "14:00".to_string(),
7470 wire_international_days: 1,
7471 ach_days: 1,
7472 }
7473 }
7474}
7475
7476#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7478pub struct CalendarSchemaConfig {
7479 #[serde(default)]
7481 pub regions: Vec<String>,
7482
7483 #[serde(default)]
7485 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
7486}
7487
7488#[derive(Debug, Clone, Serialize, Deserialize)]
7490pub struct CustomHolidaySchemaConfig {
7491 pub name: String,
7493 pub month: u8,
7495 pub day: u8,
7497 #[serde(default = "default_holiday_multiplier")]
7499 pub activity_multiplier: f64,
7500}
7501
7502fn default_holiday_multiplier() -> f64 {
7503 0.05
7504}
7505
7506#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7508pub struct PeriodEndSchemaConfig {
7509 #[serde(default)]
7511 pub model: Option<String>,
7512
7513 #[serde(default)]
7515 pub month_end: Option<PeriodEndModelSchemaConfig>,
7516
7517 #[serde(default)]
7519 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
7520
7521 #[serde(default)]
7523 pub year_end: Option<PeriodEndModelSchemaConfig>,
7524}
7525
7526#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7528pub struct PeriodEndModelSchemaConfig {
7529 #[serde(default)]
7531 pub inherit_from: Option<String>,
7532
7533 #[serde(default)]
7535 pub additional_multiplier: Option<f64>,
7536
7537 #[serde(default)]
7539 pub start_day: Option<i32>,
7540
7541 #[serde(default)]
7543 pub base_multiplier: Option<f64>,
7544
7545 #[serde(default)]
7547 pub peak_multiplier: Option<f64>,
7548
7549 #[serde(default)]
7551 pub decay_rate: Option<f64>,
7552
7553 #[serde(default)]
7555 pub sustained_high_days: Option<i32>,
7556}
7557
7558#[derive(Debug, Clone, Serialize, Deserialize)]
7560pub struct ProcessingLagSchemaConfig {
7561 #[serde(default = "default_true")]
7563 pub enabled: bool,
7564
7565 #[serde(default)]
7567 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
7568
7569 #[serde(default)]
7571 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
7572
7573 #[serde(default)]
7575 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
7576
7577 #[serde(default)]
7579 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
7580
7581 #[serde(default)]
7583 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
7584
7585 #[serde(default)]
7587 pub payment_lag: Option<LagDistributionSchemaConfig>,
7588
7589 #[serde(default)]
7591 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
7592
7593 #[serde(default)]
7595 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
7596}
7597
7598impl Default for ProcessingLagSchemaConfig {
7599 fn default() -> Self {
7600 Self {
7601 enabled: true,
7602 sales_order_lag: None,
7603 purchase_order_lag: None,
7604 goods_receipt_lag: None,
7605 invoice_receipt_lag: None,
7606 invoice_issue_lag: None,
7607 payment_lag: None,
7608 journal_entry_lag: None,
7609 cross_day_posting: None,
7610 }
7611 }
7612}
7613
7614#[derive(Debug, Clone, Serialize, Deserialize)]
7616pub struct LagDistributionSchemaConfig {
7617 pub mu: f64,
7619 pub sigma: f64,
7621 #[serde(default)]
7623 pub min_hours: Option<f64>,
7624 #[serde(default)]
7626 pub max_hours: Option<f64>,
7627}
7628
7629#[derive(Debug, Clone, Serialize, Deserialize)]
7631pub struct CrossDayPostingSchemaConfig {
7632 #[serde(default = "default_true")]
7634 pub enabled: bool,
7635
7636 #[serde(default)]
7639 pub probability_by_hour: std::collections::HashMap<u8, f64>,
7640}
7641
7642impl Default for CrossDayPostingSchemaConfig {
7643 fn default() -> Self {
7644 let mut probability_by_hour = std::collections::HashMap::new();
7645 probability_by_hour.insert(17, 0.3);
7646 probability_by_hour.insert(18, 0.6);
7647 probability_by_hour.insert(19, 0.8);
7648 probability_by_hour.insert(20, 0.9);
7649 probability_by_hour.insert(21, 0.95);
7650 probability_by_hour.insert(22, 0.99);
7651
7652 Self {
7653 enabled: true,
7654 probability_by_hour,
7655 }
7656 }
7657}
7658
7659#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7668pub struct FiscalCalendarSchemaConfig {
7669 #[serde(default)]
7671 pub enabled: bool,
7672
7673 #[serde(default = "default_fiscal_calendar_type")]
7675 pub calendar_type: String,
7676
7677 #[serde(default)]
7679 pub year_start_month: Option<u8>,
7680
7681 #[serde(default)]
7683 pub year_start_day: Option<u8>,
7684
7685 #[serde(default)]
7687 pub four_four_five: Option<FourFourFiveSchemaConfig>,
7688}
7689
7690fn default_fiscal_calendar_type() -> String {
7691 "calendar_year".to_string()
7692}
7693
7694#[derive(Debug, Clone, Serialize, Deserialize)]
7696pub struct FourFourFiveSchemaConfig {
7697 #[serde(default = "default_week_pattern")]
7699 pub pattern: String,
7700
7701 #[serde(default = "default_anchor_type")]
7703 pub anchor_type: String,
7704
7705 #[serde(default = "default_anchor_month")]
7707 pub anchor_month: u8,
7708
7709 #[serde(default = "default_leap_week_placement")]
7711 pub leap_week_placement: String,
7712}
7713
7714fn default_week_pattern() -> String {
7715 "four_four_five".to_string()
7716}
7717
7718fn default_anchor_type() -> String {
7719 "last_saturday".to_string()
7720}
7721
7722fn default_anchor_month() -> u8 {
7723 1 }
7725
7726fn default_leap_week_placement() -> String {
7727 "q4_period3".to_string()
7728}
7729
7730impl Default for FourFourFiveSchemaConfig {
7731 fn default() -> Self {
7732 Self {
7733 pattern: "four_four_five".to_string(),
7734 anchor_type: "last_saturday".to_string(),
7735 anchor_month: 1,
7736 leap_week_placement: "q4_period3".to_string(),
7737 }
7738 }
7739}
7740
7741#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7750pub struct IntraDaySchemaConfig {
7751 #[serde(default)]
7753 pub enabled: bool,
7754
7755 #[serde(default)]
7757 pub segments: Vec<IntraDaySegmentSchemaConfig>,
7758}
7759
7760#[derive(Debug, Clone, Serialize, Deserialize)]
7762pub struct IntraDaySegmentSchemaConfig {
7763 pub name: String,
7765
7766 pub start: String,
7768
7769 pub end: String,
7771
7772 #[serde(default = "default_multiplier")]
7774 pub multiplier: f64,
7775
7776 #[serde(default = "default_posting_type")]
7778 pub posting_type: String,
7779}
7780
7781fn default_multiplier() -> f64 {
7782 1.0
7783}
7784
7785fn default_posting_type() -> String {
7786 "both".to_string()
7787}
7788
7789#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7795pub struct TimezoneSchemaConfig {
7796 #[serde(default)]
7798 pub enabled: bool,
7799
7800 #[serde(default = "default_timezone")]
7802 pub default_timezone: String,
7803
7804 #[serde(default = "default_consolidation_timezone")]
7806 pub consolidation_timezone: String,
7807
7808 #[serde(default)]
7811 pub entity_mappings: Vec<EntityTimezoneMapping>,
7812}
7813
7814fn default_timezone() -> String {
7815 "America/New_York".to_string()
7816}
7817
7818fn default_consolidation_timezone() -> String {
7819 "UTC".to_string()
7820}
7821
7822#[derive(Debug, Clone, Serialize, Deserialize)]
7824pub struct EntityTimezoneMapping {
7825 pub pattern: String,
7827
7828 pub timezone: String,
7830}
7831
7832#[derive(Debug, Clone, Serialize, Deserialize)]
7838pub struct VendorNetworkSchemaConfig {
7839 #[serde(default)]
7841 pub enabled: bool,
7842
7843 #[serde(default = "default_vendor_tier_depth")]
7845 pub depth: u8,
7846
7847 #[serde(default)]
7849 pub tier1: TierCountSchemaConfig,
7850
7851 #[serde(default)]
7853 pub tier2_per_parent: TierCountSchemaConfig,
7854
7855 #[serde(default)]
7857 pub tier3_per_parent: TierCountSchemaConfig,
7858
7859 #[serde(default)]
7861 pub clusters: VendorClusterSchemaConfig,
7862
7863 #[serde(default)]
7865 pub dependencies: DependencySchemaConfig,
7866}
7867
7868fn default_vendor_tier_depth() -> u8 {
7869 3
7870}
7871
7872impl Default for VendorNetworkSchemaConfig {
7873 fn default() -> Self {
7874 Self {
7875 enabled: false,
7876 depth: 3,
7877 tier1: TierCountSchemaConfig { min: 50, max: 100 },
7878 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
7879 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
7880 clusters: VendorClusterSchemaConfig::default(),
7881 dependencies: DependencySchemaConfig::default(),
7882 }
7883 }
7884}
7885
7886#[derive(Debug, Clone, Serialize, Deserialize)]
7888pub struct TierCountSchemaConfig {
7889 #[serde(default = "default_tier_min")]
7891 pub min: usize,
7892
7893 #[serde(default = "default_tier_max")]
7895 pub max: usize,
7896}
7897
7898fn default_tier_min() -> usize {
7899 5
7900}
7901
7902fn default_tier_max() -> usize {
7903 20
7904}
7905
7906impl Default for TierCountSchemaConfig {
7907 fn default() -> Self {
7908 Self {
7909 min: default_tier_min(),
7910 max: default_tier_max(),
7911 }
7912 }
7913}
7914
7915#[derive(Debug, Clone, Serialize, Deserialize)]
7917pub struct VendorClusterSchemaConfig {
7918 #[serde(default = "default_reliable_strategic")]
7920 pub reliable_strategic: f64,
7921
7922 #[serde(default = "default_standard_operational")]
7924 pub standard_operational: f64,
7925
7926 #[serde(default = "default_transactional")]
7928 pub transactional: f64,
7929
7930 #[serde(default = "default_problematic")]
7932 pub problematic: f64,
7933}
7934
7935fn default_reliable_strategic() -> f64 {
7936 0.20
7937}
7938
7939fn default_standard_operational() -> f64 {
7940 0.50
7941}
7942
7943fn default_transactional() -> f64 {
7944 0.25
7945}
7946
7947fn default_problematic() -> f64 {
7948 0.05
7949}
7950
7951impl Default for VendorClusterSchemaConfig {
7952 fn default() -> Self {
7953 Self {
7954 reliable_strategic: 0.20,
7955 standard_operational: 0.50,
7956 transactional: 0.25,
7957 problematic: 0.05,
7958 }
7959 }
7960}
7961
7962#[derive(Debug, Clone, Serialize, Deserialize)]
7964pub struct DependencySchemaConfig {
7965 #[serde(default = "default_max_single_vendor")]
7967 pub max_single_vendor_concentration: f64,
7968
7969 #[serde(default = "default_max_top5")]
7971 pub top_5_concentration: f64,
7972
7973 #[serde(default = "default_single_source_percent")]
7975 pub single_source_percent: f64,
7976}
7977
7978fn default_max_single_vendor() -> f64 {
7979 0.15
7980}
7981
7982fn default_max_top5() -> f64 {
7983 0.45
7984}
7985
7986fn default_single_source_percent() -> f64 {
7987 0.05
7988}
7989
7990impl Default for DependencySchemaConfig {
7991 fn default() -> Self {
7992 Self {
7993 max_single_vendor_concentration: 0.15,
7994 top_5_concentration: 0.45,
7995 single_source_percent: 0.05,
7996 }
7997 }
7998}
7999
8000#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8006pub struct CustomerSegmentationSchemaConfig {
8007 #[serde(default)]
8009 pub enabled: bool,
8010
8011 #[serde(default)]
8013 pub value_segments: ValueSegmentsSchemaConfig,
8014
8015 #[serde(default)]
8017 pub lifecycle: LifecycleSchemaConfig,
8018
8019 #[serde(default)]
8021 pub networks: CustomerNetworksSchemaConfig,
8022}
8023
8024#[derive(Debug, Clone, Serialize, Deserialize)]
8026pub struct ValueSegmentsSchemaConfig {
8027 #[serde(default)]
8029 pub enterprise: SegmentDetailSchemaConfig,
8030
8031 #[serde(default)]
8033 pub mid_market: SegmentDetailSchemaConfig,
8034
8035 #[serde(default)]
8037 pub smb: SegmentDetailSchemaConfig,
8038
8039 #[serde(default)]
8041 pub consumer: SegmentDetailSchemaConfig,
8042}
8043
8044impl Default for ValueSegmentsSchemaConfig {
8045 fn default() -> Self {
8046 Self {
8047 enterprise: SegmentDetailSchemaConfig {
8048 revenue_share: 0.40,
8049 customer_share: 0.05,
8050 avg_order_value_range: "50000+".to_string(),
8051 },
8052 mid_market: SegmentDetailSchemaConfig {
8053 revenue_share: 0.35,
8054 customer_share: 0.20,
8055 avg_order_value_range: "5000-50000".to_string(),
8056 },
8057 smb: SegmentDetailSchemaConfig {
8058 revenue_share: 0.20,
8059 customer_share: 0.50,
8060 avg_order_value_range: "500-5000".to_string(),
8061 },
8062 consumer: SegmentDetailSchemaConfig {
8063 revenue_share: 0.05,
8064 customer_share: 0.25,
8065 avg_order_value_range: "50-500".to_string(),
8066 },
8067 }
8068 }
8069}
8070
8071#[derive(Debug, Clone, Serialize, Deserialize)]
8073pub struct SegmentDetailSchemaConfig {
8074 #[serde(default)]
8076 pub revenue_share: f64,
8077
8078 #[serde(default)]
8080 pub customer_share: f64,
8081
8082 #[serde(default)]
8084 pub avg_order_value_range: String,
8085}
8086
8087impl Default for SegmentDetailSchemaConfig {
8088 fn default() -> Self {
8089 Self {
8090 revenue_share: 0.25,
8091 customer_share: 0.25,
8092 avg_order_value_range: "1000-10000".to_string(),
8093 }
8094 }
8095}
8096
8097#[derive(Debug, Clone, Serialize, Deserialize)]
8099pub struct LifecycleSchemaConfig {
8100 #[serde(default)]
8102 pub prospect_rate: f64,
8103
8104 #[serde(default = "default_new_rate")]
8106 pub new_rate: f64,
8107
8108 #[serde(default = "default_growth_rate")]
8110 pub growth_rate: f64,
8111
8112 #[serde(default = "default_mature_rate")]
8114 pub mature_rate: f64,
8115
8116 #[serde(default = "default_at_risk_rate")]
8118 pub at_risk_rate: f64,
8119
8120 #[serde(default = "default_churned_rate")]
8122 pub churned_rate: f64,
8123
8124 #[serde(default)]
8126 pub won_back_rate: f64,
8127}
8128
8129fn default_new_rate() -> f64 {
8130 0.10
8131}
8132
8133fn default_growth_rate() -> f64 {
8134 0.15
8135}
8136
8137fn default_mature_rate() -> f64 {
8138 0.60
8139}
8140
8141fn default_at_risk_rate() -> f64 {
8142 0.10
8143}
8144
8145fn default_churned_rate() -> f64 {
8146 0.05
8147}
8148
8149impl Default for LifecycleSchemaConfig {
8150 fn default() -> Self {
8151 Self {
8152 prospect_rate: 0.0,
8153 new_rate: 0.10,
8154 growth_rate: 0.15,
8155 mature_rate: 0.60,
8156 at_risk_rate: 0.10,
8157 churned_rate: 0.05,
8158 won_back_rate: 0.0,
8159 }
8160 }
8161}
8162
8163#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8165pub struct CustomerNetworksSchemaConfig {
8166 #[serde(default)]
8168 pub referrals: ReferralSchemaConfig,
8169
8170 #[serde(default)]
8172 pub corporate_hierarchies: HierarchySchemaConfig,
8173}
8174
8175#[derive(Debug, Clone, Serialize, Deserialize)]
8177pub struct ReferralSchemaConfig {
8178 #[serde(default = "default_true")]
8180 pub enabled: bool,
8181
8182 #[serde(default = "default_referral_rate")]
8184 pub referral_rate: f64,
8185}
8186
8187fn default_referral_rate() -> f64 {
8188 0.15
8189}
8190
8191impl Default for ReferralSchemaConfig {
8192 fn default() -> Self {
8193 Self {
8194 enabled: true,
8195 referral_rate: 0.15,
8196 }
8197 }
8198}
8199
8200#[derive(Debug, Clone, Serialize, Deserialize)]
8202pub struct HierarchySchemaConfig {
8203 #[serde(default = "default_true")]
8205 pub enabled: bool,
8206
8207 #[serde(default = "default_hierarchy_rate")]
8209 pub probability: f64,
8210}
8211
8212fn default_hierarchy_rate() -> f64 {
8213 0.30
8214}
8215
8216impl Default for HierarchySchemaConfig {
8217 fn default() -> Self {
8218 Self {
8219 enabled: true,
8220 probability: 0.30,
8221 }
8222 }
8223}
8224
8225#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8231pub struct RelationshipStrengthSchemaConfig {
8232 #[serde(default)]
8234 pub enabled: bool,
8235
8236 #[serde(default)]
8238 pub calculation: StrengthCalculationSchemaConfig,
8239
8240 #[serde(default)]
8242 pub thresholds: StrengthThresholdsSchemaConfig,
8243}
8244
8245#[derive(Debug, Clone, Serialize, Deserialize)]
8247pub struct StrengthCalculationSchemaConfig {
8248 #[serde(default = "default_volume_weight")]
8250 pub transaction_volume_weight: f64,
8251
8252 #[serde(default = "default_count_weight")]
8254 pub transaction_count_weight: f64,
8255
8256 #[serde(default = "default_duration_weight")]
8258 pub relationship_duration_weight: f64,
8259
8260 #[serde(default = "default_recency_weight")]
8262 pub recency_weight: f64,
8263
8264 #[serde(default = "default_mutual_weight")]
8266 pub mutual_connections_weight: f64,
8267
8268 #[serde(default = "default_recency_half_life")]
8270 pub recency_half_life_days: u32,
8271}
8272
8273fn default_volume_weight() -> f64 {
8274 0.30
8275}
8276
8277fn default_count_weight() -> f64 {
8278 0.25
8279}
8280
8281fn default_duration_weight() -> f64 {
8282 0.20
8283}
8284
8285fn default_recency_weight() -> f64 {
8286 0.15
8287}
8288
8289fn default_mutual_weight() -> f64 {
8290 0.10
8291}
8292
8293fn default_recency_half_life() -> u32 {
8294 90
8295}
8296
8297impl Default for StrengthCalculationSchemaConfig {
8298 fn default() -> Self {
8299 Self {
8300 transaction_volume_weight: 0.30,
8301 transaction_count_weight: 0.25,
8302 relationship_duration_weight: 0.20,
8303 recency_weight: 0.15,
8304 mutual_connections_weight: 0.10,
8305 recency_half_life_days: 90,
8306 }
8307 }
8308}
8309
8310#[derive(Debug, Clone, Serialize, Deserialize)]
8312pub struct StrengthThresholdsSchemaConfig {
8313 #[serde(default = "default_strong_threshold")]
8315 pub strong: f64,
8316
8317 #[serde(default = "default_moderate_threshold")]
8319 pub moderate: f64,
8320
8321 #[serde(default = "default_weak_threshold")]
8323 pub weak: f64,
8324}
8325
8326fn default_strong_threshold() -> f64 {
8327 0.7
8328}
8329
8330fn default_moderate_threshold() -> f64 {
8331 0.4
8332}
8333
8334fn default_weak_threshold() -> f64 {
8335 0.1
8336}
8337
8338impl Default for StrengthThresholdsSchemaConfig {
8339 fn default() -> Self {
8340 Self {
8341 strong: 0.7,
8342 moderate: 0.4,
8343 weak: 0.1,
8344 }
8345 }
8346}
8347
8348#[derive(Debug, Clone, Serialize, Deserialize)]
8354pub struct CrossProcessLinksSchemaConfig {
8355 #[serde(default)]
8357 pub enabled: bool,
8358
8359 #[serde(default = "default_true")]
8361 pub inventory_p2p_o2c: bool,
8362
8363 #[serde(default = "default_true")]
8365 pub payment_bank_reconciliation: bool,
8366
8367 #[serde(default = "default_true")]
8369 pub intercompany_bilateral: bool,
8370
8371 #[serde(default = "default_inventory_link_rate")]
8373 pub inventory_link_rate: f64,
8374}
8375
8376fn default_inventory_link_rate() -> f64 {
8377 0.30
8378}
8379
8380impl Default for CrossProcessLinksSchemaConfig {
8381 fn default() -> Self {
8382 Self {
8383 enabled: false,
8384 inventory_p2p_o2c: true,
8385 payment_bank_reconciliation: true,
8386 intercompany_bilateral: true,
8387 inventory_link_rate: 0.30,
8388 }
8389 }
8390}
8391
8392#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8398pub struct OrganizationalEventsSchemaConfig {
8399 #[serde(default)]
8401 pub enabled: bool,
8402
8403 #[serde(default)]
8405 pub effect_blending: EffectBlendingModeConfig,
8406
8407 #[serde(default)]
8409 pub events: Vec<OrganizationalEventSchemaConfig>,
8410
8411 #[serde(default)]
8413 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
8414
8415 #[serde(default)]
8417 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
8418}
8419
8420#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8422#[serde(rename_all = "snake_case")]
8423pub enum EffectBlendingModeConfig {
8424 #[default]
8426 Multiplicative,
8427 Additive,
8429 Maximum,
8431 Minimum,
8433}
8434
8435#[derive(Debug, Clone, Serialize, Deserialize)]
8437pub struct OrganizationalEventSchemaConfig {
8438 pub id: String,
8440
8441 pub event_type: OrganizationalEventTypeSchemaConfig,
8443
8444 pub effective_date: String,
8446
8447 #[serde(default = "default_org_transition_months")]
8449 pub transition_months: u32,
8450
8451 #[serde(default)]
8453 pub description: Option<String>,
8454}
8455
8456fn default_org_transition_months() -> u32 {
8457 6
8458}
8459
8460#[derive(Debug, Clone, Serialize, Deserialize)]
8462#[serde(tag = "type", rename_all = "snake_case")]
8463pub enum OrganizationalEventTypeSchemaConfig {
8464 Acquisition {
8466 acquired_entity: String,
8468 #[serde(default = "default_acquisition_volume")]
8470 volume_increase: f64,
8471 #[serde(default = "default_acquisition_error")]
8473 integration_error_rate: f64,
8474 #[serde(default = "default_parallel_days")]
8476 parallel_posting_days: u32,
8477 },
8478 Divestiture {
8480 divested_entity: String,
8482 #[serde(default = "default_divestiture_volume")]
8484 volume_reduction: f64,
8485 #[serde(default = "default_true_val")]
8487 remove_entity: bool,
8488 },
8489 Reorganization {
8491 #[serde(default)]
8493 cost_center_remapping: std::collections::HashMap<String, String>,
8494 #[serde(default = "default_reorg_error")]
8496 transition_error_rate: f64,
8497 },
8498 LeadershipChange {
8500 role: String,
8502 #[serde(default)]
8504 policy_changes: Vec<String>,
8505 },
8506 WorkforceReduction {
8508 #[serde(default = "default_workforce_reduction")]
8510 reduction_percent: f64,
8511 #[serde(default = "default_workforce_error")]
8513 error_rate_increase: f64,
8514 },
8515 Merger {
8517 merged_entity: String,
8519 #[serde(default = "default_merger_volume")]
8521 volume_increase: f64,
8522 },
8523}
8524
8525fn default_acquisition_volume() -> f64 {
8526 1.35
8527}
8528
8529fn default_acquisition_error() -> f64 {
8530 0.05
8531}
8532
8533fn default_parallel_days() -> u32 {
8534 30
8535}
8536
8537fn default_divestiture_volume() -> f64 {
8538 0.70
8539}
8540
8541fn default_true_val() -> bool {
8542 true
8543}
8544
8545fn default_reorg_error() -> f64 {
8546 0.04
8547}
8548
8549fn default_workforce_reduction() -> f64 {
8550 0.10
8551}
8552
8553fn default_workforce_error() -> f64 {
8554 0.05
8555}
8556
8557fn default_merger_volume() -> f64 {
8558 1.80
8559}
8560
8561#[derive(Debug, Clone, Serialize, Deserialize)]
8563pub struct ProcessEvolutionSchemaConfig {
8564 pub id: String,
8566
8567 pub event_type: ProcessEvolutionTypeSchemaConfig,
8569
8570 pub effective_date: String,
8572
8573 #[serde(default)]
8575 pub description: Option<String>,
8576}
8577
8578#[derive(Debug, Clone, Serialize, Deserialize)]
8580#[serde(tag = "type", rename_all = "snake_case")]
8581pub enum ProcessEvolutionTypeSchemaConfig {
8582 ProcessAutomation {
8584 process_name: String,
8586 #[serde(default = "default_manual_before")]
8588 manual_rate_before: f64,
8589 #[serde(default = "default_manual_after")]
8591 manual_rate_after: f64,
8592 },
8593 ApprovalWorkflowChange {
8595 description: String,
8597 },
8598 ControlEnhancement {
8600 control_id: String,
8602 #[serde(default = "default_error_reduction")]
8604 error_reduction: f64,
8605 },
8606}
8607
8608fn default_manual_before() -> f64 {
8609 0.80
8610}
8611
8612fn default_manual_after() -> f64 {
8613 0.15
8614}
8615
8616fn default_error_reduction() -> f64 {
8617 0.02
8618}
8619
8620#[derive(Debug, Clone, Serialize, Deserialize)]
8622pub struct TechnologyTransitionSchemaConfig {
8623 pub id: String,
8625
8626 pub event_type: TechnologyTransitionTypeSchemaConfig,
8628
8629 #[serde(default)]
8631 pub description: Option<String>,
8632}
8633
8634#[derive(Debug, Clone, Serialize, Deserialize)]
8636#[serde(tag = "type", rename_all = "snake_case")]
8637pub enum TechnologyTransitionTypeSchemaConfig {
8638 ErpMigration {
8640 source_system: String,
8642 target_system: String,
8644 cutover_date: String,
8646 stabilization_end: String,
8648 #[serde(default = "default_erp_duplicate_rate")]
8650 duplicate_rate: f64,
8651 #[serde(default = "default_format_mismatch")]
8653 format_mismatch_rate: f64,
8654 },
8655 ModuleImplementation {
8657 module_name: String,
8659 go_live_date: String,
8661 },
8662}
8663
8664fn default_erp_duplicate_rate() -> f64 {
8665 0.02
8666}
8667
8668fn default_format_mismatch() -> f64 {
8669 0.03
8670}
8671
8672#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8687pub struct BehavioralDriftSchemaConfig {
8688 #[serde(default)]
8690 pub enabled: bool,
8691
8692 #[serde(default)]
8694 pub vendor_behavior: VendorBehaviorSchemaConfig,
8695
8696 #[serde(default)]
8698 pub customer_behavior: CustomerBehaviorSchemaConfig,
8699
8700 #[serde(default)]
8702 pub employee_behavior: EmployeeBehaviorSchemaConfig,
8703
8704 #[serde(default)]
8706 pub collective: CollectiveBehaviorSchemaConfig,
8707}
8708
8709#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8711pub struct VendorBehaviorSchemaConfig {
8712 #[serde(default)]
8714 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
8715
8716 #[serde(default)]
8718 pub quality_drift: QualityDriftSchemaConfig,
8719}
8720
8721#[derive(Debug, Clone, Serialize, Deserialize)]
8723pub struct PaymentTermsDriftSchemaConfig {
8724 #[serde(default = "default_extension_rate")]
8726 pub extension_rate_per_year: f64,
8727
8728 #[serde(default = "default_economic_sensitivity")]
8730 pub economic_sensitivity: f64,
8731}
8732
8733fn default_extension_rate() -> f64 {
8734 2.5
8735}
8736
8737fn default_economic_sensitivity() -> f64 {
8738 1.0
8739}
8740
8741impl Default for PaymentTermsDriftSchemaConfig {
8742 fn default() -> Self {
8743 Self {
8744 extension_rate_per_year: 2.5,
8745 economic_sensitivity: 1.0,
8746 }
8747 }
8748}
8749
8750#[derive(Debug, Clone, Serialize, Deserialize)]
8752pub struct QualityDriftSchemaConfig {
8753 #[serde(default = "default_improvement_rate")]
8755 pub new_vendor_improvement_rate: f64,
8756
8757 #[serde(default = "default_decline_rate")]
8759 pub complacency_decline_rate: f64,
8760}
8761
8762fn default_improvement_rate() -> f64 {
8763 0.02
8764}
8765
8766fn default_decline_rate() -> f64 {
8767 0.01
8768}
8769
8770impl Default for QualityDriftSchemaConfig {
8771 fn default() -> Self {
8772 Self {
8773 new_vendor_improvement_rate: 0.02,
8774 complacency_decline_rate: 0.01,
8775 }
8776 }
8777}
8778
8779#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8781pub struct CustomerBehaviorSchemaConfig {
8782 #[serde(default)]
8784 pub payment_drift: CustomerPaymentDriftSchemaConfig,
8785
8786 #[serde(default)]
8788 pub order_drift: OrderDriftSchemaConfig,
8789}
8790
8791#[derive(Debug, Clone, Serialize, Deserialize)]
8793pub struct CustomerPaymentDriftSchemaConfig {
8794 #[serde(default = "default_downturn_extension")]
8796 pub downturn_days_extension: (u32, u32),
8797
8798 #[serde(default = "default_bad_debt_increase")]
8800 pub downturn_bad_debt_increase: f64,
8801}
8802
8803fn default_downturn_extension() -> (u32, u32) {
8804 (5, 15)
8805}
8806
8807fn default_bad_debt_increase() -> f64 {
8808 0.02
8809}
8810
8811impl Default for CustomerPaymentDriftSchemaConfig {
8812 fn default() -> Self {
8813 Self {
8814 downturn_days_extension: (5, 15),
8815 downturn_bad_debt_increase: 0.02,
8816 }
8817 }
8818}
8819
8820#[derive(Debug, Clone, Serialize, Deserialize)]
8822pub struct OrderDriftSchemaConfig {
8823 #[serde(default = "default_digital_shift")]
8825 pub digital_shift_rate: f64,
8826}
8827
8828fn default_digital_shift() -> f64 {
8829 0.05
8830}
8831
8832impl Default for OrderDriftSchemaConfig {
8833 fn default() -> Self {
8834 Self {
8835 digital_shift_rate: 0.05,
8836 }
8837 }
8838}
8839
8840#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8842pub struct EmployeeBehaviorSchemaConfig {
8843 #[serde(default)]
8845 pub approval_drift: ApprovalDriftSchemaConfig,
8846
8847 #[serde(default)]
8849 pub error_drift: ErrorDriftSchemaConfig,
8850}
8851
8852#[derive(Debug, Clone, Serialize, Deserialize)]
8854pub struct ApprovalDriftSchemaConfig {
8855 #[serde(default = "default_eom_intensity")]
8857 pub eom_intensity_increase_per_year: f64,
8858
8859 #[serde(default = "default_rubber_stamp")]
8861 pub rubber_stamp_volume_threshold: u32,
8862}
8863
8864fn default_eom_intensity() -> f64 {
8865 0.05
8866}
8867
8868fn default_rubber_stamp() -> u32 {
8869 50
8870}
8871
8872impl Default for ApprovalDriftSchemaConfig {
8873 fn default() -> Self {
8874 Self {
8875 eom_intensity_increase_per_year: 0.05,
8876 rubber_stamp_volume_threshold: 50,
8877 }
8878 }
8879}
8880
8881#[derive(Debug, Clone, Serialize, Deserialize)]
8883pub struct ErrorDriftSchemaConfig {
8884 #[serde(default = "default_new_error")]
8886 pub new_employee_error_rate: f64,
8887
8888 #[serde(default = "default_learning_months")]
8890 pub learning_curve_months: u32,
8891}
8892
8893fn default_new_error() -> f64 {
8894 0.08
8895}
8896
8897fn default_learning_months() -> u32 {
8898 6
8899}
8900
8901impl Default for ErrorDriftSchemaConfig {
8902 fn default() -> Self {
8903 Self {
8904 new_employee_error_rate: 0.08,
8905 learning_curve_months: 6,
8906 }
8907 }
8908}
8909
8910#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8912pub struct CollectiveBehaviorSchemaConfig {
8913 #[serde(default)]
8915 pub automation_adoption: AutomationAdoptionSchemaConfig,
8916}
8917
8918#[derive(Debug, Clone, Serialize, Deserialize)]
8920pub struct AutomationAdoptionSchemaConfig {
8921 #[serde(default)]
8923 pub s_curve_enabled: bool,
8924
8925 #[serde(default = "default_midpoint")]
8927 pub adoption_midpoint_months: u32,
8928
8929 #[serde(default = "default_steepness")]
8931 pub steepness: f64,
8932}
8933
8934fn default_midpoint() -> u32 {
8935 24
8936}
8937
8938fn default_steepness() -> f64 {
8939 0.15
8940}
8941
8942impl Default for AutomationAdoptionSchemaConfig {
8943 fn default() -> Self {
8944 Self {
8945 s_curve_enabled: false,
8946 adoption_midpoint_months: 24,
8947 steepness: 0.15,
8948 }
8949 }
8950}
8951
8952#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8965pub struct MarketDriftSchemaConfig {
8966 #[serde(default)]
8968 pub enabled: bool,
8969
8970 #[serde(default)]
8972 pub economic_cycle: MarketEconomicCycleSchemaConfig,
8973
8974 #[serde(default)]
8976 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8977
8978 #[serde(default)]
8980 pub commodities: CommoditiesSchemaConfig,
8981}
8982
8983#[derive(Debug, Clone, Serialize, Deserialize)]
8985pub struct MarketEconomicCycleSchemaConfig {
8986 #[serde(default)]
8988 pub enabled: bool,
8989
8990 #[serde(default)]
8992 pub cycle_type: CycleTypeSchemaConfig,
8993
8994 #[serde(default = "default_market_cycle_period")]
8996 pub period_months: u32,
8997
8998 #[serde(default = "default_market_amplitude")]
9000 pub amplitude: f64,
9001
9002 #[serde(default)]
9004 pub recession: RecessionSchemaConfig,
9005}
9006
9007fn default_market_cycle_period() -> u32 {
9008 48
9009}
9010
9011fn default_market_amplitude() -> f64 {
9012 0.15
9013}
9014
9015impl Default for MarketEconomicCycleSchemaConfig {
9016 fn default() -> Self {
9017 Self {
9018 enabled: false,
9019 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
9020 period_months: 48,
9021 amplitude: 0.15,
9022 recession: RecessionSchemaConfig::default(),
9023 }
9024 }
9025}
9026
9027#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
9029#[serde(rename_all = "snake_case")]
9030pub enum CycleTypeSchemaConfig {
9031 #[default]
9033 Sinusoidal,
9034 Asymmetric,
9036 MeanReverting,
9038}
9039
9040#[derive(Debug, Clone, Serialize, Deserialize)]
9042pub struct RecessionSchemaConfig {
9043 #[serde(default)]
9045 pub enabled: bool,
9046
9047 #[serde(default = "default_recession_prob")]
9049 pub probability_per_year: f64,
9050
9051 #[serde(default)]
9053 pub severity: RecessionSeveritySchemaConfig,
9054
9055 #[serde(default)]
9057 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
9058}
9059
9060fn default_recession_prob() -> f64 {
9061 0.10
9062}
9063
9064impl Default for RecessionSchemaConfig {
9065 fn default() -> Self {
9066 Self {
9067 enabled: false,
9068 probability_per_year: 0.10,
9069 severity: RecessionSeveritySchemaConfig::Moderate,
9070 recession_periods: Vec::new(),
9071 }
9072 }
9073}
9074
9075#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
9077#[serde(rename_all = "snake_case")]
9078pub enum RecessionSeveritySchemaConfig {
9079 Mild,
9081 #[default]
9083 Moderate,
9084 Severe,
9086}
9087
9088#[derive(Debug, Clone, Serialize, Deserialize)]
9090pub struct RecessionPeriodSchemaConfig {
9091 pub start_month: u32,
9093 pub duration_months: u32,
9095}
9096
9097#[derive(Debug, Clone, Serialize, Deserialize)]
9099pub struct IndustryCycleSchemaConfig {
9100 #[serde(default = "default_industry_period")]
9102 pub period_months: u32,
9103
9104 #[serde(default = "default_industry_amp")]
9106 pub amplitude: f64,
9107}
9108
9109fn default_industry_period() -> u32 {
9110 36
9111}
9112
9113fn default_industry_amp() -> f64 {
9114 0.20
9115}
9116
9117#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9119pub struct CommoditiesSchemaConfig {
9120 #[serde(default)]
9122 pub enabled: bool,
9123
9124 #[serde(default)]
9126 pub items: Vec<CommodityItemSchemaConfig>,
9127}
9128
9129#[derive(Debug, Clone, Serialize, Deserialize)]
9131pub struct CommodityItemSchemaConfig {
9132 pub name: String,
9134
9135 #[serde(default = "default_volatility")]
9137 pub volatility: f64,
9138
9139 #[serde(default)]
9141 pub cogs_pass_through: f64,
9142
9143 #[serde(default)]
9145 pub overhead_pass_through: f64,
9146}
9147
9148fn default_volatility() -> f64 {
9149 0.20
9150}
9151
9152#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9165pub struct DriftLabelingSchemaConfig {
9166 #[serde(default)]
9168 pub enabled: bool,
9169
9170 #[serde(default)]
9172 pub statistical: StatisticalDriftLabelingSchemaConfig,
9173
9174 #[serde(default)]
9176 pub categorical: CategoricalDriftLabelingSchemaConfig,
9177
9178 #[serde(default)]
9180 pub temporal: TemporalDriftLabelingSchemaConfig,
9181
9182 #[serde(default)]
9184 pub regulatory_calendar_preset: Option<String>,
9185}
9186
9187#[derive(Debug, Clone, Serialize, Deserialize)]
9189pub struct StatisticalDriftLabelingSchemaConfig {
9190 #[serde(default = "default_true_val")]
9192 pub enabled: bool,
9193
9194 #[serde(default = "default_min_magnitude")]
9196 pub min_magnitude_threshold: f64,
9197}
9198
9199fn default_min_magnitude() -> f64 {
9200 0.05
9201}
9202
9203impl Default for StatisticalDriftLabelingSchemaConfig {
9204 fn default() -> Self {
9205 Self {
9206 enabled: true,
9207 min_magnitude_threshold: 0.05,
9208 }
9209 }
9210}
9211
9212#[derive(Debug, Clone, Serialize, Deserialize)]
9214pub struct CategoricalDriftLabelingSchemaConfig {
9215 #[serde(default = "default_true_val")]
9217 pub enabled: bool,
9218}
9219
9220impl Default for CategoricalDriftLabelingSchemaConfig {
9221 fn default() -> Self {
9222 Self { enabled: true }
9223 }
9224}
9225
9226#[derive(Debug, Clone, Serialize, Deserialize)]
9228pub struct TemporalDriftLabelingSchemaConfig {
9229 #[serde(default = "default_true_val")]
9231 pub enabled: bool,
9232}
9233
9234impl Default for TemporalDriftLabelingSchemaConfig {
9235 fn default() -> Self {
9236 Self { enabled: true }
9237 }
9238}
9239
9240#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9253pub struct EnhancedAnomalyConfig {
9254 #[serde(default)]
9256 pub enabled: bool,
9257
9258 #[serde(default)]
9260 pub rates: AnomalyRateConfig,
9261
9262 #[serde(default)]
9264 pub multi_stage_schemes: MultiStageSchemeConfig,
9265
9266 #[serde(default)]
9268 pub correlated_injection: CorrelatedInjectionConfig,
9269
9270 #[serde(default)]
9272 pub near_miss: NearMissConfig,
9273
9274 #[serde(default)]
9276 pub difficulty_classification: DifficultyClassificationConfig,
9277
9278 #[serde(default)]
9280 pub context_aware: ContextAwareConfig,
9281
9282 #[serde(default)]
9284 pub labeling: EnhancedLabelingConfig,
9285}
9286
9287#[derive(Debug, Clone, Serialize, Deserialize)]
9289pub struct AnomalyRateConfig {
9290 #[serde(default = "default_total_anomaly_rate")]
9292 pub total_rate: f64,
9293
9294 #[serde(default = "default_fraud_anomaly_rate")]
9296 pub fraud_rate: f64,
9297
9298 #[serde(default = "default_error_anomaly_rate")]
9300 pub error_rate: f64,
9301
9302 #[serde(default = "default_process_anomaly_rate")]
9304 pub process_rate: f64,
9305}
9306
9307fn default_total_anomaly_rate() -> f64 {
9308 0.03
9309}
9310fn default_fraud_anomaly_rate() -> f64 {
9311 0.01
9312}
9313fn default_error_anomaly_rate() -> f64 {
9314 0.015
9315}
9316fn default_process_anomaly_rate() -> f64 {
9317 0.005
9318}
9319
9320impl Default for AnomalyRateConfig {
9321 fn default() -> Self {
9322 Self {
9323 total_rate: default_total_anomaly_rate(),
9324 fraud_rate: default_fraud_anomaly_rate(),
9325 error_rate: default_error_anomaly_rate(),
9326 process_rate: default_process_anomaly_rate(),
9327 }
9328 }
9329}
9330
9331#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9333pub struct MultiStageSchemeConfig {
9334 #[serde(default)]
9336 pub enabled: bool,
9337
9338 #[serde(default)]
9340 pub embezzlement: EmbezzlementSchemeConfig,
9341
9342 #[serde(default)]
9344 pub revenue_manipulation: RevenueManipulationSchemeConfig,
9345
9346 #[serde(default)]
9348 pub kickback: KickbackSchemeConfig,
9349}
9350
9351#[derive(Debug, Clone, Serialize, Deserialize)]
9353pub struct EmbezzlementSchemeConfig {
9354 #[serde(default = "default_embezzlement_probability")]
9356 pub probability: f64,
9357
9358 #[serde(default)]
9360 pub testing_stage: SchemeStageConfig,
9361
9362 #[serde(default)]
9364 pub escalation_stage: SchemeStageConfig,
9365
9366 #[serde(default)]
9368 pub acceleration_stage: SchemeStageConfig,
9369
9370 #[serde(default)]
9372 pub desperation_stage: SchemeStageConfig,
9373}
9374
9375fn default_embezzlement_probability() -> f64 {
9376 0.02
9377}
9378
9379impl Default for EmbezzlementSchemeConfig {
9380 fn default() -> Self {
9381 Self {
9382 probability: default_embezzlement_probability(),
9383 testing_stage: SchemeStageConfig {
9384 duration_months: 2,
9385 amount_min: 100.0,
9386 amount_max: 500.0,
9387 transaction_count_min: 2,
9388 transaction_count_max: 5,
9389 difficulty: "hard".to_string(),
9390 },
9391 escalation_stage: SchemeStageConfig {
9392 duration_months: 6,
9393 amount_min: 500.0,
9394 amount_max: 2000.0,
9395 transaction_count_min: 3,
9396 transaction_count_max: 8,
9397 difficulty: "moderate".to_string(),
9398 },
9399 acceleration_stage: SchemeStageConfig {
9400 duration_months: 3,
9401 amount_min: 2000.0,
9402 amount_max: 10000.0,
9403 transaction_count_min: 5,
9404 transaction_count_max: 12,
9405 difficulty: "easy".to_string(),
9406 },
9407 desperation_stage: SchemeStageConfig {
9408 duration_months: 1,
9409 amount_min: 10000.0,
9410 amount_max: 50000.0,
9411 transaction_count_min: 3,
9412 transaction_count_max: 6,
9413 difficulty: "trivial".to_string(),
9414 },
9415 }
9416 }
9417}
9418
9419#[derive(Debug, Clone, Serialize, Deserialize)]
9421pub struct RevenueManipulationSchemeConfig {
9422 #[serde(default = "default_revenue_manipulation_probability")]
9424 pub probability: f64,
9425
9426 #[serde(default = "default_early_recognition_target")]
9428 pub early_recognition_target: f64,
9429
9430 #[serde(default = "default_expense_deferral_target")]
9432 pub expense_deferral_target: f64,
9433
9434 #[serde(default = "default_reserve_release_target")]
9436 pub reserve_release_target: f64,
9437
9438 #[serde(default = "default_channel_stuffing_target")]
9440 pub channel_stuffing_target: f64,
9441}
9442
9443fn default_revenue_manipulation_probability() -> f64 {
9444 0.01
9445}
9446fn default_early_recognition_target() -> f64 {
9447 0.02
9448}
9449fn default_expense_deferral_target() -> f64 {
9450 0.03
9451}
9452fn default_reserve_release_target() -> f64 {
9453 0.02
9454}
9455fn default_channel_stuffing_target() -> f64 {
9456 0.05
9457}
9458
9459impl Default for RevenueManipulationSchemeConfig {
9460 fn default() -> Self {
9461 Self {
9462 probability: default_revenue_manipulation_probability(),
9463 early_recognition_target: default_early_recognition_target(),
9464 expense_deferral_target: default_expense_deferral_target(),
9465 reserve_release_target: default_reserve_release_target(),
9466 channel_stuffing_target: default_channel_stuffing_target(),
9467 }
9468 }
9469}
9470
9471#[derive(Debug, Clone, Serialize, Deserialize)]
9473pub struct KickbackSchemeConfig {
9474 #[serde(default = "default_kickback_probability")]
9476 pub probability: f64,
9477
9478 #[serde(default = "default_kickback_inflation_min")]
9480 pub inflation_min: f64,
9481
9482 #[serde(default = "default_kickback_inflation_max")]
9484 pub inflation_max: f64,
9485
9486 #[serde(default = "default_kickback_percent")]
9488 pub kickback_percent: f64,
9489
9490 #[serde(default = "default_kickback_setup_months")]
9492 pub setup_months: u32,
9493
9494 #[serde(default = "default_kickback_operation_months")]
9496 pub operation_months: u32,
9497}
9498
9499fn default_kickback_probability() -> f64 {
9500 0.01
9501}
9502fn default_kickback_inflation_min() -> f64 {
9503 0.10
9504}
9505fn default_kickback_inflation_max() -> f64 {
9506 0.25
9507}
9508fn default_kickback_percent() -> f64 {
9509 0.50
9510}
9511fn default_kickback_setup_months() -> u32 {
9512 3
9513}
9514fn default_kickback_operation_months() -> u32 {
9515 12
9516}
9517
9518impl Default for KickbackSchemeConfig {
9519 fn default() -> Self {
9520 Self {
9521 probability: default_kickback_probability(),
9522 inflation_min: default_kickback_inflation_min(),
9523 inflation_max: default_kickback_inflation_max(),
9524 kickback_percent: default_kickback_percent(),
9525 setup_months: default_kickback_setup_months(),
9526 operation_months: default_kickback_operation_months(),
9527 }
9528 }
9529}
9530
9531#[derive(Debug, Clone, Serialize, Deserialize)]
9533pub struct SchemeStageConfig {
9534 pub duration_months: u32,
9536
9537 pub amount_min: f64,
9539
9540 pub amount_max: f64,
9542
9543 pub transaction_count_min: u32,
9545
9546 pub transaction_count_max: u32,
9548
9549 pub difficulty: String,
9551}
9552
9553impl Default for SchemeStageConfig {
9554 fn default() -> Self {
9555 Self {
9556 duration_months: 3,
9557 amount_min: 100.0,
9558 amount_max: 1000.0,
9559 transaction_count_min: 2,
9560 transaction_count_max: 10,
9561 difficulty: "moderate".to_string(),
9562 }
9563 }
9564}
9565
9566#[derive(Debug, Clone, Serialize, Deserialize)]
9568pub struct CorrelatedInjectionConfig {
9569 #[serde(default)]
9571 pub enabled: bool,
9572
9573 #[serde(default = "default_true_val")]
9575 pub fraud_concealment: bool,
9576
9577 #[serde(default = "default_true_val")]
9579 pub error_cascade: bool,
9580
9581 #[serde(default = "default_true_val")]
9583 pub temporal_clustering: bool,
9584
9585 #[serde(default)]
9587 pub temporal_clustering_config: TemporalClusteringConfig,
9588
9589 #[serde(default)]
9591 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
9592}
9593
9594impl Default for CorrelatedInjectionConfig {
9595 fn default() -> Self {
9596 Self {
9597 enabled: false,
9598 fraud_concealment: true,
9599 error_cascade: true,
9600 temporal_clustering: true,
9601 temporal_clustering_config: TemporalClusteringConfig::default(),
9602 co_occurrence_patterns: Vec::new(),
9603 }
9604 }
9605}
9606
9607#[derive(Debug, Clone, Serialize, Deserialize)]
9609pub struct TemporalClusteringConfig {
9610 #[serde(default = "default_period_end_multiplier")]
9612 pub period_end_multiplier: f64,
9613
9614 #[serde(default = "default_period_end_days")]
9616 pub period_end_days: u32,
9617
9618 #[serde(default = "default_quarter_end_multiplier")]
9620 pub quarter_end_multiplier: f64,
9621
9622 #[serde(default = "default_year_end_multiplier")]
9624 pub year_end_multiplier: f64,
9625}
9626
9627fn default_period_end_multiplier() -> f64 {
9628 2.5
9629}
9630fn default_period_end_days() -> u32 {
9631 5
9632}
9633fn default_quarter_end_multiplier() -> f64 {
9634 1.5
9635}
9636fn default_year_end_multiplier() -> f64 {
9637 2.0
9638}
9639
9640impl Default for TemporalClusteringConfig {
9641 fn default() -> Self {
9642 Self {
9643 period_end_multiplier: default_period_end_multiplier(),
9644 period_end_days: default_period_end_days(),
9645 quarter_end_multiplier: default_quarter_end_multiplier(),
9646 year_end_multiplier: default_year_end_multiplier(),
9647 }
9648 }
9649}
9650
9651#[derive(Debug, Clone, Serialize, Deserialize)]
9653pub struct CoOccurrencePatternConfig {
9654 pub name: String,
9656
9657 pub primary_type: String,
9659
9660 pub correlated: Vec<CorrelatedAnomalyConfig>,
9662}
9663
9664#[derive(Debug, Clone, Serialize, Deserialize)]
9666pub struct CorrelatedAnomalyConfig {
9667 pub anomaly_type: String,
9669
9670 pub probability: f64,
9672
9673 pub lag_days_min: i32,
9675
9676 pub lag_days_max: i32,
9678}
9679
9680#[derive(Debug, Clone, Serialize, Deserialize)]
9682pub struct NearMissConfig {
9683 #[serde(default)]
9685 pub enabled: bool,
9686
9687 #[serde(default = "default_near_miss_proportion")]
9689 pub proportion: f64,
9690
9691 #[serde(default = "default_true_val")]
9693 pub near_duplicate: bool,
9694
9695 #[serde(default)]
9697 pub near_duplicate_days: NearDuplicateDaysConfig,
9698
9699 #[serde(default = "default_true_val")]
9701 pub threshold_proximity: bool,
9702
9703 #[serde(default)]
9705 pub threshold_proximity_range: ThresholdProximityRangeConfig,
9706
9707 #[serde(default = "default_true_val")]
9709 pub unusual_legitimate: bool,
9710
9711 #[serde(default = "default_unusual_legitimate_types")]
9713 pub unusual_legitimate_types: Vec<String>,
9714
9715 #[serde(default = "default_true_val")]
9717 pub corrected_errors: bool,
9718
9719 #[serde(default)]
9721 pub corrected_error_lag: CorrectedErrorLagConfig,
9722}
9723
9724fn default_near_miss_proportion() -> f64 {
9725 0.30
9726}
9727
9728fn default_unusual_legitimate_types() -> Vec<String> {
9729 vec![
9730 "year_end_bonus".to_string(),
9731 "contract_prepayment".to_string(),
9732 "insurance_claim".to_string(),
9733 "settlement_payment".to_string(),
9734 ]
9735}
9736
9737impl Default for NearMissConfig {
9738 fn default() -> Self {
9739 Self {
9740 enabled: false,
9741 proportion: default_near_miss_proportion(),
9742 near_duplicate: true,
9743 near_duplicate_days: NearDuplicateDaysConfig::default(),
9744 threshold_proximity: true,
9745 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
9746 unusual_legitimate: true,
9747 unusual_legitimate_types: default_unusual_legitimate_types(),
9748 corrected_errors: true,
9749 corrected_error_lag: CorrectedErrorLagConfig::default(),
9750 }
9751 }
9752}
9753
9754#[derive(Debug, Clone, Serialize, Deserialize)]
9756pub struct NearDuplicateDaysConfig {
9757 #[serde(default = "default_near_duplicate_min")]
9759 pub min: u32,
9760
9761 #[serde(default = "default_near_duplicate_max")]
9763 pub max: u32,
9764}
9765
9766fn default_near_duplicate_min() -> u32 {
9767 1
9768}
9769fn default_near_duplicate_max() -> u32 {
9770 3
9771}
9772
9773impl Default for NearDuplicateDaysConfig {
9774 fn default() -> Self {
9775 Self {
9776 min: default_near_duplicate_min(),
9777 max: default_near_duplicate_max(),
9778 }
9779 }
9780}
9781
9782#[derive(Debug, Clone, Serialize, Deserialize)]
9784pub struct ThresholdProximityRangeConfig {
9785 #[serde(default = "default_threshold_proximity_min")]
9787 pub min: f64,
9788
9789 #[serde(default = "default_threshold_proximity_max")]
9791 pub max: f64,
9792}
9793
9794fn default_threshold_proximity_min() -> f64 {
9795 0.90
9796}
9797fn default_threshold_proximity_max() -> f64 {
9798 0.99
9799}
9800
9801impl Default for ThresholdProximityRangeConfig {
9802 fn default() -> Self {
9803 Self {
9804 min: default_threshold_proximity_min(),
9805 max: default_threshold_proximity_max(),
9806 }
9807 }
9808}
9809
9810#[derive(Debug, Clone, Serialize, Deserialize)]
9812pub struct CorrectedErrorLagConfig {
9813 #[serde(default = "default_corrected_error_lag_min")]
9815 pub min: u32,
9816
9817 #[serde(default = "default_corrected_error_lag_max")]
9819 pub max: u32,
9820}
9821
9822fn default_corrected_error_lag_min() -> u32 {
9823 1
9824}
9825fn default_corrected_error_lag_max() -> u32 {
9826 5
9827}
9828
9829impl Default for CorrectedErrorLagConfig {
9830 fn default() -> Self {
9831 Self {
9832 min: default_corrected_error_lag_min(),
9833 max: default_corrected_error_lag_max(),
9834 }
9835 }
9836}
9837
9838#[derive(Debug, Clone, Serialize, Deserialize)]
9840pub struct DifficultyClassificationConfig {
9841 #[serde(default)]
9843 pub enabled: bool,
9844
9845 #[serde(default)]
9847 pub target_distribution: DifficultyDistributionConfig,
9848}
9849
9850impl Default for DifficultyClassificationConfig {
9851 fn default() -> Self {
9852 Self {
9853 enabled: true,
9854 target_distribution: DifficultyDistributionConfig::default(),
9855 }
9856 }
9857}
9858
9859#[derive(Debug, Clone, Serialize, Deserialize)]
9861pub struct DifficultyDistributionConfig {
9862 #[serde(default = "default_difficulty_trivial")]
9864 pub trivial: f64,
9865
9866 #[serde(default = "default_difficulty_easy")]
9868 pub easy: f64,
9869
9870 #[serde(default = "default_difficulty_moderate")]
9872 pub moderate: f64,
9873
9874 #[serde(default = "default_difficulty_hard")]
9876 pub hard: f64,
9877
9878 #[serde(default = "default_difficulty_expert")]
9880 pub expert: f64,
9881}
9882
9883fn default_difficulty_trivial() -> f64 {
9884 0.15
9885}
9886fn default_difficulty_easy() -> f64 {
9887 0.25
9888}
9889fn default_difficulty_moderate() -> f64 {
9890 0.30
9891}
9892fn default_difficulty_hard() -> f64 {
9893 0.20
9894}
9895fn default_difficulty_expert() -> f64 {
9896 0.10
9897}
9898
9899impl Default for DifficultyDistributionConfig {
9900 fn default() -> Self {
9901 Self {
9902 trivial: default_difficulty_trivial(),
9903 easy: default_difficulty_easy(),
9904 moderate: default_difficulty_moderate(),
9905 hard: default_difficulty_hard(),
9906 expert: default_difficulty_expert(),
9907 }
9908 }
9909}
9910
9911#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9913pub struct ContextAwareConfig {
9914 #[serde(default)]
9916 pub enabled: bool,
9917
9918 #[serde(default)]
9920 pub vendor_rules: VendorAnomalyRulesConfig,
9921
9922 #[serde(default)]
9924 pub employee_rules: EmployeeAnomalyRulesConfig,
9925
9926 #[serde(default)]
9928 pub account_rules: AccountAnomalyRulesConfig,
9929
9930 #[serde(default)]
9932 pub behavioral_baseline: BehavioralBaselineConfig,
9933}
9934
9935#[derive(Debug, Clone, Serialize, Deserialize)]
9937pub struct VendorAnomalyRulesConfig {
9938 #[serde(default = "default_new_vendor_multiplier")]
9940 pub new_vendor_error_multiplier: f64,
9941
9942 #[serde(default = "default_new_vendor_threshold")]
9944 pub new_vendor_threshold_days: u32,
9945
9946 #[serde(default = "default_international_multiplier")]
9948 pub international_error_multiplier: f64,
9949
9950 #[serde(default = "default_strategic_vendor_types")]
9952 pub strategic_vendor_anomaly_types: Vec<String>,
9953}
9954
9955fn default_new_vendor_multiplier() -> f64 {
9956 2.5
9957}
9958fn default_new_vendor_threshold() -> u32 {
9959 90
9960}
9961fn default_international_multiplier() -> f64 {
9962 1.5
9963}
9964fn default_strategic_vendor_types() -> Vec<String> {
9965 vec![
9966 "pricing_dispute".to_string(),
9967 "contract_violation".to_string(),
9968 ]
9969}
9970
9971impl Default for VendorAnomalyRulesConfig {
9972 fn default() -> Self {
9973 Self {
9974 new_vendor_error_multiplier: default_new_vendor_multiplier(),
9975 new_vendor_threshold_days: default_new_vendor_threshold(),
9976 international_error_multiplier: default_international_multiplier(),
9977 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9978 }
9979 }
9980}
9981
9982#[derive(Debug, Clone, Serialize, Deserialize)]
9984pub struct EmployeeAnomalyRulesConfig {
9985 #[serde(default = "default_new_employee_rate")]
9987 pub new_employee_error_rate: f64,
9988
9989 #[serde(default = "default_new_employee_threshold")]
9991 pub new_employee_threshold_days: u32,
9992
9993 #[serde(default = "default_volume_fatigue_threshold")]
9995 pub volume_fatigue_threshold: u32,
9996
9997 #[serde(default = "default_coverage_multiplier")]
9999 pub coverage_error_multiplier: f64,
10000}
10001
10002fn default_new_employee_rate() -> f64 {
10003 0.05
10004}
10005fn default_new_employee_threshold() -> u32 {
10006 180
10007}
10008fn default_volume_fatigue_threshold() -> u32 {
10009 50
10010}
10011fn default_coverage_multiplier() -> f64 {
10012 1.8
10013}
10014
10015impl Default for EmployeeAnomalyRulesConfig {
10016 fn default() -> Self {
10017 Self {
10018 new_employee_error_rate: default_new_employee_rate(),
10019 new_employee_threshold_days: default_new_employee_threshold(),
10020 volume_fatigue_threshold: default_volume_fatigue_threshold(),
10021 coverage_error_multiplier: default_coverage_multiplier(),
10022 }
10023 }
10024}
10025
10026#[derive(Debug, Clone, Serialize, Deserialize)]
10028pub struct AccountAnomalyRulesConfig {
10029 #[serde(default = "default_high_risk_multiplier")]
10031 pub high_risk_account_multiplier: f64,
10032
10033 #[serde(default = "default_high_risk_accounts")]
10035 pub high_risk_accounts: Vec<String>,
10036
10037 #[serde(default = "default_suspense_multiplier")]
10039 pub suspense_account_multiplier: f64,
10040
10041 #[serde(default = "default_suspense_accounts")]
10043 pub suspense_accounts: Vec<String>,
10044
10045 #[serde(default = "default_intercompany_multiplier")]
10047 pub intercompany_account_multiplier: f64,
10048}
10049
10050fn default_high_risk_multiplier() -> f64 {
10051 2.0
10052}
10053fn default_high_risk_accounts() -> Vec<String> {
10054 vec![
10055 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
10059}
10060fn default_suspense_multiplier() -> f64 {
10061 3.0
10062}
10063fn default_suspense_accounts() -> Vec<String> {
10064 vec!["9999".to_string(), "9998".to_string()]
10065}
10066fn default_intercompany_multiplier() -> f64 {
10067 1.5
10068}
10069
10070impl Default for AccountAnomalyRulesConfig {
10071 fn default() -> Self {
10072 Self {
10073 high_risk_account_multiplier: default_high_risk_multiplier(),
10074 high_risk_accounts: default_high_risk_accounts(),
10075 suspense_account_multiplier: default_suspense_multiplier(),
10076 suspense_accounts: default_suspense_accounts(),
10077 intercompany_account_multiplier: default_intercompany_multiplier(),
10078 }
10079 }
10080}
10081
10082#[derive(Debug, Clone, Serialize, Deserialize)]
10084pub struct BehavioralBaselineConfig {
10085 #[serde(default)]
10087 pub enabled: bool,
10088
10089 #[serde(default = "default_baseline_period")]
10091 pub baseline_period_days: u32,
10092
10093 #[serde(default = "default_deviation_threshold")]
10095 pub deviation_threshold_std: f64,
10096
10097 #[serde(default = "default_frequency_deviation")]
10099 pub frequency_deviation_threshold: f64,
10100}
10101
10102fn default_baseline_period() -> u32 {
10103 90
10104}
10105fn default_deviation_threshold() -> f64 {
10106 3.0
10107}
10108fn default_frequency_deviation() -> f64 {
10109 2.0
10110}
10111
10112impl Default for BehavioralBaselineConfig {
10113 fn default() -> Self {
10114 Self {
10115 enabled: false,
10116 baseline_period_days: default_baseline_period(),
10117 deviation_threshold_std: default_deviation_threshold(),
10118 frequency_deviation_threshold: default_frequency_deviation(),
10119 }
10120 }
10121}
10122
10123#[derive(Debug, Clone, Serialize, Deserialize)]
10125pub struct EnhancedLabelingConfig {
10126 #[serde(default = "default_true_val")]
10128 pub severity_scoring: bool,
10129
10130 #[serde(default = "default_true_val")]
10132 pub difficulty_classification: bool,
10133
10134 #[serde(default)]
10136 pub materiality_thresholds: MaterialityThresholdsConfig,
10137}
10138
10139impl Default for EnhancedLabelingConfig {
10140 fn default() -> Self {
10141 Self {
10142 severity_scoring: true,
10143 difficulty_classification: true,
10144 materiality_thresholds: MaterialityThresholdsConfig::default(),
10145 }
10146 }
10147}
10148
10149#[derive(Debug, Clone, Serialize, Deserialize)]
10151pub struct MaterialityThresholdsConfig {
10152 #[serde(default = "default_materiality_trivial")]
10154 pub trivial: f64,
10155
10156 #[serde(default = "default_materiality_immaterial")]
10158 pub immaterial: f64,
10159
10160 #[serde(default = "default_materiality_material")]
10162 pub material: f64,
10163
10164 #[serde(default = "default_materiality_highly_material")]
10166 pub highly_material: f64,
10167}
10168
10169fn default_materiality_trivial() -> f64 {
10170 0.001
10171}
10172fn default_materiality_immaterial() -> f64 {
10173 0.01
10174}
10175fn default_materiality_material() -> f64 {
10176 0.05
10177}
10178fn default_materiality_highly_material() -> f64 {
10179 0.10
10180}
10181
10182impl Default for MaterialityThresholdsConfig {
10183 fn default() -> Self {
10184 Self {
10185 trivial: default_materiality_trivial(),
10186 immaterial: default_materiality_immaterial(),
10187 material: default_materiality_material(),
10188 highly_material: default_materiality_highly_material(),
10189 }
10190 }
10191}
10192
10193#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10205pub struct IndustrySpecificConfig {
10206 #[serde(default)]
10208 pub enabled: bool,
10209
10210 #[serde(default)]
10212 pub manufacturing: ManufacturingConfig,
10213
10214 #[serde(default)]
10216 pub retail: RetailConfig,
10217
10218 #[serde(default)]
10220 pub healthcare: HealthcareConfig,
10221
10222 #[serde(default)]
10224 pub technology: TechnologyConfig,
10225
10226 #[serde(default)]
10228 pub financial_services: FinancialServicesConfig,
10229
10230 #[serde(default)]
10232 pub professional_services: ProfessionalServicesConfig,
10233}
10234
10235#[derive(Debug, Clone, Serialize, Deserialize)]
10237pub struct ManufacturingConfig {
10238 #[serde(default)]
10240 pub enabled: bool,
10241
10242 #[serde(default = "default_bom_depth")]
10244 pub bom_depth: u32,
10245
10246 #[serde(default)]
10248 pub just_in_time: bool,
10249
10250 #[serde(default = "default_production_order_types")]
10252 pub production_order_types: Vec<String>,
10253
10254 #[serde(default)]
10256 pub quality_framework: Option<String>,
10257
10258 #[serde(default = "default_supplier_tiers")]
10260 pub supplier_tiers: u32,
10261
10262 #[serde(default = "default_cost_frequency")]
10264 pub standard_cost_frequency: String,
10265
10266 #[serde(default = "default_yield_rate")]
10268 pub target_yield_rate: f64,
10269
10270 #[serde(default = "default_scrap_threshold")]
10272 pub scrap_alert_threshold: f64,
10273
10274 #[serde(default)]
10276 pub anomaly_rates: ManufacturingAnomalyRates,
10277
10278 #[serde(default)]
10280 pub cost_accounting: ManufacturingCostAccountingConfig,
10281}
10282
10283#[derive(Debug, Clone, Serialize, Deserialize)]
10285pub struct ManufacturingCostAccountingConfig {
10286 #[serde(default = "default_true")]
10288 pub enabled: bool,
10289
10290 #[serde(default = "default_true")]
10292 pub variance_accounts_enabled: bool,
10293
10294 #[serde(default = "default_true")]
10296 pub warranty_provisions_enabled: bool,
10297
10298 #[serde(default = "default_warranty_defect_threshold")]
10300 pub warranty_defect_threshold: f64,
10301}
10302
10303fn default_warranty_defect_threshold() -> f64 {
10304 0.01
10305}
10306
10307impl Default for ManufacturingCostAccountingConfig {
10308 fn default() -> Self {
10309 Self {
10310 enabled: true,
10311 variance_accounts_enabled: true,
10312 warranty_provisions_enabled: true,
10313 warranty_defect_threshold: 0.01,
10314 }
10315 }
10316}
10317
10318fn default_bom_depth() -> u32 {
10319 4
10320}
10321
10322fn default_production_order_types() -> Vec<String> {
10323 vec![
10324 "standard".to_string(),
10325 "rework".to_string(),
10326 "prototype".to_string(),
10327 ]
10328}
10329
10330fn default_supplier_tiers() -> u32 {
10331 2
10332}
10333
10334fn default_cost_frequency() -> String {
10335 "quarterly".to_string()
10336}
10337
10338fn default_yield_rate() -> f64 {
10339 0.97
10340}
10341
10342fn default_scrap_threshold() -> f64 {
10343 0.03
10344}
10345
10346impl Default for ManufacturingConfig {
10347 fn default() -> Self {
10348 Self {
10349 enabled: false,
10350 bom_depth: default_bom_depth(),
10351 just_in_time: false,
10352 production_order_types: default_production_order_types(),
10353 quality_framework: Some("ISO_9001".to_string()),
10354 supplier_tiers: default_supplier_tiers(),
10355 standard_cost_frequency: default_cost_frequency(),
10356 target_yield_rate: default_yield_rate(),
10357 scrap_alert_threshold: default_scrap_threshold(),
10358 anomaly_rates: ManufacturingAnomalyRates::default(),
10359 cost_accounting: ManufacturingCostAccountingConfig::default(),
10360 }
10361 }
10362}
10363
10364#[derive(Debug, Clone, Serialize, Deserialize)]
10366pub struct ManufacturingAnomalyRates {
10367 #[serde(default = "default_mfg_yield_rate")]
10369 pub yield_manipulation: f64,
10370
10371 #[serde(default = "default_mfg_labor_rate")]
10373 pub labor_misallocation: f64,
10374
10375 #[serde(default = "default_mfg_phantom_rate")]
10377 pub phantom_production: f64,
10378
10379 #[serde(default = "default_mfg_cost_rate")]
10381 pub standard_cost_manipulation: f64,
10382
10383 #[serde(default = "default_mfg_inventory_rate")]
10385 pub inventory_fraud: f64,
10386}
10387
10388fn default_mfg_yield_rate() -> f64 {
10389 0.015
10390}
10391
10392fn default_mfg_labor_rate() -> f64 {
10393 0.02
10394}
10395
10396fn default_mfg_phantom_rate() -> f64 {
10397 0.005
10398}
10399
10400fn default_mfg_cost_rate() -> f64 {
10401 0.01
10402}
10403
10404fn default_mfg_inventory_rate() -> f64 {
10405 0.008
10406}
10407
10408impl Default for ManufacturingAnomalyRates {
10409 fn default() -> Self {
10410 Self {
10411 yield_manipulation: default_mfg_yield_rate(),
10412 labor_misallocation: default_mfg_labor_rate(),
10413 phantom_production: default_mfg_phantom_rate(),
10414 standard_cost_manipulation: default_mfg_cost_rate(),
10415 inventory_fraud: default_mfg_inventory_rate(),
10416 }
10417 }
10418}
10419
10420#[derive(Debug, Clone, Serialize, Deserialize)]
10422pub struct RetailConfig {
10423 #[serde(default)]
10425 pub enabled: bool,
10426
10427 #[serde(default)]
10429 pub store_types: RetailStoreTypeConfig,
10430
10431 #[serde(default = "default_retail_daily_txns")]
10433 pub avg_daily_transactions: u32,
10434
10435 #[serde(default = "default_true")]
10437 pub loss_prevention: bool,
10438
10439 #[serde(default = "default_shrinkage_rate")]
10441 pub shrinkage_rate: f64,
10442
10443 #[serde(default)]
10445 pub anomaly_rates: RetailAnomalyRates,
10446}
10447
10448fn default_retail_daily_txns() -> u32 {
10449 500
10450}
10451
10452fn default_shrinkage_rate() -> f64 {
10453 0.015
10454}
10455
10456impl Default for RetailConfig {
10457 fn default() -> Self {
10458 Self {
10459 enabled: false,
10460 store_types: RetailStoreTypeConfig::default(),
10461 avg_daily_transactions: default_retail_daily_txns(),
10462 loss_prevention: true,
10463 shrinkage_rate: default_shrinkage_rate(),
10464 anomaly_rates: RetailAnomalyRates::default(),
10465 }
10466 }
10467}
10468
10469#[derive(Debug, Clone, Serialize, Deserialize)]
10471pub struct RetailStoreTypeConfig {
10472 #[serde(default = "default_flagship_pct")]
10474 pub flagship: f64,
10475
10476 #[serde(default = "default_regional_pct")]
10478 pub regional: f64,
10479
10480 #[serde(default = "default_outlet_pct")]
10482 pub outlet: f64,
10483
10484 #[serde(default = "default_ecommerce_pct")]
10486 pub ecommerce: f64,
10487}
10488
10489fn default_flagship_pct() -> f64 {
10490 0.10
10491}
10492
10493fn default_regional_pct() -> f64 {
10494 0.50
10495}
10496
10497fn default_outlet_pct() -> f64 {
10498 0.25
10499}
10500
10501fn default_ecommerce_pct() -> f64 {
10502 0.15
10503}
10504
10505impl Default for RetailStoreTypeConfig {
10506 fn default() -> Self {
10507 Self {
10508 flagship: default_flagship_pct(),
10509 regional: default_regional_pct(),
10510 outlet: default_outlet_pct(),
10511 ecommerce: default_ecommerce_pct(),
10512 }
10513 }
10514}
10515
10516#[derive(Debug, Clone, Serialize, Deserialize)]
10518pub struct RetailAnomalyRates {
10519 #[serde(default = "default_sweethearting_rate")]
10521 pub sweethearting: f64,
10522
10523 #[serde(default = "default_skimming_rate")]
10525 pub skimming: f64,
10526
10527 #[serde(default = "default_refund_fraud_rate")]
10529 pub refund_fraud: f64,
10530
10531 #[serde(default = "default_void_abuse_rate")]
10533 pub void_abuse: f64,
10534
10535 #[serde(default = "default_gift_card_rate")]
10537 pub gift_card_fraud: f64,
10538
10539 #[serde(default = "default_retail_kickback_rate")]
10541 pub vendor_kickback: f64,
10542}
10543
10544fn default_sweethearting_rate() -> f64 {
10545 0.02
10546}
10547
10548fn default_skimming_rate() -> f64 {
10549 0.005
10550}
10551
10552fn default_refund_fraud_rate() -> f64 {
10553 0.015
10554}
10555
10556fn default_void_abuse_rate() -> f64 {
10557 0.01
10558}
10559
10560fn default_gift_card_rate() -> f64 {
10561 0.008
10562}
10563
10564fn default_retail_kickback_rate() -> f64 {
10565 0.003
10566}
10567
10568impl Default for RetailAnomalyRates {
10569 fn default() -> Self {
10570 Self {
10571 sweethearting: default_sweethearting_rate(),
10572 skimming: default_skimming_rate(),
10573 refund_fraud: default_refund_fraud_rate(),
10574 void_abuse: default_void_abuse_rate(),
10575 gift_card_fraud: default_gift_card_rate(),
10576 vendor_kickback: default_retail_kickback_rate(),
10577 }
10578 }
10579}
10580
10581#[derive(Debug, Clone, Serialize, Deserialize)]
10583pub struct HealthcareConfig {
10584 #[serde(default)]
10586 pub enabled: bool,
10587
10588 #[serde(default = "default_facility_type")]
10590 pub facility_type: String,
10591
10592 #[serde(default)]
10594 pub payer_mix: HealthcarePayerMix,
10595
10596 #[serde(default)]
10598 pub coding_systems: HealthcareCodingSystems,
10599
10600 #[serde(default)]
10602 pub compliance: HealthcareComplianceConfig,
10603
10604 #[serde(default = "default_daily_encounters")]
10606 pub avg_daily_encounters: u32,
10607
10608 #[serde(default = "default_charges_per_encounter")]
10610 pub avg_charges_per_encounter: u32,
10611
10612 #[serde(default = "default_hc_denial_rate")]
10614 pub denial_rate: f64,
10615
10616 #[serde(default = "default_hc_bad_debt_rate")]
10618 pub bad_debt_rate: f64,
10619
10620 #[serde(default = "default_hc_charity_care_rate")]
10622 pub charity_care_rate: f64,
10623
10624 #[serde(default)]
10626 pub anomaly_rates: HealthcareAnomalyRates,
10627}
10628
10629fn default_facility_type() -> String {
10630 "hospital".to_string()
10631}
10632
10633fn default_daily_encounters() -> u32 {
10634 150
10635}
10636
10637fn default_charges_per_encounter() -> u32 {
10638 8
10639}
10640
10641fn default_hc_denial_rate() -> f64 {
10642 0.05
10643}
10644
10645fn default_hc_bad_debt_rate() -> f64 {
10646 0.03
10647}
10648
10649fn default_hc_charity_care_rate() -> f64 {
10650 0.02
10651}
10652
10653impl Default for HealthcareConfig {
10654 fn default() -> Self {
10655 Self {
10656 enabled: false,
10657 facility_type: default_facility_type(),
10658 payer_mix: HealthcarePayerMix::default(),
10659 coding_systems: HealthcareCodingSystems::default(),
10660 compliance: HealthcareComplianceConfig::default(),
10661 avg_daily_encounters: default_daily_encounters(),
10662 avg_charges_per_encounter: default_charges_per_encounter(),
10663 denial_rate: default_hc_denial_rate(),
10664 bad_debt_rate: default_hc_bad_debt_rate(),
10665 charity_care_rate: default_hc_charity_care_rate(),
10666 anomaly_rates: HealthcareAnomalyRates::default(),
10667 }
10668 }
10669}
10670
10671#[derive(Debug, Clone, Serialize, Deserialize)]
10673pub struct HealthcarePayerMix {
10674 #[serde(default = "default_medicare_pct")]
10676 pub medicare: f64,
10677
10678 #[serde(default = "default_medicaid_pct")]
10680 pub medicaid: f64,
10681
10682 #[serde(default = "default_commercial_pct")]
10684 pub commercial: f64,
10685
10686 #[serde(default = "default_self_pay_pct")]
10688 pub self_pay: f64,
10689}
10690
10691fn default_medicare_pct() -> f64 {
10692 0.40
10693}
10694
10695fn default_medicaid_pct() -> f64 {
10696 0.20
10697}
10698
10699fn default_commercial_pct() -> f64 {
10700 0.30
10701}
10702
10703fn default_self_pay_pct() -> f64 {
10704 0.10
10705}
10706
10707impl Default for HealthcarePayerMix {
10708 fn default() -> Self {
10709 Self {
10710 medicare: default_medicare_pct(),
10711 medicaid: default_medicaid_pct(),
10712 commercial: default_commercial_pct(),
10713 self_pay: default_self_pay_pct(),
10714 }
10715 }
10716}
10717
10718#[derive(Debug, Clone, Serialize, Deserialize)]
10720pub struct HealthcareCodingSystems {
10721 #[serde(default = "default_true")]
10723 pub icd10: bool,
10724
10725 #[serde(default = "default_true")]
10727 pub cpt: bool,
10728
10729 #[serde(default = "default_true")]
10731 pub drg: bool,
10732
10733 #[serde(default = "default_true")]
10735 pub hcpcs: bool,
10736
10737 #[serde(default = "default_true")]
10739 pub revenue_codes: bool,
10740}
10741
10742impl Default for HealthcareCodingSystems {
10743 fn default() -> Self {
10744 Self {
10745 icd10: true,
10746 cpt: true,
10747 drg: true,
10748 hcpcs: true,
10749 revenue_codes: true,
10750 }
10751 }
10752}
10753
10754#[derive(Debug, Clone, Serialize, Deserialize)]
10756pub struct HealthcareComplianceConfig {
10757 #[serde(default = "default_true")]
10759 pub hipaa: bool,
10760
10761 #[serde(default = "default_true")]
10763 pub stark_law: bool,
10764
10765 #[serde(default = "default_true")]
10767 pub anti_kickback: bool,
10768
10769 #[serde(default = "default_true")]
10771 pub false_claims_act: bool,
10772
10773 #[serde(default = "default_true")]
10775 pub emtala: bool,
10776}
10777
10778impl Default for HealthcareComplianceConfig {
10779 fn default() -> Self {
10780 Self {
10781 hipaa: true,
10782 stark_law: true,
10783 anti_kickback: true,
10784 false_claims_act: true,
10785 emtala: true,
10786 }
10787 }
10788}
10789
10790#[derive(Debug, Clone, Serialize, Deserialize)]
10792pub struct HealthcareAnomalyRates {
10793 #[serde(default = "default_upcoding_rate")]
10795 pub upcoding: f64,
10796
10797 #[serde(default = "default_unbundling_rate")]
10799 pub unbundling: f64,
10800
10801 #[serde(default = "default_phantom_billing_rate")]
10803 pub phantom_billing: f64,
10804
10805 #[serde(default = "default_healthcare_kickback_rate")]
10807 pub kickbacks: f64,
10808
10809 #[serde(default = "default_duplicate_billing_rate")]
10811 pub duplicate_billing: f64,
10812
10813 #[serde(default = "default_med_necessity_rate")]
10815 pub medical_necessity_abuse: f64,
10816}
10817
10818fn default_upcoding_rate() -> f64 {
10819 0.02
10820}
10821
10822fn default_unbundling_rate() -> f64 {
10823 0.015
10824}
10825
10826fn default_phantom_billing_rate() -> f64 {
10827 0.005
10828}
10829
10830fn default_healthcare_kickback_rate() -> f64 {
10831 0.003
10832}
10833
10834fn default_duplicate_billing_rate() -> f64 {
10835 0.008
10836}
10837
10838fn default_med_necessity_rate() -> f64 {
10839 0.01
10840}
10841
10842impl Default for HealthcareAnomalyRates {
10843 fn default() -> Self {
10844 Self {
10845 upcoding: default_upcoding_rate(),
10846 unbundling: default_unbundling_rate(),
10847 phantom_billing: default_phantom_billing_rate(),
10848 kickbacks: default_healthcare_kickback_rate(),
10849 duplicate_billing: default_duplicate_billing_rate(),
10850 medical_necessity_abuse: default_med_necessity_rate(),
10851 }
10852 }
10853}
10854
10855#[derive(Debug, Clone, Serialize, Deserialize)]
10857pub struct TechnologyConfig {
10858 #[serde(default)]
10860 pub enabled: bool,
10861
10862 #[serde(default = "default_revenue_model")]
10864 pub revenue_model: String,
10865
10866 #[serde(default = "default_subscription_pct")]
10868 pub subscription_revenue_pct: f64,
10869
10870 #[serde(default = "default_license_pct")]
10872 pub license_revenue_pct: f64,
10873
10874 #[serde(default = "default_services_pct")]
10876 pub services_revenue_pct: f64,
10877
10878 #[serde(default)]
10880 pub rd_capitalization: RdCapitalizationConfig,
10881
10882 #[serde(default)]
10884 pub anomaly_rates: TechnologyAnomalyRates,
10885}
10886
10887fn default_revenue_model() -> String {
10888 "saas".to_string()
10889}
10890
10891fn default_subscription_pct() -> f64 {
10892 0.60
10893}
10894
10895fn default_license_pct() -> f64 {
10896 0.25
10897}
10898
10899fn default_services_pct() -> f64 {
10900 0.15
10901}
10902
10903impl Default for TechnologyConfig {
10904 fn default() -> Self {
10905 Self {
10906 enabled: false,
10907 revenue_model: default_revenue_model(),
10908 subscription_revenue_pct: default_subscription_pct(),
10909 license_revenue_pct: default_license_pct(),
10910 services_revenue_pct: default_services_pct(),
10911 rd_capitalization: RdCapitalizationConfig::default(),
10912 anomaly_rates: TechnologyAnomalyRates::default(),
10913 }
10914 }
10915}
10916
10917#[derive(Debug, Clone, Serialize, Deserialize)]
10919pub struct RdCapitalizationConfig {
10920 #[serde(default = "default_true")]
10922 pub enabled: bool,
10923
10924 #[serde(default = "default_cap_rate")]
10926 pub capitalization_rate: f64,
10927
10928 #[serde(default = "default_useful_life")]
10930 pub useful_life_years: u32,
10931}
10932
10933fn default_cap_rate() -> f64 {
10934 0.30
10935}
10936
10937fn default_useful_life() -> u32 {
10938 3
10939}
10940
10941impl Default for RdCapitalizationConfig {
10942 fn default() -> Self {
10943 Self {
10944 enabled: true,
10945 capitalization_rate: default_cap_rate(),
10946 useful_life_years: default_useful_life(),
10947 }
10948 }
10949}
10950
10951#[derive(Debug, Clone, Serialize, Deserialize)]
10953pub struct TechnologyAnomalyRates {
10954 #[serde(default = "default_premature_rev_rate")]
10956 pub premature_revenue: f64,
10957
10958 #[serde(default = "default_side_letter_rate")]
10960 pub side_letter_abuse: f64,
10961
10962 #[serde(default = "default_channel_stuffing_rate")]
10964 pub channel_stuffing: f64,
10965
10966 #[serde(default = "default_improper_cap_rate")]
10968 pub improper_capitalization: f64,
10969}
10970
10971fn default_premature_rev_rate() -> f64 {
10972 0.015
10973}
10974
10975fn default_side_letter_rate() -> f64 {
10976 0.008
10977}
10978
10979fn default_channel_stuffing_rate() -> f64 {
10980 0.01
10981}
10982
10983fn default_improper_cap_rate() -> f64 {
10984 0.012
10985}
10986
10987impl Default for TechnologyAnomalyRates {
10988 fn default() -> Self {
10989 Self {
10990 premature_revenue: default_premature_rev_rate(),
10991 side_letter_abuse: default_side_letter_rate(),
10992 channel_stuffing: default_channel_stuffing_rate(),
10993 improper_capitalization: default_improper_cap_rate(),
10994 }
10995 }
10996}
10997
10998#[derive(Debug, Clone, Serialize, Deserialize)]
11000pub struct FinancialServicesConfig {
11001 #[serde(default)]
11003 pub enabled: bool,
11004
11005 #[serde(default = "default_fi_type")]
11007 pub institution_type: String,
11008
11009 #[serde(default = "default_fi_regulatory")]
11011 pub regulatory_framework: String,
11012
11013 #[serde(default)]
11015 pub anomaly_rates: FinancialServicesAnomalyRates,
11016}
11017
11018fn default_fi_type() -> String {
11019 "commercial_bank".to_string()
11020}
11021
11022fn default_fi_regulatory() -> String {
11023 "us_banking".to_string()
11024}
11025
11026impl Default for FinancialServicesConfig {
11027 fn default() -> Self {
11028 Self {
11029 enabled: false,
11030 institution_type: default_fi_type(),
11031 regulatory_framework: default_fi_regulatory(),
11032 anomaly_rates: FinancialServicesAnomalyRates::default(),
11033 }
11034 }
11035}
11036
11037#[derive(Debug, Clone, Serialize, Deserialize)]
11039pub struct FinancialServicesAnomalyRates {
11040 #[serde(default = "default_loan_fraud_rate")]
11042 pub loan_fraud: f64,
11043
11044 #[serde(default = "default_trading_fraud_rate")]
11046 pub trading_fraud: f64,
11047
11048 #[serde(default = "default_insurance_fraud_rate")]
11050 pub insurance_fraud: f64,
11051
11052 #[serde(default = "default_account_manip_rate")]
11054 pub account_manipulation: f64,
11055}
11056
11057fn default_loan_fraud_rate() -> f64 {
11058 0.01
11059}
11060
11061fn default_trading_fraud_rate() -> f64 {
11062 0.008
11063}
11064
11065fn default_insurance_fraud_rate() -> f64 {
11066 0.012
11067}
11068
11069fn default_account_manip_rate() -> f64 {
11070 0.005
11071}
11072
11073impl Default for FinancialServicesAnomalyRates {
11074 fn default() -> Self {
11075 Self {
11076 loan_fraud: default_loan_fraud_rate(),
11077 trading_fraud: default_trading_fraud_rate(),
11078 insurance_fraud: default_insurance_fraud_rate(),
11079 account_manipulation: default_account_manip_rate(),
11080 }
11081 }
11082}
11083
11084#[derive(Debug, Clone, Serialize, Deserialize)]
11086pub struct ProfessionalServicesConfig {
11087 #[serde(default)]
11089 pub enabled: bool,
11090
11091 #[serde(default = "default_firm_type")]
11093 pub firm_type: String,
11094
11095 #[serde(default = "default_billing_model")]
11097 pub billing_model: String,
11098
11099 #[serde(default = "default_hourly_rate")]
11101 pub avg_hourly_rate: f64,
11102
11103 #[serde(default)]
11105 pub trust_accounting: TrustAccountingConfig,
11106
11107 #[serde(default)]
11109 pub anomaly_rates: ProfessionalServicesAnomalyRates,
11110}
11111
11112fn default_firm_type() -> String {
11113 "consulting".to_string()
11114}
11115
11116fn default_billing_model() -> String {
11117 "time_and_materials".to_string()
11118}
11119
11120fn default_hourly_rate() -> f64 {
11121 250.0
11122}
11123
11124impl Default for ProfessionalServicesConfig {
11125 fn default() -> Self {
11126 Self {
11127 enabled: false,
11128 firm_type: default_firm_type(),
11129 billing_model: default_billing_model(),
11130 avg_hourly_rate: default_hourly_rate(),
11131 trust_accounting: TrustAccountingConfig::default(),
11132 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
11133 }
11134 }
11135}
11136
11137#[derive(Debug, Clone, Serialize, Deserialize)]
11139pub struct TrustAccountingConfig {
11140 #[serde(default)]
11142 pub enabled: bool,
11143
11144 #[serde(default = "default_true")]
11146 pub require_three_way_reconciliation: bool,
11147}
11148
11149impl Default for TrustAccountingConfig {
11150 fn default() -> Self {
11151 Self {
11152 enabled: false,
11153 require_three_way_reconciliation: true,
11154 }
11155 }
11156}
11157
11158#[derive(Debug, Clone, Serialize, Deserialize)]
11160pub struct ProfessionalServicesAnomalyRates {
11161 #[serde(default = "default_time_fraud_rate")]
11163 pub time_billing_fraud: f64,
11164
11165 #[serde(default = "default_expense_fraud_rate")]
11167 pub expense_fraud: f64,
11168
11169 #[serde(default = "default_trust_misappropriation_rate")]
11171 pub trust_misappropriation: f64,
11172}
11173
11174fn default_time_fraud_rate() -> f64 {
11175 0.02
11176}
11177
11178fn default_expense_fraud_rate() -> f64 {
11179 0.015
11180}
11181
11182fn default_trust_misappropriation_rate() -> f64 {
11183 0.003
11184}
11185
11186impl Default for ProfessionalServicesAnomalyRates {
11187 fn default() -> Self {
11188 Self {
11189 time_billing_fraud: default_time_fraud_rate(),
11190 expense_fraud: default_expense_fraud_rate(),
11191 trust_misappropriation: default_trust_misappropriation_rate(),
11192 }
11193 }
11194}
11195
11196#[derive(Debug, Clone, Serialize, Deserialize)]
11210pub struct FingerprintPrivacyConfig {
11211 #[serde(default)]
11213 pub level: String,
11214 #[serde(default = "default_epsilon")]
11216 pub epsilon: f64,
11217 #[serde(default = "default_delta")]
11219 pub delta: f64,
11220 #[serde(default = "default_k_anonymity")]
11222 pub k_anonymity: u32,
11223 #[serde(default)]
11225 pub composition_method: String,
11226}
11227
11228fn default_epsilon() -> f64 {
11229 1.0
11230}
11231
11232fn default_delta() -> f64 {
11233 1e-5
11234}
11235
11236fn default_k_anonymity() -> u32 {
11237 5
11238}
11239
11240impl Default for FingerprintPrivacyConfig {
11241 fn default() -> Self {
11242 Self {
11243 level: "standard".to_string(),
11244 epsilon: default_epsilon(),
11245 delta: default_delta(),
11246 k_anonymity: default_k_anonymity(),
11247 composition_method: "naive".to_string(),
11248 }
11249 }
11250}
11251
11252#[derive(Debug, Clone, Serialize, Deserialize)]
11266pub struct QualityGatesSchemaConfig {
11267 #[serde(default)]
11269 pub enabled: bool,
11270 #[serde(default = "default_gate_profile_name")]
11272 pub profile: String,
11273 #[serde(default)]
11275 pub fail_on_violation: bool,
11276 #[serde(default)]
11278 pub custom_gates: Vec<QualityGateEntry>,
11279}
11280
11281fn default_gate_profile_name() -> String {
11282 "default".to_string()
11283}
11284
11285impl Default for QualityGatesSchemaConfig {
11286 fn default() -> Self {
11287 Self {
11288 enabled: false,
11289 profile: default_gate_profile_name(),
11290 fail_on_violation: false,
11291 custom_gates: Vec::new(),
11292 }
11293 }
11294}
11295
11296#[derive(Debug, Clone, Serialize, Deserialize)]
11298pub struct QualityGateEntry {
11299 pub name: String,
11301 pub metric: String,
11305 pub threshold: f64,
11307 #[serde(default)]
11309 pub upper_threshold: Option<f64>,
11310 #[serde(default = "default_gate_comparison")]
11312 pub comparison: String,
11313}
11314
11315fn default_gate_comparison() -> String {
11316 "gte".to_string()
11317}
11318
11319#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11329pub struct ComplianceSchemaConfig {
11330 #[serde(default)]
11332 pub content_marking: ContentMarkingSchemaConfig,
11333 #[serde(default)]
11335 pub article10_report: bool,
11336 #[serde(default)]
11338 pub certificates: CertificateSchemaConfig,
11339}
11340
11341#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11343pub struct CertificateSchemaConfig {
11344 #[serde(default)]
11346 pub enabled: bool,
11347 #[serde(default)]
11349 pub signing_key_env: Option<String>,
11350 #[serde(default)]
11352 pub include_quality_metrics: bool,
11353}
11354
11355#[derive(Debug, Clone, Serialize, Deserialize)]
11357pub struct ContentMarkingSchemaConfig {
11358 #[serde(default = "default_true")]
11360 pub enabled: bool,
11361 #[serde(default = "default_marking_format")]
11363 pub format: String,
11364}
11365
11366fn default_marking_format() -> String {
11367 "embedded".to_string()
11368}
11369
11370impl Default for ContentMarkingSchemaConfig {
11371 fn default() -> Self {
11372 Self {
11373 enabled: true,
11374 format: default_marking_format(),
11375 }
11376 }
11377}
11378
11379#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11381pub struct WebhookSchemaConfig {
11382 #[serde(default)]
11384 pub enabled: bool,
11385 #[serde(default)]
11387 pub endpoints: Vec<WebhookEndpointConfig>,
11388}
11389
11390#[derive(Debug, Clone, Serialize, Deserialize)]
11392pub struct WebhookEndpointConfig {
11393 pub url: String,
11395 #[serde(default)]
11397 pub events: Vec<String>,
11398 #[serde(default)]
11400 pub secret: Option<String>,
11401 #[serde(default = "default_webhook_retries")]
11403 pub max_retries: u32,
11404 #[serde(default = "default_webhook_timeout")]
11406 pub timeout_secs: u64,
11407}
11408
11409fn default_webhook_retries() -> u32 {
11410 3
11411}
11412fn default_webhook_timeout() -> u64 {
11413 10
11414}
11415
11416#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11422pub struct SourceToPayConfig {
11423 #[serde(default)]
11425 pub enabled: bool,
11426 #[serde(default)]
11428 pub spend_analysis: SpendAnalysisConfig,
11429 #[serde(default)]
11431 pub sourcing: SourcingConfig,
11432 #[serde(default)]
11434 pub qualification: QualificationConfig,
11435 #[serde(default)]
11437 pub rfx: RfxConfig,
11438 #[serde(default)]
11440 pub contracts: ContractConfig,
11441 #[serde(default)]
11443 pub catalog: CatalogConfig,
11444 #[serde(default)]
11446 pub scorecards: ScorecardConfig,
11447 #[serde(default)]
11449 pub p2p_integration: P2PIntegrationConfig,
11450}
11451
11452#[derive(Debug, Clone, Serialize, Deserialize)]
11454pub struct SpendAnalysisConfig {
11455 #[serde(default = "default_hhi_threshold")]
11457 pub hhi_threshold: f64,
11458 #[serde(default = "default_contract_coverage_target")]
11460 pub contract_coverage_target: f64,
11461}
11462
11463impl Default for SpendAnalysisConfig {
11464 fn default() -> Self {
11465 Self {
11466 hhi_threshold: default_hhi_threshold(),
11467 contract_coverage_target: default_contract_coverage_target(),
11468 }
11469 }
11470}
11471
11472fn default_hhi_threshold() -> f64 {
11473 2500.0
11474}
11475fn default_contract_coverage_target() -> f64 {
11476 0.80
11477}
11478
11479#[derive(Debug, Clone, Serialize, Deserialize)]
11481pub struct SourcingConfig {
11482 #[serde(default = "default_sourcing_projects_per_year")]
11484 pub projects_per_year: u32,
11485 #[serde(default = "default_renewal_horizon_months")]
11487 pub renewal_horizon_months: u32,
11488 #[serde(default = "default_project_duration_months")]
11490 pub project_duration_months: u32,
11491}
11492
11493impl Default for SourcingConfig {
11494 fn default() -> Self {
11495 Self {
11496 projects_per_year: default_sourcing_projects_per_year(),
11497 renewal_horizon_months: default_renewal_horizon_months(),
11498 project_duration_months: default_project_duration_months(),
11499 }
11500 }
11501}
11502
11503fn default_sourcing_projects_per_year() -> u32 {
11504 10
11505}
11506fn default_renewal_horizon_months() -> u32 {
11507 3
11508}
11509fn default_project_duration_months() -> u32 {
11510 4
11511}
11512
11513#[derive(Debug, Clone, Serialize, Deserialize)]
11515pub struct QualificationConfig {
11516 #[serde(default = "default_qualification_pass_rate")]
11518 pub pass_rate: f64,
11519 #[serde(default = "default_qualification_validity_days")]
11521 pub validity_days: u32,
11522 #[serde(default = "default_financial_weight")]
11524 pub financial_weight: f64,
11525 #[serde(default = "default_quality_weight")]
11527 pub quality_weight: f64,
11528 #[serde(default = "default_delivery_weight")]
11530 pub delivery_weight: f64,
11531 #[serde(default = "default_compliance_weight")]
11533 pub compliance_weight: f64,
11534}
11535
11536impl Default for QualificationConfig {
11537 fn default() -> Self {
11538 Self {
11539 pass_rate: default_qualification_pass_rate(),
11540 validity_days: default_qualification_validity_days(),
11541 financial_weight: default_financial_weight(),
11542 quality_weight: default_quality_weight(),
11543 delivery_weight: default_delivery_weight(),
11544 compliance_weight: default_compliance_weight(),
11545 }
11546 }
11547}
11548
11549fn default_qualification_pass_rate() -> f64 {
11550 0.75
11551}
11552fn default_qualification_validity_days() -> u32 {
11553 365
11554}
11555fn default_financial_weight() -> f64 {
11556 0.25
11557}
11558fn default_quality_weight() -> f64 {
11559 0.30
11560}
11561fn default_delivery_weight() -> f64 {
11562 0.25
11563}
11564fn default_compliance_weight() -> f64 {
11565 0.20
11566}
11567
11568#[derive(Debug, Clone, Serialize, Deserialize)]
11570pub struct RfxConfig {
11571 #[serde(default = "default_rfi_threshold")]
11573 pub rfi_threshold: f64,
11574 #[serde(default = "default_min_invited_vendors")]
11576 pub min_invited_vendors: u32,
11577 #[serde(default = "default_max_invited_vendors")]
11579 pub max_invited_vendors: u32,
11580 #[serde(default = "default_response_rate")]
11582 pub response_rate: f64,
11583 #[serde(default = "default_price_weight")]
11585 pub default_price_weight: f64,
11586 #[serde(default = "default_rfx_quality_weight")]
11588 pub default_quality_weight: f64,
11589 #[serde(default = "default_rfx_delivery_weight")]
11591 pub default_delivery_weight: f64,
11592}
11593
11594impl Default for RfxConfig {
11595 fn default() -> Self {
11596 Self {
11597 rfi_threshold: default_rfi_threshold(),
11598 min_invited_vendors: default_min_invited_vendors(),
11599 max_invited_vendors: default_max_invited_vendors(),
11600 response_rate: default_response_rate(),
11601 default_price_weight: default_price_weight(),
11602 default_quality_weight: default_rfx_quality_weight(),
11603 default_delivery_weight: default_rfx_delivery_weight(),
11604 }
11605 }
11606}
11607
11608fn default_rfi_threshold() -> f64 {
11609 100_000.0
11610}
11611fn default_min_invited_vendors() -> u32 {
11612 3
11613}
11614fn default_max_invited_vendors() -> u32 {
11615 8
11616}
11617fn default_response_rate() -> f64 {
11618 0.70
11619}
11620fn default_price_weight() -> f64 {
11621 0.40
11622}
11623fn default_rfx_quality_weight() -> f64 {
11624 0.35
11625}
11626fn default_rfx_delivery_weight() -> f64 {
11627 0.25
11628}
11629
11630#[derive(Debug, Clone, Serialize, Deserialize)]
11632pub struct ContractConfig {
11633 #[serde(default = "default_min_contract_months")]
11635 pub min_duration_months: u32,
11636 #[serde(default = "default_max_contract_months")]
11638 pub max_duration_months: u32,
11639 #[serde(default = "default_auto_renewal_rate")]
11641 pub auto_renewal_rate: f64,
11642 #[serde(default = "default_amendment_rate")]
11644 pub amendment_rate: f64,
11645 #[serde(default)]
11647 pub type_distribution: ContractTypeDistribution,
11648}
11649
11650impl Default for ContractConfig {
11651 fn default() -> Self {
11652 Self {
11653 min_duration_months: default_min_contract_months(),
11654 max_duration_months: default_max_contract_months(),
11655 auto_renewal_rate: default_auto_renewal_rate(),
11656 amendment_rate: default_amendment_rate(),
11657 type_distribution: ContractTypeDistribution::default(),
11658 }
11659 }
11660}
11661
11662fn default_min_contract_months() -> u32 {
11663 12
11664}
11665fn default_max_contract_months() -> u32 {
11666 36
11667}
11668fn default_auto_renewal_rate() -> f64 {
11669 0.40
11670}
11671fn default_amendment_rate() -> f64 {
11672 0.20
11673}
11674
11675#[derive(Debug, Clone, Serialize, Deserialize)]
11677pub struct ContractTypeDistribution {
11678 #[serde(default = "default_fixed_price_pct")]
11680 pub fixed_price: f64,
11681 #[serde(default = "default_blanket_pct")]
11683 pub blanket: f64,
11684 #[serde(default = "default_time_materials_pct")]
11686 pub time_and_materials: f64,
11687 #[serde(default = "default_service_agreement_pct")]
11689 pub service_agreement: f64,
11690}
11691
11692impl Default for ContractTypeDistribution {
11693 fn default() -> Self {
11694 Self {
11695 fixed_price: default_fixed_price_pct(),
11696 blanket: default_blanket_pct(),
11697 time_and_materials: default_time_materials_pct(),
11698 service_agreement: default_service_agreement_pct(),
11699 }
11700 }
11701}
11702
11703fn default_fixed_price_pct() -> f64 {
11704 0.40
11705}
11706fn default_blanket_pct() -> f64 {
11707 0.30
11708}
11709fn default_time_materials_pct() -> f64 {
11710 0.15
11711}
11712fn default_service_agreement_pct() -> f64 {
11713 0.15
11714}
11715
11716#[derive(Debug, Clone, Serialize, Deserialize)]
11718pub struct CatalogConfig {
11719 #[serde(default = "default_preferred_vendor_flag_rate")]
11721 pub preferred_vendor_flag_rate: f64,
11722 #[serde(default = "default_multi_source_rate")]
11724 pub multi_source_rate: f64,
11725}
11726
11727impl Default for CatalogConfig {
11728 fn default() -> Self {
11729 Self {
11730 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
11731 multi_source_rate: default_multi_source_rate(),
11732 }
11733 }
11734}
11735
11736fn default_preferred_vendor_flag_rate() -> f64 {
11737 0.70
11738}
11739fn default_multi_source_rate() -> f64 {
11740 0.25
11741}
11742
11743#[derive(Debug, Clone, Serialize, Deserialize)]
11745pub struct ScorecardConfig {
11746 #[serde(default = "default_scorecard_frequency")]
11748 pub frequency: String,
11749 #[serde(default = "default_otd_weight")]
11751 pub on_time_delivery_weight: f64,
11752 #[serde(default = "default_quality_score_weight")]
11754 pub quality_weight: f64,
11755 #[serde(default = "default_price_score_weight")]
11757 pub price_weight: f64,
11758 #[serde(default = "default_responsiveness_weight")]
11760 pub responsiveness_weight: f64,
11761 #[serde(default = "default_grade_a_threshold")]
11763 pub grade_a_threshold: f64,
11764 #[serde(default = "default_grade_b_threshold")]
11766 pub grade_b_threshold: f64,
11767 #[serde(default = "default_grade_c_threshold")]
11769 pub grade_c_threshold: f64,
11770}
11771
11772impl Default for ScorecardConfig {
11773 fn default() -> Self {
11774 Self {
11775 frequency: default_scorecard_frequency(),
11776 on_time_delivery_weight: default_otd_weight(),
11777 quality_weight: default_quality_score_weight(),
11778 price_weight: default_price_score_weight(),
11779 responsiveness_weight: default_responsiveness_weight(),
11780 grade_a_threshold: default_grade_a_threshold(),
11781 grade_b_threshold: default_grade_b_threshold(),
11782 grade_c_threshold: default_grade_c_threshold(),
11783 }
11784 }
11785}
11786
11787fn default_scorecard_frequency() -> String {
11788 "quarterly".to_string()
11789}
11790fn default_otd_weight() -> f64 {
11791 0.30
11792}
11793fn default_quality_score_weight() -> f64 {
11794 0.30
11795}
11796fn default_price_score_weight() -> f64 {
11797 0.25
11798}
11799fn default_responsiveness_weight() -> f64 {
11800 0.15
11801}
11802fn default_grade_a_threshold() -> f64 {
11803 90.0
11804}
11805fn default_grade_b_threshold() -> f64 {
11806 75.0
11807}
11808fn default_grade_c_threshold() -> f64 {
11809 60.0
11810}
11811
11812#[derive(Debug, Clone, Serialize, Deserialize)]
11814pub struct P2PIntegrationConfig {
11815 #[serde(default = "default_off_contract_rate")]
11817 pub off_contract_rate: f64,
11818 #[serde(default = "default_price_tolerance")]
11820 pub price_tolerance: f64,
11821 #[serde(default)]
11823 pub catalog_enforcement: bool,
11824}
11825
11826impl Default for P2PIntegrationConfig {
11827 fn default() -> Self {
11828 Self {
11829 off_contract_rate: default_off_contract_rate(),
11830 price_tolerance: default_price_tolerance(),
11831 catalog_enforcement: false,
11832 }
11833 }
11834}
11835
11836fn default_off_contract_rate() -> f64 {
11837 0.15
11838}
11839fn default_price_tolerance() -> f64 {
11840 0.02
11841}
11842
11843#[derive(Debug, Clone, Serialize, Deserialize)]
11847pub struct FinancialReportingConfig {
11848 #[serde(default)]
11850 pub enabled: bool,
11851 #[serde(default = "default_true")]
11853 pub generate_balance_sheet: bool,
11854 #[serde(default = "default_true")]
11856 pub generate_income_statement: bool,
11857 #[serde(default = "default_true")]
11859 pub generate_cash_flow: bool,
11860 #[serde(default = "default_true")]
11862 pub generate_changes_in_equity: bool,
11863 #[serde(default = "default_comparative_periods")]
11865 pub comparative_periods: u32,
11866 #[serde(default)]
11868 pub management_kpis: ManagementKpisConfig,
11869 #[serde(default)]
11871 pub budgets: BudgetConfig,
11872}
11873
11874impl Default for FinancialReportingConfig {
11875 fn default() -> Self {
11876 Self {
11877 enabled: false,
11878 generate_balance_sheet: true,
11879 generate_income_statement: true,
11880 generate_cash_flow: true,
11881 generate_changes_in_equity: true,
11882 comparative_periods: default_comparative_periods(),
11883 management_kpis: ManagementKpisConfig::default(),
11884 budgets: BudgetConfig::default(),
11885 }
11886 }
11887}
11888
11889fn default_comparative_periods() -> u32 {
11890 1
11891}
11892
11893#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11895pub struct ManagementKpisConfig {
11896 #[serde(default)]
11898 pub enabled: bool,
11899 #[serde(default = "default_kpi_frequency")]
11901 pub frequency: String,
11902}
11903
11904fn default_kpi_frequency() -> String {
11905 "monthly".to_string()
11906}
11907
11908#[derive(Debug, Clone, Serialize, Deserialize)]
11910pub struct BudgetConfig {
11911 #[serde(default)]
11913 pub enabled: bool,
11914 #[serde(default = "default_revenue_growth_rate")]
11916 pub revenue_growth_rate: f64,
11917 #[serde(default = "default_expense_inflation_rate")]
11919 pub expense_inflation_rate: f64,
11920 #[serde(default = "default_variance_noise")]
11922 pub variance_noise: f64,
11923}
11924
11925impl Default for BudgetConfig {
11926 fn default() -> Self {
11927 Self {
11928 enabled: false,
11929 revenue_growth_rate: default_revenue_growth_rate(),
11930 expense_inflation_rate: default_expense_inflation_rate(),
11931 variance_noise: default_variance_noise(),
11932 }
11933 }
11934}
11935
11936fn default_revenue_growth_rate() -> f64 {
11937 0.05
11938}
11939fn default_expense_inflation_rate() -> f64 {
11940 0.03
11941}
11942fn default_variance_noise() -> f64 {
11943 0.10
11944}
11945
11946#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11950pub struct HrConfig {
11951 #[serde(default)]
11953 pub enabled: bool,
11954 #[serde(default)]
11956 pub payroll: PayrollConfig,
11957 #[serde(default)]
11959 pub time_attendance: TimeAttendanceConfig,
11960 #[serde(default)]
11962 pub expenses: ExpenseConfig,
11963}
11964
11965#[derive(Debug, Clone, Serialize, Deserialize)]
11967pub struct PayrollConfig {
11968 #[serde(default = "default_true")]
11970 pub enabled: bool,
11971 #[serde(default = "default_pay_frequency")]
11973 pub pay_frequency: String,
11974 #[serde(default)]
11976 pub salary_ranges: PayrollSalaryRanges,
11977 #[serde(default)]
11979 pub tax_rates: PayrollTaxRates,
11980 #[serde(default = "default_benefits_enrollment_rate")]
11982 pub benefits_enrollment_rate: f64,
11983 #[serde(default = "default_retirement_participation_rate")]
11985 pub retirement_participation_rate: f64,
11986}
11987
11988impl Default for PayrollConfig {
11989 fn default() -> Self {
11990 Self {
11991 enabled: true,
11992 pay_frequency: default_pay_frequency(),
11993 salary_ranges: PayrollSalaryRanges::default(),
11994 tax_rates: PayrollTaxRates::default(),
11995 benefits_enrollment_rate: default_benefits_enrollment_rate(),
11996 retirement_participation_rate: default_retirement_participation_rate(),
11997 }
11998 }
11999}
12000
12001fn default_pay_frequency() -> String {
12002 "monthly".to_string()
12003}
12004fn default_benefits_enrollment_rate() -> f64 {
12005 0.60
12006}
12007fn default_retirement_participation_rate() -> f64 {
12008 0.45
12009}
12010
12011#[derive(Debug, Clone, Serialize, Deserialize)]
12013pub struct PayrollSalaryRanges {
12014 #[serde(default = "default_staff_min")]
12016 pub staff_min: f64,
12017 #[serde(default = "default_staff_max")]
12018 pub staff_max: f64,
12019 #[serde(default = "default_manager_min")]
12021 pub manager_min: f64,
12022 #[serde(default = "default_manager_max")]
12023 pub manager_max: f64,
12024 #[serde(default = "default_director_min")]
12026 pub director_min: f64,
12027 #[serde(default = "default_director_max")]
12028 pub director_max: f64,
12029 #[serde(default = "default_executive_min")]
12031 pub executive_min: f64,
12032 #[serde(default = "default_executive_max")]
12033 pub executive_max: f64,
12034}
12035
12036impl Default for PayrollSalaryRanges {
12037 fn default() -> Self {
12038 Self {
12039 staff_min: default_staff_min(),
12040 staff_max: default_staff_max(),
12041 manager_min: default_manager_min(),
12042 manager_max: default_manager_max(),
12043 director_min: default_director_min(),
12044 director_max: default_director_max(),
12045 executive_min: default_executive_min(),
12046 executive_max: default_executive_max(),
12047 }
12048 }
12049}
12050
12051fn default_staff_min() -> f64 {
12052 50_000.0
12053}
12054fn default_staff_max() -> f64 {
12055 70_000.0
12056}
12057fn default_manager_min() -> f64 {
12058 80_000.0
12059}
12060fn default_manager_max() -> f64 {
12061 120_000.0
12062}
12063fn default_director_min() -> f64 {
12064 120_000.0
12065}
12066fn default_director_max() -> f64 {
12067 180_000.0
12068}
12069fn default_executive_min() -> f64 {
12070 180_000.0
12071}
12072fn default_executive_max() -> f64 {
12073 350_000.0
12074}
12075
12076#[derive(Debug, Clone, Serialize, Deserialize)]
12078pub struct PayrollTaxRates {
12079 #[serde(default = "default_federal_rate")]
12081 pub federal_effective: f64,
12082 #[serde(default = "default_state_rate")]
12084 pub state_effective: f64,
12085 #[serde(default = "default_fica_rate")]
12087 pub fica: f64,
12088}
12089
12090impl Default for PayrollTaxRates {
12091 fn default() -> Self {
12092 Self {
12093 federal_effective: default_federal_rate(),
12094 state_effective: default_state_rate(),
12095 fica: default_fica_rate(),
12096 }
12097 }
12098}
12099
12100fn default_federal_rate() -> f64 {
12101 0.22
12102}
12103fn default_state_rate() -> f64 {
12104 0.05
12105}
12106fn default_fica_rate() -> f64 {
12107 0.0765
12108}
12109
12110#[derive(Debug, Clone, Serialize, Deserialize)]
12112pub struct TimeAttendanceConfig {
12113 #[serde(default = "default_true")]
12115 pub enabled: bool,
12116 #[serde(default = "default_overtime_rate")]
12118 pub overtime_rate: f64,
12119}
12120
12121impl Default for TimeAttendanceConfig {
12122 fn default() -> Self {
12123 Self {
12124 enabled: true,
12125 overtime_rate: default_overtime_rate(),
12126 }
12127 }
12128}
12129
12130fn default_overtime_rate() -> f64 {
12131 0.10
12132}
12133
12134#[derive(Debug, Clone, Serialize, Deserialize)]
12136pub struct ExpenseConfig {
12137 #[serde(default = "default_true")]
12139 pub enabled: bool,
12140 #[serde(default = "default_expense_submission_rate")]
12142 pub submission_rate: f64,
12143 #[serde(default = "default_policy_violation_rate")]
12145 pub policy_violation_rate: f64,
12146}
12147
12148impl Default for ExpenseConfig {
12149 fn default() -> Self {
12150 Self {
12151 enabled: true,
12152 submission_rate: default_expense_submission_rate(),
12153 policy_violation_rate: default_policy_violation_rate(),
12154 }
12155 }
12156}
12157
12158fn default_expense_submission_rate() -> f64 {
12159 0.30
12160}
12161fn default_policy_violation_rate() -> f64 {
12162 0.08
12163}
12164
12165#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12169pub struct ManufacturingProcessConfig {
12170 #[serde(default)]
12172 pub enabled: bool,
12173 #[serde(default)]
12175 pub production_orders: ProductionOrderConfig,
12176 #[serde(default)]
12178 pub costing: ManufacturingCostingConfig,
12179 #[serde(default)]
12181 pub routing: RoutingConfig,
12182}
12183
12184#[derive(Debug, Clone, Serialize, Deserialize)]
12186pub struct ProductionOrderConfig {
12187 #[serde(default = "default_prod_orders_per_month")]
12189 pub orders_per_month: u32,
12190 #[serde(default = "default_prod_avg_batch_size")]
12192 pub avg_batch_size: u32,
12193 #[serde(default = "default_prod_yield_rate")]
12195 pub yield_rate: f64,
12196 #[serde(default = "default_prod_make_to_order_rate")]
12198 pub make_to_order_rate: f64,
12199 #[serde(default = "default_prod_rework_rate")]
12201 pub rework_rate: f64,
12202}
12203
12204impl Default for ProductionOrderConfig {
12205 fn default() -> Self {
12206 Self {
12207 orders_per_month: default_prod_orders_per_month(),
12208 avg_batch_size: default_prod_avg_batch_size(),
12209 yield_rate: default_prod_yield_rate(),
12210 make_to_order_rate: default_prod_make_to_order_rate(),
12211 rework_rate: default_prod_rework_rate(),
12212 }
12213 }
12214}
12215
12216fn default_prod_orders_per_month() -> u32 {
12217 50
12218}
12219fn default_prod_avg_batch_size() -> u32 {
12220 100
12221}
12222fn default_prod_yield_rate() -> f64 {
12223 0.97
12224}
12225fn default_prod_make_to_order_rate() -> f64 {
12226 0.20
12227}
12228fn default_prod_rework_rate() -> f64 {
12229 0.03
12230}
12231
12232#[derive(Debug, Clone, Serialize, Deserialize)]
12234pub struct ManufacturingCostingConfig {
12235 #[serde(default = "default_labor_rate")]
12237 pub labor_rate_per_hour: f64,
12238 #[serde(default = "default_overhead_rate")]
12240 pub overhead_rate: f64,
12241 #[serde(default = "default_cost_update_frequency")]
12243 pub standard_cost_update_frequency: String,
12244}
12245
12246impl Default for ManufacturingCostingConfig {
12247 fn default() -> Self {
12248 Self {
12249 labor_rate_per_hour: default_labor_rate(),
12250 overhead_rate: default_overhead_rate(),
12251 standard_cost_update_frequency: default_cost_update_frequency(),
12252 }
12253 }
12254}
12255
12256fn default_labor_rate() -> f64 {
12257 35.0
12258}
12259fn default_overhead_rate() -> f64 {
12260 1.50
12261}
12262fn default_cost_update_frequency() -> String {
12263 "quarterly".to_string()
12264}
12265
12266#[derive(Debug, Clone, Serialize, Deserialize)]
12268pub struct RoutingConfig {
12269 #[serde(default = "default_avg_operations")]
12271 pub avg_operations: u32,
12272 #[serde(default = "default_setup_time")]
12274 pub setup_time_hours: f64,
12275 #[serde(default = "default_run_time_variation")]
12277 pub run_time_variation: f64,
12278}
12279
12280impl Default for RoutingConfig {
12281 fn default() -> Self {
12282 Self {
12283 avg_operations: default_avg_operations(),
12284 setup_time_hours: default_setup_time(),
12285 run_time_variation: default_run_time_variation(),
12286 }
12287 }
12288}
12289
12290fn default_avg_operations() -> u32 {
12291 4
12292}
12293fn default_setup_time() -> f64 {
12294 1.5
12295}
12296fn default_run_time_variation() -> f64 {
12297 0.15
12298}
12299
12300#[derive(Debug, Clone, Serialize, Deserialize)]
12304pub struct SalesQuoteConfig {
12305 #[serde(default)]
12307 pub enabled: bool,
12308 #[serde(default = "default_quotes_per_month")]
12310 pub quotes_per_month: u32,
12311 #[serde(default = "default_quote_win_rate")]
12313 pub win_rate: f64,
12314 #[serde(default = "default_quote_validity_days")]
12316 pub validity_days: u32,
12317}
12318
12319impl Default for SalesQuoteConfig {
12320 fn default() -> Self {
12321 Self {
12322 enabled: false,
12323 quotes_per_month: default_quotes_per_month(),
12324 win_rate: default_quote_win_rate(),
12325 validity_days: default_quote_validity_days(),
12326 }
12327 }
12328}
12329
12330fn default_quotes_per_month() -> u32 {
12331 30
12332}
12333fn default_quote_win_rate() -> f64 {
12334 0.35
12335}
12336fn default_quote_validity_days() -> u32 {
12337 30
12338}
12339
12340#[derive(Debug, Clone, Serialize, Deserialize)]
12349pub struct TaxConfig {
12350 #[serde(default)]
12352 pub enabled: bool,
12353 #[serde(default)]
12355 pub jurisdictions: TaxJurisdictionConfig,
12356 #[serde(default)]
12358 pub vat_gst: VatGstConfig,
12359 #[serde(default)]
12361 pub sales_tax: SalesTaxConfig,
12362 #[serde(default)]
12364 pub withholding: WithholdingTaxSchemaConfig,
12365 #[serde(default)]
12367 pub provisions: TaxProvisionSchemaConfig,
12368 #[serde(default)]
12370 pub payroll_tax: PayrollTaxSchemaConfig,
12371 #[serde(default = "default_tax_anomaly_rate")]
12373 pub anomaly_rate: f64,
12374}
12375
12376fn default_tax_anomaly_rate() -> f64 {
12377 0.03
12378}
12379
12380impl Default for TaxConfig {
12381 fn default() -> Self {
12382 Self {
12383 enabled: false,
12384 jurisdictions: TaxJurisdictionConfig::default(),
12385 vat_gst: VatGstConfig::default(),
12386 sales_tax: SalesTaxConfig::default(),
12387 withholding: WithholdingTaxSchemaConfig::default(),
12388 provisions: TaxProvisionSchemaConfig::default(),
12389 payroll_tax: PayrollTaxSchemaConfig::default(),
12390 anomaly_rate: default_tax_anomaly_rate(),
12391 }
12392 }
12393}
12394
12395#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12400pub struct TaxJurisdictionConfig {
12401 #[serde(default)]
12403 pub countries: Vec<String>,
12404 #[serde(default)]
12406 pub include_subnational: bool,
12407}
12408
12409#[derive(Debug, Clone, Serialize, Deserialize)]
12414pub struct VatGstConfig {
12415 #[serde(default)]
12417 pub enabled: bool,
12418 #[serde(default)]
12420 pub standard_rates: std::collections::HashMap<String, f64>,
12421 #[serde(default)]
12423 pub reduced_rates: std::collections::HashMap<String, f64>,
12424 #[serde(default)]
12426 pub exempt_categories: Vec<String>,
12427 #[serde(default = "default_true")]
12429 pub reverse_charge: bool,
12430}
12431
12432impl Default for VatGstConfig {
12433 fn default() -> Self {
12434 Self {
12435 enabled: false,
12436 standard_rates: std::collections::HashMap::new(),
12437 reduced_rates: std::collections::HashMap::new(),
12438 exempt_categories: Vec::new(),
12439 reverse_charge: true,
12440 }
12441 }
12442}
12443
12444#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12448pub struct SalesTaxConfig {
12449 #[serde(default)]
12451 pub enabled: bool,
12452 #[serde(default)]
12454 pub nexus_states: Vec<String>,
12455}
12456
12457#[derive(Debug, Clone, Serialize, Deserialize)]
12462pub struct WithholdingTaxSchemaConfig {
12463 #[serde(default)]
12465 pub enabled: bool,
12466 #[serde(default = "default_true")]
12468 pub treaty_network: bool,
12469 #[serde(default = "default_withholding_rate")]
12471 pub default_rate: f64,
12472 #[serde(default = "default_treaty_reduced_rate")]
12474 pub treaty_reduced_rate: f64,
12475}
12476
12477fn default_withholding_rate() -> f64 {
12478 0.30
12479}
12480
12481fn default_treaty_reduced_rate() -> f64 {
12482 0.15
12483}
12484
12485impl Default for WithholdingTaxSchemaConfig {
12486 fn default() -> Self {
12487 Self {
12488 enabled: false,
12489 treaty_network: true,
12490 default_rate: default_withholding_rate(),
12491 treaty_reduced_rate: default_treaty_reduced_rate(),
12492 }
12493 }
12494}
12495
12496#[derive(Debug, Clone, Serialize, Deserialize)]
12501pub struct TaxProvisionSchemaConfig {
12502 #[serde(default = "default_true")]
12505 pub enabled: bool,
12506 #[serde(default = "default_statutory_rate")]
12508 pub statutory_rate: f64,
12509 #[serde(default = "default_true")]
12511 pub uncertain_positions: bool,
12512}
12513
12514fn default_statutory_rate() -> f64 {
12515 0.21
12516}
12517
12518impl Default for TaxProvisionSchemaConfig {
12519 fn default() -> Self {
12520 Self {
12521 enabled: true,
12522 statutory_rate: default_statutory_rate(),
12523 uncertain_positions: true,
12524 }
12525 }
12526}
12527
12528#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12533pub struct PayrollTaxSchemaConfig {
12534 #[serde(default)]
12536 pub enabled: bool,
12537}
12538
12539#[derive(Debug, Clone, Serialize, Deserialize)]
12549pub struct TreasuryConfig {
12550 #[serde(default)]
12552 pub enabled: bool,
12553 #[serde(default)]
12555 pub cash_positioning: CashPositioningConfig,
12556 #[serde(default)]
12558 pub cash_forecasting: CashForecastingConfig,
12559 #[serde(default)]
12561 pub cash_pooling: CashPoolingConfig,
12562 #[serde(default)]
12564 pub hedging: HedgingSchemaConfig,
12565 #[serde(default)]
12567 pub debt: DebtSchemaConfig,
12568 #[serde(default)]
12570 pub netting: NettingSchemaConfig,
12571 #[serde(default)]
12573 pub bank_guarantees: BankGuaranteeSchemaConfig,
12574 #[serde(default = "default_treasury_anomaly_rate")]
12576 pub anomaly_rate: f64,
12577}
12578
12579fn default_treasury_anomaly_rate() -> f64 {
12580 0.02
12581}
12582
12583impl Default for TreasuryConfig {
12584 fn default() -> Self {
12585 Self {
12586 enabled: false,
12587 cash_positioning: CashPositioningConfig::default(),
12588 cash_forecasting: CashForecastingConfig::default(),
12589 cash_pooling: CashPoolingConfig::default(),
12590 hedging: HedgingSchemaConfig::default(),
12591 debt: DebtSchemaConfig::default(),
12592 netting: NettingSchemaConfig::default(),
12593 bank_guarantees: BankGuaranteeSchemaConfig::default(),
12594 anomaly_rate: default_treasury_anomaly_rate(),
12595 }
12596 }
12597}
12598
12599#[derive(Debug, Clone, Serialize, Deserialize)]
12603pub struct CashPositioningConfig {
12604 #[serde(default = "default_true")]
12606 pub enabled: bool,
12607 #[serde(default = "default_cash_frequency")]
12609 pub frequency: String,
12610 #[serde(default = "default_minimum_balance_policy")]
12612 pub minimum_balance_policy: f64,
12613}
12614
12615fn default_cash_frequency() -> String {
12616 "daily".to_string()
12617}
12618
12619fn default_minimum_balance_policy() -> f64 {
12620 100_000.0
12621}
12622
12623impl Default for CashPositioningConfig {
12624 fn default() -> Self {
12625 Self {
12626 enabled: true,
12627 frequency: default_cash_frequency(),
12628 minimum_balance_policy: default_minimum_balance_policy(),
12629 }
12630 }
12631}
12632
12633#[derive(Debug, Clone, Serialize, Deserialize)]
12637pub struct CashForecastingConfig {
12638 #[serde(default = "default_true")]
12640 pub enabled: bool,
12641 #[serde(default = "default_horizon_days")]
12643 pub horizon_days: u32,
12644 #[serde(default = "default_ar_probability_curve")]
12646 pub ar_collection_probability_curve: String,
12647 #[serde(default = "default_confidence_interval")]
12649 pub confidence_interval: f64,
12650}
12651
12652fn default_horizon_days() -> u32 {
12653 90
12654}
12655
12656fn default_ar_probability_curve() -> String {
12657 "aging".to_string()
12658}
12659
12660fn default_confidence_interval() -> f64 {
12661 0.90
12662}
12663
12664impl Default for CashForecastingConfig {
12665 fn default() -> Self {
12666 Self {
12667 enabled: true,
12668 horizon_days: default_horizon_days(),
12669 ar_collection_probability_curve: default_ar_probability_curve(),
12670 confidence_interval: default_confidence_interval(),
12671 }
12672 }
12673}
12674
12675#[derive(Debug, Clone, Serialize, Deserialize)]
12679pub struct CashPoolingConfig {
12680 #[serde(default)]
12682 pub enabled: bool,
12683 #[serde(default = "default_pool_type")]
12685 pub pool_type: String,
12686 #[serde(default = "default_sweep_time")]
12688 pub sweep_time: String,
12689}
12690
12691fn default_pool_type() -> String {
12692 "zero_balancing".to_string()
12693}
12694
12695fn default_sweep_time() -> String {
12696 "16:00".to_string()
12697}
12698
12699impl Default for CashPoolingConfig {
12700 fn default() -> Self {
12701 Self {
12702 enabled: false,
12703 pool_type: default_pool_type(),
12704 sweep_time: default_sweep_time(),
12705 }
12706 }
12707}
12708
12709#[derive(Debug, Clone, Serialize, Deserialize)]
12714pub struct HedgingSchemaConfig {
12715 #[serde(default)]
12717 pub enabled: bool,
12718 #[serde(default = "default_hedge_ratio")]
12720 pub hedge_ratio: f64,
12721 #[serde(default = "default_hedge_instruments")]
12723 pub instruments: Vec<String>,
12724 #[serde(default = "default_true")]
12726 pub hedge_accounting: bool,
12727 #[serde(default = "default_effectiveness_method")]
12729 pub effectiveness_method: String,
12730}
12731
12732fn default_hedge_ratio() -> f64 {
12733 0.75
12734}
12735
12736fn default_hedge_instruments() -> Vec<String> {
12737 vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
12738}
12739
12740fn default_effectiveness_method() -> String {
12741 "regression".to_string()
12742}
12743
12744impl Default for HedgingSchemaConfig {
12745 fn default() -> Self {
12746 Self {
12747 enabled: false,
12748 hedge_ratio: default_hedge_ratio(),
12749 instruments: default_hedge_instruments(),
12750 hedge_accounting: true,
12751 effectiveness_method: default_effectiveness_method(),
12752 }
12753 }
12754}
12755
12756#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12761pub struct DebtSchemaConfig {
12762 #[serde(default)]
12764 pub enabled: bool,
12765 #[serde(default)]
12767 pub instruments: Vec<DebtInstrumentDef>,
12768 #[serde(default)]
12770 pub covenants: Vec<CovenantDef>,
12771}
12772
12773#[derive(Debug, Clone, Serialize, Deserialize)]
12775pub struct DebtInstrumentDef {
12776 #[serde(rename = "type")]
12778 pub instrument_type: String,
12779 #[serde(default)]
12781 pub principal: Option<f64>,
12782 #[serde(default)]
12784 pub rate: Option<f64>,
12785 #[serde(default)]
12787 pub maturity_months: Option<u32>,
12788 #[serde(default)]
12790 pub facility: Option<f64>,
12791}
12792
12793#[derive(Debug, Clone, Serialize, Deserialize)]
12795pub struct CovenantDef {
12796 #[serde(rename = "type")]
12799 pub covenant_type: String,
12800 pub threshold: f64,
12802}
12803
12804#[derive(Debug, Clone, Serialize, Deserialize)]
12808pub struct NettingSchemaConfig {
12809 #[serde(default)]
12811 pub enabled: bool,
12812 #[serde(default = "default_netting_cycle")]
12814 pub cycle: String,
12815}
12816
12817fn default_netting_cycle() -> String {
12818 "monthly".to_string()
12819}
12820
12821impl Default for NettingSchemaConfig {
12822 fn default() -> Self {
12823 Self {
12824 enabled: false,
12825 cycle: default_netting_cycle(),
12826 }
12827 }
12828}
12829
12830#[derive(Debug, Clone, Serialize, Deserialize)]
12834pub struct BankGuaranteeSchemaConfig {
12835 #[serde(default)]
12837 pub enabled: bool,
12838 #[serde(default = "default_guarantee_count")]
12840 pub count: u32,
12841}
12842
12843fn default_guarantee_count() -> u32 {
12844 5
12845}
12846
12847impl Default for BankGuaranteeSchemaConfig {
12848 fn default() -> Self {
12849 Self {
12850 enabled: false,
12851 count: default_guarantee_count(),
12852 }
12853 }
12854}
12855
12856#[derive(Debug, Clone, Serialize, Deserialize)]
12865pub struct ProjectAccountingConfig {
12866 #[serde(default)]
12868 pub enabled: bool,
12869 #[serde(default = "default_project_count")]
12871 pub project_count: u32,
12872 #[serde(default)]
12874 pub project_types: ProjectTypeDistribution,
12875 #[serde(default)]
12877 pub wbs: WbsSchemaConfig,
12878 #[serde(default)]
12880 pub cost_allocation: CostAllocationConfig,
12881 #[serde(default)]
12883 pub revenue_recognition: ProjectRevenueRecognitionConfig,
12884 #[serde(default)]
12886 pub milestones: MilestoneSchemaConfig,
12887 #[serde(default)]
12889 pub change_orders: ChangeOrderSchemaConfig,
12890 #[serde(default)]
12892 pub retainage: RetainageSchemaConfig,
12893 #[serde(default)]
12895 pub earned_value: EarnedValueSchemaConfig,
12896 #[serde(default = "default_project_anomaly_rate")]
12898 pub anomaly_rate: f64,
12899}
12900
12901fn default_project_count() -> u32 {
12902 10
12903}
12904
12905fn default_project_anomaly_rate() -> f64 {
12906 0.03
12907}
12908
12909impl Default for ProjectAccountingConfig {
12910 fn default() -> Self {
12911 Self {
12912 enabled: false,
12913 project_count: default_project_count(),
12914 project_types: ProjectTypeDistribution::default(),
12915 wbs: WbsSchemaConfig::default(),
12916 cost_allocation: CostAllocationConfig::default(),
12917 revenue_recognition: ProjectRevenueRecognitionConfig::default(),
12918 milestones: MilestoneSchemaConfig::default(),
12919 change_orders: ChangeOrderSchemaConfig::default(),
12920 retainage: RetainageSchemaConfig::default(),
12921 earned_value: EarnedValueSchemaConfig::default(),
12922 anomaly_rate: default_project_anomaly_rate(),
12923 }
12924 }
12925}
12926
12927#[derive(Debug, Clone, Serialize, Deserialize)]
12929pub struct ProjectTypeDistribution {
12930 #[serde(default = "default_capital_weight")]
12932 pub capital: f64,
12933 #[serde(default = "default_internal_weight")]
12935 pub internal: f64,
12936 #[serde(default = "default_customer_weight")]
12938 pub customer: f64,
12939 #[serde(default = "default_rnd_weight")]
12941 pub r_and_d: f64,
12942 #[serde(default = "default_maintenance_weight")]
12944 pub maintenance: f64,
12945 #[serde(default = "default_technology_weight")]
12947 pub technology: f64,
12948}
12949
12950fn default_capital_weight() -> f64 {
12951 0.25
12952}
12953fn default_internal_weight() -> f64 {
12954 0.20
12955}
12956fn default_customer_weight() -> f64 {
12957 0.30
12958}
12959fn default_rnd_weight() -> f64 {
12960 0.10
12961}
12962fn default_maintenance_weight() -> f64 {
12963 0.10
12964}
12965fn default_technology_weight() -> f64 {
12966 0.05
12967}
12968
12969impl Default for ProjectTypeDistribution {
12970 fn default() -> Self {
12971 Self {
12972 capital: default_capital_weight(),
12973 internal: default_internal_weight(),
12974 customer: default_customer_weight(),
12975 r_and_d: default_rnd_weight(),
12976 maintenance: default_maintenance_weight(),
12977 technology: default_technology_weight(),
12978 }
12979 }
12980}
12981
12982#[derive(Debug, Clone, Serialize, Deserialize)]
12984pub struct WbsSchemaConfig {
12985 #[serde(default = "default_wbs_max_depth")]
12987 pub max_depth: u32,
12988 #[serde(default = "default_wbs_min_elements")]
12990 pub min_elements_per_level: u32,
12991 #[serde(default = "default_wbs_max_elements")]
12993 pub max_elements_per_level: u32,
12994}
12995
12996fn default_wbs_max_depth() -> u32 {
12997 3
12998}
12999fn default_wbs_min_elements() -> u32 {
13000 2
13001}
13002fn default_wbs_max_elements() -> u32 {
13003 6
13004}
13005
13006impl Default for WbsSchemaConfig {
13007 fn default() -> Self {
13008 Self {
13009 max_depth: default_wbs_max_depth(),
13010 min_elements_per_level: default_wbs_min_elements(),
13011 max_elements_per_level: default_wbs_max_elements(),
13012 }
13013 }
13014}
13015
13016#[derive(Debug, Clone, Serialize, Deserialize)]
13018pub struct CostAllocationConfig {
13019 #[serde(default = "default_time_entry_rate")]
13021 pub time_entry_project_rate: f64,
13022 #[serde(default = "default_expense_rate")]
13024 pub expense_project_rate: f64,
13025 #[serde(default = "default_po_rate")]
13027 pub purchase_order_project_rate: f64,
13028 #[serde(default = "default_vi_rate")]
13030 pub vendor_invoice_project_rate: f64,
13031}
13032
13033fn default_time_entry_rate() -> f64 {
13034 0.60
13035}
13036fn default_expense_rate() -> f64 {
13037 0.30
13038}
13039fn default_po_rate() -> f64 {
13040 0.40
13041}
13042fn default_vi_rate() -> f64 {
13043 0.35
13044}
13045
13046impl Default for CostAllocationConfig {
13047 fn default() -> Self {
13048 Self {
13049 time_entry_project_rate: default_time_entry_rate(),
13050 expense_project_rate: default_expense_rate(),
13051 purchase_order_project_rate: default_po_rate(),
13052 vendor_invoice_project_rate: default_vi_rate(),
13053 }
13054 }
13055}
13056
13057#[derive(Debug, Clone, Serialize, Deserialize)]
13059pub struct ProjectRevenueRecognitionConfig {
13060 #[serde(default = "default_true")]
13062 pub enabled: bool,
13063 #[serde(default = "default_revenue_method")]
13065 pub method: String,
13066 #[serde(default = "default_completion_measure")]
13068 pub completion_measure: String,
13069 #[serde(default = "default_avg_contract_value")]
13071 pub avg_contract_value: f64,
13072}
13073
13074fn default_revenue_method() -> String {
13075 "percentage_of_completion".to_string()
13076}
13077fn default_completion_measure() -> String {
13078 "cost_to_cost".to_string()
13079}
13080fn default_avg_contract_value() -> f64 {
13081 500_000.0
13082}
13083
13084impl Default for ProjectRevenueRecognitionConfig {
13085 fn default() -> Self {
13086 Self {
13087 enabled: true,
13088 method: default_revenue_method(),
13089 completion_measure: default_completion_measure(),
13090 avg_contract_value: default_avg_contract_value(),
13091 }
13092 }
13093}
13094
13095#[derive(Debug, Clone, Serialize, Deserialize)]
13097pub struct MilestoneSchemaConfig {
13098 #[serde(default = "default_true")]
13100 pub enabled: bool,
13101 #[serde(default = "default_milestones_per_project")]
13103 pub avg_per_project: u32,
13104 #[serde(default = "default_payment_milestone_rate")]
13106 pub payment_milestone_rate: f64,
13107}
13108
13109fn default_milestones_per_project() -> u32 {
13110 4
13111}
13112fn default_payment_milestone_rate() -> f64 {
13113 0.50
13114}
13115
13116impl Default for MilestoneSchemaConfig {
13117 fn default() -> Self {
13118 Self {
13119 enabled: true,
13120 avg_per_project: default_milestones_per_project(),
13121 payment_milestone_rate: default_payment_milestone_rate(),
13122 }
13123 }
13124}
13125
13126#[derive(Debug, Clone, Serialize, Deserialize)]
13128pub struct ChangeOrderSchemaConfig {
13129 #[serde(default = "default_true")]
13131 pub enabled: bool,
13132 #[serde(default = "default_change_order_probability")]
13134 pub probability: f64,
13135 #[serde(default = "default_max_change_orders")]
13137 pub max_per_project: u32,
13138 #[serde(default = "default_change_order_approval_rate")]
13140 pub approval_rate: f64,
13141}
13142
13143fn default_change_order_probability() -> f64 {
13144 0.40
13145}
13146fn default_max_change_orders() -> u32 {
13147 3
13148}
13149fn default_change_order_approval_rate() -> f64 {
13150 0.75
13151}
13152
13153impl Default for ChangeOrderSchemaConfig {
13154 fn default() -> Self {
13155 Self {
13156 enabled: true,
13157 probability: default_change_order_probability(),
13158 max_per_project: default_max_change_orders(),
13159 approval_rate: default_change_order_approval_rate(),
13160 }
13161 }
13162}
13163
13164#[derive(Debug, Clone, Serialize, Deserialize)]
13166pub struct RetainageSchemaConfig {
13167 #[serde(default)]
13169 pub enabled: bool,
13170 #[serde(default = "default_retainage_pct")]
13172 pub default_percentage: f64,
13173}
13174
13175fn default_retainage_pct() -> f64 {
13176 0.10
13177}
13178
13179impl Default for RetainageSchemaConfig {
13180 fn default() -> Self {
13181 Self {
13182 enabled: false,
13183 default_percentage: default_retainage_pct(),
13184 }
13185 }
13186}
13187
13188#[derive(Debug, Clone, Serialize, Deserialize)]
13190pub struct EarnedValueSchemaConfig {
13191 #[serde(default = "default_true")]
13193 pub enabled: bool,
13194 #[serde(default = "default_evm_frequency")]
13196 pub frequency: String,
13197}
13198
13199fn default_evm_frequency() -> String {
13200 "monthly".to_string()
13201}
13202
13203impl Default for EarnedValueSchemaConfig {
13204 fn default() -> Self {
13205 Self {
13206 enabled: true,
13207 frequency: default_evm_frequency(),
13208 }
13209 }
13210}
13211
13212#[derive(Debug, Clone, Serialize, Deserialize)]
13218pub struct EsgConfig {
13219 #[serde(default)]
13221 pub enabled: bool,
13222 #[serde(default)]
13224 pub environmental: EnvironmentalConfig,
13225 #[serde(default)]
13227 pub social: SocialConfig,
13228 #[serde(default)]
13230 pub governance: GovernanceSchemaConfig,
13231 #[serde(default)]
13233 pub supply_chain_esg: SupplyChainEsgConfig,
13234 #[serde(default)]
13236 pub reporting: EsgReportingConfig,
13237 #[serde(default)]
13239 pub climate_scenarios: ClimateScenarioConfig,
13240 #[serde(default = "default_esg_anomaly_rate")]
13242 pub anomaly_rate: f64,
13243}
13244
13245fn default_esg_anomaly_rate() -> f64 {
13246 0.02
13247}
13248
13249impl Default for EsgConfig {
13250 fn default() -> Self {
13251 Self {
13252 enabled: false,
13253 environmental: EnvironmentalConfig::default(),
13254 social: SocialConfig::default(),
13255 governance: GovernanceSchemaConfig::default(),
13256 supply_chain_esg: SupplyChainEsgConfig::default(),
13257 reporting: EsgReportingConfig::default(),
13258 climate_scenarios: ClimateScenarioConfig::default(),
13259 anomaly_rate: default_esg_anomaly_rate(),
13260 }
13261 }
13262}
13263
13264#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13269pub struct CountryPacksSchemaConfig {
13270 #[serde(default)]
13272 pub external_dir: Option<PathBuf>,
13273 #[serde(default)]
13277 pub overrides: std::collections::HashMap<String, serde_json::Value>,
13278}
13279
13280#[derive(Debug, Clone, Serialize, Deserialize)]
13282pub struct EnvironmentalConfig {
13283 #[serde(default = "default_true")]
13285 pub enabled: bool,
13286 #[serde(default)]
13288 pub scope1: EmissionScopeConfig,
13289 #[serde(default)]
13291 pub scope2: EmissionScopeConfig,
13292 #[serde(default)]
13294 pub scope3: Scope3Config,
13295 #[serde(default)]
13297 pub energy: EnergySchemaConfig,
13298 #[serde(default)]
13300 pub water: WaterSchemaConfig,
13301 #[serde(default)]
13303 pub waste: WasteSchemaConfig,
13304}
13305
13306impl Default for EnvironmentalConfig {
13307 fn default() -> Self {
13308 Self {
13309 enabled: true,
13310 scope1: EmissionScopeConfig::default(),
13311 scope2: EmissionScopeConfig::default(),
13312 scope3: Scope3Config::default(),
13313 energy: EnergySchemaConfig::default(),
13314 water: WaterSchemaConfig::default(),
13315 waste: WasteSchemaConfig::default(),
13316 }
13317 }
13318}
13319
13320#[derive(Debug, Clone, Serialize, Deserialize)]
13322pub struct EmissionScopeConfig {
13323 #[serde(default = "default_true")]
13325 pub enabled: bool,
13326 #[serde(default = "default_emission_region")]
13328 pub factor_region: String,
13329}
13330
13331fn default_emission_region() -> String {
13332 "US".to_string()
13333}
13334
13335impl Default for EmissionScopeConfig {
13336 fn default() -> Self {
13337 Self {
13338 enabled: true,
13339 factor_region: default_emission_region(),
13340 }
13341 }
13342}
13343
13344#[derive(Debug, Clone, Serialize, Deserialize)]
13346pub struct Scope3Config {
13347 #[serde(default = "default_true")]
13349 pub enabled: bool,
13350 #[serde(default = "default_scope3_categories")]
13352 pub categories: Vec<String>,
13353 #[serde(default = "default_spend_intensity")]
13355 pub default_spend_intensity_kg_per_usd: f64,
13356}
13357
13358fn default_scope3_categories() -> Vec<String> {
13359 vec![
13360 "purchased_goods".to_string(),
13361 "business_travel".to_string(),
13362 "employee_commuting".to_string(),
13363 ]
13364}
13365
13366fn default_spend_intensity() -> f64 {
13367 0.5
13368}
13369
13370impl Default for Scope3Config {
13371 fn default() -> Self {
13372 Self {
13373 enabled: true,
13374 categories: default_scope3_categories(),
13375 default_spend_intensity_kg_per_usd: default_spend_intensity(),
13376 }
13377 }
13378}
13379
13380#[derive(Debug, Clone, Serialize, Deserialize)]
13382pub struct EnergySchemaConfig {
13383 #[serde(default = "default_true")]
13385 pub enabled: bool,
13386 #[serde(default = "default_facility_count")]
13388 pub facility_count: u32,
13389 #[serde(default = "default_renewable_target")]
13391 pub renewable_target: f64,
13392}
13393
13394fn default_facility_count() -> u32 {
13395 5
13396}
13397
13398fn default_renewable_target() -> f64 {
13399 0.30
13400}
13401
13402impl Default for EnergySchemaConfig {
13403 fn default() -> Self {
13404 Self {
13405 enabled: true,
13406 facility_count: default_facility_count(),
13407 renewable_target: default_renewable_target(),
13408 }
13409 }
13410}
13411
13412#[derive(Debug, Clone, Serialize, Deserialize)]
13414pub struct WaterSchemaConfig {
13415 #[serde(default = "default_true")]
13417 pub enabled: bool,
13418 #[serde(default = "default_water_facility_count")]
13420 pub facility_count: u32,
13421}
13422
13423fn default_water_facility_count() -> u32 {
13424 3
13425}
13426
13427impl Default for WaterSchemaConfig {
13428 fn default() -> Self {
13429 Self {
13430 enabled: true,
13431 facility_count: default_water_facility_count(),
13432 }
13433 }
13434}
13435
13436#[derive(Debug, Clone, Serialize, Deserialize)]
13438pub struct WasteSchemaConfig {
13439 #[serde(default = "default_true")]
13441 pub enabled: bool,
13442 #[serde(default = "default_diversion_target")]
13444 pub diversion_target: f64,
13445}
13446
13447fn default_diversion_target() -> f64 {
13448 0.50
13449}
13450
13451impl Default for WasteSchemaConfig {
13452 fn default() -> Self {
13453 Self {
13454 enabled: true,
13455 diversion_target: default_diversion_target(),
13456 }
13457 }
13458}
13459
13460#[derive(Debug, Clone, Serialize, Deserialize)]
13462pub struct SocialConfig {
13463 #[serde(default = "default_true")]
13465 pub enabled: bool,
13466 #[serde(default)]
13468 pub diversity: DiversitySchemaConfig,
13469 #[serde(default)]
13471 pub pay_equity: PayEquitySchemaConfig,
13472 #[serde(default)]
13474 pub safety: SafetySchemaConfig,
13475}
13476
13477impl Default for SocialConfig {
13478 fn default() -> Self {
13479 Self {
13480 enabled: true,
13481 diversity: DiversitySchemaConfig::default(),
13482 pay_equity: PayEquitySchemaConfig::default(),
13483 safety: SafetySchemaConfig::default(),
13484 }
13485 }
13486}
13487
13488#[derive(Debug, Clone, Serialize, Deserialize)]
13490pub struct DiversitySchemaConfig {
13491 #[serde(default = "default_true")]
13493 pub enabled: bool,
13494 #[serde(default = "default_diversity_dimensions")]
13496 pub dimensions: Vec<String>,
13497}
13498
13499fn default_diversity_dimensions() -> Vec<String> {
13500 vec![
13501 "gender".to_string(),
13502 "ethnicity".to_string(),
13503 "age_group".to_string(),
13504 ]
13505}
13506
13507impl Default for DiversitySchemaConfig {
13508 fn default() -> Self {
13509 Self {
13510 enabled: true,
13511 dimensions: default_diversity_dimensions(),
13512 }
13513 }
13514}
13515
13516#[derive(Debug, Clone, Serialize, Deserialize)]
13518pub struct PayEquitySchemaConfig {
13519 #[serde(default = "default_true")]
13521 pub enabled: bool,
13522 #[serde(default = "default_pay_gap_threshold")]
13524 pub gap_threshold: f64,
13525}
13526
13527fn default_pay_gap_threshold() -> f64 {
13528 0.05
13529}
13530
13531impl Default for PayEquitySchemaConfig {
13532 fn default() -> Self {
13533 Self {
13534 enabled: true,
13535 gap_threshold: default_pay_gap_threshold(),
13536 }
13537 }
13538}
13539
13540#[derive(Debug, Clone, Serialize, Deserialize)]
13542pub struct SafetySchemaConfig {
13543 #[serde(default = "default_true")]
13545 pub enabled: bool,
13546 #[serde(default = "default_trir_target")]
13548 pub target_trir: f64,
13549 #[serde(default = "default_incident_count")]
13551 pub incident_count: u32,
13552}
13553
13554fn default_trir_target() -> f64 {
13555 2.5
13556}
13557
13558fn default_incident_count() -> u32 {
13559 20
13560}
13561
13562impl Default for SafetySchemaConfig {
13563 fn default() -> Self {
13564 Self {
13565 enabled: true,
13566 target_trir: default_trir_target(),
13567 incident_count: default_incident_count(),
13568 }
13569 }
13570}
13571
13572#[derive(Debug, Clone, Serialize, Deserialize)]
13574pub struct GovernanceSchemaConfig {
13575 #[serde(default = "default_true")]
13577 pub enabled: bool,
13578 #[serde(default = "default_board_size")]
13580 pub board_size: u32,
13581 #[serde(default = "default_independence_target")]
13583 pub independence_target: f64,
13584}
13585
13586fn default_board_size() -> u32 {
13587 11
13588}
13589
13590fn default_independence_target() -> f64 {
13591 0.67
13592}
13593
13594impl Default for GovernanceSchemaConfig {
13595 fn default() -> Self {
13596 Self {
13597 enabled: true,
13598 board_size: default_board_size(),
13599 independence_target: default_independence_target(),
13600 }
13601 }
13602}
13603
13604#[derive(Debug, Clone, Serialize, Deserialize)]
13606pub struct SupplyChainEsgConfig {
13607 #[serde(default = "default_true")]
13609 pub enabled: bool,
13610 #[serde(default = "default_assessment_coverage")]
13612 pub assessment_coverage: f64,
13613 #[serde(default = "default_high_risk_countries")]
13615 pub high_risk_countries: Vec<String>,
13616}
13617
13618fn default_assessment_coverage() -> f64 {
13619 0.80
13620}
13621
13622fn default_high_risk_countries() -> Vec<String> {
13623 vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
13624}
13625
13626impl Default for SupplyChainEsgConfig {
13627 fn default() -> Self {
13628 Self {
13629 enabled: true,
13630 assessment_coverage: default_assessment_coverage(),
13631 high_risk_countries: default_high_risk_countries(),
13632 }
13633 }
13634}
13635
13636#[derive(Debug, Clone, Serialize, Deserialize)]
13638pub struct EsgReportingConfig {
13639 #[serde(default = "default_true")]
13641 pub enabled: bool,
13642 #[serde(default = "default_esg_frameworks")]
13644 pub frameworks: Vec<String>,
13645 #[serde(default = "default_true")]
13647 pub materiality_assessment: bool,
13648 #[serde(default = "default_materiality_threshold")]
13650 pub impact_threshold: f64,
13651 #[serde(default = "default_materiality_threshold")]
13653 pub financial_threshold: f64,
13654}
13655
13656fn default_esg_frameworks() -> Vec<String> {
13657 vec!["GRI".to_string(), "ESRS".to_string()]
13658}
13659
13660fn default_materiality_threshold() -> f64 {
13661 0.6
13662}
13663
13664impl Default for EsgReportingConfig {
13665 fn default() -> Self {
13666 Self {
13667 enabled: true,
13668 frameworks: default_esg_frameworks(),
13669 materiality_assessment: true,
13670 impact_threshold: default_materiality_threshold(),
13671 financial_threshold: default_materiality_threshold(),
13672 }
13673 }
13674}
13675
13676#[derive(Debug, Clone, Serialize, Deserialize)]
13678pub struct ClimateScenarioConfig {
13679 #[serde(default)]
13681 pub enabled: bool,
13682 #[serde(default = "default_climate_scenarios")]
13684 pub scenarios: Vec<String>,
13685 #[serde(default = "default_time_horizons")]
13687 pub time_horizons: Vec<u32>,
13688}
13689
13690fn default_climate_scenarios() -> Vec<String> {
13691 vec![
13692 "net_zero_2050".to_string(),
13693 "stated_policies".to_string(),
13694 "current_trajectory".to_string(),
13695 ]
13696}
13697
13698fn default_time_horizons() -> Vec<u32> {
13699 vec![5, 10, 30]
13700}
13701
13702impl Default for ClimateScenarioConfig {
13703 fn default() -> Self {
13704 Self {
13705 enabled: false,
13706 scenarios: default_climate_scenarios(),
13707 time_horizons: default_time_horizons(),
13708 }
13709 }
13710}
13711
13712#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13716pub struct ScenariosConfig {
13717 #[serde(default)]
13719 pub enabled: bool,
13720 #[serde(default)]
13722 pub scenarios: Vec<ScenarioSchemaConfig>,
13723 #[serde(default)]
13725 pub causal_model: CausalModelSchemaConfig,
13726 #[serde(default)]
13728 pub defaults: ScenarioDefaultsConfig,
13729 #[serde(default)]
13732 pub generate_counterfactuals: bool,
13733}
13734
13735#[derive(Debug, Clone, Serialize, Deserialize)]
13737pub struct ScenarioSchemaConfig {
13738 pub name: String,
13740 #[serde(default)]
13742 pub description: String,
13743 #[serde(default)]
13745 pub tags: Vec<String>,
13746 pub base: Option<String>,
13748 pub probability_weight: Option<f64>,
13750 #[serde(default)]
13752 pub interventions: Vec<InterventionSchemaConfig>,
13753 #[serde(default)]
13755 pub constraints: ScenarioConstraintsSchemaConfig,
13756 #[serde(default)]
13758 pub output: ScenarioOutputSchemaConfig,
13759 #[serde(default)]
13761 pub metadata: std::collections::HashMap<String, String>,
13762}
13763
13764#[derive(Debug, Clone, Serialize, Deserialize)]
13766pub struct InterventionSchemaConfig {
13767 #[serde(flatten)]
13769 pub intervention_type: serde_json::Value,
13770 #[serde(default)]
13772 pub timing: InterventionTimingSchemaConfig,
13773 pub label: Option<String>,
13775 #[serde(default)]
13777 pub priority: u32,
13778}
13779
13780#[derive(Debug, Clone, Serialize, Deserialize)]
13782pub struct InterventionTimingSchemaConfig {
13783 #[serde(default = "default_start_month")]
13785 pub start_month: u32,
13786 pub duration_months: Option<u32>,
13788 #[serde(default = "default_onset")]
13790 pub onset: String,
13791 pub ramp_months: Option<u32>,
13793}
13794
13795fn default_start_month() -> u32 {
13796 1
13797}
13798
13799fn default_onset() -> String {
13800 "sudden".to_string()
13801}
13802
13803impl Default for InterventionTimingSchemaConfig {
13804 fn default() -> Self {
13805 Self {
13806 start_month: 1,
13807 duration_months: None,
13808 onset: "sudden".to_string(),
13809 ramp_months: None,
13810 }
13811 }
13812}
13813
13814#[derive(Debug, Clone, Serialize, Deserialize)]
13816pub struct ScenarioConstraintsSchemaConfig {
13817 #[serde(default = "default_true")]
13818 pub preserve_accounting_identity: bool,
13819 #[serde(default = "default_true")]
13820 pub preserve_document_chains: bool,
13821 #[serde(default = "default_true")]
13822 pub preserve_period_close: bool,
13823 #[serde(default = "default_true")]
13824 pub preserve_balance_coherence: bool,
13825 #[serde(default)]
13826 pub custom: Vec<CustomConstraintSchemaConfig>,
13827}
13828
13829impl Default for ScenarioConstraintsSchemaConfig {
13830 fn default() -> Self {
13831 Self {
13832 preserve_accounting_identity: true,
13833 preserve_document_chains: true,
13834 preserve_period_close: true,
13835 preserve_balance_coherence: true,
13836 custom: Vec::new(),
13837 }
13838 }
13839}
13840
13841#[derive(Debug, Clone, Serialize, Deserialize)]
13843pub struct CustomConstraintSchemaConfig {
13844 pub config_path: String,
13845 pub min: Option<f64>,
13846 pub max: Option<f64>,
13847 #[serde(default)]
13848 pub description: String,
13849}
13850
13851#[derive(Debug, Clone, Serialize, Deserialize)]
13853pub struct ScenarioOutputSchemaConfig {
13854 #[serde(default = "default_true")]
13855 pub paired: bool,
13856 #[serde(default = "default_diff_formats_schema")]
13857 pub diff_formats: Vec<String>,
13858 #[serde(default)]
13859 pub diff_scope: Vec<String>,
13860}
13861
13862fn default_diff_formats_schema() -> Vec<String> {
13863 vec!["summary".to_string(), "aggregate".to_string()]
13864}
13865
13866impl Default for ScenarioOutputSchemaConfig {
13867 fn default() -> Self {
13868 Self {
13869 paired: true,
13870 diff_formats: default_diff_formats_schema(),
13871 diff_scope: Vec::new(),
13872 }
13873 }
13874}
13875
13876#[derive(Debug, Clone, Serialize, Deserialize)]
13878pub struct CausalModelSchemaConfig {
13879 #[serde(default = "default_causal_preset")]
13881 pub preset: String,
13882 #[serde(default)]
13884 pub nodes: Vec<serde_json::Value>,
13885 #[serde(default)]
13887 pub edges: Vec<serde_json::Value>,
13888}
13889
13890fn default_causal_preset() -> String {
13891 "default".to_string()
13892}
13893
13894impl Default for CausalModelSchemaConfig {
13895 fn default() -> Self {
13896 Self {
13897 preset: "default".to_string(),
13898 nodes: Vec::new(),
13899 edges: Vec::new(),
13900 }
13901 }
13902}
13903
13904#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13906pub struct ScenarioDefaultsConfig {
13907 #[serde(default)]
13908 pub constraints: ScenarioConstraintsSchemaConfig,
13909 #[serde(default)]
13910 pub output: ScenarioOutputSchemaConfig,
13911}
13912
13913#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13946pub struct ComplianceRegulationsConfig {
13947 #[serde(default)]
13949 pub enabled: bool,
13950 #[serde(default)]
13953 pub jurisdictions: Vec<String>,
13954 #[serde(default)]
13957 pub reference_date: Option<String>,
13958 #[serde(default)]
13960 pub standards_selection: StandardsSelectionConfig,
13961 #[serde(default)]
13963 pub audit_procedures: AuditProcedureGenConfig,
13964 #[serde(default)]
13966 pub findings: ComplianceFindingGenConfig,
13967 #[serde(default)]
13969 pub filings: ComplianceFilingGenConfig,
13970 #[serde(default)]
13972 pub graph: ComplianceGraphConfig,
13973 #[serde(default)]
13975 pub output: ComplianceOutputConfig,
13976 #[serde(default)]
13981 pub legal_documents: LegalDocumentsConfig,
13982}
13983
13984#[derive(Debug, Clone, Serialize, Deserialize)]
13989pub struct LegalDocumentsConfig {
13990 #[serde(default)]
13992 pub enabled: bool,
13993 #[serde(default = "default_legal_opinion_probability")]
13995 pub legal_opinion_probability: f64,
13996}
13997
13998fn default_legal_opinion_probability() -> f64 {
13999 0.40
14000}
14001
14002impl Default for LegalDocumentsConfig {
14003 fn default() -> Self {
14004 Self {
14005 enabled: false,
14006 legal_opinion_probability: default_legal_opinion_probability(),
14007 }
14008 }
14009}
14010
14011#[derive(Debug, Clone, Default, Serialize, Deserialize)]
14013pub struct StandardsSelectionConfig {
14014 #[serde(default)]
14017 pub categories: Vec<String>,
14018 #[serde(default)]
14021 pub include: Vec<String>,
14022 #[serde(default)]
14024 pub exclude: Vec<String>,
14025 #[serde(default)]
14027 pub include_superseded: bool,
14028}
14029
14030#[derive(Debug, Clone, Serialize, Deserialize)]
14032pub struct AuditProcedureGenConfig {
14033 #[serde(default)]
14035 pub enabled: bool,
14036 #[serde(default = "default_procedures_per_standard")]
14038 pub procedures_per_standard: usize,
14039 #[serde(default = "default_sampling_method")]
14041 pub sampling_method: String,
14042 #[serde(default = "default_confidence_level")]
14044 pub confidence_level: f64,
14045 #[serde(default = "default_tolerable_misstatement")]
14047 pub tolerable_misstatement: f64,
14048}
14049
14050fn default_procedures_per_standard() -> usize {
14051 3
14052}
14053
14054fn default_sampling_method() -> String {
14055 "statistical".to_string()
14056}
14057
14058fn default_confidence_level() -> f64 {
14059 0.95
14060}
14061
14062fn default_tolerable_misstatement() -> f64 {
14063 0.05
14064}
14065
14066impl Default for AuditProcedureGenConfig {
14067 fn default() -> Self {
14068 Self {
14069 enabled: false,
14070 procedures_per_standard: default_procedures_per_standard(),
14071 sampling_method: default_sampling_method(),
14072 confidence_level: default_confidence_level(),
14073 tolerable_misstatement: default_tolerable_misstatement(),
14074 }
14075 }
14076}
14077
14078#[derive(Debug, Clone, Serialize, Deserialize)]
14080pub struct ComplianceFindingGenConfig {
14081 #[serde(default)]
14083 pub enabled: bool,
14084 #[serde(default = "default_finding_rate")]
14086 pub finding_rate: f64,
14087 #[serde(default = "default_cr_material_weakness_rate")]
14089 pub material_weakness_rate: f64,
14090 #[serde(default = "default_cr_significant_deficiency_rate")]
14092 pub significant_deficiency_rate: f64,
14093 #[serde(default = "default_true")]
14095 pub generate_remediation: bool,
14096}
14097
14098fn default_finding_rate() -> f64 {
14099 0.05
14100}
14101
14102fn default_cr_material_weakness_rate() -> f64 {
14103 0.02
14104}
14105
14106fn default_cr_significant_deficiency_rate() -> f64 {
14107 0.08
14108}
14109
14110impl Default for ComplianceFindingGenConfig {
14111 fn default() -> Self {
14112 Self {
14113 enabled: false,
14114 finding_rate: default_finding_rate(),
14115 material_weakness_rate: default_cr_material_weakness_rate(),
14116 significant_deficiency_rate: default_cr_significant_deficiency_rate(),
14117 generate_remediation: true,
14118 }
14119 }
14120}
14121
14122#[derive(Debug, Clone, Serialize, Deserialize)]
14124pub struct ComplianceFilingGenConfig {
14125 #[serde(default)]
14127 pub enabled: bool,
14128 #[serde(default)]
14131 pub filing_types: Vec<String>,
14132 #[serde(default = "default_true")]
14134 pub generate_status_progression: bool,
14135}
14136
14137impl Default for ComplianceFilingGenConfig {
14138 fn default() -> Self {
14139 Self {
14140 enabled: false,
14141 filing_types: Vec::new(),
14142 generate_status_progression: true,
14143 }
14144 }
14145}
14146
14147#[derive(Debug, Clone, Serialize, Deserialize)]
14149pub struct ComplianceGraphConfig {
14150 #[serde(default)]
14152 pub enabled: bool,
14153 #[serde(default = "default_true")]
14155 pub include_compliance_nodes: bool,
14156 #[serde(default = "default_true")]
14158 pub include_compliance_edges: bool,
14159 #[serde(default = "default_true")]
14161 pub include_cross_references: bool,
14162 #[serde(default)]
14164 pub include_supersession_edges: bool,
14165 #[serde(default = "default_true")]
14167 pub include_account_links: bool,
14168 #[serde(default = "default_true")]
14170 pub include_control_links: bool,
14171 #[serde(default = "default_true")]
14173 pub include_company_links: bool,
14174}
14175
14176impl Default for ComplianceGraphConfig {
14177 fn default() -> Self {
14178 Self {
14179 enabled: false,
14180 include_compliance_nodes: true,
14181 include_compliance_edges: true,
14182 include_cross_references: true,
14183 include_supersession_edges: false,
14184 include_account_links: true,
14185 include_control_links: true,
14186 include_company_links: true,
14187 }
14188 }
14189}
14190
14191#[derive(Debug, Clone, Serialize, Deserialize)]
14193pub struct ComplianceOutputConfig {
14194 #[serde(default = "default_true")]
14196 pub export_registry: bool,
14197 #[serde(default = "default_true")]
14199 pub export_jurisdictions: bool,
14200 #[serde(default = "default_true")]
14202 pub export_cross_references: bool,
14203 #[serde(default)]
14205 pub export_version_history: bool,
14206}
14207
14208impl Default for ComplianceOutputConfig {
14209 fn default() -> Self {
14210 Self {
14211 export_registry: true,
14212 export_jurisdictions: true,
14213 export_cross_references: true,
14214 export_version_history: false,
14215 }
14216 }
14217}
14218
14219#[cfg(test)]
14220#[allow(clippy::unwrap_used)]
14221mod tests {
14222 use super::*;
14223 use crate::presets::demo_preset;
14224
14225 #[test]
14230 fn test_config_yaml_roundtrip() {
14231 let config = demo_preset();
14232 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
14233 let deserialized: GeneratorConfig =
14234 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
14235
14236 assert_eq!(
14237 config.global.period_months,
14238 deserialized.global.period_months
14239 );
14240 assert_eq!(config.global.industry, deserialized.global.industry);
14241 assert_eq!(config.companies.len(), deserialized.companies.len());
14242 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
14243 }
14244
14245 #[test]
14246 fn test_config_json_roundtrip() {
14247 let mut config = demo_preset();
14249 config.master_data.employees.approval_limits.executive = 1e12;
14251
14252 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
14253 let deserialized: GeneratorConfig =
14254 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
14255
14256 assert_eq!(
14257 config.global.period_months,
14258 deserialized.global.period_months
14259 );
14260 assert_eq!(config.global.industry, deserialized.global.industry);
14261 assert_eq!(config.companies.len(), deserialized.companies.len());
14262 }
14263
14264 #[test]
14265 fn test_transaction_volume_serialization() {
14266 let volumes = vec![
14268 (TransactionVolume::TenK, "ten_k"),
14269 (TransactionVolume::HundredK, "hundred_k"),
14270 (TransactionVolume::OneM, "one_m"),
14271 (TransactionVolume::TenM, "ten_m"),
14272 (TransactionVolume::HundredM, "hundred_m"),
14273 ];
14274
14275 for (volume, expected_key) in volumes {
14276 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14277 assert!(
14278 json.contains(expected_key),
14279 "Expected {} in JSON: {}",
14280 expected_key,
14281 json
14282 );
14283 }
14284 }
14285
14286 #[test]
14287 fn test_transaction_volume_custom_serialization() {
14288 let volume = TransactionVolume::Custom(12345);
14289 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14290 let deserialized: TransactionVolume =
14291 serde_json::from_str(&json).expect("Failed to deserialize");
14292 assert_eq!(deserialized.count(), 12345);
14293 }
14294
14295 #[test]
14296 fn test_output_mode_serialization() {
14297 let modes = vec![
14298 OutputMode::Streaming,
14299 OutputMode::FlatFile,
14300 OutputMode::Both,
14301 ];
14302
14303 for mode in modes {
14304 let json = serde_json::to_string(&mode).expect("Failed to serialize");
14305 let deserialized: OutputMode =
14306 serde_json::from_str(&json).expect("Failed to deserialize");
14307 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
14308 }
14309 }
14310
14311 #[test]
14312 fn test_file_format_serialization() {
14313 let formats = vec![
14314 FileFormat::Csv,
14315 FileFormat::Parquet,
14316 FileFormat::Json,
14317 FileFormat::JsonLines,
14318 ];
14319
14320 for format in formats {
14321 let json = serde_json::to_string(&format).expect("Failed to serialize");
14322 let deserialized: FileFormat =
14323 serde_json::from_str(&json).expect("Failed to deserialize");
14324 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
14325 }
14326 }
14327
14328 #[test]
14329 fn test_compression_algorithm_serialization() {
14330 let algos = vec![
14331 CompressionAlgorithm::Gzip,
14332 CompressionAlgorithm::Zstd,
14333 CompressionAlgorithm::Lz4,
14334 CompressionAlgorithm::Snappy,
14335 ];
14336
14337 for algo in algos {
14338 let json = serde_json::to_string(&algo).expect("Failed to serialize");
14339 let deserialized: CompressionAlgorithm =
14340 serde_json::from_str(&json).expect("Failed to deserialize");
14341 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
14342 }
14343 }
14344
14345 #[test]
14346 fn test_transfer_pricing_method_serialization() {
14347 let methods = vec![
14348 TransferPricingMethod::CostPlus,
14349 TransferPricingMethod::ComparableUncontrolled,
14350 TransferPricingMethod::ResalePrice,
14351 TransferPricingMethod::TransactionalNetMargin,
14352 TransferPricingMethod::ProfitSplit,
14353 ];
14354
14355 for method in methods {
14356 let json = serde_json::to_string(&method).expect("Failed to serialize");
14357 let deserialized: TransferPricingMethod =
14358 serde_json::from_str(&json).expect("Failed to deserialize");
14359 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
14360 }
14361 }
14362
14363 #[test]
14364 fn test_benford_exemption_serialization() {
14365 let exemptions = vec![
14366 BenfordExemption::Recurring,
14367 BenfordExemption::Payroll,
14368 BenfordExemption::FixedFees,
14369 BenfordExemption::RoundAmounts,
14370 ];
14371
14372 for exemption in exemptions {
14373 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
14374 let deserialized: BenfordExemption =
14375 serde_json::from_str(&json).expect("Failed to deserialize");
14376 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
14377 }
14378 }
14379
14380 #[test]
14385 fn test_global_config_defaults() {
14386 let yaml = r#"
14387 industry: manufacturing
14388 start_date: "2024-01-01"
14389 period_months: 6
14390 "#;
14391 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14392 assert_eq!(config.group_currency, "USD");
14393 assert!(config.parallel);
14394 assert_eq!(config.worker_threads, 0);
14395 assert_eq!(config.memory_limit_mb, 0);
14396 }
14397
14398 #[test]
14399 fn test_fraud_config_defaults() {
14400 let config = FraudConfig::default();
14401 assert!(!config.enabled);
14402 assert_eq!(config.fraud_rate, 0.005);
14403 assert!(!config.clustering_enabled);
14404 }
14405
14406 #[test]
14407 fn test_internal_controls_config_defaults() {
14408 let config = InternalControlsConfig::default();
14409 assert!(!config.enabled);
14410 assert_eq!(config.exception_rate, 0.02);
14411 assert_eq!(config.sod_violation_rate, 0.01);
14412 assert!(config.export_control_master_data);
14413 assert_eq!(config.sox_materiality_threshold, 10000.0);
14414 assert!(config.coso_enabled);
14416 assert!(!config.include_entity_level_controls);
14417 assert_eq!(config.target_maturity_level, "mixed");
14418 }
14419
14420 #[test]
14421 fn test_output_config_defaults() {
14422 let config = OutputConfig::default();
14423 assert!(matches!(config.mode, OutputMode::FlatFile));
14424 assert_eq!(config.formats, vec![FileFormat::Parquet]);
14425 assert!(config.compression.enabled);
14426 assert!(matches!(
14427 config.compression.algorithm,
14428 CompressionAlgorithm::Zstd
14429 ));
14430 assert!(config.include_acdoca);
14431 assert!(!config.include_bseg);
14432 assert!(config.partition_by_period);
14433 assert!(!config.partition_by_company);
14434 }
14435
14436 #[test]
14437 fn test_approval_config_defaults() {
14438 let config = ApprovalConfig::default();
14439 assert!(!config.enabled);
14440 assert_eq!(config.auto_approve_threshold, 1000.0);
14441 assert_eq!(config.rejection_rate, 0.02);
14442 assert_eq!(config.revision_rate, 0.05);
14443 assert_eq!(config.average_approval_delay_hours, 4.0);
14444 assert_eq!(config.thresholds.len(), 4);
14445 }
14446
14447 #[test]
14448 fn test_p2p_flow_config_defaults() {
14449 let config = P2PFlowConfig::default();
14450 assert!(config.enabled);
14451 assert_eq!(config.three_way_match_rate, 0.95);
14452 assert_eq!(config.partial_delivery_rate, 0.15);
14453 assert_eq!(config.average_po_to_gr_days, 14);
14454 }
14455
14456 #[test]
14457 fn test_o2c_flow_config_defaults() {
14458 let config = O2CFlowConfig::default();
14459 assert!(config.enabled);
14460 assert_eq!(config.credit_check_failure_rate, 0.02);
14461 assert_eq!(config.return_rate, 0.03);
14462 assert_eq!(config.bad_debt_rate, 0.01);
14463 }
14464
14465 #[test]
14466 fn test_balance_config_defaults() {
14467 let config = BalanceConfig::default();
14468 assert!(!config.generate_opening_balances);
14469 assert!(config.generate_trial_balances);
14470 assert_eq!(config.target_gross_margin, 0.35);
14471 assert!(config.validate_balance_equation);
14472 assert!(config.reconcile_subledgers);
14473 }
14474
14475 #[test]
14480 fn test_partial_config_with_defaults() {
14481 let yaml = r#"
14483 global:
14484 industry: manufacturing
14485 start_date: "2024-01-01"
14486 period_months: 3
14487 companies:
14488 - code: "TEST"
14489 name: "Test Company"
14490 currency: "USD"
14491 country: "US"
14492 annual_transaction_volume: ten_k
14493 chart_of_accounts:
14494 complexity: small
14495 output:
14496 output_directory: "./output"
14497 "#;
14498
14499 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14500 assert_eq!(config.global.period_months, 3);
14501 assert_eq!(config.companies.len(), 1);
14502 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
14505
14506 #[test]
14507 fn test_config_with_fraud_enabled() {
14508 let yaml = r#"
14509 global:
14510 industry: retail
14511 start_date: "2024-01-01"
14512 period_months: 12
14513 companies:
14514 - code: "RETAIL"
14515 name: "Retail Co"
14516 currency: "USD"
14517 country: "US"
14518 annual_transaction_volume: hundred_k
14519 chart_of_accounts:
14520 complexity: medium
14521 output:
14522 output_directory: "./output"
14523 fraud:
14524 enabled: true
14525 fraud_rate: 0.05
14526 clustering_enabled: true
14527 "#;
14528
14529 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14530 assert!(config.fraud.enabled);
14531 assert_eq!(config.fraud.fraud_rate, 0.05);
14532 assert!(config.fraud.clustering_enabled);
14533 }
14534
14535 #[test]
14536 fn test_config_with_multiple_companies() {
14537 let yaml = r#"
14538 global:
14539 industry: manufacturing
14540 start_date: "2024-01-01"
14541 period_months: 6
14542 companies:
14543 - code: "HQ"
14544 name: "Headquarters"
14545 currency: "USD"
14546 country: "US"
14547 annual_transaction_volume: hundred_k
14548 volume_weight: 1.0
14549 - code: "EU"
14550 name: "European Subsidiary"
14551 currency: "EUR"
14552 country: "DE"
14553 annual_transaction_volume: hundred_k
14554 volume_weight: 0.5
14555 - code: "APAC"
14556 name: "Asia Pacific"
14557 currency: "JPY"
14558 country: "JP"
14559 annual_transaction_volume: ten_k
14560 volume_weight: 0.3
14561 chart_of_accounts:
14562 complexity: large
14563 output:
14564 output_directory: "./output"
14565 "#;
14566
14567 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14568 assert_eq!(config.companies.len(), 3);
14569 assert_eq!(config.companies[0].code, "HQ");
14570 assert_eq!(config.companies[1].currency, "EUR");
14571 assert_eq!(config.companies[2].volume_weight, 0.3);
14572 }
14573
14574 #[test]
14575 fn test_intercompany_config() {
14576 let yaml = r#"
14577 enabled: true
14578 ic_transaction_rate: 0.20
14579 transfer_pricing_method: cost_plus
14580 markup_percent: 0.08
14581 generate_matched_pairs: true
14582 generate_eliminations: true
14583 "#;
14584
14585 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14586 assert!(config.enabled);
14587 assert_eq!(config.ic_transaction_rate, 0.20);
14588 assert!(matches!(
14589 config.transfer_pricing_method,
14590 TransferPricingMethod::CostPlus
14591 ));
14592 assert_eq!(config.markup_percent, 0.08);
14593 assert!(config.generate_eliminations);
14594 }
14595
14596 #[test]
14601 fn test_company_config_defaults() {
14602 let yaml = r#"
14603 code: "TEST"
14604 name: "Test Company"
14605 currency: "USD"
14606 country: "US"
14607 annual_transaction_volume: ten_k
14608 "#;
14609
14610 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14611 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
14614
14615 #[test]
14620 fn test_coa_config_defaults() {
14621 let yaml = r#"
14622 complexity: medium
14623 "#;
14624
14625 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14626 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
14628 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
14631
14632 #[test]
14637 fn test_accounting_standards_config_defaults() {
14638 let config = AccountingStandardsConfig::default();
14639 assert!(!config.enabled);
14640 assert!(config.framework.is_none());
14641 assert!(!config.revenue_recognition.enabled);
14642 assert!(!config.leases.enabled);
14643 assert!(!config.fair_value.enabled);
14644 assert!(!config.impairment.enabled);
14645 assert!(!config.generate_differences);
14646 }
14647
14648 #[test]
14649 fn test_accounting_standards_config_yaml() {
14650 let yaml = r#"
14651 enabled: true
14652 framework: ifrs
14653 revenue_recognition:
14654 enabled: true
14655 generate_contracts: true
14656 avg_obligations_per_contract: 2.5
14657 variable_consideration_rate: 0.20
14658 over_time_recognition_rate: 0.35
14659 contract_count: 150
14660 leases:
14661 enabled: true
14662 lease_count: 75
14663 finance_lease_percent: 0.25
14664 avg_lease_term_months: 48
14665 generate_differences: true
14666 "#;
14667
14668 let config: AccountingStandardsConfig =
14669 serde_yaml::from_str(yaml).expect("Failed to parse");
14670 assert!(config.enabled);
14671 assert!(matches!(
14672 config.framework,
14673 Some(AccountingFrameworkConfig::Ifrs)
14674 ));
14675 assert!(config.revenue_recognition.enabled);
14676 assert_eq!(config.revenue_recognition.contract_count, 150);
14677 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
14678 assert!(config.leases.enabled);
14679 assert_eq!(config.leases.lease_count, 75);
14680 assert_eq!(config.leases.finance_lease_percent, 0.25);
14681 assert!(config.generate_differences);
14682 }
14683
14684 #[test]
14685 fn test_accounting_framework_serialization() {
14686 let frameworks = [
14687 AccountingFrameworkConfig::UsGaap,
14688 AccountingFrameworkConfig::Ifrs,
14689 AccountingFrameworkConfig::DualReporting,
14690 AccountingFrameworkConfig::FrenchGaap,
14691 AccountingFrameworkConfig::GermanGaap,
14692 ];
14693
14694 for framework in frameworks {
14695 let json = serde_json::to_string(&framework).expect("Failed to serialize");
14696 let deserialized: AccountingFrameworkConfig =
14697 serde_json::from_str(&json).expect("Failed to deserialize");
14698 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
14699 }
14700 }
14701
14702 #[test]
14703 fn test_revenue_recognition_config_defaults() {
14704 let config = RevenueRecognitionConfig::default();
14705 assert!(!config.enabled);
14706 assert!(config.generate_contracts);
14707 assert_eq!(config.avg_obligations_per_contract, 2.0);
14708 assert_eq!(config.variable_consideration_rate, 0.15);
14709 assert_eq!(config.over_time_recognition_rate, 0.30);
14710 assert_eq!(config.contract_count, 100);
14711 }
14712
14713 #[test]
14714 fn test_lease_accounting_config_defaults() {
14715 let config = LeaseAccountingConfig::default();
14716 assert!(!config.enabled);
14717 assert_eq!(config.lease_count, 50);
14718 assert_eq!(config.finance_lease_percent, 0.30);
14719 assert_eq!(config.avg_lease_term_months, 60);
14720 assert!(config.generate_amortization);
14721 assert_eq!(config.real_estate_percent, 0.40);
14722 }
14723
14724 #[test]
14725 fn test_fair_value_config_defaults() {
14726 let config = FairValueConfig::default();
14727 assert!(!config.enabled);
14728 assert_eq!(config.measurement_count, 25);
14729 assert_eq!(config.level1_percent, 0.40);
14730 assert_eq!(config.level2_percent, 0.35);
14731 assert_eq!(config.level3_percent, 0.25);
14732 assert!(!config.include_sensitivity_analysis);
14733 }
14734
14735 #[test]
14736 fn test_impairment_config_defaults() {
14737 let config = ImpairmentConfig::default();
14738 assert!(!config.enabled);
14739 assert_eq!(config.test_count, 15);
14740 assert_eq!(config.impairment_rate, 0.10);
14741 assert!(config.generate_projections);
14742 assert!(!config.include_goodwill);
14743 }
14744
14745 #[test]
14750 fn test_audit_standards_config_defaults() {
14751 let config = AuditStandardsConfig::default();
14752 assert!(!config.enabled);
14753 assert!(!config.isa_compliance.enabled);
14754 assert!(!config.analytical_procedures.enabled);
14755 assert!(!config.confirmations.enabled);
14756 assert!(!config.opinion.enabled);
14757 assert!(!config.generate_audit_trail);
14758 assert!(!config.sox.enabled);
14759 assert!(!config.pcaob.enabled);
14760 }
14761
14762 #[test]
14763 fn test_audit_standards_config_yaml() {
14764 let yaml = r#"
14765 enabled: true
14766 isa_compliance:
14767 enabled: true
14768 compliance_level: comprehensive
14769 generate_isa_mappings: true
14770 include_pcaob: true
14771 framework: dual
14772 analytical_procedures:
14773 enabled: true
14774 procedures_per_account: 5
14775 variance_probability: 0.25
14776 confirmations:
14777 enabled: true
14778 confirmation_count: 75
14779 positive_response_rate: 0.90
14780 exception_rate: 0.08
14781 opinion:
14782 enabled: true
14783 generate_kam: true
14784 average_kam_count: 4
14785 sox:
14786 enabled: true
14787 generate_302_certifications: true
14788 generate_404_assessments: true
14789 material_weakness_rate: 0.03
14790 pcaob:
14791 enabled: true
14792 is_pcaob_audit: true
14793 include_icfr_opinion: true
14794 generate_audit_trail: true
14795 "#;
14796
14797 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14798 assert!(config.enabled);
14799 assert!(config.isa_compliance.enabled);
14800 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
14801 assert!(config.isa_compliance.include_pcaob);
14802 assert_eq!(config.isa_compliance.framework, "dual");
14803 assert!(config.analytical_procedures.enabled);
14804 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
14805 assert!(config.confirmations.enabled);
14806 assert_eq!(config.confirmations.confirmation_count, 75);
14807 assert!(config.opinion.enabled);
14808 assert_eq!(config.opinion.average_kam_count, 4);
14809 assert!(config.sox.enabled);
14810 assert!(config.sox.generate_302_certifications);
14811 assert_eq!(config.sox.material_weakness_rate, 0.03);
14812 assert!(config.pcaob.enabled);
14813 assert!(config.pcaob.is_pcaob_audit);
14814 assert!(config.pcaob.include_icfr_opinion);
14815 assert!(config.generate_audit_trail);
14816 }
14817
14818 #[test]
14819 fn test_isa_compliance_config_defaults() {
14820 let config = IsaComplianceConfig::default();
14821 assert!(!config.enabled);
14822 assert_eq!(config.compliance_level, "standard");
14823 assert!(config.generate_isa_mappings);
14824 assert!(config.generate_coverage_summary);
14825 assert!(!config.include_pcaob);
14826 assert_eq!(config.framework, "isa");
14827 }
14828
14829 #[test]
14830 fn test_sox_compliance_config_defaults() {
14831 let config = SoxComplianceConfig::default();
14832 assert!(!config.enabled);
14833 assert!(config.generate_302_certifications);
14834 assert!(config.generate_404_assessments);
14835 assert_eq!(config.materiality_threshold, 10000.0);
14836 assert_eq!(config.material_weakness_rate, 0.02);
14837 assert_eq!(config.significant_deficiency_rate, 0.08);
14838 }
14839
14840 #[test]
14841 fn test_pcaob_config_defaults() {
14842 let config = PcaobConfig::default();
14843 assert!(!config.enabled);
14844 assert!(!config.is_pcaob_audit);
14845 assert!(config.generate_cam);
14846 assert!(!config.include_icfr_opinion);
14847 assert!(!config.generate_standard_mappings);
14848 }
14849
14850 #[test]
14851 fn test_config_with_standards_enabled() {
14852 let yaml = r#"
14853 global:
14854 industry: financial_services
14855 start_date: "2024-01-01"
14856 period_months: 12
14857 companies:
14858 - code: "BANK"
14859 name: "Test Bank"
14860 currency: "USD"
14861 country: "US"
14862 annual_transaction_volume: hundred_k
14863 chart_of_accounts:
14864 complexity: large
14865 output:
14866 output_directory: "./output"
14867 accounting_standards:
14868 enabled: true
14869 framework: us_gaap
14870 revenue_recognition:
14871 enabled: true
14872 leases:
14873 enabled: true
14874 audit_standards:
14875 enabled: true
14876 isa_compliance:
14877 enabled: true
14878 sox:
14879 enabled: true
14880 "#;
14881
14882 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14883 assert!(config.accounting_standards.enabled);
14884 assert!(matches!(
14885 config.accounting_standards.framework,
14886 Some(AccountingFrameworkConfig::UsGaap)
14887 ));
14888 assert!(config.accounting_standards.revenue_recognition.enabled);
14889 assert!(config.accounting_standards.leases.enabled);
14890 assert!(config.audit_standards.enabled);
14891 assert!(config.audit_standards.isa_compliance.enabled);
14892 assert!(config.audit_standards.sox.enabled);
14893 }
14894
14895 #[test]
14900 fn test_industry_specific_config_defaults() {
14901 let config = IndustrySpecificConfig::default();
14902 assert!(!config.enabled);
14903 assert!(!config.manufacturing.enabled);
14904 assert!(!config.retail.enabled);
14905 assert!(!config.healthcare.enabled);
14906 assert!(!config.technology.enabled);
14907 assert!(!config.financial_services.enabled);
14908 assert!(!config.professional_services.enabled);
14909 }
14910
14911 #[test]
14912 fn test_manufacturing_config_defaults() {
14913 let config = ManufacturingConfig::default();
14914 assert!(!config.enabled);
14915 assert_eq!(config.bom_depth, 4);
14916 assert!(!config.just_in_time);
14917 assert_eq!(config.supplier_tiers, 2);
14918 assert_eq!(config.target_yield_rate, 0.97);
14919 assert_eq!(config.scrap_alert_threshold, 0.03);
14920 }
14921
14922 #[test]
14923 fn test_retail_config_defaults() {
14924 let config = RetailConfig::default();
14925 assert!(!config.enabled);
14926 assert_eq!(config.avg_daily_transactions, 500);
14927 assert!(config.loss_prevention);
14928 assert_eq!(config.shrinkage_rate, 0.015);
14929 }
14930
14931 #[test]
14932 fn test_healthcare_config_defaults() {
14933 let config = HealthcareConfig::default();
14934 assert!(!config.enabled);
14935 assert_eq!(config.facility_type, "hospital");
14936 assert_eq!(config.avg_daily_encounters, 150);
14937 assert!(config.compliance.hipaa);
14938 assert!(config.compliance.stark_law);
14939 assert!(config.coding_systems.icd10);
14940 assert!(config.coding_systems.cpt);
14941 }
14942
14943 #[test]
14944 fn test_technology_config_defaults() {
14945 let config = TechnologyConfig::default();
14946 assert!(!config.enabled);
14947 assert_eq!(config.revenue_model, "saas");
14948 assert_eq!(config.subscription_revenue_pct, 0.60);
14949 assert!(config.rd_capitalization.enabled);
14950 }
14951
14952 #[test]
14953 fn test_config_with_industry_specific() {
14954 let yaml = r#"
14955 global:
14956 industry: healthcare
14957 start_date: "2024-01-01"
14958 period_months: 12
14959 companies:
14960 - code: "HOSP"
14961 name: "Test Hospital"
14962 currency: "USD"
14963 country: "US"
14964 annual_transaction_volume: hundred_k
14965 chart_of_accounts:
14966 complexity: medium
14967 output:
14968 output_directory: "./output"
14969 industry_specific:
14970 enabled: true
14971 healthcare:
14972 enabled: true
14973 facility_type: hospital
14974 payer_mix:
14975 medicare: 0.45
14976 medicaid: 0.15
14977 commercial: 0.35
14978 self_pay: 0.05
14979 coding_systems:
14980 icd10: true
14981 cpt: true
14982 drg: true
14983 compliance:
14984 hipaa: true
14985 stark_law: true
14986 anomaly_rates:
14987 upcoding: 0.03
14988 unbundling: 0.02
14989 "#;
14990
14991 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14992 assert!(config.industry_specific.enabled);
14993 assert!(config.industry_specific.healthcare.enabled);
14994 assert_eq!(
14995 config.industry_specific.healthcare.facility_type,
14996 "hospital"
14997 );
14998 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14999 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
15000 assert!(config.industry_specific.healthcare.coding_systems.icd10);
15001 assert!(config.industry_specific.healthcare.compliance.hipaa);
15002 assert_eq!(
15003 config.industry_specific.healthcare.anomaly_rates.upcoding,
15004 0.03
15005 );
15006 }
15007
15008 #[test]
15009 fn test_config_with_manufacturing_specific() {
15010 let yaml = r#"
15011 global:
15012 industry: manufacturing
15013 start_date: "2024-01-01"
15014 period_months: 12
15015 companies:
15016 - code: "MFG"
15017 name: "Test Manufacturing"
15018 currency: "USD"
15019 country: "US"
15020 annual_transaction_volume: hundred_k
15021 chart_of_accounts:
15022 complexity: medium
15023 output:
15024 output_directory: "./output"
15025 industry_specific:
15026 enabled: true
15027 manufacturing:
15028 enabled: true
15029 bom_depth: 5
15030 just_in_time: true
15031 supplier_tiers: 3
15032 target_yield_rate: 0.98
15033 anomaly_rates:
15034 yield_manipulation: 0.02
15035 phantom_production: 0.01
15036 "#;
15037
15038 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
15039 assert!(config.industry_specific.enabled);
15040 assert!(config.industry_specific.manufacturing.enabled);
15041 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
15042 assert!(config.industry_specific.manufacturing.just_in_time);
15043 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
15044 assert_eq!(
15045 config.industry_specific.manufacturing.target_yield_rate,
15046 0.98
15047 );
15048 assert_eq!(
15049 config
15050 .industry_specific
15051 .manufacturing
15052 .anomaly_rates
15053 .yield_manipulation,
15054 0.02
15055 );
15056 }
15057
15058 #[test]
15063 fn test_tax_config_defaults() {
15064 let tax = TaxConfig::default();
15065 assert!(!tax.enabled);
15066 assert!(tax.jurisdictions.countries.is_empty());
15067 assert!(!tax.jurisdictions.include_subnational);
15068 assert!(!tax.vat_gst.enabled);
15069 assert!(tax.vat_gst.standard_rates.is_empty());
15070 assert!(tax.vat_gst.reduced_rates.is_empty());
15071 assert!(tax.vat_gst.exempt_categories.is_empty());
15072 assert!(tax.vat_gst.reverse_charge);
15073 assert!(!tax.sales_tax.enabled);
15074 assert!(tax.sales_tax.nexus_states.is_empty());
15075 assert!(!tax.withholding.enabled);
15076 assert!(tax.withholding.treaty_network);
15077 assert_eq!(tax.withholding.default_rate, 0.30);
15078 assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
15079 assert!(tax.provisions.enabled);
15080 assert_eq!(tax.provisions.statutory_rate, 0.21);
15081 assert!(tax.provisions.uncertain_positions);
15082 assert!(!tax.payroll_tax.enabled);
15083 assert_eq!(tax.anomaly_rate, 0.03);
15084 }
15085
15086 #[test]
15087 fn test_tax_config_from_yaml() {
15088 let yaml = r#"
15089 global:
15090 seed: 42
15091 start_date: "2024-01-01"
15092 period_months: 12
15093 industry: retail
15094 companies:
15095 - code: C001
15096 name: Test Corp
15097 currency: USD
15098 country: US
15099 annual_transaction_volume: ten_k
15100 chart_of_accounts:
15101 complexity: small
15102 output:
15103 output_directory: ./output
15104 tax:
15105 enabled: true
15106 anomaly_rate: 0.05
15107 jurisdictions:
15108 countries: ["US", "DE", "GB"]
15109 include_subnational: true
15110 vat_gst:
15111 enabled: true
15112 standard_rates:
15113 DE: 0.19
15114 GB: 0.20
15115 reduced_rates:
15116 DE: 0.07
15117 GB: 0.05
15118 exempt_categories:
15119 - financial_services
15120 - healthcare
15121 reverse_charge: false
15122 sales_tax:
15123 enabled: true
15124 nexus_states: ["CA", "NY", "TX"]
15125 withholding:
15126 enabled: true
15127 treaty_network: false
15128 default_rate: 0.25
15129 treaty_reduced_rate: 0.10
15130 provisions:
15131 enabled: false
15132 statutory_rate: 0.28
15133 uncertain_positions: false
15134 payroll_tax:
15135 enabled: true
15136 "#;
15137
15138 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
15139 assert!(config.tax.enabled);
15140 assert_eq!(config.tax.anomaly_rate, 0.05);
15141
15142 assert_eq!(config.tax.jurisdictions.countries.len(), 3);
15144 assert!(config
15145 .tax
15146 .jurisdictions
15147 .countries
15148 .contains(&"DE".to_string()));
15149 assert!(config.tax.jurisdictions.include_subnational);
15150
15151 assert!(config.tax.vat_gst.enabled);
15153 assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
15154 assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
15155 assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
15156 assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
15157 assert!(!config.tax.vat_gst.reverse_charge);
15158
15159 assert!(config.tax.sales_tax.enabled);
15161 assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
15162 assert!(config
15163 .tax
15164 .sales_tax
15165 .nexus_states
15166 .contains(&"CA".to_string()));
15167
15168 assert!(config.tax.withholding.enabled);
15170 assert!(!config.tax.withholding.treaty_network);
15171 assert_eq!(config.tax.withholding.default_rate, 0.25);
15172 assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
15173
15174 assert!(!config.tax.provisions.enabled);
15176 assert_eq!(config.tax.provisions.statutory_rate, 0.28);
15177 assert!(!config.tax.provisions.uncertain_positions);
15178
15179 assert!(config.tax.payroll_tax.enabled);
15181 }
15182
15183 #[test]
15184 fn test_generator_config_with_tax_default() {
15185 let yaml = r#"
15186 global:
15187 seed: 42
15188 start_date: "2024-01-01"
15189 period_months: 12
15190 industry: retail
15191 companies:
15192 - code: C001
15193 name: Test Corp
15194 currency: USD
15195 country: US
15196 annual_transaction_volume: ten_k
15197 chart_of_accounts:
15198 complexity: small
15199 output:
15200 output_directory: ./output
15201 "#;
15202
15203 let config: GeneratorConfig =
15204 serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
15205 assert!(!config.tax.enabled);
15207 assert!(config.tax.jurisdictions.countries.is_empty());
15208 assert_eq!(config.tax.anomaly_rate, 0.03);
15209 assert!(config.tax.provisions.enabled); assert_eq!(config.tax.provisions.statutory_rate, 0.21);
15211 }
15212
15213 #[test]
15218 fn test_session_config_default_disabled() {
15219 let yaml = "{}";
15220 let config: SessionSchemaConfig =
15221 serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
15222 assert!(!config.enabled);
15223 assert!(config.checkpoint_path.is_none());
15224 assert!(config.per_period_output);
15225 assert!(config.consolidated_output);
15226 }
15227
15228 #[test]
15229 fn test_config_backward_compatible_without_session() {
15230 let yaml = r#"
15231 global:
15232 seed: 42
15233 start_date: "2024-01-01"
15234 period_months: 12
15235 industry: retail
15236 companies:
15237 - code: C001
15238 name: Test Corp
15239 currency: USD
15240 country: US
15241 annual_transaction_volume: ten_k
15242 chart_of_accounts:
15243 complexity: small
15244 output:
15245 output_directory: ./output
15246 "#;
15247
15248 let config: GeneratorConfig =
15249 serde_yaml::from_str(yaml).expect("Failed to parse config without session");
15250 assert!(!config.session.enabled);
15252 assert!(config.session.per_period_output);
15253 assert!(config.session.consolidated_output);
15254 assert!(config.global.fiscal_year_months.is_none());
15256 }
15257
15258 #[test]
15259 fn test_fiscal_year_months_parsed() {
15260 let yaml = r#"
15261 global:
15262 seed: 42
15263 start_date: "2024-01-01"
15264 period_months: 24
15265 industry: retail
15266 fiscal_year_months: 12
15267 companies:
15268 - code: C001
15269 name: Test Corp
15270 currency: USD
15271 country: US
15272 annual_transaction_volume: ten_k
15273 chart_of_accounts:
15274 complexity: small
15275 output:
15276 output_directory: ./output
15277 session:
15278 enabled: true
15279 checkpoint_path: /tmp/checkpoints
15280 per_period_output: true
15281 consolidated_output: false
15282 "#;
15283
15284 let config: GeneratorConfig =
15285 serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
15286 assert_eq!(config.global.fiscal_year_months, Some(12));
15287 assert!(config.session.enabled);
15288 assert_eq!(
15289 config.session.checkpoint_path,
15290 Some("/tmp/checkpoints".to_string())
15291 );
15292 assert!(config.session.per_period_output);
15293 assert!(!config.session.consolidated_output);
15294 }
15295}