double_double 0.0.2 → 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.
- data/.travis.yml +0 -3
- data/README.md +2 -0
- data/lib/double_double/account.rb +32 -7
- data/lib/double_double/amount.rb +12 -13
- data/lib/double_double/asset.rb +1 -15
- data/lib/double_double/credit_amount.rb +1 -1
- data/lib/double_double/debit_amount.rb +1 -1
- data/lib/double_double/equity.rb +1 -16
- data/lib/double_double/expense.rb +1 -16
- data/lib/double_double/left_side_account.rb +7 -0
- data/lib/double_double/liability.rb +1 -15
- data/lib/double_double/revenue.rb +1 -16
- data/lib/double_double/right_side_account.rb +7 -0
- data/lib/double_double/transaction.rb +32 -15
- data/lib/double_double/transaction_type.rb +0 -2
- data/lib/double_double/version.rb +1 -1
- data/lib/double_double.rb +2 -0
- data/spec/factories/account_factory.rb +11 -11
- data/spec/factories/amount_factory.rb +3 -3
- data/spec/factories/transaction_factory.rb +1 -1
- data/spec/factories/transaction_type_factory.rb +1 -1
- data/spec/models/credit_amount_spec.rb +7 -7
- data/spec/models/debit_amount_spec.rb +7 -7
- data/spec/models/transaction_spec.rb +1 -16
- data/spec/spec_helper.rb +16 -17
- data/spec/support/left_side_account_types.rb +15 -15
- data/spec/support/right_side_account_types.rb +15 -15
- metadata +4 -2
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# double_double
|
2
2
|
[](https://travis-ci.org/crftr/double_double)
|
3
|
+
[](https://gemnasium.com/crftr/double_double)
|
4
|
+
[](https://codeclimate.com/github/crftr/double_double)
|
3
5
|
|
4
6
|
A double-entry accounting system. Likely to change heavily in the coming days.
|
5
7
|
|
@@ -13,7 +13,7 @@ module DoubleDouble
|
|
13
13
|
# normal balance swapped. For example, to remove equity, a "Drawing" account may be created
|
14
14
|
# as a contra equity account as follows:
|
15
15
|
#
|
16
|
-
# DoubleDouble::Equity.create(:
|
16
|
+
# DoubleDouble::Equity.create(name: "Drawing", number: 2002, contra: true)
|
17
17
|
#
|
18
18
|
# At all times the balance of all accounts should conform to the "accounting equation"
|
19
19
|
# DoubleDouble::Assets = Liabilties + Owner's Equity
|
@@ -35,18 +35,19 @@ module DoubleDouble
|
|
35
35
|
|
36
36
|
has_many :credit_amounts
|
37
37
|
has_many :debit_amounts
|
38
|
-
has_many :credit_transactions, :
|
39
|
-
has_many :debit_transactions,
|
38
|
+
has_many :credit_transactions, through: :credit_amounts, source: :transaction
|
39
|
+
has_many :debit_transactions, through: :debit_amounts, source: :transaction
|
40
40
|
|
41
41
|
validates_presence_of :type, :name, :number
|
42
42
|
validates_uniqueness_of :name, :number
|
43
43
|
|
44
44
|
def side_balance(is_debit, hash)
|
45
|
+
hash_keys = hash.keys
|
45
46
|
a = is_debit ? DoubleDouble::DebitAmount.scoped : DoubleDouble::CreditAmount.scoped
|
46
47
|
a = a.where(account_id: self.id)
|
47
|
-
a = a.
|
48
|
-
a = a.
|
49
|
-
a = a.
|
48
|
+
a = a.by_context(hash[:context_id], hash[:context_type]) if (hash_keys & [:context_id, :context_type]).count == 2
|
49
|
+
a = a.by_initiator(hash[:initiator_id], hash[:initiator_type]) if (hash_keys & [:initiator_id, :initiator_type]).count == 2
|
50
|
+
a = a.by_accountee(hash[:accountee_id], hash[:accountee_type]) if (hash_keys & [:accountee_id, :accountee_type]).count == 2
|
50
51
|
Money.new(a.sum(:amount_cents))
|
51
52
|
end
|
52
53
|
|
@@ -80,6 +81,30 @@ module DoubleDouble
|
|
80
81
|
end
|
81
82
|
accounts_balance
|
82
83
|
end
|
83
|
-
|
84
|
+
|
85
|
+
protected
|
86
|
+
# Left Side Accounts:
|
87
|
+
# if contra { credits_balance(hash) - debits_balance(hash) }
|
88
|
+
# else { debits_balance(hash) - credits_balance(hash) }
|
89
|
+
#
|
90
|
+
# Right Side Accounts:
|
91
|
+
# if contra { debits_balance(hash) - credits_balance(hash) }
|
92
|
+
# else { credits_balance(hash) - debits_balance(hash) }
|
93
|
+
#
|
94
|
+
# @return [Money] The balance of the account instance
|
95
|
+
def child_account_balance(is_left_side_account, hash = {})
|
96
|
+
if (is_left_side_account && contra) || !(is_left_side_account || contra)
|
97
|
+
credits_balance(hash) - debits_balance(hash)
|
98
|
+
else
|
99
|
+
debits_balance(hash) - credits_balance(hash)
|
100
|
+
end
|
101
|
+
end
|
84
102
|
end
|
85
103
|
end
|
104
|
+
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
|
110
|
+
|
data/lib/double_double/amount.rb
CHANGED
@@ -7,27 +7,26 @@ module DoubleDouble
|
|
7
7
|
class Amount < ActiveRecord::Base
|
8
8
|
self.table_name = 'double_double_amounts'
|
9
9
|
|
10
|
-
attr_accessible :account, :amount, :transaction, :
|
10
|
+
attr_accessible :account, :amount, :transaction, :context, :initiator, :accountee
|
11
11
|
|
12
12
|
belongs_to :transaction
|
13
13
|
belongs_to :account
|
14
|
-
belongs_to :
|
15
|
-
belongs_to :
|
16
|
-
belongs_to :
|
14
|
+
belongs_to :context, polymorphic: true
|
15
|
+
belongs_to :initiator, polymorphic: true
|
16
|
+
belongs_to :accountee, polymorphic: true
|
17
17
|
|
18
|
-
scope :
|
19
|
-
scope :
|
20
|
-
scope :
|
18
|
+
scope :by_context, ->(c_id, c_base_class) { where(context_id: c_id, context_type: c_base_class) }
|
19
|
+
scope :by_initiator, ->(i_id, i_base_class) { where(initiator_id: i_id, initiator_type: i_base_class) }
|
20
|
+
scope :by_accountee, ->(a_id, a_base_class) { where(accountee_id: a_id, accountee_type: a_base_class) }
|
21
21
|
|
22
|
-
scope :by_transaction_type_number,
|
22
|
+
# scope :by_transaction_type_number, -> {|tt_num| where( transaction: {transaction_type: {number: tt_num}})}
|
23
23
|
|
24
24
|
validates_presence_of :type, :amount_cents, :transaction, :account
|
25
25
|
|
26
26
|
composed_of :amount,
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
|
27
|
+
class_name: "Money",
|
28
|
+
mapping: [%w(amount_cents cents), %w(currency currency_as_string)],
|
29
|
+
constructor: Proc.new { |cents, currency| Money.new(cents || 0, currency || Money.default_currency) },
|
30
|
+
converter: Proc.new { |value| value.respond_to?(:to_money) ? value.to_money : raise(ArgumentError, "Can't convert #{value.class} to Money") }
|
32
31
|
end
|
33
32
|
end
|
data/lib/double_double/asset.rb
CHANGED
@@ -6,20 +6,6 @@ module DoubleDouble
|
|
6
6
|
#
|
7
7
|
# @see http://en.wikipedia.org/wiki/Asset Assets
|
8
8
|
#
|
9
|
-
class Asset <
|
10
|
-
|
11
|
-
# The balance of the account.
|
12
|
-
#
|
13
|
-
# Assets have normal debit balances, so the credits are subtracted from the debits
|
14
|
-
# unless this is a contra account, in which debits are subtracted from credits
|
15
|
-
#
|
16
|
-
# @return [Money] The value balance
|
17
|
-
def balance(hash = {})
|
18
|
-
if contra
|
19
|
-
credits_balance(hash) - debits_balance(hash)
|
20
|
-
else
|
21
|
-
debits_balance(hash) - credits_balance(hash)
|
22
|
-
end
|
23
|
-
end
|
9
|
+
class Asset < LeftSideAccount
|
24
10
|
end
|
25
11
|
end
|
@@ -2,7 +2,7 @@ module DoubleDouble
|
|
2
2
|
# The CreditAmount class represents credit entries in the transaction journal.
|
3
3
|
#
|
4
4
|
# @example
|
5
|
-
# credit_amount = DoubleDouble::CreditAmount.new(:
|
5
|
+
# credit_amount = DoubleDouble::CreditAmount.new(account: "revenue", amount: 1000)
|
6
6
|
#
|
7
7
|
class CreditAmount < Amount
|
8
8
|
end
|
@@ -2,7 +2,7 @@ module DoubleDouble
|
|
2
2
|
# The DebitAmount class represents debit entries in the transaction journal.
|
3
3
|
#
|
4
4
|
# @example
|
5
|
-
# debit_amount = DoubleDouble::DebitAmount.new(:
|
5
|
+
# debit_amount = DoubleDouble::DebitAmount.new(account: "cash", amount: 1000)
|
6
6
|
#
|
7
7
|
class DebitAmount < Amount
|
8
8
|
end
|
data/lib/double_double/equity.rb
CHANGED
@@ -6,21 +6,6 @@ module DoubleDouble
|
|
6
6
|
#
|
7
7
|
# @see http://en.wikipedia.org/wiki/Equity_(finance) Equity
|
8
8
|
#
|
9
|
-
|
10
|
-
class Equity < Account
|
11
|
-
|
12
|
-
# The balance of the account.
|
13
|
-
#
|
14
|
-
# Equity accounts have normal credit balances, so the debits are subtracted from the credits
|
15
|
-
# unless this is a contra account, in which credits are subtracted from debits
|
16
|
-
#
|
17
|
-
# @return [Money] The value balance
|
18
|
-
def balance(hash = {})
|
19
|
-
if contra
|
20
|
-
debits_balance(hash) - credits_balance(hash)
|
21
|
-
else
|
22
|
-
credits_balance(hash) - debits_balance(hash)
|
23
|
-
end
|
24
|
-
end
|
9
|
+
class Equity < RightSideAccount
|
25
10
|
end
|
26
11
|
end
|
@@ -6,21 +6,6 @@ module DoubleDouble
|
|
6
6
|
#
|
7
7
|
# @see http://en.wikipedia.org/wiki/Expense Expenses
|
8
8
|
#
|
9
|
-
|
10
|
-
class Expense < Account
|
11
|
-
|
12
|
-
# The balance of the account.
|
13
|
-
#
|
14
|
-
# Expenses have normal debit balances, so the credits are subtracted from the debits
|
15
|
-
# unless this is a contra account, in which debits are subtracted from credits
|
16
|
-
#
|
17
|
-
# @return [Money] The value balance
|
18
|
-
def balance(hash = {})
|
19
|
-
if contra
|
20
|
-
credits_balance(hash) - debits_balance(hash)
|
21
|
-
else
|
22
|
-
debits_balance(hash) - credits_balance(hash)
|
23
|
-
end
|
24
|
-
end
|
9
|
+
class Expense < LeftSideAccount
|
25
10
|
end
|
26
11
|
end
|
@@ -6,20 +6,6 @@ module DoubleDouble
|
|
6
6
|
#
|
7
7
|
# @see http://en.wikipedia.org/wiki/Liability_(financial_accounting) Liability
|
8
8
|
#
|
9
|
-
class Liability <
|
10
|
-
|
11
|
-
# The balance of the account.
|
12
|
-
#
|
13
|
-
# Liability accounts have normal credit balances, so the debits are subtracted from the credits
|
14
|
-
# unless this is a contra account, in which credits are subtracted from debits
|
15
|
-
#
|
16
|
-
# @return [Money] The value balance
|
17
|
-
def balance(hash = {})
|
18
|
-
if contra
|
19
|
-
debits_balance(hash) - credits_balance(hash)
|
20
|
-
else
|
21
|
-
credits_balance(hash) - debits_balance(hash)
|
22
|
-
end
|
23
|
-
end
|
9
|
+
class Liability < RightSideAccount
|
24
10
|
end
|
25
11
|
end
|
@@ -6,21 +6,6 @@ module DoubleDouble
|
|
6
6
|
#
|
7
7
|
# @see http://en.wikipedia.org/wiki/Revenue Revenue
|
8
8
|
#
|
9
|
-
|
10
|
-
class Revenue < Account
|
11
|
-
|
12
|
-
# The balance of the account.
|
13
|
-
#
|
14
|
-
# Revenue accounts have normal credit balances, so the debits are subtracted from the credits
|
15
|
-
# unless this is a contra account, in which credits are subtracted from debits
|
16
|
-
#
|
17
|
-
# @return [Money] The value balance
|
18
|
-
def balance(hash = {})
|
19
|
-
if contra
|
20
|
-
debits_balance(hash) - credits_balance(hash)
|
21
|
-
else
|
22
|
-
credits_balance(hash) - debits_balance(hash)
|
23
|
-
end
|
24
|
-
end
|
9
|
+
class Revenue < RightSideAccount
|
25
10
|
end
|
26
11
|
end
|
@@ -10,10 +10,10 @@ module DoubleDouble
|
|
10
10
|
# cash = DoubleDouble::Asset.find_by_name('Cash')
|
11
11
|
# accounts_receivable = DoubleDouble::Asset.find_by_name('Accounts Receivable')
|
12
12
|
#
|
13
|
-
# debit_amount = DoubleDouble::DebitAmount.new(:
|
14
|
-
# credit_amount = DoubleDouble::CreditAmount.new(:
|
13
|
+
# debit_amount = DoubleDouble::DebitAmount.new(account: 'cash', amount: 1000)
|
14
|
+
# credit_amount = DoubleDouble::CreditAmount.new(account: 'accounts_receivable', amount: 1000)
|
15
15
|
#
|
16
|
-
# transaction = DoubleDouble::Transaction.new(:
|
16
|
+
# transaction = DoubleDouble::Transaction.new(description: "Receiving payment on an invoice")
|
17
17
|
# transaction.debit_amounts << debit_amount
|
18
18
|
# transaction.credit_amounts << credit_amount
|
19
19
|
# transaction.save
|
@@ -23,22 +23,21 @@ module DoubleDouble
|
|
23
23
|
class Transaction < ActiveRecord::Base
|
24
24
|
self.table_name = 'double_double_transactions'
|
25
25
|
|
26
|
-
attr_accessible :description
|
26
|
+
attr_accessible :description
|
27
27
|
|
28
28
|
belongs_to :transaction_type
|
29
|
-
belongs_to :commercial_document, :polymorphic => true
|
30
29
|
|
31
30
|
has_many :credit_amounts
|
32
31
|
has_many :debit_amounts
|
33
32
|
has_many :credit_accounts, :through => :credit_amounts, :source => :account
|
34
|
-
has_many :debit_accounts,
|
33
|
+
has_many :debit_accounts, :through => :debit_amounts, :source => :account
|
35
34
|
|
36
35
|
validates_presence_of :description
|
37
36
|
validate :has_credit_amounts?
|
38
37
|
validate :has_debit_amounts?
|
39
38
|
validate :amounts_cancel?
|
40
39
|
|
41
|
-
scope :by_transaction_type_number,
|
40
|
+
scope :by_transaction_type_number, ->(tt_num) { where(transaction_type: {number: tt_num})}
|
42
41
|
|
43
42
|
# Simple API for building a transaction and associated debit and credit amounts
|
44
43
|
#
|
@@ -53,17 +52,17 @@ module DoubleDouble
|
|
53
52
|
#
|
54
53
|
# @return [DoubleDouble::Transaction] A Transaction with built credit and debit objects ready for saving
|
55
54
|
def self.build(hash)
|
56
|
-
|
55
|
+
t = Transaction.new(description: hash[:description])
|
57
56
|
hash[:debits].each do |debit|
|
58
|
-
|
59
|
-
|
57
|
+
new_debit_amount = prepare_amount_parameters debit.merge!({transaction: t})
|
58
|
+
t.debit_amounts << DebitAmount.new(new_debit_amount)
|
60
59
|
end
|
61
60
|
hash[:credits].each do |credit|
|
62
|
-
|
63
|
-
|
61
|
+
new_credit_amount = prepare_amount_parameters credit.merge!({transaction: t})
|
62
|
+
t.credit_amounts << CreditAmount.new(new_credit_amount)
|
64
63
|
end
|
65
|
-
|
66
|
-
|
64
|
+
t.transaction_type = hash[:transaction_type] if hash.has_key?(:transaction_type)
|
65
|
+
t
|
67
66
|
end
|
68
67
|
|
69
68
|
private
|
@@ -81,8 +80,26 @@ module DoubleDouble
|
|
81
80
|
|
82
81
|
def difference_of_amounts
|
83
82
|
credit_amount_total = credit_amounts.inject(Money.new(0)) {|sum, credit_amount| sum + credit_amount.amount}
|
84
|
-
debit_amount_total = debit_amounts.inject(Money.new(0)) {|sum,
|
83
|
+
debit_amount_total = debit_amounts.inject(Money.new(0)) {|sum, debit_amount| sum + debit_amount.amount}
|
85
84
|
credit_amount_total - debit_amount_total
|
86
85
|
end
|
86
|
+
|
87
|
+
def self.prepare_amount_parameters args
|
88
|
+
prepared_params = { account: Account.find_by_name(args[:account]), transaction: args[:transaction], amount: args[:amount]}
|
89
|
+
|
90
|
+
args_keys = args.keys
|
91
|
+
if (args_keys & [:context_id, :context_type]).count == 2
|
92
|
+
prepared_params.merge!({context_id: args[:context_id], context_type: args[:context_type]})
|
93
|
+
end
|
94
|
+
|
95
|
+
if (args_keys & [:initiator_id, :initiator_type]).count == 2
|
96
|
+
prepared_params.merge!({initiator_id: args[:initiator_id], initiator_type: args[:initiator_type]})
|
97
|
+
end
|
98
|
+
|
99
|
+
if (args_keys & [:accountee_id, :accountee_type]).count == 2
|
100
|
+
prepared_params.merge!({accountee_id: args[:accountee_id], accountee_type: args[:accountee_type]})
|
101
|
+
end
|
102
|
+
prepared_params
|
103
|
+
end
|
87
104
|
end
|
88
105
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module DoubleDouble
|
2
|
-
|
3
2
|
class TransactionType < ActiveRecord::Base
|
4
3
|
self.table_name = 'double_double_transaction_types'
|
5
4
|
|
@@ -9,5 +8,4 @@ module DoubleDouble
|
|
9
8
|
validates_numericality_of :number, greater_than: 0
|
10
9
|
validates_length_of :description, minimum: 6
|
11
10
|
end
|
12
|
-
|
13
11
|
end
|
data/lib/double_double.rb
CHANGED
@@ -5,6 +5,8 @@ require 'double_double/version'
|
|
5
5
|
|
6
6
|
# Accounts
|
7
7
|
require 'double_double/account'
|
8
|
+
require 'double_double/left_side_account'
|
9
|
+
require 'double_double/right_side_account'
|
8
10
|
require 'double_double/asset'
|
9
11
|
require 'double_double/equity'
|
10
12
|
require 'double_double/expense'
|
@@ -1,20 +1,20 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
-
factory :account, :
|
2
|
+
factory :account, class: DoubleDouble::Account do |account|
|
3
3
|
account.name { FactoryGirl.generate(:account_name) }
|
4
4
|
account.number { FactoryGirl.generate(:account_number)}
|
5
5
|
account.contra false
|
6
6
|
|
7
|
-
factory :asset, :
|
8
|
-
factory :equity, :
|
9
|
-
factory :expense, :
|
10
|
-
factory :liability, :
|
11
|
-
factory :revenue, :
|
7
|
+
factory :asset, class: DoubleDouble::Asset
|
8
|
+
factory :equity, class: DoubleDouble::Equity
|
9
|
+
factory :expense, class: DoubleDouble::Expense
|
10
|
+
factory :liability, class: DoubleDouble::Liability
|
11
|
+
factory :revenue, class: DoubleDouble::Revenue
|
12
12
|
|
13
|
-
factory :not_asset, :
|
14
|
-
factory :not_equity, :
|
15
|
-
factory :not_expense, :
|
16
|
-
factory :not_liability, :
|
17
|
-
factory :not_revenue, :
|
13
|
+
factory :not_asset, class: DoubleDouble::Liability
|
14
|
+
factory :not_equity, class: DoubleDouble::Asset
|
15
|
+
factory :not_expense, class: DoubleDouble::Liability
|
16
|
+
factory :not_liability, class: DoubleDouble::Asset
|
17
|
+
factory :not_revenue, class: DoubleDouble::Asset
|
18
18
|
end
|
19
19
|
|
20
20
|
sequence :account_name do |n|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
-
factory :amount, :
|
2
|
+
factory :amount, class: DoubleDouble::Amount do |amount|
|
3
3
|
end
|
4
4
|
|
5
|
-
factory :credit_amt, :
|
5
|
+
factory :credit_amt, class: DoubleDouble::CreditAmount do
|
6
6
|
end
|
7
7
|
|
8
|
-
factory :debit_amt, :
|
8
|
+
factory :debit_amt, class: DoubleDouble::DebitAmount do
|
9
9
|
end
|
10
10
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
-
factory :transaction_type, :
|
2
|
+
factory :transaction_type, class: DoubleDouble::TransactionType do |type|
|
3
3
|
type.description { FactoryGirl.generate(:transaction_type_description) }
|
4
4
|
type.number { FactoryGirl.generate(:transaction_type_number) }
|
5
5
|
end
|
@@ -19,28 +19,28 @@ module DoubleDouble
|
|
19
19
|
credit_amount.should_not be_valid
|
20
20
|
end
|
21
21
|
|
22
|
-
it "should be sensitive to
|
22
|
+
it "should be sensitive to 'context' when calculating balances, if supplied" do
|
23
23
|
acct_1 = FactoryGirl.create(:asset)
|
24
24
|
other_acct = FactoryGirl.create(:not_asset)
|
25
25
|
t = FactoryGirl.build(:transaction)
|
26
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(123), account: acct_1,
|
26
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(123), account: acct_1, context_id: 77, context_type: 'Job')
|
27
27
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(123), account: other_acct)
|
28
28
|
t.save
|
29
29
|
t = FactoryGirl.build(:transaction)
|
30
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(321), account: acct_1,
|
30
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(321), account: acct_1, context_id: 77, context_type: 'Job')
|
31
31
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(321), account: other_acct)
|
32
32
|
t.save
|
33
33
|
t = FactoryGirl.build(:transaction)
|
34
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(275), account: acct_1,
|
34
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(275), account: acct_1, context_id: 82, context_type: 'Job')
|
35
35
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(275), account: other_acct)
|
36
36
|
t.save
|
37
37
|
t = FactoryGirl.build(:transaction)
|
38
38
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(999), account: acct_1)
|
39
39
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(999), account: other_acct)
|
40
40
|
t.save
|
41
|
-
acct_1.credits_balance({
|
42
|
-
acct_1.credits_balance({
|
43
|
-
acct_1.credits_balance.should
|
41
|
+
acct_1.credits_balance({context_id: 77, context_type: 'Job'}).should == Money.new(123 + 321)
|
42
|
+
acct_1.credits_balance({context_id: 82, context_type: 'Job'}).should == Money.new(275)
|
43
|
+
acct_1.credits_balance.should == Money.new(123 + 321 + 275 + 999)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -19,28 +19,28 @@ module DoubleDouble
|
|
19
19
|
debit_amount.should_not be_valid
|
20
20
|
end
|
21
21
|
|
22
|
-
it "should be sensitive to
|
22
|
+
it "should be sensitive to context_id when calculating balances, if supplied" do
|
23
23
|
acct_1 = FactoryGirl.create(:asset)
|
24
24
|
other_acct = FactoryGirl.create(:not_asset)
|
25
25
|
t = FactoryGirl.build(:transaction)
|
26
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(123), account: acct_1,
|
26
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(123), account: acct_1, context_id: 77, context_type: 'Job')
|
27
27
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(123), account: other_acct)
|
28
28
|
t.save
|
29
29
|
t = FactoryGirl.build(:transaction)
|
30
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(321), account: acct_1,
|
30
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(321), account: acct_1, context_id: 77, context_type: 'Job')
|
31
31
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(321), account: other_acct)
|
32
32
|
t.save
|
33
33
|
t = FactoryGirl.build(:transaction)
|
34
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(275), account: acct_1,
|
34
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(275), account: acct_1, context_id: 82, context_type: 'Job')
|
35
35
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(275), account: other_acct)
|
36
36
|
t.save
|
37
37
|
t = FactoryGirl.build(:transaction)
|
38
38
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(999), account: acct_1)
|
39
39
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(999), account: other_acct)
|
40
40
|
t.save
|
41
|
-
acct_1.debits_balance({
|
42
|
-
acct_1.debits_balance({
|
43
|
-
acct_1.debits_balance.should
|
41
|
+
acct_1.debits_balance({context_id: 77, context_type: 'Job'}).should == Money.new(123 + 321)
|
42
|
+
acct_1.debits_balance({context_id: 82, context_type: 'Job'}).should == Money.new(275)
|
43
|
+
acct_1.debits_balance.should == Money.new(123 + 321 + 275 + 999)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
end
|
@@ -65,36 +65,21 @@ module DoubleDouble
|
|
65
65
|
t.errors['base'].should == ["The credit and debit amounts are not equal"]
|
66
66
|
end
|
67
67
|
|
68
|
-
it "should have a polymorphic commercial document associations" do
|
69
|
-
mock_document = FactoryGirl.create(:asset) # one would never do this, but it allows us to not require a migration for the test
|
70
|
-
|
71
|
-
t = FactoryGirl.build(:transaction)
|
72
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(123), account: @acct)
|
73
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(123), account: @other_acct)
|
74
|
-
t.commercial_document = mock_document
|
75
|
-
t.save
|
76
|
-
|
77
|
-
saved_transaction = Transaction.find(t.id)
|
78
|
-
saved_transaction.commercial_document.should == mock_document
|
79
|
-
end
|
80
|
-
|
81
68
|
it "should allow building a transaction and credit and debits with a hash" do
|
82
69
|
FactoryGirl.create(:asset, :name => "Accounts Receivable")
|
83
70
|
FactoryGirl.create(:revenue, :name => "Sales Revenue")
|
84
71
|
FactoryGirl.create(:liability, :name => "Sales Tax Payable")
|
85
|
-
mock_document = FactoryGirl.create(:asset)
|
86
72
|
transaction = Transaction.build(
|
87
73
|
description: "Sold some widgets",
|
88
|
-
commercial_document: mock_document,
|
89
74
|
debits: [
|
90
75
|
{account: "Accounts Receivable", amount: 50}],
|
91
76
|
credits: [
|
92
77
|
{account: "Sales Revenue", amount: 45},
|
93
78
|
{account: "Sales Tax Payable", amount: 5}])
|
79
|
+
|
94
80
|
transaction.should be_valid
|
95
81
|
transaction.save
|
96
82
|
saved_transaction = DoubleDouble::Transaction.find(transaction.id)
|
97
|
-
saved_transaction.commercial_document.should == mock_document
|
98
83
|
end
|
99
84
|
|
100
85
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -10,23 +10,18 @@ ActiveRecord::Migration.verbose = false
|
|
10
10
|
@migration = Class.new(ActiveRecord::Migration) do
|
11
11
|
def change
|
12
12
|
create_table :double_double_accounts do |t|
|
13
|
-
t.integer :number,
|
14
|
-
t.string
|
15
|
-
t.string
|
16
|
-
t.boolean :contra
|
17
|
-
|
18
|
-
t.timestamps
|
13
|
+
t.integer :number, null: false
|
14
|
+
t.string :name, null: false
|
15
|
+
t.string :type, null: false
|
16
|
+
t.boolean :contra, default: false
|
19
17
|
end
|
20
18
|
add_index :double_double_accounts, [:name, :type]
|
21
19
|
|
22
20
|
create_table :double_double_transactions do |t|
|
23
21
|
t.string :description
|
24
|
-
t.integer :commercial_document_id
|
25
|
-
t.string :commercial_document_type
|
26
22
|
t.references :transaction_type
|
27
23
|
t.timestamps
|
28
24
|
end
|
29
|
-
add_index :double_double_transactions, [:commercial_document_id, :commercial_document_type], :name => "index_transactions_on_commercial_doc"
|
30
25
|
add_index :double_double_transactions, :transaction_type_id
|
31
26
|
|
32
27
|
create_table :double_double_transaction_types do |t|
|
@@ -39,15 +34,19 @@ ActiveRecord::Migration.verbose = false
|
|
39
34
|
t.string :type
|
40
35
|
t.references :account
|
41
36
|
t.references :transaction
|
42
|
-
t.references :
|
43
|
-
t.references :
|
44
|
-
t.references :
|
45
|
-
|
37
|
+
t.references :context, polymorphic: true
|
38
|
+
t.references :initiator, polymorphic: true
|
39
|
+
t.references :accountee, polymorphic: true
|
40
|
+
|
41
|
+
t.integer :amount_cents, limit: 8, default: 0, null: false
|
46
42
|
t.string :currency
|
47
|
-
end
|
48
|
-
add_index :double_double_amounts, :
|
49
|
-
add_index :double_double_amounts, :
|
50
|
-
add_index :double_double_amounts, :
|
43
|
+
end
|
44
|
+
add_index :double_double_amounts, :context_id
|
45
|
+
add_index :double_double_amounts, :context_type
|
46
|
+
add_index :double_double_amounts, :initiator_id
|
47
|
+
add_index :double_double_amounts, :initiator_type
|
48
|
+
add_index :double_double_amounts, :accountee_id
|
49
|
+
add_index :double_double_amounts, :accountee_type
|
51
50
|
add_index :double_double_amounts, :type
|
52
51
|
add_index :double_double_amounts, [:account_id, :transaction_id]
|
53
52
|
add_index :double_double_amounts, [:transaction_id, :account_id]
|
@@ -59,19 +59,19 @@ shared_examples "a left side account type" do
|
|
59
59
|
a2 = rand(1_000_000_000)
|
60
60
|
a3 = rand(1_000_000_000)
|
61
61
|
a4 = rand(1_000_000_000)
|
62
|
-
|
63
|
-
|
62
|
+
context_id_1 = 100
|
63
|
+
context_id_2 = 200
|
64
64
|
|
65
65
|
t = FactoryGirl.build(:transaction)
|
66
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a1), account: acct1,
|
66
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a1), account: acct1, context_id: context_id_1, context_type: 'Job')
|
67
67
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a1), account: other_account)
|
68
68
|
t.save
|
69
69
|
t = FactoryGirl.build(:transaction)
|
70
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: acct1,
|
70
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: acct1, context_id: context_id_1, context_type: 'Job')
|
71
71
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
72
72
|
t.save
|
73
73
|
t = FactoryGirl.build(:transaction)
|
74
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: acct1,
|
74
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: acct1, context_id: context_id_2, context_type: 'Job')
|
75
75
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
76
76
|
t.save
|
77
77
|
t = FactoryGirl.build(:transaction)
|
@@ -81,15 +81,15 @@ shared_examples "a left side account type" do
|
|
81
81
|
|
82
82
|
t = FactoryGirl.build(:transaction)
|
83
83
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a4), account: other_account)
|
84
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct1,
|
84
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct1, context_id: context_id_1, context_type: 'Job')
|
85
85
|
t.save
|
86
86
|
t = FactoryGirl.build(:transaction)
|
87
87
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
88
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct1,
|
88
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct1, context_id: context_id_1, context_type: 'Job')
|
89
89
|
t.save
|
90
90
|
t = FactoryGirl.build(:transaction)
|
91
91
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
92
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct1,
|
92
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct1, context_id: context_id_2, context_type: 'Job')
|
93
93
|
t.save
|
94
94
|
t = FactoryGirl.build(:transaction)
|
95
95
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
@@ -98,27 +98,27 @@ shared_examples "a left side account type" do
|
|
98
98
|
|
99
99
|
t = FactoryGirl.build(:transaction)
|
100
100
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a4), account: other_account)
|
101
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct2,
|
101
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct2, context_id: context_id_1, context_type: 'Job')
|
102
102
|
t.save
|
103
103
|
t = FactoryGirl.build(:transaction)
|
104
104
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
105
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct2,
|
105
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct2, context_id: context_id_1, context_type: 'Job')
|
106
106
|
t.save
|
107
107
|
t = FactoryGirl.build(:transaction)
|
108
108
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
109
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2,
|
109
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2, context_id: context_id_2, context_type: 'Job')
|
110
110
|
t.save
|
111
111
|
t = FactoryGirl.build(:transaction)
|
112
112
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
113
113
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2)
|
114
114
|
t.save
|
115
115
|
|
116
|
-
acct1.balance({
|
117
|
-
acct1.balance({
|
116
|
+
acct1.balance({context_id: context_id_1, context_type: 'Job'}).should == Money.new((a4 + a2) - (a1 + a2))
|
117
|
+
acct1.balance({context_id: context_id_2, context_type: 'Job'}).should == Money.new(a3 - a3)
|
118
118
|
acct1.balance.should == Money.new((a4 + a2 + a3 + a3) - (a1 + a2 + a3 + a3))
|
119
119
|
|
120
|
-
acct2.balance({
|
121
|
-
acct2.balance({
|
120
|
+
acct2.balance({context_id: context_id_1, context_type: 'Job'}).should == Money.new((a4 + a2))
|
121
|
+
acct2.balance({context_id: context_id_2, context_type: 'Job'}).should == Money.new(a3)
|
122
122
|
acct2.balance.should == Money.new((a4 + a2 + a3 + a3))
|
123
123
|
end
|
124
124
|
end
|
@@ -59,19 +59,19 @@ shared_examples "a right side account type" do
|
|
59
59
|
a2 = rand(1_000_000_000)
|
60
60
|
a3 = rand(1_000_000_000)
|
61
61
|
a4 = rand(1_000_000_000)
|
62
|
-
|
63
|
-
|
62
|
+
context_id_1 = 100
|
63
|
+
context_id_2 = 200
|
64
64
|
|
65
65
|
t = FactoryGirl.build(:transaction)
|
66
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a1), account: acct1,
|
66
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a1), account: acct1, context_id: context_id_1, context_type: 'Job')
|
67
67
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a1), account: other_account)
|
68
68
|
t.save
|
69
69
|
t = FactoryGirl.build(:transaction)
|
70
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: acct1,
|
70
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: acct1, context_id: context_id_1, context_type: 'Job')
|
71
71
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
72
72
|
t.save
|
73
73
|
t = FactoryGirl.build(:transaction)
|
74
|
-
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: acct1,
|
74
|
+
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: acct1, context_id: context_id_2, context_type: 'Job')
|
75
75
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
76
76
|
t.save
|
77
77
|
t = FactoryGirl.build(:transaction)
|
@@ -81,15 +81,15 @@ shared_examples "a right side account type" do
|
|
81
81
|
|
82
82
|
t = FactoryGirl.build(:transaction)
|
83
83
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a4), account: other_account)
|
84
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct1,
|
84
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct1, context_id: context_id_1, context_type: 'Job')
|
85
85
|
t.save
|
86
86
|
t = FactoryGirl.build(:transaction)
|
87
87
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
88
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct1,
|
88
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct1, context_id: context_id_1, context_type: 'Job')
|
89
89
|
t.save
|
90
90
|
t = FactoryGirl.build(:transaction)
|
91
91
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
92
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct1,
|
92
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct1, context_id: context_id_2, context_type: 'Job')
|
93
93
|
t.save
|
94
94
|
t = FactoryGirl.build(:transaction)
|
95
95
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
@@ -98,27 +98,27 @@ shared_examples "a right side account type" do
|
|
98
98
|
|
99
99
|
t = FactoryGirl.build(:transaction)
|
100
100
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a4), account: other_account)
|
101
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct2,
|
101
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a4), account: acct2, context_id: context_id_1, context_type: 'Job')
|
102
102
|
t.save
|
103
103
|
t = FactoryGirl.build(:transaction)
|
104
104
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a2), account: other_account)
|
105
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct2,
|
105
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a2), account: acct2, context_id: context_id_1, context_type: 'Job')
|
106
106
|
t.save
|
107
107
|
t = FactoryGirl.build(:transaction)
|
108
108
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
109
|
-
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2,
|
109
|
+
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2, context_id: context_id_2, context_type: 'Job')
|
110
110
|
t.save
|
111
111
|
t = FactoryGirl.build(:transaction)
|
112
112
|
t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: Money.new(a3), account: other_account)
|
113
113
|
t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: Money.new(a3), account: acct2)
|
114
114
|
t.save
|
115
115
|
|
116
|
-
acct1.balance({
|
117
|
-
acct1.balance({
|
116
|
+
acct1.balance({context_id: context_id_1, context_type: 'Job'}).should == Money.new((a1 + a2) - (a4 + a2))
|
117
|
+
acct1.balance({context_id: context_id_2, context_type: 'Job'}).should == Money.new(a3 - a3)
|
118
118
|
acct1.balance.should == Money.new((a1 + a2 + a3 + a3) - (a4 + a2 + a3 + a3))
|
119
119
|
|
120
|
-
acct2.balance({
|
121
|
-
acct2.balance({
|
120
|
+
acct2.balance({context_id: context_id_1, context_type: 'Job'}).should == Money.new(- (a4 + a2))
|
121
|
+
acct2.balance({context_id: context_id_2, context_type: 'Job'}).should == Money.new(- a3)
|
122
122
|
acct2.balance.should == Money.new(- (a4 + a2 + a3 + a3))
|
123
123
|
end
|
124
124
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: double_double
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: money
|
@@ -146,8 +146,10 @@ files:
|
|
146
146
|
- lib/double_double/debit_amount.rb
|
147
147
|
- lib/double_double/equity.rb
|
148
148
|
- lib/double_double/expense.rb
|
149
|
+
- lib/double_double/left_side_account.rb
|
149
150
|
- lib/double_double/liability.rb
|
150
151
|
- lib/double_double/revenue.rb
|
152
|
+
- lib/double_double/right_side_account.rb
|
151
153
|
- lib/double_double/transaction.rb
|
152
154
|
- lib/double_double/transaction_type.rb
|
153
155
|
- lib/double_double/version.rb
|