From 7644f08d5cc38879cfae11b44ebb80f0e6adb91f Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Fri, 2 Dec 2016 10:28:26 +1100 Subject: [PATCH] Individual StandingOrder orders can be cancelled from Standing Order index --- .../orders_panel_controller.js.coffee | 4 ++ .../standing_order_prototype.js.coffee | 8 +++ .../admin/standing_order_orders_controller.rb | 17 ++++++ app/models/spree/ability_decorator.rb | 3 ++ .../standing_orders/_orders_panel.html.haml | 47 +++++++++-------- .../admin/standing_orders/_table.html.haml | 4 +- config/locales/en.yml | 3 ++ config/routes.rb | 4 ++ .../standing_order_orders_controller_spec.rb | 52 +++++++++++++++++++ spec/features/admin/standing_orders_spec.rb | 37 +++++++++++-- 10 files changed, 151 insertions(+), 28 deletions(-) create mode 100644 app/controllers/admin/standing_order_orders_controller.rb create mode 100644 spec/controllers/admin/standing_order_orders_controller_spec.rb diff --git a/app/assets/javascripts/admin/standing_orders/controllers/orders_panel_controller.js.coffee b/app/assets/javascripts/admin/standing_orders/controllers/orders_panel_controller.js.coffee index a3ea670c6f..ad4644eeb6 100644 --- a/app/assets/javascripts/admin/standing_orders/controllers/orders_panel_controller.js.coffee +++ b/app/assets/javascripts/admin/standing_orders/controllers/orders_panel_controller.js.coffee @@ -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) diff --git a/app/assets/javascripts/admin/standing_orders/services/standing_order_prototype.js.coffee b/app/assets/javascripts/admin/standing_orders/services/standing_order_prototype.js.coffee index 976d5acfa3..57c549db39 100644 --- a/app/assets/javascripts/admin/standing_orders/services/standing_order_prototype.js.coffee +++ b/app/assets/javascripts/admin/standing_orders/services/standing_order_prototype.js.coffee @@ -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] diff --git a/app/controllers/admin/standing_order_orders_controller.rb b/app/controllers/admin/standing_order_orders_controller.rb new file mode 100644 index 0000000000..fe56c85c67 --- /dev/null +++ b/app/controllers/admin/standing_order_orders_controller.rb @@ -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 diff --git a/app/models/spree/ability_decorator.rb b/app/models/spree/ability_decorator.rb index 2bf031969c..d2cb409418 100644 --- a/app/models/spree/ability_decorator.rb +++ b/app/models/spree/ability_decorator.rb @@ -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) diff --git a/app/views/admin/standing_orders/_orders_panel.html.haml b/app/views/admin/standing_orders/_orders_panel.html.haml index ac2f917d91..245d24e590 100644 --- a/app/views/admin/standing_orders/_orders_panel.html.haml +++ b/app/views/admin/standing_orders/_orders_panel.html.haml @@ -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) } diff --git a/app/views/admin/standing_orders/_table.html.haml b/app/views/admin/standing_orders/_table.html.haml index 0da6af5d75..821f2ddea7 100644 --- a/app/views/admin/standing_orders/_table.html.haml +++ b/app/views/admin/standing_orders/_table.html.haml @@ -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' } } diff --git a/config/locales/en.yml b/config/locales/en.yml index bb382dee05..6502f18d61 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -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: diff --git a/config/routes.rb b/config/routes.rb index 0056651de9..64a1b436c3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/spec/controllers/admin/standing_order_orders_controller_spec.rb b/spec/controllers/admin/standing_order_orders_controller_spec.rb new file mode 100644 index 0000000000..33fa106116 --- /dev/null +++ b/spec/controllers/admin/standing_order_orders_controller_spec.rb @@ -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 diff --git a/spec/features/admin/standing_orders_spec.rb b/spec/features/admin/standing_orders_spec.rb index 2cac69418f..1daac42eaf 100644 --- a/spec/features/admin/standing_orders_spec.rb +++ b/spec/features/admin/standing_orders_spec.rb @@ -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