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/gl_transaction.rb, line 71
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/gl_transaction.rb, line 102
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.location
        })
        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/gl_transaction.rb, line 80
def self.record( attributes={} )
    Thread.current[:gl_transaction] ||= []
    glt = GlTransaction.new( attributes )
    Thread.current[:gl_transaction].push( glt )
    Skr::Core.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
        Skr::Core.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/gl_transaction.rb, line 118
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/gl_transaction.rb, line 47
def add_posting( amount: nil, debit: nil, credit: nil )
    Skr::Core.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/gl_transaction.rb, line 65
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/gl_transaction.rb, line 57
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/gl_transaction.rb, line 127
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/gl_transaction.rb, line 141
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/gl_transaction.rb, line 150
def set_defaults
    self.period ||= GlPeriod.current
end