diff --git a/api/app/controllers/spree/api/checkouts_controller.rb b/api/app/controllers/spree/api/checkouts_controller.rb index 5d4da3009c5..7c73c70bd83 100644 --- a/api/app/controllers/spree/api/checkouts_controller.rb +++ b/api/app/controllers/spree/api/checkouts_controller.rb @@ -114,6 +114,7 @@ def state_callback(before_or_after = :before) def after_update_attributes if params[:order] && params[:order][:coupon_code].present? + Spree::Deprecation.warn('This method is deprecated. Please use `Spree::Api::CouponCodesController#create` endpoint instead.') handler = PromotionHandler::Coupon.new(@order) handler.apply diff --git a/api/app/controllers/spree/api/coupon_codes_controller.rb b/api/app/controllers/spree/api/coupon_codes_controller.rb new file mode 100644 index 00000000000..114e9c88f01 --- /dev/null +++ b/api/app/controllers/spree/api/coupon_codes_controller.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Spree + module Api + class CouponCodesController < Spree::Api::BaseController + before_action :load_order, only: :create + around_action :lock_order, only: :create + + def create + authorize! :update, @order, order_token + + @order.coupon_code = params[:coupon_code] + @handler = PromotionHandler::Coupon.new(@order).apply + + if @handler.successful? + render 'spree/api/promotions/handler', status: 200 + else + logger.error("apply_coupon_code_error=#{@handler.error.inspect}") + render 'spree/api/promotions/handler', status: 422 + end + end + + private + + def load_order + @order = Spree::Order.find_by!(number: params[:order_id]) + end + end + end +end diff --git a/api/app/controllers/spree/api/orders_controller.rb b/api/app/controllers/spree/api/orders_controller.rb index af748c39b3d..9433132ef59 100644 --- a/api/app/controllers/spree/api/orders_controller.rb +++ b/api/app/controllers/spree/api/orders_controller.rb @@ -92,6 +92,8 @@ def mine end def apply_coupon_code + Spree::Deprecation.warn('This method is deprecated. Please use `Spree::Api::CouponCodesController#create` endpoint instead.') + authorize! :update, @order, order_token @order.coupon_code = params[:coupon_code] @handler = PromotionHandler::Coupon.new(@order).apply diff --git a/api/config/routes.rb b/api/config/routes.rb index ea13cfefdd0..b533b3b9a41 100644 --- a/api/config/routes.rb +++ b/api/config/routes.rb @@ -67,6 +67,8 @@ put :empty put :apply_coupon_code end + + resources :coupon_codes, only: :create end resources :zones diff --git a/api/spec/features/checkout_spec.rb b/api/spec/features/checkout_spec.rb index eb9ece34eac..8762768bc80 100644 --- a/api/spec/features/checkout_spec.rb +++ b/api/spec/features/checkout_spec.rb @@ -62,7 +62,7 @@ def create_line_item(variant, quantity = 1) def add_promotion(_promotion) expect { - put "/api/orders/#{@order.number}/apply_coupon_code", + post "/api/orders/#{@order.number}/coupon_codes", params: { coupon_code: promotion_code.value } }.to change { @order.promotions.count }.by 1 expect(response).to have_http_status(:ok) diff --git a/api/spec/requests/spree/api/checkouts_controller_spec.rb b/api/spec/requests/spree/api/checkouts_controller_spec.rb index 1252108c21c..530d2bdd884 100644 --- a/api/spec/requests/spree/api/checkouts_controller_spec.rb +++ b/api/spec/requests/spree/api/checkouts_controller_spec.rb @@ -357,6 +357,7 @@ module Spree end it "can apply a coupon code to an order" do + expect(Spree::Deprecation).to receive(:warn) order.update_column(:state, "payment") expect(PromotionHandler::Coupon).to receive(:new).with(order).and_call_original expect_any_instance_of(PromotionHandler::Coupon).to receive(:apply).and_return({ coupon_applied?: true }) @@ -365,6 +366,7 @@ module Spree end it "renders error failing to apply coupon" do + expect(Spree::Deprecation).to receive(:warn) order.update_column(:state, "payment") put spree.api_checkout_path(order.to_param), params: { order_token: order.guest_token, order: { coupon_code: "foobar" } } expect(response.status).to eq(422) diff --git a/api/spec/requests/spree/api/coupon_codes_controller_spec.rb b/api/spec/requests/spree/api/coupon_codes_controller_spec.rb new file mode 100644 index 00000000000..ed85fb8bc9d --- /dev/null +++ b/api/spec/requests/spree/api/coupon_codes_controller_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'spec_helper' + +module Spree + describe Api::CouponCodesController, type: :request do + let(:current_api_user) do + user = Spree.user_class.new(email: "spree@example.com") + user.generate_spree_api_key! + user + end + + before do + stub_authentication! + end + + describe '#create' do + let(:promo) { create(:promotion_with_item_adjustment, code: 'night_melody') } + let(:promo_code) { promo.codes.first } + + before do + allow_any_instance_of(Order).to receive_messages user: current_api_user + end + + context 'when successful' do + let(:order) { create(:order_with_line_items) } + + it 'applies the coupon' do + post spree.api_order_coupon_codes_path(order), params: { coupon_code: promo_code.value } + + expect(response.status).to eq(200) + expect(order.reload.promotions).to eq([promo]) + expect(json_response).to eq({ + "success" => I18n.t('spree.coupon_code_applied'), + "error" => nil, + "successful" => true, + "status_code" => "coupon_code_applied" + }) + end + end + + context 'when unsuccessful' do + let(:order) { create(:order) } + + it 'returns an error' do + post spree.api_order_coupon_codes_path(order), params: { coupon_code: promo_code.value } + + expect(response.status).to eq(422) + expect(order.reload.promotions).to eq([]) + expect(json_response).to eq({ + "success" => nil, + "error" => I18n.t('spree.coupon_code_unknown_error'), + "successful" => false, + "status_code" => "coupon_code_unknown_error" + }) + end + end + end + end +end diff --git a/api/spec/requests/spree/api/orders_controller_spec.rb b/api/spec/requests/spree/api/orders_controller_spec.rb index 3ee865775b6..8bb39cdb5ba 100644 --- a/api/spec/requests/spree/api/orders_controller_spec.rb +++ b/api/spec/requests/spree/api/orders_controller_spec.rb @@ -854,6 +854,8 @@ module Spree let(:order) { create(:order_with_line_items) } it 'applies the coupon' do + expect(Spree::Deprecation).to receive(:warn) + put spree.apply_coupon_code_api_order_path(order), params: { coupon_code: promo_code.value } expect(response.status).to eq 200 @@ -871,6 +873,8 @@ module Spree let(:order) { create(:order) } # no line items to apply the code to it 'returns an error' do + expect(Spree::Deprecation).to receive(:warn) + put spree.apply_coupon_code_api_order_path(order), params: { coupon_code: promo_code.value } expect(response.status).to eq 422 diff --git a/api/spec/requests/spree/api/promotion_application_spec.rb b/api/spec/requests/spree/api/promotion_application_spec.rb index ebf99cf2089..9a84c87b606 100644 --- a/api/spec/requests/spree/api/promotion_application_spec.rb +++ b/api/spec/requests/spree/api/promotion_application_spec.rb @@ -20,7 +20,7 @@ module Spree::Api it "can apply a coupon code to the order" do expect(order.total).to eq(110.00) - put spree.apply_coupon_code_api_order_path(order), params: { coupon_code: "10off", order_token: order.guest_token } + post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } expect(response.status).to eq(200) expect(order.reload.total).to eq(109.00) expect(json_response["success"]).to eq("The coupon code was successfully applied to your order.") @@ -37,7 +37,7 @@ module Spree::Api end it "fails to apply" do - put spree.apply_coupon_code_api_order_path(order), params: { coupon_code: "10off", order_token: order.guest_token } + post spree.api_order_coupon_codes_path(order), params: { coupon_code: "10off", order_token: order.guest_token } expect(response.status).to eq(422) expect(json_response["success"]).to be_blank expect(json_response["error"]).to eq("The coupon code is expired") diff --git a/backend/app/assets/javascripts/spree/backend/adjustments.js b/backend/app/assets/javascripts/spree/backend/adjustments.js index 6716b2a5f3d..06bf456af53 100644 --- a/backend/app/assets/javascripts/spree/backend/adjustments.js +++ b/backend/app/assets/javascripts/spree/backend/adjustments.js @@ -5,7 +5,7 @@ Spree.ready(function() { } Spree.ajax({ - type: 'PUT', + type: 'POST', url: Spree.routes.apply_coupon_code(window.order_number), data: { coupon_code: $("#coupon_code").val(), diff --git a/core/app/assets/javascripts/spree.js.erb b/core/app/assets/javascripts/spree.js.erb index 1d0d036d958..9b4d5a0ef3d 100644 --- a/core/app/assets/javascripts/spree.js.erb +++ b/core/app/assets/javascripts/spree.js.erb @@ -54,7 +54,7 @@ Spree.ajax = function(url, options) { Spree.routes = { states_search: Spree.pathFor('api/states'), apply_coupon_code: function(order_id) { - return Spree.pathFor("api/orders/" + order_id + "/apply_coupon_code"); + return Spree.pathFor("api/orders/" + order_id + "/coupon_codes"); } }; diff --git a/frontend/app/assets/javascripts/spree/frontend/checkout/coupon-code.js b/frontend/app/assets/javascripts/spree/frontend/checkout/coupon-code.js index 48eb66cf001..d917991cb02 100644 --- a/frontend/app/assets/javascripts/spree/frontend/checkout/coupon-code.js +++ b/frontend/app/assets/javascripts/spree/frontend/checkout/coupon-code.js @@ -14,7 +14,7 @@ Spree.onCouponCodeApply = function(e) { coupon_code: couponCode }; var req = Spree.ajax({ - method: "PUT", + method: 'POST', url: Spree.routes.apply_coupon_code(Spree.current_order_id), data: JSON.stringify(data), contentType: "application/json" diff --git a/frontend/app/controllers/spree/checkout_controller.rb b/frontend/app/controllers/spree/checkout_controller.rb index 98261af11e3..9d2652386e2 100644 --- a/frontend/app/controllers/spree/checkout_controller.rb +++ b/frontend/app/controllers/spree/checkout_controller.rb @@ -168,6 +168,7 @@ def completion_route def apply_coupon_code if update_params[:coupon_code].present? + Spree::Deprecation.warn('This endpoint is deprecated. Please use `Spree::CouponCodesController#create` endpoint instead.') @order.coupon_code = update_params[:coupon_code] handler = PromotionHandler::Coupon.new(@order).apply diff --git a/frontend/app/controllers/spree/coupon_codes_controller.rb b/frontend/app/controllers/spree/coupon_codes_controller.rb new file mode 100644 index 00000000000..4151b8ca7e4 --- /dev/null +++ b/frontend/app/controllers/spree/coupon_codes_controller.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module Spree + class CouponCodesController < Spree::StoreController + before_action :load_order, only: :create + around_action :lock_order, only: :create + + def create + authorize! :update, @order, cookies.signed[:guest_token] + + if params[:coupon_code].present? + @order.coupon_code = params[:coupon_code] + handler = PromotionHandler::Coupon.new(@order).apply + + respond_with(@order) do |format| + format.html do + if handler.successful? + flash[:success] = handler.success + redirect_to cart_path + else + flash.now[:error] = handler.error + render 'spree/coupon_codes/new' + end + end + end + end + end + + private + + def load_order + @order = current_order + end + end +end diff --git a/frontend/app/controllers/spree/orders_controller.rb b/frontend/app/controllers/spree/orders_controller.rb index 853eaae9dc7..ee603f0b975 100644 --- a/frontend/app/controllers/spree/orders_controller.rb +++ b/frontend/app/controllers/spree/orders_controller.rb @@ -122,6 +122,7 @@ def assign_order def apply_coupon_code if order_params[:coupon_code].present? + Spree::Deprecation.warn('This endpoint is deprecated. Please use `Spree::CouponCodesController#create` endpoint instead.') @order.coupon_code = order_params[:coupon_code] handler = PromotionHandler::Coupon.new(@order).apply diff --git a/frontend/app/views/spree/coupon_codes/new.html.erb b/frontend/app/views/spree/coupon_codes/new.html.erb new file mode 100644 index 00000000000..1660893b861 --- /dev/null +++ b/frontend/app/views/spree/coupon_codes/new.html.erb @@ -0,0 +1,6 @@ +