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