plutus 0.7.2 → 0.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: