diff --git a/api/app/controllers/spree/api/orders_controller.rb b/api/app/controllers/spree/api/orders_controller.rb index 2134ed3ae9a..b52f9491444 100644 --- a/api/app/controllers/spree/api/orders_controller.rb +++ b/api/app/controllers/spree/api/orders_controller.rb @@ -10,7 +10,7 @@ class OrdersController < Spree::Api::BaseController skip_before_action :authenticate_user, only: :apply_coupon_code before_action :find_order, except: [:create, :mine, :current, :index] - around_action :lock_order, except: [:create, :mine, :current, :index] + around_action :lock_order, except: [:create, :mine, :current, :index, :show] # Dynamically defines our stores checkout steps to ensure we check authorization on each step. Spree::Order.checkout_steps.keys.each do |step| diff --git a/api/app/controllers/spree/api/shipments_controller.rb b/api/app/controllers/spree/api/shipments_controller.rb index 835c6ec0989..5cdaaaf0609 100644 --- a/api/app/controllers/spree/api/shipments_controller.rb +++ b/api/app/controllers/spree/api/shipments_controller.rb @@ -2,9 +2,9 @@ module Spree module Api class ShipmentsController < Spree::Api::BaseController before_action :find_order_on_create, only: :create - before_action :find_shipment, only: [:update, :ship, :ready, :add, :remove] + before_action :find_shipment, only: [:update, :ship, :ready, :add, :remove, :estimated_rates, :select_shipping_method] before_action :load_transfer_params, only: [:transfer_to_location, :transfer_to_shipment] - around_action :lock_order, except: [:mine] + around_action :lock_order, except: [:mine, :estimated_rates] before_action :update_shipment, only: [:ship, :ready, :add, :remove] def mine @@ -22,6 +22,20 @@ def mine end end + def estimated_rates + authorize! :update, @shipment + estimator = Spree::Config.stock.estimator_class.new + @shipping_rates = estimator.shipping_rates(@shipment.to_package, false) + end + + def select_shipping_method + authorize! :update, @shipment + shipping_method = Spree::ShippingMethod.find(params.require(:shipping_method_id)) + @shipment.select_shipping_method(shipping_method) + @order.recalculate + respond_with(@shipment, default_template: :show) + end + def create authorize! :create, Shipment quantity = params[:quantity].to_i diff --git a/api/app/views/spree/api/shipments/estimated_rates.json.jbuilder b/api/app/views/spree/api/shipments/estimated_rates.json.jbuilder new file mode 100644 index 00000000000..74eecd98aaf --- /dev/null +++ b/api/app/views/spree/api/shipments/estimated_rates.json.jbuilder @@ -0,0 +1,4 @@ +json.shipping_rates @shipping_rates do |shipping_rate| + json.(shipping_rate, :name, :cost, :shipping_method_id, :shipping_method_code) + json.display_cost(shipping_rate.display_cost.to_s) +end diff --git a/api/config/routes.rb b/api/config/routes.rb index 3afb92da049..a92beae8351 100644 --- a/api/config/routes.rb +++ b/api/config/routes.rb @@ -82,6 +82,9 @@ end member do + get :estimated_rates + put :select_shipping_method + put :ready put :ship put :add diff --git a/api/spec/requests/spree/api/shipments_controller_spec.rb b/api/spec/requests/spree/api/shipments_controller_spec.rb index 3464a0fedf1..48254d4292f 100644 --- a/api/spec/requests/spree/api/shipments_controller_spec.rb +++ b/api/spec/requests/spree/api/shipments_controller_spec.rb @@ -237,6 +237,48 @@ end end + describe "#estimated_rates" do + let!(:user_shipping_method) { shipment.shipping_method } + let!(:admin_shipping_method) { create(:shipping_method, available_to_users: false, name: "Secret") } + + sign_in_as_admin! + + subject do + get spree.estimated_rates_api_shipment_path(shipment) + end + + it "returns success" do + subject + expect(response).to be_success + end + + it "returns rates available to user" do + subject + expect(json_response['shipping_rates']).to include( + { + "name" => user_shipping_method.name, + "cost" => "100.0", + "shipping_method_id" => user_shipping_method.id, + "shipping_method_code" => user_shipping_method.code, + "display_cost" => "$100.00" + } + ) + end + + it "returns rates available to admin" do + subject + expect(json_response['shipping_rates']).to include( + { + "name" => admin_shipping_method.name, + "cost" => "10.0", + "shipping_method_id" => admin_shipping_method.id, + "shipping_method_code" => admin_shipping_method.code, + "display_cost" => "$10.00" + } + ) + end + end + describe "#ship" do let(:shipment) { create(:order_ready_to_ship).shipments.first } diff --git a/backend/app/assets/javascripts/spree/backend/models/shipment.js b/backend/app/assets/javascripts/spree/backend/models/shipment.js index 0e8a2567f12..d6279c6b644 100644 --- a/backend/app/assets/javascripts/spree/backend/models/shipment.js +++ b/backend/app/assets/javascripts/spree/backend/models/shipment.js @@ -6,5 +6,22 @@ Spree.Models.Shipment = Backbone.Model.extend({ relations: { "selected_shipping_rate": Backbone.Model, "shipping_rates": Backbone.Collection, + }, + + estimatedRates: function() { + var ratesCollection = Backbone.Collection.extend({ + parse: function(resp){ return resp.shipping_rates } + }); + var rates = new ratesCollection(); + rates.fetch({ url: this.url() + "/estimated_rates" }) + return rates; + }, + + selectShippingMethodId: function(shippingMethodId, options) { + this.sync("update", this, _.extend({ + url: this.url() + "/select_shipping_method", + contentType: 'application/json', + data: JSON.stringify({ shipping_method_id: shippingMethodId }) + }, options)); } }) diff --git a/backend/app/assets/javascripts/spree/backend/templates/orders/shipping_method.hbs b/backend/app/assets/javascripts/spree/backend/templates/orders/shipping_method.hbs index 255a3c42cf3..4aa6cbd156b 100644 --- a/backend/app/assets/javascripts/spree/backend/templates/orders/shipping_method.hbs +++ b/backend/app/assets/javascripts/spree/backend/templates/orders/shipping_method.hbs @@ -3,13 +3,15 @@ {{#if editing}}