mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Merge pull request #7769 from Matt-Yorkley/payment-status-checking
Stripe: payment status debugging
This commit is contained in:
@@ -144,8 +144,7 @@ module Spree
|
||||
payment = fetch_payment(creditcard, gateway_options)
|
||||
raise Stripe::StripeError, I18n.t(:no_pending_payments) unless payment&.response_code
|
||||
|
||||
payment_intent_response = Stripe::PaymentIntentValidator.new.
|
||||
call(payment.response_code, stripe_account_id)
|
||||
payment_intent_response = Stripe::PaymentIntentValidator.new(payment).call
|
||||
|
||||
raise_if_not_in_capture_state(payment_intent_response)
|
||||
|
||||
|
||||
@@ -69,16 +69,6 @@ class ProcessPaymentIntent
|
||||
end
|
||||
|
||||
def payment_intent_status
|
||||
@payment_intent_status ||= Stripe::PaymentIntentValidator.new.
|
||||
call(payment_intent, stripe_account_id).
|
||||
status
|
||||
end
|
||||
|
||||
def stripe_account_id
|
||||
StripeAccount.find_by(enterprise_id: preferred_enterprise_id).stripe_user_id
|
||||
end
|
||||
|
||||
def preferred_enterprise_id
|
||||
payment.payment_method.preferred_enterprise_id
|
||||
@payment_intent_status ||= Stripe::PaymentIntentValidator.new(payment).call.status
|
||||
end
|
||||
end
|
||||
|
||||
32
app/services/stripe_payment_status.rb
Normal file
32
app/services/stripe_payment_status.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class StripePaymentStatus
|
||||
def initialize(payment)
|
||||
@payment = payment
|
||||
end
|
||||
|
||||
# Returns the current payment status from a live call to the Stripe API.
|
||||
# Returns nil if the payment is not a Stripe payment or does not have a payment intent.
|
||||
# If the payment requires authorization the status will be "requires_action".
|
||||
# If the payment has been captured the status will be "succeeded".
|
||||
# Docs: https://stripe.com/docs/api/payment_intents/object#payment_intent_object-status
|
||||
def stripe_status
|
||||
return if payment.response_code.blank?
|
||||
|
||||
Stripe::PaymentIntentValidator.new(payment).call.status
|
||||
rescue Stripe::StripeError
|
||||
# Stripe::PaymentIntentValidator will raise an error if the response from the Stripe API
|
||||
# call indicates the last attempted action on the payment intent failed.
|
||||
"failed"
|
||||
end
|
||||
|
||||
# If the payment is a Stripe payment and has been captured in the associated Stripe account,
|
||||
# returns true, otherwise false.
|
||||
def stripe_captured?
|
||||
stripe_status == "succeeded"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :payment
|
||||
end
|
||||
@@ -3,9 +3,15 @@
|
||||
# This class validates if a given payment intent ID is valid in Stripe
|
||||
module Stripe
|
||||
class PaymentIntentValidator
|
||||
def call(payment_intent_id, stripe_account_id)
|
||||
payment_intent_response = Stripe::PaymentIntent.retrieve(payment_intent_id,
|
||||
stripe_account: stripe_account_id)
|
||||
def initialize(payment)
|
||||
@payment = payment
|
||||
end
|
||||
|
||||
def call
|
||||
payment_intent_response = Stripe::PaymentIntent.retrieve(
|
||||
payment_intent_id,
|
||||
stripe_account: stripe_account_id
|
||||
)
|
||||
|
||||
raise_if_last_payment_error_present(payment_intent_response)
|
||||
|
||||
@@ -14,6 +20,18 @@ module Stripe
|
||||
|
||||
private
|
||||
|
||||
attr_accessor :payment
|
||||
|
||||
def payment_intent_id
|
||||
payment.response_code
|
||||
end
|
||||
|
||||
def stripe_account_id
|
||||
enterprise_id = payment.payment_method&.preferred_enterprise_id
|
||||
|
||||
StripeAccount.find_by(enterprise_id: enterprise_id)&.stripe_user_id
|
||||
end
|
||||
|
||||
def raise_if_last_payment_error_present(payment_intent_response)
|
||||
return unless payment_intent_response.respond_to?(:last_payment_error) &&
|
||||
payment_intent_response.last_payment_error.present?
|
||||
|
||||
@@ -113,9 +113,8 @@ describe Spree::OrdersController, type: :controller do
|
||||
let(:payment_intent_response) { double(id: "pi_123", status: "requires_capture") }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Stripe::PaymentIntentValidator)
|
||||
.to receive(:call)
|
||||
.with(payment_intent, kind_of(String))
|
||||
allow(Stripe::PaymentIntentValidator)
|
||||
.to receive_message_chain(:new, :call)
|
||||
.and_return(payment_intent_response)
|
||||
|
||||
allow(Spree::Order).to receive(:find_by!) { order }
|
||||
@@ -159,9 +158,8 @@ describe Spree::OrdersController, type: :controller do
|
||||
let(:payment_intent) { "pi_123" }
|
||||
|
||||
before do
|
||||
allow_any_instance_of(Stripe::PaymentIntentValidator)
|
||||
.to receive(:call)
|
||||
.with(payment_intent, kind_of(String))
|
||||
allow(Stripe::PaymentIntentValidator)
|
||||
.to receive_message_chain(:new, :call)
|
||||
.and_raise(Stripe::StripeError, "error message")
|
||||
end
|
||||
|
||||
@@ -183,9 +181,8 @@ describe Spree::OrdersController, type: :controller do
|
||||
before do
|
||||
allow(payment).to receive(:response_code).and_return("invalid")
|
||||
allow(OrderPaymentFinder).to receive(:new).with(order).and_return(finder)
|
||||
allow_any_instance_of(Stripe::PaymentIntentValidator)
|
||||
.to receive(:call)
|
||||
.with(payment_intent, kind_of(String))
|
||||
allow(Stripe::PaymentIntentValidator)
|
||||
.to receive_message_chain(:new, :call)
|
||||
.and_return(payment_intent)
|
||||
stub_payment_intent_get_request(payment_intent_id: "valid")
|
||||
end
|
||||
|
||||
@@ -6,14 +6,19 @@ require 'stripe/payment_intent_validator'
|
||||
module Stripe
|
||||
describe PaymentIntentValidator do
|
||||
describe "#call" do
|
||||
let(:validator) { Stripe::PaymentIntentValidator.new }
|
||||
let(:validator) { Stripe::PaymentIntentValidator.new(payment) }
|
||||
let(:payment) { build(:payment, response_code: payment_intent_id) }
|
||||
let(:payment_intent_id) { "pi_123" }
|
||||
let(:stripe_account_id) { "abc123" }
|
||||
let(:stripe_account_mock) { double(stripe_user_id: stripe_account_id) }
|
||||
let(:payment_intent_response_mock) { { status: 200, body: payment_intent_response_body } }
|
||||
|
||||
before do
|
||||
Stripe.api_key = "sk_test_12345"
|
||||
|
||||
allow(payment).to receive_message_chain(:payment_method, :preferred_enterprise_id) { 1 }
|
||||
allow(StripeAccount).to receive(:find_by) { stripe_account_mock }
|
||||
|
||||
stub_request(:get, "https://api.stripe.com/v1/payment_intents/#{payment_intent_id}")
|
||||
.with(headers: { 'Stripe-Account' => stripe_account_id })
|
||||
.to_return(payment_intent_response_mock)
|
||||
@@ -26,7 +31,7 @@ module Stripe
|
||||
|
||||
it "returns payment intent id and does not raise" do
|
||||
expect {
|
||||
result = validator.call(payment_intent_id, stripe_account_id)
|
||||
result = validator.call
|
||||
expect(result).to eq payment_intent_response_body
|
||||
}.to_not raise_error Stripe::StripeError
|
||||
end
|
||||
@@ -39,7 +44,7 @@ module Stripe
|
||||
|
||||
it "raises Stripe error with payment intent last_payment_error as message" do
|
||||
expect {
|
||||
validator.call(payment_intent_id, stripe_account_id)
|
||||
validator.call
|
||||
}.to raise_error Stripe::StripeError, "No money"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -51,9 +51,8 @@ describe ProcessPaymentIntent do
|
||||
|
||||
context "where the stripe payment intent validation responds with errors" do
|
||||
before do
|
||||
allow(validator)
|
||||
.to receive(:call).with(intent, anything).and_raise(Stripe::StripeError,
|
||||
"error message")
|
||||
allow(validator).to receive(:call).
|
||||
and_raise(Stripe::StripeError, "error message")
|
||||
end
|
||||
|
||||
it "returns returns the error message" do
|
||||
@@ -77,7 +76,7 @@ describe ProcessPaymentIntent do
|
||||
|
||||
before do
|
||||
allow(order).to receive(:deliver_order_confirmation_email)
|
||||
allow(validator).to receive(:call).with(intent, anything).and_return(intent_response)
|
||||
allow(validator).to receive(:call).and_return(intent_response)
|
||||
end
|
||||
|
||||
it "validates the intent" do
|
||||
@@ -143,7 +142,7 @@ describe ProcessPaymentIntent do
|
||||
|
||||
before do
|
||||
payment.update_attribute(:state, "failed")
|
||||
allow(validator).to receive(:call).with(intent, anything).and_return(intent)
|
||||
allow(validator).to receive(:call).and_return(intent)
|
||||
end
|
||||
|
||||
it "does not return any error message" do
|
||||
@@ -166,7 +165,7 @@ describe ProcessPaymentIntent do
|
||||
|
||||
before do
|
||||
allow(order).to receive(:process_payments!) { nil }
|
||||
allow(validator).to receive(:call).with(intent, anything).and_return(intent_response)
|
||||
allow(validator).to receive(:call).and_return(intent_response)
|
||||
end
|
||||
|
||||
it "returns a failed result" do
|
||||
|
||||
55
spec/services/stripe_payment_status_spec.rb
Normal file
55
spec/services/stripe_payment_status_spec.rb
Normal file
@@ -0,0 +1,55 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
describe StripePaymentStatus do
|
||||
subject { StripePaymentStatus.new(payment) }
|
||||
let(:payment) { build(:payment) }
|
||||
|
||||
describe '#stripe_status' do
|
||||
context "when the payment is not a Stripe payment or does not have a payment intent" do
|
||||
it "returns nil" do
|
||||
expect(subject.stripe_status).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
context "when the payment has a payment intent" do
|
||||
before { allow(payment).to receive(:response_code) { "pi_1234" } }
|
||||
|
||||
it "fetches the status with Stripe::PaymentIntentValidator" do
|
||||
expect(Stripe::PaymentIntentValidator).
|
||||
to receive_message_chain(:new, :call, :status) { true }
|
||||
|
||||
subject.stripe_status
|
||||
end
|
||||
|
||||
context "and the last action on the Stripe payment failed" do
|
||||
it "returns failed response" do
|
||||
allow(Stripe::PaymentIntentValidator).
|
||||
to receive_message_chain(:new, :call, :status).and_raise(Stripe::StripeError)
|
||||
|
||||
expect(subject.stripe_status).to eq "failed"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#stripe_captured?' do
|
||||
context "when the payment is not a Stripe payment or does not have a payment intent" do
|
||||
it "returns false" do
|
||||
expect(subject.stripe_captured?).to eq false
|
||||
end
|
||||
end
|
||||
|
||||
context "when the Stripe payment has been captured" do
|
||||
before { allow(payment).to receive(:response_code) { "pi_1234" } }
|
||||
|
||||
it "returns true" do
|
||||
allow(Stripe::PaymentIntentValidator).
|
||||
to receive_message_chain(:new, :call, :status) { "succeeded" }
|
||||
|
||||
expect(subject.stripe_captured?).to eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user