Add feature to remove line items from open order cycle

- Add JS controller to send delete requests.
- Add resource controller to destroy items.
- Add authorisation check to abilities.
- Update fees after removing line item.
This commit is contained in:
Maikel Linke
2016-08-03 17:23:02 +10:00
committed by Rob Harrington
parent 4112c3cc75
commit 4835ef067f
10 changed files with 116 additions and 6 deletions

View File

@@ -0,0 +1,10 @@
Darkswarm.controller "EditOrderCtrl", ($scope, $resource, Cart) ->
$scope.deleteLineItem = (id) ->
params = {id: id}
success = (response) ->
$(".line-item-" + id).remove()
fail = (error) ->
console.log error
$resource("/line_items/:id").delete(params, success, fail)

View File

@@ -102,7 +102,6 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $roo
for line_item in items
line_item.variant.line_item = line_item
Variants.extend line_item.variant
line_item.variant.extended_name = @extendedVariantName(line_item.variant)
items
total_item_count: =>

View File

@@ -0,0 +1,24 @@
class LineItemsController < Spree::BaseController
respond_to :json
def destroy
item = Spree::LineItem.find(params[:id])
authorize! :destroy, item
destroy_with_lock item
respond_with(item)
end
# Override default which just redirects
# See Spree::BaseController and Spree::Core::ControllerHelpers::Auth
def unauthorized
render text: '', status: 403
end
def destroy_with_lock(item)
order = item.order
order.with_lock do
item.destroy
order.update_distribution_charge!
end
end
end

View File

@@ -4,6 +4,7 @@ class AbilityDecorator
# All abilites are allocated from this initialiser, currently in 5 chunks.
# Spree also defines other abilities.
def initialize(user)
add_shopping_abilities user
add_base_abilities user if is_new_user? user
add_enterprise_management_abilities user if can_manage_enterprises? user
add_group_management_abilities user if can_manage_groups? user
@@ -50,6 +51,12 @@ class AbilityDecorator
can_manage_enterprises? user
end
def add_shopping_abilities(user)
can [:destroy], Spree::LineItem do |item|
item.andand.order.andand.order_cycle.andand.open? && item.order.user_id == user.id
end
end
# New users can create an enterprise, and gain other permissions from doing this.
def add_base_abilities(user)
can [:create], Enterprise
@@ -184,6 +191,7 @@ class AbilityDecorator
can [:admin , :for_line_items], Enterprise
can [:admin, :index, :create], Spree::LineItem
can [:destroy, :update], Spree::LineItem do |item|
order = item.order
user.admin? || user.enterprises.include?(order.distributor) || order.order_cycle.andand.coordinated_by?(user)
end

View File

@@ -48,11 +48,11 @@
= "{{ Cart.dirty ? '#{t(:cart_updating)}' : (Cart.empty() ? '#{t(:cart_empty)}' : '#{t(:cart_edit)}' ) }}"
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"}
= t 'checkout'
%h5{"ng-if" => "Cart.line_items_finalised().present()", style: 'margin-top: 1em'}
%h5{"ng-if" => "Cart.line_items_finalised().length", style: 'margin-top: 1em'}
= t '.already_ordered_products'
%table
%tr.product-cart{"ng-repeat" => "line_item in Cart.line_items_finalised()",
"ng-controller" => "LineItemCtrl", "id" => "cart-variant-{{ line_item.variant.id }}"}
"id" => "cart-variant-{{ line_item.variant.id }}"}
%td
%small
%strong

View File

@@ -1,4 +1,4 @@
%div
%div{ng: {controller: "EditOrderCtrl"}}
%div
%div
.row
@@ -21,7 +21,7 @@
%tbody
- @order.finalised_line_items.each do |line_item|
- variant = line_item.variant
%tr.line-item{class: "variant-#{variant.id}"}
%tr.line-item{class: "line-item-#{line_item.id} variant-#{variant.id}"}
%td.cart-item-description
%div.item-thumb-image
@@ -39,3 +39,5 @@
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
%td.cart-item-delete.text-center
%a.delete{ng: {click: "deleteLineItem(#{line_item.id})"}}
%i.delete.ofn-i_026-trash

View File

@@ -35,6 +35,5 @@
= line_item.display_amount_with_adjustments.to_html unless line_item.quantity.nil?
%td.cart-item-delete.text-center{"data-hook" => "cart_item_delete"}
{{ quantity }}
%a.delete{href: "#", id: "delete_#{dom_id(line_item)}"}
%i.delete.ofn-i_026-trash

View File

@@ -42,6 +42,8 @@ Openfoodnetwork::Application.routes.draw do
end
end
resources :line_items, only: [:destroy]
resources :groups, only: [:index, :show] do
collection do
get :signup

View File

@@ -0,0 +1,37 @@
require 'spec_helper'
describe LineItemsController do
let(:item) { create(:line_item) }
let(:item_with_oc) do
order_cycle = create(:simple_order_cycle)
item.order.order_cycle = order_cycle
item.order.save
item
end
it "fails without line item id" do
expect { delete :destroy }.to raise_error
end
it "denies deletion without order cycle" do
request = { format: :json, id: item }
delete :destroy, request
expect(response.status).to be 403
expect { item.reload }.to_not raise_error
end
it "denies deletion without user" do
request = { format: :json, id: item_with_oc }
delete :destroy, request
expect(response.status).to be 403
expect { item.reload }.to_not raise_error
end
it "deletes the line item" do
controller.stub spree_current_user: item.order.user
request = { format: :json, id: item_with_oc }
delete :destroy, request
expect(response.status).to be 204
expect { item.reload }.to raise_error
end
end

View File

@@ -84,5 +84,34 @@ feature "full-page cart", js: true do
page.should have_content "Insufficient stock available, only 2 remaining"
end
end
context "when ordered in the same order cycle" do
let(:address) { create(:address) }
let(:user) { create(:user, bill_address: address, ship_address: address) }
let!(:prev_order1) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor, user: user) }
let!(:prev_order2) { create(:completed_order_with_totals, order_cycle: order_cycle, distributor: distributor, user: user) }
before do
order.user = user
order.save
add_product_to_cart order, product_tax
quick_login_as user
visit spree.cart_path
end
it "shows already ordered line items" do
item1 = prev_order1.line_items.first
item2 = prev_order2.line_items.first
expect(page).to have_content item1.variant.name
expect(page).to have_content item2.variant.name
page.find(".line-item-#{item1.id} a.delete").click
expect(page).to have_no_content item1.variant.name
expect(page).to have_content item2.variant.name
visit spree.cart_path
expect(page).to have_no_content item1.variant.name
expect(page).to have_content item2.variant.name
end
end
end
end