2020-09-01 23:16:17 +00:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
# License: AGPL-3.0-or-later WITH WTO-AP-3.0-or-later
|
|
|
|
# Full license explanation at https://github.com/houdiniproject/houdini/blob/master/LICENSE
|
|
|
|
class ImportRequest < ApplicationRecord
|
|
|
|
belongs_to :nonprofit
|
|
|
|
has_one_attached :import_file
|
|
|
|
|
|
|
|
def execute_safe(user)
|
|
|
|
begin
|
|
|
|
ImportRequest.transaction do
|
|
|
|
execute(user)
|
|
|
|
end
|
|
|
|
rescue Exception => e
|
|
|
|
body = "Import failed. Error: #{e}"
|
|
|
|
GenericMailer.generic_mail(
|
2021-04-19 23:25:46 +00:00
|
|
|
Houdini.hoster.support_email, Houdini.hoster.support_email, # FROM
|
2020-09-01 23:16:17 +00:00
|
|
|
body,
|
|
|
|
'Import error', # SUBJECT
|
2021-04-19 23:25:46 +00:00
|
|
|
Houdini.hoster.support_email, Houdini.hoster.support_email # TO
|
2020-09-01 23:16:17 +00:00
|
|
|
).deliver
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute(user)
|
|
|
|
import = Import.create(date:Time.current, nonprofit:nonprofit, user: user)
|
|
|
|
|
|
|
|
row_count = 0
|
|
|
|
imported_count = 0
|
|
|
|
supporter_ids = []
|
|
|
|
created_payment_ids = []
|
|
|
|
|
|
|
|
import_file_blob.open do |file|
|
|
|
|
CSV.new(file, headers: :first_row).each do |row|
|
|
|
|
row_count += 1
|
|
|
|
# triplet of [header_name, value, import_key]
|
|
|
|
matches = row.map { |key, val| [key, val, header_matches[key]] }
|
|
|
|
next if matches.empty?
|
|
|
|
|
|
|
|
table_data = matches.each_with_object({}) do |triplet, acc|
|
|
|
|
key, val, match = triplet
|
|
|
|
if match == 'custom_field'
|
|
|
|
acc['custom_fields'] ||= []
|
|
|
|
acc['custom_fields'].push([key, val])
|
|
|
|
elsif match == 'tag'
|
|
|
|
acc['tags'] ||= []
|
|
|
|
acc['tags'].push(val)
|
|
|
|
else
|
|
|
|
table, col = match.split('.') if match.present?
|
|
|
|
if table.present? && col.present?
|
|
|
|
acc[table] ||= {}
|
|
|
|
acc[table][col] = val
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create supporter record
|
|
|
|
if table_data['supporter']
|
|
|
|
table_data['supporter'] = InsertSupporter.defaults(table_data['supporter'])
|
|
|
|
table_data['supporter']['imported_at'] = Time.current
|
|
|
|
table_data['supporter']['import_id'] = import['id']
|
|
|
|
table_data['supporter']['nonprofit_id'] = nonprofit.id
|
|
|
|
table_data['supporter'] = Qx.insert_into(:supporters).values(table_data['supporter']).ts.returning('*').execute.first
|
|
|
|
supporter_ids.push(table_data['supporter']['id'])
|
|
|
|
imported_count += 1
|
|
|
|
else
|
|
|
|
table_data['supporter'] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create custom fields
|
|
|
|
if table_data['supporter']['id'] && table_data['custom_fields'] && table_data['custom_fields'].any?
|
|
|
|
InsertCustomFieldJoins.find_or_create(nonprofit.id, [table_data['supporter']['id']], table_data['custom_fields'])
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create new tags
|
|
|
|
if table_data['supporter']['id'] && table_data['tags'] && table_data['tags'].any?
|
|
|
|
# Split tags by semicolons
|
|
|
|
tags = table_data['tags'].select(&:present?).map { |t| t.split(/[;,]/).map(&:strip) }.flatten
|
|
|
|
InsertTagJoins.find_or_create(nonprofit.id, [table_data['supporter']['id']], tags)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create donation record
|
|
|
|
if table_data['donation'] && table_data['donation']['amount'] # must have amount. donation.date without donation.amount is no good
|
|
|
|
table_data['donation']['amount'] = (table_data['donation']['amount'].gsub(/[^\d\.]/, '').to_f * 100).to_i
|
|
|
|
table_data['donation']['supporter_id'] = table_data['supporter']['id']
|
|
|
|
table_data['donation']['nonprofit_id'] = nonprofit.id
|
|
|
|
table_data['donation']['date'] = Chronic.parse(table_data['donation']['date']) if table_data['donation']['date'].present?
|
|
|
|
table_data['donation']['date'] ||= Time.current
|
|
|
|
table_data['donation'] = Qx.insert_into(:donations).values(table_data['donation']).ts.returning('*').execute.first
|
|
|
|
imported_count += 1
|
|
|
|
else
|
|
|
|
table_data['donation'] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create payment record
|
|
|
|
if table_data['donation'] && table_data['donation']['id']
|
|
|
|
table_data['payment'] = Qx.insert_into(:payments).values(
|
|
|
|
gross_amount: table_data['donation']['amount'],
|
|
|
|
fee_total: 0,
|
|
|
|
net_amount: table_data['donation']['amount'],
|
|
|
|
kind: 'OffsitePayment',
|
|
|
|
nonprofit_id: nonprofit.id,
|
|
|
|
supporter_id: table_data['supporter']['id'],
|
|
|
|
donation_id: table_data['donation']['id'],
|
|
|
|
towards: table_data['donation']['designation'],
|
|
|
|
date: table_data['donation']['date']
|
|
|
|
).ts.returning('*')
|
|
|
|
.execute.first
|
|
|
|
imported_count += 1
|
|
|
|
else
|
|
|
|
table_data['payment'] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create offsite payment record
|
|
|
|
if table_data['donation'] && table_data['donation']['id']
|
|
|
|
table_data['offsite_payment'] = Qx.insert_into(:offsite_payments).values(
|
|
|
|
gross_amount: table_data['donation']['amount'],
|
|
|
|
check_number: GetData.chain(table_data['offsite_payment'], 'check_number'),
|
|
|
|
kind: table_data['offsite_payment'] && table_data['offsite_payment']['check_number'] ? 'check' : '',
|
|
|
|
nonprofit_id: nonprofit.id,
|
|
|
|
supporter_id: table_data['supporter']['id'],
|
|
|
|
donation_id: table_data['donation']['id'],
|
|
|
|
payment_id: table_data['payment']['id'],
|
|
|
|
date: table_data['donation']['date']
|
|
|
|
).ts.returning('*')
|
|
|
|
.execute.first
|
|
|
|
imported_count += 1
|
|
|
|
else
|
|
|
|
table_data['offsite_payment'] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
created_payment_ids.push(table_data['payment']['id']) if table_data['payment'] && table_data['payment']['id']
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Create donation activity records
|
|
|
|
InsertActivities.for_offsite_donations(created_payment_ids) if created_payment_ids.count > 0
|
|
|
|
|
|
|
|
import.row_count = row_count
|
|
|
|
import.imported_count = imported_count
|
|
|
|
import.save!
|
|
|
|
|
|
|
|
Supporter.where("supporters.id IN (?)", supporter_ids).each do |s|
|
|
|
|
Houdini.event_publisher.announce(:supporter_create, s)
|
|
|
|
end
|
|
|
|
ImportCompletedJob.perform_later(import)
|
|
|
|
destroy
|
|
|
|
import
|
|
|
|
end
|
|
|
|
end
|