lib/loaders/spree/shopify_order_migrator.rb
def perform_excel_load( file_name, options = {} )

        # Spree 2 Checkout/Order states

        #       go_to_state :address
        #       go_to_state :delivery
        #       go_to_state :payment, if: ->(order) { order.payment_required? }
        #       go_to_state :confirm, if: ->(order) { order.confirmation_required? }
        #       go_to_state :complete

        Spree::Order.class_eval do

          checkout_flow do
            go_to_state :address
            go_to_state :complete
          end


          def confirmation_required?
            false;
          end

          def payment_required?
            false;
          end
        end

        line_item_rows = 0

        start_excel(file_name, options)

        begin
          puts "Dummy Run - Changes will be rolled back" if options[:dummy]

          load_object_class.transaction do

            Spree::Config[:track_inventory_levels] = false

            @sheet.each_with_index do |row, i|

              current_row_idx = i
              @current_row = row

              next if(i == header_row_index)

              # This required in some circumstances where each_with_index keeps going
              # so need to manually detect when actual data ends, so quit once we hit the first completely empty row
              if(row.nil? || row.compact.empty?)
                puts "Finished - Last Row #{current_row_idx} : #{row}"
                break
              end

              logger.info "Processing Row #{current_row_idx} : #{row}"

              @reporter.processed_object_count += 1

              # The spreadsheet contains some lines that are LineItems only for previous Order row
              if(!row[0].nil? && !row[0].empty?) && (row[2].nil? || row[2].empty?)   # Financial Status empty on LI rows

                puts("START processing Line Item Only #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}")

                line_item_rows += 1

                if(load_object && load_object.id.nil?)
                  logger.warn "No parent Order for Line Item Only row"
                  next
                end

                logger.info "Line Item Only - add row to current Order : #{load_object.id} : #{load_object.number}"

                begin
                  process_line_item( row, load_object )

                  @reporter.success_inbound_count += 1

                rescue => e
                  process_excel_failure(e, false)
                end

                next  # row contains NO OTHER data

              else
                finish if(load_object.id)    # Ok we have added all Line Items - now complete existing order

                new_load_object   # Main Order row, create new Spree::Order
              end


              # A real Order row, not just LineItem

              logger.info("Start processing new Order from row #{current_row_idx}")

              puts("START processing new Order from row #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}")

              begin
                # We are loading/migrating data - ensure emails not sent
                load_object.confirmation_delivered = true

                @total_idx ||= excel_headers.index('total' )
                @shipment_total_idx ||= excel_headers.index('shipment_total' )
                @additional_tax_total_idx ||= excel_headers.index('additional_tax_total' )
                @payment_total_idx ||= excel_headers.index('payment_total' )
                @promo_total_idx ||= excel_headers.index('promo_total' )

                @payment_state_idx ||= excel_headers.index('payment_state' )
                @shipment_state_idx ||= excel_headers.index('shipment_state' )

                @completed_at_idx ||= excel_headers.index('completed_at' )
                @paid_at_idx ||= excel_headers.index('Paid at' )
                @created_at_idx ||= excel_headers.index('Created at')

                @item_count_idx ||= excel_headers.index('item_count' )

                @shipping_method_idx ||= excel_headers.index("shipping_method:name")


                shipment_state = @current_row[@shipment_state_idx]
                payment_state =  @current_row[@payment_state_idx]

                if(payment_state == 'refunded' && shipment_state == 'pending')
                  new_load_object
                  next
                end

                load_object.shipment_state = shipment_state

                load_object.payment_state = payment_state


                #number	Email	payment_state	Paid at	shipment_state	completed_at	Accepts Marketing	Currency
                #	Discount Code	promo_total	shipping_method:name	Created at	item_count	Lineitem name	Lineitem price	Lineitem compare at price	LineItems sku	Lineitem requires shipping	Lineitem taxable	LineItems fulfillment status	Billing Name	Billing Street	bill_address:address1	Billing Address2	Billing Company	Billing City	Billing Zip	Billing Province	Billing Country	Billing Phone	Shipping Name	Shipping Street	ship_address:address1	Shipping Address2	Shipping Company	Shipping City	Shipping Zip	Shipping Province	Shipping Country	Shipping Phone	Notes	Note Attributes	Cancelled at	Payment Method	Payment Reference	Refunded Amount	Vendor	Id	Tags	Risk Level	Source	Lineitem discount

                load_object.number = @current_row[0]
                load_object.email = @current_row[1]
                load_object.currency = @current_row[7]

                load_object.item_count = row[@item_count_idx].to_f

                load_object.id = nil if(load_object.id == 0)   # why the hell is this 0 happening !?

                # We are loading/migrating data - try to ensure emails not sent
                load_object.confirmation_delivered = true

                save

                puts("Saved Order #{load_object.number} [#{load_object.id}]")

                logger.info("Saved Order #{load_object.number} [#{load_object.id}]")

                begin
                  logger.info("Order #{load_object.number} - Assigning User with email [#{row[1]}]")

                  user = Spree.user_class.where( :email =>  @current_row[1] ).first

                  if(user)
                    logger.info("Found User [#{row[1]}] - assign to #{load_object.number} (#{load_object.id}) ")
                    load_object.associate_user!(user)

                    # The user usually has address information attached so pull it if the order has no prepopulated addresses
                    load_object.ship_address = load_object.user.ship_address unless load_object.ship_address
                    load_object.bill_address = load_object.user.bill_address unless load_object.bill_address
                  end

                  def warn_no_address missing_obj
                    logger.warn("No #{missing_obj} Address info for Order #{load_object.number} (#{load_object.id})")

                    load_object.ship_address = nil
                    load_object.bill_address = nil
                  end

                  if(load_object.bill_address.nil? and load_object.ship_address.nil?)
                    warn_no_address "ship and bill"
                  elsif(load_object.ship_address.nil?)
                    if(load_object.bill_address.id.nil?)
                      warn_no_address "ship and bill id"
                    else
                      load_object.clone_billing_address
                    end
                  elsif(load_object.bill_address.nil?)
                    if(load_object.ship_address.id.nil?)
                      warn_no_address "bill and ship id"
                    else
                      load_object.bill_address.attributes = load_object.ship_address.attributes.except('id', 'updated_at', 'created_at')
                    end
                  elsif(load_object.bill_address.id.nil? and load_object.ship_address.nil?)
                    warn_no_address "bill id and ship id"
                  end

                rescue => e
                  logger.error("Error assigning User #{e.inspect}")
                  logger.warn("Could not assign User #{row[1]} to Order #{load_object.number}")
                end

                unless(load_object.valid?)
                  logger.info("INVALID ADDRESS - Order still Invalid #{load_object.inspect}")
                  logger.info("Valid Order #{load_object.valid?}")
                  puts "Row  #{current_row_idx} invalid  #{load_object.errors.full_messages.inspect}"
                  load_object.id = nil if(load_object.id == 0)   # why the hell is this 0 happening !?
                end

                begin
                  # make sure we also process the main Order rows, LineItem
                  process_line_item( row, load_object )
                  load_object.next!
                rescue => x    # logged already
                  puts "Issue assigning LineItem #{x.inspect}"
                end


                shipping_method = Spree::ShippingMethod.where( name:  @current_row[@shipping_method_idx]).first

                load_object.shipping_method_id = shipping_method.id if(shipping_method)

                load_object.completed_at = @current_row[@completed_at_idx].blank? ? @current_row[@paid_at_idx] : @current_row[@completed_at_idx]

                if(load_object.completed_at.blank?)
                  puts "No suitable completed_at date - using Created at #{@current_row[@created_at_idx]}"

                  load_object.completed_at = @current_row[@created_at_idx]
                end

                load_object.shipment_total = row[@shipment_total_idx].to_f
                load_object.promo_total = row[@promo_total_idx].to_f
                load_object.total = row[@total_idx].to_f

                load_object.id = nil if(load_object.id == 0)   # why the hell is this 0 happening !?

                save_and_report

              rescue => e
                puts "Save Failed #{e.inspect}"
                process_excel_failure(e)
                next
              end

            end   # all rows processed

            # double check the last Order
            finish

            if(options[:dummy])
              puts "Excel loading stage complete - Dummy run so Rolling Back."
              raise ActiveRecord::Rollback # Don't actually create/upload to DB if we are doing dummy run
            end

          end   # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block

        rescue => e
          puts "ERROR: Excel loading failed : #{e.inspect}"
          raise e
        ensure
          report
        end

        puts "Line Item only row count : #{line_item_rows}"
      end
# Options
#
#  :reload           : Force load of the method dictionary for object_class even if already loaded
#  :verbose          : Verbose logging and to STDOUT
#
Options
:reload           : Force load of the method dictionary for object_class even if already loaded
:verbose          : Verbose logging and to STDOUT
Options : reload : Force load of the method dictionary for object_class even if already loaded : verbose : Verbose logging and to STDOUT
def perform_excel_load( file_name, options = {} )
        Spree::Order.class_eval do
          checkout_flow do
            go_to_state :address
            go_to_state :complete
          end
          def confirmation_required?
            false;
          end
          def payment_required?
            false;
          end
        end
        line_item_rows = 0
        start_excel(file_name, options)
        begin
          puts "Dummy Run - Changes will be rolled back" if options[:dummy]
          load_object_class.transaction do
            Spree::Config[:track_inventory_levels] = false
            @sheet.each_with_index do |row, i|
              current_row_idx = i
              @current_row = row
              next if(i == header_row_index)
              if(row.nil? || row.compact.empty?)
                puts "Finished - Last Row #{current_row_idx} : #{row}"
                break
              end
              logger.info "Processing Row #{current_row_idx} : #{row}"
              @reporter.processed_object_count += 1
              if(!row[0].nil? && !row[0].empty?) && (row[2].nil? || row[2].empty?)   
                puts("START processing Line Item Only #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}")
                line_item_rows += 1
                if(load_object && load_object.id.nil?)
                  logger.warn "No parent Order for Line Item Only row"
                  next
                end
                logger.info "Line Item Only - add row to current Order : #{load_object.id} : #{load_object.number}"
                begin
                  process_line_item( row, load_object )
                  @reporter.success_inbound_count += 1
                rescue => e
                  process_excel_failure(e, false)
                end
                next  
              else
                finish if(load_object.id)    
                new_load_object   
              end
              logger.info("Start processing new Order from row #{current_row_idx}")
              puts("START processing new Order from row #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}")
              begin
                load_object.confirmation_delivered = true
                @total_idx ||= excel_headers.index('total' )
                @shipment_total_idx ||= excel_headers.index('shipment_total' )
                @additional_tax_total_idx ||= excel_headers.index('additional_tax_total' )
                @payment_total_idx ||= excel_headers.index('payment_total' )
                @promo_total_idx ||= excel_headers.index('promo_total' )
                @payment_state_idx ||= excel_headers.index('payment_state' )
                @shipment_state_idx ||= excel_headers.index('shipment_state' )
                @completed_at_idx ||= excel_headers.index('completed_at' )
                @paid_at_idx ||= excel_headers.index('Paid at' )
                @created_at_idx ||= excel_headers.index('Created at')
                @item_count_idx ||= excel_headers.index('item_count' )
                @shipping_method_idx ||= excel_headers.index("shipping_method:name")
                shipment_state = @current_row[@shipment_state_idx]
                payment_state =  @current_row[@payment_state_idx]
                if(payment_state == 'refunded' && shipment_state == 'pending')
                  new_load_object
                  next
                end
                load_object.shipment_state = shipment_state
                load_object.payment_state = payment_state
                load_object.number = @current_row[0]
                load_object.email = @current_row[1]
                load_object.currency = @current_row[7]
                load_object.item_count = row[@item_count_idx].to_f
                load_object.id = nil if(load_object.id == 0)   
                load_object.confirmation_delivered = true
                save
                puts("Saved Order #{load_object.number} [#{load_object.id}]")
                logger.info("Saved Order #{load_object.number} [#{load_object.id}]")
                begin
                  logger.info("Order #{load_object.number} - Assigning User with email [#{row[1]}]")
                  user = Spree.user_class.where( :email =>  @current_row[1] ).first
                  if(user)
                    logger.info("Found User [#{row[1]}] - assign to #{load_object.number} (#{load_object.id}) ")
                    load_object.associate_user!(user)
                    load_object.ship_address = load_object.user.ship_address unless load_object.ship_address
                    load_object.bill_address = load_object.user.bill_address unless load_object.bill_address
                  end
                  def warn_no_address missing_obj
                    logger.warn("No #{missing_obj} Address info for Order #{load_object.number} (#{load_object.id})")
                    load_object.ship_address = nil
                    load_object.bill_address = nil
                  end
                  if(load_object.bill_address.nil? and load_object.ship_address.nil?)
                    warn_no_address "ship and bill"
                  elsif(load_object.ship_address.nil?)
                    if(load_object.bill_address.id.nil?)
                      warn_no_address "ship and bill id"
                    else
                      load_object.clone_billing_address
                    end
                  elsif(load_object.bill_address.nil?)
                    if(load_object.ship_address.id.nil?)
                      warn_no_address "bill and ship id"
                    else
                      load_object.bill_address.attributes = load_object.ship_address.attributes.except('id', 'updated_at', 'created_at')
                    end
                  elsif(load_object.bill_address.id.nil? and load_object.ship_address.nil?)
                    warn_no_address "bill id and ship id"
                  end
                rescue => e
                  logger.error("Error assigning User #{e.inspect}")
                  logger.warn("Could not assign User #{row[1]} to Order #{load_object.number}")
                end
                unless(load_object.valid?)
                  logger.info("INVALID ADDRESS - Order still Invalid #{load_object.inspect}")
                  logger.info("Valid Order #{load_object.valid?}")
                  puts "Row  #{current_row_idx} invalid  #{load_object.errors.full_messages.inspect}"
                  load_object.id = nil if(load_object.id == 0)   
                end
                begin
                  process_line_item( row, load_object )
                  load_object.next!
                rescue => x    
                  puts "Issue assigning LineItem #{x.inspect}"
                end
                shipping_method = Spree::ShippingMethod.where( name:  @current_row[@shipping_method_idx]).first
                load_object.shipping_method_id = shipping_method.id if(shipping_method)
                load_object.completed_at = @current_row[@completed_at_idx].blank? ? @current_row[@paid_at_idx] : @current_row[@completed_at_idx]
                if(load_object.completed_at.blank?)
                  puts "No suitable completed_at date - using Created at #{@current_row[@created_at_idx]}"
                  load_object.completed_at = @current_row[@created_at_idx]
                end
                load_object.shipment_total = row[@shipment_total_idx].to_f
                load_object.promo_total = row[@promo_total_idx].to_f
                load_object.total = row[@total_idx].to_f
                load_object.id = nil if(load_object.id == 0)   
                save_and_report
              rescue => e
                puts "Save Failed #{e.inspect}"
                process_excel_failure(e)
                next
              end
            end   
            finish
            if(options[:dummy])
              puts "Excel loading stage complete - Dummy run so Rolling Back."
              raise ActiveRecord::Rollback 
            end
          end   
        rescue => e
          puts "ERROR: Excel loading failed : #{e.inspect}"
          raise e
        ensure
          report
        end
        puts "Line Item only row count : #{line_item_rows}"
      end
def perform_excel_load ( file_name , options = { } ) Spree :: Order . class_eval do checkout_flow do go_to_state :address go_to_state :complete end def confirmation_required? false ; end def payment_required? false ; end end line_item_rows = 0 start_excel ( file_name , options ) begin puts "Dummy Run - Changes will be rolled back" if options [ :dummy ] load_object_class . transaction do Spree :: Config [ :track_inventory_levels ] = false @sheet . each_with_index do | row , i | current_row_idx = i @current_row = row next if ( i == header_row_index ) if ( row . nil? || row . compact . empty? ) puts "Finished - Last Row #{current_row_idx} : #{row}" break end logger . info "Processing Row #{current_row_idx} : #{row}" @reporter . processed_object_count += 1 if ( ! row [ 0 ] . nil? && ! row [ 0 ] . empty? ) && ( row [ 2 ] . nil? || row [ 2 ] . empty? ) puts ( "START processing Line Item Only #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}" ) line_item_rows += 1 if ( load_object && load_object . id . nil? ) logger . warn "No parent Order for Line Item Only row" next end logger . info "Line Item Only - add row to current Order : #{load_object.id} : #{load_object.number}" begin process_line_item ( row , load_object ) @reporter . success_inbound_count += 1 rescue => e process_excel_failure ( e , false ) end next else finish if ( load_object . id ) new_load_object end logger . info ( "Start processing new Order from row #{current_row_idx}" ) puts ( "START processing new Order from row #{current_row_idx} - #{row[0]} - #{row[17]} - #{row[16]}  -#{row[18]}" ) begin load_object . confirmation_delivered = true @total_idx ||= excel_headers . index ( 'total' ) @shipment_total_idx ||= excel_headers . index ( 'shipment_total' ) @additional_tax_total_idx ||= excel_headers . index ( 'additional_tax_total' ) @payment_total_idx ||= excel_headers . index ( 'payment_total' ) @promo_total_idx ||= excel_headers . index ( 'promo_total' ) @payment_state_idx ||= excel_headers . index ( 'payment_state' ) @shipment_state_idx ||= excel_headers . index ( 'shipment_state' ) @completed_at_idx ||= excel_headers . index ( 'completed_at' ) @paid_at_idx ||= excel_headers . index ( 'Paid at' ) @created_at_idx ||= excel_headers . index ( 'Created at' ) @item_count_idx ||= excel_headers . index ( 'item_count' ) @shipping_method_idx ||= excel_headers . index ( "shipping_method:name" ) shipment_state = @current_row [ @shipment_state_idx ] payment_state = @current_row [ @payment_state_idx ] if ( payment_state == 'refunded' && shipment_state == 'pending' ) new_load_object next end load_object . shipment_state = shipment_state load_object . payment_state = payment_state load_object . number = @current_row [ 0 ] load_object . email = @current_row [ 1 ] load_object . currency = @current_row [ 7 ] load_object . item_count = row [ @item_count_idx ] . to_f load_object . id = nil if ( load_object . id == 0 ) load_object . confirmation_delivered = true save puts ( "Saved Order #{load_object.number} [#{load_object.id}]" ) logger . info ( "Saved Order #{load_object.number} [#{load_object.id}]" ) begin logger . info ( "Order #{load_object.number} - Assigning User with email [#{row[1]}]" ) user = Spree . user_class . where ( :email => @current_row [ 1 ] ) . first if ( user ) logger . info ( "Found User [#{row[1]}] - assign to #{load_object.number} (#{load_object.id}) " ) load_object . associate_user! ( user ) load_object . ship_address = load_object . user . ship_address unless load_object . ship_address load_object . bill_address = load_object . user . bill_address unless load_object . bill_address end def warn_no_address missing_obj logger . warn ( "No #{missing_obj} Address info for Order #{load_object.number} (#{load_object.id})" ) load_object . ship_address = nil load_object . bill_address = nil end if ( load_object . bill_address . nil? and load_object . ship_address . nil? ) warn_no_address "ship and bill" elsif ( load_object . ship_address . nil? ) if ( load_object . bill_address . id . nil? ) warn_no_address "ship and bill id" else load_object . clone_billing_address end elsif ( load_object . bill_address . nil? ) if ( load_object . ship_address . id . nil? ) warn_no_address "bill and ship id" else load_object . bill_address . attributes = load_object . ship_address . attributes . except ( 'id' , 'updated_at' , 'created_at' ) end elsif ( load_object . bill_address . id . nil? and load_object . ship_address . nil? ) warn_no_address "bill id and ship id" end rescue => e logger . error ( "Error assigning User #{e.inspect}" ) logger . warn ( "Could not assign User #{row[1]} to Order #{load_object.number}" ) end unless ( load_object . valid? ) logger . info ( "INVALID ADDRESS - Order still Invalid #{load_object.inspect}" ) logger . info ( "Valid Order #{load_object.valid?}" ) puts "Row  #{current_row_idx} invalid  #{load_object.errors.full_messages.inspect}" load_object . id = nil if ( load_object . id == 0 ) end begin process_line_item ( row , load_object ) load_object . next! rescue => x puts "Issue assigning LineItem #{x.inspect}" end shipping_method = Spree :: ShippingMethod . where ( name : @current_row [ @shipping_method_idx ] ) . first load_object . shipping_method_id = shipping_method . id if ( shipping_method ) load_object . completed_at = @current_row [ @completed_at_idx ] . blank? ? @current_row [ @paid_at_idx ] : @current_row [ @completed_at_idx ] if ( load_object . completed_at . blank? ) puts "No suitable completed_at date - using Created at #{@current_row[@created_at_idx]}" load_object . completed_at = @current_row [ @created_at_idx ] end load_object . shipment_total = row [ @shipment_total_idx ] . to_f load_object . promo_total = row [ @promo_total_idx ] . to_f load_object . total = row [ @total_idx ] . to_f load_object . id = nil if ( load_object . id == 0 ) save_and_report rescue => e puts "Save Failed #{e.inspect}" process_excel_failure ( e ) next end end finish if ( options [ :dummy ] ) puts "Excel loading stage complete - Dummy run so Rolling Back." raise ActiveRecord :: Rollback end end rescue => e puts "ERROR: Excel loading failed : #{e.inspect}" raise e ensure report end puts "Line Item only row count : #{line_item_rows}" end
Options
:reload           : Force load of the method dictionary for object_class even if already loaded
:verbose          : Verbose logging and to STDOUT
Options : reload : Force load of the method dictionary for object_class even if already loaded : verbose : Verbose logging and to STDOUT
# Spree 2 Checkout/Order states #       go_to_state :address #       go_to_state :delivery #       go_to_state :payment, if: ->(order) { order.payment_required? } #       go_to_state :confirm, if: ->(order) { order.confirmation_required? } #       go_to_state :complete # This required in some circumstances where each_with_index keeps going # so need to manually detect when actual data ends, so quit once we hit the first completely empty row # The spreadsheet contains some lines that are LineItems only for previous Order row # Financial Status empty on LI rows # row contains NO OTHER data # Ok we have added all Line Items - now complete existing order # Main Order row, create new Spree::Order # A real Order row, not just LineItem # We are loading/migrating data - ensure emails not sent #number	Email	payment_state	Paid at	shipment_state	completed_at	Accepts Marketing	Currency #	Discount Code	promo_total	shipping_method:name	Created at	item_count	Lineitem name	Lineitem price	Lineitem compare at price	LineItems sku	Lineitem requires shipping	Lineitem taxable	LineItems fulfillment status	Billing Name	Billing Street	bill_address:address1	Billing Address2	Billing Company	Billing City	Billing Zip	Billing Province	Billing Country	Billing Phone	Shipping Name	Shipping Street	ship_address:address1	Shipping Address2	Shipping Company	Shipping City	Shipping Zip	Shipping Province	Shipping Country	Shipping Phone	Notes	Note Attributes	Cancelled at	Payment Method	Payment Reference	Refunded Amount	Vendor	Id	Tags	Risk Level	Source	Lineitem discount # why the hell is this 0 happening !? # We are loading/migrating data - try to ensure emails not sent # The user usually has address information attached so pull it if the order has no prepopulated addresses # why the hell is this 0 happening !? # make sure we also process the main Order rows, LineItem # logged already # why the hell is this 0 happening !? # all rows processed # double check the last Order # Don't actually create/upload to DB if we are doing dummy run # TRANSACTION N.B ActiveRecord::Rollback does not propagate outside of the containing transaction block
file_name
options