Permalink
Browse files

after_product_built hook

  • Loading branch information...
1 parent 476740c commit ad6c61ca101dc74b099bf01e16bc3de63a736c83 @jzw jzw committed Jul 22, 2011
Showing with 64 additions and 49 deletions.
  1. +64 −49 app/models/product_import.rb
View
113 app/models/product_import.rb
@@ -28,15 +28,15 @@ def import_data!
@names_of_products_before_import << product.name
end
log("#{@names_of_products_before_import}")
-
+
rows = CSV.read(self.data_file.path)
-
+
if IMPORT_PRODUCT_SETTINGS[:first_row_is_headings]
col = get_column_mappings(rows[0])
else
col = IMPORT_PRODUCT_SETTINGS[:column_mappings]
end
-
+
log("Importing products for #{self.data_file_file_name} began at #{Time.now}")
rows[IMPORT_PRODUCT_SETTINGS[:rows_to_skip]..-1].each do |row|
product_information = {}
@@ -48,12 +48,12 @@ def import_data!
col.each do |key, value|
product_information[key] = row[value]
end
-
-
+
+
#Manually set available_on if it is not already set
product_information[:available_on] = DateTime.now - 1.day if product_information[:available_on].nil?
-
+
#Trim whitespace off the beginning and end of row fields
row.each do |r|
next unless r.is_a?(String)
@@ -91,21 +91,21 @@ def import_data!
private
-
-
+
+
# create_variant_for
- # This method assumes that some form of checking has already been done to
+ # This method assumes that some form of checking has already been done to
# make sure that we do actually want to create a variant.
# It performs a similar task to a product, but it also must pick up on
# size/color options
def create_variant_for(product, options = {:with => {}})
return if options[:with].nil?
variant = product.variants.new
-
+
#Remap the options - oddly enough, Spree's product model has master_price and cost_price, while
#variant has price and cost_price.
options[:with][:price] = options[:with].delete(:master_price)
-
+
#First, set the primitive fields on the object (prices, etc.)
options[:with].each do |field, value|
variant.send("#{field}=", value) if variant.respond_to?("#{field}=")
@@ -121,102 +121,104 @@ def create_variant_for(product, options = {:with => {}})
)
end
end
-
-
+
+
if variant.valid?
variant.save
-
+
#Associate our new variant with any new taxonomies
- IMPORT_PRODUCT_SETTINGS[:taxonomy_fields].each do |field|
+ IMPORT_PRODUCT_SETTINGS[:taxonomy_fields].each do |field|
associate_product_with_taxon(variant.product, field.to_s, options[:with][field.to_sym])
end
-
+
#Finally, attach any images that have been specified
IMPORT_PRODUCT_SETTINGS[:image_fields].each do |field|
find_and_attach_image_to(variant, options[:with][field.to_sym])
end
-
+
#Log a success message
- log("Variant of SKU #{variant.sku} successfully imported.\n")
+ log("Variant of SKU #{variant.sku} successfully imported.\n")
else
log("A variant could not be imported - here is the information we have:\n" +
"#{pp options[:with]}, :error")
return false
end
end
-
-
+
+
# create_product_using
- # This method performs the meaty bit of the import - taking the parameters for the
+ # This method performs the meaty bit of the import - taking the parameters for the
# product we have gathered, and creating the product and related objects.
# It also logs throughout the method to try and give some indication of process.
def create_product_using(params_hash)
product = Product.new
-
- #The product is inclined to complain if we just dump all params
- # into the product (including images and taxonomies).
+
+ #The product is inclined to complain if we just dump all params
+ # into the product (including images and taxonomies).
# What this does is only assigns values to products if the product accepts that field.
params_hash.each do |field, value|
product.send("#{field}=", value) if product.respond_to?("#{field}=")
end
-
+
+ after_product_built(product, params_hash)
+
#We can't continue without a valid product here
unless product.valid?
log("A product could not be imported - here is the information we have:\n" +
"#{pp params_hash}, :error")
return false
end
-
+
#Just log which product we're processing
log(product.name)
-
+
#This should be caught by code in the main import code that checks whether to create
#variants or not. Since that check can be turned off, however, we should double check.
if @names_of_products_before_import.include? product.name
log("#{product.name} is already in the system.\n")
else
#Save the object before creating asssociated objects
product.save
-
-
+
+
#Associate our new product with any taxonomies that we need to worry about
- IMPORT_PRODUCT_SETTINGS[:taxonomy_fields].each do |field|
+ IMPORT_PRODUCT_SETTINGS[:taxonomy_fields].each do |field|
associate_product_with_taxon(product, field.to_s, params_hash[field.to_sym])
end
-
+
#Finally, attach any images that have been specified
IMPORT_PRODUCT_SETTINGS[:image_fields].each do |field|
find_and_attach_image_to(product, params_hash[field.to_sym])
end
-
+
if IMPORT_PRODUCT_SETTINGS[:multi_domain_importing] && product.respond_to?(:stores)
begin
store = Store.find(
- :first,
- :conditions => ["id = ? OR code = ?",
- params_hash[IMPORT_PRODUCT_SETTINGS[:store_field]],
+ :first,
+ :conditions => ["id = ? OR code = ?",
+ params_hash[IMPORT_PRODUCT_SETTINGS[:store_field]],
params_hash[IMPORT_PRODUCT_SETTINGS[:store_field]]
]
)
-
+
product.stores << store
rescue
log("#{product.name} could not be associated with a store. Ensure that Spree's multi_domain extension is installed and that fields are mapped to the CSV correctly.")
end
end
-
+
#Log a success message
log("#{product.name} successfully imported.\n")
end
return true
end
-
+
# get_column_mappings
# This method attempts to automatically map headings in the CSV files
# with fields in the product and variant models.
# If the headings of columns are going to be called something other than this,
# or if the files will not have headings, then the manual initializer
- # mapping of columns must be used.
+ # mapping of columns must be used.
# Row is an array of headings for columns - SKU, Master Price, etc.)
# @return a hash of symbol heading => column index pairs
def get_column_mappings(row)
@@ -226,8 +228,8 @@ def get_column_mappings(row)
end
mappings
end
-
-
+
+
### MISC HELPERS ####
#Log a message to a file - logs in standard Rails format to logfile set up in the import_products initializer
@@ -245,11 +247,11 @@ def log(message, severity = :info)
### IMAGE HELPERS ###
# find_and_attach_image_to
- # This method attaches images to products. The images may come
+ # This method attaches images to products. The images may come
# from a local source (i.e. on disk), or they may be online (HTTP/HTTPS).
def find_and_attach_image_to(product_or_variant, filename)
return if filename.blank?
-
+
#The image can be fetched from an HTTP or local source - either method returns a Tempfile
file = filename =~ /\Ahttp[s]*:\/\// ? fetch_remote_image(filename) : fetch_local_image(filename)
#An image has an attachment (the image file) and some object which 'views' it
@@ -295,32 +297,45 @@ def fetch_remote_image(filename)
# associate_product_with_taxon
# This method accepts three formats of taxon hierarchy strings which will
# associate the given products with taxons:
- # 1. A string on it's own will will just find or create the taxon and
+ # 1. A string on it's own will will just find or create the taxon and
# add the product to it. e.g. taxonomy = "Category", taxon_hierarchy = "Tools" will
# add the product to the 'Tools' category.
# 2. A item > item > item structured string will read this like a tree - allowing
- # a particular taxon to be picked out
+ # a particular taxon to be picked out
# 3. An item > item & item > item will work as above, but will associate multiple
- # taxons with that product. This form should also work with format 1.
+ # taxons with that product. This form should also work with format 1.
def associate_product_with_taxon(product, taxonomy, taxon_hierarchy)
return if product.nil? || taxonomy.nil? || taxon_hierarchy.nil?
- #Using find_or_create_by_name is more elegant, but our magical params code automatically downcases
+ #Using find_or_create_by_name is more elegant, but our magical params code automatically downcases
# the taxonomy name, so unless we are using MySQL, this isn't going to work.
taxonomy_name = taxonomy
taxonomy = Taxonomy.find(:first, :conditions => ["lower(name) = ?", taxonomy])
taxonomy = Taxonomy.create(:name => taxonomy_name.capitalize) if taxonomy.nil? && IMPORT_PRODUCT_SETTINGS[:create_missing_taxonomies]
-
+
taxon_hierarchy.split(/\s*\&\s*/).each do |hierarchy|
hierarchy = hierarchy.split(/\s*>\s*/)
last_taxon = taxonomy.root
hierarchy.each do |taxon|
last_taxon = last_taxon.children.find_or_create_by_name_and_taxonomy_id(taxon, taxonomy.id)
end
-
+
#Spree only needs to know the most detailed taxonomy item
product.taxons << last_taxon unless product.taxons.include?(last_taxon)
end
end
### END TAXON HELPERS ###
+
+ # May be implemented via decorator if useful:
+ #
+ # ProductImport.class_eval do
+ #
+ # private
+ #
+ # def after_product_built(product, params_hash)
+ # # so something with the product
+ # end
+ # end
+ def after_product_built(product, params_hash)
+ end
end

0 comments on commit ad6c61c

Please sign in to comment.