double_double 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Build Status](https://travis-ci.org/crftr/double_double.png)](https://travis-ci.org/crftr/double_double)
|
3
|
+
[![Dependency Status](https://gemnasium.com/crftr/double_double.png)](https://gemnasium.com/crftr/double_double)
|
4
|
+
[![Code Climate](https://codeclimate.com/badge.png)](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
|