cirandas.net

ref: master

plugins/suppliers/lib/suppliers_plugin/import.rb


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 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
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 and 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 name: 'Produtos'

    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
      if product_category = attrs[:product_category]
        attrs[:product_category] = ProductCategory.find_by_solr(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) and /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|
        distributed_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? and 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

        product.distribute_to_consumer consumer, distributed_attrs
      end
    end
  end

end