diff --git a/Gemfile b/Gemfile index 1fe2fde746..ac31d89773 100644 --- a/Gemfile +++ b/Gemfile @@ -117,7 +117,7 @@ group :development do gem "ed25519", ">= 1.2", "< 2.0", require: false # Required to support ed25519 SSH keys for capistrano. https://github.com/net-ssh/net-ssh/issues/565 gem "haml_lint", require: false gem "letter_opener" - gem "rubocop", "1.73.0", require: false + gem "rubocop", "1.73.2", require: false gem "rubocop-performance" gem "rubocop-rails" gem "rubocop-rspec" diff --git a/Gemfile.lock b/Gemfile.lock index 92763ded8d..37e55f393d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -138,8 +138,8 @@ GEM amazing_print (1.7.2) ast (2.4.2) aws-eventstream (1.3.1) - aws-partitions (1.1056.0) - aws-sdk-core (3.219.0) + aws-partitions (1.1060.0) + aws-sdk-core (3.220.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -401,7 +401,7 @@ GEM mime-types (3.6.0) logger mime-types-data (~> 3.2015) - mime-types-data (3.2025.0220) + mime-types-data (3.2025.0304) mini_magick (5.2.0) benchmark logger @@ -451,7 +451,7 @@ GEM activerecord (>= 6.1) request_store (~> 1.4) parallel (1.26.3) - parallel_tests (4.9.1) + parallel_tests (5.0.1) parallel paranoia (3.0.1) activerecord (>= 6, < 8.1) @@ -482,7 +482,7 @@ GEM puma (6.6.0) nio4r (~> 2.0) racc (1.8.1) - rack (2.2.11) + rack (2.2.12) rack-test (2.2.0) rack (>= 1.3) rack-utf8_sanitizer (1.10.1) @@ -560,7 +560,7 @@ GEM rspec-support (3.13.2) rspec_junit_formatter (0.6.0) rspec-core (>= 2, < 4, != 2.12.0) - rubocop (1.73.0) + rubocop (1.73.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) lint_roller (~> 1.1.0) @@ -577,7 +577,7 @@ GEM lint_roller (~> 1.1) rubocop (>= 1.72.1, < 2.0) rubocop-ast (>= 1.38.0, < 2.0) - rubocop-rails (2.30.2) + rubocop-rails (2.30.3) activesupport (>= 4.2.0) lint_roller (~> 1.1) rack (>= 1.1) @@ -789,7 +789,7 @@ DEPENDENCIES rspec-collection_matchers rspec-rails rspec_junit_formatter - rubocop (= 1.73.0) + rubocop (= 1.73.2) rubocop-performance rubocop-rails rubocop-rspec diff --git a/app/controllers/order_management/order_details_controller.rb b/app/controllers/order_management/order_details_controller.rb index 0698c7968a..d196c86cb1 100644 --- a/app/controllers/order_management/order_details_controller.rb +++ b/app/controllers/order_management/order_details_controller.rb @@ -13,7 +13,7 @@ class OrderManagement::OrderDetailsController < ApplicationController # We can't load through the facility because of cross-core orders before_action :init_order_detail, only: [:files, :template_results] - helper_method :edit_disabled? + helper_method :edit_disabled?, :actual_cost_edit_disabled? before_action :authorize_order_detail, except: %i(sample_results) before_action :load_accounts, only: [:edit, :update] @@ -117,7 +117,19 @@ def load_order_statuses end def edit_disabled? - @order_detail.in_open_journal? || @order_detail.reconciled? + in_open_journal_or_reconciled = @order_detail.in_open_journal? || @order_detail.reconciled? + + if SettingsHelper.feature_on?(:allow_global_billing_admin_update_actual_prices) + in_open_journal_or_reconciled || (@order_detail.awaiting_payment? && !current_user.global_billing_administrator?) + else + in_open_journal_or_reconciled + end + end + + def actual_cost_edit_disabled? + return false unless SettingsHelper.feature_on?(:allow_global_billing_admin_update_actual_prices) + + @order_detail.awaiting_payment? && !current_user.global_billing_administrator? end def init_order_detail diff --git a/app/helpers/products_helper.rb b/app/helpers/products_helper.rb index 5dce81c48e..ff1ed96b8d 100644 --- a/app/helpers/products_helper.rb +++ b/app/helpers/products_helper.rb @@ -20,11 +20,15 @@ def options_for_control_mechanism end def options_for_relay - { - RelaySynaccessRevA => RelaySynaccessRevA.name, - RelaySynaccessRevB => RelaySynaccessRevB.name, - RelayDataprobe => RelayDataprobe.name, - } + [ + if SettingsHelper.feature_on?(:disable_relay_synaccess_rev_a) + nil + else + [RelaySynaccessRevA, RelaySynaccessRevA.name] + end, + [RelaySynaccessRevB, RelaySynaccessRevB.name], + [RelayDataprobe, RelayDataprobe.name], + ].compact end def instrument_pricing_modes diff --git a/app/services/order_details/param_updater.rb b/app/services/order_details/param_updater.rb index fbc32b81b2..e14da68833 100644 --- a/app/services/order_details/param_updater.rb +++ b/app/services/order_details/param_updater.rb @@ -106,7 +106,13 @@ def assign_price_changed_by_user end def cost_params(params) - params.slice(:actual_cost, :actual_subsidy).permit! + return params.slice(:actual_cost, :actual_subsidy).permit! unless SettingsHelper.feature_on?(:allow_global_billing_admin_update_actual_prices) + + if !@order_detail.awaiting_payment? || @editing_user.global_billing_administrator? + params.slice(:actual_cost, :actual_subsidy).permit! + else + {} + end end def permitted_params(params) diff --git a/app/views/order_management/order_details/_costs.html.haml b/app/views/order_management/order_details/_costs.html.haml index a4e4e532fd..b3abdfe385 100644 --- a/app/views/order_management/order_details/_costs.html.haml +++ b/app/views/order_management/order_details/_costs.html.haml @@ -1,7 +1,7 @@ - f.object.send(:extend, PriceDisplayment) - if f.object.actual_cost? .cost-table - .cost= f.input :actual_cost, as: :currency + .cost= f.input :actual_cost, as: :currency, disabled: actual_cost_edit_disabled? .subsidy= f.input :actual_subsidy, as: :currency, disabled: !f.object.price_policy.try(:has_subsidy?), hint: "#{f.object.price_policy.try(:price_group)}" .total= f.input :actual_total, as: :currency, disabled: true - else diff --git a/config/settings.yml b/config/settings.yml index 781b69fa5e..9bedb58ac5 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -162,6 +162,8 @@ feature: show_daily_rate_option: true sanger_enabled_service: <%= ENV.fetch("SANGER_ENABLED_SERVICE", false) %> well_plate_alternative_csv_format: <%= ENV.fetch("well_plate_alternative_csv_format", false) %> + disable_relay_synaccess_rev_a: false + allow_global_billing_admin_update_actual_prices: false split_accounts: # Roles are allowed to create Split Accounts diff --git a/spec/helpers/products_helper_spec.rb b/spec/helpers/products_helper_spec.rb new file mode 100644 index 0000000000..b31bdd606c --- /dev/null +++ b/spec/helpers/products_helper_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe ProductsHelper do + describe "#options_for_relay" do + let(:subject) { options_for_relay } + + it( + "list all relay types if none disabled", + { feature_setting: { disable_relay_synaccess_rev_a: false } } + ) do + expect(subject.to_h).to include( + RelaySynaccessRevA, + RelaySynaccessRevB, + RelayDataprobe + ) + end + + it( + "exclude synaccess rev a if disabled flag is on", + { feature_setting: { disable_relay_synaccess_rev_a: true } } + ) do + expect(subject.to_h).to_not include(RelaySynaccessRevA) + end + end +end diff --git a/spec/system/admin/instrument_relay_tab_spec.rb b/spec/system/admin/instrument_relay_tab_spec.rb index 901a1992fe..d838c24d77 100644 --- a/spec/system/admin/instrument_relay_tab_spec.rb +++ b/spec/system/admin/instrument_relay_tab_spec.rb @@ -2,7 +2,7 @@ require "rails_helper" -RSpec.describe "Instrument Relay Tab" do +RSpec.describe "Instrument Relay Tab", feature_setting: { disable_relay_synaccess_rev_a: false } do let(:facility) { FactoryBot.create(:setup_facility) } let(:user) { FactoryBot.create(:user, :administrator) } diff --git a/spec/system/admin/manage_order_detail_spec.rb b/spec/system/admin/manage_order_detail_spec.rb index 5a702ba7b7..0cccae36b2 100644 --- a/spec/system/admin/manage_order_detail_spec.rb +++ b/spec/system/admin/manage_order_detail_spec.rb @@ -363,4 +363,50 @@ end end end + + shared_examples "allows to update actual cost" do + it "allows to update actual cost" do + expect(page).to have_field("order_detail[actual_cost]", disabled: false) + end + end + + describe "updating actual cost" do + let(:statement) { create(:statement, facility:, created_by: 1) } + + before do + start_at = Time.zone.parse("#{Date.today} 10:00:00") - 1.day + end_at = start_at + 1.hour + + reservation.update!(actual_start_at: start_at, actual_end_at: end_at) + order_detail.update!(reviewed_at: 5.days.ago, statement:, actual_cost: 10) + + visit manage_facility_order_order_detail_path(facility, order, order_detail) + end + + context "with feature flag ON", feature_setting: { allow_global_billing_admin_update_actual_prices: true } do + context "as a global admin" do + it "does not allow to update actual cost" do + expect(page).to have_field("order_detail[actual_cost]", disabled: true) + end + end + + context "as a global billing admin" do + let(:logged_in_user) { create(:user, :global_billing_administrator) } + + it_behaves_like "allows to update actual cost" + end + end + + context "with feature flag OFF", feature_setting: { allow_global_billing_admin_update_actual_prices: false } do + context "as a global admin" do + it_behaves_like "allows to update actual cost" + end + + context "as a global billing admin" do + let(:logged_in_user) { create(:user, :global_billing_administrator) } + + it_behaves_like "allows to update actual cost" + end + end + end end