3scale/porta

View on GitHub
app/models/payment_transaction.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true

class PaymentTransaction < ApplicationRecord
  include Symbolize
  belongs_to :account
  belongs_to :invoice, inverse_of: :payment_transactions

  symbolize :action
  serialize :params
  has_money :amount

  validates :amount, presence: true
  validates :currency, length: {maximum: 4}
  validates :message, :reference, :action, length: {maximum: 255}

  attr_protected :account_id, :invoice_id, :success, :test, :tenant_id

  scope :failed, -> { where(:success => false) }
  scope :succeeded, -> { where(:success => true) }
  scope :oldest_first, -> { order(:created_at) }

  def process!(credit_card_auth_code, gateway, options)
    unless System::Application.config.three_scale.payments.enabled
      logger.info "Skipping payment transaction #process! - not in production"
      return
    end

    options[:currency] = currency

    logger.info("Processing PaymentTransaction with code #{credit_card_auth_code}, gateway #{gateway} & options #{options}")

    begin
      logger.info("Purchasing with #{gateway.class}")

      charging_service = Finance::ChargingService.new(gateway, buyer_reference: credit_card_auth_code, amount: amount, options: options.merge(invoice: invoice))
      response = charging_service.call

      self.success = response.success?
      self.reference = response.authorization
      self.message = response.message
      self.params = response.params
      self.test = response.test
    rescue ActiveMerchant::ActiveMerchantError => exception
      logger.info("Processing of PaymentTransaction threw an exception: #{exception.message}")
      self.success = false
      self.message = exception.message
      self.test = gateway.test?
      raise exception
    ensure
      logger.info("Saving PaymentTransaction")
      self.save!
    end

    unless response && response.success?
      logger.info("PaymentTransaction processing not successful. Response: #{response.inspect}")
      raise Finance::Payment::CreditCardPurchaseFailed.new(response)
    end

    self
  end

  # TODO: writable currency should be feature of the has_money plugin.
  # XXX: has_money plugin is a ghetoo
  module AmountWithCurrency
    def amount=(value)
      if value.respond_to?(:currency)
        super(value.amount)
        self.currency = value.currency
      else
        super(value)
      end
    end
  end
  prepend AmountWithCurrency


  def self.to_xml(payment_transactions, options = {})
    builder = ThreeScale::XML::Builder.new

    builder.payment_transactions do |xml|
      payment_transactions.each{ |pt| pt.to_xml(:builder => xml) }
    end

    builder.to_xml
  end

  def to_xml(options = {})
    xml = options[:builder] || ThreeScale::XML::Builder.new

    xml.payment_transaction do |xml|
      unless new_record?
        xml.id_ id
        xml.created_at created_at.xmlschema
        xml.updated_at updated_at.xmlschema
      end

      xml.invoice_id invoice_id
      xml.account_id account_id
      xml.reference reference
      xml.success success
      xml.amount amount
      xml.currency currency
      xml.action action
      xml.message message
      if params
        params.to_xml(root: 'gateway_response', builder: xml, skip_instruct: true, dasherize: false)
      else
        xml.gateway_response nil
      end
      xml.test test
    end

    xml.to_xml
  end
end