datasynth-core 5.6.0

Core domain models, traits, and distributions for synthetic enterprise data generation
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
//! Centralized GL account constants for consistent account mapping.
//!
//! This module provides standard account numbers used across all generators
//! to ensure consistency between document flow JE generation, subledger
//! generation, and reconciliation.

/// Goodwill and intangible asset accounts (used in business combinations).
pub mod intangible_accounts {
    /// Goodwill arising from business combinations
    pub const GOODWILL: &str = "1900";

    /// Customer relationships intangible asset
    pub const CUSTOMER_RELATIONSHIPS: &str = "1910";

    /// Trade name / brand intangible asset
    pub const TRADE_NAME: &str = "1920";

    /// Technology / developed software intangible asset
    pub const TECHNOLOGY: &str = "1930";

    /// Accumulated amortization – intangible assets
    pub const ACCUMULATED_AMORTIZATION: &str = "1950";

    /// Amortization expense – intangible assets
    pub const AMORTIZATION_EXPENSE: &str = "6010";

    /// Bargain purchase gain (when consideration < net identifiable assets FV)
    pub const BARGAIN_PURCHASE_GAIN: &str = "4850";
}

/// Control accounts for subledger integration.
pub mod control_accounts {
    /// Accounts Receivable control account
    pub const AR_CONTROL: &str = "1100";

    /// Accounts Payable control account
    pub const AP_CONTROL: &str = "2000";

    /// Inventory control account
    pub const INVENTORY: &str = "1200";

    /// Fixed Assets control account
    pub const FIXED_ASSETS: &str = "1500";

    /// Accumulated Depreciation control account
    pub const ACCUMULATED_DEPRECIATION: &str = "1510";

    /// GR/IR Clearing account (Goods Receipt/Invoice Receipt)
    pub const GR_IR_CLEARING: &str = "2900";

    /// Intercompany AR clearing
    pub const IC_AR_CLEARING: &str = "1150";

    /// Intercompany AP clearing
    pub const IC_AP_CLEARING: &str = "2050";
}

/// Cash and bank accounts.
pub mod cash_accounts {
    /// Primary operating cash account
    pub const OPERATING_CASH: &str = "1000";

    /// Primary bank account
    pub const BANK_ACCOUNT: &str = "1010";

    /// Petty cash account
    pub const PETTY_CASH: &str = "1020";

    /// Wire transfer clearing account
    pub const WIRE_CLEARING: &str = "1030";
}

/// Revenue accounts.
pub mod revenue_accounts {
    /// Product revenue account
    pub const PRODUCT_REVENUE: &str = "4000";

    /// Service revenue account
    pub const SERVICE_REVENUE: &str = "4100";

    /// Intercompany revenue account
    pub const IC_REVENUE: &str = "4500";

    /// Purchase discount income account
    pub const PURCHASE_DISCOUNT_INCOME: &str = "4800";

    /// Other revenue account
    pub const OTHER_REVENUE: &str = "4900";

    /// Sales discounts account
    pub const SALES_DISCOUNTS: &str = "4010";

    /// Sales returns and allowances account
    pub const SALES_RETURNS: &str = "4020";
}

/// Expense accounts.
pub mod expense_accounts {
    /// Cost of Goods Sold account
    pub const COGS: &str = "5000";

    /// Raw materials expense account
    pub const RAW_MATERIALS: &str = "5100";

    /// Direct labor expense account
    pub const DIRECT_LABOR: &str = "5200";

    /// Manufacturing overhead account
    pub const MANUFACTURING_OVERHEAD: &str = "5300";

    /// Depreciation expense account
    pub const DEPRECIATION: &str = "6000";

    /// Salaries and wages expense account
    pub const SALARIES_WAGES: &str = "6100";

    /// Benefits expense account
    pub const BENEFITS: &str = "6200";

    /// Rent expense account
    pub const RENT: &str = "6300";

    /// Utilities expense account
    pub const UTILITIES: &str = "6400";

    /// Office supplies expense account
    pub const OFFICE_SUPPLIES: &str = "6500";

    /// Travel and entertainment expense account
    pub const TRAVEL_ENTERTAINMENT: &str = "6600";

    /// Professional fees expense account
    pub const PROFESSIONAL_FEES: &str = "6700";

    /// Insurance expense account
    pub const INSURANCE: &str = "6800";

    /// Bad debt expense account
    pub const BAD_DEBT: &str = "6900";

    /// Pension expense (service cost + interest cost + amortization, IAS 19 / ASC 715)
    pub const PENSION_EXPENSE: &str = "6205";

    /// Interest expense account
    pub const INTEREST_EXPENSE: &str = "7100";

    /// Stock-based compensation expense (ASC 718)
    pub const STOCK_COMP_EXPENSE: &str = "7200";

    /// Purchase discounts account
    pub const PURCHASE_DISCOUNTS: &str = "7400";

    /// FX gain/loss account
    pub const FX_GAIN_LOSS: &str = "7500";
}

/// Manufacturing cost flow accounts.
pub mod manufacturing_accounts {
    /// Work-in-Process control account
    pub const WIP: &str = "1420";

    /// Finished Goods inventory account
    pub const FINISHED_GOODS: &str = "1410";

    /// Scrap expense account
    pub const SCRAP_EXPENSE: &str = "5210";

    /// Labor accrual liability account
    pub const LABOR_ACCRUAL: &str = "2150";

    /// Overhead applied clearing account
    pub const OVERHEAD_APPLIED: &str = "5310";

    /// Material price variance account
    pub const MATERIAL_PRICE_VARIANCE: &str = "5110";

    /// Material usage variance account
    pub const MATERIAL_USAGE_VARIANCE: &str = "5120";

    /// Labor rate variance account
    pub const LABOR_RATE_VARIANCE: &str = "5130";

    /// Labor efficiency variance account
    pub const LABOR_EFFICIENCY_VARIANCE: &str = "5140";

    /// Overhead volume variance account
    pub const OVERHEAD_VOLUME_VARIANCE: &str = "5150";

    /// Warranty provision liability account
    pub const WARRANTY_PROVISION: &str = "2410";

    /// Warranty expense account
    pub const WARRANTY_EXPENSE: &str = "5400";
}

/// Treasury accounting accounts for debt, hedging, and derivatives.
pub mod treasury_accounts {
    /// Interest payable (accrued interest on debt)
    pub const INTEREST_PAYABLE: &str = "2160";

    /// Debt premium account (above-par issuance)
    pub const DEBT_PREMIUM: &str = "2610";

    /// Debt discount account (below-par issuance, contra-liability)
    pub const DEBT_DISCOUNT: &str = "2620";

    /// Derivative asset (positive fair value of hedging instruments)
    pub const DERIVATIVE_ASSET: &str = "1450";

    /// Derivative liability (negative fair value of hedging instruments)
    /// Note: "2450" is used as PROVISION_LIABILITY in provision_accounts; using "2460".
    pub const DERIVATIVE_LIABILITY: &str = "2460";

    /// OCI — Cash flow hedge reserve (equity section)
    pub const OCI_CASH_FLOW_HEDGE: &str = "3510";

    /// Hedge ineffectiveness expense (P&L)
    pub const HEDGE_INEFFECTIVENESS: &str = "7510";

    /// IC receivable from cash pool (physical pooling)
    pub const CASH_POOL_IC_RECEIVABLE: &str = "1155";

    /// IC payable from cash pool (physical pooling)
    pub const CASH_POOL_IC_PAYABLE: &str = "2055";
}

/// Provision accounts (IAS 37 / ASC 450).
pub mod provision_accounts {
    /// Provision liability account
    pub const PROVISION_LIABILITY: &str = "2450";
    /// Provision expense account
    pub const PROVISION_EXPENSE: &str = "6850";
}

/// Tax accounts.
pub mod tax_accounts {
    /// Sales tax payable account
    pub const SALES_TAX_PAYABLE: &str = "2100";

    /// VAT payable account
    pub const VAT_PAYABLE: &str = "2110";

    /// Withholding tax payable account
    pub const WITHHOLDING_TAX_PAYABLE: &str = "2120";

    /// Income tax payable account
    pub const INCOME_TAX_PAYABLE: &str = "2130";

    /// Input VAT (VAT receivable) account
    pub const INPUT_VAT: &str = "1160";

    /// Tax receivable account (AP input tax)
    pub const TAX_RECEIVABLE: &str = "1460";

    /// Tax expense account
    pub const TAX_EXPENSE: &str = "8000";

    /// Deferred tax liability account
    pub const DEFERRED_TAX_LIABILITY: &str = "2500";

    /// Deferred tax asset account
    pub const DEFERRED_TAX_ASSET: &str = "1600";
}

/// Liability accounts.
pub mod liability_accounts {
    /// Accrued expenses account
    pub const ACCRUED_EXPENSES: &str = "2200";

    /// Accrued salaries account
    pub const ACCRUED_SALARIES: &str = "2210";

    /// Accrued benefits account
    pub const ACCRUED_BENEFITS: &str = "2220";

    /// Unearned revenue account
    pub const UNEARNED_REVENUE: &str = "2300";

    /// Short-term debt account
    pub const SHORT_TERM_DEBT: &str = "2400";

    /// Long-term debt account
    pub const LONG_TERM_DEBT: &str = "2600";

    /// Intercompany payable account
    pub const IC_PAYABLE: &str = "2700";

    /// Net pension liability account (IAS 19 / ASC 715).
    /// Also used as the contingent consideration liability under ASC 805 / IFRS 3.
    pub const NET_PENSION_LIABILITY: &str = "2800";
}

/// Fixed-asset class accounts (one acquisition account per `AssetClass`,
/// with corresponding accumulated-depreciation contras).
///
/// These mirror the accounts emitted by
/// [`crate::models::subledger::fa::AssetAccountDetermination::default_for_class`]
/// and must be seeded into the chart of accounts so generated JEs can be
/// resolved back to GL accounts.
pub mod asset_class_accounts {
    // --- Acquisition accounts ---
    /// Land
    pub const LAND: &str = "1510";
    /// Buildings
    pub const BUILDINGS: &str = "1520";
    /// Building improvements
    pub const BUILDING_IMPROVEMENTS: &str = "1525";
    /// Machinery / equipment
    pub const MACHINERY_EQUIPMENT: &str = "1530";
    /// Vehicles
    pub const VEHICLES: &str = "1540";
    /// Office equipment
    pub const OFFICE_EQUIPMENT: &str = "1550";
    /// Computer / IT hardware
    pub const COMPUTER_HARDWARE: &str = "1555";
    /// Software / intangibles (subledger-asset side)
    pub const SOFTWARE_INTANGIBLES: &str = "1560";
    /// Furniture and fixtures
    pub const FURNITURE_FIXTURES: &str = "1570";
    /// Leasehold improvements
    pub const LEASEHOLD_IMPROVEMENTS: &str = "1580";
    /// Other / misc assets
    pub const OTHER_ASSETS: &str = "1590";
    /// Low-value assets
    pub const LOW_VALUE_ASSETS: &str = "1595";
    /// Construction in progress
    pub const CONSTRUCTION_IN_PROGRESS: &str = "1600";

    // --- Accumulated depreciation contras (acquisition account with last digit '9') ---
    /// Accumulated depreciation — Land (rare; usually no depreciation)
    pub const ACC_DEP_LAND: &str = "1519";
    /// Accumulated depreciation — Buildings
    pub const ACC_DEP_BUILDINGS: &str = "1529";
    /// Accumulated depreciation — Machinery / equipment
    pub const ACC_DEP_MACHINERY: &str = "1539";
    /// Accumulated depreciation — Vehicles
    pub const ACC_DEP_VEHICLES: &str = "1549";
    /// Accumulated depreciation — Office equipment
    pub const ACC_DEP_OFFICE_EQUIPMENT: &str = "1559";
    /// Accumulated depreciation — Software / intangibles
    pub const ACC_DEP_SOFTWARE: &str = "1569";
    /// Accumulated depreciation — Furniture & fixtures
    pub const ACC_DEP_FURNITURE: &str = "1579";
    /// Accumulated depreciation — Leasehold improvements
    pub const ACC_DEP_LEASEHOLD: &str = "1589";
    /// Accumulated depreciation — Other assets
    pub const ACC_DEP_OTHER: &str = "1599";
    /// Accumulated depreciation — CIP (rare)
    pub const ACC_DEP_CIP: &str = "1609";

    /// Acquisition clearing account
    pub const ACQUISITION_CLEARING: &str = "1599";

    /// FA-subledger depreciation expense account.
    ///
    /// Distinct from the GL-level [`super::expense_accounts::DEPRECIATION`]
    /// (6000); the FA subledger has historically posted depreciation to
    /// 7100. We expose both so neither becomes an orphan.
    pub const DEPRECIATION_EXPENSE: &str = "7100";

    /// Gain on disposal of fixed assets.
    pub const GAIN_ON_DISPOSAL: &str = "4900";

    /// Loss on disposal of fixed assets.
    pub const LOSS_ON_DISPOSAL: &str = "7900";
}

/// Inventory subledger accounts beyond the canonical INVENTORY (1200).
///
/// Distinct from [`control_accounts::INVENTORY`] which is the GL-level
/// control. These are sub-classifications used by the inventory
/// subledger generator.
pub mod inventory_accounts {
    /// Inventory write-up income (rare; for fair-value markups)
    pub const WRITEUP_INCOME: &str = "4950";
    /// Inventory write-down expense (LCM/NRV adjustments)
    pub const WRITEDOWN_EXPENSE: &str = "6950";
}

/// Equity accounts.
pub mod equity_accounts {
    /// Common stock account
    pub const COMMON_STOCK: &str = "3000";

    /// Additional paid-in capital account
    pub const APIC: &str = "3100";

    /// Additional paid-in capital — stock-based compensation (ASC 718).
    pub const APIC_STOCK_COMP: &str = "3150";

    /// Retained earnings account
    pub const RETAINED_EARNINGS: &str = "3200";

    /// Current year earnings account
    pub const CURRENT_YEAR_EARNINGS: &str = "3300";

    /// Treasury stock account
    pub const TREASURY_STOCK: &str = "3400";

    /// Currency translation adjustment account
    pub const CTA: &str = "3500";

    /// Income summary account (used for year-end close)
    pub const INCOME_SUMMARY: &str = "3600";

    /// Dividends paid account
    pub const DIVIDENDS_PAID: &str = "3700";

    /// OCI — Pension remeasurements (IAS 19 / ASC 715)
    pub const OCI_REMEASUREMENTS: &str = "3800";
}

/// Dividend accounts.
pub mod dividend_accounts {
    /// Dividends payable (liability — declared but not yet paid)
    pub const DIVIDENDS_PAYABLE: &str = "2170";
    /// Dividends declared (contra-equity, reduces retained earnings)
    pub const DIVIDENDS_DECLARED: &str = "3710";
}

/// Suspense and clearing accounts.
pub mod suspense_accounts {
    /// General suspense account
    pub const GENERAL_SUSPENSE: &str = "9000";

    /// Payroll clearing account
    pub const PAYROLL_CLEARING: &str = "9100";

    /// Bank reconciliation suspense account
    pub const BANK_RECONCILIATION_SUSPENSE: &str = "9200";

    /// IC elimination suspense account
    pub const IC_ELIMINATION_SUSPENSE: &str = "9300";
}

/// Dormant / blocked / legacy accounts used by the
/// `DormantAccountActivity` anomaly strategy.
///
/// Real-world COAs retain old / migrated / test accounts as
/// `is_blocked = true` entries so audit trails remain resolvable; these
/// constants follow the same pattern. The anomaly strategy targets them
/// to simulate a classic fraud signature: posting to a long-dormant
/// account so the entry hides among genuine activity.
pub mod dormant_accounts {
    /// Legacy suspense (migrated-out, retained for trail).
    pub const LEGACY_SUSPENSE: &str = "199999";
    /// Legacy clearing (predecessor system).
    pub const LEGACY_CLEARING: &str = "299999";
    /// Obsolete account flagged for retirement.
    pub const OBSOLETE: &str = "399999";
    /// Test account (production residue from QA).
    pub const TEST_ACCOUNT: &str = "999999";
}

/// Account type by prefix.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AccountCategory {
    /// Assets (1xxx)
    Asset,
    /// Liabilities (2xxx)
    Liability,
    /// Equity (3xxx)
    Equity,
    /// Revenue (4xxx)
    Revenue,
    /// Cost of Goods Sold (5xxx)
    Cogs,
    /// Operating Expenses (6xxx)
    OperatingExpense,
    /// Other Income/Expense (7xxx)
    OtherIncomeExpense,
    /// Taxes (8xxx)
    Tax,
    /// Suspense/Clearing (9xxx)
    Suspense,
    /// Unknown
    Unknown,
}

impl AccountCategory {
    /// Snake-case label used in serialized output (CSV / JSON
    /// `financial_statement_category` column).
    pub fn as_label(&self) -> &'static str {
        match self {
            Self::Asset => "asset",
            Self::Liability => "liability",
            Self::Equity => "equity",
            Self::Revenue => "revenue",
            Self::Cogs => "cogs",
            Self::OperatingExpense => "operating_expense",
            Self::OtherIncomeExpense => "other_income_expense",
            Self::Tax => "tax",
            Self::Suspense => "suspense",
            Self::Unknown => "unknown",
        }
    }

    /// Determine account category from account number.
    pub fn from_account(account: &str) -> Self {
        if account.is_empty() {
            return Self::Unknown;
        }

        match account.chars().next() {
            Some('1') => Self::Asset,
            Some('2') => Self::Liability,
            Some('3') => Self::Equity,
            Some('4') => Self::Revenue,
            Some('5') => Self::Cogs,
            Some('6') => Self::OperatingExpense,
            Some('7') => Self::OtherIncomeExpense,
            Some('8') => Self::Tax,
            Some('9') => Self::Suspense,
            _ => Self::Unknown,
        }
    }

    /// Check if this category is a debit-normal account.
    pub fn is_debit_normal(&self) -> bool {
        matches!(
            self,
            Self::Asset
                | Self::Cogs
                | Self::OperatingExpense
                | Self::OtherIncomeExpense
                | Self::Tax
        )
    }

    /// Check if this category is a credit-normal account.
    pub fn is_credit_normal(&self) -> bool {
        matches!(self, Self::Liability | Self::Equity | Self::Revenue)
    }

    /// Check if this category is a balance sheet account.
    pub fn is_balance_sheet(&self) -> bool {
        matches!(self, Self::Asset | Self::Liability | Self::Equity)
    }

    /// Check if this category is an income statement account.
    pub fn is_income_statement(&self) -> bool {
        matches!(
            self,
            Self::Revenue
                | Self::Cogs
                | Self::OperatingExpense
                | Self::OtherIncomeExpense
                | Self::Tax
        )
    }
}

#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
    use super::*;

    #[test]
    fn test_account_category_from_account() {
        assert_eq!(
            AccountCategory::from_account(control_accounts::AR_CONTROL),
            AccountCategory::Asset
        );
        assert_eq!(
            AccountCategory::from_account(control_accounts::AP_CONTROL),
            AccountCategory::Liability
        );
        assert_eq!(
            AccountCategory::from_account(equity_accounts::RETAINED_EARNINGS),
            AccountCategory::Equity
        );
        assert_eq!(
            AccountCategory::from_account(revenue_accounts::PRODUCT_REVENUE),
            AccountCategory::Revenue
        );
        assert_eq!(
            AccountCategory::from_account(expense_accounts::COGS),
            AccountCategory::Cogs
        );
    }

    #[test]
    fn test_debit_credit_normal() {
        assert!(AccountCategory::Asset.is_debit_normal());
        assert!(AccountCategory::Revenue.is_credit_normal());
        assert!(!AccountCategory::Asset.is_credit_normal());
        assert!(!AccountCategory::Revenue.is_debit_normal());
    }

    #[test]
    fn test_balance_sheet_vs_income_statement() {
        assert!(AccountCategory::Asset.is_balance_sheet());
        assert!(AccountCategory::Liability.is_balance_sheet());
        assert!(AccountCategory::Equity.is_balance_sheet());
        assert!(!AccountCategory::Revenue.is_balance_sheet());

        assert!(AccountCategory::Revenue.is_income_statement());
        assert!(AccountCategory::Cogs.is_income_statement());
        assert!(!AccountCategory::Asset.is_income_statement());
    }
}