From 17906f378a1439c3f4fe6f8003d98373fdcb6464 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Thu, 20 Jan 2022 15:26:34 +0100 Subject: [PATCH 1/6] Create a method that actually adjust Items Separate it from the adjustItems method that previously test about the item quantity --- .../admin/spree/orders/variant_autocomplete.js.erb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb index 76a7c5e89d..abfd1bacd6 100644 --- a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb +++ b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb @@ -85,7 +85,12 @@ adjustItems = function(shipment_number, variant_id, quantity){ ofnAlert(t("js.admin.orders.cannot_remove_last_item")); return; } + doAdjustItems(shipment_number, variant_id, quantity, inventory_units, () => { + window.location.reload(); + }); +} +doAdjustItems = function(shipment_number, variant_id, quantity, inventory_units, callback) { var url = Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number; var new_quantity = 0; @@ -106,7 +111,7 @@ adjustItems = function(shipment_number, variant_id, quantity){ url: Spree.url(url), data: { variant_id: variant_id, quantity: new_quantity } }).done(function( msg ) { - window.location.reload(); + callback(); }); } } From 8624fa2a8510c71f5b6f43481bbdb5b4ea681b2b Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Thu, 20 Jan 2022 15:33:11 +0100 Subject: [PATCH 2/6] On last item deletion, prevent user on order canceling and cancellation email ... with a modal. User can cancel the modal or confirm the last item deletion & order cancelation with or without sending a cancellation email to the consumer. --- .../spree/orders/variant_autocomplete.js.erb | 28 ++++++++++++++++++- app/views/spree/admin/shared/_routes.html.erb | 3 +- app/webpacker/css/admin/orders.scss | 4 +++ config/locales/en.yml | 3 +- 4 files changed, 35 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb index abfd1bacd6..90e4c9a14d 100644 --- a/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb +++ b/app/assets/javascripts/admin/spree/orders/variant_autocomplete.js.erb @@ -82,7 +82,15 @@ adjustItems = function(shipment_number, variant_id, quantity){ var inventory_units = _.where(shipment.inventory_units, {variant_id: variant_id}); if (quantity == 0 && inventory_units.length == shipment.inventory_units.length) { - ofnAlert(t("js.admin.orders.cannot_remove_last_item")); + ofnCancelOrderAlert((confirm, sendEmailCancellation) => { + if (confirm) { + doAdjustItems(shipment_number, variant_id, quantity, inventory_units, () => { + var redirectTo = new URL(Spree.routes.cancel_order.toString()); + redirectTo.searchParams.append("send_cancellation_email", sendEmailCancellation); + window.location.href = redirectTo.toString(); + }); + } + }); return; } doAdjustItems(shipment_number, variant_id, quantity, inventory_units, () => { @@ -186,6 +194,24 @@ ofnAlert = function(message) { $('#custom-alert').show(); } +ofnCancelOrderAlert = function(callback) { + $('#custom-confirm .message').html( + ` ${t("js.admin.orders.cancel_the_order_html")} +
+ + +
`); + $('#custom-confirm button.confirm').unbind( "click" ).click(() => { + $('#custom-confirm').hide(); + callback(true, $('#send_cancellation_email').is(':checked')); + }); + $('#custom-confirm button.cancel').click(() => { + $('#custom-confirm').hide(); + callback(false) + }); + $('#custom-confirm').show(); +} + ofnConfirm = function(callback) { $('#custom-confirm').data($(event.target).data()); $('#custom-confirm button.confirm').click(callback); diff --git a/app/views/spree/admin/shared/_routes.html.erb b/app/views/spree/admin/shared/_routes.html.erb index a0a854781f..dc8fac6b9d 100644 --- a/app/views/spree/admin/shared/_routes.html.erb +++ b/app/views/spree/admin/shared/_routes.html.erb @@ -9,6 +9,7 @@ :variants_search => spree.admin_search_variants_url(:format => 'json'), :taxons_search => main_app.api_v0_taxons_url(:format => 'json'), :orders_api => main_app.api_v0_orders_url, - :states_search => main_app.api_v0_states_url(:format => 'json') + :states_search => main_app.api_v0_states_url(:format => 'json'), + :cancel_order => spree.fire_admin_order_url(id: @order ? @order.number : "", e: 'cancel') }.to_json %>; diff --git a/app/webpacker/css/admin/orders.scss b/app/webpacker/css/admin/orders.scss index 2316b27f66..8f5b724c35 100644 --- a/app/webpacker/css/admin/orders.scss +++ b/app/webpacker/css/admin/orders.scss @@ -148,5 +148,9 @@ table.index td.actions { .message { font-size: $h5-size; padding: 1.2em 0; + + .form { + padding: 1.2em 0; + } } } diff --git a/config/locales/en.yml b/config/locales/en.yml index 6c23d73022..122f1d0726 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3030,7 +3030,8 @@ See the %{link} to find out more about %{sitename}'s features and to start using invalid: "invalid" quantity_adjusted: "Insufficient stock available. Line item updated to maximum available quantity." quantity_unchanged: "Quantity unchanged from previous amount." - cannot_remove_last_item: "Cannot remove last item from order. Please cancel order instead." + cancel_the_order_html: "This will cancel the current order.
Are you sure you want to proceed?" + cancel_the_order_send_cancelation_email: "Send a cancellation email to the customer" resend_user_email_confirmation: resend: "Resend" sending: "Resend..." From 50f547af98b502950c4450383aab982f3455096f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Thu, 20 Jan 2022 15:37:26 +0100 Subject: [PATCH 3/6] Add an attribute that conditions the sending of the cancellation email true by default to not change the default behavior. Can be set to false when sending params send_cancellation_email --- app/controllers/spree/admin/orders_controller.rb | 1 + app/models/spree/order.rb | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/spree/admin/orders_controller.rb b/app/controllers/spree/admin/orders_controller.rb index c1f1ce10bd..55035f6a07 100644 --- a/app/controllers/spree/admin/orders_controller.rb +++ b/app/controllers/spree/admin/orders_controller.rb @@ -65,6 +65,7 @@ module Spree def fire event = params[:e] + @order.send_cancellation_email = params[:send_cancellation_email] == "true" if @order.public_send(event.to_s) flash[:success] = Spree.t(:order_updated) else diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 776e654192..8ef80d2daf 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -106,6 +106,7 @@ module Spree after_save_commit DefaultAddressUpdater + attribute :send_cancellation_email, type: :boolean, default: true # -- Scopes scope :not_empty, -> { left_outer_joins(:line_items).where.not(spree_line_items: { id: nil }) @@ -658,7 +659,7 @@ module Spree def after_cancel shipments.each(&:cancel!) - OrderMailer.cancel_email(id).deliver_later + OrderMailer.cancel_email(id).deliver_later if send_cancellation_email self.payment_state = 'credit_owed' unless shipped? end From c9b19811adef62de9a49922769173a8a4f2fb90f Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Fri, 21 Jan 2022 14:44:00 +0100 Subject: [PATCH 4/6] Add missing i18n key --- config/locales/en.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/config/locales/en.yml b/config/locales/en.yml index 122f1d0726..05ea552000 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3416,6 +3416,7 @@ See the %{link} to find out more about %{sitename}'s features and to start using tracking: "Tracking" tracking_number: "Tracking Number" order_total: "Order Total" + order_updated: "Order updated" customer_details: "Customer Details" customer_details_updated: "Customer Details updated" customer_search: "Customer Search" From a99ecc473d80175fbeee264d6af040a793868ee9 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Fri, 21 Jan 2022 14:44:25 +0100 Subject: [PATCH 5/6] Add tests around item deletion for an order --- spec/system/admin/order_spec.rb | 67 +++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/spec/system/admin/order_spec.rb b/spec/system/admin/order_spec.rb index dae71d2d86..59ba660608 100644 --- a/spec/system/admin/order_spec.rb +++ b/spec/system/admin/order_spec.rb @@ -126,6 +126,73 @@ describe ' expect(page).not_to have_select2 "add_variant_id", with_options: [product.name] end + context "deleting item of an order" do + context "when there a more than one items in the order" do + let(:line_item) { create(:line_item) } + + before do + order.line_items << line_item + login_as_admin_and_visit spree.edit_admin_order_path(order) + find("a.delete-item").click + expect(page).to have_content "Are you sure?" + end + + it "show a modal 'Are you sure?' that the user can close and then nothing change" do + within(".modal", visible: true) do + expect do + click_on("Cancel") + expect(page).not_to have_content "Are you sure?" + end.not_to change { order.line_items.length } + end + end + + it "show a modal 'Are you sure?' that the user confirm and then the item is deleted" do + expect(order.line_items.length).to eq(2) + within(".modal", visible: true) do + expect do + click_on("OK") + expect(page).not_to have_css(".modal", visible: true) + end.to change { order.reload.line_items.length }.by(-1) + end + end + end + + context "when it is the last item of an order" do + before do + # specify that order has only one line item + order.line_items = [order.line_items.first] + login_as_admin_and_visit spree.edit_admin_order_path(order) + find("a.delete-item").click + within(".modal", visible: true) do + # ignore first modal by confirming it + click_on("OK") + end + end + + context "it shows a second modal about last item deletion and therefore about order cancellation" do + + it "that the user can close and then nothing change" do + expect(page).to have_content "This will cancel the current order." + within(".modal", visible: true) do + click_on("Cancel") + end + + expect(order.reload.line_items.length).to eq(1) + expect(page).to have_selector('tr.stock-item', count: 1) + end + + it "that the user can confirm and then the order is cancelled" do + within(".modal", visible: true) do + click_on("OK") + end + expect(page).to have_content "Cannot add item to canceled order" + expect(order.reload.line_items.length).to eq(0) + expect(order.reload.state).to eq("canceled") + end + end + end + end + it "can't add more items than are available" do # Move the order back to the cart state order.state = 'cart' From af8500e98c61d635697c3898763d37240705e0a4 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Bellet Date: Mon, 24 Jan 2022 11:48:31 +0100 Subject: [PATCH 6/6] Add the test around the cancellation email sending or not --- spec/system/admin/order_spec.rb | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/spec/system/admin/order_spec.rb b/spec/system/admin/order_spec.rb index 59ba660608..c9d19ca64a 100644 --- a/spec/system/admin/order_spec.rb +++ b/spec/system/admin/order_spec.rb @@ -170,7 +170,6 @@ describe ' end context "it shows a second modal about last item deletion and therefore about order cancellation" do - it "that the user can close and then nothing change" do expect(page).to have_content "This will cancel the current order." within(".modal", visible: true) do @@ -181,13 +180,29 @@ describe ' expect(page).to have_selector('tr.stock-item', count: 1) end - it "that the user can confirm and then the order is cancelled" do - within(".modal", visible: true) do - click_on("OK") + context "that the user can confirm" do + it "and then the order is cancelled and no email is sent by default" do + expect do + within(".modal", visible: true) do + click_on("OK") + end + expect(page).to have_content "Cannot add item to canceled order" + expect(order.reload.line_items.length).to eq(0) + expect(order.reload.state).to eq("canceled") + end.to_not have_enqueued_mail(Spree::OrderMailer, :cancel_email) + end + + it "and check the checkbox to send an email to the customer about its order cancellation" do + expect do + within(".modal", visible: true) do + check("send_cancellation_email") + click_on("OK") + end + expect(page).to have_content "Cannot add item to canceled order" + expect(order.reload.line_items.length).to eq(0) + expect(order.reload.state).to eq("canceled") + end.to have_enqueued_mail(Spree::OrderMailer, :cancel_email) end - expect(page).to have_content "Cannot add item to canceled order" - expect(order.reload.line_items.length).to eq(0) - expect(order.reload.state).to eq("canceled") end end end