codeforamerica/clientcomm-rails

View on GitHub
app/admin/reporting_relationship.rb

Summary

Maintainability
A
3 hrs
Test Coverage
ActiveAdmin.register ReportingRelationship do
  menu false

  form title: 'Transfer Client' do |f|
    active_user = resource.user
    department = active_user&.department || Department.find(params['department_id'])
    department_users = department.users.active.order(full_name: :asc)
    options = options_from_collection_for_select(
      department_users,
      :id,
      :full_name,
      active_user.try(:id)
    )

    unread_warning = resource.messages.unread.any? ? I18n.t('views.admin.reporting_relationships.edit.unread_transfer') : ''
    transfer_label = resource.messages.unread.any? ? 'Transfer Client and Mark Messages As Read' : 'Transfer Client'

    form_user = f.object.user || User.new(department: department)
    f.inputs 'Change user', for: form_user do |u|
      u.input :department_id, as: :hidden
      # rubocop:disable Rails/OutputSafety
      u.template.concat "<input type='hidden' id='reporting_relationship_client_id' name='reporting_relationship[client_id]' value='#{params['client_id']}'>".html_safe
      u.template.concat "<input type='hidden' id='reporting_relationship_force_transfer' name='reporting_relationship[force_transfer]' value='true'>".html_safe if resource.messages.unread.any?
      u.template.concat "<li><label class='label'>Current user</label><span>#{form_user.full_name || 'None'}</span></li>".html_safe
      u.input :id, label: 'Transfer to:',
                   as: :select,
                   collection: options,
                   include_blank: true,
                   hint: unread_warning,
                   input_html: { multiple: false, id: "user_in_dept_#{department.id}" }
      u.template.concat "<li><label class='label' for='transfer_note'>Include a message for the new user</label><textarea id='transfer_note' name='transfer[note]'></textarea></li>".html_safe
      # rubocop:enable Rails/OutputSafety
    end
    f.actions do
      f.action :submit, as: :button, label: transfer_label
      f.action :cancel, label: 'Cancel', wrapper_html: { class: 'cancel' }
    end
  end

  controller do
    def create
      rr_id = params['id']
      client_id = params['reporting_relationship']['client_id']
      target_user_id = params['reporting_relationship']['user']['id']
      transfer_note = params['transfer']['note']
      department_id = params['reporting_relationship']['user']['department_id']

      new_user = User.find_by(id: target_user_id, department_id: department_id)

      rr = ReportingRelationship.find_or_create_by(id: rr_id, user: new_user, client_id: client_id)

      had_unread_messages = rr.has_unread_messages

      client = rr.client
      department = Department.find(department_id)
      old_users = department.users

      transfer_messages(client: client, old_users: old_users, new_user: new_user)

      deactivate_old_relationships(client: client, users: old_users)

      transfer_client_and_mail_and_track(
        client: client,
        previous_user: nil,
        new_user: new_user,
        transfer_note: transfer_note,
        client_status: nil,
        unread_messages: had_unread_messages
      )

      flash[:success] = "#{client.full_name} has been assigned to #{new_user.full_name} in #{department.name}"
      redirect_to(admin_client_path(client))
    end

    def update
      rr_id = params['id']
      target_user_id = params['reporting_relationship']['user']['id']
      transfer_note = params['transfer']['note']
      department_id = params['reporting_relationship']['user']['department_id']

      rr = ReportingRelationship.find(rr_id)

      new_user = User.find_by(id: target_user_id, department_id: department_id)

      previous_user = rr.user

      if rr.messages.unread.any? && !params['reporting_relationship']['force_transfer']
        redirect_to(edit_admin_reporting_relationship_path(rr))
        return
      end

      redirect_to(admin_client_path(rr.client)) && return if new_user == previous_user

      client = rr.client
      department = Department.find(department_id)
      old_users = department.users

      had_unread_messages = rr.has_unread_messages

      deactivate_old_relationships(client: client, users: old_users)

      if new_user.blank?
        flash[:success] = "#{client.full_name} has been deactivated for #{previous_user.full_name} in #{department.name}."
        redirect_to(admin_client_path(client)) && return
      end

      transfer_client_and_mail_and_track(
        client: client,
        previous_user: previous_user,
        new_user: new_user,
        transfer_note: transfer_note,
        client_status: rr.client_status,
        unread_messages: had_unread_messages
      )

      transfer_messages(client: client, old_users: old_users, new_user: new_user)

      new_rr = ReportingRelationship.find_by(client: client, user: new_user)
      Message.create_transfer_markers(sending_rr: rr, receiving_rr: new_rr)

      flash[:success] = "#{client.full_name} has been assigned to #{new_user.full_name} in #{department.name}"
      redirect_to(admin_client_path(client))
    end

    private

    def transfer_messages(client:, old_users:, new_user:)
      original_rrs = ReportingRelationship.where(client: client, user: old_users)
      original_messages = Message.where(reporting_relationship: original_rrs).scheduled

      new_rr = ReportingRelationship.find_by(client: client, user: new_user)
      original_messages.update(reporting_relationship: new_rr)

      # rubocop:disable Style/GuardClause
      if new_user.present?
        unclaimed_rr = ReportingRelationship.find_by(client: client, user: new_user.department.unclaimed_user)
        unclaimed_messages = unclaimed_rr.messages if unclaimed_rr
        unclaimed_messages.update(reporting_relationship: new_rr) if unclaimed_messages.present?
      end
      # rubocop:enable Style/GuardClause
    end

    def deactivate_old_relationships(client:, users:)
      ReportingRelationship.where(client: client, user: users).each do |relationship|
        relationship.update!(active: false, has_unread_messages: false)
        relationship.messages.unread.update(read: true)
        if relationship.user.reporting_relationships.active.where(has_unread_messages: true).empty?
          relationship.user.update!(has_unread_messages: false)
        end
      end
    end

    def transfer_client_and_mail_and_track(client:, previous_user:, new_user:, transfer_note:, client_status:, unread_messages:)
      new_user.reporting_relationships.find_or_create_by(client: client).update!(active: true, client_status: client_status)
      NotificationMailer.client_transfer_notification(
        current_user: new_user,
        previous_user: previous_user,
        client: client,
        transfer_note: transfer_note,
        transferred_by: 'admin'
      ).deliver_later

      analytics_track(
        label: :client_transfer,
        data: {
          admin_id: current_user.id,
          clients_transferred_count: 1,
          transferred_by: 'admin',
          has_transfer_note: transfer_note.present?,
          unread_messages: unread_messages
        }
      )
    end
  end
end