From cc26321ab282f03c8c629feb570cb258b6a2fd40 Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Wed, 8 Jul 2015 15:29:41 +0800 Subject: [PATCH] Billable Period Updater does not run when end_date is in the future --- app/jobs/update_billable_periods.rb | 40 +++++++++--- spec/jobs/update_billable_periods_spec.rb | 75 +++++++++++++++++------ 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/app/jobs/update_billable_periods.rb b/app/jobs/update_billable_periods.rb index 16a4c1a12a..82d9973874 100644 --- a/app/jobs/update_billable_periods.rb +++ b/app/jobs/update_billable_periods.rb @@ -1,9 +1,7 @@ -UpdateBillablePeriods = Struct.new("UpdateBillablePeriods") do +UpdateBillablePeriods = Struct.new("UpdateBillablePeriods", :year, :month) do def perform - # If it is the first of the month, calculate turnover for the previous month up until midnight last night - # Otherwise, calculate turnover for the current month - start_date = (Time.now - 1.day).beginning_of_month - end_date = Time.now.beginning_of_day + return unless end_date <= Time.now + job_start_time = Time.now enterprises = Enterprise.select([:id, :name, :owner_id, :sells, :shop_trial_start_date, :created_at]) @@ -32,7 +30,7 @@ UpdateBillablePeriods = Struct.new("UpdateBillablePeriods") do split_for_trial(enterprise, begins_at, ends_at, trial_start, trial_expiry) - clean_up_untouched_billable_periods_for(enterprise, start_date, job_start_time) + clean_up_untouched_billable_periods_for(enterprise, job_start_time) end end @@ -76,14 +74,14 @@ UpdateBillablePeriods = Struct.new("UpdateBillablePeriods") do billable_period.touch end - def clean_up_untouched_billable_periods_for(enterprise, start_of_month, job_start_time) + def clean_up_untouched_billable_periods_for(enterprise, job_start_time) # Snag and then delete any BillablePeriods which overlap - obsolete_billable_periods = enterprise.billable_periods.where('ends_at >= (?) AND updated_at < (?)', start_of_month, job_start_time) + obsolete_billable_periods = enterprise.billable_periods.where('ends_at >= (?) AND updated_at < (?)', start_date, job_start_time) if obsolete_billable_periods.any? - current_billable_periods = enterprise.billable_periods.where('ends_at >= (?) AND updated_at >= (?)', start_of_month, job_start_time) + current_billable_periods = enterprise.billable_periods.where('ends_at >= (?) AND updated_at >= (?)', start_date, job_start_time) - Delayed::Worker.logger.info "#{enterprise.name} #{start_of_month.strftime("%F %T")} #{job_start_time.strftime("%F %T")}" + Delayed::Worker.logger.info "#{enterprise.name} #{start_date.strftime("%F %T")} #{job_start_time.strftime("%F %T")}" Delayed::Worker.logger.info "#{obsolete_billable_periods.first.updated_at.strftime("%F %T")}" Bugsnag.notify(RuntimeError.new("Obsolete BillablePeriods"), { @@ -94,4 +92,26 @@ UpdateBillablePeriods = Struct.new("UpdateBillablePeriods") do obsolete_billable_periods.each(&:delete) end + + private + + def start_date + # Start at the beginning of the specified month + # or at the beginning of the month (prior to midnight last night) if none specified + @start_date ||= if month && year + Time.new(year, month) + else + (Time.now - 1.day).beginning_of_month + end + end + + def end_date + # Stop at the end of the specified month + # or at midnight last night if no month is specified + @end_date ||= if month && year + Time.new(year, month) + 1.month + else + Time.now.beginning_of_day + end + end end diff --git a/spec/jobs/update_billable_periods_spec.rb b/spec/jobs/update_billable_periods_spec.rb index f4b57db6f3..3d850587f3 100644 --- a/spec/jobs/update_billable_periods_spec.rb +++ b/spec/jobs/update_billable_periods_spec.rb @@ -14,31 +14,67 @@ describe UpdateBillablePeriods do let!(:enterprise) { create(:supplier_enterprise, created_at: start_of_july - 1.month, sells: 'any') } before do - expect(updater).to receive(:clean_up_untouched_billable_periods_for).once allow(Enterprise).to receive(:select) { [enterprise] } end - context "on the first of the month" do - travel_to(3.hours) + context "when no arguments are passed to the job" do + before do + expect(updater).to receive(:clean_up_untouched_billable_periods_for).once + end - it "processes the previous month" do - expect(updater).to receive(:split_for_trial) - .with(enterprise, start_of_july - 1.month, start_of_july, nil, nil) - updater.perform + context "on the first of the month" do + travel_to(3.hours) + + it "processes the previous month" do + expect(updater).to receive(:split_for_trial) + .with(enterprise, start_of_july - 1.month, start_of_july, nil, nil) + updater.perform + end + end + + context "on all other days" do + travel_to(1.day + 3.hours) + + it "processes the current month up until previous midnight" do + expect(updater).to receive(:split_for_trial) + .with(enterprise, start_of_july, start_of_july + 1.day, nil, nil) + updater.perform + end end end - context "on all other days" do - travel_to(1.day + 3.hours) + context "when a specfic year and month are passed as arguments" do + let!(:updater) { UpdateBillablePeriods.new(Time.now.year, 6) } - it "processes the current month up until previous midnight" do - expect(updater).to receive(:split_for_trial) - .with(enterprise, start_of_july, start_of_july + 1.day, nil, nil) - updater.perform + before do + allow(updater).to receive(:split_for_trial) + end + + context "that ends in the past" do + travel_to(3.hours) + + it "processes the previous month" do + expect(updater).to receive(:split_for_trial) + .with(enterprise, start_of_july - 1.month, start_of_july, nil, nil) + updater.perform + end + end + + context "that ends in the future" do + travel_to(-1.day) + + it "does not run" do + expect(updater).to_not receive(:split_for_trial) + updater.perform + end end end context "when an enterprise is created before the beginning of the current month" do + before do + expect(updater).to receive(:clean_up_untouched_billable_periods_for).once + end + travel_to(28.days) context "when no alterations to sells or owner have been made during the current month" do @@ -142,6 +178,7 @@ describe UpdateBillablePeriods do context "when an enterprise is created during the current month" do before do + expect(updater).to receive(:clean_up_untouched_billable_periods_for).once enterprise.update_attribute(:created_at, start_of_july + 10.days) end @@ -157,6 +194,7 @@ describe UpdateBillablePeriods do pending "when an enterprise is deleted during the current month" do before do + expect(updater).to receive(:clean_up_untouched_billable_periods_for).once enterprise.update_attribute(:deleted_at, start_of_july + 20.days) end @@ -409,15 +447,16 @@ describe UpdateBillablePeriods do end context "cleaning up untouched billable periods" do - let(:now) { Time.now } + let(:job_start_time) { Time.now } let(:enterprise) { create(:enterprise) } - let!(:bp1) { create(:billable_period, enterprise: enterprise, updated_at: now + 2.seconds, begins_at: start_of_july, ends_at: start_of_july + 5.days ) } - let!(:bp2) { create(:billable_period, enterprise: enterprise, updated_at: now + 2.seconds, begins_at: start_of_july + 5.days, ends_at: start_of_july + 10.days ) } - let!(:bp3) { create(:billable_period, enterprise: enterprise, updated_at: now - 5.seconds, begins_at: start_of_july, ends_at: start_of_july + 10.days ) } + let!(:bp1) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time + 2.seconds, begins_at: start_of_july, ends_at: start_of_july + 5.days ) } + let!(:bp2) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time + 2.seconds, begins_at: start_of_july + 5.days, ends_at: start_of_july + 10.days ) } + let!(:bp3) { create(:billable_period, enterprise: enterprise, updated_at: job_start_time - 5.seconds, begins_at: start_of_july, ends_at: start_of_july + 10.days ) } before do allow(Bugsnag).to receive(:notify) - updater.clean_up_untouched_billable_periods_for(enterprise, start_of_july, now) + allow(updater).to receive(:start_date) { start_of_july } + updater.clean_up_untouched_billable_periods_for(enterprise, job_start_time) end it "soft deletes untouched billable_periods" do