Browse Source

Remove nested deactivation periods

pull/1007/head
Kat 4 years ago
parent
commit
75b0e7cd18
  1. 12
      app/helpers/locations_helper.rb
  2. 113
      spec/helpers/locations_helper_spec.rb

12
app/helpers/locations_helper.rb

@ -46,7 +46,7 @@ module LocationsHelper
def active_periods(location) def active_periods(location)
periods = [ActivePeriod.new(location.available_from, nil)] periods = [ActivePeriod.new(location.available_from, nil)]
sorted_deactivation_periods = location.location_deactivation_periods.sort_by(&:deactivation_date) sorted_deactivation_periods = remove_nested_periods(location.location_deactivation_periods.sort_by(&:deactivation_date))
sorted_deactivation_periods.each do |deactivation| sorted_deactivation_periods.each do |deactivation|
periods.find { |period| period.to.nil? }.to = deactivation.deactivation_date periods.find { |period| period.to.nil? }.to = deactivation.deactivation_date
periods << ActivePeriod.new(deactivation.reactivation_date, nil) periods << ActivePeriod.new(deactivation.reactivation_date, nil)
@ -71,4 +71,14 @@ private
def remove_overlapping_and_empty_periods(periods) def remove_overlapping_and_empty_periods(periods)
periods.select { |period| ((period.to.nil? && period.from.present?) || (period.from.present? && period.from < period.to)) } periods.select { |period| ((period.to.nil? && period.from.present?) || (period.from.present? && period.from < period.to)) }
end end
def remove_nested_periods(periods)
periods.select { |inner_period| periods.none? { |outer_period| is_nested?(inner_period, outer_period) } }
end
def is_nested?(inner, outer)
return false if inner == outer || [inner.deactivation_date, inner.reactivation_date, outer.deactivation_date, outer.reactivation_date].any?(&:blank?)
[inner.deactivation_date, inner.reactivation_date].all? { |date| date.between?(outer.deactivation_date, outer.reactivation_date) }
end
end end

113
spec/helpers/locations_helper_spec.rb

@ -58,69 +58,76 @@ RSpec.describe LocationsHelper do
Timecop.unfreeze Timecop.unfreeze
end end
context "when there have not been any previous deactivations" do it "returns one active period without to date" do
it "returns one active period without to date" do expect(active_periods(location).count).to eq(1)
expect(active_periods(location).count).to eq(1) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: nil)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: nil) end
end
it "ignores reactivations that were deactivated on the same day" do it "ignores reactivations that were deactivated on the same day" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 6, 4))
location.save! location.save!
expect(active_periods(location).count).to eq(1) expect(active_periods(location).count).to eq(1)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5))
end end
it "returns sequential non reactivated active periods" do it "returns sequential non reactivated active periods" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6))
location.save! location.save!
expect(active_periods(location).count).to eq(2) expect(active_periods(location).count).to eq(2)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6)) expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6))
end end
it "returns sequential reactivated active periods" do it "returns sequential reactivated active periods" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5))
location.save! location.save!
expect(active_periods(location).count).to eq(3) expect(active_periods(location).count).to eq(3)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6)) expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6))
expect(active_periods(location).third).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil) expect(active_periods(location).third).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil)
end end
it "returns non sequential non reactivated active periods" do it "returns non sequential non reactivated active periods" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: nil) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: nil)
location.save! location.save!
expect(active_periods(location).count).to eq(2) expect(active_periods(location).count).to eq(2)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil) expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil)
end end
it "returns non sequential reactivated active periods" do it "returns non sequential reactivated active periods" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 7, 6), reactivation_date: Time.zone.local(2022, 8, 5))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 4))
location.save! location.save!
expect(active_periods(location).count).to eq(3) expect(active_periods(location).count).to eq(3)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 5, 5))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6)) expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 6, 4), to: Time.zone.local(2022, 7, 6))
expect(active_periods(location).third).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil) expect(active_periods(location).third).to have_attributes(from: Time.zone.local(2022, 8, 5), to: nil)
end end
it "returns correct active periods when reactivation happends during a deactivated period" do it "returns correct active periods when reactivation happends during a deactivated period" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 11, 11)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 11, 11))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 4, 6), reactivation_date: Time.zone.local(2022, 7, 7)) location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 4, 6), reactivation_date: Time.zone.local(2022, 7, 7))
expect(active_periods(location).count).to eq(2) expect(active_periods(location).count).to eq(2)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 4, 6)) expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 4, 6))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 11, 11), to: nil) expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 11, 11), to: nil)
end end
it "returns correct active periods when a full deactivation period happens during another deactivation period" do
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 5, 5), reactivation_date: Time.zone.local(2022, 6, 11))
location.location_deactivation_periods << FactoryBot.create(:location_deactivation_period, deactivation_date: Time.zone.local(2022, 4, 6), reactivation_date: Time.zone.local(2022, 7, 7))
expect(active_periods(location).count).to eq(2)
expect(active_periods(location).first).to have_attributes(from: Time.zone.local(2022, 4, 1), to: Time.zone.local(2022, 4, 6))
expect(active_periods(location).second).to have_attributes(from: Time.zone.local(2022, 7, 7), to: nil)
end end
end end

Loading…
Cancel
Save