Skip to content

Commit

Permalink
Fix broken test
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Tapia committed Jun 8, 2020
1 parent aaa7794 commit bfe832d
Show file tree
Hide file tree
Showing 11 changed files with 194 additions and 169 deletions.
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
*.gem
\#*
*~
.#*
.DS_Store
.idea
.project
.sass-cache
coverage
Gemfile.lock
tmp
nbproject
pkg
*.swp
spec/dummy
coverage/**/*
4 changes: 2 additions & 2 deletions app/controllers/spree/mercadopago_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def checkout
.create!(amount: current_order.total, payment_method: payment_method)
payment.started_processing!

preferences = ::Mercadopago::OrderPreferencesBuilder
preferences = Mercadopago::Services::OrderPreferencesBuilder
.new(current_order, payment, callback_urls)
.preferences_hash

Expand Down Expand Up @@ -43,7 +43,7 @@ def ipn
.new(operation_id: params[:id], topic: params[:topic])

if notification.save
Mercadopago::HandleReceivedNotification.new(notification).process!
Mercadopago::Services::HandleReceivedNotification.new(notification).process!
status = :ok
else
status = :bad_request
Expand Down
22 changes: 22 additions & 0 deletions app/models/mercadopago/services/handle_received_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

module Mercadopago
module Services
class HandleReceivedNotification
def initialize(notification)
@notification = notification
end

# The purpose of this method is to enable async/sync processing
# of Mercado Pago IPNs. For simplicity processing is synchronous but
# if you would like to enqueue the processing via Resque/Ost/etc you
# will be able to do it.
def process!
# Sync
::ProcessNotification.new(@notification).process!
# Async Will be configurable via block for example:
# Resque.enqueue(ProcessNotificationWorker, {id: @notification.id})
end
end
end
end
60 changes: 60 additions & 0 deletions app/models/mercadopago/services/process_notification.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# frozen_string_literal: true

# Process notification:
# ---------------------
# Fetch collection information
# Find payment by external reference
# If found
# Update payment status
# Notify user
# If not found
# Ignore notification (maybe payment from outside Spree)
module Mercadopago
module Services
class ProcessNotification
# Equivalent payment states
# MP state => Spree state
# =======================
#
# approved => complete
# pending => pend
# in_process => pend
# rejected => failed
# refunded => void
# cancelled => void
# in_mediation => pend
# charged_back => void
STATES = {
complete: %w[approved],
failure: %w[rejected],
void: %w[refunded cancelled charged_back]
}.freeze

attr_reader :notification

def initialize(notification)
@notification = notification
end

def process!
# Fix: Payment method is an instance of Spree::PaymentMethod::Mercadopago not THE class
client = ::Spree::PaymentMethod::Mercadopago.first.provider
raw_op_info = client.get_operation_info(notification.operation_id)
op_info = raw_op_info['collection'] if raw_op_info.present?
# TODO: rewrite this.
if op_info && (payment = Spree::Payment.where(number: op_info['external_reference']).first)
if STATES[:complete].include?(op_info['status'])
payment.complete
elsif STATES[:failure].include?(op_info['status'])
payment.failure
elsif STATES[:void].include?(op_info['status'])
payment.void
end

# When Spree issue #5246 is fixed we can remove this line
payment.order.updater.update
end
end
end
end
end
4 changes: 2 additions & 2 deletions app/models/spree/payment_method/mercadopago.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
module Spree
class PaymentMethod::Mercadopago < PaymentMethod
preference :sandbox, :boolean, default: true
preference :client_id, :string, default: ENV['Mercadopago_CLIENT_ID']
preference :client_secret, :string, default: ENV['Mercadopago_CLIENT_SECRET']
preference :client_id, :string, default: ENV['MERCADOPAGO_CLIENT_ID']
preference :client_secret, :string, default: ENV['MERCADOPAGO_CLIENT_SECRET']

def payment_profiles_supported?
false
Expand Down
20 changes: 0 additions & 20 deletions app/services/mercadopago/handle_received_notification.rb

This file was deleted.

58 changes: 0 additions & 58 deletions app/services/mercadopago/process_notification.rb

This file was deleted.

2 changes: 1 addition & 1 deletion spec/controllers/spree/mercado_pago_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
let(:use_case) { double('use_case') }

it 'handles notification and returns success' do
allow(Mercadopago::HandleReceivedNotification).to receive(:new).and_return(use_case)
allow(Mercadopago::Services::HandleReceivedNotification).to receive(:new).and_return(use_case)
expect(use_case).to receive(:process!)

post :ipn, params: { id: operation_id, topic: 'payment', format: :json }
Expand Down
9 changes: 7 additions & 2 deletions spec/models/mercadopago/order_preferences_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

require 'spec_helper'

describe 'OrderPreferencesBuilder' do
describe Mercadopago::OrderPreferencesBuilder do
# Factory order_with_line_items is incredibly slow..
let(:order) do
order = create(:order)
Expand All @@ -20,7 +20,12 @@
include Spree::ProductsHelper

context 'Calling preferences_hash' do
let(:subject) { Mercadopago::OrderPreferencesBuilder.new(order, payment, callback_urls, payer_data).preferences_hash }
let(:subject) do
Mercadopago::OrderPreferencesBuilder.new(order,
payment,
callback_urls,
payer_data).preferences_hash
end

it 'returns external reference' do
end
Expand Down
84 changes: 84 additions & 0 deletions spec/models/mercadopago/services/process_notification_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# frozen_string_literal: true

require 'spec_helper'

describe Mercadopago::Services::ProcessNotification do
let(:order) { FactoryBot.create(:completed_order_with_pending_payment) }
let(:payment) { order.payments.first }

let(:operation_id) { 'op123' }
let(:notification) do
Mercadopago::Notification.new(topic: 'payment', operation_id: operation_id)
end
let(:operation_info) do
{
'collection' => {
'external_reference' => order.payments.first.number,
'status' => 'approved'
}
}
end

describe 'with valid operation_info' do
# The first payment method of this kind will be picked by the process task
before do
fake_client = double('fake_client')
fake_payment_method = double('fake_payment_method', provider: fake_client)
allow(Spree::PaymentMethod::Mercadopago).to receive(:first).and_return(fake_payment_method)
allow(fake_client).to receive(:get_operation_info).with(operation_id)
.and_return(operation_info)
# TODO: check this test
# payment.pend!
expect(payment.state).to eq('pending')
end

describe '#process!' do
it 'completes payment for approved payment' do
Mercadopago::Services::ProcessNotification.new(notification).process!
payment.reload
expect(payment.state).to eq('completed')
end

it 'fails payment for rejected payment' do
operation_info['collection']['status'] = 'rejected'
Mercadopago::Services::ProcessNotification.new(notification).process!
payment.reload
expect(payment.state).to eq('failed')
end

it 'voids payment for rejected payment' do
operation_info['collection']['status'] = 'cancelled'
Mercadopago::Services::ProcessNotification.new(notification).process!
payment.reload
expect(payment.state).to eq('void')
end

it 'pends payment for pending payment' do
operation_info['collection']['status'] = 'pending'
Mercadopago::Services::ProcessNotification.new(notification).process!
payment.reload
expect(payment.state).to eq('pending')
end
end
end

describe 'with invalid operation_info' do
# The first payment method of this kind will be picked by the process task
before do
fake_client = double('fake_client')
fake_payment_method = double('fake_payment_method', provider: fake_client)
allow(Spree::PaymentMethod::Mercadopago).to receive(:first).and_return(fake_payment_method)
allow(fake_client).to receive(:get_operation_info).with(operation_id)
.and_return(nil)
# TODO: check this test
# payment.pend!
expect(payment.state).to eq('pending')
end

describe '#process!' do
it 'does not crash' do
Mercadopago::Services::ProcessNotification.new(notification).process!
end
end
end
end
Loading

0 comments on commit bfe832d

Please sign in to comment.