Применение платежей к счетам в биллинговой системе rails

Я уже написал большую часть функциональных частей для пользовательской биллинговой системы для своего бизнеса (Wireless ISP), но немного поставил себя в тупик.

Вот общий обзор: Это повторяющаяся система выставления счетов для моих клиентов, которая автоматически генерирует и отправляет счета каждому клиенту каждый месяц. Однако мне нужно разрешить платежи чеком/наличными, так как я работаю с местными клиентами, а также мне нужно разрешить предоплату, чтобы я не мог просто использовать что-то вроде регулярного выставления счетов Stripe. По сути, платежи не связаны напрямую со счетами-фактурами, что позволяет осуществлять платежи такого типа.

models/invoice.rb

class Invoice < ActiveRecord::Base
  belongs_to :customer
  has_many :line_items
  has_many :invoice_payments
  has_many :payments, through: :invoice_payments

models/payment.rb

class Payment < ActiveRecord::Base
  belongs_to :customer

models/customer.rb

class Customer < ActiveRecord::Base
  has_many :subscriptions, dependent: :destroy
  has_many :services, through: :subscriptions
  has_many :invoices, :order => 'id DESC'
  has_many :payments

Мне нужен метод, который автоматически связывает все непримененные платежи со всеми неоплаченными счетами. Прямо сейчас я помещаю это как def apply_unapplied_payments в модель клиента, но, вероятно, позже абстрагирую его в отдельный модуль в lib/.

Это то, что я сделал до сих пор в models/customer.rb

def apply_unapplied_payments
  unpaid_invoices = invoices.find_by_status("unpaid")
  unapplied_payments = payments.where("invoice_id is null")
  unpaid_invoices.each do |invoice|
    # find the oldest unapplied payment
    # apply payment to this invoice
    # if payment > invoice, keep whatever amount is left and move to next invoice
    # apply leftover amount to invoice, if invoice is still unpaid, move to next unapplied payment
  end
  customer.update_balance
end

Любые предложения о том, чем заполнить псевдокод? Я открыт для любого уровня рефакторинга, поэтому, пожалуйста, дайте мне знать, если вы можете придумать лучший способ справиться с этим!


person gmcintire    schedule 19.04.2012    source источник


Ответы (1)


Вот что я бы сделал (могут потребоваться некоторые вспомогательные методы в классах платежей и счетов):

def apply_unapplied_payments
  unpaid_invoices = invoices.find_by_status("unpaid")
  unapplied_payments = payments.where("invoice_id is null")
  invoice = unpaid_invoices.shift
  payment = unapplied_payments.shift
  while invoice && invoice.remaining_balance > 0 && payment && payment.remaining_credit > 0
      apply_payment_to_invoice(invoice, payment)
      invoice = unpaid_invoices.shift    if invoice.remaining_balance == 0
      payment = unapplied_payments.shift if payment.remaining_credit  == 0
  end
end
person klochner    schedule 20.04.2012
comment
Великолепно! Я не думал об этом таким образом и застрял, думая в циклах .each. - person gmcintire; 20.04.2012