double_double 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -3,10 +3,12 @@
3
3
  [![Dependency Status](https://gemnasium.com/crftr/double_double.png)](https://gemnasium.com/crftr/double_double)
4
4
  [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/crftr/double_double)
5
5
 
6
- A double-entry accounting system. Likely to change heavily in the coming days.
6
+ A double-entry accrual accounting system for your application. Currency-agnostic but uses the Money gem. Account holder support and contexts are built-in.
7
7
 
8
8
  ## Installation
9
9
 
10
+ ### Gem
11
+
10
12
  Add this line to your application's Gemfile:
11
13
 
12
14
  gem 'double_double'
@@ -19,22 +21,181 @@ Or install it yourself as:
19
21
 
20
22
  $ gem install double_double
21
23
 
22
- ## Usage
24
+ ### Database structure
25
+
26
+ Create the expected database structure. If using Rails, generate a migration:
27
+
28
+ $ rails generate migration CreateDoubleDouble
29
+
30
+ Edit the migration to match:
31
+
32
+ ```ruby
33
+ class CreateDoubleDouble < ActiveRecord::Migration
34
+ def change
35
+ create_table :double_double_accounts do |t|
36
+ t.string :name, null: false
37
+ t.integer :number, null: false
38
+ t.string :type, null: false
39
+ t.boolean :contra, default: false
40
+ end
41
+ add_index :double_double_accounts, [:name, :type]
42
+
43
+ create_table :double_double_transactions do |t|
44
+ t.string :description
45
+ t.references :transaction_type
46
+ t.timestamps
47
+ end
48
+ add_index :double_double_transactions, :transaction_type_id
23
49
 
24
- TODO: Write usage instructions here
50
+ create_table :double_double_transaction_types do |t|
51
+ t.integer :number, null: false
52
+ t.string :description, null: false
53
+ end
54
+ add_index :double_double_transaction_types, :number
25
55
 
26
- ## Name
56
+ create_table :double_double_amounts do |t|
57
+ t.string :type
58
+ t.references :account
59
+ t.references :transaction
60
+ t.references :accountee, polymorphic: true
61
+ t.references :context, polymorphic: true
62
+ t.references :initiator, polymorphic: true
63
+ t.integer :amount_cents, limit: 8, default: 0, null: false
64
+ t.string :currency
65
+ end
66
+ add_index :double_double_amounts, :context_id
67
+ add_index :double_double_amounts, :context_type
68
+ add_index :double_double_amounts, :initiator_id
69
+ add_index :double_double_amounts, :initiator_type
70
+ add_index :double_double_amounts, :accountee_id
71
+ add_index :double_double_amounts, :accountee_type
72
+ add_index :double_double_amounts, :type
73
+ add_index :double_double_amounts, [:account_id, :transaction_id]
74
+ add_index :double_double_amounts, [:transaction_id, :account_id]
75
+ end
76
+ end
77
+ ```
78
+
79
+ Rake the new migration
80
+
81
+ $ rake db:migrate
82
+
83
+ ## Overview
84
+
85
+ [Double-entry accounting][1] practices have been [traced back to the 13th century][2]. double_double strives to make accepted practices accessible and relatively easy to implement within other applications.
86
+
87
+ [1]: http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system
88
+ [2]: http://en.wikipedia.org/wiki/Double-entry_bookkeeping_system#History
89
+
90
+ As with many off-the-shelf accounting systems, this project supports:
91
+ * **Accountee**: an account holder.
92
+ * **Context**: to track activity on invoices, purchase orders, jobs, campaigns, etc.
93
+ * **Initiator**: *who* authorized or performed the action.
94
+
95
+ ### Accounts
96
+
97
+ All accounts created in a double-entry system make up the [chart of accounts][3]. This collection of accounts will determine how money is tracked as it moves through the system. It is important to design and create the chart of accounts prior to creating transactions. *If we want people to hold "an individual account" in this system, we will configure them as an accountee, not with a new account. __See the section on accountees__ *
98
+
99
+ [3]: http://en.wikipedia.org/wiki/Chart_of_accounts
100
+
101
+ In double_double, all accounts created are considered to be the chart of accounts. All accounts are "on the books."
102
+
103
+ **Account Class** | **Normal Balance** | **Description** | **Example Uses**
104
+ ------------------------- | ------------------ | -------------------------------------------------- | -------------------------------------------
105
+ `DoubleDouble::Asset` | Debit | Resources owned or controlled | Cash, Office Computers, Grandma's Jewelry
106
+ `DoubleDouble::Liability` | Credit | Obligations | Accounts Payable, Bank Loan
107
+ `DoubleDouble::Equity` | Credit | The claim to assets after all liabilities are paid | Paid-In Capital, Dividends, Retained Earnings
108
+ `DoubleDouble::Revenue` | Credit | Income | Sales, Interest Earned
109
+ `DoubleDouble::Expense` | Debit | Expenditures | Utilities, Salaries, Rent, Taco Tuesday
110
+
111
+ Accounts have the following attributes:
112
+
113
+ * **name**
114
+ * **number**, for reporting purposes
115
+ * **contra** flag, _optional_ `default: false`
116
+
117
+ An example 'Cash' asset account as account number `20`
118
+
119
+ ```ruby
120
+ DoubleDouble::Asset.create! name: 'Cash', number: 20
121
+ ```
122
+
123
+ An example 'Sales' revenue account and a 'Discounts' contra revenue account.
124
+
125
+ ```ruby
126
+ DoubleDouble::Revenue.create! name: 'Sales', number: 40
127
+ DoubleDouble::Revenue.create! name: 'Discounts', number: 50, contra: true
128
+ ```
129
+
130
+ Contra accounts are used to offset a related account of the same class. *The example above is a common method to track sales. The full __sales value__ of the sale would be assigned to 'Sales' while any discounts given would be assigned to 'Discounts.'*
131
+
132
+
133
+ ### Amounts & Transactions
134
+
135
+ * TODO: Transaction basics
136
+ * TODO: Amount basics
137
+ * TODO: Accountees
138
+ * TODO: Contexts
139
+ * TODO: Initiated_by
140
+
141
+ ## Example Scenarios
142
+
143
+ ### Basic Scenarios
144
+
145
+ #### Basic Scenario: We are creating a personal application to only track loan payments back to Grandpa.
146
+
147
+ We've decided to keep things very simple and only create two accounts:
148
+ * 'Cash' an asset account.
149
+ * 'Grandpa Loan' a liability account.
150
+
151
+ ```ruby
152
+ DoubleDouble::Asset.create! name:'Cash', number: 11
153
+ DoubleDouble::Liability.create! name:'Grandpa Loan', number: 12
154
+ ```
155
+ Grandpa was kind enough to loan us $800 USD in cash for college textbooks. To enter this we will require a transaction which will affect both 'Cash' and 'Grandpa Loan'
156
+ ```ruby
157
+ DoubleDouble::Transaction.create!(
158
+ description:
159
+ 'We received a loan from Grandpa',
160
+ debits:[
161
+ {account: 'Cash', amount: '$800'}],
162
+ credits:[
163
+ {account: 'Grandpa Loan', amount: '$800'}])
164
+ ```
165
+ But because we were surprised to have the option to buy a few used textbooks we can return some of Grandpa's loan. We will return $320.
166
+ ```ruby
167
+ DoubleDouble::Transaction.create!(
168
+ description:
169
+ 'Payed back $320 to Grandpa',
170
+ debits:[
171
+ {account: 'Grandpa Loan', amount: '$320'}],
172
+ credits:[
173
+ {account: 'Cash', amount: '$320'}])
174
+ ```
175
+ If we want to know how much we still owed Grandpa we can look at the balance of the account.
176
+ ```ruby
177
+ DoubleDouble::Account.find_by_name('Grandpa Loan').balance.to_s # => "480.00"
178
+ ```
27
179
 
28
- The double double is the flagship In-N-Out cheeseburger. Ask a southern-Californian.
180
+ ### Realistic Scenarios
181
+ * TODO: Write a realistic scenario
182
+
183
+ ### Complex Scenarios
184
+ * TODO: Write a realistic & complex scenario
185
+
186
+ ## Tests
187
+
188
+ All code is backed by Rspec tests. Clone this repository and either `rspec spec` or `rake spec` if Rake is installed.
29
189
 
30
190
  ## Contributing
31
191
 
32
192
  1. Fork it
33
193
  2. Create your feature branch (`git checkout -b my-new-feature`)
34
- 3. Commit your changes (`git commit -am 'Add some feature'`)
194
+ 3. Commit your changes & tests (`git commit -am 'Add some feature'`)
35
195
  4. Push to the branch (`git push origin my-new-feature`)
36
196
  5. Create new Pull Request
37
197
 
38
198
  ## Notes
39
199
 
40
- double_double was heavily influenced by mbulat's plutus project and regularly working with quickbooks.
200
+ double_double was influenced by mbulat's plutus project and regularly working with quickbooks.
201
+
@@ -18,7 +18,7 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ['lib']
19
19
 
20
20
  gem.add_dependency('money', '~> 5.1')
21
- gem.add_dependency 'activerecord', '~> 3.2.11'
21
+ gem.add_dependency('activerecord', '~> 3.2.11')
22
22
  gem.add_development_dependency('sqlite3')
23
23
  gem.add_development_dependency('rspec', '~> 2.12')
24
24
  gem.add_development_dependency('factory_girl')
@@ -40,14 +40,14 @@ module DoubleDouble
40
40
 
41
41
  validates_presence_of :type, :name, :number
42
42
  validates_uniqueness_of :name, :number
43
+ validates_length_of :name, :minimum => 1
43
44
 
44
45
  def side_balance(is_debit, hash)
45
- hash_keys = hash.keys
46
46
  a = is_debit ? DoubleDouble::DebitAmount.scoped : DoubleDouble::CreditAmount.scoped
47
47
  a = a.where(account_id: self.id)
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
48
+ a = a.by_context(hash[:context]) if hash.has_key? :context
49
+ a = a.by_initiator(hash[:initiator]) if hash.has_key? :initiator
50
+ a = a.by_accountee(hash[:accountee]) if hash.has_key? :accountee
51
51
  Money.new(a.sum(:amount_cents))
52
52
  end
53
53
 
@@ -64,12 +64,12 @@ module DoubleDouble
64
64
  #
65
65
  # @return [Money] The value balance of all accounts
66
66
  def self.trial_balance
67
- raise(NoMethodError, "undefined method 'trial_balance'") unless self.new.class == DoubleDouble::Account
67
+ raise(NoMethodError, "undefined method 'trial_balance'") unless self == DoubleDouble::Account
68
68
  Asset.balance - (Liability.balance + Equity.balance + Revenue.balance - Expense.balance)
69
69
  end
70
70
 
71
71
  def self.balance
72
- raise(NoMethodError, "undefined method 'balance'") if self.new.class == DoubleDouble::Account
72
+ raise(NoMethodError, "undefined method 'balance'") if self == DoubleDouble::Account
73
73
  accounts_balance = Money.new(0)
74
74
  accounts = self.all
75
75
  accounts.each do |acct|
@@ -83,17 +83,20 @@ module DoubleDouble
83
83
  end
84
84
 
85
85
  protected
86
- # Left Side Accounts:
86
+ # The balance method that derived Accounts utilize.
87
+ #
88
+ # Nornal Debit Accounts:
87
89
  # if contra { credits_balance(hash) - debits_balance(hash) }
88
90
  # else { debits_balance(hash) - credits_balance(hash) }
89
91
  #
90
- # Right Side Accounts:
92
+ # Normal Credit Accounts:
91
93
  # if contra { debits_balance(hash) - credits_balance(hash) }
92
94
  # else { credits_balance(hash) - debits_balance(hash) }
93
95
  #
94
96
  # @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
+ def child_account_balance(is_normal_debit_account, hash = {})
98
+ raise(NoMethodError, "undefined method 'balance'") if self == DoubleDouble::Account
99
+ if (is_normal_debit_account && contra) || !(is_normal_debit_account || contra)
97
100
  credits_balance(hash) - debits_balance(hash)
98
101
  else
99
102
  debits_balance(hash) - credits_balance(hash)
@@ -7,21 +7,22 @@ module DoubleDouble
7
7
  class Amount < ActiveRecord::Base
8
8
  self.table_name = 'double_double_amounts'
9
9
 
10
- attr_accessible :account, :amount, :transaction, :context, :initiator, :accountee
10
+ attr_accessible :account, :amount, :transaction, :context, :initiator, :accountee, as: :transation_builder
11
11
 
12
12
  belongs_to :transaction
13
13
  belongs_to :account
14
+ belongs_to :accountee, polymorphic: true
14
15
  belongs_to :context, polymorphic: true
15
16
  belongs_to :initiator, polymorphic: true
16
- belongs_to :accountee, polymorphic: true
17
17
 
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) }
18
+ scope :by_accountee, ->(a) { where(accountee_id: a.id, accountee_type: a.class.base_class) }
19
+ scope :by_context, ->(c) { where(context_id: c.id, context_type: c.class.base_class) }
20
+ scope :by_initiator, ->(i) { where(initiator_id: i.id, initiator_type: i.class.base_class) }
21
21
 
22
22
  # scope :by_transaction_type_number, -> {|tt_num| where( transaction: {transaction_type: {number: tt_num}})}
23
23
 
24
- validates_presence_of :type, :amount_cents, :transaction, :account
24
+ validates_presence_of :type, :transaction, :account
25
+ validates :amount_cents, numericality: {greater_than: 0}
25
26
 
26
27
  composed_of :amount,
27
28
  class_name: "Money",
@@ -6,6 +6,6 @@ module DoubleDouble
6
6
  #
7
7
  # @see http://en.wikipedia.org/wiki/Asset Assets
8
8
  #
9
- class Asset < LeftSideAccount
9
+ class Asset < NormalDebitAccount
10
10
  end
11
11
  end
@@ -6,6 +6,6 @@ module DoubleDouble
6
6
  #
7
7
  # @see http://en.wikipedia.org/wiki/Equity_(finance) Equity
8
8
  #
9
- class Equity < RightSideAccount
9
+ class Equity < NormalCreditAccount
10
10
  end
11
11
  end
@@ -6,6 +6,6 @@ module DoubleDouble
6
6
  #
7
7
  # @see http://en.wikipedia.org/wiki/Expense Expenses
8
8
  #
9
- class Expense < LeftSideAccount
9
+ class Expense < NormalDebitAccount
10
10
  end
11
11
  end
@@ -6,6 +6,6 @@ module DoubleDouble
6
6
  #
7
7
  # @see http://en.wikipedia.org/wiki/Liability_(financial_accounting) Liability
8
8
  #
9
- class Liability < RightSideAccount
9
+ class Liability < NormalCreditAccount
10
10
  end
11
11
  end
@@ -1,5 +1,5 @@
1
1
  module DoubleDouble
2
- class RightSideAccount < Account
2
+ class NormalCreditAccount < Account
3
3
  def balance(hash = {})
4
4
  child_account_balance(false, hash)
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module DoubleDouble
2
- class LeftSideAccount < Account
2
+ class NormalDebitAccount < Account
3
3
  def balance(hash = {})
4
4
  child_account_balance(true, hash)
5
5
  end
@@ -6,6 +6,6 @@ module DoubleDouble
6
6
  #
7
7
  # @see http://en.wikipedia.org/wiki/Revenue Revenue
8
8
  #
9
- class Revenue < RightSideAccount
9
+ class Revenue < NormalCreditAccount
10
10
  end
11
11
  end
@@ -29,8 +29,8 @@ module DoubleDouble
29
29
 
30
30
  has_many :credit_amounts
31
31
  has_many :debit_amounts
32
- has_many :credit_accounts, :through => :credit_amounts, :source => :account
33
- has_many :debit_accounts, :through => :debit_amounts, :source => :account
32
+ has_many :credit_accounts, through: :credit_amounts, source: :account
33
+ has_many :debit_accounts, through: :debit_amounts, source: :account
34
34
 
35
35
  validates_presence_of :description
36
36
  validate :has_credit_amounts?
@@ -45,27 +45,31 @@ module DoubleDouble
45
45
  # transaction = DoubleDouble::Transaction.build(
46
46
  # description: "Sold some widgets",
47
47
  # debits: [
48
- # {account: "Accounts Receivable", amount: 50}],
48
+ # {account: "Accounts Receivable", amount: 50, context_id: 20, context_type: 'Job'}],
49
49
  # credits: [
50
- # {account: "Sales Revenue", amount: 45},
51
- # {account: "Sales Tax Payable", amount: 5}])
50
+ # {account: "Sales Revenue", amount: 45},
51
+ # {account: "Sales Tax Payable", amount: 5}])
52
52
  #
53
53
  # @return [DoubleDouble::Transaction] A Transaction with built credit and debit objects ready for saving
54
- def self.build(hash)
55
- t = Transaction.new(description: hash[:description])
56
- hash[:debits].each do |debit|
57
- new_debit_amount = prepare_amount_parameters debit.merge!({transaction: t})
58
- t.debit_amounts << DebitAmount.new(new_debit_amount)
59
- end
60
- hash[:credits].each do |credit|
61
- new_credit_amount = prepare_amount_parameters credit.merge!({transaction: t})
62
- t.credit_amounts << CreditAmount.new(new_credit_amount)
63
- end
64
- t.transaction_type = hash[:transaction_type] if hash.has_key?(:transaction_type)
54
+ def self.build args
55
+ t = Transaction.new()
56
+ t.description = args[:description]
57
+ t.transaction_type = args[:transaction_type] if args.has_key? :transaction_type
58
+
59
+ add_amounts_to_transaction(args[:debits], t, true)
60
+ add_amounts_to_transaction(args[:credits], t, false)
65
61
  t
66
62
  end
67
63
 
64
+ def self.create! args
65
+ t = build args
66
+ t.save!
67
+ end
68
+
68
69
  private
70
+
71
+ # Validation
72
+
69
73
  def has_credit_amounts?
70
74
  errors[:base] << "Transaction must have at least one credit amount" if self.credit_amounts.blank?
71
75
  end
@@ -84,21 +88,24 @@ module DoubleDouble
84
88
  credit_amount_total - debit_amount_total
85
89
  end
86
90
 
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
91
+ # Assist transaction building
98
92
 
99
- if (args_keys & [:accountee_id, :accountee_type]).count == 2
100
- prepared_params.merge!({accountee_id: args[:accountee_id], accountee_type: args[:accountee_type]})
93
+ def self.add_amounts_to_transaction amounts, transaction, add_to_debits = true
94
+ return if amounts.nil? || amounts.count == 0
95
+ amounts.each do |amt|
96
+ amount_parameters = prepare_amount_parameters amt.merge!({transaction: transaction})
97
+ new_amount = add_to_debits ? DebitAmount.new : CreditAmount.new
98
+ new_amount.assign_attributes(amount_parameters, as: :transation_builder)
99
+ transaction.debit_amounts << new_amount if add_to_debits
100
+ transaction.credit_amounts << new_amount unless add_to_debits
101
101
  end
102
+ end
103
+
104
+ def self.prepare_amount_parameters args
105
+ prepared_params = { account: Account.find_by_name(args[:account]), transaction: args[:transaction], amount: args[:amount]}
106
+ prepared_params.merge!({accountee: args[:accountee]}) if args.has_key? :accountee
107
+ prepared_params.merge!({context: args[:context]}) if args.has_key? :context
108
+ prepared_params.merge!({initiator: args[:initiator]}) if args.has_key? :initiator
102
109
  prepared_params
103
110
  end
104
111
  end
@@ -1,3 +1,3 @@
1
1
  module DoubleDouble
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/double_double.rb CHANGED
@@ -5,8 +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
+ require 'double_double/normal_credit_account'
9
+ require 'double_double/normal_debit_account'
10
10
  require 'double_double/asset'
11
11
  require 'double_double/equity'
12
12
  require 'double_double/expense'
@@ -2,26 +2,26 @@ module DoubleDouble
2
2
  describe Account do
3
3
 
4
4
  it "should not allow creating an account without a subtype" do
5
- account = FactoryGirl.build(:account)
5
+ account = DoubleDouble::Account.new(name: 'Cash', number: 10)
6
6
  account.should_not be_valid
7
7
  end
8
8
 
9
9
  it "should be unique per name" do
10
- FactoryGirl.create(:asset, :name => "Test1")
11
- account = FactoryGirl.build(:asset, :name => "Test1")
10
+ DoubleDouble::Asset.new(name: 'Petty Cash', number: 10).save
11
+ account = DoubleDouble::Liability.new(name: 'Petty Cash', number: 11)
12
12
  account.should_not be_valid
13
13
  account.errors[:name].should == ["has already been taken"]
14
14
  end
15
15
 
16
16
  it "should be unique per number" do
17
- FactoryGirl.create(:asset, :number => 88)
18
- account = FactoryGirl.build(:asset, :number => 88)
17
+ DoubleDouble::Asset.new(name: 'Cash', number: 22).save
18
+ account = DoubleDouble::Liability.new(name: 'Loan', number: 22)
19
19
  account.should_not be_valid
20
20
  account.errors[:number].should == ["has already been taken"]
21
21
  end
22
22
 
23
23
  it "should not have a balance method" do
24
- lambda{Account.balance}.should raise_error(NoMethodError)
24
+ -> {Account.balance}.should raise_error(NoMethodError)
25
25
  end
26
26
 
27
27
  it "should have a trial balance" do
@@ -31,39 +31,37 @@ module DoubleDouble
31
31
 
32
32
  it "should report a trial balance of 0 with correct transactions (with a contrived example of transactions)" do
33
33
  # credit accounts
34
- liability = FactoryGirl.create(:liability)
35
- equity = FactoryGirl.create(:equity)
36
- revenue = FactoryGirl.create(:revenue)
37
- contra_asset = FactoryGirl.create(:asset, :contra => true)
38
- contra_expense = FactoryGirl.create(:expense, :contra => true)
34
+ FactoryGirl.create(:liability, name: 'liability acct')
35
+ FactoryGirl.create(:equity, name: 'equity acct')
36
+ FactoryGirl.create(:revenue, name: 'revenue acct')
37
+ FactoryGirl.create(:asset, name: 'contra asset acct', :contra => true)
38
+ FactoryGirl.create(:expense, name: 'contra expense acct', :contra => true)
39
39
  # debit accounts
40
- asset = FactoryGirl.create(:asset)
41
- expense = FactoryGirl.create(:expense)
42
- contra_liability = FactoryGirl.create(:liability, :contra => true)
43
- contra_equity = FactoryGirl.create(:equity, :contra => true)
44
- contra_revenue = FactoryGirl.create(:revenue, :contra => true)
45
-
46
- t = FactoryGirl.build(:transaction)
47
- t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: 100_000, account: liability)
48
- t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: 100_000, account: asset)
49
- t.save
50
- t = FactoryGirl.build(:transaction)
51
- t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: 1_000, account: equity)
52
- t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: 1_000, account: expense)
53
- t.save
54
- t = FactoryGirl.build(:transaction)
55
- t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: 40_404, account: revenue)
56
- t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: 40_404, account: contra_liability)
57
- t.save
58
- t = FactoryGirl.build(:transaction)
59
- t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: 2, account: contra_asset)
60
- t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: 2, account: contra_equity)
61
- t.save
62
- t = FactoryGirl.build(:transaction)
63
- t.credit_amounts << FactoryGirl.create(:credit_amt, transaction: t, amount: 333, account: contra_expense)
64
- t.debit_amounts << FactoryGirl.create(:debit_amt, transaction: t, amount: 333, account: contra_revenue)
65
- t.save
66
-
40
+ FactoryGirl.create(:asset, name: 'asset acct')
41
+ FactoryGirl.create(:expense, name: 'expense acct')
42
+ FactoryGirl.create(:liability, name: 'contra liability acct', :contra => true)
43
+ FactoryGirl.create(:equity, name: 'contra equity acct', :contra => true)
44
+ FactoryGirl.create(:revenue, name: 'contra revenue acct', :contra => true)
45
+ Transaction.create!(
46
+ description: 'spec transaction 01',
47
+ debits: [{account: 'liability acct', amount: 100_000}],
48
+ credits: [{account: 'asset acct', amount: 100_000}])
49
+ Transaction.create!(
50
+ description: 'spec transaction 02',
51
+ debits: [{account: 'equity acct', amount: 1_000}],
52
+ credits: [{account: 'expense acct', amount: 1_000}])
53
+ Transaction.create!(
54
+ description: 'spec transaction 03',
55
+ debits: [{account: 'revenue acct', amount: 40_404}],
56
+ credits: [{account: 'contra liability acct', amount: 40_404}])
57
+ Transaction.create!(
58
+ description: 'spec transaction 04',
59
+ debits: [{account: 'contra asset acct', amount: 2}],
60
+ credits: [{account: 'contra equity acct', amount: 2}])
61
+ Transaction.create!(
62
+ description: 'spec transaction 05',
63
+ debits: [{account: 'contra expense acct', amount: 333}],
64
+ credits: [{account: 'contra revenue acct', amount: 333}])
67
65
  Account.trial_balance.should == 0
68
66
  end
69
67
  end
@@ -2,7 +2,8 @@ module DoubleDouble
2
2
  describe Amount do
3
3
 
4
4
  it "should not allow creating an amount without a subtype" do
5
- amount = FactoryGirl.build(:amount)
5
+ cash = DoubleDouble::Asset.create!(name:'Cash', number: 11)
6
+ amount = DoubleDouble::Amount.new(amount: 50, account: cash)
6
7
  amount.should_not be_valid
7
8
  end
8
9
  end
@@ -5,8 +5,13 @@ module DoubleDouble
5
5
  let(:account_type) {:asset}
6
6
  end
7
7
 
8
- it_behaves_like "a left side account type" do
9
- let(:left_side_account_type) {:asset}
8
+ it_behaves_like "a normal debit account type" do
9
+ let(:normal_debit_account_type) {:asset}
10
+ end
11
+
12
+ it "should create a proper Asset account" do
13
+ -> { DoubleDouble::Asset.create! name: 'Asset acct', number: 20
14
+ }.should change(DoubleDouble::Asset, :count).by(1)
10
15
  end
11
16
  end
12
17
  end