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.05)
2077}
2078fn default_clustering_factor() -> f64 {
2079 3.0
2080}
2081
2082impl Default for FraudConfig {
2083 fn default() -> Self {
2084 Self {
2085 enabled: false,
2086 fraud_rate: default_fraud_rate(),
2087 document_fraud_rate: default_document_fraud_rate(),
2088 propagate_to_lines: true,
2089 propagate_to_document: true,
2090 fraud_type_distribution: FraudTypeDistribution::default(),
2091 clustering_enabled: false,
2092 clustering_factor: default_clustering_factor(),
2093 approval_thresholds: default_approval_thresholds(),
2094 }
2095 }
2096}
2097
2098#[derive(Debug, Clone, Serialize, Deserialize)]
2100pub struct FraudTypeDistribution {
2101 pub suspense_account_abuse: f64,
2102 pub fictitious_transaction: f64,
2103 pub revenue_manipulation: f64,
2104 pub expense_capitalization: f64,
2105 pub split_transaction: f64,
2106 pub timing_anomaly: f64,
2107 pub unauthorized_access: f64,
2108 pub duplicate_payment: f64,
2109}
2110
2111impl Default for FraudTypeDistribution {
2112 fn default() -> Self {
2113 Self {
2114 suspense_account_abuse: 0.25,
2115 fictitious_transaction: 0.15,
2116 revenue_manipulation: 0.10,
2117 expense_capitalization: 0.10,
2118 split_transaction: 0.15,
2119 timing_anomaly: 0.10,
2120 unauthorized_access: 0.10,
2121 duplicate_payment: 0.05,
2122 }
2123 }
2124}
2125
2126#[derive(Debug, Clone, Serialize, Deserialize)]
2128pub struct InternalControlsConfig {
2129 #[serde(default)]
2131 pub enabled: bool,
2132 #[serde(default = "default_exception_rate")]
2134 pub exception_rate: f64,
2135 #[serde(default = "default_sod_violation_rate")]
2137 pub sod_violation_rate: f64,
2138 #[serde(default = "default_true")]
2140 pub export_control_master_data: bool,
2141 #[serde(default = "default_sox_materiality_threshold")]
2143 pub sox_materiality_threshold: f64,
2144 #[serde(default = "default_true")]
2146 pub coso_enabled: bool,
2147 #[serde(default)]
2149 pub include_entity_level_controls: bool,
2150 #[serde(default = "default_target_maturity_level")]
2153 pub target_maturity_level: String,
2154}
2155
2156fn default_exception_rate() -> f64 {
2157 0.02
2158}
2159
2160fn default_sod_violation_rate() -> f64 {
2161 0.01
2162}
2163
2164fn default_sox_materiality_threshold() -> f64 {
2165 10000.0
2166}
2167
2168fn default_target_maturity_level() -> String {
2169 "mixed".to_string()
2170}
2171
2172impl Default for InternalControlsConfig {
2173 fn default() -> Self {
2174 Self {
2175 enabled: false,
2176 exception_rate: default_exception_rate(),
2177 sod_violation_rate: default_sod_violation_rate(),
2178 export_control_master_data: true,
2179 sox_materiality_threshold: default_sox_materiality_threshold(),
2180 coso_enabled: true,
2181 include_entity_level_controls: false,
2182 target_maturity_level: default_target_maturity_level(),
2183 }
2184 }
2185}
2186
2187#[derive(Debug, Clone, Serialize, Deserialize)]
2189pub struct BusinessProcessConfig {
2190 #[serde(default = "default_o2c")]
2192 pub o2c_weight: f64,
2193 #[serde(default = "default_p2p")]
2195 pub p2p_weight: f64,
2196 #[serde(default = "default_r2r")]
2198 pub r2r_weight: f64,
2199 #[serde(default = "default_h2r")]
2201 pub h2r_weight: f64,
2202 #[serde(default = "default_a2r")]
2204 pub a2r_weight: f64,
2205}
2206
2207fn default_o2c() -> f64 {
2208 0.35
2209}
2210fn default_p2p() -> f64 {
2211 0.30
2212}
2213fn default_r2r() -> f64 {
2214 0.20
2215}
2216fn default_h2r() -> f64 {
2217 0.10
2218}
2219fn default_a2r() -> f64 {
2220 0.05
2221}
2222
2223impl Default for BusinessProcessConfig {
2224 fn default() -> Self {
2225 Self {
2226 o2c_weight: default_o2c(),
2227 p2p_weight: default_p2p(),
2228 r2r_weight: default_r2r(),
2229 h2r_weight: default_h2r(),
2230 a2r_weight: default_a2r(),
2231 }
2232 }
2233}
2234
2235#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2237pub struct UserPersonaConfig {
2238 #[serde(default)]
2240 pub persona_distribution: PersonaDistribution,
2241 #[serde(default)]
2243 pub users_per_persona: UsersPerPersona,
2244}
2245
2246#[derive(Debug, Clone, Serialize, Deserialize)]
2248pub struct PersonaDistribution {
2249 pub junior_accountant: f64,
2250 pub senior_accountant: f64,
2251 pub controller: f64,
2252 pub manager: f64,
2253 pub automated_system: f64,
2254}
2255
2256impl Default for PersonaDistribution {
2257 fn default() -> Self {
2258 Self {
2259 junior_accountant: 0.15,
2260 senior_accountant: 0.15,
2261 controller: 0.05,
2262 manager: 0.05,
2263 automated_system: 0.60,
2264 }
2265 }
2266}
2267
2268#[derive(Debug, Clone, Serialize, Deserialize)]
2270pub struct UsersPerPersona {
2271 pub junior_accountant: usize,
2272 pub senior_accountant: usize,
2273 pub controller: usize,
2274 pub manager: usize,
2275 pub automated_system: usize,
2276}
2277
2278impl Default for UsersPerPersona {
2279 fn default() -> Self {
2280 Self {
2281 junior_accountant: 10,
2282 senior_accountant: 5,
2283 controller: 2,
2284 manager: 3,
2285 automated_system: 20,
2286 }
2287 }
2288}
2289
2290#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2304pub struct TemplateConfig {
2305 #[serde(default)]
2307 pub names: NameTemplateConfig,
2308 #[serde(default)]
2310 pub descriptions: DescriptionTemplateConfig,
2311 #[serde(default)]
2313 pub references: ReferenceTemplateConfig,
2314 #[serde(default, alias = "templatesPath")]
2320 pub path: Option<std::path::PathBuf>,
2321 #[serde(default, alias = "mergeStrategy")]
2330 pub merge_strategy: TemplateMergeStrategy,
2331}
2332
2333#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
2335#[serde(rename_all = "snake_case")]
2336pub enum TemplateMergeStrategy {
2337 #[default]
2339 Extend,
2340 Replace,
2342 MergePreferFile,
2344}
2345
2346#[derive(Debug, Clone, Serialize, Deserialize)]
2348pub struct NameTemplateConfig {
2349 #[serde(default)]
2351 pub culture_distribution: CultureDistribution,
2352 #[serde(default = "default_email_domain")]
2354 pub email_domain: String,
2355 #[serde(default = "default_true")]
2357 pub generate_realistic_names: bool,
2358}
2359
2360fn default_email_domain() -> String {
2361 "company.com".to_string()
2362}
2363
2364impl Default for NameTemplateConfig {
2365 fn default() -> Self {
2366 Self {
2367 culture_distribution: CultureDistribution::default(),
2368 email_domain: default_email_domain(),
2369 generate_realistic_names: true,
2370 }
2371 }
2372}
2373
2374#[derive(Debug, Clone, Serialize, Deserialize)]
2376pub struct CultureDistribution {
2377 pub western_us: f64,
2378 pub hispanic: f64,
2379 pub german: f64,
2380 pub french: f64,
2381 pub chinese: f64,
2382 pub japanese: f64,
2383 pub indian: f64,
2384}
2385
2386impl Default for CultureDistribution {
2387 fn default() -> Self {
2388 Self {
2389 western_us: 0.40,
2390 hispanic: 0.20,
2391 german: 0.10,
2392 french: 0.05,
2393 chinese: 0.10,
2394 japanese: 0.05,
2395 indian: 0.10,
2396 }
2397 }
2398}
2399
2400#[derive(Debug, Clone, Serialize, Deserialize)]
2402pub struct DescriptionTemplateConfig {
2403 #[serde(default = "default_true")]
2405 pub generate_header_text: bool,
2406 #[serde(default = "default_true")]
2408 pub generate_line_text: bool,
2409}
2410
2411impl Default for DescriptionTemplateConfig {
2412 fn default() -> Self {
2413 Self {
2414 generate_header_text: true,
2415 generate_line_text: true,
2416 }
2417 }
2418}
2419
2420#[derive(Debug, Clone, Serialize, Deserialize)]
2422pub struct ReferenceTemplateConfig {
2423 #[serde(default = "default_true")]
2425 pub generate_references: bool,
2426 #[serde(default = "default_invoice_prefix")]
2428 pub invoice_prefix: String,
2429 #[serde(default = "default_po_prefix")]
2431 pub po_prefix: String,
2432 #[serde(default = "default_so_prefix")]
2434 pub so_prefix: String,
2435}
2436
2437fn default_invoice_prefix() -> String {
2438 "INV".to_string()
2439}
2440fn default_po_prefix() -> String {
2441 "PO".to_string()
2442}
2443fn default_so_prefix() -> String {
2444 "SO".to_string()
2445}
2446
2447impl Default for ReferenceTemplateConfig {
2448 fn default() -> Self {
2449 Self {
2450 generate_references: true,
2451 invoice_prefix: default_invoice_prefix(),
2452 po_prefix: default_po_prefix(),
2453 so_prefix: default_so_prefix(),
2454 }
2455 }
2456}
2457
2458#[derive(Debug, Clone, Serialize, Deserialize)]
2460pub struct ApprovalConfig {
2461 #[serde(default)]
2463 pub enabled: bool,
2464 #[serde(default = "default_auto_approve_threshold")]
2466 pub auto_approve_threshold: f64,
2467 #[serde(default = "default_rejection_rate")]
2469 pub rejection_rate: f64,
2470 #[serde(default = "default_revision_rate")]
2472 pub revision_rate: f64,
2473 #[serde(default = "default_approval_delay_hours")]
2475 pub average_approval_delay_hours: f64,
2476 #[serde(default)]
2478 pub thresholds: Vec<ApprovalThresholdConfig>,
2479}
2480
2481fn default_auto_approve_threshold() -> f64 {
2482 1000.0
2483}
2484fn default_rejection_rate() -> f64 {
2485 0.02
2486}
2487fn default_revision_rate() -> f64 {
2488 0.05
2489}
2490fn default_approval_delay_hours() -> f64 {
2491 4.0
2492}
2493
2494impl Default for ApprovalConfig {
2495 fn default() -> Self {
2496 Self {
2497 enabled: false,
2498 auto_approve_threshold: default_auto_approve_threshold(),
2499 rejection_rate: default_rejection_rate(),
2500 revision_rate: default_revision_rate(),
2501 average_approval_delay_hours: default_approval_delay_hours(),
2502 thresholds: vec![
2503 ApprovalThresholdConfig {
2504 amount: 1000.0,
2505 level: 1,
2506 roles: vec!["senior_accountant".to_string()],
2507 },
2508 ApprovalThresholdConfig {
2509 amount: 10000.0,
2510 level: 2,
2511 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
2512 },
2513 ApprovalThresholdConfig {
2514 amount: 100000.0,
2515 level: 3,
2516 roles: vec![
2517 "senior_accountant".to_string(),
2518 "controller".to_string(),
2519 "manager".to_string(),
2520 ],
2521 },
2522 ApprovalThresholdConfig {
2523 amount: 500000.0,
2524 level: 4,
2525 roles: vec![
2526 "senior_accountant".to_string(),
2527 "controller".to_string(),
2528 "manager".to_string(),
2529 "executive".to_string(),
2530 ],
2531 },
2532 ],
2533 }
2534 }
2535}
2536
2537#[derive(Debug, Clone, Serialize, Deserialize)]
2539pub struct ApprovalThresholdConfig {
2540 pub amount: f64,
2542 pub level: u8,
2544 pub roles: Vec<String>,
2546}
2547
2548#[derive(Debug, Clone, Serialize, Deserialize)]
2550pub struct DepartmentConfig {
2551 #[serde(default)]
2553 pub enabled: bool,
2554 #[serde(default = "default_headcount_multiplier")]
2556 pub headcount_multiplier: f64,
2557 #[serde(default)]
2559 pub custom_departments: Vec<CustomDepartmentConfig>,
2560}
2561
2562fn default_headcount_multiplier() -> f64 {
2563 1.0
2564}
2565
2566impl Default for DepartmentConfig {
2567 fn default() -> Self {
2568 Self {
2569 enabled: false,
2570 headcount_multiplier: default_headcount_multiplier(),
2571 custom_departments: Vec::new(),
2572 }
2573 }
2574}
2575
2576#[derive(Debug, Clone, Serialize, Deserialize)]
2578pub struct CustomDepartmentConfig {
2579 pub code: String,
2581 pub name: String,
2583 #[serde(default)]
2585 pub cost_center: Option<String>,
2586 #[serde(default)]
2588 pub primary_processes: Vec<String>,
2589 #[serde(default)]
2591 pub parent_code: Option<String>,
2592}
2593
2594#[derive(Debug, Clone, Default, Serialize, Deserialize)]
2600pub struct MasterDataConfig {
2601 #[serde(default)]
2603 pub vendors: VendorMasterConfig,
2604 #[serde(default)]
2606 pub customers: CustomerMasterConfig,
2607 #[serde(default)]
2609 pub materials: MaterialMasterConfig,
2610 #[serde(default)]
2612 pub fixed_assets: FixedAssetMasterConfig,
2613 #[serde(default)]
2615 pub employees: EmployeeMasterConfig,
2616 #[serde(default)]
2618 pub cost_centers: CostCenterMasterConfig,
2619}
2620
2621#[derive(Debug, Clone, Serialize, Deserialize)]
2623pub struct VendorMasterConfig {
2624 #[serde(default = "default_vendor_count")]
2626 pub count: usize,
2627 #[serde(default = "default_intercompany_percent")]
2629 pub intercompany_percent: f64,
2630 #[serde(default)]
2632 pub payment_terms_distribution: PaymentTermsDistribution,
2633 #[serde(default)]
2635 pub behavior_distribution: VendorBehaviorDistribution,
2636 #[serde(default = "default_true")]
2638 pub generate_bank_accounts: bool,
2639 #[serde(default = "default_true")]
2641 pub generate_tax_ids: bool,
2642}
2643
2644fn default_vendor_count() -> usize {
2645 500
2646}
2647
2648fn default_intercompany_percent() -> f64 {
2649 0.05
2650}
2651
2652impl Default for VendorMasterConfig {
2653 fn default() -> Self {
2654 Self {
2655 count: default_vendor_count(),
2656 intercompany_percent: default_intercompany_percent(),
2657 payment_terms_distribution: PaymentTermsDistribution::default(),
2658 behavior_distribution: VendorBehaviorDistribution::default(),
2659 generate_bank_accounts: true,
2660 generate_tax_ids: true,
2661 }
2662 }
2663}
2664
2665#[derive(Debug, Clone, Serialize, Deserialize)]
2667pub struct PaymentTermsDistribution {
2668 pub net_30: f64,
2670 pub net_60: f64,
2672 pub net_90: f64,
2674 pub two_ten_net_30: f64,
2676 pub due_on_receipt: f64,
2678 pub end_of_month: f64,
2680}
2681
2682impl Default for PaymentTermsDistribution {
2683 fn default() -> Self {
2684 Self {
2685 net_30: 0.40,
2686 net_60: 0.20,
2687 net_90: 0.10,
2688 two_ten_net_30: 0.15,
2689 due_on_receipt: 0.05,
2690 end_of_month: 0.10,
2691 }
2692 }
2693}
2694
2695#[derive(Debug, Clone, Serialize, Deserialize)]
2697pub struct VendorBehaviorDistribution {
2698 pub reliable: f64,
2700 pub sometimes_late: f64,
2702 pub inconsistent_quality: f64,
2704 pub premium: f64,
2706 pub budget: f64,
2708}
2709
2710impl Default for VendorBehaviorDistribution {
2711 fn default() -> Self {
2712 Self {
2713 reliable: 0.50,
2714 sometimes_late: 0.20,
2715 inconsistent_quality: 0.10,
2716 premium: 0.10,
2717 budget: 0.10,
2718 }
2719 }
2720}
2721
2722#[derive(Debug, Clone, Serialize, Deserialize)]
2724pub struct CustomerMasterConfig {
2725 #[serde(default = "default_customer_count")]
2727 pub count: usize,
2728 #[serde(default = "default_intercompany_percent")]
2730 pub intercompany_percent: f64,
2731 #[serde(default)]
2733 pub credit_rating_distribution: CreditRatingDistribution,
2734 #[serde(default)]
2736 pub payment_behavior_distribution: PaymentBehaviorDistribution,
2737 #[serde(default = "default_true")]
2739 pub generate_credit_limits: bool,
2740}
2741
2742fn default_customer_count() -> usize {
2743 2000
2744}
2745
2746impl Default for CustomerMasterConfig {
2747 fn default() -> Self {
2748 Self {
2749 count: default_customer_count(),
2750 intercompany_percent: default_intercompany_percent(),
2751 credit_rating_distribution: CreditRatingDistribution::default(),
2752 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
2753 generate_credit_limits: true,
2754 }
2755 }
2756}
2757
2758#[derive(Debug, Clone, Serialize, Deserialize)]
2760pub struct CreditRatingDistribution {
2761 pub aaa: f64,
2763 pub aa: f64,
2765 pub a: f64,
2767 pub bbb: f64,
2769 pub bb: f64,
2771 pub b: f64,
2773 pub below_b: f64,
2775}
2776
2777impl Default for CreditRatingDistribution {
2778 fn default() -> Self {
2779 Self {
2780 aaa: 0.05,
2781 aa: 0.10,
2782 a: 0.20,
2783 bbb: 0.30,
2784 bb: 0.20,
2785 b: 0.10,
2786 below_b: 0.05,
2787 }
2788 }
2789}
2790
2791#[derive(Debug, Clone, Serialize, Deserialize)]
2793pub struct PaymentBehaviorDistribution {
2794 pub early_payer: f64,
2796 pub on_time: f64,
2798 pub occasional_late: f64,
2800 pub frequent_late: f64,
2802 pub discount_taker: f64,
2804}
2805
2806impl Default for PaymentBehaviorDistribution {
2807 fn default() -> Self {
2808 Self {
2809 early_payer: 0.10,
2810 on_time: 0.50,
2811 occasional_late: 0.25,
2812 frequent_late: 0.10,
2813 discount_taker: 0.05,
2814 }
2815 }
2816}
2817
2818#[derive(Debug, Clone, Serialize, Deserialize)]
2820pub struct MaterialMasterConfig {
2821 #[serde(default = "default_material_count")]
2823 pub count: usize,
2824 #[serde(default)]
2826 pub type_distribution: MaterialTypeDistribution,
2827 #[serde(default)]
2829 pub valuation_distribution: ValuationMethodDistribution,
2830 #[serde(default = "default_bom_percent")]
2832 pub bom_percent: f64,
2833 #[serde(default = "default_max_bom_depth")]
2835 pub max_bom_depth: u8,
2836}
2837
2838fn default_material_count() -> usize {
2839 5000
2840}
2841
2842fn default_bom_percent() -> f64 {
2843 0.20
2844}
2845
2846fn default_max_bom_depth() -> u8 {
2847 3
2848}
2849
2850impl Default for MaterialMasterConfig {
2851 fn default() -> Self {
2852 Self {
2853 count: default_material_count(),
2854 type_distribution: MaterialTypeDistribution::default(),
2855 valuation_distribution: ValuationMethodDistribution::default(),
2856 bom_percent: default_bom_percent(),
2857 max_bom_depth: default_max_bom_depth(),
2858 }
2859 }
2860}
2861
2862#[derive(Debug, Clone, Serialize, Deserialize)]
2864pub struct MaterialTypeDistribution {
2865 pub raw_material: f64,
2867 pub semi_finished: f64,
2869 pub finished_good: f64,
2871 pub trading_good: f64,
2873 pub operating_supply: f64,
2875 pub service: f64,
2877}
2878
2879impl Default for MaterialTypeDistribution {
2880 fn default() -> Self {
2881 Self {
2882 raw_material: 0.30,
2883 semi_finished: 0.15,
2884 finished_good: 0.25,
2885 trading_good: 0.15,
2886 operating_supply: 0.10,
2887 service: 0.05,
2888 }
2889 }
2890}
2891
2892#[derive(Debug, Clone, Serialize, Deserialize)]
2894pub struct ValuationMethodDistribution {
2895 pub standard_cost: f64,
2897 pub moving_average: f64,
2899 pub fifo: f64,
2901 pub lifo: f64,
2903}
2904
2905impl Default for ValuationMethodDistribution {
2906 fn default() -> Self {
2907 Self {
2908 standard_cost: 0.50,
2909 moving_average: 0.30,
2910 fifo: 0.15,
2911 lifo: 0.05,
2912 }
2913 }
2914}
2915
2916#[derive(Debug, Clone, Serialize, Deserialize)]
2918pub struct FixedAssetMasterConfig {
2919 #[serde(default = "default_asset_count")]
2921 pub count: usize,
2922 #[serde(default)]
2924 pub class_distribution: AssetClassDistribution,
2925 #[serde(default)]
2927 pub depreciation_distribution: DepreciationMethodDistribution,
2928 #[serde(default = "default_fully_depreciated_percent")]
2930 pub fully_depreciated_percent: f64,
2931 #[serde(default = "default_true")]
2933 pub generate_acquisition_history: bool,
2934}
2935
2936fn default_asset_count() -> usize {
2937 800
2938}
2939
2940fn default_fully_depreciated_percent() -> f64 {
2941 0.15
2942}
2943
2944impl Default for FixedAssetMasterConfig {
2945 fn default() -> Self {
2946 Self {
2947 count: default_asset_count(),
2948 class_distribution: AssetClassDistribution::default(),
2949 depreciation_distribution: DepreciationMethodDistribution::default(),
2950 fully_depreciated_percent: default_fully_depreciated_percent(),
2951 generate_acquisition_history: true,
2952 }
2953 }
2954}
2955
2956#[derive(Debug, Clone, Serialize, Deserialize)]
2958pub struct AssetClassDistribution {
2959 pub buildings: f64,
2961 pub machinery: f64,
2963 pub vehicles: f64,
2965 pub it_equipment: f64,
2967 pub furniture: f64,
2969 pub land: f64,
2971 pub leasehold: f64,
2973}
2974
2975impl Default for AssetClassDistribution {
2976 fn default() -> Self {
2977 Self {
2978 buildings: 0.15,
2979 machinery: 0.30,
2980 vehicles: 0.15,
2981 it_equipment: 0.20,
2982 furniture: 0.10,
2983 land: 0.05,
2984 leasehold: 0.05,
2985 }
2986 }
2987}
2988
2989#[derive(Debug, Clone, Serialize, Deserialize)]
2991pub struct DepreciationMethodDistribution {
2992 pub straight_line: f64,
2994 pub declining_balance: f64,
2996 pub double_declining: f64,
2998 pub sum_of_years: f64,
3000 pub units_of_production: f64,
3002}
3003
3004impl Default for DepreciationMethodDistribution {
3005 fn default() -> Self {
3006 Self {
3007 straight_line: 0.60,
3008 declining_balance: 0.20,
3009 double_declining: 0.10,
3010 sum_of_years: 0.05,
3011 units_of_production: 0.05,
3012 }
3013 }
3014}
3015
3016#[derive(Debug, Clone, Serialize, Deserialize)]
3018pub struct EmployeeMasterConfig {
3019 #[serde(default = "default_employee_count")]
3021 pub count: usize,
3022 #[serde(default = "default_true")]
3024 pub generate_hierarchy: bool,
3025 #[serde(default = "default_hierarchy_depth")]
3027 pub max_hierarchy_depth: u8,
3028 #[serde(default = "default_span_of_control")]
3030 pub average_span_of_control: f64,
3031 #[serde(default)]
3033 pub approval_limits: ApprovalLimitDistribution,
3034 #[serde(default)]
3036 pub department_distribution: EmployeeDepartmentDistribution,
3037}
3038
3039fn default_employee_count() -> usize {
3040 1500
3041}
3042
3043fn default_hierarchy_depth() -> u8 {
3044 6
3045}
3046
3047fn default_span_of_control() -> f64 {
3048 5.0
3049}
3050
3051impl Default for EmployeeMasterConfig {
3052 fn default() -> Self {
3053 Self {
3054 count: default_employee_count(),
3055 generate_hierarchy: true,
3056 max_hierarchy_depth: default_hierarchy_depth(),
3057 average_span_of_control: default_span_of_control(),
3058 approval_limits: ApprovalLimitDistribution::default(),
3059 department_distribution: EmployeeDepartmentDistribution::default(),
3060 }
3061 }
3062}
3063
3064#[derive(Debug, Clone, Serialize, Deserialize)]
3066pub struct ApprovalLimitDistribution {
3067 #[serde(default = "default_staff_limit")]
3069 pub staff: f64,
3070 #[serde(default = "default_senior_limit")]
3072 pub senior: f64,
3073 #[serde(default = "default_manager_limit")]
3075 pub manager: f64,
3076 #[serde(default = "default_director_limit")]
3078 pub director: f64,
3079 #[serde(default = "default_vp_limit")]
3081 pub vp: f64,
3082 #[serde(default = "default_executive_limit")]
3084 pub executive: f64,
3085}
3086
3087fn default_staff_limit() -> f64 {
3088 1000.0
3089}
3090fn default_senior_limit() -> f64 {
3091 5000.0
3092}
3093fn default_manager_limit() -> f64 {
3094 25000.0
3095}
3096fn default_director_limit() -> f64 {
3097 100000.0
3098}
3099fn default_vp_limit() -> f64 {
3100 500000.0
3101}
3102fn default_executive_limit() -> f64 {
3103 f64::INFINITY
3104}
3105
3106impl Default for ApprovalLimitDistribution {
3107 fn default() -> Self {
3108 Self {
3109 staff: default_staff_limit(),
3110 senior: default_senior_limit(),
3111 manager: default_manager_limit(),
3112 director: default_director_limit(),
3113 vp: default_vp_limit(),
3114 executive: default_executive_limit(),
3115 }
3116 }
3117}
3118
3119#[derive(Debug, Clone, Serialize, Deserialize)]
3121pub struct EmployeeDepartmentDistribution {
3122 pub finance: f64,
3124 pub procurement: f64,
3126 pub sales: f64,
3128 pub warehouse: f64,
3130 pub it: f64,
3132 pub hr: f64,
3134 pub operations: f64,
3136 pub executive: f64,
3138}
3139
3140impl Default for EmployeeDepartmentDistribution {
3141 fn default() -> Self {
3142 Self {
3143 finance: 0.12,
3144 procurement: 0.10,
3145 sales: 0.25,
3146 warehouse: 0.15,
3147 it: 0.10,
3148 hr: 0.05,
3149 operations: 0.20,
3150 executive: 0.03,
3151 }
3152 }
3153}
3154
3155#[derive(Debug, Clone, Serialize, Deserialize)]
3157pub struct CostCenterMasterConfig {
3158 #[serde(default = "default_cost_center_count")]
3160 pub count: usize,
3161 #[serde(default = "default_true")]
3163 pub generate_hierarchy: bool,
3164 #[serde(default = "default_cc_hierarchy_depth")]
3166 pub max_hierarchy_depth: u8,
3167}
3168
3169fn default_cost_center_count() -> usize {
3170 50
3171}
3172
3173fn default_cc_hierarchy_depth() -> u8 {
3174 3
3175}
3176
3177impl Default for CostCenterMasterConfig {
3178 fn default() -> Self {
3179 Self {
3180 count: default_cost_center_count(),
3181 generate_hierarchy: true,
3182 max_hierarchy_depth: default_cc_hierarchy_depth(),
3183 }
3184 }
3185}
3186
3187#[derive(Debug, Clone, Serialize, Deserialize)]
3193pub struct DocumentFlowConfig {
3194 #[serde(default)]
3196 pub p2p: P2PFlowConfig,
3197 #[serde(default)]
3199 pub o2c: O2CFlowConfig,
3200 #[serde(default = "default_true")]
3202 pub generate_document_references: bool,
3203 #[serde(default)]
3205 pub export_flow_graph: bool,
3206}
3207
3208impl Default for DocumentFlowConfig {
3209 fn default() -> Self {
3210 Self {
3211 p2p: P2PFlowConfig::default(),
3212 o2c: O2CFlowConfig::default(),
3213 generate_document_references: true,
3214 export_flow_graph: false,
3215 }
3216 }
3217}
3218
3219#[derive(Debug, Clone, Serialize, Deserialize)]
3221pub struct P2PFlowConfig {
3222 #[serde(default = "default_true")]
3224 pub enabled: bool,
3225 #[serde(default = "default_three_way_match_rate")]
3227 pub three_way_match_rate: f64,
3228 #[serde(default = "default_partial_delivery_rate")]
3230 pub partial_delivery_rate: f64,
3231 #[serde(default = "default_price_variance_rate")]
3233 pub price_variance_rate: f64,
3234 #[serde(default = "default_max_price_variance")]
3236 pub max_price_variance_percent: f64,
3237 #[serde(default = "default_quantity_variance_rate")]
3239 pub quantity_variance_rate: f64,
3240 #[serde(default = "default_po_to_gr_days")]
3242 pub average_po_to_gr_days: u32,
3243 #[serde(default = "default_gr_to_invoice_days")]
3245 pub average_gr_to_invoice_days: u32,
3246 #[serde(default = "default_invoice_to_payment_days")]
3248 pub average_invoice_to_payment_days: u32,
3249 #[serde(default)]
3251 pub line_count_distribution: DocumentLineCountDistribution,
3252 #[serde(default)]
3254 pub payment_behavior: P2PPaymentBehaviorConfig,
3255 #[serde(default)]
3257 pub over_delivery_rate: Option<f64>,
3258 #[serde(default)]
3260 pub early_payment_discount_rate: Option<f64>,
3261}
3262
3263fn default_three_way_match_rate() -> f64 {
3264 0.95
3265}
3266
3267fn default_partial_delivery_rate() -> f64 {
3268 0.15
3269}
3270
3271fn default_price_variance_rate() -> f64 {
3272 0.08
3273}
3274
3275fn default_max_price_variance() -> f64 {
3276 0.05
3277}
3278
3279fn default_quantity_variance_rate() -> f64 {
3280 0.05
3281}
3282
3283fn default_po_to_gr_days() -> u32 {
3284 14
3285}
3286
3287fn default_gr_to_invoice_days() -> u32 {
3288 5
3289}
3290
3291fn default_invoice_to_payment_days() -> u32 {
3292 30
3293}
3294
3295impl Default for P2PFlowConfig {
3296 fn default() -> Self {
3297 Self {
3298 enabled: true,
3299 three_way_match_rate: default_three_way_match_rate(),
3300 partial_delivery_rate: default_partial_delivery_rate(),
3301 price_variance_rate: default_price_variance_rate(),
3302 max_price_variance_percent: default_max_price_variance(),
3303 quantity_variance_rate: default_quantity_variance_rate(),
3304 average_po_to_gr_days: default_po_to_gr_days(),
3305 average_gr_to_invoice_days: default_gr_to_invoice_days(),
3306 average_invoice_to_payment_days: default_invoice_to_payment_days(),
3307 line_count_distribution: DocumentLineCountDistribution::default(),
3308 payment_behavior: P2PPaymentBehaviorConfig::default(),
3309 over_delivery_rate: None,
3310 early_payment_discount_rate: None,
3311 }
3312 }
3313}
3314
3315#[derive(Debug, Clone, Serialize, Deserialize)]
3321pub struct P2PPaymentBehaviorConfig {
3322 #[serde(default = "default_p2p_late_payment_rate")]
3324 pub late_payment_rate: f64,
3325 #[serde(default)]
3327 pub late_payment_days_distribution: LatePaymentDaysDistribution,
3328 #[serde(default = "default_p2p_partial_payment_rate")]
3330 pub partial_payment_rate: f64,
3331 #[serde(default = "default_p2p_payment_correction_rate")]
3333 pub payment_correction_rate: f64,
3334 #[serde(default = "default_p2p_avg_days_until_remainder")]
3336 pub avg_days_until_remainder: u32,
3337}
3338
3339fn default_p2p_late_payment_rate() -> f64 {
3340 0.15
3341}
3342
3343fn default_p2p_partial_payment_rate() -> f64 {
3344 0.05
3345}
3346
3347fn default_p2p_payment_correction_rate() -> f64 {
3348 0.02
3349}
3350
3351fn default_p2p_avg_days_until_remainder() -> u32 {
3352 30
3353}
3354
3355impl Default for P2PPaymentBehaviorConfig {
3356 fn default() -> Self {
3357 Self {
3358 late_payment_rate: default_p2p_late_payment_rate(),
3359 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
3360 partial_payment_rate: default_p2p_partial_payment_rate(),
3361 payment_correction_rate: default_p2p_payment_correction_rate(),
3362 avg_days_until_remainder: default_p2p_avg_days_until_remainder(),
3363 }
3364 }
3365}
3366
3367#[derive(Debug, Clone, Serialize, Deserialize)]
3369pub struct LatePaymentDaysDistribution {
3370 #[serde(default = "default_slightly_late")]
3372 pub slightly_late_1_to_7: f64,
3373 #[serde(default = "default_late_8_14")]
3375 pub late_8_to_14: f64,
3376 #[serde(default = "default_very_late")]
3378 pub very_late_15_to_30: f64,
3379 #[serde(default = "default_severely_late")]
3381 pub severely_late_31_to_60: f64,
3382 #[serde(default = "default_extremely_late")]
3384 pub extremely_late_over_60: f64,
3385}
3386
3387fn default_slightly_late() -> f64 {
3388 0.50
3389}
3390
3391fn default_late_8_14() -> f64 {
3392 0.25
3393}
3394
3395fn default_very_late() -> f64 {
3396 0.15
3397}
3398
3399fn default_severely_late() -> f64 {
3400 0.07
3401}
3402
3403fn default_extremely_late() -> f64 {
3404 0.03
3405}
3406
3407impl Default for LatePaymentDaysDistribution {
3408 fn default() -> Self {
3409 Self {
3410 slightly_late_1_to_7: default_slightly_late(),
3411 late_8_to_14: default_late_8_14(),
3412 very_late_15_to_30: default_very_late(),
3413 severely_late_31_to_60: default_severely_late(),
3414 extremely_late_over_60: default_extremely_late(),
3415 }
3416 }
3417}
3418
3419#[derive(Debug, Clone, Serialize, Deserialize)]
3421pub struct O2CFlowConfig {
3422 #[serde(default = "default_true")]
3424 pub enabled: bool,
3425 #[serde(default = "default_credit_check_failure_rate")]
3427 pub credit_check_failure_rate: f64,
3428 #[serde(default = "default_partial_shipment_rate")]
3430 pub partial_shipment_rate: f64,
3431 #[serde(default = "default_return_rate")]
3433 pub return_rate: f64,
3434 #[serde(default = "default_bad_debt_rate")]
3436 pub bad_debt_rate: f64,
3437 #[serde(default = "default_so_to_delivery_days")]
3439 pub average_so_to_delivery_days: u32,
3440 #[serde(default = "default_delivery_to_invoice_days")]
3442 pub average_delivery_to_invoice_days: u32,
3443 #[serde(default = "default_invoice_to_receipt_days")]
3445 pub average_invoice_to_receipt_days: u32,
3446 #[serde(default)]
3448 pub line_count_distribution: DocumentLineCountDistribution,
3449 #[serde(default)]
3451 pub cash_discount: CashDiscountConfig,
3452 #[serde(default)]
3454 pub payment_behavior: O2CPaymentBehaviorConfig,
3455 #[serde(default)]
3457 pub late_payment_rate: Option<f64>,
3458}
3459
3460fn default_credit_check_failure_rate() -> f64 {
3461 0.02
3462}
3463
3464fn default_partial_shipment_rate() -> f64 {
3465 0.10
3466}
3467
3468fn default_return_rate() -> f64 {
3469 0.03
3470}
3471
3472fn default_bad_debt_rate() -> f64 {
3473 0.01
3474}
3475
3476fn default_so_to_delivery_days() -> u32 {
3477 7
3478}
3479
3480fn default_delivery_to_invoice_days() -> u32 {
3481 1
3482}
3483
3484fn default_invoice_to_receipt_days() -> u32 {
3485 45
3486}
3487
3488impl Default for O2CFlowConfig {
3489 fn default() -> Self {
3490 Self {
3491 enabled: true,
3492 credit_check_failure_rate: default_credit_check_failure_rate(),
3493 partial_shipment_rate: default_partial_shipment_rate(),
3494 return_rate: default_return_rate(),
3495 bad_debt_rate: default_bad_debt_rate(),
3496 average_so_to_delivery_days: default_so_to_delivery_days(),
3497 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
3498 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
3499 line_count_distribution: DocumentLineCountDistribution::default(),
3500 cash_discount: CashDiscountConfig::default(),
3501 payment_behavior: O2CPaymentBehaviorConfig::default(),
3502 late_payment_rate: None,
3503 }
3504 }
3505}
3506
3507#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3513pub struct O2CPaymentBehaviorConfig {
3514 #[serde(default)]
3516 pub dunning: DunningConfig,
3517 #[serde(default)]
3519 pub partial_payments: PartialPaymentConfig,
3520 #[serde(default)]
3522 pub short_payments: ShortPaymentConfig,
3523 #[serde(default)]
3525 pub on_account_payments: OnAccountPaymentConfig,
3526 #[serde(default)]
3528 pub payment_corrections: PaymentCorrectionConfig,
3529}
3530
3531#[derive(Debug, Clone, Serialize, Deserialize)]
3533pub struct DunningConfig {
3534 #[serde(default)]
3536 pub enabled: bool,
3537 #[serde(default = "default_dunning_level_1_days")]
3539 pub level_1_days_overdue: u32,
3540 #[serde(default = "default_dunning_level_2_days")]
3542 pub level_2_days_overdue: u32,
3543 #[serde(default = "default_dunning_level_3_days")]
3545 pub level_3_days_overdue: u32,
3546 #[serde(default = "default_collection_days")]
3548 pub collection_days_overdue: u32,
3549 #[serde(default)]
3551 pub payment_after_dunning_rates: DunningPaymentRates,
3552 #[serde(default = "default_dunning_block_rate")]
3554 pub dunning_block_rate: f64,
3555 #[serde(default = "default_dunning_interest_rate")]
3557 pub interest_rate_per_year: f64,
3558 #[serde(default = "default_dunning_charge")]
3560 pub dunning_charge: f64,
3561}
3562
3563fn default_dunning_level_1_days() -> u32 {
3564 14
3565}
3566
3567fn default_dunning_level_2_days() -> u32 {
3568 28
3569}
3570
3571fn default_dunning_level_3_days() -> u32 {
3572 42
3573}
3574
3575fn default_collection_days() -> u32 {
3576 60
3577}
3578
3579fn default_dunning_block_rate() -> f64 {
3580 0.05
3581}
3582
3583fn default_dunning_interest_rate() -> f64 {
3584 0.09
3585}
3586
3587fn default_dunning_charge() -> f64 {
3588 25.0
3589}
3590
3591impl Default for DunningConfig {
3592 fn default() -> Self {
3593 Self {
3594 enabled: false,
3595 level_1_days_overdue: default_dunning_level_1_days(),
3596 level_2_days_overdue: default_dunning_level_2_days(),
3597 level_3_days_overdue: default_dunning_level_3_days(),
3598 collection_days_overdue: default_collection_days(),
3599 payment_after_dunning_rates: DunningPaymentRates::default(),
3600 dunning_block_rate: default_dunning_block_rate(),
3601 interest_rate_per_year: default_dunning_interest_rate(),
3602 dunning_charge: default_dunning_charge(),
3603 }
3604 }
3605}
3606
3607#[derive(Debug, Clone, Serialize, Deserialize)]
3609pub struct DunningPaymentRates {
3610 #[serde(default = "default_after_level_1")]
3612 pub after_level_1: f64,
3613 #[serde(default = "default_after_level_2")]
3615 pub after_level_2: f64,
3616 #[serde(default = "default_after_level_3")]
3618 pub after_level_3: f64,
3619 #[serde(default = "default_during_collection")]
3621 pub during_collection: f64,
3622 #[serde(default = "default_never_pay")]
3624 pub never_pay: f64,
3625}
3626
3627fn default_after_level_1() -> f64 {
3628 0.40
3629}
3630
3631fn default_after_level_2() -> f64 {
3632 0.30
3633}
3634
3635fn default_after_level_3() -> f64 {
3636 0.15
3637}
3638
3639fn default_during_collection() -> f64 {
3640 0.05
3641}
3642
3643fn default_never_pay() -> f64 {
3644 0.10
3645}
3646
3647impl Default for DunningPaymentRates {
3648 fn default() -> Self {
3649 Self {
3650 after_level_1: default_after_level_1(),
3651 after_level_2: default_after_level_2(),
3652 after_level_3: default_after_level_3(),
3653 during_collection: default_during_collection(),
3654 never_pay: default_never_pay(),
3655 }
3656 }
3657}
3658
3659#[derive(Debug, Clone, Serialize, Deserialize)]
3661pub struct PartialPaymentConfig {
3662 #[serde(default = "default_partial_payment_rate")]
3664 pub rate: f64,
3665 #[serde(default)]
3667 pub percentage_distribution: PartialPaymentPercentageDistribution,
3668 #[serde(default = "default_avg_days_until_remainder")]
3670 pub avg_days_until_remainder: u32,
3671}
3672
3673fn default_partial_payment_rate() -> f64 {
3674 0.08
3675}
3676
3677fn default_avg_days_until_remainder() -> u32 {
3678 30
3679}
3680
3681impl Default for PartialPaymentConfig {
3682 fn default() -> Self {
3683 Self {
3684 rate: default_partial_payment_rate(),
3685 percentage_distribution: PartialPaymentPercentageDistribution::default(),
3686 avg_days_until_remainder: default_avg_days_until_remainder(),
3687 }
3688 }
3689}
3690
3691#[derive(Debug, Clone, Serialize, Deserialize)]
3693pub struct PartialPaymentPercentageDistribution {
3694 #[serde(default = "default_partial_25")]
3696 pub pay_25_percent: f64,
3697 #[serde(default = "default_partial_50")]
3699 pub pay_50_percent: f64,
3700 #[serde(default = "default_partial_75")]
3702 pub pay_75_percent: f64,
3703 #[serde(default = "default_partial_random")]
3705 pub pay_random_percent: f64,
3706}
3707
3708fn default_partial_25() -> f64 {
3709 0.15
3710}
3711
3712fn default_partial_50() -> f64 {
3713 0.50
3714}
3715
3716fn default_partial_75() -> f64 {
3717 0.25
3718}
3719
3720fn default_partial_random() -> f64 {
3721 0.10
3722}
3723
3724impl Default for PartialPaymentPercentageDistribution {
3725 fn default() -> Self {
3726 Self {
3727 pay_25_percent: default_partial_25(),
3728 pay_50_percent: default_partial_50(),
3729 pay_75_percent: default_partial_75(),
3730 pay_random_percent: default_partial_random(),
3731 }
3732 }
3733}
3734
3735#[derive(Debug, Clone, Serialize, Deserialize)]
3737pub struct ShortPaymentConfig {
3738 #[serde(default = "default_short_payment_rate")]
3740 pub rate: f64,
3741 #[serde(default)]
3743 pub reason_distribution: ShortPaymentReasonDistribution,
3744 #[serde(default = "default_max_short_percent")]
3746 pub max_short_percent: f64,
3747}
3748
3749fn default_short_payment_rate() -> f64 {
3750 0.03
3751}
3752
3753fn default_max_short_percent() -> f64 {
3754 0.10
3755}
3756
3757impl Default for ShortPaymentConfig {
3758 fn default() -> Self {
3759 Self {
3760 rate: default_short_payment_rate(),
3761 reason_distribution: ShortPaymentReasonDistribution::default(),
3762 max_short_percent: default_max_short_percent(),
3763 }
3764 }
3765}
3766
3767#[derive(Debug, Clone, Serialize, Deserialize)]
3769pub struct ShortPaymentReasonDistribution {
3770 #[serde(default = "default_pricing_dispute")]
3772 pub pricing_dispute: f64,
3773 #[serde(default = "default_quality_issue")]
3775 pub quality_issue: f64,
3776 #[serde(default = "default_quantity_discrepancy")]
3778 pub quantity_discrepancy: f64,
3779 #[serde(default = "default_unauthorized_deduction")]
3781 pub unauthorized_deduction: f64,
3782 #[serde(default = "default_incorrect_discount")]
3784 pub incorrect_discount: f64,
3785}
3786
3787fn default_pricing_dispute() -> f64 {
3788 0.30
3789}
3790
3791fn default_quality_issue() -> f64 {
3792 0.20
3793}
3794
3795fn default_quantity_discrepancy() -> f64 {
3796 0.20
3797}
3798
3799fn default_unauthorized_deduction() -> f64 {
3800 0.15
3801}
3802
3803fn default_incorrect_discount() -> f64 {
3804 0.15
3805}
3806
3807impl Default for ShortPaymentReasonDistribution {
3808 fn default() -> Self {
3809 Self {
3810 pricing_dispute: default_pricing_dispute(),
3811 quality_issue: default_quality_issue(),
3812 quantity_discrepancy: default_quantity_discrepancy(),
3813 unauthorized_deduction: default_unauthorized_deduction(),
3814 incorrect_discount: default_incorrect_discount(),
3815 }
3816 }
3817}
3818
3819#[derive(Debug, Clone, Serialize, Deserialize)]
3821pub struct OnAccountPaymentConfig {
3822 #[serde(default = "default_on_account_rate")]
3824 pub rate: f64,
3825 #[serde(default = "default_avg_days_until_applied")]
3827 pub avg_days_until_applied: u32,
3828}
3829
3830fn default_on_account_rate() -> f64 {
3831 0.02
3832}
3833
3834fn default_avg_days_until_applied() -> u32 {
3835 14
3836}
3837
3838impl Default for OnAccountPaymentConfig {
3839 fn default() -> Self {
3840 Self {
3841 rate: default_on_account_rate(),
3842 avg_days_until_applied: default_avg_days_until_applied(),
3843 }
3844 }
3845}
3846
3847#[derive(Debug, Clone, Serialize, Deserialize)]
3849pub struct PaymentCorrectionConfig {
3850 #[serde(default = "default_payment_correction_rate")]
3852 pub rate: f64,
3853 #[serde(default)]
3855 pub type_distribution: PaymentCorrectionTypeDistribution,
3856}
3857
3858fn default_payment_correction_rate() -> f64 {
3859 0.02
3860}
3861
3862impl Default for PaymentCorrectionConfig {
3863 fn default() -> Self {
3864 Self {
3865 rate: default_payment_correction_rate(),
3866 type_distribution: PaymentCorrectionTypeDistribution::default(),
3867 }
3868 }
3869}
3870
3871#[derive(Debug, Clone, Serialize, Deserialize)]
3873pub struct PaymentCorrectionTypeDistribution {
3874 #[serde(default = "default_nsf_rate")]
3876 pub nsf: f64,
3877 #[serde(default = "default_chargeback_rate")]
3879 pub chargeback: f64,
3880 #[serde(default = "default_wrong_amount_rate")]
3882 pub wrong_amount: f64,
3883 #[serde(default = "default_wrong_customer_rate")]
3885 pub wrong_customer: f64,
3886 #[serde(default = "default_duplicate_payment_rate")]
3888 pub duplicate_payment: f64,
3889}
3890
3891fn default_nsf_rate() -> f64 {
3892 0.30
3893}
3894
3895fn default_chargeback_rate() -> f64 {
3896 0.20
3897}
3898
3899fn default_wrong_amount_rate() -> f64 {
3900 0.20
3901}
3902
3903fn default_wrong_customer_rate() -> f64 {
3904 0.15
3905}
3906
3907fn default_duplicate_payment_rate() -> f64 {
3908 0.15
3909}
3910
3911impl Default for PaymentCorrectionTypeDistribution {
3912 fn default() -> Self {
3913 Self {
3914 nsf: default_nsf_rate(),
3915 chargeback: default_chargeback_rate(),
3916 wrong_amount: default_wrong_amount_rate(),
3917 wrong_customer: default_wrong_customer_rate(),
3918 duplicate_payment: default_duplicate_payment_rate(),
3919 }
3920 }
3921}
3922
3923#[derive(Debug, Clone, Serialize, Deserialize)]
3925pub struct DocumentLineCountDistribution {
3926 #[serde(default = "default_min_lines")]
3928 pub min_lines: u32,
3929 #[serde(default = "default_max_lines")]
3931 pub max_lines: u32,
3932 #[serde(default = "default_mode_lines")]
3934 pub mode_lines: u32,
3935}
3936
3937fn default_min_lines() -> u32 {
3938 1
3939}
3940
3941fn default_max_lines() -> u32 {
3942 20
3943}
3944
3945fn default_mode_lines() -> u32 {
3946 3
3947}
3948
3949impl Default for DocumentLineCountDistribution {
3950 fn default() -> Self {
3951 Self {
3952 min_lines: default_min_lines(),
3953 max_lines: default_max_lines(),
3954 mode_lines: default_mode_lines(),
3955 }
3956 }
3957}
3958
3959#[derive(Debug, Clone, Serialize, Deserialize)]
3961pub struct CashDiscountConfig {
3962 #[serde(default = "default_discount_eligible_rate")]
3964 pub eligible_rate: f64,
3965 #[serde(default = "default_discount_taken_rate")]
3967 pub taken_rate: f64,
3968 #[serde(default = "default_discount_percent")]
3970 pub discount_percent: f64,
3971 #[serde(default = "default_discount_days")]
3973 pub discount_days: u32,
3974}
3975
3976fn default_discount_eligible_rate() -> f64 {
3977 0.30
3978}
3979
3980fn default_discount_taken_rate() -> f64 {
3981 0.60
3982}
3983
3984fn default_discount_percent() -> f64 {
3985 0.02
3986}
3987
3988fn default_discount_days() -> u32 {
3989 10
3990}
3991
3992impl Default for CashDiscountConfig {
3993 fn default() -> Self {
3994 Self {
3995 eligible_rate: default_discount_eligible_rate(),
3996 taken_rate: default_discount_taken_rate(),
3997 discount_percent: default_discount_percent(),
3998 discount_days: default_discount_days(),
3999 }
4000 }
4001}
4002
4003#[derive(Debug, Clone, Serialize, Deserialize)]
4009pub struct IntercompanyConfig {
4010 #[serde(default)]
4012 pub enabled: bool,
4013 #[serde(default = "default_ic_transaction_rate")]
4015 pub ic_transaction_rate: f64,
4016 #[serde(default)]
4018 pub transfer_pricing_method: TransferPricingMethod,
4019 #[serde(default = "default_markup_percent")]
4021 pub markup_percent: f64,
4022 #[serde(default = "default_true")]
4024 pub generate_matched_pairs: bool,
4025 #[serde(default)]
4027 pub transaction_type_distribution: ICTransactionTypeDistribution,
4028 #[serde(default)]
4030 pub generate_eliminations: bool,
4031}
4032
4033fn default_ic_transaction_rate() -> f64 {
4034 0.15
4035}
4036
4037fn default_markup_percent() -> f64 {
4038 0.05
4039}
4040
4041impl Default for IntercompanyConfig {
4042 fn default() -> Self {
4043 Self {
4044 enabled: false,
4045 ic_transaction_rate: default_ic_transaction_rate(),
4046 transfer_pricing_method: TransferPricingMethod::default(),
4047 markup_percent: default_markup_percent(),
4048 generate_matched_pairs: true,
4049 transaction_type_distribution: ICTransactionTypeDistribution::default(),
4050 generate_eliminations: false,
4051 }
4052 }
4053}
4054
4055#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
4057#[serde(rename_all = "snake_case")]
4058pub enum TransferPricingMethod {
4059 #[default]
4061 CostPlus,
4062 ComparableUncontrolled,
4064 ResalePrice,
4066 TransactionalNetMargin,
4068 ProfitSplit,
4070}
4071
4072#[derive(Debug, Clone, Serialize, Deserialize)]
4074pub struct ICTransactionTypeDistribution {
4075 pub goods_sale: f64,
4077 pub service_provided: f64,
4079 pub loan: f64,
4081 pub dividend: f64,
4083 pub management_fee: f64,
4085 pub royalty: f64,
4087 pub cost_sharing: f64,
4089}
4090
4091impl Default for ICTransactionTypeDistribution {
4092 fn default() -> Self {
4093 Self {
4094 goods_sale: 0.35,
4095 service_provided: 0.20,
4096 loan: 0.10,
4097 dividend: 0.05,
4098 management_fee: 0.15,
4099 royalty: 0.10,
4100 cost_sharing: 0.05,
4101 }
4102 }
4103}
4104
4105#[derive(Debug, Clone, Serialize, Deserialize)]
4111pub struct BalanceConfig {
4112 #[serde(default)]
4114 pub generate_opening_balances: bool,
4115 #[serde(default = "default_true")]
4117 pub generate_trial_balances: bool,
4118 #[serde(default = "default_gross_margin")]
4120 pub target_gross_margin: f64,
4121 #[serde(default = "default_dso")]
4123 pub target_dso_days: u32,
4124 #[serde(default = "default_dpo")]
4126 pub target_dpo_days: u32,
4127 #[serde(default = "default_current_ratio")]
4129 pub target_current_ratio: f64,
4130 #[serde(default = "default_debt_equity")]
4132 pub target_debt_to_equity: f64,
4133 #[serde(default = "default_true")]
4135 pub validate_balance_equation: bool,
4136 #[serde(default = "default_true")]
4138 pub reconcile_subledgers: bool,
4139}
4140
4141fn default_gross_margin() -> f64 {
4142 0.35
4143}
4144
4145fn default_dso() -> u32 {
4146 45
4147}
4148
4149fn default_dpo() -> u32 {
4150 30
4151}
4152
4153fn default_current_ratio() -> f64 {
4154 1.5
4155}
4156
4157fn default_debt_equity() -> f64 {
4158 0.5
4159}
4160
4161impl Default for BalanceConfig {
4162 fn default() -> Self {
4163 Self {
4164 generate_opening_balances: false,
4165 generate_trial_balances: true,
4166 target_gross_margin: default_gross_margin(),
4167 target_dso_days: default_dso(),
4168 target_dpo_days: default_dpo(),
4169 target_current_ratio: default_current_ratio(),
4170 target_debt_to_equity: default_debt_equity(),
4171 validate_balance_equation: true,
4172 reconcile_subledgers: true,
4173 }
4174 }
4175}
4176
4177#[derive(Debug, Clone, Serialize, Deserialize)]
4186pub struct OcpmConfig {
4187 #[serde(default)]
4189 pub enabled: bool,
4190
4191 #[serde(default = "default_true")]
4193 pub generate_lifecycle_events: bool,
4194
4195 #[serde(default = "default_true")]
4197 pub include_object_relationships: bool,
4198
4199 #[serde(default = "default_true")]
4201 pub compute_variants: bool,
4202
4203 #[serde(default)]
4205 pub max_variants: usize,
4206
4207 #[serde(default)]
4209 pub p2p_process: OcpmProcessConfig,
4210
4211 #[serde(default)]
4213 pub o2c_process: OcpmProcessConfig,
4214
4215 #[serde(default)]
4217 pub output: OcpmOutputConfig,
4218}
4219
4220impl Default for OcpmConfig {
4221 fn default() -> Self {
4222 Self {
4223 enabled: false,
4224 generate_lifecycle_events: true,
4225 include_object_relationships: true,
4226 compute_variants: true,
4227 max_variants: 0,
4228 p2p_process: OcpmProcessConfig::default(),
4229 o2c_process: OcpmProcessConfig::default(),
4230 output: OcpmOutputConfig::default(),
4231 }
4232 }
4233}
4234
4235#[derive(Debug, Clone, Serialize, Deserialize)]
4237pub struct OcpmProcessConfig {
4238 #[serde(default = "default_rework_probability")]
4240 pub rework_probability: f64,
4241
4242 #[serde(default = "default_skip_probability")]
4244 pub skip_step_probability: f64,
4245
4246 #[serde(default = "default_out_of_order_probability")]
4248 pub out_of_order_probability: f64,
4249}
4250
4251fn default_rework_probability() -> f64 {
4255 0.15
4256}
4257
4258fn default_skip_probability() -> f64 {
4259 0.10
4260}
4261
4262fn default_out_of_order_probability() -> f64 {
4263 0.08
4264}
4265
4266impl Default for OcpmProcessConfig {
4267 fn default() -> Self {
4268 Self {
4269 rework_probability: default_rework_probability(),
4270 skip_step_probability: default_skip_probability(),
4271 out_of_order_probability: default_out_of_order_probability(),
4272 }
4273 }
4274}
4275
4276#[derive(Debug, Clone, Serialize, Deserialize)]
4278pub struct OcpmOutputConfig {
4279 #[serde(default = "default_true")]
4281 pub ocel_json: bool,
4282
4283 #[serde(default)]
4285 pub ocel_xml: bool,
4286
4287 #[serde(default)]
4289 pub xes: bool,
4290
4291 #[serde(default = "default_true")]
4293 pub xes_include_lifecycle: bool,
4294
4295 #[serde(default = "default_true")]
4297 pub xes_include_resources: bool,
4298
4299 #[serde(default = "default_true")]
4301 pub flattened_csv: bool,
4302
4303 #[serde(default = "default_true")]
4305 pub event_object_csv: bool,
4306
4307 #[serde(default = "default_true")]
4309 pub object_relationship_csv: bool,
4310
4311 #[serde(default = "default_true")]
4313 pub variants_csv: bool,
4314
4315 #[serde(default)]
4317 pub export_reference_models: bool,
4318}
4319
4320impl Default for OcpmOutputConfig {
4321 fn default() -> Self {
4322 Self {
4323 ocel_json: true,
4324 ocel_xml: false,
4325 xes: false,
4326 xes_include_lifecycle: true,
4327 xes_include_resources: true,
4328 flattened_csv: true,
4329 event_object_csv: true,
4330 object_relationship_csv: true,
4331 variants_csv: true,
4332 export_reference_models: false,
4333 }
4334 }
4335}
4336
4337#[derive(Debug, Clone, Serialize, Deserialize)]
4339pub struct AuditGenerationConfig {
4340 #[serde(default)]
4342 pub enabled: bool,
4343
4344 #[serde(default = "default_true")]
4348 pub generate_workpapers: bool,
4349
4350 #[serde(default)]
4353 pub engagement_types: AuditEngagementTypesConfig,
4354
4355 #[serde(default)]
4360 pub workpapers: WorkpaperConfig,
4361
4362 #[serde(default)]
4368 pub team: AuditTeamConfig,
4369
4370 #[serde(default)]
4377 pub review: ReviewWorkflowConfig,
4378
4379 #[serde(default)]
4381 pub fsm: Option<AuditFsmConfig>,
4382
4383 #[serde(default)]
4389 pub it_controls: ItControlsConfig,
4390}
4391
4392#[derive(Debug, Clone, Serialize, Deserialize)]
4394pub struct ItControlsConfig {
4395 #[serde(default)]
4398 pub enabled: bool,
4399 #[serde(default = "default_access_log_count")]
4402 pub access_logs_per_engagement: usize,
4403 #[serde(default = "default_change_record_count")]
4405 pub change_records_per_engagement: usize,
4406}
4407
4408fn default_access_log_count() -> usize {
4409 500
4410}
4411fn default_change_record_count() -> usize {
4412 50
4413}
4414
4415impl Default for ItControlsConfig {
4416 fn default() -> Self {
4417 Self {
4418 enabled: false,
4419 access_logs_per_engagement: default_access_log_count(),
4420 change_records_per_engagement: default_change_record_count(),
4421 }
4422 }
4423}
4424
4425impl Default for AuditGenerationConfig {
4426 fn default() -> Self {
4427 Self {
4428 enabled: false,
4429 generate_workpapers: true,
4430 engagement_types: AuditEngagementTypesConfig::default(),
4431 workpapers: WorkpaperConfig::default(),
4432 team: AuditTeamConfig::default(),
4433 review: ReviewWorkflowConfig::default(),
4434 fsm: None,
4435 it_controls: ItControlsConfig::default(),
4436 }
4437 }
4438}
4439
4440#[derive(Debug, Clone, Serialize, Deserialize)]
4442pub struct AuditFsmConfig {
4443 #[serde(default)]
4445 pub enabled: bool,
4446
4447 #[serde(default = "default_audit_fsm_blueprint")]
4449 pub blueprint: String,
4450
4451 #[serde(default = "default_audit_fsm_overlay")]
4453 pub overlay: String,
4454
4455 #[serde(default)]
4457 pub depth: Option<String>,
4458
4459 #[serde(default)]
4461 pub discriminators: std::collections::HashMap<String, Vec<String>>,
4462
4463 #[serde(default)]
4465 pub event_trail: AuditEventTrailConfig,
4466
4467 #[serde(default)]
4469 pub seed: Option<u64>,
4470}
4471
4472impl Default for AuditFsmConfig {
4473 fn default() -> Self {
4474 Self {
4475 enabled: false,
4476 blueprint: default_audit_fsm_blueprint(),
4477 overlay: default_audit_fsm_overlay(),
4478 depth: None,
4479 discriminators: std::collections::HashMap::new(),
4480 event_trail: AuditEventTrailConfig::default(),
4481 seed: None,
4482 }
4483 }
4484}
4485
4486fn default_audit_fsm_blueprint() -> String {
4487 "builtin:fsa".to_string()
4488}
4489
4490fn default_audit_fsm_overlay() -> String {
4491 "builtin:default".to_string()
4492}
4493
4494#[derive(Debug, Clone, Serialize, Deserialize)]
4496pub struct AuditEventTrailConfig {
4497 #[serde(default = "default_true")]
4499 pub flat_log: bool,
4500 #[serde(default)]
4502 pub ocel_projection: bool,
4503}
4504
4505impl Default for AuditEventTrailConfig {
4506 fn default() -> Self {
4507 Self {
4508 flat_log: true,
4509 ocel_projection: false,
4510 }
4511 }
4512}
4513
4514#[derive(Debug, Clone, Serialize, Deserialize)]
4516pub struct AuditEngagementTypesConfig {
4517 #[serde(default = "default_financial_audit_prob")]
4519 pub financial_statement: f64,
4520 #[serde(default = "default_sox_audit_prob")]
4522 pub sox_icfr: f64,
4523 #[serde(default = "default_integrated_audit_prob")]
4525 pub integrated: f64,
4526 #[serde(default = "default_review_prob")]
4528 pub review: f64,
4529 #[serde(default = "default_aup_prob")]
4531 pub agreed_upon_procedures: f64,
4532}
4533
4534fn default_financial_audit_prob() -> f64 {
4535 0.40
4536}
4537fn default_sox_audit_prob() -> f64 {
4538 0.20
4539}
4540fn default_integrated_audit_prob() -> f64 {
4541 0.25
4542}
4543fn default_review_prob() -> f64 {
4544 0.10
4545}
4546fn default_aup_prob() -> f64 {
4547 0.05
4548}
4549
4550impl Default for AuditEngagementTypesConfig {
4551 fn default() -> Self {
4552 Self {
4553 financial_statement: default_financial_audit_prob(),
4554 sox_icfr: default_sox_audit_prob(),
4555 integrated: default_integrated_audit_prob(),
4556 review: default_review_prob(),
4557 agreed_upon_procedures: default_aup_prob(),
4558 }
4559 }
4560}
4561
4562#[derive(Debug, Clone, Serialize, Deserialize)]
4564pub struct WorkpaperConfig {
4565 #[serde(default = "default_workpapers_per_phase")]
4567 pub average_per_phase: usize,
4568
4569 #[serde(default = "default_true")]
4571 pub include_isa_references: bool,
4572
4573 #[serde(default = "default_true")]
4575 pub include_sample_details: bool,
4576
4577 #[serde(default = "default_true")]
4579 pub include_cross_references: bool,
4580
4581 #[serde(default)]
4583 pub sampling: SamplingConfig,
4584}
4585
4586fn default_workpapers_per_phase() -> usize {
4587 5
4588}
4589
4590impl Default for WorkpaperConfig {
4591 fn default() -> Self {
4592 Self {
4593 average_per_phase: default_workpapers_per_phase(),
4594 include_isa_references: true,
4595 include_sample_details: true,
4596 include_cross_references: true,
4597 sampling: SamplingConfig::default(),
4598 }
4599 }
4600}
4601
4602#[derive(Debug, Clone, Serialize, Deserialize)]
4604pub struct SamplingConfig {
4605 #[serde(default = "default_statistical_rate")]
4607 pub statistical_rate: f64,
4608 #[serde(default = "default_judgmental_rate")]
4610 pub judgmental_rate: f64,
4611 #[serde(default = "default_haphazard_rate")]
4613 pub haphazard_rate: f64,
4614 #[serde(default = "default_complete_examination_rate")]
4616 pub complete_examination_rate: f64,
4617}
4618
4619fn default_statistical_rate() -> f64 {
4620 0.40
4621}
4622fn default_judgmental_rate() -> f64 {
4623 0.30
4624}
4625fn default_haphazard_rate() -> f64 {
4626 0.20
4627}
4628fn default_complete_examination_rate() -> f64 {
4629 0.10
4630}
4631
4632impl Default for SamplingConfig {
4633 fn default() -> Self {
4634 Self {
4635 statistical_rate: default_statistical_rate(),
4636 judgmental_rate: default_judgmental_rate(),
4637 haphazard_rate: default_haphazard_rate(),
4638 complete_examination_rate: default_complete_examination_rate(),
4639 }
4640 }
4641}
4642
4643#[derive(Debug, Clone, Serialize, Deserialize)]
4645pub struct AuditTeamConfig {
4646 #[serde(default = "default_min_team_size")]
4648 pub min_team_size: usize,
4649 #[serde(default = "default_max_team_size")]
4651 pub max_team_size: usize,
4652 #[serde(default = "default_specialist_probability")]
4654 pub specialist_probability: f64,
4655}
4656
4657fn default_min_team_size() -> usize {
4658 3
4659}
4660fn default_max_team_size() -> usize {
4661 8
4662}
4663fn default_specialist_probability() -> f64 {
4664 0.30
4665}
4666
4667impl Default for AuditTeamConfig {
4668 fn default() -> Self {
4669 Self {
4670 min_team_size: default_min_team_size(),
4671 max_team_size: default_max_team_size(),
4672 specialist_probability: default_specialist_probability(),
4673 }
4674 }
4675}
4676
4677#[derive(Debug, Clone, Serialize, Deserialize)]
4679pub struct ReviewWorkflowConfig {
4680 #[serde(default = "default_review_delay_days")]
4682 pub average_review_delay_days: u32,
4683 #[serde(default = "default_rework_probability_review")]
4685 pub rework_probability: f64,
4686 #[serde(default = "default_true")]
4688 pub require_partner_signoff: bool,
4689}
4690
4691fn default_review_delay_days() -> u32 {
4692 2
4693}
4694fn default_rework_probability_review() -> f64 {
4695 0.15
4696}
4697
4698impl Default for ReviewWorkflowConfig {
4699 fn default() -> Self {
4700 Self {
4701 average_review_delay_days: default_review_delay_days(),
4702 rework_probability: default_rework_probability_review(),
4703 require_partner_signoff: true,
4704 }
4705 }
4706}
4707
4708#[derive(Debug, Clone, Serialize, Deserialize)]
4714pub struct DataQualitySchemaConfig {
4715 #[serde(default)]
4717 pub enabled: bool,
4718 #[serde(default)]
4720 pub preset: DataQualityPreset,
4721 #[serde(default)]
4723 pub missing_values: MissingValuesSchemaConfig,
4724 #[serde(default)]
4726 pub typos: TypoSchemaConfig,
4727 #[serde(default)]
4729 pub format_variations: FormatVariationSchemaConfig,
4730 #[serde(default)]
4732 pub duplicates: DuplicateSchemaConfig,
4733 #[serde(default)]
4735 pub encoding_issues: EncodingIssueSchemaConfig,
4736 #[serde(default)]
4738 pub generate_labels: bool,
4739 #[serde(default)]
4741 pub sink_profiles: SinkQualityProfiles,
4742}
4743
4744impl Default for DataQualitySchemaConfig {
4745 fn default() -> Self {
4746 Self {
4747 enabled: false,
4748 preset: DataQualityPreset::None,
4749 missing_values: MissingValuesSchemaConfig::default(),
4750 typos: TypoSchemaConfig::default(),
4751 format_variations: FormatVariationSchemaConfig::default(),
4752 duplicates: DuplicateSchemaConfig::default(),
4753 encoding_issues: EncodingIssueSchemaConfig::default(),
4754 generate_labels: true,
4755 sink_profiles: SinkQualityProfiles::default(),
4756 }
4757 }
4758}
4759
4760impl DataQualitySchemaConfig {
4761 pub fn with_preset(preset: DataQualityPreset) -> Self {
4763 let mut config = Self {
4764 preset,
4765 ..Default::default()
4766 };
4767 config.apply_preset();
4768 config
4769 }
4770
4771 pub fn apply_preset(&mut self) {
4774 if !self.preset.overrides_settings() {
4775 return;
4776 }
4777
4778 self.enabled = true;
4779
4780 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4782 self.missing_values.rate = self.preset.missing_rate();
4783
4784 self.typos.enabled = self.preset.typo_rate() > 0.0;
4786 self.typos.char_error_rate = self.preset.typo_rate();
4787
4788 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4790 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4791 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4792 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4793
4794 self.format_variations.enabled = self.preset.format_variations_enabled();
4796
4797 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4799 self.encoding_issues.rate = self.preset.encoding_issue_rate();
4800
4801 if self.preset.ocr_errors_enabled() {
4803 self.typos.type_weights.ocr_errors = 0.3;
4804 }
4805 }
4806
4807 pub fn effective_missing_rate(&self) -> f64 {
4809 if self.preset.overrides_settings() {
4810 self.preset.missing_rate()
4811 } else {
4812 self.missing_values.rate
4813 }
4814 }
4815
4816 pub fn effective_typo_rate(&self) -> f64 {
4818 if self.preset.overrides_settings() {
4819 self.preset.typo_rate()
4820 } else {
4821 self.typos.char_error_rate
4822 }
4823 }
4824
4825 pub fn effective_duplicate_rate(&self) -> f64 {
4827 if self.preset.overrides_settings() {
4828 self.preset.duplicate_rate()
4829 } else {
4830 self.duplicates.exact_duplicate_ratio
4831 + self.duplicates.near_duplicate_ratio
4832 + self.duplicates.fuzzy_duplicate_ratio
4833 }
4834 }
4835
4836 pub fn clean() -> Self {
4838 Self::with_preset(DataQualityPreset::Clean)
4839 }
4840
4841 pub fn noisy() -> Self {
4843 Self::with_preset(DataQualityPreset::Noisy)
4844 }
4845
4846 pub fn legacy() -> Self {
4848 Self::with_preset(DataQualityPreset::Legacy)
4849 }
4850}
4851
4852#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4854#[serde(rename_all = "snake_case")]
4855pub enum DataQualityPreset {
4856 #[default]
4858 None,
4859 Minimal,
4861 Normal,
4863 High,
4865 Custom,
4867
4868 Clean,
4874 Noisy,
4877 Legacy,
4880}
4881
4882impl DataQualityPreset {
4883 pub fn missing_rate(&self) -> f64 {
4885 match self {
4886 DataQualityPreset::None => 0.0,
4887 DataQualityPreset::Minimal => 0.005,
4888 DataQualityPreset::Normal => 0.02,
4889 DataQualityPreset::High => 0.08,
4890 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
4892 DataQualityPreset::Noisy => 0.05,
4893 DataQualityPreset::Legacy => 0.10,
4894 }
4895 }
4896
4897 pub fn typo_rate(&self) -> f64 {
4899 match self {
4900 DataQualityPreset::None => 0.0,
4901 DataQualityPreset::Minimal => 0.0005,
4902 DataQualityPreset::Normal => 0.002,
4903 DataQualityPreset::High => 0.01,
4904 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
4906 DataQualityPreset::Noisy => 0.02,
4907 DataQualityPreset::Legacy => 0.05,
4908 }
4909 }
4910
4911 pub fn duplicate_rate(&self) -> f64 {
4913 match self {
4914 DataQualityPreset::None => 0.0,
4915 DataQualityPreset::Minimal => 0.001,
4916 DataQualityPreset::Normal => 0.005,
4917 DataQualityPreset::High => 0.02,
4918 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
4920 DataQualityPreset::Noisy => 0.01,
4921 DataQualityPreset::Legacy => 0.03,
4922 }
4923 }
4924
4925 pub fn format_variations_enabled(&self) -> bool {
4927 match self {
4928 DataQualityPreset::None | DataQualityPreset::Clean => false,
4929 DataQualityPreset::Minimal => true,
4930 DataQualityPreset::Normal => true,
4931 DataQualityPreset::High => true,
4932 DataQualityPreset::Custom => true,
4933 DataQualityPreset::Noisy => true,
4934 DataQualityPreset::Legacy => true,
4935 }
4936 }
4937
4938 pub fn ocr_errors_enabled(&self) -> bool {
4940 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4941 }
4942
4943 pub fn encoding_issues_enabled(&self) -> bool {
4945 matches!(
4946 self,
4947 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4948 )
4949 }
4950
4951 pub fn encoding_issue_rate(&self) -> f64 {
4953 match self {
4954 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4955 DataQualityPreset::Normal => 0.002,
4956 DataQualityPreset::High => 0.01,
4957 DataQualityPreset::Custom => 0.0,
4958 DataQualityPreset::Noisy => 0.005,
4959 DataQualityPreset::Legacy => 0.02,
4960 }
4961 }
4962
4963 pub fn overrides_settings(&self) -> bool {
4965 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4966 }
4967
4968 pub fn description(&self) -> &'static str {
4970 match self {
4971 DataQualityPreset::None => "No data quality issues (pristine data)",
4972 DataQualityPreset::Minimal => "Very rare data quality issues",
4973 DataQualityPreset::Normal => "Realistic enterprise data quality",
4974 DataQualityPreset::High => "Messy data for stress testing",
4975 DataQualityPreset::Custom => "Custom settings from configuration",
4976 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4977 DataQualityPreset::Noisy => "Typical production data with moderate issues",
4978 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4979 }
4980 }
4981}
4982
4983#[derive(Debug, Clone, Serialize, Deserialize)]
4985pub struct MissingValuesSchemaConfig {
4986 #[serde(default)]
4988 pub enabled: bool,
4989 #[serde(default = "default_missing_rate")]
4991 pub rate: f64,
4992 #[serde(default)]
4994 pub strategy: MissingValueStrategy,
4995 #[serde(default)]
4997 pub field_rates: std::collections::HashMap<String, f64>,
4998 #[serde(default)]
5000 pub protected_fields: Vec<String>,
5001}
5002
5003fn default_missing_rate() -> f64 {
5004 0.01
5005}
5006
5007impl Default for MissingValuesSchemaConfig {
5008 fn default() -> Self {
5009 Self {
5010 enabled: false,
5011 rate: default_missing_rate(),
5012 strategy: MissingValueStrategy::Mcar,
5013 field_rates: std::collections::HashMap::new(),
5014 protected_fields: vec![
5015 "document_id".to_string(),
5016 "company_code".to_string(),
5017 "posting_date".to_string(),
5018 ],
5019 }
5020 }
5021}
5022
5023#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5025#[serde(rename_all = "snake_case")]
5026pub enum MissingValueStrategy {
5027 #[default]
5029 Mcar,
5030 Mar,
5032 Mnar,
5034 Systematic,
5036}
5037
5038#[derive(Debug, Clone, Serialize, Deserialize)]
5040pub struct TypoSchemaConfig {
5041 #[serde(default)]
5043 pub enabled: bool,
5044 #[serde(default = "default_typo_rate")]
5046 pub char_error_rate: f64,
5047 #[serde(default)]
5049 pub type_weights: TypoTypeWeights,
5050 #[serde(default)]
5052 pub protected_fields: Vec<String>,
5053}
5054
5055fn default_typo_rate() -> f64 {
5056 0.001
5057}
5058
5059impl Default for TypoSchemaConfig {
5060 fn default() -> Self {
5061 Self {
5062 enabled: false,
5063 char_error_rate: default_typo_rate(),
5064 type_weights: TypoTypeWeights::default(),
5065 protected_fields: vec![
5066 "document_id".to_string(),
5067 "gl_account".to_string(),
5068 "company_code".to_string(),
5069 ],
5070 }
5071 }
5072}
5073
5074#[derive(Debug, Clone, Serialize, Deserialize)]
5076pub struct TypoTypeWeights {
5077 #[serde(default = "default_substitution_weight")]
5079 pub substitution: f64,
5080 #[serde(default = "default_transposition_weight")]
5082 pub transposition: f64,
5083 #[serde(default = "default_insertion_weight")]
5085 pub insertion: f64,
5086 #[serde(default = "default_deletion_weight")]
5088 pub deletion: f64,
5089 #[serde(default = "default_ocr_weight")]
5091 pub ocr_errors: f64,
5092 #[serde(default = "default_homophone_weight")]
5094 pub homophones: f64,
5095}
5096
5097fn default_substitution_weight() -> f64 {
5098 0.35
5099}
5100fn default_transposition_weight() -> f64 {
5101 0.25
5102}
5103fn default_insertion_weight() -> f64 {
5104 0.10
5105}
5106fn default_deletion_weight() -> f64 {
5107 0.15
5108}
5109fn default_ocr_weight() -> f64 {
5110 0.10
5111}
5112fn default_homophone_weight() -> f64 {
5113 0.05
5114}
5115
5116impl Default for TypoTypeWeights {
5117 fn default() -> Self {
5118 Self {
5119 substitution: default_substitution_weight(),
5120 transposition: default_transposition_weight(),
5121 insertion: default_insertion_weight(),
5122 deletion: default_deletion_weight(),
5123 ocr_errors: default_ocr_weight(),
5124 homophones: default_homophone_weight(),
5125 }
5126 }
5127}
5128
5129#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5131pub struct FormatVariationSchemaConfig {
5132 #[serde(default)]
5134 pub enabled: bool,
5135 #[serde(default)]
5137 pub dates: DateFormatVariationConfig,
5138 #[serde(default)]
5140 pub amounts: AmountFormatVariationConfig,
5141 #[serde(default)]
5143 pub identifiers: IdentifierFormatVariationConfig,
5144}
5145
5146#[derive(Debug, Clone, Serialize, Deserialize)]
5148pub struct DateFormatVariationConfig {
5149 #[serde(default)]
5151 pub enabled: bool,
5152 #[serde(default = "default_date_variation_rate")]
5154 pub rate: f64,
5155 #[serde(default = "default_true")]
5157 pub iso_format: bool,
5158 #[serde(default)]
5160 pub us_format: bool,
5161 #[serde(default)]
5163 pub eu_format: bool,
5164 #[serde(default)]
5166 pub long_format: bool,
5167}
5168
5169fn default_date_variation_rate() -> f64 {
5170 0.05
5171}
5172
5173impl Default for DateFormatVariationConfig {
5174 fn default() -> Self {
5175 Self {
5176 enabled: false,
5177 rate: default_date_variation_rate(),
5178 iso_format: true,
5179 us_format: false,
5180 eu_format: false,
5181 long_format: false,
5182 }
5183 }
5184}
5185
5186#[derive(Debug, Clone, Serialize, Deserialize)]
5188pub struct AmountFormatVariationConfig {
5189 #[serde(default)]
5191 pub enabled: bool,
5192 #[serde(default = "default_amount_variation_rate")]
5194 pub rate: f64,
5195 #[serde(default)]
5197 pub us_comma_format: bool,
5198 #[serde(default)]
5200 pub eu_format: bool,
5201 #[serde(default)]
5203 pub currency_prefix: bool,
5204 #[serde(default)]
5206 pub accounting_format: bool,
5207}
5208
5209fn default_amount_variation_rate() -> f64 {
5210 0.02
5211}
5212
5213impl Default for AmountFormatVariationConfig {
5214 fn default() -> Self {
5215 Self {
5216 enabled: false,
5217 rate: default_amount_variation_rate(),
5218 us_comma_format: false,
5219 eu_format: false,
5220 currency_prefix: false,
5221 accounting_format: false,
5222 }
5223 }
5224}
5225
5226#[derive(Debug, Clone, Serialize, Deserialize)]
5228pub struct IdentifierFormatVariationConfig {
5229 #[serde(default)]
5231 pub enabled: bool,
5232 #[serde(default = "default_identifier_variation_rate")]
5234 pub rate: f64,
5235 #[serde(default)]
5237 pub case_variations: bool,
5238 #[serde(default)]
5240 pub padding_variations: bool,
5241 #[serde(default)]
5243 pub separator_variations: bool,
5244}
5245
5246fn default_identifier_variation_rate() -> f64 {
5247 0.02
5248}
5249
5250impl Default for IdentifierFormatVariationConfig {
5251 fn default() -> Self {
5252 Self {
5253 enabled: false,
5254 rate: default_identifier_variation_rate(),
5255 case_variations: false,
5256 padding_variations: false,
5257 separator_variations: false,
5258 }
5259 }
5260}
5261
5262#[derive(Debug, Clone, Serialize, Deserialize)]
5264pub struct DuplicateSchemaConfig {
5265 #[serde(default)]
5267 pub enabled: bool,
5268 #[serde(default = "default_duplicate_rate")]
5270 pub rate: f64,
5271 #[serde(default = "default_exact_duplicate_ratio")]
5273 pub exact_duplicate_ratio: f64,
5274 #[serde(default = "default_near_duplicate_ratio")]
5276 pub near_duplicate_ratio: f64,
5277 #[serde(default = "default_fuzzy_duplicate_ratio")]
5279 pub fuzzy_duplicate_ratio: f64,
5280 #[serde(default = "default_max_date_offset")]
5282 pub max_date_offset_days: u32,
5283 #[serde(default = "default_max_amount_variance")]
5285 pub max_amount_variance: f64,
5286}
5287
5288fn default_duplicate_rate() -> f64 {
5289 0.005
5290}
5291fn default_exact_duplicate_ratio() -> f64 {
5292 0.4
5293}
5294fn default_near_duplicate_ratio() -> f64 {
5295 0.35
5296}
5297fn default_fuzzy_duplicate_ratio() -> f64 {
5298 0.25
5299}
5300fn default_max_date_offset() -> u32 {
5301 3
5302}
5303fn default_max_amount_variance() -> f64 {
5304 0.01
5305}
5306
5307impl Default for DuplicateSchemaConfig {
5308 fn default() -> Self {
5309 Self {
5310 enabled: false,
5311 rate: default_duplicate_rate(),
5312 exact_duplicate_ratio: default_exact_duplicate_ratio(),
5313 near_duplicate_ratio: default_near_duplicate_ratio(),
5314 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
5315 max_date_offset_days: default_max_date_offset(),
5316 max_amount_variance: default_max_amount_variance(),
5317 }
5318 }
5319}
5320
5321#[derive(Debug, Clone, Serialize, Deserialize)]
5323pub struct EncodingIssueSchemaConfig {
5324 #[serde(default)]
5326 pub enabled: bool,
5327 #[serde(default = "default_encoding_rate")]
5329 pub rate: f64,
5330 #[serde(default)]
5332 pub mojibake: bool,
5333 #[serde(default)]
5335 pub html_entities: bool,
5336 #[serde(default)]
5338 pub bom_issues: bool,
5339}
5340
5341fn default_encoding_rate() -> f64 {
5342 0.001
5343}
5344
5345impl Default for EncodingIssueSchemaConfig {
5346 fn default() -> Self {
5347 Self {
5348 enabled: false,
5349 rate: default_encoding_rate(),
5350 mojibake: false,
5351 html_entities: false,
5352 bom_issues: false,
5353 }
5354 }
5355}
5356
5357#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5359pub struct SinkQualityProfiles {
5360 #[serde(default)]
5362 pub csv: Option<SinkQualityOverride>,
5363 #[serde(default)]
5365 pub json: Option<SinkQualityOverride>,
5366 #[serde(default)]
5368 pub parquet: Option<SinkQualityOverride>,
5369}
5370
5371#[derive(Debug, Clone, Serialize, Deserialize)]
5373pub struct SinkQualityOverride {
5374 pub enabled: Option<bool>,
5376 pub missing_rate: Option<f64>,
5378 pub typo_rate: Option<f64>,
5380 pub format_variation_rate: Option<f64>,
5382 pub duplicate_rate: Option<f64>,
5384}
5385
5386#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5398pub struct AccountingStandardsConfig {
5399 #[serde(default)]
5401 pub enabled: bool,
5402
5403 #[serde(default, skip_serializing_if = "Option::is_none")]
5407 pub framework: Option<AccountingFrameworkConfig>,
5408
5409 #[serde(default)]
5411 pub revenue_recognition: RevenueRecognitionConfig,
5412
5413 #[serde(default)]
5415 pub leases: LeaseAccountingConfig,
5416
5417 #[serde(default)]
5419 pub fair_value: FairValueConfig,
5420
5421 #[serde(default)]
5423 pub impairment: ImpairmentConfig,
5424
5425 #[serde(default)]
5427 pub business_combinations: BusinessCombinationsConfig,
5428
5429 #[serde(default)]
5431 pub expected_credit_loss: EclConfig,
5432
5433 #[serde(default)]
5435 pub generate_differences: bool,
5436}
5437
5438#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5440#[serde(rename_all = "snake_case")]
5441pub enum AccountingFrameworkConfig {
5442 #[default]
5444 UsGaap,
5445 Ifrs,
5447 DualReporting,
5449 FrenchGaap,
5451 GermanGaap,
5453}
5454
5455#[derive(Debug, Clone, Serialize, Deserialize)]
5457pub struct RevenueRecognitionConfig {
5458 #[serde(default)]
5460 pub enabled: bool,
5461
5462 #[serde(default = "default_true")]
5464 pub generate_contracts: bool,
5465
5466 #[serde(default = "default_avg_obligations")]
5468 pub avg_obligations_per_contract: f64,
5469
5470 #[serde(default = "default_variable_consideration_rate")]
5472 pub variable_consideration_rate: f64,
5473
5474 #[serde(default = "default_over_time_rate")]
5476 pub over_time_recognition_rate: f64,
5477
5478 #[serde(default = "default_contract_count")]
5480 pub contract_count: usize,
5481}
5482
5483fn default_avg_obligations() -> f64 {
5484 2.0
5485}
5486
5487fn default_variable_consideration_rate() -> f64 {
5488 0.15
5489}
5490
5491fn default_over_time_rate() -> f64 {
5492 0.30
5493}
5494
5495fn default_contract_count() -> usize {
5496 100
5497}
5498
5499impl Default for RevenueRecognitionConfig {
5500 fn default() -> Self {
5501 Self {
5502 enabled: false,
5503 generate_contracts: true,
5504 avg_obligations_per_contract: default_avg_obligations(),
5505 variable_consideration_rate: default_variable_consideration_rate(),
5506 over_time_recognition_rate: default_over_time_rate(),
5507 contract_count: default_contract_count(),
5508 }
5509 }
5510}
5511
5512#[derive(Debug, Clone, Serialize, Deserialize)]
5514pub struct LeaseAccountingConfig {
5515 #[serde(default)]
5517 pub enabled: bool,
5518
5519 #[serde(default = "default_lease_count")]
5521 pub lease_count: usize,
5522
5523 #[serde(default = "default_finance_lease_pct")]
5525 pub finance_lease_percent: f64,
5526
5527 #[serde(default = "default_avg_lease_term")]
5529 pub avg_lease_term_months: u32,
5530
5531 #[serde(default = "default_true")]
5533 pub generate_amortization: bool,
5534
5535 #[serde(default = "default_real_estate_pct")]
5537 pub real_estate_percent: f64,
5538}
5539
5540fn default_lease_count() -> usize {
5541 50
5542}
5543
5544fn default_finance_lease_pct() -> f64 {
5545 0.30
5546}
5547
5548fn default_avg_lease_term() -> u32 {
5549 60
5550}
5551
5552fn default_real_estate_pct() -> f64 {
5553 0.40
5554}
5555
5556impl Default for LeaseAccountingConfig {
5557 fn default() -> Self {
5558 Self {
5559 enabled: false,
5560 lease_count: default_lease_count(),
5561 finance_lease_percent: default_finance_lease_pct(),
5562 avg_lease_term_months: default_avg_lease_term(),
5563 generate_amortization: true,
5564 real_estate_percent: default_real_estate_pct(),
5565 }
5566 }
5567}
5568
5569#[derive(Debug, Clone, Serialize, Deserialize)]
5571pub struct FairValueConfig {
5572 #[serde(default)]
5574 pub enabled: bool,
5575
5576 #[serde(default = "default_fv_count")]
5578 pub measurement_count: usize,
5579
5580 #[serde(default = "default_level1_pct")]
5582 pub level1_percent: f64,
5583
5584 #[serde(default = "default_level2_pct")]
5586 pub level2_percent: f64,
5587
5588 #[serde(default = "default_level3_pct")]
5590 pub level3_percent: f64,
5591
5592 #[serde(default)]
5594 pub include_sensitivity_analysis: bool,
5595}
5596
5597fn default_fv_count() -> usize {
5598 25
5599}
5600
5601fn default_level1_pct() -> f64 {
5602 0.40
5603}
5604
5605fn default_level2_pct() -> f64 {
5606 0.35
5607}
5608
5609fn default_level3_pct() -> f64 {
5610 0.25
5611}
5612
5613impl Default for FairValueConfig {
5614 fn default() -> Self {
5615 Self {
5616 enabled: false,
5617 measurement_count: default_fv_count(),
5618 level1_percent: default_level1_pct(),
5619 level2_percent: default_level2_pct(),
5620 level3_percent: default_level3_pct(),
5621 include_sensitivity_analysis: false,
5622 }
5623 }
5624}
5625
5626#[derive(Debug, Clone, Serialize, Deserialize)]
5628pub struct ImpairmentConfig {
5629 #[serde(default)]
5631 pub enabled: bool,
5632
5633 #[serde(default = "default_impairment_count")]
5635 pub test_count: usize,
5636
5637 #[serde(default = "default_impairment_rate")]
5639 pub impairment_rate: f64,
5640
5641 #[serde(default = "default_true")]
5643 pub generate_projections: bool,
5644
5645 #[serde(default)]
5647 pub include_goodwill: bool,
5648}
5649
5650fn default_impairment_count() -> usize {
5651 15
5652}
5653
5654fn default_impairment_rate() -> f64 {
5655 0.10
5656}
5657
5658impl Default for ImpairmentConfig {
5659 fn default() -> Self {
5660 Self {
5661 enabled: false,
5662 test_count: default_impairment_count(),
5663 impairment_rate: default_impairment_rate(),
5664 generate_projections: true,
5665 include_goodwill: false,
5666 }
5667 }
5668}
5669
5670#[derive(Debug, Clone, Serialize, Deserialize)]
5676pub struct BusinessCombinationsConfig {
5677 #[serde(default)]
5679 pub enabled: bool,
5680
5681 #[serde(default = "default_bc_acquisition_count")]
5683 pub acquisition_count: usize,
5684}
5685
5686fn default_bc_acquisition_count() -> usize {
5687 2
5688}
5689
5690impl Default for BusinessCombinationsConfig {
5691 fn default() -> Self {
5692 Self {
5693 enabled: false,
5694 acquisition_count: default_bc_acquisition_count(),
5695 }
5696 }
5697}
5698
5699#[derive(Debug, Clone, Serialize, Deserialize)]
5705pub struct EclConfig {
5706 #[serde(default)]
5708 pub enabled: bool,
5709
5710 #[serde(default = "default_ecl_base_weight")]
5712 pub base_scenario_weight: f64,
5713
5714 #[serde(default = "default_ecl_base_multiplier")]
5716 pub base_scenario_multiplier: f64,
5717
5718 #[serde(default = "default_ecl_optimistic_weight")]
5720 pub optimistic_scenario_weight: f64,
5721
5722 #[serde(default = "default_ecl_optimistic_multiplier")]
5724 pub optimistic_scenario_multiplier: f64,
5725
5726 #[serde(default = "default_ecl_pessimistic_weight")]
5728 pub pessimistic_scenario_weight: f64,
5729
5730 #[serde(default = "default_ecl_pessimistic_multiplier")]
5732 pub pessimistic_scenario_multiplier: f64,
5733}
5734
5735fn default_ecl_base_weight() -> f64 {
5736 0.50
5737}
5738fn default_ecl_base_multiplier() -> f64 {
5739 1.0
5740}
5741fn default_ecl_optimistic_weight() -> f64 {
5742 0.30
5743}
5744fn default_ecl_optimistic_multiplier() -> f64 {
5745 0.8
5746}
5747fn default_ecl_pessimistic_weight() -> f64 {
5748 0.20
5749}
5750fn default_ecl_pessimistic_multiplier() -> f64 {
5751 1.4
5752}
5753
5754impl Default for EclConfig {
5755 fn default() -> Self {
5756 Self {
5757 enabled: false,
5758 base_scenario_weight: default_ecl_base_weight(),
5759 base_scenario_multiplier: default_ecl_base_multiplier(),
5760 optimistic_scenario_weight: default_ecl_optimistic_weight(),
5761 optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5762 pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5763 pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5764 }
5765 }
5766}
5767
5768#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5781pub struct AuditStandardsConfig {
5782 #[serde(default)]
5784 pub enabled: bool,
5785
5786 #[serde(default)]
5788 pub isa_compliance: IsaComplianceConfig,
5789
5790 #[serde(default)]
5792 pub analytical_procedures: AnalyticalProceduresConfig,
5793
5794 #[serde(default)]
5796 pub confirmations: ConfirmationsConfig,
5797
5798 #[serde(default)]
5800 pub opinion: AuditOpinionConfig,
5801
5802 #[serde(default)]
5804 pub generate_audit_trail: bool,
5805
5806 #[serde(default)]
5808 pub sox: SoxComplianceConfig,
5809
5810 #[serde(default)]
5812 pub pcaob: PcaobConfig,
5813}
5814
5815#[derive(Debug, Clone, Serialize, Deserialize)]
5817pub struct IsaComplianceConfig {
5818 #[serde(default)]
5820 pub enabled: bool,
5821
5822 #[serde(default = "default_compliance_level")]
5824 pub compliance_level: String,
5825
5826 #[serde(default = "default_true")]
5828 pub generate_isa_mappings: bool,
5829
5830 #[serde(default = "default_true")]
5832 pub generate_coverage_summary: bool,
5833
5834 #[serde(default)]
5836 pub include_pcaob: bool,
5837
5838 #[serde(default = "default_audit_framework")]
5840 pub framework: String,
5841}
5842
5843fn default_compliance_level() -> String {
5844 "standard".to_string()
5845}
5846
5847fn default_audit_framework() -> String {
5848 "isa".to_string()
5849}
5850
5851impl Default for IsaComplianceConfig {
5852 fn default() -> Self {
5853 Self {
5854 enabled: false,
5855 compliance_level: default_compliance_level(),
5856 generate_isa_mappings: true,
5857 generate_coverage_summary: true,
5858 include_pcaob: false,
5859 framework: default_audit_framework(),
5860 }
5861 }
5862}
5863
5864#[derive(Debug, Clone, Serialize, Deserialize)]
5866pub struct AnalyticalProceduresConfig {
5867 #[serde(default)]
5869 pub enabled: bool,
5870
5871 #[serde(default = "default_procedures_per_account")]
5873 pub procedures_per_account: usize,
5874
5875 #[serde(default = "default_variance_probability")]
5877 pub variance_probability: f64,
5878
5879 #[serde(default = "default_true")]
5881 pub generate_investigations: bool,
5882
5883 #[serde(default = "default_true")]
5885 pub include_ratio_analysis: bool,
5886}
5887
5888fn default_procedures_per_account() -> usize {
5889 3
5890}
5891
5892fn default_variance_probability() -> f64 {
5893 0.20
5894}
5895
5896impl Default for AnalyticalProceduresConfig {
5897 fn default() -> Self {
5898 Self {
5899 enabled: false,
5900 procedures_per_account: default_procedures_per_account(),
5901 variance_probability: default_variance_probability(),
5902 generate_investigations: true,
5903 include_ratio_analysis: true,
5904 }
5905 }
5906}
5907
5908#[derive(Debug, Clone, Serialize, Deserialize)]
5910pub struct ConfirmationsConfig {
5911 #[serde(default)]
5913 pub enabled: bool,
5914
5915 #[serde(default = "default_confirmation_count")]
5917 pub confirmation_count: usize,
5918
5919 #[serde(default = "default_positive_response_rate")]
5921 pub positive_response_rate: f64,
5922
5923 #[serde(default = "default_exception_rate_confirm")]
5925 pub exception_rate: f64,
5926
5927 #[serde(default = "default_non_response_rate")]
5929 pub non_response_rate: f64,
5930
5931 #[serde(default = "default_true")]
5933 pub generate_alternative_procedures: bool,
5934}
5935
5936fn default_confirmation_count() -> usize {
5937 50
5938}
5939
5940fn default_positive_response_rate() -> f64 {
5941 0.85
5942}
5943
5944fn default_exception_rate_confirm() -> f64 {
5945 0.10
5946}
5947
5948fn default_non_response_rate() -> f64 {
5949 0.05
5950}
5951
5952impl Default for ConfirmationsConfig {
5953 fn default() -> Self {
5954 Self {
5955 enabled: false,
5956 confirmation_count: default_confirmation_count(),
5957 positive_response_rate: default_positive_response_rate(),
5958 exception_rate: default_exception_rate_confirm(),
5959 non_response_rate: default_non_response_rate(),
5960 generate_alternative_procedures: true,
5961 }
5962 }
5963}
5964
5965#[derive(Debug, Clone, Serialize, Deserialize)]
5967pub struct AuditOpinionConfig {
5968 #[serde(default)]
5970 pub enabled: bool,
5971
5972 #[serde(default = "default_true")]
5974 pub generate_kam: bool,
5975
5976 #[serde(default = "default_kam_count")]
5978 pub average_kam_count: usize,
5979
5980 #[serde(default = "default_modified_opinion_rate")]
5982 pub modified_opinion_rate: f64,
5983
5984 #[serde(default)]
5986 pub include_emphasis_of_matter: bool,
5987
5988 #[serde(default = "default_true")]
5990 pub include_going_concern: bool,
5991}
5992
5993fn default_kam_count() -> usize {
5994 3
5995}
5996
5997fn default_modified_opinion_rate() -> f64 {
5998 0.05
5999}
6000
6001impl Default for AuditOpinionConfig {
6002 fn default() -> Self {
6003 Self {
6004 enabled: false,
6005 generate_kam: true,
6006 average_kam_count: default_kam_count(),
6007 modified_opinion_rate: default_modified_opinion_rate(),
6008 include_emphasis_of_matter: false,
6009 include_going_concern: true,
6010 }
6011 }
6012}
6013
6014#[derive(Debug, Clone, Serialize, Deserialize)]
6016pub struct SoxComplianceConfig {
6017 #[serde(default)]
6019 pub enabled: bool,
6020
6021 #[serde(default = "default_true")]
6023 pub generate_302_certifications: bool,
6024
6025 #[serde(default = "default_true")]
6027 pub generate_404_assessments: bool,
6028
6029 #[serde(default = "default_sox_materiality_threshold")]
6031 pub materiality_threshold: f64,
6032
6033 #[serde(default = "default_material_weakness_rate")]
6035 pub material_weakness_rate: f64,
6036
6037 #[serde(default = "default_significant_deficiency_rate")]
6039 pub significant_deficiency_rate: f64,
6040}
6041
6042fn default_material_weakness_rate() -> f64 {
6043 0.02
6044}
6045
6046fn default_significant_deficiency_rate() -> f64 {
6047 0.08
6048}
6049
6050impl Default for SoxComplianceConfig {
6051 fn default() -> Self {
6052 Self {
6053 enabled: false,
6054 generate_302_certifications: true,
6055 generate_404_assessments: true,
6056 materiality_threshold: default_sox_materiality_threshold(),
6057 material_weakness_rate: default_material_weakness_rate(),
6058 significant_deficiency_rate: default_significant_deficiency_rate(),
6059 }
6060 }
6061}
6062
6063#[derive(Debug, Clone, Serialize, Deserialize)]
6065pub struct PcaobConfig {
6066 #[serde(default)]
6068 pub enabled: bool,
6069
6070 #[serde(default)]
6072 pub is_pcaob_audit: bool,
6073
6074 #[serde(default = "default_true")]
6076 pub generate_cam: bool,
6077
6078 #[serde(default)]
6080 pub include_icfr_opinion: bool,
6081
6082 #[serde(default)]
6084 pub generate_standard_mappings: bool,
6085}
6086
6087impl Default for PcaobConfig {
6088 fn default() -> Self {
6089 Self {
6090 enabled: false,
6091 is_pcaob_audit: false,
6092 generate_cam: true,
6093 include_icfr_opinion: false,
6094 generate_standard_mappings: false,
6095 }
6096 }
6097}
6098
6099#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6112pub struct AdvancedDistributionConfig {
6113 #[serde(default)]
6115 pub enabled: bool,
6116
6117 #[serde(default)]
6119 pub amounts: MixtureDistributionSchemaConfig,
6120
6121 #[serde(default)]
6123 pub correlations: CorrelationSchemaConfig,
6124
6125 #[serde(default)]
6127 pub conditional: Vec<ConditionalDistributionSchemaConfig>,
6128
6129 #[serde(default)]
6131 pub regime_changes: RegimeChangeSchemaConfig,
6132
6133 #[serde(default)]
6135 pub industry_profile: Option<IndustryProfileType>,
6136
6137 #[serde(default)]
6139 pub validation: StatisticalValidationSchemaConfig,
6140
6141 #[serde(default)]
6147 pub pareto: Option<ParetoSchemaConfig>,
6148}
6149
6150#[derive(Debug, Clone, Serialize, Deserialize)]
6155pub struct ParetoSchemaConfig {
6156 #[serde(default)]
6159 pub enabled: bool,
6160
6161 #[serde(default = "default_pareto_alpha")]
6164 pub alpha: f64,
6165
6166 #[serde(default = "default_pareto_x_min")]
6169 pub x_min: f64,
6170
6171 #[serde(default)]
6174 pub max_value: Option<f64>,
6175
6176 #[serde(default = "default_pareto_decimal_places")]
6178 pub decimal_places: u8,
6179}
6180
6181fn default_pareto_alpha() -> f64 {
6182 2.0
6183}
6184
6185fn default_pareto_x_min() -> f64 {
6186 100.0
6187}
6188
6189fn default_pareto_decimal_places() -> u8 {
6190 2
6191}
6192
6193impl Default for ParetoSchemaConfig {
6194 fn default() -> Self {
6195 Self {
6196 enabled: false,
6197 alpha: default_pareto_alpha(),
6198 x_min: default_pareto_x_min(),
6199 max_value: None,
6200 decimal_places: default_pareto_decimal_places(),
6201 }
6202 }
6203}
6204
6205impl ParetoSchemaConfig {
6206 pub fn to_core_config(&self) -> datasynth_core::distributions::ParetoConfig {
6208 datasynth_core::distributions::ParetoConfig {
6209 alpha: self.alpha,
6210 x_min: self.x_min,
6211 max_value: self.max_value,
6212 decimal_places: self.decimal_places,
6213 }
6214 }
6215}
6216
6217#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6219#[serde(rename_all = "snake_case")]
6220pub enum IndustryProfileType {
6221 Retail,
6223 Manufacturing,
6225 FinancialServices,
6227 Healthcare,
6229 Technology,
6231}
6232
6233#[derive(Debug, Clone, Serialize, Deserialize)]
6235pub struct MixtureDistributionSchemaConfig {
6236 #[serde(default)]
6238 pub enabled: bool,
6239
6240 #[serde(default = "default_mixture_type")]
6242 pub distribution_type: MixtureDistributionType,
6243
6244 #[serde(default)]
6246 pub components: Vec<MixtureComponentConfig>,
6247
6248 #[serde(default = "default_min_amount")]
6250 pub min_value: f64,
6251
6252 #[serde(default)]
6254 pub max_value: Option<f64>,
6255
6256 #[serde(default = "default_decimal_places")]
6258 pub decimal_places: u8,
6259}
6260
6261fn default_mixture_type() -> MixtureDistributionType {
6262 MixtureDistributionType::LogNormal
6263}
6264
6265fn default_min_amount() -> f64 {
6266 0.01
6267}
6268
6269fn default_decimal_places() -> u8 {
6270 2
6271}
6272
6273impl Default for MixtureDistributionSchemaConfig {
6274 fn default() -> Self {
6275 Self {
6276 enabled: false,
6277 distribution_type: MixtureDistributionType::LogNormal,
6278 components: Vec::new(),
6279 min_value: 0.01,
6280 max_value: None,
6281 decimal_places: 2,
6282 }
6283 }
6284}
6285
6286impl MixtureDistributionSchemaConfig {
6287 pub fn to_log_normal_config(
6294 &self,
6295 ) -> Option<datasynth_core::distributions::LogNormalMixtureConfig> {
6296 if self.components.is_empty() {
6297 return None;
6298 }
6299 Some(datasynth_core::distributions::LogNormalMixtureConfig {
6300 components: self
6301 .components
6302 .iter()
6303 .map(|c| match &c.label {
6304 Some(lbl) => datasynth_core::distributions::LogNormalComponent::with_label(
6305 c.weight,
6306 c.mu,
6307 c.sigma,
6308 lbl.clone(),
6309 ),
6310 None => datasynth_core::distributions::LogNormalComponent::new(
6311 c.weight, c.mu, c.sigma,
6312 ),
6313 })
6314 .collect(),
6315 min_value: self.min_value,
6316 max_value: self.max_value,
6317 decimal_places: self.decimal_places,
6318 })
6319 }
6320
6321 pub fn to_gaussian_config(
6324 &self,
6325 ) -> Option<datasynth_core::distributions::GaussianMixtureConfig> {
6326 if self.components.is_empty() {
6327 return None;
6328 }
6329 Some(datasynth_core::distributions::GaussianMixtureConfig {
6330 components: self
6331 .components
6332 .iter()
6333 .map(|c| {
6334 datasynth_core::distributions::GaussianComponent::new(c.weight, c.mu, c.sigma)
6335 })
6336 .collect(),
6337 allow_negative: true,
6338 min_value: Some(self.min_value),
6339 max_value: self.max_value,
6340 })
6341 }
6342}
6343
6344#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6346#[serde(rename_all = "snake_case")]
6347pub enum MixtureDistributionType {
6348 Gaussian,
6350 #[default]
6352 LogNormal,
6353}
6354
6355#[derive(Debug, Clone, Serialize, Deserialize)]
6357pub struct MixtureComponentConfig {
6358 pub weight: f64,
6360
6361 pub mu: f64,
6363
6364 pub sigma: f64,
6366
6367 #[serde(default)]
6369 pub label: Option<String>,
6370}
6371
6372#[derive(Debug, Clone, Serialize, Deserialize)]
6374pub struct CorrelationSchemaConfig {
6375 #[serde(default)]
6377 pub enabled: bool,
6378
6379 #[serde(default)]
6381 pub copula_type: CopulaSchemaType,
6382
6383 #[serde(default)]
6385 pub fields: Vec<CorrelatedFieldConfig>,
6386
6387 #[serde(default)]
6390 pub matrix: Vec<f64>,
6391
6392 #[serde(default)]
6394 pub expected_correlations: Vec<ExpectedCorrelationConfig>,
6395}
6396
6397impl Default for CorrelationSchemaConfig {
6398 fn default() -> Self {
6399 Self {
6400 enabled: false,
6401 copula_type: CopulaSchemaType::Gaussian,
6402 fields: Vec::new(),
6403 matrix: Vec::new(),
6404 expected_correlations: Vec::new(),
6405 }
6406 }
6407}
6408
6409impl CorrelationSchemaConfig {
6410 pub fn correlation_between(&self, field_a: &str, field_b: &str) -> Option<f64> {
6416 let idx_a = self.fields.iter().position(|f| f.name == field_a)?;
6417 let idx_b = self.fields.iter().position(|f| f.name == field_b)?;
6418 if idx_a == idx_b {
6419 return Some(1.0);
6420 }
6421 let (i, j) = if idx_a < idx_b {
6422 (idx_a, idx_b)
6423 } else {
6424 (idx_b, idx_a)
6425 };
6426 let n = self.fields.len();
6427 if self.matrix.len() == n * n {
6429 return self.matrix.get(idx_a * n + idx_b).copied();
6430 }
6431 let expected_tri = n * (n - 1) / 2;
6433 if self.matrix.len() == expected_tri {
6434 let flat = i * (n - 1) - i * (i.saturating_sub(1)) / 2 + (j - i - 1);
6438 return self.matrix.get(flat).copied();
6439 }
6440 None
6441 }
6442
6443 pub fn to_core_config_for_pair(
6448 &self,
6449 field_a: &str,
6450 field_b: &str,
6451 ) -> Option<datasynth_core::distributions::CopulaConfig> {
6452 if !self.enabled {
6453 return None;
6454 }
6455 let rho = self.correlation_between(field_a, field_b)?;
6456 use datasynth_core::distributions::{CopulaConfig, CopulaType};
6457 let copula_type = match self.copula_type {
6458 CopulaSchemaType::Gaussian => CopulaType::Gaussian,
6459 CopulaSchemaType::Clayton => CopulaType::Clayton,
6460 CopulaSchemaType::Gumbel => CopulaType::Gumbel,
6461 CopulaSchemaType::Frank => CopulaType::Frank,
6462 CopulaSchemaType::StudentT => CopulaType::StudentT,
6463 };
6464 let theta = rho.clamp(-0.999, 0.999);
6469 Some(CopulaConfig {
6470 copula_type,
6471 theta,
6472 degrees_of_freedom: 4.0,
6473 })
6474 }
6475}
6476
6477#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6479#[serde(rename_all = "snake_case")]
6480pub enum CopulaSchemaType {
6481 #[default]
6483 Gaussian,
6484 Clayton,
6486 Gumbel,
6488 Frank,
6490 StudentT,
6492}
6493
6494#[derive(Debug, Clone, Serialize, Deserialize)]
6496pub struct CorrelatedFieldConfig {
6497 pub name: String,
6499
6500 #[serde(default)]
6502 pub distribution: MarginalDistributionConfig,
6503}
6504
6505#[derive(Debug, Clone, Serialize, Deserialize)]
6507#[serde(tag = "type", rename_all = "snake_case")]
6508pub enum MarginalDistributionConfig {
6509 Normal {
6511 mu: f64,
6513 sigma: f64,
6515 },
6516 LogNormal {
6518 mu: f64,
6520 sigma: f64,
6522 },
6523 Uniform {
6525 min: f64,
6527 max: f64,
6529 },
6530 DiscreteUniform {
6532 min: i32,
6534 max: i32,
6536 },
6537}
6538
6539impl Default for MarginalDistributionConfig {
6540 fn default() -> Self {
6541 Self::Normal {
6542 mu: 0.0,
6543 sigma: 1.0,
6544 }
6545 }
6546}
6547
6548#[derive(Debug, Clone, Serialize, Deserialize)]
6550pub struct ExpectedCorrelationConfig {
6551 pub field1: String,
6553 pub field2: String,
6555 pub expected_r: f64,
6557 #[serde(default = "default_correlation_tolerance")]
6559 pub tolerance: f64,
6560}
6561
6562fn default_correlation_tolerance() -> f64 {
6563 0.10
6564}
6565
6566#[derive(Debug, Clone, Serialize, Deserialize)]
6568pub struct ConditionalDistributionSchemaConfig {
6569 pub output_field: String,
6571
6572 pub input_field: String,
6574
6575 #[serde(default)]
6577 pub breakpoints: Vec<ConditionalBreakpointConfig>,
6578
6579 #[serde(default)]
6581 pub default_distribution: ConditionalDistributionParamsConfig,
6582
6583 #[serde(default)]
6585 pub min_value: Option<f64>,
6586
6587 #[serde(default)]
6589 pub max_value: Option<f64>,
6590
6591 #[serde(default = "default_decimal_places")]
6593 pub decimal_places: u8,
6594}
6595
6596#[derive(Debug, Clone, Serialize, Deserialize)]
6598pub struct ConditionalBreakpointConfig {
6599 pub threshold: f64,
6601
6602 pub distribution: ConditionalDistributionParamsConfig,
6604}
6605
6606impl ConditionalDistributionSchemaConfig {
6607 pub fn to_core_config(&self) -> datasynth_core::distributions::ConditionalDistributionConfig {
6611 use datasynth_core::distributions::{
6612 Breakpoint, ConditionalDistributionConfig, ConditionalDistributionParams,
6613 };
6614
6615 let default_distribution = convert_conditional_params(&self.default_distribution);
6616 let breakpoints: Vec<Breakpoint> = self
6617 .breakpoints
6618 .iter()
6619 .map(|bp| Breakpoint {
6620 threshold: bp.threshold,
6621 distribution: convert_conditional_params(&bp.distribution),
6622 })
6623 .collect();
6624
6625 let final_default = if breakpoints.is_empty() {
6630 default_distribution
6631 } else {
6632 match default_distribution {
6633 ConditionalDistributionParams::Fixed { value: 0.0 } => {
6634 breakpoints[0].distribution.clone()
6637 }
6638 other => other,
6639 }
6640 };
6641
6642 ConditionalDistributionConfig {
6643 output_field: self.output_field.clone(),
6644 input_field: self.input_field.clone(),
6645 breakpoints,
6646 default_distribution: final_default,
6647 min_value: self.min_value,
6648 max_value: self.max_value,
6649 decimal_places: self.decimal_places,
6650 }
6651 }
6652}
6653
6654fn convert_conditional_params(
6655 p: &ConditionalDistributionParamsConfig,
6656) -> datasynth_core::distributions::ConditionalDistributionParams {
6657 use datasynth_core::distributions::ConditionalDistributionParams as Core;
6658 match p {
6659 ConditionalDistributionParamsConfig::Fixed { value } => Core::Fixed { value: *value },
6660 ConditionalDistributionParamsConfig::Normal { mu, sigma } => Core::Normal {
6661 mu: *mu,
6662 sigma: *sigma,
6663 },
6664 ConditionalDistributionParamsConfig::LogNormal { mu, sigma } => Core::LogNormal {
6665 mu: *mu,
6666 sigma: *sigma,
6667 },
6668 ConditionalDistributionParamsConfig::Uniform { min, max } => Core::Uniform {
6669 min: *min,
6670 max: *max,
6671 },
6672 ConditionalDistributionParamsConfig::Beta {
6673 alpha,
6674 beta,
6675 min,
6676 max,
6677 } => Core::Beta {
6678 alpha: *alpha,
6679 beta: *beta,
6680 min: *min,
6681 max: *max,
6682 },
6683 ConditionalDistributionParamsConfig::Discrete { values, weights } => Core::Discrete {
6684 values: values.clone(),
6685 weights: weights.clone(),
6686 },
6687 }
6688}
6689
6690#[derive(Debug, Clone, Serialize, Deserialize)]
6692#[serde(tag = "type", rename_all = "snake_case")]
6693pub enum ConditionalDistributionParamsConfig {
6694 Fixed {
6696 value: f64,
6698 },
6699 Normal {
6701 mu: f64,
6703 sigma: f64,
6705 },
6706 LogNormal {
6708 mu: f64,
6710 sigma: f64,
6712 },
6713 Uniform {
6715 min: f64,
6717 max: f64,
6719 },
6720 Beta {
6722 alpha: f64,
6724 beta: f64,
6726 min: f64,
6728 max: f64,
6730 },
6731 Discrete {
6733 values: Vec<f64>,
6735 weights: Vec<f64>,
6737 },
6738}
6739
6740impl Default for ConditionalDistributionParamsConfig {
6741 fn default() -> Self {
6742 Self::Normal {
6743 mu: 0.0,
6744 sigma: 1.0,
6745 }
6746 }
6747}
6748
6749#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6751pub struct RegimeChangeSchemaConfig {
6752 #[serde(default)]
6754 pub enabled: bool,
6755
6756 #[serde(default)]
6758 pub changes: Vec<RegimeChangeEventConfig>,
6759
6760 #[serde(default)]
6762 pub economic_cycle: Option<EconomicCycleSchemaConfig>,
6763
6764 #[serde(default)]
6766 pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
6767}
6768
6769#[derive(Debug, Clone, Serialize, Deserialize)]
6771pub struct RegimeChangeEventConfig {
6772 pub date: String,
6774
6775 pub change_type: RegimeChangeTypeConfig,
6777
6778 #[serde(default)]
6780 pub description: Option<String>,
6781
6782 #[serde(default)]
6784 pub effects: Vec<RegimeEffectConfig>,
6785}
6786
6787#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
6789#[serde(rename_all = "snake_case")]
6790pub enum RegimeChangeTypeConfig {
6791 Acquisition,
6793 Divestiture,
6795 PriceIncrease,
6797 PriceDecrease,
6799 ProductLaunch,
6801 ProductDiscontinuation,
6803 PolicyChange,
6805 CompetitorEntry,
6807 Custom,
6809}
6810
6811#[derive(Debug, Clone, Serialize, Deserialize)]
6813pub struct RegimeEffectConfig {
6814 pub field: String,
6816
6817 pub multiplier: f64,
6819}
6820
6821#[derive(Debug, Clone, Serialize, Deserialize)]
6823pub struct EconomicCycleSchemaConfig {
6824 #[serde(default)]
6826 pub enabled: bool,
6827
6828 #[serde(default = "default_cycle_period")]
6830 pub period_months: u32,
6831
6832 #[serde(default = "default_cycle_amplitude")]
6834 pub amplitude: f64,
6835
6836 #[serde(default)]
6838 pub phase_offset: u32,
6839
6840 #[serde(default)]
6842 pub recessions: Vec<RecessionPeriodConfig>,
6843}
6844
6845fn default_cycle_period() -> u32 {
6846 48
6847}
6848
6849fn default_cycle_amplitude() -> f64 {
6850 0.15
6851}
6852
6853impl Default for EconomicCycleSchemaConfig {
6854 fn default() -> Self {
6855 Self {
6856 enabled: false,
6857 period_months: 48,
6858 amplitude: 0.15,
6859 phase_offset: 0,
6860 recessions: Vec::new(),
6861 }
6862 }
6863}
6864
6865#[derive(Debug, Clone, Serialize, Deserialize)]
6867pub struct RecessionPeriodConfig {
6868 pub start_month: u32,
6870
6871 pub duration_months: u32,
6873
6874 #[serde(default = "default_recession_severity")]
6876 pub severity: f64,
6877}
6878
6879impl RegimeChangeSchemaConfig {
6880 pub fn apply_to(
6888 &self,
6889 drift: &mut datasynth_core::distributions::DriftConfig,
6890 generation_start: chrono::NaiveDate,
6891 ) {
6892 if !self.enabled {
6893 return;
6894 }
6895
6896 drift.enabled = true;
6898
6899 for event in &self.changes {
6901 let period = match chrono::NaiveDate::parse_from_str(&event.date, "%Y-%m-%d") {
6902 Ok(d) => {
6903 let days = (d - generation_start).num_days();
6904 if days < 0 {
6905 continue;
6906 }
6907 (days as f64 / 30.4).round() as u32
6910 }
6911 Err(_) => continue,
6912 };
6913 let change_type = convert_regime_change_type(event.change_type);
6914 let core_effects = event
6915 .effects
6916 .iter()
6917 .map(|e| datasynth_core::distributions::RegimeEffect {
6918 field: e.field.clone(),
6919 multiplier: e.multiplier,
6920 })
6921 .collect();
6922 drift
6923 .regime_changes
6924 .push(datasynth_core::distributions::RegimeChange {
6925 period,
6926 change_type,
6927 description: event.description.clone(),
6928 effects: core_effects,
6929 transition_periods: 0,
6930 });
6931 }
6932
6933 if let Some(ec) = &self.economic_cycle {
6935 if ec.enabled {
6936 let recession_periods: Vec<u32> = ec
6937 .recessions
6938 .iter()
6939 .flat_map(|r| r.start_month..r.start_month + r.duration_months)
6940 .collect();
6941 let severity = ec
6944 .recessions
6945 .iter()
6946 .map(|r| 1.0 - r.severity)
6947 .fold(0.75f64, f64::min);
6948 drift.economic_cycle = datasynth_core::distributions::EconomicCycleConfig {
6949 enabled: true,
6950 cycle_length: ec.period_months,
6951 amplitude: ec.amplitude,
6952 phase_offset: ec.phase_offset,
6953 recession_periods,
6954 recession_severity: severity,
6955 };
6956 drift.drift_type = datasynth_core::distributions::DriftType::Mixed;
6957 }
6958 }
6959
6960 for pd in &self.parameter_drifts {
6962 let drift_type = match pd.drift_type {
6963 ParameterDriftTypeConfig::Linear => {
6964 datasynth_core::distributions::ParameterDriftType::Linear
6965 }
6966 ParameterDriftTypeConfig::Exponential => {
6967 datasynth_core::distributions::ParameterDriftType::Exponential
6968 }
6969 ParameterDriftTypeConfig::Logistic => {
6970 datasynth_core::distributions::ParameterDriftType::Logistic
6971 }
6972 ParameterDriftTypeConfig::Step => {
6973 datasynth_core::distributions::ParameterDriftType::Step
6974 }
6975 };
6976 drift
6977 .parameter_drifts
6978 .push(datasynth_core::distributions::ParameterDrift {
6979 parameter: pd.parameter.clone(),
6980 drift_type,
6981 initial_value: pd.start_value,
6982 target_or_rate: pd.end_value,
6983 start_period: pd.start_period,
6984 end_period: pd.end_period,
6985 steepness: 1.0,
6986 });
6987 }
6988 }
6989}
6990
6991fn convert_regime_change_type(
6992 t: RegimeChangeTypeConfig,
6993) -> datasynth_core::distributions::RegimeChangeType {
6994 use datasynth_core::distributions::RegimeChangeType as Core;
6995 match t {
6996 RegimeChangeTypeConfig::Acquisition => Core::Acquisition,
6997 RegimeChangeTypeConfig::Divestiture => Core::Divestiture,
6998 RegimeChangeTypeConfig::PriceIncrease => Core::PriceIncrease,
6999 RegimeChangeTypeConfig::PriceDecrease => Core::PriceDecrease,
7000 RegimeChangeTypeConfig::ProductLaunch => Core::ProductLaunch,
7001 RegimeChangeTypeConfig::ProductDiscontinuation => Core::ProductDiscontinuation,
7002 RegimeChangeTypeConfig::PolicyChange => Core::PolicyChange,
7003 RegimeChangeTypeConfig::CompetitorEntry => Core::CompetitorEntry,
7004 RegimeChangeTypeConfig::Custom => Core::Custom,
7005 }
7006}
7007
7008fn default_recession_severity() -> f64 {
7009 0.20
7010}
7011
7012#[derive(Debug, Clone, Serialize, Deserialize)]
7014pub struct ParameterDriftSchemaConfig {
7015 pub parameter: String,
7017
7018 pub drift_type: ParameterDriftTypeConfig,
7020
7021 pub start_value: f64,
7023
7024 pub end_value: f64,
7026
7027 #[serde(default)]
7029 pub start_period: u32,
7030
7031 #[serde(default)]
7033 pub end_period: Option<u32>,
7034}
7035
7036#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7038#[serde(rename_all = "snake_case")]
7039pub enum ParameterDriftTypeConfig {
7040 #[default]
7042 Linear,
7043 Exponential,
7045 Logistic,
7047 Step,
7049}
7050
7051#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7053pub struct StatisticalValidationSchemaConfig {
7054 #[serde(default)]
7056 pub enabled: bool,
7057
7058 #[serde(default)]
7060 pub tests: Vec<StatisticalTestConfig>,
7061
7062 #[serde(default)]
7064 pub reporting: ValidationReportingConfig,
7065}
7066
7067#[derive(Debug, Clone, Serialize, Deserialize)]
7069#[serde(tag = "type", rename_all = "snake_case")]
7070pub enum StatisticalTestConfig {
7071 BenfordFirstDigit {
7073 #[serde(default = "default_benford_threshold")]
7075 threshold_mad: f64,
7076 #[serde(default = "default_benford_warning")]
7078 warning_mad: f64,
7079 },
7080 DistributionFit {
7082 target: TargetDistributionConfig,
7084 #[serde(default = "default_ks_significance")]
7086 ks_significance: f64,
7087 #[serde(default)]
7089 method: DistributionFitMethod,
7090 },
7091 CorrelationCheck {
7093 expected_correlations: Vec<ExpectedCorrelationConfig>,
7095 },
7096 ChiSquared {
7098 #[serde(default = "default_chi_squared_bins")]
7100 bins: usize,
7101 #[serde(default = "default_chi_squared_significance")]
7103 significance: f64,
7104 },
7105 AndersonDarling {
7107 target: TargetDistributionConfig,
7109 #[serde(default = "default_ad_significance")]
7111 significance: f64,
7112 },
7113}
7114
7115fn default_benford_threshold() -> f64 {
7116 0.015
7117}
7118
7119fn default_benford_warning() -> f64 {
7120 0.010
7121}
7122
7123fn default_ks_significance() -> f64 {
7124 0.05
7125}
7126
7127fn default_chi_squared_bins() -> usize {
7128 10
7129}
7130
7131fn default_chi_squared_significance() -> f64 {
7132 0.05
7133}
7134
7135fn default_ad_significance() -> f64 {
7136 0.05
7137}
7138
7139#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7141#[serde(rename_all = "snake_case")]
7142pub enum TargetDistributionConfig {
7143 Normal,
7145 #[default]
7147 LogNormal,
7148 Exponential,
7150 Uniform,
7152}
7153
7154#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7156#[serde(rename_all = "snake_case")]
7157pub enum DistributionFitMethod {
7158 #[default]
7160 KolmogorovSmirnov,
7161 AndersonDarling,
7163 ChiSquared,
7165}
7166
7167#[derive(Debug, Clone, Serialize, Deserialize)]
7169pub struct ValidationReportingConfig {
7170 #[serde(default)]
7172 pub output_report: bool,
7173
7174 #[serde(default)]
7176 pub format: ValidationReportFormat,
7177
7178 #[serde(default)]
7180 pub fail_on_error: bool,
7181
7182 #[serde(default = "default_true")]
7184 pub include_details: bool,
7185}
7186
7187impl Default for ValidationReportingConfig {
7188 fn default() -> Self {
7189 Self {
7190 output_report: false,
7191 format: ValidationReportFormat::Json,
7192 fail_on_error: false,
7193 include_details: true,
7194 }
7195 }
7196}
7197
7198#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7200#[serde(rename_all = "snake_case")]
7201pub enum ValidationReportFormat {
7202 #[default]
7204 Json,
7205 Yaml,
7207 Html,
7209}
7210
7211#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7223pub struct TemporalPatternsConfig {
7224 #[serde(default)]
7226 pub enabled: bool,
7227
7228 #[serde(default)]
7230 pub business_days: BusinessDaySchemaConfig,
7231
7232 #[serde(default)]
7234 pub calendars: CalendarSchemaConfig,
7235
7236 #[serde(default)]
7238 pub period_end: PeriodEndSchemaConfig,
7239
7240 #[serde(default)]
7242 pub processing_lags: ProcessingLagSchemaConfig,
7243
7244 #[serde(default)]
7246 pub fiscal_calendar: FiscalCalendarSchemaConfig,
7247
7248 #[serde(default)]
7250 pub intraday: IntraDaySchemaConfig,
7251
7252 #[serde(default)]
7254 pub timezones: TimezoneSchemaConfig,
7255}
7256
7257#[derive(Debug, Clone, Serialize, Deserialize)]
7259pub struct BusinessDaySchemaConfig {
7260 #[serde(default = "default_true")]
7262 pub enabled: bool,
7263
7264 #[serde(default = "default_half_day_policy")]
7266 pub half_day_policy: String,
7267
7268 #[serde(default)]
7270 pub settlement_rules: SettlementRulesSchemaConfig,
7271
7272 #[serde(default = "default_month_end_convention")]
7274 pub month_end_convention: String,
7275
7276 #[serde(default)]
7278 pub weekend_days: Option<Vec<String>>,
7279}
7280
7281fn default_half_day_policy() -> String {
7282 "half_day".to_string()
7283}
7284
7285fn default_month_end_convention() -> String {
7286 "modified_following".to_string()
7287}
7288
7289impl Default for BusinessDaySchemaConfig {
7290 fn default() -> Self {
7291 Self {
7292 enabled: true,
7293 half_day_policy: "half_day".to_string(),
7294 settlement_rules: SettlementRulesSchemaConfig::default(),
7295 month_end_convention: "modified_following".to_string(),
7296 weekend_days: None,
7297 }
7298 }
7299}
7300
7301#[derive(Debug, Clone, Serialize, Deserialize)]
7303pub struct SettlementRulesSchemaConfig {
7304 #[serde(default = "default_settlement_2")]
7306 pub equity_days: i32,
7307
7308 #[serde(default = "default_settlement_1")]
7310 pub government_bonds_days: i32,
7311
7312 #[serde(default = "default_settlement_2")]
7314 pub fx_spot_days: i32,
7315
7316 #[serde(default = "default_settlement_2")]
7318 pub corporate_bonds_days: i32,
7319
7320 #[serde(default = "default_wire_cutoff")]
7322 pub wire_cutoff_time: String,
7323
7324 #[serde(default = "default_settlement_1")]
7326 pub wire_international_days: i32,
7327
7328 #[serde(default = "default_settlement_1")]
7330 pub ach_days: i32,
7331}
7332
7333fn default_settlement_1() -> i32 {
7334 1
7335}
7336
7337fn default_settlement_2() -> i32 {
7338 2
7339}
7340
7341fn default_wire_cutoff() -> String {
7342 "14:00".to_string()
7343}
7344
7345impl Default for SettlementRulesSchemaConfig {
7346 fn default() -> Self {
7347 Self {
7348 equity_days: 2,
7349 government_bonds_days: 1,
7350 fx_spot_days: 2,
7351 corporate_bonds_days: 2,
7352 wire_cutoff_time: "14:00".to_string(),
7353 wire_international_days: 1,
7354 ach_days: 1,
7355 }
7356 }
7357}
7358
7359#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7361pub struct CalendarSchemaConfig {
7362 #[serde(default)]
7364 pub regions: Vec<String>,
7365
7366 #[serde(default)]
7368 pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
7369}
7370
7371#[derive(Debug, Clone, Serialize, Deserialize)]
7373pub struct CustomHolidaySchemaConfig {
7374 pub name: String,
7376 pub month: u8,
7378 pub day: u8,
7380 #[serde(default = "default_holiday_multiplier")]
7382 pub activity_multiplier: f64,
7383}
7384
7385fn default_holiday_multiplier() -> f64 {
7386 0.05
7387}
7388
7389#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7391pub struct PeriodEndSchemaConfig {
7392 #[serde(default)]
7394 pub model: Option<String>,
7395
7396 #[serde(default)]
7398 pub month_end: Option<PeriodEndModelSchemaConfig>,
7399
7400 #[serde(default)]
7402 pub quarter_end: Option<PeriodEndModelSchemaConfig>,
7403
7404 #[serde(default)]
7406 pub year_end: Option<PeriodEndModelSchemaConfig>,
7407}
7408
7409#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7411pub struct PeriodEndModelSchemaConfig {
7412 #[serde(default)]
7414 pub inherit_from: Option<String>,
7415
7416 #[serde(default)]
7418 pub additional_multiplier: Option<f64>,
7419
7420 #[serde(default)]
7422 pub start_day: Option<i32>,
7423
7424 #[serde(default)]
7426 pub base_multiplier: Option<f64>,
7427
7428 #[serde(default)]
7430 pub peak_multiplier: Option<f64>,
7431
7432 #[serde(default)]
7434 pub decay_rate: Option<f64>,
7435
7436 #[serde(default)]
7438 pub sustained_high_days: Option<i32>,
7439}
7440
7441#[derive(Debug, Clone, Serialize, Deserialize)]
7443pub struct ProcessingLagSchemaConfig {
7444 #[serde(default = "default_true")]
7446 pub enabled: bool,
7447
7448 #[serde(default)]
7450 pub sales_order_lag: Option<LagDistributionSchemaConfig>,
7451
7452 #[serde(default)]
7454 pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
7455
7456 #[serde(default)]
7458 pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
7459
7460 #[serde(default)]
7462 pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
7463
7464 #[serde(default)]
7466 pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
7467
7468 #[serde(default)]
7470 pub payment_lag: Option<LagDistributionSchemaConfig>,
7471
7472 #[serde(default)]
7474 pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
7475
7476 #[serde(default)]
7478 pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
7479}
7480
7481impl Default for ProcessingLagSchemaConfig {
7482 fn default() -> Self {
7483 Self {
7484 enabled: true,
7485 sales_order_lag: None,
7486 purchase_order_lag: None,
7487 goods_receipt_lag: None,
7488 invoice_receipt_lag: None,
7489 invoice_issue_lag: None,
7490 payment_lag: None,
7491 journal_entry_lag: None,
7492 cross_day_posting: None,
7493 }
7494 }
7495}
7496
7497#[derive(Debug, Clone, Serialize, Deserialize)]
7499pub struct LagDistributionSchemaConfig {
7500 pub mu: f64,
7502 pub sigma: f64,
7504 #[serde(default)]
7506 pub min_hours: Option<f64>,
7507 #[serde(default)]
7509 pub max_hours: Option<f64>,
7510}
7511
7512#[derive(Debug, Clone, Serialize, Deserialize)]
7514pub struct CrossDayPostingSchemaConfig {
7515 #[serde(default = "default_true")]
7517 pub enabled: bool,
7518
7519 #[serde(default)]
7522 pub probability_by_hour: std::collections::HashMap<u8, f64>,
7523}
7524
7525impl Default for CrossDayPostingSchemaConfig {
7526 fn default() -> Self {
7527 let mut probability_by_hour = std::collections::HashMap::new();
7528 probability_by_hour.insert(17, 0.3);
7529 probability_by_hour.insert(18, 0.6);
7530 probability_by_hour.insert(19, 0.8);
7531 probability_by_hour.insert(20, 0.9);
7532 probability_by_hour.insert(21, 0.95);
7533 probability_by_hour.insert(22, 0.99);
7534
7535 Self {
7536 enabled: true,
7537 probability_by_hour,
7538 }
7539 }
7540}
7541
7542#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7551pub struct FiscalCalendarSchemaConfig {
7552 #[serde(default)]
7554 pub enabled: bool,
7555
7556 #[serde(default = "default_fiscal_calendar_type")]
7558 pub calendar_type: String,
7559
7560 #[serde(default)]
7562 pub year_start_month: Option<u8>,
7563
7564 #[serde(default)]
7566 pub year_start_day: Option<u8>,
7567
7568 #[serde(default)]
7570 pub four_four_five: Option<FourFourFiveSchemaConfig>,
7571}
7572
7573fn default_fiscal_calendar_type() -> String {
7574 "calendar_year".to_string()
7575}
7576
7577#[derive(Debug, Clone, Serialize, Deserialize)]
7579pub struct FourFourFiveSchemaConfig {
7580 #[serde(default = "default_week_pattern")]
7582 pub pattern: String,
7583
7584 #[serde(default = "default_anchor_type")]
7586 pub anchor_type: String,
7587
7588 #[serde(default = "default_anchor_month")]
7590 pub anchor_month: u8,
7591
7592 #[serde(default = "default_leap_week_placement")]
7594 pub leap_week_placement: String,
7595}
7596
7597fn default_week_pattern() -> String {
7598 "four_four_five".to_string()
7599}
7600
7601fn default_anchor_type() -> String {
7602 "last_saturday".to_string()
7603}
7604
7605fn default_anchor_month() -> u8 {
7606 1 }
7608
7609fn default_leap_week_placement() -> String {
7610 "q4_period3".to_string()
7611}
7612
7613impl Default for FourFourFiveSchemaConfig {
7614 fn default() -> Self {
7615 Self {
7616 pattern: "four_four_five".to_string(),
7617 anchor_type: "last_saturday".to_string(),
7618 anchor_month: 1,
7619 leap_week_placement: "q4_period3".to_string(),
7620 }
7621 }
7622}
7623
7624#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7633pub struct IntraDaySchemaConfig {
7634 #[serde(default)]
7636 pub enabled: bool,
7637
7638 #[serde(default)]
7640 pub segments: Vec<IntraDaySegmentSchemaConfig>,
7641}
7642
7643#[derive(Debug, Clone, Serialize, Deserialize)]
7645pub struct IntraDaySegmentSchemaConfig {
7646 pub name: String,
7648
7649 pub start: String,
7651
7652 pub end: String,
7654
7655 #[serde(default = "default_multiplier")]
7657 pub multiplier: f64,
7658
7659 #[serde(default = "default_posting_type")]
7661 pub posting_type: String,
7662}
7663
7664fn default_multiplier() -> f64 {
7665 1.0
7666}
7667
7668fn default_posting_type() -> String {
7669 "both".to_string()
7670}
7671
7672#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7678pub struct TimezoneSchemaConfig {
7679 #[serde(default)]
7681 pub enabled: bool,
7682
7683 #[serde(default = "default_timezone")]
7685 pub default_timezone: String,
7686
7687 #[serde(default = "default_consolidation_timezone")]
7689 pub consolidation_timezone: String,
7690
7691 #[serde(default)]
7694 pub entity_mappings: Vec<EntityTimezoneMapping>,
7695}
7696
7697fn default_timezone() -> String {
7698 "America/New_York".to_string()
7699}
7700
7701fn default_consolidation_timezone() -> String {
7702 "UTC".to_string()
7703}
7704
7705#[derive(Debug, Clone, Serialize, Deserialize)]
7707pub struct EntityTimezoneMapping {
7708 pub pattern: String,
7710
7711 pub timezone: String,
7713}
7714
7715#[derive(Debug, Clone, Serialize, Deserialize)]
7721pub struct VendorNetworkSchemaConfig {
7722 #[serde(default)]
7724 pub enabled: bool,
7725
7726 #[serde(default = "default_vendor_tier_depth")]
7728 pub depth: u8,
7729
7730 #[serde(default)]
7732 pub tier1: TierCountSchemaConfig,
7733
7734 #[serde(default)]
7736 pub tier2_per_parent: TierCountSchemaConfig,
7737
7738 #[serde(default)]
7740 pub tier3_per_parent: TierCountSchemaConfig,
7741
7742 #[serde(default)]
7744 pub clusters: VendorClusterSchemaConfig,
7745
7746 #[serde(default)]
7748 pub dependencies: DependencySchemaConfig,
7749}
7750
7751fn default_vendor_tier_depth() -> u8 {
7752 3
7753}
7754
7755impl Default for VendorNetworkSchemaConfig {
7756 fn default() -> Self {
7757 Self {
7758 enabled: false,
7759 depth: 3,
7760 tier1: TierCountSchemaConfig { min: 50, max: 100 },
7761 tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
7762 tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
7763 clusters: VendorClusterSchemaConfig::default(),
7764 dependencies: DependencySchemaConfig::default(),
7765 }
7766 }
7767}
7768
7769#[derive(Debug, Clone, Serialize, Deserialize)]
7771pub struct TierCountSchemaConfig {
7772 #[serde(default = "default_tier_min")]
7774 pub min: usize,
7775
7776 #[serde(default = "default_tier_max")]
7778 pub max: usize,
7779}
7780
7781fn default_tier_min() -> usize {
7782 5
7783}
7784
7785fn default_tier_max() -> usize {
7786 20
7787}
7788
7789impl Default for TierCountSchemaConfig {
7790 fn default() -> Self {
7791 Self {
7792 min: default_tier_min(),
7793 max: default_tier_max(),
7794 }
7795 }
7796}
7797
7798#[derive(Debug, Clone, Serialize, Deserialize)]
7800pub struct VendorClusterSchemaConfig {
7801 #[serde(default = "default_reliable_strategic")]
7803 pub reliable_strategic: f64,
7804
7805 #[serde(default = "default_standard_operational")]
7807 pub standard_operational: f64,
7808
7809 #[serde(default = "default_transactional")]
7811 pub transactional: f64,
7812
7813 #[serde(default = "default_problematic")]
7815 pub problematic: f64,
7816}
7817
7818fn default_reliable_strategic() -> f64 {
7819 0.20
7820}
7821
7822fn default_standard_operational() -> f64 {
7823 0.50
7824}
7825
7826fn default_transactional() -> f64 {
7827 0.25
7828}
7829
7830fn default_problematic() -> f64 {
7831 0.05
7832}
7833
7834impl Default for VendorClusterSchemaConfig {
7835 fn default() -> Self {
7836 Self {
7837 reliable_strategic: 0.20,
7838 standard_operational: 0.50,
7839 transactional: 0.25,
7840 problematic: 0.05,
7841 }
7842 }
7843}
7844
7845#[derive(Debug, Clone, Serialize, Deserialize)]
7847pub struct DependencySchemaConfig {
7848 #[serde(default = "default_max_single_vendor")]
7850 pub max_single_vendor_concentration: f64,
7851
7852 #[serde(default = "default_max_top5")]
7854 pub top_5_concentration: f64,
7855
7856 #[serde(default = "default_single_source_percent")]
7858 pub single_source_percent: f64,
7859}
7860
7861fn default_max_single_vendor() -> f64 {
7862 0.15
7863}
7864
7865fn default_max_top5() -> f64 {
7866 0.45
7867}
7868
7869fn default_single_source_percent() -> f64 {
7870 0.05
7871}
7872
7873impl Default for DependencySchemaConfig {
7874 fn default() -> Self {
7875 Self {
7876 max_single_vendor_concentration: 0.15,
7877 top_5_concentration: 0.45,
7878 single_source_percent: 0.05,
7879 }
7880 }
7881}
7882
7883#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7889pub struct CustomerSegmentationSchemaConfig {
7890 #[serde(default)]
7892 pub enabled: bool,
7893
7894 #[serde(default)]
7896 pub value_segments: ValueSegmentsSchemaConfig,
7897
7898 #[serde(default)]
7900 pub lifecycle: LifecycleSchemaConfig,
7901
7902 #[serde(default)]
7904 pub networks: CustomerNetworksSchemaConfig,
7905}
7906
7907#[derive(Debug, Clone, Serialize, Deserialize)]
7909pub struct ValueSegmentsSchemaConfig {
7910 #[serde(default)]
7912 pub enterprise: SegmentDetailSchemaConfig,
7913
7914 #[serde(default)]
7916 pub mid_market: SegmentDetailSchemaConfig,
7917
7918 #[serde(default)]
7920 pub smb: SegmentDetailSchemaConfig,
7921
7922 #[serde(default)]
7924 pub consumer: SegmentDetailSchemaConfig,
7925}
7926
7927impl Default for ValueSegmentsSchemaConfig {
7928 fn default() -> Self {
7929 Self {
7930 enterprise: SegmentDetailSchemaConfig {
7931 revenue_share: 0.40,
7932 customer_share: 0.05,
7933 avg_order_value_range: "50000+".to_string(),
7934 },
7935 mid_market: SegmentDetailSchemaConfig {
7936 revenue_share: 0.35,
7937 customer_share: 0.20,
7938 avg_order_value_range: "5000-50000".to_string(),
7939 },
7940 smb: SegmentDetailSchemaConfig {
7941 revenue_share: 0.20,
7942 customer_share: 0.50,
7943 avg_order_value_range: "500-5000".to_string(),
7944 },
7945 consumer: SegmentDetailSchemaConfig {
7946 revenue_share: 0.05,
7947 customer_share: 0.25,
7948 avg_order_value_range: "50-500".to_string(),
7949 },
7950 }
7951 }
7952}
7953
7954#[derive(Debug, Clone, Serialize, Deserialize)]
7956pub struct SegmentDetailSchemaConfig {
7957 #[serde(default)]
7959 pub revenue_share: f64,
7960
7961 #[serde(default)]
7963 pub customer_share: f64,
7964
7965 #[serde(default)]
7967 pub avg_order_value_range: String,
7968}
7969
7970impl Default for SegmentDetailSchemaConfig {
7971 fn default() -> Self {
7972 Self {
7973 revenue_share: 0.25,
7974 customer_share: 0.25,
7975 avg_order_value_range: "1000-10000".to_string(),
7976 }
7977 }
7978}
7979
7980#[derive(Debug, Clone, Serialize, Deserialize)]
7982pub struct LifecycleSchemaConfig {
7983 #[serde(default)]
7985 pub prospect_rate: f64,
7986
7987 #[serde(default = "default_new_rate")]
7989 pub new_rate: f64,
7990
7991 #[serde(default = "default_growth_rate")]
7993 pub growth_rate: f64,
7994
7995 #[serde(default = "default_mature_rate")]
7997 pub mature_rate: f64,
7998
7999 #[serde(default = "default_at_risk_rate")]
8001 pub at_risk_rate: f64,
8002
8003 #[serde(default = "default_churned_rate")]
8005 pub churned_rate: f64,
8006
8007 #[serde(default)]
8009 pub won_back_rate: f64,
8010}
8011
8012fn default_new_rate() -> f64 {
8013 0.10
8014}
8015
8016fn default_growth_rate() -> f64 {
8017 0.15
8018}
8019
8020fn default_mature_rate() -> f64 {
8021 0.60
8022}
8023
8024fn default_at_risk_rate() -> f64 {
8025 0.10
8026}
8027
8028fn default_churned_rate() -> f64 {
8029 0.05
8030}
8031
8032impl Default for LifecycleSchemaConfig {
8033 fn default() -> Self {
8034 Self {
8035 prospect_rate: 0.0,
8036 new_rate: 0.10,
8037 growth_rate: 0.15,
8038 mature_rate: 0.60,
8039 at_risk_rate: 0.10,
8040 churned_rate: 0.05,
8041 won_back_rate: 0.0,
8042 }
8043 }
8044}
8045
8046#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8048pub struct CustomerNetworksSchemaConfig {
8049 #[serde(default)]
8051 pub referrals: ReferralSchemaConfig,
8052
8053 #[serde(default)]
8055 pub corporate_hierarchies: HierarchySchemaConfig,
8056}
8057
8058#[derive(Debug, Clone, Serialize, Deserialize)]
8060pub struct ReferralSchemaConfig {
8061 #[serde(default = "default_true")]
8063 pub enabled: bool,
8064
8065 #[serde(default = "default_referral_rate")]
8067 pub referral_rate: f64,
8068}
8069
8070fn default_referral_rate() -> f64 {
8071 0.15
8072}
8073
8074impl Default for ReferralSchemaConfig {
8075 fn default() -> Self {
8076 Self {
8077 enabled: true,
8078 referral_rate: 0.15,
8079 }
8080 }
8081}
8082
8083#[derive(Debug, Clone, Serialize, Deserialize)]
8085pub struct HierarchySchemaConfig {
8086 #[serde(default = "default_true")]
8088 pub enabled: bool,
8089
8090 #[serde(default = "default_hierarchy_rate")]
8092 pub probability: f64,
8093}
8094
8095fn default_hierarchy_rate() -> f64 {
8096 0.30
8097}
8098
8099impl Default for HierarchySchemaConfig {
8100 fn default() -> Self {
8101 Self {
8102 enabled: true,
8103 probability: 0.30,
8104 }
8105 }
8106}
8107
8108#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8114pub struct RelationshipStrengthSchemaConfig {
8115 #[serde(default)]
8117 pub enabled: bool,
8118
8119 #[serde(default)]
8121 pub calculation: StrengthCalculationSchemaConfig,
8122
8123 #[serde(default)]
8125 pub thresholds: StrengthThresholdsSchemaConfig,
8126}
8127
8128#[derive(Debug, Clone, Serialize, Deserialize)]
8130pub struct StrengthCalculationSchemaConfig {
8131 #[serde(default = "default_volume_weight")]
8133 pub transaction_volume_weight: f64,
8134
8135 #[serde(default = "default_count_weight")]
8137 pub transaction_count_weight: f64,
8138
8139 #[serde(default = "default_duration_weight")]
8141 pub relationship_duration_weight: f64,
8142
8143 #[serde(default = "default_recency_weight")]
8145 pub recency_weight: f64,
8146
8147 #[serde(default = "default_mutual_weight")]
8149 pub mutual_connections_weight: f64,
8150
8151 #[serde(default = "default_recency_half_life")]
8153 pub recency_half_life_days: u32,
8154}
8155
8156fn default_volume_weight() -> f64 {
8157 0.30
8158}
8159
8160fn default_count_weight() -> f64 {
8161 0.25
8162}
8163
8164fn default_duration_weight() -> f64 {
8165 0.20
8166}
8167
8168fn default_recency_weight() -> f64 {
8169 0.15
8170}
8171
8172fn default_mutual_weight() -> f64 {
8173 0.10
8174}
8175
8176fn default_recency_half_life() -> u32 {
8177 90
8178}
8179
8180impl Default for StrengthCalculationSchemaConfig {
8181 fn default() -> Self {
8182 Self {
8183 transaction_volume_weight: 0.30,
8184 transaction_count_weight: 0.25,
8185 relationship_duration_weight: 0.20,
8186 recency_weight: 0.15,
8187 mutual_connections_weight: 0.10,
8188 recency_half_life_days: 90,
8189 }
8190 }
8191}
8192
8193#[derive(Debug, Clone, Serialize, Deserialize)]
8195pub struct StrengthThresholdsSchemaConfig {
8196 #[serde(default = "default_strong_threshold")]
8198 pub strong: f64,
8199
8200 #[serde(default = "default_moderate_threshold")]
8202 pub moderate: f64,
8203
8204 #[serde(default = "default_weak_threshold")]
8206 pub weak: f64,
8207}
8208
8209fn default_strong_threshold() -> f64 {
8210 0.7
8211}
8212
8213fn default_moderate_threshold() -> f64 {
8214 0.4
8215}
8216
8217fn default_weak_threshold() -> f64 {
8218 0.1
8219}
8220
8221impl Default for StrengthThresholdsSchemaConfig {
8222 fn default() -> Self {
8223 Self {
8224 strong: 0.7,
8225 moderate: 0.4,
8226 weak: 0.1,
8227 }
8228 }
8229}
8230
8231#[derive(Debug, Clone, Serialize, Deserialize)]
8237pub struct CrossProcessLinksSchemaConfig {
8238 #[serde(default)]
8240 pub enabled: bool,
8241
8242 #[serde(default = "default_true")]
8244 pub inventory_p2p_o2c: bool,
8245
8246 #[serde(default = "default_true")]
8248 pub payment_bank_reconciliation: bool,
8249
8250 #[serde(default = "default_true")]
8252 pub intercompany_bilateral: bool,
8253
8254 #[serde(default = "default_inventory_link_rate")]
8256 pub inventory_link_rate: f64,
8257}
8258
8259fn default_inventory_link_rate() -> f64 {
8260 0.30
8261}
8262
8263impl Default for CrossProcessLinksSchemaConfig {
8264 fn default() -> Self {
8265 Self {
8266 enabled: false,
8267 inventory_p2p_o2c: true,
8268 payment_bank_reconciliation: true,
8269 intercompany_bilateral: true,
8270 inventory_link_rate: 0.30,
8271 }
8272 }
8273}
8274
8275#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8281pub struct OrganizationalEventsSchemaConfig {
8282 #[serde(default)]
8284 pub enabled: bool,
8285
8286 #[serde(default)]
8288 pub effect_blending: EffectBlendingModeConfig,
8289
8290 #[serde(default)]
8292 pub events: Vec<OrganizationalEventSchemaConfig>,
8293
8294 #[serde(default)]
8296 pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
8297
8298 #[serde(default)]
8300 pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
8301}
8302
8303#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8305#[serde(rename_all = "snake_case")]
8306pub enum EffectBlendingModeConfig {
8307 #[default]
8309 Multiplicative,
8310 Additive,
8312 Maximum,
8314 Minimum,
8316}
8317
8318#[derive(Debug, Clone, Serialize, Deserialize)]
8320pub struct OrganizationalEventSchemaConfig {
8321 pub id: String,
8323
8324 pub event_type: OrganizationalEventTypeSchemaConfig,
8326
8327 pub effective_date: String,
8329
8330 #[serde(default = "default_org_transition_months")]
8332 pub transition_months: u32,
8333
8334 #[serde(default)]
8336 pub description: Option<String>,
8337}
8338
8339fn default_org_transition_months() -> u32 {
8340 6
8341}
8342
8343#[derive(Debug, Clone, Serialize, Deserialize)]
8345#[serde(tag = "type", rename_all = "snake_case")]
8346pub enum OrganizationalEventTypeSchemaConfig {
8347 Acquisition {
8349 acquired_entity: String,
8351 #[serde(default = "default_acquisition_volume")]
8353 volume_increase: f64,
8354 #[serde(default = "default_acquisition_error")]
8356 integration_error_rate: f64,
8357 #[serde(default = "default_parallel_days")]
8359 parallel_posting_days: u32,
8360 },
8361 Divestiture {
8363 divested_entity: String,
8365 #[serde(default = "default_divestiture_volume")]
8367 volume_reduction: f64,
8368 #[serde(default = "default_true_val")]
8370 remove_entity: bool,
8371 },
8372 Reorganization {
8374 #[serde(default)]
8376 cost_center_remapping: std::collections::HashMap<String, String>,
8377 #[serde(default = "default_reorg_error")]
8379 transition_error_rate: f64,
8380 },
8381 LeadershipChange {
8383 role: String,
8385 #[serde(default)]
8387 policy_changes: Vec<String>,
8388 },
8389 WorkforceReduction {
8391 #[serde(default = "default_workforce_reduction")]
8393 reduction_percent: f64,
8394 #[serde(default = "default_workforce_error")]
8396 error_rate_increase: f64,
8397 },
8398 Merger {
8400 merged_entity: String,
8402 #[serde(default = "default_merger_volume")]
8404 volume_increase: f64,
8405 },
8406}
8407
8408fn default_acquisition_volume() -> f64 {
8409 1.35
8410}
8411
8412fn default_acquisition_error() -> f64 {
8413 0.05
8414}
8415
8416fn default_parallel_days() -> u32 {
8417 30
8418}
8419
8420fn default_divestiture_volume() -> f64 {
8421 0.70
8422}
8423
8424fn default_true_val() -> bool {
8425 true
8426}
8427
8428fn default_reorg_error() -> f64 {
8429 0.04
8430}
8431
8432fn default_workforce_reduction() -> f64 {
8433 0.10
8434}
8435
8436fn default_workforce_error() -> f64 {
8437 0.05
8438}
8439
8440fn default_merger_volume() -> f64 {
8441 1.80
8442}
8443
8444#[derive(Debug, Clone, Serialize, Deserialize)]
8446pub struct ProcessEvolutionSchemaConfig {
8447 pub id: String,
8449
8450 pub event_type: ProcessEvolutionTypeSchemaConfig,
8452
8453 pub effective_date: String,
8455
8456 #[serde(default)]
8458 pub description: Option<String>,
8459}
8460
8461#[derive(Debug, Clone, Serialize, Deserialize)]
8463#[serde(tag = "type", rename_all = "snake_case")]
8464pub enum ProcessEvolutionTypeSchemaConfig {
8465 ProcessAutomation {
8467 process_name: String,
8469 #[serde(default = "default_manual_before")]
8471 manual_rate_before: f64,
8472 #[serde(default = "default_manual_after")]
8474 manual_rate_after: f64,
8475 },
8476 ApprovalWorkflowChange {
8478 description: String,
8480 },
8481 ControlEnhancement {
8483 control_id: String,
8485 #[serde(default = "default_error_reduction")]
8487 error_reduction: f64,
8488 },
8489}
8490
8491fn default_manual_before() -> f64 {
8492 0.80
8493}
8494
8495fn default_manual_after() -> f64 {
8496 0.15
8497}
8498
8499fn default_error_reduction() -> f64 {
8500 0.02
8501}
8502
8503#[derive(Debug, Clone, Serialize, Deserialize)]
8505pub struct TechnologyTransitionSchemaConfig {
8506 pub id: String,
8508
8509 pub event_type: TechnologyTransitionTypeSchemaConfig,
8511
8512 #[serde(default)]
8514 pub description: Option<String>,
8515}
8516
8517#[derive(Debug, Clone, Serialize, Deserialize)]
8519#[serde(tag = "type", rename_all = "snake_case")]
8520pub enum TechnologyTransitionTypeSchemaConfig {
8521 ErpMigration {
8523 source_system: String,
8525 target_system: String,
8527 cutover_date: String,
8529 stabilization_end: String,
8531 #[serde(default = "default_erp_duplicate_rate")]
8533 duplicate_rate: f64,
8534 #[serde(default = "default_format_mismatch")]
8536 format_mismatch_rate: f64,
8537 },
8538 ModuleImplementation {
8540 module_name: String,
8542 go_live_date: String,
8544 },
8545}
8546
8547fn default_erp_duplicate_rate() -> f64 {
8548 0.02
8549}
8550
8551fn default_format_mismatch() -> f64 {
8552 0.03
8553}
8554
8555#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8570pub struct BehavioralDriftSchemaConfig {
8571 #[serde(default)]
8573 pub enabled: bool,
8574
8575 #[serde(default)]
8577 pub vendor_behavior: VendorBehaviorSchemaConfig,
8578
8579 #[serde(default)]
8581 pub customer_behavior: CustomerBehaviorSchemaConfig,
8582
8583 #[serde(default)]
8585 pub employee_behavior: EmployeeBehaviorSchemaConfig,
8586
8587 #[serde(default)]
8589 pub collective: CollectiveBehaviorSchemaConfig,
8590}
8591
8592#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8594pub struct VendorBehaviorSchemaConfig {
8595 #[serde(default)]
8597 pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
8598
8599 #[serde(default)]
8601 pub quality_drift: QualityDriftSchemaConfig,
8602}
8603
8604#[derive(Debug, Clone, Serialize, Deserialize)]
8606pub struct PaymentTermsDriftSchemaConfig {
8607 #[serde(default = "default_extension_rate")]
8609 pub extension_rate_per_year: f64,
8610
8611 #[serde(default = "default_economic_sensitivity")]
8613 pub economic_sensitivity: f64,
8614}
8615
8616fn default_extension_rate() -> f64 {
8617 2.5
8618}
8619
8620fn default_economic_sensitivity() -> f64 {
8621 1.0
8622}
8623
8624impl Default for PaymentTermsDriftSchemaConfig {
8625 fn default() -> Self {
8626 Self {
8627 extension_rate_per_year: 2.5,
8628 economic_sensitivity: 1.0,
8629 }
8630 }
8631}
8632
8633#[derive(Debug, Clone, Serialize, Deserialize)]
8635pub struct QualityDriftSchemaConfig {
8636 #[serde(default = "default_improvement_rate")]
8638 pub new_vendor_improvement_rate: f64,
8639
8640 #[serde(default = "default_decline_rate")]
8642 pub complacency_decline_rate: f64,
8643}
8644
8645fn default_improvement_rate() -> f64 {
8646 0.02
8647}
8648
8649fn default_decline_rate() -> f64 {
8650 0.01
8651}
8652
8653impl Default for QualityDriftSchemaConfig {
8654 fn default() -> Self {
8655 Self {
8656 new_vendor_improvement_rate: 0.02,
8657 complacency_decline_rate: 0.01,
8658 }
8659 }
8660}
8661
8662#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8664pub struct CustomerBehaviorSchemaConfig {
8665 #[serde(default)]
8667 pub payment_drift: CustomerPaymentDriftSchemaConfig,
8668
8669 #[serde(default)]
8671 pub order_drift: OrderDriftSchemaConfig,
8672}
8673
8674#[derive(Debug, Clone, Serialize, Deserialize)]
8676pub struct CustomerPaymentDriftSchemaConfig {
8677 #[serde(default = "default_downturn_extension")]
8679 pub downturn_days_extension: (u32, u32),
8680
8681 #[serde(default = "default_bad_debt_increase")]
8683 pub downturn_bad_debt_increase: f64,
8684}
8685
8686fn default_downturn_extension() -> (u32, u32) {
8687 (5, 15)
8688}
8689
8690fn default_bad_debt_increase() -> f64 {
8691 0.02
8692}
8693
8694impl Default for CustomerPaymentDriftSchemaConfig {
8695 fn default() -> Self {
8696 Self {
8697 downturn_days_extension: (5, 15),
8698 downturn_bad_debt_increase: 0.02,
8699 }
8700 }
8701}
8702
8703#[derive(Debug, Clone, Serialize, Deserialize)]
8705pub struct OrderDriftSchemaConfig {
8706 #[serde(default = "default_digital_shift")]
8708 pub digital_shift_rate: f64,
8709}
8710
8711fn default_digital_shift() -> f64 {
8712 0.05
8713}
8714
8715impl Default for OrderDriftSchemaConfig {
8716 fn default() -> Self {
8717 Self {
8718 digital_shift_rate: 0.05,
8719 }
8720 }
8721}
8722
8723#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8725pub struct EmployeeBehaviorSchemaConfig {
8726 #[serde(default)]
8728 pub approval_drift: ApprovalDriftSchemaConfig,
8729
8730 #[serde(default)]
8732 pub error_drift: ErrorDriftSchemaConfig,
8733}
8734
8735#[derive(Debug, Clone, Serialize, Deserialize)]
8737pub struct ApprovalDriftSchemaConfig {
8738 #[serde(default = "default_eom_intensity")]
8740 pub eom_intensity_increase_per_year: f64,
8741
8742 #[serde(default = "default_rubber_stamp")]
8744 pub rubber_stamp_volume_threshold: u32,
8745}
8746
8747fn default_eom_intensity() -> f64 {
8748 0.05
8749}
8750
8751fn default_rubber_stamp() -> u32 {
8752 50
8753}
8754
8755impl Default for ApprovalDriftSchemaConfig {
8756 fn default() -> Self {
8757 Self {
8758 eom_intensity_increase_per_year: 0.05,
8759 rubber_stamp_volume_threshold: 50,
8760 }
8761 }
8762}
8763
8764#[derive(Debug, Clone, Serialize, Deserialize)]
8766pub struct ErrorDriftSchemaConfig {
8767 #[serde(default = "default_new_error")]
8769 pub new_employee_error_rate: f64,
8770
8771 #[serde(default = "default_learning_months")]
8773 pub learning_curve_months: u32,
8774}
8775
8776fn default_new_error() -> f64 {
8777 0.08
8778}
8779
8780fn default_learning_months() -> u32 {
8781 6
8782}
8783
8784impl Default for ErrorDriftSchemaConfig {
8785 fn default() -> Self {
8786 Self {
8787 new_employee_error_rate: 0.08,
8788 learning_curve_months: 6,
8789 }
8790 }
8791}
8792
8793#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8795pub struct CollectiveBehaviorSchemaConfig {
8796 #[serde(default)]
8798 pub automation_adoption: AutomationAdoptionSchemaConfig,
8799}
8800
8801#[derive(Debug, Clone, Serialize, Deserialize)]
8803pub struct AutomationAdoptionSchemaConfig {
8804 #[serde(default)]
8806 pub s_curve_enabled: bool,
8807
8808 #[serde(default = "default_midpoint")]
8810 pub adoption_midpoint_months: u32,
8811
8812 #[serde(default = "default_steepness")]
8814 pub steepness: f64,
8815}
8816
8817fn default_midpoint() -> u32 {
8818 24
8819}
8820
8821fn default_steepness() -> f64 {
8822 0.15
8823}
8824
8825impl Default for AutomationAdoptionSchemaConfig {
8826 fn default() -> Self {
8827 Self {
8828 s_curve_enabled: false,
8829 adoption_midpoint_months: 24,
8830 steepness: 0.15,
8831 }
8832 }
8833}
8834
8835#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8848pub struct MarketDriftSchemaConfig {
8849 #[serde(default)]
8851 pub enabled: bool,
8852
8853 #[serde(default)]
8855 pub economic_cycle: MarketEconomicCycleSchemaConfig,
8856
8857 #[serde(default)]
8859 pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
8860
8861 #[serde(default)]
8863 pub commodities: CommoditiesSchemaConfig,
8864}
8865
8866#[derive(Debug, Clone, Serialize, Deserialize)]
8868pub struct MarketEconomicCycleSchemaConfig {
8869 #[serde(default)]
8871 pub enabled: bool,
8872
8873 #[serde(default)]
8875 pub cycle_type: CycleTypeSchemaConfig,
8876
8877 #[serde(default = "default_market_cycle_period")]
8879 pub period_months: u32,
8880
8881 #[serde(default = "default_market_amplitude")]
8883 pub amplitude: f64,
8884
8885 #[serde(default)]
8887 pub recession: RecessionSchemaConfig,
8888}
8889
8890fn default_market_cycle_period() -> u32 {
8891 48
8892}
8893
8894fn default_market_amplitude() -> f64 {
8895 0.15
8896}
8897
8898impl Default for MarketEconomicCycleSchemaConfig {
8899 fn default() -> Self {
8900 Self {
8901 enabled: false,
8902 cycle_type: CycleTypeSchemaConfig::Sinusoidal,
8903 period_months: 48,
8904 amplitude: 0.15,
8905 recession: RecessionSchemaConfig::default(),
8906 }
8907 }
8908}
8909
8910#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8912#[serde(rename_all = "snake_case")]
8913pub enum CycleTypeSchemaConfig {
8914 #[default]
8916 Sinusoidal,
8917 Asymmetric,
8919 MeanReverting,
8921}
8922
8923#[derive(Debug, Clone, Serialize, Deserialize)]
8925pub struct RecessionSchemaConfig {
8926 #[serde(default)]
8928 pub enabled: bool,
8929
8930 #[serde(default = "default_recession_prob")]
8932 pub probability_per_year: f64,
8933
8934 #[serde(default)]
8936 pub severity: RecessionSeveritySchemaConfig,
8937
8938 #[serde(default)]
8940 pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
8941}
8942
8943fn default_recession_prob() -> f64 {
8944 0.10
8945}
8946
8947impl Default for RecessionSchemaConfig {
8948 fn default() -> Self {
8949 Self {
8950 enabled: false,
8951 probability_per_year: 0.10,
8952 severity: RecessionSeveritySchemaConfig::Moderate,
8953 recession_periods: Vec::new(),
8954 }
8955 }
8956}
8957
8958#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
8960#[serde(rename_all = "snake_case")]
8961pub enum RecessionSeveritySchemaConfig {
8962 Mild,
8964 #[default]
8966 Moderate,
8967 Severe,
8969}
8970
8971#[derive(Debug, Clone, Serialize, Deserialize)]
8973pub struct RecessionPeriodSchemaConfig {
8974 pub start_month: u32,
8976 pub duration_months: u32,
8978}
8979
8980#[derive(Debug, Clone, Serialize, Deserialize)]
8982pub struct IndustryCycleSchemaConfig {
8983 #[serde(default = "default_industry_period")]
8985 pub period_months: u32,
8986
8987 #[serde(default = "default_industry_amp")]
8989 pub amplitude: f64,
8990}
8991
8992fn default_industry_period() -> u32 {
8993 36
8994}
8995
8996fn default_industry_amp() -> f64 {
8997 0.20
8998}
8999
9000#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9002pub struct CommoditiesSchemaConfig {
9003 #[serde(default)]
9005 pub enabled: bool,
9006
9007 #[serde(default)]
9009 pub items: Vec<CommodityItemSchemaConfig>,
9010}
9011
9012#[derive(Debug, Clone, Serialize, Deserialize)]
9014pub struct CommodityItemSchemaConfig {
9015 pub name: String,
9017
9018 #[serde(default = "default_volatility")]
9020 pub volatility: f64,
9021
9022 #[serde(default)]
9024 pub cogs_pass_through: f64,
9025
9026 #[serde(default)]
9028 pub overhead_pass_through: f64,
9029}
9030
9031fn default_volatility() -> f64 {
9032 0.20
9033}
9034
9035#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9048pub struct DriftLabelingSchemaConfig {
9049 #[serde(default)]
9051 pub enabled: bool,
9052
9053 #[serde(default)]
9055 pub statistical: StatisticalDriftLabelingSchemaConfig,
9056
9057 #[serde(default)]
9059 pub categorical: CategoricalDriftLabelingSchemaConfig,
9060
9061 #[serde(default)]
9063 pub temporal: TemporalDriftLabelingSchemaConfig,
9064
9065 #[serde(default)]
9067 pub regulatory_calendar_preset: Option<String>,
9068}
9069
9070#[derive(Debug, Clone, Serialize, Deserialize)]
9072pub struct StatisticalDriftLabelingSchemaConfig {
9073 #[serde(default = "default_true_val")]
9075 pub enabled: bool,
9076
9077 #[serde(default = "default_min_magnitude")]
9079 pub min_magnitude_threshold: f64,
9080}
9081
9082fn default_min_magnitude() -> f64 {
9083 0.05
9084}
9085
9086impl Default for StatisticalDriftLabelingSchemaConfig {
9087 fn default() -> Self {
9088 Self {
9089 enabled: true,
9090 min_magnitude_threshold: 0.05,
9091 }
9092 }
9093}
9094
9095#[derive(Debug, Clone, Serialize, Deserialize)]
9097pub struct CategoricalDriftLabelingSchemaConfig {
9098 #[serde(default = "default_true_val")]
9100 pub enabled: bool,
9101}
9102
9103impl Default for CategoricalDriftLabelingSchemaConfig {
9104 fn default() -> Self {
9105 Self { enabled: true }
9106 }
9107}
9108
9109#[derive(Debug, Clone, Serialize, Deserialize)]
9111pub struct TemporalDriftLabelingSchemaConfig {
9112 #[serde(default = "default_true_val")]
9114 pub enabled: bool,
9115}
9116
9117impl Default for TemporalDriftLabelingSchemaConfig {
9118 fn default() -> Self {
9119 Self { enabled: true }
9120 }
9121}
9122
9123#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9136pub struct EnhancedAnomalyConfig {
9137 #[serde(default)]
9139 pub enabled: bool,
9140
9141 #[serde(default)]
9143 pub rates: AnomalyRateConfig,
9144
9145 #[serde(default)]
9147 pub multi_stage_schemes: MultiStageSchemeConfig,
9148
9149 #[serde(default)]
9151 pub correlated_injection: CorrelatedInjectionConfig,
9152
9153 #[serde(default)]
9155 pub near_miss: NearMissConfig,
9156
9157 #[serde(default)]
9159 pub difficulty_classification: DifficultyClassificationConfig,
9160
9161 #[serde(default)]
9163 pub context_aware: ContextAwareConfig,
9164
9165 #[serde(default)]
9167 pub labeling: EnhancedLabelingConfig,
9168}
9169
9170#[derive(Debug, Clone, Serialize, Deserialize)]
9172pub struct AnomalyRateConfig {
9173 #[serde(default = "default_total_anomaly_rate")]
9175 pub total_rate: f64,
9176
9177 #[serde(default = "default_fraud_anomaly_rate")]
9179 pub fraud_rate: f64,
9180
9181 #[serde(default = "default_error_anomaly_rate")]
9183 pub error_rate: f64,
9184
9185 #[serde(default = "default_process_anomaly_rate")]
9187 pub process_rate: f64,
9188}
9189
9190fn default_total_anomaly_rate() -> f64 {
9191 0.03
9192}
9193fn default_fraud_anomaly_rate() -> f64 {
9194 0.01
9195}
9196fn default_error_anomaly_rate() -> f64 {
9197 0.015
9198}
9199fn default_process_anomaly_rate() -> f64 {
9200 0.005
9201}
9202
9203impl Default for AnomalyRateConfig {
9204 fn default() -> Self {
9205 Self {
9206 total_rate: default_total_anomaly_rate(),
9207 fraud_rate: default_fraud_anomaly_rate(),
9208 error_rate: default_error_anomaly_rate(),
9209 process_rate: default_process_anomaly_rate(),
9210 }
9211 }
9212}
9213
9214#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9216pub struct MultiStageSchemeConfig {
9217 #[serde(default)]
9219 pub enabled: bool,
9220
9221 #[serde(default)]
9223 pub embezzlement: EmbezzlementSchemeConfig,
9224
9225 #[serde(default)]
9227 pub revenue_manipulation: RevenueManipulationSchemeConfig,
9228
9229 #[serde(default)]
9231 pub kickback: KickbackSchemeConfig,
9232}
9233
9234#[derive(Debug, Clone, Serialize, Deserialize)]
9236pub struct EmbezzlementSchemeConfig {
9237 #[serde(default = "default_embezzlement_probability")]
9239 pub probability: f64,
9240
9241 #[serde(default)]
9243 pub testing_stage: SchemeStageConfig,
9244
9245 #[serde(default)]
9247 pub escalation_stage: SchemeStageConfig,
9248
9249 #[serde(default)]
9251 pub acceleration_stage: SchemeStageConfig,
9252
9253 #[serde(default)]
9255 pub desperation_stage: SchemeStageConfig,
9256}
9257
9258fn default_embezzlement_probability() -> f64 {
9259 0.02
9260}
9261
9262impl Default for EmbezzlementSchemeConfig {
9263 fn default() -> Self {
9264 Self {
9265 probability: default_embezzlement_probability(),
9266 testing_stage: SchemeStageConfig {
9267 duration_months: 2,
9268 amount_min: 100.0,
9269 amount_max: 500.0,
9270 transaction_count_min: 2,
9271 transaction_count_max: 5,
9272 difficulty: "hard".to_string(),
9273 },
9274 escalation_stage: SchemeStageConfig {
9275 duration_months: 6,
9276 amount_min: 500.0,
9277 amount_max: 2000.0,
9278 transaction_count_min: 3,
9279 transaction_count_max: 8,
9280 difficulty: "moderate".to_string(),
9281 },
9282 acceleration_stage: SchemeStageConfig {
9283 duration_months: 3,
9284 amount_min: 2000.0,
9285 amount_max: 10000.0,
9286 transaction_count_min: 5,
9287 transaction_count_max: 12,
9288 difficulty: "easy".to_string(),
9289 },
9290 desperation_stage: SchemeStageConfig {
9291 duration_months: 1,
9292 amount_min: 10000.0,
9293 amount_max: 50000.0,
9294 transaction_count_min: 3,
9295 transaction_count_max: 6,
9296 difficulty: "trivial".to_string(),
9297 },
9298 }
9299 }
9300}
9301
9302#[derive(Debug, Clone, Serialize, Deserialize)]
9304pub struct RevenueManipulationSchemeConfig {
9305 #[serde(default = "default_revenue_manipulation_probability")]
9307 pub probability: f64,
9308
9309 #[serde(default = "default_early_recognition_target")]
9311 pub early_recognition_target: f64,
9312
9313 #[serde(default = "default_expense_deferral_target")]
9315 pub expense_deferral_target: f64,
9316
9317 #[serde(default = "default_reserve_release_target")]
9319 pub reserve_release_target: f64,
9320
9321 #[serde(default = "default_channel_stuffing_target")]
9323 pub channel_stuffing_target: f64,
9324}
9325
9326fn default_revenue_manipulation_probability() -> f64 {
9327 0.01
9328}
9329fn default_early_recognition_target() -> f64 {
9330 0.02
9331}
9332fn default_expense_deferral_target() -> f64 {
9333 0.03
9334}
9335fn default_reserve_release_target() -> f64 {
9336 0.02
9337}
9338fn default_channel_stuffing_target() -> f64 {
9339 0.05
9340}
9341
9342impl Default for RevenueManipulationSchemeConfig {
9343 fn default() -> Self {
9344 Self {
9345 probability: default_revenue_manipulation_probability(),
9346 early_recognition_target: default_early_recognition_target(),
9347 expense_deferral_target: default_expense_deferral_target(),
9348 reserve_release_target: default_reserve_release_target(),
9349 channel_stuffing_target: default_channel_stuffing_target(),
9350 }
9351 }
9352}
9353
9354#[derive(Debug, Clone, Serialize, Deserialize)]
9356pub struct KickbackSchemeConfig {
9357 #[serde(default = "default_kickback_probability")]
9359 pub probability: f64,
9360
9361 #[serde(default = "default_kickback_inflation_min")]
9363 pub inflation_min: f64,
9364
9365 #[serde(default = "default_kickback_inflation_max")]
9367 pub inflation_max: f64,
9368
9369 #[serde(default = "default_kickback_percent")]
9371 pub kickback_percent: f64,
9372
9373 #[serde(default = "default_kickback_setup_months")]
9375 pub setup_months: u32,
9376
9377 #[serde(default = "default_kickback_operation_months")]
9379 pub operation_months: u32,
9380}
9381
9382fn default_kickback_probability() -> f64 {
9383 0.01
9384}
9385fn default_kickback_inflation_min() -> f64 {
9386 0.10
9387}
9388fn default_kickback_inflation_max() -> f64 {
9389 0.25
9390}
9391fn default_kickback_percent() -> f64 {
9392 0.50
9393}
9394fn default_kickback_setup_months() -> u32 {
9395 3
9396}
9397fn default_kickback_operation_months() -> u32 {
9398 12
9399}
9400
9401impl Default for KickbackSchemeConfig {
9402 fn default() -> Self {
9403 Self {
9404 probability: default_kickback_probability(),
9405 inflation_min: default_kickback_inflation_min(),
9406 inflation_max: default_kickback_inflation_max(),
9407 kickback_percent: default_kickback_percent(),
9408 setup_months: default_kickback_setup_months(),
9409 operation_months: default_kickback_operation_months(),
9410 }
9411 }
9412}
9413
9414#[derive(Debug, Clone, Serialize, Deserialize)]
9416pub struct SchemeStageConfig {
9417 pub duration_months: u32,
9419
9420 pub amount_min: f64,
9422
9423 pub amount_max: f64,
9425
9426 pub transaction_count_min: u32,
9428
9429 pub transaction_count_max: u32,
9431
9432 pub difficulty: String,
9434}
9435
9436impl Default for SchemeStageConfig {
9437 fn default() -> Self {
9438 Self {
9439 duration_months: 3,
9440 amount_min: 100.0,
9441 amount_max: 1000.0,
9442 transaction_count_min: 2,
9443 transaction_count_max: 10,
9444 difficulty: "moderate".to_string(),
9445 }
9446 }
9447}
9448
9449#[derive(Debug, Clone, Serialize, Deserialize)]
9451pub struct CorrelatedInjectionConfig {
9452 #[serde(default)]
9454 pub enabled: bool,
9455
9456 #[serde(default = "default_true_val")]
9458 pub fraud_concealment: bool,
9459
9460 #[serde(default = "default_true_val")]
9462 pub error_cascade: bool,
9463
9464 #[serde(default = "default_true_val")]
9466 pub temporal_clustering: bool,
9467
9468 #[serde(default)]
9470 pub temporal_clustering_config: TemporalClusteringConfig,
9471
9472 #[serde(default)]
9474 pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
9475}
9476
9477impl Default for CorrelatedInjectionConfig {
9478 fn default() -> Self {
9479 Self {
9480 enabled: false,
9481 fraud_concealment: true,
9482 error_cascade: true,
9483 temporal_clustering: true,
9484 temporal_clustering_config: TemporalClusteringConfig::default(),
9485 co_occurrence_patterns: Vec::new(),
9486 }
9487 }
9488}
9489
9490#[derive(Debug, Clone, Serialize, Deserialize)]
9492pub struct TemporalClusteringConfig {
9493 #[serde(default = "default_period_end_multiplier")]
9495 pub period_end_multiplier: f64,
9496
9497 #[serde(default = "default_period_end_days")]
9499 pub period_end_days: u32,
9500
9501 #[serde(default = "default_quarter_end_multiplier")]
9503 pub quarter_end_multiplier: f64,
9504
9505 #[serde(default = "default_year_end_multiplier")]
9507 pub year_end_multiplier: f64,
9508}
9509
9510fn default_period_end_multiplier() -> f64 {
9511 2.5
9512}
9513fn default_period_end_days() -> u32 {
9514 5
9515}
9516fn default_quarter_end_multiplier() -> f64 {
9517 1.5
9518}
9519fn default_year_end_multiplier() -> f64 {
9520 2.0
9521}
9522
9523impl Default for TemporalClusteringConfig {
9524 fn default() -> Self {
9525 Self {
9526 period_end_multiplier: default_period_end_multiplier(),
9527 period_end_days: default_period_end_days(),
9528 quarter_end_multiplier: default_quarter_end_multiplier(),
9529 year_end_multiplier: default_year_end_multiplier(),
9530 }
9531 }
9532}
9533
9534#[derive(Debug, Clone, Serialize, Deserialize)]
9536pub struct CoOccurrencePatternConfig {
9537 pub name: String,
9539
9540 pub primary_type: String,
9542
9543 pub correlated: Vec<CorrelatedAnomalyConfig>,
9545}
9546
9547#[derive(Debug, Clone, Serialize, Deserialize)]
9549pub struct CorrelatedAnomalyConfig {
9550 pub anomaly_type: String,
9552
9553 pub probability: f64,
9555
9556 pub lag_days_min: i32,
9558
9559 pub lag_days_max: i32,
9561}
9562
9563#[derive(Debug, Clone, Serialize, Deserialize)]
9565pub struct NearMissConfig {
9566 #[serde(default)]
9568 pub enabled: bool,
9569
9570 #[serde(default = "default_near_miss_proportion")]
9572 pub proportion: f64,
9573
9574 #[serde(default = "default_true_val")]
9576 pub near_duplicate: bool,
9577
9578 #[serde(default)]
9580 pub near_duplicate_days: NearDuplicateDaysConfig,
9581
9582 #[serde(default = "default_true_val")]
9584 pub threshold_proximity: bool,
9585
9586 #[serde(default)]
9588 pub threshold_proximity_range: ThresholdProximityRangeConfig,
9589
9590 #[serde(default = "default_true_val")]
9592 pub unusual_legitimate: bool,
9593
9594 #[serde(default = "default_unusual_legitimate_types")]
9596 pub unusual_legitimate_types: Vec<String>,
9597
9598 #[serde(default = "default_true_val")]
9600 pub corrected_errors: bool,
9601
9602 #[serde(default)]
9604 pub corrected_error_lag: CorrectedErrorLagConfig,
9605}
9606
9607fn default_near_miss_proportion() -> f64 {
9608 0.30
9609}
9610
9611fn default_unusual_legitimate_types() -> Vec<String> {
9612 vec![
9613 "year_end_bonus".to_string(),
9614 "contract_prepayment".to_string(),
9615 "insurance_claim".to_string(),
9616 "settlement_payment".to_string(),
9617 ]
9618}
9619
9620impl Default for NearMissConfig {
9621 fn default() -> Self {
9622 Self {
9623 enabled: false,
9624 proportion: default_near_miss_proportion(),
9625 near_duplicate: true,
9626 near_duplicate_days: NearDuplicateDaysConfig::default(),
9627 threshold_proximity: true,
9628 threshold_proximity_range: ThresholdProximityRangeConfig::default(),
9629 unusual_legitimate: true,
9630 unusual_legitimate_types: default_unusual_legitimate_types(),
9631 corrected_errors: true,
9632 corrected_error_lag: CorrectedErrorLagConfig::default(),
9633 }
9634 }
9635}
9636
9637#[derive(Debug, Clone, Serialize, Deserialize)]
9639pub struct NearDuplicateDaysConfig {
9640 #[serde(default = "default_near_duplicate_min")]
9642 pub min: u32,
9643
9644 #[serde(default = "default_near_duplicate_max")]
9646 pub max: u32,
9647}
9648
9649fn default_near_duplicate_min() -> u32 {
9650 1
9651}
9652fn default_near_duplicate_max() -> u32 {
9653 3
9654}
9655
9656impl Default for NearDuplicateDaysConfig {
9657 fn default() -> Self {
9658 Self {
9659 min: default_near_duplicate_min(),
9660 max: default_near_duplicate_max(),
9661 }
9662 }
9663}
9664
9665#[derive(Debug, Clone, Serialize, Deserialize)]
9667pub struct ThresholdProximityRangeConfig {
9668 #[serde(default = "default_threshold_proximity_min")]
9670 pub min: f64,
9671
9672 #[serde(default = "default_threshold_proximity_max")]
9674 pub max: f64,
9675}
9676
9677fn default_threshold_proximity_min() -> f64 {
9678 0.90
9679}
9680fn default_threshold_proximity_max() -> f64 {
9681 0.99
9682}
9683
9684impl Default for ThresholdProximityRangeConfig {
9685 fn default() -> Self {
9686 Self {
9687 min: default_threshold_proximity_min(),
9688 max: default_threshold_proximity_max(),
9689 }
9690 }
9691}
9692
9693#[derive(Debug, Clone, Serialize, Deserialize)]
9695pub struct CorrectedErrorLagConfig {
9696 #[serde(default = "default_corrected_error_lag_min")]
9698 pub min: u32,
9699
9700 #[serde(default = "default_corrected_error_lag_max")]
9702 pub max: u32,
9703}
9704
9705fn default_corrected_error_lag_min() -> u32 {
9706 1
9707}
9708fn default_corrected_error_lag_max() -> u32 {
9709 5
9710}
9711
9712impl Default for CorrectedErrorLagConfig {
9713 fn default() -> Self {
9714 Self {
9715 min: default_corrected_error_lag_min(),
9716 max: default_corrected_error_lag_max(),
9717 }
9718 }
9719}
9720
9721#[derive(Debug, Clone, Serialize, Deserialize)]
9723pub struct DifficultyClassificationConfig {
9724 #[serde(default)]
9726 pub enabled: bool,
9727
9728 #[serde(default)]
9730 pub target_distribution: DifficultyDistributionConfig,
9731}
9732
9733impl Default for DifficultyClassificationConfig {
9734 fn default() -> Self {
9735 Self {
9736 enabled: true,
9737 target_distribution: DifficultyDistributionConfig::default(),
9738 }
9739 }
9740}
9741
9742#[derive(Debug, Clone, Serialize, Deserialize)]
9744pub struct DifficultyDistributionConfig {
9745 #[serde(default = "default_difficulty_trivial")]
9747 pub trivial: f64,
9748
9749 #[serde(default = "default_difficulty_easy")]
9751 pub easy: f64,
9752
9753 #[serde(default = "default_difficulty_moderate")]
9755 pub moderate: f64,
9756
9757 #[serde(default = "default_difficulty_hard")]
9759 pub hard: f64,
9760
9761 #[serde(default = "default_difficulty_expert")]
9763 pub expert: f64,
9764}
9765
9766fn default_difficulty_trivial() -> f64 {
9767 0.15
9768}
9769fn default_difficulty_easy() -> f64 {
9770 0.25
9771}
9772fn default_difficulty_moderate() -> f64 {
9773 0.30
9774}
9775fn default_difficulty_hard() -> f64 {
9776 0.20
9777}
9778fn default_difficulty_expert() -> f64 {
9779 0.10
9780}
9781
9782impl Default for DifficultyDistributionConfig {
9783 fn default() -> Self {
9784 Self {
9785 trivial: default_difficulty_trivial(),
9786 easy: default_difficulty_easy(),
9787 moderate: default_difficulty_moderate(),
9788 hard: default_difficulty_hard(),
9789 expert: default_difficulty_expert(),
9790 }
9791 }
9792}
9793
9794#[derive(Debug, Clone, Serialize, Deserialize, Default)]
9796pub struct ContextAwareConfig {
9797 #[serde(default)]
9799 pub enabled: bool,
9800
9801 #[serde(default)]
9803 pub vendor_rules: VendorAnomalyRulesConfig,
9804
9805 #[serde(default)]
9807 pub employee_rules: EmployeeAnomalyRulesConfig,
9808
9809 #[serde(default)]
9811 pub account_rules: AccountAnomalyRulesConfig,
9812
9813 #[serde(default)]
9815 pub behavioral_baseline: BehavioralBaselineConfig,
9816}
9817
9818#[derive(Debug, Clone, Serialize, Deserialize)]
9820pub struct VendorAnomalyRulesConfig {
9821 #[serde(default = "default_new_vendor_multiplier")]
9823 pub new_vendor_error_multiplier: f64,
9824
9825 #[serde(default = "default_new_vendor_threshold")]
9827 pub new_vendor_threshold_days: u32,
9828
9829 #[serde(default = "default_international_multiplier")]
9831 pub international_error_multiplier: f64,
9832
9833 #[serde(default = "default_strategic_vendor_types")]
9835 pub strategic_vendor_anomaly_types: Vec<String>,
9836}
9837
9838fn default_new_vendor_multiplier() -> f64 {
9839 2.5
9840}
9841fn default_new_vendor_threshold() -> u32 {
9842 90
9843}
9844fn default_international_multiplier() -> f64 {
9845 1.5
9846}
9847fn default_strategic_vendor_types() -> Vec<String> {
9848 vec![
9849 "pricing_dispute".to_string(),
9850 "contract_violation".to_string(),
9851 ]
9852}
9853
9854impl Default for VendorAnomalyRulesConfig {
9855 fn default() -> Self {
9856 Self {
9857 new_vendor_error_multiplier: default_new_vendor_multiplier(),
9858 new_vendor_threshold_days: default_new_vendor_threshold(),
9859 international_error_multiplier: default_international_multiplier(),
9860 strategic_vendor_anomaly_types: default_strategic_vendor_types(),
9861 }
9862 }
9863}
9864
9865#[derive(Debug, Clone, Serialize, Deserialize)]
9867pub struct EmployeeAnomalyRulesConfig {
9868 #[serde(default = "default_new_employee_rate")]
9870 pub new_employee_error_rate: f64,
9871
9872 #[serde(default = "default_new_employee_threshold")]
9874 pub new_employee_threshold_days: u32,
9875
9876 #[serde(default = "default_volume_fatigue_threshold")]
9878 pub volume_fatigue_threshold: u32,
9879
9880 #[serde(default = "default_coverage_multiplier")]
9882 pub coverage_error_multiplier: f64,
9883}
9884
9885fn default_new_employee_rate() -> f64 {
9886 0.05
9887}
9888fn default_new_employee_threshold() -> u32 {
9889 180
9890}
9891fn default_volume_fatigue_threshold() -> u32 {
9892 50
9893}
9894fn default_coverage_multiplier() -> f64 {
9895 1.8
9896}
9897
9898impl Default for EmployeeAnomalyRulesConfig {
9899 fn default() -> Self {
9900 Self {
9901 new_employee_error_rate: default_new_employee_rate(),
9902 new_employee_threshold_days: default_new_employee_threshold(),
9903 volume_fatigue_threshold: default_volume_fatigue_threshold(),
9904 coverage_error_multiplier: default_coverage_multiplier(),
9905 }
9906 }
9907}
9908
9909#[derive(Debug, Clone, Serialize, Deserialize)]
9911pub struct AccountAnomalyRulesConfig {
9912 #[serde(default = "default_high_risk_multiplier")]
9914 pub high_risk_account_multiplier: f64,
9915
9916 #[serde(default = "default_high_risk_accounts")]
9918 pub high_risk_accounts: Vec<String>,
9919
9920 #[serde(default = "default_suspense_multiplier")]
9922 pub suspense_account_multiplier: f64,
9923
9924 #[serde(default = "default_suspense_accounts")]
9926 pub suspense_accounts: Vec<String>,
9927
9928 #[serde(default = "default_intercompany_multiplier")]
9930 pub intercompany_account_multiplier: f64,
9931}
9932
9933fn default_high_risk_multiplier() -> f64 {
9934 2.0
9935}
9936fn default_high_risk_accounts() -> Vec<String> {
9937 vec![
9938 "1100".to_string(), "2000".to_string(), "3000".to_string(), ]
9942}
9943fn default_suspense_multiplier() -> f64 {
9944 3.0
9945}
9946fn default_suspense_accounts() -> Vec<String> {
9947 vec!["9999".to_string(), "9998".to_string()]
9948}
9949fn default_intercompany_multiplier() -> f64 {
9950 1.5
9951}
9952
9953impl Default for AccountAnomalyRulesConfig {
9954 fn default() -> Self {
9955 Self {
9956 high_risk_account_multiplier: default_high_risk_multiplier(),
9957 high_risk_accounts: default_high_risk_accounts(),
9958 suspense_account_multiplier: default_suspense_multiplier(),
9959 suspense_accounts: default_suspense_accounts(),
9960 intercompany_account_multiplier: default_intercompany_multiplier(),
9961 }
9962 }
9963}
9964
9965#[derive(Debug, Clone, Serialize, Deserialize)]
9967pub struct BehavioralBaselineConfig {
9968 #[serde(default)]
9970 pub enabled: bool,
9971
9972 #[serde(default = "default_baseline_period")]
9974 pub baseline_period_days: u32,
9975
9976 #[serde(default = "default_deviation_threshold")]
9978 pub deviation_threshold_std: f64,
9979
9980 #[serde(default = "default_frequency_deviation")]
9982 pub frequency_deviation_threshold: f64,
9983}
9984
9985fn default_baseline_period() -> u32 {
9986 90
9987}
9988fn default_deviation_threshold() -> f64 {
9989 3.0
9990}
9991fn default_frequency_deviation() -> f64 {
9992 2.0
9993}
9994
9995impl Default for BehavioralBaselineConfig {
9996 fn default() -> Self {
9997 Self {
9998 enabled: false,
9999 baseline_period_days: default_baseline_period(),
10000 deviation_threshold_std: default_deviation_threshold(),
10001 frequency_deviation_threshold: default_frequency_deviation(),
10002 }
10003 }
10004}
10005
10006#[derive(Debug, Clone, Serialize, Deserialize)]
10008pub struct EnhancedLabelingConfig {
10009 #[serde(default = "default_true_val")]
10011 pub severity_scoring: bool,
10012
10013 #[serde(default = "default_true_val")]
10015 pub difficulty_classification: bool,
10016
10017 #[serde(default)]
10019 pub materiality_thresholds: MaterialityThresholdsConfig,
10020}
10021
10022impl Default for EnhancedLabelingConfig {
10023 fn default() -> Self {
10024 Self {
10025 severity_scoring: true,
10026 difficulty_classification: true,
10027 materiality_thresholds: MaterialityThresholdsConfig::default(),
10028 }
10029 }
10030}
10031
10032#[derive(Debug, Clone, Serialize, Deserialize)]
10034pub struct MaterialityThresholdsConfig {
10035 #[serde(default = "default_materiality_trivial")]
10037 pub trivial: f64,
10038
10039 #[serde(default = "default_materiality_immaterial")]
10041 pub immaterial: f64,
10042
10043 #[serde(default = "default_materiality_material")]
10045 pub material: f64,
10046
10047 #[serde(default = "default_materiality_highly_material")]
10049 pub highly_material: f64,
10050}
10051
10052fn default_materiality_trivial() -> f64 {
10053 0.001
10054}
10055fn default_materiality_immaterial() -> f64 {
10056 0.01
10057}
10058fn default_materiality_material() -> f64 {
10059 0.05
10060}
10061fn default_materiality_highly_material() -> f64 {
10062 0.10
10063}
10064
10065impl Default for MaterialityThresholdsConfig {
10066 fn default() -> Self {
10067 Self {
10068 trivial: default_materiality_trivial(),
10069 immaterial: default_materiality_immaterial(),
10070 material: default_materiality_material(),
10071 highly_material: default_materiality_highly_material(),
10072 }
10073 }
10074}
10075
10076#[derive(Debug, Clone, Serialize, Deserialize, Default)]
10088pub struct IndustrySpecificConfig {
10089 #[serde(default)]
10091 pub enabled: bool,
10092
10093 #[serde(default)]
10095 pub manufacturing: ManufacturingConfig,
10096
10097 #[serde(default)]
10099 pub retail: RetailConfig,
10100
10101 #[serde(default)]
10103 pub healthcare: HealthcareConfig,
10104
10105 #[serde(default)]
10107 pub technology: TechnologyConfig,
10108
10109 #[serde(default)]
10111 pub financial_services: FinancialServicesConfig,
10112
10113 #[serde(default)]
10115 pub professional_services: ProfessionalServicesConfig,
10116}
10117
10118#[derive(Debug, Clone, Serialize, Deserialize)]
10120pub struct ManufacturingConfig {
10121 #[serde(default)]
10123 pub enabled: bool,
10124
10125 #[serde(default = "default_bom_depth")]
10127 pub bom_depth: u32,
10128
10129 #[serde(default)]
10131 pub just_in_time: bool,
10132
10133 #[serde(default = "default_production_order_types")]
10135 pub production_order_types: Vec<String>,
10136
10137 #[serde(default)]
10139 pub quality_framework: Option<String>,
10140
10141 #[serde(default = "default_supplier_tiers")]
10143 pub supplier_tiers: u32,
10144
10145 #[serde(default = "default_cost_frequency")]
10147 pub standard_cost_frequency: String,
10148
10149 #[serde(default = "default_yield_rate")]
10151 pub target_yield_rate: f64,
10152
10153 #[serde(default = "default_scrap_threshold")]
10155 pub scrap_alert_threshold: f64,
10156
10157 #[serde(default)]
10159 pub anomaly_rates: ManufacturingAnomalyRates,
10160
10161 #[serde(default)]
10163 pub cost_accounting: ManufacturingCostAccountingConfig,
10164}
10165
10166#[derive(Debug, Clone, Serialize, Deserialize)]
10168pub struct ManufacturingCostAccountingConfig {
10169 #[serde(default = "default_true")]
10171 pub enabled: bool,
10172
10173 #[serde(default = "default_true")]
10175 pub variance_accounts_enabled: bool,
10176
10177 #[serde(default = "default_true")]
10179 pub warranty_provisions_enabled: bool,
10180
10181 #[serde(default = "default_warranty_defect_threshold")]
10183 pub warranty_defect_threshold: f64,
10184}
10185
10186fn default_warranty_defect_threshold() -> f64 {
10187 0.01
10188}
10189
10190impl Default for ManufacturingCostAccountingConfig {
10191 fn default() -> Self {
10192 Self {
10193 enabled: true,
10194 variance_accounts_enabled: true,
10195 warranty_provisions_enabled: true,
10196 warranty_defect_threshold: 0.01,
10197 }
10198 }
10199}
10200
10201fn default_bom_depth() -> u32 {
10202 4
10203}
10204
10205fn default_production_order_types() -> Vec<String> {
10206 vec![
10207 "standard".to_string(),
10208 "rework".to_string(),
10209 "prototype".to_string(),
10210 ]
10211}
10212
10213fn default_supplier_tiers() -> u32 {
10214 2
10215}
10216
10217fn default_cost_frequency() -> String {
10218 "quarterly".to_string()
10219}
10220
10221fn default_yield_rate() -> f64 {
10222 0.97
10223}
10224
10225fn default_scrap_threshold() -> f64 {
10226 0.03
10227}
10228
10229impl Default for ManufacturingConfig {
10230 fn default() -> Self {
10231 Self {
10232 enabled: false,
10233 bom_depth: default_bom_depth(),
10234 just_in_time: false,
10235 production_order_types: default_production_order_types(),
10236 quality_framework: Some("ISO_9001".to_string()),
10237 supplier_tiers: default_supplier_tiers(),
10238 standard_cost_frequency: default_cost_frequency(),
10239 target_yield_rate: default_yield_rate(),
10240 scrap_alert_threshold: default_scrap_threshold(),
10241 anomaly_rates: ManufacturingAnomalyRates::default(),
10242 cost_accounting: ManufacturingCostAccountingConfig::default(),
10243 }
10244 }
10245}
10246
10247#[derive(Debug, Clone, Serialize, Deserialize)]
10249pub struct ManufacturingAnomalyRates {
10250 #[serde(default = "default_mfg_yield_rate")]
10252 pub yield_manipulation: f64,
10253
10254 #[serde(default = "default_mfg_labor_rate")]
10256 pub labor_misallocation: f64,
10257
10258 #[serde(default = "default_mfg_phantom_rate")]
10260 pub phantom_production: f64,
10261
10262 #[serde(default = "default_mfg_cost_rate")]
10264 pub standard_cost_manipulation: f64,
10265
10266 #[serde(default = "default_mfg_inventory_rate")]
10268 pub inventory_fraud: f64,
10269}
10270
10271fn default_mfg_yield_rate() -> f64 {
10272 0.015
10273}
10274
10275fn default_mfg_labor_rate() -> f64 {
10276 0.02
10277}
10278
10279fn default_mfg_phantom_rate() -> f64 {
10280 0.005
10281}
10282
10283fn default_mfg_cost_rate() -> f64 {
10284 0.01
10285}
10286
10287fn default_mfg_inventory_rate() -> f64 {
10288 0.008
10289}
10290
10291impl Default for ManufacturingAnomalyRates {
10292 fn default() -> Self {
10293 Self {
10294 yield_manipulation: default_mfg_yield_rate(),
10295 labor_misallocation: default_mfg_labor_rate(),
10296 phantom_production: default_mfg_phantom_rate(),
10297 standard_cost_manipulation: default_mfg_cost_rate(),
10298 inventory_fraud: default_mfg_inventory_rate(),
10299 }
10300 }
10301}
10302
10303#[derive(Debug, Clone, Serialize, Deserialize)]
10305pub struct RetailConfig {
10306 #[serde(default)]
10308 pub enabled: bool,
10309
10310 #[serde(default)]
10312 pub store_types: RetailStoreTypeConfig,
10313
10314 #[serde(default = "default_retail_daily_txns")]
10316 pub avg_daily_transactions: u32,
10317
10318 #[serde(default = "default_true")]
10320 pub loss_prevention: bool,
10321
10322 #[serde(default = "default_shrinkage_rate")]
10324 pub shrinkage_rate: f64,
10325
10326 #[serde(default)]
10328 pub anomaly_rates: RetailAnomalyRates,
10329}
10330
10331fn default_retail_daily_txns() -> u32 {
10332 500
10333}
10334
10335fn default_shrinkage_rate() -> f64 {
10336 0.015
10337}
10338
10339impl Default for RetailConfig {
10340 fn default() -> Self {
10341 Self {
10342 enabled: false,
10343 store_types: RetailStoreTypeConfig::default(),
10344 avg_daily_transactions: default_retail_daily_txns(),
10345 loss_prevention: true,
10346 shrinkage_rate: default_shrinkage_rate(),
10347 anomaly_rates: RetailAnomalyRates::default(),
10348 }
10349 }
10350}
10351
10352#[derive(Debug, Clone, Serialize, Deserialize)]
10354pub struct RetailStoreTypeConfig {
10355 #[serde(default = "default_flagship_pct")]
10357 pub flagship: f64,
10358
10359 #[serde(default = "default_regional_pct")]
10361 pub regional: f64,
10362
10363 #[serde(default = "default_outlet_pct")]
10365 pub outlet: f64,
10366
10367 #[serde(default = "default_ecommerce_pct")]
10369 pub ecommerce: f64,
10370}
10371
10372fn default_flagship_pct() -> f64 {
10373 0.10
10374}
10375
10376fn default_regional_pct() -> f64 {
10377 0.50
10378}
10379
10380fn default_outlet_pct() -> f64 {
10381 0.25
10382}
10383
10384fn default_ecommerce_pct() -> f64 {
10385 0.15
10386}
10387
10388impl Default for RetailStoreTypeConfig {
10389 fn default() -> Self {
10390 Self {
10391 flagship: default_flagship_pct(),
10392 regional: default_regional_pct(),
10393 outlet: default_outlet_pct(),
10394 ecommerce: default_ecommerce_pct(),
10395 }
10396 }
10397}
10398
10399#[derive(Debug, Clone, Serialize, Deserialize)]
10401pub struct RetailAnomalyRates {
10402 #[serde(default = "default_sweethearting_rate")]
10404 pub sweethearting: f64,
10405
10406 #[serde(default = "default_skimming_rate")]
10408 pub skimming: f64,
10409
10410 #[serde(default = "default_refund_fraud_rate")]
10412 pub refund_fraud: f64,
10413
10414 #[serde(default = "default_void_abuse_rate")]
10416 pub void_abuse: f64,
10417
10418 #[serde(default = "default_gift_card_rate")]
10420 pub gift_card_fraud: f64,
10421
10422 #[serde(default = "default_retail_kickback_rate")]
10424 pub vendor_kickback: f64,
10425}
10426
10427fn default_sweethearting_rate() -> f64 {
10428 0.02
10429}
10430
10431fn default_skimming_rate() -> f64 {
10432 0.005
10433}
10434
10435fn default_refund_fraud_rate() -> f64 {
10436 0.015
10437}
10438
10439fn default_void_abuse_rate() -> f64 {
10440 0.01
10441}
10442
10443fn default_gift_card_rate() -> f64 {
10444 0.008
10445}
10446
10447fn default_retail_kickback_rate() -> f64 {
10448 0.003
10449}
10450
10451impl Default for RetailAnomalyRates {
10452 fn default() -> Self {
10453 Self {
10454 sweethearting: default_sweethearting_rate(),
10455 skimming: default_skimming_rate(),
10456 refund_fraud: default_refund_fraud_rate(),
10457 void_abuse: default_void_abuse_rate(),
10458 gift_card_fraud: default_gift_card_rate(),
10459 vendor_kickback: default_retail_kickback_rate(),
10460 }
10461 }
10462}
10463
10464#[derive(Debug, Clone, Serialize, Deserialize)]
10466pub struct HealthcareConfig {
10467 #[serde(default)]
10469 pub enabled: bool,
10470
10471 #[serde(default = "default_facility_type")]
10473 pub facility_type: String,
10474
10475 #[serde(default)]
10477 pub payer_mix: HealthcarePayerMix,
10478
10479 #[serde(default)]
10481 pub coding_systems: HealthcareCodingSystems,
10482
10483 #[serde(default)]
10485 pub compliance: HealthcareComplianceConfig,
10486
10487 #[serde(default = "default_daily_encounters")]
10489 pub avg_daily_encounters: u32,
10490
10491 #[serde(default = "default_charges_per_encounter")]
10493 pub avg_charges_per_encounter: u32,
10494
10495 #[serde(default = "default_hc_denial_rate")]
10497 pub denial_rate: f64,
10498
10499 #[serde(default = "default_hc_bad_debt_rate")]
10501 pub bad_debt_rate: f64,
10502
10503 #[serde(default = "default_hc_charity_care_rate")]
10505 pub charity_care_rate: f64,
10506
10507 #[serde(default)]
10509 pub anomaly_rates: HealthcareAnomalyRates,
10510}
10511
10512fn default_facility_type() -> String {
10513 "hospital".to_string()
10514}
10515
10516fn default_daily_encounters() -> u32 {
10517 150
10518}
10519
10520fn default_charges_per_encounter() -> u32 {
10521 8
10522}
10523
10524fn default_hc_denial_rate() -> f64 {
10525 0.05
10526}
10527
10528fn default_hc_bad_debt_rate() -> f64 {
10529 0.03
10530}
10531
10532fn default_hc_charity_care_rate() -> f64 {
10533 0.02
10534}
10535
10536impl Default for HealthcareConfig {
10537 fn default() -> Self {
10538 Self {
10539 enabled: false,
10540 facility_type: default_facility_type(),
10541 payer_mix: HealthcarePayerMix::default(),
10542 coding_systems: HealthcareCodingSystems::default(),
10543 compliance: HealthcareComplianceConfig::default(),
10544 avg_daily_encounters: default_daily_encounters(),
10545 avg_charges_per_encounter: default_charges_per_encounter(),
10546 denial_rate: default_hc_denial_rate(),
10547 bad_debt_rate: default_hc_bad_debt_rate(),
10548 charity_care_rate: default_hc_charity_care_rate(),
10549 anomaly_rates: HealthcareAnomalyRates::default(),
10550 }
10551 }
10552}
10553
10554#[derive(Debug, Clone, Serialize, Deserialize)]
10556pub struct HealthcarePayerMix {
10557 #[serde(default = "default_medicare_pct")]
10559 pub medicare: f64,
10560
10561 #[serde(default = "default_medicaid_pct")]
10563 pub medicaid: f64,
10564
10565 #[serde(default = "default_commercial_pct")]
10567 pub commercial: f64,
10568
10569 #[serde(default = "default_self_pay_pct")]
10571 pub self_pay: f64,
10572}
10573
10574fn default_medicare_pct() -> f64 {
10575 0.40
10576}
10577
10578fn default_medicaid_pct() -> f64 {
10579 0.20
10580}
10581
10582fn default_commercial_pct() -> f64 {
10583 0.30
10584}
10585
10586fn default_self_pay_pct() -> f64 {
10587 0.10
10588}
10589
10590impl Default for HealthcarePayerMix {
10591 fn default() -> Self {
10592 Self {
10593 medicare: default_medicare_pct(),
10594 medicaid: default_medicaid_pct(),
10595 commercial: default_commercial_pct(),
10596 self_pay: default_self_pay_pct(),
10597 }
10598 }
10599}
10600
10601#[derive(Debug, Clone, Serialize, Deserialize)]
10603pub struct HealthcareCodingSystems {
10604 #[serde(default = "default_true")]
10606 pub icd10: bool,
10607
10608 #[serde(default = "default_true")]
10610 pub cpt: bool,
10611
10612 #[serde(default = "default_true")]
10614 pub drg: bool,
10615
10616 #[serde(default = "default_true")]
10618 pub hcpcs: bool,
10619
10620 #[serde(default = "default_true")]
10622 pub revenue_codes: bool,
10623}
10624
10625impl Default for HealthcareCodingSystems {
10626 fn default() -> Self {
10627 Self {
10628 icd10: true,
10629 cpt: true,
10630 drg: true,
10631 hcpcs: true,
10632 revenue_codes: true,
10633 }
10634 }
10635}
10636
10637#[derive(Debug, Clone, Serialize, Deserialize)]
10639pub struct HealthcareComplianceConfig {
10640 #[serde(default = "default_true")]
10642 pub hipaa: bool,
10643
10644 #[serde(default = "default_true")]
10646 pub stark_law: bool,
10647
10648 #[serde(default = "default_true")]
10650 pub anti_kickback: bool,
10651
10652 #[serde(default = "default_true")]
10654 pub false_claims_act: bool,
10655
10656 #[serde(default = "default_true")]
10658 pub emtala: bool,
10659}
10660
10661impl Default for HealthcareComplianceConfig {
10662 fn default() -> Self {
10663 Self {
10664 hipaa: true,
10665 stark_law: true,
10666 anti_kickback: true,
10667 false_claims_act: true,
10668 emtala: true,
10669 }
10670 }
10671}
10672
10673#[derive(Debug, Clone, Serialize, Deserialize)]
10675pub struct HealthcareAnomalyRates {
10676 #[serde(default = "default_upcoding_rate")]
10678 pub upcoding: f64,
10679
10680 #[serde(default = "default_unbundling_rate")]
10682 pub unbundling: f64,
10683
10684 #[serde(default = "default_phantom_billing_rate")]
10686 pub phantom_billing: f64,
10687
10688 #[serde(default = "default_healthcare_kickback_rate")]
10690 pub kickbacks: f64,
10691
10692 #[serde(default = "default_duplicate_billing_rate")]
10694 pub duplicate_billing: f64,
10695
10696 #[serde(default = "default_med_necessity_rate")]
10698 pub medical_necessity_abuse: f64,
10699}
10700
10701fn default_upcoding_rate() -> f64 {
10702 0.02
10703}
10704
10705fn default_unbundling_rate() -> f64 {
10706 0.015
10707}
10708
10709fn default_phantom_billing_rate() -> f64 {
10710 0.005
10711}
10712
10713fn default_healthcare_kickback_rate() -> f64 {
10714 0.003
10715}
10716
10717fn default_duplicate_billing_rate() -> f64 {
10718 0.008
10719}
10720
10721fn default_med_necessity_rate() -> f64 {
10722 0.01
10723}
10724
10725impl Default for HealthcareAnomalyRates {
10726 fn default() -> Self {
10727 Self {
10728 upcoding: default_upcoding_rate(),
10729 unbundling: default_unbundling_rate(),
10730 phantom_billing: default_phantom_billing_rate(),
10731 kickbacks: default_healthcare_kickback_rate(),
10732 duplicate_billing: default_duplicate_billing_rate(),
10733 medical_necessity_abuse: default_med_necessity_rate(),
10734 }
10735 }
10736}
10737
10738#[derive(Debug, Clone, Serialize, Deserialize)]
10740pub struct TechnologyConfig {
10741 #[serde(default)]
10743 pub enabled: bool,
10744
10745 #[serde(default = "default_revenue_model")]
10747 pub revenue_model: String,
10748
10749 #[serde(default = "default_subscription_pct")]
10751 pub subscription_revenue_pct: f64,
10752
10753 #[serde(default = "default_license_pct")]
10755 pub license_revenue_pct: f64,
10756
10757 #[serde(default = "default_services_pct")]
10759 pub services_revenue_pct: f64,
10760
10761 #[serde(default)]
10763 pub rd_capitalization: RdCapitalizationConfig,
10764
10765 #[serde(default)]
10767 pub anomaly_rates: TechnologyAnomalyRates,
10768}
10769
10770fn default_revenue_model() -> String {
10771 "saas".to_string()
10772}
10773
10774fn default_subscription_pct() -> f64 {
10775 0.60
10776}
10777
10778fn default_license_pct() -> f64 {
10779 0.25
10780}
10781
10782fn default_services_pct() -> f64 {
10783 0.15
10784}
10785
10786impl Default for TechnologyConfig {
10787 fn default() -> Self {
10788 Self {
10789 enabled: false,
10790 revenue_model: default_revenue_model(),
10791 subscription_revenue_pct: default_subscription_pct(),
10792 license_revenue_pct: default_license_pct(),
10793 services_revenue_pct: default_services_pct(),
10794 rd_capitalization: RdCapitalizationConfig::default(),
10795 anomaly_rates: TechnologyAnomalyRates::default(),
10796 }
10797 }
10798}
10799
10800#[derive(Debug, Clone, Serialize, Deserialize)]
10802pub struct RdCapitalizationConfig {
10803 #[serde(default = "default_true")]
10805 pub enabled: bool,
10806
10807 #[serde(default = "default_cap_rate")]
10809 pub capitalization_rate: f64,
10810
10811 #[serde(default = "default_useful_life")]
10813 pub useful_life_years: u32,
10814}
10815
10816fn default_cap_rate() -> f64 {
10817 0.30
10818}
10819
10820fn default_useful_life() -> u32 {
10821 3
10822}
10823
10824impl Default for RdCapitalizationConfig {
10825 fn default() -> Self {
10826 Self {
10827 enabled: true,
10828 capitalization_rate: default_cap_rate(),
10829 useful_life_years: default_useful_life(),
10830 }
10831 }
10832}
10833
10834#[derive(Debug, Clone, Serialize, Deserialize)]
10836pub struct TechnologyAnomalyRates {
10837 #[serde(default = "default_premature_rev_rate")]
10839 pub premature_revenue: f64,
10840
10841 #[serde(default = "default_side_letter_rate")]
10843 pub side_letter_abuse: f64,
10844
10845 #[serde(default = "default_channel_stuffing_rate")]
10847 pub channel_stuffing: f64,
10848
10849 #[serde(default = "default_improper_cap_rate")]
10851 pub improper_capitalization: f64,
10852}
10853
10854fn default_premature_rev_rate() -> f64 {
10855 0.015
10856}
10857
10858fn default_side_letter_rate() -> f64 {
10859 0.008
10860}
10861
10862fn default_channel_stuffing_rate() -> f64 {
10863 0.01
10864}
10865
10866fn default_improper_cap_rate() -> f64 {
10867 0.012
10868}
10869
10870impl Default for TechnologyAnomalyRates {
10871 fn default() -> Self {
10872 Self {
10873 premature_revenue: default_premature_rev_rate(),
10874 side_letter_abuse: default_side_letter_rate(),
10875 channel_stuffing: default_channel_stuffing_rate(),
10876 improper_capitalization: default_improper_cap_rate(),
10877 }
10878 }
10879}
10880
10881#[derive(Debug, Clone, Serialize, Deserialize)]
10883pub struct FinancialServicesConfig {
10884 #[serde(default)]
10886 pub enabled: bool,
10887
10888 #[serde(default = "default_fi_type")]
10890 pub institution_type: String,
10891
10892 #[serde(default = "default_fi_regulatory")]
10894 pub regulatory_framework: String,
10895
10896 #[serde(default)]
10898 pub anomaly_rates: FinancialServicesAnomalyRates,
10899}
10900
10901fn default_fi_type() -> String {
10902 "commercial_bank".to_string()
10903}
10904
10905fn default_fi_regulatory() -> String {
10906 "us_banking".to_string()
10907}
10908
10909impl Default for FinancialServicesConfig {
10910 fn default() -> Self {
10911 Self {
10912 enabled: false,
10913 institution_type: default_fi_type(),
10914 regulatory_framework: default_fi_regulatory(),
10915 anomaly_rates: FinancialServicesAnomalyRates::default(),
10916 }
10917 }
10918}
10919
10920#[derive(Debug, Clone, Serialize, Deserialize)]
10922pub struct FinancialServicesAnomalyRates {
10923 #[serde(default = "default_loan_fraud_rate")]
10925 pub loan_fraud: f64,
10926
10927 #[serde(default = "default_trading_fraud_rate")]
10929 pub trading_fraud: f64,
10930
10931 #[serde(default = "default_insurance_fraud_rate")]
10933 pub insurance_fraud: f64,
10934
10935 #[serde(default = "default_account_manip_rate")]
10937 pub account_manipulation: f64,
10938}
10939
10940fn default_loan_fraud_rate() -> f64 {
10941 0.01
10942}
10943
10944fn default_trading_fraud_rate() -> f64 {
10945 0.008
10946}
10947
10948fn default_insurance_fraud_rate() -> f64 {
10949 0.012
10950}
10951
10952fn default_account_manip_rate() -> f64 {
10953 0.005
10954}
10955
10956impl Default for FinancialServicesAnomalyRates {
10957 fn default() -> Self {
10958 Self {
10959 loan_fraud: default_loan_fraud_rate(),
10960 trading_fraud: default_trading_fraud_rate(),
10961 insurance_fraud: default_insurance_fraud_rate(),
10962 account_manipulation: default_account_manip_rate(),
10963 }
10964 }
10965}
10966
10967#[derive(Debug, Clone, Serialize, Deserialize)]
10969pub struct ProfessionalServicesConfig {
10970 #[serde(default)]
10972 pub enabled: bool,
10973
10974 #[serde(default = "default_firm_type")]
10976 pub firm_type: String,
10977
10978 #[serde(default = "default_billing_model")]
10980 pub billing_model: String,
10981
10982 #[serde(default = "default_hourly_rate")]
10984 pub avg_hourly_rate: f64,
10985
10986 #[serde(default)]
10988 pub trust_accounting: TrustAccountingConfig,
10989
10990 #[serde(default)]
10992 pub anomaly_rates: ProfessionalServicesAnomalyRates,
10993}
10994
10995fn default_firm_type() -> String {
10996 "consulting".to_string()
10997}
10998
10999fn default_billing_model() -> String {
11000 "time_and_materials".to_string()
11001}
11002
11003fn default_hourly_rate() -> f64 {
11004 250.0
11005}
11006
11007impl Default for ProfessionalServicesConfig {
11008 fn default() -> Self {
11009 Self {
11010 enabled: false,
11011 firm_type: default_firm_type(),
11012 billing_model: default_billing_model(),
11013 avg_hourly_rate: default_hourly_rate(),
11014 trust_accounting: TrustAccountingConfig::default(),
11015 anomaly_rates: ProfessionalServicesAnomalyRates::default(),
11016 }
11017 }
11018}
11019
11020#[derive(Debug, Clone, Serialize, Deserialize)]
11022pub struct TrustAccountingConfig {
11023 #[serde(default)]
11025 pub enabled: bool,
11026
11027 #[serde(default = "default_true")]
11029 pub require_three_way_reconciliation: bool,
11030}
11031
11032impl Default for TrustAccountingConfig {
11033 fn default() -> Self {
11034 Self {
11035 enabled: false,
11036 require_three_way_reconciliation: true,
11037 }
11038 }
11039}
11040
11041#[derive(Debug, Clone, Serialize, Deserialize)]
11043pub struct ProfessionalServicesAnomalyRates {
11044 #[serde(default = "default_time_fraud_rate")]
11046 pub time_billing_fraud: f64,
11047
11048 #[serde(default = "default_expense_fraud_rate")]
11050 pub expense_fraud: f64,
11051
11052 #[serde(default = "default_trust_misappropriation_rate")]
11054 pub trust_misappropriation: f64,
11055}
11056
11057fn default_time_fraud_rate() -> f64 {
11058 0.02
11059}
11060
11061fn default_expense_fraud_rate() -> f64 {
11062 0.015
11063}
11064
11065fn default_trust_misappropriation_rate() -> f64 {
11066 0.003
11067}
11068
11069impl Default for ProfessionalServicesAnomalyRates {
11070 fn default() -> Self {
11071 Self {
11072 time_billing_fraud: default_time_fraud_rate(),
11073 expense_fraud: default_expense_fraud_rate(),
11074 trust_misappropriation: default_trust_misappropriation_rate(),
11075 }
11076 }
11077}
11078
11079#[derive(Debug, Clone, Serialize, Deserialize)]
11093pub struct FingerprintPrivacyConfig {
11094 #[serde(default)]
11096 pub level: String,
11097 #[serde(default = "default_epsilon")]
11099 pub epsilon: f64,
11100 #[serde(default = "default_delta")]
11102 pub delta: f64,
11103 #[serde(default = "default_k_anonymity")]
11105 pub k_anonymity: u32,
11106 #[serde(default)]
11108 pub composition_method: String,
11109}
11110
11111fn default_epsilon() -> f64 {
11112 1.0
11113}
11114
11115fn default_delta() -> f64 {
11116 1e-5
11117}
11118
11119fn default_k_anonymity() -> u32 {
11120 5
11121}
11122
11123impl Default for FingerprintPrivacyConfig {
11124 fn default() -> Self {
11125 Self {
11126 level: "standard".to_string(),
11127 epsilon: default_epsilon(),
11128 delta: default_delta(),
11129 k_anonymity: default_k_anonymity(),
11130 composition_method: "naive".to_string(),
11131 }
11132 }
11133}
11134
11135#[derive(Debug, Clone, Serialize, Deserialize)]
11149pub struct QualityGatesSchemaConfig {
11150 #[serde(default)]
11152 pub enabled: bool,
11153 #[serde(default = "default_gate_profile_name")]
11155 pub profile: String,
11156 #[serde(default)]
11158 pub fail_on_violation: bool,
11159 #[serde(default)]
11161 pub custom_gates: Vec<QualityGateEntry>,
11162}
11163
11164fn default_gate_profile_name() -> String {
11165 "default".to_string()
11166}
11167
11168impl Default for QualityGatesSchemaConfig {
11169 fn default() -> Self {
11170 Self {
11171 enabled: false,
11172 profile: default_gate_profile_name(),
11173 fail_on_violation: false,
11174 custom_gates: Vec::new(),
11175 }
11176 }
11177}
11178
11179#[derive(Debug, Clone, Serialize, Deserialize)]
11181pub struct QualityGateEntry {
11182 pub name: String,
11184 pub metric: String,
11188 pub threshold: f64,
11190 #[serde(default)]
11192 pub upper_threshold: Option<f64>,
11193 #[serde(default = "default_gate_comparison")]
11195 pub comparison: String,
11196}
11197
11198fn default_gate_comparison() -> String {
11199 "gte".to_string()
11200}
11201
11202#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11212pub struct ComplianceSchemaConfig {
11213 #[serde(default)]
11215 pub content_marking: ContentMarkingSchemaConfig,
11216 #[serde(default)]
11218 pub article10_report: bool,
11219 #[serde(default)]
11221 pub certificates: CertificateSchemaConfig,
11222}
11223
11224#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11226pub struct CertificateSchemaConfig {
11227 #[serde(default)]
11229 pub enabled: bool,
11230 #[serde(default)]
11232 pub signing_key_env: Option<String>,
11233 #[serde(default)]
11235 pub include_quality_metrics: bool,
11236}
11237
11238#[derive(Debug, Clone, Serialize, Deserialize)]
11240pub struct ContentMarkingSchemaConfig {
11241 #[serde(default = "default_true")]
11243 pub enabled: bool,
11244 #[serde(default = "default_marking_format")]
11246 pub format: String,
11247}
11248
11249fn default_marking_format() -> String {
11250 "embedded".to_string()
11251}
11252
11253impl Default for ContentMarkingSchemaConfig {
11254 fn default() -> Self {
11255 Self {
11256 enabled: true,
11257 format: default_marking_format(),
11258 }
11259 }
11260}
11261
11262#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11264pub struct WebhookSchemaConfig {
11265 #[serde(default)]
11267 pub enabled: bool,
11268 #[serde(default)]
11270 pub endpoints: Vec<WebhookEndpointConfig>,
11271}
11272
11273#[derive(Debug, Clone, Serialize, Deserialize)]
11275pub struct WebhookEndpointConfig {
11276 pub url: String,
11278 #[serde(default)]
11280 pub events: Vec<String>,
11281 #[serde(default)]
11283 pub secret: Option<String>,
11284 #[serde(default = "default_webhook_retries")]
11286 pub max_retries: u32,
11287 #[serde(default = "default_webhook_timeout")]
11289 pub timeout_secs: u64,
11290}
11291
11292fn default_webhook_retries() -> u32 {
11293 3
11294}
11295fn default_webhook_timeout() -> u64 {
11296 10
11297}
11298
11299#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11305pub struct SourceToPayConfig {
11306 #[serde(default)]
11308 pub enabled: bool,
11309 #[serde(default)]
11311 pub spend_analysis: SpendAnalysisConfig,
11312 #[serde(default)]
11314 pub sourcing: SourcingConfig,
11315 #[serde(default)]
11317 pub qualification: QualificationConfig,
11318 #[serde(default)]
11320 pub rfx: RfxConfig,
11321 #[serde(default)]
11323 pub contracts: ContractConfig,
11324 #[serde(default)]
11326 pub catalog: CatalogConfig,
11327 #[serde(default)]
11329 pub scorecards: ScorecardConfig,
11330 #[serde(default)]
11332 pub p2p_integration: P2PIntegrationConfig,
11333}
11334
11335#[derive(Debug, Clone, Serialize, Deserialize)]
11337pub struct SpendAnalysisConfig {
11338 #[serde(default = "default_hhi_threshold")]
11340 pub hhi_threshold: f64,
11341 #[serde(default = "default_contract_coverage_target")]
11343 pub contract_coverage_target: f64,
11344}
11345
11346impl Default for SpendAnalysisConfig {
11347 fn default() -> Self {
11348 Self {
11349 hhi_threshold: default_hhi_threshold(),
11350 contract_coverage_target: default_contract_coverage_target(),
11351 }
11352 }
11353}
11354
11355fn default_hhi_threshold() -> f64 {
11356 2500.0
11357}
11358fn default_contract_coverage_target() -> f64 {
11359 0.80
11360}
11361
11362#[derive(Debug, Clone, Serialize, Deserialize)]
11364pub struct SourcingConfig {
11365 #[serde(default = "default_sourcing_projects_per_year")]
11367 pub projects_per_year: u32,
11368 #[serde(default = "default_renewal_horizon_months")]
11370 pub renewal_horizon_months: u32,
11371 #[serde(default = "default_project_duration_months")]
11373 pub project_duration_months: u32,
11374}
11375
11376impl Default for SourcingConfig {
11377 fn default() -> Self {
11378 Self {
11379 projects_per_year: default_sourcing_projects_per_year(),
11380 renewal_horizon_months: default_renewal_horizon_months(),
11381 project_duration_months: default_project_duration_months(),
11382 }
11383 }
11384}
11385
11386fn default_sourcing_projects_per_year() -> u32 {
11387 10
11388}
11389fn default_renewal_horizon_months() -> u32 {
11390 3
11391}
11392fn default_project_duration_months() -> u32 {
11393 4
11394}
11395
11396#[derive(Debug, Clone, Serialize, Deserialize)]
11398pub struct QualificationConfig {
11399 #[serde(default = "default_qualification_pass_rate")]
11401 pub pass_rate: f64,
11402 #[serde(default = "default_qualification_validity_days")]
11404 pub validity_days: u32,
11405 #[serde(default = "default_financial_weight")]
11407 pub financial_weight: f64,
11408 #[serde(default = "default_quality_weight")]
11410 pub quality_weight: f64,
11411 #[serde(default = "default_delivery_weight")]
11413 pub delivery_weight: f64,
11414 #[serde(default = "default_compliance_weight")]
11416 pub compliance_weight: f64,
11417}
11418
11419impl Default for QualificationConfig {
11420 fn default() -> Self {
11421 Self {
11422 pass_rate: default_qualification_pass_rate(),
11423 validity_days: default_qualification_validity_days(),
11424 financial_weight: default_financial_weight(),
11425 quality_weight: default_quality_weight(),
11426 delivery_weight: default_delivery_weight(),
11427 compliance_weight: default_compliance_weight(),
11428 }
11429 }
11430}
11431
11432fn default_qualification_pass_rate() -> f64 {
11433 0.75
11434}
11435fn default_qualification_validity_days() -> u32 {
11436 365
11437}
11438fn default_financial_weight() -> f64 {
11439 0.25
11440}
11441fn default_quality_weight() -> f64 {
11442 0.30
11443}
11444fn default_delivery_weight() -> f64 {
11445 0.25
11446}
11447fn default_compliance_weight() -> f64 {
11448 0.20
11449}
11450
11451#[derive(Debug, Clone, Serialize, Deserialize)]
11453pub struct RfxConfig {
11454 #[serde(default = "default_rfi_threshold")]
11456 pub rfi_threshold: f64,
11457 #[serde(default = "default_min_invited_vendors")]
11459 pub min_invited_vendors: u32,
11460 #[serde(default = "default_max_invited_vendors")]
11462 pub max_invited_vendors: u32,
11463 #[serde(default = "default_response_rate")]
11465 pub response_rate: f64,
11466 #[serde(default = "default_price_weight")]
11468 pub default_price_weight: f64,
11469 #[serde(default = "default_rfx_quality_weight")]
11471 pub default_quality_weight: f64,
11472 #[serde(default = "default_rfx_delivery_weight")]
11474 pub default_delivery_weight: f64,
11475}
11476
11477impl Default for RfxConfig {
11478 fn default() -> Self {
11479 Self {
11480 rfi_threshold: default_rfi_threshold(),
11481 min_invited_vendors: default_min_invited_vendors(),
11482 max_invited_vendors: default_max_invited_vendors(),
11483 response_rate: default_response_rate(),
11484 default_price_weight: default_price_weight(),
11485 default_quality_weight: default_rfx_quality_weight(),
11486 default_delivery_weight: default_rfx_delivery_weight(),
11487 }
11488 }
11489}
11490
11491fn default_rfi_threshold() -> f64 {
11492 100_000.0
11493}
11494fn default_min_invited_vendors() -> u32 {
11495 3
11496}
11497fn default_max_invited_vendors() -> u32 {
11498 8
11499}
11500fn default_response_rate() -> f64 {
11501 0.70
11502}
11503fn default_price_weight() -> f64 {
11504 0.40
11505}
11506fn default_rfx_quality_weight() -> f64 {
11507 0.35
11508}
11509fn default_rfx_delivery_weight() -> f64 {
11510 0.25
11511}
11512
11513#[derive(Debug, Clone, Serialize, Deserialize)]
11515pub struct ContractConfig {
11516 #[serde(default = "default_min_contract_months")]
11518 pub min_duration_months: u32,
11519 #[serde(default = "default_max_contract_months")]
11521 pub max_duration_months: u32,
11522 #[serde(default = "default_auto_renewal_rate")]
11524 pub auto_renewal_rate: f64,
11525 #[serde(default = "default_amendment_rate")]
11527 pub amendment_rate: f64,
11528 #[serde(default)]
11530 pub type_distribution: ContractTypeDistribution,
11531}
11532
11533impl Default for ContractConfig {
11534 fn default() -> Self {
11535 Self {
11536 min_duration_months: default_min_contract_months(),
11537 max_duration_months: default_max_contract_months(),
11538 auto_renewal_rate: default_auto_renewal_rate(),
11539 amendment_rate: default_amendment_rate(),
11540 type_distribution: ContractTypeDistribution::default(),
11541 }
11542 }
11543}
11544
11545fn default_min_contract_months() -> u32 {
11546 12
11547}
11548fn default_max_contract_months() -> u32 {
11549 36
11550}
11551fn default_auto_renewal_rate() -> f64 {
11552 0.40
11553}
11554fn default_amendment_rate() -> f64 {
11555 0.20
11556}
11557
11558#[derive(Debug, Clone, Serialize, Deserialize)]
11560pub struct ContractTypeDistribution {
11561 #[serde(default = "default_fixed_price_pct")]
11563 pub fixed_price: f64,
11564 #[serde(default = "default_blanket_pct")]
11566 pub blanket: f64,
11567 #[serde(default = "default_time_materials_pct")]
11569 pub time_and_materials: f64,
11570 #[serde(default = "default_service_agreement_pct")]
11572 pub service_agreement: f64,
11573}
11574
11575impl Default for ContractTypeDistribution {
11576 fn default() -> Self {
11577 Self {
11578 fixed_price: default_fixed_price_pct(),
11579 blanket: default_blanket_pct(),
11580 time_and_materials: default_time_materials_pct(),
11581 service_agreement: default_service_agreement_pct(),
11582 }
11583 }
11584}
11585
11586fn default_fixed_price_pct() -> f64 {
11587 0.40
11588}
11589fn default_blanket_pct() -> f64 {
11590 0.30
11591}
11592fn default_time_materials_pct() -> f64 {
11593 0.15
11594}
11595fn default_service_agreement_pct() -> f64 {
11596 0.15
11597}
11598
11599#[derive(Debug, Clone, Serialize, Deserialize)]
11601pub struct CatalogConfig {
11602 #[serde(default = "default_preferred_vendor_flag_rate")]
11604 pub preferred_vendor_flag_rate: f64,
11605 #[serde(default = "default_multi_source_rate")]
11607 pub multi_source_rate: f64,
11608}
11609
11610impl Default for CatalogConfig {
11611 fn default() -> Self {
11612 Self {
11613 preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
11614 multi_source_rate: default_multi_source_rate(),
11615 }
11616 }
11617}
11618
11619fn default_preferred_vendor_flag_rate() -> f64 {
11620 0.70
11621}
11622fn default_multi_source_rate() -> f64 {
11623 0.25
11624}
11625
11626#[derive(Debug, Clone, Serialize, Deserialize)]
11628pub struct ScorecardConfig {
11629 #[serde(default = "default_scorecard_frequency")]
11631 pub frequency: String,
11632 #[serde(default = "default_otd_weight")]
11634 pub on_time_delivery_weight: f64,
11635 #[serde(default = "default_quality_score_weight")]
11637 pub quality_weight: f64,
11638 #[serde(default = "default_price_score_weight")]
11640 pub price_weight: f64,
11641 #[serde(default = "default_responsiveness_weight")]
11643 pub responsiveness_weight: f64,
11644 #[serde(default = "default_grade_a_threshold")]
11646 pub grade_a_threshold: f64,
11647 #[serde(default = "default_grade_b_threshold")]
11649 pub grade_b_threshold: f64,
11650 #[serde(default = "default_grade_c_threshold")]
11652 pub grade_c_threshold: f64,
11653}
11654
11655impl Default for ScorecardConfig {
11656 fn default() -> Self {
11657 Self {
11658 frequency: default_scorecard_frequency(),
11659 on_time_delivery_weight: default_otd_weight(),
11660 quality_weight: default_quality_score_weight(),
11661 price_weight: default_price_score_weight(),
11662 responsiveness_weight: default_responsiveness_weight(),
11663 grade_a_threshold: default_grade_a_threshold(),
11664 grade_b_threshold: default_grade_b_threshold(),
11665 grade_c_threshold: default_grade_c_threshold(),
11666 }
11667 }
11668}
11669
11670fn default_scorecard_frequency() -> String {
11671 "quarterly".to_string()
11672}
11673fn default_otd_weight() -> f64 {
11674 0.30
11675}
11676fn default_quality_score_weight() -> f64 {
11677 0.30
11678}
11679fn default_price_score_weight() -> f64 {
11680 0.25
11681}
11682fn default_responsiveness_weight() -> f64 {
11683 0.15
11684}
11685fn default_grade_a_threshold() -> f64 {
11686 90.0
11687}
11688fn default_grade_b_threshold() -> f64 {
11689 75.0
11690}
11691fn default_grade_c_threshold() -> f64 {
11692 60.0
11693}
11694
11695#[derive(Debug, Clone, Serialize, Deserialize)]
11697pub struct P2PIntegrationConfig {
11698 #[serde(default = "default_off_contract_rate")]
11700 pub off_contract_rate: f64,
11701 #[serde(default = "default_price_tolerance")]
11703 pub price_tolerance: f64,
11704 #[serde(default)]
11706 pub catalog_enforcement: bool,
11707}
11708
11709impl Default for P2PIntegrationConfig {
11710 fn default() -> Self {
11711 Self {
11712 off_contract_rate: default_off_contract_rate(),
11713 price_tolerance: default_price_tolerance(),
11714 catalog_enforcement: false,
11715 }
11716 }
11717}
11718
11719fn default_off_contract_rate() -> f64 {
11720 0.15
11721}
11722fn default_price_tolerance() -> f64 {
11723 0.02
11724}
11725
11726#[derive(Debug, Clone, Serialize, Deserialize)]
11730pub struct FinancialReportingConfig {
11731 #[serde(default)]
11733 pub enabled: bool,
11734 #[serde(default = "default_true")]
11736 pub generate_balance_sheet: bool,
11737 #[serde(default = "default_true")]
11739 pub generate_income_statement: bool,
11740 #[serde(default = "default_true")]
11742 pub generate_cash_flow: bool,
11743 #[serde(default = "default_true")]
11745 pub generate_changes_in_equity: bool,
11746 #[serde(default = "default_comparative_periods")]
11748 pub comparative_periods: u32,
11749 #[serde(default)]
11751 pub management_kpis: ManagementKpisConfig,
11752 #[serde(default)]
11754 pub budgets: BudgetConfig,
11755}
11756
11757impl Default for FinancialReportingConfig {
11758 fn default() -> Self {
11759 Self {
11760 enabled: false,
11761 generate_balance_sheet: true,
11762 generate_income_statement: true,
11763 generate_cash_flow: true,
11764 generate_changes_in_equity: true,
11765 comparative_periods: default_comparative_periods(),
11766 management_kpis: ManagementKpisConfig::default(),
11767 budgets: BudgetConfig::default(),
11768 }
11769 }
11770}
11771
11772fn default_comparative_periods() -> u32 {
11773 1
11774}
11775
11776#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11778pub struct ManagementKpisConfig {
11779 #[serde(default)]
11781 pub enabled: bool,
11782 #[serde(default = "default_kpi_frequency")]
11784 pub frequency: String,
11785}
11786
11787fn default_kpi_frequency() -> String {
11788 "monthly".to_string()
11789}
11790
11791#[derive(Debug, Clone, Serialize, Deserialize)]
11793pub struct BudgetConfig {
11794 #[serde(default)]
11796 pub enabled: bool,
11797 #[serde(default = "default_revenue_growth_rate")]
11799 pub revenue_growth_rate: f64,
11800 #[serde(default = "default_expense_inflation_rate")]
11802 pub expense_inflation_rate: f64,
11803 #[serde(default = "default_variance_noise")]
11805 pub variance_noise: f64,
11806}
11807
11808impl Default for BudgetConfig {
11809 fn default() -> Self {
11810 Self {
11811 enabled: false,
11812 revenue_growth_rate: default_revenue_growth_rate(),
11813 expense_inflation_rate: default_expense_inflation_rate(),
11814 variance_noise: default_variance_noise(),
11815 }
11816 }
11817}
11818
11819fn default_revenue_growth_rate() -> f64 {
11820 0.05
11821}
11822fn default_expense_inflation_rate() -> f64 {
11823 0.03
11824}
11825fn default_variance_noise() -> f64 {
11826 0.10
11827}
11828
11829#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11833pub struct HrConfig {
11834 #[serde(default)]
11836 pub enabled: bool,
11837 #[serde(default)]
11839 pub payroll: PayrollConfig,
11840 #[serde(default)]
11842 pub time_attendance: TimeAttendanceConfig,
11843 #[serde(default)]
11845 pub expenses: ExpenseConfig,
11846}
11847
11848#[derive(Debug, Clone, Serialize, Deserialize)]
11850pub struct PayrollConfig {
11851 #[serde(default = "default_true")]
11853 pub enabled: bool,
11854 #[serde(default = "default_pay_frequency")]
11856 pub pay_frequency: String,
11857 #[serde(default)]
11859 pub salary_ranges: PayrollSalaryRanges,
11860 #[serde(default)]
11862 pub tax_rates: PayrollTaxRates,
11863 #[serde(default = "default_benefits_enrollment_rate")]
11865 pub benefits_enrollment_rate: f64,
11866 #[serde(default = "default_retirement_participation_rate")]
11868 pub retirement_participation_rate: f64,
11869}
11870
11871impl Default for PayrollConfig {
11872 fn default() -> Self {
11873 Self {
11874 enabled: true,
11875 pay_frequency: default_pay_frequency(),
11876 salary_ranges: PayrollSalaryRanges::default(),
11877 tax_rates: PayrollTaxRates::default(),
11878 benefits_enrollment_rate: default_benefits_enrollment_rate(),
11879 retirement_participation_rate: default_retirement_participation_rate(),
11880 }
11881 }
11882}
11883
11884fn default_pay_frequency() -> String {
11885 "monthly".to_string()
11886}
11887fn default_benefits_enrollment_rate() -> f64 {
11888 0.60
11889}
11890fn default_retirement_participation_rate() -> f64 {
11891 0.45
11892}
11893
11894#[derive(Debug, Clone, Serialize, Deserialize)]
11896pub struct PayrollSalaryRanges {
11897 #[serde(default = "default_staff_min")]
11899 pub staff_min: f64,
11900 #[serde(default = "default_staff_max")]
11901 pub staff_max: f64,
11902 #[serde(default = "default_manager_min")]
11904 pub manager_min: f64,
11905 #[serde(default = "default_manager_max")]
11906 pub manager_max: f64,
11907 #[serde(default = "default_director_min")]
11909 pub director_min: f64,
11910 #[serde(default = "default_director_max")]
11911 pub director_max: f64,
11912 #[serde(default = "default_executive_min")]
11914 pub executive_min: f64,
11915 #[serde(default = "default_executive_max")]
11916 pub executive_max: f64,
11917}
11918
11919impl Default for PayrollSalaryRanges {
11920 fn default() -> Self {
11921 Self {
11922 staff_min: default_staff_min(),
11923 staff_max: default_staff_max(),
11924 manager_min: default_manager_min(),
11925 manager_max: default_manager_max(),
11926 director_min: default_director_min(),
11927 director_max: default_director_max(),
11928 executive_min: default_executive_min(),
11929 executive_max: default_executive_max(),
11930 }
11931 }
11932}
11933
11934fn default_staff_min() -> f64 {
11935 50_000.0
11936}
11937fn default_staff_max() -> f64 {
11938 70_000.0
11939}
11940fn default_manager_min() -> f64 {
11941 80_000.0
11942}
11943fn default_manager_max() -> f64 {
11944 120_000.0
11945}
11946fn default_director_min() -> f64 {
11947 120_000.0
11948}
11949fn default_director_max() -> f64 {
11950 180_000.0
11951}
11952fn default_executive_min() -> f64 {
11953 180_000.0
11954}
11955fn default_executive_max() -> f64 {
11956 350_000.0
11957}
11958
11959#[derive(Debug, Clone, Serialize, Deserialize)]
11961pub struct PayrollTaxRates {
11962 #[serde(default = "default_federal_rate")]
11964 pub federal_effective: f64,
11965 #[serde(default = "default_state_rate")]
11967 pub state_effective: f64,
11968 #[serde(default = "default_fica_rate")]
11970 pub fica: f64,
11971}
11972
11973impl Default for PayrollTaxRates {
11974 fn default() -> Self {
11975 Self {
11976 federal_effective: default_federal_rate(),
11977 state_effective: default_state_rate(),
11978 fica: default_fica_rate(),
11979 }
11980 }
11981}
11982
11983fn default_federal_rate() -> f64 {
11984 0.22
11985}
11986fn default_state_rate() -> f64 {
11987 0.05
11988}
11989fn default_fica_rate() -> f64 {
11990 0.0765
11991}
11992
11993#[derive(Debug, Clone, Serialize, Deserialize)]
11995pub struct TimeAttendanceConfig {
11996 #[serde(default = "default_true")]
11998 pub enabled: bool,
11999 #[serde(default = "default_overtime_rate")]
12001 pub overtime_rate: f64,
12002}
12003
12004impl Default for TimeAttendanceConfig {
12005 fn default() -> Self {
12006 Self {
12007 enabled: true,
12008 overtime_rate: default_overtime_rate(),
12009 }
12010 }
12011}
12012
12013fn default_overtime_rate() -> f64 {
12014 0.10
12015}
12016
12017#[derive(Debug, Clone, Serialize, Deserialize)]
12019pub struct ExpenseConfig {
12020 #[serde(default = "default_true")]
12022 pub enabled: bool,
12023 #[serde(default = "default_expense_submission_rate")]
12025 pub submission_rate: f64,
12026 #[serde(default = "default_policy_violation_rate")]
12028 pub policy_violation_rate: f64,
12029}
12030
12031impl Default for ExpenseConfig {
12032 fn default() -> Self {
12033 Self {
12034 enabled: true,
12035 submission_rate: default_expense_submission_rate(),
12036 policy_violation_rate: default_policy_violation_rate(),
12037 }
12038 }
12039}
12040
12041fn default_expense_submission_rate() -> f64 {
12042 0.30
12043}
12044fn default_policy_violation_rate() -> f64 {
12045 0.08
12046}
12047
12048#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12052pub struct ManufacturingProcessConfig {
12053 #[serde(default)]
12055 pub enabled: bool,
12056 #[serde(default)]
12058 pub production_orders: ProductionOrderConfig,
12059 #[serde(default)]
12061 pub costing: ManufacturingCostingConfig,
12062 #[serde(default)]
12064 pub routing: RoutingConfig,
12065}
12066
12067#[derive(Debug, Clone, Serialize, Deserialize)]
12069pub struct ProductionOrderConfig {
12070 #[serde(default = "default_prod_orders_per_month")]
12072 pub orders_per_month: u32,
12073 #[serde(default = "default_prod_avg_batch_size")]
12075 pub avg_batch_size: u32,
12076 #[serde(default = "default_prod_yield_rate")]
12078 pub yield_rate: f64,
12079 #[serde(default = "default_prod_make_to_order_rate")]
12081 pub make_to_order_rate: f64,
12082 #[serde(default = "default_prod_rework_rate")]
12084 pub rework_rate: f64,
12085}
12086
12087impl Default for ProductionOrderConfig {
12088 fn default() -> Self {
12089 Self {
12090 orders_per_month: default_prod_orders_per_month(),
12091 avg_batch_size: default_prod_avg_batch_size(),
12092 yield_rate: default_prod_yield_rate(),
12093 make_to_order_rate: default_prod_make_to_order_rate(),
12094 rework_rate: default_prod_rework_rate(),
12095 }
12096 }
12097}
12098
12099fn default_prod_orders_per_month() -> u32 {
12100 50
12101}
12102fn default_prod_avg_batch_size() -> u32 {
12103 100
12104}
12105fn default_prod_yield_rate() -> f64 {
12106 0.97
12107}
12108fn default_prod_make_to_order_rate() -> f64 {
12109 0.20
12110}
12111fn default_prod_rework_rate() -> f64 {
12112 0.03
12113}
12114
12115#[derive(Debug, Clone, Serialize, Deserialize)]
12117pub struct ManufacturingCostingConfig {
12118 #[serde(default = "default_labor_rate")]
12120 pub labor_rate_per_hour: f64,
12121 #[serde(default = "default_overhead_rate")]
12123 pub overhead_rate: f64,
12124 #[serde(default = "default_cost_update_frequency")]
12126 pub standard_cost_update_frequency: String,
12127}
12128
12129impl Default for ManufacturingCostingConfig {
12130 fn default() -> Self {
12131 Self {
12132 labor_rate_per_hour: default_labor_rate(),
12133 overhead_rate: default_overhead_rate(),
12134 standard_cost_update_frequency: default_cost_update_frequency(),
12135 }
12136 }
12137}
12138
12139fn default_labor_rate() -> f64 {
12140 35.0
12141}
12142fn default_overhead_rate() -> f64 {
12143 1.50
12144}
12145fn default_cost_update_frequency() -> String {
12146 "quarterly".to_string()
12147}
12148
12149#[derive(Debug, Clone, Serialize, Deserialize)]
12151pub struct RoutingConfig {
12152 #[serde(default = "default_avg_operations")]
12154 pub avg_operations: u32,
12155 #[serde(default = "default_setup_time")]
12157 pub setup_time_hours: f64,
12158 #[serde(default = "default_run_time_variation")]
12160 pub run_time_variation: f64,
12161}
12162
12163impl Default for RoutingConfig {
12164 fn default() -> Self {
12165 Self {
12166 avg_operations: default_avg_operations(),
12167 setup_time_hours: default_setup_time(),
12168 run_time_variation: default_run_time_variation(),
12169 }
12170 }
12171}
12172
12173fn default_avg_operations() -> u32 {
12174 4
12175}
12176fn default_setup_time() -> f64 {
12177 1.5
12178}
12179fn default_run_time_variation() -> f64 {
12180 0.15
12181}
12182
12183#[derive(Debug, Clone, Serialize, Deserialize)]
12187pub struct SalesQuoteConfig {
12188 #[serde(default)]
12190 pub enabled: bool,
12191 #[serde(default = "default_quotes_per_month")]
12193 pub quotes_per_month: u32,
12194 #[serde(default = "default_quote_win_rate")]
12196 pub win_rate: f64,
12197 #[serde(default = "default_quote_validity_days")]
12199 pub validity_days: u32,
12200}
12201
12202impl Default for SalesQuoteConfig {
12203 fn default() -> Self {
12204 Self {
12205 enabled: false,
12206 quotes_per_month: default_quotes_per_month(),
12207 win_rate: default_quote_win_rate(),
12208 validity_days: default_quote_validity_days(),
12209 }
12210 }
12211}
12212
12213fn default_quotes_per_month() -> u32 {
12214 30
12215}
12216fn default_quote_win_rate() -> f64 {
12217 0.35
12218}
12219fn default_quote_validity_days() -> u32 {
12220 30
12221}
12222
12223#[derive(Debug, Clone, Serialize, Deserialize)]
12232pub struct TaxConfig {
12233 #[serde(default)]
12235 pub enabled: bool,
12236 #[serde(default)]
12238 pub jurisdictions: TaxJurisdictionConfig,
12239 #[serde(default)]
12241 pub vat_gst: VatGstConfig,
12242 #[serde(default)]
12244 pub sales_tax: SalesTaxConfig,
12245 #[serde(default)]
12247 pub withholding: WithholdingTaxSchemaConfig,
12248 #[serde(default)]
12250 pub provisions: TaxProvisionSchemaConfig,
12251 #[serde(default)]
12253 pub payroll_tax: PayrollTaxSchemaConfig,
12254 #[serde(default = "default_tax_anomaly_rate")]
12256 pub anomaly_rate: f64,
12257}
12258
12259fn default_tax_anomaly_rate() -> f64 {
12260 0.03
12261}
12262
12263impl Default for TaxConfig {
12264 fn default() -> Self {
12265 Self {
12266 enabled: false,
12267 jurisdictions: TaxJurisdictionConfig::default(),
12268 vat_gst: VatGstConfig::default(),
12269 sales_tax: SalesTaxConfig::default(),
12270 withholding: WithholdingTaxSchemaConfig::default(),
12271 provisions: TaxProvisionSchemaConfig::default(),
12272 payroll_tax: PayrollTaxSchemaConfig::default(),
12273 anomaly_rate: default_tax_anomaly_rate(),
12274 }
12275 }
12276}
12277
12278#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12283pub struct TaxJurisdictionConfig {
12284 #[serde(default)]
12286 pub countries: Vec<String>,
12287 #[serde(default)]
12289 pub include_subnational: bool,
12290}
12291
12292#[derive(Debug, Clone, Serialize, Deserialize)]
12297pub struct VatGstConfig {
12298 #[serde(default)]
12300 pub enabled: bool,
12301 #[serde(default)]
12303 pub standard_rates: std::collections::HashMap<String, f64>,
12304 #[serde(default)]
12306 pub reduced_rates: std::collections::HashMap<String, f64>,
12307 #[serde(default)]
12309 pub exempt_categories: Vec<String>,
12310 #[serde(default = "default_true")]
12312 pub reverse_charge: bool,
12313}
12314
12315impl Default for VatGstConfig {
12316 fn default() -> Self {
12317 Self {
12318 enabled: false,
12319 standard_rates: std::collections::HashMap::new(),
12320 reduced_rates: std::collections::HashMap::new(),
12321 exempt_categories: Vec::new(),
12322 reverse_charge: true,
12323 }
12324 }
12325}
12326
12327#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12331pub struct SalesTaxConfig {
12332 #[serde(default)]
12334 pub enabled: bool,
12335 #[serde(default)]
12337 pub nexus_states: Vec<String>,
12338}
12339
12340#[derive(Debug, Clone, Serialize, Deserialize)]
12345pub struct WithholdingTaxSchemaConfig {
12346 #[serde(default)]
12348 pub enabled: bool,
12349 #[serde(default = "default_true")]
12351 pub treaty_network: bool,
12352 #[serde(default = "default_withholding_rate")]
12354 pub default_rate: f64,
12355 #[serde(default = "default_treaty_reduced_rate")]
12357 pub treaty_reduced_rate: f64,
12358}
12359
12360fn default_withholding_rate() -> f64 {
12361 0.30
12362}
12363
12364fn default_treaty_reduced_rate() -> f64 {
12365 0.15
12366}
12367
12368impl Default for WithholdingTaxSchemaConfig {
12369 fn default() -> Self {
12370 Self {
12371 enabled: false,
12372 treaty_network: true,
12373 default_rate: default_withholding_rate(),
12374 treaty_reduced_rate: default_treaty_reduced_rate(),
12375 }
12376 }
12377}
12378
12379#[derive(Debug, Clone, Serialize, Deserialize)]
12384pub struct TaxProvisionSchemaConfig {
12385 #[serde(default = "default_true")]
12388 pub enabled: bool,
12389 #[serde(default = "default_statutory_rate")]
12391 pub statutory_rate: f64,
12392 #[serde(default = "default_true")]
12394 pub uncertain_positions: bool,
12395}
12396
12397fn default_statutory_rate() -> f64 {
12398 0.21
12399}
12400
12401impl Default for TaxProvisionSchemaConfig {
12402 fn default() -> Self {
12403 Self {
12404 enabled: true,
12405 statutory_rate: default_statutory_rate(),
12406 uncertain_positions: true,
12407 }
12408 }
12409}
12410
12411#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12416pub struct PayrollTaxSchemaConfig {
12417 #[serde(default)]
12419 pub enabled: bool,
12420}
12421
12422#[derive(Debug, Clone, Serialize, Deserialize)]
12432pub struct TreasuryConfig {
12433 #[serde(default)]
12435 pub enabled: bool,
12436 #[serde(default)]
12438 pub cash_positioning: CashPositioningConfig,
12439 #[serde(default)]
12441 pub cash_forecasting: CashForecastingConfig,
12442 #[serde(default)]
12444 pub cash_pooling: CashPoolingConfig,
12445 #[serde(default)]
12447 pub hedging: HedgingSchemaConfig,
12448 #[serde(default)]
12450 pub debt: DebtSchemaConfig,
12451 #[serde(default)]
12453 pub netting: NettingSchemaConfig,
12454 #[serde(default)]
12456 pub bank_guarantees: BankGuaranteeSchemaConfig,
12457 #[serde(default = "default_treasury_anomaly_rate")]
12459 pub anomaly_rate: f64,
12460}
12461
12462fn default_treasury_anomaly_rate() -> f64 {
12463 0.02
12464}
12465
12466impl Default for TreasuryConfig {
12467 fn default() -> Self {
12468 Self {
12469 enabled: false,
12470 cash_positioning: CashPositioningConfig::default(),
12471 cash_forecasting: CashForecastingConfig::default(),
12472 cash_pooling: CashPoolingConfig::default(),
12473 hedging: HedgingSchemaConfig::default(),
12474 debt: DebtSchemaConfig::default(),
12475 netting: NettingSchemaConfig::default(),
12476 bank_guarantees: BankGuaranteeSchemaConfig::default(),
12477 anomaly_rate: default_treasury_anomaly_rate(),
12478 }
12479 }
12480}
12481
12482#[derive(Debug, Clone, Serialize, Deserialize)]
12486pub struct CashPositioningConfig {
12487 #[serde(default = "default_true")]
12489 pub enabled: bool,
12490 #[serde(default = "default_cash_frequency")]
12492 pub frequency: String,
12493 #[serde(default = "default_minimum_balance_policy")]
12495 pub minimum_balance_policy: f64,
12496}
12497
12498fn default_cash_frequency() -> String {
12499 "daily".to_string()
12500}
12501
12502fn default_minimum_balance_policy() -> f64 {
12503 100_000.0
12504}
12505
12506impl Default for CashPositioningConfig {
12507 fn default() -> Self {
12508 Self {
12509 enabled: true,
12510 frequency: default_cash_frequency(),
12511 minimum_balance_policy: default_minimum_balance_policy(),
12512 }
12513 }
12514}
12515
12516#[derive(Debug, Clone, Serialize, Deserialize)]
12520pub struct CashForecastingConfig {
12521 #[serde(default = "default_true")]
12523 pub enabled: bool,
12524 #[serde(default = "default_horizon_days")]
12526 pub horizon_days: u32,
12527 #[serde(default = "default_ar_probability_curve")]
12529 pub ar_collection_probability_curve: String,
12530 #[serde(default = "default_confidence_interval")]
12532 pub confidence_interval: f64,
12533}
12534
12535fn default_horizon_days() -> u32 {
12536 90
12537}
12538
12539fn default_ar_probability_curve() -> String {
12540 "aging".to_string()
12541}
12542
12543fn default_confidence_interval() -> f64 {
12544 0.90
12545}
12546
12547impl Default for CashForecastingConfig {
12548 fn default() -> Self {
12549 Self {
12550 enabled: true,
12551 horizon_days: default_horizon_days(),
12552 ar_collection_probability_curve: default_ar_probability_curve(),
12553 confidence_interval: default_confidence_interval(),
12554 }
12555 }
12556}
12557
12558#[derive(Debug, Clone, Serialize, Deserialize)]
12562pub struct CashPoolingConfig {
12563 #[serde(default)]
12565 pub enabled: bool,
12566 #[serde(default = "default_pool_type")]
12568 pub pool_type: String,
12569 #[serde(default = "default_sweep_time")]
12571 pub sweep_time: String,
12572}
12573
12574fn default_pool_type() -> String {
12575 "zero_balancing".to_string()
12576}
12577
12578fn default_sweep_time() -> String {
12579 "16:00".to_string()
12580}
12581
12582impl Default for CashPoolingConfig {
12583 fn default() -> Self {
12584 Self {
12585 enabled: false,
12586 pool_type: default_pool_type(),
12587 sweep_time: default_sweep_time(),
12588 }
12589 }
12590}
12591
12592#[derive(Debug, Clone, Serialize, Deserialize)]
12597pub struct HedgingSchemaConfig {
12598 #[serde(default)]
12600 pub enabled: bool,
12601 #[serde(default = "default_hedge_ratio")]
12603 pub hedge_ratio: f64,
12604 #[serde(default = "default_hedge_instruments")]
12606 pub instruments: Vec<String>,
12607 #[serde(default = "default_true")]
12609 pub hedge_accounting: bool,
12610 #[serde(default = "default_effectiveness_method")]
12612 pub effectiveness_method: String,
12613}
12614
12615fn default_hedge_ratio() -> f64 {
12616 0.75
12617}
12618
12619fn default_hedge_instruments() -> Vec<String> {
12620 vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
12621}
12622
12623fn default_effectiveness_method() -> String {
12624 "regression".to_string()
12625}
12626
12627impl Default for HedgingSchemaConfig {
12628 fn default() -> Self {
12629 Self {
12630 enabled: false,
12631 hedge_ratio: default_hedge_ratio(),
12632 instruments: default_hedge_instruments(),
12633 hedge_accounting: true,
12634 effectiveness_method: default_effectiveness_method(),
12635 }
12636 }
12637}
12638
12639#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12644pub struct DebtSchemaConfig {
12645 #[serde(default)]
12647 pub enabled: bool,
12648 #[serde(default)]
12650 pub instruments: Vec<DebtInstrumentDef>,
12651 #[serde(default)]
12653 pub covenants: Vec<CovenantDef>,
12654}
12655
12656#[derive(Debug, Clone, Serialize, Deserialize)]
12658pub struct DebtInstrumentDef {
12659 #[serde(rename = "type")]
12661 pub instrument_type: String,
12662 #[serde(default)]
12664 pub principal: Option<f64>,
12665 #[serde(default)]
12667 pub rate: Option<f64>,
12668 #[serde(default)]
12670 pub maturity_months: Option<u32>,
12671 #[serde(default)]
12673 pub facility: Option<f64>,
12674}
12675
12676#[derive(Debug, Clone, Serialize, Deserialize)]
12678pub struct CovenantDef {
12679 #[serde(rename = "type")]
12682 pub covenant_type: String,
12683 pub threshold: f64,
12685}
12686
12687#[derive(Debug, Clone, Serialize, Deserialize)]
12691pub struct NettingSchemaConfig {
12692 #[serde(default)]
12694 pub enabled: bool,
12695 #[serde(default = "default_netting_cycle")]
12697 pub cycle: String,
12698}
12699
12700fn default_netting_cycle() -> String {
12701 "monthly".to_string()
12702}
12703
12704impl Default for NettingSchemaConfig {
12705 fn default() -> Self {
12706 Self {
12707 enabled: false,
12708 cycle: default_netting_cycle(),
12709 }
12710 }
12711}
12712
12713#[derive(Debug, Clone, Serialize, Deserialize)]
12717pub struct BankGuaranteeSchemaConfig {
12718 #[serde(default)]
12720 pub enabled: bool,
12721 #[serde(default = "default_guarantee_count")]
12723 pub count: u32,
12724}
12725
12726fn default_guarantee_count() -> u32 {
12727 5
12728}
12729
12730impl Default for BankGuaranteeSchemaConfig {
12731 fn default() -> Self {
12732 Self {
12733 enabled: false,
12734 count: default_guarantee_count(),
12735 }
12736 }
12737}
12738
12739#[derive(Debug, Clone, Serialize, Deserialize)]
12748pub struct ProjectAccountingConfig {
12749 #[serde(default)]
12751 pub enabled: bool,
12752 #[serde(default = "default_project_count")]
12754 pub project_count: u32,
12755 #[serde(default)]
12757 pub project_types: ProjectTypeDistribution,
12758 #[serde(default)]
12760 pub wbs: WbsSchemaConfig,
12761 #[serde(default)]
12763 pub cost_allocation: CostAllocationConfig,
12764 #[serde(default)]
12766 pub revenue_recognition: ProjectRevenueRecognitionConfig,
12767 #[serde(default)]
12769 pub milestones: MilestoneSchemaConfig,
12770 #[serde(default)]
12772 pub change_orders: ChangeOrderSchemaConfig,
12773 #[serde(default)]
12775 pub retainage: RetainageSchemaConfig,
12776 #[serde(default)]
12778 pub earned_value: EarnedValueSchemaConfig,
12779 #[serde(default = "default_project_anomaly_rate")]
12781 pub anomaly_rate: f64,
12782}
12783
12784fn default_project_count() -> u32 {
12785 10
12786}
12787
12788fn default_project_anomaly_rate() -> f64 {
12789 0.03
12790}
12791
12792impl Default for ProjectAccountingConfig {
12793 fn default() -> Self {
12794 Self {
12795 enabled: false,
12796 project_count: default_project_count(),
12797 project_types: ProjectTypeDistribution::default(),
12798 wbs: WbsSchemaConfig::default(),
12799 cost_allocation: CostAllocationConfig::default(),
12800 revenue_recognition: ProjectRevenueRecognitionConfig::default(),
12801 milestones: MilestoneSchemaConfig::default(),
12802 change_orders: ChangeOrderSchemaConfig::default(),
12803 retainage: RetainageSchemaConfig::default(),
12804 earned_value: EarnedValueSchemaConfig::default(),
12805 anomaly_rate: default_project_anomaly_rate(),
12806 }
12807 }
12808}
12809
12810#[derive(Debug, Clone, Serialize, Deserialize)]
12812pub struct ProjectTypeDistribution {
12813 #[serde(default = "default_capital_weight")]
12815 pub capital: f64,
12816 #[serde(default = "default_internal_weight")]
12818 pub internal: f64,
12819 #[serde(default = "default_customer_weight")]
12821 pub customer: f64,
12822 #[serde(default = "default_rnd_weight")]
12824 pub r_and_d: f64,
12825 #[serde(default = "default_maintenance_weight")]
12827 pub maintenance: f64,
12828 #[serde(default = "default_technology_weight")]
12830 pub technology: f64,
12831}
12832
12833fn default_capital_weight() -> f64 {
12834 0.25
12835}
12836fn default_internal_weight() -> f64 {
12837 0.20
12838}
12839fn default_customer_weight() -> f64 {
12840 0.30
12841}
12842fn default_rnd_weight() -> f64 {
12843 0.10
12844}
12845fn default_maintenance_weight() -> f64 {
12846 0.10
12847}
12848fn default_technology_weight() -> f64 {
12849 0.05
12850}
12851
12852impl Default for ProjectTypeDistribution {
12853 fn default() -> Self {
12854 Self {
12855 capital: default_capital_weight(),
12856 internal: default_internal_weight(),
12857 customer: default_customer_weight(),
12858 r_and_d: default_rnd_weight(),
12859 maintenance: default_maintenance_weight(),
12860 technology: default_technology_weight(),
12861 }
12862 }
12863}
12864
12865#[derive(Debug, Clone, Serialize, Deserialize)]
12867pub struct WbsSchemaConfig {
12868 #[serde(default = "default_wbs_max_depth")]
12870 pub max_depth: u32,
12871 #[serde(default = "default_wbs_min_elements")]
12873 pub min_elements_per_level: u32,
12874 #[serde(default = "default_wbs_max_elements")]
12876 pub max_elements_per_level: u32,
12877}
12878
12879fn default_wbs_max_depth() -> u32 {
12880 3
12881}
12882fn default_wbs_min_elements() -> u32 {
12883 2
12884}
12885fn default_wbs_max_elements() -> u32 {
12886 6
12887}
12888
12889impl Default for WbsSchemaConfig {
12890 fn default() -> Self {
12891 Self {
12892 max_depth: default_wbs_max_depth(),
12893 min_elements_per_level: default_wbs_min_elements(),
12894 max_elements_per_level: default_wbs_max_elements(),
12895 }
12896 }
12897}
12898
12899#[derive(Debug, Clone, Serialize, Deserialize)]
12901pub struct CostAllocationConfig {
12902 #[serde(default = "default_time_entry_rate")]
12904 pub time_entry_project_rate: f64,
12905 #[serde(default = "default_expense_rate")]
12907 pub expense_project_rate: f64,
12908 #[serde(default = "default_po_rate")]
12910 pub purchase_order_project_rate: f64,
12911 #[serde(default = "default_vi_rate")]
12913 pub vendor_invoice_project_rate: f64,
12914}
12915
12916fn default_time_entry_rate() -> f64 {
12917 0.60
12918}
12919fn default_expense_rate() -> f64 {
12920 0.30
12921}
12922fn default_po_rate() -> f64 {
12923 0.40
12924}
12925fn default_vi_rate() -> f64 {
12926 0.35
12927}
12928
12929impl Default for CostAllocationConfig {
12930 fn default() -> Self {
12931 Self {
12932 time_entry_project_rate: default_time_entry_rate(),
12933 expense_project_rate: default_expense_rate(),
12934 purchase_order_project_rate: default_po_rate(),
12935 vendor_invoice_project_rate: default_vi_rate(),
12936 }
12937 }
12938}
12939
12940#[derive(Debug, Clone, Serialize, Deserialize)]
12942pub struct ProjectRevenueRecognitionConfig {
12943 #[serde(default = "default_true")]
12945 pub enabled: bool,
12946 #[serde(default = "default_revenue_method")]
12948 pub method: String,
12949 #[serde(default = "default_completion_measure")]
12951 pub completion_measure: String,
12952 #[serde(default = "default_avg_contract_value")]
12954 pub avg_contract_value: f64,
12955}
12956
12957fn default_revenue_method() -> String {
12958 "percentage_of_completion".to_string()
12959}
12960fn default_completion_measure() -> String {
12961 "cost_to_cost".to_string()
12962}
12963fn default_avg_contract_value() -> f64 {
12964 500_000.0
12965}
12966
12967impl Default for ProjectRevenueRecognitionConfig {
12968 fn default() -> Self {
12969 Self {
12970 enabled: true,
12971 method: default_revenue_method(),
12972 completion_measure: default_completion_measure(),
12973 avg_contract_value: default_avg_contract_value(),
12974 }
12975 }
12976}
12977
12978#[derive(Debug, Clone, Serialize, Deserialize)]
12980pub struct MilestoneSchemaConfig {
12981 #[serde(default = "default_true")]
12983 pub enabled: bool,
12984 #[serde(default = "default_milestones_per_project")]
12986 pub avg_per_project: u32,
12987 #[serde(default = "default_payment_milestone_rate")]
12989 pub payment_milestone_rate: f64,
12990}
12991
12992fn default_milestones_per_project() -> u32 {
12993 4
12994}
12995fn default_payment_milestone_rate() -> f64 {
12996 0.50
12997}
12998
12999impl Default for MilestoneSchemaConfig {
13000 fn default() -> Self {
13001 Self {
13002 enabled: true,
13003 avg_per_project: default_milestones_per_project(),
13004 payment_milestone_rate: default_payment_milestone_rate(),
13005 }
13006 }
13007}
13008
13009#[derive(Debug, Clone, Serialize, Deserialize)]
13011pub struct ChangeOrderSchemaConfig {
13012 #[serde(default = "default_true")]
13014 pub enabled: bool,
13015 #[serde(default = "default_change_order_probability")]
13017 pub probability: f64,
13018 #[serde(default = "default_max_change_orders")]
13020 pub max_per_project: u32,
13021 #[serde(default = "default_change_order_approval_rate")]
13023 pub approval_rate: f64,
13024}
13025
13026fn default_change_order_probability() -> f64 {
13027 0.40
13028}
13029fn default_max_change_orders() -> u32 {
13030 3
13031}
13032fn default_change_order_approval_rate() -> f64 {
13033 0.75
13034}
13035
13036impl Default for ChangeOrderSchemaConfig {
13037 fn default() -> Self {
13038 Self {
13039 enabled: true,
13040 probability: default_change_order_probability(),
13041 max_per_project: default_max_change_orders(),
13042 approval_rate: default_change_order_approval_rate(),
13043 }
13044 }
13045}
13046
13047#[derive(Debug, Clone, Serialize, Deserialize)]
13049pub struct RetainageSchemaConfig {
13050 #[serde(default)]
13052 pub enabled: bool,
13053 #[serde(default = "default_retainage_pct")]
13055 pub default_percentage: f64,
13056}
13057
13058fn default_retainage_pct() -> f64 {
13059 0.10
13060}
13061
13062impl Default for RetainageSchemaConfig {
13063 fn default() -> Self {
13064 Self {
13065 enabled: false,
13066 default_percentage: default_retainage_pct(),
13067 }
13068 }
13069}
13070
13071#[derive(Debug, Clone, Serialize, Deserialize)]
13073pub struct EarnedValueSchemaConfig {
13074 #[serde(default = "default_true")]
13076 pub enabled: bool,
13077 #[serde(default = "default_evm_frequency")]
13079 pub frequency: String,
13080}
13081
13082fn default_evm_frequency() -> String {
13083 "monthly".to_string()
13084}
13085
13086impl Default for EarnedValueSchemaConfig {
13087 fn default() -> Self {
13088 Self {
13089 enabled: true,
13090 frequency: default_evm_frequency(),
13091 }
13092 }
13093}
13094
13095#[derive(Debug, Clone, Serialize, Deserialize)]
13101pub struct EsgConfig {
13102 #[serde(default)]
13104 pub enabled: bool,
13105 #[serde(default)]
13107 pub environmental: EnvironmentalConfig,
13108 #[serde(default)]
13110 pub social: SocialConfig,
13111 #[serde(default)]
13113 pub governance: GovernanceSchemaConfig,
13114 #[serde(default)]
13116 pub supply_chain_esg: SupplyChainEsgConfig,
13117 #[serde(default)]
13119 pub reporting: EsgReportingConfig,
13120 #[serde(default)]
13122 pub climate_scenarios: ClimateScenarioConfig,
13123 #[serde(default = "default_esg_anomaly_rate")]
13125 pub anomaly_rate: f64,
13126}
13127
13128fn default_esg_anomaly_rate() -> f64 {
13129 0.02
13130}
13131
13132impl Default for EsgConfig {
13133 fn default() -> Self {
13134 Self {
13135 enabled: false,
13136 environmental: EnvironmentalConfig::default(),
13137 social: SocialConfig::default(),
13138 governance: GovernanceSchemaConfig::default(),
13139 supply_chain_esg: SupplyChainEsgConfig::default(),
13140 reporting: EsgReportingConfig::default(),
13141 climate_scenarios: ClimateScenarioConfig::default(),
13142 anomaly_rate: default_esg_anomaly_rate(),
13143 }
13144 }
13145}
13146
13147#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13152pub struct CountryPacksSchemaConfig {
13153 #[serde(default)]
13155 pub external_dir: Option<PathBuf>,
13156 #[serde(default)]
13160 pub overrides: std::collections::HashMap<String, serde_json::Value>,
13161}
13162
13163#[derive(Debug, Clone, Serialize, Deserialize)]
13165pub struct EnvironmentalConfig {
13166 #[serde(default = "default_true")]
13168 pub enabled: bool,
13169 #[serde(default)]
13171 pub scope1: EmissionScopeConfig,
13172 #[serde(default)]
13174 pub scope2: EmissionScopeConfig,
13175 #[serde(default)]
13177 pub scope3: Scope3Config,
13178 #[serde(default)]
13180 pub energy: EnergySchemaConfig,
13181 #[serde(default)]
13183 pub water: WaterSchemaConfig,
13184 #[serde(default)]
13186 pub waste: WasteSchemaConfig,
13187}
13188
13189impl Default for EnvironmentalConfig {
13190 fn default() -> Self {
13191 Self {
13192 enabled: true,
13193 scope1: EmissionScopeConfig::default(),
13194 scope2: EmissionScopeConfig::default(),
13195 scope3: Scope3Config::default(),
13196 energy: EnergySchemaConfig::default(),
13197 water: WaterSchemaConfig::default(),
13198 waste: WasteSchemaConfig::default(),
13199 }
13200 }
13201}
13202
13203#[derive(Debug, Clone, Serialize, Deserialize)]
13205pub struct EmissionScopeConfig {
13206 #[serde(default = "default_true")]
13208 pub enabled: bool,
13209 #[serde(default = "default_emission_region")]
13211 pub factor_region: String,
13212}
13213
13214fn default_emission_region() -> String {
13215 "US".to_string()
13216}
13217
13218impl Default for EmissionScopeConfig {
13219 fn default() -> Self {
13220 Self {
13221 enabled: true,
13222 factor_region: default_emission_region(),
13223 }
13224 }
13225}
13226
13227#[derive(Debug, Clone, Serialize, Deserialize)]
13229pub struct Scope3Config {
13230 #[serde(default = "default_true")]
13232 pub enabled: bool,
13233 #[serde(default = "default_scope3_categories")]
13235 pub categories: Vec<String>,
13236 #[serde(default = "default_spend_intensity")]
13238 pub default_spend_intensity_kg_per_usd: f64,
13239}
13240
13241fn default_scope3_categories() -> Vec<String> {
13242 vec![
13243 "purchased_goods".to_string(),
13244 "business_travel".to_string(),
13245 "employee_commuting".to_string(),
13246 ]
13247}
13248
13249fn default_spend_intensity() -> f64 {
13250 0.5
13251}
13252
13253impl Default for Scope3Config {
13254 fn default() -> Self {
13255 Self {
13256 enabled: true,
13257 categories: default_scope3_categories(),
13258 default_spend_intensity_kg_per_usd: default_spend_intensity(),
13259 }
13260 }
13261}
13262
13263#[derive(Debug, Clone, Serialize, Deserialize)]
13265pub struct EnergySchemaConfig {
13266 #[serde(default = "default_true")]
13268 pub enabled: bool,
13269 #[serde(default = "default_facility_count")]
13271 pub facility_count: u32,
13272 #[serde(default = "default_renewable_target")]
13274 pub renewable_target: f64,
13275}
13276
13277fn default_facility_count() -> u32 {
13278 5
13279}
13280
13281fn default_renewable_target() -> f64 {
13282 0.30
13283}
13284
13285impl Default for EnergySchemaConfig {
13286 fn default() -> Self {
13287 Self {
13288 enabled: true,
13289 facility_count: default_facility_count(),
13290 renewable_target: default_renewable_target(),
13291 }
13292 }
13293}
13294
13295#[derive(Debug, Clone, Serialize, Deserialize)]
13297pub struct WaterSchemaConfig {
13298 #[serde(default = "default_true")]
13300 pub enabled: bool,
13301 #[serde(default = "default_water_facility_count")]
13303 pub facility_count: u32,
13304}
13305
13306fn default_water_facility_count() -> u32 {
13307 3
13308}
13309
13310impl Default for WaterSchemaConfig {
13311 fn default() -> Self {
13312 Self {
13313 enabled: true,
13314 facility_count: default_water_facility_count(),
13315 }
13316 }
13317}
13318
13319#[derive(Debug, Clone, Serialize, Deserialize)]
13321pub struct WasteSchemaConfig {
13322 #[serde(default = "default_true")]
13324 pub enabled: bool,
13325 #[serde(default = "default_diversion_target")]
13327 pub diversion_target: f64,
13328}
13329
13330fn default_diversion_target() -> f64 {
13331 0.50
13332}
13333
13334impl Default for WasteSchemaConfig {
13335 fn default() -> Self {
13336 Self {
13337 enabled: true,
13338 diversion_target: default_diversion_target(),
13339 }
13340 }
13341}
13342
13343#[derive(Debug, Clone, Serialize, Deserialize)]
13345pub struct SocialConfig {
13346 #[serde(default = "default_true")]
13348 pub enabled: bool,
13349 #[serde(default)]
13351 pub diversity: DiversitySchemaConfig,
13352 #[serde(default)]
13354 pub pay_equity: PayEquitySchemaConfig,
13355 #[serde(default)]
13357 pub safety: SafetySchemaConfig,
13358}
13359
13360impl Default for SocialConfig {
13361 fn default() -> Self {
13362 Self {
13363 enabled: true,
13364 diversity: DiversitySchemaConfig::default(),
13365 pay_equity: PayEquitySchemaConfig::default(),
13366 safety: SafetySchemaConfig::default(),
13367 }
13368 }
13369}
13370
13371#[derive(Debug, Clone, Serialize, Deserialize)]
13373pub struct DiversitySchemaConfig {
13374 #[serde(default = "default_true")]
13376 pub enabled: bool,
13377 #[serde(default = "default_diversity_dimensions")]
13379 pub dimensions: Vec<String>,
13380}
13381
13382fn default_diversity_dimensions() -> Vec<String> {
13383 vec![
13384 "gender".to_string(),
13385 "ethnicity".to_string(),
13386 "age_group".to_string(),
13387 ]
13388}
13389
13390impl Default for DiversitySchemaConfig {
13391 fn default() -> Self {
13392 Self {
13393 enabled: true,
13394 dimensions: default_diversity_dimensions(),
13395 }
13396 }
13397}
13398
13399#[derive(Debug, Clone, Serialize, Deserialize)]
13401pub struct PayEquitySchemaConfig {
13402 #[serde(default = "default_true")]
13404 pub enabled: bool,
13405 #[serde(default = "default_pay_gap_threshold")]
13407 pub gap_threshold: f64,
13408}
13409
13410fn default_pay_gap_threshold() -> f64 {
13411 0.05
13412}
13413
13414impl Default for PayEquitySchemaConfig {
13415 fn default() -> Self {
13416 Self {
13417 enabled: true,
13418 gap_threshold: default_pay_gap_threshold(),
13419 }
13420 }
13421}
13422
13423#[derive(Debug, Clone, Serialize, Deserialize)]
13425pub struct SafetySchemaConfig {
13426 #[serde(default = "default_true")]
13428 pub enabled: bool,
13429 #[serde(default = "default_trir_target")]
13431 pub target_trir: f64,
13432 #[serde(default = "default_incident_count")]
13434 pub incident_count: u32,
13435}
13436
13437fn default_trir_target() -> f64 {
13438 2.5
13439}
13440
13441fn default_incident_count() -> u32 {
13442 20
13443}
13444
13445impl Default for SafetySchemaConfig {
13446 fn default() -> Self {
13447 Self {
13448 enabled: true,
13449 target_trir: default_trir_target(),
13450 incident_count: default_incident_count(),
13451 }
13452 }
13453}
13454
13455#[derive(Debug, Clone, Serialize, Deserialize)]
13457pub struct GovernanceSchemaConfig {
13458 #[serde(default = "default_true")]
13460 pub enabled: bool,
13461 #[serde(default = "default_board_size")]
13463 pub board_size: u32,
13464 #[serde(default = "default_independence_target")]
13466 pub independence_target: f64,
13467}
13468
13469fn default_board_size() -> u32 {
13470 11
13471}
13472
13473fn default_independence_target() -> f64 {
13474 0.67
13475}
13476
13477impl Default for GovernanceSchemaConfig {
13478 fn default() -> Self {
13479 Self {
13480 enabled: true,
13481 board_size: default_board_size(),
13482 independence_target: default_independence_target(),
13483 }
13484 }
13485}
13486
13487#[derive(Debug, Clone, Serialize, Deserialize)]
13489pub struct SupplyChainEsgConfig {
13490 #[serde(default = "default_true")]
13492 pub enabled: bool,
13493 #[serde(default = "default_assessment_coverage")]
13495 pub assessment_coverage: f64,
13496 #[serde(default = "default_high_risk_countries")]
13498 pub high_risk_countries: Vec<String>,
13499}
13500
13501fn default_assessment_coverage() -> f64 {
13502 0.80
13503}
13504
13505fn default_high_risk_countries() -> Vec<String> {
13506 vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
13507}
13508
13509impl Default for SupplyChainEsgConfig {
13510 fn default() -> Self {
13511 Self {
13512 enabled: true,
13513 assessment_coverage: default_assessment_coverage(),
13514 high_risk_countries: default_high_risk_countries(),
13515 }
13516 }
13517}
13518
13519#[derive(Debug, Clone, Serialize, Deserialize)]
13521pub struct EsgReportingConfig {
13522 #[serde(default = "default_true")]
13524 pub enabled: bool,
13525 #[serde(default = "default_esg_frameworks")]
13527 pub frameworks: Vec<String>,
13528 #[serde(default = "default_true")]
13530 pub materiality_assessment: bool,
13531 #[serde(default = "default_materiality_threshold")]
13533 pub impact_threshold: f64,
13534 #[serde(default = "default_materiality_threshold")]
13536 pub financial_threshold: f64,
13537}
13538
13539fn default_esg_frameworks() -> Vec<String> {
13540 vec!["GRI".to_string(), "ESRS".to_string()]
13541}
13542
13543fn default_materiality_threshold() -> f64 {
13544 0.6
13545}
13546
13547impl Default for EsgReportingConfig {
13548 fn default() -> Self {
13549 Self {
13550 enabled: true,
13551 frameworks: default_esg_frameworks(),
13552 materiality_assessment: true,
13553 impact_threshold: default_materiality_threshold(),
13554 financial_threshold: default_materiality_threshold(),
13555 }
13556 }
13557}
13558
13559#[derive(Debug, Clone, Serialize, Deserialize)]
13561pub struct ClimateScenarioConfig {
13562 #[serde(default)]
13564 pub enabled: bool,
13565 #[serde(default = "default_climate_scenarios")]
13567 pub scenarios: Vec<String>,
13568 #[serde(default = "default_time_horizons")]
13570 pub time_horizons: Vec<u32>,
13571}
13572
13573fn default_climate_scenarios() -> Vec<String> {
13574 vec![
13575 "net_zero_2050".to_string(),
13576 "stated_policies".to_string(),
13577 "current_trajectory".to_string(),
13578 ]
13579}
13580
13581fn default_time_horizons() -> Vec<u32> {
13582 vec![5, 10, 30]
13583}
13584
13585impl Default for ClimateScenarioConfig {
13586 fn default() -> Self {
13587 Self {
13588 enabled: false,
13589 scenarios: default_climate_scenarios(),
13590 time_horizons: default_time_horizons(),
13591 }
13592 }
13593}
13594
13595#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13599pub struct ScenariosConfig {
13600 #[serde(default)]
13602 pub enabled: bool,
13603 #[serde(default)]
13605 pub scenarios: Vec<ScenarioSchemaConfig>,
13606 #[serde(default)]
13608 pub causal_model: CausalModelSchemaConfig,
13609 #[serde(default)]
13611 pub defaults: ScenarioDefaultsConfig,
13612 #[serde(default)]
13615 pub generate_counterfactuals: bool,
13616}
13617
13618#[derive(Debug, Clone, Serialize, Deserialize)]
13620pub struct ScenarioSchemaConfig {
13621 pub name: String,
13623 #[serde(default)]
13625 pub description: String,
13626 #[serde(default)]
13628 pub tags: Vec<String>,
13629 pub base: Option<String>,
13631 pub probability_weight: Option<f64>,
13633 #[serde(default)]
13635 pub interventions: Vec<InterventionSchemaConfig>,
13636 #[serde(default)]
13638 pub constraints: ScenarioConstraintsSchemaConfig,
13639 #[serde(default)]
13641 pub output: ScenarioOutputSchemaConfig,
13642 #[serde(default)]
13644 pub metadata: std::collections::HashMap<String, String>,
13645}
13646
13647#[derive(Debug, Clone, Serialize, Deserialize)]
13649pub struct InterventionSchemaConfig {
13650 #[serde(flatten)]
13652 pub intervention_type: serde_json::Value,
13653 #[serde(default)]
13655 pub timing: InterventionTimingSchemaConfig,
13656 pub label: Option<String>,
13658 #[serde(default)]
13660 pub priority: u32,
13661}
13662
13663#[derive(Debug, Clone, Serialize, Deserialize)]
13665pub struct InterventionTimingSchemaConfig {
13666 #[serde(default = "default_start_month")]
13668 pub start_month: u32,
13669 pub duration_months: Option<u32>,
13671 #[serde(default = "default_onset")]
13673 pub onset: String,
13674 pub ramp_months: Option<u32>,
13676}
13677
13678fn default_start_month() -> u32 {
13679 1
13680}
13681
13682fn default_onset() -> String {
13683 "sudden".to_string()
13684}
13685
13686impl Default for InterventionTimingSchemaConfig {
13687 fn default() -> Self {
13688 Self {
13689 start_month: 1,
13690 duration_months: None,
13691 onset: "sudden".to_string(),
13692 ramp_months: None,
13693 }
13694 }
13695}
13696
13697#[derive(Debug, Clone, Serialize, Deserialize)]
13699pub struct ScenarioConstraintsSchemaConfig {
13700 #[serde(default = "default_true")]
13701 pub preserve_accounting_identity: bool,
13702 #[serde(default = "default_true")]
13703 pub preserve_document_chains: bool,
13704 #[serde(default = "default_true")]
13705 pub preserve_period_close: bool,
13706 #[serde(default = "default_true")]
13707 pub preserve_balance_coherence: bool,
13708 #[serde(default)]
13709 pub custom: Vec<CustomConstraintSchemaConfig>,
13710}
13711
13712impl Default for ScenarioConstraintsSchemaConfig {
13713 fn default() -> Self {
13714 Self {
13715 preserve_accounting_identity: true,
13716 preserve_document_chains: true,
13717 preserve_period_close: true,
13718 preserve_balance_coherence: true,
13719 custom: Vec::new(),
13720 }
13721 }
13722}
13723
13724#[derive(Debug, Clone, Serialize, Deserialize)]
13726pub struct CustomConstraintSchemaConfig {
13727 pub config_path: String,
13728 pub min: Option<f64>,
13729 pub max: Option<f64>,
13730 #[serde(default)]
13731 pub description: String,
13732}
13733
13734#[derive(Debug, Clone, Serialize, Deserialize)]
13736pub struct ScenarioOutputSchemaConfig {
13737 #[serde(default = "default_true")]
13738 pub paired: bool,
13739 #[serde(default = "default_diff_formats_schema")]
13740 pub diff_formats: Vec<String>,
13741 #[serde(default)]
13742 pub diff_scope: Vec<String>,
13743}
13744
13745fn default_diff_formats_schema() -> Vec<String> {
13746 vec!["summary".to_string(), "aggregate".to_string()]
13747}
13748
13749impl Default for ScenarioOutputSchemaConfig {
13750 fn default() -> Self {
13751 Self {
13752 paired: true,
13753 diff_formats: default_diff_formats_schema(),
13754 diff_scope: Vec::new(),
13755 }
13756 }
13757}
13758
13759#[derive(Debug, Clone, Serialize, Deserialize)]
13761pub struct CausalModelSchemaConfig {
13762 #[serde(default = "default_causal_preset")]
13764 pub preset: String,
13765 #[serde(default)]
13767 pub nodes: Vec<serde_json::Value>,
13768 #[serde(default)]
13770 pub edges: Vec<serde_json::Value>,
13771}
13772
13773fn default_causal_preset() -> String {
13774 "default".to_string()
13775}
13776
13777impl Default for CausalModelSchemaConfig {
13778 fn default() -> Self {
13779 Self {
13780 preset: "default".to_string(),
13781 nodes: Vec::new(),
13782 edges: Vec::new(),
13783 }
13784 }
13785}
13786
13787#[derive(Debug, Clone, Serialize, Deserialize, Default)]
13789pub struct ScenarioDefaultsConfig {
13790 #[serde(default)]
13791 pub constraints: ScenarioConstraintsSchemaConfig,
13792 #[serde(default)]
13793 pub output: ScenarioOutputSchemaConfig,
13794}
13795
13796#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13829pub struct ComplianceRegulationsConfig {
13830 #[serde(default)]
13832 pub enabled: bool,
13833 #[serde(default)]
13836 pub jurisdictions: Vec<String>,
13837 #[serde(default)]
13840 pub reference_date: Option<String>,
13841 #[serde(default)]
13843 pub standards_selection: StandardsSelectionConfig,
13844 #[serde(default)]
13846 pub audit_procedures: AuditProcedureGenConfig,
13847 #[serde(default)]
13849 pub findings: ComplianceFindingGenConfig,
13850 #[serde(default)]
13852 pub filings: ComplianceFilingGenConfig,
13853 #[serde(default)]
13855 pub graph: ComplianceGraphConfig,
13856 #[serde(default)]
13858 pub output: ComplianceOutputConfig,
13859 #[serde(default)]
13864 pub legal_documents: LegalDocumentsConfig,
13865}
13866
13867#[derive(Debug, Clone, Serialize, Deserialize)]
13872pub struct LegalDocumentsConfig {
13873 #[serde(default)]
13875 pub enabled: bool,
13876 #[serde(default = "default_legal_opinion_probability")]
13878 pub legal_opinion_probability: f64,
13879}
13880
13881fn default_legal_opinion_probability() -> f64 {
13882 0.40
13883}
13884
13885impl Default for LegalDocumentsConfig {
13886 fn default() -> Self {
13887 Self {
13888 enabled: false,
13889 legal_opinion_probability: default_legal_opinion_probability(),
13890 }
13891 }
13892}
13893
13894#[derive(Debug, Clone, Default, Serialize, Deserialize)]
13896pub struct StandardsSelectionConfig {
13897 #[serde(default)]
13900 pub categories: Vec<String>,
13901 #[serde(default)]
13904 pub include: Vec<String>,
13905 #[serde(default)]
13907 pub exclude: Vec<String>,
13908 #[serde(default)]
13910 pub include_superseded: bool,
13911}
13912
13913#[derive(Debug, Clone, Serialize, Deserialize)]
13915pub struct AuditProcedureGenConfig {
13916 #[serde(default)]
13918 pub enabled: bool,
13919 #[serde(default = "default_procedures_per_standard")]
13921 pub procedures_per_standard: usize,
13922 #[serde(default = "default_sampling_method")]
13924 pub sampling_method: String,
13925 #[serde(default = "default_confidence_level")]
13927 pub confidence_level: f64,
13928 #[serde(default = "default_tolerable_misstatement")]
13930 pub tolerable_misstatement: f64,
13931}
13932
13933fn default_procedures_per_standard() -> usize {
13934 3
13935}
13936
13937fn default_sampling_method() -> String {
13938 "statistical".to_string()
13939}
13940
13941fn default_confidence_level() -> f64 {
13942 0.95
13943}
13944
13945fn default_tolerable_misstatement() -> f64 {
13946 0.05
13947}
13948
13949impl Default for AuditProcedureGenConfig {
13950 fn default() -> Self {
13951 Self {
13952 enabled: false,
13953 procedures_per_standard: default_procedures_per_standard(),
13954 sampling_method: default_sampling_method(),
13955 confidence_level: default_confidence_level(),
13956 tolerable_misstatement: default_tolerable_misstatement(),
13957 }
13958 }
13959}
13960
13961#[derive(Debug, Clone, Serialize, Deserialize)]
13963pub struct ComplianceFindingGenConfig {
13964 #[serde(default)]
13966 pub enabled: bool,
13967 #[serde(default = "default_finding_rate")]
13969 pub finding_rate: f64,
13970 #[serde(default = "default_cr_material_weakness_rate")]
13972 pub material_weakness_rate: f64,
13973 #[serde(default = "default_cr_significant_deficiency_rate")]
13975 pub significant_deficiency_rate: f64,
13976 #[serde(default = "default_true")]
13978 pub generate_remediation: bool,
13979}
13980
13981fn default_finding_rate() -> f64 {
13982 0.05
13983}
13984
13985fn default_cr_material_weakness_rate() -> f64 {
13986 0.02
13987}
13988
13989fn default_cr_significant_deficiency_rate() -> f64 {
13990 0.08
13991}
13992
13993impl Default for ComplianceFindingGenConfig {
13994 fn default() -> Self {
13995 Self {
13996 enabled: false,
13997 finding_rate: default_finding_rate(),
13998 material_weakness_rate: default_cr_material_weakness_rate(),
13999 significant_deficiency_rate: default_cr_significant_deficiency_rate(),
14000 generate_remediation: true,
14001 }
14002 }
14003}
14004
14005#[derive(Debug, Clone, Serialize, Deserialize)]
14007pub struct ComplianceFilingGenConfig {
14008 #[serde(default)]
14010 pub enabled: bool,
14011 #[serde(default)]
14014 pub filing_types: Vec<String>,
14015 #[serde(default = "default_true")]
14017 pub generate_status_progression: bool,
14018}
14019
14020impl Default for ComplianceFilingGenConfig {
14021 fn default() -> Self {
14022 Self {
14023 enabled: false,
14024 filing_types: Vec::new(),
14025 generate_status_progression: true,
14026 }
14027 }
14028}
14029
14030#[derive(Debug, Clone, Serialize, Deserialize)]
14032pub struct ComplianceGraphConfig {
14033 #[serde(default)]
14035 pub enabled: bool,
14036 #[serde(default = "default_true")]
14038 pub include_compliance_nodes: bool,
14039 #[serde(default = "default_true")]
14041 pub include_compliance_edges: bool,
14042 #[serde(default = "default_true")]
14044 pub include_cross_references: bool,
14045 #[serde(default)]
14047 pub include_supersession_edges: bool,
14048 #[serde(default = "default_true")]
14050 pub include_account_links: bool,
14051 #[serde(default = "default_true")]
14053 pub include_control_links: bool,
14054 #[serde(default = "default_true")]
14056 pub include_company_links: bool,
14057}
14058
14059impl Default for ComplianceGraphConfig {
14060 fn default() -> Self {
14061 Self {
14062 enabled: false,
14063 include_compliance_nodes: true,
14064 include_compliance_edges: true,
14065 include_cross_references: true,
14066 include_supersession_edges: false,
14067 include_account_links: true,
14068 include_control_links: true,
14069 include_company_links: true,
14070 }
14071 }
14072}
14073
14074#[derive(Debug, Clone, Serialize, Deserialize)]
14076pub struct ComplianceOutputConfig {
14077 #[serde(default = "default_true")]
14079 pub export_registry: bool,
14080 #[serde(default = "default_true")]
14082 pub export_jurisdictions: bool,
14083 #[serde(default = "default_true")]
14085 pub export_cross_references: bool,
14086 #[serde(default)]
14088 pub export_version_history: bool,
14089}
14090
14091impl Default for ComplianceOutputConfig {
14092 fn default() -> Self {
14093 Self {
14094 export_registry: true,
14095 export_jurisdictions: true,
14096 export_cross_references: true,
14097 export_version_history: false,
14098 }
14099 }
14100}
14101
14102#[cfg(test)]
14103#[allow(clippy::unwrap_used)]
14104mod tests {
14105 use super::*;
14106 use crate::presets::demo_preset;
14107
14108 #[test]
14113 fn test_config_yaml_roundtrip() {
14114 let config = demo_preset();
14115 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
14116 let deserialized: GeneratorConfig =
14117 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
14118
14119 assert_eq!(
14120 config.global.period_months,
14121 deserialized.global.period_months
14122 );
14123 assert_eq!(config.global.industry, deserialized.global.industry);
14124 assert_eq!(config.companies.len(), deserialized.companies.len());
14125 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
14126 }
14127
14128 #[test]
14129 fn test_config_json_roundtrip() {
14130 let mut config = demo_preset();
14132 config.master_data.employees.approval_limits.executive = 1e12;
14134
14135 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
14136 let deserialized: GeneratorConfig =
14137 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
14138
14139 assert_eq!(
14140 config.global.period_months,
14141 deserialized.global.period_months
14142 );
14143 assert_eq!(config.global.industry, deserialized.global.industry);
14144 assert_eq!(config.companies.len(), deserialized.companies.len());
14145 }
14146
14147 #[test]
14148 fn test_transaction_volume_serialization() {
14149 let volumes = vec![
14151 (TransactionVolume::TenK, "ten_k"),
14152 (TransactionVolume::HundredK, "hundred_k"),
14153 (TransactionVolume::OneM, "one_m"),
14154 (TransactionVolume::TenM, "ten_m"),
14155 (TransactionVolume::HundredM, "hundred_m"),
14156 ];
14157
14158 for (volume, expected_key) in volumes {
14159 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14160 assert!(
14161 json.contains(expected_key),
14162 "Expected {} in JSON: {}",
14163 expected_key,
14164 json
14165 );
14166 }
14167 }
14168
14169 #[test]
14170 fn test_transaction_volume_custom_serialization() {
14171 let volume = TransactionVolume::Custom(12345);
14172 let json = serde_json::to_string(&volume).expect("Failed to serialize");
14173 let deserialized: TransactionVolume =
14174 serde_json::from_str(&json).expect("Failed to deserialize");
14175 assert_eq!(deserialized.count(), 12345);
14176 }
14177
14178 #[test]
14179 fn test_output_mode_serialization() {
14180 let modes = vec![
14181 OutputMode::Streaming,
14182 OutputMode::FlatFile,
14183 OutputMode::Both,
14184 ];
14185
14186 for mode in modes {
14187 let json = serde_json::to_string(&mode).expect("Failed to serialize");
14188 let deserialized: OutputMode =
14189 serde_json::from_str(&json).expect("Failed to deserialize");
14190 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
14191 }
14192 }
14193
14194 #[test]
14195 fn test_file_format_serialization() {
14196 let formats = vec![
14197 FileFormat::Csv,
14198 FileFormat::Parquet,
14199 FileFormat::Json,
14200 FileFormat::JsonLines,
14201 ];
14202
14203 for format in formats {
14204 let json = serde_json::to_string(&format).expect("Failed to serialize");
14205 let deserialized: FileFormat =
14206 serde_json::from_str(&json).expect("Failed to deserialize");
14207 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
14208 }
14209 }
14210
14211 #[test]
14212 fn test_compression_algorithm_serialization() {
14213 let algos = vec![
14214 CompressionAlgorithm::Gzip,
14215 CompressionAlgorithm::Zstd,
14216 CompressionAlgorithm::Lz4,
14217 CompressionAlgorithm::Snappy,
14218 ];
14219
14220 for algo in algos {
14221 let json = serde_json::to_string(&algo).expect("Failed to serialize");
14222 let deserialized: CompressionAlgorithm =
14223 serde_json::from_str(&json).expect("Failed to deserialize");
14224 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
14225 }
14226 }
14227
14228 #[test]
14229 fn test_transfer_pricing_method_serialization() {
14230 let methods = vec![
14231 TransferPricingMethod::CostPlus,
14232 TransferPricingMethod::ComparableUncontrolled,
14233 TransferPricingMethod::ResalePrice,
14234 TransferPricingMethod::TransactionalNetMargin,
14235 TransferPricingMethod::ProfitSplit,
14236 ];
14237
14238 for method in methods {
14239 let json = serde_json::to_string(&method).expect("Failed to serialize");
14240 let deserialized: TransferPricingMethod =
14241 serde_json::from_str(&json).expect("Failed to deserialize");
14242 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
14243 }
14244 }
14245
14246 #[test]
14247 fn test_benford_exemption_serialization() {
14248 let exemptions = vec![
14249 BenfordExemption::Recurring,
14250 BenfordExemption::Payroll,
14251 BenfordExemption::FixedFees,
14252 BenfordExemption::RoundAmounts,
14253 ];
14254
14255 for exemption in exemptions {
14256 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
14257 let deserialized: BenfordExemption =
14258 serde_json::from_str(&json).expect("Failed to deserialize");
14259 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
14260 }
14261 }
14262
14263 #[test]
14268 fn test_global_config_defaults() {
14269 let yaml = r#"
14270 industry: manufacturing
14271 start_date: "2024-01-01"
14272 period_months: 6
14273 "#;
14274 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14275 assert_eq!(config.group_currency, "USD");
14276 assert!(config.parallel);
14277 assert_eq!(config.worker_threads, 0);
14278 assert_eq!(config.memory_limit_mb, 0);
14279 }
14280
14281 #[test]
14282 fn test_fraud_config_defaults() {
14283 let config = FraudConfig::default();
14284 assert!(!config.enabled);
14285 assert_eq!(config.fraud_rate, 0.005);
14286 assert!(!config.clustering_enabled);
14287 }
14288
14289 #[test]
14290 fn test_internal_controls_config_defaults() {
14291 let config = InternalControlsConfig::default();
14292 assert!(!config.enabled);
14293 assert_eq!(config.exception_rate, 0.02);
14294 assert_eq!(config.sod_violation_rate, 0.01);
14295 assert!(config.export_control_master_data);
14296 assert_eq!(config.sox_materiality_threshold, 10000.0);
14297 assert!(config.coso_enabled);
14299 assert!(!config.include_entity_level_controls);
14300 assert_eq!(config.target_maturity_level, "mixed");
14301 }
14302
14303 #[test]
14304 fn test_output_config_defaults() {
14305 let config = OutputConfig::default();
14306 assert!(matches!(config.mode, OutputMode::FlatFile));
14307 assert_eq!(config.formats, vec![FileFormat::Parquet]);
14308 assert!(config.compression.enabled);
14309 assert!(matches!(
14310 config.compression.algorithm,
14311 CompressionAlgorithm::Zstd
14312 ));
14313 assert!(config.include_acdoca);
14314 assert!(!config.include_bseg);
14315 assert!(config.partition_by_period);
14316 assert!(!config.partition_by_company);
14317 }
14318
14319 #[test]
14320 fn test_approval_config_defaults() {
14321 let config = ApprovalConfig::default();
14322 assert!(!config.enabled);
14323 assert_eq!(config.auto_approve_threshold, 1000.0);
14324 assert_eq!(config.rejection_rate, 0.02);
14325 assert_eq!(config.revision_rate, 0.05);
14326 assert_eq!(config.average_approval_delay_hours, 4.0);
14327 assert_eq!(config.thresholds.len(), 4);
14328 }
14329
14330 #[test]
14331 fn test_p2p_flow_config_defaults() {
14332 let config = P2PFlowConfig::default();
14333 assert!(config.enabled);
14334 assert_eq!(config.three_way_match_rate, 0.95);
14335 assert_eq!(config.partial_delivery_rate, 0.15);
14336 assert_eq!(config.average_po_to_gr_days, 14);
14337 }
14338
14339 #[test]
14340 fn test_o2c_flow_config_defaults() {
14341 let config = O2CFlowConfig::default();
14342 assert!(config.enabled);
14343 assert_eq!(config.credit_check_failure_rate, 0.02);
14344 assert_eq!(config.return_rate, 0.03);
14345 assert_eq!(config.bad_debt_rate, 0.01);
14346 }
14347
14348 #[test]
14349 fn test_balance_config_defaults() {
14350 let config = BalanceConfig::default();
14351 assert!(!config.generate_opening_balances);
14352 assert!(config.generate_trial_balances);
14353 assert_eq!(config.target_gross_margin, 0.35);
14354 assert!(config.validate_balance_equation);
14355 assert!(config.reconcile_subledgers);
14356 }
14357
14358 #[test]
14363 fn test_partial_config_with_defaults() {
14364 let yaml = r#"
14366 global:
14367 industry: manufacturing
14368 start_date: "2024-01-01"
14369 period_months: 3
14370 companies:
14371 - code: "TEST"
14372 name: "Test Company"
14373 currency: "USD"
14374 country: "US"
14375 annual_transaction_volume: ten_k
14376 chart_of_accounts:
14377 complexity: small
14378 output:
14379 output_directory: "./output"
14380 "#;
14381
14382 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14383 assert_eq!(config.global.period_months, 3);
14384 assert_eq!(config.companies.len(), 1);
14385 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
14388
14389 #[test]
14390 fn test_config_with_fraud_enabled() {
14391 let yaml = r#"
14392 global:
14393 industry: retail
14394 start_date: "2024-01-01"
14395 period_months: 12
14396 companies:
14397 - code: "RETAIL"
14398 name: "Retail Co"
14399 currency: "USD"
14400 country: "US"
14401 annual_transaction_volume: hundred_k
14402 chart_of_accounts:
14403 complexity: medium
14404 output:
14405 output_directory: "./output"
14406 fraud:
14407 enabled: true
14408 fraud_rate: 0.05
14409 clustering_enabled: true
14410 "#;
14411
14412 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14413 assert!(config.fraud.enabled);
14414 assert_eq!(config.fraud.fraud_rate, 0.05);
14415 assert!(config.fraud.clustering_enabled);
14416 }
14417
14418 #[test]
14419 fn test_config_with_multiple_companies() {
14420 let yaml = r#"
14421 global:
14422 industry: manufacturing
14423 start_date: "2024-01-01"
14424 period_months: 6
14425 companies:
14426 - code: "HQ"
14427 name: "Headquarters"
14428 currency: "USD"
14429 country: "US"
14430 annual_transaction_volume: hundred_k
14431 volume_weight: 1.0
14432 - code: "EU"
14433 name: "European Subsidiary"
14434 currency: "EUR"
14435 country: "DE"
14436 annual_transaction_volume: hundred_k
14437 volume_weight: 0.5
14438 - code: "APAC"
14439 name: "Asia Pacific"
14440 currency: "JPY"
14441 country: "JP"
14442 annual_transaction_volume: ten_k
14443 volume_weight: 0.3
14444 chart_of_accounts:
14445 complexity: large
14446 output:
14447 output_directory: "./output"
14448 "#;
14449
14450 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14451 assert_eq!(config.companies.len(), 3);
14452 assert_eq!(config.companies[0].code, "HQ");
14453 assert_eq!(config.companies[1].currency, "EUR");
14454 assert_eq!(config.companies[2].volume_weight, 0.3);
14455 }
14456
14457 #[test]
14458 fn test_intercompany_config() {
14459 let yaml = r#"
14460 enabled: true
14461 ic_transaction_rate: 0.20
14462 transfer_pricing_method: cost_plus
14463 markup_percent: 0.08
14464 generate_matched_pairs: true
14465 generate_eliminations: true
14466 "#;
14467
14468 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14469 assert!(config.enabled);
14470 assert_eq!(config.ic_transaction_rate, 0.20);
14471 assert!(matches!(
14472 config.transfer_pricing_method,
14473 TransferPricingMethod::CostPlus
14474 ));
14475 assert_eq!(config.markup_percent, 0.08);
14476 assert!(config.generate_eliminations);
14477 }
14478
14479 #[test]
14484 fn test_company_config_defaults() {
14485 let yaml = r#"
14486 code: "TEST"
14487 name: "Test Company"
14488 currency: "USD"
14489 country: "US"
14490 annual_transaction_volume: ten_k
14491 "#;
14492
14493 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14494 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
14497
14498 #[test]
14503 fn test_coa_config_defaults() {
14504 let yaml = r#"
14505 complexity: medium
14506 "#;
14507
14508 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14509 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
14511 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
14514
14515 #[test]
14520 fn test_accounting_standards_config_defaults() {
14521 let config = AccountingStandardsConfig::default();
14522 assert!(!config.enabled);
14523 assert!(config.framework.is_none());
14524 assert!(!config.revenue_recognition.enabled);
14525 assert!(!config.leases.enabled);
14526 assert!(!config.fair_value.enabled);
14527 assert!(!config.impairment.enabled);
14528 assert!(!config.generate_differences);
14529 }
14530
14531 #[test]
14532 fn test_accounting_standards_config_yaml() {
14533 let yaml = r#"
14534 enabled: true
14535 framework: ifrs
14536 revenue_recognition:
14537 enabled: true
14538 generate_contracts: true
14539 avg_obligations_per_contract: 2.5
14540 variable_consideration_rate: 0.20
14541 over_time_recognition_rate: 0.35
14542 contract_count: 150
14543 leases:
14544 enabled: true
14545 lease_count: 75
14546 finance_lease_percent: 0.25
14547 avg_lease_term_months: 48
14548 generate_differences: true
14549 "#;
14550
14551 let config: AccountingStandardsConfig =
14552 serde_yaml::from_str(yaml).expect("Failed to parse");
14553 assert!(config.enabled);
14554 assert!(matches!(
14555 config.framework,
14556 Some(AccountingFrameworkConfig::Ifrs)
14557 ));
14558 assert!(config.revenue_recognition.enabled);
14559 assert_eq!(config.revenue_recognition.contract_count, 150);
14560 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
14561 assert!(config.leases.enabled);
14562 assert_eq!(config.leases.lease_count, 75);
14563 assert_eq!(config.leases.finance_lease_percent, 0.25);
14564 assert!(config.generate_differences);
14565 }
14566
14567 #[test]
14568 fn test_accounting_framework_serialization() {
14569 let frameworks = [
14570 AccountingFrameworkConfig::UsGaap,
14571 AccountingFrameworkConfig::Ifrs,
14572 AccountingFrameworkConfig::DualReporting,
14573 AccountingFrameworkConfig::FrenchGaap,
14574 AccountingFrameworkConfig::GermanGaap,
14575 ];
14576
14577 for framework in frameworks {
14578 let json = serde_json::to_string(&framework).expect("Failed to serialize");
14579 let deserialized: AccountingFrameworkConfig =
14580 serde_json::from_str(&json).expect("Failed to deserialize");
14581 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
14582 }
14583 }
14584
14585 #[test]
14586 fn test_revenue_recognition_config_defaults() {
14587 let config = RevenueRecognitionConfig::default();
14588 assert!(!config.enabled);
14589 assert!(config.generate_contracts);
14590 assert_eq!(config.avg_obligations_per_contract, 2.0);
14591 assert_eq!(config.variable_consideration_rate, 0.15);
14592 assert_eq!(config.over_time_recognition_rate, 0.30);
14593 assert_eq!(config.contract_count, 100);
14594 }
14595
14596 #[test]
14597 fn test_lease_accounting_config_defaults() {
14598 let config = LeaseAccountingConfig::default();
14599 assert!(!config.enabled);
14600 assert_eq!(config.lease_count, 50);
14601 assert_eq!(config.finance_lease_percent, 0.30);
14602 assert_eq!(config.avg_lease_term_months, 60);
14603 assert!(config.generate_amortization);
14604 assert_eq!(config.real_estate_percent, 0.40);
14605 }
14606
14607 #[test]
14608 fn test_fair_value_config_defaults() {
14609 let config = FairValueConfig::default();
14610 assert!(!config.enabled);
14611 assert_eq!(config.measurement_count, 25);
14612 assert_eq!(config.level1_percent, 0.40);
14613 assert_eq!(config.level2_percent, 0.35);
14614 assert_eq!(config.level3_percent, 0.25);
14615 assert!(!config.include_sensitivity_analysis);
14616 }
14617
14618 #[test]
14619 fn test_impairment_config_defaults() {
14620 let config = ImpairmentConfig::default();
14621 assert!(!config.enabled);
14622 assert_eq!(config.test_count, 15);
14623 assert_eq!(config.impairment_rate, 0.10);
14624 assert!(config.generate_projections);
14625 assert!(!config.include_goodwill);
14626 }
14627
14628 #[test]
14633 fn test_audit_standards_config_defaults() {
14634 let config = AuditStandardsConfig::default();
14635 assert!(!config.enabled);
14636 assert!(!config.isa_compliance.enabled);
14637 assert!(!config.analytical_procedures.enabled);
14638 assert!(!config.confirmations.enabled);
14639 assert!(!config.opinion.enabled);
14640 assert!(!config.generate_audit_trail);
14641 assert!(!config.sox.enabled);
14642 assert!(!config.pcaob.enabled);
14643 }
14644
14645 #[test]
14646 fn test_audit_standards_config_yaml() {
14647 let yaml = r#"
14648 enabled: true
14649 isa_compliance:
14650 enabled: true
14651 compliance_level: comprehensive
14652 generate_isa_mappings: true
14653 include_pcaob: true
14654 framework: dual
14655 analytical_procedures:
14656 enabled: true
14657 procedures_per_account: 5
14658 variance_probability: 0.25
14659 confirmations:
14660 enabled: true
14661 confirmation_count: 75
14662 positive_response_rate: 0.90
14663 exception_rate: 0.08
14664 opinion:
14665 enabled: true
14666 generate_kam: true
14667 average_kam_count: 4
14668 sox:
14669 enabled: true
14670 generate_302_certifications: true
14671 generate_404_assessments: true
14672 material_weakness_rate: 0.03
14673 pcaob:
14674 enabled: true
14675 is_pcaob_audit: true
14676 include_icfr_opinion: true
14677 generate_audit_trail: true
14678 "#;
14679
14680 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14681 assert!(config.enabled);
14682 assert!(config.isa_compliance.enabled);
14683 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
14684 assert!(config.isa_compliance.include_pcaob);
14685 assert_eq!(config.isa_compliance.framework, "dual");
14686 assert!(config.analytical_procedures.enabled);
14687 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
14688 assert!(config.confirmations.enabled);
14689 assert_eq!(config.confirmations.confirmation_count, 75);
14690 assert!(config.opinion.enabled);
14691 assert_eq!(config.opinion.average_kam_count, 4);
14692 assert!(config.sox.enabled);
14693 assert!(config.sox.generate_302_certifications);
14694 assert_eq!(config.sox.material_weakness_rate, 0.03);
14695 assert!(config.pcaob.enabled);
14696 assert!(config.pcaob.is_pcaob_audit);
14697 assert!(config.pcaob.include_icfr_opinion);
14698 assert!(config.generate_audit_trail);
14699 }
14700
14701 #[test]
14702 fn test_isa_compliance_config_defaults() {
14703 let config = IsaComplianceConfig::default();
14704 assert!(!config.enabled);
14705 assert_eq!(config.compliance_level, "standard");
14706 assert!(config.generate_isa_mappings);
14707 assert!(config.generate_coverage_summary);
14708 assert!(!config.include_pcaob);
14709 assert_eq!(config.framework, "isa");
14710 }
14711
14712 #[test]
14713 fn test_sox_compliance_config_defaults() {
14714 let config = SoxComplianceConfig::default();
14715 assert!(!config.enabled);
14716 assert!(config.generate_302_certifications);
14717 assert!(config.generate_404_assessments);
14718 assert_eq!(config.materiality_threshold, 10000.0);
14719 assert_eq!(config.material_weakness_rate, 0.02);
14720 assert_eq!(config.significant_deficiency_rate, 0.08);
14721 }
14722
14723 #[test]
14724 fn test_pcaob_config_defaults() {
14725 let config = PcaobConfig::default();
14726 assert!(!config.enabled);
14727 assert!(!config.is_pcaob_audit);
14728 assert!(config.generate_cam);
14729 assert!(!config.include_icfr_opinion);
14730 assert!(!config.generate_standard_mappings);
14731 }
14732
14733 #[test]
14734 fn test_config_with_standards_enabled() {
14735 let yaml = r#"
14736 global:
14737 industry: financial_services
14738 start_date: "2024-01-01"
14739 period_months: 12
14740 companies:
14741 - code: "BANK"
14742 name: "Test Bank"
14743 currency: "USD"
14744 country: "US"
14745 annual_transaction_volume: hundred_k
14746 chart_of_accounts:
14747 complexity: large
14748 output:
14749 output_directory: "./output"
14750 accounting_standards:
14751 enabled: true
14752 framework: us_gaap
14753 revenue_recognition:
14754 enabled: true
14755 leases:
14756 enabled: true
14757 audit_standards:
14758 enabled: true
14759 isa_compliance:
14760 enabled: true
14761 sox:
14762 enabled: true
14763 "#;
14764
14765 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14766 assert!(config.accounting_standards.enabled);
14767 assert!(matches!(
14768 config.accounting_standards.framework,
14769 Some(AccountingFrameworkConfig::UsGaap)
14770 ));
14771 assert!(config.accounting_standards.revenue_recognition.enabled);
14772 assert!(config.accounting_standards.leases.enabled);
14773 assert!(config.audit_standards.enabled);
14774 assert!(config.audit_standards.isa_compliance.enabled);
14775 assert!(config.audit_standards.sox.enabled);
14776 }
14777
14778 #[test]
14783 fn test_industry_specific_config_defaults() {
14784 let config = IndustrySpecificConfig::default();
14785 assert!(!config.enabled);
14786 assert!(!config.manufacturing.enabled);
14787 assert!(!config.retail.enabled);
14788 assert!(!config.healthcare.enabled);
14789 assert!(!config.technology.enabled);
14790 assert!(!config.financial_services.enabled);
14791 assert!(!config.professional_services.enabled);
14792 }
14793
14794 #[test]
14795 fn test_manufacturing_config_defaults() {
14796 let config = ManufacturingConfig::default();
14797 assert!(!config.enabled);
14798 assert_eq!(config.bom_depth, 4);
14799 assert!(!config.just_in_time);
14800 assert_eq!(config.supplier_tiers, 2);
14801 assert_eq!(config.target_yield_rate, 0.97);
14802 assert_eq!(config.scrap_alert_threshold, 0.03);
14803 }
14804
14805 #[test]
14806 fn test_retail_config_defaults() {
14807 let config = RetailConfig::default();
14808 assert!(!config.enabled);
14809 assert_eq!(config.avg_daily_transactions, 500);
14810 assert!(config.loss_prevention);
14811 assert_eq!(config.shrinkage_rate, 0.015);
14812 }
14813
14814 #[test]
14815 fn test_healthcare_config_defaults() {
14816 let config = HealthcareConfig::default();
14817 assert!(!config.enabled);
14818 assert_eq!(config.facility_type, "hospital");
14819 assert_eq!(config.avg_daily_encounters, 150);
14820 assert!(config.compliance.hipaa);
14821 assert!(config.compliance.stark_law);
14822 assert!(config.coding_systems.icd10);
14823 assert!(config.coding_systems.cpt);
14824 }
14825
14826 #[test]
14827 fn test_technology_config_defaults() {
14828 let config = TechnologyConfig::default();
14829 assert!(!config.enabled);
14830 assert_eq!(config.revenue_model, "saas");
14831 assert_eq!(config.subscription_revenue_pct, 0.60);
14832 assert!(config.rd_capitalization.enabled);
14833 }
14834
14835 #[test]
14836 fn test_config_with_industry_specific() {
14837 let yaml = r#"
14838 global:
14839 industry: healthcare
14840 start_date: "2024-01-01"
14841 period_months: 12
14842 companies:
14843 - code: "HOSP"
14844 name: "Test Hospital"
14845 currency: "USD"
14846 country: "US"
14847 annual_transaction_volume: hundred_k
14848 chart_of_accounts:
14849 complexity: medium
14850 output:
14851 output_directory: "./output"
14852 industry_specific:
14853 enabled: true
14854 healthcare:
14855 enabled: true
14856 facility_type: hospital
14857 payer_mix:
14858 medicare: 0.45
14859 medicaid: 0.15
14860 commercial: 0.35
14861 self_pay: 0.05
14862 coding_systems:
14863 icd10: true
14864 cpt: true
14865 drg: true
14866 compliance:
14867 hipaa: true
14868 stark_law: true
14869 anomaly_rates:
14870 upcoding: 0.03
14871 unbundling: 0.02
14872 "#;
14873
14874 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14875 assert!(config.industry_specific.enabled);
14876 assert!(config.industry_specific.healthcare.enabled);
14877 assert_eq!(
14878 config.industry_specific.healthcare.facility_type,
14879 "hospital"
14880 );
14881 assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
14882 assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
14883 assert!(config.industry_specific.healthcare.coding_systems.icd10);
14884 assert!(config.industry_specific.healthcare.compliance.hipaa);
14885 assert_eq!(
14886 config.industry_specific.healthcare.anomaly_rates.upcoding,
14887 0.03
14888 );
14889 }
14890
14891 #[test]
14892 fn test_config_with_manufacturing_specific() {
14893 let yaml = r#"
14894 global:
14895 industry: manufacturing
14896 start_date: "2024-01-01"
14897 period_months: 12
14898 companies:
14899 - code: "MFG"
14900 name: "Test Manufacturing"
14901 currency: "USD"
14902 country: "US"
14903 annual_transaction_volume: hundred_k
14904 chart_of_accounts:
14905 complexity: medium
14906 output:
14907 output_directory: "./output"
14908 industry_specific:
14909 enabled: true
14910 manufacturing:
14911 enabled: true
14912 bom_depth: 5
14913 just_in_time: true
14914 supplier_tiers: 3
14915 target_yield_rate: 0.98
14916 anomaly_rates:
14917 yield_manipulation: 0.02
14918 phantom_production: 0.01
14919 "#;
14920
14921 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
14922 assert!(config.industry_specific.enabled);
14923 assert!(config.industry_specific.manufacturing.enabled);
14924 assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
14925 assert!(config.industry_specific.manufacturing.just_in_time);
14926 assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
14927 assert_eq!(
14928 config.industry_specific.manufacturing.target_yield_rate,
14929 0.98
14930 );
14931 assert_eq!(
14932 config
14933 .industry_specific
14934 .manufacturing
14935 .anomaly_rates
14936 .yield_manipulation,
14937 0.02
14938 );
14939 }
14940
14941 #[test]
14946 fn test_tax_config_defaults() {
14947 let tax = TaxConfig::default();
14948 assert!(!tax.enabled);
14949 assert!(tax.jurisdictions.countries.is_empty());
14950 assert!(!tax.jurisdictions.include_subnational);
14951 assert!(!tax.vat_gst.enabled);
14952 assert!(tax.vat_gst.standard_rates.is_empty());
14953 assert!(tax.vat_gst.reduced_rates.is_empty());
14954 assert!(tax.vat_gst.exempt_categories.is_empty());
14955 assert!(tax.vat_gst.reverse_charge);
14956 assert!(!tax.sales_tax.enabled);
14957 assert!(tax.sales_tax.nexus_states.is_empty());
14958 assert!(!tax.withholding.enabled);
14959 assert!(tax.withholding.treaty_network);
14960 assert_eq!(tax.withholding.default_rate, 0.30);
14961 assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
14962 assert!(tax.provisions.enabled);
14963 assert_eq!(tax.provisions.statutory_rate, 0.21);
14964 assert!(tax.provisions.uncertain_positions);
14965 assert!(!tax.payroll_tax.enabled);
14966 assert_eq!(tax.anomaly_rate, 0.03);
14967 }
14968
14969 #[test]
14970 fn test_tax_config_from_yaml() {
14971 let yaml = r#"
14972 global:
14973 seed: 42
14974 start_date: "2024-01-01"
14975 period_months: 12
14976 industry: retail
14977 companies:
14978 - code: C001
14979 name: Test Corp
14980 currency: USD
14981 country: US
14982 annual_transaction_volume: ten_k
14983 chart_of_accounts:
14984 complexity: small
14985 output:
14986 output_directory: ./output
14987 tax:
14988 enabled: true
14989 anomaly_rate: 0.05
14990 jurisdictions:
14991 countries: ["US", "DE", "GB"]
14992 include_subnational: true
14993 vat_gst:
14994 enabled: true
14995 standard_rates:
14996 DE: 0.19
14997 GB: 0.20
14998 reduced_rates:
14999 DE: 0.07
15000 GB: 0.05
15001 exempt_categories:
15002 - financial_services
15003 - healthcare
15004 reverse_charge: false
15005 sales_tax:
15006 enabled: true
15007 nexus_states: ["CA", "NY", "TX"]
15008 withholding:
15009 enabled: true
15010 treaty_network: false
15011 default_rate: 0.25
15012 treaty_reduced_rate: 0.10
15013 provisions:
15014 enabled: false
15015 statutory_rate: 0.28
15016 uncertain_positions: false
15017 payroll_tax:
15018 enabled: true
15019 "#;
15020
15021 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
15022 assert!(config.tax.enabled);
15023 assert_eq!(config.tax.anomaly_rate, 0.05);
15024
15025 assert_eq!(config.tax.jurisdictions.countries.len(), 3);
15027 assert!(config
15028 .tax
15029 .jurisdictions
15030 .countries
15031 .contains(&"DE".to_string()));
15032 assert!(config.tax.jurisdictions.include_subnational);
15033
15034 assert!(config.tax.vat_gst.enabled);
15036 assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
15037 assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
15038 assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
15039 assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
15040 assert!(!config.tax.vat_gst.reverse_charge);
15041
15042 assert!(config.tax.sales_tax.enabled);
15044 assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
15045 assert!(config
15046 .tax
15047 .sales_tax
15048 .nexus_states
15049 .contains(&"CA".to_string()));
15050
15051 assert!(config.tax.withholding.enabled);
15053 assert!(!config.tax.withholding.treaty_network);
15054 assert_eq!(config.tax.withholding.default_rate, 0.25);
15055 assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
15056
15057 assert!(!config.tax.provisions.enabled);
15059 assert_eq!(config.tax.provisions.statutory_rate, 0.28);
15060 assert!(!config.tax.provisions.uncertain_positions);
15061
15062 assert!(config.tax.payroll_tax.enabled);
15064 }
15065
15066 #[test]
15067 fn test_generator_config_with_tax_default() {
15068 let yaml = r#"
15069 global:
15070 seed: 42
15071 start_date: "2024-01-01"
15072 period_months: 12
15073 industry: retail
15074 companies:
15075 - code: C001
15076 name: Test Corp
15077 currency: USD
15078 country: US
15079 annual_transaction_volume: ten_k
15080 chart_of_accounts:
15081 complexity: small
15082 output:
15083 output_directory: ./output
15084 "#;
15085
15086 let config: GeneratorConfig =
15087 serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
15088 assert!(!config.tax.enabled);
15090 assert!(config.tax.jurisdictions.countries.is_empty());
15091 assert_eq!(config.tax.anomaly_rate, 0.03);
15092 assert!(config.tax.provisions.enabled); assert_eq!(config.tax.provisions.statutory_rate, 0.21);
15094 }
15095
15096 #[test]
15101 fn test_session_config_default_disabled() {
15102 let yaml = "{}";
15103 let config: SessionSchemaConfig =
15104 serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
15105 assert!(!config.enabled);
15106 assert!(config.checkpoint_path.is_none());
15107 assert!(config.per_period_output);
15108 assert!(config.consolidated_output);
15109 }
15110
15111 #[test]
15112 fn test_config_backward_compatible_without_session() {
15113 let yaml = r#"
15114 global:
15115 seed: 42
15116 start_date: "2024-01-01"
15117 period_months: 12
15118 industry: retail
15119 companies:
15120 - code: C001
15121 name: Test Corp
15122 currency: USD
15123 country: US
15124 annual_transaction_volume: ten_k
15125 chart_of_accounts:
15126 complexity: small
15127 output:
15128 output_directory: ./output
15129 "#;
15130
15131 let config: GeneratorConfig =
15132 serde_yaml::from_str(yaml).expect("Failed to parse config without session");
15133 assert!(!config.session.enabled);
15135 assert!(config.session.per_period_output);
15136 assert!(config.session.consolidated_output);
15137 assert!(config.global.fiscal_year_months.is_none());
15139 }
15140
15141 #[test]
15142 fn test_fiscal_year_months_parsed() {
15143 let yaml = r#"
15144 global:
15145 seed: 42
15146 start_date: "2024-01-01"
15147 period_months: 24
15148 industry: retail
15149 fiscal_year_months: 12
15150 companies:
15151 - code: C001
15152 name: Test Corp
15153 currency: USD
15154 country: US
15155 annual_transaction_volume: ten_k
15156 chart_of_accounts:
15157 complexity: small
15158 output:
15159 output_directory: ./output
15160 session:
15161 enabled: true
15162 checkpoint_path: /tmp/checkpoints
15163 per_period_output: true
15164 consolidated_output: false
15165 "#;
15166
15167 let config: GeneratorConfig =
15168 serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
15169 assert_eq!(config.global.fiscal_year_months, Some(12));
15170 assert!(config.session.enabled);
15171 assert_eq!(
15172 config.session.checkpoint_path,
15173 Some("/tmp/checkpoints".to_string())
15174 );
15175 assert!(config.session.per_period_output);
15176 assert!(!config.session.consolidated_output);
15177 }
15178}