Module: ReceiptFinancials

Extended by:
ActiveSupport::Concern
Included in:
Receipt
Defined in:
app/models/concerns/receipt_financials.rb

Overview

Money movement for a receipt: funds applied vs. unapplied, linked
invoice/credit-memo balances, and the general-ledger posting +
state-derivation callback that runs on save.

NOTE: #update_general_ledger_and_state is the financial heart of the
model and is currently exercised only via stubs in the test suite. It
was relocated here verbatim; restructuring it needs characterization
tests first.

See Also:

Instance Method Summary collapse

Instance Method Details

#credit_applied_to_summaryString

Human summary used on customer-facing emails: "Credit applied to
Invoice 12345/GL Account" when funds are applied, otherwise
"Payment issued by $category $reference" for fully unapplied
receipts.

Returns:

  • (String)


22
23
24
25
26
27
28
29
30
31
# File 'app/models/concerns/receipt_financials.rb', line 22

def credit_applied_to_summary
  list = []
  if receipt_details.non_voided.invoices.empty? && receipt_details.non_voided.gl_accounts.empty?
    "Payment issued by #{category} #{reference_summary}"
  else
    receipt_details.non_voided.invoices.each { |rd| list << "Invoice #{rd.invoice.reference_number}" }
    receipt_details.non_voided.gl_accounts.each { |_rd| list << 'GL Account' }
    "Credit applied to #{list.join('/')}"
  end
end

#detail_document_balancesHash{Integer=>BigDecimal}

Linked-document (invoice / credit-memo) balance shown in each
ReceiptDetail's "Balance" column on the edit form, batch-computed in a
handful of grouped queries instead of Invoice#balance / CreditMemo#balance
firing 3–5 aggregate queries per row (the N+1 that made editing a 600-line
receipt slow). Mirrors those two methods exactly:
Invoice#balance = total - (non-voided rd: Σamount + Σwrite_off + Σdiscount)
CreditMemo#balance = total - (non-voided rd: Σamount - applied OPI: Σamount)

Returns:

  • (Hash{Integer=>BigDecimal})

    receipt_detail id => document balance
    (nil for GL-account rows, which have no linked document)



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'app/models/concerns/receipt_financials.rb', line 43

def detail_document_balances
  details = receipt_details.to_a
  invoice_balances = invoice_balances_for(details.filter_map(&:invoice_id).uniq)
  credit_memo_balances = credit_memo_balances_for(details.filter_map(&:credit_memo_id).uniq)

  details.to_h do |detail|
    balance =
      if detail.invoice_id
        invoice_balances[detail.invoice_id]
      elsif detail.credit_memo_id
        credit_memo_balances[detail.credit_memo_id]
      end
    [detail.id, balance]
  end
end

#funds_assignedBigDecimal

Total of receipt funds already committed: amounts on every detail
line plus any unapplied funds that were later refunded out via an
OutgoingPayment.

Returns:

  • (BigDecimal)


64
65
66
67
68
69
# File 'app/models/concerns/receipt_financials.rb', line 64

def funds_assigned
  assigned = BigDecimal(0)
  receipt_details.each { |rd| assigned += rd.amount unless rd.amount.nil? }
  outgoing_payment_items.applied.each { |pi| assigned += pi.amount }
  assigned
end

#no_funds_applied?Boolean

Returns:

  • (Boolean)


71
72
73
# File 'app/models/concerns/receipt_financials.rb', line 71

def no_funds_applied?
  funds_assigned == 0
end

#unapplied_fundsBigDecimal

Cash still available to apply against open invoices/credit memos.

Returns:

  • (BigDecimal)


78
79
80
# File 'app/models/concerns/receipt_financials.rb', line 78

def unapplied_funds
  amount - funds_assigned
end