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