From d2fff168084a781deab7665389ac2cb2b6b1c88c Mon Sep 17 00:00:00 2001 From: Katherine Langford Date: Tue, 10 Feb 2026 15:29:03 +0000 Subject: [PATCH] CLDC-4177: New Sex At Birth question for sales logs (#3144) * CLDC-4177: Create new sex-at-birth question * CLDC-4177: Update database * CLDC-4177: Adds SAB form for the primary buyer. * CLDC-4177: Adds sex-at-birth question for other household members * CLCD-4177: Unit tests * CLDC-4177: Misc inclusions where sex is also used * CLDC-4177: Lint fixes * CLDC-4177: Do not include sexRAB in pre-2026 exports * CLDC-4177: Fixes bug with copy key in new page * CLDC-4177: Changes logic used to decide which fields to export * CLDC-4177: Linting fixes * CLDC-4177: Converts new field to lowercase * CLDC-4177: Satisfy bulk upload tests (not tested manually) * CLDC-4177: Rename new fields to lowercase * CLDC-4177: Rename field in bulk upload. * Fix db casing * CLDC-4177: remove frozen string literals * Delete redundant migration * Remove extraneous lines from schema.rb * Add new sexrab fields to the :completed trait in the Sales Log factory * CLDC-4177: remove redundant inferred CYA vals * CLDC-4177: update bu files * CLDC-4177: update sales log export service * CLDC-4177: update schema * CLDC-4177: linting * CLDC-4177: update sales log export constants * CLDC-4177: update factories * CLDC-4177: lint * CLDC-4177: csv parser updates * CLDC-4177: bu field updates * CLDC-4177: update var def spec * CLDC-4177: make to_2026_row explicit * CLDC-4177: use shared field count * CLDC-4177: refactor to remove max cols going forwards * CLDC-4141: update schema * CLDC-4141: update schema * CLDC-4141: update schema * CLDC-4141: remove X from factory options * CLDC-4177: update log var defs * CLDC-4177: use correct shared field count * CLDC-4177: remove trailing commas * CLDC-4177: update bulk upload csv example * CLDC-4177: update bulk upload csv example * CLDC-4177: remove sexrab from expected sales export for now --------- Co-authored-by: oscar-richardson-softwire Co-authored-by: Nat Dean-Lewis --- app/helpers/bulk_upload/sales_log_to_csv.rb | 142 ++++++++- .../pages/person_sex_registered_at_birth.rb | 16 + .../sales/pages/sex_registered_at_birth1.rb | 20 ++ .../sales/pages/sex_registered_at_birth2.rb | 23 ++ .../person_sex_registered_at_birth.rb | 19 ++ .../questions/sex_registered_at_birth1.rb | 19 ++ .../questions/sex_registered_at_birth2.rb | 20 ++ .../subsections/household_characteristics.rb | 7 + app/services/bulk_upload/sales/validator.rb | 2 +- .../bulk_upload/sales/year2026/csv_parser.rb | 3 +- .../bulk_upload/sales/year2026/row_parser.rb | 40 ++- app/services/csv/sales_log_csv_service.rb | 1 + .../exports/sales_log_export_constants.rb | 268 ++++++++-------- .../exports/sales_log_export_service.rb | 26 +- .../sales/household_characteristics.en.yml | 49 +++ ...d_sex_registered_at_birth_to_sales_logs.rb | 12 + db/schema.rb | 8 +- spec/factories/sales_log.rb | 13 + .../files/2026_27_sales_bulk_upload.csv | 20 +- .../sales_download_26_27.csv | 287 ++++++++++++++++++ .../tasks/log_variable_definitions_spec.rb | 5 +- .../person_sex_registered_at_birth_spec.rb | 104 +++++++ .../pages/sex_registered_at_birth1_spec.rb | 29 ++ .../pages/sex_registered_at_birth2_spec.rb | 38 +++ .../person_sex_registered_at_birth_spec.rb | 123 ++++++++ .../sex_registered_at_birth1_spec.rb | 49 +++ .../sex_registered_at_birth2_spec.rb | 49 +++ .../household_characteristics_spec.rb | 131 ++++++++ .../bulk_upload/sales/validator_spec.rb | 2 +- .../sales/year2026/csv_parser_spec.rb | 8 +- .../sales/year2026/row_parser_spec.rb | 8 +- .../variable_definitions_service_spec.rb | 4 +- 32 files changed, 1378 insertions(+), 167 deletions(-) create mode 100644 app/models/form/sales/pages/person_sex_registered_at_birth.rb create mode 100644 app/models/form/sales/pages/sex_registered_at_birth1.rb create mode 100644 app/models/form/sales/pages/sex_registered_at_birth2.rb create mode 100644 app/models/form/sales/questions/person_sex_registered_at_birth.rb create mode 100644 app/models/form/sales/questions/sex_registered_at_birth1.rb create mode 100644 app/models/form/sales/questions/sex_registered_at_birth2.rb create mode 100644 db/migrate/20260113143404_add_sex_registered_at_birth_to_sales_logs.rb create mode 100644 spec/fixtures/variable_definitions/sales_download_26_27.csv create mode 100644 spec/models/form/sales/pages/person_sex_registered_at_birth_spec.rb create mode 100644 spec/models/form/sales/pages/sex_registered_at_birth1_spec.rb create mode 100644 spec/models/form/sales/pages/sex_registered_at_birth2_spec.rb create mode 100644 spec/models/form/sales/questions/person_sex_registered_at_birth_spec.rb create mode 100644 spec/models/form/sales/questions/sex_registered_at_birth1_spec.rb create mode 100644 spec/models/form/sales/questions/sex_registered_at_birth2_spec.rb diff --git a/app/helpers/bulk_upload/sales_log_to_csv.rb b/app/helpers/bulk_upload/sales_log_to_csv.rb index 18e58655b..1171f481f 100644 --- a/app/helpers/bulk_upload/sales_log_to_csv.rb +++ b/app/helpers/bulk_upload/sales_log_to_csv.rb @@ -70,8 +70,7 @@ class BulkUpload::SalesLogToCsv when 2025 (1..121).to_a when 2026 - # TODO: CLDC-4162: Replace with actual field numbers when 2026 format is known - (1..121).to_a + (1..BulkUpload::Sales::Year2026::CsvParser::FIELDS).to_a else raise NotImplementedError "No mapping function implemented for year #{year}" end @@ -537,7 +536,144 @@ class BulkUpload::SalesLogToCsv def to_2026_row # TODO: CLDC-4162: Implement when 2026 template is available - to_2025_row + [ + log.saledate&.day, + log.saledate&.month, + log.saledate&.strftime("%y"), + overrides[:organisation_id] || log.owning_organisation&.old_visible_id, + overrides[:managing_organisation_id] || log.managing_organisation&.old_visible_id, + log.assigned_to&.email, + log.purchid, + log.ownershipsch, + log.ownershipsch == 1 ? log.type : "", # field_9: "What is the type of shared ownership sale?", + log.staircase, # 10 + log.ownershipsch == 2 ? log.type : "", # field_11: "What is the type of discounted ownership sale?", + log.jointpur, + log.jointmore, + log.noint, + log.privacynotice, + + log.uprn, + log.address_line1&.tr(",", " "), # 20 + log.address_line2&.tr(",", " "), + log.town_or_city&.tr(",", " "), + log.county&.tr(",", " "), + ((log.postcode_full || "").split(" ") || [""]).first, + ((log.postcode_full || "").split(" ") || [""]).last, + log.la, + log.proptype, + log.beds, + log.builtype, + log.wchair, + + log.age1, + log.sex1, + log.ethnic, # 30 + log.nationality_all_group, + log.ecstat1, + log.buy1livein, + { "P" => 1, "X" => 2, "R" => 3 }[log.relat2], + log.age2, + log.sex2, + log.ethnic_group2, + log.nationality_all_buyer2_group, + log.ecstat2, + log.buy2livein, # 40 + log.hholdcount, + + { "P" => 1, "X" => 2, "R" => 3 }[log.relat3], + log.age3, + log.sex3, + log.ecstat3, + { "P" => 1, "X" => 2, "R" => 3 }[log.relat4], + log.age4, + log.sex4, + log.ecstat4, + { "P" => 1, "X" => 2, "R" => 3 }[log.relat5], # 50 + log.age5, + log.sex5, + log.ecstat5, + { "P" => 1, "X" => 2, "R" => 3 }[log.relat6], + log.age6, + log.sex6, + log.ecstat6, + + log.prevten, + log.ppcodenk, + ((log.ppostcode_full || "").split(" ") || [""]).first, # 60 + ((log.ppostcode_full || "").split(" ") || [""]).last, + log.prevloc, + log.buy2living, + log.prevtenbuy2, + + log.hhregres, + log.hhregresstill, + log.armedforcesspouse, + log.disabled, + log.wheel, + + log.income1, # 70 + log.inc1mort, + log.income2, + log.inc2mort, + log.hb, + log.savings.present? || "R", + log.prevown, + log.prevshared, + + log.resale, + log.proplen, + log.hodate&.day, # 80 + log.hodate&.month, + log.hodate&.strftime("%y"), + log.frombeds, + log.fromprop, + log.socprevten, + log.value, + log.equity, + log.mortgageused, + log.mortgage, + log.mortlen, # 90 + log.deposit, + log.cashdis, + log.mrent, + log.mscharge, + log.management_fee, + + log.stairbought, + log.stairowned, + log.staircasesale, + log.firststair, + log.initialpurchase&.day, # 100 + log.initialpurchase&.month, + log.initialpurchase&.strftime("%y"), + log.numstair, + log.lasttransaction&.day, + log.lasttransaction&.month, + log.lasttransaction&.strftime("%y"), + log.value, + log.equity, + log.mortgageused, + log.mrentprestaircasing, # 110 + log.mrent, + + log.proplen, + log.value, + log.grant, + log.discount, + log.mortgageused, + log.mortgage, + log.mortlen, + log.extrabor, + log.deposit, # 120 + log.mscharge, + log.sexrab1, + log.sexrab2, + log.sexrab3, + log.sexrab4, + log.sexrab5, + log.sexrab6, # 127 + ] end def custom_field_numbers_row(seed: nil, field_numbers: nil) diff --git a/app/models/form/sales/pages/person_sex_registered_at_birth.rb b/app/models/form/sales/pages/person_sex_registered_at_birth.rb new file mode 100644 index 000000000..b2ea1da20 --- /dev/null +++ b/app/models/form/sales/pages/person_sex_registered_at_birth.rb @@ -0,0 +1,16 @@ +class Form::Sales::Pages::PersonSexRegisteredAtBirth < ::Form::Page + def initialize(id, hsh, subsection, person_index:) + super(id, hsh, subsection) + @copy_key = "sales.household_characteristics.sexrab2.person" if person_index == 2 + @person_index = person_index + @depends_on = [ + { "details_known_#{person_index}" => 1 }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::PersonSexRegisteredAtBirth.new("sexrab#{@person_index}", nil, self, person_index: @person_index), + ] + end +end diff --git a/app/models/form/sales/pages/sex_registered_at_birth1.rb b/app/models/form/sales/pages/sex_registered_at_birth1.rb new file mode 100644 index 000000000..4e6f012a9 --- /dev/null +++ b/app/models/form/sales/pages/sex_registered_at_birth1.rb @@ -0,0 +1,20 @@ +class Form::Sales::Pages::SexRegisteredAtBirth1 < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_1_sex_registered_at_birth" + @depends_on = [ + { + "buyer_has_seen_privacy_notice?" => true, + }, + { + "buyer_not_interviewed?" => true, + }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::SexRegisteredAtBirth1.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/pages/sex_registered_at_birth2.rb b/app/models/form/sales/pages/sex_registered_at_birth2.rb new file mode 100644 index 000000000..49ce339c4 --- /dev/null +++ b/app/models/form/sales/pages/sex_registered_at_birth2.rb @@ -0,0 +1,23 @@ +class Form::Sales::Pages::SexRegisteredAtBirth2 < ::Form::Page + def initialize(id, hsh, subsection) + super + @id = "buyer_2_sex_registered_at_birth" + @copy_key = "sales.household_characteristics.sexrab2.buyer" + @depends_on = [ + { + "joint_purchase?" => true, + "buyer_has_seen_privacy_notice?" => true, + }, + { + "joint_purchase?" => true, + "buyer_not_interviewed?" => true, + }, + ] + end + + def questions + @questions ||= [ + Form::Sales::Questions::SexRegisteredAtBirth2.new(nil, nil, self), + ] + end +end diff --git a/app/models/form/sales/questions/person_sex_registered_at_birth.rb b/app/models/form/sales/questions/person_sex_registered_at_birth.rb new file mode 100644 index 000000000..ff61f3ee0 --- /dev/null +++ b/app/models/form/sales/questions/person_sex_registered_at_birth.rb @@ -0,0 +1,19 @@ +class Form::Sales::Questions::PersonSexRegisteredAtBirth < ::Form::Question + def initialize(id, hsh, page, person_index:) + super(id, hsh, page) + @type = "radio" + @copy_key = "sales.household_characteristics.sexrab2.person" if person_index == 2 + @check_answers_card_number = person_index + @answer_options = ANSWER_OPTIONS + @question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] + end + + ANSWER_OPTIONS = { + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Person prefers not to say" }, + }.freeze + + QUESTION_NUMBER_FROM_YEAR = { 2026 => 0 }.freeze +end diff --git a/app/models/form/sales/questions/sex_registered_at_birth1.rb b/app/models/form/sales/questions/sex_registered_at_birth1.rb new file mode 100644 index 000000000..77a8e3fc3 --- /dev/null +++ b/app/models/form/sales/questions/sex_registered_at_birth1.rb @@ -0,0 +1,19 @@ +class Form::Sales::Questions::SexRegisteredAtBirth1 < ::Form::Question + def initialize(id, hsh, page) + super + @id = "sexrab1" + @type = "radio" + @check_answers_card_number = 1 + @answer_options = ANSWER_OPTIONS + @question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] + end + + ANSWER_OPTIONS = { + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Buyer prefers not to say" }, + }.freeze + + QUESTION_NUMBER_FROM_YEAR = { 2026 => 0 }.freeze +end diff --git a/app/models/form/sales/questions/sex_registered_at_birth2.rb b/app/models/form/sales/questions/sex_registered_at_birth2.rb new file mode 100644 index 000000000..6f9c77eb4 --- /dev/null +++ b/app/models/form/sales/questions/sex_registered_at_birth2.rb @@ -0,0 +1,20 @@ +class Form::Sales::Questions::SexRegisteredAtBirth2 < ::Form::Question + def initialize(id, hsh, page) + super + @id = "sexrab2" + @type = "radio" + @copy_key = "sales.household_characteristics.sexrab2.buyer" + @check_answers_card_number = 2 + @answer_options = ANSWER_OPTIONS + @question_number = QUESTION_NUMBER_FROM_YEAR[form.start_date.year] || QUESTION_NUMBER_FROM_YEAR[QUESTION_NUMBER_FROM_YEAR.keys.max] + end + + ANSWER_OPTIONS = { + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Buyer prefers not to say" }, + }.freeze + + QUESTION_NUMBER_FROM_YEAR = { 2026 => 0 }.freeze +end diff --git a/app/models/form/sales/subsections/household_characteristics.rb b/app/models/form/sales/subsections/household_characteristics.rb index a1f21ae8e..47466a492 100644 --- a/app/models/form/sales/subsections/household_characteristics.rb +++ b/app/models/form/sales/subsections/household_characteristics.rb @@ -24,6 +24,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_1_not_retired_value_check", nil, self, person_index: 1) if form.start_year_2024_or_later?), Form::Sales::Pages::OldPersonsSharedOwnershipValueCheck.new("age_1_old_persons_shared_ownership_joint_purchase_value_check", nil, self, joint_purchase: true), Form::Sales::Pages::OldPersonsSharedOwnershipValueCheck.new("age_1_old_persons_shared_ownership_value_check", nil, self, joint_purchase: false), + (Form::Sales::Pages::SexRegisteredAtBirth1.new(nil, nil, self) if form.start_year_2026_or_later?), Form::Sales::Pages::GenderIdentity1.new(nil, nil, self), Form::Sales::Pages::Buyer1EthnicGroup.new(nil, nil, self), Form::Sales::Pages::Buyer1EthnicBackgroundBlack.new(nil, nil, self), @@ -46,6 +47,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection Form::Sales::Pages::RetirementValueCheck.new("age_2_buyer_retirement_value_check", nil, self, person_index: 2), (Form::Sales::Pages::NotRetiredValueCheck.new("age_2_buyer_not_retired_value_check", nil, self, person_index: 2) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("buyer_2_age_student_not_child_value_check", nil, self, person_index: 2) unless form.start_year_2025_or_later?), + (Form::Sales::Pages::SexRegisteredAtBirth2.new(nil, nil, self) if form.start_year_2026_or_later?), Form::Sales::Pages::GenderIdentity2.new(nil, nil, self), buyer_2_ethnicity_nationality_pages, Form::Sales::Pages::Buyer2WorkingSituation.new(nil, nil, self), @@ -67,6 +69,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_2_not_retired_value_check", nil, self, person_index: 2) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("age_2_student_not_child_value_check", nil, self, person_index: 2) unless form.start_year_2025_or_later?), (Form::Sales::Pages::PartnerUnder16ValueCheck.new("age_2_partner_under_16_value_check", nil, self, person_index: 2) if form.start_year_2024_or_later?), + (Form::Sales::Pages::PersonSexRegisteredAtBirth.new("person_2_sex_registered_at_birth", nil, self, person_index: 2) if form.start_year_2026_or_later?), Form::Sales::Pages::PersonGenderIdentity.new("person_2_gender_identity", nil, self, person_index: 2), Form::Sales::Pages::PersonWorkingSituation.new("person_2_working_situation", nil, self, person_index: 2), Form::Sales::Pages::RetirementValueCheck.new("working_situation_2_retirement_value_check", nil, self, person_index: 2), @@ -82,6 +85,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_3_not_retired_value_check", nil, self, person_index: 3) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("age_3_student_not_child_value_check", nil, self, person_index: 3) unless form.start_year_2025_or_later?), (Form::Sales::Pages::PartnerUnder16ValueCheck.new("age_3_partner_under_16_value_check", nil, self, person_index: 3) if form.start_year_2024_or_later?), + (Form::Sales::Pages::PersonSexRegisteredAtBirth.new("person_3_sex_registered_at_birth", nil, self, person_index: 3) if form.start_year_2026_or_later?), Form::Sales::Pages::PersonGenderIdentity.new("person_3_gender_identity", nil, self, person_index: 3), Form::Sales::Pages::PersonWorkingSituation.new("person_3_working_situation", nil, self, person_index: 3), Form::Sales::Pages::RetirementValueCheck.new("working_situation_3_retirement_value_check", nil, self, person_index: 3), @@ -97,6 +101,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_4_not_retired_value_check", nil, self, person_index: 4) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("age_4_student_not_child_value_check", nil, self, person_index: 4) unless form.start_year_2025_or_later?), (Form::Sales::Pages::PartnerUnder16ValueCheck.new("age_4_partner_under_16_value_check", nil, self, person_index: 4) if form.start_year_2024_or_later?), + (Form::Sales::Pages::PersonSexRegisteredAtBirth.new("person_4_sex_registered_at_birth", nil, self, person_index: 4) if form.start_year_2026_or_later?), Form::Sales::Pages::PersonGenderIdentity.new("person_4_gender_identity", nil, self, person_index: 4), Form::Sales::Pages::PersonWorkingSituation.new("person_4_working_situation", nil, self, person_index: 4), Form::Sales::Pages::RetirementValueCheck.new("working_situation_4_retirement_value_check", nil, self, person_index: 4), @@ -112,6 +117,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_5_not_retired_value_check", nil, self, person_index: 5) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("age_5_student_not_child_value_check", nil, self, person_index: 5) unless form.start_year_2025_or_later?), (Form::Sales::Pages::PartnerUnder16ValueCheck.new("age_5_partner_under_16_value_check", nil, self, person_index: 5) if form.start_year_2024_or_later?), + (Form::Sales::Pages::PersonSexRegisteredAtBirth.new("person_5_sex_registered_at_birth", nil, self, person_index: 5) if form.start_year_2026_or_later?), Form::Sales::Pages::PersonGenderIdentity.new("person_5_gender_identity", nil, self, person_index: 5), Form::Sales::Pages::PersonWorkingSituation.new("person_5_working_situation", nil, self, person_index: 5), Form::Sales::Pages::RetirementValueCheck.new("working_situation_5_retirement_value_check", nil, self, person_index: 5), @@ -127,6 +133,7 @@ class Form::Sales::Subsections::HouseholdCharacteristics < ::Form::Subsection (Form::Sales::Pages::NotRetiredValueCheck.new("age_6_not_retired_value_check", nil, self, person_index: 6) if form.start_year_2024_or_later?), (Form::Sales::Pages::PersonStudentNotChildValueCheck.new("age_6_student_not_child_value_check", nil, self, person_index: 6) unless form.start_year_2025_or_later?), (Form::Sales::Pages::PartnerUnder16ValueCheck.new("age_6_partner_under_16_value_check", nil, self, person_index: 6) if form.start_year_2024_or_later?), + (Form::Sales::Pages::PersonSexRegisteredAtBirth.new("person_6_sex_registered_at_birth", nil, self, person_index: 6) if form.start_year_2026_or_later?), Form::Sales::Pages::PersonGenderIdentity.new("person_6_gender_identity", nil, self, person_index: 6), Form::Sales::Pages::PersonWorkingSituation.new("person_6_working_situation", nil, self, person_index: 6), Form::Sales::Pages::RetirementValueCheck.new("working_situation_6_retirement_value_check", nil, self, person_index: 6), diff --git a/app/services/bulk_upload/sales/validator.rb b/app/services/bulk_upload/sales/validator.rb index c26d8d1ca..7b1dbd48e 100644 --- a/app/services/bulk_upload/sales/validator.rb +++ b/app/services/bulk_upload/sales/validator.rb @@ -167,7 +167,7 @@ private column_count = rows.map(&:size).max - errors.add(:base, I18n.t("validations.sales.#{@bulk_upload.year}.bulk_upload.wrong_template.over_max_column_count")) if column_count > csv_parser.class::MAX_COLUMNS + errors.add(:base, I18n.t("validations.sales.#{@bulk_upload.year}.bulk_upload.wrong_template.over_max_column_count")) if column_count > csv_parser.class::FIELDS + 1 end def validate_correct_template diff --git a/app/services/bulk_upload/sales/year2026/csv_parser.rb b/app/services/bulk_upload/sales/year2026/csv_parser.rb index a512e2f44..78e467807 100644 --- a/app/services/bulk_upload/sales/year2026/csv_parser.rb +++ b/app/services/bulk_upload/sales/year2026/csv_parser.rb @@ -4,8 +4,7 @@ class BulkUpload::Sales::Year2026::CsvParser include CollectionTimeHelper # TODO: CLDC-4162: Update when 2026 format is known - FIELDS = 121 - MAX_COLUMNS = 142 + FIELDS = 127 FORM_YEAR = 2026 attr_reader :path diff --git a/app/services/bulk_upload/sales/year2026/row_parser.rb b/app/services/bulk_upload/sales/year2026/row_parser.rb index 1010296f6..adb7cc6a2 100644 --- a/app/services/bulk_upload/sales/year2026/row_parser.rb +++ b/app/services/bulk_upload/sales/year2026/row_parser.rb @@ -135,6 +135,13 @@ class BulkUpload::Sales::Year2026::RowParser field_119: "Does this include any extra borrowing?", field_120: "How much was the cash deposit paid on the property?", field_121: "What are the total monthly leasehold charges for the property?", + + field_122: "Buyer 1's sex, as registered at birth", + field_123: "Buyer/Person 2's sex, as registered at birth", + field_124: "Person 3's sex, as registered at birth", + field_125: "Person 4's sex, as registered at birth", + field_126: "Person 5's sex, as registered at birth", + field_127: "Person 6's sex, as registered at birth", }.freeze ERROR_BASE_KEY = "validations.sales.2026.bulk_upload".freeze @@ -275,6 +282,13 @@ class BulkUpload::Sales::Year2026::RowParser attribute :field_120, :decimal attribute :field_121, :decimal + attribute :field_122, :string + attribute :field_123, :string + attribute :field_124, :string + attribute :field_125, :string + attribute :field_126, :string + attribute :field_127, :string + validates :field_1, presence: { message: I18n.t("#{ERROR_BASE_KEY}.not_answered", question: "sale completion date (day)."), @@ -513,6 +527,7 @@ class BulkUpload::Sales::Year2026::RowParser "field_22", # postcode "field_28", # age1 "field_29", # sex1 + "field_122", # sexrab1 "field_32", # ecstat1 ) end @@ -780,6 +795,12 @@ private lasttransaction: %i[field_104 field_105 field_106], initialpurchase: %i[field_100 field_101 field_102], + sexrab1: %i[field_122], + sexrab2: %i[field_123], + sexrab3: %i[field_124], + sexrab4: %i[field_125], + sexrab5: %i[field_126], + sexrab6: %i[field_127], } end @@ -815,6 +836,13 @@ private attributes["sex5"] = field_52 attributes["sex6"] = field_56 + attributes["sexrab1"] = field_122 + attributes["sexrab2"] = field_123 + attributes["sexrab3"] = field_124 + attributes["sexrab4"] = field_125 + attributes["sexrab5"] = field_126 + attributes["sexrab6"] = field_127 + attributes["relat2"] = relationship_from_is_partner(field_34) attributes["relat3"] = relationship_from_is_partner(field_42) attributes["relat4"] = relationship_from_is_partner(field_46) @@ -1013,23 +1041,23 @@ private end def person_2_present? - field_35.present? || field_36.present? || field_34.present? + field_35.present? || field_36.present? || field_34.present? || field_123.present? end def person_3_present? - field_43.present? || field_44.present? || field_42.present? + field_43.present? || field_44.present? || field_42.present? || field_124.present? end def person_4_present? - field_47.present? || field_48.present? || field_46.present? + field_47.present? || field_48.present? || field_46.present? || field_125.present? end def person_5_present? - field_51.present? || field_52.present? || field_50.present? + field_51.present? || field_52.present? || field_50.present? || field_126.present? end def person_6_present? - field_55.present? || field_56.present? || field_54.present? + field_55.present? || field_56.present? || field_54.present? || field_127.present? end def relationship_from_is_partner(is_partner) @@ -1241,6 +1269,7 @@ private %w[ saledate age1 + sexrab1 sex1 ecstat1 owning_organisation @@ -1419,6 +1448,7 @@ private errors.add(:field_22, error_message) # Postcode errors.add(:field_28, error_message) # Buyer 1 age errors.add(:field_29, error_message) # Buyer 1 gender + errors.add(:field_122, error_message) # Buyer 1 sex registered at birth errors.add(:field_32, error_message) # Buyer 1 working situation errors.add(:field_7, error_message) # Purchaser code end diff --git a/app/services/csv/sales_log_csv_service.rb b/app/services/csv/sales_log_csv_service.rb index 0b6612a19..ed16653f1 100644 --- a/app/services/csv/sales_log_csv_service.rb +++ b/app/services/csv/sales_log_csv_service.rb @@ -114,6 +114,7 @@ module Csv hash["age1"] = { "refused_code" => "-9", "refused_label" => "Not known", "age_known_field" => "age1_known" } (2..6).each do |i| hash["age#{i}"] = { "refused_code" => "-9", "refused_label" => "Not known", "details_known_field" => "details_known_#{i}", "age_known_field" => "age#{i}_known" } + hash["sexrab#{i}"] = { "refused_code" => "R", "refused_label" => "Prefers not to say", "details_known_field" => "details_known_#{i}" } hash["sex#{i}"] = { "refused_code" => "R", "refused_label" => "Prefers not to say", "details_known_field" => "details_known_#{i}" } hash["relat#{i}"] = { "refused_code" => "R", "refused_label" => "Prefers not to say", "details_known_field" => "details_known_#{i}" } hash["ecstat#{i}"] = { "refused_code" => "10", "refused_label" => "Prefers not to say", "details_known_field" => "details_known_#{i}" } diff --git a/app/services/exports/sales_log_export_constants.rb b/app/services/exports/sales_log_export_constants.rb index 09a0d5d68..6dfb2b334 100644 --- a/app/services/exports/sales_log_export_constants.rb +++ b/app/services/exports/sales_log_export_constants.rb @@ -7,140 +7,148 @@ module Exports::SalesLogExportConstants csv: 2, }.freeze - EXPORT_FIELDS = Set["ID", - "STATUS", - "DAY", - "MONTH", - "YEAR", - "DUPLICATESET", - "CREATEDDATE", - "UPLOADDATE", - "OWNINGORGID", - "OWNINGORGNAME", - "MANINGORGID", - "MANINGORGNAME", - "USERNAME", - "USERNAMEID", - "PURCHID", - "TYPE", - "OWNERSHIP", - "COLLECTIONYEAR", - "JOINTMORE", - "JOINT", - "BEDS", - "ETHNIC", - "ETHNICGROUP1", - "LIVEINBUYER1", - "BUILTYPE", - "PROPTYPE", - "NOINT", - "LIVEINBUYER2", - "PRIVACYNOTICE", - "WHEEL", - "HHOLDCOUNT", - "LA", - "INCOME1", - "INC1NK", - "INC1MORT", - "INCOME2", - "INC2NK", - "SAVINGSNK", - "SAVINGS", - "PREVOWN", - "AMENDEDBY", - "AMENDEDBYID", - "MORTGAGE", - "INC2MORT", - "HB", - "FROMBEDS", - "STAIRCASE", - "STAIRBOUGHT", - "STAIROWNED", - "MRENT", - "MRENTPRESTAIRCASING", - "RESALE", - "DEPOSIT", - "CASHDIS", - "DISABLED", - "VALUE", - "EQUITY", - "DISCOUNT", - "GRANT", - "PPCODENK", - "PPOSTC1", - "PPOSTC2", - "PREVLOC", - "PREVLOCNAME", - "PREVIOUSLAKNOWN", - "HHREGRES", - "HHREGRESSTILL", - "PROPLEN", - "HASMSCHARGE", - "MSCHARGE", - "PREVTEN", - "MORTGAGEUSED", - "WCHAIR", - "ARMEDFORCESSPOUSE", - "HODAY", - "HOMONTH", - "HOYEAR", - "FROMPROP", - "SOCPREVTEN", - "MORTLEN1", - "EXTRABOR", - "HHTYPE", - "POSTCODE", - "ISLAINFERRED", - "BULKUPLOADID", - "VALUE_VALUE_CHECK", - "PREVSHARED", - "STAIRCASETOSALE", - "ETHNICGROUP2", - "ETHNIC2", - "BUY2LIVING", - "PREVTEN2", - "UPRN", - "ADDRESS1", - "ADDRESS2", - "TOWNCITY", - "COUNTY", - "LANAME", - "CREATIONMETHOD", - "NATIONALITYALL1", - "NATIONALITYALL2", - "MSCHARGE_VALUE_CHECK", - "ADDRESS1INPUT", - "POSTCODEINPUT", - "ADDRESS_SEARCH_VALUE_CHECK", - "UPRNSELECTED", - "BULKADDRESS1", - "BULKADDRESS2", - "BULKTOWNCITY", - "BULKCOUNTY", - "BULKPOSTCODE", - "BULKLA", - "CREATEDBY", - "CREATEDBYID", - "HASESTATEFEE", - "ESTATEFEE", - "FIRSTSTAIR", - "NUMSTAIR", - "STAIRLASTDAY", - "STAIRLASTMONTH", - "STAIRLASTYEAR", - "STAIRINITIALYEAR", - "STAIRINITIALMONTH", - "STAIRINITIALDAY", - "HASSERVICECHARGES", - "SERVICECHARGES",] + ALL_YEAR_EXPORT_FIELDS = Set[ + "ID", + "STATUS", + "DAY", + "MONTH", + "YEAR", + "DUPLICATESET", + "CREATEDDATE", + "UPLOADDATE", + "OWNINGORGID", + "OWNINGORGNAME", + "MANINGORGID", + "MANINGORGNAME", + "USERNAME", + "USERNAMEID", + "PURCHID", + "TYPE", + "OWNERSHIP", + "COLLECTIONYEAR", + "JOINTMORE", + "JOINT", + "BEDS", + "ETHNIC", + "ETHNICGROUP1", + "LIVEINBUYER1", + "BUILTYPE", + "PROPTYPE", + "NOINT", + "LIVEINBUYER2", + "PRIVACYNOTICE", + "WHEEL", + "HHOLDCOUNT", + "LA", + "INCOME1", + "INC1NK", + "INC1MORT", + "INCOME2", + "INC2NK", + "SAVINGSNK", + "SAVINGS", + "PREVOWN", + "AMENDEDBY", + "AMENDEDBYID", + "MORTGAGE", + "INC2MORT", + "HB", + "FROMBEDS", + "STAIRCASE", + "STAIRBOUGHT", + "STAIROWNED", + "MRENT", + "MRENTPRESTAIRCASING", + "RESALE", + "DEPOSIT", + "CASHDIS", + "DISABLED", + "VALUE", + "EQUITY", + "DISCOUNT", + "GRANT", + "PPCODENK", + "PPOSTC1", + "PPOSTC2", + "PREVLOC", + "PREVLOCNAME", + "PREVIOUSLAKNOWN", + "HHREGRES", + "HHREGRESSTILL", + "PROPLEN", + "HASMSCHARGE", + "MSCHARGE", + "PREVTEN", + "MORTGAGEUSED", + "WCHAIR", + "ARMEDFORCESSPOUSE", + "HODAY", + "HOMONTH", + "HOYEAR", + "FROMPROP", + "SOCPREVTEN", + "MORTLEN1", + "EXTRABOR", + "HHTYPE", + "POSTCODE", + "ISLAINFERRED", + "BULKUPLOADID", + "VALUE_VALUE_CHECK", + "PREVSHARED", + "STAIRCASETOSALE", + "ETHNICGROUP2", + "ETHNIC2", + "BUY2LIVING", + "PREVTEN2", + "UPRN", + "ADDRESS1", + "ADDRESS2", + "TOWNCITY", + "COUNTY", + "LANAME", + "CREATIONMETHOD", + "NATIONALITYALL1", + "NATIONALITYALL2", + "MSCHARGE_VALUE_CHECK", + "ADDRESS1INPUT", + "POSTCODEINPUT", + "ADDRESS_SEARCH_VALUE_CHECK", + "UPRNSELECTED", + "BULKADDRESS1", + "BULKADDRESS2", + "BULKTOWNCITY", + "BULKCOUNTY", + "BULKPOSTCODE", + "BULKLA", + "CREATEDBY", + "CREATEDBYID", + "HASESTATEFEE", + "ESTATEFEE", + "FIRSTSTAIR", + "NUMSTAIR", + "STAIRLASTDAY", + "STAIRLASTMONTH", + "STAIRLASTYEAR", + "STAIRINITIALYEAR", + "STAIRINITIALMONTH", + "STAIRINITIALDAY", + "HASSERVICECHARGES", + "SERVICECHARGES", + ] (1..6).each do |index| - EXPORT_FIELDS << "AGE#{index}" - EXPORT_FIELDS << "ECSTAT#{index}" - EXPORT_FIELDS << "SEX#{index}" + ALL_YEAR_EXPORT_FIELDS << "AGE#{index}" + ALL_YEAR_EXPORT_FIELDS << "ECSTAT#{index}" + ALL_YEAR_EXPORT_FIELDS << "SEX#{index}" end (2..6).each do |index| - EXPORT_FIELDS << "RELAT#{index}" + ALL_YEAR_EXPORT_FIELDS << "RELAT#{index}" + end + + YEAR_2026_EXPORT_FIELDS = Set[] + + (1..6).each do |index| + YEAR_2026_EXPORT_FIELDS << "SEXRAB#{index}" end end diff --git a/app/services/exports/sales_log_export_service.rb b/app/services/exports/sales_log_export_service.rb index 7fac8d27e..5b3f719e8 100644 --- a/app/services/exports/sales_log_export_service.rb +++ b/app/services/exports/sales_log_export_service.rb @@ -150,8 +150,23 @@ module Exports attribute_hash end - def is_omitted_field?(field_name, _sales_log) - !EXPORT_FIELDS.include?(field_name) + def is_included_field?(field_name, included_fields) + included_fields.include?(field_name) + end + + def get_included_fields(sales_log) + included_fields = Set[] + included_fields.merge(ALL_YEAR_EXPORT_FIELDS) + + year_fields = case sales_log.collection_start_year + when 2026 + YEAR_2026_EXPORT_FIELDS + else + Set[] + end + + included_fields.merge(year_fields) + included_fields end def build_export_xml(sales_logs) @@ -161,11 +176,12 @@ module Exports attribute_hash = apply_cds_transformation(sales_log, EXPORT_MODE[:xml]) form = doc.create_element("form") doc.at("forms") << form + included_fields = get_included_fields(sales_log) attribute_hash.each do |key, value| - if is_omitted_field?(key, sales_log) - next - else + if is_included_field?(key, included_fields) form << doc.create_element(key, value) + else + next end end end diff --git a/config/locales/forms/2026/sales/household_characteristics.en.yml b/config/locales/forms/2026/sales/household_characteristics.en.yml index 3ca9da212..4bdb07670 100644 --- a/config/locales/forms/2026/sales/household_characteristics.en.yml +++ b/config/locales/forms/2026/sales/household_characteristics.en.yml @@ -16,6 +16,13 @@ en: hint_text: "" question_text: "Age" + sexrab1: + page_header: "" + check_answer_label: "Buyer 1’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the buyer's gender identity." + question_text: "What was buyer 1's sex at birth?" + sex1: page_header: "" check_answer_label: "Buyer 1’s gender identity" @@ -130,6 +137,20 @@ en: hint_text: "" question_text: "Age" + sexrab2: + buyer: + page_header: "" + check_answer_label: "Buyer 2’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the buyer's gender identity." + question_text: "What was buyer 2's sex at birth?" + person: + page_header: "" + check_answer_label: "Person 2’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the person's gender identity." + question_text: "What was person 2's sex at birth?" + sex2: buyer: page_header: "" @@ -266,6 +287,13 @@ en: hint_text: "" question_text: "Age" + sexrab3: + page_header: "" + check_answer_label: "Person 3’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the person's gender identity." + question_text: "What was person 3's sex at birth?" + sex3: page_header: "" check_answer_label: "Person 3’s gender identity" @@ -307,6 +335,13 @@ en: hint_text: "" question_text: "Age" + sexrab4: + page_header: "" + check_answer_label: "Person 4’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the person's gender identity." + question_text: "What was person 4's sex at birth?" + sex4: page_header: "" check_answer_label: "Person 4’s gender identity" @@ -348,6 +383,13 @@ en: hint_text: "" question_text: "Age" + sexrab5: + page_header: "" + check_answer_label: "Person 5’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the person's gender identity." + question_text: "What was person 5's sex at birth?" + sex5: page_header: "" check_answer_label: "Person 5’s gender identity" @@ -389,6 +431,13 @@ en: hint_text: "" question_text: "Age" + sexrab6: + page_header: "" + check_answer_label: "Person 6’s sex registered at birth" + check_answer_prompt: "" + hint_text: "This is the sex that was registered at birth. The next question will ask about the person's gender identity." + question_text: "What was person 6's sex at birth?" + sex6: page_header: "" check_answer_label: "Person 6’s gender identity" diff --git a/db/migrate/20260113143404_add_sex_registered_at_birth_to_sales_logs.rb b/db/migrate/20260113143404_add_sex_registered_at_birth_to_sales_logs.rb new file mode 100644 index 000000000..27273b566 --- /dev/null +++ b/db/migrate/20260113143404_add_sex_registered_at_birth_to_sales_logs.rb @@ -0,0 +1,12 @@ +class AddSexRegisteredAtBirthToSalesLogs < ActiveRecord::Migration[7.2] + def change + change_table :sales_logs, bulk: true do |t| + t.column :sexrab1, :string + t.column :sexrab2, :string + t.column :sexrab3, :string + t.column :sexrab4, :string + t.column :sexrab5, :string + t.column :sexrab6, :string + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c7325e491..727e809c7 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2026_01_23_150201) do +ActiveRecord::Schema[7.2].define(version: 2026_01_28_121417) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -788,6 +788,12 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_23_150201) do t.datetime "lasttransaction" t.datetime "initialpurchase" t.boolean "manual_address_entry_selected", default: false + t.string "sexrab1" + t.string "sexrab2" + t.string "sexrab3" + t.string "sexrab4" + t.string "sexrab5" + t.string "sexrab6" t.index ["assigned_to_id"], name: "index_sales_logs_on_assigned_to_id" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" diff --git a/spec/factories/sales_log.rb b/spec/factories/sales_log.rb index a2e3f7d4c..b98cc6f75 100644 --- a/spec/factories/sales_log.rb +++ b/spec/factories/sales_log.rb @@ -64,6 +64,7 @@ FactoryBot.define do saledate_today age1_known { 1 } age1 { 20 } + sexrab1 { "F" } sex1 { "F" } ecstat1 { 1 } postcode_full { "A1 1AA" } @@ -83,6 +84,7 @@ FactoryBot.define do privacynotice { 1 } age1_known { 0 } age1 { Faker::Number.within(range: 27..45) } + sexrab1 { %w[F M R].sample } sex1 { %w[F M X R].sample } national { 18 } buy1livein { 1 } @@ -93,6 +95,7 @@ FactoryBot.define do builtype { 1 } ethnic { 3 } ethnic_group { 17 } + sexrab2 { %w[F M R].sample } sex2 { "X" } buy2livein { "1" } ecstat1 { "1" } @@ -125,9 +128,13 @@ FactoryBot.define do savingsnk { 1 } prevown { 1 } prevshared { 2 } + sexrab3 { %w[F M R].sample } sex3 { %w[F M X R].sample } + sexrab4 { %w[F M R].sample } sex4 { %w[F M X R].sample } + sexrab5 { %w[F M R].sample } sex5 { %w[F M X R].sample } + sexrab6 { %w[F M R].sample } sex6 { %w[F M X R].sample } mortgage { 20_000 } ecstat3 { 9 } @@ -280,6 +287,7 @@ FactoryBot.define do privacynotice { 1 } age1_known { 0 } age1 { 27 } + sexrab1 { "F" } sex1 { "F" } national { 18 } buy1livein { 1 } @@ -290,6 +298,7 @@ FactoryBot.define do builtype { 1 } ethnic { 3 } ethnic_group { 17 } + sexrab2 { "X" } sex2 { "X" } buy2livein { "1" } ecstat1 { "1" } @@ -322,9 +331,13 @@ FactoryBot.define do savingsnk { 1 } prevown { 1 } prevshared { 2 } + sexrab3 { "F" } sex3 { "F" } + sexrab4 { "X" } sex4 { "X" } + sexrab5 { "M" } sex5 { "M" } + sexrab6 { "X" } sex6 { "X" } mortgage { 20_000 } ecstat3 { 9 } diff --git a/spec/fixtures/files/2026_27_sales_bulk_upload.csv b/spec/fixtures/files/2026_27_sales_bulk_upload.csv index 5373fd723..bf7d70748 100644 --- a/spec/fixtures/files/2026_27_sales_bulk_upload.csv +++ b/spec/fixtures/files/2026_27_sales_bulk_upload.csv @@ -1,23 +1,23 @@ -Section,Setting up this sales log,,,,,,,,,,,,,,,Property information,,,,,,,,,,,,Household characteristics,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Household situation,,,,,,,Other household information,,,,,"Income, benefits and outgoings",,,,,,,,Shared ownership - initial purchase,,,,,,,,,,,,,,,,,,Shared ownership - staircasing transaction,,,,,,,,,,,,,,,,Discounted ownership,,,,,,,,, +Section,Setting up this sales log,,,,,,,,,,,,,,,Property information,,,,,,,,,,,,Household characteristics,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Household situation,,,,,,,Other household information,,,,,"Income, benefits and outgoings",,,,,,,,Shared ownership - initial purchase,,,,,,,,,,,,,,,,,,Shared ownership - staircasing transaction,,,,,,,,,,,,,,,,Discounted ownership,,,,,,,,,,,,,,, Question,What is the sale completion date? - day DD,What is the sale completion date? - month MM,What is the sale completion date? - year YY,Which organisation owned this property before the sale?,Which organisation is reporting this sale?,What is the CORE username of the account this sale log should be assigned to? ,What is the purchaser code?,Is this a shared ownership or discounted ownership sale?,What is the type of shared ownership sale?,Is this a staircasing transaction?,What is the type of discounted ownership sale?,Is this a joint purchase?,Are there more than 2 joint buyers of this property?,Did you interview the buyer to answer these questions?,Has the buyer seen or been given access to the MHCLG privacy notice?,"If known, enter this property’s UPRN",Address Line 1,Address Line 2,Town or city,County,Part 1 of the property's postcode,Part 2 of the property's postcode,What is the property's local authority?,What type of unit is the property?,How many bedrooms does the property have?,Which type of building is the property?,Is the property built or adapted to wheelchair-user standards?,What is buyer 1’s age?,Which of these best describes buyer 1's gender identity?,Which of the following best describes buyer 1's ethnic background?,What is buyer 1's nationality?,Which of these best describes buyer 1’s working situation? ,Will buyer 1 live in the property?,Is buyer 2 the partner of buyer 1?,What is buyer 2 or person 2's age?,Which of these best describes buyer 2 or person 2's gender identity?,Which of the following best describes buyer 2's ethnic background?,What is buyer 2's nationality?,Which of these best describes buyer 2 or person 2’s working situation? ,Will buyer 2 live in the property?,"Besides the buyer(s), how many other people live or will live in the property?",Is person 3 the partner of buyer 1?,What is person 3's age?,Which of these best describes person 3's gender identity?,Which of these best describes person 3’s working situation? ,Is person 4 the partner of buyer 1?,What is person 4's age?,Which of these best describes person 4's gender identity?,Which of these best describes person 4’s working situation? ,Is person 5 the partner of buyer 1?,What is person 5's age?,Which of these best describes person 5's gender identity?,Which of these best describes person 5’s working situation? ,Is person 6 the partner of buyer 1?,What is person 6's age?,Which of these best describes person 6's gender identity?,Which of these best describes person 6’s working situation? ,What was buyer 1's previous tenure?,Do you know the postcode of buyer 1's last settled accommodation?,Part 1 of postcode of buyer 1's last settled accommodation,Part 2 of postcode of buyer 1's last settled accommodation,What is the local authority of buyer 1's last settled accommodation?,"At the time of purchase, was buyer 2 living at the same address as buyer 1?",What was buyer 2's previous tenure?,"Have any of the buyers ever served as a regular in the UK armed forces? -",Is the buyer still serving in the UK armed forces?,Are any of the buyers a spouse or civil partner of a UK armed forces regular who died in service within the last 2 years?,Does anyone in the household consider themselves to have a disability?,Does anyone in the household use a wheelchair?,What is buyer 1's annual income?,Was buyer 1's income used for a mortgage application?,What is buyer 2's annual income?,Was buyer 2's income used for a mortgage application?,Were the buyers receiving any of these housing-related benefits immediately before buying this property?,What is the total amount the buyers had in savings before they paid any deposit for the property?,Have any of the buyers previously owned a property?,Was the previous property under shared ownership?,Is this a resale?,How long did the buyer(s) live in the property before purchasing it?,What is the day of the practical completion or handover date? - DD,What is the month of the practical completion or handover date? - MM,What is the year of the practical completion or handover date? - YY,How many bedrooms did the buyer's previous property have?,What was the previous property type?,What was the buyer’s previous tenure?,What is the full purchase price?,What was the initial percentage share purchased?,Was a mortgage used to buy this property?,What is the mortgage amount?,What is the length of the mortgage in years?,How much was the cash deposit paid on the property?,How much cash discount was given through Social HomeBuy?,What is the basic monthly rent?,What are the total monthly service charges for the property?,What are the total monthly estate management fees for the property?,What percentage of the property has been bought in this staircasing transaction?,What percentage of the property do the buyers now own in total?,Was this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market?,Is this the first time the buyer has engaged in staircasing in the home?,What was the day of the initial purchase of a share in the property? DD,What was the month of the initial purchase of a share in the property? MM,What was the year of the initial purchase of a share in the property? YYYY,"Including this time, how many times has the shared owner engaged in staircasing in the home?",What was the day of the last staircasing transaction? DD,What was the month of the last staircasing transaction? MM,What was the year of the last staircasing transaction? YYYY,What is the full purchase price for this staircasing transaction?,What was the percentage share purchased in the initial transaction?,Was a mortgage used for this staircasing transaction?,What was the basic monthly rent prior to staircasing?,What is the basic monthly rent after staircasing?,How long did the buyer(s) live in the property before purchasing it?,What is the full purchase price?,"What was the amount of any loan, grant, discount or subsidy given?",What was the percentage discount?,Was a mortgage used to buy this property?,What is the mortgage amount?,What is the length of the mortgage in years?,Does this include any extra borrowing?,How much was the cash deposit paid on the property?,What are the total monthly leasehold charges for the property? +",Is the buyer still serving in the UK armed forces?,Are any of the buyers a spouse or civil partner of a UK armed forces regular who died in service within the last 2 years?,Does anyone in the household consider themselves to have a disability?,Does anyone in the household use a wheelchair?,What is buyer 1's annual income?,Was buyer 1's income used for a mortgage application?,What is buyer 2's annual income?,Was buyer 2's income used for a mortgage application?,Were the buyers receiving any of these housing-related benefits immediately before buying this property?,What is the total amount the buyers had in savings before they paid any deposit for the property?,Have any of the buyers previously owned a property?,Was the previous property under shared ownership?,Is this a resale?,How long did the buyer(s) live in the property before purchasing it?,What is the day of the practical completion or handover date? - DD,What is the month of the practical completion or handover date? - MM,What is the year of the practical completion or handover date? - YY,How many bedrooms did the buyer's previous property have?,What was the previous property type?,What was the buyer’s previous tenure?,What is the full purchase price?,What was the initial percentage share purchased?,Was a mortgage used to buy this property?,What is the mortgage amount?,What is the length of the mortgage in years?,How much was the cash deposit paid on the property?,How much cash discount was given through Social HomeBuy?,What is the basic monthly rent?,What are the total monthly service charges for the property?,What are the total monthly estate management fees for the property?,What percentage of the property has been bought in this staircasing transaction?,What percentage of the property do the buyers now own in total?,Was this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market?,Is this the first time the buyer has engaged in staircasing in the home?,What was the day of the initial purchase of a share in the property? DD,What was the month of the initial purchase of a share in the property? MM,What was the year of the initial purchase of a share in the property? YYYY,"Including this time, how many times has the shared owner engaged in staircasing in the home?",What was the day of the last staircasing transaction? DD,What was the month of the last staircasing transaction? MM,What was the year of the last staircasing transaction? YYYY,What is the full purchase price for this staircasing transaction?,What was the percentage share purchased in the initial transaction?,Was a mortgage used for this staircasing transaction?,What was the basic monthly rent prior to staircasing?,What is the basic monthly rent after staircasing?,How long did the buyer(s) live in the property before purchasing it?,What is the full purchase price?,"What was the amount of any loan, grant, discount or subsidy given?",What was the percentage discount?,Was a mortgage used to buy this property?,What is the mortgage amount?,What is the length of the mortgage in years?,Does this include any extra borrowing?,How much was the cash deposit paid on the property?,What are the total monthly leasehold charges for the property?,What was buyer 1's sex at birth?,What was buyer/person 2's sex registered at birth?,What was person 3's sex registered at birth?,What was person 4's sex registered at birth?,What was person 5's sex registered at birth?,What was person 6's sex registered at birth? Additional info,,,,"You can find the org ID on the CORE service under 'Stock owners' or, if your organisation is the stock owner, under 'About your organisation'","You can find the org ID on the CORE service under 'Managing agents' or, if your organisation is the managing agent, under 'About your organisation'","If left empty, the sales log will be assigned to the account used to upload the log.",This is how you usually refer to this buyer on your own systems,"Sales logs are no longer required for outright and other sales. -A shared ownership sale is when the purchaser buys an initial share of up to 75% of the property value and pays rent to the Private Registered Provider (PRP) on the remaining portion, or a subsequent staircasing transaction",See specification for full description of each scheme,"A staircasing transaction is when the household purchases more shares in their property, increasing the proportion they own and decreasing the proportion the housing association owns. Once the household purchases 100% of the shares, they own the property.",See specification for full description of each scheme,This is where two or more people are named as legal owners of the property after the purchase.,,You should still try to answer all questions even if the buyer wasn't interviewed in person,"Make sure the buyer has seen or been given access to the Ministry of Housing, Communities and Local Government (MHCLG) privacy notice before completing this log. This is a legal requirement under data protection legislation.","The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and various industries across the UK. An example UPRN is 10010457355. -The UPRN may not be the same as the property reference assigned by your organisation.",,,,,Combined with field 28 it should be a postcode which lies within the local authority given in field 29.,Combined with field 27 it should be a postcode which lies within the local authority given in field 29.,,,"For bedsits, enter ‘1’",,"This is whether someone who uses a wheelchair is able to make full use of all of the property’s rooms and facilities, including use of both inside and outside space, and entering and exiting the property.","Buyer 1 is the person in the household who does the most paid work. If it’s a joint purchase and the buyers do the same amount of paid work, buyer 1 is whoever is the oldest.",This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,"If buyer 1 is a dual national of the United Kingdom and another country, enter United Kingdom. If they are a dual national of two other countries, they should decide which country to enter.","Buyer 1 is the person in the household who does the most paid work. If it’s a joint purchase and the buyers do the same amount of paid work, buyer 1 is whoever is the oldest.",,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,"If buyer 2 is a dual national of the United Kingdom and another country, enter United Kingdom. If they are a dual national of two other countries, they should decide which country to enter.",,,"You can provide details for a maximum of 4 other people if there are 2 buyers, or 5 other people if there is only one buyer",,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,This is also known as the household's 'last settled home',,,,,,"A regular is somebody who has served in the Royal Navy, the Royal Marines, the Royal Air Force or army full time and does not include reserve forces",,"A regular is somebody who has served in the Royal Navy, the Royal Marines, the Royal Air Force or army full time and does not include reserve forces",This includes any long-term health condition that has an impact on the person's day-to-day life,This can be inside or outside the home,"Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments",,"Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments",,,Enter their total savings to the nearest £10,,For any buyer,"If the social landlord has previously sold the property to another buyer and is now reselling the property, enter 'yes'. If this is the first time the property has been sold, enter 'no'.","If the buyers haven't been living in the property, enter '0'",This is the date on which the building contractor hands over responsibility for the completed property to the private registered provider (PRP).,,,"For bedsits, enter ‘1’",,,"Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser).","This is the initial stake purchased. Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)",,Enter the amount of mortgage agreed with the mortgage lender. Exclude any deposits or cash payments.,,Enter the total cash sum paid by the buyer towards the property that was not funded by the mortgage,Enter the total cash discount given on the property being purchased through the Social HomeBuy scheme,Before any charges,"This includes any charges for day-to-day maintenance and repairs, buildings insurance, and any contributions to a sinking or reserve fund. It does not include estate management fees.","Estate management fees are typically used for the maintenance of communal gardens, payments, private roads, car parks or play areas within new build estates.",,,Back-to-back staircasing transactions are used as a way for shared owners who own less than 100% of their property to sell on the open market. It involves the shared owner purchasing the remaining share from their landlord and immediately selling 100% of the property to a buyer on the open market. The landlord is then reimbursed for the staircasing transaction through the proceeds of sale to the buyer.,,,,,,,,,"Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser).","This is the initial stake purchased. Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)",,,,,"For all schemes, including Right to Acquire (RTA), Right to Buy (RTB), Voluntary Right to Buy (VRTB) or Preserved Right to Buy (PRTB) sales, enter the full price of the property without any discount","For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB) and Rent to Buy","For Right to Buy (RTB), Preserved Right to Buy (PRTB) and Voluntary Right to Buy (VRTB). For capped discount, enter capped %. If property is sold to an existing tenant under RTB, PRTB or VRTB, enter % discount from full market value.",,Enter the amount of mortgage agreed with the mortgage lender. Exclude any deposits or cash payments.,,This is 'Yes' if the mortgage includes borrowing beyond the purchase price of the property,Enter the total cash sum paid by the purchaser towards the property that was not funded by the mortgage. This excludes any grant or loan.,"For example, service and management charges" +A shared ownership sale is when the purchaser buys an initial share of up to 75% of the property value and pays rent to the Private Registered Provider (PRP) on the remaining portion, or a subsequent staircasing transaction",See specification for full description of each scheme,"A staircasing transaction is when the household purchases more shares in their property, increasing the proportion they own and decreasing the proportion the housing association owns. Once the household purchases 100% of the shares, they own the property.",See specification for full description of each scheme,This is where two or more people are named as legal owners of the property after the purchase.,,You should still try to answer all questions even if the buyer wasn't interviewed in person,"Make sure the buyer has seen or been given access to the Ministry of Housing, Communities and Local Government (MHCLG) privacy notice before completing this log. This is a legal requirement under data protection legislation.","The Unique Property Reference Number (UPRN) is a unique number system created by Ordnance Survey and used by housing providers and various industries across the UK. An example UPRN is 10010457355. +The UPRN may not be the same as the property reference assigned by your organisation.",,,,,Combined with field 28 it should be a postcode which lies within the local authority given in field 29.,Combined with field 27 it should be a postcode which lies within the local authority given in field 29.,,,"For bedsits, enter ‘1’",,"This is whether someone who uses a wheelchair is able to make full use of all of the property’s rooms and facilities, including use of both inside and outside space, and entering and exiting the property.","Buyer 1 is the person in the household who does the most paid work. If it’s a joint purchase and the buyers do the same amount of paid work, buyer 1 is whoever is the oldest.",This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,"If buyer 1 is a dual national of the United Kingdom and another country, enter United Kingdom. If they are a dual national of two other countries, they should decide which country to enter.","Buyer 1 is the person in the household who does the most paid work. If it’s a joint purchase and the buyers do the same amount of paid work, buyer 1 is whoever is the oldest.",,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,"If buyer 2 is a dual national of the United Kingdom and another country, enter United Kingdom. If they are a dual national of two other countries, they should decide which country to enter.",,,"You can provide details for a maximum of 4 other people if there are 2 buyers, or 5 other people if there is only one buyer",,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,,This should be however they personally choose to identify from the options below. This may or may not be the same as their biological sex or the sex they were assigned at birth.,,,This is also known as the household's 'last settled home',,,,,,"A regular is somebody who has served in the Royal Navy, the Royal Marines, the Royal Air Force or army full time and does not include reserve forces",,"A regular is somebody who has served in the Royal Navy, the Royal Marines, the Royal Air Force or army full time and does not include reserve forces",This includes any long-term health condition that has an impact on the person's day-to-day life,This can be inside or outside the home,"Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments",,"Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments",,,Enter their total savings to the nearest £10,,For any buyer,"If the social landlord has previously sold the property to another buyer and is now reselling the property, enter 'yes'. If this is the first time the property has been sold, enter 'no'.","If the buyers haven't been living in the property, enter '0'",This is the date on which the building contractor hands over responsibility for the completed property to the private registered provider (PRP).,,,"For bedsits, enter ‘1’",,,"Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser).","This is the initial stake purchased. Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)",,Enter the amount of mortgage agreed with the mortgage lender. Exclude any deposits or cash payments.,,Enter the total cash sum paid by the buyer towards the property that was not funded by the mortgage,Enter the total cash discount given on the property being purchased through the Social HomeBuy scheme,Before any charges,"This includes any charges for day-to-day maintenance and repairs, buildings insurance, and any contributions to a sinking or reserve fund. It does not include estate management fees.","Estate management fees are typically used for the maintenance of communal gardens, payments, private roads, car parks or play areas within new build estates.",,,Back-to-back staircasing transactions are used as a way for shared owners who own less than 100% of their property to sell on the open market. It involves the shared owner purchasing the remaining share from their landlord and immediately selling 100% of the property to a buyer on the open market. The landlord is then reimbursed for the staircasing transaction through the proceeds of sale to the buyer.,,,,,,,,,"Enter the full purchase price of the property before any discounts are applied. For shared ownership, enter the full purchase price paid for 100% equity (this is equal to the value of the share owned by the PRP plus the value bought by the purchaser).","This is the initial stake purchased. Enter the amount of initial equity held by the purchaser (for example, 25% or 50%)",,,,,"For all schemes, including Right to Acquire (RTA), Right to Buy (RTB), Voluntary Right to Buy (VRTB) or Preserved Right to Buy (PRTB) sales, enter the full price of the property without any discount","For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB) and Rent to Buy","For Right to Buy (RTB), Preserved Right to Buy (PRTB) and Voluntary Right to Buy (VRTB). For capped discount, enter capped %. If property is sold to an existing tenant under RTB, PRTB or VRTB, enter % discount from full market value.",,Enter the amount of mortgage agreed with the mortgage lender. Exclude any deposits or cash payments.,,This is 'Yes' if the mortgage includes borrowing beyond the purchase price of the property,Enter the total cash sum paid by the purchaser towards the property that was not funded by the mortgage. This excludes any grant or loan.,"For example, service and management charges",This is the sex that was registered at birth.,This is the sex that was registered at birth.,This is the sex that was registered at birth.,This is the sex that was registered at birth.,This is the sex that was registered at birth.,This is the sex that was registered at birth. Values,Jan-31,01-Dec,25 - 26,Alphanumeric,Alphanumeric,Email format,"Alphanumeric, punctuation can be used as long as not the field separator. Max 9 characters.",01-Feb,"2, 16, 18, 24, 28 or 30 - 32",01-Feb,"8, 9, 14, 21, 22, 27 or 29",01-Feb,01-Mar,01-Feb,1,"Numeric, max 12 digits",Alphanumeric,,Text,,"Alphanumeric, 2 - 4 characters","Alphanumeric, 3 characters","9 character ONS code, beginning with 'E' (https://www.get-information-schools.service.gov.uk/Guidance/LaNameCodes) ",1 - 4 or 9,01-Sep,01-Feb,01-Mar,"16 - 110 or R","F, M, X or R",Jan-20,"3 digit ISO country code, see specification",0 - 8 or 10,01-Feb,01-Mar,1 - 110 or R,"F, M, X or R",Jan-20,"3 digit ISO country code, see specification",0 - 10,01-Feb,0 - 5,01-Mar,1 - 110 or R,"F, M, X or R",0 - 10,01-Mar,1 - 110 or R,"F, M, X or R",0 - 10,01-Mar,1 - 110 or R,"F, M, X or R",0 - 10,01-Mar,1 - 110 or R,"F, M, X or R",0 - 10,"1 - 7, 9 or R",01-Feb,"Alphanumeric, 2 - 4 characters","Alphanumeric, - 3 characters","9 character ONS code, beginning with 'E' (https://www.get-information-schools.service.gov.uk/Guidance/LaNameCodes) ",01-Mar,"1 - 7, 9 or R","1, 3, 7 or 8",04-Jun,04-Jul,01-Mar,,0 - 99999 or R,01-Feb,0 - 99999 or R,01-Feb,01-Apr,0 - 999990 or R,01-Mar,,01-Feb,Integer <= 80,Jan-31,01-Dec,22 - 26,01-Sep,1 - 4 or 9,1 - 3 or 9 - 10,0 - 999999,0 - 100,01-Feb,0 - 999999,Integer <= 60,0 - 999999,,0 - 9999.99,,,1 - 100,,01-Mar,01-Feb,Jan-31,01-Dec,1980-2026,02-Oct,Jan-31,01-Dec,1980-2026,0 - 999999,0 - 100,01-Mar,0 - 9999.99,,Integer <= 80,0 - 999999,,0 - 100,01-Feb,0 - 999999,Integer <= 60,01-Mar,0 - 999999,0 - 9999.99 + 3 characters","9 character ONS code, beginning with 'E' (https://www.get-information-schools.service.gov.uk/Guidance/LaNameCodes) ",01-Mar,"1 - 7, 9 or R","1, 3, 7 or 8",04-Jun,04-Jul,01-Mar,,0 - 99999 or R,01-Feb,0 - 99999 or R,01-Feb,01-Apr,0 - 999990 or R,01-Mar,,01-Feb,Integer <= 80,Jan-31,01-Dec,22 - 26,01-Sep,1 - 4 or 9,1 - 3 or 9 - 10,0 - 999999,0 - 100,01-Feb,0 - 999999,Integer <= 60,0 - 999999,,0 - 9999.99,,,1 - 100,,01-Mar,01-Feb,Jan-31,01-Dec,1980-2026,02-Oct,Jan-31,01-Dec,1980-2026,0 - 999999,0 - 100,01-Mar,0 - 9999.99,,Integer <= 80,0 - 999999,,0 - 100,01-Feb,0 - 999999,Integer <= 60,01-Mar,0 - 999999,0 - 9999.99,"F, M or R","F, M or R","F, M or R","F, M or R","F, M or R","F, M or R" Can be empty?,No,,,No,No,Yes,Yes,No,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2)","Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)",No,"Yes, if the sale is not a joint purchase (if field 12 = 2)",No,No,"Yes, if property's full address is known (if fields 16, 18, 20 and 21 are not empty)","Yes, if property's UPRN is known (if field 16 is not empty)",Yes,"Yes, if property's UPRN is known (if field 16 is not empty)",Yes,"Yes, if property's UPRN and local authority are known (if fields 16 and 23 are not empty",,No,,,"Yes, if the purchase is a staircasing transaction (if field 10 = 1)",,No,,"Yes, if the purchase is a staircasing transaction (if field 10 = 1)",,,,"Yes, if sale is not a joint purchase (if field 12 = 2) and the other fields about this person (fields 35, 36 and 39) are also empty","Yes, if sale is not a joint purchase (if field 12 = 2) and the other fields about this person (fields 35, 36 and 39) are also empty","Yes, if sale is not a joint purchase (if field 12 = 2) and the other fields about this person (fields 35, 36 and 39) are also empty","Yes, if sale is not a joint purchase (if field 12 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,"Yes, if sale is not a joint purchase (if field 12 = 2) and the other fields about this person (fields 35, 36 and 39) are also empty, or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if sale is not a joint purchase (if field 12 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if purchase is a staircasing transaction (if field 10 = 1)","Yes, if all fields about this person (fields 42 - 45) are also empty, or if the purchase is a staircasing transaction (if field 10 = 1)",,,,"Yes, if all fields about this person (fields 46 - 49) are also empty, or if the purchase is a staircasing transaction (if field 10 = 1)",,,,"Yes, if all fields about this person (fields 50 - 53) are also empty, or if the purchase is a staircasing transaction (if field 10 = 1)",,,,"Yes, if all fields about this person (fields 54 - 57) are also empty, or if the purchase is a staircasing transaction (if field 10 = 1)",,,,"Yes, if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if sale is discounted ownership (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if postcode of buyer 1's last settled accommodation is unknown (if field 59 = 2) Yes, if sale is discounted ownership (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,Yes,"Yes, if sale is not a joint purchase (if field 12 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if sale is not a joint purchase (if field 12 = 2), or if buyer is not known to have been living at the same address as buyer 1 at the time of purchase (if field 63 = 1 or 3), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if none of the buyers are known to have served as a regular in the UK armed forces (if field 65 = 7, 3 or 8), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if buyer 1's income is not known (if field 70 = R), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if sale is not a joint purchase (if field 12 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if sale is not a joint purchase (if field 12 = 2) or if buyer 2's income is not known (if field 70 = R), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if the purchasers did not previously own a property or if it is not known (if field 76 = 2 or 3), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2) or if this is a staircasing transaction (if field 10 = 1)","Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), if this is a resale (if field 78 = 1) or if this is a staircasing transaction (if field 10 = 1)",,,,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1) -Yes, if the buyer was not a private registered provider, housing association or local authority tenant immediately before sale (if field 58 is not 1 or 2)",,,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), if the purchase is a staircasing transaction (if field 10 = 1) or if a mortgage was not used (if field 88 = 2)",,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), if the purchase is a staircasing transaction (if field 10 = 1), or if the type of shared ownership sale is not Social Homebuy (if field 9 is not 18)","Yes, if there are no monthy charges or fees, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), or if the buyers do not own 100% of the property (if field 97 is less than 100)","Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), and if this is the first time the buyer has engaged in staircasing in the home (if field 99 = 1)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), or if the buyers now own 100% of the property (if field 97 = 100)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)",,"Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if the type of discounted sale is PRTB, VRTB, RTB, or Rent to Buy (if field 11 is 9, 14, 27 or 29)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if the type of discounted sale is not PRTB, VRTB, RTB, or Rent to Buy (if field 11 is 8, 21, 22)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if a mortgage was not used (if field 116 = 2)",,,"Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)","Yes, if there are no leasehold charges or if the purchase was not made through a discounted ownership scheme (if field 8 = 1)" -Types of sales the question applies to,All,,,,,,,,Shared ownership only,Shared ownership only,Discounted ownership only,All,Joint purchase only,All,,All,,,,,,,,,,Shared ownership - initial purchase and discounted ownership,,All,,Shared ownership - initial purchase and discounted ownership,,,,Joint purchases,,,Joint purchases which are shared ownership - initial purchase and discounted ownership,,,,Shared ownership - initial purchase and discounted ownership,,,,,,,,,,,,,,,,,Shared ownership - initial purchase and discounted ownership,Shared ownership - initial purchase,,,Shared ownership - initial purchase and discounted ownership,Joint purchases which are shared ownership - initial purchase and discounted ownership,,Shared ownership - initial purchase and discounted ownership,,,,,Shared ownership - initial purchase and discounted ownership,,Joint purchases which are shared ownership - initial purchase and discounted ownership,,Shared ownership - initial purchase and discounted ownership,,,,Shared ownership - initial purchase only,,,,,,,,,,,,,,,,,,Shared ownership - staircasing transaction only,,,,,,,,,,,,,,,,Discounted ownership only,,,,,,,,, -Duplicate check field?,Yes,,,,,,,,,,,,,,,,,,,,Yes,,,,,,,Yes,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, -Field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121 -,4,9,26,ORG1,ORG1,support@example.com,1,2,,,8,2,3,1,1,,a,a,a,a,aa1,1aa,E09000001,1,1,2,3,20,M,20,GBR,10,1,,,,,,,,0,,,,,,,,,,,,,,,,,1,2,,,,,,8,,7,3,3,10000,2,,,4,20000,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30,400000,10000,25,2,,,,390000,0 +Yes, if the buyer was not a private registered provider, housing association or local authority tenant immediately before sale (if field 58 is not 1 or 2)",,,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), if the purchase is a staircasing transaction (if field 10 = 1) or if a mortgage was not used (if field 88 = 2)",,"Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)","Yes, if the purchase was not made through a shared ownership scheme (if field 8 = 2), if the purchase is a staircasing transaction (if field 10 = 1), or if the type of shared ownership sale is not Social Homebuy (if field 9 is not 18)","Yes, if there are no monthy charges or fees, if the purchase was not made through a shared ownership scheme (if field 8 = 2), or if the purchase is a staircasing transaction (if field 10 = 1)",,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), or if the buyers do not own 100% of the property (if field 97 is less than 100)","Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), and if this is the first time the buyer has engaged in staircasing in the home (if field 99 = 1)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2)",,,,"Yes, if this is not a shared ownership transaction (if field 8 = 2), or if it is not a staircasing transaction (if field 10 = 2), or if the buyers now own 100% of the property (if field 97 = 100)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)",,"Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if the type of discounted sale is PRTB, VRTB, RTB, or Rent to Buy (if field 11 is 9, 14, 27 or 29)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if the type of discounted sale is not PRTB, VRTB, RTB, or Rent to Buy (if field 11 is 8, 21, 22)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)","Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1) or if a mortgage was not used (if field 116 = 2)",,,"Yes, if the purchase was not made through a discounted ownership scheme (if field 8 = 1)","Yes, if there are no leasehold charges or if the purchase was not made through a discounted ownership scheme (if field 8 = 1)",,,,,, +Types of sales the question applies to,All,,,,,,,,Shared ownership only,Shared ownership only,Discounted ownership only,All,Joint purchase only,All,,All,,,,,,,,,,Shared ownership - initial purchase and discounted ownership,,All,,Shared ownership - initial purchase and discounted ownership,,,,Joint purchases,,,Joint purchases which are shared ownership - initial purchase and discounted ownership,,,,Shared ownership - initial purchase and discounted ownership,,,,,,,,,,,,,,,,,Shared ownership - initial purchase and discounted ownership,Shared ownership - initial purchase,,,Shared ownership - initial purchase and discounted ownership,Joint purchases which are shared ownership - initial purchase and discounted ownership,,Shared ownership - initial purchase and discounted ownership,,,,,Shared ownership - initial purchase and discounted ownership,,Joint purchases which are shared ownership - initial purchase and discounted ownership,,Shared ownership - initial purchase and discounted ownership,,,,Shared ownership - initial purchase only,,,,,,,,,,,,,,,,,,Shared ownership - staircasing transaction only,,,,,,,,,,,,,,,,Discounted ownership only,,,,,,,,,,,,,,, +Duplicate check field?,Yes,,,,,,,,,,,,,,,,,,,,Yes,,,,,,,Yes,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +Field number,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127 +,4,9,26,ORG1,ORG1,support@example.com,1,2,,,8,2,3,1,1,,a,a,a,a,aa1,1aa,E09000001,1,1,2,3,20,M,20,GBR,10,1,,,,,,,,0,,,,,,,,,,,,,,,,,1,2,,,,,,8,,7,3,3,10000,2,,,4,20000,3,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,30,400000,10000,25,2,,,,390000,0,F,,,,, diff --git a/spec/fixtures/variable_definitions/sales_download_26_27.csv b/spec/fixtures/variable_definitions/sales_download_26_27.csv new file mode 100644 index 000000000..c0759bf6d --- /dev/null +++ b/spec/fixtures/variable_definitions/sales_download_26_27.csv @@ -0,0 +1,287 @@ +ID,Log ID +STATUS,Status of log +DUPLICATESET,ID of a set of duplicate logs +CREATEDDATE,Time and date the log was created +UPLOADDATE,Time and date the log was last updated +COLLECTIONYEAR,Year collection period opened +CREATIONMETHOD,Was the log submitted in-service or via bulk upload? +BULKUPLOADID,ID of a set of bulk uploaded logs +DATAPROTECT,Is the user in the created_by column the data protection officer? +OWNINGORGNAME,Which organisation owned this property before the sale? +MANINGORGNAME,Which organisation reported the sale? +CREATEDBY,User that created the log +USERNAME,User the log is assigned to +DAY,Day of sale completion date +MONTH,Month of sale completion date +YEAR,Year of sale completion date +PURCHID,What is the purchaser code? +OWNERSHIP,Was this purchase made through an ownership scheme? +TYPE,What is the type of shared ownership/discounted ownership/outright sale? +OTHTYPE,If type = 'Other', what is the type of outright sale? +COMPANY,Is the buyer a company? +LIVEINBUYER,Will the buyer(s) live in the property? +JOINT,Is this a joint purchase? +JOINTMORE,Are there more than 2 joint buyers of this property? +NOINT,Did you interview the buyer to answer these questions? +PRIVACYNOTICE,Has the buyer seen the MHCLG privacy notice? +UPRN,What is the UPRN of the property? +ADDRESS1,Address line 1 +ADDRESS2,Address line 2 +TOWNCITY,Town/City +COUNTY,County +POSTCODE,Postcode +ISLAINFERRED,The internal value to indicate if the LA was inferred from the postcode +LANAME,LA name +LA,LA code +UPRNSELECTED,UPRN of the address selected +ADDRESS_SEARCH_VALUE_CHECK,Was the 'No address found' page seen? +ADDRESS1INPUT,Address line 1 input from address matching feature +POSTCODEINPUT,Postcode input from address matching feature +BULKADDRESS1,Address line 1 entered in bulk upload file +BULKADDRESS2,Address line 2 entered in bulk upload file +BULKTOWNCITY,Town or city entered in bulk upload file +BULKCOUNTY,County entered in bulk upload file +BULKPOSTCODE,Postcode entered in bulk upload file +BULKLA,Local authority entered in bulk upload file +BEDS,How many bedrooms does the property have? +PROPTYPE,What type of unit is the property? +BUILTYPE,Which type of building is the property? +WCHAIR,Is the property built or adapted to wheelchair-user standards? +AGE1,What is buyer 1's age? +SEX1,Which of these best describes buyer 1's gender identity? +ETHNICGROUP1,What is buyer 1's ethnic group? +ETHNIC,Which of the following best describes buyer 1's ethnic background? +NATIONALITYALL1,What is buyer 1's nationality? +ECSTAT1,Which of these best describes buyer 1's working situation? +LIVEINBUYER1,Will buyer 1 live in the property? +RELAT2,What is buyer 2 or person 2's relationship to buyer 1? +AGE2,What is buyer 2 or person 2's age? +SEX2,Which of these best describes buyer 2 or person 2's gender identity? +ETHNICGROUP2,What is buyer 2's ethnic group? +ETHNIC2,Which of the following best describes buyer 2's ethnic background? +NATIONALITYALL2,What is buyer 2's nationality? +ECSTAT2,What is buyer 2 or person 2's working situation? +LIVEINBUYER2,Will buyer 2 live in the property? +HHTYPE,Besides the buyer(s), how many other people live or will live in the property? +RELAT3,What is person 3's relationship to buyer 1? +AGE3,What is person 3's age? +SEX3,What is person 3's gender identity? +ECSTAT3,What is person 3's working situation? +RELAT4,What is person 4's relationship to buyer 1? +AGE4,What is person 4's age? +SEX4,What is person 4's gender identity? +ECSTAT4,What is person 4's working situation? +RELAT5,What is person 5's relationship to buyer 1? +AGE5,What is person 5's age? +SEX5,What is person 5's gender identity? +ECSTAT5,What is person 5's working situation? +RELAT6,What is person 6's relationship to buyer 1? +AGE6,What is person 6's age? +SEX6,What is person 6's gender identity? +ECSTAT6,What is person 6's working situation? +PREVTEN,What was buyer 1's previous tenure? +PPCODENK,Do you know the postcode of buyer 1's last settled accommodation? +PPOSTC1,Part 1 of postcode of buyer 1's last settled accommodation +PPOSTC2,Part 2 of postcode of buyer 1's last settled accommodation +PREVIOUSLAKNOWN,Do you know the local authority of buyer 1's last settled accommodation? +PREVLOC,The local authority code of buyer 1's last settled accommodation +PREVLOCNAME,The local authority name of buyer 1's last settled accommodation +PREGYRHA,Was the buyer registered with their PRP (HA)? +PREGOTHER,Was the buyer registered with another PRP (HA)? +PREGLA,Was the buyer registered with the local authority? +PREGGHB,Was the buyer registered with a Help to Buy agent? +PREGBLANK,Populated if pregyrha, pregother, pregla and pregghb are blank +BUY2LIVING,At the time of purchase, was buyer 2 living at the same address as buyer 1? +PREVTEN2,What was buyer 2's previous tenure? +HHREGRES,Have any of the buyers ever served as a regular in the UK armed forces? +HHREGRESSTILL,Is the buyer still serving in the UK armed forces? +ARMEDFORCESSPOUSE,Are any of the buyers a spouse or civil partner of a UK armed forces regular who died in service within the last 2 years? +DISABLED,Does anyone in the household consider themselves to have a disability? +WHEEL,Does anyone in the household use a wheelchair? +INC1NK,Is buyer 1's annual income known? +INCOME1,What is buyer 1's annual income? +INC1MORT,Was buyer 1's income used for a mortgage application? +INC2NK,Is buyer 1's annual income known? +INCOME2,What is buyer 2's annual income? +INC2MORT,Was buyer 2's income used for a mortgage application? +HB,Were the buyers receiving any of these housing-related benefits immediately before buying this property? +SAVINGSNK,Is the the total amount the buyers had in savings known? +SAVINGS,What is the total amount the buyers had in savings before they paid any deposit for the property? +PREVOWN,Have any of the buyers previously owned a property? +PREVSHARED,Was the previous property under shared ownership? +PROPLEN,How long did the buyer(s) live in the property before purchasing it? +STAIRCASE,Is this a staircasing transaction? +STAIRBOUGHT,What percentage of the property has been bought in this staircasing transaction? +STAIROWNED,What percentage of the property do the buyers now own in total? +STAIRCASETOSALE,Was this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market? +RESALE,Is this a resale? +EXDAY,Day of the exchange of contracts +EXMONTH,Month of the exchange of contracts +EXYEAR,Year of the exchange of contracts +HODAY,Day of the practical completion or handover date +HOMONTH,Month of the practical completion or handover date +HOYEAR,Year of the practical completion or handover date +LANOMAGR,Was the household rehoused under a local authority nominations agreement? +SOCTEN,Was the buyer a private registered provider, housing association or local authority tenant immediately before this sale? +FROMBEDS,How many bedrooms did the buyer's previous property have? +FROMPROP,What was the previous property type? +SOCPREVTEN,What was the rent type of buyer's previous tenure? +VALUE,What is the full purchase price? +VALUE_VALUE_CHECK,Populated if a soft validation is confirmed. +EQUITY,What was the initial percentage equity stake purchased? +MORTGAGEUSED,Was a mortgage used to buy this property? +MORTGAGE,What is the mortgage amount? +MORTGAGELENDER,What is the name of the mortgage lender? +MORTGAGELENDEROTHER,If mortgagelender = 'Other', what is the name of the mortgage lender? +MORTLEN1,What is the length of the mortgage in years? +EXTRABOR,Does this include any extra borrowing? +DEPOSIT,How much was the cash deposit paid on the property? +CASHDIS,How much cash discount was given through Social Homebuy? +MRENT,What is the basic monthly rent? +HASMSCHARGE,Does the property have any monthly leasehold charges? +MSCHARGE,What are the total monthly leasehold charges for the property? +MSCHARGE_VALUE_CHECK,Populated if a soft validation is confirmed. +DISCOUNT,What was the percentage discount? +GRANT,What was the amount of any loan, grant, discount or subsidy given? +id,Log ID +status,Status of log +duplicate_set_id,ID of a set of duplicate logs +created_at,Time and date the log was created +updated_at,Time and date the log was last updated +old_form_id,The ID on the old service +collection_start_year,Year collection period opened +creation_method,Was the log submitted in-service or via bulk upload? +is_dpo,Is the user in the assigned_to column the data protection officer? +owning_organisation_name,Which organisation owned this property before the sale? +managing_organisation_name,Which organisation reported the sale? +assigned_to,User the log is assigned to +day,Day of sale completion date +month,Month of sale completion date +year,Year of sale completion date +purchid,What is the purchaser code? +ownershipsch,Was this purchase made through an ownership scheme? +type,What is the type of shared ownership/discounted ownership/outright sale? +othtype,If type = 'Other', what is the type of outright sale? +companybuy,Is the buyer a company? +buylivein,Will the buyer(s) live in the property? +jointpur,Is this a joint purchase? +jointmore,Are there more than 2 joint buyers of this property? +beds,How many bedrooms does the property have? +proptype,What type of unit is the property? +builtype,Which type of building is the property? +uprn,What is the UPRN of the property? +uprn_confirmed,We found an address that might be this property. Is this the property address? +address_line1_input,Address line 1 input from address matching feature +postcode_full_input,Postcode input from address matching feature +uprn_selection,UPRN of the address selected +address_line1,Address line 1 +address_line2,Address line 2 +town_or_city,Town/City +county,County +pcode1,Part 1 of the property's postcode +pcode2,Part 2 of the property's postcode +la,LA code +la_label,LA name +wchair,Is the property built or adapted to wheelchair-user standards? +noint,Did you interview the buyer to answer these questions? +privacynotice,Has the buyer seen the MHCLG privacy notice? +age1,What is buyer 1's age? +sex1,Which of these best describes buyer 1's gender identity? +ethnic_group,What is buyer 1's ethnic group? +ethnic,Which of the following best describes buyer 1's ethnic background? +nationality_all,What is buyer 1's nationality? +ecstat1,Which of these best describes buyer 1's working situation? +buy1livein,Will buyer 1 live in the property? +relat2,What is buyer 2 or person 2's relationship to buyer 1? +age2,What is buyer 2 or person 2's age? +sex2,Which of these best describes buyer 2 or person 2's gender identity? +ethnic_group2,What is buyer 2's ethnic group? +ethnicbuy2,Which of the following best describes buyer 2's ethnic background? +nationality_all_buyer2,What is buyer 2's nationality? +ecstat2,What is buyer 2 or person 2's working situation? +buy2livein,Will buyer 2 live in the property? +hholdcount,Besides the buyer(s), how many other people live or will live in the property? +relat3,What is person 3's relationship to buyer 1? +age3,What is person 3's age? +sex3,What is person 3's gender identity? +ecstat3,What is person 3's working situation? +relat4,What is person 4's relationship to buyer 1? +age4,What is person 4's age? +sex4,What is person 4's gender identity? +ecstat4,What is person 4's working situation? +relat5,What is person 5's relationship to buyer 1? +age5,What is person 5's age? +sex5,What is person 5's gender identity? +ecstat5,What is person 5's working situation? +relat6,What is person 6's relationship to buyer 1? +age6,What is person 6's age? +sex6,What is person 6's gender identity? +ecstat6,What is person 6's working situation? +prevten,What was buyer 1's previous tenure? +ppcodenk,Do you know the postcode of buyer 1's last settled accommodation? +ppostc1,Part 1 of postcode of buyer 1's last settled accommodation +ppostc2,Part 2 of postcode of buyer 1's last settled accommodation +previous_la_known,Do you know the local authority of buyer 1's last settled accommodation? +prevloc,The local authority code of buyer 1's last settled accommodation +prevloc_label,The local authority name of buyer 1's last settled accommodation +pregyrha,Was the buyer registered with their PRP (HA)? +pregother,Was the buyer registered with another PRP (HA)? +pregla,Was the buyer registered with the local authority? +pregghb,Was the buyer registered with a Help to Buy agent? +pregblank,Populated if pregyrha, pregother, pregla and pregghb are blank +buy2living,At the time of purchase, was buyer 2 living at the same address as buyer 1? +prevtenbuy2,What was buyer 2's previous tenure? +hhregres,Have any of the buyers ever served as a regular in the UK armed forces? +hhregresstill,Is the buyer still serving in the UK armed forces? +armedforcesspouse,Are any of the buyers a spouse or civil partner of a UK armed forces regular who died in service within the last 2 years? +disabled,Does anyone in the household consider themselves to have a disability? +wheel,Does anyone in the household use a wheelchair? +income1nk,Is buyer 1's annual income known? +income1,What is buyer 1's annual income? +inc1mort,Was buyer 1's income used for a mortgage application? +income2nk,Is buyer 2's annual income known? +income2,What is buyer 2's annual income? +inc2mort,Was buyer 2's income used for a mortgage application? +hb,Were the buyers receiving any of these housing-related benefits immediately before buying this property? +savingsnk,Is the the total amount the buyers had in savings known? +savings,What is the total amount the buyers had in savings before they paid any deposit for the property? +prevown,Have any of the buyers previously owned a property? +prevshared,Was the previous property under shared ownership? +proplen,How long did the buyer(s) live in the property before purchasing it? +staircase,Is this a staircasing transaction? +stairbought,What percentage of the property has been bought in this staircasing transaction? +stairowned,What percentage of the property do the buyers now own in total? +staircasesale,Was this transaction part of a back-to-back staircasing transaction to facilitate sale of the home on the open market? +resale,Is this a resale? +exday,Day of the exchange of contracts +exmonth,Month of the exchange of contracts +exyear,Year of the exchange of contracts +hoday,Day of the practical completion or handover date +homonth,Month of the practical completion or handover date +hoyear,Year of the practical completion or handover date +lanomagr,Was the household rehoused under a local authority nominations agreement? +soctenant,Was the buyer a private registered provider, housing association or local authority tenant immediately before this sale? +frombeds,How many bedrooms did the buyer's previous property have? +fromprop,What was the previous property type? +socprevten,What was the rent type of buyer's previous tenure? +value,What is the full purchase price? +equity,What was the initial percentage equity stake purchased? +mortgageused,Was a mortgage used to buy this property? +mortgage,What is the mortgage amount? +mortgagelender,What is the name of the mortgage lender? +mortgagelenderother,If mortgagelender = 'Other', what is the name of the mortgage lender? +mortlen,What is the length of the mortgage in years? +extrabor,Does this include any extra borrowing? +deposit,How much was the cash deposit paid on the property? +cashdis,How much cash discount was given through Social Homebuy? +mrent,What is the basic monthly rent? +has_mscharge,Does the property have any monthly leasehold charges? +mscharge,What are the total monthly leasehold charges for the property? +discount,What was the percentage discount? +grant,What was the amount of any loan, grant, discount or subsidy given? +sexrab1,What was buyer 1's sex at birth? +sexrab2,What was buyer/person 2's sex at birth? +sexrab3,What was person 3's sex at birth? +sexrab4,What was person 4's sex at birth? +sexrab5,What was person 5's sex at birth? +sexrab6,What was person 6's sex at birth? diff --git a/spec/lib/tasks/log_variable_definitions_spec.rb b/spec/lib/tasks/log_variable_definitions_spec.rb index 8bae5a4d0..d0ae5b151 100644 --- a/spec/lib/tasks/log_variable_definitions_spec.rb +++ b/spec/lib/tasks/log_variable_definitions_spec.rb @@ -6,6 +6,7 @@ RSpec.describe "log_variable_definitions" do subject(:task) { Rake::Task["data_import:add_variable_definitions"] } let(:path) { "spec/fixtures/variable_definitions" } + let(:total_variable_definitions_count) { 423 } before do Rake.application.rake_require("tasks/log_variable_definitions") @@ -14,7 +15,7 @@ RSpec.describe "log_variable_definitions" do end it "adds CsvVariableDefinition records from each file in the specified directory" do - expect { task.invoke(path) }.to change(CsvVariableDefinition, :count).by(417) + expect { task.invoke(path) }.to change(CsvVariableDefinition, :count).by(total_variable_definitions_count) end it "handles an empty directory without errors" do @@ -34,7 +35,7 @@ RSpec.describe "log_variable_definitions" do task.invoke(path) second_run_count = CsvVariableDefinition.count - expect(first_run_count).to eq(initial_count + 417) + expect(first_run_count).to eq(initial_count + total_variable_definitions_count) expect(second_run_count).to eq(first_run_count) end end diff --git a/spec/models/form/sales/pages/person_sex_registered_at_birth_spec.rb b/spec/models/form/sales/pages/person_sex_registered_at_birth_spec.rb new file mode 100644 index 000000000..fa116818c --- /dev/null +++ b/spec/models/form/sales/pages/person_sex_registered_at_birth_spec.rb @@ -0,0 +1,104 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::PersonSexRegisteredAtBirth, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection, person_index:) } + + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2026, 4, 1))) } + let(:person_index) { 1 } + + let(:page_id) { "person_2_sex_registered_at_birth" } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + context "with person 2" do + let(:person_index) { 2 } + let(:page_id) { "person_2_sex_registered_at_birth" } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab2]) + end + + it "has the correct id" do + expect(page.id).to eq("person_2_sex_registered_at_birth") + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "details_known_2" => 1 }]) + end + end + + context "with person 3" do + let(:person_index) { 3 } + let(:page_id) { "person_3_sex_registered_at_birth" } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab3]) + end + + it "has the correct id" do + expect(page.id).to eq("person_3_sex_registered_at_birth") + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "details_known_3" => 1 }]) + end + end + + context "with person 4" do + let(:person_index) { 4 } + let(:page_id) { "person_4_sex_registered_at_birth" } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab4]) + end + + it "has the correct id" do + expect(page.id).to eq("person_4_sex_registered_at_birth") + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "details_known_4" => 1 }]) + end + end + + context "with person 5" do + let(:person_index) { 5 } + let(:page_id) { "person_5_sex_registered_at_birth" } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab5]) + end + + it "has the correct id" do + expect(page.id).to eq("person_5_sex_registered_at_birth") + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "details_known_5" => 1 }]) + end + end + + context "with person 6" do + let(:person_index) { 6 } + let(:page_id) { "person_6_sex_registered_at_birth" } + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab6]) + end + + it "has the correct id" do + expect(page.id).to eq("person_6_sex_registered_at_birth") + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "details_known_6" => 1 }]) + end + end +end diff --git a/spec/models/form/sales/pages/sex_registered_at_birth1_spec.rb b/spec/models/form/sales/pages/sex_registered_at_birth1_spec.rb new file mode 100644 index 000000000..da020aa91 --- /dev/null +++ b/spec/models/form/sales/pages/sex_registered_at_birth1_spec.rb @@ -0,0 +1,29 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::SexRegisteredAtBirth1, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2026, 4, 1))) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab1]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_1_sex_registered_at_birth") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([{ "buyer_has_seen_privacy_notice?" => true }, { "buyer_not_interviewed?" => true }]) + end +end diff --git a/spec/models/form/sales/pages/sex_registered_at_birth2_spec.rb b/spec/models/form/sales/pages/sex_registered_at_birth2_spec.rb new file mode 100644 index 000000000..d120c6e23 --- /dev/null +++ b/spec/models/form/sales/pages/sex_registered_at_birth2_spec.rb @@ -0,0 +1,38 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Pages::SexRegisteredAtBirth2, type: :model do + subject(:page) { described_class.new(page_id, page_definition, subsection) } + + let(:page_id) { nil } + let(:page_definition) { nil } + let(:subsection) { instance_double(Form::Subsection, form: instance_double(Form, start_date: Time.zone.local(2026, 4, 1))) } + + it "has correct subsection" do + expect(page.subsection).to eq(subsection) + end + + it "has correct questions" do + expect(page.questions.map(&:id)).to eq(%w[sexrab2]) + end + + it "has the correct id" do + expect(page.id).to eq("buyer_2_sex_registered_at_birth") + end + + it "has the correct description" do + expect(page.description).to be_nil + end + + it "has correct depends_on" do + expect(page.depends_on).to eq([ + { + "joint_purchase?" => true, + "buyer_has_seen_privacy_notice?" => true, + }, + { + "joint_purchase?" => true, + "buyer_not_interviewed?" => true, + }, + ]) + end +end diff --git a/spec/models/form/sales/questions/person_sex_registered_at_birth_spec.rb b/spec/models/form/sales/questions/person_sex_registered_at_birth_spec.rb new file mode 100644 index 000000000..eb5f10687 --- /dev/null +++ b/spec/models/form/sales/questions/person_sex_registered_at_birth_spec.rb @@ -0,0 +1,123 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::PersonSexRegisteredAtBirth, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page, person_index:) } + + let(:question_id) { "sexrab2" } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:person_index) { 2 } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form, start_date: Time.zone.local(2026, 4, 1)) } + + before do + allow(page).to receive(:subsection).and_return(subsection) + allow(subsection).to receive(:form).and_return(form) + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?(nil)).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Person prefers not to say" }, + }) + end + + context "when person 2" do + let(:question_id) { "sexrab2" } + let(:person_index) { 2 } + + it "has the correct id" do + expect(question.id).to eq("sexrab2") + end + + it "has expected check answers card number" do + expect(question.check_answers_card_number).to eq(2) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end + end + + context "when person 3" do + let(:question_id) { "sexrab3" } + let(:person_index) { 3 } + + it "has the correct id" do + expect(question.id).to eq("sexrab3") + end + + it "has expected check answers card number" do + expect(question.check_answers_card_number).to eq(3) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end + end + + context "when person 4" do + let(:question_id) { "sexrab4" } + let(:person_index) { 4 } + + it "has the correct id" do + expect(question.id).to eq("sexrab4") + end + + it "has expected check answers card number" do + expect(question.check_answers_card_number).to eq(4) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end + end + + context "when person 5" do + let(:question_id) { "sexrab5" } + let(:person_index) { 5 } + + it "has the correct id" do + expect(question.id).to eq("sexrab5") + end + + it "has expected check answers card number" do + expect(question.check_answers_card_number).to eq(5) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end + end + + context "when person 6" do + let(:question_id) { "sexrab6" } + let(:person_index) { 6 } + + it "has the correct id" do + expect(question.id).to eq("sexrab6") + end + + it "has expected check answers card number" do + expect(question.check_answers_card_number).to eq(6) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end + end +end diff --git a/spec/models/form/sales/questions/sex_registered_at_birth1_spec.rb b/spec/models/form/sales/questions/sex_registered_at_birth1_spec.rb new file mode 100644 index 000000000..cc1f981cc --- /dev/null +++ b/spec/models/form/sales/questions/sex_registered_at_birth1_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::SexRegisteredAtBirth1, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form, start_date: Time.zone.local(2026, 4, 1)) } + + before do + allow(page).to receive(:subsection).and_return(subsection) + allow(subsection).to receive(:form).and_return(form) + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("sexrab1") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?(nil)).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Buyer prefers not to say" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(1) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end +end diff --git a/spec/models/form/sales/questions/sex_registered_at_birth2_spec.rb b/spec/models/form/sales/questions/sex_registered_at_birth2_spec.rb new file mode 100644 index 000000000..99ded462a --- /dev/null +++ b/spec/models/form/sales/questions/sex_registered_at_birth2_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Form::Sales::Questions::SexRegisteredAtBirth2, type: :model do + subject(:question) { described_class.new(question_id, question_definition, page) } + + let(:question_id) { nil } + let(:question_definition) { nil } + let(:page) { instance_double(Form::Page) } + let(:subsection) { instance_double(Form::Subsection) } + let(:form) { instance_double(Form, start_date: Time.zone.local(2026, 4, 1)) } + + before do + allow(page).to receive(:subsection).and_return(subsection) + allow(subsection).to receive(:form).and_return(form) + end + + it "has correct page" do + expect(question.page).to eq(page) + end + + it "has the correct id" do + expect(question.id).to eq("sexrab2") + end + + it "has the correct type" do + expect(question.type).to eq("radio") + end + + it "is not marked as derived" do + expect(question.derived?(nil)).to be false + end + + it "has the correct answer_options" do + expect(question.answer_options).to eq({ + "F" => { "value" => "Female" }, + "M" => { "value" => "Male" }, + "divider" => { "value" => true }, + "R" => { "value" => "Buyer prefers not to say" }, + }) + end + + it "has the correct check_answers_card_number" do + expect(question.check_answers_card_number).to eq(2) + end + + it "has the correct inferred_check_answers_value" do + expect(question.inferred_check_answers_value).to be_nil + end +end diff --git a/spec/models/form/sales/subsections/household_characteristics_spec.rb b/spec/models/form/sales/subsections/household_characteristics_spec.rb index 67f758ae3..74ed15da4 100644 --- a/spec/models/form/sales/subsections/household_characteristics_spec.rb +++ b/spec/models/form/sales/subsections/household_characteristics_spec.rb @@ -21,6 +21,7 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model allow(form).to receive(:start_date).and_return(Time.zone.local(2023, 4, 1)) allow(form).to receive(:start_year_2024_or_later?).and_return(false) allow(form).to receive(:start_year_2025_or_later?).and_return(false) + allow(form).to receive(:start_year_2026_or_later?).and_return(false) end it "has correct pages" do @@ -130,6 +131,7 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model allow(form).to receive(:start_date).and_return(Time.zone.local(2024, 4, 1)) allow(form).to receive(:start_year_2024_or_later?).and_return(true) allow(form).to receive(:start_year_2025_or_later?).and_return(false) + allow(form).to receive(:start_year_2026_or_later?).and_return(false) end it "has correct depends on" do @@ -284,6 +286,7 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model allow(form).to receive(:start_date).and_return(Time.zone.local(2025, 4, 1)) allow(form).to receive(:start_year_2024_or_later?).and_return(true) allow(form).to receive(:start_year_2025_or_later?).and_return(true) + allow(form).to receive(:start_year_2026_or_later?).and_return(false) end it "has correct pages" do @@ -398,4 +401,132 @@ RSpec.describe Form::Sales::Subsections::HouseholdCharacteristics, type: :model expect(household_characteristics.depends_on).to eq([{ "setup_completed?" => true }]) end end + + context "with 2026/27 form" do + before do + allow(form).to receive(:start_date).and_return(Time.zone.local(2026, 4, 1)) + allow(form).to receive(:start_year_2024_or_later?).and_return(true) + allow(form).to receive(:start_year_2025_or_later?).and_return(true) + allow(form).to receive(:start_year_2026_or_later?).and_return(true) + end + + it "has correct pages" do + expect(household_characteristics.pages.map(&:id)).to eq( + %w[ + buyer_1_age + age_1_retirement_value_check + age_1_not_retired_value_check + age_1_old_persons_shared_ownership_joint_purchase_value_check + age_1_old_persons_shared_ownership_value_check + buyer_1_sex_registered_at_birth + buyer_1_gender_identity + buyer_1_ethnic_group + buyer_1_ethnic_background_black + buyer_1_ethnic_background_asian + buyer_1_ethnic_background_arab + buyer_1_ethnic_background_mixed + buyer_1_ethnic_background_white + buyer_1_nationality + buyer_1_working_situation + working_situation_1_retirement_value_check + working_situation_1_not_retired_value_check + working_situation_buyer_1_income_value_check + buyer_1_live_in_property + buyer_1_live_in_property_value_check + buyer_2_relationship_to_buyer_1 + buyer_2_age + age_2_old_persons_shared_ownership_joint_purchase_value_check + age_2_old_persons_shared_ownership_value_check + age_2_buyer_retirement_value_check + age_2_buyer_not_retired_value_check + buyer_2_sex_registered_at_birth + buyer_2_gender_identity + buyer_2_ethnic_group + buyer_2_ethnic_background_black + buyer_2_ethnic_background_asian + buyer_2_ethnic_background_arab + buyer_2_ethnic_background_mixed + buyer_2_ethnic_background_white + buyer_2_nationality + buyer_2_working_situation + working_situation_2_retirement_value_check_joint_purchase + working_situation_2_not_retired_value_check_joint_purchase + working_situation_buyer_2_income_value_check + buyer_2_live_in_property + buyer_2_live_in_property_value_check + number_of_others_in_property + number_of_others_in_property_joint_purchase + person_2_known + person_2_relationship_to_buyer_1 + relationship_2_partner_under_16_value_check + relationship_2_multiple_partners_value_check + person_2_age + age_2_retirement_value_check + age_2_not_retired_value_check + age_2_partner_under_16_value_check + person_2_sex_registered_at_birth + person_2_gender_identity + person_2_working_situation + working_situation_2_retirement_value_check + working_situation_2_not_retired_value_check + person_3_known + person_3_relationship_to_buyer_1 + relationship_3_partner_under_16_value_check + relationship_3_multiple_partners_value_check + person_3_age + age_3_retirement_value_check + age_3_not_retired_value_check + age_3_partner_under_16_value_check + person_3_sex_registered_at_birth + person_3_gender_identity + person_3_working_situation + working_situation_3_retirement_value_check + working_situation_3_not_retired_value_check + person_4_known + person_4_relationship_to_buyer_1 + relationship_4_partner_under_16_value_check + relationship_4_multiple_partners_value_check + person_4_age + age_4_retirement_value_check + age_4_not_retired_value_check + age_4_partner_under_16_value_check + person_4_sex_registered_at_birth + person_4_gender_identity + person_4_working_situation + working_situation_4_retirement_value_check + working_situation_4_not_retired_value_check + person_5_known + person_5_relationship_to_buyer_1 + relationship_5_partner_under_16_value_check + relationship_5_multiple_partners_value_check + person_5_age + age_5_retirement_value_check + age_5_not_retired_value_check + age_5_partner_under_16_value_check + person_5_sex_registered_at_birth + person_5_gender_identity + person_5_working_situation + working_situation_5_retirement_value_check + working_situation_5_not_retired_value_check + person_6_known + person_6_relationship_to_buyer_1 + relationship_6_partner_under_16_value_check + relationship_6_multiple_partners_value_check + person_6_age + age_6_retirement_value_check + age_6_not_retired_value_check + age_6_partner_under_16_value_check + person_6_sex_registered_at_birth + person_6_gender_identity + person_6_working_situation + working_situation_6_retirement_value_check + working_situation_6_not_retired_value_check + ], + ) + end + + it "has correct depends on" do + expect(household_characteristics.depends_on).to eq([{ "setup_completed?" => true }]) + end + end end diff --git a/spec/services/bulk_upload/sales/validator_spec.rb b/spec/services/bulk_upload/sales/validator_spec.rb index b665b2b5c..a37eff505 100644 --- a/spec/services/bulk_upload/sales/validator_spec.rb +++ b/spec/services/bulk_upload/sales/validator_spec.rb @@ -11,7 +11,7 @@ RSpec.describe BulkUpload::Sales::Validator do let(:organisation) { create(:organisation, old_visible_id: "123") } let(:log) { build(:sales_log, :completed, assigned_to: user) } let(:log_to_csv) { BulkUpload::SalesLogToCsv.new(log:) } - let(:bulk_upload) { create(:bulk_upload, user:, year: log.collection_start_year) } + let(:bulk_upload) { create(:bulk_upload, :sales, user:, year:) } let(:path) { file.path } let(:file) { Tempfile.new } diff --git a/spec/services/bulk_upload/sales/year2026/csv_parser_spec.rb b/spec/services/bulk_upload/sales/year2026/csv_parser_spec.rb index 41ed9e91a..ea97dfac7 100644 --- a/spec/services/bulk_upload/sales/year2026/csv_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2026/csv_parser_spec.rb @@ -15,8 +15,8 @@ RSpec.describe BulkUpload::Sales::Year2026::CsvParser do file.write("Can be empty?\n") file.write("Type of letting the question applies to\n") file.write("Duplicate check field?\n") - file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2025)) - file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2025)) + file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2026)) + file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2026)) file.write("\n") file.rewind end @@ -81,8 +81,8 @@ RSpec.describe BulkUpload::Sales::Year2026::CsvParser do file.write("Can be empty?\n") file.write("Type of letting the question applies to\n") file.write("Duplicate check field?\n") - file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2025, seed:)) - file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2025, seed:)) + file.write(BulkUpload::SalesLogToCsv.new(log:).default_field_numbers_row_for_year(2026, seed:)) + file.write(BulkUpload::SalesLogToCsv.new(log:).to_year_csv_row(2026, seed:)) file.rewind end diff --git a/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb b/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb index d424a5c25..f9fb2aa2c 100644 --- a/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb +++ b/spec/services/bulk_upload/sales/year2026/row_parser_spec.rb @@ -112,6 +112,12 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do field_105: "07", field_106: "2023", field_110: "900", + field_122: "F", + field_123: "F", + field_124: "M", + field_125: "M", + field_126: "R", + field_127: "R", } end @@ -1432,7 +1438,7 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do let(:attributes) { { bulk_upload: } } before do - build(:sales_log, owning_organisation: nil, saledate: nil, purchid: nil, age1: nil, sex1: nil, ecstat1: nil).save(validate: false) + build(:sales_log, owning_organisation: nil, saledate: nil, purchid: nil, age1: nil, sexrab1: nil, sex1: nil, ecstat1: nil).save(validate: false) end it "does not add duplicate logs validation to the blank row" do diff --git a/spec/services/imports/variable_definitions_service_spec.rb b/spec/services/imports/variable_definitions_service_spec.rb index 3c7a3b526..8e0ef297c 100644 --- a/spec/services/imports/variable_definitions_service_spec.rb +++ b/spec/services/imports/variable_definitions_service_spec.rb @@ -13,13 +13,13 @@ RSpec.describe Imports::VariableDefinitionsService, type: :service do describe "#call" do before do - allow(Dir).to receive(:glob).and_return(%w[lettings_download_23_24.csv lettings_download_24_25.csv sales_download_23_24.csv sales_download_24_25.csv]) + allow(Dir).to receive(:glob).and_return(%w[lettings_download_23_24.csv lettings_download_24_25.csv sales_download_23_24.csv sales_download_24_25.csv sales_download_26_27.csv]) allow(service).to receive(:process_file) end it "processes each file in the directory" do service.call - %w[lettings_download_23_24.csv lettings_download_24_25.csv sales_download_23_24.csv sales_download_24_25.csv].each do |file| + %w[lettings_download_23_24.csv lettings_download_24_25.csv sales_download_23_24.csv sales_download_24_25.csv sales_download_26_27.csv].each do |file| expect(service).to have_received(:process_file).with(file) end end