diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 44b81f61db..130d414236 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -80,7 +80,7 @@ Metrics/BlockNesting: Exclude: - 'app/models/spree/payment/processing.rb' -# Offense count: 48 +# Offense count: 49 # Configuration parameters: CountComments, Max, CountAsOne. Metrics/ClassLength: Exclude: @@ -122,6 +122,7 @@ Metrics/ClassLength: - 'app/services/order_cycles/form_service.rb' - 'app/services/orders/sync_service.rb' - 'app/services/permissions/order.rb' + - 'app/services/products_renderer.rb' - 'app/services/sets/product_set.rb' - 'engines/order_management/app/services/order_management/order/updater.rb' - 'lib/open_food_network/enterprise_fee_calculator.rb' diff --git a/app/controllers/admin/product_import_controller.rb b/app/controllers/admin/product_import_controller.rb index 3cc7e2b590..322219f54c 100644 --- a/app/controllers/admin/product_import_controller.rb +++ b/app/controllers/admin/product_import_controller.rb @@ -49,7 +49,7 @@ module Admin errors: @importer.errors.full_messages } - if helpers.feature?(:inventory, *spree_current_user.enterprises) + if helpers.inventory_enabled?(spree_current_user.enterprises) json[:results][:inventory_created] = @importer.inventory_created_count json[:results][:inventory_updated] = @importer.inventory_updated_count end @@ -175,7 +175,7 @@ module Admin # Return an error if trying to import into inventories when inventory is disable def can_import_into_inventories? - return true if helpers.feature?(:inventory, *spree_current_user.enterprises) || + return true if helpers.inventory_enabled?(spree_current_user.enterprises) || params.dig(:settings, "import_into") != 'inventories' redirect_to admin_product_import_url, notice: I18n.t(:product_import_inventory_disable) diff --git a/app/helpers/spree/admin/base_helper.rb b/app/helpers/spree/admin/base_helper.rb index badeb0783d..768e6cfb04 100644 --- a/app/helpers/spree/admin/base_helper.rb +++ b/app/helpers/spree/admin/base_helper.rb @@ -147,6 +147,10 @@ module Spree dom_id(record, 'spree') end + def inventory_enabled?(enterprises) + !feature?(:variant_tag, *enterprises) && feature?(:inventory, *enterprises) + end + private def attribute_name_for(field_name) diff --git a/app/models/product_import/product_importer.rb b/app/models/product_import/product_importer.rb index 37e8031ecd..3f1185ee50 100644 --- a/app/models/product_import/product_importer.rb +++ b/app/models/product_import/product_importer.rb @@ -185,11 +185,16 @@ module ProductImport order('is_primary_producer ASC, name'). map { |e| @editable_enterprises[e.name] = e.id } - return unless OpenFoodNetwork::FeatureToggle.enabled?(:inventory, *@current_user.enterprises) + return unless inventory_enabled? @inventory_permissions = permissions.variant_override_enterprises_per_hub end + def inventory_enabled? + !OpenFoodNetwork::FeatureToggle.enabled?(:variant_tag, *@current_user.enterprises) && + OpenFoodNetwork::FeatureToggle.enabled?(:inventory, *@current_user.enterprises) + end + def open_spreadsheet if accepted_mimetype Roo::Spreadsheet.open(@file, extension: accepted_mimetype, encoding: Encoding::UTF_8) diff --git a/app/services/products_renderer.rb b/app/services/products_renderer.rb index 2dbf12076b..270495f3d7 100644 --- a/app/services/products_renderer.rb +++ b/app/services/products_renderer.rb @@ -44,7 +44,7 @@ class ProductsRenderer paginated_products = paginate(results) - if options[:inventory_enabled] + if inventory_enabled? # Scope results with variant_overrides paginated_products.each { |product| product_scoper.scope(product) } end @@ -123,7 +123,7 @@ class ProductsRenderer includes(:default_price, :product). where(product_id: products) - if options[:inventory_enabled] + if inventory_enabled? # Scope results with variant_overrides scoper = OpenFoodNetwork::ScopeVariantToHub.new(distributor) variants = variants.each { |v| scoper.scope(v) } @@ -143,4 +143,8 @@ class ProductsRenderer vs[v.product_id] << v end end + + def inventory_enabled? + options[:inventory_enabled] && !options[:variant_tag_enabled] + end end diff --git a/app/views/admin/order_cycles/_advanced_settings.html.haml b/app/views/admin/order_cycles/_advanced_settings.html.haml index a57df385cf..a254b1a5e3 100644 --- a/app/views/admin/order_cycles/_advanced_settings.html.haml +++ b/app/views/admin/order_cycles/_advanced_settings.html.haml @@ -2,7 +2,7 @@ %h3= t('.title') = form_for [main_app, :admin, @order_cycle] do |f| - - if feature?(:inventory, @order_cycle.coordinator) + - if inventory_enabled?(@order_cycle.coordinator) .row .three.columns.alpha = f.label "enterprise_preferred_product_selection_from_coordinator_inventory_only", t('admin.order_cycles.edit.choose_products_from') diff --git a/app/views/admin/product_import/_upload_form.html.haml b/app/views/admin/product_import/_upload_form.html.haml index a8a853f556..c1cce83e18 100644 --- a/app/views/admin/product_import/_upload_form.html.haml +++ b/app/views/admin/product_import/_upload_form.html.haml @@ -5,7 +5,7 @@ %h6= t('admin.product_import.index.choose_import_type') %br - options = { "#{t('admin.product_import.index.product_list')}" => :product_list } - - options = options.merge("#{t('admin.product_import.index.inventories')}" => :inventories) if feature?(:inventory, *spree_current_user.enterprises) + - options = options.merge("#{t('admin.product_import.index.inventories')}" => :inventories) if inventory_enabled?(spree_current_user.enterprises) = select_tag "settings[import_into]", options_for_select(options), { "data-controller": "tom-select", class: "primary inline no-search", "ng-model": "settings.import_into" } diff --git a/app/views/admin/product_import/_upload_sidebar.html.haml b/app/views/admin/product_import/_upload_sidebar.html.haml index fc0c22f7c4..d089c84497 100644 --- a/app/views/admin/product_import/_upload_sidebar.html.haml +++ b/app/views/admin/product_import/_upload_sidebar.html.haml @@ -5,7 +5,7 @@ %i.icon-external-link = t('admin.product_import.index.product_list_template') - - if feature?(:inventory, *spree_current_user.enterprises) + - if inventory_enabled?(spree_current_user.enterprises) %a.download{href: '/inventory_template.csv'} %i.icon-external-link = t('admin.product_import.index.inventory_template') diff --git a/app/views/spree/admin/shared/_product_sub_menu.html.haml b/app/views/spree/admin/shared/_product_sub_menu.html.haml index c24f0da781..194825593c 100644 --- a/app/views/spree/admin/shared/_product_sub_menu.html.haml +++ b/app/views/spree/admin/shared/_product_sub_menu.html.haml @@ -2,5 +2,5 @@ %ul#sub_nav.inline-menu = tab :products, :products_v3, url: admin_products_path = tab :properties - = tab :variant_overrides, url: main_app.admin_inventory_path, match_path: '/inventory' if feature?(:inventory, *spree_current_user.enterprises) + = tab :variant_overrides, url: main_app.admin_inventory_path, match_path: '/inventory' if inventory_enabled?(spree_current_user.enterprises) = tab :import, url: main_app.admin_product_import_path, match_path: '/product_import' diff --git a/config/initializers/flipper.rb b/config/initializers/flipper.rb index c660d993a9..0c6c82d624 100644 --- a/config/initializers/flipper.rb +++ b/config/initializers/flipper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "flipper" require "flipper/adapters/active_record" require "open_food_network/feature_toggle" @@ -23,21 +25,52 @@ Flipper.register(:admins) do |actor| actor.respond_to?(:admin?) && actor.admin? end Flipper.register(:new_2024_07_03) do |actor| - actor.respond_to?(:created_at?) && actor.created_at >= "2024-07-03".to_time + actor.respond_to?(:created_at?) && actor.created_at >= Time.zone.parse("2024-07-03") end Flipper.register(:enterprise_created_before_2025_08_11) do |actor| # This group applies to enterprises only, so we return false if the actor is not an Enterprise next false unless actor.actor.instance_of? Enterprise - actor.respond_to?(:created_at?) && actor.created_at < "2025-08-11".to_time + actor.respond_to?(:created_at?) && actor.created_at < Time.zone.parse("2025-08-11") end Flipper.register(:enterprise_created_after_2025_08_11) do |actor| # This group applies to enterprises only, so we return false if the actor is not an Enterprise next false unless actor.actor.instance_of? Enterprise - actor.respond_to?(:created_at?) && actor.created_at >= "2025-08-11".to_time + actor.respond_to?(:created_at?) && actor.created_at >= Time.zone.parse("2025-08-11") end +Flipper.register(:enterprise_with_no_inventory) do |actor| + # This group applies to enterprises only, so we return false if the actor is not an Enterprise + next false unless actor.actor.instance_of? Enterprise + + # Uses 2025-08-11 as filter because variant tag did not exist before that, enterprise created + # after never had access to the inventory + enterprise_with_variant_override = Enterprise + .where(id: VariantOverride.joins(:hub).select(:hub_id)) + .where(created_at: ..."2025-08-11") + .distinct + enterprise_with_no_variant_override = Enterprise + .where.not(id: enterprise_with_variant_override) + + enterprise_with_no_variant_override.exists?(actor.id) +end + +Flipper.register(:enterprise_with_inventory) do |actor| + # This group applies to enterprises only, so we return false if the actor is not an Enterprise + next false unless actor.actor.instance_of? Enterprise + + # Uses 2025-08-11 as filter because variant tag did not exist before that, enterprise created + # after never had access to the inventory + enterprise_with_variant_override = Enterprise + .where(id: VariantOverride.joins(:hub).select(:hub_id)) + .where(created_at: ..."2025-08-11") + .distinct + + enterprise_with_variant_override.exists?(actor.id) +end + + Flipper::UI.configure do |config| config.descriptions_source = ->(_keys) do # return has to be hash of {String key => String description} @@ -59,4 +92,8 @@ Flipper::UI.configure do |config| end # Add known feature toggles. This may fail if the database isn't setup yet. -OpenFoodNetwork::FeatureToggle.setup! rescue ActiveRecord::StatementInvalid +begin + OpenFoodNetwork::FeatureToggle.setup! +rescue ActiveRecord::StatementInvalid + nil +end diff --git a/db/migrate/20251126005628_enable_variant_tag_and_enable_inventory_for_enterprise_using_it.rb b/db/migrate/20251126005628_enable_variant_tag_and_enable_inventory_for_enterprise_using_it.rb new file mode 100644 index 0000000000..4318978c9d --- /dev/null +++ b/db/migrate/20251126005628_enable_variant_tag_and_enable_inventory_for_enterprise_using_it.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +class EnableVariantTagAndEnableInventoryForEnterpriseUsingIt < ActiveRecord::Migration[7.1] + def up + Flipper.disable_group(:variant_tag, "enterprise_created_after_2025_08_11") + Flipper.disable_group(:variant_tag, "old_enterprise_with_no_inventory") + + Flipper.enable_group(:variant_tag, "enterprise_with_no_inventory") + + Flipper.disable_group(:inventory, "enterprise_created_before_2025_08_11") + + Flipper.enable_group(:inventory, "enterprise_with_inventory") + end + + def down + Flipper.enable_group(:variant_tag, "enterprise_created_after_2025_08_11") + Flipper.enable_group(:variant_tag, "old_enterprise_with_no_inventory") + + Flipper.disable_group(:variant_tag, "enterprise_with_no_inventory") + + Flipper.enable_group(:inventory, "enterprise_created_before_2025_08_11") + + Flipper.disable_group(:inventory, "enterprise_with_inventory") + end +end diff --git a/db/schema.rb b/db/schema.rb index 2de662697f..acbc0d48cd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2025_08_27_205335) do +ActiveRecord::Schema[7.1].define(version: 2025_11_26_005628) do # These are extensions that must be enabled in order to support this database enable_extension "pg_stat_statements" enable_extension "plpgsql"