From 999a33e0f7dd43e859d370ca2bb1aa7095c8998a Mon Sep 17 00:00:00 2001
From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>
Date: Wed, 20 Mar 2024 14:43:23 +0000
Subject: [PATCH 1/4] CLDC-3313 Update financial sale validations (#2313)
* Rename method
* Update staircase/non staircase validations
* Add errors to type
* Remove validate_shared_ownership_deposit
* Don't add setup BU errors, deduplicate different sale type errors
* Add tolerance
* Reuse method
* Rename methods
* Skip type error completely in BU
* Update validation messages
* Update over tolerance method
---
.../pages/about_deposit_with_discount.rb | 4 +-
.../pages/about_deposit_without_discount.rb | 4 +-
app/models/sales_log.rb | 9 +-
.../sales/financial_validations.rb | 17 --
.../sales/sale_information_validations.rb | 102 +++++--
.../validations/sales/soft_validations.rb | 10 +-
.../bulk_upload/sales/year2024/row_parser.rb | 102 +++++--
config/locales/en.yml | 12 +-
.../pages/about_deposit_with_discount_spec.rb | 8 +-
.../about_deposit_without_discount_spec.rb | 8 +-
.../sales/financial_validations_spec.rb | 175 ------------
.../sale_information_validations_spec.rb | 254 ++++++++++++++++--
.../sales/year2024/row_parser_spec.rb | 26 ++
13 files changed, 465 insertions(+), 266 deletions(-)
diff --git a/app/models/form/sales/pages/about_deposit_with_discount.rb b/app/models/form/sales/pages/about_deposit_with_discount.rb
index 5d1e41a95..4f1eed451 100644
--- a/app/models/form/sales/pages/about_deposit_with_discount.rb
+++ b/app/models/form/sales/pages/about_deposit_with_discount.rb
@@ -14,9 +14,9 @@ class Form::Sales::Pages::AboutDepositWithDiscount < ::Form::Page
def depends_on
if form.start_year_after_2024?
- [{ "is_type_discount?" => true, "stairowned_100?" => @optional }]
+ [{ "social_homebuy?" => true, "stairowned_100?" => @optional }]
else
- [{ "is_type_discount?" => true }]
+ [{ "social_homebuy?" => true }]
end
end
end
diff --git a/app/models/form/sales/pages/about_deposit_without_discount.rb b/app/models/form/sales/pages/about_deposit_without_discount.rb
index fdd74cf31..5747c3ed4 100644
--- a/app/models/form/sales/pages/about_deposit_without_discount.rb
+++ b/app/models/form/sales/pages/about_deposit_without_discount.rb
@@ -14,11 +14,11 @@ class Form::Sales::Pages::AboutDepositWithoutDiscount < ::Form::Page
def depends_on
if form.start_year_after_2024?
- [{ "is_type_discount?" => false, "ownershipsch" => 1, "stairowned_100?" => @optional },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1, "stairowned_100?" => @optional },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }]
else
- [{ "is_type_discount?" => false, "ownershipsch" => 1 },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1 },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }]
end
diff --git a/app/models/sales_log.rb b/app/models/sales_log.rb
index f35393a51..5223c249b 100644
--- a/app/models/sales_log.rb
+++ b/app/models/sales_log.rb
@@ -239,7 +239,7 @@ class SalesLog < Log
ownershipsch == 3 || (ownershipsch == 2 && rent_to_buy_full_ownership?)
end
- def is_type_discount?
+ def social_homebuy?
type == 18
end
@@ -287,6 +287,13 @@ class SalesLog < Log
mortgage_amount + deposit_amount + cashdis_amount
end
+ def deposit_and_discount_total
+ deposit_amount = deposit || 0
+ cashdis_amount = cashdis || 0
+
+ deposit_amount + cashdis_amount
+ end
+
def value_times_equity
return unless value && equity
diff --git a/app/models/validations/sales/financial_validations.rb b/app/models/validations/sales/financial_validations.rb
index 6b36091ac..3e1d3dfb8 100644
--- a/app/models/validations/sales/financial_validations.rb
+++ b/app/models/validations/sales/financial_validations.rb
@@ -102,23 +102,6 @@ module Validations::Sales::FinancialValidations
end
end
- def validate_shared_ownership_deposit(record)
- return unless record.saledate && record.form.start_year_after_2024?
- return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3
- return unless record.cashdis && record.deposit && record.value && record.equity
-
- mortgage_value = record.mortgage || 0
-
- if mortgage_value + record.deposit + record.cashdis != record.value * record.equity / 100
- %i[mortgage value deposit ownershipsch cashdis equity].each do |field|
- record.errors.add field, I18n.t("validations.financial.shared_ownership_deposit",
- mortgage_deposit_and_discount_error_fields: record.mortgage_deposit_and_discount_error_fields,
- mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"),
- value_times_equity: record.field_formatted_as_currency("value_times_equity"))
- end
- end
- end
-
def validate_equity_less_than_staircase_difference(record)
return unless record.equity && record.stairbought && record.stairowned
return unless record.saledate && record.form.start_year_after_2024?
diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb
index 883e10d1d..81054e830 100644
--- a/app/models/validations/sales/sale_information_validations.rb
+++ b/app/models/validations/sales/sale_information_validations.rb
@@ -107,53 +107,115 @@ module Validations::Sales::SaleInformationValidations
end
def validate_non_staircasing_mortgage(record)
+ return unless record.saledate && record.form.start_year_after_2024?
return unless record.value && record.deposit && record.equity
- return unless record.is_not_staircasing?
+ return unless record.shared_ownership_scheme? && record.type && record.mortgageused && record.is_not_staircasing?
+
+ if record.social_homebuy?
+ check_non_staircasing_socialhomebuy_mortgage(record)
+ else
+ check_non_staircasing_non_socialhomebuy_mortgage(record)
+ end
+ end
+
+ def validate_staircasing_mortgage(record)
return unless record.saledate && record.form.start_year_after_2024?
+ return unless record.value && record.deposit && record.stairbought
+ return unless record.shared_ownership_scheme? && record.type && record.mortgageused && record.is_staircase?
+
+ if record.social_homebuy?
+ check_staircasing_socialhomebuy_mortgage(record)
+ else
+ check_staircasing_non_socialhomebuy_mortgage(record)
+ end
+ end
+
+ def validate_mortgage_used_and_stairbought(record)
+ return unless record.stairowned && record.mortgageused
+
+ if !record.stairowned_100? && record.mortgageused == 3
+ record.errors.add :stairowned, I18n.t("validations.sale_information.stairowned.mortgageused_dont_know")
+ record.errors.add :mortgageused, I18n.t("validations.sale_information.stairowned.mortgageused_dont_know")
+ end
+ end
+
+ def check_non_staircasing_socialhomebuy_mortgage(record)
+ return unless record.cashdis
+
+ if record.mortgage_used?
+ return unless record.mortgage
+
+ if over_tolerance?(record.mortgage_deposit_and_discount_total, record.expected_shared_ownership_deposit_value, 1)
+ %i[mortgage value deposit cashdis equity].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_used_socialhomebuy", mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
+ end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_used_socialhomebuy", mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
+ end
+ elsif record.mortgage_not_used?
+ if over_tolerance?(record.deposit_and_discount_total, record.expected_shared_ownership_deposit_value, 1)
+ %i[mortgageused value deposit cashdis equity].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_not_used_socialhomebuy", deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
+ end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_not_used_socialhomebuy", deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
+ end
+ end
+ end
+ def check_non_staircasing_non_socialhomebuy_mortgage(record)
if record.mortgage_used?
return unless record.mortgage
- if record.mortgage_and_deposit_total != record.expected_shared_ownership_deposit_value
+ if over_tolerance?(record.mortgage_and_deposit_total, record.expected_shared_ownership_deposit_value, 1)
%i[mortgage value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_used", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_used", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
end
elsif record.mortgage_not_used?
- if record.deposit != record.expected_shared_ownership_deposit_value
+ if over_tolerance?(record.deposit, record.expected_shared_ownership_deposit_value, 1)
%i[mortgageused value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_not_used", deposit: record.field_formatted_as_currency("deposit"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.non_staircasing_mortgage.mortgage_not_used", deposit: record.field_formatted_as_currency("deposit"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
end
end
end
- def validate_staircasing_mortgage(record)
- return unless record.mortgageused && record.value && record.deposit && record.stairbought
- return unless record.is_staircase?
- return unless record.saledate && record.form.start_year_after_2024?
+ def check_staircasing_socialhomebuy_mortgage(record)
+ return unless record.cashdis
if record.mortgage_used?
return unless record.mortgage
- if record.mortgage_and_deposit_total != record.stairbought_part_of_value
- %i[mortgage value deposit stairbought].each do |field|
- record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_used", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
+ if over_tolerance?(record.mortgage_deposit_and_discount_total, record.stairbought_part_of_value, 1)
+ %i[mortgage value deposit cashdis stairbought].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_used_socialhomebuy", mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.staircasing_mortgage.mortgage_used_socialhomebuy", mortgage_deposit_and_discount_total: record.field_formatted_as_currency("mortgage_deposit_and_discount_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
end
- elsif record.deposit != record.stairbought_part_of_value
- %i[mortgageused value deposit stairbought].each do |field|
- record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_not_used", deposit: record.field_formatted_as_currency("deposit"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
+ elsif over_tolerance?(record.deposit_and_discount_total, record.stairbought_part_of_value, 1)
+ %i[mortgageused value deposit cashdis stairbought].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_not_used_socialhomebuy", deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.staircasing_mortgage.mortgage_not_used_socialhomebuy", deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
end
end
- def validate_mortgage_used_and_stairbought(record)
- return unless record.stairowned && record.mortgageused
+ def check_staircasing_non_socialhomebuy_mortgage(record)
+ if record.mortgage_used?
+ return unless record.mortgage
- if !record.stairowned_100? && record.mortgageused == 3
- record.errors.add :stairowned, I18n.t("validations.sale_information.stairowned.mortgageused_dont_know")
- record.errors.add :mortgageused, I18n.t("validations.sale_information.stairowned.mortgageused_dont_know")
+ if over_tolerance?(record.mortgage_and_deposit_total, record.stairbought_part_of_value, 1)
+ %i[mortgage value deposit stairbought type].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_used", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
+ end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.staircasing_mortgage.mortgage_used", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
+ end
+ elsif over_tolerance?(record.deposit, record.stairbought_part_of_value, 1)
+ %i[mortgageused value deposit stairbought type].each do |field|
+ record.errors.add field, I18n.t("validations.sale_information.staircasing_mortgage.mortgage_not_used", deposit: record.field_formatted_as_currency("deposit"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
+ end
+ record.errors.add :type, :skip_bu_error, message: I18n.t("validations.sale_information.staircasing_mortgage.mortgage_not_used", deposit: record.field_formatted_as_currency("deposit"), stairbought_part_of_value: record.field_formatted_as_currency("stairbought_part_of_value"))
end
end
@@ -170,4 +232,8 @@ module Validations::Sales::SaleInformationValidations
record.errors.add(:mortgageused, I18n.t("validations.invalid_option", question: "Was a mortgage used for the purchase of this property?"))
end
end
+
+ def over_tolerance?(expected, actual, tolerance)
+ (expected - actual).abs >= tolerance
+ end
end
diff --git a/app/models/validations/sales/soft_validations.rb b/app/models/validations/sales/soft_validations.rb
index 14c0afae4..51326a2f4 100644
--- a/app/models/validations/sales/soft_validations.rb
+++ b/app/models/validations/sales/soft_validations.rb
@@ -1,4 +1,6 @@
module Validations::Sales::SoftValidations
+ include Validations::Sales::SaleInformationValidations
+
ALLOWED_INCOME_RANGES_SALES = {
1 => OpenStruct.new(soft_min: 5000),
2 => OpenStruct.new(soft_min: 1500),
@@ -86,14 +88,10 @@ module Validations::Sales::SoftValidations
def shared_ownership_deposit_invalid?
return unless saledate && collection_start_year <= 2023
return unless mortgage || mortgageused == 2 || mortgageused == 3
- return unless cashdis || !is_type_discount?
+ return unless cashdis || !social_homebuy?
return unless deposit && value && equity
- !within_tolerance?(mortgage_deposit_and_discount_total, value * equity / 100, 1)
- end
-
- def within_tolerance?(expected, actual, tolerance)
- (expected - actual).abs <= tolerance
+ over_tolerance?(mortgage_deposit_and_discount_total, value * equity / 100, 1)
end
def mortgage_plus_deposit_less_than_discounted_value?
diff --git a/app/services/bulk_upload/sales/year2024/row_parser.rb b/app/services/bulk_upload/sales/year2024/row_parser.rb
index f1124f79d..87d6b491c 100644
--- a/app/services/bulk_upload/sales/year2024/row_parser.rb
+++ b/app/services/bulk_upload/sales/year2024/row_parser.rb
@@ -513,6 +513,7 @@ class BulkUpload::Sales::Year2024::RowParser
fields.each do |field|
next if errors.include?(field)
+ next if error.type == :skip_bu_error
question = log.form.get_question(error.attribute, log)
@@ -721,16 +722,16 @@ private
lanomagr: %i[field_97],
frombeds: %i[field_98],
fromprop: %i[field_99],
- value: %i[field_101 field_114 field_125],
+ value: value_fields,
equity: %i[field_102],
- mortgage: %i[field_104 field_118 field_127],
- extrabor: %i[field_108 field_122 field_129],
- deposit: %i[field_109 field_123 field_130],
+ mortgage: mortgage_fields,
+ extrabor: extrabor_fields,
+ deposit: deposit_fields,
cashdis: %i[field_110],
mrent: %i[field_111],
- has_mscharge: %i[field_112 field_124 field_131],
- mscharge: %i[field_112 field_124 field_131],
+ has_mscharge: mscharge_fields,
+ mscharge: mscharge_fields,
grant: %i[field_115],
discount: %i[field_116],
othtype: %i[field_12],
@@ -741,12 +742,12 @@ private
hhregresstill: %i[field_73],
armedforcesspouse: %i[field_74],
- mortgagelender: %i[field_105 field_119],
- mortgagelenderother: %i[field_106 field_120],
+ mortgagelender: mortgagelender_fields,
+ mortgagelenderother: mortgagelenderother_fields,
hb: %i[field_81],
- mortlen: %i[field_107 field_121 field_128],
- proplen: %i[field_113 field_85],
+ mortlen: mortlen_fields,
+ proplen: proplen_fields,
jointmore: %i[field_16],
staircase: %i[field_86],
@@ -762,7 +763,7 @@ private
stairbought: %i[field_87],
stairowned: %i[field_88],
socprevten: %i[field_100],
- mortgageused: [mortgageused_field],
+ mortgageused: mortgageused_fields,
uprn: %i[field_22],
address_line1: %i[field_23],
@@ -1118,10 +1119,81 @@ private
return field_126 if outright_sale?
end
- def mortgageused_field
- return :field_103 if shared_ownership?
- return :field_117 if discounted_ownership?
- return :field_126 if outright_sale?
+ def value_fields
+ return [:field_101] if shared_ownership?
+ return [:field_114] if discounted_ownership?
+ return [:field_125] if outright_sale?
+
+ %i[field_101 field_114 field_125]
+ end
+
+ def mortgage_fields
+ return [:field_104] if shared_ownership?
+ return [:field_118] if discounted_ownership?
+ return [:field_127] if outright_sale?
+
+ %i[field_104 field_118 field_127]
+ end
+
+ def extrabor_fields
+ return [:field_108] if shared_ownership?
+ return [:field_122] if discounted_ownership?
+ return [:field_129] if outright_sale?
+
+ %i[field_108 field_122 field_129]
+ end
+
+ def deposit_fields
+ return [:field_109] if shared_ownership?
+ return [:field_123] if discounted_ownership?
+ return [:field_130] if outright_sale?
+
+ %i[field_109 field_123 field_130]
+ end
+
+ def mscharge_fields
+ return [:field_112] if shared_ownership?
+ return [:field_124] if discounted_ownership?
+ return [:field_131] if outright_sale?
+
+ %i[field_112 field_124 field_131]
+ end
+
+ def mortgagelender_fields
+ return [:field_105] if shared_ownership?
+ return [:field_119] if discounted_ownership?
+
+ %i[field_105 field_119]
+ end
+
+ def mortgagelenderother_fields
+ return [:field_106] if shared_ownership?
+ return [:field_120] if discounted_ownership?
+
+ %i[field_106 field_120]
+ end
+
+ def mortlen_fields
+ return [:field_107] if shared_ownership?
+ return [:field_121] if discounted_ownership?
+ return [:field_128] if outright_sale?
+
+ %i[field_107 field_121 field_128]
+ end
+
+ def proplen_fields
+ return [:field_85] if shared_ownership?
+ return [:field_113] if discounted_ownership?
+
+ %i[field_85 field_113]
+ end
+
+ def mortgageused_fields
+ return [:field_103] if shared_ownership?
+ return [:field_117] if discounted_ownership?
+ return [:field_126] if outright_sale?
+
+ %i[field_103 field_117 field_126]
end
def owning_organisation
diff --git a/config/locales/en.yml b/config/locales/en.yml
index afbba3e2c..2f3e63020 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -641,11 +641,15 @@ en:
over_discounted_london_max: "The percentage discount multiplied by the purchase price is %{discount_value}. This figure should not be more than £136,400 for properties in London."
over_discounted_max: "The percentage discount multiplied by the purchase price is %{discount_value}. This figure should not be more than £102,400 for properties outside of London."
non_staircasing_mortgage:
- mortgage_used: "The mortgage and deposit added together is %{mortgage_and_deposit_total} and the purchase price times by the equity is %{expected_shared_ownership_deposit_value}. These figures should be the same."
- mortgage_not_used: "The deposit is %{deposit} and the purchase price times by the equity is %{expected_shared_ownership_deposit_value}. As no mortgage was used, these figures should be the same."
+ mortgage_used: "The mortgage and deposit added together is %{mortgage_and_deposit_total}. The value multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}. These figures should be the same."
+ mortgage_not_used: "The deposit is %{deposit} and the value multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}. These figures should be the same."
+ mortgage_used_socialhomebuy: "The mortgage, deposit, and cash discount added together is %{mortgage_deposit_and_discount_total}. The value multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}. These figures should be the same."
+ mortgage_not_used_socialhomebuy: "The deposit and cash discount added together is %{deposit_and_discount_total}. The value multiplied by the percentage bought is %{expected_shared_ownership_deposit_value}. These figures should be the same."
staircasing_mortgage:
- mortgage_used: "The mortgage and deposit added together is %{mortgage_and_deposit_total} and the percentage bought times the purchase price is %{stairbought_part_of_value}. These figures should be the same."
- mortgage_not_used: "The deposit is %{deposit} and the percentage bought times the purchase price is %{stairbought_part_of_value}. As no mortgage was used, these figures should be the same."
+ mortgage_used: "The mortgage and deposit added together is %{mortgage_and_deposit_total}. The value multiplied by the percentage bought is %{stairbought_part_of_value}. These figures should be the same."
+ mortgage_not_used: "The deposit is %{deposit} and the value multiplied by the percentage bought is %{stairbought_part_of_value}. These figures should be the same."
+ mortgage_used_socialhomebuy: "The mortgage, deposit, and cash discount added together is %{mortgage_deposit_and_discount_total}. The value multiplied by the percentage bought is %{stairbought_part_of_value}. These figures should be the same."
+ mortgage_not_used_socialhomebuy: "The deposit and cash discount added together is %{deposit_and_discount_total}. The value multiplied by the percentage bought is %{stairbought_part_of_value}. These figures should be the same."
stairowned:
mortgageused_dont_know: "The percentage owned has to be 100% if the mortgage used is 'Don’t know'"
merge_request:
diff --git a/spec/models/form/sales/pages/about_deposit_with_discount_spec.rb b/spec/models/form/sales/pages/about_deposit_with_discount_spec.rb
index 4cffb2b54..fabfb7836 100644
--- a/spec/models/form/sales/pages/about_deposit_with_discount_spec.rb
+++ b/spec/models/form/sales/pages/about_deposit_with_discount_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => true }],
+ [{ "social_homebuy?" => true }],
)
end
@@ -42,7 +42,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => true }],
+ [{ "social_homebuy?" => true }],
)
end
end
@@ -54,7 +54,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => true, "stairowned_100?" => false }],
+ [{ "social_homebuy?" => true, "stairowned_100?" => false }],
)
end
@@ -63,7 +63,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => true, "stairowned_100?" => true }],
+ [{ "social_homebuy?" => true, "stairowned_100?" => true }],
)
end
end
diff --git a/spec/models/form/sales/pages/about_deposit_without_discount_spec.rb b/spec/models/form/sales/pages/about_deposit_without_discount_spec.rb
index d6f58c65f..003313353 100644
--- a/spec/models/form/sales/pages/about_deposit_without_discount_spec.rb
+++ b/spec/models/form/sales/pages/about_deposit_without_discount_spec.rb
@@ -33,7 +33,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithoutDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => false, "ownershipsch" => 1 },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1 },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }],
)
@@ -44,7 +44,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithoutDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => false, "ownershipsch" => 1 },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1 },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }],
)
@@ -58,7 +58,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithoutDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => false, "ownershipsch" => 1, "stairowned_100?" => false },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1, "stairowned_100?" => false },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }],
)
@@ -69,7 +69,7 @@ RSpec.describe Form::Sales::Pages::AboutDepositWithoutDiscount, type: :model do
it "has correct depends_on" do
expect(page.depends_on).to eq(
- [{ "is_type_discount?" => false, "ownershipsch" => 1, "stairowned_100?" => true },
+ [{ "social_homebuy?" => false, "ownershipsch" => 1, "stairowned_100?" => true },
{ "ownershipsch" => 2 },
{ "ownershipsch" => 3, "mortgageused" => 1 }],
)
diff --git a/spec/models/validations/sales/financial_validations_spec.rb b/spec/models/validations/sales/financial_validations_spec.rb
index e52387987..316c2d175 100644
--- a/spec/models/validations/sales/financial_validations_spec.rb
+++ b/spec/models/validations/sales/financial_validations_spec.rb
@@ -432,181 +432,6 @@ RSpec.describe Validations::Sales::FinancialValidations do
end
end
- describe "#validate_shared_ownership_deposit" do
- let(:record) { FactoryBot.create(:sales_log, saledate: now) }
-
- around do |example|
- Timecop.freeze(now) do
- Singleton.__init__(FormHandler)
- example.run
- end
- Timecop.return
- end
-
- context "with a log in the 24/25 collection year" do
- let(:now) { Time.zone.local(2024, 4, 2) }
-
- it "does not add an error if MORTGAGE + DEPOSIT + CASHDIS are equal VALUE * EQUITY/100" do
- record.mortgage = 1000
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "does not add an error if mortgage is used and no mortgage is given" do
- record.mortgage = nil
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "adds an error if mortgage is not used and no mortgage is given" do
- record.mortgage = nil
- record.mortgageused = 2
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same")
- expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same")
- expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same")
- expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same")
- expect(record.errors["equity"]).to include("The mortgage, deposit, and cash discount added together is £2,000.00. The value times the equity percentage is £3,000.00. These figures should be the same")
- end
-
- it "does not add an error if no deposit is given" do
- record.mortgage = 1000
- record.deposit = nil
- record.cashdis = 1000
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "does not add an error if no cashdis is given and cashdis is routed to" do
- record.mortgage = 1000
- record.deposit = 1000
- record.type = 18
- record.cashdis = nil
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "does not add an error if no cashdis is given and cashdis is not routed to" do
- record.mortgageused = 1
- record.mortgage = 1000
- record.deposit = 1000
- record.type = 2
- record.cashdis = nil
- record.value = 3000
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "does not add an error if no value is given" do
- record.mortgage = 1000
- record.deposit = 1000
- record.cashdis = 1000
- record.value = nil
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "does not add an error if no equity is given" do
- record.mortgage = 1000
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 3000
- record.equity = nil
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
-
- it "adds an error if MORTGAGE + DEPOSIT + CASHDIS are not equal VALUE * EQUITY/100" do
- record.mortgageused = 1
- record.mortgage = 1000
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 4323
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same")
- expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same")
- expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same")
- expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same")
- expect(record.errors["equity"]).to include("The mortgage, deposit, and cash discount added together is £3,000.00. The value times the equity percentage is £4,323.00. These figures should be the same")
- end
- end
-
- context "with a log in 23/24 collection year" do
- let(:now) { Time.zone.local(2024, 1, 1) }
-
- it "does not add an error if MORTGAGE + DEPOSIT + CASHDIS are not equal VALUE * EQUITY/100" do
- record.mortgage = 1000
- record.deposit = 1000
- record.cashdis = 1000
- record.value = 4323
- record.equity = 100
-
- financial_validator.validate_shared_ownership_deposit(record)
- expect(record.errors["mortgage"]).to be_empty
- expect(record.errors["deposit"]).to be_empty
- expect(record.errors["cashdis"]).to be_empty
- expect(record.errors["value"]).to be_empty
- expect(record.errors["equity"]).to be_empty
- end
- end
- end
-
describe "#validate_equity_less_than_staircase_difference" do
let(:record) { FactoryBot.create(:sales_log, saledate: now) }
diff --git a/spec/models/validations/sales/sale_information_validations_spec.rb b/spec/models/validations/sales/sale_information_validations_spec.rb
index ca07da6f4..4da297f53 100644
--- a/spec/models/validations/sales/sale_information_validations_spec.rb
+++ b/spec/models/validations/sales/sale_information_validations_spec.rb
@@ -740,10 +740,45 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
it "adds an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
- expect(record.errors["mortgage"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
- expect(record.errors["value"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
- expect(record.errors["deposit"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
- expect(record.errors["equity"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
+ expect(record.errors["mortgage"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["equity"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).not_to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+
+ context "and it is a social homebuy" do
+ before do
+ record.type = 18
+ record.cashdis = "200"
+ end
+
+ it "adds an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["equity"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+ end
+
+ context "and it is not a shared ownership transaction" do
+ before do
+ record.ownershipsch = 2
+ end
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
end
end
@@ -758,12 +793,14 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
context "when MORTGAGE + DEPOSIT equals VALUE * EQUITY/100" do
- let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, staircase: 2, deposit: 5_000, value: 30_000, equity: 50, ownershipsch: 1, type: 30, saledate: now) }
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, mortgage: 10_000, staircase: 2, deposit: 5_000, value: 30_000, equity: 50, ownershipsch: 1, type: 30, saledate: now) }
it "does not add an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
@@ -771,6 +808,22 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
+ end
+
+ context "when MORTGAGE + DEPOSIT is within 1£ tolerance of VALUE * EQUITY/100" do
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, mortgage: 10_000, staircase: 2, deposit: 50_000, value: 120_001, equity: 50, ownershipsch: 1, type: 30, saledate: now) }
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
@@ -787,10 +840,45 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
it "adds an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
- expect(record.errors["mortgageused"]).to include("The deposit is £5,000.00 and the purchase price times by the equity is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["value"]).to include("The deposit is £5,000.00 and the purchase price times by the equity is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["deposit"]).to include("The deposit is £5,000.00 and the purchase price times by the equity is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["equity"]).to include("The deposit is £5,000.00 and the purchase price times by the equity is £8,400.00. As no mortgage was used, these figures should be the same.")
+ expect(record.errors["mortgageused"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["equity"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).not_to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+
+ context "and it is a social homebuy" do
+ before do
+ record.type = 18
+ record.cashdis = "200"
+ end
+
+ it "adds an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["equity"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+ end
+
+ context "and it is not a shared ownership transaction" do
+ before do
+ record.ownershipsch = 2
+ end
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
end
end
@@ -805,6 +893,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -818,6 +908,22 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
+ end
+
+ context "when DEPOSIT is within 1£ tolerance of VALUE * EQUITY/100" do
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 2, staircase: 2, deposit: 15_000, value: 30_001, equity: 50, ownershipsch: 1, type: 30, saledate: now) }
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -833,6 +939,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -860,10 +968,45 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
it "adds an error" do
sale_information_validator.validate_staircasing_mortgage(record)
- expect(record.errors["mortgage"]).to include("The mortgage and deposit added together is £15,000.00 and the percentage bought times the purchase price is £8,400.00. These figures should be the same.")
- expect(record.errors["value"]).to include("The mortgage and deposit added together is £15,000.00 and the percentage bought times the purchase price is £8,400.00. These figures should be the same.")
- expect(record.errors["deposit"]).to include("The mortgage and deposit added together is £15,000.00 and the percentage bought times the purchase price is £8,400.00. These figures should be the same.")
- expect(record.errors["stairbought"]).to include("The mortgage and deposit added together is £15,000.00 and the percentage bought times the purchase price is £8,400.00. These figures should be the same.")
+ expect(record.errors["mortgage"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["stairbought"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).not_to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+
+ context "and it is a social homebuy" do
+ before do
+ record.type = 18
+ record.cashdis = "200"
+ end
+
+ it "adds an error" do
+ sale_information_validator.validate_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["stairbought"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The mortgage, deposit, and cash discount added together is £15,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+ end
+
+ context "and it is not a shared ownership transaction" do
+ before do
+ record.ownershipsch = 2
+ end
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
end
end
@@ -878,12 +1021,14 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
context "when MORTGAGE + DEPOSIT equals STAIRBOUGHT/100 * VALUE" do
- let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, staircase: 1, deposit: 5_000, value: 30_000, stairbought: 50, ownershipsch: 1, type: 30, saledate: now) }
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, mortgage: 10_000, staircase: 1, deposit: 5_000, value: 30_000, stairbought: 50, ownershipsch: 1, type: 30, saledate: now) }
it "does not add an error" do
sale_information_validator.validate_staircasing_mortgage(record)
@@ -891,6 +1036,22 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
+ end
+
+ context "when MORTGAGE + DEPOSIT is within 1£ tolerance of STAIRBOUGHT/100 * VALUE" do
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, mortgage: 10_000, staircase: 1, deposit: 5_000, value: 30_001, stairbought: 50, ownershipsch: 1, type: 30, saledate: now) }
+
+ it "does not add an error" do
+ sale_information_validator.validate_staircasing_mortgage(record)
+ expect(record.errors["mortgage"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -905,6 +1066,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
@@ -924,10 +1087,45 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
it "adds an error" do
sale_information_validator.validate_staircasing_mortgage(record)
- expect(record.errors["mortgageused"]).to include("The deposit is £5,000.00 and the percentage bought times the purchase price is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["value"]).to include("The deposit is £5,000.00 and the percentage bought times the purchase price is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["deposit"]).to include("The deposit is £5,000.00 and the percentage bought times the purchase price is £8,400.00. As no mortgage was used, these figures should be the same.")
- expect(record.errors["stairbought"]).to include("The deposit is £5,000.00 and the percentage bought times the purchase price is £8,400.00. As no mortgage was used, these figures should be the same.")
+ expect(record.errors["mortgageused"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["stairbought"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).not_to include("The deposit is £5,000.00 and the value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+
+ context "and it is a social homebuy" do
+ before do
+ record.type = 18
+ record.cashdis = "200"
+ end
+
+ it "adds an error" do
+ sale_information_validator.validate_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["value"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["deposit"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["stairbought"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["cashdis"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(record.errors["type"]).to include("The deposit and cash discount added together is £5,200.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+ end
+
+ context "and it is not a shared ownership transaction" do
+ before do
+ record.ownershipsch = 2
+ end
+
+ it "does not add an error" do
+ sale_information_validator.validate_non_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
end
end
@@ -942,6 +1140,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -955,6 +1155,22 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
+ end
+ end
+
+ context "when DEPOSIT is within 1£ tolerance of STAIRBOUGHT/100 * VALUE" do
+ let(:record) { FactoryBot.build(:sales_log, mortgageused: 2, staircase: 1, deposit: 15_000, value: 30_001, stairbought: 50, ownershipsch: 1, type: 30, saledate: now) }
+
+ it "does not add an error" do
+ sale_information_validator.validate_staircasing_mortgage(record)
+ expect(record.errors["mortgageused"]).to be_empty
+ expect(record.errors["value"]).to be_empty
+ expect(record.errors["deposit"]).to be_empty
+ expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
@@ -969,6 +1185,8 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["stairbought"]).to be_empty
+ expect(record.errors["cashdis"]).to be_empty
+ expect(record.errors["type"]).to be_empty
end
end
end
diff --git a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
index 93ab6d9da..e68e95f06 100644
--- a/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
+++ b/spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
@@ -1134,6 +1134,32 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
expect(parser.errors[:field_109]).to be_empty
end
end
+
+ context "with non staircasing mortgage error" do
+ let(:attributes) { setup_section_params.merge(field_9: "30", field_103: "1", field_104: "10000", field_109: "5000", field_101: "30000", field_102: "28", field_86: "2") }
+
+ it "does not add a BU error on type (because it's a setup field and would block log creation)" do
+ expect(parser.errors[:field_9]).to be_empty
+ end
+
+ it "includes errors on other related fields" do
+ expect(parser.errors[:field_104]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(parser.errors[:field_109]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(parser.errors[:field_101]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ expect(parser.errors[:field_102]).to include("The mortgage and deposit added together is £15,000.00. The value multiplied by the percentage bought is £8,400.00. These figures should be the same.")
+ end
+
+ it "does not add errors to other ownership type fields" do
+ expect(parser.errors[:field_117]).to be_empty
+ expect(parser.errors[:field_126]).to be_empty
+ expect(parser.errors[:field_118]).to be_empty
+ expect(parser.errors[:field_127]).to be_empty
+ expect(parser.errors[:field_123]).to be_empty
+ expect(parser.errors[:field_130]).to be_empty
+ expect(parser.errors[:field_114]).to be_empty
+ expect(parser.errors[:field_125]).to be_empty
+ end
+ end
end
describe "#field_117" do
From 24dfdbe5eb067ef06592c9bcc567045640bc4511 Mon Sep 17 00:00:00 2001
From: natdeanlewissoftwire
<94526761+natdeanlewissoftwire@users.noreply.github.com>
Date: Wed, 20 Mar 2024 14:51:04 +0000
Subject: [PATCH 2/4] CLDC-3271 Add address fields as entered in bulk upload to
support csv downloads (#2322)
* feat: add bulk upload address info to lettings csv download
* feat: add bulk upload address info to sales csv download
* refactor: lint
* feat: fix typo
* feat: update tests
* feat: add to non question fields
* feat: update tests
* feat: add sales tests
* feat: add as entered fields to xml export for 2024 only (#2324)
* feat: update schema
---
app/jobs/email_csv_job.rb | 2 +-
.../bulk_upload/lettings/year2024/row_parser.rb | 6 ++++++
.../bulk_upload/sales/year2024/row_parser.rb | 6 ++++++
app/services/csv/lettings_log_csv_service.rb | 4 ++--
app/services/csv/sales_log_csv_service.rb | 10 +++++++---
.../exports/lettings_log_export_constants.rb | 16 ++++++++++++++--
.../exports/lettings_log_export_service.rb | 4 ----
...dd_entered_address_fields_to_lettings_logs.rb | 12 ++++++++++++
...7_add_entered_address_fields_to_sales_logs.rb | 12 ++++++++++++
db/schema.rb | 12 ++++++++++++
.../fixtures/exports/general_needs_log_24_25.xml | 6 ++++++
.../files/lettings_log_csv_export_codes_23.csv | 4 ++--
.../files/lettings_log_csv_export_codes_24.csv | 4 ++--
.../files/lettings_log_csv_export_labels_23.csv | 4 ++--
.../files/lettings_log_csv_export_labels_24.csv | 4 ++--
.../files/sales_logs_csv_export_codes_23.csv | 4 ++--
.../files/sales_logs_csv_export_codes_24.csv | 4 ++--
.../files/sales_logs_csv_export_labels_23.csv | 4 ++--
.../files/sales_logs_csv_export_labels_24.csv | 4 ++--
spec/jobs/email_csv_job_spec.rb | 4 ++--
.../csv/lettings_log_csv_service_spec.rb | 6 ++++++
spec/services/csv/sales_log_csv_service_spec.rb | 12 +++++++++---
.../exports/lettings_log_export_service_spec.rb | 2 +-
23 files changed, 112 insertions(+), 34 deletions(-)
create mode 100644 db/migrate/20240319092425_add_entered_address_fields_to_lettings_logs.rb
create mode 100644 db/migrate/20240319115447_add_entered_address_fields_to_sales_logs.rb
diff --git a/app/jobs/email_csv_job.rb b/app/jobs/email_csv_job.rb
index 89b358e28..7658cf755 100644
--- a/app/jobs/email_csv_job.rb
+++ b/app/jobs/email_csv_job.rb
@@ -15,7 +15,7 @@ class EmailCsvJob < ApplicationJob
when "sales"
unfiltered_logs = organisation.present? && user.support? ? SalesLog.visible.where(owning_organisation_id: organisation.id) : user.sales_logs.visible
filtered_logs = FilterManager.filter_logs(unfiltered_logs, search_term, filters, all_orgs, user)
- csv_string = Csv::SalesLogCsvService.new(export_type:).prepare_csv(filtered_logs)
+ csv_string = Csv::SalesLogCsvService.new(user:, export_type:).prepare_csv(filtered_logs)
end
filename = "#{[log_type, 'logs', organisation&.name, Time.zone.now].compact.join('-')}.csv"
diff --git a/app/services/bulk_upload/lettings/year2024/row_parser.rb b/app/services/bulk_upload/lettings/year2024/row_parser.rb
index 8b5fe8f3c..b0802df12 100644
--- a/app/services/bulk_upload/lettings/year2024/row_parser.rb
+++ b/app/services/bulk_upload/lettings/year2024/row_parser.rb
@@ -1092,6 +1092,7 @@ private
attributes["lettype"] = nil # should get this from rent_type
attributes["tenancycode"] = field_13
attributes["la"] = field_23
+ attributes["la_as_entered"] = field_23
attributes["postcode_known"] = postcode_known
attributes["postcode_full"] = postcode_full
attributes["owning_organisation"] = owning_organisation
@@ -1268,11 +1269,16 @@ private
attributes["skip_update_uprn_confirmed"] = true
attributes["uprn"] = field_16
attributes["address_line1"] = field_17
+ attributes["address_line1_as_entered"] = field_17
attributes["address_line2"] = field_18
+ attributes["address_line2_as_entered"] = field_18
attributes["town_or_city"] = field_19
+ attributes["town_or_city_as_entered"] = field_19
attributes["county"] = field_20
+ attributes["county_as_entered"] = field_20
attributes["address_line1_input"] = address_line1_input
attributes["postcode_full_input"] = postcode_full
+ attributes["postcode_full_as_entered"] = postcode_full
attributes["select_best_address_match"] = true if field_16.blank?
attributes
diff --git a/app/services/bulk_upload/sales/year2024/row_parser.rb b/app/services/bulk_upload/sales/year2024/row_parser.rb
index 87d6b491c..be6a9ca63 100644
--- a/app/services/bulk_upload/sales/year2024/row_parser.rb
+++ b/app/services/bulk_upload/sales/year2024/row_parser.rb
@@ -874,9 +874,11 @@ private
attributes["builtype"] = field_21
attributes["la_known"] = field_29.present? ? 1 : 0
attributes["la"] = field_29
+ attributes["la_as_entered"] = field_29
attributes["is_la_inferred"] = false
attributes["pcodenk"] = 0 if postcode_full.present?
attributes["postcode_full"] = postcode_full
+ attributes["postcode_full_as_entered"] = postcode_full
attributes["wchair"] = field_30
attributes["type"] = sale_type
@@ -942,9 +944,13 @@ private
attributes["uprn_confirmed"] = 1 if field_22.present?
attributes["skip_update_uprn_confirmed"] = true
attributes["address_line1"] = field_23
+ attributes["address_line1_as_entered"] = field_23
attributes["address_line2"] = field_24
+ attributes["address_line2_as_entered"] = field_24
attributes["town_or_city"] = field_25
+ attributes["town_or_city_as_entered"] = field_25
attributes["county"] = field_26
+ attributes["county_as_entered"] = field_26
attributes["address_line1_input"] = address_line1_input
attributes["postcode_full_input"] = postcode_full
attributes["select_best_address_match"] = true if field_22.blank?
diff --git a/app/services/csv/lettings_log_csv_service.rb b/app/services/csv/lettings_log_csv_service.rb
index 2dd817ebe..c32b82cc7 100644
--- a/app/services/csv/lettings_log_csv_service.rb
+++ b/app/services/csv/lettings_log_csv_service.rb
@@ -296,7 +296,7 @@ module Csv
"letting_allocation_unknown" => %w[letting_allocation_none],
}.freeze
- SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed address_line1_input postcode_full_input address_search_value_check uprn_selection reasonother_value_check].freeze
+ SUPPORT_ONLY_ATTRIBUTES = %w[net_income_value_check first_time_property_let_as_social_housing postcode_known is_la_inferred totchild totelder totadult net_income_known previous_la_known is_previous_la_inferred age1_known age2_known age3_known age4_known age5_known age6_known age7_known age8_known details_known_2 details_known_3 details_known_4 details_known_5 details_known_6 details_known_7 details_known_8 wrent wscharge wpschrge wsupchrg wtcharge wtshortfall rent_value_check old_form_id old_id retirement_value_check tshortfall_known pregnancy_value_check hhtype new_old la prevloc updated_by_id bulk_upload_id uprn_confirmed address_line1_input postcode_full_input address_search_value_check uprn_selection reasonother_value_check address_line1_as_entered address_line2_as_entered town_or_city_as_entered county_as_entered postcode_full_as_entered la_as_entered].freeze
def lettings_log_attributes
ordered_questions = FormHandler.instance.ordered_lettings_questions_for_all_years
@@ -310,7 +310,7 @@ module Csv
ATTRIBUTE_MAPPINGS.fetch(question.id, question.id)
end
end
- non_question_fields = %w[id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year]
+ non_question_fields = %w[id status duplicate_set_id created_by is_dpo created_at updated_by updated_at creation_method old_id old_form_id collection_start_year address_line1_as_entered address_line2_as_entered town_or_city_as_entered county_as_entered postcode_full_as_entered la_as_entered]
scheme_and_location_attributes = %w[scheme_code scheme_service_name scheme_sensitive SCHTYPE scheme_registered_under_care_act scheme_owning_organisation_name scheme_primary_client_group scheme_has_other_client_group scheme_secondary_client_group scheme_support_type scheme_intended_stay scheme_created_at location_code location_postcode location_name location_units location_type_of_unit location_mobility_type location_local_authority location_startdate]
final_attributes = non_question_fields + attributes + scheme_and_location_attributes
@user.support? ? final_attributes : final_attributes - SUPPORT_ONLY_ATTRIBUTES
diff --git a/app/services/csv/sales_log_csv_service.rb b/app/services/csv/sales_log_csv_service.rb
index a1fbc1ca9..c0d030842 100644
--- a/app/services/csv/sales_log_csv_service.rb
+++ b/app/services/csv/sales_log_csv_service.rb
@@ -1,6 +1,7 @@
module Csv
class SalesLogCsvService
- def initialize(export_type:)
+ def initialize(user:, export_type:)
+ @user = user
@export_type = export_type
@attributes = sales_log_attributes
end
@@ -132,6 +133,8 @@ module Csv
"managing_organisation_id" => %w[managing_organisation_name],
}.freeze
+ SUPPORT_ONLY_ATTRIBUTES = %w[address_line1_as_entered address_line2_as_entered town_or_city_as_entered county_as_entered postcode_full_as_entered la_as_entered].freeze
+
def sales_log_attributes
ordered_questions = FormHandler.instance.ordered_sales_questions_for_all_years
ordered_questions.reject! { |q| q.id.match?(/((?
2
+ address line 1 as entered
+ address line 2 as entered
+ town or city as entered
+ county as entered
+ AB1 2CD
+ la as entered
{id}
{owning_org_id}
DLUHC
diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv
index 5071b4a09..547d2f5b1 100644
--- a/spec/fixtures/files/lettings_log_csv_export_codes_23.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_codes_23.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,,,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
+,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,1,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,1,4,,1,4,0,0,2,35,,F,0,2,,13,0,0,P,,,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv
index c73ad3ab7..e2ef9674e 100644
--- a/spec/fixtures/files/lettings_log_csv_export_codes_24.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_codes_24.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,,,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
+,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,1,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,1,7,0,2023-11-26,2,2,1,,2,HIJKLMN,ABCDEFG,1,1,0,,,,,,,fake address,,London,,NW9 5LL,false,Barnet,E09000003,0,2,6,2,2,7,1,1,3,2023-11-24,,,1,2023-11-25,,3,1,4,,2,,4,,1,4,0,0,2,35,,F,0,2,13,,0,0,P,,,32,M,6,1,R,-9,R,10,0,R,-9,R,10,,,,,,,,,,,,,,,,,,,,,1,4,1,2,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,2,7,4,,,6,2,1,0,TN23 6LZ,1,false,Ashford,E07000105,1,0,1,0,0,0,0,0,1,0,,2,,0,0,1,268,,6,1,1,,0,2,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,1,0,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv
index 638212806..ce4e13518 100644
--- a/spec/fixtures/files/lettings_log_csv_export_labels_23.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_labels_23.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,declaration,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
+,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2023-11-26T00:00:00+00:00,single log,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,Yes,4,,Yes,4,0,0,2,35,,Female,White,Irish,,Tenant prefers not to say,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv
index bbe790ef1..378e3150f 100644
--- a/spec/fixtures/files/lettings_log_csv_export_labels_24.csv
+++ b/spec/fixtures/files/lettings_log_csv_export_labels_24.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
-,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
+id,status,duplicate_set_id,created_by,is_dpo,created_at,updated_by,updated_at,creation_method,old_id,old_form_id,collection_start_year,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,needstype,lettype,renewal,startdate,renttype,renttype_detail,irproduct,irproduct_other,lar,tenancycode,propcode,declaration,postcode_known,uprn_known,uprn,uprn_confirmed,address_line1_input,postcode_full_input,address_search_value_check,uprn_selection,address_line1,address_line2,town_or_city,county,postcode_full,is_la_inferred,la_label,la,first_time_property_let_as_social_housing,unitletas,rsnvac,newprop,offered,unittype_gn,builtype,wchair,beds,voiddate,vacdays,void_date_value_check,majorrepairs,mrcdate,major_repairs_date_value_check,joint,startertenancy,tenancy,tenancyother,tenancylength,sheltered,hhmemb,pregnancy_value_check,refused,hhtype,totchild,totelder,totadult,age1,retirement_value_check,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,details_known_2,relat2,partner_under_16_value_check,multiple_partners_value_check,age2,sex2,ecstat2,details_known_3,relat3,age3,sex3,ecstat3,details_known_4,relat4,age4,sex4,ecstat4,details_known_5,relat5,age5,sex5,ecstat5,details_known_6,relat6,age6,sex6,ecstat6,details_known_7,relat7,age7,sex7,ecstat7,details_known_8,relat8,age8,sex8,ecstat8,armedforces,leftreg,reservist,preg_occ,housingneeds,housingneeds_type,housingneeds_a,housingneeds_b,housingneeds_c,housingneeds_f,housingneeds_g,housingneeds_h,housingneeds_other,illness,illness_type_4,illness_type_5,illness_type_2,illness_type_6,illness_type_7,illness_type_3,illness_type_9,illness_type_8,illness_type_1,illness_type_10,layear,waityear,reason,reasonother,reasonother_value_check,prevten,new_old,homeless,ppcodenk,ppostcode_full,previous_la_known,is_previous_la_inferred,prevloc_label,prevloc,reasonpref,rp_homeless,rp_insan_unsat,rp_medwel,rp_hardship,rp_dontknow,cbl,cap,chr,accessible_register,letting_allocation_none,referral,referral_value_check,net_income_known,incref,incfreq,earnings,net_income_value_check,hb,has_benefits,benefits,household_charge,nocharge,period,is_carehome,chcharge,wchchrg,carehome_charges_value_check,brent,wrent,rent_value_check,scharge,wscharge,pscharge,wpschrge,supcharg,wsupchrg,tcharge,wtcharge,scharge_value_check,pscharge_value_check,supcharg_value_check,hbrentshortfall,tshortfall_known,tshortfall,wtshortfall,scheme_code,scheme_service_name,scheme_sensitive,SCHTYPE,scheme_registered_under_care_act,scheme_owning_organisation_name,scheme_primary_client_group,scheme_has_other_client_group,scheme_secondary_client_group,scheme_support_type,scheme_intended_stay,scheme_created_at,location_code,location_postcode,location_name,location_units,location_type_of_unit,location_mobility_type,location_local_authority,location_startdate
+,completed,,s.port@jeemayle.com,false,2023-11-26T00:00:00+00:00,,2024-04-01T00:00:00+01:00,single log,,,2023,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,General needs,Affordable rent general needs local authority,No,2023-11-26,Affordable Rent,Affordable Rent,Rent to Buy,,No,HIJKLMN,ABCDEFG,Yes,Yes,No,,,,,,,fake address,,London,,NW9 5LL,No,Barnet,E09000003,No,Affordable rent basis,Tenant abandoned property,No,2,House,Purpose built,Yes,3,2023-11-24,,,Yes,2023-11-25,,Don’t know,Yes,Assured Shorthold Tenancy (AST) – Fixed term,,2,,4,,Yes,4,0,0,2,35,,Female,White,Irish,Tenant prefers not to say,,Other,Yes,Partner,,,32,Male,Not seeking work,No,Prefers not to say,Not known,Prefers not to say,Prefers not to say,Yes,Person prefers not to say,Not known,Person prefers not to say,Person prefers not to say,,,,,,,,,,,,,,,,,,,,,Yes – the person is a current or former regular,No – they left up to and including 5 years ago,Yes,No,Yes,Fully wheelchair accessible housing,Yes,No,No,No,No,No,No,Yes,No,No,Yes,No,No,No,No,No,No,No,Less than 1 year,1 year but under 2 years,Loss of tied accommodation,,,Other supported housing,2,No,Yes,TN23 6LZ,Yes,No,Ashford,E07000105,Yes,,Yes,,,,No,No,Yes,No,,Tenant applied directly (no referral or nomination),,Yes,No,Weekly,268,,Universal Credit housing element,Yes,All,,No,Every 2 weeks,,,,,200.0,100.0,,50.0,25.0,40.0,20.0,35.0,17.5,325.0,162.5,,,,Yes,Yes,12.0,6.0,,,,,,,,,,,,,,,,,,,,
diff --git a/spec/fixtures/files/sales_logs_csv_export_codes_23.csv b/spec/fixtures/files/sales_logs_csv_export_codes_23.csv
index 0ecac1947..474487bbf 100644
--- a/spec/fixtures/files/sales_logs_csv_export_codes_23.csv
+++ b/spec/fixtures/files/sales_logs_csv_export_codes_23.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
-,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,1,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,,18,1,1,P,35,X,17,,,13,1,1,3,C,14,X,,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0
+id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
+,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,1,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,1,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,1,2,1,30,X,17,17,,18,1,1,P,35,X,17,,,13,1,1,3,C,14,X,,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0
diff --git a/spec/fixtures/files/sales_logs_csv_export_codes_24.csv b/spec/fixtures/files/sales_logs_csv_export_codes_24.csv
index 4182589ff..b4b5befa3 100644
--- a/spec/fixtures/files/sales_logs_csv_export_codes_24.csv
+++ b/spec/fixtures/files/sales_logs_csv_export_codes_24.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
-,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,1,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,1,1,0,1,30,X,17,17,18,,1,1,P,35,X,17,,13,,1,1,3,C,14,X,,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0
+id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
+,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,1,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,2,8,,,,1,1,2,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,1,1,0,1,30,X,17,17,18,,1,1,P,35,X,17,,13,,1,1,3,C,14,X,,X,-9,X,3,R,-9,R,10,,,,,1,1,,,0,,,1,1,1,1,,3,,1,4,5,1,1,0,10000,1,0,10000,1,4,1,,1,2,10,,,,,,,,,,,,,,,,,110000.0,,1,20000.0,5,,10,1,80000.0,,,1,100.0,,10000.0
diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_23.csv b/spec/fixtures/files/sales_logs_csv_export_labels_23.csv
index ca7b4b1b7..d299a2612 100644
--- a/spec/fixtures/files/sales_logs_csv_export_labels_23.csv
+++ b/spec/fixtures/files/sales_logs_csv_export_labels_23.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
-,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer prefers not to say,17,,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,,Buyer prefers not to say,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0
+id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,beds,proptype,builtype,pcodenk,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,wchair,noint,privacynotice,age1,sex1,ethnic_group,ethnic,nationality_all,national,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationality_all_buyer2,nationalbuy2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
+,completed,,2023-12-08T00:00:00+00:00,2024-01-01T00:00:00+00:00,,2023,single log,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,2,Flat or maisonette,Purpose built,0,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,Yes,Yes,1,30,Non-binary,Buyer prefers not to say,17,,United Kingdom,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,,Buyer prefers not to say,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0
diff --git a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv
index 44c97dd06..833173e3b 100644
--- a/spec/fixtures/files/sales_logs_csv_export_labels_24.csv
+++ b/spec/fixtures/files/sales_logs_csv_export_labels_24.csv
@@ -1,2 +1,2 @@
-id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
-,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0
+id,status,duplicate_set_id,created_at,updated_at,old_form_id,collection_start_year,creation_method,is_dpo,address_line1_as_entered,address_line2_as_entered,town_or_city_as_entered,county_as_entered,postcode_full_as_entered,la_as_entered,owning_organisation_name,managing_organisation_name,created_by,day,month,year,purchid,ownershipsch,type,othtype,companybuy,buylivein,jointpur,jointmore,noint,privacynotice,uprn,uprn_confirmed,address_line1_input,postcode_full_input,uprn_selection,address_line1,address_line2,town_or_city,county,pcode1,pcode2,la_known,la,la_label,beds,proptype,builtype,pcodenk,wchair,age1,sex1,ethnic_group,ethnic,national,nationality_all,ecstat1,buy1livein,relat2,age2,sex2,ethnic_group2,ethnicbuy2,nationalbuy2,nationality_all_buyer2,ecstat2,buy2livein,hholdcount,relat3,age3,sex3,ecstat3,relat4,age4,sex4,ecstat4,relat5,age5,sex5,ecstat5,relat6,age6,sex6,ecstat6,prevten,ppcodenk,ppostc1,ppostc2,previous_la_known,prevloc,prevloc_label,pregyrha,pregother,pregla,pregghb,pregblank,buy2living,prevtenbuy2,hhregres,hhregresstill,armedforcesspouse,disabled,wheel,income1nk,income1,inc1mort,income2nk,income2,inc2mort,hb,savingsnk,savings,prevown,prevshared,proplen,staircase,stairbought,stairowned,staircasesale,resale,exday,exmonth,exyear,hoday,homonth,hoyear,lanomagr,soctenant,frombeds,fromprop,socprevten,value,equity,mortgageused,mortgage,mortgagelender,mortgagelenderother,mortlen,extrabor,deposit,cashdis,mrent,has_mscharge,mscharge,discount,grant
+,completed,,2023-12-08T00:00:00+00:00,2024-05-01T00:00:00+01:00,,2023,single log,false,address line 1 as entered,address line 2 as entered,town or city as entered,county as entered,AB1 2CD,la as entered,DLUHC,DLUHC,billyboy@eyeklaud.com,8,12,2023,,Yes - a discounted ownership scheme,Right to Acquire (RTA),,,,Yes,Yes,Yes,1,,,,,,Address line 1,,Town or city,,SW1A,1AA,1,E09000003,Barnet,2,Flat or maisonette,Purpose built,0,Yes,30,Non-binary,Buyer prefers not to say,17,United Kingdom,,Full-time - 30 hours or more,Yes,Partner,35,Non-binary,Buyer prefers not to say,,Buyer prefers not to say,,Full-time - 30 hours or more,Yes,3,Child,14,Non-binary,,Other,Not known,Non-binary,"In government training into work, such as New Deal",Prefers not to say,Not known,Prefers not to say,Prefers not to say,,,,,Local authority tenant,No,,,No,,,1,1,1,1,,Don't know,,Yes,Yes,No,Yes,Yes,Yes,10000,Yes,Yes,10000,Yes,"Don’t know ",No,,Yes,No,10,,,,,,,,,,,,,,,,,110000.0,,Yes,20000.0,Cambridge Building Society,,10,Yes,80000.0,,,Yes,100.0,,10000.0
diff --git a/spec/jobs/email_csv_job_spec.rb b/spec/jobs/email_csv_job_spec.rb
index 61d5dca74..791c1ec1a 100644
--- a/spec/jobs/email_csv_job_spec.rb
+++ b/spec/jobs/email_csv_job_spec.rb
@@ -90,10 +90,10 @@ describe EmailCsvJob do
end
it "creates a SalesLogCsvService with the correct export type" do
- expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "labels")
+ expect(Csv::SalesLogCsvService).to receive(:new).with(user:, export_type: "labels")
codes_only = false
job.perform(user, nil, {}, nil, nil, codes_only, "sales")
- expect(Csv::SalesLogCsvService).to receive(:new).with(export_type: "codes")
+ expect(Csv::SalesLogCsvService).to receive(:new).with(user:, export_type: "codes")
codes_only = true
job.perform(user, nil, {}, nil, nil, codes_only, "sales")
end
diff --git a/spec/services/csv/lettings_log_csv_service_spec.rb b/spec/services/csv/lettings_log_csv_service_spec.rb
index 7109d0e94..c0232ef5d 100644
--- a/spec/services/csv/lettings_log_csv_service_spec.rb
+++ b/spec/services/csv/lettings_log_csv_service_spec.rb
@@ -41,6 +41,12 @@ RSpec.describe Csv::LettingsLogCsvService do
relat4: "R",
age4_known: 1,
incref: 0,
+ address_line1_as_entered: "address line 1 as entered",
+ address_line2_as_entered: "address line 2 as entered",
+ town_or_city_as_entered: "town or city as entered",
+ county_as_entered: "county as entered",
+ postcode_full_as_entered: "AB1 2CD",
+ la_as_entered: "la as entered",
)
end
let(:user) { create(:user, :support, email: "s.port@jeemayle.com") }
diff --git a/spec/services/csv/sales_log_csv_service_spec.rb b/spec/services/csv/sales_log_csv_service_spec.rb
index 79efaf920..e34595942 100644
--- a/spec/services/csv/sales_log_csv_service_spec.rb
+++ b/spec/services/csv/sales_log_csv_service_spec.rb
@@ -5,7 +5,7 @@ RSpec.describe Csv::SalesLogCsvService do
let(:organisation) { create(:organisation) }
let(:fixed_time) { Time.zone.local(2023, 12, 8) }
let(:now) { Time.zone.now }
- let(:user) { create(:user, email: "billyboy@eyeKLAUD.com") }
+ let(:user) { create(:user, :support, email: "billyboy@eyeKLAUD.com") }
let(:log) do
create(
:sales_log,
@@ -24,9 +24,15 @@ RSpec.describe Csv::SalesLogCsvService do
ecstat6: nil,
relat6: nil,
sex6: nil,
+ address_line1_as_entered: "address line 1 as entered",
+ address_line2_as_entered: "address line 2 as entered",
+ town_or_city_as_entered: "town or city as entered",
+ county_as_entered: "county as entered",
+ postcode_full_as_entered: "AB1 2CD",
+ la_as_entered: "la as entered",
)
end
- let(:service) { described_class.new(export_type: "labels") }
+ let(:service) { described_class.new(user:, export_type: "labels") }
let(:csv) { CSV.parse(service.prepare_csv(SalesLog.all)) }
before do
@@ -201,7 +207,7 @@ RSpec.describe Csv::SalesLogCsvService do
end
context "when exporting values as codes" do
- let(:service) { described_class.new(export_type: "codes") }
+ let(:service) { described_class.new(user:, export_type: "codes") }
it "gives answers to radio questions as their codes" do
national_column_index = csv.first.index("national")
diff --git a/spec/services/exports/lettings_log_export_service_spec.rb b/spec/services/exports/lettings_log_export_service_spec.rb
index 6141207d1..2e534f748 100644
--- a/spec/services/exports/lettings_log_export_service_spec.rb
+++ b/spec/services/exports/lettings_log_export_service_spec.rb
@@ -472,7 +472,7 @@ RSpec.describe Exports::LettingsLogExportService do
end
context "and one lettings log is available for export" do
- let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, created_by: user, ppostcode_full: "A1 1AA", nationality_all_group: 13, propcode: "123", postcode_full: "SE2 6RT", tenancycode: "BZ737", startdate: Time.zone.local(2024, 4, 2, 10, 36, 49), voiddate: Time.zone.local(2021, 11, 3), mrcdate: Time.zone.local(2022, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4) }
+ let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, created_by: user, ppostcode_full: "A1 1AA", nationality_all_group: 13, propcode: "123", postcode_full: "SE2 6RT", tenancycode: "BZ737", startdate: Time.zone.local(2024, 4, 2, 10, 36, 49), voiddate: Time.zone.local(2021, 11, 3), mrcdate: Time.zone.local(2022, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4, address_line1_as_entered: "address line 1 as entered", address_line2_as_entered: "address line 2 as entered", town_or_city_as_entered: "town or city as entered", county_as_entered: "county as entered", postcode_full_as_entered: "AB1 2CD", la_as_entered: "la as entered") }
let(:expected_zip_filename) { "core_2024_2025_apr_mar_f0001_inc0001.zip" }
let(:expected_data_filename) { "core_2024_2025_apr_mar_f0001_inc0001_pt001.xml" }
let(:xml_export_file) { File.open("spec/fixtures/exports/general_needs_log_24_25.xml", "r:UTF-8") }
From 9dc37f7fff1aa6ccbec213200192a73ab2afd7ff Mon Sep 17 00:00:00 2001
From: Rachael Booth
Date: Wed, 20 Mar 2024 15:38:15 +0000
Subject: [PATCH 3/4] CLDC-3304: Add bulk upload id to xml exports from 2024
(#2323)
---
app/services/exports/lettings_log_export_constants.rb | 2 ++
spec/fixtures/exports/general_needs_log_24_25.xml | 3 ++-
spec/services/exports/lettings_log_export_service_spec.rb | 2 +-
3 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/app/services/exports/lettings_log_export_constants.rb b/app/services/exports/lettings_log_export_constants.rb
index c60f1339d..0e6edd139 100644
--- a/app/services/exports/lettings_log_export_constants.rb
+++ b/app/services/exports/lettings_log_export_constants.rb
@@ -141,6 +141,7 @@ module Exports::LettingsLogExportConstants
"duplicate_set_id",
"accessible_register",
"nationality_all",
+ "bulk_upload_id",
"address_line1_as_entered",
"address_line2_as_entered",
"town_or_city_as_entered",
@@ -167,6 +168,7 @@ module Exports::LettingsLogExportConstants
POST_2024_EXPORT_FIELDS = Set[
"accessible_register",
"nationality_all",
+ "bulk_upload_id",
"address_line1_as_entered",
"address_line2_as_entered",
"town_or_city_as_entered",
diff --git a/spec/fixtures/exports/general_needs_log_24_25.xml b/spec/fixtures/exports/general_needs_log_24_25.xml
index f21e20f47..3b27d50af 100644
--- a/spec/fixtures/exports/general_needs_log_24_25.xml
+++ b/spec/fixtures/exports/general_needs_log_24_25.xml
@@ -134,6 +134,7 @@
4
2
698
+ 1
0
@@ -142,7 +143,7 @@
London
- 1
+ 2
2
diff --git a/spec/services/exports/lettings_log_export_service_spec.rb b/spec/services/exports/lettings_log_export_service_spec.rb
index 2e534f748..dd2230598 100644
--- a/spec/services/exports/lettings_log_export_service_spec.rb
+++ b/spec/services/exports/lettings_log_export_service_spec.rb
@@ -472,7 +472,7 @@ RSpec.describe Exports::LettingsLogExportService do
end
context "and one lettings log is available for export" do
- let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, created_by: user, ppostcode_full: "A1 1AA", nationality_all_group: 13, propcode: "123", postcode_full: "SE2 6RT", tenancycode: "BZ737", startdate: Time.zone.local(2024, 4, 2, 10, 36, 49), voiddate: Time.zone.local(2021, 11, 3), mrcdate: Time.zone.local(2022, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4, address_line1_as_entered: "address line 1 as entered", address_line2_as_entered: "address line 2 as entered", town_or_city_as_entered: "town or city as entered", county_as_entered: "county as entered", postcode_full_as_entered: "AB1 2CD", la_as_entered: "la as entered") }
+ let!(:lettings_log) { FactoryBot.create(:lettings_log, :completed, created_by: user, ppostcode_full: "A1 1AA", nationality_all_group: 13, propcode: "123", postcode_full: "SE2 6RT", tenancycode: "BZ737", startdate: Time.zone.local(2024, 4, 2, 10, 36, 49), voiddate: Time.zone.local(2021, 11, 3), mrcdate: Time.zone.local(2022, 5, 5, 10, 36, 49), tenancylength: 5, underoccupation_benefitcap: 4, creation_method: 2, bulk_upload_id: 1, address_line1_as_entered: "address line 1 as entered", address_line2_as_entered: "address line 2 as entered", town_or_city_as_entered: "town or city as entered", county_as_entered: "county as entered", postcode_full_as_entered: "AB1 2CD", la_as_entered: "la as entered") }
let(:expected_zip_filename) { "core_2024_2025_apr_mar_f0001_inc0001.zip" }
let(:expected_data_filename) { "core_2024_2025_apr_mar_f0001_inc0001_pt001.xml" }
let(:xml_export_file) { File.open("spec/fixtures/exports/general_needs_log_24_25.xml", "r:UTF-8") }
From e52a8238cc41528219921fe94b2412745dcee047 Mon Sep 17 00:00:00 2001
From: kosiakkatrina <54268893+kosiakkatrina@users.noreply.github.com>
Date: Wed, 20 Mar 2024 15:44:36 +0000
Subject: [PATCH 4/4] CLDC-3343 Check relat fields for people we collect data
for (#2335)
* Check relat fields for people we collect data for
* rename
---
app/models/validations/soft_validations.rb | 3 +-
.../sales/soft_validations_spec.rb | 38 +++++++++++++++++++
2 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/app/models/validations/soft_validations.rb b/app/models/validations/soft_validations.rb
index d5c301066..7be2f5090 100644
--- a/app/models/validations/soft_validations.rb
+++ b/app/models/validations/soft_validations.rb
@@ -194,7 +194,8 @@ module Validations::SoftValidations
def multiple_partners?
return unless hhmemb
- (2..hhmemb).many? { |n| public_send("relat#{n}") == "P" }
+ max_person_with_details = sales? ? [hhmemb, 6].min : [hhmemb, 8].min
+ (2..max_person_with_details).many? { |n| public_send("relat#{n}") == "P" }
end
private
diff --git a/spec/models/validations/sales/soft_validations_spec.rb b/spec/models/validations/sales/soft_validations_spec.rb
index 299968436..b64eb1bde 100644
--- a/spec/models/validations/sales/soft_validations_spec.rb
+++ b/spec/models/validations/sales/soft_validations_spec.rb
@@ -1324,4 +1324,42 @@ RSpec.describe Validations::Sales::SoftValidations do
end
end
end
+
+ describe "#multiple_partners?" do
+ let(:record) { FactoryBot.create(:sales_log, :completed, ownershipsch: 1, jointpur: 1) }
+
+ context "when there are multiple partners" do
+ before do
+ record.hhmemb = 3
+ record.relat2 = "P"
+ record.relat3 = "P"
+ end
+
+ it "returns true" do
+ expect(record).to be_multiple_partners
+ end
+ end
+
+ context "when there are not multiple partners" do
+ before do
+ record.hhmemb = 2
+ record.relat2 = "P"
+ end
+
+ it "returns false" do
+ expect(record).not_to be_multiple_partners
+ end
+ end
+
+ context "when hhmemb is more than the number of person details we require for joint purchase" do
+ before do
+ record.hhmemb = 14
+ record.relat2 = "P"
+ end
+
+ it "correctly runs the method" do
+ expect(record).not_to be_multiple_partners
+ end
+ end
+ end
end