Skip to content

Commit

Permalink
Merge pull request #2499 from jhawthorn/admin_only_shipping_methods
Browse files Browse the repository at this point in the history
Allow selecting admin-only shipping methods
  • Loading branch information
jhawthorn authored Jan 26, 2018
2 parents 51253a8 + 3239735 commit 0223bff
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 14 deletions.
2 changes: 1 addition & 1 deletion api/app/controllers/spree/api/orders_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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|
Expand Down
18 changes: 16 additions & 2 deletions api/app/controllers/spree/api/shipments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions api/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@
end

member do
get :estimated_rates
put :select_shipping_method

put :ready
put :ship
put :add
Expand Down
42 changes: 42 additions & 0 deletions api/spec/requests/spree/api/shipments_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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 }

Expand Down
17 changes: 17 additions & 0 deletions backend/app/assets/javascripts/spree/backend/models/shipment.js
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
})
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
</th>
{{#if editing}}
<td colspan="4">
{{#if shipping_rates}}
<form>
<select class="custom-select fullwidth" name="selected_shipping_rate_id">
<select class="custom-select fullwidth" name="selected_shipping_method_id">
{{#each shipping_rates}}
<option value="{{ id }}">{{name}} {{display_cost}}</option>
<option value="{{ shipping_method_id }}">{{name}} {{display_cost}}</option>
{{/each}}
</select>
</form>
{{/if}}
</td>
{{else}}
<td colspan="3">
Expand All @@ -22,7 +24,9 @@

<td class="actions">
{{#if editing}}
{{#if shipping_rates}}
<button class="js-save fa fa-check no-text with-tip" data-action="save" title="{{ t "actions.save" }}"></button>
{{/if}}
<button class="js-cancel fa fa-cancel no-text with-tip" data-action="cancel" title="{{ t "actions.cancel" }}"></button>
{{else}}
<button class="js-edit fa fa-edit no-text with-tip" data-action="edit" title=""{{ t "actions.edit" }}"></button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,35 @@ Spree.Views.Order.ShippingMethod = Backbone.View.extend({
},

initialize: function(options) {
this.shippingRateId = this.model.get('selected_shipping_rate').get('id')
this.shippingMethodId = this.model.get('selected_shipping_rate').get('shipping_method_id');
this.shippingRates = new Backbone.Collection();
this.render();
},

onEdit: function(event) {
this.editing = true;
this.shippingRates = this.model.estimatedRates();
this.listenTo(this.shippingRates, "sync", this.render);
this.render();
},

onSave: function(event) {
this.editing = false;
this.model.save({
selected_shipping_rate_id: this.$('select').val()
}, {
patch: true,
this.shippingMethodId = this.$('select').val();
this.shippingRates = new Backbone.Collection();
this.model.selectShippingMethodId(this.shippingMethodId, {
success: function() {
// FIXME: should update page without reloading
window.location.reload();
}
});
this.render();

return false;
},

onCancel: function(event) {
this.editing = false;
this.shippingRates = new Backbone.Collection();
this.render();
},

Expand All @@ -45,10 +48,10 @@ Spree.Views.Order.ShippingMethod = Backbone.View.extend({
order: this.model.collection.parent.toJSON(),
shipment: this.model.toJSON(),
selected_shipping_rate: this.model.get("selected_shipping_rate").toJSON(),
shipping_rates: this.model.get("shipping_rates").toJSON()
shipping_rates: this.shippingRates.toJSON()
});

this.$el.html(html);
this.$('select').val(this.shippingRateId);
this.$('select').val(this.shippingMethodId);
}
})
20 changes: 19 additions & 1 deletion backend/spec/features/admin/orders/order_details_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,24 @@
expect(page).to have_content("UPS Ground")
end

it "can use admin-only shipping methods" do
create(:shipping_method, name: "Admin Free Shipping", cost: 0, available_to_users: false)

visit spree.edit_admin_order_path(order)

screenshot_and_open_image

within("tr", text: "Shipping Method") do
click_icon :edit
select "Admin Free Shipping $0.00"
click_icon :check
end

expect(page).not_to have_css('#selected_shipping_rate_id')
expect(page).to have_no_content("UPS Ground")
expect(page).to have_content("Admin Free Shipping")
end

it "will show the variant sku" do
visit spree.edit_admin_order_path(order)
sku = order.line_items.first.variant.sku
Expand Down Expand Up @@ -537,7 +555,7 @@
within("tr", text: "Shipping Method") do
click_icon :edit
end
select "UPS Ground $100.00", from: "selected_shipping_rate_id"
select "UPS Ground $100.00"
click_icon :check

expect(page).not_to have_css('#selected_shipping_rate_id')
Expand Down
8 changes: 8 additions & 0 deletions core/app/models/spree/shipment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,14 @@ def refresh_rates
shipping_rates
end

def select_shipping_method(shipping_method)
estimator = Spree::Config.stock.estimator_class.new
rates = estimator.shipping_rates(to_package, false)
rate = rates.detect { |r| r.shipping_method_id == shipping_method.id }
rate.selected = true
self.shipping_rates = [rate]
end

def selected_shipping_rate
shipping_rates.detect(&:selected?)
end
Expand Down

0 comments on commit 0223bff

Please sign in to comment.