app/controllers/setup/formula_mappings_controller.rb

Summary

Maintainability
C
7 hrs
Test Coverage
A
94%
# frozen_string_literal: true

class Setup::FormulaMappingsController < PrivateController
  attr_reader :formula_mappings
  helper_method :formula_mappings

  def new
    check_problems
    @formula_mappings = build_formula_mappings(to_options)
  end

  def create
    check_problems

    @formula_mappings = build_formula_mappings(to_options)

    @formula_mappings.mappings.each do |mapping|
      mapping.save! if mapping.valid?
      mapping.destroy! if mapping.external_reference.blank? && mapping.id
    end
    @formula_mappings.mappings = @formula_mappings.mappings.reject(&:destroyed?)

    OutputDatasetWorker.trigger_sync_for_project(current_project)

    render :new
  end

  def create_data_element
    activity = current_project.activities.find(params[:activity_id]) if params[:activity_id]
    formula = Formula.find(params[:formula_id])
    raise "invalid formula id" if formula.project_id != current_project.id

    CreateDhis2ElementForFormulaMappingWorker.perform_async(
      current_project.id,
      "activity_id"  => activity&.id,
      "formula_id"   => formula.id,
      "kind"         => params[:kind],
      "data_element" => {
        "name"       => params[:name],
        "short_name" => params[:short_name],
        "code"       => params[:code]
      }
    )
    render partial: "create_data_element"
  end

  private

  def check_problems
    project = current_project(project_scope: :fully_loaded)
    in_references = project.activities.flat_map(&:activity_states).map(&:external_reference)
    out_references = project.formula_mappings.map(&:external_reference)

    bad_references = in_references & out_references

    @problems = bad_references.map do |bad_reference|
      as = project.activities.flat_map(&:activity_states).select { |as| as.external_reference == bad_reference }.first
      fm = project.formula_mappings.select { |fm| fm.external_reference == bad_reference }.first
      [bad_reference, "MAPPED IN AND OUT", as.activity.name, as.state.name, fm.formula.code, fm.activity&.name]
    end

    @problems += project.formula_mappings.group_by(&:external_reference).select { |_k, v| v.size > 1 }.map do |k, v|
      [k, "MAPPED OUT MULTIPLE TIMES", v.map { |fm| [fm.kind, fm.activity&.name, fm.formula.code] }].flatten
    end

    @to_check = @problems.map(&:first)
  end

  def to_options
    mode_options = {
      missing_only: { missing_only: true },
      activity_only: { package: false, payment: false, zone: false },
      package_only: { activity: false, payment: false, zone: false },
      payment_only: { package: false, activity: false, zone: false },
      all: {},
      create: { missing_only: true },
      nil => { missing_only: true }
    }
    mode_options[params[:mode] ? params[:mode].to_sym : nil]
  end

  def build_formula_mappings(options = {})
    default_options = { activity: true, package: true, payment: true, zone: true, missing_only: false }
    options = default_options.merge(options)
    mappings = []
    project = current_project(project_scope: :fully_loaded)
    mapping_by_key = params[:formula_mappings] ? params[:formula_mappings].index_by { |mapping| [mapping[:formula_id].to_i, mapping[:activity_id].to_i] } : {}

    if options[:activity]
      activity_rules = project.packages.flat_map(&:rules).select(&:activity_related_kind?)

      mappings += activity_rules.map do |rule|
        rule.package
            .activities
            .select { |a| params[:activity_code].presence ? a.code == params[:activity_code] : true }
            .map do |activity|
          rule.formulas.map do |formula|
            mapping = formula.find_or_build_mapping(
              activity: activity,
              kind:     rule.kind
            )
            mapping = missing?(options, mapping)
            if mapping
              mapping.external_reference = external_reference(mapping_by_key[[formula.id, activity.id]]) unless mapping_by_key.empty?
            end
            mapping
          end
        end
      end
    end

    other_rules = []
    unless params[:activity_code].presence
      other_rules += project.packages.flat_map(&:rules).select(&:package_kind?) if options[:package]
      other_rules += project.packages.flat_map(&:rules).select(&:zone_kind?) if options[:zone]
      other_rules += project.payment_rules.flat_map(&:rule) if options[:payment]
    end

    mappings += other_rules.map do |rule|
      rule.formulas.map do |formula|
        mapping = formula.find_or_build_mapping(
          kind: rule.kind
        )
        mapping = missing?(options, mapping)
        if mapping
          mapping.external_reference = external_reference(mapping_by_key[[formula.id, 0]]) unless mapping_by_key.empty?
        end
        mapping
      end
    end
    if params[:formula_code].presence
      mappings = mappings.flatten.compact.select { |mapping| mapping.formula.code == params[:formula_code] }
    end

    FormulaMappings.new(mappings: mappings.flatten.compact, project: project, mode: params[:mode])
  end

  def missing?(options, mapping)
    return mapping if @to_check.include?(mapping.external_reference)

    options[:missing_only] && mapping.id ? nil : mapping
  end

  def external_reference(param)
    param ? param[:external_reference] : nil
  end
end