var.rb 4.84 KB
require "var/version"
require 'conekta'
require 'paypal-sdk-rest'

module Var
  # TODO: add paypal
  # @@valid_services = [:conekta, :paypal]
  VALID_SERVICES = [:conekta]

  def self.valid_services
    VALID_SERVICES
  end

  def self.create_charge(service, object, options = {})
    return { error_message: 'Service is not supported' } unless VALID_SERVICES.include? service
    return { error_message: "#{object.class.to_s} doesn't support charges"} unless object.respond_to?(:charge_with)
    charge = object.charge_with(service, options)
    object.update_columns(var_status: 'payed') unless charge.include? :error_message
    return charge
  end
end

module ActsAsChargeable
  extend ActiveSupport::Concern

  module ClassMethods
    def acts_as_chargeable(keys = {})
      include ChargeableInstanceMethods
      cattr_accessor :sync_attributes
      self.sync_attributes = keys
    end
  end

  module ChargeableInstanceMethods
    def charge_with(service, options)
      if !instance_support?(service)
        error_message = "#{self.class.to_s} doesn't support" \
                        " charges with #{service.to_s}"
        return { error_message: error_message}
      end
      self.send("charge_with_#{service.to_s}", options)
    rescue  Exception => exception
      { error_message: exception.message }
    end

    def charge_with_conekta(options)
      if(!options.include? :card_token)
        error_message = "Conekta needs a card token sent as a third paramater"
        return { error_message: error_message}
      end
      @charge ||= Conekta::Charge.create({
        description: self.sync(:conekta, 'description'),
        amount: self.sync(:conekta, 'amount'), currency: "MXN",
        reference_id: self.sync(:conekta, 'reference_id'),
        card: options[:card_token],
        details: {
          name: self.sync(:conekta, 'name'),
          email: self.sync(:conekta, 'email'),
          line_items: [{
            name: self.sync(:conekta, 'name'),
            description: self.sync(:conekta, 'description'),
            unit_price: self.sync(:conekta, 'amount'), quantity: 1,
          }]
        }
      })
    rescue Conekta::ParameterValidationError, Conekta::ProcessingError, Conekta::Error  => e
      self.update_columns(var_status: 'failed')
      { error_message: e.message }
    end

    # def charge_with_paypal(options)
    #   if(!options.include? :card)
    #     error_message = "Paypal needs a card sent as a third paramater"
    #     return { error_message: error_message}
    #   end
    #   @payment = PayPal::SDK::REST::Payment.new({
    #     intent: "sale",
    #     payer: {
    #       payer_info: {
    #         email: self.sync(:paypal, 'email')},
    #       payment_method: "credit_card",
    #       funding_instruments: [{
    #         credit_card: {
    #           type: options[:card][:type],
    #           number: options[:card][:number],
    #           expire_month: options[:card][:expire_month],
    #           expire_year: options[:card][:expire_year],
    #           cvv2: options[:card][:cvv2]}}]},
    #     transactions: [{
    #       item_list: {
    #         items: [{
    #           name: self.sync(:paypal, 'name'),
    #           sku: self.sync(:paypal, 'sku'),
    #           price: self.sync(:paypal, 'price'),
    #           currency: "MXN",
    #           quantity: 1 }]},
    #       amount: {
    #         total: self.sync(:paypal, 'price'),
    #         currency: "MXN" },
    #       description: self.sync(:paypal, 'description') }]})
    # end

    def find_charge(service)
      if !instance_support?(service)
        error_message = "#{self.class.to_s} doesn't support" \
                      " charges with #{service.to_s}"
        return { error_message: error_message}
      end
      self.send("find_#{service.to_s}_charge")
    rescue  Exception => exception
      { error_message: exception.message }
    end

    def charged?(service)
      charge = find_charge(service)
      charge.any? && !charge.include?(:error_message)
    end

    def find_conekta_charge
      ref_id = self.sync(:conekta, 'reference_id')
      Conekta::Charge.where({'status.ne'=>'paid', 'reference_id'=> ref_id})
    end

    def instance_support?(service)
      return self.sync_attributes.include?(service)
    end

    def sync(service, key)
      service_attributes = self.send("#{service.to_s}_attributes")
      return self.send(key) if !service_attributes.include? key.to_sym
      self.send(service_attributes[key.to_sym])
    end

    # def sync_attribute(key)
    #   return self.send(key) unless self.sync_attributes.include? key.to_sym
    #   self.send(sync_attributes[key.to_sym])
    # end

    def conekta_attributes
      self.sync_attributes[:conekta] || {}
    end

    def paypal_attributes
      self.sync_attributes[:paypal] || {}
    end
  end
end

ActiveRecord::Base.send(:include, ActsAsChargeable) if defined? ActiveRecord::Base