solidus_product_assembly 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +35 -0
- data/.gem_release.yml +5 -0
- data/.github/dependabot.yml +7 -0
- data/.github/stale.yml +17 -0
- data/.gitignore +14 -2
- data/.rspec +2 -2
- data/.rubocop.yml +4 -0
- data/.rubocop_todo.yml +192 -0
- data/CHANGELOG.md +19 -0
- data/Gemfile +21 -9
- data/LICENSE +26 -0
- data/README.md +52 -18
- data/Rakefile +4 -19
- data/app/controllers/spree/admin/parts_controller.rb +13 -11
- data/app/decorators/controllers/solidus_product_assembly/spree/checkout_controller_decorator.rb +13 -0
- data/app/decorators/helpers/solidus_product_assembly/spree/admin/orders_helper_decorator.rb +19 -0
- data/app/decorators/models/solidus_product_assembly/spree/inventory_unit_decorator.rb +19 -0
- data/app/decorators/models/solidus_product_assembly/spree/line_item_decorator.rb +52 -0
- data/app/decorators/models/solidus_product_assembly/spree/product_decorator.rb +70 -0
- data/app/decorators/models/solidus_product_assembly/spree/return_item_decorator.rb +15 -0
- data/app/decorators/models/solidus_product_assembly/spree/shipment_decorator.rb +55 -0
- data/app/decorators/models/solidus_product_assembly/spree/stock/availability_validator_decorator.rb +37 -0
- data/app/decorators/models/solidus_product_assembly/spree/stock/inventory_unit_builder_decorator.rb +39 -0
- data/app/decorators/models/solidus_product_assembly/spree/stock/inventory_units_finalizer_decorator.rb +33 -0
- data/app/decorators/models/solidus_product_assembly/spree/stock/inventory_validator_decorator.rb +22 -0
- data/app/decorators/models/solidus_product_assembly/spree/variant_decorator.rb +26 -0
- data/app/models/spree/assemblies_part.rb +6 -4
- data/app/models/spree/calculator/returns/assemblies_default_refund_amount.rb +17 -0
- data/app/models/spree/order_inventory_assembly.rb +11 -2
- data/app/overrides/add_admin_product_form_fields.rb +7 -5
- data/app/overrides/add_admin_tabs.rb +7 -5
- data/app/overrides/add_line_item_description.rb +7 -5
- data/app/overrides/spree/admin/orders/_carton_manifest/_assembly_parts_price.html.erb.deface +9 -0
- data/app/overrides/spree/admin/orders/_carton_manifest/_assembly_parts_total_price.html.erb.deface +9 -0
- data/app/overrides/spree/admin/orders/_shipment/stock_contents.html.erb.deface +7 -1
- data/app/overrides/spree/products/show/add_links_to_parts.html.erb.deface +2 -2
- data/app/views/spree/admin/orders/_assemblies.html.erb +8 -17
- data/app/views/spree/admin/orders/_stock_contents.html.erb +2 -62
- data/app/views/spree/admin/orders/_stock_contents_2_3.html.erb +69 -0
- data/app/views/spree/admin/orders/_stock_contents_2_4.html.erb +70 -0
- data/app/views/spree/admin/orders/_stock_item.html.erb +13 -10
- data/app/views/spree/admin/parts/_parts_table.html.erb +17 -11
- data/app/views/spree/admin/parts/available.html.erb +10 -8
- data/app/views/spree/admin/parts/available.js.erb +9 -7
- data/app/views/spree/admin/parts/index.html.erb +1 -1
- data/app/views/spree/admin/products/_product_assembly_fields.html.erb +2 -2
- data/app/views/spree/admin/shared/_product_assembly_product_tabs.html.erb +1 -1
- data/app/views/spree/api/line_items/show.v1.rabl +27 -0
- data/app/views/spree/checkout/_line_item_manifest.html.erb +3 -1
- data/bin/console +17 -0
- data/bin/rails +12 -4
- data/bin/setup +8 -0
- data/config/routes.rb +2 -2
- data/db/migrate/20091028152124_add_many_to_many_relation_to_products.rb +7 -5
- data/db/migrate/20091029165620_add_parts_fields_to_products.rb +18 -16
- data/db/migrate/20120316141830_namespace_product_assembly_for_spree_one.rb +3 -1
- data/db/migrate/20140620223938_add_id_to_spree_assemblies_parts.rb +4 -2
- data/lib/generators/solidus_product_assembly/install/install_generator.rb +13 -8
- data/lib/solidus_product_assembly/engine.rb +11 -8
- data/lib/solidus_product_assembly/testing_support/factories.rb +4 -0
- data/lib/solidus_product_assembly/version.rb +3 -1
- data/lib/solidus_product_assembly.rb +5 -1
- data/lib/tasks/spree2_upgrade.rake +12 -12
- data/solidus_product_assembly.gemspec +25 -20
- data/spec/features/admin/orders_spec.rb +114 -16
- data/spec/features/admin/parts_spec.rb +5 -3
- data/spec/features/admin/return_items_spec.rb +151 -0
- data/spec/features/checkout_spec.rb +103 -21
- data/spec/models/spree/assemblies_part_spec.rb +3 -1
- data/spec/models/spree/inventory_unit_spec.rb +15 -6
- data/spec/models/spree/line_item_spec.rb +6 -4
- data/spec/models/spree/order_contents_spec.rb +6 -5
- data/spec/models/spree/order_inventory_assembly_spec.rb +8 -6
- data/spec/models/spree/order_inventory_spec.rb +7 -3
- data/spec/models/spree/product_spec.rb +15 -14
- data/spec/models/spree/shipment_spec.rb +20 -13
- data/spec/models/spree/stock/availability_validator_spec.rb +22 -33
- data/spec/models/spree/stock/coordinator_spec.rb +11 -3
- data/spec/models/spree/stock/inventory_unit_builder_spec.rb +5 -7
- data/spec/models/spree/variant_spec.rb +3 -1
- data/spec/spec_helper.rb +18 -47
- data/spec/support/shared_contexts/order_with_bundle.rb +2 -0
- metadata +80 -102
- data/.travis.yml +0 -21
- data/LICENSE.md +0 -13
- data/app/controllers/spree/checkout_controller_decorator.rb +0 -9
- data/app/helpers/spree/admin/orders_helper_decorator.rb +0 -9
- data/app/models/spree/inventory_unit_decorator.rb +0 -13
- data/app/models/spree/line_item_decorator.rb +0 -44
- data/app/models/spree/product_decorator.rb +0 -56
- data/app/models/spree/shipment_decorator.rb +0 -50
- data/app/models/spree/stock/availability_validator.rb +0 -28
- data/app/models/spree/stock/inventory_unit_builder_decorator.rb +0 -30
- data/app/models/spree/stock/inventory_validator_decorator.rb +0 -12
- data/app/models/spree/variant_decorator.rb +0 -13
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module LineItemDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
base.class_eval do
|
8
|
+
scope :assemblies, -> { joins(product: :parts).distinct }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def any_units_shipped?
|
13
|
+
inventory_units.any?(&:shipped?)
|
14
|
+
end
|
15
|
+
|
16
|
+
# The parts that apply to this particular LineItem. Usually `product#parts`, but
|
17
|
+
# provided as a hook if you want to override and customize the parts for a specific
|
18
|
+
# LineItem.
|
19
|
+
delegate :parts, to: :product
|
20
|
+
|
21
|
+
# The number of the specified variant that make up this LineItem. By default, calls
|
22
|
+
# `product#count_of`, but provided as a hook if you want to override and customize
|
23
|
+
# the parts available for a specific LineItem. Note that if you only customize whether
|
24
|
+
# a variant is included in the LineItem, and don't customize the quantity of that part
|
25
|
+
# per LineItem, you shouldn't need to override this method.
|
26
|
+
delegate :count_of, to: :product
|
27
|
+
|
28
|
+
def quantity_by_variant
|
29
|
+
if product.assembly?
|
30
|
+
{}.tap { |hash| product.assemblies_parts.each { |ap| hash[ap.part] = ap.count * quantity } }
|
31
|
+
else
|
32
|
+
{ variant => quantity }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def update_inventory
|
39
|
+
saved_changes = respond_to?(:saved_changes?) ? saved_changes? : changed?
|
40
|
+
if (saved_changes || target_shipment.present?) && order.has_checkout_step?("delivery")
|
41
|
+
if product.assembly?
|
42
|
+
::Spree::OrderInventoryAssembly.new(self).verify(target_shipment)
|
43
|
+
else
|
44
|
+
::Spree::OrderInventory.new(order, self).verify(target_shipment)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
::Spree::LineItem.prepend self
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module ProductDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
base.class_eval do
|
8
|
+
has_and_belongs_to_many :parts, class_name: "Spree::Variant",
|
9
|
+
join_table: "spree_assemblies_parts",
|
10
|
+
foreign_key: "assembly_id", association_foreign_key: "part_id"
|
11
|
+
|
12
|
+
has_many :assemblies_parts, class_name: "Spree::AssembliesPart",
|
13
|
+
foreign_key: "assembly_id"
|
14
|
+
|
15
|
+
scope :individual_saled, -> { where(individual_sale: true) }
|
16
|
+
|
17
|
+
scope :search_can_be_part, ->(query){
|
18
|
+
not_deleted.available.joins(:master)
|
19
|
+
.where(arel_table["name"].matches("%#{query}%").or(::Spree::Variant.arel_table["sku"].matches("%#{query}%")))
|
20
|
+
.where(can_be_part: true)
|
21
|
+
.limit(30)
|
22
|
+
}
|
23
|
+
|
24
|
+
validate :assembly_cannot_be_part, if: :assembly?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_part(variant, count = 1)
|
29
|
+
set_part_count(variant, count_of(variant) + count)
|
30
|
+
end
|
31
|
+
|
32
|
+
def remove_part(variant)
|
33
|
+
set_part_count(variant, 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_part_count(variant, count)
|
37
|
+
ap = assemblies_part(variant)
|
38
|
+
if count > 0
|
39
|
+
ap.count = count
|
40
|
+
ap.save
|
41
|
+
else
|
42
|
+
ap.destroy
|
43
|
+
end
|
44
|
+
reload
|
45
|
+
end
|
46
|
+
|
47
|
+
def assembly?
|
48
|
+
parts.present?
|
49
|
+
end
|
50
|
+
|
51
|
+
def count_of(variant)
|
52
|
+
ap = assemblies_part(variant)
|
53
|
+
# This checks persisted because the default count is 1
|
54
|
+
ap.persisted? ? ap.count : 0
|
55
|
+
end
|
56
|
+
|
57
|
+
def assembly_cannot_be_part
|
58
|
+
errors.add(:can_be_part, I18n.t('spree.assembly_cannot_be_part')) if can_be_part
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def assemblies_part(variant)
|
64
|
+
::Spree::AssembliesPart.get(id, variant.id)
|
65
|
+
end
|
66
|
+
|
67
|
+
::Spree::Product.prepend self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module ReturnItemDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
base.class_eval do
|
8
|
+
self.refund_amount_calculator = ::Spree::Calculator::Returns::AssembliesDefaultRefundAmount
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
::Spree::ReturnItem.prepend self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module ShipmentDecorator
|
6
|
+
# Overriden from Spree core as a product bundle part should not be put
|
7
|
+
# together with an individual product purchased (even though they're the
|
8
|
+
# very same variant) That is so we can tell the store admin which units
|
9
|
+
# were purchased individually and which ones as parts of the bundle
|
10
|
+
#
|
11
|
+
# Account for situations where we can't track the line_item for a variant.
|
12
|
+
# This should avoid exceptions when users upgrade from spree 1.3
|
13
|
+
#
|
14
|
+
# TODO Can possibly be removed as well. We already override the manifest
|
15
|
+
# partial so we can get the product there
|
16
|
+
def manifest
|
17
|
+
items = []
|
18
|
+
inventory_units.joins(:variant).includes(:variant, :line_item).group_by(&:variant).each do |variant, units|
|
19
|
+
units.group_by(&:line_item).each do |line_item, units|
|
20
|
+
states = {}
|
21
|
+
units.group_by(&:state).each { |state, iu| states[state] = iu.count }
|
22
|
+
line_item ||= order.find_line_item_by_variant(variant)
|
23
|
+
|
24
|
+
part = line_item ? line_item.product.assembly? : false
|
25
|
+
items << OpenStruct.new(part: part,
|
26
|
+
product: line_item.try(:product),
|
27
|
+
line_item: line_item,
|
28
|
+
variant: variant,
|
29
|
+
quantity: units.length,
|
30
|
+
states: states)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
items
|
34
|
+
end
|
35
|
+
|
36
|
+
# There might be scenarios where we don't want to display every single
|
37
|
+
# variant on the shipment. e.g. when ordering a product bundle that includes
|
38
|
+
# 5 other parts. Frontend users should only see the product bundle as a
|
39
|
+
# single item to ship
|
40
|
+
def line_item_manifest
|
41
|
+
inventory_units.includes(:line_item, :variant).group_by(&:line_item).map do |line_item, units|
|
42
|
+
states = {}
|
43
|
+
units.group_by(&:state).each { |state, iu| states[state] = iu.count }
|
44
|
+
OpenStruct.new(line_item: line_item, variant: line_item.variant, quantity: units.length, states: states)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def inventory_units_for_item(line_item, variant)
|
49
|
+
inventory_units.where(line_item_id: line_item.id, variant_id: variant.id)
|
50
|
+
end
|
51
|
+
|
52
|
+
::Spree::Shipment.prepend self
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/app/decorators/models/solidus_product_assembly/spree/stock/availability_validator_decorator.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module Stock
|
6
|
+
# Overridden from spree core to make it also check for assembly parts stock
|
7
|
+
module AvailabilityValidatorDecorator
|
8
|
+
def validate(line_item)
|
9
|
+
if line_item.product.assembly?
|
10
|
+
line_item.quantity_by_variant.each do |variant, variant_quantity|
|
11
|
+
inventory_units = line_item.inventory_units.where(variant: variant).count
|
12
|
+
quantity = variant_quantity - inventory_units
|
13
|
+
next if quantity <= 0
|
14
|
+
next unless variant
|
15
|
+
|
16
|
+
quantifier = ::Spree::Stock::Quantifier.new(variant)
|
17
|
+
|
18
|
+
next if quantifier.can_supply? quantity
|
19
|
+
|
20
|
+
display_name = variant.name.to_s
|
21
|
+
display_name += %{ (#{variant.options_text})} if variant.options_text.present?
|
22
|
+
|
23
|
+
line_item.errors[:quantity] << I18n.t(
|
24
|
+
'spree.selected_quantity_not_available',
|
25
|
+
item: display_name.inspect
|
26
|
+
)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
::Spree::Stock::AvailabilityValidator.prepend self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/app/decorators/models/solidus_product_assembly/spree/stock/inventory_unit_builder_decorator.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module Stock
|
6
|
+
module InventoryUnitBuilderDecorator
|
7
|
+
def units
|
8
|
+
@order.line_items.flat_map do |line_item|
|
9
|
+
line_item.quantity_by_variant.flat_map do |variant, quantity|
|
10
|
+
quantity.times.map { build_inventory_unit(variant, line_item) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_inventory_unit(variant, line_item)
|
16
|
+
inventory_unit_attributes = {
|
17
|
+
pending: true,
|
18
|
+
variant: variant,
|
19
|
+
line_item: line_item,
|
20
|
+
}
|
21
|
+
if ::Spree.solidus_gem_version < Gem::Version.new('2.5.x')
|
22
|
+
inventory_unit_attributes[:order] = @order
|
23
|
+
end
|
24
|
+
@order.inventory_units.includes(
|
25
|
+
variant: {
|
26
|
+
product: {
|
27
|
+
shipping_category: {
|
28
|
+
shipping_methods: [:calculator, { zones: :zone_members }]
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
).build(inventory_unit_attributes)
|
33
|
+
end
|
34
|
+
|
35
|
+
::Spree::Stock::InventoryUnitBuilder.prepend self
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module Stock
|
6
|
+
module InventoryUnitsFinalizerDecorator
|
7
|
+
private
|
8
|
+
|
9
|
+
def unstock_inventory_units
|
10
|
+
inventory_units.group_by(&:shipment_id).each_value do |inventory_units_for_shipment|
|
11
|
+
inventory_units_for_shipment.group_by(&:line_item_id).each_value do |units|
|
12
|
+
shipment = units.first.shipment
|
13
|
+
line_item = units.first.line_item
|
14
|
+
|
15
|
+
if line_item.product.assembly?
|
16
|
+
units.group_by(&:variant_id).each_value do |units_for_part|
|
17
|
+
part = units_for_part.first.variant
|
18
|
+
shipment.stock_location.unstock part, units_for_part.count, shipment
|
19
|
+
end
|
20
|
+
else
|
21
|
+
shipment.stock_location.unstock line_item.variant, units.count, shipment
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if ::Spree.solidus_gem_version >= Gem::Version.new('2.8')
|
28
|
+
::Spree::Stock::InventoryUnitsFinalizer.prepend self
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/app/decorators/models/solidus_product_assembly/spree/stock/inventory_validator_decorator.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module Stock
|
6
|
+
module InventoryValidatorDecorator
|
7
|
+
def validate(line_item)
|
8
|
+
total_quantity = line_item.quantity_by_variant.values.sum
|
9
|
+
|
10
|
+
if line_item.inventory_units.count != total_quantity
|
11
|
+
line_item.errors[:inventory] << I18n.t(
|
12
|
+
'spree.inventory_not_available',
|
13
|
+
item: line_item.variant.name
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
::Spree::Stock::InventoryValidator.prepend self
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SolidusProductAssembly
|
4
|
+
module Spree
|
5
|
+
module VariantDecorator
|
6
|
+
def self.prepended(base)
|
7
|
+
base.class_eval do
|
8
|
+
has_and_belongs_to_many :assemblies,
|
9
|
+
class_name: "Spree::Product",
|
10
|
+
join_table: "spree_assemblies_parts",
|
11
|
+
foreign_key: "part_id", association_foreign_key: "assembly_id"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def assemblies_for(products)
|
16
|
+
assemblies.where(id: products)
|
17
|
+
end
|
18
|
+
|
19
|
+
def part?
|
20
|
+
assemblies.exists?
|
21
|
+
end
|
22
|
+
|
23
|
+
::Spree::Variant.prepend self
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Spree
|
2
|
-
class AssembliesPart <
|
3
|
-
belongs_to :assembly, :
|
4
|
-
|
4
|
+
class AssembliesPart < ApplicationRecord
|
5
|
+
belongs_to :assembly, class_name: "Spree::Product",
|
6
|
+
foreign_key: "assembly_id", touch: true
|
5
7
|
|
6
|
-
belongs_to :part, :
|
8
|
+
belongs_to :part, class_name: "Spree::Variant", foreign_key: "part_id"
|
7
9
|
|
8
10
|
def self.get(assembly_id, part_id)
|
9
11
|
find_or_initialize_by(assembly_id: assembly_id, part_id: part_id)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spree
|
4
|
+
module Calculator::Returns
|
5
|
+
class AssembliesDefaultRefundAmount < DefaultRefundAmount
|
6
|
+
def compute(return_item)
|
7
|
+
percentage = return_item.inventory_unit.percentage_of_line_item
|
8
|
+
if percentage < 1 && return_item.variant.part?
|
9
|
+
line_item = return_item.inventory_unit.line_item
|
10
|
+
(super * percentage * line_item.quantity).round 4, :up
|
11
|
+
else
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Spree
|
2
4
|
# This class has basically the same functionality of Spree core OrderInventory
|
3
5
|
# except that it takes account of bundle parts and properly creates and removes
|
@@ -19,8 +21,14 @@ module Spree
|
|
19
21
|
self.variant = part
|
20
22
|
|
21
23
|
if existing_parts < total_parts
|
22
|
-
|
23
|
-
|
24
|
+
if method(:determine_target_shipment).arity == 1
|
25
|
+
quantity = total_parts - existing_parts
|
26
|
+
shipment = determine_target_shipment(quantity) unless shipment
|
27
|
+
add_to_shipment(shipment, quantity)
|
28
|
+
else
|
29
|
+
shipment = determine_target_shipment unless shipment
|
30
|
+
add_to_shipment(shipment, total_parts - existing_parts)
|
31
|
+
end
|
24
32
|
elsif existing_parts > total_parts
|
25
33
|
quantity = existing_parts - total_parts
|
26
34
|
if shipment.present?
|
@@ -28,6 +36,7 @@ module Spree
|
|
28
36
|
else
|
29
37
|
order.shipments.each do |shipment|
|
30
38
|
break if quantity == 0
|
39
|
+
|
31
40
|
quantity -= remove_from_shipment(shipment, quantity)
|
32
41
|
end
|
33
42
|
end
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Deface::Override.new(virtual_path: "spree/admin/products/_form",
|
4
|
+
name: "product_assembly_admin_product_form_right",
|
5
|
+
insert_after: "[data-hook='admin_product_form_right'], #admin_product_form_right[data-hook]",
|
6
|
+
partial: "spree/admin/products/product_assembly_fields",
|
7
|
+
disabled: false)
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Deface::Override.new(virtual_path: "spree/admin/shared/_product_tabs",
|
4
|
+
name: "product_assembly_admin_product_tabs",
|
5
|
+
insert_bottom: "[data-hook='admin_product_tabs']",
|
6
|
+
partial: "spree/admin/shared/product_assembly_product_tabs",
|
7
|
+
disabled: false)
|
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Deface::Override.new(virtual_path: "spree/orders/_line_item",
|
4
|
+
name: "product_assembly_cart_item_description",
|
5
|
+
insert_bottom: "[data-hook='cart_item_description']",
|
6
|
+
partial: "spree/orders/cart_description",
|
7
|
+
disabled: false)
|
@@ -1,2 +1,8 @@
|
|
1
1
|
<!-- replace_contents '.stock-contents tbody' -->
|
2
|
-
|
2
|
+
<% if Spree.solidus_gem_version < Gem::Version.new('2.4') %>
|
3
|
+
<%= render "stock_contents_2_3", shipment: shipment %>
|
4
|
+
<% elsif Spree.solidus_gem_version < Gem::Version.new('2.5') %>
|
5
|
+
<%= render "stock_contents_2_4", shipment: shipment %>
|
6
|
+
<% else %>
|
7
|
+
<%= render "stock_contents", shipment: shipment %>
|
8
|
+
<% end %>
|
@@ -1,14 +1,14 @@
|
|
1
1
|
<!-- insert_after '#cart-form' -->
|
2
2
|
<% if @product.parts.any?(&:in_stock?) %>
|
3
3
|
|
4
|
-
<h6><%=
|
4
|
+
<h6><%= t('spree.parts_included') %></h6>
|
5
5
|
|
6
6
|
<ul id="products" class="inline product-listing" data-hook>
|
7
7
|
<% @product.parts.each do |variant| %>
|
8
8
|
<% if variant.in_stock? %>
|
9
9
|
<li id="product_<%= variant.product.id %>" class="columns three <%= cycle("alpha", "secondary", "", "omega secondary") %>" data-hook="products_list_item" itemscope itemtype="http://schema.org/Product">
|
10
10
|
<div class="product-image">
|
11
|
-
<%=
|
11
|
+
<%= render 'spree/shared/image', image: variant.product.gallery.images.first, size: :small %>
|
12
12
|
</div>
|
13
13
|
<%= link_to truncate(variant.product.name, :length => 50), variant.product, :class => 'info', :itemprop => "name", :title => variant.product.name %>
|
14
14
|
<% if variant.product.individual_sale? %>
|
@@ -1,15 +1,16 @@
|
|
1
1
|
<% if order.line_items.assemblies.any? %>
|
2
2
|
<fieldset class="no-border-bottom">
|
3
3
|
<legend align="center" class="" data-hook="">
|
4
|
-
<%=
|
4
|
+
<%= t('spree.product_bundles') %>
|
5
5
|
</legend>
|
6
6
|
</fieldset>
|
7
7
|
|
8
8
|
<table class="product-bundles index" data-hook="line-items">
|
9
9
|
<colgroup>
|
10
|
-
<col style="width:
|
11
|
-
<col style="width:
|
12
|
-
<col style="width:
|
10
|
+
<col style="width: 15%;" />
|
11
|
+
<col style="width: 40%;" />
|
12
|
+
<col style="width: 15%;" />
|
13
|
+
<col style="width: 15%;" />
|
13
14
|
<col style="width: 15%;" />
|
14
15
|
</colgroup>
|
15
16
|
|
@@ -19,14 +20,15 @@
|
|
19
20
|
<th><%= Spree::LineItem.human_attribute_name(:price) %></th>
|
20
21
|
<th><%= Spree::LineItem.human_attribute_name(:quantity) %></th>
|
21
22
|
<th><%= Spree::LineItem.human_attribute_name(:total) %></th>
|
22
|
-
<th class="orders-actions actions" data-hook="admin_order_form_line_items_header_actions"> </th>
|
23
23
|
</tr>
|
24
24
|
</thead>
|
25
25
|
|
26
26
|
<tbody>
|
27
27
|
<% order.line_items.assemblies.each do |item| %>
|
28
28
|
<%= content_tag :tr, class: 'line-item', id: "line-item-#{item.id}", data: { line_item_id: item.id } do %>
|
29
|
-
<td class="line-item-image"><%=
|
29
|
+
<td class="line-item-image"><%= render 'spree/shared/image',
|
30
|
+
image: (item.variant.gallery.images.first || item.variant.product.gallery.images.first),
|
31
|
+
size: :mini %></td>
|
30
32
|
<td class="line-item-name">
|
31
33
|
<%= item.variant.product.name %><br><%= "(" + variant_options(item.variant) + ")" unless item.variant.option_values.empty? %>
|
32
34
|
<% if item.variant.sku.present? %>
|
@@ -37,18 +39,7 @@
|
|
37
39
|
<td class="line-item-qty-show align-center">
|
38
40
|
<%= item.quantity %>
|
39
41
|
</td>
|
40
|
-
<td class="line-item-qty-edit">
|
41
|
-
<%= number_field_tag :quantity, item.quantity, :min => 0, :class => "line_item_quantity", :size => 5 %>
|
42
|
-
</td>
|
43
42
|
<td class="line-item-total align-center"><%= line_item_shipment_price(item, item.quantity) %></td>
|
44
|
-
<td class="cart-line-item-delete actions" data-hook="cart_line_item_delete">
|
45
|
-
<% if can? :update, item %>
|
46
|
-
<%= link_to '', '#', :class => 'save-line-item fa fa-ok no-text with-tip', :title => Spree.t('actions.save') %>
|
47
|
-
<%= link_to '', '#', :class => 'cancel-line-item fa fa-cancel no-text with-tip', :title => Spree.t('actions.cancel') %>
|
48
|
-
<%= link_to '', '#', :class => 'edit-line-item fa fa-edit no-text with-tip', :title => Spree.t('actions.edit') %>
|
49
|
-
<%= link_to '', '#', :class => 'delete-line-item fa fa-trash no-text with-tip', :title => Spree.t('actions.delete') %>
|
50
|
-
<% end %>
|
51
|
-
</td>
|
52
43
|
<% end %>
|
53
44
|
<% end %>
|
54
45
|
</tbody>
|
@@ -1,69 +1,9 @@
|
|
1
1
|
<%= render 'stock_item', shipment: shipment %>
|
2
2
|
|
3
3
|
<% unless shipment.shipped? %>
|
4
|
-
<tr class="edit-method
|
5
|
-
<td colspan="5">
|
6
|
-
<div class="field alpha five columns">
|
7
|
-
<%= label_tag 'selected_shipping_rate_id', Spree.t(:shipping_method) %>
|
8
|
-
<%= select_tag :selected_shipping_rate_id,
|
9
|
-
options_for_select(shipment.shipping_rates.map {|sr| ["#{sr.name} #{sr.display_price}", sr.id] }, shipment.selected_shipping_rate_id),
|
10
|
-
{:class => 'select2 fullwidth', :data => {'shipment-number' => shipment.number } } %>
|
11
|
-
</div>
|
12
|
-
</td>
|
13
|
-
<td class="actions">
|
14
|
-
<% if can? :update, shipment %>
|
15
|
-
<%= link_to '', '#', :class => 'save-method fa fa-ok no-text with-tip',
|
16
|
-
:data => {'shipment-number' => shipment.number, :action => 'save'}, title: Spree.t('actions.save') %>
|
17
|
-
<%= link_to '', '#', :class => 'cancel-method fa fa-cancel no-text with-tip',
|
18
|
-
:data => {:action => 'cancel'}, :title => Spree.t('actions.cancel') %>
|
19
|
-
<% end %>
|
20
|
-
</td>
|
4
|
+
<tr class="edit-shipping-method vertical-middle">
|
21
5
|
</tr>
|
22
6
|
<% end %>
|
23
7
|
|
24
|
-
<tr class="
|
25
|
-
<% if shipment.shipping_method %>
|
26
|
-
<td colspan="4">
|
27
|
-
<strong><%= shipment.shipping_method.name %></strong>
|
28
|
-
</td>
|
29
|
-
<td class="total" align="center">
|
30
|
-
<span><%= shipment.display_cost %></span>
|
31
|
-
</td>
|
32
|
-
<% else %>
|
33
|
-
<td colspan='5'><%= Spree.t(:no_shipping_method_selected) %></td>
|
34
|
-
<% end %>
|
35
|
-
|
36
|
-
<td class="actions">
|
37
|
-
<% if can? :update, shipment %>
|
38
|
-
<%= link_to '', '#', :class => 'edit-method fa fa-edit no-text with-tip', :data => {:action => 'edit'}, :title => Spree.t('edit') %>
|
39
|
-
<% end %>
|
40
|
-
</td>
|
41
|
-
</tr>
|
42
|
-
|
43
|
-
<tr class="edit-tracking hidden total">
|
44
|
-
<td colspan="5">
|
45
|
-
<label><%= Spree.t(:tracking_number) %>:</label>
|
46
|
-
<%= text_field_tag :tracking, shipment.tracking %>
|
47
|
-
</td>
|
48
|
-
<td class="actions">
|
49
|
-
<% if can? :update, shipment %>
|
50
|
-
<%= link_to '', '#', :class => 'save-tracking fa fa-ok no-text with-tip', :data => {'shipment-number' => shipment.number, :action => 'save'}, :title => Spree.t('actions.save') %>
|
51
|
-
<%= link_to '', '#', :class => 'cancel-tracking fa fa-cancel no-text with-tip', :data => {:action => 'cancel'}, :title => Spree.t('actions.cancel') %>
|
52
|
-
<% end %>
|
53
|
-
</td>
|
54
|
-
</tr>
|
55
|
-
|
56
|
-
<tr class="show-tracking total">
|
57
|
-
<td colspan="5">
|
58
|
-
<% if shipment.tracking.present? %>
|
59
|
-
<strong><%= Spree.t(:tracking) %>:</strong> <%= shipment.tracking %>
|
60
|
-
<% else %>
|
61
|
-
<%= Spree.t(:no_tracking_present) %>
|
62
|
-
<% end %>
|
63
|
-
</td>
|
64
|
-
<td class="actions">
|
65
|
-
<% if can? :update, shipment %>
|
66
|
-
<%= link_to '', '#', :class => 'edit-tracking fa fa-edit no-text with-tip', :data => {:action => 'edit'}, :title => Spree.t('edit') %>
|
67
|
-
<% end %>
|
68
|
-
</td>
|
8
|
+
<tr class="edit-tracking vertical-middle">
|
69
9
|
</tr>
|