Browse Source

Merge branch 'main' into CLDC-1821-wheelchair-conditionally-visible

pull/1343/head
Arthur Campbell 3 years ago committed by GitHub
parent
commit
2974e5ba59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      app/components/bulk_upload_error_summary_table_component.rb
  2. 19
      app/components/check_answers_summary_list_card_component.rb
  3. 8
      app/mailers/bulk_upload_mailer.rb
  4. 9
      app/models/derived_variables/sales_log_variables.rb
  5. 10
      app/models/form/sales/pages/number_of_others_in_property.rb
  6. 12
      app/models/form/sales/questions/buyer1_mortgage.rb
  7. 29
      app/models/form/sales/questions/buyer1_previous_tenure.rb
  8. 12
      app/models/form/sales/questions/buyer2_mortgage.rb
  9. 10
      app/models/form/sales/questions/buyers_organisations.rb
  10. 8
      app/models/form/sales/questions/mortgageused.rb
  11. 18
      app/models/form/sales/questions/number_of_others_in_property.rb
  12. 35
      app/models/form/sales/questions/shared_ownership_type.rb
  13. 11
      app/models/form/sales/subsections/household_characteristics.rb
  14. 5
      app/models/lettings_log.rb
  15. 5
      app/models/log.rb
  16. 16
      app/models/sales_log.rb
  17. 10
      app/models/validations/financial_validations.rb
  18. 2
      app/models/validations/household_validations.rb
  19. 2
      app/models/validations/sales/sale_information_validations.rb
  20. 2
      app/models/validations/sales/soft_validations.rb
  21. 32
      app/services/imports/lettings_logs_import_service.rb
  22. 80
      app/services/imports/sales_logs_import_service.rb
  23. 8
      app/views/bulk_upload_lettings_results/show.html.erb
  24. 1
      app/views/form/headers/_person_6_known_page.erb
  25. 32
      config/sale_range_data/2023.csv
  26. 5
      db/migrate/20230301144555_add_pregblank.rb
  27. 9
      db/schema.rb
  28. 1
      db/seeds.rb
  29. 1
      lib/tasks/full_import.rake
  30. 35
      spec/components/bulk_upload_error_summary_table_component_spec.rb
  31. 333
      spec/fixtures/imports/logs/shared_ownership_sales_log.xml
  32. 2
      spec/fixtures/imports/sales_logs/discounted_ownership_sales_log.xml
  33. 524
      spec/fixtures/imports/sales_logs/lettings_log.xml
  34. 4
      spec/lib/tasks/full_import_spec.rb
  35. 4
      spec/mailers/bulk_upload_mailer_spec.rb
  36. 4
      spec/models/form/sales/pages/buyer1_previous_tenure_spec.rb
  37. 40
      spec/models/form/sales/pages/number_of_others_in_property_spec.rb
  38. 4
      spec/models/form/sales/pages/shared_ownership_type_spec.rb
  39. 13
      spec/models/form/sales/questions/buyer1_mortgage_spec.rb
  40. 10
      spec/models/form/sales/questions/buyer1_previous_tenure_spec.rb
  41. 13
      spec/models/form/sales/questions/buyer2_mortgage_spec.rb
  42. 12
      spec/models/form/sales/questions/buyers_organisations_spec.rb
  43. 9
      spec/models/form/sales/questions/mortgageused_spec.rb
  44. 25
      spec/models/form/sales/questions/number_of_others_in_property_spec.rb
  45. 44
      spec/models/form/sales/questions/shared_ownership_type_spec.rb
  46. 18
      spec/models/form/sales/subsections/household_characteristics_spec.rb
  47. 30
      spec/models/sales_log_spec.rb
  48. 2
      spec/models/validations/financial_validations_spec.rb
  49. 110
      spec/services/imports/lettings_logs_import_service_spec.rb
  50. 199
      spec/services/imports/sales_logs_import_service_spec.rb

13
app/components/bulk_upload_error_summary_table_component.rb

@ -1,4 +1,6 @@
class BulkUploadErrorSummaryTableComponent < ViewComponent::Base
DISPLAY_THRESHOLD = 16
attr_reader :bulk_upload
def initialize(bulk_upload:)
@ -11,7 +13,18 @@ class BulkUploadErrorSummaryTableComponent < ViewComponent::Base
@sorted_errors ||= bulk_upload
.bulk_upload_errors
.group(:col, :field, :error)
.having("count(*) > ?", display_threshold)
.count
.sort_by { |el| el[0][0].rjust(3, "0") }
end
def errors?
sorted_errors.present?
end
private
def display_threshold
DISPLAY_THRESHOLD
end
end

19
app/components/check_answers_summary_list_card_component.rb

@ -18,21 +18,10 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base
end
def check_answers_card_title(question)
if question.form.type == "lettings"
case question.check_answers_card_number
when 1
"Lead tenant"
when 2..8
"Person #{question.check_answers_card_number}"
end
else
case question.check_answers_card_number
when 1..number_of_buyers
"Buyer #{question.check_answers_card_number}"
when (number_of_buyers + 1)..(number_of_buyers + 4)
"Person #{question.check_answers_card_number}"
end
end
return "Lead tenant" if question.form.type == "lettings" && question.check_answers_card_number == 1
return "Buyer #{question.check_answers_card_number}" if question.check_answers_card_number <= number_of_buyers
"Person #{question.check_answers_card_number}"
end
private

8
app/mailers/bulk_upload_mailer.rb

@ -46,6 +46,12 @@ class BulkUploadMailer < NotifyMailer
def send_correct_and_upload_again_mail(bulk_upload:)
error_description = "We noticed that you have a lot of similar errors in column #{columns_with_errors(bulk_upload:)}. Please correct your data export and upload again."
summary_report_link = if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
summary_bulk_upload_lettings_result_url(bulk_upload)
else
bulk_upload_lettings_result_url(bulk_upload)
end
send_email(
bulk_upload.user.email,
BULK_UPLOAD_FAILED_CSV_ERRORS_TEMPLATE_ID,
@ -55,7 +61,7 @@ class BulkUploadMailer < NotifyMailer
year_combo: bulk_upload.year_combo,
lettings_or_sales: bulk_upload.log_type,
error_description:,
summary_report_link: summary_bulk_upload_lettings_result_url(bulk_upload),
summary_report_link:,
},
)
end

9
app/models/derived_variables/sales_log_variables.rb

@ -21,12 +21,19 @@ module DerivedVariables::SalesLogVariables
self.pcode1, self.pcode2 = postcode_full.split(" ") if postcode_full.present?
self.totchild = total_child
self.totadult = total_adult + total_elder
self.hhmemb = totchild + totadult
self.hhmemb = number_of_household_members
self.hhtype = household_type
end
private
def number_of_household_members
return unless hholdcount.present? && jointpur.present?
number_of_buyers = joint_purchase? ? 2 : 1
hholdcount + number_of_buyers
end
def total_elder
ages = [age1, age2, age3, age4, age5, age6]
ages.count { |age| age.present? && age >= 60 }

10
app/models/form/sales/pages/number_of_others_in_property.rb

@ -1,20 +1,22 @@
class Form::Sales::Pages::NumberOfOthersInProperty < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "number_of_others_in_property"
def initialize(id, hsh, subsection, joint_purchase:)
super(id, hsh, subsection)
@depends_on = [
{
"privacynotice" => 1,
"jointpur" => joint_purchase ? 1 : 2,
},
{
"noint" => 1,
"jointpur" => joint_purchase ? 1 : 2,
},
]
@joint_purchase = joint_purchase
end
def questions
@questions ||= [
Form::Sales::Questions::NumberOfOthersInProperty.new(nil, nil, self),
Form::Sales::Questions::NumberOfOthersInProperty.new(nil, nil, self, joint_purchase: @joint_purchase),
]
end
end

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

@ -2,8 +2,8 @@ class Form::Sales::Questions::Buyer1Mortgage < ::Form::Question
def initialize(id, hsh, page)
super
@id = "inc1mort"
@check_answer_label = "Buyer 1's income used for mortgage application"
@header = "Was buyer 1's income used for a mortgage application?"
@check_answer_label = "Buyer 1s income used for mortgage application"
@header = "Was buyer 1s income used for a mortgage application?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@check_answers_card_number = 1
@ -12,5 +12,13 @@ class Form::Sales::Questions::Buyer1Mortgage < ::Form::Question
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
}.freeze
def displayed_answer_options(_log, _user = nil)
{
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
}
end
end

29
app/models/form/sales/questions/buyer1_previous_tenure.rb

@ -2,20 +2,23 @@ class Form::Sales::Questions::Buyer1PreviousTenure < ::Form::Question
def initialize(id, hsh, page)
super
@id = "prevten"
@check_answer_label = "Buyer 1's previous tenure"
@header = "What was buyer 1's previous tenure?"
@check_answer_label = "Buyer 1s previous tenure"
@header = "What was buyer 1s previous tenure?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@answer_options = answer_options
end
ANSWER_OPTIONS = {
"1" => { "value" => "Local Authority" },
"2" => { "value" => "Private registered provider or housing association tenant" },
"3" => { "value" => "Private tenant" },
"5" => { "value" => "Owner occupier" },
"4" => { "value" => "Tied home or renting with job" },
"6" => { "value" => "Living with family or friends" },
"7" => { "value" => "Temporary accomodation" },
"9" => { "value" => "Other" },
}.freeze
def answer_options
{
"1" => { "value" => "Local Authority" },
"2" => { "value" => "Private registered provider or housing association tenant" },
"3" => { "value" => "Private tenant" },
"5" => { "value" => "Owner occupier" },
"4" => { "value" => "Tied home or renting with job" },
"6" => { "value" => "Living with family or friends" },
"7" => { "value" => "Temporary accomodation" },
"9" => { "value" => "Other" },
"0" => { "value" => "Don’t know" },
}
end
end

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

@ -2,8 +2,8 @@ class Form::Sales::Questions::Buyer2Mortgage < ::Form::Question
def initialize(id, hsh, page)
super
@id = "inc2mort"
@check_answer_label = "Buyer 2's income used for mortgage application"
@header = "Was buyer 2's income used for a mortgage application?"
@check_answer_label = "Buyer 2s income used for mortgage application"
@header = "Was buyer 2s income used for a mortgage application?"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@check_answers_card_number = 2
@ -12,5 +12,13 @@ class Form::Sales::Questions::Buyer2Mortgage < ::Form::Question
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
}.freeze
def displayed_answer_options(_log, _user = nil)
{
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
}
end
end

10
app/models/form/sales/questions/buyers_organisations.rb

@ -14,8 +14,18 @@ class Form::Sales::Questions::BuyersOrganisations < ::Form::Question
"pregother" => { "value" => "Other private registered provider (PRP) - housing association" },
"pregla" => { "value" => "Local Authority" },
"pregghb" => { "value" => "Help to Buy Agent" },
"pregblank" => { "value" => "None of the above" },
}.freeze
def displayed_answer_options(_log, _user = nil)
{
"pregyrha" => { "value" => "Their private registered provider (PRP) - housing association" },
"pregother" => { "value" => "Other private registered provider (PRP) - housing association" },
"pregla" => { "value" => "Local Authority" },
"pregghb" => { "value" => "Help to Buy Agent" },
}
end
def unanswered_error_message
"At least one option must be selected of these four"
end

8
app/models/form/sales/questions/mortgageused.rb

@ -11,5 +11,13 @@ class Form::Sales::Questions::Mortgageused < ::Form::Question
ANSWER_OPTIONS = {
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
}.freeze
def displayed_answer_options(_log, _user = nil)
{
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
}
end
end

18
app/models/form/sales/questions/number_of_others_in_property.rb

@ -1,13 +1,23 @@
class Form::Sales::Questions::NumberOfOthersInProperty < ::Form::Question
def initialize(id, hsh, page)
super
def initialize(id, hsh, page, joint_purchase:)
super(id, hsh, page)
@id = "hholdcount"
@check_answer_label = "Number of other people living in the property"
@header = "Besides the buyer(s), how many other people live or will live in the property?"
@type = "numeric"
@hint_text = "You can provide details for a maximum of 4 other people."
@hint_text = hint(joint_purchase)
@width = 2
@min = 0
@max = 4
@max = joint_purchase ? 4 : 5
end
private
def hint(joint_purchase)
if joint_purchase
"You can provide details for a maximum of 4 other people for a joint purchase."
else
"You can provide details for a maximum of 5 other people if there is only one buyer."
end
end
end

35
app/models/form/sales/questions/shared_ownership_type.rb

@ -6,16 +6,31 @@ class Form::Sales::Questions::SharedOwnershipType < ::Form::Question
@header = "What is the type of shared ownership sale?"
@hint_text = "A shared ownership sale is when the purchaser buys up to 75% of the property value and pays rent to the Private Registered Provider (PRP) on the remaining portion"
@type = "radio"
@answer_options = ANSWER_OPTIONS
@answer_options = answer_options
end
ANSWER_OPTIONS = {
"2" => { "value" => "Shared Ownership" },
"24" => { "value" => "Old Persons Shared Ownership" },
"18" => { "value" => "Social HomeBuy (shared ownership purchase)" },
"16" => { "value" => "Home Ownership for people with Long Term Disabilities (HOLD)" },
"28" => { "value" => "Rent to Buy - Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership" },
"30" => { "value" => "Shared Ownership - 2021 model lease" },
}.freeze
def answer_options
if form.start_date.year >= 2023
{
"2" => { "value" => "Shared Ownership (old model lease)" },
"30" => { "value" => "Shared Ownership (new model lease)" },
"18" => { "value" => "Social HomeBuy — shared ownership purchase" },
"16" => { "value" => "Home Ownership for people with Long-Term Disabilities (HOLD)" },
"24" => { "value" => "Older Persons Shared Ownership" },
"28" => { "value" => "Rent to Buy — Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership (RtSO)" },
"32" => { "value" => "London Living Rent — Shared Ownership" },
}
else
{
"2" => { "value" => "Shared Ownership" },
"24" => { "value" => "Old Persons Shared Ownership" },
"18" => { "value" => "Social HomeBuy (shared ownership purchase)" },
"16" => { "value" => "Home Ownership for people with Long-Term Disabilities (HOLD)" },
"28" => { "value" => "Rent to Buy - Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership" },
"30" => { "value" => "Shared Ownership - 2021 model lease" },
}
end
end
end

11
app/models/form/sales/subsections/household_characteristics.rb

@ -37,7 +37,8 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection
Form::Sales::Pages::RetirementValueCheck.new("working_situation_2_retirement_value_check_joint_purchase", nil, self, person_index: 2),
Form::Sales::Pages::Buyer2IncomeValueCheck.new("working_situation_buyer_2_income_value_check", nil, self),
Form::Sales::Pages::Buyer2LiveInProperty.new(nil, nil, self),
Form::Sales::Pages::NumberOfOthersInProperty.new(nil, nil, self),
Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property", nil, self, joint_purchase: false),
Form::Sales::Pages::NumberOfOthersInProperty.new("number_of_others_in_property_joint_purchase", nil, self, joint_purchase: true),
Form::Sales::Pages::PersonKnown.new("person_2_known", nil, self, person_index: 2),
Form::Sales::Pages::PersonRelationshipToBuyer1.new("person_2_relationship_to_buyer_1", nil, self, person_index: 2),
Form::Sales::Pages::PersonAge.new("person_2_age", nil, self, person_index: 2),
@ -70,6 +71,14 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection
Form::Sales::Pages::RetirementValueCheck.new("gender_5_retirement_value_check", nil, self, person_index: 5),
Form::Sales::Pages::PersonWorkingSituation.new("person_5_working_situation", nil, self, person_index: 5),
Form::Sales::Pages::RetirementValueCheck.new("working_situation_5_retirement_value_check", nil, self, person_index: 5),
Form::Sales::Pages::PersonKnown.new("person_6_known", nil, self, person_index: 6),
Form::Sales::Pages::PersonRelationshipToBuyer1.new("person_6_relationship_to_buyer_1", nil, self, person_index: 6),
Form::Sales::Pages::PersonAge.new("person_6_age", nil, self, person_index: 6),
Form::Sales::Pages::RetirementValueCheck.new("age_6_retirement_value_check", nil, self, person_index: 6),
Form::Sales::Pages::PersonGenderIdentity.new("person_6_gender_identity", nil, self, person_index: 6),
Form::Sales::Pages::RetirementValueCheck.new("gender_6_retirement_value_check", nil, self, person_index: 6),
Form::Sales::Pages::PersonWorkingSituation.new("person_6_working_situation", nil, self, person_index: 6),
Form::Sales::Pages::RetirementValueCheck.new("working_situation_6_retirement_value_check", nil, self, person_index: 6),
].flatten.compact
end

5
app/models/lettings_log.rb

@ -65,11 +65,6 @@ class LettingsLog < Log
FormHandler.instance.get_form(form_name) || FormHandler.instance.current_lettings_form
end
def recalculate_start_year!
@start_year = nil
collection_start_year
end
def lettings?
true
end

5
app/models/log.rb

@ -39,6 +39,11 @@ class Log < ApplicationRecord
@start_year = startdate < window_end_date ? startdate.year - 1 : startdate.year
end
def recalculate_start_year!
@start_year = nil
collection_start_year
end
def lettings?
false
end

16
app/models/sales_log.rb

@ -24,6 +24,7 @@ class SalesLog < Log
has_paper_trail
validates_with SalesLogValidator
before_validation :recalculate_start_year!, if: :saledate_changed?
before_validation :reset_invalidated_dependent_fields!
before_validation :process_postcode_changes!, if: :postcode_full_changed?
before_validation :process_previous_postcode_changes!, if: :ppostcode_full_changed?
@ -65,7 +66,20 @@ class SalesLog < Log
end
def optional_fields
OPTIONAL_FIELDS
OPTIONAL_FIELDS + dynamically_not_required
end
def dynamically_not_required
not_required = []
not_required << "proplen" if proplen_optional?
not_required
end
def proplen_optional?
return false unless collection_start_year
collection_start_year < 2023
end
def not_started?

10
app/models/validations/financial_validations.rb

@ -24,11 +24,11 @@ module Validations::FinancialValidations
def validate_net_income(record)
if record.ecstat1 && record.weekly_net_income
if record.weekly_net_income > record.applicable_income_range.hard_max
record.errors.add :earnings, I18n.t("validations.financial.earnings.over_hard_max", hard_max: record.applicable_income_range.hard_max)
record.errors.add :earnings, :over_hard_max, message: I18n.t("validations.financial.earnings.over_hard_max", hard_max: record.applicable_income_range.hard_max)
end
if record.weekly_net_income < record.applicable_income_range.hard_min
record.errors.add :earnings, I18n.t("validations.financial.earnings.under_hard_min", hard_min: record.applicable_income_range.hard_min)
record.errors.add :earnings, :under_hard_min, message: I18n.t("validations.financial.earnings.under_hard_min", hard_min: record.applicable_income_range.hard_min)
end
end
@ -111,9 +111,11 @@ module Validations::FinancialValidations
def validate_care_home_charges(record)
if record.is_carehome?
period = record.form.get_question("period", record).label_from_value(record.period).downcase
# NOTE: This is a temporary change to allow `ccharge` values despite `is_carehome` being true. This value
# is going to be moved to a soft validation in CLDC-2074, so we can safely do this.
if record.chcharge.blank?
record.errors.add :is_carehome, I18n.t("validations.financial.carehome.not_provided", period:)
record.errors.add :chcharge, I18n.t("validations.financial.carehome.not_provided", period:)
# record.errors.add :is_carehome, I18n.t("validations.financial.carehome.not_provided", period:)
# record.errors.add :chcharge, I18n.t("validations.financial.carehome.not_provided", period:)
elsif !weekly_value_in_range(record, "chcharge", 10, 1000)
max_chcharge = record.weekly_to_value_per_period(1000)
min_chcharge = record.weekly_to_value_per_period(10)

2
app/models/validations/household_validations.rb

@ -67,7 +67,7 @@ module Validations::HouseholdValidations
end
if record.age1.present? && record.age1 > 19 && record.previous_tenancy_was_foster_care?
record.errors.add :prevten, I18n.t("validations.household.prevten.over_20_foster_care")
record.errors.add :prevten, :over_20_foster_care, message: I18n.t("validations.household.prevten.over_20_foster_care")
record.errors.add :age1, I18n.t("validations.household.age.lead.over_20")
end

2
app/models/validations/sales/sale_information_validations.rb

@ -46,7 +46,7 @@ module Validations::Sales::SaleInformationValidations
def validate_discounted_ownership_value(record)
return unless record.value && record.deposit && record.ownershipsch
return unless record.mortgage || record.mortgageused == 2
return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3
return unless record.discount || record.grant || record.type == 29
discount_amount = record.discount ? record.value * record.discount / 100 : 0

2
app/models/validations/sales/soft_validations.rb

@ -60,7 +60,7 @@ module Validations::Sales::SoftValidations
end
def shared_ownership_deposit_invalid?
return unless mortgage || mortgageused == 2
return unless mortgage || mortgageused == 2 || mortgageused == 3
return unless cashdis || !is_type_discount?
return unless deposit && value && equity

32
app/services/imports/lettings_logs_import_service.rb

@ -55,6 +55,8 @@ module Imports
}.freeze
def create_log(xml_doc)
return if meta_field_value(xml_doc, "form-name").include?("Sales")
attributes = {}
previous_status = meta_field_value(xml_doc, "status")
@ -287,8 +289,38 @@ module Imports
@logs_overridden << lettings_log.old_id
attributes.delete("referral")
save_lettings_log(attributes, previous_status)
elsif lettings_log.errors.of_kind?(:earnings, :under_hard_min)
@logger.warn("Log #{lettings_log.old_id}: Where the income is 0, set earnings and income to blank and set incref to refused")
@logs_overridden << lettings_log.old_id
attributes.delete("earnings")
attributes.delete("incfreq")
attributes["incref"] = 1
attributes["net_income_known"] = 2
save_lettings_log(attributes, previous_status)
elsif lettings_log.errors.include?(:tenancylength) && lettings_log.errors.include?(:tenancy)
@logger.warn("Log #{lettings_log.old_id}: Removing tenancylength as invalid")
@logs_overridden << lettings_log.old_id
attributes.delete("tenancylength")
attributes.delete("tenancy")
save_lettings_log(attributes, previous_status)
elsif lettings_log.errors.of_kind?(:prevten, :over_20_foster_care)
@logger.warn("Log #{lettings_log.old_id}: Removing age1 and prevten as incompatible")
@logs_overridden << lettings_log.old_id
attributes.delete("prevten")
attributes.delete("age1")
save_lettings_log(attributes, previous_status)
else
@logger.error("Log #{lettings_log.old_id}: Failed to import")
lettings_log.errors.each do |error|
@logger.error("Validation error: Field #{error.attribute}:")
@logger.error("\tOwning Organisation: #{lettings_log.owning_organisation&.name}")
@logger.error("\tManaging Organisation: #{lettings_log.managing_organisation&.name}")
@logger.error("\tOld CORE ID: #{lettings_log.old_id}")
@logger.error("\tOld CORE: #{attributes[error.attribute.to_s]&.inspect}")
@logger.error("\tNew CORE: #{lettings_log.read_attribute(error.attribute)&.inspect}")
@logger.error("\tError message: #{error.type}")
end
raise exception
end
end

80
app/services/imports/sales_logs_import_service.rb

@ -16,6 +16,8 @@ module Imports
private
def create_log(xml_doc)
return unless meta_field_value(xml_doc, "form-name").include?("Sales")
attributes = {}
previous_status = meta_field_value(xml_doc, "status")
@ -31,12 +33,14 @@ module Imports
attributes["updated_at"] = Time.zone.parse(meta_field_value(xml_doc, "modified-date"))
attributes["purchid"] = string_or_nil(xml_doc, "PurchaserCode")
attributes["ownershipsch"] = unsafe_string_as_integer(xml_doc, "Ownership")
attributes["ownershipsch"] = ownership_from_type(attributes) if attributes["ownershipsch"].blank? # sometimes Ownership is missing, but type is set
attributes["othtype"] = string_or_nil(xml_doc, "Q38OtherSale")
attributes["jointmore"] = unsafe_string_as_integer(xml_doc, "JointMore")
attributes["jointpur"] = unsafe_string_as_integer(xml_doc, "joint")
attributes["jointmore"] = unsafe_string_as_integer(xml_doc, "JointMore") if attributes["jointpur"] == 1
attributes["beds"] = safe_string_as_integer(xml_doc, "Q11Bedrooms")
attributes["companybuy"] = unsafe_string_as_integer(xml_doc, "company") if attributes["ownershipsch"] == 3
attributes["hhmemb"] = safe_string_as_integer(xml_doc, "HHMEMB")
attributes["hholdcount"] = other_household_members(xml_doc, attributes)
attributes["hhmemb"] = household_members(xml_doc, attributes)
(1..6).each do |index|
attributes["age#{index}"] = safe_string_as_integer(xml_doc, "P#{index}Age")
attributes["sex#{index}"] = sex(xml_doc, index)
@ -59,7 +63,6 @@ module Imports
attributes["noint"] = unsafe_string_as_integer(xml_doc, "PartAPurchaser")
attributes["buy2livein"] = unsafe_string_as_integer(xml_doc, "LiveInBuyer2")
attributes["wheel"] = unsafe_string_as_integer(xml_doc, "Q10Wheelchair")
attributes["hholdcount"] = safe_string_as_integer(xml_doc, "LiveInOther")
attributes["la"] = string_or_nil(xml_doc, "Q14ONSLACode")
attributes["income1"] = safe_string_as_integer(xml_doc, "Q2Person1Income")
attributes["income1nk"] = income_known(unsafe_string_as_integer(xml_doc, "P1IncKnown"))
@ -102,10 +105,12 @@ module Imports
attributes["previous_la_known"] = nil
attributes["hhregres"] = unsafe_string_as_integer(xml_doc, "ArmedF")
attributes["hhregresstill"] = still_serving(xml_doc)
attributes["proplen"] = safe_string_as_integer(xml_doc, "Q16aProplen2")
attributes["proplen"] = safe_string_as_integer(xml_doc, "Q16aProplen2") || safe_string_as_integer(xml_doc, "Q16aProplensec2")
attributes["mscharge"] = monthly_charges(xml_doc, attributes)
attributes["mscharge_known"] = 1 if attributes["mscharge"].present?
attributes["prevten"] = unsafe_string_as_integer(xml_doc, "Q6PrevTenure")
attributes["mortlen"] = mortgage_length(xml_doc, attributes)
attributes["extrabor"] = borrowing(xml_doc, attributes)
attributes["mortgageused"] = unsafe_string_as_integer(xml_doc, "MORTGAGEUSED")
attributes["wchair"] = unsafe_string_as_integer(xml_doc, "Q15Wheelchair")
attributes["armedforcesspouse"] = unsafe_string_as_integer(xml_doc, "ARMEDFORCESSPOUSE")
@ -117,11 +122,6 @@ module Imports
attributes["socprevten"] = unsafe_string_as_integer(xml_doc, "PrevRentType")
attributes["mortgagelender"] = mortgage_lender(xml_doc, attributes)
attributes["mortgagelenderother"] = mortgage_lender_other(xml_doc, attributes)
attributes["mortlen"] = mortgage_length(xml_doc, attributes)
attributes["extrabor"] = borrowing(xml_doc, attributes)
attributes["totadult"] = safe_string_as_integer(xml_doc, "TOTADULT") # would get overridden
attributes["totchild"] = safe_string_as_integer(xml_doc, "TOTCHILD") # would get overridden
attributes["hhtype"] = unsafe_string_as_integer(xml_doc, "HHTYPE")
attributes["pcode1"] = string_or_nil(xml_doc, "PCODE1")
attributes["pcode2"] = string_or_nil(xml_doc, "PCODE2")
attributes["postcode_full"] = compose_postcode(xml_doc, "PCODE1", "PCODE2")
@ -396,6 +396,49 @@ module Imports
end
end
def ownership_from_type(attributes)
case attributes["type"]
when 2, 24, 18, 16, 28, 31, 30
1 # shared ownership
when 8, 14, 27, 9, 29, 21, 22
2 # discounted ownership
when 10, 12
3 # outright sale
end
end
def other_household_members(xml_doc, attributes)
hholdcount = safe_string_as_integer(xml_doc, "LiveInOther")
return hholdcount if hholdcount.present?
other_people_with_details(xml_doc, attributes)
end
def other_people_with_details(xml_doc, attributes)
number_of_buyers = attributes["jointpur"] == 1 ? 2 : 1
highest_person_index_with_details = number_of_buyers
(2..6).each do |person_index|
age = string_or_nil(xml_doc, "P#{person_index}Age")
gender = string_or_nil(xml_doc, "P#{person_index}Sex")
relationship = string_or_nil(xml_doc, "P#{person_index}Rel")
economic_status = string_or_nil(xml_doc, "P#{person_index}Eco")
if gender.present? || age.present? || relationship.present? || economic_status.present?
highest_person_index_with_details = person_index
end
end
highest_person_index_with_details - number_of_buyers
end
def household_members(_xml_doc, attributes)
if attributes["jointpur"] == 2
attributes["hholdcount"] + 1
else
attributes["hholdcount"] + 2
end
end
def set_default_values(attributes)
attributes["armedforcesspouse"] ||= 7
attributes["hhregres"] ||= 8
@ -404,7 +447,11 @@ module Imports
attributes["hb"] ||= 4
attributes["prevown"] ||= 3
attributes["savingsnk"] ||= attributes["savings"].present? ? 0 : 1
# attributes["noint"] = 1 # not interviewed
attributes["jointmore"] ||= 3 if attributes["jointpur"] == 1
attributes["inc1mort"] ||= 3
if [attributes["pregyrha"], attributes["pregla"], attributes["pregghb"], attributes["pregother"]].all?(&:blank?)
attributes["pregblank"] = 1
end
# buyer 1 characteristics
attributes["age1_known"] ||= 1
@ -414,7 +461,6 @@ module Imports
attributes["national"] ||= 13
attributes["ecstat1"] ||= 10
attributes["income1nk"] ||= attributes["income1"].present? ? 0 : 1
attributes["hholdcount"] ||= default_household_count(attributes) # just for testing, might need to change
# buyer 2 characteristics
if attributes["jointpur"] == 1
@ -422,6 +468,9 @@ module Imports
attributes["sex2"] ||= "R"
attributes["ecstat2"] ||= 10
attributes["income2nk"] ||= attributes["income2"].present? ? 0 : 1
attributes["relat2"] ||= "R"
attributes["inc2mort"] ||= 3
attributes["buy2livein"] ||= 1 unless attributes["ownershipsch"] == 3
end
# other household members characteristics
@ -434,15 +483,8 @@ module Imports
end
def missing_answers(sales_log)
applicable_questions = sales_log.form.subsections.map { |s| s.applicable_questions(sales_log) }.flatten
applicable_questions = sales_log.form.subsections.map { |s| s.applicable_questions(sales_log).select { |q| q.enabled?(sales_log) } }.flatten
applicable_questions.filter { |q| q.unanswered?(sales_log) }.map(&:id)
end
# just for testing, logic might need to change
def default_household_count(attributes)
return 0 if attributes["hhmemb"].zero? || attributes["hhmemb"].blank?
attributes["jointpur"] == 1 ? attributes["hhmemb"] - 2 : attributes["hhmemb"] - 1
end
end
end

8
app/views/bulk_upload_lettings_results/show.html.erb

@ -1,5 +1,7 @@
<% content_for :before_content do %>
<%= govuk_back_link(text: "Back", href: summary_bulk_upload_lettings_result_path(@bulk_upload)) %>
<% if BulkUploadErrorSummaryTableComponent.new(bulk_upload: @bulk_upload).errors? %>
<% content_for :before_content do %>
<%= govuk_back_link(text: "Back", href: summary_bulk_upload_lettings_result_path(@bulk_upload)) %>
<% end %>
<% end %>
<div class="govuk-grid-row">
@ -22,3 +24,5 @@
<% end %>
</div>
</div>
<%= govuk_button_link_to "Upload your file again", start_bulk_upload_lettings_logs_path %>

1
app/views/form/headers/_person_6_known_page.erb

@ -0,0 +1 @@
You have given us the details for <%= log.joint_purchase? ? 3 : 4 %> of the <%= log.hholdcount %> other people in the household

32
config/sale_range_data/2023.csv

@ -87,10 +87,10 @@ Boston,E07000136,1,58000,258000
Boston,E07000136,2,58000,258000
Boston,E07000136,3,111000,308000
Boston,E07000136,4,212000,510000
Bournemouth, Christchurch and Poole,E06000058,1,140000,500000
Bournemouth, Christchurch and Poole,E06000058,2,197000,500000
Bournemouth, Christchurch and Poole,E06000058,3,285000,657000
Bournemouth, Christchurch and Poole,E06000058,4,370000,1321000
"Bournemouth, Christchurch and Poole",E06000058,1,140000,500000
"Bournemouth, Christchurch and Poole",E06000058,2,197000,500000
"Bournemouth, Christchurch and Poole",E06000058,3,285000,657000
"Bournemouth, Christchurch and Poole",E06000058,4,370000,1321000
Bracknell Forest,E06000036,1,95000,488000
Bracknell Forest,E06000036,2,157000,488000
Bracknell Forest,E06000036,3,341000,654000
@ -119,10 +119,10 @@ Brighton and Hove,E06000043,1,185000,526000
Brighton and Hove,E06000043,2,270000,610000
Brighton and Hove,E06000043,3,350000,846000
Brighton and Hove,E06000043,4,458000,1487000
Bristol, City of,E06000023,1,145000,417000
Bristol, City of,E06000023,2,184000,562000
Bristol, City of,E06000023,3,242000,685000
Bristol, City of,E06000023,4,331000,1394000
"Bristol, City of",E06000023,1,145000,417000
"Bristol, City of",E06000023,2,184000,562000
"Bristol, City of",E06000023,3,242000,685000
"Bristol, City of",E06000023,4,331000,1394000
Broadland,E07000144,1,126000,334000
Broadland,E07000144,2,140000,334000
Broadland,E07000144,3,225000,433000
@ -459,10 +459,10 @@ Havering,E09000016,1,137000,472000
Havering,E09000016,2,204000,481000
Havering,E09000016,3,336000,657000
Havering,E09000016,4,412000,1232000
Herefordshire, County of,E06000019,1,98000,419000
Herefordshire, County of,E06000019,2,105000,419000
Herefordshire, County of,E06000019,3,162000,499000
Herefordshire, County of,E06000019,4,283000,885000
"Herefordshire, County of",E06000019,1,98000,419000
"Herefordshire, County of",E06000019,2,105000,419000
"Herefordshire, County of",E06000019,3,162000,499000
"Herefordshire, County of",E06000019,4,283000,885000
Hertsmere,E07000098,1,178000,666000
Hertsmere,E07000098,2,316000,666000
Hertsmere,E07000098,3,440000,918000
@ -515,10 +515,10 @@ King's Lynn and West Norfolk,E07000146,1,77000,346000
King's Lynn and West Norfolk,E07000146,2,123000,346000
King's Lynn and West Norfolk,E07000146,3,161000,408000
King's Lynn and West Norfolk,E07000146,4,243000,778000
Kingston upon Hull, City of,E06000010,1,63000,189000
Kingston upon Hull, City of,E06000010,2,67000,189000
Kingston upon Hull, City of,E06000010,3,84000,259000
Kingston upon Hull, City of,E06000010,4,110000,415000
"Kingston upon Hull, City of",E06000010,1,63000,189000
"Kingston upon Hull, City of",E06000010,2,67000,189000
"Kingston upon Hull, City of",E06000010,3,84000,259000
"Kingston upon Hull, City of",E06000010,4,110000,415000
Kingston upon Thames,E09000021,1,156000,649000
Kingston upon Thames,E09000021,2,325000,708000
Kingston upon Thames,E09000021,3,398000,935000

Can't render this file because it has a wrong number of fields in line 90.

5
db/migrate/20230301144555_add_pregblank.rb

@ -0,0 +1,5 @@
class AddPregblank < ActiveRecord::Migration[7.0]
def change
add_column :sales_logs, :pregblank, :integer
end
end

9
db/schema.rb

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_02_15_112932) do
ActiveRecord::Schema[7.0].define(version: 2023_03_01_144555) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -522,15 +522,16 @@ ActiveRecord::Schema[7.0].define(version: 2023_02_15_112932) do
t.integer "income2_value_check"
t.integer "monthly_charges_value_check"
t.integer "value_value_check"
t.integer "saledate_check"
t.integer "details_known_5"
t.integer "details_known_6"
t.integer "saledate_check"
t.integer "prevshared"
t.integer "staircasesale"
t.integer "ethnic_group2"
t.integer "ethnicbuy2"
t.integer "proplen_asked"
t.integer "prevshared"
t.integer "staircasesale"
t.string "old_id"
t.integer "pregblank"
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"
t.index ["old_id"], name: "index_sales_logs_on_old_id", unique: true

1
db/seeds.rb

@ -324,6 +324,5 @@ unless Rails.env.test?
service.call
end
end
puts LaSaleRange.count
end
# rubocop:enable Rails/Output

1
lib/tasks/full_import.rake

@ -18,6 +18,7 @@ namespace :core do
Import.new(Imports::DataProtectionConfirmationImportService, :create_data_protection_confirmations, "dataprotect"),
Import.new(Imports::OrganisationRentPeriodImportService, :create_organisation_rent_periods, "rent-period"),
Import.new(Imports::LettingsLogsImportService, :create_logs, "logs"),
# Import.new(Imports::SalesLogsImportService, :create_logs, "logs"),
]
import_list.each do |step|

35
spec/components/bulk_upload_error_summary_table_component_spec.rb

@ -5,6 +5,10 @@ RSpec.describe BulkUploadErrorSummaryTableComponent, type: :component do
let(:bulk_upload) { create(:bulk_upload) }
before do
stub_const("BulkUploadErrorSummaryTableComponent::DISPLAY_THRESHOLD", 0)
end
context "when no errors" do
it "does not renders any rows" do
result = render_inline(component)
@ -12,6 +16,19 @@ RSpec.describe BulkUploadErrorSummaryTableComponent, type: :component do
end
end
context "when below threshold" do
before do
stub_const("BulkUploadErrorSummaryTableComponent::DISPLAY_THRESHOLD", 16)
create(:bulk_upload_error, bulk_upload:, col: "A", row: 1)
end
it "does not render rows" do
result = render_inline(component)
expect(result).to have_selector("tbody tr", count: 0)
end
end
context "when there are 2 independent errors" do
let!(:error_2) { create(:bulk_upload_error, bulk_upload:, col: "B", row: 2) }
let!(:error_1) { create(:bulk_upload_error, bulk_upload:, col: "A", row: 1) }
@ -78,4 +95,22 @@ RSpec.describe BulkUploadErrorSummaryTableComponent, type: :component do
])
end
end
describe "#errors?" do
context "when there are no errors" do
it "returns false" do
expect(component).not_to be_errors
end
end
context "when there are errors" do
before do
create(:bulk_upload_error, bulk_upload:, col: "A", row: 2, field: "field_1")
end
it "returns true" do
expect(component).to be_errors
end
end
end
end

333
spec/fixtures/imports/logs/shared_ownership_sales_log.xml vendored

@ -0,0 +1,333 @@
<Group xmlns="http://data.gov.uk/core/logs/2022-CORE-Sales" xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:meta="http://data.gov.uk/core/metadata" xmlns:svc="http://www.w3.org/2007/app" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xfimpl="http://www.w3.org/2002/xforms/implementation" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xxf="http://orbeon.org/oxf/xml/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<meta:metadata xmlns:es="http://www.ecmascript.org/" xmlns:xqx="http://www.w3.org/2005/XQueryX" xmlns:XSLT="http://www.w3.org/1999/XSL/Transform/compile">
<meta:form-name>2022-CORE-Sales</meta:form-name>
<meta:document-id>shared_ownership_sales_log</meta:document-id>
<meta:owner-user-id>c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa</meta:owner-user-id>
<meta:owner-institution-id>7c5bd5fb549c09a2c55d7cb90d7ba84927e64618</meta:owner-institution-id>
<meta:managing-institution-id>7c5bd5fb549c09a2c55d7cb90d7ba84927e64618</meta:managing-institution-id>
<meta:created-date>2023-02-21T11:48:28.255968Z</meta:created-date>
<meta:modified-date>2023-02-22T11:00:06.575832Z</meta:modified-date>
<meta:status>submitted-valid</meta:status>
<meta:reporting-year>2022</meta:reporting-year>
<meta:upload-method>Manual Entry</meta:upload-method>
<meta:schema assert-valid="true"/>
<meta:rules assert-valid="true"/>
</meta:metadata>
<Group>
<Qdp>Yes</Qdp>
<CompletionDate>2023-01-17</CompletionDate>
<PurchaserCode>Shared ownership example</PurchaserCode>
<Ownership>1 Yes - a shared ownership scheme</Ownership>
<Q16SaleType>2 Shared Ownership</Q16SaleType>
<Q30SaleType/>
<Q38SaleType/>
<Q38OtherSale/>
<company>2 No</company>
<LiveInBuyer>1 Yes</LiveInBuyer>
<joint>2 No</joint>
<JointMore/>
<PartAPurchaser>2 Yes</PartAPurchaser>
</Group>
<Group>
<Q11Bedrooms override-field="">2</Q11Bedrooms>
<Q12PropertyType>1 Flat or maisonette</Q12PropertyType>
<Q13BuildingType>1 Purpose built</Q13BuildingType>
<Q14Postcode override-field="">SW1A 1AA</Q14Postcode>
<Q14PropertyLocation>Westminster</Q14PropertyLocation>
<Q14ONSLACode>E09000033</Q14ONSLACode>
<Q15Wheelchair>3 Don&#x2019;t know</Q15Wheelchair>
</Group>
<Group>
<P1Age>30</P1Age>
<P1Sex override-field="">Male</P1Sex>
<P1Eco>1 Full Time - 30 hours or more a week</P1Eco>
<P1Eth>2 White: Irish</P1Eth>
<P1Nat>18 United Kingdom</P1Nat>
<P2Age/>
<P2Sex override-field=""/>
<P2Rel/>
<P2Eco/>
<P3Age/>
<P3Sex override-field=""/>
<P3Rel/>
<P3Eco/>
<P4Age/>
<P4Sex override-field=""/>
<P4Rel/>
<P4Eco/>
<P5Age/>
<P5Sex override-field=""/>
<P5Rel/>
<P5Eco/>
<P6Age/>
<P6Sex override-field=""/>
<P6Rel/>
<P6Eco/>
<P7Age/>
<P7Sex override-field=""/>
<P7Rel/>
<P7Eco/>
<P8Age/>
<P8Sex override-field=""/>
<P8Rel/>
<P8Eco/>
<LiveInBuyer1>1 Yes</LiveInBuyer1>
<LiveInBuyer2/>
<LiveInOther/>
</Group>
<Group>
<P2Partner>0</P2Partner>
<P3Partner>0</P3Partner>
<P4Partner>0</P4Partner>
<P5Partner>0</P5Partner>
<P6Partner>0</P6Partner>
<P7Partner>0</P7Partner>
<P8Partner>0</P8Partner>
<Partner>0</Partner>
<P2AgeT>0</P2AgeT>
<P3AgeT>0</P3AgeT>
<P4AgeT>0</P4AgeT>
<P5AgeT>0</P5AgeT>
<P6AgeT>0</P6AgeT>
<P7AgeT>0</P7AgeT>
<P8AgeT>0</P8AgeT>
<P2SexT>0</P2SexT>
<P3SexT>0</P3SexT>
<P4SexT>0</P4SexT>
<P5SexT>0</P5SexT>
<P6SexT>0</P6SexT>
<P7SexT>0</P7SexT>
<P8SexT>0</P8SexT>
<P2RelT>0</P2RelT>
<P3RelT>0</P3RelT>
<P4RelT>0</P4RelT>
<P5RelT>0</P5RelT>
<P6RelT>0</P6RelT>
<P7RelT>0</P7RelT>
<P8RelT>0</P8RelT>
<P2EcoT>0</P2EcoT>
<P3EcoT>0</P3EcoT>
<P4EcoT>0</P4EcoT>
<P5EcoT>0</P5EcoT>
<P6EcoT>0</P6EcoT>
<P7EcoT>0</P7EcoT>
<P8EcoT>0</P8EcoT>
<P2HHoldT>0</P2HHoldT>
<P3HHoldT>0</P3HHoldT>
<P4HHoldT>0</P4HHoldT>
<P5HHoldT>0</P5HHoldT>
<P6HHoldT>0</P6HHoldT>
<P7HHoldT>0</P7HHoldT>
<P8HHoldT>0</P8HHoldT>
<P2PAge>0</P2PAge>
<P3PAge>0</P3PAge>
<P4PAge>0</P4PAge>
<P5PAge>0</P5PAge>
<P6PAge>0</P6PAge>
<P7PAge>0</P7PAge>
<P8PAge>0</P8PAge>
<PAGE/>
<Q30Answer/>
<P2Other>0</P2Other>
<P3Other>0</P3Other>
<P4Other>0</P4Other>
<P5Other>0</P5Other>
<P6Other>0</P6Other>
<P7Other>0</P7Other>
<P8Other>0</P8Other>
<Other>0</Other>
<P2RRefused>0</P2RRefused>
<P3RRefused>0</P3RRefused>
<P4RRefused>0</P4RRefused>
<P5RRefused>0</P5RRefused>
<P6RRefused>0</P6RRefused>
<P7RRefused>0</P7RRefused>
<P8RRefused>0</P8RRefused>
<TotRRefused>0</TotRRefused>
<CALCMORT>76000</CALCMORT>
<MORTGAGEUSED>1</MORTGAGEUSED>
<IM1>47000</IM1>
<IM2>0</IM2>
<IMT>235000</IMT>
<MortMultiple>0</MortMultiple>
<Form>300204</Form>
</Group>
<Group>
<minmaxP11/>
<minmaxP12/>
<minmaxP13/>
<minmaxP14/>
<minmaxP15/>
<minmaxP16/>
<minmaxP17/>
<minmaxP18/>
<minmaxP1T/>
<minmaxP19/>
<minmaxP10/>
<minmaxP21/>
<minmaxP22/>
<minmaxP23/>
<minmaxP24/>
<minmaxP25/>
<minmaxP26/>
<minmaxP27/>
<minmaxP28/>
<minmaxP2T/>
<minmaxP29/>
<minmaxP20/>
<Q16CHK>1</Q16CHK>
<Q30CHK>0</Q30CHK>
<Q38CHK>0</Q38CHK>
<SalesCHKT>1</SalesCHKT>
<Q23CHK>1</Q23CHK>
<Q16typeCHK>2</Q16typeCHK>
<Q16Q23>3</Q16Q23>
<DAY>17</DAY>
<MONTH>1</MONTH>
<YEAR>2023</YEAR>
<HODAY>6</HODAY>
<HOMONTH>9</HOMONTH>
<HOYEAR>2022</HOYEAR>
<EXDAY>8</EXDAY>
<EXMONTH>1</EXMONTH>
<EXYEAR>2023</EXYEAR>
<PPOSTC1>SW14</PPOSTC1>
<PPOSTC2>7QP</PPOSTC2>
<PCODE1>SW1A</PCODE1>
<PCODE2>1AA</PCODE2>
<NOINT/>
</Group>
<Group>
<Q6PrevTenure>2 Private registered provider (PRP) or housing association tenant</Q6PrevTenure>
<Q7Postcode override-field="">SW14 7QP</Q7Postcode>
<Q7UnknownPostcode/>
<Q7PrevLocation>Richmond-upon-Thames</Q7PrevLocation>
<Q7ONSLACode>E09000027</Q7ONSLACode>
<PREGYRHA>Yes</PREGYRHA>
<PREGORHA/>
<PREGLA/>
<PREGHBA/>
<PREGOTHER/>
</Group>
<Group>
<ArmedF>8 Don&#x2019;t know</ArmedF>
<LeftArmedF/>
<ARMEDFORCESSPOUSE/>
<Disability>2 No</Disability>
<Q10Wheelchair override-field="">2 No</Q10Wheelchair>
</Group>
<Group>
<P1IncKnown>1 Yes</P1IncKnown>
<Q2Person1Income>47000</Q2Person1Income>
<Q2Person1Mortgage>1 Yes</Q2Person1Mortgage>
<P2IncKnown/>
<Q2Person2Income/>
<Q2Person2MortApplication/>
<Q2a>4 Don&#x2019;t know</Q2a>
<savingsKnown>1 Yes</savingsKnown>
<Q3Savings override-field="true">89000</Q3Savings>
<Q4PrevOwnedProperty>1 Yes</Q4PrevOwnedProperty>
</Group>
<Group>
<!-- replace with commented options to test in the future -->
<!-- <Q16aProplen2/> -->
<Q16aProplen2>1</Q16aProplen2>
<Q17aStaircase>2 No</Q17aStaircase>
<PercentBought override-field=""/>
<PercentOwns>30</PercentOwns>
<Q17Resale>2 No</Q17Resale>
<Q18ContractExchange override-field="">2023-01-08</Q18ContractExchange>
<Q18PracticalCompletion override-field="">2022-09-06</Q18PracticalCompletion>
<Q19Rehoused>2 No</Q19Rehoused>
<Q20Bedrooms/>
<Q21PropertyType/>
<PrevRentType/>
<Q22PurchasePrice override-field="true">550000</Q22PurchasePrice>
<Q23Equity override-field="">30</Q23Equity>
<MortgageUsedSO>1 Yes</MortgageUsedSO>
<Q24Mortgage override-field="">76000</Q24Mortgage>
<Q24aMortgageLender>Nationwide</Q24aMortgageLender>
<Q24b>33</Q24b>
<Q25Borrowing>2 No</Q25Borrowing>
<Q26CashDeposit override-field="">89000</Q26CashDeposit>
<Q27SocialHomeBuy/>
<Q28MonthlyRent>912.00</Q28MonthlyRent>
<Q29MonthlyCharges>134.24</Q29MonthlyCharges>
</Group>
<Group>
<Q16aProplensec2/>
<Q31PurchasePrice override-field=""/>
<Q32Reductions override-field=""/>
<Q33Discount override-field=""/>
<MortgageUsedDO/>
<Q34Mortgage override-field=""/>
<Q34a/>
<Q34b/>
<Q35Borrowing/>
<Q36CashDeposit/>
<Q37MonthlyCharges/>
</Group>
<Group>
<Q40PurchasePrice override-field=""/>
<MortgageUsedOS/>
<Q41Mortgage override-field=""/>
<Q41aMortgageLender/>
<Q41b/>
<Q42Borrowing/>
<Q43CashDeposit override-field=""/>
</Group>
<Group>
<HHMEMB>1</HHMEMB>
<TOTADULT>1</TOTADULT>
<TOTCHILD>0</TOTCHILD>
</Group>
<Group>
<HHTYPE>3 = 1 adult</HHTYPE>
</Group>
<Group>
<DerSaleType>2 Shared Ownership</DerSaleType>
</Group>
<Group>
<HHTYPEP1A>1</HHTYPEP1A>
<HHTYPEP2A>0</HHTYPEP2A>
<HHTYPEP3A>0</HHTYPEP3A>
<HHTYPEP4A>0</HHTYPEP4A>
<HHTYPEP5A>0</HHTYPEP5A>
<HHTYPEP6A>0</HHTYPEP6A>
<HHTYPEP7A>0</HHTYPEP7A>
<HHTYPEP8A>0</HHTYPEP8A>
<TADULT>1</TADULT>
<HHTYPEP1E>0</HHTYPEP1E>
<HHTYPEP2E>0</HHTYPEP2E>
<HHTYPEP3E>0</HHTYPEP3E>
<HHTYPEP4E>0</HHTYPEP4E>
<HHTYPEP5E>0</HHTYPEP5E>
<HHTYPEP6E>0</HHTYPEP6E>
<HHTYPEP7E>0</HHTYPEP7E>
<HHTYPEP8E>0</HHTYPEP8E>
<TELDER>0</TELDER>
<HHTYPEP1C>0</HHTYPEP1C>
<HHTYPEP2C>0</HHTYPEP2C>
<HHTYPEP3C>0</HHTYPEP3C>
<HHTYPEP4C>0</HHTYPEP4C>
<HHTYPEP5C>0</HHTYPEP5C>
<HHTYPEP6C>0</HHTYPEP6C>
<HHTYPEP7C>0</HHTYPEP7C>
<HHTYPEP8C>0</HHTYPEP8C>
<TCHILD>0</TCHILD>
<Q8av>1</Q8av>
<Q8bv>0</Q8bv>
<Q8cv>0</Q8cv>
<Q8dv>0</Q8dv>
<Q8ev>0</Q8ev>
<Q8Validate>1</Q8Validate>
</Group>
<Group>
<PLOACODE/>
<OACODE/>
<GOVREG>E12000007</GOVREG>
<OWNINGORGID>1</OWNINGORGID>
<OWNINGORGNAME>1 Test</OWNINGORGNAME>
<HCNUM>655</HCNUM>
</Group>
</Group>

2
spec/fixtures/imports/sales_logs/discounted_ownership_sales_log.xml vendored

@ -292,7 +292,7 @@
<Q43CashDeposit override-field=""/>
</Group>
<Group>
<HHMEMB>0</HHMEMB>
<HHMEMB>1</HHMEMB>
<TOTADULT>0</TOTADULT>
<TOTCHILD>0</TOTCHILD>
</Group>

524
spec/fixtures/imports/sales_logs/lettings_log.xml vendored

@ -0,0 +1,524 @@
<Group xmlns="http://data.gov.uk/core/logs/2021-CORE-SR-SH" xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:meta="http://data.gov.uk/core/metadata" xmlns:svc="http://www.w3.org/2007/app" xmlns:xf="http://www.w3.org/2002/xforms" xmlns:xfimpl="http://www.w3.org/2002/xforms/implementation" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xxf="http://orbeon.org/oxf/xml/xforms" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<meta:metadata xmlns:es="http://www.ecmascript.org/" xmlns:xqx="http://www.w3.org/2005/XQueryX" xmlns:XSLT="http://www.w3.org/1999/XSL/Transform/compile">
<meta:form-name>2021-CORE-SR-SH</meta:form-name>
<meta:document-id>lettings_log</meta:document-id>
<meta:owner-user-id>c3061a2e6ea0b702e6f6210d5c52d2a92612d2aa</meta:owner-user-id>
<meta:owner-institution-id>7c5bd5fb549c09z2c55d9cb90d7ba84927e64618</meta:owner-institution-id>
<meta:managing-institution-id>7c5bd5fb549c09z2c55d9cb90d7ba84927e64618</meta:managing-institution-id>
<meta:created-date>2022-01-05T12:50:20.39153Z</meta:created-date>
<meta:modified-date>2022-01-05T12:50:20.39153Z</meta:modified-date>
<meta:status>submitted-valid</meta:status>
<meta:reporting-year>2021</meta:reporting-year>
<meta:upload-method>Manual Entry</meta:upload-method>
<meta:schema assert-valid="true"/>
<meta:rules assert-valid="true"/>
</meta:metadata>
<Group>
<Qdp>Yes</Qdp>
<KeyDate>2021-11-05</KeyDate>
<FORM>123456</FORM>
<Landlord source-value="2">2 Local Authority</Landlord>
<Group>
<_1cmangroupcode>0123</_1cmangroupcode>
<_1cschemecode>10</_1cschemecode>
<schPC/>
<Q1e>3 No</Q1e>
</Group>
</Group>
<Group>
<_2a>2 No</_2a>
<Q2b>1 Secure (inc flexible)</Q2b>
<Q2ba/>
<_2bTenCode>14044912001</_2bTenCode>
<_2cYears>2</_2cYears>
</Group>
<Group>
<P1Age override-field="">72</P1Age>
<P1AR/>
<P1Sex override-field="">Female</P1Sex>
<P1Eco>5) Retired</P1Eco>
<P1Eth>1 White: English/Scottish/Welsh/Northern Irish/British</P1Eth>
<P1Nat>1 UK national resident in UK</P1Nat>
<P2Age override-field="">74</P2Age>
<P2AR/>
<P2Sex override-field="">Male</P2Sex>
<P2Rel>Partner</P2Rel>
<P2Eco>5) Retired</P2Eco>
<P3Age override-field=""/>
<P3AR/>
<P3Sex override-field=""/>
<P3Rel/>
<P3Eco/>
<P4Age override-field=""/>
<P4AR/>
<P4Sex override-field=""/>
<P4Rel/>
<P4Eco/>
<P5Age override-field=""/>
<P5AR/>
<P5Sex override-field=""/>
<P5Rel/>
<P5Eco/>
<P6Age override-field=""/>
<P6AR/>
<P6Sex override-field=""/>
<P6Rel/>
<P6Eco/>
<P7Age override-field=""/>
<P7AR/>
<P7Sex override-field=""/>
<P7Rel/>
<P7Eco/>
<P8Age override-field=""/>
<P8AR/>
<P8Sex override-field=""/>
<P8Rel/>
<P8Eco/>
<Group>
<ArmedF>2 No</ArmedF>
<LeftAF/>
<Inj/>
<Preg override-field="">2 No</Preg>
</Group>
<Group>
<Q6Ben>9 Not in receipt of either UC or HB</Q6Ben>
</Group>
<Group>
<Q7Ben>2 Some</Q7Ben>
<Q8Refused>Refused</Q8Refused>
<Q8Money override-field=""/>
<Q8a/>
</Group>
<Group>
<Q9a>13 Property unsuitable because of ill health / disability</Q9a>
<Q9aa/>
</Group>
<Group>
<_9b override-field="">2 No</_9b>
<Q10-a/>
<Q10-b/>
<Q10-c/>
<Q10-f/>
<Q10-g>Yes</Q10-g>
<Q10-h/>
<Q10ia>1 Yes</Q10ia>
<Q10ib-1/>
<Q10ib-2/>
<Q10ib-3>Yes</Q10ib-3>
<Q10ib-4/>
<Q10ib-5/>
<Q10ib-6/>
<Q10ib-7/>
<Q10ib-8/>
<Q10ib-9/>
<Q10ib-10/>
<Q11 override-field="">26 Owner occupation (private)</Q11>
<Q12a>DLUHC</Q12a>
<Q12aONS>E08000035</Q12aONS>
<Q12b override-field="">S80 4DJ</Q12b>
<Q12bnot/>
<Q12c>5 5 years or more</Q12c>
<Q12d>9 3 years but under 4 years</Q12d>
</Group>
<Group>
<Q13>1 Not homeless</Q13>
<Q14a>2 No</Q14a>
<Q14b1/>
<Q14b2/>
<Q14b3/>
<Q14b4/>
<Q14b5/>
</Group>
<Group>
<Q15CBL>1 Yes</Q15CBL>
<Q15CHR>1 Yes</Q15CHR>
<Q15CAP>1 Yes</Q15CAP>
</Group>
<Group>
<Q16>2 Tenant applied direct (no referral or nomination)</Q16>
</Group>
</Group>
<Group>
<Q17>7 Weekly for 48 weeks</Q17>
<Q18ai override-field="true">125.00</Q18ai>
<Q18aii override-field=""/>
<Q18aiii override-field=""/>
<Q18aiv override-field="">7.00</Q18aiv>
<Q18av override-field="">132.00</Q18av>
<Q18b override-field=""/>
<Q18c/>
<Q18d/>
<Q18dyes override-field=""/>
<Q19void>2021-08-24</Q19void>
<Q19repair/>
<Q19supsch/>
<Q20 override-field="">0</Q20>
<Q21a>14044912</Q21a>
</Group>
<Group>
<Q25>1 Yes</Q25>
<Q27>15 First let of newbuild property</Q27>
</Group>
<Group>
<F1Age>0</F1Age>
<F2Age>0</F2Age>
<F3Age>0</F3Age>
<F4Age>0</F4Age>
<F5Age>0</F5Age>
<F6Age>0</F6Age>
<F7Age>0</F7Age>
<F8Age>0</F8Age>
<FAge>0</FAge>
<F1>1</F1>
<F2>0</F2>
<F3>0</F3>
<F4>0</F4>
<F5>0</F5>
<F6>0</F6>
<F7>0</F7>
<F8>0</F8>
<F>1</F>
<P1100>0</P1100>
<P2100>0</P2100>
<P3100>0</P3100>
<P4100>0</P4100>
<P5100>0</P5100>
<P6100>0</P6100>
<P7100>0</P7100>
<P8100>0</P8100>
<_100>0</_100>
<P170>1</P170>
<P270>1</P270>
<P370>0</P370>
<P470>0</P470>
<P570>0</P570>
<P670>0</P670>
<P770>0</P770>
<P870>0</P870>
<_70>1</_70>
<P1PT>0</P1PT>
<P2PT>0</P2PT>
<P3PT>0</P3PT>
<P4PT>0</P4PT>
<P5PT>0</P5PT>
<P6PT>0</P6PT>
<P7PT>0</P7PT>
<P8PT>0</P8PT>
<PT>0</PT>
<P1FT>0</P1FT>
<P2FT>0</P2FT>
<P3FT>0</P3FT>
<P4FT>0</P4FT>
<P5FT>0</P5FT>
<P6FT>0</P6FT>
<P7FT>0</P7FT>
<P8FT>0</P8FT>
<FT>0</FT>
<P1Stud>0</P1Stud>
<P2Stud>0</P2Stud>
<P3Stud>0</P3Stud>
<P4Stud>0</P4Stud>
<P5Stud>0</P5Stud>
<P6Stud>0</P6Stud>
<P7Stud>0</P7Stud>
<P8Stud>0</P8Stud>
<Stud>0</Stud>
<P2Child>0</P2Child>
<P3Child>0</P3Child>
<P4Child>0</P4Child>
<P5Child>0</P5Child>
<P6Child>0</P6Child>
<P7Child>0</P7Child>
<P8Child>0</P8Child>
<Child>0</Child>
<P2Partner>1</P2Partner>
<P3Partner>0</P3Partner>
<P4Partner>0</P4Partner>
<P5Partner>0</P5Partner>
<P6Partner>0</P6Partner>
<P7Partner>0</P7Partner>
<P8Partner>0</P8Partner>
<Partner>1</Partner>
<Q1cV1>1</Q1cV1>
<Q1cV2>1</Q1cV2>
<Q1cVT>2</Q1cVT>
<P1Adult>1</P1Adult>
<P2Adult>1</P2Adult>
<P3Adult>0</P3Adult>
<P4Adult>0</P4Adult>
<P5Adult>0</P5Adult>
<P6Adult>0</P6Adult>
<P7Adult>0</P7Adult>
<P8Adult>0</P8Adult>
<PAdultT>2</PAdultT>
<P2PAge>74</P2PAge>
<P3PAge>0</P3PAge>
<P4PAge>0</P4PAge>
<P5PAge>0</P5PAge>
<P6PAge>0</P6PAge>
<P7PAge>0</P7PAge>
<P8PAge>0</P8PAge>
<PAGE>74</PAGE>
<P2ChildAge>0</P2ChildAge>
<P3ChildAge>0</P3ChildAge>
<P4ChildAge>0</P4ChildAge>
<P5ChildAge>0</P5ChildAge>
<P6ChildAge>0</P6ChildAge>
<P7ChildAge>0</P7ChildAge>
<P8ChildAge>0</P8ChildAge>
<ChildAgeMin>0</ChildAgeMin>
<AgeDiff1>72</AgeDiff1>
<AgeDiff2>0</AgeDiff2>
<AgeDiff3>74</AgeDiff3>
<TODAY>2022-01-05Z</TODAY>
<FutureLimit>2022-01-20Z</FutureLimit>
<minmax1/>
<minmax2/>
<minmax3/>
<minmax4/>
<minmax5/>
<minmax6/>
<minmax7/>
<minmax8/>
<minmax9/>
<minmax0/>
<minmax10/>
<minmaxT/>
<Q10av>0</Q10av>
<Q10bv>0</Q10bv>
<Q10cv>0</Q10cv>
<Q10fv>0</Q10fv>
<Q10gv>20</Q10gv>
<Q10hv>0</Q10hv>
<Q10Validate>20</Q10Validate>
<Q2bv>A</Q2bv>
<P2Agev>1</P2Agev>
<P2Sexv>1</P2Sexv>
<P2Relv>1</P2Relv>
<P2Ecov>1</P2Ecov>
<P2valid>4</P2valid>
<P3Agev>0</P3Agev>
<P3Sexv>0</P3Sexv>
<P3Relv>0</P3Relv>
<P3Ecov>0</P3Ecov>
<P3valid>0</P3valid>
<P4Agev>0</P4Agev>
<P4Sexv>0</P4Sexv>
<P4Relv>0</P4Relv>
<P4Ecov>0</P4Ecov>
<P4valid>0</P4valid>
<P5Agev>0</P5Agev>
<P5Sexv>0</P5Sexv>
<P5Relv>0</P5Relv>
<P5Ecov>0</P5Ecov>
<P5valid>0</P5valid>
<P6Agev>0</P6Agev>
<P6Sexv>0</P6Sexv>
<P6Relv>0</P6Relv>
<P6Ecov>0</P6Ecov>
<P6valid>0</P6valid>
<P7Agev>0</P7Agev>
<P7Sexv>0</P7Sexv>
<P7Relv>0</P7Relv>
<P7Ecov>0</P7Ecov>
<P7valid>0</P7valid>
<P8Agev>0</P8Agev>
<P8Sexv>0</P8Sexv>
<P8Relv>0</P8Relv>
<P8Ecov>0</P8Ecov>
<P8valid>0</P8valid>
<Q14b1v>0</Q14b1v>
<Q14b2v>0</Q14b2v>
<Q14b3v>0</Q14b3v>
<Q14b4v>0</Q14b4v>
<Q14b5v>0</Q14b5v>
<Q14bv>0</Q14bv>
<P2Other>0</P2Other>
<P3Other>0</P3Other>
<P4Other>0</P4Other>
<P5Other>0</P5Other>
<P6Other>0</P6Other>
<P7Other>0</P7Other>
<P8Other>0</P8Other>
<Other>0</Other>
<P2ARefused>0</P2ARefused>
<P3ARefused>0</P3ARefused>
<P4ARefused>0</P4ARefused>
<P5ARefused>0</P5ARefused>
<P6ARefused>0</P6ARefused>
<P7ARefused>0</P7ARefused>
<P8ARefused>0</P8ARefused>
<TAREUSED>0</TAREUSED>
<P2RRefused>0</P2RRefused>
<P3RRefused>0</P3RRefused>
<P4RRefused>0</P4RRefused>
<P5RRefused>0</P5RRefused>
<P6RRefused>0</P6RRefused>
<P7RRefused>0</P7RRefused>
<P8RRefused>0</P8RRefused>
<TotRRefused>0</TotRRefused>
<TOTREFUSED>0</TOTREFUSED>
</Group>
<Group>
<ChildBen>0.00</ChildBen>
<TOTADULT>2</TOTADULT>
<NEW_OLD>1 New Tenant</NEW_OLD>
<WCHCHRG/>
<VACDAYS>73</VACDAYS>
<HHMEMB>2</HHMEMB>
<HHTYPEP1A>0</HHTYPEP1A>
<HHTYPEP2A>0</HHTYPEP2A>
<HHTYPEP3A>0</HHTYPEP3A>
<HHTYPEP4A>0</HHTYPEP4A>
<HHTYPEP5A>0</HHTYPEP5A>
<HHTYPEP6A>0</HHTYPEP6A>
<HHTYPEP7A>0</HHTYPEP7A>
<HHTYPEP8A>0</HHTYPEP8A>
<TADULT>0</TADULT>
<HHTYPEP1E>1</HHTYPEP1E>
<HHTYPEP2E>1</HHTYPEP2E>
<HHTYPEP3E>0</HHTYPEP3E>
<HHTYPEP4E>0</HHTYPEP4E>
<HHTYPEP5E>0</HHTYPEP5E>
<HHTYPEP6E>0</HHTYPEP6E>
<HHTYPEP7E>0</HHTYPEP7E>
<HHTYPEP8E>0</HHTYPEP8E>
<TELDER>2</TELDER>
<HHTYPEP1C>0</HHTYPEP1C>
<HHTYPEP2C>0</HHTYPEP2C>
<HHTYPEP3C>0</HHTYPEP3C>
<HHTYPEP4C>0</HHTYPEP4C>
<HHTYPEP5C>0</HHTYPEP5C>
<HHTYPEP6C>0</HHTYPEP6C>
<HHTYPEP7C>0</HHTYPEP7C>
<HHTYPEP8C>0</HHTYPEP8C>
<TCHILD>0</TCHILD>
<Q18aValid>1</Q18aValid>
<Q18bValid>0</Q18bValid>
<Q18cValid>0</Q18cValid>
<Q18Valid>1</Q18Valid>
<HHTYPE>2 = 2 Adults at least one is an Elder</HHTYPE>
<WEEKLYINC/>
<INCOME/>
<TYPEHB>15.00</TYPEHB>
<AFFRATE/>
<Weekinc/>
<LETTYPE>2 Local Authority</LETTYPE>
<PLOACODE/>
<OACODE/>
<GOVREG>E12000004</GOVREG>
<OWNINGORGID>1</OWNINGORGID>
<OWNINGORGNAME>DLUHC</OWNINGORGNAME>
<MANINGORGNAME>DLUHC</MANINGORGNAME>
<HCNUM>N/A</HCNUM>
<MANHCNUM>N/A</MANHCNUM>
<LAHA/>
<MANINGORGID>2</MANINGORGID>
<Q28same1>false</Q28same1>
<HBTYPE1/>
<HBTYPE2/>
<HBTYPE3/>
<HBTYPE4/>
<HBTYPE5/>
<HBTYPE6/>
<HBTYPE7/>
<HBTYPE8/>
<HBTYPE9/>
<HBTYPE10/>
<HBTYPE11/>
<HBTYPE12/>
<HBTYPE13/>
<HBTYPE14/>
<HBTYPE15>15</HBTYPE15>
<HBTYPE>15</HBTYPE>
<SCHEME>000001005048</SCHEME>
<MANTYPE>D</MANTYPE>
<UNITS>15</UNITS>
<UNITTYPE>6</UNITTYPE>
<SCHTYPE>7</SCHTYPE>
<REGHOME>1</REGHOME>
<SUPPORT>2</SUPPORT>
<MOBSTAND>A</MOBSTAND>
<INTSTAY>P</INTSTAY>
<CLIGRP1>M</CLIGRP1>
<CLIGRP2/>
<Q28Auth>DLUHC</Q28Auth>
<Q28ONS>E08000035</Q28ONS>
<Q28pc override-field="">S80 4QE</Q28pc>
<Q28same/>
<P1R>0</P1R>
<P2R>0</P2R>
<P3R>0</P3R>
<P4R>0</P4R>
<P5R>0</P5R>
<P6R>0</P6R>
<P7R>0</P7R>
<P8R>0</P8R>
<REFUSEDTOT>0</REFUSEDTOT>
<REFUSED/>
<WTSHORTFALL/>
<WTSHORTFALLHB/>
<WTSHORTFALLHE/>
<WRENT>115.38</WRENT>
<WTCHARGE>121.85</WTCHARGE>
<WSCHARGE/>
<WPSCHRGE/>
<WSUPCHRG>6.46</WSUPCHRG>
<WTSHORTFALL1/>
<WRENT1>115.38</WRENT1>
<WTCHARGE1>121.85</WTCHARGE1>
<WSCHARGE1/>
<WPSCHRGE1/>
<WSUPCHRG1>6.46</WSUPCHRG1>
</Group>
<Group>
<BSa>1</BSa>
<BSb>0</BSb>
<BSc>0</BSc>
<BScm>0</BScm>
<BScf>0</BScf>
<BSd>0</BSd>
<BSdm>0</BSdm>
<BSdf>0</BSdf>
<BSe>0</BSe>
<BSem>0</BSem>
<BSef>0</BSef>
<BSf>0</BSf>
<BSfm>0</BSfm>
<BSff>0</BSff>
<BSfmx>0</BSfmx>
<BSffx>0</BSffx>
<BEDROOMSTAND>1</BEDROOMSTAND>
<BEDMINUSBEDS/>
<WRENTreduced>115.38</WRENTreduced>
<NonDepDeduct>0</NonDepDeduct>
<RENTHB/>
<ChildAllowan>0</ChildAllowan>
<PrsnlAllowan>117.4</PrsnlAllowan>
<HousBenDisAl>10</HousBenDisAl>
<PAIDHB/>
<HCNETAF/>
<ChldAlloCat1>0</ChldAlloCat1>
<ChldAlloCat2>0</ChldAlloCat2>
<P2NnDepDedct>0</P2NnDepDedct>
<P3NnDepDedct>0</P3NnDepDedct>
<P4NnDepDedct>0</P4NnDepDedct>
<P5NnDepDedct>0</P5NnDepDedct>
<P6NnDepDedct>0</P6NnDepDedct>
<P7NnDepDedct>0</P7NnDepDedct>
<P8NnDepDedct>0</P8NnDepDedct>
<DAY>5</DAY>
<MONTH>11</MONTH>
<YEAR>2021</YEAR>
<VDAY>24</VDAY>
<VMONTH>8</VMONTH>
<VYEAR>2021</VYEAR>
<MRCDAY/>
<MRCMONTH/>
<MRCYEAR/>
<PPOSTC1>LS16</PPOSTC1>
<PPOSTC2>6FT</PPOSTC2>
<POSTCODE>LS16</POSTCODE>
<POSTCOD2>6FT</POSTCOD2>
</Group>
</Group>

4
spec/lib/tasks/full_import_spec.rb

@ -22,6 +22,7 @@ describe "rake core:full_import", type: :task do
context "when starting a full import" do
let(:lettings_logs_service) { instance_double(Imports::LettingsLogsImportService) }
let(:sales_logs_service) { instance_double(Imports::SalesLogsImportService) }
let(:rent_period_service) { instance_double(Imports::OrganisationRentPeriodImportService) }
let(:data_protection_service) { instance_double(Imports::DataProtectionConfirmationImportService) }
let(:user_service) { instance_double(Imports::UserImportService) }
@ -37,6 +38,7 @@ describe "rake core:full_import", type: :task do
allow(Imports::DataProtectionConfirmationImportService).to receive(:new).and_return(data_protection_service)
allow(Imports::OrganisationRentPeriodImportService).to receive(:new).and_return(rent_period_service)
allow(Imports::LettingsLogsImportService).to receive(:new).and_return(lettings_logs_service)
allow(Imports::SalesLogsImportService).to receive(:new).and_return(sales_logs_service)
end
it "raises an exception if no parameters are provided" do
@ -54,6 +56,7 @@ describe "rake core:full_import", type: :task do
expect(data_protection_service).to receive(:create_data_protection_confirmations).with("dataprotect")
expect(rent_period_service).to receive(:create_organisation_rent_periods).with("rent-period")
expect(lettings_logs_service).to receive(:create_logs).with("logs")
# expect(sales_logs_service).to receive(:create_logs).with("logs")
task.invoke(fixture_path)
end
@ -73,6 +76,7 @@ describe "rake core:full_import", type: :task do
expect(data_protection_service).to receive(:create_data_protection_confirmations)
expect(rent_period_service).to receive(:create_organisation_rent_periods)
expect(lettings_logs_service).to receive(:create_logs)
# expect(sales_logs_service).to receive(:create_logs)
expect(scheme_service).not_to receive(:create_schemes)
expect(location_service).not_to receive(:create_scheme_locations)

4
spec/mailers/bulk_upload_mailer_spec.rb

@ -93,7 +93,7 @@ RSpec.describe BulkUploadMailer do
year_combo: bulk_upload.year_combo,
lettings_or_sales: bulk_upload.log_type,
error_description: "We noticed that you have a lot of similar errors in column A, B. Please correct your data export and upload again.",
summary_report_link: "http://localhost:3000/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary",
summary_report_link: "http://localhost:3000/lettings-logs/bulk-upload-results/#{bulk_upload.id}",
},
)
@ -103,6 +103,8 @@ RSpec.describe BulkUploadMailer do
context "when 4 columns with errors" do
before do
stub_const("BulkUploadErrorSummaryTableComponent::DISPLAY_THRESHOLD", 0)
create(:bulk_upload_error, bulk_upload:, col: "A")
create(:bulk_upload_error, bulk_upload:, col: "B")
create(:bulk_upload_error, bulk_upload:, col: "C")

4
spec/models/form/sales/pages/buyer1_previous_tenure_spec.rb

@ -1,10 +1,8 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::Buyer1PreviousTenure, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
subject(:page) { described_class.new(nil, nil, subsection) }
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do

40
spec/models/form/sales/pages/number_of_others_in_property_spec.rb

@ -1,10 +1,11 @@
require "rails_helper"
RSpec.describe Form::Sales::Pages::NumberOfOthersInProperty, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) }
subject(:page) { described_class.new(page_id, page_definition, subsection, joint_purchase:) }
let(:page_id) { nil }
let(:page_id) { "number_of_others_in_property" }
let(:page_definition) { nil }
let(:joint_purchase) { false }
let(:subsection) { instance_double(Form::Subsection) }
it "has correct subsection" do
@ -26,4 +27,39 @@ RSpec.describe Form::Sales::Pages::NumberOfOthersInProperty, type: :model do
it "has the correct description" do
expect(page.description).to be_nil
end
it "has the correct depends_on" do
expect(page.depends_on).to eq([
{
"privacynotice" => 1,
"jointpur" => 2,
},
{
"noint" => 1,
"jointpur" => 2,
},
])
end
context "with joint purchase" do
let(:page_id) { "number_of_others_in_property_joint_purchase" }
let(:joint_purchase) { true }
it "has the correct id" do
expect(page.id).to eq("number_of_others_in_property_joint_purchase")
end
it "has the correct depends_on" do
expect(page.depends_on).to eq([
{
"privacynotice" => 1,
"jointpur" => 1,
},
{
"noint" => 1,
"jointpur" => 1,
},
])
end
end
end

4
spec/models/form/sales/pages/shared_ownership_type_spec.rb

@ -5,7 +5,9 @@ RSpec.describe Form::Sales::Pages::SharedOwnershipType, type: :model do
let(:page_id) { nil }
let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) }
let(:start_date) { Time.utc(2022, 4, 1) }
let(:form) { instance_double(Form, start_date:) }
let(:subsection) { instance_double(Form::Subsection, form:) }
it "has correct subsection" do
expect(page.subsection).to eq(subsection)

13
spec/models/form/sales/questions/buyer1_mortgage_spec.rb

@ -6,6 +6,7 @@ RSpec.describe Form::Sales::Questions::Buyer1Mortgage, type: :model do
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:log) { create(:sales_log) }
it "has correct page" do
expect(question.page).to eq(page)
@ -16,11 +17,11 @@ RSpec.describe Form::Sales::Questions::Buyer1Mortgage, type: :model do
end
it "has the correct header" do
expect(question.header).to eq("Was buyer 1's income used for a mortgage application?")
expect(question.header).to eq("Was buyer 1s income used for a mortgage application?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Buyer 1's income used for mortgage application")
expect(question.check_answer_label).to eq("Buyer 1s income used for mortgage application")
end
it "has the correct type" do
@ -35,6 +36,14 @@ RSpec.describe Form::Sales::Questions::Buyer1Mortgage, type: :model do
expect(question.answer_options).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
})
end
it "has the correct displayed_answer_options" do
expect(question.displayed_answer_options(log)).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
})
end

10
spec/models/form/sales/questions/buyer1_previous_tenure_spec.rb

@ -1,11 +1,10 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::Buyer1PreviousTenure, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
subject(:question) { described_class.new(nil, nil, page) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:log) { create(:sales_log) }
it "has correct page" do
expect(question.page).to eq(page)
@ -16,11 +15,11 @@ RSpec.describe Form::Sales::Questions::Buyer1PreviousTenure, type: :model do
end
it "has the correct header" do
expect(question.header).to eq("What was buyer 1's previous tenure?")
expect(question.header).to eq("What was buyer 1s previous tenure?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Buyer 1's previous tenure")
expect(question.check_answer_label).to eq("Buyer 1s previous tenure")
end
it "has the correct type" do
@ -41,6 +40,7 @@ RSpec.describe Form::Sales::Questions::Buyer1PreviousTenure, type: :model do
"6" => { "value" => "Living with family or friends" },
"7" => { "value" => "Temporary accomodation" },
"9" => { "value" => "Other" },
"0" => { "value" => "Don’t know" },
})
end
end

13
spec/models/form/sales/questions/buyer2_mortgage_spec.rb

@ -6,6 +6,7 @@ RSpec.describe Form::Sales::Questions::Buyer2Mortgage, type: :model do
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:log) { create(:sales_log) }
it "has correct page" do
expect(question.page).to eq(page)
@ -16,11 +17,11 @@ RSpec.describe Form::Sales::Questions::Buyer2Mortgage, type: :model do
end
it "has the correct header" do
expect(question.header).to eq("Was buyer 2's income used for a mortgage application?")
expect(question.header).to eq("Was buyer 2s income used for a mortgage application?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Buyer 2's income used for mortgage application")
expect(question.check_answer_label).to eq("Buyer 2s income used for mortgage application")
end
it "has the correct type" do
@ -35,6 +36,14 @@ RSpec.describe Form::Sales::Questions::Buyer2Mortgage, type: :model do
expect(question.answer_options).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
})
end
it "has the correct displayed_answer_options" do
expect(question.displayed_answer_options(log)).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
})
end

12
spec/models/form/sales/questions/buyers_organisations_spec.rb

@ -41,6 +41,18 @@ RSpec.describe Form::Sales::Questions::BuyersOrganisations, type: :model do
it "has the correct answer_options" do
expect(question.answer_options).to eq(
{
"pregyrha" => { "value" => "Their private registered provider (PRP) - housing association" },
"pregother" => { "value" => "Other private registered provider (PRP) - housing association" },
"pregla" => { "value" => "Local Authority" },
"pregghb" => { "value" => "Help to Buy Agent" },
"pregblank" => { "value" => "None of the above" },
},
)
end
it "has the correct displayed_answer_options" do
expect(question.displayed_answer_options(FactoryBot.create(:sales_log))).to eq(
{
"pregyrha" => { "value" => "Their private registered provider (PRP) - housing association" },
"pregother" => { "value" => "Other private registered provider (PRP) - housing association" },

9
spec/models/form/sales/questions/mortgageused_spec.rb

@ -6,6 +6,7 @@ RSpec.describe Form::Sales::Questions::Mortgageused, type: :model do
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:log) { create(:sales_log) }
it "has correct page" do
expect(question.page).to eq(page)
@ -35,6 +36,7 @@ RSpec.describe Form::Sales::Questions::Mortgageused, type: :model do
expect(question.answer_options).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
"3" => { "value" => "Don’t know" },
})
end
@ -45,4 +47,11 @@ RSpec.describe Form::Sales::Questions::Mortgageused, type: :model do
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
it "has the correct displayed_answer_options" do
expect(question.displayed_answer_options(log)).to eq({
"1" => { "value" => "Yes" },
"2" => { "value" => "No" },
})
end
end

25
spec/models/form/sales/questions/number_of_others_in_property_spec.rb

@ -1,11 +1,12 @@
require "rails_helper"
RSpec.describe Form::Sales::Questions::NumberOfOthersInProperty, type: :model do
subject(:question) { described_class.new(question_id, question_definition, page) }
subject(:question) { described_class.new(question_id, question_definition, page, joint_purchase:) }
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:joint_purchase) { true }
it "has correct page" do
expect(question.page).to eq(page)
@ -32,6 +33,26 @@ RSpec.describe Form::Sales::Questions::NumberOfOthersInProperty, type: :model do
end
it "has the correct hint" do
expect(question.hint_text).to eq("You can provide details for a maximum of 4 other people.")
expect(question.hint_text).to eq("You can provide details for a maximum of 4 other people for a joint purchase.")
end
it "has the correct min" do
expect(question.min).to eq(0)
end
it "has the correct max" do
expect(question.max).to eq(4)
end
context "with non joint purchase" do
let(:joint_purchase) { false }
it "has the correct hint" do
expect(question.hint_text).to eq("You can provide details for a maximum of 5 other people if there is only one buyer.")
end
it "has the correct max" do
expect(question.max).to eq(5)
end
end
end

44
spec/models/form/sales/questions/shared_ownership_type_spec.rb

@ -5,7 +5,10 @@ RSpec.describe Form::Sales::Questions::SharedOwnershipType, type: :model do
let(:question_id) { nil }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:start_date) { Time.utc(2022, 4, 1) }
let(:form) { instance_double(Form, start_date:) }
let(:subsection) { instance_double(Form::Subsection, form:) }
let(:page) { instance_double(Form::Page, subsection:) }
it "has correct page" do
expect(question.page).to eq(page)
@ -35,15 +38,34 @@ RSpec.describe Form::Sales::Questions::SharedOwnershipType, type: :model do
expect(question.hint_text).to eq("A shared ownership sale is when the purchaser buys up to 75% of the property value and pays rent to the Private Registered Provider (PRP) on the remaining portion")
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Shared Ownership" },
"24" => { "value" => "Old Persons Shared Ownership" },
"18" => { "value" => "Social HomeBuy (shared ownership purchase)" },
"16" => { "value" => "Home Ownership for people with Long Term Disabilities (HOLD)" },
"28" => { "value" => "Rent to Buy - Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership" },
"30" => { "value" => "Shared Ownership - 2021 model lease" },
})
context "when form start date is 2022" do
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Shared Ownership" },
"24" => { "value" => "Old Persons Shared Ownership" },
"18" => { "value" => "Social HomeBuy (shared ownership purchase)" },
"16" => { "value" => "Home Ownership for people with Long-Term Disabilities (HOLD)" },
"28" => { "value" => "Rent to Buy - Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership" },
"30" => { "value" => "Shared Ownership - 2021 model lease" },
})
end
end
context "when form start date is 2023" do
let(:start_date) { Time.utc(2023, 4, 2) }
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"2" => { "value" => "Shared Ownership (old model lease)" },
"30" => { "value" => "Shared Ownership (new model lease)" },
"18" => { "value" => "Social HomeBuy — shared ownership purchase" },
"16" => { "value" => "Home Ownership for people with Long-Term Disabilities (HOLD)" },
"24" => { "value" => "Older Persons Shared Ownership" },
"28" => { "value" => "Rent to Buy — Shared Ownership" },
"31" => { "value" => "Right to Shared Ownership (RtSO)" },
"32" => { "value" => "London Living Rent — Shared Ownership" },
})
end
end
end

18
spec/models/form/sales/subsections/household_characteristics_spec.rb

@ -50,6 +50,7 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
working_situation_buyer_2_income_value_check
buyer_2_live_in_property
number_of_others_in_property
number_of_others_in_property_joint_purchase
person_2_known
person_2_relationship_to_buyer_1
person_2_age
@ -82,6 +83,14 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
gender_5_retirement_value_check
person_5_working_situation
working_situation_5_retirement_value_check
person_6_known
person_6_relationship_to_buyer_1
person_6_age
age_6_retirement_value_check
person_6_gender_identity
gender_6_retirement_value_check
person_6_working_situation
working_situation_6_retirement_value_check
],
)
end
@ -131,6 +140,7 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
working_situation_buyer_2_income_value_check
buyer_2_live_in_property
number_of_others_in_property
number_of_others_in_property_joint_purchase
person_2_known
person_2_relationship_to_buyer_1
person_2_age
@ -163,6 +173,14 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model
gender_5_retirement_value_check
person_5_working_situation
working_situation_5_retirement_value_check
person_6_known
person_6_relationship_to_buyer_1
person_6_age
age_6_retirement_value_check
person_6_gender_identity
gender_6_retirement_value_check
person_6_working_situation
working_situation_6_retirement_value_check
],
)
end

30
spec/models/sales_log_spec.rb

@ -90,6 +90,30 @@ RSpec.describe SalesLog, type: :model do
expect(completed_sales_log.not_started?).to be(false)
expect(completed_sales_log.completed?).to be(true)
end
context "when proplen is not given" do
before do
Timecop.freeze(Time.zone.local(2023, 5, 1))
end
after do
Timecop.unfreeze
end
it "is set to completed for a log with a saledate before 23/24" do
completed_sales_log.update!(proplen: nil, saledate: Time.zone.local(2022, 5, 1))
expect(completed_sales_log.in_progress?).to be(false)
expect(completed_sales_log.not_started?).to be(false)
expect(completed_sales_log.completed?).to be(true)
end
it "is set to in_progress for a log with a saledate after 23/24" do
completed_sales_log.update!(proplen: nil, saledate: Time.zone.local(2023, 5, 1))
expect(completed_sales_log.in_progress?).to be(true)
expect(completed_sales_log.not_started?).to be(false)
expect(completed_sales_log.completed?).to be(false)
end
end
end
context "when filtering by organisation" do
@ -283,6 +307,12 @@ RSpec.describe SalesLog, type: :model do
expect(record_from_db["hhmemb"]).to eq(6)
end
it "correctly derives and saves hhmemb if it's a joint purchase" do
sales_log.update!(jointpur: 2, jointmore: 2)
record_from_db = ActiveRecord::Base.connection.execute("select hhmemb from sales_logs where id=#{sales_log.id}").to_a[0]
expect(record_from_db["hhmemb"]).to eq(5)
end
it "correctly derives and saves totchild" do
record_from_db = ActiveRecord::Base.connection.execute("select totchild from sales_logs where id=#{sales_log.id}").to_a[0]
expect(record_from_db["totchild"]).to eq(2)

2
spec/models/validations/financial_validations_spec.rb

@ -990,7 +990,7 @@ RSpec.describe Validations::FinancialValidations do
end
context "and charges are not provided" do
it "throws and error" do
xit "throws and error" do
record.period = 3
record.chcharge = nil
financial_validator.validate_care_home_charges(record)

110
spec/services/imports/lettings_logs_import_service_spec.rb

@ -47,11 +47,12 @@ RSpec.describe Imports::LettingsLogsImportService do
let(:lettings_log_id2) { "166fc004-392e-47a8-acb8-1c018734882b" }
let(:lettings_log_id3) { "00d2343e-d5fa-4c89-8400-ec3854b0f2b4" }
let(:lettings_log_id4) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
let(:sales_log) { "shared_ownership_sales_log" }
before do
# Stub the S3 file listing and download
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/#{lettings_log_id}.xml #{remote_folder}/#{lettings_log_id2}.xml #{remote_folder}/#{lettings_log_id3}.xml #{remote_folder}/#{lettings_log_id4}.xml])
.and_return(%W[#{remote_folder}/#{lettings_log_id}.xml #{remote_folder}/#{lettings_log_id2}.xml #{remote_folder}/#{lettings_log_id3}.xml #{remote_folder}/#{lettings_log_id4}.xml #{remote_folder}/#{sales_log}.xml])
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id}.xml")
.and_return(open_file(fixture_directory, lettings_log_id), open_file(fixture_directory, lettings_log_id))
@ -64,6 +65,9 @@ RSpec.describe Imports::LettingsLogsImportService do
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{lettings_log_id4}.xml")
.and_return(open_file(fixture_directory, lettings_log_id4), open_file(fixture_directory, lettings_log_id4))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/#{sales_log}.xml")
.and_return(open_file(fixture_directory, sales_log), open_file(fixture_directory, sales_log))
end
it "successfully create all lettings logs" do
@ -205,6 +209,110 @@ RSpec.describe Imports::LettingsLogsImportService do
end
end
context "and it has zero earnings" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q8Money").content = 0
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Where the income is 0, set earnings and income to blank and set incref to refused/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.earnings).to be_nil
expect(lettings_log.incref).to eq(1)
expect(lettings_log.net_income_known).to eq(2)
end
end
context "and an invalid tenancy length for tenancy type" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_2cYears").content = "1"
lettings_log_xml.at_xpath("//xmlns:Q2b").content = "4"
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing tenancylength as invalid/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.tenancylength).to be_nil
expect(lettings_log.tenancy).to be_nil
end
end
context "and an lead tenant must be under 20 if childrens home or foster care" do
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:Q11").content = "13"
lettings_log_xml.at_xpath("//xmlns:P1Age").content = "22"
end
it "intercepts the relevant validation error" do
expect(logger).to receive(:warn).with(/Removing age1 and prevten as incompatible/)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.age1).to be_nil
expect(lettings_log.prevten).to be_nil
end
end
context "and is a carehome but missing carehome charge" do
let(:lettings_log_id) { "0b4a68df-30cc-474a-93c0-a56ce8fdad3b" }
before do
lettings_log_xml.at_xpath("//meta:status").content = "submitted"
lettings_log_xml.at_xpath("//xmlns:_1cmangroupcode").content = scheme2.old_visible_id
scheme2.update!(registered_under_care_act: 2)
lettings_log_xml.at_xpath("//xmlns:Q18b").content = ""
end
it "intercepts the relevant validation error" do
allow(logger).to receive(:warn)
expect { lettings_log_service.send(:create_log, lettings_log_xml) }
.not_to raise_error
end
it "clears out the invalid answers" do
allow(logger).to receive(:warn)
lettings_log_service.send(:create_log, lettings_log_xml)
lettings_log = LettingsLog.find_by(old_id: lettings_log_id)
expect(lettings_log).not_to be_nil
expect(lettings_log.is_carehome).to be_truthy
expect(lettings_log.chcharge).to be_nil
end
end
context "and this is an internal transfer from a non social housing" do
before do
lettings_log_xml.at_xpath("//xmlns:Q11").content = "9 Residential care home"

199
spec/services/imports/sales_logs_import_service_spec.rb

@ -38,7 +38,7 @@ RSpec.describe Imports::SalesLogsImportService do
before do
# Stub the S3 file listing and download
allow(storage_service).to receive(:list_files)
.and_return(%W[#{remote_folder}/shared_ownership_sales_log.xml #{remote_folder}/shared_ownership_sales_log2.xml #{remote_folder}/outright_sale_sales_log.xml #{remote_folder}/discounted_ownership_sales_log.xml])
.and_return(%W[#{remote_folder}/shared_ownership_sales_log.xml #{remote_folder}/shared_ownership_sales_log2.xml #{remote_folder}/outright_sale_sales_log.xml #{remote_folder}/discounted_ownership_sales_log.xml #{remote_folder}/lettings_log.xml])
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/shared_ownership_sales_log.xml")
.and_return(open_file(fixture_directory, "shared_ownership_sales_log"), open_file(fixture_directory, "shared_ownership_sales_log"))
@ -51,6 +51,9 @@ RSpec.describe Imports::SalesLogsImportService do
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/discounted_ownership_sales_log.xml")
.and_return(open_file(fixture_directory, "discounted_ownership_sales_log"), open_file(fixture_directory, "discounted_ownership_sales_log"))
allow(storage_service).to receive(:get_file_io)
.with("#{remote_folder}/lettings_log.xml")
.and_return(open_file(fixture_directory, "lettings_log"), open_file(fixture_directory, "lettings_log"))
end
it "successfully creates all sales logs" do
@ -540,40 +543,216 @@ RSpec.describe Imports::SalesLogsImportService do
allow(logger).to receive(:warn).and_return(nil)
end
it "sets hholdcount to hhmemb - 1 if not answered and not joint purchase" do
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = "3"
it "sets hholdcount to last person the information is given for if HHMEMB is not set" do
sales_log_xml.at_xpath("//xmlns:joint").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInOther").content = ""
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = ""
sales_log_xml.at_xpath("//xmlns:P2Age").content = "20"
sales_log_xml.at_xpath("//xmlns:P3Sex").content = "R"
sales_log_xml.at_xpath("//xmlns:P4Age").content = "23"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.hholdcount).to eq(2)
expect(sales_log&.hholdcount).to eq(3)
end
it "sets hholdcount to hhmemb - 2 if not answered and joint purchase" do
it "sets hholdcount to last person the information is given for - buyers if HHMEMB is 0" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = "3"
sales_log_xml.at_xpath("//xmlns:LiveInOther").content = ""
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = ""
sales_log_xml.at_xpath("//xmlns:P2Age").content = "20"
sales_log_xml.at_xpath("//xmlns:P3Sex").content = "R"
sales_log_xml.at_xpath("//xmlns:P4Age").content = "23"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.hholdcount).to eq(1)
expect(sales_log&.hholdcount).to eq(2)
end
it "sets hholdcount to 0 if HHMEMB is 0" do
it "sets hholdcount to 0 no information for people is given and HHMEMB is not set" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = ""
sales_log_xml.at_xpath("//xmlns:LiveInOther").content = ""
sales_log_xml.at_xpath("//xmlns:P2Age").content = ""
sales_log_xml.at_xpath("//xmlns:P2Sex").content = ""
sales_log_xml.at_xpath("//xmlns:P3Age").content = ""
sales_log_xml.at_xpath("//xmlns:P3Sex").content = ""
sales_log_xml.at_xpath("//xmlns:P4Age").content = ""
sales_log_xml.at_xpath("//xmlns:P4Sex").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.hholdcount).to eq(0)
end
it "sets hholdcount to the 0 if no information for people is given and HHMEMB is 0" do
sales_log_xml.at_xpath("//xmlns:joint").content = "2 No"
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = "0"
sales_log_xml.at_xpath("//xmlns:LiveInOther").content = ""
sales_log_xml.at_xpath("//xmlns:P2Age").content = ""
sales_log_xml.at_xpath("//xmlns:P2Sex").content = ""
sales_log_xml.at_xpath("//xmlns:P3Age").content = ""
sales_log_xml.at_xpath("//xmlns:P3Sex").content = ""
sales_log_xml.at_xpath("//xmlns:P4Age").content = ""
sales_log_xml.at_xpath("//xmlns:P4Sex").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.hholdcount).to eq(0)
end
it "doesn't hang if jointpur is not given" do
sales_log_xml.at_xpath("//xmlns:joint").content = ""
sales_log_xml.at_xpath("//xmlns:HHMEMB").content = "0"
sales_log_service.send(:create_log, sales_log_xml)
end
end
context "when inferring income used" do
let(:sales_log_id) { "discounted_ownership_sales_log" }
before do
allow(logger).to receive(:warn).and_return(nil)
end
it "sets inc1mort and inc2mort to don't know if not answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:Q2Person1Mortgage").content = ""
sales_log_xml.at_xpath("//xmlns:Q2Person2MortApplication").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.inc1mort).to eq(3)
expect(sales_log&.inc2mort).to eq(3)
end
it "sets inc1mort and inc2mort correctly if answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:Q2Person1Mortgage").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:Q2Person2MortApplication").content = "2 No"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.inc1mort).to eq(1)
expect(sales_log&.inc2mort).to eq(2)
end
end
context "when inferring buyer organisation" do
let(:sales_log_id) { "discounted_ownership_sales_log" }
before do
allow(logger).to receive(:warn).and_return(nil)
end
it "sets pregblank to true if no other organisations are selected" do
sales_log_xml.at_xpath("//xmlns:PREGYRHA").content = ""
sales_log_xml.at_xpath("//xmlns:PREGLA").content = ""
sales_log_xml.at_xpath("//xmlns:PREGHBA").content = ""
sales_log_xml.at_xpath("//xmlns:PREGOTHER").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.pregyrha).to eq(nil)
expect(sales_log&.pregla).to eq(nil)
expect(sales_log&.pregghb).to eq(nil)
expect(sales_log&.pregother).to eq(nil)
expect(sales_log&.pregblank).to eq(1)
end
it "sets pregblank and other organisation fields correctly if answered" do
sales_log_xml.at_xpath("//xmlns:PREGYRHA").content = "Yes"
sales_log_xml.at_xpath("//xmlns:PREGLA").content = "Yes"
sales_log_xml.at_xpath("//xmlns:PREGHBA").content = "Yes"
sales_log_xml.at_xpath("//xmlns:PREGOTHER").content = "Yes"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.pregyrha).to eq(1)
expect(sales_log&.pregla).to eq(1)
expect(sales_log&.pregghb).to eq(1)
expect(sales_log&.pregother).to eq(1)
expect(sales_log&.pregblank).to eq(nil)
end
end
context "when setting default buyer 2 live in for discounted ownership" do
let(:sales_log_id) { "discounted_ownership_sales_log" }
before do
allow(logger).to receive(:warn).and_return(nil)
end
it "sets buy2livein to true if it is joint purchase and it's not answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInBuyer2").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.buy2livein).to eq(1)
end
it "sets buy2livein correctly if it's answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInBuyer2").content = "1 Yes"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.buy2livein).to eq(1)
end
end
context "when setting default buyer 2 live in for shared ownership" do
let(:sales_log_id) { "shared_ownership_sales_log" }
before do
allow(logger).to receive(:warn).and_return(nil)
end
it "sets buy2livein to true if it is joint purchase and it's not answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInBuyer2").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.buy2livein).to eq(1)
end
it "sets buy2livein correctly if it's answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInBuyer2").content = "2 No"
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.buy2livein).to eq(2)
end
end
context "when setting default buyer 2 live in for outright sale" do
let(:sales_log_id) { "outright_sale_sales_log" }
before do
allow(logger).to receive(:warn).and_return(nil)
end
it "does not set buy2livein if it is joint purchase and it's not answered" do
sales_log_xml.at_xpath("//xmlns:joint").content = "1 Yes"
sales_log_xml.at_xpath("//xmlns:JointMore").content = "2 No"
sales_log_xml.at_xpath("//xmlns:LiveInBuyer2").content = ""
sales_log_service.send(:create_log, sales_log_xml)
sales_log = SalesLog.find_by(old_id: sales_log_id)
expect(sales_log&.buy2livein).to eq(nil)
end
end
end
end

Loading…
Cancel
Save