ministryofjustice/Claim-for-Crown-Court-Defence

View on GitHub
app/services/stats/stats_report_generator.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
module Stats
  class StatsReportGenerator
    class InvalidReportType < StandardError; end

    # rubocop:disable Metrics/MethodLength
    def self.for(report_type)
      Hash.new({ class: SimpleReportGenerator, default_args: {} }).merge(
        management_information:
          { class: ManagementInformationGenerator,
            default_args: {} },
        agfs_management_information:
          { class: ManagementInformationGenerator,
            default_args: { scheme: :agfs } },
        lgfs_management_information:
          { class: ManagementInformationGenerator,
            default_args: { scheme: :lgfs } },
        fee_scheme_usage:
          { class: FeeSchemeUsageGenerator,
            default_args: {} },
        management_information_v2:
          { class: Stats::ManagementInformation::DailyReportGenerator,
            default_args: {} },
        agfs_management_information_v2:
          { class: Stats::ManagementInformation::DailyReportGenerator,
            default_args: { scheme: :agfs } },
        lgfs_management_information_v2:
          { class: Stats::ManagementInformation::DailyReportGenerator,
            default_args: { scheme: :lgfs } },
        agfs_management_information_statistics:
          { class: Stats::ManagementInformation::DailyReportCountGenerator,
            default_args: { query_set: Stats::ManagementInformation::AGFSQuerySet.new, duration: (1.month - 1.day) } },
        lgfs_management_information_statistics:
          { class: Stats::ManagementInformation::DailyReportCountGenerator,
            default_args: { query_set: Stats::ManagementInformation::LGFSQuerySet.new, duration: (1.month - 1.day) } }
      )[report_type.to_sym]
    end
    # rubocop:enable Metrics/MethodLength

    def self.call(...)
      new(...).call
    end

    def initialize(**kwargs)
      @report_type = kwargs[:report_type]
      @generator = self.class.for(report_type)
      @options = kwargs
    end

    def call
      validate_report_type
      StatsReport.clean_up(report_type)
      return if StatsReport.generation_in_progress?(report_type)
      report_record = Stats::StatsReport.record_start(report_type)
      report_contents = generate_new_report
      report_record.write_report(report_contents)
    rescue StandardError => e
      report_record&.update(status: 'error')
      notify_error(report_record, e)
      raise
    end

    private

    attr_reader :report_type, :generator, :options

    def validate_report_type
      raise InvalidReportType unless StatsReport.reports[report_type]
    end

    def generate_new_report
      generator[:class].call(**options.merge(generator[:default_args]))
    end

    def notify_error(report_record, error)
      return unless Settings.notify_report_errors
      ActiveSupport::Notifications.instrument('call_failed.stats_report',
                                              id: report_record&.id, name: report_type, error:)
    end
  end
end