mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
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:
committed by
Rob Harrington
parent
4112c3cc75
commit
4835ef067f
@@ -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)
|
||||
@@ -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: =>
|
||||
|
||||
24
app/controllers/line_items_controller.rb
Normal file
24
app/controllers/line_items_controller.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
37
spec/controllers/line_items_controller_spec.rb
Normal file
37
spec/controllers/line_items_controller_spec.rb
Normal 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
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user