Class: DataImportRow

Inherits:
ApplicationRecord show all
Defined in:
app/models/data_import_row.rb

Overview

== Schema Information

Table name: data_import_rows
Database name: primary

id :integer not null, primary key
import_errors :text
import_state :integer default("not_imported"), not null
row_index :integer
customer_id :integer
data_import_id :integer

Indexes

idx_data_import_rows_unique (data_import_id,row_index) UNIQUE
index_data_import_rows_on_customer_id (customer_id)

Foreign Keys

data_import_rows_data_import_id_fk (data_import_id => data_imports.id) ON DELETE => cascade
fk_rails_... (customer_id => parties.id) ON DELETE => nullify
fk_rails_... (data_import_id => data_imports.id) ON DELETE => cascade

Belongs to collapse

Has many collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ApplicationRecord

ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation

Methods included from Models::EventPublishable

#publish_event

Class Method Details

.name_cleanup(target_value) ⇒ Object



34
35
36
# File 'app/models/data_import_row.rb', line 34

def self.name_cleanup(target_value)
  target_value.split(' ').map(&:capitalize).join(' ')
end

Instance Method Details

#customerCustomer

Returns:

See Also:



27
# File 'app/models/data_import_row.rb', line 27

belongs_to :customer, optional: true, inverse_of: :data_import_row

#data_importDataImport

Returns:

See Also:



28
# File 'app/models/data_import_row.rb', line 28

belongs_to :data_import, inverse_of: :data_import_rows

#data_import_cellsActiveRecord::Relation<DataImportCell>

Returns:

See Also:



30
# File 'app/models/data_import_row.rb', line 30

has_many :data_import_cells, inverse_of: :data_import_row

#import(logger = nil) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'app/models/data_import_row.rb', line 38

def import(logger = nil)
  return { status: :invalid_state } unless queued?
  return { status: :already_imported } if customer

  logger ||= Rails.logger
  logger.info "Import triggered on data import row #{id}"

  c = Customer.new
  begin
    Customer.transaction do
      c.source_id = data_import.source_id
      c.state = data_import.initial_state
      # c.reception_type = self.data_import.reception_type
      c.perform_lead_verification = true
      c.must_have_one_contact = false
      notes = ["Import Details created from import #{data_import.name} (id: #{data_import_id})"]
      address = nil
      logger.debug 'Starting Cell Processing'
      data_import_cells.each do |cell|
        next unless dds = cell.data_import_column&.data_dictionary_set
        next unless target_value = cell.target_value
        target_object,target_field = dds.destination.split('.')
        case target_object.to_sym
        when :customer
          target_value = self.class.name_cleanup(target_value) if /name/.match?(target_field)
          if target_field == 'customer.affiliation' && target_value.present?
            c.affiliations << target_value
          end
          if target_field == 'person_name'
            pnp = PersonNameParser.new(target_value)
            c.full_name = pnp.full_name # This sorts people name back in a normalized form, e.g Smith, John becomes John Smith company name
          else
            c.send "#{target_field}=", target_value
          end
        when :contact
          contact = (c.contacts.first || c.contacts.build)
          if /name/.match?(target_field)
            target_value = self.class.name_cleanup(target_value)
            if target_field == 'full_name'
              pnp = PersonNameParser.new(target_value).to_party(contact)
            else
              contact.send "#{target_field}=", target_value
            end
          end
        when :billing_address
          if target_field == 'full_address'
            #parse and explode the address first
            if addr = Address::NormalizedAddress.from_string(target_value)
              address ||= c.addresses.build(disable_address_correction: true)
              address.disable_address_correction = true
              address.street1 = addr.address_line1
              address.street2 = addr.address_line2
              address.city = addr.city
              address.state_code = addr.state_code
              address.zip = addr.postal_code
              address.country_iso3 = Country.iso_to_iso3_map[addr.country_iso]
              address.lng = addr.longitude
              address.lat = addr.latitude
            else #unparseable address so report in notes
              notes << "address unrecognized: #{target_value}"
            end
          else
            address ||= c.addresses.build(disable_address_correction: data_import.disable_address_correction)
            address.send "#{target_field}=", target_value
          end
        when :notes
          notes << "#{cell.data_import_column.name}: #{cell.content}"
        end
      end
      logger.debug 'Cell Processing Complete'

      country_iso3_default = (data_import.default_country_iso3 || 'USA')
      if address # some default
        logger.debug 'Address processing'
        address.country_iso3 ||= country_iso3_default
        country_iso3_default = address.country_iso3 # in case of change
        logger.debug "Address processing complete, final address is #{address}"
      end

      # A country always override the catalog
      c.catalog = Catalog.default_for_country(country_iso3_default)
      c.profile ||= data_import.try(:default_profile)
      c.profile ||= Profile.find_by(name: 'Unknown') if c.company_name.present?
      c.buying_group ||= data_import.try(:default_buying_group)
      c.tier2_program_pricing ||= c.buying_group.try(:tier2_program_pricing)
      c.tier2_program_pricing ||= c.profile.try(:tier2_program_pricing)
      c.tier2_program_pricing ||= data_import.try(:tier2_program_pricing)
      c.affiliations ||= [*c.affiliations, data_import.default_affiliation].map(&:presence).compact.uniq
      c.primary_sales_rep_id = data_import.default_primary_sales_rep_id

      if c.save
        update(import_state: :complete, customer_id: c.id, import_errors: nil)
        c.quick_note(notes.join("\n")) if notes.present?
        if data_import.activity_type.present?
          logger.info "Creating activity for new imported customer id #{c.id} from data import row #{id}"
          target_datetime = data_import.activity_resource ? data_import.activity_resource.next_working_day : Time.current
          if data_import.activity_schedule_offset_days.present?
            target_datetime += data_import.activity_schedule_offset_days.days
          end
          Activity.create(activity_type_id: data_import.activity_type_id,
                          assigned_resource_id: data_import.activity_assigned_resource_id,
                          description: data_import.activity_description,
                          new_note: data_import.activity_notes,
                          target_datetime: target_datetime,
                          creator_id: (data_import.updater_id || data_import.creator_id),
                          party_id: (c.contacts.first&.id || c.id)
                          )
        end
      else
        update(import_state: :not_imported,
                          import_errors: c.errors_to_s)
      end
    end
  rescue StandardError => e
    update(import_state: :not_imported,
                      import_errors: "Exception occured while processing: #{e}. #{e.backtrace.first(10).join("\n")}")
  end
  { status: import_state.to_sym, import_errors: import_errors, customer: customer }
end