double_entry 0.1.0 → 0.2.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.
- data/README.md +16 -14
- data/lib/double_entry.rb +9 -62
- data/lib/double_entry/account.rb +5 -1
- data/lib/double_entry/configuration.rb +21 -0
- data/lib/double_entry/reporting.rb +51 -0
- data/lib/double_entry/{aggregate.rb → reporting/aggregate.rb} +9 -7
- data/lib/double_entry/{aggregate_array.rb → reporting/aggregate_array.rb} +3 -1
- data/lib/double_entry/{day_range.rb → reporting/day_range.rb} +2 -0
- data/lib/double_entry/{hour_range.rb → reporting/hour_range.rb} +2 -0
- data/lib/double_entry/{line_aggregate.rb → reporting/line_aggregate.rb} +4 -2
- data/lib/double_entry/{month_range.rb → reporting/month_range.rb} +4 -2
- data/lib/double_entry/{time_range.rb → reporting/time_range.rb} +7 -5
- data/lib/double_entry/{time_range_array.rb → reporting/time_range_array.rb} +2 -0
- data/lib/double_entry/{week_range.rb → reporting/week_range.rb} +3 -1
- data/lib/double_entry/{year_range.rb → reporting/year_range.rb} +4 -3
- data/lib/double_entry/transfer.rb +4 -0
- data/lib/double_entry/validation.rb +1 -0
- data/lib/double_entry/{line_check.rb → validation/line_check.rb} +2 -0
- data/lib/double_entry/version.rb +1 -1
- data/script/jack_hammer +21 -16
- data/spec/double_entry/account_spec.rb +9 -0
- data/spec/double_entry/configuration_spec.rb +23 -0
- data/spec/double_entry/locking_spec.rb +24 -13
- data/spec/double_entry/{aggregate_array_spec.rb → reporting/aggregate_array_spec.rb} +2 -2
- data/spec/double_entry/reporting/aggregate_spec.rb +171 -0
- data/spec/double_entry/reporting/line_aggregate_spec.rb +10 -0
- data/spec/double_entry/{month_range_spec.rb → reporting/month_range_spec.rb} +23 -21
- data/spec/double_entry/{time_range_array_spec.rb → reporting/time_range_array_spec.rb} +41 -39
- data/spec/double_entry/{time_range_spec.rb → reporting/time_range_spec.rb} +10 -9
- data/spec/double_entry/{week_range_spec.rb → reporting/week_range_spec.rb} +26 -25
- data/spec/double_entry/reporting_spec.rb +24 -0
- data/spec/double_entry/transfer_spec.rb +17 -0
- data/spec/double_entry/{line_check_spec.rb → validation/line_check_spec.rb} +17 -16
- data/spec/double_entry_spec.rb +409 -0
- data/spec/support/accounts.rb +16 -17
- metadata +70 -35
- checksums.yaml +0 -15
- data/spec/double_entry/aggregate_spec.rb +0 -168
- data/spec/double_entry/double_entry_spec.rb +0 -391
- data/spec/double_entry/line_aggregate_spec.rb +0 -8
    
        data/README.md
    CHANGED
    
    | @@ -133,7 +133,7 @@ the accounts, and permitted transfers between those accounts. | |
| 133 133 | 
             
            The configuration file should be kept in your application's load path.  For example,
         | 
| 134 134 | 
             
            *config/initializers/double_entry.rb*
         | 
| 135 135 |  | 
| 136 | 
            -
            For example, the following specifies two accounts,  | 
| 136 | 
            +
            For example, the following specifies two accounts, savings and checking.
         | 
| 137 137 | 
             
            Each account is scoped by User (where User is an object with an ID), meaning
         | 
| 138 138 | 
             
            each user can have their own account of each type.
         | 
| 139 139 |  | 
| @@ -142,22 +142,24 @@ This configuration also specifies that money can be transferred between the two | |
| 142 142 | 
             
            ```ruby
         | 
| 143 143 | 
             
            require 'double_entry'
         | 
| 144 144 |  | 
| 145 | 
            -
            DoubleEntry. | 
| 146 | 
            -
               | 
| 147 | 
            -
                 | 
| 148 | 
            -
                  user_identifier. | 
| 149 | 
            -
             | 
| 150 | 
            -
                   | 
| 145 | 
            +
            DoubleEntry.configure do |config|
         | 
| 146 | 
            +
              config.define_accounts do |accounts|
         | 
| 147 | 
            +
                user_scope = lambda do |user_identifier|
         | 
| 148 | 
            +
                  if user_identifier.is_a?(User)
         | 
| 149 | 
            +
                    user_identifier.id
         | 
| 150 | 
            +
                  else
         | 
| 151 | 
            +
                    user_identifier
         | 
| 152 | 
            +
                  end
         | 
| 151 153 | 
             
                end
         | 
| 152 | 
            -
              end
         | 
| 153 154 |  | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 156 | 
            -
            end
         | 
| 155 | 
            +
                accounts.define(identifier: :savings,  scope_identifier: user_scope, positive_only: true)
         | 
| 156 | 
            +
                accounts.define(identifier: :checking, scope_identifier: user_scope)
         | 
| 157 | 
            +
              end
         | 
| 157 158 |  | 
| 158 | 
            -
             | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 159 | 
            +
              config.define_transfers do |transfers|
         | 
| 160 | 
            +
                transfers.define(from: :checking, to: :savings,  code: :deposit)
         | 
| 161 | 
            +
                transfers.define(from: :savings,  to: :checking, code: :withdraw)
         | 
| 162 | 
            +
              end
         | 
| 161 163 | 
             
            end
         | 
| 162 164 | 
             
            ```
         | 
| 163 165 |  | 
    
        data/lib/double_entry.rb
    CHANGED
    
    | @@ -1,32 +1,20 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 | 
            -
             | 
| 3 2 | 
             
            require 'active_record'
         | 
| 4 3 | 
             
            require 'active_record/locking_extensions'
         | 
| 5 | 
            -
             | 
| 6 4 | 
             
            require 'active_support/all'
         | 
| 7 | 
            -
             | 
| 8 5 | 
             
            require 'money'
         | 
| 9 6 | 
             
            require 'encapsulate_as_money'
         | 
| 10 7 |  | 
| 11 8 | 
             
            require 'double_entry/version'
         | 
| 12 9 | 
             
            require 'double_entry/configurable'
         | 
| 10 | 
            +
            require 'double_entry/configuration'
         | 
| 13 11 | 
             
            require 'double_entry/account'
         | 
| 14 12 | 
             
            require 'double_entry/account_balance'
         | 
| 15 | 
            -
            require 'double_entry/reporting'
         | 
| 16 | 
            -
            require 'double_entry/aggregate'
         | 
| 17 | 
            -
            require 'double_entry/aggregate_array'
         | 
| 18 | 
            -
            require 'double_entry/time_range'
         | 
| 19 | 
            -
            require 'double_entry/time_range_array'
         | 
| 20 | 
            -
            require 'double_entry/day_range'
         | 
| 21 | 
            -
            require 'double_entry/hour_range'
         | 
| 22 | 
            -
            require 'double_entry/week_range'
         | 
| 23 | 
            -
            require 'double_entry/month_range'
         | 
| 24 | 
            -
            require 'double_entry/year_range'
         | 
| 25 | 
            -
            require 'double_entry/line'
         | 
| 26 | 
            -
            require 'double_entry/line_aggregate'
         | 
| 27 | 
            -
            require 'double_entry/line_check'
         | 
| 28 13 | 
             
            require 'double_entry/locking'
         | 
| 29 14 | 
             
            require 'double_entry/transfer'
         | 
| 15 | 
            +
            require 'double_entry/line'
         | 
| 16 | 
            +
            require 'double_entry/reporting'
         | 
| 17 | 
            +
            require 'double_entry/validation'
         | 
| 30 18 |  | 
| 31 19 | 
             
            # Keep track of all the monies!
         | 
| 32 20 | 
             
            #
         | 
| @@ -44,7 +32,6 @@ module DoubleEntry | |
| 44 32 | 
             
              class AccountWouldBeSentNegative < RuntimeError; end
         | 
| 45 33 |  | 
| 46 34 | 
             
              class << self
         | 
| 47 | 
            -
                attr_accessor :accounts, :transfers
         | 
| 48 35 |  | 
| 49 36 | 
             
                # Get the particular account instance with the provided identifier and
         | 
| 50 37 | 
             
                # scope.
         | 
| @@ -60,8 +47,8 @@ module DoubleEntry | |
| 60 47 | 
             
                #   configured. It is unknown.
         | 
| 61 48 | 
             
                #
         | 
| 62 49 | 
             
                def account(identifier, options = {})
         | 
| 63 | 
            -
                  account =  | 
| 64 | 
            -
                    current_account.identifier == identifier  | 
| 50 | 
            +
                  account = configuration.accounts.detect do |current_account|
         | 
| 51 | 
            +
                    current_account.identifier == identifier &&
         | 
| 65 52 | 
             
                      (options[:scope] ? current_account.scoped? : !current_account.scoped?)
         | 
| 66 53 | 
             
                  end
         | 
| 67 54 |  | 
| @@ -108,7 +95,7 @@ module DoubleEntry | |
| 108 95 | 
             
                def transfer(amount, options = {})
         | 
| 109 96 | 
             
                  raise TransferIsNegative if amount < Money.new(0)
         | 
| 110 97 | 
             
                  from, to, code, meta, detail = options[:from], options[:to], options[:code], options[:meta], options[:detail]
         | 
| 111 | 
            -
                  transfer =  | 
| 98 | 
            +
                  transfer = configuration.transfers.find(from, to, code)
         | 
| 112 99 | 
             
                  if transfer
         | 
| 113 100 | 
             
                    transfer.process!(amount, from, to, code, meta, detail)
         | 
| 114 101 | 
             
                  else
         | 
| @@ -179,27 +166,6 @@ module DoubleEntry | |
| 179 166 | 
             
                  end
         | 
| 180 167 | 
             
                end
         | 
| 181 168 |  | 
| 182 | 
            -
                # Identify the scopes with the given account identifier holding at least
         | 
| 183 | 
            -
                # the provided minimum balance.
         | 
| 184 | 
            -
                #
         | 
| 185 | 
            -
                # @example Find users with at lease $1,000,000 in their savings accounts
         | 
| 186 | 
            -
                #   DoubleEntry.scopes_with_minimum_balance_for_account(
         | 
| 187 | 
            -
                #     Money.new(1_000_000_00),
         | 
| 188 | 
            -
                #     :savings
         | 
| 189 | 
            -
                #   ) # might return user ids: [ 1423, 12232, 34729 ]
         | 
| 190 | 
            -
                # @param minimum_balance [Money] Minimum account balance a scope must have
         | 
| 191 | 
            -
                #   to be included in the result set.
         | 
| 192 | 
            -
                # @param account_identifier [Symbol]
         | 
| 193 | 
            -
                # @return [Array<Fixnum>] Scopes
         | 
| 194 | 
            -
                def scopes_with_minimum_balance_for_account(minimum_balance, account_identifier)
         | 
| 195 | 
            -
                  select_values(sanitize_sql_array([<<-SQL, account_identifier, minimum_balance.cents])).map {|scope| scope.to_i }
         | 
| 196 | 
            -
                    SELECT scope
         | 
| 197 | 
            -
                      FROM #{AccountBalance.table_name}
         | 
| 198 | 
            -
                     WHERE account = ?
         | 
| 199 | 
            -
                       AND balance >= ?
         | 
| 200 | 
            -
                  SQL
         | 
| 201 | 
            -
                end
         | 
| 202 | 
            -
             | 
| 203 169 | 
             
                # Lock accounts in preparation for transfers.
         | 
| 204 170 | 
             
                #
         | 
| 205 171 | 
             
                # This creates a transaction, and uses database-level locking to ensure
         | 
| @@ -225,20 +191,12 @@ module DoubleEntry | |
| 225 191 | 
             
                  # make sure we have a test for this refactoring, the test
         | 
| 226 192 | 
             
                  # conditions are: i forget... but it's important!
         | 
| 227 193 | 
             
                  if line.credit?
         | 
| 228 | 
            -
                     | 
| 194 | 
            +
                    configuration.transfers.find(line.account, line.partner_account, line.code)
         | 
| 229 195 | 
             
                  else
         | 
| 230 | 
            -
                     | 
| 196 | 
            +
                    configuration.transfers.find(line.partner_account, line.account, line.code)
         | 
| 231 197 | 
             
                  end.description.call(line)
         | 
| 232 198 | 
             
                end
         | 
| 233 199 |  | 
| 234 | 
            -
                def aggregate(function, account, code, options = {})
         | 
| 235 | 
            -
                  DoubleEntry::Aggregate.new(function, account, code, options).formatted_amount
         | 
| 236 | 
            -
                end
         | 
| 237 | 
            -
             | 
| 238 | 
            -
                def aggregate_array(function, account, code, options = {})
         | 
| 239 | 
            -
                  DoubleEntry::AggregateArray.new(function, account, code, options)
         | 
| 240 | 
            -
                end
         | 
| 241 | 
            -
             | 
| 242 200 | 
             
                # This is used by the concurrency test script.
         | 
| 243 201 | 
             
                #
         | 
| 244 202 | 
             
                # @api private
         | 
| @@ -255,16 +213,5 @@ module DoubleEntry | |
| 255 213 | 
             
                def table_name_prefix
         | 
| 256 214 | 
             
                  'double_entry_'
         | 
| 257 215 | 
             
                end
         | 
| 258 | 
            -
             | 
| 259 | 
            -
              private
         | 
| 260 | 
            -
             | 
| 261 | 
            -
                delegate :connection, :to => ActiveRecord::Base
         | 
| 262 | 
            -
                delegate :select_values, :to => :connection
         | 
| 263 | 
            -
             | 
| 264 | 
            -
                def sanitize_sql_array(sql_array)
         | 
| 265 | 
            -
                  ActiveRecord::Base.send(:sanitize_sql_array, sql_array)
         | 
| 266 | 
            -
                end
         | 
| 267 | 
            -
             | 
| 268 216 | 
             
              end
         | 
| 269 | 
            -
             | 
| 270 217 | 
             
            end
         | 
    
        data/lib/double_entry/account.rb
    CHANGED
    
    | @@ -2,8 +2,12 @@ | |
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 3 | 
             
              class Account
         | 
| 4 4 | 
             
                class Set < Array
         | 
| 5 | 
            +
                  def define(attributes)
         | 
| 6 | 
            +
                    self << Account.new(attributes)
         | 
| 7 | 
            +
                  end
         | 
| 8 | 
            +
             | 
| 5 9 | 
             
                  def <<(account)
         | 
| 6 | 
            -
                    if  | 
| 10 | 
            +
                    if any? { |a| a.identifier == account.identifier }
         | 
| 7 11 | 
             
                      raise DuplicateAccount.new
         | 
| 8 12 | 
             
                    else
         | 
| 9 13 | 
             
                      super(account)
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
            module DoubleEntry
         | 
| 3 | 
            +
              include Configurable
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              class Configuration
         | 
| 6 | 
            +
                attr_accessor :accounts, :transfers
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                def initialize #:nodoc:
         | 
| 9 | 
            +
                  @accounts = Account::Set.new
         | 
| 10 | 
            +
                  @transfers = Transfer::Set.new
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def define_accounts
         | 
| 14 | 
            +
                  yield accounts
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                def define_transfers
         | 
| 18 | 
            +
                  yield transfers
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -1,7 +1,21 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 | 
            +
            require 'double_entry/reporting/aggregate'
         | 
| 3 | 
            +
            require 'double_entry/reporting/aggregate_array'
         | 
| 4 | 
            +
            require 'double_entry/reporting/time_range'
         | 
| 5 | 
            +
            require 'double_entry/reporting/time_range_array'
         | 
| 6 | 
            +
            require 'double_entry/reporting/day_range'
         | 
| 7 | 
            +
            require 'double_entry/reporting/hour_range'
         | 
| 8 | 
            +
            require 'double_entry/reporting/week_range'
         | 
| 9 | 
            +
            require 'double_entry/reporting/month_range'
         | 
| 10 | 
            +
            require 'double_entry/reporting/year_range'
         | 
| 11 | 
            +
            require 'double_entry/reporting/line_aggregate'
         | 
| 12 | 
            +
             | 
| 2 13 | 
             
            module DoubleEntry
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              # @api private
         | 
| 3 16 | 
             
              module Reporting
         | 
| 4 17 | 
             
                include Configurable
         | 
| 18 | 
            +
                extend self
         | 
| 5 19 |  | 
| 6 20 | 
             
                class Configuration
         | 
| 7 21 | 
             
                  attr_accessor :start_of_business, :first_month_of_financial_year
         | 
| @@ -12,5 +26,42 @@ module DoubleEntry | |
| 12 26 | 
             
                  end
         | 
| 13 27 | 
             
                end
         | 
| 14 28 |  | 
| 29 | 
            +
                def aggregate(function, account, code, options = {})
         | 
| 30 | 
            +
                  Aggregate.new(function, account, code, options).formatted_amount
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def aggregate_array(function, account, code, options = {})
         | 
| 34 | 
            +
                  AggregateArray.new(function, account, code, options)
         | 
| 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.scopes_with_minimum_balance_for_account(
         | 
| 42 | 
            +
                #     Money.new(1_000_000_00),
         | 
| 43 | 
            +
                #     :savings
         | 
| 44 | 
            +
                #   ) # might return user ids: [ 1423, 12232, 34729 ]
         | 
| 45 | 
            +
                # @param minimum_balance [Money] Minimum account balance a scope must have
         | 
| 46 | 
            +
                #   to be included in the result set.
         | 
| 47 | 
            +
                # @param account_identifier [Symbol]
         | 
| 48 | 
            +
                # @return [Array<Fixnum>] Scopes
         | 
| 49 | 
            +
                def scopes_with_minimum_balance_for_account(minimum_balance, account_identifier)
         | 
| 50 | 
            +
                  select_values(sanitize_sql_array([<<-SQL, account_identifier, minimum_balance.cents])).map {|scope| scope.to_i }
         | 
| 51 | 
            +
                    SELECT scope
         | 
| 52 | 
            +
                      FROM #{AccountBalance.table_name}
         | 
| 53 | 
            +
                     WHERE account = ?
         | 
| 54 | 
            +
                       AND balance >= ?
         | 
| 55 | 
            +
                  SQL
         | 
| 56 | 
            +
                end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
              private
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                delegate :connection, :to => ActiveRecord::Base
         | 
| 61 | 
            +
                delegate :select_values, :to => :connection
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                def sanitize_sql_array(sql_array)
         | 
| 64 | 
            +
                  ActiveRecord::Base.send(:sanitize_sql_array, sql_array)
         | 
| 65 | 
            +
                end
         | 
| 15 66 | 
             
              end
         | 
| 16 67 | 
             
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 | 
            +
             module Reporting
         | 
| 3 4 | 
             
              class Aggregate
         | 
| 4 5 | 
             
                attr_reader :function, :account, :code, :scope, :range, :options, :filter
         | 
| 5 6 |  | 
| @@ -51,7 +52,7 @@ module DoubleEntry | |
| 51 52 | 
             
                end
         | 
| 52 53 |  | 
| 53 54 | 
             
                def calculate
         | 
| 54 | 
            -
                  if range.class ==  | 
| 55 | 
            +
                  if range.class == YearRange
         | 
| 55 56 | 
             
                    aggregate = calculate_yearly_aggregate
         | 
| 56 57 | 
             
                  else
         | 
| 57 58 | 
             
                    aggregate = LineAggregate.aggregate(function, account, code, nil, range, filter)
         | 
| @@ -78,8 +79,8 @@ module DoubleEntry | |
| 78 79 | 
             
                    zero = Aggregate.formatted_amount(function, 0)
         | 
| 79 80 |  | 
| 80 81 | 
             
                    result = (1..12).inject(zero) do |total, month|
         | 
| 81 | 
            -
                      total +=  | 
| 82 | 
            -
                                                  :range =>  | 
| 82 | 
            +
                      total += Reporting.aggregate(function, account, code,
         | 
| 83 | 
            +
                                                  :range => MonthRange.new(:year => range.year, :month => month), :filter => filter)
         | 
| 83 84 | 
             
                    end
         | 
| 84 85 |  | 
| 85 86 | 
             
                    result = result.cents if result.class == Money
         | 
| @@ -89,10 +90,10 @@ module DoubleEntry | |
| 89 90 |  | 
| 90 91 | 
             
                def calculate_yearly_average
         | 
| 91 92 | 
             
                  # need this seperate function, because an average of averages is not the correct average
         | 
| 92 | 
            -
                  sum =  | 
| 93 | 
            -
                                           :range =>  | 
| 94 | 
            -
                  count =  | 
| 95 | 
            -
                                             :range =>  | 
| 93 | 
            +
                  sum = Reporting.aggregate(:sum, account, code,
         | 
| 94 | 
            +
                                           :range => YearRange.new(:year => range.year), :filter => filter)
         | 
| 95 | 
            +
                  count = Reporting.aggregate(:count, account, code,
         | 
| 96 | 
            +
                                             :range => YearRange.new(:year => range.year), :filter => filter)
         | 
| 96 97 | 
             
                  (count == 0) ? 0 : (sum / count).cents
         | 
| 97 98 | 
             
                end
         | 
| 98 99 |  | 
| @@ -115,4 +116,5 @@ module DoubleEntry | |
| 115 116 | 
             
                  }
         | 
| 116 117 | 
             
                end
         | 
| 117 118 | 
             
              end
         | 
| 119 | 
            +
             end
         | 
| 118 120 | 
             
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 | 
            +
             module Reporting
         | 
| 3 4 | 
             
              class AggregateArray < Array
         | 
| 4 5 | 
             
                # An AggregateArray is awesome
         | 
| 5 6 | 
             
                # It is useful for making reports
         | 
| @@ -37,7 +38,7 @@ module DoubleEntry | |
| 37 38 | 
             
                  # (this includes aggregates for the still-running period)
         | 
| 38 39 | 
             
                  all_periods.each do |period|
         | 
| 39 40 | 
             
                    unless @aggregates[period.key]
         | 
| 40 | 
            -
                      @aggregates[period.key] =  | 
| 41 | 
            +
                      @aggregates[period.key] = Reporting.aggregate(function, account, code, :filter => filter, :range => period)
         | 
| 41 42 | 
             
                    end
         | 
| 42 43 | 
             
                  end
         | 
| 43 44 | 
             
                end
         | 
| @@ -62,4 +63,5 @@ module DoubleEntry | |
| 62 63 | 
             
                  TimeRangeArray.make(range_type, start, finish)
         | 
| 63 64 | 
             
                end
         | 
| 64 65 | 
             
              end
         | 
| 66 | 
            +
             end
         | 
| 65 67 | 
             
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 | 
            +
             module Reporting
         | 
| 3 4 | 
             
              class LineAggregate < ActiveRecord::Base
         | 
| 4 5 | 
             
                extend EncapsulateAsMoney
         | 
| 5 6 |  | 
| @@ -15,7 +16,7 @@ module DoubleEntry | |
| 15 16 | 
             
                # in named_scopes to bring in data from other tables.
         | 
| 16 17 | 
             
                def self.aggregate_collection(named_scopes)
         | 
| 17 18 | 
             
                  if named_scopes
         | 
| 18 | 
            -
                    collection = Line
         | 
| 19 | 
            +
                    collection = DoubleEntry::Line
         | 
| 19 20 | 
             
                    named_scopes.each do |named_scope|
         | 
| 20 21 | 
             
                      if named_scope.is_a?(Hash)
         | 
| 21 22 | 
             
                        method_name = named_scope.keys[0]
         | 
| @@ -26,7 +27,7 @@ module DoubleEntry | |
| 26 27 | 
             
                    end
         | 
| 27 28 | 
             
                    collection
         | 
| 28 29 | 
             
                  else
         | 
| 29 | 
            -
                    Line
         | 
| 30 | 
            +
                    DoubleEntry::Line
         | 
| 30 31 | 
             
                  end
         | 
| 31 32 | 
             
                end
         | 
| 32 33 |  | 
| @@ -34,4 +35,5 @@ module DoubleEntry | |
| 34 35 | 
             
                  "#{year}:#{month}:#{week}:#{day}:#{hour}"
         | 
| 35 36 | 
             
                end
         | 
| 36 37 | 
             
              end
         | 
| 38 | 
            +
             end
         | 
| 37 39 | 
             
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 | 
            +
             module Reporting
         | 
| 3 4 | 
             
              class MonthRange < TimeRange
         | 
| 4 5 |  | 
| 5 6 | 
             
                class << self
         | 
| @@ -29,7 +30,7 @@ module DoubleEntry | |
| 29 30 | 
             
                  end
         | 
| 30 31 |  | 
| 31 32 | 
             
                  def earliest_month
         | 
| 32 | 
            -
                    from_time( | 
| 33 | 
            +
                    from_time(Reporting.configuration.start_of_business)
         | 
| 33 34 | 
             
                  end
         | 
| 34 35 | 
             
                end
         | 
| 35 36 |  | 
| @@ -66,7 +67,7 @@ module DoubleEntry | |
| 66 67 | 
             
                end
         | 
| 67 68 |  | 
| 68 69 | 
             
                def beginning_of_financial_year
         | 
| 69 | 
            -
                  first_month_of_financial_year =  | 
| 70 | 
            +
                  first_month_of_financial_year = Reporting.configuration.first_month_of_financial_year
         | 
| 70 71 | 
             
                  year = (month >= first_month_of_financial_year) ? @year : (@year - 1)
         | 
| 71 72 | 
             
                  MonthRange.new(:year => year, :month => first_month_of_financial_year)
         | 
| 72 73 | 
             
                end
         | 
| @@ -89,4 +90,5 @@ module DoubleEntry | |
| 89 90 | 
             
                  start.strftime("%Y, %b")
         | 
| 90 91 | 
             
                end
         | 
| 91 92 | 
             
              end
         | 
| 93 | 
            +
             end
         | 
| 92 94 | 
             
            end
         | 
| @@ -1,5 +1,6 @@ | |
| 1 1 | 
             
            # encoding: utf-8
         | 
| 2 2 | 
             
            module DoubleEntry
         | 
| 3 | 
            +
             module Reporting
         | 
| 3 4 | 
             
              class TimeRange
         | 
| 4 5 | 
             
                attr_reader :start, :finish
         | 
| 5 6 | 
             
                attr_reader :year, :month, :week, :day, :hour, :range_type
         | 
| @@ -25,13 +26,13 @@ module DoubleEntry | |
| 25 26 | 
             
                def self.range_from_time_for_period(start_time, period_name)
         | 
| 26 27 | 
             
                   case period_name
         | 
| 27 28 | 
             
                     when 'month'
         | 
| 28 | 
            -
                        | 
| 29 | 
            +
                       YearRange.from_time(start_time)
         | 
| 29 30 | 
             
                     when 'week'
         | 
| 30 | 
            -
                         | 
| 31 | 
            +
                        YearRange.from_time(start_time)
         | 
| 31 32 | 
             
                     when 'day'
         | 
| 32 | 
            -
                        | 
| 33 | 
            +
                       MonthRange.from_time(start_time)
         | 
| 33 34 | 
             
                     when 'hour'
         | 
| 34 | 
            -
                        | 
| 35 | 
            +
                       DayRange.from_time(start_time)
         | 
| 35 36 | 
             
                   end
         | 
| 36 37 | 
             
                end
         | 
| 37 38 |  | 
| @@ -49,7 +50,8 @@ module DoubleEntry | |
| 49 50 | 
             
                end
         | 
| 50 51 |  | 
| 51 52 | 
             
                def human_readable_name
         | 
| 52 | 
            -
                  self.class.name.gsub('DoubleEntry::', '').gsub('Range', '')
         | 
| 53 | 
            +
                  self.class.name.gsub('DoubleEntry::Reporting::', '').gsub('Range', '')
         | 
| 53 54 | 
             
                end
         | 
| 54 55 | 
             
              end
         | 
| 56 | 
            +
             end
         | 
| 55 57 | 
             
            end
         |