diff --git a/.rubocop.yml b/.rubocop.yml index ca15931c..02fd138c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -18,6 +18,7 @@ AllCops: - 'bin/*' - 'db/schema.rb' - 'node_modules/**/*' + - 'spec/models/reports/applications_spec.rb' Style/MethodCallWithArgsParentheses: AllowParenthesesInMultilineCall: true diff --git a/app/controllers/system_admin/applicants_controller.rb b/app/controllers/system_admin/applicants_controller.rb index 206bc98e..06bbca36 100644 --- a/app/controllers/system_admin/applicants_controller.rb +++ b/app/controllers/system_admin/applicants_controller.rb @@ -21,19 +21,6 @@ def index session[:application_ids] = results.map(&:id) end - def download_qa_csv - status = session[:filter_status] - application_ids = session[:application_ids] - - applications = Application.where(id: application_ids).reject(&:qa?) - - applications.each(&:mark_as_qa!) - - report = Reports::QaReport.new(applications, status) - create_audit(action: "Downloaded QA CSV report (#{status.humanize})") - send_data(report.csv, filename: report.name) - end - def duplicates @pagy, @duplicates = pagy(DuplicateApplication.search(params[:search]).select("DISTINCT ON (urn) *")) end diff --git a/app/controllers/system_admin/reports_controller.rb b/app/controllers/system_admin/reports_controller.rb index e4187e58..b09876d9 100644 --- a/app/controllers/system_admin/reports_controller.rb +++ b/app/controllers/system_admin/reports_controller.rb @@ -3,20 +3,16 @@ class ReportsController < AdminController def index; end def show - report = find_report(params[:id]) - create_audit(action: "Downloaded #{report.class.to_s.capitalize} report") + service = Report.call(params[:id], **report_params) + create_audit(action: "Downloaded #{service.report_name} report") - send_data(report.csv, filename: report.name) + send_data(service.data, filename: service.filename) end private - def find_report(report_id) - { - home_office: Reports::HomeOffice.new, - standing_data: Reports::StandingData.new, - payroll: Reports::Payroll.new, - }.with_indifferent_access.fetch(report_id) + def report_params + params.permit(:id, :status) end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index dd7e9147..e5e2f9cd 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -20,4 +20,18 @@ def mailto_irp_express_interest def banner_feedback_form govuk_link_to("feedback", "https://forms.office.com/e/p45Wm1Vmxg", target: "_blank") end + + def application_statuses + ApplicationProgress + .statuses + .keys + .map { |status| [status.humanize, status] } + end + + def application_statuses_options(selected: nil, all_statuses: false) + statuses = application_statuses + statuses = application_statuses.unshift(["All statuses", ""]) if all_statuses + + options_for_select(statuses, selected:) + end end diff --git a/app/models/reports/applications.rb b/app/models/reports/applications.rb new file mode 100644 index 00000000..870ce2eb --- /dev/null +++ b/app/models/reports/applications.rb @@ -0,0 +1,79 @@ +module Reports + class Applications + def name + current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S") + + "Applications-Report-#{current_time}.csv" + end + + def csv + CSV.generate do |csv| + csv << header + rows.find_each(batch_size: 50) { |row| csv << columns(row) } + end + end + + private + + def header + %i[ + ip_address + given_name + middle_name + family_name + email_address + phone_number + date_of_birth + sex + passport_number + nationality + student_loan + address_line_1 + address_line_2 + city + postcode + application_date + application_route + status + date_of_entry + start_date + subject + urn + visa_type + ].map { _1.to_s.titleize } + end + + def columns(application) + applicant = application.applicant + [ + applicant.ip_address, + applicant.given_name, + applicant.middle_name, + applicant.family_name, + applicant.email_address, + applicant.phone_number, + applicant.date_of_birth, + applicant.sex, + applicant.passport_number, + applicant.nationality, + applicant.student_loan, + applicant.address.address_line_1, + applicant.address.address_line_2, + applicant.address.city, + applicant.address.postcode, + application.application_date, + application.application_route, + application.status, + application.date_of_entry, + application.start_date, + application.subject, + application.urn, + application.visa_type, + ] + end + + def rows + Application.includes(:applicant, :application_progress, applicant: :address) + end + end +end diff --git a/app/services/report.rb b/app/services/report.rb new file mode 100644 index 00000000..dbfb50b4 --- /dev/null +++ b/app/services/report.rb @@ -0,0 +1,61 @@ +class Report + REGISTERED_REPORTS = { + home_office: Reports::HomeOffice, + standing_data: Reports::StandingData, + payroll: Reports::Payroll, + applications: Reports::Applications, + qa: Reports::QaReport, + }.freeze + + def self.call(...) + service = new(...) + service.data + service + end + + def initialize(report_id, **kwargs) + @kwargs = kwargs&.symbolize_keys || {} + @report_class = REGISTERED_REPORTS.with_indifferent_access.fetch(report_id) + rescue KeyError + raise(ArgumentError, "Invalid report id #{report_id}") + end + + def report_name + report_class.to_s.capitalize + end + + def filename + report.name + end + + def data + report.csv + end + +private + + attr_reader :report_class, :kwargs + + def report + return @report if @report + return @report = report_class.new(*report_args) if report_args + + @report = report_class.new + end + + def report_args + return qa_report_args if report_class == Reports::QaReport + + nil + end + + def qa_report_args + return @qa_report_args if @qa_report_args + + status = kwargs.fetch(:status) + applications = Application.filter_by_status(status).reject(&:qa?) + applications.each(&:mark_as_qa!) + + @qa_report_args = [applications, status] + end +end diff --git a/app/views/system_admin/applicants/index.html.erb b/app/views/system_admin/applicants/index.html.erb index dc6637ab..5aba9eb6 100644 --- a/app/views/system_admin/applicants/index.html.erb +++ b/app/views/system_admin/applicants/index.html.erb @@ -1,8 +1,3 @@ -<% statuses = options_for_select( - ApplicationProgress.statuses.keys.map { |status| [status.humanize, status] }.unshift(['All statuses', '']), - selected: params[:status] - ) -%> <%= form_with(url: applicants_path, method: :get, id: :search) do |f| %>
+ Download a CSV file of all applications +
++ <%= link_to "Download", report_path(:applications), class: "govuk-button" %> +
++ Download a QA CSV file +
++ + <%= form_with(url: report_path(:qa), method: :get) do |f| %> +