ngelx/solidus_import_products

View on GitHub
app/services/solidus_import_products/process_row.rb

Summary

Maintainability
A
2 hrs
Test Coverage
module SolidusImportProducts
  class ProcessRow
    attr_accessor :parser, :product_imports, :logger, :row, :col, :product_information, :variant_field, :skus_of_products_before_import

    VARIANT_FIELD_NAME = :name

    def initialize(args = { parser: nil, product_imports: nil, row: nil, col: nil, skus_of_products_before_import: nil })
      self.parser = args[:parser]
      self.product_imports = args[:product_imports]
      self.row = args[:row]
      self.col = args[:col]
      self.variant_field = VARIANT_FIELD_NAME
      self.skus_of_products_before_import = args[:skus_of_products_before_import]
      self.logger = SolidusImportProducts::Logger.instance
      self.product_information = { variant_options: {}, images: [], variant_images: [], product_properties: {}, attributes: {} }
    end

    def self.call(options = {})
      new(options).call
    end

    def call
      extract_product_information
      product_information_default_values
      logger.log(product_information.to_s, :debug)

      variant_column = col[variant_field]
      product = Spree::Product.find_by(variant_field.to_s => row[variant_column])

      unless product
        if skus_of_products_before_import.include?(product_information[:attributes][:sku])
          raise SolidusImportProducts::Exception::ProductError, "SKU #{product_information[:attributes][:sku]} exists, but #{variant_field}: #{row[variant_column]} not exists!! "
        end
        product = Spree::Product.new
      end

      unless product_imports.product?(product)
        create_or_update_product(product)
        product_imports.add_product(product)
      end

      SolidusImportProducts::CreateVariant.call(product: product, product_information: product_information)
    end

    private

    def create_or_update_product(product)
      properties_hash = SolidusImportProducts::UpdateProduct.call(product: product, product_information: product_information)
      SolidusImportProducts::SaveProduct.call(product: product, product_information: product_information)
      SolidusImportProducts::SaveProperties.call(product: product, properties_hash: properties_hash)
    end

    def extract_product_information
      col.each do |key, value|
        row[value].try :strip!
        if parser.variant_option_field?(key)
          product_information[:variant_options][key] = row[value]
        elsif parser.property_field?(key)
          product_information[:product_properties][key] = row[value]
        elsif parser.image_field?(key)
          product_information[:images].push(row[value])
        elsif parser.variant_image_field?(key)
          product_information[:variant_images].push(row[value])
        else
          product_information[:attributes][key] = key.to_s.eql?('price') ? convert_to_price(row[value]) : row[value]
        end
      end
    end

    def product_information_default_values
      product_information[:attributes][:available_on] = Time.zone.today - 1.day if product_information[:attributes][:available_on].nil?

      if product_information[:attributes][:shipping_category_id].nil?
        sc = Spree::ShippingCategory.first
        product_information[:attributes][:shipping_category_id] = sc.id if sc
      end

      product_information[:attributes][:retail_only] = 0 if product_information[:attributes][:retail_only].nil?
    end

    # Special process of prices because of locales and different decimal separator characters.
    # We want to get a format with dot as decimal separator and without thousand separator
    def convert_to_price(price_str)
      raise SolidusImportProducts::Exception::InvalidPrice unless price_str
      punt = price_str.index('.')
      coma = price_str.index(',')
      if !coma.nil? && !punt.nil?
        price_str.gsub!(punt < coma ? '.' : ',', '')
      end
      price_str.tr(',', '.').to_f
    end
  end
end