CheckoutController can render payment gateway error messages as json

This commit is contained in:
Rob Harrington
2017-06-14 14:30:19 +10:00
parent 14f6ea4c01
commit 64009a2c9e
6 changed files with 64 additions and 21 deletions

View File

@@ -12,7 +12,7 @@ Darkswarm.factory 'Checkout', ($injector, CurrentOrder, ShippingMethods, StripeJ
submit: =>
Loading.message = t 'submitting_order'
$http.put('/checkout', {order: @preprocess()}).success (data, status)=>
$http.put('/checkout.json', {order: @preprocess()}).success (data, status)=>
Navigation.go data.path
.error (response, status)=>
if response.path

View File

@@ -48,7 +48,7 @@ class CheckoutController < Spree::CheckoutController
format.html do
respond_with(@order, :location => order_path(@order))
end
format.js do
format.json do
render json: {path: order_path(@order)}, status: 200
end
end
@@ -141,7 +141,7 @@ class CheckoutController < Spree::CheckoutController
format.html do
render :edit
end
format.js do
format.json do
render json: {errors: @order.errors, flash: flash.to_hash}.to_json, status: 400
end
end
@@ -222,4 +222,12 @@ class CheckoutController < Spree::CheckoutController
params[:order][:payments_attributes].first.delete :source_attributes
end
end
def rescue_from_spree_gateway_error(error)
flash[:error] = t(:spree_gateway_error_flash_for_checkout, error: error.message)
respond_to do |format|
format.html { render :edit }
format.json { render json: { flash: flash.to_hash }, status: 400 }
end
end
end

View File

@@ -766,6 +766,10 @@ en:
require_login_html: "Please %{login} if you have an account already. Otherwise, %{register} to become a customer."
require_customer_html: "Please %{contact} %{enterprise} to become a customer."
# Front-end controller translations
spree_gateway_error_flash_for_checkout: "There was a problem with your payment information: %{error}"
# Printable Invoice Columns
invoice_billing_address: "Billing address:"
invoice_column_tax: "GST"

View File

@@ -69,14 +69,14 @@ describe CheckoutController do
it "clears the ship address when re-rendering edit" do
controller.should_receive(:clear_ship_address).and_return true
order.stub(:update_attributes).and_return false
spree_post :update, order: {}
spree_post :update, format: :json, order: {}
end
it "clears the ship address when the order state cannot be advanced" do
controller.should_receive(:clear_ship_address).and_return true
order.stub(:update_attributes).and_return true
order.stub(:next).and_return false
spree_post :update, order: {}
spree_post :update, format: :json, order: {}
end
it "only clears the ship address with a pickup shipping method" do
@@ -133,7 +133,7 @@ describe CheckoutController do
end
it "returns errors" do
xhr :post, :update, order: {}, use_route: :spree
spree_post :update, format: :json, order: {}
response.status.should == 400
response.body.should == {errors: assigns[:order].errors, flash: {}}.to_json
end
@@ -141,7 +141,7 @@ describe CheckoutController do
it "returns flash" do
order.stub(:update_attributes).and_return true
order.stub(:next).and_return false
xhr :post, :update, order: {}, use_route: :spree
spree_post :update, format: :json, order: {}
response.body.should == {errors: assigns[:order].errors, flash: {error: "Payment could not be processed, please check the details you entered"}}.to_json
end
@@ -152,7 +152,7 @@ describe CheckoutController do
order.stub(:update_attributes).and_return true
order.stub(:state).and_return "complete"
xhr :post, :update, order: {}, use_route: :spree
spree_post :update, format: :json, order: {}
response.status.should == 200
response.body.should == {path: spree.order_path(order)}.to_json
end
@@ -173,7 +173,7 @@ describe CheckoutController do
true
end
xhr :post, :update, order: {}, use_route: :spree
spree_post :update, format: :json, order: {}
response.status.should == 200
end
@@ -181,7 +181,7 @@ describe CheckoutController do
order.stub(:update_attributes).and_return true
order.stub(:next) { raise ActiveRecord::StaleObjectError.new(Spree::Variant.new, 'update') }
xhr :post, :update, order: {}, use_route: :spree
spree_post :update, format: :json, order: {}
response.status.should == 400
end
end

View File

@@ -91,27 +91,27 @@ describe 'Checkout service', ->
describe "submitting", ->
it "Posts the Checkout to the server", ->
$httpBackend.expectPUT("/checkout", {order: Checkout.preprocess()}).respond 200, {path: "test"}
$httpBackend.expectPUT("/checkout.json", {order: Checkout.preprocess()}).respond 200, {path: "test"}
Checkout.submit()
$httpBackend.flush()
describe "when there is an error", ->
it "redirects when a redirect is given", ->
$httpBackend.expectPUT("/checkout").respond 400, {path: 'path'}
$httpBackend.expectPUT("/checkout.json").respond 400, {path: 'path'}
Checkout.submit()
$httpBackend.flush()
expect(Navigation.go).toHaveBeenCalledWith 'path'
it "sends flash messages to the flash service", ->
spyOn(FlashLoaderMock, "loadFlash") # Stubbing out writes to window.location
$httpBackend.expectPUT("/checkout").respond 400, {flash: {error: "frogs"}}
$httpBackend.expectPUT("/checkout.json").respond 400, {flash: {error: "frogs"}}
Checkout.submit()
$httpBackend.flush()
expect(FlashLoaderMock.loadFlash).toHaveBeenCalledWith {error: "frogs"}
it "puts errors into the scope", ->
$httpBackend.expectPUT("/checkout").respond 400, {errors: {error: "frogs"}}
$httpBackend.expectPUT("/checkout.json").respond 400, {errors: {error: "frogs"}}
Checkout.submit()
$httpBackend.flush()
expect(Checkout.errors).toEqual {error: "frogs"}

View File

@@ -14,7 +14,7 @@ describe "Submitting Stripe Connect charge requests", type: :request do
let!(:order) { line_item.order }
let(:address) { create(:address) }
let(:token) { "token123" }
let(:params) { { order: {
let(:params) { { format: :json, order: {
shipping_method_id: shipping_method.id,
payments_attributes: [{payment_method_id: payment_method.id, source_attributes: { gateway_payment_profile_id: token, cc_type: "visa", last_digits: "4242", month: 10, year: 2025 }}],
bill_address_attributes: address.attributes.slice("firstname","lastname","address1","address2","phone","city","zipcode","state_id","country_id"),
@@ -33,12 +33,12 @@ describe "Submitting Stripe Connect charge requests", type: :request do
# Saves the card against the user
stub_request(:post, "https://sk_test_123456:@api.stripe.com/v1/customers")
.with(:body => { card: token, email: order.email})
.to_return(status: 200, body: JSON.generate({ id: "cus_A123", default_card: "card_XyZ456", sources: { data: [{id: "1"}] } }), headers: {})
.to_return(status: 200, body: JSON.generate(store_response_mock))
# Requests a token from the newly saved card
stub_request(:post, "https://api.stripe.com/v1/tokens")
.with(:body => { card: "card_XyZ456", customer: "cus_A123"})
.to_return(status: 200, body: JSON.generate({id: "newtoken_123"}), headers: {})
.to_return(status: 200, body: JSON.generate({id: "newtoken_123"}))
# Charges the card
stub_request(:post, "https://sk_test_123456:@api.stripe.com/v1/charges")
@@ -46,12 +46,14 @@ describe "Submitting Stripe Connect charge requests", type: :request do
.to_return(body: JSON.generate(charge_response_mock))
end
context "and the charge request is accepted" do
context "and the store and charge requests are accepted" do
let(:store_response_mock) { { id: "cus_A123", default_card: "card_XyZ456", sources: { data: [{id: "1"}] } } }
let(:charge_response_mock) { { id: "ch_1234", object: "charge", amount: 2000} }
it "should process the payment, and stores the card/customer details" do
put update_checkout_path, params
expect(response).to redirect_to(spree.order_path(order))
json_response = JSON.parse(response.body)
expect(json_response["path"]).to eq spree.order_path(order)
expect(order.payments.completed.count).to be 1
card = order.payments.completed.first.source
expect(card.gateway_customer_profile_id).to eq "cus_A123"
@@ -59,12 +61,28 @@ describe "Submitting Stripe Connect charge requests", type: :request do
end
end
context "when the store request returns an error message" do
let(:store_response_mock) { { error: { message: "Bup-bow..."} } }
let(:charge_response_mock) { { id: "ch_1234", object: "charge", amount: 2000} }
it "should not process the payment" do
put update_checkout_path, params
expect(response.status).to be 400
json_response = JSON.parse(response.body)
expect(json_response["flash"]["error"]).to eq I18n.t(:spree_gateway_error_flash_for_checkout, error: 'Bup-bow...')
expect(order.payments.completed.count).to be 0
end
end
context "when the charge request returns an error message" do
let(:store_response_mock) { { id: "cus_A123", default_card: "card_XyZ456", sources: { data: [{id: "1"}] } } }
let(:charge_response_mock) { { error: { message: "Bup-bow..."} } }
it "should not process the payment" do
put update_checkout_path, params
expect(response).to render_template(:edit)
expect(response.status).to be 400
json_response = JSON.parse(response.body)
expect(json_response["flash"]["error"]).to eq I18n.t(:payment_processing_failed)
expect(order.payments.completed.count).to be 0
end
end
@@ -98,12 +116,25 @@ describe "Submitting Stripe Connect charge requests", type: :request do
it "should process the payment, and keep the profile ids" do
put update_checkout_path, params
expect(response).to redirect_to(spree.order_path(order))
json_response = JSON.parse(response.body)
expect(json_response["path"]).to eq spree.order_path(order)
expect(order.payments.completed.count).to be 1
card = order.payments.completed.first.source
expect(card.gateway_customer_profile_id).to eq "cus_Z456"
expect(card.gateway_payment_profile_id).to eq "card_AbC123"
end
end
context "when the charge request returns an error message" do
let(:charge_response_mock) { { error: { message: "Bup-bow..."} } }
it "should not process the payment" do
put update_checkout_path, params
expect(response.status).to be 400
json_response = JSON.parse(response.body)
expect(json_response["flash"]["error"]).to eq I18n.t(:payment_processing_failed)
expect(order.payments.completed.count).to be 0
end
end
end
end