module Imports
class SalesLogsImportService < LogsImportService
include CollectionTimeHelper
def initialize ( storage_service , logger = Rails . logger , allow_updates : false )
@logs_with_discrepancies = Set . new
@logs_overridden = Set . new
super
end
def create_logs ( folder )
import_from ( folder , :create_log )
end
private
def create_log ( xml_doc )
# only import sales logs from 22/23 collection period onwards
return unless meta_field_value ( xml_doc , " form-name " ) . include? ( " Sales " )
return unless ( compose_date ( xml_doc , " DAY " , " MONTH " , " YEAR " ) || Time . zone . parse ( field_value ( xml_doc , " xmlns " , " CompletionDate " ) ) ) > = Time . zone . local ( 2022 , 4 , 1 )
attributes = { }
previous_status = meta_field_value ( xml_doc , " status " )
# Required fields for status complete or logic to work
# Note: order matters when we derive from previous values (attributes parameter)
attributes [ " saledate " ] = compose_date ( xml_doc , " DAY " , " MONTH " , " YEAR " ) || Time . zone . parse ( field_value ( xml_doc , " xmlns " , " CompletionDate " ) )
attributes [ " owning_organisation_id " ] = find_organisation_id ( xml_doc , " owner-institution-id " )
attributes [ " type " ] = unsafe_string_as_integer ( xml_doc , " DerSaleType " )
attributes [ " old_id " ] = meta_field_value ( xml_doc , " document-id " )
attributes [ " old_form_id " ] = safe_string_as_integer ( xml_doc , " Form " )
attributes [ " creation_method " ] = creation_method ( xml_doc )
attributes [ " created_at " ] = Time . zone . parse ( meta_field_value ( xml_doc , " created-date " ) )
attributes [ " updated_at " ] = Time . zone . parse ( meta_field_value ( xml_doc , " modified-date " ) )
attributes [ " purchid " ] = string_or_nil ( xml_doc , " PurchaserCode " )
attributes [ " ownershipsch " ] = unsafe_string_as_integer ( xml_doc , " Ownership " )
attributes [ " ownershipsch " ] = ownership_from_type ( attributes ) if attributes [ " ownershipsch " ] . blank? # sometimes Ownership is missing, but type is set
attributes [ " othtype " ] = string_or_nil ( xml_doc , " Q38OtherSale " )
attributes [ " jointpur " ] = unsafe_string_as_integer ( xml_doc , " joint " )
attributes [ " jointmore " ] = unsafe_string_as_integer ( xml_doc , " JointMore " ) || 3 if attributes [ " jointpur " ] == 1
attributes [ " beds " ] = safe_string_as_integer ( xml_doc , " Q11Bedrooms " )
attributes [ " companybuy " ] = unsafe_string_as_integer ( xml_doc , " company " ) if attributes [ " ownershipsch " ] == 3
attributes [ " hholdcount " ] = other_household_members ( xml_doc , attributes )
attributes [ " hhmemb " ] = household_members ( xml_doc , attributes )
( 1 .. 6 ) . each do | index |
attributes [ " age #{ index } " ] = safe_string_as_integer ( xml_doc , " P #{ index } Age " )
attributes [ " sex #{ index } " ] = sex ( xml_doc , index )
attributes [ " ecstat #{ index } " ] = unsafe_string_as_integer ( xml_doc , " P #{ index } Eco " )
attributes [ " age #{ index } _known " ] = age_known ( xml_doc , index , attributes [ " hhmemb " ] , attributes [ " age #{ index } " ] )
end
( 2 .. 6 ) . each do | index |
attributes [ " relat #{ index } " ] = relat ( xml_doc , index )
attributes [ " details_known_ #{ index } " ] = details_known ( index , attributes )
end
attributes [ " national " ] = unsafe_string_as_integer ( xml_doc , " P1Nat " )
attributes [ " ethnic " ] = unsafe_string_as_integer ( xml_doc , " P1Eth " )
attributes [ " ethnic_group " ] = ethnic_group ( attributes [ " ethnic " ] )
attributes [ " buy1livein " ] = unsafe_string_as_integer ( xml_doc , " LiveInBuyer1 " )
attributes [ " buylivein " ] = unsafe_string_as_integer ( xml_doc , " LiveInBuyer " ) if attributes [ " ownershipsch " ] == 3
attributes [ " builtype " ] = unsafe_string_as_integer ( xml_doc , " Q13BuildingType " )
attributes [ " proptype " ] = unsafe_string_as_integer ( xml_doc , " Q12PropertyType " )
attributes [ " privacynotice " ] = 1 if string_or_nil ( xml_doc , " Qdp " ) == " Yes "
attributes [ " noint " ] = unsafe_string_as_integer ( xml_doc , " PartAPurchaser " )
attributes [ " buy2livein " ] = unsafe_string_as_integer ( xml_doc , " LiveInBuyer2 " )
attributes [ " wheel " ] = unsafe_string_as_integer ( xml_doc , " Q10Wheelchair " )
attributes [ " la " ] = string_or_nil ( xml_doc , " Q14ONSLACode " )
attributes [ " income1 " ] = safe_string_as_integer ( xml_doc , " Q2Person1Income " )
attributes [ " income1nk " ] = income_known ( unsafe_string_as_integer ( xml_doc , " P1IncKnown " ) )
attributes [ " income1nk " ] || = 0 if attributes [ " income1 " ] . present?
attributes [ " inc1mort " ] = unsafe_string_as_integer ( xml_doc , " Q2Person1Mortgage " )
attributes [ " income2 " ] = safe_string_as_integer ( xml_doc , " Q2Person2Income " )
attributes [ " income2nk " ] = income_known ( unsafe_string_as_integer ( xml_doc , " P2IncKnown " ) )
attributes [ " income2nk " ] || = 0 if attributes [ " income2 " ] . present?
attributes [ " savings " ] = safe_string_as_integer ( xml_doc , " Q3Savings " ) & . round ( - 1 )
attributes [ " savingsnk " ] = savings_known ( xml_doc )
attributes [ " savingsnk " ] || = 0 if attributes [ " savings " ] . present?
attributes [ " prevown " ] = unsafe_string_as_integer ( xml_doc , " Q4PrevOwnedProperty " )
attributes [ " mortgage " ] = safe_string_as_decimal ( xml_doc , " CALCMORT " )
attributes [ " inc2mort " ] = unsafe_string_as_integer ( xml_doc , " Q2Person2MortApplication " )
attributes [ " hb " ] = unsafe_string_as_integer ( xml_doc , " Q2a " )
attributes [ " frombeds " ] = safe_string_as_integer ( xml_doc , " Q20Bedrooms " )
attributes [ " staircase " ] = unsafe_string_as_integer ( xml_doc , " Q17aStaircase " ) if attributes [ " ownershipsch " ] == 1
attributes [ " stairbought " ] = safe_string_as_integer ( xml_doc , " PercentBought " )
attributes [ " stairowned " ] = safe_string_as_integer ( xml_doc , " PercentOwns " ) if attributes [ " staircase " ] == 1
attributes [ " mrent " ] = safe_string_as_decimal ( xml_doc , " Q28MonthlyRent " )
attributes [ " exdate " ] = compose_date ( xml_doc , " EXDAY " , " EXMONTH " , " EXYEAR " )
attributes [ " exday " ] = safe_string_as_integer ( xml_doc , " EXDAY " )
attributes [ " exmonth " ] = safe_string_as_integer ( xml_doc , " EXMONTH " )
attributes [ " exyear " ] = safe_string_as_integer ( xml_doc , " EXYEAR " )
attributes [ " resale " ] = unsafe_string_as_integer ( xml_doc , " Q17Resale " )
attributes [ " deposit " ] = deposit ( xml_doc , attributes )
attributes [ " cashdis " ] = safe_string_as_decimal ( xml_doc , " Q27SocialHomeBuy " )
attributes [ " disabled " ] = unsafe_string_as_integer ( xml_doc , " Disability " )
attributes [ " lanomagr " ] = unsafe_string_as_integer ( xml_doc , " Q19Rehoused " )
attributes [ " value " ] = purchase_price ( xml_doc , attributes )
attributes [ " equity " ] = safe_string_as_decimal ( xml_doc , " Q23Equity " )
attributes [ " discount " ] = safe_string_as_decimal ( xml_doc , " Q33Discount " )
attributes [ " grant " ] = safe_string_as_decimal ( xml_doc , " Q32Reductions " )
attributes [ " pregyrha " ] = 1 if string_or_nil ( xml_doc , " PREGYRHA " ) == " Yes "
attributes [ " pregla " ] = 1 if string_or_nil ( xml_doc , " PREGLA " ) == " Yes "
attributes [ " pregghb " ] = 1 if string_or_nil ( xml_doc , " PREGHBA " ) == " Yes "
attributes [ " pregother " ] = 1 if string_or_nil ( xml_doc , " PREGOTHER " ) == " Yes "
attributes [ " ppostcode_full " ] = parse_postcode ( string_or_nil ( xml_doc , " Q7Postcode " ) )
attributes [ " prevloc " ] = string_or_nil ( xml_doc , " Q7ONSLACode " )
attributes [ " ppcodenk " ] = previous_postcode_known ( xml_doc , attributes [ " ppostcode_full " ] , attributes [ " prevloc " ] ) # Q7UNKNOWNPOSTCODE check mapping
attributes [ " ppostc1 " ] = string_or_nil ( xml_doc , " PPOSTC1 " )
attributes [ " ppostc2 " ] = string_or_nil ( xml_doc , " PPOSTC2 " )
attributes [ " hhregres " ] = unsafe_string_as_integer ( xml_doc , " ArmedF " )
attributes [ " hhregresstill " ] = still_serving ( xml_doc )
attributes [ " proplen " ] = safe_string_as_integer ( xml_doc , " Q16aProplen2 " ) || safe_string_as_integer ( xml_doc , " Q16aProplensec2 " )
attributes [ " mscharge " ] = monthly_charges ( xml_doc , attributes )
attributes [ " has_mscharge " ] = 1 if attributes [ " mscharge " ] & . positive?
attributes [ " has_mscharge " ] = 0 if attributes [ " mscharge " ] . present? && attributes [ " mscharge " ] < = 0
attributes [ " prevten " ] = unsafe_string_as_integer ( xml_doc , " Q6PrevTenure " )
attributes [ " mortlen " ] = mortgage_length ( xml_doc , attributes )
attributes [ " extrabor " ] = borrowing ( xml_doc , attributes )
attributes [ " mortgageused " ] = mortgage_used ( xml_doc , attributes )
attributes [ " wchair " ] = unsafe_string_as_integer ( xml_doc , " Q15Wheelchair " )
attributes [ " armedforcesspouse " ] = unsafe_string_as_integer ( xml_doc , " ARMEDFORCESSPOUSE " )
attributes [ " hodate " ] = compose_date ( xml_doc , " HODAY " , " HOMONTH " , " HOYEAR " )
attributes [ " hoday " ] = safe_string_as_integer ( xml_doc , " HODAY " )
attributes [ " homonth " ] = safe_string_as_integer ( xml_doc , " HOMONTH " )
attributes [ " hoyear " ] = safe_string_as_integer ( xml_doc , " HOYEAR " )
attributes [ " fromprop " ] = unsafe_string_as_integer ( xml_doc , " Q21PropertyType " )
attributes [ " socprevten " ] = unsafe_string_as_integer ( xml_doc , " PrevRentType " )
attributes [ " mortgagelender " ] = mortgage_lender ( xml_doc , attributes )
attributes [ " mortgagelenderother " ] = mortgage_lender_other ( xml_doc , attributes )
attributes [ " postcode_full " ] = parse_postcode ( string_or_nil ( xml_doc , " Q14Postcode " ) )
attributes [ " pcodenk " ] = 0 if attributes [ " postcode_full " ] . present? # known if given
attributes [ " soctenant " ] = 0 if set_soctenant_fields? ( attributes )
attributes [ " previous_la_known " ] = 1 if attributes [ " prevloc " ] . present?
if attributes [ " la " ] . present?
attributes [ " la_known " ] = 1
attributes [ " is_la_inferred " ] = false
end
# Soft validations can become required answers, set them to yes by default
attributes [ " mortgage_value_check " ] = 0
attributes [ " shared_ownership_deposit_value_check " ] = 0
attributes [ " value_value_check " ] = 0
attributes [ " savings_value_check " ] = 0
attributes [ " income1_value_check " ] = 0
attributes [ " deposit_value_check " ] = 0
attributes [ " wheel_value_check " ] = 0
attributes [ " retirement_value_check " ] = 0
attributes [ " extrabor_value_check " ] = 0
attributes [ " grant_value_check " ] = 0
attributes [ " staircase_bought_value_check " ] = 0
attributes [ " deposit_and_mortgage_value_check " ] = 0
attributes [ " old_persons_shared_ownership_value_check " ] = 0
attributes [ " income2_value_check " ] = 0
attributes [ " monthly_charges_value_check " ] = 0
attributes [ " student_not_child_value_check " ] = 0
attributes [ " discounted_sale_value_check " ] = 0
attributes [ " buyer_livein_value_check " ] = 0
attributes [ " percentage_discount_value_check " ] = 0
attributes [ " hodate_check " ] = 0
attributes [ " saledate_check " ] = 0
attributes [ " combined_income_value_check " ] = 0
attributes [ " stairowned_value_check " ] = 0
# 2023/34 attributes
attributes [ " address_line1 " ] = string_or_nil ( xml_doc , " AddressLine1 " )
attributes [ " address_line2 " ] = string_or_nil ( xml_doc , " AddressLine2 " )
attributes [ " town_or_city " ] = string_or_nil ( xml_doc , " TownCity " )
attributes [ " county " ] = string_or_nil ( xml_doc , " County " )
attributes [ " uprn " ] = address_given? ( attributes ) ? nil : string_or_nil ( xml_doc , " UPRN " )
attributes [ " uprn_known " ] = attributes [ " uprn " ] . present? ? 1 : 0
attributes [ " uprn_confirmed " ] = attributes [ " uprn " ] . present? ? 1 : 0
attributes [ " proplen_asked " ] = 0 if attributes [ " proplen " ] & . positive?
attributes [ " proplen_asked " ] = 1 if attributes [ " proplen " ] & . zero?
attributes [ " prevshared " ] = unsafe_string_as_integer ( xml_doc , " PREVSHARED " )
attributes [ " ethnicbuy2 " ] = unsafe_string_as_integer ( xml_doc , " P2Eth " )
attributes [ " ethnic_group2 " ] = ethnic_group ( attributes [ " ethnicbuy2 " ] )
attributes [ " nationalbuy2 " ] = unsafe_string_as_integer ( xml_doc , " P2Nat " )
attributes [ " buy2living " ] = unsafe_string_as_integer ( xml_doc , " BUY2LIVEIN " )
attributes [ " staircasesale " ] = unsafe_string_as_integer ( xml_doc , " STAIRCASESALE " )
attributes [ " prevtenbuy2 " ] = unsafe_string_as_integer ( xml_doc , " PREVTENBUY2 " )
# Sets the log creator
owner_id = meta_field_value ( xml_doc , " owner-user-id " ) . strip
if owner_id . present?
user = LegacyUser . find_by ( old_user_id : owner_id ) & . user
if user . blank? || user . organisation_id != attributes [ " owning_organisation_id " ]
if user . blank?
@logger . error ( " Sales log ' #{ attributes [ 'old_id' ] } ' belongs to legacy user with owner-user-id: ' #{ owner_id } ' which cannot be found. Assigning log to 'Unassigned' user. " )
else
@logger . error ( " Sales log ' #{ attributes [ 'old_id' ] } ' belongs to legacy user with owner-user-id: ' #{ owner_id } ' which belongs to a different organisation. Assigning log to 'Unassigned' user. " )
end
if User . find_by ( name : " Unassigned " , organisation_id : attributes [ " owning_organisation_id " ] )
user = User . find_by ( name : " Unassigned " , organisation_id : attributes [ " owning_organisation_id " ] )
else
user = User . new (
name : " Unassigned " ,
organisation_id : attributes [ " owning_organisation_id " ] ,
is_dpo : false ,
encrypted_password : SecureRandom . hex ( 10 ) ,
email : SecureRandom . uuid ,
confirmed_at : Time . zone . now ,
active : false ,
)
user . save! ( validate : false )
end
end
attributes [ " created_by " ] = user
end
attributes [ " values_updated_at " ] = Time . zone . now
set_default_values ( attributes ) if previous_status . include? ( " submitted " )
sales_log = save_sales_log ( attributes , previous_status )
compute_differences ( sales_log , attributes )
check_status_completed ( sales_log , previous_status ) unless @logs_overridden . include? ( sales_log . old_id )
end
def save_sales_log ( attributes , previous_status )
sales_log = SalesLog . new ( attributes )
begin
sales_log . save!
sales_log
rescue ActiveRecord :: RecordNotUnique
legacy_id = attributes [ " old_id " ]
record = SalesLog . find_by ( old_id : legacy_id )
if allow_updates
attributes [ " updated_at " ] = Time . zone . now
record . update! ( attributes )
end
record
rescue ActiveRecord :: RecordInvalid = > e
rescue_validation_or_raise ( sales_log , attributes , previous_status , e )
end
end
def rescue_validation_or_raise ( sales_log , attributes , previous_status , exception )
if %w[ saved submitted-invalid ] . include? ( previous_status )
sales_log . errors . each do | error |
unless error . attribute == :type || error . attribute == :ownershipsch
attributes . delete ( error . attribute . to_s )
end
attributes . delete ( " pcodenk " ) if error . attribute == :postcode_full
attributes . delete ( " ppcodenk " ) if error . attribute == :ppostcode_full
end
@logs_overridden << sales_log . old_id
return save_sales_log ( attributes , previous_status )
end
errors = {
% i [ postcode_full postcodes_not_matching ] = > %w[ ppcodenk ppostcode_full ] ,
% i [ exdate over_a_year_from_saledate ] = > %w[ exdate ] ,
% i [ income1 over_hard_max_for_outside_london ] = > %w[ income1 ] ,
% i [ income1 over_combined_hard_max_for_outside_london ] = > %w[ income1 income2 ] ,
% i [ income1 over_hard_max_for_london ] = > %w[ income1 ] ,
% i [ income1 over_combined_hard_max_for_london ] = > %w[ income1 income2 ] ,
% i [ income2 over_hard_max_for_outside_london ] = > %w[ income2 ] ,
% i [ income2 over_combined_hard_max_for_outside_london ] = > %w[ income1 income2 ] ,
% i [ income2 over_hard_max_for_london ] = > %w[ income2 ] ,
% i [ income2 over_combined_hard_max_for_london ] = > %w[ income1 income2 ] ,
% i [ equity over_max ] = > %w[ equity ] ,
% i [ equity under_min ] = > %w[ equity ] ,
% i [ mscharge under_min ] = > %w[ mscharge has_mscharge ] ,
% i [ mortgage cannot_be_0 ] = > %w[ mortgage ] ,
% i [ frombeds outside_the_range ] = > %w[ frombeds ] ,
% i [ age1 outside_the_range ] = > %w[ age1 age1_known ] ,
% i [ proplen outside_the_range ] = > %w[ proplen ] ,
}
errors . each do | ( error , fields ) |
next unless sales_log . errors . of_kind? ( * error )
fields . each do | field |
attributes . delete ( field )
end
@logs_overridden << sales_log . old_id
return save_sales_log ( attributes , previous_status )
end
if sales_log . errors . of_kind? ( :postcode_full , :wrong_format )
@logs_overridden << sales_log . old_id
attributes . delete ( " postcode_full " )
attributes [ " pcodenk " ] = attributes [ " la " ] . present? ? 1 : nil
save_sales_log ( attributes , previous_status )
elsif sales_log . errors . of_kind? ( :ppostcode_full , :wrong_format )
@logs_overridden << sales_log . old_id
attributes . delete ( " ppostcode_full " )
attributes [ " ppcodenk " ] = attributes [ " prevloc " ] . present? ? 1 : nil
save_sales_log ( attributes , previous_status )
elsif sales_log . errors . of_kind? ( :uprn , :uprn_error )
@logs_overridden << sales_log . old_id
attributes [ " uprn_known " ] = 0
save_sales_log ( attributes , previous_status )
else
@logger . error ( " Log #{ sales_log . old_id } : Failed to import " )
sales_log . errors . each do | error |
@logger . error ( " Validation error: Field #{ error . attribute } : " )
@logger . error ( " \t Owning Organisation: #{ sales_log . owning_organisation & . name } " )
@logger . error ( " \t Old CORE ID: #{ sales_log . old_id } " )
@logger . error ( " \t Old CORE: #{ attributes [ error . attribute . to_s ] & . inspect } " )
@logger . error ( " \t New CORE: #{ sales_log . read_attribute ( error . attribute ) & . inspect } " )
@logger . error ( " \t Error message: #{ error . type } " )
end
raise exception
end
end
def compute_differences ( sales_log , attributes )
differences = [ ]
attributes . each do | key , value |
sales_log_value = sales_log . send ( key . to_sym )
next if fields_not_present_in_softwire_data . include? ( key )
if value != sales_log_value
differences . push ( " #{ key } #{ value . inspect } #{ sales_log_value . inspect } " )
end
end
end
def fields_not_present_in_softwire_data
%w[ created_by
income1_value_check
income2_value_check
mortgage_value_check
savings_value_check
deposit_value_check
wheel_value_check
retirement_value_check
extrabor_value_check
deposit_and_mortgage_value_check
shared_ownership_deposit_value_check
grant_value_check
value_value_check
old_persons_shared_ownership_value_check
staircase_bought_value_check
monthly_charges_value_check
hodate_check
saledate_check
student_not_child_value_check
discounted_sale_value_check
buyer_livein_value_check
percentage_discount_value_check
combined_income_value_check
stairowned_value_check
uprn_known
uprn_confirmed ]
end
def check_status_completed ( sales_log , previous_status )
if previous_status . include? ( " submitted " ) && sales_log . status != " completed "
@logs_with_discrepancies << sales_log . old_id
end
end
def age_known ( _xml_doc , index , hhmemb , age )
return nil if hhmemb . present? && index > hhmemb
return 0 if age . present?
end
def details_known ( index , attributes )
return nil if attributes [ " hhmemb " ] . nil? || index > attributes [ " hhmemb " ]
return nil if attributes [ " jointpur " ] == 1 && index == 2
if attributes [ " age #{ index } _known " ] != 0 &&
attributes [ " sex #{ index } " ] == " R " &&
attributes [ " relat #{ index } " ] == " R " &&
attributes [ " ecstat #{ index } " ] == 10
2 # No
else
1 # Yes
end
end
MORTGAGE_LENDER_OPTIONS = {
" atom bank " = > 1 ,
" barclays bank plc " = > 2 ,
" bath building society " = > 3 ,
" buckinghamshire building society " = > 4 ,
" cambridge building society " = > 5 ,
" coventry building society " = > 6 ,
" cumberland building society " = > 7 ,
" darlington building society " = > 8 ,
" dudley building society " = > 9 ,
" ecology building society " = > 10 ,
" halifax " = > 11 ,
" hanley economic building society " = > 12 ,
" hinckley and rugby building society " = > 13 ,
" holmesdale building society " = > 14 ,
" ipswich building society " = > 15 ,
" leeds building society " = > 16 ,
" lloyds bank " = > 17 ,
" mansfield building society " = > 18 ,
" market harborough building society " = > 19 ,
" melton mowbray building society " = > 20 ,
" nationwide building society " = > 21 ,
" natwest " = > 22 ,
" nedbank private wealth " = > 23 ,
" newbury building society " = > 24 ,
" oneSavings bank " = > 25 ,
" parity trust " = > 26 ,
" penrith building society " = > 27 ,
" pepper homeloans " = > 28 ,
" royal bank of scotland " = > 29 ,
" santander " = > 30 ,
" skipton building society " = > 31 ,
" teachers building society " = > 32 ,
" the co-operative bank " = > 33 ,
" tipton & coseley building society " = > 34 ,
" tss " = > 35 ,
" ulster bank " = > 36 ,
" virgin money " = > 37 ,
" west bromwich building society " = > 38 ,
" yorkshire building society " = > 39 ,
" other " = > 40 ,
} . freeze
# this comes through as a string, need to map to a corresponding integer
def mortgage_lender ( xml_doc , attributes )
lender = case attributes [ " ownershipsch " ]
when 1
string_or_nil ( xml_doc , " Q24aMortgageLender " )
when 2
string_or_nil ( xml_doc , " Q34a " )
when 3
string_or_nil ( xml_doc , " Q41aMortgageLender " )
end
return if lender . blank?
MORTGAGE_LENDER_OPTIONS [ lender . downcase ] || MORTGAGE_LENDER_OPTIONS [ " other " ]
end
def mortgage_lender_other ( xml_doc , attributes )
return unless attributes [ " mortgagelender " ] == MORTGAGE_LENDER_OPTIONS [ " other " ]
case attributes [ " ownershipsch " ]
when 1
string_or_nil ( xml_doc , " Q24aMortgageLender " )
when 2
string_or_nil ( xml_doc , " Q34a " )
when 3
string_or_nil ( xml_doc , " Q41aMortgageLender " )
end
end
def mortgage_length ( xml_doc , attributes )
case attributes [ " ownershipsch " ]
when 1
unsafe_string_as_integer ( xml_doc , " Q24b " )
when 2
unsafe_string_as_integer ( xml_doc , " Q34b " )
when 3
unsafe_string_as_integer ( xml_doc , " Q41b " )
end
end
def savings_known ( xml_doc )
case unsafe_string_as_integer ( xml_doc , " savingsKnown " )
when 1 # known
0
when 2 # unknown
1
end
end
def still_serving ( xml_doc )
case unsafe_string_as_integer ( xml_doc , " LeftArmedF " )
when 4
4
when 5 , 6
5
end
end
def income_known ( value )
case value
when 1 # known
0
when 2 # unknown
1
end
end
def borrowing ( xml_doc , attributes )
case attributes [ " ownershipsch " ]
when 1
unsafe_string_as_integer ( xml_doc , " Q25Borrowing " )
when 2
unsafe_string_as_integer ( xml_doc , " Q35Borrowing " )
when 3
unsafe_string_as_integer ( xml_doc , " Q42Borrowing " )
end
end
def purchase_price ( xml_doc , attributes )
case attributes [ " ownershipsch " ]
when 1
safe_string_as_decimal ( xml_doc , " Q22PurchasePrice " )
when 2
safe_string_as_decimal ( xml_doc , " Q31PurchasePrice " )
when 3
safe_string_as_decimal ( xml_doc , " Q40PurchasePrice " )
end
end
def deposit ( xml_doc , attributes )
case attributes [ " ownershipsch " ]
when 1
safe_string_as_decimal ( xml_doc , " Q26CashDeposit " )
when 2
safe_string_as_decimal ( xml_doc , " Q36CashDeposit " )
when 3
safe_string_as_decimal ( xml_doc , " Q43CashDeposit " )
end
end
def monthly_charges ( xml_doc , attributes )
case attributes [ " ownershipsch " ]
when 1
safe_string_as_decimal ( xml_doc , " Q29MonthlyCharges " )
when 2
safe_string_as_decimal ( xml_doc , " Q37MonthlyCharges " )
when 3
safe_string_as_decimal ( xml_doc , " Q44MonthlyCharges " )
end
end
def ownership_from_type ( attributes )
case attributes [ " type " ]
when 2 , 24 , 18 , 16 , 28 , 31 , 30 , 32
1 # shared ownership
when 8 , 14 , 27 , 9 , 29 , 21 , 22
2 # discounted ownership
when 10 , 12
3 # outright sale
end
end
def other_household_members ( xml_doc , attributes )
hholdcount = safe_string_as_integer ( xml_doc , " LiveInOther " )
return hholdcount if hholdcount . present?
other_people_with_details ( xml_doc , attributes )
end
def other_people_with_details ( xml_doc , attributes )
number_of_buyers = attributes [ " jointpur " ] == 1 ? 2 : 1
highest_person_index_with_details = number_of_buyers
( 2 .. 6 ) . each do | person_index |
age = string_or_nil ( xml_doc , " P #{ person_index } Age " )
gender = string_or_nil ( xml_doc , " P #{ person_index } Sex " )
relationship = string_or_nil ( xml_doc , " P #{ person_index } Rel " )
economic_status = string_or_nil ( xml_doc , " P #{ person_index } Eco " )
if gender . present? || age . present? || relationship . present? || economic_status . present?
highest_person_index_with_details = person_index
end
end
highest_person_index_with_details - number_of_buyers
end
def household_members ( _xml_doc , attributes )
if attributes [ " jointpur " ] == 2
attributes [ " hholdcount " ] + 1
else
attributes [ " hholdcount " ] + 2
end
end
def parse_postcode ( postcode )
return if postcode . blank?
UKPostcode . parse ( postcode ) . to_s
end
def mortgage_used ( xml_doc , attributes )
mortgageused = unsafe_string_as_integer ( xml_doc , " MORTGAGEUSED " )
return mortgageused unless mortgageused == 3
if attributes [ " mortgage " ] . present? || attributes [ " mortlen " ] . present? || attributes [ " extrabor " ] . present?
1 # yes
else
3 # don't know
end
end
def set_soctenant_fields? ( attributes )
return false if attributes [ " ownershipsch " ] != 1
%w[ socprevten frombeds fromprop ] . any? { | field | attributes [ field ] . present? } || collection_start_year_for_date ( attributes [ " saledate " ] ) < 2023
end
def set_default_values ( attributes )
attributes [ " armedforcesspouse " ] || = 7
attributes [ " hhregres " ] || = 8
attributes [ " hhregresstill " ] || = 7 if attributes [ " hhregres " ] == 1
attributes [ " disabled " ] || = 3
attributes [ " wheel " ] || = 3
attributes [ " hb " ] || = 4
attributes [ " prevown " ] || = 3
attributes [ " savingsnk " ] || = attributes [ " savings " ] . present? ? 0 : 1
attributes [ " inc1mort " ] || = 3
if [ attributes [ " pregyrha " ] , attributes [ " pregla " ] , attributes [ " pregghb " ] , attributes [ " pregother " ] ] . all? ( & :blank? )
attributes [ " pregblank " ] = 1
end
attributes [ " pcodenk " ] || = 1
attributes [ " prevten " ] || = 0
attributes [ " extrabor " ] || = 3 if attributes [ " mortgageused " ] == 1
attributes [ " socprevten " ] || = 10 if set_soctenant_fields? ( attributes )
attributes [ " fromprop " ] || = 0 if set_soctenant_fields? ( attributes )
attributes [ " mortgagelender " ] || = 0 if attributes [ " mortgageused " ] == 1
# buyer 1 characteristics
attributes [ " age1_known " ] || = 1
attributes [ " sex1 " ] || = " R "
attributes [ " ethnic_group " ] || = 17
attributes [ " ethnic " ] || = 17
attributes [ " national " ] || = 13
attributes [ " ecstat1 " ] || = 10
attributes [ " income1nk " ] || = attributes [ " income1 " ] . present? ? 0 : 1
# buyer 2 characteristics
if attributes [ " jointpur " ] == 1
attributes [ " age2_known " ] || = 1
attributes [ " sex2 " ] || = " R "
attributes [ " ecstat2 " ] || = 10
attributes [ " income2nk " ] || = attributes [ " income2 " ] . present? ? 0 : 1
attributes [ " relat2 " ] || = " R "
attributes [ " inc2mort " ] || = 3
attributes [ " buy2livein " ] || = 1 unless attributes [ " ownershipsch " ] == 3
attributes [ " ethnic_group2 " ] || = 17
attributes [ " ethnicbuy2 " ] || = 17
attributes [ " nationalbuy2 " ] || = 13
end
# other household members characteristics
( 2 .. [ attributes [ " hhmemb " ] , 6 ] . min ) . each do | index |
attributes [ " age #{ index } _known " ] || = 1
attributes [ " sex #{ index } " ] || = " R "
attributes [ " ecstat #{ index } " ] || = 10
attributes [ " relat #{ index } " ] || = " R "
end
end
def missing_answers ( sales_log )
applicable_questions = sales_log . form . subsections . map { | s | s . applicable_questions ( sales_log ) . select { | q | q . enabled? ( sales_log ) } } . flatten
applicable_questions . filter { | q | q . unanswered? ( sales_log ) } . map ( & :id ) - sales_log . optional_fields
end
def address_given? ( attributes )
attributes [ " address_line1 " ] . present? && attributes [ " town_or_city " ] . present?
end
end
end