From 58a1deef7c7ae01d0eb69c54823f57c521994f82 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Tue, 28 May 2013 18:10:54 -0600 Subject: [PATCH 1/6] uncommented params[:lists][:marketplace_id] to get it to work --- bin/ruby-mws | 0 lib/ruby-mws/api/base.rb | 9 ++++++--- lib/ruby-mws/api/order.rb | 6 ++++++ lib/ruby-mws/version.rb | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) mode change 100644 => 100755 bin/ruby-mws diff --git a/bin/ruby-mws b/bin/ruby-mws old mode 100644 new mode 100755 diff --git a/lib/ruby-mws/api/base.rb b/lib/ruby-mws/api/base.rb index ee5a10d..160e042 100644 --- a/lib/ruby-mws/api/base.rb +++ b/lib/ruby-mws/api/base.rb @@ -11,7 +11,7 @@ class Base include HTTParty # debug_output $stderr # only in development format :xml - headers "User-Agent" => "ruby-mws/#{MWS::VERSION} (Language=Ruby/1.9.3-p0)" + headers "User-Agent" => "ruby-mws/#{MWS::VERSION} (Language=Ruby/#{RUBY_VERSION})" headers "Content-Type" => "text/xml" attr_accessor :response @@ -47,14 +47,17 @@ def send_request(name, params, options={}) params[:version] ||= '2009-01-01' params[:uri] ||= '/' - params[:lists] ||= {} - #params[:lists][:marketplace_id] = "MarketplaceId.Id" + # params[:lists] ||= {} + params[:lists][:marketplace_id] = "MarketplaceId.Id" if params[:lists] query = Query.new params if $VERBOSE puts "ruby-mws: Sending #{params[:verb].upcase} request to #{query.request_uri}. Options: #{query.http_options.inspect}" end resp = self.class.send(params[:verb], query.request_uri, query.http_options) + if $VERBOSE + puts "ruby-mws: response: #{resp}" + end content_type = resp.headers['content-type'] if not content_type =~ /text\/xml/ || content_type =~ /application\/xml/ || content_type =~ /application\/octet-stream/ diff --git a/lib/ruby-mws/api/order.rb b/lib/ruby-mws/api/order.rb index 1b11a92..7c77eed 100644 --- a/lib/ruby-mws/api/order.rb +++ b/lib/ruby-mws/api/order.rb @@ -2,6 +2,12 @@ module MWS module API class Order < Base + + def_request :report, + verb: :get, + uri: '/OrderReport', + version: '2011-01-01' + def_request [:list_orders, :list_orders_by_next_token], :verb => :get, :uri => '/Orders/2011-01-01', diff --git a/lib/ruby-mws/version.rb b/lib/ruby-mws/version.rb index 1b46bcd..3ac0baf 100644 --- a/lib/ruby-mws/version.rb +++ b/lib/ruby-mws/version.rb @@ -1,3 +1,3 @@ module MWS - VERSION = "0.0.3" + VERSION = "0.0.5" end From be78c3ab6b1eab44e4dfa7b17234f4197686b89c Mon Sep 17 00:00:00 2001 From: mike-ball Date: Sat, 1 Jun 2013 19:43:32 -0600 Subject: [PATCH 2/6] properly handle the xml hash if only one order is returned --- lib/ruby-mws/api/order.rb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/ruby-mws/api/order.rb b/lib/ruby-mws/api/order.rb index 7c77eed..2a84795 100644 --- a/lib/ruby-mws/api/order.rb +++ b/lib/ruby-mws/api/order.rb @@ -3,11 +3,6 @@ module API class Order < Base - def_request :report, - verb: :get, - uri: '/OrderReport', - version: '2011-01-01' - def_request [:list_orders, :list_orders_by_next_token], :verb => :get, :uri => '/Orders/2011-01-01', @@ -16,7 +11,8 @@ class Order < Base :order_status => "OrderStatus.Status" }, :mods => [ - lambda {|r| r.orders = r.orders.order if r.orders} + lambda {|r| r.orders = r.orders.order if r.orders && r.orders.size > 1}, + lambda {|r| r.orders = [r.orders.order] if r.orders && r.orders.size == 1} ] def_request [:list_order_items, :list_order_items_by_next_token], From d07adad0b5131d572a385d3b4e0150f428e9fb86 Mon Sep 17 00:00:00 2001 From: mike-ball Date: Mon, 3 Jun 2013 03:00:25 -0600 Subject: [PATCH 3/6] correctly handle the xml when only one item is found --- lib/ruby-mws/api/order.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/ruby-mws/api/order.rb b/lib/ruby-mws/api/order.rb index 2a84795..5ba33b2 100644 --- a/lib/ruby-mws/api/order.rb +++ b/lib/ruby-mws/api/order.rb @@ -20,7 +20,9 @@ class Order < Base :uri => '/Orders/2011-01-01', :version => '2011-01-01', :mods => [ - lambda {|r| r.order_items = [r.order_items.order_item].flatten} + # lambda {|r| r.order_items = [r.order_items.order_item].flatten} + lambda {|i| i.order_items = i.order_items.order_item if i.order_items && i.order_items.size > 1}, + lambda {|i| i.order_items = [i.order_items.order_item] if i.order_items && i.order_items.size == 1} ] def_request :get_order, From bfebcaaa3eabbf3c13acc4e8b8b0f579ad2caad5 Mon Sep 17 00:00:00 2001 From: mike-ball Date: Mon, 3 Jun 2013 03:00:44 -0600 Subject: [PATCH 4/6] add some more output for VERBOSE testing --- lib/ruby-mws/api/base.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/ruby-mws/api/base.rb b/lib/ruby-mws/api/base.rb index 160e042..eeb7dbc 100644 --- a/lib/ruby-mws/api/base.rb +++ b/lib/ruby-mws/api/base.rb @@ -44,11 +44,11 @@ def send_request(name, params, options={}) params[:signature_method] ||= 'HmacSHA256' params[:signature_version] ||= '2' params[:timestamp] ||= Time.now.iso8601 - params[:version] ||= '2009-01-01' + # params[:version] ||= '2009-01-01' params[:uri] ||= '/' - # params[:lists] ||= {} - params[:lists][:marketplace_id] = "MarketplaceId.Id" if params[:lists] + params[:lists] ||= {} + params[:lists][:marketplace_id] = "MarketplaceId.Id" query = Query.new params if $VERBOSE @@ -57,6 +57,9 @@ def send_request(name, params, options={}) resp = self.class.send(params[:verb], query.request_uri, query.http_options) if $VERBOSE puts "ruby-mws: response: #{resp}" + puts "response body:" + puts resp.body.inspect + puts "\n" end content_type = resp.headers['content-type'] From 0c5ef344d8ffdbf1b9ae577242ace1e8d2660aaa Mon Sep 17 00:00:00 2001 From: mike-ball Date: Tue, 4 Jun 2013 00:43:29 -0600 Subject: [PATCH 5/6] Added fulfillment class and methods for order_acknowledgement and shipping_confirmation --- lib/ruby-mws.rb | 1 + lib/ruby-mws/api/fulfillment.rb | 101 ++++++++++++++++++++++++++++++++ lib/ruby-mws/base.rb | 4 ++ 3 files changed, 106 insertions(+) create mode 100644 lib/ruby-mws/api/fulfillment.rb diff --git a/lib/ruby-mws.rb b/lib/ruby-mws.rb index 6a60bee..72bbbf1 100644 --- a/lib/ruby-mws.rb +++ b/lib/ruby-mws.rb @@ -60,3 +60,4 @@ def camelize(first_letter_in_uppercase = true) require 'ruby-mws/api/reports' require 'ruby-mws/api/response' require 'ruby-mws/api/sellers' +require 'ruby-mws/api/fulfillment' diff --git a/lib/ruby-mws/api/fulfillment.rb b/lib/ruby-mws/api/fulfillment.rb new file mode 100644 index 0000000..6d25099 --- /dev/null +++ b/lib/ruby-mws/api/fulfillment.rb @@ -0,0 +1,101 @@ +require 'builder' + +module MWS + module API + + class Fulfillment < Base + include Feeds + + # Takes a hash of order and item details + # Returns true if the order was acknowledged successfully + # Otherwise raises an exception + def order_acknowledgement(hash) + # example use: order_acknowledgement(amazon_order_id: '112-2598432-0713054', merchant_order_id: 336, status: 'Success', items: {'47979057082330' => '438'}) + # order_acknowledgement(amazon_order_id: '112-2598432-0713054', merchant_order_id: 336, status: 'Success') + # order acknowledgment is done by sending an XML "feed" to Amazon + # as of this writing, XML schema docs are available at: + # https://images-na.ssl-images-amazon.com/images/G/01/rainier/help/XML_Documentation_Intl.pdf + # https://images-na.ssl-images-amazon.com/images/G/01/mwsportal/doc/en_US/bde/MWSFeedsApiReference._V372272627_.pdf + xml = "" + builder = Builder::XmlMarkup.new(:indent => 2, :target => xml) + builder.instruct! # + builder.AmazonEnvelope(:"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", :"xsi:noNamespaceSchemaLocation" => "amzn-envelope.xsd") do |env| + env.Header do |head| + head.DocumentVersion('1.01') + head.MerchantIdentifier(@connection.seller_id) + end + env.MessageType('OrderAcknowledgement') + env.Message do |mes| + mes.MessageID('1') + mes.OrderAcknowledgement do |oa| + oa.AmazonOrderID(hash[:amazon_order_id]) + oa.MerchantOrderID(hash[:merchant_order_id]) unless hash[:merchant_order_id].blank? + oa.StatusCode(hash[:status]) + (hash[:items] || {}).each do |item_code, merchant_item_id| + oa.Item do |item| + item.AmazonOrderItemCode(item_code) + item.MerchantOrderItemID(merchant_item_id) unless merchant_item_id.blank? + end + end + end + end + end + + submit_feed('_POST_ORDER_ACKNOWLEDGEMENT_DATA_', xml) + end + + def shipping_confirmation(hash) + # example use: shipping_confirmation(merchant_order_id: 336, date: Time.parse("2013-06-03 17:58:25"), carrier: 'USPS', shipping_method: 'First Class', tracking: '9400110200883803727403') + # shipping_confirmation(mamazon_order_id: '112-2598432-0713054', date: Time.parse("2013-06-03 17:58:25"), carrier: 'USPS', shipping_method: 'First Class', tracking: '9400110200883803727403') + if hash[:date].is_a? String + # do nothing for now. Maybe later ensure it's the correct format. + else + # assume it's a Time, DateTime, ActiveSupport::TimeWithZone, etc... + hash[:date] = hash[:date].strftime('%Y-%m-%dT%H:%M:%S%:z') + end + xml = "" + builder = Builder::XmlMarkup.new(:indent => 2, :target => xml) + builder.instruct! # + builder.AmazonEnvelope(:"xmlns:xsi" => "http://www.w3.org/2001/XMLSchema-instance", :"xsi:noNamespaceSchemaLocation" => "amzn-envelope.xsd") do |env| + env.Header do |head| + head.DocumentVersion('1.01') + head.MerchantIdentifier(@connection.seller_id) + end + env.MessageType('OrderFulfillment') + env.Message do |mes| + mes.MessageID('1') + mes.OrderFulfillment do |orf| + if hash[:amazon_order_id] + orf.AmazonOrderID(hash[:amazon_order_id]) + else + orf.MerchantOrderID(hash[:merchant_order_id]) + end + orf.MerchantFulfillmentID(hash[:merchant_fulfillment_id]) if hash[:merchant_fulfillment_id] + orf.FulfillmentDate(hash[:date]) + orf.FulfillmentData do |fd| + fd.CarrierCode(hash[:carrier]) + fd.ShippingMethod(hash[:shipping_method]) + fd.ShipperTrackingNumber(hash[:tracking]) + end + (hash[:items] || []).each do |item| + orf.Item do |oi| + if item[:amazon_order_item_code] + oi.AmazonOrderItemCode(item[:amazon_order_item_code]) + else + oi.MerchantOrderItemID(item[:merchant_order_item_id]) + end + oi.MerchantFulfillmentItemID(item[:merchant_fulfillment_item_id]) if item[:merchant_fulfillment_item_id] + oi.Quantity if item[:quantity] + end + end + end + end + end + submit_feed('_POST_ORDER_FULFILLMENT_DATA_', xml) + end + + end + + end + +end diff --git a/lib/ruby-mws/base.rb b/lib/ruby-mws/base.rb index 663de0b..a20adda 100644 --- a/lib/ruby-mws/base.rb +++ b/lib/ruby-mws/base.rb @@ -28,6 +28,10 @@ def sellers @sellers ||= MWS::API::Sellers.new(@connection) end + def fulfillment + @fulfillment ||= MWS::API::Fulfillment.new(@connection) + end + # serves as a server ping def self.server_time MWS::Connection.server_time From 73df177484d26471d91cad35bd7487e4bdca5534 Mon Sep 17 00:00:00 2001 From: Mike Ball Date: Fri, 12 Aug 2016 11:55:50 -0600 Subject: [PATCH 6/6] Digest::Digest is deprecated; using Digest --- lib/ruby-mws/api/query.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ruby-mws/api/query.rb b/lib/ruby-mws/api/query.rb index 6a76677..b1abcda 100644 --- a/lib/ruby-mws/api/query.rb +++ b/lib/ruby-mws/api/query.rb @@ -24,7 +24,7 @@ def canonical end def signature - digest = OpenSSL::Digest::Digest.new('sha256') + digest = OpenSSL::Digest.new('sha256') key = @params[:secret_access_key] Base64.encode64(OpenSSL::HMAC.digest(digest, key, canonical)).chomp end @@ -89,4 +89,4 @@ def set_body_digest end end -end \ No newline at end of file +end