double_entry 1.0.1 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
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,4 +1,4 @@
1
- # encoding: utf-8
1
+
2
2
  lib = File.expand_path('../lib', __FILE__)
3
3
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
 
@@ -7,67 +7,39 @@ require 'double_entry/version'
7
7
  Gem::Specification.new do |gem|
8
8
  gem.name = 'double_entry'
9
9
  gem.version = DoubleEntry::VERSION
10
- gem.authors = ['Anthony Sellitti', 'Keith Pitt', 'Martin Jagusch', 'Martin Spickermann', 'Mark Turnley', 'Orien Madgwick', 'Pete Yandall', 'Stephanie Staub', 'Giancarlo Salamanca']
11
- gem.email = ['anthony.sellitti@envato.com', 'me@keithpitt.com', '_@mj.io', 'spickemann@gmail.com', 'mark@envato.com', '_@orien.io', 'pete@envato.com', 'staub.steph@gmail.com', 'giancarlo@salamanca.net.au']
10
+ gem.authors = ['Envato']
11
+ gem.email = ['rubygems@envato.com']
12
12
  gem.summary = 'Tools to build your double entry financial ledger'
13
13
  gem.homepage = 'https://github.com/envato/double_entry'
14
14
 
15
- gem.files = `git ls-files`.split($/)
16
- gem.executables = gem.files.grep(%r{bin/}).map { |f| File.basename(f) }
17
- gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ['lib']
19
-
20
- gem.post_install_message = <<-'POSTINSTALLMESSAGE'
21
- Please note the following changes in DoubleEntry:
22
- - New table `double_entry_line_metadata` has been introduced and is *required* for
23
- aggregate reporting filtering to work. Existing applications must manually manage
24
- this change via a migration similar to the following:
25
-
26
- class CreateDoubleEntryLineMetadata < ActiveRecord::Migration
27
- def self.up
28
- create_table "#{DoubleEntry.table_name_prefix}line_metadata", :force => true do |t|
29
- t.integer "line_id", :null => false
30
- t.string "key", :limit => 48, :null => false
31
- t.string "value", :limit => 64, :null => false
32
- t.timestamps :null => false
33
- end
34
-
35
- add_index "#{DoubleEntry.table_name_prefix}line_metadata",
36
- ["line_id", "key", "value"],
37
- :name => "lines_meta_line_id_key_value_idx"
38
- end
15
+ gem.metadata = {
16
+ 'bug_tracker_uri' => 'https://github.com/envato/double_entry/issues',
17
+ 'changelog_uri' => 'https://github.com/envato/double_entry/blob/master/CHANGELOG.md',
18
+ 'documentation_uri' => 'https://www.rubydoc.info/github/envato/double_entry/',
19
+ 'source_code_uri' => 'https://github.com/envato/double_entry',
20
+ }
39
21
 
40
- def self.down
41
- drop_table "#{DoubleEntry.table_name_prefix}line_metadata"
42
- end
43
- end
44
-
45
- Please ensure that you update your database accordingly.
46
- POSTINSTALLMESSAGE
22
+ gem.files = `git ls-files -z`.split("\x0").select do |f|
23
+ f.match(%r{^(?:double_entry.gemspec|README|LICENSE|CHANGELOG|lib/)})
24
+ end
25
+ gem.require_paths = ['lib']
26
+ gem.required_ruby_version = '>= 2.2.0'
47
27
 
48
- gem.add_dependency 'money', '>= 6.0.0'
49
28
  gem.add_dependency 'activerecord', '>= 3.2.0'
50
29
  gem.add_dependency 'activesupport', '>= 3.2.0'
30
+ gem.add_dependency 'money', '>= 6.0.0'
51
31
  gem.add_dependency 'railties', '>= 3.2.0'
52
32
 
53
- gem.add_development_dependency 'rake'
54
33
  gem.add_development_dependency 'mysql2'
55
34
  gem.add_development_dependency 'pg'
35
+ gem.add_development_dependency 'rake'
56
36
  gem.add_development_dependency 'sqlite3'
57
37
 
58
- gem.add_development_dependency 'rspec'
59
- gem.add_development_dependency 'rspec-its'
60
- gem.add_development_dependency 'rspec-instafail'
61
38
  gem.add_development_dependency 'database_cleaner'
39
+ gem.add_development_dependency 'factory_bot'
62
40
  gem.add_development_dependency 'generator_spec'
63
- gem.add_development_dependency 'machinist'
64
- gem.add_development_dependency 'timecop'
65
- gem.add_development_dependency 'test-unit'
66
-
67
- gem.add_development_dependency 'pry'
68
- gem.add_development_dependency 'pry-doc'
69
- gem.add_development_dependency 'pry-byebug' if RUBY_VERSION >= '2.0.0'
70
- gem.add_development_dependency 'pry-stack_explorer'
71
- gem.add_development_dependency 'awesome_print'
41
+ gem.add_development_dependency 'rspec'
42
+ gem.add_development_dependency 'rspec-its'
72
43
  gem.add_development_dependency 'ruby-prof'
44
+ gem.add_development_dependency 'timecop'
73
45
  end
@@ -18,7 +18,7 @@ module ActiveRecord
18
18
  yield
19
19
  rescue ActiveRecord::StatementInvalid => exception
20
20
  if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
21
- ActiveSupport::Notifications.publish('deadlock_restart.active_record', :exception => exception)
21
+ ActiveSupport::Notifications.publish('deadlock_restart.double_entry', :exception => exception)
22
22
 
23
23
  raise ActiveRecord::RestartTransaction
24
24
  else
@@ -46,7 +46,7 @@ module ActiveRecord
46
46
  yield
47
47
  rescue ActiveRecord::StatementInvalid, ActiveRecord::RecordNotUnique => exception
48
48
  if exception.message =~ /duplicate/i || exception.message =~ /ConstraintException/
49
- ActiveSupport::Notifications.publish('duplicate_ignore.active_record', :exception => exception)
49
+ ActiveSupport::Notifications.publish('duplicate_ignore.double_entry', :exception => exception)
50
50
 
51
51
  # Just ignore it...someone else has already created the record.
52
52
  else
@@ -63,7 +63,7 @@ module ActiveRecord
63
63
  if exception.message =~ /deadlock/i || exception.message =~ /database is locked/i
64
64
  # Somebody else is in the midst of creating the record. We'd better
65
65
  # retry, so we ensure they're done before we move on.
66
- ActiveSupport::Notifications.publish('deadlock_retry.active_record', :exception => exception)
66
+ ActiveSupport::Notifications.publish('deadlock_retry.double_entry', :exception => exception)
67
67
 
68
68
  retry
69
69
  else
@@ -26,4 +26,4 @@ module ActiveRecord
26
26
  end
27
27
  end
28
28
 
29
- ActiveRecord::LockingExtensions::LogSubscriber.attach_to :active_record
29
+ ActiveRecord::LockingExtensions::LogSubscriber.attach_to :double_entry
@@ -1,79 +1,67 @@
1
1
  # encoding: utf-8
2
+ require 'forwardable'
3
+
2
4
  module DoubleEntry
3
5
  class Account
4
6
  class << self
5
- attr_writer :accounts, :scope_identifier_max_length, :account_identifier_max_length
7
+ attr_accessor :scope_identifier_max_length, :account_identifier_max_length
8
+ attr_writer :accounts
6
9
 
7
10
  # @api private
8
11
  def accounts
9
12
  @accounts ||= Set.new
10
13
  end
11
14
 
12
- # @api private
13
- def scope_identifier_max_length
14
- @scope_identifier_max_length ||= 23
15
- end
16
-
17
- # @api private
18
- def account_identifier_max_length
19
- @account_identifier_max_length ||= 31
20
- end
21
-
22
15
  # @api private
23
16
  def account(identifier, options = {})
24
- account = accounts.find(identifier, options[:scope].present?)
25
- Instance.new(:account => account, :scope => options[:scope])
17
+ account = accounts.find(identifier, (options[:scope].present? || options[:scope_identity].present?))
18
+ Instance.new(:account => account, :scope => options[:scope], :scope_identity => options[:scope_identity])
26
19
  end
27
20
 
28
21
  # @api private
29
22
  def currency(identifier)
30
- accounts.detect { |a| a.identifier == identifier }.try(:currency)
23
+ accounts.find_without_scope(identifier).try(:currency)
31
24
  end
32
25
  end
33
26
 
34
27
  # @api private
35
- class Set < Array
28
+ class Set
29
+ extend Forwardable
30
+
31
+ delegate [:each, :map] => :all
32
+
36
33
  def define(attributes)
37
- self << Account.new(attributes)
34
+ Account.new(attributes).tap do |account|
35
+ if find_without_scope(account.identifier)
36
+ fail DuplicateAccount
37
+ else
38
+ backing_collection[account.identifier] = account
39
+ end
40
+ end
38
41
  end
39
42
 
40
43
  def find(identifier, scoped)
41
- found_account = detect do |account|
42
- account.identifier == identifier && account.scoped? == scoped
43
- end
44
- fail UnknownAccount, "account: #{identifier} scoped?: #{scoped}" unless found_account
45
- found_account
46
- end
44
+ found_account = find_without_scope(identifier)
47
45
 
48
- def <<(account)
49
- if any? { |a| a.identifier == account.identifier }
50
- fail DuplicateAccount
46
+ if found_account && found_account.scoped? == scoped
47
+ found_account
51
48
  else
52
- super
49
+ fail UnknownAccount, "account: #{identifier} scoped?: #{scoped}"
53
50
  end
54
51
  end
55
52
 
56
- def active_record_scope_identifier(active_record_class)
57
- ActiveRecordScopeFactory.new(active_record_class).scope_identifier
53
+ def find_without_scope(identifier)
54
+ backing_collection[identifier]
58
55
  end
59
- end
60
56
 
61
- class ActiveRecordScopeFactory
62
- def initialize(active_record_class)
63
- @active_record_class = active_record_class
57
+ def all
58
+ backing_collection.values
64
59
  end
65
60
 
66
- def scope_identifier
67
- lambda do |value|
68
- case value
69
- when @active_record_class
70
- value.id
71
- when String, Fixnum
72
- value
73
- else
74
- fail AccountScopeMismatchError, "Expected instance of `#{@active_record_class}`, received instance of `#{value.class}`"
75
- end
76
- end
61
+ private
62
+
63
+ def backing_collection
64
+ @backing_collection ||= Hash.new
77
65
  end
78
66
  end
79
67
 
@@ -84,10 +72,15 @@ module DoubleEntry
84
72
  def initialize(args)
85
73
  @account = args[:account]
86
74
  @scope = args[:scope]
75
+ @scope_identity = args[:scope_identity]
87
76
  ensure_scope_is_valid
88
77
  end
89
78
 
90
79
  def scope_identity
80
+ @scope_identity || call_scope_identifier
81
+ end
82
+
83
+ def call_scope_identifier
91
84
  scope_identifier.call(scope).to_s if scoped?
92
85
  end
93
86
 
@@ -138,7 +131,7 @@ module DoubleEntry
138
131
 
139
132
  def ensure_scope_is_valid
140
133
  identity = scope_identity
141
- if identity && identity.length > Account.scope_identifier_max_length
134
+ if identity && Account.scope_identifier_max_length && identity.length > Account.scope_identifier_max_length
142
135
  fail ScopeIdentifierTooLongError,
143
136
  "scope identifier '#{identity}' is too long. Please limit it to #{Account.scope_identifier_max_length} characters."
144
137
  end
@@ -153,7 +146,7 @@ module DoubleEntry
153
146
  @positive_only = args[:positive_only]
154
147
  @negative_only = args[:negative_only]
155
148
  @currency = args[:currency] || Money.default_currency
156
- if identifier.length > Account.account_identifier_max_length
149
+ if Account.account_identifier_max_length && identifier.length > Account.account_identifier_max_length
157
150
  fail AccountIdentifierTooLongError,
158
151
  "account identifier '#{identifier}' is too long. Please limit it to #{Account.account_identifier_max_length} characters."
159
152
  end
@@ -25,7 +25,7 @@ module DoubleEntry
25
25
  end
26
26
 
27
27
  def account
28
- DoubleEntry.account(self[:account].to_sym, :scope => self[:scope])
28
+ DoubleEntry.account(self[:account].to_sym, :scope_identity => self[:scope])
29
29
  end
30
30
 
31
31
  def self.find_by_account(account, options = {})
@@ -33,5 +33,22 @@ module DoubleEntry
33
33
  scope = scope.lock(true) if options[:lock]
34
34
  scope.first
35
35
  end
36
+
37
+ # Identify the scopes with the given account identifier holding at least
38
+ # the provided minimum balance.
39
+ #
40
+ # @example Find users with at least $1,000,000 in their savings accounts
41
+ # DoubleEntry::AccountBalance.scopes_with_minimum_balance_for_account(
42
+ # 1_000_000.dollars,
43
+ # :savings,
44
+ # ) # might return the user ids: [ '1423', '12232', '34729' ]
45
+ # @param [Money] minimum_balance Minimum account balance a scope must have
46
+ # to be included in the result set.
47
+ # @param [Symbol] account_identifier
48
+ # @return [Array<String>] Scopes
49
+ #
50
+ def self.scopes_with_minimum_balance_for_account(minimum_balance, account_identifier)
51
+ where(account: account_identifier).where('balance >= ?', minimum_balance.fractional).pluck(:scope)
52
+ end
36
53
  end
37
54
  end
@@ -1,16 +1,16 @@
1
1
  # encoding: utf-8
2
2
  module DoubleEntry
3
- class UnknownAccount < RuntimeError; end
4
- class AccountIdentifierTooLongError < RuntimeError; end
5
- class ScopeIdentifierTooLongError < RuntimeError; end
6
- class TransferNotAllowed < RuntimeError; end
7
- class TransferIsNegative < RuntimeError; end
8
- class TransferCodeTooLongError < RuntimeError; end
9
- class DuplicateAccount < RuntimeError; end
10
- class DuplicateTransfer < RuntimeError; end
11
- class AccountWouldBeSentNegative < RuntimeError; end
12
- class AccountWouldBeSentPositiveError < RuntimeError; end
13
- class MismatchedCurrencies < RuntimeError; end
14
- class MissingAccountError < RuntimeError; end
15
- class AccountScopeMismatchError < RuntimeError; end
3
+ class DoubleEntryError < RuntimeError; end
4
+ class UnknownAccount < DoubleEntryError; end
5
+ class AccountIdentifierTooLongError < DoubleEntryError; end
6
+ class ScopeIdentifierTooLongError < DoubleEntryError; end
7
+ class TransferNotAllowed < DoubleEntryError; end
8
+ class TransferIsNegative < DoubleEntryError; end
9
+ class TransferCodeTooLongError < DoubleEntryError; end
10
+ class DuplicateAccount < DoubleEntryError; end
11
+ class DuplicateTransfer < DoubleEntryError; end
12
+ class AccountWouldBeSentNegative < DoubleEntryError; end
13
+ class AccountWouldBeSentPositiveError < DoubleEntryError; end
14
+ class MismatchedCurrencies < DoubleEntryError; end
15
+ class MissingAccountError < DoubleEntryError; end
16
16
  end
@@ -57,6 +57,7 @@ module DoubleEntry
57
57
  class Line < ActiveRecord::Base
58
58
  belongs_to :detail, :polymorphic => true
59
59
  has_many :metadata, :class_name => 'DoubleEntry::LineMetadata'
60
+ scope :with_id_greater_than, ->(id) { where('id > ?', id) }
60
61
 
61
62
  def amount
62
63
  self[:amount] && Money.new(self[:amount], currency)
@@ -101,7 +102,7 @@ module DoubleEntry
101
102
  end
102
103
 
103
104
  def account
104
- DoubleEntry.account(self[:account].to_sym, :scope => scope)
105
+ DoubleEntry.account(self[:account].to_sym, :scope_identity => scope)
105
106
  end
106
107
 
107
108
  def currency
@@ -116,7 +117,7 @@ module DoubleEntry
116
117
  end
117
118
 
118
119
  def partner_account
119
- DoubleEntry.account(self[:partner_account].to_sym, :scope => partner_scope)
120
+ DoubleEntry.account(self[:partner_account].to_sym, :scope_identity => partner_scope)
120
121
  end
121
122
 
122
123
  def partner
@@ -9,6 +9,7 @@ require 'double_entry/reporting/month_range'
9
9
  require 'double_entry/reporting/year_range'
10
10
  require 'double_entry/reporting/line_aggregate'
11
11
  require 'double_entry/reporting/line_aggregate_filter'
12
+ require 'double_entry/reporting/line_metadata_filter'
12
13
  require 'double_entry/reporting/time_range_array'
13
14
 
14
15
  module DoubleEntry
@@ -62,9 +63,12 @@ module DoubleEntry
62
63
  # @param [Symbol] code The application specific code for the type of
63
64
  # transfer to perform an aggregate calculation on. As specified in the
64
65
  # transfer configuration.
65
- # @param [DoubleEntry::Reporting::TimeRange] Only include transfers in the
66
- # given time range in the calculation.
67
- # @option options :filter [Array<Hash<Symbol,Hash<Symbol,Object>>>]
66
+ # @param [DoubleEntry::Reporting::TimeRange] range Only include transfers in
67
+ # the given time range in the calculation.
68
+ # @param [Symbol] partner_account The symbol identifying the partner account
69
+ # to perform the aggregate calculatoin on. As specified in the account
70
+ # configuration.
71
+ # @param [Array<Hash<Symbol,Hash<Symbol,Object>>>] filter
68
72
  # An array of custom filter to apply before performing the aggregate
69
73
  # calculation. Filters can be either scope filters, where the name must be
70
74
  # specified, or they can be metadata filters, where the key/value pair to
@@ -73,13 +77,14 @@ module DoubleEntry
73
77
  # class, as the example above shows. Scope filters may also take a list of
74
78
  # arguments to pass into the monkey patched scope, and, if provided, must
75
79
  # be contained within an array.
76
- # @return [Money, Fixnum] Returns a Money object for :sum and :average
77
- # calculations, or a Fixnum for :count calculations.
80
+ # @return [Money, Integer] Returns a Money object for :sum and :average
81
+ # calculations, or a Integer for :count calculations.
78
82
  # @raise [Reporting::AggregateFunctionNotSupported] The provided function
79
83
  # is not supported.
80
84
  #
81
- def aggregate(function, account, code, range, options = {})
82
- Aggregate.formatted_amount(function, account, code, range, options)
85
+ def aggregate(function:, account:, code:, range:, partner_account: nil, filter: nil)
86
+ Aggregate.formatted_amount(function: function, account: account, code: code, range: range,
87
+ partner_account: partner_account, filter: filter)
83
88
  end
84
89
 
85
90
  # Perform an aggregate calculation on a set of transfers for an account
@@ -104,54 +109,37 @@ module DoubleEntry
104
109
  # @param [Symbol] code The application specific code for the type of
105
110
  # transfer to perform an aggregate calculation on. As specified in the
106
111
  # transfer configuration.
107
- # @option options :filter [Array<Symbol>, Array<Hash<Symbol, Object>>]
112
+ # @param [Symbol] partner_account The symbol identifying the partner account
113
+ # to perform the aggregative calculation on. As specified in the account
114
+ # configuration.
115
+ # @param [Array<Symbol>, Array<Hash<Symbol, Object>>] filter
108
116
  # A custom filter to apply before performing the aggregate calculation.
109
117
  # Currently, filters must be monkey patched as scopes into the
110
118
  # DoubleEntry::Line class in order to be used as filters, as the example
111
119
  # shows. If the filter requires a parameter, it must be given in a Hash,
112
120
  # otherwise pass an array with the symbol names for the defined scopes.
113
- # @option options :range_type [String] The type of time range to return data
114
- # for. For example, specifying 'month' will return an array of the resulting
121
+ # @param [String] range_type The type of time range to return data
122
+ # for. For example, specifying 'month' will return an array of the resulting
115
123
  # aggregate calculation for each month.
116
124
  # Valid range_types are 'hour', 'day', 'week', 'month', and 'year'
117
- # @option options :start [String] The start date for the time range to perform
125
+ # @param [String] start The start date for the time range to perform
118
126
  # calculations in. The default start date is the start_of_business (can
119
127
  # be specified in configuration).
120
128
  # The format of the string must be as follows: 'YYYY-mm-dd'
121
- # @option options :finish [String] The finish (or end) date for the time range
129
+ # @param [String] finish The finish (or end) date for the time range
122
130
  # to perform calculations in. The default finish date is the current date.
123
131
  # The format of the string must be as follows: 'YYYY-mm-dd'
124
- # @return [Array<Money, Fixnum>] Returns an array of Money objects for :sum
125
- # and :average calculations, or an array of Fixnum for :count calculations.
132
+ # @return [Array<Money, Integer>] Returns an array of Money objects for :sum
133
+ # and :average calculations, or an array of Integer for :count calculations.
126
134
  # The array is indexed by the range_type. For example, if range_type is
127
135
  # specified as 'month', each index in the array will represent a month.
128
136
  # @raise [Reporting::AggregateFunctionNotSupported] The provided function
129
137
  # is not supported.
130
138
  #
131
- def aggregate_array(function, account, code, options = {})
132
- AggregateArray.new(function, account, code, options)
133
- end
134
-
135
- # Identify the scopes with the given account identifier holding at least
136
- # the provided minimum balance.
137
- #
138
- # @example Find users with at least $1,000,000 in their savings accounts
139
- # DoubleEntry::Reporting.scopes_with_minimum_balance_for_account(
140
- # 1_000_000.dollars,
141
- # :savings,
142
- # ) # might return the user ids: [ 1423, 12232, 34729 ]
143
- # @param [Money] minimum_balance Minimum account balance a scope must have
144
- # to be included in the result set.
145
- # @param [Symbol] account_identifier
146
- # @return [Array<Fixnum>] Scopes
147
- #
148
- def scopes_with_minimum_balance_for_account(minimum_balance, account_identifier)
149
- select_values(sanitize_sql_array([<<-SQL, account_identifier, minimum_balance.cents])).map(&:to_i)
150
- SELECT scope
151
- FROM #{AccountBalance.table_name}
152
- WHERE account = ?
153
- AND balance >= ?
154
- SQL
139
+ def aggregate_array(function:, account:, code:, partner_account: nil, filter: nil,
140
+ range_type: nil, start: nil, finish: nil)
141
+ AggregateArray.new(function: function, account: account, code: code, partner_account: partner_account,
142
+ filter: filter, range_type: range_type, start: start, finish: finish)
155
143
  end
156
144
 
157
145
  # This is used by the concurrency test script.