Browse Source

Merge branch 'main' into create-test-log-button

pull/2804/head
kosiakkatrina 1 year ago committed by GitHub
parent
commit
c1aed2f737
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 13
      app/models/form/sales/pages/estate_management_fee.rb
  2. 12
      app/models/form/sales/pages/living_before_purchase.rb
  3. 24
      app/models/form/sales/questions/has_management_fee.rb
  4. 12
      app/models/form/sales/questions/management_fee.rb
  5. 10
      app/models/form/sales/sections/sale_information.rb
  6. 48
      app/models/form/sales/subsections/shared_ownership_initial_purchase.rb
  7. 2
      app/models/form/sales/subsections/shared_ownership_scheme.rb
  8. 2
      app/services/bulk_upload/lettings/year2024/csv_parser.rb
  9. 2
      app/services/bulk_upload/sales/year2024/csv_parser.rb
  10. 6
      app/views/form/guidance/_financial_calculations_shared_ownership.html.erb
  11. 21
      config/locales/forms/2025/sales/sale_information.en.yml
  12. 8
      db/migrate/20241114154215_add_management_fee_fields.rb
  13. 2
      db/schema.rb
  14. 5
      spec/features/accessibility_spec.rb
  15. 68
      spec/models/form/sales/pages/living_before_purchase_spec.rb
  16. 16
      spec/models/form/sales/sections/sale_information_spec.rb
  17. 95
      spec/models/form/sales/subsections/shared_ownership_initial_purchase_spec.rb
  18. 23
      spec/services/bulk_upload/lettings/year2024/csv_parser_spec.rb
  19. 32
      spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb

13
app/models/form/sales/pages/estate_management_fee.rb

@ -0,0 +1,13 @@
class Form::Sales::Pages::EstateManagementFee < ::Form::Page
def initialize(id, hsh, subsection)
super
@copy_key = "sales.sale_information.management_fee"
end
def questions
@questions ||= [
Form::Sales::Questions::HasManagementFee.new(nil, nil, self),
Form::Sales::Questions::ManagementFee.new(nil, nil, self),
]
end
end

12
app/models/form/sales/pages/living_before_purchase.rb

@ -19,11 +19,17 @@ class Form::Sales::Pages::LivingBeforePurchase < ::Form::Page
end
end
def depends_on
def routed_to?(log, _user)
super && page_routed_to?(log)
end
def page_routed_to?(log)
return false if form.start_year_2025_or_later? && log.resale != 2
if @joint_purchase
[{ "joint_purchase?" => true }]
log.joint_purchase?
else
[{ "not_joint_purchase?" => true }, { "jointpur" => nil }]
log.not_joint_purchase? || log.jointpur.nil?
end
end
end

24
app/models/form/sales/questions/has_management_fee.rb

@ -0,0 +1,24 @@
class Form::Sales::Questions::HasManagementFee < ::Form::Question
def initialize(id, hsh, subsection)
super
@id = "has_management_fee"
@copy_key = "sales.sale_information.management_fee.has_management_fee"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@conditional_for = {
"management_fee" => [1],
}
@hidden_in_check_answers = {
"depends_on" => [
{
"has_management_fee" => 1,
},
],
}
end
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"0" => { "value" => "No" },
}.freeze
end

12
app/models/form/sales/questions/management_fee.rb

@ -0,0 +1,12 @@
class Form::Sales::Questions::ManagementFee < ::Form::Question
def initialize(id, hsh, subsection)
super
@id = "management_fee"
@copy_key = "sales.sale_information.management_fee.management_fee"
@type = "numeric"
@min = 1
@step = 0.01
@width = 5
@prefix = "£"
end
end

10
app/models/form/sales/sections/sale_information.rb

@ -5,9 +5,17 @@ class Form::Sales::Sections::SaleInformation < ::Form::Section
@label = "Sale information"
@description = ""
@subsections = [
Form::Sales::Subsections::SharedOwnershipScheme.new(nil, nil, self),
shared_ownership_scheme_subsection,
Form::Sales::Subsections::DiscountedOwnershipScheme.new(nil, nil, self),
Form::Sales::Subsections::OutrightSale.new(nil, nil, self),
] || []
end
def shared_ownership_scheme_subsection
if form.start_year_2025_or_later?
Form::Sales::Subsections::SharedOwnershipInitialPurchase.new(nil, nil, self)
else
Form::Sales::Subsections::SharedOwnershipScheme.new(nil, nil, self)
end
end
end

48
app/models/form/sales/subsections/shared_ownership_initial_purchase.rb

@ -0,0 +1,48 @@
class Form::Sales::Subsections::SharedOwnershipInitialPurchase < ::Form::Subsection
def initialize(id, hsh, section)
super
@id = "shared_ownership_initial_purchase"
@label = "Shared ownership - initial purchase"
@depends_on = [{ "ownershipsch" => 1, "setup_completed?" => true, "staircase" => 2 }]
end
def pages
@pages ||= [
Form::Sales::Pages::Resale.new(nil, nil, self),
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_shared_ownership_joint_purchase", nil, self, ownershipsch: 1, joint_purchase: true),
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_shared_ownership", nil, self, ownershipsch: 1, joint_purchase: false),
Form::Sales::Pages::HandoverDate.new(nil, nil, self),
Form::Sales::Pages::HandoverDateCheck.new(nil, nil, self),
Form::Sales::Pages::BuyerPrevious.new("buyer_previous_joint_purchase", nil, self, joint_purchase: true),
Form::Sales::Pages::BuyerPrevious.new("buyer_previous_not_joint_purchase", nil, self, joint_purchase: false),
Form::Sales::Pages::PreviousBedrooms.new(nil, nil, self),
Form::Sales::Pages::PreviousPropertyType.new(nil, nil, self),
Form::Sales::Pages::PreviousTenure.new(nil, nil, self),
Form::Sales::Pages::ValueSharedOwnership.new(nil, nil, self),
Form::Sales::Pages::AboutPriceValueCheck.new("about_price_shared_ownership_value_check", nil, self),
Form::Sales::Pages::Equity.new(nil, nil, self),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_equity_value_check", nil, self),
Form::Sales::Pages::Mortgageused.new("mortgage_used_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_used_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageAmount.new("mortgage_amount_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_mortgage_amount_value_check", nil, self),
Form::Sales::Pages::MortgageValueCheck.new("mortgage_amount_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageLength.new("mortgage_length_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::Deposit.new("deposit_shared_ownership", nil, self, ownershipsch: 1, optional: false),
Form::Sales::Pages::Deposit.new("deposit_shared_ownership_optional", nil, self, ownershipsch: 1, optional: true),
Form::Sales::Pages::DepositValueCheck.new("deposit_joint_purchase_value_check", nil, self, joint_purchase: true),
Form::Sales::Pages::DepositValueCheck.new("deposit_value_check", nil, self, joint_purchase: false),
Form::Sales::Pages::DepositDiscount.new("deposit_discount", nil, self, optional: false),
Form::Sales::Pages::DepositDiscount.new("deposit_discount_optional", nil, self, optional: true),
Form::Sales::Pages::SharedOwnershipDepositValueCheck.new("shared_ownership_deposit_value_check", nil, self),
Form::Sales::Pages::MonthlyRent.new(nil, nil, self),
Form::Sales::Pages::LeaseholdCharges.new("leasehold_charges_shared_ownership", nil, self, ownershipsch: 1),
Form::Sales::Pages::MonthlyChargesValueCheck.new("monthly_charges_shared_ownership_value_check", nil, self),
Form::Sales::Pages::EstateManagementFee.new("estate_management_fee", nil, self),
].compact
end
def displayed_in_tasklist?(log)
log.staircase == 2 && (log.ownershipsch.nil? || log.ownershipsch == 1)
end
end

2
app/models/form/sales/subsections/shared_ownership_scheme.rb

@ -11,7 +11,7 @@ class Form::Sales::Subsections::SharedOwnershipScheme < ::Form::Subsection
@pages ||= [
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_shared_ownership_joint_purchase", nil, self, ownershipsch: 1, joint_purchase: true),
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_shared_ownership", nil, self, ownershipsch: 1, joint_purchase: false),
(Form::Sales::Pages::Staircase.new(nil, nil, self) unless form.start_year_2025_or_later?),
Form::Sales::Pages::Staircase.new(nil, nil, self),
Form::Sales::Pages::AboutStaircase.new("about_staircasing_joint_purchase", nil, self, joint_purchase: true),
Form::Sales::Pages::AboutStaircase.new("about_staircasing_not_joint_purchase", nil, self, joint_purchase: false),
Form::Sales::Pages::StaircaseBoughtValueCheck.new(nil, nil, self),

2
app/services/bulk_upload/lettings/year2024/csv_parser.rb

@ -15,7 +15,7 @@ class BulkUpload::Lettings::Year2024::CsvParser
def row_offset
if with_headers?
rows.find_index { |row| row[0].match(/field number/i) } + 1
rows.find_index { |row| row[0].present? && row[0].match(/field number/i) } + 1
else
0
end

2
app/services/bulk_upload/sales/year2024/csv_parser.rb

@ -15,7 +15,7 @@ class BulkUpload::Sales::Year2024::CsvParser
def row_offset
if with_headers?
rows.find_index { |row| row[0].match(/field number/i) } + 1
rows.find_index { |row| row[0].present? && row[0].match(/field number/i) } + 1
else
0
end

6
app/views/form/guidance/_financial_calculations_shared_ownership.html.erb

@ -20,11 +20,11 @@
<% end %>
must equal
the purchase price <%= question_link("value", log, current_user) %>
<% stairbought_page = log.form.get_question("stairbought", log).page %>
<% if stairbought_page.routed_to?(log, current_user) %>
<% stairbought_page = log.form.get_question("stairbought", log)&.page %>
<% if stairbought_page&.routed_to?(log, current_user) %>
multiplied by the percentage bought <%= question_link("stairbought", log, current_user) %>
<% else %>
multiplied by the percentage equity stake <%= question_link("equity", log, current_user) %>
multiplied by the percentage equity share <%= question_link("equity", log, current_user) %>
<% end %>
</p>
<% end %>

21
config/locales/forms/2025/sales/sale_information.en.yml

@ -107,9 +107,9 @@ en:
equity:
page_header: "About the price of the property"
check_answer_label: "Initial percentage equity stake"
hint_text: "Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)"
question_text: "What was the initial percentage equity stake purchased?"
check_answer_label: "Initial percentage equity share"
hint_text: "Enter the amount of initial equity share held by the purchaser (for example, 25% or 50%)"
question_text: "What was the initial percentage share purchased?"
mortgageused:
page_header: "Mortgage Amount"
@ -168,9 +168,9 @@ en:
leaseholdcharges:
page_header: ""
has_mscharge:
check_answer_label: "Does the property have any monthly leasehold charges?"
check_answer_label: "Does the property have any service charges?"
hint_text: "For example, service and management charges"
question_text: "Does the property have any monthly leasehold charges?"
question_text: "Does the property have any service charges?"
mscharge:
check_answer_label: "Monthly leasehold charges"
hint_text: ""
@ -199,3 +199,14 @@ en:
check_answer_label: "Amount of any loan, grant or subsidy"
hint_text: "For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB) and Rent to Buy"
question_text: "What was the amount of any loan, grant, discount or subsidy given?"
management_fee:
page_header: ""
has_management_fee:
check_answer_label: "Does the property have an estate management fee?"
hint_text: "Estate management fees are typically used for the maintenance of communal gardens, payments, private roads, car parks and/or play areas within new build estates."
question_text: "Does the property have an estate management fee?"
management_fee:
check_answer_label: "Monthly estate management fee"
hint_text: ""
question_text: "Enter the total monthly management fee"

8
db/migrate/20241114154215_add_management_fee_fields.rb

@ -0,0 +1,8 @@
class AddManagementFeeFields < ActiveRecord::Migration[7.0]
def change
change_table :sales_logs, bulk: true do |t|
t.column :has_management_fee, :integer
t.column :management_fee, :decimal, precision: 10, scale: 2
end
end
end

2
db/schema.rb

@ -758,6 +758,8 @@ ActiveRecord::Schema[7.0].define(version: 2024_11_18_104046) do
t.integer "partner_under_16_value_check"
t.integer "multiple_partners_value_check"
t.bigint "created_by_id"
t.integer "has_management_fee"
t.decimal "management_fee", precision: 10, scale: 2
t.index ["assigned_to_id"], name: "index_sales_logs_on_assigned_to_id"
t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"

5
spec/features/accessibility_spec.rb

@ -138,15 +138,18 @@ RSpec.describe "Accessibility", js: true do
routes = find_routes("sales-log", sales_log, bulk_upload)
routes.reject { |path|
routes = routes.reject { |path|
path.include?("/edit") || path.include?("/new") || path.include?("*page") ||
path.include?("/sales-logs/bulk-upload-logs/#{bulk_upload.id}") ||
path.include?("bulk-upload-soft-validations-check") || path.include?("filters/update") ||
path == "/sales-logs/bulk-upload-resume/#{bulk_upload.id}" ||
path == "/sales-logs/bulk-upload-logs" ||
path.include?("/check-answers") ||
other_form_page_ids.any? { |page_id| path.include?(page_id.dasherize) } ||
sales_log_pages.any? { |page| path.include?(page.id.dasherize) && !page.routed_to?(sales_log, user) }
}.uniq
routes + sales_log.form.subsections.map(&:id).map { |id| "/sales-logs/#{sales_log.id}/#{id.dasherize}/check-answers" }
end
before do

68
spec/models/form/sales/pages/living_before_purchase_spec.rb

@ -5,17 +5,19 @@ RSpec.describe Form::Sales::Pages::LivingBeforePurchase, type: :model do
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
let(:start_year) { 2022 }
let(:form) { Form.new(nil, start_year, [], "sales") }
let(:subsection) { instance_double(Form::Subsection, depends_on: nil, form:) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)
end
describe "questions" do
let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date:)) }
let(:subsection) { instance_double(Form::Subsection, form:, depends_on: nil) }
context "when 2022" do
let(:start_date) { Time.utc(2022, 2, 8) }
let(:start_year) { 2022 }
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[proplen])
@ -23,7 +25,7 @@ RSpec.describe Form::Sales::Pages::LivingBeforePurchase, type: :model do
end
context "when 2023" do
let(:start_date) { Time.utc(2023, 2, 8) }
let(:start_year) { 2023 }
it "has correct questions" do
expect(page.questions.map(&:id)).to eq(%w[proplen_asked proplen])
@ -39,15 +41,63 @@ RSpec.describe Form::Sales::Pages::LivingBeforePurchase, type: :model do
expect(page.description).to be_nil
end
it "has correct depends_on" do
expect(page.depends_on).to eq([{ "not_joint_purchase?" => true }, { "jointpur" => nil }])
end
context "when routing" do
context "with form before 2025" do
let(:start_year) { 2024 }
context "with joint purchase" do
subject(:page) { described_class.new(page_id, page_definition, subsection, ownershipsch: 1, joint_purchase: true) }
it "has correct depends_on" do
expect(page.depends_on).to eq([{ "joint_purchase?" => true }])
it "routes to the page when joint purchase is true" do
log = build(:sales_log, jointpur: 1)
expect(page.routed_to?(log, nil)).to eq(true)
end
it "does not route to the page when joint purchase is false" do
log = build(:sales_log, jointpur: 2)
expect(page.routed_to?(log, nil)).to eq(false)
end
it "does not route to the page when joint purchase is missing" do
log = build(:sales_log, jointpur: nil)
expect(page.routed_to?(log, nil)).to eq(false)
end
end
context "with non joint purchase" do
subject(:page) { described_class.new(page_id, page_definition, subsection, ownershipsch: 1, joint_purchase: false) }
it "routes to the page when joint purchase is false" do
log = build(:sales_log, jointpur: 2)
expect(page.routed_to?(log, nil)).to eq(true)
end
it "does not route to the page when joint purchase is true" do
log = build(:sales_log, jointpur: 1)
expect(page.routed_to?(log, nil)).to eq(false)
end
it "routes to the page when joint purchase is missing" do
log = build(:sales_log, jointpur: nil)
expect(page.routed_to?(log, nil)).to eq(true)
end
end
end
context "with form on or after 2025" do
subject(:page) { described_class.new(page_id, page_definition, subsection, ownershipsch: 1, joint_purchase: true) }
let(:start_year) { 2025 }
it "routes to the page when resale is 2" do
log = build(:sales_log, jointpur: 1, resale: 2)
expect(page.routed_to?(log, nil)).to eq(true)
end
it "does not route to the page when resale is not 2" do
log = build(:sales_log, jointpur: 1, resale: nil)
expect(page.routed_to?(log, nil)).to eq(false)
end
end
end
end

16
spec/models/form/sales/sections/sale_information_spec.rb

@ -5,12 +5,13 @@ RSpec.describe Form::Sales::Sections::SaleInformation, type: :model do
let(:section_id) { nil }
let(:section_definition) { nil }
let(:form) { instance_double(Form) }
let(:form) { instance_double(Form, start_year_2025_or_later?: false) }
it "has correct form" do
expect(sale_information.form).to eq(form)
end
context "when form is before 2025" do
it "has correct subsections" do
expect(sale_information.subsections.map(&:id)).to eq(%w[
shared_ownership_scheme
@ -18,6 +19,19 @@ RSpec.describe Form::Sales::Sections::SaleInformation, type: :model do
outright_sale
])
end
end
context "when form is 2025 or later" do
let(:form) { instance_double(Form, start_year_2025_or_later?: true) }
it "has correct subsections" do
expect(sale_information.subsections.map(&:id)).to eq(%w[
shared_ownership_initial_purchase
discounted_ownership_scheme
outright_sale
])
end
end
it "has the correct id" do
expect(sale_information.id).to eq("sale_information")

95
spec/models/form/sales/subsections/shared_ownership_initial_purchase_spec.rb

@ -0,0 +1,95 @@
require "rails_helper"
RSpec.describe Form::Sales::Subsections::SharedOwnershipInitialPurchase, type: :model do
subject(:shared_ownership_initial_purchase) { described_class.new(subsection_id, subsection_definition, section) }
let(:subsection_id) { nil }
let(:subsection_definition) { nil }
let(:section) { instance_double(Form::Sales::Sections::SaleInformation) }
before do
allow(section).to receive(:form).and_return(instance_double(Form, start_date: Time.zone.local(2025, 4, 1)))
end
it "has correct section" do
expect(shared_ownership_initial_purchase.section).to eq(section)
end
it "has correct pages" do
expect(shared_ownership_initial_purchase.pages.map(&:id)).to eq(
%w[
resale
living_before_purchase_shared_ownership_joint_purchase
living_before_purchase_shared_ownership
handover_date
handover_date_check
buyer_previous_joint_purchase
buyer_previous_not_joint_purchase
previous_bedrooms
previous_property_type
shared_ownership_previous_tenure
value_shared_ownership
about_price_shared_ownership_value_check
equity
shared_ownership_equity_value_check
mortgage_used_shared_ownership
mortgage_used_mortgage_value_check
mortgage_amount_shared_ownership
shared_ownership_mortgage_amount_value_check
mortgage_amount_mortgage_value_check
mortgage_length_shared_ownership
deposit_shared_ownership
deposit_shared_ownership_optional
deposit_joint_purchase_value_check
deposit_value_check
deposit_discount
deposit_discount_optional
shared_ownership_deposit_value_check
monthly_rent
leasehold_charges_shared_ownership
monthly_charges_shared_ownership_value_check
estate_management_fee
],
)
end
it "has the correct id" do
expect(shared_ownership_initial_purchase.id).to eq("shared_ownership_initial_purchase")
end
it "has the correct label" do
expect(shared_ownership_initial_purchase.label).to eq("Shared ownership - initial purchase")
end
it "has the correct depends_on" do
expect(shared_ownership_initial_purchase.depends_on).to eq([
{
"ownershipsch" => 1, "setup_completed?" => true, "staircase" => 2
},
])
end
context "when it is a shared ownership scheme and not staircase" do
let(:log) { FactoryBot.build(:sales_log, ownershipsch: 1, staircase: 2) }
it "is displayed in tasklist" do
expect(shared_ownership_initial_purchase.displayed_in_tasklist?(log)).to eq(true)
end
end
context "when it is not a shared ownership scheme" do
let(:log) { FactoryBot.build(:sales_log, ownershipsch: 2, staircase: 2) }
it "is displayed in tasklist" do
expect(shared_ownership_initial_purchase.displayed_in_tasklist?(log)).to eq(false)
end
end
context "when it is staircase" do
let(:log) { FactoryBot.build(:sales_log, ownershipsch: 1, staircase: 1) }
it "is displayed in tasklist" do
expect(shared_ownership_initial_purchase.displayed_in_tasklist?(log)).to eq(false)
end
end
end

23
spec/services/bulk_upload/lettings/year2024/csv_parser_spec.rb

@ -30,6 +30,29 @@ RSpec.describe BulkUpload::Lettings::Year2024::CsvParser do
end
end
context "when some csv headers are empty (and we don't care about them)" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::LettingsLogToCsv.new(log:).default_2024_field_numbers_row)
file.write(BulkUpload::LettingsLogToCsv.new(log:).to_2024_csv_row)
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_13).to eql(log.tenancycode)
end
end
context "when parsing csv with headers with extra rows" do
before do
file.write("Section\n")

32
spec/services/bulk_upload/sales/year2024/csv_parser_spec.rb

@ -39,6 +39,38 @@ RSpec.describe BulkUpload::Sales::Year2024::CsvParser do
end
end
context "when some csv headers are empty (and we don't care about them)" do
before do
file.write("Question\n")
file.write("Additional info\n")
file.write("Values\n")
file.write("\n")
file.write("Type of letting the question applies to\n")
file.write("Duplicate check field?\n")
file.write(BulkUpload::SalesLogToCsv.new(log:).default_2024_field_numbers_row)
file.write(BulkUpload::SalesLogToCsv.new(log:).to_2024_csv_row)
file.write("\n")
file.rewind
end
it "returns correct offsets" do
expect(service.row_offset).to eq(7)
expect(service.col_offset).to eq(1)
end
it "parses csv correctly" do
expect(service.row_parsers[0].field_22).to eql(log.uprn)
end
it "counts the number of valid field numbers correctly" do
expect(service).to be_correct_field_count
end
it "does not parse the last empty row" do
expect(service.row_parsers.count).to eq(1)
end
end
context "when parsing csv with headers in arbitrary order" do
let(:seed) { rand }

Loading…
Cancel
Save