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