amazon-mws-plus 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +10 -0
- data/.project +12 -0
- data/Gemfile +13 -0
- data/README.markdown +30 -0
- data/Rakefile +50 -0
- data/amazon-mws-plus.gemspec +23 -0
- data/amazon-mws.tmproj +27 -0
- data/examples/xml/cancel_feed_submissions.xml +16 -0
- data/examples/xml/cancel_fulfillment_order.xml +6 -0
- data/examples/xml/cancel_report_requests.xml +18 -0
- data/examples/xml/create_fulfillment_order.xml +6 -0
- data/examples/xml/error.xml +10 -0
- data/examples/xml/get_feed_submission_count.xml +10 -0
- data/examples/xml/get_feed_submission_list.xml +18 -0
- data/examples/xml/get_feed_submission_list_by_next_token.xml +16 -0
- data/examples/xml/get_feed_submission_result.xml +30 -0
- data/examples/xml/get_fulfillment_order.xml +113 -0
- data/examples/xml/get_fulfillment_preview.xml +148 -0
- data/examples/xml/get_matching_product.xml +115 -0
- data/examples/xml/get_matching_product_for_id.xml +119 -0
- data/examples/xml/get_report.xml +237 -0
- data/examples/xml/get_report_count.xml +9 -0
- data/examples/xml/get_report_list.xml +17 -0
- data/examples/xml/get_report_request_count.xml +8 -0
- data/examples/xml/get_report_request_list.xml +120 -0
- data/examples/xml/get_report_request_list_by_next_token.xml +20 -0
- data/examples/xml/get_report_schedule_count.xml +10 -0
- data/examples/xml/get_report_schedule_list.xml +15 -0
- data/examples/xml/get_report_schedule_list_by_next_token.xml +15 -0
- data/examples/xml/list_all_fulfillment_orders.xml +69 -0
- data/examples/xml/list_all_fulfillment_orders_by_next_token.xml +61 -0
- data/examples/xml/manage_report_schedule.xml +14 -0
- data/examples/xml/orders_request.xml +39 -0
- data/examples/xml/request_order_items.xml +51 -0
- data/examples/xml/request_order_items_by_next_token.xml +51 -0
- data/examples/xml/request_orders.xml +43 -0
- data/examples/xml/request_orders_by_next_token.xml +69 -0
- data/examples/xml/request_report.xml +17 -0
- data/examples/xml/submit_feed.xml +14 -0
- data/examples/xml/update_report_acknowledgements.xml +18 -0
- data/examples/xsd/Inventory.xsd +49 -0
- data/examples/xsd/Item.xsd +285 -0
- data/examples/xsd/Listings.xsd +32 -0
- data/examples/xsd/OrderAcknowledgement.xsd +55 -0
- data/examples/xsd/OrderAdjustment.xsd +94 -0
- data/examples/xsd/OrderFulfillment.xsd +57 -0
- data/examples/xsd/Override.xsd +48 -0
- data/examples/xsd/Price.xsd +59 -0
- data/examples/xsd/ProcessingReport.xsd +87 -0
- data/examples/xsd/Product.xsd +220 -0
- data/examples/xsd/Product/AutoAccessory.xsd +807 -0
- data/examples/xsd/Product/Beauty.xsd +114 -0
- data/examples/xsd/Product/CE.xsd +544 -0
- data/examples/xsd/Product/CameraPhoto.xsd +2410 -0
- data/examples/xsd/Product/FoodAndBeverages.xsd +270 -0
- data/examples/xsd/Product/Gourmet.xsd +85 -0
- data/examples/xsd/Product/Health.xsd +189 -0
- data/examples/xsd/Product/Home.xsd +654 -0
- data/examples/xsd/Product/Jewelry.xsd +603 -0
- data/examples/xsd/Product/Miscellaneous.xsd +157 -0
- data/examples/xsd/Product/MusicalInstruments.xsd +853 -0
- data/examples/xsd/Product/Office.xsd +550 -0
- data/examples/xsd/Product/PetSupplies.xsd +40 -0
- data/examples/xsd/Product/ProductClothing.xsd +197 -0
- data/examples/xsd/Product/SWVG.xsd +238 -0
- data/examples/xsd/Product/Sports.xsd +308 -0
- data/examples/xsd/Product/TiresAndWheels.xsd +159 -0
- data/examples/xsd/Product/Tools.xsd +62 -0
- data/examples/xsd/Product/ToysBaby.xsd +241 -0
- data/examples/xsd/Product/Wireless.xsd +77 -0
- data/examples/xsd/ProductImage.xsd +39 -0
- data/examples/xsd/Relationship.xsd +47 -0
- data/examples/xsd/SettlementReport.xsd +158 -0
- data/examples/xsd/amzn-base.xsd +1600 -0
- data/examples/xsd/amzn-envelope.xsd +98 -0
- data/examples/xsd/amzn-header.xsd +45 -0
- data/lib/amazon-mws.rb +6 -0
- data/lib/amazon/mws.rb +69 -0
- data/lib/amazon/mws/authentication.rb +10 -0
- data/lib/amazon/mws/authentication/query_string.rb +36 -0
- data/lib/amazon/mws/authentication/signature.rb +43 -0
- data/lib/amazon/mws/base.rb +74 -0
- data/lib/amazon/mws/connection.rb +107 -0
- data/lib/amazon/mws/connection/management.rb +95 -0
- data/lib/amazon/mws/connection/request_builder.rb +67 -0
- data/lib/amazon/mws/exceptions.rb +55 -0
- data/lib/amazon/mws/lib/extensions.rb +178 -0
- data/lib/amazon/mws/lib/memoizable.rb +10 -0
- data/lib/amazon/mws/request/feed.rb +276 -0
- data/lib/amazon/mws/request/feed_builder.rb +83 -0
- data/lib/amazon/mws/request/fulfillment.rb +50 -0
- data/lib/amazon/mws/request/orders.rb +107 -0
- data/lib/amazon/mws/request/products.rb +38 -0
- data/lib/amazon/mws/request/report.rb +330 -0
- data/lib/amazon/mws/response.rb +43 -0
- data/lib/amazon/mws/response/feed/cancel_feed_submissions_response.rb +15 -0
- data/lib/amazon/mws/response/feed/get_feed_submission_count_response.rb +13 -0
- data/lib/amazon/mws/response/feed/get_feed_submission_list_by_next_token_response.rb +17 -0
- data/lib/amazon/mws/response/feed/get_feed_submission_list_response.rb +16 -0
- data/lib/amazon/mws/response/feed/get_feed_submission_result_response.rb +54 -0
- data/lib/amazon/mws/response/feed/models/feed_submission.rb +16 -0
- data/lib/amazon/mws/response/feed/submit_feed_response.rb +15 -0
- data/lib/amazon/mws/response/fulfillment_order/cancel_fulfillment_order_response.rb +11 -0
- data/lib/amazon/mws/response/fulfillment_order/create_fulfillment_order_response.rb +12 -0
- data/lib/amazon/mws/response/fulfillment_order/get_fulfillment_order_response.rb +19 -0
- data/lib/amazon/mws/response/fulfillment_order/list_all_fulfillment_orders_by_next_token_response.rb +16 -0
- data/lib/amazon/mws/response/fulfillment_order/list_all_fulfillment_orders_response.rb +15 -0
- data/lib/amazon/mws/response/fulfillment_order/models/fulfillment_address.rb +18 -0
- data/lib/amazon/mws/response/fulfillment_order/models/fulfillment_order.rb +24 -0
- data/lib/amazon/mws/response/fulfillment_order/models/fulfillment_order_item.rb +20 -0
- data/lib/amazon/mws/response/fulfillment_order/models/fulfillment_shipment.rb +18 -0
- data/lib/amazon/mws/response/fulfillment_order/models/fulfillment_shipment_item.rb +14 -0
- data/lib/amazon/mws/response/order/models/order.rb +43 -0
- data/lib/amazon/mws/response/order/models/order_item.rb +48 -0
- data/lib/amazon/mws/response/order/models/promotion_id.rb +9 -0
- data/lib/amazon/mws/response/order/request_get_order_response.rb +15 -0
- data/lib/amazon/mws/response/order/request_order_items_response.rb +25 -0
- data/lib/amazon/mws/response/order/request_orders_response.rb +28 -0
- data/lib/amazon/mws/response/product/get_matching_proudct.rb +31 -0
- data/lib/amazon/mws/response/product/models/product.rb +36 -0
- data/lib/amazon/mws/response/report/cancel_report_requests_response.rb +16 -0
- data/lib/amazon/mws/response/report/get_report_count_response.rb +13 -0
- data/lib/amazon/mws/response/report/get_report_list_response.rb +17 -0
- data/lib/amazon/mws/response/report/get_report_request_count_response.rb +13 -0
- data/lib/amazon/mws/response/report/get_report_request_list_by_next_token_response.rb +17 -0
- data/lib/amazon/mws/response/report/get_report_request_list_response.rb +17 -0
- data/lib/amazon/mws/response/report/get_report_schedule_count_response.rb +13 -0
- data/lib/amazon/mws/response/report/get_report_schedule_list_by_next_token_response.rb +17 -0
- data/lib/amazon/mws/response/report/get_report_schedule_list_response.rb +17 -0
- data/lib/amazon/mws/response/report/manage_report_schedule_response.rb +16 -0
- data/lib/amazon/mws/response/report/models/report_info.rb +16 -0
- data/lib/amazon/mws/response/report/models/report_request.rb +20 -0
- data/lib/amazon/mws/response/report/models/report_schedule.rb +13 -0
- data/lib/amazon/mws/response/report/request_report_response.rb +15 -0
- data/lib/amazon/mws/response/report/update_reports_acknowledgements_response.rb +16 -0
- data/lib/amazon/mws/response/response.rb +43 -0
- data/lib/amazon/mws/response/response_error.rb +21 -0
- data/test/connection_test.rb +14 -0
- data/test/feed_builder_test.rb +74 -0
- data/test/feed_test.rb +144 -0
- data/test/fulfillment_order.rb +49 -0
- data/test/orders_test.rb +78 -0
- data/test/products_test.rb +28 -0
- data/test/query_string_test.rb +18 -0
- data/test/report_test.rb +88 -0
- data/test/response_test.rb +172 -0
- data/test/signature_test.rb +32 -0
- data/test/test_config.yml +6 -0
- data/test/test_helper.rb +33 -0
- metadata +335 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
class Amazon::MWS::Connection
|
2
|
+
|
3
|
+
module Management #:nodoc:
|
4
|
+
=begin
|
5
|
+
def self.included(base)
|
6
|
+
base.cattr_accessor :connections
|
7
|
+
base.connections = {}
|
8
|
+
base.extend ClassMethods
|
9
|
+
end
|
10
|
+
|
11
|
+
# Manage the creation and destruction of connections for Amazon::MWS::Base and its subclasses. Connections are
|
12
|
+
# created with establish_connection!.
|
13
|
+
module ClassMethods
|
14
|
+
# Creates a new connection with which to make requests to the S3 servers for the calling class.
|
15
|
+
#
|
16
|
+
# Amazon::MWS::Base.establish_connection!(
|
17
|
+
# :access_key_id => '...',
|
18
|
+
# :secret_access_key => '...',
|
19
|
+
# :merchant_id => '...',
|
20
|
+
# :marketplace_id => '...'
|
21
|
+
# )
|
22
|
+
#
|
23
|
+
# == Required arguments
|
24
|
+
#
|
25
|
+
# * <tt>:access_key_id</tt> - The access key id for your S3 account. Provided by Amazon.
|
26
|
+
# * <tt>:secret_access_key</tt> - The secret access key for your S3 account. Provided by Amazon.
|
27
|
+
# * <tt>:merchant_id</tt>
|
28
|
+
# * <tt>:marketplace_id</tt>
|
29
|
+
#
|
30
|
+
# If any of these required arguments is missing, a MissingAccessKey exception will be raised.
|
31
|
+
#
|
32
|
+
# == Optional arguments
|
33
|
+
#
|
34
|
+
# * <tt>:server</tt> - The server to make requests to. You can use this to specify your bucket in the subdomain,
|
35
|
+
# or your own domain's cname if you are using virtual hosted buckets. Defaults to <tt>mws.amazonaws.com</tt>.
|
36
|
+
# will be implicitly set to 443, unless specified otherwise. Defaults to false.
|
37
|
+
# * <tt>:persistent</tt> - Whether to use a persistent connection to the server. Having this on provides around a two fold
|
38
|
+
# performance increase but for long running processes some firewalls may find the long lived connection suspicious and close the connection.
|
39
|
+
# If you run into connection errors, try setting <tt>:persistent</tt> to false. Defaults to false.
|
40
|
+
#
|
41
|
+
def establish_connection!(options = {})
|
42
|
+
# After you've already established the default connection, just specify
|
43
|
+
# the difference for subsequent connections
|
44
|
+
#options = default_connection.options.merge(options) if connected?
|
45
|
+
connections[connection_name] = Amazon::MWS::Connection.connect(options)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns the connection for the current class, or Base's default connection if the current class does not
|
49
|
+
# have its own connection.
|
50
|
+
#
|
51
|
+
# If not connection has been established yet, NoConnectionEstablished will be raised.
|
52
|
+
def connection
|
53
|
+
if connected?
|
54
|
+
connections[connection_name] || default_connection
|
55
|
+
else
|
56
|
+
raise Amazon::MWS::NoConnectionEstablished.new
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Returns true if a connection has been made yet.
|
61
|
+
def connected?
|
62
|
+
!connections.empty?
|
63
|
+
end
|
64
|
+
|
65
|
+
# Removes the connection for the current class. If there is no connection for the current class, the default
|
66
|
+
# connection will be removed.
|
67
|
+
def disconnect(name = connection_name)
|
68
|
+
name = default_connection unless connections.has_key?(name)
|
69
|
+
connection = connections[name]
|
70
|
+
connection.http.finish if connection.persistent?
|
71
|
+
connections.delete(name)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Clears *all* connections, from all classes, with prejudice.
|
75
|
+
def disconnect!
|
76
|
+
connections.each_key {|connection| disconnect(connection)}
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def connection_name
|
81
|
+
name
|
82
|
+
end
|
83
|
+
|
84
|
+
def default_connection_name
|
85
|
+
'Amazon::MWS::Base'
|
86
|
+
end
|
87
|
+
|
88
|
+
def default_connection
|
89
|
+
connections[default_connection_name]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
=end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Amazon::MWS::Connection
|
2
|
+
class RequestBuilder
|
3
|
+
attr_accessor :request
|
4
|
+
|
5
|
+
def initialize(verb, path, body = nil)
|
6
|
+
# Create the request object
|
7
|
+
@request = request_method(verb).new(path)
|
8
|
+
process_body(body)
|
9
|
+
end
|
10
|
+
|
11
|
+
def request_method(verb)
|
12
|
+
Net::HTTP.const_get(verb.to_s.capitalize)
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_body(body)
|
16
|
+
@request.content_length = 0 and return self if body.nil?
|
17
|
+
|
18
|
+
if body.respond_to?(:read)
|
19
|
+
@request.body_stream = body
|
20
|
+
else
|
21
|
+
@request.body = body
|
22
|
+
end
|
23
|
+
|
24
|
+
@request.content_length = body.respond_to?(:lstat) ? body.stat.size : body.size
|
25
|
+
return self
|
26
|
+
end
|
27
|
+
|
28
|
+
# For the SubmitFeed (p. 41) function, we require that you pass the Content-MD5 HTTP header,
|
29
|
+
# which contains the MD5 hash of the HTTP entity body (see Section 14.15 of RFC 2616, the HTTP/1.1
|
30
|
+
# specification), so we can check if the feed we stored for processing is bit for bit identical with what you
|
31
|
+
# sent, protecting you from corrupted descriptive or pricing product data appearing on Amazon.com.
|
32
|
+
#
|
33
|
+
#def add_host
|
34
|
+
# @request['Host'] = Amazon::MWS::DEFAULT_HOST
|
35
|
+
# return self
|
36
|
+
#end
|
37
|
+
|
38
|
+
def add_user_agent
|
39
|
+
@request['User-Agent'] = "Amazon::MWS (Language=Ruby)"
|
40
|
+
return self
|
41
|
+
end
|
42
|
+
|
43
|
+
def add_content_type
|
44
|
+
@request.content_type = "text/html; charset=iso-8859-1"
|
45
|
+
return self
|
46
|
+
end
|
47
|
+
|
48
|
+
def add_content_md5(body = "")
|
49
|
+
@request['Content-MD5'] = Base64.encode64(create_md5(body)).chomp
|
50
|
+
return self # chainable
|
51
|
+
end
|
52
|
+
|
53
|
+
# think about chaining this with process_body
|
54
|
+
def create_md5(body)
|
55
|
+
md5 = Digest::MD5.new
|
56
|
+
|
57
|
+
# stream from file or in memory?
|
58
|
+
if body.respond_to?(:read)
|
59
|
+
digest = body.each { |line| md5.update(line) }
|
60
|
+
else
|
61
|
+
digest = md5.update(body)
|
62
|
+
end
|
63
|
+
|
64
|
+
return digest.digest
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Amazon
|
2
|
+
module MWS
|
3
|
+
|
4
|
+
# Abstract super class of all Amazon::MWS exceptions
|
5
|
+
class MWSException < StandardError
|
6
|
+
end
|
7
|
+
|
8
|
+
# Abstract super class for all invalid options.
|
9
|
+
class InvalidOption < MWSException
|
10
|
+
end
|
11
|
+
|
12
|
+
class InvalidMessageType < MWSException
|
13
|
+
end
|
14
|
+
|
15
|
+
class InvalidReportType < MWSException
|
16
|
+
end
|
17
|
+
|
18
|
+
class InvalidSchedule < MWSException
|
19
|
+
end
|
20
|
+
|
21
|
+
class MissingConnectionOptions < MWSException
|
22
|
+
end
|
23
|
+
|
24
|
+
# Raised if an unrecognized option is passed when establishing a connection.
|
25
|
+
class InvalidConnectionOption < InvalidOption
|
26
|
+
def initialize(invalid_options)
|
27
|
+
message = "The following connection options are invalid: #{invalid_options.join(', ')}. " +
|
28
|
+
"The valid connection options are: #{Connection::Options::VALID_OPTIONS.join(', ')}."
|
29
|
+
super(message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Raised if either the access key id or secret access key arguments are missing when establishing a connection.
|
34
|
+
class MissingAccessKey < InvalidOption
|
35
|
+
def initialize(missing_keys)
|
36
|
+
key_list = missing_keys.map {|key| key.to_s}.join(' and the ')
|
37
|
+
super("You did not provide both required access keys. Please provide the #{key_list}.")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Raised if a request is attempted before any connections have been established.
|
42
|
+
class NoConnectionEstablished < MWSException
|
43
|
+
def initialize
|
44
|
+
super("\nPlease use Amazon::MWS::Base.establish_connection! before making API calls.")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class InvalidParams < MWSException
|
49
|
+
def initialize(params)
|
50
|
+
super("\nInvalid Params For The Request! Please Pass Correct Params #{params.inspect} to Build The Request.")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
|
4
|
+
=begin
|
5
|
+
if RUBY_VERSION >= '1.9'
|
6
|
+
def valid_utf8?
|
7
|
+
dup.force_encoding('UTF-8').valid_encoding?
|
8
|
+
end
|
9
|
+
else
|
10
|
+
def valid_utf8?
|
11
|
+
scan(Regexp.new('[^\x00-\xa0]', nil, 'u')) { |s| s.unpack('U') }
|
12
|
+
true
|
13
|
+
rescue ArgumentError
|
14
|
+
false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
=end
|
18
|
+
|
19
|
+
=begin
|
20
|
+
def to_boolean
|
21
|
+
(self == "true") ? true : false
|
22
|
+
end
|
23
|
+
=end
|
24
|
+
|
25
|
+
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to +camelize+
|
26
|
+
# is set to <tt>:lower</tt> then +camelize+ produces lowerCamelCase.
|
27
|
+
#
|
28
|
+
# +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
|
29
|
+
#
|
30
|
+
# Examples:
|
31
|
+
# "active_record".camelize # => "ActiveRecord"
|
32
|
+
# "active_record".camelize(:lower) # => "activeRecord"
|
33
|
+
# "active_record/errors".camelize # => "ActiveRecord::Errors"
|
34
|
+
# "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
|
35
|
+
def camelize(first_letter_in_uppercase = true)
|
36
|
+
if first_letter_in_uppercase
|
37
|
+
self.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
38
|
+
else
|
39
|
+
self.to_s.first.downcase + camelize(lower_case_and_underscored_word)[1..-1]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
=begin
|
44
|
+
def underscore
|
45
|
+
self.gsub(/::/, '/').
|
46
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
47
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
48
|
+
tr("-", "_").
|
49
|
+
downcase
|
50
|
+
end
|
51
|
+
=end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Hash
|
55
|
+
|
56
|
+
=begin
|
57
|
+
def self.from_query_string(string)
|
58
|
+
query = string.split(/\?/)[-1]
|
59
|
+
parts = query.split(/&|=/)
|
60
|
+
Hash[*parts]
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_query_string
|
64
|
+
self.map { |k,v| "%s=%s" % [URI.encode(k.to_s), URI.encode(v.to_s)] }.join('&') unless self.empty?
|
65
|
+
end
|
66
|
+
=end
|
67
|
+
|
68
|
+
#take keys of hash and transform those to a symbols
|
69
|
+
def self.keys_to_s(value)
|
70
|
+
return value if not value.is_a?(Hash)
|
71
|
+
hash = value.inject({}){|memo,(k,v)| memo[k.to_s] = Hash.keys_to_s(v); memo}
|
72
|
+
return hash
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
class Array
|
78
|
+
def extract_options!
|
79
|
+
last.is_a?(::Hash) ? pop : {}
|
80
|
+
end
|
81
|
+
|
82
|
+
#def to_query_string
|
83
|
+
# self.map { |k| "%s=%s" % [URI.encode(k[0].to_s), URI.encode(k[1].to_s)] }.join('&') unless self.empty?
|
84
|
+
#end
|
85
|
+
end
|
86
|
+
|
87
|
+
=begin
|
88
|
+
class Object
|
89
|
+
def returning(value)
|
90
|
+
yield(value)
|
91
|
+
value
|
92
|
+
end
|
93
|
+
end
|
94
|
+
=end
|
95
|
+
|
96
|
+
=begin
|
97
|
+
module Kernel
|
98
|
+
def __method__(depth = 0)
|
99
|
+
caller[depth][/`([^']+)'/, 1]
|
100
|
+
end if RUBY_VERSION <= '1.8.7'
|
101
|
+
|
102
|
+
def __called_from__
|
103
|
+
caller[1][/`([^']+)'/, 1]
|
104
|
+
end if RUBY_VERSION > '1.8.7'
|
105
|
+
|
106
|
+
def expirable_memoize(reload = false, storage = nil)
|
107
|
+
current_method = RUBY_VERSION > '1.8.7' ? __called_from__ : __method__(1)
|
108
|
+
storage = "@#{storage || current_method}"
|
109
|
+
if reload
|
110
|
+
instance_variable_set(storage, nil)
|
111
|
+
else
|
112
|
+
if cache = instance_variable_get(storage)
|
113
|
+
return cache
|
114
|
+
end
|
115
|
+
end
|
116
|
+
instance_variable_set(storage, yield)
|
117
|
+
end
|
118
|
+
|
119
|
+
def require_library_or_gem(library, gem_name = nil)
|
120
|
+
if RUBY_VERSION >= '1.9'
|
121
|
+
gem(gem_name || library, '>=0')
|
122
|
+
end
|
123
|
+
require library
|
124
|
+
rescue LoadError => library_not_installed
|
125
|
+
begin
|
126
|
+
require 'rubygems'
|
127
|
+
require library
|
128
|
+
rescue LoadError
|
129
|
+
raise library_not_installed
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
=end
|
134
|
+
|
135
|
+
=begin
|
136
|
+
class Class # :nodoc:
|
137
|
+
def cattr_reader(*syms)
|
138
|
+
syms.flatten.each do |sym|
|
139
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
140
|
+
unless defined? @@#{sym}
|
141
|
+
@@#{sym} = nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.#{sym}
|
145
|
+
@@#{sym}
|
146
|
+
end
|
147
|
+
|
148
|
+
def #{sym}
|
149
|
+
@@#{sym}
|
150
|
+
end
|
151
|
+
EOS
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def cattr_writer(*syms)
|
156
|
+
syms.flatten.each do |sym|
|
157
|
+
class_eval(<<-EOS, __FILE__, __LINE__)
|
158
|
+
unless defined? @@#{sym}
|
159
|
+
@@#{sym} = nil
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.#{sym}=(obj)
|
163
|
+
@@#{sym} = obj
|
164
|
+
end
|
165
|
+
|
166
|
+
def #{sym}=(obj)
|
167
|
+
@@#{sym} = obj
|
168
|
+
end
|
169
|
+
EOS
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def cattr_accessor(*syms)
|
174
|
+
cattr_reader(*syms)
|
175
|
+
cattr_writer(*syms)
|
176
|
+
end
|
177
|
+
end if Class.instance_methods(false).grep(/^cattr_(?:reader|writer|accessor)$/).empty?
|
178
|
+
=end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Memoizable
|
2
|
+
def memoize( name, cache = Hash.new )
|
3
|
+
original = "__unmemoized_#{name}__"
|
4
|
+
([Class, Module].include?(self.class) ? self : self.class).class_eval do
|
5
|
+
alias_method original, name
|
6
|
+
private original
|
7
|
+
define_method(name) { |*args| cache[args] ||= send(original, *args) }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
module Amazon
|
2
|
+
module MWS
|
3
|
+
module Feed
|
4
|
+
|
5
|
+
# Note: We do not handle flat file feed types
|
6
|
+
FEED_TYPES = {
|
7
|
+
:product_data => '_POST_PRODUCT_DATA_',
|
8
|
+
:product_relationship_data => '_POST_PRODUCT_RELATIONSHIP_DATA_',
|
9
|
+
:item_data => '_POST_ITEM_DATA_',
|
10
|
+
:product_overrides => '_POST_PRODUCT_OVERRIDES_DATA_',
|
11
|
+
:product_image_data => '_POST_PRODUCT_IMAGE_DATA_',
|
12
|
+
:product_pricing => '_POST_PRODUCT_PRICING_DATA_',
|
13
|
+
:inventory_availability => '_POST_INVENTORY_AVAILABILITY_DATA_',
|
14
|
+
:order_acknowledgement => '_POST_ORDER_ACKNOWLEDGEMENT_DATA_',
|
15
|
+
:order_fulfillment => '_POST_ORDER_FULFILLMENT_DATA_',
|
16
|
+
:payment_adjustment => '_POST_PAYMENT_ADJUSTMENT_DATA_',
|
17
|
+
:invoice_confirmation => '_POST_INVOICE_CONFIRMATION_DATA_'
|
18
|
+
# :flat_file_listings => '_POST_FLAT_FILE_LISTINGS_DATA_',
|
19
|
+
# :flat_file_order_acknowledgement => '_POST_FLAT_FILE_ORDER_ACKNOWLEDGEMENT_DATA_',
|
20
|
+
# :flat_file_fulfillment_data => '_POST_FLAT_FILE_FULFILLMENT_DATA_',
|
21
|
+
# :flat_file_payment_adjustment => '_POST_FLAT_FILE_PAYMENT_ADJUSTMENT_DATA_',
|
22
|
+
# :flat_file_invloader => '_POST_FLAT_FILE_INVLOADER_DATA_'
|
23
|
+
}
|
24
|
+
|
25
|
+
MESSAGE_TYPES = [
|
26
|
+
"FulfillmentCenter",
|
27
|
+
"Inventory",
|
28
|
+
"OrderAcknowledgement",
|
29
|
+
"OrderAdjustment",
|
30
|
+
"OrderFulfillment",
|
31
|
+
"OrderReport",
|
32
|
+
"Override",
|
33
|
+
"Price",
|
34
|
+
"ProcessingReport",
|
35
|
+
"Product",
|
36
|
+
"ProductImage",
|
37
|
+
"Relationship",
|
38
|
+
"SettlementReport",
|
39
|
+
"InvoiceConfirmation"
|
40
|
+
]
|
41
|
+
|
42
|
+
PRODUCT_MESSAGE_TYPES = [
|
43
|
+
"Product",
|
44
|
+
"Price",
|
45
|
+
"ProductImage",
|
46
|
+
"Relationship",
|
47
|
+
"Inventory"
|
48
|
+
]
|
49
|
+
|
50
|
+
PROCESSING_STATUSES = {
|
51
|
+
:submitted => '_SUBMITTED_',
|
52
|
+
:in_progress => '_IN_PROGRESS_',
|
53
|
+
:done => '_DONE_',
|
54
|
+
:completed => '_COMPLETED_'
|
55
|
+
}
|
56
|
+
# The SubmitFeed operation uploads a file for processing together with
|
57
|
+
# the necessary metadata to process the file.
|
58
|
+
|
59
|
+
# Amazon MWS limits calls to 1,000 total calls per hour per seller
|
60
|
+
# account. For best performance, you should limit your calls to
|
61
|
+
# SubmitFeed to no more than three feeds per hour per seller account,
|
62
|
+
# although you can successfully call SubmitFeed up to 30 times per
|
63
|
+
# hour. Feed size is limited to 2,147,483,647 bytes (2^32 -1) per
|
64
|
+
# feed.
|
65
|
+
|
66
|
+
def submit_flat_file_feed(records, purge_flag = false)
|
67
|
+
header = "sku\tproduct-id\tproduct-id-type\tprice\titem-condition\tquantity\tadd-delete\twill-ship-internationally\texpedited-shipping\titem-note\tfulfillment-center-id"
|
68
|
+
query_params = {"Action" => "SubmitFeed","FeedType" => "_POST_FLAT_FILE_INVLOADER_DATA_"}
|
69
|
+
query_params['PurgeAndReplace'] = 'true' if purge_flag
|
70
|
+
response = post("/", query_params, ([header] + records).join("\r"))
|
71
|
+
result = SubmitFeedResponse.format(response)
|
72
|
+
end
|
73
|
+
|
74
|
+
# params can only contain {:purge => true}
|
75
|
+
def submit_feed(feed_type, message_type, messages = [], params = {})
|
76
|
+
message_type= message_type.to_s.camelize
|
77
|
+
raise InvalidMessageType if !MESSAGE_TYPES.include?(message_type)
|
78
|
+
raise "Missing merchant_id" unless @merchant_id
|
79
|
+
|
80
|
+
body = Amazon::MWS::FeedBuilder.new(message_type, messages, params.merge({:merchant_id => @merchant_id})).render
|
81
|
+
puts body if Amazon::MWS::Base.debug
|
82
|
+
|
83
|
+
response =
|
84
|
+
post("/", {
|
85
|
+
"Action" => "SubmitFeed",
|
86
|
+
"FeedType" => FEED_TYPES[feed_type]
|
87
|
+
}, body)
|
88
|
+
|
89
|
+
result = SubmitFeedResponse.format(response)
|
90
|
+
end
|
91
|
+
|
92
|
+
alias_method :submit, :submit_feed
|
93
|
+
|
94
|
+
# The GetFeedSubmissionList operation returns the total list of feed
|
95
|
+
# submissions within the previous 90 days that match the query
|
96
|
+
# parameters. Amazon MWS limits calls to 1,000 total calls per hour
|
97
|
+
# per seller account, including calls to GetFeedSubmissionList.
|
98
|
+
#
|
99
|
+
# The maximum number of results that will be returned in one call is
|
100
|
+
# one hundred. If there are additional results to return, HasNext will
|
101
|
+
# be returned in the response with a true value. To retrieve all the
|
102
|
+
# results, you can use the value of the NextToken parameter to call
|
103
|
+
# GetFeedSubmissionListByNextToken until HasNext is false.
|
104
|
+
|
105
|
+
# Optional Request Parameters
|
106
|
+
# ------------------
|
107
|
+
# FeedSubmissionIdList
|
108
|
+
# A structured list of feed submission IDs. If you pass in explicit
|
109
|
+
# IDs in this call, the other conditions, if specified, will be
|
110
|
+
# ignored.
|
111
|
+
|
112
|
+
# MaxCount
|
113
|
+
# Maximum number of feed submissions to return in the list. If you
|
114
|
+
# specify a number greater than 100, the call will be rejected.
|
115
|
+
|
116
|
+
# FeedTypeList
|
117
|
+
# A structured list of one or more FeedType constants by which to
|
118
|
+
# filter feed submissions.
|
119
|
+
|
120
|
+
# FeedProcessingStatusList
|
121
|
+
# A structured list of one or more feed processing statuses by which
|
122
|
+
# to filter feed submissions. Valid values are:
|
123
|
+
#
|
124
|
+
# _SUBMITTED_
|
125
|
+
# _IN_PROGRESS_
|
126
|
+
# _CANCELLED_
|
127
|
+
# _DONE_
|
128
|
+
|
129
|
+
# SubmittedFromDate
|
130
|
+
# The earliest submission date you are looking for, in ISO8601 date
|
131
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
132
|
+
# "2008-07-03T18:12:22.093-07:00").
|
133
|
+
|
134
|
+
# SubmittedToDate
|
135
|
+
# The latest submission date you are looking for, in ISO8601 date
|
136
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
137
|
+
# "2008-07-03T18:12:22.093-07:00").
|
138
|
+
|
139
|
+
def get_feed_submission_list(params = {})
|
140
|
+
response = get("/", {"Action" => "GetFeedSubmissionList"}.merge(params))
|
141
|
+
result = GetFeedSubmissionListResponse.format(response)
|
142
|
+
end
|
143
|
+
|
144
|
+
alias_method :feed_submission_list, :get_feed_submission_list
|
145
|
+
|
146
|
+
# The GetFeedSubmissionListByNextToken operation returns a list of
|
147
|
+
# feed submissions that match the query parameters, using the
|
148
|
+
# NextToken, which was supplied by a previous call to either
|
149
|
+
# GetFeedSubmissionListByNextToken or a call to GetFeedSubmissionList,
|
150
|
+
# where the value of HasNext was true in that previous call.
|
151
|
+
#
|
152
|
+
# Request Parameters
|
153
|
+
# ------------------
|
154
|
+
# NextToken
|
155
|
+
# Token returned in a previous call to either GetFeedSubmissionList or
|
156
|
+
# GetFeedSubmissionListByNextToken when the value of HasNext was true.
|
157
|
+
def get_feed_submission_list_by_next_token(next_token)
|
158
|
+
response =
|
159
|
+
get("/", {
|
160
|
+
"Action" => "GetFeedSubmissionListByNextToken",
|
161
|
+
"NextToken" => next_token
|
162
|
+
})
|
163
|
+
|
164
|
+
GetFeedSubmissionListByNextTokenResponse.format(response)
|
165
|
+
end
|
166
|
+
|
167
|
+
alias_method :feed_submission_list_by_next_token, :get_feed_submission_list_by_next_token
|
168
|
+
|
169
|
+
# The GetFeedsubmissionCount operation returns a count of the total
|
170
|
+
# number of feed submissions within the previous 90 days.
|
171
|
+
#
|
172
|
+
# Optional Request Parameters
|
173
|
+
# ------------------
|
174
|
+
# FeedTypeList
|
175
|
+
# A structured list of one or more FeedType constants by which to
|
176
|
+
# filter feed submissions.
|
177
|
+
|
178
|
+
# FeedProcessingStatusList
|
179
|
+
# A structured list of one or more feed processing statuses by which
|
180
|
+
# to filter feed submissions. Valid values are:
|
181
|
+
#
|
182
|
+
# _SUBMITTED_
|
183
|
+
# _IN_PROGRESS_
|
184
|
+
# _CANCELLED_
|
185
|
+
# _DONE_
|
186
|
+
|
187
|
+
# SubmittedFromDate
|
188
|
+
# The earliest submission date you are looking for, in ISO8601 date
|
189
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
190
|
+
# "2008-07-03T18:12:22.093-07:00").
|
191
|
+
|
192
|
+
# SubmittedToDate
|
193
|
+
# The latest submission date you are looking for, in ISO8601 date
|
194
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
195
|
+
# "2008-07-03T18:12:22.093-07:00").
|
196
|
+
|
197
|
+
def get_feed_submission_count(params = {})
|
198
|
+
response = get("/", {"Action" => "GetFeedSubmissionCount"}.merge(params))
|
199
|
+
GetFeedSubmissionCountResponse.format(response)
|
200
|
+
end
|
201
|
+
|
202
|
+
alias_method :feed_submission_count, :get_feed_submission_count
|
203
|
+
|
204
|
+
# The CancelFeedSubmissions operation cancels one or more feed
|
205
|
+
# submissions, returning the count of the canceled feed submissions
|
206
|
+
# and the feed submission information. You can specify a number to
|
207
|
+
# cancel of greater than one hundred, but information will only be
|
208
|
+
# returned about the first one hundred feed submissions in the list.
|
209
|
+
# To return metadata about a greater number of canceled feed
|
210
|
+
# submissions, you can call GetFeedSubmissionList. If feeds have
|
211
|
+
# already begun processing, they cannot be canceled.
|
212
|
+
|
213
|
+
# Amazon MWS limits calls to 1,000 total calls per hour per seller
|
214
|
+
# account, including calls to CancelFeedSubmissions.
|
215
|
+
|
216
|
+
# Optional Request Parameters
|
217
|
+
# ------------------
|
218
|
+
# FeedSubmissionIdList
|
219
|
+
# A structured list of feed submission IDs. If you pass in explicit
|
220
|
+
# IDs in this call, the other conditions, if specified, will be
|
221
|
+
# ignored.
|
222
|
+
|
223
|
+
# FeedTypeList
|
224
|
+
# A structured list of one or more FeedType constants by which to
|
225
|
+
# filter feed submissions.
|
226
|
+
|
227
|
+
# SubmittedFromDate
|
228
|
+
# The earliest submission date you are looking for, in ISO8601 date
|
229
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
230
|
+
# "2008-07-03T18:12:22.093-07:00").
|
231
|
+
|
232
|
+
# SubmittedToDate
|
233
|
+
# The latest submission date you are looking for, in ISO8601 date
|
234
|
+
# format (for example, "2008-07-03T18:12:22Z" or
|
235
|
+
# "2008-07-03T18:12:22.093-07:00").
|
236
|
+
|
237
|
+
def cancel_feed_submissions(params = {})
|
238
|
+
response =
|
239
|
+
get("/", {"Action" => "CancelFeedSubmissions"}.merge(params))
|
240
|
+
|
241
|
+
CancelFeedSubmissionsResponse.format(response)
|
242
|
+
end
|
243
|
+
|
244
|
+
# The GetFeedSubmissionResult operation returns the feed processing
|
245
|
+
# report and the Content-MD5 header for the returned body.
|
246
|
+
|
247
|
+
# You should compute the MD5 hash of the HTTP body that we returned to
|
248
|
+
# you, and compare that with the Content-MD5 header value that we
|
249
|
+
# returned. If they do not match, which means the body was corrupted
|
250
|
+
# during transmission, you should discard the result and automatically
|
251
|
+
# retry the call for up to three more times. Please notify us if you
|
252
|
+
# ever see such a corrupted body. You can contact us by using the
|
253
|
+
# contact form at http://mws.amazon.com (http://mws.amazon.com). For
|
254
|
+
# more information on computing the MD5, see Using the Content-MD5
|
255
|
+
# Header with SubmitFeed.
|
256
|
+
|
257
|
+
# FeedSubmissionId
|
258
|
+
# The identifier of the feed submission to get results for. Obtained
|
259
|
+
# by a call to GetFeedSubmissionList.
|
260
|
+
|
261
|
+
def get_feed_submission_result(feed_submission_id, params = {})
|
262
|
+
response = get("/", {
|
263
|
+
"Action" => "GetFeedSubmissionResult",
|
264
|
+
"FeedSubmissionId" => feed_submission_id
|
265
|
+
}.merge(params))
|
266
|
+
|
267
|
+
GetFeedSubmissionResultResponse.format(response)
|
268
|
+
end
|
269
|
+
|
270
|
+
alias_method :feed_submission_result, :get_feed_submission_result
|
271
|
+
end
|
272
|
+
|
273
|
+
# Feed
|
274
|
+
|
275
|
+
end
|
276
|
+
end
|