foodcoops/foodsoft

View on GitHub
app/models/bank_transaction.rb

Summary

Maintainability
A
2 hrs
Test Coverage
class BankTransaction < ApplicationRecord
  include LocalizeInput
  # @!attribute external_id
  #   @return [String] Unique Identifier of the transaction within the bank account.
  # @!attribute date
  #   @return [Date] Date of the transaction.
  # @!attribute amount
  #   @return [Number] Amount credited.
  # @!attribute iban
  #   @return [String] Internation Bank Account Number of the sending/receiving account.
  # @!attribute reference
  #   @return [String] 140 character long reference field as defined by SEPA.
  # @!attribute text
  #   @return [String] Short description of the transaction.
  # @!attribute receipt
  #   @return [String] Optional additional more detailed description of the transaction.
  # @!attribute image
  #   @return [Binary] Optional PNG image for e.g. scan of paper receipt.

  belongs_to :bank_account
  belongs_to :financial_link, optional: true
  belongs_to :supplier, optional: true, foreign_key: 'iban', primary_key: 'iban'
  belongs_to :user, optional: true, foreign_key: 'iban', primary_key: 'iban'

  validates :date, :amount, :bank_account_id, presence: true
  validates :amount, numericality: true

  scope :without_financial_link, -> { where(financial_link: nil) }

  # Replace numeric seperator with database format
  localize_input_of :amount

  def image_url
    'data:image/png;base64,' + Base64.encode64(image)
  end

  def assign_to_invoice
    return false unless supplier

    content = text || ''
    content += "\n" + reference if reference.present?
    invoices = supplier.invoices.unpaid.select { |i| content.include? i.number }
    invoices_sum = invoices.map(&:amount).sum
    return false if amount != -invoices_sum

    transaction do
      link = FinancialLink.new
      invoices.each { |i| i.update!(financial_link: link, paid_on: date) }
      update_attribute :financial_link, link
    end

    true
  end

  def assign_to_ordergroup
    m = BankTransactionReference.parse(reference)
    return unless m

    return false if m[:parts].values.sum != amount

    group = Ordergroup.find_by_id(m[:group])
    return false unless group

    usr = m[:user] ? User.find_by_id(m[:user]) : group.users.first
    return false unless usr

    transaction do
      note = "ID=#{id} (#{amount})"
      link = FinancialLink.new

      m[:parts].each do |short, value|
        ftt = FinancialTransactionType.find_by_name_short(short)
        return false unless ftt

        group.add_financial_transaction! value, note, usr, ftt, link if value > 0
      end

      update_attribute :financial_link, link
    end

    true
  end
end