Matthew Phelan
3 years ago
41 changed files with 606 additions and 189 deletions
@ -0,0 +1,22 @@
|
||||
class BulkUploadController < ApplicationController |
||||
def show |
||||
@bulk_upload = BulkUpload.new(nil, nil) |
||||
render "case_logs/bulk_upload" |
||||
end |
||||
|
||||
def bulk_upload |
||||
file = upload_params.tempfile |
||||
content_type = upload_params.content_type |
||||
@bulk_upload = BulkUpload.new(file, content_type) |
||||
@bulk_upload.process |
||||
if @bulk_upload.errors.present? |
||||
render "case_logs/bulk_upload", status: :unprocessable_entity |
||||
else |
||||
redirect_to(case_logs_path) |
||||
end |
||||
end |
||||
|
||||
def upload_params |
||||
params.require("bulk_upload")["case_log_bulk_upload"] |
||||
end |
||||
end |
@ -0,0 +1,199 @@
|
||||
class BulkUpload |
||||
include ActiveModel::Model |
||||
include ActiveModel::Validations |
||||
include ActiveModel::Conversion |
||||
|
||||
SPREADSHEET_CONTENT_TYPES = %w[ |
||||
application/vnd.ms-excel |
||||
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet |
||||
].freeze |
||||
|
||||
FIRST_DATA_ROW = 7 |
||||
|
||||
def initialize(file, content_type) |
||||
@file = file |
||||
@content_type = content_type |
||||
end |
||||
|
||||
def process |
||||
return unless valid_content_type? |
||||
|
||||
xlsx = Roo::Spreadsheet.open(@file, extension: :xlsx) |
||||
sheet = xlsx.sheet(0) |
||||
last_row = sheet.last_row |
||||
if last_row < FIRST_DATA_ROW |
||||
errors.add(:case_log_bulk_upload, "No data found") |
||||
else |
||||
data_range = FIRST_DATA_ROW..last_row |
||||
data_range.map do |row_num| |
||||
case_log = CaseLog.create |
||||
map_row(sheet.row(row_num)).each do |attr_key, attr_val| |
||||
begin |
||||
case_log.update_attribute(attr_key, attr_val) |
||||
rescue ArgumentError |
||||
end |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
def valid_content_type? |
||||
if SPREADSHEET_CONTENT_TYPES.include?(@content_type) |
||||
true |
||||
else |
||||
errors.add(:case_log_bulk_upload, "Invalid file type") |
||||
false |
||||
end |
||||
end |
||||
|
||||
def map_row(row) |
||||
{ |
||||
lettype: row[1], |
||||
landlord: row[2], |
||||
# reg_num_la_core_code: row[3], |
||||
# managementgroup: row[4], |
||||
# schemecode: row[5], |
||||
# firstletting: row[6], |
||||
tenant_code: row[7], |
||||
startertenancy: row[8], |
||||
tenancy: row[9], |
||||
tenancyother: row[10], |
||||
# tenancyduration: row[11], |
||||
other_hhmemb: other_hhmemb(row), |
||||
hhmemb: other_hhmemb(row) + 1, |
||||
age1: row[12], |
||||
age2: row[13], |
||||
age3: row[14], |
||||
age4: row[15], |
||||
age5: row[16], |
||||
age6: row[17], |
||||
age7: row[18], |
||||
age8: row[19], |
||||
sex1: row[20], |
||||
sex2: row[21], |
||||
sex3: row[22], |
||||
sex4: row[23], |
||||
sex5: row[24], |
||||
sex6: row[25], |
||||
sex7: row[26], |
||||
sex8: row[27], |
||||
relat2: row[28], |
||||
relat3: row[29], |
||||
relat4: row[30], |
||||
relat5: row[31], |
||||
relat6: row[32], |
||||
relat7: row[33], |
||||
relat8: row[34], |
||||
ecstat1: row[35], |
||||
ecstat2: row[36], |
||||
ecstat3: row[37], |
||||
ecstat4: row[38], |
||||
ecstat5: row[39], |
||||
ecstat6: row[40], |
||||
ecstat7: row[41], |
||||
ecstat8: row[42], |
||||
ethnic: row[43], |
||||
national: row[44], |
||||
armed_forces: row[45], |
||||
reservist: row[46], |
||||
preg_occ: row[47], |
||||
hb: row[48], |
||||
benefits: row[49], |
||||
net_income_known: row[50].present? ? 1 : nil, |
||||
earnings: row[50], |
||||
# increfused: row[51], |
||||
reason: row[52], |
||||
other_reason_for_leaving_last_settled_home: row[53], |
||||
underoccupation_benefitcap: row[54], |
||||
housingneeds_a: row[55], |
||||
housingneeds_b: row[56], |
||||
housingneeds_c: row[57], |
||||
housingneeds_f: row[58], |
||||
housingneeds_g: row[59], |
||||
housingneeds_h: row[60], |
||||
prevten: row[61], |
||||
prevloc: row[62], |
||||
# ppostc1: row[63], |
||||
# ppostc2: row[64], |
||||
# prevpco_unknown: row[65], |
||||
layear: row[66], |
||||
lawaitlist: row[67], |
||||
homeless: row[68], |
||||
reasonpref: row[69], |
||||
rp_homeless: row[70], |
||||
rp_insan_unsat: row[71], |
||||
rp_medwel: row[72], |
||||
rp_hardship: row[73], |
||||
rp_dontknow: row[74], |
||||
cbl: row[75], |
||||
chr: row[76], |
||||
cap: row[77], |
||||
# referral_source: row[78], |
||||
period: row[79], |
||||
brent: row[80], |
||||
scharge: row[81], |
||||
pscharge: row[82], |
||||
supcharg: row[83], |
||||
tcharge: row[84], |
||||
# tcharge_care_homes: row[85], |
||||
# no_rent_or_charge: row[86], |
||||
hbrentshortfall: row[87], |
||||
tshortfall: row[88], |
||||
property_void_date: row[89].to_s + row[90].to_s + row[91].to_s, |
||||
# property_void_date_day: row[89], |
||||
# property_void_date_month: row[90], |
||||
# property_void_date_year: row[91], |
||||
majorrepairs: row[92].present? ? "1" : nil, |
||||
mrcdate: row[92].to_s + row[93].to_s + row[94].to_s, |
||||
mrcday: row[92], |
||||
mrcmonth: row[93], |
||||
mrcyear: row[94], |
||||
# supported_scheme: row[95], |
||||
startdate: row[96].to_s + row[97].to_s + row[98].to_s, |
||||
# startdate_day: row[96], |
||||
# startdate_month: row[97], |
||||
# startdate_year: row[98], |
||||
offered: row[99], |
||||
# property_reference: row[100], |
||||
beds: row[101], |
||||
unittype_gn: row[102], |
||||
property_building_type: row[103], |
||||
wchair: row[104], |
||||
property_relet: row[105], |
||||
rsnvac: row[106], |
||||
la: row[107], |
||||
# postcode: row[108], |
||||
# postcod2: row[109], |
||||
# row[110] removed |
||||
property_owner_organisation: row[111], |
||||
# username: row[112], |
||||
property_manager_organisation: row[113], |
||||
leftreg: row[114], |
||||
# uprn: row[115], |
||||
incfreq: row[116], |
||||
# sheltered_accom: row[117], |
||||
illness: row[118], |
||||
illness_type_1: row[119], |
||||
illness_type_2: row[120], |
||||
illness_type_3: row[121], |
||||
illness_type_4: row[122], |
||||
illness_type_8: row[123], |
||||
illness_type_5: row[124], |
||||
illness_type_6: row[125], |
||||
illness_type_7: row[126], |
||||
illness_type_9: row[127], |
||||
illness_type_10: row[128], |
||||
# london_affordable: row[129], |
||||
rent_type: row[130], |
||||
intermediate_rent_product_name: row[131], |
||||
# data_protection: row[132], |
||||
sale_or_letting: "letting", |
||||
gdpr_acceptance: 1, |
||||
gdpr_declined: 0, |
||||
} |
||||
end |
||||
|
||||
def other_hhmemb(row) |
||||
[13, 14, 15, 16, 17, 18, 19].count { |idx| row[idx].present? } |
||||
end |
||||
end |
@ -0,0 +1,10 @@
|
||||
<div class="govuk-form-group"> |
||||
<%= form_for @bulk_upload, url: bulk_upload_case_logs_path, method: "post", builder: GOVUKDesignSystemFormBuilder::FormBuilder do |f| %> |
||||
<%= f.govuk_error_summary %> |
||||
<%= f.govuk_file_field :case_log_bulk_upload, |
||||
label: { text: "Bulk Upload", size: "l" }, |
||||
hint: { text: "Upload a spreadsheet using the template" } |
||||
%> |
||||
<%= f.govuk_submit "Upload" %> |
||||
<% end %> |
||||
</div> |
@ -0,0 +1,48 @@
|
||||
<div class="govuk-width-container "> |
||||
|
||||
<div class="govuk-footer__meta"> |
||||
<div class="govuk-footer__meta-item govuk-footer__meta-item--grow"> |
||||
|
||||
<h2 class="govuk-visually-hidden">Support links</h2> |
||||
|
||||
<div class="govuk-footer__meta-custom"> |
||||
|
||||
<h2 class="govuk-heading-m">Get help with this service</h2> |
||||
<h3 class="govuk-heading-s govuk-!-margin-bottom-1">Online helpdesk</h3> |
||||
<p class="govuk-body govuk-!-font-size-16"> |
||||
<a class="govuk-link govuk-footer__link" href="https://digital.dclg.gov.uk/jira/servicedesk/customer/portal/4/group/21" target="_blank">CORE helpdesk</a> |
||||
(opens in a new tab)</p> |
||||
|
||||
<h3 class="govuk-heading-s govuk-!-margin-bottom-1">Telephone</h3> |
||||
<ul class="govuk-list govuk-!-font-size-16"> |
||||
<li>Telephone: 0333 202 5084</li> |
||||
<li>Monday to Friday, 9am to 5:30pm (except public holidays)</li> |
||||
</ul> |
||||
|
||||
<h3 class="govuk-heading-s govuk-!-margin-bottom-1">Email</h3> |
||||
<ul class="govuk-list govuk-!-font-size-16"> |
||||
<li> |
||||
<a class="govuk-link govuk-footer__link" href="mailto:mhclg.digital-services@communities.gov.uk?subject=CORE">dluhc.digital-services@communities.gov.uk</a> |
||||
</li> |
||||
<li>We aim to respond within 2 working days</li> |
||||
</ul> |
||||
|
||||
<h2 class="govuk-visually-hidden">Footer links</h2> |
||||
|
||||
</div> |
||||
|
||||
<svg aria-hidden="true" focusable="false" class="govuk-footer__licence-logo" xmlns="http://www.w3.org/2000/svg" viewbox="0 0 483.2 195.7" height="17" width="41"> |
||||
<path |
||||
fill="currentColor" |
||||
d="M421.5 142.8V.1l-50.7 32.3v161.1h112.4v-50.7zm-122.3-9.6A47.12 47.12 0 0 1 221 97.8c0-26 21.1-47.1 47.1-47.1 16.7 0 31.4 8.7 39.7 21.8l42.7-27.2A97.63 97.63 0 0 0 268.1 0c-36.5 0-68.3 20.1-85.1 49.7A98 98 0 0 0 97.8 0C43.9 0 0 43.9 0 97.8s43.9 97.8 97.8 97.8c36.5 0 68.3-20.1 85.1-49.7a97.76 97.76 0 0 0 149.6 25.4l19.4 22.2h3v-87.8h-80l24.3 27.5zM97.8 145c-26 0-47.1-21.1-47.1-47.1s21.1-47.1 47.1-47.1 47.2 21 47.2 47S123.8 145 97.8 145"/> |
||||
</svg> |
||||
<span class="govuk-footer__licence-description"> |
||||
All content is available under the |
||||
<a class="govuk-footer__link" href="https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/" rel="license">Open Government Licence v3.0</a>, except where otherwise stated |
||||
</span> |
||||
</div> |
||||
<div class="govuk-footer__meta-item"> |
||||
<a class="govuk-footer__link govuk-footer__copyright-logo" href="https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/">© Crown copyright</a> |
||||
</div> |
||||
</div> |
||||
</div> |
@ -0,0 +1,10 @@
|
||||
class ChangeDatetime < ActiveRecord::Migration[6.1] |
||||
def change |
||||
change_table :case_logs, bulk: true do |t| |
||||
t.remove :sale_completion_date |
||||
t.column :sale_completion_date, :datetime |
||||
t.remove :startdate |
||||
t.column :startdate, :datetime |
||||
end |
||||
end |
||||
end |
Binary file not shown.
Binary file not shown.
@ -0,0 +1,33 @@
|
||||
require "rails_helper" |
||||
require "rake" |
||||
|
||||
describe "rake form_definition:validate_all", type: :task do |
||||
subject(:task) { Rake::Task["form_definition:validate_all"] } |
||||
|
||||
before do |
||||
Rake.application.rake_require("tasks/form_definition") |
||||
Rake::Task.define_task(:environment) |
||||
task.reenable |
||||
end |
||||
|
||||
it "runs the validate task for each form definition in the project" do |
||||
expect(Rake::Task["form_definition:validate"]).to receive(:invoke).exactly(4).times |
||||
task.invoke |
||||
end |
||||
end |
||||
|
||||
describe "rake form_definition:validate", type: :task do |
||||
subject(:task) { Rake::Task["form_definition:validate"] } |
||||
|
||||
before do |
||||
Rake.application.rake_require("tasks/form_definition") |
||||
Rake::Task.define_task(:environment) |
||||
allow(JSON::Validator).to receive(:validate).and_return(true) |
||||
task.reenable |
||||
end |
||||
|
||||
it "runs the validate task for the given form definition" do |
||||
expect(JSON::Validator).to receive(:validate!).at_least(1).time |
||||
task.invoke("config/forms/2021_2022.json") |
||||
end |
||||
end |
@ -0,0 +1,60 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe BulkUploadController, type: :request do |
||||
let(:url) { "/case_logs/bulk_upload" } |
||||
|
||||
describe "GET #show" do |
||||
before do |
||||
get url, params: {} |
||||
end |
||||
|
||||
it "returns a success response" do |
||||
expect(response).to be_successful |
||||
end |
||||
|
||||
it "returns a page with a file upload form" do |
||||
expect(response.body).to match(/<input id="bulk-upload-case-log-bulk-upload-field" class="govuk-file-upload"/) |
||||
expect(response.body).to match(/<button type="submit" formnovalidate="formnovalidate" class="govuk-button"/) |
||||
end |
||||
end |
||||
|
||||
describe "POST #bulk upload" do |
||||
subject { post url, params: { bulk_upload: { case_log_bulk_upload: @file } } } |
||||
|
||||
context "given a valid file based on the upload template" do |
||||
before do |
||||
@file = fixture_file_upload("2021_22_lettings_bulk_upload.xlsx", "application/vnd.ms-excel") |
||||
end |
||||
|
||||
it "creates case logs for each row in the template" do |
||||
expect { subject }.to change(CaseLog, :count).by(9) |
||||
end |
||||
|
||||
it "redirects to the case log index page" do |
||||
expect(subject).to redirect_to(case_logs_path) |
||||
end |
||||
end |
||||
|
||||
context "given an invalid file type" do |
||||
before do |
||||
@file = fixture_file_upload("random.txt", "text/plain") |
||||
subject |
||||
end |
||||
|
||||
it "displays an error message" do |
||||
expect(response.body).to match(/Invalid file type/) |
||||
end |
||||
end |
||||
|
||||
context "given an empty file" do |
||||
before do |
||||
@file = fixture_file_upload("2021_22_lettings_bulk_upload_empty.xlsx", "application/vnd.ms-excel") |
||||
subject |
||||
end |
||||
|
||||
it "displays an error message" do |
||||
expect(response.body).to match(/No data found/) |
||||
end |
||||
end |
||||
end |
||||
end |
Loading…
Reference in new issue