double_entry 1.0.1 → 2.0.0.beta1

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 (67) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +432 -0
  3. data/README.md +36 -9
  4. data/double_entry.gemspec +20 -48
  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/account.rb +38 -45
  8. data/lib/double_entry/account_balance.rb +18 -1
  9. data/lib/double_entry/errors.rb +13 -13
  10. data/lib/double_entry/line.rb +3 -2
  11. data/lib/double_entry/reporting.rb +26 -38
  12. data/lib/double_entry/reporting/aggregate.rb +43 -23
  13. data/lib/double_entry/reporting/aggregate_array.rb +16 -13
  14. data/lib/double_entry/reporting/line_aggregate.rb +3 -2
  15. data/lib/double_entry/reporting/line_aggregate_filter.rb +8 -10
  16. data/lib/double_entry/reporting/line_metadata_filter.rb +33 -0
  17. data/lib/double_entry/transfer.rb +33 -27
  18. data/lib/double_entry/validation.rb +1 -0
  19. data/lib/double_entry/validation/account_fixer.rb +36 -0
  20. data/lib/double_entry/validation/line_check.rb +22 -40
  21. data/lib/double_entry/version.rb +1 -1
  22. data/lib/generators/double_entry/install/install_generator.rb +7 -1
  23. data/lib/generators/double_entry/install/templates/migration.rb +27 -25
  24. metadata +33 -243
  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/script/jack_hammer +0 -210
  32. data/script/setup.sh +0 -8
  33. data/spec/active_record/locking_extensions_spec.rb +0 -110
  34. data/spec/double_entry/account_balance_spec.rb +0 -7
  35. data/spec/double_entry/account_spec.rb +0 -130
  36. data/spec/double_entry/balance_calculator_spec.rb +0 -88
  37. data/spec/double_entry/configuration_spec.rb +0 -50
  38. data/spec/double_entry/line_spec.rb +0 -80
  39. data/spec/double_entry/locking_spec.rb +0 -214
  40. data/spec/double_entry/performance/double_entry_performance_spec.rb +0 -32
  41. data/spec/double_entry/performance/reporting/aggregate_performance_spec.rb +0 -50
  42. data/spec/double_entry/reporting/aggregate_array_spec.rb +0 -123
  43. data/spec/double_entry/reporting/aggregate_spec.rb +0 -205
  44. data/spec/double_entry/reporting/line_aggregate_filter_spec.rb +0 -90
  45. data/spec/double_entry/reporting/line_aggregate_spec.rb +0 -39
  46. data/spec/double_entry/reporting/month_range_spec.rb +0 -139
  47. data/spec/double_entry/reporting/time_range_array_spec.rb +0 -169
  48. data/spec/double_entry/reporting/time_range_spec.rb +0 -45
  49. data/spec/double_entry/reporting/week_range_spec.rb +0 -103
  50. data/spec/double_entry/reporting_spec.rb +0 -181
  51. data/spec/double_entry/transfer_spec.rb +0 -93
  52. data/spec/double_entry/validation/line_check_spec.rb +0 -99
  53. data/spec/double_entry_spec.rb +0 -428
  54. data/spec/generators/double_entry/install/install_generator_spec.rb +0 -30
  55. data/spec/spec_helper.rb +0 -118
  56. data/spec/support/accounts.rb +0 -21
  57. data/spec/support/blueprints.rb +0 -43
  58. data/spec/support/database.example.yml +0 -21
  59. data/spec/support/database.travis.yml +0 -24
  60. data/spec/support/double_entry_spec_helper.rb +0 -27
  61. data/spec/support/gemfiles/Gemfile.rails-3.2.x +0 -8
  62. data/spec/support/gemfiles/Gemfile.rails-4.1.x +0 -6
  63. data/spec/support/gemfiles/Gemfile.rails-4.2.x +0 -5
  64. data/spec/support/gemfiles/Gemfile.rails-5.0.x +0 -5
  65. data/spec/support/performance_helper.rb +0 -26
  66. data/spec/support/reporting_configuration.rb +0 -6
  67. data/spec/support/schema.rb +0 -74
@@ -1,39 +0,0 @@
1
- # encoding: utf-8
2
- RSpec.describe DoubleEntry::Reporting::LineAggregate do
3
- describe '.table_name' do
4
- subject { DoubleEntry::Reporting::LineAggregate.table_name }
5
- it { should eq('double_entry_line_aggregates') }
6
- end
7
-
8
- describe '#aggregate' do
9
- let(:line_relation) { spy }
10
- let(:filter) do
11
- instance_double(DoubleEntry::Reporting::LineAggregateFilter, :filter => line_relation)
12
- end
13
-
14
- let(:function) { :sum }
15
- let(:account) { spy }
16
- let(:code) { spy }
17
- let(:named_scopes) { spy }
18
- let(:range) { spy }
19
-
20
- subject(:aggregate) do
21
- DoubleEntry::Reporting::LineAggregate.aggregate(function, account, code, range, named_scopes)
22
- end
23
-
24
- before do
25
- allow(DoubleEntry::Reporting::LineAggregateFilter).to receive(:new).and_return(filter)
26
- aggregate
27
- end
28
-
29
- it 'applies the specified filters' do
30
- expect(DoubleEntry::Reporting::LineAggregateFilter).to have_received(:new).
31
- with(account, code, range, named_scopes)
32
- expect(filter).to have_received(:filter)
33
- end
34
-
35
- it 'performs the aggregation on the filtered lines' do
36
- expect(line_relation).to have_received(:sum).with(:amount)
37
- end
38
- end
39
- end
@@ -1,139 +0,0 @@
1
- # encoding: utf-8
2
- module DoubleEntry
3
- module Reporting
4
- RSpec.describe MonthRange do
5
- describe '.from_time' do
6
- subject(:from_time) { MonthRange.from_time(given_time) }
7
-
8
- context 'given the Time 31st March 2012' do
9
- let(:given_time) { Time.new(2012, 3, 31) }
10
- its(:year) { should eq 2012 }
11
- its(:month) { should eq 3 }
12
- end
13
-
14
- context 'given the Date 31st March 2012' do
15
- let(:given_time) { Date.parse('2012-03-31') }
16
- its(:year) { should eq 2012 }
17
- its(:month) { should eq 3 }
18
- end
19
- end
20
-
21
- describe '.reportable_months' do
22
- subject(:reportable_months) { MonthRange.reportable_months }
23
-
24
- context 'The date is 1st March 1970' do
25
- before { Timecop.freeze(Time.new(1970, 3, 1)) }
26
-
27
- specify do
28
- should eq [
29
- MonthRange.new(:year => 1970, :month => 1),
30
- MonthRange.new(:year => 1970, :month => 2),
31
- MonthRange.new(:year => 1970, :month => 3),
32
- ]
33
- end
34
-
35
- context 'My business started on 5th Feb 1970' do
36
- before do
37
- DoubleEntry::Reporting.configure do |config|
38
- config.start_of_business = Time.new(1970, 2, 5)
39
- end
40
- end
41
-
42
- specify do
43
- should eq [
44
- MonthRange.new(:year => 1970, :month => 2),
45
- MonthRange.new(:year => 1970, :month => 3),
46
- ]
47
- end
48
- end
49
- end
50
-
51
- context 'The date is 1st Jan 1970' do
52
- before { Timecop.freeze(Time.new(1970, 1, 1)) }
53
-
54
- it { should eq [MonthRange.new(:year => 1970, :month => 1)] }
55
- end
56
- end
57
-
58
- describe '.beginning_of_financial_year' do
59
- let(:month_range) { MonthRange.new(:year => year, :month => month) }
60
- let(:year) { 2014 }
61
-
62
- context 'the first month of the financial year is July' do
63
- subject(:beginning_of_financial_year) { month_range.beginning_of_financial_year }
64
- context 'returns the current year if the month is after July' do
65
- let(:month) { 10 }
66
- it { should eq(MonthRange.new(:year => 2014, :month => 7)) }
67
- end
68
-
69
- context 'returns the previous year if the month is before July' do
70
- let(:month) { 3 }
71
- it { should eq(MonthRange.new(:year => 2013, :month => 7)) }
72
- end
73
- end
74
-
75
- context 'the first month of the financial year is January' do
76
- subject(:beginning_of_financial_year) { month_range.beginning_of_financial_year }
77
-
78
- before do
79
- DoubleEntry::Reporting.configure do |config|
80
- config.first_month_of_financial_year = 1
81
- end
82
- end
83
-
84
- context 'returns the current year if the month is after January' do
85
- let(:month) { 10 }
86
- it { should eq(MonthRange.new(:year => 2014, :month => 1)) }
87
- end
88
-
89
- context 'returns the current year if the month is January' do
90
- let(:month) { 1 }
91
- it { should eq(MonthRange.new(:year => 2014, :month => 1)) }
92
- end
93
- end
94
-
95
- context 'the first month of the financial year is December' do
96
- subject(:beginning_of_financial_year) { month_range.beginning_of_financial_year }
97
-
98
- before do
99
- DoubleEntry::Reporting.configure do |config|
100
- config.first_month_of_financial_year = 12
101
- end
102
- end
103
-
104
- context 'returns the previous year if the month is before December (in the same year)' do
105
- let(:month) { 11 }
106
- it { should eq(MonthRange.new(:year => 2013, :month => 12)) }
107
- end
108
-
109
- context 'returns the previous year if the month is after December (in the next year)' do
110
- let(:year) { 2015 }
111
- let(:month) { 1 }
112
- it { should eq(MonthRange.new(:year => 2014, :month => 12)) }
113
- end
114
-
115
- context 'returns the current year if the month is December' do
116
- let(:month) { 12 }
117
- it { should eq(MonthRange.new(:year => 2014, :month => 12)) }
118
- end
119
- end
120
-
121
- context 'Given a start time of 3rd Dec 1982' do
122
- subject(:reportable_months) { MonthRange.reportable_months(:from => Time.new(1982, 12, 3)) }
123
-
124
- context 'The date is 2nd Feb 1983' do
125
- before { Timecop.freeze(Time.new(1983, 2, 2)) }
126
-
127
- specify do
128
- should eq [
129
- MonthRange.new(:year => 1982, :month => 12),
130
- MonthRange.new(:year => 1983, :month => 1),
131
- MonthRange.new(:year => 1983, :month => 2),
132
- ]
133
- end
134
- end
135
- end
136
- end
137
- end
138
- end
139
- end
@@ -1,169 +0,0 @@
1
- module DoubleEntry
2
- module Reporting
3
- RSpec.describe TimeRangeArray do
4
- describe '.make' do
5
- subject(:time_range_array) { TimeRangeArray.make(range_type, start, finish) }
6
-
7
- context 'for "hour" range type' do
8
- let(:range_type) { 'hour' }
9
-
10
- context 'given start is "2007-05-03 15:00:00" and finish is "2007-05-03 18:00:00"' do
11
- let(:start) { '2007-05-03 15:00:00' }
12
- let(:finish) { '2007-05-03 18:00:00' }
13
- specify do
14
- should eq [
15
- HourRange.from_time(Time.new(2007, 5, 3, 15)),
16
- HourRange.from_time(Time.new(2007, 5, 3, 16)),
17
- HourRange.from_time(Time.new(2007, 5, 3, 17)),
18
- HourRange.from_time(Time.new(2007, 5, 3, 18)),
19
- ]
20
- end
21
- end
22
-
23
- context 'given start and finish are nil' do
24
- it 'should raise an error' do
25
- expect { TimeRangeArray.make(range_type, nil, nil) }.
26
- to raise_error 'Must specify start of range'
27
- end
28
- end
29
- end
30
-
31
- context 'for "day" range type' do
32
- let(:range_type) { 'day' }
33
-
34
- context 'given start is "2007-05-03" and finish is "2007-05-07"' do
35
- let(:start) { '2007-05-03' }
36
- let(:finish) { '2007-05-07' }
37
- specify do
38
- should eq [
39
- DayRange.from_time(Time.new(2007, 5, 3)),
40
- DayRange.from_time(Time.new(2007, 5, 4)),
41
- DayRange.from_time(Time.new(2007, 5, 5)),
42
- DayRange.from_time(Time.new(2007, 5, 6)),
43
- DayRange.from_time(Time.new(2007, 5, 7)),
44
- ]
45
- end
46
- end
47
-
48
- context 'given start and finish are nil' do
49
- it 'should raise an error' do
50
- expect { TimeRangeArray.make(range_type, nil, nil) }.
51
- to raise_error 'Must specify start of range'
52
- end
53
- end
54
- end
55
-
56
- context 'for "week" range type' do
57
- let(:range_type) { 'week' }
58
-
59
- context 'given start is "2007-05-03" and finish is "2007-05-24"' do
60
- let(:start) { '2007-05-03' }
61
- let(:finish) { '2007-05-24' }
62
- specify do
63
- should eq [
64
- WeekRange.from_time(Time.new(2007, 5, 3)),
65
- WeekRange.from_time(Time.new(2007, 5, 10)),
66
- WeekRange.from_time(Time.new(2007, 5, 17)),
67
- WeekRange.from_time(Time.new(2007, 5, 24)),
68
- ]
69
- end
70
- end
71
-
72
- context 'given start and finish are nil' do
73
- it 'should raise an error' do
74
- expect { TimeRangeArray.make(range_type, nil, nil) }.
75
- to raise_error 'Must specify start of range'
76
- end
77
- end
78
- end
79
-
80
- context 'for "month" range type' do
81
- let(:range_type) { 'month' }
82
-
83
- context 'given start is "2007-05-03" and finish is "2007-08-24"' do
84
- let(:start) { '2007-05-03' }
85
- let(:finish) { '2007-08-24' }
86
- specify do
87
- should eq [
88
- MonthRange.from_time(Time.new(2007, 5)),
89
- MonthRange.from_time(Time.new(2007, 6)),
90
- MonthRange.from_time(Time.new(2007, 7)),
91
- MonthRange.from_time(Time.new(2007, 8)),
92
- ]
93
- end
94
- end
95
-
96
- context 'given finish is nil' do
97
- let(:start) { '2006-08-03' }
98
- let(:finish) { nil }
99
-
100
- context 'and the date is "2007-04-13"' do
101
- before { Timecop.freeze(Time.new(2007, 4, 13)) }
102
-
103
- specify do
104
- should eq [
105
- MonthRange.from_time(Time.new(2006, 8)),
106
- MonthRange.from_time(Time.new(2006, 9)),
107
- MonthRange.from_time(Time.new(2006, 10)),
108
- MonthRange.from_time(Time.new(2006, 11)),
109
- MonthRange.from_time(Time.new(2006, 12)),
110
- MonthRange.from_time(Time.new(2007, 1)),
111
- MonthRange.from_time(Time.new(2007, 2)),
112
- MonthRange.from_time(Time.new(2007, 3)),
113
- MonthRange.from_time(Time.new(2007, 4)),
114
- ]
115
- end
116
- end
117
- end
118
- end
119
-
120
- context 'for "year" range type' do
121
- let(:range_type) { 'year' }
122
-
123
- context 'given the date is "2009-11-23"' do
124
- before { Timecop.freeze(Time.new(2009, 11, 23)) }
125
-
126
- context 'given start is "2007-05-03" and finish is "2008-08-24"' do
127
- let(:start) { '2007-05-03' }
128
- let(:finish) { '2008-08-24' }
129
-
130
- it 'takes notice of start and finish' do
131
- should eq [
132
- YearRange.from_time(Time.new(2007)),
133
- YearRange.from_time(Time.new(2008)),
134
- ]
135
- end
136
- end
137
-
138
- context 'given the start of business is "2006-07-10"' do
139
- before do
140
- allow(DoubleEntry::Reporting).
141
- to receive_message_chain('configuration.start_of_business').
142
- and_return(Time.new(2006, 7, 10))
143
- end
144
-
145
- context 'given start and finish are nil' do
146
- let(:start) { nil }
147
- let(:finish) { nil }
148
- specify do
149
- should eq [
150
- YearRange.from_time(Time.new(2006)),
151
- YearRange.from_time(Time.new(2007)),
152
- YearRange.from_time(Time.new(2008)),
153
- YearRange.from_time(Time.new(2009)),
154
- ]
155
- end
156
- end
157
- end
158
- end
159
- end
160
-
161
- context 'given an invalid range type "ueue"' do
162
- it 'should raise an error' do
163
- expect { TimeRangeArray.make('ueue') }.to raise_error ArgumentError
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end
@@ -1,45 +0,0 @@
1
- # encoding: utf-8
2
- module DoubleEntry
3
- module Reporting
4
- RSpec.describe TimeRange do
5
- it 'should correctly calculate a month range' do
6
- ar = TimeRange.make(:year => 2009, :month => 10)
7
- expect(ar.start.to_s).to eq Time.mktime(2009, 10, 1, 0, 0, 0).to_s
8
- expect(ar.finish.to_s).to eq Time.mktime(2009, 10, 31, 23, 59, 59).to_s
9
- end
10
-
11
- it 'should correctly calculate the beginning of the financial year' do
12
- range = TimeRange.make(:year => 2009, :month => 6).beginning_of_financial_year
13
- expect(range.month).to eq 7
14
- expect(range.year).to eq 2008
15
- range = TimeRange.make(:year => 2009, :month => 7).beginning_of_financial_year
16
- expect(range.month).to eq 7
17
- expect(range.year).to eq 2009
18
- end
19
-
20
- it "should correctly calculate the current week range for New Year's Day" do
21
- Timecop.freeze Time.mktime(2009, 1, 1) do
22
- expect(WeekRange.current.week).to eq 1
23
- end
24
- end
25
-
26
- it 'should correctly calculate the current week range for the first Sunday in the year after New Years' do
27
- Timecop.freeze Time.mktime(2009, 1, 4) do
28
- expect(WeekRange.current.week).to eq 1
29
- end
30
- end
31
-
32
- it 'should correctly calculate the current week range for the first Monday in the year after New Years' do
33
- Timecop.freeze Time.mktime(2009, 1, 5) do
34
- expect(WeekRange.current.week).to eq 2
35
- end
36
- end
37
-
38
- it 'should correctly calculate the current week range for my birthday' do
39
- Timecop.freeze Time.mktime(2009, 3, 27) do
40
- expect(WeekRange.current.week).to eq 13
41
- end
42
- end
43
- end
44
- end
45
- end
@@ -1,103 +0,0 @@
1
- # encoding: utf-8
2
- module DoubleEntry
3
- module Reporting
4
- RSpec.describe WeekRange do
5
- it 'should start week 1 of a year in the first week that has any day in the year' do
6
- range = WeekRange.new(:year => 2011, :week => 1)
7
- expect(range.start).to eq Time.parse('2010-12-27 00:00:00')
8
- end
9
-
10
- it 'should handle times in the last week of the year properly' do
11
- range = WeekRange.from_time(Time.parse('2010-12-29 11:30:00'))
12
- expect(range.year).to eq 2011
13
- expect(range.week).to eq 1
14
- expect(range.start).to eq Time.parse('2010-12-27 00:00:00')
15
- end
16
-
17
- it 'handles daylight savings time properly' do
18
- Time.use_zone('America/Los_Angeles') do
19
- time = Time.zone.parse('Mon, 10 Mar 2014')
20
- range = WeekRange.from_time time
21
- expect(range.start.day).to eq 10
22
- end
23
- end
24
-
25
- describe '::from_time' do
26
- subject(:from_time) { WeekRange.from_time(given_time) }
27
-
28
- context 'given the Time 31st March 2012' do
29
- let(:given_time) { Time.new(2012, 3, 31) }
30
- its(:year) { should eq 2012 }
31
- its(:week) { should eq 14 }
32
- end
33
-
34
- context 'given the Date 31st March 2012' do
35
- let(:given_time) { Date.parse('2012-03-31') }
36
- its(:year) { should eq 2012 }
37
- its(:week) { should eq 14 }
38
- end
39
- end
40
-
41
- describe '::reportable_weeks' do
42
- subject(:reportable_weeks) { WeekRange.reportable_weeks }
43
-
44
- context 'The date is 1st Feb 1970' do
45
- before { Timecop.freeze(Time.new(1970, 2, 1)) }
46
-
47
- specify do
48
- should eq [
49
- WeekRange.new(:year => 1970, :week => 1),
50
- WeekRange.new(:year => 1970, :week => 2),
51
- WeekRange.new(:year => 1970, :week => 3),
52
- WeekRange.new(:year => 1970, :week => 4),
53
- WeekRange.new(:year => 1970, :week => 5),
54
- ]
55
- end
56
-
57
- context 'My business started on 25th Jan 1970' do
58
- before do
59
- DoubleEntry::Reporting.configure do |config|
60
- config.start_of_business = Time.new(1970, 1, 25)
61
- end
62
- end
63
-
64
- specify do
65
- should eq [
66
- WeekRange.new(:year => 1970, :week => 4),
67
- WeekRange.new(:year => 1970, :week => 5),
68
- ]
69
- end
70
- end
71
- end
72
-
73
- context 'The date is 1st Jan 1970' do
74
- before { Timecop.freeze(Time.new(1970, 1, 1)) }
75
-
76
- it { should eq [WeekRange.new(:year => 1970, :week => 1)] }
77
- end
78
-
79
- context 'Given a start time of 3rd Dec 1982' do
80
- subject(:reportable_weeks) { WeekRange.reportable_weeks(:from => Time.new(1982, 12, 3)) }
81
-
82
- context 'The date is 12nd Jan 1983' do
83
- before { Timecop.freeze(Time.new(1983, 2, 2)) }
84
- specify do
85
- should eq [
86
- WeekRange.new(:year => 1982, :week => 49),
87
- WeekRange.new(:year => 1982, :week => 50),
88
- WeekRange.new(:year => 1982, :week => 51),
89
- WeekRange.new(:year => 1982, :week => 52),
90
- WeekRange.new(:year => 1983, :week => 1),
91
- WeekRange.new(:year => 1983, :week => 2),
92
- WeekRange.new(:year => 1983, :week => 3),
93
- WeekRange.new(:year => 1983, :week => 4),
94
- WeekRange.new(:year => 1983, :week => 5),
95
- WeekRange.new(:year => 1983, :week => 6),
96
- ]
97
- end
98
- end
99
- end
100
- end
101
- end
102
- end
103
- end