borutus 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +62 -64
- data/app/models/borutus/account.rb +97 -86
- data/app/models/borutus/amount.rb +9 -4
- data/app/models/borutus/amounts_extension.rb +1 -1
- data/app/services/borutus/accounts/build_running_balance_query.rb +73 -0
- data/db/migrate/20191025095830_add_borutus_amount_counter_cache.rb +15 -0
- data/lib/borutus.rb +1 -0
- data/lib/borutus/version.rb +1 -1
- data/spec/controllers/accounts_controller_spec.rb +1 -1
- data/spec/controllers/entries_controller_spec.rb +1 -1
- data/spec/controllers/reports_controller_spec.rb +1 -1
- data/spec/factories/account_factory.rb +13 -13
- data/spec/factories/amount_factory.rb +13 -13
- data/spec/factories/entry_factory.rb +11 -8
- data/spec/models/account_spec.rb +98 -53
- data/spec/models/amount_spec.rb +1 -1
- data/spec/models/entry_spec.rb +54 -50
- data/spec/models/tenancy_spec.rb +6 -6
- data/spec/routing/entries_routing_spec.rb +1 -1
- data/spec/spec_helper.rb +16 -14
- data/spec/support/account_shared_examples.rb +3 -3
- data/spec/support/amount_shared_examples.rb +1 -1
- data/spec/support/factory_bot_helpers.rb +8 -0
- metadata +44 -25
- data/spec/support/factory_girl_helpers.rb +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99c7e9b6c1428c39c6419f3899b8274f16529da5c764393c04212b322510ce32
|
4
|
+
data.tar.gz: be8481eb09396b05a8ec1c16333ed98458d76b64af964394a62705e33595ecea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa81c5a98f4dcaa9d94b644bdc6af9e29ba2dd3cc219b68b4dbe69e74de96a65f7b92991173a44b31290c3966a4a3ed10265a4ca9787a88d39ffda15358c7f34
|
7
|
+
data.tar.gz: 6261072d1a25213b31d16a6a9e99b33d4c6279e8b9ca6e271fc410df85771ad45322acef1fa4790a2700e70cfb7134b71916144ff7ac3eac8d1331ad0ebae97a
|
data/README.md
CHANGED
@@ -45,11 +45,11 @@ The Account class represents accounts in the system. The Account table uses sing
|
|
45
45
|
Your Book of Accounts needs to be created prior to recording any entries. The simplest method is to have a number of `create` methods in your db/seeds.rb file like so:
|
46
46
|
|
47
47
|
```ruby
|
48
|
-
Borutus::Asset.create(:
|
49
|
-
Borutus::Asset.create(:
|
50
|
-
Borutus::Revenue.create(:
|
51
|
-
Borutus::Liability.create(:
|
52
|
-
Borutus::Liability.create(:
|
48
|
+
Borutus::Asset.create(name: "Accounts Receivable")
|
49
|
+
Borutus::Asset.create(name: "Cash")
|
50
|
+
Borutus::Revenue.create(name: "Sales Revenue")
|
51
|
+
Borutus::Liability.create(name: "Unearned Revenue")
|
52
|
+
Borutus::Liability.create(name: "Sales Tax Payable")
|
53
53
|
```
|
54
54
|
|
55
55
|
Then simply run `rake db:seed`
|
@@ -57,7 +57,7 @@ Then simply run `rake db:seed`
|
|
57
57
|
Each account can also be marked as a "Contra Account". A contra account will have its normal balance swapped. For example, to remove equity, a "Drawing" account may be created as a contra equity account as follows:
|
58
58
|
|
59
59
|
```ruby
|
60
|
-
Borutus::Equity.create(:
|
60
|
+
Borutus::Equity.create(name: "Drawing", contra: true)
|
61
61
|
```
|
62
62
|
|
63
63
|
At all times the balance of all accounts should conform to the [Accounting
|
@@ -78,20 +78,19 @@ Recording an Entry
|
|
78
78
|
Let's assume we're accounting on an [Accrual basis](http://en.wikipedia.org/wiki/Accounting_methods#Accrual_basis). We've just taken a customer's order for some widgets, which we've also billed him for. At this point we've actually added a liability to the company until we deliver the goods. To record this entry we'd need two accounts:
|
79
79
|
|
80
80
|
```ruby
|
81
|
-
>> Borutus::Asset.create(:
|
82
|
-
>> Borutus::Liability.create(:
|
81
|
+
>> Borutus::Asset.create(name: "Cash")
|
82
|
+
>> Borutus::Liability.create(name: "Unearned Revenue")
|
83
83
|
```
|
84
84
|
|
85
85
|
Next we'll build the entry we want to record. Borutus uses ActiveRecord conventions to build the transaction and its associated amounts.
|
86
86
|
|
87
87
|
```ruby
|
88
88
|
entry = Borutus::Entry.new(
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
{:account_name => "Unearned Revenue", :amount => 100.00}])
|
89
|
+
description: "Order placed for widgets",
|
90
|
+
date: Date.yesterday,
|
91
|
+
debits: [{ account_name: "Cash", amount: 100.00 }],
|
92
|
+
credits: [{ account_name: "Unearned Revenue", amount: 100.00 }]
|
93
|
+
)
|
95
94
|
```
|
96
95
|
|
97
96
|
Entries must specify a description, as well as at least one credit and debit amount. Specifying the date is optional; by default, the current date will be assigned to the entry before the record is saved. `debits` and `credits` must specify an array of hashes, with an amount value as well as an account, either by providing a `Borutus::Account` to `account` or by passing in an `account_name` string.
|
@@ -110,21 +109,22 @@ Recording an Entry with multiple accounts
|
|
110
109
|
Often times a single entry requires more than one type of account. A classic example would be a entry in which a tax is charged. We'll assume that we have not yet received payment for the order, so we'll need an "Accounts Receivable" Asset:
|
111
110
|
|
112
111
|
```ruby
|
113
|
-
>> Borutus::Asset.create(:
|
114
|
-
>> Borutus::Revenue.create(:
|
115
|
-
>> Borutus::Liability.create(:
|
112
|
+
>> Borutus::Asset.create(name: "Accounts Receivable")
|
113
|
+
>> Borutus::Revenue.create(name: "Sales Revenue")
|
114
|
+
>> Borutus::Liability.create(name: "Sales Tax Payable")
|
116
115
|
```
|
117
116
|
|
118
117
|
And here's the entry:
|
119
118
|
|
120
119
|
```ruby
|
121
120
|
entry = Borutus::Entry.build(
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
121
|
+
description: "Sold some widgets",
|
122
|
+
debits: [{ account_name: "Accounts Receivable", :amount: 50}],
|
123
|
+
credits: [
|
124
|
+
{ account_name: "Sales Revenue", amount: 45},
|
125
|
+
{ account_name: "Sales Tax Payable", amount: 5}
|
126
|
+
]
|
127
|
+
)
|
128
128
|
entry.save
|
129
129
|
```
|
130
130
|
|
@@ -143,13 +143,13 @@ Let's assume we're using the same entry from the last example
|
|
143
143
|
|
144
144
|
```ruby
|
145
145
|
entry = Borutus::Entry.new(
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
146
|
+
description: "Sold some widgets",
|
147
|
+
commercial_document: invoice,
|
148
|
+
debits: [
|
149
|
+
{ account_name: "Accounts Receivable", amount: invoice.total_amount}],
|
150
|
+
credits: [
|
151
|
+
{ account_name: "Sales Revenue", amount: invoice.sales_amount},
|
152
|
+
{ account_name: "Sales Tax Payable", amount: invoice.tax_amount}])
|
153
153
|
entry.save
|
154
154
|
```
|
155
155
|
|
@@ -170,7 +170,7 @@ The balance can also be calculated within a specified date range. Dates can be s
|
|
170
170
|
|
171
171
|
```ruby
|
172
172
|
>> cash = Borutus::Asset.find_by_name("Cash")
|
173
|
-
>> cash.balance(:
|
173
|
+
>> cash.balance(from_date: "2014-01-01", to_date: Date.today)
|
174
174
|
=> #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
175
175
|
```
|
176
176
|
|
@@ -187,7 +187,7 @@ Each subclass of accounts can report on the total balance of all the accounts of
|
|
187
187
|
Again, a date range can be given
|
188
188
|
|
189
189
|
```ruby
|
190
|
-
>> Borutus::Asset.balance(:
|
190
|
+
>> Borutus::Asset.balance(from_date: "2014-01-01", to_date: Date.today)
|
191
191
|
=> #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
192
192
|
```
|
193
193
|
|
@@ -211,38 +211,36 @@ For complex entries, you should always ensure that you are balancing your accoun
|
|
211
211
|
For example, let's assume the owner of a business wants to withdraw cash. First we'll assume that we have an asset account for "Cash" which the funds will be drawn from. We'll then need an Equity account to record where the funds are going, however, in this case, we can't simply create a regular Equity account. The "Cash" account must be credited for the decrease in its balance since it's an Asset. Likewise, Equity accounts are typically credited when there is an increase in their balance. Equity is considered an owner's rights to Assets in the business. In this case however, we are not simply increasing the owner's rights to assets within the business; we are actually removing capital from the business altogether. Hence both sides of our accounting equation will see a decrease. In order to accomplish this, we need to create a Contra-Equity account we'll call "Drawings". Since Equity accounts normally have credit balances, a Contra-Equity account will have a debit balance, which is what we need for our entry.
|
212
212
|
|
213
213
|
```ruby
|
214
|
-
>> Borutus::Equity.create(:
|
215
|
-
>> Borutus::Asset.create(:
|
214
|
+
>> Borutus::Equity.create(name: "Drawing", contra: true)
|
215
|
+
>> Borutus::Asset.create(name: "Cash")
|
216
216
|
```
|
217
217
|
|
218
218
|
We would then create the following entry:
|
219
219
|
|
220
220
|
```ruby
|
221
221
|
entry = Borutus::Entry.new(
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
{:account_name => "Cash", :amount => 1000}])
|
222
|
+
description: "Owner withdrawing cash",
|
223
|
+
debits: [{ account_name: "Drawing", amount: 1000}],
|
224
|
+
credits: [{ account_name: "Cash", amount: 1000}],
|
225
|
+
)
|
227
226
|
entry.save
|
228
227
|
```
|
229
228
|
|
230
229
|
To make the example clearer, imagine instead that the owner decides to invest his money into the business in exchange for some type of equity security. In this case we might have the following accounts:
|
231
230
|
|
232
231
|
```ruby
|
233
|
-
>> Borutus::Equity.create(:
|
234
|
-
>> Borutus::Asset.create(:
|
232
|
+
>> Borutus::Equity.create(name: "Common Stock")
|
233
|
+
>> Borutus::Asset.create(name: "Cash")
|
235
234
|
```
|
236
235
|
|
237
236
|
And out entry would be:
|
238
237
|
|
239
238
|
```ruby
|
240
239
|
entry = Borutus::Entry.new(
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
{:account_name => "Common Stock", :amount => 1000}])
|
240
|
+
description: "Owner investing cash",
|
241
|
+
debits: [{ account_name: "Cash", amount: 1000}],
|
242
|
+
credits: [{ account_name: "Common Stock", amount: 1000}]
|
243
|
+
)
|
246
244
|
entry.save
|
247
245
|
```
|
248
246
|
|
@@ -252,17 +250,16 @@ Equity, keeping everything balanced.
|
|
252
250
|
Money & Currency Support
|
253
251
|
========================
|
254
252
|
|
255
|
-
Borutus aims to be agnostic about the values used for amounts. All fields are maintained as BigDecimal values, with `:precision
|
253
|
+
Borutus aims to be agnostic about the values used for amounts. All fields are maintained as BigDecimal values, with `:precision: 20, :scale: 10`, which means that any currency can be safely stored in the tables.
|
256
254
|
|
257
255
|
Borutus is also compatible with the [Money](https://github.com/RubyMoney/money) gem. With Money versions greater than 6.0, the `money.amount` will returns a BigDecimal which you can use with borutus as follows:
|
258
256
|
|
259
257
|
```ruby
|
260
258
|
entry = Borutus::Entry.build(
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
{:account_name => "Unearned Revenue", :amount => money.amount}])
|
259
|
+
description: "Order placed for widgets",
|
260
|
+
debits: [{ account_name: "Cash", amount: money.amount}],
|
261
|
+
credits: [{ account_name: "Unearned Revenue", amount: money.amount}]
|
262
|
+
)
|
266
263
|
```
|
267
264
|
|
268
265
|
Multitenancy Support
|
@@ -295,15 +292,14 @@ end
|
|
295
292
|
|
296
293
|
|
297
294
|
```ruby
|
298
|
-
debit_account = Borutus::Account.where(:
|
299
|
-
credit_account = Borutus::Account.where(:
|
295
|
+
debit_account = Borutus::Account.where(name: "Cash", tenant: my_tenant).last
|
296
|
+
credit_account = Borutus::Account.where(name: "Unearned Revenue", tenant: my_tenant).last
|
300
297
|
entry = Borutus::Entry.new(
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
{:account => credit_account, :amount => 100.00}])
|
298
|
+
description: "Order placed for widgets",
|
299
|
+
date: Date.yesterday,
|
300
|
+
debits: [{ account: debit_account, amount: 100.00}],
|
301
|
+
credits: [{ account: credit_account, amount: 100.00}]
|
302
|
+
)
|
307
303
|
```
|
308
304
|
|
309
305
|
Reporting Views
|
@@ -316,7 +312,7 @@ These views and controllers are read-only for reporting purposes. It is assumed
|
|
316
312
|
Routing is supplied via an engine mount point. Borutus can be mounted on a subpath in your existing Rails 3 app by adding the following to your routes.rb:
|
317
313
|
|
318
314
|
```ruby
|
319
|
-
mount Borutus::Engine => "/borutus", :
|
315
|
+
mount Borutus::Engine => "/borutus", as: "borutus"
|
320
316
|
```
|
321
317
|
|
322
318
|
*NOTE: The `Borutus::ApplicationController` does not currently support authentication. If you enable routing, the views will be publicly available on your mount point. Authentication can be added by overriding the controller.*
|
@@ -326,7 +322,11 @@ mount Borutus::Engine => "/borutus", :as => "borutus"
|
|
326
322
|
Testing
|
327
323
|
=======
|
328
324
|
|
329
|
-
Run `docker-compose up pg`, this will create a local postgresql database. Then create a DB name `borutus_fixture_test`, you can do this via
|
325
|
+
Run `docker-compose up pg`, this will create a local postgresql database. Then create a DB name `borutus_fixture_test`, you can do this via:
|
326
|
+
|
327
|
+
```bash
|
328
|
+
createdb --username=postgres --host=localhost --port=5432 --template=template0 borutus_fixture_test
|
329
|
+
```
|
330
330
|
|
331
331
|
[Rspec](http://rspec.info/) tests are provided. Run `bundle install` then `bundle exec rspec spec`.
|
332
332
|
|
@@ -339,11 +339,9 @@ Many thanks to all our contributors! Check them all at:
|
|
339
339
|
|
340
340
|
https://github.com/bloom-solutions/borutus/graphs/contributors
|
341
341
|
|
342
|
-
|
343
342
|
Reference
|
344
343
|
=========
|
345
344
|
|
346
345
|
For a complete reference on Accounting principles, we recommend the following textbook
|
347
346
|
|
348
347
|
[http://amzn.com/0324662963](http://amzn.com/0324662963)
|
349
|
-
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module Borutus
|
2
|
-
# The Account class represents accounts in the system. Each account must be
|
2
|
+
# The Account class represents accounts in the system. Each account must be
|
3
|
+
# subclassed as one of the following types:
|
3
4
|
#
|
4
5
|
# TYPE | NORMAL BALANCE | DESCRIPTION
|
5
6
|
# --------------------------------------------------------------------------
|
@@ -7,74 +8,73 @@ module Borutus
|
|
7
8
|
# Liability | Credit | Debts owed to outsiders
|
8
9
|
# Equity | Credit | Owners rights to the Assets
|
9
10
|
# Revenue | Credit | Increases in owners equity
|
10
|
-
# Expense | Debit | Assets or services consumed in the
|
11
|
+
# Expense | Debit | Assets or services consumed in the
|
12
|
+
# generation of revenue
|
11
13
|
#
|
12
|
-
# Each account can also be marked as a "Contra Account". A contra account
|
13
|
-
# normal balance swapped. For example, to remove equity, a
|
14
|
+
# Each account can also be marked as a "Contra Account". A contra account
|
15
|
+
# will have it's normal balance swapped. For example, to remove equity, a
|
16
|
+
# "Drawing" account may be created
|
14
17
|
# as a contra equity account as follows:
|
15
18
|
#
|
16
|
-
# Borutus::Equity.create(:
|
19
|
+
# Borutus::Equity.create(name: "Drawing", contra: true)
|
17
20
|
#
|
18
|
-
# At all times the balance of all accounts should conform to the
|
19
|
-
#
|
21
|
+
# At all times the balance of all accounts should conform to the
|
22
|
+
# "accounting equation" Borutus::Assets = Liabilties + Owner's Equity
|
20
23
|
#
|
21
|
-
# Each sublclass account acts as it's own ledger. See the individual
|
22
|
-
# description.
|
24
|
+
# Each sublclass account acts as it's own ledger. See the individual
|
25
|
+
# subclasses for a description.
|
23
26
|
#
|
24
27
|
# @abstract
|
25
|
-
# An account must be a subclass to be saved to the database. The Account
|
26
|
-
# has a singleton method {trial_balance} to calculate the balance
|
28
|
+
# An account must be a subclass to be saved to the database. The Account
|
29
|
+
# class has a singleton method {trial_balance} to calculate the balance
|
30
|
+
# on all Accounts.
|
27
31
|
#
|
28
32
|
# @see http://en.wikipedia.org/wiki/Accounting_equation Accounting Equation
|
29
|
-
# @see http://en.wikipedia.org/wiki/Debits_and_credits Debits, Credits, and
|
33
|
+
# @see http://en.wikipedia.org/wiki/Debits_and_credits Debits, Credits, and
|
34
|
+
# Contra Accounts
|
30
35
|
#
|
31
36
|
# @author Michael Bulat
|
32
37
|
class Account < ActiveRecord::Base
|
38
|
+
|
33
39
|
class_attribute :normal_credit_balance
|
34
40
|
|
35
41
|
has_many :amounts
|
36
|
-
has_many
|
37
|
-
|
42
|
+
has_many(:credit_amounts, {
|
43
|
+
extend: AmountsExtension,
|
44
|
+
class_name: "Borutus::CreditAmount",
|
45
|
+
})
|
46
|
+
has_many(:debit_amounts, {
|
47
|
+
extend: AmountsExtension,
|
48
|
+
class_name: "Borutus::DebitAmount",
|
49
|
+
})
|
38
50
|
has_many :entries, through: :amounts, source: :entry do
|
39
51
|
def with_running_balance
|
40
52
|
account = proxy_association.owner
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
:entry_id,
|
47
|
-
%{ SUM("borutus_amounts".amount) AS amount }
|
48
|
-
).group(:entry_id, :id)
|
49
|
-
|
50
|
-
debit_table = debit_amounts.joins(:entry).select(
|
51
|
-
:id,
|
52
|
-
:entry_id,
|
53
|
-
%{ SUM("borutus_amounts".amount) AS amount }
|
54
|
-
).group(:entry_id, :id)
|
55
|
-
|
56
|
-
sum_statement = if account.normal_credit_balance
|
57
|
-
%{ COALESCE("credit_table"."amount", 0) - COALESCE("debit_table"."amount", 0) }
|
58
|
-
else
|
59
|
-
%{ COALESCE("debit_table"."amount", 0) - COALESCE("credit_table"."amount", 0) }
|
60
|
-
end
|
61
|
-
|
62
|
-
joins(%{
|
63
|
-
LEFT OUTER JOIN (#{credit_table.to_sql}) AS "credit_table" ON "credit_table".entry_id = "borutus_entries".id
|
64
|
-
LEFT OUTER JOIN (#{debit_table.to_sql}) AS "debit_table" ON "debit_table".entry_id = "borutus_entries".id
|
65
|
-
}).select(%{
|
66
|
-
"borutus_entries".*,
|
67
|
-
SUM(#{sum_statement}) OVER(ORDER BY "borutus_entries"."created_at") AS balance,
|
68
|
-
#{sum_statement} AS change_amount
|
69
|
-
}).group(:id, %{ "debit_table".amount, "credit_table".amount })
|
53
|
+
result = Accounts::BuildRunningBalanceQuery.execute(account: account)
|
54
|
+
|
55
|
+
joins(result.joins_statement)
|
56
|
+
.select(result.select_statement)
|
57
|
+
.group(result.group_statement)
|
70
58
|
.order(created_at: :asc)
|
71
59
|
end
|
72
60
|
end
|
73
|
-
has_many
|
74
|
-
|
61
|
+
has_many(:credit_entries, {
|
62
|
+
through: :credit_amounts,
|
63
|
+
source: :entry,
|
64
|
+
class_name: "Borutus::Entry",
|
65
|
+
})
|
66
|
+
has_many(:debit_entries, {
|
67
|
+
through: :debit_amounts,
|
68
|
+
source: :entry,
|
69
|
+
class_name: "Borutus::Entry",
|
70
|
+
})
|
75
71
|
|
76
72
|
validates_presence_of :type
|
77
73
|
|
74
|
+
scope :with_amounts, -> do
|
75
|
+
where("borutus_amounts_count > 0")
|
76
|
+
end
|
77
|
+
|
78
78
|
def self.types
|
79
79
|
[
|
80
80
|
::Borutus::Asset,
|
@@ -94,14 +94,17 @@ module Borutus
|
|
94
94
|
# The balance of the account. This instance method is intended for use only
|
95
95
|
# on instances of account subclasses.
|
96
96
|
#
|
97
|
-
# If the account has a normal credit balance, the debits are subtracted
|
98
|
-
# unless this is a contra account, in which case credits
|
97
|
+
# If the account has a normal credit balance, the debits are subtracted
|
98
|
+
# from the credits unless this is a contra account, in which case credits
|
99
|
+
# are substracted from debits.
|
99
100
|
#
|
100
101
|
# For a normal debit balance, the credits are subtracted from the debits
|
101
|
-
# unless this is a contra account, in which case debits are subtracted from
|
102
|
+
# unless this is a contra account, in which case debits are subtracted from
|
103
|
+
# credits.
|
102
104
|
#
|
103
|
-
# Takes an optional hash specifying :from_date and :to_date for
|
104
|
-
# :from_date and :to_date may be
|
105
|
+
# Takes an optional hash specifying :from_date and :to_date for
|
106
|
+
# calculating balances during periods. # :from_date and :to_date may be
|
107
|
+
# strings of the form "yyyy-mm-dd" or Ruby Date objects
|
105
108
|
#
|
106
109
|
# @example
|
107
110
|
# >> liability.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
@@ -112,25 +115,26 @@ module Borutus
|
|
112
115
|
# => #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
113
116
|
#
|
114
117
|
# @return [BigDecimal] The decimal value balance
|
115
|
-
def balance(options={})
|
118
|
+
def balance(options = {})
|
116
119
|
if self.class == Borutus::Account
|
117
|
-
raise
|
120
|
+
raise NoMethodError, "undefined method 'balance'"
|
121
|
+
end
|
122
|
+
|
123
|
+
if normal_credit_balance ^ contra
|
124
|
+
credits_balance(options) - debits_balance(options)
|
118
125
|
else
|
119
|
-
|
120
|
-
credits_balance(options) - debits_balance(options)
|
121
|
-
else
|
122
|
-
debits_balance(options) - credits_balance(options)
|
123
|
-
end
|
126
|
+
debits_balance(options) - credits_balance(options)
|
124
127
|
end
|
125
128
|
end
|
126
129
|
|
127
130
|
# The credit balance for the account.
|
128
131
|
#
|
129
|
-
# Takes an optional hash specifying :from_date and :to_date for calculating
|
130
|
-
# :from_date and :to_date may be strings of the
|
132
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating
|
133
|
+
# balances during periods. :from_date and :to_date may be strings of the
|
134
|
+
# form "yyyy-mm-dd" or Ruby Date objects
|
131
135
|
#
|
132
136
|
# @example
|
133
|
-
# >> asset.credits_balance({:
|
137
|
+
# >> asset.credits_balance({from_date: "2000-01-01", to_date: Date.today})
|
134
138
|
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
135
139
|
#
|
136
140
|
# @example
|
@@ -138,17 +142,18 @@ module Borutus
|
|
138
142
|
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
139
143
|
#
|
140
144
|
# @return [BigDecimal] The decimal value credit balance
|
141
|
-
def credits_balance(options={})
|
145
|
+
def credits_balance(options = {})
|
142
146
|
credit_amounts.balance(options)
|
143
147
|
end
|
144
148
|
|
145
149
|
# The debit balance for the account.
|
146
150
|
#
|
147
|
-
# Takes an optional hash specifying :from_date and :to_date for calculating
|
148
|
-
# :from_date and :to_date may be strings of the
|
151
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating
|
152
|
+
# balances during periods. :from_date and :to_date may be strings of the
|
153
|
+
# form "yyyy-mm-dd" or Ruby Date objects
|
149
154
|
#
|
150
155
|
# @example
|
151
|
-
# >> asset.debits_balance({:
|
156
|
+
# >> asset.debits_balance({ from_date: "2000-01-01", to_date: Date.today})
|
152
157
|
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
153
158
|
#
|
154
159
|
# @example
|
@@ -156,7 +161,7 @@ module Borutus
|
|
156
161
|
# => #<BigDecimal:103259bb8,'0.3E4',4(12)>
|
157
162
|
#
|
158
163
|
# @return [BigDecimal] The decimal value credit balance
|
159
|
-
def debits_balance(options={})
|
164
|
+
def debits_balance(options = {})
|
160
165
|
debit_amounts.balance(options)
|
161
166
|
end
|
162
167
|
|
@@ -165,11 +170,12 @@ module Borutus
|
|
165
170
|
#
|
166
171
|
# Contra accounts are automatically subtracted from the balance.
|
167
172
|
#
|
168
|
-
# Takes an optional hash specifying :from_date and :to_date for
|
169
|
-
# :from_date and :to_date may be
|
173
|
+
# Takes an optional hash specifying :from_date and :to_date for
|
174
|
+
# calculating balances during periods. :from_date and :to_date may be
|
175
|
+
# strings of the form "yyyy-mm-dd" or Ruby Date objects
|
170
176
|
#
|
171
177
|
# @example
|
172
|
-
# >> Borutus::Liability.balance({:
|
178
|
+
# >> Borutus::Liability.balance({from_date: "2000-01-01", to_date: Date.today})
|
173
179
|
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
174
180
|
#
|
175
181
|
# @example
|
@@ -177,25 +183,25 @@ module Borutus
|
|
177
183
|
# => #<BigDecimal:1030fcc98,'0.82875E5',8(20)>
|
178
184
|
#
|
179
185
|
# @return [BigDecimal] The decimal value balance
|
180
|
-
def self.balance(options={})
|
181
|
-
if
|
186
|
+
def self.balance(options = {})
|
187
|
+
if new.class == Borutus::Account
|
182
188
|
raise(NoMethodError, "undefined method 'balance'")
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
189
|
+
end
|
190
|
+
|
191
|
+
accounts_balance = BigDecimal("0")
|
192
|
+
accounts = all
|
193
|
+
accounts.each do |account|
|
194
|
+
if account.contra
|
195
|
+
accounts_balance -= account.balance(options)
|
196
|
+
else
|
197
|
+
accounts_balance += account.balance(options)
|
192
198
|
end
|
193
|
-
accounts_balance
|
194
199
|
end
|
200
|
+
accounts_balance
|
195
201
|
end
|
196
202
|
|
197
|
-
# The trial balance of all accounts in the system. This should always
|
198
|
-
# otherwise there is an error in the system.
|
203
|
+
# The trial balance of all accounts in the system. This should always
|
204
|
+
# equal zero, otherwise there is an error in the system.
|
199
205
|
#
|
200
206
|
# @example
|
201
207
|
# >> Account.trial_balance.to_i
|
@@ -203,11 +209,16 @@ module Borutus
|
|
203
209
|
#
|
204
210
|
# @return [BigDecimal] The decimal value balance of all accounts
|
205
211
|
def self.trial_balance
|
206
|
-
if
|
207
|
-
|
208
|
-
else
|
209
|
-
raise(NoMethodError, "undefined method 'trial_balance'")
|
212
|
+
if new.class != Borutus::Account
|
213
|
+
raise NoMethodError, "undefined method 'trial_balance'"
|
210
214
|
end
|
215
|
+
|
216
|
+
Borutus::Asset.balance - (
|
217
|
+
Borutus::Liability.balance +
|
218
|
+
Borutus::Equity.balance +
|
219
|
+
Borutus::Revenue.balance -
|
220
|
+
Borutus::Expense.balance
|
221
|
+
)
|
211
222
|
end
|
212
223
|
|
213
224
|
end
|