1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct GeneratorConfig {
14 pub global: GlobalConfig,
16 pub companies: Vec<CompanyConfig>,
18 pub chart_of_accounts: ChartOfAccountsConfig,
20 #[serde(default)]
22 pub transactions: TransactionConfig,
23 pub output: OutputConfig,
25 #[serde(default)]
27 pub fraud: FraudConfig,
28 #[serde(default)]
30 pub data_quality: DataQualitySchemaConfig,
31 #[serde(default)]
33 pub internal_controls: InternalControlsConfig,
34 #[serde(default)]
36 pub business_processes: BusinessProcessConfig,
37 #[serde(default)]
39 pub user_personas: UserPersonaConfig,
40 #[serde(default)]
42 pub templates: TemplateConfig,
43 #[serde(default)]
45 pub approval: ApprovalConfig,
46 #[serde(default)]
48 pub departments: DepartmentConfig,
49 #[serde(default)]
51 pub master_data: MasterDataConfig,
52 #[serde(default)]
54 pub document_flows: DocumentFlowConfig,
55 #[serde(default)]
57 pub intercompany: IntercompanyConfig,
58 #[serde(default)]
60 pub balance: BalanceConfig,
61 #[serde(default)]
63 pub ocpm: OcpmConfig,
64 #[serde(default)]
66 pub audit: AuditGenerationConfig,
67 #[serde(default)]
69 pub banking: datasynth_banking::BankingConfig,
70 #[serde(default)]
72 pub scenario: ScenarioConfig,
73 #[serde(default)]
75 pub temporal: TemporalDriftConfig,
76 #[serde(default)]
78 pub graph_export: GraphExportConfig,
79 #[serde(default)]
81 pub streaming: StreamingSchemaConfig,
82 #[serde(default)]
84 pub rate_limit: RateLimitSchemaConfig,
85 #[serde(default)]
87 pub temporal_attributes: TemporalAttributeSchemaConfig,
88 #[serde(default)]
90 pub relationships: RelationshipSchemaConfig,
91 #[serde(default)]
93 pub accounting_standards: AccountingStandardsConfig,
94 #[serde(default)]
96 pub audit_standards: AuditStandardsConfig,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct GraphExportConfig {
107 #[serde(default)]
109 pub enabled: bool,
110
111 #[serde(default = "default_graph_types")]
113 pub graph_types: Vec<GraphTypeConfig>,
114
115 #[serde(default = "default_graph_formats")]
117 pub formats: Vec<GraphExportFormat>,
118
119 #[serde(default = "default_train_ratio")]
121 pub train_ratio: f64,
122
123 #[serde(default = "default_val_ratio")]
125 pub validation_ratio: f64,
126
127 #[serde(default)]
129 pub split_seed: Option<u64>,
130
131 #[serde(default = "default_graph_subdir")]
133 pub output_subdirectory: String,
134}
135
136fn default_graph_types() -> Vec<GraphTypeConfig> {
137 vec![GraphTypeConfig::default()]
138}
139
140fn default_graph_formats() -> Vec<GraphExportFormat> {
141 vec![GraphExportFormat::PytorchGeometric]
142}
143
144fn default_train_ratio() -> f64 {
145 0.7
146}
147
148fn default_val_ratio() -> f64 {
149 0.15
150}
151
152fn default_graph_subdir() -> String {
153 "graphs".to_string()
154}
155
156impl Default for GraphExportConfig {
157 fn default() -> Self {
158 Self {
159 enabled: false,
160 graph_types: default_graph_types(),
161 formats: default_graph_formats(),
162 train_ratio: 0.7,
163 validation_ratio: 0.15,
164 split_seed: None,
165 output_subdirectory: "graphs".to_string(),
166 }
167 }
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct GraphTypeConfig {
173 #[serde(default = "default_graph_name")]
175 pub name: String,
176
177 #[serde(default)]
179 pub aggregate_edges: bool,
180
181 #[serde(default)]
183 pub min_edge_weight: f64,
184
185 #[serde(default)]
187 pub include_document_nodes: bool,
188}
189
190fn default_graph_name() -> String {
191 "accounting_network".to_string()
192}
193
194impl Default for GraphTypeConfig {
195 fn default() -> Self {
196 Self {
197 name: "accounting_network".to_string(),
198 aggregate_edges: false,
199 min_edge_weight: 0.0,
200 include_document_nodes: false,
201 }
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
207#[serde(rename_all = "snake_case")]
208pub enum GraphExportFormat {
209 PytorchGeometric,
211 Neo4j,
213 Dgl,
215 RustGraph,
217}
218
219#[derive(Debug, Clone, Default, Serialize, Deserialize)]
223pub struct ScenarioConfig {
224 #[serde(default)]
227 pub tags: Vec<String>,
228
229 #[serde(default)]
234 pub profile: Option<String>,
235
236 #[serde(default)]
238 pub description: Option<String>,
239
240 #[serde(default)]
242 pub ml_training: bool,
243
244 #[serde(default)]
247 pub target_anomaly_ratio: Option<f64>,
248
249 #[serde(default)]
251 pub metadata: std::collections::HashMap<String, String>,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct TemporalDriftConfig {
260 #[serde(default)]
262 pub enabled: bool,
263
264 #[serde(default = "default_amount_drift")]
267 pub amount_mean_drift: f64,
268
269 #[serde(default)]
272 pub amount_variance_drift: f64,
273
274 #[serde(default)]
277 pub anomaly_rate_drift: f64,
278
279 #[serde(default = "default_concept_drift")]
282 pub concept_drift_rate: f64,
283
284 #[serde(default)]
286 pub sudden_drift_probability: f64,
287
288 #[serde(default = "default_sudden_drift_magnitude")]
290 pub sudden_drift_magnitude: f64,
291
292 #[serde(default)]
294 pub seasonal_drift: bool,
295
296 #[serde(default)]
298 pub drift_start_period: u32,
299
300 #[serde(default = "default_drift_type")]
302 pub drift_type: DriftType,
303}
304
305fn default_amount_drift() -> f64 {
306 0.02
307}
308
309fn default_concept_drift() -> f64 {
310 0.01
311}
312
313fn default_sudden_drift_magnitude() -> f64 {
314 2.0
315}
316
317fn default_drift_type() -> DriftType {
318 DriftType::Gradual
319}
320
321impl Default for TemporalDriftConfig {
322 fn default() -> Self {
323 Self {
324 enabled: false,
325 amount_mean_drift: 0.02,
326 amount_variance_drift: 0.0,
327 anomaly_rate_drift: 0.0,
328 concept_drift_rate: 0.01,
329 sudden_drift_probability: 0.0,
330 sudden_drift_magnitude: 2.0,
331 seasonal_drift: false,
332 drift_start_period: 0,
333 drift_type: DriftType::Gradual,
334 }
335 }
336}
337
338impl TemporalDriftConfig {
339 pub fn to_core_config(&self) -> datasynth_core::distributions::DriftConfig {
341 datasynth_core::distributions::DriftConfig {
342 enabled: self.enabled,
343 amount_mean_drift: self.amount_mean_drift,
344 amount_variance_drift: self.amount_variance_drift,
345 anomaly_rate_drift: self.anomaly_rate_drift,
346 concept_drift_rate: self.concept_drift_rate,
347 sudden_drift_probability: self.sudden_drift_probability,
348 sudden_drift_magnitude: self.sudden_drift_magnitude,
349 seasonal_drift: self.seasonal_drift,
350 drift_start_period: self.drift_start_period,
351 drift_type: match self.drift_type {
352 DriftType::Gradual => datasynth_core::distributions::DriftType::Gradual,
353 DriftType::Sudden => datasynth_core::distributions::DriftType::Sudden,
354 DriftType::Recurring => datasynth_core::distributions::DriftType::Recurring,
355 DriftType::Mixed => datasynth_core::distributions::DriftType::Mixed,
356 },
357 }
358 }
359}
360
361#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
363#[serde(rename_all = "snake_case")]
364pub enum DriftType {
365 #[default]
367 Gradual,
368 Sudden,
370 Recurring,
372 Mixed,
374}
375
376#[derive(Debug, Clone, Serialize, Deserialize)]
382pub struct StreamingSchemaConfig {
383 #[serde(default)]
385 pub enabled: bool,
386 #[serde(default = "default_buffer_size")]
388 pub buffer_size: usize,
389 #[serde(default = "default_true")]
391 pub enable_progress: bool,
392 #[serde(default = "default_progress_interval")]
394 pub progress_interval: u64,
395 #[serde(default)]
397 pub backpressure: BackpressureSchemaStrategy,
398}
399
400fn default_buffer_size() -> usize {
401 1000
402}
403
404fn default_progress_interval() -> u64 {
405 100
406}
407
408impl Default for StreamingSchemaConfig {
409 fn default() -> Self {
410 Self {
411 enabled: false,
412 buffer_size: 1000,
413 enable_progress: true,
414 progress_interval: 100,
415 backpressure: BackpressureSchemaStrategy::Block,
416 }
417 }
418}
419
420#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
422#[serde(rename_all = "snake_case")]
423pub enum BackpressureSchemaStrategy {
424 #[default]
426 Block,
427 DropOldest,
429 DropNewest,
431 Buffer,
433}
434
435#[derive(Debug, Clone, Serialize, Deserialize)]
441pub struct RateLimitSchemaConfig {
442 #[serde(default)]
444 pub enabled: bool,
445 #[serde(default = "default_entities_per_second")]
447 pub entities_per_second: f64,
448 #[serde(default = "default_burst_size")]
450 pub burst_size: u32,
451 #[serde(default)]
453 pub backpressure: RateLimitBackpressureSchema,
454}
455
456fn default_entities_per_second() -> f64 {
457 1000.0
458}
459
460fn default_burst_size() -> u32 {
461 100
462}
463
464impl Default for RateLimitSchemaConfig {
465 fn default() -> Self {
466 Self {
467 enabled: false,
468 entities_per_second: 1000.0,
469 burst_size: 100,
470 backpressure: RateLimitBackpressureSchema::Block,
471 }
472 }
473}
474
475#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
477#[serde(rename_all = "snake_case")]
478pub enum RateLimitBackpressureSchema {
479 #[default]
481 Block,
482 Drop,
484 Buffer,
486}
487
488#[derive(Debug, Clone, Serialize, Deserialize)]
494pub struct TemporalAttributeSchemaConfig {
495 #[serde(default)]
497 pub enabled: bool,
498 #[serde(default)]
500 pub valid_time: ValidTimeSchemaConfig,
501 #[serde(default)]
503 pub transaction_time: TransactionTimeSchemaConfig,
504 #[serde(default)]
506 pub generate_version_chains: bool,
507 #[serde(default = "default_avg_versions")]
509 pub avg_versions_per_entity: f64,
510}
511
512fn default_avg_versions() -> f64 {
513 1.5
514}
515
516impl Default for TemporalAttributeSchemaConfig {
517 fn default() -> Self {
518 Self {
519 enabled: false,
520 valid_time: ValidTimeSchemaConfig::default(),
521 transaction_time: TransactionTimeSchemaConfig::default(),
522 generate_version_chains: false,
523 avg_versions_per_entity: 1.5,
524 }
525 }
526}
527
528#[derive(Debug, Clone, Serialize, Deserialize)]
530pub struct ValidTimeSchemaConfig {
531 #[serde(default = "default_closed_probability")]
533 pub closed_probability: f64,
534 #[serde(default = "default_avg_validity_days")]
536 pub avg_validity_days: u32,
537 #[serde(default = "default_validity_stddev")]
539 pub validity_stddev_days: u32,
540}
541
542fn default_closed_probability() -> f64 {
543 0.1
544}
545
546fn default_avg_validity_days() -> u32 {
547 365
548}
549
550fn default_validity_stddev() -> u32 {
551 90
552}
553
554impl Default for ValidTimeSchemaConfig {
555 fn default() -> Self {
556 Self {
557 closed_probability: 0.1,
558 avg_validity_days: 365,
559 validity_stddev_days: 90,
560 }
561 }
562}
563
564#[derive(Debug, Clone, Serialize, Deserialize)]
566pub struct TransactionTimeSchemaConfig {
567 #[serde(default)]
569 pub avg_recording_delay_seconds: u32,
570 #[serde(default)]
572 pub allow_backdating: bool,
573 #[serde(default = "default_backdating_probability")]
575 pub backdating_probability: f64,
576 #[serde(default = "default_max_backdate_days")]
578 pub max_backdate_days: u32,
579}
580
581fn default_backdating_probability() -> f64 {
582 0.01
583}
584
585fn default_max_backdate_days() -> u32 {
586 30
587}
588
589impl Default for TransactionTimeSchemaConfig {
590 fn default() -> Self {
591 Self {
592 avg_recording_delay_seconds: 0,
593 allow_backdating: false,
594 backdating_probability: 0.01,
595 max_backdate_days: 30,
596 }
597 }
598}
599
600#[derive(Debug, Clone, Serialize, Deserialize)]
606pub struct RelationshipSchemaConfig {
607 #[serde(default)]
609 pub relationship_types: Vec<RelationshipTypeSchemaConfig>,
610 #[serde(default = "default_true")]
612 pub allow_orphans: bool,
613 #[serde(default = "default_orphan_probability")]
615 pub orphan_probability: f64,
616 #[serde(default)]
618 pub allow_circular: bool,
619 #[serde(default = "default_max_circular_depth")]
621 pub max_circular_depth: u32,
622}
623
624fn default_orphan_probability() -> f64 {
625 0.01
626}
627
628fn default_max_circular_depth() -> u32 {
629 3
630}
631
632impl Default for RelationshipSchemaConfig {
633 fn default() -> Self {
634 Self {
635 relationship_types: Vec::new(),
636 allow_orphans: true,
637 orphan_probability: 0.01,
638 allow_circular: false,
639 max_circular_depth: 3,
640 }
641 }
642}
643
644#[derive(Debug, Clone, Serialize, Deserialize)]
646pub struct RelationshipTypeSchemaConfig {
647 pub name: String,
649 pub source_type: String,
651 pub target_type: String,
653 #[serde(default)]
655 pub cardinality: CardinalitySchemaRule,
656 #[serde(default = "default_relationship_weight")]
658 pub weight: f64,
659 #[serde(default)]
661 pub required: bool,
662 #[serde(default = "default_true")]
664 pub directed: bool,
665}
666
667fn default_relationship_weight() -> f64 {
668 1.0
669}
670
671impl Default for RelationshipTypeSchemaConfig {
672 fn default() -> Self {
673 Self {
674 name: String::new(),
675 source_type: String::new(),
676 target_type: String::new(),
677 cardinality: CardinalitySchemaRule::default(),
678 weight: 1.0,
679 required: false,
680 directed: true,
681 }
682 }
683}
684
685#[derive(Debug, Clone, Serialize, Deserialize)]
687#[serde(rename_all = "snake_case")]
688pub enum CardinalitySchemaRule {
689 OneToOne,
691 OneToMany {
693 min: u32,
695 max: u32,
697 },
698 ManyToOne {
700 min: u32,
702 max: u32,
704 },
705 ManyToMany {
707 min_per_source: u32,
709 max_per_source: u32,
711 },
712}
713
714impl Default for CardinalitySchemaRule {
715 fn default() -> Self {
716 Self::OneToMany { min: 1, max: 5 }
717 }
718}
719
720#[derive(Debug, Clone, Serialize, Deserialize)]
722pub struct GlobalConfig {
723 pub seed: Option<u64>,
725 pub industry: IndustrySector,
727 pub start_date: String,
729 pub period_months: u32,
731 #[serde(default = "default_currency")]
733 pub group_currency: String,
734 #[serde(default = "default_true")]
736 pub parallel: bool,
737 #[serde(default)]
739 pub worker_threads: usize,
740 #[serde(default)]
742 pub memory_limit_mb: usize,
743}
744
745fn default_currency() -> String {
746 "USD".to_string()
747}
748fn default_true() -> bool {
749 true
750}
751
752#[derive(Debug, Clone, Serialize, Deserialize)]
754pub struct CompanyConfig {
755 pub code: String,
757 pub name: String,
759 pub currency: String,
761 pub country: String,
763 #[serde(default = "default_fiscal_variant")]
765 pub fiscal_year_variant: String,
766 pub annual_transaction_volume: TransactionVolume,
768 #[serde(default = "default_weight")]
770 pub volume_weight: f64,
771}
772
773fn default_fiscal_variant() -> String {
774 "K4".to_string()
775}
776fn default_weight() -> f64 {
777 1.0
778}
779
780#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
782#[serde(rename_all = "snake_case")]
783pub enum TransactionVolume {
784 TenK,
786 HundredK,
788 OneM,
790 TenM,
792 HundredM,
794 Custom(u64),
796}
797
798impl TransactionVolume {
799 pub fn count(&self) -> u64 {
801 match self {
802 Self::TenK => 10_000,
803 Self::HundredK => 100_000,
804 Self::OneM => 1_000_000,
805 Self::TenM => 10_000_000,
806 Self::HundredM => 100_000_000,
807 Self::Custom(n) => *n,
808 }
809 }
810}
811
812#[derive(Debug, Clone, Serialize, Deserialize)]
814pub struct ChartOfAccountsConfig {
815 pub complexity: CoAComplexity,
817 #[serde(default = "default_true")]
819 pub industry_specific: bool,
820 pub custom_accounts: Option<PathBuf>,
822 #[serde(default = "default_min_depth")]
824 pub min_hierarchy_depth: u8,
825 #[serde(default = "default_max_depth")]
827 pub max_hierarchy_depth: u8,
828}
829
830fn default_min_depth() -> u8 {
831 2
832}
833fn default_max_depth() -> u8 {
834 5
835}
836
837impl Default for ChartOfAccountsConfig {
838 fn default() -> Self {
839 Self {
840 complexity: CoAComplexity::Small,
841 industry_specific: true,
842 custom_accounts: None,
843 min_hierarchy_depth: default_min_depth(),
844 max_hierarchy_depth: default_max_depth(),
845 }
846 }
847}
848
849#[derive(Debug, Clone, Serialize, Deserialize, Default)]
851pub struct TransactionConfig {
852 #[serde(default)]
854 pub line_item_distribution: LineItemDistributionConfig,
855 #[serde(default)]
857 pub debit_credit_distribution: DebitCreditDistributionConfig,
858 #[serde(default)]
860 pub even_odd_distribution: EvenOddDistributionConfig,
861 #[serde(default)]
863 pub source_distribution: SourceDistribution,
864 #[serde(default)]
866 pub seasonality: SeasonalityConfig,
867 #[serde(default)]
869 pub amounts: AmountDistributionConfig,
870 #[serde(default)]
872 pub benford: BenfordConfig,
873}
874
875#[derive(Debug, Clone, Serialize, Deserialize)]
877pub struct BenfordConfig {
878 #[serde(default = "default_true")]
880 pub enabled: bool,
881 #[serde(default = "default_benford_tolerance")]
883 pub tolerance: f64,
884 #[serde(default)]
886 pub exempt_sources: Vec<BenfordExemption>,
887}
888
889fn default_benford_tolerance() -> f64 {
890 0.05
891}
892
893impl Default for BenfordConfig {
894 fn default() -> Self {
895 Self {
896 enabled: true,
897 tolerance: default_benford_tolerance(),
898 exempt_sources: vec![BenfordExemption::Recurring, BenfordExemption::Payroll],
899 }
900 }
901}
902
903#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
905#[serde(rename_all = "snake_case")]
906pub enum BenfordExemption {
907 Recurring,
909 Payroll,
911 FixedFees,
913 RoundAmounts,
915}
916
917#[derive(Debug, Clone, Serialize, Deserialize)]
919pub struct SourceDistribution {
920 pub manual: f64,
922 pub automated: f64,
924 pub recurring: f64,
926 pub adjustment: f64,
928}
929
930impl Default for SourceDistribution {
931 fn default() -> Self {
932 Self {
933 manual: 0.20,
934 automated: 0.70,
935 recurring: 0.07,
936 adjustment: 0.03,
937 }
938 }
939}
940
941#[derive(Debug, Clone, Serialize, Deserialize)]
943pub struct OutputConfig {
944 #[serde(default)]
946 pub mode: OutputMode,
947 pub output_directory: PathBuf,
949 #[serde(default = "default_formats")]
951 pub formats: Vec<FileFormat>,
952 #[serde(default)]
954 pub compression: CompressionConfig,
955 #[serde(default = "default_batch_size")]
957 pub batch_size: usize,
958 #[serde(default = "default_true")]
960 pub include_acdoca: bool,
961 #[serde(default)]
963 pub include_bseg: bool,
964 #[serde(default = "default_true")]
966 pub partition_by_period: bool,
967 #[serde(default)]
969 pub partition_by_company: bool,
970}
971
972fn default_formats() -> Vec<FileFormat> {
973 vec![FileFormat::Parquet]
974}
975fn default_batch_size() -> usize {
976 100_000
977}
978
979impl Default for OutputConfig {
980 fn default() -> Self {
981 Self {
982 mode: OutputMode::FlatFile,
983 output_directory: PathBuf::from("./output"),
984 formats: default_formats(),
985 compression: CompressionConfig::default(),
986 batch_size: default_batch_size(),
987 include_acdoca: true,
988 include_bseg: false,
989 partition_by_period: true,
990 partition_by_company: false,
991 }
992 }
993}
994
995#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
997#[serde(rename_all = "snake_case")]
998pub enum OutputMode {
999 Streaming,
1001 #[default]
1003 FlatFile,
1004 Both,
1006}
1007
1008#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1010#[serde(rename_all = "snake_case")]
1011pub enum FileFormat {
1012 Csv,
1013 Parquet,
1014 Json,
1015 JsonLines,
1016}
1017
1018#[derive(Debug, Clone, Serialize, Deserialize)]
1020pub struct CompressionConfig {
1021 #[serde(default = "default_true")]
1023 pub enabled: bool,
1024 #[serde(default)]
1026 pub algorithm: CompressionAlgorithm,
1027 #[serde(default = "default_compression_level")]
1029 pub level: u8,
1030}
1031
1032fn default_compression_level() -> u8 {
1033 3
1034}
1035
1036impl Default for CompressionConfig {
1037 fn default() -> Self {
1038 Self {
1039 enabled: true,
1040 algorithm: CompressionAlgorithm::default(),
1041 level: default_compression_level(),
1042 }
1043 }
1044}
1045
1046#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
1048#[serde(rename_all = "snake_case")]
1049pub enum CompressionAlgorithm {
1050 Gzip,
1051 #[default]
1052 Zstd,
1053 Lz4,
1054 Snappy,
1055}
1056
1057#[derive(Debug, Clone, Serialize, Deserialize)]
1059pub struct FraudConfig {
1060 #[serde(default)]
1062 pub enabled: bool,
1063 #[serde(default = "default_fraud_rate")]
1065 pub fraud_rate: f64,
1066 #[serde(default)]
1068 pub fraud_type_distribution: FraudTypeDistribution,
1069 #[serde(default)]
1071 pub clustering_enabled: bool,
1072 #[serde(default = "default_clustering_factor")]
1074 pub clustering_factor: f64,
1075 #[serde(default = "default_approval_thresholds")]
1077 pub approval_thresholds: Vec<f64>,
1078}
1079
1080fn default_approval_thresholds() -> Vec<f64> {
1081 vec![1000.0, 5000.0, 10000.0, 25000.0, 50000.0, 100000.0]
1082}
1083
1084fn default_fraud_rate() -> f64 {
1085 0.005
1086}
1087fn default_clustering_factor() -> f64 {
1088 3.0
1089}
1090
1091impl Default for FraudConfig {
1092 fn default() -> Self {
1093 Self {
1094 enabled: false,
1095 fraud_rate: default_fraud_rate(),
1096 fraud_type_distribution: FraudTypeDistribution::default(),
1097 clustering_enabled: false,
1098 clustering_factor: default_clustering_factor(),
1099 approval_thresholds: default_approval_thresholds(),
1100 }
1101 }
1102}
1103
1104#[derive(Debug, Clone, Serialize, Deserialize)]
1106pub struct FraudTypeDistribution {
1107 pub suspense_account_abuse: f64,
1108 pub fictitious_transaction: f64,
1109 pub revenue_manipulation: f64,
1110 pub expense_capitalization: f64,
1111 pub split_transaction: f64,
1112 pub timing_anomaly: f64,
1113 pub unauthorized_access: f64,
1114 pub duplicate_payment: f64,
1115}
1116
1117impl Default for FraudTypeDistribution {
1118 fn default() -> Self {
1119 Self {
1120 suspense_account_abuse: 0.25,
1121 fictitious_transaction: 0.15,
1122 revenue_manipulation: 0.10,
1123 expense_capitalization: 0.10,
1124 split_transaction: 0.15,
1125 timing_anomaly: 0.10,
1126 unauthorized_access: 0.10,
1127 duplicate_payment: 0.05,
1128 }
1129 }
1130}
1131
1132#[derive(Debug, Clone, Serialize, Deserialize)]
1134pub struct InternalControlsConfig {
1135 #[serde(default)]
1137 pub enabled: bool,
1138 #[serde(default = "default_exception_rate")]
1140 pub exception_rate: f64,
1141 #[serde(default = "default_sod_violation_rate")]
1143 pub sod_violation_rate: f64,
1144 #[serde(default = "default_true")]
1146 pub export_control_master_data: bool,
1147 #[serde(default = "default_sox_materiality_threshold")]
1149 pub sox_materiality_threshold: f64,
1150 #[serde(default = "default_true")]
1152 pub coso_enabled: bool,
1153 #[serde(default)]
1155 pub include_entity_level_controls: bool,
1156 #[serde(default = "default_target_maturity_level")]
1159 pub target_maturity_level: String,
1160}
1161
1162fn default_exception_rate() -> f64 {
1163 0.02
1164}
1165
1166fn default_sod_violation_rate() -> f64 {
1167 0.01
1168}
1169
1170fn default_sox_materiality_threshold() -> f64 {
1171 10000.0
1172}
1173
1174fn default_target_maturity_level() -> String {
1175 "mixed".to_string()
1176}
1177
1178impl Default for InternalControlsConfig {
1179 fn default() -> Self {
1180 Self {
1181 enabled: false,
1182 exception_rate: default_exception_rate(),
1183 sod_violation_rate: default_sod_violation_rate(),
1184 export_control_master_data: true,
1185 sox_materiality_threshold: default_sox_materiality_threshold(),
1186 coso_enabled: true,
1187 include_entity_level_controls: false,
1188 target_maturity_level: default_target_maturity_level(),
1189 }
1190 }
1191}
1192
1193#[derive(Debug, Clone, Serialize, Deserialize)]
1195pub struct BusinessProcessConfig {
1196 #[serde(default = "default_o2c")]
1198 pub o2c_weight: f64,
1199 #[serde(default = "default_p2p")]
1201 pub p2p_weight: f64,
1202 #[serde(default = "default_r2r")]
1204 pub r2r_weight: f64,
1205 #[serde(default = "default_h2r")]
1207 pub h2r_weight: f64,
1208 #[serde(default = "default_a2r")]
1210 pub a2r_weight: f64,
1211}
1212
1213fn default_o2c() -> f64 {
1214 0.35
1215}
1216fn default_p2p() -> f64 {
1217 0.30
1218}
1219fn default_r2r() -> f64 {
1220 0.20
1221}
1222fn default_h2r() -> f64 {
1223 0.10
1224}
1225fn default_a2r() -> f64 {
1226 0.05
1227}
1228
1229impl Default for BusinessProcessConfig {
1230 fn default() -> Self {
1231 Self {
1232 o2c_weight: default_o2c(),
1233 p2p_weight: default_p2p(),
1234 r2r_weight: default_r2r(),
1235 h2r_weight: default_h2r(),
1236 a2r_weight: default_a2r(),
1237 }
1238 }
1239}
1240
1241#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1243pub struct UserPersonaConfig {
1244 #[serde(default)]
1246 pub persona_distribution: PersonaDistribution,
1247 #[serde(default)]
1249 pub users_per_persona: UsersPerPersona,
1250}
1251
1252#[derive(Debug, Clone, Serialize, Deserialize)]
1254pub struct PersonaDistribution {
1255 pub junior_accountant: f64,
1256 pub senior_accountant: f64,
1257 pub controller: f64,
1258 pub manager: f64,
1259 pub automated_system: f64,
1260}
1261
1262impl Default for PersonaDistribution {
1263 fn default() -> Self {
1264 Self {
1265 junior_accountant: 0.15,
1266 senior_accountant: 0.15,
1267 controller: 0.05,
1268 manager: 0.05,
1269 automated_system: 0.60,
1270 }
1271 }
1272}
1273
1274#[derive(Debug, Clone, Serialize, Deserialize)]
1276pub struct UsersPerPersona {
1277 pub junior_accountant: usize,
1278 pub senior_accountant: usize,
1279 pub controller: usize,
1280 pub manager: usize,
1281 pub automated_system: usize,
1282}
1283
1284impl Default for UsersPerPersona {
1285 fn default() -> Self {
1286 Self {
1287 junior_accountant: 10,
1288 senior_accountant: 5,
1289 controller: 2,
1290 manager: 3,
1291 automated_system: 20,
1292 }
1293 }
1294}
1295
1296#[derive(Debug, Clone, Serialize, Deserialize, Default)]
1298pub struct TemplateConfig {
1299 #[serde(default)]
1301 pub names: NameTemplateConfig,
1302 #[serde(default)]
1304 pub descriptions: DescriptionTemplateConfig,
1305 #[serde(default)]
1307 pub references: ReferenceTemplateConfig,
1308}
1309
1310#[derive(Debug, Clone, Serialize, Deserialize)]
1312pub struct NameTemplateConfig {
1313 #[serde(default)]
1315 pub culture_distribution: CultureDistribution,
1316 #[serde(default = "default_email_domain")]
1318 pub email_domain: String,
1319 #[serde(default = "default_true")]
1321 pub generate_realistic_names: bool,
1322}
1323
1324fn default_email_domain() -> String {
1325 "company.com".to_string()
1326}
1327
1328impl Default for NameTemplateConfig {
1329 fn default() -> Self {
1330 Self {
1331 culture_distribution: CultureDistribution::default(),
1332 email_domain: default_email_domain(),
1333 generate_realistic_names: true,
1334 }
1335 }
1336}
1337
1338#[derive(Debug, Clone, Serialize, Deserialize)]
1340pub struct CultureDistribution {
1341 pub western_us: f64,
1342 pub hispanic: f64,
1343 pub german: f64,
1344 pub french: f64,
1345 pub chinese: f64,
1346 pub japanese: f64,
1347 pub indian: f64,
1348}
1349
1350impl Default for CultureDistribution {
1351 fn default() -> Self {
1352 Self {
1353 western_us: 0.40,
1354 hispanic: 0.20,
1355 german: 0.10,
1356 french: 0.05,
1357 chinese: 0.10,
1358 japanese: 0.05,
1359 indian: 0.10,
1360 }
1361 }
1362}
1363
1364#[derive(Debug, Clone, Serialize, Deserialize)]
1366pub struct DescriptionTemplateConfig {
1367 #[serde(default = "default_true")]
1369 pub generate_header_text: bool,
1370 #[serde(default = "default_true")]
1372 pub generate_line_text: bool,
1373}
1374
1375impl Default for DescriptionTemplateConfig {
1376 fn default() -> Self {
1377 Self {
1378 generate_header_text: true,
1379 generate_line_text: true,
1380 }
1381 }
1382}
1383
1384#[derive(Debug, Clone, Serialize, Deserialize)]
1386pub struct ReferenceTemplateConfig {
1387 #[serde(default = "default_true")]
1389 pub generate_references: bool,
1390 #[serde(default = "default_invoice_prefix")]
1392 pub invoice_prefix: String,
1393 #[serde(default = "default_po_prefix")]
1395 pub po_prefix: String,
1396 #[serde(default = "default_so_prefix")]
1398 pub so_prefix: String,
1399}
1400
1401fn default_invoice_prefix() -> String {
1402 "INV".to_string()
1403}
1404fn default_po_prefix() -> String {
1405 "PO".to_string()
1406}
1407fn default_so_prefix() -> String {
1408 "SO".to_string()
1409}
1410
1411impl Default for ReferenceTemplateConfig {
1412 fn default() -> Self {
1413 Self {
1414 generate_references: true,
1415 invoice_prefix: default_invoice_prefix(),
1416 po_prefix: default_po_prefix(),
1417 so_prefix: default_so_prefix(),
1418 }
1419 }
1420}
1421
1422#[derive(Debug, Clone, Serialize, Deserialize)]
1424pub struct ApprovalConfig {
1425 #[serde(default)]
1427 pub enabled: bool,
1428 #[serde(default = "default_auto_approve_threshold")]
1430 pub auto_approve_threshold: f64,
1431 #[serde(default = "default_rejection_rate")]
1433 pub rejection_rate: f64,
1434 #[serde(default = "default_revision_rate")]
1436 pub revision_rate: f64,
1437 #[serde(default = "default_approval_delay_hours")]
1439 pub average_approval_delay_hours: f64,
1440 #[serde(default)]
1442 pub thresholds: Vec<ApprovalThresholdConfig>,
1443}
1444
1445fn default_auto_approve_threshold() -> f64 {
1446 1000.0
1447}
1448fn default_rejection_rate() -> f64 {
1449 0.02
1450}
1451fn default_revision_rate() -> f64 {
1452 0.05
1453}
1454fn default_approval_delay_hours() -> f64 {
1455 4.0
1456}
1457
1458impl Default for ApprovalConfig {
1459 fn default() -> Self {
1460 Self {
1461 enabled: false,
1462 auto_approve_threshold: default_auto_approve_threshold(),
1463 rejection_rate: default_rejection_rate(),
1464 revision_rate: default_revision_rate(),
1465 average_approval_delay_hours: default_approval_delay_hours(),
1466 thresholds: vec![
1467 ApprovalThresholdConfig {
1468 amount: 1000.0,
1469 level: 1,
1470 roles: vec!["senior_accountant".to_string()],
1471 },
1472 ApprovalThresholdConfig {
1473 amount: 10000.0,
1474 level: 2,
1475 roles: vec!["senior_accountant".to_string(), "controller".to_string()],
1476 },
1477 ApprovalThresholdConfig {
1478 amount: 100000.0,
1479 level: 3,
1480 roles: vec![
1481 "senior_accountant".to_string(),
1482 "controller".to_string(),
1483 "manager".to_string(),
1484 ],
1485 },
1486 ApprovalThresholdConfig {
1487 amount: 500000.0,
1488 level: 4,
1489 roles: vec![
1490 "senior_accountant".to_string(),
1491 "controller".to_string(),
1492 "manager".to_string(),
1493 "executive".to_string(),
1494 ],
1495 },
1496 ],
1497 }
1498 }
1499}
1500
1501#[derive(Debug, Clone, Serialize, Deserialize)]
1503pub struct ApprovalThresholdConfig {
1504 pub amount: f64,
1506 pub level: u8,
1508 pub roles: Vec<String>,
1510}
1511
1512#[derive(Debug, Clone, Serialize, Deserialize)]
1514pub struct DepartmentConfig {
1515 #[serde(default)]
1517 pub enabled: bool,
1518 #[serde(default = "default_headcount_multiplier")]
1520 pub headcount_multiplier: f64,
1521 #[serde(default)]
1523 pub custom_departments: Vec<CustomDepartmentConfig>,
1524}
1525
1526fn default_headcount_multiplier() -> f64 {
1527 1.0
1528}
1529
1530impl Default for DepartmentConfig {
1531 fn default() -> Self {
1532 Self {
1533 enabled: false,
1534 headcount_multiplier: default_headcount_multiplier(),
1535 custom_departments: Vec::new(),
1536 }
1537 }
1538}
1539
1540#[derive(Debug, Clone, Serialize, Deserialize)]
1542pub struct CustomDepartmentConfig {
1543 pub code: String,
1545 pub name: String,
1547 #[serde(default)]
1549 pub cost_center: Option<String>,
1550 #[serde(default)]
1552 pub primary_processes: Vec<String>,
1553 #[serde(default)]
1555 pub parent_code: Option<String>,
1556}
1557
1558#[derive(Debug, Clone, Default, Serialize, Deserialize)]
1564pub struct MasterDataConfig {
1565 #[serde(default)]
1567 pub vendors: VendorMasterConfig,
1568 #[serde(default)]
1570 pub customers: CustomerMasterConfig,
1571 #[serde(default)]
1573 pub materials: MaterialMasterConfig,
1574 #[serde(default)]
1576 pub fixed_assets: FixedAssetMasterConfig,
1577 #[serde(default)]
1579 pub employees: EmployeeMasterConfig,
1580 #[serde(default)]
1582 pub cost_centers: CostCenterMasterConfig,
1583}
1584
1585#[derive(Debug, Clone, Serialize, Deserialize)]
1587pub struct VendorMasterConfig {
1588 #[serde(default = "default_vendor_count")]
1590 pub count: usize,
1591 #[serde(default = "default_intercompany_percent")]
1593 pub intercompany_percent: f64,
1594 #[serde(default)]
1596 pub payment_terms_distribution: PaymentTermsDistribution,
1597 #[serde(default)]
1599 pub behavior_distribution: VendorBehaviorDistribution,
1600 #[serde(default = "default_true")]
1602 pub generate_bank_accounts: bool,
1603 #[serde(default = "default_true")]
1605 pub generate_tax_ids: bool,
1606}
1607
1608fn default_vendor_count() -> usize {
1609 500
1610}
1611
1612fn default_intercompany_percent() -> f64 {
1613 0.05
1614}
1615
1616impl Default for VendorMasterConfig {
1617 fn default() -> Self {
1618 Self {
1619 count: default_vendor_count(),
1620 intercompany_percent: default_intercompany_percent(),
1621 payment_terms_distribution: PaymentTermsDistribution::default(),
1622 behavior_distribution: VendorBehaviorDistribution::default(),
1623 generate_bank_accounts: true,
1624 generate_tax_ids: true,
1625 }
1626 }
1627}
1628
1629#[derive(Debug, Clone, Serialize, Deserialize)]
1631pub struct PaymentTermsDistribution {
1632 pub net_30: f64,
1634 pub net_60: f64,
1636 pub net_90: f64,
1638 pub two_ten_net_30: f64,
1640 pub due_on_receipt: f64,
1642 pub end_of_month: f64,
1644}
1645
1646impl Default for PaymentTermsDistribution {
1647 fn default() -> Self {
1648 Self {
1649 net_30: 0.40,
1650 net_60: 0.20,
1651 net_90: 0.10,
1652 two_ten_net_30: 0.15,
1653 due_on_receipt: 0.05,
1654 end_of_month: 0.10,
1655 }
1656 }
1657}
1658
1659#[derive(Debug, Clone, Serialize, Deserialize)]
1661pub struct VendorBehaviorDistribution {
1662 pub reliable: f64,
1664 pub sometimes_late: f64,
1666 pub inconsistent_quality: f64,
1668 pub premium: f64,
1670 pub budget: f64,
1672}
1673
1674impl Default for VendorBehaviorDistribution {
1675 fn default() -> Self {
1676 Self {
1677 reliable: 0.50,
1678 sometimes_late: 0.20,
1679 inconsistent_quality: 0.10,
1680 premium: 0.10,
1681 budget: 0.10,
1682 }
1683 }
1684}
1685
1686#[derive(Debug, Clone, Serialize, Deserialize)]
1688pub struct CustomerMasterConfig {
1689 #[serde(default = "default_customer_count")]
1691 pub count: usize,
1692 #[serde(default = "default_intercompany_percent")]
1694 pub intercompany_percent: f64,
1695 #[serde(default)]
1697 pub credit_rating_distribution: CreditRatingDistribution,
1698 #[serde(default)]
1700 pub payment_behavior_distribution: PaymentBehaviorDistribution,
1701 #[serde(default = "default_true")]
1703 pub generate_credit_limits: bool,
1704}
1705
1706fn default_customer_count() -> usize {
1707 2000
1708}
1709
1710impl Default for CustomerMasterConfig {
1711 fn default() -> Self {
1712 Self {
1713 count: default_customer_count(),
1714 intercompany_percent: default_intercompany_percent(),
1715 credit_rating_distribution: CreditRatingDistribution::default(),
1716 payment_behavior_distribution: PaymentBehaviorDistribution::default(),
1717 generate_credit_limits: true,
1718 }
1719 }
1720}
1721
1722#[derive(Debug, Clone, Serialize, Deserialize)]
1724pub struct CreditRatingDistribution {
1725 pub aaa: f64,
1727 pub aa: f64,
1729 pub a: f64,
1731 pub bbb: f64,
1733 pub bb: f64,
1735 pub b: f64,
1737 pub below_b: f64,
1739}
1740
1741impl Default for CreditRatingDistribution {
1742 fn default() -> Self {
1743 Self {
1744 aaa: 0.05,
1745 aa: 0.10,
1746 a: 0.20,
1747 bbb: 0.30,
1748 bb: 0.20,
1749 b: 0.10,
1750 below_b: 0.05,
1751 }
1752 }
1753}
1754
1755#[derive(Debug, Clone, Serialize, Deserialize)]
1757pub struct PaymentBehaviorDistribution {
1758 pub early_payer: f64,
1760 pub on_time: f64,
1762 pub occasional_late: f64,
1764 pub frequent_late: f64,
1766 pub discount_taker: f64,
1768}
1769
1770impl Default for PaymentBehaviorDistribution {
1771 fn default() -> Self {
1772 Self {
1773 early_payer: 0.10,
1774 on_time: 0.50,
1775 occasional_late: 0.25,
1776 frequent_late: 0.10,
1777 discount_taker: 0.05,
1778 }
1779 }
1780}
1781
1782#[derive(Debug, Clone, Serialize, Deserialize)]
1784pub struct MaterialMasterConfig {
1785 #[serde(default = "default_material_count")]
1787 pub count: usize,
1788 #[serde(default)]
1790 pub type_distribution: MaterialTypeDistribution,
1791 #[serde(default)]
1793 pub valuation_distribution: ValuationMethodDistribution,
1794 #[serde(default = "default_bom_percent")]
1796 pub bom_percent: f64,
1797 #[serde(default = "default_max_bom_depth")]
1799 pub max_bom_depth: u8,
1800}
1801
1802fn default_material_count() -> usize {
1803 5000
1804}
1805
1806fn default_bom_percent() -> f64 {
1807 0.20
1808}
1809
1810fn default_max_bom_depth() -> u8 {
1811 3
1812}
1813
1814impl Default for MaterialMasterConfig {
1815 fn default() -> Self {
1816 Self {
1817 count: default_material_count(),
1818 type_distribution: MaterialTypeDistribution::default(),
1819 valuation_distribution: ValuationMethodDistribution::default(),
1820 bom_percent: default_bom_percent(),
1821 max_bom_depth: default_max_bom_depth(),
1822 }
1823 }
1824}
1825
1826#[derive(Debug, Clone, Serialize, Deserialize)]
1828pub struct MaterialTypeDistribution {
1829 pub raw_material: f64,
1831 pub semi_finished: f64,
1833 pub finished_good: f64,
1835 pub trading_good: f64,
1837 pub operating_supply: f64,
1839 pub service: f64,
1841}
1842
1843impl Default for MaterialTypeDistribution {
1844 fn default() -> Self {
1845 Self {
1846 raw_material: 0.30,
1847 semi_finished: 0.15,
1848 finished_good: 0.25,
1849 trading_good: 0.15,
1850 operating_supply: 0.10,
1851 service: 0.05,
1852 }
1853 }
1854}
1855
1856#[derive(Debug, Clone, Serialize, Deserialize)]
1858pub struct ValuationMethodDistribution {
1859 pub standard_cost: f64,
1861 pub moving_average: f64,
1863 pub fifo: f64,
1865 pub lifo: f64,
1867}
1868
1869impl Default for ValuationMethodDistribution {
1870 fn default() -> Self {
1871 Self {
1872 standard_cost: 0.50,
1873 moving_average: 0.30,
1874 fifo: 0.15,
1875 lifo: 0.05,
1876 }
1877 }
1878}
1879
1880#[derive(Debug, Clone, Serialize, Deserialize)]
1882pub struct FixedAssetMasterConfig {
1883 #[serde(default = "default_asset_count")]
1885 pub count: usize,
1886 #[serde(default)]
1888 pub class_distribution: AssetClassDistribution,
1889 #[serde(default)]
1891 pub depreciation_distribution: DepreciationMethodDistribution,
1892 #[serde(default = "default_fully_depreciated_percent")]
1894 pub fully_depreciated_percent: f64,
1895 #[serde(default = "default_true")]
1897 pub generate_acquisition_history: bool,
1898}
1899
1900fn default_asset_count() -> usize {
1901 800
1902}
1903
1904fn default_fully_depreciated_percent() -> f64 {
1905 0.15
1906}
1907
1908impl Default for FixedAssetMasterConfig {
1909 fn default() -> Self {
1910 Self {
1911 count: default_asset_count(),
1912 class_distribution: AssetClassDistribution::default(),
1913 depreciation_distribution: DepreciationMethodDistribution::default(),
1914 fully_depreciated_percent: default_fully_depreciated_percent(),
1915 generate_acquisition_history: true,
1916 }
1917 }
1918}
1919
1920#[derive(Debug, Clone, Serialize, Deserialize)]
1922pub struct AssetClassDistribution {
1923 pub buildings: f64,
1925 pub machinery: f64,
1927 pub vehicles: f64,
1929 pub it_equipment: f64,
1931 pub furniture: f64,
1933 pub land: f64,
1935 pub leasehold: f64,
1937}
1938
1939impl Default for AssetClassDistribution {
1940 fn default() -> Self {
1941 Self {
1942 buildings: 0.15,
1943 machinery: 0.30,
1944 vehicles: 0.15,
1945 it_equipment: 0.20,
1946 furniture: 0.10,
1947 land: 0.05,
1948 leasehold: 0.05,
1949 }
1950 }
1951}
1952
1953#[derive(Debug, Clone, Serialize, Deserialize)]
1955pub struct DepreciationMethodDistribution {
1956 pub straight_line: f64,
1958 pub declining_balance: f64,
1960 pub double_declining: f64,
1962 pub sum_of_years: f64,
1964 pub units_of_production: f64,
1966}
1967
1968impl Default for DepreciationMethodDistribution {
1969 fn default() -> Self {
1970 Self {
1971 straight_line: 0.60,
1972 declining_balance: 0.20,
1973 double_declining: 0.10,
1974 sum_of_years: 0.05,
1975 units_of_production: 0.05,
1976 }
1977 }
1978}
1979
1980#[derive(Debug, Clone, Serialize, Deserialize)]
1982pub struct EmployeeMasterConfig {
1983 #[serde(default = "default_employee_count")]
1985 pub count: usize,
1986 #[serde(default = "default_true")]
1988 pub generate_hierarchy: bool,
1989 #[serde(default = "default_hierarchy_depth")]
1991 pub max_hierarchy_depth: u8,
1992 #[serde(default = "default_span_of_control")]
1994 pub average_span_of_control: f64,
1995 #[serde(default)]
1997 pub approval_limits: ApprovalLimitDistribution,
1998 #[serde(default)]
2000 pub department_distribution: EmployeeDepartmentDistribution,
2001}
2002
2003fn default_employee_count() -> usize {
2004 1500
2005}
2006
2007fn default_hierarchy_depth() -> u8 {
2008 6
2009}
2010
2011fn default_span_of_control() -> f64 {
2012 5.0
2013}
2014
2015impl Default for EmployeeMasterConfig {
2016 fn default() -> Self {
2017 Self {
2018 count: default_employee_count(),
2019 generate_hierarchy: true,
2020 max_hierarchy_depth: default_hierarchy_depth(),
2021 average_span_of_control: default_span_of_control(),
2022 approval_limits: ApprovalLimitDistribution::default(),
2023 department_distribution: EmployeeDepartmentDistribution::default(),
2024 }
2025 }
2026}
2027
2028#[derive(Debug, Clone, Serialize, Deserialize)]
2030pub struct ApprovalLimitDistribution {
2031 #[serde(default = "default_staff_limit")]
2033 pub staff: f64,
2034 #[serde(default = "default_senior_limit")]
2036 pub senior: f64,
2037 #[serde(default = "default_manager_limit")]
2039 pub manager: f64,
2040 #[serde(default = "default_director_limit")]
2042 pub director: f64,
2043 #[serde(default = "default_vp_limit")]
2045 pub vp: f64,
2046 #[serde(default = "default_executive_limit")]
2048 pub executive: f64,
2049}
2050
2051fn default_staff_limit() -> f64 {
2052 1000.0
2053}
2054fn default_senior_limit() -> f64 {
2055 5000.0
2056}
2057fn default_manager_limit() -> f64 {
2058 25000.0
2059}
2060fn default_director_limit() -> f64 {
2061 100000.0
2062}
2063fn default_vp_limit() -> f64 {
2064 500000.0
2065}
2066fn default_executive_limit() -> f64 {
2067 f64::INFINITY
2068}
2069
2070impl Default for ApprovalLimitDistribution {
2071 fn default() -> Self {
2072 Self {
2073 staff: default_staff_limit(),
2074 senior: default_senior_limit(),
2075 manager: default_manager_limit(),
2076 director: default_director_limit(),
2077 vp: default_vp_limit(),
2078 executive: default_executive_limit(),
2079 }
2080 }
2081}
2082
2083#[derive(Debug, Clone, Serialize, Deserialize)]
2085pub struct EmployeeDepartmentDistribution {
2086 pub finance: f64,
2088 pub procurement: f64,
2090 pub sales: f64,
2092 pub warehouse: f64,
2094 pub it: f64,
2096 pub hr: f64,
2098 pub operations: f64,
2100 pub executive: f64,
2102}
2103
2104impl Default for EmployeeDepartmentDistribution {
2105 fn default() -> Self {
2106 Self {
2107 finance: 0.12,
2108 procurement: 0.10,
2109 sales: 0.25,
2110 warehouse: 0.15,
2111 it: 0.10,
2112 hr: 0.05,
2113 operations: 0.20,
2114 executive: 0.03,
2115 }
2116 }
2117}
2118
2119#[derive(Debug, Clone, Serialize, Deserialize)]
2121pub struct CostCenterMasterConfig {
2122 #[serde(default = "default_cost_center_count")]
2124 pub count: usize,
2125 #[serde(default = "default_true")]
2127 pub generate_hierarchy: bool,
2128 #[serde(default = "default_cc_hierarchy_depth")]
2130 pub max_hierarchy_depth: u8,
2131}
2132
2133fn default_cost_center_count() -> usize {
2134 50
2135}
2136
2137fn default_cc_hierarchy_depth() -> u8 {
2138 3
2139}
2140
2141impl Default for CostCenterMasterConfig {
2142 fn default() -> Self {
2143 Self {
2144 count: default_cost_center_count(),
2145 generate_hierarchy: true,
2146 max_hierarchy_depth: default_cc_hierarchy_depth(),
2147 }
2148 }
2149}
2150
2151#[derive(Debug, Clone, Serialize, Deserialize)]
2157pub struct DocumentFlowConfig {
2158 #[serde(default)]
2160 pub p2p: P2PFlowConfig,
2161 #[serde(default)]
2163 pub o2c: O2CFlowConfig,
2164 #[serde(default = "default_true")]
2166 pub generate_document_references: bool,
2167 #[serde(default)]
2169 pub export_flow_graph: bool,
2170}
2171
2172impl Default for DocumentFlowConfig {
2173 fn default() -> Self {
2174 Self {
2175 p2p: P2PFlowConfig::default(),
2176 o2c: O2CFlowConfig::default(),
2177 generate_document_references: true,
2178 export_flow_graph: false,
2179 }
2180 }
2181}
2182
2183#[derive(Debug, Clone, Serialize, Deserialize)]
2185pub struct P2PFlowConfig {
2186 #[serde(default = "default_true")]
2188 pub enabled: bool,
2189 #[serde(default = "default_three_way_match_rate")]
2191 pub three_way_match_rate: f64,
2192 #[serde(default = "default_partial_delivery_rate")]
2194 pub partial_delivery_rate: f64,
2195 #[serde(default = "default_price_variance_rate")]
2197 pub price_variance_rate: f64,
2198 #[serde(default = "default_max_price_variance")]
2200 pub max_price_variance_percent: f64,
2201 #[serde(default = "default_quantity_variance_rate")]
2203 pub quantity_variance_rate: f64,
2204 #[serde(default = "default_po_to_gr_days")]
2206 pub average_po_to_gr_days: u32,
2207 #[serde(default = "default_gr_to_invoice_days")]
2209 pub average_gr_to_invoice_days: u32,
2210 #[serde(default = "default_invoice_to_payment_days")]
2212 pub average_invoice_to_payment_days: u32,
2213 #[serde(default)]
2215 pub line_count_distribution: DocumentLineCountDistribution,
2216 #[serde(default)]
2218 pub payment_behavior: P2PPaymentBehaviorConfig,
2219}
2220
2221fn default_three_way_match_rate() -> f64 {
2222 0.95
2223}
2224
2225fn default_partial_delivery_rate() -> f64 {
2226 0.15
2227}
2228
2229fn default_price_variance_rate() -> f64 {
2230 0.08
2231}
2232
2233fn default_max_price_variance() -> f64 {
2234 0.05
2235}
2236
2237fn default_quantity_variance_rate() -> f64 {
2238 0.05
2239}
2240
2241fn default_po_to_gr_days() -> u32 {
2242 14
2243}
2244
2245fn default_gr_to_invoice_days() -> u32 {
2246 5
2247}
2248
2249fn default_invoice_to_payment_days() -> u32 {
2250 30
2251}
2252
2253impl Default for P2PFlowConfig {
2254 fn default() -> Self {
2255 Self {
2256 enabled: true,
2257 three_way_match_rate: default_three_way_match_rate(),
2258 partial_delivery_rate: default_partial_delivery_rate(),
2259 price_variance_rate: default_price_variance_rate(),
2260 max_price_variance_percent: default_max_price_variance(),
2261 quantity_variance_rate: default_quantity_variance_rate(),
2262 average_po_to_gr_days: default_po_to_gr_days(),
2263 average_gr_to_invoice_days: default_gr_to_invoice_days(),
2264 average_invoice_to_payment_days: default_invoice_to_payment_days(),
2265 line_count_distribution: DocumentLineCountDistribution::default(),
2266 payment_behavior: P2PPaymentBehaviorConfig::default(),
2267 }
2268 }
2269}
2270
2271#[derive(Debug, Clone, Serialize, Deserialize)]
2277pub struct P2PPaymentBehaviorConfig {
2278 #[serde(default = "default_p2p_late_payment_rate")]
2280 pub late_payment_rate: f64,
2281 #[serde(default)]
2283 pub late_payment_days_distribution: LatePaymentDaysDistribution,
2284 #[serde(default = "default_p2p_partial_payment_rate")]
2286 pub partial_payment_rate: f64,
2287 #[serde(default = "default_p2p_payment_correction_rate")]
2289 pub payment_correction_rate: f64,
2290}
2291
2292fn default_p2p_late_payment_rate() -> f64 {
2293 0.15
2294}
2295
2296fn default_p2p_partial_payment_rate() -> f64 {
2297 0.05
2298}
2299
2300fn default_p2p_payment_correction_rate() -> f64 {
2301 0.02
2302}
2303
2304impl Default for P2PPaymentBehaviorConfig {
2305 fn default() -> Self {
2306 Self {
2307 late_payment_rate: default_p2p_late_payment_rate(),
2308 late_payment_days_distribution: LatePaymentDaysDistribution::default(),
2309 partial_payment_rate: default_p2p_partial_payment_rate(),
2310 payment_correction_rate: default_p2p_payment_correction_rate(),
2311 }
2312 }
2313}
2314
2315#[derive(Debug, Clone, Serialize, Deserialize)]
2317pub struct LatePaymentDaysDistribution {
2318 #[serde(default = "default_slightly_late")]
2320 pub slightly_late_1_to_7: f64,
2321 #[serde(default = "default_late_8_14")]
2323 pub late_8_to_14: f64,
2324 #[serde(default = "default_very_late")]
2326 pub very_late_15_to_30: f64,
2327 #[serde(default = "default_severely_late")]
2329 pub severely_late_31_to_60: f64,
2330 #[serde(default = "default_extremely_late")]
2332 pub extremely_late_over_60: f64,
2333}
2334
2335fn default_slightly_late() -> f64 {
2336 0.50
2337}
2338
2339fn default_late_8_14() -> f64 {
2340 0.25
2341}
2342
2343fn default_very_late() -> f64 {
2344 0.15
2345}
2346
2347fn default_severely_late() -> f64 {
2348 0.07
2349}
2350
2351fn default_extremely_late() -> f64 {
2352 0.03
2353}
2354
2355impl Default for LatePaymentDaysDistribution {
2356 fn default() -> Self {
2357 Self {
2358 slightly_late_1_to_7: default_slightly_late(),
2359 late_8_to_14: default_late_8_14(),
2360 very_late_15_to_30: default_very_late(),
2361 severely_late_31_to_60: default_severely_late(),
2362 extremely_late_over_60: default_extremely_late(),
2363 }
2364 }
2365}
2366
2367#[derive(Debug, Clone, Serialize, Deserialize)]
2369pub struct O2CFlowConfig {
2370 #[serde(default = "default_true")]
2372 pub enabled: bool,
2373 #[serde(default = "default_credit_check_failure_rate")]
2375 pub credit_check_failure_rate: f64,
2376 #[serde(default = "default_partial_shipment_rate")]
2378 pub partial_shipment_rate: f64,
2379 #[serde(default = "default_return_rate")]
2381 pub return_rate: f64,
2382 #[serde(default = "default_bad_debt_rate")]
2384 pub bad_debt_rate: f64,
2385 #[serde(default = "default_so_to_delivery_days")]
2387 pub average_so_to_delivery_days: u32,
2388 #[serde(default = "default_delivery_to_invoice_days")]
2390 pub average_delivery_to_invoice_days: u32,
2391 #[serde(default = "default_invoice_to_receipt_days")]
2393 pub average_invoice_to_receipt_days: u32,
2394 #[serde(default)]
2396 pub line_count_distribution: DocumentLineCountDistribution,
2397 #[serde(default)]
2399 pub cash_discount: CashDiscountConfig,
2400 #[serde(default)]
2402 pub payment_behavior: O2CPaymentBehaviorConfig,
2403}
2404
2405fn default_credit_check_failure_rate() -> f64 {
2406 0.02
2407}
2408
2409fn default_partial_shipment_rate() -> f64 {
2410 0.10
2411}
2412
2413fn default_return_rate() -> f64 {
2414 0.03
2415}
2416
2417fn default_bad_debt_rate() -> f64 {
2418 0.01
2419}
2420
2421fn default_so_to_delivery_days() -> u32 {
2422 7
2423}
2424
2425fn default_delivery_to_invoice_days() -> u32 {
2426 1
2427}
2428
2429fn default_invoice_to_receipt_days() -> u32 {
2430 45
2431}
2432
2433impl Default for O2CFlowConfig {
2434 fn default() -> Self {
2435 Self {
2436 enabled: true,
2437 credit_check_failure_rate: default_credit_check_failure_rate(),
2438 partial_shipment_rate: default_partial_shipment_rate(),
2439 return_rate: default_return_rate(),
2440 bad_debt_rate: default_bad_debt_rate(),
2441 average_so_to_delivery_days: default_so_to_delivery_days(),
2442 average_delivery_to_invoice_days: default_delivery_to_invoice_days(),
2443 average_invoice_to_receipt_days: default_invoice_to_receipt_days(),
2444 line_count_distribution: DocumentLineCountDistribution::default(),
2445 cash_discount: CashDiscountConfig::default(),
2446 payment_behavior: O2CPaymentBehaviorConfig::default(),
2447 }
2448 }
2449}
2450
2451#[derive(Debug, Clone, Serialize, Deserialize, Default)]
2457pub struct O2CPaymentBehaviorConfig {
2458 #[serde(default)]
2460 pub dunning: DunningConfig,
2461 #[serde(default)]
2463 pub partial_payments: PartialPaymentConfig,
2464 #[serde(default)]
2466 pub short_payments: ShortPaymentConfig,
2467 #[serde(default)]
2469 pub on_account_payments: OnAccountPaymentConfig,
2470 #[serde(default)]
2472 pub payment_corrections: PaymentCorrectionConfig,
2473}
2474
2475#[derive(Debug, Clone, Serialize, Deserialize)]
2477pub struct DunningConfig {
2478 #[serde(default)]
2480 pub enabled: bool,
2481 #[serde(default = "default_dunning_level_1_days")]
2483 pub level_1_days_overdue: u32,
2484 #[serde(default = "default_dunning_level_2_days")]
2486 pub level_2_days_overdue: u32,
2487 #[serde(default = "default_dunning_level_3_days")]
2489 pub level_3_days_overdue: u32,
2490 #[serde(default = "default_collection_days")]
2492 pub collection_days_overdue: u32,
2493 #[serde(default)]
2495 pub payment_after_dunning_rates: DunningPaymentRates,
2496 #[serde(default = "default_dunning_block_rate")]
2498 pub dunning_block_rate: f64,
2499 #[serde(default = "default_dunning_interest_rate")]
2501 pub interest_rate_per_year: f64,
2502 #[serde(default = "default_dunning_charge")]
2504 pub dunning_charge: f64,
2505}
2506
2507fn default_dunning_level_1_days() -> u32 {
2508 14
2509}
2510
2511fn default_dunning_level_2_days() -> u32 {
2512 28
2513}
2514
2515fn default_dunning_level_3_days() -> u32 {
2516 42
2517}
2518
2519fn default_collection_days() -> u32 {
2520 60
2521}
2522
2523fn default_dunning_block_rate() -> f64 {
2524 0.05
2525}
2526
2527fn default_dunning_interest_rate() -> f64 {
2528 0.09
2529}
2530
2531fn default_dunning_charge() -> f64 {
2532 25.0
2533}
2534
2535impl Default for DunningConfig {
2536 fn default() -> Self {
2537 Self {
2538 enabled: false,
2539 level_1_days_overdue: default_dunning_level_1_days(),
2540 level_2_days_overdue: default_dunning_level_2_days(),
2541 level_3_days_overdue: default_dunning_level_3_days(),
2542 collection_days_overdue: default_collection_days(),
2543 payment_after_dunning_rates: DunningPaymentRates::default(),
2544 dunning_block_rate: default_dunning_block_rate(),
2545 interest_rate_per_year: default_dunning_interest_rate(),
2546 dunning_charge: default_dunning_charge(),
2547 }
2548 }
2549}
2550
2551#[derive(Debug, Clone, Serialize, Deserialize)]
2553pub struct DunningPaymentRates {
2554 #[serde(default = "default_after_level_1")]
2556 pub after_level_1: f64,
2557 #[serde(default = "default_after_level_2")]
2559 pub after_level_2: f64,
2560 #[serde(default = "default_after_level_3")]
2562 pub after_level_3: f64,
2563 #[serde(default = "default_during_collection")]
2565 pub during_collection: f64,
2566 #[serde(default = "default_never_pay")]
2568 pub never_pay: f64,
2569}
2570
2571fn default_after_level_1() -> f64 {
2572 0.40
2573}
2574
2575fn default_after_level_2() -> f64 {
2576 0.30
2577}
2578
2579fn default_after_level_3() -> f64 {
2580 0.15
2581}
2582
2583fn default_during_collection() -> f64 {
2584 0.05
2585}
2586
2587fn default_never_pay() -> f64 {
2588 0.10
2589}
2590
2591impl Default for DunningPaymentRates {
2592 fn default() -> Self {
2593 Self {
2594 after_level_1: default_after_level_1(),
2595 after_level_2: default_after_level_2(),
2596 after_level_3: default_after_level_3(),
2597 during_collection: default_during_collection(),
2598 never_pay: default_never_pay(),
2599 }
2600 }
2601}
2602
2603#[derive(Debug, Clone, Serialize, Deserialize)]
2605pub struct PartialPaymentConfig {
2606 #[serde(default = "default_partial_payment_rate")]
2608 pub rate: f64,
2609 #[serde(default)]
2611 pub percentage_distribution: PartialPaymentPercentageDistribution,
2612 #[serde(default = "default_avg_days_until_remainder")]
2614 pub avg_days_until_remainder: u32,
2615}
2616
2617fn default_partial_payment_rate() -> f64 {
2618 0.08
2619}
2620
2621fn default_avg_days_until_remainder() -> u32 {
2622 30
2623}
2624
2625impl Default for PartialPaymentConfig {
2626 fn default() -> Self {
2627 Self {
2628 rate: default_partial_payment_rate(),
2629 percentage_distribution: PartialPaymentPercentageDistribution::default(),
2630 avg_days_until_remainder: default_avg_days_until_remainder(),
2631 }
2632 }
2633}
2634
2635#[derive(Debug, Clone, Serialize, Deserialize)]
2637pub struct PartialPaymentPercentageDistribution {
2638 #[serde(default = "default_partial_25")]
2640 pub pay_25_percent: f64,
2641 #[serde(default = "default_partial_50")]
2643 pub pay_50_percent: f64,
2644 #[serde(default = "default_partial_75")]
2646 pub pay_75_percent: f64,
2647 #[serde(default = "default_partial_random")]
2649 pub pay_random_percent: f64,
2650}
2651
2652fn default_partial_25() -> f64 {
2653 0.15
2654}
2655
2656fn default_partial_50() -> f64 {
2657 0.50
2658}
2659
2660fn default_partial_75() -> f64 {
2661 0.25
2662}
2663
2664fn default_partial_random() -> f64 {
2665 0.10
2666}
2667
2668impl Default for PartialPaymentPercentageDistribution {
2669 fn default() -> Self {
2670 Self {
2671 pay_25_percent: default_partial_25(),
2672 pay_50_percent: default_partial_50(),
2673 pay_75_percent: default_partial_75(),
2674 pay_random_percent: default_partial_random(),
2675 }
2676 }
2677}
2678
2679#[derive(Debug, Clone, Serialize, Deserialize)]
2681pub struct ShortPaymentConfig {
2682 #[serde(default = "default_short_payment_rate")]
2684 pub rate: f64,
2685 #[serde(default)]
2687 pub reason_distribution: ShortPaymentReasonDistribution,
2688 #[serde(default = "default_max_short_percent")]
2690 pub max_short_percent: f64,
2691}
2692
2693fn default_short_payment_rate() -> f64 {
2694 0.03
2695}
2696
2697fn default_max_short_percent() -> f64 {
2698 0.10
2699}
2700
2701impl Default for ShortPaymentConfig {
2702 fn default() -> Self {
2703 Self {
2704 rate: default_short_payment_rate(),
2705 reason_distribution: ShortPaymentReasonDistribution::default(),
2706 max_short_percent: default_max_short_percent(),
2707 }
2708 }
2709}
2710
2711#[derive(Debug, Clone, Serialize, Deserialize)]
2713pub struct ShortPaymentReasonDistribution {
2714 #[serde(default = "default_pricing_dispute")]
2716 pub pricing_dispute: f64,
2717 #[serde(default = "default_quality_issue")]
2719 pub quality_issue: f64,
2720 #[serde(default = "default_quantity_discrepancy")]
2722 pub quantity_discrepancy: f64,
2723 #[serde(default = "default_unauthorized_deduction")]
2725 pub unauthorized_deduction: f64,
2726 #[serde(default = "default_incorrect_discount")]
2728 pub incorrect_discount: f64,
2729}
2730
2731fn default_pricing_dispute() -> f64 {
2732 0.30
2733}
2734
2735fn default_quality_issue() -> f64 {
2736 0.20
2737}
2738
2739fn default_quantity_discrepancy() -> f64 {
2740 0.20
2741}
2742
2743fn default_unauthorized_deduction() -> f64 {
2744 0.15
2745}
2746
2747fn default_incorrect_discount() -> f64 {
2748 0.15
2749}
2750
2751impl Default for ShortPaymentReasonDistribution {
2752 fn default() -> Self {
2753 Self {
2754 pricing_dispute: default_pricing_dispute(),
2755 quality_issue: default_quality_issue(),
2756 quantity_discrepancy: default_quantity_discrepancy(),
2757 unauthorized_deduction: default_unauthorized_deduction(),
2758 incorrect_discount: default_incorrect_discount(),
2759 }
2760 }
2761}
2762
2763#[derive(Debug, Clone, Serialize, Deserialize)]
2765pub struct OnAccountPaymentConfig {
2766 #[serde(default = "default_on_account_rate")]
2768 pub rate: f64,
2769 #[serde(default = "default_avg_days_until_applied")]
2771 pub avg_days_until_applied: u32,
2772}
2773
2774fn default_on_account_rate() -> f64 {
2775 0.02
2776}
2777
2778fn default_avg_days_until_applied() -> u32 {
2779 14
2780}
2781
2782impl Default for OnAccountPaymentConfig {
2783 fn default() -> Self {
2784 Self {
2785 rate: default_on_account_rate(),
2786 avg_days_until_applied: default_avg_days_until_applied(),
2787 }
2788 }
2789}
2790
2791#[derive(Debug, Clone, Serialize, Deserialize)]
2793pub struct PaymentCorrectionConfig {
2794 #[serde(default = "default_payment_correction_rate")]
2796 pub rate: f64,
2797 #[serde(default)]
2799 pub type_distribution: PaymentCorrectionTypeDistribution,
2800}
2801
2802fn default_payment_correction_rate() -> f64 {
2803 0.02
2804}
2805
2806impl Default for PaymentCorrectionConfig {
2807 fn default() -> Self {
2808 Self {
2809 rate: default_payment_correction_rate(),
2810 type_distribution: PaymentCorrectionTypeDistribution::default(),
2811 }
2812 }
2813}
2814
2815#[derive(Debug, Clone, Serialize, Deserialize)]
2817pub struct PaymentCorrectionTypeDistribution {
2818 #[serde(default = "default_nsf_rate")]
2820 pub nsf: f64,
2821 #[serde(default = "default_chargeback_rate")]
2823 pub chargeback: f64,
2824 #[serde(default = "default_wrong_amount_rate")]
2826 pub wrong_amount: f64,
2827 #[serde(default = "default_wrong_customer_rate")]
2829 pub wrong_customer: f64,
2830 #[serde(default = "default_duplicate_payment_rate")]
2832 pub duplicate_payment: f64,
2833}
2834
2835fn default_nsf_rate() -> f64 {
2836 0.30
2837}
2838
2839fn default_chargeback_rate() -> f64 {
2840 0.20
2841}
2842
2843fn default_wrong_amount_rate() -> f64 {
2844 0.20
2845}
2846
2847fn default_wrong_customer_rate() -> f64 {
2848 0.15
2849}
2850
2851fn default_duplicate_payment_rate() -> f64 {
2852 0.15
2853}
2854
2855impl Default for PaymentCorrectionTypeDistribution {
2856 fn default() -> Self {
2857 Self {
2858 nsf: default_nsf_rate(),
2859 chargeback: default_chargeback_rate(),
2860 wrong_amount: default_wrong_amount_rate(),
2861 wrong_customer: default_wrong_customer_rate(),
2862 duplicate_payment: default_duplicate_payment_rate(),
2863 }
2864 }
2865}
2866
2867#[derive(Debug, Clone, Serialize, Deserialize)]
2869pub struct DocumentLineCountDistribution {
2870 #[serde(default = "default_min_lines")]
2872 pub min_lines: u32,
2873 #[serde(default = "default_max_lines")]
2875 pub max_lines: u32,
2876 #[serde(default = "default_mode_lines")]
2878 pub mode_lines: u32,
2879}
2880
2881fn default_min_lines() -> u32 {
2882 1
2883}
2884
2885fn default_max_lines() -> u32 {
2886 20
2887}
2888
2889fn default_mode_lines() -> u32 {
2890 3
2891}
2892
2893impl Default for DocumentLineCountDistribution {
2894 fn default() -> Self {
2895 Self {
2896 min_lines: default_min_lines(),
2897 max_lines: default_max_lines(),
2898 mode_lines: default_mode_lines(),
2899 }
2900 }
2901}
2902
2903#[derive(Debug, Clone, Serialize, Deserialize)]
2905pub struct CashDiscountConfig {
2906 #[serde(default = "default_discount_eligible_rate")]
2908 pub eligible_rate: f64,
2909 #[serde(default = "default_discount_taken_rate")]
2911 pub taken_rate: f64,
2912 #[serde(default = "default_discount_percent")]
2914 pub discount_percent: f64,
2915 #[serde(default = "default_discount_days")]
2917 pub discount_days: u32,
2918}
2919
2920fn default_discount_eligible_rate() -> f64 {
2921 0.30
2922}
2923
2924fn default_discount_taken_rate() -> f64 {
2925 0.60
2926}
2927
2928fn default_discount_percent() -> f64 {
2929 0.02
2930}
2931
2932fn default_discount_days() -> u32 {
2933 10
2934}
2935
2936impl Default for CashDiscountConfig {
2937 fn default() -> Self {
2938 Self {
2939 eligible_rate: default_discount_eligible_rate(),
2940 taken_rate: default_discount_taken_rate(),
2941 discount_percent: default_discount_percent(),
2942 discount_days: default_discount_days(),
2943 }
2944 }
2945}
2946
2947#[derive(Debug, Clone, Serialize, Deserialize)]
2953pub struct IntercompanyConfig {
2954 #[serde(default)]
2956 pub enabled: bool,
2957 #[serde(default = "default_ic_transaction_rate")]
2959 pub ic_transaction_rate: f64,
2960 #[serde(default)]
2962 pub transfer_pricing_method: TransferPricingMethod,
2963 #[serde(default = "default_markup_percent")]
2965 pub markup_percent: f64,
2966 #[serde(default = "default_true")]
2968 pub generate_matched_pairs: bool,
2969 #[serde(default)]
2971 pub transaction_type_distribution: ICTransactionTypeDistribution,
2972 #[serde(default)]
2974 pub generate_eliminations: bool,
2975}
2976
2977fn default_ic_transaction_rate() -> f64 {
2978 0.15
2979}
2980
2981fn default_markup_percent() -> f64 {
2982 0.05
2983}
2984
2985impl Default for IntercompanyConfig {
2986 fn default() -> Self {
2987 Self {
2988 enabled: false,
2989 ic_transaction_rate: default_ic_transaction_rate(),
2990 transfer_pricing_method: TransferPricingMethod::default(),
2991 markup_percent: default_markup_percent(),
2992 generate_matched_pairs: true,
2993 transaction_type_distribution: ICTransactionTypeDistribution::default(),
2994 generate_eliminations: false,
2995 }
2996 }
2997}
2998
2999#[derive(Debug, Clone, Copy, Default, Serialize, Deserialize)]
3001#[serde(rename_all = "snake_case")]
3002pub enum TransferPricingMethod {
3003 #[default]
3005 CostPlus,
3006 ComparableUncontrolled,
3008 ResalePrice,
3010 TransactionalNetMargin,
3012 ProfitSplit,
3014}
3015
3016#[derive(Debug, Clone, Serialize, Deserialize)]
3018pub struct ICTransactionTypeDistribution {
3019 pub goods_sale: f64,
3021 pub service_provided: f64,
3023 pub loan: f64,
3025 pub dividend: f64,
3027 pub management_fee: f64,
3029 pub royalty: f64,
3031 pub cost_sharing: f64,
3033}
3034
3035impl Default for ICTransactionTypeDistribution {
3036 fn default() -> Self {
3037 Self {
3038 goods_sale: 0.35,
3039 service_provided: 0.20,
3040 loan: 0.10,
3041 dividend: 0.05,
3042 management_fee: 0.15,
3043 royalty: 0.10,
3044 cost_sharing: 0.05,
3045 }
3046 }
3047}
3048
3049#[derive(Debug, Clone, Serialize, Deserialize)]
3055pub struct BalanceConfig {
3056 #[serde(default)]
3058 pub generate_opening_balances: bool,
3059 #[serde(default = "default_true")]
3061 pub generate_trial_balances: bool,
3062 #[serde(default = "default_gross_margin")]
3064 pub target_gross_margin: f64,
3065 #[serde(default = "default_dso")]
3067 pub target_dso_days: u32,
3068 #[serde(default = "default_dpo")]
3070 pub target_dpo_days: u32,
3071 #[serde(default = "default_current_ratio")]
3073 pub target_current_ratio: f64,
3074 #[serde(default = "default_debt_equity")]
3076 pub target_debt_to_equity: f64,
3077 #[serde(default = "default_true")]
3079 pub validate_balance_equation: bool,
3080 #[serde(default = "default_true")]
3082 pub reconcile_subledgers: bool,
3083}
3084
3085fn default_gross_margin() -> f64 {
3086 0.35
3087}
3088
3089fn default_dso() -> u32 {
3090 45
3091}
3092
3093fn default_dpo() -> u32 {
3094 30
3095}
3096
3097fn default_current_ratio() -> f64 {
3098 1.5
3099}
3100
3101fn default_debt_equity() -> f64 {
3102 0.5
3103}
3104
3105impl Default for BalanceConfig {
3106 fn default() -> Self {
3107 Self {
3108 generate_opening_balances: false,
3109 generate_trial_balances: true,
3110 target_gross_margin: default_gross_margin(),
3111 target_dso_days: default_dso(),
3112 target_dpo_days: default_dpo(),
3113 target_current_ratio: default_current_ratio(),
3114 target_debt_to_equity: default_debt_equity(),
3115 validate_balance_equation: true,
3116 reconcile_subledgers: true,
3117 }
3118 }
3119}
3120
3121#[derive(Debug, Clone, Serialize, Deserialize)]
3130pub struct OcpmConfig {
3131 #[serde(default)]
3133 pub enabled: bool,
3134
3135 #[serde(default = "default_true")]
3137 pub generate_lifecycle_events: bool,
3138
3139 #[serde(default = "default_true")]
3141 pub include_object_relationships: bool,
3142
3143 #[serde(default = "default_true")]
3145 pub compute_variants: bool,
3146
3147 #[serde(default)]
3149 pub max_variants: usize,
3150
3151 #[serde(default)]
3153 pub p2p_process: OcpmProcessConfig,
3154
3155 #[serde(default)]
3157 pub o2c_process: OcpmProcessConfig,
3158
3159 #[serde(default)]
3161 pub output: OcpmOutputConfig,
3162}
3163
3164impl Default for OcpmConfig {
3165 fn default() -> Self {
3166 Self {
3167 enabled: false,
3168 generate_lifecycle_events: true,
3169 include_object_relationships: true,
3170 compute_variants: true,
3171 max_variants: 0,
3172 p2p_process: OcpmProcessConfig::default(),
3173 o2c_process: OcpmProcessConfig::default(),
3174 output: OcpmOutputConfig::default(),
3175 }
3176 }
3177}
3178
3179#[derive(Debug, Clone, Serialize, Deserialize)]
3181pub struct OcpmProcessConfig {
3182 #[serde(default = "default_rework_probability")]
3184 pub rework_probability: f64,
3185
3186 #[serde(default = "default_skip_probability")]
3188 pub skip_step_probability: f64,
3189
3190 #[serde(default = "default_out_of_order_probability")]
3192 pub out_of_order_probability: f64,
3193}
3194
3195fn default_rework_probability() -> f64 {
3196 0.05
3197}
3198
3199fn default_skip_probability() -> f64 {
3200 0.02
3201}
3202
3203fn default_out_of_order_probability() -> f64 {
3204 0.03
3205}
3206
3207impl Default for OcpmProcessConfig {
3208 fn default() -> Self {
3209 Self {
3210 rework_probability: default_rework_probability(),
3211 skip_step_probability: default_skip_probability(),
3212 out_of_order_probability: default_out_of_order_probability(),
3213 }
3214 }
3215}
3216
3217#[derive(Debug, Clone, Serialize, Deserialize)]
3219pub struct OcpmOutputConfig {
3220 #[serde(default = "default_true")]
3222 pub ocel_json: bool,
3223
3224 #[serde(default)]
3226 pub ocel_xml: bool,
3227
3228 #[serde(default = "default_true")]
3230 pub flattened_csv: bool,
3231
3232 #[serde(default = "default_true")]
3234 pub event_object_csv: bool,
3235
3236 #[serde(default = "default_true")]
3238 pub object_relationship_csv: bool,
3239
3240 #[serde(default = "default_true")]
3242 pub variants_csv: bool,
3243}
3244
3245impl Default for OcpmOutputConfig {
3246 fn default() -> Self {
3247 Self {
3248 ocel_json: true,
3249 ocel_xml: false,
3250 flattened_csv: true,
3251 event_object_csv: true,
3252 object_relationship_csv: true,
3253 variants_csv: true,
3254 }
3255 }
3256}
3257
3258#[derive(Debug, Clone, Serialize, Deserialize)]
3260pub struct AuditGenerationConfig {
3261 #[serde(default)]
3263 pub enabled: bool,
3264
3265 #[serde(default = "default_true")]
3267 pub generate_workpapers: bool,
3268
3269 #[serde(default)]
3271 pub engagement_types: AuditEngagementTypesConfig,
3272
3273 #[serde(default)]
3275 pub workpapers: WorkpaperConfig,
3276
3277 #[serde(default)]
3279 pub team: AuditTeamConfig,
3280
3281 #[serde(default)]
3283 pub review: ReviewWorkflowConfig,
3284}
3285
3286impl Default for AuditGenerationConfig {
3287 fn default() -> Self {
3288 Self {
3289 enabled: false,
3290 generate_workpapers: true,
3291 engagement_types: AuditEngagementTypesConfig::default(),
3292 workpapers: WorkpaperConfig::default(),
3293 team: AuditTeamConfig::default(),
3294 review: ReviewWorkflowConfig::default(),
3295 }
3296 }
3297}
3298
3299#[derive(Debug, Clone, Serialize, Deserialize)]
3301pub struct AuditEngagementTypesConfig {
3302 #[serde(default = "default_financial_audit_prob")]
3304 pub financial_statement: f64,
3305 #[serde(default = "default_sox_audit_prob")]
3307 pub sox_icfr: f64,
3308 #[serde(default = "default_integrated_audit_prob")]
3310 pub integrated: f64,
3311 #[serde(default = "default_review_prob")]
3313 pub review: f64,
3314 #[serde(default = "default_aup_prob")]
3316 pub agreed_upon_procedures: f64,
3317}
3318
3319fn default_financial_audit_prob() -> f64 {
3320 0.40
3321}
3322fn default_sox_audit_prob() -> f64 {
3323 0.20
3324}
3325fn default_integrated_audit_prob() -> f64 {
3326 0.25
3327}
3328fn default_review_prob() -> f64 {
3329 0.10
3330}
3331fn default_aup_prob() -> f64 {
3332 0.05
3333}
3334
3335impl Default for AuditEngagementTypesConfig {
3336 fn default() -> Self {
3337 Self {
3338 financial_statement: default_financial_audit_prob(),
3339 sox_icfr: default_sox_audit_prob(),
3340 integrated: default_integrated_audit_prob(),
3341 review: default_review_prob(),
3342 agreed_upon_procedures: default_aup_prob(),
3343 }
3344 }
3345}
3346
3347#[derive(Debug, Clone, Serialize, Deserialize)]
3349pub struct WorkpaperConfig {
3350 #[serde(default = "default_workpapers_per_phase")]
3352 pub average_per_phase: usize,
3353
3354 #[serde(default = "default_true")]
3356 pub include_isa_references: bool,
3357
3358 #[serde(default = "default_true")]
3360 pub include_sample_details: bool,
3361
3362 #[serde(default = "default_true")]
3364 pub include_cross_references: bool,
3365
3366 #[serde(default)]
3368 pub sampling: SamplingConfig,
3369}
3370
3371fn default_workpapers_per_phase() -> usize {
3372 5
3373}
3374
3375impl Default for WorkpaperConfig {
3376 fn default() -> Self {
3377 Self {
3378 average_per_phase: default_workpapers_per_phase(),
3379 include_isa_references: true,
3380 include_sample_details: true,
3381 include_cross_references: true,
3382 sampling: SamplingConfig::default(),
3383 }
3384 }
3385}
3386
3387#[derive(Debug, Clone, Serialize, Deserialize)]
3389pub struct SamplingConfig {
3390 #[serde(default = "default_statistical_rate")]
3392 pub statistical_rate: f64,
3393 #[serde(default = "default_judgmental_rate")]
3395 pub judgmental_rate: f64,
3396 #[serde(default = "default_haphazard_rate")]
3398 pub haphazard_rate: f64,
3399 #[serde(default = "default_complete_examination_rate")]
3401 pub complete_examination_rate: f64,
3402}
3403
3404fn default_statistical_rate() -> f64 {
3405 0.40
3406}
3407fn default_judgmental_rate() -> f64 {
3408 0.30
3409}
3410fn default_haphazard_rate() -> f64 {
3411 0.20
3412}
3413fn default_complete_examination_rate() -> f64 {
3414 0.10
3415}
3416
3417impl Default for SamplingConfig {
3418 fn default() -> Self {
3419 Self {
3420 statistical_rate: default_statistical_rate(),
3421 judgmental_rate: default_judgmental_rate(),
3422 haphazard_rate: default_haphazard_rate(),
3423 complete_examination_rate: default_complete_examination_rate(),
3424 }
3425 }
3426}
3427
3428#[derive(Debug, Clone, Serialize, Deserialize)]
3430pub struct AuditTeamConfig {
3431 #[serde(default = "default_min_team_size")]
3433 pub min_team_size: usize,
3434 #[serde(default = "default_max_team_size")]
3436 pub max_team_size: usize,
3437 #[serde(default = "default_specialist_probability")]
3439 pub specialist_probability: f64,
3440}
3441
3442fn default_min_team_size() -> usize {
3443 3
3444}
3445fn default_max_team_size() -> usize {
3446 8
3447}
3448fn default_specialist_probability() -> f64 {
3449 0.30
3450}
3451
3452impl Default for AuditTeamConfig {
3453 fn default() -> Self {
3454 Self {
3455 min_team_size: default_min_team_size(),
3456 max_team_size: default_max_team_size(),
3457 specialist_probability: default_specialist_probability(),
3458 }
3459 }
3460}
3461
3462#[derive(Debug, Clone, Serialize, Deserialize)]
3464pub struct ReviewWorkflowConfig {
3465 #[serde(default = "default_review_delay_days")]
3467 pub average_review_delay_days: u32,
3468 #[serde(default = "default_rework_probability_review")]
3470 pub rework_probability: f64,
3471 #[serde(default = "default_true")]
3473 pub require_partner_signoff: bool,
3474}
3475
3476fn default_review_delay_days() -> u32 {
3477 2
3478}
3479fn default_rework_probability_review() -> f64 {
3480 0.15
3481}
3482
3483impl Default for ReviewWorkflowConfig {
3484 fn default() -> Self {
3485 Self {
3486 average_review_delay_days: default_review_delay_days(),
3487 rework_probability: default_rework_probability_review(),
3488 require_partner_signoff: true,
3489 }
3490 }
3491}
3492
3493#[derive(Debug, Clone, Serialize, Deserialize)]
3499pub struct DataQualitySchemaConfig {
3500 #[serde(default)]
3502 pub enabled: bool,
3503 #[serde(default)]
3505 pub preset: DataQualityPreset,
3506 #[serde(default)]
3508 pub missing_values: MissingValuesSchemaConfig,
3509 #[serde(default)]
3511 pub typos: TypoSchemaConfig,
3512 #[serde(default)]
3514 pub format_variations: FormatVariationSchemaConfig,
3515 #[serde(default)]
3517 pub duplicates: DuplicateSchemaConfig,
3518 #[serde(default)]
3520 pub encoding_issues: EncodingIssueSchemaConfig,
3521 #[serde(default)]
3523 pub generate_labels: bool,
3524 #[serde(default)]
3526 pub sink_profiles: SinkQualityProfiles,
3527}
3528
3529impl Default for DataQualitySchemaConfig {
3530 fn default() -> Self {
3531 Self {
3532 enabled: false,
3533 preset: DataQualityPreset::None,
3534 missing_values: MissingValuesSchemaConfig::default(),
3535 typos: TypoSchemaConfig::default(),
3536 format_variations: FormatVariationSchemaConfig::default(),
3537 duplicates: DuplicateSchemaConfig::default(),
3538 encoding_issues: EncodingIssueSchemaConfig::default(),
3539 generate_labels: true,
3540 sink_profiles: SinkQualityProfiles::default(),
3541 }
3542 }
3543}
3544
3545impl DataQualitySchemaConfig {
3546 pub fn with_preset(preset: DataQualityPreset) -> Self {
3548 let mut config = Self {
3549 preset,
3550 ..Default::default()
3551 };
3552 config.apply_preset();
3553 config
3554 }
3555
3556 pub fn apply_preset(&mut self) {
3559 if !self.preset.overrides_settings() {
3560 return;
3561 }
3562
3563 self.enabled = true;
3564
3565 self.missing_values.enabled = self.preset.missing_rate() > 0.0;
3567 self.missing_values.rate = self.preset.missing_rate();
3568
3569 self.typos.enabled = self.preset.typo_rate() > 0.0;
3571 self.typos.char_error_rate = self.preset.typo_rate();
3572
3573 self.duplicates.enabled = self.preset.duplicate_rate() > 0.0;
3575 self.duplicates.exact_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3576 self.duplicates.near_duplicate_ratio = self.preset.duplicate_rate() * 0.4;
3577 self.duplicates.fuzzy_duplicate_ratio = self.preset.duplicate_rate() * 0.2;
3578
3579 self.format_variations.enabled = self.preset.format_variations_enabled();
3581
3582 self.encoding_issues.enabled = self.preset.encoding_issues_enabled();
3584 self.encoding_issues.rate = self.preset.encoding_issue_rate();
3585
3586 if self.preset.ocr_errors_enabled() {
3588 self.typos.type_weights.ocr_errors = 0.3;
3589 }
3590 }
3591
3592 pub fn effective_missing_rate(&self) -> f64 {
3594 if self.preset.overrides_settings() {
3595 self.preset.missing_rate()
3596 } else {
3597 self.missing_values.rate
3598 }
3599 }
3600
3601 pub fn effective_typo_rate(&self) -> f64 {
3603 if self.preset.overrides_settings() {
3604 self.preset.typo_rate()
3605 } else {
3606 self.typos.char_error_rate
3607 }
3608 }
3609
3610 pub fn effective_duplicate_rate(&self) -> f64 {
3612 if self.preset.overrides_settings() {
3613 self.preset.duplicate_rate()
3614 } else {
3615 self.duplicates.exact_duplicate_ratio
3616 + self.duplicates.near_duplicate_ratio
3617 + self.duplicates.fuzzy_duplicate_ratio
3618 }
3619 }
3620
3621 pub fn clean() -> Self {
3623 Self::with_preset(DataQualityPreset::Clean)
3624 }
3625
3626 pub fn noisy() -> Self {
3628 Self::with_preset(DataQualityPreset::Noisy)
3629 }
3630
3631 pub fn legacy() -> Self {
3633 Self::with_preset(DataQualityPreset::Legacy)
3634 }
3635}
3636
3637#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3639#[serde(rename_all = "snake_case")]
3640pub enum DataQualityPreset {
3641 #[default]
3643 None,
3644 Minimal,
3646 Normal,
3648 High,
3650 Custom,
3652
3653 Clean,
3659 Noisy,
3662 Legacy,
3665}
3666
3667impl DataQualityPreset {
3668 pub fn missing_rate(&self) -> f64 {
3670 match self {
3671 DataQualityPreset::None => 0.0,
3672 DataQualityPreset::Minimal => 0.005,
3673 DataQualityPreset::Normal => 0.02,
3674 DataQualityPreset::High => 0.08,
3675 DataQualityPreset::Custom => 0.01, DataQualityPreset::Clean => 0.001,
3677 DataQualityPreset::Noisy => 0.05,
3678 DataQualityPreset::Legacy => 0.10,
3679 }
3680 }
3681
3682 pub fn typo_rate(&self) -> f64 {
3684 match self {
3685 DataQualityPreset::None => 0.0,
3686 DataQualityPreset::Minimal => 0.0005,
3687 DataQualityPreset::Normal => 0.002,
3688 DataQualityPreset::High => 0.01,
3689 DataQualityPreset::Custom => 0.001, DataQualityPreset::Clean => 0.0005,
3691 DataQualityPreset::Noisy => 0.02,
3692 DataQualityPreset::Legacy => 0.05,
3693 }
3694 }
3695
3696 pub fn duplicate_rate(&self) -> f64 {
3698 match self {
3699 DataQualityPreset::None => 0.0,
3700 DataQualityPreset::Minimal => 0.001,
3701 DataQualityPreset::Normal => 0.005,
3702 DataQualityPreset::High => 0.02,
3703 DataQualityPreset::Custom => 0.0, DataQualityPreset::Clean => 0.0,
3705 DataQualityPreset::Noisy => 0.01,
3706 DataQualityPreset::Legacy => 0.03,
3707 }
3708 }
3709
3710 pub fn format_variations_enabled(&self) -> bool {
3712 match self {
3713 DataQualityPreset::None | DataQualityPreset::Clean => false,
3714 DataQualityPreset::Minimal => true,
3715 DataQualityPreset::Normal => true,
3716 DataQualityPreset::High => true,
3717 DataQualityPreset::Custom => true,
3718 DataQualityPreset::Noisy => true,
3719 DataQualityPreset::Legacy => true,
3720 }
3721 }
3722
3723 pub fn ocr_errors_enabled(&self) -> bool {
3725 matches!(self, DataQualityPreset::Legacy | DataQualityPreset::High)
3726 }
3727
3728 pub fn encoding_issues_enabled(&self) -> bool {
3730 matches!(
3731 self,
3732 DataQualityPreset::Legacy | DataQualityPreset::High | DataQualityPreset::Noisy
3733 )
3734 }
3735
3736 pub fn encoding_issue_rate(&self) -> f64 {
3738 match self {
3739 DataQualityPreset::None | DataQualityPreset::Clean | DataQualityPreset::Minimal => 0.0,
3740 DataQualityPreset::Normal => 0.002,
3741 DataQualityPreset::High => 0.01,
3742 DataQualityPreset::Custom => 0.0,
3743 DataQualityPreset::Noisy => 0.005,
3744 DataQualityPreset::Legacy => 0.02,
3745 }
3746 }
3747
3748 pub fn overrides_settings(&self) -> bool {
3750 !matches!(self, DataQualityPreset::Custom | DataQualityPreset::None)
3751 }
3752
3753 pub fn description(&self) -> &'static str {
3755 match self {
3756 DataQualityPreset::None => "No data quality issues (pristine data)",
3757 DataQualityPreset::Minimal => "Very rare data quality issues",
3758 DataQualityPreset::Normal => "Realistic enterprise data quality",
3759 DataQualityPreset::High => "Messy data for stress testing",
3760 DataQualityPreset::Custom => "Custom settings from configuration",
3761 DataQualityPreset::Clean => "ML-ready clean data with minimal issues",
3762 DataQualityPreset::Noisy => "Typical production data with moderate issues",
3763 DataQualityPreset::Legacy => "Legacy/migrated data with heavy issues and OCR errors",
3764 }
3765 }
3766}
3767
3768#[derive(Debug, Clone, Serialize, Deserialize)]
3770pub struct MissingValuesSchemaConfig {
3771 #[serde(default)]
3773 pub enabled: bool,
3774 #[serde(default = "default_missing_rate")]
3776 pub rate: f64,
3777 #[serde(default)]
3779 pub strategy: MissingValueStrategy,
3780 #[serde(default)]
3782 pub field_rates: std::collections::HashMap<String, f64>,
3783 #[serde(default)]
3785 pub protected_fields: Vec<String>,
3786}
3787
3788fn default_missing_rate() -> f64 {
3789 0.01
3790}
3791
3792impl Default for MissingValuesSchemaConfig {
3793 fn default() -> Self {
3794 Self {
3795 enabled: false,
3796 rate: default_missing_rate(),
3797 strategy: MissingValueStrategy::Mcar,
3798 field_rates: std::collections::HashMap::new(),
3799 protected_fields: vec![
3800 "document_id".to_string(),
3801 "company_code".to_string(),
3802 "posting_date".to_string(),
3803 ],
3804 }
3805 }
3806}
3807
3808#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
3810#[serde(rename_all = "snake_case")]
3811pub enum MissingValueStrategy {
3812 #[default]
3814 Mcar,
3815 Mar,
3817 Mnar,
3819 Systematic,
3821}
3822
3823#[derive(Debug, Clone, Serialize, Deserialize)]
3825pub struct TypoSchemaConfig {
3826 #[serde(default)]
3828 pub enabled: bool,
3829 #[serde(default = "default_typo_rate")]
3831 pub char_error_rate: f64,
3832 #[serde(default)]
3834 pub type_weights: TypoTypeWeights,
3835 #[serde(default)]
3837 pub protected_fields: Vec<String>,
3838}
3839
3840fn default_typo_rate() -> f64 {
3841 0.001
3842}
3843
3844impl Default for TypoSchemaConfig {
3845 fn default() -> Self {
3846 Self {
3847 enabled: false,
3848 char_error_rate: default_typo_rate(),
3849 type_weights: TypoTypeWeights::default(),
3850 protected_fields: vec![
3851 "document_id".to_string(),
3852 "gl_account".to_string(),
3853 "company_code".to_string(),
3854 ],
3855 }
3856 }
3857}
3858
3859#[derive(Debug, Clone, Serialize, Deserialize)]
3861pub struct TypoTypeWeights {
3862 #[serde(default = "default_substitution_weight")]
3864 pub substitution: f64,
3865 #[serde(default = "default_transposition_weight")]
3867 pub transposition: f64,
3868 #[serde(default = "default_insertion_weight")]
3870 pub insertion: f64,
3871 #[serde(default = "default_deletion_weight")]
3873 pub deletion: f64,
3874 #[serde(default = "default_ocr_weight")]
3876 pub ocr_errors: f64,
3877 #[serde(default = "default_homophone_weight")]
3879 pub homophones: f64,
3880}
3881
3882fn default_substitution_weight() -> f64 {
3883 0.35
3884}
3885fn default_transposition_weight() -> f64 {
3886 0.25
3887}
3888fn default_insertion_weight() -> f64 {
3889 0.10
3890}
3891fn default_deletion_weight() -> f64 {
3892 0.15
3893}
3894fn default_ocr_weight() -> f64 {
3895 0.10
3896}
3897fn default_homophone_weight() -> f64 {
3898 0.05
3899}
3900
3901impl Default for TypoTypeWeights {
3902 fn default() -> Self {
3903 Self {
3904 substitution: default_substitution_weight(),
3905 transposition: default_transposition_weight(),
3906 insertion: default_insertion_weight(),
3907 deletion: default_deletion_weight(),
3908 ocr_errors: default_ocr_weight(),
3909 homophones: default_homophone_weight(),
3910 }
3911 }
3912}
3913
3914#[derive(Debug, Clone, Serialize, Deserialize, Default)]
3916pub struct FormatVariationSchemaConfig {
3917 #[serde(default)]
3919 pub enabled: bool,
3920 #[serde(default)]
3922 pub dates: DateFormatVariationConfig,
3923 #[serde(default)]
3925 pub amounts: AmountFormatVariationConfig,
3926 #[serde(default)]
3928 pub identifiers: IdentifierFormatVariationConfig,
3929}
3930
3931#[derive(Debug, Clone, Serialize, Deserialize)]
3933pub struct DateFormatVariationConfig {
3934 #[serde(default)]
3936 pub enabled: bool,
3937 #[serde(default = "default_date_variation_rate")]
3939 pub rate: f64,
3940 #[serde(default = "default_true")]
3942 pub iso_format: bool,
3943 #[serde(default)]
3945 pub us_format: bool,
3946 #[serde(default)]
3948 pub eu_format: bool,
3949 #[serde(default)]
3951 pub long_format: bool,
3952}
3953
3954fn default_date_variation_rate() -> f64 {
3955 0.05
3956}
3957
3958impl Default for DateFormatVariationConfig {
3959 fn default() -> Self {
3960 Self {
3961 enabled: false,
3962 rate: default_date_variation_rate(),
3963 iso_format: true,
3964 us_format: false,
3965 eu_format: false,
3966 long_format: false,
3967 }
3968 }
3969}
3970
3971#[derive(Debug, Clone, Serialize, Deserialize)]
3973pub struct AmountFormatVariationConfig {
3974 #[serde(default)]
3976 pub enabled: bool,
3977 #[serde(default = "default_amount_variation_rate")]
3979 pub rate: f64,
3980 #[serde(default)]
3982 pub us_comma_format: bool,
3983 #[serde(default)]
3985 pub eu_format: bool,
3986 #[serde(default)]
3988 pub currency_prefix: bool,
3989 #[serde(default)]
3991 pub accounting_format: bool,
3992}
3993
3994fn default_amount_variation_rate() -> f64 {
3995 0.02
3996}
3997
3998impl Default for AmountFormatVariationConfig {
3999 fn default() -> Self {
4000 Self {
4001 enabled: false,
4002 rate: default_amount_variation_rate(),
4003 us_comma_format: false,
4004 eu_format: false,
4005 currency_prefix: false,
4006 accounting_format: false,
4007 }
4008 }
4009}
4010
4011#[derive(Debug, Clone, Serialize, Deserialize)]
4013pub struct IdentifierFormatVariationConfig {
4014 #[serde(default)]
4016 pub enabled: bool,
4017 #[serde(default = "default_identifier_variation_rate")]
4019 pub rate: f64,
4020 #[serde(default)]
4022 pub case_variations: bool,
4023 #[serde(default)]
4025 pub padding_variations: bool,
4026 #[serde(default)]
4028 pub separator_variations: bool,
4029}
4030
4031fn default_identifier_variation_rate() -> f64 {
4032 0.02
4033}
4034
4035impl Default for IdentifierFormatVariationConfig {
4036 fn default() -> Self {
4037 Self {
4038 enabled: false,
4039 rate: default_identifier_variation_rate(),
4040 case_variations: false,
4041 padding_variations: false,
4042 separator_variations: false,
4043 }
4044 }
4045}
4046
4047#[derive(Debug, Clone, Serialize, Deserialize)]
4049pub struct DuplicateSchemaConfig {
4050 #[serde(default)]
4052 pub enabled: bool,
4053 #[serde(default = "default_duplicate_rate")]
4055 pub rate: f64,
4056 #[serde(default = "default_exact_duplicate_ratio")]
4058 pub exact_duplicate_ratio: f64,
4059 #[serde(default = "default_near_duplicate_ratio")]
4061 pub near_duplicate_ratio: f64,
4062 #[serde(default = "default_fuzzy_duplicate_ratio")]
4064 pub fuzzy_duplicate_ratio: f64,
4065 #[serde(default = "default_max_date_offset")]
4067 pub max_date_offset_days: u32,
4068 #[serde(default = "default_max_amount_variance")]
4070 pub max_amount_variance: f64,
4071}
4072
4073fn default_duplicate_rate() -> f64 {
4074 0.005
4075}
4076fn default_exact_duplicate_ratio() -> f64 {
4077 0.4
4078}
4079fn default_near_duplicate_ratio() -> f64 {
4080 0.35
4081}
4082fn default_fuzzy_duplicate_ratio() -> f64 {
4083 0.25
4084}
4085fn default_max_date_offset() -> u32 {
4086 3
4087}
4088fn default_max_amount_variance() -> f64 {
4089 0.01
4090}
4091
4092impl Default for DuplicateSchemaConfig {
4093 fn default() -> Self {
4094 Self {
4095 enabled: false,
4096 rate: default_duplicate_rate(),
4097 exact_duplicate_ratio: default_exact_duplicate_ratio(),
4098 near_duplicate_ratio: default_near_duplicate_ratio(),
4099 fuzzy_duplicate_ratio: default_fuzzy_duplicate_ratio(),
4100 max_date_offset_days: default_max_date_offset(),
4101 max_amount_variance: default_max_amount_variance(),
4102 }
4103 }
4104}
4105
4106#[derive(Debug, Clone, Serialize, Deserialize)]
4108pub struct EncodingIssueSchemaConfig {
4109 #[serde(default)]
4111 pub enabled: bool,
4112 #[serde(default = "default_encoding_rate")]
4114 pub rate: f64,
4115 #[serde(default)]
4117 pub mojibake: bool,
4118 #[serde(default)]
4120 pub html_entities: bool,
4121 #[serde(default)]
4123 pub bom_issues: bool,
4124}
4125
4126fn default_encoding_rate() -> f64 {
4127 0.001
4128}
4129
4130impl Default for EncodingIssueSchemaConfig {
4131 fn default() -> Self {
4132 Self {
4133 enabled: false,
4134 rate: default_encoding_rate(),
4135 mojibake: false,
4136 html_entities: false,
4137 bom_issues: false,
4138 }
4139 }
4140}
4141
4142#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4144pub struct SinkQualityProfiles {
4145 #[serde(default)]
4147 pub csv: Option<SinkQualityOverride>,
4148 #[serde(default)]
4150 pub json: Option<SinkQualityOverride>,
4151 #[serde(default)]
4153 pub parquet: Option<SinkQualityOverride>,
4154}
4155
4156#[derive(Debug, Clone, Serialize, Deserialize)]
4158pub struct SinkQualityOverride {
4159 pub enabled: Option<bool>,
4161 pub missing_rate: Option<f64>,
4163 pub typo_rate: Option<f64>,
4165 pub format_variation_rate: Option<f64>,
4167 pub duplicate_rate: Option<f64>,
4169}
4170
4171#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4183pub struct AccountingStandardsConfig {
4184 #[serde(default)]
4186 pub enabled: bool,
4187
4188 #[serde(default)]
4190 pub framework: AccountingFrameworkConfig,
4191
4192 #[serde(default)]
4194 pub revenue_recognition: RevenueRecognitionConfig,
4195
4196 #[serde(default)]
4198 pub leases: LeaseAccountingConfig,
4199
4200 #[serde(default)]
4202 pub fair_value: FairValueConfig,
4203
4204 #[serde(default)]
4206 pub impairment: ImpairmentConfig,
4207
4208 #[serde(default)]
4210 pub generate_differences: bool,
4211}
4212
4213#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
4215#[serde(rename_all = "snake_case")]
4216pub enum AccountingFrameworkConfig {
4217 #[default]
4219 UsGaap,
4220 Ifrs,
4222 DualReporting,
4224}
4225
4226#[derive(Debug, Clone, Serialize, Deserialize)]
4228pub struct RevenueRecognitionConfig {
4229 #[serde(default)]
4231 pub enabled: bool,
4232
4233 #[serde(default = "default_true")]
4235 pub generate_contracts: bool,
4236
4237 #[serde(default = "default_avg_obligations")]
4239 pub avg_obligations_per_contract: f64,
4240
4241 #[serde(default = "default_variable_consideration_rate")]
4243 pub variable_consideration_rate: f64,
4244
4245 #[serde(default = "default_over_time_rate")]
4247 pub over_time_recognition_rate: f64,
4248
4249 #[serde(default = "default_contract_count")]
4251 pub contract_count: usize,
4252}
4253
4254fn default_avg_obligations() -> f64 {
4255 2.0
4256}
4257
4258fn default_variable_consideration_rate() -> f64 {
4259 0.15
4260}
4261
4262fn default_over_time_rate() -> f64 {
4263 0.30
4264}
4265
4266fn default_contract_count() -> usize {
4267 100
4268}
4269
4270impl Default for RevenueRecognitionConfig {
4271 fn default() -> Self {
4272 Self {
4273 enabled: false,
4274 generate_contracts: true,
4275 avg_obligations_per_contract: default_avg_obligations(),
4276 variable_consideration_rate: default_variable_consideration_rate(),
4277 over_time_recognition_rate: default_over_time_rate(),
4278 contract_count: default_contract_count(),
4279 }
4280 }
4281}
4282
4283#[derive(Debug, Clone, Serialize, Deserialize)]
4285pub struct LeaseAccountingConfig {
4286 #[serde(default)]
4288 pub enabled: bool,
4289
4290 #[serde(default = "default_lease_count")]
4292 pub lease_count: usize,
4293
4294 #[serde(default = "default_finance_lease_pct")]
4296 pub finance_lease_percent: f64,
4297
4298 #[serde(default = "default_avg_lease_term")]
4300 pub avg_lease_term_months: u32,
4301
4302 #[serde(default = "default_true")]
4304 pub generate_amortization: bool,
4305
4306 #[serde(default = "default_real_estate_pct")]
4308 pub real_estate_percent: f64,
4309}
4310
4311fn default_lease_count() -> usize {
4312 50
4313}
4314
4315fn default_finance_lease_pct() -> f64 {
4316 0.30
4317}
4318
4319fn default_avg_lease_term() -> u32 {
4320 60
4321}
4322
4323fn default_real_estate_pct() -> f64 {
4324 0.40
4325}
4326
4327impl Default for LeaseAccountingConfig {
4328 fn default() -> Self {
4329 Self {
4330 enabled: false,
4331 lease_count: default_lease_count(),
4332 finance_lease_percent: default_finance_lease_pct(),
4333 avg_lease_term_months: default_avg_lease_term(),
4334 generate_amortization: true,
4335 real_estate_percent: default_real_estate_pct(),
4336 }
4337 }
4338}
4339
4340#[derive(Debug, Clone, Serialize, Deserialize)]
4342pub struct FairValueConfig {
4343 #[serde(default)]
4345 pub enabled: bool,
4346
4347 #[serde(default = "default_fv_count")]
4349 pub measurement_count: usize,
4350
4351 #[serde(default = "default_level1_pct")]
4353 pub level1_percent: f64,
4354
4355 #[serde(default = "default_level2_pct")]
4357 pub level2_percent: f64,
4358
4359 #[serde(default = "default_level3_pct")]
4361 pub level3_percent: f64,
4362
4363 #[serde(default)]
4365 pub include_sensitivity_analysis: bool,
4366}
4367
4368fn default_fv_count() -> usize {
4369 25
4370}
4371
4372fn default_level1_pct() -> f64 {
4373 0.40
4374}
4375
4376fn default_level2_pct() -> f64 {
4377 0.35
4378}
4379
4380fn default_level3_pct() -> f64 {
4381 0.25
4382}
4383
4384impl Default for FairValueConfig {
4385 fn default() -> Self {
4386 Self {
4387 enabled: false,
4388 measurement_count: default_fv_count(),
4389 level1_percent: default_level1_pct(),
4390 level2_percent: default_level2_pct(),
4391 level3_percent: default_level3_pct(),
4392 include_sensitivity_analysis: false,
4393 }
4394 }
4395}
4396
4397#[derive(Debug, Clone, Serialize, Deserialize)]
4399pub struct ImpairmentConfig {
4400 #[serde(default)]
4402 pub enabled: bool,
4403
4404 #[serde(default = "default_impairment_count")]
4406 pub test_count: usize,
4407
4408 #[serde(default = "default_impairment_rate")]
4410 pub impairment_rate: f64,
4411
4412 #[serde(default = "default_true")]
4414 pub generate_projections: bool,
4415
4416 #[serde(default)]
4418 pub include_goodwill: bool,
4419}
4420
4421fn default_impairment_count() -> usize {
4422 15
4423}
4424
4425fn default_impairment_rate() -> f64 {
4426 0.10
4427}
4428
4429impl Default for ImpairmentConfig {
4430 fn default() -> Self {
4431 Self {
4432 enabled: false,
4433 test_count: default_impairment_count(),
4434 impairment_rate: default_impairment_rate(),
4435 generate_projections: true,
4436 include_goodwill: false,
4437 }
4438 }
4439}
4440
4441#[derive(Debug, Clone, Serialize, Deserialize, Default)]
4454pub struct AuditStandardsConfig {
4455 #[serde(default)]
4457 pub enabled: bool,
4458
4459 #[serde(default)]
4461 pub isa_compliance: IsaComplianceConfig,
4462
4463 #[serde(default)]
4465 pub analytical_procedures: AnalyticalProceduresConfig,
4466
4467 #[serde(default)]
4469 pub confirmations: ConfirmationsConfig,
4470
4471 #[serde(default)]
4473 pub opinion: AuditOpinionConfig,
4474
4475 #[serde(default)]
4477 pub generate_audit_trail: bool,
4478
4479 #[serde(default)]
4481 pub sox: SoxComplianceConfig,
4482
4483 #[serde(default)]
4485 pub pcaob: PcaobConfig,
4486}
4487
4488#[derive(Debug, Clone, Serialize, Deserialize)]
4490pub struct IsaComplianceConfig {
4491 #[serde(default)]
4493 pub enabled: bool,
4494
4495 #[serde(default = "default_compliance_level")]
4497 pub compliance_level: String,
4498
4499 #[serde(default = "default_true")]
4501 pub generate_isa_mappings: bool,
4502
4503 #[serde(default = "default_true")]
4505 pub generate_coverage_summary: bool,
4506
4507 #[serde(default)]
4509 pub include_pcaob: bool,
4510
4511 #[serde(default = "default_audit_framework")]
4513 pub framework: String,
4514}
4515
4516fn default_compliance_level() -> String {
4517 "standard".to_string()
4518}
4519
4520fn default_audit_framework() -> String {
4521 "isa".to_string()
4522}
4523
4524impl Default for IsaComplianceConfig {
4525 fn default() -> Self {
4526 Self {
4527 enabled: false,
4528 compliance_level: default_compliance_level(),
4529 generate_isa_mappings: true,
4530 generate_coverage_summary: true,
4531 include_pcaob: false,
4532 framework: default_audit_framework(),
4533 }
4534 }
4535}
4536
4537#[derive(Debug, Clone, Serialize, Deserialize)]
4539pub struct AnalyticalProceduresConfig {
4540 #[serde(default)]
4542 pub enabled: bool,
4543
4544 #[serde(default = "default_procedures_per_account")]
4546 pub procedures_per_account: usize,
4547
4548 #[serde(default = "default_variance_probability")]
4550 pub variance_probability: f64,
4551
4552 #[serde(default = "default_true")]
4554 pub generate_investigations: bool,
4555
4556 #[serde(default = "default_true")]
4558 pub include_ratio_analysis: bool,
4559}
4560
4561fn default_procedures_per_account() -> usize {
4562 3
4563}
4564
4565fn default_variance_probability() -> f64 {
4566 0.20
4567}
4568
4569impl Default for AnalyticalProceduresConfig {
4570 fn default() -> Self {
4571 Self {
4572 enabled: false,
4573 procedures_per_account: default_procedures_per_account(),
4574 variance_probability: default_variance_probability(),
4575 generate_investigations: true,
4576 include_ratio_analysis: true,
4577 }
4578 }
4579}
4580
4581#[derive(Debug, Clone, Serialize, Deserialize)]
4583pub struct ConfirmationsConfig {
4584 #[serde(default)]
4586 pub enabled: bool,
4587
4588 #[serde(default = "default_confirmation_count")]
4590 pub confirmation_count: usize,
4591
4592 #[serde(default = "default_positive_response_rate")]
4594 pub positive_response_rate: f64,
4595
4596 #[serde(default = "default_exception_rate_confirm")]
4598 pub exception_rate: f64,
4599
4600 #[serde(default = "default_non_response_rate")]
4602 pub non_response_rate: f64,
4603
4604 #[serde(default = "default_true")]
4606 pub generate_alternative_procedures: bool,
4607}
4608
4609fn default_confirmation_count() -> usize {
4610 50
4611}
4612
4613fn default_positive_response_rate() -> f64 {
4614 0.85
4615}
4616
4617fn default_exception_rate_confirm() -> f64 {
4618 0.10
4619}
4620
4621fn default_non_response_rate() -> f64 {
4622 0.05
4623}
4624
4625impl Default for ConfirmationsConfig {
4626 fn default() -> Self {
4627 Self {
4628 enabled: false,
4629 confirmation_count: default_confirmation_count(),
4630 positive_response_rate: default_positive_response_rate(),
4631 exception_rate: default_exception_rate_confirm(),
4632 non_response_rate: default_non_response_rate(),
4633 generate_alternative_procedures: true,
4634 }
4635 }
4636}
4637
4638#[derive(Debug, Clone, Serialize, Deserialize)]
4640pub struct AuditOpinionConfig {
4641 #[serde(default)]
4643 pub enabled: bool,
4644
4645 #[serde(default = "default_true")]
4647 pub generate_kam: bool,
4648
4649 #[serde(default = "default_kam_count")]
4651 pub average_kam_count: usize,
4652
4653 #[serde(default = "default_modified_opinion_rate")]
4655 pub modified_opinion_rate: f64,
4656
4657 #[serde(default)]
4659 pub include_emphasis_of_matter: bool,
4660
4661 #[serde(default = "default_true")]
4663 pub include_going_concern: bool,
4664}
4665
4666fn default_kam_count() -> usize {
4667 3
4668}
4669
4670fn default_modified_opinion_rate() -> f64 {
4671 0.05
4672}
4673
4674impl Default for AuditOpinionConfig {
4675 fn default() -> Self {
4676 Self {
4677 enabled: false,
4678 generate_kam: true,
4679 average_kam_count: default_kam_count(),
4680 modified_opinion_rate: default_modified_opinion_rate(),
4681 include_emphasis_of_matter: false,
4682 include_going_concern: true,
4683 }
4684 }
4685}
4686
4687#[derive(Debug, Clone, Serialize, Deserialize)]
4689pub struct SoxComplianceConfig {
4690 #[serde(default)]
4692 pub enabled: bool,
4693
4694 #[serde(default = "default_true")]
4696 pub generate_302_certifications: bool,
4697
4698 #[serde(default = "default_true")]
4700 pub generate_404_assessments: bool,
4701
4702 #[serde(default = "default_sox_materiality_threshold")]
4704 pub materiality_threshold: f64,
4705
4706 #[serde(default = "default_material_weakness_rate")]
4708 pub material_weakness_rate: f64,
4709
4710 #[serde(default = "default_significant_deficiency_rate")]
4712 pub significant_deficiency_rate: f64,
4713}
4714
4715fn default_material_weakness_rate() -> f64 {
4716 0.02
4717}
4718
4719fn default_significant_deficiency_rate() -> f64 {
4720 0.08
4721}
4722
4723impl Default for SoxComplianceConfig {
4724 fn default() -> Self {
4725 Self {
4726 enabled: false,
4727 generate_302_certifications: true,
4728 generate_404_assessments: true,
4729 materiality_threshold: default_sox_materiality_threshold(),
4730 material_weakness_rate: default_material_weakness_rate(),
4731 significant_deficiency_rate: default_significant_deficiency_rate(),
4732 }
4733 }
4734}
4735
4736#[derive(Debug, Clone, Serialize, Deserialize)]
4738pub struct PcaobConfig {
4739 #[serde(default)]
4741 pub enabled: bool,
4742
4743 #[serde(default)]
4745 pub is_pcaob_audit: bool,
4746
4747 #[serde(default = "default_true")]
4749 pub generate_cam: bool,
4750
4751 #[serde(default)]
4753 pub include_icfr_opinion: bool,
4754
4755 #[serde(default)]
4757 pub generate_standard_mappings: bool,
4758}
4759
4760impl Default for PcaobConfig {
4761 fn default() -> Self {
4762 Self {
4763 enabled: false,
4764 is_pcaob_audit: false,
4765 generate_cam: true,
4766 include_icfr_opinion: false,
4767 generate_standard_mappings: false,
4768 }
4769 }
4770}
4771
4772#[cfg(test)]
4773mod tests {
4774 use super::*;
4775 use crate::presets::demo_preset;
4776
4777 #[test]
4782 fn test_config_yaml_roundtrip() {
4783 let config = demo_preset();
4784 let yaml = serde_yaml::to_string(&config).expect("Failed to serialize to YAML");
4785 let deserialized: GeneratorConfig =
4786 serde_yaml::from_str(&yaml).expect("Failed to deserialize from YAML");
4787
4788 assert_eq!(
4789 config.global.period_months,
4790 deserialized.global.period_months
4791 );
4792 assert_eq!(config.global.industry, deserialized.global.industry);
4793 assert_eq!(config.companies.len(), deserialized.companies.len());
4794 assert_eq!(config.companies[0].code, deserialized.companies[0].code);
4795 }
4796
4797 #[test]
4798 fn test_config_json_roundtrip() {
4799 let mut config = demo_preset();
4801 config.master_data.employees.approval_limits.executive = 1e12;
4803
4804 let json = serde_json::to_string(&config).expect("Failed to serialize to JSON");
4805 let deserialized: GeneratorConfig =
4806 serde_json::from_str(&json).expect("Failed to deserialize from JSON");
4807
4808 assert_eq!(
4809 config.global.period_months,
4810 deserialized.global.period_months
4811 );
4812 assert_eq!(config.global.industry, deserialized.global.industry);
4813 assert_eq!(config.companies.len(), deserialized.companies.len());
4814 }
4815
4816 #[test]
4817 fn test_transaction_volume_serialization() {
4818 let volumes = vec![
4820 (TransactionVolume::TenK, "ten_k"),
4821 (TransactionVolume::HundredK, "hundred_k"),
4822 (TransactionVolume::OneM, "one_m"),
4823 (TransactionVolume::TenM, "ten_m"),
4824 (TransactionVolume::HundredM, "hundred_m"),
4825 ];
4826
4827 for (volume, expected_key) in volumes {
4828 let json = serde_json::to_string(&volume).expect("Failed to serialize");
4829 assert!(
4830 json.contains(expected_key),
4831 "Expected {} in JSON: {}",
4832 expected_key,
4833 json
4834 );
4835 }
4836 }
4837
4838 #[test]
4839 fn test_transaction_volume_custom_serialization() {
4840 let volume = TransactionVolume::Custom(12345);
4841 let json = serde_json::to_string(&volume).expect("Failed to serialize");
4842 let deserialized: TransactionVolume =
4843 serde_json::from_str(&json).expect("Failed to deserialize");
4844 assert_eq!(deserialized.count(), 12345);
4845 }
4846
4847 #[test]
4848 fn test_output_mode_serialization() {
4849 let modes = vec![
4850 OutputMode::Streaming,
4851 OutputMode::FlatFile,
4852 OutputMode::Both,
4853 ];
4854
4855 for mode in modes {
4856 let json = serde_json::to_string(&mode).expect("Failed to serialize");
4857 let deserialized: OutputMode =
4858 serde_json::from_str(&json).expect("Failed to deserialize");
4859 assert!(format!("{:?}", mode) == format!("{:?}", deserialized));
4860 }
4861 }
4862
4863 #[test]
4864 fn test_file_format_serialization() {
4865 let formats = vec![
4866 FileFormat::Csv,
4867 FileFormat::Parquet,
4868 FileFormat::Json,
4869 FileFormat::JsonLines,
4870 ];
4871
4872 for format in formats {
4873 let json = serde_json::to_string(&format).expect("Failed to serialize");
4874 let deserialized: FileFormat =
4875 serde_json::from_str(&json).expect("Failed to deserialize");
4876 assert!(format!("{:?}", format) == format!("{:?}", deserialized));
4877 }
4878 }
4879
4880 #[test]
4881 fn test_compression_algorithm_serialization() {
4882 let algos = vec![
4883 CompressionAlgorithm::Gzip,
4884 CompressionAlgorithm::Zstd,
4885 CompressionAlgorithm::Lz4,
4886 CompressionAlgorithm::Snappy,
4887 ];
4888
4889 for algo in algos {
4890 let json = serde_json::to_string(&algo).expect("Failed to serialize");
4891 let deserialized: CompressionAlgorithm =
4892 serde_json::from_str(&json).expect("Failed to deserialize");
4893 assert!(format!("{:?}", algo) == format!("{:?}", deserialized));
4894 }
4895 }
4896
4897 #[test]
4898 fn test_transfer_pricing_method_serialization() {
4899 let methods = vec![
4900 TransferPricingMethod::CostPlus,
4901 TransferPricingMethod::ComparableUncontrolled,
4902 TransferPricingMethod::ResalePrice,
4903 TransferPricingMethod::TransactionalNetMargin,
4904 TransferPricingMethod::ProfitSplit,
4905 ];
4906
4907 for method in methods {
4908 let json = serde_json::to_string(&method).expect("Failed to serialize");
4909 let deserialized: TransferPricingMethod =
4910 serde_json::from_str(&json).expect("Failed to deserialize");
4911 assert!(format!("{:?}", method) == format!("{:?}", deserialized));
4912 }
4913 }
4914
4915 #[test]
4916 fn test_benford_exemption_serialization() {
4917 let exemptions = vec![
4918 BenfordExemption::Recurring,
4919 BenfordExemption::Payroll,
4920 BenfordExemption::FixedFees,
4921 BenfordExemption::RoundAmounts,
4922 ];
4923
4924 for exemption in exemptions {
4925 let json = serde_json::to_string(&exemption).expect("Failed to serialize");
4926 let deserialized: BenfordExemption =
4927 serde_json::from_str(&json).expect("Failed to deserialize");
4928 assert!(format!("{:?}", exemption) == format!("{:?}", deserialized));
4929 }
4930 }
4931
4932 #[test]
4937 fn test_global_config_defaults() {
4938 let yaml = r#"
4939 industry: manufacturing
4940 start_date: "2024-01-01"
4941 period_months: 6
4942 "#;
4943 let config: GlobalConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
4944 assert_eq!(config.group_currency, "USD");
4945 assert!(config.parallel);
4946 assert_eq!(config.worker_threads, 0);
4947 assert_eq!(config.memory_limit_mb, 0);
4948 }
4949
4950 #[test]
4951 fn test_fraud_config_defaults() {
4952 let config = FraudConfig::default();
4953 assert!(!config.enabled);
4954 assert_eq!(config.fraud_rate, 0.005);
4955 assert!(!config.clustering_enabled);
4956 }
4957
4958 #[test]
4959 fn test_internal_controls_config_defaults() {
4960 let config = InternalControlsConfig::default();
4961 assert!(!config.enabled);
4962 assert_eq!(config.exception_rate, 0.02);
4963 assert_eq!(config.sod_violation_rate, 0.01);
4964 assert!(config.export_control_master_data);
4965 assert_eq!(config.sox_materiality_threshold, 10000.0);
4966 assert!(config.coso_enabled);
4968 assert!(!config.include_entity_level_controls);
4969 assert_eq!(config.target_maturity_level, "mixed");
4970 }
4971
4972 #[test]
4973 fn test_output_config_defaults() {
4974 let config = OutputConfig::default();
4975 assert!(matches!(config.mode, OutputMode::FlatFile));
4976 assert_eq!(config.formats, vec![FileFormat::Parquet]);
4977 assert!(config.compression.enabled);
4978 assert!(matches!(
4979 config.compression.algorithm,
4980 CompressionAlgorithm::Zstd
4981 ));
4982 assert!(config.include_acdoca);
4983 assert!(!config.include_bseg);
4984 assert!(config.partition_by_period);
4985 assert!(!config.partition_by_company);
4986 }
4987
4988 #[test]
4989 fn test_approval_config_defaults() {
4990 let config = ApprovalConfig::default();
4991 assert!(!config.enabled);
4992 assert_eq!(config.auto_approve_threshold, 1000.0);
4993 assert_eq!(config.rejection_rate, 0.02);
4994 assert_eq!(config.revision_rate, 0.05);
4995 assert_eq!(config.average_approval_delay_hours, 4.0);
4996 assert_eq!(config.thresholds.len(), 4);
4997 }
4998
4999 #[test]
5000 fn test_p2p_flow_config_defaults() {
5001 let config = P2PFlowConfig::default();
5002 assert!(config.enabled);
5003 assert_eq!(config.three_way_match_rate, 0.95);
5004 assert_eq!(config.partial_delivery_rate, 0.15);
5005 assert_eq!(config.average_po_to_gr_days, 14);
5006 }
5007
5008 #[test]
5009 fn test_o2c_flow_config_defaults() {
5010 let config = O2CFlowConfig::default();
5011 assert!(config.enabled);
5012 assert_eq!(config.credit_check_failure_rate, 0.02);
5013 assert_eq!(config.return_rate, 0.03);
5014 assert_eq!(config.bad_debt_rate, 0.01);
5015 }
5016
5017 #[test]
5018 fn test_balance_config_defaults() {
5019 let config = BalanceConfig::default();
5020 assert!(!config.generate_opening_balances);
5021 assert!(config.generate_trial_balances);
5022 assert_eq!(config.target_gross_margin, 0.35);
5023 assert!(config.validate_balance_equation);
5024 assert!(config.reconcile_subledgers);
5025 }
5026
5027 #[test]
5032 fn test_partial_config_with_defaults() {
5033 let yaml = r#"
5035 global:
5036 industry: manufacturing
5037 start_date: "2024-01-01"
5038 period_months: 3
5039 companies:
5040 - code: "TEST"
5041 name: "Test Company"
5042 currency: "USD"
5043 country: "US"
5044 annual_transaction_volume: ten_k
5045 chart_of_accounts:
5046 complexity: small
5047 output:
5048 output_directory: "./output"
5049 "#;
5050
5051 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5052 assert_eq!(config.global.period_months, 3);
5053 assert_eq!(config.companies.len(), 1);
5054 assert!(!config.fraud.enabled); assert!(!config.internal_controls.enabled); }
5057
5058 #[test]
5059 fn test_config_with_fraud_enabled() {
5060 let yaml = r#"
5061 global:
5062 industry: retail
5063 start_date: "2024-01-01"
5064 period_months: 12
5065 companies:
5066 - code: "RETAIL"
5067 name: "Retail Co"
5068 currency: "USD"
5069 country: "US"
5070 annual_transaction_volume: hundred_k
5071 chart_of_accounts:
5072 complexity: medium
5073 output:
5074 output_directory: "./output"
5075 fraud:
5076 enabled: true
5077 fraud_rate: 0.05
5078 clustering_enabled: true
5079 "#;
5080
5081 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5082 assert!(config.fraud.enabled);
5083 assert_eq!(config.fraud.fraud_rate, 0.05);
5084 assert!(config.fraud.clustering_enabled);
5085 }
5086
5087 #[test]
5088 fn test_config_with_multiple_companies() {
5089 let yaml = r#"
5090 global:
5091 industry: manufacturing
5092 start_date: "2024-01-01"
5093 period_months: 6
5094 companies:
5095 - code: "HQ"
5096 name: "Headquarters"
5097 currency: "USD"
5098 country: "US"
5099 annual_transaction_volume: hundred_k
5100 volume_weight: 1.0
5101 - code: "EU"
5102 name: "European Subsidiary"
5103 currency: "EUR"
5104 country: "DE"
5105 annual_transaction_volume: hundred_k
5106 volume_weight: 0.5
5107 - code: "APAC"
5108 name: "Asia Pacific"
5109 currency: "JPY"
5110 country: "JP"
5111 annual_transaction_volume: ten_k
5112 volume_weight: 0.3
5113 chart_of_accounts:
5114 complexity: large
5115 output:
5116 output_directory: "./output"
5117 "#;
5118
5119 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5120 assert_eq!(config.companies.len(), 3);
5121 assert_eq!(config.companies[0].code, "HQ");
5122 assert_eq!(config.companies[1].currency, "EUR");
5123 assert_eq!(config.companies[2].volume_weight, 0.3);
5124 }
5125
5126 #[test]
5127 fn test_intercompany_config() {
5128 let yaml = r#"
5129 enabled: true
5130 ic_transaction_rate: 0.20
5131 transfer_pricing_method: cost_plus
5132 markup_percent: 0.08
5133 generate_matched_pairs: true
5134 generate_eliminations: true
5135 "#;
5136
5137 let config: IntercompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5138 assert!(config.enabled);
5139 assert_eq!(config.ic_transaction_rate, 0.20);
5140 assert!(matches!(
5141 config.transfer_pricing_method,
5142 TransferPricingMethod::CostPlus
5143 ));
5144 assert_eq!(config.markup_percent, 0.08);
5145 assert!(config.generate_eliminations);
5146 }
5147
5148 #[test]
5153 fn test_company_config_defaults() {
5154 let yaml = r#"
5155 code: "TEST"
5156 name: "Test Company"
5157 currency: "USD"
5158 country: "US"
5159 annual_transaction_volume: ten_k
5160 "#;
5161
5162 let config: CompanyConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5163 assert_eq!(config.fiscal_year_variant, "K4"); assert_eq!(config.volume_weight, 1.0); }
5166
5167 #[test]
5172 fn test_coa_config_defaults() {
5173 let yaml = r#"
5174 complexity: medium
5175 "#;
5176
5177 let config: ChartOfAccountsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5178 assert!(config.industry_specific); assert!(config.custom_accounts.is_none());
5180 assert_eq!(config.min_hierarchy_depth, 2); assert_eq!(config.max_hierarchy_depth, 5); }
5183
5184 #[test]
5189 fn test_accounting_standards_config_defaults() {
5190 let config = AccountingStandardsConfig::default();
5191 assert!(!config.enabled);
5192 assert!(matches!(
5193 config.framework,
5194 AccountingFrameworkConfig::UsGaap
5195 ));
5196 assert!(!config.revenue_recognition.enabled);
5197 assert!(!config.leases.enabled);
5198 assert!(!config.fair_value.enabled);
5199 assert!(!config.impairment.enabled);
5200 assert!(!config.generate_differences);
5201 }
5202
5203 #[test]
5204 fn test_accounting_standards_config_yaml() {
5205 let yaml = r#"
5206 enabled: true
5207 framework: ifrs
5208 revenue_recognition:
5209 enabled: true
5210 generate_contracts: true
5211 avg_obligations_per_contract: 2.5
5212 variable_consideration_rate: 0.20
5213 over_time_recognition_rate: 0.35
5214 contract_count: 150
5215 leases:
5216 enabled: true
5217 lease_count: 75
5218 finance_lease_percent: 0.25
5219 avg_lease_term_months: 48
5220 generate_differences: true
5221 "#;
5222
5223 let config: AccountingStandardsConfig =
5224 serde_yaml::from_str(yaml).expect("Failed to parse");
5225 assert!(config.enabled);
5226 assert!(matches!(config.framework, AccountingFrameworkConfig::Ifrs));
5227 assert!(config.revenue_recognition.enabled);
5228 assert_eq!(config.revenue_recognition.contract_count, 150);
5229 assert_eq!(config.revenue_recognition.avg_obligations_per_contract, 2.5);
5230 assert!(config.leases.enabled);
5231 assert_eq!(config.leases.lease_count, 75);
5232 assert_eq!(config.leases.finance_lease_percent, 0.25);
5233 assert!(config.generate_differences);
5234 }
5235
5236 #[test]
5237 fn test_accounting_framework_serialization() {
5238 let frameworks = [
5239 AccountingFrameworkConfig::UsGaap,
5240 AccountingFrameworkConfig::Ifrs,
5241 AccountingFrameworkConfig::DualReporting,
5242 ];
5243
5244 for framework in frameworks {
5245 let json = serde_json::to_string(&framework).expect("Failed to serialize");
5246 let deserialized: AccountingFrameworkConfig =
5247 serde_json::from_str(&json).expect("Failed to deserialize");
5248 assert!(format!("{:?}", framework) == format!("{:?}", deserialized));
5249 }
5250 }
5251
5252 #[test]
5253 fn test_revenue_recognition_config_defaults() {
5254 let config = RevenueRecognitionConfig::default();
5255 assert!(!config.enabled);
5256 assert!(config.generate_contracts);
5257 assert_eq!(config.avg_obligations_per_contract, 2.0);
5258 assert_eq!(config.variable_consideration_rate, 0.15);
5259 assert_eq!(config.over_time_recognition_rate, 0.30);
5260 assert_eq!(config.contract_count, 100);
5261 }
5262
5263 #[test]
5264 fn test_lease_accounting_config_defaults() {
5265 let config = LeaseAccountingConfig::default();
5266 assert!(!config.enabled);
5267 assert_eq!(config.lease_count, 50);
5268 assert_eq!(config.finance_lease_percent, 0.30);
5269 assert_eq!(config.avg_lease_term_months, 60);
5270 assert!(config.generate_amortization);
5271 assert_eq!(config.real_estate_percent, 0.40);
5272 }
5273
5274 #[test]
5275 fn test_fair_value_config_defaults() {
5276 let config = FairValueConfig::default();
5277 assert!(!config.enabled);
5278 assert_eq!(config.measurement_count, 25);
5279 assert_eq!(config.level1_percent, 0.40);
5280 assert_eq!(config.level2_percent, 0.35);
5281 assert_eq!(config.level3_percent, 0.25);
5282 assert!(!config.include_sensitivity_analysis);
5283 }
5284
5285 #[test]
5286 fn test_impairment_config_defaults() {
5287 let config = ImpairmentConfig::default();
5288 assert!(!config.enabled);
5289 assert_eq!(config.test_count, 15);
5290 assert_eq!(config.impairment_rate, 0.10);
5291 assert!(config.generate_projections);
5292 assert!(!config.include_goodwill);
5293 }
5294
5295 #[test]
5300 fn test_audit_standards_config_defaults() {
5301 let config = AuditStandardsConfig::default();
5302 assert!(!config.enabled);
5303 assert!(!config.isa_compliance.enabled);
5304 assert!(!config.analytical_procedures.enabled);
5305 assert!(!config.confirmations.enabled);
5306 assert!(!config.opinion.enabled);
5307 assert!(!config.generate_audit_trail);
5308 assert!(!config.sox.enabled);
5309 assert!(!config.pcaob.enabled);
5310 }
5311
5312 #[test]
5313 fn test_audit_standards_config_yaml() {
5314 let yaml = r#"
5315 enabled: true
5316 isa_compliance:
5317 enabled: true
5318 compliance_level: comprehensive
5319 generate_isa_mappings: true
5320 include_pcaob: true
5321 framework: dual
5322 analytical_procedures:
5323 enabled: true
5324 procedures_per_account: 5
5325 variance_probability: 0.25
5326 confirmations:
5327 enabled: true
5328 confirmation_count: 75
5329 positive_response_rate: 0.90
5330 exception_rate: 0.08
5331 opinion:
5332 enabled: true
5333 generate_kam: true
5334 average_kam_count: 4
5335 sox:
5336 enabled: true
5337 generate_302_certifications: true
5338 generate_404_assessments: true
5339 material_weakness_rate: 0.03
5340 pcaob:
5341 enabled: true
5342 is_pcaob_audit: true
5343 include_icfr_opinion: true
5344 generate_audit_trail: true
5345 "#;
5346
5347 let config: AuditStandardsConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5348 assert!(config.enabled);
5349 assert!(config.isa_compliance.enabled);
5350 assert_eq!(config.isa_compliance.compliance_level, "comprehensive");
5351 assert!(config.isa_compliance.include_pcaob);
5352 assert_eq!(config.isa_compliance.framework, "dual");
5353 assert!(config.analytical_procedures.enabled);
5354 assert_eq!(config.analytical_procedures.procedures_per_account, 5);
5355 assert!(config.confirmations.enabled);
5356 assert_eq!(config.confirmations.confirmation_count, 75);
5357 assert!(config.opinion.enabled);
5358 assert_eq!(config.opinion.average_kam_count, 4);
5359 assert!(config.sox.enabled);
5360 assert!(config.sox.generate_302_certifications);
5361 assert_eq!(config.sox.material_weakness_rate, 0.03);
5362 assert!(config.pcaob.enabled);
5363 assert!(config.pcaob.is_pcaob_audit);
5364 assert!(config.pcaob.include_icfr_opinion);
5365 assert!(config.generate_audit_trail);
5366 }
5367
5368 #[test]
5369 fn test_isa_compliance_config_defaults() {
5370 let config = IsaComplianceConfig::default();
5371 assert!(!config.enabled);
5372 assert_eq!(config.compliance_level, "standard");
5373 assert!(config.generate_isa_mappings);
5374 assert!(config.generate_coverage_summary);
5375 assert!(!config.include_pcaob);
5376 assert_eq!(config.framework, "isa");
5377 }
5378
5379 #[test]
5380 fn test_sox_compliance_config_defaults() {
5381 let config = SoxComplianceConfig::default();
5382 assert!(!config.enabled);
5383 assert!(config.generate_302_certifications);
5384 assert!(config.generate_404_assessments);
5385 assert_eq!(config.materiality_threshold, 10000.0);
5386 assert_eq!(config.material_weakness_rate, 0.02);
5387 assert_eq!(config.significant_deficiency_rate, 0.08);
5388 }
5389
5390 #[test]
5391 fn test_pcaob_config_defaults() {
5392 let config = PcaobConfig::default();
5393 assert!(!config.enabled);
5394 assert!(!config.is_pcaob_audit);
5395 assert!(config.generate_cam);
5396 assert!(!config.include_icfr_opinion);
5397 assert!(!config.generate_standard_mappings);
5398 }
5399
5400 #[test]
5401 fn test_config_with_standards_enabled() {
5402 let yaml = r#"
5403 global:
5404 industry: financial_services
5405 start_date: "2024-01-01"
5406 period_months: 12
5407 companies:
5408 - code: "BANK"
5409 name: "Test Bank"
5410 currency: "USD"
5411 country: "US"
5412 annual_transaction_volume: hundred_k
5413 chart_of_accounts:
5414 complexity: large
5415 output:
5416 output_directory: "./output"
5417 accounting_standards:
5418 enabled: true
5419 framework: us_gaap
5420 revenue_recognition:
5421 enabled: true
5422 leases:
5423 enabled: true
5424 audit_standards:
5425 enabled: true
5426 isa_compliance:
5427 enabled: true
5428 sox:
5429 enabled: true
5430 "#;
5431
5432 let config: GeneratorConfig = serde_yaml::from_str(yaml).expect("Failed to parse");
5433 assert!(config.accounting_standards.enabled);
5434 assert!(matches!(
5435 config.accounting_standards.framework,
5436 AccountingFrameworkConfig::UsGaap
5437 ));
5438 assert!(config.accounting_standards.revenue_recognition.enabled);
5439 assert!(config.accounting_standards.leases.enabled);
5440 assert!(config.audit_standards.enabled);
5441 assert!(config.audit_standards.isa_compliance.enabled);
5442 assert!(config.audit_standards.sox.enabled);
5443 }
5444}