diff --git a/app/assets/javascripts/admin/spree/orders/shipments.js.erb b/app/assets/javascripts/admin/spree/orders/shipments.js.erb index 322a648683..f28cbeeee8 100644 --- a/app/assets/javascripts/admin/spree/orders/shipments.js.erb +++ b/app/assets/javascripts/admin/spree/orders/shipments.js.erb @@ -1,22 +1,6 @@ // Shipments AJAX API $(document).ready(function() { - - handle_ship_click = function(){ - var link = $(this); - var shipment_number = link.data('shipment-number'); - var url = Spree.url( Spree.routes.orders_api + "/" + order_number + "/shipments/" + shipment_number + "/ship.json"); - $.ajax({ - type: "PUT", - url: url - }).done(function( msg ) { - window.location.reload(); - }).error(function( msg ) { - console.log(msg); - }); - } - $('.admin-order-edit-form a.ship').click(handle_ship_click); - //handle shipping method edit click $('a.edit-method').click(toggleMethodEdit); $('a.cancel-method').click(toggleMethodEdit); diff --git a/app/components/ship_order_component.html.haml b/app/components/ship_order_component.html.haml new file mode 100644 index 0000000000..be05f354e1 --- /dev/null +++ b/app/components/ship_order_component.html.haml @@ -0,0 +1,8 @@ += render ConfirmModalComponent.new(id: dom_id(@order, :ship), confirm_reflexes: "click->Admin::OrdersReflex#ship", controller: "orders", reflex: "Admin::Orders#ship") do + %div{class: "margin-bottom-30"} + %p= t('spree.admin.orders.shipment.mark_as_shipped_message_html') + %div{class: "margin-bottom-30"} + = hidden_field_tag :id, @order.id + = label_tag do + = check_box_tag :send_shipment_email, "1", true + = t('spree.admin.orders.shipment.mark_as_shipped_label_message') diff --git a/app/components/ship_order_component.rb b/app/components/ship_order_component.rb new file mode 100644 index 0000000000..89f500afcb --- /dev/null +++ b/app/components/ship_order_component.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class ShipOrderComponent < ViewComponent::Base + def initialize(order:) + @order = order + end +end diff --git a/app/helpers/spree/admin/orders_helper.rb b/app/helpers/spree/admin/orders_helper.rb index 700b6bdcb4..6937e2990d 100644 --- a/app/helpers/spree/admin/orders_helper.rb +++ b/app/helpers/spree/admin/orders_helper.rb @@ -95,10 +95,8 @@ module Spree def ship_order_link { name: t(:ship_order), - url: spree.fire_admin_order_path(@order, e: 'ship'), - method: 'put', - icon: 'icon-truck', - confirm: t(:are_you_sure) } + url: '#', + icon: 'icon-truck' } end def cancel_order_link diff --git a/app/models/spree/order.rb b/app/models/spree/order.rb index 238e935e5d..1ab58d530c 100644 --- a/app/models/spree/order.rb +++ b/app/models/spree/order.rb @@ -27,7 +27,9 @@ module Spree go_to_state :complete end - attr_accessor :use_billing, :checkout_processing, :save_bill_address, :save_ship_address + attr_accessor :use_billing, :checkout_processing, :save_bill_address, + :save_ship_address + attr_writer :send_shipment_email token_resource @@ -616,6 +618,12 @@ module Spree state.in?(["payment", "confirmation"]) end + def send_shipment_email + return true if @send_shipment_email.nil? + + @send_shipment_email + end + private def reapply_tax_on_changed_address diff --git a/app/models/spree/shipment.rb b/app/models/spree/shipment.rb index 476658b13a..0b060c727c 100644 --- a/app/models/spree/shipment.rb +++ b/app/models/spree/shipment.rb @@ -346,7 +346,7 @@ module Spree def after_ship inventory_units.each(&:ship!) fee_adjustment.finalize! - send_shipped_email + send_shipped_email if order.send_shipment_email touch :shipped_at update_order_shipment_state end diff --git a/app/reflexes/admin/orders_reflex.rb b/app/reflexes/admin/orders_reflex.rb index 765438d7cc..b3145214a1 100644 --- a/app/reflexes/admin/orders_reflex.rb +++ b/app/reflexes/admin/orders_reflex.rb @@ -8,8 +8,10 @@ module Admin payment_capture = OrderCaptureService.new(@order) if payment_capture.call - morph dom_id(@order), render(partial: "spree/admin/orders/table_row", - locals: { order: @order.reload, success: true }) + cable_ready.replace(selector: dom_id(@order), + html: render(partial: "spree/admin/orders/table_row", + locals: { order: @order.reload, success: true })) + morph :nothing else flash[:error] = payment_capture.gateway_error || I18n.t(:payment_processing_failed) morph_admin_flashes @@ -17,7 +19,10 @@ module Admin end def ship + @order.send_shipment_email = false unless params[:send_shipment_email] if @order.ship + return set_param_for_controller if request.url.match?('edit') + morph dom_id(@order), render(partial: "spree/admin/orders/table_row", locals: { order: @order.reload, success: true }) else @@ -83,7 +88,8 @@ module Admin private def authorize_order - @order = Spree::Order.find_by(id: element.dataset[:id]) + id = element.dataset[:id] || params[:id] + @order = Spree::Order.find_by(id:) authorize! :admin, @order end @@ -96,5 +102,9 @@ module Admin def editable_orders Permissions::Order.new(current_user).editable_orders end + + def set_param_for_controller + params[:id] = @order.number + end end end diff --git a/app/views/admin/shared/_tooltip_button.html.haml b/app/views/admin/shared/_tooltip_button.html.haml index 06b37688cd..3eebca4671 100644 --- a/app/views/admin/shared/_tooltip_button.html.haml +++ b/app/views/admin/shared/_tooltip_button.html.haml @@ -1,5 +1,8 @@ %div{ "data-controller": "tooltip" } - %button{class: button_class, "data-reflex": button_reflex, "data-id": reflex_data_id, "data-tooltip-target": "element" } + - if local_assigns[:shipment] + %button{class: button_class,"data-controller": "modal-link", "data-action": "click->modal-link#open", "data-modal-link-target-value": "ship_order_#{reflex_data_id}", "data-id": reflex_data_id, "data-tooltip-target": "element" } + - else + %button{class: button_class, "data-reflex": button_reflex, "data-id": reflex_data_id, "data-tooltip-target": "element" } .tooltip-container .tooltip{"data-tooltip-target": "tooltip"} = sanitize tooltip_text diff --git a/app/views/spree/admin/orders/_shipment.html.haml b/app/views/spree/admin/orders/_shipment.html.haml index f28ef2740f..599900c295 100644 --- a/app/views/spree/admin/orders/_shipment.html.haml +++ b/app/views/spree/admin/orders/_shipment.html.haml @@ -8,7 +8,10 @@ = Spree.t("shipment_states.#{shipment.state}") - if shipment.ready? and can? :update, shipment = "-" - = link_to t(:ship), '#', :class => 'ship button icon-arrow-right', :data => { 'shipment-number' => shipment.number } + %button{"class": "ship button icon-arrow-right","data-controller": "modal-link", + "data-action": "click->modal-link#open", "data-modal-link-target-value": dom_id(order, :ship)}= t(:ship) + %form + = render ShipOrderComponent.new(order: order) %table.stock-contents.index %colgroup diff --git a/app/views/spree/admin/orders/_table_row.html.haml b/app/views/spree/admin/orders/_table_row.html.haml index 9c0ffb5e17..cb0b579391 100644 --- a/app/views/spree/admin/orders/_table_row.html.haml +++ b/app/views/spree/admin/orders/_table_row.html.haml @@ -47,6 +47,9 @@ %i.success.icon-ok-sign{"data-controller": "ephemeral"} = render partial: 'admin/shared/tooltip', locals: {link_class: "icon_link with-tip icon-edit no-text" ,link: edit_admin_order_path(order), link_text: "", tooltip_text: t('spree.admin.orders.index.edit')} - if order.ready_to_ship? - = render partial: 'admin/shared/tooltip_button', locals: {button_class: "icon-road icon_link with-tip no-text", button_reflex: "click->Admin::OrdersReflex#ship", reflex_data_id: order.id.to_s, tooltip_text: t('spree.admin.orders.index.ship')} + %form + = render ShipOrderComponent.new(order: order) + = render partial: 'admin/shared/tooltip_button', locals: {button_class: "icon-road icon_link with-tip no-text", reflex_data_id: order.id.to_s, tooltip_text: t('spree.admin.orders.index.ship'), shipment: true} + - if order.payment_required? && order.pending_payments.reject(&:requires_authorization?).any? = render partial: 'admin/shared/tooltip_button', locals: {button_class: "icon-capture icon_link no-text", button_reflex: "click->Admin::OrdersReflex#capture", reflex_data_id: order.id.to_s, tooltip_text: t('spree.admin.orders.index.capture')} diff --git a/app/views/spree/admin/shared/_order_links.html.haml b/app/views/spree/admin/shared/_order_links.html.haml index 6afd99bac2..5b46b6e4b0 100644 --- a/app/views/spree/admin/shared/_order_links.html.haml +++ b/app/views/spree/admin/shared/_order_links.html.haml @@ -6,9 +6,15 @@ %i{ "data-dropdown-target": "arrow", "data-expanded-class": "icon-caret-up", "data-collapsed-class": "icon-caret-down" } %div.menu{"data-dropdown-target": "menu"} - order_links(@order).each do |link| - %a.menu_item{ href: link[:url], target: link[:target] || "_self", data: { method: link[:method], "ujs-navigate": link[:method] ? "false" : "undefined", confirm: link[:confirm] } } - %span - %i{ class: link[:icon] } - %span=link[:name] + - if link[:name] == t(:ship_order) + %a.menu_item{ href: link[:url], target: link[:target] || "_self", data: { "modal-link-target-value": dom_id(@order, :ship), "action": "click->modal-link#open", "controller": "modal-link" } } + %span + %i{ class: link[:icon] } + %span=link[:name] + - else + %a.menu_item{ href: link[:url], target: link[:target] || "_self", data: { method: link[:method], "ujs-navigate": link[:method] ? "false" : "undefined", confirm: link[:confirm] } } + %span + %i{ class: link[:icon] } + %span=link[:name] = render 'spree/admin/shared/custom-confirm' diff --git a/config/locales/en.yml b/config/locales/en.yml index bd1e28d44e..4289cc584c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -4183,6 +4183,9 @@ See the %{link} to find out more about %{sitename}'s features and to start using add_product: cannot_add_item_to_canceled_order: "Cannot add item to canceled order" include_out_of_stock_variants: "Include variants with no available stock" + shipment: + mark_as_shipped_message_html: "This will mark the order as Shipped.
Are you sure you want to proceed?" + mark_as_shipped_label_message: "Send a shipment/pick up notification email to the customer." index: listing_orders: "Listing Orders" new_order: "New Order" diff --git a/spec/models/spree/shipment_spec.rb b/spec/models/spree/shipment_spec.rb index 114fb6d8ca..8a3d4bd195 100644 --- a/spec/models/spree/shipment_spec.rb +++ b/spec/models/spree/shipment_spec.rb @@ -353,7 +353,8 @@ describe Spree::Shipment do expect(shipment.shipped_at).to_not be_nil end - it "should send a shipment email" do + it "should send a shipment email if order.send_shipment_email is true" do + shipment.order.send_shipment_email = true mail_message = double 'Mail::Message' shipment_id = nil expect(Spree::ShipmentMailer).to receive(:shipped_email) { |*args| diff --git a/spec/system/admin/order_spec.rb b/spec/system/admin/order_spec.rb index 7722111544..379bd88e8f 100644 --- a/spec/system/admin/order_spec.rb +++ b/spec/system/admin/order_spec.rb @@ -915,6 +915,86 @@ describe ' expect(page).to have_selector 'td.tax', text: shipping_fee.included_tax_total.to_s end + context "shipping orders" do + before do + order.finalize! # ensure order has a payment to capture + order.payments << create(:check_payment, order:, amount: order.total) + order.payments.first.capture! + visit spree.edit_admin_order_path(order) + end + + it "ships the order and shipment email is sent" do + expect(order.reload.shipped?).to be false + + click_button 'Ship' + + within ".reveal-modal" do + expect(page).to have_checked_field('Send a shipment/pick up ' \ + 'notification email to the customer.') + expect { + find_button("Confirm").click + }.to enqueue_job(ActionMailer::MailDeliveryJob).exactly(:once) + end + + expect(order.reload.shipped?).to be true + expect(page).to have_text 'SHIPPED' + end + + it "ships the order without sending email" do + expect(order.reload.shipped?).to be false + + click_button 'Ship' + + within ".reveal-modal" do + uncheck 'Send a shipment/pick up notification email to the customer.' + expect { + find_button("Confirm").click + }.to_not enqueue_job(ActionMailer::MailDeliveryJob) + end + + save_screenshot('~/hello.png') + expect(order.reload.shipped?).to be true + expect(page).to have_text 'SHIPPED' + end + + context "ship order from dropdown" do + it "ships the order and sends email" do + expect(order.reload.shipped?).to be false + + find('.ofn-drop-down').click + click_link 'Ship Order' + + within ".reveal-modal" do + expect(page).to have_checked_field('Send a shipment/pick up ' \ + 'notification email to the customer.') + expect { + find_button("Confirm").click + }.to enqueue_job(ActionMailer::MailDeliveryJob).exactly(:once) + end + + expect(order.reload.shipped?).to be true + expect(page).to have_text 'SHIPPED' + end + + it "ships the order without sending email" do + expect(order.reload.shipped?).to be false + + find('.ofn-drop-down').click + click_link 'Ship Order' + + within ".reveal-modal" do + uncheck 'Send a shipment/pick up notification email to the customer.' + expect { + find_button("Confirm").click + }.to_not enqueue_job(ActionMailer::MailDeliveryJob) + end + + expect(order.reload.shipped?).to be true + expect(page).to have_text 'SHIPPED' + end + end + end + context "when an included variant has been deleted" do let!(:deleted_variant) do order.line_items.first.variant.tap(&:delete) diff --git a/spec/system/admin/orders_spec.rb b/spec/system/admin/orders_spec.rb index 9883469106..41858b9e1e 100644 --- a/spec/system/admin/orders_spec.rb +++ b/spec/system/admin/orders_spec.rb @@ -746,13 +746,36 @@ describe ' expect(page).to have_current_path spree.admin_orders_path end - it "ship order from the orders index page" do + it "ship order from the orders index page and send email" do order.payments.first.capture! login_as_admin visit spree.admin_orders_path page.find("button.icon-road").click + within ".reveal-modal" do + expect { + find_button("Confirm").click + }.to enqueue_job(ActionMailer::MailDeliveryJob).exactly(:once) + end + expect(page).to have_css "i.success" + expect(order.reload.shipments.any?(&:shipped?)).to be true + expect(order.shipment_state).to eq("shipped") + end + + it "ship order from the orders index page and do not send email" do + order.payments.first.capture! + login_as_admin + visit spree.admin_orders_path + + page.find("button.icon-road").click + + within ".reveal-modal" do + uncheck 'Send a shipment/pick up notification email to the customer.' + expect { + find_button("Confirm").click + }.not_to enqueue_job(ActionMailer::MailDeliveryJob) + end expect(page).to have_css "i.success" expect(order.reload.shipments.any?(&:shipped?)).to be true expect(order.shipment_state).to eq("shipped")