sqlx_ledger/balance/
entity.rs1use chrono::{DateTime, Utc};
2use rust_decimal::Decimal;
3use serde::{Deserialize, Serialize};
4
5use crate::entry::StagedEntry;
6use crate::primitives::*;
7
8#[derive(Debug, Clone)]
10pub struct AccountBalance {
11 pub(super) balance_type: DebitOrCredit,
12 pub details: BalanceDetails,
13}
14
15impl AccountBalance {
16 pub fn pending(&self) -> Decimal {
17 if self.balance_type == DebitOrCredit::Credit {
18 self.details.pending_cr_balance - self.details.pending_dr_balance
19 } else {
20 self.details.pending_dr_balance - self.details.pending_cr_balance
21 }
22 }
23
24 pub fn settled(&self) -> Decimal {
25 if self.balance_type == DebitOrCredit::Credit {
26 self.details.settled_cr_balance - self.details.settled_dr_balance
27 } else {
28 self.details.settled_dr_balance - self.details.settled_cr_balance
29 }
30 }
31
32 pub fn encumbered(&self) -> Decimal {
33 if self.balance_type == DebitOrCredit::Credit {
34 self.details.encumbered_cr_balance - self.details.encumbered_dr_balance
35 } else {
36 self.details.encumbered_dr_balance - self.details.encumbered_cr_balance
37 }
38 }
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
44pub struct BalanceDetails {
45 pub journal_id: JournalId,
46 pub account_id: AccountId,
47 pub entry_id: EntryId,
48 pub currency: Currency,
49 pub settled_dr_balance: Decimal,
50 pub settled_cr_balance: Decimal,
51 pub settled_entry_id: EntryId,
52 pub settled_modified_at: DateTime<Utc>,
53 pub pending_dr_balance: Decimal,
54 pub pending_cr_balance: Decimal,
55 pub pending_entry_id: EntryId,
56 pub pending_modified_at: DateTime<Utc>,
57 pub encumbered_dr_balance: Decimal,
58 pub encumbered_cr_balance: Decimal,
59 pub encumbered_entry_id: EntryId,
60 pub encumbered_modified_at: DateTime<Utc>,
61 pub version: i32,
62 pub modified_at: DateTime<Utc>,
63 pub created_at: DateTime<Utc>,
64}
65
66impl BalanceDetails {
67 pub(crate) fn update(self, entry: &StagedEntry) -> Self {
68 self.update_inner(entry)
69 }
70
71 pub(crate) fn init(journal_id: JournalId, entry: &StagedEntry) -> Self {
72 Self {
73 journal_id,
74 account_id: entry.account_id,
75 entry_id: entry.entry_id,
76 currency: entry.currency,
77 settled_dr_balance: Decimal::ZERO,
78 settled_cr_balance: Decimal::ZERO,
79 settled_entry_id: entry.entry_id,
80 settled_modified_at: entry.created_at,
81 pending_dr_balance: Decimal::ZERO,
82 pending_cr_balance: Decimal::ZERO,
83 pending_entry_id: entry.entry_id,
84 pending_modified_at: entry.created_at,
85 encumbered_dr_balance: Decimal::ZERO,
86 encumbered_cr_balance: Decimal::ZERO,
87 encumbered_entry_id: entry.entry_id,
88 encumbered_modified_at: entry.created_at,
89 version: 0,
90 modified_at: entry.created_at,
91 created_at: entry.created_at,
92 }
93 .update_inner(entry)
94 }
95
96 fn update_inner(mut self, entry: &StagedEntry) -> Self {
97 self.version += 1;
98 self.modified_at = entry.created_at;
99 self.entry_id = entry.entry_id;
100 match entry.layer {
101 Layer::Settled => {
102 self.settled_entry_id = entry.entry_id;
103 self.settled_modified_at = entry.created_at;
104 match entry.direction {
105 DebitOrCredit::Debit => {
106 self.settled_dr_balance += entry.units;
107 }
108 DebitOrCredit::Credit => {
109 self.settled_cr_balance += entry.units;
110 }
111 }
112 }
113 Layer::Pending => {
114 self.pending_entry_id = entry.entry_id;
115 self.pending_modified_at = entry.created_at;
116 match entry.direction {
117 DebitOrCredit::Debit => {
118 self.pending_dr_balance += entry.units;
119 }
120 DebitOrCredit::Credit => {
121 self.pending_cr_balance += entry.units;
122 }
123 }
124 }
125 Layer::Encumbered => {
126 self.encumbered_entry_id = entry.entry_id;
127 self.encumbered_modified_at = entry.created_at;
128 match entry.direction {
129 DebitOrCredit::Debit => {
130 self.encumbered_dr_balance += entry.units;
131 }
132 DebitOrCredit::Credit => {
133 self.encumbered_cr_balance += entry.units;
134 }
135 }
136 }
137 }
138 self
139 }
140}