-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Jonathan Tapia
committed
Jun 8, 2020
1 parent
aaa7794
commit 119591e
Showing
11 changed files
with
204 additions
and
169 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
.DS_Store | ||
Gemfile.lock | ||
spec/test_app | ||
spec/dummy | ||
.sass-cache | ||
.bundle | ||
*.swp | ||
.rvmrc | ||
*.gem | ||
.idea | ||
VersionFile | ||
|
||
*.rbc | ||
capybara-*.html | ||
/db/*.sqlite3 | ||
/db/*.sqlite3-journal | ||
|
||
/coverage/ | ||
/spec/tmp | ||
docker-compose.yml | ||
/.docker-sync | ||
/.bundle | ||
/vendor/bundle | ||
|
||
spec/dummy/**/* | ||
coverage/**/* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
22 changes: 22 additions & 0 deletions
22
app/models/mercadopago/services/handle_received_notification.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
84 changes: 84 additions & 0 deletions
84
spec/models/mercadopago/services/process_notification_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.