Browse Source

Merge branch 'main' into CLDC-3196-update-bu-resources-link

# Conflicts:
#	app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb
#	app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb
#	app/views/bulk_upload_shared/guidance.html.erb
#	spec/requests/bulk_upload_lettings_logs_controller_spec.rb
#	spec/requests/bulk_upload_sales_logs_controller_spec.rb
CLDC-3196-update-bu-resources-link
natdeanlewissoftwire 1 year ago
parent
commit
a53cf0120d
  1. 6
      app/models/derived_variables/lettings_log_variables.rb
  2. 14
      app/models/derived_variables/sales_log_variables.rb
  3. 2
      app/models/form/lettings/pages/property_number_of_bedrooms.rb
  4. 5
      app/models/form/lettings/questions/beds.rb
  5. 9
      app/models/form/lettings/questions/gender_identity1.rb
  6. 9
      app/models/form/lettings/questions/person_gender_identity.rb
  7. 190
      app/models/form/lettings/questions/reason.rb
  8. 40
      app/models/form/lettings/questions/reason_renewal.rb
  9. 2
      app/models/form/lettings/questions/wheelchair.rb
  10. 8
      app/models/form/sales/pages/buyer_previous.rb
  11. 6
      app/models/form/sales/pages/la_nominations.rb
  12. 2
      app/models/form/sales/questions/buyer_live.rb
  13. 4
      app/models/form/sales/questions/buyer_previous.rb
  14. 2
      app/models/form/sales/questions/discount.rb
  15. 9
      app/models/form/sales/questions/gender_identity1.rb
  16. 6
      app/models/form/sales/questions/gender_identity2.rb
  17. 6
      app/models/form/sales/questions/person_gender_identity.rb
  18. 1
      app/models/form/sales/questions/property_wheelchair_accessible.rb
  19. 4
      app/models/lettings_log.rb
  20. 18
      app/models/sales_log.rb
  21. 2
      app/models/validations/property_validations.rb
  22. 55
      app/models/validations/sales/sale_information_validations.rb
  23. 3
      app/models/validations/sales/soft_validations.rb
  24. 2
      app/services/bulk_upload/lettings/year2024/row_parser.rb
  25. 13
      app/services/bulk_upload/sales/year2024/row_parser.rb
  26. 13
      app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb
  27. 12
      app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb
  28. 23
      app/views/bulk_upload_shared/guidance.html.erb
  29. 8
      config/locales/en.yml
  30. 33
      spec/models/form/lettings/pages/property_number_of_bedrooms_spec.rb
  31. 4
      spec/models/form/lettings/pages/property_wheelchair_accessible_spec.rb
  32. 65
      spec/models/form/lettings/questions/beds_spec.rb
  33. 69
      spec/models/form/lettings/questions/gender_identity1_spec.rb
  34. 27
      spec/models/form/lettings/questions/person_gender_identity_spec.rb
  35. 85
      spec/models/form/lettings/questions/reason_renewal_spec.rb
  36. 215
      spec/models/form/lettings/questions/reason_spec.rb
  37. 16
      spec/models/form/lettings/questions/wheelchair_spec.rb
  38. 4
      spec/models/form/sales/pages/about_price_rtb_spec.rb
  39. 6
      spec/models/form/sales/pages/buyer_live_spec.rb
  40. 61
      spec/models/form/sales/pages/buyer_previous_spec.rb
  41. 53
      spec/models/form/sales/pages/la_nominations_spec.rb
  42. 4
      spec/models/form/sales/pages/property_wheelchair_accessible_spec.rb
  43. 28
      spec/models/form/sales/questions/buyer_live_spec.rb
  44. 31
      spec/models/form/sales/questions/buyer_previous_spec.rb
  45. 16
      spec/models/form/sales/questions/discount_spec.rb
  46. 31
      spec/models/form/sales/questions/gender_identity1_spec.rb
  47. 27
      spec/models/form/sales/questions/gender_identity2_spec.rb
  48. 27
      spec/models/form/sales/questions/person_gender_identity_spec.rb
  49. 16
      spec/models/form/sales/questions/property_wheelchair_accessible_spec.rb
  50. 289
      spec/models/validations/sales/sale_information_validations_spec.rb
  51. 30
      spec/models/validations/sales/soft_validations_spec.rb
  52. 6
      spec/requests/bulk_upload_lettings_logs_controller_spec.rb
  53. 7
      spec/requests/bulk_upload_sales_logs_controller_spec.rb
  54. 18
      spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb
  55. 52
      spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

6
app/models/derived_variables/lettings_log_variables.rb

@ -91,6 +91,9 @@ module DerivedVariables::LettingsLogVariables
self.prevten = 30 if owning_organisation&.provider_type == "LA" self.prevten = 30 if owning_organisation&.provider_type == "LA"
end end
end end
if form.start_year_after_2024? && is_bedsit?
self.beds = 1
end
child_under_16_constraints! child_under_16_constraints!
@ -179,6 +182,9 @@ private
self.wchair = nil self.wchair = nil
self.location_id = nil self.location_id = nil
end end
if form.start_year_after_2024? && (unittype_gn_changed? && unittype_gn_was == 2)
self.beds = nil
end
end end
def get_totelder def get_totelder

14
app/models/derived_variables/sales_log_variables.rb

@ -24,6 +24,10 @@ module DerivedVariables::SalesLogVariables
self.hhmemb = number_of_household_members self.hhmemb = number_of_household_members
self.hhtype = household_type self.hhtype = household_type
if saledate && form.start_year_after_2024?
self.soctenant = soctenant_from_prevten_values
end
self.uprn_known = 0 if address_answered_without_uprn? self.uprn_known = 0 if address_answered_without_uprn?
if uprn_known&.zero? if uprn_known&.zero?
@ -157,4 +161,14 @@ private
def address_answered_without_uprn? def address_answered_without_uprn?
[address_line1, town_or_city].all?(&:present?) && uprn.nil? && form.start_date.year >= 2023 [address_line1, town_or_city].all?(&:present?) && uprn.nil? && form.start_date.year >= 2023
end end
def soctenant_from_prevten_values
return unless prevten && shared_ownership_scheme?
prevten_was_social_housing? ? 1 : 2
end
def prevten_was_social_housing?
[1, 2].include?(prevten) || [1, 2].include?(prevtenbuy2)
end
end end

2
app/models/form/lettings/pages/property_number_of_bedrooms.rb

@ -2,7 +2,7 @@ class Form::Lettings::Pages::PropertyNumberOfBedrooms < ::Form::Page
def initialize(id, hsh, subsection) def initialize(id, hsh, subsection)
super super
@id = "property_number_of_bedrooms" @id = "property_number_of_bedrooms"
@depends_on = [{ "is_general_needs?" => true }] @depends_on = [{ "is_general_needs?" => true, "is_beds_inferred?" => false }]
end end
def questions def questions

5
app/models/form/lettings/questions/beds.rb

@ -9,8 +9,11 @@ class Form::Lettings::Questions::Beds < ::Form::Question
@check_answers_card_number = 0 @check_answers_card_number = 0
@max = 12 @max = 12
@min = 1 @min = 1
@hint_text = "If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom."
@step = 1 @step = 1
@question_number = 22 @question_number = 22
end end
def hint_text
form.start_year_after_2024? ? "If shared accommodation, enter the number of bedrooms occupied by this household." : "If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom."
end
end end

9
app/models/form/lettings/questions/gender_identity1.rb

@ -6,7 +6,6 @@ class Form::Lettings::Questions::GenderIdentity1 < ::Form::Question
@header = "Which of these best describes the lead tenant’s gender identity?" @header = "Which of these best describes the lead tenant’s gender identity?"
@type = "radio" @type = "radio"
@check_answers_card_number = 1 @check_answers_card_number = 1
@hint_text = "The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest."
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@question_number = 33 @question_number = 33
end end
@ -18,4 +17,12 @@ class Form::Lettings::Questions::GenderIdentity1 < ::Form::Question
"divider" => { "value" => true }, "divider" => { "value" => true },
"R" => { "value" => "Tenant prefers not to say" }, "R" => { "value" => "Tenant prefers not to say" },
}.freeze }.freeze
def hint_text
if form.start_year_after_2024?
"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."
else
"The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest."
end
end
end end

9
app/models/form/lettings/questions/person_gender_identity.rb

@ -6,7 +6,6 @@ class Form::Lettings::Questions::PersonGenderIdentity < ::Form::Question
@header = "Which of these best describes person #{person_index}’s gender identity?" @header = "Which of these best describes person #{person_index}’s gender identity?"
@type = "radio" @type = "radio"
@check_answers_card_number = person_index @check_answers_card_number = person_index
@hint_text = ""
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@question_number = 32 + (4 * person_index) @question_number = 32 + (4 * person_index)
end end
@ -18,4 +17,12 @@ class Form::Lettings::Questions::PersonGenderIdentity < ::Form::Question
"divider" => { "value" => true }, "divider" => { "value" => true },
"R" => { "value" => "Person prefers not to say" }, "R" => { "value" => "Person prefers not to say" },
}.freeze }.freeze
def hint_text
if form.start_year_after_2024?
"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."
else
""
end
end
end end

190
app/models/form/lettings/questions/reason.rb

@ -6,8 +6,7 @@ class Form::Lettings::Questions::Reason < ::Form::Question
@header = "What is the tenant’s main reason for the household leaving their last settled home?" @header = "What is the tenant’s main reason for the household leaving their last settled home?"
@type = "radio" @type = "radio"
@check_answers_card_number = 0 @check_answers_card_number = 0
@hint_text = "The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation or sleeping rough, their last settled home is where they were living previously." @hint_text = form.start_year_after_2024? ? "The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation, sleeping rough or otherwise homeless, their last settled home is where they were living previously." : "The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation or sleeping rough, their last settled home is where they were living previously."
@answer_options = ANSWER_OPTIONS
@conditional_for = { @conditional_for = {
"reasonother" => [ "reasonother" => [
20, 20,
@ -16,114 +15,81 @@ class Form::Lettings::Questions::Reason < ::Form::Question
@question_number = 77 @question_number = 77
end end
ANSWER_OPTIONS = { def answer_options
"40" => { if form.start_year_after_2024?
"value" => "End of assured shorthold tenancy (no fault)", {
}, "50" => { "value" => "End of social housing tenancy - no fault" },
"41" => { "51" => { "value" => "End of social housing tenancy - evicted due to anti-social behaviour (ASB)" },
"value" => "End of assured shorthold tenancy (eviction or tenant at fault)", "52" => { "value" => "End of social housing tenancy - evicted due to rent arrears" },
}, "53" => { "value" => "End of social housing tenancy - evicted for any other reason" },
"42" => { "1" => { "value" => "Permanently decanted from another property owned by this landlord" },
"value" => "End of fixed term tenancy (no fault)", "2" => { "value" => "Left home country as a refugee" },
}, "45" => { "value" => "Discharged from prison" },
"43" => { "46" => { "value" => "Discharged from long-stay hospital or similar institution" },
"value" => "End of fixed term tenancy (eviction or tenant at fault)", "4" => { "value" => "Loss of tied accommodation" },
}, "9" => { "value" => "Asked to leave by family or friends" },
"1" => { "8" => { "value" => "Relationship breakdown (non-violent) with partner" },
"value" => "Permanently decanted from another property owned by this landlord", "44" => { "value" => "Death of household member in last settled accommodation" },
}, "16" => { "value" => "To move nearer to family, friends or school" },
"46" => { "17" => { "value" => "To move nearer to work" },
"value" => "Discharged from long-stay hospital or similar institution", "48" => { "value" => "Domestic abuse - previously joint tenancy with partner" },
}, "49" => { "value" => "Domestic abuse - other" },
"45" => { "10" => { "value" => "Racial harassment" },
"value" => "Discharged from prison", "31" => { "value" => "Hate crime" },
}, "11" => { "value" => "Other problems with neighbours" },
"2" => { "34" => { "value" => "Repossession" },
"value" => "Left home country as a refugee", "54" => { "value" => "Could no longer afford rent or mortgage" },
}, "12" => { "value" => "Property unsuitable because of overcrowding" },
"4" => { "13" => { "value" => "Property unsuitable because of ill health or disability" },
"value" => "Loss of tied accommodation", "14" => { "value" => "Property unsuitable because of poor condition" },
}, "29" => { "value" => "Under occupation (offered incentive to downsize)" },
"9" => { "30" => { "value" => "Under occupation (no incentive)" },
"value" => "Asked to leave by family or friends", "18" => { "value" => "To move to accommodation with support" },
}, "19" => { "value" => "To move to independent accommodation" },
"44" => { "20" => { "value" => "Other" },
"value" => "Death of household member in last settled accommodation", "28" => { "value" => "Don’t know" },
}, "divider" => { "value" => true },
"8" => { "47" => { "value" => "Tenant prefers not to say" },
"value" => "Relationship breakdown (non-violent) with partner", }.freeze
}, else
"16" => { {
"value" => "To move nearer to family, friends or school", "40" => { "value" => "End of assured shorthold tenancy (no fault)" },
}, "41" => { "value" => "End of assured shorthold tenancy (eviction or tenant at fault)" },
"17" => { "42" => { "value" => "End of fixed term tenancy (no fault)" },
"value" => "To move nearer to work", "43" => { "value" => "End of fixed term tenancy (eviction or tenant at fault)" },
}, "1" => { "value" => "Permanently decanted from another property owned by this landlord" },
"48" => { "46" => { "value" => "Discharged from long-stay hospital or similar institution" },
"value" => "Domestic abuse - previously joint tenancy with partner", "45" => { "value" => "Discharged from prison" },
}, "2" => { "value" => "Left home country as a refugee" },
"49" => { "4" => { "value" => "Loss of tied accommodation" },
"value" => "Domestic abuse - other", "9" => { "value" => "Asked to leave by family or friends" },
}, "44" => { "value" => "Death of household member in last settled accommodation" },
"31" => { "8" => { "value" => "Relationship breakdown (non-violent) with partner" },
"value" => "Hate crime", "16" => { "value" => "To move nearer to family, friends or school" },
}, "17" => { "value" => "To move nearer to work" },
"10" => { "48" => { "value" => "Domestic abuse - previously joint tenancy with partner" },
"value" => "Racial harassment", "49" => { "value" => "Domestic abuse - other" },
}, "31" => { "value" => "Hate crime" },
"11" => { "10" => { "value" => "Racial harassment" },
"value" => "Other problems with neighbours", "11" => { "value" => "Other problems with neighbours" },
}, "35" => { "value" => "Couldn’t afford fees attached to renewing the tenancy" },
"35" => { "36" => { "value" => "Couldn’t afford increase in rent" },
"value" => "Couldn’t afford fees attached to renewing the tenancy", "38" => { "value" => "Couldn’t afford rent or mortgage (employment)" },
}, "37" => { "value" => "Couldn’t afford rent or mortgage (welfare reforms)" },
"36" => { "39" => { "value" => "Couldn’t afford rent or mortgage (other)" },
"value" => "Couldn’t afford increase in rent", "34" => { "value" => "Repossession" },
}, "12" => { "value" => "Property unsuitable because of overcrowding" },
"38" => { "13" => { "value" => "Property unsuitable because of ill health or disability" },
"value" => "Couldn’t afford rent or mortgage (employment)", "14" => { "value" => "Property unsuitable because of poor condition" },
}, "18" => { "value" => "To move to accommodation with support" },
"37" => { "19" => { "value" => "To move to independent accommodation" },
"value" => "Couldn’t afford rent or mortgage (welfare reforms)", "30" => { "value" => "Under occupation (no incentive)" },
}, "29" => { "value" => "Under occupation (offered incentive to downsize)" },
"39" => { "20" => { "value" => "Other" },
"value" => "Couldn’t afford rent or mortgage (other)", "47" => { "value" => "Tenant prefers not to say" },
}, "divider" => { "value" => true },
"34" => { "28" => { "value" => "Don’t know" },
"value" => "Repossession", }.freeze
}, end
"12" => { end
"value" => "Property unsuitable because of overcrowding",
},
"13" => {
"value" => "Property unsuitable because of ill health or disability",
},
"14" => {
"value" => "Property unsuitable because of poor condition",
},
"18" => {
"value" => "To move to accommodation with support",
},
"19" => {
"value" => "To move to independent accommodation",
},
"30" => {
"value" => "Under occupation (no incentive)",
},
"29" => {
"value" => "Under occupation (offered incentive to downsize)",
},
"20" => {
"value" => "Other",
},
"47" => {
"value" => "Tenant prefers not to say",
},
"divider" => {
"value" => true,
},
"28" => {
"value" => "Don’t know",
},
}.freeze
end end

40
app/models/form/lettings/questions/reason_renewal.rb

@ -7,7 +7,6 @@ class Form::Lettings::Questions::ReasonRenewal < ::Form::Question
@type = "radio" @type = "radio"
@check_answers_card_number = 0 @check_answers_card_number = 0
@hint_text = "You told us this letting is a renewal. We have removed some options because of this." @hint_text = "You told us this letting is a renewal. We have removed some options because of this."
@answer_options = ANSWER_OPTIONS
@question_number = 77 @question_number = 77
@conditional_for = { @conditional_for = {
"reasonother" => [ "reasonother" => [
@ -16,20 +15,27 @@ class Form::Lettings::Questions::ReasonRenewal < ::Form::Question
} }
end end
ANSWER_OPTIONS = { def answer_options
"40" => { "value" => "End of assured shorthold tenancy (no fault)" }, if form.start_year_after_2024?
"42" => { "value" => "End of fixed term tenancy (no fault)" }, {
"20" => { "50" => { "value" => "End of social housing tenancy - no fault" },
"value" => "Other", "51" => { "value" => "End of social housing tenancy - evicted due to anti-social behaviour (ASB)" },
}, "52" => { "value" => "End of social housing tenancy - evicted due to rent arrears" },
"47" => { "53" => { "value" => "End of social housing tenancy - evicted for any other reason" },
"value" => "Tenant prefers not to say", "20" => { "value" => "Other" },
}, "47" => { "value" => "Tenant prefers not to say" },
"divider" => { "divider" => { "value" => true },
"value" => true, "28" => { "value" => "Don’t know" },
}, }.freeze
"28" => { else
"value" => "Don’t know", {
}, "40" => { "value" => "End of assured shorthold tenancy (no fault)" },
}.freeze "42" => { "value" => "End of fixed term tenancy (no fault)" },
"20" => { "value" => "Other" },
"47" => { "value" => "Tenant prefers not to say" },
"divider" => { "value" => true },
"28" => { "value" => "Don’t know" },
}.freeze
end
end
end end

2
app/models/form/lettings/questions/wheelchair.rb

@ -6,7 +6,7 @@ class Form::Lettings::Questions::Wheelchair < ::Form::Question
@header = "Is the property built or adapted to wheelchair-user standards?" @header = "Is the property built or adapted to wheelchair-user standards?"
@type = "radio" @type = "radio"
@check_answers_card_number = 0 @check_answers_card_number = 0
@hint_text = "" @hint_text = form.start_year_after_2024? ? "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." : ""
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@question_number = 21 @question_number = 21
end end

8
app/models/form/sales/pages/buyer_previous.rb

@ -2,7 +2,7 @@ class Form::Sales::Pages::BuyerPrevious < ::Form::Page
def initialize(id, hsh, subsection, joint_purchase:) def initialize(id, hsh, subsection, joint_purchase:)
super(id, hsh, subsection) super(id, hsh, subsection)
@joint_purchase = joint_purchase @joint_purchase = joint_purchase
@depends_on = [{ "joint_purchase?" => joint_purchase }] @depends_on = [{ "joint_purchase?" => joint_purchase, "soctenant_is_inferred?" => false }]
end end
def questions def questions
@ -10,4 +10,10 @@ class Form::Sales::Pages::BuyerPrevious < ::Form::Page
Form::Sales::Questions::BuyerPrevious.new(nil, nil, self, joint_purchase: @joint_purchase), Form::Sales::Questions::BuyerPrevious.new(nil, nil, self, joint_purchase: @joint_purchase),
] ]
end end
def routed_to?(log, _current_user)
return false if log.is_staircase? && log.form.start_year_after_2024?
super
end
end end

6
app/models/form/sales/pages/la_nominations.rb

@ -9,4 +9,10 @@ class Form::Sales::Pages::LaNominations < ::Form::Page
Form::Sales::Questions::LaNominations.new(nil, nil, self), Form::Sales::Questions::LaNominations.new(nil, nil, self),
] ]
end end
def routed_to?(log, _current_user)
return false if log.staircase == 1 && log.form.start_year_after_2024?
super
end
end end

2
app/models/form/sales/questions/buyer_live.rb

@ -3,7 +3,7 @@ class Form::Sales::Questions::BuyerLive < ::Form::Question
super super
@id = "buylivein" @id = "buylivein"
@check_answer_label = "Buyers living in property" @check_answer_label = "Buyers living in property"
@header = "Will the buyers live in the property?" @header = form.start_year_after_2024? ? "Will any buyers live in the property?" : "Will the buyers live in the property?"
@type = "radio" @type = "radio"
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@question_number = 8 @question_number = 8

4
app/models/form/sales/questions/buyer_previous.rb

@ -21,4 +21,8 @@ class Form::Sales::Questions::BuyerPrevious < ::Form::Question
"2" => { "value" => "No" }, "2" => { "value" => "No" },
} }
end end
def derived?
form.start_year_after_2024?
end
end end

2
app/models/form/sales/questions/discount.rb

@ -6,7 +6,7 @@ class Form::Sales::Questions::Discount < ::Form::Question
@header = "What was the percentage discount?" @header = "What was the percentage discount?"
@type = "numeric" @type = "numeric"
@min = 0 @min = 0
@max = 100 @max = form.start_year_after_2024? ? 70 : 100
@step = 1 @step = 1
@width = 5 @width = 5
@suffix = "%" @suffix = "%"

9
app/models/form/sales/questions/gender_identity1.rb

@ -5,7 +5,6 @@ class Form::Sales::Questions::GenderIdentity1 < ::Form::Question
@check_answer_label = "Buyer 1’s gender identity" @check_answer_label = "Buyer 1’s gender identity"
@header = "Which of these best describes buyer 1’s gender identity?" @header = "Which of these best describes buyer 1’s gender identity?"
@type = "radio" @type = "radio"
@hint_text = "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."
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@check_answers_card_number = 1 @check_answers_card_number = 1
@question_number = 21 @question_number = 21
@ -17,4 +16,12 @@ class Form::Sales::Questions::GenderIdentity1 < ::Form::Question
"X" => { "value" => "Non-binary" }, "X" => { "value" => "Non-binary" },
"R" => { "value" => "Prefers not to say" }, "R" => { "value" => "Prefers not to say" },
}.freeze }.freeze
def hint_text
if form.start_year_after_2024?
"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."
else
"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."
end
end
end end

6
app/models/form/sales/questions/gender_identity2.rb

@ -22,4 +22,10 @@ class Form::Sales::Questions::GenderIdentity2 < ::Form::Question
"X" => { "value" => "Non-binary" }, "X" => { "value" => "Non-binary" },
"R" => { "value" => "Buyer prefers not to say" }, "R" => { "value" => "Buyer prefers not to say" },
}.freeze }.freeze
def hint_text
return unless form.start_year_after_2024?
"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."
end
end end

6
app/models/form/sales/questions/person_gender_identity.rb

@ -21,4 +21,10 @@ class Form::Sales::Questions::PersonGenderIdentity < ::Form::Question
"X" => { "value" => "Non-binary" }, "X" => { "value" => "Non-binary" },
"R" => { "value" => "Person prefers not to say" }, "R" => { "value" => "Person prefers not to say" },
}.freeze }.freeze
def hint_text
return unless form.start_year_after_2024?
"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."
end
end end

1
app/models/form/sales/questions/property_wheelchair_accessible.rb

@ -7,6 +7,7 @@ class Form::Sales::Questions::PropertyWheelchairAccessible < ::Form::Question
@type = "radio" @type = "radio"
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@question_number = 17 @question_number = 17
@hint_text = form.start_year_after_2024? ? "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." : nil
end end
ANSWER_OPTIONS = { ANSWER_OPTIONS = {

4
app/models/lettings_log.rb

@ -356,6 +356,10 @@ class LettingsLog < Log
unittype_gn == 2 unittype_gn == 2
end end
def is_beds_inferred?
form.start_year_after_2024? && is_bedsit?
end
def is_shared_housing? def is_shared_housing?
# 4: Shared flat or maisonette # 4: Shared flat or maisonette
# 9: Shared house # 9: Shared house

18
app/models/sales_log.rb

@ -470,6 +470,10 @@ class SalesLog < Log
form.start_date.year >= 2023 && uprn.present? ? "uprn" : nil].compact form.start_date.year >= 2023 && uprn.present? ? "uprn" : nil].compact
end end
def soctenant_is_inferred?
form.start_year_after_2024?
end
def duplicates def duplicates
SalesLog.where.not(duplicate_set_id: nil).where(duplicate_set_id:).where.not(id:) SalesLog.where.not(duplicate_set_id: nil).where(duplicate_set_id:).where.not(id:)
end end
@ -477,4 +481,18 @@ class SalesLog < Log
def nationality2_uk_or_prefers_not_to_say? def nationality2_uk_or_prefers_not_to_say?
nationality_all_buyer2_group&.zero? || nationality_all_buyer2_group == 826 nationality_all_buyer2_group&.zero? || nationality_all_buyer2_group == 826
end end
def is_staircase?
staircase == 1
end
def discount_value
return unless discount && value
value * discount / 100
end
def is_not_staircasing?
staircase == 2 || staircase == 3
end
end end

2
app/models/validations/property_validations.rb

@ -34,7 +34,7 @@ module Validations::PropertyValidations
def validate_shared_housing_rooms(record) def validate_shared_housing_rooms(record)
unless record.unittype_gn.nil? unless record.unittype_gn.nil?
if record.is_bedsit? && record.beds != 1 && record.beds.present? if record.is_bedsit? && record.beds != 1 && record.beds.present? && !record.form.start_year_after_2024?
record.errors.add :unittype_gn, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit") record.errors.add :unittype_gn, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit")
record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit") record.errors.add :beds, I18n.t("validations.property.unittype_gn.one_bedroom_bedsit")
end end

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

@ -55,4 +55,59 @@ module Validations::Sales::SaleInformationValidations
record.errors.add :type, I18n.t("validations.sale_information.monthly_rent.higher_than_expected") record.errors.add :type, I18n.t("validations.sale_information.monthly_rent.higher_than_expected")
end end
end end
def validate_grant_amount(record)
return unless record.saledate && record.form.start_year_after_2024?
return unless record.grant && (record.type == 8 || record.type == 21)
unless record.grant.between?(9_000, 16_000)
record.errors.add :grant, I18n.t("validations.sale_information.grant.out_of_range")
end
end
def validate_stairbought(record)
return unless record.stairbought && record.type
return unless record.saledate && record.form.start_year_after_2024?
max_stairbought = case record.type
when 30, 16, 28, 31, 32
90
when 2, 18
75
when 24
50
end
if max_stairbought && record.stairbought > max_stairbought
record.errors.add :stairbought, I18n.t("validations.sale_information.stairbought.over_max", max_stairbought:, type: record.form.get_question("type", record).answer_label(record))
record.errors.add :type, I18n.t("validations.sale_information.stairbought.over_max", max_stairbought:, type: record.form.get_question("type", record).answer_label(record))
end
end
def validate_discount_and_value(record)
return unless record.saledate && record.form.start_year_after_2024?
return unless record.discount && record.value && record.la
if record.london_property? && record.discount_value > 136_400
%i[discount value la postcode_full uprn].each do |field|
record.errors.add field, I18n.t("validations.sale_information.value.over_discounted_london_max", discount_value: record.field_formatted_as_currency("discount_value"))
end
elsif record.property_not_in_london? && record.discount_value > 102_400
%i[discount value la postcode_full uprn].each do |field|
record.errors.add field, I18n.t("validations.sale_information.value.over_discounted_max", discount_value: record.field_formatted_as_currency("discount_value"))
end
end
end
def validate_non_staircasing_mortgage(record)
return unless record.mortgage && record.value && record.deposit && record.equity
return unless record.is_not_staircasing?
return unless record.saledate && record.form.start_year_after_2024?
if record.mortgage_and_deposit_total != record.expected_shared_ownership_deposit_value
%i[mortgage value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sale_information.non_staircasing_mortgage", mortgage_and_deposit_total: record.field_formatted_as_currency("mortgage_and_deposit_total"), expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value"))
end
end
end
end end

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

@ -116,7 +116,8 @@ module Validations::Sales::SoftValidations
end end
def grant_outside_common_range? def grant_outside_common_range?
return unless grant return unless grant && type && saledate
return if form.start_year_after_2024? && (type == 21 || type == 8)
!grant.between?(9_000, 16_000) !grant.between?(9_000, 16_000)
end end

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

@ -1036,7 +1036,7 @@ private
attributes["unittype_gn"] = field_26 attributes["unittype_gn"] = field_26
attributes["builtype"] = field_27 attributes["builtype"] = field_27
attributes["wchair"] = field_28 attributes["wchair"] = field_28
attributes["beds"] = field_29 attributes["beds"] = field_26 == 2 ? 1 : field_29
attributes["joint"] = field_36 attributes["joint"] = field_36
attributes["startertenancy"] = field_37 attributes["startertenancy"] = field_37
attributes["tenancy"] = field_38 attributes["tenancy"] = field_38

13
app/services/bulk_upload/sales/year2024/row_parser.rb

@ -717,7 +717,6 @@ private
lanomagr: %i[field_97], lanomagr: %i[field_97],
frombeds: %i[field_98], frombeds: %i[field_98],
fromprop: %i[field_99], fromprop: %i[field_99],
soctenant: %i[field_98 field_99 field_100],
value: %i[field_101 field_114 field_125], value: %i[field_101 field_114 field_125],
equity: %i[field_102], equity: %i[field_102],
mortgage: %i[field_104 field_118 field_127], mortgage: %i[field_104 field_118 field_127],
@ -927,7 +926,7 @@ private
attributes["stairbought"] = field_87 attributes["stairbought"] = field_87
attributes["stairowned"] = field_88 attributes["stairowned"] = field_88
attributes["socprevten"] = field_100 attributes["socprevten"] = field_100
attributes["soctenant"] = [attributes["socprevten"], attributes["frombeds"], attributes["fromprop"]].any?(&:present?) ? 1 : 0 attributes["soctenant"] = infer_soctenant_from_prevten_and_prevtenbuy2
attributes["mortgageused"] = mortgageused attributes["mortgageused"] = mortgageused
attributes["uprn"] = field_22 attributes["uprn"] = field_22
@ -1123,6 +1122,16 @@ private
0 if field_62 == 1 0 if field_62 == 1
end end
def infer_soctenant_from_prevten_and_prevtenbuy2
return unless shared_ownership?
if [1, 2].include?(field_61) || [1, 2].include?(field_71.to_i)
1
else
2
end
end
def block_log_creation! def block_log_creation!
self.block_log_creation = true self.block_log_creation = true
end end

13
app/views/bulk_upload_lettings_logs/forms/prepare_your_file_2024.html.erb

@ -13,22 +13,17 @@
<h2 class="govuk-heading-s">Download template</h2> <h2 class="govuk-heading-s">Download template</h2>
<p class="govuk-body govuk-!-margin-bottom-2">Use this template to upload logs for 2024/25:</p> <p class="govuk-body govuk-!-margin-bottom-2"><%= govuk_link_to "Download the lettings bulk upload template (2024 to 2025)", @form.template_path %></p>
<ul class="govuk-list govuk-list--bullet"> <p class="govuk-body govuk-!-margin-bottom-2">There are 8 rows of content in the templates. These rows are called the ‘headers’. They contain the CORE form questions and guidance about which questions are required and how to format your answers.</p>
<li>
<%= govuk_link_to "Download the template", @form.template_path %>: In this template, the questions are in the same order as the 2024/25 paper form and web form.
</li>
</ul>
<p class="govuk-body govuk-!-margin-bottom-2">There are 7 or 8 rows of content in the templates. These rows are called the ‘headers’. They contain the CORE form questions and guidance about which questions are required and how to format your answers.</p>
<h2 class="govuk-heading-s">Create your file</h2> <h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. Leave column A blank - the bulk upload fields start in column B.</li> <li>Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. Leave column A blank - the bulk upload fields start in column B.</li>
<li>Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.</li> <li>Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.</li>
<li>Use the <%= govuk_link_to "Lettings #{@form.year_combo} Bulk Upload Specification", @form.specification_path %> to check your data is in the correct format.</li> <li>Use the <%= govuk_link_to "Lettings bulk upload Specification (2024 to 2025)", @form.specification_path %> to check your data is in the correct format.</li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li> <li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li>
<li>If you are using the new template, keep the headers. If you are using the legacy template, you can either keep or remove the headers. If you remove the headers, you should also remove the blank column A.</li> <li>If you have reordered the headers, keep the headers in the file.</li>
</ul> </ul>
<%= govuk_inset_text(text: "You can upload both general needs and supported housing logs in the same file for 2023/24 data.") %> <%= govuk_inset_text(text: "You can upload both general needs and supported housing logs in the same file for 2023/24 data.") %>

12
app/views/bulk_upload_sales_logs/forms/prepare_your_file_2024.html.erb

@ -13,19 +13,17 @@
<h2 class="govuk-heading-s">Download template</h2> <h2 class="govuk-heading-s">Download template</h2>
<p class="govuk-body govuk-!-margin-bottom-2">Use this template to upload logs for 2024/25:</p> <p class="govuk-body govuk-!-margin-bottom-2">Use one of these templates to upload logs for 2024/25:</p>
<ul class="govuk-list govuk-list--bullet"> <p class="govuk-body govuk-!-margin-bottom-2"><%= govuk_link_to "Download the sales bulk upload template (2024 to 2025)", @form.template_path %>: In this template, the questions are in the same order as the 2024/25 paper form and web form.</p>
<li><%= govuk_link_to "Download the template", @form.template_path %>: In this template, the questions are in the same order as the 2024/25 paper form and web form.</li> <p class="govuk-body govuk-!-margin-bottom-2">There are 8 rows of content in the templates. These rows are called the ‘headers’. They contain the CORE form questions and guidance about which questions are required and how to format your answers.</p>
</ul>
<p class="govuk-body govuk-!-margin-bottom-2">There are 7 or 8 rows of content in the templates. These rows are called the ‘headers’. They contain the CORE form questions and guidance about which questions are required and how to format your answers.</p>
<h2 class="govuk-heading-s">Create your file</h2> <h2 class="govuk-heading-s">Create your file</h2>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. The bulk upload fields start at column B. Leave column A blank.</li> <li>Fill in the template with data from your housing management system. Your data should go below the headers, with one row per log. The bulk upload fields start at column B. Leave column A blank.</li>
<li>Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.</li> <li>Make sure each column of your data aligns with the matching headers above. You may need to reorder your data.</li>
<li>Use the <%= govuk_link_to "Sales #{@form.year_combo} Bulk Upload Specification", @form.specification_path %> to check your data is in the correct format.</li> <li>Use the <%= govuk_link_to "Sales bulk upload Specification (2024 to 2025)", @form.specification_path %> to check your data is in the correct format.</li>
<li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li> <li><strong>Username field:</strong> To assign a log to someone else, enter the email address they use to log into CORE.</li>
<li>If you are using the new template, keep the headers. If you are using the legacy template, you can either keep or remove the headers. If you remove the headers, you should also remove the blank column A.</li> <li>If you have reordered the headers, keep the headers in the file.</li>
</ul> </ul>
<h2 class="govuk-heading-s">Save your file</h2> <h2 class="govuk-heading-s">Save your file</h2>

23
app/views/bulk_upload_shared/guidance.html.erb

@ -28,7 +28,11 @@
<%= accordion.with_section(heading_text: "Using the bulk upload template") do %> <%= accordion.with_section(heading_text: "Using the bulk upload template") do %>
<p class="govuk-body">For each collection year, we publish a bulk upload template and specification.</p> <p class="govuk-body">For each collection year, we publish a bulk upload template and specification.</p>
<p class="govuk-body">The bulk upload templates contain 7 or 8 rows of ‘headers’ with information about how to fill in the template, including:</p> <% if @form.year == 2023 %>
<p class="govuk-body">The bulk upload templates contain 7 or 8 rows of ‘headers’ with information about how to fill in the template, including:</p>
<% else %>
<p class="govuk-body">The bulk upload templates contain 8 rows of ‘headers’ with information about how to fill in the template, including:</p>
<% end %>
<ul class="govuk-list govuk-list--bullet"> <ul class="govuk-list govuk-list--bullet">
<li>the CORE form questions and their field numbers</li> <li>the CORE form questions and their field numbers</li>
@ -39,19 +43,20 @@
<p class="govuk-body">You can paste your data below the headers or copy the headers and insert them above the data in your file. The bulk upload fields start at column B. Leave column A blank.</p> <p class="govuk-body">You can paste your data below the headers or copy the headers and insert them above the data in your file. The bulk upload fields start at column B. Leave column A blank.</p>
<p class="govuk-body">Make sure that each column of data aligns with the corresponding question in the headers. We recommend ordering your data to match the headers, but you can also reorder the headers to match your data. When processing the file, we check what each column of data represents based on the headers above.</p> <p class="govuk-body">Make sure that each column of data aligns with the corresponding question in the headers. We recommend ordering your data to match the headers, but you can also reorder the headers to match your data. When processing the file, we check what each column of data represents based on the headers above.</p>
<% if @form.year == 2023 %>
<p class="govuk-body">For 2023/24 uploads, there are 2 templates to choose from, a new template and a legacy template. They outline suggested ways of ordering your data.</p>
<p class="govuk-body">You must include the headers in your file when you upload, unless your data matches the exact order of the legacy template. If you choose to remove the headers, you must also remove the blank column A.</p>
<% unless @form.year == 2023 %> <p class="govuk-body"><strong>New template</strong>: In this template, the questions are in the same order as the 2023/24 paper form and web form. Use this template if your organisation is new to bulk upload or if your housing management system matches the new column ordering.</p>
<p class="govuk-body">For 2023/24 uploads, there are 2 templates to choose from, a new template and a legacy template. They outline suggested ways of ordering your data.</p> <p class="govuk-body"><%= govuk_link_to @form.download_text("lettings", "template", "new"), @form.lettings_template_path %></p>
<p class="govuk-body">You must include the headers in your file when you upload, unless your data matches the exact order of the legacy template. If you choose to remove the headers, you must also remove the blank column A.</p> <p class="govuk-body"><%= govuk_link_to @form.download_text("sales", "template", "new"), @form.sales_template_path %></p>
<p class="govuk-body"><strong>New template</strong>: In this template, the questions are in the same order as the <%= @form.year_combo %> paper form and web form. Use this template if your organisation is new to bulk upload or if your housing management system matches the new column ordering.</p>
<% end %>
<p class="govuk-body"><%= govuk_link_to @form.download_text("lettings", "template", "new"), @form.lettings_template_path %></p>
<p class="govuk-body"><%= govuk_link_to @form.download_text("sales", "template", "new"), @form.sales_template_path %></p>
<% if @form.year == 2023 %>
<p class="govuk-body"><strong>Legacy template</strong>: In this template, the questions are in the same order as the 2022/23 template, with new questions added on to the end. Use this template if you have not updated your system to match the new template yet.</p> <p class="govuk-body"><strong>Legacy template</strong>: In this template, the questions are in the same order as the 2022/23 template, with new questions added on to the end. Use this template if you have not updated your system to match the new template yet.</p>
<p class="govuk-body"><%= govuk_link_to @form.download_text("lettings", "template", "legacy"), @form.lettings_legacy_template_path %></p> <p class="govuk-body"><%= govuk_link_to @form.download_text("lettings", "template", "legacy"), @form.lettings_legacy_template_path %></p>
<p class="govuk-body"><%= govuk_link_to @form.download_text("sales", "template", "legacy"), @form.sales_legacy_template_path %></p> <p class="govuk-body"><%= govuk_link_to @form.download_text("sales", "template", "legacy"), @form.sales_legacy_template_path %></p>
<% else %>
<p class="govuk-body"><%= govuk_link_to @form.download_text("lettings", "template"), @form.lettings_template_path %></p>
<p class="govuk-body"><%= govuk_link_to @form.download_text("sales", "template"), @form.sales_template_path %></p>
<% end %> <% end %>
<% end %> <% end %>

8
config/locales/en.yml

@ -615,6 +615,14 @@ en:
discounted_ownership_value: "The mortgage, deposit, and grant when added together is %{mortgage_deposit_and_grant_total}, and the purchase purchase price times by the discount is %{value_with_discount}. These figures should be the same" discounted_ownership_value: "The mortgage, deposit, and grant when added together is %{mortgage_deposit_and_grant_total}, and the purchase purchase price times by the discount is %{value_with_discount}. These figures should be the same"
monthly_rent: monthly_rent:
higher_than_expected: "Basic monthly rent must be between £0.00 and £9,999.00" higher_than_expected: "Basic monthly rent must be between £0.00 and £9,999.00"
grant:
out_of_range: "Loan, grants or subsidies must be between £9,000 and £16,000"
stairbought:
over_max: "The percentage bought in this staircasing transaction cannot be higher than %{max_stairbought}% for %{type} sales."
value:
over_discounted_london_max: "The percentage discount multiplied by the purchase price is %{discount_value}. This figure should not be more than £136,400 for properties in London."
over_discounted_max: "The percentage discount multiplied by the purchase price is %{discount_value}. This figure should not be more than £102,400 for properties outside of London."
non_staircasing_mortgage: "The mortgage and deposit added together is %{mortgage_and_deposit_total} and the purchase price times by the equity is %{expected_shared_ownership_deposit_value}. These figures should be the same."
merge_request: merge_request:
organisation_part_of_another_merge: "This organisation is part of another merge - select a different one" organisation_part_of_another_merge: "This organisation is part of another merge - select a different one"
organisation_not_selected: "Select an organisation from the search list" organisation_not_selected: "Select an organisation from the search list"

33
spec/models/form/lettings/pages/property_number_of_bedrooms_spec.rb

@ -0,0 +1,33 @@
require "rails_helper"
RSpec.describe Form::Lettings::Pages::PropertyNumberOfBedrooms, 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) }
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[beds])
end
it "has the correct id" do
expect(page.id).to eq("property_number_of_bedrooms")
end
it "has the correct header" do
expect(page.header).to be_nil
end
it "has the correct description" do
expect(page.description).to be_nil
end
it "has the correct depends_on" do
expect(page.depends_on).to eq([{ "is_general_needs?" => true, "is_beds_inferred?" => false }])
end
end

4
spec/models/form/lettings/pages/property_wheelchair_accessible_spec.rb

@ -5,6 +5,10 @@ RSpec.describe Form::Lettings::Pages::PropertyWheelchairAccessible, type: :model
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to be(subsection) expect(page.subsection).to be(subsection)
end end

65
spec/models/form/lettings/questions/beds_spec.rb

@ -0,0 +1,65 @@
require "rails_helper"
RSpec.describe Form::Lettings::Questions::Beds, 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) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
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("beds")
end
it "has the correct header" do
expect(question.header).to eq("How many bedrooms does the property have?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Number of bedrooms")
end
it "has the correct type" do
expect(question.type).to eq("numeric")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct min" do
expect(question.min).to eq(1)
end
it "has the correct max" do
expect(question.max).to eq(12)
end
context "with 2023/24 form" do
it "has the correct hint_text" do
expect(question.hint_text).to eq("If shared accommodation, enter the number of bedrooms occupied by this household. A bedsit has 1 bedroom.")
end
end
context "with 2024/25 form" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint_text" do
expect(question.hint_text).to eq("If shared accommodation, enter the number of bedrooms occupied by this household.")
end
end
end

69
spec/models/form/lettings/questions/gender_identity1_spec.rb

@ -0,0 +1,69 @@
require "rails_helper"
RSpec.describe Form::Lettings::Questions::GenderIdentity1, type: :model do
subject(:question) { described_class.new(nil, question_definition, page) }
let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has the correct id" do
expect(question.id).to eq("sex1")
end
it "has the correct header" do
expect(question.header).to eq("Which of these best describes the lead tenant’s gender identity?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Lead tenant’s gender identity")
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to eq(1)
end
it "has the correct type" do
expect(question.type).to eq("radio")
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"F" => { "value" => "Female" },
"M" => { "value" => "Male" },
"X" => { "value" => "Non-binary" },
"divider" => { "value" => true },
"R" => { "value" => "Tenant prefers not to say" },
})
end
context "with form year before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has the correct hint" do
expect(question.hint_text).to eq("The lead tenant is the person in the household who does the most paid work. If several people do the same paid work, the lead tenant is whoever is the oldest.")
end
end
context "with form year >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end
end

27
spec/models/form/lettings/questions/person_gender_identity_spec.rb

@ -6,6 +6,13 @@ RSpec.describe Form::Lettings::Questions::PersonGenderIdentity, type: :model do
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:person_index) { 2 } let(:person_index) { 2 }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -19,8 +26,24 @@ RSpec.describe Form::Lettings::Questions::PersonGenderIdentity, type: :model do
expect(question.derived?).to be false expect(question.derived?).to be false
end end
it "has the correct hint" do context "with form year before 2024" do
expect(question.hint_text).to eq("") before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has the correct hint" do
expect(question.hint_text).to eq("")
end
end
context "with form year >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end end
context "with person 2" do context "with person 2" do

85
spec/models/form/lettings/questions/reason_renewal_spec.rb

@ -0,0 +1,85 @@
require "rails_helper"
RSpec.describe Form::Lettings::Questions::ReasonRenewal, 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) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
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("reason")
end
it "has the correct header" do
expect(question.header).to eq("What is the tenant’s main reason for the household leaving their last settled home?")
end
it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Reason for leaving last settled home")
end
it "has the correct type" do
expect(question.type).to eq("radio")
end
it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to eq(0)
end
it "has the correct hint" do
expect(question.hint_text).to eq("You told us this letting is a renewal. We have removed some options because of this.")
end
it "has the correct conditional_for" do
expect(question.conditional_for).to eq({ "reasonother" => [20] })
end
it "is not marked as derived" do
expect(question).not_to be_derived
end
context "with 2023/24 form" do
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"40" => { "value" => "End of assured shorthold tenancy (no fault)" },
"42" => { "value" => "End of fixed term tenancy (no fault)" },
"20" => { "value" => "Other" },
"47" => { "value" => "Tenant prefers not to say" },
"divider" => { "value" => true },
"28" => { "value" => "Don’t know" },
})
end
end
context "with 2024/25 form" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct answer_options" do
expect(question.answer_options).to eq({
"50" => { "value" => "End of social housing tenancy - no fault" },
"51" => { "value" => "End of social housing tenancy - evicted due to anti-social behaviour (ASB)" },
"52" => { "value" => "End of social housing tenancy - evicted due to rent arrears" },
"53" => { "value" => "End of social housing tenancy - evicted for any other reason" },
"20" => { "value" => "Other" },
"47" => { "value" => "Tenant prefers not to say" },
"divider" => { "value" => true },
"28" => { "value" => "Don’t know" },
})
end
end
end

215
spec/models/form/lettings/questions/reason_spec.rb

@ -6,6 +6,14 @@ RSpec.describe Form::Lettings::Questions::Reason, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -31,10 +39,6 @@ RSpec.describe Form::Lettings::Questions::Reason, type: :model do
expect(question.check_answers_card_number).to eq(0) expect(question.check_answers_card_number).to eq(0)
end end
it "has the correct hint" do
expect(question.hint_text).to eq("The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation or sleeping rough, their last settled home is where they were living previously.")
end
it "has the correct conditional_for" do it "has the correct conditional_for" do
expect(question.conditional_for).to eq({ "reasonother" => [20] }) expect(question.conditional_for).to eq({ "reasonother" => [20] })
end end
@ -43,116 +47,97 @@ RSpec.describe Form::Lettings::Questions::Reason, type: :model do
expect(question).not_to be_derived expect(question).not_to be_derived
end end
it "has the correct answer_options" do context "with 2023/24 form" do
expect(question.answer_options).to eq({ it "has the correct hint" do
"40" => { expect(question.hint_text).to eq("The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation or sleeping rough, their last settled home is where they were living previously.")
"value" => "End of assured shorthold tenancy (no fault)", end
},
"41" => { it "has the correct answer_options" do
"value" => "End of assured shorthold tenancy (eviction or tenant at fault)", expect(question.answer_options).to eq({
}, "40" => { "value" => "End of assured shorthold tenancy (no fault)" },
"42" => { "41" => { "value" => "End of assured shorthold tenancy (eviction or tenant at fault)" },
"value" => "End of fixed term tenancy (no fault)", "42" => { "value" => "End of fixed term tenancy (no fault)" },
}, "43" => { "value" => "End of fixed term tenancy (eviction or tenant at fault)" },
"43" => { "1" => { "value" => "Permanently decanted from another property owned by this landlord" },
"value" => "End of fixed term tenancy (eviction or tenant at fault)", "46" => { "value" => "Discharged from long-stay hospital or similar institution" },
}, "45" => { "value" => "Discharged from prison" },
"1" => { "2" => { "value" => "Left home country as a refugee" },
"value" => "Permanently decanted from another property owned by this landlord", "4" => { "value" => "Loss of tied accommodation" },
}, "9" => { "value" => "Asked to leave by family or friends" },
"46" => { "44" => { "value" => "Death of household member in last settled accommodation" },
"value" => "Discharged from long-stay hospital or similar institution", "8" => { "value" => "Relationship breakdown (non-violent) with partner" },
}, "16" => { "value" => "To move nearer to family, friends or school" },
"45" => { "17" => { "value" => "To move nearer to work" },
"value" => "Discharged from prison", "48" => { "value" => "Domestic abuse - previously joint tenancy with partner" },
}, "49" => { "value" => "Domestic abuse - other" },
"2" => { "31" => { "value" => "Hate crime" },
"value" => "Left home country as a refugee", "10" => { "value" => "Racial harassment" },
}, "11" => { "value" => "Other problems with neighbours" },
"4" => { "35" => { "value" => "Couldn’t afford fees attached to renewing the tenancy" },
"value" => "Loss of tied accommodation", "36" => { "value" => "Couldn’t afford increase in rent" },
}, "38" => { "value" => "Couldn’t afford rent or mortgage (employment)" },
"9" => { "37" => { "value" => "Couldn’t afford rent or mortgage (welfare reforms)" },
"value" => "Asked to leave by family or friends", "39" => { "value" => "Couldn’t afford rent or mortgage (other)" },
}, "34" => { "value" => "Repossession" },
"44" => { "12" => { "value" => "Property unsuitable because of overcrowding" },
"value" => "Death of household member in last settled accommodation", "13" => { "value" => "Property unsuitable because of ill health or disability" },
}, "14" => { "value" => "Property unsuitable because of poor condition" },
"8" => { "18" => { "value" => "To move to accommodation with support" },
"value" => "Relationship breakdown (non-violent) with partner", "19" => { "value" => "To move to independent accommodation" },
}, "30" => { "value" => "Under occupation (no incentive)" },
"16" => { "29" => { "value" => "Under occupation (offered incentive to downsize)" },
"value" => "To move nearer to family, friends or school", "20" => { "value" => "Other" },
}, "47" => { "value" => "Tenant prefers not to say" },
"17" => { "divider" => { "value" => true },
"value" => "To move nearer to work", "28" => { "value" => "Don’t know" },
}, })
"48" => { end
"value" => "Domestic abuse - previously joint tenancy with partner", end
},
"49" => { context "with 2024/25 form" do
"value" => "Domestic abuse - other", before do
}, allow(form).to receive(:start_year_after_2024?).and_return(true)
"31" => { end
"value" => "Hate crime",
}, it "has the correct hint" do
"10" => { expect(question.hint_text).to eq("The tenant’s ‘last settled home’ is their last long-standing home. For tenants who were in temporary accommodation, sleeping rough or otherwise homeless, their last settled home is where they were living previously.")
"value" => "Racial harassment", end
},
"11" => { it "has the correct answer_options" do
"value" => "Other problems with neighbours", expect(question.answer_options).to eq({
}, "50" => { "value" => "End of social housing tenancy - no fault" },
"35" => { "51" => { "value" => "End of social housing tenancy - evicted due to anti-social behaviour (ASB)" },
"value" => "Couldn’t afford fees attached to renewing the tenancy", "52" => { "value" => "End of social housing tenancy - evicted due to rent arrears" },
}, "53" => { "value" => "End of social housing tenancy - evicted for any other reason" },
"36" => { "1" => { "value" => "Permanently decanted from another property owned by this landlord" },
"value" => "Couldn’t afford increase in rent", "2" => { "value" => "Left home country as a refugee" },
}, "45" => { "value" => "Discharged from prison" },
"38" => { "46" => { "value" => "Discharged from long-stay hospital or similar institution" },
"value" => "Couldn’t afford rent or mortgage (employment)", "4" => { "value" => "Loss of tied accommodation" },
}, "9" => { "value" => "Asked to leave by family or friends" },
"37" => { "8" => { "value" => "Relationship breakdown (non-violent) with partner" },
"value" => "Couldn’t afford rent or mortgage (welfare reforms)", "44" => { "value" => "Death of household member in last settled accommodation" },
}, "16" => { "value" => "To move nearer to family, friends or school" },
"39" => { "17" => { "value" => "To move nearer to work" },
"value" => "Couldn’t afford rent or mortgage (other)", "48" => { "value" => "Domestic abuse - previously joint tenancy with partner" },
}, "49" => { "value" => "Domestic abuse - other" },
"34" => { "10" => { "value" => "Racial harassment" },
"value" => "Repossession", "31" => { "value" => "Hate crime" },
}, "11" => { "value" => "Other problems with neighbours" },
"12" => { "34" => { "value" => "Repossession" },
"value" => "Property unsuitable because of overcrowding", "54" => { "value" => "Could no longer afford rent or mortgage" },
}, "12" => { "value" => "Property unsuitable because of overcrowding" },
"13" => { "13" => { "value" => "Property unsuitable because of ill health or disability" },
"value" => "Property unsuitable because of ill health or disability", "14" => { "value" => "Property unsuitable because of poor condition" },
}, "29" => { "value" => "Under occupation (offered incentive to downsize)" },
"14" => { "30" => { "value" => "Under occupation (no incentive)" },
"value" => "Property unsuitable because of poor condition", "18" => { "value" => "To move to accommodation with support" },
}, "19" => { "value" => "To move to independent accommodation" },
"18" => { "20" => { "value" => "Other" },
"value" => "To move to accommodation with support", "28" => { "value" => "Don’t know" },
}, "divider" => { "value" => true },
"19" => { "47" => { "value" => "Tenant prefers not to say" },
"value" => "To move to independent accommodation", })
}, end
"30" => {
"value" => "Under occupation (no incentive)",
},
"29" => {
"value" => "Under occupation (offered incentive to downsize)",
},
"20" => {
"value" => "Other",
},
"47" => {
"value" => "Tenant prefers not to say",
},
"divider" => {
"value" => true,
},
"28" => {
"value" => "Don’t know",
},
})
end end
end end

16
spec/models/form/lettings/questions/wheelchair_spec.rb

@ -4,6 +4,12 @@ RSpec.describe Form::Lettings::Questions::Wheelchair, type: :model do
subject(:question) { described_class.new(nil, nil, page) } subject(:question) { described_class.new(nil, nil, page) }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -39,4 +45,14 @@ RSpec.describe Form::Lettings::Questions::Wheelchair, type: :model do
it "is not marked as derived" do it "is not marked as derived" do
expect(question.derived?).to be false expect(question.derived?).to be false
end end
context "with 2024 form" do
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: true))
end
it "has the correct hint_text" do
expect(question.hint_text).to eq "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."
end
end
end end

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

@ -7,6 +7,10 @@ RSpec.describe Form::Sales::Pages::AboutPriceRtb, type: :model do
let(:page_definition) { nil } let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to eq(subsection) expect(page.subsection).to eq(subsection)
end end

6
spec/models/form/sales/pages/buyer_live_spec.rb

@ -6,6 +6,12 @@ RSpec.describe Form::Sales::Pages::BuyerLive, type: :model do
let(:page_id) { nil } let(:page_id) { nil }
let(:page_definition) { nil } let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to eq(subsection) expect(page.subsection).to eq(subsection)

61
spec/models/form/sales/pages/buyer_previous_spec.rb

@ -3,11 +3,21 @@ require "rails_helper"
RSpec.describe Form::Sales::Pages::BuyerPrevious, type: :model do RSpec.describe Form::Sales::Pages::BuyerPrevious, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection, joint_purchase:) } subject(:page) { described_class.new(page_id, page_definition, subsection, joint_purchase:) }
let(:log) { create(:sales_log, :completed) }
let(:page_id) { "example" } let(:page_id) { "example" }
let(:page_definition) { nil } let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
let(:joint_purchase) { false } let(:joint_purchase) { false }
before do
allow(subsection).to receive(:depends_on).and_return(nil)
allow(subsection).to receive(:enabled?).and_return(true)
allow(subsection).to receive(:form).and_return(form)
allow(form).to receive(:depends_on_met).and_return(true)
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to eq(subsection) expect(page.subsection).to eq(subsection)
end end
@ -32,13 +42,60 @@ RSpec.describe Form::Sales::Pages::BuyerPrevious, type: :model do
let(:joint_purchase) { true } let(:joint_purchase) { true }
it "has the correct depends on" do it "has the correct depends on" do
expect(page.depends_on).to eq([{ "joint_purchase?" => true }]) expect(page.depends_on).to eq([{ "joint_purchase?" => true, "soctenant_is_inferred?" => false }])
end end
end end
context "when sales is not a joint purchase" do context "when sales is not a joint purchase" do
it "has the correct depends on" do it "has the correct depends on" do
expect(page.depends_on).to eq([{ "joint_purchase?" => false }]) expect(page.depends_on).to eq([{ "joint_purchase?" => false, "soctenant_is_inferred?" => false }])
end
end
context "with 23/24 log" do
before do
Timecop.freeze(Time.zone.local(2023, 4, 2))
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
it "has correct routed to" do
log.staircase = 1
expect(page.routed_to?(log, nil)).to eq(true)
end
end
context "with 24/25 log" do
before do
Timecop.freeze(Time.zone.local(2024, 4, 2))
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
it "has correct routed to when staircase is yes" do
log.staircase = 1
expect(page.routed_to?(log, nil)).to eq(false)
end
it "has correct routed to when staircase is nil" do
log.staircase = nil
expect(page.routed_to?(log, nil)).to eq(true)
end
it "has correct routed to when staircase is no" do
log.staircase = 2
expect(page.routed_to?(log, nil)).to eq(true)
end
it "has correct routed to when staircase is don't know" do
log.staircase = 3
expect(page.routed_to?(log, nil)).to eq(true)
end end
end end
end end

53
spec/models/form/sales/pages/la_nominations_spec.rb

@ -3,10 +3,16 @@ require "rails_helper"
RSpec.describe Form::Sales::Pages::LaNominations, type: :model do RSpec.describe Form::Sales::Pages::LaNominations, type: :model do
subject(:page) { described_class.new(page_id, page_definition, subsection) } subject(:page) { described_class.new(page_id, page_definition, subsection) }
let(:log) { create(:sales_log, :completed) }
let(:page_id) { nil } let(:page_id) { nil }
let(:page_definition) { nil } let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
before do
allow(subsection).to receive(:depends_on).and_return(nil)
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to eq(subsection) expect(page.subsection).to eq(subsection)
end end
@ -26,4 +32,51 @@ RSpec.describe Form::Sales::Pages::LaNominations, type: :model do
it "has the correct description" do it "has the correct description" do
expect(page.description).to be_nil expect(page.description).to be_nil
end end
context "with 23/24 log" do
before do
Timecop.freeze(Time.zone.local(2023, 4, 2))
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
it "has correct routed to" do
log.staircase = 1
expect(page.routed_to?(log, nil)).to eq(true)
end
end
context "with 24/25 log" do
before do
Timecop.freeze(Time.zone.local(2024, 4, 2))
Singleton.__init__(FormHandler)
end
after do
Timecop.return
end
it "has correct routed to when staircase is yes" do
log.staircase = 1
expect(page.routed_to?(log, nil)).to eq(false)
end
it "has correct routed to when staircase is nil" do
log.staircase = nil
expect(page.routed_to?(log, nil)).to eq(true)
end
it "has correct routed to when staircase is no" do
log.staircase = 2
expect(page.routed_to?(log, nil)).to eq(true)
end
it "has correct routed to when staircase is don't know" do
log.staircase = 3
expect(page.routed_to?(log, nil)).to eq(true)
end
end
end end

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

@ -7,6 +7,10 @@ RSpec.describe Form::Sales::Pages::PropertyWheelchairAccessible, type: :model do
let(:page_definition) { nil } let(:page_definition) { nil }
let(:subsection) { instance_double(Form::Subsection) } let(:subsection) { instance_double(Form::Subsection) }
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct subsection" do it "has correct subsection" do
expect(page.subsection).to eq(subsection) expect(page.subsection).to eq(subsection)
end end

28
spec/models/form/sales/questions/buyer_live_spec.rb

@ -6,6 +6,14 @@ RSpec.describe Form::Sales::Questions::BuyerLive, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -15,10 +23,6 @@ RSpec.describe Form::Sales::Questions::BuyerLive, type: :model do
expect(question.id).to eq("buylivein") expect(question.id).to eq("buylivein")
end end
it "has the correct header" do
expect(question.header).to eq("Will the buyers live in the property?")
end
it "has the correct check_answer_label" do it "has the correct check_answer_label" do
expect(question.check_answer_label).to eq("Buyers living in property") expect(question.check_answer_label).to eq("Buyers living in property")
end end
@ -37,4 +41,20 @@ RSpec.describe Form::Sales::Questions::BuyerLive, type: :model do
"2" => { "value" => "No" }, "2" => { "value" => "No" },
}) })
end end
context "with 2023/24 form" do
it "has the correct header" do
expect(question.header).to eq("Will the buyers live in the property?")
end
end
context "with 2024/25 form" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct header" do
expect(question.header).to eq("Will any buyers live in the property?")
end
end
end end

31
spec/models/form/sales/questions/buyer_previous_spec.rb

@ -6,8 +6,15 @@ RSpec.describe Form::Sales::Questions::BuyerPrevious, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
let(:joint_purchase) { true } let(:joint_purchase) { true }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
end end
@ -42,10 +49,6 @@ RSpec.describe Form::Sales::Questions::BuyerPrevious, type: :model do
expect(question.type).to eq("radio") expect(question.type).to eq("radio")
end end
it "is not marked as derived" do
expect(question.derived?).to be false
end
it "has the correct displayed_answer_options" do it "has the correct displayed_answer_options" do
expect(question.displayed_answer_options(nil)).to eq({ expect(question.displayed_answer_options(nil)).to eq({
"1" => { "value" => "Yes" }, "1" => { "value" => "Yes" },
@ -68,4 +71,24 @@ RSpec.describe Form::Sales::Questions::BuyerPrevious, type: :model do
it "has the correct hint" do it "has the correct hint" do
expect(question.hint_text).to eq(nil) expect(question.hint_text).to eq(nil)
end end
context "when form year is before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "is not marked as derived" do
expect(question.derived?).to be false
end
end
context "when form year is >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "is marked as derived" do
expect(question.derived?).to be true
end
end
end end

16
spec/models/form/sales/questions/discount_spec.rb

@ -6,6 +6,12 @@ RSpec.describe Form::Sales::Questions::Discount, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -52,4 +58,14 @@ RSpec.describe Form::Sales::Questions::Discount, type: :model do
it "has correct max" do it "has correct max" do
expect(question.max).to eq(100) expect(question.max).to eq(100)
end end
context "with form start year after 2024" do
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: true))
end
it "has correct max" do
expect(question.max).to eq(70)
end
end
end end

31
spec/models/form/sales/questions/gender_identity1_spec.rb

@ -6,6 +6,13 @@ RSpec.describe Form::Sales::Questions::GenderIdentity1, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -31,10 +38,6 @@ RSpec.describe Form::Sales::Questions::GenderIdentity1, type: :model do
expect(question.derived?).to be false expect(question.derived?).to be false
end end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
it "has the correct answer_options" do it "has the correct answer_options" do
expect(question.answer_options).to eq({ expect(question.answer_options).to eq({
"F" => { "value" => "Female" }, "F" => { "value" => "Female" },
@ -47,4 +50,24 @@ RSpec.describe Form::Sales::Questions::GenderIdentity1, type: :model do
it "has the correct check_answers_card_number" do it "has the correct check_answers_card_number" do
expect(question.check_answers_card_number).to eq(1) expect(question.check_answers_card_number).to eq(1)
end end
context "with start year before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end
context "with start year >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end
end end

27
spec/models/form/sales/questions/gender_identity2_spec.rb

@ -6,6 +6,13 @@ RSpec.describe Form::Sales::Questions::GenderIdentity2, type: :model do
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -49,4 +56,24 @@ RSpec.describe Form::Sales::Questions::GenderIdentity2, type: :model do
{ "condition" => { "sex2" => "R" }, "value" => "Prefers not to say" }, { "condition" => { "sex2" => "R" }, "value" => "Prefers not to say" },
]) ])
end end
context "with start year before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
end
context "with start year >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end
end end

27
spec/models/form/sales/questions/person_gender_identity_spec.rb

@ -7,6 +7,13 @@ RSpec.describe Form::Sales::Questions::PersonGenderIdentity, type: :model do
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:person_index) { 2 } let(:person_index) { 2 }
let(:subsection) { instance_double(Form::Subsection) }
let(:form) { instance_double(Form) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(form)
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -29,6 +36,26 @@ RSpec.describe Form::Sales::Questions::PersonGenderIdentity, type: :model do
}) })
end end
context "when form year is before 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(false)
end
it "has the correct hint" do
expect(question.hint_text).to be_nil
end
end
context "when form year is >= 2024" do
before do
allow(form).to receive(:start_year_after_2024?).and_return(true)
end
it "has the correct hint" do
expect(question.hint_text).to eq("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.")
end
end
context "when person 2" do context "when person 2" do
let(:question_id) { "sex2" } let(:question_id) { "sex2" }
let(:person_index) { 2 } let(:person_index) { 2 }

16
spec/models/form/sales/questions/property_wheelchair_accessible_spec.rb

@ -6,6 +6,12 @@ RSpec.describe Form::Sales::Questions::PropertyWheelchairAccessible, type: :mode
let(:question_id) { nil } let(:question_id) { nil }
let(:question_definition) { nil } let(:question_definition) { nil }
let(:page) { instance_double(Form::Page) } let(:page) { instance_double(Form::Page) }
let(:subsection) { instance_double(Form::Subsection) }
before do
allow(page).to receive(:subsection).and_return(subsection)
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: false))
end
it "has correct page" do it "has correct page" do
expect(question.page).to eq(page) expect(question.page).to eq(page)
@ -38,4 +44,14 @@ RSpec.describe Form::Sales::Questions::PropertyWheelchairAccessible, type: :mode
"3" => { "value" => "Don't know" }, "3" => { "value" => "Don't know" },
}) })
end end
context "with 2024 form" do
before do
allow(subsection).to receive(:form).and_return(instance_double(Form, start_year_after_2024?: true))
end
it "has the correct hint_text" do
expect(question.hint_text).to eq("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.")
end
end
end end

289
spec/models/validations/sales/sale_information_validations_spec.rb

@ -467,4 +467,293 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
end end
end end
describe "#validate_grant_amount" do
context "when within permitted bounds" do
let(:record) { build(:sales_log, grant: 10_000, saledate: Time.zone.local(2024, 4, 5)) }
it "does not add an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors).not_to be_present
end
end
context "when over the max" do
let(:record) { build(:sales_log, type: 8, grant: 17_000, saledate: Time.zone.local(2024, 4, 5)) }
it "adds an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors[:grant]).to include("Loan, grants or subsidies must be between £9,000 and £16,000")
end
end
context "when under the min" do
let(:record) { build(:sales_log, type: 21, grant: 3, saledate: Time.zone.local(2024, 4, 5)) }
it "adds an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors[:grant]).to include("Loan, grants or subsidies must be between £9,000 and £16,000")
end
end
context "when grant is blank" do
let(:record) { build(:sales_log, type: 21, grant: nil, saledate: Time.zone.local(2024, 4, 5)) }
it "does not add an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors).not_to be_present
end
end
context "when over the max and type is not RTA of social homebuy" do
let(:record) { build(:sales_log, type: 9, grant: 17_000, saledate: Time.zone.local(2024, 4, 5)) }
it "does not add an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors).not_to be_present
end
end
context "when under the min and type is not RTA of social homebuy" do
let(:record) { build(:sales_log, type: 9, grant: 17_000, saledate: Time.zone.local(2024, 4, 5)) }
it "does not add error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors).not_to be_present
end
end
context "with log before 2024/25 collection" do
let(:record) { build(:sales_log, type: 8, grant: 3, saledate: Time.zone.local(2023, 4, 5)) }
it "does not add an error" do
sale_information_validator.validate_grant_amount(record)
expect(record.errors).not_to be_present
end
end
end
describe "#validate_stairbought" do
let(:now) { Time.zone.local(2024, 4, 4) }
before do
Timecop.freeze(now)
Singleton.__init__(FormHandler)
end
after do
Timecop.return
Singleton.__init__(FormHandler)
end
[
["Shared Ownership (new model lease)", 30, 90],
["Home Ownership for people with Long-Term Disabilities (HOLD)", 16, 90],
["Rent to Buy — Shared Ownership", 28, 90],
["Right to Shared Ownership (RtSO)", 31, 90],
["London Living Rent — Shared Ownership", 32, 90],
["Shared Ownership (old model lease)", 2, 75],
["Social HomeBuy — shared ownership purchase", 18, 75],
["Older Persons Shared Ownership", 24, 50],
].each do |label, type, max|
context "when ownership type is #{label}" do
let(:record) { build(:sales_log, ownershipsch: 1, type:, saledate: now) }
it "does not add an error if stairbought is under #{max}%" do
record.stairbought = max - 1
sale_information_validator.validate_stairbought(record)
expect(record.errors).to be_empty
end
it "does not add an error if stairbought is #{max}%" do
record.stairbought = max
sale_information_validator.validate_stairbought(record)
expect(record.errors).to be_empty
end
it "does not add an error if stairbought is not given" do
record.stairbought = nil
sale_information_validator.validate_stairbought(record)
expect(record.errors).to be_empty
end
it "adds an error if stairbought is over #{max}%" do
record.stairbought = max + 2
sale_information_validator.validate_stairbought(record)
expect(record.errors[:stairbought]).to include("The percentage bought in this staircasing transaction cannot be higher than #{max}% for #{label} sales.")
expect(record.errors[:type]).to include("The percentage bought in this staircasing transaction cannot be higher than #{max}% for #{label} sales.")
end
end
end
context "when the collection year is before 2024" do
let(:record) { build(:sales_log, ownershipsch: 1, type: 24, saledate: now, stairbought: 90) }
let(:now) { Time.zone.local(2023, 4, 4) }
it "does not add an error" do
sale_information_validator.validate_stairbought(record)
expect(record.errors).to be_empty
end
end
end
describe "#validate_discount_and_value" do
let(:record) { FactoryBot.build(:sales_log, value: 200_000, discount: 50, ownershipsch: 2, type: 9, saledate: now) }
let(:now) { Time.zone.local(2024, 4, 1) }
around do |example|
Timecop.freeze(now) do
example.run
end
Timecop.return
end
context "with a log in the 24/25 collection year" do
context "when in London" do
before do
record.la = "E09000001"
end
it "adds an error if value * discount is more than 136,400" do
record.discount = 80
sale_information_validator.validate_discount_and_value(record)
expect(record.errors["value"]).to include("The percentage discount multiplied by the purchase price is £160,000.00. This figure should not be more than £136,400 for properties in London.")
expect(record.errors["discount"]).to include("The percentage discount multiplied by the purchase price is £160,000.00. This figure should not be more than £136,400 for properties in London.")
expect(record.errors["la"]).to include("The percentage discount multiplied by the purchase price is £160,000.00. This figure should not be more than £136,400 for properties in London.")
expect(record.errors["postcode_full"]).to include("The percentage discount multiplied by the purchase price is £160,000.00. This figure should not be more than £136,400 for properties in London.")
expect(record.errors["uprn"]).to include("The percentage discount multiplied by the purchase price is £160,000.00. This figure should not be more than £136,400 for properties in London.")
end
it "does not add an error value * discount is less than 136,400" do
sale_information_validator.validate_discount_and_value(record)
expect(record.errors["value"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["la"]).to be_empty
expect(record.errors["postcode_full"]).to be_empty
expect(record.errors["uprn"]).to be_empty
end
end
context "when in outside of London" do
before do
record.la = "E06000015"
end
it "adds an error if value * discount is more than 136,400" do
record.discount = 52
sale_information_validator.validate_discount_and_value(record)
expect(record.errors["value"]).to include("The percentage discount multiplied by the purchase price is £104,000.00. This figure should not be more than £102,400 for properties outside of London.")
expect(record.errors["discount"]).to include("The percentage discount multiplied by the purchase price is £104,000.00. This figure should not be more than £102,400 for properties outside of London.")
expect(record.errors["la"]).to include("The percentage discount multiplied by the purchase price is £104,000.00. This figure should not be more than £102,400 for properties outside of London.")
expect(record.errors["postcode_full"]).to include("The percentage discount multiplied by the purchase price is £104,000.00. This figure should not be more than £102,400 for properties outside of London.")
expect(record.errors["uprn"]).to include("The percentage discount multiplied by the purchase price is £104,000.00. This figure should not be more than £102,400 for properties outside of London.")
end
it "does not add an error value * discount is less than 136,400" do
sale_information_validator.validate_discount_and_value(record)
expect(record.errors["value"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["la"]).to be_empty
expect(record.errors["postcode_full"]).to be_empty
expect(record.errors["uprn"]).to be_empty
end
end
end
context "when it is a 2023 log" do
let(:record) { FactoryBot.build(:sales_log, value: 200_000, discount: 80, ownershipsch: 2, type: 9, saledate: Time.zone.local(2023, 4, 1), la: "E06000015") }
it "does not add an error" do
sale_information_validator.validate_discount_and_value(record)
expect(record.errors["value"]).to be_empty
expect(record.errors["discount"]).to be_empty
expect(record.errors["la"]).to be_empty
expect(record.errors["postcode_full"]).to be_empty
expect(record.errors["uprn"]).to be_empty
end
end
end
describe "#validate_non_staircasing_mortgage" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, value: 30_000, equity: 28, ownershipsch: 1, type: 30, saledate: now) }
around do |example|
Timecop.freeze(now) do
Singleton.__init__(FormHandler)
example.run
end
Timecop.return
Singleton.__init__(FormHandler)
end
context "with a log in the 24/25 collection year" do
let(:now) { Time.zone.local(2024, 4, 4) }
context "when MORTGAGE + DEPOSIT does not equal VALUE * EQUITY/100 " do
context "and it is not a staircase transaction" do
before do
record.staircase = 2
end
it "adds an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
expect(record.errors["mortgage"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
expect(record.errors["value"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
expect(record.errors["deposit"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
expect(record.errors["equity"]).to include("The mortgage and deposit added together is £15,000.00 and the purchase price times by the equity is £8,400.00. These figures should be the same.")
end
end
context "and it is a staircase transaction" do
before do
record.staircase = 1
end
it "does not add an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
end
end
end
context "when MORTGAGE + DEPOSIT equals VALUE * EQUITY/100" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, staircase: 2, deposit: 5_000, value: 30_000, equity: 50, ownershipsch: 1, type: 30, saledate: now) }
it "does not add an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
end
end
end
context "when it is a 2023 log" do
let(:now) { Time.zone.local(2023, 4, 1) }
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, staircase: 2, deposit: 5_000, value: 30_000, equity: 28, ownershipsch: 1, type: 30, saledate: now) }
it "does not add an error" do
sale_information_validator.validate_non_staircasing_mortgage(record)
expect(record.errors["mortgage"]).to be_empty
expect(record.errors["value"]).to be_empty
expect(record.errors["deposit"]).to be_empty
expect(record.errors["equity"]).to be_empty
end
end
end
end end

30
spec/models/validations/sales/soft_validations_spec.rb

@ -660,21 +660,51 @@ RSpec.describe Validations::Sales::SoftValidations do
describe "#grant_outside_common_range?" do describe "#grant_outside_common_range?" do
it "returns true if grant is below 9000" do it "returns true if grant is below 9000" do
record.grant = 1_000 record.grant = 1_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
expect(record).to be_grant_outside_common_range expect(record).to be_grant_outside_common_range
end end
it "returns true if grant is above 16000" do it "returns true if grant is above 16000" do
record.grant = 100_000 record.grant = 100_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
expect(record).to be_grant_outside_common_range expect(record).to be_grant_outside_common_range
end end
it "returns false if grant is within expected range" do it "returns false if grant is within expected range" do
record.grant = 10_000 record.grant = 10_000
record.type = 9
record.saledate = Time.zone.local(2024, 1, 1)
expect(record).not_to be_grant_outside_common_range expect(record).not_to be_grant_outside_common_range
end end
it "returns false for logs after 2024 with RTA" do
record.grant = 100_000
record.type = 8
record.saledate = Time.zone.local(2025, 1, 1)
expect(record).not_to be_grant_outside_common_range
end
it "returns false for logs after 2024 with socialBuy" do
record.grant = 100_000
record.type = 21
record.saledate = Time.zone.local(2025, 1, 1)
expect(record).not_to be_grant_outside_common_range
end
it "returns true for logs after 2024 with other type" do
record.grant = 100_000
record.type = 9
record.saledate = Time.zone.local(2025, 1, 1)
expect(record).to be_grant_outside_common_range
end
end end
describe "#staircase_bought_above_fifty" do describe "#staircase_bought_above_fifty" do

6
spec/requests/bulk_upload_lettings_logs_controller_spec.rb

@ -49,7 +49,7 @@ RSpec.describe BulkUploadLettingsLogsController, type: :request do
it "shows guidance page with correct title" do it "shows guidance page with correct title" do
Timecop.freeze(2022, 1, 1) do Timecop.freeze(2022, 1, 1) do
get "/lettings-logs/bulk-upload-logs/guidance?form%5Byear%5D=#{expected_year}", params: {} get "/lettings-logs/bulk-upload-logs/guidance?form%5Byear%5D=2022", params: {}
expect(response.body).to include("How to upload logs in bulk") expect(response.body).to include("How to upload logs in bulk")
end end
@ -57,11 +57,9 @@ RSpec.describe BulkUploadLettingsLogsController, type: :request do
end end
context "when in crossover period" do context "when in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year }
it "shows guidance page with correct title" do it "shows guidance page with correct title" do
Timecop.freeze(2023, 6, 1) do Timecop.freeze(2023, 6, 1) do
get "/lettings-logs/bulk-upload-logs/guidance?form%5Byear%5D=#{expected_year}", params: {} get "/lettings-logs/bulk-upload-logs/guidance?form%5Byear%5D=2023", params: {}
expect(response.body).to include("How to upload logs in bulk") expect(response.body).to include("How to upload logs in bulk")
end end

7
spec/requests/bulk_upload_sales_logs_controller_spec.rb

@ -45,11 +45,10 @@ RSpec.describe BulkUploadSalesLogsController, type: :request do
describe "GET /sales-logs/bulk-upload-logs/guidance" do describe "GET /sales-logs/bulk-upload-logs/guidance" do
context "when not in crossover period" do context "when not in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year }
it "shows guidance page with correct title" do it "shows guidance page with correct title" do
Timecop.freeze(2022, 1, 1) do Timecop.freeze(2022, 1, 1) do
get "/sales-logs/bulk-upload-logs/guidance?form%5Byear%5D=#{expected_year}", params: {} get "/sales-logs/bulk-upload-logs/guidance?form%5Byear%5D=2022", params: {}
expect(response.body).to include("How to upload logs in bulk") expect(response.body).to include("How to upload logs in bulk")
end end
@ -57,11 +56,9 @@ RSpec.describe BulkUploadSalesLogsController, type: :request do
end end
context "when in crossover period" do context "when in crossover period" do
let(:expected_year) { FormHandler.instance.forms["current_sales"].start_date.year }
it "shows guidance page with correct title" do it "shows guidance page with correct title" do
Timecop.freeze(2023, 6, 1) do Timecop.freeze(2023, 6, 1) do
get "/sales-logs/bulk-upload-logs/guidance?form%5Byear%5D=#{expected_year}", params: {} get "/sales-logs/bulk-upload-logs/guidance?form%5Byear%5D=2023", params: {}
expect(response.body).to include("How to upload logs in bulk") expect(response.body).to include("How to upload logs in bulk")
end end

18
spec/services/bulk_upload/lettings/year2024/row_parser_spec.rb

@ -1816,6 +1816,24 @@ RSpec.describe BulkUpload::Lettings::Year2024::RowParser do
end end
end end
describe "#beds" do
context "when property is a bedsit" do
let(:attributes) { setup_section_params.merge({ field_26: 2, field_29: 2 }) }
it "sets value to 1 even if field_29 contradicts this" do
expect(parser.log.beds).to be(1)
end
end
context "when property is not a bedsit" do
let(:attributes) { setup_section_params.merge({ field_26: 1, field_29: 2 }) }
it "sets value to field_29" do
expect(parser.log.beds).to be(2)
end
end
end
describe "#cbl" do describe "#cbl" do
context "when field_112 is yes ie 1" do context "when field_112 is yes ie 1" do
let(:attributes) { { bulk_upload:, field_112: 1 } } let(:attributes) { { bulk_upload:, field_112: 1 } }

52
spec/services/bulk_upload/sales/year2024/row_parser_spec.rb

@ -1264,10 +1264,56 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
end end
describe "#soctenant" do describe "#soctenant" do
let(:attributes) { setup_section_params.merge({ field_99: "1" }) } context "when discounted ownership" do
let(:attributes) { valid_attributes.merge({ field_8: "2" }) }
it "is correctly set" do it "is set to nil" do
expect(parser.log.soctenant).to be(1) expect(parser.log.soctenant).to be_nil
end
end
context "when outright sale" do
let(:attributes) { valid_attributes.merge({ field_8: "3" }) }
it "is set to nil" do
expect(parser.log.soctenant).to be_nil
end
end
context "when shared ownership" do
context "when prevten is a social housing type" do
let(:attributes) { valid_attributes.merge({ field_8: "1", field_61: "1" }) }
it "is set to yes" do
expect(parser.log.soctenant).to be(1)
end
end
context "when prevten is not a social housing type" do
context "and prevtenbuy2 is a social housing type" do
let(:attributes) { valid_attributes.merge({ field_8: "1", field_61: "3", field_71: "2" }) }
it "is set to yes" do
expect(parser.log.soctenant).to be(1)
end
end
context "and prevtenbuy2 is not a social housing type" do
let(:attributes) { valid_attributes.merge({ field_8: "1", field_61: "3", field_71: "4" }) }
it "is set to no" do
expect(parser.log.soctenant).to be(2)
end
end
context "and prevtenbuy2 is blank" do
let(:attributes) { valid_attributes.merge({ field_8: "1", field_61: "3", field_71: nil }) }
it "is set to no" do
expect(parser.log.soctenant).to be(2)
end
end
end
end end
end end

Loading…
Cancel
Save