Browse Source

Merge branch 'main' into CLDC-4325-ensure-tests-will-pass-on-go-live

pull/3250/head
samyou-softwire 2 weeks ago
parent
commit
ba0431a78d
  1. 119
      Gemfile.lock
  2. 3
      app/services/bulk_upload/lettings/year2025/row_parser.rb
  3. 3
      app/services/bulk_upload/lettings/year2026/row_parser.rb
  4. 3
      app/services/bulk_upload/sales/year2025/row_parser.rb
  5. 83
      app/services/bulk_upload/sales/year2026/row_parser.rb
  6. 4
      config/locales/validations/sales/2026/bulk_upload.en.yml
  7. 27
      docs/Gemfile.lock
  8. 6
      spec/services/bulk_upload/sales/year2023/row_parser_spec.rb
  9. 6
      spec/services/bulk_upload/sales/year2024/row_parser_spec.rb
  10. 4
      spec/services/bulk_upload/sales/year2025/row_parser_spec.rb
  11. 562
      spec/services/bulk_upload/sales/year2026/row_parser_spec.rb

119
Gemfile.lock

@ -1,70 +1,72 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.2.2.2) actioncable (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (7.2.2.2) actionmailbox (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
activejob (= 7.2.2.2) activejob (= 7.2.3.1)
activerecord (= 7.2.2.2) activerecord (= 7.2.3.1)
activestorage (= 7.2.2.2) activestorage (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (7.2.2.2) actionmailer (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
actionview (= 7.2.2.2) actionview (= 7.2.3.1)
activejob (= 7.2.2.2) activejob (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.2.2.2) actionpack (7.2.3.1)
actionview (= 7.2.2.2) actionview (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
cgi
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc racc
rack (>= 2.2.4, < 3.2) rack (>= 2.2.4, < 3.3)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) useragent (~> 0.16)
actiontext (7.2.2.2) actiontext (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
activerecord (= 7.2.2.2) activerecord (= 7.2.3.1)
activestorage (= 7.2.2.2) activestorage (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.2.2.2) actionview (7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
builder (~> 3.1) builder (~> 3.1)
cgi
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
activejob (7.2.2.2) activejob (7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.2.2.2) activemodel (7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
activemodel-serializers-xml (1.0.3) activemodel-serializers-xml (1.0.3)
activemodel (>= 5.0.0.a) activemodel (>= 5.0.0.a)
activesupport (>= 5.0.0.a) activesupport (>= 5.0.0.a)
builder (~> 3.1) builder (~> 3.1)
activerecord (7.2.2.2) activerecord (7.2.3.1)
activemodel (= 7.2.2.2) activemodel (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (7.2.2.2) activestorage (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
activejob (= 7.2.2.2) activejob (= 7.2.3.1)
activerecord (= 7.2.2.2) activerecord (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (7.2.2.2) activesupport (7.2.3.1)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
@ -73,7 +75,7 @@ GEM
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
logger (>= 1.4.2) logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1, < 6)
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.6) addressable (2.8.6)
@ -147,6 +149,7 @@ GEM
capybara-screenshot (1.0.26) capybara-screenshot (1.0.26)
capybara (>= 1.0, < 4) capybara (>= 1.0, < 4)
launchy launchy
cgi (0.5.1)
childprocess (5.0.0) childprocess (5.0.0)
coderay (1.1.3) coderay (1.1.3)
coercible (1.0.0) coercible (1.0.0)
@ -283,9 +286,7 @@ GEM
matrix (0.4.2) matrix (0.4.2)
method_source (1.1.0) method_source (1.1.0)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (6.0.2) minitest (5.27.0)
drb (~> 2.0)
prism (~> 1.5)
msgpack (1.7.2) msgpack (1.7.2)
multipart-post (2.4.1) multipart-post (2.4.1)
nested_form (0.3.2) nested_form (0.3.2)
@ -368,20 +369,20 @@ GEM
rack (>= 1.3) rack (>= 1.3)
rackup (2.3.1) rackup (2.3.1)
rack (>= 3) rack (>= 3)
rails (7.2.2.2) rails (7.2.3.1)
actioncable (= 7.2.2.2) actioncable (= 7.2.3.1)
actionmailbox (= 7.2.2.2) actionmailbox (= 7.2.3.1)
actionmailer (= 7.2.2.2) actionmailer (= 7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
actiontext (= 7.2.2.2) actiontext (= 7.2.3.1)
actionview (= 7.2.2.2) actionview (= 7.2.3.1)
activejob (= 7.2.2.2) activejob (= 7.2.3.1)
activemodel (= 7.2.2.2) activemodel (= 7.2.3.1)
activerecord (= 7.2.2.2) activerecord (= 7.2.3.1)
activestorage (= 7.2.2.2) activestorage (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.2.2.2) railties (= 7.2.3.1)
rails-dom-testing (2.3.0) rails-dom-testing (2.3.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
@ -396,13 +397,15 @@ GEM
nested_form (~> 0.3) nested_form (~> 0.3)
rails (>= 6.0, < 9) rails (>= 6.0, < 9)
turbo-rails (>= 1.0, < 3) turbo-rails (>= 1.0, < 3)
railties (7.2.2.2) railties (7.2.3.1)
actionpack (= 7.2.2.2) actionpack (= 7.2.3.1)
activesupport (= 7.2.2.2) activesupport (= 7.2.3.1)
cgi
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0, >= 1.2.2) thor (~> 1.0, >= 1.2.2)
tsort (>= 0.2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.1) rake (13.3.1)

3
app/services/bulk_upload/lettings/year2025/row_parser.rb

@ -525,6 +525,9 @@ class BulkUpload::Lettings::Year2025::RowParser
@log ||= LettingsLog.new(attributes_for_log) @log ||= LettingsLog.new(attributes_for_log)
end end
# Will send a "Bulk upload failed" email rather than an "Errors in bulk upload" email.
# The body of the "Bulk upload failed" email says there are errors in the setup section,
# so only use this method for setup section errors.
def block_log_creation! def block_log_creation!
self.block_log_creation = true self.block_log_creation = true
end end

3
app/services/bulk_upload/lettings/year2026/row_parser.rb

@ -560,6 +560,9 @@ class BulkUpload::Lettings::Year2026::RowParser
@log ||= LettingsLog.new(attributes_for_log) @log ||= LettingsLog.new(attributes_for_log)
end end
# Will send a "Bulk upload failed" email rather than an "Errors in bulk upload" email.
# The body of the "Bulk upload failed" email says there are errors in the setup section,
# so only use this method for setup section errors.
def block_log_creation! def block_log_creation!
self.block_log_creation = true self.block_log_creation = true
end end

3
app/services/bulk_upload/sales/year2025/row_parser.rb

@ -1290,6 +1290,9 @@ private
end end
end end
# Will send a "Bulk upload failed" email rather than an "Errors in bulk upload" email.
# The body of the "Bulk upload failed" email says there are errors in the setup section,
# so only use this method for setup section errors.
def block_log_creation! def block_log_creation!
self.block_log_creation = true self.block_log_creation = true
end end

83
app/services/bulk_upload/sales/year2026/row_parser.rb

@ -152,6 +152,7 @@ class BulkUpload::Sales::Year2026::RowParser
}.freeze }.freeze
ERROR_BASE_KEY = "validations.sales.2026.bulk_upload".freeze ERROR_BASE_KEY = "validations.sales.2026.bulk_upload".freeze
NUMBER_OR_R_FORMAT = /\A(\d+(\.\d+)?|R)\z/i
CASE_INSENSITIVE_FIELDS = [ CASE_INSENSITIVE_FIELDS = [
:field_29, # Age of buyer 1 :field_29, # Age of buyer 1
@ -176,6 +177,11 @@ class BulkUpload::Sales::Year2026::RowParser
:field_103, # What is the length of the mortgage in years? - Shared ownership :field_103, # What is the length of the mortgage in years? - Shared ownership
:field_133, # What is the length of the mortgage in years? - Discounted ownership :field_133, # What is the length of the mortgage in years? - Discounted ownership
:field_107, # What are the total monthly service charges for the property?
:field_125, # What are the monthly service charges for the property?
:field_126, # New monthly service charge amount
:field_136, # What are the total monthly leasehold charges for the property?
].freeze ].freeze
attribute :bulk_upload attribute :bulk_upload
@ -296,7 +302,7 @@ class BulkUpload::Sales::Year2026::RowParser
attribute :field_104, :decimal attribute :field_104, :decimal
attribute :field_105, :decimal attribute :field_105, :decimal
attribute :field_106, :decimal attribute :field_106, :decimal
attribute :field_107, :decimal attribute :field_107, :string
attribute :field_108, :decimal attribute :field_108, :decimal
attribute :field_109, :decimal attribute :field_109, :decimal
@ -315,8 +321,8 @@ class BulkUpload::Sales::Year2026::RowParser
attribute :field_122, :integer attribute :field_122, :integer
attribute :field_123, :decimal attribute :field_123, :decimal
attribute :field_124, :decimal attribute :field_124, :decimal
attribute :field_125, :integer attribute :field_125, :string
attribute :field_126, :decimal attribute :field_126, :string
attribute :field_127, :integer attribute :field_127, :integer
attribute :field_128, :decimal attribute :field_128, :decimal
@ -327,7 +333,7 @@ class BulkUpload::Sales::Year2026::RowParser
attribute :field_133, :string attribute :field_133, :string
attribute :field_134, :integer attribute :field_134, :integer
attribute :field_135, :decimal attribute :field_135, :decimal
attribute :field_136, :decimal attribute :field_136, :string
validates :field_1, validates :field_1,
presence: { presence: {
@ -496,6 +502,8 @@ class BulkUpload::Sales::Year2026::RowParser
validate :validate_buyer_2_nationality, on: :after_log validate :validate_buyer_2_nationality, on: :after_log
validate :validate_mortlen_field_if_buyer_interviewed, on: :after_log validate :validate_mortlen_field_if_buyer_interviewed, on: :after_log
validate :validate_service_charge_fields, on: :after_log
validate :validate_nulls, on: :after_log validate :validate_nulls, on: :after_log
def self.question_for_field(field) def self.question_for_field(field)
@ -899,7 +907,7 @@ private
gender_same_as_sex6: %i[field_68], gender_same_as_sex6: %i[field_68],
gender_description6: %i[field_69], gender_description6: %i[field_69],
hasservicechargeschanged: %i[field_125], hasservicechargeschanged: %i[field_126],
newservicecharges: %i[field_126], newservicecharges: %i[field_126],
} }
end end
@ -950,9 +958,6 @@ private
attributes["gender_same_as_sex6"] = field_68 attributes["gender_same_as_sex6"] = field_68
attributes["gender_description6"] = field_69 attributes["gender_description6"] = field_69
attributes["hasservicechargeschanged"] = field_125
attributes["newservicecharges"] = field_126
attributes["relat2"] = relationship_from_is_partner(field_37) attributes["relat2"] = relationship_from_is_partner(field_37)
attributes["relat3"] = relationship_from_is_partner(field_47) attributes["relat3"] = relationship_from_is_partner(field_47)
attributes["relat4"] = relationship_from_is_partner(field_53) attributes["relat4"] = relationship_from_is_partner(field_53)
@ -1026,8 +1031,6 @@ private
attributes["cashdis"] = field_105 attributes["cashdis"] = field_105
attributes["mrent"] = mrent attributes["mrent"] = mrent
attributes["mscharge"] = mscharge if mscharge&.positive?
attributes["has_mscharge"] = attributes["mscharge"].present? ? 1 : 0
attributes["grant"] = field_129 attributes["grant"] = field_129
attributes["discount"] = field_130 attributes["discount"] = field_130
@ -1097,6 +1100,11 @@ private
attributes["management_fee"] = field_108 attributes["management_fee"] = field_108
attributes["has_management_fee"] = field_108.present? && field_108.positive? ? 1 : 0 attributes["has_management_fee"] = field_108.present? && field_108.positive? ? 1 : 0
attributes["has_mscharge"] = has_mscharge_value
attributes["mscharge"] = mscharge_value
attributes["hasservicechargeschanged"] = hasservicechargeschanged_value
attributes["newservicecharges"] = newservicecharges_value
attributes attributes
end end
@ -1256,11 +1264,36 @@ private
end end
def mscharge def mscharge
return field_107 if shared_ownership? return field_107 if shared_ownership_initial_purchase?
return field_125 if staircasing?
field_136 if discounted_ownership? field_136 if discounted_ownership?
end end
def has_mscharge_value
return unless mscharge.present? && mscharge.match?(NUMBER_OR_R_FORMAT)
mscharge.casecmp?("R") ? 0 : 1
end
def mscharge_value
return unless mscharge.present? && mscharge.match?(NUMBER_OR_R_FORMAT) && !mscharge.casecmp?("R")
mscharge.to_d
end
def hasservicechargeschanged_value
return unless field_126.present? && field_126.match?(NUMBER_OR_R_FORMAT)
field_126.casecmp?("R") ? 2 : 1
end
def newservicecharges_value
return unless field_126.present? && field_126.match?(NUMBER_OR_R_FORMAT) && !field_126.casecmp?("R")
field_126.to_d
end
def mortlen def mortlen
return field_103 if shared_ownership? return field_103 if shared_ownership?
@ -1333,10 +1366,11 @@ private
end end
def mscharge_fields def mscharge_fields
return [:field_107] if shared_ownership? return [:field_107] if shared_ownership_initial_purchase?
return [:field_125] if staircasing?
return [:field_136] if discounted_ownership? return [:field_136] if discounted_ownership?
%i[field_107 field_136] %i[field_107 field_125 field_136]
end end
def mortlen_fields def mortlen_fields
@ -1389,6 +1423,29 @@ private
end end
end end
def validate_service_charge_fields
message = I18n.t("#{ERROR_BASE_KEY}.mscharge.invalid")
if shared_ownership_initial_purchase? && field_107.present? && !field_107.match?(NUMBER_OR_R_FORMAT)
errors.add(:field_107, message)
end
if staircasing?
if field_125.present? && !field_125.match?(NUMBER_OR_R_FORMAT)
errors.add(:field_125, message)
end
if field_126.present? && !field_126.match?(NUMBER_OR_R_FORMAT)
errors.add(:field_126, I18n.t("#{ERROR_BASE_KEY}.newservicecharges.invalid"))
end
end
if discounted_ownership? && field_136.present? && !field_136.match?(NUMBER_OR_R_FORMAT)
errors.add(:field_136, message)
end
end
# Will send a "Bulk upload failed" email rather than an "Errors in bulk upload" email
def block_log_creation! def block_log_creation!
self.block_log_creation = true self.block_log_creation = true
end end

4
config/locales/validations/sales/2026/bulk_upload.en.yml

@ -44,6 +44,10 @@ en:
not_answered: "Enter either the UPRN or the full address." not_answered: "Enter either the UPRN or the full address."
nationality: nationality:
invalid: "Select a valid nationality." invalid: "Select a valid nationality."
mscharge:
invalid: "Service charge must be a positive number or the letter R."
newservicecharges:
invalid: "New service charge must be a number or the letter R."
mortlen: mortlen:
invalid: "Mortgage length must be a number or the letter R" invalid: "Mortgage length must be a number or the letter R"
invalid_for_interviewed: "You indicated that you interviewed the buyer(s), but selected “Don’t know” for mortgage length. Please provide the mortgage length or update your response." invalid_for_interviewed: "You indicated that you interviewed the buyer(s), but selected “Don’t know” for mortgage length. Please provide the mortgage length or update your response."

27
docs/Gemfile.lock

@ -1,22 +1,34 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
activesupport (7.0.7.2) activesupport (7.2.3.1)
concurrent-ruby (~> 1.0, >= 1.0.2) base64
benchmark (>= 0.3)
bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
minitest (>= 5.1) logger (>= 1.4.2)
tzinfo (~> 2.0) minitest (>= 5.1, < 6)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.1) addressable (2.8.1)
public_suffix (>= 2.0.2, < 6.0) public_suffix (>= 2.0.2, < 6.0)
base64 (0.3.0)
benchmark (0.5.0)
bigdecimal (4.0.1)
coffee-script (2.4.1) coffee-script (2.4.1)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.11.1) coffee-script-source (1.11.1)
colorator (1.1.0) colorator (1.1.0)
commonmarker (0.23.10) commonmarker (0.23.10)
concurrent-ruby (1.2.2) concurrent-ruby (1.3.6)
connection_pool (3.0.2)
dnsruby (1.61.9) dnsruby (1.61.9)
simpleidn (~> 0.1) simpleidn (~> 0.1)
drb (2.2.3)
em-websocket (0.5.3) em-websocket (0.5.3)
eventmachine (>= 0.12.9) eventmachine (>= 0.12.9)
http_parser.rb (~> 0) http_parser.rb (~> 0)
@ -88,7 +100,7 @@ GEM
activesupport (>= 2) activesupport (>= 2)
nokogiri (>= 1.4) nokogiri (>= 1.4)
http_parser.rb (0.8.0) http_parser.rb (0.8.0)
i18n (1.14.1) i18n (1.14.8)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jekyll (3.9.3) jekyll (3.9.3)
addressable (~> 2.4) addressable (~> 2.4)
@ -213,7 +225,7 @@ GEM
jekyll (>= 3.5, < 5.0) jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9) jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1) jekyll-seo-tag (~> 2.1)
minitest (5.19.0) minitest (5.27.0)
net-http (0.9.1) net-http (0.9.1)
uri (>= 0.11.1) uri (>= 0.11.1)
nokogiri (1.19.1-arm64-darwin) nokogiri (1.19.1-arm64-darwin)
@ -244,6 +256,7 @@ GEM
sawyer (0.9.2) sawyer (0.9.2)
addressable (>= 2.3.5) addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3) faraday (>= 0.17.3, < 3)
securerandom (0.4.1)
simpleidn (0.2.1) simpleidn (0.2.1)
unf (~> 0.1.4) unf (~> 0.1.4)
terminal-table (1.8.0) terminal-table (1.8.0)

6
spec/services/bulk_upload/sales/year2023/row_parser_spec.rb

@ -1334,7 +1334,7 @@ RSpec.describe BulkUpload::Sales::Year2023::RowParser do
context "when mscharge is given, but is set to 0 for shared ownership" do context "when mscharge is given, but is set to 0 for shared ownership" do
let(:attributes) { valid_attributes.merge(field_114: "0") } let(:attributes) { valid_attributes.merge(field_114: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil
@ -1344,7 +1344,7 @@ RSpec.describe BulkUpload::Sales::Year2023::RowParser do
context "when mscharge is given, but is set to 0 for discounted ownership" do context "when mscharge is given, but is set to 0 for discounted ownership" do
let(:attributes) { valid_attributes.merge(field_7: "2", field_126: "0") } let(:attributes) { valid_attributes.merge(field_7: "2", field_126: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil
@ -1354,7 +1354,7 @@ RSpec.describe BulkUpload::Sales::Year2023::RowParser do
context "when mscharge is given, but is set to 0 for outright sale" do context "when mscharge is given, but is set to 0 for outright sale" do
let(:attributes) { valid_attributes.merge(field_7: "3", field_135: "0") } let(:attributes) { valid_attributes.merge(field_7: "3", field_135: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil

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

@ -1973,7 +1973,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
context "when mscharge is given, but is set to 0 for shared ownership" do context "when mscharge is given, but is set to 0 for shared ownership" do
let(:attributes) { valid_attributes.merge(field_112: "0") } let(:attributes) { valid_attributes.merge(field_112: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil
@ -1983,7 +1983,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
context "when mscharge is given, but is set to 0 for discounted ownership" do context "when mscharge is given, but is set to 0 for discounted ownership" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_124: "0") } let(:attributes) { valid_attributes.merge(field_8: "2", field_124: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil
@ -1993,7 +1993,7 @@ RSpec.describe BulkUpload::Sales::Year2024::RowParser do
context "when mscharge is given, but is set to 0 for outright sale" do context "when mscharge is given, but is set to 0 for outright sale" do
let(:attributes) { valid_attributes.merge(field_8: "3", field_131: "0") } let(:attributes) { valid_attributes.merge(field_8: "3", field_131: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil

4
spec/services/bulk_upload/sales/year2025/row_parser_spec.rb

@ -1889,7 +1889,7 @@ RSpec.describe BulkUpload::Sales::Year2025::RowParser do
context "when mscharge is given, but is set to 0 for shared ownership" do context "when mscharge is given, but is set to 0 for shared ownership" do
let(:attributes) { valid_attributes.merge(field_94: "0") } let(:attributes) { valid_attributes.merge(field_94: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil
@ -1899,7 +1899,7 @@ RSpec.describe BulkUpload::Sales::Year2025::RowParser do
context "when mscharge is given, but is set to 0 for discounted ownership" do context "when mscharge is given, but is set to 0 for discounted ownership" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_121: "0") } let(:attributes) { valid_attributes.merge(field_8: "2", field_121: "0") }
it "does not override variables correctly" do it "does not override variables" do
log = parser.log log = parser.log
expect(log["has_mscharge"]).to eq(0) # no expect(log["has_mscharge"]).to eq(0) # no
expect(log["mscharge"]).to be_nil expect(log["mscharge"]).to be_nil

562
spec/services/bulk_upload/sales/year2026/row_parser_spec.rb

@ -116,7 +116,7 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do
field_31: "1", field_31: "1",
field_40: "2", field_40: "2",
field_41: "Non-binary", field_41: "Non-binary",
field_125: "1", field_125: "200",
field_126: "150", field_126: "150",
} }
end end
@ -301,7 +301,7 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do
context "and case insensitive fields are set to lowercase" do context "and case insensitive fields are set to lowercase" do
let(:case_insensitive_fields) { %w[field_30 field_39 field_49 field_55 field_61 field_67] } let(:case_insensitive_fields) { %w[field_30 field_39 field_49 field_55 field_61 field_67] }
let(:case_insensitive_integer_fields_with_r_option) { %w[field_29 field_38 field_48 field_54 field_60 field_66 field_77 field_88 field_83 field_85 field_103 field_133] } let(:case_insensitive_integer_fields_with_r_option) { %w[field_29 field_38 field_48 field_54 field_60 field_66 field_77 field_88 field_83 field_85 field_103 field_107 field_125 field_126 field_133 field_136] }
let(:attributes) do let(:attributes) do
valid_attributes valid_attributes
.merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase }) .merge(case_insensitive_fields.each_with_object({}) { |field, h| h[field.to_sym] = valid_attributes[field.to_sym]&.downcase })
@ -1948,23 +1948,555 @@ RSpec.describe BulkUpload::Sales::Year2026::RowParser do
end end
end end
context "when mscharge is given, but is set to 0 for shared ownership" do context "with service charges fields" do
let(:attributes) { valid_attributes.merge(field_107: "0") } context "with mscharge for shared ownership initial purchase (field_107)" do
context "when positive" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "100") }
it "does not override variables correctly" do it "does not add a validation error" do
log = parser.log parser.valid?
expect(log["has_mscharge"]).to eq(0) # no expect(parser.errors[:field_107]).to be_blank
expect(log["mscharge"]).to be_nil end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(100)
end
end
context "when set to 1" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "1") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_107]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(1)
end
end
context "when set to 0" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "0") }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_107]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_107]).to include(I18n.t("validations.sales.financial.mscharge.monthly_leasehold_charges.not_zero"))
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to 0.0" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "0.0") }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_107]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_107]).to include(I18n.t("validations.sales.financial.mscharge.monthly_leasehold_charges.not_zero"))
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to R" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "R") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_107]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when set to lowercase r" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "r") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_107]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when an invalid string" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "X") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_107]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when blank" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: nil) }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_107]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_107]).to include("You must answer property service charges.")
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when negative" do
let(:attributes) { valid_attributes.merge(field_10: "2", field_107: "-100") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_107]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
end end
end
context "when mscharge is given, but is set to 0 for discounted ownership" do context "with mscharge for staircasing (field_125)" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "0") } context "when positive" do
let(:attributes) { valid_attributes.merge(field_125: "100") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(100)
end
end
context "when set to 1" do
let(:attributes) { valid_attributes.merge(field_125: "1") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(1)
end
end
context "when set to 0" do
let(:attributes) { valid_attributes.merge(field_125: "0") }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_125]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_125]).to include(I18n.t("validations.sales.financial.mscharge.monthly_leasehold_charges.not_zero"))
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to 0.0" do
let(:attributes) { valid_attributes.merge(field_125: "0.0") }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_125]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_125]).to include(I18n.t("validations.sales.financial.mscharge.monthly_leasehold_charges.not_zero"))
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to R" do
let(:attributes) { valid_attributes.merge(field_125: "R") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when set to lowercase r" do
let(:attributes) { valid_attributes.merge(field_125: "r") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when an invalid string" do
let(:attributes) { valid_attributes.merge(field_125: "X") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when blank" do
let(:attributes) { valid_attributes.merge(field_125: nil) }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_125]).not_to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
expect(parser.errors[:field_125]).to include("You must answer property service charges.")
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when negative" do
let(:attributes) { valid_attributes.merge(field_125: "-100") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_125]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
end
context "with mscharge for discounted ownership (field_136)" do
context "when positive" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "100") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(100)
end
end
context "when set to 1" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "1") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(1)
end
end
context "when set to 0" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "0") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to 0.0" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "0.0") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to yes and mscharge to the value" do
log = parser.log
expect(log["has_mscharge"]).to eq(1)
expect(log["mscharge"]).to eq(0)
end
end
context "when set to R" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "R") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when set to lowercase r" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "r") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "sets has_mscharge to no and does not set mscharge" do
log = parser.log
expect(log["has_mscharge"]).to eq(0)
expect(log["mscharge"]).to be_nil
end
end
context "when an invalid string" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "X") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when blank" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: nil) }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to be_blank
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
context "when negative" do
let(:attributes) { valid_attributes.merge(field_8: "2", field_136: "-100") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_136]).to include(I18n.t("validations.sales.2026.bulk_upload.mscharge.invalid"))
end
it "does not set has_mscharge or mscharge" do
log = parser.log
expect(log["has_mscharge"]).to be_nil
expect(log["mscharge"]).to be_nil
end
end
end
context "with newservicecharges (field_126)" do
context "when positive" do
let(:attributes) { valid_attributes.merge(field_126: "150") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to be_blank
end
it "sets hasservicechargeschanged to yes and newservicecharges to the value" do
log = parser.log
expect(log["hasservicechargeschanged"]).to eq(1)
expect(log["newservicecharges"]).to eq(150)
end
end
context "when set to 0" do
let(:attributes) { valid_attributes.merge(field_126: "0") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to be_blank
end
it "sets hasservicechargeschanged to yes and newservicecharges to 0" do
log = parser.log
expect(log["hasservicechargeschanged"]).to eq(1)
expect(log["newservicecharges"]).to eq(0)
end
end
context "when set to 0.0" do
let(:attributes) { valid_attributes.merge(field_126: "0.0") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to be_blank
end
it "sets hasservicechargeschanged to yes and newservicecharges to 0" do
log = parser.log
expect(log["hasservicechargeschanged"]).to eq(1)
expect(log["newservicecharges"]).to eq(0)
end
end
context "when set to R" do
let(:attributes) { valid_attributes.merge(field_126: "R") }
it "does not add a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to be_blank
end
it "sets hasservicechargeschanged to no and does not set newservicecharges" do
log = parser.log
expect(log["hasservicechargeschanged"]).to eq(2)
expect(log["newservicecharges"]).to be_nil
end
end
context "when set to lowercase r" do
let(:attributes) { valid_attributes.merge(field_126: "r") }
it "does not override variables correctly" do it "does not add a validation error" do
log = parser.log parser.valid?
expect(log["has_mscharge"]).to eq(0) # no expect(parser.errors[:field_126]).to be_blank
expect(log["mscharge"]).to be_nil end
it "sets hasservicechargeschanged to no and does not set newservicecharges" do
log = parser.log
expect(log["hasservicechargeschanged"]).to eq(2)
expect(log["newservicecharges"]).to be_nil
end
end
context "when an invalid string" do
let(:attributes) { valid_attributes.merge(field_126: "X") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to include(I18n.t("validations.sales.2026.bulk_upload.newservicecharges.invalid"))
end
it "does not set hasservicechargeschanged or newservicecharges" do
log = parser.log
expect(log["hasservicechargeschanged"]).to be_nil
expect(log["newservicecharges"]).to be_nil
end
end
context "when blank" do
let(:attributes) { valid_attributes.merge(field_126: nil) }
it "does not add a bulk upload format validation error but adds a site validation error" do
parser.valid?
expect(parser.errors[:field_126]).not_to include(I18n.t("validations.sales.2026.bulk_upload.newservicecharges.invalid"))
expect(parser.errors[:field_126]).to include("You must answer service charge will change.")
end
it "does not set hasservicechargeschanged or newservicecharges" do
log = parser.log
expect(log["hasservicechargeschanged"]).to be_nil
expect(log["newservicecharges"]).to be_nil
end
end
context "when negative" do
let(:attributes) { valid_attributes.merge(field_126: "-150") }
it "adds a validation error" do
parser.valid?
expect(parser.errors[:field_126]).to include(I18n.t("validations.sales.2026.bulk_upload.newservicecharges.invalid"))
end
it "does not set hasservicechargeschanged or newservicecharges" do
log = parser.log
expect(log["hasservicechargeschanged"]).to be_nil
expect(log["newservicecharges"]).to be_nil
end
end
end
context "when newservicecharges equals mscharge (field_125 == field_126)" do
let(:attributes) { valid_attributes.merge(field_125: "200", field_126: "200") }
it "adds validation errors to both fields" do
parser.valid?
expect(parser.errors[:field_125]).to include(I18n.t("validations.sales.financial.mscharge.same_as_new"))
expect(parser.errors[:field_126]).to include(I18n.t("validations.sales.financial.newservicecharges.same_as_previous"))
end
end end
end end

Loading…
Cancel
Save