Browse Source

fixup! CLDC-4212: Add 0.1% tolerance to % calculations

calculate a tolerance instead
pull/3214/head
samyou-softwire 2 months ago
parent
commit
72aa578a8e
  1. 35
      app/models/sales_log.rb
  2. 35
      app/models/validations/sales/sale_information_validations.rb

35
app/models/sales_log.rb

@ -268,10 +268,20 @@ class SalesLog < Log
value * equity / 100 value * equity / 100
end end
def expected_shared_ownership_deposit_value_range def expected_shared_ownership_deposit_value_tolerance
return unless value && equity return 1 unless value && equity
# we found that a simple tolerance was not quite what we wanted here.
# CORE wants it so if a user say, has a 66.6% equity then can enter either 66.6% or 66.7%
# so in 2026 we base our tolerance off of a discount 0.1% higher or lower
if form.start_year_2026_or_later?
lower_bound = value * ((equity - 0.1) / 100)
upper_bound = value * ((equity + 0.1) / 100)
(value * ((equity - 0.1) / 100)..value * ((equity + 0.1) / 100)) (upper_bound - lower_bound) / 2
else
1
end
end end
def stairbought_part_of_value def stairbought_part_of_value
@ -474,13 +484,20 @@ class SalesLog < Log
value - discount_amount value - discount_amount
end end
def value_with_discount_range def value_with_discount_tolerance
return if value.blank? return 1 if value.blank? || discount.nil?
return (value..value) if discount.nil?
# we found that a simple tolerance was not quite what we wanted here.
# CORE wants it so if a user say, has a 66.6% discount then can enter either 66.6% or 66.7%
# so in 2026 we base our tolerance off of a discount 0.1% higher or lower
if form.start_year_2026_or_later?
discount_amount_lower_bound = value * (discount - 0.1) / 100
discount_amount_upper_bound = value * (discount + 0.1) / 100
discount_amount_lower_bound = value * (discount - 0.1) / 100 (discount_amount_upper_bound - discount_amount_lower_bound) / 2
discount_amount_upper_bound = value * (discount + 0.1) / 100 else
(value - discount_amount_upper_bound..value - discount_amount_lower_bound) discount ? value * 0.05 / 100 : 1
end
end end
def mortgage_deposit_and_grant_total def mortgage_deposit_and_grant_total

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

@ -80,7 +80,9 @@ module Validations::Sales::SaleInformationValidations
return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3 return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3
return unless record.discount || record.grant || record.type == 29 return unless record.discount || record.grant || record.type == 29
if mortgage_deposit_and_grant_total_is_over_discount_tolerance?(record) && record.discounted_ownership_sale? tolerance = record.value_with_discount_tolerance
if over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: !record.discount.nil? || record.form.start_year_2026_or_later?) && record.discounted_ownership_sale?
deposit_and_grant_sentence = record.grant.present? ? ", cash deposit (#{record.field_formatted_as_currency('deposit')}), and grant (#{record.field_formatted_as_currency('grant')})" : " and cash deposit (#{record.field_formatted_as_currency('deposit')})" deposit_and_grant_sentence = record.grant.present? ? ", cash deposit (#{record.field_formatted_as_currency('deposit')}), and grant (#{record.field_formatted_as_currency('grant')})" : " and cash deposit (#{record.field_formatted_as_currency('deposit')})"
discount_sentence = record.discount.present? ? " (#{record.field_formatted_as_currency('value')}) subtracted by the sum of the full purchase price (#{record.field_formatted_as_currency('value')}) multiplied by the percentage discount (#{record.discount}%)" : "" discount_sentence = record.discount.present? ? " (#{record.field_formatted_as_currency('value')}) subtracted by the sum of the full purchase price (#{record.field_formatted_as_currency('value')}) multiplied by the percentage discount (#{record.discount}%)" : ""
%i[mortgageused mortgage value deposit discount grant].each do |field| %i[mortgageused mortgage value deposit discount grant].each do |field|
@ -201,10 +203,12 @@ module Validations::Sales::SaleInformationValidations
def check_non_staircasing_socialhomebuy_mortgage(record) def check_non_staircasing_socialhomebuy_mortgage(record)
return unless record.cashdis return unless record.cashdis
tolerance = record.expected_shared_ownership_deposit_value_tolerance
if record.mortgage_used? if record.mortgage_used?
return unless record.mortgage return unless record.mortgage
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.mortgage_deposit_and_discount_total, record) if over_tolerance?(record.mortgage_deposit_and_discount_total, record.expected_shared_ownership_deposit_value, tolerance, strict: record.form.start_year_2026_or_later?)
%i[mortgage value deposit cashdis equity].each do |field| %i[mortgage value deposit cashdis equity].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_used_socialhomebuy", record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_used_socialhomebuy",
mortgage: record.field_formatted_as_currency("mortgage"), mortgage: record.field_formatted_as_currency("mortgage"),
@ -225,7 +229,7 @@ module Validations::Sales::SaleInformationValidations
expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe
end end
elsif record.mortgage_not_used? elsif record.mortgage_not_used?
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.deposit_and_discount_total, record) if over_tolerance?(record.deposit_and_discount_total, record.expected_shared_ownership_deposit_value, tolerance, strict: record.form.start_year_2026_or_later?)
%i[mortgageused value deposit cashdis equity].each do |field| %i[mortgageused value deposit cashdis equity].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_not_used_socialhomebuy", record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_not_used_socialhomebuy",
deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"), deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"),
@ -247,10 +251,12 @@ module Validations::Sales::SaleInformationValidations
end end
def check_non_staircasing_non_socialhomebuy_mortgage(record) def check_non_staircasing_non_socialhomebuy_mortgage(record)
tolerance = record.expected_shared_ownership_deposit_value_tolerance
if record.mortgage_used? if record.mortgage_used?
return unless record.mortgage return unless record.mortgage
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.mortgage_and_deposit_total, record) if over_tolerance?(record.mortgage_and_deposit_total, record.expected_shared_ownership_deposit_value, tolerance, strict: record.form.start_year_2026_or_later?)
%i[mortgage value deposit equity].each do |field| %i[mortgage value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_used", record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_used",
mortgage: record.field_formatted_as_currency("mortgage"), mortgage: record.field_formatted_as_currency("mortgage"),
@ -269,7 +275,7 @@ module Validations::Sales::SaleInformationValidations
expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe
end end
elsif record.mortgage_not_used? elsif record.mortgage_not_used?
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.deposit, record) if over_tolerance?(record.deposit, record.expected_shared_ownership_deposit_value, tolerance, strict: record.form.start_year_2026_or_later?)
%i[mortgageused value deposit equity].each do |field| %i[mortgageused value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_not_used", record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_not_used",
deposit: record.field_formatted_as_currency("deposit"), deposit: record.field_formatted_as_currency("deposit"),
@ -393,25 +399,6 @@ module Validations::Sales::SaleInformationValidations
end end
end end
def total_is_over_expected_shared_ownership_deposit_tolerance?(total, record)
if record.form.start_year_2026_or_later?
!record.expected_shared_ownership_deposit_value_range.cover?(total)
else
over_tolerance?(total, record.expected_shared_ownership_deposit_value, 1)
end
end
def mortgage_deposit_and_grant_total_is_over_discount_tolerance?(record)
if record.form.start_year_2026_or_later?
!record.value_with_discount_range.cover?(record.mortgage_deposit_and_grant_total)
else
# we found that this tolerance still wasn't working for us, so for post 2026 we just calculate a range for 0.1% higher and lower.
# this means we can be certain an answer 0.1% higher or lower will always be accepted without needed to backsolve for the tolerance
tolerance = record.discount ? record.value * 0.05 / 100 : 1
over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: record.discount.present?)
end
end
def over_tolerance?(expected, actual, tolerance, strict: false) def over_tolerance?(expected, actual, tolerance, strict: false)
if strict if strict
(expected - actual).abs > tolerance (expected - actual).abs > tolerance

Loading…
Cancel
Save