3scale/porta

View on GitHub
app/models/account/billing.rb

Summary

Maintainability
A
25 mins
Test Coverage
# TODO: place to the right folder
# TODO: extract to separate model / library / strategy
module Account::Billing
  extend ActiveSupport::Concern

  included do
    has_many :invoices, :foreign_key => 'buyer_account_id'
    after_save :update_invoices_vat_rates, if: :saved_change_to_vat_rate?
    before_destroy :check_unresolved_invoices
  end

  # MODEL: Buyer
  def is_billed?
    provider_account && provider_account.is_billing_buyers?
  end

  def billable_contracts
    if provider_account.provider_can_use?(:billable_contracts)
      contracts.where.not(state: 'pending')
    else
      contracts
    end
  end

  def billable_contracts_with_trial_period_expired(now)
    if provider_account.provider_can_use?(:billable_contracts)
      billable_contracts.with_trial_period_expired_or_accepted(now)
    else
      billable_contracts.with_trial_period_expired(now)
    end
  end

  protected

  def update_invoices_vat_rates
    invoices.not_frozen.reorder('').update_all(vat_rate: vat_rate)
  end

  # Will prevent the buyer from destroying if there are unresolved
  # invoices present.
  #
  def check_unresolved_invoices
    return true if !invoices.unresolved.exists? || should_be_deleted?
    errors.add(:invoices, :unresolved_invoices)
    throw :abort
  end

  def save_in_payment!
    @in_payment = true
    save!
  ensure
    @in_payment = false
  end

  public

  # This returns true only if account is in the middle of executing a payment (the pay! method,
  # account can be either the payer or the payee).
  #
  # This is used by observers, to differentiate between saving an account and just calling the
  # pay! method.
  def in_payment?
    @in_payment
  end

  # MODEL: Buyer
  # Charge this account the given amount via payment gateway.
  #
  # REFACTOR: move to billing strategy!
  #
  # options has :invoice
  def charge!(amount, options = {})
    unless credit_card_stored?
      logger.info("Buyer #{self.id} was not charged: credit card missing")
      raise Finance::Payment::CreditCardMissing
    end

    gateway_options = options.delete(:gateway_options) || {}

    transaction = payment_transactions.build(options.reverse_merge(:action => :purchase,
                                                                   :amount => amount))

    # add order_id
    if options[:invoice].is_a?(Invoice) && gateway_options.include?(:order_id)== false
      gateway_options[:order_id]= options[:invoice].id
    end

    gateway_options.reverse_merge!(payment_method_id: payment_detail.payment_method_id) if provider_payment_gateway.is_a?(ActiveMerchant::Billing::StripeGateway)

    logger.info("Processing transaction for buyer #{self.id} with code #{credit_card_auth_code}, gateway #{provider_payment_gateway} & options #{gateway_options}")

    transaction.process!(credit_card_auth_code, provider_payment_gateway, gateway_options)
  end


  # MODEL: Buyer
  # TODO: Remove?
  #
  def current_invoice
    invoices.opened.first
  end
end