Skip to content

Commit

Permalink
Merge branch 'main' into feature/rename-rejection-details-to-comments
Browse files Browse the repository at this point in the history
  • Loading branch information
raul-gracia committed Oct 5, 2023
2 parents 00941b1 + 55205ea commit 679bce6
Show file tree
Hide file tree
Showing 30 changed files with 436 additions and 190 deletions.
6 changes: 3 additions & 3 deletions app/controllers/system_admin/reports_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ class ReportsController < AdminController
def index; end

def show
service = Report.call(params[:id], **report_params)
create_audit(action: "Downloaded #{service.report_name} report")
report = Report.call(params[:id], **report_params)
create_audit(action: "Downloaded #{report.name} report")

send_data(service.data, filename: service.filename)
send_data(report.data, filename: report.filename)
end

private
Expand Down
18 changes: 7 additions & 11 deletions app/models/reports/applications.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
module Reports
class Applications
def name
current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S")

"Applications-Report-#{current_time}.csv"
end

class Applications < Base
def csv
CSV.generate do |csv|
csv << header
Expand All @@ -17,7 +11,7 @@ def csv

def header
%i[
ip_address
urn
given_name
middle_name
family_name
Expand All @@ -38,15 +32,16 @@ def header
date_of_entry
start_date
subject
urn
visa_type
rejection_reason
ip_address
].map { _1.to_s.titleize }
end

def columns(application)
applicant = application.applicant
[
applicant.ip_address,
application.urn,
applicant.given_name,
applicant.middle_name,
applicant.family_name,
Expand All @@ -67,8 +62,9 @@ def columns(application)
application.date_of_entry,
application.start_date,
application.subject,
application.urn,
application.visa_type,
application.application_progress.rejection_reason,
applicant.ip_address,
]
end

Expand Down
20 changes: 20 additions & 0 deletions app/models/reports/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module Reports
class Base
def initialize(**kwargs)
@kwargs = kwargs
@name = self.class.name.titleize.tr(" /", "-").downcase
end

attr_reader :name, :kwargs

def filename
current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S")

"#{name}-#{current_time}.csv"
end

def csv; end

def post_generation_hook; end
end
end
16 changes: 6 additions & 10 deletions app/models/reports/home_office.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
# frozen_string_literal: true

module Reports
class HomeOffice
def name
current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S")

"Home-Office-Report-#{current_time}.csv"
end

class HomeOffice < Base
def csv
csv_file = CSV.generate do |csv|
CSV.generate do |csv|
csv << header
rows.each { |row| csv << row }
end
end

def post_generation_hook
applications.update_all(home_office_csv_downloaded_at: Time.zone.now) # rubocop:disable Rails/SkipsModelValidations
csv_file
end

private
Expand All @@ -40,7 +36,7 @@ def rows
end

def applications
Application
@applications ||= Application
.joins(:application_progress)
.includes(:applicant)
.where.not(application_progresses: { initial_checks_completed_at: nil })
Expand Down
16 changes: 6 additions & 10 deletions app/models/reports/payroll.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
# frozen_string_literal: true

module Reports
class Payroll
def name
current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S")

"Payroll-Report-#{current_time}.csv"
end

class Payroll < Base
def csv
csv_file = CSV.generate do |csv|
CSV.generate do |csv|
csv << header
rows.each { |row| csv << row }
end
end

def post_generation_hook
applications.update_all(payroll_csv_downloaded_at: Time.zone.now) # rubocop:disable Rails/SkipsModelValidations
csv_file
end

private
Expand Down Expand Up @@ -56,7 +52,7 @@ def rows
end

def applications
Application
@applications ||= Application
.joins(:application_progress)
.joins(applicant: :address)
.where.not(application_progresses: { banking_approval_completed_at: nil })
Expand Down
34 changes: 23 additions & 11 deletions app/models/reports/qa_report.rb
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
module Reports
class QaReport
attr_reader :applications, :status

def initialize(applications, status)
@applications = applications
@status = status
end

def name
current_time = Time.zone.now.strftime("%Y_%m_%d-%H_%M_%S")
"QA-Report-#{status}-#{current_time}.csv"
class QaReport < Base
def initialize(...)
super(...)
@name = [@name, status].join("-")
end

def csv
Expand All @@ -19,8 +12,27 @@ def csv
end
end

def post_generation_hook
applications.each(&:mark_as_qa!)
end

def status
kwargs.fetch(:status)
end

private

def applications
@applications ||= Application
.includes(
:applicant,
:application_progress,
applicant: :address,
)
.filter_by_status(status)
.reject(&:qa?)
end

def rows
applications.map do |application|
[
Expand Down
16 changes: 6 additions & 10 deletions app/models/reports/standing_data.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
# frozen_string_literal: true

module Reports
class StandingData
def name
current_time = Time.zone.now.strftime("%Y%m%d-%H%M%S")

"Standing-Data-Report-#{current_time}.csv"
end

class StandingData < Base
def csv
csv_file = CSV.generate do |csv|
CSV.generate do |csv|
csv << header
rows.each { |row| csv << row }
end
end

def post_generation_hook
applications.update_all(standing_data_csv_downloaded_at: Time.zone.now) # rubocop:disable Rails/SkipsModelValidations
csv_file
end

private
Expand All @@ -34,7 +30,7 @@ def rows
end

def applications
Application
@applications ||= Application
.joins(:application_progress)
.joins(applicant: :address)
.where.not(application_progresses: { school_checks_completed_at: nil })
Expand Down
63 changes: 33 additions & 30 deletions app/models/urn.rb
Original file line number Diff line number Diff line change
@@ -1,38 +1,41 @@
# frozen_string_literal: true

# Urn represents a Uniform Resource Name (URN) generator.
# It generates a URN with a fixed prefix and a random alphanumeric suffix.
#
# == Schema Information
#
# Example:
# Table name: urns
#
# Urn.generate('teacher') # => "IRPTE12345"
# Urn.generate('teacher') # => "IRPTE12345"
# Urn.generate('salaried_trainee') # => "IRPST12345"
# id :bigint not null, primary key
# code :string
# prefix :string
# suffix :integer
# created_at :datetime not null
# updated_at :datetime not null
#
class Urn
attr_reader :value
attr_writer :suffix

def self.generate(applicant_type)
code = applicant_type_code(applicant_type)
PREFIX + code + Array.new(LENGTH) { CHARSET.sample }.join
end
class Urn < ApplicationRecord
class NoUrnAvailableError < StandardError; end

CHARSET = %w[0 1 2 3 4 5 6 7 8 9].freeze
PREFIX = "IRP"
LENGTH = 5
private_constant :CHARSET, :PREFIX, :LENGTH
PREFIX = "IRP".freeze
MAX_SUFFIX = 99_999
PADDING_SIZE = MAX_SUFFIX.to_s.size
VALID_CODES = {
"teacher" => "TE",
"salaried_trainee" => "ST",
}.freeze

def self.applicant_type_code(applicant_type)
case applicant_type
when "teacher"
"TE"
when "salaried_trainee"
"ST"
else
raise(ArgumentError, "Invalid applicant type: #{applicant_type}")
def self.next(route)
code = VALID_CODES.fetch(route)
Urn.transaction do
urn = find_by!(code:)
urn.destroy!
urn.to_s
end
rescue KeyError => e
Sentry.capture_exception(e)
raise(ArgumentError, "Unknown route #{route}")
rescue ActiveRecord::RecordNotFound => e
Sentry.capture_exception(e)
raise(NoUrnAvailableError, "There no more unique URN available for #{route}")
end

def to_s
[prefix, code, sprintf("%0#{PADDING_SIZE}d", suffix)].join
end
private_methods :applicant_type_code
end
62 changes: 62 additions & 0 deletions app/services/generate_urns.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Service responsible for the generation of all urns
# It will save the set of available urns based the current URN format
# and store it in the database URNs table.
#
# The Urn model will then be able to fetch the next available unique and
# random urn for application submition
#
# Example:
#
# Urn.next("teacher") # => "IRPTE12345"
# Urn.next("teacher") # => "IRPTE12345"
# Urn.next("salaried_trainee") # => "IRPST12345"
#
class GenerateUrns
def self.call
return if Urn.count.positive? # Do not override the current urn state

Urn.transaction do
Urn::VALID_CODES.each_value do |code|
new(code:).generate
end
end
end

def initialize(code:)
@code = code
end

attr_reader :code

def generate
data = unused_urns.map do |suffix|
{ prefix: Urn::PREFIX, code: code, suffix: suffix }
end
Urn.insert_all(data) # rubocop:disable Rails/SkipsModelValidations
end

private

def unused_urns
generate_suffixes - existing_suffixes
end

def generate_suffixes
Array
.new(Urn::MAX_SUFFIX) { _1 }
.drop(1)
.shuffle!
end

def existing_suffixes
route = Urn::VALID_CODES.key(code)
Application
.where(application_route: route)
.pluck(:urn)
.map { extract_suffix(_1) }
end

def extract_suffix(urn)
urn.match(/\d+/)[0].to_i
end
end
Loading

0 comments on commit 679bce6

Please sign in to comment.