1use tracing::debug;
4
5use datasynth_core::accounts::{
6 cash_accounts, control_accounts, equity_accounts, expense_accounts, liability_accounts,
7 revenue_accounts, suspense_accounts, tax_accounts,
8};
9use datasynth_core::models::*;
10use datasynth_core::traits::Generator;
11use datasynth_core::utils::seeded_rng;
12use rand_chacha::ChaCha8Rng;
13
14pub struct ChartOfAccountsGenerator {
16 rng: ChaCha8Rng,
17 seed: u64,
18 complexity: CoAComplexity,
19 industry: IndustrySector,
20 count: u64,
21}
22
23impl ChartOfAccountsGenerator {
24 pub fn new(complexity: CoAComplexity, industry: IndustrySector, seed: u64) -> Self {
26 Self {
27 rng: seeded_rng(seed, 0),
28 seed,
29 complexity,
30 industry,
31 count: 0,
32 }
33 }
34
35 pub fn generate(&mut self) -> ChartOfAccounts {
37 debug!(
38 complexity = ?self.complexity,
39 industry = ?self.industry,
40 seed = self.seed,
41 "Generating chart of accounts"
42 );
43
44 self.count += 1;
45 let target_count = self.complexity.target_count();
46
47 let mut coa = ChartOfAccounts::new(
48 format!("COA_{:?}_{}", self.industry, self.complexity.target_count()),
49 format!("{:?} Chart of Accounts", self.industry),
50 "US".to_string(),
51 self.industry,
52 self.complexity,
53 );
54
55 Self::seed_canonical_accounts(&mut coa);
57
58 self.generate_asset_accounts(&mut coa, target_count / 5);
60 self.generate_liability_accounts(&mut coa, target_count / 6);
61 self.generate_equity_accounts(&mut coa, target_count / 10);
62 self.generate_revenue_accounts(&mut coa, target_count / 5);
63 self.generate_expense_accounts(&mut coa, target_count / 4);
64 self.generate_suspense_accounts(&mut coa);
65
66 coa
67 }
68
69 fn seed_canonical_accounts(coa: &mut ChartOfAccounts) {
75 coa.add_account(GLAccount::new(
77 cash_accounts::OPERATING_CASH.to_string(),
78 "Operating Cash".to_string(),
79 AccountType::Asset,
80 AccountSubType::Cash,
81 ));
82 coa.add_account(GLAccount::new(
83 cash_accounts::BANK_ACCOUNT.to_string(),
84 "Bank Account".to_string(),
85 AccountType::Asset,
86 AccountSubType::Cash,
87 ));
88 coa.add_account(GLAccount::new(
89 cash_accounts::PETTY_CASH.to_string(),
90 "Petty Cash".to_string(),
91 AccountType::Asset,
92 AccountSubType::Cash,
93 ));
94 coa.add_account(GLAccount::new(
95 cash_accounts::WIRE_CLEARING.to_string(),
96 "Wire Transfer Clearing".to_string(),
97 AccountType::Asset,
98 AccountSubType::BankClearing,
99 ));
100
101 {
103 let mut acct = GLAccount::new(
104 control_accounts::AR_CONTROL.to_string(),
105 "Accounts Receivable Control".to_string(),
106 AccountType::Asset,
107 AccountSubType::AccountsReceivable,
108 );
109 acct.is_control_account = true;
110 coa.add_account(acct);
111 }
112 {
113 let mut acct = GLAccount::new(
114 control_accounts::IC_AR_CLEARING.to_string(),
115 "Intercompany AR Clearing".to_string(),
116 AccountType::Asset,
117 AccountSubType::AccountsReceivable,
118 );
119 acct.is_control_account = true;
120 coa.add_account(acct);
121 }
122 coa.add_account(GLAccount::new(
123 control_accounts::INVENTORY.to_string(),
124 "Inventory".to_string(),
125 AccountType::Asset,
126 AccountSubType::Inventory,
127 ));
128 coa.add_account(GLAccount::new(
129 control_accounts::FIXED_ASSETS.to_string(),
130 "Fixed Assets".to_string(),
131 AccountType::Asset,
132 AccountSubType::FixedAssets,
133 ));
134 coa.add_account(GLAccount::new(
135 control_accounts::ACCUMULATED_DEPRECIATION.to_string(),
136 "Accumulated Depreciation".to_string(),
137 AccountType::Asset,
138 AccountSubType::AccumulatedDepreciation,
139 ));
140
141 coa.add_account(GLAccount::new(
143 tax_accounts::INPUT_VAT.to_string(),
144 "Input VAT".to_string(),
145 AccountType::Asset,
146 AccountSubType::OtherReceivables,
147 ));
148 coa.add_account(GLAccount::new(
149 tax_accounts::DEFERRED_TAX_ASSET.to_string(),
150 "Deferred Tax Asset".to_string(),
151 AccountType::Asset,
152 AccountSubType::OtherAssets,
153 ));
154
155 {
157 let mut acct = GLAccount::new(
158 control_accounts::AP_CONTROL.to_string(),
159 "Accounts Payable Control".to_string(),
160 AccountType::Liability,
161 AccountSubType::AccountsPayable,
162 );
163 acct.is_control_account = true;
164 coa.add_account(acct);
165 }
166 {
167 let mut acct = GLAccount::new(
168 control_accounts::IC_AP_CLEARING.to_string(),
169 "Intercompany AP Clearing".to_string(),
170 AccountType::Liability,
171 AccountSubType::AccountsPayable,
172 );
173 acct.is_control_account = true;
174 coa.add_account(acct);
175 }
176 coa.add_account(GLAccount::new(
177 tax_accounts::SALES_TAX_PAYABLE.to_string(),
178 "Sales Tax Payable".to_string(),
179 AccountType::Liability,
180 AccountSubType::TaxLiabilities,
181 ));
182 coa.add_account(GLAccount::new(
183 tax_accounts::VAT_PAYABLE.to_string(),
184 "VAT Payable".to_string(),
185 AccountType::Liability,
186 AccountSubType::TaxLiabilities,
187 ));
188 coa.add_account(GLAccount::new(
189 tax_accounts::WITHHOLDING_TAX_PAYABLE.to_string(),
190 "Withholding Tax Payable".to_string(),
191 AccountType::Liability,
192 AccountSubType::TaxLiabilities,
193 ));
194 coa.add_account(GLAccount::new(
195 liability_accounts::ACCRUED_EXPENSES.to_string(),
196 "Accrued Expenses".to_string(),
197 AccountType::Liability,
198 AccountSubType::AccruedLiabilities,
199 ));
200 coa.add_account(GLAccount::new(
201 liability_accounts::ACCRUED_SALARIES.to_string(),
202 "Accrued Salaries".to_string(),
203 AccountType::Liability,
204 AccountSubType::AccruedLiabilities,
205 ));
206 coa.add_account(GLAccount::new(
207 liability_accounts::ACCRUED_BENEFITS.to_string(),
208 "Accrued Benefits".to_string(),
209 AccountType::Liability,
210 AccountSubType::AccruedLiabilities,
211 ));
212 coa.add_account(GLAccount::new(
213 liability_accounts::UNEARNED_REVENUE.to_string(),
214 "Unearned Revenue".to_string(),
215 AccountType::Liability,
216 AccountSubType::DeferredRevenue,
217 ));
218 coa.add_account(GLAccount::new(
219 liability_accounts::SHORT_TERM_DEBT.to_string(),
220 "Short-Term Debt".to_string(),
221 AccountType::Liability,
222 AccountSubType::ShortTermDebt,
223 ));
224 coa.add_account(GLAccount::new(
225 tax_accounts::DEFERRED_TAX_LIABILITY.to_string(),
226 "Deferred Tax Liability".to_string(),
227 AccountType::Liability,
228 AccountSubType::TaxLiabilities,
229 ));
230 coa.add_account(GLAccount::new(
231 liability_accounts::LONG_TERM_DEBT.to_string(),
232 "Long-Term Debt".to_string(),
233 AccountType::Liability,
234 AccountSubType::LongTermDebt,
235 ));
236 coa.add_account(GLAccount::new(
237 liability_accounts::IC_PAYABLE.to_string(),
238 "Intercompany Payable".to_string(),
239 AccountType::Liability,
240 AccountSubType::OtherLiabilities,
241 ));
242 {
243 let mut acct = GLAccount::new(
244 control_accounts::GR_IR_CLEARING.to_string(),
245 "GR/IR Clearing".to_string(),
246 AccountType::Liability,
247 AccountSubType::GoodsReceivedClearing,
248 );
249 acct.is_suspense_account = true;
250 coa.add_account(acct);
251 }
252
253 coa.add_account(GLAccount::new(
255 equity_accounts::COMMON_STOCK.to_string(),
256 "Common Stock".to_string(),
257 AccountType::Equity,
258 AccountSubType::CommonStock,
259 ));
260 coa.add_account(GLAccount::new(
261 equity_accounts::APIC.to_string(),
262 "Additional Paid-In Capital".to_string(),
263 AccountType::Equity,
264 AccountSubType::AdditionalPaidInCapital,
265 ));
266 coa.add_account(GLAccount::new(
267 equity_accounts::RETAINED_EARNINGS.to_string(),
268 "Retained Earnings".to_string(),
269 AccountType::Equity,
270 AccountSubType::RetainedEarnings,
271 ));
272 coa.add_account(GLAccount::new(
273 equity_accounts::CURRENT_YEAR_EARNINGS.to_string(),
274 "Current Year Earnings".to_string(),
275 AccountType::Equity,
276 AccountSubType::NetIncome,
277 ));
278 coa.add_account(GLAccount::new(
279 equity_accounts::TREASURY_STOCK.to_string(),
280 "Treasury Stock".to_string(),
281 AccountType::Equity,
282 AccountSubType::TreasuryStock,
283 ));
284 coa.add_account(GLAccount::new(
285 equity_accounts::CTA.to_string(),
286 "Currency Translation Adjustment".to_string(),
287 AccountType::Equity,
288 AccountSubType::OtherComprehensiveIncome,
289 ));
290
291 coa.add_account(GLAccount::new(
293 revenue_accounts::PRODUCT_REVENUE.to_string(),
294 "Product Revenue".to_string(),
295 AccountType::Revenue,
296 AccountSubType::ProductRevenue,
297 ));
298 coa.add_account(GLAccount::new(
299 revenue_accounts::SALES_DISCOUNTS.to_string(),
300 "Sales Discounts".to_string(),
301 AccountType::Revenue,
302 AccountSubType::ProductRevenue,
303 ));
304 coa.add_account(GLAccount::new(
305 revenue_accounts::SALES_RETURNS.to_string(),
306 "Sales Returns and Allowances".to_string(),
307 AccountType::Revenue,
308 AccountSubType::ProductRevenue,
309 ));
310 coa.add_account(GLAccount::new(
311 revenue_accounts::SERVICE_REVENUE.to_string(),
312 "Service Revenue".to_string(),
313 AccountType::Revenue,
314 AccountSubType::ServiceRevenue,
315 ));
316 coa.add_account(GLAccount::new(
317 revenue_accounts::IC_REVENUE.to_string(),
318 "Intercompany Revenue".to_string(),
319 AccountType::Revenue,
320 AccountSubType::OtherIncome,
321 ));
322 coa.add_account(GLAccount::new(
323 revenue_accounts::OTHER_REVENUE.to_string(),
324 "Other Revenue".to_string(),
325 AccountType::Revenue,
326 AccountSubType::OtherIncome,
327 ));
328
329 {
331 let mut acct = GLAccount::new(
332 expense_accounts::COGS.to_string(),
333 "Cost of Goods Sold".to_string(),
334 AccountType::Expense,
335 AccountSubType::CostOfGoodsSold,
336 );
337 acct.requires_cost_center = true;
338 coa.add_account(acct);
339 }
340 {
341 let mut acct = GLAccount::new(
342 expense_accounts::RAW_MATERIALS.to_string(),
343 "Raw Materials".to_string(),
344 AccountType::Expense,
345 AccountSubType::CostOfGoodsSold,
346 );
347 acct.requires_cost_center = true;
348 coa.add_account(acct);
349 }
350 {
351 let mut acct = GLAccount::new(
352 expense_accounts::DIRECT_LABOR.to_string(),
353 "Direct Labor".to_string(),
354 AccountType::Expense,
355 AccountSubType::CostOfGoodsSold,
356 );
357 acct.requires_cost_center = true;
358 coa.add_account(acct);
359 }
360 {
361 let mut acct = GLAccount::new(
362 expense_accounts::MANUFACTURING_OVERHEAD.to_string(),
363 "Manufacturing Overhead".to_string(),
364 AccountType::Expense,
365 AccountSubType::CostOfGoodsSold,
366 );
367 acct.requires_cost_center = true;
368 coa.add_account(acct);
369 }
370 {
371 let mut acct = GLAccount::new(
372 expense_accounts::DEPRECIATION.to_string(),
373 "Depreciation Expense".to_string(),
374 AccountType::Expense,
375 AccountSubType::DepreciationExpense,
376 );
377 acct.requires_cost_center = true;
378 coa.add_account(acct);
379 }
380 {
381 let mut acct = GLAccount::new(
382 expense_accounts::SALARIES_WAGES.to_string(),
383 "Salaries and Wages".to_string(),
384 AccountType::Expense,
385 AccountSubType::OperatingExpenses,
386 );
387 acct.requires_cost_center = true;
388 coa.add_account(acct);
389 }
390 {
391 let mut acct = GLAccount::new(
392 expense_accounts::BENEFITS.to_string(),
393 "Benefits Expense".to_string(),
394 AccountType::Expense,
395 AccountSubType::OperatingExpenses,
396 );
397 acct.requires_cost_center = true;
398 coa.add_account(acct);
399 }
400 {
401 let mut acct = GLAccount::new(
402 expense_accounts::RENT.to_string(),
403 "Rent Expense".to_string(),
404 AccountType::Expense,
405 AccountSubType::OperatingExpenses,
406 );
407 acct.requires_cost_center = true;
408 coa.add_account(acct);
409 }
410 {
411 let mut acct = GLAccount::new(
412 expense_accounts::UTILITIES.to_string(),
413 "Utilities Expense".to_string(),
414 AccountType::Expense,
415 AccountSubType::OperatingExpenses,
416 );
417 acct.requires_cost_center = true;
418 coa.add_account(acct);
419 }
420 {
421 let mut acct = GLAccount::new(
422 expense_accounts::OFFICE_SUPPLIES.to_string(),
423 "Office Supplies".to_string(),
424 AccountType::Expense,
425 AccountSubType::AdministrativeExpenses,
426 );
427 acct.requires_cost_center = true;
428 coa.add_account(acct);
429 }
430 {
431 let mut acct = GLAccount::new(
432 expense_accounts::TRAVEL_ENTERTAINMENT.to_string(),
433 "Travel and Entertainment".to_string(),
434 AccountType::Expense,
435 AccountSubType::SellingExpenses,
436 );
437 acct.requires_cost_center = true;
438 coa.add_account(acct);
439 }
440 {
441 let mut acct = GLAccount::new(
442 expense_accounts::PROFESSIONAL_FEES.to_string(),
443 "Professional Fees".to_string(),
444 AccountType::Expense,
445 AccountSubType::AdministrativeExpenses,
446 );
447 acct.requires_cost_center = true;
448 coa.add_account(acct);
449 }
450 {
451 let mut acct = GLAccount::new(
452 expense_accounts::INSURANCE.to_string(),
453 "Insurance Expense".to_string(),
454 AccountType::Expense,
455 AccountSubType::OperatingExpenses,
456 );
457 acct.requires_cost_center = true;
458 coa.add_account(acct);
459 }
460 {
461 let mut acct = GLAccount::new(
462 expense_accounts::BAD_DEBT.to_string(),
463 "Bad Debt Expense".to_string(),
464 AccountType::Expense,
465 AccountSubType::OperatingExpenses,
466 );
467 acct.requires_cost_center = true;
468 coa.add_account(acct);
469 }
470 {
471 let mut acct = GLAccount::new(
472 expense_accounts::INTEREST_EXPENSE.to_string(),
473 "Interest Expense".to_string(),
474 AccountType::Expense,
475 AccountSubType::InterestExpense,
476 );
477 acct.requires_cost_center = true;
478 coa.add_account(acct);
479 }
480 {
481 let mut acct = GLAccount::new(
482 expense_accounts::PURCHASE_DISCOUNTS.to_string(),
483 "Purchase Discounts".to_string(),
484 AccountType::Expense,
485 AccountSubType::OtherExpenses,
486 );
487 acct.requires_cost_center = true;
488 coa.add_account(acct);
489 }
490 {
491 let mut acct = GLAccount::new(
492 expense_accounts::FX_GAIN_LOSS.to_string(),
493 "FX Gain/Loss".to_string(),
494 AccountType::Expense,
495 AccountSubType::ForeignExchangeLoss,
496 );
497 acct.requires_cost_center = true;
498 coa.add_account(acct);
499 }
500
501 {
503 let mut acct = GLAccount::new(
504 tax_accounts::TAX_EXPENSE.to_string(),
505 "Tax Expense".to_string(),
506 AccountType::Expense,
507 AccountSubType::TaxExpense,
508 );
509 acct.requires_cost_center = true;
510 coa.add_account(acct);
511 }
512
513 {
515 let mut acct = GLAccount::new(
516 suspense_accounts::GENERAL_SUSPENSE.to_string(),
517 "General Suspense".to_string(),
518 AccountType::Asset,
519 AccountSubType::SuspenseClearing,
520 );
521 acct.is_suspense_account = true;
522 coa.add_account(acct);
523 }
524 {
525 let mut acct = GLAccount::new(
526 suspense_accounts::PAYROLL_CLEARING.to_string(),
527 "Payroll Clearing".to_string(),
528 AccountType::Asset,
529 AccountSubType::SuspenseClearing,
530 );
531 acct.is_suspense_account = true;
532 coa.add_account(acct);
533 }
534 {
535 let mut acct = GLAccount::new(
536 suspense_accounts::BANK_RECONCILIATION_SUSPENSE.to_string(),
537 "Bank Reconciliation Suspense".to_string(),
538 AccountType::Asset,
539 AccountSubType::BankClearing,
540 );
541 acct.is_suspense_account = true;
542 coa.add_account(acct);
543 }
544 {
545 let mut acct = GLAccount::new(
546 suspense_accounts::IC_ELIMINATION_SUSPENSE.to_string(),
547 "IC Elimination Suspense".to_string(),
548 AccountType::Asset,
549 AccountSubType::IntercompanyClearing,
550 );
551 acct.is_suspense_account = true;
552 coa.add_account(acct);
553 }
554 }
555
556 fn generate_asset_accounts(&mut self, coa: &mut ChartOfAccounts, count: usize) {
557 let sub_types = vec![
558 (AccountSubType::Cash, "Cash", 0.15),
559 (
560 AccountSubType::AccountsReceivable,
561 "Accounts Receivable",
562 0.20,
563 ),
564 (AccountSubType::Inventory, "Inventory", 0.15),
565 (AccountSubType::PrepaidExpenses, "Prepaid Expenses", 0.10),
566 (AccountSubType::FixedAssets, "Fixed Assets", 0.25),
567 (
568 AccountSubType::AccumulatedDepreciation,
569 "Accumulated Depreciation",
570 0.10,
571 ),
572 (AccountSubType::OtherAssets, "Other Assets", 0.05),
573 ];
574
575 let mut account_num = 100000u32;
576 for (sub_type, name_prefix, weight) in sub_types {
577 let sub_count = ((count as f64) * weight).round() as usize;
578 for i in 0..sub_count.max(1) {
579 let account = GLAccount::new(
580 format!("{}", account_num),
581 format!("{} {}", name_prefix, i + 1),
582 AccountType::Asset,
583 sub_type,
584 );
585 coa.add_account(account);
586 account_num += 10;
587 }
588 }
589 }
590
591 fn generate_liability_accounts(&mut self, coa: &mut ChartOfAccounts, count: usize) {
592 let sub_types = vec![
593 (AccountSubType::AccountsPayable, "Accounts Payable", 0.25),
594 (
595 AccountSubType::AccruedLiabilities,
596 "Accrued Liabilities",
597 0.20,
598 ),
599 (AccountSubType::ShortTermDebt, "Short-Term Debt", 0.15),
600 (AccountSubType::LongTermDebt, "Long-Term Debt", 0.15),
601 (AccountSubType::DeferredRevenue, "Deferred Revenue", 0.15),
602 (AccountSubType::TaxLiabilities, "Tax Liabilities", 0.10),
603 ];
604
605 let mut account_num = 200000u32;
606 for (sub_type, name_prefix, weight) in sub_types {
607 let sub_count = ((count as f64) * weight).round() as usize;
608 for i in 0..sub_count.max(1) {
609 let account = GLAccount::new(
610 format!("{}", account_num),
611 format!("{} {}", name_prefix, i + 1),
612 AccountType::Liability,
613 sub_type,
614 );
615 coa.add_account(account);
616 account_num += 10;
617 }
618 }
619 }
620
621 fn generate_equity_accounts(&mut self, coa: &mut ChartOfAccounts, count: usize) {
622 let sub_types = vec![
623 (AccountSubType::CommonStock, "Common Stock", 0.20),
624 (AccountSubType::RetainedEarnings, "Retained Earnings", 0.30),
625 (AccountSubType::AdditionalPaidInCapital, "APIC", 0.20),
626 (AccountSubType::OtherComprehensiveIncome, "OCI", 0.30),
627 ];
628
629 let mut account_num = 300000u32;
630 for (sub_type, name_prefix, weight) in sub_types {
631 let sub_count = ((count as f64) * weight).round() as usize;
632 for i in 0..sub_count.max(1) {
633 let account = GLAccount::new(
634 format!("{}", account_num),
635 format!("{} {}", name_prefix, i + 1),
636 AccountType::Equity,
637 sub_type,
638 );
639 coa.add_account(account);
640 account_num += 10;
641 }
642 }
643 }
644
645 fn generate_revenue_accounts(&mut self, coa: &mut ChartOfAccounts, count: usize) {
646 let sub_types = vec![
647 (AccountSubType::ProductRevenue, "Product Revenue", 0.40),
648 (AccountSubType::ServiceRevenue, "Service Revenue", 0.30),
649 (AccountSubType::InterestIncome, "Interest Income", 0.10),
650 (AccountSubType::OtherIncome, "Other Income", 0.20),
651 ];
652
653 let mut account_num = 400000u32;
654 for (sub_type, name_prefix, weight) in sub_types {
655 let sub_count = ((count as f64) * weight).round() as usize;
656 for i in 0..sub_count.max(1) {
657 let account = GLAccount::new(
658 format!("{}", account_num),
659 format!("{} {}", name_prefix, i + 1),
660 AccountType::Revenue,
661 sub_type,
662 );
663 coa.add_account(account);
664 account_num += 10;
665 }
666 }
667 }
668
669 fn generate_expense_accounts(&mut self, coa: &mut ChartOfAccounts, count: usize) {
670 let sub_types = vec![
671 (AccountSubType::CostOfGoodsSold, "COGS", 0.20),
672 (
673 AccountSubType::OperatingExpenses,
674 "Operating Expenses",
675 0.25,
676 ),
677 (AccountSubType::SellingExpenses, "Selling Expenses", 0.15),
678 (
679 AccountSubType::AdministrativeExpenses,
680 "Admin Expenses",
681 0.15,
682 ),
683 (AccountSubType::DepreciationExpense, "Depreciation", 0.10),
684 (AccountSubType::InterestExpense, "Interest Expense", 0.05),
685 (AccountSubType::TaxExpense, "Tax Expense", 0.05),
686 (AccountSubType::OtherExpenses, "Other Expenses", 0.05),
687 ];
688
689 let mut account_num = 500000u32;
690 for (sub_type, name_prefix, weight) in sub_types {
691 let sub_count = ((count as f64) * weight).round() as usize;
692 for i in 0..sub_count.max(1) {
693 let mut account = GLAccount::new(
694 format!("{}", account_num),
695 format!("{} {}", name_prefix, i + 1),
696 AccountType::Expense,
697 sub_type,
698 );
699 account.requires_cost_center = true;
700 coa.add_account(account);
701 account_num += 10;
702 }
703 }
704 }
705
706 fn generate_suspense_accounts(&mut self, coa: &mut ChartOfAccounts) {
707 let suspense_types = vec![
708 (AccountSubType::SuspenseClearing, "Suspense Clearing"),
709 (AccountSubType::GoodsReceivedClearing, "GR/IR Clearing"),
710 (AccountSubType::BankClearing, "Bank Clearing"),
711 (
712 AccountSubType::IntercompanyClearing,
713 "Intercompany Clearing",
714 ),
715 ];
716
717 let mut account_num = 199000u32;
718 for (sub_type, name) in suspense_types {
719 let mut account = GLAccount::new(
720 format!("{}", account_num),
721 name.to_string(),
722 AccountType::Asset,
723 sub_type,
724 );
725 account.is_suspense_account = true;
726 coa.add_account(account);
727 account_num += 100;
728 }
729 }
730}
731
732impl Generator for ChartOfAccountsGenerator {
733 type Item = ChartOfAccounts;
734 type Config = (CoAComplexity, IndustrySector);
735
736 fn new(config: Self::Config, seed: u64) -> Self {
737 Self::new(config.0, config.1, seed)
738 }
739
740 fn generate_one(&mut self) -> Self::Item {
741 self.generate()
742 }
743
744 fn reset(&mut self) {
745 self.rng = seeded_rng(self.seed, 0);
746 self.count = 0;
747 }
748
749 fn count(&self) -> u64 {
750 self.count
751 }
752
753 fn seed(&self) -> u64 {
754 self.seed
755 }
756}
757
758#[cfg(test)]
759#[allow(clippy::unwrap_used)]
760mod tests {
761 use super::*;
762
763 #[test]
764 fn test_generate_small_coa() {
765 let mut gen =
766 ChartOfAccountsGenerator::new(CoAComplexity::Small, IndustrySector::Manufacturing, 42);
767 let coa = gen.generate();
768
769 assert!(coa.account_count() >= 50);
770 assert!(!coa.get_suspense_accounts().is_empty());
771 }
772}