plugins/suppliers/lib/suppliers_plugin/import.rb
require "csv"
require "charlock_holmes"
class SuppliersPlugin::Import
def self.product_columns(header)
keys = I18n.t "suppliers_plugin.lib.import.keys"
columns = []
header.each do |name|
c = nil; keys.each do |key, regex|
if /#{regex}/i =~ name
c = key
break
end
end
raise "duplicate column match '#{name}' already added as :#{c}" if c && c.in?(columns)
columns << c
end
# check required fields
return if ([:supplier_name, :product_name, :price] - columns).present?
columns
end
def self.products(consumer, csv)
default_product_category = consumer.environment.product_categories.find_by slug: "software-livre"
detection = CharlockHolmes::EncodingDetector.detect csv
csv = CharlockHolmes::Converter.convert csv, detection[:encoding], "UTF-8"
data = {}
rows = []
columns = []
quote_chars = %w[" | ~ ^ & *]
[",", ";", "\t"].each do |sep|
begin
rows = CSV.parse csv, quote_char: quote_chars.shift, col_sep: sep
columns = self.product_columns rows.first
rescue
if quote_chars.empty? then raise else retry end
ensure
break if columns.present?
end
end
rows.shift
raise "can't find required columns" if columns.blank?
# extract and treat attributes
rows.each do |row|
attrs = {}; row.each.with_index do |value, i|
next unless c = columns[i]
value = value.to_s.squish
attrs[c] = if value.present? then value else nil end
end
distributed = attrs[:distributed] = {}
distributed[:external_id] = attrs.delete :external_id
if supplier_price = attrs.delete(:supplier_price)
distributed[:price] = attrs[:price]
attrs[:price] = supplier_price
end
attrs[:name] = attrs.delete :product_name
unless attrs[:product_category].blank?
attrs[:product_category] = ProductCategory.find_by_solr(
attrs[:product_category], query_fields: ["name"]
).first
end
attrs[:product_category] ||= default_product_category
if qualifiers = attrs[:qualifiers]
qualifiers = JSON.parse qualifiers
qualifiers.map! do |q|
next if q.blank?
Qualifier.find_by_solr(q, query_fields: ["name"]).first
end.compact!
attrs[:qualifiers] = qualifiers
end
attrs[:unit] = consumer.environment.units.where(singular: attrs[:unit]).first || SuppliersPlugin::BaseProduct.default_unit
# FIXME
attrs.delete :stock
if composition = attrs.delete(:composition)
composition = JSON.parse composition rescue nil
distributed[:price_details] = composition.map do |name, price|
production_cost = consumer.environment.production_costs.where(name: name).first
production_cost ||= consumer.production_costs.where(name: name).first
production_cost ||= consumer.production_costs.create! name: name, owner: profile
PriceDetail.new production_cost: production_cost, price: price
end
end
# treat URLs
profile = nil
if (product_url = attrs.delete(:product_url)) && /manage_products\/show\/(\d+)/ =~ product_url
product = Product.where(id: $1).first
next if product.blank?
attrs[:record] = product
profile = product.profile
end
if supplier_url = attrs.delete(:supplier_url)
uri = URI.parse supplier_url
profile = Domain.where(name: uri.host).first.profile rescue nil
profile ||= Profile.where(identifier: Rails.application.routes.recognize_path(uri.path)[:profile]).first
next if profile.blank?
end
supplier_name = attrs.delete :supplier_name
supplier = profile || supplier_name
data[supplier] ||= []
data[supplier] << attrs
end
data.each do |supplier, products|
if supplier.is_a? Profile
supplier = consumer.add_supplier supplier, distribute_products_on_create: false
else
supplier_name = supplier
supplier = consumer.suppliers.where(name: supplier_name).first
supplier ||= SuppliersPlugin::Supplier.create_dummy consumer: consumer, name: supplier_name
end
products.each do |attrs|
attrs.delete :distributed
product = attrs.delete :record
product ||= supplier.profile.products.where(name: attrs[:name]).first
product ||= supplier.profile.products.build attrs
# let update happen only on dummy suppliers
if product.persisted? && supplier.dummy?
product.update! attrs
elsif product.new_record?
# create products as not available
attrs[:available] = false if not supplier.dummy?
product.update! attrs
end
distributed_product = product.distribute_to_consumer consumer, attrs
end
end
end
end