Skip to content

Instantly share code, notes, and snippets.

@lucashour
Last active October 3, 2019 13:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucashour/af4b666cabd488b1c9fd429776d24a61 to your computer and use it in GitHub Desktop.
Save lucashour/af4b666cabd488b1c9fd429776d24a61 to your computer and use it in GitHub Desktop.
RoR: Mercado Pago webhooks integration
# app/services/mercadopago_client/base.rb
module MercadopagoClient
class Base
require 'mercadopago'
STATUSES = [
APPROVED = 'approved',
BPP_COVERED = 'bpp_covered',
CHARGED_BACK = 'charged_back',
IN_MEDIATION = 'in_mediation',
IN_PROCESS = 'in_process',
PARTIALLY_REFUNDED = 'partially_refunded',
REFUNDED = 'refunded',
REJECTED = 'rejected'
].freeze
TOPICS = [
PAYMENT = 'payment',
CHARGEBACKS = 'chargebacks'
].freeze
private
def connector
MercadoPago.new(Rails.application.secrets['mercadopago']['access_token'])
end
def valid_response?(response)
['200', '201'].include?(response[:status].to_s)
end
end
end
# app/services/mercadopago_client/webhook.rb
module MercadopagoClient
class Webhook < Base
def initialize(params)
@params = params
end
def call
case @params[:topic]
when PAYMENT then process_payment_webhook
when CHARGEBACKS then process_chargeback_webhook
end
true
rescue
false
end
private
def process_payment_webhook
payment = gateway_payment@params[:id])
return false unless payment
data = payment[:response][:collection]
status = data[:status]
status_detail = data[:status_detail]
@invoice = Invoice.find(data[:external_reference])
if bpp_covered_refund?(status, status_detail)
process_bpp_covered_refund(data)
elsif refunded?(status, status_detail)
process_refund(data[:refunds])
elsif charged_back?(status, status_detail)
process_charged_back_payment
elsif in_mediation?(status)
process_in_mediation_payment
elsif in_process?(status)
process_in_process_payment
elsif rejected?(status)
process_rejected_payment
elsif approved?(status)
process_created_payment(data)
end
end
def bpp_covered_refund?(status, status_detail)
status == REFUNDED && status_detail == BPP_COVERED
end
def refunded?(status, status_detail)
status == REFUNDED || status_detail == PARTIALLY_REFUNDED
end
def charged_back?(status, status_detail)
status == CHARGED_BACK && status_detail == IN_PROCESS
end
def in_mediation?(status)
status == IN_MEDIATION
end
def in_process?(status)
status == IN_PROCESS
end
def rejected?(status)
status == REJECTED
end
def approved?(status)
status == APPROVED
end
def process_chargeback_webhook
return unless chargeback
payment = gateway_payment(chargeback[:payments].first)
return unless payment
# ...
end
def process_chargeback(payment_transaction, payment)
# ...
end
def unsolved_chargeback?
chargeback[:coverage_applied].nil?
end
def chargeback_favorable_resolution?
chargeback[:coverage_applied]
end
def process_refund(refunds)
# ...
end
def process_bpp_covered_refund(data)
# ...
end
def process_charged_back_payment
# ...
end
def process_in_mediation_payment
# ...
end
def process_in_process_payment
# ...
end
def process_rejected_payment
# ...
end
def process_created_payment(data)
# ...
end
def gateway_payment(id)
data = connector
.get_payment_info(id.to_s)
.deep_symbolize_keys
valid_response?(data) ? data : false
end
def chargeback
return @chargeback if @chargeback
data = connector
.get("/v1/chargebacks/#{@params[:id]}")
.deep_symbolize_keys
@chargeback = valid_response?(data) ? data : false
end
end
end
# app/controllers/api/v1/webhooks_controller.rb
class Api::V1::WebhooksController < ApiController
def mercadopago
MercadopagoClient::Webhook.new(params).delay.call # Using Delayed::Job
render nothing: true, status: :ok
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment