module Imports class SchemeLocationImportService < ImportService def create_scheme_locations(folder) import_from(folder, :create_scheme_location) end def create_scheme_location(xml_document) attributes = scheme_attributes(xml_document) schemes = Scheme.where(old_id: attributes["scheme_old_id"]) raise "Scheme not found with legacy ID #{attributes['scheme_old_id']}" if schemes.empty? if schemes.size == 1 && schemes.first.locations&.empty? scheme = update_scheme(schemes.first, attributes) else scheme = find_scheme_to_merge(attributes) scheme ||= duplicate_scheme(schemes, attributes) end add_location(scheme, attributes) end private REGISTERED_UNDER_CARE_ACT = { 2 => "(Part-registered care home)", 3 => "(Registered personal care home)", 4 => "(Registered nursing care home)", }.freeze def create_scheme(source_scheme, attributes) scheme = Scheme.new( scheme_type: attributes["scheme_type"], registered_under_care_act: attributes["registered_under_care_act"], support_type: attributes["support_type"], intended_stay: attributes["intended_stay"], primary_client_group: attributes["primary_client_group"], secondary_client_group: attributes["secondary_client_group"], has_other_client_group: attributes["has_other_client_group"], sensitive: attributes["sensitive"], # These values were set by the scheme import (management groups) owning_organisation_id: source_scheme.owning_organisation_id, service_name: source_scheme.service_name, arrangement_type: source_scheme.arrangement_type, old_id: source_scheme.old_id, old_visible_id: source_scheme.old_visible_id, ) confirm_scheme_or_location(scheme) scheme.save! && scheme rescue ActiveRecord::RecordInvalid @logger.error("Scheme #{source_scheme.old_visible_id}: Failed to import") raise end def update_scheme(scheme, attributes) scheme.attributes = { scheme_type: attributes["scheme_type"], registered_under_care_act: attributes["registered_under_care_act"], support_type: attributes["support_type"], intended_stay: attributes["intended_stay"], primary_client_group: attributes["primary_client_group"], has_other_client_group: attributes["has_other_client_group"], secondary_client_group: attributes["secondary_client_group"], sensitive: attributes["sensitive"], } confirm_scheme_or_location(scheme) scheme.save! && scheme end def confirm_scheme_or_location(obj) obj.confirmed = true obj.validate_confirmed unless obj.errors.empty? obj.confirmed = false obj.errors.clear end end def scheme_attributes(xml_doc) attributes = {} attributes["scheme_type"] = safe_string_as_integer(xml_doc, "scheme-type") registered_under_care_act = safe_string_as_integer(xml_doc, "reg-home-type") attributes["registered_under_care_act"] = registered_under_care_act&.zero? ? nil : registered_under_care_act attributes["support_type"] = support_type(xml_doc) attributes["intended_stay"] = string_or_nil(xml_doc, "intended-stay") attributes["mobility_type"] = string_or_nil(xml_doc, "mobility-type") attributes["primary_client_group"] = string_or_nil(xml_doc, "client-group-1") attributes["secondary_client_group"] = string_or_nil(xml_doc, "client-group-2") attributes["secondary_client_group"] = nil if attributes["primary_client_group"] == attributes["secondary_client_group"] attributes["has_other_client_group"] = attributes["secondary_client_group"].present? ? 1 : 0 attributes["sensitive"] = sensitive(xml_doc) attributes["start_date"] = parse_date(xml_doc, "start-date") attributes["end_date"] = parse_date(xml_doc, "end-date") attributes["location_name"] = string_or_nil(xml_doc, "name") attributes["postcode"] = string_or_nil(xml_doc, "postcode") attributes["units"] = safe_string_as_integer(xml_doc, "total-units") attributes["type_of_unit"] = safe_string_as_integer(xml_doc, "unit-type") attributes["location_old_id"] = string_or_nil(xml_doc, "id") attributes["location_old_visible_id"] = string_or_nil(xml_doc, "visible-id") attributes["scheme_old_id"] = string_or_nil(xml_doc, "mgmtgroup") attributes["location_code"] = LocationConstants::LA_NAME_TO_CODE[string_or_nil(xml_doc, "local-authority-name")] attributes end def add_location(scheme, attributes) location = Location.create!( name: attributes["location_name"], postcode: attributes["postcode"], mobility_type: attributes["mobility_type"], units: attributes["units"], type_of_unit: attributes["type_of_unit"], old_visible_id: attributes["location_old_visible_id"], old_id: attributes["location_old_id"], startdate: attributes["start_date"], location_code: attributes["location_code"], scheme:, ) if attributes["end_date"] location.location_deactivation_periods.create!(deactivation_date: attributes["end_date"]) end confirm_scheme_or_location(location) location.save! && location rescue ActiveRecord::RecordNotUnique @logger.warn("Location is already present with legacy ID #{attributes['location_old_id']}, skipping") rescue ActiveRecord::RecordInvalid @logger.error("Location #{attributes['location_old_id']}: Failed to import") raise end def find_scheme_to_merge(attributes) Scheme.find_by( old_id: attributes["scheme_old_id"], scheme_type: attributes["scheme_type"], registered_under_care_act: attributes["registered_under_care_act"], support_type: attributes["support_type"], intended_stay: attributes["intended_stay"], primary_client_group: attributes["primary_client_group"], secondary_client_group: attributes["secondary_client_group"], ) end def duplicate_scheme(schemes, attributes) # Since all schemes in the array are different, pick the first one # In the future, consider a better selection method if needed old_scheme = schemes.first new_scheme = create_scheme(old_scheme, attributes) if old_scheme.scheme_type != new_scheme.scheme_type rename_schemes(old_scheme, new_scheme, :scheme_type) elsif old_scheme.registered_under_care_act != new_scheme.registered_under_care_act rename_registered_care(old_scheme, new_scheme) elsif old_scheme.support_type != new_scheme.support_type rename_schemes(old_scheme, new_scheme, :support_type) elsif old_scheme.intended_stay != new_scheme.intended_stay rename_schemes(old_scheme, new_scheme, :intended_stay) elsif old_scheme.primary_client_group != new_scheme.primary_client_group rename_schemes(old_scheme, new_scheme, :primary_client_group) elsif old_scheme.secondary_client_group != new_scheme.secondary_client_group rename_schemes(old_scheme, new_scheme, :secondary_client_group) end new_scheme end def rename_registered_care(*schemes) schemes.each do |scheme| if REGISTERED_UNDER_CARE_ACT.key?(scheme.registered_under_care_act_before_type_cast) suffix = REGISTERED_UNDER_CARE_ACT[scheme.registered_under_care_act_before_type_cast] scheme.update!(service_name: "#{scheme.service_name} - #{suffix}") end end end def rename_schemes(old_scheme, new_scheme, attribute) old_scheme_attribute = old_scheme.send(attribute) new_scheme_attribute = new_scheme.send(attribute) if old_scheme_attribute old_scheme_name = "#{old_scheme.service_name} - #{old_scheme_attribute}" old_scheme.update!(service_name: old_scheme_name) end if new_scheme_attribute new_scheme_name = "#{new_scheme.service_name} - #{new_scheme_attribute}" new_scheme.update!(service_name: new_scheme_name) end end def location_field_value(xml_doc, field) field_value(xml_doc, "scheme", field) end def string_or_nil(xml_doc, attribute) str = location_field_value(xml_doc, attribute) str.presence end # Safe: A string that represents only an integer (or empty/nil) def safe_string_as_integer(xml_doc, attribute) str = location_field_value(xml_doc, attribute) Integer(str, exception: false) end def sensitive(xml_doc) value = string_or_nil(xml_doc, "sensitive") if value == "true" 1 else 0 end end def parse_date(xml_doc, attribute) date = string_or_nil(xml_doc, attribute) Time.zone.parse(date) if date end def support_type(xml_doc) type = safe_string_as_integer(xml_doc, "support-type") return unless type Scheme::SUPPORT_TYPE.value?(type) ? type : 0 end end end