double_entry 0.10.0 → 0.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -1
  3. data/.rubocop.yml +55 -0
  4. data/.travis.yml +23 -12
  5. data/README.md +5 -1
  6. data/Rakefile +8 -3
  7. data/double_entry.gemspec +4 -3
  8. data/lib/active_record/locking_extensions.rb +28 -40
  9. data/lib/active_record/locking_extensions/log_subscriber.rb +4 -4
  10. data/lib/double_entry.rb +0 -2
  11. data/lib/double_entry/account.rb +13 -16
  12. data/lib/double_entry/account_balance.rb +0 -4
  13. data/lib/double_entry/balance_calculator.rb +4 -5
  14. data/lib/double_entry/configurable.rb +0 -2
  15. data/lib/double_entry/configuration.rb +2 -3
  16. data/lib/double_entry/errors.rb +2 -2
  17. data/lib/double_entry/line.rb +13 -16
  18. data/lib/double_entry/locking.rb +13 -18
  19. data/lib/double_entry/reporting.rb +2 -3
  20. data/lib/double_entry/reporting/aggregate.rb +90 -88
  21. data/lib/double_entry/reporting/aggregate_array.rb +58 -58
  22. data/lib/double_entry/reporting/day_range.rb +37 -35
  23. data/lib/double_entry/reporting/hour_range.rb +40 -37
  24. data/lib/double_entry/reporting/line_aggregate.rb +27 -28
  25. data/lib/double_entry/reporting/month_range.rb +67 -67
  26. data/lib/double_entry/reporting/time_range.rb +40 -38
  27. data/lib/double_entry/reporting/time_range_array.rb +3 -5
  28. data/lib/double_entry/reporting/week_range.rb +77 -78
  29. data/lib/double_entry/reporting/year_range.rb +27 -27
  30. data/lib/double_entry/transfer.rb +14 -15
  31. data/lib/double_entry/validation/line_check.rb +92 -86
  32. data/lib/double_entry/version.rb +1 -1
  33. data/lib/generators/double_entry/install/install_generator.rb +1 -2
  34. data/lib/generators/double_entry/install/templates/migration.rb +0 -2
  35. data/script/jack_hammer +1 -1
  36. data/spec/active_record/locking_extensions_spec.rb +45 -38
  37. data/spec/double_entry/account_balance_spec.rb +4 -5
  38. data/spec/double_entry/account_spec.rb +43 -44
  39. data/spec/double_entry/balance_calculator_spec.rb +6 -8
  40. data/spec/double_entry/configuration_spec.rb +14 -16
  41. data/spec/double_entry/line_spec.rb +25 -26
  42. data/spec/double_entry/locking_spec.rb +34 -39
  43. data/spec/double_entry/reporting/aggregate_array_spec.rb +8 -10
  44. data/spec/double_entry/reporting/aggregate_spec.rb +84 -44
  45. data/spec/double_entry/reporting/line_aggregate_spec.rb +7 -6
  46. data/spec/double_entry/reporting/month_range_spec.rb +109 -103
  47. data/spec/double_entry/reporting/time_range_array_spec.rb +145 -135
  48. data/spec/double_entry/reporting/time_range_spec.rb +36 -35
  49. data/spec/double_entry/reporting/week_range_spec.rb +82 -76
  50. data/spec/double_entry/reporting_spec.rb +9 -13
  51. data/spec/double_entry/transfer_spec.rb +13 -15
  52. data/spec/double_entry/validation/line_check_spec.rb +73 -79
  53. data/spec/double_entry_spec.rb +65 -68
  54. data/spec/generators/double_entry/install/install_generator_spec.rb +7 -10
  55. data/spec/spec_helper.rb +68 -10
  56. data/spec/support/accounts.rb +2 -4
  57. data/spec/support/double_entry_spec_helper.rb +4 -4
  58. data/spec/support/gemfiles/Gemfile.rails-3.2.x +1 -0
  59. metadata +31 -2
@@ -1,57 +1,59 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
- module Reporting
4
- class TimeRange
5
- attr_reader :start, :finish
6
- attr_reader :year, :month, :week, :day, :hour, :range_type
3
+ module Reporting
4
+ class TimeRange
5
+ attr_reader :start, :finish
6
+ attr_reader :year, :month, :week, :day, :hour, :range_type
7
7
 
8
- def self.make(options = {})
9
- @options = options
10
- case
11
- when (options[:year] and options[:week] and options[:day] and options[:hour])
8
+ def self.make(options = {})
9
+ @options = options
10
+ case
11
+ when options[:year] && options[:week] && options[:day] && options[:hour]
12
12
  HourRange.new(options)
13
- when (options[:year] and options[:week] and options[:day])
13
+ when options[:year] && options[:week] && options[:day]
14
14
  DayRange.new(options)
15
- when (options[:year] and options[:week])
15
+ when options[:year] && options[:week]
16
16
  WeekRange.new(options)
17
- when (options[:year] and options[:month])
17
+ when options[:year] && options[:month]
18
18
  MonthRange.new(options)
19
19
  when options[:year]
20
20
  YearRange.new(options)
21
21
  else
22
- raise "Invalid range information #{options}"
22
+ fail "Invalid range information #{options}"
23
+ end
23
24
  end
24
- end
25
25
 
26
- def self.range_from_time_for_period(start_time, period_name)
27
- case period_name
28
- when 'month'
29
- YearRange.from_time(start_time)
30
- when 'week'
31
- YearRange.from_time(start_time)
32
- when 'day'
33
- MonthRange.from_time(start_time)
34
- when 'hour'
35
- DayRange.from_time(start_time)
36
- end
37
- end
26
+ def self.range_from_time_for_period(start_time, period_name)
27
+ case period_name
28
+ when 'month'
29
+ YearRange.from_time(start_time)
30
+ when 'week'
31
+ YearRange.from_time(start_time)
32
+ when 'day'
33
+ MonthRange.from_time(start_time)
34
+ when 'hour'
35
+ DayRange.from_time(start_time)
36
+ end
37
+ end
38
38
 
39
- def include?(time)
40
- (time >= @start) and (time <= @finish)
41
- end
39
+ def include?(time)
40
+ time >= @start &&
41
+ time <= @finish
42
+ end
42
43
 
43
- def initialize(options)
44
- @year = options[:year]
45
- @range_type = options[:range_type] || :normal
46
- end
44
+ def initialize(options)
45
+ @year = options[:year]
46
+ @range_type = options[:range_type] || :normal
47
+ @month = @week = @day = @hour = nil
48
+ end
47
49
 
48
- def key
49
- "#{@year}:#{@month}:#{@week}:#{@day}:#{@hour}"
50
- end
50
+ def key
51
+ "#{@year}:#{@month}:#{@week}:#{@day}:#{@hour}"
52
+ end
51
53
 
52
- def human_readable_name
53
- self.class.name.gsub('DoubleEntry::Reporting::', '').gsub('Range', '')
54
+ def human_readable_name
55
+ self.class.name.gsub('DoubleEntry::Reporting::', '').gsub('Range', '')
56
+ end
54
57
  end
55
58
  end
56
- end
57
59
  end
@@ -2,7 +2,6 @@
2
2
  module DoubleEntry
3
3
  module Reporting
4
4
  class TimeRangeArray
5
-
6
5
  attr_reader :type, :require_start
7
6
  alias_method :require_start?, :require_start
8
7
 
@@ -14,7 +13,7 @@ module DoubleEntry
14
13
  def make(start = nil, finish = nil)
15
14
  start = start_range(start)
16
15
  finish = finish_range(finish)
17
- [ start ].tap do |array|
16
+ [start].tap do |array|
18
17
  while start != finish
19
18
  start = start.next
20
19
  array << start
@@ -23,7 +22,7 @@ module DoubleEntry
23
22
  end
24
23
 
25
24
  def start_range(start = nil)
26
- raise "Must specify start of range" if start.blank? && require_start?
25
+ fail 'Must specify start of range' if start.blank? && require_start?
27
26
  start_time = start ? Time.parse(start) : Reporting.configuration.start_of_business
28
27
  type.from_time(start_time)
29
28
  end
@@ -42,10 +41,9 @@ module DoubleEntry
42
41
 
43
42
  def self.make(range_type, start = nil, finish = nil)
44
43
  factory = FACTORIES[range_type]
45
- raise ArgumentError.new("Invalid range type '#{range_type}'") unless factory
44
+ fail ArgumentError, "Invalid range type '#{range_type}'" unless factory
46
45
  factory.make(start, finish)
47
46
  end
48
-
49
47
  end
50
48
  end
51
49
  end
@@ -1,108 +1,107 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
- module Reporting
4
- # We use a particularly crazy week numbering system: week 1 of any given year
5
- # is the first week with any days that fall into that year.
6
- #
7
- # So, for example, week 1 of 2011 starts on 27 Dec 2010.
8
- class WeekRange < TimeRange
9
-
10
- class << self
3
+ module Reporting
4
+ # We use a particularly crazy week numbering system: week 1 of any given year
5
+ # is the first week with any days that fall into that year.
6
+ #
7
+ # So, for example, week 1 of 2011 starts on 27 Dec 2010.
8
+ class WeekRange < TimeRange
9
+ class << self
10
+ def from_time(time)
11
+ date = time.to_date
12
+ week = date.cweek
13
+ year = date.end_of_week.year
14
+
15
+ if date.beginning_of_week.year != year
16
+ week = 1
17
+ elsif date.beginning_of_year.cwday > Date::DAYNAMES.index('Thursday')
18
+ week += 1
19
+ end
11
20
 
12
- def from_time(time)
13
- date = time.to_date
14
- week = date.cweek
15
- year = date.end_of_week.year
16
-
17
- if date.beginning_of_week.year != year
18
- week = 1
19
- elsif date.beginning_of_year.cwday > Date::DAYNAMES.index('Thursday')
20
- week += 1
21
+ new(:year => year, :week => week)
21
22
  end
22
23
 
23
- new(:year => year, :week => week)
24
- end
25
-
26
- def current
27
- from_time(Time.now)
28
- end
24
+ def current
25
+ from_time(Time.now)
26
+ end
29
27
 
30
- # Obtain a sequence of WeekRanges from the given start to the current
31
- # week.
32
- #
33
- # @option options :from [Time] Time of the first in the returned sequence
34
- # of WeekRanges.
35
- # @return [Array<WeekRange>]
36
- def reportable_weeks(options = {})
37
- week = options[:from] ? from_time(options[:from]) : earliest_week
38
- last_in_sequence = self.current
39
- [week].tap do |weeks|
40
- while week != last_in_sequence
41
- week = week.next
42
- weeks << week
28
+ # Obtain a sequence of WeekRanges from the given start to the current
29
+ # week.
30
+ #
31
+ # @option options :from [Time] Time of the first in the returned sequence
32
+ # of WeekRanges.
33
+ # @return [Array<WeekRange>]
34
+ def reportable_weeks(options = {})
35
+ week = options[:from] ? from_time(options[:from]) : earliest_week
36
+ last_in_sequence = current
37
+ [week].tap do |weeks|
38
+ while week != last_in_sequence
39
+ week = week.next
40
+ weeks << week
41
+ end
43
42
  end
44
43
  end
45
- end
46
44
 
47
- private
45
+ private
48
46
 
49
- def start_of_year(year)
50
- Time.local(year, 1, 1).beginning_of_week
51
- end
47
+ def start_of_year(year)
48
+ Time.local(year, 1, 1).beginning_of_week
49
+ end
52
50
 
53
- def earliest_week
54
- from_time(Reporting.configuration.start_of_business)
51
+ def earliest_week
52
+ from_time(Reporting.configuration.start_of_business)
53
+ end
55
54
  end
56
- end
57
55
 
58
- attr_reader :year, :week
56
+ attr_reader :year, :week
59
57
 
60
- def initialize(options = {})
61
- super options
58
+ def initialize(options = {})
59
+ super options
62
60
 
63
- if options.present?
64
- @week = options[:week]
61
+ if options.present?
62
+ @week = options[:week]
65
63
 
66
- @start = week_and_year_to_time(@week, @year)
67
- @finish = @start.end_of_week
64
+ @start = week_and_year_to_time(@week, @year)
65
+ @finish = @start.end_of_week
68
66
 
69
- @start = earliest_week.start if options[:range_type] == :all_time
67
+ @start = earliest_week.start if options[:range_type] == :all_time
68
+ end
70
69
  end
71
- end
72
70
 
73
- def previous
74
- from_time(@start - 1.week)
75
- end
71
+ def previous
72
+ from_time(@start - 1.week)
73
+ end
76
74
 
77
- def next
78
- from_time(@start + 1.week)
79
- end
75
+ def next
76
+ from_time(@start + 1.week)
77
+ end
80
78
 
81
- def ==(other)
82
- (self.week == other.week) && (self.year == other.year)
83
- end
79
+ def ==(other)
80
+ week == other.week &&
81
+ year == other.year
82
+ end
84
83
 
85
- def all_time
86
- self.class.new(:year => year, :week => week, :range_type => :all_time)
87
- end
84
+ def all_time
85
+ self.class.new(:year => year, :week => week, :range_type => :all_time)
86
+ end
88
87
 
89
- def to_s
90
- "#{year}, Week #{week}"
91
- end
88
+ def to_s
89
+ "#{year}, Week #{week}"
90
+ end
92
91
 
93
- private
92
+ private
94
93
 
95
- def from_time(time)
96
- self.class.from_time(time)
97
- end
94
+ def from_time(time)
95
+ self.class.from_time(time)
96
+ end
98
97
 
99
- def earliest_week
100
- self.class.send(:earliest_week)
101
- end
98
+ def earliest_week
99
+ self.class.send(:earliest_week)
100
+ end
102
101
 
103
- def week_and_year_to_time(week, year)
104
- self.class.send(:start_of_year, year) + (week - 1).weeks
102
+ def week_and_year_to_time(week, year)
103
+ self.class.send(:start_of_year, year) + (week - 1).weeks
104
+ end
105
105
  end
106
106
  end
107
- end
108
107
  end
@@ -1,40 +1,40 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
- module Reporting
4
- class YearRange < TimeRange
5
- attr_reader :year
3
+ module Reporting
4
+ class YearRange < TimeRange
5
+ attr_reader :year
6
6
 
7
- def initialize(options)
8
- super options
7
+ def initialize(options)
8
+ super options
9
9
 
10
- year_start = Time.local(@year, 1, 1)
11
- @start = year_start
12
- @finish = year_start.end_of_year
13
- end
10
+ year_start = Time.local(@year, 1, 1)
11
+ @start = year_start
12
+ @finish = year_start.end_of_year
13
+ end
14
14
 
15
- def self.current
16
- new(:year => Time.now.year)
17
- end
15
+ def self.current
16
+ new(:year => Time.now.year)
17
+ end
18
18
 
19
- def self.from_time(time)
20
- new(:year => time.year)
21
- end
19
+ def self.from_time(time)
20
+ new(:year => time.year)
21
+ end
22
22
 
23
- def ==(other)
24
- self.year == other.year
25
- end
23
+ def ==(other)
24
+ year == other.year
25
+ end
26
26
 
27
- def previous
28
- YearRange.new(:year => year - 1)
29
- end
27
+ def previous
28
+ YearRange.new(:year => year - 1)
29
+ end
30
30
 
31
- def next
32
- YearRange.new(:year => year + 1)
33
- end
31
+ def next
32
+ YearRange.new(:year => year + 1)
33
+ end
34
34
 
35
- def to_s
36
- year.to_s
35
+ def to_s
36
+ year.to_s
37
+ end
37
38
  end
38
39
  end
39
- end
40
40
  end
@@ -1,7 +1,6 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
3
  class Transfer
4
-
5
4
  class << self
6
5
  attr_writer :transfers, :code_max_length
7
6
 
@@ -17,7 +16,7 @@ module DoubleEntry
17
16
 
18
17
  # @api private
19
18
  def transfer(amount, options = {})
20
- raise TransferIsNegative if amount < Money.zero
19
+ fail TransferIsNegative if amount < Money.zero
21
20
  from = options[:from]
22
21
  to = options[:to]
23
22
  code = options[:code]
@@ -37,14 +36,14 @@ module DoubleEntry
37
36
  end
38
37
 
39
38
  def find!(from, to, code)
40
- transfer = find(from, to, code)
41
- raise TransferNotAllowed.new([from.identifier, to.identifier, code].inspect) unless transfer
42
- return transfer
39
+ find(from, to, code).tap do |transfer|
40
+ fail TransferNotAllowed, [from.identifier, to.identifier, code].inspect unless transfer
41
+ end
43
42
  end
44
43
 
45
44
  def <<(transfer)
46
45
  if _find(transfer.from, transfer.to, transfer.code)
47
- raise DuplicateTransfer.new
46
+ fail DuplicateTransfer
48
47
  else
49
48
  super(transfer)
50
49
  end
@@ -54,7 +53,9 @@ module DoubleEntry
54
53
 
55
54
  def _find(from, to, code)
56
55
  detect do |transfer|
57
- transfer.from == from and transfer.to == to and transfer.code == code
56
+ transfer.from == from &&
57
+ transfer.to == to &&
58
+ transfer.code == code
58
59
  end
59
60
  end
60
61
  end
@@ -66,18 +67,17 @@ module DoubleEntry
66
67
  @from = attributes[:from]
67
68
  @to = attributes[:to]
68
69
  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
- )
70
+ fail TransferCodeTooLongError,
71
+ "transfer code '#{code}' is too long. Please limit it to #{Transfer.code_max_length} characters."
72
72
  end
73
73
  end
74
74
 
75
75
  def process(amount, from, to, code, detail)
76
- if from.scope_identity == to.scope_identity and from.identifier == to.identifier
77
- raise TransferNotAllowed.new("from and to are identical")
76
+ if from.scope_identity == to.scope_identity && from.identifier == to.identifier
77
+ fail TransferNotAllowed, 'from and to are identical'
78
78
  end
79
79
  if to.currency != from.currency
80
- raise MismatchedCurrencies.new("Missmatched currency (#{to.currency} <> #{from.currency})")
80
+ fail MismatchedCurrencies, "Missmatched currency (#{to.currency} <> #{from.currency})"
81
81
  end
82
82
  Locking.lock_accounts(from, to) do
83
83
  credit, debit = Line.new, Line.new
@@ -86,7 +86,7 @@ module DoubleEntry
86
86
  debit_balance = Locking.balance_for_locked_account(to)
87
87
 
88
88
  credit_balance.update_attribute :balance, credit_balance.balance - amount
89
- debit_balance.update_attribute :balance, debit_balance.balance + amount
89
+ debit_balance.update_attribute :balance, debit_balance.balance + amount
90
90
 
91
91
  credit.amount, debit.amount = -amount, amount
92
92
  credit.account, debit.account = from, to
@@ -102,6 +102,5 @@ module DoubleEntry
102
102
  credit.update_attribute :partner_id, debit.id
103
103
  end
104
104
  end
105
-
106
105
  end
107
106
  end