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