diff --git a/app/models/spree/line_item.rb b/app/models/spree/line_item.rb index fed86cd802..c1312df1dd 100644 --- a/app/models/spree/line_item.rb +++ b/app/models/spree/line_item.rb @@ -24,6 +24,8 @@ module Spree before_validation :copy_price before_validation :copy_tax_category before_validation :copy_dimensions + before_validation :copy_product_name, on: :create + before_validation :copy_variant_name, on: :create validates :quantity, numericality: { only_integer: true, @@ -250,6 +252,18 @@ module Spree adjustments.enterprise_fee end + def full_variant_name + return variant_name if variant_name.present? + + variant.full_name + end + + def full_product_name + return product_name if product_name.present? + + variant.product.name + end + private def computed_weight_from_variant @@ -274,6 +288,18 @@ module Spree order.create_tax_charge! end + def copy_product_name + return if variant.nil? || variant.product.nil? + + self.product_name = variant.product.name + end + + def copy_variant_name + return if variant.nil? + + self.variant_name = variant.full_name + end + def update_inventory_before_destroy # This is necessary before destroying the line item # so that update_inventory will restore stock to the variant diff --git a/app/services/line_item_syncer.rb b/app/services/line_item_syncer.rb index 010312fef4..fb2af07b13 100644 --- a/app/services/line_item_syncer.rb +++ b/app/services/line_item_syncer.rb @@ -77,7 +77,7 @@ class LineItemSyncer end def add_order_update_issue(order, line_item) - issue_description = "#{line_item.product.name} - #{line_item.variant.full_name}" + issue_description = "#{line_item.product.name} - #{line_item.full_variant_name}" issue_description << " - #{stock_issue_description(line_item)}" if line_item.insufficient_stock? order_update_issues.add(order, issue_description) end diff --git a/db/migrate/20250416074033_add_product_name_to_line_items.rb b/db/migrate/20250416074033_add_product_name_to_line_items.rb new file mode 100644 index 0000000000..92c256fdae --- /dev/null +++ b/db/migrate/20250416074033_add_product_name_to_line_items.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddProductNameToLineItems < ActiveRecord::Migration[7.0] + def change + add_column :spree_line_items, :product_name, :string + end +end diff --git a/db/migrate/20250713110052_add_variant_name_to_line_items.rb b/db/migrate/20250713110052_add_variant_name_to_line_items.rb new file mode 100644 index 0000000000..dffc7735d6 --- /dev/null +++ b/db/migrate/20250713110052_add_variant_name_to_line_items.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddVariantNameToLineItems < ActiveRecord::Migration[7.0] + def change + add_column :spree_line_items, :variant_name, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index 9ebfe7a970..ccbcc56233 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -579,6 +579,8 @@ ActiveRecord::Schema[7.1].define(version: 2025_11_26_005628) do t.decimal "width", precision: 8, scale: 2 t.decimal "depth", precision: 8, scale: 2 t.string "unit_presentation" + t.string "product_name" + t.string "variant_name" t.index ["order_id"], name: "index_line_items_on_order_id" t.index ["variant_id"], name: "index_line_items_on_variant_id" end diff --git a/lib/reporting/reports/bulk_coop/base.rb b/lib/reporting/reports/bulk_coop/base.rb index 371713d676..bc7503d2f7 100644 --- a/lib/reporting/reports/bulk_coop/base.rb +++ b/lib/reporting/reports/bulk_coop/base.rb @@ -85,7 +85,7 @@ module Reporting end def product_name(line_items) - line_items.first.product.name + line_items.first.full_product_name end def remainder(line_items) @@ -118,7 +118,7 @@ module Reporting end def variant_product_name(line_items) - line_items.first.variant.product.name + line_items.first.full_product_name end def weight_from_unit_value(line_items) diff --git a/lib/reporting/reports/orders_and_fulfillment/base.rb b/lib/reporting/reports/orders_and_fulfillment/base.rb index fef26eb194..8c083efe25 100644 --- a/lib/reporting/reports/orders_and_fulfillment/base.rb +++ b/lib/reporting/reports/orders_and_fulfillment/base.rb @@ -41,7 +41,7 @@ module Reporting end def variant_name - proc { |line_items| line_items.first.variant.full_name } + proc { |line_items| line_items.first.full_variant_name } end def variant_sku @@ -57,7 +57,7 @@ module Reporting end def product_name - proc { |line_items| line_items.first.variant.product.name } + proc { |line_items| line_items.first.full_product_name } end def product_tax_category diff --git a/lib/reporting/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor.rb b/lib/reporting/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor.rb index 039ed25e6d..83f5d31704 100644 --- a/lib/reporting/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor.rb +++ b/lib/reporting/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor.rb @@ -25,7 +25,7 @@ module Reporting }, { group_by: proc { |line_items, _row| line_items.first.variant }, - sort_by: proc { |variant| variant.product.name } + sort_by: proc { |variant| variant.line_items.first.full_product_name } }, { group_by: :hub, diff --git a/spec/factories/line_item_factory.rb b/spec/factories/line_item_factory.rb index f575fb0d3b..284c7440d8 100644 --- a/spec/factories/line_item_factory.rb +++ b/spec/factories/line_item_factory.rb @@ -6,6 +6,7 @@ FactoryBot.define do price { BigDecimal('10.00') } order variant + product_name { variant.product.name } end factory :line_item_with_shipment, parent: :line_item do diff --git a/spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb b/spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb index f7e4231fc1..892a592afe 100644 --- a/spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb +++ b/spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb @@ -28,7 +28,7 @@ RSpec.describe Reporting::Reports::OrdersAndFulfillment::OrderCycleCustomerTotal completed_at: order_date, ).tap do |order| order.line_items[0].variant.supplier.update(name: "Apple Farmer") - order.line_items[0].product.update(name: "Apples") + order.line_items[0].update(product_name: "Apples") order.line_items[0].variant.update(sku: "APP") end end diff --git a/spec/lib/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor_report_spec.rb b/spec/lib/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor_report_spec.rb index eb4f5661f3..cc1fe3c826 100644 --- a/spec/lib/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor_report_spec.rb +++ b/spec/lib/reports/orders_and_fulfillment/order_cycle_supplier_totals_by_distributor_report_spec.rb @@ -32,9 +32,10 @@ module Reporting end it "lists products sorted by name" do - order.line_items[0].variant.product.update(name: "Cucumber") - order.line_items[1].variant.product.update(name: "Apple") - order.line_items[2].variant.product.update(name: "Banane") + order.line_items[0].update(product_name: "Cucumber") + order.line_items[1].update(product_name: "Apple") + order.line_items[2].update(product_name: "Banane") + product_names = report.rows.map(&:product).compact_blank expect(product_names).to eq(["Apple", "Banane", "Cucumber"]) end @@ -79,9 +80,9 @@ module Reporting end it "lists products sorted by name" do - order.line_items[0].variant.product.update(name: "Cucumber") - order.line_items[1].variant.product.update(name: "Apple") - order.line_items[2].variant.product.update(name: "Banane") + order.line_items[0].update(product_name: "Cucumber") + order.line_items[1].update(product_name: "Apple") + order.line_items[2].update(product_name: "Banane") product_names = report.rows.map(&:product).compact_blank # only the supplier's variant is displayed expect(product_names).to include("Cucumber") diff --git a/spec/lib/reports/orders_and_fulfillment/orders_cycle_supplier_totals_report_spec.rb b/spec/lib/reports/orders_and_fulfillment/orders_cycle_supplier_totals_report_spec.rb index 1fd1ae3841..a76c4448fc 100644 --- a/spec/lib/reports/orders_and_fulfillment/orders_cycle_supplier_totals_report_spec.rb +++ b/spec/lib/reports/orders_and_fulfillment/orders_cycle_supplier_totals_report_spec.rb @@ -23,14 +23,14 @@ RSpec.describe Reporting::Reports::OrdersAndFulfillment::OrderCycleSupplierTotal report.table_rows end + let(:item) { order.line_items.first } + let(:variant) { item.variant } + it "generates the report" do expect(report_table.length).to eq(1) end describe "total_units column" do - let(:item) { order.line_items.first } - let(:variant) { item.variant } - it "contains a sum of total items" do variant.update!(variant_unit: "items", variant_unit_name: "bottle", unit_value: 6) # six-pack item.update!(final_weight_volume: nil) # reset unit information @@ -178,4 +178,21 @@ RSpec.describe Reporting::Reports::OrdersAndFulfillment::OrderCycleSupplierTotal expect(last_column_title).to eq "SKU" expect(first_row_last_column_value).to eq variant_sku end + + it "doesn't update product name in report" do + variant_sku = order.line_items.first.variant.sku + last_column_title = table_headers[-3] + first_row_last_column_value = report_table.first[-3] + + expect(last_column_title).to eq "SKU" + expect(first_row_last_column_value).to eq variant_sku + + expect(report_table.first[1]).to eq(variant.product.name) + product_name = variant.product.name + variant.product.update(name: "#{product_name} Updated") + + new_report = described_class.new(current_user, params) + + expect(new_report.table_rows.first[1]).to eq(product_name) + end end diff --git a/spec/models/spree/line_item_spec.rb b/spec/models/spree/line_item_spec.rb index 5ece7b8034..616c95a134 100644 --- a/spec/models/spree/line_item_spec.rb +++ b/spec/models/spree/line_item_spec.rb @@ -62,6 +62,17 @@ RSpec.describe Spree::LineItem do end end + context '#full_variant_name' do + it "returns variant's full name" do + expect(line_item.full_variant_name).to eq(line_item.variant.full_name) + end + + it "uses variant.full_name when variant_name is nil" do + line_item.variant_name = nil + expect(line_item.full_variant_name).to eq(line_item.variant.full_name) + end + end + describe '.currency' do it 'returns the globally configured currency' do line_item.currency == 'USD' diff --git a/spec/services/orders/sync_service_spec.rb b/spec/services/orders/sync_service_spec.rb index 31fe0d4136..594e76ae11 100644 --- a/spec/services/orders/sync_service_spec.rb +++ b/spec/services/orders/sync_service_spec.rb @@ -438,7 +438,7 @@ RSpec.describe Orders::SyncService do expect(order.reload.total.to_f).to eq 59.97 line_item = order.line_items.find_by(variant_id: sli.variant_id) expect(syncer.order_update_issues[order.id]) - .to include "#{line_item.product.name} - #{line_item.variant.full_name} - " \ + .to include "#{line_item.product.name} - #{line_item.full_variant_name} - " \ "Insufficient stock available" end @@ -453,7 +453,7 @@ RSpec.describe Orders::SyncService do line_item = order.line_items.find_by(variant_id: sli.variant_id) expect(syncer.order_update_issues[order.id]) - .to include "#{line_item.product.name} - #{line_item.variant.full_name} - Out of Stock" + .to include "#{line_item.product.name} - #{line_item.full_variant_name} - Out of Stock" end end end @@ -498,7 +498,7 @@ RSpec.describe Orders::SyncService do expect(changed_line_item.reload.quantity).to eq 2 expect(order.reload.total.to_f).to eq 79.96 expect(syncer.order_update_issues[order.id]) - .to include "#{changed_line_item.product.name} - #{changed_line_item.variant.full_name}" + .to include "#{changed_line_item.product.name} - #{changed_line_item.full_variant_name}" end end end