Created
November 12, 2018 15:52
-
-
Save raeno/c0da28cdb0779ac18d38ed63871cbfab to your computer and use it in GitHub Desktop.
Amazon MWS examples
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Amazon | |
class InboundShipmentApi | |
include Logging | |
include WithThrottling | |
ACTIVE_SHIPMENT_STATUSES = %w( WORKING SHIPPED IN_TRANSIT DELIVERED CHECKED_IN RECEIVING CLOSED CANCELLED DELETED ERROR).freeze | |
DEFAULT_SHIPMENTS_RANGE = 24.months.ago | |
def self.build(amazon_config, options = {}) | |
inbound_shipment_client = MWS.fulfillment_inbound_shipment(amazon_config) | |
new(inbound_shipment_client, options) | |
end | |
def initialize(inbound_shipment_client, options = {}) | |
@inbound_shipment_client = inbound_shipment_client | |
@ship_from_address = options.fetch(:ship_from_address, {}) | |
end | |
def get_prep_instructions_for_sku(*skus) | |
response = inbound_shipment_client.get_prep_instructions_for_sku('US', skus) | |
response.parse | |
rescue => e | |
log(e.message, :error) | |
nil | |
end | |
def create_shipment_plan(items) | |
shipment_plans = inbound_shipment_client.create_inbound_shipment_plan(ship_from_address, items) | |
shipment_plans.parse | |
rescue => e | |
log(e.message, :error) | |
nil | |
end | |
def create_shipment(shipment_id, header, items_to_ship) | |
response = inbound_shipment_client.create_inbound_shipment(shipment_id, header, inbound_shipment_items: items_to_ship) | |
ShipmentApiResult.new response: response, success: true | |
rescue => e | |
ShipmentApiResult.new response: e.response, success: false, errors: [e.message, e.response.body] | |
end | |
def update_shipment(shipment_id, header, items_to_ship) | |
response = inbound_shipment_client.update_inbound_shipment(shipment_id, header, inbound_shipment_items: items_to_ship) | |
ShipmentApiResult.new(response: response, success: true) | |
rescue => e | |
ShipmentApiResult.new(response: e.response, success: false, errors: [e.message, e.response.body]) | |
end | |
def fetch_shipments(statuses: ACTIVE_SHIPMENT_STATUSES, | |
date_from: DEFAULT_SHIPMENTS_RANGE, | |
date_to: Time.zone.now) | |
params = { | |
shipment_status_list: statuses, | |
last_updated_before: date_to.to_s(:iso8601), | |
last_updated_after: date_from.to_s(:iso8601) | |
} | |
shipments_response = inbound_shipment_client.list_inbound_shipments(params).parse | |
shipments = [shipments_response] | |
while shipments_response['NextToken'] | |
throttle 30, per: :minute do | |
token = shipments_response['NextToken'] | |
shipments_response = inbound_shipment_client.list_inbound_shipments_by_next_token(token).parse | |
shipments << shipments_response | |
end | |
end | |
shipments | |
end | |
private | |
attr_reader :inbound_shipment_client, :ship_from_address | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Amazon | |
class InventoryApi | |
include Logging | |
include WithThrottling | |
AMAZON_REPORT_NAME = '_GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA_' | |
INVENTORY_DATA_KEY = '_GET_FBA_MYI_UNSUPPRESSED_INVENTORY_DATA_' | |
def self.build(config = {}) | |
reports_client = MWS.reports(config) | |
new(reports_client) | |
end | |
def initialize(reports_client) | |
@reports_client = reports_client | |
end | |
# only asks Amazon to prepare report, it can take up to few hours | |
# to make the report on Amazon side. Fetch reports with #fetch_reports | |
def request_report | |
reports_client.request_report(AMAZON_REPORT_NAME) | |
end | |
def fetch_reports(reports_range) | |
start_date = reports_range.ago.to_date.to_s(:iso8601) | |
reports_lists = fetch_reports_lists(start_date) | |
reports_lists.compact.flat_map { |list| extract_reports(list) } | |
end | |
def fetch_report(report_id) | |
log "Fetching report data for #{report_id}" | |
report = reports_client.get_report(report_id) | |
return nil unless report | |
report.body | |
end | |
private | |
attr_reader :reports_client | |
def fetch_reports_lists(start_date) | |
log "Getting initial reports list from Amazon" | |
reports_list = fetch_initial_reports_list(start_date) | |
return [] unless reports_list | |
all_lists = [reports_list] | |
while reports_list['NextToken'] | |
log "Getting following reports list from Amazon" | |
throttle 30, per: :minute do | |
reports_list = fetch_next_reports_list reports_list['NextToken'] | |
end | |
all_lists << reports_list | |
end | |
all_lists | |
end | |
def extract_reports(list) | |
report_info = list['ReportInfo'] | |
return [] unless report_info | |
report_info.select { |r| r['ReportType'] == INVENTORY_DATA_KEY } | |
end | |
def fetch_initial_reports_list(start_date) | |
reports_list = reports_client.get_report_list(available_from_date: start_date) | |
reports_list.parse | |
rescue => e | |
log "Error while fetching initial reports list: #{e.message}", :error | |
nil | |
end | |
def fetch_next_reports_list(token) | |
reports_list = reports_client.get_report_list_by_next_token(token) | |
reports_list.parse | |
rescue => e | |
log "Error while fetching following reports list:: #{e.message}", :error | |
nil | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module Amazon | |
module Parsers | |
class ShipmentPlansParser | |
attr_reader :address_parser, :prep_instructions_parser | |
def self.build | |
address_parser = Amazon::Parsers::AddressParser.new | |
new(address_parser) | |
end | |
def initialize(address_parser) | |
@address_parser = address_parser | |
end | |
def parse(response) | |
return ShipmentPlansResult.new([], false, ['Invalid response in creating shipment plan']) unless response | |
plans = response.dig 'InboundShipmentPlans', 'member' | |
result = Array.wrap(plans).map do |plan_body| | |
build_shipment_plan(plan_body) | |
end | |
ShipmentPlansResult.new(result, true, []) | |
rescue => e | |
ShipmentPlansResult.new(result, false, [e.message]) | |
end | |
private | |
def build_shipment_plan(plan) | |
shipment_plan = OpenStruct.new | |
shipment_plan.destination_fulfillment_center_id = plan.dig 'DestinationFulfillmentCenterId' | |
shipment_plan.label_prep_type = plan.dig 'LabelPrepType' | |
shipment_plan.shipment_id = plan.dig 'ShipmentId' | |
shipment_plan.ship_to_address = parse_address plan | |
items = plan.dig 'Items', 'member' | |
shipment_plan.items = parse_items_on_shipment_plan items | |
shipment_plan | |
end | |
def parse_items_on_shipment_plan(items) | |
return [] unless items | |
Array.wrap(items).map do |item| | |
prep_details = item.dig 'PrepDetailsList', 'PrepDetails' | |
OpenStruct.new( | |
fulfillment_network_sku: item.dig('FulfillmentNetworkSKU'), | |
quantity: item.dig('Quantity'), | |
seller_sku: item.dig('SellerSKU'), | |
prep_details_list: parse_preparation_details(prep_details) | |
) | |
end | |
end | |
def parse_preparation_details(preparation_details) | |
return [] unless preparation_details | |
Array.wrap(preparation_details).map do |details| | |
owner = details.dig 'PrepOwner' | |
instruction = details.dig 'PrepInstruction' | |
OpenStruct.new prep_owner: owner, prep_instruction: instruction | |
end | |
end | |
def parse_address(response) | |
address_response = response.dig 'ShipToAddress' | |
raise ArgumentError, 'Invalid shipping address' unless address_response | |
address_parser.parse(address_response) | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment