class Skr::GlTransaction

A transaction is a record of a business event that has financial consequences. It consists of an at least one credit and at least one debit Transactions can be nested, with each level compacting all the entries that were made on it

require 'skr/core'
customer = Customer.find_by_code "MONEYBAGS"
GlTransaction.record( source: invoice, description: "Invoice Example" ) do | transaction |
  transaction.location = Location.default # <- could also specify in record's options
  Sku.where( code: ['HAT','STRING'] ).each do | sku |
      transaction.add_posting( amount: sku.default_price,
                                debit:  sku.gl_asset_account,
                               credit: customer.gl_receivables_account )
  end
end

Public Class Methods

current() click to toggle source

@return [GlTransaction] the current transaction that's in progress

# File lib/skr/models/gl_transaction.rb, line 80
def self.current
    glt = Thread.current[:gl_transaction]
    glt ? glt.last : nil
end
push_or_save( owner: nil, amount: nil, debit:nil, credit:nil, options:{} ) click to toggle source

@param owner [Skr::Model] @param amount [BigDecimal] @param debit [GlAccount] @param credit [GlAccount] @param options [Hash] options to pass to the [GlTransaction] if one is created

# File lib/skr/models/gl_transaction.rb, line 111
def self.push_or_save( owner: nil, amount: nil, debit:nil, credit:nil, options:{} )
    if (glt = self.current) # we push
        glt.add_posting( amount: amount, debit: debit, credit: credit )
    else
        options.merge!(source: owner, location: options[:location] || owner.try(:location))
        if owner.respond_to?(:attributes_for_gl_transaction)
            options.reverse_merge!( owner.attributes_for_gl_transaction )
        end
        glt = GlTransaction.new( options )
        glt.add_posting( amount: amount, debit: debit, credit: credit )
        glt.save!
    end
    glt
end
record( attributes={} ) { |glt| ... } click to toggle source

Start a new nested GlTransaction When a transaction is created, it can have @return [GlTransaction] new transaction @yield [GlTransaction] new transaction

# File lib/skr/models/gl_transaction.rb, line 89
def self.record( attributes={} )
    Thread.current[:gl_transaction] ||= []
    glt = GlTransaction.new( attributes )
    Thread.current[:gl_transaction].push( glt )
    Lanes.logger.debug "B4 GlTransaction"
    results = yield glt
    Thread.current[:gl_transaction].pop
    if results
        if results.is_a?(Hash) && results.has_key?(:attributes)
            glt.assign_attributes( results[:attributes] )
        end
        glt._save_recorded
        Lanes.logger.debug "AF GlTransaction new=#{glt.new_record?} #{glt.errors.full_messages}"
    end
    return glt
end

Public Instance Methods

_save_recorded() click to toggle source

@private

# File lib/skr/models/gl_transaction.rb, line 127
def _save_recorded
    compact( 'debits'  )
    compact( 'credits' )
    self.save if self.credits.any? || self.debits.any?
    self
end
add_posting(amount: nil, debit: nil, credit: nil) click to toggle source

Add a debit/credit pair to the transaction with amount @param amount [BigDecimal] the amount to apply to each posting @param debit [GlAccount] @param credit [GlAccount]

# File lib/skr/models/gl_transaction.rb, line 56
def add_posting(amount: nil, debit: nil, credit: nil)
    Lanes.logger.debug "GlTransaction add_posting #{debit} : #{credit}"
    self.credits.build( location: @location, is_debit: false,
                        account: credit, amount: amount )
    self.debits.build(  location: @location, is_debit: true,
                        account: debit,  amount: amount * -1 )
end
each_posting() { |posting| ... } click to toggle source

@yield [GlPosting] each posting associated with the Transaction

# File lib/skr/models/gl_transaction.rb, line 74
def each_posting
    self.credits.each{ |posting| yield posting }
    self.debits.each{  |posting| yield posting }
end
location=(location) click to toggle source

Passes the location onto the postings. @param location [Location]

# File lib/skr/models/gl_transaction.rb, line 66
def location=(location)
    @location = location
    each_posting do | posting |
        posting.location = location
    end
end

Private Instance Methods

compact( assoc_name ) click to toggle source
# File lib/skr/models/gl_transaction.rb, line 136
def compact( assoc_name )
    accounts = self.send( assoc_name ).to_a
    self.send( assoc_name + "=", [] )
    account_numbers = accounts.group_by{ |posting| posting.account_number }
    account_numbers.each do | number, matching |
        amount = matching.sum(&:amount)
        self.send( assoc_name ).build({
            account_number: number,
            is_debit: ( assoc_name == "debits" ),
            amount: amount,
        })
    end
end
ensure_postings_correct() click to toggle source
# File lib/skr/models/gl_transaction.rb, line 150
def ensure_postings_correct
    if debits.total !=  ( -1 * credits.total )
        self.errors.add(:credits, "must equal debits")
        self.errors.add(:debits, "must equal credits")
        return false
    end
    true
end
set_defaults() click to toggle source
# File lib/skr/models/gl_transaction.rb, line 159
def set_defaults
    self.period ||= GlPeriod.current
end