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