diff --git a/admin/app/components/solidus_admin/orders/show/shipment/component.html.erb b/admin/app/components/solidus_admin/orders/show/shipment/component.html.erb index a1651551be8..b9ab905aa66 100644 --- a/admin/app/components/solidus_admin/orders/show/shipment/component.html.erb +++ b/admin/app/components/solidus_admin/orders/show/shipment/component.html.erb @@ -1,7 +1,10 @@
<%= render component('ui/panel').new do |panel| %> - <% panel.with_menu t(".edit_shipment"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %> + <% panel.with_menu t(".edit"), solidus_admin.edit_order_shipments_path(@order, shipment_id: @shipment.id) %> + <% panel.with_menu t(".split"), solidus_admin.split_edit_order_shipments_path(@order, shipment_id: @shipment.id) %> + <% panel.with_menu t(".merge"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %> + <% panel.with_menu t(".change_location"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %> <% panel.with_section(wide: true, high: true) do %>
diff --git a/admin/app/components/solidus_admin/orders/show/shipment/component.yml b/admin/app/components/solidus_admin/orders/show/shipment/component.yml index ad59106d2cc..dd74c21c7d6 100644 --- a/admin/app/components/solidus_admin/orders/show/shipment/component.yml +++ b/admin/app/components/solidus_admin/orders/show/shipment/component.yml @@ -5,7 +5,10 @@ en: total: Total Price actions: Actions none: No tracking details provided - edit_shipment: Edit shipment + edit: Edit + split: Split + merge: Merge + change_location: Change Location inventory_states: backordered: Backordered canceled: Canceled diff --git a/admin/app/components/solidus_admin/orders/show/shipment/split/component.html.erb b/admin/app/components/solidus_admin/orders/show/shipment/split/component.html.erb new file mode 100644 index 00000000000..157d88e0f18 --- /dev/null +++ b/admin/app/components/solidus_admin/orders/show/shipment/split/component.html.erb @@ -0,0 +1,96 @@ +
+ <%= render component("orders/show").new(order: @order) %> + <%= render component("ui/modal").new(title: t(".title", number: @shipment.number), close_path: close_path) do |modal| %> + + + + + + + + + + + <% manifest.each do |item| %> + + + + + + + + <% end %> + +
+ <%= + render component("ui/forms/checkbox").new( + form: form_id, + "data-action": "#{stimulus_id}#selectAllRows", + "data-#{stimulus_id}-target": "headerCheckbox", + "aria-label": t('.select_all'), + ) + %> + + <%= t(".product") %> + + <%= t(".quantity") %> + + <%= t(".total") %> +
+ <%= + render component("ui/forms/checkbox").new( + name: "selected_variants[]", + form: form_id, + value: item.variant.id, + "data-#{stimulus_id}-target": "checkbox", + ) + %> + +
+ <% variant = item.variant %> + <%= render component("ui/thumbnail").new( + src: (variant.images.first || variant.product.gallery.images.first)&.url(:small), + alt: variant.name + ) %> +
+
<%= variant.name %>
+
+ SKU: <%= variant.sku %> + <%= variant.options_text.presence&.prepend("- ") %> +
+
+
+
+ + <%= render component("ui/forms/input").new( + value: item.line_item.quantity, + form: form_id, + name: "variants[#{item.variant.id}][quantity]", + type: :number, + step: 1, + min: "1", + max: item.line_item.quantity, + "data-#{stimulus_id}-target": "quantity", + "data-action": "focus->#{stimulus_id}#selectRow", + ) %> + + + <%= item.line_item.display_amount %> +
+ + <% modal.with_actions do %> + <%= form_tag '', id: form_id, "data-action": "submit->#{stimulus_id}#submit" %> + <%= render component("ui/button").new(tag: :a, scheme: :secondary, href: close_path, type: :submit, text: t('.cancel')) %> + <%= render_split_action_button %> + <% end %> + <% end %> +
+ + + +
+ + + + +
diff --git a/admin/app/components/solidus_admin/orders/show/shipment/split/component.js b/admin/app/components/solidus_admin/orders/show/shipment/split/component.js new file mode 100644 index 00000000000..d1ff8d5d93b --- /dev/null +++ b/admin/app/components/solidus_admin/orders/show/shipment/split/component.js @@ -0,0 +1,23 @@ +import { Controller } from '@hotwired/stimulus' + +export default class extends Controller { + static targets = [ + "checkbox", + "headerCheckbox", + "quantity" + ] + + selectAllRows(event) { + this.checkboxTargets.forEach((checkbox) => (checkbox.checked = event.target.checked)) + } + + selectRow(event) { + const checkbox = this.checkboxTargets.find(selection => event.target.closest("tr").contains(selection)) + if (checkbox) checkbox.checked = true + } + + submit(event) { + event.preventDefault() + //this.quantityTargets.forEach((quantity) => (quantity.disabled = !this.checkboxTargets.find(selection => quantity.contains(selection).checked ))) + } +} diff --git a/admin/app/components/solidus_admin/orders/show/shipment/split/component.rb b/admin/app/components/solidus_admin/orders/show/shipment/split/component.rb new file mode 100644 index 00000000000..c555cea3a79 --- /dev/null +++ b/admin/app/components/solidus_admin/orders/show/shipment/split/component.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +class SolidusAdmin::Orders::Show::Shipment::Split::Component < SolidusAdmin::BaseComponent + include SolidusAdmin::Layout::PageHelpers + + def initialize(shipment:) + @order = shipment.order + @shipment = shipment + end + + def manifest + Spree::ShippingManifest.new( + inventory_units: @shipment.inventory_units.where(carton_id: nil), + ).items.sort_by { |item| item.line_item.created_at } + end + + def form_id + dom_id(@order, "#{stimulus_id}_shipment_form_#{@shipment.id}") + end + + + def render_split_action_button + render component("ui/button").new( + name: request_forgery_protection_token, + value: form_authenticity_token(form_options: { + action: solidus_admin.split_create_order_shipments_path(@order), + method: :put, + }), + formaction: solidus_admin.split_create_order_shipments_path(@order), + formmethod: :put, + form: form_id, + text: t('.split'), + type: :submit, + ) + end + + def close_path + @close_path ||= solidus_admin.order_path(@order) + end +end diff --git a/admin/app/components/solidus_admin/orders/show/shipment/split/component.yml b/admin/app/components/solidus_admin/orders/show/shipment/split/component.yml new file mode 100644 index 00000000000..1c5a2184577 --- /dev/null +++ b/admin/app/components/solidus_admin/orders/show/shipment/split/component.yml @@ -0,0 +1,16 @@ +en: + title: "Split shipment %{number}" + submit: "Save" + cancel: "Cancel" + product: Product + quantity: Quantity + total: Total Price + actions: Actions + split: Split + select_all: Select All + inventory_states: + backordered: Backordered + canceled: Canceled + on_hand: On hand + returned: Returned + shipped: Shipped diff --git a/admin/app/controllers/solidus_admin/shipments_controller.rb b/admin/app/controllers/solidus_admin/shipments_controller.rb index 54680638f2b..532267b47b8 100644 --- a/admin/app/controllers/solidus_admin/shipments_controller.rb +++ b/admin/app/controllers/solidus_admin/shipments_controller.rb @@ -3,21 +3,57 @@ class SolidusAdmin::ShipmentsController < SolidusAdmin::BaseController include Spree::Core::ControllerHelpers::StrongParameters - before_action :load_order, :load_shipment, only: [:show, :update] + before_action :load_order, :load_shipment, only: [:edit, :update, :split_edit] + #before_action :load_transfer_params, only: [:split_create] - def show + def edit render component('orders/show/shipment/edit').new(shipment: @shipment) end + def split_edit + render component('orders/show/shipment/split').new(shipment: @shipment) + + # if params[:stock_location_id] + # @desired_stock_location = Spree::StockLocation.find(params[:stock_location_id]) + # @desired_shipment = @original_shipment.order.shipments.build(stock_location: @desired_stock_location) + # end + # + # @desired_shipment ||= Spree::Shipment.find_by!(number: params[:target_shipment_number]) + # + # fulfilment_changer = Spree::FulfilmentChanger.new( + # current_shipment: @original_shipment, + # desired_shipment: @desired_shipment, + # variant: @variant, + # quantity: @quantity, + # track_inventory: Spree::Config.track_inventory_levels + # ) + # + # if fulfilment_changer.run! + # redirect_to order_path(@order), status: :see_other, notice: t('.success') + # else + # flash.now[:error] = @shipment.errors[:base].join(", ") if @shipment.errors[:base].any? + # + # respond_to do |format| + # format.html do + # render component('orders/show/shipment/split').new(shipment: @shipment), status: :unprocessable_entity + # end + # end + # end + end + + def split_create + raise + end + def update if @shipment.update_attributes_and_order(shipment_params) redirect_to order_path(@order), status: :see_other, notice: t('.success') else - flash.now[:error] = @order.errors[:base].join(", ") if @order.errors[:base].any? + flash.now[:error] = @shipment.errors[:base].join(", ") if @shipment.errors[:base].any? respond_to do |format| format.html do - render component('orders/show/shipment/edit').new(order: @order), status: :unprocessable_entity + render component('orders/show/shipment/edit').new(shipment: @shipment), status: :unprocessable_entity end end end @@ -33,6 +69,15 @@ def load_shipment @shipment = @order.shipments.find_by(id: params[:shipment_id]) end + # def load_transfer_params + # @original_shipment = Spree::Shipment.find_by!(number: params[:original_shipment_number]) + # @order = @original_shipment.order + # @variant = Spree::Variant.find(params[:variant_id]) + # @quantity = params[:quantity].to_i + # authorize! [:update, :destroy], @original_shipment + # authorize! :create, Shipment + # end + def shipment_params if params[:shipment] && !params[:shipment].empty? params.require(:shipment).permit(permitted_shipment_attributes) diff --git a/admin/config/routes.rb b/admin/config/routes.rb index 3f3a57610fe..0fd49c33b41 100644 --- a/admin/config/routes.rb +++ b/admin/config/routes.rb @@ -38,7 +38,12 @@ resource :customer resource :ship_address, only: [:show, :edit, :update], controller: "addresses", type: "ship" resource :bill_address, only: [:show, :edit, :update], controller: "addresses", type: "bill" - resource :shipments + resource :shipments do + member do + get :split_edit + put :split_create + end + end member do get :variants_for diff --git a/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview.rb b/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview.rb new file mode 100644 index 00000000000..572e06f7c37 --- /dev/null +++ b/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +# @component "orders/show/shipment/split" +class SolidusAdmin::Orders::Show::Shipment::Split::ComponentPreview < ViewComponent::Preview + include SolidusAdmin::Preview + + def overview + render_with_template + end + + # @param shipment text + def playground(shipment: "shipment") + render component("orders/show/shipment/split").new(shipment: shipment) + end +end diff --git a/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview/overview.html.erb b/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview/overview.html.erb new file mode 100644 index 00000000000..66873ba36a2 --- /dev/null +++ b/admin/spec/components/previews/solidus_admin/orders/show/shipment/split/component_preview/overview.html.erb @@ -0,0 +1,7 @@ +
+
+ Scenario 1 +
+ + <%= render current_component.new(shipment: "shipment") %> +
diff --git a/admin/spec/components/solidus_admin/orders/show/shipment/split/component_spec.rb b/admin/spec/components/solidus_admin/orders/show/shipment/split/component_spec.rb new file mode 100644 index 00000000000..f03db69b5c9 --- /dev/null +++ b/admin/spec/components/solidus_admin/orders/show/shipment/split/component_spec.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +require "spec_helper" + +RSpec.describe SolidusAdmin::Orders::Show::Shipment::Split::Component, type: :component do + it "renders the overview preview" do + render_preview(:overview) + end + + # it "renders something useful" do + # render_inline(described_class.new(shipment: "shipment")) + # + # expect(page).to have_text "Hello, components!" + # expect(page).to have_css '.value' + # end +end