From 76a4804201e93b36e20b4dab9acaa7963adc852a Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Mon, 8 Aug 2016 14:59:44 -0400 Subject: [PATCH 1/9] Add prototyped version of the Shopify Gateway This includes the void, credit and cancel operations. Those are the only once required for our current implementation of Shopify Gateway. --- app/models/spree/gateway/shopify_gateway.rb | 64 ++++++++++ solidus_gateway.gemspec | 1 + spec/models/gateway/shopify_gateway_spec.rb | 134 ++++++++++++++++++++ spec/spec_helper.rb | 1 + 4 files changed, 200 insertions(+) create mode 100644 app/models/spree/gateway/shopify_gateway.rb create mode 100644 spec/models/gateway/shopify_gateway_spec.rb diff --git a/app/models/spree/gateway/shopify_gateway.rb b/app/models/spree/gateway/shopify_gateway.rb new file mode 100644 index 0000000..4e8ebb0 --- /dev/null +++ b/app/models/spree/gateway/shopify_gateway.rb @@ -0,0 +1,64 @@ +module Spree + class Gateway::ShopifyGateway < Gateway + preference :api_key, :string + preference :password, :string + preference :shop_name, :string + preference :shared_secret, :string + # Reimburse + + # Should all this logic be a active_merchant/billing/gateways/ instead of directly the gateway? + def credit(money, transaction_id, gateway_options) + configure_shopify_api! + refund = gateway_options[:originator] + transaction = ::ShopifyAPI::Transaction.find(transaction_id) + if BigDecimal.new(money.to_s) == (transaction.amount * 100) + full_refund_on_shopify(refund, transaction) + elsif BigDecimal.new(money.to_s) < (transaction.amount * 100) + # Partial refund + binding.pry + else + # HUHO! + binding.pry + raise NotImplementedError + end + end + + def void(transaction_id, gateway_options) + configure_shopify_api! + # Figure out how to directly do a post request instead of get and post + transaction = ::ShopifyAPI::Transaction.find(transaction_id) + transaction.kind = 'void' + transaction.save + end + + def cancel(transaction_id) + configure_shopify_api! + # Figure out how to directly do a post request instead of get and post + transaction = ::ShopifyAPI::Transaction.find(transaction_id) + transaction.kind = 'void' + transaction.save + end + + private + + def full_refund_on_shopify(refund, transaction) + transaction = ::ShopifyAPI::Refund.calculate({ shipping: { full_refund: true } }, + params: { order_id: transaction.order_id }) + + ::ShopifyAPI::Refund.create({ shipping: { full_refund: true }, + note: refund.reason.name, + notify: false, + restock: false, + transaction: transaction }, + params: { order_id: transaction.order_id }) + end + + def configure_shopify_api! + ::ShopifyAPI::Base.site = shopify_shop_url + end + + def shopify_shop_url + "https://#{preferred_api_key}:#{preferred_password}@#{preferred_shop_name}" + end + end +end diff --git a/solidus_gateway.gemspec b/solidus_gateway.gemspec index 0eb62f1..b41651e 100644 --- a/solidus_gateway.gemspec +++ b/solidus_gateway.gemspec @@ -32,6 +32,7 @@ Gem::Specification.new do |s| s.add_dependency "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0" s.add_development_dependency "braintree", "~> 2.0" + s.add_development_dependency "shopify_api", "~> 4.0" s.add_development_dependency "rspec-rails", "~> 3.2" s.add_development_dependency "simplecov" s.add_development_dependency "sqlite3" diff --git a/spec/models/gateway/shopify_gateway_spec.rb b/spec/models/gateway/shopify_gateway_spec.rb new file mode 100644 index 0000000..e547dfe --- /dev/null +++ b/spec/models/gateway/shopify_gateway_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' + +describe Spree::Gateway::ShopifyGateway do + let(:api_key) { '5ea25b239cdbe5df107b7ff2c366b5de' } + let(:password) { '0343a464bacb8ceff405e6e4e4b88ff3' } + let(:shop_name) { 'dynamo-staging.myshopify.com/admin' } + let(:shared_secret) { '3781b32c2fb712e5a4f90a1a1bb8e0a397527d0e3530f755c41b28d0b2ee5c11' } + + let(:gateway) do + gateway = described_class.new(active: true) + gateway.set_preference(:api_key, api_key) + gateway.set_preference(:password, password) + gateway.set_preference(:shop_name, shop_name) + gateway.set_preference(:shared_secret, shared_secret) + gateway + end + + let!(:store) { FactoryGirl.create(:store) } + let(:order) { Spree::Order.create! } + + let(:card) do + FactoryGirl.create( + :credit_card, + gateway_customer_profile_id: 'cus_abcde', + imported: false + ) + end + + let(:payment) do + payment = Spree::Payment.new + payment.source = card + payment.order = order + payment.payment_method = gateway + payment.amount = 54 + payment.state = 'pending' + payment.response_code = '12345' + payment + end + + context '.void' do + let(:shopify_transaction) { double('shopify_transaction') } + let(:transaction_id) { 1 } + + before do + allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) + end + + it 'calls save on the shopify transaction once' do + expect(shopify_transaction).to receive(:save).once + void!(transaction_id, nil) + end + + private + + def void!(transaction_id, gateway_options) + subject.void(transaction_id, gateway_options) + end + end + + context '.cancel' do + let(:shopify_transaction) { double('shopify_transaction') } + let(:transaction_id) { 1 } + + before do + allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) + end + + it 'calls save on the shopify transaction once' do + expect(shopify_transaction).to receive(:save).once + cancel!(transaction_id) + end + + private + + def cancel!(transaction_id) + subject.cancel(transaction_id) + end + end + + context '.credit' do + let(:amount) { 48 } + let(:amount_in_cents) { amount * 100 } + let(:shopify_order_id) { 3910455495 } + let(:transaction_id) { 1 } + + let(:shopify_transaction) do + double('shopify_transaction').tap do |s_t| + allow(s_t).to receive(:amount).and_return(amount) + allow(s_t).to receive(:order_id).and_return(shopify_order_id) + end + end + + before do + allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) + allow(::ShopifyAPI::Refund).to receive(:calculate).and_return(shopify_transaction) + allow(::ShopifyAPI::Refund).to receive(:create).and_return(true) + end + + context 'all line items' do + context 'with a full refund' do + let(:reason) { FactoryGirl.create(:refund_reason) } + # let(:return_item) { build(:return_item, inventory_unit: inventory_unit) } + # let(:customer_return) { build(:customer_return, return_items: [return_item]) } + # let(:reimbursement) { FactoryGirl.create(:reimbursement, refunds: refund) } + + let(:refund) do + refund = Spree::Refund.new + refund.payment = payment + refund.reason = reason + refund.amount = payment.amount + refund.transaction_id = nil + + refund + end + + it 'calls the shopify calculate refund method once' do + expect(::ShopifyAPI::Refund).to receive(:calculate).once + refund!(amount_in_cents, transaction_id, refund) + end + + it 'calls the shopify calculate create method once' do + expect(::ShopifyAPI::Refund).to receive(:create).once + refund!(amount_in_cents, transaction_id, refund) + end + end + end + end + + private + + def refund!(amount_in_cents, transaction_id, refund) + subject.credit(amount_in_cents, transaction_id, originator: refund) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 72f8644..0e3dec1 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,6 +16,7 @@ require "database_cleaner" require "braintree" +require "shopify_api" require "ffaker" require "spree/testing_support/factories" From d3468682d8e74eb87c3524e917833a7239d404f8 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Mon, 8 Aug 2016 16:05:26 -0400 Subject: [PATCH 2/9] Add ShopifyGateway to the list of possible gateways --- lib/spree_gateway/engine.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/spree_gateway/engine.rb b/lib/spree_gateway/engine.rb index 6f00024..629e95d 100644 --- a/lib/spree_gateway/engine.rb +++ b/lib/spree_gateway/engine.rb @@ -28,6 +28,7 @@ class Engine < Rails::Engine app.config.spree.payment_methods << Spree::Gateway::Paymill app.config.spree.payment_methods << Spree::Gateway::PayflowPro app.config.spree.payment_methods << Spree::Gateway::SecurePayAU + app.config.spree.payment_methods << Spree::Gateway::ShopifyGateway app.config.spree.payment_methods << Spree::Gateway::Maxipago app.config.spree.payment_methods << Spree::Gateway::Migs app.config.spree.payment_methods << Spree::Gateway::SpreedlyCoreGateway From e8449da96d74fb7f5d8bbfaa659432082eecae9c Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Mon, 8 Aug 2016 18:05:29 -0400 Subject: [PATCH 3/9] Remove some debug break point and comments --- app/models/spree/gateway/shopify_gateway.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/models/spree/gateway/shopify_gateway.rb b/app/models/spree/gateway/shopify_gateway.rb index 4e8ebb0..7bc022e 100644 --- a/app/models/spree/gateway/shopify_gateway.rb +++ b/app/models/spree/gateway/shopify_gateway.rb @@ -14,11 +14,8 @@ def credit(money, transaction_id, gateway_options) if BigDecimal.new(money.to_s) == (transaction.amount * 100) full_refund_on_shopify(refund, transaction) elsif BigDecimal.new(money.to_s) < (transaction.amount * 100) - # Partial refund - binding.pry + raise NotImplementedError else - # HUHO! - binding.pry raise NotImplementedError end end From 5e6af0ab87282e6275756163ec96d0d6c97cade9 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Tue, 9 Aug 2016 15:20:57 -0400 Subject: [PATCH 4/9] Refactor the Shopify Gateway to follow the ActiveMerchant convention In the end, I feel like ActiveMerchant should be aware of how stuff interact with each others it should not be the job of the gateway. All the logic has been move in the ActiveMerchant Github repository that can access here: https://github.com/DynamoMTL/active_merchant --- Gemfile | 6 +++ app/models/spree/gateway/shopify_gateway.rb | 57 +++++---------------- solidus_gateway.gemspec | 7 --- 3 files changed, 19 insertions(+), 51 deletions(-) diff --git a/Gemfile b/Gemfile index 4e30e9d..1330c32 100644 --- a/Gemfile +++ b/Gemfile @@ -3,6 +3,12 @@ source "https://rubygems.org" branch = ENV.fetch('SOLIDUS_BRANCH', 'master') gem "solidus", github: "solidusio/solidus", branch: branch +# ActiveMerchant v1.58 through v1.59 introduced a breaking change +# to the stripe gateway. +# +# This was resolved in v1.60, but we still need to skip 1.58 & 1.59. +gem "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0", github: "dynamomtl/active_merchant", branch: 'master' + group :development, :test do gem "pry-rails" end diff --git a/app/models/spree/gateway/shopify_gateway.rb b/app/models/spree/gateway/shopify_gateway.rb index 7bc022e..fccdc0b 100644 --- a/app/models/spree/gateway/shopify_gateway.rb +++ b/app/models/spree/gateway/shopify_gateway.rb @@ -3,59 +3,28 @@ class Gateway::ShopifyGateway < Gateway preference :api_key, :string preference :password, :string preference :shop_name, :string - preference :shared_secret, :string - # Reimburse - # Should all this logic be a active_merchant/billing/gateways/ instead of directly the gateway? - def credit(money, transaction_id, gateway_options) - configure_shopify_api! - refund = gateway_options[:originator] - transaction = ::ShopifyAPI::Transaction.find(transaction_id) - if BigDecimal.new(money.to_s) == (transaction.amount * 100) - full_refund_on_shopify(refund, transaction) - elsif BigDecimal.new(money.to_s) < (transaction.amount * 100) - raise NotImplementedError - else - raise NotImplementedError - end - end - - def void(transaction_id, gateway_options) - configure_shopify_api! - # Figure out how to directly do a post request instead of get and post - transaction = ::ShopifyAPI::Transaction.find(transaction_id) - transaction.kind = 'void' - transaction.save + def provider_class + ActiveMerchant::Billing::ShopifyGateway end - def cancel(transaction_id) - configure_shopify_api! - # Figure out how to directly do a post request instead of get and post - transaction = ::ShopifyAPI::Transaction.find(transaction_id) - transaction.kind = 'void' - transaction.save + def method_type + 'shopify' end - private - - def full_refund_on_shopify(refund, transaction) - transaction = ::ShopifyAPI::Refund.calculate({ shipping: { full_refund: true } }, - params: { order_id: transaction.order_id }) - - ::ShopifyAPI::Refund.create({ shipping: { full_refund: true }, - note: refund.reason.name, - notify: false, - restock: false, - transaction: transaction }, - params: { order_id: transaction.order_id }) + def credit(money, transaction_id, gateway_options) + provider.refund(money, transaction_id, gateway_options) end - def configure_shopify_api! - ::ShopifyAPI::Base.site = shopify_shop_url + def void(transaction_id, gateway_options) + pos_order_id = gateway_options[:originator].pos_order_id + provider.void(transaction_id, order_id: pos_order_id) end - def shopify_shop_url - "https://#{preferred_api_key}:#{preferred_password}@#{preferred_shop_name}" + def cancel(_transaction_id) + # NOTE(cab): I am unsure how we can achieve that, since we are required + # to have the order_id in order to call the Shopify API. + raise NotImplementedError end end end diff --git a/solidus_gateway.gemspec b/solidus_gateway.gemspec index b41651e..c39dbf3 100644 --- a/solidus_gateway.gemspec +++ b/solidus_gateway.gemspec @@ -25,14 +25,7 @@ Gem::Specification.new do |s| s.add_dependency "solidus_core", "~> 1.1" - # ActiveMerchant v1.58 through v1.59 introduced a breaking change - # to the stripe gateway. - # - # This was resolved in v1.60, but we still need to skip 1.58 & 1.59. - s.add_dependency "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0" - s.add_development_dependency "braintree", "~> 2.0" - s.add_development_dependency "shopify_api", "~> 4.0" s.add_development_dependency "rspec-rails", "~> 3.2" s.add_development_dependency "simplecov" s.add_development_dependency "sqlite3" From 9e99e927c62bfa244b75c29230c3a64ed0c75daf Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Tue, 9 Aug 2016 15:41:55 -0400 Subject: [PATCH 5/9] Add the ActiveMerchant version that contains the Shopify Prototype --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 1330c32..f5c9865 100644 --- a/Gemfile +++ b/Gemfile @@ -7,7 +7,7 @@ gem "solidus", github: "solidusio/solidus", branch: branch # to the stripe gateway. # # This was resolved in v1.60, but we still need to skip 1.58 & 1.59. -gem "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0", github: "dynamomtl/active_merchant", branch: 'master' +gem "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0", github: "dynamomtl/active_merchant_new", branch: 'feature/shopify/prototype-implementation' group :development, :test do gem "pry-rails" From 79b278266586e3522811416d935994cb8ed6df54 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Tue, 9 Aug 2016 17:54:53 -0400 Subject: [PATCH 6/9] WIP --- solidus_gateway.gemspec | 2 +- spec/models/gateway/shopify_gateway_spec.rb | 122 ++++---------------- spec/spec_helper.rb | 1 - 3 files changed, 22 insertions(+), 103 deletions(-) diff --git a/solidus_gateway.gemspec b/solidus_gateway.gemspec index c39dbf3..ac49e76 100644 --- a/solidus_gateway.gemspec +++ b/solidus_gateway.gemspec @@ -11,7 +11,7 @@ Gem::Specification.new do |s| s.version = SolidusGateway::VERSION s.summary = "Additional Payment Gateways for Solidus" s.description = s.summary - s.required_ruby_version = ">= 2.1" + s.required_ruby_version = ">= 2.3" s.author = "Solidus Team" s.email = "contact@solidus.io" diff --git a/spec/models/gateway/shopify_gateway_spec.rb b/spec/models/gateway/shopify_gateway_spec.rb index e547dfe..b3f0f5e 100644 --- a/spec/models/gateway/shopify_gateway_spec.rb +++ b/spec/models/gateway/shopify_gateway_spec.rb @@ -1,134 +1,54 @@ require 'spec_helper' describe Spree::Gateway::ShopifyGateway do - let(:api_key) { '5ea25b239cdbe5df107b7ff2c366b5de' } - let(:password) { '0343a464bacb8ceff405e6e4e4b88ff3' } - let(:shop_name) { 'dynamo-staging.myshopify.com/admin' } - let(:shared_secret) { '3781b32c2fb712e5a4f90a1a1bb8e0a397527d0e3530f755c41b28d0b2ee5c11' } + let(:transaction_id) { '0xDEADBEEF' } + let(:pos_order_id) { '0xBAADF00D' } + let(:refund) { double('refund') } + let(:gateway_options) { { originator: refund } } - let(:gateway) do - gateway = described_class.new(active: true) - gateway.set_preference(:api_key, api_key) - gateway.set_preference(:password, password) - gateway.set_preference(:shop_name, shop_name) - gateway.set_preference(:shared_secret, shared_secret) - gateway - end - - let!(:store) { FactoryGirl.create(:store) } - let(:order) { Spree::Order.create! } + let(:provider_class) { ActiveMerchant::Billing::ShopifyGateway } - let(:card) do - FactoryGirl.create( - :credit_card, - gateway_customer_profile_id: 'cus_abcde', - imported: false - ) - end - - let(:payment) do - payment = Spree::Payment.new - payment.source = card - payment.order = order - payment.payment_method = gateway - payment.amount = 54 - payment.state = 'pending' - payment.response_code = '12345' - payment + before do + allow(refund).to receive(:pos_order_id).and_return(pos_order_id) end context '.void' do - let(:shopify_transaction) { double('shopify_transaction') } - let(:transaction_id) { 1 } - - before do - allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) - end - - it 'calls save on the shopify transaction once' do - expect(shopify_transaction).to receive(:save).once - void!(transaction_id, nil) + it 'calls the provider void method once' do + expect(provider_class).to receive(:void).once + void! end private - def void!(transaction_id, gateway_options) + def void! subject.void(transaction_id, gateway_options) end end context '.cancel' do - let(:shopify_transaction) { double('shopify_transaction') } - let(:transaction_id) { 1 } - - before do - allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) - end - - it 'calls save on the shopify transaction once' do - expect(shopify_transaction).to receive(:save).once - cancel!(transaction_id) + it 'throws an error because it\'s not implemented' do + expect { cancel! }.to raise_error(NotImplementedError) end private - def cancel!(transaction_id) + def cancel! subject.cancel(transaction_id) end end context '.credit' do - let(:amount) { 48 } - let(:amount_in_cents) { amount * 100 } - let(:shopify_order_id) { 3910455495 } - let(:transaction_id) { 1 } + let(:amount_in_cents) { '100' } - let(:shopify_transaction) do - double('shopify_transaction').tap do |s_t| - allow(s_t).to receive(:amount).and_return(amount) - allow(s_t).to receive(:order_id).and_return(shopify_order_id) - end + it 'calls the provider refund method once' do + expect(provider_class).to receive(:credit).once + refund! end - before do - allow(::ShopifyAPI::Transaction).to receive(:find).and_return(shopify_transaction) - allow(::ShopifyAPI::Refund).to receive(:calculate).and_return(shopify_transaction) - allow(::ShopifyAPI::Refund).to receive(:create).and_return(true) - end - - context 'all line items' do - context 'with a full refund' do - let(:reason) { FactoryGirl.create(:refund_reason) } - # let(:return_item) { build(:return_item, inventory_unit: inventory_unit) } - # let(:customer_return) { build(:customer_return, return_items: [return_item]) } - # let(:reimbursement) { FactoryGirl.create(:reimbursement, refunds: refund) } - - let(:refund) do - refund = Spree::Refund.new - refund.payment = payment - refund.reason = reason - refund.amount = payment.amount - refund.transaction_id = nil - - refund - end - - it 'calls the shopify calculate refund method once' do - expect(::ShopifyAPI::Refund).to receive(:calculate).once - refund!(amount_in_cents, transaction_id, refund) - end + private - it 'calls the shopify calculate create method once' do - expect(::ShopifyAPI::Refund).to receive(:create).once - refund!(amount_in_cents, transaction_id, refund) - end - end + def refund! + subject.credit(amount_in_cents, transaction_id, originator: refund) end end - - private - - def refund!(amount_in_cents, transaction_id, refund) - subject.credit(amount_in_cents, transaction_id, originator: refund) - end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 0e3dec1..72f8644 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -16,7 +16,6 @@ require "database_cleaner" require "braintree" -require "shopify_api" require "ffaker" require "spree/testing_support/factories" From 2fea036fd02ebae030a72ad43fcb2b99575d3166 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Wed, 10 Aug 2016 11:16:48 -0400 Subject: [PATCH 7/9] Pass the proper preferences in order to test the ShopifyGateway This also updates to the latest version of the ActiveMerchant --- .gitignore | 1 + Gemfile | 1 + solidus_gateway.gemspec | 3 +++ spec/models/gateway/shopify_gateway_spec.rb | 3 +++ spec/spec_helper.rb | 1 + 5 files changed, 9 insertions(+) diff --git a/.gitignore b/.gitignore index 094d3e7..202c883 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ Gemfile.lock coverage .ruby-version pkg +.env diff --git a/Gemfile b/Gemfile index f5c9865..36e521c 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ gem "activemerchant", "~> 1.48", "!= 1.58.0", "!= 1.59.0", github: "dynamomtl/ac group :development, :test do gem "pry-rails" + gem "dotenv-rails", require: 'dotenv/rails-now' end gem 'pg' diff --git a/solidus_gateway.gemspec b/solidus_gateway.gemspec index ac49e76..628cca3 100644 --- a/solidus_gateway.gemspec +++ b/solidus_gateway.gemspec @@ -35,4 +35,7 @@ Gem::Specification.new do |s| s.add_development_dependency "capybara" s.add_development_dependency "poltergeist", "~> 1.9" s.add_development_dependency "database_cleaner", "1.2.0" + + s.add_development_dependency "shopify_api", "~> 4.0" + # s.add_development_dependency "dotenv-rails" end diff --git a/spec/models/gateway/shopify_gateway_spec.rb b/spec/models/gateway/shopify_gateway_spec.rb index b3f0f5e..fd297a3 100644 --- a/spec/models/gateway/shopify_gateway_spec.rb +++ b/spec/models/gateway/shopify_gateway_spec.rb @@ -9,6 +9,9 @@ let(:provider_class) { ActiveMerchant::Billing::ShopifyGateway } before do + subject.preferences = { api_key: ENV['SHOPIFY_API_KEY'], + password: ENV['SHOPIFY_PASSWORD'], + shop_name: ENV['SHOPIFY_SHOP_NAME'] } allow(refund).to receive(:pos_order_id).and_return(pos_order_id) end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 72f8644..19d056c 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -17,6 +17,7 @@ require "database_cleaner" require "braintree" require "ffaker" +require "dotenv-rails" require "spree/testing_support/factories" require "spree/testing_support/order_walkthrough" From 589a90f1e4c613dbcdce2390184dc7252857bff7 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Wed, 10 Aug 2016 12:38:13 -0400 Subject: [PATCH 8/9] Change the parameters passed to the provider We don't want to pass the full object, we only want to pass what the provider is required to know, nothing more. Also fix the specs to represent those changes. --- app/models/spree/gateway/shopify_gateway.rb | 4 +++- spec/models/gateway/shopify_gateway_spec.rb | 14 ++++++++++---- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/app/models/spree/gateway/shopify_gateway.rb b/app/models/spree/gateway/shopify_gateway.rb index fccdc0b..ee28fa6 100644 --- a/app/models/spree/gateway/shopify_gateway.rb +++ b/app/models/spree/gateway/shopify_gateway.rb @@ -13,7 +13,9 @@ def method_type end def credit(money, transaction_id, gateway_options) - provider.refund(money, transaction_id, gateway_options) + refund = gateway_options[:originator] + options = { order_id: refund.pos_order_id, reason: refund.reason.name } + provider.refund(money, transaction_id, options) end def void(transaction_id, gateway_options) diff --git a/spec/models/gateway/shopify_gateway_spec.rb b/spec/models/gateway/shopify_gateway_spec.rb index fd297a3..1f0fb10 100644 --- a/spec/models/gateway/shopify_gateway_spec.rb +++ b/spec/models/gateway/shopify_gateway_spec.rb @@ -3,21 +3,23 @@ describe Spree::Gateway::ShopifyGateway do let(:transaction_id) { '0xDEADBEEF' } let(:pos_order_id) { '0xBAADF00D' } - let(:refund) { double('refund') } + let(:refund) { double('refund', pos_order_id: pos_order_id) } + let(:refund_reason) { double('refund_reason', name: 'Product not working') } let(:gateway_options) { { originator: refund } } let(:provider_class) { ActiveMerchant::Billing::ShopifyGateway } + let(:provider_instance) { double('provider', refund: true, void: true) } before do subject.preferences = { api_key: ENV['SHOPIFY_API_KEY'], password: ENV['SHOPIFY_PASSWORD'], shop_name: ENV['SHOPIFY_SHOP_NAME'] } - allow(refund).to receive(:pos_order_id).and_return(pos_order_id) + allow(provider_class).to receive(:new).and_return(provider_instance) end context '.void' do it 'calls the provider void method once' do - expect(provider_class).to receive(:void).once + expect(provider_instance).to receive(:void).once void! end @@ -43,8 +45,12 @@ def cancel! context '.credit' do let(:amount_in_cents) { '100' } + before do + allow(refund).to receive(:reason).and_return(refund_reason) + end + it 'calls the provider refund method once' do - expect(provider_class).to receive(:credit).once + expect(provider_instance).to receive(:refund).once refund! end From d92c845a21ec38dc822c5730e574dafd39bf3ef8 Mon Sep 17 00:00:00 2001 From: Charles-Andre Bouffard Date: Wed, 10 Aug 2016 14:26:18 -0400 Subject: [PATCH 9/9] Throw NotImplementError on method that aren't implemented The methods that are not implemented are methods that will never / not required to be called in our scenarios. --- app/models/spree/gateway/shopify_gateway.rb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/app/models/spree/gateway/shopify_gateway.rb b/app/models/spree/gateway/shopify_gateway.rb index ee28fa6..934f090 100644 --- a/app/models/spree/gateway/shopify_gateway.rb +++ b/app/models/spree/gateway/shopify_gateway.rb @@ -24,8 +24,22 @@ def void(transaction_id, gateway_options) end def cancel(_transaction_id) - # NOTE(cab): I am unsure how we can achieve that, since we are required - # to have the order_id in order to call the Shopify API. + raise NotImplementedError + end + + def purchase(_money, _creditcard, _gateway_options) + raise NotImplementedError + end + + def authorize(_money, _creditcard, _gateway_options) + raise NotImplementedError + end + + def capture(_money, _response_code, _gateway_options) + raise NotImplementedError + end + + def create_profile(_payment) raise NotImplementedError end end