Skip to main content

datasynth_config/
schema.rs

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