Persist unit_value on variant and "option value text" on variant and line_item and improve related AR callbacks

This commit is contained in:
Matt-Yorkley
2023-05-06 00:36:24 +01:00
parent bfcf1203ac
commit 35b41fc7fe
6 changed files with 109 additions and 68 deletions

View File

@@ -42,12 +42,16 @@ module Spree
before_save :update_inventory
before_save :calculate_final_weight_volume, if: :quantity_changed?,
unless: :final_weight_volume_changed?
after_save :update_order
after_save :update_units
before_destroy :update_inventory_before_destroy
after_destroy :update_order
before_save :assign_units, if: ->(line_item) {
line_item.new_record? || line_item.changed_attributes.keys.include?("final_weight_volume")
}
delegate :product, :unit_description, :display_name, to: :variant
before_destroy :update_inventory_before_destroy
after_destroy :update_order
after_save :update_order
delegate :product, :variant_unit, :unit_description, :display_name, :display_as, to: :variant
attr_accessor :skip_stock_check, :target_shipment # Allows manual skipping of Stock::AvailabilityValidator

View File

@@ -326,17 +326,6 @@ module Spree
variants.map(&:import_date).compact.max
end
def variant_unit_option_type
return if variant_unit.blank?
option_type_name = "unit_#{variant_unit}"
option_type_presentation = variant_unit.capitalize
Spree::OptionType.find_by(name: option_type_name) ||
Spree::OptionType.create!(name: option_type_name,
presentation: option_type_presentation)
end
def destroy
transaction do
touch_distributors
@@ -396,8 +385,6 @@ module Spree
def update_units
return unless saved_change_to_variant_unit? || saved_change_to_variant_unit_name?
option_types.delete self.class.all_variant_unit_option_types
option_types << variant_unit_option_type if variant_unit.present?
variants_including_master.each(&:update_units)
end

View File

@@ -17,6 +17,8 @@ module Spree
searchable_associations :product, :option_values, :default_price
searchable_scopes :active, :deleted
NAME_FIELDS = ["display_name", "display_as", "weight", "unit_value", "unit_description"].freeze
belongs_to :product, -> { with_deleted }, touch: true, class_name: 'Spree::Product'
delegate_belongs_to :product, :name, :description, :permalink, :available_on,
@@ -73,14 +75,16 @@ module Spree
before_validation :ensure_unit_value
before_validation :update_weight_from_unit_value, if: ->(v) { v.product.present? }
before_save :convert_variant_weight_to_decimal
before_save :assign_units, if: ->(variant) {
variant.new_record? || variant.changed_attributes.keys.intersection(NAME_FIELDS).any?
}
after_save :save_default_price
after_save :update_units
after_create :create_stock_items
after_create :set_position
before_save :convert_variant_weight_to_decimal
around_destroy :destruction
# default variant scope only lists non-deleted variants

View File

@@ -8,31 +8,12 @@ require 'variant_units/option_value_namer'
module VariantUnits
module VariantAndLineItemNaming
# Copied and modified from Spree::Variant
def options_text
values = if option_values_eager_loaded?
# Don't trigger N+1 queries if option_values are already eager-loaded.
# For best results, use: `Spree::Variant.includes(option_values: :option_type)`
# or: `Spree::Product.includes(variant: {option_values: :option_type})`
option_values.sort_by{ |o| o.option_type.position }
else
option_values.joins(:option_type).
order("#{Spree::OptionType.table_name}.position asc")
end
values.map { |option_value|
presentation(option_value)
}.to_sentence(words_connector: ", ", two_words_connector: ", ")
end
def presentation(option_value)
return option_value.presentation unless option_value.option_type.name == "unit_weight"
return unit_presentation unless variant_unit == "weight"
return display_as if has_attribute?(:display_as) && display_as.present?
return variant.display_as if variant_display_as?
option_value.presentation
unit_presentation
end
def variant_display_as?
@@ -68,47 +49,35 @@ module VariantUnits
def unit_to_display
return display_as if has_attribute?(:display_as) && display_as.present?
return variant.display_as if variant_display_as?
options_text
end
def update_units
delete_unit_option_values
option_type = product.variant_unit_option_type
if option_type
name = option_value_name
ov = Spree::OptionValue.where(option_type_id: option_type, name: name,
presentation: name).first ||
Spree::OptionValue.create!(option_type: option_type, name: name, presentation: name)
option_values << ov
end
def assign_units
assign_attributes(unit_value_attributes)
end
def delete_unit_option_values
ovs = option_values.where(option_type_id: Spree::Product.all_variant_unit_option_types)
option_values.destroy ovs
def update_units
update_columns(unit_value_attributes)
end
def unit_value_attributes
units = { unit_presentation: option_value_name }
units.merge!({ variant_unit: product.variant_unit }) if has_attribute?(:variant_unit)
units
end
def weight_from_unit_value
(unit_value || 0) / 1000 if product.variant_unit == 'weight'
(unit_value || 0) / 1000 if variant_unit == 'weight'
end
private
def option_values_eager_loaded?
option_values.loaded?
end
def option_value_name
if has_attribute?(:display_as) && display_as.present?
display_as
else
option_value_namer = VariantUnits::OptionValueNamer.new self
option_value_namer.name
end
return display_as if has_attribute?(:display_as) && display_as.present?
VariantUnits::OptionValueNamer.new(self).name
end
end
end

View File

@@ -0,0 +1,74 @@
class VariantOptionsColumns < ActiveRecord::Migration[7.0]
def up
add_column :spree_variants, :variant_unit, :string
add_column :spree_variants, :unit_presentation, :string
add_column :spree_line_items, :unit_presentation, :string
migrate_variant_unit
migrate_variant_presentation
migrate_line_item_presentation
end
def down
remove_column :spree_variants, :variant_unit
remove_column :spree_variants, :unit_presentation
remove_column :spree_line_items, :unit_presentation
end
# Migrates variant's product's variant_unit value onto variant
#
# Spree::Variant.includes(:product).each do |variant|
# variant.update_columns(variant_unit: variant.product.variant_unit)
# end
def migrate_variant_unit
ActiveRecord::Base.connection.execute(<<-SQL
UPDATE spree_variants
SET variant_unit = product.variant_unit
FROM spree_products AS product
WHERE spree_variants.product_id = product.id
SQL
)
end
# Migrates the variants' option_value's presentation onto the variant's unit_presentation
#
# Spree::Variant.includes(:option_values: :option_type).each do |variant|
# variant.update_columns(unit_presentation: variant.option_values.first.presentation)
# end
def migrate_variant_presentation
ActiveRecord::Base.connection.execute(<<-SQL
UPDATE spree_variants
SET unit_presentation = option_values.presentation
FROM (
SELECT
DISTINCT ON (spree_option_values_variants.variant_id) variant_id,
spree_option_values.presentation AS presentation
FROM spree_option_values_variants
LEFT JOIN spree_option_values ON spree_option_values.id = spree_option_values_variants.option_value_id
) option_values
WHERE spree_variants.id = option_values.variant_id
SQL
)
end
# Migrates the line_items' option_value's presentation onto the line_items's unit_presentation
#
# Spree::LineItem.includes(:option_values: :option_type).each do |line_item|
# line_item.update_columns(unit_presentation: line_item.option_values.first.presentation)
# end
def migrate_line_item_presentation
ActiveRecord::Base.connection.execute(<<-SQL
UPDATE spree_line_items
SET unit_presentation = option_values.presentation
FROM (
SELECT
DISTINCT ON (spree_option_values_line_items.line_item_id) line_item_id,
spree_option_values.presentation AS presentation
FROM spree_option_values_line_items
LEFT JOIN spree_option_values ON spree_option_values.id = spree_option_values_line_items.option_value_id
) option_values
WHERE spree_line_items.id = option_values.line_item_id
SQL
)
end
end

View File

@@ -549,6 +549,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_22_120633) do
t.decimal "height", precision: 8, scale: 2
t.decimal "width", precision: 8, scale: 2
t.decimal "depth", precision: 8, scale: 2
t.string "unit_presentation"
t.index ["order_id"], name: "index_line_items_on_order_id"
t.index ["variant_id"], name: "index_line_items_on_variant_id"
end
@@ -1076,6 +1077,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_05_22_120633) do
t.string "display_name", limit: 255
t.string "display_as", limit: 255
t.datetime "import_date", precision: nil
t.string "variant_unit"
t.string "unit_presentation"
t.index ["product_id"], name: "index_variants_on_product_id"
t.index ["sku"], name: "index_spree_variants_on_sku"
t.check_constraint "unit_value > 0::double precision", name: "positive_unit_value"