lib/loaders/spree/product_loader.rb
def add_options_variants

        # TODO smart column ordering to ensure always valid by time we get to associations
        begin
          save_if_new
        rescue => e
          raise ProductLoadError.new("Cannot add OptionTypes/Variants - Save failed on parent Product")
        end
        # example : mime_type:jpeg;print_type:black_white|mime_type:jpeg|mime_type:png, PDF;print_type:colour

        variants = get_each_assoc

        logger.info "add_options_variants #{variants.inspect}"

        # example line becomes :
        #   1) mime_type:jpeg|print_type:black_white
        #   2) mime_type:jpeg
        #   3) mime_type:png, PDF|print_type:colour

        variants.each do |per_variant|

          option_types = per_variant.split(Delimiters::multi_facet_delim)    # => [mime_type:jpeg, print_type:black_white]

          logger.info "add_options_variants #{option_types.inspect}"

          optiontype_vlist_map = {}

          option_types.each do |ostr|

            oname, value_str = ostr.split(Delimiters::name_value_delim)

            option_type = @@option_type_klass.where(:name => oname).first

            unless option_type
              option_type = @@option_type_klass.create( :name => oname, :presentation => oname.humanize)
              # TODO - dynamic creation should be an option

              unless option_type
                puts "WARNING: OptionType #{oname} NOT found and could not create - Not set Product"
                next
              end
              logger.info "Created missing OptionType #{option_type.inspect}"
              puts "Created missing OptionType #{option_type.inspect}"
            end

            # OptionTypes must be specified first on Product to enable Variants to be created
            # TODO - is include? very inefficient ??
            @load_object.option_types << option_type unless @load_object.option_types.include?(option_type)

            # Can be simply list of OptionTypes, some or all without values
            next unless(value_str)

            optiontype_vlist_map[option_type] = []

            # Now get the value(s) for the option e.g red,blue,green for OptType 'colour'
            optiontype_vlist_map[option_type] = value_str.split(',')
          end

          next if(optiontype_vlist_map.empty?) # only option types specified - no values

          # Now create set of Variants, some of which maybe composites
          # Find the longest set of OVs to use as base for combining with the rest
          sorted_map = optiontype_vlist_map.sort_by { |k,v| v.size }.reverse




          # [ [mime, ['pdf', 'jpeg', 'gif']], [print_type, ['black_white']] ]

          lead_option_type, lead_ovalues = sorted_map.shift
          # TODO .. benchmarking to find most efficient way to create these but ensure Product.variants list
          # populated .. currently need to call reload to ensure this (seems reqd for Spree 1/Rails 3, wasn't required b4
          lead_ovalues.each do |ovname|
            ov_list = []
            ovname.strip!
            name = ovname
            presentation = ovname.humanize
            option_type_id = lead_option_type.id

            ov = @@option_value_klass.find_or_create_by(name: name, option_type_id: option_type_id,
                presentation: presentation)
            ov_list << ov if ov

            # Process rest of array of types => values
            sorted_map.each do |ot, ovlist|
              ovlist.each do |for_composite|

                for_composite.strip!
                ov = @@option_value_klass.find_or_create_by(for_composite, ot.id, :presentation => for_composite.humanize)

                ov_list << ov if(ov)
              end
            end

            unless(ov_list.empty?)

              logger.info("Creating Variant from OptionValue(s) #{ov_list.collect(&:name).inspect}")

              i = @load_object.variants.size + 1
              variant_position = 1

              # This one line seems to works for 1.1.0 - 3.2 but not 1.0.0 - 3.1 ??
              if(SpreeHelper::version.to_f >= 1.1)
                variant = @load_object.variants.create( :price => @load_object.price,
                                                        :position => variant_position)
                variant_position += 1
                puts "Variant #{variant}"
              else
                variant = @@variant_klass.create( :product => @load_object, :price => @load_object.price)
              end

              variant.option_values << ov_list if(variant)
            end
          end

          @load_object.reload unless @load_object.new_record?
          #puts "DEBUG Load Object now has Variants : #{@load_object.variants.inspect}" if(verbose)
        end

      end
# Special case for OptionTypes as it's two stage process
# First add the possible option_types to Product, then we are able
# to define Variants on those options values.
# So to defiene a Variant :
#   1) define at least one OptionType on Product, for example Size
#   2) Provide a value for at least one of these OptionType
#   3) A composite Variant can be created by supplying a value for more than one OptionType
#       fro example Colour : Red and Size Medium
# Supported Syntax :
#  '|' seperates Variants
#
#   ';' list of option values
#  Examples :
#
#     mime_type:jpeg;print_type:black_white|mime_type:jpeg|mime_type:png, PDF;print_type:colour
#
Special case for OptionTypes as it's two stage process
First add the possible option_types to Product, then we are able
to define Variants on those options values.
So to defiene a Variant :
1) define at least one OptionType on Product, for example Size
2) Provide a value for at least one of these OptionType
3) A composite Variant can be created by supplying a value for more than one OptionType
fro example Colour : Red and Size Medium
Supported Syntax :
'|' seperates Variants

';' list of option values
Examples .


Special case for OptionTypes as it ' s two stage process First add the possible option_types to Product then we are able to define Variants on those options values . So to defiene a Variant : 1 ) define at least one OptionType on Product for example Size 2 ) Provide a value for at least one of these OptionType 3 ) A composite Variant can be created by supplying a value for more than one OptionType fro example Colour : Red and Size Medium Supported Syntax : ' | ' seperates Variants ' ; ' list of option values Examples .
def add_options_variants
        begin
          save_if_new
        rescue => e
          raise ProductLoadError.new("Cannot add OptionTypes/Variants - Save failed on parent Product")
        end
        variants = get_each_assoc
        logger.info "add_options_variants #{variants.inspect}"
        variants.each do |per_variant|
          option_types = per_variant.split(Delimiters::multi_facet_delim)    
          logger.info "add_options_variants #{option_types.inspect}"
          optiontype_vlist_map = {}
          option_types.each do |ostr|
            oname, value_str = ostr.split(Delimiters::name_value_delim)
            option_type = @@option_type_klass.where(:name => oname).first
            unless option_type
              option_type = @@option_type_klass.create( :name => oname, :presentation => oname.humanize)
              unless option_type
                puts "WARNING: OptionType #{oname} NOT found and could not create - Not set Product"
                next
              end
              logger.info "Created missing OptionType #{option_type.inspect}"
              puts "Created missing OptionType #{option_type.inspect}"
            end
            @load_object.option_types << option_type unless @load_object.option_types.include?(option_type)
            next unless(value_str)
            optiontype_vlist_map[option_type] = []
            optiontype_vlist_map[option_type] = value_str.split(',')
          end
          next if(optiontype_vlist_map.empty?) 
          sorted_map = optiontype_vlist_map.sort_by { |k,v| v.size }.reverse
          lead_option_type, lead_ovalues = sorted_map.shift
          lead_ovalues.each do |ovname|
            ov_list = []
            ovname.strip!
            name = ovname
            presentation = ovname.humanize
            option_type_id = lead_option_type.id
            ov = @@option_value_klass.find_or_create_by(name: name, option_type_id: option_type_id,
                presentation: presentation)
            ov_list << ov if ov
            sorted_map.each do |ot, ovlist|
              ovlist.each do |for_composite|
                for_composite.strip!
                ov = @@option_value_klass.find_or_create_by(for_composite, ot.id, :presentation => for_composite.humanize)
                ov_list << ov if(ov)
              end
            end
            unless(ov_list.empty?)
              logger.info("Creating Variant from OptionValue(s) #{ov_list.collect(&:name).inspect}")
              i = @load_object.variants.size + 1
              variant_position = 1
              if(SpreeHelper::version.to_f >= 1.1)
                variant = @load_object.variants.create( :price => @load_object.price,
                                                        :position => variant_position)
                variant_position += 1
                puts "Variant #{variant}"
              else
                variant = @@variant_klass.create( :product => @load_object, :price => @load_object.price)
              end
              variant.option_values << ov_list if(variant)
            end
          end
          @load_object.reload unless @load_object.new_record?
        end
      end
def add_options_variants begin save_if_new rescue => e raise ProductLoadError . new ( "Cannot add OptionTypes/Variants - Save failed on parent Product" ) end variants = get_each_assoc logger . info "add_options_variants #{variants.inspect}" variants . each do | per_variant | option_types = per_variant . split ( Delimiters :: multi_facet_delim ) logger . info "add_options_variants #{option_types.inspect}" optiontype_vlist_map = { } option_types . each do | ostr | oname , value_str = ostr . split ( Delimiters :: name_value_delim ) option_type = @@option_type_klass . where ( :name => oname ) . first unless option_type option_type = @@option_type_klass . create ( :name => oname , :presentation => oname . humanize ) unless option_type puts "WARNING: OptionType #{oname} NOT found and could not create - Not set Product" next end logger . info "Created missing OptionType #{option_type.inspect}" puts "Created missing OptionType #{option_type.inspect}" end @load_object . option_types << option_type unless @load_object . option_types . include? ( option_type ) next unless ( value_str ) optiontype_vlist_map [ option_type ] = [ ] optiontype_vlist_map [ option_type ] = value_str . split ( ',' ) end next if ( optiontype_vlist_map . empty? ) sorted_map = optiontype_vlist_map . sort_by { | k , v | v . size } . reverse lead_option_type , lead_ovalues = sorted_map . shift lead_ovalues . each do | ovname | ov_list = [ ] ovname . strip! name = ovname presentation = ovname . humanize option_type_id = lead_option_type . id ov = @@option_value_klass . find_or_create_by ( name : name , option_type_id : option_type_id , presentation : presentation ) ov_list << ov if ov sorted_map . each do | ot , ovlist | ovlist . each do | for_composite | for_composite . strip! ov = @@option_value_klass . find_or_create_by ( for_composite , ot . id , :presentation => for_composite . humanize ) ov_list << ov if ( ov ) end end unless ( ov_list . empty? ) logger . info ( "Creating Variant from OptionValue(s) #{ov_list.collect(&:name).inspect}" ) i = @load_object . variants . size + 1 variant_position = 1 if ( SpreeHelper :: version . to_f >= 1.1 ) variant = @load_object . variants . create ( :price => @load_object . price , :position => variant_position ) variant_position += 1 puts "Variant #{variant}" else variant = @@variant_klass . create ( :product => @load_object , :price => @load_object . price ) end variant . option_values << ov_list if ( variant ) end end @load_object . reload unless @load_object . new_record? end end
Special case for OptionTypes as it's two stage process
First add the possible option_types to Product, then we are able
to define Variants on those options values.
Special case for OptionTypes as it ' s two stage process First add the possible option_types to Product then we are able to define Variants on those options values .
# TODO smart column ordering to ensure always valid by time we get to associations # example : mime_type:jpeg;print_type:black_white|mime_type:jpeg|mime_type:png, PDF;print_type:colour # example line becomes : #   1) mime_type:jpeg|print_type:black_white #   2) mime_type:jpeg #   3) mime_type:png, PDF|print_type:colour # => [mime_type:jpeg, print_type:black_white] # TODO - dynamic creation should be an option # OptionTypes must be specified first on Product to enable Variants to be created # TODO - is include? very inefficient ?? # Can be simply list of OptionTypes, some or all without values # Now get the value(s) for the option e.g red,blue,green for OptType 'colour' # only option types specified - no values # Now create set of Variants, some of which maybe composites # Find the longest set of OVs to use as base for combining with the rest # [ [mime, ['pdf', 'jpeg', 'gif']], [print_type, ['black_white']] ] # TODO .. benchmarking to find most efficient way to create these but ensure Product.variants list # populated .. currently need to call reload to ensure this (seems reqd for Spree 1/Rails 3, wasn't required b4 # Process rest of array of types => values # This one line seems to works for 1.1.0 - 3.2 but not 1.0.0 - 3.1 ?? #puts "DEBUG Load Object now has Variants : #{@load_object.variants.inspect}" if(verbose)