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