diff --git a/.gitignore b/.gitignore index 3ef027c..f0982f7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ test/tmp test/version_tmp tmp *.sublime-workspace +.idea \ No newline at end of file diff --git a/README.md b/README.md index 6a9bc04..3cd00c3 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,27 @@ Example: Get the results for a submission: _For an example of putting it all together check out the 'scripts/catalog-workflow'_ + +Access the Reports Api: + + reports_api = mws.reports + +Get products from a specific seller (http://stackoverflow.com/questions/13477797/get-products-from-a-specific-seller-from-amazon-via-api): + + reports_api.flat_file_open_listings_data.request + => "7589360560" # returns report request id + + reports_api.get_report_request("7589360560") + => nil # returns nil until report is uncompleted + + reports_api.get_report_request("7589360650") + => "11760935522" # returns report_id when report is ready + + reports_api.flat_file_open_listings_data.get("11760935522") + => [ {"sku"=>"GY-8IYT-2DCD", "asin"=>"B027DCI0D2", "price"=>"47.00", "quantity"=>"2"}, + {"sku"=>"II-2561-BW36", "asin"=>"B104BUTEIO", "price"=>"39.00", "quantity"=>"3"} ] + + ## Contributing 1. Fork it diff --git a/lib/mws/apis.rb b/lib/mws/apis.rb index 1b041d8..ecb14ce 100644 --- a/lib/mws/apis.rb +++ b/lib/mws/apis.rb @@ -2,5 +2,6 @@ module Mws::Apis autoload :Feeds, 'mws/apis/feeds' autoload :Orders, 'mws/apis/orders' + autoload :Reports, 'mws/apis/reports' end diff --git a/lib/mws/apis/reports.rb b/lib/mws/apis/reports.rb new file mode 100644 index 0000000..97ffd74 --- /dev/null +++ b/lib/mws/apis/reports.rb @@ -0,0 +1,6 @@ +module Mws::Apis::Reports + + autoload :Api, 'mws/apis/reports/api' + autoload :FlatFileOpenListingsData, 'mws/apis/reports/flat_file_open_listings_data' + +end diff --git a/lib/mws/apis/reports/api.rb b/lib/mws/apis/reports/api.rb new file mode 100644 index 0000000..16bc775 --- /dev/null +++ b/lib/mws/apis/reports/api.rb @@ -0,0 +1,39 @@ +module Mws::Apis::Reports + + class Api + + attr_reader :flat_file_open_listings_data + + def initialize(connection, overrides={}) + raise Mws::Errors::ValidationError, 'A connection is required.' if connection.nil? + @connection = connection + @param_defaults = { + market: 'ATVPDKIKX0DER' + }.merge overrides + @option_defaults = { + version: '2009-01-01' + } + + @flat_file_open_listings_data = FlatFileOpenListingsData.new(connection) + end + + # Gets status of a formerly initiated report generation, required parameter: report_request_id + def get_report_request(report_request_id, params={}) + options = @option_defaults.merge action: 'GetReportRequestList' + params.merge! :"report_request_id_list.id.1" => report_request_id + doc = @connection.get "/", params, options + request_info = doc.xpath("/GetReportRequestListResponse/GetReportRequestListResult/ReportRequestInfo[1]").first + status = request_info.xpath("ReportProcessingStatus").text + report_id = request_info.xpath("GeneratedReportId").text + (status == "_DONE_") ? report_id : nil + end + + def get_report_count(params={}) + options = @option_defaults.merge action: 'GetReportCount' + doc = @connection.get "/", params, options + count = doc.xpath("/GetReportCountResponse/GetReportCountResult/Count[1]").text.to_i + end + + end + +end diff --git a/lib/mws/apis/reports/flat_file_open_listings_data.rb b/lib/mws/apis/reports/flat_file_open_listings_data.rb new file mode 100644 index 0000000..1b61d4a --- /dev/null +++ b/lib/mws/apis/reports/flat_file_open_listings_data.rb @@ -0,0 +1,46 @@ +class Mws::Apis::Reports::FlatFileOpenListingsData + + require "csv" + + def initialize(connection, overrides={}) + @connection = connection + @param_defaults = { + market: 'ATVPDKIKX0DER' + }.merge overrides + @option_defaults = { + version: '2009-01-01' + } + end + + # Initiates a "flat file open listings data" report generation + def request(params={}) + options = @option_defaults.merge action: 'RequestReport' + params.merge! report_type: "_GET_FLAT_FILE_OPEN_LISTINGS_DATA_" + doc = @connection.get("/", params, options) + request_info = doc.xpath("/RequestReportResponse/RequestReportResult/ReportRequestInfo[1]").first + status = request_info.xpath("ReportProcessingStatus").text + status == "_SUBMITTED_" ? request_info.xpath("ReportRequestId").text : nil + end + + # Gets and parses a formerly generated "flat file open listings data" report result + # Required parameter: report_id which can be obtained by get_report_request method + def get(report_id, params={}) + options = @option_defaults.merge action: 'GetReport' + params.merge! :"report_id" => report_id + lines = @connection.get "/", params, options + parsed_report = parse_report(lines) + convert_to_hash(parsed_report) + end + + def parse_report(report_lines) + report_lines.gsub! /\r\n?/, "\n" + parsed_report = report_lines.split("\n").map { |line| CSV.parse_line(line, col_sep: "\t") } + parsed_report + end + + def convert_to_hash(parsed_report) + header = parsed_report.shift + parsed_report.map { |item| Hash[header.zip(item)] } + end + +end diff --git a/lib/mws/connection.rb b/lib/mws/connection.rb index a2ec28b..73e1b41 100644 --- a/lib/mws/connection.rb +++ b/lib/mws/connection.rb @@ -8,7 +8,7 @@ module Mws class Connection - attr_reader :merchant, :orders, :feeds + attr_reader :merchant, :orders, :feeds, :reports def initialize(overrides) @log = Logging.logger[self] @@ -22,6 +22,7 @@ def initialize(overrides) raise Mws::Errors::ValidationError, 'A secret key must be specified.' if @secret.nil? @orders = Apis::Orders.new self @feeds = Apis::Feeds::Api.new self + @reports = Apis::Reports::Api.new self end def get(path, params, overrides) @@ -43,7 +44,8 @@ def request(method, path, params, body, overrides) list_pattern: overrides.delete(:list_pattern) }.merge(params)) signer = Signer.new method: method, host: @host, path: path, secret: @secret - parse response_for(method, path, signer.sign(query), body), overrides + response = response_for(method, path, signer.sign(query), body) + parse(response, overrides) || response end def response_for(method, path, query, body) diff --git a/lib/mws/query.rb b/lib/mws/query.rb index 37bf48a..8f9102b 100644 --- a/lib/mws/query.rb +++ b/lib/mws/query.rb @@ -35,7 +35,7 @@ def to_s private def normalize_key(key) - Mws::Utils.camelize(key).sub /^Aws/, 'AWS' + Mws::Utils.camelize(key).sub(/^Aws/, 'AWS').sub(".id.", ".Id.") end def normalize_val(value) diff --git a/spec/mws/apis/reports/api_spec.rb b/spec/mws/apis/reports/api_spec.rb new file mode 100644 index 0000000..c08be2f --- /dev/null +++ b/spec/mws/apis/reports/api_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +module Mws::Apis::Reports + + describe Api do + + let(:connection) do + Mws::Connection.new( + merchant: 'GSWCJ4UBA31UTJ', + access: 'AYQAKIAJSCWMLYXAQ6K3', + secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX' + ) + end + + let(:reports_api) do + connection.reports + end + + it "should return generated report id for a report with DONE status" do + response_xml_body = < + + + + + false + + 7580976354 + _GET_FLAT_FILE_OPEN_LISTINGS_DATA_ + 2013-07-20T11:19:01+00:00 + 2013-07-20T11:19:01+00:00 + false + 2013-07-20T11:19:01+00:00 + _DONE_ + 11743408783 + 2013-07-20T11:27:42+00:00 + 2013-07-20T11:28:03+00:00 + + + + 1b435755-d127-413e-9dd1-5c2f54cea33b + +" +END + connection.should_receive(:response_for).and_return { response_xml_body } + reports_api.get_report_request("7580976354").should eq "11743408783" + end + + it "should return nil for an uncompleted report" do + response_xml_body = < + + + + + false + + 7589329190 + _GET_FLAT_FILE_OPEN_LISTINGS_DATA_ + 2013-07-21T18:10:28+00:00 + 2013-07-21T18:10:28+00:00 + false + 2013-07-21T18:10:28+00:00 + _SUBMITTED_ + + + + 96241497-20bd-4edc-90f0-4e9dda39c340 + + +END + connection.should_receive(:response_for).and_return { response_xml_body } + reports_api.get_report_request("7589329190").should be nil + end + + it "should return reports count" do + response_xml_body = < + + + 7 + + + 87a113eb-18a8-4c46-874c-e6d740f750a8 + + +END + connection.should_receive(:response_for).and_return { response_xml_body } + reports_api.get_report_count.should be 7 + end + + + end + +end \ No newline at end of file diff --git a/spec/mws/apis/reports/flat_file_open_listings_data_spec.rb b/spec/mws/apis/reports/flat_file_open_listings_data_spec.rb new file mode 100644 index 0000000..5fd75ac --- /dev/null +++ b/spec/mws/apis/reports/flat_file_open_listings_data_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +module Mws::Apis::Reports + + describe FlatFileOpenListingsData do + + let(:connection) do + Mws::Connection.new( + merchant: 'GSWCJ4UBA31UTJ', + access: 'AYQAKIAJSCWMLYXAQ6K3', + secret: 'Ubzq/NskSrW4m5ncq53kddzBej7O7IE5Yx9drGrX' + ) + end + + let(:reports_flat_file_open_listings_data_api) do + connection.reports.flat_file_open_listings_data + end + + it "should request a report generation" do + response_xml_body = < + + + + 7589269186 + _GET_FLAT_FILE_OPEN_LISTINGS_DATA_ + 2013-07-21T18:00:06+00:00 + 2013-07-21T18:00:06+00:00 + false + 2013-07-21T18:00:06+00:00 + _SUBMITTED_ + + + + 5e529e1b-c0fa-438d-a602-704d5ab80728 + + +END + connection.should_receive(:response_for).and_return { response_xml_body } + reports_flat_file_open_listings_data_api.request.should eq "7589269186" + end + + it "should parse tab delimited lines of a report result" do + input = "sku asin price quantity +GY-8YTI-6CDC B007DCI0E6 47.00 2 +II-4545-W3B6 B004UBTEIO 39.00 3" + output = [["sku", "asin", "price", "quantity"], ["GY-8YTI-6CDC", "B007DCI0E6", "47.00", "2"], ["II-4545-W3B6", "B004UBTEIO", "39.00", "3"]] + reports_flat_file_open_listings_data_api.parse_report(input).should eq output + end + + it "should convert report arrays to hash using the header line as keys" do + input = [["sku", "asin", "price", "quantity"], ["GY-8YTI-6CDC", "B007DCI0E6", "47.00", "2"], ["II-4545-W3B6", "B004UBTEIO", "39.00", "3"]] + output = [{"sku" => "GY-8YTI-6CDC", "asin" => "B007DCI0E6", "price" => "47.00", "quantity" => "2"}, {"sku" => "II-4545-W3B6", "asin" => "B004UBTEIO", "price" => "39.00", "quantity" => "3"}] + reports_flat_file_open_listings_data_api.convert_to_hash(input).should eq output + end + + end + +end \ No newline at end of file