double_entry 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e815a7e5aabf260a4697a11f7685d362c017cdfb
4
- data.tar.gz: 416041a85f823156b3211c58edcb751a07ea60d1
3
+ metadata.gz: bee621c780c82e734a95964749650675683f1460
4
+ data.tar.gz: 326d9d02768905beede8b785215b1eb164a4c8cc
5
5
  SHA512:
6
- metadata.gz: 0b36f7c934a87f36ec0250d360b043e4a98c033bd74289eaa9cade1e120f35fa438376629bb8d099de122481f28411ecc4a6890641646e56ba49afad52d99312
7
- data.tar.gz: 4c8a843ba84218611d2545b161f58cddbb03617c94564027f02e85957e6754d299d5381f37527e5cc0f7b3e58e05a4821fb27c82883b750fe139db61e901cf0c
6
+ metadata.gz: e98f6f1a3b11a5bd9f8b4e384eb3dff8a6cd56b40ae3f8b430565fdbc601e3532a6cc95f8fdacc469457425533745d99a7b6cc8accaf4a6dd67b0d2b27ed41b0
7
+ data.tar.gz: 945ba3173e2b170e1cee74fcb89e31f8ce4a2245fa75dbe6efa267850196c7470495ffd3b4f47bae23acef6aa89722e7ca0379a53ff927ca7f8e49d9727fdb48
@@ -3,13 +3,23 @@ module DoubleEntry
3
3
  class Account
4
4
 
5
5
  class << self
6
- attr_writer :accounts
6
+ attr_writer :accounts, :scope_identifier_max_length, :account_identifier_max_length
7
7
 
8
8
  # @api private
9
9
  def accounts
10
10
  @accounts ||= Set.new
11
11
  end
12
12
 
13
+ # @api private
14
+ def scope_identifier_max_length
15
+ @scope_identifier_max_length ||= 23
16
+ end
17
+
18
+ # @api private
19
+ def account_identifier_max_length
20
+ @account_identifier_max_length ||= 31
21
+ end
22
+
13
23
  # @api private
14
24
  def account(identifier, options = {})
15
25
  account = accounts.find(identifier, options[:scope].present?)
@@ -128,7 +138,12 @@ module DoubleEntry
128
138
  private
129
139
 
130
140
  def ensure_scope_is_valid
131
- scope_identity
141
+ identity = scope_identity
142
+ if identity && identity.length > Account.scope_identifier_max_length
143
+ raise ScopeIdentifierTooLongError.new(
144
+ "scope identifier '#{identity}' is too long. Please limit it to #{Account.scope_identifier_max_length} characters."
145
+ )
146
+ end
132
147
  end
133
148
  end
134
149
 
@@ -139,6 +154,11 @@ module DoubleEntry
139
154
  @scope_identifier = args[:scope_identifier]
140
155
  @positive_only = args[:positive_only]
141
156
  @currency = args[:currency] || Money.default_currency
157
+ if identifier.length > Account.account_identifier_max_length
158
+ raise AccountIdentifierTooLongError.new(
159
+ "account identifier '#{identifier}' is too long. Please limit it to #{Account.account_identifier_max_length} characters."
160
+ )
161
+ end
142
162
  end
143
163
 
144
164
  def scoped?
@@ -3,8 +3,24 @@ module DoubleEntry
3
3
  include Configurable
4
4
 
5
5
  class Configuration
6
- delegate :accounts, :accounts=, :to => "DoubleEntry::Account"
7
- delegate :transfers, :transfers=, :to => "DoubleEntry::Transfer"
6
+
7
+ delegate(
8
+ :accounts,
9
+ :accounts=,
10
+ :scope_identifier_max_length,
11
+ :scope_identifier_max_length=,
12
+ :account_identifier_max_length,
13
+ :account_identifier_max_length=,
14
+ :to => "DoubleEntry::Account",
15
+ )
16
+
17
+ delegate(
18
+ :transfers,
19
+ :transfers=,
20
+ :code_max_length,
21
+ :code_max_length=,
22
+ :to => "DoubleEntry::Transfer",
23
+ )
8
24
 
9
25
  def define_accounts
10
26
  yield accounts
@@ -1,8 +1,11 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
3
  class UnknownAccount < RuntimeError; end
4
+ class AccountIdentifierTooLongError < RuntimeError; end
5
+ class ScopeIdentifierTooLongError < RuntimeError; end
4
6
  class TransferNotAllowed < RuntimeError; end
5
7
  class TransferIsNegative < RuntimeError; end
8
+ class TransferCodeTooLongError < RuntimeError; end
6
9
  class DuplicateAccount < RuntimeError; end
7
10
  class DuplicateTransfer < RuntimeError; end
8
11
  class AccountWouldBeSentNegative < RuntimeError; end
@@ -2,7 +2,7 @@
2
2
  module DoubleEntry
3
3
  module Reporting
4
4
  class Aggregate
5
- attr_reader :function, :account, :code, :range, :options, :filter
5
+ attr_reader :function, :account, :code, :range, :options, :filter, :currency
6
6
 
7
7
  def initialize(function, account, code, options)
8
8
  @function = function.to_s
@@ -13,6 +13,7 @@ module DoubleEntry
13
13
  @options = options
14
14
  @range = options[:range]
15
15
  @filter = options[:filter]
16
+ @currency = DoubleEntry::Account.currency(account)
16
17
  end
17
18
 
18
19
  def amount(force_recalculation = false)
@@ -24,18 +25,12 @@ module DoubleEntry
24
25
  end
25
26
  end
26
27
 
27
- def formatted_amount
28
- Aggregate.formatted_amount(function, amount, currency)
29
- end
30
-
31
- def self.formatted_amount(function, amount, currency)
32
- safe_amount = amount || 0
33
-
34
- case function.to_s
35
- when 'count'
36
- safe_amount
28
+ def formatted_amount(amount = amount)
29
+ amount ||= 0
30
+ if function == "count"
31
+ amount
37
32
  else
38
- Money.new(safe_amount, currency)
33
+ Money.new(amount, currency)
39
34
  end
40
35
  end
41
36
 
@@ -46,10 +41,6 @@ module DoubleEntry
46
41
  aggregate.amount if aggregate
47
42
  end
48
43
 
49
- def currency
50
- DoubleEntry::Account.currency(account)
51
- end
52
-
53
44
  def clear_old_aggregates
54
45
  LineAggregate.delete_all(field_hash)
55
46
  end
@@ -75,28 +66,26 @@ module DoubleEntry
75
66
  # otherwise they will get excruciatingly slow to calculate
76
67
  # as the year progresses. (I am thinking mainly of the 'current' year.)
77
68
  # Combining monthly aggregates will mean that the figure will be partially memoized
78
- case function.to_s
79
- when 'average'
69
+ if function == "average"
80
70
  calculate_yearly_average
81
71
  else
82
- zero = Aggregate.formatted_amount(function, 0, currency)
83
-
72
+ zero = formatted_amount(0)
84
73
  result = (1..12).inject(zero) do |total, month|
85
- total += Reporting.aggregate(function, account, code,
86
- :range => MonthRange.new(:year => range.year, :month => month), :filter => filter)
74
+ total += Reporting.aggregate(
75
+ function, account, code,
76
+ :range => MonthRange.new(:year => range.year, :month => month),
77
+ :filter => filter,
78
+ )
87
79
  end
88
-
89
- result = result.cents if result.class == Money
90
- result
80
+ result.is_a?(Money) ? result.cents : result
91
81
  end
92
82
  end
93
83
 
94
84
  def calculate_yearly_average
95
85
  # need this seperate function, because an average of averages is not the correct average
96
- sum = Reporting.aggregate(:sum, account, code,
97
- :range => YearRange.new(:year => range.year), :filter => filter)
98
- count = Reporting.aggregate(:count, account, code,
99
- :range => YearRange.new(:year => range.year), :filter => filter)
86
+ year_range = YearRange.new(:year => range.year)
87
+ sum = Reporting.aggregate(:sum, account, code, :range => year_range, :filter => filter)
88
+ count = Reporting.aggregate(:count, account, code, :range => year_range, :filter => filter)
100
89
  (count == 0) ? 0 : (sum / count).cents
101
90
  end
102
91
 
@@ -9,16 +9,17 @@ module DoubleEntry
9
9
  #
10
10
  # For example, you could request all sales
11
11
  # broken down by month and it would return an array of values
12
- attr_reader :function, :account, :code, :filter, :range_type, :start, :finish
12
+ attr_reader :function, :account, :code, :filter, :range_type, :start, :finish, :currency
13
13
 
14
14
  def initialize(function, account, code, options)
15
- @function = function
15
+ @function = function.to_s
16
16
  @account = account
17
17
  @code = code
18
18
  @filter = options[:filter]
19
19
  @range_type = options[:range_type]
20
20
  @start = options[:start]
21
21
  @finish = options[:finish]
22
+ @currency = DoubleEntry::Account.currency(account)
22
23
 
23
24
  retrieve_aggregates
24
25
  fill_in_missing_aggregates
@@ -47,15 +48,14 @@ module DoubleEntry
47
48
  def retrieve_aggregates
48
49
  raise ArgumentError.new("Invalid range type '#{range_type}'") unless %w(year month week day hour).include? range_type
49
50
  @aggregates = LineAggregate.
50
- where(:function => function.to_s).
51
+ where(:function => function).
51
52
  where(:range_type => 'normal').
52
53
  where(:account => account.to_s).
53
54
  where(:code => code.to_s).
54
55
  where(:filter => filter.inspect).
55
56
  where(LineAggregate.arel_table[range_type].not_eq(nil)).
56
- inject({}) do |hash, result|
57
- hash[result.key] = Aggregate.formatted_amount(function, result.amount, currency)
58
- hash
57
+ each_with_object({}) do |hash, result|
58
+ hash[result.key] = formatted_amount(result.amount)
59
59
  end
60
60
  end
61
61
 
@@ -63,8 +63,13 @@ module DoubleEntry
63
63
  TimeRangeArray.make(range_type, start, finish)
64
64
  end
65
65
 
66
- def currency
67
- DoubleEntry::Account.currency(account)
66
+ def formatted_amount(amount)
67
+ amount ||= 0
68
+ if function == "count"
69
+ amount
70
+ else
71
+ Money.new(amount, currency)
72
+ end
68
73
  end
69
74
  end
70
75
  end
@@ -3,13 +3,18 @@ module DoubleEntry
3
3
  class Transfer
4
4
 
5
5
  class << self
6
- attr_writer :transfers
6
+ attr_writer :transfers, :code_max_length
7
7
 
8
8
  # @api private
9
9
  def transfers
10
10
  @transfers ||= Set.new
11
11
  end
12
12
 
13
+ # @api private
14
+ def code_max_length
15
+ @code_max_length ||= 47
16
+ end
17
+
13
18
  # @api private
14
19
  def transfer(amount, options = {})
15
20
  raise TransferIsNegative if amount < Money.zero
@@ -54,10 +59,17 @@ module DoubleEntry
54
59
  end
55
60
  end
56
61
 
57
- attr_accessor :code, :from, :to, :description
62
+ attr_reader :code, :from, :to
58
63
 
59
64
  def initialize(attributes)
60
- attributes.each { |name, value| send("#{name}=", value) }
65
+ @code = attributes[:code]
66
+ @from = attributes[:from]
67
+ @to = attributes[:to]
68
+ if code.length > Transfer.code_max_length
69
+ raise TransferCodeTooLongError.new(
70
+ "transfer code '#{code}' is too long. Please limit it to #{Transfer.code_max_length} characters."
71
+ )
72
+ end
61
73
  end
62
74
 
63
75
  def process(amount, from, to, code, detail)
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module DoubleEntry
4
- VERSION = "0.8.0"
4
+ VERSION = "0.9.0"
5
5
  end
@@ -2,56 +2,56 @@ class CreateDoubleEntryTables < ActiveRecord::Migration
2
2
 
3
3
  def self.up
4
4
  create_table "double_entry_account_balances", :force => true do |t|
5
- t.string "account", :null => false
6
- t.string "scope"
7
- t.integer "balance"
5
+ t.string "account", :limit => 31, :null => false
6
+ t.string "scope", :limit => 23
7
+ t.integer "balance", :null => false
8
8
  t.timestamps
9
9
  end
10
10
 
11
- add_index "double_entry_account_balances", ["account"], :name => "index_account_balances_on_account"
11
+ add_index "double_entry_account_balances", ["account"], :name => "index_account_balances_on_account"
12
12
  add_index "double_entry_account_balances", ["scope", "account"], :name => "index_account_balances_on_scope_and_account", :unique => true
13
13
 
14
14
  create_table "double_entry_lines", :force => true do |t|
15
- t.string "account"
16
- t.string "scope"
17
- t.string "code"
18
- t.integer "amount"
19
- t.integer "balance"
20
- t.integer "partner_id"
21
- t.string "partner_account"
22
- t.string "partner_scope"
23
- t.integer "detail_id"
24
- t.string "detail_type"
15
+ t.string "account", :limit => 31, :null => false
16
+ t.string "scope", :limit => 23
17
+ t.string "code", :limit => 47, :null => false
18
+ t.integer "amount", :null => false
19
+ t.integer "balance", :null => false
20
+ t.integer "partner_id"
21
+ t.string "partner_account", :limit => 31, :null => false
22
+ t.string "partner_scope", :limit => 23
23
+ t.integer "detail_id"
24
+ t.string "detail_type"
25
25
  t.timestamps
26
26
  end
27
27
 
28
- add_index "double_entry_lines", ["account", "code", "created_at"], :name => "lines_account_code_created_at_idx"
29
- add_index "double_entry_lines", ["account", "created_at"], :name => "lines_account_created_at_idx"
28
+ add_index "double_entry_lines", ["account", "code", "created_at"], :name => "lines_account_code_created_at_idx"
29
+ add_index "double_entry_lines", ["account", "created_at"], :name => "lines_account_created_at_idx"
30
30
  add_index "double_entry_lines", ["scope", "account", "created_at"], :name => "lines_scope_account_created_at_idx"
31
- add_index "double_entry_lines", ["scope", "account", "id"], :name => "lines_scope_account_id_idx"
31
+ add_index "double_entry_lines", ["scope", "account", "id"], :name => "lines_scope_account_id_idx"
32
32
 
33
33
  create_table "double_entry_line_aggregates", :force => true do |t|
34
- t.string "function"
35
- t.string "account"
36
- t.string "code"
37
- t.string "scope"
38
- t.integer "year"
39
- t.integer "month"
40
- t.integer "week"
41
- t.integer "day"
42
- t.integer "hour"
43
- t.integer "amount"
44
- t.string "filter"
45
- t.string "range_type"
34
+ t.string "function", :limit => 15, :null => false
35
+ t.string "account", :limit => 31, :null => false
36
+ t.string "code", :limit => 47
37
+ t.string "scope", :limit => 23
38
+ t.integer "year"
39
+ t.integer "month"
40
+ t.integer "week"
41
+ t.integer "day"
42
+ t.integer "hour"
43
+ t.integer "amount", :null => false
44
+ t.string "filter"
45
+ t.string "range_type", :limit => 15, :null => false
46
46
  t.timestamps
47
47
  end
48
48
 
49
49
  add_index "double_entry_line_aggregates", ["function", "account", "code", "year", "month", "week", "day"], :name => "line_aggregate_idx"
50
50
 
51
51
  create_table "double_entry_line_checks", :force => true do |t|
52
- t.integer "last_line_id"
53
- t.boolean "errors_found"
54
- t.text "log"
52
+ t.integer "last_line_id", :null => false
53
+ t.boolean "errors_found", :null => false
54
+ t.text "log"
55
55
  t.timestamps
56
56
  end
57
57
 
@@ -4,21 +4,54 @@ module DoubleEntry
4
4
  describe Account do
5
5
  let(:identity_scope) { ->(value) { value } }
6
6
 
7
- it "instances should be sortable" do
8
- account = Account.new(:identifier => "savings", :scope_identifier => identity_scope)
9
- a = Account::Instance.new(:account => account, :scope => "123")
10
- b = Account::Instance.new(:account => account, :scope => "456")
11
- expect([b, a].sort).to eq [a, b]
7
+ describe "::new" do
8
+ context "given an identifier 31 characters in length" do
9
+ let(:identifier) { "xxxxxxxx 31 characters xxxxxxxx" }
10
+ specify do
11
+ expect { Account.new(:identifier => identifier) }.to_not raise_error
12
+ end
13
+ end
14
+
15
+ context "given an identifier 32 characters in length" do
16
+ let(:identifier) { "xxxxxxxx 32 characters xxxxxxxxx" }
17
+ specify do
18
+ expect { Account.new(:identifier => identifier) }.to raise_error AccountIdentifierTooLongError, /'#{identifier}'/
19
+ end
20
+ end
12
21
  end
13
22
 
14
- it "instances should be hashable" do
15
- account = Account.new(:identifier => "savings", :scope_identifier => identity_scope)
16
- a1 = Account::Instance.new(:account => account, :scope => "123")
17
- a2 = Account::Instance.new(:account => account, :scope => "123")
18
- b = Account::Instance.new(:account => account, :scope => "456")
23
+ describe Account::Instance do
24
+ it "is sortable" do
25
+ account = Account.new(:identifier => "savings", :scope_identifier => identity_scope)
26
+ a = Account::Instance.new(:account => account, :scope => "123")
27
+ b = Account::Instance.new(:account => account, :scope => "456")
28
+ expect([b, a].sort).to eq [a, b]
29
+ end
30
+
31
+ it "is hashable" do
32
+ account = Account.new(:identifier => "savings", :scope_identifier => identity_scope)
33
+ a1 = Account::Instance.new(:account => account, :scope => "123")
34
+ a2 = Account::Instance.new(:account => account, :scope => "123")
35
+ b = Account::Instance.new(:account => account, :scope => "456")
36
+
37
+ expect(a1.hash).to eq a2.hash
38
+ expect(a1.hash).to_not eq b.hash
39
+ end
40
+
41
+ describe "::new" do
42
+ let(:account) { Account.new(:identifier => "x", :scope_identifier => identity_scope) }
43
+ subject(:initialize_account_instance) { Account::Instance.new(:account => account, :scope => scope) }
44
+
45
+ context "given a scope identifier 23 characters in length" do
46
+ let(:scope) { "xxxx 23 characters xxxx" }
47
+ specify { expect { initialize_account_instance }.to_not raise_error }
48
+ end
19
49
 
20
- expect(a1.hash).to eq a2.hash
21
- expect(a1.hash).to_not eq b.hash
50
+ context "given a scope identifier 24 characters in length" do
51
+ let(:scope) { "xxxx 24 characters xxxxx" }
52
+ specify { expect { initialize_account_instance }.to raise_error ScopeIdentifierTooLongError, /'#{scope}'/ }
53
+ end
54
+ end
22
55
  end
23
56
 
24
57
  describe "currency" do
@@ -32,27 +65,27 @@ module DoubleEntry
32
65
  expect(DoubleEntry::Account::Instance.new(:account => account).currency).to eq("AUD")
33
66
  end
34
67
  end
35
- end
36
68
 
37
- describe Account::Set do
38
- describe "#define" do
39
- context "given a 'savings' account is defined" do
40
- before { subject.define(:identifier => "savings") }
41
- its(:first) { should be_a Account }
42
- its("first.identifier") { should eq "savings" }
69
+ describe Account::Set do
70
+ describe "#define" do
71
+ context "given a 'savings' account is defined" do
72
+ before { subject.define(:identifier => "savings") }
73
+ its(:first) { should be_an Account }
74
+ its("first.identifier") { should eq "savings" }
75
+ end
43
76
  end
44
- end
45
77
 
46
- describe "#active_record_scope_identifier" do
47
- subject(:scope) { Account::Set.new.active_record_scope_identifier(ar_class) }
78
+ describe "#active_record_scope_identifier" do
79
+ subject(:scope) { Account::Set.new.active_record_scope_identifier(ar_class) }
48
80
 
49
- context "given ActiveRecordScopeFactory is stubbed" do
50
- let(:scope_identifier) { double(:scope_identifier) }
51
- let(:scope_factory) { double(:scope_factory, :scope_identifier => scope_identifier) }
52
- let(:ar_class) { double(:ar_class) }
53
- before { allow(Account::ActiveRecordScopeFactory).to receive(:new).with(ar_class).and_return(scope_factory) }
81
+ context "given ActiveRecordScopeFactory is stubbed" do
82
+ let(:scope_identifier) { double(:scope_identifier) }
83
+ let(:scope_factory) { double(:scope_factory, :scope_identifier => scope_identifier) }
84
+ let(:ar_class) { double(:ar_class) }
85
+ before { allow(Account::ActiveRecordScopeFactory).to receive(:new).with(ar_class).and_return(scope_factory) }
54
86
 
55
- it { should eq scope_identifier }
87
+ it { should eq scope_identifier }
88
+ end
56
89
  end
57
90
  end
58
91
  end
@@ -5,6 +5,35 @@ describe DoubleEntry::Configuration do
5
5
  its(:accounts) { should be_a DoubleEntry::Account::Set }
6
6
  its(:transfers) { should be_a DoubleEntry::Transfer::Set }
7
7
 
8
+ describe "max lengths" do
9
+ context "given a max length has not been set" do
10
+ its(:code_max_length) { should be 47 }
11
+ its(:scope_identifier_max_length) { should be 23 }
12
+ its(:account_identifier_max_length) { should be 31 }
13
+ end
14
+
15
+ context "given a code max length of 10 has been set" do
16
+ before { subject.code_max_length = 10 }
17
+ its(:code_max_length) { should be 10 }
18
+ end
19
+
20
+ context "given a scope identifier max length of 11 has been set" do
21
+ before { subject.scope_identifier_max_length = 11 }
22
+ its(:scope_identifier_max_length) { should be 11 }
23
+ end
24
+
25
+ context "given an account identifier max length of 9 has been set" do
26
+ before { subject.account_identifier_max_length = 9 }
27
+ its(:account_identifier_max_length) { should be 9 }
28
+ end
29
+
30
+ after do
31
+ subject.code_max_length = nil
32
+ subject.scope_identifier_max_length = nil
33
+ subject.account_identifier_max_length = nil
34
+ end
35
+ end
36
+
8
37
  describe "#define_accounts" do
9
38
  it "yields the accounts set" do
10
39
  expect { |block|
@@ -6,7 +6,7 @@ describe DoubleEntry::Line do
6
6
  end
7
7
 
8
8
  describe "persistance" do
9
- let(:persisted_line) {
9
+ let(:line_to_persist) {
10
10
  DoubleEntry::Line.new(
11
11
  :amount => Money.new(10_00),
12
12
  :balance => Money.zero,
@@ -18,11 +18,13 @@ describe DoubleEntry::Line do
18
18
  let(:account) { DoubleEntry.account(:test, :scope => "17") }
19
19
  let(:partner_account) { DoubleEntry.account(:test, :scope => "72") }
20
20
  let(:code) { :test_code }
21
- subject { DoubleEntry::Line.last }
22
21
 
23
- describe "attributes" do
24
- before { persisted_line.save! }
22
+ subject(:persisted_line) do
23
+ line_to_persist.save!
24
+ line_to_persist.reload
25
+ end
25
26
 
27
+ describe "attributes" do
26
28
  context "given code = :the_code" do
27
29
  let(:code) { :the_code }
28
30
  its(:code) { should eq :the_code }
@@ -30,7 +32,7 @@ describe DoubleEntry::Line do
30
32
 
31
33
  context "given code = nil" do
32
34
  let(:code) { nil }
33
- its(:code) { should eq nil }
35
+ specify { expect { line_to_persist.save! }.to raise_error }
34
36
  end
35
37
 
36
38
  context "given account = :test, 54 " do
@@ -52,22 +54,20 @@ describe DoubleEntry::Line do
52
54
  end
53
55
  end
54
56
 
55
- describe '#save' do
56
- context 'when balance is sent negative' do
57
- let(:account) {
58
- DoubleEntry.account(:savings, :scope => '17', :positive_only => true)
59
- }
57
+ context 'when balance is sent negative' do
58
+ let(:account) {
59
+ DoubleEntry.account(:savings, :scope => '17', :positive_only => true)
60
+ }
60
61
 
61
- let(:line) {
62
- DoubleEntry::Line.new(
63
- :balance => Money.new(-1),
64
- :account => account,
65
- )
66
- }
62
+ let(:line) {
63
+ DoubleEntry::Line.new(
64
+ :balance => Money.new(-1),
65
+ :account => account,
66
+ )
67
+ }
67
68
 
68
- it 'raises AccountWouldBeSentNegative exception' do
69
- expect { line.save }.to raise_error DoubleEntry::AccountWouldBeSentNegative
70
- end
69
+ it 'raises AccountWouldBeSentNegative exception' do
70
+ expect { line.save }.to raise_error DoubleEntry::AccountWouldBeSentNegative
71
71
  end
72
72
  end
73
73
 
@@ -51,8 +51,20 @@ describe DoubleEntry::Locking do
51
51
  end
52
52
 
53
53
  it "takes the balance for new account balance records from the lines table" do
54
- DoubleEntry::Line.create!(:account => @account_a, :partner_account => @account_b, :amount => Money.new(3_00), :balance => Money.new( 3_00), :code => :test)
55
- DoubleEntry::Line.create!(:account => @account_a, :partner_account => @account_b, :amount => Money.new(7_00), :balance => Money.new(10_00), :code => :test)
54
+ DoubleEntry::Line.create!(
55
+ :account => @account_a,
56
+ :partner_account => @account_b,
57
+ :amount => Money.new(3_00),
58
+ :balance => Money.new(3_00),
59
+ :code => :test,
60
+ )
61
+ DoubleEntry::Line.create!(
62
+ :account => @account_a,
63
+ :partner_account => @account_b,
64
+ :amount => Money.new(7_00),
65
+ :balance => Money.new(10_00),
66
+ :code => :test,
67
+ )
56
68
 
57
69
  expect do
58
70
  DoubleEntry::Locking.lock_accounts(@account_a) { }
@@ -1,17 +1,38 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
- describe DoubleEntry::Transfer::Set do
4
- describe "#define" do
5
- before do
6
- subject.define(
7
- :code => "code",
8
- :from => double(:identifier => "from"),
9
- :to => double(:identifier => "to"),
10
- )
3
+ module DoubleEntry
4
+ describe Transfer do
5
+
6
+ describe "::new" do
7
+ context "given a code 47 characters in length" do
8
+ let(:code) { "xxxxxxxxxxxxxxxx 47 characters xxxxxxxxxxxxxxxx" }
9
+ specify do
10
+ expect { Transfer.new(:code => code) }.to_not raise_error
11
+ end
12
+ end
13
+
14
+ context "given a code 48 characters in length" do
15
+ let(:code) { "xxxxxxxxxxxxxxxx 48 characters xxxxxxxxxxxxxxxxx" }
16
+ specify do
17
+ expect { Transfer.new(:code => code) }.to raise_error TransferCodeTooLongError, /'#{code}'/
18
+ end
19
+ end
20
+ end
21
+
22
+ describe Transfer::Set do
23
+ describe "#define" do
24
+ before do
25
+ subject.define(
26
+ :code => "code",
27
+ :from => double(:identifier => "from"),
28
+ :to => double(:identifier => "to"),
29
+ )
30
+ end
31
+ its(:first) { should be_a Transfer }
32
+ its("first.code") { should eq "code" }
33
+ its("first.from.identifier") { should eq "from" }
34
+ its("first.to.identifier") { should eq "to" }
35
+ end
11
36
  end
12
- its(:first) { should be_a DoubleEntry::Transfer }
13
- its("first.code") { should eq "code" }
14
- its("first.from.identifier") { should eq "from" }
15
- its("first.to.identifier") { should eq "to" }
16
37
  end
17
38
  end
@@ -173,9 +173,8 @@ describe DoubleEntry do
173
173
  accounts.define(:identifier => :b)
174
174
  end
175
175
 
176
- description = ->(line) { "Money goes #{line.decrease? ? 'out' : 'in'}: #{line.amount.format}" }
177
176
  config.define_transfers do |transfers|
178
- transfers.define(:code => :xfer, :from => :a, :to => :b, :description => description)
177
+ transfers.define(:code => :xfer, :from => :a, :to => :b)
179
178
  end
180
179
  end
181
180
 
@@ -2,68 +2,63 @@ ActiveRecord::Schema.define do
2
2
  self.verbose = false
3
3
 
4
4
  create_table "double_entry_account_balances", :force => true do |t|
5
- t.string "account", :null => false
6
- t.string "scope"
7
- t.integer "balance"
8
- t.datetime "created_at"
9
- t.datetime "updated_at"
5
+ t.string "account", :limit => 31, :null => false
6
+ t.string "scope", :limit => 23
7
+ t.integer "balance", :null => false
8
+ t.timestamps
10
9
  end
11
10
 
12
- add_index "double_entry_account_balances", ["account"], :name => "index_account_balances_on_account"
11
+ add_index "double_entry_account_balances", ["account"], :name => "index_account_balances_on_account"
13
12
  add_index "double_entry_account_balances", ["scope", "account"], :name => "index_account_balances_on_scope_and_account", :unique => true
14
13
 
15
14
  create_table "double_entry_lines", :force => true do |t|
16
- t.string "account"
17
- t.string "scope"
18
- t.string "code"
19
- t.integer "amount"
20
- t.integer "balance"
21
- t.integer "partner_id"
22
- t.string "partner_account"
23
- t.string "partner_scope"
24
- t.integer "detail_id"
25
- t.string "detail_type"
26
- t.datetime "created_at"
27
- t.datetime "updated_at"
15
+ t.string "account", :limit => 31, :null => false
16
+ t.string "scope", :limit => 23
17
+ t.string "code", :limit => 47, :null => false
18
+ t.integer "amount", :null => false
19
+ t.integer "balance", :null => false
20
+ t.integer "partner_id"
21
+ t.string "partner_account", :limit => 31, :null => false
22
+ t.string "partner_scope", :limit => 23
23
+ t.integer "detail_id"
24
+ t.string "detail_type"
25
+ t.timestamps
28
26
  end
29
27
 
30
- add_index "double_entry_lines", ["account", "code", "created_at"], :name => "lines_account_code_created_at_idx"
31
- add_index "double_entry_lines", ["account", "created_at"], :name => "lines_account_created_at_idx"
28
+ add_index "double_entry_lines", ["account", "code", "created_at"], :name => "lines_account_code_created_at_idx"
29
+ add_index "double_entry_lines", ["account", "created_at"], :name => "lines_account_created_at_idx"
32
30
  add_index "double_entry_lines", ["scope", "account", "created_at"], :name => "lines_scope_account_created_at_idx"
33
- add_index "double_entry_lines", ["scope", "account", "id"], :name => "lines_scope_account_id_idx"
31
+ add_index "double_entry_lines", ["scope", "account", "id"], :name => "lines_scope_account_id_idx"
34
32
 
35
33
  create_table "double_entry_line_aggregates", :force => true do |t|
36
- t.string "function"
37
- t.string "account"
38
- t.string "code"
39
- t.string "scope"
40
- t.integer "year"
41
- t.integer "month"
42
- t.integer "week"
43
- t.integer "day"
44
- t.integer "hour"
45
- t.integer "amount"
46
- t.datetime "created_at"
47
- t.datetime "updated_at"
48
- t.string "filter"
49
- t.string "range_type"
34
+ t.string "function", :limit => 15, :null => false
35
+ t.string "account", :limit => 31, :null => false
36
+ t.string "code", :limit => 47
37
+ t.string "scope", :limit => 23
38
+ t.integer "year"
39
+ t.integer "month"
40
+ t.integer "week"
41
+ t.integer "day"
42
+ t.integer "hour"
43
+ t.integer "amount", :null => false
44
+ t.string "filter"
45
+ t.string "range_type", :limit => 15, :null => false
46
+ t.timestamps
50
47
  end
51
48
 
52
49
  add_index "double_entry_line_aggregates", ["function", "account", "code", "year", "month", "week", "day"], :name => "line_aggregate_idx"
53
50
 
54
51
  create_table "double_entry_line_checks", :force => true do |t|
55
- t.integer "last_line_id"
56
- t.boolean "errors_found"
57
- t.text "log"
58
- t.datetime "created_at"
59
- t.datetime "updated_at"
52
+ t.integer "last_line_id", :null => false
53
+ t.boolean "errors_found", :null => false
54
+ t.text "log"
55
+ t.timestamps
60
56
  end
61
57
 
62
58
  # test table only
63
59
  create_table "users", :force => true do |t|
64
- t.string "username"
65
- t.datetime "created_at"
66
- t.datetime "updated_at"
60
+ t.string "username", :null => false
61
+ t.timestamps
67
62
  end
68
63
 
69
64
  add_index "users", ["username"], :name => "index_users_on_username", :unique => true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: double_entry
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Sellitti
@@ -15,7 +15,7 @@ authors:
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
- date: 2014-11-19 00:00:00.000000000 Z
18
+ date: 2014-12-08 00:00:00.000000000 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: money