3scale/porta

View on GitHub
app/workers/billing_worker.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

class BillingWorker
  include Sidekiq::Job

  sidekiq_options queue: :billing, retry: 3

  sidekiq_retry_in do |_count|
    # after lock has been released
    1.hours + 10
  end

  class Callback
    delegate :logger, to: 'Rails'

    def on_complete(status, options)
      batch_id = options['batch_id']
      account_id = options['account_id']
      billing_date = options['billing_date']

      logger.info("Billing batch complete: #{batch_id} (account_id: #{account_id}, billing_date: #{billing_date})")

      billing_summary = BillingSummary.new(batch_id)
      billing_service = Finance::BillingService.new(account_id, now: billing_date)
      billing_service.notify_billing_finished(status, billing_summary.build_result(account_id, billing_date))
      billing_summary.unstore

      batch_status = Sidekiq::Batch::Status.new(batch_id)
      batch_status.try(:delete)
    end
  end

  # @param [Account] provider
  # @param [Time] billing_date
  # @param [ActiveRecord::Relation] buyers_scope
  def self.enqueue(provider, billing_date, buyers_scope = nil)

    with_billing_batch(provider.id, billing_date) do
      scope = provider.buyer_accounts.select(:id, :provider_account_id)
      scope = scope.merge(buyers_scope) if buyers_scope
      scope.find_in_batches do |group|
        group.each { |buyer| enqueue_for_buyer(buyer, billing_date) }
      end
    end
  end

  def self.enqueue_for_buyer(buyer, billing_date)
    if buyer.id == buyer.provider_account_id
      System::ErrorReporting.report_error(ArgumentError.new("invalid buyer #{buyer.id}, has self as provider"),
                                          buyer_id: buyer.id,
                                          billing_date: billing_date)
      return
    end

    time = billing_date.to_s(:iso8601)
    perform_async(buyer.id, buyer.provider_account_id, time)
  end

  def self.with_billing_batch(provider_id, billing_date, &block)
    batch = Sidekiq::Batch.new
    batch.description = "Billing (id: #{provider_id})"
    batch.on(:complete, BillingWorker::Callback, batch_id: batch.bid, account_id: provider_id, billing_date: billing_date)
    batch.jobs(&block)
  end

  # @param [Integer] buyer_id
  # @param [Integer] provider_id
  # @param [String] time
  def perform(buyer_id, provider_id, time)
    Rails.logger.info("[billing] provider #{provider_id} buyer #{buyer_id}: BillingWorker#perform invoked at #{time}")
    billing_results = Finance::BillingService.call!(buyer_id, { provider_account_id: provider_id, now: time, skip_notifications: true })
    store_summary(buyer_id, billing_results[provider_id]) if billing_results
  end

  private

  def store_summary(buyer_id, billing_result)
    summary = BillingSummary.new(batch && bid)
    summary.store(buyer_id, billing_result)
  end

  delegate :logger, to: :Rails
end