Browse Source

Merge branch 'main' into CLDC-868-purchase-price-validations

# Conflicts:
#	app/models/validations/sales/sale_information_validations.rb
#	app/models/validations/sales/soft_validations.rb
#	config/locales/en.yml
#	db/schema.rb
#	spec/models/form_handler_spec.rb
#	spec/models/validations/sales/sale_information_validations_spec.rb
#	spec/models/validations/sales/soft_validations_spec.rb
pull/1225/head
natdeanlewissoftwire 2 years ago
parent
commit
2f64c66aa9
  1. 8
      app/components/log_summary_component.html.erb
  2. 6
      app/controllers/lettings_logs_controller.rb
  3. 1
      app/controllers/logs_controller.rb
  4. 7
      app/helpers/tab_nav_helper.rb
  5. 2
      app/models/form.rb
  6. 21
      app/models/form/sales/pages/extra_borrowing_value_check.rb
  7. 18
      app/models/form/sales/pages/grant_value_check.rb
  8. 1
      app/models/form/sales/questions/buyer1_income.rb
  9. 2
      app/models/form/sales/questions/buyer1_income_known.rb
  10. 1
      app/models/form/sales/questions/buyer2_income.rb
  11. 2
      app/models/form/sales/questions/buyer2_income_known.rb
  12. 23
      app/models/form/sales/questions/extra_borrowing_value_check.rb
  13. 1
      app/models/form/sales/questions/grant.rb
  14. 23
      app/models/form/sales/questions/grant_value_check.rb
  15. 1
      app/models/form/sales/questions/mortgage_length.rb
  16. 2
      app/models/form/sales/questions/number_of_others_in_property.rb
  17. 5
      app/models/form/sales/subsections/discounted_ownership_scheme.rb
  18. 14
      app/models/lettings_log.rb
  19. 14
      app/models/log.rb
  20. 1
      app/models/organisation.rb
  21. 9
      app/models/sales_log.rb
  22. 1
      app/models/user.rb
  23. 4
      app/models/validations/sales/household_validations.rb
  24. 39
      app/models/validations/sales/sale_information_validations.rb
  25. 13
      app/models/validations/sales/soft_validations.rb
  26. 10
      app/services/filter_service.rb
  27. 17
      app/views/form/guidance/_what_counts_as_income_sales.html.erb
  28. 2
      app/views/form/page.html.erb
  29. 2
      app/views/logs/_log_list.html.erb
  30. 2
      config/environments/development.rb
  31. 2
      config/environments/test.rb
  32. 11
      config/locales/en.yml
  33. 15450
      config/rent_range_data/2022.csv
  34. 13
      db/migrate/20230110094518_remove_managing_organisation_id_from_sales_logs.rb
  35. 7
      db/migrate/20230118170602_add_extra_borrowing_value_check_to_sales.rb
  36. 5
      db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb
  37. 21
      db/schema.rb
  38. 2
      db/seeds.rb
  39. 39
      spec/components/log_summary_component_spec.rb
  40. 5
      spec/factories/sales_log.rb
  41. 2
      spec/features/form/check_answers_page_lettings_logs_spec.rb
  42. 4
      spec/features/form/check_answers_page_sales_logs_spec.rb
  43. 2
      spec/features/organisation_spec.rb
  44. 22
      spec/helpers/tab_nav_helper_spec.rb
  45. 9
      spec/models/form/sales/questions/buyer1_income_known_spec.rb
  46. 2
      spec/models/form/sales/questions/buyer1_income_spec.rb
  47. 9
      spec/models/form/sales/questions/buyer2_income_known_spec.rb
  48. 2
      spec/models/form/sales/questions/buyer2_income_spec.rb
  49. 4
      spec/models/form/sales/questions/mortgage_length_spec.rb
  50. 2
      spec/models/form/sales/questions/number_of_others_in_property_spec.rb
  51. 5
      spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb
  52. 4
      spec/models/form_handler_spec.rb
  53. 6
      spec/models/lettings_log_spec.rb
  54. 2
      spec/models/organisation_spec.rb
  55. 19
      spec/models/sales_log_spec.rb
  56. 323
      spec/models/validations/sales/sale_information_validations_spec.rb
  57. 103
      spec/models/validations/sales/soft_validations_spec.rb
  58. 1
      spec/requests/lettings_logs_controller_spec.rb
  59. 9
      spec/requests/organisations_controller_spec.rb
  60. 19
      spec/requests/sales_logs_controller_spec.rb

8
app/components/log_summary_component.html.erb

@ -25,7 +25,7 @@
<% end %> <% end %>
</header> </header>
<% if log.is_a?(LettingsLog) && (log.needstype? or log.startdate?) %> <% if log.lettings? && (log.needstype? or log.startdate?) %>
<p class="govuk-body govuk-!-margin-bottom-2"> <p class="govuk-body govuk-!-margin-bottom-2">
<% if log.needstype? %> <% if log.needstype? %>
<%= log.is_general_needs? ? "General needs" : "Supported housing" %><br> <%= log.is_general_needs? ? "General needs" : "Supported housing" %><br>
@ -37,18 +37,20 @@
<% end %> <% end %>
<% if current_user.support? || current_user.organisation.has_managing_agents? %> <% if current_user.support? || current_user.organisation.has_managing_agents? %>
<% if log.owning_organisation or log.managing_organisation %>
<dl class="app-metadata"> <dl class="app-metadata">
<% if log.owning_organisation %>
<div class="app-metadata__item"> <div class="app-metadata__item">
<dt class="app-metadata__term">Owned by</dt> <dt class="app-metadata__term">Owned by</dt>
<dd class="app-metadata__definition"><%= log.owning_organisation&.name %></dd> <dd class="app-metadata__definition"><%= log.owning_organisation&.name %></dd>
</div> </div>
<% end %>
<% if log.lettings? && log.managing_organisation %>
<div class="app-metadata__item"> <div class="app-metadata__item">
<dt class="app-metadata__term">Managed by</dt> <dt class="app-metadata__term">Managed by</dt>
<dd class="app-metadata__definition"><%= log.managing_organisation&.name %></dd> <dd class="app-metadata__definition"><%= log.managing_organisation&.name %></dd>
</div> </div>
</dl>
<% end %> <% end %>
</dl>
<% end %> <% end %>
</div> </div>

6
app/controllers/lettings_logs_controller.rb

@ -101,6 +101,12 @@ class LettingsLogsController < LogsController
end end
end end
def org_params
super.merge(
{ "managing_organisation_id" => current_user.organisation.id },
)
end
private private
def permitted_log_params def permitted_log_params

1
app/controllers/logs_controller.rb

@ -63,7 +63,6 @@ private
owning_organisation_id = current_user.organisation.holds_own_stock? ? current_user.organisation.id : nil owning_organisation_id = current_user.organisation.holds_own_stock? ? current_user.organisation.id : nil
{ {
"owning_organisation_id" => owning_organisation_id, "owning_organisation_id" => owning_organisation_id,
"managing_organisation_id" => current_user.organisation.id,
"created_by_id" => current_user.id, "created_by_id" => current_user.id,
} }
end end

7
app/helpers/tab_nav_helper.rb

@ -21,11 +21,4 @@ module TabNavHelper
role = "<span class=\"app-!-colour-muted\">#{user.role.to_s.humanize}</span>" role = "<span class=\"app-!-colour-muted\">#{user.role.to_s.humanize}</span>"
[user.organisation.name, role].join("\n") [user.organisation.name, role].join("\n")
end end
def tab_items(user)
[
{ name: t("Details"), url: details_organisation_path(user.organisation) },
{ name: t("Users"), url: users_organisation_path(user.organisation) },
]
end
end end

2
app/models/form.rb

@ -61,7 +61,7 @@ class Form
page_ids = subsection_for_page(page).pages.map(&:id) page_ids = subsection_for_page(page).pages.map(&:id)
page_index = page_ids.index(page.id) page_index = page_ids.index(page.id)
page_id = if page.id.include?("value_check") && log[page.questions[0].id] == 1 && page.routed_to?(log, current_user) page_id = if page.interruption_screen? && log[page.questions[0].id] == 1 && page.routed_to?(log, current_user)
previous_page(page_ids, page_index, log, current_user) previous_page(page_ids, page_index, log, current_user)
else else
page_ids[page_index + 1] page_ids[page_index + 1]

21
app/models/form/sales/pages/extra_borrowing_value_check.rb

@ -0,0 +1,21 @@
class Form::Sales::Pages::ExtraBorrowingValueCheck < Form::Page
def initialize(id, hsh, subsection)
super
@depends_on = [
{
"extra_borrowing_expected_but_not_reported?" => true,
},
]
@title_text = {
"translation" => "soft_validations.extra_borrowing.title",
}
@informative_text = {
}
end
def questions
@questions ||= [
Form::Sales::Questions::ExtraBorrowingValueCheck.new(nil, nil, self),
]
end
end

18
app/models/form/sales/pages/grant_value_check.rb

@ -0,0 +1,18 @@
class Form::Sales::Pages::GrantValueCheck < ::Form::Page
def initialize(id, hsh, subsection)
super
@id = "grant_value_check"
@depends_on = [
{
"grant_outside_common_range?" => true,
},
]
@informative_text = {}
end
def questions
@questions ||= [
Form::Sales::Questions::GrantValueCheck.new(nil, nil, self),
]
end
end

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

@ -4,6 +4,7 @@ class Form::Sales::Questions::Buyer1Income < ::Form::Question
@id = "income1" @id = "income1"
@check_answer_label = "Buyer 1’s gross annual income" @check_answer_label = "Buyer 1’s gross annual income"
@header = "Buyer 1’s gross annual income" @header = "Buyer 1’s gross annual income"
@hint_text = "Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments."
@type = "numeric" @type = "numeric"
@min = 0 @min = 0
@max = 999_999 @max = 999_999

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

@ -6,8 +6,6 @@ class Form::Sales::Questions::Buyer1IncomeKnown < ::Form::Question
@header = "Do you know buyer 1’s annual income?" @header = "Do you know buyer 1’s annual income?"
@type = "radio" @type = "radio"
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@guidance_position = GuidancePosition::BOTTOM
@guidance_partial = "what_counts_as_income_sales"
@conditional_for = { @conditional_for = {
"income1" => [0], "income1" => [0],
} }

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

@ -5,6 +5,7 @@ class Form::Sales::Questions::Buyer2Income < ::Form::Question
@check_answer_label = "Buyer 2’s gross annual income" @check_answer_label = "Buyer 2’s gross annual income"
@header = "Buyer 2’s gross annual income" @header = "Buyer 2’s gross annual income"
@type = "numeric" @type = "numeric"
@hint_text = "Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments."
@min = 0 @min = 0
@step = 1 @step = 1
@width = 5 @width = 5

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

@ -6,8 +6,6 @@ class Form::Sales::Questions::Buyer2IncomeKnown < ::Form::Question
@header = "Do you know buyer 2’s annual income?" @header = "Do you know buyer 2’s annual income?"
@type = "radio" @type = "radio"
@answer_options = ANSWER_OPTIONS @answer_options = ANSWER_OPTIONS
@guidance_position = GuidancePosition::BOTTOM
@guidance_partial = "what_counts_as_income_sales"
@conditional_for = { @conditional_for = {
"income2" => [0], "income2" => [0],
} }

23
app/models/form/sales/questions/extra_borrowing_value_check.rb

@ -0,0 +1,23 @@
class Form::Sales::Questions::ExtraBorrowingValueCheck < ::Form::Question
def initialize(id, hsh, page)
super(id, hsh, page)
@id = "extrabor_value_check"
@check_answer_label = "Extra borrowing confirmation"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"extrabor_value_check" => 0,
},
{
"extrabor_value_check" => 1,
},
],
}
@header = "Are you sure there is no extra borrowing?"
end
end

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

@ -6,6 +6,7 @@ class Form::Sales::Questions::Grant < ::Form::Question
@header = "What was the amount of any loan, grant, discount or subsidy given?" @header = "What was the amount of any loan, grant, discount or subsidy given?"
@type = "numeric" @type = "numeric"
@min = 0 @min = 0
@max = 999_999
@width = 5 @width = 5
@prefix = "£" @prefix = "£"
@hint_text = "For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB)" @hint_text = "For all schemes except Right to Buy (RTB), Preserved Right to Buy (PRTB), Voluntary Right to Buy (VRTB)"

23
app/models/form/sales/questions/grant_value_check.rb

@ -0,0 +1,23 @@
class Form::Sales::Questions::GrantValueCheck < ::Form::Question
def initialize(id, hsh, page)
super
@id = "grant_value_check"
@check_answer_label = "Grant value confirmation"
@header = "Are you sure? Grants are usually £9,000 - £16,000"
@type = "interruption_screen"
@answer_options = {
"0" => { "value" => "Yes" },
"1" => { "value" => "No" },
}
@hidden_in_check_answers = {
"depends_on" => [
{
"grant_value_check" => 0,
},
{
"grant_value_check" => 1,
},
],
}
end
end

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

@ -8,5 +8,6 @@ class Form::Sales::Questions::MortgageLength < ::Form::Question
@min = 0 @min = 0
@width = 5 @width = 5
@suffix = " years" @suffix = " years"
@hint_text = "You should round up to the nearest year. Value should not exceed 60 years."
end end
end end

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

@ -3,7 +3,7 @@ class Form::Sales::Questions::NumberOfOthersInProperty < ::Form::Question
super super
@id = "hholdcount" @id = "hholdcount"
@check_answer_label = "Number of other people living in the property" @check_answer_label = "Number of other people living in the property"
@header = "Besides the buyers, how many other people live in the property?" @header = "Besides the buyer(s), how many other people live or will live in the property?"
@type = "numeric" @type = "numeric"
@hint_text = "You can provide details for a maximum of 4 other people." @hint_text = "You can provide details for a maximum of 4 other people."
@width = 2 @width = 2

5
app/models/form/sales/subsections/discounted_ownership_scheme.rb

@ -10,15 +10,20 @@ class Form::Sales::Subsections::DiscountedOwnershipScheme < ::Form::Subsection
@pages ||= [ @pages ||= [
Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_discounted_ownership", nil, self), Form::Sales::Pages::LivingBeforePurchase.new("living_before_purchase_discounted_ownership", nil, self),
Form::Sales::Pages::AboutPriceRtb.new(nil, nil, self), Form::Sales::Pages::AboutPriceRtb.new(nil, nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_price_value_check", nil, self),
Form::Sales::Pages::AboutPriceNotRtb.new(nil, nil, self), Form::Sales::Pages::AboutPriceNotRtb.new(nil, nil, self),
Form::Sales::Pages::GrantValueCheck.new(nil, nil, self),
Form::Sales::Pages::PurchasePrice.new("purchase_price_discounted_ownership", nil, self), Form::Sales::Pages::PurchasePrice.new("purchase_price_discounted_ownership", nil, self),
Form::Sales::Pages::Mortgageused.new("mortgage_used_discounted_ownership", nil, self), Form::Sales::Pages::Mortgageused.new("mortgage_used_discounted_ownership", nil, self),
Form::Sales::Pages::MortgageAmount.new("mortgage_amount_discounted_ownership", nil, self), Form::Sales::Pages::MortgageAmount.new("mortgage_amount_discounted_ownership", nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_mortgage_value_check", nil, self),
Form::Sales::Pages::MortgageLender.new("mortgage_lender_discounted_ownership", nil, self), Form::Sales::Pages::MortgageLender.new("mortgage_lender_discounted_ownership", nil, self),
Form::Sales::Pages::MortgageLenderOther.new("mortgage_lender_other_discounted_ownership", nil, self), Form::Sales::Pages::MortgageLenderOther.new("mortgage_lender_other_discounted_ownership", nil, self),
Form::Sales::Pages::MortgageLength.new("mortgage_length_discounted_ownership", nil, self), Form::Sales::Pages::MortgageLength.new("mortgage_length_discounted_ownership", nil, self),
Form::Sales::Pages::ExtraBorrowing.new("extra_borrowing_discounted_ownership", nil, self), Form::Sales::Pages::ExtraBorrowing.new("extra_borrowing_discounted_ownership", nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_value_check", nil, self),
Form::Sales::Pages::AboutDepositWithoutDiscount.new("about_deposit_discounted_ownership", nil, self), Form::Sales::Pages::AboutDepositWithoutDiscount.new("about_deposit_discounted_ownership", nil, self),
Form::Sales::Pages::ExtraBorrowingValueCheck.new("extra_borrowing_deposit_value_check", nil, self),
Form::Sales::Pages::DepositValueCheck.new("discounted_ownership_deposit_value_check", nil, self), Form::Sales::Pages::DepositValueCheck.new("discounted_ownership_deposit_value_check", nil, self),
Form::Sales::Pages::LeaseholdCharges.new("leasehold_charges_discounted_ownership", nil, self), Form::Sales::Pages::LeaseholdCharges.new("leasehold_charges_discounted_ownership", nil, self),
] ]

14
app/models/lettings_log.rb

@ -35,6 +35,7 @@ class LettingsLog < Log
belongs_to :scheme, optional: true belongs_to :scheme, optional: true
belongs_to :location, optional: true belongs_to :location, optional: true
belongs_to :managing_organisation, class_name: "Organisation", optional: true
scope :filter_by_year, ->(year) { where(startdate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) } scope :filter_by_year, ->(year) { where(startdate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) }
scope :filter_by_tenant_code, ->(tenant_code) { where("tenancycode ILIKE ?", "%#{tenant_code}%") } scope :filter_by_tenant_code, ->(tenant_code) { where("tenancycode ILIKE ?", "%#{tenant_code}%") }
@ -50,6 +51,7 @@ class LettingsLog < Log
} }
scope :filter_by_before_startdate, ->(date) { where("lettings_logs.startdate >= ?", date) } scope :filter_by_before_startdate, ->(date) { where("lettings_logs.startdate >= ?", date) }
scope :unresolved, -> { where(unresolved: true) } scope :unresolved, -> { where(unresolved: true) }
scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org).or(where(managing_organisation: org)) }
AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze AUTOGENERATED_FIELDS = %w[id status created_at updated_at discarded_at].freeze
OPTIONAL_FIELDS = %w[first_time_property_let_as_social_housing tenancycode propcode].freeze OPTIONAL_FIELDS = %w[first_time_property_let_as_social_housing tenancycode propcode].freeze
@ -495,6 +497,18 @@ class LettingsLog < Log
update(unresolved: false) update(unresolved: false)
end end
def managing_organisation_provider_type
managing_organisation&.provider_type
end
def reset_created_by!
return unless updated_by&.support?
return if owning_organisation.blank? || managing_organisation.blank? || created_by.blank?
return if created_by&.organisation == managing_organisation || created_by&.organisation == owning_organisation
update!(created_by: nil)
end
private private
def reset_derived_questions def reset_derived_questions

14
app/models/log.rb

@ -2,7 +2,6 @@ class Log < ApplicationRecord
self.abstract_class = true self.abstract_class = true
belongs_to :owning_organisation, class_name: "Organisation", optional: true belongs_to :owning_organisation, class_name: "Organisation", optional: true
belongs_to :managing_organisation, class_name: "Organisation", optional: true
belongs_to :created_by, class_name: "User", optional: true belongs_to :created_by, class_name: "User", optional: true
belongs_to :updated_by, class_name: "User", optional: true belongs_to :updated_by, class_name: "User", optional: true
belongs_to :bulk_upload, optional: true belongs_to :bulk_upload, optional: true
@ -12,7 +11,6 @@ class Log < ApplicationRecord
STATUS = { "not_started" => 0, "in_progress" => 1, "completed" => 2 }.freeze STATUS = { "not_started" => 0, "in_progress" => 1, "completed" => 2 }.freeze
enum status: STATUS enum status: STATUS
scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org).or(where(managing_organisation: org)) }
scope :filter_by_status, ->(status, _user = nil) { where status: } scope :filter_by_status, ->(status, _user = nil) { where status: }
scope :filter_by_years, lambda { |years, _user = nil| scope :filter_by_years, lambda { |years, _user = nil|
first_year = years.shift first_year = years.shift
@ -45,10 +43,6 @@ class Log < ApplicationRecord
ethnic_group == 17 ethnic_group == 17
end end
def managing_organisation_provider_type
managing_organisation&.provider_type
end
def collection_period_open? def collection_period_open?
form.end_date > Time.zone.today form.end_date > Time.zone.today
end end
@ -115,14 +109,6 @@ private
reset_created_by! reset_created_by!
end end
def reset_created_by!
return unless updated_by&.support?
return if owning_organisation.blank? || managing_organisation.blank? || created_by.blank?
return if created_by&.organisation == managing_organisation || created_by&.organisation == owning_organisation
update!(created_by: nil)
end
PIO = PostcodeService.new PIO = PostcodeService.new
def process_previous_postcode_changes! def process_previous_postcode_changes!

1
app/models/organisation.rb

@ -3,7 +3,6 @@ class Organisation < ApplicationRecord
has_many :owned_lettings_logs, class_name: "LettingsLog", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_lettings_logs, class_name: "LettingsLog", foreign_key: "owning_organisation_id", dependent: :delete_all
has_many :managed_lettings_logs, class_name: "LettingsLog", foreign_key: "managing_organisation_id" has_many :managed_lettings_logs, class_name: "LettingsLog", foreign_key: "managing_organisation_id"
has_many :owned_sales_logs, class_name: "SalesLog", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_sales_logs, class_name: "SalesLog", foreign_key: "owning_organisation_id", dependent: :delete_all
has_many :managed_sales_logs, class_name: "SalesLog", foreign_key: "managing_organisation_id"
has_many :data_protection_confirmations has_many :data_protection_confirmations
has_many :organisation_rent_periods has_many :organisation_rent_periods
has_many :owned_schemes, class_name: "Scheme", foreign_key: "owning_organisation_id", dependent: :delete_all has_many :owned_schemes, class_name: "Scheme", foreign_key: "owning_organisation_id", dependent: :delete_all

9
app/models/sales_log.rb

@ -32,6 +32,7 @@ class SalesLog < Log
scope :filter_by_year, ->(year) { where(saledate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) } scope :filter_by_year, ->(year) { where(saledate: Time.zone.local(year.to_i, 4, 1)...Time.zone.local(year.to_i + 1, 4, 1)) }
scope :search_by, ->(param) { filter_by_id(param) } scope :search_by, ->(param) { filter_by_id(param) }
scope :filter_by_organisation, ->(org, _user = nil) { where(owning_organisation: org) }
OPTIONAL_FIELDS = %w[purchid].freeze OPTIONAL_FIELDS = %w[purchid].freeze
RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze RETIREMENT_AGES = { "M" => 65, "F" => 60, "X" => 65 }.freeze
@ -184,6 +185,14 @@ class SalesLog < Log
process_postcode(postcode_full, "pcodenk", "is_la_inferred", "la") process_postcode(postcode_full, "pcodenk", "is_la_inferred", "la")
end end
def reset_created_by!
return unless updated_by&.support?
return if owning_organisation.blank? || created_by.blank?
return if created_by&.organisation == owning_organisation
update!(created_by: nil)
end
def retirement_age_for_person(person_num) def retirement_age_for_person(person_num)
gender = public_send("sex#{person_num}".to_sym) gender = public_send("sex#{person_num}".to_sym)
return unless gender return unless gender

1
app/models/user.rb

@ -10,7 +10,6 @@ class User < ApplicationRecord
has_many :owned_lettings_logs, through: :organisation has_many :owned_lettings_logs, through: :organisation
has_many :managed_lettings_logs, through: :organisation has_many :managed_lettings_logs, through: :organisation
has_many :owned_sales_logs, through: :organisation has_many :owned_sales_logs, through: :organisation
has_many :managed_sales_logs, through: :organisation
has_many :legacy_users has_many :legacy_users
has_many :bulk_uploads has_many :bulk_uploads

4
app/models/validations/sales/household_validations.rb

@ -109,10 +109,6 @@ private
economic_status == 7 economic_status == 7
end end
def person_economic_status_refused?(economic_status)
economic_status == 10
end
def person_is_child?(relationship) def person_is_child?(relationship)
relationship == "C" relationship == "C"
end end

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

@ -16,6 +16,29 @@ module Validations::Sales::SaleInformationValidations
end end
end end
def validate_years_living_in_property_before_purchase(record)
return unless record.proplen && record.proplen.nonzero?
case record.type
when 18
record.errors.add :type, I18n.t("validations.sale_information.proplen.social_homebuy")
record.errors.add :proplen, I18n.t("validations.sale_information.proplen.social_homebuy")
when 28, 29
record.errors.add :type, I18n.t("validations.sale_information.proplen.rent_to_buy")
record.errors.add :proplen, I18n.t("validations.sale_information.proplen.rent_to_buy")
end
end
def validate_exchange_date(record)
return unless record.exdate && record.saledate
record.errors.add(:exdate, I18n.t("validations.sale_information.exdate.must_be_before_saledate")) if record.exdate > record.saledate
return if (record.saledate.to_date - record.exdate.to_date).to_i / 365 < 1
record.errors.add(:exdate, I18n.t("validations.sale_information.exdate.must_be_less_than_1_year_from_saledate"))
end
def validate_previous_property_unit_type(record) def validate_previous_property_unit_type(record)
return unless record.fromprop && record.frombeds return unless record.fromprop && record.frombeds
@ -24,4 +47,20 @@ module Validations::Sales::SaleInformationValidations
record.errors.add :fromprop, I18n.t("validations.sale_information.previous_property_type.property_type_bedsit") record.errors.add :fromprop, I18n.t("validations.sale_information.previous_property_type.property_type_bedsit")
end end
end end
def validate_discounted_ownership_value(record)
return unless record.value && record.deposit && record.ownershipsch
return unless record.mortgage || record.mortgageused == 2
return unless record.discount || record.grant || record.type == 29
discount_amount = record.discount ? record.value * record.discount / 100 : 0
grant_amount = record.grant || 0
mortgage_amount = record.mortgage || 0
value_with_discount = (record.value - discount_amount)
if mortgage_amount + record.deposit + grant_amount != value_with_discount && record.discounted_ownership_sale?
%i[mortgage deposit grant value discount ownershipsch].each do |field|
record.errors.add field, I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: sprintf("%.2f", value_with_discount))
end
end
end
end end

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

@ -37,6 +37,13 @@ module Validations::Sales::SoftValidations
deposit > savings * 4 / 3 deposit > savings * 4 / 3
end end
def extra_borrowing_expected_but_not_reported?
return unless extrabor && mortgage && deposit && value && discount
extrabor != 1 && mortgage + deposit > value - value * discount / 100
end
def hodate_3_years_or_more_exdate? def hodate_3_years_or_more_exdate?
return unless hodate && exdate return unless hodate && exdate
@ -57,6 +64,12 @@ module Validations::Sales::SoftValidations
value < sale_range.soft_min ? sale_range.soft_min : sale_range.soft_max value < sale_range.soft_min ? sale_range.soft_min : sale_range.soft_max
end end
def grant_outside_common_range?
return unless grant
!grant.between?(9_000, 16_000)
end
private private
def sale_range def sale_range

10
app/services/filter_service.rb

@ -17,6 +17,14 @@ class FilterService
logs = logs.public_send("filter_by_#{category}", values, user) logs = logs.public_send("filter_by_#{category}", values, user)
end end
logs = logs.order(created_at: :desc) logs = logs.order(created_at: :desc)
user.support? ? logs.all.includes(:owning_organisation, :managing_organisation) : logs if user.support?
if logs.first&.lettings?
logs.all.includes(:owning_organisation, :managing_organisation)
else
logs.all.includes(:owning_organisation)
end
else
logs
end
end end
end end

17
app/views/form/guidance/_what_counts_as_income_sales.html.erb

@ -1,17 +0,0 @@
<%= govuk_details(summary_text: "What counts as income?") do %>
<p class="govuk-body">You should include any income from:</p>
<ul class="govuk-list govuk-list--bullet">
<li>employment</li>
<li>pensions</li>
<li>investments</li>
<li>Universal Credit</li>
</ul>
<p class="govuk-body">Don’t include:</p>
<ul class="govuk-list govuk-list--bullet">
<li>National Insurance (NI) contributions and tax</li>
<li>housing benefit</li>
<li>child benefit</li>
<li>council tax support</li>
</ul>
<% end %>

2
app/views/form/page.html.erb

@ -44,7 +44,7 @@
<%= f.hidden_field :page, value: @page.id %> <%= f.hidden_field :page, value: @page.id %>
<div class="govuk-button-group"> <div class="govuk-button-group">
<% if !@page.id.include?("value_check") && if request.query_parameters["referrer"] != "check_answers" %> <% if !@page.interruption_screen? && if request.query_parameters["referrer"] != "check_answers" %>
<%= f.govuk_submit "Save and continue" %> <%= f.govuk_submit "Save and continue" %>
<%= govuk_link_to "Skip for now", send(@log.form.next_page_redirect_path(@page, @log, current_user), @log) %> <%= govuk_link_to "Skip for now", send(@log.form.next_page_redirect_path(@page, @log, current_user), @log) %>
<% else %> <% else %>

2
app/views/logs/_log_list.html.erb

@ -1,6 +1,8 @@
<h2 class="govuk-body"> <h2 class="govuk-body">
<%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "logs", path: request.path)) %> <%= render(SearchResultCaptionComponent.new(searched:, count: pagy.count, item_label:, total_count:, item: "logs", path: request.path)) %>
<% if logs&.first&.lettings? %>
<%= govuk_link_to "Download (CSV)", csv_download_url, type: "text/csv" %> <%= govuk_link_to "Download (CSV)", csv_download_url, type: "text/csv" %>
<% end %>
</h2> </h2>
<% logs.map do |log| %> <% logs.map do |log| %>
<%= render(LogSummaryComponent.new(current_user:, log:)) %> <%= render(LogSummaryComponent.new(current_user:, log:)) %>

2
config/environments/development.rb

@ -73,7 +73,7 @@ Rails.application.configure do
config.active_record.verbose_query_logs = true config.active_record.verbose_query_logs = true
# Raises error for missing translations. # Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names. # Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true # config.action_view.annotate_rendered_view_with_filenames = true

2
config/environments/test.rb

@ -57,7 +57,7 @@ Rails.application.configure do
config.active_support.disallowed_deprecation_warnings = [] config.active_support.disallowed_deprecation_warnings = []
# Raises error for missing translations. # Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true config.i18n.raise_on_missing_translations = true
# Annotate rendered view with file names. # Annotate rendered view with file names.
# config.action_view.annotate_rendered_view_with_filenames = true # config.action_view.annotate_rendered_view_with_filenames = true

11
config/locales/en.yml

@ -413,6 +413,14 @@ en:
deactivation: deactivation:
during_deactivated_period: "The location is already deactivated during this date, please enter a different date" during_deactivated_period: "The location is already deactivated during this date, please enter a different date"
sale_information: sale_information:
proplen:
social_homebuy: "Social HomeBuy buyers should not have lived here before"
rent_to_buy: "Rent to Buy buyers should not have lived here before"
exdate:
must_be_before_saledate:
Contract exchange date must be less than 1 year before completion date
must_be_less_than_1_year_from_saledate:
Contract exchange date must be less than 1 year before completion date
previous_property_beds: previous_property_beds:
property_type_bedsit: "Bedsit bedroom maximum 1" property_type_bedsit: "Bedsit bedroom maximum 1"
previous_property_type: previous_property_type:
@ -420,6 +428,7 @@ en:
handover_exchange: handover_exchange:
handover_before_exchange: "Practical completion or handover date must be before exchange date" handover_before_exchange: "Practical completion or handover date must be before exchange date"
exchange_after_handover: "Exchange date must be after practical completion or handover date" exchange_after_handover: "Exchange date must be after practical completion or handover date"
discounted_ownership_value: "Mortgage, deposit, and grant total must equal £%{value_with_discount}"
soft_validations: soft_validations:
net_income: net_income:
@ -446,6 +455,8 @@ en:
max: max:
title: "You told us this person is %{age} or over and not retired" title: "You told us this person is %{age} or over and not retired"
hint_text: "The minimum expected retirement age for %{gender} in England is %{age}." hint_text: "The minimum expected retirement age for %{gender} in England is %{age}."
extra_borrowing:
title: "The mortgage and deposit are higher than the purchase minus the discount"
pregnancy: pregnancy:
title: "You told us somebody in the household is pregnant" title: "You told us somebody in the household is pregnant"
no_females: "You also told us there are no female tenants living at the property." no_females: "You also told us there are no female tenants living at the property."

15450
config/rent_range_data/2022.csv

File diff suppressed because it is too large Load Diff

13
db/migrate/20230110094518_remove_managing_organisation_id_from_sales_logs.rb

@ -0,0 +1,13 @@
class RemoveManagingOrganisationIdFromSalesLogs < ActiveRecord::Migration[7.0]
def up
change_table :sales_logs, bulk: true do |t|
t.remove :managing_organisation_id
end
end
def down
change_table :sales_logs, bulk: true do |t|
t.column :managing_organisation_id, :bigint
end
end
end

7
db/migrate/20230118170602_add_extra_borrowing_value_check_to_sales.rb

@ -0,0 +1,7 @@
class AddExtraBorrowingValueCheckToSales < ActiveRecord::Migration[7.0]
def change
change_table :sales_logs, bulk: true do |t|
t.column :extrabor_value_check, :integer
end
end
end

5
db/migrate/20230123160741_add_grant_value_check_to_sales_log.rb

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

21
db/schema.rb

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.0].define(version: 2023_01_24_111328) do ActiveRecord::Schema[7.0].define(version: 2023_01_23_160741) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -69,17 +69,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_24_111328) do
t.index ["start_year", "lettype", "beds", "la"], name: "index_la_rent_ranges_on_start_year_and_lettype_and_beds_and_la", unique: true t.index ["start_year", "lettype", "beds", "la"], name: "index_la_rent_ranges_on_start_year_and_lettype_and_beds_and_la", unique: true
end end
create_table "la_sale_ranges", force: :cascade do |t|
t.string "la"
t.integer "bedrooms"
t.decimal "soft_min", precision: 10, scale: 2
t.decimal "soft_max", precision: 10, scale: 2
t.integer "start_year"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["start_year", "bedrooms", "la"], name: "index_la_sale_ranges_on_start_year_bedrooms_la", unique: true
end
create_table "legacy_users", force: :cascade do |t| create_table "legacy_users", force: :cascade do |t|
t.string "old_user_id" t.string "old_user_id"
t.integer "user_id" t.integer "user_id"
@ -378,7 +367,6 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_24_111328) do
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.bigint "owning_organisation_id" t.bigint "owning_organisation_id"
t.bigint "managing_organisation_id"
t.bigint "created_by_id" t.bigint "created_by_id"
t.string "purchid" t.string "purchid"
t.integer "type" t.integer "type"
@ -498,9 +486,9 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_24_111328) do
t.integer "hoyear" t.integer "hoyear"
t.integer "fromprop" t.integer "fromprop"
t.integer "socprevten" t.integer "socprevten"
t.integer "mortlen"
t.integer "mortgagelender" t.integer "mortgagelender"
t.string "mortgagelenderother" t.string "mortgagelenderother"
t.integer "mortlen"
t.integer "extrabor" t.integer "extrabor"
t.integer "hhmemb" t.integer "hhmemb"
t.integer "totadult" t.integer "totadult"
@ -513,11 +501,12 @@ ActiveRecord::Schema[7.0].define(version: 2023_01_24_111328) do
t.boolean "is_la_inferred" t.boolean "is_la_inferred"
t.bigint "bulk_upload_id" t.bigint "bulk_upload_id"
t.integer "retirement_value_check" t.integer "retirement_value_check"
t.integer "deposit_and_mortgage_value_check"
t.integer "grant_value_check"
t.integer "hodate_check" t.integer "hodate_check"
t.integer "value_value_check" t.integer "extrabor_value_check"
t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id" t.index ["bulk_upload_id"], name: "index_sales_logs_on_bulk_upload_id"
t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id" t.index ["created_by_id"], name: "index_sales_logs_on_created_by_id"
t.index ["managing_organisation_id"], name: "index_sales_logs_on_managing_organisation_id"
t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id" t.index ["owning_organisation_id"], name: "index_sales_logs_on_owning_organisation_id"
t.index ["updated_by_id"], name: "index_sales_logs_on_updated_by_id" t.index ["updated_by_id"], name: "index_sales_logs_on_updated_by_id"
end end

2
db/seeds.rb

@ -160,7 +160,7 @@ unless Rails.env.test?
saledate: Date.new(1, 1, 1), saledate: Date.new(1, 1, 1),
purchid: "1", purchid: "1",
ownershipsch: 2, ownershipsch: 2,
type: 8, type: 9,
jointpur: 1, jointpur: 1,
jointmore: 1, jointmore: 1,
) )

39
spec/components/log_summary_component_spec.rb

@ -5,15 +5,16 @@ RSpec.describe LogSummaryComponent, type: :component do
let(:coordinator_user) { FactoryBot.create(:user) } let(:coordinator_user) { FactoryBot.create(:user) }
let(:propcode) { "P3647" } let(:propcode) { "P3647" }
let(:tenancycode) { "T62863" } let(:tenancycode) { "T62863" }
let(:log) { FactoryBot.create(:lettings_log, needstype: 1, startdate: Time.utc(2022, 1, 1), tenancycode:, propcode:) } let(:lettings_log) { FactoryBot.create(:lettings_log, needstype: 1, startdate: Time.utc(2022, 1, 1), tenancycode:, propcode:) }
let(:sales_log) { FactoryBot.create(:sales_log) }
context "when rendering log for a support user" do context "when rendering lettings log for a support user" do
it "show the log summary with organisational relationships" do it "show the log summary with organisational relationships" do
result = render_inline(described_class.new(current_user: support_user, log:)) result = render_inline(described_class.new(current_user: support_user, log: lettings_log))
expect(result).to have_link(log.id.to_s) expect(result).to have_link(lettings_log.id.to_s)
expect(result).to have_text(log.tenancycode) expect(result).to have_text(lettings_log.tenancycode)
expect(result).to have_text(log.propcode) expect(result).to have_text(lettings_log.propcode)
expect(result).to have_text("General needs") expect(result).to have_text("General needs")
expect(result).to have_text("Tenancy starts 1 January 2022") expect(result).to have_text("Tenancy starts 1 January 2022")
expect(result).to have_text("Created 8 February 2022") expect(result).to have_text("Created 8 February 2022")
@ -23,12 +24,30 @@ RSpec.describe LogSummaryComponent, type: :component do
end end
end end
context "when rendering log for a data coordinator user" do context "when rendering lettings log for a data coordinator user" do
it "show the log summary" do it "show the log summary" do
result = render_inline(described_class.new(current_user: coordinator_user, log:)) result = render_inline(described_class.new(current_user: coordinator_user, log: lettings_log))
expect(result).not_to have_content("Owned by\n DLUHC") expect(result).not_to have_content("Owned by")
expect(result).not_to have_content("Managed by\n DLUHC") expect(result).not_to have_content("Managed by")
end
end
context "when rendering sales log for a support user" do
it "show the log summary with organisational relationships" do
result = render_inline(described_class.new(current_user: support_user, log: sales_log))
expect(result).to have_content("Owned by\n DLUHC")
expect(result).not_to have_content("Managed by")
end
end
context "when rendering sales log for a data coordinator user" do
it "show the log summary" do
result = render_inline(described_class.new(current_user: coordinator_user, log: sales_log))
expect(result).not_to have_content("Owned by")
expect(result).not_to have_content("Managed by")
end end
end end
end end

5
spec/factories/sales_log.rb

@ -2,7 +2,6 @@ FactoryBot.define do
factory :sales_log do factory :sales_log do
created_by { FactoryBot.create(:user) } created_by { FactoryBot.create(:user) }
owning_organisation { created_by.organisation } owning_organisation { created_by.organisation }
managing_organisation { created_by.organisation }
created_at { Time.utc(2022, 2, 8, 16, 52, 15) } created_at { Time.utc(2022, 2, 8, 16, 52, 15) }
updated_at { Time.utc(2022, 2, 8, 16, 52, 15) } updated_at { Time.utc(2022, 2, 8, 16, 52, 15) }
trait :in_progress do trait :in_progress do
@ -71,10 +70,10 @@ FactoryBot.define do
ecstat5 { 2 } ecstat5 { 2 }
ecstat6 { 1 } ecstat6 { 1 }
disabled { 1 } disabled { 1 }
deposit { 10_000 } deposit { 80_000 }
cashdis { 1_000 } cashdis { 1_000 }
value { 110_000 } value { 110_000 }
grant { 1_000 } grant { 10_000 }
proplen { 10 } proplen { 10 }
pregyrha { 1 } pregyrha { 1 }
pregla { 1 } pregla { 1 }

2
spec/features/form/check_answers_page_lettings_logs_spec.rb

@ -143,7 +143,7 @@ RSpec.describe "Lettings Log Check Answers Page" do
end end
context "when the user is checking their answers for the household characteristics subsection" do context "when the user is checking their answers for the household characteristics subsection" do
it "they see a seperate summary card for each member of the household" do it "they see a separate summary card for each member of the household" do
visit("/lettings-logs/#{completed_lettings_log.id}/#{subsection}/check-answers") visit("/lettings-logs/#{completed_lettings_log.id}/#{subsection}/check-answers")
assert_selector ".x-govuk-summary-card__title", text: "Lead tenant", count: 1 assert_selector ".x-govuk-summary-card__title", text: "Lead tenant", count: 1
assert_selector ".x-govuk-summary-card__title", text: "Person 2", count: 1 assert_selector ".x-govuk-summary-card__title", text: "Person 2", count: 1

4
spec/features/form/check_answers_page_sales_logs_spec.rb

@ -39,7 +39,7 @@ RSpec.describe "Sales Log Check Answers Page" do
context "when the user is checking their answers for the household characteristics subsection" do context "when the user is checking their answers for the household characteristics subsection" do
context "and the log is for a joint purchase" do context "and the log is for a joint purchase" do
it "they see a seperate summary card for each member of the household" do it "they see a separate summary card for each member of the household" do
visit("/sales-logs/#{completed_sales_log_joint_purchase.id}/#{subsection}/check-answers") visit("/sales-logs/#{completed_sales_log_joint_purchase.id}/#{subsection}/check-answers")
assert_selector ".x-govuk-summary-card__title", text: "Buyer 1", count: 1 assert_selector ".x-govuk-summary-card__title", text: "Buyer 1", count: 1
assert_selector ".x-govuk-summary-card__title", text: "Buyer 2", count: 1 assert_selector ".x-govuk-summary-card__title", text: "Buyer 2", count: 1
@ -49,7 +49,7 @@ RSpec.describe "Sales Log Check Answers Page" do
end end
context "and the log is for a non-joint purchase" do context "and the log is for a non-joint purchase" do
it "they see a seperate summary card for each member of the household" do it "they see a separate summary card for each member of the household" do
visit("/sales-logs/#{completed_sales_log_non_joint_purchase.id}/#{subsection}/check-answers") visit("/sales-logs/#{completed_sales_log_non_joint_purchase.id}/#{subsection}/check-answers")
assert_selector ".x-govuk-summary-card__title", text: "Buyer 1", count: 1 assert_selector ".x-govuk-summary-card__title", text: "Buyer 1", count: 1
assert_selector ".x-govuk-summary-card__title", text: "Buyer 2", count: 0 assert_selector ".x-govuk-summary-card__title", text: "Buyer 2", count: 0

2
spec/features/organisation_spec.rb

@ -215,7 +215,7 @@ RSpec.describe "User Features" do
let(:number_of_sales_logs) { SalesLog.count } let(:number_of_sales_logs) { SalesLog.count }
before do before do
FactoryBot.create_list(:sales_log, 4, owning_organisation_id: organisation.id, managing_organisation_id: organisation.id) FactoryBot.create_list(:sales_log, 4, owning_organisation_id: organisation.id)
visit("/organisations/#{org_id}/sales-logs") visit("/organisations/#{org_id}/sales-logs")
end end

22
spec/helpers/tab_nav_helper_spec.rb

@ -34,26 +34,4 @@ RSpec.describe TabNavHelper do
expect(scheme_cell(scheme)).to match(expected_html) expect(scheme_cell(scheme)).to match(expected_html)
end end
end end
describe "#tab_items" do
context "when user is a data_coordinator" do
let(:user) { FactoryBot.build(:user, :data_coordinator, organisation:) }
it "returns details and user tabs" do
result = tab_items(user).map { |i| i[:name] }
expect(result.count).to eq(2)
expect(result.first).to match("Details")
expect(result.second).to match("Users")
end
end
context "when user is a data_provider" do
it "returns details and user tabs" do
result = tab_items(user).map { |i| i[:name] }
expect(result.count).to eq(2)
expect(result.first).to match("Details")
expect(result.second).to match("Users")
end
end
end
end end

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

@ -44,15 +44,6 @@ RSpec.describe Form::Sales::Questions::Buyer1IncomeKnown, type: :model do
}) })
end end
it "has the correct guidance_partial" do
expect(question.guidance_partial).to eq("what_counts_as_income_sales")
end
it "has the correct guidance position", :aggregate_failures do
expect(question.bottom_guidance?).to eq(true)
expect(question.top_guidance?).to eq(false)
end
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

2
spec/models/form/sales/questions/buyer1_income_spec.rb

@ -32,7 +32,7 @@ RSpec.describe Form::Sales::Questions::Buyer1Income, type: :model do
end end
it "has the correct hint" do it "has the correct hint" do
expect(question.hint_text).to be_nil expect(question.hint_text).to eq("Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments.")
end end
it "has correct width" do it "has correct width" do

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

@ -44,15 +44,6 @@ RSpec.describe Form::Sales::Questions::Buyer2IncomeKnown, type: :model do
}) })
end end
it "has the correct guidance_partial" do
expect(question.guidance_partial).to eq("what_counts_as_income_sales")
end
it "has the correct guidance position", :aggregate_failures do
expect(question.bottom_guidance?).to eq(true)
expect(question.top_guidance?).to eq(false)
end
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(2) expect(question.check_answers_card_number).to eq(2)
end end

2
spec/models/form/sales/questions/buyer2_income_spec.rb

@ -32,7 +32,7 @@ RSpec.describe Form::Sales::Questions::Buyer2Income, type: :model do
end end
it "has the correct hint" do it "has the correct hint" do
expect(question.hint_text).to be_nil expect(question.hint_text).to eq("Provide the gross annual income (i.e. salary before tax) plus the annual amount of benefits, Universal Credit or pensions, and income from investments.")
end end
it "has correct width" do it "has correct width" do

4
spec/models/form/sales/questions/mortgage_length_spec.rb

@ -32,7 +32,9 @@ RSpec.describe Form::Sales::Questions::MortgageLength, type: :model do
end end
it "has the correct hint" do it "has the correct hint" do
expect(question.hint_text).to be_nil expect(question.hint_text).to eq(
"You should round up to the nearest year. Value should not exceed 60 years.",
)
end end
it "has correct width" do it "has correct width" do

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

@ -16,7 +16,7 @@ RSpec.describe Form::Sales::Questions::NumberOfOthersInProperty, type: :model do
end end
it "has the correct header" do it "has the correct header" do
expect(question.header).to eq("Besides the buyers, how many other people live in the property?") expect(question.header).to eq("Besides the buyer(s), how many other people live or will live in the property?")
end end
it "has the correct check_answer_label" do it "has the correct check_answer_label" do

5
spec/models/form/sales/subsections/discounted_ownership_scheme_spec.rb

@ -16,15 +16,20 @@ RSpec.describe Form::Sales::Subsections::DiscountedOwnershipScheme, type: :model
%w[ %w[
living_before_purchase_discounted_ownership living_before_purchase_discounted_ownership
about_price_rtb about_price_rtb
extra_borrowing_price_value_check
about_price_not_rtb about_price_not_rtb
grant_value_check
purchase_price_discounted_ownership purchase_price_discounted_ownership
mortgage_used_discounted_ownership mortgage_used_discounted_ownership
mortgage_amount_discounted_ownership mortgage_amount_discounted_ownership
extra_borrowing_mortgage_value_check
mortgage_lender_discounted_ownership mortgage_lender_discounted_ownership
mortgage_lender_other_discounted_ownership mortgage_lender_other_discounted_ownership
mortgage_length_discounted_ownership mortgage_length_discounted_ownership
extra_borrowing_discounted_ownership extra_borrowing_discounted_ownership
extra_borrowing_value_check
about_deposit_discounted_ownership about_deposit_discounted_ownership
extra_borrowing_deposit_value_check
discounted_ownership_deposit_value_check discounted_ownership_deposit_value_check
leasehold_charges_discounted_ownership leasehold_charges_discounted_ownership
], ],

4
spec/models/form_handler_spec.rb

@ -52,14 +52,14 @@ RSpec.describe FormHandler do
it "is able to load a current sales form" do it "is able to load a current sales form" do
form = form_handler.get_form("current_sales") form = form_handler.get_form("current_sales")
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(184) expect(form.pages.count).to eq(189)
expect(form.name).to eq("2022_2023_sales") expect(form.name).to eq("2022_2023_sales")
end end
it "is able to load a previous sales form" do it "is able to load a previous sales form" do
form = form_handler.get_form("previous_sales") form = form_handler.get_form("previous_sales")
expect(form).to be_a(Form) expect(form).to be_a(Form)
expect(form.pages.count).to eq(184) expect(form.pages.count).to eq(189)
expect(form.name).to eq("2021_2022_sales") expect(form.name).to eq("2021_2022_sales")
end end
end end

6
spec/models/lettings_log_spec.rb

@ -2392,12 +2392,6 @@ RSpec.describe LettingsLog do
FactoryBot.create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2, created_by: nil) FactoryBot.create(:lettings_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2, created_by: nil)
end end
it "filters by given organisation id" do
expect(described_class.filter_by_organisation([organisation_1.id]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_1.id, organisation_2.id]).count).to eq(4)
expect(described_class.filter_by_organisation([organisation_3.id]).count).to eq(0)
end
it "filters by given organisation" do it "filters by given organisation" do
expect(described_class.filter_by_organisation([organisation_1]).count).to eq(3) expect(described_class.filter_by_organisation([organisation_1]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_1, organisation_2]).count).to eq(4) expect(described_class.filter_by_organisation([organisation_1, organisation_2]).count).to eq(4)

2
spec/models/organisation_spec.rb

@ -196,7 +196,7 @@ RSpec.describe Organisation, type: :model do
let!(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now, organisation:) } let!(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now, organisation:) }
let!(:scheme_to_delete) { FactoryBot.create(:scheme, owning_organisation: user.organisation) } let!(:scheme_to_delete) { FactoryBot.create(:scheme, owning_organisation: user.organisation) }
let!(:log_to_delete) { FactoryBot.create(:lettings_log, owning_organisation: user.organisation) } let!(:log_to_delete) { FactoryBot.create(:lettings_log, owning_organisation: user.organisation) }
let!(:sales_log_to_delete) { FactoryBot.create(:sales_log, owning_organisation: user.organisation, managing_organisation: user.organisation) } let!(:sales_log_to_delete) { FactoryBot.create(:sales_log, owning_organisation: user.organisation) }
context "when organisation is deleted" do context "when organisation is deleted" do
it "child relationships ie logs, schemes and users are deleted too - application" do it "child relationships ie logs, schemes and users are deleted too - application" do

19
spec/models/sales_log_spec.rb

@ -93,21 +93,14 @@ RSpec.describe SalesLog, type: :model do
let(:organisation_3) { create(:organisation) } let(:organisation_3) { create(:organisation) }
before do before do
create(:sales_log, :in_progress, owning_organisation: organisation_1, managing_organisation: organisation_1) create(:sales_log, :in_progress, owning_organisation: organisation_1)
create(:sales_log, :completed, owning_organisation: organisation_1, managing_organisation: organisation_2) create(:sales_log, :completed, owning_organisation: organisation_1)
create(:sales_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_1) create(:sales_log, :completed, owning_organisation: organisation_2)
create(:sales_log, :completed, owning_organisation: organisation_2, managing_organisation: organisation_2)
end
it "filters by given organisation id" do
expect(described_class.filter_by_organisation([organisation_1.id]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_1.id, organisation_2.id]).count).to eq(4)
expect(described_class.filter_by_organisation([organisation_3.id]).count).to eq(0)
end end
it "filters by given organisation" do it "filters by given organisation" do
expect(described_class.filter_by_organisation([organisation_1]).count).to eq(3) expect(described_class.filter_by_organisation([organisation_1]).count).to eq(2)
expect(described_class.filter_by_organisation([organisation_1, organisation_2]).count).to eq(4) expect(described_class.filter_by_organisation([organisation_1, organisation_2]).count).to eq(3)
expect(described_class.filter_by_organisation([organisation_3]).count).to eq(0) expect(described_class.filter_by_organisation([organisation_3]).count).to eq(0)
end end
end end
@ -165,7 +158,6 @@ RSpec.describe SalesLog, type: :model do
FactoryBot.create( FactoryBot.create(
:sales_log, :sales_log,
:completed, :completed,
managing_organisation: owning_organisation,
owning_organisation:, owning_organisation:,
created_by: created_by_user, created_by: created_by_user,
pcodenk: 0, pcodenk: 0,
@ -297,7 +289,6 @@ RSpec.describe SalesLog, type: :model do
let!(:address_sales_log) do let!(:address_sales_log) do
described_class.create({ described_class.create({
managing_organisation: owning_organisation,
owning_organisation:, owning_organisation:,
created_by: created_by_user, created_by: created_by_user,
ppcodenk: 1, ppcodenk: 1,

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

@ -5,106 +5,140 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
let(:validator_class) { Class.new { include Validations::Sales::SaleInformationValidations } } let(:validator_class) { Class.new { include Validations::Sales::SaleInformationValidations } }
describe "#validate_deposit_range" do describe "#validate_practical_completion_date_before_exdate" do
context "when within permitted bounds" do context "when hodate blank" do
let(:record) { build(:sales_log, deposit: 0) } let(:record) { build(:sales_log, hodate: nil) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_deposit_range(record) sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors[:deposit]).not_to be_present expect(record.errors).not_to be_present
end end
end end
context "when blank" do context "when exdate blank" do
let(:record) { build(:sales_log, deposit: nil) } let(:record) { build(:sales_log, exdate: nil) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_deposit_range(record) sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors[:deposit]).not_to be_present expect(record.errors).not_to be_present
end end
end end
context "when below lower bound" do context "when exdate and hodate blank" do
let(:record) { build(:sales_log, deposit: -1) } let(:record) { build(:sales_log, hodate: nil, exdate: nil) }
it "adds an error" do it "does not add an error" do
sale_information_validator.validate_deposit_range(record) sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors[:deposit]).to be_present expect(record.errors).not_to be_present
end end
end end
context "when higher than upper bound" do context "when hodate before exdate" do
let(:record) { build(:sales_log, deposit: 1_000_000) } let(:record) { build(:sales_log, hodate: 2.months.ago, exdate: 1.month.ago) }
it "adds an error" do it "does not add the error" do
sale_information_validator.validate_deposit_range(record) sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors[:deposit]).to be_present expect(record.errors).not_to be_present
end end
end end
context "when hodate after exdate" do
let(:record) { build(:sales_log, hodate: 1.month.ago, exdate: 2.months.ago) }
it "adds error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors[:hodate]).to be_present
end
end end
describe "#validate_practical_completion_date_before_exdate" do context "when hodate == exdate" do
context "when hodate blank" do let(:record) { build(:sales_log, hodate: Time.zone.parse("2023-07-01"), exdate: Time.zone.parse("2023-07-01")) }
let(:record) { build(:sales_log, hodate: nil) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_practical_completion_date_before_exdate(record)
expect(record.errors).not_to be_present expect(record.errors[:hodate]).to be_present
end
end end
end end
describe "#validate_exchange_date" do
context "when exdate blank" do context "when exdate blank" do
let(:record) { build(:sales_log, exdate: nil) } let(:record) { build(:sales_log, exdate: nil) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_exchange_date(record)
expect(record.errors).not_to be_present expect(record.errors[:exdate]).not_to be_present
end end
end end
context "when exdate and hodate blank" do context "when saledate blank" do
let(:record) { build(:sales_log, hodate: nil, exdate: nil) } let(:record) { build(:sales_log, saledate: nil) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_exchange_date(record)
expect(record.errors).not_to be_present expect(record.errors[:exdate]).not_to be_present
end end
end end
context "when hodate before exdate" do context "when saledate and exdate blank" do
let(:record) { build(:sales_log, hodate: 2.months.ago, exdate: 1.month.ago) } let(:record) { build(:sales_log, exdate: nil, saledate: nil) }
it "does not add an error" do
sale_information_validator.validate_exchange_date(record)
expect(record.errors[:exdate]).not_to be_present
end
end
context "when exdate before saledate" do
let(:record) { build(:sales_log, exdate: 2.months.ago, saledate: 1.month.ago) }
it "does not add the error" do it "does not add the error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_exchange_date(record)
expect(record.errors).not_to be_present expect(record.errors[:exdate]).not_to be_present
end end
end end
context "when hodate after exdate" do context "when exdate more than 1 year before saledate" do
let(:record) { build(:sales_log, hodate: 1.month.ago, exdate: 2.months.ago) } let(:record) { build(:sales_log, exdate: 2.years.ago, saledate: 1.month.ago) }
it "does not add the error" do
sale_information_validator.validate_exchange_date(record)
expect(record.errors[:exdate]).to eq(
["Contract exchange date must be less than 1 year before completion date"],
)
end
end
context "when exdate after saledate" do
let(:record) { build(:sales_log, exdate: 1.month.ago, saledate: 2.months.ago) }
it "adds error" do it "adds error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_exchange_date(record)
expect(record.errors[:hodate]).to be_present expect(record.errors[:exdate]).to eq(
["Contract exchange date must be less than 1 year before completion date"],
)
end end
end end
context "when hodate == exdate" do context "when exdate == saledate" do
let(:record) { build(:sales_log, hodate: Time.zone.parse("2023-07-01"), exdate: Time.zone.parse("2023-07-01")) } let(:record) { build(:sales_log, exdate: Time.zone.parse("2023-07-01"), saledate: Time.zone.parse("2023-07-01")) }
it "does not add an error" do it "does not add an error" do
sale_information_validator.validate_practical_completion_date_before_exdate(record) sale_information_validator.validate_exchange_date(record)
expect(record.errors[:hodate]).to be_present expect(record.errors[:exdate]).not_to be_present
end end
end end
end end
@ -130,4 +164,211 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end end
end end
end end
describe "#validate_years_living_in_property_before_purchase" do
context "when proplen blank" do
let(:record) { build(:sales_log, proplen: nil) }
it "does not add an error" do
sale_information_validator.validate_years_living_in_property_before_purchase(record)
expect(record.errors).not_to be_present
end
end
context "when type blank" do
let(:record) { build(:sales_log, type: nil) }
it "does not add an error" do
sale_information_validator.validate_years_living_in_property_before_purchase(record)
expect(record.errors).not_to be_present
end
end
context "when proplen 0" do
let(:record) { build(:sales_log, proplen: 0) }
it "does not add an error" do
sale_information_validator.validate_years_living_in_property_before_purchase(record)
expect(record.errors).not_to be_present
end
end
context "when type Rent to Buy and proplen > 0" do
let(:record) { build(:sales_log, proplen: 1, type: 28) }
it "adds an error" do
sale_information_validator.validate_years_living_in_property_before_purchase(record)
expect(record.errors[:type]).to include(I18n.t("validations.sale_information.proplen.rent_to_buy"))
expect(record.errors[:proplen]).to include(I18n.t("validations.sale_information.proplen.rent_to_buy"))
end
end
context "when type Social HomeBuy and proplen > 0" do
let(:record) { build(:sales_log, proplen: 1, type: 18) }
it "adds an error" do
sale_information_validator.validate_years_living_in_property_before_purchase(record)
expect(record.errors[:type]).to include(I18n.t("validations.sale_information.proplen.social_homebuy"))
expect(record.errors[:proplen]).to include(I18n.t("validations.sale_information.proplen.social_homebuy"))
end
end
end
describe "#validate_discounted_ownership_value" do
context "when grant is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, value: 30_000, ownershipsch: 2, type: 8) }
context "and not provided" do
before do
record.grant = nil
end
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
context "and is provided" do
it "adds an error if mortgage, deposit and grant total does not equal market value" do
record.grant = 3_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
end
it "does not add an error if mortgage, deposit and grant total equals market value" do
record.grant = 15_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
end
context "when discount is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, value: 30_000, ownershipsch: 2, type: 9) }
context "and not provided" do
before do
record.discount = nil
end
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
context "and is provided" do
it "adds an error if mortgage and deposit total does not equal market value - discount" do
record.discount = 10
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00"))
expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00"))
expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00"))
expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00"))
expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "27000.00"))
end
it "does not add an error if mortgage and deposit total equals market value - discount" do
record.discount = 50
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
end
context "when neither discount nor grant is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, value: 30_000, ownershipsch: 2, type: 29) }
it "adds an error if mortgage and deposit total does not equal market value" do
record.deposit = 2_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "30000.00"))
end
it "does not add an error if mortgage and deposit total equals market value" do
record.deposit = 20_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
context "when mortgage is routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgageused: 1, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 2) }
context "and not provided" do
before do
record.mortgage = nil
end
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
context "and is provided" do
it "adds an error if mortgage, grant and deposit total does not equal market value - discount" do
record.mortgage = 10
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
end
it "does not add an error if mortgage, grant and deposit total equals market value - discount" do
record.mortgage = 10_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
end
context "when mortgage is not routed to" do
let(:record) { FactoryBot.build(:sales_log, mortgageused: 2, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 2) }
it "adds an error if grant and deposit total does not equal market value - discount" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors[:mortgage]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:deposit]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:grant]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:value]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
expect(record.errors[:discount]).to include(I18n.t("validations.sale_information.discounted_ownership_value", value_with_discount: "18000.00"))
end
it "does not add an error if mortgage, grant and deposit total equals market value - discount" do
record.grant = 13_000
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
context "when owhership is not discounted" do
let(:record) { FactoryBot.build(:sales_log, mortgage: 10_000, deposit: 5_000, grant: 3_000, value: 20_000, discount: 10, ownershipsch: 1) }
it "does not add an error" do
sale_information_validator.validate_discounted_ownership_value(record)
expect(record.errors).to be_empty
end
end
end
end end

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

@ -128,7 +128,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_mortgage_over_soft_max .not_to be_mortgage_over_soft_max
end end
it "returns true if only income1 is used for morgage and it is less than 1/5 of the morgage" do it "returns true if only income1 is used for mortgage and it is less than 1/5 of the mortgage" do
record.inc1mort = 1 record.inc1mort = 1
record.income1 = 10_000 record.income1 = 10_000
record.mortgage = 51_000 record.mortgage = 51_000
@ -137,7 +137,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.to be_mortgage_over_soft_max .to be_mortgage_over_soft_max
end end
it "returns false if only income1 is used for morgage and it is more than 1/5 of the morgage" do it "returns false if only income1 is used for mortgage and it is more than 1/5 of the mortgage" do
record.inc1mort = 1 record.inc1mort = 1
record.income1 = 10_000 record.income1 = 10_000
record.mortgage = 44_000 record.mortgage = 44_000
@ -146,7 +146,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_mortgage_over_soft_max .not_to be_mortgage_over_soft_max
end end
it "returns true if only income2 is used for morgage and it is less than 1/5 of the morgage" do it "returns true if only income2 is used for mortgage and it is less than 1/5 of the mortgage" do
record.inc1mort = 2 record.inc1mort = 2
record.inc2mort = 1 record.inc2mort = 1
record.income2 = 10_000 record.income2 = 10_000
@ -155,7 +155,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.to be_mortgage_over_soft_max .to be_mortgage_over_soft_max
end end
it "returns false if only income2 is used for morgage and it is more than 1/5 of the morgage" do it "returns false if only income2 is used for mortgage and it is more than 1/5 of the mortgage" do
record.inc1mort = 2 record.inc1mort = 2
record.inc2mort = 1 record.inc2mort = 1
record.income2 = 10_000 record.income2 = 10_000
@ -164,7 +164,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_mortgage_over_soft_max .not_to be_mortgage_over_soft_max
end end
it "returns true if income1 and income2 are used for morgage and their sum is less than 1/5 of the morgage" do it "returns true if income1 and income2 are used for mortgage and their sum is less than 1/5 of the mortgage" do
record.inc1mort = 1 record.inc1mort = 1
record.inc2mort = 1 record.inc2mort = 1
record.income1 = 10_000 record.income1 = 10_000
@ -174,7 +174,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.to be_mortgage_over_soft_max .to be_mortgage_over_soft_max
end end
it "returns false if income1 and income2 are used for morgage and their sum is more than 1/5 of the morgage" do it "returns false if income1 and income2 are used for mortgage and their sum is more than 1/5 of the mortgage" do
record.inc1mort = 1 record.inc1mort = 1
record.inc2mort = 1 record.inc2mort = 1
record.income1 = 8_000 record.income1 = 8_000
@ -184,7 +184,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_mortgage_over_soft_max .not_to be_mortgage_over_soft_max
end end
it "returns true if neither of the incomes are used for morgage and the morgage is more than 0" do it "returns true if neither of the incomes are used for mortgage and the mortgage is more than 0" do
record.inc1mort = 2 record.inc1mort = 2
record.inc2mort = 2 record.inc2mort = 2
record.mortgage = 124_000 record.mortgage = 124_000
@ -192,7 +192,7 @@ RSpec.describe Validations::Sales::SoftValidations do
.to be_mortgage_over_soft_max .to be_mortgage_over_soft_max
end end
it "returns true if neither of the incomes are used for morgage and the morgage is 0" do it "returns false if neither of the incomes are used for mortgage and the mortgage is 0" do
record.inc1mort = 2 record.inc1mort = 2
record.inc2mort = 2 record.inc2mort = 2
record.mortgage = 0 record.mortgage = 0
@ -200,6 +200,73 @@ RSpec.describe Validations::Sales::SoftValidations do
.not_to be_mortgage_over_soft_max .not_to be_mortgage_over_soft_max
end end
end end
context "when validating extra borrowing" do
it "returns false if extrabor not present" do
record.mortgage = 50_000
record.deposit = 40_000
record.value = 100_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns false if mortgage not present" do
record.extrabor = 2
record.deposit = 40_000
record.value = 100_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns false if deposit not present" do
record.extrabor = 2
record.mortgage = 50_000
record.value = 100_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns false if value not present" do
record.extrabor = 2
record.mortgage = 50_000
record.deposit = 40_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns false if discount not present" do
record.extrabor = 2
record.mortgage = 50_000
record.deposit = 40_000
record.value = 100_000
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns false if extra borrowing expected and reported" do
record.extrabor = 1
record.mortgage = 50_000
record.deposit = 40_000
record.value = 100_000
record.discount = 11
expect(record)
.not_to be_extra_borrowing_expected_but_not_reported
end
it "returns true if extra borrowing expected but not reported" do
record.extrabor = 2
record.mortgage = 50_000
record.deposit = 40_000
record.value = 100_000
record.discount = 11
expect(record)
.to be_extra_borrowing_expected_but_not_reported
end
end
end end
describe "savings amount validations" do describe "savings amount validations" do
@ -392,4 +459,24 @@ RSpec.describe Validations::Sales::SoftValidations do
expect(record).not_to be_purchase_price_out_of_soft_range expect(record).not_to be_purchase_price_out_of_soft_range
end end
end end
describe "#grant_outside_common_range?" do
it "returns true if grant is below 9000" do
record.grant = 1_000
expect(record).to be_grant_outside_common_range
end
it "returns true if grant is above 16000" do
record.grant = 100_000
expect(record).to be_grant_outside_common_range
end
it "returns false if grant is within expected range" do
record.grant = 10_000
expect(record).not_to be_grant_outside_common_range
end
end
end end

1
spec/requests/lettings_logs_controller_spec.rb

@ -458,6 +458,7 @@ RSpec.describe LettingsLogsController, type: :request do
it "includes the search on the CSV link" do it "includes the search on the CSV link" do
search_term = "foo" search_term = "foo"
FactoryBot.create(:lettings_log, created_by: user, owning_organisation: user.organisation, tenancycode: "foo")
get "/lettings-logs?search=#{search_term}", headers: headers, params: {} get "/lettings-logs?search=#{search_term}", headers: headers, params: {}
expect(page).to have_link("Download (CSV)", href: "/lettings-logs/csv-download?search=#{search_term}") expect(page).to have_link("Download (CSV)", href: "/lettings-logs/csv-download?search=#{search_term}")
end end

9
spec/requests/organisations_controller_spec.rb

@ -734,8 +734,8 @@ RSpec.describe OrganisationsController, type: :request do
let(:number_of_org2_sales_logs) { 4 } let(:number_of_org2_sales_logs) { 4 }
before do before do
FactoryBot.create_list(:sales_log, number_of_org1_sales_logs, owning_organisation_id: organisation.id, managing_organisation_id: organisation.id) FactoryBot.create_list(:sales_log, number_of_org1_sales_logs, owning_organisation_id: organisation.id)
FactoryBot.create_list(:sales_log, number_of_org2_sales_logs, owning_organisation_id: unauthorised_organisation.id, managing_organisation_id: unauthorised_organisation.id) FactoryBot.create_list(:sales_log, number_of_org2_sales_logs, owning_organisation_id: unauthorised_organisation.id)
get "/organisations/#{organisation.id}/sales-logs", headers:, params: {} get "/organisations/#{organisation.id}/sales-logs", headers:, params: {}
end end
@ -1141,10 +1141,11 @@ RSpec.describe OrganisationsController, type: :request do
context "when they view the logs tab" do context "when they view the logs tab" do
before do before do
FactoryBot.create(:lettings_log, owning_organisation: organisation)
get "/organisations/#{organisation.id}/lettings-logs" get "/organisations/#{organisation.id}/lettings-logs"
end end
it "has a CSV download button with the correct path" do it "has a CSV download button with the correct path if at least 1 log exists" do
expect(page).to have_link("Download (CSV)", href: "/organisations/#{organisation.id}/logs/csv-download") expect(page).to have_link("Download (CSV)", href: "/organisations/#{organisation.id}/logs/csv-download")
end end
@ -1152,7 +1153,7 @@ RSpec.describe OrganisationsController, type: :request do
let(:other_organisation) { FactoryBot.create(:organisation) } let(:other_organisation) { FactoryBot.create(:organisation) }
before do before do
FactoryBot.create_list(:lettings_log, 3, owning_organisation: organisation) FactoryBot.create_list(:lettings_log, 2, owning_organisation: organisation)
FactoryBot.create_list(:lettings_log, 2, owning_organisation: other_organisation) FactoryBot.create_list(:lettings_log, 2, owning_organisation: other_organisation)
end end

19
spec/requests/sales_logs_controller_spec.rb

@ -3,7 +3,6 @@ require "rails_helper"
RSpec.describe SalesLogsController, type: :request do RSpec.describe SalesLogsController, type: :request do
let(:user) { FactoryBot.create(:user) } let(:user) { FactoryBot.create(:user) }
let(:owning_organisation) { user.organisation } let(:owning_organisation) { user.organisation }
let(:managing_organisation) { owning_organisation }
let(:api_username) { "test_user" } let(:api_username) { "test_user" }
let(:api_password) { "test_password" } let(:api_password) { "test_password" }
let(:basic_credentials) do let(:basic_credentials) do
@ -14,7 +13,6 @@ RSpec.describe SalesLogsController, type: :request do
let(:params) do let(:params) do
{ {
"owning_organisation_id": owning_organisation.id, "owning_organisation_id": owning_organisation.id,
"managing_organisation_id": managing_organisation.id,
"created_by_id": user.id, "created_by_id": user.id,
} }
end end
@ -51,7 +49,6 @@ RSpec.describe SalesLogsController, type: :request do
it "creates a sales log with the values passed" do it "creates a sales log with the values passed" do
json_response = JSON.parse(response.body) json_response = JSON.parse(response.body)
expect(json_response["owning_organisation_id"]).to eq(owning_organisation.id) expect(json_response["owning_organisation_id"]).to eq(owning_organisation.id)
expect(json_response["managing_organisation_id"]).to eq(managing_organisation.id)
expect(json_response["created_by_id"]).to eq(user.id) expect(json_response["created_by_id"]).to eq(user.id)
end end
@ -94,14 +91,12 @@ RSpec.describe SalesLogsController, type: :request do
FactoryBot.create( FactoryBot.create(
:sales_log, :sales_log,
owning_organisation: organisation, owning_organisation: organisation,
managing_organisation: organisation,
) )
end end
let!(:unauthorized_sales_log) do let!(:unauthorized_sales_log) do
FactoryBot.create( FactoryBot.create(
:sales_log, :sales_log,
owning_organisation: other_organisation, owning_organisation: other_organisation,
managing_organisation: other_organisation,
) )
end end
@ -119,7 +114,7 @@ RSpec.describe SalesLogsController, type: :request do
it "does have organisation values" do it "does have organisation values" do
get "/sales-logs", headers: headers, params: {} get "/sales-logs", headers: headers, params: {}
expect(page).to have_content("Owned by") expect(page).to have_content("Owned by")
expect(page).to have_content("Managed by") expect(page).not_to have_content("Managed by")
end end
it "shows sales logs for all organisations" do it "shows sales logs for all organisations" do
@ -146,13 +141,11 @@ RSpec.describe SalesLogsController, type: :request do
let!(:not_started_sales_log) do let!(:not_started_sales_log) do
FactoryBot.create(:sales_log, FactoryBot.create(:sales_log,
owning_organisation: organisation, owning_organisation: organisation,
managing_organisation: organisation,
created_by: user) created_by: user)
end end
let!(:completed_sales_log) do let!(:completed_sales_log) do
FactoryBot.create(:sales_log, :completed, FactoryBot.create(:sales_log, :completed,
owning_organisation: organisation_2, owning_organisation: organisation_2,
managing_organisation: organisation,
created_by: user_2) created_by: user_2)
end end
@ -189,14 +182,12 @@ RSpec.describe SalesLogsController, type: :request do
let!(:sales_log_2021) do let!(:sales_log_2021) do
FactoryBot.create(:sales_log, :in_progress, FactoryBot.create(:sales_log, :in_progress,
owning_organisation: organisation, owning_organisation: organisation,
saledate: Time.zone.local(2022, 3, 1), saledate: Time.zone.local(2022, 3, 1))
managing_organisation: organisation)
end end
let!(:sales_log_2022) do let!(:sales_log_2022) do
sales_log = FactoryBot.build(:sales_log, :completed, sales_log = FactoryBot.build(:sales_log, :completed,
owning_organisation: organisation, owning_organisation: organisation,
saledate: Time.zone.local(2022, 12, 1), saledate: Time.zone.local(2022, 12, 1))
managing_organisation: organisation)
sales_log.save!(validate: false) sales_log.save!(validate: false)
sales_log sales_log
end end
@ -227,14 +218,12 @@ RSpec.describe SalesLogsController, type: :request do
FactoryBot.create(:sales_log, :completed, FactoryBot.create(:sales_log, :completed,
owning_organisation: organisation, owning_organisation: organisation,
saledate: Time.zone.local(2022, 3, 1), saledate: Time.zone.local(2022, 3, 1),
managing_organisation: organisation,
created_by: user) created_by: user)
end end
let!(:sales_log_2022) do let!(:sales_log_2022) do
FactoryBot.create(:sales_log, FactoryBot.create(:sales_log,
owning_organisation: organisation, owning_organisation: organisation,
saledate: Time.zone.local(2022, 12, 1), saledate: Time.zone.local(2022, 12, 1),
managing_organisation: organisation,
created_by: user) created_by: user)
end end
@ -362,7 +351,7 @@ RSpec.describe SalesLogsController, type: :request do
context "when there are more than 20 logs" do context "when there are more than 20 logs" do
before do before do
FactoryBot.create_list(:sales_log, 25, owning_organisation: organisation, managing_organisation: organisation) FactoryBot.create_list(:sales_log, 25, owning_organisation: organisation)
end end
context "when on the first page" do context "when on the first page" do

Loading…
Cancel
Save