datasynth_generators/period_close/
dividend_generator.rs1use chrono::NaiveDate;
8use datasynth_core::accounts::{cash_accounts, dividend_accounts, equity_accounts};
9use datasynth_core::models::{DividendDeclaration, JournalEntry, JournalEntryLine};
10use datasynth_core::utils::seeded_rng;
11use datasynth_core::uuid_factory::{DeterministicUuidFactory, GeneratorType};
12use rand_chacha::ChaCha8Rng;
13use rust_decimal::Decimal;
14
15pub struct DividendResult {
17 pub declarations: Vec<DividendDeclaration>,
19 pub journal_entries: Vec<JournalEntry>,
21}
22
23pub struct DividendGenerator {
25 #[allow(dead_code)]
27 rng: ChaCha8Rng,
28 uuid_factory: DeterministicUuidFactory,
29}
30
31impl DividendGenerator {
32 pub fn new(seed: u64) -> Self {
34 Self {
35 rng: seeded_rng(seed, 0),
36 uuid_factory: DeterministicUuidFactory::new(seed, GeneratorType::PeriodClose),
37 }
38 }
39
40 pub fn generate(
49 &mut self,
50 entity_code: &str,
51 declaration_date: NaiveDate,
52 per_share_amount: Decimal,
53 total_amount: Decimal,
54 currency: &str,
55 ) -> DividendResult {
56 let id = self.uuid_factory.next().to_string();
57
58 let record_date = declaration_date + chrono::Duration::days(14);
59 let payment_date = record_date + chrono::Duration::days(30);
60
61 let declaration = DividendDeclaration {
62 id: id.clone(),
63 entity_code: entity_code.to_string(),
64 declaration_date,
65 record_date,
66 payment_date,
67 per_share_amount,
68 total_amount,
69 currency: currency.to_string(),
70 };
71
72 let decl_doc_id = format!("JE-DIV-DECL-{id}");
75 let mut decl_je = JournalEntry::new_simple(
76 decl_doc_id,
77 entity_code.to_string(),
78 declaration_date,
79 format!("Dividend declaration – {entity_code}"),
80 );
81 decl_je.add_line(JournalEntryLine {
82 line_number: 1,
83 gl_account: equity_accounts::RETAINED_EARNINGS.to_string(),
84 debit_amount: total_amount,
85 credit_amount: Decimal::ZERO,
86 reference: Some(id.clone()),
87 ..Default::default()
88 });
89 decl_je.add_line(JournalEntryLine {
90 line_number: 2,
91 gl_account: dividend_accounts::DIVIDENDS_PAYABLE.to_string(),
92 debit_amount: Decimal::ZERO,
93 credit_amount: total_amount,
94 reference: Some(id.clone()),
95 ..Default::default()
96 });
97
98 let pay_doc_id = format!("JE-DIV-PAY-{id}");
101 let mut pay_je = JournalEntry::new_simple(
102 pay_doc_id,
103 entity_code.to_string(),
104 payment_date,
105 format!("Dividend payment – {entity_code}"),
106 );
107 pay_je.add_line(JournalEntryLine {
108 line_number: 1,
109 gl_account: dividend_accounts::DIVIDENDS_PAYABLE.to_string(),
110 debit_amount: total_amount,
111 credit_amount: Decimal::ZERO,
112 reference: Some(id.clone()),
113 ..Default::default()
114 });
115 pay_je.add_line(JournalEntryLine {
116 line_number: 2,
117 gl_account: cash_accounts::OPERATING_CASH.to_string(),
118 debit_amount: Decimal::ZERO,
119 credit_amount: total_amount,
120 reference: Some(id.clone()),
121 ..Default::default()
122 });
123
124 DividendResult {
125 declarations: vec![declaration],
126 journal_entries: vec![decl_je, pay_je],
127 }
128 }
129}