double_entry 1.0.1 → 2.0.0.beta5

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.
Files changed (79) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +497 -0
  3. data/README.md +107 -44
  4. data/double_entry.gemspec +22 -49
  5. data/lib/active_record/locking_extensions.rb +3 -3
  6. data/lib/active_record/locking_extensions/log_subscriber.rb +1 -1
  7. data/lib/double_entry.rb +29 -21
  8. data/lib/double_entry/account.rb +39 -46
  9. data/lib/double_entry/account_balance.rb +20 -3
  10. data/lib/double_entry/balance_calculator.rb +5 -5
  11. data/lib/double_entry/configurable.rb +1 -0
  12. data/lib/double_entry/configuration.rb +8 -2
  13. data/lib/double_entry/errors.rb +13 -13
  14. data/lib/double_entry/line.rb +7 -6
  15. data/lib/double_entry/locking.rb +5 -5
  16. data/lib/double_entry/transfer.rb +37 -30
  17. data/lib/double_entry/validation.rb +1 -0
  18. data/lib/double_entry/validation/account_fixer.rb +36 -0
  19. data/lib/double_entry/validation/line_check.rb +25 -43
  20. data/lib/double_entry/version.rb +1 -1
  21. data/lib/generators/double_entry/install/install_generator.rb +22 -1
  22. data/lib/generators/double_entry/install/templates/initializer.rb +20 -0
  23. data/lib/generators/double_entry/install/templates/migration.rb +45 -55
  24. metadata +35 -256
  25. data/.gitignore +0 -32
  26. data/.rspec +0 -2
  27. data/.travis.yml +0 -29
  28. data/.yardopts +0 -2
  29. data/Gemfile +0 -2
  30. data/Rakefile +0 -15
  31. data/lib/double_entry/reporting.rb +0 -181
  32. data/lib/double_entry/reporting/aggregate.rb +0 -110
  33. data/lib/double_entry/reporting/aggregate_array.rb +0 -76
  34. data/lib/double_entry/reporting/day_range.rb +0 -42
  35. data/lib/double_entry/reporting/hour_range.rb +0 -45
  36. data/lib/double_entry/reporting/line_aggregate.rb +0 -16
  37. data/lib/double_entry/reporting/line_aggregate_filter.rb +0 -79
  38. data/lib/double_entry/reporting/month_range.rb +0 -94
  39. data/lib/double_entry/reporting/time_range.rb +0 -59
  40. data/lib/double_entry/reporting/time_range_array.rb +0 -49
  41. data/lib/double_entry/reporting/week_range.rb +0 -107
  42. data/lib/double_entry/reporting/year_range.rb +0 -40
  43. data/script/jack_hammer +0 -210
  44. data/script/setup.sh +0 -8
  45. data/spec/active_record/locking_extensions_spec.rb +0 -110
  46. data/spec/double_entry/account_balance_spec.rb +0 -7
  47. data/spec/double_entry/account_spec.rb +0 -130
  48. data/spec/double_entry/balance_calculator_spec.rb +0 -88
  49. data/spec/double_entry/configuration_spec.rb +0 -50
  50. data/spec/double_entry/line_spec.rb +0 -80
  51. data/spec/double_entry/locking_spec.rb +0 -214
  52. data/spec/double_entry/performance/double_entry_performance_spec.rb +0 -32
  53. data/spec/double_entry/performance/reporting/aggregate_performance_spec.rb +0 -50
  54. data/spec/double_entry/reporting/aggregate_array_spec.rb +0 -123
  55. data/spec/double_entry/reporting/aggregate_spec.rb +0 -205
  56. data/spec/double_entry/reporting/line_aggregate_filter_spec.rb +0 -90
  57. data/spec/double_entry/reporting/line_aggregate_spec.rb +0 -39
  58. data/spec/double_entry/reporting/month_range_spec.rb +0 -139
  59. data/spec/double_entry/reporting/time_range_array_spec.rb +0 -169
  60. data/spec/double_entry/reporting/time_range_spec.rb +0 -45
  61. data/spec/double_entry/reporting/week_range_spec.rb +0 -103
  62. data/spec/double_entry/reporting_spec.rb +0 -181
  63. data/spec/double_entry/transfer_spec.rb +0 -93
  64. data/spec/double_entry/validation/line_check_spec.rb +0 -99
  65. data/spec/double_entry_spec.rb +0 -428
  66. data/spec/generators/double_entry/install/install_generator_spec.rb +0 -30
  67. data/spec/spec_helper.rb +0 -118
  68. data/spec/support/accounts.rb +0 -21
  69. data/spec/support/blueprints.rb +0 -43
  70. data/spec/support/database.example.yml +0 -21
  71. data/spec/support/database.travis.yml +0 -24
  72. data/spec/support/double_entry_spec_helper.rb +0 -27
  73. data/spec/support/gemfiles/Gemfile.rails-3.2.x +0 -8
  74. data/spec/support/gemfiles/Gemfile.rails-4.1.x +0 -6
  75. data/spec/support/gemfiles/Gemfile.rails-4.2.x +0 -5
  76. data/spec/support/gemfiles/Gemfile.rails-5.0.x +0 -5
  77. data/spec/support/performance_helper.rb +0 -26
  78. data/spec/support/reporting_configuration.rb +0 -6
  79. data/spec/support/schema.rb +0 -74
@@ -1,50 +0,0 @@
1
- module DoubleEntry
2
- module Reporting
3
- RSpec.describe Aggregate do
4
- include PerformanceHelper
5
- let(:user) { User.make! }
6
- let(:amount) { Money.new(10_00) }
7
- let(:test) { DoubleEntry.account(:test, :scope => user) }
8
- let(:savings) { DoubleEntry.account(:savings, :scope => user) }
9
-
10
- subject(:transfer) { Transfer.transfer(amount, options) }
11
-
12
- context '200 transfers in a single day, half with metadata' do
13
- # Surprisingly, the number of transfers makes no difference to the time taken to aggregate them. Some sample results:
14
- # 20,000 => 524ms
15
- # 10,000 => 573ms
16
- # 1,000 => 486ms
17
- # 100 => 608ms
18
- # 10 => 509ms
19
- # 1 => 473ms
20
- before do
21
- Timecop.freeze Time.local(2015, 06, 30) do
22
- 100.times { Transfer.transfer(amount, :from => test, :to => savings, :code => :bonus) }
23
- 100.times { Transfer.transfer(amount, :from => test, :to => savings, :code => :bonus, :metadata => { :country => 'AU', :tax => 'GST' }) }
24
- end
25
- end
26
-
27
- it 'calculates monthly all_time ranges quickly without a filter' do
28
- profile_aggregation_with_filter(nil)
29
- # local results: 517ms, 484ms, 505ms, 482ms, 525ms
30
- end
31
-
32
- it 'calculates monthly all_time ranges quickly with a filter' do
33
- profile_aggregation_with_filter([:metadata => { :country => 'AU' }])
34
- # local results when run independently (caching improves performance when run consecutively):
35
- # 655ms, 613ms, 597ms, 607ms, 627ms
36
- end
37
- end
38
-
39
- def profile_aggregation_with_filter(filter)
40
- start_profiling
41
- range = TimeRange.make(:year => 2015, :month => 06, :range_type => :all_time)
42
- options = {}
43
- options[:filter] = filter if filter
44
- Reporting.aggregate(:sum, :savings, :bonus, range, options)
45
- profile_name = filter ? 'aggregate-with-metadata' : 'aggregate'
46
- stop_profiling(profile_name)
47
- end
48
- end
49
- end
50
- end
@@ -1,123 +0,0 @@
1
- module DoubleEntry
2
- module Reporting
3
- RSpec.describe AggregateArray do
4
- let(:user) { User.make! }
5
- let(:start) { nil }
6
- let(:finish) { nil }
7
- let(:range_type) { 'year' }
8
- let(:function) { 'sum' }
9
- let(:account) { :savings }
10
- let(:transfer_code) { :bonus }
11
- subject(:aggregate_array) do
12
- AggregateArray.new(
13
- function,
14
- account,
15
- transfer_code,
16
- :range_type => range_type,
17
- :start => start,
18
- :finish => finish,
19
- )
20
- end
21
-
22
- context 'given a deposit was made in 2007 and 2008' do
23
- before do
24
- Timecop.travel(Time.local(2007)) do
25
- perform_deposit user, 10_00
26
- end
27
- Timecop.travel(Time.local(2008)) do
28
- perform_deposit user, 20_00
29
- end
30
- end
31
-
32
- context 'given the date is 2009-03-19' do
33
- before { Timecop.travel(Time.local(2009, 3, 19)) }
34
-
35
- context 'when called with range type of "year"' do
36
- let(:range_type) { 'year' }
37
- let(:start) { '2006-08-03' }
38
- it { should eq [Money.zero, Money.new(10_00), Money.new(20_00), Money.zero] }
39
-
40
- describe 'reuse of aggregates' do
41
- let(:years) { TimeRangeArray.make(range_type, start, finish) }
42
-
43
- context 'and some aggregates were created previously' do
44
- before do
45
- Aggregate.formatted_amount(function, account, transfer_code, years[0])
46
- Aggregate.formatted_amount(function, account, transfer_code, years[1])
47
- allow(Aggregate).to receive(:formatted_amount)
48
- end
49
-
50
- it 'only asks Aggregate for the non-existent ones' do
51
- expect(Aggregate).not_to receive(:formatted_amount).with(function, account, transfer_code, years[0], :filter => nil)
52
- expect(Aggregate).not_to receive(:formatted_amount).with(function, account, transfer_code, years[1], :filter => nil)
53
-
54
- expect(Aggregate).to receive(:formatted_amount).with(function, account, transfer_code, years[2], :filter => nil)
55
- expect(Aggregate).to receive(:formatted_amount).with(function, account, transfer_code, years[3], :filter => nil)
56
- aggregate_array
57
- end
58
- end
59
- end
60
- end
61
- end
62
- end
63
-
64
- context 'given a deposit was made in October and December 2006' do
65
- before do
66
- Timecop.travel(Time.local(2006, 10)) do
67
- perform_deposit user, 10_00
68
- end
69
- Timecop.travel(Time.local(2006, 12)) do
70
- perform_deposit user, 20_00
71
- end
72
- end
73
-
74
- context 'when called with range type of "month", a start of "2006-09-01", and finish of "2007-01-02"' do
75
- let(:range_type) { 'month' }
76
- let(:start) { '2006-09-01' }
77
- let(:finish) { '2007-01-02' }
78
- it { should eq [Money.zero, Money.new(10_00), Money.zero, Money.new(20_00), Money.zero] }
79
- end
80
-
81
- context 'given the date is 2007-02-02' do
82
- before { Timecop.travel(Time.local(2007, 2, 2)) }
83
-
84
- context 'when called with range type of "month"' do
85
- let(:range_type) { 'month' }
86
- let(:start) { '2006-08-03' }
87
- it { should eq [Money.zero, Money.zero, Money.new(10_00), Money.zero, Money.new(20_00), Money.zero, Money.zero] }
88
- end
89
- end
90
- end
91
-
92
- context 'when account is in BTC currency' do
93
- let(:account) { :btc_savings }
94
- let(:range_type) { 'year' }
95
- let(:start) { "#{Time.now.year}-01-01" }
96
- let(:transfer_code) { :btc_test_transfer }
97
-
98
- before do
99
- perform_btc_deposit(user, 100_000_000)
100
- perform_btc_deposit(user, 100_000_000)
101
- end
102
-
103
- it { should eq [Money.new(200_000_000, :btc)] }
104
- end
105
-
106
- context 'when called with range type of "invalid_and_should_not_work"' do
107
- let(:range_type) { 'invalid_and_should_not_work' }
108
- it 'raises an argument error' do
109
- expect { aggregate_array }.to raise_error ArgumentError, "Invalid range type 'invalid_and_should_not_work'"
110
- end
111
- end
112
-
113
- context 'when an invalid function is provided' do
114
- let(:range_type) { 'month' }
115
- let(:start) { '2006-08-03' }
116
- let(:function) { :invalid_function }
117
- it 'raises an AggregateFunctionNotSupported error' do
118
- expect { aggregate_array }.to raise_error AggregateFunctionNotSupported
119
- end
120
- end
121
- end
122
- end
123
- end
@@ -1,205 +0,0 @@
1
- # encoding: utf-8
2
- module DoubleEntry
3
- module Reporting
4
- RSpec.describe Aggregate do
5
- let(:user) { User.make! }
6
- let(:expected_weekly_average) do
7
- (Money.new(20_00) + Money.new(40_00) + Money.new(50_00)) / 3
8
- end
9
- let(:expected_monthly_average) do
10
- (Money.new(20_00) + Money.new(40_00) + Money.new(50_00) + Money.new(40_00) + Money.new(50_00)) / 5
11
- end
12
-
13
- before do
14
- # Thursday
15
- Timecop.freeze Time.local(2009, 10, 1) do
16
- perform_deposit user, 20_00
17
- end
18
-
19
- # Saturday
20
- Timecop.freeze Time.local(2009, 10, 3) do
21
- perform_deposit user, 40_00
22
- end
23
-
24
- Timecop.freeze Time.local(2009, 10, 10) do
25
- perform_deposit user, 50_00
26
- end
27
- Timecop.freeze Time.local(2009, 11, 1, 0, 59, 0) do
28
- perform_deposit user, 40_00
29
- end
30
- Timecop.freeze Time.local(2009, 11, 1, 1, 00, 0) do
31
- perform_deposit user, 50_00
32
- end
33
- end
34
-
35
- it 'should store the aggregate for quick retrieval' do
36
- Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 10)).amount
37
- expect(LineAggregate.count).to eq 1
38
- end
39
-
40
- it 'should only store the aggregate once if it is requested more than once' do
41
- Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 9)).amount
42
- Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 9)).amount
43
- Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 10)).amount
44
- expect(LineAggregate.count).to eq 2
45
- end
46
-
47
- it 'should calculate the complete year correctly' do
48
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009)).formatted_amount
49
- expect(amount).to eq Money.new(200_00)
50
- end
51
-
52
- it 'should calculate seperate months correctly' do
53
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 10)).formatted_amount
54
- expect(amount).to eq Money.new(110_00)
55
-
56
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 11)).formatted_amount
57
- expect(amount).to eq Money.new(90_00)
58
- end
59
-
60
- it 'should calculate seperate weeks correctly' do
61
- # Week 40 - Mon Sep 28, 2009 to Sun Oct 4 2009
62
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :week => 40)).formatted_amount
63
- expect(amount).to eq Money.new(60_00)
64
- end
65
-
66
- it 'should calculate seperate days correctly' do
67
- # 1 Nov 2009
68
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :week => 44, :day => 7)).formatted_amount
69
- expect(amount).to eq Money.new(90_00)
70
- end
71
-
72
- it 'should calculate seperate hours correctly' do
73
- # 1 Nov 2009
74
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :week => 44, :day => 7, :hour => 0)).formatted_amount
75
- expect(amount).to eq Money.new(40_00)
76
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :week => 44, :day => 7, :hour => 1)).formatted_amount
77
- expect(amount).to eq Money.new(50_00)
78
- end
79
-
80
- it 'should calculate, but not store aggregates when the time range is still current' do
81
- Timecop.freeze Time.local(2009, 11, 21) do
82
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 11)).formatted_amount
83
- expect(amount).to eq Money.new(90_00)
84
- expect(LineAggregate.count).to eq 0
85
- end
86
- end
87
-
88
- it 'should calculate, but not store aggregates when the time range is in the future' do
89
- Timecop.freeze Time.local(2009, 11, 21) do
90
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 12)).formatted_amount
91
- expect(amount).to eq Money.new(0)
92
- expect(LineAggregate.count).to eq 0
93
- end
94
- end
95
-
96
- it 'should calculate monthly all_time ranges correctly' do
97
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :month => 12, :range_type => :all_time)).formatted_amount
98
- expect(amount).to eq Money.new(200_00)
99
- end
100
-
101
- it 'calculates the average monthly all_time ranges correctly' do
102
- amount = Aggregate.new(:average, :savings, :bonus, TimeRange.make(:year => 2009, :month => 12, :range_type => :all_time)).formatted_amount
103
- expect(amount).to eq expected_monthly_average
104
- end
105
-
106
- it 'returns the correct count for weekly all_time ranges correctly' do
107
- amount = Aggregate.new(:count, :savings, :bonus, TimeRange.make(:year => 2009, :month => 12, :range_type => :all_time)).formatted_amount
108
- expect(amount).to eq 5
109
- end
110
-
111
- it 'should calculate weekly all_time ranges correctly' do
112
- amount = Aggregate.new(:sum, :savings, :bonus, TimeRange.make(:year => 2009, :week => 43, :range_type => :all_time)).formatted_amount
113
- expect(amount).to eq Money.new(110_00)
114
- end
115
-
116
- it 'calculates the average weekly all_time ranges correctly' do
117
- amount = Aggregate.new(:average, :savings, :bonus, TimeRange.make(:year => 2009, :week => 43, :range_type => :all_time)).formatted_amount
118
- expect(amount).to eq expected_weekly_average
119
- end
120
-
121
- it 'returns the correct count for weekly all_time ranges correctly' do
122
- amount = Aggregate.new(:count, :savings, :bonus, TimeRange.make(:year => 2009, :week => 43, :range_type => :all_time)).formatted_amount
123
- expect(amount).to eq 3
124
- end
125
-
126
- it 'raises an AggregateFunctionNotSupported exception' do
127
- expect do
128
- Aggregate.new(
129
- :not_supported_calculation, :savings, :bonus, TimeRange.make(:year => 2009, :week => 43, :range_type => :all_time)
130
- ).amount
131
- end.to raise_error(AggregateFunctionNotSupported)
132
- end
133
-
134
- context 'filters' do
135
- let(:range) { TimeRange.make(:year => 2011, :month => 10) }
136
- let(:filter) do
137
- [
138
- :scope => {
139
- :name => :test_filter,
140
- },
141
- ]
142
- end
143
-
144
- DoubleEntry::Line.class_eval do
145
- scope :test_filter, -> { where(:amount => 10_00) }
146
- end
147
-
148
- before do
149
- Timecop.freeze Time.local(2011, 10, 10) do
150
- perform_deposit user, 10_00
151
- end
152
-
153
- Timecop.freeze Time.local(2011, 10, 10) do
154
- perform_deposit user, 9_00
155
- end
156
- end
157
-
158
- it 'saves filtered aggregations' do
159
- expect do
160
- Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).amount
161
- end.to change { LineAggregate.count }.by 1
162
- end
163
-
164
- it 'saves filtered aggregation only once for a range' do
165
- expect do
166
- Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).amount
167
- Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).amount
168
- end.to change { LineAggregate.count }.by 1
169
- end
170
-
171
- it 'saves filtered aggregations and non filtered aggregations separately' do
172
- expect do
173
- Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).amount
174
- Aggregate.new(:sum, :savings, :bonus, range).amount
175
- end.to change { LineAggregate.count }.by 2
176
- end
177
-
178
- it 'loads the correct saved aggregation' do
179
- # cache the results for filtered and unfiltered aggregations
180
- Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).amount
181
- Aggregate.new(:sum, :savings, :bonus, range).amount
182
-
183
- # ensure a second call loads the correct cached value
184
- amount = Aggregate.new(:sum, :savings, :bonus, range, :filter => filter).formatted_amount
185
- expect(amount).to eq Money.new(10_00)
186
-
187
- amount = Aggregate.new(:sum, :savings, :bonus, range).formatted_amount
188
- expect(amount).to eq Money.new(19_00)
189
- end
190
- end
191
- end
192
- RSpec.describe Aggregate, 'currencies' do
193
- let(:user) { User.make! }
194
- before do
195
- perform_btc_deposit(user, 100_000_000)
196
- perform_btc_deposit(user, 200_000_000)
197
- end
198
-
199
- it 'should calculate the sum in the correct currency' do
200
- amount = Aggregate.new(:sum, :btc_savings, :btc_test_transfer, TimeRange.make(:year => Time.now.year)).formatted_amount
201
- expect(amount).to eq(Money.new(300_000_000, :btc))
202
- end
203
- end
204
- end
205
- end
@@ -1,90 +0,0 @@
1
- # encoding: utf-8
2
- RSpec.describe DoubleEntry::Reporting::LineAggregateFilter do
3
- describe '.filter' do
4
- let(:function) { :sum }
5
- let(:account) { :account }
6
- let(:code) { :transfer_code }
7
- let(:filter_criteria) { nil }
8
- let(:start) { Time.parse('2014-07-27 10:55:44 +1000') }
9
- let(:finish) { Time.parse('2015-07-27 10:55:44 +1000') }
10
- let(:range) do
11
- instance_double(DoubleEntry::Reporting::MonthRange, :start => start, :finish => finish)
12
- end
13
-
14
- let(:lines_scope) { spy(DoubleEntry::Line) }
15
-
16
- subject(:filter) do
17
- DoubleEntry::Reporting::LineAggregateFilter.new(account, code, range, filter_criteria)
18
- end
19
-
20
- before do
21
- stub_const('DoubleEntry::Line', lines_scope)
22
-
23
- allow(DoubleEntry::LineMetadata).to receive(:table_name).and_return('double_entry_line_metadata')
24
-
25
- allow(lines_scope).to receive(:where).and_return(lines_scope)
26
- allow(lines_scope).to receive(:joins).and_return(lines_scope)
27
- allow(lines_scope).to receive(:ten_dollar_purchases).and_return(lines_scope)
28
- allow(lines_scope).to receive(:ten_dollar_purchases_by_category).and_return(lines_scope)
29
-
30
- filter.filter
31
- end
32
-
33
- context 'with named scopes specified' do
34
- let(:filter_criteria) do
35
- [
36
- # an example of calling a named scope called with arguments
37
- {
38
- :scope => {
39
- :name => :ten_dollar_purchases_by_category,
40
- :arguments => [:cat_videos, :cat_pictures],
41
- },
42
- },
43
- # an example of calling a named scope with no arguments
44
- {
45
- :scope => {
46
- :name => :ten_dollar_purchases,
47
- },
48
- },
49
- # an example of providing a single metadatum criteria to filter on
50
- {
51
- :metadata => {
52
- :meme => 'business_cat',
53
- },
54
- },
55
- ]
56
- end
57
-
58
- it 'filters by all the scopes provided' do
59
- expect(DoubleEntry::Line).to have_received(:ten_dollar_purchases)
60
- expect(DoubleEntry::Line).to have_received(:ten_dollar_purchases_by_category).
61
- with(:cat_videos, :cat_pictures)
62
- end
63
-
64
- it 'filters by all the metadata provided' do
65
- expect(DoubleEntry::Line).to have_received(:joins).with(:metadata)
66
- expect(DoubleEntry::Line).to have_received(:where).
67
- with(:double_entry_line_metadata => { :key => :meme, :value => 'business_cat' })
68
- end
69
- end
70
-
71
- context 'with a code specified' do
72
- let(:code) { :transfer_code }
73
-
74
- it 'retrieves the appropriate lines for aggregation' do
75
- expect(DoubleEntry::Line).to have_received(:where).with(:account => account)
76
- expect(DoubleEntry::Line).to have_received(:where).with(:created_at => start..finish)
77
- expect(DoubleEntry::Line).to have_received(:where).with(:code => code)
78
- end
79
- end
80
-
81
- context 'with no code specified' do
82
- let(:code) { nil }
83
-
84
- it 'retrieves the appropriate lines for aggregation' do
85
- expect(DoubleEntry::Line).to have_received(:where).with(:account => account)
86
- expect(DoubleEntry::Line).to have_received(:where).with(:created_at => start..finish)
87
- end
88
- end
89
- end
90
- end