Skip to main content

datasynth_config/
schema.rs

1//! Configuration schema for synthetic data generation.
2
3use 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/// Root configuration for the synthetic data generator.
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct GeneratorConfig {
14    /// Global settings
15    pub global: GlobalConfig,
16    /// Company configuration
17    pub companies: Vec<CompanyConfig>,
18    /// Chart of Accounts configuration
19    pub chart_of_accounts: ChartOfAccountsConfig,
20    /// Transaction generation settings
21    #[serde(default)]
22    pub transactions: TransactionConfig,
23    /// Output configuration
24    pub output: OutputConfig,
25    /// Fraud simulation settings
26    #[serde(default)]
27    pub fraud: FraudConfig,
28    /// Data quality variation settings
29    #[serde(default)]
30    pub data_quality: DataQualitySchemaConfig,
31    /// Internal Controls System settings
32    #[serde(default)]
33    pub internal_controls: InternalControlsConfig,
34    /// Business process mix
35    #[serde(default)]
36    pub business_processes: BusinessProcessConfig,
37    /// User persona distribution
38    #[serde(default)]
39    pub user_personas: UserPersonaConfig,
40    /// Template configuration for realistic data
41    #[serde(default)]
42    pub templates: TemplateConfig,
43    /// Approval workflow configuration
44    #[serde(default)]
45    pub approval: ApprovalConfig,
46    /// Department structure configuration
47    #[serde(default)]
48    pub departments: DepartmentConfig,
49    /// Master data generation settings
50    #[serde(default)]
51    pub master_data: MasterDataConfig,
52    /// Document flow generation settings
53    #[serde(default)]
54    pub document_flows: DocumentFlowConfig,
55    /// Intercompany transaction settings
56    #[serde(default)]
57    pub intercompany: IntercompanyConfig,
58    /// Balance and trial balance settings
59    #[serde(default)]
60    pub balance: BalanceConfig,
61    /// OCPM (Object-Centric Process Mining) settings
62    #[serde(default)]
63    pub ocpm: OcpmConfig,
64    /// Audit engagement and workpaper generation settings
65    #[serde(default)]
66    pub audit: AuditGenerationConfig,
67    /// Banking KYC/AML transaction generation settings
68    #[serde(default)]
69    pub banking: datasynth_banking::BankingConfig,
70    /// Scenario configuration for metadata and tagging (Phase 1.3)
71    #[serde(default)]
72    pub scenario: ScenarioConfig,
73    /// Temporal drift configuration for simulating distribution changes over time (Phase 2.2)
74    #[serde(default)]
75    pub temporal: TemporalDriftConfig,
76    /// Graph export configuration for accounting network export
77    #[serde(default)]
78    pub graph_export: GraphExportConfig,
79    /// Streaming output API configuration
80    #[serde(default)]
81    pub streaming: StreamingSchemaConfig,
82    /// Rate limiting configuration
83    #[serde(default)]
84    pub rate_limit: RateLimitSchemaConfig,
85    /// Temporal attribute generation configuration
86    #[serde(default)]
87    pub temporal_attributes: TemporalAttributeSchemaConfig,
88    /// Relationship generation configuration
89    #[serde(default)]
90    pub relationships: RelationshipSchemaConfig,
91    /// Accounting standards framework configuration (IFRS, US GAAP)
92    #[serde(default)]
93    pub accounting_standards: AccountingStandardsConfig,
94    /// Audit standards framework configuration (ISA, PCAOB)
95    #[serde(default)]
96    pub audit_standards: AuditStandardsConfig,
97    /// Advanced distribution configuration (mixture models, correlations, regime changes)
98    #[serde(default)]
99    pub distributions: AdvancedDistributionConfig,
100    /// Temporal patterns configuration (business days, period-end dynamics, processing lags)
101    #[serde(default)]
102    pub temporal_patterns: TemporalPatternsConfig,
103    /// Vendor network configuration (multi-tier supply chain modeling)
104    #[serde(default)]
105    pub vendor_network: VendorNetworkSchemaConfig,
106    /// Customer segmentation configuration (value segments, lifecycle stages)
107    #[serde(default)]
108    pub customer_segmentation: CustomerSegmentationSchemaConfig,
109    /// Relationship strength calculation configuration
110    #[serde(default)]
111    pub relationship_strength: RelationshipStrengthSchemaConfig,
112    /// Cross-process link configuration (P2P ↔ O2C via inventory)
113    #[serde(default)]
114    pub cross_process_links: CrossProcessLinksSchemaConfig,
115    /// Organizational events configuration (acquisitions, divestitures, etc.)
116    #[serde(default)]
117    pub organizational_events: OrganizationalEventsSchemaConfig,
118    /// Behavioral drift configuration (vendor, customer, employee behavior)
119    #[serde(default)]
120    pub behavioral_drift: BehavioralDriftSchemaConfig,
121    /// Market drift configuration (economic cycles, commodities, price shocks)
122    #[serde(default)]
123    pub market_drift: MarketDriftSchemaConfig,
124    /// Drift labeling configuration for ground truth generation
125    #[serde(default)]
126    pub drift_labeling: DriftLabelingSchemaConfig,
127    /// Enhanced anomaly injection configuration (multi-stage schemes, correlated injection, near-miss)
128    #[serde(default)]
129    pub anomaly_injection: EnhancedAnomalyConfig,
130    /// Industry-specific transaction and anomaly generation configuration
131    #[serde(default)]
132    pub industry_specific: IndustrySpecificConfig,
133}
134
135/// Graph export configuration for accounting network and ML training exports.
136///
137/// This section enables exporting generated data as graphs for:
138/// - Network reconstruction algorithms
139/// - Graph neural network training
140/// - Neo4j graph database import
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct GraphExportConfig {
143    /// Enable graph export.
144    #[serde(default)]
145    pub enabled: bool,
146
147    /// Graph types to generate.
148    #[serde(default = "default_graph_types")]
149    pub graph_types: Vec<GraphTypeConfig>,
150
151    /// Export formats to generate.
152    #[serde(default = "default_graph_formats")]
153    pub formats: Vec<GraphExportFormat>,
154
155    /// Train split ratio for ML datasets.
156    #[serde(default = "default_train_ratio")]
157    pub train_ratio: f64,
158
159    /// Validation split ratio for ML datasets.
160    #[serde(default = "default_val_ratio")]
161    pub validation_ratio: f64,
162
163    /// Random seed for train/val/test splits.
164    #[serde(default)]
165    pub split_seed: Option<u64>,
166
167    /// Output subdirectory for graph exports (relative to output directory).
168    #[serde(default = "default_graph_subdir")]
169    pub output_subdirectory: String,
170
171    /// Multi-layer hypergraph export settings for RustGraph integration.
172    #[serde(default)]
173    pub hypergraph: HypergraphExportSettings,
174}
175
176fn default_graph_types() -> Vec<GraphTypeConfig> {
177    vec![GraphTypeConfig::default()]
178}
179
180fn default_graph_formats() -> Vec<GraphExportFormat> {
181    vec![GraphExportFormat::PytorchGeometric]
182}
183
184fn default_train_ratio() -> f64 {
185    0.7
186}
187
188fn default_val_ratio() -> f64 {
189    0.15
190}
191
192fn default_graph_subdir() -> String {
193    "graphs".to_string()
194}
195
196impl Default for GraphExportConfig {
197    fn default() -> Self {
198        Self {
199            enabled: false,
200            graph_types: default_graph_types(),
201            formats: default_graph_formats(),
202            train_ratio: 0.7,
203            validation_ratio: 0.15,
204            split_seed: None,
205            output_subdirectory: "graphs".to_string(),
206            hypergraph: HypergraphExportSettings::default(),
207        }
208    }
209}
210
211/// Settings for the multi-layer hypergraph export (RustGraph integration).
212///
213/// Produces a 3-layer hypergraph:
214/// - Layer 1: Governance & Controls (COSO, SOX, internal controls, organizational)
215/// - Layer 2: Process Events (P2P/O2C document flows, OCPM events)
216/// - Layer 3: Accounting Network (GL accounts, journal entries as hyperedges)
217#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct HypergraphExportSettings {
219    /// Enable hypergraph export.
220    #[serde(default)]
221    pub enabled: bool,
222
223    /// Maximum total nodes across all layers (default 50000).
224    #[serde(default = "default_hypergraph_max_nodes")]
225    pub max_nodes: usize,
226
227    /// Aggregation strategy when node budget is exceeded.
228    #[serde(default = "default_aggregation_strategy")]
229    pub aggregation_strategy: String,
230
231    /// Layer 1 (Governance & Controls) settings.
232    #[serde(default)]
233    pub governance_layer: GovernanceLayerSettings,
234
235    /// Layer 2 (Process Events) settings.
236    #[serde(default)]
237    pub process_layer: ProcessLayerSettings,
238
239    /// Layer 3 (Accounting Network) settings.
240    #[serde(default)]
241    pub accounting_layer: AccountingLayerSettings,
242
243    /// Cross-layer edge generation settings.
244    #[serde(default)]
245    pub cross_layer: CrossLayerSettings,
246
247    /// Output subdirectory for hypergraph files (relative to graph output directory).
248    #[serde(default = "default_hypergraph_subdir")]
249    pub output_subdirectory: String,
250}
251
252fn default_hypergraph_max_nodes() -> usize {
253    50_000
254}
255
256fn default_aggregation_strategy() -> String {
257    "pool_by_counterparty".to_string()
258}
259
260fn default_hypergraph_subdir() -> String {
261    "hypergraph".to_string()
262}
263
264impl Default for HypergraphExportSettings {
265    fn default() -> Self {
266        Self {
267            enabled: false,
268            max_nodes: 50_000,
269            aggregation_strategy: "pool_by_counterparty".to_string(),
270            governance_layer: GovernanceLayerSettings::default(),
271            process_layer: ProcessLayerSettings::default(),
272            accounting_layer: AccountingLayerSettings::default(),
273            cross_layer: CrossLayerSettings::default(),
274            output_subdirectory: "hypergraph".to_string(),
275        }
276    }
277}
278
279/// Layer 1: Governance & Controls layer settings.
280#[derive(Debug, Clone, Serialize, Deserialize)]
281pub struct GovernanceLayerSettings {
282    /// Include COSO framework nodes (5 components + 17 principles).
283    #[serde(default = "default_true")]
284    pub include_coso: bool,
285    /// Include internal control nodes.
286    #[serde(default = "default_true")]
287    pub include_controls: bool,
288    /// Include SOX assertion nodes.
289    #[serde(default = "default_true")]
290    pub include_sox: bool,
291    /// Include vendor master data nodes.
292    #[serde(default = "default_true")]
293    pub include_vendors: bool,
294    /// Include customer master data nodes.
295    #[serde(default = "default_true")]
296    pub include_customers: bool,
297    /// Include employee/organizational nodes.
298    #[serde(default = "default_true")]
299    pub include_employees: bool,
300}
301
302impl Default for GovernanceLayerSettings {
303    fn default() -> Self {
304        Self {
305            include_coso: true,
306            include_controls: true,
307            include_sox: true,
308            include_vendors: true,
309            include_customers: true,
310            include_employees: true,
311        }
312    }
313}
314
315/// Layer 2: Process Events layer settings.
316#[derive(Debug, Clone, Serialize, Deserialize)]
317pub struct ProcessLayerSettings {
318    /// Include P2P (Procure-to-Pay) document flow nodes.
319    #[serde(default = "default_true")]
320    pub include_p2p: bool,
321    /// Include O2C (Order-to-Cash) document flow nodes.
322    #[serde(default = "default_true")]
323    pub include_o2c: bool,
324    /// Export OCPM events as hyperedges.
325    #[serde(default = "default_true")]
326    pub events_as_hyperedges: bool,
327    /// Threshold: if a counterparty has more documents than this, aggregate into pool nodes.
328    #[serde(default = "default_docs_per_counterparty_threshold")]
329    pub docs_per_counterparty_threshold: usize,
330}
331
332fn default_docs_per_counterparty_threshold() -> usize {
333    20
334}
335
336impl Default for ProcessLayerSettings {
337    fn default() -> Self {
338        Self {
339            include_p2p: true,
340            include_o2c: true,
341            events_as_hyperedges: true,
342            docs_per_counterparty_threshold: 20,
343        }
344    }
345}
346
347/// Layer 3: Accounting Network layer settings.
348#[derive(Debug, Clone, Serialize, Deserialize)]
349pub struct AccountingLayerSettings {
350    /// Include GL account nodes.
351    #[serde(default = "default_true")]
352    pub include_accounts: bool,
353    /// Export journal entries as hyperedges (debit+credit accounts as participants).
354    #[serde(default = "default_true")]
355    pub je_as_hyperedges: bool,
356}
357
358impl Default for AccountingLayerSettings {
359    fn default() -> Self {
360        Self {
361            include_accounts: true,
362            je_as_hyperedges: true,
363        }
364    }
365}
366
367/// Cross-layer edge generation settings.
368#[derive(Debug, Clone, Serialize, Deserialize)]
369pub struct CrossLayerSettings {
370    /// Generate cross-layer edges (Control→Account, Vendor→PO, etc.).
371    #[serde(default = "default_true")]
372    pub enabled: bool,
373}
374
375impl Default for CrossLayerSettings {
376    fn default() -> Self {
377        Self { enabled: true }
378    }
379}
380
381/// Configuration for a specific graph type to export.
382#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct GraphTypeConfig {
384    /// Name identifier for this graph configuration.
385    #[serde(default = "default_graph_name")]
386    pub name: String,
387
388    /// Whether to aggregate parallel edges between the same nodes.
389    #[serde(default)]
390    pub aggregate_edges: bool,
391
392    /// Minimum edge weight to include (filters out small transactions).
393    #[serde(default)]
394    pub min_edge_weight: f64,
395
396    /// Whether to include document nodes (creates hub-and-spoke structure).
397    #[serde(default)]
398    pub include_document_nodes: bool,
399}
400
401fn default_graph_name() -> String {
402    "accounting_network".to_string()
403}
404
405impl Default for GraphTypeConfig {
406    fn default() -> Self {
407        Self {
408            name: "accounting_network".to_string(),
409            aggregate_edges: false,
410            min_edge_weight: 0.0,
411            include_document_nodes: false,
412        }
413    }
414}
415
416/// Export format for graph data.
417#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
418#[serde(rename_all = "snake_case")]
419pub enum GraphExportFormat {
420    /// PyTorch Geometric format (.npy files + metadata.json).
421    PytorchGeometric,
422    /// Neo4j format (CSV files + Cypher import scripts).
423    Neo4j,
424    /// Deep Graph Library format.
425    Dgl,
426    /// RustGraph/RustAssureTwin JSON format.
427    RustGraph,
428    /// RustGraph multi-layer hypergraph format (nodes.jsonl + edges.jsonl + hyperedges.jsonl).
429    RustGraphHypergraph,
430}
431
432/// Scenario configuration for metadata, tagging, and ML training setup.
433///
434/// This section enables tracking the purpose and characteristics of a generation run.
435#[derive(Debug, Clone, Default, Serialize, Deserialize)]
436pub struct ScenarioConfig {
437    /// Tags for categorizing and filtering datasets.
438    /// Examples: "fraud_detection", "retail", "month_end_stress", "ml_training"
439    #[serde(default)]
440    pub tags: Vec<String>,
441
442    /// Data quality profile preset.
443    /// - "clean": Minimal data quality issues (0.1% missing, 0.05% typos)
444    /// - "noisy": Moderate issues (5% missing, 2% typos, 1% duplicates)
445    /// - "legacy": Heavy issues simulating legacy system data (10% missing, 5% typos)
446    #[serde(default)]
447    pub profile: Option<String>,
448
449    /// Human-readable description of the scenario purpose.
450    #[serde(default)]
451    pub description: Option<String>,
452
453    /// Whether this run is for ML training (enables balanced labeling).
454    #[serde(default)]
455    pub ml_training: bool,
456
457    /// Target anomaly class balance for ML training.
458    /// If set, anomalies will be injected to achieve this ratio.
459    #[serde(default)]
460    pub target_anomaly_ratio: Option<f64>,
461
462    /// Custom metadata key-value pairs.
463    #[serde(default)]
464    pub metadata: std::collections::HashMap<String, String>,
465}
466
467/// Temporal drift configuration for simulating distribution changes over time.
468///
469/// This enables generation of data that shows realistic temporal evolution,
470/// useful for training drift detection models and testing temporal robustness.
471#[derive(Debug, Clone, Serialize, Deserialize)]
472pub struct TemporalDriftConfig {
473    /// Enable temporal drift simulation.
474    #[serde(default)]
475    pub enabled: bool,
476
477    /// Amount mean drift per period (e.g., 0.02 = 2% mean shift per month).
478    /// Simulates gradual inflation or business growth.
479    #[serde(default = "default_amount_drift")]
480    pub amount_mean_drift: f64,
481
482    /// Amount variance drift per period (e.g., 0.01 = 1% variance increase per month).
483    /// Simulates increasing volatility over time.
484    #[serde(default)]
485    pub amount_variance_drift: f64,
486
487    /// Anomaly rate drift per period (e.g., 0.001 = 0.1% increase per month).
488    /// Simulates increasing fraud attempts or degrading controls.
489    #[serde(default)]
490    pub anomaly_rate_drift: f64,
491
492    /// Concept drift rate - how quickly feature distributions change (0.0-1.0).
493    /// Higher values cause more rapid distribution shifts.
494    #[serde(default = "default_concept_drift")]
495    pub concept_drift_rate: f64,
496
497    /// Sudden drift events - probability of a sudden distribution shift in any period.
498    #[serde(default)]
499    pub sudden_drift_probability: f64,
500
501    /// Magnitude of sudden drift events when they occur (multiplier).
502    #[serde(default = "default_sudden_drift_magnitude")]
503    pub sudden_drift_magnitude: f64,
504
505    /// Seasonal drift - enable cyclic patterns that repeat annually.
506    #[serde(default)]
507    pub seasonal_drift: bool,
508
509    /// Drift start period (0 = from beginning). Use to simulate stable baseline before drift.
510    #[serde(default)]
511    pub drift_start_period: u32,
512
513    /// Drift type: "gradual", "sudden", "recurring", "mixed"
514    #[serde(default = "default_drift_type")]
515    pub drift_type: DriftType,
516}
517
518fn default_amount_drift() -> f64 {
519    0.02
520}
521
522fn default_concept_drift() -> f64 {
523    0.01
524}
525
526fn default_sudden_drift_magnitude() -> f64 {
527    2.0
528}
529
530fn default_drift_type() -> DriftType {
531    DriftType::Gradual
532}
533
534impl Default for TemporalDriftConfig {
535    fn default() -> Self {
536        Self {
537            enabled: false,
538            amount_mean_drift: 0.02,
539            amount_variance_drift: 0.0,
540            anomaly_rate_drift: 0.0,
541            concept_drift_rate: 0.01,
542            sudden_drift_probability: 0.0,
543            sudden_drift_magnitude: 2.0,
544            seasonal_drift: false,
545            drift_start_period: 0,
546            drift_type: DriftType::Gradual,
547        }
548    }
549}
550
551impl TemporalDriftConfig {
552    /// Convert to core DriftConfig for use in generators.
553    pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
554        datasynth_core::distributions::DriftConfig {
555            enabled: self.enabled,
556            amount_mean_drift: self.amount_mean_drift,
557            amount_variance_drift: self.amount_variance_drift,
558            anomaly_rate_drift: self.anomaly_rate_drift,
559            concept_drift_rate: self.concept_drift_rate,
560            sudden_drift_probability: self.sudden_drift_probability,
561            sudden_drift_magnitude: self.sudden_drift_magnitude,
562            seasonal_drift: self.seasonal_drift,
563            drift_start_period: self.drift_start_period,
564            drift_type: match self.drift_type {
565                DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
566                DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
567                DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
568                DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
569            },
570            regime_changes: Vec::new(),
571            economic_cycle: Default::default(),
572            parameter_drifts: Vec::new(),
573        }
574    }
575}
576
577/// Types of temporal drift patterns.
578#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
579#[serde(rename_all = "snake_case")]
580pub enum DriftType {
581    /// Gradual, continuous drift over time (like inflation).
582    #[default]
583    Gradual,
584    /// Sudden, point-in-time shifts (like policy changes).
585    Sudden,
586    /// Recurring patterns that cycle (like seasonal variations).
587    Recurring,
588    /// Combination of gradual background drift with occasional sudden shifts.
589    Mixed,
590}
591
592// ============================================================================
593// Streaming Output API Configuration (Phase 2)
594// ============================================================================
595
596/// Configuration for streaming output API.
597#[derive(Debug, Clone, Serialize, Deserialize)]
598pub struct StreamingSchemaConfig {
599    /// Enable streaming output.
600    #[serde(default)]
601    pub enabled: bool,
602    /// Buffer size for streaming (number of items).
603    #[serde(default = "default_buffer_size")]
604    pub buffer_size: usize,
605    /// Enable progress reporting.
606    #[serde(default = "default_true")]
607    pub enable_progress: bool,
608    /// Progress reporting interval (number of items).
609    #[serde(default = "default_progress_interval")]
610    pub progress_interval: u64,
611    /// Backpressure strategy.
612    #[serde(default)]
613    pub backpressure: BackpressureSchemaStrategy,
614}
615
616fn default_buffer_size() -> usize {
617    1000
618}
619
620fn default_progress_interval() -> u64 {
621    100
622}
623
624impl Default for StreamingSchemaConfig {
625    fn default() -> Self {
626        Self {
627            enabled: false,
628            buffer_size: 1000,
629            enable_progress: true,
630            progress_interval: 100,
631            backpressure: BackpressureSchemaStrategy::Block,
632        }
633    }
634}
635
636/// Backpressure strategy for streaming output.
637#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
638#[serde(rename_all = "snake_case")]
639pub enum BackpressureSchemaStrategy {
640    /// Block until space is available in the buffer.
641    #[default]
642    Block,
643    /// Drop oldest items when buffer is full.
644    DropOldest,
645    /// Drop newest items when buffer is full.
646    DropNewest,
647    /// Buffer overflow items up to a limit, then block.
648    Buffer,
649}
650
651// ============================================================================
652// Rate Limiting Configuration (Phase 5)
653// ============================================================================
654
655/// Configuration for rate limiting.
656#[derive(Debug, Clone, Serialize, Deserialize)]
657pub struct RateLimitSchemaConfig {
658    /// Enable rate limiting.
659    #[serde(default)]
660    pub enabled: bool,
661    /// Entities per second limit.
662    #[serde(default = "default_entities_per_second")]
663    pub entities_per_second: f64,
664    /// Burst size (number of tokens in bucket).
665    #[serde(default = "default_burst_size")]
666    pub burst_size: u32,
667    /// Backpressure strategy for rate limiting.
668    #[serde(default)]
669    pub backpressure: RateLimitBackpressureSchema,
670}
671
672fn default_entities_per_second() -> f64 {
673    1000.0
674}
675
676fn default_burst_size() -> u32 {
677    100
678}
679
680impl Default for RateLimitSchemaConfig {
681    fn default() -> Self {
682        Self {
683            enabled: false,
684            entities_per_second: 1000.0,
685            burst_size: 100,
686            backpressure: RateLimitBackpressureSchema::Block,
687        }
688    }
689}
690
691/// Backpressure strategy for rate limiting.
692#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
693#[serde(rename_all = "snake_case")]
694pub enum RateLimitBackpressureSchema {
695    /// Block until rate allows.
696    #[default]
697    Block,
698    /// Drop items that exceed rate.
699    Drop,
700    /// Buffer items and process when rate allows.
701    Buffer,
702}
703
704// ============================================================================
705// Temporal Attribute Generation Configuration (Phase 3)
706// ============================================================================
707
708/// Configuration for temporal attribute generation.
709#[derive(Debug, Clone, Serialize, Deserialize)]
710pub struct TemporalAttributeSchemaConfig {
711    /// Enable temporal attribute generation.
712    #[serde(default)]
713    pub enabled: bool,
714    /// Valid time configuration.
715    #[serde(default)]
716    pub valid_time: ValidTimeSchemaConfig,
717    /// Transaction time configuration.
718    #[serde(default)]
719    pub transaction_time: TransactionTimeSchemaConfig,
720    /// Generate version chains for entities.
721    #[serde(default)]
722    pub generate_version_chains: bool,
723    /// Average number of versions per entity.
724    #[serde(default = "default_avg_versions")]
725    pub avg_versions_per_entity: f64,
726}
727
728fn default_avg_versions() -> f64 {
729    1.5
730}
731
732impl Default for TemporalAttributeSchemaConfig {
733    fn default() -> Self {
734        Self {
735            enabled: false,
736            valid_time: ValidTimeSchemaConfig::default(),
737            transaction_time: TransactionTimeSchemaConfig::default(),
738            generate_version_chains: false,
739            avg_versions_per_entity: 1.5,
740        }
741    }
742}
743
744/// Configuration for valid time (business time) generation.
745#[derive(Debug, Clone, Serialize, Deserialize)]
746pub struct ValidTimeSchemaConfig {
747    /// Probability that valid_to is set (entity has ended validity).
748    #[serde(default = "default_closed_probability")]
749    pub closed_probability: f64,
750    /// Average validity duration in days.
751    #[serde(default = "default_avg_validity_days")]
752    pub avg_validity_days: u32,
753    /// Standard deviation of validity duration in days.
754    #[serde(default = "default_validity_stddev")]
755    pub validity_stddev_days: u32,
756}
757
758fn default_closed_probability() -> f64 {
759    0.1
760}
761
762fn default_avg_validity_days() -> u32 {
763    365
764}
765
766fn default_validity_stddev() -> u32 {
767    90
768}
769
770impl Default for ValidTimeSchemaConfig {
771    fn default() -> Self {
772        Self {
773            closed_probability: 0.1,
774            avg_validity_days: 365,
775            validity_stddev_days: 90,
776        }
777    }
778}
779
780/// Configuration for transaction time (system time) generation.
781#[derive(Debug, Clone, Serialize, Deserialize)]
782pub struct TransactionTimeSchemaConfig {
783    /// Average recording delay in seconds (0 = immediate).
784    #[serde(default)]
785    pub avg_recording_delay_seconds: u32,
786    /// Allow backdating (recording time before valid time).
787    #[serde(default)]
788    pub allow_backdating: bool,
789    /// Probability of backdating if allowed.
790    #[serde(default = "default_backdating_probability")]
791    pub backdating_probability: f64,
792    /// Maximum backdate days.
793    #[serde(default = "default_max_backdate_days")]
794    pub max_backdate_days: u32,
795}
796
797fn default_backdating_probability() -> f64 {
798    0.01
799}
800
801fn default_max_backdate_days() -> u32 {
802    30
803}
804
805impl Default for TransactionTimeSchemaConfig {
806    fn default() -> Self {
807        Self {
808            avg_recording_delay_seconds: 0,
809            allow_backdating: false,
810            backdating_probability: 0.01,
811            max_backdate_days: 30,
812        }
813    }
814}
815
816// ============================================================================
817// Relationship Generation Configuration (Phase 4)
818// ============================================================================
819
820/// Configuration for relationship generation.
821#[derive(Debug, Clone, Serialize, Deserialize)]
822pub struct RelationshipSchemaConfig {
823    /// Relationship type definitions.
824    #[serde(default)]
825    pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
826    /// Allow orphan entities (entities with no relationships).
827    #[serde(default = "default_true")]
828    pub allow_orphans: bool,
829    /// Probability of creating an orphan entity.
830    #[serde(default = "default_orphan_probability")]
831    pub orphan_probability: f64,
832    /// Allow circular relationships.
833    #[serde(default)]
834    pub allow_circular: bool,
835    /// Maximum depth for circular relationship detection.
836    #[serde(default = "default_max_circular_depth")]
837    pub max_circular_depth: u32,
838}
839
840fn default_orphan_probability() -> f64 {
841    0.01
842}
843
844fn default_max_circular_depth() -> u32 {
845    3
846}
847
848impl Default for RelationshipSchemaConfig {
849    fn default() -> Self {
850        Self {
851            relationship_types: Vec::new(),
852            allow_orphans: true,
853            orphan_probability: 0.01,
854            allow_circular: false,
855            max_circular_depth: 3,
856        }
857    }
858}
859
860/// Configuration for a specific relationship type.
861#[derive(Debug, Clone, Serialize, Deserialize)]
862pub struct RelationshipTypeSchemaConfig {
863    /// Name of the relationship type (e.g., "debits", "credits", "created").
864    pub name: String,
865    /// Source entity type (e.g., "journal_entry").
866    pub source_type: String,
867    /// Target entity type (e.g., "account").
868    pub target_type: String,
869    /// Cardinality rule for this relationship.
870    #[serde(default)]
871    pub cardinality: CardinalitySchemaRule,
872    /// Weight for this relationship in random selection.
873    #[serde(default = "default_relationship_weight")]
874    pub weight: f64,
875    /// Whether this relationship is required.
876    #[serde(default)]
877    pub required: bool,
878    /// Whether this relationship is directed.
879    #[serde(default = "default_true")]
880    pub directed: bool,
881}
882
883fn default_relationship_weight() -> f64 {
884    1.0
885}
886
887impl Default for RelationshipTypeSchemaConfig {
888    fn default() -> Self {
889        Self {
890            name: String::new(),
891            source_type: String::new(),
892            target_type: String::new(),
893            cardinality: CardinalitySchemaRule::default(),
894            weight: 1.0,
895            required: false,
896            directed: true,
897        }
898    }
899}
900
901/// Cardinality rule for relationships in schema config.
902#[derive(Debug, Clone, Serialize, Deserialize)]
903#[serde(rename_all = "snake_case")]
904pub enum CardinalitySchemaRule {
905    /// One source to one target.
906    OneToOne,
907    /// One source to many targets.
908    OneToMany {
909        /// Minimum number of targets.
910        min: u32,
911        /// Maximum number of targets.
912        max: u32,
913    },
914    /// Many sources to one target.
915    ManyToOne {
916        /// Minimum number of sources.
917        min: u32,
918        /// Maximum number of sources.
919        max: u32,
920    },
921    /// Many sources to many targets.
922    ManyToMany {
923        /// Minimum targets per source.
924        min_per_source: u32,
925        /// Maximum targets per source.
926        max_per_source: u32,
927    },
928}
929
930impl Default for CardinalitySchemaRule {
931    fn default() -> Self {
932        Self::OneToMany { min: 1, max: 5 }
933    }
934}
935
936/// Global configuration settings.
937#[derive(Debug, Clone, Serialize, Deserialize)]
938pub struct GlobalConfig {
939    /// Random seed for reproducibility
940    pub seed: Option<u64>,
941    /// Industry sector
942    pub industry: IndustrySector,
943    /// Simulation start date (YYYY-MM-DD)
944    pub start_date: String,
945    /// Simulation period in months
946    pub period_months: u32,
947    /// Base currency for group reporting
948    #[serde(default = "default_currency")]
949    pub group_currency: String,
950    /// Enable parallel generation
951    #[serde(default = "default_true")]
952    pub parallel: bool,
953    /// Number of worker threads (0 = auto-detect)
954    #[serde(default)]
955    pub worker_threads: usize,
956    /// Memory limit in MB (0 = unlimited)
957    #[serde(default)]
958    pub memory_limit_mb: usize,
959}
960
961fn default_currency() -> String {
962    "USD".to_string()
963}
964fn default_true() -> bool {
965    true
966}
967
968/// Company code configuration.
969#[derive(Debug, Clone, Serialize, Deserialize)]
970pub struct CompanyConfig {
971    /// Company code identifier
972    pub code: String,
973    /// Company name
974    pub name: String,
975    /// Local currency (ISO 4217)
976    pub currency: String,
977    /// Country code (ISO 3166-1 alpha-2)
978    pub country: String,
979    /// Fiscal year variant
980    #[serde(default = "default_fiscal_variant")]
981    pub fiscal_year_variant: String,
982    /// Transaction volume per year
983    pub annual_transaction_volume: TransactionVolume,
984    /// Company-specific transaction weight
985    #[serde(default = "default_weight")]
986    pub volume_weight: f64,
987}
988
989fn default_fiscal_variant() -> String {
990    "K4".to_string()
991}
992fn default_weight() -> f64 {
993    1.0
994}
995
996/// Transaction volume presets.
997#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
998#[serde(rename_all = "snake_case")]
999pub enum TransactionVolume {
1000    /// 10,000 transactions per year
1001    TenK,
1002    /// 100,000 transactions per year
1003    HundredK,
1004    /// 1,000,000 transactions per year
1005    OneM,
1006    /// 10,000,000 transactions per year
1007    TenM,
1008    /// 100,000,000 transactions per year
1009    HundredM,
1010    /// Custom count
1011    Custom(u64),
1012}
1013
1014impl TransactionVolume {
1015    /// Get the transaction count.
1016    pub fn count(&self) -> u64 {
1017        match self {
1018            Self::TenK => 10_000,
1019            Self::HundredK => 100_000,
1020            Self::OneM => 1_000_000,
1021            Self::TenM => 10_000_000,
1022            Self::HundredM => 100_000_000,
1023            Self::Custom(n) => *n,
1024        }
1025    }
1026}
1027
1028/// Chart of Accounts configuration.
1029#[derive(Debug, Clone, Serialize, Deserialize)]
1030pub struct ChartOfAccountsConfig {
1031    /// CoA complexity level
1032    pub complexity: CoAComplexity,
1033    /// Use industry-specific accounts
1034    #[serde(default = "default_true")]
1035    pub industry_specific: bool,
1036    /// Custom account definitions file
1037    pub custom_accounts: Option<PathBuf>,
1038    /// Minimum hierarchy depth
1039    #[serde(default = "default_min_depth")]
1040    pub min_hierarchy_depth: u8,
1041    /// Maximum hierarchy depth
1042    #[serde(default = "default_max_depth")]
1043    pub max_hierarchy_depth: u8,
1044}
1045
1046fn default_min_depth() -> u8 {
1047    2
1048}
1049fn default_max_depth() -> u8 {
1050    5
1051}
1052
1053impl Default for ChartOfAccountsConfig {
1054    fn default() -> Self {
1055        Self {
1056            complexity: CoAComplexity::Small,
1057            industry_specific: true,
1058            custom_accounts: None,
1059            min_hierarchy_depth: default_min_depth(),
1060            max_hierarchy_depth: default_max_depth(),
1061        }
1062    }
1063}
1064
1065/// Transaction generation configuration.
1066#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1067pub struct TransactionConfig {
1068    /// Line item distribution
1069    #[serde(default)]
1070    pub line_item_distribution: LineItemDistributionConfig,
1071    /// Debit/credit balance distribution
1072    #[serde(default)]
1073    pub debit_credit_distribution: DebitCreditDistributionConfig,
1074    /// Even/odd line count distribution
1075    #[serde(default)]
1076    pub even_odd_distribution: EvenOddDistributionConfig,
1077    /// Transaction source distribution
1078    #[serde(default)]
1079    pub source_distribution: SourceDistribution,
1080    /// Seasonality configuration
1081    #[serde(default)]
1082    pub seasonality: SeasonalityConfig,
1083    /// Amount distribution
1084    #[serde(default)]
1085    pub amounts: AmountDistributionConfig,
1086    /// Benford's Law compliance configuration
1087    #[serde(default)]
1088    pub benford: BenfordConfig,
1089}
1090
1091/// Benford's Law compliance configuration.
1092#[derive(Debug, Clone, Serialize, Deserialize)]
1093pub struct BenfordConfig {
1094    /// Enable Benford's Law compliance for amount generation
1095    #[serde(default = "default_true")]
1096    pub enabled: bool,
1097    /// Tolerance for deviation from ideal Benford distribution (0.0-1.0)
1098    #[serde(default = "default_benford_tolerance")]
1099    pub tolerance: f64,
1100    /// Transaction sources exempt from Benford's Law (fixed amounts)
1101    #[serde(default)]
1102    pub exempt_sources: Vec<BenfordExemption>,
1103}
1104
1105fn default_benford_tolerance() -> f64 {
1106    0.05
1107}
1108
1109impl Default for BenfordConfig {
1110    fn default() -> Self {
1111        Self {
1112            enabled: true,
1113            tolerance: default_benford_tolerance(),
1114            exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
1115        }
1116    }
1117}
1118
1119/// Types of transactions exempt from Benford's Law.
1120#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1121#[serde(rename_all = "snake_case")]
1122pub enum BenfordExemption {
1123    /// Recurring fixed amounts (rent, subscriptions)
1124    Recurring,
1125    /// Payroll (standardized salaries)
1126    Payroll,
1127    /// Fixed fees and charges
1128    FixedFees,
1129    /// Round number purchases (often legitimate)
1130    RoundAmounts,
1131}
1132
1133/// Distribution of transaction sources.
1134#[derive(Debug, Clone, Serialize, Deserialize)]
1135pub struct SourceDistribution {
1136    /// Manual entries percentage
1137    pub manual: f64,
1138    /// Automated system entries
1139    pub automated: f64,
1140    /// Recurring entries
1141    pub recurring: f64,
1142    /// Adjustment entries
1143    pub adjustment: f64,
1144}
1145
1146impl Default for SourceDistribution {
1147    fn default() -> Self {
1148        Self {
1149            manual: 0.20,
1150            automated: 0.70,
1151            recurring: 0.07,
1152            adjustment: 0.03,
1153        }
1154    }
1155}
1156
1157/// Output configuration.
1158#[derive(Debug, Clone, Serialize, Deserialize)]
1159pub struct OutputConfig {
1160    /// Output mode
1161    #[serde(default)]
1162    pub mode: OutputMode,
1163    /// Output directory
1164    pub output_directory: PathBuf,
1165    /// File formats to generate
1166    #[serde(default = "default_formats")]
1167    pub formats: Vec<FileFormat>,
1168    /// Compression settings
1169    #[serde(default)]
1170    pub compression: CompressionConfig,
1171    /// Batch size for writes
1172    #[serde(default = "default_batch_size")]
1173    pub batch_size: usize,
1174    /// Include ACDOCA format
1175    #[serde(default = "default_true")]
1176    pub include_acdoca: bool,
1177    /// Include BSEG format
1178    #[serde(default)]
1179    pub include_bseg: bool,
1180    /// Partition by fiscal period
1181    #[serde(default = "default_true")]
1182    pub partition_by_period: bool,
1183    /// Partition by company code
1184    #[serde(default)]
1185    pub partition_by_company: bool,
1186}
1187
1188fn default_formats() -> Vec<FileFormat> {
1189    vec![FileFormat::Parquet]
1190}
1191fn default_batch_size() -> usize {
1192    100_000
1193}
1194
1195impl Default for OutputConfig {
1196    fn default() -> Self {
1197        Self {
1198            mode: OutputMode::FlatFile,
1199            output_directory: PathBuf::from("./output"),
1200            formats: default_formats(),
1201            compression: CompressionConfig::default(),
1202            batch_size: default_batch_size(),
1203            include_acdoca: true,
1204            include_bseg: false,
1205            partition_by_period: true,
1206            partition_by_company: false,
1207        }
1208    }
1209}
1210
1211/// Output mode.
1212#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1213#[serde(rename_all = "snake_case")]
1214pub enum OutputMode {
1215    /// Stream records as generated
1216    Streaming,
1217    /// Write to flat files
1218    #[default]
1219    FlatFile,
1220    /// Both streaming and flat file
1221    Both,
1222}
1223
1224/// Supported file formats.
1225#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1226#[serde(rename_all = "snake_case")]
1227pub enum FileFormat {
1228    Csv,
1229    Parquet,
1230    Json,
1231    JsonLines,
1232}
1233
1234/// Compression configuration.
1235#[derive(Debug, Clone, Serialize, Deserialize)]
1236pub struct CompressionConfig {
1237    /// Enable compression
1238    #[serde(default = "default_true")]
1239    pub enabled: bool,
1240    /// Compression algorithm
1241    #[serde(default)]
1242    pub algorithm: CompressionAlgorithm,
1243    /// Compression level (1-9)
1244    #[serde(default = "default_compression_level")]
1245    pub level: u8,
1246}
1247
1248fn default_compression_level() -> u8 {
1249    3
1250}
1251
1252impl Default for CompressionConfig {
1253    fn default() -> Self {
1254        Self {
1255            enabled: true,
1256            algorithm: CompressionAlgorithm::default(),
1257            level: default_compression_level(),
1258        }
1259    }
1260}
1261
1262/// Compression algorithms.
1263#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1264#[serde(rename_all = "snake_case")]
1265pub enum CompressionAlgorithm {
1266    Gzip,
1267    #[default]
1268    Zstd,
1269    Lz4,
1270    Snappy,
1271}
1272
1273/// Fraud simulation configuration.
1274#[derive(Debug, Clone, Serialize, Deserialize)]
1275pub struct FraudConfig {
1276    /// Enable fraud scenario generation
1277    #[serde(default)]
1278    pub enabled: bool,
1279    /// Overall fraud rate (0.0 to 1.0)
1280    #[serde(default = "default_fraud_rate")]
1281    pub fraud_rate: f64,
1282    /// Fraud type distribution
1283    #[serde(default)]
1284    pub fraud_type_distribution: FraudTypeDistribution,
1285    /// Enable fraud clustering
1286    #[serde(default)]
1287    pub clustering_enabled: bool,
1288    /// Clustering factor
1289    #[serde(default = "default_clustering_factor")]
1290    pub clustering_factor: f64,
1291    /// Approval thresholds for threshold-adjacent fraud pattern
1292    #[serde(default = "default_approval_thresholds")]
1293    pub approval_thresholds: Vec<f64>,
1294}
1295
1296fn default_approval_thresholds() -> Vec<f64> {
1297    vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1298}
1299
1300fn default_fraud_rate() -> f64 {
1301    0.005
1302}
1303fn default_clustering_factor() -> f64 {
1304    3.0
1305}
1306
1307impl Default for FraudConfig {
1308    fn default() -> Self {
1309        Self {
1310            enabled: false,
1311            fraud_rate: default_fraud_rate(),
1312            fraud_type_distribution: FraudTypeDistribution::default(),
1313            clustering_enabled: false,
1314            clustering_factor: default_clustering_factor(),
1315            approval_thresholds: default_approval_thresholds(),
1316        }
1317    }
1318}
1319
1320/// Distribution of fraud types.
1321#[derive(Debug, Clone, Serialize, Deserialize)]
1322pub struct FraudTypeDistribution {
1323    pub suspense_account_abuse: f64,
1324    pub fictitious_transaction: f64,
1325    pub revenue_manipulation: f64,
1326    pub expense_capitalization: f64,
1327    pub split_transaction: f64,
1328    pub timing_anomaly: f64,
1329    pub unauthorized_access: f64,
1330    pub duplicate_payment: f64,
1331}
1332
1333impl Default for FraudTypeDistribution {
1334    fn default() -> Self {
1335        Self {
1336            suspense_account_abuse: 0.25,
1337            fictitious_transaction: 0.15,
1338            revenue_manipulation: 0.10,
1339            expense_capitalization: 0.10,
1340            split_transaction: 0.15,
1341            timing_anomaly: 0.10,
1342            unauthorized_access: 0.10,
1343            duplicate_payment: 0.05,
1344        }
1345    }
1346}
1347
1348/// Internal Controls System (ICS) configuration.
1349#[derive(Debug, Clone, Serialize, Deserialize)]
1350pub struct InternalControlsConfig {
1351    /// Enable internal controls system
1352    #[serde(default)]
1353    pub enabled: bool,
1354    /// Rate at which controls result in exceptions (0.0 - 1.0)
1355    #[serde(default = "default_exception_rate")]
1356    pub exception_rate: f64,
1357    /// Rate at which SoD violations occur (0.0 - 1.0)
1358    #[serde(default = "default_sod_violation_rate")]
1359    pub sod_violation_rate: f64,
1360    /// Export control master data to separate files
1361    #[serde(default = "default_true")]
1362    pub export_control_master_data: bool,
1363    /// SOX materiality threshold for marking transactions as SOX-relevant
1364    #[serde(default = "default_sox_materiality_threshold")]
1365    pub sox_materiality_threshold: f64,
1366    /// Enable COSO 2013 framework integration
1367    #[serde(default = "default_true")]
1368    pub coso_enabled: bool,
1369    /// Include entity-level controls in generation
1370    #[serde(default)]
1371    pub include_entity_level_controls: bool,
1372    /// Target maturity level for controls
1373    /// Valid values: "ad_hoc", "repeatable", "defined", "managed", "optimized", "mixed"
1374    #[serde(default = "default_target_maturity_level")]
1375    pub target_maturity_level: String,
1376}
1377
1378fn default_exception_rate() -> f64 {
1379    0.02
1380}
1381
1382fn default_sod_violation_rate() -> f64 {
1383    0.01
1384}
1385
1386fn default_sox_materiality_threshold() -> f64 {
1387    10000.0
1388}
1389
1390fn default_target_maturity_level() -> String {
1391    "mixed".to_string()
1392}
1393
1394impl Default for InternalControlsConfig {
1395    fn default() -> Self {
1396        Self {
1397            enabled: false,
1398            exception_rate: default_exception_rate(),
1399            sod_violation_rate: default_sod_violation_rate(),
1400            export_control_master_data: true,
1401            sox_materiality_threshold: default_sox_materiality_threshold(),
1402            coso_enabled: true,
1403            include_entity_level_controls: false,
1404            target_maturity_level: default_target_maturity_level(),
1405        }
1406    }
1407}
1408
1409/// Business process configuration.
1410#[derive(Debug, Clone, Serialize, Deserialize)]
1411pub struct BusinessProcessConfig {
1412    /// Order-to-Cash weight
1413    #[serde(default = "default_o2c")]
1414    pub o2c_weight: f64,
1415    /// Procure-to-Pay weight
1416    #[serde(default = "default_p2p")]
1417    pub p2p_weight: f64,
1418    /// Record-to-Report weight
1419    #[serde(default = "default_r2r")]
1420    pub r2r_weight: f64,
1421    /// Hire-to-Retire weight
1422    #[serde(default = "default_h2r")]
1423    pub h2r_weight: f64,
1424    /// Acquire-to-Retire weight
1425    #[serde(default = "default_a2r")]
1426    pub a2r_weight: f64,
1427}
1428
1429fn default_o2c() -> f64 {
1430    0.35
1431}
1432fn default_p2p() -> f64 {
1433    0.30
1434}
1435fn default_r2r() -> f64 {
1436    0.20
1437}
1438fn default_h2r() -> f64 {
1439    0.10
1440}
1441fn default_a2r() -> f64 {
1442    0.05
1443}
1444
1445impl Default for BusinessProcessConfig {
1446    fn default() -> Self {
1447        Self {
1448            o2c_weight: default_o2c(),
1449            p2p_weight: default_p2p(),
1450            r2r_weight: default_r2r(),
1451            h2r_weight: default_h2r(),
1452            a2r_weight: default_a2r(),
1453        }
1454    }
1455}
1456
1457/// User persona configuration.
1458#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1459pub struct UserPersonaConfig {
1460    /// Distribution of user personas
1461    #[serde(default)]
1462    pub persona_distribution: PersonaDistribution,
1463    /// Users per persona type
1464    #[serde(default)]
1465    pub users_per_persona: UsersPerPersona,
1466}
1467
1468/// Distribution of user personas for transaction generation.
1469#[derive(Debug, Clone, Serialize, Deserialize)]
1470pub struct PersonaDistribution {
1471    pub junior_accountant: f64,
1472    pub senior_accountant: f64,
1473    pub controller: f64,
1474    pub manager: f64,
1475    pub automated_system: f64,
1476}
1477
1478impl Default for PersonaDistribution {
1479    fn default() -> Self {
1480        Self {
1481            junior_accountant: 0.15,
1482            senior_accountant: 0.15,
1483            controller: 0.05,
1484            manager: 0.05,
1485            automated_system: 0.60,
1486        }
1487    }
1488}
1489
1490/// Number of users per persona type.
1491#[derive(Debug, Clone, Serialize, Deserialize)]
1492pub struct UsersPerPersona {
1493    pub junior_accountant: usize,
1494    pub senior_accountant: usize,
1495    pub controller: usize,
1496    pub manager: usize,
1497    pub automated_system: usize,
1498}
1499
1500impl Default for UsersPerPersona {
1501    fn default() -> Self {
1502        Self {
1503            junior_accountant: 10,
1504            senior_accountant: 5,
1505            controller: 2,
1506            manager: 3,
1507            automated_system: 20,
1508        }
1509    }
1510}
1511
1512/// Template configuration for realistic data generation.
1513#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1514pub struct TemplateConfig {
1515    /// Name generation settings
1516    #[serde(default)]
1517    pub names: NameTemplateConfig,
1518    /// Description generation settings
1519    #[serde(default)]
1520    pub descriptions: DescriptionTemplateConfig,
1521    /// Reference number settings
1522    #[serde(default)]
1523    pub references: ReferenceTemplateConfig,
1524}
1525
1526/// Name template configuration.
1527#[derive(Debug, Clone, Serialize, Deserialize)]
1528pub struct NameTemplateConfig {
1529    /// Distribution of name cultures
1530    #[serde(default)]
1531    pub culture_distribution: CultureDistribution,
1532    /// Email domain for generated users
1533    #[serde(default = "default_email_domain")]
1534    pub email_domain: String,
1535    /// Generate realistic display names
1536    #[serde(default = "default_true")]
1537    pub generate_realistic_names: bool,
1538}
1539
1540fn default_email_domain() -> String {
1541    "company.com".to_string()
1542}
1543
1544impl Default for NameTemplateConfig {
1545    fn default() -> Self {
1546        Self {
1547            culture_distribution: CultureDistribution::default(),
1548            email_domain: default_email_domain(),
1549            generate_realistic_names: true,
1550        }
1551    }
1552}
1553
1554/// Distribution of name cultures for generation.
1555#[derive(Debug, Clone, Serialize, Deserialize)]
1556pub struct CultureDistribution {
1557    pub western_us: f64,
1558    pub hispanic: f64,
1559    pub german: f64,
1560    pub french: f64,
1561    pub chinese: f64,
1562    pub japanese: f64,
1563    pub indian: f64,
1564}
1565
1566impl Default for CultureDistribution {
1567    fn default() -> Self {
1568        Self {
1569            western_us: 0.40,
1570            hispanic: 0.20,
1571            german: 0.10,
1572            french: 0.05,
1573            chinese: 0.10,
1574            japanese: 0.05,
1575            indian: 0.10,
1576        }
1577    }
1578}
1579
1580/// Description template configuration.
1581#[derive(Debug, Clone, Serialize, Deserialize)]
1582pub struct DescriptionTemplateConfig {
1583    /// Generate header text for journal entries
1584    #[serde(default = "default_true")]
1585    pub generate_header_text: bool,
1586    /// Generate line text for journal entry lines
1587    #[serde(default = "default_true")]
1588    pub generate_line_text: bool,
1589}
1590
1591impl Default for DescriptionTemplateConfig {
1592    fn default() -> Self {
1593        Self {
1594            generate_header_text: true,
1595            generate_line_text: true,
1596        }
1597    }
1598}
1599
1600/// Reference number template configuration.
1601#[derive(Debug, Clone, Serialize, Deserialize)]
1602pub struct ReferenceTemplateConfig {
1603    /// Generate reference numbers
1604    #[serde(default = "default_true")]
1605    pub generate_references: bool,
1606    /// Invoice prefix
1607    #[serde(default = "default_invoice_prefix")]
1608    pub invoice_prefix: String,
1609    /// Purchase order prefix
1610    #[serde(default = "default_po_prefix")]
1611    pub po_prefix: String,
1612    /// Sales order prefix
1613    #[serde(default = "default_so_prefix")]
1614    pub so_prefix: String,
1615}
1616
1617fn default_invoice_prefix() -> String {
1618    "INV".to_string()
1619}
1620fn default_po_prefix() -> String {
1621    "PO".to_string()
1622}
1623fn default_so_prefix() -> String {
1624    "SO".to_string()
1625}
1626
1627impl Default for ReferenceTemplateConfig {
1628    fn default() -> Self {
1629        Self {
1630            generate_references: true,
1631            invoice_prefix: default_invoice_prefix(),
1632            po_prefix: default_po_prefix(),
1633            so_prefix: default_so_prefix(),
1634        }
1635    }
1636}
1637
1638/// Approval workflow configuration.
1639#[derive(Debug, Clone, Serialize, Deserialize)]
1640pub struct ApprovalConfig {
1641    /// Enable approval workflow generation
1642    #[serde(default)]
1643    pub enabled: bool,
1644    /// Threshold below which transactions are auto-approved
1645    #[serde(default = "default_auto_approve_threshold")]
1646    pub auto_approve_threshold: f64,
1647    /// Rate at which approvals are rejected (0.0 to 1.0)
1648    #[serde(default = "default_rejection_rate")]
1649    pub rejection_rate: f64,
1650    /// Rate at which approvals require revision (0.0 to 1.0)
1651    #[serde(default = "default_revision_rate")]
1652    pub revision_rate: f64,
1653    /// Average delay in hours for approval processing
1654    #[serde(default = "default_approval_delay_hours")]
1655    pub average_approval_delay_hours: f64,
1656    /// Approval chain thresholds
1657    #[serde(default)]
1658    pub thresholds: Vec<ApprovalThresholdConfig>,
1659}
1660
1661fn default_auto_approve_threshold() -> f64 {
1662    1000.0
1663}
1664fn default_rejection_rate() -> f64 {
1665    0.02
1666}
1667fn default_revision_rate() -> f64 {
1668    0.05
1669}
1670fn default_approval_delay_hours() -> f64 {
1671    4.0
1672}
1673
1674impl Default for ApprovalConfig {
1675    fn default() -> Self {
1676        Self {
1677            enabled: false,
1678            auto_approve_threshold: default_auto_approve_threshold(),
1679            rejection_rate: default_rejection_rate(),
1680            revision_rate: default_revision_rate(),
1681            average_approval_delay_hours: default_approval_delay_hours(),
1682            thresholds: vec![
1683                ApprovalThresholdConfig {
1684                    amount: 1000.0,
1685                    level: 1,
1686                    roles: vec!["senior_accountant".to_string()],
1687                },
1688                ApprovalThresholdConfig {
1689                    amount: 10000.0,
1690                    level: 2,
1691                    roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1692                },
1693                ApprovalThresholdConfig {
1694                    amount: 100000.0,
1695                    level: 3,
1696                    roles: vec![
1697                        "senior_accountant".to_string(),
1698                        "controller".to_string(),
1699                        "manager".to_string(),
1700                    ],
1701                },
1702                ApprovalThresholdConfig {
1703                    amount: 500000.0,
1704                    level: 4,
1705                    roles: vec![
1706                        "senior_accountant".to_string(),
1707                        "controller".to_string(),
1708                        "manager".to_string(),
1709                        "executive".to_string(),
1710                    ],
1711                },
1712            ],
1713        }
1714    }
1715}
1716
1717/// Configuration for a single approval threshold.
1718#[derive(Debug, Clone, Serialize, Deserialize)]
1719pub struct ApprovalThresholdConfig {
1720    /// Amount threshold
1721    pub amount: f64,
1722    /// Approval level required
1723    pub level: u8,
1724    /// Roles that can approve at this level
1725    pub roles: Vec<String>,
1726}
1727
1728/// Department configuration.
1729#[derive(Debug, Clone, Serialize, Deserialize)]
1730pub struct DepartmentConfig {
1731    /// Enable department assignment
1732    #[serde(default)]
1733    pub enabled: bool,
1734    /// Multiplier for department headcounts
1735    #[serde(default = "default_headcount_multiplier")]
1736    pub headcount_multiplier: f64,
1737    /// Custom department definitions (optional)
1738    #[serde(default)]
1739    pub custom_departments: Vec<CustomDepartmentConfig>,
1740}
1741
1742fn default_headcount_multiplier() -> f64 {
1743    1.0
1744}
1745
1746impl Default for DepartmentConfig {
1747    fn default() -> Self {
1748        Self {
1749            enabled: false,
1750            headcount_multiplier: default_headcount_multiplier(),
1751            custom_departments: Vec::new(),
1752        }
1753    }
1754}
1755
1756/// Custom department definition.
1757#[derive(Debug, Clone, Serialize, Deserialize)]
1758pub struct CustomDepartmentConfig {
1759    /// Department code
1760    pub code: String,
1761    /// Department name
1762    pub name: String,
1763    /// Associated cost center
1764    #[serde(default)]
1765    pub cost_center: Option<String>,
1766    /// Primary business processes
1767    #[serde(default)]
1768    pub primary_processes: Vec<String>,
1769    /// Parent department code
1770    #[serde(default)]
1771    pub parent_code: Option<String>,
1772}
1773
1774// ============================================================================
1775// Master Data Configuration
1776// ============================================================================
1777
1778/// Master data generation configuration.
1779#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1780pub struct MasterDataConfig {
1781    /// Vendor master data settings
1782    #[serde(default)]
1783    pub vendors: VendorMasterConfig,
1784    /// Customer master data settings
1785    #[serde(default)]
1786    pub customers: CustomerMasterConfig,
1787    /// Material master data settings
1788    #[serde(default)]
1789    pub materials: MaterialMasterConfig,
1790    /// Fixed asset master data settings
1791    #[serde(default)]
1792    pub fixed_assets: FixedAssetMasterConfig,
1793    /// Employee master data settings
1794    #[serde(default)]
1795    pub employees: EmployeeMasterConfig,
1796    /// Cost center master data settings
1797    #[serde(default)]
1798    pub cost_centers: CostCenterMasterConfig,
1799}
1800
1801/// Vendor master data configuration.
1802#[derive(Debug, Clone, Serialize, Deserialize)]
1803pub struct VendorMasterConfig {
1804    /// Number of vendors to generate
1805    #[serde(default = "default_vendor_count")]
1806    pub count: usize,
1807    /// Percentage of vendors that are intercompany (0.0 to 1.0)
1808    #[serde(default = "default_intercompany_percent")]
1809    pub intercompany_percent: f64,
1810    /// Payment terms distribution
1811    #[serde(default)]
1812    pub payment_terms_distribution: PaymentTermsDistribution,
1813    /// Vendor behavior distribution
1814    #[serde(default)]
1815    pub behavior_distribution: VendorBehaviorDistribution,
1816    /// Generate bank account details
1817    #[serde(default = "default_true")]
1818    pub generate_bank_accounts: bool,
1819    /// Generate tax IDs
1820    #[serde(default = "default_true")]
1821    pub generate_tax_ids: bool,
1822}
1823
1824fn default_vendor_count() -> usize {
1825    500
1826}
1827
1828fn default_intercompany_percent() -> f64 {
1829    0.05
1830}
1831
1832impl Default for VendorMasterConfig {
1833    fn default() -> Self {
1834        Self {
1835            count: default_vendor_count(),
1836            intercompany_percent: default_intercompany_percent(),
1837            payment_terms_distribution: PaymentTermsDistribution::default(),
1838            behavior_distribution: VendorBehaviorDistribution::default(),
1839            generate_bank_accounts: true,
1840            generate_tax_ids: true,
1841        }
1842    }
1843}
1844
1845/// Payment terms distribution for vendors.
1846#[derive(Debug, Clone, Serialize, Deserialize)]
1847pub struct PaymentTermsDistribution {
1848    /// Net 30 days
1849    pub net_30: f64,
1850    /// Net 60 days
1851    pub net_60: f64,
1852    /// Net 90 days
1853    pub net_90: f64,
1854    /// 2% 10 Net 30 (early payment discount)
1855    pub two_ten_net_30: f64,
1856    /// Due on receipt
1857    pub due_on_receipt: f64,
1858    /// End of month
1859    pub end_of_month: f64,
1860}
1861
1862impl Default for PaymentTermsDistribution {
1863    fn default() -> Self {
1864        Self {
1865            net_30: 0.40,
1866            net_60: 0.20,
1867            net_90: 0.10,
1868            two_ten_net_30: 0.15,
1869            due_on_receipt: 0.05,
1870            end_of_month: 0.10,
1871        }
1872    }
1873}
1874
1875/// Vendor behavior distribution.
1876#[derive(Debug, Clone, Serialize, Deserialize)]
1877pub struct VendorBehaviorDistribution {
1878    /// Reliable vendors (consistent delivery, quality)
1879    pub reliable: f64,
1880    /// Sometimes late vendors
1881    pub sometimes_late: f64,
1882    /// Inconsistent quality vendors
1883    pub inconsistent_quality: f64,
1884    /// Premium vendors (high quality, premium pricing)
1885    pub premium: f64,
1886    /// Budget vendors (lower quality, lower pricing)
1887    pub budget: f64,
1888}
1889
1890impl Default for VendorBehaviorDistribution {
1891    fn default() -> Self {
1892        Self {
1893            reliable: 0.50,
1894            sometimes_late: 0.20,
1895            inconsistent_quality: 0.10,
1896            premium: 0.10,
1897            budget: 0.10,
1898        }
1899    }
1900}
1901
1902/// Customer master data configuration.
1903#[derive(Debug, Clone, Serialize, Deserialize)]
1904pub struct CustomerMasterConfig {
1905    /// Number of customers to generate
1906    #[serde(default = "default_customer_count")]
1907    pub count: usize,
1908    /// Percentage of customers that are intercompany (0.0 to 1.0)
1909    #[serde(default = "default_intercompany_percent")]
1910    pub intercompany_percent: f64,
1911    /// Credit rating distribution
1912    #[serde(default)]
1913    pub credit_rating_distribution: CreditRatingDistribution,
1914    /// Payment behavior distribution
1915    #[serde(default)]
1916    pub payment_behavior_distribution: PaymentBehaviorDistribution,
1917    /// Generate credit limits based on rating
1918    #[serde(default = "default_true")]
1919    pub generate_credit_limits: bool,
1920}
1921
1922fn default_customer_count() -> usize {
1923    2000
1924}
1925
1926impl Default for CustomerMasterConfig {
1927    fn default() -> Self {
1928        Self {
1929            count: default_customer_count(),
1930            intercompany_percent: default_intercompany_percent(),
1931            credit_rating_distribution: CreditRatingDistribution::default(),
1932            payment_behavior_distribution: PaymentBehaviorDistribution::default(),
1933            generate_credit_limits: true,
1934        }
1935    }
1936}
1937
1938/// Credit rating distribution for customers.
1939#[derive(Debug, Clone, Serialize, Deserialize)]
1940pub struct CreditRatingDistribution {
1941    /// AAA rating
1942    pub aaa: f64,
1943    /// AA rating
1944    pub aa: f64,
1945    /// A rating
1946    pub a: f64,
1947    /// BBB rating
1948    pub bbb: f64,
1949    /// BB rating
1950    pub bb: f64,
1951    /// B rating
1952    pub b: f64,
1953    /// Below B rating
1954    pub below_b: f64,
1955}
1956
1957impl Default for CreditRatingDistribution {
1958    fn default() -> Self {
1959        Self {
1960            aaa: 0.05,
1961            aa: 0.10,
1962            a: 0.20,
1963            bbb: 0.30,
1964            bb: 0.20,
1965            b: 0.10,
1966            below_b: 0.05,
1967        }
1968    }
1969}
1970
1971/// Payment behavior distribution for customers.
1972#[derive(Debug, Clone, Serialize, Deserialize)]
1973pub struct PaymentBehaviorDistribution {
1974    /// Always pays early
1975    pub early_payer: f64,
1976    /// Pays on time
1977    pub on_time: f64,
1978    /// Occasionally late
1979    pub occasional_late: f64,
1980    /// Frequently late
1981    pub frequent_late: f64,
1982    /// Takes early payment discounts
1983    pub discount_taker: f64,
1984}
1985
1986impl Default for PaymentBehaviorDistribution {
1987    fn default() -> Self {
1988        Self {
1989            early_payer: 0.10,
1990            on_time: 0.50,
1991            occasional_late: 0.25,
1992            frequent_late: 0.10,
1993            discount_taker: 0.05,
1994        }
1995    }
1996}
1997
1998/// Material master data configuration.
1999#[derive(Debug, Clone, Serialize, Deserialize)]
2000pub struct MaterialMasterConfig {
2001    /// Number of materials to generate
2002    #[serde(default = "default_material_count")]
2003    pub count: usize,
2004    /// Material type distribution
2005    #[serde(default)]
2006    pub type_distribution: MaterialTypeDistribution,
2007    /// Valuation method distribution
2008    #[serde(default)]
2009    pub valuation_distribution: ValuationMethodDistribution,
2010    /// Percentage of materials with BOM (bill of materials)
2011    #[serde(default = "default_bom_percent")]
2012    pub bom_percent: f64,
2013    /// Maximum BOM depth
2014    #[serde(default = "default_max_bom_depth")]
2015    pub max_bom_depth: u8,
2016}
2017
2018fn default_material_count() -> usize {
2019    5000
2020}
2021
2022fn default_bom_percent() -> f64 {
2023    0.20
2024}
2025
2026fn default_max_bom_depth() -> u8 {
2027    3
2028}
2029
2030impl Default for MaterialMasterConfig {
2031    fn default() -> Self {
2032        Self {
2033            count: default_material_count(),
2034            type_distribution: MaterialTypeDistribution::default(),
2035            valuation_distribution: ValuationMethodDistribution::default(),
2036            bom_percent: default_bom_percent(),
2037            max_bom_depth: default_max_bom_depth(),
2038        }
2039    }
2040}
2041
2042/// Material type distribution.
2043#[derive(Debug, Clone, Serialize, Deserialize)]
2044pub struct MaterialTypeDistribution {
2045    /// Raw materials
2046    pub raw_material: f64,
2047    /// Semi-finished goods
2048    pub semi_finished: f64,
2049    /// Finished goods
2050    pub finished_good: f64,
2051    /// Trading goods (purchased for resale)
2052    pub trading_good: f64,
2053    /// Operating supplies
2054    pub operating_supply: f64,
2055    /// Services
2056    pub service: f64,
2057}
2058
2059impl Default for MaterialTypeDistribution {
2060    fn default() -> Self {
2061        Self {
2062            raw_material: 0.30,
2063            semi_finished: 0.15,
2064            finished_good: 0.25,
2065            trading_good: 0.15,
2066            operating_supply: 0.10,
2067            service: 0.05,
2068        }
2069    }
2070}
2071
2072/// Valuation method distribution for materials.
2073#[derive(Debug, Clone, Serialize, Deserialize)]
2074pub struct ValuationMethodDistribution {
2075    /// Standard cost
2076    pub standard_cost: f64,
2077    /// Moving average
2078    pub moving_average: f64,
2079    /// FIFO (First In, First Out)
2080    pub fifo: f64,
2081    /// LIFO (Last In, First Out)
2082    pub lifo: f64,
2083}
2084
2085impl Default for ValuationMethodDistribution {
2086    fn default() -> Self {
2087        Self {
2088            standard_cost: 0.50,
2089            moving_average: 0.30,
2090            fifo: 0.15,
2091            lifo: 0.05,
2092        }
2093    }
2094}
2095
2096/// Fixed asset master data configuration.
2097#[derive(Debug, Clone, Serialize, Deserialize)]
2098pub struct FixedAssetMasterConfig {
2099    /// Number of fixed assets to generate
2100    #[serde(default = "default_asset_count")]
2101    pub count: usize,
2102    /// Asset class distribution
2103    #[serde(default)]
2104    pub class_distribution: AssetClassDistribution,
2105    /// Depreciation method distribution
2106    #[serde(default)]
2107    pub depreciation_distribution: DepreciationMethodDistribution,
2108    /// Percentage of assets that are fully depreciated
2109    #[serde(default = "default_fully_depreciated_percent")]
2110    pub fully_depreciated_percent: f64,
2111    /// Generate acquisition history
2112    #[serde(default = "default_true")]
2113    pub generate_acquisition_history: bool,
2114}
2115
2116fn default_asset_count() -> usize {
2117    800
2118}
2119
2120fn default_fully_depreciated_percent() -> f64 {
2121    0.15
2122}
2123
2124impl Default for FixedAssetMasterConfig {
2125    fn default() -> Self {
2126        Self {
2127            count: default_asset_count(),
2128            class_distribution: AssetClassDistribution::default(),
2129            depreciation_distribution: DepreciationMethodDistribution::default(),
2130            fully_depreciated_percent: default_fully_depreciated_percent(),
2131            generate_acquisition_history: true,
2132        }
2133    }
2134}
2135
2136/// Asset class distribution.
2137#[derive(Debug, Clone, Serialize, Deserialize)]
2138pub struct AssetClassDistribution {
2139    /// Buildings and structures
2140    pub buildings: f64,
2141    /// Machinery and equipment
2142    pub machinery: f64,
2143    /// Vehicles
2144    pub vehicles: f64,
2145    /// IT equipment
2146    pub it_equipment: f64,
2147    /// Furniture and fixtures
2148    pub furniture: f64,
2149    /// Land (non-depreciable)
2150    pub land: f64,
2151    /// Leasehold improvements
2152    pub leasehold: f64,
2153}
2154
2155impl Default for AssetClassDistribution {
2156    fn default() -> Self {
2157        Self {
2158            buildings: 0.15,
2159            machinery: 0.30,
2160            vehicles: 0.15,
2161            it_equipment: 0.20,
2162            furniture: 0.10,
2163            land: 0.05,
2164            leasehold: 0.05,
2165        }
2166    }
2167}
2168
2169/// Depreciation method distribution.
2170#[derive(Debug, Clone, Serialize, Deserialize)]
2171pub struct DepreciationMethodDistribution {
2172    /// Straight line
2173    pub straight_line: f64,
2174    /// Declining balance
2175    pub declining_balance: f64,
2176    /// Double declining balance
2177    pub double_declining: f64,
2178    /// Sum of years' digits
2179    pub sum_of_years: f64,
2180    /// Units of production
2181    pub units_of_production: f64,
2182}
2183
2184impl Default for DepreciationMethodDistribution {
2185    fn default() -> Self {
2186        Self {
2187            straight_line: 0.60,
2188            declining_balance: 0.20,
2189            double_declining: 0.10,
2190            sum_of_years: 0.05,
2191            units_of_production: 0.05,
2192        }
2193    }
2194}
2195
2196/// Employee master data configuration.
2197#[derive(Debug, Clone, Serialize, Deserialize)]
2198pub struct EmployeeMasterConfig {
2199    /// Number of employees to generate
2200    #[serde(default = "default_employee_count")]
2201    pub count: usize,
2202    /// Generate organizational hierarchy
2203    #[serde(default = "default_true")]
2204    pub generate_hierarchy: bool,
2205    /// Maximum hierarchy depth
2206    #[serde(default = "default_hierarchy_depth")]
2207    pub max_hierarchy_depth: u8,
2208    /// Average span of control (direct reports per manager)
2209    #[serde(default = "default_span_of_control")]
2210    pub average_span_of_control: f64,
2211    /// Approval limit distribution by job level
2212    #[serde(default)]
2213    pub approval_limits: ApprovalLimitDistribution,
2214    /// Department distribution
2215    #[serde(default)]
2216    pub department_distribution: EmployeeDepartmentDistribution,
2217}
2218
2219fn default_employee_count() -> usize {
2220    1500
2221}
2222
2223fn default_hierarchy_depth() -> u8 {
2224    6
2225}
2226
2227fn default_span_of_control() -> f64 {
2228    5.0
2229}
2230
2231impl Default for EmployeeMasterConfig {
2232    fn default() -> Self {
2233        Self {
2234            count: default_employee_count(),
2235            generate_hierarchy: true,
2236            max_hierarchy_depth: default_hierarchy_depth(),
2237            average_span_of_control: default_span_of_control(),
2238            approval_limits: ApprovalLimitDistribution::default(),
2239            department_distribution: EmployeeDepartmentDistribution::default(),
2240        }
2241    }
2242}
2243
2244/// Approval limit distribution by job level.
2245#[derive(Debug, Clone, Serialize, Deserialize)]
2246pub struct ApprovalLimitDistribution {
2247    /// Staff level approval limit
2248    #[serde(default = "default_staff_limit")]
2249    pub staff: f64,
2250    /// Senior staff approval limit
2251    #[serde(default = "default_senior_limit")]
2252    pub senior: f64,
2253    /// Manager approval limit
2254    #[serde(default = "default_manager_limit")]
2255    pub manager: f64,
2256    /// Director approval limit
2257    #[serde(default = "default_director_limit")]
2258    pub director: f64,
2259    /// VP approval limit
2260    #[serde(default = "default_vp_limit")]
2261    pub vp: f64,
2262    /// Executive approval limit
2263    #[serde(default = "default_executive_limit")]
2264    pub executive: f64,
2265}
2266
2267fn default_staff_limit() -> f64 {
2268    1000.0
2269}
2270fn default_senior_limit() -> f64 {
2271    5000.0
2272}
2273fn default_manager_limit() -> f64 {
2274    25000.0
2275}
2276fn default_director_limit() -> f64 {
2277    100000.0
2278}
2279fn default_vp_limit() -> f64 {
2280    500000.0
2281}
2282fn default_executive_limit() -> f64 {
2283    f64::INFINITY
2284}
2285
2286impl Default for ApprovalLimitDistribution {
2287    fn default() -> Self {
2288        Self {
2289            staff: default_staff_limit(),
2290            senior: default_senior_limit(),
2291            manager: default_manager_limit(),
2292            director: default_director_limit(),
2293            vp: default_vp_limit(),
2294            executive: default_executive_limit(),
2295        }
2296    }
2297}
2298
2299/// Employee distribution across departments.
2300#[derive(Debug, Clone, Serialize, Deserialize)]
2301pub struct EmployeeDepartmentDistribution {
2302    /// Finance and Accounting
2303    pub finance: f64,
2304    /// Procurement
2305    pub procurement: f64,
2306    /// Sales
2307    pub sales: f64,
2308    /// Warehouse and Logistics
2309    pub warehouse: f64,
2310    /// IT
2311    pub it: f64,
2312    /// Human Resources
2313    pub hr: f64,
2314    /// Operations
2315    pub operations: f64,
2316    /// Executive
2317    pub executive: f64,
2318}
2319
2320impl Default for EmployeeDepartmentDistribution {
2321    fn default() -> Self {
2322        Self {
2323            finance: 0.12,
2324            procurement: 0.10,
2325            sales: 0.25,
2326            warehouse: 0.15,
2327            it: 0.10,
2328            hr: 0.05,
2329            operations: 0.20,
2330            executive: 0.03,
2331        }
2332    }
2333}
2334
2335/// Cost center master data configuration.
2336#[derive(Debug, Clone, Serialize, Deserialize)]
2337pub struct CostCenterMasterConfig {
2338    /// Number of cost centers to generate
2339    #[serde(default = "default_cost_center_count")]
2340    pub count: usize,
2341    /// Generate cost center hierarchy
2342    #[serde(default = "default_true")]
2343    pub generate_hierarchy: bool,
2344    /// Maximum hierarchy depth
2345    #[serde(default = "default_cc_hierarchy_depth")]
2346    pub max_hierarchy_depth: u8,
2347}
2348
2349fn default_cost_center_count() -> usize {
2350    50
2351}
2352
2353fn default_cc_hierarchy_depth() -> u8 {
2354    3
2355}
2356
2357impl Default for CostCenterMasterConfig {
2358    fn default() -> Self {
2359        Self {
2360            count: default_cost_center_count(),
2361            generate_hierarchy: true,
2362            max_hierarchy_depth: default_cc_hierarchy_depth(),
2363        }
2364    }
2365}
2366
2367// ============================================================================
2368// Document Flow Configuration
2369// ============================================================================
2370
2371/// Document flow generation configuration.
2372#[derive(Debug, Clone, Serialize, Deserialize)]
2373pub struct DocumentFlowConfig {
2374    /// P2P (Procure-to-Pay) flow configuration
2375    #[serde(default)]
2376    pub p2p: P2PFlowConfig,
2377    /// O2C (Order-to-Cash) flow configuration
2378    #[serde(default)]
2379    pub o2c: O2CFlowConfig,
2380    /// Generate document reference chains
2381    #[serde(default = "default_true")]
2382    pub generate_document_references: bool,
2383    /// Export document flow graph
2384    #[serde(default)]
2385    pub export_flow_graph: bool,
2386}
2387
2388impl Default for DocumentFlowConfig {
2389    fn default() -> Self {
2390        Self {
2391            p2p: P2PFlowConfig::default(),
2392            o2c: O2CFlowConfig::default(),
2393            generate_document_references: true,
2394            export_flow_graph: false,
2395        }
2396    }
2397}
2398
2399/// P2P (Procure-to-Pay) flow configuration.
2400#[derive(Debug, Clone, Serialize, Deserialize)]
2401pub struct P2PFlowConfig {
2402    /// Enable P2P document flow generation
2403    #[serde(default = "default_true")]
2404    pub enabled: bool,
2405    /// Three-way match success rate (PO-GR-Invoice)
2406    #[serde(default = "default_three_way_match_rate")]
2407    pub three_way_match_rate: f64,
2408    /// Rate of partial deliveries
2409    #[serde(default = "default_partial_delivery_rate")]
2410    pub partial_delivery_rate: f64,
2411    /// Rate of price variances between PO and Invoice
2412    #[serde(default = "default_price_variance_rate")]
2413    pub price_variance_rate: f64,
2414    /// Maximum price variance percentage
2415    #[serde(default = "default_max_price_variance")]
2416    pub max_price_variance_percent: f64,
2417    /// Rate of quantity variances between PO/GR and Invoice
2418    #[serde(default = "default_quantity_variance_rate")]
2419    pub quantity_variance_rate: f64,
2420    /// Average days from PO to goods receipt
2421    #[serde(default = "default_po_to_gr_days")]
2422    pub average_po_to_gr_days: u32,
2423    /// Average days from GR to invoice
2424    #[serde(default = "default_gr_to_invoice_days")]
2425    pub average_gr_to_invoice_days: u32,
2426    /// Average days from invoice to payment
2427    #[serde(default = "default_invoice_to_payment_days")]
2428    pub average_invoice_to_payment_days: u32,
2429    /// PO line count distribution
2430    #[serde(default)]
2431    pub line_count_distribution: DocumentLineCountDistribution,
2432    /// Payment behavior configuration
2433    #[serde(default)]
2434    pub payment_behavior: P2PPaymentBehaviorConfig,
2435}
2436
2437fn default_three_way_match_rate() -> f64 {
2438    0.95
2439}
2440
2441fn default_partial_delivery_rate() -> f64 {
2442    0.15
2443}
2444
2445fn default_price_variance_rate() -> f64 {
2446    0.08
2447}
2448
2449fn default_max_price_variance() -> f64 {
2450    0.05
2451}
2452
2453fn default_quantity_variance_rate() -> f64 {
2454    0.05
2455}
2456
2457fn default_po_to_gr_days() -> u32 {
2458    14
2459}
2460
2461fn default_gr_to_invoice_days() -> u32 {
2462    5
2463}
2464
2465fn default_invoice_to_payment_days() -> u32 {
2466    30
2467}
2468
2469impl Default for P2PFlowConfig {
2470    fn default() -> Self {
2471        Self {
2472            enabled: true,
2473            three_way_match_rate: default_three_way_match_rate(),
2474            partial_delivery_rate: default_partial_delivery_rate(),
2475            price_variance_rate: default_price_variance_rate(),
2476            max_price_variance_percent: default_max_price_variance(),
2477            quantity_variance_rate: default_quantity_variance_rate(),
2478            average_po_to_gr_days: default_po_to_gr_days(),
2479            average_gr_to_invoice_days: default_gr_to_invoice_days(),
2480            average_invoice_to_payment_days: default_invoice_to_payment_days(),
2481            line_count_distribution: DocumentLineCountDistribution::default(),
2482            payment_behavior: P2PPaymentBehaviorConfig::default(),
2483        }
2484    }
2485}
2486
2487// ============================================================================
2488// P2P Payment Behavior Configuration
2489// ============================================================================
2490
2491/// P2P payment behavior configuration.
2492#[derive(Debug, Clone, Serialize, Deserialize)]
2493pub struct P2PPaymentBehaviorConfig {
2494    /// Rate of late payments (beyond due date)
2495    #[serde(default = "default_p2p_late_payment_rate")]
2496    pub late_payment_rate: f64,
2497    /// Distribution of late payment days
2498    #[serde(default)]
2499    pub late_payment_days_distribution: LatePaymentDaysDistribution,
2500    /// Rate of partial payments
2501    #[serde(default = "default_p2p_partial_payment_rate")]
2502    pub partial_payment_rate: f64,
2503    /// Rate of payment corrections (NSF, chargebacks, reversals)
2504    #[serde(default = "default_p2p_payment_correction_rate")]
2505    pub payment_correction_rate: f64,
2506}
2507
2508fn default_p2p_late_payment_rate() -> f64 {
2509    0.15
2510}
2511
2512fn default_p2p_partial_payment_rate() -> f64 {
2513    0.05
2514}
2515
2516fn default_p2p_payment_correction_rate() -> f64 {
2517    0.02
2518}
2519
2520impl Default for P2PPaymentBehaviorConfig {
2521    fn default() -> Self {
2522        Self {
2523            late_payment_rate: default_p2p_late_payment_rate(),
2524            late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2525            partial_payment_rate: default_p2p_partial_payment_rate(),
2526            payment_correction_rate: default_p2p_payment_correction_rate(),
2527        }
2528    }
2529}
2530
2531/// Distribution of late payment days for P2P.
2532#[derive(Debug, Clone, Serialize, Deserialize)]
2533pub struct LatePaymentDaysDistribution {
2534    /// 1-7 days late (slightly late)
2535    #[serde(default = "default_slightly_late")]
2536    pub slightly_late_1_to_7: f64,
2537    /// 8-14 days late
2538    #[serde(default = "default_late_8_14")]
2539    pub late_8_to_14: f64,
2540    /// 15-30 days late (very late)
2541    #[serde(default = "default_very_late")]
2542    pub very_late_15_to_30: f64,
2543    /// 31-60 days late (severely late)
2544    #[serde(default = "default_severely_late")]
2545    pub severely_late_31_to_60: f64,
2546    /// Over 60 days late (extremely late)
2547    #[serde(default = "default_extremely_late")]
2548    pub extremely_late_over_60: f64,
2549}
2550
2551fn default_slightly_late() -> f64 {
2552    0.50
2553}
2554
2555fn default_late_8_14() -> f64 {
2556    0.25
2557}
2558
2559fn default_very_late() -> f64 {
2560    0.15
2561}
2562
2563fn default_severely_late() -> f64 {
2564    0.07
2565}
2566
2567fn default_extremely_late() -> f64 {
2568    0.03
2569}
2570
2571impl Default for LatePaymentDaysDistribution {
2572    fn default() -> Self {
2573        Self {
2574            slightly_late_1_to_7: default_slightly_late(),
2575            late_8_to_14: default_late_8_14(),
2576            very_late_15_to_30: default_very_late(),
2577            severely_late_31_to_60: default_severely_late(),
2578            extremely_late_over_60: default_extremely_late(),
2579        }
2580    }
2581}
2582
2583/// O2C (Order-to-Cash) flow configuration.
2584#[derive(Debug, Clone, Serialize, Deserialize)]
2585pub struct O2CFlowConfig {
2586    /// Enable O2C document flow generation
2587    #[serde(default = "default_true")]
2588    pub enabled: bool,
2589    /// Credit check failure rate
2590    #[serde(default = "default_credit_check_failure_rate")]
2591    pub credit_check_failure_rate: f64,
2592    /// Rate of partial shipments
2593    #[serde(default = "default_partial_shipment_rate")]
2594    pub partial_shipment_rate: f64,
2595    /// Rate of returns
2596    #[serde(default = "default_return_rate")]
2597    pub return_rate: f64,
2598    /// Bad debt write-off rate
2599    #[serde(default = "default_bad_debt_rate")]
2600    pub bad_debt_rate: f64,
2601    /// Average days from SO to delivery
2602    #[serde(default = "default_so_to_delivery_days")]
2603    pub average_so_to_delivery_days: u32,
2604    /// Average days from delivery to invoice
2605    #[serde(default = "default_delivery_to_invoice_days")]
2606    pub average_delivery_to_invoice_days: u32,
2607    /// Average days from invoice to receipt
2608    #[serde(default = "default_invoice_to_receipt_days")]
2609    pub average_invoice_to_receipt_days: u32,
2610    /// SO line count distribution
2611    #[serde(default)]
2612    pub line_count_distribution: DocumentLineCountDistribution,
2613    /// Cash discount configuration
2614    #[serde(default)]
2615    pub cash_discount: CashDiscountConfig,
2616    /// Payment behavior configuration
2617    #[serde(default)]
2618    pub payment_behavior: O2CPaymentBehaviorConfig,
2619}
2620
2621fn default_credit_check_failure_rate() -> f64 {
2622    0.02
2623}
2624
2625fn default_partial_shipment_rate() -> f64 {
2626    0.10
2627}
2628
2629fn default_return_rate() -> f64 {
2630    0.03
2631}
2632
2633fn default_bad_debt_rate() -> f64 {
2634    0.01
2635}
2636
2637fn default_so_to_delivery_days() -> u32 {
2638    7
2639}
2640
2641fn default_delivery_to_invoice_days() -> u32 {
2642    1
2643}
2644
2645fn default_invoice_to_receipt_days() -> u32 {
2646    45
2647}
2648
2649impl Default for O2CFlowConfig {
2650    fn default() -> Self {
2651        Self {
2652            enabled: true,
2653            credit_check_failure_rate: default_credit_check_failure_rate(),
2654            partial_shipment_rate: default_partial_shipment_rate(),
2655            return_rate: default_return_rate(),
2656            bad_debt_rate: default_bad_debt_rate(),
2657            average_so_to_delivery_days: default_so_to_delivery_days(),
2658            average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2659            average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2660            line_count_distribution: DocumentLineCountDistribution::default(),
2661            cash_discount: CashDiscountConfig::default(),
2662            payment_behavior: O2CPaymentBehaviorConfig::default(),
2663        }
2664    }
2665}
2666
2667// ============================================================================
2668// O2C Payment Behavior Configuration
2669// ============================================================================
2670
2671/// O2C payment behavior configuration.
2672#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2673pub struct O2CPaymentBehaviorConfig {
2674    /// Dunning (Mahnung) configuration
2675    #[serde(default)]
2676    pub dunning: DunningConfig,
2677    /// Partial payment configuration
2678    #[serde(default)]
2679    pub partial_payments: PartialPaymentConfig,
2680    /// Short payment configuration (unauthorized deductions)
2681    #[serde(default)]
2682    pub short_payments: ShortPaymentConfig,
2683    /// On-account payment configuration (unapplied payments)
2684    #[serde(default)]
2685    pub on_account_payments: OnAccountPaymentConfig,
2686    /// Payment correction configuration (NSF, chargebacks)
2687    #[serde(default)]
2688    pub payment_corrections: PaymentCorrectionConfig,
2689}
2690
2691/// Dunning (Mahnungen) configuration for AR collections.
2692#[derive(Debug, Clone, Serialize, Deserialize)]
2693pub struct DunningConfig {
2694    /// Enable dunning process
2695    #[serde(default)]
2696    pub enabled: bool,
2697    /// Days overdue for level 1 dunning (1st reminder)
2698    #[serde(default = "default_dunning_level_1_days")]
2699    pub level_1_days_overdue: u32,
2700    /// Days overdue for level 2 dunning (2nd reminder)
2701    #[serde(default = "default_dunning_level_2_days")]
2702    pub level_2_days_overdue: u32,
2703    /// Days overdue for level 3 dunning (final notice)
2704    #[serde(default = "default_dunning_level_3_days")]
2705    pub level_3_days_overdue: u32,
2706    /// Days overdue for collection handover
2707    #[serde(default = "default_collection_days")]
2708    pub collection_days_overdue: u32,
2709    /// Payment rates after each dunning level
2710    #[serde(default)]
2711    pub payment_after_dunning_rates: DunningPaymentRates,
2712    /// Rate of invoices blocked from dunning (disputes)
2713    #[serde(default = "default_dunning_block_rate")]
2714    pub dunning_block_rate: f64,
2715    /// Interest rate per year for overdue amounts
2716    #[serde(default = "default_dunning_interest_rate")]
2717    pub interest_rate_per_year: f64,
2718    /// Fixed dunning charge per letter
2719    #[serde(default = "default_dunning_charge")]
2720    pub dunning_charge: f64,
2721}
2722
2723fn default_dunning_level_1_days() -> u32 {
2724    14
2725}
2726
2727fn default_dunning_level_2_days() -> u32 {
2728    28
2729}
2730
2731fn default_dunning_level_3_days() -> u32 {
2732    42
2733}
2734
2735fn default_collection_days() -> u32 {
2736    60
2737}
2738
2739fn default_dunning_block_rate() -> f64 {
2740    0.05
2741}
2742
2743fn default_dunning_interest_rate() -> f64 {
2744    0.09
2745}
2746
2747fn default_dunning_charge() -> f64 {
2748    25.0
2749}
2750
2751impl Default for DunningConfig {
2752    fn default() -> Self {
2753        Self {
2754            enabled: false,
2755            level_1_days_overdue: default_dunning_level_1_days(),
2756            level_2_days_overdue: default_dunning_level_2_days(),
2757            level_3_days_overdue: default_dunning_level_3_days(),
2758            collection_days_overdue: default_collection_days(),
2759            payment_after_dunning_rates: DunningPaymentRates::default(),
2760            dunning_block_rate: default_dunning_block_rate(),
2761            interest_rate_per_year: default_dunning_interest_rate(),
2762            dunning_charge: default_dunning_charge(),
2763        }
2764    }
2765}
2766
2767/// Payment rates after each dunning level.
2768#[derive(Debug, Clone, Serialize, Deserialize)]
2769pub struct DunningPaymentRates {
2770    /// Rate that pays after level 1 reminder
2771    #[serde(default = "default_after_level_1")]
2772    pub after_level_1: f64,
2773    /// Rate that pays after level 2 reminder
2774    #[serde(default = "default_after_level_2")]
2775    pub after_level_2: f64,
2776    /// Rate that pays after level 3 final notice
2777    #[serde(default = "default_after_level_3")]
2778    pub after_level_3: f64,
2779    /// Rate that pays during collection
2780    #[serde(default = "default_during_collection")]
2781    pub during_collection: f64,
2782    /// Rate that never pays (becomes bad debt)
2783    #[serde(default = "default_never_pay")]
2784    pub never_pay: f64,
2785}
2786
2787fn default_after_level_1() -> f64 {
2788    0.40
2789}
2790
2791fn default_after_level_2() -> f64 {
2792    0.30
2793}
2794
2795fn default_after_level_3() -> f64 {
2796    0.15
2797}
2798
2799fn default_during_collection() -> f64 {
2800    0.05
2801}
2802
2803fn default_never_pay() -> f64 {
2804    0.10
2805}
2806
2807impl Default for DunningPaymentRates {
2808    fn default() -> Self {
2809        Self {
2810            after_level_1: default_after_level_1(),
2811            after_level_2: default_after_level_2(),
2812            after_level_3: default_after_level_3(),
2813            during_collection: default_during_collection(),
2814            never_pay: default_never_pay(),
2815        }
2816    }
2817}
2818
2819/// Partial payment configuration.
2820#[derive(Debug, Clone, Serialize, Deserialize)]
2821pub struct PartialPaymentConfig {
2822    /// Rate of invoices paid partially
2823    #[serde(default = "default_partial_payment_rate")]
2824    pub rate: f64,
2825    /// Distribution of partial payment percentages
2826    #[serde(default)]
2827    pub percentage_distribution: PartialPaymentPercentageDistribution,
2828    /// Average days until remainder is paid
2829    #[serde(default = "default_avg_days_until_remainder")]
2830    pub avg_days_until_remainder: u32,
2831}
2832
2833fn default_partial_payment_rate() -> f64 {
2834    0.08
2835}
2836
2837fn default_avg_days_until_remainder() -> u32 {
2838    30
2839}
2840
2841impl Default for PartialPaymentConfig {
2842    fn default() -> Self {
2843        Self {
2844            rate: default_partial_payment_rate(),
2845            percentage_distribution: PartialPaymentPercentageDistribution::default(),
2846            avg_days_until_remainder: default_avg_days_until_remainder(),
2847        }
2848    }
2849}
2850
2851/// Distribution of partial payment percentages.
2852#[derive(Debug, Clone, Serialize, Deserialize)]
2853pub struct PartialPaymentPercentageDistribution {
2854    /// Pay 25% of invoice
2855    #[serde(default = "default_partial_25")]
2856    pub pay_25_percent: f64,
2857    /// Pay 50% of invoice
2858    #[serde(default = "default_partial_50")]
2859    pub pay_50_percent: f64,
2860    /// Pay 75% of invoice
2861    #[serde(default = "default_partial_75")]
2862    pub pay_75_percent: f64,
2863    /// Pay random percentage
2864    #[serde(default = "default_partial_random")]
2865    pub pay_random_percent: f64,
2866}
2867
2868fn default_partial_25() -> f64 {
2869    0.15
2870}
2871
2872fn default_partial_50() -> f64 {
2873    0.50
2874}
2875
2876fn default_partial_75() -> f64 {
2877    0.25
2878}
2879
2880fn default_partial_random() -> f64 {
2881    0.10
2882}
2883
2884impl Default for PartialPaymentPercentageDistribution {
2885    fn default() -> Self {
2886        Self {
2887            pay_25_percent: default_partial_25(),
2888            pay_50_percent: default_partial_50(),
2889            pay_75_percent: default_partial_75(),
2890            pay_random_percent: default_partial_random(),
2891        }
2892    }
2893}
2894
2895/// Short payment configuration (unauthorized deductions).
2896#[derive(Debug, Clone, Serialize, Deserialize)]
2897pub struct ShortPaymentConfig {
2898    /// Rate of payments that are short
2899    #[serde(default = "default_short_payment_rate")]
2900    pub rate: f64,
2901    /// Distribution of short payment reasons
2902    #[serde(default)]
2903    pub reason_distribution: ShortPaymentReasonDistribution,
2904    /// Maximum percentage that can be short
2905    #[serde(default = "default_max_short_percent")]
2906    pub max_short_percent: f64,
2907}
2908
2909fn default_short_payment_rate() -> f64 {
2910    0.03
2911}
2912
2913fn default_max_short_percent() -> f64 {
2914    0.10
2915}
2916
2917impl Default for ShortPaymentConfig {
2918    fn default() -> Self {
2919        Self {
2920            rate: default_short_payment_rate(),
2921            reason_distribution: ShortPaymentReasonDistribution::default(),
2922            max_short_percent: default_max_short_percent(),
2923        }
2924    }
2925}
2926
2927/// Distribution of short payment reasons.
2928#[derive(Debug, Clone, Serialize, Deserialize)]
2929pub struct ShortPaymentReasonDistribution {
2930    /// Pricing dispute
2931    #[serde(default = "default_pricing_dispute")]
2932    pub pricing_dispute: f64,
2933    /// Quality issue
2934    #[serde(default = "default_quality_issue")]
2935    pub quality_issue: f64,
2936    /// Quantity discrepancy
2937    #[serde(default = "default_quantity_discrepancy")]
2938    pub quantity_discrepancy: f64,
2939    /// Unauthorized deduction
2940    #[serde(default = "default_unauthorized_deduction")]
2941    pub unauthorized_deduction: f64,
2942    /// Early payment discount taken incorrectly
2943    #[serde(default = "default_incorrect_discount")]
2944    pub incorrect_discount: f64,
2945}
2946
2947fn default_pricing_dispute() -> f64 {
2948    0.30
2949}
2950
2951fn default_quality_issue() -> f64 {
2952    0.20
2953}
2954
2955fn default_quantity_discrepancy() -> f64 {
2956    0.20
2957}
2958
2959fn default_unauthorized_deduction() -> f64 {
2960    0.15
2961}
2962
2963fn default_incorrect_discount() -> f64 {
2964    0.15
2965}
2966
2967impl Default for ShortPaymentReasonDistribution {
2968    fn default() -> Self {
2969        Self {
2970            pricing_dispute: default_pricing_dispute(),
2971            quality_issue: default_quality_issue(),
2972            quantity_discrepancy: default_quantity_discrepancy(),
2973            unauthorized_deduction: default_unauthorized_deduction(),
2974            incorrect_discount: default_incorrect_discount(),
2975        }
2976    }
2977}
2978
2979/// On-account payment configuration (unapplied payments).
2980#[derive(Debug, Clone, Serialize, Deserialize)]
2981pub struct OnAccountPaymentConfig {
2982    /// Rate of payments that are on-account (unapplied)
2983    #[serde(default = "default_on_account_rate")]
2984    pub rate: f64,
2985    /// Average days until on-account payments are applied
2986    #[serde(default = "default_avg_days_until_applied")]
2987    pub avg_days_until_applied: u32,
2988}
2989
2990fn default_on_account_rate() -> f64 {
2991    0.02
2992}
2993
2994fn default_avg_days_until_applied() -> u32 {
2995    14
2996}
2997
2998impl Default for OnAccountPaymentConfig {
2999    fn default() -> Self {
3000        Self {
3001            rate: default_on_account_rate(),
3002            avg_days_until_applied: default_avg_days_until_applied(),
3003        }
3004    }
3005}
3006
3007/// Payment correction configuration.
3008#[derive(Debug, Clone, Serialize, Deserialize)]
3009pub struct PaymentCorrectionConfig {
3010    /// Rate of payments requiring correction
3011    #[serde(default = "default_payment_correction_rate")]
3012    pub rate: f64,
3013    /// Distribution of correction types
3014    #[serde(default)]
3015    pub type_distribution: PaymentCorrectionTypeDistribution,
3016}
3017
3018fn default_payment_correction_rate() -> f64 {
3019    0.02
3020}
3021
3022impl Default for PaymentCorrectionConfig {
3023    fn default() -> Self {
3024        Self {
3025            rate: default_payment_correction_rate(),
3026            type_distribution: PaymentCorrectionTypeDistribution::default(),
3027        }
3028    }
3029}
3030
3031/// Distribution of payment correction types.
3032#[derive(Debug, Clone, Serialize, Deserialize)]
3033pub struct PaymentCorrectionTypeDistribution {
3034    /// NSF (Non-sufficient funds) / bounced check
3035    #[serde(default = "default_nsf_rate")]
3036    pub nsf: f64,
3037    /// Chargeback
3038    #[serde(default = "default_chargeback_rate")]
3039    pub chargeback: f64,
3040    /// Wrong amount applied
3041    #[serde(default = "default_wrong_amount_rate")]
3042    pub wrong_amount: f64,
3043    /// Wrong customer applied
3044    #[serde(default = "default_wrong_customer_rate")]
3045    pub wrong_customer: f64,
3046    /// Duplicate payment
3047    #[serde(default = "default_duplicate_payment_rate")]
3048    pub duplicate_payment: f64,
3049}
3050
3051fn default_nsf_rate() -> f64 {
3052    0.30
3053}
3054
3055fn default_chargeback_rate() -> f64 {
3056    0.20
3057}
3058
3059fn default_wrong_amount_rate() -> f64 {
3060    0.20
3061}
3062
3063fn default_wrong_customer_rate() -> f64 {
3064    0.15
3065}
3066
3067fn default_duplicate_payment_rate() -> f64 {
3068    0.15
3069}
3070
3071impl Default for PaymentCorrectionTypeDistribution {
3072    fn default() -> Self {
3073        Self {
3074            nsf: default_nsf_rate(),
3075            chargeback: default_chargeback_rate(),
3076            wrong_amount: default_wrong_amount_rate(),
3077            wrong_customer: default_wrong_customer_rate(),
3078            duplicate_payment: default_duplicate_payment_rate(),
3079        }
3080    }
3081}
3082
3083/// Document line count distribution.
3084#[derive(Debug, Clone, Serialize, Deserialize)]
3085pub struct DocumentLineCountDistribution {
3086    /// Minimum number of lines
3087    #[serde(default = "default_min_lines")]
3088    pub min_lines: u32,
3089    /// Maximum number of lines
3090    #[serde(default = "default_max_lines")]
3091    pub max_lines: u32,
3092    /// Most common line count (mode)
3093    #[serde(default = "default_mode_lines")]
3094    pub mode_lines: u32,
3095}
3096
3097fn default_min_lines() -> u32 {
3098    1
3099}
3100
3101fn default_max_lines() -> u32 {
3102    20
3103}
3104
3105fn default_mode_lines() -> u32 {
3106    3
3107}
3108
3109impl Default for DocumentLineCountDistribution {
3110    fn default() -> Self {
3111        Self {
3112            min_lines: default_min_lines(),
3113            max_lines: default_max_lines(),
3114            mode_lines: default_mode_lines(),
3115        }
3116    }
3117}
3118
3119/// Cash discount configuration.
3120#[derive(Debug, Clone, Serialize, Deserialize)]
3121pub struct CashDiscountConfig {
3122    /// Percentage of invoices eligible for cash discount
3123    #[serde(default = "default_discount_eligible_rate")]
3124    pub eligible_rate: f64,
3125    /// Rate at which customers take the discount
3126    #[serde(default = "default_discount_taken_rate")]
3127    pub taken_rate: f64,
3128    /// Standard discount percentage
3129    #[serde(default = "default_discount_percent")]
3130    pub discount_percent: f64,
3131    /// Days within which discount must be taken
3132    #[serde(default = "default_discount_days")]
3133    pub discount_days: u32,
3134}
3135
3136fn default_discount_eligible_rate() -> f64 {
3137    0.30
3138}
3139
3140fn default_discount_taken_rate() -> f64 {
3141    0.60
3142}
3143
3144fn default_discount_percent() -> f64 {
3145    0.02
3146}
3147
3148fn default_discount_days() -> u32 {
3149    10
3150}
3151
3152impl Default for CashDiscountConfig {
3153    fn default() -> Self {
3154        Self {
3155            eligible_rate: default_discount_eligible_rate(),
3156            taken_rate: default_discount_taken_rate(),
3157            discount_percent: default_discount_percent(),
3158            discount_days: default_discount_days(),
3159        }
3160    }
3161}
3162
3163// ============================================================================
3164// Intercompany Configuration
3165// ============================================================================
3166
3167/// Intercompany transaction configuration.
3168#[derive(Debug, Clone, Serialize, Deserialize)]
3169pub struct IntercompanyConfig {
3170    /// Enable intercompany transaction generation
3171    #[serde(default)]
3172    pub enabled: bool,
3173    /// Rate of transactions that are intercompany
3174    #[serde(default = "default_ic_transaction_rate")]
3175    pub ic_transaction_rate: f64,
3176    /// Transfer pricing method
3177    #[serde(default)]
3178    pub transfer_pricing_method: TransferPricingMethod,
3179    /// Transfer pricing markup percentage (for cost-plus)
3180    #[serde(default = "default_markup_percent")]
3181    pub markup_percent: f64,
3182    /// Generate matched IC pairs (offsetting entries)
3183    #[serde(default = "default_true")]
3184    pub generate_matched_pairs: bool,
3185    /// IC transaction type distribution
3186    #[serde(default)]
3187    pub transaction_type_distribution: ICTransactionTypeDistribution,
3188    /// Generate elimination entries for consolidation
3189    #[serde(default)]
3190    pub generate_eliminations: bool,
3191}
3192
3193fn default_ic_transaction_rate() -> f64 {
3194    0.15
3195}
3196
3197fn default_markup_percent() -> f64 {
3198    0.05
3199}
3200
3201impl Default for IntercompanyConfig {
3202    fn default() -> Self {
3203        Self {
3204            enabled: false,
3205            ic_transaction_rate: default_ic_transaction_rate(),
3206            transfer_pricing_method: TransferPricingMethod::default(),
3207            markup_percent: default_markup_percent(),
3208            generate_matched_pairs: true,
3209            transaction_type_distribution: ICTransactionTypeDistribution::default(),
3210            generate_eliminations: false,
3211        }
3212    }
3213}
3214
3215/// Transfer pricing method.
3216#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3217#[serde(rename_all = "snake_case")]
3218pub enum TransferPricingMethod {
3219    /// Cost plus a markup
3220    #[default]
3221    CostPlus,
3222    /// Comparable uncontrolled price
3223    ComparableUncontrolled,
3224    /// Resale price method
3225    ResalePrice,
3226    /// Transactional net margin method
3227    TransactionalNetMargin,
3228    /// Profit split method
3229    ProfitSplit,
3230}
3231
3232/// IC transaction type distribution.
3233#[derive(Debug, Clone, Serialize, Deserialize)]
3234pub struct ICTransactionTypeDistribution {
3235    /// Goods sales between entities
3236    pub goods_sale: f64,
3237    /// Services provided
3238    pub service_provided: f64,
3239    /// Intercompany loans
3240    pub loan: f64,
3241    /// Dividends
3242    pub dividend: f64,
3243    /// Management fees
3244    pub management_fee: f64,
3245    /// Royalties
3246    pub royalty: f64,
3247    /// Cost sharing
3248    pub cost_sharing: f64,
3249}
3250
3251impl Default for ICTransactionTypeDistribution {
3252    fn default() -> Self {
3253        Self {
3254            goods_sale: 0.35,
3255            service_provided: 0.20,
3256            loan: 0.10,
3257            dividend: 0.05,
3258            management_fee: 0.15,
3259            royalty: 0.10,
3260            cost_sharing: 0.05,
3261        }
3262    }
3263}
3264
3265// ============================================================================
3266// Balance Configuration
3267// ============================================================================
3268
3269/// Balance and trial balance configuration.
3270#[derive(Debug, Clone, Serialize, Deserialize)]
3271pub struct BalanceConfig {
3272    /// Generate opening balances
3273    #[serde(default)]
3274    pub generate_opening_balances: bool,
3275    /// Generate trial balances
3276    #[serde(default = "default_true")]
3277    pub generate_trial_balances: bool,
3278    /// Target gross margin (for revenue/COGS coherence)
3279    #[serde(default = "default_gross_margin")]
3280    pub target_gross_margin: f64,
3281    /// Target DSO (Days Sales Outstanding)
3282    #[serde(default = "default_dso")]
3283    pub target_dso_days: u32,
3284    /// Target DPO (Days Payable Outstanding)
3285    #[serde(default = "default_dpo")]
3286    pub target_dpo_days: u32,
3287    /// Target current ratio
3288    #[serde(default = "default_current_ratio")]
3289    pub target_current_ratio: f64,
3290    /// Target debt-to-equity ratio
3291    #[serde(default = "default_debt_equity")]
3292    pub target_debt_to_equity: f64,
3293    /// Validate balance sheet equation (A = L + E)
3294    #[serde(default = "default_true")]
3295    pub validate_balance_equation: bool,
3296    /// Reconcile subledgers to GL control accounts
3297    #[serde(default = "default_true")]
3298    pub reconcile_subledgers: bool,
3299}
3300
3301fn default_gross_margin() -> f64 {
3302    0.35
3303}
3304
3305fn default_dso() -> u32 {
3306    45
3307}
3308
3309fn default_dpo() -> u32 {
3310    30
3311}
3312
3313fn default_current_ratio() -> f64 {
3314    1.5
3315}
3316
3317fn default_debt_equity() -> f64 {
3318    0.5
3319}
3320
3321impl Default for BalanceConfig {
3322    fn default() -> Self {
3323        Self {
3324            generate_opening_balances: false,
3325            generate_trial_balances: true,
3326            target_gross_margin: default_gross_margin(),
3327            target_dso_days: default_dso(),
3328            target_dpo_days: default_dpo(),
3329            target_current_ratio: default_current_ratio(),
3330            target_debt_to_equity: default_debt_equity(),
3331            validate_balance_equation: true,
3332            reconcile_subledgers: true,
3333        }
3334    }
3335}
3336
3337// ==========================================================================
3338// OCPM (Object-Centric Process Mining) Configuration
3339// ==========================================================================
3340
3341/// OCPM (Object-Centric Process Mining) configuration.
3342///
3343/// Controls generation of OCEL 2.0 compatible event logs with
3344/// many-to-many event-to-object relationships.
3345#[derive(Debug, Clone, Serialize, Deserialize)]
3346pub struct OcpmConfig {
3347    /// Enable OCPM event log generation
3348    #[serde(default)]
3349    pub enabled: bool,
3350
3351    /// Generate lifecycle events (Start/Complete pairs vs atomic events)
3352    #[serde(default = "default_true")]
3353    pub generate_lifecycle_events: bool,
3354
3355    /// Include object-to-object relationships in output
3356    #[serde(default = "default_true")]
3357    pub include_object_relationships: bool,
3358
3359    /// Compute and export process variants
3360    #[serde(default = "default_true")]
3361    pub compute_variants: bool,
3362
3363    /// Maximum variants to track (0 = unlimited)
3364    #[serde(default)]
3365    pub max_variants: usize,
3366
3367    /// P2P process configuration
3368    #[serde(default)]
3369    pub p2p_process: OcpmProcessConfig,
3370
3371    /// O2C process configuration
3372    #[serde(default)]
3373    pub o2c_process: OcpmProcessConfig,
3374
3375    /// Output format configuration
3376    #[serde(default)]
3377    pub output: OcpmOutputConfig,
3378}
3379
3380impl Default for OcpmConfig {
3381    fn default() -> Self {
3382        Self {
3383            enabled: false,
3384            generate_lifecycle_events: true,
3385            include_object_relationships: true,
3386            compute_variants: true,
3387            max_variants: 0,
3388            p2p_process: OcpmProcessConfig::default(),
3389            o2c_process: OcpmProcessConfig::default(),
3390            output: OcpmOutputConfig::default(),
3391        }
3392    }
3393}
3394
3395/// Process-specific OCPM configuration.
3396#[derive(Debug, Clone, Serialize, Deserialize)]
3397pub struct OcpmProcessConfig {
3398    /// Rework probability (0.0-1.0)
3399    #[serde(default = "default_rework_probability")]
3400    pub rework_probability: f64,
3401
3402    /// Skip step probability (0.0-1.0)
3403    #[serde(default = "default_skip_probability")]
3404    pub skip_step_probability: f64,
3405
3406    /// Out-of-order step probability (0.0-1.0)
3407    #[serde(default = "default_out_of_order_probability")]
3408    pub out_of_order_probability: f64,
3409}
3410
3411fn default_rework_probability() -> f64 {
3412    0.05
3413}
3414
3415fn default_skip_probability() -> f64 {
3416    0.02
3417}
3418
3419fn default_out_of_order_probability() -> f64 {
3420    0.03
3421}
3422
3423impl Default for OcpmProcessConfig {
3424    fn default() -> Self {
3425        Self {
3426            rework_probability: default_rework_probability(),
3427            skip_step_probability: default_skip_probability(),
3428            out_of_order_probability: default_out_of_order_probability(),
3429        }
3430    }
3431}
3432
3433/// OCPM output format configuration.
3434#[derive(Debug, Clone, Serialize, Deserialize)]
3435pub struct OcpmOutputConfig {
3436    /// Export OCEL 2.0 JSON format
3437    #[serde(default = "default_true")]
3438    pub ocel_json: bool,
3439
3440    /// Export OCEL 2.0 XML format
3441    #[serde(default)]
3442    pub ocel_xml: bool,
3443
3444    /// Export XES 2.0 XML format (IEEE standard for process mining tools)
3445    #[serde(default)]
3446    pub xes: bool,
3447
3448    /// Include lifecycle transitions in XES output (start/complete pairs)
3449    #[serde(default = "default_true")]
3450    pub xes_include_lifecycle: bool,
3451
3452    /// Include resource attributes in XES output
3453    #[serde(default = "default_true")]
3454    pub xes_include_resources: bool,
3455
3456    /// Export flattened CSV for each object type
3457    #[serde(default = "default_true")]
3458    pub flattened_csv: bool,
3459
3460    /// Export event-object relationship table
3461    #[serde(default = "default_true")]
3462    pub event_object_csv: bool,
3463
3464    /// Export object-object relationship table
3465    #[serde(default = "default_true")]
3466    pub object_relationship_csv: bool,
3467
3468    /// Export process variants summary
3469    #[serde(default = "default_true")]
3470    pub variants_csv: bool,
3471
3472    /// Export reference process models (canonical P2P, O2C, R2R)
3473    #[serde(default)]
3474    pub export_reference_models: bool,
3475}
3476
3477impl Default for OcpmOutputConfig {
3478    fn default() -> Self {
3479        Self {
3480            ocel_json: true,
3481            ocel_xml: false,
3482            xes: false,
3483            xes_include_lifecycle: true,
3484            xes_include_resources: true,
3485            flattened_csv: true,
3486            event_object_csv: true,
3487            object_relationship_csv: true,
3488            variants_csv: true,
3489            export_reference_models: false,
3490        }
3491    }
3492}
3493
3494/// Audit engagement and workpaper generation configuration.
3495#[derive(Debug, Clone, Serialize, Deserialize)]
3496pub struct AuditGenerationConfig {
3497    /// Enable audit engagement generation
3498    #[serde(default)]
3499    pub enabled: bool,
3500
3501    /// Generate engagement documents and workpapers
3502    #[serde(default = "default_true")]
3503    pub generate_workpapers: bool,
3504
3505    /// Default engagement type distribution
3506    #[serde(default)]
3507    pub engagement_types: AuditEngagementTypesConfig,
3508
3509    /// Workpaper configuration
3510    #[serde(default)]
3511    pub workpapers: WorkpaperConfig,
3512
3513    /// Team configuration
3514    #[serde(default)]
3515    pub team: AuditTeamConfig,
3516
3517    /// Review workflow configuration
3518    #[serde(default)]
3519    pub review: ReviewWorkflowConfig,
3520}
3521
3522impl Default for AuditGenerationConfig {
3523    fn default() -> Self {
3524        Self {
3525            enabled: false,
3526            generate_workpapers: true,
3527            engagement_types: AuditEngagementTypesConfig::default(),
3528            workpapers: WorkpaperConfig::default(),
3529            team: AuditTeamConfig::default(),
3530            review: ReviewWorkflowConfig::default(),
3531        }
3532    }
3533}
3534
3535/// Engagement type distribution configuration.
3536#[derive(Debug, Clone, Serialize, Deserialize)]
3537pub struct AuditEngagementTypesConfig {
3538    /// Financial statement audit probability
3539    #[serde(default = "default_financial_audit_prob")]
3540    pub financial_statement: f64,
3541    /// SOX/ICFR audit probability
3542    #[serde(default = "default_sox_audit_prob")]
3543    pub sox_icfr: f64,
3544    /// Integrated audit probability
3545    #[serde(default = "default_integrated_audit_prob")]
3546    pub integrated: f64,
3547    /// Review engagement probability
3548    #[serde(default = "default_review_prob")]
3549    pub review: f64,
3550    /// Agreed-upon procedures probability
3551    #[serde(default = "default_aup_prob")]
3552    pub agreed_upon_procedures: f64,
3553}
3554
3555fn default_financial_audit_prob() -> f64 {
3556    0.40
3557}
3558fn default_sox_audit_prob() -> f64 {
3559    0.20
3560}
3561fn default_integrated_audit_prob() -> f64 {
3562    0.25
3563}
3564fn default_review_prob() -> f64 {
3565    0.10
3566}
3567fn default_aup_prob() -> f64 {
3568    0.05
3569}
3570
3571impl Default for AuditEngagementTypesConfig {
3572    fn default() -> Self {
3573        Self {
3574            financial_statement: default_financial_audit_prob(),
3575            sox_icfr: default_sox_audit_prob(),
3576            integrated: default_integrated_audit_prob(),
3577            review: default_review_prob(),
3578            agreed_upon_procedures: default_aup_prob(),
3579        }
3580    }
3581}
3582
3583/// Workpaper generation configuration.
3584#[derive(Debug, Clone, Serialize, Deserialize)]
3585pub struct WorkpaperConfig {
3586    /// Average workpapers per engagement phase
3587    #[serde(default = "default_workpapers_per_phase")]
3588    pub average_per_phase: usize,
3589
3590    /// Include ISA compliance references
3591    #[serde(default = "default_true")]
3592    pub include_isa_references: bool,
3593
3594    /// Generate sample details
3595    #[serde(default = "default_true")]
3596    pub include_sample_details: bool,
3597
3598    /// Include cross-references between workpapers
3599    #[serde(default = "default_true")]
3600    pub include_cross_references: bool,
3601
3602    /// Sampling configuration
3603    #[serde(default)]
3604    pub sampling: SamplingConfig,
3605}
3606
3607fn default_workpapers_per_phase() -> usize {
3608    5
3609}
3610
3611impl Default for WorkpaperConfig {
3612    fn default() -> Self {
3613        Self {
3614            average_per_phase: default_workpapers_per_phase(),
3615            include_isa_references: true,
3616            include_sample_details: true,
3617            include_cross_references: true,
3618            sampling: SamplingConfig::default(),
3619        }
3620    }
3621}
3622
3623/// Sampling method configuration.
3624#[derive(Debug, Clone, Serialize, Deserialize)]
3625pub struct SamplingConfig {
3626    /// Statistical sampling rate (0.0-1.0)
3627    #[serde(default = "default_statistical_rate")]
3628    pub statistical_rate: f64,
3629    /// Judgmental sampling rate (0.0-1.0)
3630    #[serde(default = "default_judgmental_rate")]
3631    pub judgmental_rate: f64,
3632    /// Haphazard sampling rate (0.0-1.0)
3633    #[serde(default = "default_haphazard_rate")]
3634    pub haphazard_rate: f64,
3635    /// 100% examination rate (0.0-1.0)
3636    #[serde(default = "default_complete_examination_rate")]
3637    pub complete_examination_rate: f64,
3638}
3639
3640fn default_statistical_rate() -> f64 {
3641    0.40
3642}
3643fn default_judgmental_rate() -> f64 {
3644    0.30
3645}
3646fn default_haphazard_rate() -> f64 {
3647    0.20
3648}
3649fn default_complete_examination_rate() -> f64 {
3650    0.10
3651}
3652
3653impl Default for SamplingConfig {
3654    fn default() -> Self {
3655        Self {
3656            statistical_rate: default_statistical_rate(),
3657            judgmental_rate: default_judgmental_rate(),
3658            haphazard_rate: default_haphazard_rate(),
3659            complete_examination_rate: default_complete_examination_rate(),
3660        }
3661    }
3662}
3663
3664/// Audit team configuration.
3665#[derive(Debug, Clone, Serialize, Deserialize)]
3666pub struct AuditTeamConfig {
3667    /// Minimum team size
3668    #[serde(default = "default_min_team_size")]
3669    pub min_team_size: usize,
3670    /// Maximum team size
3671    #[serde(default = "default_max_team_size")]
3672    pub max_team_size: usize,
3673    /// Probability of having a specialist on the team
3674    #[serde(default = "default_specialist_probability")]
3675    pub specialist_probability: f64,
3676}
3677
3678fn default_min_team_size() -> usize {
3679    3
3680}
3681fn default_max_team_size() -> usize {
3682    8
3683}
3684fn default_specialist_probability() -> f64 {
3685    0.30
3686}
3687
3688impl Default for AuditTeamConfig {
3689    fn default() -> Self {
3690        Self {
3691            min_team_size: default_min_team_size(),
3692            max_team_size: default_max_team_size(),
3693            specialist_probability: default_specialist_probability(),
3694        }
3695    }
3696}
3697
3698/// Review workflow configuration.
3699#[derive(Debug, Clone, Serialize, Deserialize)]
3700pub struct ReviewWorkflowConfig {
3701    /// Average days between preparer completion and first review
3702    #[serde(default = "default_review_delay_days")]
3703    pub average_review_delay_days: u32,
3704    /// Probability of review notes requiring rework
3705    #[serde(default = "default_rework_probability_review")]
3706    pub rework_probability: f64,
3707    /// Require partner sign-off for all workpapers
3708    #[serde(default = "default_true")]
3709    pub require_partner_signoff: bool,
3710}
3711
3712fn default_review_delay_days() -> u32 {
3713    2
3714}
3715fn default_rework_probability_review() -> f64 {
3716    0.15
3717}
3718
3719impl Default for ReviewWorkflowConfig {
3720    fn default() -> Self {
3721        Self {
3722            average_review_delay_days: default_review_delay_days(),
3723            rework_probability: default_rework_probability_review(),
3724            require_partner_signoff: true,
3725        }
3726    }
3727}
3728
3729// =============================================================================
3730// Data Quality Configuration
3731// =============================================================================
3732
3733/// Data quality variation settings for realistic flakiness injection.
3734#[derive(Debug, Clone, Serialize, Deserialize)]
3735pub struct DataQualitySchemaConfig {
3736    /// Enable data quality variations
3737    #[serde(default)]
3738    pub enabled: bool,
3739    /// Preset to use (overrides individual settings if set)
3740    #[serde(default)]
3741    pub preset: DataQualityPreset,
3742    /// Missing value injection settings
3743    #[serde(default)]
3744    pub missing_values: MissingValuesSchemaConfig,
3745    /// Typo injection settings
3746    #[serde(default)]
3747    pub typos: TypoSchemaConfig,
3748    /// Format variation settings
3749    #[serde(default)]
3750    pub format_variations: FormatVariationSchemaConfig,
3751    /// Duplicate injection settings
3752    #[serde(default)]
3753    pub duplicates: DuplicateSchemaConfig,
3754    /// Encoding issue settings
3755    #[serde(default)]
3756    pub encoding_issues: EncodingIssueSchemaConfig,
3757    /// Generate quality issue labels for ML training
3758    #[serde(default)]
3759    pub generate_labels: bool,
3760    /// Per-sink quality profiles (different settings for CSV vs JSON etc.)
3761    #[serde(default)]
3762    pub sink_profiles: SinkQualityProfiles,
3763}
3764
3765impl Default for DataQualitySchemaConfig {
3766    fn default() -> Self {
3767        Self {
3768            enabled: false,
3769            preset: DataQualityPreset::None,
3770            missing_values: MissingValuesSchemaConfig::default(),
3771            typos: TypoSchemaConfig::default(),
3772            format_variations: FormatVariationSchemaConfig::default(),
3773            duplicates: DuplicateSchemaConfig::default(),
3774            encoding_issues: EncodingIssueSchemaConfig::default(),
3775            generate_labels: true,
3776            sink_profiles: SinkQualityProfiles::default(),
3777        }
3778    }
3779}
3780
3781impl DataQualitySchemaConfig {
3782    /// Creates a config for a specific preset profile.
3783    pub fn with_preset(preset: DataQualityPreset) -> Self {
3784        let mut config = Self {
3785            preset,
3786            ..Default::default()
3787        };
3788        config.apply_preset();
3789        config
3790    }
3791
3792    /// Applies the preset settings to the individual configuration fields.
3793    /// Call this after deserializing if preset is not Custom or None.
3794    pub fn apply_preset(&mut self) {
3795        if !self.preset.overrides_settings() {
3796            return;
3797        }
3798
3799        self.enabled = true;
3800
3801        // Missing values
3802        self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3803        self.missing_values.rate = self.preset.missing_rate();
3804
3805        // Typos
3806        self.typos.enabled = self.preset.typo_rate() > 0.0;
3807        self.typos.char_error_rate = self.preset.typo_rate();
3808
3809        // Duplicates
3810        self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3811        self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3812        self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3813        self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3814
3815        // Format variations
3816        self.format_variations.enabled = self.preset.format_variations_enabled();
3817
3818        // Encoding issues
3819        self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3820        self.encoding_issues.rate = self.preset.encoding_issue_rate();
3821
3822        // OCR errors for typos in legacy preset
3823        if self.preset.ocr_errors_enabled() {
3824            self.typos.type_weights.ocr_errors = 0.3;
3825        }
3826    }
3827
3828    /// Returns the effective missing value rate (considering preset).
3829    pub fn effective_missing_rate(&self) -> f64 {
3830        if self.preset.overrides_settings() {
3831            self.preset.missing_rate()
3832        } else {
3833            self.missing_values.rate
3834        }
3835    }
3836
3837    /// Returns the effective typo rate (considering preset).
3838    pub fn effective_typo_rate(&self) -> f64 {
3839        if self.preset.overrides_settings() {
3840            self.preset.typo_rate()
3841        } else {
3842            self.typos.char_error_rate
3843        }
3844    }
3845
3846    /// Returns the effective duplicate rate (considering preset).
3847    pub fn effective_duplicate_rate(&self) -> f64 {
3848        if self.preset.overrides_settings() {
3849            self.preset.duplicate_rate()
3850        } else {
3851            self.duplicates.exact_duplicate_ratio
3852                + self.duplicates.near_duplicate_ratio
3853                + self.duplicates.fuzzy_duplicate_ratio
3854        }
3855    }
3856
3857    /// Creates a clean profile config.
3858    pub fn clean() -> Self {
3859        Self::with_preset(DataQualityPreset::Clean)
3860    }
3861
3862    /// Creates a noisy profile config.
3863    pub fn noisy() -> Self {
3864        Self::with_preset(DataQualityPreset::Noisy)
3865    }
3866
3867    /// Creates a legacy profile config.
3868    pub fn legacy() -> Self {
3869        Self::with_preset(DataQualityPreset::Legacy)
3870    }
3871}
3872
3873/// Preset configurations for common data quality scenarios.
3874#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3875#[serde(rename_all = "snake_case")]
3876pub enum DataQualityPreset {
3877    /// No data quality variations (clean data)
3878    #[default]
3879    None,
3880    /// Minimal variations (very clean data with rare issues)
3881    Minimal,
3882    /// Normal variations (realistic enterprise data quality)
3883    Normal,
3884    /// High variations (messy data for stress testing)
3885    High,
3886    /// Custom (use individual settings)
3887    Custom,
3888
3889    // ========================================
3890    // ML-Oriented Profiles (Phase 2.1)
3891    // ========================================
3892    /// Clean profile for ML training - minimal data quality issues
3893    /// Missing: 0.1%, Typos: 0.05%, Duplicates: 0%, Format: None
3894    Clean,
3895    /// Noisy profile simulating typical production data issues
3896    /// Missing: 5%, Typos: 2%, Duplicates: 1%, Format: Medium
3897    Noisy,
3898    /// Legacy profile simulating migrated/OCR'd historical data
3899    /// Missing: 10%, Typos: 5%, Duplicates: 3%, Format: Heavy + OCR
3900    Legacy,
3901}
3902
3903impl DataQualityPreset {
3904    /// Returns the missing value rate for this preset.
3905    pub fn missing_rate(&self) -> f64 {
3906        match self {
3907            DataQualityPreset::None => 0.0,
3908            DataQualityPreset::Minimal => 0.005,
3909            DataQualityPreset::Normal => 0.02,
3910            DataQualityPreset::High => 0.08,
3911            DataQualityPreset::Custom => 0.01, // Use config value
3912            DataQualityPreset::Clean => 0.001,
3913            DataQualityPreset::Noisy => 0.05,
3914            DataQualityPreset::Legacy => 0.10,
3915        }
3916    }
3917
3918    /// Returns the typo rate for this preset.
3919    pub fn typo_rate(&self) -> f64 {
3920        match self {
3921            DataQualityPreset::None => 0.0,
3922            DataQualityPreset::Minimal => 0.0005,
3923            DataQualityPreset::Normal => 0.002,
3924            DataQualityPreset::High => 0.01,
3925            DataQualityPreset::Custom => 0.001, // Use config value
3926            DataQualityPreset::Clean => 0.0005,
3927            DataQualityPreset::Noisy => 0.02,
3928            DataQualityPreset::Legacy => 0.05,
3929        }
3930    }
3931
3932    /// Returns the duplicate rate for this preset.
3933    pub fn duplicate_rate(&self) -> f64 {
3934        match self {
3935            DataQualityPreset::None => 0.0,
3936            DataQualityPreset::Minimal => 0.001,
3937            DataQualityPreset::Normal => 0.005,
3938            DataQualityPreset::High => 0.02,
3939            DataQualityPreset::Custom => 0.0, // Use config value
3940            DataQualityPreset::Clean => 0.0,
3941            DataQualityPreset::Noisy => 0.01,
3942            DataQualityPreset::Legacy => 0.03,
3943        }
3944    }
3945
3946    /// Returns whether format variations are enabled for this preset.
3947    pub fn format_variations_enabled(&self) -> bool {
3948        match self {
3949            DataQualityPreset::None | DataQualityPreset::Clean => false,
3950            DataQualityPreset::Minimal => true,
3951            DataQualityPreset::Normal => true,
3952            DataQualityPreset::High => true,
3953            DataQualityPreset::Custom => true,
3954            DataQualityPreset::Noisy => true,
3955            DataQualityPreset::Legacy => true,
3956        }
3957    }
3958
3959    /// Returns whether OCR-style errors are enabled for this preset.
3960    pub fn ocr_errors_enabled(&self) -> bool {
3961        matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
3962    }
3963
3964    /// Returns whether encoding issues are enabled for this preset.
3965    pub fn encoding_issues_enabled(&self) -> bool {
3966        matches!(
3967            self,
3968            DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
3969        )
3970    }
3971
3972    /// Returns the encoding issue rate for this preset.
3973    pub fn encoding_issue_rate(&self) -> f64 {
3974        match self {
3975            DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
3976            DataQualityPreset::Normal => 0.002,
3977            DataQualityPreset::High => 0.01,
3978            DataQualityPreset::Custom => 0.0,
3979            DataQualityPreset::Noisy => 0.005,
3980            DataQualityPreset::Legacy => 0.02,
3981        }
3982    }
3983
3984    /// Returns true if this preset overrides individual settings.
3985    pub fn overrides_settings(&self) -> bool {
3986        !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
3987    }
3988
3989    /// Returns a human-readable description of this preset.
3990    pub fn description(&self) -> &'static str {
3991        match self {
3992            DataQualityPreset::None => "No data quality issues (pristine data)",
3993            DataQualityPreset::Minimal => "Very rare data quality issues",
3994            DataQualityPreset::Normal => "Realistic enterprise data quality",
3995            DataQualityPreset::High => "Messy data for stress testing",
3996            DataQualityPreset::Custom => "Custom settings from configuration",
3997            DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
3998            DataQualityPreset::Noisy => "Typical production data with moderate issues",
3999            DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4000        }
4001    }
4002}
4003
4004/// Missing value injection configuration.
4005#[derive(Debug, Clone, Serialize, Deserialize)]
4006pub struct MissingValuesSchemaConfig {
4007    /// Enable missing value injection
4008    #[serde(default)]
4009    pub enabled: bool,
4010    /// Global missing rate (0.0 to 1.0)
4011    #[serde(default = "default_missing_rate")]
4012    pub rate: f64,
4013    /// Missing value strategy
4014    #[serde(default)]
4015    pub strategy: MissingValueStrategy,
4016    /// Field-specific rates (field name -> rate)
4017    #[serde(default)]
4018    pub field_rates: std::collections::HashMap<String, f64>,
4019    /// Fields that should never have missing values
4020    #[serde(default)]
4021    pub protected_fields: Vec<String>,
4022}
4023
4024fn default_missing_rate() -> f64 {
4025    0.01
4026}
4027
4028impl Default for MissingValuesSchemaConfig {
4029    fn default() -> Self {
4030        Self {
4031            enabled: false,
4032            rate: default_missing_rate(),
4033            strategy: MissingValueStrategy::Mcar,
4034            field_rates: std::collections::HashMap::new(),
4035            protected_fields: vec![
4036                "document_id".to_string(),
4037                "company_code".to_string(),
4038                "posting_date".to_string(),
4039            ],
4040        }
4041    }
4042}
4043
4044/// Missing value strategy types.
4045#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4046#[serde(rename_all = "snake_case")]
4047pub enum MissingValueStrategy {
4048    /// Missing Completely At Random - equal probability for all values
4049    #[default]
4050    Mcar,
4051    /// Missing At Random - depends on other observed values
4052    Mar,
4053    /// Missing Not At Random - depends on the value itself
4054    Mnar,
4055    /// Systematic - entire field groups missing together
4056    Systematic,
4057}
4058
4059/// Typo injection configuration.
4060#[derive(Debug, Clone, Serialize, Deserialize)]
4061pub struct TypoSchemaConfig {
4062    /// Enable typo injection
4063    #[serde(default)]
4064    pub enabled: bool,
4065    /// Character error rate (per character, not per field)
4066    #[serde(default = "default_typo_rate")]
4067    pub char_error_rate: f64,
4068    /// Typo type weights
4069    #[serde(default)]
4070    pub type_weights: TypoTypeWeights,
4071    /// Fields that should never have typos
4072    #[serde(default)]
4073    pub protected_fields: Vec<String>,
4074}
4075
4076fn default_typo_rate() -> f64 {
4077    0.001
4078}
4079
4080impl Default for TypoSchemaConfig {
4081    fn default() -> Self {
4082        Self {
4083            enabled: false,
4084            char_error_rate: default_typo_rate(),
4085            type_weights: TypoTypeWeights::default(),
4086            protected_fields: vec![
4087                "document_id".to_string(),
4088                "gl_account".to_string(),
4089                "company_code".to_string(),
4090            ],
4091        }
4092    }
4093}
4094
4095/// Weights for different typo types.
4096#[derive(Debug, Clone, Serialize, Deserialize)]
4097pub struct TypoTypeWeights {
4098    /// Keyboard-adjacent substitution (e.g., 'a' -> 's')
4099    #[serde(default = "default_substitution_weight")]
4100    pub substitution: f64,
4101    /// Adjacent character transposition (e.g., 'ab' -> 'ba')
4102    #[serde(default = "default_transposition_weight")]
4103    pub transposition: f64,
4104    /// Character insertion
4105    #[serde(default = "default_insertion_weight")]
4106    pub insertion: f64,
4107    /// Character deletion
4108    #[serde(default = "default_deletion_weight")]
4109    pub deletion: f64,
4110    /// OCR-style errors (e.g., '0' -> 'O')
4111    #[serde(default = "default_ocr_weight")]
4112    pub ocr_errors: f64,
4113    /// Homophone substitution (e.g., 'their' -> 'there')
4114    #[serde(default = "default_homophone_weight")]
4115    pub homophones: f64,
4116}
4117
4118fn default_substitution_weight() -> f64 {
4119    0.35
4120}
4121fn default_transposition_weight() -> f64 {
4122    0.25
4123}
4124fn default_insertion_weight() -> f64 {
4125    0.10
4126}
4127fn default_deletion_weight() -> f64 {
4128    0.15
4129}
4130fn default_ocr_weight() -> f64 {
4131    0.10
4132}
4133fn default_homophone_weight() -> f64 {
4134    0.05
4135}
4136
4137impl Default for TypoTypeWeights {
4138    fn default() -> Self {
4139        Self {
4140            substitution: default_substitution_weight(),
4141            transposition: default_transposition_weight(),
4142            insertion: default_insertion_weight(),
4143            deletion: default_deletion_weight(),
4144            ocr_errors: default_ocr_weight(),
4145            homophones: default_homophone_weight(),
4146        }
4147    }
4148}
4149
4150/// Format variation configuration.
4151#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4152pub struct FormatVariationSchemaConfig {
4153    /// Enable format variations
4154    #[serde(default)]
4155    pub enabled: bool,
4156    /// Date format variation settings
4157    #[serde(default)]
4158    pub dates: DateFormatVariationConfig,
4159    /// Amount format variation settings
4160    #[serde(default)]
4161    pub amounts: AmountFormatVariationConfig,
4162    /// Identifier format variation settings
4163    #[serde(default)]
4164    pub identifiers: IdentifierFormatVariationConfig,
4165}
4166
4167/// Date format variation configuration.
4168#[derive(Debug, Clone, Serialize, Deserialize)]
4169pub struct DateFormatVariationConfig {
4170    /// Enable date format variations
4171    #[serde(default)]
4172    pub enabled: bool,
4173    /// Overall variation rate
4174    #[serde(default = "default_date_variation_rate")]
4175    pub rate: f64,
4176    /// Include ISO format (2024-01-15)
4177    #[serde(default = "default_true")]
4178    pub iso_format: bool,
4179    /// Include US format (01/15/2024)
4180    #[serde(default)]
4181    pub us_format: bool,
4182    /// Include EU format (15.01.2024)
4183    #[serde(default)]
4184    pub eu_format: bool,
4185    /// Include long format (January 15, 2024)
4186    #[serde(default)]
4187    pub long_format: bool,
4188}
4189
4190fn default_date_variation_rate() -> f64 {
4191    0.05
4192}
4193
4194impl Default for DateFormatVariationConfig {
4195    fn default() -> Self {
4196        Self {
4197            enabled: false,
4198            rate: default_date_variation_rate(),
4199            iso_format: true,
4200            us_format: false,
4201            eu_format: false,
4202            long_format: false,
4203        }
4204    }
4205}
4206
4207/// Amount format variation configuration.
4208#[derive(Debug, Clone, Serialize, Deserialize)]
4209pub struct AmountFormatVariationConfig {
4210    /// Enable amount format variations
4211    #[serde(default)]
4212    pub enabled: bool,
4213    /// Overall variation rate
4214    #[serde(default = "default_amount_variation_rate")]
4215    pub rate: f64,
4216    /// Include US comma format (1,234.56)
4217    #[serde(default)]
4218    pub us_comma_format: bool,
4219    /// Include EU format (1.234,56)
4220    #[serde(default)]
4221    pub eu_format: bool,
4222    /// Include currency prefix ($1,234.56)
4223    #[serde(default)]
4224    pub currency_prefix: bool,
4225    /// Include accounting format with parentheses for negatives
4226    #[serde(default)]
4227    pub accounting_format: bool,
4228}
4229
4230fn default_amount_variation_rate() -> f64 {
4231    0.02
4232}
4233
4234impl Default for AmountFormatVariationConfig {
4235    fn default() -> Self {
4236        Self {
4237            enabled: false,
4238            rate: default_amount_variation_rate(),
4239            us_comma_format: false,
4240            eu_format: false,
4241            currency_prefix: false,
4242            accounting_format: false,
4243        }
4244    }
4245}
4246
4247/// Identifier format variation configuration.
4248#[derive(Debug, Clone, Serialize, Deserialize)]
4249pub struct IdentifierFormatVariationConfig {
4250    /// Enable identifier format variations
4251    #[serde(default)]
4252    pub enabled: bool,
4253    /// Overall variation rate
4254    #[serde(default = "default_identifier_variation_rate")]
4255    pub rate: f64,
4256    /// Case variations (uppercase, lowercase, mixed)
4257    #[serde(default)]
4258    pub case_variations: bool,
4259    /// Padding variations (leading zeros)
4260    #[serde(default)]
4261    pub padding_variations: bool,
4262    /// Separator variations (dash vs underscore)
4263    #[serde(default)]
4264    pub separator_variations: bool,
4265}
4266
4267fn default_identifier_variation_rate() -> f64 {
4268    0.02
4269}
4270
4271impl Default for IdentifierFormatVariationConfig {
4272    fn default() -> Self {
4273        Self {
4274            enabled: false,
4275            rate: default_identifier_variation_rate(),
4276            case_variations: false,
4277            padding_variations: false,
4278            separator_variations: false,
4279        }
4280    }
4281}
4282
4283/// Duplicate injection configuration.
4284#[derive(Debug, Clone, Serialize, Deserialize)]
4285pub struct DuplicateSchemaConfig {
4286    /// Enable duplicate injection
4287    #[serde(default)]
4288    pub enabled: bool,
4289    /// Overall duplicate rate
4290    #[serde(default = "default_duplicate_rate")]
4291    pub rate: f64,
4292    /// Exact duplicate proportion (out of duplicates)
4293    #[serde(default = "default_exact_duplicate_ratio")]
4294    pub exact_duplicate_ratio: f64,
4295    /// Near duplicate proportion (slight variations)
4296    #[serde(default = "default_near_duplicate_ratio")]
4297    pub near_duplicate_ratio: f64,
4298    /// Fuzzy duplicate proportion (typos in key fields)
4299    #[serde(default = "default_fuzzy_duplicate_ratio")]
4300    pub fuzzy_duplicate_ratio: f64,
4301    /// Maximum date offset for near/fuzzy duplicates (days)
4302    #[serde(default = "default_max_date_offset")]
4303    pub max_date_offset_days: u32,
4304    /// Maximum amount variance for near duplicates (fraction)
4305    #[serde(default = "default_max_amount_variance")]
4306    pub max_amount_variance: f64,
4307}
4308
4309fn default_duplicate_rate() -> f64 {
4310    0.005
4311}
4312fn default_exact_duplicate_ratio() -> f64 {
4313    0.4
4314}
4315fn default_near_duplicate_ratio() -> f64 {
4316    0.35
4317}
4318fn default_fuzzy_duplicate_ratio() -> f64 {
4319    0.25
4320}
4321fn default_max_date_offset() -> u32 {
4322    3
4323}
4324fn default_max_amount_variance() -> f64 {
4325    0.01
4326}
4327
4328impl Default for DuplicateSchemaConfig {
4329    fn default() -> Self {
4330        Self {
4331            enabled: false,
4332            rate: default_duplicate_rate(),
4333            exact_duplicate_ratio: default_exact_duplicate_ratio(),
4334            near_duplicate_ratio: default_near_duplicate_ratio(),
4335            fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4336            max_date_offset_days: default_max_date_offset(),
4337            max_amount_variance: default_max_amount_variance(),
4338        }
4339    }
4340}
4341
4342/// Encoding issue configuration.
4343#[derive(Debug, Clone, Serialize, Deserialize)]
4344pub struct EncodingIssueSchemaConfig {
4345    /// Enable encoding issue injection
4346    #[serde(default)]
4347    pub enabled: bool,
4348    /// Overall encoding issue rate
4349    #[serde(default = "default_encoding_rate")]
4350    pub rate: f64,
4351    /// Include mojibake (UTF-8/Latin-1 confusion)
4352    #[serde(default)]
4353    pub mojibake: bool,
4354    /// Include HTML entity corruption
4355    #[serde(default)]
4356    pub html_entities: bool,
4357    /// Include BOM issues
4358    #[serde(default)]
4359    pub bom_issues: bool,
4360}
4361
4362fn default_encoding_rate() -> f64 {
4363    0.001
4364}
4365
4366impl Default for EncodingIssueSchemaConfig {
4367    fn default() -> Self {
4368        Self {
4369            enabled: false,
4370            rate: default_encoding_rate(),
4371            mojibake: false,
4372            html_entities: false,
4373            bom_issues: false,
4374        }
4375    }
4376}
4377
4378/// Per-sink quality profiles for different output formats.
4379#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4380pub struct SinkQualityProfiles {
4381    /// CSV-specific quality settings
4382    #[serde(default)]
4383    pub csv: Option<SinkQualityOverride>,
4384    /// JSON-specific quality settings
4385    #[serde(default)]
4386    pub json: Option<SinkQualityOverride>,
4387    /// Parquet-specific quality settings
4388    #[serde(default)]
4389    pub parquet: Option<SinkQualityOverride>,
4390}
4391
4392/// Quality setting overrides for a specific sink type.
4393#[derive(Debug, Clone, Serialize, Deserialize)]
4394pub struct SinkQualityOverride {
4395    /// Override enabled state
4396    pub enabled: Option<bool>,
4397    /// Override missing value rate
4398    pub missing_rate: Option<f64>,
4399    /// Override typo rate
4400    pub typo_rate: Option<f64>,
4401    /// Override format variation rate
4402    pub format_variation_rate: Option<f64>,
4403    /// Override duplicate rate
4404    pub duplicate_rate: Option<f64>,
4405}
4406
4407// =============================================================================
4408// Accounting Standards Configuration
4409// =============================================================================
4410
4411/// Accounting standards framework configuration for generating standards-compliant data.
4412///
4413/// Supports US GAAP and IFRS frameworks with specific standards:
4414/// - ASC 606/IFRS 15: Revenue Recognition
4415/// - ASC 842/IFRS 16: Leases
4416/// - ASC 820/IFRS 13: Fair Value Measurement
4417/// - ASC 360/IAS 36: Impairment
4418#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4419pub struct AccountingStandardsConfig {
4420    /// Enable accounting standards generation
4421    #[serde(default)]
4422    pub enabled: bool,
4423
4424    /// Accounting framework to use
4425    #[serde(default)]
4426    pub framework: AccountingFrameworkConfig,
4427
4428    /// Revenue recognition configuration (ASC 606/IFRS 15)
4429    #[serde(default)]
4430    pub revenue_recognition: RevenueRecognitionConfig,
4431
4432    /// Lease accounting configuration (ASC 842/IFRS 16)
4433    #[serde(default)]
4434    pub leases: LeaseAccountingConfig,
4435
4436    /// Fair value measurement configuration (ASC 820/IFRS 13)
4437    #[serde(default)]
4438    pub fair_value: FairValueConfig,
4439
4440    /// Impairment testing configuration (ASC 360/IAS 36)
4441    #[serde(default)]
4442    pub impairment: ImpairmentConfig,
4443
4444    /// Generate framework differences for dual reporting
4445    #[serde(default)]
4446    pub generate_differences: bool,
4447}
4448
4449/// Accounting framework selection.
4450#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4451#[serde(rename_all = "snake_case")]
4452pub enum AccountingFrameworkConfig {
4453    /// US Generally Accepted Accounting Principles
4454    #[default]
4455    UsGaap,
4456    /// International Financial Reporting Standards
4457    Ifrs,
4458    /// Generate data for both frameworks with reconciliation
4459    DualReporting,
4460}
4461
4462/// Revenue recognition configuration (ASC 606/IFRS 15).
4463#[derive(Debug, Clone, Serialize, Deserialize)]
4464pub struct RevenueRecognitionConfig {
4465    /// Enable revenue recognition generation
4466    #[serde(default)]
4467    pub enabled: bool,
4468
4469    /// Generate customer contracts
4470    #[serde(default = "default_true")]
4471    pub generate_contracts: bool,
4472
4473    /// Average number of performance obligations per contract
4474    #[serde(default = "default_avg_obligations")]
4475    pub avg_obligations_per_contract: f64,
4476
4477    /// Rate of contracts with variable consideration
4478    #[serde(default = "default_variable_consideration_rate")]
4479    pub variable_consideration_rate: f64,
4480
4481    /// Rate of over-time revenue recognition (vs point-in-time)
4482    #[serde(default = "default_over_time_rate")]
4483    pub over_time_recognition_rate: f64,
4484
4485    /// Number of contracts to generate
4486    #[serde(default = "default_contract_count")]
4487    pub contract_count: usize,
4488}
4489
4490fn default_avg_obligations() -> f64 {
4491    2.0
4492}
4493
4494fn default_variable_consideration_rate() -> f64 {
4495    0.15
4496}
4497
4498fn default_over_time_rate() -> f64 {
4499    0.30
4500}
4501
4502fn default_contract_count() -> usize {
4503    100
4504}
4505
4506impl Default for RevenueRecognitionConfig {
4507    fn default() -> Self {
4508        Self {
4509            enabled: false,
4510            generate_contracts: true,
4511            avg_obligations_per_contract: default_avg_obligations(),
4512            variable_consideration_rate: default_variable_consideration_rate(),
4513            over_time_recognition_rate: default_over_time_rate(),
4514            contract_count: default_contract_count(),
4515        }
4516    }
4517}
4518
4519/// Lease accounting configuration (ASC 842/IFRS 16).
4520#[derive(Debug, Clone, Serialize, Deserialize)]
4521pub struct LeaseAccountingConfig {
4522    /// Enable lease accounting generation
4523    #[serde(default)]
4524    pub enabled: bool,
4525
4526    /// Number of leases to generate
4527    #[serde(default = "default_lease_count")]
4528    pub lease_count: usize,
4529
4530    /// Percentage of finance leases (vs operating)
4531    #[serde(default = "default_finance_lease_pct")]
4532    pub finance_lease_percent: f64,
4533
4534    /// Average lease term in months
4535    #[serde(default = "default_avg_lease_term")]
4536    pub avg_lease_term_months: u32,
4537
4538    /// Generate amortization schedules
4539    #[serde(default = "default_true")]
4540    pub generate_amortization: bool,
4541
4542    /// Real estate lease percentage
4543    #[serde(default = "default_real_estate_pct")]
4544    pub real_estate_percent: f64,
4545}
4546
4547fn default_lease_count() -> usize {
4548    50
4549}
4550
4551fn default_finance_lease_pct() -> f64 {
4552    0.30
4553}
4554
4555fn default_avg_lease_term() -> u32 {
4556    60
4557}
4558
4559fn default_real_estate_pct() -> f64 {
4560    0.40
4561}
4562
4563impl Default for LeaseAccountingConfig {
4564    fn default() -> Self {
4565        Self {
4566            enabled: false,
4567            lease_count: default_lease_count(),
4568            finance_lease_percent: default_finance_lease_pct(),
4569            avg_lease_term_months: default_avg_lease_term(),
4570            generate_amortization: true,
4571            real_estate_percent: default_real_estate_pct(),
4572        }
4573    }
4574}
4575
4576/// Fair value measurement configuration (ASC 820/IFRS 13).
4577#[derive(Debug, Clone, Serialize, Deserialize)]
4578pub struct FairValueConfig {
4579    /// Enable fair value measurement generation
4580    #[serde(default)]
4581    pub enabled: bool,
4582
4583    /// Number of fair value measurements to generate
4584    #[serde(default = "default_fv_count")]
4585    pub measurement_count: usize,
4586
4587    /// Level 1 (quoted prices) percentage
4588    #[serde(default = "default_level1_pct")]
4589    pub level1_percent: f64,
4590
4591    /// Level 2 (observable inputs) percentage
4592    #[serde(default = "default_level2_pct")]
4593    pub level2_percent: f64,
4594
4595    /// Level 3 (unobservable inputs) percentage
4596    #[serde(default = "default_level3_pct")]
4597    pub level3_percent: f64,
4598
4599    /// Include sensitivity analysis for Level 3
4600    #[serde(default)]
4601    pub include_sensitivity_analysis: bool,
4602}
4603
4604fn default_fv_count() -> usize {
4605    25
4606}
4607
4608fn default_level1_pct() -> f64 {
4609    0.40
4610}
4611
4612fn default_level2_pct() -> f64 {
4613    0.35
4614}
4615
4616fn default_level3_pct() -> f64 {
4617    0.25
4618}
4619
4620impl Default for FairValueConfig {
4621    fn default() -> Self {
4622        Self {
4623            enabled: false,
4624            measurement_count: default_fv_count(),
4625            level1_percent: default_level1_pct(),
4626            level2_percent: default_level2_pct(),
4627            level3_percent: default_level3_pct(),
4628            include_sensitivity_analysis: false,
4629        }
4630    }
4631}
4632
4633/// Impairment testing configuration (ASC 360/IAS 36).
4634#[derive(Debug, Clone, Serialize, Deserialize)]
4635pub struct ImpairmentConfig {
4636    /// Enable impairment testing generation
4637    #[serde(default)]
4638    pub enabled: bool,
4639
4640    /// Number of impairment tests to generate
4641    #[serde(default = "default_impairment_count")]
4642    pub test_count: usize,
4643
4644    /// Rate of tests resulting in impairment
4645    #[serde(default = "default_impairment_rate")]
4646    pub impairment_rate: f64,
4647
4648    /// Generate cash flow projections
4649    #[serde(default = "default_true")]
4650    pub generate_projections: bool,
4651
4652    /// Include goodwill impairment tests
4653    #[serde(default)]
4654    pub include_goodwill: bool,
4655}
4656
4657fn default_impairment_count() -> usize {
4658    15
4659}
4660
4661fn default_impairment_rate() -> f64 {
4662    0.10
4663}
4664
4665impl Default for ImpairmentConfig {
4666    fn default() -> Self {
4667        Self {
4668            enabled: false,
4669            test_count: default_impairment_count(),
4670            impairment_rate: default_impairment_rate(),
4671            generate_projections: true,
4672            include_goodwill: false,
4673        }
4674    }
4675}
4676
4677// =============================================================================
4678// Audit Standards Configuration
4679// =============================================================================
4680
4681/// Audit standards framework configuration for generating standards-compliant audit data.
4682///
4683/// Supports ISA (International Standards on Auditing) and PCAOB standards:
4684/// - ISA 200-720: Complete coverage of audit standards
4685/// - ISA 520: Analytical Procedures
4686/// - ISA 505: External Confirmations
4687/// - ISA 700/705/706/701: Audit Reports
4688/// - PCAOB AS 2201: ICFR Auditing
4689#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4690pub struct AuditStandardsConfig {
4691    /// Enable audit standards generation
4692    #[serde(default)]
4693    pub enabled: bool,
4694
4695    /// ISA compliance configuration
4696    #[serde(default)]
4697    pub isa_compliance: IsaComplianceConfig,
4698
4699    /// Analytical procedures configuration (ISA 520)
4700    #[serde(default)]
4701    pub analytical_procedures: AnalyticalProceduresConfig,
4702
4703    /// External confirmations configuration (ISA 505)
4704    #[serde(default)]
4705    pub confirmations: ConfirmationsConfig,
4706
4707    /// Audit opinion configuration (ISA 700/705/706/701)
4708    #[serde(default)]
4709    pub opinion: AuditOpinionConfig,
4710
4711    /// Generate complete audit trail with traceability
4712    #[serde(default)]
4713    pub generate_audit_trail: bool,
4714
4715    /// SOX 302/404 compliance configuration
4716    #[serde(default)]
4717    pub sox: SoxComplianceConfig,
4718
4719    /// PCAOB-specific configuration
4720    #[serde(default)]
4721    pub pcaob: PcaobConfig,
4722}
4723
4724/// ISA compliance level configuration.
4725#[derive(Debug, Clone, Serialize, Deserialize)]
4726pub struct IsaComplianceConfig {
4727    /// Enable ISA compliance tracking
4728    #[serde(default)]
4729    pub enabled: bool,
4730
4731    /// Compliance level: "basic", "standard", "comprehensive"
4732    #[serde(default = "default_compliance_level")]
4733    pub compliance_level: String,
4734
4735    /// Generate ISA requirement mappings
4736    #[serde(default = "default_true")]
4737    pub generate_isa_mappings: bool,
4738
4739    /// Generate ISA coverage summary
4740    #[serde(default = "default_true")]
4741    pub generate_coverage_summary: bool,
4742
4743    /// Include PCAOB standard mappings (for dual framework)
4744    #[serde(default)]
4745    pub include_pcaob: bool,
4746
4747    /// Framework to use: "isa", "pcaob", "dual"
4748    #[serde(default = "default_audit_framework")]
4749    pub framework: String,
4750}
4751
4752fn default_compliance_level() -> String {
4753    "standard".to_string()
4754}
4755
4756fn default_audit_framework() -> String {
4757    "isa".to_string()
4758}
4759
4760impl Default for IsaComplianceConfig {
4761    fn default() -> Self {
4762        Self {
4763            enabled: false,
4764            compliance_level: default_compliance_level(),
4765            generate_isa_mappings: true,
4766            generate_coverage_summary: true,
4767            include_pcaob: false,
4768            framework: default_audit_framework(),
4769        }
4770    }
4771}
4772
4773/// Analytical procedures configuration (ISA 520).
4774#[derive(Debug, Clone, Serialize, Deserialize)]
4775pub struct AnalyticalProceduresConfig {
4776    /// Enable analytical procedures generation
4777    #[serde(default)]
4778    pub enabled: bool,
4779
4780    /// Number of procedures per account/area
4781    #[serde(default = "default_procedures_per_account")]
4782    pub procedures_per_account: usize,
4783
4784    /// Probability of variance exceeding threshold
4785    #[serde(default = "default_variance_probability")]
4786    pub variance_probability: f64,
4787
4788    /// Include variance investigations
4789    #[serde(default = "default_true")]
4790    pub generate_investigations: bool,
4791
4792    /// Include financial ratio analysis
4793    #[serde(default = "default_true")]
4794    pub include_ratio_analysis: bool,
4795}
4796
4797fn default_procedures_per_account() -> usize {
4798    3
4799}
4800
4801fn default_variance_probability() -> f64 {
4802    0.20
4803}
4804
4805impl Default for AnalyticalProceduresConfig {
4806    fn default() -> Self {
4807        Self {
4808            enabled: false,
4809            procedures_per_account: default_procedures_per_account(),
4810            variance_probability: default_variance_probability(),
4811            generate_investigations: true,
4812            include_ratio_analysis: true,
4813        }
4814    }
4815}
4816
4817/// External confirmations configuration (ISA 505).
4818#[derive(Debug, Clone, Serialize, Deserialize)]
4819pub struct ConfirmationsConfig {
4820    /// Enable confirmation generation
4821    #[serde(default)]
4822    pub enabled: bool,
4823
4824    /// Number of confirmations to generate
4825    #[serde(default = "default_confirmation_count")]
4826    pub confirmation_count: usize,
4827
4828    /// Positive response rate
4829    #[serde(default = "default_positive_response_rate")]
4830    pub positive_response_rate: f64,
4831
4832    /// Exception rate (responses with differences)
4833    #[serde(default = "default_exception_rate_confirm")]
4834    pub exception_rate: f64,
4835
4836    /// Non-response rate
4837    #[serde(default = "default_non_response_rate")]
4838    pub non_response_rate: f64,
4839
4840    /// Generate alternative procedures for non-responses
4841    #[serde(default = "default_true")]
4842    pub generate_alternative_procedures: bool,
4843}
4844
4845fn default_confirmation_count() -> usize {
4846    50
4847}
4848
4849fn default_positive_response_rate() -> f64 {
4850    0.85
4851}
4852
4853fn default_exception_rate_confirm() -> f64 {
4854    0.10
4855}
4856
4857fn default_non_response_rate() -> f64 {
4858    0.05
4859}
4860
4861impl Default for ConfirmationsConfig {
4862    fn default() -> Self {
4863        Self {
4864            enabled: false,
4865            confirmation_count: default_confirmation_count(),
4866            positive_response_rate: default_positive_response_rate(),
4867            exception_rate: default_exception_rate_confirm(),
4868            non_response_rate: default_non_response_rate(),
4869            generate_alternative_procedures: true,
4870        }
4871    }
4872}
4873
4874/// Audit opinion configuration (ISA 700/705/706/701).
4875#[derive(Debug, Clone, Serialize, Deserialize)]
4876pub struct AuditOpinionConfig {
4877    /// Enable audit opinion generation
4878    #[serde(default)]
4879    pub enabled: bool,
4880
4881    /// Generate Key Audit Matters (KAM) / Critical Audit Matters (CAM)
4882    #[serde(default = "default_true")]
4883    pub generate_kam: bool,
4884
4885    /// Average number of KAMs/CAMs per opinion
4886    #[serde(default = "default_kam_count")]
4887    pub average_kam_count: usize,
4888
4889    /// Rate of modified opinions
4890    #[serde(default = "default_modified_opinion_rate")]
4891    pub modified_opinion_rate: f64,
4892
4893    /// Include emphasis of matter paragraphs
4894    #[serde(default)]
4895    pub include_emphasis_of_matter: bool,
4896
4897    /// Include going concern conclusions
4898    #[serde(default = "default_true")]
4899    pub include_going_concern: bool,
4900}
4901
4902fn default_kam_count() -> usize {
4903    3
4904}
4905
4906fn default_modified_opinion_rate() -> f64 {
4907    0.05
4908}
4909
4910impl Default for AuditOpinionConfig {
4911    fn default() -> Self {
4912        Self {
4913            enabled: false,
4914            generate_kam: true,
4915            average_kam_count: default_kam_count(),
4916            modified_opinion_rate: default_modified_opinion_rate(),
4917            include_emphasis_of_matter: false,
4918            include_going_concern: true,
4919        }
4920    }
4921}
4922
4923/// SOX compliance configuration (Sections 302/404).
4924#[derive(Debug, Clone, Serialize, Deserialize)]
4925pub struct SoxComplianceConfig {
4926    /// Enable SOX compliance generation
4927    #[serde(default)]
4928    pub enabled: bool,
4929
4930    /// Generate Section 302 CEO/CFO certifications
4931    #[serde(default = "default_true")]
4932    pub generate_302_certifications: bool,
4933
4934    /// Generate Section 404 ICFR assessments
4935    #[serde(default = "default_true")]
4936    pub generate_404_assessments: bool,
4937
4938    /// Materiality threshold for SOX testing
4939    #[serde(default = "default_sox_materiality_threshold")]
4940    pub materiality_threshold: f64,
4941
4942    /// Rate of material weaknesses
4943    #[serde(default = "default_material_weakness_rate")]
4944    pub material_weakness_rate: f64,
4945
4946    /// Rate of significant deficiencies
4947    #[serde(default = "default_significant_deficiency_rate")]
4948    pub significant_deficiency_rate: f64,
4949}
4950
4951fn default_material_weakness_rate() -> f64 {
4952    0.02
4953}
4954
4955fn default_significant_deficiency_rate() -> f64 {
4956    0.08
4957}
4958
4959impl Default for SoxComplianceConfig {
4960    fn default() -> Self {
4961        Self {
4962            enabled: false,
4963            generate_302_certifications: true,
4964            generate_404_assessments: true,
4965            materiality_threshold: default_sox_materiality_threshold(),
4966            material_weakness_rate: default_material_weakness_rate(),
4967            significant_deficiency_rate: default_significant_deficiency_rate(),
4968        }
4969    }
4970}
4971
4972/// PCAOB-specific configuration.
4973#[derive(Debug, Clone, Serialize, Deserialize)]
4974pub struct PcaobConfig {
4975    /// Enable PCAOB-specific elements
4976    #[serde(default)]
4977    pub enabled: bool,
4978
4979    /// Treat as PCAOB audit (vs ISA-only)
4980    #[serde(default)]
4981    pub is_pcaob_audit: bool,
4982
4983    /// Generate Critical Audit Matters (CAM)
4984    #[serde(default = "default_true")]
4985    pub generate_cam: bool,
4986
4987    /// Include ICFR opinion (for integrated audits)
4988    #[serde(default)]
4989    pub include_icfr_opinion: bool,
4990
4991    /// Generate PCAOB-ISA standard mappings
4992    #[serde(default)]
4993    pub generate_standard_mappings: bool,
4994}
4995
4996impl Default for PcaobConfig {
4997    fn default() -> Self {
4998        Self {
4999            enabled: false,
5000            is_pcaob_audit: false,
5001            generate_cam: true,
5002            include_icfr_opinion: false,
5003            generate_standard_mappings: false,
5004        }
5005    }
5006}
5007
5008// =============================================================================
5009// Advanced Distribution Configuration
5010// =============================================================================
5011
5012/// Advanced distribution configuration for realistic data generation.
5013///
5014/// This section enables sophisticated distribution models including:
5015/// - Mixture models (multi-modal distributions)
5016/// - Cross-field correlations
5017/// - Conditional distributions
5018/// - Regime changes and economic cycles
5019/// - Statistical validation
5020#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5021pub struct AdvancedDistributionConfig {
5022    /// Enable advanced distribution features.
5023    #[serde(default)]
5024    pub enabled: bool,
5025
5026    /// Mixture model configuration for amounts.
5027    #[serde(default)]
5028    pub amounts: MixtureDistributionSchemaConfig,
5029
5030    /// Cross-field correlation configuration.
5031    #[serde(default)]
5032    pub correlations: CorrelationSchemaConfig,
5033
5034    /// Conditional distribution configurations.
5035    #[serde(default)]
5036    pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5037
5038    /// Regime change configuration.
5039    #[serde(default)]
5040    pub regime_changes: RegimeChangeSchemaConfig,
5041
5042    /// Industry-specific distribution profile.
5043    #[serde(default)]
5044    pub industry_profile: Option<IndustryProfileType>,
5045
5046    /// Statistical validation configuration.
5047    #[serde(default)]
5048    pub validation: StatisticalValidationSchemaConfig,
5049}
5050
5051/// Industry profile types for pre-configured distribution settings.
5052#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5053#[serde(rename_all = "snake_case")]
5054pub enum IndustryProfileType {
5055    /// Retail industry profile (POS sales, inventory, seasonal)
5056    Retail,
5057    /// Manufacturing industry profile (raw materials, maintenance, capital)
5058    Manufacturing,
5059    /// Financial services profile (wire transfers, ACH, fee income)
5060    FinancialServices,
5061    /// Healthcare profile (claims, procedures, supplies)
5062    Healthcare,
5063    /// Technology profile (subscriptions, services, R&D)
5064    Technology,
5065}
5066
5067/// Mixture model distribution configuration.
5068#[derive(Debug, Clone, Serialize, Deserialize)]
5069pub struct MixtureDistributionSchemaConfig {
5070    /// Enable mixture model for amount generation.
5071    #[serde(default)]
5072    pub enabled: bool,
5073
5074    /// Distribution type: "gaussian" or "lognormal".
5075    #[serde(default = "default_mixture_type")]
5076    pub distribution_type: MixtureDistributionType,
5077
5078    /// Mixture components with weights.
5079    #[serde(default)]
5080    pub components: Vec<MixtureComponentConfig>,
5081
5082    /// Minimum value constraint.
5083    #[serde(default = "default_min_amount")]
5084    pub min_value: f64,
5085
5086    /// Maximum value constraint (optional).
5087    #[serde(default)]
5088    pub max_value: Option<f64>,
5089
5090    /// Decimal places for rounding.
5091    #[serde(default = "default_decimal_places")]
5092    pub decimal_places: u8,
5093}
5094
5095fn default_mixture_type() -> MixtureDistributionType {
5096    MixtureDistributionType::LogNormal
5097}
5098
5099fn default_min_amount() -> f64 {
5100    0.01
5101}
5102
5103fn default_decimal_places() -> u8 {
5104    2
5105}
5106
5107impl Default for MixtureDistributionSchemaConfig {
5108    fn default() -> Self {
5109        Self {
5110            enabled: false,
5111            distribution_type: MixtureDistributionType::LogNormal,
5112            components: Vec::new(),
5113            min_value: 0.01,
5114            max_value: None,
5115            decimal_places: 2,
5116        }
5117    }
5118}
5119
5120/// Mixture distribution type.
5121#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5122#[serde(rename_all = "snake_case")]
5123pub enum MixtureDistributionType {
5124    /// Gaussian (normal) mixture
5125    Gaussian,
5126    /// Log-normal mixture (for positive amounts)
5127    #[default]
5128    LogNormal,
5129}
5130
5131/// Configuration for a single mixture component.
5132#[derive(Debug, Clone, Serialize, Deserialize)]
5133pub struct MixtureComponentConfig {
5134    /// Weight of this component (must sum to 1.0 across all components).
5135    pub weight: f64,
5136
5137    /// Location parameter (mean for Gaussian, mu for log-normal).
5138    pub mu: f64,
5139
5140    /// Scale parameter (std dev for Gaussian, sigma for log-normal).
5141    pub sigma: f64,
5142
5143    /// Optional label for this component (e.g., "routine", "significant", "major").
5144    #[serde(default)]
5145    pub label: Option<String>,
5146}
5147
5148/// Cross-field correlation configuration.
5149#[derive(Debug, Clone, Serialize, Deserialize)]
5150pub struct CorrelationSchemaConfig {
5151    /// Enable correlation modeling.
5152    #[serde(default)]
5153    pub enabled: bool,
5154
5155    /// Copula type for dependency modeling.
5156    #[serde(default)]
5157    pub copula_type: CopulaSchemaType,
5158
5159    /// Field definitions for correlation.
5160    #[serde(default)]
5161    pub fields: Vec<CorrelatedFieldConfig>,
5162
5163    /// Correlation matrix (upper triangular, row-major).
5164    /// For n fields, this should have n*(n-1)/2 values.
5165    #[serde(default)]
5166    pub matrix: Vec<f64>,
5167
5168    /// Expected correlations for validation.
5169    #[serde(default)]
5170    pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5171}
5172
5173impl Default for CorrelationSchemaConfig {
5174    fn default() -> Self {
5175        Self {
5176            enabled: false,
5177            copula_type: CopulaSchemaType::Gaussian,
5178            fields: Vec::new(),
5179            matrix: Vec::new(),
5180            expected_correlations: Vec::new(),
5181        }
5182    }
5183}
5184
5185/// Copula type for dependency modeling.
5186#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5187#[serde(rename_all = "snake_case")]
5188pub enum CopulaSchemaType {
5189    /// Gaussian copula (symmetric, no tail dependence)
5190    #[default]
5191    Gaussian,
5192    /// Clayton copula (lower tail dependence)
5193    Clayton,
5194    /// Gumbel copula (upper tail dependence)
5195    Gumbel,
5196    /// Frank copula (symmetric, no tail dependence)
5197    Frank,
5198    /// Student-t copula (both tail dependencies)
5199    StudentT,
5200}
5201
5202/// Configuration for a correlated field.
5203#[derive(Debug, Clone, Serialize, Deserialize)]
5204pub struct CorrelatedFieldConfig {
5205    /// Field name.
5206    pub name: String,
5207
5208    /// Marginal distribution type.
5209    #[serde(default)]
5210    pub distribution: MarginalDistributionConfig,
5211}
5212
5213/// Marginal distribution configuration.
5214#[derive(Debug, Clone, Serialize, Deserialize)]
5215#[serde(tag = "type", rename_all = "snake_case")]
5216pub enum MarginalDistributionConfig {
5217    /// Normal distribution.
5218    Normal {
5219        /// Mean
5220        mu: f64,
5221        /// Standard deviation
5222        sigma: f64,
5223    },
5224    /// Log-normal distribution.
5225    LogNormal {
5226        /// Location parameter
5227        mu: f64,
5228        /// Scale parameter
5229        sigma: f64,
5230    },
5231    /// Uniform distribution.
5232    Uniform {
5233        /// Minimum value
5234        min: f64,
5235        /// Maximum value
5236        max: f64,
5237    },
5238    /// Discrete uniform distribution.
5239    DiscreteUniform {
5240        /// Minimum integer value
5241        min: i32,
5242        /// Maximum integer value
5243        max: i32,
5244    },
5245}
5246
5247impl Default for MarginalDistributionConfig {
5248    fn default() -> Self {
5249        Self::Normal {
5250            mu: 0.0,
5251            sigma: 1.0,
5252        }
5253    }
5254}
5255
5256/// Expected correlation for validation.
5257#[derive(Debug, Clone, Serialize, Deserialize)]
5258pub struct ExpectedCorrelationConfig {
5259    /// First field name.
5260    pub field1: String,
5261    /// Second field name.
5262    pub field2: String,
5263    /// Expected correlation coefficient.
5264    pub expected_r: f64,
5265    /// Acceptable tolerance.
5266    #[serde(default = "default_correlation_tolerance")]
5267    pub tolerance: f64,
5268}
5269
5270fn default_correlation_tolerance() -> f64 {
5271    0.10
5272}
5273
5274/// Conditional distribution configuration.
5275#[derive(Debug, Clone, Serialize, Deserialize)]
5276pub struct ConditionalDistributionSchemaConfig {
5277    /// Output field name to generate.
5278    pub output_field: String,
5279
5280    /// Input field name that conditions the distribution.
5281    pub input_field: String,
5282
5283    /// Breakpoints defining distribution changes.
5284    #[serde(default)]
5285    pub breakpoints: Vec<ConditionalBreakpointConfig>,
5286
5287    /// Default distribution when below all breakpoints.
5288    #[serde(default)]
5289    pub default_distribution: ConditionalDistributionParamsConfig,
5290
5291    /// Minimum output value constraint.
5292    #[serde(default)]
5293    pub min_value: Option<f64>,
5294
5295    /// Maximum output value constraint.
5296    #[serde(default)]
5297    pub max_value: Option<f64>,
5298
5299    /// Decimal places for output rounding.
5300    #[serde(default = "default_decimal_places")]
5301    pub decimal_places: u8,
5302}
5303
5304/// Breakpoint for conditional distribution.
5305#[derive(Debug, Clone, Serialize, Deserialize)]
5306pub struct ConditionalBreakpointConfig {
5307    /// Input value threshold.
5308    pub threshold: f64,
5309
5310    /// Distribution to use when input >= threshold.
5311    pub distribution: ConditionalDistributionParamsConfig,
5312}
5313
5314/// Distribution parameters for conditional distributions.
5315#[derive(Debug, Clone, Serialize, Deserialize)]
5316#[serde(tag = "type", rename_all = "snake_case")]
5317pub enum ConditionalDistributionParamsConfig {
5318    /// Fixed value.
5319    Fixed {
5320        /// The fixed value
5321        value: f64,
5322    },
5323    /// Normal distribution.
5324    Normal {
5325        /// Mean
5326        mu: f64,
5327        /// Standard deviation
5328        sigma: f64,
5329    },
5330    /// Log-normal distribution.
5331    LogNormal {
5332        /// Location parameter
5333        mu: f64,
5334        /// Scale parameter
5335        sigma: f64,
5336    },
5337    /// Uniform distribution.
5338    Uniform {
5339        /// Minimum
5340        min: f64,
5341        /// Maximum
5342        max: f64,
5343    },
5344    /// Beta distribution (scaled).
5345    Beta {
5346        /// Alpha parameter
5347        alpha: f64,
5348        /// Beta parameter
5349        beta: f64,
5350        /// Minimum output value
5351        min: f64,
5352        /// Maximum output value
5353        max: f64,
5354    },
5355    /// Discrete values with weights.
5356    Discrete {
5357        /// Possible values
5358        values: Vec<f64>,
5359        /// Weights (should sum to 1.0)
5360        weights: Vec<f64>,
5361    },
5362}
5363
5364impl Default for ConditionalDistributionParamsConfig {
5365    fn default() -> Self {
5366        Self::Normal {
5367            mu: 0.0,
5368            sigma: 1.0,
5369        }
5370    }
5371}
5372
5373/// Regime change configuration.
5374#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5375pub struct RegimeChangeSchemaConfig {
5376    /// Enable regime change modeling.
5377    #[serde(default)]
5378    pub enabled: bool,
5379
5380    /// List of regime changes.
5381    #[serde(default)]
5382    pub changes: Vec<RegimeChangeEventConfig>,
5383
5384    /// Economic cycle configuration.
5385    #[serde(default)]
5386    pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5387
5388    /// Parameter drift configurations.
5389    #[serde(default)]
5390    pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5391}
5392
5393/// A single regime change event.
5394#[derive(Debug, Clone, Serialize, Deserialize)]
5395pub struct RegimeChangeEventConfig {
5396    /// Date when the change occurs (ISO 8601 format).
5397    pub date: String,
5398
5399    /// Type of regime change.
5400    pub change_type: RegimeChangeTypeConfig,
5401
5402    /// Description of the change.
5403    #[serde(default)]
5404    pub description: Option<String>,
5405
5406    /// Effects of this regime change.
5407    #[serde(default)]
5408    pub effects: Vec<RegimeEffectConfig>,
5409}
5410
5411/// Type of regime change.
5412#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5413#[serde(rename_all = "snake_case")]
5414pub enum RegimeChangeTypeConfig {
5415    /// Acquisition - sudden volume and amount increase
5416    Acquisition,
5417    /// Divestiture - sudden volume and amount decrease
5418    Divestiture,
5419    /// Price increase - amounts increase
5420    PriceIncrease,
5421    /// Price decrease - amounts decrease
5422    PriceDecrease,
5423    /// New product launch - volume ramp-up
5424    ProductLaunch,
5425    /// Product discontinuation - volume ramp-down
5426    ProductDiscontinuation,
5427    /// Policy change - affects patterns
5428    PolicyChange,
5429    /// Competitor entry - market disruption
5430    CompetitorEntry,
5431    /// Custom effect
5432    Custom,
5433}
5434
5435/// Effect of a regime change on a specific field.
5436#[derive(Debug, Clone, Serialize, Deserialize)]
5437pub struct RegimeEffectConfig {
5438    /// Field being affected.
5439    pub field: String,
5440
5441    /// Multiplier to apply (1.0 = no change, 1.5 = 50% increase).
5442    pub multiplier: f64,
5443}
5444
5445/// Economic cycle configuration.
5446#[derive(Debug, Clone, Serialize, Deserialize)]
5447pub struct EconomicCycleSchemaConfig {
5448    /// Enable economic cycle modeling.
5449    #[serde(default)]
5450    pub enabled: bool,
5451
5452    /// Cycle period in months (e.g., 48 for 4-year business cycle).
5453    #[serde(default = "default_cycle_period")]
5454    pub period_months: u32,
5455
5456    /// Amplitude of cycle effect (0.0-1.0).
5457    #[serde(default = "default_cycle_amplitude")]
5458    pub amplitude: f64,
5459
5460    /// Phase offset in months.
5461    #[serde(default)]
5462    pub phase_offset: u32,
5463
5464    /// Recession periods (start_month, duration_months).
5465    #[serde(default)]
5466    pub recessions: Vec<RecessionPeriodConfig>,
5467}
5468
5469fn default_cycle_period() -> u32 {
5470    48
5471}
5472
5473fn default_cycle_amplitude() -> f64 {
5474    0.15
5475}
5476
5477impl Default for EconomicCycleSchemaConfig {
5478    fn default() -> Self {
5479        Self {
5480            enabled: false,
5481            period_months: 48,
5482            amplitude: 0.15,
5483            phase_offset: 0,
5484            recessions: Vec::new(),
5485        }
5486    }
5487}
5488
5489/// Recession period configuration.
5490#[derive(Debug, Clone, Serialize, Deserialize)]
5491pub struct RecessionPeriodConfig {
5492    /// Start month (0-indexed from generation start).
5493    pub start_month: u32,
5494
5495    /// Duration in months.
5496    pub duration_months: u32,
5497
5498    /// Severity (0.0-1.0, affects volume reduction).
5499    #[serde(default = "default_recession_severity")]
5500    pub severity: f64,
5501}
5502
5503fn default_recession_severity() -> f64 {
5504    0.20
5505}
5506
5507/// Parameter drift configuration.
5508#[derive(Debug, Clone, Serialize, Deserialize)]
5509pub struct ParameterDriftSchemaConfig {
5510    /// Parameter being drifted.
5511    pub parameter: String,
5512
5513    /// Drift type.
5514    pub drift_type: ParameterDriftTypeConfig,
5515
5516    /// Start value.
5517    pub start_value: f64,
5518
5519    /// End value.
5520    pub end_value: f64,
5521
5522    /// Start period (month, 0-indexed).
5523    #[serde(default)]
5524    pub start_period: u32,
5525
5526    /// End period (month, optional - defaults to end of generation).
5527    #[serde(default)]
5528    pub end_period: Option<u32>,
5529}
5530
5531/// Parameter drift type.
5532#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5533#[serde(rename_all = "snake_case")]
5534pub enum ParameterDriftTypeConfig {
5535    /// Linear interpolation
5536    #[default]
5537    Linear,
5538    /// Exponential growth/decay
5539    Exponential,
5540    /// S-curve (logistic)
5541    Logistic,
5542    /// Step function
5543    Step,
5544}
5545
5546/// Statistical validation configuration.
5547#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5548pub struct StatisticalValidationSchemaConfig {
5549    /// Enable statistical validation.
5550    #[serde(default)]
5551    pub enabled: bool,
5552
5553    /// Statistical tests to run.
5554    #[serde(default)]
5555    pub tests: Vec<StatisticalTestConfig>,
5556
5557    /// Validation reporting configuration.
5558    #[serde(default)]
5559    pub reporting: ValidationReportingConfig,
5560}
5561
5562/// Statistical test configuration.
5563#[derive(Debug, Clone, Serialize, Deserialize)]
5564#[serde(tag = "type", rename_all = "snake_case")]
5565pub enum StatisticalTestConfig {
5566    /// Benford's Law first digit test.
5567    BenfordFirstDigit {
5568        /// Threshold MAD for failure.
5569        #[serde(default = "default_benford_threshold")]
5570        threshold_mad: f64,
5571        /// Warning MAD threshold.
5572        #[serde(default = "default_benford_warning")]
5573        warning_mad: f64,
5574    },
5575    /// Distribution fit test.
5576    DistributionFit {
5577        /// Target distribution to test.
5578        target: TargetDistributionConfig,
5579        /// K-S test significance level.
5580        #[serde(default = "default_ks_significance")]
5581        ks_significance: f64,
5582        /// Test method (ks, anderson_darling, chi_squared).
5583        #[serde(default)]
5584        method: DistributionFitMethod,
5585    },
5586    /// Correlation check.
5587    CorrelationCheck {
5588        /// Expected correlations to validate.
5589        expected_correlations: Vec<ExpectedCorrelationConfig>,
5590    },
5591    /// Chi-squared test.
5592    ChiSquared {
5593        /// Number of bins.
5594        #[serde(default = "default_chi_squared_bins")]
5595        bins: usize,
5596        /// Significance level.
5597        #[serde(default = "default_chi_squared_significance")]
5598        significance: f64,
5599    },
5600    /// Anderson-Darling test.
5601    AndersonDarling {
5602        /// Target distribution.
5603        target: TargetDistributionConfig,
5604        /// Significance level.
5605        #[serde(default = "default_ad_significance")]
5606        significance: f64,
5607    },
5608}
5609
5610fn default_benford_threshold() -> f64 {
5611    0.015
5612}
5613
5614fn default_benford_warning() -> f64 {
5615    0.010
5616}
5617
5618fn default_ks_significance() -> f64 {
5619    0.05
5620}
5621
5622fn default_chi_squared_bins() -> usize {
5623    10
5624}
5625
5626fn default_chi_squared_significance() -> f64 {
5627    0.05
5628}
5629
5630fn default_ad_significance() -> f64 {
5631    0.05
5632}
5633
5634/// Target distribution for fit tests.
5635#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5636#[serde(rename_all = "snake_case")]
5637pub enum TargetDistributionConfig {
5638    /// Normal distribution
5639    Normal,
5640    /// Log-normal distribution
5641    #[default]
5642    LogNormal,
5643    /// Exponential distribution
5644    Exponential,
5645    /// Uniform distribution
5646    Uniform,
5647}
5648
5649/// Distribution fit test method.
5650#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5651#[serde(rename_all = "snake_case")]
5652pub enum DistributionFitMethod {
5653    /// Kolmogorov-Smirnov test
5654    #[default]
5655    KolmogorovSmirnov,
5656    /// Anderson-Darling test
5657    AndersonDarling,
5658    /// Chi-squared test
5659    ChiSquared,
5660}
5661
5662/// Validation reporting configuration.
5663#[derive(Debug, Clone, Serialize, Deserialize)]
5664pub struct ValidationReportingConfig {
5665    /// Output validation report to file.
5666    #[serde(default)]
5667    pub output_report: bool,
5668
5669    /// Report format.
5670    #[serde(default)]
5671    pub format: ValidationReportFormat,
5672
5673    /// Fail generation if validation fails.
5674    #[serde(default)]
5675    pub fail_on_error: bool,
5676
5677    /// Include detailed statistics in report.
5678    #[serde(default = "default_true")]
5679    pub include_details: bool,
5680}
5681
5682impl Default for ValidationReportingConfig {
5683    fn default() -> Self {
5684        Self {
5685            output_report: false,
5686            format: ValidationReportFormat::Json,
5687            fail_on_error: false,
5688            include_details: true,
5689        }
5690    }
5691}
5692
5693/// Validation report format.
5694#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5695#[serde(rename_all = "snake_case")]
5696pub enum ValidationReportFormat {
5697    /// JSON format
5698    #[default]
5699    Json,
5700    /// YAML format
5701    Yaml,
5702    /// HTML report
5703    Html,
5704}
5705
5706// =============================================================================
5707// Temporal Patterns Configuration
5708// =============================================================================
5709
5710/// Temporal patterns configuration for business days, period-end dynamics, and processing lags.
5711///
5712/// This section enables sophisticated temporal modeling including:
5713/// - Business day calculations and settlement dates
5714/// - Regional holiday calendars
5715/// - Period-end decay curves (non-flat volume spikes)
5716/// - Processing lag modeling (event-to-posting delays)
5717#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5718pub struct TemporalPatternsConfig {
5719    /// Enable temporal patterns features.
5720    #[serde(default)]
5721    pub enabled: bool,
5722
5723    /// Business day calculation configuration.
5724    #[serde(default)]
5725    pub business_days: BusinessDaySchemaConfig,
5726
5727    /// Regional calendar configuration.
5728    #[serde(default)]
5729    pub calendars: CalendarSchemaConfig,
5730
5731    /// Period-end dynamics configuration.
5732    #[serde(default)]
5733    pub period_end: PeriodEndSchemaConfig,
5734
5735    /// Processing lag configuration.
5736    #[serde(default)]
5737    pub processing_lags: ProcessingLagSchemaConfig,
5738
5739    /// Fiscal calendar configuration (custom year start, 4-4-5, 13-period).
5740    #[serde(default)]
5741    pub fiscal_calendar: FiscalCalendarSchemaConfig,
5742
5743    /// Intra-day patterns configuration (morning spike, lunch dip, EOD rush).
5744    #[serde(default)]
5745    pub intraday: IntraDaySchemaConfig,
5746
5747    /// Timezone handling configuration.
5748    #[serde(default)]
5749    pub timezones: TimezoneSchemaConfig,
5750}
5751
5752/// Business day calculation configuration.
5753#[derive(Debug, Clone, Serialize, Deserialize)]
5754pub struct BusinessDaySchemaConfig {
5755    /// Enable business day calculations.
5756    #[serde(default = "default_true")]
5757    pub enabled: bool,
5758
5759    /// Half-day policy: "full_day", "half_day", "non_business_day".
5760    #[serde(default = "default_half_day_policy")]
5761    pub half_day_policy: String,
5762
5763    /// Settlement rules configuration.
5764    #[serde(default)]
5765    pub settlement_rules: SettlementRulesSchemaConfig,
5766
5767    /// Month-end convention: "modified_following", "preceding", "following", "end_of_month".
5768    #[serde(default = "default_month_end_convention")]
5769    pub month_end_convention: String,
5770
5771    /// Weekend days (e.g., ["saturday", "sunday"] or ["friday", "saturday"] for Middle East).
5772    #[serde(default)]
5773    pub weekend_days: Option<Vec<String>>,
5774}
5775
5776fn default_half_day_policy() -> String {
5777    "half_day".to_string()
5778}
5779
5780fn default_month_end_convention() -> String {
5781    "modified_following".to_string()
5782}
5783
5784impl Default for BusinessDaySchemaConfig {
5785    fn default() -> Self {
5786        Self {
5787            enabled: true,
5788            half_day_policy: "half_day".to_string(),
5789            settlement_rules: SettlementRulesSchemaConfig::default(),
5790            month_end_convention: "modified_following".to_string(),
5791            weekend_days: None,
5792        }
5793    }
5794}
5795
5796/// Settlement rules configuration.
5797#[derive(Debug, Clone, Serialize, Deserialize)]
5798pub struct SettlementRulesSchemaConfig {
5799    /// Equity settlement days (T+N).
5800    #[serde(default = "default_settlement_2")]
5801    pub equity_days: i32,
5802
5803    /// Government bonds settlement days.
5804    #[serde(default = "default_settlement_1")]
5805    pub government_bonds_days: i32,
5806
5807    /// FX spot settlement days.
5808    #[serde(default = "default_settlement_2")]
5809    pub fx_spot_days: i32,
5810
5811    /// Corporate bonds settlement days.
5812    #[serde(default = "default_settlement_2")]
5813    pub corporate_bonds_days: i32,
5814
5815    /// Wire transfer cutoff time (HH:MM format).
5816    #[serde(default = "default_wire_cutoff")]
5817    pub wire_cutoff_time: String,
5818
5819    /// International wire settlement days.
5820    #[serde(default = "default_settlement_1")]
5821    pub wire_international_days: i32,
5822
5823    /// ACH settlement days.
5824    #[serde(default = "default_settlement_1")]
5825    pub ach_days: i32,
5826}
5827
5828fn default_settlement_1() -> i32 {
5829    1
5830}
5831
5832fn default_settlement_2() -> i32 {
5833    2
5834}
5835
5836fn default_wire_cutoff() -> String {
5837    "14:00".to_string()
5838}
5839
5840impl Default for SettlementRulesSchemaConfig {
5841    fn default() -> Self {
5842        Self {
5843            equity_days: 2,
5844            government_bonds_days: 1,
5845            fx_spot_days: 2,
5846            corporate_bonds_days: 2,
5847            wire_cutoff_time: "14:00".to_string(),
5848            wire_international_days: 1,
5849            ach_days: 1,
5850        }
5851    }
5852}
5853
5854/// Regional calendar configuration.
5855#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5856pub struct CalendarSchemaConfig {
5857    /// List of regions to include (e.g., ["US", "DE", "BR", "SG", "KR"]).
5858    #[serde(default)]
5859    pub regions: Vec<String>,
5860
5861    /// Custom holidays (in addition to regional calendars).
5862    #[serde(default)]
5863    pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
5864}
5865
5866/// Custom holiday configuration.
5867#[derive(Debug, Clone, Serialize, Deserialize)]
5868pub struct CustomHolidaySchemaConfig {
5869    /// Holiday name.
5870    pub name: String,
5871    /// Month (1-12).
5872    pub month: u8,
5873    /// Day of month.
5874    pub day: u8,
5875    /// Activity multiplier (0.0-1.0, default 0.05).
5876    #[serde(default = "default_holiday_multiplier")]
5877    pub activity_multiplier: f64,
5878}
5879
5880fn default_holiday_multiplier() -> f64 {
5881    0.05
5882}
5883
5884/// Period-end dynamics configuration.
5885#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5886pub struct PeriodEndSchemaConfig {
5887    /// Model type: "flat", "exponential", "extended_crunch", "daily_profile".
5888    #[serde(default)]
5889    pub model: Option<String>,
5890
5891    /// Month-end configuration.
5892    #[serde(default)]
5893    pub month_end: Option<PeriodEndModelSchemaConfig>,
5894
5895    /// Quarter-end configuration.
5896    #[serde(default)]
5897    pub quarter_end: Option<PeriodEndModelSchemaConfig>,
5898
5899    /// Year-end configuration.
5900    #[serde(default)]
5901    pub year_end: Option<PeriodEndModelSchemaConfig>,
5902}
5903
5904/// Period-end model configuration.
5905#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5906pub struct PeriodEndModelSchemaConfig {
5907    /// Inherit configuration from another period (e.g., "month_end").
5908    #[serde(default)]
5909    pub inherit_from: Option<String>,
5910
5911    /// Additional multiplier on top of inherited/base model.
5912    #[serde(default)]
5913    pub additional_multiplier: Option<f64>,
5914
5915    /// Days before period end to start acceleration (negative, e.g., -10).
5916    #[serde(default)]
5917    pub start_day: Option<i32>,
5918
5919    /// Base multiplier at start of acceleration.
5920    #[serde(default)]
5921    pub base_multiplier: Option<f64>,
5922
5923    /// Peak multiplier on last day.
5924    #[serde(default)]
5925    pub peak_multiplier: Option<f64>,
5926
5927    /// Decay rate for exponential model (0.1-0.5 typical).
5928    #[serde(default)]
5929    pub decay_rate: Option<f64>,
5930
5931    /// Sustained high days for crunch model.
5932    #[serde(default)]
5933    pub sustained_high_days: Option<i32>,
5934}
5935
5936/// Processing lag configuration.
5937#[derive(Debug, Clone, Serialize, Deserialize)]
5938pub struct ProcessingLagSchemaConfig {
5939    /// Enable processing lag calculations.
5940    #[serde(default = "default_true")]
5941    pub enabled: bool,
5942
5943    /// Sales order lag configuration (log-normal mu, sigma).
5944    #[serde(default)]
5945    pub sales_order_lag: Option<LagDistributionSchemaConfig>,
5946
5947    /// Purchase order lag configuration.
5948    #[serde(default)]
5949    pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
5950
5951    /// Goods receipt lag configuration.
5952    #[serde(default)]
5953    pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
5954
5955    /// Invoice receipt lag configuration.
5956    #[serde(default)]
5957    pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
5958
5959    /// Invoice issue lag configuration.
5960    #[serde(default)]
5961    pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
5962
5963    /// Payment lag configuration.
5964    #[serde(default)]
5965    pub payment_lag: Option<LagDistributionSchemaConfig>,
5966
5967    /// Journal entry lag configuration.
5968    #[serde(default)]
5969    pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
5970
5971    /// Cross-day posting configuration.
5972    #[serde(default)]
5973    pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
5974}
5975
5976impl Default for ProcessingLagSchemaConfig {
5977    fn default() -> Self {
5978        Self {
5979            enabled: true,
5980            sales_order_lag: None,
5981            purchase_order_lag: None,
5982            goods_receipt_lag: None,
5983            invoice_receipt_lag: None,
5984            invoice_issue_lag: None,
5985            payment_lag: None,
5986            journal_entry_lag: None,
5987            cross_day_posting: None,
5988        }
5989    }
5990}
5991
5992/// Lag distribution configuration (log-normal parameters).
5993#[derive(Debug, Clone, Serialize, Deserialize)]
5994pub struct LagDistributionSchemaConfig {
5995    /// Log-scale mean (mu for log-normal).
5996    pub mu: f64,
5997    /// Log-scale standard deviation (sigma for log-normal).
5998    pub sigma: f64,
5999    /// Minimum lag in hours.
6000    #[serde(default)]
6001    pub min_hours: Option<f64>,
6002    /// Maximum lag in hours.
6003    #[serde(default)]
6004    pub max_hours: Option<f64>,
6005}
6006
6007/// Cross-day posting configuration.
6008#[derive(Debug, Clone, Serialize, Deserialize)]
6009pub struct CrossDayPostingSchemaConfig {
6010    /// Enable cross-day posting logic.
6011    #[serde(default = "default_true")]
6012    pub enabled: bool,
6013
6014    /// Probability of next-day posting by hour (map of hour -> probability).
6015    /// E.g., { 17: 0.7, 19: 0.9, 21: 0.99 }
6016    #[serde(default)]
6017    pub probability_by_hour: std::collections::HashMap<u8, f64>,
6018}
6019
6020impl Default for CrossDayPostingSchemaConfig {
6021    fn default() -> Self {
6022        let mut probability_by_hour = std::collections::HashMap::new();
6023        probability_by_hour.insert(17, 0.3);
6024        probability_by_hour.insert(18, 0.6);
6025        probability_by_hour.insert(19, 0.8);
6026        probability_by_hour.insert(20, 0.9);
6027        probability_by_hour.insert(21, 0.95);
6028        probability_by_hour.insert(22, 0.99);
6029
6030        Self {
6031            enabled: true,
6032            probability_by_hour,
6033        }
6034    }
6035}
6036
6037// =============================================================================
6038// Fiscal Calendar Configuration (P2)
6039// =============================================================================
6040
6041/// Fiscal calendar configuration.
6042///
6043/// Supports calendar year, custom year start, 4-4-5 retail calendar,
6044/// and 13-period calendars.
6045#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6046pub struct FiscalCalendarSchemaConfig {
6047    /// Enable non-standard fiscal calendar.
6048    #[serde(default)]
6049    pub enabled: bool,
6050
6051    /// Fiscal calendar type: "calendar_year", "custom", "four_four_five", "thirteen_period".
6052    #[serde(default = "default_fiscal_calendar_type")]
6053    pub calendar_type: String,
6054
6055    /// Month the fiscal year starts (1-12). Used for custom year start.
6056    #[serde(default)]
6057    pub year_start_month: Option<u8>,
6058
6059    /// Day the fiscal year starts (1-31). Used for custom year start.
6060    #[serde(default)]
6061    pub year_start_day: Option<u8>,
6062
6063    /// 4-4-5 calendar configuration (if calendar_type is "four_four_five").
6064    #[serde(default)]
6065    pub four_four_five: Option<FourFourFiveSchemaConfig>,
6066}
6067
6068fn default_fiscal_calendar_type() -> String {
6069    "calendar_year".to_string()
6070}
6071
6072/// 4-4-5 retail calendar configuration.
6073#[derive(Debug, Clone, Serialize, Deserialize)]
6074pub struct FourFourFiveSchemaConfig {
6075    /// Week pattern: "four_four_five", "four_five_four", "five_four_four".
6076    #[serde(default = "default_week_pattern")]
6077    pub pattern: String,
6078
6079    /// Anchor type: "first_sunday", "last_saturday", "nearest_saturday".
6080    #[serde(default = "default_anchor_type")]
6081    pub anchor_type: String,
6082
6083    /// Anchor month (1-12).
6084    #[serde(default = "default_anchor_month")]
6085    pub anchor_month: u8,
6086
6087    /// Where to place leap week: "q4_period3" or "q1_period1".
6088    #[serde(default = "default_leap_week_placement")]
6089    pub leap_week_placement: String,
6090}
6091
6092fn default_week_pattern() -> String {
6093    "four_four_five".to_string()
6094}
6095
6096fn default_anchor_type() -> String {
6097    "last_saturday".to_string()
6098}
6099
6100fn default_anchor_month() -> u8 {
6101    1 // January
6102}
6103
6104fn default_leap_week_placement() -> String {
6105    "q4_period3".to_string()
6106}
6107
6108impl Default for FourFourFiveSchemaConfig {
6109    fn default() -> Self {
6110        Self {
6111            pattern: "four_four_five".to_string(),
6112            anchor_type: "last_saturday".to_string(),
6113            anchor_month: 1,
6114            leap_week_placement: "q4_period3".to_string(),
6115        }
6116    }
6117}
6118
6119// =============================================================================
6120// Intra-Day Patterns Configuration (P2)
6121// =============================================================================
6122
6123/// Intra-day patterns configuration.
6124///
6125/// Defines time-of-day segments with different activity multipliers
6126/// for realistic modeling of morning spikes, lunch dips, and end-of-day rushes.
6127#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6128pub struct IntraDaySchemaConfig {
6129    /// Enable intra-day patterns.
6130    #[serde(default)]
6131    pub enabled: bool,
6132
6133    /// Custom intra-day segments.
6134    #[serde(default)]
6135    pub segments: Vec<IntraDaySegmentSchemaConfig>,
6136}
6137
6138/// Intra-day segment configuration.
6139#[derive(Debug, Clone, Serialize, Deserialize)]
6140pub struct IntraDaySegmentSchemaConfig {
6141    /// Name of the segment (e.g., "morning_spike", "lunch_dip").
6142    pub name: String,
6143
6144    /// Start time (HH:MM format).
6145    pub start: String,
6146
6147    /// End time (HH:MM format).
6148    pub end: String,
6149
6150    /// Activity multiplier (1.0 = normal).
6151    #[serde(default = "default_multiplier")]
6152    pub multiplier: f64,
6153
6154    /// Posting type: "human", "system", "both".
6155    #[serde(default = "default_posting_type")]
6156    pub posting_type: String,
6157}
6158
6159fn default_multiplier() -> f64 {
6160    1.0
6161}
6162
6163fn default_posting_type() -> String {
6164    "both".to_string()
6165}
6166
6167// =============================================================================
6168// Timezone Configuration
6169// =============================================================================
6170
6171/// Timezone handling configuration for multi-region entities.
6172#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6173pub struct TimezoneSchemaConfig {
6174    /// Enable timezone handling.
6175    #[serde(default)]
6176    pub enabled: bool,
6177
6178    /// Default timezone (IANA format, e.g., "America/New_York").
6179    #[serde(default = "default_timezone")]
6180    pub default_timezone: String,
6181
6182    /// Consolidation timezone for group reporting (IANA format).
6183    #[serde(default = "default_consolidation_timezone")]
6184    pub consolidation_timezone: String,
6185
6186    /// Entity-to-timezone mappings.
6187    /// Supports patterns like "EU_*" -> "Europe/London".
6188    #[serde(default)]
6189    pub entity_mappings: Vec<EntityTimezoneMapping>,
6190}
6191
6192fn default_timezone() -> String {
6193    "America/New_York".to_string()
6194}
6195
6196fn default_consolidation_timezone() -> String {
6197    "UTC".to_string()
6198}
6199
6200/// Mapping from entity pattern to timezone.
6201#[derive(Debug, Clone, Serialize, Deserialize)]
6202pub struct EntityTimezoneMapping {
6203    /// Entity code pattern (e.g., "EU_*", "*_APAC", "1000").
6204    pub pattern: String,
6205
6206    /// Timezone (IANA format, e.g., "Europe/London").
6207    pub timezone: String,
6208}
6209
6210// =============================================================================
6211// Vendor Network Configuration
6212// =============================================================================
6213
6214/// Configuration for multi-tier vendor network generation.
6215#[derive(Debug, Clone, Serialize, Deserialize)]
6216pub struct VendorNetworkSchemaConfig {
6217    /// Enable vendor network generation.
6218    #[serde(default)]
6219    pub enabled: bool,
6220
6221    /// Maximum depth of supply chain tiers (1-3).
6222    #[serde(default = "default_vendor_tier_depth")]
6223    pub depth: u8,
6224
6225    /// Tier 1 vendor count configuration.
6226    #[serde(default)]
6227    pub tier1: TierCountSchemaConfig,
6228
6229    /// Tier 2 vendors per Tier 1 parent.
6230    #[serde(default)]
6231    pub tier2_per_parent: TierCountSchemaConfig,
6232
6233    /// Tier 3 vendors per Tier 2 parent.
6234    #[serde(default)]
6235    pub tier3_per_parent: TierCountSchemaConfig,
6236
6237    /// Vendor cluster distribution.
6238    #[serde(default)]
6239    pub clusters: VendorClusterSchemaConfig,
6240
6241    /// Concentration limits.
6242    #[serde(default)]
6243    pub dependencies: DependencySchemaConfig,
6244}
6245
6246fn default_vendor_tier_depth() -> u8 {
6247    3
6248}
6249
6250impl Default for VendorNetworkSchemaConfig {
6251    fn default() -> Self {
6252        Self {
6253            enabled: false,
6254            depth: 3,
6255            tier1: TierCountSchemaConfig { min: 50, max: 100 },
6256            tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6257            tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6258            clusters: VendorClusterSchemaConfig::default(),
6259            dependencies: DependencySchemaConfig::default(),
6260        }
6261    }
6262}
6263
6264/// Tier count configuration.
6265#[derive(Debug, Clone, Serialize, Deserialize)]
6266pub struct TierCountSchemaConfig {
6267    /// Minimum count.
6268    #[serde(default = "default_tier_min")]
6269    pub min: usize,
6270
6271    /// Maximum count.
6272    #[serde(default = "default_tier_max")]
6273    pub max: usize,
6274}
6275
6276fn default_tier_min() -> usize {
6277    5
6278}
6279
6280fn default_tier_max() -> usize {
6281    20
6282}
6283
6284impl Default for TierCountSchemaConfig {
6285    fn default() -> Self {
6286        Self {
6287            min: default_tier_min(),
6288            max: default_tier_max(),
6289        }
6290    }
6291}
6292
6293/// Vendor cluster distribution configuration.
6294#[derive(Debug, Clone, Serialize, Deserialize)]
6295pub struct VendorClusterSchemaConfig {
6296    /// Reliable strategic vendors percentage (default: 0.20).
6297    #[serde(default = "default_reliable_strategic")]
6298    pub reliable_strategic: f64,
6299
6300    /// Standard operational vendors percentage (default: 0.50).
6301    #[serde(default = "default_standard_operational")]
6302    pub standard_operational: f64,
6303
6304    /// Transactional vendors percentage (default: 0.25).
6305    #[serde(default = "default_transactional")]
6306    pub transactional: f64,
6307
6308    /// Problematic vendors percentage (default: 0.05).
6309    #[serde(default = "default_problematic")]
6310    pub problematic: f64,
6311}
6312
6313fn default_reliable_strategic() -> f64 {
6314    0.20
6315}
6316
6317fn default_standard_operational() -> f64 {
6318    0.50
6319}
6320
6321fn default_transactional() -> f64 {
6322    0.25
6323}
6324
6325fn default_problematic() -> f64 {
6326    0.05
6327}
6328
6329impl Default for VendorClusterSchemaConfig {
6330    fn default() -> Self {
6331        Self {
6332            reliable_strategic: 0.20,
6333            standard_operational: 0.50,
6334            transactional: 0.25,
6335            problematic: 0.05,
6336        }
6337    }
6338}
6339
6340/// Dependency and concentration limits configuration.
6341#[derive(Debug, Clone, Serialize, Deserialize)]
6342pub struct DependencySchemaConfig {
6343    /// Maximum concentration for a single vendor (default: 0.15).
6344    #[serde(default = "default_max_single_vendor")]
6345    pub max_single_vendor_concentration: f64,
6346
6347    /// Maximum concentration for top 5 vendors (default: 0.45).
6348    #[serde(default = "default_max_top5")]
6349    pub top_5_concentration: f64,
6350
6351    /// Percentage of single-source vendors (default: 0.05).
6352    #[serde(default = "default_single_source_percent")]
6353    pub single_source_percent: f64,
6354}
6355
6356fn default_max_single_vendor() -> f64 {
6357    0.15
6358}
6359
6360fn default_max_top5() -> f64 {
6361    0.45
6362}
6363
6364fn default_single_source_percent() -> f64 {
6365    0.05
6366}
6367
6368impl Default for DependencySchemaConfig {
6369    fn default() -> Self {
6370        Self {
6371            max_single_vendor_concentration: 0.15,
6372            top_5_concentration: 0.45,
6373            single_source_percent: 0.05,
6374        }
6375    }
6376}
6377
6378// =============================================================================
6379// Customer Segmentation Configuration
6380// =============================================================================
6381
6382/// Configuration for customer segmentation generation.
6383#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6384pub struct CustomerSegmentationSchemaConfig {
6385    /// Enable customer segmentation generation.
6386    #[serde(default)]
6387    pub enabled: bool,
6388
6389    /// Value segment distribution.
6390    #[serde(default)]
6391    pub value_segments: ValueSegmentsSchemaConfig,
6392
6393    /// Lifecycle stage configuration.
6394    #[serde(default)]
6395    pub lifecycle: LifecycleSchemaConfig,
6396
6397    /// Network (referrals, hierarchies) configuration.
6398    #[serde(default)]
6399    pub networks: CustomerNetworksSchemaConfig,
6400}
6401
6402/// Customer value segments distribution configuration.
6403#[derive(Debug, Clone, Serialize, Deserialize)]
6404pub struct ValueSegmentsSchemaConfig {
6405    /// Enterprise segment configuration.
6406    #[serde(default)]
6407    pub enterprise: SegmentDetailSchemaConfig,
6408
6409    /// Mid-market segment configuration.
6410    #[serde(default)]
6411    pub mid_market: SegmentDetailSchemaConfig,
6412
6413    /// SMB segment configuration.
6414    #[serde(default)]
6415    pub smb: SegmentDetailSchemaConfig,
6416
6417    /// Consumer segment configuration.
6418    #[serde(default)]
6419    pub consumer: SegmentDetailSchemaConfig,
6420}
6421
6422impl Default for ValueSegmentsSchemaConfig {
6423    fn default() -> Self {
6424        Self {
6425            enterprise: SegmentDetailSchemaConfig {
6426                revenue_share: 0.40,
6427                customer_share: 0.05,
6428                avg_order_value_range: "50000+".to_string(),
6429            },
6430            mid_market: SegmentDetailSchemaConfig {
6431                revenue_share: 0.35,
6432                customer_share: 0.20,
6433                avg_order_value_range: "5000-50000".to_string(),
6434            },
6435            smb: SegmentDetailSchemaConfig {
6436                revenue_share: 0.20,
6437                customer_share: 0.50,
6438                avg_order_value_range: "500-5000".to_string(),
6439            },
6440            consumer: SegmentDetailSchemaConfig {
6441                revenue_share: 0.05,
6442                customer_share: 0.25,
6443                avg_order_value_range: "50-500".to_string(),
6444            },
6445        }
6446    }
6447}
6448
6449/// Individual segment detail configuration.
6450#[derive(Debug, Clone, Serialize, Deserialize)]
6451pub struct SegmentDetailSchemaConfig {
6452    /// Revenue share for this segment.
6453    #[serde(default)]
6454    pub revenue_share: f64,
6455
6456    /// Customer share for this segment.
6457    #[serde(default)]
6458    pub customer_share: f64,
6459
6460    /// Average order value range (e.g., "5000-50000" or "50000+").
6461    #[serde(default)]
6462    pub avg_order_value_range: String,
6463}
6464
6465impl Default for SegmentDetailSchemaConfig {
6466    fn default() -> Self {
6467        Self {
6468            revenue_share: 0.25,
6469            customer_share: 0.25,
6470            avg_order_value_range: "1000-10000".to_string(),
6471        }
6472    }
6473}
6474
6475/// Customer lifecycle stage configuration.
6476#[derive(Debug, Clone, Serialize, Deserialize)]
6477pub struct LifecycleSchemaConfig {
6478    /// Prospect stage rate.
6479    #[serde(default)]
6480    pub prospect_rate: f64,
6481
6482    /// New customer stage rate.
6483    #[serde(default = "default_new_rate")]
6484    pub new_rate: f64,
6485
6486    /// Growth stage rate.
6487    #[serde(default = "default_growth_rate")]
6488    pub growth_rate: f64,
6489
6490    /// Mature stage rate.
6491    #[serde(default = "default_mature_rate")]
6492    pub mature_rate: f64,
6493
6494    /// At-risk stage rate.
6495    #[serde(default = "default_at_risk_rate")]
6496    pub at_risk_rate: f64,
6497
6498    /// Churned stage rate.
6499    #[serde(default = "default_churned_rate")]
6500    pub churned_rate: f64,
6501}
6502
6503fn default_new_rate() -> f64 {
6504    0.10
6505}
6506
6507fn default_growth_rate() -> f64 {
6508    0.15
6509}
6510
6511fn default_mature_rate() -> f64 {
6512    0.60
6513}
6514
6515fn default_at_risk_rate() -> f64 {
6516    0.10
6517}
6518
6519fn default_churned_rate() -> f64 {
6520    0.05
6521}
6522
6523impl Default for LifecycleSchemaConfig {
6524    fn default() -> Self {
6525        Self {
6526            prospect_rate: 0.0,
6527            new_rate: 0.10,
6528            growth_rate: 0.15,
6529            mature_rate: 0.60,
6530            at_risk_rate: 0.10,
6531            churned_rate: 0.05,
6532        }
6533    }
6534}
6535
6536/// Customer networks configuration (referrals, hierarchies).
6537#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6538pub struct CustomerNetworksSchemaConfig {
6539    /// Referral network configuration.
6540    #[serde(default)]
6541    pub referrals: ReferralSchemaConfig,
6542
6543    /// Corporate hierarchy configuration.
6544    #[serde(default)]
6545    pub corporate_hierarchies: HierarchySchemaConfig,
6546}
6547
6548/// Referral network configuration.
6549#[derive(Debug, Clone, Serialize, Deserialize)]
6550pub struct ReferralSchemaConfig {
6551    /// Enable referral generation.
6552    #[serde(default = "default_true")]
6553    pub enabled: bool,
6554
6555    /// Rate of customers acquired via referral.
6556    #[serde(default = "default_referral_rate")]
6557    pub referral_rate: f64,
6558}
6559
6560fn default_referral_rate() -> f64 {
6561    0.15
6562}
6563
6564impl Default for ReferralSchemaConfig {
6565    fn default() -> Self {
6566        Self {
6567            enabled: true,
6568            referral_rate: 0.15,
6569        }
6570    }
6571}
6572
6573/// Corporate hierarchy configuration.
6574#[derive(Debug, Clone, Serialize, Deserialize)]
6575pub struct HierarchySchemaConfig {
6576    /// Enable corporate hierarchy generation.
6577    #[serde(default = "default_true")]
6578    pub enabled: bool,
6579
6580    /// Rate of customers in hierarchies.
6581    #[serde(default = "default_hierarchy_rate")]
6582    pub probability: f64,
6583}
6584
6585fn default_hierarchy_rate() -> f64 {
6586    0.30
6587}
6588
6589impl Default for HierarchySchemaConfig {
6590    fn default() -> Self {
6591        Self {
6592            enabled: true,
6593            probability: 0.30,
6594        }
6595    }
6596}
6597
6598// =============================================================================
6599// Relationship Strength Configuration
6600// =============================================================================
6601
6602/// Configuration for relationship strength calculation.
6603#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6604pub struct RelationshipStrengthSchemaConfig {
6605    /// Enable relationship strength calculation.
6606    #[serde(default)]
6607    pub enabled: bool,
6608
6609    /// Calculation weights.
6610    #[serde(default)]
6611    pub calculation: StrengthCalculationSchemaConfig,
6612
6613    /// Strength thresholds for classification.
6614    #[serde(default)]
6615    pub thresholds: StrengthThresholdsSchemaConfig,
6616}
6617
6618/// Strength calculation weights configuration.
6619#[derive(Debug, Clone, Serialize, Deserialize)]
6620pub struct StrengthCalculationSchemaConfig {
6621    /// Weight for transaction volume (default: 0.30).
6622    #[serde(default = "default_volume_weight")]
6623    pub transaction_volume_weight: f64,
6624
6625    /// Weight for transaction count (default: 0.25).
6626    #[serde(default = "default_count_weight")]
6627    pub transaction_count_weight: f64,
6628
6629    /// Weight for relationship duration (default: 0.20).
6630    #[serde(default = "default_duration_weight")]
6631    pub relationship_duration_weight: f64,
6632
6633    /// Weight for recency (default: 0.15).
6634    #[serde(default = "default_recency_weight")]
6635    pub recency_weight: f64,
6636
6637    /// Weight for mutual connections (default: 0.10).
6638    #[serde(default = "default_mutual_weight")]
6639    pub mutual_connections_weight: f64,
6640
6641    /// Recency half-life in days (default: 90).
6642    #[serde(default = "default_recency_half_life")]
6643    pub recency_half_life_days: u32,
6644}
6645
6646fn default_volume_weight() -> f64 {
6647    0.30
6648}
6649
6650fn default_count_weight() -> f64 {
6651    0.25
6652}
6653
6654fn default_duration_weight() -> f64 {
6655    0.20
6656}
6657
6658fn default_recency_weight() -> f64 {
6659    0.15
6660}
6661
6662fn default_mutual_weight() -> f64 {
6663    0.10
6664}
6665
6666fn default_recency_half_life() -> u32 {
6667    90
6668}
6669
6670impl Default for StrengthCalculationSchemaConfig {
6671    fn default() -> Self {
6672        Self {
6673            transaction_volume_weight: 0.30,
6674            transaction_count_weight: 0.25,
6675            relationship_duration_weight: 0.20,
6676            recency_weight: 0.15,
6677            mutual_connections_weight: 0.10,
6678            recency_half_life_days: 90,
6679        }
6680    }
6681}
6682
6683/// Strength thresholds for relationship classification.
6684#[derive(Debug, Clone, Serialize, Deserialize)]
6685pub struct StrengthThresholdsSchemaConfig {
6686    /// Threshold for strong relationships (default: 0.7).
6687    #[serde(default = "default_strong_threshold")]
6688    pub strong: f64,
6689
6690    /// Threshold for moderate relationships (default: 0.4).
6691    #[serde(default = "default_moderate_threshold")]
6692    pub moderate: f64,
6693
6694    /// Threshold for weak relationships (default: 0.1).
6695    #[serde(default = "default_weak_threshold")]
6696    pub weak: f64,
6697}
6698
6699fn default_strong_threshold() -> f64 {
6700    0.7
6701}
6702
6703fn default_moderate_threshold() -> f64 {
6704    0.4
6705}
6706
6707fn default_weak_threshold() -> f64 {
6708    0.1
6709}
6710
6711impl Default for StrengthThresholdsSchemaConfig {
6712    fn default() -> Self {
6713        Self {
6714            strong: 0.7,
6715            moderate: 0.4,
6716            weak: 0.1,
6717        }
6718    }
6719}
6720
6721// =============================================================================
6722// Cross-Process Links Configuration
6723// =============================================================================
6724
6725/// Configuration for cross-process linkages.
6726#[derive(Debug, Clone, Serialize, Deserialize)]
6727pub struct CrossProcessLinksSchemaConfig {
6728    /// Enable cross-process link generation.
6729    #[serde(default)]
6730    pub enabled: bool,
6731
6732    /// Enable inventory links between P2P and O2C.
6733    #[serde(default = "default_true")]
6734    pub inventory_p2p_o2c: bool,
6735
6736    /// Enable payment to bank reconciliation links.
6737    #[serde(default = "default_true")]
6738    pub payment_bank_reconciliation: bool,
6739
6740    /// Enable intercompany bilateral matching.
6741    #[serde(default = "default_true")]
6742    pub intercompany_bilateral: bool,
6743
6744    /// Percentage of GR/Deliveries to link via inventory (0.0 - 1.0).
6745    #[serde(default = "default_inventory_link_rate")]
6746    pub inventory_link_rate: f64,
6747}
6748
6749fn default_inventory_link_rate() -> f64 {
6750    0.30
6751}
6752
6753impl Default for CrossProcessLinksSchemaConfig {
6754    fn default() -> Self {
6755        Self {
6756            enabled: false,
6757            inventory_p2p_o2c: true,
6758            payment_bank_reconciliation: true,
6759            intercompany_bilateral: true,
6760            inventory_link_rate: 0.30,
6761        }
6762    }
6763}
6764
6765// =============================================================================
6766// Organizational Events Configuration
6767// =============================================================================
6768
6769/// Configuration for organizational events (acquisitions, divestitures, etc.).
6770#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6771pub struct OrganizationalEventsSchemaConfig {
6772    /// Enable organizational events.
6773    #[serde(default)]
6774    pub enabled: bool,
6775
6776    /// Effect blending mode (multiplicative, additive, maximum, minimum).
6777    #[serde(default)]
6778    pub effect_blending: EffectBlendingModeConfig,
6779
6780    /// Organizational events (acquisitions, divestitures, reorganizations, etc.).
6781    #[serde(default)]
6782    pub events: Vec<OrganizationalEventSchemaConfig>,
6783
6784    /// Process evolution events.
6785    #[serde(default)]
6786    pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
6787
6788    /// Technology transition events.
6789    #[serde(default)]
6790    pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
6791}
6792
6793/// Effect blending mode for combining multiple event effects.
6794#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6795#[serde(rename_all = "snake_case")]
6796pub enum EffectBlendingModeConfig {
6797    /// Multiply effects together.
6798    #[default]
6799    Multiplicative,
6800    /// Add effects together.
6801    Additive,
6802    /// Take the maximum effect.
6803    Maximum,
6804    /// Take the minimum effect.
6805    Minimum,
6806}
6807
6808/// Configuration for a single organizational event.
6809#[derive(Debug, Clone, Serialize, Deserialize)]
6810pub struct OrganizationalEventSchemaConfig {
6811    /// Event ID.
6812    pub id: String,
6813
6814    /// Event type and configuration.
6815    pub event_type: OrganizationalEventTypeSchemaConfig,
6816
6817    /// Effective date.
6818    pub effective_date: String,
6819
6820    /// Transition duration in months.
6821    #[serde(default = "default_org_transition_months")]
6822    pub transition_months: u32,
6823
6824    /// Description.
6825    #[serde(default)]
6826    pub description: Option<String>,
6827}
6828
6829fn default_org_transition_months() -> u32 {
6830    6
6831}
6832
6833/// Organizational event type configuration.
6834#[derive(Debug, Clone, Serialize, Deserialize)]
6835#[serde(tag = "type", rename_all = "snake_case")]
6836pub enum OrganizationalEventTypeSchemaConfig {
6837    /// Acquisition event.
6838    Acquisition {
6839        /// Acquired entity code.
6840        acquired_entity: String,
6841        /// Volume increase multiplier.
6842        #[serde(default = "default_acquisition_volume")]
6843        volume_increase: f64,
6844        /// Integration error rate.
6845        #[serde(default = "default_acquisition_error")]
6846        integration_error_rate: f64,
6847        /// Parallel posting days.
6848        #[serde(default = "default_parallel_days")]
6849        parallel_posting_days: u32,
6850    },
6851    /// Divestiture event.
6852    Divestiture {
6853        /// Divested entity code.
6854        divested_entity: String,
6855        /// Volume reduction factor.
6856        #[serde(default = "default_divestiture_volume")]
6857        volume_reduction: f64,
6858        /// Remove entity from generation.
6859        #[serde(default = "default_true_val")]
6860        remove_entity: bool,
6861    },
6862    /// Reorganization event.
6863    Reorganization {
6864        /// Cost center remapping.
6865        #[serde(default)]
6866        cost_center_remapping: std::collections::HashMap<String, String>,
6867        /// Transition error rate.
6868        #[serde(default = "default_reorg_error")]
6869        transition_error_rate: f64,
6870    },
6871    /// Leadership change event.
6872    LeadershipChange {
6873        /// Role that changed.
6874        role: String,
6875        /// Policy changes.
6876        #[serde(default)]
6877        policy_changes: Vec<String>,
6878    },
6879    /// Workforce reduction event.
6880    WorkforceReduction {
6881        /// Reduction percentage.
6882        #[serde(default = "default_workforce_reduction")]
6883        reduction_percent: f64,
6884        /// Error rate increase.
6885        #[serde(default = "default_workforce_error")]
6886        error_rate_increase: f64,
6887    },
6888    /// Merger event.
6889    Merger {
6890        /// Merged entity code.
6891        merged_entity: String,
6892        /// Volume increase multiplier.
6893        #[serde(default = "default_merger_volume")]
6894        volume_increase: f64,
6895    },
6896}
6897
6898fn default_acquisition_volume() -> f64 {
6899    1.35
6900}
6901
6902fn default_acquisition_error() -> f64 {
6903    0.05
6904}
6905
6906fn default_parallel_days() -> u32 {
6907    30
6908}
6909
6910fn default_divestiture_volume() -> f64 {
6911    0.70
6912}
6913
6914fn default_true_val() -> bool {
6915    true
6916}
6917
6918fn default_reorg_error() -> f64 {
6919    0.04
6920}
6921
6922fn default_workforce_reduction() -> f64 {
6923    0.10
6924}
6925
6926fn default_workforce_error() -> f64 {
6927    0.05
6928}
6929
6930fn default_merger_volume() -> f64 {
6931    1.80
6932}
6933
6934/// Configuration for a process evolution event.
6935#[derive(Debug, Clone, Serialize, Deserialize)]
6936pub struct ProcessEvolutionSchemaConfig {
6937    /// Event ID.
6938    pub id: String,
6939
6940    /// Event type.
6941    pub event_type: ProcessEvolutionTypeSchemaConfig,
6942
6943    /// Effective date.
6944    pub effective_date: String,
6945
6946    /// Description.
6947    #[serde(default)]
6948    pub description: Option<String>,
6949}
6950
6951/// Process evolution type configuration.
6952#[derive(Debug, Clone, Serialize, Deserialize)]
6953#[serde(tag = "type", rename_all = "snake_case")]
6954pub enum ProcessEvolutionTypeSchemaConfig {
6955    /// Process automation.
6956    ProcessAutomation {
6957        /// Process name.
6958        process_name: String,
6959        /// Manual rate before.
6960        #[serde(default = "default_manual_before")]
6961        manual_rate_before: f64,
6962        /// Manual rate after.
6963        #[serde(default = "default_manual_after")]
6964        manual_rate_after: f64,
6965    },
6966    /// Approval workflow change.
6967    ApprovalWorkflowChange {
6968        /// Description.
6969        description: String,
6970    },
6971    /// Control enhancement.
6972    ControlEnhancement {
6973        /// Control ID.
6974        control_id: String,
6975        /// Error reduction.
6976        #[serde(default = "default_error_reduction")]
6977        error_reduction: f64,
6978    },
6979}
6980
6981fn default_manual_before() -> f64 {
6982    0.80
6983}
6984
6985fn default_manual_after() -> f64 {
6986    0.15
6987}
6988
6989fn default_error_reduction() -> f64 {
6990    0.02
6991}
6992
6993/// Configuration for a technology transition event.
6994#[derive(Debug, Clone, Serialize, Deserialize)]
6995pub struct TechnologyTransitionSchemaConfig {
6996    /// Event ID.
6997    pub id: String,
6998
6999    /// Event type.
7000    pub event_type: TechnologyTransitionTypeSchemaConfig,
7001
7002    /// Description.
7003    #[serde(default)]
7004    pub description: Option<String>,
7005}
7006
7007/// Technology transition type configuration.
7008#[derive(Debug, Clone, Serialize, Deserialize)]
7009#[serde(tag = "type", rename_all = "snake_case")]
7010pub enum TechnologyTransitionTypeSchemaConfig {
7011    /// ERP migration.
7012    ErpMigration {
7013        /// Source system.
7014        source_system: String,
7015        /// Target system.
7016        target_system: String,
7017        /// Cutover date.
7018        cutover_date: String,
7019        /// Stabilization end date.
7020        stabilization_end: String,
7021        /// Duplicate rate during migration.
7022        #[serde(default = "default_erp_duplicate_rate")]
7023        duplicate_rate: f64,
7024        /// Format mismatch rate.
7025        #[serde(default = "default_format_mismatch")]
7026        format_mismatch_rate: f64,
7027    },
7028    /// Module implementation.
7029    ModuleImplementation {
7030        /// Module name.
7031        module_name: String,
7032        /// Go-live date.
7033        go_live_date: String,
7034    },
7035}
7036
7037fn default_erp_duplicate_rate() -> f64 {
7038    0.02
7039}
7040
7041fn default_format_mismatch() -> f64 {
7042    0.03
7043}
7044
7045// =============================================================================
7046// Behavioral Drift Configuration
7047// =============================================================================
7048
7049/// Configuration for behavioral drift (vendor, customer, employee behavior).
7050#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7051pub struct BehavioralDriftSchemaConfig {
7052    /// Enable behavioral drift.
7053    #[serde(default)]
7054    pub enabled: bool,
7055
7056    /// Vendor behavior drift.
7057    #[serde(default)]
7058    pub vendor_behavior: VendorBehaviorSchemaConfig,
7059
7060    /// Customer behavior drift.
7061    #[serde(default)]
7062    pub customer_behavior: CustomerBehaviorSchemaConfig,
7063
7064    /// Employee behavior drift.
7065    #[serde(default)]
7066    pub employee_behavior: EmployeeBehaviorSchemaConfig,
7067
7068    /// Collective behavior drift.
7069    #[serde(default)]
7070    pub collective: CollectiveBehaviorSchemaConfig,
7071}
7072
7073/// Vendor behavior drift configuration.
7074#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7075pub struct VendorBehaviorSchemaConfig {
7076    /// Payment terms drift.
7077    #[serde(default)]
7078    pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7079
7080    /// Quality drift.
7081    #[serde(default)]
7082    pub quality_drift: QualityDriftSchemaConfig,
7083}
7084
7085/// Payment terms drift configuration.
7086#[derive(Debug, Clone, Serialize, Deserialize)]
7087pub struct PaymentTermsDriftSchemaConfig {
7088    /// Extension rate per year (days).
7089    #[serde(default = "default_extension_rate")]
7090    pub extension_rate_per_year: f64,
7091
7092    /// Economic sensitivity.
7093    #[serde(default = "default_economic_sensitivity")]
7094    pub economic_sensitivity: f64,
7095}
7096
7097fn default_extension_rate() -> f64 {
7098    2.5
7099}
7100
7101fn default_economic_sensitivity() -> f64 {
7102    1.0
7103}
7104
7105impl Default for PaymentTermsDriftSchemaConfig {
7106    fn default() -> Self {
7107        Self {
7108            extension_rate_per_year: 2.5,
7109            economic_sensitivity: 1.0,
7110        }
7111    }
7112}
7113
7114/// Quality drift configuration.
7115#[derive(Debug, Clone, Serialize, Deserialize)]
7116pub struct QualityDriftSchemaConfig {
7117    /// New vendor improvement rate (per year).
7118    #[serde(default = "default_improvement_rate")]
7119    pub new_vendor_improvement_rate: f64,
7120
7121    /// Complacency decline rate (per year after first year).
7122    #[serde(default = "default_decline_rate")]
7123    pub complacency_decline_rate: f64,
7124}
7125
7126fn default_improvement_rate() -> f64 {
7127    0.02
7128}
7129
7130fn default_decline_rate() -> f64 {
7131    0.01
7132}
7133
7134impl Default for QualityDriftSchemaConfig {
7135    fn default() -> Self {
7136        Self {
7137            new_vendor_improvement_rate: 0.02,
7138            complacency_decline_rate: 0.01,
7139        }
7140    }
7141}
7142
7143/// Customer behavior drift configuration.
7144#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7145pub struct CustomerBehaviorSchemaConfig {
7146    /// Payment drift.
7147    #[serde(default)]
7148    pub payment_drift: CustomerPaymentDriftSchemaConfig,
7149
7150    /// Order drift.
7151    #[serde(default)]
7152    pub order_drift: OrderDriftSchemaConfig,
7153}
7154
7155/// Customer payment drift configuration.
7156#[derive(Debug, Clone, Serialize, Deserialize)]
7157pub struct CustomerPaymentDriftSchemaConfig {
7158    /// Days extension during downturn (min, max).
7159    #[serde(default = "default_downturn_extension")]
7160    pub downturn_days_extension: (u32, u32),
7161
7162    /// Bad debt increase during downturn.
7163    #[serde(default = "default_bad_debt_increase")]
7164    pub downturn_bad_debt_increase: f64,
7165}
7166
7167fn default_downturn_extension() -> (u32, u32) {
7168    (5, 15)
7169}
7170
7171fn default_bad_debt_increase() -> f64 {
7172    0.02
7173}
7174
7175impl Default for CustomerPaymentDriftSchemaConfig {
7176    fn default() -> Self {
7177        Self {
7178            downturn_days_extension: (5, 15),
7179            downturn_bad_debt_increase: 0.02,
7180        }
7181    }
7182}
7183
7184/// Order drift configuration.
7185#[derive(Debug, Clone, Serialize, Deserialize)]
7186pub struct OrderDriftSchemaConfig {
7187    /// Digital shift rate (per year).
7188    #[serde(default = "default_digital_shift")]
7189    pub digital_shift_rate: f64,
7190}
7191
7192fn default_digital_shift() -> f64 {
7193    0.05
7194}
7195
7196impl Default for OrderDriftSchemaConfig {
7197    fn default() -> Self {
7198        Self {
7199            digital_shift_rate: 0.05,
7200        }
7201    }
7202}
7203
7204/// Employee behavior drift configuration.
7205#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7206pub struct EmployeeBehaviorSchemaConfig {
7207    /// Approval drift.
7208    #[serde(default)]
7209    pub approval_drift: ApprovalDriftSchemaConfig,
7210
7211    /// Error drift.
7212    #[serde(default)]
7213    pub error_drift: ErrorDriftSchemaConfig,
7214}
7215
7216/// Approval drift configuration.
7217#[derive(Debug, Clone, Serialize, Deserialize)]
7218pub struct ApprovalDriftSchemaConfig {
7219    /// EOM intensity increase per year.
7220    #[serde(default = "default_eom_intensity")]
7221    pub eom_intensity_increase_per_year: f64,
7222
7223    /// Rubber stamp volume threshold.
7224    #[serde(default = "default_rubber_stamp")]
7225    pub rubber_stamp_volume_threshold: u32,
7226}
7227
7228fn default_eom_intensity() -> f64 {
7229    0.05
7230}
7231
7232fn default_rubber_stamp() -> u32 {
7233    50
7234}
7235
7236impl Default for ApprovalDriftSchemaConfig {
7237    fn default() -> Self {
7238        Self {
7239            eom_intensity_increase_per_year: 0.05,
7240            rubber_stamp_volume_threshold: 50,
7241        }
7242    }
7243}
7244
7245/// Error drift configuration.
7246#[derive(Debug, Clone, Serialize, Deserialize)]
7247pub struct ErrorDriftSchemaConfig {
7248    /// New employee error rate.
7249    #[serde(default = "default_new_error")]
7250    pub new_employee_error_rate: f64,
7251
7252    /// Learning curve months.
7253    #[serde(default = "default_learning_months")]
7254    pub learning_curve_months: u32,
7255}
7256
7257fn default_new_error() -> f64 {
7258    0.08
7259}
7260
7261fn default_learning_months() -> u32 {
7262    6
7263}
7264
7265impl Default for ErrorDriftSchemaConfig {
7266    fn default() -> Self {
7267        Self {
7268            new_employee_error_rate: 0.08,
7269            learning_curve_months: 6,
7270        }
7271    }
7272}
7273
7274/// Collective behavior drift configuration.
7275#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7276pub struct CollectiveBehaviorSchemaConfig {
7277    /// Automation adoption configuration.
7278    #[serde(default)]
7279    pub automation_adoption: AutomationAdoptionSchemaConfig,
7280}
7281
7282/// Automation adoption configuration.
7283#[derive(Debug, Clone, Serialize, Deserialize)]
7284pub struct AutomationAdoptionSchemaConfig {
7285    /// Enable S-curve adoption model.
7286    #[serde(default)]
7287    pub s_curve_enabled: bool,
7288
7289    /// Adoption midpoint in months.
7290    #[serde(default = "default_midpoint")]
7291    pub adoption_midpoint_months: u32,
7292
7293    /// Steepness of adoption curve.
7294    #[serde(default = "default_steepness")]
7295    pub steepness: f64,
7296}
7297
7298fn default_midpoint() -> u32 {
7299    24
7300}
7301
7302fn default_steepness() -> f64 {
7303    0.15
7304}
7305
7306impl Default for AutomationAdoptionSchemaConfig {
7307    fn default() -> Self {
7308        Self {
7309            s_curve_enabled: false,
7310            adoption_midpoint_months: 24,
7311            steepness: 0.15,
7312        }
7313    }
7314}
7315
7316// =============================================================================
7317// Market Drift Configuration
7318// =============================================================================
7319
7320/// Configuration for market drift (economic cycles, commodities, price shocks).
7321#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7322pub struct MarketDriftSchemaConfig {
7323    /// Enable market drift.
7324    #[serde(default)]
7325    pub enabled: bool,
7326
7327    /// Economic cycle configuration.
7328    #[serde(default)]
7329    pub economic_cycle: MarketEconomicCycleSchemaConfig,
7330
7331    /// Industry-specific cycles.
7332    #[serde(default)]
7333    pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7334
7335    /// Commodity drift configuration.
7336    #[serde(default)]
7337    pub commodities: CommoditiesSchemaConfig,
7338}
7339
7340/// Market economic cycle configuration.
7341#[derive(Debug, Clone, Serialize, Deserialize)]
7342pub struct MarketEconomicCycleSchemaConfig {
7343    /// Enable economic cycle.
7344    #[serde(default)]
7345    pub enabled: bool,
7346
7347    /// Cycle type.
7348    #[serde(default)]
7349    pub cycle_type: CycleTypeSchemaConfig,
7350
7351    /// Cycle period in months.
7352    #[serde(default = "default_market_cycle_period")]
7353    pub period_months: u32,
7354
7355    /// Amplitude.
7356    #[serde(default = "default_market_amplitude")]
7357    pub amplitude: f64,
7358
7359    /// Recession configuration.
7360    #[serde(default)]
7361    pub recession: RecessionSchemaConfig,
7362}
7363
7364fn default_market_cycle_period() -> u32 {
7365    48
7366}
7367
7368fn default_market_amplitude() -> f64 {
7369    0.15
7370}
7371
7372impl Default for MarketEconomicCycleSchemaConfig {
7373    fn default() -> Self {
7374        Self {
7375            enabled: false,
7376            cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7377            period_months: 48,
7378            amplitude: 0.15,
7379            recession: RecessionSchemaConfig::default(),
7380        }
7381    }
7382}
7383
7384/// Cycle type configuration.
7385#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7386#[serde(rename_all = "snake_case")]
7387pub enum CycleTypeSchemaConfig {
7388    /// Sinusoidal cycle.
7389    #[default]
7390    Sinusoidal,
7391    /// Asymmetric cycle.
7392    Asymmetric,
7393    /// Mean-reverting cycle.
7394    MeanReverting,
7395}
7396
7397/// Recession configuration.
7398#[derive(Debug, Clone, Serialize, Deserialize)]
7399pub struct RecessionSchemaConfig {
7400    /// Enable recession simulation.
7401    #[serde(default)]
7402    pub enabled: bool,
7403
7404    /// Probability per year.
7405    #[serde(default = "default_recession_prob")]
7406    pub probability_per_year: f64,
7407
7408    /// Severity.
7409    #[serde(default)]
7410    pub severity: RecessionSeveritySchemaConfig,
7411
7412    /// Specific recession periods.
7413    #[serde(default)]
7414    pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7415}
7416
7417fn default_recession_prob() -> f64 {
7418    0.10
7419}
7420
7421impl Default for RecessionSchemaConfig {
7422    fn default() -> Self {
7423        Self {
7424            enabled: false,
7425            probability_per_year: 0.10,
7426            severity: RecessionSeveritySchemaConfig::Moderate,
7427            recession_periods: Vec::new(),
7428        }
7429    }
7430}
7431
7432/// Recession severity configuration.
7433#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7434#[serde(rename_all = "snake_case")]
7435pub enum RecessionSeveritySchemaConfig {
7436    /// Mild recession.
7437    Mild,
7438    /// Moderate recession.
7439    #[default]
7440    Moderate,
7441    /// Severe recession.
7442    Severe,
7443}
7444
7445/// Recession period configuration.
7446#[derive(Debug, Clone, Serialize, Deserialize)]
7447pub struct RecessionPeriodSchemaConfig {
7448    /// Start month.
7449    pub start_month: u32,
7450    /// Duration in months.
7451    pub duration_months: u32,
7452}
7453
7454/// Industry cycle configuration.
7455#[derive(Debug, Clone, Serialize, Deserialize)]
7456pub struct IndustryCycleSchemaConfig {
7457    /// Period in months.
7458    #[serde(default = "default_industry_period")]
7459    pub period_months: u32,
7460
7461    /// Amplitude.
7462    #[serde(default = "default_industry_amp")]
7463    pub amplitude: f64,
7464}
7465
7466fn default_industry_period() -> u32 {
7467    36
7468}
7469
7470fn default_industry_amp() -> f64 {
7471    0.20
7472}
7473
7474/// Commodities drift configuration.
7475#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7476pub struct CommoditiesSchemaConfig {
7477    /// Enable commodity drift.
7478    #[serde(default)]
7479    pub enabled: bool,
7480
7481    /// Commodity items.
7482    #[serde(default)]
7483    pub items: Vec<CommodityItemSchemaConfig>,
7484}
7485
7486/// Commodity item configuration.
7487#[derive(Debug, Clone, Serialize, Deserialize)]
7488pub struct CommodityItemSchemaConfig {
7489    /// Commodity name.
7490    pub name: String,
7491
7492    /// Volatility.
7493    #[serde(default = "default_volatility")]
7494    pub volatility: f64,
7495
7496    /// COGS pass-through.
7497    #[serde(default)]
7498    pub cogs_pass_through: f64,
7499
7500    /// Overhead pass-through.
7501    #[serde(default)]
7502    pub overhead_pass_through: f64,
7503}
7504
7505fn default_volatility() -> f64 {
7506    0.20
7507}
7508
7509// =============================================================================
7510// Drift Labeling Configuration
7511// =============================================================================
7512
7513/// Configuration for drift ground truth labeling.
7514#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7515pub struct DriftLabelingSchemaConfig {
7516    /// Enable drift labeling.
7517    #[serde(default)]
7518    pub enabled: bool,
7519
7520    /// Statistical drift labeling.
7521    #[serde(default)]
7522    pub statistical: StatisticalDriftLabelingSchemaConfig,
7523
7524    /// Categorical drift labeling.
7525    #[serde(default)]
7526    pub categorical: CategoricalDriftLabelingSchemaConfig,
7527
7528    /// Temporal drift labeling.
7529    #[serde(default)]
7530    pub temporal: TemporalDriftLabelingSchemaConfig,
7531
7532    /// Regulatory calendar preset.
7533    #[serde(default)]
7534    pub regulatory_calendar_preset: Option<String>,
7535}
7536
7537/// Statistical drift labeling configuration.
7538#[derive(Debug, Clone, Serialize, Deserialize)]
7539pub struct StatisticalDriftLabelingSchemaConfig {
7540    /// Enable statistical drift labeling.
7541    #[serde(default = "default_true_val")]
7542    pub enabled: bool,
7543
7544    /// Minimum magnitude threshold.
7545    #[serde(default = "default_min_magnitude")]
7546    pub min_magnitude_threshold: f64,
7547}
7548
7549fn default_min_magnitude() -> f64 {
7550    0.05
7551}
7552
7553impl Default for StatisticalDriftLabelingSchemaConfig {
7554    fn default() -> Self {
7555        Self {
7556            enabled: true,
7557            min_magnitude_threshold: 0.05,
7558        }
7559    }
7560}
7561
7562/// Categorical drift labeling configuration.
7563#[derive(Debug, Clone, Serialize, Deserialize)]
7564pub struct CategoricalDriftLabelingSchemaConfig {
7565    /// Enable categorical drift labeling.
7566    #[serde(default = "default_true_val")]
7567    pub enabled: bool,
7568}
7569
7570impl Default for CategoricalDriftLabelingSchemaConfig {
7571    fn default() -> Self {
7572        Self { enabled: true }
7573    }
7574}
7575
7576/// Temporal drift labeling configuration.
7577#[derive(Debug, Clone, Serialize, Deserialize)]
7578pub struct TemporalDriftLabelingSchemaConfig {
7579    /// Enable temporal drift labeling.
7580    #[serde(default = "default_true_val")]
7581    pub enabled: bool,
7582}
7583
7584impl Default for TemporalDriftLabelingSchemaConfig {
7585    fn default() -> Self {
7586        Self { enabled: true }
7587    }
7588}
7589
7590// =============================================================================
7591// Enhanced Anomaly Injection Configuration
7592// =============================================================================
7593
7594/// Enhanced anomaly injection configuration.
7595///
7596/// Provides comprehensive anomaly injection capabilities including:
7597/// - Multi-stage fraud schemes (embezzlement, revenue manipulation, kickbacks)
7598/// - Correlated anomaly injection (co-occurrence patterns, error cascades)
7599/// - Near-miss generation for false positive reduction
7600/// - Detection difficulty classification
7601/// - Context-aware injection based on entity behavior
7602#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7603pub struct EnhancedAnomalyConfig {
7604    /// Enable enhanced anomaly injection.
7605    #[serde(default)]
7606    pub enabled: bool,
7607
7608    /// Base anomaly rates.
7609    #[serde(default)]
7610    pub rates: AnomalyRateConfig,
7611
7612    /// Multi-stage fraud scheme configuration.
7613    #[serde(default)]
7614    pub multi_stage_schemes: MultiStageSchemeConfig,
7615
7616    /// Correlated anomaly injection configuration.
7617    #[serde(default)]
7618    pub correlated_injection: CorrelatedInjectionConfig,
7619
7620    /// Near-miss generation configuration.
7621    #[serde(default)]
7622    pub near_miss: NearMissConfig,
7623
7624    /// Detection difficulty classification configuration.
7625    #[serde(default)]
7626    pub difficulty_classification: DifficultyClassificationConfig,
7627
7628    /// Context-aware injection configuration.
7629    #[serde(default)]
7630    pub context_aware: ContextAwareConfig,
7631
7632    /// Enhanced labeling configuration.
7633    #[serde(default)]
7634    pub labeling: EnhancedLabelingConfig,
7635}
7636
7637/// Base anomaly rate configuration.
7638#[derive(Debug, Clone, Serialize, Deserialize)]
7639pub struct AnomalyRateConfig {
7640    /// Total anomaly rate (0.0 to 1.0).
7641    #[serde(default = "default_total_anomaly_rate")]
7642    pub total_rate: f64,
7643
7644    /// Fraud anomaly rate.
7645    #[serde(default = "default_fraud_anomaly_rate")]
7646    pub fraud_rate: f64,
7647
7648    /// Error anomaly rate.
7649    #[serde(default = "default_error_anomaly_rate")]
7650    pub error_rate: f64,
7651
7652    /// Process issue rate.
7653    #[serde(default = "default_process_anomaly_rate")]
7654    pub process_rate: f64,
7655}
7656
7657fn default_total_anomaly_rate() -> f64 {
7658    0.03
7659}
7660fn default_fraud_anomaly_rate() -> f64 {
7661    0.01
7662}
7663fn default_error_anomaly_rate() -> f64 {
7664    0.015
7665}
7666fn default_process_anomaly_rate() -> f64 {
7667    0.005
7668}
7669
7670impl Default for AnomalyRateConfig {
7671    fn default() -> Self {
7672        Self {
7673            total_rate: default_total_anomaly_rate(),
7674            fraud_rate: default_fraud_anomaly_rate(),
7675            error_rate: default_error_anomaly_rate(),
7676            process_rate: default_process_anomaly_rate(),
7677        }
7678    }
7679}
7680
7681/// Multi-stage fraud scheme configuration.
7682#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7683pub struct MultiStageSchemeConfig {
7684    /// Enable multi-stage fraud schemes.
7685    #[serde(default)]
7686    pub enabled: bool,
7687
7688    /// Embezzlement scheme configuration.
7689    #[serde(default)]
7690    pub embezzlement: EmbezzlementSchemeConfig,
7691
7692    /// Revenue manipulation scheme configuration.
7693    #[serde(default)]
7694    pub revenue_manipulation: RevenueManipulationSchemeConfig,
7695
7696    /// Vendor kickback scheme configuration.
7697    #[serde(default)]
7698    pub kickback: KickbackSchemeConfig,
7699}
7700
7701/// Embezzlement scheme configuration.
7702#[derive(Debug, Clone, Serialize, Deserialize)]
7703pub struct EmbezzlementSchemeConfig {
7704    /// Probability of starting an embezzlement scheme per perpetrator per year.
7705    #[serde(default = "default_embezzlement_probability")]
7706    pub probability: f64,
7707
7708    /// Testing stage configuration.
7709    #[serde(default)]
7710    pub testing_stage: SchemeStageConfig,
7711
7712    /// Escalation stage configuration.
7713    #[serde(default)]
7714    pub escalation_stage: SchemeStageConfig,
7715
7716    /// Acceleration stage configuration.
7717    #[serde(default)]
7718    pub acceleration_stage: SchemeStageConfig,
7719
7720    /// Desperation stage configuration.
7721    #[serde(default)]
7722    pub desperation_stage: SchemeStageConfig,
7723}
7724
7725fn default_embezzlement_probability() -> f64 {
7726    0.02
7727}
7728
7729impl Default for EmbezzlementSchemeConfig {
7730    fn default() -> Self {
7731        Self {
7732            probability: default_embezzlement_probability(),
7733            testing_stage: SchemeStageConfig {
7734                duration_months: 2,
7735                amount_min: 100.0,
7736                amount_max: 500.0,
7737                transaction_count_min: 2,
7738                transaction_count_max: 5,
7739                difficulty: "hard".to_string(),
7740            },
7741            escalation_stage: SchemeStageConfig {
7742                duration_months: 6,
7743                amount_min: 500.0,
7744                amount_max: 2000.0,
7745                transaction_count_min: 3,
7746                transaction_count_max: 8,
7747                difficulty: "moderate".to_string(),
7748            },
7749            acceleration_stage: SchemeStageConfig {
7750                duration_months: 3,
7751                amount_min: 2000.0,
7752                amount_max: 10000.0,
7753                transaction_count_min: 5,
7754                transaction_count_max: 12,
7755                difficulty: "easy".to_string(),
7756            },
7757            desperation_stage: SchemeStageConfig {
7758                duration_months: 1,
7759                amount_min: 10000.0,
7760                amount_max: 50000.0,
7761                transaction_count_min: 3,
7762                transaction_count_max: 6,
7763                difficulty: "trivial".to_string(),
7764            },
7765        }
7766    }
7767}
7768
7769/// Revenue manipulation scheme configuration.
7770#[derive(Debug, Clone, Serialize, Deserialize)]
7771pub struct RevenueManipulationSchemeConfig {
7772    /// Probability of starting a revenue manipulation scheme per period.
7773    #[serde(default = "default_revenue_manipulation_probability")]
7774    pub probability: f64,
7775
7776    /// Early revenue recognition inflation target (Q4).
7777    #[serde(default = "default_early_recognition_target")]
7778    pub early_recognition_target: f64,
7779
7780    /// Expense deferral inflation target (Q1).
7781    #[serde(default = "default_expense_deferral_target")]
7782    pub expense_deferral_target: f64,
7783
7784    /// Reserve release inflation target (Q2).
7785    #[serde(default = "default_reserve_release_target")]
7786    pub reserve_release_target: f64,
7787
7788    /// Channel stuffing inflation target (Q4).
7789    #[serde(default = "default_channel_stuffing_target")]
7790    pub channel_stuffing_target: f64,
7791}
7792
7793fn default_revenue_manipulation_probability() -> f64 {
7794    0.01
7795}
7796fn default_early_recognition_target() -> f64 {
7797    0.02
7798}
7799fn default_expense_deferral_target() -> f64 {
7800    0.03
7801}
7802fn default_reserve_release_target() -> f64 {
7803    0.02
7804}
7805fn default_channel_stuffing_target() -> f64 {
7806    0.05
7807}
7808
7809impl Default for RevenueManipulationSchemeConfig {
7810    fn default() -> Self {
7811        Self {
7812            probability: default_revenue_manipulation_probability(),
7813            early_recognition_target: default_early_recognition_target(),
7814            expense_deferral_target: default_expense_deferral_target(),
7815            reserve_release_target: default_reserve_release_target(),
7816            channel_stuffing_target: default_channel_stuffing_target(),
7817        }
7818    }
7819}
7820
7821/// Vendor kickback scheme configuration.
7822#[derive(Debug, Clone, Serialize, Deserialize)]
7823pub struct KickbackSchemeConfig {
7824    /// Probability of starting a kickback scheme.
7825    #[serde(default = "default_kickback_probability")]
7826    pub probability: f64,
7827
7828    /// Minimum price inflation percentage.
7829    #[serde(default = "default_kickback_inflation_min")]
7830    pub inflation_min: f64,
7831
7832    /// Maximum price inflation percentage.
7833    #[serde(default = "default_kickback_inflation_max")]
7834    pub inflation_max: f64,
7835
7836    /// Kickback percentage (of inflation).
7837    #[serde(default = "default_kickback_percent")]
7838    pub kickback_percent: f64,
7839
7840    /// Setup duration in months.
7841    #[serde(default = "default_kickback_setup_months")]
7842    pub setup_months: u32,
7843
7844    /// Main operation duration in months.
7845    #[serde(default = "default_kickback_operation_months")]
7846    pub operation_months: u32,
7847}
7848
7849fn default_kickback_probability() -> f64 {
7850    0.01
7851}
7852fn default_kickback_inflation_min() -> f64 {
7853    0.10
7854}
7855fn default_kickback_inflation_max() -> f64 {
7856    0.25
7857}
7858fn default_kickback_percent() -> f64 {
7859    0.50
7860}
7861fn default_kickback_setup_months() -> u32 {
7862    3
7863}
7864fn default_kickback_operation_months() -> u32 {
7865    12
7866}
7867
7868impl Default for KickbackSchemeConfig {
7869    fn default() -> Self {
7870        Self {
7871            probability: default_kickback_probability(),
7872            inflation_min: default_kickback_inflation_min(),
7873            inflation_max: default_kickback_inflation_max(),
7874            kickback_percent: default_kickback_percent(),
7875            setup_months: default_kickback_setup_months(),
7876            operation_months: default_kickback_operation_months(),
7877        }
7878    }
7879}
7880
7881/// Individual scheme stage configuration.
7882#[derive(Debug, Clone, Serialize, Deserialize)]
7883pub struct SchemeStageConfig {
7884    /// Duration in months.
7885    pub duration_months: u32,
7886
7887    /// Minimum transaction amount.
7888    pub amount_min: f64,
7889
7890    /// Maximum transaction amount.
7891    pub amount_max: f64,
7892
7893    /// Minimum number of transactions.
7894    pub transaction_count_min: u32,
7895
7896    /// Maximum number of transactions.
7897    pub transaction_count_max: u32,
7898
7899    /// Detection difficulty level (trivial, easy, moderate, hard, expert).
7900    pub difficulty: String,
7901}
7902
7903impl Default for SchemeStageConfig {
7904    fn default() -> Self {
7905        Self {
7906            duration_months: 3,
7907            amount_min: 100.0,
7908            amount_max: 1000.0,
7909            transaction_count_min: 2,
7910            transaction_count_max: 10,
7911            difficulty: "moderate".to_string(),
7912        }
7913    }
7914}
7915
7916/// Correlated anomaly injection configuration.
7917#[derive(Debug, Clone, Serialize, Deserialize)]
7918pub struct CorrelatedInjectionConfig {
7919    /// Enable correlated anomaly injection.
7920    #[serde(default)]
7921    pub enabled: bool,
7922
7923    /// Enable fraud concealment co-occurrence patterns.
7924    #[serde(default = "default_true_val")]
7925    pub fraud_concealment: bool,
7926
7927    /// Enable error cascade patterns.
7928    #[serde(default = "default_true_val")]
7929    pub error_cascade: bool,
7930
7931    /// Enable temporal clustering (period-end spikes).
7932    #[serde(default = "default_true_val")]
7933    pub temporal_clustering: bool,
7934
7935    /// Temporal clustering configuration.
7936    #[serde(default)]
7937    pub temporal_clustering_config: TemporalClusteringConfig,
7938
7939    /// Co-occurrence patterns.
7940    #[serde(default)]
7941    pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
7942}
7943
7944impl Default for CorrelatedInjectionConfig {
7945    fn default() -> Self {
7946        Self {
7947            enabled: false,
7948            fraud_concealment: true,
7949            error_cascade: true,
7950            temporal_clustering: true,
7951            temporal_clustering_config: TemporalClusteringConfig::default(),
7952            co_occurrence_patterns: Vec::new(),
7953        }
7954    }
7955}
7956
7957/// Temporal clustering configuration.
7958#[derive(Debug, Clone, Serialize, Deserialize)]
7959pub struct TemporalClusteringConfig {
7960    /// Period-end error multiplier.
7961    #[serde(default = "default_period_end_multiplier")]
7962    pub period_end_multiplier: f64,
7963
7964    /// Number of business days before period end to apply multiplier.
7965    #[serde(default = "default_period_end_days")]
7966    pub period_end_days: u32,
7967
7968    /// Quarter-end additional multiplier.
7969    #[serde(default = "default_quarter_end_multiplier")]
7970    pub quarter_end_multiplier: f64,
7971
7972    /// Year-end additional multiplier.
7973    #[serde(default = "default_year_end_multiplier")]
7974    pub year_end_multiplier: f64,
7975}
7976
7977fn default_period_end_multiplier() -> f64 {
7978    2.5
7979}
7980fn default_period_end_days() -> u32 {
7981    5
7982}
7983fn default_quarter_end_multiplier() -> f64 {
7984    1.5
7985}
7986fn default_year_end_multiplier() -> f64 {
7987    2.0
7988}
7989
7990impl Default for TemporalClusteringConfig {
7991    fn default() -> Self {
7992        Self {
7993            period_end_multiplier: default_period_end_multiplier(),
7994            period_end_days: default_period_end_days(),
7995            quarter_end_multiplier: default_quarter_end_multiplier(),
7996            year_end_multiplier: default_year_end_multiplier(),
7997        }
7998    }
7999}
8000
8001/// Co-occurrence pattern configuration.
8002#[derive(Debug, Clone, Serialize, Deserialize)]
8003pub struct CoOccurrencePatternConfig {
8004    /// Pattern name.
8005    pub name: String,
8006
8007    /// Primary anomaly type that triggers the pattern.
8008    pub primary_type: String,
8009
8010    /// Correlated anomalies.
8011    pub correlated: Vec<CorrelatedAnomalyConfig>,
8012}
8013
8014/// Correlated anomaly configuration.
8015#[derive(Debug, Clone, Serialize, Deserialize)]
8016pub struct CorrelatedAnomalyConfig {
8017    /// Anomaly type.
8018    pub anomaly_type: String,
8019
8020    /// Probability of occurrence (0.0 to 1.0).
8021    pub probability: f64,
8022
8023    /// Minimum lag in days.
8024    pub lag_days_min: i32,
8025
8026    /// Maximum lag in days.
8027    pub lag_days_max: i32,
8028}
8029
8030/// Near-miss generation configuration.
8031#[derive(Debug, Clone, Serialize, Deserialize)]
8032pub struct NearMissConfig {
8033    /// Enable near-miss generation.
8034    #[serde(default)]
8035    pub enabled: bool,
8036
8037    /// Proportion of "anomalies" that are actually near-misses (0.0 to 1.0).
8038    #[serde(default = "default_near_miss_proportion")]
8039    pub proportion: f64,
8040
8041    /// Enable near-duplicate pattern.
8042    #[serde(default = "default_true_val")]
8043    pub near_duplicate: bool,
8044
8045    /// Near-duplicate date difference range in days.
8046    #[serde(default)]
8047    pub near_duplicate_days: NearDuplicateDaysConfig,
8048
8049    /// Enable threshold proximity pattern.
8050    #[serde(default = "default_true_val")]
8051    pub threshold_proximity: bool,
8052
8053    /// Threshold proximity range (e.g., 0.90-0.99 of threshold).
8054    #[serde(default)]
8055    pub threshold_proximity_range: ThresholdProximityRangeConfig,
8056
8057    /// Enable unusual but legitimate patterns.
8058    #[serde(default = "default_true_val")]
8059    pub unusual_legitimate: bool,
8060
8061    /// Types of unusual legitimate patterns to generate.
8062    #[serde(default = "default_unusual_legitimate_types")]
8063    pub unusual_legitimate_types: Vec<String>,
8064
8065    /// Enable corrected error patterns.
8066    #[serde(default = "default_true_val")]
8067    pub corrected_errors: bool,
8068
8069    /// Corrected error correction lag range in days.
8070    #[serde(default)]
8071    pub corrected_error_lag: CorrectedErrorLagConfig,
8072}
8073
8074fn default_near_miss_proportion() -> f64 {
8075    0.30
8076}
8077
8078fn default_unusual_legitimate_types() -> Vec<String> {
8079    vec![
8080        "year_end_bonus".to_string(),
8081        "contract_prepayment".to_string(),
8082        "insurance_claim".to_string(),
8083        "settlement_payment".to_string(),
8084    ]
8085}
8086
8087impl Default for NearMissConfig {
8088    fn default() -> Self {
8089        Self {
8090            enabled: false,
8091            proportion: default_near_miss_proportion(),
8092            near_duplicate: true,
8093            near_duplicate_days: NearDuplicateDaysConfig::default(),
8094            threshold_proximity: true,
8095            threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8096            unusual_legitimate: true,
8097            unusual_legitimate_types: default_unusual_legitimate_types(),
8098            corrected_errors: true,
8099            corrected_error_lag: CorrectedErrorLagConfig::default(),
8100        }
8101    }
8102}
8103
8104/// Near-duplicate days configuration.
8105#[derive(Debug, Clone, Serialize, Deserialize)]
8106pub struct NearDuplicateDaysConfig {
8107    /// Minimum days apart.
8108    #[serde(default = "default_near_duplicate_min")]
8109    pub min: u32,
8110
8111    /// Maximum days apart.
8112    #[serde(default = "default_near_duplicate_max")]
8113    pub max: u32,
8114}
8115
8116fn default_near_duplicate_min() -> u32 {
8117    1
8118}
8119fn default_near_duplicate_max() -> u32 {
8120    3
8121}
8122
8123impl Default for NearDuplicateDaysConfig {
8124    fn default() -> Self {
8125        Self {
8126            min: default_near_duplicate_min(),
8127            max: default_near_duplicate_max(),
8128        }
8129    }
8130}
8131
8132/// Threshold proximity range configuration.
8133#[derive(Debug, Clone, Serialize, Deserialize)]
8134pub struct ThresholdProximityRangeConfig {
8135    /// Minimum proximity (e.g., 0.90 = 90% of threshold).
8136    #[serde(default = "default_threshold_proximity_min")]
8137    pub min: f64,
8138
8139    /// Maximum proximity (e.g., 0.99 = 99% of threshold).
8140    #[serde(default = "default_threshold_proximity_max")]
8141    pub max: f64,
8142}
8143
8144fn default_threshold_proximity_min() -> f64 {
8145    0.90
8146}
8147fn default_threshold_proximity_max() -> f64 {
8148    0.99
8149}
8150
8151impl Default for ThresholdProximityRangeConfig {
8152    fn default() -> Self {
8153        Self {
8154            min: default_threshold_proximity_min(),
8155            max: default_threshold_proximity_max(),
8156        }
8157    }
8158}
8159
8160/// Corrected error lag configuration.
8161#[derive(Debug, Clone, Serialize, Deserialize)]
8162pub struct CorrectedErrorLagConfig {
8163    /// Minimum correction lag in days.
8164    #[serde(default = "default_corrected_error_lag_min")]
8165    pub min: u32,
8166
8167    /// Maximum correction lag in days.
8168    #[serde(default = "default_corrected_error_lag_max")]
8169    pub max: u32,
8170}
8171
8172fn default_corrected_error_lag_min() -> u32 {
8173    1
8174}
8175fn default_corrected_error_lag_max() -> u32 {
8176    5
8177}
8178
8179impl Default for CorrectedErrorLagConfig {
8180    fn default() -> Self {
8181        Self {
8182            min: default_corrected_error_lag_min(),
8183            max: default_corrected_error_lag_max(),
8184        }
8185    }
8186}
8187
8188/// Detection difficulty classification configuration.
8189#[derive(Debug, Clone, Serialize, Deserialize)]
8190pub struct DifficultyClassificationConfig {
8191    /// Enable detection difficulty classification.
8192    #[serde(default)]
8193    pub enabled: bool,
8194
8195    /// Target distribution of difficulty levels.
8196    #[serde(default)]
8197    pub target_distribution: DifficultyDistributionConfig,
8198}
8199
8200impl Default for DifficultyClassificationConfig {
8201    fn default() -> Self {
8202        Self {
8203            enabled: true,
8204            target_distribution: DifficultyDistributionConfig::default(),
8205        }
8206    }
8207}
8208
8209/// Target distribution of detection difficulty levels.
8210#[derive(Debug, Clone, Serialize, Deserialize)]
8211pub struct DifficultyDistributionConfig {
8212    /// Proportion of trivial anomalies (expected 99% detection).
8213    #[serde(default = "default_difficulty_trivial")]
8214    pub trivial: f64,
8215
8216    /// Proportion of easy anomalies (expected 90% detection).
8217    #[serde(default = "default_difficulty_easy")]
8218    pub easy: f64,
8219
8220    /// Proportion of moderate anomalies (expected 70% detection).
8221    #[serde(default = "default_difficulty_moderate")]
8222    pub moderate: f64,
8223
8224    /// Proportion of hard anomalies (expected 40% detection).
8225    #[serde(default = "default_difficulty_hard")]
8226    pub hard: f64,
8227
8228    /// Proportion of expert anomalies (expected 15% detection).
8229    #[serde(default = "default_difficulty_expert")]
8230    pub expert: f64,
8231}
8232
8233fn default_difficulty_trivial() -> f64 {
8234    0.15
8235}
8236fn default_difficulty_easy() -> f64 {
8237    0.25
8238}
8239fn default_difficulty_moderate() -> f64 {
8240    0.30
8241}
8242fn default_difficulty_hard() -> f64 {
8243    0.20
8244}
8245fn default_difficulty_expert() -> f64 {
8246    0.10
8247}
8248
8249impl Default for DifficultyDistributionConfig {
8250    fn default() -> Self {
8251        Self {
8252            trivial: default_difficulty_trivial(),
8253            easy: default_difficulty_easy(),
8254            moderate: default_difficulty_moderate(),
8255            hard: default_difficulty_hard(),
8256            expert: default_difficulty_expert(),
8257        }
8258    }
8259}
8260
8261/// Context-aware injection configuration.
8262#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8263pub struct ContextAwareConfig {
8264    /// Enable context-aware injection.
8265    #[serde(default)]
8266    pub enabled: bool,
8267
8268    /// Vendor-specific anomaly rules.
8269    #[serde(default)]
8270    pub vendor_rules: VendorAnomalyRulesConfig,
8271
8272    /// Employee-specific anomaly rules.
8273    #[serde(default)]
8274    pub employee_rules: EmployeeAnomalyRulesConfig,
8275
8276    /// Account-specific anomaly rules.
8277    #[serde(default)]
8278    pub account_rules: AccountAnomalyRulesConfig,
8279
8280    /// Behavioral baseline configuration.
8281    #[serde(default)]
8282    pub behavioral_baseline: BehavioralBaselineConfig,
8283}
8284
8285/// Vendor-specific anomaly rules configuration.
8286#[derive(Debug, Clone, Serialize, Deserialize)]
8287pub struct VendorAnomalyRulesConfig {
8288    /// Error rate multiplier for new vendors (< threshold days).
8289    #[serde(default = "default_new_vendor_multiplier")]
8290    pub new_vendor_error_multiplier: f64,
8291
8292    /// Days threshold for "new" vendor classification.
8293    #[serde(default = "default_new_vendor_threshold")]
8294    pub new_vendor_threshold_days: u32,
8295
8296    /// Error rate multiplier for international vendors.
8297    #[serde(default = "default_international_multiplier")]
8298    pub international_error_multiplier: f64,
8299
8300    /// Strategic vendor anomaly types (may differ from general vendors).
8301    #[serde(default = "default_strategic_vendor_types")]
8302    pub strategic_vendor_anomaly_types: Vec<String>,
8303}
8304
8305fn default_new_vendor_multiplier() -> f64 {
8306    2.5
8307}
8308fn default_new_vendor_threshold() -> u32 {
8309    90
8310}
8311fn default_international_multiplier() -> f64 {
8312    1.5
8313}
8314fn default_strategic_vendor_types() -> Vec<String> {
8315    vec![
8316        "pricing_dispute".to_string(),
8317        "contract_violation".to_string(),
8318    ]
8319}
8320
8321impl Default for VendorAnomalyRulesConfig {
8322    fn default() -> Self {
8323        Self {
8324            new_vendor_error_multiplier: default_new_vendor_multiplier(),
8325            new_vendor_threshold_days: default_new_vendor_threshold(),
8326            international_error_multiplier: default_international_multiplier(),
8327            strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8328        }
8329    }
8330}
8331
8332/// Employee-specific anomaly rules configuration.
8333#[derive(Debug, Clone, Serialize, Deserialize)]
8334pub struct EmployeeAnomalyRulesConfig {
8335    /// Error rate for new employees (< threshold days).
8336    #[serde(default = "default_new_employee_rate")]
8337    pub new_employee_error_rate: f64,
8338
8339    /// Days threshold for "new" employee classification.
8340    #[serde(default = "default_new_employee_threshold")]
8341    pub new_employee_threshold_days: u32,
8342
8343    /// Transaction volume threshold for fatigue errors.
8344    #[serde(default = "default_volume_fatigue_threshold")]
8345    pub volume_fatigue_threshold: u32,
8346
8347    /// Error rate multiplier when primary approver is absent.
8348    #[serde(default = "default_coverage_multiplier")]
8349    pub coverage_error_multiplier: f64,
8350}
8351
8352fn default_new_employee_rate() -> f64 {
8353    0.05
8354}
8355fn default_new_employee_threshold() -> u32 {
8356    180
8357}
8358fn default_volume_fatigue_threshold() -> u32 {
8359    50
8360}
8361fn default_coverage_multiplier() -> f64 {
8362    1.8
8363}
8364
8365impl Default for EmployeeAnomalyRulesConfig {
8366    fn default() -> Self {
8367        Self {
8368            new_employee_error_rate: default_new_employee_rate(),
8369            new_employee_threshold_days: default_new_employee_threshold(),
8370            volume_fatigue_threshold: default_volume_fatigue_threshold(),
8371            coverage_error_multiplier: default_coverage_multiplier(),
8372        }
8373    }
8374}
8375
8376/// Account-specific anomaly rules configuration.
8377#[derive(Debug, Clone, Serialize, Deserialize)]
8378pub struct AccountAnomalyRulesConfig {
8379    /// Error rate multiplier for high-risk accounts.
8380    #[serde(default = "default_high_risk_multiplier")]
8381    pub high_risk_account_multiplier: f64,
8382
8383    /// Account codes considered high-risk.
8384    #[serde(default = "default_high_risk_accounts")]
8385    pub high_risk_accounts: Vec<String>,
8386
8387    /// Error rate multiplier for suspense accounts.
8388    #[serde(default = "default_suspense_multiplier")]
8389    pub suspense_account_multiplier: f64,
8390
8391    /// Account codes considered suspense accounts.
8392    #[serde(default = "default_suspense_accounts")]
8393    pub suspense_accounts: Vec<String>,
8394
8395    /// Error rate multiplier for intercompany accounts.
8396    #[serde(default = "default_intercompany_multiplier")]
8397    pub intercompany_account_multiplier: f64,
8398}
8399
8400fn default_high_risk_multiplier() -> f64 {
8401    2.0
8402}
8403fn default_high_risk_accounts() -> Vec<String> {
8404    vec![
8405        "1100".to_string(), // AR Control
8406        "2000".to_string(), // AP Control
8407        "3000".to_string(), // Cash
8408    ]
8409}
8410fn default_suspense_multiplier() -> f64 {
8411    3.0
8412}
8413fn default_suspense_accounts() -> Vec<String> {
8414    vec!["9999".to_string(), "9998".to_string()]
8415}
8416fn default_intercompany_multiplier() -> f64 {
8417    1.5
8418}
8419
8420impl Default for AccountAnomalyRulesConfig {
8421    fn default() -> Self {
8422        Self {
8423            high_risk_account_multiplier: default_high_risk_multiplier(),
8424            high_risk_accounts: default_high_risk_accounts(),
8425            suspense_account_multiplier: default_suspense_multiplier(),
8426            suspense_accounts: default_suspense_accounts(),
8427            intercompany_account_multiplier: default_intercompany_multiplier(),
8428        }
8429    }
8430}
8431
8432/// Behavioral baseline configuration.
8433#[derive(Debug, Clone, Serialize, Deserialize)]
8434pub struct BehavioralBaselineConfig {
8435    /// Enable behavioral baseline tracking.
8436    #[serde(default)]
8437    pub enabled: bool,
8438
8439    /// Number of days to build baseline from.
8440    #[serde(default = "default_baseline_period")]
8441    pub baseline_period_days: u32,
8442
8443    /// Standard deviation threshold for amount anomalies.
8444    #[serde(default = "default_deviation_threshold")]
8445    pub deviation_threshold_std: f64,
8446
8447    /// Standard deviation threshold for frequency anomalies.
8448    #[serde(default = "default_frequency_deviation")]
8449    pub frequency_deviation_threshold: f64,
8450}
8451
8452fn default_baseline_period() -> u32 {
8453    90
8454}
8455fn default_deviation_threshold() -> f64 {
8456    3.0
8457}
8458fn default_frequency_deviation() -> f64 {
8459    2.0
8460}
8461
8462impl Default for BehavioralBaselineConfig {
8463    fn default() -> Self {
8464        Self {
8465            enabled: false,
8466            baseline_period_days: default_baseline_period(),
8467            deviation_threshold_std: default_deviation_threshold(),
8468            frequency_deviation_threshold: default_frequency_deviation(),
8469        }
8470    }
8471}
8472
8473/// Enhanced labeling configuration.
8474#[derive(Debug, Clone, Serialize, Deserialize)]
8475pub struct EnhancedLabelingConfig {
8476    /// Enable severity scoring.
8477    #[serde(default = "default_true_val")]
8478    pub severity_scoring: bool,
8479
8480    /// Enable difficulty classification.
8481    #[serde(default = "default_true_val")]
8482    pub difficulty_classification: bool,
8483
8484    /// Materiality thresholds for severity classification.
8485    #[serde(default)]
8486    pub materiality_thresholds: MaterialityThresholdsConfig,
8487}
8488
8489impl Default for EnhancedLabelingConfig {
8490    fn default() -> Self {
8491        Self {
8492            severity_scoring: true,
8493            difficulty_classification: true,
8494            materiality_thresholds: MaterialityThresholdsConfig::default(),
8495        }
8496    }
8497}
8498
8499/// Materiality thresholds configuration.
8500#[derive(Debug, Clone, Serialize, Deserialize)]
8501pub struct MaterialityThresholdsConfig {
8502    /// Threshold for trivial impact (as percentage of total).
8503    #[serde(default = "default_materiality_trivial")]
8504    pub trivial: f64,
8505
8506    /// Threshold for immaterial impact.
8507    #[serde(default = "default_materiality_immaterial")]
8508    pub immaterial: f64,
8509
8510    /// Threshold for material impact.
8511    #[serde(default = "default_materiality_material")]
8512    pub material: f64,
8513
8514    /// Threshold for highly material impact.
8515    #[serde(default = "default_materiality_highly_material")]
8516    pub highly_material: f64,
8517}
8518
8519fn default_materiality_trivial() -> f64 {
8520    0.001
8521}
8522fn default_materiality_immaterial() -> f64 {
8523    0.01
8524}
8525fn default_materiality_material() -> f64 {
8526    0.05
8527}
8528fn default_materiality_highly_material() -> f64 {
8529    0.10
8530}
8531
8532impl Default for MaterialityThresholdsConfig {
8533    fn default() -> Self {
8534        Self {
8535            trivial: default_materiality_trivial(),
8536            immaterial: default_materiality_immaterial(),
8537            material: default_materiality_material(),
8538            highly_material: default_materiality_highly_material(),
8539        }
8540    }
8541}
8542
8543// =============================================================================
8544// Industry-Specific Configuration
8545// =============================================================================
8546
8547/// Industry-specific transaction and anomaly generation configuration.
8548///
8549/// This configuration enables generation of industry-authentic:
8550/// - Transaction types with appropriate terminology
8551/// - Master data (BOM, routings, clinical codes, etc.)
8552/// - Industry-specific anomaly patterns
8553/// - Regulatory framework compliance
8554#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8555pub struct IndustrySpecificConfig {
8556    /// Enable industry-specific generation.
8557    #[serde(default)]
8558    pub enabled: bool,
8559
8560    /// Manufacturing industry settings.
8561    #[serde(default)]
8562    pub manufacturing: ManufacturingConfig,
8563
8564    /// Retail industry settings.
8565    #[serde(default)]
8566    pub retail: RetailConfig,
8567
8568    /// Healthcare industry settings.
8569    #[serde(default)]
8570    pub healthcare: HealthcareConfig,
8571
8572    /// Technology industry settings.
8573    #[serde(default)]
8574    pub technology: TechnologyConfig,
8575
8576    /// Financial services industry settings.
8577    #[serde(default)]
8578    pub financial_services: FinancialServicesConfig,
8579
8580    /// Professional services industry settings.
8581    #[serde(default)]
8582    pub professional_services: ProfessionalServicesConfig,
8583}
8584
8585/// Manufacturing industry configuration.
8586#[derive(Debug, Clone, Serialize, Deserialize)]
8587pub struct ManufacturingConfig {
8588    /// Enable manufacturing-specific generation.
8589    #[serde(default)]
8590    pub enabled: bool,
8591
8592    /// Bill of Materials depth (typical: 3-7).
8593    #[serde(default = "default_bom_depth")]
8594    pub bom_depth: u32,
8595
8596    /// Whether to use just-in-time inventory.
8597    #[serde(default)]
8598    pub just_in_time: bool,
8599
8600    /// Production order types to generate.
8601    #[serde(default = "default_production_order_types")]
8602    pub production_order_types: Vec<String>,
8603
8604    /// Quality framework (ISO_9001, Six_Sigma, etc.).
8605    #[serde(default)]
8606    pub quality_framework: Option<String>,
8607
8608    /// Number of supplier tiers to model (1-3).
8609    #[serde(default = "default_supplier_tiers")]
8610    pub supplier_tiers: u32,
8611
8612    /// Standard cost update frequency.
8613    #[serde(default = "default_cost_frequency")]
8614    pub standard_cost_frequency: String,
8615
8616    /// Target yield rate (0.95-0.99 typical).
8617    #[serde(default = "default_yield_rate")]
8618    pub target_yield_rate: f64,
8619
8620    /// Scrap percentage threshold for alerts.
8621    #[serde(default = "default_scrap_threshold")]
8622    pub scrap_alert_threshold: f64,
8623
8624    /// Manufacturing anomaly injection rates.
8625    #[serde(default)]
8626    pub anomaly_rates: ManufacturingAnomalyRates,
8627}
8628
8629fn default_bom_depth() -> u32 {
8630    4
8631}
8632
8633fn default_production_order_types() -> Vec<String> {
8634    vec![
8635        "standard".to_string(),
8636        "rework".to_string(),
8637        "prototype".to_string(),
8638    ]
8639}
8640
8641fn default_supplier_tiers() -> u32 {
8642    2
8643}
8644
8645fn default_cost_frequency() -> String {
8646    "quarterly".to_string()
8647}
8648
8649fn default_yield_rate() -> f64 {
8650    0.97
8651}
8652
8653fn default_scrap_threshold() -> f64 {
8654    0.03
8655}
8656
8657impl Default for ManufacturingConfig {
8658    fn default() -> Self {
8659        Self {
8660            enabled: false,
8661            bom_depth: default_bom_depth(),
8662            just_in_time: false,
8663            production_order_types: default_production_order_types(),
8664            quality_framework: Some("ISO_9001".to_string()),
8665            supplier_tiers: default_supplier_tiers(),
8666            standard_cost_frequency: default_cost_frequency(),
8667            target_yield_rate: default_yield_rate(),
8668            scrap_alert_threshold: default_scrap_threshold(),
8669            anomaly_rates: ManufacturingAnomalyRates::default(),
8670        }
8671    }
8672}
8673
8674/// Manufacturing anomaly injection rates.
8675#[derive(Debug, Clone, Serialize, Deserialize)]
8676pub struct ManufacturingAnomalyRates {
8677    /// Yield manipulation rate.
8678    #[serde(default = "default_mfg_yield_rate")]
8679    pub yield_manipulation: f64,
8680
8681    /// Labor misallocation rate.
8682    #[serde(default = "default_mfg_labor_rate")]
8683    pub labor_misallocation: f64,
8684
8685    /// Phantom production rate.
8686    #[serde(default = "default_mfg_phantom_rate")]
8687    pub phantom_production: f64,
8688
8689    /// Standard cost manipulation rate.
8690    #[serde(default = "default_mfg_cost_rate")]
8691    pub standard_cost_manipulation: f64,
8692
8693    /// Inventory fraud rate.
8694    #[serde(default = "default_mfg_inventory_rate")]
8695    pub inventory_fraud: f64,
8696}
8697
8698fn default_mfg_yield_rate() -> f64 {
8699    0.015
8700}
8701
8702fn default_mfg_labor_rate() -> f64 {
8703    0.02
8704}
8705
8706fn default_mfg_phantom_rate() -> f64 {
8707    0.005
8708}
8709
8710fn default_mfg_cost_rate() -> f64 {
8711    0.01
8712}
8713
8714fn default_mfg_inventory_rate() -> f64 {
8715    0.008
8716}
8717
8718impl Default for ManufacturingAnomalyRates {
8719    fn default() -> Self {
8720        Self {
8721            yield_manipulation: default_mfg_yield_rate(),
8722            labor_misallocation: default_mfg_labor_rate(),
8723            phantom_production: default_mfg_phantom_rate(),
8724            standard_cost_manipulation: default_mfg_cost_rate(),
8725            inventory_fraud: default_mfg_inventory_rate(),
8726        }
8727    }
8728}
8729
8730/// Retail industry configuration.
8731#[derive(Debug, Clone, Serialize, Deserialize)]
8732pub struct RetailConfig {
8733    /// Enable retail-specific generation.
8734    #[serde(default)]
8735    pub enabled: bool,
8736
8737    /// Store type distribution.
8738    #[serde(default)]
8739    pub store_types: RetailStoreTypeConfig,
8740
8741    /// Average daily transactions per store.
8742    #[serde(default = "default_retail_daily_txns")]
8743    pub avg_daily_transactions: u32,
8744
8745    /// Enable loss prevention tracking.
8746    #[serde(default = "default_true")]
8747    pub loss_prevention: bool,
8748
8749    /// Shrinkage rate (0.01-0.03 typical).
8750    #[serde(default = "default_shrinkage_rate")]
8751    pub shrinkage_rate: f64,
8752
8753    /// Retail anomaly injection rates.
8754    #[serde(default)]
8755    pub anomaly_rates: RetailAnomalyRates,
8756}
8757
8758fn default_retail_daily_txns() -> u32 {
8759    500
8760}
8761
8762fn default_shrinkage_rate() -> f64 {
8763    0.015
8764}
8765
8766impl Default for RetailConfig {
8767    fn default() -> Self {
8768        Self {
8769            enabled: false,
8770            store_types: RetailStoreTypeConfig::default(),
8771            avg_daily_transactions: default_retail_daily_txns(),
8772            loss_prevention: true,
8773            shrinkage_rate: default_shrinkage_rate(),
8774            anomaly_rates: RetailAnomalyRates::default(),
8775        }
8776    }
8777}
8778
8779/// Retail store type distribution.
8780#[derive(Debug, Clone, Serialize, Deserialize)]
8781pub struct RetailStoreTypeConfig {
8782    /// Percentage of flagship stores.
8783    #[serde(default = "default_flagship_pct")]
8784    pub flagship: f64,
8785
8786    /// Percentage of regional stores.
8787    #[serde(default = "default_regional_pct")]
8788    pub regional: f64,
8789
8790    /// Percentage of outlet stores.
8791    #[serde(default = "default_outlet_pct")]
8792    pub outlet: f64,
8793
8794    /// Percentage of e-commerce.
8795    #[serde(default = "default_ecommerce_pct")]
8796    pub ecommerce: f64,
8797}
8798
8799fn default_flagship_pct() -> f64 {
8800    0.10
8801}
8802
8803fn default_regional_pct() -> f64 {
8804    0.50
8805}
8806
8807fn default_outlet_pct() -> f64 {
8808    0.25
8809}
8810
8811fn default_ecommerce_pct() -> f64 {
8812    0.15
8813}
8814
8815impl Default for RetailStoreTypeConfig {
8816    fn default() -> Self {
8817        Self {
8818            flagship: default_flagship_pct(),
8819            regional: default_regional_pct(),
8820            outlet: default_outlet_pct(),
8821            ecommerce: default_ecommerce_pct(),
8822        }
8823    }
8824}
8825
8826/// Retail anomaly injection rates.
8827#[derive(Debug, Clone, Serialize, Deserialize)]
8828pub struct RetailAnomalyRates {
8829    /// Sweethearting rate.
8830    #[serde(default = "default_sweethearting_rate")]
8831    pub sweethearting: f64,
8832
8833    /// Skimming rate.
8834    #[serde(default = "default_skimming_rate")]
8835    pub skimming: f64,
8836
8837    /// Refund fraud rate.
8838    #[serde(default = "default_refund_fraud_rate")]
8839    pub refund_fraud: f64,
8840
8841    /// Void abuse rate.
8842    #[serde(default = "default_void_abuse_rate")]
8843    pub void_abuse: f64,
8844
8845    /// Gift card fraud rate.
8846    #[serde(default = "default_gift_card_rate")]
8847    pub gift_card_fraud: f64,
8848
8849    /// Vendor kickback rate.
8850    #[serde(default = "default_retail_kickback_rate")]
8851    pub vendor_kickback: f64,
8852}
8853
8854fn default_sweethearting_rate() -> f64 {
8855    0.02
8856}
8857
8858fn default_skimming_rate() -> f64 {
8859    0.005
8860}
8861
8862fn default_refund_fraud_rate() -> f64 {
8863    0.015
8864}
8865
8866fn default_void_abuse_rate() -> f64 {
8867    0.01
8868}
8869
8870fn default_gift_card_rate() -> f64 {
8871    0.008
8872}
8873
8874fn default_retail_kickback_rate() -> f64 {
8875    0.003
8876}
8877
8878impl Default for RetailAnomalyRates {
8879    fn default() -> Self {
8880        Self {
8881            sweethearting: default_sweethearting_rate(),
8882            skimming: default_skimming_rate(),
8883            refund_fraud: default_refund_fraud_rate(),
8884            void_abuse: default_void_abuse_rate(),
8885            gift_card_fraud: default_gift_card_rate(),
8886            vendor_kickback: default_retail_kickback_rate(),
8887        }
8888    }
8889}
8890
8891/// Healthcare industry configuration.
8892#[derive(Debug, Clone, Serialize, Deserialize)]
8893pub struct HealthcareConfig {
8894    /// Enable healthcare-specific generation.
8895    #[serde(default)]
8896    pub enabled: bool,
8897
8898    /// Healthcare facility type.
8899    #[serde(default = "default_facility_type")]
8900    pub facility_type: String,
8901
8902    /// Payer mix distribution.
8903    #[serde(default)]
8904    pub payer_mix: HealthcarePayerMix,
8905
8906    /// Coding systems enabled.
8907    #[serde(default)]
8908    pub coding_systems: HealthcareCodingSystems,
8909
8910    /// Healthcare compliance settings.
8911    #[serde(default)]
8912    pub compliance: HealthcareComplianceConfig,
8913
8914    /// Average daily encounters.
8915    #[serde(default = "default_daily_encounters")]
8916    pub avg_daily_encounters: u32,
8917
8918    /// Average charges per encounter.
8919    #[serde(default = "default_charges_per_encounter")]
8920    pub avg_charges_per_encounter: u32,
8921
8922    /// Denial rate (0.0-1.0).
8923    #[serde(default = "default_hc_denial_rate")]
8924    pub denial_rate: f64,
8925
8926    /// Bad debt rate (0.0-1.0).
8927    #[serde(default = "default_hc_bad_debt_rate")]
8928    pub bad_debt_rate: f64,
8929
8930    /// Charity care rate (0.0-1.0).
8931    #[serde(default = "default_hc_charity_care_rate")]
8932    pub charity_care_rate: f64,
8933
8934    /// Healthcare anomaly injection rates.
8935    #[serde(default)]
8936    pub anomaly_rates: HealthcareAnomalyRates,
8937}
8938
8939fn default_facility_type() -> String {
8940    "hospital".to_string()
8941}
8942
8943fn default_daily_encounters() -> u32 {
8944    150
8945}
8946
8947fn default_charges_per_encounter() -> u32 {
8948    8
8949}
8950
8951fn default_hc_denial_rate() -> f64 {
8952    0.05
8953}
8954
8955fn default_hc_bad_debt_rate() -> f64 {
8956    0.03
8957}
8958
8959fn default_hc_charity_care_rate() -> f64 {
8960    0.02
8961}
8962
8963impl Default for HealthcareConfig {
8964    fn default() -> Self {
8965        Self {
8966            enabled: false,
8967            facility_type: default_facility_type(),
8968            payer_mix: HealthcarePayerMix::default(),
8969            coding_systems: HealthcareCodingSystems::default(),
8970            compliance: HealthcareComplianceConfig::default(),
8971            avg_daily_encounters: default_daily_encounters(),
8972            avg_charges_per_encounter: default_charges_per_encounter(),
8973            denial_rate: default_hc_denial_rate(),
8974            bad_debt_rate: default_hc_bad_debt_rate(),
8975            charity_care_rate: default_hc_charity_care_rate(),
8976            anomaly_rates: HealthcareAnomalyRates::default(),
8977        }
8978    }
8979}
8980
8981/// Healthcare payer mix distribution.
8982#[derive(Debug, Clone, Serialize, Deserialize)]
8983pub struct HealthcarePayerMix {
8984    /// Medicare percentage.
8985    #[serde(default = "default_medicare_pct")]
8986    pub medicare: f64,
8987
8988    /// Medicaid percentage.
8989    #[serde(default = "default_medicaid_pct")]
8990    pub medicaid: f64,
8991
8992    /// Commercial insurance percentage.
8993    #[serde(default = "default_commercial_pct")]
8994    pub commercial: f64,
8995
8996    /// Self-pay percentage.
8997    #[serde(default = "default_self_pay_pct")]
8998    pub self_pay: f64,
8999}
9000
9001fn default_medicare_pct() -> f64 {
9002    0.40
9003}
9004
9005fn default_medicaid_pct() -> f64 {
9006    0.20
9007}
9008
9009fn default_commercial_pct() -> f64 {
9010    0.30
9011}
9012
9013fn default_self_pay_pct() -> f64 {
9014    0.10
9015}
9016
9017impl Default for HealthcarePayerMix {
9018    fn default() -> Self {
9019        Self {
9020            medicare: default_medicare_pct(),
9021            medicaid: default_medicaid_pct(),
9022            commercial: default_commercial_pct(),
9023            self_pay: default_self_pay_pct(),
9024        }
9025    }
9026}
9027
9028/// Healthcare coding systems configuration.
9029#[derive(Debug, Clone, Serialize, Deserialize)]
9030pub struct HealthcareCodingSystems {
9031    /// Enable ICD-10 diagnosis coding.
9032    #[serde(default = "default_true")]
9033    pub icd10: bool,
9034
9035    /// Enable CPT procedure coding.
9036    #[serde(default = "default_true")]
9037    pub cpt: bool,
9038
9039    /// Enable DRG grouping.
9040    #[serde(default = "default_true")]
9041    pub drg: bool,
9042
9043    /// Enable HCPCS Level II coding.
9044    #[serde(default = "default_true")]
9045    pub hcpcs: bool,
9046
9047    /// Enable revenue codes.
9048    #[serde(default = "default_true")]
9049    pub revenue_codes: bool,
9050}
9051
9052impl Default for HealthcareCodingSystems {
9053    fn default() -> Self {
9054        Self {
9055            icd10: true,
9056            cpt: true,
9057            drg: true,
9058            hcpcs: true,
9059            revenue_codes: true,
9060        }
9061    }
9062}
9063
9064/// Healthcare compliance configuration.
9065#[derive(Debug, Clone, Serialize, Deserialize)]
9066pub struct HealthcareComplianceConfig {
9067    /// Enable HIPAA compliance.
9068    #[serde(default = "default_true")]
9069    pub hipaa: bool,
9070
9071    /// Enable Stark Law compliance.
9072    #[serde(default = "default_true")]
9073    pub stark_law: bool,
9074
9075    /// Enable Anti-Kickback Statute compliance.
9076    #[serde(default = "default_true")]
9077    pub anti_kickback: bool,
9078
9079    /// Enable False Claims Act compliance.
9080    #[serde(default = "default_true")]
9081    pub false_claims_act: bool,
9082
9083    /// Enable EMTALA compliance (for hospitals).
9084    #[serde(default = "default_true")]
9085    pub emtala: bool,
9086}
9087
9088impl Default for HealthcareComplianceConfig {
9089    fn default() -> Self {
9090        Self {
9091            hipaa: true,
9092            stark_law: true,
9093            anti_kickback: true,
9094            false_claims_act: true,
9095            emtala: true,
9096        }
9097    }
9098}
9099
9100/// Healthcare anomaly injection rates.
9101#[derive(Debug, Clone, Serialize, Deserialize)]
9102pub struct HealthcareAnomalyRates {
9103    /// Upcoding rate.
9104    #[serde(default = "default_upcoding_rate")]
9105    pub upcoding: f64,
9106
9107    /// Unbundling rate.
9108    #[serde(default = "default_unbundling_rate")]
9109    pub unbundling: f64,
9110
9111    /// Phantom billing rate.
9112    #[serde(default = "default_phantom_billing_rate")]
9113    pub phantom_billing: f64,
9114
9115    /// Kickback rate.
9116    #[serde(default = "default_healthcare_kickback_rate")]
9117    pub kickbacks: f64,
9118
9119    /// Duplicate billing rate.
9120    #[serde(default = "default_duplicate_billing_rate")]
9121    pub duplicate_billing: f64,
9122
9123    /// Medical necessity abuse rate.
9124    #[serde(default = "default_med_necessity_rate")]
9125    pub medical_necessity_abuse: f64,
9126}
9127
9128fn default_upcoding_rate() -> f64 {
9129    0.02
9130}
9131
9132fn default_unbundling_rate() -> f64 {
9133    0.015
9134}
9135
9136fn default_phantom_billing_rate() -> f64 {
9137    0.005
9138}
9139
9140fn default_healthcare_kickback_rate() -> f64 {
9141    0.003
9142}
9143
9144fn default_duplicate_billing_rate() -> f64 {
9145    0.008
9146}
9147
9148fn default_med_necessity_rate() -> f64 {
9149    0.01
9150}
9151
9152impl Default for HealthcareAnomalyRates {
9153    fn default() -> Self {
9154        Self {
9155            upcoding: default_upcoding_rate(),
9156            unbundling: default_unbundling_rate(),
9157            phantom_billing: default_phantom_billing_rate(),
9158            kickbacks: default_healthcare_kickback_rate(),
9159            duplicate_billing: default_duplicate_billing_rate(),
9160            medical_necessity_abuse: default_med_necessity_rate(),
9161        }
9162    }
9163}
9164
9165/// Technology industry configuration.
9166#[derive(Debug, Clone, Serialize, Deserialize)]
9167pub struct TechnologyConfig {
9168    /// Enable technology-specific generation.
9169    #[serde(default)]
9170    pub enabled: bool,
9171
9172    /// Revenue model type.
9173    #[serde(default = "default_revenue_model")]
9174    pub revenue_model: String,
9175
9176    /// Subscription revenue percentage (for SaaS).
9177    #[serde(default = "default_subscription_pct")]
9178    pub subscription_revenue_pct: f64,
9179
9180    /// License revenue percentage.
9181    #[serde(default = "default_license_pct")]
9182    pub license_revenue_pct: f64,
9183
9184    /// Services revenue percentage.
9185    #[serde(default = "default_services_pct")]
9186    pub services_revenue_pct: f64,
9187
9188    /// R&D capitalization settings.
9189    #[serde(default)]
9190    pub rd_capitalization: RdCapitalizationConfig,
9191
9192    /// Technology anomaly injection rates.
9193    #[serde(default)]
9194    pub anomaly_rates: TechnologyAnomalyRates,
9195}
9196
9197fn default_revenue_model() -> String {
9198    "saas".to_string()
9199}
9200
9201fn default_subscription_pct() -> f64 {
9202    0.60
9203}
9204
9205fn default_license_pct() -> f64 {
9206    0.25
9207}
9208
9209fn default_services_pct() -> f64 {
9210    0.15
9211}
9212
9213impl Default for TechnologyConfig {
9214    fn default() -> Self {
9215        Self {
9216            enabled: false,
9217            revenue_model: default_revenue_model(),
9218            subscription_revenue_pct: default_subscription_pct(),
9219            license_revenue_pct: default_license_pct(),
9220            services_revenue_pct: default_services_pct(),
9221            rd_capitalization: RdCapitalizationConfig::default(),
9222            anomaly_rates: TechnologyAnomalyRates::default(),
9223        }
9224    }
9225}
9226
9227/// R&D capitalization configuration.
9228#[derive(Debug, Clone, Serialize, Deserialize)]
9229pub struct RdCapitalizationConfig {
9230    /// Enable R&D capitalization.
9231    #[serde(default = "default_true")]
9232    pub enabled: bool,
9233
9234    /// Capitalization rate (0.0-1.0).
9235    #[serde(default = "default_cap_rate")]
9236    pub capitalization_rate: f64,
9237
9238    /// Useful life in years.
9239    #[serde(default = "default_useful_life")]
9240    pub useful_life_years: u32,
9241}
9242
9243fn default_cap_rate() -> f64 {
9244    0.30
9245}
9246
9247fn default_useful_life() -> u32 {
9248    3
9249}
9250
9251impl Default for RdCapitalizationConfig {
9252    fn default() -> Self {
9253        Self {
9254            enabled: true,
9255            capitalization_rate: default_cap_rate(),
9256            useful_life_years: default_useful_life(),
9257        }
9258    }
9259}
9260
9261/// Technology anomaly injection rates.
9262#[derive(Debug, Clone, Serialize, Deserialize)]
9263pub struct TechnologyAnomalyRates {
9264    /// Premature revenue recognition rate.
9265    #[serde(default = "default_premature_rev_rate")]
9266    pub premature_revenue: f64,
9267
9268    /// Side letter abuse rate.
9269    #[serde(default = "default_side_letter_rate")]
9270    pub side_letter_abuse: f64,
9271
9272    /// Channel stuffing rate.
9273    #[serde(default = "default_channel_stuffing_rate")]
9274    pub channel_stuffing: f64,
9275
9276    /// Improper capitalization rate.
9277    #[serde(default = "default_improper_cap_rate")]
9278    pub improper_capitalization: f64,
9279}
9280
9281fn default_premature_rev_rate() -> f64 {
9282    0.015
9283}
9284
9285fn default_side_letter_rate() -> f64 {
9286    0.008
9287}
9288
9289fn default_channel_stuffing_rate() -> f64 {
9290    0.01
9291}
9292
9293fn default_improper_cap_rate() -> f64 {
9294    0.012
9295}
9296
9297impl Default for TechnologyAnomalyRates {
9298    fn default() -> Self {
9299        Self {
9300            premature_revenue: default_premature_rev_rate(),
9301            side_letter_abuse: default_side_letter_rate(),
9302            channel_stuffing: default_channel_stuffing_rate(),
9303            improper_capitalization: default_improper_cap_rate(),
9304        }
9305    }
9306}
9307
9308/// Financial services industry configuration.
9309#[derive(Debug, Clone, Serialize, Deserialize)]
9310pub struct FinancialServicesConfig {
9311    /// Enable financial services-specific generation.
9312    #[serde(default)]
9313    pub enabled: bool,
9314
9315    /// Financial institution type.
9316    #[serde(default = "default_fi_type")]
9317    pub institution_type: String,
9318
9319    /// Regulatory framework.
9320    #[serde(default = "default_fi_regulatory")]
9321    pub regulatory_framework: String,
9322
9323    /// Financial services anomaly injection rates.
9324    #[serde(default)]
9325    pub anomaly_rates: FinancialServicesAnomalyRates,
9326}
9327
9328fn default_fi_type() -> String {
9329    "commercial_bank".to_string()
9330}
9331
9332fn default_fi_regulatory() -> String {
9333    "us_banking".to_string()
9334}
9335
9336impl Default for FinancialServicesConfig {
9337    fn default() -> Self {
9338        Self {
9339            enabled: false,
9340            institution_type: default_fi_type(),
9341            regulatory_framework: default_fi_regulatory(),
9342            anomaly_rates: FinancialServicesAnomalyRates::default(),
9343        }
9344    }
9345}
9346
9347/// Financial services anomaly injection rates.
9348#[derive(Debug, Clone, Serialize, Deserialize)]
9349pub struct FinancialServicesAnomalyRates {
9350    /// Loan fraud rate.
9351    #[serde(default = "default_loan_fraud_rate")]
9352    pub loan_fraud: f64,
9353
9354    /// Trading fraud rate.
9355    #[serde(default = "default_trading_fraud_rate")]
9356    pub trading_fraud: f64,
9357
9358    /// Insurance fraud rate.
9359    #[serde(default = "default_insurance_fraud_rate")]
9360    pub insurance_fraud: f64,
9361
9362    /// Account manipulation rate.
9363    #[serde(default = "default_account_manip_rate")]
9364    pub account_manipulation: f64,
9365}
9366
9367fn default_loan_fraud_rate() -> f64 {
9368    0.01
9369}
9370
9371fn default_trading_fraud_rate() -> f64 {
9372    0.008
9373}
9374
9375fn default_insurance_fraud_rate() -> f64 {
9376    0.012
9377}
9378
9379fn default_account_manip_rate() -> f64 {
9380    0.005
9381}
9382
9383impl Default for FinancialServicesAnomalyRates {
9384    fn default() -> Self {
9385        Self {
9386            loan_fraud: default_loan_fraud_rate(),
9387            trading_fraud: default_trading_fraud_rate(),
9388            insurance_fraud: default_insurance_fraud_rate(),
9389            account_manipulation: default_account_manip_rate(),
9390        }
9391    }
9392}
9393
9394/// Professional services industry configuration.
9395#[derive(Debug, Clone, Serialize, Deserialize)]
9396pub struct ProfessionalServicesConfig {
9397    /// Enable professional services-specific generation.
9398    #[serde(default)]
9399    pub enabled: bool,
9400
9401    /// Firm type.
9402    #[serde(default = "default_firm_type")]
9403    pub firm_type: String,
9404
9405    /// Billing model.
9406    #[serde(default = "default_billing_model")]
9407    pub billing_model: String,
9408
9409    /// Average hourly rate.
9410    #[serde(default = "default_hourly_rate")]
9411    pub avg_hourly_rate: f64,
9412
9413    /// Trust account settings (for law firms).
9414    #[serde(default)]
9415    pub trust_accounting: TrustAccountingConfig,
9416
9417    /// Professional services anomaly injection rates.
9418    #[serde(default)]
9419    pub anomaly_rates: ProfessionalServicesAnomalyRates,
9420}
9421
9422fn default_firm_type() -> String {
9423    "consulting".to_string()
9424}
9425
9426fn default_billing_model() -> String {
9427    "time_and_materials".to_string()
9428}
9429
9430fn default_hourly_rate() -> f64 {
9431    250.0
9432}
9433
9434impl Default for ProfessionalServicesConfig {
9435    fn default() -> Self {
9436        Self {
9437            enabled: false,
9438            firm_type: default_firm_type(),
9439            billing_model: default_billing_model(),
9440            avg_hourly_rate: default_hourly_rate(),
9441            trust_accounting: TrustAccountingConfig::default(),
9442            anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9443        }
9444    }
9445}
9446
9447/// Trust accounting configuration for law firms.
9448#[derive(Debug, Clone, Serialize, Deserialize)]
9449pub struct TrustAccountingConfig {
9450    /// Enable trust accounting.
9451    #[serde(default)]
9452    pub enabled: bool,
9453
9454    /// Require three-way reconciliation.
9455    #[serde(default = "default_true")]
9456    pub require_three_way_reconciliation: bool,
9457}
9458
9459impl Default for TrustAccountingConfig {
9460    fn default() -> Self {
9461        Self {
9462            enabled: false,
9463            require_three_way_reconciliation: true,
9464        }
9465    }
9466}
9467
9468/// Professional services anomaly injection rates.
9469#[derive(Debug, Clone, Serialize, Deserialize)]
9470pub struct ProfessionalServicesAnomalyRates {
9471    /// Time billing fraud rate.
9472    #[serde(default = "default_time_fraud_rate")]
9473    pub time_billing_fraud: f64,
9474
9475    /// Expense report fraud rate.
9476    #[serde(default = "default_expense_fraud_rate")]
9477    pub expense_fraud: f64,
9478
9479    /// Trust misappropriation rate.
9480    #[serde(default = "default_trust_misappropriation_rate")]
9481    pub trust_misappropriation: f64,
9482}
9483
9484fn default_time_fraud_rate() -> f64 {
9485    0.02
9486}
9487
9488fn default_expense_fraud_rate() -> f64 {
9489    0.015
9490}
9491
9492fn default_trust_misappropriation_rate() -> f64 {
9493    0.003
9494}
9495
9496impl Default for ProfessionalServicesAnomalyRates {
9497    fn default() -> Self {
9498        Self {
9499            time_billing_fraud: default_time_fraud_rate(),
9500            expense_fraud: default_expense_fraud_rate(),
9501            trust_misappropriation: default_trust_misappropriation_rate(),
9502        }
9503    }
9504}
9505
9506#[cfg(test)]
9507mod tests {
9508    use super::*;
9509    use crate::presets::demo_preset;
9510
9511    // ==========================================================================
9512    // Serialization/Deserialization Tests
9513    // ==========================================================================
9514
9515    #[test]
9516    fn test_config_yaml_roundtrip() {
9517        let config = demo_preset();
9518        let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
9519        let deserialized: GeneratorConfig =
9520            serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
9521
9522        assert_eq!(
9523            config.global.period_months,
9524            deserialized.global.period_months
9525        );
9526        assert_eq!(config.global.industry, deserialized.global.industry);
9527        assert_eq!(config.companies.len(), deserialized.companies.len());
9528        assert_eq!(config.companies[0].code, deserialized.companies[0].code);
9529    }
9530
9531    #[test]
9532    fn test_config_json_roundtrip() {
9533        // Create a config without infinity values (JSON can't serialize f64::INFINITY)
9534        let mut config = demo_preset();
9535        // Replace infinity with a large but finite value for JSON compatibility
9536        config.master_data.employees.approval_limits.executive = 1e12;
9537
9538        let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
9539        let deserialized: GeneratorConfig =
9540            serde_json::from_str(&json).expect("Failed to deserialize from JSON");
9541
9542        assert_eq!(
9543            config.global.period_months,
9544            deserialized.global.period_months
9545        );
9546        assert_eq!(config.global.industry, deserialized.global.industry);
9547        assert_eq!(config.companies.len(), deserialized.companies.len());
9548    }
9549
9550    #[test]
9551    fn test_transaction_volume_serialization() {
9552        // Test various transaction volumes serialize correctly
9553        let volumes = vec![
9554            (TransactionVolume::TenK, "ten_k"),
9555            (TransactionVolume::HundredK, "hundred_k"),
9556            (TransactionVolume::OneM, "one_m"),
9557            (TransactionVolume::TenM, "ten_m"),
9558            (TransactionVolume::HundredM, "hundred_m"),
9559        ];
9560
9561        for (volume, expected_key) in volumes {
9562            let json = serde_json::to_string(&volume).expect("Failed to serialize");
9563            assert!(
9564                json.contains(expected_key),
9565                "Expected {} in JSON: {}",
9566                expected_key,
9567                json
9568            );
9569        }
9570    }
9571
9572    #[test]
9573    fn test_transaction_volume_custom_serialization() {
9574        let volume = TransactionVolume::Custom(12345);
9575        let json = serde_json::to_string(&volume).expect("Failed to serialize");
9576        let deserialized: TransactionVolume =
9577            serde_json::from_str(&json).expect("Failed to deserialize");
9578        assert_eq!(deserialized.count(), 12345);
9579    }
9580
9581    #[test]
9582    fn test_output_mode_serialization() {
9583        let modes = vec![
9584            OutputMode::Streaming,
9585            OutputMode::FlatFile,
9586            OutputMode::Both,
9587        ];
9588
9589        for mode in modes {
9590            let json = serde_json::to_string(&mode).expect("Failed to serialize");
9591            let deserialized: OutputMode =
9592                serde_json::from_str(&json).expect("Failed to deserialize");
9593            assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
9594        }
9595    }
9596
9597    #[test]
9598    fn test_file_format_serialization() {
9599        let formats = vec![
9600            FileFormat::Csv,
9601            FileFormat::Parquet,
9602            FileFormat::Json,
9603            FileFormat::JsonLines,
9604        ];
9605
9606        for format in formats {
9607            let json = serde_json::to_string(&format).expect("Failed to serialize");
9608            let deserialized: FileFormat =
9609                serde_json::from_str(&json).expect("Failed to deserialize");
9610            assert!(format!("{:?}", format) == format!("{:?}", deserialized));
9611        }
9612    }
9613
9614    #[test]
9615    fn test_compression_algorithm_serialization() {
9616        let algos = vec![
9617            CompressionAlgorithm::Gzip,
9618            CompressionAlgorithm::Zstd,
9619            CompressionAlgorithm::Lz4,
9620            CompressionAlgorithm::Snappy,
9621        ];
9622
9623        for algo in algos {
9624            let json = serde_json::to_string(&algo).expect("Failed to serialize");
9625            let deserialized: CompressionAlgorithm =
9626                serde_json::from_str(&json).expect("Failed to deserialize");
9627            assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
9628        }
9629    }
9630
9631    #[test]
9632    fn test_transfer_pricing_method_serialization() {
9633        let methods = vec![
9634            TransferPricingMethod::CostPlus,
9635            TransferPricingMethod::ComparableUncontrolled,
9636            TransferPricingMethod::ResalePrice,
9637            TransferPricingMethod::TransactionalNetMargin,
9638            TransferPricingMethod::ProfitSplit,
9639        ];
9640
9641        for method in methods {
9642            let json = serde_json::to_string(&method).expect("Failed to serialize");
9643            let deserialized: TransferPricingMethod =
9644                serde_json::from_str(&json).expect("Failed to deserialize");
9645            assert!(format!("{:?}", method) == format!("{:?}", deserialized));
9646        }
9647    }
9648
9649    #[test]
9650    fn test_benford_exemption_serialization() {
9651        let exemptions = vec![
9652            BenfordExemption::Recurring,
9653            BenfordExemption::Payroll,
9654            BenfordExemption::FixedFees,
9655            BenfordExemption::RoundAmounts,
9656        ];
9657
9658        for exemption in exemptions {
9659            let json = serde_json::to_string(&exemption).expect("Failed to serialize");
9660            let deserialized: BenfordExemption =
9661                serde_json::from_str(&json).expect("Failed to deserialize");
9662            assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
9663        }
9664    }
9665
9666    // ==========================================================================
9667    // Default Value Tests
9668    // ==========================================================================
9669
9670    #[test]
9671    fn test_global_config_defaults() {
9672        let yaml = r#"
9673            industry: manufacturing
9674            start_date: "2024-01-01"
9675            period_months: 6
9676        "#;
9677        let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9678        assert_eq!(config.group_currency, "USD");
9679        assert!(config.parallel);
9680        assert_eq!(config.worker_threads, 0);
9681        assert_eq!(config.memory_limit_mb, 0);
9682    }
9683
9684    #[test]
9685    fn test_fraud_config_defaults() {
9686        let config = FraudConfig::default();
9687        assert!(!config.enabled);
9688        assert_eq!(config.fraud_rate, 0.005);
9689        assert!(!config.clustering_enabled);
9690    }
9691
9692    #[test]
9693    fn test_internal_controls_config_defaults() {
9694        let config = InternalControlsConfig::default();
9695        assert!(!config.enabled);
9696        assert_eq!(config.exception_rate, 0.02);
9697        assert_eq!(config.sod_violation_rate, 0.01);
9698        assert!(config.export_control_master_data);
9699        assert_eq!(config.sox_materiality_threshold, 10000.0);
9700        // COSO fields
9701        assert!(config.coso_enabled);
9702        assert!(!config.include_entity_level_controls);
9703        assert_eq!(config.target_maturity_level, "mixed");
9704    }
9705
9706    #[test]
9707    fn test_output_config_defaults() {
9708        let config = OutputConfig::default();
9709        assert!(matches!(config.mode, OutputMode::FlatFile));
9710        assert_eq!(config.formats, vec![FileFormat::Parquet]);
9711        assert!(config.compression.enabled);
9712        assert!(matches!(
9713            config.compression.algorithm,
9714            CompressionAlgorithm::Zstd
9715        ));
9716        assert!(config.include_acdoca);
9717        assert!(!config.include_bseg);
9718        assert!(config.partition_by_period);
9719        assert!(!config.partition_by_company);
9720    }
9721
9722    #[test]
9723    fn test_approval_config_defaults() {
9724        let config = ApprovalConfig::default();
9725        assert!(!config.enabled);
9726        assert_eq!(config.auto_approve_threshold, 1000.0);
9727        assert_eq!(config.rejection_rate, 0.02);
9728        assert_eq!(config.revision_rate, 0.05);
9729        assert_eq!(config.average_approval_delay_hours, 4.0);
9730        assert_eq!(config.thresholds.len(), 4);
9731    }
9732
9733    #[test]
9734    fn test_p2p_flow_config_defaults() {
9735        let config = P2PFlowConfig::default();
9736        assert!(config.enabled);
9737        assert_eq!(config.three_way_match_rate, 0.95);
9738        assert_eq!(config.partial_delivery_rate, 0.15);
9739        assert_eq!(config.average_po_to_gr_days, 14);
9740    }
9741
9742    #[test]
9743    fn test_o2c_flow_config_defaults() {
9744        let config = O2CFlowConfig::default();
9745        assert!(config.enabled);
9746        assert_eq!(config.credit_check_failure_rate, 0.02);
9747        assert_eq!(config.return_rate, 0.03);
9748        assert_eq!(config.bad_debt_rate, 0.01);
9749    }
9750
9751    #[test]
9752    fn test_balance_config_defaults() {
9753        let config = BalanceConfig::default();
9754        assert!(!config.generate_opening_balances);
9755        assert!(config.generate_trial_balances);
9756        assert_eq!(config.target_gross_margin, 0.35);
9757        assert!(config.validate_balance_equation);
9758        assert!(config.reconcile_subledgers);
9759    }
9760
9761    // ==========================================================================
9762    // Partial Config Deserialization Tests
9763    // ==========================================================================
9764
9765    #[test]
9766    fn test_partial_config_with_defaults() {
9767        // Minimal config that should use all defaults
9768        let yaml = r#"
9769            global:
9770              industry: manufacturing
9771              start_date: "2024-01-01"
9772              period_months: 3
9773            companies:
9774              - code: "TEST"
9775                name: "Test Company"
9776                currency: "USD"
9777                country: "US"
9778                annual_transaction_volume: ten_k
9779            chart_of_accounts:
9780              complexity: small
9781            output:
9782              output_directory: "./output"
9783        "#;
9784
9785        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9786        assert_eq!(config.global.period_months, 3);
9787        assert_eq!(config.companies.len(), 1);
9788        assert!(!config.fraud.enabled); // Default
9789        assert!(!config.internal_controls.enabled); // Default
9790    }
9791
9792    #[test]
9793    fn test_config_with_fraud_enabled() {
9794        let yaml = r#"
9795            global:
9796              industry: retail
9797              start_date: "2024-01-01"
9798              period_months: 12
9799            companies:
9800              - code: "RETAIL"
9801                name: "Retail Co"
9802                currency: "USD"
9803                country: "US"
9804                annual_transaction_volume: hundred_k
9805            chart_of_accounts:
9806              complexity: medium
9807            output:
9808              output_directory: "./output"
9809            fraud:
9810              enabled: true
9811              fraud_rate: 0.05
9812              clustering_enabled: true
9813        "#;
9814
9815        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9816        assert!(config.fraud.enabled);
9817        assert_eq!(config.fraud.fraud_rate, 0.05);
9818        assert!(config.fraud.clustering_enabled);
9819    }
9820
9821    #[test]
9822    fn test_config_with_multiple_companies() {
9823        let yaml = r#"
9824            global:
9825              industry: manufacturing
9826              start_date: "2024-01-01"
9827              period_months: 6
9828            companies:
9829              - code: "HQ"
9830                name: "Headquarters"
9831                currency: "USD"
9832                country: "US"
9833                annual_transaction_volume: hundred_k
9834                volume_weight: 1.0
9835              - code: "EU"
9836                name: "European Subsidiary"
9837                currency: "EUR"
9838                country: "DE"
9839                annual_transaction_volume: hundred_k
9840                volume_weight: 0.5
9841              - code: "APAC"
9842                name: "Asia Pacific"
9843                currency: "JPY"
9844                country: "JP"
9845                annual_transaction_volume: ten_k
9846                volume_weight: 0.3
9847            chart_of_accounts:
9848              complexity: large
9849            output:
9850              output_directory: "./output"
9851        "#;
9852
9853        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9854        assert_eq!(config.companies.len(), 3);
9855        assert_eq!(config.companies[0].code, "HQ");
9856        assert_eq!(config.companies[1].currency, "EUR");
9857        assert_eq!(config.companies[2].volume_weight, 0.3);
9858    }
9859
9860    #[test]
9861    fn test_intercompany_config() {
9862        let yaml = r#"
9863            enabled: true
9864            ic_transaction_rate: 0.20
9865            transfer_pricing_method: cost_plus
9866            markup_percent: 0.08
9867            generate_matched_pairs: true
9868            generate_eliminations: true
9869        "#;
9870
9871        let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9872        assert!(config.enabled);
9873        assert_eq!(config.ic_transaction_rate, 0.20);
9874        assert!(matches!(
9875            config.transfer_pricing_method,
9876            TransferPricingMethod::CostPlus
9877        ));
9878        assert_eq!(config.markup_percent, 0.08);
9879        assert!(config.generate_eliminations);
9880    }
9881
9882    // ==========================================================================
9883    // Company Config Tests
9884    // ==========================================================================
9885
9886    #[test]
9887    fn test_company_config_defaults() {
9888        let yaml = r#"
9889            code: "TEST"
9890            name: "Test Company"
9891            currency: "USD"
9892            country: "US"
9893            annual_transaction_volume: ten_k
9894        "#;
9895
9896        let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9897        assert_eq!(config.fiscal_year_variant, "K4"); // Default
9898        assert_eq!(config.volume_weight, 1.0); // Default
9899    }
9900
9901    // ==========================================================================
9902    // Chart of Accounts Config Tests
9903    // ==========================================================================
9904
9905    #[test]
9906    fn test_coa_config_defaults() {
9907        let yaml = r#"
9908            complexity: medium
9909        "#;
9910
9911        let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
9912        assert!(config.industry_specific); // Default true
9913        assert!(config.custom_accounts.is_none());
9914        assert_eq!(config.min_hierarchy_depth, 2); // Default
9915        assert_eq!(config.max_hierarchy_depth, 5); // Default
9916    }
9917
9918    // ==========================================================================
9919    // Accounting Standards Config Tests
9920    // ==========================================================================
9921
9922    #[test]
9923    fn test_accounting_standards_config_defaults() {
9924        let config = AccountingStandardsConfig::default();
9925        assert!(!config.enabled);
9926        assert!(matches!(
9927            config.framework,
9928            AccountingFrameworkConfig::UsGaap
9929        ));
9930        assert!(!config.revenue_recognition.enabled);
9931        assert!(!config.leases.enabled);
9932        assert!(!config.fair_value.enabled);
9933        assert!(!config.impairment.enabled);
9934        assert!(!config.generate_differences);
9935    }
9936
9937    #[test]
9938    fn test_accounting_standards_config_yaml() {
9939        let yaml = r#"
9940            enabled: true
9941            framework: ifrs
9942            revenue_recognition:
9943              enabled: true
9944              generate_contracts: true
9945              avg_obligations_per_contract: 2.5
9946              variable_consideration_rate: 0.20
9947              over_time_recognition_rate: 0.35
9948              contract_count: 150
9949            leases:
9950              enabled: true
9951              lease_count: 75
9952              finance_lease_percent: 0.25
9953              avg_lease_term_months: 48
9954            generate_differences: true
9955        "#;
9956
9957        let config: AccountingStandardsConfig =
9958            serde_yaml::from_str(yaml).expect("Failed to parse");
9959        assert!(config.enabled);
9960        assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
9961        assert!(config.revenue_recognition.enabled);
9962        assert_eq!(config.revenue_recognition.contract_count, 150);
9963        assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
9964        assert!(config.leases.enabled);
9965        assert_eq!(config.leases.lease_count, 75);
9966        assert_eq!(config.leases.finance_lease_percent, 0.25);
9967        assert!(config.generate_differences);
9968    }
9969
9970    #[test]
9971    fn test_accounting_framework_serialization() {
9972        let frameworks = [
9973            AccountingFrameworkConfig::UsGaap,
9974            AccountingFrameworkConfig::Ifrs,
9975            AccountingFrameworkConfig::DualReporting,
9976        ];
9977
9978        for framework in frameworks {
9979            let json = serde_json::to_string(&framework).expect("Failed to serialize");
9980            let deserialized: AccountingFrameworkConfig =
9981                serde_json::from_str(&json).expect("Failed to deserialize");
9982            assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
9983        }
9984    }
9985
9986    #[test]
9987    fn test_revenue_recognition_config_defaults() {
9988        let config = RevenueRecognitionConfig::default();
9989        assert!(!config.enabled);
9990        assert!(config.generate_contracts);
9991        assert_eq!(config.avg_obligations_per_contract, 2.0);
9992        assert_eq!(config.variable_consideration_rate, 0.15);
9993        assert_eq!(config.over_time_recognition_rate, 0.30);
9994        assert_eq!(config.contract_count, 100);
9995    }
9996
9997    #[test]
9998    fn test_lease_accounting_config_defaults() {
9999        let config = LeaseAccountingConfig::default();
10000        assert!(!config.enabled);
10001        assert_eq!(config.lease_count, 50);
10002        assert_eq!(config.finance_lease_percent, 0.30);
10003        assert_eq!(config.avg_lease_term_months, 60);
10004        assert!(config.generate_amortization);
10005        assert_eq!(config.real_estate_percent, 0.40);
10006    }
10007
10008    #[test]
10009    fn test_fair_value_config_defaults() {
10010        let config = FairValueConfig::default();
10011        assert!(!config.enabled);
10012        assert_eq!(config.measurement_count, 25);
10013        assert_eq!(config.level1_percent, 0.40);
10014        assert_eq!(config.level2_percent, 0.35);
10015        assert_eq!(config.level3_percent, 0.25);
10016        assert!(!config.include_sensitivity_analysis);
10017    }
10018
10019    #[test]
10020    fn test_impairment_config_defaults() {
10021        let config = ImpairmentConfig::default();
10022        assert!(!config.enabled);
10023        assert_eq!(config.test_count, 15);
10024        assert_eq!(config.impairment_rate, 0.10);
10025        assert!(config.generate_projections);
10026        assert!(!config.include_goodwill);
10027    }
10028
10029    // ==========================================================================
10030    // Audit Standards Config Tests
10031    // ==========================================================================
10032
10033    #[test]
10034    fn test_audit_standards_config_defaults() {
10035        let config = AuditStandardsConfig::default();
10036        assert!(!config.enabled);
10037        assert!(!config.isa_compliance.enabled);
10038        assert!(!config.analytical_procedures.enabled);
10039        assert!(!config.confirmations.enabled);
10040        assert!(!config.opinion.enabled);
10041        assert!(!config.generate_audit_trail);
10042        assert!(!config.sox.enabled);
10043        assert!(!config.pcaob.enabled);
10044    }
10045
10046    #[test]
10047    fn test_audit_standards_config_yaml() {
10048        let yaml = r#"
10049            enabled: true
10050            isa_compliance:
10051              enabled: true
10052              compliance_level: comprehensive
10053              generate_isa_mappings: true
10054              include_pcaob: true
10055              framework: dual
10056            analytical_procedures:
10057              enabled: true
10058              procedures_per_account: 5
10059              variance_probability: 0.25
10060            confirmations:
10061              enabled: true
10062              confirmation_count: 75
10063              positive_response_rate: 0.90
10064              exception_rate: 0.08
10065            opinion:
10066              enabled: true
10067              generate_kam: true
10068              average_kam_count: 4
10069            sox:
10070              enabled: true
10071              generate_302_certifications: true
10072              generate_404_assessments: true
10073              material_weakness_rate: 0.03
10074            pcaob:
10075              enabled: true
10076              is_pcaob_audit: true
10077              include_icfr_opinion: true
10078            generate_audit_trail: true
10079        "#;
10080
10081        let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10082        assert!(config.enabled);
10083        assert!(config.isa_compliance.enabled);
10084        assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
10085        assert!(config.isa_compliance.include_pcaob);
10086        assert_eq!(config.isa_compliance.framework, "dual");
10087        assert!(config.analytical_procedures.enabled);
10088        assert_eq!(config.analytical_procedures.procedures_per_account, 5);
10089        assert!(config.confirmations.enabled);
10090        assert_eq!(config.confirmations.confirmation_count, 75);
10091        assert!(config.opinion.enabled);
10092        assert_eq!(config.opinion.average_kam_count, 4);
10093        assert!(config.sox.enabled);
10094        assert!(config.sox.generate_302_certifications);
10095        assert_eq!(config.sox.material_weakness_rate, 0.03);
10096        assert!(config.pcaob.enabled);
10097        assert!(config.pcaob.is_pcaob_audit);
10098        assert!(config.pcaob.include_icfr_opinion);
10099        assert!(config.generate_audit_trail);
10100    }
10101
10102    #[test]
10103    fn test_isa_compliance_config_defaults() {
10104        let config = IsaComplianceConfig::default();
10105        assert!(!config.enabled);
10106        assert_eq!(config.compliance_level, "standard");
10107        assert!(config.generate_isa_mappings);
10108        assert!(config.generate_coverage_summary);
10109        assert!(!config.include_pcaob);
10110        assert_eq!(config.framework, "isa");
10111    }
10112
10113    #[test]
10114    fn test_sox_compliance_config_defaults() {
10115        let config = SoxComplianceConfig::default();
10116        assert!(!config.enabled);
10117        assert!(config.generate_302_certifications);
10118        assert!(config.generate_404_assessments);
10119        assert_eq!(config.materiality_threshold, 10000.0);
10120        assert_eq!(config.material_weakness_rate, 0.02);
10121        assert_eq!(config.significant_deficiency_rate, 0.08);
10122    }
10123
10124    #[test]
10125    fn test_pcaob_config_defaults() {
10126        let config = PcaobConfig::default();
10127        assert!(!config.enabled);
10128        assert!(!config.is_pcaob_audit);
10129        assert!(config.generate_cam);
10130        assert!(!config.include_icfr_opinion);
10131        assert!(!config.generate_standard_mappings);
10132    }
10133
10134    #[test]
10135    fn test_config_with_standards_enabled() {
10136        let yaml = r#"
10137            global:
10138              industry: financial_services
10139              start_date: "2024-01-01"
10140              period_months: 12
10141            companies:
10142              - code: "BANK"
10143                name: "Test Bank"
10144                currency: "USD"
10145                country: "US"
10146                annual_transaction_volume: hundred_k
10147            chart_of_accounts:
10148              complexity: large
10149            output:
10150              output_directory: "./output"
10151            accounting_standards:
10152              enabled: true
10153              framework: us_gaap
10154              revenue_recognition:
10155                enabled: true
10156              leases:
10157                enabled: true
10158            audit_standards:
10159              enabled: true
10160              isa_compliance:
10161                enabled: true
10162              sox:
10163                enabled: true
10164        "#;
10165
10166        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10167        assert!(config.accounting_standards.enabled);
10168        assert!(matches!(
10169            config.accounting_standards.framework,
10170            AccountingFrameworkConfig::UsGaap
10171        ));
10172        assert!(config.accounting_standards.revenue_recognition.enabled);
10173        assert!(config.accounting_standards.leases.enabled);
10174        assert!(config.audit_standards.enabled);
10175        assert!(config.audit_standards.isa_compliance.enabled);
10176        assert!(config.audit_standards.sox.enabled);
10177    }
10178
10179    // ==========================================================================
10180    // Industry-Specific Config Tests
10181    // ==========================================================================
10182
10183    #[test]
10184    fn test_industry_specific_config_defaults() {
10185        let config = IndustrySpecificConfig::default();
10186        assert!(!config.enabled);
10187        assert!(!config.manufacturing.enabled);
10188        assert!(!config.retail.enabled);
10189        assert!(!config.healthcare.enabled);
10190        assert!(!config.technology.enabled);
10191        assert!(!config.financial_services.enabled);
10192        assert!(!config.professional_services.enabled);
10193    }
10194
10195    #[test]
10196    fn test_manufacturing_config_defaults() {
10197        let config = ManufacturingConfig::default();
10198        assert!(!config.enabled);
10199        assert_eq!(config.bom_depth, 4);
10200        assert!(!config.just_in_time);
10201        assert_eq!(config.supplier_tiers, 2);
10202        assert_eq!(config.target_yield_rate, 0.97);
10203        assert_eq!(config.scrap_alert_threshold, 0.03);
10204    }
10205
10206    #[test]
10207    fn test_retail_config_defaults() {
10208        let config = RetailConfig::default();
10209        assert!(!config.enabled);
10210        assert_eq!(config.avg_daily_transactions, 500);
10211        assert!(config.loss_prevention);
10212        assert_eq!(config.shrinkage_rate, 0.015);
10213    }
10214
10215    #[test]
10216    fn test_healthcare_config_defaults() {
10217        let config = HealthcareConfig::default();
10218        assert!(!config.enabled);
10219        assert_eq!(config.facility_type, "hospital");
10220        assert_eq!(config.avg_daily_encounters, 150);
10221        assert!(config.compliance.hipaa);
10222        assert!(config.compliance.stark_law);
10223        assert!(config.coding_systems.icd10);
10224        assert!(config.coding_systems.cpt);
10225    }
10226
10227    #[test]
10228    fn test_technology_config_defaults() {
10229        let config = TechnologyConfig::default();
10230        assert!(!config.enabled);
10231        assert_eq!(config.revenue_model, "saas");
10232        assert_eq!(config.subscription_revenue_pct, 0.60);
10233        assert!(config.rd_capitalization.enabled);
10234    }
10235
10236    #[test]
10237    fn test_config_with_industry_specific() {
10238        let yaml = r#"
10239            global:
10240              industry: healthcare
10241              start_date: "2024-01-01"
10242              period_months: 12
10243            companies:
10244              - code: "HOSP"
10245                name: "Test Hospital"
10246                currency: "USD"
10247                country: "US"
10248                annual_transaction_volume: hundred_k
10249            chart_of_accounts:
10250              complexity: medium
10251            output:
10252              output_directory: "./output"
10253            industry_specific:
10254              enabled: true
10255              healthcare:
10256                enabled: true
10257                facility_type: hospital
10258                payer_mix:
10259                  medicare: 0.45
10260                  medicaid: 0.15
10261                  commercial: 0.35
10262                  self_pay: 0.05
10263                coding_systems:
10264                  icd10: true
10265                  cpt: true
10266                  drg: true
10267                compliance:
10268                  hipaa: true
10269                  stark_law: true
10270                anomaly_rates:
10271                  upcoding: 0.03
10272                  unbundling: 0.02
10273        "#;
10274
10275        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10276        assert!(config.industry_specific.enabled);
10277        assert!(config.industry_specific.healthcare.enabled);
10278        assert_eq!(
10279            config.industry_specific.healthcare.facility_type,
10280            "hospital"
10281        );
10282        assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
10283        assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
10284        assert!(config.industry_specific.healthcare.coding_systems.icd10);
10285        assert!(config.industry_specific.healthcare.compliance.hipaa);
10286        assert_eq!(
10287            config.industry_specific.healthcare.anomaly_rates.upcoding,
10288            0.03
10289        );
10290    }
10291
10292    #[test]
10293    fn test_config_with_manufacturing_specific() {
10294        let yaml = r#"
10295            global:
10296              industry: manufacturing
10297              start_date: "2024-01-01"
10298              period_months: 12
10299            companies:
10300              - code: "MFG"
10301                name: "Test Manufacturing"
10302                currency: "USD"
10303                country: "US"
10304                annual_transaction_volume: hundred_k
10305            chart_of_accounts:
10306              complexity: medium
10307            output:
10308              output_directory: "./output"
10309            industry_specific:
10310              enabled: true
10311              manufacturing:
10312                enabled: true
10313                bom_depth: 5
10314                just_in_time: true
10315                supplier_tiers: 3
10316                target_yield_rate: 0.98
10317                anomaly_rates:
10318                  yield_manipulation: 0.02
10319                  phantom_production: 0.01
10320        "#;
10321
10322        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
10323        assert!(config.industry_specific.enabled);
10324        assert!(config.industry_specific.manufacturing.enabled);
10325        assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
10326        assert!(config.industry_specific.manufacturing.just_in_time);
10327        assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
10328        assert_eq!(
10329            config.industry_specific.manufacturing.target_yield_rate,
10330            0.98
10331        );
10332        assert_eq!(
10333            config
10334                .industry_specific
10335                .manufacturing
10336                .anomaly_rates
10337                .yield_manipulation,
10338            0.02
10339        );
10340    }
10341}