Created
June 15, 2009 11:46
-
-
Save paulcc/130061 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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