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
3845impl Default for AuditGenerationConfig {
3846    fn default() -> Self {
3847        Self {
3848            enabled: false,
3849            generate_workpapers: true,
3850            engagement_types: AuditEngagementTypesConfig::default(),
3851            workpapers: WorkpaperConfig::default(),
3852            team: AuditTeamConfig::default(),
3853            review: ReviewWorkflowConfig::default(),
3854        }
3855    }
3856}
3857
3858/// Engagement type distribution configuration.
3859#[derive(Debug, Clone, Serialize, Deserialize)]
3860pub struct AuditEngagementTypesConfig {
3861    /// Financial statement audit probability
3862    #[serde(default = "default_financial_audit_prob")]
3863    pub financial_statement: f64,
3864    /// SOX/ICFR audit probability
3865    #[serde(default = "default_sox_audit_prob")]
3866    pub sox_icfr: f64,
3867    /// Integrated audit probability
3868    #[serde(default = "default_integrated_audit_prob")]
3869    pub integrated: f64,
3870    /// Review engagement probability
3871    #[serde(default = "default_review_prob")]
3872    pub review: f64,
3873    /// Agreed-upon procedures probability
3874    #[serde(default = "default_aup_prob")]
3875    pub agreed_upon_procedures: f64,
3876}
3877
3878fn default_financial_audit_prob() -> f64 {
3879    0.40
3880}
3881fn default_sox_audit_prob() -> f64 {
3882    0.20
3883}
3884fn default_integrated_audit_prob() -> f64 {
3885    0.25
3886}
3887fn default_review_prob() -> f64 {
3888    0.10
3889}
3890fn default_aup_prob() -> f64 {
3891    0.05
3892}
3893
3894impl Default for AuditEngagementTypesConfig {
3895    fn default() -> Self {
3896        Self {
3897            financial_statement: default_financial_audit_prob(),
3898            sox_icfr: default_sox_audit_prob(),
3899            integrated: default_integrated_audit_prob(),
3900            review: default_review_prob(),
3901            agreed_upon_procedures: default_aup_prob(),
3902        }
3903    }
3904}
3905
3906/// Workpaper generation configuration.
3907#[derive(Debug, Clone, Serialize, Deserialize)]
3908pub struct WorkpaperConfig {
3909    /// Average workpapers per engagement phase
3910    #[serde(default = "default_workpapers_per_phase")]
3911    pub average_per_phase: usize,
3912
3913    /// Include ISA compliance references
3914    #[serde(default = "default_true")]
3915    pub include_isa_references: bool,
3916
3917    /// Generate sample details
3918    #[serde(default = "default_true")]
3919    pub include_sample_details: bool,
3920
3921    /// Include cross-references between workpapers
3922    #[serde(default = "default_true")]
3923    pub include_cross_references: bool,
3924
3925    /// Sampling configuration
3926    #[serde(default)]
3927    pub sampling: SamplingConfig,
3928}
3929
3930fn default_workpapers_per_phase() -> usize {
3931    5
3932}
3933
3934impl Default for WorkpaperConfig {
3935    fn default() -> Self {
3936        Self {
3937            average_per_phase: default_workpapers_per_phase(),
3938            include_isa_references: true,
3939            include_sample_details: true,
3940            include_cross_references: true,
3941            sampling: SamplingConfig::default(),
3942        }
3943    }
3944}
3945
3946/// Sampling method configuration.
3947#[derive(Debug, Clone, Serialize, Deserialize)]
3948pub struct SamplingConfig {
3949    /// Statistical sampling rate (0.0-1.0)
3950    #[serde(default = "default_statistical_rate")]
3951    pub statistical_rate: f64,
3952    /// Judgmental sampling rate (0.0-1.0)
3953    #[serde(default = "default_judgmental_rate")]
3954    pub judgmental_rate: f64,
3955    /// Haphazard sampling rate (0.0-1.0)
3956    #[serde(default = "default_haphazard_rate")]
3957    pub haphazard_rate: f64,
3958    /// 100% examination rate (0.0-1.0)
3959    #[serde(default = "default_complete_examination_rate")]
3960    pub complete_examination_rate: f64,
3961}
3962
3963fn default_statistical_rate() -> f64 {
3964    0.40
3965}
3966fn default_judgmental_rate() -> f64 {
3967    0.30
3968}
3969fn default_haphazard_rate() -> f64 {
3970    0.20
3971}
3972fn default_complete_examination_rate() -> f64 {
3973    0.10
3974}
3975
3976impl Default for SamplingConfig {
3977    fn default() -> Self {
3978        Self {
3979            statistical_rate: default_statistical_rate(),
3980            judgmental_rate: default_judgmental_rate(),
3981            haphazard_rate: default_haphazard_rate(),
3982            complete_examination_rate: default_complete_examination_rate(),
3983        }
3984    }
3985}
3986
3987/// Audit team configuration.
3988#[derive(Debug, Clone, Serialize, Deserialize)]
3989pub struct AuditTeamConfig {
3990    /// Minimum team size
3991    #[serde(default = "default_min_team_size")]
3992    pub min_team_size: usize,
3993    /// Maximum team size
3994    #[serde(default = "default_max_team_size")]
3995    pub max_team_size: usize,
3996    /// Probability of having a specialist on the team
3997    #[serde(default = "default_specialist_probability")]
3998    pub specialist_probability: f64,
3999}
4000
4001fn default_min_team_size() -> usize {
4002    3
4003}
4004fn default_max_team_size() -> usize {
4005    8
4006}
4007fn default_specialist_probability() -> f64 {
4008    0.30
4009}
4010
4011impl Default for AuditTeamConfig {
4012    fn default() -> Self {
4013        Self {
4014            min_team_size: default_min_team_size(),
4015            max_team_size: default_max_team_size(),
4016            specialist_probability: default_specialist_probability(),
4017        }
4018    }
4019}
4020
4021/// Review workflow configuration.
4022#[derive(Debug, Clone, Serialize, Deserialize)]
4023pub struct ReviewWorkflowConfig {
4024    /// Average days between preparer completion and first review
4025    #[serde(default = "default_review_delay_days")]
4026    pub average_review_delay_days: u32,
4027    /// Probability of review notes requiring rework
4028    #[serde(default = "default_rework_probability_review")]
4029    pub rework_probability: f64,
4030    /// Require partner sign-off for all workpapers
4031    #[serde(default = "default_true")]
4032    pub require_partner_signoff: bool,
4033}
4034
4035fn default_review_delay_days() -> u32 {
4036    2
4037}
4038fn default_rework_probability_review() -> f64 {
4039    0.15
4040}
4041
4042impl Default for ReviewWorkflowConfig {
4043    fn default() -> Self {
4044        Self {
4045            average_review_delay_days: default_review_delay_days(),
4046            rework_probability: default_rework_probability_review(),
4047            require_partner_signoff: true,
4048        }
4049    }
4050}
4051
4052// =============================================================================
4053// Data Quality Configuration
4054// =============================================================================
4055
4056/// Data quality variation settings for realistic flakiness injection.
4057#[derive(Debug, Clone, Serialize, Deserialize)]
4058pub struct DataQualitySchemaConfig {
4059    /// Enable data quality variations
4060    #[serde(default)]
4061    pub enabled: bool,
4062    /// Preset to use (overrides individual settings if set)
4063    #[serde(default)]
4064    pub preset: DataQualityPreset,
4065    /// Missing value injection settings
4066    #[serde(default)]
4067    pub missing_values: MissingValuesSchemaConfig,
4068    /// Typo injection settings
4069    #[serde(default)]
4070    pub typos: TypoSchemaConfig,
4071    /// Format variation settings
4072    #[serde(default)]
4073    pub format_variations: FormatVariationSchemaConfig,
4074    /// Duplicate injection settings
4075    #[serde(default)]
4076    pub duplicates: DuplicateSchemaConfig,
4077    /// Encoding issue settings
4078    #[serde(default)]
4079    pub encoding_issues: EncodingIssueSchemaConfig,
4080    /// Generate quality issue labels for ML training
4081    #[serde(default)]
4082    pub generate_labels: bool,
4083    /// Per-sink quality profiles (different settings for CSV vs JSON etc.)
4084    #[serde(default)]
4085    pub sink_profiles: SinkQualityProfiles,
4086}
4087
4088impl Default for DataQualitySchemaConfig {
4089    fn default() -> Self {
4090        Self {
4091            enabled: false,
4092            preset: DataQualityPreset::None,
4093            missing_values: MissingValuesSchemaConfig::default(),
4094            typos: TypoSchemaConfig::default(),
4095            format_variations: FormatVariationSchemaConfig::default(),
4096            duplicates: DuplicateSchemaConfig::default(),
4097            encoding_issues: EncodingIssueSchemaConfig::default(),
4098            generate_labels: true,
4099            sink_profiles: SinkQualityProfiles::default(),
4100        }
4101    }
4102}
4103
4104impl DataQualitySchemaConfig {
4105    /// Creates a config for a specific preset profile.
4106    pub fn with_preset(preset: DataQualityPreset) -> Self {
4107        let mut config = Self {
4108            preset,
4109            ..Default::default()
4110        };
4111        config.apply_preset();
4112        config
4113    }
4114
4115    /// Applies the preset settings to the individual configuration fields.
4116    /// Call this after deserializing if preset is not Custom or None.
4117    pub fn apply_preset(&mut self) {
4118        if !self.preset.overrides_settings() {
4119            return;
4120        }
4121
4122        self.enabled = true;
4123
4124        // Missing values
4125        self.missing_values.enabled = self.preset.missing_rate() > 0.0;
4126        self.missing_values.rate = self.preset.missing_rate();
4127
4128        // Typos
4129        self.typos.enabled = self.preset.typo_rate() > 0.0;
4130        self.typos.char_error_rate = self.preset.typo_rate();
4131
4132        // Duplicates
4133        self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
4134        self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4135        self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
4136        self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
4137
4138        // Format variations
4139        self.format_variations.enabled = self.preset.format_variations_enabled();
4140
4141        // Encoding issues
4142        self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
4143        self.encoding_issues.rate = self.preset.encoding_issue_rate();
4144
4145        // OCR errors for typos in legacy preset
4146        if self.preset.ocr_errors_enabled() {
4147            self.typos.type_weights.ocr_errors = 0.3;
4148        }
4149    }
4150
4151    /// Returns the effective missing value rate (considering preset).
4152    pub fn effective_missing_rate(&self) -> f64 {
4153        if self.preset.overrides_settings() {
4154            self.preset.missing_rate()
4155        } else {
4156            self.missing_values.rate
4157        }
4158    }
4159
4160    /// Returns the effective typo rate (considering preset).
4161    pub fn effective_typo_rate(&self) -> f64 {
4162        if self.preset.overrides_settings() {
4163            self.preset.typo_rate()
4164        } else {
4165            self.typos.char_error_rate
4166        }
4167    }
4168
4169    /// Returns the effective duplicate rate (considering preset).
4170    pub fn effective_duplicate_rate(&self) -> f64 {
4171        if self.preset.overrides_settings() {
4172            self.preset.duplicate_rate()
4173        } else {
4174            self.duplicates.exact_duplicate_ratio
4175                + self.duplicates.near_duplicate_ratio
4176                + self.duplicates.fuzzy_duplicate_ratio
4177        }
4178    }
4179
4180    /// Creates a clean profile config.
4181    pub fn clean() -> Self {
4182        Self::with_preset(DataQualityPreset::Clean)
4183    }
4184
4185    /// Creates a noisy profile config.
4186    pub fn noisy() -> Self {
4187        Self::with_preset(DataQualityPreset::Noisy)
4188    }
4189
4190    /// Creates a legacy profile config.
4191    pub fn legacy() -> Self {
4192        Self::with_preset(DataQualityPreset::Legacy)
4193    }
4194}
4195
4196/// Preset configurations for common data quality scenarios.
4197#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4198#[serde(rename_all = "snake_case")]
4199pub enum DataQualityPreset {
4200    /// No data quality variations (clean data)
4201    #[default]
4202    None,
4203    /// Minimal variations (very clean data with rare issues)
4204    Minimal,
4205    /// Normal variations (realistic enterprise data quality)
4206    Normal,
4207    /// High variations (messy data for stress testing)
4208    High,
4209    /// Custom (use individual settings)
4210    Custom,
4211
4212    // ========================================
4213    // ML-Oriented Profiles (Phase 2.1)
4214    // ========================================
4215    /// Clean profile for ML training - minimal data quality issues
4216    /// Missing: 0.1%, Typos: 0.05%, Duplicates: 0%, Format: None
4217    Clean,
4218    /// Noisy profile simulating typical production data issues
4219    /// Missing: 5%, Typos: 2%, Duplicates: 1%, Format: Medium
4220    Noisy,
4221    /// Legacy profile simulating migrated/OCR'd historical data
4222    /// Missing: 10%, Typos: 5%, Duplicates: 3%, Format: Heavy + OCR
4223    Legacy,
4224}
4225
4226impl DataQualityPreset {
4227    /// Returns the missing value rate for this preset.
4228    pub fn missing_rate(&self) -> f64 {
4229        match self {
4230            DataQualityPreset::None => 0.0,
4231            DataQualityPreset::Minimal => 0.005,
4232            DataQualityPreset::Normal => 0.02,
4233            DataQualityPreset::High => 0.08,
4234            DataQualityPreset::Custom => 0.01, // Use config value
4235            DataQualityPreset::Clean => 0.001,
4236            DataQualityPreset::Noisy => 0.05,
4237            DataQualityPreset::Legacy => 0.10,
4238        }
4239    }
4240
4241    /// Returns the typo rate for this preset.
4242    pub fn typo_rate(&self) -> f64 {
4243        match self {
4244            DataQualityPreset::None => 0.0,
4245            DataQualityPreset::Minimal => 0.0005,
4246            DataQualityPreset::Normal => 0.002,
4247            DataQualityPreset::High => 0.01,
4248            DataQualityPreset::Custom => 0.001, // Use config value
4249            DataQualityPreset::Clean => 0.0005,
4250            DataQualityPreset::Noisy => 0.02,
4251            DataQualityPreset::Legacy => 0.05,
4252        }
4253    }
4254
4255    /// Returns the duplicate rate for this preset.
4256    pub fn duplicate_rate(&self) -> f64 {
4257        match self {
4258            DataQualityPreset::None => 0.0,
4259            DataQualityPreset::Minimal => 0.001,
4260            DataQualityPreset::Normal => 0.005,
4261            DataQualityPreset::High => 0.02,
4262            DataQualityPreset::Custom => 0.0, // Use config value
4263            DataQualityPreset::Clean => 0.0,
4264            DataQualityPreset::Noisy => 0.01,
4265            DataQualityPreset::Legacy => 0.03,
4266        }
4267    }
4268
4269    /// Returns whether format variations are enabled for this preset.
4270    pub fn format_variations_enabled(&self) -> bool {
4271        match self {
4272            DataQualityPreset::None | DataQualityPreset::Clean => false,
4273            DataQualityPreset::Minimal => true,
4274            DataQualityPreset::Normal => true,
4275            DataQualityPreset::High => true,
4276            DataQualityPreset::Custom => true,
4277            DataQualityPreset::Noisy => true,
4278            DataQualityPreset::Legacy => true,
4279        }
4280    }
4281
4282    /// Returns whether OCR-style errors are enabled for this preset.
4283    pub fn ocr_errors_enabled(&self) -> bool {
4284        matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
4285    }
4286
4287    /// Returns whether encoding issues are enabled for this preset.
4288    pub fn encoding_issues_enabled(&self) -> bool {
4289        matches!(
4290            self,
4291            DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
4292        )
4293    }
4294
4295    /// Returns the encoding issue rate for this preset.
4296    pub fn encoding_issue_rate(&self) -> f64 {
4297        match self {
4298            DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
4299            DataQualityPreset::Normal => 0.002,
4300            DataQualityPreset::High => 0.01,
4301            DataQualityPreset::Custom => 0.0,
4302            DataQualityPreset::Noisy => 0.005,
4303            DataQualityPreset::Legacy => 0.02,
4304        }
4305    }
4306
4307    /// Returns true if this preset overrides individual settings.
4308    pub fn overrides_settings(&self) -> bool {
4309        !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
4310    }
4311
4312    /// Returns a human-readable description of this preset.
4313    pub fn description(&self) -> &'static str {
4314        match self {
4315            DataQualityPreset::None => "No data quality issues (pristine data)",
4316            DataQualityPreset::Minimal => "Very rare data quality issues",
4317            DataQualityPreset::Normal => "Realistic enterprise data quality",
4318            DataQualityPreset::High => "Messy data for stress testing",
4319            DataQualityPreset::Custom => "Custom settings from configuration",
4320            DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
4321            DataQualityPreset::Noisy => "Typical production data with moderate issues",
4322            DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
4323        }
4324    }
4325}
4326
4327/// Missing value injection configuration.
4328#[derive(Debug, Clone, Serialize, Deserialize)]
4329pub struct MissingValuesSchemaConfig {
4330    /// Enable missing value injection
4331    #[serde(default)]
4332    pub enabled: bool,
4333    /// Global missing rate (0.0 to 1.0)
4334    #[serde(default = "default_missing_rate")]
4335    pub rate: f64,
4336    /// Missing value strategy
4337    #[serde(default)]
4338    pub strategy: MissingValueStrategy,
4339    /// Field-specific rates (field name -> rate)
4340    #[serde(default)]
4341    pub field_rates: std::collections::HashMap<String, f64>,
4342    /// Fields that should never have missing values
4343    #[serde(default)]
4344    pub protected_fields: Vec<String>,
4345}
4346
4347fn default_missing_rate() -> f64 {
4348    0.01
4349}
4350
4351impl Default for MissingValuesSchemaConfig {
4352    fn default() -> Self {
4353        Self {
4354            enabled: false,
4355            rate: default_missing_rate(),
4356            strategy: MissingValueStrategy::Mcar,
4357            field_rates: std::collections::HashMap::new(),
4358            protected_fields: vec![
4359                "document_id".to_string(),
4360                "company_code".to_string(),
4361                "posting_date".to_string(),
4362            ],
4363        }
4364    }
4365}
4366
4367/// Missing value strategy types.
4368#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4369#[serde(rename_all = "snake_case")]
4370pub enum MissingValueStrategy {
4371    /// Missing Completely At Random - equal probability for all values
4372    #[default]
4373    Mcar,
4374    /// Missing At Random - depends on other observed values
4375    Mar,
4376    /// Missing Not At Random - depends on the value itself
4377    Mnar,
4378    /// Systematic - entire field groups missing together
4379    Systematic,
4380}
4381
4382/// Typo injection configuration.
4383#[derive(Debug, Clone, Serialize, Deserialize)]
4384pub struct TypoSchemaConfig {
4385    /// Enable typo injection
4386    #[serde(default)]
4387    pub enabled: bool,
4388    /// Character error rate (per character, not per field)
4389    #[serde(default = "default_typo_rate")]
4390    pub char_error_rate: f64,
4391    /// Typo type weights
4392    #[serde(default)]
4393    pub type_weights: TypoTypeWeights,
4394    /// Fields that should never have typos
4395    #[serde(default)]
4396    pub protected_fields: Vec<String>,
4397}
4398
4399fn default_typo_rate() -> f64 {
4400    0.001
4401}
4402
4403impl Default for TypoSchemaConfig {
4404    fn default() -> Self {
4405        Self {
4406            enabled: false,
4407            char_error_rate: default_typo_rate(),
4408            type_weights: TypoTypeWeights::default(),
4409            protected_fields: vec![
4410                "document_id".to_string(),
4411                "gl_account".to_string(),
4412                "company_code".to_string(),
4413            ],
4414        }
4415    }
4416}
4417
4418/// Weights for different typo types.
4419#[derive(Debug, Clone, Serialize, Deserialize)]
4420pub struct TypoTypeWeights {
4421    /// Keyboard-adjacent substitution (e.g., 'a' -> 's')
4422    #[serde(default = "default_substitution_weight")]
4423    pub substitution: f64,
4424    /// Adjacent character transposition (e.g., 'ab' -> 'ba')
4425    #[serde(default = "default_transposition_weight")]
4426    pub transposition: f64,
4427    /// Character insertion
4428    #[serde(default = "default_insertion_weight")]
4429    pub insertion: f64,
4430    /// Character deletion
4431    #[serde(default = "default_deletion_weight")]
4432    pub deletion: f64,
4433    /// OCR-style errors (e.g., '0' -> 'O')
4434    #[serde(default = "default_ocr_weight")]
4435    pub ocr_errors: f64,
4436    /// Homophone substitution (e.g., 'their' -> 'there')
4437    #[serde(default = "default_homophone_weight")]
4438    pub homophones: f64,
4439}
4440
4441fn default_substitution_weight() -> f64 {
4442    0.35
4443}
4444fn default_transposition_weight() -> f64 {
4445    0.25
4446}
4447fn default_insertion_weight() -> f64 {
4448    0.10
4449}
4450fn default_deletion_weight() -> f64 {
4451    0.15
4452}
4453fn default_ocr_weight() -> f64 {
4454    0.10
4455}
4456fn default_homophone_weight() -> f64 {
4457    0.05
4458}
4459
4460impl Default for TypoTypeWeights {
4461    fn default() -> Self {
4462        Self {
4463            substitution: default_substitution_weight(),
4464            transposition: default_transposition_weight(),
4465            insertion: default_insertion_weight(),
4466            deletion: default_deletion_weight(),
4467            ocr_errors: default_ocr_weight(),
4468            homophones: default_homophone_weight(),
4469        }
4470    }
4471}
4472
4473/// Format variation configuration.
4474#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4475pub struct FormatVariationSchemaConfig {
4476    /// Enable format variations
4477    #[serde(default)]
4478    pub enabled: bool,
4479    /// Date format variation settings
4480    #[serde(default)]
4481    pub dates: DateFormatVariationConfig,
4482    /// Amount format variation settings
4483    #[serde(default)]
4484    pub amounts: AmountFormatVariationConfig,
4485    /// Identifier format variation settings
4486    #[serde(default)]
4487    pub identifiers: IdentifierFormatVariationConfig,
4488}
4489
4490/// Date format variation configuration.
4491#[derive(Debug, Clone, Serialize, Deserialize)]
4492pub struct DateFormatVariationConfig {
4493    /// Enable date format variations
4494    #[serde(default)]
4495    pub enabled: bool,
4496    /// Overall variation rate
4497    #[serde(default = "default_date_variation_rate")]
4498    pub rate: f64,
4499    /// Include ISO format (2024-01-15)
4500    #[serde(default = "default_true")]
4501    pub iso_format: bool,
4502    /// Include US format (01/15/2024)
4503    #[serde(default)]
4504    pub us_format: bool,
4505    /// Include EU format (15.01.2024)
4506    #[serde(default)]
4507    pub eu_format: bool,
4508    /// Include long format (January 15, 2024)
4509    #[serde(default)]
4510    pub long_format: bool,
4511}
4512
4513fn default_date_variation_rate() -> f64 {
4514    0.05
4515}
4516
4517impl Default for DateFormatVariationConfig {
4518    fn default() -> Self {
4519        Self {
4520            enabled: false,
4521            rate: default_date_variation_rate(),
4522            iso_format: true,
4523            us_format: false,
4524            eu_format: false,
4525            long_format: false,
4526        }
4527    }
4528}
4529
4530/// Amount format variation configuration.
4531#[derive(Debug, Clone, Serialize, Deserialize)]
4532pub struct AmountFormatVariationConfig {
4533    /// Enable amount format variations
4534    #[serde(default)]
4535    pub enabled: bool,
4536    /// Overall variation rate
4537    #[serde(default = "default_amount_variation_rate")]
4538    pub rate: f64,
4539    /// Include US comma format (1,234.56)
4540    #[serde(default)]
4541    pub us_comma_format: bool,
4542    /// Include EU format (1.234,56)
4543    #[serde(default)]
4544    pub eu_format: bool,
4545    /// Include currency prefix ($1,234.56)
4546    #[serde(default)]
4547    pub currency_prefix: bool,
4548    /// Include accounting format with parentheses for negatives
4549    #[serde(default)]
4550    pub accounting_format: bool,
4551}
4552
4553fn default_amount_variation_rate() -> f64 {
4554    0.02
4555}
4556
4557impl Default for AmountFormatVariationConfig {
4558    fn default() -> Self {
4559        Self {
4560            enabled: false,
4561            rate: default_amount_variation_rate(),
4562            us_comma_format: false,
4563            eu_format: false,
4564            currency_prefix: false,
4565            accounting_format: false,
4566        }
4567    }
4568}
4569
4570/// Identifier format variation configuration.
4571#[derive(Debug, Clone, Serialize, Deserialize)]
4572pub struct IdentifierFormatVariationConfig {
4573    /// Enable identifier format variations
4574    #[serde(default)]
4575    pub enabled: bool,
4576    /// Overall variation rate
4577    #[serde(default = "default_identifier_variation_rate")]
4578    pub rate: f64,
4579    /// Case variations (uppercase, lowercase, mixed)
4580    #[serde(default)]
4581    pub case_variations: bool,
4582    /// Padding variations (leading zeros)
4583    #[serde(default)]
4584    pub padding_variations: bool,
4585    /// Separator variations (dash vs underscore)
4586    #[serde(default)]
4587    pub separator_variations: bool,
4588}
4589
4590fn default_identifier_variation_rate() -> f64 {
4591    0.02
4592}
4593
4594impl Default for IdentifierFormatVariationConfig {
4595    fn default() -> Self {
4596        Self {
4597            enabled: false,
4598            rate: default_identifier_variation_rate(),
4599            case_variations: false,
4600            padding_variations: false,
4601            separator_variations: false,
4602        }
4603    }
4604}
4605
4606/// Duplicate injection configuration.
4607#[derive(Debug, Clone, Serialize, Deserialize)]
4608pub struct DuplicateSchemaConfig {
4609    /// Enable duplicate injection
4610    #[serde(default)]
4611    pub enabled: bool,
4612    /// Overall duplicate rate
4613    #[serde(default = "default_duplicate_rate")]
4614    pub rate: f64,
4615    /// Exact duplicate proportion (out of duplicates)
4616    #[serde(default = "default_exact_duplicate_ratio")]
4617    pub exact_duplicate_ratio: f64,
4618    /// Near duplicate proportion (slight variations)
4619    #[serde(default = "default_near_duplicate_ratio")]
4620    pub near_duplicate_ratio: f64,
4621    /// Fuzzy duplicate proportion (typos in key fields)
4622    #[serde(default = "default_fuzzy_duplicate_ratio")]
4623    pub fuzzy_duplicate_ratio: f64,
4624    /// Maximum date offset for near/fuzzy duplicates (days)
4625    #[serde(default = "default_max_date_offset")]
4626    pub max_date_offset_days: u32,
4627    /// Maximum amount variance for near duplicates (fraction)
4628    #[serde(default = "default_max_amount_variance")]
4629    pub max_amount_variance: f64,
4630}
4631
4632fn default_duplicate_rate() -> f64 {
4633    0.005
4634}
4635fn default_exact_duplicate_ratio() -> f64 {
4636    0.4
4637}
4638fn default_near_duplicate_ratio() -> f64 {
4639    0.35
4640}
4641fn default_fuzzy_duplicate_ratio() -> f64 {
4642    0.25
4643}
4644fn default_max_date_offset() -> u32 {
4645    3
4646}
4647fn default_max_amount_variance() -> f64 {
4648    0.01
4649}
4650
4651impl Default for DuplicateSchemaConfig {
4652    fn default() -> Self {
4653        Self {
4654            enabled: false,
4655            rate: default_duplicate_rate(),
4656            exact_duplicate_ratio: default_exact_duplicate_ratio(),
4657            near_duplicate_ratio: default_near_duplicate_ratio(),
4658            fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4659            max_date_offset_days: default_max_date_offset(),
4660            max_amount_variance: default_max_amount_variance(),
4661        }
4662    }
4663}
4664
4665/// Encoding issue configuration.
4666#[derive(Debug, Clone, Serialize, Deserialize)]
4667pub struct EncodingIssueSchemaConfig {
4668    /// Enable encoding issue injection
4669    #[serde(default)]
4670    pub enabled: bool,
4671    /// Overall encoding issue rate
4672    #[serde(default = "default_encoding_rate")]
4673    pub rate: f64,
4674    /// Include mojibake (UTF-8/Latin-1 confusion)
4675    #[serde(default)]
4676    pub mojibake: bool,
4677    /// Include HTML entity corruption
4678    #[serde(default)]
4679    pub html_entities: bool,
4680    /// Include BOM issues
4681    #[serde(default)]
4682    pub bom_issues: bool,
4683}
4684
4685fn default_encoding_rate() -> f64 {
4686    0.001
4687}
4688
4689impl Default for EncodingIssueSchemaConfig {
4690    fn default() -> Self {
4691        Self {
4692            enabled: false,
4693            rate: default_encoding_rate(),
4694            mojibake: false,
4695            html_entities: false,
4696            bom_issues: false,
4697        }
4698    }
4699}
4700
4701/// Per-sink quality profiles for different output formats.
4702#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4703pub struct SinkQualityProfiles {
4704    /// CSV-specific quality settings
4705    #[serde(default)]
4706    pub csv: Option<SinkQualityOverride>,
4707    /// JSON-specific quality settings
4708    #[serde(default)]
4709    pub json: Option<SinkQualityOverride>,
4710    /// Parquet-specific quality settings
4711    #[serde(default)]
4712    pub parquet: Option<SinkQualityOverride>,
4713}
4714
4715/// Quality setting overrides for a specific sink type.
4716#[derive(Debug, Clone, Serialize, Deserialize)]
4717pub struct SinkQualityOverride {
4718    /// Override enabled state
4719    pub enabled: Option<bool>,
4720    /// Override missing value rate
4721    pub missing_rate: Option<f64>,
4722    /// Override typo rate
4723    pub typo_rate: Option<f64>,
4724    /// Override format variation rate
4725    pub format_variation_rate: Option<f64>,
4726    /// Override duplicate rate
4727    pub duplicate_rate: Option<f64>,
4728}
4729
4730// =============================================================================
4731// Accounting Standards Configuration
4732// =============================================================================
4733
4734/// Accounting standards framework configuration for generating standards-compliant data.
4735///
4736/// Supports US GAAP, IFRS, and French GAAP (PCG) frameworks with specific standards:
4737/// - ASC 606/IFRS 15/PCG: Revenue Recognition
4738/// - ASC 842/IFRS 16/PCG: Leases
4739/// - ASC 820/IFRS 13/PCG: Fair Value Measurement
4740/// - ASC 360/IAS 36/PCG: Impairment
4741#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4742pub struct AccountingStandardsConfig {
4743    /// Enable accounting standards generation
4744    #[serde(default)]
4745    pub enabled: bool,
4746
4747    /// Accounting framework to use.
4748    /// When `None`, the country pack's `accounting.framework` is used as fallback;
4749    /// if that is also absent the orchestrator defaults to US GAAP.
4750    #[serde(default, skip_serializing_if = "Option::is_none")]
4751    pub framework: Option<AccountingFrameworkConfig>,
4752
4753    /// Revenue recognition configuration (ASC 606/IFRS 15)
4754    #[serde(default)]
4755    pub revenue_recognition: RevenueRecognitionConfig,
4756
4757    /// Lease accounting configuration (ASC 842/IFRS 16)
4758    #[serde(default)]
4759    pub leases: LeaseAccountingConfig,
4760
4761    /// Fair value measurement configuration (ASC 820/IFRS 13)
4762    #[serde(default)]
4763    pub fair_value: FairValueConfig,
4764
4765    /// Impairment testing configuration (ASC 360/IAS 36)
4766    #[serde(default)]
4767    pub impairment: ImpairmentConfig,
4768
4769    /// Business combination configuration (IFRS 3 / ASC 805)
4770    #[serde(default)]
4771    pub business_combinations: BusinessCombinationsConfig,
4772
4773    /// Expected Credit Loss configuration (IFRS 9 / ASC 326)
4774    #[serde(default)]
4775    pub expected_credit_loss: EclConfig,
4776
4777    /// Generate framework differences for dual reporting
4778    #[serde(default)]
4779    pub generate_differences: bool,
4780}
4781
4782/// Accounting framework selection.
4783#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4784#[serde(rename_all = "snake_case")]
4785pub enum AccountingFrameworkConfig {
4786    /// US Generally Accepted Accounting Principles
4787    #[default]
4788    UsGaap,
4789    /// International Financial Reporting Standards
4790    Ifrs,
4791    /// Generate data for both frameworks with reconciliation
4792    DualReporting,
4793    /// French GAAP (Plan Comptable Général – PCG)
4794    FrenchGaap,
4795    /// German GAAP (Handelsgesetzbuch – HGB, §238-263)
4796    GermanGaap,
4797}
4798
4799/// Revenue recognition configuration (ASC 606/IFRS 15).
4800#[derive(Debug, Clone, Serialize, Deserialize)]
4801pub struct RevenueRecognitionConfig {
4802    /// Enable revenue recognition generation
4803    #[serde(default)]
4804    pub enabled: bool,
4805
4806    /// Generate customer contracts
4807    #[serde(default = "default_true")]
4808    pub generate_contracts: bool,
4809
4810    /// Average number of performance obligations per contract
4811    #[serde(default = "default_avg_obligations")]
4812    pub avg_obligations_per_contract: f64,
4813
4814    /// Rate of contracts with variable consideration
4815    #[serde(default = "default_variable_consideration_rate")]
4816    pub variable_consideration_rate: f64,
4817
4818    /// Rate of over-time revenue recognition (vs point-in-time)
4819    #[serde(default = "default_over_time_rate")]
4820    pub over_time_recognition_rate: f64,
4821
4822    /// Number of contracts to generate
4823    #[serde(default = "default_contract_count")]
4824    pub contract_count: usize,
4825}
4826
4827fn default_avg_obligations() -> f64 {
4828    2.0
4829}
4830
4831fn default_variable_consideration_rate() -> f64 {
4832    0.15
4833}
4834
4835fn default_over_time_rate() -> f64 {
4836    0.30
4837}
4838
4839fn default_contract_count() -> usize {
4840    100
4841}
4842
4843impl Default for RevenueRecognitionConfig {
4844    fn default() -> Self {
4845        Self {
4846            enabled: false,
4847            generate_contracts: true,
4848            avg_obligations_per_contract: default_avg_obligations(),
4849            variable_consideration_rate: default_variable_consideration_rate(),
4850            over_time_recognition_rate: default_over_time_rate(),
4851            contract_count: default_contract_count(),
4852        }
4853    }
4854}
4855
4856/// Lease accounting configuration (ASC 842/IFRS 16).
4857#[derive(Debug, Clone, Serialize, Deserialize)]
4858pub struct LeaseAccountingConfig {
4859    /// Enable lease accounting generation
4860    #[serde(default)]
4861    pub enabled: bool,
4862
4863    /// Number of leases to generate
4864    #[serde(default = "default_lease_count")]
4865    pub lease_count: usize,
4866
4867    /// Percentage of finance leases (vs operating)
4868    #[serde(default = "default_finance_lease_pct")]
4869    pub finance_lease_percent: f64,
4870
4871    /// Average lease term in months
4872    #[serde(default = "default_avg_lease_term")]
4873    pub avg_lease_term_months: u32,
4874
4875    /// Generate amortization schedules
4876    #[serde(default = "default_true")]
4877    pub generate_amortization: bool,
4878
4879    /// Real estate lease percentage
4880    #[serde(default = "default_real_estate_pct")]
4881    pub real_estate_percent: f64,
4882}
4883
4884fn default_lease_count() -> usize {
4885    50
4886}
4887
4888fn default_finance_lease_pct() -> f64 {
4889    0.30
4890}
4891
4892fn default_avg_lease_term() -> u32 {
4893    60
4894}
4895
4896fn default_real_estate_pct() -> f64 {
4897    0.40
4898}
4899
4900impl Default for LeaseAccountingConfig {
4901    fn default() -> Self {
4902        Self {
4903            enabled: false,
4904            lease_count: default_lease_count(),
4905            finance_lease_percent: default_finance_lease_pct(),
4906            avg_lease_term_months: default_avg_lease_term(),
4907            generate_amortization: true,
4908            real_estate_percent: default_real_estate_pct(),
4909        }
4910    }
4911}
4912
4913/// Fair value measurement configuration (ASC 820/IFRS 13).
4914#[derive(Debug, Clone, Serialize, Deserialize)]
4915pub struct FairValueConfig {
4916    /// Enable fair value measurement generation
4917    #[serde(default)]
4918    pub enabled: bool,
4919
4920    /// Number of fair value measurements to generate
4921    #[serde(default = "default_fv_count")]
4922    pub measurement_count: usize,
4923
4924    /// Level 1 (quoted prices) percentage
4925    #[serde(default = "default_level1_pct")]
4926    pub level1_percent: f64,
4927
4928    /// Level 2 (observable inputs) percentage
4929    #[serde(default = "default_level2_pct")]
4930    pub level2_percent: f64,
4931
4932    /// Level 3 (unobservable inputs) percentage
4933    #[serde(default = "default_level3_pct")]
4934    pub level3_percent: f64,
4935
4936    /// Include sensitivity analysis for Level 3
4937    #[serde(default)]
4938    pub include_sensitivity_analysis: bool,
4939}
4940
4941fn default_fv_count() -> usize {
4942    25
4943}
4944
4945fn default_level1_pct() -> f64 {
4946    0.40
4947}
4948
4949fn default_level2_pct() -> f64 {
4950    0.35
4951}
4952
4953fn default_level3_pct() -> f64 {
4954    0.25
4955}
4956
4957impl Default for FairValueConfig {
4958    fn default() -> Self {
4959        Self {
4960            enabled: false,
4961            measurement_count: default_fv_count(),
4962            level1_percent: default_level1_pct(),
4963            level2_percent: default_level2_pct(),
4964            level3_percent: default_level3_pct(),
4965            include_sensitivity_analysis: false,
4966        }
4967    }
4968}
4969
4970/// Impairment testing configuration (ASC 360/IAS 36).
4971#[derive(Debug, Clone, Serialize, Deserialize)]
4972pub struct ImpairmentConfig {
4973    /// Enable impairment testing generation
4974    #[serde(default)]
4975    pub enabled: bool,
4976
4977    /// Number of impairment tests to generate
4978    #[serde(default = "default_impairment_count")]
4979    pub test_count: usize,
4980
4981    /// Rate of tests resulting in impairment
4982    #[serde(default = "default_impairment_rate")]
4983    pub impairment_rate: f64,
4984
4985    /// Generate cash flow projections
4986    #[serde(default = "default_true")]
4987    pub generate_projections: bool,
4988
4989    /// Include goodwill impairment tests
4990    #[serde(default)]
4991    pub include_goodwill: bool,
4992}
4993
4994fn default_impairment_count() -> usize {
4995    15
4996}
4997
4998fn default_impairment_rate() -> f64 {
4999    0.10
5000}
5001
5002impl Default for ImpairmentConfig {
5003    fn default() -> Self {
5004        Self {
5005            enabled: false,
5006            test_count: default_impairment_count(),
5007            impairment_rate: default_impairment_rate(),
5008            generate_projections: true,
5009            include_goodwill: false,
5010        }
5011    }
5012}
5013
5014// =============================================================================
5015// Business Combinations Configuration (IFRS 3 / ASC 805)
5016// =============================================================================
5017
5018/// Configuration for generating business combination (acquisition) data.
5019#[derive(Debug, Clone, Serialize, Deserialize)]
5020pub struct BusinessCombinationsConfig {
5021    /// Enable business combination generation
5022    #[serde(default)]
5023    pub enabled: bool,
5024
5025    /// Number of acquisitions to generate per company (1-5)
5026    #[serde(default = "default_bc_acquisition_count")]
5027    pub acquisition_count: usize,
5028}
5029
5030fn default_bc_acquisition_count() -> usize {
5031    2
5032}
5033
5034impl Default for BusinessCombinationsConfig {
5035    fn default() -> Self {
5036        Self {
5037            enabled: false,
5038            acquisition_count: default_bc_acquisition_count(),
5039        }
5040    }
5041}
5042
5043// =============================================================================
5044// ECL Configuration (IFRS 9 / ASC 326)
5045// =============================================================================
5046
5047/// Configuration for Expected Credit Loss generation.
5048#[derive(Debug, Clone, Serialize, Deserialize)]
5049pub struct EclConfig {
5050    /// Enable ECL generation.
5051    #[serde(default)]
5052    pub enabled: bool,
5053
5054    /// Weight for base economic scenario (0–1).
5055    #[serde(default = "default_ecl_base_weight")]
5056    pub base_scenario_weight: f64,
5057
5058    /// Multiplier for base scenario (typically 1.0).
5059    #[serde(default = "default_ecl_base_multiplier")]
5060    pub base_scenario_multiplier: f64,
5061
5062    /// Weight for optimistic economic scenario (0–1).
5063    #[serde(default = "default_ecl_optimistic_weight")]
5064    pub optimistic_scenario_weight: f64,
5065
5066    /// Multiplier for optimistic scenario (< 1.0 means lower losses).
5067    #[serde(default = "default_ecl_optimistic_multiplier")]
5068    pub optimistic_scenario_multiplier: f64,
5069
5070    /// Weight for pessimistic economic scenario (0–1).
5071    #[serde(default = "default_ecl_pessimistic_weight")]
5072    pub pessimistic_scenario_weight: f64,
5073
5074    /// Multiplier for pessimistic scenario (> 1.0 means higher losses).
5075    #[serde(default = "default_ecl_pessimistic_multiplier")]
5076    pub pessimistic_scenario_multiplier: f64,
5077}
5078
5079fn default_ecl_base_weight() -> f64 {
5080    0.50
5081}
5082fn default_ecl_base_multiplier() -> f64 {
5083    1.0
5084}
5085fn default_ecl_optimistic_weight() -> f64 {
5086    0.30
5087}
5088fn default_ecl_optimistic_multiplier() -> f64 {
5089    0.8
5090}
5091fn default_ecl_pessimistic_weight() -> f64 {
5092    0.20
5093}
5094fn default_ecl_pessimistic_multiplier() -> f64 {
5095    1.4
5096}
5097
5098impl Default for EclConfig {
5099    fn default() -> Self {
5100        Self {
5101            enabled: false,
5102            base_scenario_weight: default_ecl_base_weight(),
5103            base_scenario_multiplier: default_ecl_base_multiplier(),
5104            optimistic_scenario_weight: default_ecl_optimistic_weight(),
5105            optimistic_scenario_multiplier: default_ecl_optimistic_multiplier(),
5106            pessimistic_scenario_weight: default_ecl_pessimistic_weight(),
5107            pessimistic_scenario_multiplier: default_ecl_pessimistic_multiplier(),
5108        }
5109    }
5110}
5111
5112// =============================================================================
5113// Audit Standards Configuration
5114// =============================================================================
5115
5116/// Audit standards framework configuration for generating standards-compliant audit data.
5117///
5118/// Supports ISA (International Standards on Auditing) and PCAOB standards:
5119/// - ISA 200-720: Complete coverage of audit standards
5120/// - ISA 520: Analytical Procedures
5121/// - ISA 505: External Confirmations
5122/// - ISA 700/705/706/701: Audit Reports
5123/// - PCAOB AS 2201: ICFR Auditing
5124#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5125pub struct AuditStandardsConfig {
5126    /// Enable audit standards generation
5127    #[serde(default)]
5128    pub enabled: bool,
5129
5130    /// ISA compliance configuration
5131    #[serde(default)]
5132    pub isa_compliance: IsaComplianceConfig,
5133
5134    /// Analytical procedures configuration (ISA 520)
5135    #[serde(default)]
5136    pub analytical_procedures: AnalyticalProceduresConfig,
5137
5138    /// External confirmations configuration (ISA 505)
5139    #[serde(default)]
5140    pub confirmations: ConfirmationsConfig,
5141
5142    /// Audit opinion configuration (ISA 700/705/706/701)
5143    #[serde(default)]
5144    pub opinion: AuditOpinionConfig,
5145
5146    /// Generate complete audit trail with traceability
5147    #[serde(default)]
5148    pub generate_audit_trail: bool,
5149
5150    /// SOX 302/404 compliance configuration
5151    #[serde(default)]
5152    pub sox: SoxComplianceConfig,
5153
5154    /// PCAOB-specific configuration
5155    #[serde(default)]
5156    pub pcaob: PcaobConfig,
5157}
5158
5159/// ISA compliance level configuration.
5160#[derive(Debug, Clone, Serialize, Deserialize)]
5161pub struct IsaComplianceConfig {
5162    /// Enable ISA compliance tracking
5163    #[serde(default)]
5164    pub enabled: bool,
5165
5166    /// Compliance level: "basic", "standard", "comprehensive"
5167    #[serde(default = "default_compliance_level")]
5168    pub compliance_level: String,
5169
5170    /// Generate ISA requirement mappings
5171    #[serde(default = "default_true")]
5172    pub generate_isa_mappings: bool,
5173
5174    /// Generate ISA coverage summary
5175    #[serde(default = "default_true")]
5176    pub generate_coverage_summary: bool,
5177
5178    /// Include PCAOB standard mappings (for dual framework)
5179    #[serde(default)]
5180    pub include_pcaob: bool,
5181
5182    /// Framework to use: "isa", "pcaob", "dual"
5183    #[serde(default = "default_audit_framework")]
5184    pub framework: String,
5185}
5186
5187fn default_compliance_level() -> String {
5188    "standard".to_string()
5189}
5190
5191fn default_audit_framework() -> String {
5192    "isa".to_string()
5193}
5194
5195impl Default for IsaComplianceConfig {
5196    fn default() -> Self {
5197        Self {
5198            enabled: false,
5199            compliance_level: default_compliance_level(),
5200            generate_isa_mappings: true,
5201            generate_coverage_summary: true,
5202            include_pcaob: false,
5203            framework: default_audit_framework(),
5204        }
5205    }
5206}
5207
5208/// Analytical procedures configuration (ISA 520).
5209#[derive(Debug, Clone, Serialize, Deserialize)]
5210pub struct AnalyticalProceduresConfig {
5211    /// Enable analytical procedures generation
5212    #[serde(default)]
5213    pub enabled: bool,
5214
5215    /// Number of procedures per account/area
5216    #[serde(default = "default_procedures_per_account")]
5217    pub procedures_per_account: usize,
5218
5219    /// Probability of variance exceeding threshold
5220    #[serde(default = "default_variance_probability")]
5221    pub variance_probability: f64,
5222
5223    /// Include variance investigations
5224    #[serde(default = "default_true")]
5225    pub generate_investigations: bool,
5226
5227    /// Include financial ratio analysis
5228    #[serde(default = "default_true")]
5229    pub include_ratio_analysis: bool,
5230}
5231
5232fn default_procedures_per_account() -> usize {
5233    3
5234}
5235
5236fn default_variance_probability() -> f64 {
5237    0.20
5238}
5239
5240impl Default for AnalyticalProceduresConfig {
5241    fn default() -> Self {
5242        Self {
5243            enabled: false,
5244            procedures_per_account: default_procedures_per_account(),
5245            variance_probability: default_variance_probability(),
5246            generate_investigations: true,
5247            include_ratio_analysis: true,
5248        }
5249    }
5250}
5251
5252/// External confirmations configuration (ISA 505).
5253#[derive(Debug, Clone, Serialize, Deserialize)]
5254pub struct ConfirmationsConfig {
5255    /// Enable confirmation generation
5256    #[serde(default)]
5257    pub enabled: bool,
5258
5259    /// Number of confirmations to generate
5260    #[serde(default = "default_confirmation_count")]
5261    pub confirmation_count: usize,
5262
5263    /// Positive response rate
5264    #[serde(default = "default_positive_response_rate")]
5265    pub positive_response_rate: f64,
5266
5267    /// Exception rate (responses with differences)
5268    #[serde(default = "default_exception_rate_confirm")]
5269    pub exception_rate: f64,
5270
5271    /// Non-response rate
5272    #[serde(default = "default_non_response_rate")]
5273    pub non_response_rate: f64,
5274
5275    /// Generate alternative procedures for non-responses
5276    #[serde(default = "default_true")]
5277    pub generate_alternative_procedures: bool,
5278}
5279
5280fn default_confirmation_count() -> usize {
5281    50
5282}
5283
5284fn default_positive_response_rate() -> f64 {
5285    0.85
5286}
5287
5288fn default_exception_rate_confirm() -> f64 {
5289    0.10
5290}
5291
5292fn default_non_response_rate() -> f64 {
5293    0.05
5294}
5295
5296impl Default for ConfirmationsConfig {
5297    fn default() -> Self {
5298        Self {
5299            enabled: false,
5300            confirmation_count: default_confirmation_count(),
5301            positive_response_rate: default_positive_response_rate(),
5302            exception_rate: default_exception_rate_confirm(),
5303            non_response_rate: default_non_response_rate(),
5304            generate_alternative_procedures: true,
5305        }
5306    }
5307}
5308
5309/// Audit opinion configuration (ISA 700/705/706/701).
5310#[derive(Debug, Clone, Serialize, Deserialize)]
5311pub struct AuditOpinionConfig {
5312    /// Enable audit opinion generation
5313    #[serde(default)]
5314    pub enabled: bool,
5315
5316    /// Generate Key Audit Matters (KAM) / Critical Audit Matters (CAM)
5317    #[serde(default = "default_true")]
5318    pub generate_kam: bool,
5319
5320    /// Average number of KAMs/CAMs per opinion
5321    #[serde(default = "default_kam_count")]
5322    pub average_kam_count: usize,
5323
5324    /// Rate of modified opinions
5325    #[serde(default = "default_modified_opinion_rate")]
5326    pub modified_opinion_rate: f64,
5327
5328    /// Include emphasis of matter paragraphs
5329    #[serde(default)]
5330    pub include_emphasis_of_matter: bool,
5331
5332    /// Include going concern conclusions
5333    #[serde(default = "default_true")]
5334    pub include_going_concern: bool,
5335}
5336
5337fn default_kam_count() -> usize {
5338    3
5339}
5340
5341fn default_modified_opinion_rate() -> f64 {
5342    0.05
5343}
5344
5345impl Default for AuditOpinionConfig {
5346    fn default() -> Self {
5347        Self {
5348            enabled: false,
5349            generate_kam: true,
5350            average_kam_count: default_kam_count(),
5351            modified_opinion_rate: default_modified_opinion_rate(),
5352            include_emphasis_of_matter: false,
5353            include_going_concern: true,
5354        }
5355    }
5356}
5357
5358/// SOX compliance configuration (Sections 302/404).
5359#[derive(Debug, Clone, Serialize, Deserialize)]
5360pub struct SoxComplianceConfig {
5361    /// Enable SOX compliance generation
5362    #[serde(default)]
5363    pub enabled: bool,
5364
5365    /// Generate Section 302 CEO/CFO certifications
5366    #[serde(default = "default_true")]
5367    pub generate_302_certifications: bool,
5368
5369    /// Generate Section 404 ICFR assessments
5370    #[serde(default = "default_true")]
5371    pub generate_404_assessments: bool,
5372
5373    /// Materiality threshold for SOX testing
5374    #[serde(default = "default_sox_materiality_threshold")]
5375    pub materiality_threshold: f64,
5376
5377    /// Rate of material weaknesses
5378    #[serde(default = "default_material_weakness_rate")]
5379    pub material_weakness_rate: f64,
5380
5381    /// Rate of significant deficiencies
5382    #[serde(default = "default_significant_deficiency_rate")]
5383    pub significant_deficiency_rate: f64,
5384}
5385
5386fn default_material_weakness_rate() -> f64 {
5387    0.02
5388}
5389
5390fn default_significant_deficiency_rate() -> f64 {
5391    0.08
5392}
5393
5394impl Default for SoxComplianceConfig {
5395    fn default() -> Self {
5396        Self {
5397            enabled: false,
5398            generate_302_certifications: true,
5399            generate_404_assessments: true,
5400            materiality_threshold: default_sox_materiality_threshold(),
5401            material_weakness_rate: default_material_weakness_rate(),
5402            significant_deficiency_rate: default_significant_deficiency_rate(),
5403        }
5404    }
5405}
5406
5407/// PCAOB-specific configuration.
5408#[derive(Debug, Clone, Serialize, Deserialize)]
5409pub struct PcaobConfig {
5410    /// Enable PCAOB-specific elements
5411    #[serde(default)]
5412    pub enabled: bool,
5413
5414    /// Treat as PCAOB audit (vs ISA-only)
5415    #[serde(default)]
5416    pub is_pcaob_audit: bool,
5417
5418    /// Generate Critical Audit Matters (CAM)
5419    #[serde(default = "default_true")]
5420    pub generate_cam: bool,
5421
5422    /// Include ICFR opinion (for integrated audits)
5423    #[serde(default)]
5424    pub include_icfr_opinion: bool,
5425
5426    /// Generate PCAOB-ISA standard mappings
5427    #[serde(default)]
5428    pub generate_standard_mappings: bool,
5429}
5430
5431impl Default for PcaobConfig {
5432    fn default() -> Self {
5433        Self {
5434            enabled: false,
5435            is_pcaob_audit: false,
5436            generate_cam: true,
5437            include_icfr_opinion: false,
5438            generate_standard_mappings: false,
5439        }
5440    }
5441}
5442
5443// =============================================================================
5444// Advanced Distribution Configuration
5445// =============================================================================
5446
5447/// Advanced distribution configuration for realistic data generation.
5448///
5449/// This section enables sophisticated distribution models including:
5450/// - Mixture models (multi-modal distributions)
5451/// - Cross-field correlations
5452/// - Conditional distributions
5453/// - Regime changes and economic cycles
5454/// - Statistical validation
5455#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5456pub struct AdvancedDistributionConfig {
5457    /// Enable advanced distribution features.
5458    #[serde(default)]
5459    pub enabled: bool,
5460
5461    /// Mixture model configuration for amounts.
5462    #[serde(default)]
5463    pub amounts: MixtureDistributionSchemaConfig,
5464
5465    /// Cross-field correlation configuration.
5466    #[serde(default)]
5467    pub correlations: CorrelationSchemaConfig,
5468
5469    /// Conditional distribution configurations.
5470    #[serde(default)]
5471    pub conditional: Vec<ConditionalDistributionSchemaConfig>,
5472
5473    /// Regime change configuration.
5474    #[serde(default)]
5475    pub regime_changes: RegimeChangeSchemaConfig,
5476
5477    /// Industry-specific distribution profile.
5478    #[serde(default)]
5479    pub industry_profile: Option<IndustryProfileType>,
5480
5481    /// Statistical validation configuration.
5482    #[serde(default)]
5483    pub validation: StatisticalValidationSchemaConfig,
5484}
5485
5486/// Industry profile types for pre-configured distribution settings.
5487#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5488#[serde(rename_all = "snake_case")]
5489pub enum IndustryProfileType {
5490    /// Retail industry profile (POS sales, inventory, seasonal)
5491    Retail,
5492    /// Manufacturing industry profile (raw materials, maintenance, capital)
5493    Manufacturing,
5494    /// Financial services profile (wire transfers, ACH, fee income)
5495    FinancialServices,
5496    /// Healthcare profile (claims, procedures, supplies)
5497    Healthcare,
5498    /// Technology profile (subscriptions, services, R&D)
5499    Technology,
5500}
5501
5502/// Mixture model distribution configuration.
5503#[derive(Debug, Clone, Serialize, Deserialize)]
5504pub struct MixtureDistributionSchemaConfig {
5505    /// Enable mixture model for amount generation.
5506    #[serde(default)]
5507    pub enabled: bool,
5508
5509    /// Distribution type: "gaussian" or "lognormal".
5510    #[serde(default = "default_mixture_type")]
5511    pub distribution_type: MixtureDistributionType,
5512
5513    /// Mixture components with weights.
5514    #[serde(default)]
5515    pub components: Vec<MixtureComponentConfig>,
5516
5517    /// Minimum value constraint.
5518    #[serde(default = "default_min_amount")]
5519    pub min_value: f64,
5520
5521    /// Maximum value constraint (optional).
5522    #[serde(default)]
5523    pub max_value: Option<f64>,
5524
5525    /// Decimal places for rounding.
5526    #[serde(default = "default_decimal_places")]
5527    pub decimal_places: u8,
5528}
5529
5530fn default_mixture_type() -> MixtureDistributionType {
5531    MixtureDistributionType::LogNormal
5532}
5533
5534fn default_min_amount() -> f64 {
5535    0.01
5536}
5537
5538fn default_decimal_places() -> u8 {
5539    2
5540}
5541
5542impl Default for MixtureDistributionSchemaConfig {
5543    fn default() -> Self {
5544        Self {
5545            enabled: false,
5546            distribution_type: MixtureDistributionType::LogNormal,
5547            components: Vec::new(),
5548            min_value: 0.01,
5549            max_value: None,
5550            decimal_places: 2,
5551        }
5552    }
5553}
5554
5555/// Mixture distribution type.
5556#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5557#[serde(rename_all = "snake_case")]
5558pub enum MixtureDistributionType {
5559    /// Gaussian (normal) mixture
5560    Gaussian,
5561    /// Log-normal mixture (for positive amounts)
5562    #[default]
5563    LogNormal,
5564}
5565
5566/// Configuration for a single mixture component.
5567#[derive(Debug, Clone, Serialize, Deserialize)]
5568pub struct MixtureComponentConfig {
5569    /// Weight of this component (must sum to 1.0 across all components).
5570    pub weight: f64,
5571
5572    /// Location parameter (mean for Gaussian, mu for log-normal).
5573    pub mu: f64,
5574
5575    /// Scale parameter (std dev for Gaussian, sigma for log-normal).
5576    pub sigma: f64,
5577
5578    /// Optional label for this component (e.g., "routine", "significant", "major").
5579    #[serde(default)]
5580    pub label: Option<String>,
5581}
5582
5583/// Cross-field correlation configuration.
5584#[derive(Debug, Clone, Serialize, Deserialize)]
5585pub struct CorrelationSchemaConfig {
5586    /// Enable correlation modeling.
5587    #[serde(default)]
5588    pub enabled: bool,
5589
5590    /// Copula type for dependency modeling.
5591    #[serde(default)]
5592    pub copula_type: CopulaSchemaType,
5593
5594    /// Field definitions for correlation.
5595    #[serde(default)]
5596    pub fields: Vec<CorrelatedFieldConfig>,
5597
5598    /// Correlation matrix (upper triangular, row-major).
5599    /// For n fields, this should have n*(n-1)/2 values.
5600    #[serde(default)]
5601    pub matrix: Vec<f64>,
5602
5603    /// Expected correlations for validation.
5604    #[serde(default)]
5605    pub expected_correlations: Vec<ExpectedCorrelationConfig>,
5606}
5607
5608impl Default for CorrelationSchemaConfig {
5609    fn default() -> Self {
5610        Self {
5611            enabled: false,
5612            copula_type: CopulaSchemaType::Gaussian,
5613            fields: Vec::new(),
5614            matrix: Vec::new(),
5615            expected_correlations: Vec::new(),
5616        }
5617    }
5618}
5619
5620/// Copula type for dependency modeling.
5621#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5622#[serde(rename_all = "snake_case")]
5623pub enum CopulaSchemaType {
5624    /// Gaussian copula (symmetric, no tail dependence)
5625    #[default]
5626    Gaussian,
5627    /// Clayton copula (lower tail dependence)
5628    Clayton,
5629    /// Gumbel copula (upper tail dependence)
5630    Gumbel,
5631    /// Frank copula (symmetric, no tail dependence)
5632    Frank,
5633    /// Student-t copula (both tail dependencies)
5634    StudentT,
5635}
5636
5637/// Configuration for a correlated field.
5638#[derive(Debug, Clone, Serialize, Deserialize)]
5639pub struct CorrelatedFieldConfig {
5640    /// Field name.
5641    pub name: String,
5642
5643    /// Marginal distribution type.
5644    #[serde(default)]
5645    pub distribution: MarginalDistributionConfig,
5646}
5647
5648/// Marginal distribution configuration.
5649#[derive(Debug, Clone, Serialize, Deserialize)]
5650#[serde(tag = "type", rename_all = "snake_case")]
5651pub enum MarginalDistributionConfig {
5652    /// Normal distribution.
5653    Normal {
5654        /// Mean
5655        mu: f64,
5656        /// Standard deviation
5657        sigma: f64,
5658    },
5659    /// Log-normal distribution.
5660    LogNormal {
5661        /// Location parameter
5662        mu: f64,
5663        /// Scale parameter
5664        sigma: f64,
5665    },
5666    /// Uniform distribution.
5667    Uniform {
5668        /// Minimum value
5669        min: f64,
5670        /// Maximum value
5671        max: f64,
5672    },
5673    /// Discrete uniform distribution.
5674    DiscreteUniform {
5675        /// Minimum integer value
5676        min: i32,
5677        /// Maximum integer value
5678        max: i32,
5679    },
5680}
5681
5682impl Default for MarginalDistributionConfig {
5683    fn default() -> Self {
5684        Self::Normal {
5685            mu: 0.0,
5686            sigma: 1.0,
5687        }
5688    }
5689}
5690
5691/// Expected correlation for validation.
5692#[derive(Debug, Clone, Serialize, Deserialize)]
5693pub struct ExpectedCorrelationConfig {
5694    /// First field name.
5695    pub field1: String,
5696    /// Second field name.
5697    pub field2: String,
5698    /// Expected correlation coefficient.
5699    pub expected_r: f64,
5700    /// Acceptable tolerance.
5701    #[serde(default = "default_correlation_tolerance")]
5702    pub tolerance: f64,
5703}
5704
5705fn default_correlation_tolerance() -> f64 {
5706    0.10
5707}
5708
5709/// Conditional distribution configuration.
5710#[derive(Debug, Clone, Serialize, Deserialize)]
5711pub struct ConditionalDistributionSchemaConfig {
5712    /// Output field name to generate.
5713    pub output_field: String,
5714
5715    /// Input field name that conditions the distribution.
5716    pub input_field: String,
5717
5718    /// Breakpoints defining distribution changes.
5719    #[serde(default)]
5720    pub breakpoints: Vec<ConditionalBreakpointConfig>,
5721
5722    /// Default distribution when below all breakpoints.
5723    #[serde(default)]
5724    pub default_distribution: ConditionalDistributionParamsConfig,
5725
5726    /// Minimum output value constraint.
5727    #[serde(default)]
5728    pub min_value: Option<f64>,
5729
5730    /// Maximum output value constraint.
5731    #[serde(default)]
5732    pub max_value: Option<f64>,
5733
5734    /// Decimal places for output rounding.
5735    #[serde(default = "default_decimal_places")]
5736    pub decimal_places: u8,
5737}
5738
5739/// Breakpoint for conditional distribution.
5740#[derive(Debug, Clone, Serialize, Deserialize)]
5741pub struct ConditionalBreakpointConfig {
5742    /// Input value threshold.
5743    pub threshold: f64,
5744
5745    /// Distribution to use when input >= threshold.
5746    pub distribution: ConditionalDistributionParamsConfig,
5747}
5748
5749/// Distribution parameters for conditional distributions.
5750#[derive(Debug, Clone, Serialize, Deserialize)]
5751#[serde(tag = "type", rename_all = "snake_case")]
5752pub enum ConditionalDistributionParamsConfig {
5753    /// Fixed value.
5754    Fixed {
5755        /// The fixed value
5756        value: f64,
5757    },
5758    /// Normal distribution.
5759    Normal {
5760        /// Mean
5761        mu: f64,
5762        /// Standard deviation
5763        sigma: f64,
5764    },
5765    /// Log-normal distribution.
5766    LogNormal {
5767        /// Location parameter
5768        mu: f64,
5769        /// Scale parameter
5770        sigma: f64,
5771    },
5772    /// Uniform distribution.
5773    Uniform {
5774        /// Minimum
5775        min: f64,
5776        /// Maximum
5777        max: f64,
5778    },
5779    /// Beta distribution (scaled).
5780    Beta {
5781        /// Alpha parameter
5782        alpha: f64,
5783        /// Beta parameter
5784        beta: f64,
5785        /// Minimum output value
5786        min: f64,
5787        /// Maximum output value
5788        max: f64,
5789    },
5790    /// Discrete values with weights.
5791    Discrete {
5792        /// Possible values
5793        values: Vec<f64>,
5794        /// Weights (should sum to 1.0)
5795        weights: Vec<f64>,
5796    },
5797}
5798
5799impl Default for ConditionalDistributionParamsConfig {
5800    fn default() -> Self {
5801        Self::Normal {
5802            mu: 0.0,
5803            sigma: 1.0,
5804        }
5805    }
5806}
5807
5808/// Regime change configuration.
5809#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5810pub struct RegimeChangeSchemaConfig {
5811    /// Enable regime change modeling.
5812    #[serde(default)]
5813    pub enabled: bool,
5814
5815    /// List of regime changes.
5816    #[serde(default)]
5817    pub changes: Vec<RegimeChangeEventConfig>,
5818
5819    /// Economic cycle configuration.
5820    #[serde(default)]
5821    pub economic_cycle: Option<EconomicCycleSchemaConfig>,
5822
5823    /// Parameter drift configurations.
5824    #[serde(default)]
5825    pub parameter_drifts: Vec<ParameterDriftSchemaConfig>,
5826}
5827
5828/// A single regime change event.
5829#[derive(Debug, Clone, Serialize, Deserialize)]
5830pub struct RegimeChangeEventConfig {
5831    /// Date when the change occurs (ISO 8601 format).
5832    pub date: String,
5833
5834    /// Type of regime change.
5835    pub change_type: RegimeChangeTypeConfig,
5836
5837    /// Description of the change.
5838    #[serde(default)]
5839    pub description: Option<String>,
5840
5841    /// Effects of this regime change.
5842    #[serde(default)]
5843    pub effects: Vec<RegimeEffectConfig>,
5844}
5845
5846/// Type of regime change.
5847#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5848#[serde(rename_all = "snake_case")]
5849pub enum RegimeChangeTypeConfig {
5850    /// Acquisition - sudden volume and amount increase
5851    Acquisition,
5852    /// Divestiture - sudden volume and amount decrease
5853    Divestiture,
5854    /// Price increase - amounts increase
5855    PriceIncrease,
5856    /// Price decrease - amounts decrease
5857    PriceDecrease,
5858    /// New product launch - volume ramp-up
5859    ProductLaunch,
5860    /// Product discontinuation - volume ramp-down
5861    ProductDiscontinuation,
5862    /// Policy change - affects patterns
5863    PolicyChange,
5864    /// Competitor entry - market disruption
5865    CompetitorEntry,
5866    /// Custom effect
5867    Custom,
5868}
5869
5870/// Effect of a regime change on a specific field.
5871#[derive(Debug, Clone, Serialize, Deserialize)]
5872pub struct RegimeEffectConfig {
5873    /// Field being affected.
5874    pub field: String,
5875
5876    /// Multiplier to apply (1.0 = no change, 1.5 = 50% increase).
5877    pub multiplier: f64,
5878}
5879
5880/// Economic cycle configuration.
5881#[derive(Debug, Clone, Serialize, Deserialize)]
5882pub struct EconomicCycleSchemaConfig {
5883    /// Enable economic cycle modeling.
5884    #[serde(default)]
5885    pub enabled: bool,
5886
5887    /// Cycle period in months (e.g., 48 for 4-year business cycle).
5888    #[serde(default = "default_cycle_period")]
5889    pub period_months: u32,
5890
5891    /// Amplitude of cycle effect (0.0-1.0).
5892    #[serde(default = "default_cycle_amplitude")]
5893    pub amplitude: f64,
5894
5895    /// Phase offset in months.
5896    #[serde(default)]
5897    pub phase_offset: u32,
5898
5899    /// Recession periods (start_month, duration_months).
5900    #[serde(default)]
5901    pub recessions: Vec<RecessionPeriodConfig>,
5902}
5903
5904fn default_cycle_period() -> u32 {
5905    48
5906}
5907
5908fn default_cycle_amplitude() -> f64 {
5909    0.15
5910}
5911
5912impl Default for EconomicCycleSchemaConfig {
5913    fn default() -> Self {
5914        Self {
5915            enabled: false,
5916            period_months: 48,
5917            amplitude: 0.15,
5918            phase_offset: 0,
5919            recessions: Vec::new(),
5920        }
5921    }
5922}
5923
5924/// Recession period configuration.
5925#[derive(Debug, Clone, Serialize, Deserialize)]
5926pub struct RecessionPeriodConfig {
5927    /// Start month (0-indexed from generation start).
5928    pub start_month: u32,
5929
5930    /// Duration in months.
5931    pub duration_months: u32,
5932
5933    /// Severity (0.0-1.0, affects volume reduction).
5934    #[serde(default = "default_recession_severity")]
5935    pub severity: f64,
5936}
5937
5938fn default_recession_severity() -> f64 {
5939    0.20
5940}
5941
5942/// Parameter drift configuration.
5943#[derive(Debug, Clone, Serialize, Deserialize)]
5944pub struct ParameterDriftSchemaConfig {
5945    /// Parameter being drifted.
5946    pub parameter: String,
5947
5948    /// Drift type.
5949    pub drift_type: ParameterDriftTypeConfig,
5950
5951    /// Start value.
5952    pub start_value: f64,
5953
5954    /// End value.
5955    pub end_value: f64,
5956
5957    /// Start period (month, 0-indexed).
5958    #[serde(default)]
5959    pub start_period: u32,
5960
5961    /// End period (month, optional - defaults to end of generation).
5962    #[serde(default)]
5963    pub end_period: Option<u32>,
5964}
5965
5966/// Parameter drift type.
5967#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
5968#[serde(rename_all = "snake_case")]
5969pub enum ParameterDriftTypeConfig {
5970    /// Linear interpolation
5971    #[default]
5972    Linear,
5973    /// Exponential growth/decay
5974    Exponential,
5975    /// S-curve (logistic)
5976    Logistic,
5977    /// Step function
5978    Step,
5979}
5980
5981/// Statistical validation configuration.
5982#[derive(Debug, Clone, Serialize, Deserialize, Default)]
5983pub struct StatisticalValidationSchemaConfig {
5984    /// Enable statistical validation.
5985    #[serde(default)]
5986    pub enabled: bool,
5987
5988    /// Statistical tests to run.
5989    #[serde(default)]
5990    pub tests: Vec<StatisticalTestConfig>,
5991
5992    /// Validation reporting configuration.
5993    #[serde(default)]
5994    pub reporting: ValidationReportingConfig,
5995}
5996
5997/// Statistical test configuration.
5998#[derive(Debug, Clone, Serialize, Deserialize)]
5999#[serde(tag = "type", rename_all = "snake_case")]
6000pub enum StatisticalTestConfig {
6001    /// Benford's Law first digit test.
6002    BenfordFirstDigit {
6003        /// Threshold MAD for failure.
6004        #[serde(default = "default_benford_threshold")]
6005        threshold_mad: f64,
6006        /// Warning MAD threshold.
6007        #[serde(default = "default_benford_warning")]
6008        warning_mad: f64,
6009    },
6010    /// Distribution fit test.
6011    DistributionFit {
6012        /// Target distribution to test.
6013        target: TargetDistributionConfig,
6014        /// K-S test significance level.
6015        #[serde(default = "default_ks_significance")]
6016        ks_significance: f64,
6017        /// Test method (ks, anderson_darling, chi_squared).
6018        #[serde(default)]
6019        method: DistributionFitMethod,
6020    },
6021    /// Correlation check.
6022    CorrelationCheck {
6023        /// Expected correlations to validate.
6024        expected_correlations: Vec<ExpectedCorrelationConfig>,
6025    },
6026    /// Chi-squared test.
6027    ChiSquared {
6028        /// Number of bins.
6029        #[serde(default = "default_chi_squared_bins")]
6030        bins: usize,
6031        /// Significance level.
6032        #[serde(default = "default_chi_squared_significance")]
6033        significance: f64,
6034    },
6035    /// Anderson-Darling test.
6036    AndersonDarling {
6037        /// Target distribution.
6038        target: TargetDistributionConfig,
6039        /// Significance level.
6040        #[serde(default = "default_ad_significance")]
6041        significance: f64,
6042    },
6043}
6044
6045fn default_benford_threshold() -> f64 {
6046    0.015
6047}
6048
6049fn default_benford_warning() -> f64 {
6050    0.010
6051}
6052
6053fn default_ks_significance() -> f64 {
6054    0.05
6055}
6056
6057fn default_chi_squared_bins() -> usize {
6058    10
6059}
6060
6061fn default_chi_squared_significance() -> f64 {
6062    0.05
6063}
6064
6065fn default_ad_significance() -> f64 {
6066    0.05
6067}
6068
6069/// Target distribution for fit tests.
6070#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6071#[serde(rename_all = "snake_case")]
6072pub enum TargetDistributionConfig {
6073    /// Normal distribution
6074    Normal,
6075    /// Log-normal distribution
6076    #[default]
6077    LogNormal,
6078    /// Exponential distribution
6079    Exponential,
6080    /// Uniform distribution
6081    Uniform,
6082}
6083
6084/// Distribution fit test method.
6085#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6086#[serde(rename_all = "snake_case")]
6087pub enum DistributionFitMethod {
6088    /// Kolmogorov-Smirnov test
6089    #[default]
6090    KolmogorovSmirnov,
6091    /// Anderson-Darling test
6092    AndersonDarling,
6093    /// Chi-squared test
6094    ChiSquared,
6095}
6096
6097/// Validation reporting configuration.
6098#[derive(Debug, Clone, Serialize, Deserialize)]
6099pub struct ValidationReportingConfig {
6100    /// Output validation report to file.
6101    #[serde(default)]
6102    pub output_report: bool,
6103
6104    /// Report format.
6105    #[serde(default)]
6106    pub format: ValidationReportFormat,
6107
6108    /// Fail generation if validation fails.
6109    #[serde(default)]
6110    pub fail_on_error: bool,
6111
6112    /// Include detailed statistics in report.
6113    #[serde(default = "default_true")]
6114    pub include_details: bool,
6115}
6116
6117impl Default for ValidationReportingConfig {
6118    fn default() -> Self {
6119        Self {
6120            output_report: false,
6121            format: ValidationReportFormat::Json,
6122            fail_on_error: false,
6123            include_details: true,
6124        }
6125    }
6126}
6127
6128/// Validation report format.
6129#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
6130#[serde(rename_all = "snake_case")]
6131pub enum ValidationReportFormat {
6132    /// JSON format
6133    #[default]
6134    Json,
6135    /// YAML format
6136    Yaml,
6137    /// HTML report
6138    Html,
6139}
6140
6141// =============================================================================
6142// Temporal Patterns Configuration
6143// =============================================================================
6144
6145/// Temporal patterns configuration for business days, period-end dynamics, and processing lags.
6146///
6147/// This section enables sophisticated temporal modeling including:
6148/// - Business day calculations and settlement dates
6149/// - Regional holiday calendars
6150/// - Period-end decay curves (non-flat volume spikes)
6151/// - Processing lag modeling (event-to-posting delays)
6152#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6153pub struct TemporalPatternsConfig {
6154    /// Enable temporal patterns features.
6155    #[serde(default)]
6156    pub enabled: bool,
6157
6158    /// Business day calculation configuration.
6159    #[serde(default)]
6160    pub business_days: BusinessDaySchemaConfig,
6161
6162    /// Regional calendar configuration.
6163    #[serde(default)]
6164    pub calendars: CalendarSchemaConfig,
6165
6166    /// Period-end dynamics configuration.
6167    #[serde(default)]
6168    pub period_end: PeriodEndSchemaConfig,
6169
6170    /// Processing lag configuration.
6171    #[serde(default)]
6172    pub processing_lags: ProcessingLagSchemaConfig,
6173
6174    /// Fiscal calendar configuration (custom year start, 4-4-5, 13-period).
6175    #[serde(default)]
6176    pub fiscal_calendar: FiscalCalendarSchemaConfig,
6177
6178    /// Intra-day patterns configuration (morning spike, lunch dip, EOD rush).
6179    #[serde(default)]
6180    pub intraday: IntraDaySchemaConfig,
6181
6182    /// Timezone handling configuration.
6183    #[serde(default)]
6184    pub timezones: TimezoneSchemaConfig,
6185}
6186
6187/// Business day calculation configuration.
6188#[derive(Debug, Clone, Serialize, Deserialize)]
6189pub struct BusinessDaySchemaConfig {
6190    /// Enable business day calculations.
6191    #[serde(default = "default_true")]
6192    pub enabled: bool,
6193
6194    /// Half-day policy: "full_day", "half_day", "non_business_day".
6195    #[serde(default = "default_half_day_policy")]
6196    pub half_day_policy: String,
6197
6198    /// Settlement rules configuration.
6199    #[serde(default)]
6200    pub settlement_rules: SettlementRulesSchemaConfig,
6201
6202    /// Month-end convention: "modified_following", "preceding", "following", "end_of_month".
6203    #[serde(default = "default_month_end_convention")]
6204    pub month_end_convention: String,
6205
6206    /// Weekend days (e.g., ["saturday", "sunday"] or ["friday", "saturday"] for Middle East).
6207    #[serde(default)]
6208    pub weekend_days: Option<Vec<String>>,
6209}
6210
6211fn default_half_day_policy() -> String {
6212    "half_day".to_string()
6213}
6214
6215fn default_month_end_convention() -> String {
6216    "modified_following".to_string()
6217}
6218
6219impl Default for BusinessDaySchemaConfig {
6220    fn default() -> Self {
6221        Self {
6222            enabled: true,
6223            half_day_policy: "half_day".to_string(),
6224            settlement_rules: SettlementRulesSchemaConfig::default(),
6225            month_end_convention: "modified_following".to_string(),
6226            weekend_days: None,
6227        }
6228    }
6229}
6230
6231/// Settlement rules configuration.
6232#[derive(Debug, Clone, Serialize, Deserialize)]
6233pub struct SettlementRulesSchemaConfig {
6234    /// Equity settlement days (T+N).
6235    #[serde(default = "default_settlement_2")]
6236    pub equity_days: i32,
6237
6238    /// Government bonds settlement days.
6239    #[serde(default = "default_settlement_1")]
6240    pub government_bonds_days: i32,
6241
6242    /// FX spot settlement days.
6243    #[serde(default = "default_settlement_2")]
6244    pub fx_spot_days: i32,
6245
6246    /// Corporate bonds settlement days.
6247    #[serde(default = "default_settlement_2")]
6248    pub corporate_bonds_days: i32,
6249
6250    /// Wire transfer cutoff time (HH:MM format).
6251    #[serde(default = "default_wire_cutoff")]
6252    pub wire_cutoff_time: String,
6253
6254    /// International wire settlement days.
6255    #[serde(default = "default_settlement_1")]
6256    pub wire_international_days: i32,
6257
6258    /// ACH settlement days.
6259    #[serde(default = "default_settlement_1")]
6260    pub ach_days: i32,
6261}
6262
6263fn default_settlement_1() -> i32 {
6264    1
6265}
6266
6267fn default_settlement_2() -> i32 {
6268    2
6269}
6270
6271fn default_wire_cutoff() -> String {
6272    "14:00".to_string()
6273}
6274
6275impl Default for SettlementRulesSchemaConfig {
6276    fn default() -> Self {
6277        Self {
6278            equity_days: 2,
6279            government_bonds_days: 1,
6280            fx_spot_days: 2,
6281            corporate_bonds_days: 2,
6282            wire_cutoff_time: "14:00".to_string(),
6283            wire_international_days: 1,
6284            ach_days: 1,
6285        }
6286    }
6287}
6288
6289/// Regional calendar configuration.
6290#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6291pub struct CalendarSchemaConfig {
6292    /// List of regions to include (e.g., ["US", "DE", "BR", "SG", "KR"]).
6293    #[serde(default)]
6294    pub regions: Vec<String>,
6295
6296    /// Custom holidays (in addition to regional calendars).
6297    #[serde(default)]
6298    pub custom_holidays: Vec<CustomHolidaySchemaConfig>,
6299}
6300
6301/// Custom holiday configuration.
6302#[derive(Debug, Clone, Serialize, Deserialize)]
6303pub struct CustomHolidaySchemaConfig {
6304    /// Holiday name.
6305    pub name: String,
6306    /// Month (1-12).
6307    pub month: u8,
6308    /// Day of month.
6309    pub day: u8,
6310    /// Activity multiplier (0.0-1.0, default 0.05).
6311    #[serde(default = "default_holiday_multiplier")]
6312    pub activity_multiplier: f64,
6313}
6314
6315fn default_holiday_multiplier() -> f64 {
6316    0.05
6317}
6318
6319/// Period-end dynamics configuration.
6320#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6321pub struct PeriodEndSchemaConfig {
6322    /// Model type: "flat", "exponential", "extended_crunch", "daily_profile".
6323    #[serde(default)]
6324    pub model: Option<String>,
6325
6326    /// Month-end configuration.
6327    #[serde(default)]
6328    pub month_end: Option<PeriodEndModelSchemaConfig>,
6329
6330    /// Quarter-end configuration.
6331    #[serde(default)]
6332    pub quarter_end: Option<PeriodEndModelSchemaConfig>,
6333
6334    /// Year-end configuration.
6335    #[serde(default)]
6336    pub year_end: Option<PeriodEndModelSchemaConfig>,
6337}
6338
6339/// Period-end model configuration.
6340#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6341pub struct PeriodEndModelSchemaConfig {
6342    /// Inherit configuration from another period (e.g., "month_end").
6343    #[serde(default)]
6344    pub inherit_from: Option<String>,
6345
6346    /// Additional multiplier on top of inherited/base model.
6347    #[serde(default)]
6348    pub additional_multiplier: Option<f64>,
6349
6350    /// Days before period end to start acceleration (negative, e.g., -10).
6351    #[serde(default)]
6352    pub start_day: Option<i32>,
6353
6354    /// Base multiplier at start of acceleration.
6355    #[serde(default)]
6356    pub base_multiplier: Option<f64>,
6357
6358    /// Peak multiplier on last day.
6359    #[serde(default)]
6360    pub peak_multiplier: Option<f64>,
6361
6362    /// Decay rate for exponential model (0.1-0.5 typical).
6363    #[serde(default)]
6364    pub decay_rate: Option<f64>,
6365
6366    /// Sustained high days for crunch model.
6367    #[serde(default)]
6368    pub sustained_high_days: Option<i32>,
6369}
6370
6371/// Processing lag configuration.
6372#[derive(Debug, Clone, Serialize, Deserialize)]
6373pub struct ProcessingLagSchemaConfig {
6374    /// Enable processing lag calculations.
6375    #[serde(default = "default_true")]
6376    pub enabled: bool,
6377
6378    /// Sales order lag configuration (log-normal mu, sigma).
6379    #[serde(default)]
6380    pub sales_order_lag: Option<LagDistributionSchemaConfig>,
6381
6382    /// Purchase order lag configuration.
6383    #[serde(default)]
6384    pub purchase_order_lag: Option<LagDistributionSchemaConfig>,
6385
6386    /// Goods receipt lag configuration.
6387    #[serde(default)]
6388    pub goods_receipt_lag: Option<LagDistributionSchemaConfig>,
6389
6390    /// Invoice receipt lag configuration.
6391    #[serde(default)]
6392    pub invoice_receipt_lag: Option<LagDistributionSchemaConfig>,
6393
6394    /// Invoice issue lag configuration.
6395    #[serde(default)]
6396    pub invoice_issue_lag: Option<LagDistributionSchemaConfig>,
6397
6398    /// Payment lag configuration.
6399    #[serde(default)]
6400    pub payment_lag: Option<LagDistributionSchemaConfig>,
6401
6402    /// Journal entry lag configuration.
6403    #[serde(default)]
6404    pub journal_entry_lag: Option<LagDistributionSchemaConfig>,
6405
6406    /// Cross-day posting configuration.
6407    #[serde(default)]
6408    pub cross_day_posting: Option<CrossDayPostingSchemaConfig>,
6409}
6410
6411impl Default for ProcessingLagSchemaConfig {
6412    fn default() -> Self {
6413        Self {
6414            enabled: true,
6415            sales_order_lag: None,
6416            purchase_order_lag: None,
6417            goods_receipt_lag: None,
6418            invoice_receipt_lag: None,
6419            invoice_issue_lag: None,
6420            payment_lag: None,
6421            journal_entry_lag: None,
6422            cross_day_posting: None,
6423        }
6424    }
6425}
6426
6427/// Lag distribution configuration (log-normal parameters).
6428#[derive(Debug, Clone, Serialize, Deserialize)]
6429pub struct LagDistributionSchemaConfig {
6430    /// Log-scale mean (mu for log-normal).
6431    pub mu: f64,
6432    /// Log-scale standard deviation (sigma for log-normal).
6433    pub sigma: f64,
6434    /// Minimum lag in hours.
6435    #[serde(default)]
6436    pub min_hours: Option<f64>,
6437    /// Maximum lag in hours.
6438    #[serde(default)]
6439    pub max_hours: Option<f64>,
6440}
6441
6442/// Cross-day posting configuration.
6443#[derive(Debug, Clone, Serialize, Deserialize)]
6444pub struct CrossDayPostingSchemaConfig {
6445    /// Enable cross-day posting logic.
6446    #[serde(default = "default_true")]
6447    pub enabled: bool,
6448
6449    /// Probability of next-day posting by hour (map of hour -> probability).
6450    /// E.g., { 17: 0.7, 19: 0.9, 21: 0.99 }
6451    #[serde(default)]
6452    pub probability_by_hour: std::collections::HashMap<u8, f64>,
6453}
6454
6455impl Default for CrossDayPostingSchemaConfig {
6456    fn default() -> Self {
6457        let mut probability_by_hour = std::collections::HashMap::new();
6458        probability_by_hour.insert(17, 0.3);
6459        probability_by_hour.insert(18, 0.6);
6460        probability_by_hour.insert(19, 0.8);
6461        probability_by_hour.insert(20, 0.9);
6462        probability_by_hour.insert(21, 0.95);
6463        probability_by_hour.insert(22, 0.99);
6464
6465        Self {
6466            enabled: true,
6467            probability_by_hour,
6468        }
6469    }
6470}
6471
6472// =============================================================================
6473// Fiscal Calendar Configuration (P2)
6474// =============================================================================
6475
6476/// Fiscal calendar configuration.
6477///
6478/// Supports calendar year, custom year start, 4-4-5 retail calendar,
6479/// and 13-period calendars.
6480#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6481pub struct FiscalCalendarSchemaConfig {
6482    /// Enable non-standard fiscal calendar.
6483    #[serde(default)]
6484    pub enabled: bool,
6485
6486    /// Fiscal calendar type: "calendar_year", "custom", "four_four_five", "thirteen_period".
6487    #[serde(default = "default_fiscal_calendar_type")]
6488    pub calendar_type: String,
6489
6490    /// Month the fiscal year starts (1-12). Used for custom year start.
6491    #[serde(default)]
6492    pub year_start_month: Option<u8>,
6493
6494    /// Day the fiscal year starts (1-31). Used for custom year start.
6495    #[serde(default)]
6496    pub year_start_day: Option<u8>,
6497
6498    /// 4-4-5 calendar configuration (if calendar_type is "four_four_five").
6499    #[serde(default)]
6500    pub four_four_five: Option<FourFourFiveSchemaConfig>,
6501}
6502
6503fn default_fiscal_calendar_type() -> String {
6504    "calendar_year".to_string()
6505}
6506
6507/// 4-4-5 retail calendar configuration.
6508#[derive(Debug, Clone, Serialize, Deserialize)]
6509pub struct FourFourFiveSchemaConfig {
6510    /// Week pattern: "four_four_five", "four_five_four", "five_four_four".
6511    #[serde(default = "default_week_pattern")]
6512    pub pattern: String,
6513
6514    /// Anchor type: "first_sunday", "last_saturday", "nearest_saturday".
6515    #[serde(default = "default_anchor_type")]
6516    pub anchor_type: String,
6517
6518    /// Anchor month (1-12).
6519    #[serde(default = "default_anchor_month")]
6520    pub anchor_month: u8,
6521
6522    /// Where to place leap week: "q4_period3" or "q1_period1".
6523    #[serde(default = "default_leap_week_placement")]
6524    pub leap_week_placement: String,
6525}
6526
6527fn default_week_pattern() -> String {
6528    "four_four_five".to_string()
6529}
6530
6531fn default_anchor_type() -> String {
6532    "last_saturday".to_string()
6533}
6534
6535fn default_anchor_month() -> u8 {
6536    1 // January
6537}
6538
6539fn default_leap_week_placement() -> String {
6540    "q4_period3".to_string()
6541}
6542
6543impl Default for FourFourFiveSchemaConfig {
6544    fn default() -> Self {
6545        Self {
6546            pattern: "four_four_five".to_string(),
6547            anchor_type: "last_saturday".to_string(),
6548            anchor_month: 1,
6549            leap_week_placement: "q4_period3".to_string(),
6550        }
6551    }
6552}
6553
6554// =============================================================================
6555// Intra-Day Patterns Configuration (P2)
6556// =============================================================================
6557
6558/// Intra-day patterns configuration.
6559///
6560/// Defines time-of-day segments with different activity multipliers
6561/// for realistic modeling of morning spikes, lunch dips, and end-of-day rushes.
6562#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6563pub struct IntraDaySchemaConfig {
6564    /// Enable intra-day patterns.
6565    #[serde(default)]
6566    pub enabled: bool,
6567
6568    /// Custom intra-day segments.
6569    #[serde(default)]
6570    pub segments: Vec<IntraDaySegmentSchemaConfig>,
6571}
6572
6573/// Intra-day segment configuration.
6574#[derive(Debug, Clone, Serialize, Deserialize)]
6575pub struct IntraDaySegmentSchemaConfig {
6576    /// Name of the segment (e.g., "morning_spike", "lunch_dip").
6577    pub name: String,
6578
6579    /// Start time (HH:MM format).
6580    pub start: String,
6581
6582    /// End time (HH:MM format).
6583    pub end: String,
6584
6585    /// Activity multiplier (1.0 = normal).
6586    #[serde(default = "default_multiplier")]
6587    pub multiplier: f64,
6588
6589    /// Posting type: "human", "system", "both".
6590    #[serde(default = "default_posting_type")]
6591    pub posting_type: String,
6592}
6593
6594fn default_multiplier() -> f64 {
6595    1.0
6596}
6597
6598fn default_posting_type() -> String {
6599    "both".to_string()
6600}
6601
6602// =============================================================================
6603// Timezone Configuration
6604// =============================================================================
6605
6606/// Timezone handling configuration for multi-region entities.
6607#[derive(Debug, Clone, Serialize, Deserialize, Default)]
6608pub struct TimezoneSchemaConfig {
6609    /// Enable timezone handling.
6610    #[serde(default)]
6611    pub enabled: bool,
6612
6613    /// Default timezone (IANA format, e.g., "America/New_York").
6614    #[serde(default = "default_timezone")]
6615    pub default_timezone: String,
6616
6617    /// Consolidation timezone for group reporting (IANA format).
6618    #[serde(default = "default_consolidation_timezone")]
6619    pub consolidation_timezone: String,
6620
6621    /// Entity-to-timezone mappings.
6622    /// Supports patterns like "EU_*" -> "Europe/London".
6623    #[serde(default)]
6624    pub entity_mappings: Vec<EntityTimezoneMapping>,
6625}
6626
6627fn default_timezone() -> String {
6628    "America/New_York".to_string()
6629}
6630
6631fn default_consolidation_timezone() -> String {
6632    "UTC".to_string()
6633}
6634
6635/// Mapping from entity pattern to timezone.
6636#[derive(Debug, Clone, Serialize, Deserialize)]
6637pub struct EntityTimezoneMapping {
6638    /// Entity code pattern (e.g., "EU_*", "*_APAC", "1000").
6639    pub pattern: String,
6640
6641    /// Timezone (IANA format, e.g., "Europe/London").
6642    pub timezone: String,
6643}
6644
6645// =============================================================================
6646// Vendor Network Configuration
6647// =============================================================================
6648
6649/// Configuration for multi-tier vendor network generation.
6650#[derive(Debug, Clone, Serialize, Deserialize)]
6651pub struct VendorNetworkSchemaConfig {
6652    /// Enable vendor network generation.
6653    #[serde(default)]
6654    pub enabled: bool,
6655
6656    /// Maximum depth of supply chain tiers (1-3).
6657    #[serde(default = "default_vendor_tier_depth")]
6658    pub depth: u8,
6659
6660    /// Tier 1 vendor count configuration.
6661    #[serde(default)]
6662    pub tier1: TierCountSchemaConfig,
6663
6664    /// Tier 2 vendors per Tier 1 parent.
6665    #[serde(default)]
6666    pub tier2_per_parent: TierCountSchemaConfig,
6667
6668    /// Tier 3 vendors per Tier 2 parent.
6669    #[serde(default)]
6670    pub tier3_per_parent: TierCountSchemaConfig,
6671
6672    /// Vendor cluster distribution.
6673    #[serde(default)]
6674    pub clusters: VendorClusterSchemaConfig,
6675
6676    /// Concentration limits.
6677    #[serde(default)]
6678    pub dependencies: DependencySchemaConfig,
6679}
6680
6681fn default_vendor_tier_depth() -> u8 {
6682    3
6683}
6684
6685impl Default for VendorNetworkSchemaConfig {
6686    fn default() -> Self {
6687        Self {
6688            enabled: false,
6689            depth: 3,
6690            tier1: TierCountSchemaConfig { min: 50, max: 100 },
6691            tier2_per_parent: TierCountSchemaConfig { min: 4, max: 10 },
6692            tier3_per_parent: TierCountSchemaConfig { min: 2, max: 5 },
6693            clusters: VendorClusterSchemaConfig::default(),
6694            dependencies: DependencySchemaConfig::default(),
6695        }
6696    }
6697}
6698
6699/// Tier count configuration.
6700#[derive(Debug, Clone, Serialize, Deserialize)]
6701pub struct TierCountSchemaConfig {
6702    /// Minimum count.
6703    #[serde(default = "default_tier_min")]
6704    pub min: usize,
6705
6706    /// Maximum count.
6707    #[serde(default = "default_tier_max")]
6708    pub max: usize,
6709}
6710
6711fn default_tier_min() -> usize {
6712    5
6713}
6714
6715fn default_tier_max() -> usize {
6716    20
6717}
6718
6719impl Default for TierCountSchemaConfig {
6720    fn default() -> Self {
6721        Self {
6722            min: default_tier_min(),
6723            max: default_tier_max(),
6724        }
6725    }
6726}
6727
6728/// Vendor cluster distribution configuration.
6729#[derive(Debug, Clone, Serialize, Deserialize)]
6730pub struct VendorClusterSchemaConfig {
6731    /// Reliable strategic vendors percentage (default: 0.20).
6732    #[serde(default = "default_reliable_strategic")]
6733    pub reliable_strategic: f64,
6734
6735    /// Standard operational vendors percentage (default: 0.50).
6736    #[serde(default = "default_standard_operational")]
6737    pub standard_operational: f64,
6738
6739    /// Transactional vendors percentage (default: 0.25).
6740    #[serde(default = "default_transactional")]
6741    pub transactional: f64,
6742
6743    /// Problematic vendors percentage (default: 0.05).
6744    #[serde(default = "default_problematic")]
6745    pub problematic: f64,
6746}
6747
6748fn default_reliable_strategic() -> f64 {
6749    0.20
6750}
6751
6752fn default_standard_operational() -> f64 {
6753    0.50
6754}
6755
6756fn default_transactional() -> f64 {
6757    0.25
6758}
6759
6760fn default_problematic() -> f64 {
6761    0.05
6762}
6763
6764impl Default for VendorClusterSchemaConfig {
6765    fn default() -> Self {
6766        Self {
6767            reliable_strategic: 0.20,
6768            standard_operational: 0.50,
6769            transactional: 0.25,
6770            problematic: 0.05,
6771        }
6772    }
6773}
6774
6775/// Dependency and concentration limits configuration.
6776#[derive(Debug, Clone, Serialize, Deserialize)]
6777pub struct DependencySchemaConfig {
6778    /// Maximum concentration for a single vendor (default: 0.15).
6779    #[serde(default = "default_max_single_vendor")]
6780    pub max_single_vendor_concentration: f64,
6781
6782    /// Maximum concentration for top 5 vendors (default: 0.45).
6783    #[serde(default = "default_max_top5")]
6784    pub top_5_concentration: f64,
6785
6786    /// Percentage of single-source vendors (default: 0.05).
6787    #[serde(default = "default_single_source_percent")]
6788    pub single_source_percent: f64,
6789}
6790
6791fn default_max_single_vendor() -> f64 {
6792    0.15
6793}
6794
6795fn default_max_top5() -> f64 {
6796    0.45
6797}
6798
6799fn default_single_source_percent() -> f64 {
6800    0.05
6801}
6802
6803impl Default for DependencySchemaConfig {
6804    fn default() -> Self {
6805        Self {
6806            max_single_vendor_concentration: 0.15,
6807            top_5_concentration: 0.45,
6808            single_source_percent: 0.05,
6809        }
6810    }
6811}
6812
6813// =============================================================================
6814// Customer Segmentation Configuration
6815// =============================================================================
6816
6817/// Configuration for customer segmentation generation.
6818#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6819pub struct CustomerSegmentationSchemaConfig {
6820    /// Enable customer segmentation generation.
6821    #[serde(default)]
6822    pub enabled: bool,
6823
6824    /// Value segment distribution.
6825    #[serde(default)]
6826    pub value_segments: ValueSegmentsSchemaConfig,
6827
6828    /// Lifecycle stage configuration.
6829    #[serde(default)]
6830    pub lifecycle: LifecycleSchemaConfig,
6831
6832    /// Network (referrals, hierarchies) configuration.
6833    #[serde(default)]
6834    pub networks: CustomerNetworksSchemaConfig,
6835}
6836
6837/// Customer value segments distribution configuration.
6838#[derive(Debug, Clone, Serialize, Deserialize)]
6839pub struct ValueSegmentsSchemaConfig {
6840    /// Enterprise segment configuration.
6841    #[serde(default)]
6842    pub enterprise: SegmentDetailSchemaConfig,
6843
6844    /// Mid-market segment configuration.
6845    #[serde(default)]
6846    pub mid_market: SegmentDetailSchemaConfig,
6847
6848    /// SMB segment configuration.
6849    #[serde(default)]
6850    pub smb: SegmentDetailSchemaConfig,
6851
6852    /// Consumer segment configuration.
6853    #[serde(default)]
6854    pub consumer: SegmentDetailSchemaConfig,
6855}
6856
6857impl Default for ValueSegmentsSchemaConfig {
6858    fn default() -> Self {
6859        Self {
6860            enterprise: SegmentDetailSchemaConfig {
6861                revenue_share: 0.40,
6862                customer_share: 0.05,
6863                avg_order_value_range: "50000+".to_string(),
6864            },
6865            mid_market: SegmentDetailSchemaConfig {
6866                revenue_share: 0.35,
6867                customer_share: 0.20,
6868                avg_order_value_range: "5000-50000".to_string(),
6869            },
6870            smb: SegmentDetailSchemaConfig {
6871                revenue_share: 0.20,
6872                customer_share: 0.50,
6873                avg_order_value_range: "500-5000".to_string(),
6874            },
6875            consumer: SegmentDetailSchemaConfig {
6876                revenue_share: 0.05,
6877                customer_share: 0.25,
6878                avg_order_value_range: "50-500".to_string(),
6879            },
6880        }
6881    }
6882}
6883
6884/// Individual segment detail configuration.
6885#[derive(Debug, Clone, Serialize, Deserialize)]
6886pub struct SegmentDetailSchemaConfig {
6887    /// Revenue share for this segment.
6888    #[serde(default)]
6889    pub revenue_share: f64,
6890
6891    /// Customer share for this segment.
6892    #[serde(default)]
6893    pub customer_share: f64,
6894
6895    /// Average order value range (e.g., "5000-50000" or "50000+").
6896    #[serde(default)]
6897    pub avg_order_value_range: String,
6898}
6899
6900impl Default for SegmentDetailSchemaConfig {
6901    fn default() -> Self {
6902        Self {
6903            revenue_share: 0.25,
6904            customer_share: 0.25,
6905            avg_order_value_range: "1000-10000".to_string(),
6906        }
6907    }
6908}
6909
6910/// Customer lifecycle stage configuration.
6911#[derive(Debug, Clone, Serialize, Deserialize)]
6912pub struct LifecycleSchemaConfig {
6913    /// Prospect stage rate.
6914    #[serde(default)]
6915    pub prospect_rate: f64,
6916
6917    /// New customer stage rate.
6918    #[serde(default = "default_new_rate")]
6919    pub new_rate: f64,
6920
6921    /// Growth stage rate.
6922    #[serde(default = "default_growth_rate")]
6923    pub growth_rate: f64,
6924
6925    /// Mature stage rate.
6926    #[serde(default = "default_mature_rate")]
6927    pub mature_rate: f64,
6928
6929    /// At-risk stage rate.
6930    #[serde(default = "default_at_risk_rate")]
6931    pub at_risk_rate: f64,
6932
6933    /// Churned stage rate.
6934    #[serde(default = "default_churned_rate")]
6935    pub churned_rate: f64,
6936
6937    /// Won-back stage rate (churned customers reacquired).
6938    #[serde(default)]
6939    pub won_back_rate: f64,
6940}
6941
6942fn default_new_rate() -> f64 {
6943    0.10
6944}
6945
6946fn default_growth_rate() -> f64 {
6947    0.15
6948}
6949
6950fn default_mature_rate() -> f64 {
6951    0.60
6952}
6953
6954fn default_at_risk_rate() -> f64 {
6955    0.10
6956}
6957
6958fn default_churned_rate() -> f64 {
6959    0.05
6960}
6961
6962impl Default for LifecycleSchemaConfig {
6963    fn default() -> Self {
6964        Self {
6965            prospect_rate: 0.0,
6966            new_rate: 0.10,
6967            growth_rate: 0.15,
6968            mature_rate: 0.60,
6969            at_risk_rate: 0.10,
6970            churned_rate: 0.05,
6971            won_back_rate: 0.0,
6972        }
6973    }
6974}
6975
6976/// Customer networks configuration (referrals, hierarchies).
6977#[derive(Debug, Clone, Default, Serialize, Deserialize)]
6978pub struct CustomerNetworksSchemaConfig {
6979    /// Referral network configuration.
6980    #[serde(default)]
6981    pub referrals: ReferralSchemaConfig,
6982
6983    /// Corporate hierarchy configuration.
6984    #[serde(default)]
6985    pub corporate_hierarchies: HierarchySchemaConfig,
6986}
6987
6988/// Referral network configuration.
6989#[derive(Debug, Clone, Serialize, Deserialize)]
6990pub struct ReferralSchemaConfig {
6991    /// Enable referral generation.
6992    #[serde(default = "default_true")]
6993    pub enabled: bool,
6994
6995    /// Rate of customers acquired via referral.
6996    #[serde(default = "default_referral_rate")]
6997    pub referral_rate: f64,
6998}
6999
7000fn default_referral_rate() -> f64 {
7001    0.15
7002}
7003
7004impl Default for ReferralSchemaConfig {
7005    fn default() -> Self {
7006        Self {
7007            enabled: true,
7008            referral_rate: 0.15,
7009        }
7010    }
7011}
7012
7013/// Corporate hierarchy configuration.
7014#[derive(Debug, Clone, Serialize, Deserialize)]
7015pub struct HierarchySchemaConfig {
7016    /// Enable corporate hierarchy generation.
7017    #[serde(default = "default_true")]
7018    pub enabled: bool,
7019
7020    /// Rate of customers in hierarchies.
7021    #[serde(default = "default_hierarchy_rate")]
7022    pub probability: f64,
7023}
7024
7025fn default_hierarchy_rate() -> f64 {
7026    0.30
7027}
7028
7029impl Default for HierarchySchemaConfig {
7030    fn default() -> Self {
7031        Self {
7032            enabled: true,
7033            probability: 0.30,
7034        }
7035    }
7036}
7037
7038// =============================================================================
7039// Relationship Strength Configuration
7040// =============================================================================
7041
7042/// Configuration for relationship strength calculation.
7043#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7044pub struct RelationshipStrengthSchemaConfig {
7045    /// Enable relationship strength calculation.
7046    #[serde(default)]
7047    pub enabled: bool,
7048
7049    /// Calculation weights.
7050    #[serde(default)]
7051    pub calculation: StrengthCalculationSchemaConfig,
7052
7053    /// Strength thresholds for classification.
7054    #[serde(default)]
7055    pub thresholds: StrengthThresholdsSchemaConfig,
7056}
7057
7058/// Strength calculation weights configuration.
7059#[derive(Debug, Clone, Serialize, Deserialize)]
7060pub struct StrengthCalculationSchemaConfig {
7061    /// Weight for transaction volume (default: 0.30).
7062    #[serde(default = "default_volume_weight")]
7063    pub transaction_volume_weight: f64,
7064
7065    /// Weight for transaction count (default: 0.25).
7066    #[serde(default = "default_count_weight")]
7067    pub transaction_count_weight: f64,
7068
7069    /// Weight for relationship duration (default: 0.20).
7070    #[serde(default = "default_duration_weight")]
7071    pub relationship_duration_weight: f64,
7072
7073    /// Weight for recency (default: 0.15).
7074    #[serde(default = "default_recency_weight")]
7075    pub recency_weight: f64,
7076
7077    /// Weight for mutual connections (default: 0.10).
7078    #[serde(default = "default_mutual_weight")]
7079    pub mutual_connections_weight: f64,
7080
7081    /// Recency half-life in days (default: 90).
7082    #[serde(default = "default_recency_half_life")]
7083    pub recency_half_life_days: u32,
7084}
7085
7086fn default_volume_weight() -> f64 {
7087    0.30
7088}
7089
7090fn default_count_weight() -> f64 {
7091    0.25
7092}
7093
7094fn default_duration_weight() -> f64 {
7095    0.20
7096}
7097
7098fn default_recency_weight() -> f64 {
7099    0.15
7100}
7101
7102fn default_mutual_weight() -> f64 {
7103    0.10
7104}
7105
7106fn default_recency_half_life() -> u32 {
7107    90
7108}
7109
7110impl Default for StrengthCalculationSchemaConfig {
7111    fn default() -> Self {
7112        Self {
7113            transaction_volume_weight: 0.30,
7114            transaction_count_weight: 0.25,
7115            relationship_duration_weight: 0.20,
7116            recency_weight: 0.15,
7117            mutual_connections_weight: 0.10,
7118            recency_half_life_days: 90,
7119        }
7120    }
7121}
7122
7123/// Strength thresholds for relationship classification.
7124#[derive(Debug, Clone, Serialize, Deserialize)]
7125pub struct StrengthThresholdsSchemaConfig {
7126    /// Threshold for strong relationships (default: 0.7).
7127    #[serde(default = "default_strong_threshold")]
7128    pub strong: f64,
7129
7130    /// Threshold for moderate relationships (default: 0.4).
7131    #[serde(default = "default_moderate_threshold")]
7132    pub moderate: f64,
7133
7134    /// Threshold for weak relationships (default: 0.1).
7135    #[serde(default = "default_weak_threshold")]
7136    pub weak: f64,
7137}
7138
7139fn default_strong_threshold() -> f64 {
7140    0.7
7141}
7142
7143fn default_moderate_threshold() -> f64 {
7144    0.4
7145}
7146
7147fn default_weak_threshold() -> f64 {
7148    0.1
7149}
7150
7151impl Default for StrengthThresholdsSchemaConfig {
7152    fn default() -> Self {
7153        Self {
7154            strong: 0.7,
7155            moderate: 0.4,
7156            weak: 0.1,
7157        }
7158    }
7159}
7160
7161// =============================================================================
7162// Cross-Process Links Configuration
7163// =============================================================================
7164
7165/// Configuration for cross-process linkages.
7166#[derive(Debug, Clone, Serialize, Deserialize)]
7167pub struct CrossProcessLinksSchemaConfig {
7168    /// Enable cross-process link generation.
7169    #[serde(default)]
7170    pub enabled: bool,
7171
7172    /// Enable inventory links between P2P and O2C.
7173    #[serde(default = "default_true")]
7174    pub inventory_p2p_o2c: bool,
7175
7176    /// Enable payment to bank reconciliation links.
7177    #[serde(default = "default_true")]
7178    pub payment_bank_reconciliation: bool,
7179
7180    /// Enable intercompany bilateral matching.
7181    #[serde(default = "default_true")]
7182    pub intercompany_bilateral: bool,
7183
7184    /// Percentage of GR/Deliveries to link via inventory (0.0 - 1.0).
7185    #[serde(default = "default_inventory_link_rate")]
7186    pub inventory_link_rate: f64,
7187}
7188
7189fn default_inventory_link_rate() -> f64 {
7190    0.30
7191}
7192
7193impl Default for CrossProcessLinksSchemaConfig {
7194    fn default() -> Self {
7195        Self {
7196            enabled: false,
7197            inventory_p2p_o2c: true,
7198            payment_bank_reconciliation: true,
7199            intercompany_bilateral: true,
7200            inventory_link_rate: 0.30,
7201        }
7202    }
7203}
7204
7205// =============================================================================
7206// Organizational Events Configuration
7207// =============================================================================
7208
7209/// Configuration for organizational events (acquisitions, divestitures, etc.).
7210#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7211pub struct OrganizationalEventsSchemaConfig {
7212    /// Enable organizational events.
7213    #[serde(default)]
7214    pub enabled: bool,
7215
7216    /// Effect blending mode (multiplicative, additive, maximum, minimum).
7217    #[serde(default)]
7218    pub effect_blending: EffectBlendingModeConfig,
7219
7220    /// Organizational events (acquisitions, divestitures, reorganizations, etc.).
7221    #[serde(default)]
7222    pub events: Vec<OrganizationalEventSchemaConfig>,
7223
7224    /// Process evolution events.
7225    #[serde(default)]
7226    pub process_evolution: Vec<ProcessEvolutionSchemaConfig>,
7227
7228    /// Technology transition events.
7229    #[serde(default)]
7230    pub technology_transitions: Vec<TechnologyTransitionSchemaConfig>,
7231}
7232
7233/// Effect blending mode for combining multiple event effects.
7234#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7235#[serde(rename_all = "snake_case")]
7236pub enum EffectBlendingModeConfig {
7237    /// Multiply effects together.
7238    #[default]
7239    Multiplicative,
7240    /// Add effects together.
7241    Additive,
7242    /// Take the maximum effect.
7243    Maximum,
7244    /// Take the minimum effect.
7245    Minimum,
7246}
7247
7248/// Configuration for a single organizational event.
7249#[derive(Debug, Clone, Serialize, Deserialize)]
7250pub struct OrganizationalEventSchemaConfig {
7251    /// Event ID.
7252    pub id: String,
7253
7254    /// Event type and configuration.
7255    pub event_type: OrganizationalEventTypeSchemaConfig,
7256
7257    /// Effective date.
7258    pub effective_date: String,
7259
7260    /// Transition duration in months.
7261    #[serde(default = "default_org_transition_months")]
7262    pub transition_months: u32,
7263
7264    /// Description.
7265    #[serde(default)]
7266    pub description: Option<String>,
7267}
7268
7269fn default_org_transition_months() -> u32 {
7270    6
7271}
7272
7273/// Organizational event type configuration.
7274#[derive(Debug, Clone, Serialize, Deserialize)]
7275#[serde(tag = "type", rename_all = "snake_case")]
7276pub enum OrganizationalEventTypeSchemaConfig {
7277    /// Acquisition event.
7278    Acquisition {
7279        /// Acquired entity code.
7280        acquired_entity: String,
7281        /// Volume increase multiplier.
7282        #[serde(default = "default_acquisition_volume")]
7283        volume_increase: f64,
7284        /// Integration error rate.
7285        #[serde(default = "default_acquisition_error")]
7286        integration_error_rate: f64,
7287        /// Parallel posting days.
7288        #[serde(default = "default_parallel_days")]
7289        parallel_posting_days: u32,
7290    },
7291    /// Divestiture event.
7292    Divestiture {
7293        /// Divested entity code.
7294        divested_entity: String,
7295        /// Volume reduction factor.
7296        #[serde(default = "default_divestiture_volume")]
7297        volume_reduction: f64,
7298        /// Remove entity from generation.
7299        #[serde(default = "default_true_val")]
7300        remove_entity: bool,
7301    },
7302    /// Reorganization event.
7303    Reorganization {
7304        /// Cost center remapping.
7305        #[serde(default)]
7306        cost_center_remapping: std::collections::HashMap<String, String>,
7307        /// Transition error rate.
7308        #[serde(default = "default_reorg_error")]
7309        transition_error_rate: f64,
7310    },
7311    /// Leadership change event.
7312    LeadershipChange {
7313        /// Role that changed.
7314        role: String,
7315        /// Policy changes.
7316        #[serde(default)]
7317        policy_changes: Vec<String>,
7318    },
7319    /// Workforce reduction event.
7320    WorkforceReduction {
7321        /// Reduction percentage.
7322        #[serde(default = "default_workforce_reduction")]
7323        reduction_percent: f64,
7324        /// Error rate increase.
7325        #[serde(default = "default_workforce_error")]
7326        error_rate_increase: f64,
7327    },
7328    /// Merger event.
7329    Merger {
7330        /// Merged entity code.
7331        merged_entity: String,
7332        /// Volume increase multiplier.
7333        #[serde(default = "default_merger_volume")]
7334        volume_increase: f64,
7335    },
7336}
7337
7338fn default_acquisition_volume() -> f64 {
7339    1.35
7340}
7341
7342fn default_acquisition_error() -> f64 {
7343    0.05
7344}
7345
7346fn default_parallel_days() -> u32 {
7347    30
7348}
7349
7350fn default_divestiture_volume() -> f64 {
7351    0.70
7352}
7353
7354fn default_true_val() -> bool {
7355    true
7356}
7357
7358fn default_reorg_error() -> f64 {
7359    0.04
7360}
7361
7362fn default_workforce_reduction() -> f64 {
7363    0.10
7364}
7365
7366fn default_workforce_error() -> f64 {
7367    0.05
7368}
7369
7370fn default_merger_volume() -> f64 {
7371    1.80
7372}
7373
7374/// Configuration for a process evolution event.
7375#[derive(Debug, Clone, Serialize, Deserialize)]
7376pub struct ProcessEvolutionSchemaConfig {
7377    /// Event ID.
7378    pub id: String,
7379
7380    /// Event type.
7381    pub event_type: ProcessEvolutionTypeSchemaConfig,
7382
7383    /// Effective date.
7384    pub effective_date: String,
7385
7386    /// Description.
7387    #[serde(default)]
7388    pub description: Option<String>,
7389}
7390
7391/// Process evolution type configuration.
7392#[derive(Debug, Clone, Serialize, Deserialize)]
7393#[serde(tag = "type", rename_all = "snake_case")]
7394pub enum ProcessEvolutionTypeSchemaConfig {
7395    /// Process automation.
7396    ProcessAutomation {
7397        /// Process name.
7398        process_name: String,
7399        /// Manual rate before.
7400        #[serde(default = "default_manual_before")]
7401        manual_rate_before: f64,
7402        /// Manual rate after.
7403        #[serde(default = "default_manual_after")]
7404        manual_rate_after: f64,
7405    },
7406    /// Approval workflow change.
7407    ApprovalWorkflowChange {
7408        /// Description.
7409        description: String,
7410    },
7411    /// Control enhancement.
7412    ControlEnhancement {
7413        /// Control ID.
7414        control_id: String,
7415        /// Error reduction.
7416        #[serde(default = "default_error_reduction")]
7417        error_reduction: f64,
7418    },
7419}
7420
7421fn default_manual_before() -> f64 {
7422    0.80
7423}
7424
7425fn default_manual_after() -> f64 {
7426    0.15
7427}
7428
7429fn default_error_reduction() -> f64 {
7430    0.02
7431}
7432
7433/// Configuration for a technology transition event.
7434#[derive(Debug, Clone, Serialize, Deserialize)]
7435pub struct TechnologyTransitionSchemaConfig {
7436    /// Event ID.
7437    pub id: String,
7438
7439    /// Event type.
7440    pub event_type: TechnologyTransitionTypeSchemaConfig,
7441
7442    /// Description.
7443    #[serde(default)]
7444    pub description: Option<String>,
7445}
7446
7447/// Technology transition type configuration.
7448#[derive(Debug, Clone, Serialize, Deserialize)]
7449#[serde(tag = "type", rename_all = "snake_case")]
7450pub enum TechnologyTransitionTypeSchemaConfig {
7451    /// ERP migration.
7452    ErpMigration {
7453        /// Source system.
7454        source_system: String,
7455        /// Target system.
7456        target_system: String,
7457        /// Cutover date.
7458        cutover_date: String,
7459        /// Stabilization end date.
7460        stabilization_end: String,
7461        /// Duplicate rate during migration.
7462        #[serde(default = "default_erp_duplicate_rate")]
7463        duplicate_rate: f64,
7464        /// Format mismatch rate.
7465        #[serde(default = "default_format_mismatch")]
7466        format_mismatch_rate: f64,
7467    },
7468    /// Module implementation.
7469    ModuleImplementation {
7470        /// Module name.
7471        module_name: String,
7472        /// Go-live date.
7473        go_live_date: String,
7474    },
7475}
7476
7477fn default_erp_duplicate_rate() -> f64 {
7478    0.02
7479}
7480
7481fn default_format_mismatch() -> f64 {
7482    0.03
7483}
7484
7485// =============================================================================
7486// Behavioral Drift Configuration
7487// =============================================================================
7488
7489/// Configuration for behavioral drift (vendor, customer, employee behavior).
7490#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7491pub struct BehavioralDriftSchemaConfig {
7492    /// Enable behavioral drift.
7493    #[serde(default)]
7494    pub enabled: bool,
7495
7496    /// Vendor behavior drift.
7497    #[serde(default)]
7498    pub vendor_behavior: VendorBehaviorSchemaConfig,
7499
7500    /// Customer behavior drift.
7501    #[serde(default)]
7502    pub customer_behavior: CustomerBehaviorSchemaConfig,
7503
7504    /// Employee behavior drift.
7505    #[serde(default)]
7506    pub employee_behavior: EmployeeBehaviorSchemaConfig,
7507
7508    /// Collective behavior drift.
7509    #[serde(default)]
7510    pub collective: CollectiveBehaviorSchemaConfig,
7511}
7512
7513/// Vendor behavior drift configuration.
7514#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7515pub struct VendorBehaviorSchemaConfig {
7516    /// Payment terms drift.
7517    #[serde(default)]
7518    pub payment_terms_drift: PaymentTermsDriftSchemaConfig,
7519
7520    /// Quality drift.
7521    #[serde(default)]
7522    pub quality_drift: QualityDriftSchemaConfig,
7523}
7524
7525/// Payment terms drift configuration.
7526#[derive(Debug, Clone, Serialize, Deserialize)]
7527pub struct PaymentTermsDriftSchemaConfig {
7528    /// Extension rate per year (days).
7529    #[serde(default = "default_extension_rate")]
7530    pub extension_rate_per_year: f64,
7531
7532    /// Economic sensitivity.
7533    #[serde(default = "default_economic_sensitivity")]
7534    pub economic_sensitivity: f64,
7535}
7536
7537fn default_extension_rate() -> f64 {
7538    2.5
7539}
7540
7541fn default_economic_sensitivity() -> f64 {
7542    1.0
7543}
7544
7545impl Default for PaymentTermsDriftSchemaConfig {
7546    fn default() -> Self {
7547        Self {
7548            extension_rate_per_year: 2.5,
7549            economic_sensitivity: 1.0,
7550        }
7551    }
7552}
7553
7554/// Quality drift configuration.
7555#[derive(Debug, Clone, Serialize, Deserialize)]
7556pub struct QualityDriftSchemaConfig {
7557    /// New vendor improvement rate (per year).
7558    #[serde(default = "default_improvement_rate")]
7559    pub new_vendor_improvement_rate: f64,
7560
7561    /// Complacency decline rate (per year after first year).
7562    #[serde(default = "default_decline_rate")]
7563    pub complacency_decline_rate: f64,
7564}
7565
7566fn default_improvement_rate() -> f64 {
7567    0.02
7568}
7569
7570fn default_decline_rate() -> f64 {
7571    0.01
7572}
7573
7574impl Default for QualityDriftSchemaConfig {
7575    fn default() -> Self {
7576        Self {
7577            new_vendor_improvement_rate: 0.02,
7578            complacency_decline_rate: 0.01,
7579        }
7580    }
7581}
7582
7583/// Customer behavior drift configuration.
7584#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7585pub struct CustomerBehaviorSchemaConfig {
7586    /// Payment drift.
7587    #[serde(default)]
7588    pub payment_drift: CustomerPaymentDriftSchemaConfig,
7589
7590    /// Order drift.
7591    #[serde(default)]
7592    pub order_drift: OrderDriftSchemaConfig,
7593}
7594
7595/// Customer payment drift configuration.
7596#[derive(Debug, Clone, Serialize, Deserialize)]
7597pub struct CustomerPaymentDriftSchemaConfig {
7598    /// Days extension during downturn (min, max).
7599    #[serde(default = "default_downturn_extension")]
7600    pub downturn_days_extension: (u32, u32),
7601
7602    /// Bad debt increase during downturn.
7603    #[serde(default = "default_bad_debt_increase")]
7604    pub downturn_bad_debt_increase: f64,
7605}
7606
7607fn default_downturn_extension() -> (u32, u32) {
7608    (5, 15)
7609}
7610
7611fn default_bad_debt_increase() -> f64 {
7612    0.02
7613}
7614
7615impl Default for CustomerPaymentDriftSchemaConfig {
7616    fn default() -> Self {
7617        Self {
7618            downturn_days_extension: (5, 15),
7619            downturn_bad_debt_increase: 0.02,
7620        }
7621    }
7622}
7623
7624/// Order drift configuration.
7625#[derive(Debug, Clone, Serialize, Deserialize)]
7626pub struct OrderDriftSchemaConfig {
7627    /// Digital shift rate (per year).
7628    #[serde(default = "default_digital_shift")]
7629    pub digital_shift_rate: f64,
7630}
7631
7632fn default_digital_shift() -> f64 {
7633    0.05
7634}
7635
7636impl Default for OrderDriftSchemaConfig {
7637    fn default() -> Self {
7638        Self {
7639            digital_shift_rate: 0.05,
7640        }
7641    }
7642}
7643
7644/// Employee behavior drift configuration.
7645#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7646pub struct EmployeeBehaviorSchemaConfig {
7647    /// Approval drift.
7648    #[serde(default)]
7649    pub approval_drift: ApprovalDriftSchemaConfig,
7650
7651    /// Error drift.
7652    #[serde(default)]
7653    pub error_drift: ErrorDriftSchemaConfig,
7654}
7655
7656/// Approval drift configuration.
7657#[derive(Debug, Clone, Serialize, Deserialize)]
7658pub struct ApprovalDriftSchemaConfig {
7659    /// EOM intensity increase per year.
7660    #[serde(default = "default_eom_intensity")]
7661    pub eom_intensity_increase_per_year: f64,
7662
7663    /// Rubber stamp volume threshold.
7664    #[serde(default = "default_rubber_stamp")]
7665    pub rubber_stamp_volume_threshold: u32,
7666}
7667
7668fn default_eom_intensity() -> f64 {
7669    0.05
7670}
7671
7672fn default_rubber_stamp() -> u32 {
7673    50
7674}
7675
7676impl Default for ApprovalDriftSchemaConfig {
7677    fn default() -> Self {
7678        Self {
7679            eom_intensity_increase_per_year: 0.05,
7680            rubber_stamp_volume_threshold: 50,
7681        }
7682    }
7683}
7684
7685/// Error drift configuration.
7686#[derive(Debug, Clone, Serialize, Deserialize)]
7687pub struct ErrorDriftSchemaConfig {
7688    /// New employee error rate.
7689    #[serde(default = "default_new_error")]
7690    pub new_employee_error_rate: f64,
7691
7692    /// Learning curve months.
7693    #[serde(default = "default_learning_months")]
7694    pub learning_curve_months: u32,
7695}
7696
7697fn default_new_error() -> f64 {
7698    0.08
7699}
7700
7701fn default_learning_months() -> u32 {
7702    6
7703}
7704
7705impl Default for ErrorDriftSchemaConfig {
7706    fn default() -> Self {
7707        Self {
7708            new_employee_error_rate: 0.08,
7709            learning_curve_months: 6,
7710        }
7711    }
7712}
7713
7714/// Collective behavior drift configuration.
7715#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7716pub struct CollectiveBehaviorSchemaConfig {
7717    /// Automation adoption configuration.
7718    #[serde(default)]
7719    pub automation_adoption: AutomationAdoptionSchemaConfig,
7720}
7721
7722/// Automation adoption configuration.
7723#[derive(Debug, Clone, Serialize, Deserialize)]
7724pub struct AutomationAdoptionSchemaConfig {
7725    /// Enable S-curve adoption model.
7726    #[serde(default)]
7727    pub s_curve_enabled: bool,
7728
7729    /// Adoption midpoint in months.
7730    #[serde(default = "default_midpoint")]
7731    pub adoption_midpoint_months: u32,
7732
7733    /// Steepness of adoption curve.
7734    #[serde(default = "default_steepness")]
7735    pub steepness: f64,
7736}
7737
7738fn default_midpoint() -> u32 {
7739    24
7740}
7741
7742fn default_steepness() -> f64 {
7743    0.15
7744}
7745
7746impl Default for AutomationAdoptionSchemaConfig {
7747    fn default() -> Self {
7748        Self {
7749            s_curve_enabled: false,
7750            adoption_midpoint_months: 24,
7751            steepness: 0.15,
7752        }
7753    }
7754}
7755
7756// =============================================================================
7757// Market Drift Configuration
7758// =============================================================================
7759
7760/// Configuration for market drift (economic cycles, commodities, price shocks).
7761#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7762pub struct MarketDriftSchemaConfig {
7763    /// Enable market drift.
7764    #[serde(default)]
7765    pub enabled: bool,
7766
7767    /// Economic cycle configuration.
7768    #[serde(default)]
7769    pub economic_cycle: MarketEconomicCycleSchemaConfig,
7770
7771    /// Industry-specific cycles.
7772    #[serde(default)]
7773    pub industry_cycles: std::collections::HashMap<String, IndustryCycleSchemaConfig>,
7774
7775    /// Commodity drift configuration.
7776    #[serde(default)]
7777    pub commodities: CommoditiesSchemaConfig,
7778}
7779
7780/// Market economic cycle configuration.
7781#[derive(Debug, Clone, Serialize, Deserialize)]
7782pub struct MarketEconomicCycleSchemaConfig {
7783    /// Enable economic cycle.
7784    #[serde(default)]
7785    pub enabled: bool,
7786
7787    /// Cycle type.
7788    #[serde(default)]
7789    pub cycle_type: CycleTypeSchemaConfig,
7790
7791    /// Cycle period in months.
7792    #[serde(default = "default_market_cycle_period")]
7793    pub period_months: u32,
7794
7795    /// Amplitude.
7796    #[serde(default = "default_market_amplitude")]
7797    pub amplitude: f64,
7798
7799    /// Recession configuration.
7800    #[serde(default)]
7801    pub recession: RecessionSchemaConfig,
7802}
7803
7804fn default_market_cycle_period() -> u32 {
7805    48
7806}
7807
7808fn default_market_amplitude() -> f64 {
7809    0.15
7810}
7811
7812impl Default for MarketEconomicCycleSchemaConfig {
7813    fn default() -> Self {
7814        Self {
7815            enabled: false,
7816            cycle_type: CycleTypeSchemaConfig::Sinusoidal,
7817            period_months: 48,
7818            amplitude: 0.15,
7819            recession: RecessionSchemaConfig::default(),
7820        }
7821    }
7822}
7823
7824/// Cycle type configuration.
7825#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7826#[serde(rename_all = "snake_case")]
7827pub enum CycleTypeSchemaConfig {
7828    /// Sinusoidal cycle.
7829    #[default]
7830    Sinusoidal,
7831    /// Asymmetric cycle.
7832    Asymmetric,
7833    /// Mean-reverting cycle.
7834    MeanReverting,
7835}
7836
7837/// Recession configuration.
7838#[derive(Debug, Clone, Serialize, Deserialize)]
7839pub struct RecessionSchemaConfig {
7840    /// Enable recession simulation.
7841    #[serde(default)]
7842    pub enabled: bool,
7843
7844    /// Probability per year.
7845    #[serde(default = "default_recession_prob")]
7846    pub probability_per_year: f64,
7847
7848    /// Severity.
7849    #[serde(default)]
7850    pub severity: RecessionSeveritySchemaConfig,
7851
7852    /// Specific recession periods.
7853    #[serde(default)]
7854    pub recession_periods: Vec<RecessionPeriodSchemaConfig>,
7855}
7856
7857fn default_recession_prob() -> f64 {
7858    0.10
7859}
7860
7861impl Default for RecessionSchemaConfig {
7862    fn default() -> Self {
7863        Self {
7864            enabled: false,
7865            probability_per_year: 0.10,
7866            severity: RecessionSeveritySchemaConfig::Moderate,
7867            recession_periods: Vec::new(),
7868        }
7869    }
7870}
7871
7872/// Recession severity configuration.
7873#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7874#[serde(rename_all = "snake_case")]
7875pub enum RecessionSeveritySchemaConfig {
7876    /// Mild recession.
7877    Mild,
7878    /// Moderate recession.
7879    #[default]
7880    Moderate,
7881    /// Severe recession.
7882    Severe,
7883}
7884
7885/// Recession period configuration.
7886#[derive(Debug, Clone, Serialize, Deserialize)]
7887pub struct RecessionPeriodSchemaConfig {
7888    /// Start month.
7889    pub start_month: u32,
7890    /// Duration in months.
7891    pub duration_months: u32,
7892}
7893
7894/// Industry cycle configuration.
7895#[derive(Debug, Clone, Serialize, Deserialize)]
7896pub struct IndustryCycleSchemaConfig {
7897    /// Period in months.
7898    #[serde(default = "default_industry_period")]
7899    pub period_months: u32,
7900
7901    /// Amplitude.
7902    #[serde(default = "default_industry_amp")]
7903    pub amplitude: f64,
7904}
7905
7906fn default_industry_period() -> u32 {
7907    36
7908}
7909
7910fn default_industry_amp() -> f64 {
7911    0.20
7912}
7913
7914/// Commodities drift configuration.
7915#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7916pub struct CommoditiesSchemaConfig {
7917    /// Enable commodity drift.
7918    #[serde(default)]
7919    pub enabled: bool,
7920
7921    /// Commodity items.
7922    #[serde(default)]
7923    pub items: Vec<CommodityItemSchemaConfig>,
7924}
7925
7926/// Commodity item configuration.
7927#[derive(Debug, Clone, Serialize, Deserialize)]
7928pub struct CommodityItemSchemaConfig {
7929    /// Commodity name.
7930    pub name: String,
7931
7932    /// Volatility.
7933    #[serde(default = "default_volatility")]
7934    pub volatility: f64,
7935
7936    /// COGS pass-through.
7937    #[serde(default)]
7938    pub cogs_pass_through: f64,
7939
7940    /// Overhead pass-through.
7941    #[serde(default)]
7942    pub overhead_pass_through: f64,
7943}
7944
7945fn default_volatility() -> f64 {
7946    0.20
7947}
7948
7949// =============================================================================
7950// Drift Labeling Configuration
7951// =============================================================================
7952
7953/// Configuration for drift ground truth labeling.
7954#[derive(Debug, Clone, Serialize, Deserialize, Default)]
7955pub struct DriftLabelingSchemaConfig {
7956    /// Enable drift labeling.
7957    #[serde(default)]
7958    pub enabled: bool,
7959
7960    /// Statistical drift labeling.
7961    #[serde(default)]
7962    pub statistical: StatisticalDriftLabelingSchemaConfig,
7963
7964    /// Categorical drift labeling.
7965    #[serde(default)]
7966    pub categorical: CategoricalDriftLabelingSchemaConfig,
7967
7968    /// Temporal drift labeling.
7969    #[serde(default)]
7970    pub temporal: TemporalDriftLabelingSchemaConfig,
7971
7972    /// Regulatory calendar preset.
7973    #[serde(default)]
7974    pub regulatory_calendar_preset: Option<String>,
7975}
7976
7977/// Statistical drift labeling configuration.
7978#[derive(Debug, Clone, Serialize, Deserialize)]
7979pub struct StatisticalDriftLabelingSchemaConfig {
7980    /// Enable statistical drift labeling.
7981    #[serde(default = "default_true_val")]
7982    pub enabled: bool,
7983
7984    /// Minimum magnitude threshold.
7985    #[serde(default = "default_min_magnitude")]
7986    pub min_magnitude_threshold: f64,
7987}
7988
7989fn default_min_magnitude() -> f64 {
7990    0.05
7991}
7992
7993impl Default for StatisticalDriftLabelingSchemaConfig {
7994    fn default() -> Self {
7995        Self {
7996            enabled: true,
7997            min_magnitude_threshold: 0.05,
7998        }
7999    }
8000}
8001
8002/// Categorical drift labeling configuration.
8003#[derive(Debug, Clone, Serialize, Deserialize)]
8004pub struct CategoricalDriftLabelingSchemaConfig {
8005    /// Enable categorical drift labeling.
8006    #[serde(default = "default_true_val")]
8007    pub enabled: bool,
8008}
8009
8010impl Default for CategoricalDriftLabelingSchemaConfig {
8011    fn default() -> Self {
8012        Self { enabled: true }
8013    }
8014}
8015
8016/// Temporal drift labeling configuration.
8017#[derive(Debug, Clone, Serialize, Deserialize)]
8018pub struct TemporalDriftLabelingSchemaConfig {
8019    /// Enable temporal drift labeling.
8020    #[serde(default = "default_true_val")]
8021    pub enabled: bool,
8022}
8023
8024impl Default for TemporalDriftLabelingSchemaConfig {
8025    fn default() -> Self {
8026        Self { enabled: true }
8027    }
8028}
8029
8030// =============================================================================
8031// Enhanced Anomaly Injection Configuration
8032// =============================================================================
8033
8034/// Enhanced anomaly injection configuration.
8035///
8036/// Provides comprehensive anomaly injection capabilities including:
8037/// - Multi-stage fraud schemes (embezzlement, revenue manipulation, kickbacks)
8038/// - Correlated anomaly injection (co-occurrence patterns, error cascades)
8039/// - Near-miss generation for false positive reduction
8040/// - Detection difficulty classification
8041/// - Context-aware injection based on entity behavior
8042#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8043pub struct EnhancedAnomalyConfig {
8044    /// Enable enhanced anomaly injection.
8045    #[serde(default)]
8046    pub enabled: bool,
8047
8048    /// Base anomaly rates.
8049    #[serde(default)]
8050    pub rates: AnomalyRateConfig,
8051
8052    /// Multi-stage fraud scheme configuration.
8053    #[serde(default)]
8054    pub multi_stage_schemes: MultiStageSchemeConfig,
8055
8056    /// Correlated anomaly injection configuration.
8057    #[serde(default)]
8058    pub correlated_injection: CorrelatedInjectionConfig,
8059
8060    /// Near-miss generation configuration.
8061    #[serde(default)]
8062    pub near_miss: NearMissConfig,
8063
8064    /// Detection difficulty classification configuration.
8065    #[serde(default)]
8066    pub difficulty_classification: DifficultyClassificationConfig,
8067
8068    /// Context-aware injection configuration.
8069    #[serde(default)]
8070    pub context_aware: ContextAwareConfig,
8071
8072    /// Enhanced labeling configuration.
8073    #[serde(default)]
8074    pub labeling: EnhancedLabelingConfig,
8075}
8076
8077/// Base anomaly rate configuration.
8078#[derive(Debug, Clone, Serialize, Deserialize)]
8079pub struct AnomalyRateConfig {
8080    /// Total anomaly rate (0.0 to 1.0).
8081    #[serde(default = "default_total_anomaly_rate")]
8082    pub total_rate: f64,
8083
8084    /// Fraud anomaly rate.
8085    #[serde(default = "default_fraud_anomaly_rate")]
8086    pub fraud_rate: f64,
8087
8088    /// Error anomaly rate.
8089    #[serde(default = "default_error_anomaly_rate")]
8090    pub error_rate: f64,
8091
8092    /// Process issue rate.
8093    #[serde(default = "default_process_anomaly_rate")]
8094    pub process_rate: f64,
8095}
8096
8097fn default_total_anomaly_rate() -> f64 {
8098    0.03
8099}
8100fn default_fraud_anomaly_rate() -> f64 {
8101    0.01
8102}
8103fn default_error_anomaly_rate() -> f64 {
8104    0.015
8105}
8106fn default_process_anomaly_rate() -> f64 {
8107    0.005
8108}
8109
8110impl Default for AnomalyRateConfig {
8111    fn default() -> Self {
8112        Self {
8113            total_rate: default_total_anomaly_rate(),
8114            fraud_rate: default_fraud_anomaly_rate(),
8115            error_rate: default_error_anomaly_rate(),
8116            process_rate: default_process_anomaly_rate(),
8117        }
8118    }
8119}
8120
8121/// Multi-stage fraud scheme configuration.
8122#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8123pub struct MultiStageSchemeConfig {
8124    /// Enable multi-stage fraud schemes.
8125    #[serde(default)]
8126    pub enabled: bool,
8127
8128    /// Embezzlement scheme configuration.
8129    #[serde(default)]
8130    pub embezzlement: EmbezzlementSchemeConfig,
8131
8132    /// Revenue manipulation scheme configuration.
8133    #[serde(default)]
8134    pub revenue_manipulation: RevenueManipulationSchemeConfig,
8135
8136    /// Vendor kickback scheme configuration.
8137    #[serde(default)]
8138    pub kickback: KickbackSchemeConfig,
8139}
8140
8141/// Embezzlement scheme configuration.
8142#[derive(Debug, Clone, Serialize, Deserialize)]
8143pub struct EmbezzlementSchemeConfig {
8144    /// Probability of starting an embezzlement scheme per perpetrator per year.
8145    #[serde(default = "default_embezzlement_probability")]
8146    pub probability: f64,
8147
8148    /// Testing stage configuration.
8149    #[serde(default)]
8150    pub testing_stage: SchemeStageConfig,
8151
8152    /// Escalation stage configuration.
8153    #[serde(default)]
8154    pub escalation_stage: SchemeStageConfig,
8155
8156    /// Acceleration stage configuration.
8157    #[serde(default)]
8158    pub acceleration_stage: SchemeStageConfig,
8159
8160    /// Desperation stage configuration.
8161    #[serde(default)]
8162    pub desperation_stage: SchemeStageConfig,
8163}
8164
8165fn default_embezzlement_probability() -> f64 {
8166    0.02
8167}
8168
8169impl Default for EmbezzlementSchemeConfig {
8170    fn default() -> Self {
8171        Self {
8172            probability: default_embezzlement_probability(),
8173            testing_stage: SchemeStageConfig {
8174                duration_months: 2,
8175                amount_min: 100.0,
8176                amount_max: 500.0,
8177                transaction_count_min: 2,
8178                transaction_count_max: 5,
8179                difficulty: "hard".to_string(),
8180            },
8181            escalation_stage: SchemeStageConfig {
8182                duration_months: 6,
8183                amount_min: 500.0,
8184                amount_max: 2000.0,
8185                transaction_count_min: 3,
8186                transaction_count_max: 8,
8187                difficulty: "moderate".to_string(),
8188            },
8189            acceleration_stage: SchemeStageConfig {
8190                duration_months: 3,
8191                amount_min: 2000.0,
8192                amount_max: 10000.0,
8193                transaction_count_min: 5,
8194                transaction_count_max: 12,
8195                difficulty: "easy".to_string(),
8196            },
8197            desperation_stage: SchemeStageConfig {
8198                duration_months: 1,
8199                amount_min: 10000.0,
8200                amount_max: 50000.0,
8201                transaction_count_min: 3,
8202                transaction_count_max: 6,
8203                difficulty: "trivial".to_string(),
8204            },
8205        }
8206    }
8207}
8208
8209/// Revenue manipulation scheme configuration.
8210#[derive(Debug, Clone, Serialize, Deserialize)]
8211pub struct RevenueManipulationSchemeConfig {
8212    /// Probability of starting a revenue manipulation scheme per period.
8213    #[serde(default = "default_revenue_manipulation_probability")]
8214    pub probability: f64,
8215
8216    /// Early revenue recognition inflation target (Q4).
8217    #[serde(default = "default_early_recognition_target")]
8218    pub early_recognition_target: f64,
8219
8220    /// Expense deferral inflation target (Q1).
8221    #[serde(default = "default_expense_deferral_target")]
8222    pub expense_deferral_target: f64,
8223
8224    /// Reserve release inflation target (Q2).
8225    #[serde(default = "default_reserve_release_target")]
8226    pub reserve_release_target: f64,
8227
8228    /// Channel stuffing inflation target (Q4).
8229    #[serde(default = "default_channel_stuffing_target")]
8230    pub channel_stuffing_target: f64,
8231}
8232
8233fn default_revenue_manipulation_probability() -> f64 {
8234    0.01
8235}
8236fn default_early_recognition_target() -> f64 {
8237    0.02
8238}
8239fn default_expense_deferral_target() -> f64 {
8240    0.03
8241}
8242fn default_reserve_release_target() -> f64 {
8243    0.02
8244}
8245fn default_channel_stuffing_target() -> f64 {
8246    0.05
8247}
8248
8249impl Default for RevenueManipulationSchemeConfig {
8250    fn default() -> Self {
8251        Self {
8252            probability: default_revenue_manipulation_probability(),
8253            early_recognition_target: default_early_recognition_target(),
8254            expense_deferral_target: default_expense_deferral_target(),
8255            reserve_release_target: default_reserve_release_target(),
8256            channel_stuffing_target: default_channel_stuffing_target(),
8257        }
8258    }
8259}
8260
8261/// Vendor kickback scheme configuration.
8262#[derive(Debug, Clone, Serialize, Deserialize)]
8263pub struct KickbackSchemeConfig {
8264    /// Probability of starting a kickback scheme.
8265    #[serde(default = "default_kickback_probability")]
8266    pub probability: f64,
8267
8268    /// Minimum price inflation percentage.
8269    #[serde(default = "default_kickback_inflation_min")]
8270    pub inflation_min: f64,
8271
8272    /// Maximum price inflation percentage.
8273    #[serde(default = "default_kickback_inflation_max")]
8274    pub inflation_max: f64,
8275
8276    /// Kickback percentage (of inflation).
8277    #[serde(default = "default_kickback_percent")]
8278    pub kickback_percent: f64,
8279
8280    /// Setup duration in months.
8281    #[serde(default = "default_kickback_setup_months")]
8282    pub setup_months: u32,
8283
8284    /// Main operation duration in months.
8285    #[serde(default = "default_kickback_operation_months")]
8286    pub operation_months: u32,
8287}
8288
8289fn default_kickback_probability() -> f64 {
8290    0.01
8291}
8292fn default_kickback_inflation_min() -> f64 {
8293    0.10
8294}
8295fn default_kickback_inflation_max() -> f64 {
8296    0.25
8297}
8298fn default_kickback_percent() -> f64 {
8299    0.50
8300}
8301fn default_kickback_setup_months() -> u32 {
8302    3
8303}
8304fn default_kickback_operation_months() -> u32 {
8305    12
8306}
8307
8308impl Default for KickbackSchemeConfig {
8309    fn default() -> Self {
8310        Self {
8311            probability: default_kickback_probability(),
8312            inflation_min: default_kickback_inflation_min(),
8313            inflation_max: default_kickback_inflation_max(),
8314            kickback_percent: default_kickback_percent(),
8315            setup_months: default_kickback_setup_months(),
8316            operation_months: default_kickback_operation_months(),
8317        }
8318    }
8319}
8320
8321/// Individual scheme stage configuration.
8322#[derive(Debug, Clone, Serialize, Deserialize)]
8323pub struct SchemeStageConfig {
8324    /// Duration in months.
8325    pub duration_months: u32,
8326
8327    /// Minimum transaction amount.
8328    pub amount_min: f64,
8329
8330    /// Maximum transaction amount.
8331    pub amount_max: f64,
8332
8333    /// Minimum number of transactions.
8334    pub transaction_count_min: u32,
8335
8336    /// Maximum number of transactions.
8337    pub transaction_count_max: u32,
8338
8339    /// Detection difficulty level (trivial, easy, moderate, hard, expert).
8340    pub difficulty: String,
8341}
8342
8343impl Default for SchemeStageConfig {
8344    fn default() -> Self {
8345        Self {
8346            duration_months: 3,
8347            amount_min: 100.0,
8348            amount_max: 1000.0,
8349            transaction_count_min: 2,
8350            transaction_count_max: 10,
8351            difficulty: "moderate".to_string(),
8352        }
8353    }
8354}
8355
8356/// Correlated anomaly injection configuration.
8357#[derive(Debug, Clone, Serialize, Deserialize)]
8358pub struct CorrelatedInjectionConfig {
8359    /// Enable correlated anomaly injection.
8360    #[serde(default)]
8361    pub enabled: bool,
8362
8363    /// Enable fraud concealment co-occurrence patterns.
8364    #[serde(default = "default_true_val")]
8365    pub fraud_concealment: bool,
8366
8367    /// Enable error cascade patterns.
8368    #[serde(default = "default_true_val")]
8369    pub error_cascade: bool,
8370
8371    /// Enable temporal clustering (period-end spikes).
8372    #[serde(default = "default_true_val")]
8373    pub temporal_clustering: bool,
8374
8375    /// Temporal clustering configuration.
8376    #[serde(default)]
8377    pub temporal_clustering_config: TemporalClusteringConfig,
8378
8379    /// Co-occurrence patterns.
8380    #[serde(default)]
8381    pub co_occurrence_patterns: Vec<CoOccurrencePatternConfig>,
8382}
8383
8384impl Default for CorrelatedInjectionConfig {
8385    fn default() -> Self {
8386        Self {
8387            enabled: false,
8388            fraud_concealment: true,
8389            error_cascade: true,
8390            temporal_clustering: true,
8391            temporal_clustering_config: TemporalClusteringConfig::default(),
8392            co_occurrence_patterns: Vec::new(),
8393        }
8394    }
8395}
8396
8397/// Temporal clustering configuration.
8398#[derive(Debug, Clone, Serialize, Deserialize)]
8399pub struct TemporalClusteringConfig {
8400    /// Period-end error multiplier.
8401    #[serde(default = "default_period_end_multiplier")]
8402    pub period_end_multiplier: f64,
8403
8404    /// Number of business days before period end to apply multiplier.
8405    #[serde(default = "default_period_end_days")]
8406    pub period_end_days: u32,
8407
8408    /// Quarter-end additional multiplier.
8409    #[serde(default = "default_quarter_end_multiplier")]
8410    pub quarter_end_multiplier: f64,
8411
8412    /// Year-end additional multiplier.
8413    #[serde(default = "default_year_end_multiplier")]
8414    pub year_end_multiplier: f64,
8415}
8416
8417fn default_period_end_multiplier() -> f64 {
8418    2.5
8419}
8420fn default_period_end_days() -> u32 {
8421    5
8422}
8423fn default_quarter_end_multiplier() -> f64 {
8424    1.5
8425}
8426fn default_year_end_multiplier() -> f64 {
8427    2.0
8428}
8429
8430impl Default for TemporalClusteringConfig {
8431    fn default() -> Self {
8432        Self {
8433            period_end_multiplier: default_period_end_multiplier(),
8434            period_end_days: default_period_end_days(),
8435            quarter_end_multiplier: default_quarter_end_multiplier(),
8436            year_end_multiplier: default_year_end_multiplier(),
8437        }
8438    }
8439}
8440
8441/// Co-occurrence pattern configuration.
8442#[derive(Debug, Clone, Serialize, Deserialize)]
8443pub struct CoOccurrencePatternConfig {
8444    /// Pattern name.
8445    pub name: String,
8446
8447    /// Primary anomaly type that triggers the pattern.
8448    pub primary_type: String,
8449
8450    /// Correlated anomalies.
8451    pub correlated: Vec<CorrelatedAnomalyConfig>,
8452}
8453
8454/// Correlated anomaly configuration.
8455#[derive(Debug, Clone, Serialize, Deserialize)]
8456pub struct CorrelatedAnomalyConfig {
8457    /// Anomaly type.
8458    pub anomaly_type: String,
8459
8460    /// Probability of occurrence (0.0 to 1.0).
8461    pub probability: f64,
8462
8463    /// Minimum lag in days.
8464    pub lag_days_min: i32,
8465
8466    /// Maximum lag in days.
8467    pub lag_days_max: i32,
8468}
8469
8470/// Near-miss generation configuration.
8471#[derive(Debug, Clone, Serialize, Deserialize)]
8472pub struct NearMissConfig {
8473    /// Enable near-miss generation.
8474    #[serde(default)]
8475    pub enabled: bool,
8476
8477    /// Proportion of "anomalies" that are actually near-misses (0.0 to 1.0).
8478    #[serde(default = "default_near_miss_proportion")]
8479    pub proportion: f64,
8480
8481    /// Enable near-duplicate pattern.
8482    #[serde(default = "default_true_val")]
8483    pub near_duplicate: bool,
8484
8485    /// Near-duplicate date difference range in days.
8486    #[serde(default)]
8487    pub near_duplicate_days: NearDuplicateDaysConfig,
8488
8489    /// Enable threshold proximity pattern.
8490    #[serde(default = "default_true_val")]
8491    pub threshold_proximity: bool,
8492
8493    /// Threshold proximity range (e.g., 0.90-0.99 of threshold).
8494    #[serde(default)]
8495    pub threshold_proximity_range: ThresholdProximityRangeConfig,
8496
8497    /// Enable unusual but legitimate patterns.
8498    #[serde(default = "default_true_val")]
8499    pub unusual_legitimate: bool,
8500
8501    /// Types of unusual legitimate patterns to generate.
8502    #[serde(default = "default_unusual_legitimate_types")]
8503    pub unusual_legitimate_types: Vec<String>,
8504
8505    /// Enable corrected error patterns.
8506    #[serde(default = "default_true_val")]
8507    pub corrected_errors: bool,
8508
8509    /// Corrected error correction lag range in days.
8510    #[serde(default)]
8511    pub corrected_error_lag: CorrectedErrorLagConfig,
8512}
8513
8514fn default_near_miss_proportion() -> f64 {
8515    0.30
8516}
8517
8518fn default_unusual_legitimate_types() -> Vec<String> {
8519    vec![
8520        "year_end_bonus".to_string(),
8521        "contract_prepayment".to_string(),
8522        "insurance_claim".to_string(),
8523        "settlement_payment".to_string(),
8524    ]
8525}
8526
8527impl Default for NearMissConfig {
8528    fn default() -> Self {
8529        Self {
8530            enabled: false,
8531            proportion: default_near_miss_proportion(),
8532            near_duplicate: true,
8533            near_duplicate_days: NearDuplicateDaysConfig::default(),
8534            threshold_proximity: true,
8535            threshold_proximity_range: ThresholdProximityRangeConfig::default(),
8536            unusual_legitimate: true,
8537            unusual_legitimate_types: default_unusual_legitimate_types(),
8538            corrected_errors: true,
8539            corrected_error_lag: CorrectedErrorLagConfig::default(),
8540        }
8541    }
8542}
8543
8544/// Near-duplicate days configuration.
8545#[derive(Debug, Clone, Serialize, Deserialize)]
8546pub struct NearDuplicateDaysConfig {
8547    /// Minimum days apart.
8548    #[serde(default = "default_near_duplicate_min")]
8549    pub min: u32,
8550
8551    /// Maximum days apart.
8552    #[serde(default = "default_near_duplicate_max")]
8553    pub max: u32,
8554}
8555
8556fn default_near_duplicate_min() -> u32 {
8557    1
8558}
8559fn default_near_duplicate_max() -> u32 {
8560    3
8561}
8562
8563impl Default for NearDuplicateDaysConfig {
8564    fn default() -> Self {
8565        Self {
8566            min: default_near_duplicate_min(),
8567            max: default_near_duplicate_max(),
8568        }
8569    }
8570}
8571
8572/// Threshold proximity range configuration.
8573#[derive(Debug, Clone, Serialize, Deserialize)]
8574pub struct ThresholdProximityRangeConfig {
8575    /// Minimum proximity (e.g., 0.90 = 90% of threshold).
8576    #[serde(default = "default_threshold_proximity_min")]
8577    pub min: f64,
8578
8579    /// Maximum proximity (e.g., 0.99 = 99% of threshold).
8580    #[serde(default = "default_threshold_proximity_max")]
8581    pub max: f64,
8582}
8583
8584fn default_threshold_proximity_min() -> f64 {
8585    0.90
8586}
8587fn default_threshold_proximity_max() -> f64 {
8588    0.99
8589}
8590
8591impl Default for ThresholdProximityRangeConfig {
8592    fn default() -> Self {
8593        Self {
8594            min: default_threshold_proximity_min(),
8595            max: default_threshold_proximity_max(),
8596        }
8597    }
8598}
8599
8600/// Corrected error lag configuration.
8601#[derive(Debug, Clone, Serialize, Deserialize)]
8602pub struct CorrectedErrorLagConfig {
8603    /// Minimum correction lag in days.
8604    #[serde(default = "default_corrected_error_lag_min")]
8605    pub min: u32,
8606
8607    /// Maximum correction lag in days.
8608    #[serde(default = "default_corrected_error_lag_max")]
8609    pub max: u32,
8610}
8611
8612fn default_corrected_error_lag_min() -> u32 {
8613    1
8614}
8615fn default_corrected_error_lag_max() -> u32 {
8616    5
8617}
8618
8619impl Default for CorrectedErrorLagConfig {
8620    fn default() -> Self {
8621        Self {
8622            min: default_corrected_error_lag_min(),
8623            max: default_corrected_error_lag_max(),
8624        }
8625    }
8626}
8627
8628/// Detection difficulty classification configuration.
8629#[derive(Debug, Clone, Serialize, Deserialize)]
8630pub struct DifficultyClassificationConfig {
8631    /// Enable detection difficulty classification.
8632    #[serde(default)]
8633    pub enabled: bool,
8634
8635    /// Target distribution of difficulty levels.
8636    #[serde(default)]
8637    pub target_distribution: DifficultyDistributionConfig,
8638}
8639
8640impl Default for DifficultyClassificationConfig {
8641    fn default() -> Self {
8642        Self {
8643            enabled: true,
8644            target_distribution: DifficultyDistributionConfig::default(),
8645        }
8646    }
8647}
8648
8649/// Target distribution of detection difficulty levels.
8650#[derive(Debug, Clone, Serialize, Deserialize)]
8651pub struct DifficultyDistributionConfig {
8652    /// Proportion of trivial anomalies (expected 99% detection).
8653    #[serde(default = "default_difficulty_trivial")]
8654    pub trivial: f64,
8655
8656    /// Proportion of easy anomalies (expected 90% detection).
8657    #[serde(default = "default_difficulty_easy")]
8658    pub easy: f64,
8659
8660    /// Proportion of moderate anomalies (expected 70% detection).
8661    #[serde(default = "default_difficulty_moderate")]
8662    pub moderate: f64,
8663
8664    /// Proportion of hard anomalies (expected 40% detection).
8665    #[serde(default = "default_difficulty_hard")]
8666    pub hard: f64,
8667
8668    /// Proportion of expert anomalies (expected 15% detection).
8669    #[serde(default = "default_difficulty_expert")]
8670    pub expert: f64,
8671}
8672
8673fn default_difficulty_trivial() -> f64 {
8674    0.15
8675}
8676fn default_difficulty_easy() -> f64 {
8677    0.25
8678}
8679fn default_difficulty_moderate() -> f64 {
8680    0.30
8681}
8682fn default_difficulty_hard() -> f64 {
8683    0.20
8684}
8685fn default_difficulty_expert() -> f64 {
8686    0.10
8687}
8688
8689impl Default for DifficultyDistributionConfig {
8690    fn default() -> Self {
8691        Self {
8692            trivial: default_difficulty_trivial(),
8693            easy: default_difficulty_easy(),
8694            moderate: default_difficulty_moderate(),
8695            hard: default_difficulty_hard(),
8696            expert: default_difficulty_expert(),
8697        }
8698    }
8699}
8700
8701/// Context-aware injection configuration.
8702#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8703pub struct ContextAwareConfig {
8704    /// Enable context-aware injection.
8705    #[serde(default)]
8706    pub enabled: bool,
8707
8708    /// Vendor-specific anomaly rules.
8709    #[serde(default)]
8710    pub vendor_rules: VendorAnomalyRulesConfig,
8711
8712    /// Employee-specific anomaly rules.
8713    #[serde(default)]
8714    pub employee_rules: EmployeeAnomalyRulesConfig,
8715
8716    /// Account-specific anomaly rules.
8717    #[serde(default)]
8718    pub account_rules: AccountAnomalyRulesConfig,
8719
8720    /// Behavioral baseline configuration.
8721    #[serde(default)]
8722    pub behavioral_baseline: BehavioralBaselineConfig,
8723}
8724
8725/// Vendor-specific anomaly rules configuration.
8726#[derive(Debug, Clone, Serialize, Deserialize)]
8727pub struct VendorAnomalyRulesConfig {
8728    /// Error rate multiplier for new vendors (< threshold days).
8729    #[serde(default = "default_new_vendor_multiplier")]
8730    pub new_vendor_error_multiplier: f64,
8731
8732    /// Days threshold for "new" vendor classification.
8733    #[serde(default = "default_new_vendor_threshold")]
8734    pub new_vendor_threshold_days: u32,
8735
8736    /// Error rate multiplier for international vendors.
8737    #[serde(default = "default_international_multiplier")]
8738    pub international_error_multiplier: f64,
8739
8740    /// Strategic vendor anomaly types (may differ from general vendors).
8741    #[serde(default = "default_strategic_vendor_types")]
8742    pub strategic_vendor_anomaly_types: Vec<String>,
8743}
8744
8745fn default_new_vendor_multiplier() -> f64 {
8746    2.5
8747}
8748fn default_new_vendor_threshold() -> u32 {
8749    90
8750}
8751fn default_international_multiplier() -> f64 {
8752    1.5
8753}
8754fn default_strategic_vendor_types() -> Vec<String> {
8755    vec![
8756        "pricing_dispute".to_string(),
8757        "contract_violation".to_string(),
8758    ]
8759}
8760
8761impl Default for VendorAnomalyRulesConfig {
8762    fn default() -> Self {
8763        Self {
8764            new_vendor_error_multiplier: default_new_vendor_multiplier(),
8765            new_vendor_threshold_days: default_new_vendor_threshold(),
8766            international_error_multiplier: default_international_multiplier(),
8767            strategic_vendor_anomaly_types: default_strategic_vendor_types(),
8768        }
8769    }
8770}
8771
8772/// Employee-specific anomaly rules configuration.
8773#[derive(Debug, Clone, Serialize, Deserialize)]
8774pub struct EmployeeAnomalyRulesConfig {
8775    /// Error rate for new employees (< threshold days).
8776    #[serde(default = "default_new_employee_rate")]
8777    pub new_employee_error_rate: f64,
8778
8779    /// Days threshold for "new" employee classification.
8780    #[serde(default = "default_new_employee_threshold")]
8781    pub new_employee_threshold_days: u32,
8782
8783    /// Transaction volume threshold for fatigue errors.
8784    #[serde(default = "default_volume_fatigue_threshold")]
8785    pub volume_fatigue_threshold: u32,
8786
8787    /// Error rate multiplier when primary approver is absent.
8788    #[serde(default = "default_coverage_multiplier")]
8789    pub coverage_error_multiplier: f64,
8790}
8791
8792fn default_new_employee_rate() -> f64 {
8793    0.05
8794}
8795fn default_new_employee_threshold() -> u32 {
8796    180
8797}
8798fn default_volume_fatigue_threshold() -> u32 {
8799    50
8800}
8801fn default_coverage_multiplier() -> f64 {
8802    1.8
8803}
8804
8805impl Default for EmployeeAnomalyRulesConfig {
8806    fn default() -> Self {
8807        Self {
8808            new_employee_error_rate: default_new_employee_rate(),
8809            new_employee_threshold_days: default_new_employee_threshold(),
8810            volume_fatigue_threshold: default_volume_fatigue_threshold(),
8811            coverage_error_multiplier: default_coverage_multiplier(),
8812        }
8813    }
8814}
8815
8816/// Account-specific anomaly rules configuration.
8817#[derive(Debug, Clone, Serialize, Deserialize)]
8818pub struct AccountAnomalyRulesConfig {
8819    /// Error rate multiplier for high-risk accounts.
8820    #[serde(default = "default_high_risk_multiplier")]
8821    pub high_risk_account_multiplier: f64,
8822
8823    /// Account codes considered high-risk.
8824    #[serde(default = "default_high_risk_accounts")]
8825    pub high_risk_accounts: Vec<String>,
8826
8827    /// Error rate multiplier for suspense accounts.
8828    #[serde(default = "default_suspense_multiplier")]
8829    pub suspense_account_multiplier: f64,
8830
8831    /// Account codes considered suspense accounts.
8832    #[serde(default = "default_suspense_accounts")]
8833    pub suspense_accounts: Vec<String>,
8834
8835    /// Error rate multiplier for intercompany accounts.
8836    #[serde(default = "default_intercompany_multiplier")]
8837    pub intercompany_account_multiplier: f64,
8838}
8839
8840fn default_high_risk_multiplier() -> f64 {
8841    2.0
8842}
8843fn default_high_risk_accounts() -> Vec<String> {
8844    vec![
8845        "1100".to_string(), // AR Control
8846        "2000".to_string(), // AP Control
8847        "3000".to_string(), // Cash
8848    ]
8849}
8850fn default_suspense_multiplier() -> f64 {
8851    3.0
8852}
8853fn default_suspense_accounts() -> Vec<String> {
8854    vec!["9999".to_string(), "9998".to_string()]
8855}
8856fn default_intercompany_multiplier() -> f64 {
8857    1.5
8858}
8859
8860impl Default for AccountAnomalyRulesConfig {
8861    fn default() -> Self {
8862        Self {
8863            high_risk_account_multiplier: default_high_risk_multiplier(),
8864            high_risk_accounts: default_high_risk_accounts(),
8865            suspense_account_multiplier: default_suspense_multiplier(),
8866            suspense_accounts: default_suspense_accounts(),
8867            intercompany_account_multiplier: default_intercompany_multiplier(),
8868        }
8869    }
8870}
8871
8872/// Behavioral baseline configuration.
8873#[derive(Debug, Clone, Serialize, Deserialize)]
8874pub struct BehavioralBaselineConfig {
8875    /// Enable behavioral baseline tracking.
8876    #[serde(default)]
8877    pub enabled: bool,
8878
8879    /// Number of days to build baseline from.
8880    #[serde(default = "default_baseline_period")]
8881    pub baseline_period_days: u32,
8882
8883    /// Standard deviation threshold for amount anomalies.
8884    #[serde(default = "default_deviation_threshold")]
8885    pub deviation_threshold_std: f64,
8886
8887    /// Standard deviation threshold for frequency anomalies.
8888    #[serde(default = "default_frequency_deviation")]
8889    pub frequency_deviation_threshold: f64,
8890}
8891
8892fn default_baseline_period() -> u32 {
8893    90
8894}
8895fn default_deviation_threshold() -> f64 {
8896    3.0
8897}
8898fn default_frequency_deviation() -> f64 {
8899    2.0
8900}
8901
8902impl Default for BehavioralBaselineConfig {
8903    fn default() -> Self {
8904        Self {
8905            enabled: false,
8906            baseline_period_days: default_baseline_period(),
8907            deviation_threshold_std: default_deviation_threshold(),
8908            frequency_deviation_threshold: default_frequency_deviation(),
8909        }
8910    }
8911}
8912
8913/// Enhanced labeling configuration.
8914#[derive(Debug, Clone, Serialize, Deserialize)]
8915pub struct EnhancedLabelingConfig {
8916    /// Enable severity scoring.
8917    #[serde(default = "default_true_val")]
8918    pub severity_scoring: bool,
8919
8920    /// Enable difficulty classification.
8921    #[serde(default = "default_true_val")]
8922    pub difficulty_classification: bool,
8923
8924    /// Materiality thresholds for severity classification.
8925    #[serde(default)]
8926    pub materiality_thresholds: MaterialityThresholdsConfig,
8927}
8928
8929impl Default for EnhancedLabelingConfig {
8930    fn default() -> Self {
8931        Self {
8932            severity_scoring: true,
8933            difficulty_classification: true,
8934            materiality_thresholds: MaterialityThresholdsConfig::default(),
8935        }
8936    }
8937}
8938
8939/// Materiality thresholds configuration.
8940#[derive(Debug, Clone, Serialize, Deserialize)]
8941pub struct MaterialityThresholdsConfig {
8942    /// Threshold for trivial impact (as percentage of total).
8943    #[serde(default = "default_materiality_trivial")]
8944    pub trivial: f64,
8945
8946    /// Threshold for immaterial impact.
8947    #[serde(default = "default_materiality_immaterial")]
8948    pub immaterial: f64,
8949
8950    /// Threshold for material impact.
8951    #[serde(default = "default_materiality_material")]
8952    pub material: f64,
8953
8954    /// Threshold for highly material impact.
8955    #[serde(default = "default_materiality_highly_material")]
8956    pub highly_material: f64,
8957}
8958
8959fn default_materiality_trivial() -> f64 {
8960    0.001
8961}
8962fn default_materiality_immaterial() -> f64 {
8963    0.01
8964}
8965fn default_materiality_material() -> f64 {
8966    0.05
8967}
8968fn default_materiality_highly_material() -> f64 {
8969    0.10
8970}
8971
8972impl Default for MaterialityThresholdsConfig {
8973    fn default() -> Self {
8974        Self {
8975            trivial: default_materiality_trivial(),
8976            immaterial: default_materiality_immaterial(),
8977            material: default_materiality_material(),
8978            highly_material: default_materiality_highly_material(),
8979        }
8980    }
8981}
8982
8983// =============================================================================
8984// Industry-Specific Configuration
8985// =============================================================================
8986
8987/// Industry-specific transaction and anomaly generation configuration.
8988///
8989/// This configuration enables generation of industry-authentic:
8990/// - Transaction types with appropriate terminology
8991/// - Master data (BOM, routings, clinical codes, etc.)
8992/// - Industry-specific anomaly patterns
8993/// - Regulatory framework compliance
8994#[derive(Debug, Clone, Serialize, Deserialize, Default)]
8995pub struct IndustrySpecificConfig {
8996    /// Enable industry-specific generation.
8997    #[serde(default)]
8998    pub enabled: bool,
8999
9000    /// Manufacturing industry settings.
9001    #[serde(default)]
9002    pub manufacturing: ManufacturingConfig,
9003
9004    /// Retail industry settings.
9005    #[serde(default)]
9006    pub retail: RetailConfig,
9007
9008    /// Healthcare industry settings.
9009    #[serde(default)]
9010    pub healthcare: HealthcareConfig,
9011
9012    /// Technology industry settings.
9013    #[serde(default)]
9014    pub technology: TechnologyConfig,
9015
9016    /// Financial services industry settings.
9017    #[serde(default)]
9018    pub financial_services: FinancialServicesConfig,
9019
9020    /// Professional services industry settings.
9021    #[serde(default)]
9022    pub professional_services: ProfessionalServicesConfig,
9023}
9024
9025/// Manufacturing industry configuration.
9026#[derive(Debug, Clone, Serialize, Deserialize)]
9027pub struct ManufacturingConfig {
9028    /// Enable manufacturing-specific generation.
9029    #[serde(default)]
9030    pub enabled: bool,
9031
9032    /// Bill of Materials depth (typical: 3-7).
9033    #[serde(default = "default_bom_depth")]
9034    pub bom_depth: u32,
9035
9036    /// Whether to use just-in-time inventory.
9037    #[serde(default)]
9038    pub just_in_time: bool,
9039
9040    /// Production order types to generate.
9041    #[serde(default = "default_production_order_types")]
9042    pub production_order_types: Vec<String>,
9043
9044    /// Quality framework (ISO_9001, Six_Sigma, etc.).
9045    #[serde(default)]
9046    pub quality_framework: Option<String>,
9047
9048    /// Number of supplier tiers to model (1-3).
9049    #[serde(default = "default_supplier_tiers")]
9050    pub supplier_tiers: u32,
9051
9052    /// Standard cost update frequency.
9053    #[serde(default = "default_cost_frequency")]
9054    pub standard_cost_frequency: String,
9055
9056    /// Target yield rate (0.95-0.99 typical).
9057    #[serde(default = "default_yield_rate")]
9058    pub target_yield_rate: f64,
9059
9060    /// Scrap percentage threshold for alerts.
9061    #[serde(default = "default_scrap_threshold")]
9062    pub scrap_alert_threshold: f64,
9063
9064    /// Manufacturing anomaly injection rates.
9065    #[serde(default)]
9066    pub anomaly_rates: ManufacturingAnomalyRates,
9067}
9068
9069fn default_bom_depth() -> u32 {
9070    4
9071}
9072
9073fn default_production_order_types() -> Vec<String> {
9074    vec![
9075        "standard".to_string(),
9076        "rework".to_string(),
9077        "prototype".to_string(),
9078    ]
9079}
9080
9081fn default_supplier_tiers() -> u32 {
9082    2
9083}
9084
9085fn default_cost_frequency() -> String {
9086    "quarterly".to_string()
9087}
9088
9089fn default_yield_rate() -> f64 {
9090    0.97
9091}
9092
9093fn default_scrap_threshold() -> f64 {
9094    0.03
9095}
9096
9097impl Default for ManufacturingConfig {
9098    fn default() -> Self {
9099        Self {
9100            enabled: false,
9101            bom_depth: default_bom_depth(),
9102            just_in_time: false,
9103            production_order_types: default_production_order_types(),
9104            quality_framework: Some("ISO_9001".to_string()),
9105            supplier_tiers: default_supplier_tiers(),
9106            standard_cost_frequency: default_cost_frequency(),
9107            target_yield_rate: default_yield_rate(),
9108            scrap_alert_threshold: default_scrap_threshold(),
9109            anomaly_rates: ManufacturingAnomalyRates::default(),
9110        }
9111    }
9112}
9113
9114/// Manufacturing anomaly injection rates.
9115#[derive(Debug, Clone, Serialize, Deserialize)]
9116pub struct ManufacturingAnomalyRates {
9117    /// Yield manipulation rate.
9118    #[serde(default = "default_mfg_yield_rate")]
9119    pub yield_manipulation: f64,
9120
9121    /// Labor misallocation rate.
9122    #[serde(default = "default_mfg_labor_rate")]
9123    pub labor_misallocation: f64,
9124
9125    /// Phantom production rate.
9126    #[serde(default = "default_mfg_phantom_rate")]
9127    pub phantom_production: f64,
9128
9129    /// Standard cost manipulation rate.
9130    #[serde(default = "default_mfg_cost_rate")]
9131    pub standard_cost_manipulation: f64,
9132
9133    /// Inventory fraud rate.
9134    #[serde(default = "default_mfg_inventory_rate")]
9135    pub inventory_fraud: f64,
9136}
9137
9138fn default_mfg_yield_rate() -> f64 {
9139    0.015
9140}
9141
9142fn default_mfg_labor_rate() -> f64 {
9143    0.02
9144}
9145
9146fn default_mfg_phantom_rate() -> f64 {
9147    0.005
9148}
9149
9150fn default_mfg_cost_rate() -> f64 {
9151    0.01
9152}
9153
9154fn default_mfg_inventory_rate() -> f64 {
9155    0.008
9156}
9157
9158impl Default for ManufacturingAnomalyRates {
9159    fn default() -> Self {
9160        Self {
9161            yield_manipulation: default_mfg_yield_rate(),
9162            labor_misallocation: default_mfg_labor_rate(),
9163            phantom_production: default_mfg_phantom_rate(),
9164            standard_cost_manipulation: default_mfg_cost_rate(),
9165            inventory_fraud: default_mfg_inventory_rate(),
9166        }
9167    }
9168}
9169
9170/// Retail industry configuration.
9171#[derive(Debug, Clone, Serialize, Deserialize)]
9172pub struct RetailConfig {
9173    /// Enable retail-specific generation.
9174    #[serde(default)]
9175    pub enabled: bool,
9176
9177    /// Store type distribution.
9178    #[serde(default)]
9179    pub store_types: RetailStoreTypeConfig,
9180
9181    /// Average daily transactions per store.
9182    #[serde(default = "default_retail_daily_txns")]
9183    pub avg_daily_transactions: u32,
9184
9185    /// Enable loss prevention tracking.
9186    #[serde(default = "default_true")]
9187    pub loss_prevention: bool,
9188
9189    /// Shrinkage rate (0.01-0.03 typical).
9190    #[serde(default = "default_shrinkage_rate")]
9191    pub shrinkage_rate: f64,
9192
9193    /// Retail anomaly injection rates.
9194    #[serde(default)]
9195    pub anomaly_rates: RetailAnomalyRates,
9196}
9197
9198fn default_retail_daily_txns() -> u32 {
9199    500
9200}
9201
9202fn default_shrinkage_rate() -> f64 {
9203    0.015
9204}
9205
9206impl Default for RetailConfig {
9207    fn default() -> Self {
9208        Self {
9209            enabled: false,
9210            store_types: RetailStoreTypeConfig::default(),
9211            avg_daily_transactions: default_retail_daily_txns(),
9212            loss_prevention: true,
9213            shrinkage_rate: default_shrinkage_rate(),
9214            anomaly_rates: RetailAnomalyRates::default(),
9215        }
9216    }
9217}
9218
9219/// Retail store type distribution.
9220#[derive(Debug, Clone, Serialize, Deserialize)]
9221pub struct RetailStoreTypeConfig {
9222    /// Percentage of flagship stores.
9223    #[serde(default = "default_flagship_pct")]
9224    pub flagship: f64,
9225
9226    /// Percentage of regional stores.
9227    #[serde(default = "default_regional_pct")]
9228    pub regional: f64,
9229
9230    /// Percentage of outlet stores.
9231    #[serde(default = "default_outlet_pct")]
9232    pub outlet: f64,
9233
9234    /// Percentage of e-commerce.
9235    #[serde(default = "default_ecommerce_pct")]
9236    pub ecommerce: f64,
9237}
9238
9239fn default_flagship_pct() -> f64 {
9240    0.10
9241}
9242
9243fn default_regional_pct() -> f64 {
9244    0.50
9245}
9246
9247fn default_outlet_pct() -> f64 {
9248    0.25
9249}
9250
9251fn default_ecommerce_pct() -> f64 {
9252    0.15
9253}
9254
9255impl Default for RetailStoreTypeConfig {
9256    fn default() -> Self {
9257        Self {
9258            flagship: default_flagship_pct(),
9259            regional: default_regional_pct(),
9260            outlet: default_outlet_pct(),
9261            ecommerce: default_ecommerce_pct(),
9262        }
9263    }
9264}
9265
9266/// Retail anomaly injection rates.
9267#[derive(Debug, Clone, Serialize, Deserialize)]
9268pub struct RetailAnomalyRates {
9269    /// Sweethearting rate.
9270    #[serde(default = "default_sweethearting_rate")]
9271    pub sweethearting: f64,
9272
9273    /// Skimming rate.
9274    #[serde(default = "default_skimming_rate")]
9275    pub skimming: f64,
9276
9277    /// Refund fraud rate.
9278    #[serde(default = "default_refund_fraud_rate")]
9279    pub refund_fraud: f64,
9280
9281    /// Void abuse rate.
9282    #[serde(default = "default_void_abuse_rate")]
9283    pub void_abuse: f64,
9284
9285    /// Gift card fraud rate.
9286    #[serde(default = "default_gift_card_rate")]
9287    pub gift_card_fraud: f64,
9288
9289    /// Vendor kickback rate.
9290    #[serde(default = "default_retail_kickback_rate")]
9291    pub vendor_kickback: f64,
9292}
9293
9294fn default_sweethearting_rate() -> f64 {
9295    0.02
9296}
9297
9298fn default_skimming_rate() -> f64 {
9299    0.005
9300}
9301
9302fn default_refund_fraud_rate() -> f64 {
9303    0.015
9304}
9305
9306fn default_void_abuse_rate() -> f64 {
9307    0.01
9308}
9309
9310fn default_gift_card_rate() -> f64 {
9311    0.008
9312}
9313
9314fn default_retail_kickback_rate() -> f64 {
9315    0.003
9316}
9317
9318impl Default for RetailAnomalyRates {
9319    fn default() -> Self {
9320        Self {
9321            sweethearting: default_sweethearting_rate(),
9322            skimming: default_skimming_rate(),
9323            refund_fraud: default_refund_fraud_rate(),
9324            void_abuse: default_void_abuse_rate(),
9325            gift_card_fraud: default_gift_card_rate(),
9326            vendor_kickback: default_retail_kickback_rate(),
9327        }
9328    }
9329}
9330
9331/// Healthcare industry configuration.
9332#[derive(Debug, Clone, Serialize, Deserialize)]
9333pub struct HealthcareConfig {
9334    /// Enable healthcare-specific generation.
9335    #[serde(default)]
9336    pub enabled: bool,
9337
9338    /// Healthcare facility type.
9339    #[serde(default = "default_facility_type")]
9340    pub facility_type: String,
9341
9342    /// Payer mix distribution.
9343    #[serde(default)]
9344    pub payer_mix: HealthcarePayerMix,
9345
9346    /// Coding systems enabled.
9347    #[serde(default)]
9348    pub coding_systems: HealthcareCodingSystems,
9349
9350    /// Healthcare compliance settings.
9351    #[serde(default)]
9352    pub compliance: HealthcareComplianceConfig,
9353
9354    /// Average daily encounters.
9355    #[serde(default = "default_daily_encounters")]
9356    pub avg_daily_encounters: u32,
9357
9358    /// Average charges per encounter.
9359    #[serde(default = "default_charges_per_encounter")]
9360    pub avg_charges_per_encounter: u32,
9361
9362    /// Denial rate (0.0-1.0).
9363    #[serde(default = "default_hc_denial_rate")]
9364    pub denial_rate: f64,
9365
9366    /// Bad debt rate (0.0-1.0).
9367    #[serde(default = "default_hc_bad_debt_rate")]
9368    pub bad_debt_rate: f64,
9369
9370    /// Charity care rate (0.0-1.0).
9371    #[serde(default = "default_hc_charity_care_rate")]
9372    pub charity_care_rate: f64,
9373
9374    /// Healthcare anomaly injection rates.
9375    #[serde(default)]
9376    pub anomaly_rates: HealthcareAnomalyRates,
9377}
9378
9379fn default_facility_type() -> String {
9380    "hospital".to_string()
9381}
9382
9383fn default_daily_encounters() -> u32 {
9384    150
9385}
9386
9387fn default_charges_per_encounter() -> u32 {
9388    8
9389}
9390
9391fn default_hc_denial_rate() -> f64 {
9392    0.05
9393}
9394
9395fn default_hc_bad_debt_rate() -> f64 {
9396    0.03
9397}
9398
9399fn default_hc_charity_care_rate() -> f64 {
9400    0.02
9401}
9402
9403impl Default for HealthcareConfig {
9404    fn default() -> Self {
9405        Self {
9406            enabled: false,
9407            facility_type: default_facility_type(),
9408            payer_mix: HealthcarePayerMix::default(),
9409            coding_systems: HealthcareCodingSystems::default(),
9410            compliance: HealthcareComplianceConfig::default(),
9411            avg_daily_encounters: default_daily_encounters(),
9412            avg_charges_per_encounter: default_charges_per_encounter(),
9413            denial_rate: default_hc_denial_rate(),
9414            bad_debt_rate: default_hc_bad_debt_rate(),
9415            charity_care_rate: default_hc_charity_care_rate(),
9416            anomaly_rates: HealthcareAnomalyRates::default(),
9417        }
9418    }
9419}
9420
9421/// Healthcare payer mix distribution.
9422#[derive(Debug, Clone, Serialize, Deserialize)]
9423pub struct HealthcarePayerMix {
9424    /// Medicare percentage.
9425    #[serde(default = "default_medicare_pct")]
9426    pub medicare: f64,
9427
9428    /// Medicaid percentage.
9429    #[serde(default = "default_medicaid_pct")]
9430    pub medicaid: f64,
9431
9432    /// Commercial insurance percentage.
9433    #[serde(default = "default_commercial_pct")]
9434    pub commercial: f64,
9435
9436    /// Self-pay percentage.
9437    #[serde(default = "default_self_pay_pct")]
9438    pub self_pay: f64,
9439}
9440
9441fn default_medicare_pct() -> f64 {
9442    0.40
9443}
9444
9445fn default_medicaid_pct() -> f64 {
9446    0.20
9447}
9448
9449fn default_commercial_pct() -> f64 {
9450    0.30
9451}
9452
9453fn default_self_pay_pct() -> f64 {
9454    0.10
9455}
9456
9457impl Default for HealthcarePayerMix {
9458    fn default() -> Self {
9459        Self {
9460            medicare: default_medicare_pct(),
9461            medicaid: default_medicaid_pct(),
9462            commercial: default_commercial_pct(),
9463            self_pay: default_self_pay_pct(),
9464        }
9465    }
9466}
9467
9468/// Healthcare coding systems configuration.
9469#[derive(Debug, Clone, Serialize, Deserialize)]
9470pub struct HealthcareCodingSystems {
9471    /// Enable ICD-10 diagnosis coding.
9472    #[serde(default = "default_true")]
9473    pub icd10: bool,
9474
9475    /// Enable CPT procedure coding.
9476    #[serde(default = "default_true")]
9477    pub cpt: bool,
9478
9479    /// Enable DRG grouping.
9480    #[serde(default = "default_true")]
9481    pub drg: bool,
9482
9483    /// Enable HCPCS Level II coding.
9484    #[serde(default = "default_true")]
9485    pub hcpcs: bool,
9486
9487    /// Enable revenue codes.
9488    #[serde(default = "default_true")]
9489    pub revenue_codes: bool,
9490}
9491
9492impl Default for HealthcareCodingSystems {
9493    fn default() -> Self {
9494        Self {
9495            icd10: true,
9496            cpt: true,
9497            drg: true,
9498            hcpcs: true,
9499            revenue_codes: true,
9500        }
9501    }
9502}
9503
9504/// Healthcare compliance configuration.
9505#[derive(Debug, Clone, Serialize, Deserialize)]
9506pub struct HealthcareComplianceConfig {
9507    /// Enable HIPAA compliance.
9508    #[serde(default = "default_true")]
9509    pub hipaa: bool,
9510
9511    /// Enable Stark Law compliance.
9512    #[serde(default = "default_true")]
9513    pub stark_law: bool,
9514
9515    /// Enable Anti-Kickback Statute compliance.
9516    #[serde(default = "default_true")]
9517    pub anti_kickback: bool,
9518
9519    /// Enable False Claims Act compliance.
9520    #[serde(default = "default_true")]
9521    pub false_claims_act: bool,
9522
9523    /// Enable EMTALA compliance (for hospitals).
9524    #[serde(default = "default_true")]
9525    pub emtala: bool,
9526}
9527
9528impl Default for HealthcareComplianceConfig {
9529    fn default() -> Self {
9530        Self {
9531            hipaa: true,
9532            stark_law: true,
9533            anti_kickback: true,
9534            false_claims_act: true,
9535            emtala: true,
9536        }
9537    }
9538}
9539
9540/// Healthcare anomaly injection rates.
9541#[derive(Debug, Clone, Serialize, Deserialize)]
9542pub struct HealthcareAnomalyRates {
9543    /// Upcoding rate.
9544    #[serde(default = "default_upcoding_rate")]
9545    pub upcoding: f64,
9546
9547    /// Unbundling rate.
9548    #[serde(default = "default_unbundling_rate")]
9549    pub unbundling: f64,
9550
9551    /// Phantom billing rate.
9552    #[serde(default = "default_phantom_billing_rate")]
9553    pub phantom_billing: f64,
9554
9555    /// Kickback rate.
9556    #[serde(default = "default_healthcare_kickback_rate")]
9557    pub kickbacks: f64,
9558
9559    /// Duplicate billing rate.
9560    #[serde(default = "default_duplicate_billing_rate")]
9561    pub duplicate_billing: f64,
9562
9563    /// Medical necessity abuse rate.
9564    #[serde(default = "default_med_necessity_rate")]
9565    pub medical_necessity_abuse: f64,
9566}
9567
9568fn default_upcoding_rate() -> f64 {
9569    0.02
9570}
9571
9572fn default_unbundling_rate() -> f64 {
9573    0.015
9574}
9575
9576fn default_phantom_billing_rate() -> f64 {
9577    0.005
9578}
9579
9580fn default_healthcare_kickback_rate() -> f64 {
9581    0.003
9582}
9583
9584fn default_duplicate_billing_rate() -> f64 {
9585    0.008
9586}
9587
9588fn default_med_necessity_rate() -> f64 {
9589    0.01
9590}
9591
9592impl Default for HealthcareAnomalyRates {
9593    fn default() -> Self {
9594        Self {
9595            upcoding: default_upcoding_rate(),
9596            unbundling: default_unbundling_rate(),
9597            phantom_billing: default_phantom_billing_rate(),
9598            kickbacks: default_healthcare_kickback_rate(),
9599            duplicate_billing: default_duplicate_billing_rate(),
9600            medical_necessity_abuse: default_med_necessity_rate(),
9601        }
9602    }
9603}
9604
9605/// Technology industry configuration.
9606#[derive(Debug, Clone, Serialize, Deserialize)]
9607pub struct TechnologyConfig {
9608    /// Enable technology-specific generation.
9609    #[serde(default)]
9610    pub enabled: bool,
9611
9612    /// Revenue model type.
9613    #[serde(default = "default_revenue_model")]
9614    pub revenue_model: String,
9615
9616    /// Subscription revenue percentage (for SaaS).
9617    #[serde(default = "default_subscription_pct")]
9618    pub subscription_revenue_pct: f64,
9619
9620    /// License revenue percentage.
9621    #[serde(default = "default_license_pct")]
9622    pub license_revenue_pct: f64,
9623
9624    /// Services revenue percentage.
9625    #[serde(default = "default_services_pct")]
9626    pub services_revenue_pct: f64,
9627
9628    /// R&D capitalization settings.
9629    #[serde(default)]
9630    pub rd_capitalization: RdCapitalizationConfig,
9631
9632    /// Technology anomaly injection rates.
9633    #[serde(default)]
9634    pub anomaly_rates: TechnologyAnomalyRates,
9635}
9636
9637fn default_revenue_model() -> String {
9638    "saas".to_string()
9639}
9640
9641fn default_subscription_pct() -> f64 {
9642    0.60
9643}
9644
9645fn default_license_pct() -> f64 {
9646    0.25
9647}
9648
9649fn default_services_pct() -> f64 {
9650    0.15
9651}
9652
9653impl Default for TechnologyConfig {
9654    fn default() -> Self {
9655        Self {
9656            enabled: false,
9657            revenue_model: default_revenue_model(),
9658            subscription_revenue_pct: default_subscription_pct(),
9659            license_revenue_pct: default_license_pct(),
9660            services_revenue_pct: default_services_pct(),
9661            rd_capitalization: RdCapitalizationConfig::default(),
9662            anomaly_rates: TechnologyAnomalyRates::default(),
9663        }
9664    }
9665}
9666
9667/// R&D capitalization configuration.
9668#[derive(Debug, Clone, Serialize, Deserialize)]
9669pub struct RdCapitalizationConfig {
9670    /// Enable R&D capitalization.
9671    #[serde(default = "default_true")]
9672    pub enabled: bool,
9673
9674    /// Capitalization rate (0.0-1.0).
9675    #[serde(default = "default_cap_rate")]
9676    pub capitalization_rate: f64,
9677
9678    /// Useful life in years.
9679    #[serde(default = "default_useful_life")]
9680    pub useful_life_years: u32,
9681}
9682
9683fn default_cap_rate() -> f64 {
9684    0.30
9685}
9686
9687fn default_useful_life() -> u32 {
9688    3
9689}
9690
9691impl Default for RdCapitalizationConfig {
9692    fn default() -> Self {
9693        Self {
9694            enabled: true,
9695            capitalization_rate: default_cap_rate(),
9696            useful_life_years: default_useful_life(),
9697        }
9698    }
9699}
9700
9701/// Technology anomaly injection rates.
9702#[derive(Debug, Clone, Serialize, Deserialize)]
9703pub struct TechnologyAnomalyRates {
9704    /// Premature revenue recognition rate.
9705    #[serde(default = "default_premature_rev_rate")]
9706    pub premature_revenue: f64,
9707
9708    /// Side letter abuse rate.
9709    #[serde(default = "default_side_letter_rate")]
9710    pub side_letter_abuse: f64,
9711
9712    /// Channel stuffing rate.
9713    #[serde(default = "default_channel_stuffing_rate")]
9714    pub channel_stuffing: f64,
9715
9716    /// Improper capitalization rate.
9717    #[serde(default = "default_improper_cap_rate")]
9718    pub improper_capitalization: f64,
9719}
9720
9721fn default_premature_rev_rate() -> f64 {
9722    0.015
9723}
9724
9725fn default_side_letter_rate() -> f64 {
9726    0.008
9727}
9728
9729fn default_channel_stuffing_rate() -> f64 {
9730    0.01
9731}
9732
9733fn default_improper_cap_rate() -> f64 {
9734    0.012
9735}
9736
9737impl Default for TechnologyAnomalyRates {
9738    fn default() -> Self {
9739        Self {
9740            premature_revenue: default_premature_rev_rate(),
9741            side_letter_abuse: default_side_letter_rate(),
9742            channel_stuffing: default_channel_stuffing_rate(),
9743            improper_capitalization: default_improper_cap_rate(),
9744        }
9745    }
9746}
9747
9748/// Financial services industry configuration.
9749#[derive(Debug, Clone, Serialize, Deserialize)]
9750pub struct FinancialServicesConfig {
9751    /// Enable financial services-specific generation.
9752    #[serde(default)]
9753    pub enabled: bool,
9754
9755    /// Financial institution type.
9756    #[serde(default = "default_fi_type")]
9757    pub institution_type: String,
9758
9759    /// Regulatory framework.
9760    #[serde(default = "default_fi_regulatory")]
9761    pub regulatory_framework: String,
9762
9763    /// Financial services anomaly injection rates.
9764    #[serde(default)]
9765    pub anomaly_rates: FinancialServicesAnomalyRates,
9766}
9767
9768fn default_fi_type() -> String {
9769    "commercial_bank".to_string()
9770}
9771
9772fn default_fi_regulatory() -> String {
9773    "us_banking".to_string()
9774}
9775
9776impl Default for FinancialServicesConfig {
9777    fn default() -> Self {
9778        Self {
9779            enabled: false,
9780            institution_type: default_fi_type(),
9781            regulatory_framework: default_fi_regulatory(),
9782            anomaly_rates: FinancialServicesAnomalyRates::default(),
9783        }
9784    }
9785}
9786
9787/// Financial services anomaly injection rates.
9788#[derive(Debug, Clone, Serialize, Deserialize)]
9789pub struct FinancialServicesAnomalyRates {
9790    /// Loan fraud rate.
9791    #[serde(default = "default_loan_fraud_rate")]
9792    pub loan_fraud: f64,
9793
9794    /// Trading fraud rate.
9795    #[serde(default = "default_trading_fraud_rate")]
9796    pub trading_fraud: f64,
9797
9798    /// Insurance fraud rate.
9799    #[serde(default = "default_insurance_fraud_rate")]
9800    pub insurance_fraud: f64,
9801
9802    /// Account manipulation rate.
9803    #[serde(default = "default_account_manip_rate")]
9804    pub account_manipulation: f64,
9805}
9806
9807fn default_loan_fraud_rate() -> f64 {
9808    0.01
9809}
9810
9811fn default_trading_fraud_rate() -> f64 {
9812    0.008
9813}
9814
9815fn default_insurance_fraud_rate() -> f64 {
9816    0.012
9817}
9818
9819fn default_account_manip_rate() -> f64 {
9820    0.005
9821}
9822
9823impl Default for FinancialServicesAnomalyRates {
9824    fn default() -> Self {
9825        Self {
9826            loan_fraud: default_loan_fraud_rate(),
9827            trading_fraud: default_trading_fraud_rate(),
9828            insurance_fraud: default_insurance_fraud_rate(),
9829            account_manipulation: default_account_manip_rate(),
9830        }
9831    }
9832}
9833
9834/// Professional services industry configuration.
9835#[derive(Debug, Clone, Serialize, Deserialize)]
9836pub struct ProfessionalServicesConfig {
9837    /// Enable professional services-specific generation.
9838    #[serde(default)]
9839    pub enabled: bool,
9840
9841    /// Firm type.
9842    #[serde(default = "default_firm_type")]
9843    pub firm_type: String,
9844
9845    /// Billing model.
9846    #[serde(default = "default_billing_model")]
9847    pub billing_model: String,
9848
9849    /// Average hourly rate.
9850    #[serde(default = "default_hourly_rate")]
9851    pub avg_hourly_rate: f64,
9852
9853    /// Trust account settings (for law firms).
9854    #[serde(default)]
9855    pub trust_accounting: TrustAccountingConfig,
9856
9857    /// Professional services anomaly injection rates.
9858    #[serde(default)]
9859    pub anomaly_rates: ProfessionalServicesAnomalyRates,
9860}
9861
9862fn default_firm_type() -> String {
9863    "consulting".to_string()
9864}
9865
9866fn default_billing_model() -> String {
9867    "time_and_materials".to_string()
9868}
9869
9870fn default_hourly_rate() -> f64 {
9871    250.0
9872}
9873
9874impl Default for ProfessionalServicesConfig {
9875    fn default() -> Self {
9876        Self {
9877            enabled: false,
9878            firm_type: default_firm_type(),
9879            billing_model: default_billing_model(),
9880            avg_hourly_rate: default_hourly_rate(),
9881            trust_accounting: TrustAccountingConfig::default(),
9882            anomaly_rates: ProfessionalServicesAnomalyRates::default(),
9883        }
9884    }
9885}
9886
9887/// Trust accounting configuration for law firms.
9888#[derive(Debug, Clone, Serialize, Deserialize)]
9889pub struct TrustAccountingConfig {
9890    /// Enable trust accounting.
9891    #[serde(default)]
9892    pub enabled: bool,
9893
9894    /// Require three-way reconciliation.
9895    #[serde(default = "default_true")]
9896    pub require_three_way_reconciliation: bool,
9897}
9898
9899impl Default for TrustAccountingConfig {
9900    fn default() -> Self {
9901        Self {
9902            enabled: false,
9903            require_three_way_reconciliation: true,
9904        }
9905    }
9906}
9907
9908/// Professional services anomaly injection rates.
9909#[derive(Debug, Clone, Serialize, Deserialize)]
9910pub struct ProfessionalServicesAnomalyRates {
9911    /// Time billing fraud rate.
9912    #[serde(default = "default_time_fraud_rate")]
9913    pub time_billing_fraud: f64,
9914
9915    /// Expense report fraud rate.
9916    #[serde(default = "default_expense_fraud_rate")]
9917    pub expense_fraud: f64,
9918
9919    /// Trust misappropriation rate.
9920    #[serde(default = "default_trust_misappropriation_rate")]
9921    pub trust_misappropriation: f64,
9922}
9923
9924fn default_time_fraud_rate() -> f64 {
9925    0.02
9926}
9927
9928fn default_expense_fraud_rate() -> f64 {
9929    0.015
9930}
9931
9932fn default_trust_misappropriation_rate() -> f64 {
9933    0.003
9934}
9935
9936impl Default for ProfessionalServicesAnomalyRates {
9937    fn default() -> Self {
9938        Self {
9939            time_billing_fraud: default_time_fraud_rate(),
9940            expense_fraud: default_expense_fraud_rate(),
9941            trust_misappropriation: default_trust_misappropriation_rate(),
9942        }
9943    }
9944}
9945
9946/// Fingerprint privacy configuration for extraction and synthesis.
9947///
9948/// Controls the privacy parameters used when extracting fingerprints
9949/// from sensitive data. Supports predefined levels or custom (epsilon, delta) tuples.
9950///
9951/// ```yaml
9952/// fingerprint_privacy:
9953///   level: custom
9954///   epsilon: 0.5
9955///   delta: 1.0e-5
9956///   k_anonymity: 10
9957///   composition_method: renyi_dp
9958/// ```
9959#[derive(Debug, Clone, Serialize, Deserialize)]
9960pub struct FingerprintPrivacyConfig {
9961    /// Privacy level preset. Use "custom" for user-specified epsilon/delta.
9962    #[serde(default)]
9963    pub level: String,
9964    /// Custom epsilon value (only used when level = "custom").
9965    #[serde(default = "default_epsilon")]
9966    pub epsilon: f64,
9967    /// Custom delta value for (epsilon, delta)-DP (only used with RDP/zCDP).
9968    #[serde(default = "default_delta")]
9969    pub delta: f64,
9970    /// K-anonymity threshold.
9971    #[serde(default = "default_k_anonymity")]
9972    pub k_anonymity: u32,
9973    /// Composition method: "naive", "advanced", "renyi_dp", "zcdp".
9974    #[serde(default)]
9975    pub composition_method: String,
9976}
9977
9978fn default_epsilon() -> f64 {
9979    1.0
9980}
9981
9982fn default_delta() -> f64 {
9983    1e-5
9984}
9985
9986fn default_k_anonymity() -> u32 {
9987    5
9988}
9989
9990impl Default for FingerprintPrivacyConfig {
9991    fn default() -> Self {
9992        Self {
9993            level: "standard".to_string(),
9994            epsilon: default_epsilon(),
9995            delta: default_delta(),
9996            k_anonymity: default_k_anonymity(),
9997            composition_method: "naive".to_string(),
9998        }
9999    }
10000}
10001
10002/// Quality gates configuration for pass/fail thresholds on generation runs.
10003///
10004/// ```yaml
10005/// quality_gates:
10006///   enabled: true
10007///   profile: strict  # strict, default, lenient, custom
10008///   fail_on_violation: true
10009///   custom_gates:
10010///     - name: benford_compliance
10011///       metric: benford_mad
10012///       threshold: 0.015
10013///       comparison: lte
10014/// ```
10015#[derive(Debug, Clone, Serialize, Deserialize)]
10016pub struct QualityGatesSchemaConfig {
10017    /// Enable quality gate evaluation.
10018    #[serde(default)]
10019    pub enabled: bool,
10020    /// Gate profile: "strict", "default", "lenient", or "custom".
10021    #[serde(default = "default_gate_profile_name")]
10022    pub profile: String,
10023    /// Whether to fail the generation on gate violations.
10024    #[serde(default)]
10025    pub fail_on_violation: bool,
10026    /// Custom gate definitions (used when profile = "custom").
10027    #[serde(default)]
10028    pub custom_gates: Vec<QualityGateEntry>,
10029}
10030
10031fn default_gate_profile_name() -> String {
10032    "default".to_string()
10033}
10034
10035impl Default for QualityGatesSchemaConfig {
10036    fn default() -> Self {
10037        Self {
10038            enabled: false,
10039            profile: default_gate_profile_name(),
10040            fail_on_violation: false,
10041            custom_gates: Vec::new(),
10042        }
10043    }
10044}
10045
10046/// A single quality gate entry in configuration.
10047#[derive(Debug, Clone, Serialize, Deserialize)]
10048pub struct QualityGateEntry {
10049    /// Gate name.
10050    pub name: String,
10051    /// Metric to check: benford_mad, balance_coherence, document_chain_integrity,
10052    /// correlation_preservation, temporal_consistency, privacy_mia_auc,
10053    /// completion_rate, duplicate_rate, referential_integrity, ic_match_rate.
10054    pub metric: String,
10055    /// Threshold value.
10056    pub threshold: f64,
10057    /// Upper threshold for "between" comparison.
10058    #[serde(default)]
10059    pub upper_threshold: Option<f64>,
10060    /// Comparison operator: "gte", "lte", "eq", "between".
10061    #[serde(default = "default_gate_comparison")]
10062    pub comparison: String,
10063}
10064
10065fn default_gate_comparison() -> String {
10066    "gte".to_string()
10067}
10068
10069/// Compliance configuration for regulatory requirements.
10070///
10071/// ```yaml
10072/// compliance:
10073///   content_marking:
10074///     enabled: true
10075///     format: embedded  # embedded, sidecar, both
10076///   article10_report: true
10077/// ```
10078#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10079pub struct ComplianceSchemaConfig {
10080    /// Synthetic content marking configuration (EU AI Act Article 50).
10081    #[serde(default)]
10082    pub content_marking: ContentMarkingSchemaConfig,
10083    /// Generate Article 10 data governance report.
10084    #[serde(default)]
10085    pub article10_report: bool,
10086    /// Certificate configuration for proving DP guarantees.
10087    #[serde(default)]
10088    pub certificates: CertificateSchemaConfig,
10089}
10090
10091/// Configuration for synthetic data certificates.
10092#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10093pub struct CertificateSchemaConfig {
10094    /// Whether certificate generation is enabled.
10095    #[serde(default)]
10096    pub enabled: bool,
10097    /// Environment variable name for the signing key.
10098    #[serde(default)]
10099    pub signing_key_env: Option<String>,
10100    /// Whether to include quality metrics in the certificate.
10101    #[serde(default)]
10102    pub include_quality_metrics: bool,
10103}
10104
10105/// Content marking configuration for synthetic data output.
10106#[derive(Debug, Clone, Serialize, Deserialize)]
10107pub struct ContentMarkingSchemaConfig {
10108    /// Whether content marking is enabled.
10109    #[serde(default = "default_true")]
10110    pub enabled: bool,
10111    /// Marking format: "embedded", "sidecar", or "both".
10112    #[serde(default = "default_marking_format")]
10113    pub format: String,
10114}
10115
10116fn default_marking_format() -> String {
10117    "embedded".to_string()
10118}
10119
10120impl Default for ContentMarkingSchemaConfig {
10121    fn default() -> Self {
10122        Self {
10123            enabled: true,
10124            format: default_marking_format(),
10125        }
10126    }
10127}
10128
10129/// Webhook notification configuration.
10130#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10131pub struct WebhookSchemaConfig {
10132    /// Whether webhooks are enabled.
10133    #[serde(default)]
10134    pub enabled: bool,
10135    /// Webhook endpoint configurations.
10136    #[serde(default)]
10137    pub endpoints: Vec<WebhookEndpointConfig>,
10138}
10139
10140/// Configuration for a single webhook endpoint.
10141#[derive(Debug, Clone, Serialize, Deserialize)]
10142pub struct WebhookEndpointConfig {
10143    /// Target URL for the webhook.
10144    pub url: String,
10145    /// Event types this endpoint subscribes to.
10146    #[serde(default)]
10147    pub events: Vec<String>,
10148    /// Optional secret for HMAC-SHA256 signature.
10149    #[serde(default)]
10150    pub secret: Option<String>,
10151    /// Maximum retry attempts (default: 3).
10152    #[serde(default = "default_webhook_retries")]
10153    pub max_retries: u32,
10154    /// Timeout in seconds (default: 10).
10155    #[serde(default = "default_webhook_timeout")]
10156    pub timeout_secs: u64,
10157}
10158
10159fn default_webhook_retries() -> u32 {
10160    3
10161}
10162fn default_webhook_timeout() -> u64 {
10163    10
10164}
10165
10166// ===== Enterprise Process Chain Config Structs =====
10167
10168// ----- Source-to-Pay (S2C/S2P) -----
10169
10170/// Source-to-Pay configuration covering the entire sourcing lifecycle.
10171#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10172pub struct SourceToPayConfig {
10173    /// Enable source-to-pay generation
10174    #[serde(default)]
10175    pub enabled: bool,
10176    /// Spend analysis configuration
10177    #[serde(default)]
10178    pub spend_analysis: SpendAnalysisConfig,
10179    /// Sourcing project configuration
10180    #[serde(default)]
10181    pub sourcing: SourcingConfig,
10182    /// Supplier qualification configuration
10183    #[serde(default)]
10184    pub qualification: QualificationConfig,
10185    /// RFx event configuration
10186    #[serde(default)]
10187    pub rfx: RfxConfig,
10188    /// Contract configuration
10189    #[serde(default)]
10190    pub contracts: ContractConfig,
10191    /// Catalog configuration
10192    #[serde(default)]
10193    pub catalog: CatalogConfig,
10194    /// Scorecard configuration
10195    #[serde(default)]
10196    pub scorecards: ScorecardConfig,
10197    /// P2P integration settings
10198    #[serde(default)]
10199    pub p2p_integration: P2PIntegrationConfig,
10200}
10201
10202/// Spend analysis configuration.
10203#[derive(Debug, Clone, Serialize, Deserialize)]
10204pub struct SpendAnalysisConfig {
10205    /// HHI threshold for triggering sourcing project
10206    #[serde(default = "default_hhi_threshold")]
10207    pub hhi_threshold: f64,
10208    /// Target spend coverage under contracts
10209    #[serde(default = "default_contract_coverage_target")]
10210    pub contract_coverage_target: f64,
10211}
10212
10213impl Default for SpendAnalysisConfig {
10214    fn default() -> Self {
10215        Self {
10216            hhi_threshold: default_hhi_threshold(),
10217            contract_coverage_target: default_contract_coverage_target(),
10218        }
10219    }
10220}
10221
10222fn default_hhi_threshold() -> f64 {
10223    2500.0
10224}
10225fn default_contract_coverage_target() -> f64 {
10226    0.80
10227}
10228
10229/// Sourcing project configuration.
10230#[derive(Debug, Clone, Serialize, Deserialize)]
10231pub struct SourcingConfig {
10232    /// Number of sourcing projects per year
10233    #[serde(default = "default_sourcing_projects_per_year")]
10234    pub projects_per_year: u32,
10235    /// Months before expiry to trigger renewal project
10236    #[serde(default = "default_renewal_horizon_months")]
10237    pub renewal_horizon_months: u32,
10238    /// Average project duration in months
10239    #[serde(default = "default_project_duration_months")]
10240    pub project_duration_months: u32,
10241}
10242
10243impl Default for SourcingConfig {
10244    fn default() -> Self {
10245        Self {
10246            projects_per_year: default_sourcing_projects_per_year(),
10247            renewal_horizon_months: default_renewal_horizon_months(),
10248            project_duration_months: default_project_duration_months(),
10249        }
10250    }
10251}
10252
10253fn default_sourcing_projects_per_year() -> u32 {
10254    10
10255}
10256fn default_renewal_horizon_months() -> u32 {
10257    3
10258}
10259fn default_project_duration_months() -> u32 {
10260    4
10261}
10262
10263/// Supplier qualification configuration.
10264#[derive(Debug, Clone, Serialize, Deserialize)]
10265pub struct QualificationConfig {
10266    /// Pass rate for qualification
10267    #[serde(default = "default_qualification_pass_rate")]
10268    pub pass_rate: f64,
10269    /// Qualification validity in days
10270    #[serde(default = "default_qualification_validity_days")]
10271    pub validity_days: u32,
10272    /// Financial stability weight
10273    #[serde(default = "default_financial_weight")]
10274    pub financial_weight: f64,
10275    /// Quality management weight
10276    #[serde(default = "default_quality_weight")]
10277    pub quality_weight: f64,
10278    /// Delivery performance weight
10279    #[serde(default = "default_delivery_weight")]
10280    pub delivery_weight: f64,
10281    /// Compliance weight
10282    #[serde(default = "default_compliance_weight")]
10283    pub compliance_weight: f64,
10284}
10285
10286impl Default for QualificationConfig {
10287    fn default() -> Self {
10288        Self {
10289            pass_rate: default_qualification_pass_rate(),
10290            validity_days: default_qualification_validity_days(),
10291            financial_weight: default_financial_weight(),
10292            quality_weight: default_quality_weight(),
10293            delivery_weight: default_delivery_weight(),
10294            compliance_weight: default_compliance_weight(),
10295        }
10296    }
10297}
10298
10299fn default_qualification_pass_rate() -> f64 {
10300    0.75
10301}
10302fn default_qualification_validity_days() -> u32 {
10303    365
10304}
10305fn default_financial_weight() -> f64 {
10306    0.25
10307}
10308fn default_quality_weight() -> f64 {
10309    0.30
10310}
10311fn default_delivery_weight() -> f64 {
10312    0.25
10313}
10314fn default_compliance_weight() -> f64 {
10315    0.20
10316}
10317
10318/// RFx event configuration.
10319#[derive(Debug, Clone, Serialize, Deserialize)]
10320pub struct RfxConfig {
10321    /// Spend threshold above which RFI is required before RFP
10322    #[serde(default = "default_rfi_threshold")]
10323    pub rfi_threshold: f64,
10324    /// Minimum vendors invited per RFx
10325    #[serde(default = "default_min_invited_vendors")]
10326    pub min_invited_vendors: u32,
10327    /// Maximum vendors invited per RFx
10328    #[serde(default = "default_max_invited_vendors")]
10329    pub max_invited_vendors: u32,
10330    /// Response rate (% of invited vendors that submit bids)
10331    #[serde(default = "default_response_rate")]
10332    pub response_rate: f64,
10333    /// Default price weight in evaluation
10334    #[serde(default = "default_price_weight")]
10335    pub default_price_weight: f64,
10336    /// Default quality weight in evaluation
10337    #[serde(default = "default_rfx_quality_weight")]
10338    pub default_quality_weight: f64,
10339    /// Default delivery weight in evaluation
10340    #[serde(default = "default_rfx_delivery_weight")]
10341    pub default_delivery_weight: f64,
10342}
10343
10344impl Default for RfxConfig {
10345    fn default() -> Self {
10346        Self {
10347            rfi_threshold: default_rfi_threshold(),
10348            min_invited_vendors: default_min_invited_vendors(),
10349            max_invited_vendors: default_max_invited_vendors(),
10350            response_rate: default_response_rate(),
10351            default_price_weight: default_price_weight(),
10352            default_quality_weight: default_rfx_quality_weight(),
10353            default_delivery_weight: default_rfx_delivery_weight(),
10354        }
10355    }
10356}
10357
10358fn default_rfi_threshold() -> f64 {
10359    100_000.0
10360}
10361fn default_min_invited_vendors() -> u32 {
10362    3
10363}
10364fn default_max_invited_vendors() -> u32 {
10365    8
10366}
10367fn default_response_rate() -> f64 {
10368    0.70
10369}
10370fn default_price_weight() -> f64 {
10371    0.40
10372}
10373fn default_rfx_quality_weight() -> f64 {
10374    0.35
10375}
10376fn default_rfx_delivery_weight() -> f64 {
10377    0.25
10378}
10379
10380/// Contract configuration.
10381#[derive(Debug, Clone, Serialize, Deserialize)]
10382pub struct ContractConfig {
10383    /// Minimum contract duration in months
10384    #[serde(default = "default_min_contract_months")]
10385    pub min_duration_months: u32,
10386    /// Maximum contract duration in months
10387    #[serde(default = "default_max_contract_months")]
10388    pub max_duration_months: u32,
10389    /// Auto-renewal rate
10390    #[serde(default = "default_auto_renewal_rate")]
10391    pub auto_renewal_rate: f64,
10392    /// Amendment rate (% of contracts with at least one amendment)
10393    #[serde(default = "default_amendment_rate")]
10394    pub amendment_rate: f64,
10395    /// Distribution of contract types
10396    #[serde(default)]
10397    pub type_distribution: ContractTypeDistribution,
10398}
10399
10400impl Default for ContractConfig {
10401    fn default() -> Self {
10402        Self {
10403            min_duration_months: default_min_contract_months(),
10404            max_duration_months: default_max_contract_months(),
10405            auto_renewal_rate: default_auto_renewal_rate(),
10406            amendment_rate: default_amendment_rate(),
10407            type_distribution: ContractTypeDistribution::default(),
10408        }
10409    }
10410}
10411
10412fn default_min_contract_months() -> u32 {
10413    12
10414}
10415fn default_max_contract_months() -> u32 {
10416    36
10417}
10418fn default_auto_renewal_rate() -> f64 {
10419    0.40
10420}
10421fn default_amendment_rate() -> f64 {
10422    0.20
10423}
10424
10425/// Distribution of contract types.
10426#[derive(Debug, Clone, Serialize, Deserialize)]
10427pub struct ContractTypeDistribution {
10428    /// Fixed price percentage
10429    #[serde(default = "default_fixed_price_pct")]
10430    pub fixed_price: f64,
10431    /// Blanket/framework percentage
10432    #[serde(default = "default_blanket_pct")]
10433    pub blanket: f64,
10434    /// Time and materials percentage
10435    #[serde(default = "default_time_materials_pct")]
10436    pub time_and_materials: f64,
10437    /// Service agreement percentage
10438    #[serde(default = "default_service_agreement_pct")]
10439    pub service_agreement: f64,
10440}
10441
10442impl Default for ContractTypeDistribution {
10443    fn default() -> Self {
10444        Self {
10445            fixed_price: default_fixed_price_pct(),
10446            blanket: default_blanket_pct(),
10447            time_and_materials: default_time_materials_pct(),
10448            service_agreement: default_service_agreement_pct(),
10449        }
10450    }
10451}
10452
10453fn default_fixed_price_pct() -> f64 {
10454    0.40
10455}
10456fn default_blanket_pct() -> f64 {
10457    0.30
10458}
10459fn default_time_materials_pct() -> f64 {
10460    0.15
10461}
10462fn default_service_agreement_pct() -> f64 {
10463    0.15
10464}
10465
10466/// Catalog configuration.
10467#[derive(Debug, Clone, Serialize, Deserialize)]
10468pub struct CatalogConfig {
10469    /// Percentage of catalog items marked as preferred
10470    #[serde(default = "default_preferred_vendor_flag_rate")]
10471    pub preferred_vendor_flag_rate: f64,
10472    /// Rate of materials with multiple sources in catalog
10473    #[serde(default = "default_multi_source_rate")]
10474    pub multi_source_rate: f64,
10475}
10476
10477impl Default for CatalogConfig {
10478    fn default() -> Self {
10479        Self {
10480            preferred_vendor_flag_rate: default_preferred_vendor_flag_rate(),
10481            multi_source_rate: default_multi_source_rate(),
10482        }
10483    }
10484}
10485
10486fn default_preferred_vendor_flag_rate() -> f64 {
10487    0.70
10488}
10489fn default_multi_source_rate() -> f64 {
10490    0.25
10491}
10492
10493/// Scorecard configuration.
10494#[derive(Debug, Clone, Serialize, Deserialize)]
10495pub struct ScorecardConfig {
10496    /// Scorecard review frequency (quarterly, monthly)
10497    #[serde(default = "default_scorecard_frequency")]
10498    pub frequency: String,
10499    /// On-time delivery weight in overall score
10500    #[serde(default = "default_otd_weight")]
10501    pub on_time_delivery_weight: f64,
10502    /// Quality weight in overall score
10503    #[serde(default = "default_quality_score_weight")]
10504    pub quality_weight: f64,
10505    /// Price competitiveness weight
10506    #[serde(default = "default_price_score_weight")]
10507    pub price_weight: f64,
10508    /// Responsiveness weight
10509    #[serde(default = "default_responsiveness_weight")]
10510    pub responsiveness_weight: f64,
10511    /// Grade A threshold (score >= this)
10512    #[serde(default = "default_grade_a_threshold")]
10513    pub grade_a_threshold: f64,
10514    /// Grade B threshold
10515    #[serde(default = "default_grade_b_threshold")]
10516    pub grade_b_threshold: f64,
10517    /// Grade C threshold
10518    #[serde(default = "default_grade_c_threshold")]
10519    pub grade_c_threshold: f64,
10520}
10521
10522impl Default for ScorecardConfig {
10523    fn default() -> Self {
10524        Self {
10525            frequency: default_scorecard_frequency(),
10526            on_time_delivery_weight: default_otd_weight(),
10527            quality_weight: default_quality_score_weight(),
10528            price_weight: default_price_score_weight(),
10529            responsiveness_weight: default_responsiveness_weight(),
10530            grade_a_threshold: default_grade_a_threshold(),
10531            grade_b_threshold: default_grade_b_threshold(),
10532            grade_c_threshold: default_grade_c_threshold(),
10533        }
10534    }
10535}
10536
10537fn default_scorecard_frequency() -> String {
10538    "quarterly".to_string()
10539}
10540fn default_otd_weight() -> f64 {
10541    0.30
10542}
10543fn default_quality_score_weight() -> f64 {
10544    0.30
10545}
10546fn default_price_score_weight() -> f64 {
10547    0.25
10548}
10549fn default_responsiveness_weight() -> f64 {
10550    0.15
10551}
10552fn default_grade_a_threshold() -> f64 {
10553    90.0
10554}
10555fn default_grade_b_threshold() -> f64 {
10556    75.0
10557}
10558fn default_grade_c_threshold() -> f64 {
10559    60.0
10560}
10561
10562/// P2P integration settings for contract enforcement.
10563#[derive(Debug, Clone, Serialize, Deserialize)]
10564pub struct P2PIntegrationConfig {
10565    /// Rate of off-contract (maverick) purchases
10566    #[serde(default = "default_off_contract_rate")]
10567    pub off_contract_rate: f64,
10568    /// Price tolerance for contract price validation
10569    #[serde(default = "default_price_tolerance")]
10570    pub price_tolerance: f64,
10571    /// Whether to enforce catalog ordering
10572    #[serde(default)]
10573    pub catalog_enforcement: bool,
10574}
10575
10576impl Default for P2PIntegrationConfig {
10577    fn default() -> Self {
10578        Self {
10579            off_contract_rate: default_off_contract_rate(),
10580            price_tolerance: default_price_tolerance(),
10581            catalog_enforcement: false,
10582        }
10583    }
10584}
10585
10586fn default_off_contract_rate() -> f64 {
10587    0.15
10588}
10589fn default_price_tolerance() -> f64 {
10590    0.02
10591}
10592
10593// ----- Financial Reporting -----
10594
10595/// Financial reporting configuration.
10596#[derive(Debug, Clone, Serialize, Deserialize)]
10597pub struct FinancialReportingConfig {
10598    /// Enable financial reporting generation
10599    #[serde(default)]
10600    pub enabled: bool,
10601    /// Generate balance sheet
10602    #[serde(default = "default_true")]
10603    pub generate_balance_sheet: bool,
10604    /// Generate income statement
10605    #[serde(default = "default_true")]
10606    pub generate_income_statement: bool,
10607    /// Generate cash flow statement
10608    #[serde(default = "default_true")]
10609    pub generate_cash_flow: bool,
10610    /// Generate changes in equity statement
10611    #[serde(default = "default_true")]
10612    pub generate_changes_in_equity: bool,
10613    /// Number of comparative periods
10614    #[serde(default = "default_comparative_periods")]
10615    pub comparative_periods: u32,
10616    /// Management KPIs configuration
10617    #[serde(default)]
10618    pub management_kpis: ManagementKpisConfig,
10619    /// Budget configuration
10620    #[serde(default)]
10621    pub budgets: BudgetConfig,
10622}
10623
10624impl Default for FinancialReportingConfig {
10625    fn default() -> Self {
10626        Self {
10627            enabled: false,
10628            generate_balance_sheet: true,
10629            generate_income_statement: true,
10630            generate_cash_flow: true,
10631            generate_changes_in_equity: true,
10632            comparative_periods: default_comparative_periods(),
10633            management_kpis: ManagementKpisConfig::default(),
10634            budgets: BudgetConfig::default(),
10635        }
10636    }
10637}
10638
10639fn default_comparative_periods() -> u32 {
10640    1
10641}
10642
10643/// Management KPIs configuration.
10644#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10645pub struct ManagementKpisConfig {
10646    /// Enable KPI generation
10647    #[serde(default)]
10648    pub enabled: bool,
10649    /// KPI calculation frequency (monthly, quarterly)
10650    #[serde(default = "default_kpi_frequency")]
10651    pub frequency: String,
10652}
10653
10654fn default_kpi_frequency() -> String {
10655    "monthly".to_string()
10656}
10657
10658/// Budget configuration.
10659#[derive(Debug, Clone, Serialize, Deserialize)]
10660pub struct BudgetConfig {
10661    /// Enable budget generation
10662    #[serde(default)]
10663    pub enabled: bool,
10664    /// Expected revenue growth rate for budgeting
10665    #[serde(default = "default_revenue_growth_rate")]
10666    pub revenue_growth_rate: f64,
10667    /// Expected expense inflation rate
10668    #[serde(default = "default_expense_inflation_rate")]
10669    pub expense_inflation_rate: f64,
10670    /// Random noise to add to budget vs actual
10671    #[serde(default = "default_variance_noise")]
10672    pub variance_noise: f64,
10673}
10674
10675impl Default for BudgetConfig {
10676    fn default() -> Self {
10677        Self {
10678            enabled: false,
10679            revenue_growth_rate: default_revenue_growth_rate(),
10680            expense_inflation_rate: default_expense_inflation_rate(),
10681            variance_noise: default_variance_noise(),
10682        }
10683    }
10684}
10685
10686fn default_revenue_growth_rate() -> f64 {
10687    0.05
10688}
10689fn default_expense_inflation_rate() -> f64 {
10690    0.03
10691}
10692fn default_variance_noise() -> f64 {
10693    0.10
10694}
10695
10696// ----- HR Configuration -----
10697
10698/// HR (Hire-to-Retire) process configuration.
10699#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10700pub struct HrConfig {
10701    /// Enable HR generation
10702    #[serde(default)]
10703    pub enabled: bool,
10704    /// Payroll configuration
10705    #[serde(default)]
10706    pub payroll: PayrollConfig,
10707    /// Time and attendance configuration
10708    #[serde(default)]
10709    pub time_attendance: TimeAttendanceConfig,
10710    /// Expense management configuration
10711    #[serde(default)]
10712    pub expenses: ExpenseConfig,
10713}
10714
10715/// Payroll configuration.
10716#[derive(Debug, Clone, Serialize, Deserialize)]
10717pub struct PayrollConfig {
10718    /// Enable payroll generation
10719    #[serde(default = "default_true")]
10720    pub enabled: bool,
10721    /// Pay frequency (monthly, biweekly, weekly)
10722    #[serde(default = "default_pay_frequency")]
10723    pub pay_frequency: String,
10724    /// Salary ranges by job level
10725    #[serde(default)]
10726    pub salary_ranges: PayrollSalaryRanges,
10727    /// Effective tax rates
10728    #[serde(default)]
10729    pub tax_rates: PayrollTaxRates,
10730    /// Benefits enrollment rate
10731    #[serde(default = "default_benefits_enrollment_rate")]
10732    pub benefits_enrollment_rate: f64,
10733    /// Retirement plan participation rate
10734    #[serde(default = "default_retirement_participation_rate")]
10735    pub retirement_participation_rate: f64,
10736}
10737
10738impl Default for PayrollConfig {
10739    fn default() -> Self {
10740        Self {
10741            enabled: true,
10742            pay_frequency: default_pay_frequency(),
10743            salary_ranges: PayrollSalaryRanges::default(),
10744            tax_rates: PayrollTaxRates::default(),
10745            benefits_enrollment_rate: default_benefits_enrollment_rate(),
10746            retirement_participation_rate: default_retirement_participation_rate(),
10747        }
10748    }
10749}
10750
10751fn default_pay_frequency() -> String {
10752    "monthly".to_string()
10753}
10754fn default_benefits_enrollment_rate() -> f64 {
10755    0.60
10756}
10757fn default_retirement_participation_rate() -> f64 {
10758    0.45
10759}
10760
10761/// Salary ranges by job level.
10762#[derive(Debug, Clone, Serialize, Deserialize)]
10763pub struct PayrollSalaryRanges {
10764    /// Staff level min/max
10765    #[serde(default = "default_staff_min")]
10766    pub staff_min: f64,
10767    #[serde(default = "default_staff_max")]
10768    pub staff_max: f64,
10769    /// Manager level min/max
10770    #[serde(default = "default_manager_min")]
10771    pub manager_min: f64,
10772    #[serde(default = "default_manager_max")]
10773    pub manager_max: f64,
10774    /// Director level min/max
10775    #[serde(default = "default_director_min")]
10776    pub director_min: f64,
10777    #[serde(default = "default_director_max")]
10778    pub director_max: f64,
10779    /// Executive level min/max
10780    #[serde(default = "default_executive_min")]
10781    pub executive_min: f64,
10782    #[serde(default = "default_executive_max")]
10783    pub executive_max: f64,
10784}
10785
10786impl Default for PayrollSalaryRanges {
10787    fn default() -> Self {
10788        Self {
10789            staff_min: default_staff_min(),
10790            staff_max: default_staff_max(),
10791            manager_min: default_manager_min(),
10792            manager_max: default_manager_max(),
10793            director_min: default_director_min(),
10794            director_max: default_director_max(),
10795            executive_min: default_executive_min(),
10796            executive_max: default_executive_max(),
10797        }
10798    }
10799}
10800
10801fn default_staff_min() -> f64 {
10802    50_000.0
10803}
10804fn default_staff_max() -> f64 {
10805    70_000.0
10806}
10807fn default_manager_min() -> f64 {
10808    80_000.0
10809}
10810fn default_manager_max() -> f64 {
10811    120_000.0
10812}
10813fn default_director_min() -> f64 {
10814    120_000.0
10815}
10816fn default_director_max() -> f64 {
10817    180_000.0
10818}
10819fn default_executive_min() -> f64 {
10820    180_000.0
10821}
10822fn default_executive_max() -> f64 {
10823    350_000.0
10824}
10825
10826/// Effective tax rates for payroll.
10827#[derive(Debug, Clone, Serialize, Deserialize)]
10828pub struct PayrollTaxRates {
10829    /// Federal effective tax rate
10830    #[serde(default = "default_federal_rate")]
10831    pub federal_effective: f64,
10832    /// State effective tax rate
10833    #[serde(default = "default_state_rate")]
10834    pub state_effective: f64,
10835    /// FICA/social security rate
10836    #[serde(default = "default_fica_rate")]
10837    pub fica: f64,
10838}
10839
10840impl Default for PayrollTaxRates {
10841    fn default() -> Self {
10842        Self {
10843            federal_effective: default_federal_rate(),
10844            state_effective: default_state_rate(),
10845            fica: default_fica_rate(),
10846        }
10847    }
10848}
10849
10850fn default_federal_rate() -> f64 {
10851    0.22
10852}
10853fn default_state_rate() -> f64 {
10854    0.05
10855}
10856fn default_fica_rate() -> f64 {
10857    0.0765
10858}
10859
10860/// Time and attendance configuration.
10861#[derive(Debug, Clone, Serialize, Deserialize)]
10862pub struct TimeAttendanceConfig {
10863    /// Enable time tracking
10864    #[serde(default = "default_true")]
10865    pub enabled: bool,
10866    /// Overtime rate (% of employees with overtime in a period)
10867    #[serde(default = "default_overtime_rate")]
10868    pub overtime_rate: f64,
10869}
10870
10871impl Default for TimeAttendanceConfig {
10872    fn default() -> Self {
10873        Self {
10874            enabled: true,
10875            overtime_rate: default_overtime_rate(),
10876        }
10877    }
10878}
10879
10880fn default_overtime_rate() -> f64 {
10881    0.10
10882}
10883
10884/// Expense management configuration.
10885#[derive(Debug, Clone, Serialize, Deserialize)]
10886pub struct ExpenseConfig {
10887    /// Enable expense report generation
10888    #[serde(default = "default_true")]
10889    pub enabled: bool,
10890    /// Rate of employees submitting expenses per month
10891    #[serde(default = "default_expense_submission_rate")]
10892    pub submission_rate: f64,
10893    /// Rate of policy violations
10894    #[serde(default = "default_policy_violation_rate")]
10895    pub policy_violation_rate: f64,
10896}
10897
10898impl Default for ExpenseConfig {
10899    fn default() -> Self {
10900        Self {
10901            enabled: true,
10902            submission_rate: default_expense_submission_rate(),
10903            policy_violation_rate: default_policy_violation_rate(),
10904        }
10905    }
10906}
10907
10908fn default_expense_submission_rate() -> f64 {
10909    0.30
10910}
10911fn default_policy_violation_rate() -> f64 {
10912    0.08
10913}
10914
10915// ----- Manufacturing Configuration -----
10916
10917/// Manufacturing process configuration (production orders, WIP, routing).
10918#[derive(Debug, Clone, Default, Serialize, Deserialize)]
10919pub struct ManufacturingProcessConfig {
10920    /// Enable manufacturing generation
10921    #[serde(default)]
10922    pub enabled: bool,
10923    /// Production order configuration
10924    #[serde(default)]
10925    pub production_orders: ProductionOrderConfig,
10926    /// Costing configuration
10927    #[serde(default)]
10928    pub costing: ManufacturingCostingConfig,
10929    /// Routing configuration
10930    #[serde(default)]
10931    pub routing: RoutingConfig,
10932}
10933
10934/// Production order configuration.
10935#[derive(Debug, Clone, Serialize, Deserialize)]
10936pub struct ProductionOrderConfig {
10937    /// Orders per month
10938    #[serde(default = "default_prod_orders_per_month")]
10939    pub orders_per_month: u32,
10940    /// Average batch size
10941    #[serde(default = "default_prod_avg_batch_size")]
10942    pub avg_batch_size: u32,
10943    /// Yield rate
10944    #[serde(default = "default_prod_yield_rate")]
10945    pub yield_rate: f64,
10946    /// Make-to-order rate (vs make-to-stock)
10947    #[serde(default = "default_prod_make_to_order_rate")]
10948    pub make_to_order_rate: f64,
10949    /// Rework rate
10950    #[serde(default = "default_prod_rework_rate")]
10951    pub rework_rate: f64,
10952}
10953
10954impl Default for ProductionOrderConfig {
10955    fn default() -> Self {
10956        Self {
10957            orders_per_month: default_prod_orders_per_month(),
10958            avg_batch_size: default_prod_avg_batch_size(),
10959            yield_rate: default_prod_yield_rate(),
10960            make_to_order_rate: default_prod_make_to_order_rate(),
10961            rework_rate: default_prod_rework_rate(),
10962        }
10963    }
10964}
10965
10966fn default_prod_orders_per_month() -> u32 {
10967    50
10968}
10969fn default_prod_avg_batch_size() -> u32 {
10970    100
10971}
10972fn default_prod_yield_rate() -> f64 {
10973    0.97
10974}
10975fn default_prod_make_to_order_rate() -> f64 {
10976    0.20
10977}
10978fn default_prod_rework_rate() -> f64 {
10979    0.03
10980}
10981
10982/// Manufacturing costing configuration.
10983#[derive(Debug, Clone, Serialize, Deserialize)]
10984pub struct ManufacturingCostingConfig {
10985    /// Labor rate per hour
10986    #[serde(default = "default_labor_rate")]
10987    pub labor_rate_per_hour: f64,
10988    /// Overhead application rate (multiplier on direct labor)
10989    #[serde(default = "default_overhead_rate")]
10990    pub overhead_rate: f64,
10991    /// Standard cost update frequency
10992    #[serde(default = "default_cost_update_frequency")]
10993    pub standard_cost_update_frequency: String,
10994}
10995
10996impl Default for ManufacturingCostingConfig {
10997    fn default() -> Self {
10998        Self {
10999            labor_rate_per_hour: default_labor_rate(),
11000            overhead_rate: default_overhead_rate(),
11001            standard_cost_update_frequency: default_cost_update_frequency(),
11002        }
11003    }
11004}
11005
11006fn default_labor_rate() -> f64 {
11007    35.0
11008}
11009fn default_overhead_rate() -> f64 {
11010    1.50
11011}
11012fn default_cost_update_frequency() -> String {
11013    "quarterly".to_string()
11014}
11015
11016/// Routing configuration for production operations.
11017#[derive(Debug, Clone, Serialize, Deserialize)]
11018pub struct RoutingConfig {
11019    /// Average number of operations per routing
11020    #[serde(default = "default_avg_operations")]
11021    pub avg_operations: u32,
11022    /// Average setup time in hours
11023    #[serde(default = "default_setup_time")]
11024    pub setup_time_hours: f64,
11025    /// Run time variation coefficient
11026    #[serde(default = "default_run_time_variation")]
11027    pub run_time_variation: f64,
11028}
11029
11030impl Default for RoutingConfig {
11031    fn default() -> Self {
11032        Self {
11033            avg_operations: default_avg_operations(),
11034            setup_time_hours: default_setup_time(),
11035            run_time_variation: default_run_time_variation(),
11036        }
11037    }
11038}
11039
11040fn default_avg_operations() -> u32 {
11041    4
11042}
11043fn default_setup_time() -> f64 {
11044    1.5
11045}
11046fn default_run_time_variation() -> f64 {
11047    0.15
11048}
11049
11050// ----- Sales Quote Configuration -----
11051
11052/// Sales quote (quote-to-order) pipeline configuration.
11053#[derive(Debug, Clone, Serialize, Deserialize)]
11054pub struct SalesQuoteConfig {
11055    /// Enable sales quote generation
11056    #[serde(default)]
11057    pub enabled: bool,
11058    /// Quotes per month
11059    #[serde(default = "default_quotes_per_month")]
11060    pub quotes_per_month: u32,
11061    /// Win rate (fraction of quotes that convert to orders)
11062    #[serde(default = "default_quote_win_rate")]
11063    pub win_rate: f64,
11064    /// Average quote validity in days
11065    #[serde(default = "default_quote_validity_days")]
11066    pub validity_days: u32,
11067}
11068
11069impl Default for SalesQuoteConfig {
11070    fn default() -> Self {
11071        Self {
11072            enabled: false,
11073            quotes_per_month: default_quotes_per_month(),
11074            win_rate: default_quote_win_rate(),
11075            validity_days: default_quote_validity_days(),
11076        }
11077    }
11078}
11079
11080fn default_quotes_per_month() -> u32 {
11081    30
11082}
11083fn default_quote_win_rate() -> f64 {
11084    0.35
11085}
11086fn default_quote_validity_days() -> u32 {
11087    30
11088}
11089
11090// =============================================================================
11091// Tax Accounting Configuration
11092// =============================================================================
11093
11094/// Tax accounting configuration.
11095///
11096/// Controls generation of tax-related data including VAT/GST, sales tax,
11097/// withholding tax, tax provisions, and payroll tax across multiple jurisdictions.
11098#[derive(Debug, Clone, Serialize, Deserialize)]
11099pub struct TaxConfig {
11100    /// Whether tax generation is enabled.
11101    #[serde(default)]
11102    pub enabled: bool,
11103    /// Tax jurisdiction configuration.
11104    #[serde(default)]
11105    pub jurisdictions: TaxJurisdictionConfig,
11106    /// VAT/GST configuration.
11107    #[serde(default)]
11108    pub vat_gst: VatGstConfig,
11109    /// Sales tax configuration.
11110    #[serde(default)]
11111    pub sales_tax: SalesTaxConfig,
11112    /// Withholding tax configuration.
11113    #[serde(default)]
11114    pub withholding: WithholdingTaxSchemaConfig,
11115    /// Tax provision configuration.
11116    #[serde(default)]
11117    pub provisions: TaxProvisionSchemaConfig,
11118    /// Payroll tax configuration.
11119    #[serde(default)]
11120    pub payroll_tax: PayrollTaxSchemaConfig,
11121    /// Anomaly injection rate for tax data (0.0 to 1.0).
11122    #[serde(default = "default_tax_anomaly_rate")]
11123    pub anomaly_rate: f64,
11124}
11125
11126fn default_tax_anomaly_rate() -> f64 {
11127    0.03
11128}
11129
11130impl Default for TaxConfig {
11131    fn default() -> Self {
11132        Self {
11133            enabled: false,
11134            jurisdictions: TaxJurisdictionConfig::default(),
11135            vat_gst: VatGstConfig::default(),
11136            sales_tax: SalesTaxConfig::default(),
11137            withholding: WithholdingTaxSchemaConfig::default(),
11138            provisions: TaxProvisionSchemaConfig::default(),
11139            payroll_tax: PayrollTaxSchemaConfig::default(),
11140            anomaly_rate: default_tax_anomaly_rate(),
11141        }
11142    }
11143}
11144
11145/// Tax jurisdiction configuration.
11146///
11147/// Specifies which countries and subnational jurisdictions to include
11148/// when generating tax data.
11149#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11150pub struct TaxJurisdictionConfig {
11151    /// List of country codes to include (e.g., ["US", "DE", "GB"]).
11152    #[serde(default)]
11153    pub countries: Vec<String>,
11154    /// Whether to include subnational jurisdictions (e.g., US states, Canadian provinces).
11155    #[serde(default)]
11156    pub include_subnational: bool,
11157}
11158
11159/// VAT/GST configuration.
11160///
11161/// Controls generation of Value Added Tax / Goods and Services Tax data,
11162/// including standard and reduced rates, exempt categories, and reverse charge.
11163#[derive(Debug, Clone, Serialize, Deserialize)]
11164pub struct VatGstConfig {
11165    /// Whether VAT/GST generation is enabled.
11166    #[serde(default)]
11167    pub enabled: bool,
11168    /// Standard VAT/GST rates by country code (e.g., {"DE": 0.19, "GB": 0.20}).
11169    #[serde(default)]
11170    pub standard_rates: std::collections::HashMap<String, f64>,
11171    /// Reduced VAT/GST rates by country code (e.g., {"DE": 0.07, "GB": 0.05}).
11172    #[serde(default)]
11173    pub reduced_rates: std::collections::HashMap<String, f64>,
11174    /// Categories exempt from VAT/GST (e.g., ["financial_services", "healthcare"]).
11175    #[serde(default)]
11176    pub exempt_categories: Vec<String>,
11177    /// Whether to apply reverse charge mechanism for cross-border B2B transactions.
11178    #[serde(default = "default_true")]
11179    pub reverse_charge: bool,
11180}
11181
11182impl Default for VatGstConfig {
11183    fn default() -> Self {
11184        Self {
11185            enabled: false,
11186            standard_rates: std::collections::HashMap::new(),
11187            reduced_rates: std::collections::HashMap::new(),
11188            exempt_categories: Vec::new(),
11189            reverse_charge: true,
11190        }
11191    }
11192}
11193
11194/// Sales tax configuration.
11195///
11196/// Controls generation of US-style sales tax data including nexus determination.
11197#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11198pub struct SalesTaxConfig {
11199    /// Whether sales tax generation is enabled.
11200    #[serde(default)]
11201    pub enabled: bool,
11202    /// US states where the company has nexus (e.g., ["CA", "NY", "TX"]).
11203    #[serde(default)]
11204    pub nexus_states: Vec<String>,
11205}
11206
11207/// Withholding tax configuration.
11208///
11209/// Controls generation of withholding tax data for cross-border payments,
11210/// including treaty network and rate overrides.
11211#[derive(Debug, Clone, Serialize, Deserialize)]
11212pub struct WithholdingTaxSchemaConfig {
11213    /// Whether withholding tax generation is enabled.
11214    #[serde(default)]
11215    pub enabled: bool,
11216    /// Whether to simulate a treaty network with reduced rates.
11217    #[serde(default = "default_true")]
11218    pub treaty_network: bool,
11219    /// Default withholding tax rate for non-treaty countries (0.0 to 1.0).
11220    #[serde(default = "default_withholding_rate")]
11221    pub default_rate: f64,
11222    /// Reduced withholding tax rate for treaty countries (0.0 to 1.0).
11223    #[serde(default = "default_treaty_reduced_rate")]
11224    pub treaty_reduced_rate: f64,
11225}
11226
11227fn default_withholding_rate() -> f64 {
11228    0.30
11229}
11230
11231fn default_treaty_reduced_rate() -> f64 {
11232    0.15
11233}
11234
11235impl Default for WithholdingTaxSchemaConfig {
11236    fn default() -> Self {
11237        Self {
11238            enabled: false,
11239            treaty_network: true,
11240            default_rate: default_withholding_rate(),
11241            treaty_reduced_rate: default_treaty_reduced_rate(),
11242        }
11243    }
11244}
11245
11246/// Tax provision configuration.
11247///
11248/// Controls generation of tax provision data including statutory rates
11249/// and uncertain tax positions (ASC 740 / IAS 12).
11250#[derive(Debug, Clone, Serialize, Deserialize)]
11251pub struct TaxProvisionSchemaConfig {
11252    /// Whether tax provision generation is enabled.
11253    /// Defaults to true when tax is enabled, as provisions are typically required.
11254    #[serde(default = "default_true")]
11255    pub enabled: bool,
11256    /// Statutory corporate tax rate (0.0 to 1.0).
11257    #[serde(default = "default_statutory_rate")]
11258    pub statutory_rate: f64,
11259    /// Whether to generate uncertain tax positions (FIN 48 / IFRIC 23).
11260    #[serde(default = "default_true")]
11261    pub uncertain_positions: bool,
11262}
11263
11264fn default_statutory_rate() -> f64 {
11265    0.21
11266}
11267
11268impl Default for TaxProvisionSchemaConfig {
11269    fn default() -> Self {
11270        Self {
11271            enabled: true,
11272            statutory_rate: default_statutory_rate(),
11273            uncertain_positions: true,
11274        }
11275    }
11276}
11277
11278/// Payroll tax configuration.
11279///
11280/// Controls generation of payroll tax data (employer/employee contributions,
11281/// social security, Medicare, etc.).
11282#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11283pub struct PayrollTaxSchemaConfig {
11284    /// Whether payroll tax generation is enabled.
11285    #[serde(default)]
11286    pub enabled: bool,
11287}
11288
11289// ---------------------------------------------------------------------------
11290// Treasury & Cash Management Configuration
11291// ---------------------------------------------------------------------------
11292
11293/// Treasury and cash management configuration.
11294///
11295/// Controls generation of cash positions, forecasts, pooling, hedging
11296/// instruments (ASC 815 / IFRS 9), debt instruments with covenants,
11297/// bank guarantees, and intercompany netting runs.
11298#[derive(Debug, Clone, Serialize, Deserialize)]
11299pub struct TreasuryConfig {
11300    /// Whether treasury generation is enabled.
11301    #[serde(default)]
11302    pub enabled: bool,
11303    /// Cash positioning configuration.
11304    #[serde(default)]
11305    pub cash_positioning: CashPositioningConfig,
11306    /// Cash forecasting configuration.
11307    #[serde(default)]
11308    pub cash_forecasting: CashForecastingConfig,
11309    /// Cash pooling configuration.
11310    #[serde(default)]
11311    pub cash_pooling: CashPoolingConfig,
11312    /// Hedging configuration (FX forwards, IR swaps, etc.).
11313    #[serde(default)]
11314    pub hedging: HedgingSchemaConfig,
11315    /// Debt instrument and covenant configuration.
11316    #[serde(default)]
11317    pub debt: DebtSchemaConfig,
11318    /// Intercompany netting configuration.
11319    #[serde(default)]
11320    pub netting: NettingSchemaConfig,
11321    /// Bank guarantee / letter of credit configuration.
11322    #[serde(default)]
11323    pub bank_guarantees: BankGuaranteeSchemaConfig,
11324    /// Anomaly injection rate for treasury data (0.0 to 1.0).
11325    #[serde(default = "default_treasury_anomaly_rate")]
11326    pub anomaly_rate: f64,
11327}
11328
11329fn default_treasury_anomaly_rate() -> f64 {
11330    0.02
11331}
11332
11333impl Default for TreasuryConfig {
11334    fn default() -> Self {
11335        Self {
11336            enabled: false,
11337            cash_positioning: CashPositioningConfig::default(),
11338            cash_forecasting: CashForecastingConfig::default(),
11339            cash_pooling: CashPoolingConfig::default(),
11340            hedging: HedgingSchemaConfig::default(),
11341            debt: DebtSchemaConfig::default(),
11342            netting: NettingSchemaConfig::default(),
11343            bank_guarantees: BankGuaranteeSchemaConfig::default(),
11344            anomaly_rate: default_treasury_anomaly_rate(),
11345        }
11346    }
11347}
11348
11349/// Cash positioning configuration.
11350///
11351/// Controls daily cash position generation per entity/bank account.
11352#[derive(Debug, Clone, Serialize, Deserialize)]
11353pub struct CashPositioningConfig {
11354    /// Whether cash positioning is enabled.
11355    #[serde(default = "default_true")]
11356    pub enabled: bool,
11357    /// Position generation frequency.
11358    #[serde(default = "default_cash_frequency")]
11359    pub frequency: String,
11360    /// Minimum cash balance policy threshold.
11361    #[serde(default = "default_minimum_balance_policy")]
11362    pub minimum_balance_policy: f64,
11363}
11364
11365fn default_cash_frequency() -> String {
11366    "daily".to_string()
11367}
11368
11369fn default_minimum_balance_policy() -> f64 {
11370    100_000.0
11371}
11372
11373impl Default for CashPositioningConfig {
11374    fn default() -> Self {
11375        Self {
11376            enabled: true,
11377            frequency: default_cash_frequency(),
11378            minimum_balance_policy: default_minimum_balance_policy(),
11379        }
11380    }
11381}
11382
11383/// Cash forecasting configuration.
11384///
11385/// Controls forward-looking cash forecast generation with probability-weighted items.
11386#[derive(Debug, Clone, Serialize, Deserialize)]
11387pub struct CashForecastingConfig {
11388    /// Whether cash forecasting is enabled.
11389    #[serde(default = "default_true")]
11390    pub enabled: bool,
11391    /// Number of days to forecast into the future.
11392    #[serde(default = "default_horizon_days")]
11393    pub horizon_days: u32,
11394    /// AR collection probability curve type ("aging" or "flat").
11395    #[serde(default = "default_ar_probability_curve")]
11396    pub ar_collection_probability_curve: String,
11397    /// Confidence interval for the forecast (0.0 to 1.0).
11398    #[serde(default = "default_confidence_interval")]
11399    pub confidence_interval: f64,
11400}
11401
11402fn default_horizon_days() -> u32 {
11403    90
11404}
11405
11406fn default_ar_probability_curve() -> String {
11407    "aging".to_string()
11408}
11409
11410fn default_confidence_interval() -> f64 {
11411    0.90
11412}
11413
11414impl Default for CashForecastingConfig {
11415    fn default() -> Self {
11416        Self {
11417            enabled: true,
11418            horizon_days: default_horizon_days(),
11419            ar_collection_probability_curve: default_ar_probability_curve(),
11420            confidence_interval: default_confidence_interval(),
11421        }
11422    }
11423}
11424
11425/// Cash pooling configuration.
11426///
11427/// Controls cash pool structure generation (physical, notional, zero-balancing).
11428#[derive(Debug, Clone, Serialize, Deserialize)]
11429pub struct CashPoolingConfig {
11430    /// Whether cash pooling is enabled.
11431    #[serde(default)]
11432    pub enabled: bool,
11433    /// Pool type: "physical_pooling", "notional_pooling", or "zero_balancing".
11434    #[serde(default = "default_pool_type")]
11435    pub pool_type: String,
11436    /// Time of day when sweeps occur (HH:MM format).
11437    #[serde(default = "default_sweep_time")]
11438    pub sweep_time: String,
11439}
11440
11441fn default_pool_type() -> String {
11442    "zero_balancing".to_string()
11443}
11444
11445fn default_sweep_time() -> String {
11446    "16:00".to_string()
11447}
11448
11449impl Default for CashPoolingConfig {
11450    fn default() -> Self {
11451        Self {
11452            enabled: false,
11453            pool_type: default_pool_type(),
11454            sweep_time: default_sweep_time(),
11455        }
11456    }
11457}
11458
11459/// Hedging configuration.
11460///
11461/// Controls generation of hedging instruments and hedge relationship designations
11462/// under ASC 815 / IFRS 9.
11463#[derive(Debug, Clone, Serialize, Deserialize)]
11464pub struct HedgingSchemaConfig {
11465    /// Whether hedging generation is enabled.
11466    #[serde(default)]
11467    pub enabled: bool,
11468    /// Target hedge ratio (0.0 to 1.0). Proportion of FX exposure to hedge.
11469    #[serde(default = "default_hedge_ratio")]
11470    pub hedge_ratio: f64,
11471    /// Types of instruments to generate (e.g., ["fx_forward", "interest_rate_swap"]).
11472    #[serde(default = "default_hedge_instruments")]
11473    pub instruments: Vec<String>,
11474    /// Whether to designate formal hedge accounting relationships.
11475    #[serde(default = "default_true")]
11476    pub hedge_accounting: bool,
11477    /// Effectiveness testing method: "dollar_offset", "regression", or "critical_terms".
11478    #[serde(default = "default_effectiveness_method")]
11479    pub effectiveness_method: String,
11480}
11481
11482fn default_hedge_ratio() -> f64 {
11483    0.75
11484}
11485
11486fn default_hedge_instruments() -> Vec<String> {
11487    vec!["fx_forward".to_string(), "interest_rate_swap".to_string()]
11488}
11489
11490fn default_effectiveness_method() -> String {
11491    "regression".to_string()
11492}
11493
11494impl Default for HedgingSchemaConfig {
11495    fn default() -> Self {
11496        Self {
11497            enabled: false,
11498            hedge_ratio: default_hedge_ratio(),
11499            instruments: default_hedge_instruments(),
11500            hedge_accounting: true,
11501            effectiveness_method: default_effectiveness_method(),
11502        }
11503    }
11504}
11505
11506/// Debt instrument configuration.
11507///
11508/// Controls generation of debt instruments (term loans, revolving credit, bonds)
11509/// with amortization schedules and financial covenants.
11510#[derive(Debug, Clone, Default, Serialize, Deserialize)]
11511pub struct DebtSchemaConfig {
11512    /// Whether debt instrument generation is enabled.
11513    #[serde(default)]
11514    pub enabled: bool,
11515    /// Debt instrument definitions.
11516    #[serde(default)]
11517    pub instruments: Vec<DebtInstrumentDef>,
11518    /// Covenant definitions.
11519    #[serde(default)]
11520    pub covenants: Vec<CovenantDef>,
11521}
11522
11523/// Definition of a debt instrument in configuration.
11524#[derive(Debug, Clone, Serialize, Deserialize)]
11525pub struct DebtInstrumentDef {
11526    /// Instrument type: "term_loan", "revolving_credit", "bond", "commercial_paper", "bridge_loan".
11527    #[serde(rename = "type")]
11528    pub instrument_type: String,
11529    /// Principal amount (for term loans, bonds).
11530    #[serde(default)]
11531    pub principal: Option<f64>,
11532    /// Interest rate (annual, as decimal fraction).
11533    #[serde(default)]
11534    pub rate: Option<f64>,
11535    /// Maturity in months.
11536    #[serde(default)]
11537    pub maturity_months: Option<u32>,
11538    /// Facility limit (for revolving credit).
11539    #[serde(default)]
11540    pub facility: Option<f64>,
11541}
11542
11543/// Definition of a debt covenant in configuration.
11544#[derive(Debug, Clone, Serialize, Deserialize)]
11545pub struct CovenantDef {
11546    /// Covenant type: "debt_to_equity", "interest_coverage", "current_ratio",
11547    /// "net_worth", "debt_to_ebitda", "fixed_charge_coverage".
11548    #[serde(rename = "type")]
11549    pub covenant_type: String,
11550    /// Covenant threshold value.
11551    pub threshold: f64,
11552}
11553
11554/// Intercompany netting configuration.
11555///
11556/// Controls generation of multilateral netting runs.
11557#[derive(Debug, Clone, Serialize, Deserialize)]
11558pub struct NettingSchemaConfig {
11559    /// Whether netting generation is enabled.
11560    #[serde(default)]
11561    pub enabled: bool,
11562    /// Netting cycle: "daily", "weekly", or "monthly".
11563    #[serde(default = "default_netting_cycle")]
11564    pub cycle: String,
11565}
11566
11567fn default_netting_cycle() -> String {
11568    "monthly".to_string()
11569}
11570
11571impl Default for NettingSchemaConfig {
11572    fn default() -> Self {
11573        Self {
11574            enabled: false,
11575            cycle: default_netting_cycle(),
11576        }
11577    }
11578}
11579
11580/// Bank guarantee and letter of credit configuration.
11581///
11582/// Controls generation of bank guarantees, standby LCs, and performance bonds.
11583#[derive(Debug, Clone, Serialize, Deserialize)]
11584pub struct BankGuaranteeSchemaConfig {
11585    /// Whether bank guarantee generation is enabled.
11586    #[serde(default)]
11587    pub enabled: bool,
11588    /// Number of guarantees to generate.
11589    #[serde(default = "default_guarantee_count")]
11590    pub count: u32,
11591}
11592
11593fn default_guarantee_count() -> u32 {
11594    5
11595}
11596
11597impl Default for BankGuaranteeSchemaConfig {
11598    fn default() -> Self {
11599        Self {
11600            enabled: false,
11601            count: default_guarantee_count(),
11602        }
11603    }
11604}
11605
11606// ===========================================================================
11607// Project Accounting Configuration
11608// ===========================================================================
11609
11610/// Project accounting configuration.
11611///
11612/// Controls generation of project cost lines, revenue recognition,
11613/// milestones, change orders, retainage, and earned value metrics.
11614#[derive(Debug, Clone, Serialize, Deserialize)]
11615pub struct ProjectAccountingConfig {
11616    /// Whether project accounting is enabled.
11617    #[serde(default)]
11618    pub enabled: bool,
11619    /// Number of projects to generate.
11620    #[serde(default = "default_project_count")]
11621    pub project_count: u32,
11622    /// Distribution of project types (capital, internal, customer, r_and_d, maintenance, technology).
11623    #[serde(default)]
11624    pub project_types: ProjectTypeDistribution,
11625    /// WBS structure configuration.
11626    #[serde(default)]
11627    pub wbs: WbsSchemaConfig,
11628    /// Cost allocation rates (what % of source documents get project-tagged).
11629    #[serde(default)]
11630    pub cost_allocation: CostAllocationConfig,
11631    /// Revenue recognition configuration for project accounting.
11632    #[serde(default)]
11633    pub revenue_recognition: ProjectRevenueRecognitionConfig,
11634    /// Milestone configuration.
11635    #[serde(default)]
11636    pub milestones: MilestoneSchemaConfig,
11637    /// Change order configuration.
11638    #[serde(default)]
11639    pub change_orders: ChangeOrderSchemaConfig,
11640    /// Retainage configuration.
11641    #[serde(default)]
11642    pub retainage: RetainageSchemaConfig,
11643    /// Earned value management configuration.
11644    #[serde(default)]
11645    pub earned_value: EarnedValueSchemaConfig,
11646    /// Anomaly injection rate for project accounting data (0.0 to 1.0).
11647    #[serde(default = "default_project_anomaly_rate")]
11648    pub anomaly_rate: f64,
11649}
11650
11651fn default_project_count() -> u32 {
11652    10
11653}
11654
11655fn default_project_anomaly_rate() -> f64 {
11656    0.03
11657}
11658
11659impl Default for ProjectAccountingConfig {
11660    fn default() -> Self {
11661        Self {
11662            enabled: false,
11663            project_count: default_project_count(),
11664            project_types: ProjectTypeDistribution::default(),
11665            wbs: WbsSchemaConfig::default(),
11666            cost_allocation: CostAllocationConfig::default(),
11667            revenue_recognition: ProjectRevenueRecognitionConfig::default(),
11668            milestones: MilestoneSchemaConfig::default(),
11669            change_orders: ChangeOrderSchemaConfig::default(),
11670            retainage: RetainageSchemaConfig::default(),
11671            earned_value: EarnedValueSchemaConfig::default(),
11672            anomaly_rate: default_project_anomaly_rate(),
11673        }
11674    }
11675}
11676
11677/// Distribution of project types by weight.
11678#[derive(Debug, Clone, Serialize, Deserialize)]
11679pub struct ProjectTypeDistribution {
11680    /// Weight for capital projects (default 0.25).
11681    #[serde(default = "default_capital_weight")]
11682    pub capital: f64,
11683    /// Weight for internal projects (default 0.20).
11684    #[serde(default = "default_internal_weight")]
11685    pub internal: f64,
11686    /// Weight for customer projects (default 0.30).
11687    #[serde(default = "default_customer_weight")]
11688    pub customer: f64,
11689    /// Weight for R&D projects (default 0.10).
11690    #[serde(default = "default_rnd_weight")]
11691    pub r_and_d: f64,
11692    /// Weight for maintenance projects (default 0.10).
11693    #[serde(default = "default_maintenance_weight")]
11694    pub maintenance: f64,
11695    /// Weight for technology projects (default 0.05).
11696    #[serde(default = "default_technology_weight")]
11697    pub technology: f64,
11698}
11699
11700fn default_capital_weight() -> f64 {
11701    0.25
11702}
11703fn default_internal_weight() -> f64 {
11704    0.20
11705}
11706fn default_customer_weight() -> f64 {
11707    0.30
11708}
11709fn default_rnd_weight() -> f64 {
11710    0.10
11711}
11712fn default_maintenance_weight() -> f64 {
11713    0.10
11714}
11715fn default_technology_weight() -> f64 {
11716    0.05
11717}
11718
11719impl Default for ProjectTypeDistribution {
11720    fn default() -> Self {
11721        Self {
11722            capital: default_capital_weight(),
11723            internal: default_internal_weight(),
11724            customer: default_customer_weight(),
11725            r_and_d: default_rnd_weight(),
11726            maintenance: default_maintenance_weight(),
11727            technology: default_technology_weight(),
11728        }
11729    }
11730}
11731
11732/// WBS structure configuration.
11733#[derive(Debug, Clone, Serialize, Deserialize)]
11734pub struct WbsSchemaConfig {
11735    /// Maximum depth of WBS hierarchy (default 3).
11736    #[serde(default = "default_wbs_max_depth")]
11737    pub max_depth: u32,
11738    /// Minimum elements per level-1 WBS (default 2).
11739    #[serde(default = "default_wbs_min_elements")]
11740    pub min_elements_per_level: u32,
11741    /// Maximum elements per level-1 WBS (default 6).
11742    #[serde(default = "default_wbs_max_elements")]
11743    pub max_elements_per_level: u32,
11744}
11745
11746fn default_wbs_max_depth() -> u32 {
11747    3
11748}
11749fn default_wbs_min_elements() -> u32 {
11750    2
11751}
11752fn default_wbs_max_elements() -> u32 {
11753    6
11754}
11755
11756impl Default for WbsSchemaConfig {
11757    fn default() -> Self {
11758        Self {
11759            max_depth: default_wbs_max_depth(),
11760            min_elements_per_level: default_wbs_min_elements(),
11761            max_elements_per_level: default_wbs_max_elements(),
11762        }
11763    }
11764}
11765
11766/// Cost allocation rates — what fraction of each document type gets linked to a project.
11767#[derive(Debug, Clone, Serialize, Deserialize)]
11768pub struct CostAllocationConfig {
11769    /// Fraction of time entries assigned to projects (0.0 to 1.0).
11770    #[serde(default = "default_time_entry_rate")]
11771    pub time_entry_project_rate: f64,
11772    /// Fraction of expense reports assigned to projects (0.0 to 1.0).
11773    #[serde(default = "default_expense_rate")]
11774    pub expense_project_rate: f64,
11775    /// Fraction of purchase orders assigned to projects (0.0 to 1.0).
11776    #[serde(default = "default_po_rate")]
11777    pub purchase_order_project_rate: f64,
11778    /// Fraction of vendor invoices assigned to projects (0.0 to 1.0).
11779    #[serde(default = "default_vi_rate")]
11780    pub vendor_invoice_project_rate: f64,
11781}
11782
11783fn default_time_entry_rate() -> f64 {
11784    0.60
11785}
11786fn default_expense_rate() -> f64 {
11787    0.30
11788}
11789fn default_po_rate() -> f64 {
11790    0.40
11791}
11792fn default_vi_rate() -> f64 {
11793    0.35
11794}
11795
11796impl Default for CostAllocationConfig {
11797    fn default() -> Self {
11798        Self {
11799            time_entry_project_rate: default_time_entry_rate(),
11800            expense_project_rate: default_expense_rate(),
11801            purchase_order_project_rate: default_po_rate(),
11802            vendor_invoice_project_rate: default_vi_rate(),
11803        }
11804    }
11805}
11806
11807/// Revenue recognition configuration for project accounting.
11808#[derive(Debug, Clone, Serialize, Deserialize)]
11809pub struct ProjectRevenueRecognitionConfig {
11810    /// Whether revenue recognition is enabled for customer projects.
11811    #[serde(default = "default_true")]
11812    pub enabled: bool,
11813    /// Default method: "percentage_of_completion", "completed_contract", "milestone_based".
11814    #[serde(default = "default_revenue_method")]
11815    pub method: String,
11816    /// Default completion measure: "cost_to_cost", "labor_hours", "physical_completion".
11817    #[serde(default = "default_completion_measure")]
11818    pub completion_measure: String,
11819    /// Average contract value for customer projects.
11820    #[serde(default = "default_avg_contract_value")]
11821    pub avg_contract_value: f64,
11822}
11823
11824fn default_revenue_method() -> String {
11825    "percentage_of_completion".to_string()
11826}
11827fn default_completion_measure() -> String {
11828    "cost_to_cost".to_string()
11829}
11830fn default_avg_contract_value() -> f64 {
11831    500_000.0
11832}
11833
11834impl Default for ProjectRevenueRecognitionConfig {
11835    fn default() -> Self {
11836        Self {
11837            enabled: true,
11838            method: default_revenue_method(),
11839            completion_measure: default_completion_measure(),
11840            avg_contract_value: default_avg_contract_value(),
11841        }
11842    }
11843}
11844
11845/// Milestone configuration.
11846#[derive(Debug, Clone, Serialize, Deserialize)]
11847pub struct MilestoneSchemaConfig {
11848    /// Whether milestone generation is enabled.
11849    #[serde(default = "default_true")]
11850    pub enabled: bool,
11851    /// Average number of milestones per project.
11852    #[serde(default = "default_milestones_per_project")]
11853    pub avg_per_project: u32,
11854    /// Fraction of milestones that are payment milestones (0.0 to 1.0).
11855    #[serde(default = "default_payment_milestone_rate")]
11856    pub payment_milestone_rate: f64,
11857}
11858
11859fn default_milestones_per_project() -> u32 {
11860    4
11861}
11862fn default_payment_milestone_rate() -> f64 {
11863    0.50
11864}
11865
11866impl Default for MilestoneSchemaConfig {
11867    fn default() -> Self {
11868        Self {
11869            enabled: true,
11870            avg_per_project: default_milestones_per_project(),
11871            payment_milestone_rate: default_payment_milestone_rate(),
11872        }
11873    }
11874}
11875
11876/// Change order configuration.
11877#[derive(Debug, Clone, Serialize, Deserialize)]
11878pub struct ChangeOrderSchemaConfig {
11879    /// Whether change order generation is enabled.
11880    #[serde(default = "default_true")]
11881    pub enabled: bool,
11882    /// Probability that a project will have at least one change order (0.0 to 1.0).
11883    #[serde(default = "default_change_order_probability")]
11884    pub probability: f64,
11885    /// Maximum change orders per project.
11886    #[serde(default = "default_max_change_orders")]
11887    pub max_per_project: u32,
11888    /// Approval rate for change orders (0.0 to 1.0).
11889    #[serde(default = "default_change_order_approval_rate")]
11890    pub approval_rate: f64,
11891}
11892
11893fn default_change_order_probability() -> f64 {
11894    0.40
11895}
11896fn default_max_change_orders() -> u32 {
11897    3
11898}
11899fn default_change_order_approval_rate() -> f64 {
11900    0.75
11901}
11902
11903impl Default for ChangeOrderSchemaConfig {
11904    fn default() -> Self {
11905        Self {
11906            enabled: true,
11907            probability: default_change_order_probability(),
11908            max_per_project: default_max_change_orders(),
11909            approval_rate: default_change_order_approval_rate(),
11910        }
11911    }
11912}
11913
11914/// Retainage configuration.
11915#[derive(Debug, Clone, Serialize, Deserialize)]
11916pub struct RetainageSchemaConfig {
11917    /// Whether retainage is enabled.
11918    #[serde(default)]
11919    pub enabled: bool,
11920    /// Default retainage percentage (0.0 to 1.0, e.g., 0.10 for 10%).
11921    #[serde(default = "default_retainage_pct")]
11922    pub default_percentage: f64,
11923}
11924
11925fn default_retainage_pct() -> f64 {
11926    0.10
11927}
11928
11929impl Default for RetainageSchemaConfig {
11930    fn default() -> Self {
11931        Self {
11932            enabled: false,
11933            default_percentage: default_retainage_pct(),
11934        }
11935    }
11936}
11937
11938/// Earned value management (EVM) configuration.
11939#[derive(Debug, Clone, Serialize, Deserialize)]
11940pub struct EarnedValueSchemaConfig {
11941    /// Whether EVM metrics are generated.
11942    #[serde(default = "default_true")]
11943    pub enabled: bool,
11944    /// Measurement frequency: "weekly", "biweekly", "monthly".
11945    #[serde(default = "default_evm_frequency")]
11946    pub frequency: String,
11947}
11948
11949fn default_evm_frequency() -> String {
11950    "monthly".to_string()
11951}
11952
11953impl Default for EarnedValueSchemaConfig {
11954    fn default() -> Self {
11955        Self {
11956            enabled: true,
11957            frequency: default_evm_frequency(),
11958        }
11959    }
11960}
11961
11962// =============================================================================
11963// ESG / Sustainability Configuration
11964// =============================================================================
11965
11966/// Top-level ESG / sustainability reporting configuration.
11967#[derive(Debug, Clone, Serialize, Deserialize)]
11968pub struct EsgConfig {
11969    /// Whether ESG generation is enabled.
11970    #[serde(default)]
11971    pub enabled: bool,
11972    /// Environmental metrics (emissions, energy, water, waste).
11973    #[serde(default)]
11974    pub environmental: EnvironmentalConfig,
11975    /// Social metrics (diversity, pay equity, safety).
11976    #[serde(default)]
11977    pub social: SocialConfig,
11978    /// Governance metrics (board composition, ethics, compliance).
11979    #[serde(default)]
11980    pub governance: GovernanceSchemaConfig,
11981    /// Supply-chain ESG assessment settings.
11982    #[serde(default)]
11983    pub supply_chain_esg: SupplyChainEsgConfig,
11984    /// ESG reporting / disclosure framework settings.
11985    #[serde(default)]
11986    pub reporting: EsgReportingConfig,
11987    /// Climate scenario analysis settings.
11988    #[serde(default)]
11989    pub climate_scenarios: ClimateScenarioConfig,
11990    /// Anomaly injection rate for ESG data (0.0 to 1.0).
11991    #[serde(default = "default_esg_anomaly_rate")]
11992    pub anomaly_rate: f64,
11993}
11994
11995fn default_esg_anomaly_rate() -> f64 {
11996    0.02
11997}
11998
11999impl Default for EsgConfig {
12000    fn default() -> Self {
12001        Self {
12002            enabled: false,
12003            environmental: EnvironmentalConfig::default(),
12004            social: SocialConfig::default(),
12005            governance: GovernanceSchemaConfig::default(),
12006            supply_chain_esg: SupplyChainEsgConfig::default(),
12007            reporting: EsgReportingConfig::default(),
12008            climate_scenarios: ClimateScenarioConfig::default(),
12009            anomaly_rate: default_esg_anomaly_rate(),
12010        }
12011    }
12012}
12013
12014/// Country pack configuration.
12015///
12016/// Controls where to load additional country packs and per-country overrides.
12017/// When omitted, only the built-in packs (_default, US, DE, GB) are used.
12018#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12019pub struct CountryPacksSchemaConfig {
12020    /// Optional directory containing additional `*.json` country packs.
12021    #[serde(default)]
12022    pub external_dir: Option<PathBuf>,
12023    /// Per-country overrides applied after loading.
12024    /// Keys are ISO 3166-1 alpha-2 codes; values are partial JSON objects
12025    /// that are deep-merged on top of the loaded pack.
12026    #[serde(default)]
12027    pub overrides: std::collections::HashMap<String, serde_json::Value>,
12028}
12029
12030/// Environmental metrics configuration.
12031#[derive(Debug, Clone, Serialize, Deserialize)]
12032pub struct EnvironmentalConfig {
12033    /// Whether environmental metrics are generated.
12034    #[serde(default = "default_true")]
12035    pub enabled: bool,
12036    /// Scope 1 (direct) emission generation settings.
12037    #[serde(default)]
12038    pub scope1: EmissionScopeConfig,
12039    /// Scope 2 (purchased energy) emission generation settings.
12040    #[serde(default)]
12041    pub scope2: EmissionScopeConfig,
12042    /// Scope 3 (value chain) emission generation settings.
12043    #[serde(default)]
12044    pub scope3: Scope3Config,
12045    /// Energy consumption tracking settings.
12046    #[serde(default)]
12047    pub energy: EnergySchemaConfig,
12048    /// Water usage tracking settings.
12049    #[serde(default)]
12050    pub water: WaterSchemaConfig,
12051    /// Waste management tracking settings.
12052    #[serde(default)]
12053    pub waste: WasteSchemaConfig,
12054}
12055
12056impl Default for EnvironmentalConfig {
12057    fn default() -> Self {
12058        Self {
12059            enabled: true,
12060            scope1: EmissionScopeConfig::default(),
12061            scope2: EmissionScopeConfig::default(),
12062            scope3: Scope3Config::default(),
12063            energy: EnergySchemaConfig::default(),
12064            water: WaterSchemaConfig::default(),
12065            waste: WasteSchemaConfig::default(),
12066        }
12067    }
12068}
12069
12070/// Configuration for a single emission scope (Scope 1 or 2).
12071#[derive(Debug, Clone, Serialize, Deserialize)]
12072pub struct EmissionScopeConfig {
12073    /// Whether this scope is enabled.
12074    #[serde(default = "default_true")]
12075    pub enabled: bool,
12076    /// Emission factor region (e.g., "US", "EU", "global").
12077    #[serde(default = "default_emission_region")]
12078    pub factor_region: String,
12079}
12080
12081fn default_emission_region() -> String {
12082    "US".to_string()
12083}
12084
12085impl Default for EmissionScopeConfig {
12086    fn default() -> Self {
12087        Self {
12088            enabled: true,
12089            factor_region: default_emission_region(),
12090        }
12091    }
12092}
12093
12094/// Scope 3 (value chain) emission configuration.
12095#[derive(Debug, Clone, Serialize, Deserialize)]
12096pub struct Scope3Config {
12097    /// Whether Scope 3 emissions are generated.
12098    #[serde(default = "default_true")]
12099    pub enabled: bool,
12100    /// Categories to include (e.g., "purchased_goods", "business_travel", "commuting").
12101    #[serde(default = "default_scope3_categories")]
12102    pub categories: Vec<String>,
12103    /// Spend-based emission intensity (kg CO2e per USD).
12104    #[serde(default = "default_spend_intensity")]
12105    pub default_spend_intensity_kg_per_usd: f64,
12106}
12107
12108fn default_scope3_categories() -> Vec<String> {
12109    vec![
12110        "purchased_goods".to_string(),
12111        "business_travel".to_string(),
12112        "employee_commuting".to_string(),
12113    ]
12114}
12115
12116fn default_spend_intensity() -> f64 {
12117    0.5
12118}
12119
12120impl Default for Scope3Config {
12121    fn default() -> Self {
12122        Self {
12123            enabled: true,
12124            categories: default_scope3_categories(),
12125            default_spend_intensity_kg_per_usd: default_spend_intensity(),
12126        }
12127    }
12128}
12129
12130/// Energy consumption configuration.
12131#[derive(Debug, Clone, Serialize, Deserialize)]
12132pub struct EnergySchemaConfig {
12133    /// Whether energy consumption tracking is enabled.
12134    #[serde(default = "default_true")]
12135    pub enabled: bool,
12136    /// Number of facilities to generate.
12137    #[serde(default = "default_facility_count")]
12138    pub facility_count: u32,
12139    /// Target percentage of energy from renewable sources (0.0 to 1.0).
12140    #[serde(default = "default_renewable_target")]
12141    pub renewable_target: f64,
12142}
12143
12144fn default_facility_count() -> u32 {
12145    5
12146}
12147
12148fn default_renewable_target() -> f64 {
12149    0.30
12150}
12151
12152impl Default for EnergySchemaConfig {
12153    fn default() -> Self {
12154        Self {
12155            enabled: true,
12156            facility_count: default_facility_count(),
12157            renewable_target: default_renewable_target(),
12158        }
12159    }
12160}
12161
12162/// Water usage configuration.
12163#[derive(Debug, Clone, Serialize, Deserialize)]
12164pub struct WaterSchemaConfig {
12165    /// Whether water usage tracking is enabled.
12166    #[serde(default = "default_true")]
12167    pub enabled: bool,
12168    /// Number of facilities with water tracking.
12169    #[serde(default = "default_water_facility_count")]
12170    pub facility_count: u32,
12171}
12172
12173fn default_water_facility_count() -> u32 {
12174    3
12175}
12176
12177impl Default for WaterSchemaConfig {
12178    fn default() -> Self {
12179        Self {
12180            enabled: true,
12181            facility_count: default_water_facility_count(),
12182        }
12183    }
12184}
12185
12186/// Waste management configuration.
12187#[derive(Debug, Clone, Serialize, Deserialize)]
12188pub struct WasteSchemaConfig {
12189    /// Whether waste tracking is enabled.
12190    #[serde(default = "default_true")]
12191    pub enabled: bool,
12192    /// Target diversion rate (0.0 to 1.0).
12193    #[serde(default = "default_diversion_target")]
12194    pub diversion_target: f64,
12195}
12196
12197fn default_diversion_target() -> f64 {
12198    0.50
12199}
12200
12201impl Default for WasteSchemaConfig {
12202    fn default() -> Self {
12203        Self {
12204            enabled: true,
12205            diversion_target: default_diversion_target(),
12206        }
12207    }
12208}
12209
12210/// Social metrics configuration.
12211#[derive(Debug, Clone, Serialize, Deserialize)]
12212pub struct SocialConfig {
12213    /// Whether social metrics are generated.
12214    #[serde(default = "default_true")]
12215    pub enabled: bool,
12216    /// Workforce diversity tracking settings.
12217    #[serde(default)]
12218    pub diversity: DiversitySchemaConfig,
12219    /// Pay equity analysis settings.
12220    #[serde(default)]
12221    pub pay_equity: PayEquitySchemaConfig,
12222    /// Safety incident and metrics settings.
12223    #[serde(default)]
12224    pub safety: SafetySchemaConfig,
12225}
12226
12227impl Default for SocialConfig {
12228    fn default() -> Self {
12229        Self {
12230            enabled: true,
12231            diversity: DiversitySchemaConfig::default(),
12232            pay_equity: PayEquitySchemaConfig::default(),
12233            safety: SafetySchemaConfig::default(),
12234        }
12235    }
12236}
12237
12238/// Workforce diversity configuration.
12239#[derive(Debug, Clone, Serialize, Deserialize)]
12240pub struct DiversitySchemaConfig {
12241    /// Whether diversity metrics are generated.
12242    #[serde(default = "default_true")]
12243    pub enabled: bool,
12244    /// Dimensions to track (e.g., "gender", "ethnicity", "age_group").
12245    #[serde(default = "default_diversity_dimensions")]
12246    pub dimensions: Vec<String>,
12247}
12248
12249fn default_diversity_dimensions() -> Vec<String> {
12250    vec![
12251        "gender".to_string(),
12252        "ethnicity".to_string(),
12253        "age_group".to_string(),
12254    ]
12255}
12256
12257impl Default for DiversitySchemaConfig {
12258    fn default() -> Self {
12259        Self {
12260            enabled: true,
12261            dimensions: default_diversity_dimensions(),
12262        }
12263    }
12264}
12265
12266/// Pay equity analysis configuration.
12267#[derive(Debug, Clone, Serialize, Deserialize)]
12268pub struct PayEquitySchemaConfig {
12269    /// Whether pay equity analysis is generated.
12270    #[serde(default = "default_true")]
12271    pub enabled: bool,
12272    /// Target pay gap threshold for flagging (e.g., 0.05 = 5% gap).
12273    #[serde(default = "default_pay_gap_threshold")]
12274    pub gap_threshold: f64,
12275}
12276
12277fn default_pay_gap_threshold() -> f64 {
12278    0.05
12279}
12280
12281impl Default for PayEquitySchemaConfig {
12282    fn default() -> Self {
12283        Self {
12284            enabled: true,
12285            gap_threshold: default_pay_gap_threshold(),
12286        }
12287    }
12288}
12289
12290/// Safety metrics configuration.
12291#[derive(Debug, Clone, Serialize, Deserialize)]
12292pub struct SafetySchemaConfig {
12293    /// Whether safety metrics are generated.
12294    #[serde(default = "default_true")]
12295    pub enabled: bool,
12296    /// Average annual recordable incidents per 200,000 hours.
12297    #[serde(default = "default_trir_target")]
12298    pub target_trir: f64,
12299    /// Number of safety incidents to generate.
12300    #[serde(default = "default_incident_count")]
12301    pub incident_count: u32,
12302}
12303
12304fn default_trir_target() -> f64 {
12305    2.5
12306}
12307
12308fn default_incident_count() -> u32 {
12309    20
12310}
12311
12312impl Default for SafetySchemaConfig {
12313    fn default() -> Self {
12314        Self {
12315            enabled: true,
12316            target_trir: default_trir_target(),
12317            incident_count: default_incident_count(),
12318        }
12319    }
12320}
12321
12322/// Governance metrics configuration.
12323#[derive(Debug, Clone, Serialize, Deserialize)]
12324pub struct GovernanceSchemaConfig {
12325    /// Whether governance metrics are generated.
12326    #[serde(default = "default_true")]
12327    pub enabled: bool,
12328    /// Number of board members.
12329    #[serde(default = "default_board_size")]
12330    pub board_size: u32,
12331    /// Target independent director ratio (0.0 to 1.0).
12332    #[serde(default = "default_independence_target")]
12333    pub independence_target: f64,
12334}
12335
12336fn default_board_size() -> u32 {
12337    11
12338}
12339
12340fn default_independence_target() -> f64 {
12341    0.67
12342}
12343
12344impl Default for GovernanceSchemaConfig {
12345    fn default() -> Self {
12346        Self {
12347            enabled: true,
12348            board_size: default_board_size(),
12349            independence_target: default_independence_target(),
12350        }
12351    }
12352}
12353
12354/// Supply-chain ESG assessment configuration.
12355#[derive(Debug, Clone, Serialize, Deserialize)]
12356pub struct SupplyChainEsgConfig {
12357    /// Whether supply chain ESG assessments are generated.
12358    #[serde(default = "default_true")]
12359    pub enabled: bool,
12360    /// Proportion of vendors to assess (0.0 to 1.0).
12361    #[serde(default = "default_assessment_coverage")]
12362    pub assessment_coverage: f64,
12363    /// High-risk country codes for automatic flagging.
12364    #[serde(default = "default_high_risk_countries")]
12365    pub high_risk_countries: Vec<String>,
12366}
12367
12368fn default_assessment_coverage() -> f64 {
12369    0.80
12370}
12371
12372fn default_high_risk_countries() -> Vec<String> {
12373    vec!["CN".to_string(), "BD".to_string(), "MM".to_string()]
12374}
12375
12376impl Default for SupplyChainEsgConfig {
12377    fn default() -> Self {
12378        Self {
12379            enabled: true,
12380            assessment_coverage: default_assessment_coverage(),
12381            high_risk_countries: default_high_risk_countries(),
12382        }
12383    }
12384}
12385
12386/// ESG reporting / disclosure framework configuration.
12387#[derive(Debug, Clone, Serialize, Deserialize)]
12388pub struct EsgReportingConfig {
12389    /// Whether ESG disclosures are generated.
12390    #[serde(default = "default_true")]
12391    pub enabled: bool,
12392    /// Frameworks to generate disclosures for.
12393    #[serde(default = "default_esg_frameworks")]
12394    pub frameworks: Vec<String>,
12395    /// Whether materiality assessment is performed.
12396    #[serde(default = "default_true")]
12397    pub materiality_assessment: bool,
12398    /// Materiality threshold for impact dimension (0.0 to 1.0).
12399    #[serde(default = "default_materiality_threshold")]
12400    pub impact_threshold: f64,
12401    /// Materiality threshold for financial dimension (0.0 to 1.0).
12402    #[serde(default = "default_materiality_threshold")]
12403    pub financial_threshold: f64,
12404}
12405
12406fn default_esg_frameworks() -> Vec<String> {
12407    vec!["GRI".to_string(), "ESRS".to_string()]
12408}
12409
12410fn default_materiality_threshold() -> f64 {
12411    0.6
12412}
12413
12414impl Default for EsgReportingConfig {
12415    fn default() -> Self {
12416        Self {
12417            enabled: true,
12418            frameworks: default_esg_frameworks(),
12419            materiality_assessment: true,
12420            impact_threshold: default_materiality_threshold(),
12421            financial_threshold: default_materiality_threshold(),
12422        }
12423    }
12424}
12425
12426/// Climate scenario analysis configuration.
12427#[derive(Debug, Clone, Serialize, Deserialize)]
12428pub struct ClimateScenarioConfig {
12429    /// Whether climate scenario analysis is generated.
12430    #[serde(default)]
12431    pub enabled: bool,
12432    /// Scenarios to model (e.g., "net_zero_2050", "stated_policies", "current_trajectory").
12433    #[serde(default = "default_climate_scenarios")]
12434    pub scenarios: Vec<String>,
12435    /// Time horizons in years to project.
12436    #[serde(default = "default_time_horizons")]
12437    pub time_horizons: Vec<u32>,
12438}
12439
12440fn default_climate_scenarios() -> Vec<String> {
12441    vec![
12442        "net_zero_2050".to_string(),
12443        "stated_policies".to_string(),
12444        "current_trajectory".to_string(),
12445    ]
12446}
12447
12448fn default_time_horizons() -> Vec<u32> {
12449    vec![5, 10, 30]
12450}
12451
12452impl Default for ClimateScenarioConfig {
12453    fn default() -> Self {
12454        Self {
12455            enabled: false,
12456            scenarios: default_climate_scenarios(),
12457            time_horizons: default_time_horizons(),
12458        }
12459    }
12460}
12461
12462// ===== Counterfactual Simulation Scenarios =====
12463
12464/// Configuration for counterfactual simulation scenarios.
12465#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12466pub struct ScenariosConfig {
12467    /// Whether scenario generation is enabled.
12468    #[serde(default)]
12469    pub enabled: bool,
12470    /// List of scenario definitions.
12471    #[serde(default)]
12472    pub scenarios: Vec<ScenarioSchemaConfig>,
12473    /// Causal model configuration.
12474    #[serde(default)]
12475    pub causal_model: CausalModelSchemaConfig,
12476    /// Default settings applied to all scenarios.
12477    #[serde(default)]
12478    pub defaults: ScenarioDefaultsConfig,
12479    /// Generate counterfactual (original, mutated) JE pairs for ML training.
12480    /// When true, the orchestrator produces paired clean/anomalous journal entries.
12481    #[serde(default)]
12482    pub generate_counterfactuals: bool,
12483}
12484
12485/// A single scenario definition in the config.
12486#[derive(Debug, Clone, Serialize, Deserialize)]
12487pub struct ScenarioSchemaConfig {
12488    /// Scenario name (must be unique).
12489    pub name: String,
12490    /// Human-readable description.
12491    #[serde(default)]
12492    pub description: String,
12493    /// Tags for categorization.
12494    #[serde(default)]
12495    pub tags: Vec<String>,
12496    /// Base scenario name (None = default config).
12497    pub base: Option<String>,
12498    /// IFRS 9-style probability weight.
12499    pub probability_weight: Option<f64>,
12500    /// List of interventions to apply.
12501    #[serde(default)]
12502    pub interventions: Vec<InterventionSchemaConfig>,
12503    /// Constraint overrides for this scenario.
12504    #[serde(default)]
12505    pub constraints: ScenarioConstraintsSchemaConfig,
12506    /// Output configuration for this scenario.
12507    #[serde(default)]
12508    pub output: ScenarioOutputSchemaConfig,
12509    /// Arbitrary metadata.
12510    #[serde(default)]
12511    pub metadata: std::collections::HashMap<String, String>,
12512}
12513
12514/// An intervention definition in the config.
12515#[derive(Debug, Clone, Serialize, Deserialize)]
12516pub struct InterventionSchemaConfig {
12517    /// Intervention type and parameters (flattened tagged enum).
12518    #[serde(flatten)]
12519    pub intervention_type: serde_json::Value,
12520    /// Timing configuration.
12521    #[serde(default)]
12522    pub timing: InterventionTimingSchemaConfig,
12523    /// Human-readable label.
12524    pub label: Option<String>,
12525    /// Priority for conflict resolution (higher wins).
12526    #[serde(default)]
12527    pub priority: u32,
12528}
12529
12530/// Timing configuration for an intervention.
12531#[derive(Debug, Clone, Serialize, Deserialize)]
12532pub struct InterventionTimingSchemaConfig {
12533    /// Month offset from start (1-indexed).
12534    #[serde(default = "default_start_month")]
12535    pub start_month: u32,
12536    /// Duration in months.
12537    pub duration_months: Option<u32>,
12538    /// Onset type: "sudden", "gradual", "oscillating", "custom".
12539    #[serde(default = "default_onset")]
12540    pub onset: String,
12541    /// Ramp period in months.
12542    pub ramp_months: Option<u32>,
12543}
12544
12545fn default_start_month() -> u32 {
12546    1
12547}
12548
12549fn default_onset() -> String {
12550    "sudden".to_string()
12551}
12552
12553impl Default for InterventionTimingSchemaConfig {
12554    fn default() -> Self {
12555        Self {
12556            start_month: 1,
12557            duration_months: None,
12558            onset: "sudden".to_string(),
12559            ramp_months: None,
12560        }
12561    }
12562}
12563
12564/// Scenario constraint overrides.
12565#[derive(Debug, Clone, Serialize, Deserialize)]
12566pub struct ScenarioConstraintsSchemaConfig {
12567    #[serde(default = "default_true")]
12568    pub preserve_accounting_identity: bool,
12569    #[serde(default = "default_true")]
12570    pub preserve_document_chains: bool,
12571    #[serde(default = "default_true")]
12572    pub preserve_period_close: bool,
12573    #[serde(default = "default_true")]
12574    pub preserve_balance_coherence: bool,
12575    #[serde(default)]
12576    pub custom: Vec<CustomConstraintSchemaConfig>,
12577}
12578
12579impl Default for ScenarioConstraintsSchemaConfig {
12580    fn default() -> Self {
12581        Self {
12582            preserve_accounting_identity: true,
12583            preserve_document_chains: true,
12584            preserve_period_close: true,
12585            preserve_balance_coherence: true,
12586            custom: Vec::new(),
12587        }
12588    }
12589}
12590
12591/// Custom constraint in config.
12592#[derive(Debug, Clone, Serialize, Deserialize)]
12593pub struct CustomConstraintSchemaConfig {
12594    pub config_path: String,
12595    pub min: Option<f64>,
12596    pub max: Option<f64>,
12597    #[serde(default)]
12598    pub description: String,
12599}
12600
12601/// Output configuration for a scenario.
12602#[derive(Debug, Clone, Serialize, Deserialize)]
12603pub struct ScenarioOutputSchemaConfig {
12604    #[serde(default = "default_true")]
12605    pub paired: bool,
12606    #[serde(default = "default_diff_formats_schema")]
12607    pub diff_formats: Vec<String>,
12608    #[serde(default)]
12609    pub diff_scope: Vec<String>,
12610}
12611
12612fn default_diff_formats_schema() -> Vec<String> {
12613    vec!["summary".to_string(), "aggregate".to_string()]
12614}
12615
12616impl Default for ScenarioOutputSchemaConfig {
12617    fn default() -> Self {
12618        Self {
12619            paired: true,
12620            diff_formats: default_diff_formats_schema(),
12621            diff_scope: Vec::new(),
12622        }
12623    }
12624}
12625
12626/// Causal model configuration.
12627#[derive(Debug, Clone, Serialize, Deserialize)]
12628pub struct CausalModelSchemaConfig {
12629    /// Preset name: "default", "minimal", or "custom".
12630    #[serde(default = "default_causal_preset")]
12631    pub preset: String,
12632    /// Custom nodes (merged with preset).
12633    #[serde(default)]
12634    pub nodes: Vec<serde_json::Value>,
12635    /// Custom edges (merged with preset).
12636    #[serde(default)]
12637    pub edges: Vec<serde_json::Value>,
12638}
12639
12640fn default_causal_preset() -> String {
12641    "default".to_string()
12642}
12643
12644impl Default for CausalModelSchemaConfig {
12645    fn default() -> Self {
12646        Self {
12647            preset: "default".to_string(),
12648            nodes: Vec::new(),
12649            edges: Vec::new(),
12650        }
12651    }
12652}
12653
12654/// Default settings applied to all scenarios.
12655#[derive(Debug, Clone, Serialize, Deserialize, Default)]
12656pub struct ScenarioDefaultsConfig {
12657    #[serde(default)]
12658    pub constraints: ScenarioConstraintsSchemaConfig,
12659    #[serde(default)]
12660    pub output: ScenarioOutputSchemaConfig,
12661}
12662
12663// =====================================================================
12664// Compliance Regulations Framework Configuration
12665// =====================================================================
12666
12667/// Top-level configuration for the compliance regulations framework.
12668///
12669/// Controls standards registry, jurisdiction profiles, temporal versioning,
12670/// audit procedure templates, compliance graph integration, and output settings.
12671///
12672/// # Example
12673///
12674/// ```yaml
12675/// compliance_regulations:
12676///   enabled: true
12677///   jurisdictions: [US, DE, GB]
12678///   reference_date: "2025-06-30"
12679///   standards_selection:
12680///     categories: [accounting, auditing, regulatory]
12681///     include: ["IFRS-16", "ASC-606"]
12682///   audit_procedures:
12683///     enabled: true
12684///     procedures_per_standard: 3
12685///   findings:
12686///     enabled: true
12687///     finding_rate: 0.05
12688///   filings:
12689///     enabled: true
12690///   graph:
12691///     enabled: true
12692///     include_compliance_nodes: true
12693///     include_compliance_edges: true
12694/// ```
12695#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12696pub struct ComplianceRegulationsConfig {
12697    /// Master switch for the compliance regulations framework.
12698    #[serde(default)]
12699    pub enabled: bool,
12700    /// Jurisdictions to generate compliance data for (ISO 3166-1 alpha-2 codes).
12701    /// If empty, inferred from company countries in the config.
12702    #[serde(default)]
12703    pub jurisdictions: Vec<String>,
12704    /// Reference date for temporal standard resolution (YYYY-MM-DD).
12705    /// Defaults to the global start_date if not set.
12706    #[serde(default)]
12707    pub reference_date: Option<String>,
12708    /// Standards selection filters.
12709    #[serde(default)]
12710    pub standards_selection: StandardsSelectionConfig,
12711    /// Audit procedure generation settings.
12712    #[serde(default)]
12713    pub audit_procedures: AuditProcedureGenConfig,
12714    /// Compliance finding generation settings.
12715    #[serde(default)]
12716    pub findings: ComplianceFindingGenConfig,
12717    /// Regulatory filing generation settings.
12718    #[serde(default)]
12719    pub filings: ComplianceFilingGenConfig,
12720    /// Compliance graph integration settings.
12721    #[serde(default)]
12722    pub graph: ComplianceGraphConfig,
12723    /// Output settings for compliance-specific files.
12724    #[serde(default)]
12725    pub output: ComplianceOutputConfig,
12726}
12727
12728/// Filters which standards are included in the generation.
12729#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12730pub struct StandardsSelectionConfig {
12731    /// Standard categories to include (accounting, auditing, regulatory, tax, esg).
12732    /// Empty = all categories.
12733    #[serde(default)]
12734    pub categories: Vec<String>,
12735    /// Explicit standard IDs to include (e.g., ["IFRS-16", "ASC-606"]).
12736    /// When non-empty, only these standards (plus mandatory ones for selected jurisdictions) are used.
12737    #[serde(default)]
12738    pub include: Vec<String>,
12739    /// Standard IDs to exclude.
12740    #[serde(default)]
12741    pub exclude: Vec<String>,
12742    /// Include superseded standards in the output (for historical analysis).
12743    #[serde(default)]
12744    pub include_superseded: bool,
12745}
12746
12747/// Configuration for audit procedure template generation.
12748#[derive(Debug, Clone, Serialize, Deserialize)]
12749pub struct AuditProcedureGenConfig {
12750    /// Whether audit procedure generation is enabled.
12751    #[serde(default)]
12752    pub enabled: bool,
12753    /// Number of procedures to generate per applicable standard.
12754    #[serde(default = "default_procedures_per_standard")]
12755    pub procedures_per_standard: usize,
12756    /// Sampling methodology: "statistical", "non_statistical", "mixed".
12757    #[serde(default = "default_sampling_method")]
12758    pub sampling_method: String,
12759    /// Confidence level for statistical sampling (0.0-1.0).
12760    #[serde(default = "default_confidence_level")]
12761    pub confidence_level: f64,
12762    /// Tolerable misstatement rate for sampling (0.0-1.0).
12763    #[serde(default = "default_tolerable_misstatement")]
12764    pub tolerable_misstatement: f64,
12765}
12766
12767fn default_procedures_per_standard() -> usize {
12768    3
12769}
12770
12771fn default_sampling_method() -> String {
12772    "statistical".to_string()
12773}
12774
12775fn default_confidence_level() -> f64 {
12776    0.95
12777}
12778
12779fn default_tolerable_misstatement() -> f64 {
12780    0.05
12781}
12782
12783impl Default for AuditProcedureGenConfig {
12784    fn default() -> Self {
12785        Self {
12786            enabled: false,
12787            procedures_per_standard: default_procedures_per_standard(),
12788            sampling_method: default_sampling_method(),
12789            confidence_level: default_confidence_level(),
12790            tolerable_misstatement: default_tolerable_misstatement(),
12791        }
12792    }
12793}
12794
12795/// Configuration for compliance finding generation.
12796#[derive(Debug, Clone, Serialize, Deserialize)]
12797pub struct ComplianceFindingGenConfig {
12798    /// Whether finding generation is enabled.
12799    #[serde(default)]
12800    pub enabled: bool,
12801    /// Rate of findings per audit procedure (0.0-1.0).
12802    #[serde(default = "default_finding_rate")]
12803    pub finding_rate: f64,
12804    /// Rate of material weakness findings among all findings (0.0-1.0).
12805    #[serde(default = "default_cr_material_weakness_rate")]
12806    pub material_weakness_rate: f64,
12807    /// Rate of significant deficiency findings among all findings (0.0-1.0).
12808    #[serde(default = "default_cr_significant_deficiency_rate")]
12809    pub significant_deficiency_rate: f64,
12810    /// Whether to generate remediation plans for findings.
12811    #[serde(default = "default_true")]
12812    pub generate_remediation: bool,
12813}
12814
12815fn default_finding_rate() -> f64 {
12816    0.05
12817}
12818
12819fn default_cr_material_weakness_rate() -> f64 {
12820    0.02
12821}
12822
12823fn default_cr_significant_deficiency_rate() -> f64 {
12824    0.08
12825}
12826
12827impl Default for ComplianceFindingGenConfig {
12828    fn default() -> Self {
12829        Self {
12830            enabled: false,
12831            finding_rate: default_finding_rate(),
12832            material_weakness_rate: default_cr_material_weakness_rate(),
12833            significant_deficiency_rate: default_cr_significant_deficiency_rate(),
12834            generate_remediation: true,
12835        }
12836    }
12837}
12838
12839/// Configuration for regulatory filing generation.
12840#[derive(Debug, Clone, Serialize, Deserialize)]
12841pub struct ComplianceFilingGenConfig {
12842    /// Whether filing generation is enabled.
12843    #[serde(default)]
12844    pub enabled: bool,
12845    /// Filing types to include (e.g., ["10-K", "10-Q", "Jahresabschluss"]).
12846    /// Empty = all applicable filings for the selected jurisdictions.
12847    #[serde(default)]
12848    pub filing_types: Vec<String>,
12849    /// Generate filing status progression (draft → filed → accepted).
12850    #[serde(default = "default_true")]
12851    pub generate_status_progression: bool,
12852}
12853
12854impl Default for ComplianceFilingGenConfig {
12855    fn default() -> Self {
12856        Self {
12857            enabled: false,
12858            filing_types: Vec::new(),
12859            generate_status_progression: true,
12860        }
12861    }
12862}
12863
12864/// Configuration for compliance graph integration.
12865#[derive(Debug, Clone, Serialize, Deserialize)]
12866pub struct ComplianceGraphConfig {
12867    /// Whether compliance graph integration is enabled.
12868    #[serde(default)]
12869    pub enabled: bool,
12870    /// Include compliance nodes (Standard, Regulation, Jurisdiction, etc.).
12871    #[serde(default = "default_true")]
12872    pub include_compliance_nodes: bool,
12873    /// Include compliance edges (MapsToStandard, TestsControl, etc.).
12874    #[serde(default = "default_true")]
12875    pub include_compliance_edges: bool,
12876    /// Include cross-reference edges between standards.
12877    #[serde(default = "default_true")]
12878    pub include_cross_references: bool,
12879    /// Include temporal supersession edges.
12880    #[serde(default)]
12881    pub include_supersession_edges: bool,
12882    /// Include edges linking standards to the GL account types they govern.
12883    #[serde(default = "default_true")]
12884    pub include_account_links: bool,
12885    /// Include edges linking standards to the internal controls that implement them.
12886    #[serde(default = "default_true")]
12887    pub include_control_links: bool,
12888    /// Include edges linking filings and jurisdictions to the originating company.
12889    #[serde(default = "default_true")]
12890    pub include_company_links: bool,
12891}
12892
12893impl Default for ComplianceGraphConfig {
12894    fn default() -> Self {
12895        Self {
12896            enabled: false,
12897            include_compliance_nodes: true,
12898            include_compliance_edges: true,
12899            include_cross_references: true,
12900            include_supersession_edges: false,
12901            include_account_links: true,
12902            include_control_links: true,
12903            include_company_links: true,
12904        }
12905    }
12906}
12907
12908/// Output settings for compliance-specific data files.
12909#[derive(Debug, Clone, Serialize, Deserialize)]
12910pub struct ComplianceOutputConfig {
12911    /// Export the standards registry catalog.
12912    #[serde(default = "default_true")]
12913    pub export_registry: bool,
12914    /// Export jurisdiction profiles.
12915    #[serde(default = "default_true")]
12916    pub export_jurisdictions: bool,
12917    /// Export cross-reference map.
12918    #[serde(default = "default_true")]
12919    pub export_cross_references: bool,
12920    /// Export temporal version history.
12921    #[serde(default)]
12922    pub export_version_history: bool,
12923}
12924
12925impl Default for ComplianceOutputConfig {
12926    fn default() -> Self {
12927        Self {
12928            export_registry: true,
12929            export_jurisdictions: true,
12930            export_cross_references: true,
12931            export_version_history: false,
12932        }
12933    }
12934}
12935
12936#[cfg(test)]
12937#[allow(clippy::unwrap_used)]
12938mod tests {
12939    use super::*;
12940    use crate::presets::demo_preset;
12941
12942    // ==========================================================================
12943    // Serialization/Deserialization Tests
12944    // ==========================================================================
12945
12946    #[test]
12947    fn test_config_yaml_roundtrip() {
12948        let config = demo_preset();
12949        let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
12950        let deserialized: GeneratorConfig =
12951            serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
12952
12953        assert_eq!(
12954            config.global.period_months,
12955            deserialized.global.period_months
12956        );
12957        assert_eq!(config.global.industry, deserialized.global.industry);
12958        assert_eq!(config.companies.len(), deserialized.companies.len());
12959        assert_eq!(config.companies[0].code, deserialized.companies[0].code);
12960    }
12961
12962    #[test]
12963    fn test_config_json_roundtrip() {
12964        // Create a config without infinity values (JSON can't serialize f64::INFINITY)
12965        let mut config = demo_preset();
12966        // Replace infinity with a large but finite value for JSON compatibility
12967        config.master_data.employees.approval_limits.executive = 1e12;
12968
12969        let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
12970        let deserialized: GeneratorConfig =
12971            serde_json::from_str(&json).expect("Failed to deserialize from JSON");
12972
12973        assert_eq!(
12974            config.global.period_months,
12975            deserialized.global.period_months
12976        );
12977        assert_eq!(config.global.industry, deserialized.global.industry);
12978        assert_eq!(config.companies.len(), deserialized.companies.len());
12979    }
12980
12981    #[test]
12982    fn test_transaction_volume_serialization() {
12983        // Test various transaction volumes serialize correctly
12984        let volumes = vec![
12985            (TransactionVolume::TenK, "ten_k"),
12986            (TransactionVolume::HundredK, "hundred_k"),
12987            (TransactionVolume::OneM, "one_m"),
12988            (TransactionVolume::TenM, "ten_m"),
12989            (TransactionVolume::HundredM, "hundred_m"),
12990        ];
12991
12992        for (volume, expected_key) in volumes {
12993            let json = serde_json::to_string(&volume).expect("Failed to serialize");
12994            assert!(
12995                json.contains(expected_key),
12996                "Expected {} in JSON: {}",
12997                expected_key,
12998                json
12999            );
13000        }
13001    }
13002
13003    #[test]
13004    fn test_transaction_volume_custom_serialization() {
13005        let volume = TransactionVolume::Custom(12345);
13006        let json = serde_json::to_string(&volume).expect("Failed to serialize");
13007        let deserialized: TransactionVolume =
13008            serde_json::from_str(&json).expect("Failed to deserialize");
13009        assert_eq!(deserialized.count(), 12345);
13010    }
13011
13012    #[test]
13013    fn test_output_mode_serialization() {
13014        let modes = vec![
13015            OutputMode::Streaming,
13016            OutputMode::FlatFile,
13017            OutputMode::Both,
13018        ];
13019
13020        for mode in modes {
13021            let json = serde_json::to_string(&mode).expect("Failed to serialize");
13022            let deserialized: OutputMode =
13023                serde_json::from_str(&json).expect("Failed to deserialize");
13024            assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
13025        }
13026    }
13027
13028    #[test]
13029    fn test_file_format_serialization() {
13030        let formats = vec![
13031            FileFormat::Csv,
13032            FileFormat::Parquet,
13033            FileFormat::Json,
13034            FileFormat::JsonLines,
13035        ];
13036
13037        for format in formats {
13038            let json = serde_json::to_string(&format).expect("Failed to serialize");
13039            let deserialized: FileFormat =
13040                serde_json::from_str(&json).expect("Failed to deserialize");
13041            assert!(format!("{:?}", format) == format!("{:?}", deserialized));
13042        }
13043    }
13044
13045    #[test]
13046    fn test_compression_algorithm_serialization() {
13047        let algos = vec![
13048            CompressionAlgorithm::Gzip,
13049            CompressionAlgorithm::Zstd,
13050            CompressionAlgorithm::Lz4,
13051            CompressionAlgorithm::Snappy,
13052        ];
13053
13054        for algo in algos {
13055            let json = serde_json::to_string(&algo).expect("Failed to serialize");
13056            let deserialized: CompressionAlgorithm =
13057                serde_json::from_str(&json).expect("Failed to deserialize");
13058            assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
13059        }
13060    }
13061
13062    #[test]
13063    fn test_transfer_pricing_method_serialization() {
13064        let methods = vec![
13065            TransferPricingMethod::CostPlus,
13066            TransferPricingMethod::ComparableUncontrolled,
13067            TransferPricingMethod::ResalePrice,
13068            TransferPricingMethod::TransactionalNetMargin,
13069            TransferPricingMethod::ProfitSplit,
13070        ];
13071
13072        for method in methods {
13073            let json = serde_json::to_string(&method).expect("Failed to serialize");
13074            let deserialized: TransferPricingMethod =
13075                serde_json::from_str(&json).expect("Failed to deserialize");
13076            assert!(format!("{:?}", method) == format!("{:?}", deserialized));
13077        }
13078    }
13079
13080    #[test]
13081    fn test_benford_exemption_serialization() {
13082        let exemptions = vec![
13083            BenfordExemption::Recurring,
13084            BenfordExemption::Payroll,
13085            BenfordExemption::FixedFees,
13086            BenfordExemption::RoundAmounts,
13087        ];
13088
13089        for exemption in exemptions {
13090            let json = serde_json::to_string(&exemption).expect("Failed to serialize");
13091            let deserialized: BenfordExemption =
13092                serde_json::from_str(&json).expect("Failed to deserialize");
13093            assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
13094        }
13095    }
13096
13097    // ==========================================================================
13098    // Default Value Tests
13099    // ==========================================================================
13100
13101    #[test]
13102    fn test_global_config_defaults() {
13103        let yaml = r#"
13104            industry: manufacturing
13105            start_date: "2024-01-01"
13106            period_months: 6
13107        "#;
13108        let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13109        assert_eq!(config.group_currency, "USD");
13110        assert!(config.parallel);
13111        assert_eq!(config.worker_threads, 0);
13112        assert_eq!(config.memory_limit_mb, 0);
13113    }
13114
13115    #[test]
13116    fn test_fraud_config_defaults() {
13117        let config = FraudConfig::default();
13118        assert!(!config.enabled);
13119        assert_eq!(config.fraud_rate, 0.005);
13120        assert!(!config.clustering_enabled);
13121    }
13122
13123    #[test]
13124    fn test_internal_controls_config_defaults() {
13125        let config = InternalControlsConfig::default();
13126        assert!(!config.enabled);
13127        assert_eq!(config.exception_rate, 0.02);
13128        assert_eq!(config.sod_violation_rate, 0.01);
13129        assert!(config.export_control_master_data);
13130        assert_eq!(config.sox_materiality_threshold, 10000.0);
13131        // COSO fields
13132        assert!(config.coso_enabled);
13133        assert!(!config.include_entity_level_controls);
13134        assert_eq!(config.target_maturity_level, "mixed");
13135    }
13136
13137    #[test]
13138    fn test_output_config_defaults() {
13139        let config = OutputConfig::default();
13140        assert!(matches!(config.mode, OutputMode::FlatFile));
13141        assert_eq!(config.formats, vec![FileFormat::Parquet]);
13142        assert!(config.compression.enabled);
13143        assert!(matches!(
13144            config.compression.algorithm,
13145            CompressionAlgorithm::Zstd
13146        ));
13147        assert!(config.include_acdoca);
13148        assert!(!config.include_bseg);
13149        assert!(config.partition_by_period);
13150        assert!(!config.partition_by_company);
13151    }
13152
13153    #[test]
13154    fn test_approval_config_defaults() {
13155        let config = ApprovalConfig::default();
13156        assert!(!config.enabled);
13157        assert_eq!(config.auto_approve_threshold, 1000.0);
13158        assert_eq!(config.rejection_rate, 0.02);
13159        assert_eq!(config.revision_rate, 0.05);
13160        assert_eq!(config.average_approval_delay_hours, 4.0);
13161        assert_eq!(config.thresholds.len(), 4);
13162    }
13163
13164    #[test]
13165    fn test_p2p_flow_config_defaults() {
13166        let config = P2PFlowConfig::default();
13167        assert!(config.enabled);
13168        assert_eq!(config.three_way_match_rate, 0.95);
13169        assert_eq!(config.partial_delivery_rate, 0.15);
13170        assert_eq!(config.average_po_to_gr_days, 14);
13171    }
13172
13173    #[test]
13174    fn test_o2c_flow_config_defaults() {
13175        let config = O2CFlowConfig::default();
13176        assert!(config.enabled);
13177        assert_eq!(config.credit_check_failure_rate, 0.02);
13178        assert_eq!(config.return_rate, 0.03);
13179        assert_eq!(config.bad_debt_rate, 0.01);
13180    }
13181
13182    #[test]
13183    fn test_balance_config_defaults() {
13184        let config = BalanceConfig::default();
13185        assert!(!config.generate_opening_balances);
13186        assert!(config.generate_trial_balances);
13187        assert_eq!(config.target_gross_margin, 0.35);
13188        assert!(config.validate_balance_equation);
13189        assert!(config.reconcile_subledgers);
13190    }
13191
13192    // ==========================================================================
13193    // Partial Config Deserialization Tests
13194    // ==========================================================================
13195
13196    #[test]
13197    fn test_partial_config_with_defaults() {
13198        // Minimal config that should use all defaults
13199        let yaml = r#"
13200            global:
13201              industry: manufacturing
13202              start_date: "2024-01-01"
13203              period_months: 3
13204            companies:
13205              - code: "TEST"
13206                name: "Test Company"
13207                currency: "USD"
13208                country: "US"
13209                annual_transaction_volume: ten_k
13210            chart_of_accounts:
13211              complexity: small
13212            output:
13213              output_directory: "./output"
13214        "#;
13215
13216        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13217        assert_eq!(config.global.period_months, 3);
13218        assert_eq!(config.companies.len(), 1);
13219        assert!(!config.fraud.enabled); // Default
13220        assert!(!config.internal_controls.enabled); // Default
13221    }
13222
13223    #[test]
13224    fn test_config_with_fraud_enabled() {
13225        let yaml = r#"
13226            global:
13227              industry: retail
13228              start_date: "2024-01-01"
13229              period_months: 12
13230            companies:
13231              - code: "RETAIL"
13232                name: "Retail Co"
13233                currency: "USD"
13234                country: "US"
13235                annual_transaction_volume: hundred_k
13236            chart_of_accounts:
13237              complexity: medium
13238            output:
13239              output_directory: "./output"
13240            fraud:
13241              enabled: true
13242              fraud_rate: 0.05
13243              clustering_enabled: true
13244        "#;
13245
13246        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13247        assert!(config.fraud.enabled);
13248        assert_eq!(config.fraud.fraud_rate, 0.05);
13249        assert!(config.fraud.clustering_enabled);
13250    }
13251
13252    #[test]
13253    fn test_config_with_multiple_companies() {
13254        let yaml = r#"
13255            global:
13256              industry: manufacturing
13257              start_date: "2024-01-01"
13258              period_months: 6
13259            companies:
13260              - code: "HQ"
13261                name: "Headquarters"
13262                currency: "USD"
13263                country: "US"
13264                annual_transaction_volume: hundred_k
13265                volume_weight: 1.0
13266              - code: "EU"
13267                name: "European Subsidiary"
13268                currency: "EUR"
13269                country: "DE"
13270                annual_transaction_volume: hundred_k
13271                volume_weight: 0.5
13272              - code: "APAC"
13273                name: "Asia Pacific"
13274                currency: "JPY"
13275                country: "JP"
13276                annual_transaction_volume: ten_k
13277                volume_weight: 0.3
13278            chart_of_accounts:
13279              complexity: large
13280            output:
13281              output_directory: "./output"
13282        "#;
13283
13284        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13285        assert_eq!(config.companies.len(), 3);
13286        assert_eq!(config.companies[0].code, "HQ");
13287        assert_eq!(config.companies[1].currency, "EUR");
13288        assert_eq!(config.companies[2].volume_weight, 0.3);
13289    }
13290
13291    #[test]
13292    fn test_intercompany_config() {
13293        let yaml = r#"
13294            enabled: true
13295            ic_transaction_rate: 0.20
13296            transfer_pricing_method: cost_plus
13297            markup_percent: 0.08
13298            generate_matched_pairs: true
13299            generate_eliminations: true
13300        "#;
13301
13302        let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13303        assert!(config.enabled);
13304        assert_eq!(config.ic_transaction_rate, 0.20);
13305        assert!(matches!(
13306            config.transfer_pricing_method,
13307            TransferPricingMethod::CostPlus
13308        ));
13309        assert_eq!(config.markup_percent, 0.08);
13310        assert!(config.generate_eliminations);
13311    }
13312
13313    // ==========================================================================
13314    // Company Config Tests
13315    // ==========================================================================
13316
13317    #[test]
13318    fn test_company_config_defaults() {
13319        let yaml = r#"
13320            code: "TEST"
13321            name: "Test Company"
13322            currency: "USD"
13323            country: "US"
13324            annual_transaction_volume: ten_k
13325        "#;
13326
13327        let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13328        assert_eq!(config.fiscal_year_variant, "K4"); // Default
13329        assert_eq!(config.volume_weight, 1.0); // Default
13330    }
13331
13332    // ==========================================================================
13333    // Chart of Accounts Config Tests
13334    // ==========================================================================
13335
13336    #[test]
13337    fn test_coa_config_defaults() {
13338        let yaml = r#"
13339            complexity: medium
13340        "#;
13341
13342        let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13343        assert!(config.industry_specific); // Default true
13344        assert!(config.custom_accounts.is_none());
13345        assert_eq!(config.min_hierarchy_depth, 2); // Default
13346        assert_eq!(config.max_hierarchy_depth, 5); // Default
13347    }
13348
13349    // ==========================================================================
13350    // Accounting Standards Config Tests
13351    // ==========================================================================
13352
13353    #[test]
13354    fn test_accounting_standards_config_defaults() {
13355        let config = AccountingStandardsConfig::default();
13356        assert!(!config.enabled);
13357        assert!(config.framework.is_none());
13358        assert!(!config.revenue_recognition.enabled);
13359        assert!(!config.leases.enabled);
13360        assert!(!config.fair_value.enabled);
13361        assert!(!config.impairment.enabled);
13362        assert!(!config.generate_differences);
13363    }
13364
13365    #[test]
13366    fn test_accounting_standards_config_yaml() {
13367        let yaml = r#"
13368            enabled: true
13369            framework: ifrs
13370            revenue_recognition:
13371              enabled: true
13372              generate_contracts: true
13373              avg_obligations_per_contract: 2.5
13374              variable_consideration_rate: 0.20
13375              over_time_recognition_rate: 0.35
13376              contract_count: 150
13377            leases:
13378              enabled: true
13379              lease_count: 75
13380              finance_lease_percent: 0.25
13381              avg_lease_term_months: 48
13382            generate_differences: true
13383        "#;
13384
13385        let config: AccountingStandardsConfig =
13386            serde_yaml::from_str(yaml).expect("Failed to parse");
13387        assert!(config.enabled);
13388        assert!(matches!(
13389            config.framework,
13390            Some(AccountingFrameworkConfig::Ifrs)
13391        ));
13392        assert!(config.revenue_recognition.enabled);
13393        assert_eq!(config.revenue_recognition.contract_count, 150);
13394        assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
13395        assert!(config.leases.enabled);
13396        assert_eq!(config.leases.lease_count, 75);
13397        assert_eq!(config.leases.finance_lease_percent, 0.25);
13398        assert!(config.generate_differences);
13399    }
13400
13401    #[test]
13402    fn test_accounting_framework_serialization() {
13403        let frameworks = [
13404            AccountingFrameworkConfig::UsGaap,
13405            AccountingFrameworkConfig::Ifrs,
13406            AccountingFrameworkConfig::DualReporting,
13407            AccountingFrameworkConfig::FrenchGaap,
13408            AccountingFrameworkConfig::GermanGaap,
13409        ];
13410
13411        for framework in frameworks {
13412            let json = serde_json::to_string(&framework).expect("Failed to serialize");
13413            let deserialized: AccountingFrameworkConfig =
13414                serde_json::from_str(&json).expect("Failed to deserialize");
13415            assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
13416        }
13417    }
13418
13419    #[test]
13420    fn test_revenue_recognition_config_defaults() {
13421        let config = RevenueRecognitionConfig::default();
13422        assert!(!config.enabled);
13423        assert!(config.generate_contracts);
13424        assert_eq!(config.avg_obligations_per_contract, 2.0);
13425        assert_eq!(config.variable_consideration_rate, 0.15);
13426        assert_eq!(config.over_time_recognition_rate, 0.30);
13427        assert_eq!(config.contract_count, 100);
13428    }
13429
13430    #[test]
13431    fn test_lease_accounting_config_defaults() {
13432        let config = LeaseAccountingConfig::default();
13433        assert!(!config.enabled);
13434        assert_eq!(config.lease_count, 50);
13435        assert_eq!(config.finance_lease_percent, 0.30);
13436        assert_eq!(config.avg_lease_term_months, 60);
13437        assert!(config.generate_amortization);
13438        assert_eq!(config.real_estate_percent, 0.40);
13439    }
13440
13441    #[test]
13442    fn test_fair_value_config_defaults() {
13443        let config = FairValueConfig::default();
13444        assert!(!config.enabled);
13445        assert_eq!(config.measurement_count, 25);
13446        assert_eq!(config.level1_percent, 0.40);
13447        assert_eq!(config.level2_percent, 0.35);
13448        assert_eq!(config.level3_percent, 0.25);
13449        assert!(!config.include_sensitivity_analysis);
13450    }
13451
13452    #[test]
13453    fn test_impairment_config_defaults() {
13454        let config = ImpairmentConfig::default();
13455        assert!(!config.enabled);
13456        assert_eq!(config.test_count, 15);
13457        assert_eq!(config.impairment_rate, 0.10);
13458        assert!(config.generate_projections);
13459        assert!(!config.include_goodwill);
13460    }
13461
13462    // ==========================================================================
13463    // Audit Standards Config Tests
13464    // ==========================================================================
13465
13466    #[test]
13467    fn test_audit_standards_config_defaults() {
13468        let config = AuditStandardsConfig::default();
13469        assert!(!config.enabled);
13470        assert!(!config.isa_compliance.enabled);
13471        assert!(!config.analytical_procedures.enabled);
13472        assert!(!config.confirmations.enabled);
13473        assert!(!config.opinion.enabled);
13474        assert!(!config.generate_audit_trail);
13475        assert!(!config.sox.enabled);
13476        assert!(!config.pcaob.enabled);
13477    }
13478
13479    #[test]
13480    fn test_audit_standards_config_yaml() {
13481        let yaml = r#"
13482            enabled: true
13483            isa_compliance:
13484              enabled: true
13485              compliance_level: comprehensive
13486              generate_isa_mappings: true
13487              include_pcaob: true
13488              framework: dual
13489            analytical_procedures:
13490              enabled: true
13491              procedures_per_account: 5
13492              variance_probability: 0.25
13493            confirmations:
13494              enabled: true
13495              confirmation_count: 75
13496              positive_response_rate: 0.90
13497              exception_rate: 0.08
13498            opinion:
13499              enabled: true
13500              generate_kam: true
13501              average_kam_count: 4
13502            sox:
13503              enabled: true
13504              generate_302_certifications: true
13505              generate_404_assessments: true
13506              material_weakness_rate: 0.03
13507            pcaob:
13508              enabled: true
13509              is_pcaob_audit: true
13510              include_icfr_opinion: true
13511            generate_audit_trail: true
13512        "#;
13513
13514        let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13515        assert!(config.enabled);
13516        assert!(config.isa_compliance.enabled);
13517        assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
13518        assert!(config.isa_compliance.include_pcaob);
13519        assert_eq!(config.isa_compliance.framework, "dual");
13520        assert!(config.analytical_procedures.enabled);
13521        assert_eq!(config.analytical_procedures.procedures_per_account, 5);
13522        assert!(config.confirmations.enabled);
13523        assert_eq!(config.confirmations.confirmation_count, 75);
13524        assert!(config.opinion.enabled);
13525        assert_eq!(config.opinion.average_kam_count, 4);
13526        assert!(config.sox.enabled);
13527        assert!(config.sox.generate_302_certifications);
13528        assert_eq!(config.sox.material_weakness_rate, 0.03);
13529        assert!(config.pcaob.enabled);
13530        assert!(config.pcaob.is_pcaob_audit);
13531        assert!(config.pcaob.include_icfr_opinion);
13532        assert!(config.generate_audit_trail);
13533    }
13534
13535    #[test]
13536    fn test_isa_compliance_config_defaults() {
13537        let config = IsaComplianceConfig::default();
13538        assert!(!config.enabled);
13539        assert_eq!(config.compliance_level, "standard");
13540        assert!(config.generate_isa_mappings);
13541        assert!(config.generate_coverage_summary);
13542        assert!(!config.include_pcaob);
13543        assert_eq!(config.framework, "isa");
13544    }
13545
13546    #[test]
13547    fn test_sox_compliance_config_defaults() {
13548        let config = SoxComplianceConfig::default();
13549        assert!(!config.enabled);
13550        assert!(config.generate_302_certifications);
13551        assert!(config.generate_404_assessments);
13552        assert_eq!(config.materiality_threshold, 10000.0);
13553        assert_eq!(config.material_weakness_rate, 0.02);
13554        assert_eq!(config.significant_deficiency_rate, 0.08);
13555    }
13556
13557    #[test]
13558    fn test_pcaob_config_defaults() {
13559        let config = PcaobConfig::default();
13560        assert!(!config.enabled);
13561        assert!(!config.is_pcaob_audit);
13562        assert!(config.generate_cam);
13563        assert!(!config.include_icfr_opinion);
13564        assert!(!config.generate_standard_mappings);
13565    }
13566
13567    #[test]
13568    fn test_config_with_standards_enabled() {
13569        let yaml = r#"
13570            global:
13571              industry: financial_services
13572              start_date: "2024-01-01"
13573              period_months: 12
13574            companies:
13575              - code: "BANK"
13576                name: "Test Bank"
13577                currency: "USD"
13578                country: "US"
13579                annual_transaction_volume: hundred_k
13580            chart_of_accounts:
13581              complexity: large
13582            output:
13583              output_directory: "./output"
13584            accounting_standards:
13585              enabled: true
13586              framework: us_gaap
13587              revenue_recognition:
13588                enabled: true
13589              leases:
13590                enabled: true
13591            audit_standards:
13592              enabled: true
13593              isa_compliance:
13594                enabled: true
13595              sox:
13596                enabled: true
13597        "#;
13598
13599        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13600        assert!(config.accounting_standards.enabled);
13601        assert!(matches!(
13602            config.accounting_standards.framework,
13603            Some(AccountingFrameworkConfig::UsGaap)
13604        ));
13605        assert!(config.accounting_standards.revenue_recognition.enabled);
13606        assert!(config.accounting_standards.leases.enabled);
13607        assert!(config.audit_standards.enabled);
13608        assert!(config.audit_standards.isa_compliance.enabled);
13609        assert!(config.audit_standards.sox.enabled);
13610    }
13611
13612    // ==========================================================================
13613    // Industry-Specific Config Tests
13614    // ==========================================================================
13615
13616    #[test]
13617    fn test_industry_specific_config_defaults() {
13618        let config = IndustrySpecificConfig::default();
13619        assert!(!config.enabled);
13620        assert!(!config.manufacturing.enabled);
13621        assert!(!config.retail.enabled);
13622        assert!(!config.healthcare.enabled);
13623        assert!(!config.technology.enabled);
13624        assert!(!config.financial_services.enabled);
13625        assert!(!config.professional_services.enabled);
13626    }
13627
13628    #[test]
13629    fn test_manufacturing_config_defaults() {
13630        let config = ManufacturingConfig::default();
13631        assert!(!config.enabled);
13632        assert_eq!(config.bom_depth, 4);
13633        assert!(!config.just_in_time);
13634        assert_eq!(config.supplier_tiers, 2);
13635        assert_eq!(config.target_yield_rate, 0.97);
13636        assert_eq!(config.scrap_alert_threshold, 0.03);
13637    }
13638
13639    #[test]
13640    fn test_retail_config_defaults() {
13641        let config = RetailConfig::default();
13642        assert!(!config.enabled);
13643        assert_eq!(config.avg_daily_transactions, 500);
13644        assert!(config.loss_prevention);
13645        assert_eq!(config.shrinkage_rate, 0.015);
13646    }
13647
13648    #[test]
13649    fn test_healthcare_config_defaults() {
13650        let config = HealthcareConfig::default();
13651        assert!(!config.enabled);
13652        assert_eq!(config.facility_type, "hospital");
13653        assert_eq!(config.avg_daily_encounters, 150);
13654        assert!(config.compliance.hipaa);
13655        assert!(config.compliance.stark_law);
13656        assert!(config.coding_systems.icd10);
13657        assert!(config.coding_systems.cpt);
13658    }
13659
13660    #[test]
13661    fn test_technology_config_defaults() {
13662        let config = TechnologyConfig::default();
13663        assert!(!config.enabled);
13664        assert_eq!(config.revenue_model, "saas");
13665        assert_eq!(config.subscription_revenue_pct, 0.60);
13666        assert!(config.rd_capitalization.enabled);
13667    }
13668
13669    #[test]
13670    fn test_config_with_industry_specific() {
13671        let yaml = r#"
13672            global:
13673              industry: healthcare
13674              start_date: "2024-01-01"
13675              period_months: 12
13676            companies:
13677              - code: "HOSP"
13678                name: "Test Hospital"
13679                currency: "USD"
13680                country: "US"
13681                annual_transaction_volume: hundred_k
13682            chart_of_accounts:
13683              complexity: medium
13684            output:
13685              output_directory: "./output"
13686            industry_specific:
13687              enabled: true
13688              healthcare:
13689                enabled: true
13690                facility_type: hospital
13691                payer_mix:
13692                  medicare: 0.45
13693                  medicaid: 0.15
13694                  commercial: 0.35
13695                  self_pay: 0.05
13696                coding_systems:
13697                  icd10: true
13698                  cpt: true
13699                  drg: true
13700                compliance:
13701                  hipaa: true
13702                  stark_law: true
13703                anomaly_rates:
13704                  upcoding: 0.03
13705                  unbundling: 0.02
13706        "#;
13707
13708        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13709        assert!(config.industry_specific.enabled);
13710        assert!(config.industry_specific.healthcare.enabled);
13711        assert_eq!(
13712            config.industry_specific.healthcare.facility_type,
13713            "hospital"
13714        );
13715        assert_eq!(config.industry_specific.healthcare.payer_mix.medicare, 0.45);
13716        assert_eq!(config.industry_specific.healthcare.payer_mix.self_pay, 0.05);
13717        assert!(config.industry_specific.healthcare.coding_systems.icd10);
13718        assert!(config.industry_specific.healthcare.compliance.hipaa);
13719        assert_eq!(
13720            config.industry_specific.healthcare.anomaly_rates.upcoding,
13721            0.03
13722        );
13723    }
13724
13725    #[test]
13726    fn test_config_with_manufacturing_specific() {
13727        let yaml = r#"
13728            global:
13729              industry: manufacturing
13730              start_date: "2024-01-01"
13731              period_months: 12
13732            companies:
13733              - code: "MFG"
13734                name: "Test Manufacturing"
13735                currency: "USD"
13736                country: "US"
13737                annual_transaction_volume: hundred_k
13738            chart_of_accounts:
13739              complexity: medium
13740            output:
13741              output_directory: "./output"
13742            industry_specific:
13743              enabled: true
13744              manufacturing:
13745                enabled: true
13746                bom_depth: 5
13747                just_in_time: true
13748                supplier_tiers: 3
13749                target_yield_rate: 0.98
13750                anomaly_rates:
13751                  yield_manipulation: 0.02
13752                  phantom_production: 0.01
13753        "#;
13754
13755        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13756        assert!(config.industry_specific.enabled);
13757        assert!(config.industry_specific.manufacturing.enabled);
13758        assert_eq!(config.industry_specific.manufacturing.bom_depth, 5);
13759        assert!(config.industry_specific.manufacturing.just_in_time);
13760        assert_eq!(config.industry_specific.manufacturing.supplier_tiers, 3);
13761        assert_eq!(
13762            config.industry_specific.manufacturing.target_yield_rate,
13763            0.98
13764        );
13765        assert_eq!(
13766            config
13767                .industry_specific
13768                .manufacturing
13769                .anomaly_rates
13770                .yield_manipulation,
13771            0.02
13772        );
13773    }
13774
13775    // ==========================================================================
13776    // Tax Configuration Tests
13777    // ==========================================================================
13778
13779    #[test]
13780    fn test_tax_config_defaults() {
13781        let tax = TaxConfig::default();
13782        assert!(!tax.enabled);
13783        assert!(tax.jurisdictions.countries.is_empty());
13784        assert!(!tax.jurisdictions.include_subnational);
13785        assert!(!tax.vat_gst.enabled);
13786        assert!(tax.vat_gst.standard_rates.is_empty());
13787        assert!(tax.vat_gst.reduced_rates.is_empty());
13788        assert!(tax.vat_gst.exempt_categories.is_empty());
13789        assert!(tax.vat_gst.reverse_charge);
13790        assert!(!tax.sales_tax.enabled);
13791        assert!(tax.sales_tax.nexus_states.is_empty());
13792        assert!(!tax.withholding.enabled);
13793        assert!(tax.withholding.treaty_network);
13794        assert_eq!(tax.withholding.default_rate, 0.30);
13795        assert_eq!(tax.withholding.treaty_reduced_rate, 0.15);
13796        assert!(tax.provisions.enabled);
13797        assert_eq!(tax.provisions.statutory_rate, 0.21);
13798        assert!(tax.provisions.uncertain_positions);
13799        assert!(!tax.payroll_tax.enabled);
13800        assert_eq!(tax.anomaly_rate, 0.03);
13801    }
13802
13803    #[test]
13804    fn test_tax_config_from_yaml() {
13805        let yaml = r#"
13806            global:
13807              seed: 42
13808              start_date: "2024-01-01"
13809              period_months: 12
13810              industry: retail
13811            companies:
13812              - code: C001
13813                name: Test Corp
13814                currency: USD
13815                country: US
13816                annual_transaction_volume: ten_k
13817            chart_of_accounts:
13818              complexity: small
13819            output:
13820              output_directory: ./output
13821            tax:
13822              enabled: true
13823              anomaly_rate: 0.05
13824              jurisdictions:
13825                countries: ["US", "DE", "GB"]
13826                include_subnational: true
13827              vat_gst:
13828                enabled: true
13829                standard_rates:
13830                  DE: 0.19
13831                  GB: 0.20
13832                reduced_rates:
13833                  DE: 0.07
13834                  GB: 0.05
13835                exempt_categories:
13836                  - financial_services
13837                  - healthcare
13838                reverse_charge: false
13839              sales_tax:
13840                enabled: true
13841                nexus_states: ["CA", "NY", "TX"]
13842              withholding:
13843                enabled: true
13844                treaty_network: false
13845                default_rate: 0.25
13846                treaty_reduced_rate: 0.10
13847              provisions:
13848                enabled: false
13849                statutory_rate: 0.28
13850                uncertain_positions: false
13851              payroll_tax:
13852                enabled: true
13853        "#;
13854
13855        let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
13856        assert!(config.tax.enabled);
13857        assert_eq!(config.tax.anomaly_rate, 0.05);
13858
13859        // Jurisdictions
13860        assert_eq!(config.tax.jurisdictions.countries.len(), 3);
13861        assert!(config
13862            .tax
13863            .jurisdictions
13864            .countries
13865            .contains(&"DE".to_string()));
13866        assert!(config.tax.jurisdictions.include_subnational);
13867
13868        // VAT/GST
13869        assert!(config.tax.vat_gst.enabled);
13870        assert_eq!(config.tax.vat_gst.standard_rates.get("DE"), Some(&0.19));
13871        assert_eq!(config.tax.vat_gst.standard_rates.get("GB"), Some(&0.20));
13872        assert_eq!(config.tax.vat_gst.reduced_rates.get("DE"), Some(&0.07));
13873        assert_eq!(config.tax.vat_gst.exempt_categories.len(), 2);
13874        assert!(!config.tax.vat_gst.reverse_charge);
13875
13876        // Sales tax
13877        assert!(config.tax.sales_tax.enabled);
13878        assert_eq!(config.tax.sales_tax.nexus_states.len(), 3);
13879        assert!(config
13880            .tax
13881            .sales_tax
13882            .nexus_states
13883            .contains(&"CA".to_string()));
13884
13885        // Withholding
13886        assert!(config.tax.withholding.enabled);
13887        assert!(!config.tax.withholding.treaty_network);
13888        assert_eq!(config.tax.withholding.default_rate, 0.25);
13889        assert_eq!(config.tax.withholding.treaty_reduced_rate, 0.10);
13890
13891        // Provisions
13892        assert!(!config.tax.provisions.enabled);
13893        assert_eq!(config.tax.provisions.statutory_rate, 0.28);
13894        assert!(!config.tax.provisions.uncertain_positions);
13895
13896        // Payroll tax
13897        assert!(config.tax.payroll_tax.enabled);
13898    }
13899
13900    #[test]
13901    fn test_generator_config_with_tax_default() {
13902        let yaml = r#"
13903            global:
13904              seed: 42
13905              start_date: "2024-01-01"
13906              period_months: 12
13907              industry: retail
13908            companies:
13909              - code: C001
13910                name: Test Corp
13911                currency: USD
13912                country: US
13913                annual_transaction_volume: ten_k
13914            chart_of_accounts:
13915              complexity: small
13916            output:
13917              output_directory: ./output
13918        "#;
13919
13920        let config: GeneratorConfig =
13921            serde_yaml::from_str(yaml).expect("Failed to parse config without tax section");
13922        // Tax should be present with defaults when not specified in YAML
13923        assert!(!config.tax.enabled);
13924        assert!(config.tax.jurisdictions.countries.is_empty());
13925        assert_eq!(config.tax.anomaly_rate, 0.03);
13926        assert!(config.tax.provisions.enabled); // provisions default to enabled=true
13927        assert_eq!(config.tax.provisions.statutory_rate, 0.21);
13928    }
13929
13930    // ==========================================================================
13931    // SessionSchemaConfig Tests
13932    // ==========================================================================
13933
13934    #[test]
13935    fn test_session_config_default_disabled() {
13936        let yaml = "{}";
13937        let config: SessionSchemaConfig =
13938            serde_yaml::from_str(yaml).expect("Failed to parse empty session config");
13939        assert!(!config.enabled);
13940        assert!(config.checkpoint_path.is_none());
13941        assert!(config.per_period_output);
13942        assert!(config.consolidated_output);
13943    }
13944
13945    #[test]
13946    fn test_config_backward_compatible_without_session() {
13947        let yaml = r#"
13948            global:
13949              seed: 42
13950              start_date: "2024-01-01"
13951              period_months: 12
13952              industry: retail
13953            companies:
13954              - code: C001
13955                name: Test Corp
13956                currency: USD
13957                country: US
13958                annual_transaction_volume: ten_k
13959            chart_of_accounts:
13960              complexity: small
13961            output:
13962              output_directory: ./output
13963        "#;
13964
13965        let config: GeneratorConfig =
13966            serde_yaml::from_str(yaml).expect("Failed to parse config without session");
13967        // Session should default to disabled
13968        assert!(!config.session.enabled);
13969        assert!(config.session.per_period_output);
13970        assert!(config.session.consolidated_output);
13971        // fiscal_year_months should be None
13972        assert!(config.global.fiscal_year_months.is_none());
13973    }
13974
13975    #[test]
13976    fn test_fiscal_year_months_parsed() {
13977        let yaml = r#"
13978            global:
13979              seed: 42
13980              start_date: "2024-01-01"
13981              period_months: 24
13982              industry: retail
13983              fiscal_year_months: 12
13984            companies:
13985              - code: C001
13986                name: Test Corp
13987                currency: USD
13988                country: US
13989                annual_transaction_volume: ten_k
13990            chart_of_accounts:
13991              complexity: small
13992            output:
13993              output_directory: ./output
13994            session:
13995              enabled: true
13996              checkpoint_path: /tmp/checkpoints
13997              per_period_output: true
13998              consolidated_output: false
13999        "#;
14000
14001        let config: GeneratorConfig =
14002            serde_yaml::from_str(yaml).expect("Failed to parse config with fiscal_year_months");
14003        assert_eq!(config.global.fiscal_year_months, Some(12));
14004        assert!(config.session.enabled);
14005        assert_eq!(
14006            config.session.checkpoint_path,
14007            Some("/tmp/checkpoints".to_string())
14008        );
14009        assert!(config.session.per_period_output);
14010        assert!(!config.session.consolidated_output);
14011    }
14012}