diff --git a/CHANGELOG.md b/CHANGELOG.md index d9c7635124..2e9bf6d066 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,14 @@ Because we use squash and merge, you should be able to see the changes by lookin at the [commit log](https://github.com/tablexi/nucore-open/commits/master). However, we have begun keeping track of breaking changes or optional rake tasks. +### Addition of `PriceGroupDiscount` ([#3397](https://github.com/tablexi/nucore-open/pull/3397), [#3594](https://github.com/tablexi/nucore-open/pull/3594)) + +Rather than one discount being set on a schedule rule, each global price group has its own discount (`PriceGroupDiscount`) for each schedule rule. + +When transitioning a school to use `PriceGroupDiscount`s, the `schedule_rule:add_price_group_discounts` rake task should be run, which adds `PriceGroupDiscount`s for every global price group to every schedule rule. + +When adding a new global price group, the `price_group:add_global_price_group` rake task should be run. This creates the global price group and sets up `PriceGroupDiscount`s for it for every schedule rule. + ### Addition of `facility_tile_list: true` feature flag ([#3193](https://github.com/tablexi/nucore-open/pull/3193)) Schools that have set the feature flag `facility_tile_list: false` are not affected by this change. diff --git a/app/models/price_group.rb b/app/models/price_group.rb index 01b1585764..3dcf7e129c 100644 --- a/app/models/price_group.rb +++ b/app/models/price_group.rb @@ -33,6 +33,14 @@ def self.external globals.find_by(name: Settings.price_group.name.external) end + # Create a global price group, if it does not exist, and setup all the + # schedule rules with price group discounts for the price group. + def self.setup_global(name:, is_internal: false, admin_editable: true, discount_percent: 0, display_order: nil) + price_group = find_or_create_global(name:, is_internal:, admin_editable:, display_order:) + price_group.setup_schedule_rules(discount_percent:) + price_group + end + def is_not_global? !global? end @@ -78,4 +86,50 @@ def external? !is_internal? end + # Creates price group discounts for this price group, if they do not exist + def setup_schedule_rules(discount_percent: 0) + ScheduleRule.all.each do |schedule_rule| + schedule_price_groups = schedule_rule.price_group_discounts.map(&:price_group) + + if schedule_price_groups.include? self + puts("price_group_discount for #{self} already exists for schedule rule #{schedule_rule.id}") unless Rails.env.test? + next + end + + schedule_rule.price_group_discounts.create( + price_group: self, + discount_percent: + ) + + puts("Created price_group_discount for #{self} and schedule rule #{schedule_rule.id}") unless Rails.env.test? + end + end + + private + + # Find a global price group by name, or create it if it does not exist + def self.find_or_create_global(name:, display_order:, is_internal: false, admin_editable: true) + global_price_groups = PriceGroup.globals + found_price_group = global_price_groups.find_by(name:) + + if found_price_group + puts("Global price group '#{name}' already exists.") unless Rails.env.test? + + found_price_group + else + pg = PriceGroup.new( + name:, + is_internal:, + admin_editable:, + facility_id: nil, + display_order: display_order || (global_price_groups.count + 1) + ) + + pg.save(validate: false) + + puts("Created global price group '#{name}'") unless Rails.env.test? + + pg + end + end end diff --git a/db/seeds.rb b/db/seeds.rb index 93957b1eb1..df80ca708e 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -21,11 +21,15 @@ PriceGroup.reset_column_information [ - PriceGroup.create_with(is_internal: true, admin_editable: false).find_or_initialize_by(name: Settings.price_group.name.base), - PriceGroup.create_with(is_internal: true, admin_editable: true).find_or_initialize_by(name: Settings.price_group.name.cancer_center), - PriceGroup.create_with(is_internal: false, admin_editable: false).find_or_initialize_by(name: Settings.price_group.name.external), -].each_with_index do |price_group, index| - next if price_group.name.blank? || price_group.persisted? - price_group.display_order = index + 1 - price_group.save(validate: false) + { name: Settings.price_group.name.base, is_internal: true, admin_editable: false }, + { name: Settings.price_group.name.cancer_center, is_internal: true, admin_editable: true }, + { name: Settings.price_group.name.external, is_internal: false, admin_editable: false }, +].each do |pg_data| + next if pg_data[:name].blank? + + PriceGroup.setup_global( + name: pg_data[:name], + is_internal: pg_data[:is_internal], + admin_editable: pg_data[:admin_editable] + ) end diff --git a/lib/tasks/demo_seed.rake b/lib/tasks/demo_seed.rake index 1e0c4f4d81..c14d988bef 100644 --- a/lib/tasks/demo_seed.rake +++ b/lib/tasks/demo_seed.rake @@ -51,24 +51,18 @@ namespace :demo do end end - order = 1 pgnu = pgex = nil Settings.price_group.name.to_hash.each do |k, v| - price_group = PriceGroup.find_or_initialize_by(name: v) do |pg| - pg.is_internal = (k == :base || k == :cancer_center) - pg.display_order = order - end - - price_group.save(validate: false) # override facility validator + price_group = PriceGroup.setup_global( + name: v, is_internal: (k == :base || k == :cancer_center) + ) if k == :base pgnu = price_group elsif k == :external pgex = price_group end - - order += 1 end fa = FacilityAccount.find_or_initialize_by(facility_id: facility.id) do |facility_account| diff --git a/lib/tasks/pirce_groups.rake b/lib/tasks/pirce_groups.rake new file mode 100644 index 0000000000..919693a17b --- /dev/null +++ b/lib/tasks/pirce_groups.rake @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +namespace :price_group do + # This creates a new global price group, if it does not exist, and adds + # a PriceGroupDiscount for it to every ScheduleRule. If the price group + # already exists, this will just add PriceGroupDiscounts for it to ScheduleRules + # that are missing then. + # + # rake price_group:add_global_price_group["new group",true,false,15] + desc "Create a new global price group and/or setup schedule rules for it" + task :add_global_price_group, [:name, :internal, :admin_editable, :discount] => :environment do |_t, args| + name = args[:name] + is_internal = args[:internal].casecmp("true").zero? + admin_editable = args[:admin_editable].casecmp("true").zero? + discount_percent = args[:discount] || 0 + + PriceGroup.setup_global(name:, is_internal:, admin_editable:, discount_percent:) + end +end diff --git a/lib/tasks/schedule_rules.rake b/lib/tasks/schedule_rules.rake index a44e864a6e..3e119b9e2c 100644 --- a/lib/tasks/schedule_rules.rake +++ b/lib/tasks/schedule_rules.rake @@ -1,7 +1,10 @@ # frozen_string_literal: true namespace :schedule_rule do - desc "Adds PriceGroupDiscounts for global price groups to every schedule rule" + # This task is useful for switching a school over to PriceGroupDiscounts. If a + # school is already using price group discounts on all its schedule rules, this + # task will do nothing + desc "Adds PriceGroupDiscounts for existing global price groups to every schedule rule" task add_price_group_discounts: :environment do |_t, _args| price_groups = PriceGroup.globals diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 7ffe9035ba..8a34b9de59 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -132,9 +132,8 @@ Affiliate.OTHER # initialize price groups - @nupg = PriceGroup.find_or_create_by(name: Settings.price_group.name.base, is_internal: true, display_order: 1) - @nupg.save(validate: false) - PriceGroup.find_or_create_by(name: Settings.price_group.name.external, is_internal: false, display_order: 3).save(validate: false) + @nupg = PriceGroup.setup_global(name: Settings.price_group.name.base, is_internal: true, display_order: 1) + PriceGroup.setup_global(name: Settings.price_group.name.external, is_internal: false, display_order: 3) # Because many specs rely on not crossing a fiscal year boundary we lock the # time globally. Rails's `travel_to` helper does not work well with nesting, so