mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-06 22:36:07 +00:00
Persist unit_value on variant and "option value text" on variant and line_item and improve related AR callbacks
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
74
db/migrate/20230505165821_variant_options_columns.rb
Normal file
74
db/migrate/20230505165821_variant_options_columns.rb
Normal 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
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user