Feature: Sync MWS Shipment with Database

Various restructuring and misc. features added.
Removed reliance on ABrain Amazon MWS NuGet package, added Amazon's own C# lib
This commit is contained in:
Bobbie Hodgetts
2019-06-24 16:01:50 +01:00
committed by GitHub
parent bc44546efd
commit 116aedb897
27 changed files with 2236 additions and 289 deletions

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.AmazonMWS
{
public class CredentialMws
{
public string merchantId { get { return "A3RUYNKLWWM5KW"; } }
public string marketPlaceId { get { return "A1F83G8C2ARO7P"; } } // Amazon.co.uk
public string accessKeyId { get { return "AKIAJU45WSYVINEN45UA"; } }
public string secretAccessKey { get { return "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"; } }
public string applicationName { get { return "bnhtrade.Core"; } }
public string applicationVersion { get { return "0.1"; } }
public string serviceURL { get { return "https://mws.amazonservices.co.uk"; } }
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.XPath;
namespace bnhtrade.Core.Data.AmazonMWS
{
public class CurrentDateTime
{
public DateTime GetUtc()
{
var xmlDoc = new XmlDocument();
xmlDoc.Load("https://mws.amazonservices.com/");
DateTime returnTime = default(DateTime);
XmlNodeList elemList = xmlDoc.GetElementsByTagName("Timestamp");
for (int i = 0; i < elemList.Count; i++)
{
string attrVal = elemList[i].Attributes["timestamp"].Value;
if (!string.IsNullOrWhiteSpace(attrVal))
{
returnTime = DateTime.Parse(attrVal);
break;
}
}
if (returnTime == default(DateTime))
{
throw new Exception("Error requesting time from Amazon");
}
returnTime = returnTime.ToUniversalTime();
returnTime = returnTime.AddTicks(-(returnTime.Ticks % TimeSpan.TicksPerSecond));
return returnTime;
}
public DateTime GetLocal()
{
return GetUtc().ToLocalTime();
}
}
}

View File

@@ -0,0 +1,189 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FBAInboundServiceMWS.Model;
namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound
{
class ListInboundShipmentItems
{
public string AmazonShipmentId { get; private set; }
public DateTime LastUpdatedAfter { get; private set; }
public DateTime LastUpdatedBefore { get; private set; }
public bool IsSetAmazonShipmentId()
{
return AmazonShipmentId != null;
}
public bool IsSetLastUpdatedAfter()
{
return LastUpdatedAfter != null;
}
public bool IsSetLastUpdatedBefore()
{
return LastUpdatedBefore != null;
}
public List<Model.AmazonFBAInbound.ShipmentItemInfo> GetByAmazonShipmentId(string amazonShipmentId)
{
// checks
if (amazonShipmentId.Length < 9)
{
throw new Exception("Amazon shipment id incorrect length '" + amazonShipmentId + "'");
}
var request = new ListInboundShipmentItemsRequest();
request.ShipmentId = amazonShipmentId;
AmazonShipmentId = amazonShipmentId;
return ListInboundShipmentItemsGet(request);
}
public List<Model.AmazonFBAInbound.ShipmentItemInfo> GetByDates(DateTime lastUpdatedAfter, DateTime lastUpdatedBefore)
{
//checks
if (lastUpdatedAfter >= lastUpdatedBefore)
{
throw new Exception("Paramter LastUpdatedAfter must be greater than LastUpdatedBefore");
}
var request = new ListInboundShipmentItemsRequest();
request.LastUpdatedAfter = lastUpdatedAfter;
request.LastUpdatedBefore = lastUpdatedBefore;
LastUpdatedAfter = lastUpdatedAfter;
LastUpdatedBefore = lastUpdatedBefore;
return ListInboundShipmentItemsGet(request);
}
private List<Model.AmazonFBAInbound.ShipmentItemInfo> ListInboundShipmentItemsGet(ListInboundShipmentItemsRequest request)
{
// variables
int mwsPollFrequency = 500;
int mwsPollTimeout = 60;
// add default entries, if not already set
if (!request.IsSetSellerId())
{
var cred = new AmazonMWS.CredentialMws();
request.SellerId = cred.merchantId;
}
// checks
if ((request.IsSetLastUpdatedAfter() || request.IsSetLastUpdatedBefore()) && request.IsSetShipmentId())
{
throw new Exception("If ShipmentId is specified, LastUpdatedBefore and LastUpdatedAfter are ignored.");
}
// get amazon service, responce and result
var service = new AmazonMWS.Service().FbaInbound;
//var response = new ListInboundShipmentItemsResponse();
var result = new ListInboundShipmentItemsResult();
// poll mws for response
int count = 0;
do
{
var response = service.ListInboundShipmentItems(request);
if (response.IsSetListInboundShipmentItemsResult())
{
result = response.ListInboundShipmentItemsResult;
break;
}
else
{
Thread.Sleep(mwsPollFrequency);
count++;
}
} while (count < mwsPollTimeout);
if (count == mwsPollTimeout)
{
throw new Exception("Response from Amazon MWS timeout");
}
// create the return list
var returnList = new List<Model.AmazonFBAInbound.ShipmentItemInfo>();
// check a result was returned, return empty list on no results
if (!result.IsSetItemData())
{
return returnList;
}
// add data list
InboundShipmentItemList resultList = result.ItemData;
var infoList = new List<InboundShipmentItem>();
infoList.AddRange(resultList.member);
// check for next dataset
if (result.IsSetNextToken())
{
string nextToken = result.NextToken;
do
{
var nextRequest = new ListInboundShipmentItemsByNextTokenRequest();
var nextResult = new ListInboundShipmentItemsByNextTokenResult();
nextRequest.NextToken = nextToken;
nextRequest.SellerId = request.SellerId;
count = 0;
do
{
var response = service.ListInboundShipmentItemsByNextToken(nextRequest);
if (response.IsSetListInboundShipmentItemsByNextTokenResult())
{
nextResult = response.ListInboundShipmentItemsByNextTokenResult;
break;
}
else
{
Thread.Sleep(mwsPollFrequency);
count++;
}
} while (count < mwsPollTimeout);
if (count == mwsPollTimeout)
{
throw new Exception("Response from Amazon MWS timeout");
}
// add data to list
InboundShipmentItemList nextResultList = nextResult.ItemData;
infoList.AddRange(nextResultList.member);
if (nextResult.IsSetNextToken())
{
nextToken = nextResult.NextToken;
}
else
{
nextToken = "";
}
} while (nextToken.Length > 0); // next token is true
}
// load data set into returnList
foreach (var item in infoList)
{
var returnItem = new Model.AmazonFBAInbound.ShipmentItemInfo();
returnItem.AmazonShipmentId = item.ShipmentId;
returnItem.SKUNumber = item.SellerSKU;
returnItem.AmazonFNSKU = item.FulfillmentNetworkSKU;
if (item.IsSetQuantityShipped()) { returnItem.QuantityAllocated = (int)item.QuantityShipped; }
else { returnItem.QuantityAllocated = 0; }
if (item.IsSetQuantityReceived()) { returnItem.QuantityReceived = (int)item.QuantityReceived; }
else { returnItem.QuantityReceived = 0; }
returnList.Add(returnItem);
}
return returnList;
}
}
}

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FBAInboundServiceMWS.Model;
namespace bnhtrade.Core.Data.AmazonMWS.FBAInbound
{
public class ListInboundShipments
{
/// <summary>
/// List of Shipment Status' to return. Default is all status' returned.
/// </summary>
public List<string> ShipmentStatusList { get; set; }
/// <summary>
/// List of Shipment Id to return.
/// </summary>
public List<string> ShipmentIdList { get; set; }
public DateTime LastUpdatedAfter { get; set; }
public DateTime LastUpdatedBefore { get; set; }
public bool IsSetShipmentStatusList()
{
return ShipmentStatusList != null;
}
public bool IsSetShipmentIdList()
{
return ShipmentIdList != null;
}
public bool IsSetLastUpdatedAfter()
{
return LastUpdatedAfter != null;
}
public bool IsSetLastUpdatedBefore()
{
return LastUpdatedBefore != null;
}
public List<Core.Model.AmazonFBAInbound.ShipmentInfo> GetShipmentInfo()
{
// variables
int mwsPollFrequency = 500; // restore rate of two requests every second
int mwsPollTimeout = 60;
// at least one search variable needs to be set (to make sure EVERYTHING isn't returned)
if (!IsSetShipmentStatusList() && !IsSetShipmentIdList() && !IsSetLastUpdatedAfter() && !IsSetLastUpdatedBefore())
{
throw new Exception("No request variables have been set");
}
// date checks
if (IsSetLastUpdatedAfter() || IsSetLastUpdatedBefore())
{
if (!IsSetLastUpdatedAfter() || !IsSetLastUpdatedBefore())
{
throw new Exception("If LastUpdatedBefore or LastUpdatedAfter is specified then both parameters must be specified");
}
// set date types
DateTime.SpecifyKind(LastUpdatedAfter, DateTimeKind.Utc);
DateTime.SpecifyKind(LastUpdatedBefore, DateTimeKind.Utc);
if (LastUpdatedBefore.ToUniversalTime() < LastUpdatedAfter.ToUniversalTime())
{
throw new Exception("Parameter LastUpdatedBefore must be less than LastUpdatedAfter");
}
}
// down to business, build the mws request
var request = new ListInboundShipmentsRequest();
var cred = new AmazonMWS.CredentialMws();
request.SellerId = cred.merchantId;
// add shipment status to request
if (!IsSetShipmentStatusList() && !IsSetShipmentIdList())
{
// defaults values
var statusList = new ShipmentStatusList();
statusList.member.Add("WORKING");
statusList.member.Add("SHIPPED");
statusList.member.Add("IN_TRANSIT");
statusList.member.Add("DELIVERED");
statusList.member.Add("CHECKED_IN");
statusList.member.Add("RECEIVING");
statusList.member.Add("CLOSED");
statusList.member.Add("CANCELLED");
statusList.member.Add("DELETED");
statusList.member.Add("ERROR");
request.ShipmentStatusList = statusList;
}
else if (IsSetShipmentStatusList())
{
var statusList = new ShipmentStatusList();
foreach (string item in ShipmentStatusList)
{
statusList.member.Add(item);
}
request.ShipmentStatusList = statusList;
}
// add shipment Id list to request
if (IsSetShipmentIdList())
{
var shipmentIdList = new ShipmentIdList();
foreach (string item in ShipmentIdList)
{
shipmentIdList.member.Add(item);
}
request.ShipmentIdList = shipmentIdList;
}
// add dates to request
if (IsSetLastUpdatedAfter())
{
request.LastUpdatedAfter = LastUpdatedAfter.ToUniversalTime();
request.LastUpdatedBefore = LastUpdatedBefore.ToUniversalTime();
}
// get amazon service, responce and result
var service = new AmazonMWS.Service().FbaInbound;
var result = new ListInboundShipmentsResult();
// poll mws for response
int count = 0;
do
{
var response = service.ListInboundShipments(request);
if (response.IsSetListInboundShipmentsResult())
{
result = response.ListInboundShipmentsResult;
break;
}
else
{
Thread.Sleep(mwsPollFrequency);
count++;
}
} while (count < mwsPollTimeout);
if (count == mwsPollTimeout)
{
throw new Exception("Response from Amazon MWS timeout");
}
// check a result was returned
if (!result.IsSetShipmentData())
{
return null;
}
// add data list
InboundShipmentList resultList = result.ShipmentData;
var infoList = new List<InboundShipmentInfo>();
infoList.AddRange(resultList.member);
// check for next dataset
if (result.IsSetNextToken())
{
string nextToken = result.NextToken;
do
{
var nextRequest = new ListInboundShipmentsByNextTokenRequest();
var nextResult = new ListInboundShipmentsByNextTokenResult();
nextRequest.NextToken = nextToken;
nextRequest.SellerId = request.SellerId;
count = 0;
do
{
var response = service.ListInboundShipmentsByNextToken(nextRequest);
if (response.IsSetListInboundShipmentsByNextTokenResult())
{
nextResult = response.ListInboundShipmentsByNextTokenResult;
break;
}
else
{
Thread.Sleep(mwsPollFrequency);
count++;
}
} while (count < mwsPollTimeout);
if (count == mwsPollTimeout)
{
throw new Exception("Response from Amazon MWS timeout");
}
// add data to list
InboundShipmentList nextResultList = nextResult.ShipmentData;
infoList.AddRange(nextResultList.member);
if (nextResult.IsSetNextToken())
{
nextToken = nextResult.NextToken;
}
else
{
nextToken = "";
}
} while (nextToken.Length > 0); // next token is true
}
// build return value
var returnItem = new List<Core.Model.AmazonFBAInbound.ShipmentInfo>();
//var lastUpdated = infoList.
foreach( InboundShipmentInfo item in infoList)
{
var listItem = new Core.Model.AmazonFBAInbound.ShipmentInfo();
listItem.AmazonShipmentId = item.ShipmentId;
listItem.DestinationFulfillmentCenterId = item.DestinationFulfillmentCenterId;
listItem.ShipmentName = item.ShipmentName;
listItem.ShipmentStatus = item.ShipmentStatus;
returnItem.Add(listItem);
}
return returnItem;
}
}
}

View File

@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//using bnhtrade.Core.Data.AmazonMWS.FBAInbound;
using FBAInboundServiceMWS;
//using bnhtrade.Core.Data.AmazonMWS;
using MarketplaceWebService;
namespace bnhtrade.Core.Data.AmazonMWS
{
public class Service : CredentialMws
{
private string merchantId;
private string marketplaceId; // Amazon.co.uk
private string accessKeyId;
private string secretAccessKey;
private string applicationName;
private string applicationVersion;
private string serviceURL;
// class constructor
public Service()
{
var cred = new AmazonMWS.CredentialMws();
this.merchantId = cred.merchantId;
this.marketplaceId = cred.marketPlaceId;
this.accessKeyId = cred.accessKeyId;
this.secretAccessKey = cred.secretAccessKey;
this.applicationName = cred.applicationName;
this.applicationVersion = cred.applicationVersion;
this.serviceURL = cred.serviceURL;
}
public MarketplaceWebService.MarketplaceWebService MarketPlaceWeb
{
get
{
MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig();
config.ServiceURL = serviceURL;
MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient(
accessKeyId,
secretAccessKey,
applicationName,
applicationVersion,
config);
return service;
}
}
public global::FBAInboundServiceMWS.FBAInboundServiceMWS FbaInbound
{
get
{
FBAInboundServiceMWSConfig config = new FBAInboundServiceMWSConfig();
config.ServiceURL = serviceURL;
global::FBAInboundServiceMWS.FBAInboundServiceMWS service = new FBAInboundServiceMWSClient(
accessKeyId,
secretAccessKey,
applicationName,
applicationVersion,
config);
return service;
}
}
}
}