solidus_import_products 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +71 -0
- data/app/controllers/spree/admin/product_imports_controller.rb +35 -0
- data/app/jobs/import_products_job.rb +14 -0
- data/app/models/solidus_import_products/parser.rb +15 -0
- data/app/models/solidus_import_products/parser/base.rb +24 -0
- data/app/models/solidus_import_products/parser/csv.rb +98 -0
- data/app/models/spree/product_import.rb +82 -0
- data/app/overrides/add_import_to_admin_sidebar_menu.rb +6 -0
- data/app/services/solidus_import_products/create_variant.rb +109 -0
- data/app/services/solidus_import_products/import.rb +38 -0
- data/app/services/solidus_import_products/process_row.rb +93 -0
- data/app/services/solidus_import_products/save_product.rb +41 -0
- data/app/services/solidus_import_products/save_properties.rb +23 -0
- data/app/services/solidus_import_products/update_product.rb +45 -0
- data/app/views/spree/admin/product_imports/index.html.erb +71 -0
- data/app/views/spree/admin/product_imports/show.html.erb +37 -0
- data/app/views/spree/admin/shared/_import_sidebar_menu.erb +3 -0
- data/app/views/spree/user_mailer/product_import_results.text.erb +23 -0
- data/lib/generators/solidus_import_products/install/install_generator.rb +41 -0
- data/lib/generators/solidus_import_products/install/templates/config/initializers/solidus_import_product_settings.rb +10 -0
- data/lib/solidus_import_products.rb +8 -0
- data/lib/solidus_import_products/engine.rb +26 -0
- data/lib/solidus_import_products/exception.rb +19 -0
- data/lib/solidus_import_products/import_helper.rb +118 -0
- data/lib/solidus_import_products/logger.rb +15 -0
- data/lib/solidus_import_products/user_mailer_ext.rb +15 -0
- data/lib/tasks/solidus_import_products.rake +1 -0
- metadata +255 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7cbe547a1f35bff8d13c359e012af39a7d6280bf
|
4
|
+
data.tar.gz: 5ce9aa54661c7b0069b68648350aeba1c5dabdd7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0506cd0571e1348fe37dfb2633b97fd537dd7c9e11f36cc007f446916f1cc2fa26e2f612ed16654993b77e8c3f196a0df1fcf0c634a163a7b8e5c13934ae1fe7
|
7
|
+
data.tar.gz: b68387bf007c5b6a616c9f335a1ad56a2a86e8ed78911e12dd81376d9e484f1ecf655b6db1f146eeb731a337077a40c641163874f4ef6480628510df43c72b4a
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2018 Angel Arancibia
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in all
|
11
|
+
copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
19
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/solidus_import_products.svg)](https://badge.fury.io/rb/solidus_import_products)
|
2
|
+
[![Build Status](https://travis-ci.org/ngelx/solidus_import_products.svg?branch=master)](https://travis-ci.org/ngelx/solidus_import_products)
|
3
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/132ebaa254502b25d886/maintainability)](https://codeclimate.com/github/ngelx/solidus_import_products/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/132ebaa254502b25d886/test_coverage)](https://codeclimate.com/github/ngelx/solidus_import_products/test_coverage)
|
4
|
+
[![Dependency Status](https://beta.gemnasium.com/badges/github.com/ngelx/solidus_import_products.svg)](https://beta.gemnasium.com/projects/github.com/ngelx/solidus_import_products)
|
5
|
+
|
6
|
+
This extension adds product import functionality to Solidus, with a bunch of features that give it similar functionality to Shopify's importer.
|
7
|
+
|
8
|
+
This extension adds a tab to the administration area of Solidus, allowing a logged-in user to select and upload a file in any of the [supported formats](https://github.com/ngelx/solidus_import_products#Formats-supported) containing product information. The upload is then placed on queue for processing. Once it has been processed, the user who initiated the job is notified by email that their import has completed.
|
9
|
+
|
10
|
+
|
11
|
+
Features
|
12
|
+
==============
|
13
|
+
|
14
|
+
Products
|
15
|
+
-------------
|
16
|
+
* Create if they do not exists, otherwise update them.
|
17
|
+
* Set Properties.
|
18
|
+
* Attach/import multiple local or remote images.
|
19
|
+
* Create/Associate to many taxonomies.
|
20
|
+
|
21
|
+
Variations
|
22
|
+
------------
|
23
|
+
* Create if they do not exists, otherwise update them.
|
24
|
+
* Create Options types as needed.
|
25
|
+
* Create Options values as needed.
|
26
|
+
|
27
|
+
Formats supported
|
28
|
+
-----------
|
29
|
+
* CSV. [examples](spec/fixtures/)
|
30
|
+
|
31
|
+
ActiveJob
|
32
|
+
----------
|
33
|
+
This gem relies on ActiveJob for scheduling imports greater than 20 products/variantions. For more information about activeJob see [ActiveJob Rails Guide](http://guides.rubyonrails.org/active_job_basics.html)
|
34
|
+
|
35
|
+
|
36
|
+
Installation
|
37
|
+
==============
|
38
|
+
1. Add the gem to your Gemfile, and run bundle install.
|
39
|
+
`gem 'solidus_import_products', :git => 'git://github.com/ngelx/solidus_import_products.git'` then `bundle install`
|
40
|
+
|
41
|
+
2. rails generate solidus_import_products:install
|
42
|
+
|
43
|
+
3. Configure the extension to suit your application by changing config variables in `config/initializers/solidus_import_product_settings.rb`
|
44
|
+
|
45
|
+
4. Run application!
|
46
|
+
|
47
|
+
Sample files and documentation
|
48
|
+
==============
|
49
|
+
|
50
|
+
Some basic samples files could be find in [spec/fixtures](spec/fixtures/)
|
51
|
+
|
52
|
+
For documentation refer to the [wiki](https://github.com/ngelx/solidus_import_products/wiki)
|
53
|
+
|
54
|
+
Contributing
|
55
|
+
=======
|
56
|
+
|
57
|
+
* Fork the project
|
58
|
+
* Make your changes, including tests that exercise the code. The first steps to setup the env is something like:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
rake test_app
|
62
|
+
rake spec
|
63
|
+
```
|
64
|
+
|
65
|
+
* Summarize your changes in CHANGELOG.md
|
66
|
+
* Make a pull request
|
67
|
+
|
68
|
+
History and attribution
|
69
|
+
==============
|
70
|
+
The product import script was based on a simple import script written by Brian Quinn [here](https://gist.github.com/31710). Then it was extended by Josh McArthur (2010). After that by [2beDigital team](https://github.com/2beDigital/solidus_import_products).
|
71
|
+
Finaly after all that, I've made some big estructural changes and here we are.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Spree
|
2
|
+
module Admin
|
3
|
+
class ProductImportsController < BaseController
|
4
|
+
def index
|
5
|
+
@product_import = Spree::ProductImport.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def show
|
9
|
+
@product_import = Spree::ProductImport.find(params[:id])
|
10
|
+
@products = @product_import.products
|
11
|
+
end
|
12
|
+
|
13
|
+
def create
|
14
|
+
@product_imports = spree_current_user.product_imports.create(product_import_params)
|
15
|
+
ImportProductsJob.perform_later(@product_imports)
|
16
|
+
flash[:notice] = t('product_import_processing')
|
17
|
+
redirect_to admin_product_imports_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def destroy
|
21
|
+
@product_import = Spree::ProductImport.find(params[:id])
|
22
|
+
if @product_import.destroy
|
23
|
+
flash[:success] = t('delete_product_import_successful')
|
24
|
+
end
|
25
|
+
redirect_to admin_product_imports_path
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def product_import_params
|
31
|
+
params.require(:product_import).permit!
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class ImportProductsJob < ApplicationJob
|
2
|
+
queue_as :default
|
3
|
+
|
4
|
+
def perform(product_imports)
|
5
|
+
user = product_imports.user
|
6
|
+
begin
|
7
|
+
SolidusImportProducts::Import.call(product_imports: product_imports)
|
8
|
+
Spree::UserMailer.product_import_results(user).deliver_later
|
9
|
+
rescue StandardError => exception
|
10
|
+
Rails.logger.error("[ActiveJob] [ImportProductsJob] [#{job_id}] ID: #{product_imports} #{exception}")
|
11
|
+
Spree::UserMailer.product_import_results(user, "#{exception.message} #{exception.backtrace.join('\n')}").deliver_later
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module SolidusImportProducts
|
2
|
+
module Parser
|
3
|
+
def parse(strategy, data_file, options)
|
4
|
+
if strategy == :csv
|
5
|
+
Parser::Csv.new(data_file, options)
|
6
|
+
else
|
7
|
+
raise SolidusImportProducts::Exception::InvalidParseStrategy
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
module_function :parse
|
12
|
+
|
13
|
+
# Seguir arreglando esto apra arriba. PAra abajo aprece estar aunque un poco ams de test no vendiran mal
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SolidusImportProducts
|
2
|
+
module Parser
|
3
|
+
class Base
|
4
|
+
attr_accessor :rows, :data_file, :image_fields, :variant_image_fields, :property_fields
|
5
|
+
|
6
|
+
# column_mappings
|
7
|
+
# This method attempts to automatically map headings in the CSV files
|
8
|
+
# with fields in the product and variant models.
|
9
|
+
# Rows[0] is an array of headings for columns - SKU, Master Price, etc.)
|
10
|
+
# @return a hash of symbol heading => column index pairs
|
11
|
+
def column_mappings
|
12
|
+
raise SolidusImportProducts::AbstractMthodCall
|
13
|
+
end
|
14
|
+
|
15
|
+
def data_rows
|
16
|
+
raise SolidusImportProducts::AbstractMthodCall
|
17
|
+
end
|
18
|
+
|
19
|
+
def products_count
|
20
|
+
raise SolidusImportProducts::AbstractMthodCall
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'csv'
|
2
|
+
|
3
|
+
module SolidusImportProducts
|
4
|
+
module Parser
|
5
|
+
class Csv < Base
|
6
|
+
DEFAULT_CSV_ENCODING = 'utf-8'.freeze
|
7
|
+
DEFAULT_CSV_SEPARATOR = ','.freeze
|
8
|
+
|
9
|
+
attr_accessor :variant_option_fields, :mappings
|
10
|
+
|
11
|
+
def initialize(data_file, options)
|
12
|
+
self.data_file = data_file
|
13
|
+
self.mappings = {}
|
14
|
+
self.variant_option_fields = []
|
15
|
+
self.image_fields = []
|
16
|
+
self.variant_image_fields = []
|
17
|
+
self.property_fields = []
|
18
|
+
encoding_csv = (options[:encoding_csv] if options) || DEFAULT_CSV_ENCODING
|
19
|
+
separator_char = (options[:separator_char] if options) || DEFAULT_CSV_SEPARATOR
|
20
|
+
csv_string = open(data_file, "r:#{encoding_csv}").read.encode('utf-8')
|
21
|
+
self.rows = CSV.parse(csv_string, col_sep: separator_char)
|
22
|
+
extract_column_mappings
|
23
|
+
end
|
24
|
+
|
25
|
+
# column_mappings
|
26
|
+
# This method attempts to automatically map headings in the CSV files
|
27
|
+
# with fields in the product and variant models.
|
28
|
+
# Rows[0] is an array of headings for columns - SKU, Master Price, etc.)
|
29
|
+
# @return a hash of symbol heading => column index pairs
|
30
|
+
def column_mappings
|
31
|
+
mappings
|
32
|
+
end
|
33
|
+
|
34
|
+
# variant_option_field?
|
35
|
+
# Class method that check if a field is a variant option field
|
36
|
+
# @return true or false
|
37
|
+
def variant_option_field?(field)
|
38
|
+
variant_option_fields.include?(field.to_s)
|
39
|
+
end
|
40
|
+
|
41
|
+
# property_field?
|
42
|
+
# Class method that check if a field is a product property field
|
43
|
+
# @return true or false
|
44
|
+
def property_field?(field)
|
45
|
+
property_fields.include?(field.to_s)
|
46
|
+
end
|
47
|
+
|
48
|
+
# image_field?
|
49
|
+
# Class method that check if a field is an image field
|
50
|
+
# @return true or false
|
51
|
+
def image_field?(field)
|
52
|
+
image_fields.include?(field.to_s)
|
53
|
+
end
|
54
|
+
|
55
|
+
# variant_image_field?
|
56
|
+
# Class method that check if a field is a variant image field
|
57
|
+
# @return true or false
|
58
|
+
def variant_image_field?(field)
|
59
|
+
variant_image_fields.include?(field.to_s)
|
60
|
+
end
|
61
|
+
|
62
|
+
# data_rows
|
63
|
+
# This method fetch the product rows.
|
64
|
+
# @return a array of columns with product information
|
65
|
+
def data_rows
|
66
|
+
rows[1..-1]
|
67
|
+
end
|
68
|
+
|
69
|
+
# products_count
|
70
|
+
# This method count the product rows.
|
71
|
+
# @return a integer
|
72
|
+
def products_count
|
73
|
+
data_rows.count
|
74
|
+
end
|
75
|
+
|
76
|
+
protected
|
77
|
+
|
78
|
+
def extract_column_mappings
|
79
|
+
rows[0].each_with_index do |heading, index|
|
80
|
+
break if heading.blank?
|
81
|
+
field_name = heading.downcase.gsub(/\A\s*/, '').chomp.gsub(/\s/, '_')
|
82
|
+
if field_name.include?('[opt]')
|
83
|
+
field_name.gsub!('[opt]', '')
|
84
|
+
variant_option_fields.push(field_name)
|
85
|
+
elsif field_name.include?('[prop]')
|
86
|
+
field_name.gsub!('[prop]', '')
|
87
|
+
property_fields.push(field_name)
|
88
|
+
elsif field_name.include?('image_product')
|
89
|
+
image_fields.push(field_name)
|
90
|
+
elsif field_name.include?('image_variant')
|
91
|
+
variant_image_fields.push(field_name)
|
92
|
+
end
|
93
|
+
mappings[field_name.to_sym] = index
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
# This model is the master routine for uploading products
|
2
|
+
# Requires Paperclip and CSV to upload the CSV file and read it nicely.
|
3
|
+
|
4
|
+
# Original Author:: Josh McArthur
|
5
|
+
# License:: MIT
|
6
|
+
module Spree
|
7
|
+
class ProductImport < ActiveRecord::Base
|
8
|
+
ENCODINGS = %w[UTF-8 iso-8859-1].freeze
|
9
|
+
|
10
|
+
has_attached_file :data_file,
|
11
|
+
path: ':rails_root/tmp/product_data/data-files/:basename_:timestamp.:extension',
|
12
|
+
url: ':rails_root/tmp/product_data/data-files/:basename_:timestamp.:extension'
|
13
|
+
|
14
|
+
belongs_to :user, class_name: 'Spree::User', foreign_key: 'created_by', inverse_of: :product_imports
|
15
|
+
|
16
|
+
validates_attachment_presence :data_file
|
17
|
+
# Content type of csv vary in different browsers.
|
18
|
+
validates_attachment :data_file, presence: true, content_type: { content_type: ['text/csv', 'text/plain', 'text/comma-separated-values', 'application/octet-stream', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] }
|
19
|
+
|
20
|
+
after_destroy :destroy_products
|
21
|
+
|
22
|
+
serialize :product_ids, Array
|
23
|
+
cattr_accessor :settings
|
24
|
+
|
25
|
+
state_machine initial: :created do
|
26
|
+
event :start do
|
27
|
+
transition to: :started, from: :created
|
28
|
+
end
|
29
|
+
event :complete do
|
30
|
+
transition to: :completed, from: :started
|
31
|
+
end
|
32
|
+
event :failure do
|
33
|
+
transition to: :failed, from: %i[created started]
|
34
|
+
end
|
35
|
+
|
36
|
+
before_transition to: [:failed] do |import|
|
37
|
+
import.product_ids = []
|
38
|
+
import.failed_at = Time.current
|
39
|
+
import.completed_at = nil
|
40
|
+
end
|
41
|
+
|
42
|
+
before_transition to: [:completed] do |import|
|
43
|
+
import.failed_at = nil
|
44
|
+
import.completed_at = Time.current
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def parse
|
49
|
+
@_parse ||= SolidusImportProducts::Parser.parse(:csv, data_file.url(:default, timestamp: false), { encoding_csv: encoding_csv, separator_char: separatorChar })
|
50
|
+
end
|
51
|
+
|
52
|
+
def products
|
53
|
+
Product.where(id: product_ids)
|
54
|
+
end
|
55
|
+
|
56
|
+
def add_product(product)
|
57
|
+
product_ids << product.id unless product?(product)
|
58
|
+
end
|
59
|
+
|
60
|
+
def product?(product)
|
61
|
+
product.id && product_ids.include?(product.id)
|
62
|
+
end
|
63
|
+
|
64
|
+
def products_count
|
65
|
+
parse.product_count
|
66
|
+
end
|
67
|
+
|
68
|
+
def destroy_products
|
69
|
+
products.destroy_all
|
70
|
+
end
|
71
|
+
|
72
|
+
def state_datetime
|
73
|
+
if failed?
|
74
|
+
failed_at
|
75
|
+
elsif completed?
|
76
|
+
completed_at
|
77
|
+
else
|
78
|
+
updated_at
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module SolidusImportProducts
|
2
|
+
# CreateVariant
|
3
|
+
# This method assumes that some form of checking has already been done to
|
4
|
+
# make sure that we do actually want to create a variant.
|
5
|
+
# It performs a similar task to a product, but it also must pick up on
|
6
|
+
# size/color options
|
7
|
+
class CreateVariant
|
8
|
+
attr_accessor :product, :variant, :product_information, :logger
|
9
|
+
|
10
|
+
include SolidusImportProducts::ImportHelper
|
11
|
+
|
12
|
+
def self.call(options = {})
|
13
|
+
new.call(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def call(args = { product: nil, product_information: nil })
|
17
|
+
self.logger = SolidusImportProducts::Logger.instance
|
18
|
+
self.product_information = args[:product_information]
|
19
|
+
self.product = args[:product]
|
20
|
+
return if product_information.nil?
|
21
|
+
|
22
|
+
load_or_initialize_variant
|
23
|
+
|
24
|
+
product_information.each do |field, value|
|
25
|
+
if field == :variant_options
|
26
|
+
value.each { |variant_field, variant_value| options(variant_field, variant_value) }
|
27
|
+
elsif field == :attributes
|
28
|
+
value.each { |attr_field, attr_value| variant.send("#{attr_field}=", attr_value) if variant.respond_to?("#{attr_field}=") }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
variant.save
|
34
|
+
|
35
|
+
product_information[:variant_images].each do |filename|
|
36
|
+
find_and_attach_image_to(variant, filename)
|
37
|
+
end
|
38
|
+
|
39
|
+
stock_items
|
40
|
+
logger.log("Variant of SKU #{variant.sku} successfully imported.\n", :debug)
|
41
|
+
rescue StandardError => e
|
42
|
+
message = "A variant could not be imported - here is the information we have:\n"
|
43
|
+
message += "#{product_information}, #{variant.errors.full_messages.join(', ')}\n"
|
44
|
+
message += e.message.to_s
|
45
|
+
logger.log(message, :error)
|
46
|
+
raise SolidusImportProducts::Exception::VariantError, message
|
47
|
+
end
|
48
|
+
variant
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def load_or_initialize_variant
|
54
|
+
self.variant = Spree::Variant.find_by(sku: product_information[:attributes][:sku])
|
55
|
+
|
56
|
+
if variant
|
57
|
+
if variant.product != product
|
58
|
+
raise SolidusImportProducts::Exception::SkuError,
|
59
|
+
"SKU #{product_information[:attributes][:sku]} should belongs to #{product.inspect} but was #{variant.product.inspect}"
|
60
|
+
end
|
61
|
+
product_information[:attributes].delete(:id)
|
62
|
+
else
|
63
|
+
self.variant = product.variants.new(sku: product_information[:attributes][:sku], id: product_information[:attributes][:id])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def options(field, value)
|
68
|
+
return unless value
|
69
|
+
|
70
|
+
option_type = get_or_create_option_type(field)
|
71
|
+
option_value = get_or_create_option_value(option_type, value)
|
72
|
+
|
73
|
+
product.option_types << option_type unless product.option_types.include?(option_type)
|
74
|
+
|
75
|
+
variant.option_values << option_value unless variant.option_values.include?(option_value)
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_or_create_option_type(field)
|
79
|
+
Spree::OptionType.where('name = :field or presentation = :field', field: field.to_s).first ||
|
80
|
+
Spree::OptionType.create(name: field, presentation: field)
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_or_create_option_value(option_type, value)
|
84
|
+
option_type.option_values.where('name = :value or presentation = :value', value: value).first ||
|
85
|
+
option_type.option_values.create(presentation: value, name: value)
|
86
|
+
end
|
87
|
+
|
88
|
+
def attach_image
|
89
|
+
Spree::ProductImport.settings[:image_fields_variants].each do |field|
|
90
|
+
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def stock_items
|
95
|
+
source_location = Spree::StockLocation.find_by(default: true)
|
96
|
+
unless source_location
|
97
|
+
logger.log('Seems that there are no SourceLocation set right?, so stock will not set.', :warn) if product_information[:attributes][:stock] || product_information[:attributes][:backorderable]
|
98
|
+
return
|
99
|
+
end
|
100
|
+
logger.log("SourceLocation: #{source_location.inspect}", :debug)
|
101
|
+
|
102
|
+
stock_item = variant.stock_items.where(stock_location_id: source_location.id).first_or_initialize
|
103
|
+
|
104
|
+
stock_item.send('backorderable=', product_information[:attributes][:backorderable]) if product_information[:attributes].key?(:backorderable) && stock_item.respond_to?('backorderable=')
|
105
|
+
|
106
|
+
stock_item.set_count_on_hand(product_information[:attributes][:stock]) if product_information[:attributes][:stock]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|