39 changed files with 871 additions and 560 deletions
@ -1,16 +0,0 @@
|
||||
class Form::Common::Pages::CreatedBy < ::Form::Page |
||||
def initialize(id, hsh, subsection) |
||||
super |
||||
@id = "created_by" |
||||
end |
||||
|
||||
def questions |
||||
@questions ||= [ |
||||
Form::Common::Questions::CreatedById.new(nil, nil, self), |
||||
] |
||||
end |
||||
|
||||
def routed_to?(_log, current_user) |
||||
!!current_user&.support? |
||||
end |
||||
end |
||||
@ -1,46 +0,0 @@
|
||||
class Form::Common::Questions::CreatedById < ::Form::Question |
||||
def initialize(id, hsh, page) |
||||
super |
||||
@id = "created_by_id" |
||||
@check_answer_label = "User" |
||||
@header = "Which user are you creating this log for?" |
||||
@type = "select" |
||||
end |
||||
|
||||
def answer_options |
||||
answer_opts = { "" => "Select an option" } |
||||
return answer_opts unless ActiveRecord::Base.connected? |
||||
|
||||
User.select(:id, :name).each_with_object(answer_opts) do |user, hsh| |
||||
hsh[user.id] = user.name |
||||
hsh |
||||
end |
||||
end |
||||
|
||||
def displayed_answer_options(log, _user = nil) |
||||
return answer_options unless log.owning_organisation |
||||
|
||||
user_ids = log.owning_organisation.users.pluck(:id) + [""] |
||||
answer_options.select { |k, _v| user_ids.include?(k) } |
||||
end |
||||
|
||||
def label_from_value(value, _log = nil, _user = nil) |
||||
return unless value |
||||
|
||||
answer_options[value] |
||||
end |
||||
|
||||
def hidden_in_check_answers?(_log, current_user) |
||||
!current_user.support? |
||||
end |
||||
|
||||
def derived? |
||||
true |
||||
end |
||||
|
||||
private |
||||
|
||||
def selected_answer_option_is_derived?(_log) |
||||
false |
||||
end |
||||
end |
||||
@ -0,0 +1,19 @@
|
||||
class Form::Sales::Pages::CreatedBy < ::Form::Page |
||||
def initialize(id, hsh, subsection) |
||||
super |
||||
@id = "created_by" |
||||
end |
||||
|
||||
def questions |
||||
@questions ||= [ |
||||
Form::Sales::Questions::CreatedById.new(nil, nil, self), |
||||
] |
||||
end |
||||
|
||||
def routed_to?(_log, current_user) |
||||
return true if current_user&.support? |
||||
return true if current_user&.data_coordinator? |
||||
|
||||
false |
||||
end |
||||
end |
||||
@ -0,0 +1,54 @@
|
||||
class Form::Sales::Questions::CreatedById < ::Form::Question |
||||
ANSWER_OPTS = { "" => "Select an option" }.freeze |
||||
|
||||
def initialize(id, hsh, page) |
||||
super |
||||
@id = "created_by_id" |
||||
@check_answer_label = "User" |
||||
@header = "Which user are you creating this log for?" |
||||
@type = "select" |
||||
end |
||||
|
||||
def answer_options |
||||
ANSWER_OPTS |
||||
end |
||||
|
||||
def displayed_answer_options(log, current_user = nil) |
||||
return ANSWER_OPTS unless log.owning_organisation |
||||
return ANSWER_OPTS unless current_user |
||||
|
||||
users = current_user.support? ? log.owning_organisation.users : current_user.organisation.users |
||||
|
||||
users.each_with_object(ANSWER_OPTS.dup) do |user, hsh| |
||||
hsh[user.id] = present_user(user) |
||||
hsh |
||||
end |
||||
end |
||||
|
||||
def label_from_value(value, _log = nil, _user = nil) |
||||
return unless value |
||||
|
||||
present_user(User.find(value)) |
||||
end |
||||
|
||||
def hidden_in_check_answers?(_log, current_user) |
||||
return false if current_user.support? |
||||
return false if current_user.data_coordinator? |
||||
|
||||
true |
||||
end |
||||
|
||||
def derived? |
||||
true |
||||
end |
||||
|
||||
private |
||||
|
||||
def present_user(user) |
||||
"#{user.name} (#{user.email})" |
||||
end |
||||
|
||||
def selected_answer_option_is_derived?(_log) |
||||
false |
||||
end |
||||
end |
||||
@ -0,0 +1,45 @@
|
||||
<% content_for :before_content do %> |
||||
<%= govuk_back_link href: @form.back_path %> |
||||
<% end %> |
||||
|
||||
<div class="govuk-grid-row"> |
||||
<div class="govuk-grid-column-two-thirds"> |
||||
<%= form_with model: @form, scope: :form, url: bulk_upload_lettings_log_path(id: "prepare-your-file"), method: :patch do |f| %> |
||||
<%= f.hidden_field :year %> |
||||
|
||||
<span class="govuk-caption-l">Upload lettings logs in bulk (<%= @form.year_combo %>)</span> |
||||
<h1 class="govuk-heading-l">Prepare your file</h1> |
||||
|
||||
<h2 class="govuk-heading-s">Download template</h2> |
||||
|
||||
<ul class="govuk-list govuk-list--bullet"> |
||||
<li> |
||||
If your organisation is new to using bulk upload or you have updated your HMS export, use <%= govuk_link_to "this template (improved question ordering)", @form.template_path %>. |
||||
</li> |
||||
|
||||
<li> |
||||
If your organisation was using bulk upload on the previous CORE website and hasn't changed its HMS to be compatible with the new CORE service, use <%= govuk_link_to "this template", @form.old_template_path %>. |
||||
</li> |
||||
</ul> |
||||
|
||||
<h2 class="govuk-heading-s">Create your file</h2> |
||||
|
||||
<ul class="govuk-list govuk-list--bullet"> |
||||
<li>Fill in the template with CORE data from your housing management system according to the <%= govuk_link_to "Lettings #{@form.year_combo} Bulk Upload Specification", @form.specification_path %></li> |
||||
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE</li> |
||||
<li>If you have to manually enter large volumes of data into the bulk upload template, we recommend creating logs directly in the service instead. <%= govuk_link_to "Find out more about exporting your data", bulk_upload_lettings_log_path(id: "guidance", form: { year: @form.year }) %></li> |
||||
</ul> |
||||
|
||||
<%= govuk_inset_text(text: "You can upload both general needs and supported housing logs in the same file for 2023/24 data.") %> |
||||
|
||||
<h2 class="govuk-heading-s">Save your file</h2> |
||||
|
||||
<ul class="govuk-list govuk-list--bullet"> |
||||
<li>Save your file as a CSV</li> |
||||
<li>Your file should now be ready to upload</li> |
||||
</ul> |
||||
|
||||
<%= f.govuk_submit class: "govuk-!-margin-top-7" %> |
||||
<% end %> |
||||
</div> |
||||
</div> |
||||
@ -0,0 +1,8 @@
|
||||
<% content_for :before_content do %> |
||||
<% title = "Tell us if your organisation is merging" %> |
||||
<% content_for :title, title %> |
||||
<%# TODO: Update this backlink to also work with the create org flow %> |
||||
<%= govuk_back_link href: confirm_telephone_number_merge_request_path(@merge_request) %> |
||||
<% end %> |
||||
|
||||
<h2 class="govuk-heading-l">What is the merge date?</h2> |
||||
@ -0,0 +1,6 @@
|
||||
class AddPhoneNumberToMergeRequest < ActiveRecord::Migration[7.0] |
||||
change_table :merge_requests, bulk: true do |t| |
||||
t.column :telephone_number_correct, :boolean |
||||
t.column :new_telephone_number, :string |
||||
end |
||||
end |
||||
@ -1,82 +0,0 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Form::Common::Questions::CreatedById, type: :model do |
||||
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||
|
||||
let(:question_id) { nil } |
||||
let(:question_definition) { nil } |
||||
let(:page) { instance_double(Form::Page) } |
||||
let(:subsection) { instance_double(Form::Subsection) } |
||||
let(:form) { instance_double(Form) } |
||||
let(:user_1) { FactoryBot.create(:user, name: "first user") } |
||||
let(:user_2) { FactoryBot.create(:user, name: "second user") } |
||||
let!(:expected_answer_options) do |
||||
{ |
||||
"" => "Select an option", |
||||
user_1.id => user_1.name, |
||||
user_2.id => user_2.name, |
||||
} |
||||
end |
||||
|
||||
it "has correct page" do |
||||
expect(question.page).to eq(page) |
||||
end |
||||
|
||||
it "has the correct id" do |
||||
expect(question.id).to eq("created_by_id") |
||||
end |
||||
|
||||
it "has the correct header" do |
||||
expect(question.header).to eq("Which user are you creating this log for?") |
||||
end |
||||
|
||||
it "has the correct check_answer_label" do |
||||
expect(question.check_answer_label).to eq("User") |
||||
end |
||||
|
||||
it "has the correct type" do |
||||
expect(question.type).to eq("select") |
||||
end |
||||
|
||||
it "has the correct hint_text" do |
||||
expect(question.hint_text).to be_nil |
||||
end |
||||
|
||||
it "has the correct answer options" do |
||||
expect(question.answer_options).to eq(expected_answer_options) |
||||
end |
||||
|
||||
it "is marked as derived" do |
||||
expect(question.derived?).to be true |
||||
end |
||||
|
||||
context "when the current user is support" do |
||||
let(:support_user) { FactoryBot.build(:user, :support) } |
||||
|
||||
it "is shown in check answers" do |
||||
expect(question.hidden_in_check_answers?(nil, support_user)).to be false |
||||
end |
||||
end |
||||
|
||||
context "when the current user is not support" do |
||||
let(:user) { FactoryBot.build(:user) } |
||||
|
||||
it "is not shown in check answers" do |
||||
expect(question.hidden_in_check_answers?(nil, user)).to be true |
||||
end |
||||
end |
||||
|
||||
context "when the owning organisation is already set" do |
||||
let(:lettings_log) { FactoryBot.create(:lettings_log, owning_organisation: user_2.organisation) } |
||||
let(:expected_answer_options) do |
||||
{ |
||||
"" => "Select an option", |
||||
user_2.id => user_2.name, |
||||
} |
||||
end |
||||
|
||||
it "only displays users that belong to that organisation" do |
||||
expect(question.displayed_answer_options(lettings_log)).to eq(expected_answer_options) |
||||
end |
||||
end |
||||
end |
||||
@ -0,0 +1,88 @@
|
||||
require "rails_helper" |
||||
|
||||
RSpec.describe Form::Sales::Questions::CreatedById, type: :model do |
||||
subject(:question) { described_class.new(question_id, question_definition, page) } |
||||
|
||||
let(:question_id) { nil } |
||||
let(:question_definition) { nil } |
||||
let(:page) { instance_double(Form::Page) } |
||||
let(:subsection) { instance_double(Form::Subsection) } |
||||
let(:form) { instance_double(Form) } |
||||
|
||||
it "has correct page" do |
||||
expect(question.page).to eq(page) |
||||
end |
||||
|
||||
it "has the correct id" do |
||||
expect(question.id).to eq("created_by_id") |
||||
end |
||||
|
||||
it "has the correct header" do |
||||
expect(question.header).to eq("Which user are you creating this log for?") |
||||
end |
||||
|
||||
it "has the correct check_answer_label" do |
||||
expect(question.check_answer_label).to eq("User") |
||||
end |
||||
|
||||
it "has the correct type" do |
||||
expect(question.type).to eq("select") |
||||
end |
||||
|
||||
it "has the correct hint_text" do |
||||
expect(question.hint_text).to be_nil |
||||
end |
||||
|
||||
it "is marked as derived" do |
||||
expect(question.derived?).to be true |
||||
end |
||||
|
||||
context "when the current user is support" do |
||||
let(:support_user) { build(:user, :support) } |
||||
|
||||
it "is shown in check answers" do |
||||
expect(question.hidden_in_check_answers?(nil, support_user)).to be false |
||||
end |
||||
|
||||
describe "#displayed_answer_options" do |
||||
let(:owning_org_user) { create(:user) } |
||||
let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) } |
||||
let(:expected_answer_options) do |
||||
{ |
||||
"" => "Select an option", |
||||
owning_org_user.id => "#{owning_org_user.name} (#{owning_org_user.email})", |
||||
} |
||||
end |
||||
|
||||
it "only displays users that belong to the owning organisation" do |
||||
expect(question.displayed_answer_options(sales_log, support_user)).to eq(expected_answer_options) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context "when the current user is data_coordinator" do |
||||
let(:data_coordinator) { create(:user, :data_coordinator) } |
||||
|
||||
it "is shown in check answers" do |
||||
expect(question.hidden_in_check_answers?(nil, data_coordinator)).to be false |
||||
end |
||||
|
||||
describe "#displayed_answer_options" do |
||||
let(:owning_org_user) { create(:user) } |
||||
let(:sales_log) { create(:sales_log, owning_organisation: owning_org_user.organisation) } |
||||
let!(:user_in_same_org) { create(:user, organisation: data_coordinator.organisation) } |
||||
|
||||
let(:expected_answer_options) do |
||||
{ |
||||
"" => "Select an option", |
||||
user_in_same_org.id => "#{user_in_same_org.name} (#{user_in_same_org.email})", |
||||
data_coordinator.id => "#{data_coordinator.name} (#{data_coordinator.email})", |
||||
} |
||||
end |
||||
|
||||
it "only displays users that belong user's org" do |
||||
expect(question.displayed_answer_options(sales_log, data_coordinator)).to eq(expected_answer_options) |
||||
end |
||||
end |
||||
end |
||||
end |
||||
@ -0,0 +1,187 @@
|
||||
class BulkUpload::SalesLogToCsv |
||||
attr_reader :log, :line_ending, :col_offset, :overrides |
||||
|
||||
def initialize(log:, line_ending: "\n", col_offset: 1, overrides: {}) |
||||
@log = log |
||||
@line_ending = line_ending |
||||
@col_offset = col_offset |
||||
@overrides = overrides |
||||
end |
||||
|
||||
def row_prefix |
||||
[nil] * col_offset |
||||
end |
||||
|
||||
def to_2022_csv_row |
||||
(row_prefix + to_2022_row).flatten.join(",") + line_ending |
||||
end |
||||
|
||||
def default_2022_field_numbers |
||||
(1..125).to_a |
||||
end |
||||
|
||||
def default_2022_field_numbers_row(seed: nil) |
||||
if seed |
||||
["Bulk upload field number"] + default_2022_field_numbers.shuffle(random: Random.new(seed)) |
||||
else |
||||
["Bulk upload field number"] + default_2022_field_numbers |
||||
end.flatten.join(",") + line_ending |
||||
end |
||||
|
||||
def to_2022_row |
||||
[ |
||||
log.purchid, # 1 |
||||
log.saledate&.day, |
||||
log.saledate&.month, |
||||
log.saledate&.strftime("%y"), |
||||
nil, |
||||
log.noint, |
||||
log.age1, |
||||
log.age2, |
||||
log.age3, |
||||
log.age4, |
||||
log.age5, |
||||
log.age6, |
||||
|
||||
log.sex1, |
||||
log.sex2, |
||||
log.sex3, |
||||
log.sex4, |
||||
log.sex5, |
||||
log.sex6, |
||||
|
||||
log.relat2, |
||||
log.relat3, # 20 |
||||
log.relat4, |
||||
log.relat5, |
||||
log.relat6, |
||||
|
||||
log.ecstat1, |
||||
log.ecstat2, |
||||
log.ecstat3, |
||||
log.ecstat4, |
||||
log.ecstat5, |
||||
log.ecstat6, |
||||
|
||||
log.ethnic, # 30 |
||||
log.national, |
||||
log.income1, |
||||
log.income2, |
||||
log.inc1mort, |
||||
log.inc2mort, |
||||
log.savings, |
||||
log.prevown, |
||||
nil, |
||||
|
||||
log.prevten, |
||||
log.prevloc, # 40 |
||||
((log.ppostcode_full || "").split(" ") || [""]).first, |
||||
((log.ppostcode_full || "").split(" ") || [""]).last, |
||||
log.ppcodenk == 0 ? 1 : nil, |
||||
|
||||
log.pregyrha, |
||||
log.pregla, |
||||
log.pregghb, |
||||
log.pregother, |
||||
|
||||
log.disabled, |
||||
log.wheel, |
||||
log.beds, # 50 |
||||
log.proptype, |
||||
log.builtype, |
||||
log.la, |
||||
((log.postcode_full || "").split(" ") || [""]).first, |
||||
((log.postcode_full || "").split(" ") || [""]).last, |
||||
log.wchair, |
||||
|
||||
log.type, # shared ownership |
||||
log.resale, |
||||
log.hodate&.day, |
||||
log.hodate&.month, # 60 |
||||
log.hodate&.strftime("%y"), |
||||
log.exdate&.day, |
||||
log.exdate&.month, |
||||
log.exdate&.strftime("%y"), |
||||
log.lanomagr, |
||||
|
||||
log.frombeds, |
||||
log.fromprop, |
||||
|
||||
log.value, |
||||
log.equity, |
||||
log.mortgage, # 70 |
||||
log.extrabor, |
||||
log.deposit, |
||||
log.cashdis, |
||||
|
||||
log.mrent, |
||||
log.mscharge, |
||||
|
||||
log.type, # discounted ownership |
||||
log.value, |
||||
log.grant, |
||||
log.discount, |
||||
log.mortgage, # 80 |
||||
log.extrabor, |
||||
log.deposit, |
||||
log.mscharge, |
||||
|
||||
log.type, # outright sale |
||||
log.othtype, |
||||
nil, |
||||
|
||||
log.value, |
||||
log.mortgage, |
||||
log.extrabor, |
||||
log.deposit, # 90 |
||||
log.mscharge, |
||||
|
||||
overrides[:organisation_id] || log.owning_organisation&.old_visible_id, |
||||
log.created_by&.email, |
||||
nil, |
||||
hhregres, |
||||
nil, |
||||
log.armedforcesspouse, |
||||
log.mortgagelender, # shared ownership |
||||
log.mortgagelenderother, |
||||
log.mortgagelender, # discounted ownership 100 |
||||
log.mortgagelenderother, |
||||
log.mortgagelender, # outright ownership |
||||
log.mortgagelenderother, |
||||
|
||||
log.hb, |
||||
log.mortlen, # shared ownership |
||||
log.mortlen, # discounted ownership |
||||
log.mortlen, # outright ownership |
||||
|
||||
log.proplen, # discounted ownership |
||||
log.jointmore, |
||||
log.proplen, # shared ownership 110 |
||||
log.staircase, |
||||
log.privacynotice, |
||||
log.ownershipsch, |
||||
log.companybuy, # outright sale |
||||
log.buylivein, |
||||
log.jointpur, |
||||
log.buy1livein, |
||||
log.buy2livein, |
||||
log.hholdcount, |
||||
log.stairbought, # 120 |
||||
log.stairowned, |
||||
log.socprevten, |
||||
log.mortgageused, # shared ownership |
||||
log.mortgageused, # discounted ownership |
||||
log.mortgageused, # outright ownership |
||||
] |
||||
end |
||||
|
||||
private |
||||
|
||||
def hhregres |
||||
if log.hhregres == 1 |
||||
log.hhregresstill |
||||
else |
||||
log.hhregres |
||||
end |
||||
end |
||||
end |
||||
Loading…
Reference in new issue