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 HundredK,
1506 OneM,
1508 TenM,
1510 HundredM,
1512 Custom(u64),
1514}
1515
1516impl TransactionVolume {
1517 pub fn count(&self) -> u64 {
1519 match self {
1520 Self::TenK => 10_000,
1521 Self::HundredK => 100_000,
1522 Self::OneM => 1_000_000,
1523 Self::TenM => 10_000_000,
1524 Self::HundredM => 100_000_000,
1525 Self::Custom(n) => *n,
1526 }
1527 }
1528}
1529
1530#[derive(Debug, Clone, Serialize, Deserialize)]
1532pub struct ChartOfAccountsConfig {
1533 pub complexity: CoAComplexity,
1535 #[serde(default = "default_true")]
1537 pub industry_specific: bool,
1538 pub custom_accounts: Option<PathBuf>,
1540 #[serde(default = "default_min_depth")]
1542 pub min_hierarchy_depth: u8,
1543 #[serde(default = "default_max_depth")]
1545 pub max_hierarchy_depth: u8,
1546}
1547
1548fn default_min_depth() -> u8 {
1549 2
1550}
1551fn default_max_depth() -> u8 {
1552 5
1553}
1554
1555impl Default for ChartOfAccountsConfig {
1556 fn default() -> Self {
1557 Self {
1558 complexity: CoAComplexity::Small,
1559 industry_specific: true,
1560 custom_accounts: None,
1561 min_hierarchy_depth: default_min_depth(),
1562 max_hierarchy_depth: default_max_depth(),
1563 }
1564 }
1565}
1566
1567#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1569pub struct TransactionConfig {
1570 #[serde(default)]
1572 pub line_item_distribution: LineItemDistributionConfig,
1573 #[serde(default)]
1575 pub debit_credit_distribution: DebitCreditDistributionConfig,
1576 #[serde(default)]
1578 pub even_odd_distribution: EvenOddDistributionConfig,
1579 #[serde(default)]
1581 pub source_distribution: SourceDistribution,
1582 #[serde(default)]
1584 pub seasonality: SeasonalityConfig,
1585 #[serde(default)]
1587 pub amounts: AmountDistributionConfig,
1588 #[serde(default)]
1590 pub benford: BenfordConfig,
1591}
1592
1593#[derive(Debug, Clone, Serialize, Deserialize)]
1595pub struct BenfordConfig {
1596 #[serde(default = "default_true")]
1598 pub enabled: bool,
1599 #[serde(default = "default_benford_tolerance")]
1601 pub tolerance: f64,
1602 #[serde(default)]
1604 pub exempt_sources: Vec<BenfordExemption>,
1605}
1606
1607fn default_benford_tolerance() -> f64 {
1608 0.05
1609}
1610
1611impl Default for BenfordConfig {
1612 fn default() -> Self {
1613 Self {
1614 enabled: true,
1615 tolerance: default_benford_tolerance(),
1616 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1617 }
1618 }
1619}
1620
1621#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1623#[serde(rename_all = "snake_case")]
1624pub enum BenfordExemption {
1625 Recurring,
1627 Payroll,
1629 FixedFees,
1631 RoundAmounts,
1633}
1634
1635#[derive(Debug, Clone, Serialize, Deserialize)]
1637pub struct SourceDistribution {
1638 pub manual: f64,
1640 pub automated: f64,
1642 pub recurring: f64,
1644 pub adjustment: f64,
1646}
1647
1648impl Default for SourceDistribution {
1649 fn default() -> Self {
1650 Self {
1651 manual: 0.20,
1652 automated: 0.70,
1653 recurring: 0.07,
1654 adjustment: 0.03,
1655 }
1656 }
1657}
1658
1659#[derive(Debug, Clone, Serialize, Deserialize)]
1661pub struct OutputConfig {
1662 #[serde(default)]
1664 pub mode: OutputMode,
1665 #[serde(alias = "outputDirectory")]
1667 pub output_directory: PathBuf,
1668 #[serde(
1676 default = "default_formats",
1677 alias = "exportFormats",
1678 alias = "exportFormat",
1679 deserialize_with = "one_or_many_formats"
1680 )]
1681 pub formats: Vec<FileFormat>,
1682 #[serde(default)]
1684 pub compression: CompressionConfig,
1685 #[serde(default = "default_batch_size", alias = "batchSize")]
1687 pub batch_size: usize,
1688 #[serde(default = "default_true", alias = "includeAcdoca")]
1690 pub include_acdoca: bool,
1691 #[serde(default, alias = "includeBseg")]
1693 pub include_bseg: bool,
1694 #[serde(default = "default_true", alias = "partitionByPeriod")]
1696 pub partition_by_period: bool,
1697 #[serde(default, alias = "partitionByCompany")]
1699 pub partition_by_company: bool,
1700 #[serde(default, alias = "numericMode")]
1704 pub numeric_mode: NumericMode,
1705 #[serde(default, alias = "exportLayout")]
1717 pub export_layout: ExportLayout,
1718 #[serde(default, alias = "sapExport")]
1723 pub sap: SapExportSettings,
1724 #[serde(default, alias = "saftExport")]
1730 pub saft: SaftExportSettings,
1731}
1732
1733#[derive(Debug, Clone, Serialize, Deserialize)]
1740pub struct SapExportSettings {
1741 #[serde(default = "default_sap_client")]
1743 pub client: String,
1744 #[serde(default = "default_sap_ledger")]
1746 pub ledger: String,
1747 #[serde(default = "default_sap_source_system")]
1750 pub source_system: String,
1751 #[serde(default = "default_sap_currency")]
1753 pub local_currency: String,
1754 #[serde(default, skip_serializing_if = "Option::is_none")]
1756 pub group_currency: Option<String>,
1757 #[serde(default)]
1759 pub tables: Vec<String>,
1760 #[serde(default = "default_true")]
1762 pub include_extension_fields: bool,
1763 #[serde(default)]
1765 pub dialect: SapDialectSetting,
1766 #[serde(default = "default_true")]
1769 pub use_sap_date_format: bool,
1770}
1771
1772impl Default for SapExportSettings {
1773 fn default() -> Self {
1774 Self {
1775 client: default_sap_client(),
1776 ledger: default_sap_ledger(),
1777 source_system: default_sap_source_system(),
1778 local_currency: default_sap_currency(),
1779 group_currency: None,
1780 tables: Vec::new(),
1781 include_extension_fields: true,
1782 dialect: SapDialectSetting::default(),
1783 use_sap_date_format: true,
1784 }
1785 }
1786}
1787
1788fn default_sap_client() -> String {
1789 "100".to_string()
1790}
1791fn default_sap_ledger() -> String {
1792 "0L".to_string()
1793}
1794fn default_sap_source_system() -> String {
1795 "SYNTH".to_string()
1796}
1797fn default_sap_currency() -> String {
1798 "USD".to_string()
1799}
1800
1801#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
1804#[serde(rename_all = "snake_case")]
1805pub enum SapDialectSetting {
1806 #[default]
1808 Classic,
1809 Hana,
1811}
1812
1813#[derive(Debug, Clone, Serialize, Deserialize)]
1815pub struct SaftExportSettings {
1816 #[serde(default = "default_saft_jurisdiction")]
1819 pub jurisdiction: String,
1820 #[serde(default)]
1824 pub company_tax_id: String,
1825 #[serde(default)]
1828 pub company_name: String,
1829}
1830
1831impl Default for SaftExportSettings {
1832 fn default() -> Self {
1833 Self {
1834 jurisdiction: default_saft_jurisdiction(),
1835 company_tax_id: String::new(),
1836 company_name: String::new(),
1837 }
1838 }
1839}
1840
1841fn default_saft_jurisdiction() -> String {
1842 "pt".to_string()
1843}
1844
1845fn default_formats() -> Vec<FileFormat> {
1846 vec![FileFormat::Parquet]
1847}
1848fn default_batch_size() -> usize {
1849 100_000
1850}
1851
1852fn one_or_many_formats<'de, D>(deserializer: D) -> Result<Vec<FileFormat>, D::Error>
1858where
1859 D: serde::Deserializer<'de>,
1860{
1861 #[derive(Deserialize)]
1862 #[serde(untagged)]
1863 enum OneOrMany {
1864 One(FileFormat),
1865 Many(Vec<FileFormat>),
1866 }
1867 match OneOrMany::deserialize(deserializer)? {
1868 OneOrMany::One(f) => Ok(vec![f]),
1869 OneOrMany::Many(v) => Ok(v),
1870 }
1871}
1872
1873impl Default for OutputConfig {
1874 fn default() -> Self {
1875 Self {
1876 mode: OutputMode::FlatFile,
1877 output_directory: PathBuf::from("./output"),
1878 formats: default_formats(),
1879 compression: CompressionConfig::default(),
1880 batch_size: default_batch_size(),
1881 include_acdoca: true,
1882 include_bseg: false,
1883 partition_by_period: true,
1884 partition_by_company: false,
1885 numeric_mode: NumericMode::default(),
1886 export_layout: ExportLayout::default(),
1887 sap: SapExportSettings::default(),
1888 saft: SaftExportSettings::default(),
1889 }
1890 }
1891}
1892
1893#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1895#[serde(rename_all = "snake_case")]
1896pub enum NumericMode {
1897 #[default]
1899 String,
1900 Native,
1902}
1903
1904#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
1906#[serde(rename_all = "snake_case")]
1907pub enum ExportLayout {
1908 #[default]
1910 Nested,
1911 Flat,
1913}
1914
1915#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1917#[serde(rename_all = "snake_case")]
1918pub enum OutputMode {
1919 Streaming,
1921 #[default]
1923 FlatFile,
1924 Both,
1926}
1927
1928#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1930#[serde(rename_all = "snake_case")]
1931pub enum FileFormat {
1932 Csv,
1933 Parquet,
1934 Json,
1935 JsonLines,
1936}
1937
1938#[derive(Debug, Clone, Serialize, Deserialize)]
1940pub struct CompressionConfig {
1941 #[serde(default = "default_true")]
1943 pub enabled: bool,
1944 #[serde(default)]
1946 pub algorithm: CompressionAlgorithm,
1947 #[serde(default = "default_compression_level")]
1949 pub level: u8,
1950}
1951
1952fn default_compression_level() -> u8 {
1953 3
1954}
1955
1956impl Default for CompressionConfig {
1957 fn default() -> Self {
1958 Self {
1959 enabled: true,
1960 algorithm: CompressionAlgorithm::default(),
1961 level: default_compression_level(),
1962 }
1963 }
1964}
1965
1966#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1968#[serde(rename_all = "snake_case")]
1969pub enum CompressionAlgorithm {
1970 Gzip,
1971 #[default]
1972 Zstd,
1973 Lz4,
1974 Snappy,
1975}
1976
1977#[derive(Debug, Clone, Serialize, Deserialize)]
1997pub struct FraudConfig {
1998 #[serde(default)]
2000 pub enabled: bool,
2001 #[serde(default = "default_fraud_rate", alias = "fraudRate")]
2019 pub fraud_rate: f64,
2020 #[serde(default = "default_document_fraud_rate", alias = "documentFraudRate")]
2033 pub document_fraud_rate: Option<f64>,
2034 #[serde(default = "default_true", alias = "propagateToLines")]
2039 pub propagate_to_lines: bool,
2040 #[serde(default = "default_true", alias = "propagateToDocument")]
2044 pub propagate_to_document: bool,
2045 #[serde(default)]
2047 pub fraud_type_distribution: FraudTypeDistribution,
2048 #[serde(default)]
2050 pub clustering_enabled: bool,
2051 #[serde(default = "default_clustering_factor")]
2053 pub clustering_factor: f64,
2054 #[serde(default = "default_approval_thresholds")]
2056 pub approval_thresholds: Vec<f64>,
2057}
2058
2059fn default_approval_thresholds() -> Vec<f64> {
2060 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
2061}
2062
2063fn default_fraud_rate() -> f64 {
2064 0.005
2065}
2066fn default_document_fraud_rate() -> Option<f64> {
2067 Some(0.01)
2068}
2069fn default_clustering_factor() -> f64 {
2070 3.0
2071}
2072
2073impl Default for FraudConfig {
2074 fn default() -> Self {
2075 Self {
2076 enabled: false,
2077 fraud_rate: default_fraud_rate(),
2078 document_fraud_rate: default_document_fraud_rate(),
2079 propagate_to_lines: true,
2080 propagate_to_document: true,
2081 fraud_type_distribution: FraudTypeDistribution::default(),
2082 clustering_enabled: false,
2083 clustering_factor: default_clustering_factor(),
2084 approval_thresholds: default_approval_thresholds(),
2085 }
2086 }
2087}
2088
2089#[derive(Debug, Clone, Serialize, Deserialize)]
2091pub struct FraudTypeDistribution {
2092 pub suspense_account_abuse: f64,
2093 pub fictitious_transaction: f64,
2094 pub revenue_manipulation: f64,
2095 pub expense_capitalization: f64,
2096 pub split_transaction: f64,
2097 pub timing_anomaly: f64,
2098 pub unauthorized_access: f64,
2099 pub duplicate_payment: f64,
2100}
2101
2102impl Default for FraudTypeDistribution {
2103 fn default() -> Self {
2104 Self {
2105 suspense_account_abuse: 0.25,
2106 fictitious_transaction: 0.15,
2107 revenue_manipulation: 0.10,
2108 expense_capitalization: 0.10,
2109 split_transaction: 0.15,
2110 timing_anomaly: 0.10,
2111 unauthorized_access: 0.10,
2112 duplicate_payment: 0.05,
2113 }
2114 }
2115}
2116
2117#[derive(Debug, Clone, Serialize, Deserialize)]
2119pub struct InternalControlsConfig {
2120 #[serde(default)]
2122 pub enabled: bool,
2123 #[serde(default = "default_exception_rate")]
2125 pub exception_rate: f64,
2126 #[serde(default = "default_sod_violation_rate")]
2128 pub sod_violation_rate: f64,
2129 #[serde(default = "default_true")]
2131 pub export_control_master_data: bool,
2132 #[serde(default = "default_sox_materiality_threshold")]
2134 pub sox_materiality_threshold: f64,
2135 #[serde(default = "default_true")]
2137 pub coso_enabled: bool,
2138 #[serde(default)]
2140 pub include_entity_level_controls: bool,
2141 #[serde(default = "default_target_maturity_level")]
2144 pub target_maturity_level: String,
2145}
2146
2147fn default_exception_rate() -> f64 {
2148 0.02
2149}
2150
2151fn default_sod_violation_rate() -> f64 {
2152 0.01
2153}
2154
2155fn default_sox_materiality_threshold() -> f64 {
2156 10000.0
2157}
2158
2159fn default_target_maturity_level() -> String {
2160 "mixed".to_string()
2161}
2162
2163impl Default for InternalControlsConfig {
2164 fn default() -> Self {
2165 Self {
2166 enabled: false,
2167 exception_rate: default_exception_rate(),
2168 sod_violation_rate: default_sod_violation_rate(),
2169 export_control_master_data: true,
2170 sox_materiality_threshold: default_sox_materiality_threshold(),
2171 coso_enabled: true,
2172 include_entity_level_controls: false,
2173 target_maturity_level: default_target_maturity_level(),
2174 }
2175 }
2176}
2177
2178#[derive(Debug, Clone, Serialize, Deserialize)]
2180pub struct BusinessProcessConfig {
2181 #[serde(default = "default_o2c")]
2183 pub o2c_weight: f64,
2184 #[serde(default = "default_p2p")]
2186 pub p2p_weight: f64,
2187 #[serde(default = "default_r2r")]
2189 pub r2r_weight: f64,
2190 #[serde(default = "default_h2r")]
2192 pub h2r_weight: f64,
2193 #[serde(default = "default_a2r")]
2195 pub a2r_weight: f64,
2196}
2197
2198fn default_o2c() -> f64 {
2199 0.35
2200}
2201fn default_p2p() -> f64 {
2202 0.30
2203}
2204fn default_r2r() -> f64 {
2205 0.20
2206}
2207fn default_h2r() -> f64 {
2208 0.10
2209}
2210fn default_a2r() -> f64 {
2211 0.05
2212}
2213
2214impl Default for BusinessProcessConfig {
2215 fn default() -> Self {
2216 Self {
2217 o2c_weight: default_o2c(),
2218 p2p_weight: default_p2p(),
2219 r2r_weight: default_r2r(),
2220 h2r_weight: default_h2r(),
2221 a2r_weight: default_a2r(),
2222 }
2223 }
2224}
2225
2226#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2228pub struct UserPersonaConfig {
2229 #[serde(default)]
2231 pub persona_distribution: PersonaDistribution,
2232 #[serde(default)]
2234 pub users_per_persona: UsersPerPersona,
2235}
2236
2237#[derive(Debug, Clone, Serialize, Deserialize)]
2239pub struct PersonaDistribution {
2240 pub junior_accountant: f64,
2241 pub senior_accountant: f64,
2242 pub controller: f64,
2243 pub manager: f64,
2244 pub automated_system: f64,
2245}
2246
2247impl Default for PersonaDistribution {
2248 fn default() -> Self {
2249 Self {
2250 junior_accountant: 0.15,
2251 senior_accountant: 0.15,
2252 controller: 0.05,
2253 manager: 0.05,
2254 automated_system: 0.60,
2255 }
2256 }
2257}
2258
2259#[derive(Debug, Clone, Serialize, Deserialize)]
2261pub struct UsersPerPersona {
2262 pub junior_accountant: usize,
2263 pub senior_accountant: usize,
2264 pub controller: usize,
2265 pub manager: usize,
2266 pub automated_system: usize,
2267}
2268
2269impl Default for UsersPerPersona {
2270 fn default() -> Self {
2271 Self {
2272 junior_accountant: 10,
2273 senior_accountant: 5,
2274 controller: 2,
2275 manager: 3,
2276 automated_system: 20,
2277 }
2278 }
2279}
2280
2281#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2295pub struct TemplateConfig {
2296 #[serde(default)]
2298 pub names: NameTemplateConfig,
2299 #[serde(default)]
2301 pub descriptions: DescriptionTemplateConfig,
2302 #[serde(default)]
2304 pub references: ReferenceTemplateConfig,
2305 #[serde(default, alias = "templatesPath")]
2311 pub path: Option<std::path::PathBuf>,
2312 #[serde(default, alias = "mergeStrategy")]
2321 pub merge_strategy: TemplateMergeStrategy,
2322}
2323
2324#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
2326#[serde(rename_all = "snake_case")]
2327pub enum TemplateMergeStrategy {
2328 #[default]
2330 Extend,
2331 Replace,
2333 MergePreferFile,
2335}
2336
2337#[derive(Debug, Clone, Serialize, Deserialize)]
2339pub struct NameTemplateConfig {
2340 #[serde(default)]
2342 pub culture_distribution: CultureDistribution,
2343 #[serde(default = "default_email_domain")]
2345 pub email_domain: String,
2346 #[serde(default = "default_true")]
2348 pub generate_realistic_names: bool,
2349}
2350
2351fn default_email_domain() -> String {
2352 "company.com".to_string()
2353}
2354
2355impl Default for NameTemplateConfig {
2356 fn default() -> Self {
2357 Self {
2358 culture_distribution: CultureDistribution::default(),
2359 email_domain: default_email_domain(),
2360 generate_realistic_names: true,
2361 }
2362 }
2363}
2364
2365#[derive(Debug, Clone, Serialize, Deserialize)]
2367pub struct CultureDistribution {
2368 pub western_us: f64,
2369 pub hispanic: f64,
2370 pub german: f64,
2371 pub french: f64,
2372 pub chinese: f64,
2373 pub japanese: f64,
2374 pub indian: f64,
2375}
2376
2377impl Default for CultureDistribution {
2378 fn default() -> Self {
2379 Self {
2380 western_us: 0.40,
2381 hispanic: 0.20,
2382 german: 0.10,
2383 french: 0.05,
2384 chinese: 0.10,
2385 japanese: 0.05,
2386 indian: 0.10,
2387 }
2388 }
2389}
2390
2391#[derive(Debug, Clone, Serialize, Deserialize)]
2393pub struct DescriptionTemplateConfig {
2394 #[serde(default = "default_true")]
2396 pub generate_header_text: bool,
2397 #[serde(default = "default_true")]
2399 pub generate_line_text: bool,
2400}
2401
2402impl Default for DescriptionTemplateConfig {
2403 fn default() -> Self {
2404 Self {
2405 generate_header_text: true,
2406 generate_line_text: true,
2407 }
2408 }
2409}
2410
2411#[derive(Debug, Clone, Serialize, Deserialize)]
2413pub struct ReferenceTemplateConfig {
2414 #[serde(default = "default_true")]
2416 pub generate_references: bool,
2417 #[serde(default = "default_invoice_prefix")]
2419 pub invoice_prefix: String,
2420 #[serde(default = "default_po_prefix")]
2422 pub po_prefix: String,
2423 #[serde(default = "default_so_prefix")]
2425 pub so_prefix: String,
2426}
2427
2428fn default_invoice_prefix() -> String {
2429 "INV".to_string()
2430}
2431fn default_po_prefix() -> String {
2432 "PO".to_string()
2433}
2434fn default_so_prefix() -> String {
2435 "SO".to_string()
2436}
2437
2438impl Default for ReferenceTemplateConfig {
2439 fn default() -> Self {
2440 Self {
2441 generate_references: true,
2442 invoice_prefix: default_invoice_prefix(),
2443 po_prefix: default_po_prefix(),
2444 so_prefix: default_so_prefix(),
2445 }
2446 }
2447}
2448
2449#[derive(Debug, Clone, Serialize, Deserialize)]
2451pub struct ApprovalConfig {
2452 #[serde(default)]
2454 pub enabled: bool,
2455 #[serde(default = "default_auto_approve_threshold")]
2457 pub auto_approve_threshold: f64,
2458 #[serde(default = "default_rejection_rate")]
2460 pub rejection_rate: f64,
2461 #[serde(default = "default_revision_rate")]
2463 pub revision_rate: f64,
2464 #[serde(default = "default_approval_delay_hours")]
2466 pub average_approval_delay_hours: f64,
2467 #[serde(default)]
2469 pub thresholds: Vec<ApprovalThresholdConfig>,
2470}
2471
2472fn default_auto_approve_threshold() -> f64 {
2473 1000.0
2474}
2475fn default_rejection_rate() -> f64 {
2476 0.02
2477}
2478fn default_revision_rate() -> f64 {
2479 0.05
2480}
2481fn default_approval_delay_hours() -> f64 {
2482 4.0
2483}
2484
2485impl Default for ApprovalConfig {
2486 fn default() -> Self {
2487 Self {
2488 enabled: false,
2489 auto_approve_threshold: default_auto_approve_threshold(),
2490 rejection_rate: default_rejection_rate(),
2491 revision_rate: default_revision_rate(),
2492 average_approval_delay_hours: default_approval_delay_hours(),
2493 thresholds: vec![
2494 ApprovalThresholdConfig {
2495 amount: 1000.0,
2496 level: 1,
2497 roles: vec!["senior_accountant".to_string()],
2498 },
2499 ApprovalThresholdConfig {
2500 amount: 10000.0,
2501 level: 2,
2502 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2503 },
2504 ApprovalThresholdConfig {
2505 amount: 100000.0,
2506 level: 3,
2507 roles: vec![
2508 "senior_accountant".to_string(),
2509 "controller".to_string(),
2510 "manager".to_string(),
2511 ],
2512 },
2513 ApprovalThresholdConfig {
2514 amount: 500000.0,
2515 level: 4,
2516 roles: vec![
2517 "senior_accountant".to_string(),
2518 "controller".to_string(),
2519 "manager".to_string(),
2520 "executive".to_string(),
2521 ],
2522 },
2523 ],
2524 }
2525 }
2526}
2527
2528#[derive(Debug, Clone, Serialize, Deserialize)]
2530pub struct ApprovalThresholdConfig {
2531 pub amount: f64,
2533 pub level: u8,
2535 pub roles: Vec<String>,
2537}
2538
2539#[derive(Debug, Clone, Serialize, Deserialize)]
2541pub struct DepartmentConfig {
2542 #[serde(default)]
2544 pub enabled: bool,
2545 #[serde(default = "default_headcount_multiplier")]
2547 pub headcount_multiplier: f64,
2548 #[serde(default)]
2550 pub custom_departments: Vec<CustomDepartmentConfig>,
2551}
2552
2553fn default_headcount_multiplier() -> f64 {
2554 1.0
2555}
2556
2557impl Default for DepartmentConfig {
2558 fn default() -> Self {
2559 Self {
2560 enabled: false,
2561 headcount_multiplier: default_headcount_multiplier(),
2562 custom_departments: Vec::new(),
2563 }
2564 }
2565}
2566
2567#[derive(Debug, Clone, Serialize, Deserialize)]
2569pub struct CustomDepartmentConfig {
2570 pub code: String,
2572 pub name: String,
2574 #[serde(default)]
2576 pub cost_center: Option<String>,
2577 #[serde(default)]
2579 pub primary_processes: Vec<String>,
2580 #[serde(default)]
2582 pub parent_code: Option<String>,
2583}
2584
2585#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2591pub struct MasterDataConfig {
2592 #[serde(default)]
2594 pub vendors: VendorMasterConfig,
2595 #[serde(default)]
2597 pub customers: CustomerMasterConfig,
2598 #[serde(default)]
2600 pub materials: MaterialMasterConfig,
2601 #[serde(default)]
2603 pub fixed_assets: FixedAssetMasterConfig,
2604 #[serde(default)]
2606 pub employees: EmployeeMasterConfig,
2607 #[serde(default)]
2609 pub cost_centers: CostCenterMasterConfig,
2610}
2611
2612#[derive(Debug, Clone, Serialize, Deserialize)]
2614pub struct VendorMasterConfig {
2615 #[serde(default = "default_vendor_count")]
2617 pub count: usize,
2618 #[serde(default = "default_intercompany_percent")]
2620 pub intercompany_percent: f64,
2621 #[serde(default)]
2623 pub payment_terms_distribution: PaymentTermsDistribution,
2624 #[serde(default)]
2626 pub behavior_distribution: VendorBehaviorDistribution,
2627 #[serde(default = "default_true")]
2629 pub generate_bank_accounts: bool,
2630 #[serde(default = "default_true")]
2632 pub generate_tax_ids: bool,
2633}
2634
2635fn default_vendor_count() -> usize {
2636 500
2637}
2638
2639fn default_intercompany_percent() -> f64 {
2640 0.05
2641}
2642
2643impl Default for VendorMasterConfig {
2644 fn default() -> Self {
2645 Self {
2646 count: default_vendor_count(),
2647 intercompany_percent: default_intercompany_percent(),
2648 payment_terms_distribution: PaymentTermsDistribution::default(),
2649 behavior_distribution: VendorBehaviorDistribution::default(),
2650 generate_bank_accounts: true,
2651 generate_tax_ids: true,
2652 }
2653 }
2654}
2655
2656#[derive(Debug, Clone, Serialize, Deserialize)]
2658pub struct PaymentTermsDistribution {
2659 pub net_30: f64,
2661 pub net_60: f64,
2663 pub net_90: f64,
2665 pub two_ten_net_30: f64,
2667 pub due_on_receipt: f64,
2669 pub end_of_month: f64,
2671}
2672
2673impl Default for PaymentTermsDistribution {
2674 fn default() -> Self {
2675 Self {
2676 net_30: 0.40,
2677 net_60: 0.20,
2678 net_90: 0.10,
2679 two_ten_net_30: 0.15,
2680 due_on_receipt: 0.05,
2681 end_of_month: 0.10,
2682 }
2683 }
2684}
2685
2686#[derive(Debug, Clone, Serialize, Deserialize)]
2688pub struct VendorBehaviorDistribution {
2689 pub reliable: f64,
2691 pub sometimes_late: f64,
2693 pub inconsistent_quality: f64,
2695 pub premium: f64,
2697 pub budget: f64,
2699}
2700
2701impl Default for VendorBehaviorDistribution {
2702 fn default() -> Self {
2703 Self {
2704 reliable: 0.50,
2705 sometimes_late: 0.20,
2706 inconsistent_quality: 0.10,
2707 premium: 0.10,
2708 budget: 0.10,
2709 }
2710 }
2711}
2712
2713#[derive(Debug, Clone, Serialize, Deserialize)]
2715pub struct CustomerMasterConfig {
2716 #[serde(default = "default_customer_count")]
2718 pub count: usize,
2719 #[serde(default = "default_intercompany_percent")]
2721 pub intercompany_percent: f64,
2722 #[serde(default)]
2724 pub credit_rating_distribution: CreditRatingDistribution,
2725 #[serde(default)]
2727 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2728 #[serde(default = "default_true")]
2730 pub generate_credit_limits: bool,
2731}
2732
2733fn default_customer_count() -> usize {
2734 2000
2735}
2736
2737impl Default for CustomerMasterConfig {
2738 fn default() -> Self {
2739 Self {
2740 count: default_customer_count(),
2741 intercompany_percent: default_intercompany_percent(),
2742 credit_rating_distribution: CreditRatingDistribution::default(),
2743 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2744 generate_credit_limits: true,
2745 }
2746 }
2747}
2748
2749#[derive(Debug, Clone, Serialize, Deserialize)]
2751pub struct CreditRatingDistribution {
2752 pub aaa: f64,
2754 pub aa: f64,
2756 pub a: f64,
2758 pub bbb: f64,
2760 pub bb: f64,
2762 pub b: f64,
2764 pub below_b: f64,
2766}
2767
2768impl Default for CreditRatingDistribution {
2769 fn default() -> Self {
2770 Self {
2771 aaa: 0.05,
2772 aa: 0.10,
2773 a: 0.20,
2774 bbb: 0.30,
2775 bb: 0.20,
2776 b: 0.10,
2777 below_b: 0.05,
2778 }
2779 }
2780}
2781
2782#[derive(Debug, Clone, Serialize, Deserialize)]
2784pub struct PaymentBehaviorDistribution {
2785 pub early_payer: f64,
2787 pub on_time: f64,
2789 pub occasional_late: f64,
2791 pub frequent_late: f64,
2793 pub discount_taker: f64,
2795}
2796
2797impl Default for PaymentBehaviorDistribution {
2798 fn default() -> Self {
2799 Self {
2800 early_payer: 0.10,
2801 on_time: 0.50,
2802 occasional_late: 0.25,
2803 frequent_late: 0.10,
2804 discount_taker: 0.05,
2805 }
2806 }
2807}
2808
2809#[derive(Debug, Clone, Serialize, Deserialize)]
2811pub struct MaterialMasterConfig {
2812 #[serde(default = "default_material_count")]
2814 pub count: usize,
2815 #[serde(default)]
2817 pub type_distribution: MaterialTypeDistribution,
2818 #[serde(default)]
2820 pub valuation_distribution: ValuationMethodDistribution,
2821 #[serde(default = "default_bom_percent")]
2823 pub bom_percent: f64,
2824 #[serde(default = "default_max_bom_depth")]
2826 pub max_bom_depth: u8,
2827}
2828
2829fn default_material_count() -> usize {
2830 5000
2831}
2832
2833fn default_bom_percent() -> f64 {
2834 0.20
2835}
2836
2837fn default_max_bom_depth() -> u8 {
2838 3
2839}
2840
2841impl Default for MaterialMasterConfig {
2842 fn default() -> Self {
2843 Self {
2844 count: default_material_count(),
2845 type_distribution: MaterialTypeDistribution::default(),
2846 valuation_distribution: ValuationMethodDistribution::default(),
2847 bom_percent: default_bom_percent(),
2848 max_bom_depth: default_max_bom_depth(),
2849 }
2850 }
2851}
2852
2853#[derive(Debug, Clone, Serialize, Deserialize)]
2855pub struct MaterialTypeDistribution {
2856 pub raw_material: f64,
2858 pub semi_finished: f64,
2860 pub finished_good: f64,
2862 pub trading_good: f64,
2864 pub operating_supply: f64,
2866 pub service: f64,
2868}
2869
2870impl Default for MaterialTypeDistribution {
2871 fn default() -> Self {
2872 Self {
2873 raw_material: 0.30,
2874 semi_finished: 0.15,
2875 finished_good: 0.25,
2876 trading_good: 0.15,
2877 operating_supply: 0.10,
2878 service: 0.05,
2879 }
2880 }
2881}
2882
2883#[derive(Debug, Clone, Serialize, Deserialize)]
2885pub struct ValuationMethodDistribution {
2886 pub standard_cost: f64,
2888 pub moving_average: f64,
2890 pub fifo: f64,
2892 pub lifo: f64,
2894}
2895
2896impl Default for ValuationMethodDistribution {
2897 fn default() -> Self {
2898 Self {
2899 standard_cost: 0.50,
2900 moving_average: 0.30,
2901 fifo: 0.15,
2902 lifo: 0.05,
2903 }
2904 }
2905}
2906
2907#[derive(Debug, Clone, Serialize, Deserialize)]
2909pub struct FixedAssetMasterConfig {
2910 #[serde(default = "default_asset_count")]
2912 pub count: usize,
2913 #[serde(default)]
2915 pub class_distribution: AssetClassDistribution,
2916 #[serde(default)]
2918 pub depreciation_distribution: DepreciationMethodDistribution,
2919 #[serde(default = "default_fully_depreciated_percent")]
2921 pub fully_depreciated_percent: f64,
2922 #[serde(default = "default_true")]
2924 pub generate_acquisition_history: bool,
2925}
2926
2927fn default_asset_count() -> usize {
2928 800
2929}
2930
2931fn default_fully_depreciated_percent() -> f64 {
2932 0.15
2933}
2934
2935impl Default for FixedAssetMasterConfig {
2936 fn default() -> Self {
2937 Self {
2938 count: default_asset_count(),
2939 class_distribution: AssetClassDistribution::default(),
2940 depreciation_distribution: DepreciationMethodDistribution::default(),
2941 fully_depreciated_percent: default_fully_depreciated_percent(),
2942 generate_acquisition_history: true,
2943 }
2944 }
2945}
2946
2947#[derive(Debug, Clone, Serialize, Deserialize)]
2949pub struct AssetClassDistribution {
2950 pub buildings: f64,
2952 pub machinery: f64,
2954 pub vehicles: f64,
2956 pub it_equipment: f64,
2958 pub furniture: f64,
2960 pub land: f64,
2962 pub leasehold: f64,
2964}
2965
2966impl Default for AssetClassDistribution {
2967 fn default() -> Self {
2968 Self {
2969 buildings: 0.15,
2970 machinery: 0.30,
2971 vehicles: 0.15,
2972 it_equipment: 0.20,
2973 furniture: 0.10,
2974 land: 0.05,
2975 leasehold: 0.05,
2976 }
2977 }
2978}
2979
2980#[derive(Debug, Clone, Serialize, Deserialize)]
2982pub struct DepreciationMethodDistribution {
2983 pub straight_line: f64,
2985 pub declining_balance: f64,
2987 pub double_declining: f64,
2989 pub sum_of_years: f64,
2991 pub units_of_production: f64,
2993}
2994
2995impl Default for DepreciationMethodDistribution {
2996 fn default() -> Self {
2997 Self {
2998 straight_line: 0.60,
2999 declining_balance: 0.20,
3000 double_declining: 0.10,
3001 sum_of_years: 0.05,
3002 units_of_production: 0.05,
3003 }
3004 }
3005}
3006
3007#[derive(Debug, Clone, Serialize, Deserialize)]
3009pub struct EmployeeMasterConfig {
3010 #[serde(default = "default_employee_count")]
3012 pub count: usize,
3013 #[serde(default = "default_true")]
3015 pub generate_hierarchy: bool,
3016 #[serde(default = "default_hierarchy_depth")]
3018 pub max_hierarchy_depth: u8,
3019 #[serde(default = "default_span_of_control")]
3021 pub average_span_of_control: f64,
3022 #[serde(default)]
3024 pub approval_limits: ApprovalLimitDistribution,
3025 #[serde(default)]
3027 pub department_distribution: EmployeeDepartmentDistribution,
3028}
3029
3030fn default_employee_count() -> usize {
3031 1500
3032}
3033
3034fn default_hierarchy_depth() -> u8 {
3035 6
3036}
3037
3038fn default_span_of_control() -> f64 {
3039 5.0
3040}
3041
3042impl Default for EmployeeMasterConfig {
3043 fn default() -> Self {
3044 Self {
3045 count: default_employee_count(),
3046 generate_hierarchy: true,
3047 max_hierarchy_depth: default_hierarchy_depth(),
3048 average_span_of_control: default_span_of_control(),
3049 approval_limits: ApprovalLimitDistribution::default(),
3050 department_distribution: EmployeeDepartmentDistribution::default(),
3051 }
3052 }
3053}
3054
3055#[derive(Debug, Clone, Serialize, Deserialize)]
3057pub struct ApprovalLimitDistribution {
3058 #[serde(default = "default_staff_limit")]
3060 pub staff: f64,
3061 #[serde(default = "default_senior_limit")]
3063 pub senior: f64,
3064 #[serde(default = "default_manager_limit")]
3066 pub manager: f64,
3067 #[serde(default = "default_director_limit")]
3069 pub director: f64,
3070 #[serde(default = "default_vp_limit")]
3072 pub vp: f64,
3073 #[serde(default = "default_executive_limit")]
3075 pub executive: f64,
3076}
3077
3078fn default_staff_limit() -> f64 {
3079 1000.0
3080}
3081fn default_senior_limit() -> f64 {
3082 5000.0
3083}
3084fn default_manager_limit() -> f64 {
3085 25000.0
3086}
3087fn default_director_limit() -> f64 {
3088 100000.0
3089}
3090fn default_vp_limit() -> f64 {
3091 500000.0
3092}
3093fn default_executive_limit() -> f64 {
3094 f64::INFINITY
3095}
3096
3097impl Default for ApprovalLimitDistribution {
3098 fn default() -> Self {
3099 Self {
3100 staff: default_staff_limit(),
3101 senior: default_senior_limit(),
3102 manager: default_manager_limit(),
3103 director: default_director_limit(),
3104 vp: default_vp_limit(),
3105 executive: default_executive_limit(),
3106 }
3107 }
3108}
3109
3110#[derive(Debug, Clone, Serialize, Deserialize)]
3112pub struct EmployeeDepartmentDistribution {
3113 pub finance: f64,
3115 pub procurement: f64,
3117 pub sales: f64,
3119 pub warehouse: f64,
3121 pub it: f64,
3123 pub hr: f64,
3125 pub operations: f64,
3127 pub executive: f64,
3129}
3130
3131impl Default for EmployeeDepartmentDistribution {
3132 fn default() -> Self {
3133 Self {
3134 finance: 0.12,
3135 procurement: 0.10,
3136 sales: 0.25,
3137 warehouse: 0.15,
3138 it: 0.10,
3139 hr: 0.05,
3140 operations: 0.20,
3141 executive: 0.03,
3142 }
3143 }
3144}
3145
3146#[derive(Debug, Clone, Serialize, Deserialize)]
3148pub struct CostCenterMasterConfig {
3149 #[serde(default = "default_cost_center_count")]
3151 pub count: usize,
3152 #[serde(default = "default_true")]
3154 pub generate_hierarchy: bool,
3155 #[serde(default = "default_cc_hierarchy_depth")]
3157 pub max_hierarchy_depth: u8,
3158}
3159
3160fn default_cost_center_count() -> usize {
3161 50
3162}
3163
3164fn default_cc_hierarchy_depth() -> u8 {
3165 3
3166}
3167
3168impl Default for CostCenterMasterConfig {
3169 fn default() -> Self {
3170 Self {
3171 count: default_cost_center_count(),
3172 generate_hierarchy: true,
3173 max_hierarchy_depth: default_cc_hierarchy_depth(),
3174 }
3175 }
3176}
3177
3178#[derive(Debug, Clone, Serialize, Deserialize)]
3184pub struct DocumentFlowConfig {
3185 #[serde(default)]
3187 pub p2p: P2PFlowConfig,
3188 #[serde(default)]
3190 pub o2c: O2CFlowConfig,
3191 #[serde(default = "default_true")]
3193 pub generate_document_references: bool,
3194 #[serde(default)]
3196 pub export_flow_graph: bool,
3197}
3198
3199impl Default for DocumentFlowConfig {
3200 fn default() -> Self {
3201 Self {
3202 p2p: P2PFlowConfig::default(),
3203 o2c: O2CFlowConfig::default(),
3204 generate_document_references: true,
3205 export_flow_graph: false,
3206 }
3207 }
3208}
3209
3210#[derive(Debug, Clone, Serialize, Deserialize)]
3212pub struct P2PFlowConfig {
3213 #[serde(default = "default_true")]
3215 pub enabled: bool,
3216 #[serde(default = "default_three_way_match_rate")]
3218 pub three_way_match_rate: f64,
3219 #[serde(default = "default_partial_delivery_rate")]
3221 pub partial_delivery_rate: f64,
3222 #[serde(default = "default_price_variance_rate")]
3224 pub price_variance_rate: f64,
3225 #[serde(default = "default_max_price_variance")]
3227 pub max_price_variance_percent: f64,
3228 #[serde(default = "default_quantity_variance_rate")]
3230 pub quantity_variance_rate: f64,
3231 #[serde(default = "default_po_to_gr_days")]
3233 pub average_po_to_gr_days: u32,
3234 #[serde(default = "default_gr_to_invoice_days")]
3236 pub average_gr_to_invoice_days: u32,
3237 #[serde(default = "default_invoice_to_payment_days")]
3239 pub average_invoice_to_payment_days: u32,
3240 #[serde(default)]
3242 pub line_count_distribution: DocumentLineCountDistribution,
3243 #[serde(default)]
3245 pub payment_behavior: P2PPaymentBehaviorConfig,
3246 #[serde(default)]
3248 pub over_delivery_rate: Option<f64>,
3249 #[serde(default)]
3251 pub early_payment_discount_rate: Option<f64>,
3252}
3253
3254fn default_three_way_match_rate() -> f64 {
3255 0.95
3256}
3257
3258fn default_partial_delivery_rate() -> f64 {
3259 0.15
3260}
3261
3262fn default_price_variance_rate() -> f64 {
3263 0.08
3264}
3265
3266fn default_max_price_variance() -> f64 {
3267 0.05
3268}
3269
3270fn default_quantity_variance_rate() -> f64 {
3271 0.05
3272}
3273
3274fn default_po_to_gr_days() -> u32 {
3275 14
3276}
3277
3278fn default_gr_to_invoice_days() -> u32 {
3279 5
3280}
3281
3282fn default_invoice_to_payment_days() -> u32 {
3283 30
3284}
3285
3286impl Default for P2PFlowConfig {
3287 fn default() -> Self {
3288 Self {
3289 enabled: true,
3290 three_way_match_rate: default_three_way_match_rate(),
3291 partial_delivery_rate: default_partial_delivery_rate(),
3292 price_variance_rate: default_price_variance_rate(),
3293 max_price_variance_percent: default_max_price_variance(),
3294 quantity_variance_rate: default_quantity_variance_rate(),
3295 average_po_to_gr_days: default_po_to_gr_days(),
3296 average_gr_to_invoice_days: default_gr_to_invoice_days(),
3297 average_invoice_to_payment_days: default_invoice_to_payment_days(),
3298 line_count_distribution: DocumentLineCountDistribution::default(),
3299 payment_behavior: P2PPaymentBehaviorConfig::default(),
3300 over_delivery_rate: None,
3301 early_payment_discount_rate: None,
3302 }
3303 }
3304}
3305
3306#[derive(Debug, Clone, Serialize, Deserialize)]
3312pub struct P2PPaymentBehaviorConfig {
3313 #[serde(default = "default_p2p_late_payment_rate")]
3315 pub late_payment_rate: f64,
3316 #[serde(default)]
3318 pub late_payment_days_distribution: LatePaymentDaysDistribution,
3319 #[serde(default = "default_p2p_partial_payment_rate")]
3321 pub partial_payment_rate: f64,
3322 #[serde(default = "default_p2p_payment_correction_rate")]
3324 pub payment_correction_rate: f64,
3325 #[serde(default = "default_p2p_avg_days_until_remainder")]
3327 pub avg_days_until_remainder: u32,
3328}
3329
3330fn default_p2p_late_payment_rate() -> f64 {
3331 0.15
3332}
3333
3334fn default_p2p_partial_payment_rate() -> f64 {
3335 0.05
3336}
3337
3338fn default_p2p_payment_correction_rate() -> f64 {
3339 0.02
3340}
3341
3342fn default_p2p_avg_days_until_remainder() -> u32 {
3343 30
3344}
3345
3346impl Default for P2PPaymentBehaviorConfig {
3347 fn default() -> Self {
3348 Self {
3349 late_payment_rate: default_p2p_late_payment_rate(),
3350 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3351 partial_payment_rate: default_p2p_partial_payment_rate(),
3352 payment_correction_rate: default_p2p_payment_correction_rate(),
3353 avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3354 }
3355 }
3356}
3357
3358#[derive(Debug, Clone, Serialize, Deserialize)]
3360pub struct LatePaymentDaysDistribution {
3361 #[serde(default = "default_slightly_late")]
3363 pub slightly_late_1_to_7: f64,
3364 #[serde(default = "default_late_8_14")]
3366 pub late_8_to_14: f64,
3367 #[serde(default = "default_very_late")]
3369 pub very_late_15_to_30: f64,
3370 #[serde(default = "default_severely_late")]
3372 pub severely_late_31_to_60: f64,
3373 #[serde(default = "default_extremely_late")]
3375 pub extremely_late_over_60: f64,
3376}
3377
3378fn default_slightly_late() -> f64 {
3379 0.50
3380}
3381
3382fn default_late_8_14() -> f64 {
3383 0.25
3384}
3385
3386fn default_very_late() -> f64 {
3387 0.15
3388}
3389
3390fn default_severely_late() -> f64 {
3391 0.07
3392}
3393
3394fn default_extremely_late() -> f64 {
3395 0.03
3396}
3397
3398impl Default for LatePaymentDaysDistribution {
3399 fn default() -> Self {
3400 Self {
3401 slightly_late_1_to_7: default_slightly_late(),
3402 late_8_to_14: default_late_8_14(),
3403 very_late_15_to_30: default_very_late(),
3404 severely_late_31_to_60: default_severely_late(),
3405 extremely_late_over_60: default_extremely_late(),
3406 }
3407 }
3408}
3409
3410#[derive(Debug, Clone, Serialize, Deserialize)]
3412pub struct O2CFlowConfig {
3413 #[serde(default = "default_true")]
3415 pub enabled: bool,
3416 #[serde(default = "default_credit_check_failure_rate")]
3418 pub credit_check_failure_rate: f64,
3419 #[serde(default = "default_partial_shipment_rate")]
3421 pub partial_shipment_rate: f64,
3422 #[serde(default = "default_return_rate")]
3424 pub return_rate: f64,
3425 #[serde(default = "default_bad_debt_rate")]
3427 pub bad_debt_rate: f64,
3428 #[serde(default = "default_so_to_delivery_days")]
3430 pub average_so_to_delivery_days: u32,
3431 #[serde(default = "default_delivery_to_invoice_days")]
3433 pub average_delivery_to_invoice_days: u32,
3434 #[serde(default = "default_invoice_to_receipt_days")]
3436 pub average_invoice_to_receipt_days: u32,
3437 #[serde(default)]
3439 pub line_count_distribution: DocumentLineCountDistribution,
3440 #[serde(default)]
3442 pub cash_discount: CashDiscountConfig,
3443 #[serde(default)]
3445 pub payment_behavior: O2CPaymentBehaviorConfig,
3446 #[serde(default)]
3448 pub late_payment_rate: Option<f64>,
3449}
3450
3451fn default_credit_check_failure_rate() -> f64 {
3452 0.02
3453}
3454
3455fn default_partial_shipment_rate() -> f64 {
3456 0.10
3457}
3458
3459fn default_return_rate() -> f64 {
3460 0.03
3461}
3462
3463fn default_bad_debt_rate() -> f64 {
3464 0.01
3465}
3466
3467fn default_so_to_delivery_days() -> u32 {
3468 7
3469}
3470
3471fn default_delivery_to_invoice_days() -> u32 {
3472 1
3473}
3474
3475fn default_invoice_to_receipt_days() -> u32 {
3476 45
3477}
3478
3479impl Default for O2CFlowConfig {
3480 fn default() -> Self {
3481 Self {
3482 enabled: true,
3483 credit_check_failure_rate: default_credit_check_failure_rate(),
3484 partial_shipment_rate: default_partial_shipment_rate(),
3485 return_rate: default_return_rate(),
3486 bad_debt_rate: default_bad_debt_rate(),
3487 average_so_to_delivery_days: default_so_to_delivery_days(),
3488 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3489 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3490 line_count_distribution: DocumentLineCountDistribution::default(),
3491 cash_discount: CashDiscountConfig::default(),
3492 payment_behavior: O2CPaymentBehaviorConfig::default(),
3493 late_payment_rate: None,
3494 }
3495 }
3496}
3497
3498#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3504pub struct O2CPaymentBehaviorConfig {
3505 #[serde(default)]
3507 pub dunning: DunningConfig,
3508 #[serde(default)]
3510 pub partial_payments: PartialPaymentConfig,
3511 #[serde(default)]
3513 pub short_payments: ShortPaymentConfig,
3514 #[serde(default)]
3516 pub on_account_payments: OnAccountPaymentConfig,
3517 #[serde(default)]
3519 pub payment_corrections: PaymentCorrectionConfig,
3520}
3521
3522#[derive(Debug, Clone, Serialize, Deserialize)]
3524pub struct DunningConfig {
3525 #[serde(default)]
3527 pub enabled: bool,
3528 #[serde(default = "default_dunning_level_1_days")]
3530 pub level_1_days_overdue: u32,
3531 #[serde(default = "default_dunning_level_2_days")]
3533 pub level_2_days_overdue: u32,
3534 #[serde(default = "default_dunning_level_3_days")]
3536 pub level_3_days_overdue: u32,
3537 #[serde(default = "default_collection_days")]
3539 pub collection_days_overdue: u32,
3540 #[serde(default)]
3542 pub payment_after_dunning_rates: DunningPaymentRates,
3543 #[serde(default = "default_dunning_block_rate")]
3545 pub dunning_block_rate: f64,
3546 #[serde(default = "default_dunning_interest_rate")]
3548 pub interest_rate_per_year: f64,
3549 #[serde(default = "default_dunning_charge")]
3551 pub dunning_charge: f64,
3552}
3553
3554fn default_dunning_level_1_days() -> u32 {
3555 14
3556}
3557
3558fn default_dunning_level_2_days() -> u32 {
3559 28
3560}
3561
3562fn default_dunning_level_3_days() -> u32 {
3563 42
3564}
3565
3566fn default_collection_days() -> u32 {
3567 60
3568}
3569
3570fn default_dunning_block_rate() -> f64 {
3571 0.05
3572}
3573
3574fn default_dunning_interest_rate() -> f64 {
3575 0.09
3576}
3577
3578fn default_dunning_charge() -> f64 {
3579 25.0
3580}
3581
3582impl Default for DunningConfig {
3583 fn default() -> Self {
3584 Self {
3585 enabled: false,
3586 level_1_days_overdue: default_dunning_level_1_days(),
3587 level_2_days_overdue: default_dunning_level_2_days(),
3588 level_3_days_overdue: default_dunning_level_3_days(),
3589 collection_days_overdue: default_collection_days(),
3590 payment_after_dunning_rates: DunningPaymentRates::default(),
3591 dunning_block_rate: default_dunning_block_rate(),
3592 interest_rate_per_year: default_dunning_interest_rate(),
3593 dunning_charge: default_dunning_charge(),
3594 }
3595 }
3596}
3597
3598#[derive(Debug, Clone, Serialize, Deserialize)]
3600pub struct DunningPaymentRates {
3601 #[serde(default = "default_after_level_1")]
3603 pub after_level_1: f64,
3604 #[serde(default = "default_after_level_2")]
3606 pub after_level_2: f64,
3607 #[serde(default = "default_after_level_3")]
3609 pub after_level_3: f64,
3610 #[serde(default = "default_during_collection")]
3612 pub during_collection: f64,
3613 #[serde(default = "default_never_pay")]
3615 pub never_pay: f64,
3616}
3617
3618fn default_after_level_1() -> f64 {
3619 0.40
3620}
3621
3622fn default_after_level_2() -> f64 {
3623 0.30
3624}
3625
3626fn default_after_level_3() -> f64 {
3627 0.15
3628}
3629
3630fn default_during_collection() -> f64 {
3631 0.05
3632}
3633
3634fn default_never_pay() -> f64 {
3635 0.10
3636}
3637
3638impl Default for DunningPaymentRates {
3639 fn default() -> Self {
3640 Self {
3641 after_level_1: default_after_level_1(),
3642 after_level_2: default_after_level_2(),
3643 after_level_3: default_after_level_3(),
3644 during_collection: default_during_collection(),
3645 never_pay: default_never_pay(),
3646 }
3647 }
3648}
3649
3650#[derive(Debug, Clone, Serialize, Deserialize)]
3652pub struct PartialPaymentConfig {
3653 #[serde(default = "default_partial_payment_rate")]
3655 pub rate: f64,
3656 #[serde(default)]
3658 pub percentage_distribution: PartialPaymentPercentageDistribution,
3659 #[serde(default = "default_avg_days_until_remainder")]
3661 pub avg_days_until_remainder: u32,
3662}
3663
3664fn default_partial_payment_rate() -> f64 {
3665 0.08
3666}
3667
3668fn default_avg_days_until_remainder() -> u32 {
3669 30
3670}
3671
3672impl Default for PartialPaymentConfig {
3673 fn default() -> Self {
3674 Self {
3675 rate: default_partial_payment_rate(),
3676 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3677 avg_days_until_remainder: default_avg_days_until_remainder(),
3678 }
3679 }
3680}
3681
3682#[derive(Debug, Clone, Serialize, Deserialize)]
3684pub struct PartialPaymentPercentageDistribution {
3685 #[serde(default = "default_partial_25")]
3687 pub pay_25_percent: f64,
3688 #[serde(default = "default_partial_50")]
3690 pub pay_50_percent: f64,
3691 #[serde(default = "default_partial_75")]
3693 pub pay_75_percent: f64,
3694 #[serde(default = "default_partial_random")]
3696 pub pay_random_percent: f64,
3697}
3698
3699fn default_partial_25() -> f64 {
3700 0.15
3701}
3702
3703fn default_partial_50() -> f64 {
3704 0.50
3705}
3706
3707fn default_partial_75() -> f64 {
3708 0.25
3709}
3710
3711fn default_partial_random() -> f64 {
3712 0.10
3713}
3714
3715impl Default for PartialPaymentPercentageDistribution {
3716 fn default() -> Self {
3717 Self {
3718 pay_25_percent: default_partial_25(),
3719 pay_50_percent: default_partial_50(),
3720 pay_75_percent: default_partial_75(),
3721 pay_random_percent: default_partial_random(),
3722 }
3723 }
3724}
3725
3726#[derive(Debug, Clone, Serialize, Deserialize)]
3728pub struct ShortPaymentConfig {
3729 #[serde(default = "default_short_payment_rate")]
3731 pub rate: f64,
3732 #[serde(default)]
3734 pub reason_distribution: ShortPaymentReasonDistribution,
3735 #[serde(default = "default_max_short_percent")]
3737 pub max_short_percent: f64,
3738}
3739
3740fn default_short_payment_rate() -> f64 {
3741 0.03
3742}
3743
3744fn default_max_short_percent() -> f64 {
3745 0.10
3746}
3747
3748impl Default for ShortPaymentConfig {
3749 fn default() -> Self {
3750 Self {
3751 rate: default_short_payment_rate(),
3752 reason_distribution: ShortPaymentReasonDistribution::default(),
3753 max_short_percent: default_max_short_percent(),
3754 }
3755 }
3756}
3757
3758#[derive(Debug, Clone, Serialize, Deserialize)]
3760pub struct ShortPaymentReasonDistribution {
3761 #[serde(default = "default_pricing_dispute")]
3763 pub pricing_dispute: f64,
3764 #[serde(default = "default_quality_issue")]
3766 pub quality_issue: f64,
3767 #[serde(default = "default_quantity_discrepancy")]
3769 pub quantity_discrepancy: f64,
3770 #[serde(default = "default_unauthorized_deduction")]
3772 pub unauthorized_deduction: f64,
3773 #[serde(default = "default_incorrect_discount")]
3775 pub incorrect_discount: f64,
3776}
3777
3778fn default_pricing_dispute() -> f64 {
3779 0.30
3780}
3781
3782fn default_quality_issue() -> f64 {
3783 0.20
3784}
3785
3786fn default_quantity_discrepancy() -> f64 {
3787 0.20
3788}
3789
3790fn default_unauthorized_deduction() -> f64 {
3791 0.15
3792}
3793
3794fn default_incorrect_discount() -> f64 {
3795 0.15
3796}
3797
3798impl Default for ShortPaymentReasonDistribution {
3799 fn default() -> Self {
3800 Self {
3801 pricing_dispute: default_pricing_dispute(),
3802 quality_issue: default_quality_issue(),
3803 quantity_discrepancy: default_quantity_discrepancy(),
3804 unauthorized_deduction: default_unauthorized_deduction(),
3805 incorrect_discount: default_incorrect_discount(),
3806 }
3807 }
3808}
3809
3810#[derive(Debug, Clone, Serialize, Deserialize)]
3812pub struct OnAccountPaymentConfig {
3813 #[serde(default = "default_on_account_rate")]
3815 pub rate: f64,
3816 #[serde(default = "default_avg_days_until_applied")]
3818 pub avg_days_until_applied: u32,
3819}
3820
3821fn default_on_account_rate() -> f64 {
3822 0.02
3823}
3824
3825fn default_avg_days_until_applied() -> u32 {
3826 14
3827}
3828
3829impl Default for OnAccountPaymentConfig {
3830 fn default() -> Self {
3831 Self {
3832 rate: default_on_account_rate(),
3833 avg_days_until_applied: default_avg_days_until_applied(),
3834 }
3835 }
3836}
3837
3838#[derive(Debug, Clone, Serialize, Deserialize)]
3840pub struct PaymentCorrectionConfig {
3841 #[serde(default = "default_payment_correction_rate")]
3843 pub rate: f64,
3844 #[serde(default)]
3846 pub type_distribution: PaymentCorrectionTypeDistribution,
3847}
3848
3849fn default_payment_correction_rate() -> f64 {
3850 0.02
3851}
3852
3853impl Default for PaymentCorrectionConfig {
3854 fn default() -> Self {
3855 Self {
3856 rate: default_payment_correction_rate(),
3857 type_distribution: PaymentCorrectionTypeDistribution::default(),
3858 }
3859 }
3860}
3861
3862#[derive(Debug, Clone, Serialize, Deserialize)]
3864pub struct PaymentCorrectionTypeDistribution {
3865 #[serde(default = "default_nsf_rate")]
3867 pub nsf: f64,
3868 #[serde(default = "default_chargeback_rate")]
3870 pub chargeback: f64,
3871 #[serde(default = "default_wrong_amount_rate")]
3873 pub wrong_amount: f64,
3874 #[serde(default = "default_wrong_customer_rate")]
3876 pub wrong_customer: f64,
3877 #[serde(default = "default_duplicate_payment_rate")]
3879 pub duplicate_payment: f64,
3880}
3881
3882fn default_nsf_rate() -> f64 {
3883 0.30
3884}
3885
3886fn default_chargeback_rate() -> f64 {
3887 0.20
3888}
3889
3890fn default_wrong_amount_rate() -> f64 {
3891 0.20
3892}
3893
3894fn default_wrong_customer_rate() -> f64 {
3895 0.15
3896}
3897
3898fn default_duplicate_payment_rate() -> f64 {
3899 0.15
3900}
3901
3902impl Default for PaymentCorrectionTypeDistribution {
3903 fn default() -> Self {
3904 Self {
3905 nsf: default_nsf_rate(),
3906 chargeback: default_chargeback_rate(),
3907 wrong_amount: default_wrong_amount_rate(),
3908 wrong_customer: default_wrong_customer_rate(),
3909 duplicate_payment: default_duplicate_payment_rate(),
3910 }
3911 }
3912}
3913
3914#[derive(Debug, Clone, Serialize, Deserialize)]
3916pub struct DocumentLineCountDistribution {
3917 #[serde(default = "default_min_lines")]
3919 pub min_lines: u32,
3920 #[serde(default = "default_max_lines")]
3922 pub max_lines: u32,
3923 #[serde(default = "default_mode_lines")]
3925 pub mode_lines: u32,
3926}
3927
3928fn default_min_lines() -> u32 {
3929 1
3930}
3931
3932fn default_max_lines() -> u32 {
3933 20
3934}
3935
3936fn default_mode_lines() -> u32 {
3937 3
3938}
3939
3940impl Default for DocumentLineCountDistribution {
3941 fn default() -> Self {
3942 Self {
3943 min_lines: default_min_lines(),
3944 max_lines: default_max_lines(),
3945 mode_lines: default_mode_lines(),
3946 }
3947 }
3948}
3949
3950#[derive(Debug, Clone, Serialize, Deserialize)]
3952pub struct CashDiscountConfig {
3953 #[serde(default = "default_discount_eligible_rate")]
3955 pub eligible_rate: f64,
3956 #[serde(default = "default_discount_taken_rate")]
3958 pub taken_rate: f64,
3959 #[serde(default = "default_discount_percent")]
3961 pub discount_percent: f64,
3962 #[serde(default = "default_discount_days")]
3964 pub discount_days: u32,
3965}
3966
3967fn default_discount_eligible_rate() -> f64 {
3968 0.30
3969}
3970
3971fn default_discount_taken_rate() -> f64 {
3972 0.60
3973}
3974
3975fn default_discount_percent() -> f64 {
3976 0.02
3977}
3978
3979fn default_discount_days() -> u32 {
3980 10
3981}
3982
3983impl Default for CashDiscountConfig {
3984 fn default() -> Self {
3985 Self {
3986 eligible_rate: default_discount_eligible_rate(),
3987 taken_rate: default_discount_taken_rate(),
3988 discount_percent: default_discount_percent(),
3989 discount_days: default_discount_days(),
3990 }
3991 }
3992}
3993
3994#[derive(Debug, Clone, Serialize, Deserialize)]
4000pub struct IntercompanyConfig {
4001 #[serde(default)]
4003 pub enabled: bool,
4004 #[serde(default = "default_ic_transaction_rate")]
4006 pub ic_transaction_rate: f64,
4007 #[serde(default)]
4009 pub transfer_pricing_method: TransferPricingMethod,
4010 #[serde(default = "default_markup_percent")]
4012 pub markup_percent: f64,
4013 #[serde(default = "default_true")]
4015 pub generate_matched_pairs: bool,
4016 #[serde(default)]
4018 pub transaction_type_distribution: ICTransactionTypeDistribution,
4019 #[serde(default)]
4021 pub generate_eliminations: bool,
4022}
4023
4024fn default_ic_transaction_rate() -> f64 {
4025 0.15
4026}
4027
4028fn default_markup_percent() -> f64 {
4029 0.05
4030}
4031
4032impl Default for IntercompanyConfig {
4033 fn default() -> Self {
4034 Self {
4035 enabled: false,
4036 ic_transaction_rate: default_ic_transaction_rate(),
4037 transfer_pricing_method: TransferPricingMethod::default(),
4038 markup_percent: default_markup_percent(),
4039 generate_matched_pairs: true,
4040 transaction_type_distribution: ICTransactionTypeDistribution::default(),
4041 generate_eliminations: false,
4042 }
4043 }
4044}
4045
4046#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
4048#[serde(rename_all = "snake_case")]
4049pub enum TransferPricingMethod {
4050 #[default]
4052 CostPlus,
4053 ComparableUncontrolled,
4055 ResalePrice,
4057 TransactionalNetMargin,
4059 ProfitSplit,
4061}
4062
4063#[derive(Debug, Clone, Serialize, Deserialize)]
4065pub struct ICTransactionTypeDistribution {
4066 pub goods_sale: f64,
4068 pub service_provided: f64,
4070 pub loan: f64,
4072 pub dividend: f64,
4074 pub management_fee: f64,
4076 pub royalty: f64,
4078 pub cost_sharing: f64,
4080}
4081
4082impl Default for ICTransactionTypeDistribution {
4083 fn default() -> Self {
4084 Self {
4085 goods_sale: 0.35,
4086 service_provided: 0.20,
4087 loan: 0.10,
4088 dividend: 0.05,
4089 management_fee: 0.15,
4090 royalty: 0.10,
4091 cost_sharing: 0.05,
4092 }
4093 }
4094}
4095
4096#[derive(Debug, Clone, Serialize, Deserialize)]
4102pub struct BalanceConfig {
4103 #[serde(default)]
4105 pub generate_opening_balances: bool,
4106 #[serde(default = "default_true")]
4108 pub generate_trial_balances: bool,
4109 #[serde(default = "default_gross_margin")]
4111 pub target_gross_margin: f64,
4112 #[serde(default = "default_dso")]
4114 pub target_dso_days: u32,
4115 #[serde(default = "default_dpo")]
4117 pub target_dpo_days: u32,
4118 #[serde(default = "default_current_ratio")]
4120 pub target_current_ratio: f64,
4121 #[serde(default = "default_debt_equity")]
4123 pub target_debt_to_equity: f64,
4124 #[serde(default = "default_true")]
4126 pub validate_balance_equation: bool,
4127 #[serde(default = "default_true")]
4129 pub reconcile_subledgers: bool,
4130}
4131
4132fn default_gross_margin() -> f64 {
4133 0.35
4134}
4135
4136fn default_dso() -> u32 {
4137 45
4138}
4139
4140fn default_dpo() -> u32 {
4141 30
4142}
4143
4144fn default_current_ratio() -> f64 {
4145 1.5
4146}
4147
4148fn default_debt_equity() -> f64 {
4149 0.5
4150}
4151
4152impl Default for BalanceConfig {
4153 fn default() -> Self {
4154 Self {
4155 generate_opening_balances: false,
4156 generate_trial_balances: true,
4157 target_gross_margin: default_gross_margin(),
4158 target_dso_days: default_dso(),
4159 target_dpo_days: default_dpo(),
4160 target_current_ratio: default_current_ratio(),
4161 target_debt_to_equity: default_debt_equity(),
4162 validate_balance_equation: true,
4163 reconcile_subledgers: true,
4164 }
4165 }
4166}
4167
4168#[derive(Debug, Clone, Serialize, Deserialize)]
4177pub struct OcpmConfig {
4178 #[serde(default)]
4180 pub enabled: bool,
4181
4182 #[serde(default = "default_true")]
4184 pub generate_lifecycle_events: bool,
4185
4186 #[serde(default = "default_true")]
4188 pub include_object_relationships: bool,
4189
4190 #[serde(default = "default_true")]
4192 pub compute_variants: bool,
4193
4194 #[serde(default)]
4196 pub max_variants: usize,
4197
4198 #[serde(default)]
4200 pub p2p_process: OcpmProcessConfig,
4201
4202 #[serde(default)]
4204 pub o2c_process: OcpmProcessConfig,
4205
4206 #[serde(default)]
4208 pub output: OcpmOutputConfig,
4209}
4210
4211impl Default for OcpmConfig {
4212 fn default() -> Self {
4213 Self {
4214 enabled: false,
4215 generate_lifecycle_events: true,
4216 include_object_relationships: true,
4217 compute_variants: true,
4218 max_variants: 0,
4219 p2p_process: OcpmProcessConfig::default(),
4220 o2c_process: OcpmProcessConfig::default(),
4221 output: OcpmOutputConfig::default(),
4222 }
4223 }
4224}
4225
4226#[derive(Debug, Clone, Serialize, Deserialize)]
4228pub struct OcpmProcessConfig {
4229 #[serde(default = "default_rework_probability")]
4231 pub rework_probability: f64,
4232
4233 #[serde(default = "default_skip_probability")]
4235 pub skip_step_probability: f64,
4236
4237 #[serde(default = "default_out_of_order_probability")]
4239 pub out_of_order_probability: f64,
4240}
4241
4242fn default_rework_probability() -> f64 {
4246 0.15
4247}
4248
4249fn default_skip_probability() -> f64 {
4250 0.10
4251}
4252
4253fn default_out_of_order_probability() -> f64 {
4254 0.08
4255}
4256
4257impl Default for OcpmProcessConfig {
4258 fn default() -> Self {
4259 Self {
4260 rework_probability: default_rework_probability(),
4261 skip_step_probability: default_skip_probability(),
4262 out_of_order_probability: default_out_of_order_probability(),
4263 }
4264 }
4265}
4266
4267#[derive(Debug, Clone, Serialize, Deserialize)]
4269pub struct OcpmOutputConfig {
4270 #[serde(default = "default_true")]
4272 pub ocel_json: bool,
4273
4274 #[serde(default)]
4276 pub ocel_xml: bool,
4277
4278 #[serde(default)]
4280 pub xes: bool,
4281
4282 #[serde(default = "default_true")]
4284 pub xes_include_lifecycle: bool,
4285
4286 #[serde(default = "default_true")]
4288 pub xes_include_resources: bool,
4289
4290 #[serde(default = "default_true")]
4292 pub flattened_csv: bool,
4293
4294 #[serde(default = "default_true")]
4296 pub event_object_csv: bool,
4297
4298 #[serde(default = "default_true")]
4300 pub object_relationship_csv: bool,
4301
4302 #[serde(default = "default_true")]
4304 pub variants_csv: bool,
4305
4306 #[serde(default)]
4308 pub export_reference_models: bool,
4309}
4310
4311impl Default for OcpmOutputConfig {
4312 fn default() -> Self {
4313 Self {
4314 ocel_json: true,
4315 ocel_xml: false,
4316 xes: false,
4317 xes_include_lifecycle: true,
4318 xes_include_resources: true,
4319 flattened_csv: true,
4320 event_object_csv: true,
4321 object_relationship_csv: true,
4322 variants_csv: true,
4323 export_reference_models: false,
4324 }
4325 }
4326}
4327
4328#[derive(Debug, Clone, Serialize, Deserialize)]
4330pub struct AuditGenerationConfig {
4331 #[serde(default)]
4333 pub enabled: bool,
4334
4335 #[serde(default = "default_true")]
4339 pub generate_workpapers: bool,
4340
4341 #[serde(default)]
4344 pub engagement_types: AuditEngagementTypesConfig,
4345
4346 #[serde(default)]
4351 pub workpapers: WorkpaperConfig,
4352
4353 #[serde(default)]
4359 pub team: AuditTeamConfig,
4360
4361 #[serde(default)]
4368 pub review: ReviewWorkflowConfig,
4369
4370 #[serde(default)]
4372 pub fsm: Option<AuditFsmConfig>,
4373
4374 #[serde(default)]
4380 pub it_controls: ItControlsConfig,
4381}
4382
4383#[derive(Debug, Clone, Serialize, Deserialize)]
4385pub struct ItControlsConfig {
4386 #[serde(default)]
4389 pub enabled: bool,
4390 #[serde(default = "default_access_log_count")]
4393 pub access_logs_per_engagement: usize,
4394 #[serde(default = "default_change_record_count")]
4396 pub change_records_per_engagement: usize,
4397}
4398
4399fn default_access_log_count() -> usize {
4400 500
4401}
4402fn default_change_record_count() -> usize {
4403 50
4404}
4405
4406impl Default for ItControlsConfig {
4407 fn default() -> Self {
4408 Self {
4409 enabled: false,
4410 access_logs_per_engagement: default_access_log_count(),
4411 change_records_per_engagement: default_change_record_count(),
4412 }
4413 }
4414}
4415
4416impl Default for AuditGenerationConfig {
4417 fn default() -> Self {
4418 Self {
4419 enabled: false,
4420 generate_workpapers: true,
4421 engagement_types: AuditEngagementTypesConfig::default(),
4422 workpapers: WorkpaperConfig::default(),
4423 team: AuditTeamConfig::default(),
4424 review: ReviewWorkflowConfig::default(),
4425 fsm: None,
4426 it_controls: ItControlsConfig::default(),
4427 }
4428 }
4429}
4430
4431#[derive(Debug, Clone, Serialize, Deserialize)]
4433pub struct AuditFsmConfig {
4434 #[serde(default)]
4436 pub enabled: bool,
4437
4438 #[serde(default = "default_audit_fsm_blueprint")]
4440 pub blueprint: String,
4441
4442 #[serde(default = "default_audit_fsm_overlay")]
4444 pub overlay: String,
4445
4446 #[serde(default)]
4448 pub depth: Option<String>,
4449
4450 #[serde(default)]
4452 pub discriminators: std::collections::HashMap<String, Vec<String>>,
4453
4454 #[serde(default)]
4456 pub event_trail: AuditEventTrailConfig,
4457
4458 #[serde(default)]
4460 pub seed: Option<u64>,
4461}
4462
4463impl Default for AuditFsmConfig {
4464 fn default() -> Self {
4465 Self {
4466 enabled: false,
4467 blueprint: default_audit_fsm_blueprint(),
4468 overlay: default_audit_fsm_overlay(),
4469 depth: None,
4470 discriminators: std::collections::HashMap::new(),
4471 event_trail: AuditEventTrailConfig::default(),
4472 seed: None,
4473 }
4474 }
4475}
4476
4477fn default_audit_fsm_blueprint() -> String {
4478 "builtin:fsa".to_string()
4479}
4480
4481fn default_audit_fsm_overlay() -> String {
4482 "builtin:default".to_string()
4483}
4484
4485#[derive(Debug, Clone, Serialize, Deserialize)]
4487pub struct AuditEventTrailConfig {
4488 #[serde(default = "default_true")]
4490 pub flat_log: bool,
4491 #[serde(default)]
4493 pub ocel_projection: bool,
4494}
4495
4496impl Default for AuditEventTrailConfig {
4497 fn default() -> Self {
4498 Self {
4499 flat_log: true,
4500 ocel_projection: false,
4501 }
4502 }
4503}
4504
4505#[derive(Debug, Clone, Serialize, Deserialize)]
4507pub struct AuditEngagementTypesConfig {
4508 #[serde(default = "default_financial_audit_prob")]
4510 pub financial_statement: f64,
4511 #[serde(default = "default_sox_audit_prob")]
4513 pub sox_icfr: f64,
4514 #[serde(default = "default_integrated_audit_prob")]
4516 pub integrated: f64,
4517 #[serde(default = "default_review_prob")]
4519 pub review: f64,
4520 #[serde(default = "default_aup_prob")]
4522 pub agreed_upon_procedures: f64,
4523}
4524
4525fn default_financial_audit_prob() -> f64 {
4526 0.40
4527}
4528fn default_sox_audit_prob() -> f64 {
4529 0.20
4530}
4531fn default_integrated_audit_prob() -> f64 {
4532 0.25
4533}
4534fn default_review_prob() -> f64 {
4535 0.10
4536}
4537fn default_aup_prob() -> f64 {
4538 0.05
4539}
4540
4541impl Default for AuditEngagementTypesConfig {
4542 fn default() -> Self {
4543 Self {
4544 financial_statement: default_financial_audit_prob(),
4545 sox_icfr: default_sox_audit_prob(),
4546 integrated: default_integrated_audit_prob(),
4547 review: default_review_prob(),
4548 agreed_upon_procedures: default_aup_prob(),
4549 }
4550 }
4551}
4552
4553#[derive(Debug, Clone, Serialize, Deserialize)]
4555pub struct WorkpaperConfig {
4556 #[serde(default = "default_workpapers_per_phase")]
4558 pub average_per_phase: usize,
4559
4560 #[serde(default = "default_true")]
4562 pub include_isa_references: bool,
4563
4564 #[serde(default = "default_true")]
4566 pub include_sample_details: bool,
4567
4568 #[serde(default = "default_true")]
4570 pub include_cross_references: bool,
4571
4572 #[serde(default)]
4574 pub sampling: SamplingConfig,
4575}
4576
4577fn default_workpapers_per_phase() -> usize {
4578 5
4579}
4580
4581impl Default for WorkpaperConfig {
4582 fn default() -> Self {
4583 Self {
4584 average_per_phase: default_workpapers_per_phase(),
4585 include_isa_references: true,
4586 include_sample_details: true,
4587 include_cross_references: true,
4588 sampling: SamplingConfig::default(),
4589 }
4590 }
4591}
4592
4593#[derive(Debug, Clone, Serialize, Deserialize)]
4595pub struct SamplingConfig {
4596 #[serde(default = "default_statistical_rate")]
4598 pub statistical_rate: f64,
4599 #[serde(default = "default_judgmental_rate")]
4601 pub judgmental_rate: f64,
4602 #[serde(default = "default_haphazard_rate")]
4604 pub haphazard_rate: f64,
4605 #[serde(default = "default_complete_examination_rate")]
4607 pub complete_examination_rate: f64,
4608}
4609
4610fn default_statistical_rate() -> f64 {
4611 0.40
4612}
4613fn default_judgmental_rate() -> f64 {
4614 0.30
4615}
4616fn default_haphazard_rate() -> f64 {
4617 0.20
4618}
4619fn default_complete_examination_rate() -> f64 {
4620 0.10
4621}
4622
4623impl Default for SamplingConfig {
4624 fn default() -> Self {
4625 Self {
4626 statistical_rate: default_statistical_rate(),
4627 judgmental_rate: default_judgmental_rate(),
4628 haphazard_rate: default_haphazard_rate(),
4629 complete_examination_rate: default_complete_examination_rate(),
4630 }
4631 }
4632}
4633
4634#[derive(Debug, Clone, Serialize, Deserialize)]
4636pub struct AuditTeamConfig {
4637 #[serde(default = "default_min_team_size")]
4639 pub min_team_size: usize,
4640 #[serde(default = "default_max_team_size")]
4642 pub max_team_size: usize,
4643 #[serde(default = "default_specialist_probability")]
4645 pub specialist_probability: f64,
4646}
4647
4648fn default_min_team_size() -> usize {
4649 3
4650}
4651fn default_max_team_size() -> usize {
4652 8
4653}
4654fn default_specialist_probability() -> f64 {
4655 0.30
4656}
4657
4658impl Default for AuditTeamConfig {
4659 fn default() -> Self {
4660 Self {
4661 min_team_size: default_min_team_size(),
4662 max_team_size: default_max_team_size(),
4663 specialist_probability: default_specialist_probability(),
4664 }
4665 }
4666}
4667
4668#[derive(Debug, Clone, Serialize, Deserialize)]
4670pub struct ReviewWorkflowConfig {
4671 #[serde(default = "default_review_delay_days")]
4673 pub average_review_delay_days: u32,
4674 #[serde(default = "default_rework_probability_review")]
4676 pub rework_probability: f64,
4677 #[serde(default = "default_true")]
4679 pub require_partner_signoff: bool,
4680}
4681
4682fn default_review_delay_days() -> u32 {
4683 2
4684}
4685fn default_rework_probability_review() -> f64 {
4686 0.15
4687}
4688
4689impl Default for ReviewWorkflowConfig {
4690 fn default() -> Self {
4691 Self {
4692 average_review_delay_days: default_review_delay_days(),
4693 rework_probability: default_rework_probability_review(),
4694 require_partner_signoff: true,
4695 }
4696 }
4697}
4698
4699#[derive(Debug, Clone, Serialize, Deserialize)]
4705pub struct DataQualitySchemaConfig {
4706 #[serde(default)]
4708 pub enabled: bool,
4709 #[serde(default)]
4711 pub preset: DataQualityPreset,
4712 #[serde(default)]
4714 pub missing_values: MissingValuesSchemaConfig,
4715 #[serde(default)]
4717 pub typos: TypoSchemaConfig,
4718 #[serde(default)]
4720 pub format_variations: FormatVariationSchemaConfig,
4721 #[serde(default)]
4723 pub duplicates: DuplicateSchemaConfig,
4724 #[serde(default)]
4726 pub encoding_issues: EncodingIssueSchemaConfig,
4727 #[serde(default)]
4729 pub generate_labels: bool,
4730 #[serde(default)]
4732 pub sink_profiles: SinkQualityProfiles,
4733}
4734
4735impl Default for DataQualitySchemaConfig {
4736 fn default() -> Self {
4737 Self {
4738 enabled: false,
4739 preset: DataQualityPreset::None,
4740 missing_values: MissingValuesSchemaConfig::default(),
4741 typos: TypoSchemaConfig::default(),
4742 format_variations: FormatVariationSchemaConfig::default(),
4743 duplicates: DuplicateSchemaConfig::default(),
4744 encoding_issues: EncodingIssueSchemaConfig::default(),
4745 generate_labels: true,
4746 sink_profiles: SinkQualityProfiles::default(),
4747 }
4748 }
4749}
4750
4751impl DataQualitySchemaConfig {
4752 pub fn with_preset(preset: DataQualityPreset) -> Self {
4754 let mut config = Self {
4755 preset,
4756 ..Default::default()
4757 };
4758 config.apply_preset();
4759 config
4760 }
4761
4762 pub fn apply_preset(&mut self) {
4765 if !self.preset.overrides_settings() {
4766 return;
4767 }
4768
4769 self.enabled = true;
4770
4771 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4773 self.missing_values.rate = self.preset.missing_rate();
4774
4775 self.typos.enabled = self.preset.typo_rate() > 0.0;
4777 self.typos.char_error_rate = self.preset.typo_rate();
4778
4779 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4781 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4782 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4783 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4784
4785 self.format_variations.enabled = self.preset.format_variations_enabled();
4787
4788 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4790 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4791
4792 if self.preset.ocr_errors_enabled() {
4794 self.typos.type_weights.ocr_errors = 0.3;
4795 }
4796 }
4797
4798 pub fn effective_missing_rate(&self) -> f64 {
4800 if self.preset.overrides_settings() {
4801 self.preset.missing_rate()
4802 } else {
4803 self.missing_values.rate
4804 }
4805 }
4806
4807 pub fn effective_typo_rate(&self) -> f64 {
4809 if self.preset.overrides_settings() {
4810 self.preset.typo_rate()
4811 } else {
4812 self.typos.char_error_rate
4813 }
4814 }
4815
4816 pub fn effective_duplicate_rate(&self) -> f64 {
4818 if self.preset.overrides_settings() {
4819 self.preset.duplicate_rate()
4820 } else {
4821 self.duplicates.exact_duplicate_ratio
4822 + self.duplicates.near_duplicate_ratio
4823 + self.duplicates.fuzzy_duplicate_ratio
4824 }
4825 }
4826
4827 pub fn clean() -> Self {
4829 Self::with_preset(DataQualityPreset::Clean)
4830 }
4831
4832 pub fn noisy() -> Self {
4834 Self::with_preset(DataQualityPreset::Noisy)
4835 }
4836
4837 pub fn legacy() -> Self {
4839 Self::with_preset(DataQualityPreset::Legacy)
4840 }
4841}
4842
4843#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4845#[serde(rename_all = "snake_case")]
4846pub enum DataQualityPreset {
4847 #[default]
4849 None,
4850 Minimal,
4852 Normal,
4854 High,
4856 Custom,
4858
4859 Clean,
4865 Noisy,
4868 Legacy,
4871}
4872
4873impl DataQualityPreset {
4874 pub fn missing_rate(&self) -> f64 {
4876 match self {
4877 DataQualityPreset::None => 0.0,
4878 DataQualityPreset::Minimal => 0.005,
4879 DataQualityPreset::Normal => 0.02,
4880 DataQualityPreset::High => 0.08,
4881 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4883 DataQualityPreset::Noisy => 0.05,
4884 DataQualityPreset::Legacy => 0.10,
4885 }
4886 }
4887
4888 pub fn typo_rate(&self) -> f64 {
4890 match self {
4891 DataQualityPreset::None => 0.0,
4892 DataQualityPreset::Minimal => 0.0005,
4893 DataQualityPreset::Normal => 0.002,
4894 DataQualityPreset::High => 0.01,
4895 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4897 DataQualityPreset::Noisy => 0.02,
4898 DataQualityPreset::Legacy => 0.05,
4899 }
4900 }
4901
4902 pub fn duplicate_rate(&self) -> f64 {
4904 match self {
4905 DataQualityPreset::None => 0.0,
4906 DataQualityPreset::Minimal => 0.001,
4907 DataQualityPreset::Normal => 0.005,
4908 DataQualityPreset::High => 0.02,
4909 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4911 DataQualityPreset::Noisy => 0.01,
4912 DataQualityPreset::Legacy => 0.03,
4913 }
4914 }
4915
4916 pub fn format_variations_enabled(&self) -> bool {
4918 match self {
4919 DataQualityPreset::None | DataQualityPreset::Clean => false,
4920 DataQualityPreset::Minimal => true,
4921 DataQualityPreset::Normal => true,
4922 DataQualityPreset::High => true,
4923 DataQualityPreset::Custom => true,
4924 DataQualityPreset::Noisy => true,
4925 DataQualityPreset::Legacy => true,
4926 }
4927 }
4928
4929 pub fn ocr_errors_enabled(&self) -> bool {
4931 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4932 }
4933
4934 pub fn encoding_issues_enabled(&self) -> bool {
4936 matches!(
4937 self,
4938 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4939 )
4940 }
4941
4942 pub fn encoding_issue_rate(&self) -> f64 {
4944 match self {
4945 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4946 DataQualityPreset::Normal => 0.002,
4947 DataQualityPreset::High => 0.01,
4948 DataQualityPreset::Custom => 0.0,
4949 DataQualityPreset::Noisy => 0.005,
4950 DataQualityPreset::Legacy => 0.02,
4951 }
4952 }
4953
4954 pub fn overrides_settings(&self) -> bool {
4956 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4957 }
4958
4959 pub fn description(&self) -> &'static str {
4961 match self {
4962 DataQualityPreset::None => "No data quality issues (pristine data)",
4963 DataQualityPreset::Minimal => "Very rare data quality issues",
4964 DataQualityPreset::Normal => "Realistic enterprise data quality",
4965 DataQualityPreset::High => "Messy data for stress testing",
4966 DataQualityPreset::Custom => "Custom settings from configuration",
4967 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4968 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4969 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4970 }
4971 }
4972}
4973
4974#[derive(Debug, Clone, Serialize, Deserialize)]
4976pub struct MissingValuesSchemaConfig {
4977 #[serde(default)]
4979 pub enabled: bool,
4980 #[serde(default = "default_missing_rate")]
4982 pub rate: f64,
4983 #[serde(default)]
4985 pub strategy: MissingValueStrategy,
4986 #[serde(default)]
4988 pub field_rates: std::collections::HashMap<String, f64>,
4989 #[serde(default)]
4991 pub protected_fields: Vec<String>,
4992}
4993
4994fn default_missing_rate() -> f64 {
4995 0.01
4996}
4997
4998impl Default for MissingValuesSchemaConfig {
4999 fn default() -> Self {
5000 Self {
5001 enabled: false,
5002 rate: default_missing_rate(),
5003 strategy: MissingValueStrategy::Mcar,
5004 field_rates: std::collections::HashMap::new(),
5005 protected_fields: vec![
5006 "document_id".to_string(),
5007 "company_code".to_string(),
5008 "posting_date".to_string(),
5009 ],
5010 }
5011 }
5012}
5013
5014#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5016#[serde(rename_all = "snake_case")]
5017pub enum MissingValueStrategy {
5018 #[default]
5020 Mcar,
5021 Mar,
5023 Mnar,
5025 Systematic,
5027}
5028
5029#[derive(Debug, Clone, Serialize, Deserialize)]
5031pub struct TypoSchemaConfig {
5032 #[serde(default)]
5034 pub enabled: bool,
5035 #[serde(default = "default_typo_rate")]
5037 pub char_error_rate: f64,
5038 #[serde(default)]
5040 pub type_weights: TypoTypeWeights,
5041 #[serde(default)]
5043 pub protected_fields: Vec<String>,
5044}
5045
5046fn default_typo_rate() -> f64 {
5047 0.001
5048}
5049
5050impl Default for TypoSchemaConfig {
5051 fn default() -> Self {
5052 Self {
5053 enabled: false,
5054 char_error_rate: default_typo_rate(),
5055 type_weights: TypoTypeWeights::default(),
5056 protected_fields: vec![
5057 "document_id".to_string(),
5058 "gl_account".to_string(),
5059 "company_code".to_string(),
5060 ],
5061 }
5062 }
5063}
5064
5065#[derive(Debug, Clone, Serialize, Deserialize)]
5067pub struct TypoTypeWeights {
5068 #[serde(default = "default_substitution_weight")]
5070 pub substitution: f64,
5071 #[serde(default = "default_transposition_weight")]
5073 pub transposition: f64,
5074 #[serde(default = "default_insertion_weight")]
5076 pub insertion: f64,
5077 #[serde(default = "default_deletion_weight")]
5079 pub deletion: f64,
5080 #[serde(default = "default_ocr_weight")]
5082 pub ocr_errors: f64,
5083 #[serde(default = "default_homophone_weight")]
5085 pub homophones: f64,
5086}
5087
5088fn default_substitution_weight() -> f64 {
5089 0.35
5090}
5091fn default_transposition_weight() -> f64 {
5092 0.25
5093}
5094fn default_insertion_weight() -> f64 {
5095 0.10
5096}
5097fn default_deletion_weight() -> f64 {
5098 0.15
5099}
5100fn default_ocr_weight() -> f64 {
5101 0.10
5102}
5103fn default_homophone_weight() -> f64 {
5104 0.05
5105}
5106
5107impl Default for TypoTypeWeights {
5108 fn default() -> Self {
5109 Self {
5110 substitution: default_substitution_weight(),
5111 transposition: default_transposition_weight(),
5112 insertion: default_insertion_weight(),
5113 deletion: default_deletion_weight(),
5114 ocr_errors: default_ocr_weight(),
5115 homophones: default_homophone_weight(),
5116 }
5117 }
5118}
5119
5120#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5122pub struct FormatVariationSchemaConfig {
5123 #[serde(default)]
5125 pub enabled: bool,
5126 #[serde(default)]
5128 pub dates: DateFormatVariationConfig,
5129 #[serde(default)]
5131 pub amounts: AmountFormatVariationConfig,
5132 #[serde(default)]
5134 pub identifiers: IdentifierFormatVariationConfig,
5135}
5136
5137#[derive(Debug, Clone, Serialize, Deserialize)]
5139pub struct DateFormatVariationConfig {
5140 #[serde(default)]
5142 pub enabled: bool,
5143 #[serde(default = "default_date_variation_rate")]
5145 pub rate: f64,
5146 #[serde(default = "default_true")]
5148 pub iso_format: bool,
5149 #[serde(default)]
5151 pub us_format: bool,
5152 #[serde(default)]
5154 pub eu_format: bool,
5155 #[serde(default)]
5157 pub long_format: bool,
5158}
5159
5160fn default_date_variation_rate() -> f64 {
5161 0.05
5162}
5163
5164impl Default for DateFormatVariationConfig {
5165 fn default() -> Self {
5166 Self {
5167 enabled: false,
5168 rate: default_date_variation_rate(),
5169 iso_format: true,
5170 us_format: false,
5171 eu_format: false,
5172 long_format: false,
5173 }
5174 }
5175}
5176
5177#[derive(Debug, Clone, Serialize, Deserialize)]
5179pub struct AmountFormatVariationConfig {
5180 #[serde(default)]
5182 pub enabled: bool,
5183 #[serde(default = "default_amount_variation_rate")]
5185 pub rate: f64,
5186 #[serde(default)]
5188 pub us_comma_format: bool,
5189 #[serde(default)]
5191 pub eu_format: bool,
5192 #[serde(default)]
5194 pub currency_prefix: bool,
5195 #[serde(default)]
5197 pub accounting_format: bool,
5198}
5199
5200fn default_amount_variation_rate() -> f64 {
5201 0.02
5202}
5203
5204impl Default for AmountFormatVariationConfig {
5205 fn default() -> Self {
5206 Self {
5207 enabled: false,
5208 rate: default_amount_variation_rate(),
5209 us_comma_format: false,
5210 eu_format: false,
5211 currency_prefix: false,
5212 accounting_format: false,
5213 }
5214 }
5215}
5216
5217#[derive(Debug, Clone, Serialize, Deserialize)]
5219pub struct IdentifierFormatVariationConfig {
5220 #[serde(default)]
5222 pub enabled: bool,
5223 #[serde(default = "default_identifier_variation_rate")]
5225 pub rate: f64,
5226 #[serde(default)]
5228 pub case_variations: bool,
5229 #[serde(default)]
5231 pub padding_variations: bool,
5232 #[serde(default)]
5234 pub separator_variations: bool,
5235}
5236
5237fn default_identifier_variation_rate() -> f64 {
5238 0.02
5239}
5240
5241impl Default for IdentifierFormatVariationConfig {
5242 fn default() -> Self {
5243 Self {
5244 enabled: false,
5245 rate: default_identifier_variation_rate(),
5246 case_variations: false,
5247 padding_variations: false,
5248 separator_variations: false,
5249 }
5250 }
5251}
5252
5253#[derive(Debug, Clone, Serialize, Deserialize)]
5255pub struct DuplicateSchemaConfig {
5256 #[serde(default)]
5258 pub enabled: bool,
5259 #[serde(default = "default_duplicate_rate")]
5261 pub rate: f64,
5262 #[serde(default = "default_exact_duplicate_ratio")]
5264 pub exact_duplicate_ratio: f64,
5265 #[serde(default = "default_near_duplicate_ratio")]
5267 pub near_duplicate_ratio: f64,
5268 #[serde(default = "default_fuzzy_duplicate_ratio")]
5270 pub fuzzy_duplicate_ratio: f64,
5271 #[serde(default = "default_max_date_offset")]
5273 pub max_date_offset_days: u32,
5274 #[serde(default = "default_max_amount_variance")]
5276 pub max_amount_variance: f64,
5277}
5278
5279fn default_duplicate_rate() -> f64 {
5280 0.005
5281}
5282fn default_exact_duplicate_ratio() -> f64 {
5283 0.4
5284}
5285fn default_near_duplicate_ratio() -> f64 {
5286 0.35
5287}
5288fn default_fuzzy_duplicate_ratio() -> f64 {
5289 0.25
5290}
5291fn default_max_date_offset() -> u32 {
5292 3
5293}
5294fn default_max_amount_variance() -> f64 {
5295 0.01
5296}
5297
5298impl Default for DuplicateSchemaConfig {
5299 fn default() -> Self {
5300 Self {
5301 enabled: false,
5302 rate: default_duplicate_rate(),
5303 exact_duplicate_ratio: default_exact_duplicate_ratio(),
5304 near_duplicate_ratio: default_near_duplicate_ratio(),
5305 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
5306 max_date_offset_days: default_max_date_offset(),
5307 max_amount_variance: default_max_amount_variance(),
5308 }
5309 }
5310}
5311
5312#[derive(Debug, Clone, Serialize, Deserialize)]
5314pub struct EncodingIssueSchemaConfig {
5315 #[serde(default)]
5317 pub enabled: bool,
5318 #[serde(default = "default_encoding_rate")]
5320 pub rate: f64,
5321 #[serde(default)]
5323 pub mojibake: bool,
5324 #[serde(default)]
5326 pub html_entities: bool,
5327 #[serde(default)]
5329 pub bom_issues: bool,
5330}
5331
5332fn default_encoding_rate() -> f64 {
5333 0.001
5334}
5335
5336impl Default for EncodingIssueSchemaConfig {
5337 fn default() -> Self {
5338 Self {
5339 enabled: false,
5340 rate: default_encoding_rate(),
5341 mojibake: false,
5342 html_entities: false,
5343 bom_issues: false,
5344 }
5345 }
5346}
5347
5348#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5350pub struct SinkQualityProfiles {
5351 #[serde(default)]
5353 pub csv: Option<SinkQualityOverride>,
5354 #[serde(default)]
5356 pub json: Option<SinkQualityOverride>,
5357 #[serde(default)]
5359 pub parquet: Option<SinkQualityOverride>,
5360}
5361
5362#[derive(Debug, Clone, Serialize, Deserialize)]
5364pub struct SinkQualityOverride {
5365 pub enabled: Option<bool>,
5367 pub missing_rate: Option<f64>,
5369 pub typo_rate: Option<f64>,
5371 pub format_variation_rate: Option<f64>,
5373 pub duplicate_rate: Option<f64>,
5375}
5376
5377#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5389pub struct AccountingStandardsConfig {
5390 #[serde(default)]
5392 pub enabled: bool,
5393
5394 #[serde(default, skip_serializing_if = "Option::is_none")]
5398 pub framework: Option<AccountingFrameworkConfig>,
5399
5400 #[serde(default)]
5402 pub revenue_recognition: RevenueRecognitionConfig,
5403
5404 #[serde(default)]
5406 pub leases: LeaseAccountingConfig,
5407
5408 #[serde(default)]
5410 pub fair_value: FairValueConfig,
5411
5412 #[serde(default)]
5414 pub impairment: ImpairmentConfig,
5415
5416 #[serde(default)]
5418 pub business_combinations: BusinessCombinationsConfig,
5419
5420 #[serde(default)]
5422 pub expected_credit_loss: EclConfig,
5423
5424 #[serde(default)]
5426 pub generate_differences: bool,
5427}
5428
5429#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5431#[serde(rename_all = "snake_case")]
5432pub enum AccountingFrameworkConfig {
5433 #[default]
5435 UsGaap,
5436 Ifrs,
5438 DualReporting,
5440 FrenchGaap,
5442 GermanGaap,
5444}
5445
5446#[derive(Debug, Clone, Serialize, Deserialize)]
5448pub struct RevenueRecognitionConfig {
5449 #[serde(default)]
5451 pub enabled: bool,
5452
5453 #[serde(default = "default_true")]
5455 pub generate_contracts: bool,
5456
5457 #[serde(default = "default_avg_obligations")]
5459 pub avg_obligations_per_contract: f64,
5460
5461 #[serde(default = "default_variable_consideration_rate")]
5463 pub variable_consideration_rate: f64,
5464
5465 #[serde(default = "default_over_time_rate")]
5467 pub over_time_recognition_rate: f64,
5468
5469 #[serde(default = "default_contract_count")]
5471 pub contract_count: usize,
5472}
5473
5474fn default_avg_obligations() -> f64 {
5475 2.0
5476}
5477
5478fn default_variable_consideration_rate() -> f64 {
5479 0.15
5480}
5481
5482fn default_over_time_rate() -> f64 {
5483 0.30
5484}
5485
5486fn default_contract_count() -> usize {
5487 100
5488}
5489
5490impl Default for RevenueRecognitionConfig {
5491 fn default() -> Self {
5492 Self {
5493 enabled: false,
5494 generate_contracts: true,
5495 avg_obligations_per_contract: default_avg_obligations(),
5496 variable_consideration_rate: default_variable_consideration_rate(),
5497 over_time_recognition_rate: default_over_time_rate(),
5498 contract_count: default_contract_count(),
5499 }
5500 }
5501}
5502
5503#[derive(Debug, Clone, Serialize, Deserialize)]
5505pub struct LeaseAccountingConfig {
5506 #[serde(default)]
5508 pub enabled: bool,
5509
5510 #[serde(default = "default_lease_count")]
5512 pub lease_count: usize,
5513
5514 #[serde(default = "default_finance_lease_pct")]
5516 pub finance_lease_percent: f64,
5517
5518 #[serde(default = "default_avg_lease_term")]
5520 pub avg_lease_term_months: u32,
5521
5522 #[serde(default = "default_true")]
5524 pub generate_amortization: bool,
5525
5526 #[serde(default = "default_real_estate_pct")]
5528 pub real_estate_percent: f64,
5529}
5530
5531fn default_lease_count() -> usize {
5532 50
5533}
5534
5535fn default_finance_lease_pct() -> f64 {
5536 0.30
5537}
5538
5539fn default_avg_lease_term() -> u32 {
5540 60
5541}
5542
5543fn default_real_estate_pct() -> f64 {
5544 0.40
5545}
5546
5547impl Default for LeaseAccountingConfig {
5548 fn default() -> Self {
5549 Self {
5550 enabled: false,
5551 lease_count: default_lease_count(),
5552 finance_lease_percent: default_finance_lease_pct(),
5553 avg_lease_term_months: default_avg_lease_term(),
5554 generate_amortization: true,
5555 real_estate_percent: default_real_estate_pct(),
5556 }
5557 }
5558}
5559
5560#[derive(Debug, Clone, Serialize, Deserialize)]
5562pub struct FairValueConfig {
5563 #[serde(default)]
5565 pub enabled: bool,
5566
5567 #[serde(default = "default_fv_count")]
5569 pub measurement_count: usize,
5570
5571 #[serde(default = "default_level1_pct")]
5573 pub level1_percent: f64,
5574
5575 #[serde(default = "default_level2_pct")]
5577 pub level2_percent: f64,
5578
5579 #[serde(default = "default_level3_pct")]
5581 pub level3_percent: f64,
5582
5583 #[serde(default)]
5585 pub include_sensitivity_analysis: bool,
5586}
5587
5588fn default_fv_count() -> usize {
5589 25
5590}
5591
5592fn default_level1_pct() -> f64 {
5593 0.40
5594}
5595
5596fn default_level2_pct() -> f64 {
5597 0.35
5598}
5599
5600fn default_level3_pct() -> f64 {
5601 0.25
5602}
5603
5604impl Default for FairValueConfig {
5605 fn default() -> Self {
5606 Self {
5607 enabled: false,
5608 measurement_count: default_fv_count(),
5609 level1_percent: default_level1_pct(),
5610 level2_percent: default_level2_pct(),
5611 level3_percent: default_level3_pct(),
5612 include_sensitivity_analysis: false,
5613 }
5614 }
5615}
5616
5617#[derive(Debug, Clone, Serialize, Deserialize)]
5619pub struct ImpairmentConfig {
5620 #[serde(default)]
5622 pub enabled: bool,
5623
5624 #[serde(default = "default_impairment_count")]
5626 pub test_count: usize,
5627
5628 #[serde(default = "default_impairment_rate")]
5630 pub impairment_rate: f64,
5631
5632 #[serde(default = "default_true")]
5634 pub generate_projections: bool,
5635
5636 #[serde(default)]
5638 pub include_goodwill: bool,
5639}
5640
5641fn default_impairment_count() -> usize {
5642 15
5643}
5644
5645fn default_impairment_rate() -> f64 {
5646 0.10
5647}
5648
5649impl Default for ImpairmentConfig {
5650 fn default() -> Self {
5651 Self {
5652 enabled: false,
5653 test_count: default_impairment_count(),
5654 impairment_rate: default_impairment_rate(),
5655 generate_projections: true,
5656 include_goodwill: false,
5657 }
5658 }
5659}
5660
5661#[derive(Debug, Clone, Serialize, Deserialize)]
5667pub struct BusinessCombinationsConfig {
5668 #[serde(default)]
5670 pub enabled: bool,
5671
5672 #[serde(default = "default_bc_acquisition_count")]
5674 pub acquisition_count: usize,
5675}
5676
5677fn default_bc_acquisition_count() -> usize {
5678 2
5679}
5680
5681impl Default for BusinessCombinationsConfig {
5682 fn default() -> Self {
5683 Self {
5684 enabled: false,
5685 acquisition_count: default_bc_acquisition_count(),
5686 }
5687 }
5688}
5689
5690#[derive(Debug, Clone, Serialize, Deserialize)]
5696pub struct EclConfig {
5697 #[serde(default)]
5699 pub enabled: bool,
5700
5701 #[serde(default = "default_ecl_base_weight")]
5703 pub base_scenario_weight: f64,
5704
5705 #[serde(default = "default_ecl_base_multiplier")]
5707 pub base_scenario_multiplier: f64,
5708
5709 #[serde(default = "default_ecl_optimistic_weight")]
5711 pub optimistic_scenario_weight: f64,
5712
5713 #[serde(default = "default_ecl_optimistic_multiplier")]
5715 pub optimistic_scenario_multiplier: f64,
5716
5717 #[serde(default = "default_ecl_pessimistic_weight")]
5719 pub pessimistic_scenario_weight: f64,
5720
5721 #[serde(default = "default_ecl_pessimistic_multiplier")]
5723 pub pessimistic_scenario_multiplier: f64,
5724}
5725
5726fn default_ecl_base_weight() -> f64 {
5727 0.50
5728}
5729fn default_ecl_base_multiplier() -> f64 {
5730 1.0
5731}
5732fn default_ecl_optimistic_weight() -> f64 {
5733 0.30
5734}
5735fn default_ecl_optimistic_multiplier() -> f64 {
5736 0.8
5737}
5738fn default_ecl_pessimistic_weight() -> f64 {
5739 0.20
5740}
5741fn default_ecl_pessimistic_multiplier() -> f64 {
5742 1.4
5743}
5744
5745impl Default for EclConfig {
5746 fn default() -> Self {
5747 Self {
5748 enabled: false,
5749 base_scenario_weight: default_ecl_base_weight(),
5750 base_scenario_multiplier: default_ecl_base_multiplier(),
5751 optimistic_scenario_weight: default_ecl_optimistic_weight(),
5752 optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5753 pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5754 pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5755 }
5756 }
5757}
5758
5759#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5772pub struct AuditStandardsConfig {
5773 #[serde(default)]
5775 pub enabled: bool,
5776
5777 #[serde(default)]
5779 pub isa_compliance: IsaComplianceConfig,
5780
5781 #[serde(default)]
5783 pub analytical_procedures: AnalyticalProceduresConfig,
5784
5785 #[serde(default)]
5787 pub confirmations: ConfirmationsConfig,
5788
5789 #[serde(default)]
5791 pub opinion: AuditOpinionConfig,
5792
5793 #[serde(default)]
5795 pub generate_audit_trail: bool,
5796
5797 #[serde(default)]
5799 pub sox: SoxComplianceConfig,
5800
5801 #[serde(default)]
5803 pub pcaob: PcaobConfig,
5804}
5805
5806#[derive(Debug, Clone, Serialize, Deserialize)]
5808pub struct IsaComplianceConfig {
5809 #[serde(default)]
5811 pub enabled: bool,
5812
5813 #[serde(default = "default_compliance_level")]
5815 pub compliance_level: String,
5816
5817 #[serde(default = "default_true")]
5819 pub generate_isa_mappings: bool,
5820
5821 #[serde(default = "default_true")]
5823 pub generate_coverage_summary: bool,
5824
5825 #[serde(default)]
5827 pub include_pcaob: bool,
5828
5829 #[serde(default = "default_audit_framework")]
5831 pub framework: String,
5832}
5833
5834fn default_compliance_level() -> String {
5835 "standard".to_string()
5836}
5837
5838fn default_audit_framework() -> String {
5839 "isa".to_string()
5840}
5841
5842impl Default for IsaComplianceConfig {
5843 fn default() -> Self {
5844 Self {
5845 enabled: false,
5846 compliance_level: default_compliance_level(),
5847 generate_isa_mappings: true,
5848 generate_coverage_summary: true,
5849 include_pcaob: false,
5850 framework: default_audit_framework(),
5851 }
5852 }
5853}
5854
5855#[derive(Debug, Clone, Serialize, Deserialize)]
5857pub struct AnalyticalProceduresConfig {
5858 #[serde(default)]
5860 pub enabled: bool,
5861
5862 #[serde(default = "default_procedures_per_account")]
5864 pub procedures_per_account: usize,
5865
5866 #[serde(default = "default_variance_probability")]
5868 pub variance_probability: f64,
5869
5870 #[serde(default = "default_true")]
5872 pub generate_investigations: bool,
5873
5874 #[serde(default = "default_true")]
5876 pub include_ratio_analysis: bool,
5877}
5878
5879fn default_procedures_per_account() -> usize {
5880 3
5881}
5882
5883fn default_variance_probability() -> f64 {
5884 0.20
5885}
5886
5887impl Default for AnalyticalProceduresConfig {
5888 fn default() -> Self {
5889 Self {
5890 enabled: false,
5891 procedures_per_account: default_procedures_per_account(),
5892 variance_probability: default_variance_probability(),
5893 generate_investigations: true,
5894 include_ratio_analysis: true,
5895 }
5896 }
5897}
5898
5899#[derive(Debug, Clone, Serialize, Deserialize)]
5901pub struct ConfirmationsConfig {
5902 #[serde(default)]
5904 pub enabled: bool,
5905
5906 #[serde(default = "default_confirmation_count")]
5908 pub confirmation_count: usize,
5909
5910 #[serde(default = "default_positive_response_rate")]
5912 pub positive_response_rate: f64,
5913
5914 #[serde(default = "default_exception_rate_confirm")]
5916 pub exception_rate: f64,
5917
5918 #[serde(default = "default_non_response_rate")]
5920 pub non_response_rate: f64,
5921
5922 #[serde(default = "default_true")]
5924 pub generate_alternative_procedures: bool,
5925}
5926
5927fn default_confirmation_count() -> usize {
5928 50
5929}
5930
5931fn default_positive_response_rate() -> f64 {
5932 0.85
5933}
5934
5935fn default_exception_rate_confirm() -> f64 {
5936 0.10
5937}
5938
5939fn default_non_response_rate() -> f64 {
5940 0.05
5941}
5942
5943impl Default for ConfirmationsConfig {
5944 fn default() -> Self {
5945 Self {
5946 enabled: false,
5947 confirmation_count: default_confirmation_count(),
5948 positive_response_rate: default_positive_response_rate(),
5949 exception_rate: default_exception_rate_confirm(),
5950 non_response_rate: default_non_response_rate(),
5951 generate_alternative_procedures: true,
5952 }
5953 }
5954}
5955
5956#[derive(Debug, Clone, Serialize, Deserialize)]
5958pub struct AuditOpinionConfig {
5959 #[serde(default)]
5961 pub enabled: bool,
5962
5963 #[serde(default = "default_true")]
5965 pub generate_kam: bool,
5966
5967 #[serde(default = "default_kam_count")]
5969 pub average_kam_count: usize,
5970
5971 #[serde(default = "default_modified_opinion_rate")]
5973 pub modified_opinion_rate: f64,
5974
5975 #[serde(default)]
5977 pub include_emphasis_of_matter: bool,
5978
5979 #[serde(default = "default_true")]
5981 pub include_going_concern: bool,
5982}
5983
5984fn default_kam_count() -> usize {
5985 3
5986}
5987
5988fn default_modified_opinion_rate() -> f64 {
5989 0.05
5990}
5991
5992impl Default for AuditOpinionConfig {
5993 fn default() -> Self {
5994 Self {
5995 enabled: false,
5996 generate_kam: true,
5997 average_kam_count: default_kam_count(),
5998 modified_opinion_rate: default_modified_opinion_rate(),
5999 include_emphasis_of_matter: false,
6000 include_going_concern: true,
6001 }
6002 }
6003}
6004
6005#[derive(Debug, Clone, Serialize, Deserialize)]
6007pub struct SoxComplianceConfig {
6008 #[serde(default)]
6010 pub enabled: bool,
6011
6012 #[serde(default = "default_true")]
6014 pub generate_302_certifications: bool,
6015
6016 #[serde(default = "default_true")]
6018 pub generate_404_assessments: bool,
6019
6020 #[serde(default = "default_sox_materiality_threshold")]
6022 pub materiality_threshold: f64,
6023
6024 #[serde(default = "default_material_weakness_rate")]
6026 pub material_weakness_rate: f64,
6027
6028 #[serde(default = "default_significant_deficiency_rate")]
6030 pub significant_deficiency_rate: f64,
6031}
6032
6033fn default_material_weakness_rate() -> f64 {
6034 0.02
6035}
6036
6037fn default_significant_deficiency_rate() -> f64 {
6038 0.08
6039}
6040
6041impl Default for SoxComplianceConfig {
6042 fn default() -> Self {
6043 Self {
6044 enabled: false,
6045 generate_302_certifications: true,
6046 generate_404_assessments: true,
6047 materiality_threshold: default_sox_materiality_threshold(),
6048 material_weakness_rate: default_material_weakness_rate(),
6049 significant_deficiency_rate: default_significant_deficiency_rate(),
6050 }
6051 }
6052}
6053
6054#[derive(Debug, Clone, Serialize, Deserialize)]
6056pub struct PcaobConfig {
6057 #[serde(default)]
6059 pub enabled: bool,
6060
6061 #[serde(default)]
6063 pub is_pcaob_audit: bool,
6064
6065 #[serde(default = "default_true")]
6067 pub generate_cam: bool,
6068
6069 #[serde(default)]
6071 pub include_icfr_opinion: bool,
6072
6073 #[serde(default)]
6075 pub generate_standard_mappings: bool,
6076}
6077
6078impl Default for PcaobConfig {
6079 fn default() -> Self {
6080 Self {
6081 enabled: false,
6082 is_pcaob_audit: false,
6083 generate_cam: true,
6084 include_icfr_opinion: false,
6085 generate_standard_mappings: false,
6086 }
6087 }
6088}
6089
6090#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6103pub struct AdvancedDistributionConfig {
6104 #[serde(default)]
6106 pub enabled: bool,
6107
6108 #[serde(default)]
6110 pub amounts: MixtureDistributionSchemaConfig,
6111
6112 #[serde(default)]
6114 pub correlations: CorrelationSchemaConfig,
6115
6116 #[serde(default)]
6118 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
6119
6120 #[serde(default)]
6122 pub regime_changes: RegimeChangeSchemaConfig,
6123
6124 #[serde(default)]
6126 pub industry_profile: Option<IndustryProfileType>,
6127
6128 #[serde(default)]
6130 pub validation: StatisticalValidationSchemaConfig,
6131
6132 #[serde(default)]
6138 pub pareto: Option<ParetoSchemaConfig>,
6139}
6140
6141#[derive(Debug, Clone, Serialize, Deserialize)]
6146pub struct ParetoSchemaConfig {
6147 #[serde(default)]
6150 pub enabled: bool,
6151
6152 #[serde(default = "default_pareto_alpha")]
6155 pub alpha: f64,
6156
6157 #[serde(default = "default_pareto_x_min")]
6160 pub x_min: f64,
6161
6162 #[serde(default)]
6165 pub max_value: Option<f64>,
6166
6167 #[serde(default = "default_pareto_decimal_places")]
6169 pub decimal_places: u8,
6170}
6171
6172fn default_pareto_alpha() -> f64 {
6173 2.0
6174}
6175
6176fn default_pareto_x_min() -> f64 {
6177 100.0
6178}
6179
6180fn default_pareto_decimal_places() -> u8 {
6181 2
6182}
6183
6184impl Default for ParetoSchemaConfig {
6185 fn default() -> Self {
6186 Self {
6187 enabled: false,
6188 alpha: default_pareto_alpha(),
6189 x_min: default_pareto_x_min(),
6190 max_value: None,
6191 decimal_places: default_pareto_decimal_places(),
6192 }
6193 }
6194}
6195
6196impl ParetoSchemaConfig {
6197 pub fn to_core_config(&self) -> datasynth_core::distributions::ParetoConfig {
6199 datasynth_core::distributions::ParetoConfig {
6200 alpha: self.alpha,
6201 x_min: self.x_min,
6202 max_value: self.max_value,
6203 decimal_places: self.decimal_places,
6204 }
6205 }
6206}
6207
6208#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6210#[serde(rename_all = "snake_case")]
6211pub enum IndustryProfileType {
6212 Retail,
6214 Manufacturing,
6216 FinancialServices,
6218 Healthcare,
6220 Technology,
6222}
6223
6224#[derive(Debug, Clone, Serialize, Deserialize)]
6226pub struct MixtureDistributionSchemaConfig {
6227 #[serde(default)]
6229 pub enabled: bool,
6230
6231 #[serde(default = "default_mixture_type")]
6233 pub distribution_type: MixtureDistributionType,
6234
6235 #[serde(default)]
6237 pub components: Vec<MixtureComponentConfig>,
6238
6239 #[serde(default = "default_min_amount")]
6241 pub min_value: f64,
6242
6243 #[serde(default)]
6245 pub max_value: Option<f64>,
6246
6247 #[serde(default = "default_decimal_places")]
6249 pub decimal_places: u8,
6250}
6251
6252fn default_mixture_type() -> MixtureDistributionType {
6253 MixtureDistributionType::LogNormal
6254}
6255
6256fn default_min_amount() -> f64 {
6257 0.01
6258}
6259
6260fn default_decimal_places() -> u8 {
6261 2
6262}
6263
6264impl Default for MixtureDistributionSchemaConfig {
6265 fn default() -> Self {
6266 Self {
6267 enabled: false,
6268 distribution_type: MixtureDistributionType::LogNormal,
6269 components: Vec::new(),
6270 min_value: 0.01,
6271 max_value: None,
6272 decimal_places: 2,
6273 }
6274 }
6275}
6276
6277impl MixtureDistributionSchemaConfig {
6278 pub fn to_log_normal_config(
6285 &self,
6286 ) -> Option<datasynth_core::distributions::LogNormalMixtureConfig> {
6287 if self.components.is_empty() {
6288 return None;
6289 }
6290 Some(datasynth_core::distributions::LogNormalMixtureConfig {
6291 components: self
6292 .components
6293 .iter()
6294 .map(|c| match &c.label {
6295 Some(lbl) => datasynth_core::distributions::LogNormalComponent::with_label(
6296 c.weight,
6297 c.mu,
6298 c.sigma,
6299 lbl.clone(),
6300 ),
6301 None => datasynth_core::distributions::LogNormalComponent::new(
6302 c.weight, c.mu, c.sigma,
6303 ),
6304 })
6305 .collect(),
6306 min_value: self.min_value,
6307 max_value: self.max_value,
6308 decimal_places: self.decimal_places,
6309 })
6310 }
6311
6312 pub fn to_gaussian_config(
6315 &self,
6316 ) -> Option<datasynth_core::distributions::GaussianMixtureConfig> {
6317 if self.components.is_empty() {
6318 return None;
6319 }
6320 Some(datasynth_core::distributions::GaussianMixtureConfig {
6321 components: self
6322 .components
6323 .iter()
6324 .map(|c| {
6325 datasynth_core::distributions::GaussianComponent::new(c.weight, c.mu, c.sigma)
6326 })
6327 .collect(),
6328 allow_negative: true,
6329 min_value: Some(self.min_value),
6330 max_value: self.max_value,
6331 })
6332 }
6333}
6334
6335#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6337#[serde(rename_all = "snake_case")]
6338pub enum MixtureDistributionType {
6339 Gaussian,
6341 #[default]
6343 LogNormal,
6344}
6345
6346#[derive(Debug, Clone, Serialize, Deserialize)]
6348pub struct MixtureComponentConfig {
6349 pub weight: f64,
6351
6352 pub mu: f64,
6354
6355 pub sigma: f64,
6357
6358 #[serde(default)]
6360 pub label: Option<String>,
6361}
6362
6363#[derive(Debug, Clone, Serialize, Deserialize)]
6365pub struct CorrelationSchemaConfig {
6366 #[serde(default)]
6368 pub enabled: bool,
6369
6370 #[serde(default)]
6372 pub copula_type: CopulaSchemaType,
6373
6374 #[serde(default)]
6376 pub fields: Vec<CorrelatedFieldConfig>,
6377
6378 #[serde(default)]
6381 pub matrix: Vec<f64>,
6382
6383 #[serde(default)]
6385 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
6386}
6387
6388impl Default for CorrelationSchemaConfig {
6389 fn default() -> Self {
6390 Self {
6391 enabled: false,
6392 copula_type: CopulaSchemaType::Gaussian,
6393 fields: Vec::new(),
6394 matrix: Vec::new(),
6395 expected_correlations: Vec::new(),
6396 }
6397 }
6398}
6399
6400impl CorrelationSchemaConfig {
6401 pub fn correlation_between(&self, field_a: &str, field_b: &str) -> Option<f64> {
6407 let idx_a = self.fields.iter().position(|f| f.name == field_a)?;
6408 let idx_b = self.fields.iter().position(|f| f.name == field_b)?;
6409 if idx_a == idx_b {
6410 return Some(1.0);
6411 }
6412 let (i, j) = if idx_a < idx_b {
6413 (idx_a, idx_b)
6414 } else {
6415 (idx_b, idx_a)
6416 };
6417 let n = self.fields.len();
6418 if self.matrix.len() == n * n {
6420 return self.matrix.get(idx_a * n + idx_b).copied();
6421 }
6422 let expected_tri = n * (n - 1) / 2;
6424 if self.matrix.len() == expected_tri {
6425 let flat = i * (n - 1) - i * (i.saturating_sub(1)) / 2 + (j - i - 1);
6429 return self.matrix.get(flat).copied();
6430 }
6431 None
6432 }
6433
6434 pub fn to_core_config_for_pair(
6439 &self,
6440 field_a: &str,
6441 field_b: &str,
6442 ) -> Option<datasynth_core::distributions::CopulaConfig> {
6443 if !self.enabled {
6444 return None;
6445 }
6446 let rho = self.correlation_between(field_a, field_b)?;
6447 use datasynth_core::distributions::{CopulaConfig, CopulaType};
6448 let copula_type = match self.copula_type {
6449 CopulaSchemaType::Gaussian => CopulaType::Gaussian,
6450 CopulaSchemaType::Clayton => CopulaType::Clayton,
6451 CopulaSchemaType::Gumbel => CopulaType::Gumbel,
6452 CopulaSchemaType::Frank => CopulaType::Frank,
6453 CopulaSchemaType::StudentT => CopulaType::StudentT,
6454 };
6455 let theta = rho.clamp(-0.999, 0.999);
6460 Some(CopulaConfig {
6461 copula_type,
6462 theta,
6463 degrees_of_freedom: 4.0,
6464 })
6465 }
6466}
6467
6468#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6470#[serde(rename_all = "snake_case")]
6471pub enum CopulaSchemaType {
6472 #[default]
6474 Gaussian,
6475 Clayton,
6477 Gumbel,
6479 Frank,
6481 StudentT,
6483}
6484
6485#[derive(Debug, Clone, Serialize, Deserialize)]
6487pub struct CorrelatedFieldConfig {
6488 pub name: String,
6490
6491 #[serde(default)]
6493 pub distribution: MarginalDistributionConfig,
6494}
6495
6496#[derive(Debug, Clone, Serialize, Deserialize)]
6498#[serde(tag = "type", rename_all = "snake_case")]
6499pub enum MarginalDistributionConfig {
6500 Normal {
6502 mu: f64,
6504 sigma: f64,
6506 },
6507 LogNormal {
6509 mu: f64,
6511 sigma: f64,
6513 },
6514 Uniform {
6516 min: f64,
6518 max: f64,
6520 },
6521 DiscreteUniform {
6523 min: i32,
6525 max: i32,
6527 },
6528}
6529
6530impl Default for MarginalDistributionConfig {
6531 fn default() -> Self {
6532 Self::Normal {
6533 mu: 0.0,
6534 sigma: 1.0,
6535 }
6536 }
6537}
6538
6539#[derive(Debug, Clone, Serialize, Deserialize)]
6541pub struct ExpectedCorrelationConfig {
6542 pub field1: String,
6544 pub field2: String,
6546 pub expected_r: f64,
6548 #[serde(default = "default_correlation_tolerance")]
6550 pub tolerance: f64,
6551}
6552
6553fn default_correlation_tolerance() -> f64 {
6554 0.10
6555}
6556
6557#[derive(Debug, Clone, Serialize, Deserialize)]
6559pub struct ConditionalDistributionSchemaConfig {
6560 pub output_field: String,
6562
6563 pub input_field: String,
6565
6566 #[serde(default)]
6568 pub breakpoints: Vec<ConditionalBreakpointConfig>,
6569
6570 #[serde(default)]
6572 pub default_distribution: ConditionalDistributionParamsConfig,
6573
6574 #[serde(default)]
6576 pub min_value: Option<f64>,
6577
6578 #[serde(default)]
6580 pub max_value: Option<f64>,
6581
6582 #[serde(default = "default_decimal_places")]
6584 pub decimal_places: u8,
6585}
6586
6587#[derive(Debug, Clone, Serialize, Deserialize)]
6589pub struct ConditionalBreakpointConfig {
6590 pub threshold: f64,
6592
6593 pub distribution: ConditionalDistributionParamsConfig,
6595}
6596
6597impl ConditionalDistributionSchemaConfig {
6598 pub fn to_core_config(&self) -> datasynth_core::distributions::ConditionalDistributionConfig {
6602 use datasynth_core::distributions::{
6603 Breakpoint, ConditionalDistributionConfig, ConditionalDistributionParams,
6604 };
6605
6606 let default_distribution = convert_conditional_params(&self.default_distribution);
6607 let breakpoints: Vec<Breakpoint> = self
6608 .breakpoints
6609 .iter()
6610 .map(|bp| Breakpoint {
6611 threshold: bp.threshold,
6612 distribution: convert_conditional_params(&bp.distribution),
6613 })
6614 .collect();
6615
6616 let final_default = if breakpoints.is_empty() {
6621 default_distribution
6622 } else {
6623 match default_distribution {
6624 ConditionalDistributionParams::Fixed { value: 0.0 } => {
6625 breakpoints[0].distribution.clone()
6628 }
6629 other => other,
6630 }
6631 };
6632
6633 ConditionalDistributionConfig {
6634 output_field: self.output_field.clone(),
6635 input_field: self.input_field.clone(),
6636 breakpoints,
6637 default_distribution: final_default,
6638 min_value: self.min_value,
6639 max_value: self.max_value,
6640 decimal_places: self.decimal_places,
6641 }
6642 }
6643}
6644
6645fn convert_conditional_params(
6646 p: &ConditionalDistributionParamsConfig,
6647) -> datasynth_core::distributions::ConditionalDistributionParams {
6648 use datasynth_core::distributions::ConditionalDistributionParams as Core;
6649 match p {
6650 ConditionalDistributionParamsConfig::Fixed { value } => Core::Fixed { value: *value },
6651 ConditionalDistributionParamsConfig::Normal { mu, sigma } => Core::Normal {
6652 mu: *mu,
6653 sigma: *sigma,
6654 },
6655 ConditionalDistributionParamsConfig::LogNormal { mu, sigma } => Core::LogNormal {
6656 mu: *mu,
6657 sigma: *sigma,
6658 },
6659 ConditionalDistributionParamsConfig::Uniform { min, max } => Core::Uniform {
6660 min: *min,
6661 max: *max,
6662 },
6663 ConditionalDistributionParamsConfig::Beta {
6664 alpha,
6665 beta,
6666 min,
6667 max,
6668 } => Core::Beta {
6669 alpha: *alpha,
6670 beta: *beta,
6671 min: *min,
6672 max: *max,
6673 },
6674 ConditionalDistributionParamsConfig::Discrete { values, weights } => Core::Discrete {
6675 values: values.clone(),
6676 weights: weights.clone(),
6677 },
6678 }
6679}
6680
6681#[derive(Debug, Clone, Serialize, Deserialize)]
6683#[serde(tag = "type", rename_all = "snake_case")]
6684pub enum ConditionalDistributionParamsConfig {
6685 Fixed {
6687 value: f64,
6689 },
6690 Normal {
6692 mu: f64,
6694 sigma: f64,
6696 },
6697 LogNormal {
6699 mu: f64,
6701 sigma: f64,
6703 },
6704 Uniform {
6706 min: f64,
6708 max: f64,
6710 },
6711 Beta {
6713 alpha: f64,
6715 beta: f64,
6717 min: f64,
6719 max: f64,
6721 },
6722 Discrete {
6724 values: Vec<f64>,
6726 weights: Vec<f64>,
6728 },
6729}
6730
6731impl Default for ConditionalDistributionParamsConfig {
6732 fn default() -> Self {
6733 Self::Normal {
6734 mu: 0.0,
6735 sigma: 1.0,
6736 }
6737 }
6738}
6739
6740#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6742pub struct RegimeChangeSchemaConfig {
6743 #[serde(default)]
6745 pub enabled: bool,
6746
6747 #[serde(default)]
6749 pub changes: Vec<RegimeChangeEventConfig>,
6750
6751 #[serde(default)]
6753 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6754
6755 #[serde(default)]
6757 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6758}
6759
6760#[derive(Debug, Clone, Serialize, Deserialize)]
6762pub struct RegimeChangeEventConfig {
6763 pub date: String,
6765
6766 pub change_type: RegimeChangeTypeConfig,
6768
6769 #[serde(default)]
6771 pub description: Option<String>,
6772
6773 #[serde(default)]
6775 pub effects: Vec<RegimeEffectConfig>,
6776}
6777
6778#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6780#[serde(rename_all = "snake_case")]
6781pub enum RegimeChangeTypeConfig {
6782 Acquisition,
6784 Divestiture,
6786 PriceIncrease,
6788 PriceDecrease,
6790 ProductLaunch,
6792 ProductDiscontinuation,
6794 PolicyChange,
6796 CompetitorEntry,
6798 Custom,
6800}
6801
6802#[derive(Debug, Clone, Serialize, Deserialize)]
6804pub struct RegimeEffectConfig {
6805 pub field: String,
6807
6808 pub multiplier: f64,
6810}
6811
6812#[derive(Debug, Clone, Serialize, Deserialize)]
6814pub struct EconomicCycleSchemaConfig {
6815 #[serde(default)]
6817 pub enabled: bool,
6818
6819 #[serde(default = "default_cycle_period")]
6821 pub period_months: u32,
6822
6823 #[serde(default = "default_cycle_amplitude")]
6825 pub amplitude: f64,
6826
6827 #[serde(default)]
6829 pub phase_offset: u32,
6830
6831 #[serde(default)]
6833 pub recessions: Vec<RecessionPeriodConfig>,
6834}
6835
6836fn default_cycle_period() -> u32 {
6837 48
6838}
6839
6840fn default_cycle_amplitude() -> f64 {
6841 0.15
6842}
6843
6844impl Default for EconomicCycleSchemaConfig {
6845 fn default() -> Self {
6846 Self {
6847 enabled: false,
6848 period_months: 48,
6849 amplitude: 0.15,
6850 phase_offset: 0,
6851 recessions: Vec::new(),
6852 }
6853 }
6854}
6855
6856#[derive(Debug, Clone, Serialize, Deserialize)]
6858pub struct RecessionPeriodConfig {
6859 pub start_month: u32,
6861
6862 pub duration_months: u32,
6864
6865 #[serde(default = "default_recession_severity")]
6867 pub severity: f64,
6868}
6869
6870impl RegimeChangeSchemaConfig {
6871 pub fn apply_to(
6879 &self,
6880 drift: &mut datasynth_core::distributions::DriftConfig,
6881 generation_start: chrono::NaiveDate,
6882 ) {
6883 if !self.enabled {
6884 return;
6885 }
6886
6887 drift.enabled = true;
6889
6890 for event in &self.changes {
6892 let period = match chrono::NaiveDate::parse_from_str(&event.date, "%Y-%m-%d") {
6893 Ok(d) => {
6894 let days = (d - generation_start).num_days();
6895 if days < 0 {
6896 continue;
6897 }
6898 (days as f64 / 30.4).round() as u32
6901 }
6902 Err(_) => continue,
6903 };
6904 let change_type = convert_regime_change_type(event.change_type);
6905 let core_effects = event
6906 .effects
6907 .iter()
6908 .map(|e| datasynth_core::distributions::RegimeEffect {
6909 field: e.field.clone(),
6910 multiplier: e.multiplier,
6911 })
6912 .collect();
6913 drift
6914 .regime_changes
6915 .push(datasynth_core::distributions::RegimeChange {
6916 period,
6917 change_type,
6918 description: event.description.clone(),
6919 effects: core_effects,
6920 transition_periods: 0,
6921 });
6922 }
6923
6924 if let Some(ec) = &self.economic_cycle {
6926 if ec.enabled {
6927 let recession_periods: Vec<u32> = ec
6928 .recessions
6929 .iter()
6930 .flat_map(|r| r.start_month..r.start_month + r.duration_months)
6931 .collect();
6932 let severity = ec
6935 .recessions
6936 .iter()
6937 .map(|r| 1.0 - r.severity)
6938 .fold(0.75f64, f64::min);
6939 drift.economic_cycle = datasynth_core::distributions::EconomicCycleConfig {
6940 enabled: true,
6941 cycle_length: ec.period_months,
6942 amplitude: ec.amplitude,
6943 phase_offset: ec.phase_offset,
6944 recession_periods,
6945 recession_severity: severity,
6946 };
6947 drift.drift_type = datasynth_core::distributions::DriftType::Mixed;
6948 }
6949 }
6950
6951 for pd in &self.parameter_drifts {
6953 let drift_type = match pd.drift_type {
6954 ParameterDriftTypeConfig::Linear => {
6955 datasynth_core::distributions::ParameterDriftType::Linear
6956 }
6957 ParameterDriftTypeConfig::Exponential => {
6958 datasynth_core::distributions::ParameterDriftType::Exponential
6959 }
6960 ParameterDriftTypeConfig::Logistic => {
6961 datasynth_core::distributions::ParameterDriftType::Logistic
6962 }
6963 ParameterDriftTypeConfig::Step => {
6964 datasynth_core::distributions::ParameterDriftType::Step
6965 }
6966 };
6967 drift
6968 .parameter_drifts
6969 .push(datasynth_core::distributions::ParameterDrift {
6970 parameter: pd.parameter.clone(),
6971 drift_type,
6972 initial_value: pd.start_value,
6973 target_or_rate: pd.end_value,
6974 start_period: pd.start_period,
6975 end_period: pd.end_period,
6976 steepness: 1.0,
6977 });
6978 }
6979 }
6980}
6981
6982fn convert_regime_change_type(
6983 t: RegimeChangeTypeConfig,
6984) -> datasynth_core::distributions::RegimeChangeType {
6985 use datasynth_core::distributions::RegimeChangeType as Core;
6986 match t {
6987 RegimeChangeTypeConfig::Acquisition => Core::Acquisition,
6988 RegimeChangeTypeConfig::Divestiture => Core::Divestiture,
6989 RegimeChangeTypeConfig::PriceIncrease => Core::PriceIncrease,
6990 RegimeChangeTypeConfig::PriceDecrease => Core::PriceDecrease,
6991 RegimeChangeTypeConfig::ProductLaunch => Core::ProductLaunch,
6992 RegimeChangeTypeConfig::ProductDiscontinuation => Core::ProductDiscontinuation,
6993 RegimeChangeTypeConfig::PolicyChange => Core::PolicyChange,
6994 RegimeChangeTypeConfig::CompetitorEntry => Core::CompetitorEntry,
6995 RegimeChangeTypeConfig::Custom => Core::Custom,
6996 }
6997}
6998
6999fn default_recession_severity() -> f64 {
7000 0.20
7001}
7002
7003#[derive(Debug, Clone, Serialize, Deserialize)]
7005pub struct ParameterDriftSchemaConfig {
7006 pub parameter: String,
7008
7009 pub drift_type: ParameterDriftTypeConfig,
7011
7012 pub start_value: f64,
7014
7015 pub end_value: f64,
7017
7018 #[serde(default)]
7020 pub start_period: u32,
7021
7022 #[serde(default)]
7024 pub end_period: Option<u32>,
7025}
7026
7027#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7029#[serde(rename_all = "snake_case")]
7030pub enum ParameterDriftTypeConfig {
7031 #[default]
7033 Linear,
7034 Exponential,
7036 Logistic,
7038 Step,
7040}
7041
7042#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7044pub struct StatisticalValidationSchemaConfig {
7045 #[serde(default)]
7047 pub enabled: bool,
7048
7049 #[serde(default)]
7051 pub tests: Vec<StatisticalTestConfig>,
7052
7053 #[serde(default)]
7055 pub reporting: ValidationReportingConfig,
7056}
7057
7058#[derive(Debug, Clone, Serialize, Deserialize)]
7060#[serde(tag = "type", rename_all = "snake_case")]
7061pub enum StatisticalTestConfig {
7062 BenfordFirstDigit {
7064 #[serde(default = "default_benford_threshold")]
7066 threshold_mad: f64,
7067 #[serde(default = "default_benford_warning")]
7069 warning_mad: f64,
7070 },
7071 DistributionFit {
7073 target: TargetDistributionConfig,
7075 #[serde(default = "default_ks_significance")]
7077 ks_significance: f64,
7078 #[serde(default)]
7080 method: DistributionFitMethod,
7081 },
7082 CorrelationCheck {
7084 expected_correlations: Vec<ExpectedCorrelationConfig>,
7086 },
7087 ChiSquared {
7089 #[serde(default = "default_chi_squared_bins")]
7091 bins: usize,
7092 #[serde(default = "default_chi_squared_significance")]
7094 significance: f64,
7095 },
7096 AndersonDarling {
7098 target: TargetDistributionConfig,
7100 #[serde(default = "default_ad_significance")]
7102 significance: f64,
7103 },
7104}
7105
7106fn default_benford_threshold() -> f64 {
7107 0.015
7108}
7109
7110fn default_benford_warning() -> f64 {
7111 0.010
7112}
7113
7114fn default_ks_significance() -> f64 {
7115 0.05
7116}
7117
7118fn default_chi_squared_bins() -> usize {
7119 10
7120}
7121
7122fn default_chi_squared_significance() -> f64 {
7123 0.05
7124}
7125
7126fn default_ad_significance() -> f64 {
7127 0.05
7128}
7129
7130#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7132#[serde(rename_all = "snake_case")]
7133pub enum TargetDistributionConfig {
7134 Normal,
7136 #[default]
7138 LogNormal,
7139 Exponential,
7141 Uniform,
7143}
7144
7145#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7147#[serde(rename_all = "snake_case")]
7148pub enum DistributionFitMethod {
7149 #[default]
7151 KolmogorovSmirnov,
7152 AndersonDarling,
7154 ChiSquared,
7156}
7157
7158#[derive(Debug, Clone, Serialize, Deserialize)]
7160pub struct ValidationReportingConfig {
7161 #[serde(default)]
7163 pub output_report: bool,
7164
7165 #[serde(default)]
7167 pub format: ValidationReportFormat,
7168
7169 #[serde(default)]
7171 pub fail_on_error: bool,
7172
7173 #[serde(default = "default_true")]
7175 pub include_details: bool,
7176}
7177
7178impl Default for ValidationReportingConfig {
7179 fn default() -> Self {
7180 Self {
7181 output_report: false,
7182 format: ValidationReportFormat::Json,
7183 fail_on_error: false,
7184 include_details: true,
7185 }
7186 }
7187}
7188
7189#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7191#[serde(rename_all = "snake_case")]
7192pub enum ValidationReportFormat {
7193 #[default]
7195 Json,
7196 Yaml,
7198 Html,
7200}
7201
7202#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7214pub struct TemporalPatternsConfig {
7215 #[serde(default)]
7217 pub enabled: bool,
7218
7219 #[serde(default)]
7221 pub business_days: BusinessDaySchemaConfig,
7222
7223 #[serde(default)]
7225 pub calendars: CalendarSchemaConfig,
7226
7227 #[serde(default)]
7229 pub period_end: PeriodEndSchemaConfig,
7230
7231 #[serde(default)]
7233 pub processing_lags: ProcessingLagSchemaConfig,
7234
7235 #[serde(default)]
7237 pub fiscal_calendar: FiscalCalendarSchemaConfig,
7238
7239 #[serde(default)]
7241 pub intraday: IntraDaySchemaConfig,
7242
7243 #[serde(default)]
7245 pub timezones: TimezoneSchemaConfig,
7246}
7247
7248#[derive(Debug, Clone, Serialize, Deserialize)]
7250pub struct BusinessDaySchemaConfig {
7251 #[serde(default = "default_true")]
7253 pub enabled: bool,
7254
7255 #[serde(default = "default_half_day_policy")]
7257 pub half_day_policy: String,
7258
7259 #[serde(default)]
7261 pub settlement_rules: SettlementRulesSchemaConfig,
7262
7263 #[serde(default = "default_month_end_convention")]
7265 pub month_end_convention: String,
7266
7267 #[serde(default)]
7269 pub weekend_days: Option<Vec<String>>,
7270}
7271
7272fn default_half_day_policy() -> String {
7273 "half_day".to_string()
7274}
7275
7276fn default_month_end_convention() -> String {
7277 "modified_following".to_string()
7278}
7279
7280impl Default for BusinessDaySchemaConfig {
7281 fn default() -> Self {
7282 Self {
7283 enabled: true,
7284 half_day_policy: "half_day".to_string(),
7285 settlement_rules: SettlementRulesSchemaConfig::default(),
7286 month_end_convention: "modified_following".to_string(),
7287 weekend_days: None,
7288 }
7289 }
7290}
7291
7292#[derive(Debug, Clone, Serialize, Deserialize)]
7294pub struct SettlementRulesSchemaConfig {
7295 #[serde(default = "default_settlement_2")]
7297 pub equity_days: i32,
7298
7299 #[serde(default = "default_settlement_1")]
7301 pub government_bonds_days: i32,
7302
7303 #[serde(default = "default_settlement_2")]
7305 pub fx_spot_days: i32,
7306
7307 #[serde(default = "default_settlement_2")]
7309 pub corporate_bonds_days: i32,
7310
7311 #[serde(default = "default_wire_cutoff")]
7313 pub wire_cutoff_time: String,
7314
7315 #[serde(default = "default_settlement_1")]
7317 pub wire_international_days: i32,
7318
7319 #[serde(default = "default_settlement_1")]
7321 pub ach_days: i32,
7322}
7323
7324fn default_settlement_1() -> i32 {
7325 1
7326}
7327
7328fn default_settlement_2() -> i32 {
7329 2
7330}
7331
7332fn default_wire_cutoff() -> String {
7333 "14:00".to_string()
7334}
7335
7336impl Default for SettlementRulesSchemaConfig {
7337 fn default() -> Self {
7338 Self {
7339 equity_days: 2,
7340 government_bonds_days: 1,
7341 fx_spot_days: 2,
7342 corporate_bonds_days: 2,
7343 wire_cutoff_time: "14:00".to_string(),
7344 wire_international_days: 1,
7345 ach_days: 1,
7346 }
7347 }
7348}
7349
7350#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7352pub struct CalendarSchemaConfig {
7353 #[serde(default)]
7355 pub regions: Vec<String>,
7356
7357 #[serde(default)]
7359 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
7360}
7361
7362#[derive(Debug, Clone, Serialize, Deserialize)]
7364pub struct CustomHolidaySchemaConfig {
7365 pub name: String,
7367 pub month: u8,
7369 pub day: u8,
7371 #[serde(default = "default_holiday_multiplier")]
7373 pub activity_multiplier: f64,
7374}
7375
7376fn default_holiday_multiplier() -> f64 {
7377 0.05
7378}
7379
7380#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7382pub struct PeriodEndSchemaConfig {
7383 #[serde(default)]
7385 pub model: Option<String>,
7386
7387 #[serde(default)]
7389 pub month_end: Option<PeriodEndModelSchemaConfig>,
7390
7391 #[serde(default)]
7393 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
7394
7395 #[serde(default)]
7397 pub year_end: Option<PeriodEndModelSchemaConfig>,
7398}
7399
7400#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7402pub struct PeriodEndModelSchemaConfig {
7403 #[serde(default)]
7405 pub inherit_from: Option<String>,
7406
7407 #[serde(default)]
7409 pub additional_multiplier: Option<f64>,
7410
7411 #[serde(default)]
7413 pub start_day: Option<i32>,
7414
7415 #[serde(default)]
7417 pub base_multiplier: Option<f64>,
7418
7419 #[serde(default)]
7421 pub peak_multiplier: Option<f64>,
7422
7423 #[serde(default)]
7425 pub decay_rate: Option<f64>,
7426
7427 #[serde(default)]
7429 pub sustained_high_days: Option<i32>,
7430}
7431
7432#[derive(Debug, Clone, Serialize, Deserialize)]
7434pub struct ProcessingLagSchemaConfig {
7435 #[serde(default = "default_true")]
7437 pub enabled: bool,
7438
7439 #[serde(default)]
7441 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
7442
7443 #[serde(default)]
7445 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
7446
7447 #[serde(default)]
7449 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
7450
7451 #[serde(default)]
7453 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
7454
7455 #[serde(default)]
7457 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
7458
7459 #[serde(default)]
7461 pub payment_lag: Option<LagDistributionSchemaConfig>,
7462
7463 #[serde(default)]
7465 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
7466
7467 #[serde(default)]
7469 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
7470}
7471
7472impl Default for ProcessingLagSchemaConfig {
7473 fn default() -> Self {
7474 Self {
7475 enabled: true,
7476 sales_order_lag: None,
7477 purchase_order_lag: None,
7478 goods_receipt_lag: None,
7479 invoice_receipt_lag: None,
7480 invoice_issue_lag: None,
7481 payment_lag: None,
7482 journal_entry_lag: None,
7483 cross_day_posting: None,
7484 }
7485 }
7486}
7487
7488#[derive(Debug, Clone, Serialize, Deserialize)]
7490pub struct LagDistributionSchemaConfig {
7491 pub mu: f64,
7493 pub sigma: f64,
7495 #[serde(default)]
7497 pub min_hours: Option<f64>,
7498 #[serde(default)]
7500 pub max_hours: Option<f64>,
7501}
7502
7503#[derive(Debug, Clone, Serialize, Deserialize)]
7505pub struct CrossDayPostingSchemaConfig {
7506 #[serde(default = "default_true")]
7508 pub enabled: bool,
7509
7510 #[serde(default)]
7513 pub probability_by_hour: std::collections::HashMap<u8, f64>,
7514}
7515
7516impl Default for CrossDayPostingSchemaConfig {
7517 fn default() -> Self {
7518 let mut probability_by_hour = std::collections::HashMap::new();
7519 probability_by_hour.insert(17, 0.3);
7520 probability_by_hour.insert(18, 0.6);
7521 probability_by_hour.insert(19, 0.8);
7522 probability_by_hour.insert(20, 0.9);
7523 probability_by_hour.insert(21, 0.95);
7524 probability_by_hour.insert(22, 0.99);
7525
7526 Self {
7527 enabled: true,
7528 probability_by_hour,
7529 }
7530 }
7531}
7532
7533#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7542pub struct FiscalCalendarSchemaConfig {
7543 #[serde(default)]
7545 pub enabled: bool,
7546
7547 #[serde(default = "default_fiscal_calendar_type")]
7549 pub calendar_type: String,
7550
7551 #[serde(default)]
7553 pub year_start_month: Option<u8>,
7554
7555 #[serde(default)]
7557 pub year_start_day: Option<u8>,
7558
7559 #[serde(default)]
7561 pub four_four_five: Option<FourFourFiveSchemaConfig>,
7562}
7563
7564fn default_fiscal_calendar_type() -> String {
7565 "calendar_year".to_string()
7566}
7567
7568#[derive(Debug, Clone, Serialize, Deserialize)]
7570pub struct FourFourFiveSchemaConfig {
7571 #[serde(default = "default_week_pattern")]
7573 pub pattern: String,
7574
7575 #[serde(default = "default_anchor_type")]
7577 pub anchor_type: String,
7578
7579 #[serde(default = "default_anchor_month")]
7581 pub anchor_month: u8,
7582
7583 #[serde(default = "default_leap_week_placement")]
7585 pub leap_week_placement: String,
7586}
7587
7588fn default_week_pattern() -> String {
7589 "four_four_five".to_string()
7590}
7591
7592fn default_anchor_type() -> String {
7593 "last_saturday".to_string()
7594}
7595
7596fn default_anchor_month() -> u8 {
7597 1 }
7599
7600fn default_leap_week_placement() -> String {
7601 "q4_period3".to_string()
7602}
7603
7604impl Default for FourFourFiveSchemaConfig {
7605 fn default() -> Self {
7606 Self {
7607 pattern: "four_four_five".to_string(),
7608 anchor_type: "last_saturday".to_string(),
7609 anchor_month: 1,
7610 leap_week_placement: "q4_period3".to_string(),
7611 }
7612 }
7613}
7614
7615#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7624pub struct IntraDaySchemaConfig {
7625 #[serde(default)]
7627 pub enabled: bool,
7628
7629 #[serde(default)]
7631 pub segments: Vec<IntraDaySegmentSchemaConfig>,
7632}
7633
7634#[derive(Debug, Clone, Serialize, Deserialize)]
7636pub struct IntraDaySegmentSchemaConfig {
7637 pub name: String,
7639
7640 pub start: String,
7642
7643 pub end: String,
7645
7646 #[serde(default = "default_multiplier")]
7648 pub multiplier: f64,
7649
7650 #[serde(default = "default_posting_type")]
7652 pub posting_type: String,
7653}
7654
7655fn default_multiplier() -> f64 {
7656 1.0
7657}
7658
7659fn default_posting_type() -> String {
7660 "both".to_string()
7661}
7662
7663#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7669pub struct TimezoneSchemaConfig {
7670 #[serde(default)]
7672 pub enabled: bool,
7673
7674 #[serde(default = "default_timezone")]
7676 pub default_timezone: String,
7677
7678 #[serde(default = "default_consolidation_timezone")]
7680 pub consolidation_timezone: String,
7681
7682 #[serde(default)]
7685 pub entity_mappings: Vec<EntityTimezoneMapping>,
7686}
7687
7688fn default_timezone() -> String {
7689 "America/New_York".to_string()
7690}
7691
7692fn default_consolidation_timezone() -> String {
7693 "UTC".to_string()
7694}
7695
7696#[derive(Debug, Clone, Serialize, Deserialize)]
7698pub struct EntityTimezoneMapping {
7699 pub pattern: String,
7701
7702 pub timezone: String,
7704}
7705
7706#[derive(Debug, Clone, Serialize, Deserialize)]
7712pub struct VendorNetworkSchemaConfig {
7713 #[serde(default)]
7715 pub enabled: bool,
7716
7717 #[serde(default = "default_vendor_tier_depth")]
7719 pub depth: u8,
7720
7721 #[serde(default)]
7723 pub tier1: TierCountSchemaConfig,
7724
7725 #[serde(default)]
7727 pub tier2_per_parent: TierCountSchemaConfig,
7728
7729 #[serde(default)]
7731 pub tier3_per_parent: TierCountSchemaConfig,
7732
7733 #[serde(default)]
7735 pub clusters: VendorClusterSchemaConfig,
7736
7737 #[serde(default)]
7739 pub dependencies: DependencySchemaConfig,
7740}
7741
7742fn default_vendor_tier_depth() -> u8 {
7743 3
7744}
7745
7746impl Default for VendorNetworkSchemaConfig {
7747 fn default() -> Self {
7748 Self {
7749 enabled: false,
7750 depth: 3,
7751 tier1: TierCountSchemaConfig { min: 50, max: 100 },
7752 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
7753 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
7754 clusters: VendorClusterSchemaConfig::default(),
7755 dependencies: DependencySchemaConfig::default(),
7756 }
7757 }
7758}
7759
7760#[derive(Debug, Clone, Serialize, Deserialize)]
7762pub struct TierCountSchemaConfig {
7763 #[serde(default = "default_tier_min")]
7765 pub min: usize,
7766
7767 #[serde(default = "default_tier_max")]
7769 pub max: usize,
7770}
7771
7772fn default_tier_min() -> usize {
7773 5
7774}
7775
7776fn default_tier_max() -> usize {
7777 20
7778}
7779
7780impl Default for TierCountSchemaConfig {
7781 fn default() -> Self {
7782 Self {
7783 min: default_tier_min(),
7784 max: default_tier_max(),
7785 }
7786 }
7787}
7788
7789#[derive(Debug, Clone, Serialize, Deserialize)]
7791pub struct VendorClusterSchemaConfig {
7792 #[serde(default = "default_reliable_strategic")]
7794 pub reliable_strategic: f64,
7795
7796 #[serde(default = "default_standard_operational")]
7798 pub standard_operational: f64,
7799
7800 #[serde(default = "default_transactional")]
7802 pub transactional: f64,
7803
7804 #[serde(default = "default_problematic")]
7806 pub problematic: f64,
7807}
7808
7809fn default_reliable_strategic() -> f64 {
7810 0.20
7811}
7812
7813fn default_standard_operational() -> f64 {
7814 0.50
7815}
7816
7817fn default_transactional() -> f64 {
7818 0.25
7819}
7820
7821fn default_problematic() -> f64 {
7822 0.05
7823}
7824
7825impl Default for VendorClusterSchemaConfig {
7826 fn default() -> Self {
7827 Self {
7828 reliable_strategic: 0.20,
7829 standard_operational: 0.50,
7830 transactional: 0.25,
7831 problematic: 0.05,
7832 }
7833 }
7834}
7835
7836#[derive(Debug, Clone, Serialize, Deserialize)]
7838pub struct DependencySchemaConfig {
7839 #[serde(default = "default_max_single_vendor")]
7841 pub max_single_vendor_concentration: f64,
7842
7843 #[serde(default = "default_max_top5")]
7845 pub top_5_concentration: f64,
7846
7847 #[serde(default = "default_single_source_percent")]
7849 pub single_source_percent: f64,
7850}
7851
7852fn default_max_single_vendor() -> f64 {
7853 0.15
7854}
7855
7856fn default_max_top5() -> f64 {
7857 0.45
7858}
7859
7860fn default_single_source_percent() -> f64 {
7861 0.05
7862}
7863
7864impl Default for DependencySchemaConfig {
7865 fn default() -> Self {
7866 Self {
7867 max_single_vendor_concentration: 0.15,
7868 top_5_concentration: 0.45,
7869 single_source_percent: 0.05,
7870 }
7871 }
7872}
7873
7874#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7880pub struct CustomerSegmentationSchemaConfig {
7881 #[serde(default)]
7883 pub enabled: bool,
7884
7885 #[serde(default)]
7887 pub value_segments: ValueSegmentsSchemaConfig,
7888
7889 #[serde(default)]
7891 pub lifecycle: LifecycleSchemaConfig,
7892
7893 #[serde(default)]
7895 pub networks: CustomerNetworksSchemaConfig,
7896}
7897
7898#[derive(Debug, Clone, Serialize, Deserialize)]
7900pub struct ValueSegmentsSchemaConfig {
7901 #[serde(default)]
7903 pub enterprise: SegmentDetailSchemaConfig,
7904
7905 #[serde(default)]
7907 pub mid_market: SegmentDetailSchemaConfig,
7908
7909 #[serde(default)]
7911 pub smb: SegmentDetailSchemaConfig,
7912
7913 #[serde(default)]
7915 pub consumer: SegmentDetailSchemaConfig,
7916}
7917
7918impl Default for ValueSegmentsSchemaConfig {
7919 fn default() -> Self {
7920 Self {
7921 enterprise: SegmentDetailSchemaConfig {
7922 revenue_share: 0.40,
7923 customer_share: 0.05,
7924 avg_order_value_range: "50000+".to_string(),
7925 },
7926 mid_market: SegmentDetailSchemaConfig {
7927 revenue_share: 0.35,
7928 customer_share: 0.20,
7929 avg_order_value_range: "5000-50000".to_string(),
7930 },
7931 smb: SegmentDetailSchemaConfig {
7932 revenue_share: 0.20,
7933 customer_share: 0.50,
7934 avg_order_value_range: "500-5000".to_string(),
7935 },
7936 consumer: SegmentDetailSchemaConfig {
7937 revenue_share: 0.05,
7938 customer_share: 0.25,
7939 avg_order_value_range: "50-500".to_string(),
7940 },
7941 }
7942 }
7943}
7944
7945#[derive(Debug, Clone, Serialize, Deserialize)]
7947pub struct SegmentDetailSchemaConfig {
7948 #[serde(default)]
7950 pub revenue_share: f64,
7951
7952 #[serde(default)]
7954 pub customer_share: f64,
7955
7956 #[serde(default)]
7958 pub avg_order_value_range: String,
7959}
7960
7961impl Default for SegmentDetailSchemaConfig {
7962 fn default() -> Self {
7963 Self {
7964 revenue_share: 0.25,
7965 customer_share: 0.25,
7966 avg_order_value_range: "1000-10000".to_string(),
7967 }
7968 }
7969}
7970
7971#[derive(Debug, Clone, Serialize, Deserialize)]
7973pub struct LifecycleSchemaConfig {
7974 #[serde(default)]
7976 pub prospect_rate: f64,
7977
7978 #[serde(default = "default_new_rate")]
7980 pub new_rate: f64,
7981
7982 #[serde(default = "default_growth_rate")]
7984 pub growth_rate: f64,
7985
7986 #[serde(default = "default_mature_rate")]
7988 pub mature_rate: f64,
7989
7990 #[serde(default = "default_at_risk_rate")]
7992 pub at_risk_rate: f64,
7993
7994 #[serde(default = "default_churned_rate")]
7996 pub churned_rate: f64,
7997
7998 #[serde(default)]
8000 pub won_back_rate: f64,
8001}
8002
8003fn default_new_rate() -> f64 {
8004 0.10
8005}
8006
8007fn default_growth_rate() -> f64 {
8008 0.15
8009}
8010
8011fn default_mature_rate() -> f64 {
8012 0.60
8013}
8014
8015fn default_at_risk_rate() -> f64 {
8016 0.10
8017}
8018
8019fn default_churned_rate() -> f64 {
8020 0.05
8021}
8022
8023impl Default for LifecycleSchemaConfig {
8024 fn default() -> Self {
8025 Self {
8026 prospect_rate: 0.0,
8027 new_rate: 0.10,
8028 growth_rate: 0.15,
8029 mature_rate: 0.60,
8030 at_risk_rate: 0.10,
8031 churned_rate: 0.05,
8032 won_back_rate: 0.0,
8033 }
8034 }
8035}
8036
8037#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8039pub struct CustomerNetworksSchemaConfig {
8040 #[serde(default)]
8042 pub referrals: ReferralSchemaConfig,
8043
8044 #[serde(default)]
8046 pub corporate_hierarchies: HierarchySchemaConfig,
8047}
8048
8049#[derive(Debug, Clone, Serialize, Deserialize)]
8051pub struct ReferralSchemaConfig {
8052 #[serde(default = "default_true")]
8054 pub enabled: bool,
8055
8056 #[serde(default = "default_referral_rate")]
8058 pub referral_rate: f64,
8059}
8060
8061fn default_referral_rate() -> f64 {
8062 0.15
8063}
8064
8065impl Default for ReferralSchemaConfig {
8066 fn default() -> Self {
8067 Self {
8068 enabled: true,
8069 referral_rate: 0.15,
8070 }
8071 }
8072}
8073
8074#[derive(Debug, Clone, Serialize, Deserialize)]
8076pub struct HierarchySchemaConfig {
8077 #[serde(default = "default_true")]
8079 pub enabled: bool,
8080
8081 #[serde(default = "default_hierarchy_rate")]
8083 pub probability: f64,
8084}
8085
8086fn default_hierarchy_rate() -> f64 {
8087 0.30
8088}
8089
8090impl Default for HierarchySchemaConfig {
8091 fn default() -> Self {
8092 Self {
8093 enabled: true,
8094 probability: 0.30,
8095 }
8096 }
8097}
8098
8099#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8105pub struct RelationshipStrengthSchemaConfig {
8106 #[serde(default)]
8108 pub enabled: bool,
8109
8110 #[serde(default)]
8112 pub calculation: StrengthCalculationSchemaConfig,
8113
8114 #[serde(default)]
8116 pub thresholds: StrengthThresholdsSchemaConfig,
8117}
8118
8119#[derive(Debug, Clone, Serialize, Deserialize)]
8121pub struct StrengthCalculationSchemaConfig {
8122 #[serde(default = "default_volume_weight")]
8124 pub transaction_volume_weight: f64,
8125
8126 #[serde(default = "default_count_weight")]
8128 pub transaction_count_weight: f64,
8129
8130 #[serde(default = "default_duration_weight")]
8132 pub relationship_duration_weight: f64,
8133
8134 #[serde(default = "default_recency_weight")]
8136 pub recency_weight: f64,
8137
8138 #[serde(default = "default_mutual_weight")]
8140 pub mutual_connections_weight: f64,
8141
8142 #[serde(default = "default_recency_half_life")]
8144 pub recency_half_life_days: u32,
8145}
8146
8147fn default_volume_weight() -> f64 {
8148 0.30
8149}
8150
8151fn default_count_weight() -> f64 {
8152 0.25
8153}
8154
8155fn default_duration_weight() -> f64 {
8156 0.20
8157}
8158
8159fn default_recency_weight() -> f64 {
8160 0.15
8161}
8162
8163fn default_mutual_weight() -> f64 {
8164 0.10
8165}
8166
8167fn default_recency_half_life() -> u32 {
8168 90
8169}
8170
8171impl Default for StrengthCalculationSchemaConfig {
8172 fn default() -> Self {
8173 Self {
8174 transaction_volume_weight: 0.30,
8175 transaction_count_weight: 0.25,
8176 relationship_duration_weight: 0.20,
8177 recency_weight: 0.15,
8178 mutual_connections_weight: 0.10,
8179 recency_half_life_days: 90,
8180 }
8181 }
8182}
8183
8184#[derive(Debug, Clone, Serialize, Deserialize)]
8186pub struct StrengthThresholdsSchemaConfig {
8187 #[serde(default = "default_strong_threshold")]
8189 pub strong: f64,
8190
8191 #[serde(default = "default_moderate_threshold")]
8193 pub moderate: f64,
8194
8195 #[serde(default = "default_weak_threshold")]
8197 pub weak: f64,
8198}
8199
8200fn default_strong_threshold() -> f64 {
8201 0.7
8202}
8203
8204fn default_moderate_threshold() -> f64 {
8205 0.4
8206}
8207
8208fn default_weak_threshold() -> f64 {
8209 0.1
8210}
8211
8212impl Default for StrengthThresholdsSchemaConfig {
8213 fn default() -> Self {
8214 Self {
8215 strong: 0.7,
8216 moderate: 0.4,
8217 weak: 0.1,
8218 }
8219 }
8220}
8221
8222#[derive(Debug, Clone, Serialize, Deserialize)]
8228pub struct CrossProcessLinksSchemaConfig {
8229 #[serde(default)]
8231 pub enabled: bool,
8232
8233 #[serde(default = "default_true")]
8235 pub inventory_p2p_o2c: bool,
8236
8237 #[serde(default = "default_true")]
8239 pub payment_bank_reconciliation: bool,
8240
8241 #[serde(default = "default_true")]
8243 pub intercompany_bilateral: bool,
8244
8245 #[serde(default = "default_inventory_link_rate")]
8247 pub inventory_link_rate: f64,
8248}
8249
8250fn default_inventory_link_rate() -> f64 {
8251 0.30
8252}
8253
8254impl Default for CrossProcessLinksSchemaConfig {
8255 fn default() -> Self {
8256 Self {
8257 enabled: false,
8258 inventory_p2p_o2c: true,
8259 payment_bank_reconciliation: true,
8260 intercompany_bilateral: true,
8261 inventory_link_rate: 0.30,
8262 }
8263 }
8264}
8265
8266#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8272pub struct OrganizationalEventsSchemaConfig {
8273 #[serde(default)]
8275 pub enabled: bool,
8276
8277 #[serde(default)]
8279 pub effect_blending: EffectBlendingModeConfig,
8280
8281 #[serde(default)]
8283 pub events: Vec<OrganizationalEventSchemaConfig>,
8284
8285 #[serde(default)]
8287 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
8288
8289 #[serde(default)]
8291 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
8292}
8293
8294#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8296#[serde(rename_all = "snake_case")]
8297pub enum EffectBlendingModeConfig {
8298 #[default]
8300 Multiplicative,
8301 Additive,
8303 Maximum,
8305 Minimum,
8307}
8308
8309#[derive(Debug, Clone, Serialize, Deserialize)]
8311pub struct OrganizationalEventSchemaConfig {
8312 pub id: String,
8314
8315 pub event_type: OrganizationalEventTypeSchemaConfig,
8317
8318 pub effective_date: String,
8320
8321 #[serde(default = "default_org_transition_months")]
8323 pub transition_months: u32,
8324
8325 #[serde(default)]
8327 pub description: Option<String>,
8328}
8329
8330fn default_org_transition_months() -> u32 {
8331 6
8332}
8333
8334#[derive(Debug, Clone, Serialize, Deserialize)]
8336#[serde(tag = "type", rename_all = "snake_case")]
8337pub enum OrganizationalEventTypeSchemaConfig {
8338 Acquisition {
8340 acquired_entity: String,
8342 #[serde(default = "default_acquisition_volume")]
8344 volume_increase: f64,
8345 #[serde(default = "default_acquisition_error")]
8347 integration_error_rate: f64,
8348 #[serde(default = "default_parallel_days")]
8350 parallel_posting_days: u32,
8351 },
8352 Divestiture {
8354 divested_entity: String,
8356 #[serde(default = "default_divestiture_volume")]
8358 volume_reduction: f64,
8359 #[serde(default = "default_true_val")]
8361 remove_entity: bool,
8362 },
8363 Reorganization {
8365 #[serde(default)]
8367 cost_center_remapping: std::collections::HashMap<String, String>,
8368 #[serde(default = "default_reorg_error")]
8370 transition_error_rate: f64,
8371 },
8372 LeadershipChange {
8374 role: String,
8376 #[serde(default)]
8378 policy_changes: Vec<String>,
8379 },
8380 WorkforceReduction {
8382 #[serde(default = "default_workforce_reduction")]
8384 reduction_percent: f64,
8385 #[serde(default = "default_workforce_error")]
8387 error_rate_increase: f64,
8388 },
8389 Merger {
8391 merged_entity: String,
8393 #[serde(default = "default_merger_volume")]
8395 volume_increase: f64,
8396 },
8397}
8398
8399fn default_acquisition_volume() -> f64 {
8400 1.35
8401}
8402
8403fn default_acquisition_error() -> f64 {
8404 0.05
8405}
8406
8407fn default_parallel_days() -> u32 {
8408 30
8409}
8410
8411fn default_divestiture_volume() -> f64 {
8412 0.70
8413}
8414
8415fn default_true_val() -> bool {
8416 true
8417}
8418
8419fn default_reorg_error() -> f64 {
8420 0.04
8421}
8422
8423fn default_workforce_reduction() -> f64 {
8424 0.10
8425}
8426
8427fn default_workforce_error() -> f64 {
8428 0.05
8429}
8430
8431fn default_merger_volume() -> f64 {
8432 1.80
8433}
8434
8435#[derive(Debug, Clone, Serialize, Deserialize)]
8437pub struct ProcessEvolutionSchemaConfig {
8438 pub id: String,
8440
8441 pub event_type: ProcessEvolutionTypeSchemaConfig,
8443
8444 pub effective_date: String,
8446
8447 #[serde(default)]
8449 pub description: Option<String>,
8450}
8451
8452#[derive(Debug, Clone, Serialize, Deserialize)]
8454#[serde(tag = "type", rename_all = "snake_case")]
8455pub enum ProcessEvolutionTypeSchemaConfig {
8456 ProcessAutomation {
8458 process_name: String,
8460 #[serde(default = "default_manual_before")]
8462 manual_rate_before: f64,
8463 #[serde(default = "default_manual_after")]
8465 manual_rate_after: f64,
8466 },
8467 ApprovalWorkflowChange {
8469 description: String,
8471 },
8472 ControlEnhancement {
8474 control_id: String,
8476 #[serde(default = "default_error_reduction")]
8478 error_reduction: f64,
8479 },
8480}
8481
8482fn default_manual_before() -> f64 {
8483 0.80
8484}
8485
8486fn default_manual_after() -> f64 {
8487 0.15
8488}
8489
8490fn default_error_reduction() -> f64 {
8491 0.02
8492}
8493
8494#[derive(Debug, Clone, Serialize, Deserialize)]
8496pub struct TechnologyTransitionSchemaConfig {
8497 pub id: String,
8499
8500 pub event_type: TechnologyTransitionTypeSchemaConfig,
8502
8503 #[serde(default)]
8505 pub description: Option<String>,
8506}
8507
8508#[derive(Debug, Clone, Serialize, Deserialize)]
8510#[serde(tag = "type", rename_all = "snake_case")]
8511pub enum TechnologyTransitionTypeSchemaConfig {
8512 ErpMigration {
8514 source_system: String,
8516 target_system: String,
8518 cutover_date: String,
8520 stabilization_end: String,
8522 #[serde(default = "default_erp_duplicate_rate")]
8524 duplicate_rate: f64,
8525 #[serde(default = "default_format_mismatch")]
8527 format_mismatch_rate: f64,
8528 },
8529 ModuleImplementation {
8531 module_name: String,
8533 go_live_date: String,
8535 },
8536}
8537
8538fn default_erp_duplicate_rate() -> f64 {
8539 0.02
8540}
8541
8542fn default_format_mismatch() -> f64 {
8543 0.03
8544}
8545
8546#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8561pub struct BehavioralDriftSchemaConfig {
8562 #[serde(default)]
8564 pub enabled: bool,
8565
8566 #[serde(default)]
8568 pub vendor_behavior: VendorBehaviorSchemaConfig,
8569
8570 #[serde(default)]
8572 pub customer_behavior: CustomerBehaviorSchemaConfig,
8573
8574 #[serde(default)]
8576 pub employee_behavior: EmployeeBehaviorSchemaConfig,
8577
8578 #[serde(default)]
8580 pub collective: CollectiveBehaviorSchemaConfig,
8581}
8582
8583#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8585pub struct VendorBehaviorSchemaConfig {
8586 #[serde(default)]
8588 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
8589
8590 #[serde(default)]
8592 pub quality_drift: QualityDriftSchemaConfig,
8593}
8594
8595#[derive(Debug, Clone, Serialize, Deserialize)]
8597pub struct PaymentTermsDriftSchemaConfig {
8598 #[serde(default = "default_extension_rate")]
8600 pub extension_rate_per_year: f64,
8601
8602 #[serde(default = "default_economic_sensitivity")]
8604 pub economic_sensitivity: f64,
8605}
8606
8607fn default_extension_rate() -> f64 {
8608 2.5
8609}
8610
8611fn default_economic_sensitivity() -> f64 {
8612 1.0
8613}
8614
8615impl Default for PaymentTermsDriftSchemaConfig {
8616 fn default() -> Self {
8617 Self {
8618 extension_rate_per_year: 2.5,
8619 economic_sensitivity: 1.0,
8620 }
8621 }
8622}
8623
8624#[derive(Debug, Clone, Serialize, Deserialize)]
8626pub struct QualityDriftSchemaConfig {
8627 #[serde(default = "default_improvement_rate")]
8629 pub new_vendor_improvement_rate: f64,
8630
8631 #[serde(default = "default_decline_rate")]
8633 pub complacency_decline_rate: f64,
8634}
8635
8636fn default_improvement_rate() -> f64 {
8637 0.02
8638}
8639
8640fn default_decline_rate() -> f64 {
8641 0.01
8642}
8643
8644impl Default for QualityDriftSchemaConfig {
8645 fn default() -> Self {
8646 Self {
8647 new_vendor_improvement_rate: 0.02,
8648 complacency_decline_rate: 0.01,
8649 }
8650 }
8651}
8652
8653#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8655pub struct CustomerBehaviorSchemaConfig {
8656 #[serde(default)]
8658 pub payment_drift: CustomerPaymentDriftSchemaConfig,
8659
8660 #[serde(default)]
8662 pub order_drift: OrderDriftSchemaConfig,
8663}
8664
8665#[derive(Debug, Clone, Serialize, Deserialize)]
8667pub struct CustomerPaymentDriftSchemaConfig {
8668 #[serde(default = "default_downturn_extension")]
8670 pub downturn_days_extension: (u32, u32),
8671
8672 #[serde(default = "default_bad_debt_increase")]
8674 pub downturn_bad_debt_increase: f64,
8675}
8676
8677fn default_downturn_extension() -> (u32, u32) {
8678 (5, 15)
8679}
8680
8681fn default_bad_debt_increase() -> f64 {
8682 0.02
8683}
8684
8685impl Default for CustomerPaymentDriftSchemaConfig {
8686 fn default() -> Self {
8687 Self {
8688 downturn_days_extension: (5, 15),
8689 downturn_bad_debt_increase: 0.02,
8690 }
8691 }
8692}
8693
8694#[derive(Debug, Clone, Serialize, Deserialize)]
8696pub struct OrderDriftSchemaConfig {
8697 #[serde(default = "default_digital_shift")]
8699 pub digital_shift_rate: f64,
8700}
8701
8702fn default_digital_shift() -> f64 {
8703 0.05
8704}
8705
8706impl Default for OrderDriftSchemaConfig {
8707 fn default() -> Self {
8708 Self {
8709 digital_shift_rate: 0.05,
8710 }
8711 }
8712}
8713
8714#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8716pub struct EmployeeBehaviorSchemaConfig {
8717 #[serde(default)]
8719 pub approval_drift: ApprovalDriftSchemaConfig,
8720
8721 #[serde(default)]
8723 pub error_drift: ErrorDriftSchemaConfig,
8724}
8725
8726#[derive(Debug, Clone, Serialize, Deserialize)]
8728pub struct ApprovalDriftSchemaConfig {
8729 #[serde(default = "default_eom_intensity")]
8731 pub eom_intensity_increase_per_year: f64,
8732
8733 #[serde(default = "default_rubber_stamp")]
8735 pub rubber_stamp_volume_threshold: u32,
8736}
8737
8738fn default_eom_intensity() -> f64 {
8739 0.05
8740}
8741
8742fn default_rubber_stamp() -> u32 {
8743 50
8744}
8745
8746impl Default for ApprovalDriftSchemaConfig {
8747 fn default() -> Self {
8748 Self {
8749 eom_intensity_increase_per_year: 0.05,
8750 rubber_stamp_volume_threshold: 50,
8751 }
8752 }
8753}
8754
8755#[derive(Debug, Clone, Serialize, Deserialize)]
8757pub struct ErrorDriftSchemaConfig {
8758 #[serde(default = "default_new_error")]
8760 pub new_employee_error_rate: f64,
8761
8762 #[serde(default = "default_learning_months")]
8764 pub learning_curve_months: u32,
8765}
8766
8767fn default_new_error() -> f64 {
8768 0.08
8769}
8770
8771fn default_learning_months() -> u32 {
8772 6
8773}
8774
8775impl Default for ErrorDriftSchemaConfig {
8776 fn default() -> Self {
8777 Self {
8778 new_employee_error_rate: 0.08,
8779 learning_curve_months: 6,
8780 }
8781 }
8782}
8783
8784#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8786pub struct CollectiveBehaviorSchemaConfig {
8787 #[serde(default)]
8789 pub automation_adoption: AutomationAdoptionSchemaConfig,
8790}
8791
8792#[derive(Debug, Clone, Serialize, Deserialize)]
8794pub struct AutomationAdoptionSchemaConfig {
8795 #[serde(default)]
8797 pub s_curve_enabled: bool,
8798
8799 #[serde(default = "default_midpoint")]
8801 pub adoption_midpoint_months: u32,
8802
8803 #[serde(default = "default_steepness")]
8805 pub steepness: f64,
8806}
8807
8808fn default_midpoint() -> u32 {
8809 24
8810}
8811
8812fn default_steepness() -> f64 {
8813 0.15
8814}
8815
8816impl Default for AutomationAdoptionSchemaConfig {
8817 fn default() -> Self {
8818 Self {
8819 s_curve_enabled: false,
8820 adoption_midpoint_months: 24,
8821 steepness: 0.15,
8822 }
8823 }
8824}
8825
8826#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8839pub struct MarketDriftSchemaConfig {
8840 #[serde(default)]
8842 pub enabled: bool,
8843
8844 #[serde(default)]
8846 pub economic_cycle: MarketEconomicCycleSchemaConfig,
8847
8848 #[serde(default)]
8850 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8851
8852 #[serde(default)]
8854 pub commodities: CommoditiesSchemaConfig,
8855}
8856
8857#[derive(Debug, Clone, Serialize, Deserialize)]
8859pub struct MarketEconomicCycleSchemaConfig {
8860 #[serde(default)]
8862 pub enabled: bool,
8863
8864 #[serde(default)]
8866 pub cycle_type: CycleTypeSchemaConfig,
8867
8868 #[serde(default = "default_market_cycle_period")]
8870 pub period_months: u32,
8871
8872 #[serde(default = "default_market_amplitude")]
8874 pub amplitude: f64,
8875
8876 #[serde(default)]
8878 pub recession: RecessionSchemaConfig,
8879}
8880
8881fn default_market_cycle_period() -> u32 {
8882 48
8883}
8884
8885fn default_market_amplitude() -> f64 {
8886 0.15
8887}
8888
8889impl Default for MarketEconomicCycleSchemaConfig {
8890 fn default() -> Self {
8891 Self {
8892 enabled: false,
8893 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8894 period_months: 48,
8895 amplitude: 0.15,
8896 recession: RecessionSchemaConfig::default(),
8897 }
8898 }
8899}
8900
8901#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8903#[serde(rename_all = "snake_case")]
8904pub enum CycleTypeSchemaConfig {
8905 #[default]
8907 Sinusoidal,
8908 Asymmetric,
8910 MeanReverting,
8912}
8913
8914#[derive(Debug, Clone, Serialize, Deserialize)]
8916pub struct RecessionSchemaConfig {
8917 #[serde(default)]
8919 pub enabled: bool,
8920
8921 #[serde(default = "default_recession_prob")]
8923 pub probability_per_year: f64,
8924
8925 #[serde(default)]
8927 pub severity: RecessionSeveritySchemaConfig,
8928
8929 #[serde(default)]
8931 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8932}
8933
8934fn default_recession_prob() -> f64 {
8935 0.10
8936}
8937
8938impl Default for RecessionSchemaConfig {
8939 fn default() -> Self {
8940 Self {
8941 enabled: false,
8942 probability_per_year: 0.10,
8943 severity: RecessionSeveritySchemaConfig::Moderate,
8944 recession_periods: Vec::new(),
8945 }
8946 }
8947}
8948
8949#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8951#[serde(rename_all = "snake_case")]
8952pub enum RecessionSeveritySchemaConfig {
8953 Mild,
8955 #[default]
8957 Moderate,
8958 Severe,
8960}
8961
8962#[derive(Debug, Clone, Serialize, Deserialize)]
8964pub struct RecessionPeriodSchemaConfig {
8965 pub start_month: u32,
8967 pub duration_months: u32,
8969}
8970
8971#[derive(Debug, Clone, Serialize, Deserialize)]
8973pub struct IndustryCycleSchemaConfig {
8974 #[serde(default = "default_industry_period")]
8976 pub period_months: u32,
8977
8978 #[serde(default = "default_industry_amp")]
8980 pub amplitude: f64,
8981}
8982
8983fn default_industry_period() -> u32 {
8984 36
8985}
8986
8987fn default_industry_amp() -> f64 {
8988 0.20
8989}
8990
8991#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8993pub struct CommoditiesSchemaConfig {
8994 #[serde(default)]
8996 pub enabled: bool,
8997
8998 #[serde(default)]
9000 pub items: Vec<CommodityItemSchemaConfig>,
9001}
9002
9003#[derive(Debug, Clone, Serialize, Deserialize)]
9005pub struct CommodityItemSchemaConfig {
9006 pub name: String,
9008
9009 #[serde(default = "default_volatility")]
9011 pub volatility: f64,
9012
9013 #[serde(default)]
9015 pub cogs_pass_through: f64,
9016
9017 #[serde(default)]
9019 pub overhead_pass_through: f64,
9020}
9021
9022fn default_volatility() -> f64 {
9023 0.20
9024}
9025
9026#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9039pub struct DriftLabelingSchemaConfig {
9040 #[serde(default)]
9042 pub enabled: bool,
9043
9044 #[serde(default)]
9046 pub statistical: StatisticalDriftLabelingSchemaConfig,
9047
9048 #[serde(default)]
9050 pub categorical: CategoricalDriftLabelingSchemaConfig,
9051
9052 #[serde(default)]
9054 pub temporal: TemporalDriftLabelingSchemaConfig,
9055
9056 #[serde(default)]
9058 pub regulatory_calendar_preset: Option<String>,
9059}
9060
9061#[derive(Debug, Clone, Serialize, Deserialize)]
9063pub struct StatisticalDriftLabelingSchemaConfig {
9064 #[serde(default = "default_true_val")]
9066 pub enabled: bool,
9067
9068 #[serde(default = "default_min_magnitude")]
9070 pub min_magnitude_threshold: f64,
9071}
9072
9073fn default_min_magnitude() -> f64 {
9074 0.05
9075}
9076
9077impl Default for StatisticalDriftLabelingSchemaConfig {
9078 fn default() -> Self {
9079 Self {
9080 enabled: true,
9081 min_magnitude_threshold: 0.05,
9082 }
9083 }
9084}
9085
9086#[derive(Debug, Clone, Serialize, Deserialize)]
9088pub struct CategoricalDriftLabelingSchemaConfig {
9089 #[serde(default = "default_true_val")]
9091 pub enabled: bool,
9092}
9093
9094impl Default for CategoricalDriftLabelingSchemaConfig {
9095 fn default() -> Self {
9096 Self { enabled: true }
9097 }
9098}
9099
9100#[derive(Debug, Clone, Serialize, Deserialize)]
9102pub struct TemporalDriftLabelingSchemaConfig {
9103 #[serde(default = "default_true_val")]
9105 pub enabled: bool,
9106}
9107
9108impl Default for TemporalDriftLabelingSchemaConfig {
9109 fn default() -> Self {
9110 Self { enabled: true }
9111 }
9112}
9113
9114#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9127pub struct EnhancedAnomalyConfig {
9128 #[serde(default)]
9130 pub enabled: bool,
9131
9132 #[serde(default)]
9134 pub rates: AnomalyRateConfig,
9135
9136 #[serde(default)]
9138 pub multi_stage_schemes: MultiStageSchemeConfig,
9139
9140 #[serde(default)]
9142 pub correlated_injection: CorrelatedInjectionConfig,
9143
9144 #[serde(default)]
9146 pub near_miss: NearMissConfig,
9147
9148 #[serde(default)]
9150 pub difficulty_classification: DifficultyClassificationConfig,
9151
9152 #[serde(default)]
9154 pub context_aware: ContextAwareConfig,
9155
9156 #[serde(default)]
9158 pub labeling: EnhancedLabelingConfig,
9159}
9160
9161#[derive(Debug, Clone, Serialize, Deserialize)]
9163pub struct AnomalyRateConfig {
9164 #[serde(default = "default_total_anomaly_rate")]
9166 pub total_rate: f64,
9167
9168 #[serde(default = "default_fraud_anomaly_rate")]
9170 pub fraud_rate: f64,
9171
9172 #[serde(default = "default_error_anomaly_rate")]
9174 pub error_rate: f64,
9175
9176 #[serde(default = "default_process_anomaly_rate")]
9178 pub process_rate: f64,
9179}
9180
9181fn default_total_anomaly_rate() -> f64 {
9182 0.03
9183}
9184fn default_fraud_anomaly_rate() -> f64 {
9185 0.01
9186}
9187fn default_error_anomaly_rate() -> f64 {
9188 0.015
9189}
9190fn default_process_anomaly_rate() -> f64 {
9191 0.005
9192}
9193
9194impl Default for AnomalyRateConfig {
9195 fn default() -> Self {
9196 Self {
9197 total_rate: default_total_anomaly_rate(),
9198 fraud_rate: default_fraud_anomaly_rate(),
9199 error_rate: default_error_anomaly_rate(),
9200 process_rate: default_process_anomaly_rate(),
9201 }
9202 }
9203}
9204
9205#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9207pub struct MultiStageSchemeConfig {
9208 #[serde(default)]
9210 pub enabled: bool,
9211
9212 #[serde(default)]
9214 pub embezzlement: EmbezzlementSchemeConfig,
9215
9216 #[serde(default)]
9218 pub revenue_manipulation: RevenueManipulationSchemeConfig,
9219
9220 #[serde(default)]
9222 pub kickback: KickbackSchemeConfig,
9223}
9224
9225#[derive(Debug, Clone, Serialize, Deserialize)]
9227pub struct EmbezzlementSchemeConfig {
9228 #[serde(default = "default_embezzlement_probability")]
9230 pub probability: f64,
9231
9232 #[serde(default)]
9234 pub testing_stage: SchemeStageConfig,
9235
9236 #[serde(default)]
9238 pub escalation_stage: SchemeStageConfig,
9239
9240 #[serde(default)]
9242 pub acceleration_stage: SchemeStageConfig,
9243
9244 #[serde(default)]
9246 pub desperation_stage: SchemeStageConfig,
9247}
9248
9249fn default_embezzlement_probability() -> f64 {
9250 0.02
9251}
9252
9253impl Default for EmbezzlementSchemeConfig {
9254 fn default() -> Self {
9255 Self {
9256 probability: default_embezzlement_probability(),
9257 testing_stage: SchemeStageConfig {
9258 duration_months: 2,
9259 amount_min: 100.0,
9260 amount_max: 500.0,
9261 transaction_count_min: 2,
9262 transaction_count_max: 5,
9263 difficulty: "hard".to_string(),
9264 },
9265 escalation_stage: SchemeStageConfig {
9266 duration_months: 6,
9267 amount_min: 500.0,
9268 amount_max: 2000.0,
9269 transaction_count_min: 3,
9270 transaction_count_max: 8,
9271 difficulty: "moderate".to_string(),
9272 },
9273 acceleration_stage: SchemeStageConfig {
9274 duration_months: 3,
9275 amount_min: 2000.0,
9276 amount_max: 10000.0,
9277 transaction_count_min: 5,
9278 transaction_count_max: 12,
9279 difficulty: "easy".to_string(),
9280 },
9281 desperation_stage: SchemeStageConfig {
9282 duration_months: 1,
9283 amount_min: 10000.0,
9284 amount_max: 50000.0,
9285 transaction_count_min: 3,
9286 transaction_count_max: 6,
9287 difficulty: "trivial".to_string(),
9288 },
9289 }
9290 }
9291}
9292
9293#[derive(Debug, Clone, Serialize, Deserialize)]
9295pub struct RevenueManipulationSchemeConfig {
9296 #[serde(default = "default_revenue_manipulation_probability")]
9298 pub probability: f64,
9299
9300 #[serde(default = "default_early_recognition_target")]
9302 pub early_recognition_target: f64,
9303
9304 #[serde(default = "default_expense_deferral_target")]
9306 pub expense_deferral_target: f64,
9307
9308 #[serde(default = "default_reserve_release_target")]
9310 pub reserve_release_target: f64,
9311
9312 #[serde(default = "default_channel_stuffing_target")]
9314 pub channel_stuffing_target: f64,
9315}
9316
9317fn default_revenue_manipulation_probability() -> f64 {
9318 0.01
9319}
9320fn default_early_recognition_target() -> f64 {
9321 0.02
9322}
9323fn default_expense_deferral_target() -> f64 {
9324 0.03
9325}
9326fn default_reserve_release_target() -> f64 {
9327 0.02
9328}
9329fn default_channel_stuffing_target() -> f64 {
9330 0.05
9331}
9332
9333impl Default for RevenueManipulationSchemeConfig {
9334 fn default() -> Self {
9335 Self {
9336 probability: default_revenue_manipulation_probability(),
9337 early_recognition_target: default_early_recognition_target(),
9338 expense_deferral_target: default_expense_deferral_target(),
9339 reserve_release_target: default_reserve_release_target(),
9340 channel_stuffing_target: default_channel_stuffing_target(),
9341 }
9342 }
9343}
9344
9345#[derive(Debug, Clone, Serialize, Deserialize)]
9347pub struct KickbackSchemeConfig {
9348 #[serde(default = "default_kickback_probability")]
9350 pub probability: f64,
9351
9352 #[serde(default = "default_kickback_inflation_min")]
9354 pub inflation_min: f64,
9355
9356 #[serde(default = "default_kickback_inflation_max")]
9358 pub inflation_max: f64,
9359
9360 #[serde(default = "default_kickback_percent")]
9362 pub kickback_percent: f64,
9363
9364 #[serde(default = "default_kickback_setup_months")]
9366 pub setup_months: u32,
9367
9368 #[serde(default = "default_kickback_operation_months")]
9370 pub operation_months: u32,
9371}
9372
9373fn default_kickback_probability() -> f64 {
9374 0.01
9375}
9376fn default_kickback_inflation_min() -> f64 {
9377 0.10
9378}
9379fn default_kickback_inflation_max() -> f64 {
9380 0.25
9381}
9382fn default_kickback_percent() -> f64 {
9383 0.50
9384}
9385fn default_kickback_setup_months() -> u32 {
9386 3
9387}
9388fn default_kickback_operation_months() -> u32 {
9389 12
9390}
9391
9392impl Default for KickbackSchemeConfig {
9393 fn default() -> Self {
9394 Self {
9395 probability: default_kickback_probability(),
9396 inflation_min: default_kickback_inflation_min(),
9397 inflation_max: default_kickback_inflation_max(),
9398 kickback_percent: default_kickback_percent(),
9399 setup_months: default_kickback_setup_months(),
9400 operation_months: default_kickback_operation_months(),
9401 }
9402 }
9403}
9404
9405#[derive(Debug, Clone, Serialize, Deserialize)]
9407pub struct SchemeStageConfig {
9408 pub duration_months: u32,
9410
9411 pub amount_min: f64,
9413
9414 pub amount_max: f64,
9416
9417 pub transaction_count_min: u32,
9419
9420 pub transaction_count_max: u32,
9422
9423 pub difficulty: String,
9425}
9426
9427impl Default for SchemeStageConfig {
9428 fn default() -> Self {
9429 Self {
9430 duration_months: 3,
9431 amount_min: 100.0,
9432 amount_max: 1000.0,
9433 transaction_count_min: 2,
9434 transaction_count_max: 10,
9435 difficulty: "moderate".to_string(),
9436 }
9437 }
9438}
9439
9440#[derive(Debug, Clone, Serialize, Deserialize)]
9442pub struct CorrelatedInjectionConfig {
9443 #[serde(default)]
9445 pub enabled: bool,
9446
9447 #[serde(default = "default_true_val")]
9449 pub fraud_concealment: bool,
9450
9451 #[serde(default = "default_true_val")]
9453 pub error_cascade: bool,
9454
9455 #[serde(default = "default_true_val")]
9457 pub temporal_clustering: bool,
9458
9459 #[serde(default)]
9461 pub temporal_clustering_config: TemporalClusteringConfig,
9462
9463 #[serde(default)]
9465 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
9466}
9467
9468impl Default for CorrelatedInjectionConfig {
9469 fn default() -> Self {
9470 Self {
9471 enabled: false,
9472 fraud_concealment: true,
9473 error_cascade: true,
9474 temporal_clustering: true,
9475 temporal_clustering_config: TemporalClusteringConfig::default(),
9476 co_occurrence_patterns: Vec::new(),
9477 }
9478 }
9479}
9480
9481#[derive(Debug, Clone, Serialize, Deserialize)]
9483pub struct TemporalClusteringConfig {
9484 #[serde(default = "default_period_end_multiplier")]
9486 pub period_end_multiplier: f64,
9487
9488 #[serde(default = "default_period_end_days")]
9490 pub period_end_days: u32,
9491
9492 #[serde(default = "default_quarter_end_multiplier")]
9494 pub quarter_end_multiplier: f64,
9495
9496 #[serde(default = "default_year_end_multiplier")]
9498 pub year_end_multiplier: f64,
9499}
9500
9501fn default_period_end_multiplier() -> f64 {
9502 2.5
9503}
9504fn default_period_end_days() -> u32 {
9505 5
9506}
9507fn default_quarter_end_multiplier() -> f64 {
9508 1.5
9509}
9510fn default_year_end_multiplier() -> f64 {
9511 2.0
9512}
9513
9514impl Default for TemporalClusteringConfig {
9515 fn default() -> Self {
9516 Self {
9517 period_end_multiplier: default_period_end_multiplier(),
9518 period_end_days: default_period_end_days(),
9519 quarter_end_multiplier: default_quarter_end_multiplier(),
9520 year_end_multiplier: default_year_end_multiplier(),
9521 }
9522 }
9523}
9524
9525#[derive(Debug, Clone, Serialize, Deserialize)]
9527pub struct CoOccurrencePatternConfig {
9528 pub name: String,
9530
9531 pub primary_type: String,
9533
9534 pub correlated: Vec<CorrelatedAnomalyConfig>,
9536}
9537
9538#[derive(Debug, Clone, Serialize, Deserialize)]
9540pub struct CorrelatedAnomalyConfig {
9541 pub anomaly_type: String,
9543
9544 pub probability: f64,
9546
9547 pub lag_days_min: i32,
9549
9550 pub lag_days_max: i32,
9552}
9553
9554#[derive(Debug, Clone, Serialize, Deserialize)]
9556pub struct NearMissConfig {
9557 #[serde(default)]
9559 pub enabled: bool,
9560
9561 #[serde(default = "default_near_miss_proportion")]
9563 pub proportion: f64,
9564
9565 #[serde(default = "default_true_val")]
9567 pub near_duplicate: bool,
9568
9569 #[serde(default)]
9571 pub near_duplicate_days: NearDuplicateDaysConfig,
9572
9573 #[serde(default = "default_true_val")]
9575 pub threshold_proximity: bool,
9576
9577 #[serde(default)]
9579 pub threshold_proximity_range: ThresholdProximityRangeConfig,
9580
9581 #[serde(default = "default_true_val")]
9583 pub unusual_legitimate: bool,
9584
9585 #[serde(default = "default_unusual_legitimate_types")]
9587 pub unusual_legitimate_types: Vec<String>,
9588
9589 #[serde(default = "default_true_val")]
9591 pub corrected_errors: bool,
9592
9593 #[serde(default)]
9595 pub corrected_error_lag: CorrectedErrorLagConfig,
9596}
9597
9598fn default_near_miss_proportion() -> f64 {
9599 0.30
9600}
9601
9602fn default_unusual_legitimate_types() -> Vec<String> {
9603 vec![
9604 "year_end_bonus".to_string(),
9605 "contract_prepayment".to_string(),
9606 "insurance_claim".to_string(),
9607 "settlement_payment".to_string(),
9608 ]
9609}
9610
9611impl Default for NearMissConfig {
9612 fn default() -> Self {
9613 Self {
9614 enabled: false,
9615 proportion: default_near_miss_proportion(),
9616 near_duplicate: true,
9617 near_duplicate_days: NearDuplicateDaysConfig::default(),
9618 threshold_proximity: true,
9619 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
9620 unusual_legitimate: true,
9621 unusual_legitimate_types: default_unusual_legitimate_types(),
9622 corrected_errors: true,
9623 corrected_error_lag: CorrectedErrorLagConfig::default(),
9624 }
9625 }
9626}
9627
9628#[derive(Debug, Clone, Serialize, Deserialize)]
9630pub struct NearDuplicateDaysConfig {
9631 #[serde(default = "default_near_duplicate_min")]
9633 pub min: u32,
9634
9635 #[serde(default = "default_near_duplicate_max")]
9637 pub max: u32,
9638}
9639
9640fn default_near_duplicate_min() -> u32 {
9641 1
9642}
9643fn default_near_duplicate_max() -> u32 {
9644 3
9645}
9646
9647impl Default for NearDuplicateDaysConfig {
9648 fn default() -> Self {
9649 Self {
9650 min: default_near_duplicate_min(),
9651 max: default_near_duplicate_max(),
9652 }
9653 }
9654}
9655
9656#[derive(Debug, Clone, Serialize, Deserialize)]
9658pub struct ThresholdProximityRangeConfig {
9659 #[serde(default = "default_threshold_proximity_min")]
9661 pub min: f64,
9662
9663 #[serde(default = "default_threshold_proximity_max")]
9665 pub max: f64,
9666}
9667
9668fn default_threshold_proximity_min() -> f64 {
9669 0.90
9670}
9671fn default_threshold_proximity_max() -> f64 {
9672 0.99
9673}
9674
9675impl Default for ThresholdProximityRangeConfig {
9676 fn default() -> Self {
9677 Self {
9678 min: default_threshold_proximity_min(),
9679 max: default_threshold_proximity_max(),
9680 }
9681 }
9682}
9683
9684#[derive(Debug, Clone, Serialize, Deserialize)]
9686pub struct CorrectedErrorLagConfig {
9687 #[serde(default = "default_corrected_error_lag_min")]
9689 pub min: u32,
9690
9691 #[serde(default = "default_corrected_error_lag_max")]
9693 pub max: u32,
9694}
9695
9696fn default_corrected_error_lag_min() -> u32 {
9697 1
9698}
9699fn default_corrected_error_lag_max() -> u32 {
9700 5
9701}
9702
9703impl Default for CorrectedErrorLagConfig {
9704 fn default() -> Self {
9705 Self {
9706 min: default_corrected_error_lag_min(),
9707 max: default_corrected_error_lag_max(),
9708 }
9709 }
9710}
9711
9712#[derive(Debug, Clone, Serialize, Deserialize)]
9714pub struct DifficultyClassificationConfig {
9715 #[serde(default)]
9717 pub enabled: bool,
9718
9719 #[serde(default)]
9721 pub target_distribution: DifficultyDistributionConfig,
9722}
9723
9724impl Default for DifficultyClassificationConfig {
9725 fn default() -> Self {
9726 Self {
9727 enabled: true,
9728 target_distribution: DifficultyDistributionConfig::default(),
9729 }
9730 }
9731}
9732
9733#[derive(Debug, Clone, Serialize, Deserialize)]
9735pub struct DifficultyDistributionConfig {
9736 #[serde(default = "default_difficulty_trivial")]
9738 pub trivial: f64,
9739
9740 #[serde(default = "default_difficulty_easy")]
9742 pub easy: f64,
9743
9744 #[serde(default = "default_difficulty_moderate")]
9746 pub moderate: f64,
9747
9748 #[serde(default = "default_difficulty_hard")]
9750 pub hard: f64,
9751
9752 #[serde(default = "default_difficulty_expert")]
9754 pub expert: f64,
9755}
9756
9757fn default_difficulty_trivial() -> f64 {
9758 0.15
9759}
9760fn default_difficulty_easy() -> f64 {
9761 0.25
9762}
9763fn default_difficulty_moderate() -> f64 {
9764 0.30
9765}
9766fn default_difficulty_hard() -> f64 {
9767 0.20
9768}
9769fn default_difficulty_expert() -> f64 {
9770 0.10
9771}
9772
9773impl Default for DifficultyDistributionConfig {
9774 fn default() -> Self {
9775 Self {
9776 trivial: default_difficulty_trivial(),
9777 easy: default_difficulty_easy(),
9778 moderate: default_difficulty_moderate(),
9779 hard: default_difficulty_hard(),
9780 expert: default_difficulty_expert(),
9781 }
9782 }
9783}
9784
9785#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9787pub struct ContextAwareConfig {
9788 #[serde(default)]
9790 pub enabled: bool,
9791
9792 #[serde(default)]
9794 pub vendor_rules: VendorAnomalyRulesConfig,
9795
9796 #[serde(default)]
9798 pub employee_rules: EmployeeAnomalyRulesConfig,
9799
9800 #[serde(default)]
9802 pub account_rules: AccountAnomalyRulesConfig,
9803
9804 #[serde(default)]
9806 pub behavioral_baseline: BehavioralBaselineConfig,
9807}
9808
9809#[derive(Debug, Clone, Serialize, Deserialize)]
9811pub struct VendorAnomalyRulesConfig {
9812 #[serde(default = "default_new_vendor_multiplier")]
9814 pub new_vendor_error_multiplier: f64,
9815
9816 #[serde(default = "default_new_vendor_threshold")]
9818 pub new_vendor_threshold_days: u32,
9819
9820 #[serde(default = "default_international_multiplier")]
9822 pub international_error_multiplier: f64,
9823
9824 #[serde(default = "default_strategic_vendor_types")]
9826 pub strategic_vendor_anomaly_types: Vec<String>,
9827}
9828
9829fn default_new_vendor_multiplier() -> f64 {
9830 2.5
9831}
9832fn default_new_vendor_threshold() -> u32 {
9833 90
9834}
9835fn default_international_multiplier() -> f64 {
9836 1.5
9837}
9838fn default_strategic_vendor_types() -> Vec<String> {
9839 vec![
9840 "pricing_dispute".to_string(),
9841 "contract_violation".to_string(),
9842 ]
9843}
9844
9845impl Default for VendorAnomalyRulesConfig {
9846 fn default() -> Self {
9847 Self {
9848 new_vendor_error_multiplier: default_new_vendor_multiplier(),
9849 new_vendor_threshold_days: default_new_vendor_threshold(),
9850 international_error_multiplier: default_international_multiplier(),
9851 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9852 }
9853 }
9854}
9855
9856#[derive(Debug, Clone, Serialize, Deserialize)]
9858pub struct EmployeeAnomalyRulesConfig {
9859 #[serde(default = "default_new_employee_rate")]
9861 pub new_employee_error_rate: f64,
9862
9863 #[serde(default = "default_new_employee_threshold")]
9865 pub new_employee_threshold_days: u32,
9866
9867 #[serde(default = "default_volume_fatigue_threshold")]
9869 pub volume_fatigue_threshold: u32,
9870
9871 #[serde(default = "default_coverage_multiplier")]
9873 pub coverage_error_multiplier: f64,
9874}
9875
9876fn default_new_employee_rate() -> f64 {
9877 0.05
9878}
9879fn default_new_employee_threshold() -> u32 {
9880 180
9881}
9882fn default_volume_fatigue_threshold() -> u32 {
9883 50
9884}
9885fn default_coverage_multiplier() -> f64 {
9886 1.8
9887}
9888
9889impl Default for EmployeeAnomalyRulesConfig {
9890 fn default() -> Self {
9891 Self {
9892 new_employee_error_rate: default_new_employee_rate(),
9893 new_employee_threshold_days: default_new_employee_threshold(),
9894 volume_fatigue_threshold: default_volume_fatigue_threshold(),
9895 coverage_error_multiplier: default_coverage_multiplier(),
9896 }
9897 }
9898}
9899
9900#[derive(Debug, Clone, Serialize, Deserialize)]
9902pub struct AccountAnomalyRulesConfig {
9903 #[serde(default = "default_high_risk_multiplier")]
9905 pub high_risk_account_multiplier: f64,
9906
9907 #[serde(default = "default_high_risk_accounts")]
9909 pub high_risk_accounts: Vec<String>,
9910
9911 #[serde(default = "default_suspense_multiplier")]
9913 pub suspense_account_multiplier: f64,
9914
9915 #[serde(default = "default_suspense_accounts")]
9917 pub suspense_accounts: Vec<String>,
9918
9919 #[serde(default = "default_intercompany_multiplier")]
9921 pub intercompany_account_multiplier: f64,
9922}
9923
9924fn default_high_risk_multiplier() -> f64 {
9925 2.0
9926}
9927fn default_high_risk_accounts() -> Vec<String> {
9928 vec![
9929 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
9933}
9934fn default_suspense_multiplier() -> f64 {
9935 3.0
9936}
9937fn default_suspense_accounts() -> Vec<String> {
9938 vec!["9999".to_string(), "9998".to_string()]
9939}
9940fn default_intercompany_multiplier() -> f64 {
9941 1.5
9942}
9943
9944impl Default for AccountAnomalyRulesConfig {
9945 fn default() -> Self {
9946 Self {
9947 high_risk_account_multiplier: default_high_risk_multiplier(),
9948 high_risk_accounts: default_high_risk_accounts(),
9949 suspense_account_multiplier: default_suspense_multiplier(),
9950 suspense_accounts: default_suspense_accounts(),
9951 intercompany_account_multiplier: default_intercompany_multiplier(),
9952 }
9953 }
9954}
9955
9956#[derive(Debug, Clone, Serialize, Deserialize)]
9958pub struct BehavioralBaselineConfig {
9959 #[serde(default)]
9961 pub enabled: bool,
9962
9963 #[serde(default = "default_baseline_period")]
9965 pub baseline_period_days: u32,
9966
9967 #[serde(default = "default_deviation_threshold")]
9969 pub deviation_threshold_std: f64,
9970
9971 #[serde(default = "default_frequency_deviation")]
9973 pub frequency_deviation_threshold: f64,
9974}
9975
9976fn default_baseline_period() -> u32 {
9977 90
9978}
9979fn default_deviation_threshold() -> f64 {
9980 3.0
9981}
9982fn default_frequency_deviation() -> f64 {
9983 2.0
9984}
9985
9986impl Default for BehavioralBaselineConfig {
9987 fn default() -> Self {
9988 Self {
9989 enabled: false,
9990 baseline_period_days: default_baseline_period(),
9991 deviation_threshold_std: default_deviation_threshold(),
9992 frequency_deviation_threshold: default_frequency_deviation(),
9993 }
9994 }
9995}
9996
9997#[derive(Debug, Clone, Serialize, Deserialize)]
9999pub struct EnhancedLabelingConfig {
10000 #[serde(default = "default_true_val")]
10002 pub severity_scoring: bool,
10003
10004 #[serde(default = "default_true_val")]
10006 pub difficulty_classification: bool,
10007
10008 #[serde(default)]
10010 pub materiality_thresholds: MaterialityThresholdsConfig,
10011}
10012
10013impl Default for EnhancedLabelingConfig {
10014 fn default() -> Self {
10015 Self {
10016 severity_scoring: true,
10017 difficulty_classification: true,
10018 materiality_thresholds: MaterialityThresholdsConfig::default(),
10019 }
10020 }
10021}
10022
10023#[derive(Debug, Clone, Serialize, Deserialize)]
10025pub struct MaterialityThresholdsConfig {
10026 #[serde(default = "default_materiality_trivial")]
10028 pub trivial: f64,
10029
10030 #[serde(default = "default_materiality_immaterial")]
10032 pub immaterial: f64,
10033
10034 #[serde(default = "default_materiality_material")]
10036 pub material: f64,
10037
10038 #[serde(default = "default_materiality_highly_material")]
10040 pub highly_material: f64,
10041}
10042
10043fn default_materiality_trivial() -> f64 {
10044 0.001
10045}
10046fn default_materiality_immaterial() -> f64 {
10047 0.01
10048}
10049fn default_materiality_material() -> f64 {
10050 0.05
10051}
10052fn default_materiality_highly_material() -> f64 {
10053 0.10
10054}
10055
10056impl Default for MaterialityThresholdsConfig {
10057 fn default() -> Self {
10058 Self {
10059 trivial: default_materiality_trivial(),
10060 immaterial: default_materiality_immaterial(),
10061 material: default_materiality_material(),
10062 highly_material: default_materiality_highly_material(),
10063 }
10064 }
10065}
10066
10067#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10079pub struct IndustrySpecificConfig {
10080 #[serde(default)]
10082 pub enabled: bool,
10083
10084 #[serde(default)]
10086 pub manufacturing: ManufacturingConfig,
10087
10088 #[serde(default)]
10090 pub retail: RetailConfig,
10091
10092 #[serde(default)]
10094 pub healthcare: HealthcareConfig,
10095
10096 #[serde(default)]
10098 pub technology: TechnologyConfig,
10099
10100 #[serde(default)]
10102 pub financial_services: FinancialServicesConfig,
10103
10104 #[serde(default)]
10106 pub professional_services: ProfessionalServicesConfig,
10107}
10108
10109#[derive(Debug, Clone, Serialize, Deserialize)]
10111pub struct ManufacturingConfig {
10112 #[serde(default)]
10114 pub enabled: bool,
10115
10116 #[serde(default = "default_bom_depth")]
10118 pub bom_depth: u32,
10119
10120 #[serde(default)]
10122 pub just_in_time: bool,
10123
10124 #[serde(default = "default_production_order_types")]
10126 pub production_order_types: Vec<String>,
10127
10128 #[serde(default)]
10130 pub quality_framework: Option<String>,
10131
10132 #[serde(default = "default_supplier_tiers")]
10134 pub supplier_tiers: u32,
10135
10136 #[serde(default = "default_cost_frequency")]
10138 pub standard_cost_frequency: String,
10139
10140 #[serde(default = "default_yield_rate")]
10142 pub target_yield_rate: f64,
10143
10144 #[serde(default = "default_scrap_threshold")]
10146 pub scrap_alert_threshold: f64,
10147
10148 #[serde(default)]
10150 pub anomaly_rates: ManufacturingAnomalyRates,
10151
10152 #[serde(default)]
10154 pub cost_accounting: ManufacturingCostAccountingConfig,
10155}
10156
10157#[derive(Debug, Clone, Serialize, Deserialize)]
10159pub struct ManufacturingCostAccountingConfig {
10160 #[serde(default = "default_true")]
10162 pub enabled: bool,
10163
10164 #[serde(default = "default_true")]
10166 pub variance_accounts_enabled: bool,
10167
10168 #[serde(default = "default_true")]
10170 pub warranty_provisions_enabled: bool,
10171
10172 #[serde(default = "default_warranty_defect_threshold")]
10174 pub warranty_defect_threshold: f64,
10175}
10176
10177fn default_warranty_defect_threshold() -> f64 {
10178 0.01
10179}
10180
10181impl Default for ManufacturingCostAccountingConfig {
10182 fn default() -> Self {
10183 Self {
10184 enabled: true,
10185 variance_accounts_enabled: true,
10186 warranty_provisions_enabled: true,
10187 warranty_defect_threshold: 0.01,
10188 }
10189 }
10190}
10191
10192fn default_bom_depth() -> u32 {
10193 4
10194}
10195
10196fn default_production_order_types() -> Vec<String> {
10197 vec![
10198 "standard".to_string(),
10199 "rework".to_string(),
10200 "prototype".to_string(),
10201 ]
10202}
10203
10204fn default_supplier_tiers() -> u32 {
10205 2
10206}
10207
10208fn default_cost_frequency() -> String {
10209 "quarterly".to_string()
10210}
10211
10212fn default_yield_rate() -> f64 {
10213 0.97
10214}
10215
10216fn default_scrap_threshold() -> f64 {
10217 0.03
10218}
10219
10220impl Default for ManufacturingConfig {
10221 fn default() -> Self {
10222 Self {
10223 enabled: false,
10224 bom_depth: default_bom_depth(),
10225 just_in_time: false,
10226 production_order_types: default_production_order_types(),
10227 quality_framework: Some("ISO_9001".to_string()),
10228 supplier_tiers: default_supplier_tiers(),
10229 standard_cost_frequency: default_cost_frequency(),
10230 target_yield_rate: default_yield_rate(),
10231 scrap_alert_threshold: default_scrap_threshold(),
10232 anomaly_rates: ManufacturingAnomalyRates::default(),
10233 cost_accounting: ManufacturingCostAccountingConfig::default(),
10234 }
10235 }
10236}
10237
10238#[derive(Debug, Clone, Serialize, Deserialize)]
10240pub struct ManufacturingAnomalyRates {
10241 #[serde(default = "default_mfg_yield_rate")]
10243 pub yield_manipulation: f64,
10244
10245 #[serde(default = "default_mfg_labor_rate")]
10247 pub labor_misallocation: f64,
10248
10249 #[serde(default = "default_mfg_phantom_rate")]
10251 pub phantom_production: f64,
10252
10253 #[serde(default = "default_mfg_cost_rate")]
10255 pub standard_cost_manipulation: f64,
10256
10257 #[serde(default = "default_mfg_inventory_rate")]
10259 pub inventory_fraud: f64,
10260}
10261
10262fn default_mfg_yield_rate() -> f64 {
10263 0.015
10264}
10265
10266fn default_mfg_labor_rate() -> f64 {
10267 0.02
10268}
10269
10270fn default_mfg_phantom_rate() -> f64 {
10271 0.005
10272}
10273
10274fn default_mfg_cost_rate() -> f64 {
10275 0.01
10276}
10277
10278fn default_mfg_inventory_rate() -> f64 {
10279 0.008
10280}
10281
10282impl Default for ManufacturingAnomalyRates {
10283 fn default() -> Self {
10284 Self {
10285 yield_manipulation: default_mfg_yield_rate(),
10286 labor_misallocation: default_mfg_labor_rate(),
10287 phantom_production: default_mfg_phantom_rate(),
10288 standard_cost_manipulation: default_mfg_cost_rate(),
10289 inventory_fraud: default_mfg_inventory_rate(),
10290 }
10291 }
10292}
10293
10294#[derive(Debug, Clone, Serialize, Deserialize)]
10296pub struct RetailConfig {
10297 #[serde(default)]
10299 pub enabled: bool,
10300
10301 #[serde(default)]
10303 pub store_types: RetailStoreTypeConfig,
10304
10305 #[serde(default = "default_retail_daily_txns")]
10307 pub avg_daily_transactions: u32,
10308
10309 #[serde(default = "default_true")]
10311 pub loss_prevention: bool,
10312
10313 #[serde(default = "default_shrinkage_rate")]
10315 pub shrinkage_rate: f64,
10316
10317 #[serde(default)]
10319 pub anomaly_rates: RetailAnomalyRates,
10320}
10321
10322fn default_retail_daily_txns() -> u32 {
10323 500
10324}
10325
10326fn default_shrinkage_rate() -> f64 {
10327 0.015
10328}
10329
10330impl Default for RetailConfig {
10331 fn default() -> Self {
10332 Self {
10333 enabled: false,
10334 store_types: RetailStoreTypeConfig::default(),
10335 avg_daily_transactions: default_retail_daily_txns(),
10336 loss_prevention: true,
10337 shrinkage_rate: default_shrinkage_rate(),
10338 anomaly_rates: RetailAnomalyRates::default(),
10339 }
10340 }
10341}
10342
10343#[derive(Debug, Clone, Serialize, Deserialize)]
10345pub struct RetailStoreTypeConfig {
10346 #[serde(default = "default_flagship_pct")]
10348 pub flagship: f64,
10349
10350 #[serde(default = "default_regional_pct")]
10352 pub regional: f64,
10353
10354 #[serde(default = "default_outlet_pct")]
10356 pub outlet: f64,
10357
10358 #[serde(default = "default_ecommerce_pct")]
10360 pub ecommerce: f64,
10361}
10362
10363fn default_flagship_pct() -> f64 {
10364 0.10
10365}
10366
10367fn default_regional_pct() -> f64 {
10368 0.50
10369}
10370
10371fn default_outlet_pct() -> f64 {
10372 0.25
10373}
10374
10375fn default_ecommerce_pct() -> f64 {
10376 0.15
10377}
10378
10379impl Default for RetailStoreTypeConfig {
10380 fn default() -> Self {
10381 Self {
10382 flagship: default_flagship_pct(),
10383 regional: default_regional_pct(),
10384 outlet: default_outlet_pct(),
10385 ecommerce: default_ecommerce_pct(),
10386 }
10387 }
10388}
10389
10390#[derive(Debug, Clone, Serialize, Deserialize)]
10392pub struct RetailAnomalyRates {
10393 #[serde(default = "default_sweethearting_rate")]
10395 pub sweethearting: f64,
10396
10397 #[serde(default = "default_skimming_rate")]
10399 pub skimming: f64,
10400
10401 #[serde(default = "default_refund_fraud_rate")]
10403 pub refund_fraud: f64,
10404
10405 #[serde(default = "default_void_abuse_rate")]
10407 pub void_abuse: f64,
10408
10409 #[serde(default = "default_gift_card_rate")]
10411 pub gift_card_fraud: f64,
10412
10413 #[serde(default = "default_retail_kickback_rate")]
10415 pub vendor_kickback: f64,
10416}
10417
10418fn default_sweethearting_rate() -> f64 {
10419 0.02
10420}
10421
10422fn default_skimming_rate() -> f64 {
10423 0.005
10424}
10425
10426fn default_refund_fraud_rate() -> f64 {
10427 0.015
10428}
10429
10430fn default_void_abuse_rate() -> f64 {
10431 0.01
10432}
10433
10434fn default_gift_card_rate() -> f64 {
10435 0.008
10436}
10437
10438fn default_retail_kickback_rate() -> f64 {
10439 0.003
10440}
10441
10442impl Default for RetailAnomalyRates {
10443 fn default() -> Self {
10444 Self {
10445 sweethearting: default_sweethearting_rate(),
10446 skimming: default_skimming_rate(),
10447 refund_fraud: default_refund_fraud_rate(),
10448 void_abuse: default_void_abuse_rate(),
10449 gift_card_fraud: default_gift_card_rate(),
10450 vendor_kickback: default_retail_kickback_rate(),
10451 }
10452 }
10453}
10454
10455#[derive(Debug, Clone, Serialize, Deserialize)]
10457pub struct HealthcareConfig {
10458 #[serde(default)]
10460 pub enabled: bool,
10461
10462 #[serde(default = "default_facility_type")]
10464 pub facility_type: String,
10465
10466 #[serde(default)]
10468 pub payer_mix: HealthcarePayerMix,
10469
10470 #[serde(default)]
10472 pub coding_systems: HealthcareCodingSystems,
10473
10474 #[serde(default)]
10476 pub compliance: HealthcareComplianceConfig,
10477
10478 #[serde(default = "default_daily_encounters")]
10480 pub avg_daily_encounters: u32,
10481
10482 #[serde(default = "default_charges_per_encounter")]
10484 pub avg_charges_per_encounter: u32,
10485
10486 #[serde(default = "default_hc_denial_rate")]
10488 pub denial_rate: f64,
10489
10490 #[serde(default = "default_hc_bad_debt_rate")]
10492 pub bad_debt_rate: f64,
10493
10494 #[serde(default = "default_hc_charity_care_rate")]
10496 pub charity_care_rate: f64,
10497
10498 #[serde(default)]
10500 pub anomaly_rates: HealthcareAnomalyRates,
10501}
10502
10503fn default_facility_type() -> String {
10504 "hospital".to_string()
10505}
10506
10507fn default_daily_encounters() -> u32 {
10508 150
10509}
10510
10511fn default_charges_per_encounter() -> u32 {
10512 8
10513}
10514
10515fn default_hc_denial_rate() -> f64 {
10516 0.05
10517}
10518
10519fn default_hc_bad_debt_rate() -> f64 {
10520 0.03
10521}
10522
10523fn default_hc_charity_care_rate() -> f64 {
10524 0.02
10525}
10526
10527impl Default for HealthcareConfig {
10528 fn default() -> Self {
10529 Self {
10530 enabled: false,
10531 facility_type: default_facility_type(),
10532 payer_mix: HealthcarePayerMix::default(),
10533 coding_systems: HealthcareCodingSystems::default(),
10534 compliance: HealthcareComplianceConfig::default(),
10535 avg_daily_encounters: default_daily_encounters(),
10536 avg_charges_per_encounter: default_charges_per_encounter(),
10537 denial_rate: default_hc_denial_rate(),
10538 bad_debt_rate: default_hc_bad_debt_rate(),
10539 charity_care_rate: default_hc_charity_care_rate(),
10540 anomaly_rates: HealthcareAnomalyRates::default(),
10541 }
10542 }
10543}
10544
10545#[derive(Debug, Clone, Serialize, Deserialize)]
10547pub struct HealthcarePayerMix {
10548 #[serde(default = "default_medicare_pct")]
10550 pub medicare: f64,
10551
10552 #[serde(default = "default_medicaid_pct")]
10554 pub medicaid: f64,
10555
10556 #[serde(default = "default_commercial_pct")]
10558 pub commercial: f64,
10559
10560 #[serde(default = "default_self_pay_pct")]
10562 pub self_pay: f64,
10563}
10564
10565fn default_medicare_pct() -> f64 {
10566 0.40
10567}
10568
10569fn default_medicaid_pct() -> f64 {
10570 0.20
10571}
10572
10573fn default_commercial_pct() -> f64 {
10574 0.30
10575}
10576
10577fn default_self_pay_pct() -> f64 {
10578 0.10
10579}
10580
10581impl Default for HealthcarePayerMix {
10582 fn default() -> Self {
10583 Self {
10584 medicare: default_medicare_pct(),
10585 medicaid: default_medicaid_pct(),
10586 commercial: default_commercial_pct(),
10587 self_pay: default_self_pay_pct(),
10588 }
10589 }
10590}
10591
10592#[derive(Debug, Clone, Serialize, Deserialize)]
10594pub struct HealthcareCodingSystems {
10595 #[serde(default = "default_true")]
10597 pub icd10: bool,
10598
10599 #[serde(default = "default_true")]
10601 pub cpt: bool,
10602
10603 #[serde(default = "default_true")]
10605 pub drg: bool,
10606
10607 #[serde(default = "default_true")]
10609 pub hcpcs: bool,
10610
10611 #[serde(default = "default_true")]
10613 pub revenue_codes: bool,
10614}
10615
10616impl Default for HealthcareCodingSystems {
10617 fn default() -> Self {
10618 Self {
10619 icd10: true,
10620 cpt: true,
10621 drg: true,
10622 hcpcs: true,
10623 revenue_codes: true,
10624 }
10625 }
10626}
10627
10628#[derive(Debug, Clone, Serialize, Deserialize)]
10630pub struct HealthcareComplianceConfig {
10631 #[serde(default = "default_true")]
10633 pub hipaa: bool,
10634
10635 #[serde(default = "default_true")]
10637 pub stark_law: bool,
10638
10639 #[serde(default = "default_true")]
10641 pub anti_kickback: bool,
10642
10643 #[serde(default = "default_true")]
10645 pub false_claims_act: bool,
10646
10647 #[serde(default = "default_true")]
10649 pub emtala: bool,
10650}
10651
10652impl Default for HealthcareComplianceConfig {
10653 fn default() -> Self {
10654 Self {
10655 hipaa: true,
10656 stark_law: true,
10657 anti_kickback: true,
10658 false_claims_act: true,
10659 emtala: true,
10660 }
10661 }
10662}
10663
10664#[derive(Debug, Clone, Serialize, Deserialize)]
10666pub struct HealthcareAnomalyRates {
10667 #[serde(default = "default_upcoding_rate")]
10669 pub upcoding: f64,
10670
10671 #[serde(default = "default_unbundling_rate")]
10673 pub unbundling: f64,
10674
10675 #[serde(default = "default_phantom_billing_rate")]
10677 pub phantom_billing: f64,
10678
10679 #[serde(default = "default_healthcare_kickback_rate")]
10681 pub kickbacks: f64,
10682
10683 #[serde(default = "default_duplicate_billing_rate")]
10685 pub duplicate_billing: f64,
10686
10687 #[serde(default = "default_med_necessity_rate")]
10689 pub medical_necessity_abuse: f64,
10690}
10691
10692fn default_upcoding_rate() -> f64 {
10693 0.02
10694}
10695
10696fn default_unbundling_rate() -> f64 {
10697 0.015
10698}
10699
10700fn default_phantom_billing_rate() -> f64 {
10701 0.005
10702}
10703
10704fn default_healthcare_kickback_rate() -> f64 {
10705 0.003
10706}
10707
10708fn default_duplicate_billing_rate() -> f64 {
10709 0.008
10710}
10711
10712fn default_med_necessity_rate() -> f64 {
10713 0.01
10714}
10715
10716impl Default for HealthcareAnomalyRates {
10717 fn default() -> Self {
10718 Self {
10719 upcoding: default_upcoding_rate(),
10720 unbundling: default_unbundling_rate(),
10721 phantom_billing: default_phantom_billing_rate(),
10722 kickbacks: default_healthcare_kickback_rate(),
10723 duplicate_billing: default_duplicate_billing_rate(),
10724 medical_necessity_abuse: default_med_necessity_rate(),
10725 }
10726 }
10727}
10728
10729#[derive(Debug, Clone, Serialize, Deserialize)]
10731pub struct TechnologyConfig {
10732 #[serde(default)]
10734 pub enabled: bool,
10735
10736 #[serde(default = "default_revenue_model")]
10738 pub revenue_model: String,
10739
10740 #[serde(default = "default_subscription_pct")]
10742 pub subscription_revenue_pct: f64,
10743
10744 #[serde(default = "default_license_pct")]
10746 pub license_revenue_pct: f64,
10747
10748 #[serde(default = "default_services_pct")]
10750 pub services_revenue_pct: f64,
10751
10752 #[serde(default)]
10754 pub rd_capitalization: RdCapitalizationConfig,
10755
10756 #[serde(default)]
10758 pub anomaly_rates: TechnologyAnomalyRates,
10759}
10760
10761fn default_revenue_model() -> String {
10762 "saas".to_string()
10763}
10764
10765fn default_subscription_pct() -> f64 {
10766 0.60
10767}
10768
10769fn default_license_pct() -> f64 {
10770 0.25
10771}
10772
10773fn default_services_pct() -> f64 {
10774 0.15
10775}
10776
10777impl Default for TechnologyConfig {
10778 fn default() -> Self {
10779 Self {
10780 enabled: false,
10781 revenue_model: default_revenue_model(),
10782 subscription_revenue_pct: default_subscription_pct(),
10783 license_revenue_pct: default_license_pct(),
10784 services_revenue_pct: default_services_pct(),
10785 rd_capitalization: RdCapitalizationConfig::default(),
10786 anomaly_rates: TechnologyAnomalyRates::default(),
10787 }
10788 }
10789}
10790
10791#[derive(Debug, Clone, Serialize, Deserialize)]
10793pub struct RdCapitalizationConfig {
10794 #[serde(default = "default_true")]
10796 pub enabled: bool,
10797
10798 #[serde(default = "default_cap_rate")]
10800 pub capitalization_rate: f64,
10801
10802 #[serde(default = "default_useful_life")]
10804 pub useful_life_years: u32,
10805}
10806
10807fn default_cap_rate() -> f64 {
10808 0.30
10809}
10810
10811fn default_useful_life() -> u32 {
10812 3
10813}
10814
10815impl Default for RdCapitalizationConfig {
10816 fn default() -> Self {
10817 Self {
10818 enabled: true,
10819 capitalization_rate: default_cap_rate(),
10820 useful_life_years: default_useful_life(),
10821 }
10822 }
10823}
10824
10825#[derive(Debug, Clone, Serialize, Deserialize)]
10827pub struct TechnologyAnomalyRates {
10828 #[serde(default = "default_premature_rev_rate")]
10830 pub premature_revenue: f64,
10831
10832 #[serde(default = "default_side_letter_rate")]
10834 pub side_letter_abuse: f64,
10835
10836 #[serde(default = "default_channel_stuffing_rate")]
10838 pub channel_stuffing: f64,
10839
10840 #[serde(default = "default_improper_cap_rate")]
10842 pub improper_capitalization: f64,
10843}
10844
10845fn default_premature_rev_rate() -> f64 {
10846 0.015
10847}
10848
10849fn default_side_letter_rate() -> f64 {
10850 0.008
10851}
10852
10853fn default_channel_stuffing_rate() -> f64 {
10854 0.01
10855}
10856
10857fn default_improper_cap_rate() -> f64 {
10858 0.012
10859}
10860
10861impl Default for TechnologyAnomalyRates {
10862 fn default() -> Self {
10863 Self {
10864 premature_revenue: default_premature_rev_rate(),
10865 side_letter_abuse: default_side_letter_rate(),
10866 channel_stuffing: default_channel_stuffing_rate(),
10867 improper_capitalization: default_improper_cap_rate(),
10868 }
10869 }
10870}
10871
10872#[derive(Debug, Clone, Serialize, Deserialize)]
10874pub struct FinancialServicesConfig {
10875 #[serde(default)]
10877 pub enabled: bool,
10878
10879 #[serde(default = "default_fi_type")]
10881 pub institution_type: String,
10882
10883 #[serde(default = "default_fi_regulatory")]
10885 pub regulatory_framework: String,
10886
10887 #[serde(default)]
10889 pub anomaly_rates: FinancialServicesAnomalyRates,
10890}
10891
10892fn default_fi_type() -> String {
10893 "commercial_bank".to_string()
10894}
10895
10896fn default_fi_regulatory() -> String {
10897 "us_banking".to_string()
10898}
10899
10900impl Default for FinancialServicesConfig {
10901 fn default() -> Self {
10902 Self {
10903 enabled: false,
10904 institution_type: default_fi_type(),
10905 regulatory_framework: default_fi_regulatory(),
10906 anomaly_rates: FinancialServicesAnomalyRates::default(),
10907 }
10908 }
10909}
10910
10911#[derive(Debug, Clone, Serialize, Deserialize)]
10913pub struct FinancialServicesAnomalyRates {
10914 #[serde(default = "default_loan_fraud_rate")]
10916 pub loan_fraud: f64,
10917
10918 #[serde(default = "default_trading_fraud_rate")]
10920 pub trading_fraud: f64,
10921
10922 #[serde(default = "default_insurance_fraud_rate")]
10924 pub insurance_fraud: f64,
10925
10926 #[serde(default = "default_account_manip_rate")]
10928 pub account_manipulation: f64,
10929}
10930
10931fn default_loan_fraud_rate() -> f64 {
10932 0.01
10933}
10934
10935fn default_trading_fraud_rate() -> f64 {
10936 0.008
10937}
10938
10939fn default_insurance_fraud_rate() -> f64 {
10940 0.012
10941}
10942
10943fn default_account_manip_rate() -> f64 {
10944 0.005
10945}
10946
10947impl Default for FinancialServicesAnomalyRates {
10948 fn default() -> Self {
10949 Self {
10950 loan_fraud: default_loan_fraud_rate(),
10951 trading_fraud: default_trading_fraud_rate(),
10952 insurance_fraud: default_insurance_fraud_rate(),
10953 account_manipulation: default_account_manip_rate(),
10954 }
10955 }
10956}
10957
10958#[derive(Debug, Clone, Serialize, Deserialize)]
10960pub struct ProfessionalServicesConfig {
10961 #[serde(default)]
10963 pub enabled: bool,
10964
10965 #[serde(default = "default_firm_type")]
10967 pub firm_type: String,
10968
10969 #[serde(default = "default_billing_model")]
10971 pub billing_model: String,
10972
10973 #[serde(default = "default_hourly_rate")]
10975 pub avg_hourly_rate: f64,
10976
10977 #[serde(default)]
10979 pub trust_accounting: TrustAccountingConfig,
10980
10981 #[serde(default)]
10983 pub anomaly_rates: ProfessionalServicesAnomalyRates,
10984}
10985
10986fn default_firm_type() -> String {
10987 "consulting".to_string()
10988}
10989
10990fn default_billing_model() -> String {
10991 "time_and_materials".to_string()
10992}
10993
10994fn default_hourly_rate() -> f64 {
10995 250.0
10996}
10997
10998impl Default for ProfessionalServicesConfig {
10999 fn default() -> Self {
11000 Self {
11001 enabled: false,
11002 firm_type: default_firm_type(),
11003 billing_model: default_billing_model(),
11004 avg_hourly_rate: default_hourly_rate(),
11005 trust_accounting: TrustAccountingConfig::default(),
11006 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
11007 }
11008 }
11009}
11010
11011#[derive(Debug, Clone, Serialize, Deserialize)]
11013pub struct TrustAccountingConfig {
11014 #[serde(default)]
11016 pub enabled: bool,
11017
11018 #[serde(default = "default_true")]
11020 pub require_three_way_reconciliation: bool,
11021}
11022
11023impl Default for TrustAccountingConfig {
11024 fn default() -> Self {
11025 Self {
11026 enabled: false,
11027 require_three_way_reconciliation: true,
11028 }
11029 }
11030}
11031
11032#[derive(Debug, Clone, Serialize, Deserialize)]
11034pub struct ProfessionalServicesAnomalyRates {
11035 #[serde(default = "default_time_fraud_rate")]
11037 pub time_billing_fraud: f64,
11038
11039 #[serde(default = "default_expense_fraud_rate")]
11041 pub expense_fraud: f64,
11042
11043 #[serde(default = "default_trust_misappropriation_rate")]
11045 pub trust_misappropriation: f64,
11046}
11047
11048fn default_time_fraud_rate() -> f64 {
11049 0.02
11050}
11051
11052fn default_expense_fraud_rate() -> f64 {
11053 0.015
11054}
11055
11056fn default_trust_misappropriation_rate() -> f64 {
11057 0.003
11058}
11059
11060impl Default for ProfessionalServicesAnomalyRates {
11061 fn default() -> Self {
11062 Self {
11063 time_billing_fraud: default_time_fraud_rate(),
11064 expense_fraud: default_expense_fraud_rate(),
11065 trust_misappropriation: default_trust_misappropriation_rate(),
11066 }
11067 }
11068}
11069
11070#[derive(Debug, Clone, Serialize, Deserialize)]
11084pub struct FingerprintPrivacyConfig {
11085 #[serde(default)]
11087 pub level: String,
11088 #[serde(default = "default_epsilon")]
11090 pub epsilon: f64,
11091 #[serde(default = "default_delta")]
11093 pub delta: f64,
11094 #[serde(default = "default_k_anonymity")]
11096 pub k_anonymity: u32,
11097 #[serde(default)]
11099 pub composition_method: String,
11100}
11101
11102fn default_epsilon() -> f64 {
11103 1.0
11104}
11105
11106fn default_delta() -> f64 {
11107 1e-5
11108}
11109
11110fn default_k_anonymity() -> u32 {
11111 5
11112}
11113
11114impl Default for FingerprintPrivacyConfig {
11115 fn default() -> Self {
11116 Self {
11117 level: "standard".to_string(),
11118 epsilon: default_epsilon(),
11119 delta: default_delta(),
11120 k_anonymity: default_k_anonymity(),
11121 composition_method: "naive".to_string(),
11122 }
11123 }
11124}
11125
11126#[derive(Debug, Clone, Serialize, Deserialize)]
11140pub struct QualityGatesSchemaConfig {
11141 #[serde(default)]
11143 pub enabled: bool,
11144 #[serde(default = "default_gate_profile_name")]
11146 pub profile: String,
11147 #[serde(default)]
11149 pub fail_on_violation: bool,
11150 #[serde(default)]
11152 pub custom_gates: Vec<QualityGateEntry>,
11153}
11154
11155fn default_gate_profile_name() -> String {
11156 "default".to_string()
11157}
11158
11159impl Default for QualityGatesSchemaConfig {
11160 fn default() -> Self {
11161 Self {
11162 enabled: false,
11163 profile: default_gate_profile_name(),
11164 fail_on_violation: false,
11165 custom_gates: Vec::new(),
11166 }
11167 }
11168}
11169
11170#[derive(Debug, Clone, Serialize, Deserialize)]
11172pub struct QualityGateEntry {
11173 pub name: String,
11175 pub metric: String,
11179 pub threshold: f64,
11181 #[serde(default)]
11183 pub upper_threshold: Option<f64>,
11184 #[serde(default = "default_gate_comparison")]
11186 pub comparison: String,
11187}
11188
11189fn default_gate_comparison() -> String {
11190 "gte".to_string()
11191}
11192
11193#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11203pub struct ComplianceSchemaConfig {
11204 #[serde(default)]
11206 pub content_marking: ContentMarkingSchemaConfig,
11207 #[serde(default)]
11209 pub article10_report: bool,
11210 #[serde(default)]
11212 pub certificates: CertificateSchemaConfig,
11213}
11214
11215#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11217pub struct CertificateSchemaConfig {
11218 #[serde(default)]
11220 pub enabled: bool,
11221 #[serde(default)]
11223 pub signing_key_env: Option<String>,
11224 #[serde(default)]
11226 pub include_quality_metrics: bool,
11227}
11228
11229#[derive(Debug, Clone, Serialize, Deserialize)]
11231pub struct ContentMarkingSchemaConfig {
11232 #[serde(default = "default_true")]
11234 pub enabled: bool,
11235 #[serde(default = "default_marking_format")]
11237 pub format: String,
11238}
11239
11240fn default_marking_format() -> String {
11241 "embedded".to_string()
11242}
11243
11244impl Default for ContentMarkingSchemaConfig {
11245 fn default() -> Self {
11246 Self {
11247 enabled: true,
11248 format: default_marking_format(),
11249 }
11250 }
11251}
11252
11253#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11255pub struct WebhookSchemaConfig {
11256 #[serde(default)]
11258 pub enabled: bool,
11259 #[serde(default)]
11261 pub endpoints: Vec<WebhookEndpointConfig>,
11262}
11263
11264#[derive(Debug, Clone, Serialize, Deserialize)]
11266pub struct WebhookEndpointConfig {
11267 pub url: String,
11269 #[serde(default)]
11271 pub events: Vec<String>,
11272 #[serde(default)]
11274 pub secret: Option<String>,
11275 #[serde(default = "default_webhook_retries")]
11277 pub max_retries: u32,
11278 #[serde(default = "default_webhook_timeout")]
11280 pub timeout_secs: u64,
11281}
11282
11283fn default_webhook_retries() -> u32 {
11284 3
11285}
11286fn default_webhook_timeout() -> u64 {
11287 10
11288}
11289
11290#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11296pub struct SourceToPayConfig {
11297 #[serde(default)]
11299 pub enabled: bool,
11300 #[serde(default)]
11302 pub spend_analysis: SpendAnalysisConfig,
11303 #[serde(default)]
11305 pub sourcing: SourcingConfig,
11306 #[serde(default)]
11308 pub qualification: QualificationConfig,
11309 #[serde(default)]
11311 pub rfx: RfxConfig,
11312 #[serde(default)]
11314 pub contracts: ContractConfig,
11315 #[serde(default)]
11317 pub catalog: CatalogConfig,
11318 #[serde(default)]
11320 pub scorecards: ScorecardConfig,
11321 #[serde(default)]
11323 pub p2p_integration: P2PIntegrationConfig,
11324}
11325
11326#[derive(Debug, Clone, Serialize, Deserialize)]
11328pub struct SpendAnalysisConfig {
11329 #[serde(default = "default_hhi_threshold")]
11331 pub hhi_threshold: f64,
11332 #[serde(default = "default_contract_coverage_target")]
11334 pub contract_coverage_target: f64,
11335}
11336
11337impl Default for SpendAnalysisConfig {
11338 fn default() -> Self {
11339 Self {
11340 hhi_threshold: default_hhi_threshold(),
11341 contract_coverage_target: default_contract_coverage_target(),
11342 }
11343 }
11344}
11345
11346fn default_hhi_threshold() -> f64 {
11347 2500.0
11348}
11349fn default_contract_coverage_target() -> f64 {
11350 0.80
11351}
11352
11353#[derive(Debug, Clone, Serialize, Deserialize)]
11355pub struct SourcingConfig {
11356 #[serde(default = "default_sourcing_projects_per_year")]
11358 pub projects_per_year: u32,
11359 #[serde(default = "default_renewal_horizon_months")]
11361 pub renewal_horizon_months: u32,
11362 #[serde(default = "default_project_duration_months")]
11364 pub project_duration_months: u32,
11365}
11366
11367impl Default for SourcingConfig {
11368 fn default() -> Self {
11369 Self {
11370 projects_per_year: default_sourcing_projects_per_year(),
11371 renewal_horizon_months: default_renewal_horizon_months(),
11372 project_duration_months: default_project_duration_months(),
11373 }
11374 }
11375}
11376
11377fn default_sourcing_projects_per_year() -> u32 {
11378 10
11379}
11380fn default_renewal_horizon_months() -> u32 {
11381 3
11382}
11383fn default_project_duration_months() -> u32 {
11384 4
11385}
11386
11387#[derive(Debug, Clone, Serialize, Deserialize)]
11389pub struct QualificationConfig {
11390 #[serde(default = "default_qualification_pass_rate")]
11392 pub pass_rate: f64,
11393 #[serde(default = "default_qualification_validity_days")]
11395 pub validity_days: u32,
11396 #[serde(default = "default_financial_weight")]
11398 pub financial_weight: f64,
11399 #[serde(default = "default_quality_weight")]
11401 pub quality_weight: f64,
11402 #[serde(default = "default_delivery_weight")]
11404 pub delivery_weight: f64,
11405 #[serde(default = "default_compliance_weight")]
11407 pub compliance_weight: f64,
11408}
11409
11410impl Default for QualificationConfig {
11411 fn default() -> Self {
11412 Self {
11413 pass_rate: default_qualification_pass_rate(),
11414 validity_days: default_qualification_validity_days(),
11415 financial_weight: default_financial_weight(),
11416 quality_weight: default_quality_weight(),
11417 delivery_weight: default_delivery_weight(),
11418 compliance_weight: default_compliance_weight(),
11419 }
11420 }
11421}
11422
11423fn default_qualification_pass_rate() -> f64 {
11424 0.75
11425}
11426fn default_qualification_validity_days() -> u32 {
11427 365
11428}
11429fn default_financial_weight() -> f64 {
11430 0.25
11431}
11432fn default_quality_weight() -> f64 {
11433 0.30
11434}
11435fn default_delivery_weight() -> f64 {
11436 0.25
11437}
11438fn default_compliance_weight() -> f64 {
11439 0.20
11440}
11441
11442#[derive(Debug, Clone, Serialize, Deserialize)]
11444pub struct RfxConfig {
11445 #[serde(default = "default_rfi_threshold")]
11447 pub rfi_threshold: f64,
11448 #[serde(default = "default_min_invited_vendors")]
11450 pub min_invited_vendors: u32,
11451 #[serde(default = "default_max_invited_vendors")]
11453 pub max_invited_vendors: u32,
11454 #[serde(default = "default_response_rate")]
11456 pub response_rate: f64,
11457 #[serde(default = "default_price_weight")]
11459 pub default_price_weight: f64,
11460 #[serde(default = "default_rfx_quality_weight")]
11462 pub default_quality_weight: f64,
11463 #[serde(default = "default_rfx_delivery_weight")]
11465 pub default_delivery_weight: f64,
11466}
11467
11468impl Default for RfxConfig {
11469 fn default() -> Self {
11470 Self {
11471 rfi_threshold: default_rfi_threshold(),
11472 min_invited_vendors: default_min_invited_vendors(),
11473 max_invited_vendors: default_max_invited_vendors(),
11474 response_rate: default_response_rate(),
11475 default_price_weight: default_price_weight(),
11476 default_quality_weight: default_rfx_quality_weight(),
11477 default_delivery_weight: default_rfx_delivery_weight(),
11478 }
11479 }
11480}
11481
11482fn default_rfi_threshold() -> f64 {
11483 100_000.0
11484}
11485fn default_min_invited_vendors() -> u32 {
11486 3
11487}
11488fn default_max_invited_vendors() -> u32 {
11489 8
11490}
11491fn default_response_rate() -> f64 {
11492 0.70
11493}
11494fn default_price_weight() -> f64 {
11495 0.40
11496}
11497fn default_rfx_quality_weight() -> f64 {
11498 0.35
11499}
11500fn default_rfx_delivery_weight() -> f64 {
11501 0.25
11502}
11503
11504#[derive(Debug, Clone, Serialize, Deserialize)]
11506pub struct ContractConfig {
11507 #[serde(default = "default_min_contract_months")]
11509 pub min_duration_months: u32,
11510 #[serde(default = "default_max_contract_months")]
11512 pub max_duration_months: u32,
11513 #[serde(default = "default_auto_renewal_rate")]
11515 pub auto_renewal_rate: f64,
11516 #[serde(default = "default_amendment_rate")]
11518 pub amendment_rate: f64,
11519 #[serde(default)]
11521 pub type_distribution: ContractTypeDistribution,
11522}
11523
11524impl Default for ContractConfig {
11525 fn default() -> Self {
11526 Self {
11527 min_duration_months: default_min_contract_months(),
11528 max_duration_months: default_max_contract_months(),
11529 auto_renewal_rate: default_auto_renewal_rate(),
11530 amendment_rate: default_amendment_rate(),
11531 type_distribution: ContractTypeDistribution::default(),
11532 }
11533 }
11534}
11535
11536fn default_min_contract_months() -> u32 {
11537 12
11538}
11539fn default_max_contract_months() -> u32 {
11540 36
11541}
11542fn default_auto_renewal_rate() -> f64 {
11543 0.40
11544}
11545fn default_amendment_rate() -> f64 {
11546 0.20
11547}
11548
11549#[derive(Debug, Clone, Serialize, Deserialize)]
11551pub struct ContractTypeDistribution {
11552 #[serde(default = "default_fixed_price_pct")]
11554 pub fixed_price: f64,
11555 #[serde(default = "default_blanket_pct")]
11557 pub blanket: f64,
11558 #[serde(default = "default_time_materials_pct")]
11560 pub time_and_materials: f64,
11561 #[serde(default = "default_service_agreement_pct")]
11563 pub service_agreement: f64,
11564}
11565
11566impl Default for ContractTypeDistribution {
11567 fn default() -> Self {
11568 Self {
11569 fixed_price: default_fixed_price_pct(),
11570 blanket: default_blanket_pct(),
11571 time_and_materials: default_time_materials_pct(),
11572 service_agreement: default_service_agreement_pct(),
11573 }
11574 }
11575}
11576
11577fn default_fixed_price_pct() -> f64 {
11578 0.40
11579}
11580fn default_blanket_pct() -> f64 {
11581 0.30
11582}
11583fn default_time_materials_pct() -> f64 {
11584 0.15
11585}
11586fn default_service_agreement_pct() -> f64 {
11587 0.15
11588}
11589
11590#[derive(Debug, Clone, Serialize, Deserialize)]
11592pub struct CatalogConfig {
11593 #[serde(default = "default_preferred_vendor_flag_rate")]
11595 pub preferred_vendor_flag_rate: f64,
11596 #[serde(default = "default_multi_source_rate")]
11598 pub multi_source_rate: f64,
11599}
11600
11601impl Default for CatalogConfig {
11602 fn default() -> Self {
11603 Self {
11604 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
11605 multi_source_rate: default_multi_source_rate(),
11606 }
11607 }
11608}
11609
11610fn default_preferred_vendor_flag_rate() -> f64 {
11611 0.70
11612}
11613fn default_multi_source_rate() -> f64 {
11614 0.25
11615}
11616
11617#[derive(Debug, Clone, Serialize, Deserialize)]
11619pub struct ScorecardConfig {
11620 #[serde(default = "default_scorecard_frequency")]
11622 pub frequency: String,
11623 #[serde(default = "default_otd_weight")]
11625 pub on_time_delivery_weight: f64,
11626 #[serde(default = "default_quality_score_weight")]
11628 pub quality_weight: f64,
11629 #[serde(default = "default_price_score_weight")]
11631 pub price_weight: f64,
11632 #[serde(default = "default_responsiveness_weight")]
11634 pub responsiveness_weight: f64,
11635 #[serde(default = "default_grade_a_threshold")]
11637 pub grade_a_threshold: f64,
11638 #[serde(default = "default_grade_b_threshold")]
11640 pub grade_b_threshold: f64,
11641 #[serde(default = "default_grade_c_threshold")]
11643 pub grade_c_threshold: f64,
11644}
11645
11646impl Default for ScorecardConfig {
11647 fn default() -> Self {
11648 Self {
11649 frequency: default_scorecard_frequency(),
11650 on_time_delivery_weight: default_otd_weight(),
11651 quality_weight: default_quality_score_weight(),
11652 price_weight: default_price_score_weight(),
11653 responsiveness_weight: default_responsiveness_weight(),
11654 grade_a_threshold: default_grade_a_threshold(),
11655 grade_b_threshold: default_grade_b_threshold(),
11656 grade_c_threshold: default_grade_c_threshold(),
11657 }
11658 }
11659}
11660
11661fn default_scorecard_frequency() -> String {
11662 "quarterly".to_string()
11663}
11664fn default_otd_weight() -> f64 {
11665 0.30
11666}
11667fn default_quality_score_weight() -> f64 {
11668 0.30
11669}
11670fn default_price_score_weight() -> f64 {
11671 0.25
11672}
11673fn default_responsiveness_weight() -> f64 {
11674 0.15
11675}
11676fn default_grade_a_threshold() -> f64 {
11677 90.0
11678}
11679fn default_grade_b_threshold() -> f64 {
11680 75.0
11681}
11682fn default_grade_c_threshold() -> f64 {
11683 60.0
11684}
11685
11686#[derive(Debug, Clone, Serialize, Deserialize)]
11688pub struct P2PIntegrationConfig {
11689 #[serde(default = "default_off_contract_rate")]
11691 pub off_contract_rate: f64,
11692 #[serde(default = "default_price_tolerance")]
11694 pub price_tolerance: f64,
11695 #[serde(default)]
11697 pub catalog_enforcement: bool,
11698}
11699
11700impl Default for P2PIntegrationConfig {
11701 fn default() -> Self {
11702 Self {
11703 off_contract_rate: default_off_contract_rate(),
11704 price_tolerance: default_price_tolerance(),
11705 catalog_enforcement: false,
11706 }
11707 }
11708}
11709
11710fn default_off_contract_rate() -> f64 {
11711 0.15
11712}
11713fn default_price_tolerance() -> f64 {
11714 0.02
11715}
11716
11717#[derive(Debug, Clone, Serialize, Deserialize)]
11721pub struct FinancialReportingConfig {
11722 #[serde(default)]
11724 pub enabled: bool,
11725 #[serde(default = "default_true")]
11727 pub generate_balance_sheet: bool,
11728 #[serde(default = "default_true")]
11730 pub generate_income_statement: bool,
11731 #[serde(default = "default_true")]
11733 pub generate_cash_flow: bool,
11734 #[serde(default = "default_true")]
11736 pub generate_changes_in_equity: bool,
11737 #[serde(default = "default_comparative_periods")]
11739 pub comparative_periods: u32,
11740 #[serde(default)]
11742 pub management_kpis: ManagementKpisConfig,
11743 #[serde(default)]
11745 pub budgets: BudgetConfig,
11746}
11747
11748impl Default for FinancialReportingConfig {
11749 fn default() -> Self {
11750 Self {
11751 enabled: false,
11752 generate_balance_sheet: true,
11753 generate_income_statement: true,
11754 generate_cash_flow: true,
11755 generate_changes_in_equity: true,
11756 comparative_periods: default_comparative_periods(),
11757 management_kpis: ManagementKpisConfig::default(),
11758 budgets: BudgetConfig::default(),
11759 }
11760 }
11761}
11762
11763fn default_comparative_periods() -> u32 {
11764 1
11765}
11766
11767#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11769pub struct ManagementKpisConfig {
11770 #[serde(default)]
11772 pub enabled: bool,
11773 #[serde(default = "default_kpi_frequency")]
11775 pub frequency: String,
11776}
11777
11778fn default_kpi_frequency() -> String {
11779 "monthly".to_string()
11780}
11781
11782#[derive(Debug, Clone, Serialize, Deserialize)]
11784pub struct BudgetConfig {
11785 #[serde(default)]
11787 pub enabled: bool,
11788 #[serde(default = "default_revenue_growth_rate")]
11790 pub revenue_growth_rate: f64,
11791 #[serde(default = "default_expense_inflation_rate")]
11793 pub expense_inflation_rate: f64,
11794 #[serde(default = "default_variance_noise")]
11796 pub variance_noise: f64,
11797}
11798
11799impl Default for BudgetConfig {
11800 fn default() -> Self {
11801 Self {
11802 enabled: false,
11803 revenue_growth_rate: default_revenue_growth_rate(),
11804 expense_inflation_rate: default_expense_inflation_rate(),
11805 variance_noise: default_variance_noise(),
11806 }
11807 }
11808}
11809
11810fn default_revenue_growth_rate() -> f64 {
11811 0.05
11812}
11813fn default_expense_inflation_rate() -> f64 {
11814 0.03
11815}
11816fn default_variance_noise() -> f64 {
11817 0.10
11818}
11819
11820#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11824pub struct HrConfig {
11825 #[serde(default)]
11827 pub enabled: bool,
11828 #[serde(default)]
11830 pub payroll: PayrollConfig,
11831 #[serde(default)]
11833 pub time_attendance: TimeAttendanceConfig,
11834 #[serde(default)]
11836 pub expenses: ExpenseConfig,
11837}
11838
11839#[derive(Debug, Clone, Serialize, Deserialize)]
11841pub struct PayrollConfig {
11842 #[serde(default = "default_true")]
11844 pub enabled: bool,
11845 #[serde(default = "default_pay_frequency")]
11847 pub pay_frequency: String,
11848 #[serde(default)]
11850 pub salary_ranges: PayrollSalaryRanges,
11851 #[serde(default)]
11853 pub tax_rates: PayrollTaxRates,
11854 #[serde(default = "default_benefits_enrollment_rate")]
11856 pub benefits_enrollment_rate: f64,
11857 #[serde(default = "default_retirement_participation_rate")]
11859 pub retirement_participation_rate: f64,
11860}
11861
11862impl Default for PayrollConfig {
11863 fn default() -> Self {
11864 Self {
11865 enabled: true,
11866 pay_frequency: default_pay_frequency(),
11867 salary_ranges: PayrollSalaryRanges::default(),
11868 tax_rates: PayrollTaxRates::default(),
11869 benefits_enrollment_rate: default_benefits_enrollment_rate(),
11870 retirement_participation_rate: default_retirement_participation_rate(),
11871 }
11872 }
11873}
11874
11875fn default_pay_frequency() -> String {
11876 "monthly".to_string()
11877}
11878fn default_benefits_enrollment_rate() -> f64 {
11879 0.60
11880}
11881fn default_retirement_participation_rate() -> f64 {
11882 0.45
11883}
11884
11885#[derive(Debug, Clone, Serialize, Deserialize)]
11887pub struct PayrollSalaryRanges {
11888 #[serde(default = "default_staff_min")]
11890 pub staff_min: f64,
11891 #[serde(default = "default_staff_max")]
11892 pub staff_max: f64,
11893 #[serde(default = "default_manager_min")]
11895 pub manager_min: f64,
11896 #[serde(default = "default_manager_max")]
11897 pub manager_max: f64,
11898 #[serde(default = "default_director_min")]
11900 pub director_min: f64,
11901 #[serde(default = "default_director_max")]
11902 pub director_max: f64,
11903 #[serde(default = "default_executive_min")]
11905 pub executive_min: f64,
11906 #[serde(default = "default_executive_max")]
11907 pub executive_max: f64,
11908}
11909
11910impl Default for PayrollSalaryRanges {
11911 fn default() -> Self {
11912 Self {
11913 staff_min: default_staff_min(),
11914 staff_max: default_staff_max(),
11915 manager_min: default_manager_min(),
11916 manager_max: default_manager_max(),
11917 director_min: default_director_min(),
11918 director_max: default_director_max(),
11919 executive_min: default_executive_min(),
11920 executive_max: default_executive_max(),
11921 }
11922 }
11923}
11924
11925fn default_staff_min() -> f64 {
11926 50_000.0
11927}
11928fn default_staff_max() -> f64 {
11929 70_000.0
11930}
11931fn default_manager_min() -> f64 {
11932 80_000.0
11933}
11934fn default_manager_max() -> f64 {
11935 120_000.0
11936}
11937fn default_director_min() -> f64 {
11938 120_000.0
11939}
11940fn default_director_max() -> f64 {
11941 180_000.0
11942}
11943fn default_executive_min() -> f64 {
11944 180_000.0
11945}
11946fn default_executive_max() -> f64 {
11947 350_000.0
11948}
11949
11950#[derive(Debug, Clone, Serialize, Deserialize)]
11952pub struct PayrollTaxRates {
11953 #[serde(default = "default_federal_rate")]
11955 pub federal_effective: f64,
11956 #[serde(default = "default_state_rate")]
11958 pub state_effective: f64,
11959 #[serde(default = "default_fica_rate")]
11961 pub fica: f64,
11962}
11963
11964impl Default for PayrollTaxRates {
11965 fn default() -> Self {
11966 Self {
11967 federal_effective: default_federal_rate(),
11968 state_effective: default_state_rate(),
11969 fica: default_fica_rate(),
11970 }
11971 }
11972}
11973
11974fn default_federal_rate() -> f64 {
11975 0.22
11976}
11977fn default_state_rate() -> f64 {
11978 0.05
11979}
11980fn default_fica_rate() -> f64 {
11981 0.0765
11982}
11983
11984#[derive(Debug, Clone, Serialize, Deserialize)]
11986pub struct TimeAttendanceConfig {
11987 #[serde(default = "default_true")]
11989 pub enabled: bool,
11990 #[serde(default = "default_overtime_rate")]
11992 pub overtime_rate: f64,
11993}
11994
11995impl Default for TimeAttendanceConfig {
11996 fn default() -> Self {
11997 Self {
11998 enabled: true,
11999 overtime_rate: default_overtime_rate(),
12000 }
12001 }
12002}
12003
12004fn default_overtime_rate() -> f64 {
12005 0.10
12006}
12007
12008#[derive(Debug, Clone, Serialize, Deserialize)]
12010pub struct ExpenseConfig {
12011 #[serde(default = "default_true")]
12013 pub enabled: bool,
12014 #[serde(default = "default_expense_submission_rate")]
12016 pub submission_rate: f64,
12017 #[serde(default = "default_policy_violation_rate")]
12019 pub policy_violation_rate: f64,
12020}
12021
12022impl Default for ExpenseConfig {
12023 fn default() -> Self {
12024 Self {
12025 enabled: true,
12026 submission_rate: default_expense_submission_rate(),
12027 policy_violation_rate: default_policy_violation_rate(),
12028 }
12029 }
12030}
12031
12032fn default_expense_submission_rate() -> f64 {
12033 0.30
12034}
12035fn default_policy_violation_rate() -> f64 {
12036 0.08
12037}
12038
12039#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12043pub struct ManufacturingProcessConfig {
12044 #[serde(default)]
12046 pub enabled: bool,
12047 #[serde(default)]
12049 pub production_orders: ProductionOrderConfig,
12050 #[serde(default)]
12052 pub costing: ManufacturingCostingConfig,
12053 #[serde(default)]
12055 pub routing: RoutingConfig,
12056}
12057
12058#[derive(Debug, Clone, Serialize, Deserialize)]
12060pub struct ProductionOrderConfig {
12061 #[serde(default = "default_prod_orders_per_month")]
12063 pub orders_per_month: u32,
12064 #[serde(default = "default_prod_avg_batch_size")]
12066 pub avg_batch_size: u32,
12067 #[serde(default = "default_prod_yield_rate")]
12069 pub yield_rate: f64,
12070 #[serde(default = "default_prod_make_to_order_rate")]
12072 pub make_to_order_rate: f64,
12073 #[serde(default = "default_prod_rework_rate")]
12075 pub rework_rate: f64,
12076}
12077
12078impl Default for ProductionOrderConfig {
12079 fn default() -> Self {
12080 Self {
12081 orders_per_month: default_prod_orders_per_month(),
12082 avg_batch_size: default_prod_avg_batch_size(),
12083 yield_rate: default_prod_yield_rate(),
12084 make_to_order_rate: default_prod_make_to_order_rate(),
12085 rework_rate: default_prod_rework_rate(),
12086 }
12087 }
12088}
12089
12090fn default_prod_orders_per_month() -> u32 {
12091 50
12092}
12093fn default_prod_avg_batch_size() -> u32 {
12094 100
12095}
12096fn default_prod_yield_rate() -> f64 {
12097 0.97
12098}
12099fn default_prod_make_to_order_rate() -> f64 {
12100 0.20
12101}
12102fn default_prod_rework_rate() -> f64 {
12103 0.03
12104}
12105
12106#[derive(Debug, Clone, Serialize, Deserialize)]
12108pub struct ManufacturingCostingConfig {
12109 #[serde(default = "default_labor_rate")]
12111 pub labor_rate_per_hour: f64,
12112 #[serde(default = "default_overhead_rate")]
12114 pub overhead_rate: f64,
12115 #[serde(default = "default_cost_update_frequency")]
12117 pub standard_cost_update_frequency: String,
12118}
12119
12120impl Default for ManufacturingCostingConfig {
12121 fn default() -> Self {
12122 Self {
12123 labor_rate_per_hour: default_labor_rate(),
12124 overhead_rate: default_overhead_rate(),
12125 standard_cost_update_frequency: default_cost_update_frequency(),
12126 }
12127 }
12128}
12129
12130fn default_labor_rate() -> f64 {
12131 35.0
12132}
12133fn default_overhead_rate() -> f64 {
12134 1.50
12135}
12136fn default_cost_update_frequency() -> String {
12137 "quarterly".to_string()
12138}
12139
12140#[derive(Debug, Clone, Serialize, Deserialize)]
12142pub struct RoutingConfig {
12143 #[serde(default = "default_avg_operations")]
12145 pub avg_operations: u32,
12146 #[serde(default = "default_setup_time")]
12148 pub setup_time_hours: f64,
12149 #[serde(default = "default_run_time_variation")]
12151 pub run_time_variation: f64,
12152}
12153
12154impl Default for RoutingConfig {
12155 fn default() -> Self {
12156 Self {
12157 avg_operations: default_avg_operations(),
12158 setup_time_hours: default_setup_time(),
12159 run_time_variation: default_run_time_variation(),
12160 }
12161 }
12162}
12163
12164fn default_avg_operations() -> u32 {
12165 4
12166}
12167fn default_setup_time() -> f64 {
12168 1.5
12169}
12170fn default_run_time_variation() -> f64 {
12171 0.15
12172}
12173
12174#[derive(Debug, Clone, Serialize, Deserialize)]
12178pub struct SalesQuoteConfig {
12179 #[serde(default)]
12181 pub enabled: bool,
12182 #[serde(default = "default_quotes_per_month")]
12184 pub quotes_per_month: u32,
12185 #[serde(default = "default_quote_win_rate")]
12187 pub win_rate: f64,
12188 #[serde(default = "default_quote_validity_days")]
12190 pub validity_days: u32,
12191}
12192
12193impl Default for SalesQuoteConfig {
12194 fn default() -> Self {
12195 Self {
12196 enabled: false,
12197 quotes_per_month: default_quotes_per_month(),
12198 win_rate: default_quote_win_rate(),
12199 validity_days: default_quote_validity_days(),
12200 }
12201 }
12202}
12203
12204fn default_quotes_per_month() -> u32 {
12205 30
12206}
12207fn default_quote_win_rate() -> f64 {
12208 0.35
12209}
12210fn default_quote_validity_days() -> u32 {
12211 30
12212}
12213
12214#[derive(Debug, Clone, Serialize, Deserialize)]
12223pub struct TaxConfig {
12224 #[serde(default)]
12226 pub enabled: bool,
12227 #[serde(default)]
12229 pub jurisdictions: TaxJurisdictionConfig,
12230 #[serde(default)]
12232 pub vat_gst: VatGstConfig,
12233 #[serde(default)]
12235 pub sales_tax: SalesTaxConfig,
12236 #[serde(default)]
12238 pub withholding: WithholdingTaxSchemaConfig,
12239 #[serde(default)]
12241 pub provisions: TaxProvisionSchemaConfig,
12242 #[serde(default)]
12244 pub payroll_tax: PayrollTaxSchemaConfig,
12245 #[serde(default = "default_tax_anomaly_rate")]
12247 pub anomaly_rate: f64,
12248}
12249
12250fn default_tax_anomaly_rate() -> f64 {
12251 0.03
12252}
12253
12254impl Default for TaxConfig {
12255 fn default() -> Self {
12256 Self {
12257 enabled: false,
12258 jurisdictions: TaxJurisdictionConfig::default(),
12259 vat_gst: VatGstConfig::default(),
12260 sales_tax: SalesTaxConfig::default(),
12261 withholding: WithholdingTaxSchemaConfig::default(),
12262 provisions: TaxProvisionSchemaConfig::default(),
12263 payroll_tax: PayrollTaxSchemaConfig::default(),
12264 anomaly_rate: default_tax_anomaly_rate(),
12265 }
12266 }
12267}
12268
12269#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12274pub struct TaxJurisdictionConfig {
12275 #[serde(default)]
12277 pub countries: Vec<String>,
12278 #[serde(default)]
12280 pub include_subnational: bool,
12281}
12282
12283#[derive(Debug, Clone, Serialize, Deserialize)]
12288pub struct VatGstConfig {
12289 #[serde(default)]
12291 pub enabled: bool,
12292 #[serde(default)]
12294 pub standard_rates: std::collections::HashMap<String, f64>,
12295 #[serde(default)]
12297 pub reduced_rates: std::collections::HashMap<String, f64>,
12298 #[serde(default)]
12300 pub exempt_categories: Vec<String>,
12301 #[serde(default = "default_true")]
12303 pub reverse_charge: bool,
12304}
12305
12306impl Default for VatGstConfig {
12307 fn default() -> Self {
12308 Self {
12309 enabled: false,
12310 standard_rates: std::collections::HashMap::new(),
12311 reduced_rates: std::collections::HashMap::new(),
12312 exempt_categories: Vec::new(),
12313 reverse_charge: true,
12314 }
12315 }
12316}
12317
12318#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12322pub struct SalesTaxConfig {
12323 #[serde(default)]
12325 pub enabled: bool,
12326 #[serde(default)]
12328 pub nexus_states: Vec<String>,
12329}
12330
12331#[derive(Debug, Clone, Serialize, Deserialize)]
12336pub struct WithholdingTaxSchemaConfig {
12337 #[serde(default)]
12339 pub enabled: bool,
12340 #[serde(default = "default_true")]
12342 pub treaty_network: bool,
12343 #[serde(default = "default_withholding_rate")]
12345 pub default_rate: f64,
12346 #[serde(default = "default_treaty_reduced_rate")]
12348 pub treaty_reduced_rate: f64,
12349}
12350
12351fn default_withholding_rate() -> f64 {
12352 0.30
12353}
12354
12355fn default_treaty_reduced_rate() -> f64 {
12356 0.15
12357}
12358
12359impl Default for WithholdingTaxSchemaConfig {
12360 fn default() -> Self {
12361 Self {
12362 enabled: false,
12363 treaty_network: true,
12364 default_rate: default_withholding_rate(),
12365 treaty_reduced_rate: default_treaty_reduced_rate(),
12366 }
12367 }
12368}
12369
12370#[derive(Debug, Clone, Serialize, Deserialize)]
12375pub struct TaxProvisionSchemaConfig {
12376 #[serde(default = "default_true")]
12379 pub enabled: bool,
12380 #[serde(default = "default_statutory_rate")]
12382 pub statutory_rate: f64,
12383 #[serde(default = "default_true")]
12385 pub uncertain_positions: bool,
12386}
12387
12388fn default_statutory_rate() -> f64 {
12389 0.21
12390}
12391
12392impl Default for TaxProvisionSchemaConfig {
12393 fn default() -> Self {
12394 Self {
12395 enabled: true,
12396 statutory_rate: default_statutory_rate(),
12397 uncertain_positions: true,
12398 }
12399 }
12400}
12401
12402#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12407pub struct PayrollTaxSchemaConfig {
12408 #[serde(default)]
12410 pub enabled: bool,
12411}
12412
12413#[derive(Debug, Clone, Serialize, Deserialize)]
12423pub struct TreasuryConfig {
12424 #[serde(default)]
12426 pub enabled: bool,
12427 #[serde(default)]
12429 pub cash_positioning: CashPositioningConfig,
12430 #[serde(default)]
12432 pub cash_forecasting: CashForecastingConfig,
12433 #[serde(default)]
12435 pub cash_pooling: CashPoolingConfig,
12436 #[serde(default)]
12438 pub hedging: HedgingSchemaConfig,
12439 #[serde(default)]
12441 pub debt: DebtSchemaConfig,
12442 #[serde(default)]
12444 pub netting: NettingSchemaConfig,
12445 #[serde(default)]
12447 pub bank_guarantees: BankGuaranteeSchemaConfig,
12448 #[serde(default = "default_treasury_anomaly_rate")]
12450 pub anomaly_rate: f64,
12451}
12452
12453fn default_treasury_anomaly_rate() -> f64 {
12454 0.02
12455}
12456
12457impl Default for TreasuryConfig {
12458 fn default() -> Self {
12459 Self {
12460 enabled: false,
12461 cash_positioning: CashPositioningConfig::default(),
12462 cash_forecasting: CashForecastingConfig::default(),
12463 cash_pooling: CashPoolingConfig::default(),
12464 hedging: HedgingSchemaConfig::default(),
12465 debt: DebtSchemaConfig::default(),
12466 netting: NettingSchemaConfig::default(),
12467 bank_guarantees: BankGuaranteeSchemaConfig::default(),
12468 anomaly_rate: default_treasury_anomaly_rate(),
12469 }
12470 }
12471}
12472
12473#[derive(Debug, Clone, Serialize, Deserialize)]
12477pub struct CashPositioningConfig {
12478 #[serde(default = "default_true")]
12480 pub enabled: bool,
12481 #[serde(default = "default_cash_frequency")]
12483 pub frequency: String,
12484 #[serde(default = "default_minimum_balance_policy")]
12486 pub minimum_balance_policy: f64,
12487}
12488
12489fn default_cash_frequency() -> String {
12490 "daily".to_string()
12491}
12492
12493fn default_minimum_balance_policy() -> f64 {
12494 100_000.0
12495}
12496
12497impl Default for CashPositioningConfig {
12498 fn default() -> Self {
12499 Self {
12500 enabled: true,
12501 frequency: default_cash_frequency(),
12502 minimum_balance_policy: default_minimum_balance_policy(),
12503 }
12504 }
12505}
12506
12507#[derive(Debug, Clone, Serialize, Deserialize)]
12511pub struct CashForecastingConfig {
12512 #[serde(default = "default_true")]
12514 pub enabled: bool,
12515 #[serde(default = "default_horizon_days")]
12517 pub horizon_days: u32,
12518 #[serde(default = "default_ar_probability_curve")]
12520 pub ar_collection_probability_curve: String,
12521 #[serde(default = "default_confidence_interval")]
12523 pub confidence_interval: f64,
12524}
12525
12526fn default_horizon_days() -> u32 {
12527 90
12528}
12529
12530fn default_ar_probability_curve() -> String {
12531 "aging".to_string()
12532}
12533
12534fn default_confidence_interval() -> f64 {
12535 0.90
12536}
12537
12538impl Default for CashForecastingConfig {
12539 fn default() -> Self {
12540 Self {
12541 enabled: true,
12542 horizon_days: default_horizon_days(),
12543 ar_collection_probability_curve: default_ar_probability_curve(),
12544 confidence_interval: default_confidence_interval(),
12545 }
12546 }
12547}
12548
12549#[derive(Debug, Clone, Serialize, Deserialize)]
12553pub struct CashPoolingConfig {
12554 #[serde(default)]
12556 pub enabled: bool,
12557 #[serde(default = "default_pool_type")]
12559 pub pool_type: String,
12560 #[serde(default = "default_sweep_time")]
12562 pub sweep_time: String,
12563}
12564
12565fn default_pool_type() -> String {
12566 "zero_balancing".to_string()
12567}
12568
12569fn default_sweep_time() -> String {
12570 "16:00".to_string()
12571}
12572
12573impl Default for CashPoolingConfig {
12574 fn default() -> Self {
12575 Self {
12576 enabled: false,
12577 pool_type: default_pool_type(),
12578 sweep_time: default_sweep_time(),
12579 }
12580 }
12581}
12582
12583#[derive(Debug, Clone, Serialize, Deserialize)]
12588pub struct HedgingSchemaConfig {
12589 #[serde(default)]
12591 pub enabled: bool,
12592 #[serde(default = "default_hedge_ratio")]
12594 pub hedge_ratio: f64,
12595 #[serde(default = "default_hedge_instruments")]
12597 pub instruments: Vec<String>,
12598 #[serde(default = "default_true")]
12600 pub hedge_accounting: bool,
12601 #[serde(default = "default_effectiveness_method")]
12603 pub effectiveness_method: String,
12604}
12605
12606fn default_hedge_ratio() -> f64 {
12607 0.75
12608}
12609
12610fn default_hedge_instruments() -> Vec<String> {
12611 vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
12612}
12613
12614fn default_effectiveness_method() -> String {
12615 "regression".to_string()
12616}
12617
12618impl Default for HedgingSchemaConfig {
12619 fn default() -> Self {
12620 Self {
12621 enabled: false,
12622 hedge_ratio: default_hedge_ratio(),
12623 instruments: default_hedge_instruments(),
12624 hedge_accounting: true,
12625 effectiveness_method: default_effectiveness_method(),
12626 }
12627 }
12628}
12629
12630#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12635pub struct DebtSchemaConfig {
12636 #[serde(default)]
12638 pub enabled: bool,
12639 #[serde(default)]
12641 pub instruments: Vec<DebtInstrumentDef>,
12642 #[serde(default)]
12644 pub covenants: Vec<CovenantDef>,
12645}
12646
12647#[derive(Debug, Clone, Serialize, Deserialize)]
12649pub struct DebtInstrumentDef {
12650 #[serde(rename = "type")]
12652 pub instrument_type: String,
12653 #[serde(default)]
12655 pub principal: Option<f64>,
12656 #[serde(default)]
12658 pub rate: Option<f64>,
12659 #[serde(default)]
12661 pub maturity_months: Option<u32>,
12662 #[serde(default)]
12664 pub facility: Option<f64>,
12665}
12666
12667#[derive(Debug, Clone, Serialize, Deserialize)]
12669pub struct CovenantDef {
12670 #[serde(rename = "type")]
12673 pub covenant_type: String,
12674 pub threshold: f64,
12676}
12677
12678#[derive(Debug, Clone, Serialize, Deserialize)]
12682pub struct NettingSchemaConfig {
12683 #[serde(default)]
12685 pub enabled: bool,
12686 #[serde(default = "default_netting_cycle")]
12688 pub cycle: String,
12689}
12690
12691fn default_netting_cycle() -> String {
12692 "monthly".to_string()
12693}
12694
12695impl Default for NettingSchemaConfig {
12696 fn default() -> Self {
12697 Self {
12698 enabled: false,
12699 cycle: default_netting_cycle(),
12700 }
12701 }
12702}
12703
12704#[derive(Debug, Clone, Serialize, Deserialize)]
12708pub struct BankGuaranteeSchemaConfig {
12709 #[serde(default)]
12711 pub enabled: bool,
12712 #[serde(default = "default_guarantee_count")]
12714 pub count: u32,
12715}
12716
12717fn default_guarantee_count() -> u32 {
12718 5
12719}
12720
12721impl Default for BankGuaranteeSchemaConfig {
12722 fn default() -> Self {
12723 Self {
12724 enabled: false,
12725 count: default_guarantee_count(),
12726 }
12727 }
12728}
12729
12730#[derive(Debug, Clone, Serialize, Deserialize)]
12739pub struct ProjectAccountingConfig {
12740 #[serde(default)]
12742 pub enabled: bool,
12743 #[serde(default = "default_project_count")]
12745 pub project_count: u32,
12746 #[serde(default)]
12748 pub project_types: ProjectTypeDistribution,
12749 #[serde(default)]
12751 pub wbs: WbsSchemaConfig,
12752 #[serde(default)]
12754 pub cost_allocation: CostAllocationConfig,
12755 #[serde(default)]
12757 pub revenue_recognition: ProjectRevenueRecognitionConfig,
12758 #[serde(default)]
12760 pub milestones: MilestoneSchemaConfig,
12761 #[serde(default)]
12763 pub change_orders: ChangeOrderSchemaConfig,
12764 #[serde(default)]
12766 pub retainage: RetainageSchemaConfig,
12767 #[serde(default)]
12769 pub earned_value: EarnedValueSchemaConfig,
12770 #[serde(default = "default_project_anomaly_rate")]
12772 pub anomaly_rate: f64,
12773}
12774
12775fn default_project_count() -> u32 {
12776 10
12777}
12778
12779fn default_project_anomaly_rate() -> f64 {
12780 0.03
12781}
12782
12783impl Default for ProjectAccountingConfig {
12784 fn default() -> Self {
12785 Self {
12786 enabled: false,
12787 project_count: default_project_count(),
12788 project_types: ProjectTypeDistribution::default(),
12789 wbs: WbsSchemaConfig::default(),
12790 cost_allocation: CostAllocationConfig::default(),
12791 revenue_recognition: ProjectRevenueRecognitionConfig::default(),
12792 milestones: MilestoneSchemaConfig::default(),
12793 change_orders: ChangeOrderSchemaConfig::default(),
12794 retainage: RetainageSchemaConfig::default(),
12795 earned_value: EarnedValueSchemaConfig::default(),
12796 anomaly_rate: default_project_anomaly_rate(),
12797 }
12798 }
12799}
12800
12801#[derive(Debug, Clone, Serialize, Deserialize)]
12803pub struct ProjectTypeDistribution {
12804 #[serde(default = "default_capital_weight")]
12806 pub capital: f64,
12807 #[serde(default = "default_internal_weight")]
12809 pub internal: f64,
12810 #[serde(default = "default_customer_weight")]
12812 pub customer: f64,
12813 #[serde(default = "default_rnd_weight")]
12815 pub r_and_d: f64,
12816 #[serde(default = "default_maintenance_weight")]
12818 pub maintenance: f64,
12819 #[serde(default = "default_technology_weight")]
12821 pub technology: f64,
12822}
12823
12824fn default_capital_weight() -> f64 {
12825 0.25
12826}
12827fn default_internal_weight() -> f64 {
12828 0.20
12829}
12830fn default_customer_weight() -> f64 {
12831 0.30
12832}
12833fn default_rnd_weight() -> f64 {
12834 0.10
12835}
12836fn default_maintenance_weight() -> f64 {
12837 0.10
12838}
12839fn default_technology_weight() -> f64 {
12840 0.05
12841}
12842
12843impl Default for ProjectTypeDistribution {
12844 fn default() -> Self {
12845 Self {
12846 capital: default_capital_weight(),
12847 internal: default_internal_weight(),
12848 customer: default_customer_weight(),
12849 r_and_d: default_rnd_weight(),
12850 maintenance: default_maintenance_weight(),
12851 technology: default_technology_weight(),
12852 }
12853 }
12854}
12855
12856#[derive(Debug, Clone, Serialize, Deserialize)]
12858pub struct WbsSchemaConfig {
12859 #[serde(default = "default_wbs_max_depth")]
12861 pub max_depth: u32,
12862 #[serde(default = "default_wbs_min_elements")]
12864 pub min_elements_per_level: u32,
12865 #[serde(default = "default_wbs_max_elements")]
12867 pub max_elements_per_level: u32,
12868}
12869
12870fn default_wbs_max_depth() -> u32 {
12871 3
12872}
12873fn default_wbs_min_elements() -> u32 {
12874 2
12875}
12876fn default_wbs_max_elements() -> u32 {
12877 6
12878}
12879
12880impl Default for WbsSchemaConfig {
12881 fn default() -> Self {
12882 Self {
12883 max_depth: default_wbs_max_depth(),
12884 min_elements_per_level: default_wbs_min_elements(),
12885 max_elements_per_level: default_wbs_max_elements(),
12886 }
12887 }
12888}
12889
12890#[derive(Debug, Clone, Serialize, Deserialize)]
12892pub struct CostAllocationConfig {
12893 #[serde(default = "default_time_entry_rate")]
12895 pub time_entry_project_rate: f64,
12896 #[serde(default = "default_expense_rate")]
12898 pub expense_project_rate: f64,
12899 #[serde(default = "default_po_rate")]
12901 pub purchase_order_project_rate: f64,
12902 #[serde(default = "default_vi_rate")]
12904 pub vendor_invoice_project_rate: f64,
12905}
12906
12907fn default_time_entry_rate() -> f64 {
12908 0.60
12909}
12910fn default_expense_rate() -> f64 {
12911 0.30
12912}
12913fn default_po_rate() -> f64 {
12914 0.40
12915}
12916fn default_vi_rate() -> f64 {
12917 0.35
12918}
12919
12920impl Default for CostAllocationConfig {
12921 fn default() -> Self {
12922 Self {
12923 time_entry_project_rate: default_time_entry_rate(),
12924 expense_project_rate: default_expense_rate(),
12925 purchase_order_project_rate: default_po_rate(),
12926 vendor_invoice_project_rate: default_vi_rate(),
12927 }
12928 }
12929}
12930
12931#[derive(Debug, Clone, Serialize, Deserialize)]
12933pub struct ProjectRevenueRecognitionConfig {
12934 #[serde(default = "default_true")]
12936 pub enabled: bool,
12937 #[serde(default = "default_revenue_method")]
12939 pub method: String,
12940 #[serde(default = "default_completion_measure")]
12942 pub completion_measure: String,
12943 #[serde(default = "default_avg_contract_value")]
12945 pub avg_contract_value: f64,
12946}
12947
12948fn default_revenue_method() -> String {
12949 "percentage_of_completion".to_string()
12950}
12951fn default_completion_measure() -> String {
12952 "cost_to_cost".to_string()
12953}
12954fn default_avg_contract_value() -> f64 {
12955 500_000.0
12956}
12957
12958impl Default for ProjectRevenueRecognitionConfig {
12959 fn default() -> Self {
12960 Self {
12961 enabled: true,
12962 method: default_revenue_method(),
12963 completion_measure: default_completion_measure(),
12964 avg_contract_value: default_avg_contract_value(),
12965 }
12966 }
12967}
12968
12969#[derive(Debug, Clone, Serialize, Deserialize)]
12971pub struct MilestoneSchemaConfig {
12972 #[serde(default = "default_true")]
12974 pub enabled: bool,
12975 #[serde(default = "default_milestones_per_project")]
12977 pub avg_per_project: u32,
12978 #[serde(default = "default_payment_milestone_rate")]
12980 pub payment_milestone_rate: f64,
12981}
12982
12983fn default_milestones_per_project() -> u32 {
12984 4
12985}
12986fn default_payment_milestone_rate() -> f64 {
12987 0.50
12988}
12989
12990impl Default for MilestoneSchemaConfig {
12991 fn default() -> Self {
12992 Self {
12993 enabled: true,
12994 avg_per_project: default_milestones_per_project(),
12995 payment_milestone_rate: default_payment_milestone_rate(),
12996 }
12997 }
12998}
12999
13000#[derive(Debug, Clone, Serialize, Deserialize)]
13002pub struct ChangeOrderSchemaConfig {
13003 #[serde(default = "default_true")]
13005 pub enabled: bool,
13006 #[serde(default = "default_change_order_probability")]
13008 pub probability: f64,
13009 #[serde(default = "default_max_change_orders")]
13011 pub max_per_project: u32,
13012 #[serde(default = "default_change_order_approval_rate")]
13014 pub approval_rate: f64,
13015}
13016
13017fn default_change_order_probability() -> f64 {
13018 0.40
13019}
13020fn default_max_change_orders() -> u32 {
13021 3
13022}
13023fn default_change_order_approval_rate() -> f64 {
13024 0.75
13025}
13026
13027impl Default for ChangeOrderSchemaConfig {
13028 fn default() -> Self {
13029 Self {
13030 enabled: true,
13031 probability: default_change_order_probability(),
13032 max_per_project: default_max_change_orders(),
13033 approval_rate: default_change_order_approval_rate(),
13034 }
13035 }
13036}
13037
13038#[derive(Debug, Clone, Serialize, Deserialize)]
13040pub struct RetainageSchemaConfig {
13041 #[serde(default)]
13043 pub enabled: bool,
13044 #[serde(default = "default_retainage_pct")]
13046 pub default_percentage: f64,
13047}
13048
13049fn default_retainage_pct() -> f64 {
13050 0.10
13051}
13052
13053impl Default for RetainageSchemaConfig {
13054 fn default() -> Self {
13055 Self {
13056 enabled: false,
13057 default_percentage: default_retainage_pct(),
13058 }
13059 }
13060}
13061
13062#[derive(Debug, Clone, Serialize, Deserialize)]
13064pub struct EarnedValueSchemaConfig {
13065 #[serde(default = "default_true")]
13067 pub enabled: bool,
13068 #[serde(default = "default_evm_frequency")]
13070 pub frequency: String,
13071}
13072
13073fn default_evm_frequency() -> String {
13074 "monthly".to_string()
13075}
13076
13077impl Default for EarnedValueSchemaConfig {
13078 fn default() -> Self {
13079 Self {
13080 enabled: true,
13081 frequency: default_evm_frequency(),
13082 }
13083 }
13084}
13085
13086#[derive(Debug, Clone, Serialize, Deserialize)]
13092pub struct EsgConfig {
13093 #[serde(default)]
13095 pub enabled: bool,
13096 #[serde(default)]
13098 pub environmental: EnvironmentalConfig,
13099 #[serde(default)]
13101 pub social: SocialConfig,
13102 #[serde(default)]
13104 pub governance: GovernanceSchemaConfig,
13105 #[serde(default)]
13107 pub supply_chain_esg: SupplyChainEsgConfig,
13108 #[serde(default)]
13110 pub reporting: EsgReportingConfig,
13111 #[serde(default)]
13113 pub climate_scenarios: ClimateScenarioConfig,
13114 #[serde(default = "default_esg_anomaly_rate")]
13116 pub anomaly_rate: f64,
13117}
13118
13119fn default_esg_anomaly_rate() -> f64 {
13120 0.02
13121}
13122
13123impl Default for EsgConfig {
13124 fn default() -> Self {
13125 Self {
13126 enabled: false,
13127 environmental: EnvironmentalConfig::default(),
13128 social: SocialConfig::default(),
13129 governance: GovernanceSchemaConfig::default(),
13130 supply_chain_esg: SupplyChainEsgConfig::default(),
13131 reporting: EsgReportingConfig::default(),
13132 climate_scenarios: ClimateScenarioConfig::default(),
13133 anomaly_rate: default_esg_anomaly_rate(),
13134 }
13135 }
13136}
13137
13138#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13143pub struct CountryPacksSchemaConfig {
13144 #[serde(default)]
13146 pub external_dir: Option<PathBuf>,
13147 #[serde(default)]
13151 pub overrides: std::collections::HashMap<String, serde_json::Value>,
13152}
13153
13154#[derive(Debug, Clone, Serialize, Deserialize)]
13156pub struct EnvironmentalConfig {
13157 #[serde(default = "default_true")]
13159 pub enabled: bool,
13160 #[serde(default)]
13162 pub scope1: EmissionScopeConfig,
13163 #[serde(default)]
13165 pub scope2: EmissionScopeConfig,
13166 #[serde(default)]
13168 pub scope3: Scope3Config,
13169 #[serde(default)]
13171 pub energy: EnergySchemaConfig,
13172 #[serde(default)]
13174 pub water: WaterSchemaConfig,
13175 #[serde(default)]
13177 pub waste: WasteSchemaConfig,
13178}
13179
13180impl Default for EnvironmentalConfig {
13181 fn default() -> Self {
13182 Self {
13183 enabled: true,
13184 scope1: EmissionScopeConfig::default(),
13185 scope2: EmissionScopeConfig::default(),
13186 scope3: Scope3Config::default(),
13187 energy: EnergySchemaConfig::default(),
13188 water: WaterSchemaConfig::default(),
13189 waste: WasteSchemaConfig::default(),
13190 }
13191 }
13192}
13193
13194#[derive(Debug, Clone, Serialize, Deserialize)]
13196pub struct EmissionScopeConfig {
13197 #[serde(default = "default_true")]
13199 pub enabled: bool,
13200 #[serde(default = "default_emission_region")]
13202 pub factor_region: String,
13203}
13204
13205fn default_emission_region() -> String {
13206 "US".to_string()
13207}
13208
13209impl Default for EmissionScopeConfig {
13210 fn default() -> Self {
13211 Self {
13212 enabled: true,
13213 factor_region: default_emission_region(),
13214 }
13215 }
13216}
13217
13218#[derive(Debug, Clone, Serialize, Deserialize)]
13220pub struct Scope3Config {
13221 #[serde(default = "default_true")]
13223 pub enabled: bool,
13224 #[serde(default = "default_scope3_categories")]
13226 pub categories: Vec<String>,
13227 #[serde(default = "default_spend_intensity")]
13229 pub default_spend_intensity_kg_per_usd: f64,
13230}
13231
13232fn default_scope3_categories() -> Vec<String> {
13233 vec![
13234 "purchased_goods".to_string(),
13235 "business_travel".to_string(),
13236 "employee_commuting".to_string(),
13237 ]
13238}
13239
13240fn default_spend_intensity() -> f64 {
13241 0.5
13242}
13243
13244impl Default for Scope3Config {
13245 fn default() -> Self {
13246 Self {
13247 enabled: true,
13248 categories: default_scope3_categories(),
13249 default_spend_intensity_kg_per_usd: default_spend_intensity(),
13250 }
13251 }
13252}
13253
13254#[derive(Debug, Clone, Serialize, Deserialize)]
13256pub struct EnergySchemaConfig {
13257 #[serde(default = "default_true")]
13259 pub enabled: bool,
13260 #[serde(default = "default_facility_count")]
13262 pub facility_count: u32,
13263 #[serde(default = "default_renewable_target")]
13265 pub renewable_target: f64,
13266}
13267
13268fn default_facility_count() -> u32 {
13269 5
13270}
13271
13272fn default_renewable_target() -> f64 {
13273 0.30
13274}
13275
13276impl Default for EnergySchemaConfig {
13277 fn default() -> Self {
13278 Self {
13279 enabled: true,
13280 facility_count: default_facility_count(),
13281 renewable_target: default_renewable_target(),
13282 }
13283 }
13284}
13285
13286#[derive(Debug, Clone, Serialize, Deserialize)]
13288pub struct WaterSchemaConfig {
13289 #[serde(default = "default_true")]
13291 pub enabled: bool,
13292 #[serde(default = "default_water_facility_count")]
13294 pub facility_count: u32,
13295}
13296
13297fn default_water_facility_count() -> u32 {
13298 3
13299}
13300
13301impl Default for WaterSchemaConfig {
13302 fn default() -> Self {
13303 Self {
13304 enabled: true,
13305 facility_count: default_water_facility_count(),
13306 }
13307 }
13308}
13309
13310#[derive(Debug, Clone, Serialize, Deserialize)]
13312pub struct WasteSchemaConfig {
13313 #[serde(default = "default_true")]
13315 pub enabled: bool,
13316 #[serde(default = "default_diversion_target")]
13318 pub diversion_target: f64,
13319}
13320
13321fn default_diversion_target() -> f64 {
13322 0.50
13323}
13324
13325impl Default for WasteSchemaConfig {
13326 fn default() -> Self {
13327 Self {
13328 enabled: true,
13329 diversion_target: default_diversion_target(),
13330 }
13331 }
13332}
13333
13334#[derive(Debug, Clone, Serialize, Deserialize)]
13336pub struct SocialConfig {
13337 #[serde(default = "default_true")]
13339 pub enabled: bool,
13340 #[serde(default)]
13342 pub diversity: DiversitySchemaConfig,
13343 #[serde(default)]
13345 pub pay_equity: PayEquitySchemaConfig,
13346 #[serde(default)]
13348 pub safety: SafetySchemaConfig,
13349}
13350
13351impl Default for SocialConfig {
13352 fn default() -> Self {
13353 Self {
13354 enabled: true,
13355 diversity: DiversitySchemaConfig::default(),
13356 pay_equity: PayEquitySchemaConfig::default(),
13357 safety: SafetySchemaConfig::default(),
13358 }
13359 }
13360}
13361
13362#[derive(Debug, Clone, Serialize, Deserialize)]
13364pub struct DiversitySchemaConfig {
13365 #[serde(default = "default_true")]
13367 pub enabled: bool,
13368 #[serde(default = "default_diversity_dimensions")]
13370 pub dimensions: Vec<String>,
13371}
13372
13373fn default_diversity_dimensions() -> Vec<String> {
13374 vec![
13375 "gender".to_string(),
13376 "ethnicity".to_string(),
13377 "age_group".to_string(),
13378 ]
13379}
13380
13381impl Default for DiversitySchemaConfig {
13382 fn default() -> Self {
13383 Self {
13384 enabled: true,
13385 dimensions: default_diversity_dimensions(),
13386 }
13387 }
13388}
13389
13390#[derive(Debug, Clone, Serialize, Deserialize)]
13392pub struct PayEquitySchemaConfig {
13393 #[serde(default = "default_true")]
13395 pub enabled: bool,
13396 #[serde(default = "default_pay_gap_threshold")]
13398 pub gap_threshold: f64,
13399}
13400
13401fn default_pay_gap_threshold() -> f64 {
13402 0.05
13403}
13404
13405impl Default for PayEquitySchemaConfig {
13406 fn default() -> Self {
13407 Self {
13408 enabled: true,
13409 gap_threshold: default_pay_gap_threshold(),
13410 }
13411 }
13412}
13413
13414#[derive(Debug, Clone, Serialize, Deserialize)]
13416pub struct SafetySchemaConfig {
13417 #[serde(default = "default_true")]
13419 pub enabled: bool,
13420 #[serde(default = "default_trir_target")]
13422 pub target_trir: f64,
13423 #[serde(default = "default_incident_count")]
13425 pub incident_count: u32,
13426}
13427
13428fn default_trir_target() -> f64 {
13429 2.5
13430}
13431
13432fn default_incident_count() -> u32 {
13433 20
13434}
13435
13436impl Default for SafetySchemaConfig {
13437 fn default() -> Self {
13438 Self {
13439 enabled: true,
13440 target_trir: default_trir_target(),
13441 incident_count: default_incident_count(),
13442 }
13443 }
13444}
13445
13446#[derive(Debug, Clone, Serialize, Deserialize)]
13448pub struct GovernanceSchemaConfig {
13449 #[serde(default = "default_true")]
13451 pub enabled: bool,
13452 #[serde(default = "default_board_size")]
13454 pub board_size: u32,
13455 #[serde(default = "default_independence_target")]
13457 pub independence_target: f64,
13458}
13459
13460fn default_board_size() -> u32 {
13461 11
13462}
13463
13464fn default_independence_target() -> f64 {
13465 0.67
13466}
13467
13468impl Default for GovernanceSchemaConfig {
13469 fn default() -> Self {
13470 Self {
13471 enabled: true,
13472 board_size: default_board_size(),
13473 independence_target: default_independence_target(),
13474 }
13475 }
13476}
13477
13478#[derive(Debug, Clone, Serialize, Deserialize)]
13480pub struct SupplyChainEsgConfig {
13481 #[serde(default = "default_true")]
13483 pub enabled: bool,
13484 #[serde(default = "default_assessment_coverage")]
13486 pub assessment_coverage: f64,
13487 #[serde(default = "default_high_risk_countries")]
13489 pub high_risk_countries: Vec<String>,
13490}
13491
13492fn default_assessment_coverage() -> f64 {
13493 0.80
13494}
13495
13496fn default_high_risk_countries() -> Vec<String> {
13497 vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
13498}
13499
13500impl Default for SupplyChainEsgConfig {
13501 fn default() -> Self {
13502 Self {
13503 enabled: true,
13504 assessment_coverage: default_assessment_coverage(),
13505 high_risk_countries: default_high_risk_countries(),
13506 }
13507 }
13508}
13509
13510#[derive(Debug, Clone, Serialize, Deserialize)]
13512pub struct EsgReportingConfig {
13513 #[serde(default = "default_true")]
13515 pub enabled: bool,
13516 #[serde(default = "default_esg_frameworks")]
13518 pub frameworks: Vec<String>,
13519 #[serde(default = "default_true")]
13521 pub materiality_assessment: bool,
13522 #[serde(default = "default_materiality_threshold")]
13524 pub impact_threshold: f64,
13525 #[serde(default = "default_materiality_threshold")]
13527 pub financial_threshold: f64,
13528}
13529
13530fn default_esg_frameworks() -> Vec<String> {
13531 vec!["GRI".to_string(), "ESRS".to_string()]
13532}
13533
13534fn default_materiality_threshold() -> f64 {
13535 0.6
13536}
13537
13538impl Default for EsgReportingConfig {
13539 fn default() -> Self {
13540 Self {
13541 enabled: true,
13542 frameworks: default_esg_frameworks(),
13543 materiality_assessment: true,
13544 impact_threshold: default_materiality_threshold(),
13545 financial_threshold: default_materiality_threshold(),
13546 }
13547 }
13548}
13549
13550#[derive(Debug, Clone, Serialize, Deserialize)]
13552pub struct ClimateScenarioConfig {
13553 #[serde(default)]
13555 pub enabled: bool,
13556 #[serde(default = "default_climate_scenarios")]
13558 pub scenarios: Vec<String>,
13559 #[serde(default = "default_time_horizons")]
13561 pub time_horizons: Vec<u32>,
13562}
13563
13564fn default_climate_scenarios() -> Vec<String> {
13565 vec![
13566 "net_zero_2050".to_string(),
13567 "stated_policies".to_string(),
13568 "current_trajectory".to_string(),
13569 ]
13570}
13571
13572fn default_time_horizons() -> Vec<u32> {
13573 vec![5, 10, 30]
13574}
13575
13576impl Default for ClimateScenarioConfig {
13577 fn default() -> Self {
13578 Self {
13579 enabled: false,
13580 scenarios: default_climate_scenarios(),
13581 time_horizons: default_time_horizons(),
13582 }
13583 }
13584}
13585
13586#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13590pub struct ScenariosConfig {
13591 #[serde(default)]
13593 pub enabled: bool,
13594 #[serde(default)]
13596 pub scenarios: Vec<ScenarioSchemaConfig>,
13597 #[serde(default)]
13599 pub causal_model: CausalModelSchemaConfig,
13600 #[serde(default)]
13602 pub defaults: ScenarioDefaultsConfig,
13603 #[serde(default)]
13606 pub generate_counterfactuals: bool,
13607}
13608
13609#[derive(Debug, Clone, Serialize, Deserialize)]
13611pub struct ScenarioSchemaConfig {
13612 pub name: String,
13614 #[serde(default)]
13616 pub description: String,
13617 #[serde(default)]
13619 pub tags: Vec<String>,
13620 pub base: Option<String>,
13622 pub probability_weight: Option<f64>,
13624 #[serde(default)]
13626 pub interventions: Vec<InterventionSchemaConfig>,
13627 #[serde(default)]
13629 pub constraints: ScenarioConstraintsSchemaConfig,
13630 #[serde(default)]
13632 pub output: ScenarioOutputSchemaConfig,
13633 #[serde(default)]
13635 pub metadata: std::collections::HashMap<String, String>,
13636}
13637
13638#[derive(Debug, Clone, Serialize, Deserialize)]
13640pub struct InterventionSchemaConfig {
13641 #[serde(flatten)]
13643 pub intervention_type: serde_json::Value,
13644 #[serde(default)]
13646 pub timing: InterventionTimingSchemaConfig,
13647 pub label: Option<String>,
13649 #[serde(default)]
13651 pub priority: u32,
13652}
13653
13654#[derive(Debug, Clone, Serialize, Deserialize)]
13656pub struct InterventionTimingSchemaConfig {
13657 #[serde(default = "default_start_month")]
13659 pub start_month: u32,
13660 pub duration_months: Option<u32>,
13662 #[serde(default = "default_onset")]
13664 pub onset: String,
13665 pub ramp_months: Option<u32>,
13667}
13668
13669fn default_start_month() -> u32 {
13670 1
13671}
13672
13673fn default_onset() -> String {
13674 "sudden".to_string()
13675}
13676
13677impl Default for InterventionTimingSchemaConfig {
13678 fn default() -> Self {
13679 Self {
13680 start_month: 1,
13681 duration_months: None,
13682 onset: "sudden".to_string(),
13683 ramp_months: None,
13684 }
13685 }
13686}
13687
13688#[derive(Debug, Clone, Serialize, Deserialize)]
13690pub struct ScenarioConstraintsSchemaConfig {
13691 #[serde(default = "default_true")]
13692 pub preserve_accounting_identity: bool,
13693 #[serde(default = "default_true")]
13694 pub preserve_document_chains: bool,
13695 #[serde(default = "default_true")]
13696 pub preserve_period_close: bool,
13697 #[serde(default = "default_true")]
13698 pub preserve_balance_coherence: bool,
13699 #[serde(default)]
13700 pub custom: Vec<CustomConstraintSchemaConfig>,
13701}
13702
13703impl Default for ScenarioConstraintsSchemaConfig {
13704 fn default() -> Self {
13705 Self {
13706 preserve_accounting_identity: true,
13707 preserve_document_chains: true,
13708 preserve_period_close: true,
13709 preserve_balance_coherence: true,
13710 custom: Vec::new(),
13711 }
13712 }
13713}
13714
13715#[derive(Debug, Clone, Serialize, Deserialize)]
13717pub struct CustomConstraintSchemaConfig {
13718 pub config_path: String,
13719 pub min: Option<f64>,
13720 pub max: Option<f64>,
13721 #[serde(default)]
13722 pub description: String,
13723}
13724
13725#[derive(Debug, Clone, Serialize, Deserialize)]
13727pub struct ScenarioOutputSchemaConfig {
13728 #[serde(default = "default_true")]
13729 pub paired: bool,
13730 #[serde(default = "default_diff_formats_schema")]
13731 pub diff_formats: Vec<String>,
13732 #[serde(default)]
13733 pub diff_scope: Vec<String>,
13734}
13735
13736fn default_diff_formats_schema() -> Vec<String> {
13737 vec!["summary".to_string(), "aggregate".to_string()]
13738}
13739
13740impl Default for ScenarioOutputSchemaConfig {
13741 fn default() -> Self {
13742 Self {
13743 paired: true,
13744 diff_formats: default_diff_formats_schema(),
13745 diff_scope: Vec::new(),
13746 }
13747 }
13748}
13749
13750#[derive(Debug, Clone, Serialize, Deserialize)]
13752pub struct CausalModelSchemaConfig {
13753 #[serde(default = "default_causal_preset")]
13755 pub preset: String,
13756 #[serde(default)]
13758 pub nodes: Vec<serde_json::Value>,
13759 #[serde(default)]
13761 pub edges: Vec<serde_json::Value>,
13762}
13763
13764fn default_causal_preset() -> String {
13765 "default".to_string()
13766}
13767
13768impl Default for CausalModelSchemaConfig {
13769 fn default() -> Self {
13770 Self {
13771 preset: "default".to_string(),
13772 nodes: Vec::new(),
13773 edges: Vec::new(),
13774 }
13775 }
13776}
13777
13778#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13780pub struct ScenarioDefaultsConfig {
13781 #[serde(default)]
13782 pub constraints: ScenarioConstraintsSchemaConfig,
13783 #[serde(default)]
13784 pub output: ScenarioOutputSchemaConfig,
13785}
13786
13787#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13820pub struct ComplianceRegulationsConfig {
13821 #[serde(default)]
13823 pub enabled: bool,
13824 #[serde(default)]
13827 pub jurisdictions: Vec<String>,
13828 #[serde(default)]
13831 pub reference_date: Option<String>,
13832 #[serde(default)]
13834 pub standards_selection: StandardsSelectionConfig,
13835 #[serde(default)]
13837 pub audit_procedures: AuditProcedureGenConfig,
13838 #[serde(default)]
13840 pub findings: ComplianceFindingGenConfig,
13841 #[serde(default)]
13843 pub filings: ComplianceFilingGenConfig,
13844 #[serde(default)]
13846 pub graph: ComplianceGraphConfig,
13847 #[serde(default)]
13849 pub output: ComplianceOutputConfig,
13850 #[serde(default)]
13855 pub legal_documents: LegalDocumentsConfig,
13856}
13857
13858#[derive(Debug, Clone, Serialize, Deserialize)]
13863pub struct LegalDocumentsConfig {
13864 #[serde(default)]
13866 pub enabled: bool,
13867 #[serde(default = "default_legal_opinion_probability")]
13869 pub legal_opinion_probability: f64,
13870}
13871
13872fn default_legal_opinion_probability() -> f64 {
13873 0.40
13874}
13875
13876impl Default for LegalDocumentsConfig {
13877 fn default() -> Self {
13878 Self {
13879 enabled: false,
13880 legal_opinion_probability: default_legal_opinion_probability(),
13881 }
13882 }
13883}
13884
13885#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13887pub struct StandardsSelectionConfig {
13888 #[serde(default)]
13891 pub categories: Vec<String>,
13892 #[serde(default)]
13895 pub include: Vec<String>,
13896 #[serde(default)]
13898 pub exclude: Vec<String>,
13899 #[serde(default)]
13901 pub include_superseded: bool,
13902}
13903
13904#[derive(Debug, Clone, Serialize, Deserialize)]
13906pub struct AuditProcedureGenConfig {
13907 #[serde(default)]
13909 pub enabled: bool,
13910 #[serde(default = "default_procedures_per_standard")]
13912 pub procedures_per_standard: usize,
13913 #[serde(default = "default_sampling_method")]
13915 pub sampling_method: String,
13916 #[serde(default = "default_confidence_level")]
13918 pub confidence_level: f64,
13919 #[serde(default = "default_tolerable_misstatement")]
13921 pub tolerable_misstatement: f64,
13922}
13923
13924fn default_procedures_per_standard() -> usize {
13925 3
13926}
13927
13928fn default_sampling_method() -> String {
13929 "statistical".to_string()
13930}
13931
13932fn default_confidence_level() -> f64 {
13933 0.95
13934}
13935
13936fn default_tolerable_misstatement() -> f64 {
13937 0.05
13938}
13939
13940impl Default for AuditProcedureGenConfig {
13941 fn default() -> Self {
13942 Self {
13943 enabled: false,
13944 procedures_per_standard: default_procedures_per_standard(),
13945 sampling_method: default_sampling_method(),
13946 confidence_level: default_confidence_level(),
13947 tolerable_misstatement: default_tolerable_misstatement(),
13948 }
13949 }
13950}
13951
13952#[derive(Debug, Clone, Serialize, Deserialize)]
13954pub struct ComplianceFindingGenConfig {
13955 #[serde(default)]
13957 pub enabled: bool,
13958 #[serde(default = "default_finding_rate")]
13960 pub finding_rate: f64,
13961 #[serde(default = "default_cr_material_weakness_rate")]
13963 pub material_weakness_rate: f64,
13964 #[serde(default = "default_cr_significant_deficiency_rate")]
13966 pub significant_deficiency_rate: f64,
13967 #[serde(default = "default_true")]
13969 pub generate_remediation: bool,
13970}
13971
13972fn default_finding_rate() -> f64 {
13973 0.05
13974}
13975
13976fn default_cr_material_weakness_rate() -> f64 {
13977 0.02
13978}
13979
13980fn default_cr_significant_deficiency_rate() -> f64 {
13981 0.08
13982}
13983
13984impl Default for ComplianceFindingGenConfig {
13985 fn default() -> Self {
13986 Self {
13987 enabled: false,
13988 finding_rate: default_finding_rate(),
13989 material_weakness_rate: default_cr_material_weakness_rate(),
13990 significant_deficiency_rate: default_cr_significant_deficiency_rate(),
13991 generate_remediation: true,
13992 }
13993 }
13994}
13995
13996#[derive(Debug, Clone, Serialize, Deserialize)]
13998pub struct ComplianceFilingGenConfig {
13999 #[serde(default)]
14001 pub enabled: bool,
14002 #[serde(default)]
14005 pub filing_types: Vec<String>,
14006 #[serde(default = "default_true")]
14008 pub generate_status_progression: bool,
14009}
14010
14011impl Default for ComplianceFilingGenConfig {
14012 fn default() -> Self {
14013 Self {
14014 enabled: false,
14015 filing_types: Vec::new(),
14016 generate_status_progression: true,
14017 }
14018 }
14019}
14020
14021#[derive(Debug, Clone, Serialize, Deserialize)]
14023pub struct ComplianceGraphConfig {
14024 #[serde(default)]
14026 pub enabled: bool,
14027 #[serde(default = "default_true")]
14029 pub include_compliance_nodes: bool,
14030 #[serde(default = "default_true")]
14032 pub include_compliance_edges: bool,
14033 #[serde(default = "default_true")]
14035 pub include_cross_references: bool,
14036 #[serde(default)]
14038 pub include_supersession_edges: bool,
14039 #[serde(default = "default_true")]
14041 pub include_account_links: bool,
14042 #[serde(default = "default_true")]
14044 pub include_control_links: bool,
14045 #[serde(default = "default_true")]
14047 pub include_company_links: bool,
14048}
14049
14050impl Default for ComplianceGraphConfig {
14051 fn default() -> Self {
14052 Self {
14053 enabled: false,
14054 include_compliance_nodes: true,
14055 include_compliance_edges: true,
14056 include_cross_references: true,
14057 include_supersession_edges: false,
14058 include_account_links: true,
14059 include_control_links: true,
14060 include_company_links: true,
14061 }
14062 }
14063}
14064
14065#[derive(Debug, Clone, Serialize, Deserialize)]
14067pub struct ComplianceOutputConfig {
14068 #[serde(default = "default_true")]
14070 pub export_registry: bool,
14071 #[serde(default = "default_true")]
14073 pub export_jurisdictions: bool,
14074 #[serde(default = "default_true")]
14076 pub export_cross_references: bool,
14077 #[serde(default)]
14079 pub export_version_history: bool,
14080}
14081
14082impl Default for ComplianceOutputConfig {
14083 fn default() -> Self {
14084 Self {
14085 export_registry: true,
14086 export_jurisdictions: true,
14087 export_cross_references: true,
14088 export_version_history: false,
14089 }
14090 }
14091}
14092
14093#[cfg(test)]
14094#[allow(clippy::unwrap_used)]
14095mod tests {
14096 use super::*;
14097 use crate::presets::demo_preset;
14098
14099 #[test]
14104 fn test_config_yaml_roundtrip() {
14105 let config = demo_preset();
14106 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
14107 let deserialized: GeneratorConfig =
14108 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
14109
14110 assert_eq!(
14111 config.global.period_months,
14112 deserialized.global.period_months
14113 );
14114 assert_eq!(config.global.industry, deserialized.global.industry);
14115 assert_eq!(config.companies.len(), deserialized.companies.len());
14116 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
14117 }
14118
14119 #[test]
14120 fn test_config_json_roundtrip() {
14121 let mut config = demo_preset();
14123 config.master_data.employees.approval_limits.executive = 1e12;
14125
14126 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
14127 let deserialized: GeneratorConfig =
14128 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
14129
14130 assert_eq!(
14131 config.global.period_months,
14132 deserialized.global.period_months
14133 );
14134 assert_eq!(config.global.industry, deserialized.global.industry);
14135 assert_eq!(config.companies.len(), deserialized.companies.len());
14136 }
14137
14138 #[test]
14139 fn test_transaction_volume_serialization() {
14140 let volumes = vec![
14142 (TransactionVolume::TenK, "ten_k"),
14143 (TransactionVolume::HundredK, "hundred_k"),
14144 (TransactionVolume::OneM, "one_m"),
14145 (TransactionVolume::TenM, "ten_m"),
14146 (TransactionVolume::HundredM, "hundred_m"),
14147 ];
14148
14149 for (volume, expected_key) in volumes {
14150 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14151 assert!(
14152 json.contains(expected_key),
14153 "Expected {} in JSON: {}",
14154 expected_key,
14155 json
14156 );
14157 }
14158 }
14159
14160 #[test]
14161 fn test_transaction_volume_custom_serialization() {
14162 let volume = TransactionVolume::Custom(12345);
14163 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14164 let deserialized: TransactionVolume =
14165 serde_json::from_str(&json).expect("Failed to deserialize");
14166 assert_eq!(deserialized.count(), 12345);
14167 }
14168
14169 #[test]
14170 fn test_output_mode_serialization() {
14171 let modes = vec![
14172 OutputMode::Streaming,
14173 OutputMode::FlatFile,
14174 OutputMode::Both,
14175 ];
14176
14177 for mode in modes {
14178 let json = serde_json::to_string(&mode).expect("Failed to serialize");
14179 let deserialized: OutputMode =
14180 serde_json::from_str(&json).expect("Failed to deserialize");
14181 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
14182 }
14183 }
14184
14185 #[test]
14186 fn test_file_format_serialization() {
14187 let formats = vec![
14188 FileFormat::Csv,
14189 FileFormat::Parquet,
14190 FileFormat::Json,
14191 FileFormat::JsonLines,
14192 ];
14193
14194 for format in formats {
14195 let json = serde_json::to_string(&format).expect("Failed to serialize");
14196 let deserialized: FileFormat =
14197 serde_json::from_str(&json).expect("Failed to deserialize");
14198 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
14199 }
14200 }
14201
14202 #[test]
14203 fn test_compression_algorithm_serialization() {
14204 let algos = vec![
14205 CompressionAlgorithm::Gzip,
14206 CompressionAlgorithm::Zstd,
14207 CompressionAlgorithm::Lz4,
14208 CompressionAlgorithm::Snappy,
14209 ];
14210
14211 for algo in algos {
14212 let json = serde_json::to_string(&algo).expect("Failed to serialize");
14213 let deserialized: CompressionAlgorithm =
14214 serde_json::from_str(&json).expect("Failed to deserialize");
14215 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
14216 }
14217 }
14218
14219 #[test]
14220 fn test_transfer_pricing_method_serialization() {
14221 let methods = vec![
14222 TransferPricingMethod::CostPlus,
14223 TransferPricingMethod::ComparableUncontrolled,
14224 TransferPricingMethod::ResalePrice,
14225 TransferPricingMethod::TransactionalNetMargin,
14226 TransferPricingMethod::ProfitSplit,
14227 ];
14228
14229 for method in methods {
14230 let json = serde_json::to_string(&method).expect("Failed to serialize");
14231 let deserialized: TransferPricingMethod =
14232 serde_json::from_str(&json).expect("Failed to deserialize");
14233 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
14234 }
14235 }
14236
14237 #[test]
14238 fn test_benford_exemption_serialization() {
14239 let exemptions = vec![
14240 BenfordExemption::Recurring,
14241 BenfordExemption::Payroll,
14242 BenfordExemption::FixedFees,
14243 BenfordExemption::RoundAmounts,
14244 ];
14245
14246 for exemption in exemptions {
14247 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
14248 let deserialized: BenfordExemption =
14249 serde_json::from_str(&json).expect("Failed to deserialize");
14250 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
14251 }
14252 }
14253
14254 #[test]
14259 fn test_global_config_defaults() {
14260 let yaml = r#"
14261 industry: manufacturing
14262 start_date: "2024-01-01"
14263 period_months: 6
14264 "#;
14265 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14266 assert_eq!(config.group_currency, "USD");
14267 assert!(config.parallel);
14268 assert_eq!(config.worker_threads, 0);
14269 assert_eq!(config.memory_limit_mb, 0);
14270 }
14271
14272 #[test]
14273 fn test_fraud_config_defaults() {
14274 let config = FraudConfig::default();
14275 assert!(!config.enabled);
14276 assert_eq!(config.fraud_rate, 0.005);
14277 assert!(!config.clustering_enabled);
14278 }
14279
14280 #[test]
14281 fn test_internal_controls_config_defaults() {
14282 let config = InternalControlsConfig::default();
14283 assert!(!config.enabled);
14284 assert_eq!(config.exception_rate, 0.02);
14285 assert_eq!(config.sod_violation_rate, 0.01);
14286 assert!(config.export_control_master_data);
14287 assert_eq!(config.sox_materiality_threshold, 10000.0);
14288 assert!(config.coso_enabled);
14290 assert!(!config.include_entity_level_controls);
14291 assert_eq!(config.target_maturity_level, "mixed");
14292 }
14293
14294 #[test]
14295 fn test_output_config_defaults() {
14296 let config = OutputConfig::default();
14297 assert!(matches!(config.mode, OutputMode::FlatFile));
14298 assert_eq!(config.formats, vec![FileFormat::Parquet]);
14299 assert!(config.compression.enabled);
14300 assert!(matches!(
14301 config.compression.algorithm,
14302 CompressionAlgorithm::Zstd
14303 ));
14304 assert!(config.include_acdoca);
14305 assert!(!config.include_bseg);
14306 assert!(config.partition_by_period);
14307 assert!(!config.partition_by_company);
14308 }
14309
14310 #[test]
14311 fn test_approval_config_defaults() {
14312 let config = ApprovalConfig::default();
14313 assert!(!config.enabled);
14314 assert_eq!(config.auto_approve_threshold, 1000.0);
14315 assert_eq!(config.rejection_rate, 0.02);
14316 assert_eq!(config.revision_rate, 0.05);
14317 assert_eq!(config.average_approval_delay_hours, 4.0);
14318 assert_eq!(config.thresholds.len(), 4);
14319 }
14320
14321 #[test]
14322 fn test_p2p_flow_config_defaults() {
14323 let config = P2PFlowConfig::default();
14324 assert!(config.enabled);
14325 assert_eq!(config.three_way_match_rate, 0.95);
14326 assert_eq!(config.partial_delivery_rate, 0.15);
14327 assert_eq!(config.average_po_to_gr_days, 14);
14328 }
14329
14330 #[test]
14331 fn test_o2c_flow_config_defaults() {
14332 let config = O2CFlowConfig::default();
14333 assert!(config.enabled);
14334 assert_eq!(config.credit_check_failure_rate, 0.02);
14335 assert_eq!(config.return_rate, 0.03);
14336 assert_eq!(config.bad_debt_rate, 0.01);
14337 }
14338
14339 #[test]
14340 fn test_balance_config_defaults() {
14341 let config = BalanceConfig::default();
14342 assert!(!config.generate_opening_balances);
14343 assert!(config.generate_trial_balances);
14344 assert_eq!(config.target_gross_margin, 0.35);
14345 assert!(config.validate_balance_equation);
14346 assert!(config.reconcile_subledgers);
14347 }
14348
14349 #[test]
14354 fn test_partial_config_with_defaults() {
14355 let yaml = r#"
14357 global:
14358 industry: manufacturing
14359 start_date: "2024-01-01"
14360 period_months: 3
14361 companies:
14362 - code: "TEST"
14363 name: "Test Company"
14364 currency: "USD"
14365 country: "US"
14366 annual_transaction_volume: ten_k
14367 chart_of_accounts:
14368 complexity: small
14369 output:
14370 output_directory: "./output"
14371 "#;
14372
14373 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14374 assert_eq!(config.global.period_months, 3);
14375 assert_eq!(config.companies.len(), 1);
14376 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
14379
14380 #[test]
14381 fn test_config_with_fraud_enabled() {
14382 let yaml = r#"
14383 global:
14384 industry: retail
14385 start_date: "2024-01-01"
14386 period_months: 12
14387 companies:
14388 - code: "RETAIL"
14389 name: "Retail Co"
14390 currency: "USD"
14391 country: "US"
14392 annual_transaction_volume: hundred_k
14393 chart_of_accounts:
14394 complexity: medium
14395 output:
14396 output_directory: "./output"
14397 fraud:
14398 enabled: true
14399 fraud_rate: 0.05
14400 clustering_enabled: true
14401 "#;
14402
14403 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14404 assert!(config.fraud.enabled);
14405 assert_eq!(config.fraud.fraud_rate, 0.05);
14406 assert!(config.fraud.clustering_enabled);
14407 }
14408
14409 #[test]
14410 fn test_config_with_multiple_companies() {
14411 let yaml = r#"
14412 global:
14413 industry: manufacturing
14414 start_date: "2024-01-01"
14415 period_months: 6
14416 companies:
14417 - code: "HQ"
14418 name: "Headquarters"
14419 currency: "USD"
14420 country: "US"
14421 annual_transaction_volume: hundred_k
14422 volume_weight: 1.0
14423 - code: "EU"
14424 name: "European Subsidiary"
14425 currency: "EUR"
14426 country: "DE"
14427 annual_transaction_volume: hundred_k
14428 volume_weight: 0.5
14429 - code: "APAC"
14430 name: "Asia Pacific"
14431 currency: "JPY"
14432 country: "JP"
14433 annual_transaction_volume: ten_k
14434 volume_weight: 0.3
14435 chart_of_accounts:
14436 complexity: large
14437 output:
14438 output_directory: "./output"
14439 "#;
14440
14441 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14442 assert_eq!(config.companies.len(), 3);
14443 assert_eq!(config.companies[0].code, "HQ");
14444 assert_eq!(config.companies[1].currency, "EUR");
14445 assert_eq!(config.companies[2].volume_weight, 0.3);
14446 }
14447
14448 #[test]
14449 fn test_intercompany_config() {
14450 let yaml = r#"
14451 enabled: true
14452 ic_transaction_rate: 0.20
14453 transfer_pricing_method: cost_plus
14454 markup_percent: 0.08
14455 generate_matched_pairs: true
14456 generate_eliminations: true
14457 "#;
14458
14459 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14460 assert!(config.enabled);
14461 assert_eq!(config.ic_transaction_rate, 0.20);
14462 assert!(matches!(
14463 config.transfer_pricing_method,
14464 TransferPricingMethod::CostPlus
14465 ));
14466 assert_eq!(config.markup_percent, 0.08);
14467 assert!(config.generate_eliminations);
14468 }
14469
14470 #[test]
14475 fn test_company_config_defaults() {
14476 let yaml = r#"
14477 code: "TEST"
14478 name: "Test Company"
14479 currency: "USD"
14480 country: "US"
14481 annual_transaction_volume: ten_k
14482 "#;
14483
14484 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14485 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
14488
14489 #[test]
14494 fn test_coa_config_defaults() {
14495 let yaml = r#"
14496 complexity: medium
14497 "#;
14498
14499 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14500 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
14502 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
14505
14506 #[test]
14511 fn test_accounting_standards_config_defaults() {
14512 let config = AccountingStandardsConfig::default();
14513 assert!(!config.enabled);
14514 assert!(config.framework.is_none());
14515 assert!(!config.revenue_recognition.enabled);
14516 assert!(!config.leases.enabled);
14517 assert!(!config.fair_value.enabled);
14518 assert!(!config.impairment.enabled);
14519 assert!(!config.generate_differences);
14520 }
14521
14522 #[test]
14523 fn test_accounting_standards_config_yaml() {
14524 let yaml = r#"
14525 enabled: true
14526 framework: ifrs
14527 revenue_recognition:
14528 enabled: true
14529 generate_contracts: true
14530 avg_obligations_per_contract: 2.5
14531 variable_consideration_rate: 0.20
14532 over_time_recognition_rate: 0.35
14533 contract_count: 150
14534 leases:
14535 enabled: true
14536 lease_count: 75
14537 finance_lease_percent: 0.25
14538 avg_lease_term_months: 48
14539 generate_differences: true
14540 "#;
14541
14542 let config: AccountingStandardsConfig =
14543 serde_yaml::from_str(yaml).expect("Failed to parse");
14544 assert!(config.enabled);
14545 assert!(matches!(
14546 config.framework,
14547 Some(AccountingFrameworkConfig::Ifrs)
14548 ));
14549 assert!(config.revenue_recognition.enabled);
14550 assert_eq!(config.revenue_recognition.contract_count, 150);
14551 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
14552 assert!(config.leases.enabled);
14553 assert_eq!(config.leases.lease_count, 75);
14554 assert_eq!(config.leases.finance_lease_percent, 0.25);
14555 assert!(config.generate_differences);
14556 }
14557
14558 #[test]
14559 fn test_accounting_framework_serialization() {
14560 let frameworks = [
14561 AccountingFrameworkConfig::UsGaap,
14562 AccountingFrameworkConfig::Ifrs,
14563 AccountingFrameworkConfig::DualReporting,
14564 AccountingFrameworkConfig::FrenchGaap,
14565 AccountingFrameworkConfig::GermanGaap,
14566 ];
14567
14568 for framework in frameworks {
14569 let json = serde_json::to_string(&framework).expect("Failed to serialize");
14570 let deserialized: AccountingFrameworkConfig =
14571 serde_json::from_str(&json).expect("Failed to deserialize");
14572 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
14573 }
14574 }
14575
14576 #[test]
14577 fn test_revenue_recognition_config_defaults() {
14578 let config = RevenueRecognitionConfig::default();
14579 assert!(!config.enabled);
14580 assert!(config.generate_contracts);
14581 assert_eq!(config.avg_obligations_per_contract, 2.0);
14582 assert_eq!(config.variable_consideration_rate, 0.15);
14583 assert_eq!(config.over_time_recognition_rate, 0.30);
14584 assert_eq!(config.contract_count, 100);
14585 }
14586
14587 #[test]
14588 fn test_lease_accounting_config_defaults() {
14589 let config = LeaseAccountingConfig::default();
14590 assert!(!config.enabled);
14591 assert_eq!(config.lease_count, 50);
14592 assert_eq!(config.finance_lease_percent, 0.30);
14593 assert_eq!(config.avg_lease_term_months, 60);
14594 assert!(config.generate_amortization);
14595 assert_eq!(config.real_estate_percent, 0.40);
14596 }
14597
14598 #[test]
14599 fn test_fair_value_config_defaults() {
14600 let config = FairValueConfig::default();
14601 assert!(!config.enabled);
14602 assert_eq!(config.measurement_count, 25);
14603 assert_eq!(config.level1_percent, 0.40);
14604 assert_eq!(config.level2_percent, 0.35);
14605 assert_eq!(config.level3_percent, 0.25);
14606 assert!(!config.include_sensitivity_analysis);
14607 }
14608
14609 #[test]
14610 fn test_impairment_config_defaults() {
14611 let config = ImpairmentConfig::default();
14612 assert!(!config.enabled);
14613 assert_eq!(config.test_count, 15);
14614 assert_eq!(config.impairment_rate, 0.10);
14615 assert!(config.generate_projections);
14616 assert!(!config.include_goodwill);
14617 }
14618
14619 #[test]
14624 fn test_audit_standards_config_defaults() {
14625 let config = AuditStandardsConfig::default();
14626 assert!(!config.enabled);
14627 assert!(!config.isa_compliance.enabled);
14628 assert!(!config.analytical_procedures.enabled);
14629 assert!(!config.confirmations.enabled);
14630 assert!(!config.opinion.enabled);
14631 assert!(!config.generate_audit_trail);
14632 assert!(!config.sox.enabled);
14633 assert!(!config.pcaob.enabled);
14634 }
14635
14636 #[test]
14637 fn test_audit_standards_config_yaml() {
14638 let yaml = r#"
14639 enabled: true
14640 isa_compliance:
14641 enabled: true
14642 compliance_level: comprehensive
14643 generate_isa_mappings: true
14644 include_pcaob: true
14645 framework: dual
14646 analytical_procedures:
14647 enabled: true
14648 procedures_per_account: 5
14649 variance_probability: 0.25
14650 confirmations:
14651 enabled: true
14652 confirmation_count: 75
14653 positive_response_rate: 0.90
14654 exception_rate: 0.08
14655 opinion:
14656 enabled: true
14657 generate_kam: true
14658 average_kam_count: 4
14659 sox:
14660 enabled: true
14661 generate_302_certifications: true
14662 generate_404_assessments: true
14663 material_weakness_rate: 0.03
14664 pcaob:
14665 enabled: true
14666 is_pcaob_audit: true
14667 include_icfr_opinion: true
14668 generate_audit_trail: true
14669 "#;
14670
14671 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14672 assert!(config.enabled);
14673 assert!(config.isa_compliance.enabled);
14674 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
14675 assert!(config.isa_compliance.include_pcaob);
14676 assert_eq!(config.isa_compliance.framework, "dual");
14677 assert!(config.analytical_procedures.enabled);
14678 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
14679 assert!(config.confirmations.enabled);
14680 assert_eq!(config.confirmations.confirmation_count, 75);
14681 assert!(config.opinion.enabled);
14682 assert_eq!(config.opinion.average_kam_count, 4);
14683 assert!(config.sox.enabled);
14684 assert!(config.sox.generate_302_certifications);
14685 assert_eq!(config.sox.material_weakness_rate, 0.03);
14686 assert!(config.pcaob.enabled);
14687 assert!(config.pcaob.is_pcaob_audit);
14688 assert!(config.pcaob.include_icfr_opinion);
14689 assert!(config.generate_audit_trail);
14690 }
14691
14692 #[test]
14693 fn test_isa_compliance_config_defaults() {
14694 let config = IsaComplianceConfig::default();
14695 assert!(!config.enabled);
14696 assert_eq!(config.compliance_level, "standard");
14697 assert!(config.generate_isa_mappings);
14698 assert!(config.generate_coverage_summary);
14699 assert!(!config.include_pcaob);
14700 assert_eq!(config.framework, "isa");
14701 }
14702
14703 #[test]
14704 fn test_sox_compliance_config_defaults() {
14705 let config = SoxComplianceConfig::default();
14706 assert!(!config.enabled);
14707 assert!(config.generate_302_certifications);
14708 assert!(config.generate_404_assessments);
14709 assert_eq!(config.materiality_threshold, 10000.0);
14710 assert_eq!(config.material_weakness_rate, 0.02);
14711 assert_eq!(config.significant_deficiency_rate, 0.08);
14712 }
14713
14714 #[test]
14715 fn test_pcaob_config_defaults() {
14716 let config = PcaobConfig::default();
14717 assert!(!config.enabled);
14718 assert!(!config.is_pcaob_audit);
14719 assert!(config.generate_cam);
14720 assert!(!config.include_icfr_opinion);
14721 assert!(!config.generate_standard_mappings);
14722 }
14723
14724 #[test]
14725 fn test_config_with_standards_enabled() {
14726 let yaml = r#"
14727 global:
14728 industry: financial_services
14729 start_date: "2024-01-01"
14730 period_months: 12
14731 companies:
14732 - code: "BANK"
14733 name: "Test Bank"
14734 currency: "USD"
14735 country: "US"
14736 annual_transaction_volume: hundred_k
14737 chart_of_accounts:
14738 complexity: large
14739 output:
14740 output_directory: "./output"
14741 accounting_standards:
14742 enabled: true
14743 framework: us_gaap
14744 revenue_recognition:
14745 enabled: true
14746 leases:
14747 enabled: true
14748 audit_standards:
14749 enabled: true
14750 isa_compliance:
14751 enabled: true
14752 sox:
14753 enabled: true
14754 "#;
14755
14756 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14757 assert!(config.accounting_standards.enabled);
14758 assert!(matches!(
14759 config.accounting_standards.framework,
14760 Some(AccountingFrameworkConfig::UsGaap)
14761 ));
14762 assert!(config.accounting_standards.revenue_recognition.enabled);
14763 assert!(config.accounting_standards.leases.enabled);
14764 assert!(config.audit_standards.enabled);
14765 assert!(config.audit_standards.isa_compliance.enabled);
14766 assert!(config.audit_standards.sox.enabled);
14767 }
14768
14769 #[test]
14774 fn test_industry_specific_config_defaults() {
14775 let config = IndustrySpecificConfig::default();
14776 assert!(!config.enabled);
14777 assert!(!config.manufacturing.enabled);
14778 assert!(!config.retail.enabled);
14779 assert!(!config.healthcare.enabled);
14780 assert!(!config.technology.enabled);
14781 assert!(!config.financial_services.enabled);
14782 assert!(!config.professional_services.enabled);
14783 }
14784
14785 #[test]
14786 fn test_manufacturing_config_defaults() {
14787 let config = ManufacturingConfig::default();
14788 assert!(!config.enabled);
14789 assert_eq!(config.bom_depth, 4);
14790 assert!(!config.just_in_time);
14791 assert_eq!(config.supplier_tiers, 2);
14792 assert_eq!(config.target_yield_rate, 0.97);
14793 assert_eq!(config.scrap_alert_threshold, 0.03);
14794 }
14795
14796 #[test]
14797 fn test_retail_config_defaults() {
14798 let config = RetailConfig::default();
14799 assert!(!config.enabled);
14800 assert_eq!(config.avg_daily_transactions, 500);
14801 assert!(config.loss_prevention);
14802 assert_eq!(config.shrinkage_rate, 0.015);
14803 }
14804
14805 #[test]
14806 fn test_healthcare_config_defaults() {
14807 let config = HealthcareConfig::default();
14808 assert!(!config.enabled);
14809 assert_eq!(config.facility_type, "hospital");
14810 assert_eq!(config.avg_daily_encounters, 150);
14811 assert!(config.compliance.hipaa);
14812 assert!(config.compliance.stark_law);
14813 assert!(config.coding_systems.icd10);
14814 assert!(config.coding_systems.cpt);
14815 }
14816
14817 #[test]
14818 fn test_technology_config_defaults() {
14819 let config = TechnologyConfig::default();
14820 assert!(!config.enabled);
14821 assert_eq!(config.revenue_model, "saas");
14822 assert_eq!(config.subscription_revenue_pct, 0.60);
14823 assert!(config.rd_capitalization.enabled);
14824 }
14825
14826 #[test]
14827 fn test_config_with_industry_specific() {
14828 let yaml = r#"
14829 global:
14830 industry: healthcare
14831 start_date: "2024-01-01"
14832 period_months: 12
14833 companies:
14834 - code: "HOSP"
14835 name: "Test Hospital"
14836 currency: "USD"
14837 country: "US"
14838 annual_transaction_volume: hundred_k
14839 chart_of_accounts:
14840 complexity: medium
14841 output:
14842 output_directory: "./output"
14843 industry_specific:
14844 enabled: true
14845 healthcare:
14846 enabled: true
14847 facility_type: hospital
14848 payer_mix:
14849 medicare: 0.45
14850 medicaid: 0.15
14851 commercial: 0.35
14852 self_pay: 0.05
14853 coding_systems:
14854 icd10: true
14855 cpt: true
14856 drg: true
14857 compliance:
14858 hipaa: true
14859 stark_law: true
14860 anomaly_rates:
14861 upcoding: 0.03
14862 unbundling: 0.02
14863 "#;
14864
14865 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14866 assert!(config.industry_specific.enabled);
14867 assert!(config.industry_specific.healthcare.enabled);
14868 assert_eq!(
14869 config.industry_specific.healthcare.facility_type,
14870 "hospital"
14871 );
14872 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14873 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14874 assert!(config.industry_specific.healthcare.coding_systems.icd10);
14875 assert!(config.industry_specific.healthcare.compliance.hipaa);
14876 assert_eq!(
14877 config.industry_specific.healthcare.anomaly_rates.upcoding,
14878 0.03
14879 );
14880 }
14881
14882 #[test]
14883 fn test_config_with_manufacturing_specific() {
14884 let yaml = r#"
14885 global:
14886 industry: manufacturing
14887 start_date: "2024-01-01"
14888 period_months: 12
14889 companies:
14890 - code: "MFG"
14891 name: "Test Manufacturing"
14892 currency: "USD"
14893 country: "US"
14894 annual_transaction_volume: hundred_k
14895 chart_of_accounts:
14896 complexity: medium
14897 output:
14898 output_directory: "./output"
14899 industry_specific:
14900 enabled: true
14901 manufacturing:
14902 enabled: true
14903 bom_depth: 5
14904 just_in_time: true
14905 supplier_tiers: 3
14906 target_yield_rate: 0.98
14907 anomaly_rates:
14908 yield_manipulation: 0.02
14909 phantom_production: 0.01
14910 "#;
14911
14912 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14913 assert!(config.industry_specific.enabled);
14914 assert!(config.industry_specific.manufacturing.enabled);
14915 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14916 assert!(config.industry_specific.manufacturing.just_in_time);
14917 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14918 assert_eq!(
14919 config.industry_specific.manufacturing.target_yield_rate,
14920 0.98
14921 );
14922 assert_eq!(
14923 config
14924 .industry_specific
14925 .manufacturing
14926 .anomaly_rates
14927 .yield_manipulation,
14928 0.02
14929 );
14930 }
14931
14932 #[test]
14937 fn test_tax_config_defaults() {
14938 let tax = TaxConfig::default();
14939 assert!(!tax.enabled);
14940 assert!(tax.jurisdictions.countries.is_empty());
14941 assert!(!tax.jurisdictions.include_subnational);
14942 assert!(!tax.vat_gst.enabled);
14943 assert!(tax.vat_gst.standard_rates.is_empty());
14944 assert!(tax.vat_gst.reduced_rates.is_empty());
14945 assert!(tax.vat_gst.exempt_categories.is_empty());
14946 assert!(tax.vat_gst.reverse_charge);
14947 assert!(!tax.sales_tax.enabled);
14948 assert!(tax.sales_tax.nexus_states.is_empty());
14949 assert!(!tax.withholding.enabled);
14950 assert!(tax.withholding.treaty_network);
14951 assert_eq!(tax.withholding.default_rate, 0.30);
14952 assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14953 assert!(tax.provisions.enabled);
14954 assert_eq!(tax.provisions.statutory_rate, 0.21);
14955 assert!(tax.provisions.uncertain_positions);
14956 assert!(!tax.payroll_tax.enabled);
14957 assert_eq!(tax.anomaly_rate, 0.03);
14958 }
14959
14960 #[test]
14961 fn test_tax_config_from_yaml() {
14962 let yaml = r#"
14963 global:
14964 seed: 42
14965 start_date: "2024-01-01"
14966 period_months: 12
14967 industry: retail
14968 companies:
14969 - code: C001
14970 name: Test Corp
14971 currency: USD
14972 country: US
14973 annual_transaction_volume: ten_k
14974 chart_of_accounts:
14975 complexity: small
14976 output:
14977 output_directory: ./output
14978 tax:
14979 enabled: true
14980 anomaly_rate: 0.05
14981 jurisdictions:
14982 countries: ["US", "DE", "GB"]
14983 include_subnational: true
14984 vat_gst:
14985 enabled: true
14986 standard_rates:
14987 DE: 0.19
14988 GB: 0.20
14989 reduced_rates:
14990 DE: 0.07
14991 GB: 0.05
14992 exempt_categories:
14993 - financial_services
14994 - healthcare
14995 reverse_charge: false
14996 sales_tax:
14997 enabled: true
14998 nexus_states: ["CA", "NY", "TX"]
14999 withholding:
15000 enabled: true
15001 treaty_network: false
15002 default_rate: 0.25
15003 treaty_reduced_rate: 0.10
15004 provisions:
15005 enabled: false
15006 statutory_rate: 0.28
15007 uncertain_positions: false
15008 payroll_tax:
15009 enabled: true
15010 "#;
15011
15012 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
15013 assert!(config.tax.enabled);
15014 assert_eq!(config.tax.anomaly_rate, 0.05);
15015
15016 assert_eq!(config.tax.jurisdictions.countries.len(), 3);
15018 assert!(config
15019 .tax
15020 .jurisdictions
15021 .countries
15022 .contains(&"DE".to_string()));
15023 assert!(config.tax.jurisdictions.include_subnational);
15024
15025 assert!(config.tax.vat_gst.enabled);
15027 assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
15028 assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
15029 assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
15030 assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
15031 assert!(!config.tax.vat_gst.reverse_charge);
15032
15033 assert!(config.tax.sales_tax.enabled);
15035 assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
15036 assert!(config
15037 .tax
15038 .sales_tax
15039 .nexus_states
15040 .contains(&"CA".to_string()));
15041
15042 assert!(config.tax.withholding.enabled);
15044 assert!(!config.tax.withholding.treaty_network);
15045 assert_eq!(config.tax.withholding.default_rate, 0.25);
15046 assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
15047
15048 assert!(!config.tax.provisions.enabled);
15050 assert_eq!(config.tax.provisions.statutory_rate, 0.28);
15051 assert!(!config.tax.provisions.uncertain_positions);
15052
15053 assert!(config.tax.payroll_tax.enabled);
15055 }
15056
15057 #[test]
15058 fn test_generator_config_with_tax_default() {
15059 let yaml = r#"
15060 global:
15061 seed: 42
15062 start_date: "2024-01-01"
15063 period_months: 12
15064 industry: retail
15065 companies:
15066 - code: C001
15067 name: Test Corp
15068 currency: USD
15069 country: US
15070 annual_transaction_volume: ten_k
15071 chart_of_accounts:
15072 complexity: small
15073 output:
15074 output_directory: ./output
15075 "#;
15076
15077 let config: GeneratorConfig =
15078 serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
15079 assert!(!config.tax.enabled);
15081 assert!(config.tax.jurisdictions.countries.is_empty());
15082 assert_eq!(config.tax.anomaly_rate, 0.03);
15083 assert!(config.tax.provisions.enabled); assert_eq!(config.tax.provisions.statutory_rate, 0.21);
15085 }
15086
15087 #[test]
15092 fn test_session_config_default_disabled() {
15093 let yaml = "{}";
15094 let config: SessionSchemaConfig =
15095 serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
15096 assert!(!config.enabled);
15097 assert!(config.checkpoint_path.is_none());
15098 assert!(config.per_period_output);
15099 assert!(config.consolidated_output);
15100 }
15101
15102 #[test]
15103 fn test_config_backward_compatible_without_session() {
15104 let yaml = r#"
15105 global:
15106 seed: 42
15107 start_date: "2024-01-01"
15108 period_months: 12
15109 industry: retail
15110 companies:
15111 - code: C001
15112 name: Test Corp
15113 currency: USD
15114 country: US
15115 annual_transaction_volume: ten_k
15116 chart_of_accounts:
15117 complexity: small
15118 output:
15119 output_directory: ./output
15120 "#;
15121
15122 let config: GeneratorConfig =
15123 serde_yaml::from_str(yaml).expect("Failed to parse config without session");
15124 assert!(!config.session.enabled);
15126 assert!(config.session.per_period_output);
15127 assert!(config.session.consolidated_output);
15128 assert!(config.global.fiscal_year_months.is_none());
15130 }
15131
15132 #[test]
15133 fn test_fiscal_year_months_parsed() {
15134 let yaml = r#"
15135 global:
15136 seed: 42
15137 start_date: "2024-01-01"
15138 period_months: 24
15139 industry: retail
15140 fiscal_year_months: 12
15141 companies:
15142 - code: C001
15143 name: Test Corp
15144 currency: USD
15145 country: US
15146 annual_transaction_volume: ten_k
15147 chart_of_accounts:
15148 complexity: small
15149 output:
15150 output_directory: ./output
15151 session:
15152 enabled: true
15153 checkpoint_path: /tmp/checkpoints
15154 per_period_output: true
15155 consolidated_output: false
15156 "#;
15157
15158 let config: GeneratorConfig =
15159 serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
15160 assert_eq!(config.global.fiscal_year_months, Some(12));
15161 assert!(config.session.enabled);
15162 assert_eq!(
15163 config.session.checkpoint_path,
15164 Some("/tmp/checkpoints".to_string())
15165 );
15166 assert!(config.session.per_period_output);
15167 assert!(!config.session.consolidated_output);
15168 }
15169}