Skip to content

Instantly share code, notes, and snippets.

@paulcc
Created June 15, 2009 11:46
Show Gist options
  • Save paulcc/130061 to your computer and use it in GitHub Desktop.
Save paulcc/130061 to your computer and use it in GitHub Desktop.
require "csv"
require 'action_controller/test_process'
file = `ls upload/*.csv | grep -v and-r`.chomp
info = CSV.read(ARGV.first || file)
info.shift
# TODO: set this list by eliminating the expected cols
properties = %w[Colour Material Size Weight Warranty] + ["Pole Diameter", "Fits Pole Size"]
# expect these fields
fields = properties + ["SKU","Product Name","Product Details","List Price","Sale Price","Delivery Cost","Delivery Information","Image File Name","Taxon info","Features", "Commercial Product", "Format"]
# set up convenient name mapping
$names = {}
info.first.each_with_index { |v,i| $names[v] = i }
unless $names.keys.all? {|n| fields.include?(n) }
puts $names.keys.reject {|n| fields.include?(n) }.inspect
raise "funny names"
end
$main = []
$row = []
def get(n) # I would use lambda, but call syntax is ugly...
$row[$names[n]] # query: other closure-y things that would work?
end
# initial value and pattern for sku
psku = "P0000"
stop = false
# check image availability
info[1..-1].each do |line|
$row = line
next if get("Image File Name").blank?
get("Image File Name").split(',').map(&:strip).each do |file|
pick = `find upload | grep -i "/#{file}[.]"`.chomp
if pick.empty?
puts "Warning: couldn't find #{file}"
puts " Other = #{get "Image File Name"}"
stop = true
end
end
end
raise "image errors" if stop
def colour_codes(n,cs)
return {} if cs.empty?
split = cs.group_by {|col| col.slice(0,n)}.partition {|code,names| names.count == 1}
split[0] + split[1].map {|_, vs| colour_codes(n+1, vs)}.inject([]) {|old,new| old.concat new}
end
def colour_table(cs)
out = {}
no_whitespace = cs.map {|c| c.gsub(/\s+/,'') }
colour_codes(1,no_whitespace).each {|code, vals| out[vals[0]] = code}
out
end
# reformat into UL
def convert_features(txt)
return "" if txt.blank?
out = '<p>Features include:</p><ul>'
txt.lines.drop(1).each do |l|
next if l.strip.blank?
l.gsub!(/^\s*[*]/,'')
out += "<li>#{l}</li>\n"
end
out + '</ul>'
end
# split into related groups
# groups are identified by product name, ie all variants must have an empty name cell
def split(lines)
out = []
lines.each do |l|
next if l[1..100].all? &:blank? # skip sku placeholder
if l[1].blank?
out.last.push l
else
out.push [l]
end
end
out
end
# split "A=B, C=D, ..." cell into list of pairs
def decode_attributes(nm)
(get(nm) || "").split(',').map do |c|
c.strip.split /\s*=\s*/
end
end
# options in variants
colour_type = OptionType.find_or_create_by_name_and_presentation("colour", "Colour")
commercial = Taxon.find_by_name("Commercial Parasols")
# maybe better to extend via costed-options framework
####
# now process as groups of product lines
split(info[1..-1]).each do |group|
group.each do |line|
$row = line
if line == group[0]
# start of a new product group (which might not have format variants)
puts "Adding new product group #{get "Product Name"}."
$main = line
else
# merge new info with earlier info
$row = $main.zip(line).map {|o,n| n.present? ? n : o }
puts "Extending product group with format #{get "Format"}"
end
product_name = get("Product Name")
product_name += ' - ' + get("Format") unless get("Format").blank? || group.count == 1
if get("Sale Price").nil? || get("List Price").nil?
# validation won't let these fields be blank
puts "Problem with blank prices for #{product_name} -- rejecting."
next
end
if get("Delivery Cost").blank? || get("Delivery Cost") == "Free"
shipping = nil
else
shipping = ShippingCategory.find_or_create_by_name("Just #{get "Delivery Cost"}")
end
in_stock = get("Delivery Information") != "Out of stock"
# do para conversion here?
blurb = get("Product Details").strip # + convert_features(get("Features"))
psku.succ!
if ! psku.match(get "SKU")
puts " *** Sync problem with PSKU = #{psku} and #{get "SKU"} -- please check."
end
if Product.find_by_psku(psku)
puts " *** Problem with PSKU - already used for #{Product.find_by_psku(psku).inspect}"
raise "sku already taken"
end
p = Product.create :name => product_name,
:description => blurb,
:psku => psku,
:available_on => Time.zone.now,
:shipping_category => shipping
p.master_price = get("Sale Price").delete("£$,") if get("Sale Price")
p.window = Window.find_or_create_by_name(get "Delivery Information") if in_stock
p.save!
# might want to loop in future
# note: admin will need to pull hierarchies together later
taxonomy = Taxonomy.first # default to main taxonomy for now
if get("Taxon info").blank?
puts "Warning: missing taxon info for #{p.name}"
else
taxon = taxonomy.root
get("Taxon info").split(/\s*,\s*/).each do |name|
nxt = Taxon.find_or_create_by_name_and_parent_id_and_taxonomy_id(name, taxon.id, taxonomy.id)
taxon = nxt
end
p.taxons << taxon
end
if (is_commercial = get("Commercial Product")) && is_commercial.match(/yes/i)
taxons = get("Taxon info").split(/\s*,\s*/)
if taxons.count > 1
taxon = Taxon.find_or_create_by_name_and_parent_id_and_taxonomy_id(taxons.last, commercial.id, taxonomy.id)
elsif ["Parasol Bases", "Cantilever Parasols"].include taxons.first
taxon = Taxon.find_or_create_by_name_and_parent_id_and_taxonomy_id(taxons.first, commercial.id, taxonomy.id)
else
taxon = commercial
end
p.taxons << taxon
end
# create images
get("Image File Name").split(',').map(&:strip).each do |file|
pick = `find upload/* | grep -i "/#{file}[.]"`.chomp
puts "Using: ===#{pick}=== from #{file}"
next if pick.blank?
mime = "image/" + pick.match(/\w+$/).to_s
i = Image.new(:attachment => ActionController::TestUploadedFile.new(pick, mime))
i.viewable_type = "Product"
# link main image to the product
i.viewable = p
p.images << i
i.save!
end
p.save_image_sizes
properties.each do |k|
unless get(k).nil? || get(k).empty? # blank?
kp = Property.find_or_create_by_name_and_presentation(k,k)
if (k == "Colour")
the_value = decode_attributes("Colour").map(&:first).
to_sentence({:last_word_connector => " or ", :two_words_connector => " or "})
else
the_value = get k
end
ProductProperty.create :property => kp, :product => p, :value => the_value
end
end
# Colour format :: Name, Name = file_without_ext, ...
colours = decode_attributes("Colour").map do |c,f|
OptionValue.create :name => f.nil? ? "{no file}" : (f + '.jpg'),
:presentation => c,
:option_type => colour_type
end
colour_map = colour_table(colours.map(&:presentation))
colours = [nil] if colours.empty?
colours.each do |c|
vsku = p.psku
vsku += colour_map[c.presentation.gsub(/\s+/,'')] if colours.count > 1
puts "Adding variant #{vsku} -- #{c.inspect}"
v = Variant.create :product => p, :sku => vsku
v.price = get("Sale Price") ? get("Sale Price").delete("£$,") : p.master_price
v.list_price = get("List Price") ? get("List Price").delete("£$,") : p.variants.first.list_price
v.option_values << c unless c.nil?
v.save!
# PURELY for demo purposes, seed with some inventory
InventoryUnit.create_on_hand(v,20) if in_stock
# and include the variant as the singleton, and save the info
p.variants << v
p.save!
end
# register the option types used with this product
p.option_types = p.variants.map(&:option_values).flatten.map(&:option_type).uniq
p.save!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment