# $Id: marketplace.rb,v 1.31 2006/08/03 16:35:30 ianmacd Exp $
module Amazon
module Search
module Exchange
# This module provides functionality for interacting with Amazon
# Marketplace.
#
module Marketplace
class Request < Amazon::Search::Request
# Exception class for bad keyword search types.
#
class KeywordSearchError < StandardError; end
# Exception class for bad zip codes.
#
class ZipcodeError < StandardError; end
# Exception class for bad geo types.
#
class GeoError < StandardError; end
# Exception class for bad area IDs.
#
class AreaIdError < StandardError; end
# Exception class for bad sort types.
#
class SortError < Amazon::Search::Request::SortError; end
# Exception class for bad index types.
#
class IndexError < StandardError; end
# Returns an Array of valid keyword search types, such as:
#
# *title*, *titledesc*
#
def Marketplace.keyword_search_types
%w[title titledesc]
end
# Returns an Array of valid geo types, such as:
#
# ship-to, ship-from
#
def Marketplace.geo_types
%w[ship-to ship-from]
end
# Returns an Array of valid sort types, such as:
#
# -startdate, startdate, +startdate,
# -enddate, enddate, -sku, sku,
# -quantity, quantity, -price, price,
# +price, -title, Title
#
def Marketplace.sort_types
%w[-startdate startdate +startdate -enddate enddate -sku sku
-quantity quantity -price price +price -title Title]
end
# Returns an Array of valid index types, such as:
#
# *marketplace*, *zshops*
#
def Marketplace.index_types
%w[marketplace zshops]
end
# Search Amazon Marketplace by keyword and return an
# Amazon::Search::Exchange::Marketplace::Response. If a block is
# supplied, that Response's @products, which is an Array of
# Amazon::Exchange::Product objects, will be passed to the block.
#
def keyword_search(seller_id, keyword, weight=HEAVY,
keyword_search=nil, browse_id=nil, zipcode=nil,
area_id=nil, geo=nil, sort=nil, index=nil, &block)
url = AWS_PREFIX + "?t=%s&MarketplaceSearch=keyword&f=xml" +
"&type=%s&dev-t=%s&keyword=%s&seller-id=%s"
type = WEIGHT[weight]
keyword = url_encode(keyword)
unless keyword_search.nil?
if keyword_search_types.include? keyword_search
url << "&keyword-search=" << keyword_search
else
raise KeywordSearchError,
"'keyword_search' must be one of %s" %
keyword_search_types.join(', ')
end
end
url << "&browse-id=" << browse_id unless browse_id.nil?
unless zipcode.nil?
if zipcode !~ /^\d{5}$/
raise ZipcodeError, "'zipcode' must be 5 digits"
end
url << "&zipcode=" << zipcode
end
unless area_id.nil? && geo.nil?
if geo.nil?
raise GeoError,
"'geo' must be specified in combination with 'area_id'"
elsif area_id.nil?
raise AreaIdError,
"'area_id' must be specified in combination with 'geo'"
elsif area_id !~ /^4000\d\d\d$/
raise AreaIdError, "area code not well formed"
elsif ! geo_types.include? geo
raise GeoError, "'geo' must be one of %s" %
geo_types.join(', ')
end
url << "&area-id=%s&geo=%s" % [area_id, geo]
end
unless index.nil?
if index_types.include? index
url << "&index=" << index
else
raise IndexError,
"'index' must be one of %s" % index_types.join(', ')
end
end
url = url % [@id, type, @token, keyword, seller_id]
unless sort.nil?
if sort_types.include? sort
url << "&sort=" << sort
else
raise SortError,
"'sort' must be one of %s" % sort_types.join(', ')
end
end
search(url, &block)
end
# Search Amazon Marketplace by listing ID and return an
# Amazon::Search::Exchange::Marketplace::Response. If a block is
# supplied, that Response's @products, which is an Array of
# Amazon::Exchange::Product objects, will be passed to the block.
#
def listing_search(seller_id, listing_id, weight=HEAVY, &block)
url = "/onca/xml3?t=%s&MarketplaceSearch=listing-id&f=xml" +
"&type=%s&dev-t=%s&listing-id=%s&seller-id=%s"
type = weight ? 'heavy' : 'lite'
search(url % [@id, type, @token, listing_id, seller_id], &block)
end
end
class Response < Amazon::Search::Exchange::Response
attr_reader :open_listings
# Parse an Amazon::Search::Exchange::Marketplace::Request and
# return an Amazon::Search::Exchange::Marketplace::Response.
#
def parse
doc = REXML::Document.new(self).elements['MarketplaceSearch']
detail_node = doc.elements['MarketplaceSearchDetails']
# populate args from top of doc
get_args(doc, detail_node)
doc = detail_node
# get the number of open listings for a Marketplace search
begin
@open_listings = doc.elements['NumberOfOpenListings'].text.to_i
raise "zero open listings returned" if @open_listings == 0
rescue NoMethodError
# Marketplace searches seem to often fail
raise SearchError, self
end
return nil if @open_listings == 0
@stream = doc.elements['ListingProductInfo']
super
self
end
private :parse
end
end
end
end
end