Skip to main content

datasynth_config/
schema.rs

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