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
@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
@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
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
@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 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
@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
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
# 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
# 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
# File lib/skr/models/gl_transaction.rb, line 159 def set_defaults self.period ||= GlPeriod.current end