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