iPhone Backorder Status

Ruby TechStuff Apple

Fri Jul 18 09:08:00 -0700 2008

UPDATE (20080729): AT&T put a captcha on the order status page, so the script below no longer works. It was fun while it lasted.

Lots of people ordered iPhones at AT&T locations under the Direct Fulfillment method, and we are getting anxious. They are shipping out, but in more of a trickle than a flood. I found a forum of other people who are just as neurotic about it as I am, which makes me feel a little better. This time last week was the Day Of The iPhone Launch, and I was like a kid on Christmas morning. I could Not Sit Still.

So now we wait.

Someone on the forum whipped up a screen scraping script that would tell you how the orders for the store you placed your order is fairing. We brought his server down. He came up with another version of the page, which is here.

I also decided to whip up a quick and dirty ruby script that does the same thing. I called it att.rb on my compy.

UPDATE: fixed some formatting with the code vs blog markup and added the queue. UPDATE 2: redid code to be a little more ruby and a lot less perl. UPDATE 3: Added better reporting on cancel status.

#!/usr/local/bin/ruby
require 'rubygems'
require 'open-uri'
require 'openssl'
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE

ORDER_NUMBER_LOWER_LIMIT = 15183
ORDER_NUMBER_UPPER_LIMIT = 15270
ZIPCODE = 12345
queue = 0

class OrderStatus
  attr_accessor :response

  def initialize(response)
    self.response = response
  end

  def nil?
    err = self.response.scan("We're sorry, but the information you entered was not").to_s
    err.empty? == true ? false : true
  end

  def canceled?
    cancel = self.response.scan("Canceled")[0].to_s
    cancel.empty? == true ? false : true
  end

  def name
    name = self.response.scan(/Customer:\s*\w*/).to_s
    name.gsub!(/Customer:\s*/, "")
  end

  def order
    order = self.response.scan(/Order Number:\s*\w*/).to_s
    order.gsub!(/Order Number:\s*/, "")
  end

  def date
    date = self.response.scan(/Date Ordered:.*/).to_s
    date.gsub!(/Date Ordered:\s*/, "")
    date.gsub!(/\s/, "")
  end

  def ship_date
    ship_date = self.response.scan(/\<td width="6%".*/)[5]
    ship_date.remove_p_tag
  end

  def shipped
    shipped = self.response.scan(/\<td width="5%".*/)[3].scan(/[01]/).to_s.to_i
  end

  def ship_info
    ship_info = self.response.scan(/\<td width="6%".*/)[7]
    ship_info.remove_p_tag
  end

  def display(q)
    "#{name.slice(0..20).ljust(20)} | #{order} | #{date} | #{shipped} | #{q.rjust(2)} | #{ship_date} #{ship_info}"    
  end
end

class String
  # add this to the String class to help clean up some cruft
  def remove_p_tag
    self.gsub!(/^.*\<p\>/, "")
    self.gsub!(/\<\/p\>.*$/, "")
  end
end

puts "Name                 | Order | Order Dt |Yn | Qu | Ship Info     "
for order_number in ORDER_NUMBER_LOWER_LIMIT..ORDER_NUMBER_UPPER_LIMIT
  @url = "https://www.wireless.att.com/order_status/order_status_results.jsp?fromwhere=order_status&vMethod=ordernum&vNumber=#{order_number}&ZipCode=#{ZIPCODE}&x=48&y=6"

  # open-uri RDoc: http://stdlib.rubyonrails.org/libdoc/open-uri/rdoc/index.html
  open( @url,
        "User-Agent" => "Ruby/#{RUBY_VERSION}",
        "From" => "email@addr.com",
        "Referer" => "https://www.wireless.att.com/order_status") { |f|
      # Save the response body
      stat = OrderStatus.new(f.read)
      if stat.canceled?
        puts "#{order_number} canceled"
      elsif !stat.nil?
        # calculate the queue
        queue += 1 if stat.shipped == 0
        display_queue = stat.shipped == 0 ? queue.to_s : ""
  
        # display the info
        puts stat.display(display_queue)
      else
        puts "#{order_number} not found"
      end
  }
end

It could be a lot prettier, but it works. It will also hopefully take some of the load off the webserver since you can just run this on your local mac. You’ve got ruby on it already, although it may not be in /usr/local/bin. If it doesn’t run, you can take out that shebang line and just run the script like this:

ruby att.rb

There you have it. Good luck to all of us.

blog comments powered by Disqus