plutus 0.7.2 → 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -32,14 +32,36 @@ module Plutus
32
32
  class Account < ActiveRecord::Base
33
33
  attr_accessible :name, :contra
34
34
 
35
- has_many :credit_amounts
36
- has_many :debit_amounts
35
+ has_many :credit_amounts, :extend => AmountsExtension
36
+ has_many :debit_amounts, :extend => AmountsExtension
37
37
  has_many :credit_transactions, :through => :credit_amounts, :source => :transaction
38
38
  has_many :debit_transactions, :through => :debit_amounts, :source => :transaction
39
39
 
40
40
  validates_presence_of :type, :name
41
41
  validates_uniqueness_of :name
42
42
 
43
+ # The credit balance for the account.
44
+ #
45
+ # @example
46
+ # >> asset.credits_balance
47
+ # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
48
+ #
49
+ # @return [BigDecimal] The decimal value credit balance
50
+ def credits_balance
51
+ credit_amounts.balance
52
+ end
53
+
54
+ # The debit balance for the account.
55
+ #
56
+ # @example
57
+ # >> asset.debits_balance
58
+ # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
59
+ #
60
+ # @return [BigDecimal] The decimal value credit balance
61
+ def debits_balance
62
+ debit_amounts.balance
63
+ end
64
+
43
65
  # The trial balance of all accounts in the system. This should always equal zero,
44
66
  # otherwise there is an error in the system.
45
67
  #
@@ -0,0 +1,17 @@
1
+ module Plutus
2
+ # Association extension for has_many :amounts relations. Internal.
3
+ module AmountsExtension
4
+ # Returns a sum of the referenced Amount objects.
5
+ def balance
6
+ balance = BigDecimal.new('0')
7
+ each do |amount_record|
8
+ if amount_record.amount
9
+ balance += amount_record.amount
10
+ else
11
+ balance = nil
12
+ end
13
+ end
14
+ return balance
15
+ end
16
+ end
17
+ end
@@ -9,36 +9,6 @@ module Plutus
9
9
  # @author Michael Bulat
10
10
  class Asset < Account
11
11
 
12
- # The credit balance for the account.
13
- #
14
- # @example
15
- # >> asset.credits_balance
16
- # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
17
- #
18
- # @return [BigDecimal] The decimal value credit balance
19
- def credits_balance
20
- credits_balance = BigDecimal.new('0')
21
- credit_amounts.each do |credit_amount|
22
- credits_balance += credit_amount.amount
23
- end
24
- return credits_balance
25
- end
26
-
27
- # The debit balance for the account.
28
- #
29
- # @example
30
- # >> asset.debits_balance
31
- # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
32
- #
33
- # @return [BigDecimal] The decimal value credit balance
34
- def debits_balance
35
- debits_balance = BigDecimal.new('0')
36
- debit_amounts.each do |debit_amount|
37
- debits_balance += debit_amount.amount
38
- end
39
- return debits_balance
40
- end
41
-
42
12
  # The balance of the account.
43
13
  #
44
14
  # Assets have normal debit balances, so the credits are subtracted from the debits
@@ -9,37 +9,6 @@ module Plutus
9
9
  # @author Michael Bulat
10
10
  class Equity < Account
11
11
 
12
- # The credit balance for the account.
13
- #
14
- # @example
15
- # >> equity.credits_balance
16
- # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
17
- #
18
- # @return [BigDecimal] The decimal value credit balance
19
- def credits_balance
20
- credits_balance = BigDecimal.new('0')
21
- credit_amounts.each do |credit_amount|
22
- credits_balance = credits_balance + credit_amount.amount
23
- end
24
- return credits_balance
25
- end
26
-
27
- # The debit balance for the account.
28
- #
29
- # @example
30
- # >> equity.debits_balance
31
- # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
32
- #
33
- # @return [BigDecimal] The decimal value credit balance
34
- def debits_balance
35
- debits_balance = BigDecimal.new('0')
36
- debit_amounts.each do |debit_amount|
37
- debits_balance = debits_balance + debit_amount.amount
38
- end
39
- return debits_balance
40
- end
41
-
42
-
43
12
  # The balance of the account.
44
13
  #
45
14
  # Equity accounts have normal credit balances, so the debits are subtracted from the credits
@@ -9,36 +9,6 @@ module Plutus
9
9
  # @author Michael Bulat
10
10
  class Expense < Account
11
11
 
12
- # The credit balance for the account.
13
- #
14
- # @example
15
- # >> expense.credits_balance
16
- # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
17
- #
18
- # @return [BigDecimal] The decimal value credit balance
19
- def credits_balance
20
- credits_balance = BigDecimal.new('0')
21
- credit_amounts.each do |credit_amount|
22
- credits_balance = credits_balance + credit_amount.amount
23
- end
24
- return credits_balance
25
- end
26
-
27
- # The debit balance for the account.
28
- #
29
- # @example
30
- # >> expense.debits_balance
31
- # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
32
- #
33
- # @return [BigDecimal] The decimal value credit balance
34
- def debits_balance
35
- debits_balance = BigDecimal.new('0')
36
- debit_amounts.each do |debit_amount|
37
- debits_balance = debits_balance + debit_amount.amount
38
- end
39
- return debits_balance
40
- end
41
-
42
12
  # The balance of the account.
43
13
  #
44
14
  # Expenses have normal debit balances, so the credits are subtracted from the debits
@@ -9,36 +9,6 @@ module Plutus
9
9
  # @author Michael Bulat
10
10
  class Liability < Account
11
11
 
12
- # The credit balance for the account.
13
- #
14
- # @example
15
- # >> liability.credits_balance
16
- # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
17
- #
18
- # @return [BigDecimal] The decimal value credit balance
19
- def credits_balance
20
- credits_balance = BigDecimal.new('0')
21
- credit_amounts.each do |credit_amount|
22
- credits_balance = credits_balance + credit_amount.amount
23
- end
24
- return credits_balance
25
- end
26
-
27
- # The debit balance for the account.
28
- #
29
- # @example
30
- # >> liability.debits_balance
31
- # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
32
- #
33
- # @return [BigDecimal] The decimal value credit balance
34
- def debits_balance
35
- debits_balance = BigDecimal.new('0')
36
- debit_amounts.each do |debit_amount|
37
- debits_balance = debits_balance + debit_amount.amount
38
- end
39
- return debits_balance
40
- end
41
-
42
12
  # The balance of the account.
43
13
  #
44
14
  # Liability accounts have normal credit balances, so the debits are subtracted from the credits
@@ -9,36 +9,6 @@ module Plutus
9
9
  # @author Michael Bulat
10
10
  class Revenue < Account
11
11
 
12
- # The credit balance for the account.
13
- #
14
- # @example
15
- # >> revenue.credits_balance
16
- # => #<BigDecimal:103259bb8,'0.3E4',4(12)>
17
- #
18
- # @return [BigDecimal] The decimal value credit balance
19
- def credits_balance
20
- credits_balance = BigDecimal.new('0')
21
- credit_amounts.each do |credit_amount|
22
- credits_balance = credits_balance + credit_amount.amount
23
- end
24
- return credits_balance
25
- end
26
-
27
- # The debit balance for the account.
28
- #
29
- # @example
30
- # >> revenue.debits_balance
31
- # => #<BigDecimal:103259bb8,'0.1E4',4(12)>
32
- #
33
- # @return [BigDecimal] The decimal value credit balance
34
- def debits_balance
35
- debits_balance = BigDecimal.new('0')
36
- debit_amounts.each do |debit_amount|
37
- debits_balance = debits_balance + debit_amount.amount
38
- end
39
- return debits_balance
40
- end
41
-
42
12
  # The balance of the account.
43
13
  #
44
14
  # Revenue accounts have normal credit balances, so the debits are subtracted from the credits
@@ -25,8 +25,8 @@ module Plutus
25
25
  attr_accessible :description, :commercial_document
26
26
 
27
27
  belongs_to :commercial_document, :polymorphic => true
28
- has_many :credit_amounts
29
- has_many :debit_amounts
28
+ has_many :credit_amounts, :extend => AmountsExtension
29
+ has_many :debit_amounts, :extend => AmountsExtension
30
30
  has_many :credit_accounts, :through => :credit_amounts, :source => :account
31
31
  has_many :debit_accounts, :through => :debit_amounts, :source => :account
32
32
 
@@ -71,13 +71,7 @@ module Plutus
71
71
  end
72
72
 
73
73
  def amounts_cancel?
74
- errors[:base] << "The credit and debit amounts are not equal" if difference_of_amounts != 0
75
- end
76
-
77
- def difference_of_amounts
78
- credit_amount_total = credit_amounts.inject(0) {|sum, credit_amount| sum + credit_amount.amount.to_i}
79
- debit_amount_total = debit_amounts.inject(0) {|sum, debit_amount| sum + debit_amount.amount.to_i}
80
- credit_amount_total - debit_amount_total
74
+ errors[:base] << "The credit and debit amounts are not equal" if credit_amounts.balance != debit_amounts.balance
81
75
  end
82
76
  end
83
77
  end
@@ -1,3 +1,3 @@
1
1
  module Plutus
2
- VERSION = "0.7.2"
2
+ VERSION = "0.7.4"
3
3
  end
@@ -2,63 +2,69 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Account do
5
+ let(:account) { FactoryGirl.build(:account) }
6
+ subject { account }
7
+
8
+ it { should_not be_valid } # must construct a child type instead
5
9
 
6
- it "should not allow creating an account without a subtype" do
7
- account = FactoryGirl.build(:account)
8
- account.should_not be_valid
10
+ describe "when using a child type" do
11
+ let(:account) { FactoryGirl.create(:account, type: "Finance::Asset") }
12
+ it { should be_valid }
13
+
14
+ it "should be unique per name" do
15
+ conflict = FactoryGirl.build(:account, name: account.name, type: account.type)
16
+ conflict.should_not be_valid
17
+ conflict.errors[:name].should == ["has already been taken"]
18
+ end
9
19
  end
20
+
21
+ it { should_not respond_to(:balance) }
22
+
23
+ describe ".trial_balance" do
24
+ subject { Account.trial_balance }
25
+ it { should be_kind_of BigDecimal }
26
+
27
+ context "when given no transactions" do
28
+ it { should == 0 }
29
+ end
30
+
31
+ context "when given correct transactions" do
32
+ before {
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)
39
+ # credit amounts
40
+ ca1 = FactoryGirl.build(:credit_amount, :account => liability, :amount => 100000)
41
+ ca2 = FactoryGirl.build(:credit_amount, :account => equity, :amount => 1000)
42
+ ca3 = FactoryGirl.build(:credit_amount, :account => revenue, :amount => 40404)
43
+ ca4 = FactoryGirl.build(:credit_amount, :account => contra_asset, :amount => 2)
44
+ ca5 = FactoryGirl.build(:credit_amount, :account => contra_expense, :amount => 333)
10
45
 
11
- it "should be unique per name" do
12
- FactoryGirl.create(:account, :name => "Test1", :type => "Plutus::Asset")
13
- account = FactoryGirl.build(:account, :name => "Test1", :type => "Plutus::Asset")
14
- account.should_not be_valid
15
- account.errors[:name].should == ["has already been taken"]
16
- end
17
-
18
- it "should not have a balance method" do
19
- lambda{Account.balance}.should raise_error(NoMethodError)
20
- end
46
+ # debit accounts
47
+ asset = FactoryGirl.create(:asset)
48
+ expense = FactoryGirl.create(:expense)
49
+ contra_liability = FactoryGirl.create(:liability, :contra => true)
50
+ contra_equity = FactoryGirl.create(:equity, :contra => true)
51
+ contra_revenue = FactoryGirl.create(:revenue, :contra => true)
52
+ # debit amounts
53
+ da1 = FactoryGirl.build(:debit_amount, :account => asset, :amount => 100000)
54
+ da2 = FactoryGirl.build(:debit_amount, :account => expense, :amount => 1000)
55
+ da3 = FactoryGirl.build(:debit_amount, :account => contra_liability, :amount => 40404)
56
+ da4 = FactoryGirl.build(:debit_amount, :account => contra_equity, :amount => 2)
57
+ da5 = FactoryGirl.build(:debit_amount, :account => contra_revenue, :amount => 333)
21
58
 
22
- it "should have a trial balance" do
23
- Account.should respond_to(:trial_balance)
24
- Account.trial_balance.should be_kind_of(BigDecimal)
59
+ FactoryGirl.create(:transaction, :credit_amounts => [ca1], :debit_amounts => [da1])
60
+ FactoryGirl.create(:transaction, :credit_amounts => [ca2], :debit_amounts => [da2])
61
+ FactoryGirl.create(:transaction, :credit_amounts => [ca3], :debit_amounts => [da3])
62
+ FactoryGirl.create(:transaction, :credit_amounts => [ca4], :debit_amounts => [da4])
63
+ FactoryGirl.create(:transaction, :credit_amounts => [ca5], :debit_amounts => [da5])
64
+ }
65
+
66
+ it { should == 0 }
67
+ end
25
68
  end
26
-
27
- it "should report a trial balance of 0 with correct transactions" do
28
- # credit accounts
29
- liability = FactoryGirl.create(:liability)
30
- equity = FactoryGirl.create(:equity)
31
- revenue = FactoryGirl.create(:revenue)
32
- contra_asset = FactoryGirl.create(:asset, :contra => true)
33
- contra_expense = FactoryGirl.create(:expense, :contra => true)
34
- # credit amounts
35
- ca1 = FactoryGirl.build(:credit_amount, :account => liability, :amount => 100000)
36
- ca2 = FactoryGirl.build(:credit_amount, :account => equity, :amount => 1000)
37
- ca3 = FactoryGirl.build(:credit_amount, :account => revenue, :amount => 40404)
38
- ca4 = FactoryGirl.build(:credit_amount, :account => contra_asset, :amount => 2)
39
- ca5 = FactoryGirl.build(:credit_amount, :account => contra_expense, :amount => 333)
40
-
41
- # debit accounts
42
- asset = FactoryGirl.create(:asset)
43
- expense = FactoryGirl.create(:expense)
44
- contra_liability = FactoryGirl.create(:liability, :contra => true)
45
- contra_equity = FactoryGirl.create(:equity, :contra => true)
46
- contra_revenue = FactoryGirl.create(:revenue, :contra => true)
47
- # debit amounts
48
- da1 = FactoryGirl.build(:debit_amount, :account => asset, :amount => 100000)
49
- da2 = FactoryGirl.build(:debit_amount, :account => expense, :amount => 1000)
50
- da3 = FactoryGirl.build(:debit_amount, :account => contra_liability, :amount => 40404)
51
- da4 = FactoryGirl.build(:debit_amount, :account => contra_equity, :amount => 2)
52
- da5 = FactoryGirl.build(:debit_amount, :account => contra_revenue, :amount => 333)
53
-
54
- FactoryGirl.create(:transaction, :credit_amounts => [ca1], :debit_amounts => [da1])
55
- FactoryGirl.create(:transaction, :credit_amounts => [ca2], :debit_amounts => [da2])
56
- FactoryGirl.create(:transaction, :credit_amounts => [ca3], :debit_amounts => [da3])
57
- FactoryGirl.create(:transaction, :credit_amounts => [ca4], :debit_amounts => [da4])
58
- FactoryGirl.create(:transaction, :credit_amounts => [ca5], :debit_amounts => [da5])
59
-
60
- Account.trial_balance.should == 0
61
- end
62
-
63
69
  end
64
70
  end
@@ -2,11 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Amount do
5
-
6
- it "should not allow creating an amount without a subtype" do
7
- amount = FactoryGirl.build(:amount)
8
- amount.should_not be_valid
9
- end
10
-
5
+ subject { FactoryGirl.build(:amount) }
6
+ it { should_not be_valid } # construct a child class instead
11
7
  end
12
8
  end
@@ -2,52 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Asset do
5
-
6
- it "should allow creating an asset account" do
7
- asset = FactoryGirl.create(:asset)
8
- end
9
-
10
- it "should report a balance for the asset account" do
11
- asset = FactoryGirl.create(:asset)
12
- FactoryGirl.create(:debit_amount, :account => asset)
13
- asset.balance.should > 0
14
- asset.balance.should be_kind_of(BigDecimal)
15
- end
16
-
17
- it "should report a balance for the class of accounts" do
18
- asset = FactoryGirl.create(:asset)
19
- FactoryGirl.create(:debit_amount, :account => asset)
20
- Asset.should respond_to(:balance)
21
- Asset.balance.should > 0
22
- Asset.balance.should be_kind_of(BigDecimal)
23
- end
24
-
25
- it "should not report a trial balance" do
26
- lambda{Asset.trial_balance}.should raise_error(NoMethodError)
27
- end
28
-
29
- it "should not be valid without a name" do
30
- asset = FactoryGirl.build(:asset, :name => nil)
31
- asset.should_not be_valid
32
- end
33
-
34
- it "should have many credit transactions" do
35
- asset = Factory(:asset)
36
- asset.should respond_to(:credit_transactions)
37
- end
38
-
39
- it "should have many debit transactions" do
40
- asset = Factory(:asset)
41
- asset.should respond_to(:debit_transactions)
42
- end
43
-
44
- it "a contra account should reverse the normal balance" do
45
- contra_asset = Factory(:asset, :contra => true)
46
- # the odd amount below is because factories create an asset debit_amount
47
- FactoryGirl.create(:credit_amount, :account => contra_asset, :amount => 473)
48
- contra_asset.balance.should > 0
49
- Asset.balance.should == 0
50
- end
51
-
5
+ it_behaves_like 'a Plutus::Account subtype', kind: :asset, normal_balance: :debit
52
6
  end
53
7
  end
@@ -2,21 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe CreditAmount do
5
-
6
- it "should be invalid without an amount" do
7
- credit_amount = FactoryGirl.build(:credit_amount, :amount => nil)
8
- credit_amount.should_not be_valid
9
- end
10
-
11
- it "should not be valid without a transaction" do
12
- credit_amount = FactoryGirl.build(:credit_amount, :transaction => nil)
13
- credit_amount.should_not be_valid
14
- end
15
-
16
- it "should not be valid without an account" do
17
- credit_amount = FactoryGirl.build(:credit_amount, :account => nil)
18
- credit_amount.should_not be_valid
19
- end
20
-
5
+ it_behaves_like 'a Plutus::Amount subtype', kind: :credit_amount
21
6
  end
22
7
  end
@@ -2,21 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe DebitAmount do
5
-
6
- it "should be invalid without an amount" do
7
- debit_amount = FactoryGirl.build(:debit_amount, :amount => nil)
8
- debit_amount.should_not be_valid
9
- end
10
-
11
- it "should not be valid without a transaction" do
12
- debit_amount = FactoryGirl.build(:debit_amount, :transaction => nil)
13
- debit_amount.should_not be_valid
14
- end
15
-
16
- it "should not be valid without an account" do
17
- debit_amount = FactoryGirl.build(:debit_amount, :account => nil)
18
- debit_amount.should_not be_valid
19
- end
20
-
5
+ it_behaves_like 'a Plutus::Amount subtype', kind: :debit_amount
21
6
  end
22
7
  end
@@ -2,53 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Equity do
5
-
6
- it "should allow creating an equity account" do
7
- equity = FactoryGirl.create(:equity)
8
- end
9
-
10
- it "should report a balance for the equity account" do
11
- equity = FactoryGirl.create(:equity)
12
- FactoryGirl.create(:credit_amount, :account => equity)
13
- equity.balance.should > 0
14
- equity.balance.should be_kind_of(BigDecimal)
15
- end
16
-
17
- it "should report a balance for the class of accounts" do
18
- equity = FactoryGirl.create(:equity)
19
- FactoryGirl.create(:credit_amount, :account => equity)
20
- Equity.should respond_to(:balance)
21
- Equity.balance.should > 0
22
- Equity.balance.should be_kind_of(BigDecimal)
23
- end
24
-
25
- it "should not report a trial balance" do
26
- lambda{Equity.trial_balance}.should raise_error(NoMethodError)
27
- end
28
-
29
- it "should not be valid without a name" do
30
- equity = FactoryGirl.build(:equity, :name => nil)
31
- equity.should_not be_valid
32
- end
33
-
34
- it "should have many credit transactions" do
35
- equity = Factory(:equity)
36
- equity.should respond_to(:credit_transactions)
37
- end
38
-
39
- it "should have many debit transactions" do
40
- equity = Factory(:equity)
41
- equity.should respond_to(:debit_transactions)
42
- end
43
-
44
- it "a contra account should reverse the normal balance" do
45
- equity = FactoryGirl.create(:equity)
46
- contra_equity = Factory(:equity, :contra => true)
47
- FactoryGirl.create(:credit_amount, :account => equity)
48
- FactoryGirl.create(:debit_amount, :account => contra_equity)
49
- contra_equity.balance.should > 0
50
- Equity.balance.should == 0
51
- end
52
-
5
+ it_behaves_like 'a Plutus::Account subtype', kind: :equity, normal_balance: :credit
53
6
  end
54
7
  end
@@ -2,53 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Expense do
5
-
6
- it "should allow creating an expense account" do
7
- expense = FactoryGirl.create(:expense)
8
- end
9
-
10
- it "should report a balance for the expense account" do
11
- expense = FactoryGirl.create(:expense)
12
- FactoryGirl.create(:debit_amount, :account => expense)
13
- expense.balance.should > 0
14
- expense.balance.should be_kind_of(BigDecimal)
15
- end
16
-
17
- it "should report a balance for the class of accounts" do
18
- expense = FactoryGirl.create(:expense)
19
- FactoryGirl.create(:debit_amount, :account => expense)
20
- Expense.should respond_to(:balance)
21
- Expense.balance.should > 0
22
- Expense.balance.should be_kind_of(BigDecimal)
23
- end
24
-
25
- it "should not report a trial balance" do
26
- lambda{Expense.trial_balance}.should raise_error(NoMethodError)
27
- end
28
-
29
- it "should not be valid without a name" do
30
- expense = FactoryGirl.build(:expense, :name => nil)
31
- expense.should_not be_valid
32
- end
33
-
34
- it "should have many credit transactions" do
35
- expense = Factory(:expense)
36
- expense.should respond_to(:credit_transactions)
37
- end
38
-
39
- it "should have many debit transactions" do
40
- expense = Factory(:expense)
41
- expense.should respond_to(:debit_transactions)
42
- end
43
-
44
- it "a contra account should reverse the normal balance" do
45
- expense = FactoryGirl.create(:expense)
46
- contra_expense = Factory(:expense, :contra => true)
47
- FactoryGirl.create(:debit_amount, :account => expense)
48
- FactoryGirl.create(:credit_amount, :account => contra_expense)
49
- contra_expense.balance.should > 0
50
- Expense.balance.should == 0
51
- end
52
-
5
+ it_behaves_like 'a Plutus::Account subtype', kind: :expense, normal_balance: :debit
53
6
  end
54
7
  end
@@ -2,53 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Liability do
5
-
6
- it "should allow creating an liability account" do
7
- liability = FactoryGirl.create(:liability)
8
- end
9
-
10
- it "should report a balance for the liability account" do
11
- liability = FactoryGirl.create(:liability)
12
- FactoryGirl.create(:credit_amount, :account => liability)
13
- liability.balance.should > 0
14
- liability.balance.should be_kind_of(BigDecimal)
15
- end
16
-
17
- it "should report a balance for the class of accounts" do
18
- liability = FactoryGirl.create(:liability)
19
- FactoryGirl.create(:credit_amount, :account => liability)
20
- Liability.should respond_to(:balance)
21
- Liability.balance.should > 0
22
- Liability.balance.should be_kind_of(BigDecimal)
23
- end
24
-
25
- it "should not report a trial balance" do
26
- lambda{Liability.trial_balance}.should raise_error(NoMethodError)
27
- end
28
-
29
- it "should not be valid without a name" do
30
- liability = FactoryGirl.build(:liability, :name => nil)
31
- liability.should_not be_valid
32
- end
33
-
34
- it "should have many credit transactions" do
35
- liability = Factory(:liability)
36
- liability.should respond_to(:credit_transactions)
37
- end
38
-
39
- it "should have many debit transactions" do
40
- liability = Factory(:liability)
41
- liability.should respond_to(:debit_transactions)
42
- end
43
-
44
- it "a contra account should reverse the normal balance" do
45
- liability = FactoryGirl.create(:liability)
46
- contra_liability = Factory(:liability, :contra => true)
47
- FactoryGirl.create(:credit_amount, :account => liability)
48
- FactoryGirl.create(:debit_amount, :account => contra_liability)
49
- contra_liability.balance.should > 0
50
- Liability.balance.should == 0
51
- end
52
-
5
+ it_behaves_like 'a Plutus::Account subtype', kind: :liability, normal_balance: :credit
53
6
  end
54
7
  end
@@ -2,52 +2,6 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Revenue do
5
-
6
- it "should allow creating an revenue account" do
7
- revenue = FactoryGirl.create(:revenue)
8
- end
9
-
10
- it "should report a balance for the revenue account" do
11
- revenue = FactoryGirl.create(:revenue)
12
- FactoryGirl.create(:credit_amount, :account => revenue)
13
- revenue.balance.should > 0
14
- revenue.balance.should be_kind_of(BigDecimal)
15
- end
16
-
17
- it "should report a balance for the class of accounts" do
18
- revenue = FactoryGirl.create(:revenue)
19
- FactoryGirl.create(:credit_amount, :account => revenue)
20
- Revenue.should respond_to(:balance)
21
- Revenue.balance.should > 0
22
- Revenue.balance.should be_kind_of(BigDecimal)
23
- end
24
-
25
- it "should not report a trial balance" do
26
- lambda{Revenue.trial_balance}.should raise_error(NoMethodError)
27
- end
28
-
29
- it "should not be valid without a name" do
30
- revenue = FactoryGirl.build(:revenue, :name => nil)
31
- revenue.should_not be_valid
32
- end
33
-
34
- it "should have many credit transactions" do
35
- revenue = Factory(:revenue)
36
- revenue.should respond_to(:credit_transactions)
37
- end
38
-
39
- it "should have many debit transactions" do
40
- revenue = Factory(:revenue)
41
- revenue.should respond_to(:debit_transactions)
42
- end
43
-
44
- it "a contra account should reverse the normal balance" do
45
- contra_revenue = Factory(:revenue, :contra => true)
46
- # the odd amount below is because factories create an revenue debit_amount
47
- FactoryGirl.create(:debit_amount, :account => contra_revenue, :amount => 473)
48
- contra_revenue.balance.should > 0
49
- Revenue.balance.should == 0
50
- end
51
-
5
+ it_behaves_like 'a Plutus::Account subtype', kind: :revenue, normal_balance: :credit
52
6
  end
53
7
  end
@@ -2,68 +2,76 @@ require 'spec_helper'
2
2
 
3
3
  module Plutus
4
4
  describe Transaction do
5
+ let(:transaction) { FactoryGirl.build(:transaction) }
6
+ subject { transaction }
5
7
 
6
- it "should create a transaction" do
7
- transaction = FactoryGirl.build(:transaction_with_credit_and_debit)
8
- transaction.save!
9
- end
8
+ it { should_not be_valid }
10
9
 
11
- it "should not be valid without a credit amount" do
12
- transaction = FactoryGirl.build(:transaction)
13
- transaction.debit_amounts << FactoryGirl.build(:debit_amount, :transaction => transaction)
14
- transaction.should_not be_valid
15
- transaction.errors['base'].should include("Transaction must have at least one credit amount")
10
+ context "with credit and debit" do
11
+ let(:transaction) { FactoryGirl.build(:transaction_with_credit_and_debit) }
12
+ it { should be_valid }
13
+
14
+ it "should require a description" do
15
+ transaction.description = nil
16
+ transaction.should_not be_valid
17
+ end
16
18
  end
17
19
 
18
- it "should not be valid with an invalid credit amount" do
19
- transaction = FactoryGirl.build(:transaction)
20
- transaction.debit_amounts << FactoryGirl.build(:debit_amount, :transaction => transaction)
21
- transaction.credit_amounts << FactoryGirl.build(:credit_amount, :transaction => transaction, :amount => nil)
22
- transaction.should_not be_valid
23
- transaction.errors[:credit_amounts].should == ["is invalid"]
24
- end
20
+ context "with a debit" do
21
+ before {
22
+ transaction.debit_amounts << FactoryGirl.build(:debit_amount, transaction: transaction)
23
+ }
24
+ it { should_not be_valid }
25
25
 
26
- it "should not be valid without a debit amount" do
27
- transaction = FactoryGirl.build(:transaction)
28
- transaction.credit_amounts << FactoryGirl.build(:credit_amount, :transaction => transaction)
29
- transaction.should_not be_valid
30
- transaction.errors['base'].should include("Transaction must have at least one debit amount")
26
+ context "with an invalid credit" do
27
+ before {
28
+ transaction.credit_amounts << FactoryGirl.build(:credit_amount, transaction: transaction, amount: nil)
29
+ }
30
+ it { should_not be_valid }
31
+ end
31
32
  end
32
33
 
33
- it "should not be valid with an invalid debit amount" do
34
- transaction = FactoryGirl.build(:transaction)
35
- transaction.credit_amounts << FactoryGirl.build(:credit_amount, :transaction => transaction)
36
- transaction.debit_amounts << FactoryGirl.build(:debit_amount, :transaction => transaction, :amount => nil)
37
- transaction.should_not be_valid
38
- transaction.errors[:debit_amounts].should == ["is invalid"]
39
- end
34
+ context "with a credit" do
35
+ before {
36
+ transaction.credit_amounts << FactoryGirl.build(:credit_amount, transaction: transaction)
37
+ }
38
+ it { should_not be_valid }
40
39
 
41
- it "should not be valid without a description" do
42
- transaction = FactoryGirl.build(:transaction_with_credit_and_debit, :description => nil)
43
- transaction.should_not be_valid
44
- transaction.errors[:description].should == ["can't be blank"]
40
+ context "with an invalid debit" do
41
+ before {
42
+ transaction.debit_amounts << FactoryGirl.build(:debit_amount, transaction: transaction, amount: nil)
43
+ }
44
+ it { should_not be_valid }
45
+ end
45
46
  end
46
47
 
47
48
  it "should require the debit and credit amounts to cancel" do
48
- transaction = FactoryGirl.build(:transaction)
49
49
  transaction.credit_amounts << FactoryGirl.build(:credit_amount, :amount => 100, :transaction => transaction)
50
50
  transaction.debit_amounts << FactoryGirl.build(:debit_amount, :amount => 200, :transaction => transaction)
51
51
  transaction.should_not be_valid
52
52
  transaction.errors['base'].should == ["The credit and debit amounts are not equal"]
53
53
  end
54
54
 
55
+ it "should require the debit and credit amounts to cancel even with fractions" do
56
+ transaction = FactoryGirl.build(:transaction)
57
+ transaction.credit_amounts << FactoryGirl.build(:credit_amount, :amount => 100.1, :transaction => transaction)
58
+ transaction.debit_amounts << FactoryGirl.build(:debit_amount, :amount => 100.2, :transaction => transaction)
59
+ transaction.should_not be_valid
60
+ transaction.errors['base'].should == ["The credit and debit amounts are not equal"]
61
+ end
62
+
55
63
  it "should have a polymorphic commercial document associations" do
56
64
  mock_document = FactoryGirl.create(:asset) # one would never do this, but it allows us to not require a migration for the test
57
- transaction = FactoryGirl.build(:transaction_with_credit_and_debit, :commercial_document => mock_document)
58
- transaction.save
65
+ transaction = FactoryGirl.build(:transaction_with_credit_and_debit, commercial_document: mock_document)
66
+ transaction.save!
59
67
  saved_transaction = Transaction.find(transaction.id)
60
68
  saved_transaction.commercial_document.should == mock_document
61
69
  end
62
70
 
63
71
  it "should allow building a transaction and credit and debits with a hash" do
64
- FactoryGirl.create(:asset, :name => "Accounts Receivable")
65
- FactoryGirl.create(:revenue, :name => "Sales Revenue")
66
- FactoryGirl.create(:liability, :name => "Sales Tax Payable")
72
+ FactoryGirl.create(:asset, name: "Accounts Receivable")
73
+ FactoryGirl.create(:revenue, name: "Sales Revenue")
74
+ FactoryGirl.create(:liability, name: "Sales Tax Payable")
67
75
  mock_document = FactoryGirl.create(:asset)
68
76
  transaction = Transaction.build(
69
77
  description: "Sold some widgets",
@@ -73,8 +81,8 @@ module Plutus
73
81
  credits: [
74
82
  {account: "Sales Revenue", amount: 45},
75
83
  {account: "Sales Tax Payable", amount: 5}])
76
- transaction.should be_valid
77
- transaction.save
84
+ transaction.save!
85
+
78
86
  saved_transaction = Transaction.find(transaction.id)
79
87
  saved_transaction.commercial_document.should == mock_document
80
88
  end
data/spec/spec_helper.rb CHANGED
@@ -9,6 +9,7 @@ $: << File.expand_path(File.dirname(__FILE__) + '/../lib/')
9
9
  require 'plutus'
10
10
 
11
11
  Dir[File.expand_path(File.join(File.dirname(__FILE__),'factories','**','*.rb'))].each {|f| require f}
12
+ Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}
12
13
 
13
14
  RSpec.configure do |config|
14
15
  config.use_transactional_fixtures = true
@@ -0,0 +1,56 @@
1
+ shared_examples_for 'a Plutus::Account subtype' do |elements|
2
+ let(:contra) { false }
3
+ let(:account) { FactoryGirl.create(elements[:kind], contra: contra)}
4
+ subject { account }
5
+
6
+ describe "class methods" do
7
+ subject { account.class }
8
+ its(:balance) { should be_kind_of(BigDecimal) }
9
+ describe "trial_balance" do
10
+ it "should raise NoMethodError" do
11
+ lambda { subject.trial_balance }.should raise_error NoMethodError
12
+ end
13
+ end
14
+ end
15
+
16
+ describe "instance methods" do
17
+ its(:balance) { should be_kind_of(BigDecimal) }
18
+
19
+ it { should respond_to(:credit_transactions) }
20
+ it { should respond_to(:debit_transactions) }
21
+ end
22
+
23
+ it "requires a name" do
24
+ account.name = nil
25
+ account.should_not be_valid
26
+ end
27
+
28
+ # Figure out which way credits and debits should apply
29
+ if elements[:normal_balance] == :debit
30
+ debit_condition = :>
31
+ credit_condition = :<
32
+ else
33
+ credit_condition = :>
34
+ debit_condition = :<
35
+ end
36
+
37
+ describe "when given a debit" do
38
+ before { FactoryGirl.create(:debit_amount, account: account) }
39
+ its(:balance) { should be.send(debit_condition, 0) }
40
+
41
+ describe "on a contra account" do
42
+ let(:contra) { true }
43
+ its(:balance) { should be.send(credit_condition, 0) }
44
+ end
45
+ end
46
+
47
+ describe "when given a credit" do
48
+ before { FactoryGirl.create(:credit_amount, account: account) }
49
+ its(:balance) { should be.send(credit_condition, 0) }
50
+
51
+ describe "on a contra account" do
52
+ let(:contra) { true }
53
+ its(:balance) { should be.send(debit_condition, 0) }
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,21 @@
1
+ shared_examples_for 'a Plutus::Amount subtype' do |elements|
2
+ let(:amount) { FactoryGirl.build(elements[:kind]) }
3
+ subject { amount }
4
+
5
+ it { should be_valid }
6
+
7
+ it "should require an amount" do
8
+ amount.amount = nil
9
+ amount.should_not be_valid
10
+ end
11
+
12
+ it "should require a transaction" do
13
+ amount.transaction = nil
14
+ amount.should_not be_valid
15
+ end
16
+
17
+ it "should require an account" do
18
+ amount.account = nil
19
+ amount.should_not be_valid
20
+ end
21
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: plutus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.2
4
+ version: 0.7.4
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: 2012-09-05 00:00:00.000000000 Z
12
+ date: 2013-04-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rails
@@ -167,62 +167,65 @@ extra_rdoc_files:
167
167
  - LICENSE
168
168
  - README.markdown
169
169
  files:
170
- - app/assets/javascripts/plutus/application.js
171
- - app/assets/stylesheets/plutus/application.css
172
- - app/assets/stylesheets/plutus/main.css.scss
173
- - app/controllers/plutus/accounts_controller.rb
174
- - app/controllers/plutus/transactions_controller.rb
175
- - app/models/plutus/account.rb
176
- - app/models/plutus/amount.rb
177
170
  - app/models/plutus/asset.rb
178
- - app/models/plutus/credit_amount.rb
179
- - app/models/plutus/debit_amount.rb
180
171
  - app/models/plutus/equity.rb
181
- - app/models/plutus/expense.rb
172
+ - app/models/plutus/debit_amount.rb
182
173
  - app/models/plutus/liability.rb
183
- - app/models/plutus/revenue.rb
174
+ - app/models/plutus/amount.rb
175
+ - app/models/plutus/amounts_extension.rb
176
+ - app/models/plutus/credit_amount.rb
177
+ - app/models/plutus/account.rb
178
+ - app/models/plutus/expense.rb
184
179
  - app/models/plutus/transaction.rb
185
- - app/views/plutus/accounts/index.html.erb
186
- - app/views/plutus/accounts/show.html.erb
180
+ - app/models/plutus/revenue.rb
187
181
  - app/views/plutus/transactions/index.html.erb
188
182
  - app/views/plutus/transactions/show.html.erb
189
- - config/backtrace_silencers.rb
183
+ - app/views/plutus/accounts/index.html.erb
184
+ - app/views/plutus/accounts/show.html.erb
185
+ - app/assets/javascripts/plutus/application.js
186
+ - app/assets/stylesheets/plutus/main.css.scss
187
+ - app/assets/stylesheets/plutus/application.css
188
+ - app/controllers/plutus/accounts_controller.rb
189
+ - app/controllers/plutus/transactions_controller.rb
190
+ - config/session_store.rb
191
+ - config/secret_token.rb
190
192
  - config/database.yml
191
193
  - config/inflections.rb
192
- - config/mime_types.rb
194
+ - config/backtrace_silencers.rb
193
195
  - config/routes.rb
194
- - config/secret_token.rb
195
- - config/session_store.rb
196
- - lib/generators/plutus/plutus_generator.rb
197
- - lib/generators/plutus/templates/migration.rb
198
- - lib/generators/plutus/USAGE
199
- - lib/plutus/version.rb
196
+ - config/mime_types.rb
200
197
  - lib/plutus.rb
198
+ - lib/plutus/version.rb
199
+ - lib/generators/plutus/USAGE
200
+ - lib/generators/plutus/templates/migration.rb
201
+ - lib/generators/plutus/plutus_generator.rb
201
202
  - LICENSE
202
203
  - Rakefile
203
204
  - README.markdown
204
- - spec/controllers/accounts_controller_spec.rb
205
- - spec/controllers/transactions_controller_spec.rb
206
- - spec/factories/account_factory.rb
207
- - spec/factories/amount_factory.rb
208
- - spec/factories/transaction_factory.rb
209
- - spec/lib/plutus_spec.rb
205
+ - spec/spec_helper.rb
206
+ - spec/models/transaction_spec.rb
207
+ - spec/models/equity_spec.rb
210
208
  - spec/models/account_spec.rb
211
- - spec/models/amount_spec.rb
212
- - spec/models/asset_spec.rb
209
+ - spec/models/revenue_spec.rb
213
210
  - spec/models/credit_amount_spec.rb
214
- - spec/models/debit_amount_spec.rb
215
- - spec/models/equity_spec.rb
216
211
  - spec/models/expense_spec.rb
212
+ - spec/models/debit_amount_spec.rb
217
213
  - spec/models/liability_spec.rb
218
- - spec/models/revenue_spec.rb
219
- - spec/models/transaction_spec.rb
220
- - spec/rcov.opts
221
- - spec/routing/accounts_routing_spec.rb
222
- - spec/routing/transactions_routing_spec.rb
214
+ - spec/models/asset_spec.rb
215
+ - spec/models/amount_spec.rb
216
+ - spec/support/amount_shared_examples.rb
217
+ - spec/support/account_shared_examples.rb
223
218
  - spec/schema.rb
219
+ - spec/routing/transactions_routing_spec.rb
220
+ - spec/routing/accounts_routing_spec.rb
221
+ - spec/rcov.opts
222
+ - spec/factories/transaction_factory.rb
223
+ - spec/factories/amount_factory.rb
224
+ - spec/factories/account_factory.rb
225
+ - spec/controllers/accounts_controller_spec.rb
226
+ - spec/controllers/transactions_controller_spec.rb
227
+ - spec/lib/plutus_spec.rb
224
228
  - spec/spec.opts
225
- - spec/spec_helper.rb
226
229
  homepage: http://github.com/mbulat/plutus
227
230
  licenses: []
228
231
  post_install_message:
@@ -248,26 +251,28 @@ signing_key:
248
251
  specification_version: 3
249
252
  summary: A Plugin providing a Double Entry Accounting Engine for Rails
250
253
  test_files:
251
- - spec/controllers/accounts_controller_spec.rb
252
- - spec/controllers/transactions_controller_spec.rb
253
- - spec/factories/account_factory.rb
254
- - spec/factories/amount_factory.rb
255
- - spec/factories/transaction_factory.rb
256
- - spec/lib/plutus_spec.rb
254
+ - spec/spec_helper.rb
255
+ - spec/models/transaction_spec.rb
256
+ - spec/models/equity_spec.rb
257
257
  - spec/models/account_spec.rb
258
- - spec/models/amount_spec.rb
259
- - spec/models/asset_spec.rb
258
+ - spec/models/revenue_spec.rb
260
259
  - spec/models/credit_amount_spec.rb
261
- - spec/models/debit_amount_spec.rb
262
- - spec/models/equity_spec.rb
263
260
  - spec/models/expense_spec.rb
261
+ - spec/models/debit_amount_spec.rb
264
262
  - spec/models/liability_spec.rb
265
- - spec/models/revenue_spec.rb
266
- - spec/models/transaction_spec.rb
267
- - spec/rcov.opts
268
- - spec/routing/accounts_routing_spec.rb
269
- - spec/routing/transactions_routing_spec.rb
263
+ - spec/models/asset_spec.rb
264
+ - spec/models/amount_spec.rb
265
+ - spec/support/amount_shared_examples.rb
266
+ - spec/support/account_shared_examples.rb
270
267
  - spec/schema.rb
268
+ - spec/routing/transactions_routing_spec.rb
269
+ - spec/routing/accounts_routing_spec.rb
270
+ - spec/rcov.opts
271
+ - spec/factories/transaction_factory.rb
272
+ - spec/factories/amount_factory.rb
273
+ - spec/factories/account_factory.rb
274
+ - spec/controllers/accounts_controller_spec.rb
275
+ - spec/controllers/transactions_controller_spec.rb
276
+ - spec/lib/plutus_spec.rb
271
277
  - spec/spec.opts
272
- - spec/spec_helper.rb
273
278
  has_rdoc: