borutus 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +346 -0
- data/Rakefile +11 -0
- data/app/assets/javascripts/borutus/application.js +16 -0
- data/app/assets/javascripts/borutus/reports.js +5 -0
- data/app/assets/stylesheets/bootstrap-theme.min.css +5 -0
- data/app/assets/stylesheets/bootstrap.min.css +5 -0
- data/app/assets/stylesheets/borutus/application.css +19 -0
- data/app/controllers/borutus/accounts_controller.rb +30 -0
- data/app/controllers/borutus/application_controller.rb +4 -0
- data/app/controllers/borutus/entries_controller.rb +34 -0
- data/app/controllers/borutus/reports_controller.rb +40 -0
- data/app/models/borutus/account.rb +180 -0
- data/app/models/borutus/amount.rb +24 -0
- data/app/models/borutus/amounts_extension.rb +42 -0
- data/app/models/borutus/asset.rb +56 -0
- data/app/models/borutus/credit_amount.rb +10 -0
- data/app/models/borutus/debit_amount.rb +10 -0
- data/app/models/borutus/entry.rb +77 -0
- data/app/models/borutus/equity.rb +56 -0
- data/app/models/borutus/expense.rb +56 -0
- data/app/models/borutus/liability.rb +56 -0
- data/app/models/borutus/no_tenancy.rb +9 -0
- data/app/models/borutus/revenue.rb +56 -0
- data/app/models/borutus/tenancy.rb +15 -0
- data/app/views/borutus/accounts/index.html.erb +26 -0
- data/app/views/borutus/entries/index.html.erb +59 -0
- data/app/views/borutus/reports/_account.html.erb +28 -0
- data/app/views/borutus/reports/balance_sheet.html.erb +21 -0
- data/app/views/borutus/reports/income_statement.html.erb +24 -0
- data/app/views/layouts/borutus/_messages.html.erb +9 -0
- data/app/views/layouts/borutus/_navigation.html.erb +19 -0
- data/app/views/layouts/borutus/_navigation_links.html.erb +5 -0
- data/app/views/layouts/borutus/application.html.erb +19 -0
- data/config/backtrace_silencers.rb +7 -0
- data/config/database.yml +5 -0
- data/config/inflections.rb +10 -0
- data/config/mime_types.rb +5 -0
- data/config/routes.rb +9 -0
- data/config/secret_token.rb +7 -0
- data/config/session_store.rb +8 -0
- data/db/migrate/20160422010135_create_borutus_tables.rb +33 -0
- data/lib/borutus.rb +20 -0
- data/lib/borutus/engine.rb +5 -0
- data/lib/borutus/version.rb +3 -0
- data/lib/generators/borutus/USAGE +13 -0
- data/lib/generators/borutus/add_date_upgrade_generator.rb +11 -0
- data/lib/generators/borutus/base_generator.rb +19 -0
- data/lib/generators/borutus/borutus_generator.rb +12 -0
- data/lib/generators/borutus/templates/tenant_migration.rb +6 -0
- data/lib/generators/borutus/tenancy_generator.rb +12 -0
- data/lib/generators/borutus/upgrade_borutus_generator.rb +12 -0
- data/spec/controllers/accounts_controller_spec.rb +19 -0
- data/spec/controllers/entries_controller_spec.rb +19 -0
- data/spec/controllers/reports_controller_spec.rb +24 -0
- data/spec/factories/account_factory.rb +35 -0
- data/spec/factories/amount_factory.rb +19 -0
- data/spec/factories/entry_factory.rb +11 -0
- data/spec/lib/borutus_spec.rb +0 -0
- data/spec/models/account_spec.rb +140 -0
- data/spec/models/amount_spec.rb +13 -0
- data/spec/models/asset_spec.rb +7 -0
- data/spec/models/credit_amount_spec.rb +7 -0
- data/spec/models/debit_amount_spec.rb +7 -0
- data/spec/models/entry_spec.rb +170 -0
- data/spec/models/equity_spec.rb +7 -0
- data/spec/models/expense_spec.rb +7 -0
- data/spec/models/liability_spec.rb +7 -0
- data/spec/models/revenue_spec.rb +7 -0
- data/spec/models/tenancy_spec.rb +45 -0
- data/spec/rcov.opts +2 -0
- data/spec/routing/accounts_routing_spec.rb +13 -0
- data/spec/routing/entries_routing_spec.rb +13 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/support/account_shared_examples.rb +60 -0
- data/spec/support/active_support_helpers.rb +13 -0
- data/spec/support/amount_shared_examples.rb +21 -0
- data/spec/support/factory_girl_helpers.rb +8 -0
- data/spec/support/shoulda_matchers.rb +8 -0
- metadata +243 -0
@@ -0,0 +1,34 @@
|
|
1
|
+
module Borutus
|
2
|
+
# This controller provides restful route handling for Entries.
|
3
|
+
#
|
4
|
+
# The controller supports ActiveResource, and provides for
|
5
|
+
# HMTL, XML, and JSON presentation.
|
6
|
+
#
|
7
|
+
# == Security:
|
8
|
+
# Only GET requests are supported. You should ensure that your application
|
9
|
+
# controller enforces its own authentication and authorization, which this
|
10
|
+
# controller will inherit.
|
11
|
+
#
|
12
|
+
# @author Michael Bulat
|
13
|
+
class EntriesController < Borutus::ApplicationController
|
14
|
+
unloadable
|
15
|
+
# @example
|
16
|
+
# GET /entries
|
17
|
+
# GET /entries.xml
|
18
|
+
# GET /entries.json
|
19
|
+
def index
|
20
|
+
if params[:order] == 'ascending'
|
21
|
+
order = 'ASC'
|
22
|
+
else
|
23
|
+
order = 'DESC'
|
24
|
+
end
|
25
|
+
@entries = Entry.page(params[:page]).per(params[:limit]).order("date #{order}")
|
26
|
+
|
27
|
+
respond_to do |format|
|
28
|
+
format.html # index.html.erb
|
29
|
+
format.xml { render :xml => @entries }
|
30
|
+
format.json { render :json => @entries }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Borutus
|
2
|
+
# == Security:
|
3
|
+
# Only GET requests are supported. You should ensure that your application
|
4
|
+
# controller enforces its own authentication and authorization, which this
|
5
|
+
# controller will inherit.
|
6
|
+
#
|
7
|
+
# @author Michael Bulat
|
8
|
+
class ReportsController < ::Borutus::ApplicationController
|
9
|
+
unloadable
|
10
|
+
|
11
|
+
# @example
|
12
|
+
# GET /reports/balance_sheet
|
13
|
+
def balance_sheet
|
14
|
+
first_entry = Borutus::Entry.order('date ASC').first
|
15
|
+
@from_date = first_entry ? first_entry.date: Date.today
|
16
|
+
@to_date = params[:date] ? Date.parse(params[:date]) : Date.today
|
17
|
+
@assets = Borutus::Asset.all
|
18
|
+
@liabilities = Borutus::Liability.all
|
19
|
+
@equity = Borutus::Equity.all
|
20
|
+
|
21
|
+
respond_to do |format|
|
22
|
+
format.html # index.html.erb
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @example
|
27
|
+
# GET /reports/income_statement
|
28
|
+
def income_statement
|
29
|
+
@from_date = params[:from_date] ? Date.parse(params[:from_date]) : Date.today.at_beginning_of_month
|
30
|
+
@to_date = params[:to_date] ? Date.parse(params[:to_date]) : Date.today
|
31
|
+
@revenues = Borutus::Revenue.all
|
32
|
+
@expenses = Borutus::Expense.all
|
33
|
+
|
34
|
+
respond_to do |format|
|
35
|
+
format.html # index.html.erb
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
module Borutus
|
2
|
+
# The Account class represents accounts in the system. Each account must be subclassed as one of the following types:
|
3
|
+
#
|
4
|
+
# TYPE | NORMAL BALANCE | DESCRIPTION
|
5
|
+
# --------------------------------------------------------------------------
|
6
|
+
# Asset | Debit | Resources owned by the Business Entity
|
7
|
+
# Liability | Credit | Debts owed to outsiders
|
8
|
+
# Equity | Credit | Owners rights to the Assets
|
9
|
+
# Revenue | Credit | Increases in owners equity
|
10
|
+
# Expense | Debit | Assets or services consumed in the generation of revenue
|
11
|
+
#
|
12
|
+
# Each account can also be marked as a "Contra Account". A contra account will have it's
|
13
|
+
# normal balance swapped. For example, to remove equity, a "Drawing" account may be created
|
14
|
+
# as a contra equity account as follows:
|
15
|
+
#
|
16
|
+
# Borutus::Equity.create(:name => "Drawing", contra => true)
|
17
|
+
#
|
18
|
+
# At all times the balance of all accounts should conform to the "accounting equation"
|
19
|
+
# Borutus::Assets = Liabilties + Owner's Equity
|
20
|
+
#
|
21
|
+
# Each sublclass account acts as it's own ledger. See the individual subclasses for a
|
22
|
+
# description.
|
23
|
+
#
|
24
|
+
# @abstract
|
25
|
+
# An account must be a subclass to be saved to the database. The Account class
|
26
|
+
# has a singleton method {trial_balance} to calculate the balance on all Accounts.
|
27
|
+
#
|
28
|
+
# @see http://en.wikipedia.org/wiki/Accounting_equation Accounting Equation
|
29
|
+
# @see http://en.wikipedia.org/wiki/Debits_and_credits Debits, Credits, and Contra Accounts
|
30
|
+
#
|
31
|
+
# @author Michael Bulat
|
32
|
+
class Account < ActiveRecord::Base
|
33
|
+
class_attribute :normal_credit_balance
|
34
|
+
|
35
|
+
has_many :amounts
|
36
|
+
has_many :credit_amounts, :extend => AmountsExtension, :class_name => 'Borutus::CreditAmount'
|
37
|
+
has_many :debit_amounts, :extend => AmountsExtension, :class_name => 'Borutus::DebitAmount'
|
38
|
+
has_many :entries, through: :amounts, source: :entry
|
39
|
+
has_many :credit_entries, :through => :credit_amounts, :source => :entry, :class_name => 'Borutus::Entry'
|
40
|
+
has_many :debit_entries, :through => :debit_amounts, :source => :entry, :class_name => 'Borutus::Entry'
|
41
|
+
|
42
|
+
validates_presence_of :type
|
43
|
+
|
44
|
+
def self.types
|
45
|
+
[
|
46
|
+
::Borutus::Asset,
|
47
|
+
::Borutus::Equity,
|
48
|
+
::Borutus::Expense,
|
49
|
+
::Borutus::Liability,
|
50
|
+
::Borutus::Revenue,
|
51
|
+
]
|
52
|
+
end
|
53
|
+
|
54
|
+
if Borutus.enable_tenancy
|
55
|
+
include Borutus::Tenancy
|
56
|
+
else
|
57
|
+
include Borutus::NoTenancy
|
58
|
+
end
|
59
|
+
|
60
|
+
# The balance of the account. This instance method is intended for use only
|
61
|
+
# on instances of account subclasses.
|
62
|
+
#
|
63
|
+
# If the account has a normal credit balance, the debits are subtracted from the credits
|
64
|
+
# unless this is a contra account, in which case credits are substracted from debits.
|
65
|
+
#
|
66
|
+
# For a normal debit balance, the credits are subtracted from the debits
|
67
|
+
# unless this is a contra account, in which case debits are subtracted from credits.
|
68
|
+
#
|
69
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
70
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
71
|
+
#
|
72
|
+
# @example
|
73
|
+
# >> liability.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
74
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
75
|
+
#
|
76
|
+
# @example
|
77
|
+
# >> liability.balance
|
78
|
+
# => #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
79
|
+
#
|
80
|
+
# @return [BigDecimal] The decimal value balance
|
81
|
+
def balance(options={})
|
82
|
+
if self.class == Borutus::Account
|
83
|
+
raise(NoMethodError, "undefined method 'balance'")
|
84
|
+
else
|
85
|
+
if self.normal_credit_balance ^ contra
|
86
|
+
credits_balance(options) - debits_balance(options)
|
87
|
+
else
|
88
|
+
debits_balance(options) - credits_balance(options)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# The credit balance for the account.
|
94
|
+
#
|
95
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
96
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
97
|
+
#
|
98
|
+
# @example
|
99
|
+
# >> asset.credits_balance({:from_date => "2000-01-01", :to_date => Date.today})
|
100
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
101
|
+
#
|
102
|
+
# @example
|
103
|
+
# >> asset.credits_balance
|
104
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
105
|
+
#
|
106
|
+
# @return [BigDecimal] The decimal value credit balance
|
107
|
+
def credits_balance(options={})
|
108
|
+
credit_amounts.balance(options)
|
109
|
+
end
|
110
|
+
|
111
|
+
# The debit balance for the account.
|
112
|
+
#
|
113
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
114
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
115
|
+
#
|
116
|
+
# @example
|
117
|
+
# >> asset.debits_balance({:from_date => "2000-01-01", :to_date => Date.today})
|
118
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# >> asset.debits_balance
|
122
|
+
# => #<BigDecimal:103259bb8,'0.3E4',4(12)>
|
123
|
+
#
|
124
|
+
# @return [BigDecimal] The decimal value credit balance
|
125
|
+
def debits_balance(options={})
|
126
|
+
debit_amounts.balance(options)
|
127
|
+
end
|
128
|
+
|
129
|
+
# This class method is used to return the balance of all accounts
|
130
|
+
# for a given class and is intended for use only on account subclasses.
|
131
|
+
#
|
132
|
+
# Contra accounts are automatically subtracted from the balance.
|
133
|
+
#
|
134
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
135
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
136
|
+
#
|
137
|
+
# @example
|
138
|
+
# >> Borutus::Liability.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
139
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
140
|
+
#
|
141
|
+
# @example
|
142
|
+
# >> Borutus::Liability.balance
|
143
|
+
# => #<BigDecimal:1030fcc98,'0.82875E5',8(20)>
|
144
|
+
#
|
145
|
+
# @return [BigDecimal] The decimal value balance
|
146
|
+
def self.balance(options={})
|
147
|
+
if self.new.class == Borutus::Account
|
148
|
+
raise(NoMethodError, "undefined method 'balance'")
|
149
|
+
else
|
150
|
+
accounts_balance = BigDecimal.new('0')
|
151
|
+
accounts = self.all
|
152
|
+
accounts.each do |account|
|
153
|
+
if account.contra
|
154
|
+
accounts_balance -= account.balance(options)
|
155
|
+
else
|
156
|
+
accounts_balance += account.balance(options)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
accounts_balance
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# The trial balance of all accounts in the system. This should always equal zero,
|
164
|
+
# otherwise there is an error in the system.
|
165
|
+
#
|
166
|
+
# @example
|
167
|
+
# >> Account.trial_balance.to_i
|
168
|
+
# => 0
|
169
|
+
#
|
170
|
+
# @return [BigDecimal] The decimal value balance of all accounts
|
171
|
+
def self.trial_balance
|
172
|
+
if self.new.class == Borutus::Account
|
173
|
+
Borutus::Asset.balance - (Borutus::Liability.balance + Borutus::Equity.balance + Borutus::Revenue.balance - Borutus::Expense.balance)
|
174
|
+
else
|
175
|
+
raise(NoMethodError, "undefined method 'trial_balance'")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
end
|
180
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Borutus
|
2
|
+
# The Amount class represents debit and credit amounts in the system.
|
3
|
+
#
|
4
|
+
# @abstract
|
5
|
+
# An amount must be a subclass as either a debit or a credit to be saved to the database.
|
6
|
+
#
|
7
|
+
# @author Michael Bulat
|
8
|
+
class Amount < ActiveRecord::Base
|
9
|
+
belongs_to :entry, :class_name => 'Borutus::Entry'
|
10
|
+
belongs_to :account, :class_name => 'Borutus::Account'
|
11
|
+
|
12
|
+
validates_presence_of :type, :amount, :entry, :account
|
13
|
+
# attr_accessible :account, :account_name, :amount, :entry
|
14
|
+
|
15
|
+
delegate :name, to: :account, prefix: true, allow_nil: true
|
16
|
+
|
17
|
+
# Assign an account by name
|
18
|
+
def account_name=(name)
|
19
|
+
self.account = Account.find_by_name!(name)
|
20
|
+
end
|
21
|
+
|
22
|
+
protected
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Borutus
|
2
|
+
# Association extension for has_many :amounts relations. Internal.
|
3
|
+
module AmountsExtension
|
4
|
+
# Returns a sum of the referenced Amount objects.
|
5
|
+
#
|
6
|
+
# Takes a hash specifying :from_date and :to_date for calculating balances during periods.
|
7
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
8
|
+
#
|
9
|
+
# This runs the summation in the database, so it only works on persisted records.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# credit_amounts.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
13
|
+
# => #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
14
|
+
#
|
15
|
+
# @return [BigDecimal] The decimal value balance
|
16
|
+
def balance(hash={})
|
17
|
+
if hash[:from_date] && hash[:to_date]
|
18
|
+
from_date = hash[:from_date].kind_of?(Date) ? hash[:from_date] : Date.parse(hash[:from_date])
|
19
|
+
to_date = hash[:to_date].kind_of?(Date) ? hash[:to_date] : Date.parse(hash[:to_date])
|
20
|
+
includes(:entry).where('borutus_entries.date' => from_date..to_date).sum(:amount)
|
21
|
+
else
|
22
|
+
sum(:amount)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns a sum of the referenced Amount objects.
|
27
|
+
#
|
28
|
+
# This is used primarly in the validation step in Borutus::Entry
|
29
|
+
# in order to ensure that the debit and credits are canceling out.
|
30
|
+
#
|
31
|
+
# Since this does not use the database for sumation, it may be used on non-persisted records.
|
32
|
+
def balance_for_new_record
|
33
|
+
balance = BigDecimal.new('0')
|
34
|
+
each do |amount_record|
|
35
|
+
if amount_record.amount && !amount_record.marked_for_destruction?
|
36
|
+
balance += amount_record.amount # unless amount_record.marked_for_destruction?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
return balance
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Borutus
|
2
|
+
# The Asset class is an account type used to represents resources owned by the business entity.
|
3
|
+
#
|
4
|
+
# === Normal Balance
|
5
|
+
# The normal balance on Asset accounts is a *Debit*.
|
6
|
+
#
|
7
|
+
# @see http://en.wikipedia.org/wiki/Asset Assets
|
8
|
+
#
|
9
|
+
# @author Michael Bulat
|
10
|
+
class Asset < ::Borutus::Account
|
11
|
+
|
12
|
+
self.normal_credit_balance = false
|
13
|
+
|
14
|
+
# The balance of the account.
|
15
|
+
#
|
16
|
+
# Assets have normal debit balances, so the credits are subtracted from the debits
|
17
|
+
# unless this is a contra account, in which debits are subtracted from credits
|
18
|
+
#
|
19
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
20
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# >> asset.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
24
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
25
|
+
#
|
26
|
+
# @example
|
27
|
+
# >> asset.balance
|
28
|
+
# => #<BigDecimal:103259bb8,'0.2E4',4(12)>
|
29
|
+
#
|
30
|
+
# @return [BigDecimal] The decimal value balance
|
31
|
+
def balance(options={})
|
32
|
+
super(options)
|
33
|
+
end
|
34
|
+
|
35
|
+
# This class method is used to return
|
36
|
+
# the balance of all Asset accounts.
|
37
|
+
#
|
38
|
+
# Contra accounts are automatically subtracted from the balance.
|
39
|
+
#
|
40
|
+
# Takes an optional hash specifying :from_date and :to_date for calculating balances during periods.
|
41
|
+
# :from_date and :to_date may be strings of the form "yyyy-mm-dd" or Ruby Date objects
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
# >> Borutus::Asset.balance({:from_date => "2000-01-01", :to_date => Date.today})
|
45
|
+
# => #<BigDecimal:103259bb8,'0.1E4',4(12)>
|
46
|
+
#
|
47
|
+
# @example
|
48
|
+
# >> Borutus::Asset.balance
|
49
|
+
# => #<BigDecimal:1030fcc98,'0.82875E5',8(20)>
|
50
|
+
#
|
51
|
+
# @return [BigDecimal] The decimal value balance
|
52
|
+
def self.balance(options={})
|
53
|
+
super(options)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Borutus
|
2
|
+
# The CreditAmount class represents credit entries in the entry journal.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# credit_amount = Borutus::CreditAmount.new(:account => revenue, :amount => 1000)
|
6
|
+
#
|
7
|
+
# @author Michael Bulat
|
8
|
+
class CreditAmount < ::Borutus::Amount
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Borutus
|
2
|
+
# The DebitAmount class represents debit entries in the entry journal.
|
3
|
+
#
|
4
|
+
# @example
|
5
|
+
# debit_amount = Borutus::DebitAmount.new(:account => cash, :amount => 1000)
|
6
|
+
#
|
7
|
+
# @author Michael Bulat
|
8
|
+
class DebitAmount < ::Borutus::Amount
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Borutus
|
2
|
+
# Entries are the recording of debits and credits to various accounts.
|
3
|
+
# This table can be thought of as a traditional accounting Journal.
|
4
|
+
#
|
5
|
+
# Posting to a Ledger can be considered to happen automatically, since
|
6
|
+
# Accounts have the reverse 'has_many' relationship to either it's credit or
|
7
|
+
# debit entries
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# cash = Borutus::Asset.find_by_name('Cash')
|
11
|
+
# accounts_receivable = Borutus::Asset.find_by_name('Accounts Receivable')
|
12
|
+
#
|
13
|
+
# debit_amount = Borutus::DebitAmount.new(:account => cash, :amount => 1000)
|
14
|
+
# credit_amount = Borutus::CreditAmount.new(:account => accounts_receivable, :amount => 1000)
|
15
|
+
#
|
16
|
+
# entry = Borutus::Entry.new(:description => "Receiving payment on an invoice")
|
17
|
+
# entry.debit_amounts << debit_amount
|
18
|
+
# entry.credit_amounts << credit_amount
|
19
|
+
# entry.save
|
20
|
+
#
|
21
|
+
# @see http://en.wikipedia.org/wiki/Journal_entry Journal Entry
|
22
|
+
#
|
23
|
+
# @author Michael Bulat
|
24
|
+
class Entry < ActiveRecord::Base
|
25
|
+
before_save :default_date
|
26
|
+
|
27
|
+
if ActiveRecord::VERSION::MAJOR > 4
|
28
|
+
belongs_to :commercial_document, :polymorphic => true, optional: true
|
29
|
+
else
|
30
|
+
belongs_to :commercial_document, :polymorphic => true
|
31
|
+
end
|
32
|
+
|
33
|
+
has_many :credit_amounts, :extend => AmountsExtension, :class_name => 'Borutus::CreditAmount', :inverse_of => :entry
|
34
|
+
has_many :debit_amounts, :extend => AmountsExtension, :class_name => 'Borutus::DebitAmount', :inverse_of => :entry
|
35
|
+
has_many :credit_accounts, :through => :credit_amounts, :source => :account, :class_name => 'Borutus::Account'
|
36
|
+
has_many :debit_accounts, :through => :debit_amounts, :source => :account, :class_name => 'Borutus::Account'
|
37
|
+
|
38
|
+
validates_presence_of :description
|
39
|
+
validate :has_credit_amounts?
|
40
|
+
validate :has_debit_amounts?
|
41
|
+
validate :amounts_cancel?
|
42
|
+
|
43
|
+
# Support construction using 'credits' and 'debits' keys
|
44
|
+
accepts_nested_attributes_for :credit_amounts, :debit_amounts, allow_destroy: true
|
45
|
+
alias_method :credits=, :credit_amounts_attributes=
|
46
|
+
alias_method :debits=, :debit_amounts_attributes=
|
47
|
+
# attr_accessible :credits, :debits
|
48
|
+
|
49
|
+
# Support the deprecated .build method
|
50
|
+
def self.build(hash)
|
51
|
+
ActiveSupport::Deprecation.warn('Borutus::Transaction.build() is deprecated (use new instead)', caller)
|
52
|
+
new(hash)
|
53
|
+
end
|
54
|
+
|
55
|
+
def initialize(*args)
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
def default_date
|
61
|
+
todays_date = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
|
62
|
+
self.date ||= todays_date
|
63
|
+
end
|
64
|
+
|
65
|
+
def has_credit_amounts?
|
66
|
+
errors[:base] << "Entry must have at least one credit amount" if self.credit_amounts.blank?
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_debit_amounts?
|
70
|
+
errors[:base] << "Entry must have at least one debit amount" if self.debit_amounts.blank?
|
71
|
+
end
|
72
|
+
|
73
|
+
def amounts_cancel?
|
74
|
+
errors[:base] << "The credit and debit amounts are not equal" if credit_amounts.balance_for_new_record != debit_amounts.balance_for_new_record
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|