Browse Source

CLDC-4212: Add 0.1% tolerance to % calculations

this is to specifically allow 0.1% more or less than the calculation expects, for those that contain %s in them

this removes difficulties on adding 66.6% equity (or should it be 66.7%?)
pull/3214/head
samyou-softwire 2 months ago
parent
commit
e77ae1d813
  1. 15
      app/models/sales_log.rb
  2. 32
      app/models/validations/sales/sale_information_validations.rb

15
app/models/sales_log.rb

@ -268,6 +268,12 @@ class SalesLog < Log
value * equity / 100
end
def expected_shared_ownership_deposit_value_range
return unless value && equity
(value * ((equity - 0.1) / 100)..value * ((equity + 0.1) / 100))
end
def stairbought_part_of_value
return unless value && stairbought
@ -468,6 +474,15 @@ class SalesLog < Log
value - discount_amount
end
def value_with_discount_range
return if value.blank?
return (value..value) if discount.nil?
discount_amount_lower_bound = value * (discount - 0.1) / 100
discount_amount_upper_bound = value * (discount + 0.1) / 100
(value - discount_amount_upper_bound..value - discount_amount_lower_bound)
end
def mortgage_deposit_and_grant_total
return if deposit.blank?

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

@ -80,10 +80,7 @@ module Validations::Sales::SaleInformationValidations
return unless record.mortgage || record.mortgageused == 2 || record.mortgageused == 3
return unless record.discount || record.grant || record.type == 29
# When a percentage discount is used, a percentage tolerance is needed to account for rounding errors
tolerance = record.discount ? record.value * 0.05 / 100 : 1
if over_tolerance?(record.mortgage_deposit_and_grant_total, record.value_with_discount, tolerance, strict: !record.discount.nil?) && record.discounted_ownership_sale?
if mortgage_deposit_and_grant_total_is_over_discount_tolerance?(record) && 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')})"
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|
@ -207,7 +204,7 @@ module Validations::Sales::SaleInformationValidations
if record.mortgage_used?
return unless record.mortgage
if over_tolerance?(record.mortgage_deposit_and_discount_total, record.expected_shared_ownership_deposit_value, 1)
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.mortgage_deposit_and_discount_total, record)
%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",
mortgage: record.field_formatted_as_currency("mortgage"),
@ -228,7 +225,7 @@ module Validations::Sales::SaleInformationValidations
expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe
end
elsif record.mortgage_not_used?
if over_tolerance?(record.deposit_and_discount_total, record.expected_shared_ownership_deposit_value, 1)
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.deposit_and_discount_total, record)
%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",
deposit_and_discount_total: record.field_formatted_as_currency("deposit_and_discount_total"),
@ -253,7 +250,7 @@ module Validations::Sales::SaleInformationValidations
if record.mortgage_used?
return unless record.mortgage
if over_tolerance?(record.mortgage_and_deposit_total, record.expected_shared_ownership_deposit_value, 1)
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.mortgage_and_deposit_total, record)
%i[mortgage value deposit equity].each do |field|
record.errors.add field, I18n.t("validations.sales.sale_information.#{field}.non_staircasing_mortgage.mortgage_used",
mortgage: record.field_formatted_as_currency("mortgage"),
@ -272,7 +269,7 @@ module Validations::Sales::SaleInformationValidations
expected_shared_ownership_deposit_value: record.field_formatted_as_currency("expected_shared_ownership_deposit_value")).html_safe
end
elsif record.mortgage_not_used?
if over_tolerance?(record.deposit, record.expected_shared_ownership_deposit_value, 1)
if total_is_over_expected_shared_ownership_deposit_tolerance?(record.deposit, record)
%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",
deposit: record.field_formatted_as_currency("deposit"),
@ -396,6 +393,25 @@ module Validations::Sales::SaleInformationValidations
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)
if strict
(expected - actual).abs > tolerance

Loading…
Cancel
Save