From 6efad74c5c7ed4937f8b7b111ff92f1b6522e3a0 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Wed, 3 Feb 2021 13:32:27 -0800 Subject: [PATCH 1/7] add authorize link to transactions page --- app/serializers/api/order_serializer.rb | 2 +- app/serializers/api/payment_serializer.rb | 2 +- app/views/spree/users/_fat.html.haml | 2 ++ config/locales/en.yml | 1 + 4 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/serializers/api/order_serializer.rb b/app/serializers/api/order_serializer.rb index 958187a0b5..14b7eca32e 100644 --- a/app/serializers/api/order_serializer.rb +++ b/app/serializers/api/order_serializer.rb @@ -16,7 +16,7 @@ module Api end def payments - object.payments.joins(:payment_method).completed + object.payments.joins(:payment_method).valid end def shop_id diff --git a/app/serializers/api/payment_serializer.rb b/app/serializers/api/payment_serializer.rb index 7172e21f12..033803faf9 100644 --- a/app/serializers/api/payment_serializer.rb +++ b/app/serializers/api/payment_serializer.rb @@ -1,6 +1,6 @@ module Api class PaymentSerializer < ActiveModel::Serializer - attributes :amount, :updated_at, :payment_method, :state + attributes :amount, :updated_at, :payment_method, :state, :cvv_response_message def payment_method object.payment_method.try(:name) diff --git a/app/views/spree/users/_fat.html.haml b/app/views/spree/users/_fat.html.haml index dfbcfade38..56439d0e19 100644 --- a/app/views/spree/users/_fat.html.haml +++ b/app/views/spree/users/_fat.html.haml @@ -16,6 +16,8 @@ %td.order3.show-for-large-up %i{"ng-class" => "{'ofn-i_012-warning': payment.state == 'invalid' || payment.state == 'void' || payment.state == 'failed'}"} %span{"ng-bind" => "::'spree.payment_states.' + payment.state | t | capitalize"} + %span{"ng-if" => "payment.cvv_response_message.length > 0" } + %a{"ng-href" => "{{payment.cvv_response_message}}", "ng-bind" => "::'spree.payment_states.authorise' | t | capitalize" } %td.order4.show-for-large-up %td.order5.text-right{"ng-class" => "{'credit' : payment.amount > 0, 'debit' : payment.amount < 0, 'paid' : payment.amount == 0}","ng-bind" => "::payment.amount | localizeCurrency"} %td.order6.show-for-large-up diff --git a/config/locales/en.yml b/config/locales/en.yml index 4237d739f1..a86df86873 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3620,6 +3620,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using processing: processing void: void invalid: invalid + authorise: authorise order_mailer: cancel_email: customer_greeting: "Dear %{name}," From 8c7bf863f89db50678f49a5c274fc7ab42f04e4e Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Fri, 5 Feb 2021 10:45:10 -0800 Subject: [PATCH 2/7] return pending payments in order serializer --- app/serializers/api/order_serializer.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/serializers/api/order_serializer.rb b/app/serializers/api/order_serializer.rb index 14b7eca32e..f5e9b001d8 100644 --- a/app/serializers/api/order_serializer.rb +++ b/app/serializers/api/order_serializer.rb @@ -16,7 +16,7 @@ module Api end def payments - object.payments.joins(:payment_method).valid + object.payments.joins(:payment_method).where('state IN (?)', %w(completed pending)) end def shop_id From cd2b4d2fb237f827a8f9acd1cc6080363ddb1a14 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Fri, 12 Feb 2021 13:36:04 -0800 Subject: [PATCH 3/7] advance order after processing payment intent --- app/services/process_payment_intent.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/services/process_payment_intent.rb b/app/services/process_payment_intent.rb index 4f2aeec7df..218d1eeff3 100644 --- a/app/services/process_payment_intent.rb +++ b/app/services/process_payment_intent.rb @@ -11,7 +11,8 @@ class ProcessPaymentIntent return unless valid? last_payment.update_attribute(:cvv_response_message, nil) - last_payment.complete! + OrderWorkflow.new(@order).next + last_payment.complete! if !last_payment.completed? end private From c851705d5a6160f9c77249d5a747d41587fc8151 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Fri, 12 Feb 2021 13:36:17 -0800 Subject: [PATCH 4/7] reload order's new state after processing payment --- app/controllers/spree/orders_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/spree/orders_controller.rb b/app/controllers/spree/orders_controller.rb index 40c315400c..a25f43b1a5 100644 --- a/app/controllers/spree/orders_controller.rb +++ b/app/controllers/spree/orders_controller.rb @@ -27,6 +27,7 @@ module Spree def show @order = Spree::Order.find_by!(number: params[:id]) ProcessPaymentIntent.new(params["payment_intent"], @order).call! + @order.reload end def empty From 77a3649e500b6804b5cc84c3c5fe286d9764048d Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Fri, 12 Feb 2021 13:41:35 -0800 Subject: [PATCH 5/7] documentation --- app/services/process_payment_intent.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/services/process_payment_intent.rb b/app/services/process_payment_intent.rb index 218d1eeff3..5c5085cb55 100644 --- a/app/services/process_payment_intent.rb +++ b/app/services/process_payment_intent.rb @@ -1,5 +1,13 @@ # frozen_string_literal: true +# When directing a customer to Stripe to authorize the payment, we specify a +# redirect_url that Stripe should return them to. When checking out, it's +# /checkout; for admin payments and subscription payemnts it's the order url. +# This class confirms that the payment intent matches what's in our database, +# marks the payment as complete, and removes the cvv_response_message field, +# which we use to indicate that authorization is required. It also completes the +# Order, if appropriate. + class ProcessPaymentIntent def initialize(payment_intent, order) @payment_intent = payment_intent From 05e762ff2151c0fd5406f000a8ba3795f28fe7d3 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Mon, 15 Feb 2021 17:09:38 -0800 Subject: [PATCH 6/7] add controller specs for confirming payment intent --- .../spree/orders_controller_spec.rb | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/spec/controllers/spree/orders_controller_spec.rb b/spec/controllers/spree/orders_controller_spec.rb index 64102934ad..dcc25c2a00 100644 --- a/spec/controllers/spree/orders_controller_spec.rb +++ b/spec/controllers/spree/orders_controller_spec.rb @@ -79,6 +79,50 @@ describe Spree::OrdersController, type: :controller do end end + describe "confirming a payment intent" do + let(:customer) { create(:customer) } + let(:order) { create(:order, customer: customer, distributor: customer.enterprise) } + let!(:payment) { create( + :payment, + cvv_response_message: "https://stripe.com/redirect", + response_code: "pi_123", + order: order, + state: "pending") + } + + before do + allow(controller).to receive(:spree_current_user) { current_user } + end + + context "after returning from Stripe to authorize a payment" do + let(:current_user) { order.user } + + context "with a valid payment intent" do + let(:payment_intent) { "pi_123" } + + it "completes the payment" do + get :show, id: order.number, payment_intent: payment_intent + expect(response).to be_success + payment.reload + expect(payment.cvv_response_message).to be nil + expect(payment.state).to eq("completed") + end + end + + context "with an invalid payment intent" do + let(:payment_intent) { "invalid" } + + it "does not complete the payment" do + get :show, id: order.number, payment_intent: payment_intent + expect(response).to be_success + payment.reload + expect(payment.cvv_response_message).to eq("https://stripe.com/redirect") + expect(payment.state).to eq("pending") + end + end + end + end + describe "viewing cart" do it "redirects home when no distributor is selected" do get :edit From 560ad49057384d0acdd9eda5abf68d0ccbe67f44 Mon Sep 17 00:00:00 2001 From: Andy Brett Date: Mon, 15 Feb 2021 18:02:47 -0800 Subject: [PATCH 7/7] unit tests for ProcessPaymentIntent --- spec/services/process_payment_intent_spec.rb | 51 ++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 spec/services/process_payment_intent_spec.rb diff --git a/spec/services/process_payment_intent_spec.rb b/spec/services/process_payment_intent_spec.rb new file mode 100644 index 0000000000..fdb906c2ea --- /dev/null +++ b/spec/services/process_payment_intent_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe ProcessPaymentIntent do + let(:service) { described_class.new } + + describe "processing a payment intent" do + let(:customer) { create(:customer) } + let(:order) { create(:order, customer: customer, distributor: customer.enterprise, state: "payment") } + let!(:payment) { create( + :payment, + cvv_response_message: "https://stripe.com/redirect", + response_code: "pi_123", + order: order, + state: "pending") + } + + context "an invalid intent" do + let(:invalid_intent) { "invalid" } + let(:service) { ProcessPaymentIntent.new(invalid_intent, order) } + + it "does not complete the payment" do + service.call! + expect(payment.reload.state).to eq("pending") + end + end + + context "a valid intent" do + let(:valid_intent) { "pi_123" } + let(:service) { ProcessPaymentIntent.new(valid_intent, order) } + + before do + allow(order).to receive(:deliver_order_confirmation_email) + end + + it "completes the payment" do + service.call! + payment.reload + expect(payment.state).to eq("completed") + expect(payment.cvv_response_message).to be nil + end + + it "completes the order" do + service.call! + expect(order.state).to eq("complete") + expect(order).to have_received(:deliver_order_confirmation_email) + end + end + end +end