Skip to content

Commit e1f8c30

Browse files
[wip] Add orders/show/shipment component
Co-Authored-By: andrea longhi <andrea@spaghetticode.it>
1 parent 547d0d2 commit e1f8c30

File tree

11 files changed

+276
-7
lines changed

11 files changed

+276
-7
lines changed

admin/app/components/solidus_admin/orders/show/shipment/component.html.erb

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
<div class="<%= stimulus_id %>" data-controller="<%= stimulus_id %>">
22
<div class="rounded p-2">
33
<%= render component('ui/panel').new do |panel| %>
4-
<% panel.with_menu t(".edit_shipment"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %>
4+
<% panel.with_menu t(".edit"), solidus_admin.edit_order_shipments_path(@order, shipment_id: @shipment.id) %>
5+
<% panel.with_menu t(".split"), solidus_admin.split_edit_order_shipments_path(@order, shipment_id: @shipment.id) %>
6+
<% panel.with_menu t(".merge"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %>
7+
<% panel.with_menu t(".change_location"), solidus_admin.order_shipments_path(@order, shipment_id: @shipment.id) %>
58

69
<% panel.with_section(wide: true, high: true) do %>
710
<section class="border-gray-100 border-t w-full first-of-type:border-t-0 p-6">

admin/app/components/solidus_admin/orders/show/shipment/component.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ en:
55
total: Total Price
66
actions: Actions
77
none: No tracking details provided
8-
edit_shipment: Edit shipment
8+
edit: Edit
9+
split: Split
10+
merge: Merge
11+
change_location: Change Location
912
inventory_states:
1013
backordered: Backordered
1114
canceled: Canceled
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<div class="<%= stimulus_id %>" data-controller="<%= stimulus_id %>">
2+
<%= render component("orders/show").new(order: @order) %>
3+
<%= render component("ui/modal").new(title: t(".title", number: @shipment.number), close_path: close_path) do |modal| %>
4+
<table class="table-auto w-full">
5+
<thead>
6+
<tr>
7+
<th class="py-2 px-4 h-10 bg-gray-15 w-16">
8+
<%=
9+
render component("ui/forms/checkbox").new(
10+
form: form_id,
11+
"data-action": "#{stimulus_id}#selectAllRows",
12+
"data-#{stimulus_id}-target": "headerCheckbox",
13+
"aria-label": t('.select_all'),
14+
)
15+
%>
16+
</th>
17+
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none">
18+
<%= t(".product") %>
19+
</th>
20+
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16">
21+
<%= t(".quantity") %>
22+
</th>
23+
<th class="text-left body-small-bold text-gray-800 bg-gray-15 px-6 py-3 leading-none w-16 whitespace-nowrap">
24+
<%= t(".total") %>
25+
</th>
26+
</tr>
27+
</thead>
28+
<tbody>
29+
<% manifest.each do |item| %>
30+
<tr class="border-gray-100 border-t">
31+
<td class="py-2 px-4">
32+
<%=
33+
render component("ui/forms/checkbox").new(
34+
name: "selected_variants[]",
35+
form: form_id,
36+
value: item.variant.id,
37+
"data-#{stimulus_id}-target": "checkbox",
38+
)
39+
%>
40+
</td>
41+
42+
<td class="px-6 py-4">
43+
<div class="flex gap-2 grow">
44+
<% variant = item.variant %>
45+
<%= render component("ui/thumbnail").new(
46+
src: (variant.images.first || variant.product.gallery.images.first)&.url(:small),
47+
alt: variant.name
48+
) %>
49+
<div class="flex-col">
50+
<div class="leading-5 text-black body-small-bold"><%= variant.name %></div>
51+
<div class="leading-5 text-gray-500 body-small">
52+
SKU: <%= variant.sku %>
53+
<%= variant.options_text.presence&.prepend("- ") %>
54+
</div>
55+
</div>
56+
</div>
57+
</td>
58+
<td class="px-6 py-4">
59+
<span class="text-gray-500 body-small whitespace-nowrap">
60+
<%= render component("ui/forms/input").new(
61+
value: item.line_item.quantity,
62+
form: form_id,
63+
name: "variants[#{item.variant.id}][quantity]",
64+
type: :number,
65+
step: 1,
66+
min: "1",
67+
max: item.line_item.quantity,
68+
"data-#{stimulus_id}-target": "quantity",
69+
"data-action": "focus->#{stimulus_id}#selectRow",
70+
) %>
71+
</span>
72+
</td>
73+
<td class="px-6 py-4">
74+
<span class="text-gray-500 body-small"><%= item.line_item.display_amount %></span>
75+
</td>
76+
</tr>
77+
<% end %>
78+
</tbody>
79+
</table>
80+
81+
<% modal.with_actions do %>
82+
<%= form_tag '', id: form_id, "data-action": "submit->#{stimulus_id}#submit" %>
83+
<%= render component("ui/button").new(tag: :a, scheme: :secondary, href: close_path, type: :submit, text: t('.cancel')) %>
84+
<%= render_split_action_button %>
85+
<% end %>
86+
<% end %>
87+
</div>
88+
89+
90+
91+
<form action="/your_action" method="post">
92+
<input type="hidden" name="authenticity_token" value="<%= form_authenticity_token %>">
93+
<input type="text" name="variants[1][quantity]" value="12">
94+
<input type="text" name="variants[2][quantity]" value="3">
95+
<input type="submit" value="Submit">
96+
</form>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { Controller } from '@hotwired/stimulus'
2+
3+
export default class extends Controller {
4+
static targets = [
5+
"checkbox",
6+
"headerCheckbox",
7+
"quantity"
8+
]
9+
10+
selectAllRows(event) {
11+
this.checkboxTargets.forEach((checkbox) => (checkbox.checked = event.target.checked))
12+
}
13+
14+
selectRow(event) {
15+
const checkbox = this.checkboxTargets.find(selection => event.target.closest("tr").contains(selection))
16+
if (checkbox) checkbox.checked = true
17+
}
18+
19+
submit(event) {
20+
event.preventDefault()
21+
//this.quantityTargets.forEach((quantity) => (quantity.disabled = !this.checkboxTargets.find(selection => quantity.contains(selection).checked )))
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
3+
class SolidusAdmin::Orders::Show::Shipment::Split::Component < SolidusAdmin::BaseComponent
4+
include SolidusAdmin::Layout::PageHelpers
5+
6+
def initialize(shipment:)
7+
@order = shipment.order
8+
@shipment = shipment
9+
end
10+
11+
def manifest
12+
Spree::ShippingManifest.new(
13+
inventory_units: @shipment.inventory_units.where(carton_id: nil),
14+
).items.sort_by { |item| item.line_item.created_at }
15+
end
16+
17+
def form_id
18+
dom_id(@order, "#{stimulus_id}_shipment_form_#{@shipment.id}")
19+
end
20+
21+
22+
def render_split_action_button
23+
render component("ui/button").new(
24+
name: request_forgery_protection_token,
25+
value: form_authenticity_token(form_options: {
26+
action: solidus_admin.split_create_order_shipments_path(@order),
27+
method: :put,
28+
}),
29+
formaction: solidus_admin.split_create_order_shipments_path(@order),
30+
formmethod: :put,
31+
form: form_id,
32+
text: t('.split'),
33+
type: :submit,
34+
)
35+
end
36+
37+
def close_path
38+
@close_path ||= solidus_admin.order_path(@order)
39+
end
40+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
en:
2+
title: "Split shipment %{number}"
3+
submit: "Save"
4+
cancel: "Cancel"
5+
product: Product
6+
quantity: Quantity
7+
total: Total Price
8+
actions: Actions
9+
split: Split
10+
select_all: Select All
11+
inventory_states:
12+
backordered: Backordered
13+
canceled: Canceled
14+
on_hand: On hand
15+
returned: Returned
16+
shipped: Shipped

admin/app/controllers/solidus_admin/shipments_controller.rb

+49-4
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,57 @@
33
class SolidusAdmin::ShipmentsController < SolidusAdmin::BaseController
44
include Spree::Core::ControllerHelpers::StrongParameters
55

6-
before_action :load_order, :load_shipment, only: [:show, :update]
6+
before_action :load_order, :load_shipment, only: [:edit, :update, :split_edit]
7+
#before_action :load_transfer_params, only: [:split_create]
78

8-
def show
9+
def edit
910
render component('orders/show/shipment/edit').new(shipment: @shipment)
1011
end
1112

13+
def split_edit
14+
render component('orders/show/shipment/split').new(shipment: @shipment)
15+
16+
# if params[:stock_location_id]
17+
# @desired_stock_location = Spree::StockLocation.find(params[:stock_location_id])
18+
# @desired_shipment = @original_shipment.order.shipments.build(stock_location: @desired_stock_location)
19+
# end
20+
#
21+
# @desired_shipment ||= Spree::Shipment.find_by!(number: params[:target_shipment_number])
22+
#
23+
# fulfilment_changer = Spree::FulfilmentChanger.new(
24+
# current_shipment: @original_shipment,
25+
# desired_shipment: @desired_shipment,
26+
# variant: @variant,
27+
# quantity: @quantity,
28+
# track_inventory: Spree::Config.track_inventory_levels
29+
# )
30+
#
31+
# if fulfilment_changer.run!
32+
# redirect_to order_path(@order), status: :see_other, notice: t('.success')
33+
# else
34+
# flash.now[:error] = @shipment.errors[:base].join(", ") if @shipment.errors[:base].any?
35+
#
36+
# respond_to do |format|
37+
# format.html do
38+
# render component('orders/show/shipment/split').new(shipment: @shipment), status: :unprocessable_entity
39+
# end
40+
# end
41+
# end
42+
end
43+
44+
def split_create
45+
raise
46+
end
47+
1248
def update
1349
if @shipment.update_attributes_and_order(shipment_params)
1450
redirect_to order_path(@order), status: :see_other, notice: t('.success')
1551
else
16-
flash.now[:error] = @order.errors[:base].join(", ") if @order.errors[:base].any?
52+
flash.now[:error] = @shipment.errors[:base].join(", ") if @shipment.errors[:base].any?
1753

1854
respond_to do |format|
1955
format.html do
20-
render component('orders/show/shipment/edit').new(order: @order), status: :unprocessable_entity
56+
render component('orders/show/shipment/edit').new(shipment: @shipment), status: :unprocessable_entity
2157
end
2258
end
2359
end
@@ -33,6 +69,15 @@ def load_shipment
3369
@shipment = @order.shipments.find_by(id: params[:shipment_id])
3470
end
3571

72+
# def load_transfer_params
73+
# @original_shipment = Spree::Shipment.find_by!(number: params[:original_shipment_number])
74+
# @order = @original_shipment.order
75+
# @variant = Spree::Variant.find(params[:variant_id])
76+
# @quantity = params[:quantity].to_i
77+
# authorize! [:update, :destroy], @original_shipment
78+
# authorize! :create, Shipment
79+
# end
80+
3681
def shipment_params
3782
if params[:shipment] && !params[:shipment].empty?
3883
params.require(:shipment).permit(permitted_shipment_attributes)

admin/config/routes.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,12 @@
3838
resource :customer
3939
resource :ship_address, only: [:show, :edit, :update], controller: "addresses", type: "ship"
4040
resource :bill_address, only: [:show, :edit, :update], controller: "addresses", type: "bill"
41-
resource :shipments
41+
resource :shipments do
42+
member do
43+
get :split_edit
44+
put :split_create
45+
end
46+
end
4247

4348
member do
4449
get :variants_for
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
# @component "orders/show/shipment/split"
4+
class SolidusAdmin::Orders::Show::Shipment::Split::ComponentPreview < ViewComponent::Preview
5+
include SolidusAdmin::Preview
6+
7+
def overview
8+
render_with_template
9+
end
10+
11+
# @param shipment text
12+
def playground(shipment: "shipment")
13+
render component("orders/show/shipment/split").new(shipment: shipment)
14+
end
15+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div class="mb-8">
2+
<h6 class="text-gray-500 mb-3 mt-0">
3+
Scenario 1
4+
</h6>
5+
6+
<%= render current_component.new(shipment: "shipment") %>
7+
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# frozen_string_literal: true
2+
3+
require "spec_helper"
4+
5+
RSpec.describe SolidusAdmin::Orders::Show::Shipment::Split::Component, type: :component do
6+
it "renders the overview preview" do
7+
render_preview(:overview)
8+
end
9+
10+
# it "renders something useful" do
11+
# render_inline(described_class.new(shipment: "shipment"))
12+
#
13+
# expect(page).to have_text "Hello, components!"
14+
# expect(page).to have_css '.value'
15+
# end
16+
end

0 commit comments

Comments
 (0)