mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-24 20:36:49 +00:00
Individual StandingOrder orders can be cancelled from Standing Order index
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
angular.module("admin.standingOrders").controller "OrdersPanelController", ($scope, OrderCycles) ->
|
||||
$scope.standingOrder = $scope.object
|
||||
$scope.orderCyclesByID = OrderCycles.byID
|
||||
|
||||
$scope.cancelOrder = (order) ->
|
||||
if confirm(t('are_you_sure'))
|
||||
$scope.standingOrder.cancelOrder(order)
|
||||
|
||||
@@ -32,3 +32,11 @@ angular.module("admin.standingOrders").factory 'StandingOrderPrototype', ($http,
|
||||
, (response) =>
|
||||
StatusMessage.display 'failure', 'Oh no! I was unable to save your changes.'
|
||||
angular.extend(@errors, response.data.errors)
|
||||
|
||||
|
||||
cancelOrder: (order) ->
|
||||
if order.id?
|
||||
$http.put("/admin/standing_order_orders/#{order.id}/cancel").then (response) =>
|
||||
angular.extend(order,response.data)
|
||||
, (response) ->
|
||||
InfoDialog.open 'error', response.data.errors[0]
|
||||
|
||||
17
app/controllers/admin/standing_order_orders_controller.rb
Normal file
17
app/controllers/admin/standing_order_orders_controller.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module Admin
|
||||
class StandingOrderOrdersController < ResourceController
|
||||
respond_to :json
|
||||
|
||||
def cancel
|
||||
if @standing_order_order.cancel
|
||||
respond_with(@standing_order_order) do |format|
|
||||
format.json { render_as_json @standing_order_order }
|
||||
end
|
||||
else
|
||||
respond_with(@standing_order_order) do |format|
|
||||
format.json { render json: { errors: @standing_order_order.errors.full_messages }, status: :unprocessable_entity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -260,6 +260,9 @@ class AbilityDecorator
|
||||
can [:destroy], StandingLineItem do |standing_line_item|
|
||||
user.enterprises.include?(standing_line_item.standing_order.shop)
|
||||
end
|
||||
can [:admin, :cancel], StandingOrderOrder do |standing_order_order|
|
||||
user.enterprises.include?(standing_order_order.standing_order.shop)
|
||||
end
|
||||
end
|
||||
|
||||
def add_relationship_management_abilities(user)
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
%script{ type: "text/ng-template", id: "admin/panels/standing_order_orders.html" }
|
||||
%form{ name: 'standing_order_form', ng: { controller: 'OrdersPanelController' } }
|
||||
%div{ style: 'width: 90%; margin: auto;' }
|
||||
%table
|
||||
%col{ style: 'width: 20%' }
|
||||
%col{ style: 'width: 20%' }
|
||||
%col{ style: 'width: 20%' }
|
||||
%col{ style: 'width: 20%' }
|
||||
%col{ style: 'width: 20%' }
|
||||
%thead
|
||||
%th Number
|
||||
%th OC
|
||||
%th Status
|
||||
%th Total
|
||||
%th.actions
|
||||
%tbody
|
||||
%tr{ ng: { repeat: 'order in standingOrder.not_closed_standing_order_orders' } }
|
||||
%td
|
||||
%a{ ng: { href: "{{::order.edit_path}}", bind: '::order.number' }, target: '_blank' }
|
||||
%td{ ng: { bind: '::orderCyclesByID[order.order_cycle_id].name' } }
|
||||
%td{ ng: { bind: '::order.status' } }
|
||||
%td{ ng: { bind: '::order.total' } }
|
||||
%td.actions
|
||||
|
||||
%form.margin-top-30{ name: 'standing_order_form', ng: { controller: 'OrdersPanelController' } }
|
||||
.row.standing-order-orders
|
||||
.fourteen.columns.offset-by-one
|
||||
%table
|
||||
%col{ style: 'width: 25%' }
|
||||
%col{ style: 'width: 25%' }
|
||||
%col{ style: 'width: 25%' }
|
||||
%col{ style: 'width: 15%' }
|
||||
%col{ style: 'width: 10%' }
|
||||
%thead
|
||||
%th= t('admin.standing_orders.orders.number')
|
||||
%th= t('admin.order_cycle')
|
||||
%th= t('admin.standing_orders.orders.status')
|
||||
%th= t('total')
|
||||
%th.actions
|
||||
%tbody
|
||||
%tr.standing_order_order{ :id => "o_{{order.id}}", ng: { repeat: 'order in standingOrder.not_closed_standing_order_orders' } }
|
||||
%td
|
||||
%a{ ng: { href: "{{::order.edit_path}}", bind: '::order.number' }, target: '_blank' }
|
||||
%td{ ng: { bind: '::orderCyclesByID[order.order_cycle_id].name' } }
|
||||
%td.text-center{ ng: { bind: 'order.status' } }
|
||||
%td.text-center{ ng: { bind: 'order.total' } }
|
||||
%td.actions
|
||||
%a.cancel-order.icon-remove.no-text{ href: 'javascript:void(0)', ng: { click: "cancelOrder(order)" }, 'ofn-with-tip' => t(:cancel_order) }
|
||||
|
||||
@@ -33,8 +33,8 @@
|
||||
= t('admin.shipping_method')
|
||||
%th.actions
|
||||
|
||||
%tbody.panel-ctrl{ object: 'standingOrder', ng: { repeat: "standingOrder in standingOrders | filter:query" } }
|
||||
%tr.standing_order{ :id => "so_{{standingOrder.id}}", class: { even: "'even'", odd: "'odd'" } }
|
||||
%tbody.panel-ctrl{ object: 'standingOrder', ng: { repeat: "standingOrder in standingOrders | filter:query track by standingOrder.id" } }
|
||||
%tr.standing_order{ :id => "so_{{standingOrder.id}}", ng: { class: { even: "'even'", odd: "'odd'" } } }
|
||||
%td.customer.text-center{ ng: { show: 'columns.customer.visible', bind: '::standingOrder.customer_email' } }
|
||||
%td.schedule.text-center{ ng: { show: 'columns.schedule.visible', bind: '::standingOrder.schedule_name' } }
|
||||
%td.items.panel-toggle.text-center{ name: 'products', ng: { show: 'columns.items.visible' } }
|
||||
|
||||
@@ -809,6 +809,9 @@ en:
|
||||
details: Details
|
||||
invalid_error: Oops! Please fill in all of the required fields...
|
||||
product_already_in_order: This product has already been added to the order. Please edit the quantity directly.
|
||||
orders:
|
||||
number: Number
|
||||
status: Status
|
||||
|
||||
stripe_connect_settings:
|
||||
edit:
|
||||
|
||||
@@ -182,6 +182,10 @@ Openfoodnetwork::Application.routes.draw do
|
||||
resources :standing_line_items, only: [], format: :json do
|
||||
post :build, on: :collection
|
||||
end
|
||||
|
||||
resources :standing_order_orders, only: [], format: :json do
|
||||
put :cancel, on: :member
|
||||
end
|
||||
end
|
||||
|
||||
namespace :api do
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Admin::StandingOrderOrdersController, type: :controller do
|
||||
include AuthenticationWorkflow
|
||||
|
||||
describe 'cancel' do
|
||||
let!(:user) { create(:user, enterprise_limit: 10) }
|
||||
let!(:shop) { create(:distributor_enterprise) }
|
||||
let!(:order) { create(:order, order_cycle: create(:simple_order_cycle)) }
|
||||
let!(:standing_order) { create(:standing_order_with_items, shop: shop, orders: [order]) }
|
||||
let!(:standing_order_order) { standing_order.standing_order_orders.first }
|
||||
|
||||
before do
|
||||
allow(controller).to receive(:spree_current_user) { user }
|
||||
end
|
||||
|
||||
context 'json' do
|
||||
let(:params) { { format: :json, id: standing_order_order.id } }
|
||||
|
||||
context 'as a regular user' do
|
||||
it 'redirects to unauthorized' do
|
||||
spree_put :cancel, params
|
||||
expect(response).to redirect_to spree.unauthorized_path
|
||||
end
|
||||
end
|
||||
|
||||
context 'as an enterprise user' do
|
||||
context "without authorisation" do
|
||||
let!(:shop2) { create(:distributor_enterprise) }
|
||||
before { shop2.update_attributes(owner: user) }
|
||||
|
||||
it 'redirects to unauthorized' do
|
||||
spree_put :cancel, params
|
||||
expect(response).to redirect_to spree.unauthorized_path
|
||||
end
|
||||
end
|
||||
|
||||
context "with authorisation" do
|
||||
before { shop.update_attributes(owner: user) }
|
||||
|
||||
it 'renders the cancelled standing_order_order as json' do
|
||||
spree_get :cancel, params
|
||||
json_response = JSON.parse(response.body)
|
||||
expect(json_response['status']).to eq "cancelled"
|
||||
expect(json_response['id']).to eq standing_order_order.id
|
||||
expect(standing_order_order.reload.cancelled_at).to be_within(5.seconds).of Time.now
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -13,9 +13,16 @@ feature 'Standing Orders' do
|
||||
before { quick_login_as user }
|
||||
|
||||
context 'listing standing orders' do
|
||||
let!(:standing_order) { create(:standing_order, shop: shop) }
|
||||
let!(:standing_order2) { create(:standing_order, shop: shop2) }
|
||||
let!(:standing_order_unmanaged) { create(:standing_order, shop: shop_unmanaged) }
|
||||
let!(:standing_order) { create(:standing_order_with_items, shop: shop) }
|
||||
let!(:standing_order2) { create(:standing_order_with_items, shop: shop2) }
|
||||
let!(:standing_order_unmanaged) { create(:standing_order_with_items, shop: shop_unmanaged) }
|
||||
|
||||
before do
|
||||
# initialise standing orders
|
||||
StandingOrderForm.new(standing_order).send(:initialise_orders!)
|
||||
StandingOrderForm.new(standing_order2).send(:initialise_orders!)
|
||||
StandingOrderForm.new(standing_order_unmanaged).send(:initialise_orders!)
|
||||
end
|
||||
|
||||
it "passes the smoke test" do
|
||||
visit spree.admin_path
|
||||
@@ -59,6 +66,30 @@ feature 'Standing Orders' do
|
||||
first("div#columns-dropdown div.menu div.menu_item", text: "Customer").click
|
||||
expect(page).to_not have_selector "th.customer"
|
||||
expect(page).to_not have_content standing_order.customer.email
|
||||
|
||||
# Viewing Orders
|
||||
within "tr#so_#{standing_order.id}" do
|
||||
expect(page).to have_selector "td.orders.panel-toggle", text: 1
|
||||
page.find("td.orders.panel-toggle").trigger('click')
|
||||
end
|
||||
|
||||
# save_screenshot '/Users/rob/Desktop/ss1.png'
|
||||
# expect(page).to have_selector ".standing-order-orders"
|
||||
|
||||
within ".standing-order-orders" do
|
||||
expect(page).to have_selector "tr.standing_order_order", count: 1
|
||||
|
||||
# Cancelling an order
|
||||
standing_order_order = standing_order.standing_order_orders.first
|
||||
within "tr#o_#{standing_order_order.id}" do
|
||||
expect(page).to_not have_content 'CANCELLED'
|
||||
accept_alert 'Are you sure?' do
|
||||
find("a.cancel-order").trigger('click')
|
||||
end
|
||||
expect(page).to have_content 'CANCELLED'
|
||||
expect(standing_order_order.reload.cancelled_at).to be_within(5.seconds).of Time.now
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user