Require action from user when pausing/cancelling standing order with open orders

This commit is contained in:
Rob Harrington
2017-03-16 15:13:12 +11:00
parent 3ce8a1abba
commit ab5dc7ddd5
5 changed files with 137 additions and 15 deletions

View File

@@ -6,6 +6,7 @@ module Admin
before_filter :load_form_data, only: [:new, :edit]
before_filter :strip_banned_attrs, only: [:update]
before_filter :wrap_nested_attrs, only: [:create, :update]
before_filter :check_for_open_orders, only: [:cancel, :pause]
respond_to :json
def index
@@ -48,7 +49,7 @@ module Admin
end
def cancel
@standing_order.cancel
@standing_order.cancel(@open_orders_to_keep || [])
respond_with(@standing_order) do |format|
format.json { render_as_json @standing_order, fee_calculator: fee_calculator }
@@ -56,6 +57,10 @@ module Admin
end
def pause
unless params[:open_orders] == 'keep'
@standing_order.proxy_orders.placed_and_open.each(&:cancel)
end
@standing_order.update_attributes(paused_at: Time.zone.now)
render_as_json @standing_order, fee_calculator: fee_calculator
end
@@ -116,6 +121,13 @@ module Admin
end
end
def check_for_open_orders
return if params[:open_orders] == 'cancel'
@open_orders_to_keep = @standing_order.proxy_orders.placed_and_open.pluck(:id)
return if @open_orders_to_keep.empty? || params[:open_orders] == 'keep'
return render json: { errors: { open_orders: t('admin.standing_orders.confirm_cancel_open_orders_msg') } }, status: :conflict
end
def strip_banned_attrs
params[:standing_order].delete :schedule_id
params[:standing_order].delete :customer_id

View File

@@ -8,6 +8,7 @@ class ProxyOrder < ActiveRecord::Base
scope :closed, -> { joins(:order_cycle).merge(OrderCycle.closed) }
scope :not_closed, -> { joins(:order_cycle).merge(OrderCycle.not_closed) }
scope :not_canceled, where('proxy_orders.canceled_at IS NULL')
scope :placed_and_open, joins(:order).not_closed.where(spree_orders: { state: 'complete' })
def state
return 'canceled' if canceled?

View File

@@ -30,10 +30,10 @@ class StandingOrder < ActiveRecord::Base
proxy_orders.not_closed
end
def cancel
def cancel(keep_ids = [])
transaction do
self.update_column(:canceled_at, Time.zone.now)
proxy_orders.each(&:cancel)
proxy_orders.reject{ |o| keep_ids.include? o.id }.each(&:cancel)
true
end
end

View File

@@ -858,6 +858,7 @@ en:
pause_failure_msg: 'Sorry, pausing failed!'
confirm_unpause_msg: Are you sure you want to unpause this standing order?
unpause_failure_msg: 'Sorry, unpausing failed!'
confirm_cancel_open_orders_msg: "Some orders for this standing order are currently open. The customer has already been notified that the order will be placed. Would you like to cancel these order(s) or keep them?"
order_update_issues_msg: Some orders could not be automatically updated, this is most likely because they have been manually edited. Please review the issues listed below and make any adjustments to individual orders if required.
no_results:
no_standing_orders: No standing orders yet...

View File

@@ -415,12 +415,66 @@ describe Admin::StandingOrdersController, type: :controller do
context "with authorisation" do
before { shop.update_attributes(owner: user) }
it 'renders the cancelled standing_order as json' do
spree_put :cancel, params
json_response = JSON.parse(response.body)
expect(json_response['canceled_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.canceled_at).to be_within(5.seconds).of Time.now
context "when at least one associated order is still 'open'" do
let(:order_cycle) { standing_order.order_cycles.first }
let(:proxy_order) { create(:proxy_order, standing_order: standing_order, order_cycle: order_cycle) }
let!(:order) { proxy_order.initialise_order! }
before { while !order.completed? do break unless order.next! end }
context "when no 'open_orders' directive has been provided" do
it "renders an error, asking what to do" do
spree_put :cancel, params
expect(response.status).to be 409
json_response = JSON.parse(response.body)
expect(json_response['errors']['open_orders']).to eq I18n.t('admin.standing_orders.confirm_cancel_open_orders_msg')
end
end
context "when 'keep' has been provided as the 'open_orders' directive" do
before { params.merge!({ open_orders: 'keep'}) }
it 'renders the cancelled standing_order as json, and does not cancel the open order' do
spree_put :cancel, params
json_response = JSON.parse(response.body)
expect(json_response['canceled_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.canceled_at).to be_within(5.seconds).of Time.now
expect(order.reload.state).to eq 'complete'
expect(proxy_order.reload.canceled_at).to be nil
end
end
context "when 'cancel' has been provided as the 'open_orders' directive" do
let(:mail_mock) { double(:mail) }
before do
params.merge!({ open_orders: 'cancel'})
allow(Spree::OrderMailer).to receive(:cancel_email) { mail_mock }
allow(mail_mock).to receive(:deliver)
end
it 'renders the cancelled standing_order as json, and cancels the open order' do
spree_put :cancel, params
json_response = JSON.parse(response.body)
expect(json_response['canceled_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.canceled_at).to be_within(5.seconds).of Time.now
expect(order.reload.state).to eq 'canceled'
expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.now
expect(mail_mock).to have_received(:deliver)
end
end
end
context "when no associated orders are still 'open'" do
it 'renders the cancelled standing_order as json' do
spree_put :cancel, params
json_response = JSON.parse(response.body)
expect(json_response['canceled_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.canceled_at).to be_within(5.seconds).of Time.now
end
end
end
end
@@ -460,12 +514,66 @@ describe Admin::StandingOrdersController, type: :controller do
context "with authorisation" do
before { shop.update_attributes(owner: user) }
it 'renders the paused standing_order as json' do
spree_put :pause, params
json_response = JSON.parse(response.body)
expect(json_response['paused_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.paused_at).to be_within(5.seconds).of Time.now
context "when at least one associated order is still 'open'" do
let(:order_cycle) { standing_order.order_cycles.first }
let(:proxy_order) { create(:proxy_order, standing_order: standing_order, order_cycle: order_cycle) }
let!(:order) { proxy_order.initialise_order! }
before { while !order.completed? do break unless order.next! end }
context "when no 'open_orders' directive has been provided" do
it "renders an error, asking what to do" do
spree_put :pause, params
expect(response.status).to be 409
json_response = JSON.parse(response.body)
expect(json_response['errors']['open_orders']).to eq I18n.t('admin.standing_orders.confirm_cancel_open_orders_msg')
end
end
context "when 'keep' has been provided as the 'open_orders' directive" do
before { params.merge!({ open_orders: 'keep'}) }
it 'renders the paused standing_order as json, and does not cancel the open order' do
spree_put :pause, params
json_response = JSON.parse(response.body)
expect(json_response['paused_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.paused_at).to be_within(5.seconds).of Time.now
expect(order.reload.state).to eq 'complete'
expect(proxy_order.reload.canceled_at).to be nil
end
end
context "when 'cancel' has been provided as the 'open_orders' directive" do
let(:mail_mock) { double(:mail) }
before do
params.merge!({ open_orders: 'cancel'})
allow(Spree::OrderMailer).to receive(:cancel_email) { mail_mock }
allow(mail_mock).to receive(:deliver)
end
it 'renders the paused standing_order as json, and cancels the open order' do
spree_put :pause, params
json_response = JSON.parse(response.body)
expect(json_response['paused_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.paused_at).to be_within(5.seconds).of Time.now
expect(order.reload.state).to eq 'canceled'
expect(proxy_order.reload.canceled_at).to be_within(5.seconds).of Time.now
expect(mail_mock).to have_received(:deliver)
end
end
end
context "when no associated orders are still 'open'" do
it 'renders the paused standing_order as json' do
spree_put :pause, params
json_response = JSON.parse(response.body)
expect(json_response['paused_at']).to_not be nil
expect(json_response['id']).to eq standing_order.id
expect(standing_order.reload.paused_at).to be_within(5.seconds).of Time.now
end
end
end
end