ministryofjustice/Claim-for-Crown-Court-Defence

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

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
require 'csv'

module Stats
  class FeeSchemeUsageGenerator
    CLAIM_TYPES =
      %w[Claim::AdvocateClaim
         Claim::AdvocateHardshipClaim
         Claim::AdvocateInterimClaim
         Claim::AdvocateSupplementaryClaim
         Claim::InterimClaim
         Claim::LitigatorClaim
         Claim::LitigatorHardshipClaim
         Claim::TransferClaim].freeze

    include StuffLogger

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

    def initialize(**kwargs)
      @format = kwargs.fetch(:format, :csv)
    end

    def call
      log_info('Fee Scheme Usage Report generation started...')
      output = generate_new_report
      log_info('Fee Scheme Usage Report generation finished')
      Stats::Result.new(output, @format)
    end

    private

    def ordered_fee_schemes
      @ordered_fee_schemes ||= FeeScheme.where(name: %w[AGFS LGFS]).order(:name, :version)
                                        .map { |scheme| "#{scheme.name} #{scheme.version}" }
    end

    def case_types
      CaseType.all.map(&:name)
    end

    def generate_new_report
      CSV.generate do |csv|
        csv << headers
        month_array.each do |month|
          generate_month(csv, month[0], month[1])
          csv << []
        end
      end
    rescue StandardError => e
      log_error(e, 'Fee Scheme Usage Report generation error')
    end

    def generate_month(csv, date_start, date_end)
      generate_data(date_start, date_end)
      ordered_fee_schemes.each do |scheme|
        csv << generate_row(date_start.strftime('%B'), scheme)
      end
    end

    def empty_results_hash
      output = {}
      ordered_fee_schemes.each do |scheme|
        # Hash default set to 0 to simplify building the results csv
        output[symbol_key(scheme)] = Hash.new(0)
      end
      output
    end

    def generate_data(date_start, date_end)
      @results = empty_results_hash

      claims.where(last_submitted_at: date_start..date_end).find_each do |claim|
        fee_scheme = symbol_key("#{claim.fee_scheme.name} #{claim.fee_scheme.version}")
        update_total_claims(fee_scheme)
        update_total_value_of_claims(claim, fee_scheme)
        update_most_recent_claim(claim, fee_scheme)
        update_claim_types(claim, fee_scheme)
        update_case_types(claim, fee_scheme)
      end
    end

    def generate_row(month, fee_scheme)
      key_fs = symbol_key(fee_scheme)
      row = [month, fee_scheme,
             @results[key_fs][:total_claims], @results[key_fs][:total_value].round(2), @results[key_fs][:latest]]

      case_and_claim_types = CLAIM_TYPES + case_types
      case_and_claim_types.each do |type|
        row << @results[key_fs][symbol_key(type)]
      end

      row
    end

    def month_array
      month_array = []
      6.times do |offset|
        month = Time.current - offset.month # Current month will be -0 months
        dates = [
          month.at_beginning_of_month,
          month.at_end_of_month
        ]
        month_array << dates
      end
      month_array.reverse
    end

    def headers
      Settings.fee_scheme_usage_csv_headers.map { |header| header.to_s.humanize }
    end

    def claims
      @claims ||= Claim::BaseClaim.active.non_draft
    end

    def symbol_key(string)
      string.parameterize.underscore.to_sym
    end

    def update_total_claims(fee_scheme)
      @results[fee_scheme][:total_claims] += 1
    end

    def update_total_value_of_claims(claim, fee_scheme)
      claim_total = (claim.total.to_f + claim.vat_amount.to_f).round(2)
      @results[fee_scheme][:total_value] += claim_total
    end

    def update_most_recent_claim(claim, fee_scheme)
      date_submitted = claim.last_submitted_at
      # Rubocop error ignored as rails date types don't have a #zero? method. 0 is set as hash default to simplify
      # building the CSV later.
      return unless @results[fee_scheme][:latest] == 0 || @results[fee_scheme][:latest] < date_submitted
      @results[fee_scheme][:latest] = date_submitted.to_time
    end

    def update_claim_types(claim, fee_scheme)
      claim_type = symbol_key(claim.type)
      @results[fee_scheme][claim_type] += 1
    end

    def update_case_types(claim, fee_scheme)
      return if claim.case_type_id.nil?
      case_type = symbol_key(CaseType.find(claim.case_type_id).name)
      @results[fee_scheme][case_type] += 1
    end
  end
end