diff --git a/app/jobs/daily_usages/fill_history_job.rb b/app/jobs/daily_usages/fill_history_job.rb new file mode 100644 index 00000000000..40df65091f5 --- /dev/null +++ b/app/jobs/daily_usages/fill_history_job.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module DailyUsages + class FillHistoryJob < ApplicationJob + queue_as 'low_priority' + + def perform(subscription:, from_datetime:) + DailyUsages::FillHistoryService.call!(subscription:, from_datetime:) + end + end +end diff --git a/app/services/daily_usages/fill_history_service.rb b/app/services/daily_usages/fill_history_service.rb new file mode 100644 index 00000000000..9b1882038ef --- /dev/null +++ b/app/services/daily_usages/fill_history_service.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +module DailyUsages + class FillHistoryService < BaseService + def initialize(subscription:, from_datetime:) + @subscription = subscription + @from_datetime = from_datetime + + super + end + + def call + previous_daily_usage = nil + + (from..to).each do |date| + datetime = date.in_time_zone(subscription.customer.applicable_timezone).beginning_of_day.utc + + next if date == Time.zone.today && + DailyUsage.refreshed_at_in_timezone(datetime).where(subscription_id: subscription.id).exists? + + Timecop.freeze(datetime + 5.minutes) do + usage = Invoices::CustomerUsageService.call( + customer: subscription.customer, + subscription: subscription, + apply_taxes: false, + with_cache: false, + max_to_datetime: datetime + ).raise_if_error!.usage + + if previous_daily_usage.present? && previous_daily_usage.from_datetime != usage.from_datetime + # NOTE: A new billing period was started, the diff should contains the complete current usage + previous_daily_usage = nil + end + + daily_usage = DailyUsage.new( + organization:, + customer: subscription.customer, + subscription:, + external_subscription_id: subscription.external_id, + usage: ::V1::Customers::UsageSerializer.new(usage, includes: %i[charges_usage]).serialize, + from_datetime: usage.from_datetime, + to_datetime: usage.to_datetime, + refreshed_at: datetime + ) + + daily_usage.usage_diff = DailyUsages::ComputeDiffService + .call(daily_usage:, previous_daily_usage:) + .raise_if_error! + .usage_diff + + daily_usage.save! + + previous_daily_usage = daily_usage + end + end + + result + end + + attr_reader :subscription, :from_datetime + delegate :organization, to: :subscription + + def from + return @from if defined?(@from) + + @from = subscription.started_at.to_date + @from = from_datetime.to_date if @from < from_datetime + @from + end + + def to + @to ||= (subscription.terminated_at || Time.current).to_date + end + end +end diff --git a/lib/tasks/daily_usages.rake b/lib/tasks/daily_usages.rake index bda6552eeb8..b7bef5842ee 100644 --- a/lib/tasks/daily_usages.rake +++ b/lib/tasks/daily_usages.rake @@ -19,56 +19,7 @@ namespace :daily_usages do .includes(customer: :organization) subscriptions.find_each do |subscription| - from = subscription.started_at.to_date - if from < days_ago - from = days_ago.to_date - end - - to = (subscription.terminated_at || Time.current).to_date - - previous_daily_usage = nil - - (from..to).each do |date| - datetime = date.in_time_zone(subscription.customer.applicable_timezone).beginning_of_day.utc - - next if date == Date.today && - DailyUsage.refreshed_at_in_timezone(datetime).where(subscription_id: subscription.id).exists? - - Timecop.freeze(datetime + 5.minutes) do - usage = Invoices::CustomerUsageService.call( - customer: subscription.customer, - subscription: subscription, - apply_taxes: false, - with_cache: false, - max_to_datetime: datetime - ).raise_if_error!.usage - - if previous_daily_usage.present? && previous_daily_usage.from_datetime != usage.from_datetime - # NOTE: A new billing period was started, the diff should contains the complete current usage - previous_daily_usage = nil - end - - daily_usage = DailyUsage.new( - organization:, - customer: subscription.customer, - subscription:, - external_subscription_id: subscription.external_id, - usage: ::V1::Customers::UsageSerializer.new(usage, includes: %i[charges_usage]).serialize, - from_datetime: usage.from_datetime, - to_datetime: usage.to_datetime, - refreshed_at: datetime - ) - - daily_usage.usage_diff = DailyUsages::ComputeDiffService - .call(daily_usage:, previous_daily_usage:) - .raise_if_error! - .usage_diff - - daily_usage.save! - - previous_daily_usage = daily_usage - end - end + DailyUsages::FillHistoryJob.perform_later(subscription:, from_datetime: days_ago) end end end