-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3331 from DFE-Digital/CAPT-1185/flag-known-ninos-…
…and-trns Add fraud check
- Loading branch information
Showing
36 changed files
with
920 additions
and
22 deletions.
There are no files selected for viewing
25 changes: 25 additions & 0 deletions
25
app/controllers/admin/fraud_risk_csv_downloads_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module Admin | ||
class FraudRiskCsvDownloadsController < BaseAdminController | ||
before_action :ensure_service_operator | ||
|
||
def show | ||
respond_to do |format| | ||
format.csv do | ||
send_data(csv, filename: "fraud_risk.csv") | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def csv | ||
CSV.generate do |csv| | ||
csv << %w[field value] | ||
|
||
RiskIndicator.order(created_at: :asc).pluck(:field, :value).each do |row| | ||
csv << row | ||
end | ||
end | ||
end | ||
end | ||
end |
28 changes: 28 additions & 0 deletions
28
app/controllers/admin/fraud_risk_csv_uploads_controller.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
module Admin | ||
class FraudRiskCsvUploadsController < BaseAdminController | ||
before_action :ensure_service_operator | ||
|
||
def new | ||
@form = FraudRiskCsvUploadForm.new | ||
end | ||
|
||
def create | ||
@form = FraudRiskCsvUploadForm.new(fraud_risk_csv_upload_params) | ||
|
||
if @form.save | ||
redirect_to( | ||
new_admin_fraud_risk_csv_upload_path, | ||
notice: "Fraud prevention list uploaded successfully." | ||
) | ||
else | ||
render :new | ||
end | ||
end | ||
|
||
private | ||
|
||
def fraud_risk_csv_upload_params | ||
params.fetch(:admin_fraud_risk_csv_upload_form, {}).permit(:file) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
module Admin | ||
class FraudRiskCsvUploadForm | ||
include ActiveModel::Model | ||
|
||
attr_accessor :file | ||
|
||
validates :file, presence: {message: "CSV file is required"} | ||
|
||
validate :csv_has_required_headers, if: -> { file.present? } | ||
|
||
validate :all_rows_are_valid, if: -> { file.present? && csv_has_required_headers? } | ||
|
||
def initialize(params = {}) | ||
super | ||
end | ||
|
||
def save | ||
return false unless valid? | ||
|
||
ApplicationRecord.transaction do | ||
RiskIndicator.where.not(id: records.map(&:id)).destroy_all | ||
|
||
records.each(&:save!) | ||
|
||
claims_to_note.each do |claim| | ||
AutomatedChecks::ClaimVerifiers::FraudRisk.new(claim: claim).perform | ||
end | ||
end | ||
|
||
true | ||
end | ||
|
||
private | ||
|
||
def csv | ||
@csv ||= CSV.parse(file.read, headers: true, skip_blanks: true) | ||
end | ||
|
||
def records | ||
@records ||= csv.map do |row| | ||
RiskIndicator.find_or_initialize_by(row.to_h) | ||
end.uniq { |record| record.attributes.slice("field", "value") } | ||
end | ||
|
||
def all_rows_are_valid | ||
csv.each do |row| | ||
unless RiskIndicator::SUPPORTED_FIELDS.include?(row["field"]) | ||
errors.add( | ||
:base, | ||
"'#{row["field"]}' is not a valid attribute - " \ | ||
"must be one of #{RiskIndicator::SUPPORTED_FIELDS.join(", ")}" | ||
) | ||
end | ||
|
||
if row["value"].blank? | ||
errors.add(:base, "'value' can't be blank") | ||
end | ||
end | ||
end | ||
|
||
def csv_has_required_headers | ||
unless csv_has_required_headers? | ||
errors.add(:base, "csv is missing required headers `field`, `value`") | ||
end | ||
end | ||
|
||
def csv_has_required_headers? | ||
csv.headers.include?("field") && csv.headers.include?("value") | ||
end | ||
|
||
def claims_to_note | ||
flagged_eligibility_claim_ids = Policies.with_attribute(:teacher_reference_number).flat_map do |policy| | ||
policy::Eligibility | ||
.where(teacher_reference_number: RiskIndicator.teacher_reference_number.select(:value)) | ||
.joins(:claim) | ||
.select("claims.id") | ||
end | ||
|
||
Claim | ||
.where( | ||
"LOWER(national_insurance_number) IN (?)", | ||
RiskIndicator.national_insurance_number.select("LOWER(value)") | ||
) | ||
.or(Claim.where(id: flagged_eligibility_claim_ids)) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
module AutomatedChecks | ||
module ClaimVerifiers | ||
class FraudRisk | ||
TASK_NAME = "fraud_risk".freeze | ||
|
||
def initialize(claim:) | ||
@claim = claim | ||
end | ||
|
||
def perform | ||
return unless claim.attributes_flagged_by_risk_indicator.any? | ||
|
||
flagged_attributes = @claim | ||
.attributes_flagged_by_risk_indicator | ||
.map(&:humanize) | ||
.to_sentence | ||
.downcase | ||
|
||
plural_verbs = claim.attributes_flagged_by_risk_indicator.many? ? "are" : "is" | ||
|
||
body = "This claim has been flagged as the #{flagged_attributes} " \ | ||
"#{plural_verbs} included on the fraud prevention list." | ||
|
||
claim.notes.create!( | ||
body: body, | ||
label: TASK_NAME | ||
) | ||
end | ||
|
||
private | ||
|
||
attr_reader :claim | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
class RiskIndicator < ApplicationRecord | ||
SUPPORTED_FIELDS = %w[ | ||
teacher_reference_number | ||
national_insurance_number | ||
].freeze | ||
|
||
enum field: SUPPORTED_FIELDS.index_by(&:itself) | ||
|
||
validates :value, presence: { | ||
message: "'value' can't be blank" | ||
} | ||
|
||
validates :value, uniqueness: {scope: :field} | ||
|
||
def self.flagged_attributes(claim) | ||
where( | ||
"field = 'national_insurance_number' AND LOWER(value) = :value", | ||
value: claim.national_insurance_number&.downcase | ||
).or( | ||
where( | ||
field: "teacher_reference_number", | ||
value: claim.eligibility.try(:teacher_reference_number) | ||
) | ||
).pluck(:field).compact | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<div class="govuk-grid-row"> | ||
<div class="govuk-grid-column-two-thirds"> | ||
<h1 class="govuk-heading-xl"> | ||
Fraud risk CSV upload | ||
</h1> | ||
|
||
<%= form_with( | ||
url: admin_fraud_risk_csv_uploads_path, | ||
model: @form, | ||
builder: GOVUKDesignSystemFormBuilder::FormBuilder | ||
) do |f| %> | ||
<%= f.govuk_error_summary %> | ||
|
||
<%= f.govuk_file_field( | ||
:file, | ||
label: { text: "Upload fraud risk CSV file" }, | ||
hint: { | ||
text: "Currently supported attributes are #{RiskIndicator::SUPPORTED_FIELDS.join(", ")}." | ||
} | ||
) %> | ||
|
||
<%= f.govuk_submit "Upload CSV" %> | ||
<% end %> | ||
|
||
<%= govuk_link_to( | ||
"Download CSV", | ||
admin_fraud_risk_csv_download_path(format: :csv), | ||
class: "govuk-button" | ||
) %> | ||
</div> | ||
</div> |
Oops, something went wrong.