Migration from Amazon MWS to Selling Partner API

This commit is contained in:
Bobbie Hodgetts
2024-04-11 12:26:13 +01:00
committed by GitHub
parent e054278cdd
commit a7bc00e73a
1318 changed files with 2778105 additions and 5936 deletions
@@ -0,0 +1,78 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.Parameter.FbaInventory;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.FbaInventory
{
public class GetFbaInventoryInfo
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public List<string> MarketPlaceIds { get; set; }
/// <summary>
/// True to return inventory summaries with additional summarized inventory details and quantities.
/// Otherwise, returns inventory summaries only (the default value).
/// </summary>
public bool WithDetails { get; set; }
public GetFbaInventoryInfo()
{
}
public Dictionary<string, string> GetFnsku(List<string> skuList)
{
var returnList = new Dictionary<string, string>();
var result = GetInventorySummaries(skuList);
foreach (var list in result)
{
foreach(var item in list)
{
returnList.Add(item.SellerSku, item.FnSku);
}
}
return returnList;
}
private List<FikaAmazonAPI.AmazonSpApiSDK.Models.FbaInventory.InventorySummaries> GetInventorySummaries(List<string> skuList, DateTime? startDateTime = null)
{
var returnList = new List<FikaAmazonAPI.AmazonSpApiSDK.Models.FbaInventory.InventorySummaries>();
// max of 50 sku in one call
int i = 0;
int total = skuList.Count;
var skuRequestList = new List<string>();
foreach (string sku in skuList)
{
i++;
skuRequestList.Add(sku);
if (i == total || i % 50 == 0)
{
var parameters = new ParameterGetInventorySummaries();
//parameters.details = WithDetails;
parameters.granularityType = FikaAmazonAPI.AmazonSpApiSDK.Models.FbaInventory.Granularity.GranularityTypeEnum.Marketplace;
parameters.granularityId = new Data.Amazon.SellingPartnerAPI.Defaults().MarketPlaceIdAsString();
parameters.marketplaceIds = MarketPlaceIds;
//parameters.startDateTime = startDateTime;
parameters.sellerSkus = skuRequestList;
var lkdsjflds = amznConn.FbaInventory.GetInventorySummaries(parameters);
returnList.AddRange(lkdsjflds);
skuRequestList = new List<string>();
}
}
return returnList;
}
}
}
@@ -0,0 +1,27 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Feeds
{
public class GetFeed
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public void GetFeeds(string feedId)
{
var param = new FikaAmazonAPI.Parameter.Feed.ParameterGetFeed();
param.pageSize = 100;
param.processingStatuses = ProcessingStatuses.DONE;
param.feedTypes = new List<FeedType> { FeedType.POST_PRODUCT_PRICING_DATA };
var result = amznConn.Feed.GetFeeds(param);
}
}
}
@@ -0,0 +1,450 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Feeds;
using FikaAmazonAPI.ConstructFeed;
using FikaAmazonAPI.ConstructFeed.Messages;
using FikaAmazonAPI.Utils;
using static FikaAmazonAPI.ConstructFeed.BaseXML;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Feeds
{
public class SampleFeeds
{
AmazonConnection amazonConnection;
public SampleFeeds(AmazonConnection amazonConnection)
{
this.amazonConnection = amazonConnection;
}
public void CallFlatfile()
{
string text = System.IO.File.ReadAllText(@"C:\Users\tareq\Downloads\Beispiel_Upload.txt");
var feedresultTXT = amazonConnection.Feed.SubmitFeed(text
, FeedType.POST_FLAT_FILE_INVLOADER_DATA
, new List<string>() { MarketPlace.UnitedArabEmirates.ID }
, null
, ContentType.TXT);
string pathURL = string.Empty;
while (pathURL == string.Empty)
{
Thread.Sleep(1000 * 30);
var feedOutput = amazonConnection.Feed.GetFeed(feedresultTXT);
if (feedOutput.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Feeds.Feed.ProcessingStatusEnum.DONE)
{
var outPut = amazonConnection.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
pathURL = outPut.Url;
}
}
}
public void GetFeeds()
{
var data = amazonConnection.Feed.GetFeeds(new FikaAmazonAPI.Parameter.Feed.ParameterGetFeed()
{
processingStatuses = ProcessingStatuses.DONE,
pageSize = 100,
feedTypes = new List<FeedType> { FeedType.POST_PRODUCT_PRICING_DATA },
createdSince = DateTime.UtcNow.AddDays(-6),
createdUntil = DateTime.UtcNow.AddDays(-1),
marketplaceIds = new List<string> { MarketPlace.UnitedArabEmirates.ID }
});
}
public void CreateFeedDocument()
{
var data = amazonConnection.Feed.CreateFeedDocument(ContentType.XML);
}
public void GetFeedDocument()
{
var data2 = amazonConnection.Feed.GetFeedDocument("amzn1.tortuga.3.92d8fd38-6ccf-49be-979f-6dc27375ea3e.T2DF7HINJ0NRA2");
}
public void GetFeed()
{
var data2 = amazonConnection.Feed.GetFeed("194146018872");
}
public void CancelFeed()
{
var data2 = amazonConnection.Feed.CancelFeed("194146018872");
}
public void SubmitFeedInventory()
{
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<InventoryMessage>();
list.Add(new InventoryMessage()
{
SKU = "API.853038006021.20789.1001",
Quantity = 1
});
createDocument.AddInventoryMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_INVENTORY_AVAILABILITY_DATA);
GetFeedDetails(feedID);
}
/// <summary>
/// UnderTest
/// </summary>
public void SubmitFeedAddProductMessage(string ASIN, string SKU)
{
ConstructFeedService createDocument = new ConstructFeedService(amazonConnection.GetCurrentSellerID, "1.02");
var list = new List<ProductMessage>();
list.Add(new ProductMessage()
{
SKU = SKU,
StandardProductID = new FikaAmazonAPI.ConstructFeed.Messages.StandardProductID()
{
Type = "ASIN",
Value = ASIN
}
});
createDocument.AddProductMessage(list, OperationType.Update);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_DATA);
GetFeedDetails(feedID);
}
public void SubmitFeedDeleteAddProductMessage()
{
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<ProductMessage>();
list.Add(new ProductMessage()
{
SKU = "8432225129778...."
});
createDocument.AddProductMessage(list, OperationType.Delete);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeedContent(xml, FeedType.POST_PRODUCT_DATA);
GetFeedDetails(feedID);
}
public void AddOfferMessageMessage()
{
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<OfferMessage>();
list.Add(new OfferMessage()
{
SKU = "4049639414402_b"
});
createDocument.AddOfferMessage(list, OperationType.Delete);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_DATA);
GetFeedDetails(feedID);
}
public void SubmitFeedPRICING(double PRICE, string SKU)
{
ConstructFeedService createDocument = new ConstructFeedService(amazonConnection.GetCurrentSellerID, "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage()
{
SKU = SKU,
StandardPrice = new StandardPrice()
{
currency = amazonConnection.GetCurrentMarketplace.CurrencyCode.ToString(),
Value = (PRICE).ToString("0.00")
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_PRICING_DATA);
GetFeedDetails(feedID);
}
public async void SubmitFeedPricingWithSalePrice(string sku, decimal price, decimal salePrice, DateTime startDate, DateTime endDate)
{
var currencyCode = amazonConnection.GetCurrentMarketplace.CurrencyCode.ToString();
var createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage
{
SKU = sku,
StandardPrice = new StandardPrice
{
currency = currencyCode,
Value = price.ToString("0.00")
},
Sale = new Sale
{
SalePrice = new StandardPrice
{
currency = currencyCode,
Value = salePrice.ToString("0.00")
},
StartDate = startDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"),
EndDate = endDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:ss.fffK")
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedId = await amazonConnection.Feed.SubmitFeedAsync(xml, FeedType.POST_PRODUCT_PRICING_DATA);
GetFeedDetails(feedId);
}
public void SubmitFeedSale(double PRICE, string SKU)
{
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage()
{
SKU = SKU,
StandardPrice = new StandardPrice()
{
currency = amazonConnection.GetCurrentMarketplace.CurrencyCode.ToString(),
Value = (PRICE).ToString("0.00")
},
Sale = new Sale()
{
StartDate = DateTime.UtcNow.AddDays(+1).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"),
EndDate = DateTime.UtcNow.AddDays(+2).ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"),
SalePrice = new StandardPrice()
{
currency = amazonConnection.GetCurrentMarketplace.CurrencyCode.ToString(),
Value = (PRICE - 10).ToString("0.00")
}
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_PRICING_DATA);
GetFeedDetails(feedID);
}
public void FeebPostOrderFullfillment()
{
ConstructFeedService createDocument = new ConstructFeedService("{sellerId}", "1.02");
var list = new List<OrderFulfillmentMessage>();
list.Add(new OrderFulfillmentMessage()
{
AmazonOrderID = "{orderId}",
FulfillmentDate = DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss.fffK"),
FulfillmentData = new FulfillmentData()
{
CarrierName = "Correos Express",
ShippingMethod = "ePaq",
ShipperTrackingNumber = "{trackingNumber}"
}
});
createDocument.AddOrderFulfillmentMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_ORDER_FULFILLMENT_DATA);
GetFeedDetails(feedID);
}
public void SubmitFeedOrderAcknowledgement()
{
ConstructFeedService createDocument = new ConstructFeedService("{sellerId}", "1.02");
var list = new List<OrderAcknowledgementMessage>();
list.Add(new OrderAcknowledgementMessage()
{
AmazonOrderID = "AMZ1234567890123",
MerchantOrderID = "12345678",
StatusCode = OrderAcknowledgementStatusCode.Success,
Item = new List<OrderAcknowledgementItem>() {
new OrderAcknowledgementItem() {
AmazonOrderItemCode = "52986411826454",
MerchantOrderItemID = "1"
}
}
});
createDocument.AddOrderAcknowledgementMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_ORDER_ACKNOWLEDGEMENT_DATA);
GetFeedDetails(feedID);
}
public void SubmitFeedOrderAdjustment()
{
ConstructFeedService createDocument = new ConstructFeedService("{sellerId}", "1.02");
var list = new List<OrderAdjustmentMessage>();
list.Add(new OrderAdjustmentMessage()
{
AmazonOrderID = "AMZ1234567890123",
ActionType = AdjustmentActionType.Refund,
AdjustedItem = new List<AdjustedItem>() {
new AdjustedItem() {
AmazonOrderItemCode = "52986411826454",
AdjustmentReason = AdjustmentReason.CustomerCancel,
DirectPaymentAdjustments = new List<DirectPaymentAdjustments>()
{
new DirectPaymentAdjustments()
{
Component = new List<DirectPaymentAdjustmentsComponent>()
{
new DirectPaymentAdjustmentsComponent() {
DirectPaymentType = "Credit Card Refund",
Amount = new CurrencyAmount() {
Value = 10.50M,
currency = amazonConnection.GetCurrentMarketplace.CurrencyCode
}
}
}
}
}
}
}
});
createDocument.AddOrderAdjustmentMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PAYMENT_ADJUSTMENT_DATA);
GetFeedDetails(feedID);
}
public void CartonContentsRequestFeed()
{
ConstructFeedService createDocument2 = new ConstructFeedService("{SellerID}", "1.02");
var list22 = new List<CartonContentsRequest>();
list22.Add(new CartonContentsRequest()
{
ShipmentId = "FBA123456",
Carton = new List<Carton> {
new Carton() {
CartonId="1",
Item=new List<CartonItem>(){
new CartonItem() {
QuantityInCase=1,
QuantityShipped=1,
SKU="7004"
}
}
},
new Carton() {
CartonId="2",
Item=new List<CartonItem>(){
new CartonItem() {
QuantityInCase=12,
QuantityShipped=12,
SKU="4051",
ExpirationDate=DateTime.Now,
}
}
}
}
});
createDocument2.AddCartonContentsRequest(list22);
var xml222 = createDocument2.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml222, FeedType.POST_FBA_INBOUND_CARTON_CONTENTS);
GetFeedDetails(feedID);
}
public void SubmitFeedEasyShipDocument()
{
ConstructFeedService createDocument = new ConstructFeedService("{sellerId}", "1.02");
var list = new List<EasyShipDocumentMessage>();
list.Add(new EasyShipDocumentMessage()
{
AmazonOrderID = "AMZ1234567890123",
DocumentTypes = new List<EasyShipDocumentType>() {
EasyShipDocumentType.ShippingLabel
}
});
createDocument.AddEasyShipDocumentMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_EASYSHIP_DOCUMENTS);
GetFeedDetails(feedID);
}
public void GetFeedDetails(string feedID)
{
string ResultFeedDocumentId = string.Empty;
while (string.IsNullOrEmpty(ResultFeedDocumentId))
{
var feedOutput = amazonConnection.Feed.GetFeed(feedID);
if (feedOutput.ProcessingStatus == Feed.ProcessingStatusEnum.DONE)
{
var outPut = amazonConnection.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
var reportOutput = outPut.Url;
var processingReport = amazonConnection.Feed.GetFeedDocumentProcessingReport(outPut);
DisplayProcessingReportMessage(processingReport);
break;
}
if (!(feedOutput.ProcessingStatus == Feed.ProcessingStatusEnum.INPROGRESS ||
feedOutput.ProcessingStatus == Feed.ProcessingStatusEnum.INQUEUE))
break;
else Thread.Sleep(10000);
}
}
private void DisplayProcessingReportMessage(ProcessingReportMessage processingReport)
{
Console.WriteLine("MessagesProcessed=" + processingReport.ProcessingSummary.MessagesProcessed);
Console.WriteLine("MessagesSuccessful= " + processingReport.ProcessingSummary.MessagesSuccessful);
Console.WriteLine("MessagesWithError=" + processingReport.ProcessingSummary.MessagesWithError);
Console.WriteLine("MessagesWithWarning=" + processingReport.ProcessingSummary.MessagesWithWarning);
if (processingReport.Result != null && processingReport.Result.Count > 0)
{
foreach (var itm in processingReport.Result)
{
Console.WriteLine("ResultDescription=" + (itm.AdditionalInfo?.SKU ?? string.Empty) + " > " + itm.ResultDescription);
}
}
}
}
}
@@ -0,0 +1,113 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Feeds
{
class SubmittFeed
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
private Logic.Log.LogEvent logEvent = new Logic.Log.LogEvent();
public bool FeedSubmissionRecived { get; set; } = false;
// make these functions only accept a database object
public SubmittFeed()
{
}
public Model.Export.AmazonFeedSubmission FlatFileInvLoaderData(System.IO.MemoryStream filestream)
{
return Post("POST_FLAT_FILE_INVLOADER_DATA", filestream, "TXT");
}
private Model.Export.AmazonFeedSubmission Post(string feedType, System.IO.MemoryStream filestream, string fileExtension)
{
throw new NotImplementedException();
if (filestream.Length == 0) { throw new Exception("Filestreeam is empty"); }
if (string.IsNullOrEmpty(fileExtension)) { throw new Exception("Filestreeam is empty"); }
var feedresultTXT = amznConn.Feed.SubmitFeed(filestream.ToString()
, GetFeedType(feedType)
, new List<string>() { amznConn.GetCurrentMarketplace.ID }
, null
, ContentType.TXT);
string pathURL = string.Empty;
while (pathURL == string.Empty)
{
Thread.Sleep(1000 * 30);
var feedOutput = amznConn.Feed.GetFeed(feedresultTXT);
if (feedOutput.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Feeds.Feed.ProcessingStatusEnum.DONE)
{
var outPut = amznConn.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
pathURL = outPut.Url;
}
}
}
private FeedType GetFeedType(string feedTypeText)
{
// add more here as needed
if (feedTypeText == "POST_FLAT_FILE_INVLOADER_DATA")
{ return FeedType.POST_FLAT_FILE_INVLOADER_DATA; }
else
{ throw new NotImplementedException("Need to implement feed type for " + feedTypeText); }
}
public void SubmitFeed(Model.Export.AmazonFeedSubmission feedSubmission)
{
FeedSubmissionRecived = false;
if (feedSubmission.FileIsSet == false) { throw new Exception("Filestreeam is empty"); }
// get feed type
var feedType = GetFeedType(feedSubmission.FeedType);
string text = feedSubmission.File.FileData.ToString();
var feedresultTXT = amznConn.Feed.SubmitFeed(text
, feedType
, new List<string>() { amznConn.GetCurrentMarketplace.ID }
, null
, ContentType.TXT);
var result = new FikaAmazonAPI.AmazonSpApiSDK.Models.Feeds.FeedDocument();
int sleepTime = (1000 * 25);
int retryCount = 0;
int retryTimeout = 20;
UI.Console.Wait("Feed:" + feedType + " submitted to Amazon, awaiting status check.", 5000);
while (retryCount <= retryTimeout)
{
var feedOutput = amznConn.Feed.GetFeed(feedresultTXT);
if (feedOutput.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Feeds.Feed.ProcessingStatusEnum.DONE)
{
result = amznConn.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
break;
}
retryCount++;
UI.Console.Wait("Feed: " + feedType + ", Processing status: " + feedOutput.ProcessingStatus + ", Retry: " + retryCount + " of "+ retryTimeout, sleepTime);
}
// retry timeout
if (retryCount > retryTimeout)
{
logEvent.LogError("Feed submission timeout. Feedtype:" + feedType + " FeedSubmissionId:" + feedSubmission.FeedSubmissionId);
return;
}
// get and do somehting with this
string pathURL = string.Empty;
pathURL = result.Url;
}
}
}
@@ -0,0 +1,66 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.FulFillmentInbound
{
public class CreateInboundShipmentPlan
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public CreateInboundShipmentPlan()
{
}
public void CreatePlan(List<bnhtrade.Core.Model.AmazonFba.ShippingPlanItem> itemList)
{
throw new NotImplementedException();
// complete, but not tested (need to do something with the result)
var request = new FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.CreateInboundShipmentPlanRequest();
request.LabelPrepPreference = FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.LabelPrepPreference.SELLERLABEL;
request.ShipFromAddress.Name = ConfigurationManager.AppSettings["AmazonFbaShipFrom.Name"];
request.ShipFromAddress.AddressLine1 = ConfigurationManager.AppSettings["AmazonFbaShipFrom.AddressLine1"];
request.ShipFromAddress.AddressLine2 = ConfigurationManager.AppSettings["AmazonFbaShipFrom.AddressLine2"];
//request.ShipFromAddress.DistrictOrCounty = null; // not required
request.ShipFromAddress.City = ConfigurationManager.AppSettings["AmazonFbaShipFrom.City"];
request.ShipFromAddress.StateOrProvinceCode = ConfigurationManager.AppSettings["AmazonFbaShipFrom.StateOrProvinceCode"]; //required
request.ShipFromAddress.PostalCode = ConfigurationManager.AppSettings["AmazonFbaShipFrom.PostalCode"];
request.ShipFromAddress.CountryCode = ConfigurationManager.AppSettings["AmazonFbaShipFrom.CountryCode"];
request.ShipToCountryCode = ConfigurationManager.AppSettings["AmazonFbaShipFrom.CountryCode"];
// add item list
request.InboundShipmentPlanRequestItems = TransposeItemList(itemList);
var result = amznConn.FulFillmentInbound.CreateInboundShipmentPlan(request);
}
private InboundShipmentPlanRequestItemList TransposeItemList(List<bnhtrade.Core.Model.AmazonFba.ShippingPlanItem> itemList)
{
var returnList = new InboundShipmentPlanRequestItemList();
foreach(var item in itemList)
{
var requestItem = new InboundShipmentPlanRequestItem();
requestItem.SellerSKU = item.SkuNumber;
requestItem.ASIN = item.ASIN;
if (Enum.TryParse(item.Condition, out Condition myStatus)) { requestItem.Condition = myStatus; }
else { throw new Exception("Unable to parse string '" + item.Condition + "' to ENUM"); }
requestItem.Quantity = item.Quantity;
//requestItem.QuantityInCase;
//requestItem.PrepDetailsList;
returnList.Add(requestItem);
}
return returnList;
}
}
}
@@ -0,0 +1,128 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.FulFillmentInbound
{
public class GetShipmentItems
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public GetShipmentItems()
{
}
public List<Model.AmazonFba.ShipmentItemInfo> GetByDateRange(DateTime utcDateTimeAfter, DateTime utcDateTimeBefore)
{
var result = new List<Model.AmazonFba.ShipmentItemInfo>();
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipmentItems();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.DATE_RANGE;
parameter.LastUpdatedAfter = utcDateTimeAfter;
parameter.LastUpdatedBefore = utcDateTimeBefore;
var apiResult = amznConn.FulFillmentInbound.GetShipmentItems(parameter);
AppendNextToken(ref apiResult);
return TransposeModel(apiResult);
}
public List<Model.AmazonFba.ShipmentItemInfo> GetByShipmentId(string shipmentId)
{
var result = new List<Model.AmazonFba.ShipmentItemInfo>();
if (string.IsNullOrEmpty(shipmentId)) { return result; }
// build the request
//var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipmentItems();
//parameter.MarketplaceId = marketPlaceId;
//parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.SHIPMENT;
//parameter.ShipmentId = shipmentId;
var apiResult = amznConn.FulFillmentInbound.GetShipmentItemsByShipmentId(shipmentId);
AppendNextToken(ref apiResult);
return TransposeModel(apiResult);
}
// checks for next-token, if true appends additional data to the ShipmentData
private void AppendNextToken(ref FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.InboundShipmentItemList shipmentList)
{
while (!string.IsNullOrEmpty(shipmentList.NextToken))
{
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipmentItems();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.NEXT_TOKEN;
parameter.NextToken = shipmentList.NextToken;
var result = amznConn.FulFillmentInbound.GetShipmentItems(parameter);
shipmentList.AddRange(result);
shipmentList.NextToken = result.NextToken;
}
}
private void AppendNextToken(ref FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.GetShipmentItemsResult shipmentList)
{
while (!string.IsNullOrEmpty(shipmentList.NextToken))
{
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipmentItems();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.NEXT_TOKEN;
parameter.NextToken = shipmentList.NextToken;
var result = amznConn.FulFillmentInbound.GetShipmentItems(parameter);
shipmentList.ItemData.AddRange(result);
shipmentList.NextToken = result.NextToken;
}
}
private List<Model.AmazonFba.ShipmentItemInfo> TransposeModel(FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.InboundShipmentItemList shipmentResult)
{
var returnList = new List<Model.AmazonFba.ShipmentItemInfo>();
for (var i = 0; i < shipmentResult.Count; i++)
{
var item = new Model.AmazonFba.ShipmentItemInfo();
// under new SP-API there are more details to be used, if needed
item.AmazonFNSKU = shipmentResult[i].FulfillmentNetworkSKU;
item.AmazonShipmentId = shipmentResult[i].ShipmentId;
item.QuantityAllocated = shipmentResult[i].QuantityShipped.GetValueOrDefault();
item.QuantityReceived = shipmentResult[i].QuantityReceived.GetValueOrDefault();
item.SKUNumber = shipmentResult[i].SellerSKU;
returnList.Add(item);
}
return returnList;
}
private List<Model.AmazonFba.ShipmentItemInfo> TransposeModel(FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.GetShipmentItemsResult shipmentResult)
{
var returnList = new List<Model.AmazonFba.ShipmentItemInfo>();
for (var i = 0; i < shipmentResult.ItemData.Count; i++)
{
var item = new Model.AmazonFba.ShipmentItemInfo();
// under new SP-API there are more details to be used, if needed
item.AmazonFNSKU = shipmentResult.ItemData[i].FulfillmentNetworkSKU;
item.AmazonShipmentId = shipmentResult.ItemData[i].ShipmentId;
item.QuantityAllocated = shipmentResult.ItemData[i].QuantityShipped.GetValueOrDefault();
item.QuantityReceived = shipmentResult.ItemData[i].QuantityReceived.GetValueOrDefault();
item.SKUNumber = shipmentResult.ItemData[i].SellerSKU;
returnList.Add(item);
}
return returnList;
}
}
}
@@ -0,0 +1,110 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.FulFillmentInbound
{
public class GetShipments
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public GetShipments()
{
}
public List<Model.AmazonFba.ShipmentInfo> GetByDateRange(DateTime utcDateTimeAfter, DateTime utcDateTimeBefore)
{
// At least one of the ShipmentStatusList and ShipmentIdList must be provided
var result = new List<Model.AmazonFba.ShipmentInfo>();
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipments();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.DATE_RANGE;
parameter.LastUpdatedAfter = utcDateTimeAfter;
parameter.LastUpdatedBefore = utcDateTimeBefore;
AddShipmentStatusList(ref parameter);
var apiResult = amznConn.FulFillmentInbound.GetShipments(parameter);
AppendNextToken(ref apiResult);
return TransposeModel(apiResult);
}
public List<Model.AmazonFba.ShipmentInfo> GetByShipmentIdList(List<string> shipmentIdList)
{
var result = new List<Model.AmazonFba.ShipmentInfo>();
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipments();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.SHIPMENT;
parameter.ShipmentIdList = shipmentIdList;
var apiResult = amznConn.FulFillmentInbound.GetShipments(parameter);
AppendNextToken(ref apiResult);
return TransposeModel(apiResult);
}
private void AddShipmentStatusList(ref FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipments parameters)
{
var list = new List<ShipmentStatus>();
list.Add(ShipmentStatus.CANCELLED);
list.Add(ShipmentStatus.CHECKED_IN);
list.Add(ShipmentStatus.CLOSED);
list.Add(ShipmentStatus.DELETED);
list.Add(ShipmentStatus.DELIVERED);
list.Add(ShipmentStatus.ERROR);
list.Add(ShipmentStatus.IN_TRANSIT);
list.Add(ShipmentStatus.READY_TO_SHIP);
list.Add(ShipmentStatus.RECEIVING);
list.Add(ShipmentStatus.SHIPPED);
list.Add(ShipmentStatus.WORKING);
parameters.ShipmentStatusList = list;
}
// checks for next-token, if true appends additional data to the ShipmentData
private void AppendNextToken(ref FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.GetShipmentsResult shipmentList)
{
while (!string.IsNullOrEmpty(shipmentList.NextToken))
{
// build the request
var parameter = new FikaAmazonAPI.Parameter.FulFillmentInbound.ParameterGetShipments();
parameter.MarketplaceId = amznConn.GetCurrentMarketplace.ID;
parameter.QueryType = FikaAmazonAPI.Utils.Constants.QueryType.NEXT_TOKEN;
parameter.NextToken = shipmentList.NextToken;
var result = amznConn.FulFillmentInbound.GetShipments(parameter);
shipmentList.ShipmentData.AddRange(result.ShipmentData);
shipmentList.NextToken = result.NextToken;
}
}
// transposes return api object data to my model
private List<Model.AmazonFba.ShipmentInfo> TransposeModel(FikaAmazonAPI.AmazonSpApiSDK.Models.FulfillmentInbound.GetShipmentsResult shipmentResult)
{
var returnList = new List<Model.AmazonFba.ShipmentInfo>();
for (var i = 0; i < shipmentResult.ShipmentData.Count; i++)
{
var item = new Model.AmazonFba.ShipmentInfo();
item.FbaShipmentId = shipmentResult.ShipmentData[i].ShipmentId;
item.DestinationFulfillmentCenterId = shipmentResult.ShipmentData[i].DestinationFulfillmentCenterId;
item.ShipmentName = shipmentResult.ShipmentData[i].ShipmentName;
item.ShipmentStatus = shipmentResult.ShipmentData[i].ShipmentStatus.ToString();
returnList.Add(item);
}
return returnList;
}
}
}
@@ -0,0 +1,100 @@
//using MarketplaceWebServiceProducts.Model;
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.ProductFees;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.ProductFee
{
public class GetFeeEstimate
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public string CurrencyCode { get; set; } = "GBP";
public string MarketPlaceId { get; set; }
public GetFeeEstimate()
{
}
public Model.Amazon.ProductFeeEstimate GetFba(string asin, int productId, decimal listingPrice)
{
var returnObj = new Model.Amazon.ProductFeeEstimate();
if (string.IsNullOrWhiteSpace(asin))
{
throw new Exception("ASIN given to GetFeeEstimate is null or whitespace.");
}
var listingPriceObj = new MoneyType(CurrencyCode, listingPrice);
var priceToEstimateFees = new PriceToEstimateFees(listingPriceObj);
// create the request and get a response
var request = new FeesEstimateRequest(MarketPlaceId, true, priceToEstimateFees, productId.ToString());
var result = amznConn.ProductFee.GetMyFeesEstimateForASIN(asin, request);
if (result.FeesEstimateIdentifier.IdValue != asin)
throw new Exception("returned ud value does not match ASIN");
returnObj.Asin = asin;
returnObj.ProductId = int.Parse(result.FeesEstimateIdentifier.SellerInputIdentifier);
// test for error
if (result.Error != null)
{
var sb = new StringBuilder();
sb.AppendLine("ASIN: " + asin);
sb.AppendLine("Error Code: " + result.Error.Code);
if (result.Error.Detail != null)
{ sb.AppendLine("Detail: " + result.Error.Detail); }
if (result.Error.Message != null)
{ sb.AppendLine("Message: " + result.Error.Message); }
if (result.Error.Type != null)
{ sb.AppendLine("Type: " + result.Error.Type); }
MiscFunction.EventLogInsert("Error running GetProductEstimateFee for ASIN:" + asin + ", further details attached.", 1, sb.ToString());
throw new Exception("ProductFeeEstimate error, check logs for further details");
}
returnObj.IsAmazonFulfilled = result.FeesEstimateIdentifier.IsAmazonFulfilled.Value;
returnObj.TimeOfFeeEstimation = result.FeesEstimate.TimeOfFeesEstimation.Value;
returnObj.TotalFeeEstimate = result.FeesEstimate.TotalFeesEstimate.Amount.Value;
returnObj.CurrencyCode = result.FeesEstimate.TotalFeesEstimate.CurrencyCode;
returnObj.PriceToEstimateFeeListingPrice = result.FeesEstimateIdentifier.PriceToEstimateFees.ListingPrice.Amount.Value;
returnObj.PriceToEstimateFeeShipping = 0;
if (result.FeesEstimateIdentifier.PriceToEstimateFees.Shipping != null)
returnObj.PriceToEstimateFeeShipping = result.FeesEstimateIdentifier.PriceToEstimateFees.Shipping.Amount.Value;
returnObj.PriceToEstimateFeePoints = 0;
if (result.FeesEstimateIdentifier.PriceToEstimateFees.Points != null)
returnObj.PriceToEstimateFeePoints = result.FeesEstimateIdentifier.PriceToEstimateFees.Points.PointsMonetaryValue.Amount.Value;
returnObj.ReferralFee = 0m;
returnObj.VariableClosingFee = 0m;
returnObj.FulfillmentFees = 0m;
returnObj.PerItemFee = 0m;
returnObj.OtherFee_Exception = 0m;
FeeDetailList feeDetailList = result.FeesEstimate.FeeDetailList;
List<FeeDetail> feeDetail = feeDetailList;
foreach (FeeDetail feeDetailItem in feeDetail)
{
if (feeDetailItem.FeeType == "AmazonReferralFee" || feeDetailItem.FeeType == "ReferralFee")
{ returnObj.ReferralFee = (decimal)feeDetailItem.FinalFee.Amount; }
else if (feeDetailItem.FeeType == "VariableClosingFee")
{ returnObj.VariableClosingFee = (decimal)feeDetailItem.FinalFee.Amount; }
else if (feeDetailItem.FeeType == "PerItemFee")
{ returnObj.PerItemFee = (decimal)feeDetailItem.FinalFee.Amount; }
else if (feeDetailItem.FeeType == "FBAFees" || feeDetailItem.FeeType == "FulfillmentFees")
{ returnObj.FulfillmentFees = (decimal)feeDetailItem.FinalFee.Amount; }
else
{ returnObj.OtherFee_Exception = returnObj.OtherFee_Exception + (decimal)feeDetailItem.FinalFee.Amount; }
}
return returnObj;
}
}
}
@@ -0,0 +1,155 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.AmazonSpApiSDK.Models.ProductPricing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.ProductPricing
{
public class GetCompetitivePricing
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public string MarketPlaceId { get; set; }
/// <summary>
/// Gets Amazon Buy Box price for a given product. Will return no price if page does not have buy box
/// </summary>
public GetCompetitivePricing()
{
}
/// <summary>
/// Retrives current Buy Box price (+ additional info) for a given ASIN
/// </summary>
/// <param name="asin">Amazon ASIN product reference</param>
/// <returns></returns>
public Model.Amazon.ProductCompetitivePrice ByAsin(string asin)
{
var result = Execute(new List<string> { asin }, false);
if (result.Any()) { return result[0]; }
else { return null; }
}
/// <summary>
/// Retrives current Buy Box price (+ additional info) for a given ASIN
/// </summary>
/// <param name="asin">Amazon ASIN product reference</param>
/// <returns></returns>
public List<Model.Amazon.ProductCompetitivePrice> ByAsin(List<string> asinList)
{
return Execute(asinList, false);
}
/// <summary>
/// Ideally use ASIN
/// </summary>
/// <param name="skuList"></param>
/// <returns></returns>
private Model.Amazon.ProductCompetitivePrice BySku(string sku)
{
var result = Execute(new List<string> { sku }, true);
if (result.Any()) { return result[0]; }
else { return null; }
}
/// <summary>
/// Ideally use ASIN
/// </summary>
/// <param name="skuList"></param>
/// <returns></returns>
private List<Model.Amazon.ProductCompetitivePrice> BySku(List<string> skuList)
{
return Execute(skuList, true);
}
private List<Model.Amazon.ProductCompetitivePrice> Execute(List<string> itemList, bool isSkuList)
{
var apiList = new List<Price>();
// max of 20 items in one call
int i = 0;
int total = itemList.Count;
var itemRequestList = new List<string>();
foreach (string sku in itemList)
{
i++;
itemRequestList.Add(sku);
if (i == total || i % 20 == 0)
{
var parameter = new FikaAmazonAPI.Parameter.ProductPricing.ParameterGetCompetitivePricing();
if (isSkuList) { parameter.Skus = itemRequestList; }
else { parameter.Asins = itemRequestList; }
parameter.MarketplaceId = MarketPlaceId;
apiList.AddRange(amznConn.ProductPricing.GetCompetitivePricing(parameter));
itemRequestList = new List<string>();
}
}
return TransposeData(apiList);
}
private List<Model.Amazon.ProductCompetitivePrice> TransposeData(IList<Price> spapiList)
{
var returnList = new List<Model.Amazon.ProductCompetitivePrice>();
foreach (var item in spapiList)
{
string asin = item.ASIN;
decimal competitivePrice;
bool competitivePriceIsSet;
bool isBuyBox;
bool buyBoxBelongsToRequester;
int offersCountNew = 0;
int offersCountUsed = 0;
if (item.Product.CompetitivePricing.CompetitivePrices.Count == 0)
{
competitivePrice = 0;
competitivePriceIsSet = false;
isBuyBox = false;
buyBoxBelongsToRequester = false;
}
else if (item.Product.CompetitivePricing.CompetitivePrices.Count == 1)
{
if (item.Product.CompetitivePricing.CompetitivePrices[0].Condition != "New")
throw new Exception("Condition returned is not new");
competitivePrice = item.Product.CompetitivePricing.CompetitivePrices[0].Price.LandedPrice.Amount.Value;
competitivePriceIsSet = true;
isBuyBox = true;
buyBoxBelongsToRequester = item.Product.CompetitivePricing.CompetitivePrices[0].BelongsToRequester.Value;
}
else
{
throw new Exception("More than one competitive price returned");
}
// get quanities
foreach (var offer in item.Product.CompetitivePricing.NumberOfOfferListings)
{
if (offer.Condition == "New") { offersCountNew = offer.Count.Value; }
if (offer.Condition == "Used") { offersCountUsed = offer.Count.Value; }
}
// add to list
var returnItem = new Model.Amazon.ProductCompetitivePrice(
asin
, competitivePrice
, competitivePriceIsSet
, isBuyBox
, buyBoxBelongsToRequester
, offersCountNew
, offersCountUsed);
returnList.Add(returnItem);
}
return returnList;
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaCustomerReturn : ReportLogic
{
public FbaCustomerReturn() : base(ReportTypes.GET_FBA_FULFILLMENT_CUSTOMER_RETURNS_DATA)
{
}
public void GetReport(DateTime startTime, DateTime endTime)
{
int maxRange = 0; // there doesn't appear to be any limit on time span
DownloadTimePeriodReport(startTime, endTime, maxRange);
}
}
}
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaInventory : ReportLogic
{
public FbaInventory() : base (ReportTypes.GET_FBA_MYI_ALL_INVENTORY_DATA)
{
}
public void GetReport(int reportMaxAge = 30)
{
// Amazon will throttle (return 'FATAL' error) when requesting this report twice within 15 minutes
DownloadSnapshotReport(reportMaxAge);
}
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaInventoryAdustment : ReportLogic
{
public FbaInventoryAdustment() : base(ReportTypes.GET_FBA_FULFILLMENT_INVENTORY_ADJUSTMENTS_DATA)
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
}
public void GetReport(DateTime startTime, DateTime endTime)
{
DownloadTimePeriodReport(startTime, endTime, 0);
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaInventoryAge : ReportLogic
{
public FbaInventoryAge() : base(ReportTypes.GET_FBA_INVENTORY_AGED_DATA)
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
}
public new void GetReport(int reportMaxAge = 30)
{
throw new Exception("GET_FBA_INVENTORY_AGED_DATA report has been retired since 22/06/2022 and replaced by GET_FBA_INVENTORY_PLANNING_DATA");
//DownloadSnapshotReport(reportMaxAge);
}
}
}
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaInventoryReceipt : ReportLogic
{
/*
* Not able to uniquley define each row in flat file and check for duplicate in DB
* therefore, do not download report date range that has already been imported, as records will be duplicated
*
* Due to a MWS bug, MWS can/will include some records that are before the specified date range. As mws report is updated once daily,
* it is safe to omitt lines < startDate when parsing/inserting lines into db (as these will have been previously imported)
*/
public FbaInventoryReceipt() : base(ReportTypes.GET_FBA_FULFILLMENT_INVENTORY_RECEIPTS_DATA)
{
throw new Exception("report has been depreciated https://developer-docs.amazon.com/sp-api/docs/sp-api-deprecations");
}
public void GetReport(DateTime startTime, DateTime endTime)
{
DownloadTimePeriodReport(startTime, endTime, 0);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaReimbursement : ReportLogic
{
public FbaReimbursement() : base(ReportTypes.GET_FBA_REIMBURSEMENTS_DATA)
{
}
public void GetReport(DateTime startTime, DateTime endTime)
{
DownloadTimePeriodReport(startTime, endTime, 0);
}
}
}
@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaRemovalOrder : ReportLogic
{
public FbaRemovalOrder() : base(ReportTypes.GET_FBA_FULFILLMENT_REMOVAL_ORDER_DETAIL_DATA)
{
}
public void GetReport(DateTime startTime, DateTime endTime)
{
DownloadTimePeriodReport(startTime, endTime, 0);
}
}
}
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class FbaSaleShipment : ReportLogic
{
//public FbaSaleShipment() : base(ReportTypes.GET_FBA_FULFILLMENT_CUSTOMER_SHIPMENT_SALES_DATA)
public FbaSaleShipment() : base(ReportTypes.GET_AMAZON_FULFILLED_SHIPMENTS_DATA_GENERAL)
{
}
public void GetReport(DateTime startTime, DateTime endTime)
{
DownloadTimePeriodReport(startTime, endTime, 30);
}
}
}
@@ -0,0 +1,236 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.Parameter.Report;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class ReportLogic
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
private FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report;
private ReportTypes reportType;
protected Logic.Log.LogEvent log = new Logic.Log.LogEvent();
public DateTime? ReportCreatedTime
{
get
{
if (report == null) { return null; }
else { return report.CreatedTime; }
}
}
public bool ReportDoneNoData { get; private set; }
public string ReportFilePath { get; private set; }
private FikaAmazonAPI.Utils.MarketplaceIds MarketPlaceIds { get; set; }
public bool ReportFilePathIsSet
{
get { return !string.IsNullOrWhiteSpace(ReportFilePath); }
}
public ReportLogic(ReportTypes reportType)
{
this.reportType = reportType;
this.MarketPlaceIds = new MarketplaceIds();
this.MarketPlaceIds.Add(amznConn.GetCurrentMarketplace.ID);
Innit();
}
private void Innit()
{
ReportDoneNoData = false;
ReportFilePath = null;
report = null;
}
/// <summary>
/// Always use this function to report and it's filepath, this ensures the two correlate
/// </summary>
/// <param name="report"></param>
/// <param name="reportFilePath"></param>
private void SetFilePath(FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, string reportFilePath)
{
this.report = report;
this.ReportFilePath = reportFilePath;
}
protected void DownloadTimePeriodReport(DateTime utcDataStartTime, DateTime utcDataEndTime, int maxDateRangeDays)
{
if (utcDataStartTime.Kind != DateTimeKind.Utc || utcDataEndTime.Kind != DateTimeKind.Utc)
throw new Exception("Report period time should be set to UTC");
if (maxDateRangeDays > 0 && (utcDataEndTime - utcDataStartTime).TotalDays > maxDateRangeDays)
throw new Exception("Date range for report is greater than the maximum allowable");
var specification = new ParameterCreateReportSpecification();
specification.marketplaceIds = this.MarketPlaceIds;
specification.reportType = reportType;
specification.dataStartTime = utcDataStartTime;
specification.dataEndTime = utcDataEndTime;
DownloadReport(specification, false);
}
protected void DownloadSnapshotReport(int snapshotMaxAge)
{
var specification = new ParameterCreateReportSpecification();
specification.marketplaceIds = this.MarketPlaceIds;
specification.reportType = reportType;
DownloadReport(specification, true, snapshotMaxAge);
}
private void DownloadReport(ParameterCreateReportSpecification specification, bool isSnapshotReport, int snapshotMaxAge = 0)
{
// Amazon create report is throttled to 1 report every 15 minutes
Innit();
// check for existing report with same specification
string reportId = ExistingReportSearch(specification);
if (reportId == null)
{ reportId = amznConn.Reports.CreateReport(specification); }
var filePath = amznConn.Reports.GetReportFile(reportId);
var report = amznConn.Reports.GetReport(reportId); // filePath and report need to be called in this order
if (!string.IsNullOrWhiteSpace(filePath))
{
SetFilePath(report, filePath);
return;
}
else
{
// test for 'Fatal' return when report has recently been requested.
report = amznConn.Reports.GetReport(reportId);
if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED)
{
// From SPAPI Documentation: The report was cancelled. There are two ways a report can be cancelled:
// an explicit cancellation request before the report starts processing, or an automatic cancellation
// if there is no data to return.
log.Initialise();
log.LogInformation("ReportID:" + reportId + " returned 'CANCELLED' status (no data).");
ReportDoneNoData = true;
return;
}
else if (report.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
if (isSnapshotReport)
{
SnapahotThrottleHanderler(ref report, specification, snapshotMaxAge);
filePath = amznConn.Reports.GetReportFile(report.ReportId);
if (string.IsNullOrWhiteSpace(filePath))
{
LogReportError(report, "Error while retriving report " + reportType.ToString());
throw new Exception("Error while retriving report " + reportType.ToString());
}
SetFilePath(report, filePath);
return;
}
else
{
throw new Exception("Report processing status returned 'FATAL' report#" + reportType.ToString());
}
}
}
throw new Exception("Error while retriving " + reportType.ToString() + " report, nothing should be getting here!!");
}
/// <summary>
/// If a duplicate report has been recently requested, Amazon may return 'FATAL'. This method tests for, and attempts to retrive the duplicate report that is causing the error.
/// </summary>
/// <param name="report">Report to test for throttled response</param>
/// <param name="specification">The specification that created to throttle report.</param>
private void SnapahotThrottleHanderler(ref FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, ParameterCreateReportSpecification specification, int snapshotMaxAge)
{
if (report.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
return;
if (snapshotMaxAge <= 0)
{
// report not avaiable
throw new Exception( reportType.ToString() + " report not avaibale for requested timeframe");
}
// search for valid reports with required timeframe
var parameters = new ParameterReportList();
parameters.reportTypes = new List<ReportTypes> { specification.reportType };
parameters.createdSince = report.CreatedTime.Value.AddMinutes(-snapshotMaxAge);
parameters.marketplaceIds = specification.marketplaceIds;
var reports = amznConn.Reports.GetReports(parameters);
if (reports == null || !reports.Any())
{
return;
}
foreach (var item in reports)
{
if (item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED
&& item.ProcessingStatus != FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
{
report = item;
}
}
}
private string ExistingReportSearch(ParameterCreateReportSpecification specification)
{
// amazon may return 'fatal' due to report already existing and/or report request matches an recent existing request
// search for valid reports with required timeframe
var parameters = new ParameterReportList();
parameters.reportTypes = new List<ReportTypes> { specification.reportType };
parameters.marketplaceIds = specification.marketplaceIds;
var reportList = amznConn.Reports.GetReports(parameters);
// list is ordered with the most recent first
foreach (var item in reportList)
{
if (item.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.DONE
|| item.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INPROGRESS
|| item.ProcessingStatus == FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report.ProcessingStatusEnum.INQUEUE)
{
if(item.DataStartTime == specification.dataStartTime
&& item.DataEndTime == specification.dataEndTime)
{
return item.ReportId;
}
}
}
return null;
}
private void LogReportError(FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report report, string errorTitle)
{
log.Initialise();
log.LogError(errorTitle,
"ReportType: " + report.ReportType + "\r\n"
+ "ReportId: " + report.ReportId + "\r\n"
+ "MarketplaceIds: " + report.MarketplaceIds + "\r\n"
+ "CreatedTime: " + report.CreatedTime + "\r\n"
+ "ReportScheduleId: " + report.ReportScheduleId + "\r\n"
+ "ReportDocumentId: " + report.ReportDocumentId + "\r\n"
+ "DataStartTime: " + report.DataStartTime + "\r\n"
+ "DataEndTime: " + report.DataEndTime + "\r\n"
+ "ProcessingStartTime: " + report.ProcessingStartTime + "\r\n"
+ "ProcessingEndTime: " + report.ProcessingEndTime + "\r\n"
+ "ProcessingStatus: " + report.ProcessingStatus + "\r\n"
);
}
}
}
@@ -0,0 +1,52 @@
using bnhtrade.Core.Data.Amazon.SellingPartnerAPI;
using FikaAmazonAPI;
using FikaAmazonAPI.Parameter.Report;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.Report
{
public class SettlementReport
{
private AmazonConnection amznConn = new SpApiConnection().Connection;
public SettlementReport ()
{
}
/// <summary>
/// Gets a list of reportId (not settlement report Id) for settlement reports available on the amazon api
/// </summary>
/// <returns>ReportId list</returns>
public List<string> ListAvaliableReports()
{
UI.Console.WriteLine("Requesting list of avaliable settlement reports form Amazon SP-API");
// set parameters
var parameters = new ParameterReportList();
parameters.reportTypes = new List<ReportTypes>() { ReportTypes.GET_V2_SETTLEMENT_REPORT_DATA_FLAT_FILE_V2};
parameters.marketplaceIds.Add(amznConn.GetCurrentMarketplace.ID);
// request from amazon
var result = amznConn.Reports.GetReports(parameters);
var returnList = new List<string>();
foreach (var report in result)
{
returnList.Add(report.ReportId);
}
UI.Console.WriteLine("{0} Settlement reports avaible on Amazon SP-API");
return returnList;
}
public string GetFile(string reportId)
{
return amznConn.Reports.GetReportFile(reportId);
}
}
}
@@ -0,0 +1,122 @@
////using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Services;
//using FikaAmazonAPI.Services;
//using System;
//using System.Collections.Generic;
//using System.Text;
//namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
//{
// public class AmazonConnection
// {
// private AmazonCredential Credentials { get; set; }
// public FbaInboundService FbaInbound => this._FbaInbound ?? throw _NoCredentials;
// public FbaInventoryService FbaInventory => this._FbaInventory ?? throw _NoCredentials;
// public FulFillmentInboundService FulFillmentInbound => this._FulFillmentInbound ?? throw _NoCredentials;
// public ProductFeeService ProductFee => this._ProductFee ?? throw _NoCredentials;
// public ProductPricingService ProductPricing => this._ProductPricing ?? throw _NoCredentials;
// public ReportService Reports => this._Reports ?? throw _NoCredentials;
// //public AplusContentService AplusContent => this._AplusContent ?? throw _NoCredentials;
// //public AuthorizationService Authorization => this._Authorization ?? throw _NoCredentials;
// //public CatalogItemService CatalogItem => this._CatalogItems ?? throw _NoCredentials;
// //public FbaInboundEligibilityService FbaInboundEligibility => this._FbaInboundEligibility ?? throw _NoCredentials;
// //public FbaOutboundService FbaOutbound => this._FbaOutbound ?? throw _NoCredentials;
// //public FbaSmallandLightService FbaSmallandLight => this._FbaSmallandLight ?? throw _NoCredentials;
// //public FeedService Feed => this._Feed ?? throw _NoCredentials;
// //public FinancialService Financial => this._Financials ?? throw _NoCredentials;
// //public FulFillmentOutboundService FulFillmentOutbound => this._FulFillmentOutbound ?? throw _NoCredentials;
// //public ListingsItemService ListingsItem => this._ListingsItem ?? throw _NoCredentials;
// //public MerchantFulfillmentService MerchantFulfillment => this._MerchantFulfillment ?? throw _NoCredentials;
// //public MessagingService Messaging => this._Messaging ?? throw _NoCredentials;
// //public NotificationService Notification => this._Notification ?? throw _NoCredentials;
// //public OrderService Orders => this._Orders ?? throw _NoCredentials;
// //public SalesService Sales => this._Sales ?? throw _NoCredentials;
// //public SellerService Seller => this._Seller ?? throw _NoCredentials;
// //public ServicesService Services => this._Services ?? throw _NoCredentials;
// //public ShipmentInvoicingService ShipmentInvoicing => this._ShipmentInvoicing ?? throw _NoCredentials;
// //public ShippingService Shipping => this._Shipping ?? throw _NoCredentials;
// //public SolicitationService Solicitations => this._Solicitations ?? throw _NoCredentials;
// //public TokenService Tokens => this._Tokens ?? throw _NoCredentials;
// //public UploadService Upload => this._Upload ?? throw _NoCredentials;
// private FbaInboundService _FbaInbound { get; set; }
// private FbaInventoryService _FbaInventory { get; set; }
// private FulFillmentInboundService _FulFillmentInbound { get; set; }
// private ProductFeeService _ProductFee { get; set; }
// private ProductPricingService _ProductPricing { get; set; }
// private ReportService _Reports { get; set; }
// //private AplusContentService _AplusContent { get; set; }
// //private AuthorizationService _Authorization { get; set; }
// //private CatalogItemService _CatalogItems { get; set; }
// //private FbaInboundEligibilityService _FbaInboundEligibility { get; set; }
// //private FbaOutboundService _FbaOutbound { get; set; }
// //private FbaSmallandLightService _FbaSmallandLight { get; set; }
// private FeedService _Feed { get; set; }
// //private FinancialService _Financials { get; set; }
// //private FulFillmentOutboundService _FulFillmentOutbound { get; set; }
// //private ListingsItemService _ListingsItem { get; set; }
// //private MerchantFulfillmentService _MerchantFulfillment { get; set; }
// //private MessagingService _Messaging { get; set; }
// //private NotificationService _Notification { get; set; }
// //private OrderService _Orders { get; set; }
// //private SalesService _Sales { get; set; }
// //private SellerService _Seller { get; set; }
// //private ServicesService _Services { get; set; }
// //private ShipmentInvoicingService _ShipmentInvoicing { get; set; }
// //private ShippingService _Shipping { get; set; }
// //private SolicitationService _Solicitations { get; set; }
// //private TokenService _Tokens { get; set; }
// //private UploadService _Upload { get; set; }
// private UnauthorizedAccessException _NoCredentials = new UnauthorizedAccessException($"Error, you cannot make calls to Amazon without credentials!");
// public AmazonConnection(AmazonCredential Credentials)
// {
// this.Authenticate(Credentials);
// }
// public void Authenticate(AmazonCredential Credentials)
// {
// if (this.Credentials == default(AmazonCredential))
// Init(Credentials);
// else
// throw new InvalidOperationException("Error, you are already authenticated to amazon in this AmazonConnection, dispose of this connection and create a new one to connect to a different account.");
// }
// private void Init(AmazonCredential Credentials)
// {
// this.Credentials = Credentials;
// this._FbaInbound = new FbaInboundService(this.Credentials);
// this._FbaInventory = new FbaInventoryService(this.Credentials);
// this._FulFillmentInbound = new FulFillmentInboundService(this.Credentials);
// this._ProductFee = new ProductFeeService(this.Credentials);
// this._ProductPricing = new ProductPricingService(this.Credentials);
// this._Reports = new ReportService(this.Credentials);
// //this._AplusContent = new AplusContentService(this.Credentials);
// //this._CatalogItems = new CatalogItemService(this.Credentials);
// //this._FbaInboundEligibility = new FbaInboundEligibilityService(this.Credentials);
// //this._FbaOutbound = new FbaOutboundService(this.Credentials);
// //this._FbaSmallandLight = new FbaSmallandLightService(this.Credentials);
// this._Feed = new FeedService(this.Credentials);
// //this._Financials = new FinancialService(this.Credentials);
// //this._FulFillmentOutbound= new FulFillmentOutboundService(this.Credentials);
// //this._ListingsItem = new ListingsItemService(this.Credentials);
// //this._MerchantFulfillment = new MerchantFulfillmentService(this.Credentials);
// //this._Messaging= new MessagingService(this.Credentials);
// //this._Notification= new NotificationService(this.Credentials);
// //this._Orders = new OrderService(this.Credentials);
// //this._Sales= new SalesService(this.Credentials);
// //this._Seller= new SellerService(this.Credentials);
// //this._Services= new ServicesService(this.Credentials);
// //this._ShipmentInvoicing= new ShipmentInvoicingService(this.Credentials);
// //this._Shipping= new ShippingService(this.Credentials);
// //this._Solicitations = new SolicitationService(this.Credentials);
// //this._Tokens= new TokenService(this.Credentials);
// //this._Upload= new UploadService(this.Credentials);
// }
// }
//}
@@ -0,0 +1,103 @@
//using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.SDK.Models.Token;
//using bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Utils;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Token;
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Text;
using static FikaAmazonAPI.AmazonSpApiSDK.Models.Token.CacheTokenData;
using static FikaAmazonAPI.Utils.Constants;
//using static bnhtrade.Core.Data.Amazon.SellingPartnerAPI.SDK.Models.Token.CacheTokenData;
//using static bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Utils.Constants;
namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
public class AmazonCredential
{
public string AccessKey { get; set; }
public string SecretKey { get; set; }
public string RoleArn { get; set; }
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string RefreshToken { get; set; }
public MarketPlace MarketPlace { get; set; }
private CacheTokenData CacheTokenData { get; set; } = new CacheTokenData();
public bool IsActiveLimitRate { get; set; } = true;
public Environments Environment { get; set; } = Environments.Production;
public AmazonCredential()
{
// attempt to retrive credentials from app.local.config
try
{
Innit(ConfigurationManager.AppSettings["SpapiAccessKey"]
, ConfigurationManager.AppSettings["SpapiSecretKey"]
, ConfigurationManager.AppSettings["SpapiRoleArn"]
, ConfigurationManager.AppSettings["SpapiClientId"]
, ConfigurationManager.AppSettings["SpapiClientSecret"]
, ConfigurationManager.AppSettings["SpapiRefreshToken"]);
if (!string.IsNullOrWhiteSpace(ConfigurationManager.AppSettings["SpapiMarketplaceId"]))
{
this.MarketPlace = MarketPlace.UnitedKingdom;
}
}
catch (Exception ex)
{
throw new Exception("Unable to retirve Amazon SP API credentials: " + ex.Message);
}
}
private AmazonCredential(string accessKey, string secretKey, string roleArn, string clientId, string clientSecret, string refreshToken)
{
// Use other method by default, however can change this method back to public is the need arises.
Innit(accessKey
, secretKey
, roleArn
, clientId
, clientSecret
, refreshToken);
}
public AmazonCredential(Core.Model.Credentials.AmazonSPAPI userCredentials)
{
Innit(userCredentials.AccessKey
, userCredentials.SecretKey
, userCredentials.RoleArn
, userCredentials.ClientId
, userCredentials.ClientSecret
, userCredentials.RefreshToken);
}
private void Innit(string accessKey, string secretKey, string roleArn, string clientId, string clientSecret, string refreshToken)
{
this.AccessKey = accessKey;
this.SecretKey = secretKey;
this.RoleArn = roleArn;
this.ClientId = clientId;
this.ClientSecret = clientSecret;
this.RefreshToken = refreshToken;
}
public TokenResponse GetToken(TokenDataType tokenDataType)
{
return CacheTokenData.GetToken(tokenDataType);
}
public void SetToken(TokenDataType tokenDataType, TokenResponse token)
{
CacheTokenData.SetToken(tokenDataType, token);
}
public AWSAuthenticationTokenData GetAWSAuthenticationTokenData()
{
return CacheTokenData.GetAWSAuthenticationTokenData();
}
public void SetAWSAuthenticationTokenData(AWSAuthenticationTokenData tokenData)
{
CacheTokenData.SetAWSAuthenticationTokenData(tokenData);
}
}
}
@@ -0,0 +1,22 @@
using FikaAmazonAPI.Utils;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
public class Defaults
{
public MarketPlace MarketPlaceId()
{
return MarketPlace.GetMarketPlaceByID(ConfigurationManager.AppSettings["SpapiMarketplaceId"]);
}
public string MarketPlaceIdAsString()
{
return ConfigurationManager.AppSettings["SpapiMarketplaceId"];
}
}
}
@@ -0,0 +1,318 @@
//using System;
//using System.Collections.Generic;
//using System.IO;
//using System.Text;
//namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Services
//{
// public class ReportService : RequestService
// {
// private Dictionary<string, RestSharp.RestResponse<SDK.Models.Reports.Report>> reportList;
// private Dictionary<string, string> filePath;
// private bool fatalEncounter = false;
// protected Logic.Log.LogEvent log = new Logic.Log.LogEvent();
// private int reportRequestCount = 0;
// public ReportService() : base (new AmazonCredential())
// {
// Innit();
// }
// public ReportService(AmazonCredential amazonCredential) : base(amazonCredential)
// {
// Innit();
// }
// public void Innit()
// {
// reportList = new Dictionary<string, RestSharp.RestResponse<FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report>>();
// filePath = new Dictionary<string, string>();
// }
// public FikaAmazonAPI.AmazonSpApiSDK.Models.Reports.Report GetReport(string reportId, bool forceRequery = false)
// {
// // Rate limit: 2.0 requests per second, 15 burst
// int rateLimitMilliseconds = 500;
// if (reportList.ContainsKey(reportId))
// {
// if (forceRequery)
// {
// reportList.Remove(reportId);
// }
// else
// {
// return reportList[reportId].Data;
// }
// }
// // request report form amaozn
// if (reportRequestCount == 0)
// {
// UI.Console.WriteLine("Requesting report from amazon SPAPI (ReportId:" + reportId + ").");
// reportRequestCount = reportRequestCount + 1;
// }
// CreateAuthorizedRequest(ReportApiUrls.GetReport(reportId), RestSharp.Method.Get);
// var response = ExecuteRequestWithHttpInfo<SDK.Models.Reports.Report>(rateLimitMilliseconds);
// if (response == null)
// { return null; }
// reportList.Add(response.Data.ReportId, response);
// return response.Data;
// }
// public List<SDK.Models.Reports.Report> GetReports(ParameterReportList parameterReportList)
// {
// var parameters = parameterReportList.getParameters();
// CreateAuthorizedRequest(ReportApiUrls.GetReports, RestSharp.Method.Get, parameters);
// var response = ExecuteRequest<GetReportsResponseV00>();
// parameterReportList.nextToken = response.NextToken;
// var list = response.Reports;
// while (!string.IsNullOrEmpty(parameterReportList.nextToken))
// {
// var nextTokenResponse = GetReportsByNextToken(parameterReportList);
// list.AddRange(nextTokenResponse.Reports);
// parameterReportList.nextToken = nextTokenResponse.NextToken;
// }
// return list;
// }
// public bool CancelReport(string reportId)
// {
// CreateAuthorizedRequest(ReportApiUrls.CancelReport(reportId), RestSharp.Method.Delete);
// var response = ExecuteRequest<CancelReportResponse>();
// if (response != null && response.Errors != null)
// return false;
// return true;
// }
// public ReportScheduleList GetReportSchedules(ParameterReportSchedules parametersSchedules)
// {
// var parameters = parametersSchedules.getParameters();
// CreateAuthorizedRequest(ReportApiUrls.GetReportSchedules, RestSharp.Method.Get, parameters);
// var response = ExecuteRequest<GetReportSchedulesResponseV00>();
// if (response != null && response.ReportSchedules != null)
// return response.ReportSchedules;
// return null;
// }
// private GetReportsResponseV00 GetReportsByNextToken(ParameterReportList parameterReportList)
// {
// var parameterReportListNew = new ParameterReportList();
// parameterReportListNew.nextToken = parameterReportList.nextToken;
// var parameters = parameterReportListNew.getParameters();
// CreateAuthorizedRequest(ReportApiUrls.GetReports, RestSharp.Method.Get, parameters);
// var response = ExecuteRequest<GetReportsResponseV00>();
// return response;
// }
// public string CreateReport(ParameterCreateReportSpecification createReportSpecification)
// {
// CreateAuthorizedRequest(ReportApiUrls.CreateReport, RestSharp.Method.Post, null, createReportSpecification);
// var response = ExecuteRequest<SDK.Models.Reports.CreateReportResult>();
// if (response == null)
// return null;
// string reportId = response.ReportId;
// return response.ReportId;
// }
// public string CreateReportSchedule(ParameterCreateReportScheduleSpecification createReportScheduleSpecification)
// {
// CreateAuthorizedRequest(ReportApiUrls.CreateReportSchedule, RestSharp.Method.Post, null, createReportScheduleSpecification);
// var response = ExecuteRequest<CreateReportScheduleResult>();
// if (response == null)
// return null;
// return response.ReportScheduleId;
// }
// public ReportSchedule GetReportSchedule(string reportScheduleId)
// {
// CreateAuthorizedRequest(ReportApiUrls.GetReportSchedule(reportScheduleId), RestSharp.Method.Get);
// var response = ExecuteRequest<ReportSchedule>();
// if (response != null)
// return response;
// return null;
// }
// public ReportDocument GetReportDocument(string reportDocumentId, IParameterBasedPII ParameterBasedPII = null)
// {
// CreateAuthorizedRequest(ReportApiUrls.GetReportDocument(reportDocumentId), RestSharp.Method.Get, parameter: ParameterBasedPII);
// var response = ExecuteRequest<ReportDocument>();
// if (response != null)
// return response;
// return null;
// }
// public bool WaitForReportProcessing(SDK.Models.Reports.Report report)
// {
// // wait for report processing loop
// int checkCount = 0;
// int checkRequency = 10000;
// while (true)
// {
// checkCount++;
// if (checkCount > 60)
// {
// throw new Exception("GetReport timedout requesting reportId:" + report.ReportId + ".");
// }
// if (report.ProcessingStatus == SDK.Models.Reports.Report.ProcessingStatusEnum.DONE)
// {
// UI.Console.WriteLine("Report proccessing status is 'DONE' (ReportId:" + report.ReportId + ").");
// return true;
// }
// else if (report.ProcessingStatus == SDK.Models.Reports.Report.ProcessingStatusEnum.INPROGRESS)
// {
// // wait for 10 seconds between chacks
// UI.Console.Wait("Report processing 'In Progress'. Updating in {0} seconds...", checkRequency);
// report = GetReport(report.ReportId, true);
// }
// else if (report.ProcessingStatus == SDK.Models.Reports.Report.ProcessingStatusEnum.INQUEUE)
// {
// // wait for 10 seconds between chacks
// UI.Console.Wait("Report processing 'In Queue'. Updating in {0} seconds...", checkRequency);
// report = GetReport(report.ReportId, true);
// }
// else if (report.ProcessingStatus == SDK.Models.Reports.Report.ProcessingStatusEnum.CANCELLED)
// {
// // when report has been cancelled by client or amazon (no data)
// return false;
// }
// else if (report.ProcessingStatus == SDK.Models.Reports.Report.ProcessingStatusEnum.FATAL)
// {
// // some report requests will return a 'FATAL' if they have already been requsted recently (15 minutes).
// return false;
// }
// else
// {
// throw new Exception("New ReportProcessingStatusEnum '" + report.ProcessingStatus + "' "
// + " found for reportid:" + report.ReportId);
// }
// }
// }
// /// <summary>
// /// Retrives file containing Amazon SP-API report
// /// </summary>
// /// <param name="reportId">Amazon SP-API unique report id</param>
// /// <returns>File path for report</returns>
// public string GetReportFile(string reportId)
// {
// if (string.IsNullOrWhiteSpace(reportId))
// {
// throw new Exception("invalid Report ID");
// }
// // check for cached filepath
// if (!filePath.ContainsKey(reportId))
// {
// var report = GetReport(reportId); // this can return null, need to deal with this
// if (WaitForReportProcessing(report))
// {
// // download report from url
// string reportFilePath = GetFile(reportId);
// filePath.Add(reportId, reportFilePath);
// return reportFilePath;
// }
// else
// {
// return null;
// }
// }
// return filePath[reportId];
// }
// private string GetFile(string reportId)
// {
// // fatal error and reportDoument Id check
// if (fatalEncounter)
// {
// if (string.IsNullOrWhiteSpace(reportList[reportId].Data.ReportDocumentId))
// {
// log.LogError("Fatal error from Amazon SPAPI when requesting reportId:" + reportId
// , "The reason for the fatal error is unknown, no document was available for further information.");
// return "FATAL";
// }
// else
// {
// log.LogError("Fatal error from Amazon SPAPI when requesting reportId:" + reportId
// , "The report was aborted due to a fatal error and a reportDocumentId is present. Check reportDocumentId as it may explain why the report processing ended.");
// }
// fatalEncounter = false;
// }
// // as file url expires after 5 minutes, request just before download
// UI.Console.WriteLine("Requesting download url for Amazon report (ReportId:" + reportId + ").");
// var reportDocument = GetReportDocument(reportList[reportId].Data.ReportDocumentId);
// // download report from url
// log.LogInformation("Downloading Amazon report #" + reportId, "Report Document ID: " + reportDocument.ReportDocumentId);
// var response = new byte[0];
// using (var webClient = new System.Net.WebClient())
// {
// response = webClient.DownloadData(reportDocument.Url);
// }
// string report = null;
// // decrypt report
// UI.Console.WriteLine("Processing download (ReportId:" + reportId + ").");
// if (reportDocument.EncryptionDetails != null)
// {
// byte[] key = Encoding.ASCII.GetBytes(reportDocument.EncryptionDetails.Key);
// byte[] iv = Encoding.ASCII.GetBytes(reportDocument.EncryptionDetails.InitializationVector);
// report = Logic.Utilities.FileTransform.DecryptString(key, iv, response);
// }
// else
// {
// report = Encoding.ASCII.GetString(response);
// }
// // decompress
// if (reportDocument.CompressionAlgorithm != null)
// {
// report = Logic.Utilities.FileTransform.Decompress(report);
// }
// // save to file
// string reportFilePath = MiscFunction.GetTempFilePath(reportId + ".txt");
// System.IO.File.WriteAllText(reportFilePath, report);
// log.LogInformation("Amazon report #" + reportId + " sucessfully saved to disk.");
// return reportFilePath;
// }
// public bool CancelReportSchedule(string reportScheduleId)
// {
// CreateAuthorizedRequest(ReportApiUrls.CancelReportSchedule(reportScheduleId), RestSharp.Method.Delete);
// var response = ExecuteRequest<CancelReportScheduleResponse>();
// if (response != null && response.Errors != null)
// return false;
// return true;
// }
// protected void SleepForRateLimit(IList<RestSharp.Parameter> headers)
// {
// // get report has limit rate 0.0222 per second (1 every 45 seconds) and a burst of 10
// int defaultTime = 46000;
// SleepForRateLimit(headers, defaultTime);
// }
// }
//}
@@ -0,0 +1,50 @@
using FikaAmazonAPI;
using FikaAmazonAPI.Utils;
using FikaAmazonAPI.AmazonSpApiSDK.Models.Token;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static FikaAmazonAPI.AmazonSpApiSDK.Services.EnvironemntManager;
namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI
{
class SpApiConnection
{
public AmazonConnection Connection { get; private set; }
//public MarketPlace MarketPlace { get; private set; }
//public string MarketPlaceId { get; private set; }
public SpApiConnection()
{
InnitConnection();
}
private void InnitConnection()
{
// attempt to create credential object from app.local.config
var credential = new FikaAmazonAPI.AmazonCredential();
try
{
credential = new FikaAmazonAPI.AmazonCredential();
credential.AccessKey = ConfigurationManager.AppSettings["SpapiAccessKey"];
credential.SecretKey = ConfigurationManager.AppSettings["SpapiSecretKey"];
credential.RoleArn = ConfigurationManager.AppSettings["SpapiRoleArn"];
credential.ClientId = ConfigurationManager.AppSettings["SpapiClientId"];
credential.ClientSecret = ConfigurationManager.AppSettings["SpapiClientSecret"];
credential.RefreshToken = ConfigurationManager.AppSettings["SpapiRefreshToken"];
credential.MarketPlaceID = ConfigurationManager.AppSettings["SpapiMarketplaceId"];
credential.IsDebugMode = true;
credential.MaxThrottledRetryCount = 3;
}
catch (Exception ex)
{
throw new Exception("Unable to retirve Amazon SP API credentials: " + ex.Message);
}
this.Connection = new AmazonConnection(credential);
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Xml;
namespace bnhtrade.Core.Data.Amazon.SellingPartnerAPI.Utils
{
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.SpecifyKind(DateTime.Parse(attrVal), DateTimeKind.Utc);
break;
}
}
if (returnTime == default(DateTime))
{
throw new Exception("Error requesting time from Amazon");
}
returnTime = returnTime.AddTicks(-(returnTime.Ticks % TimeSpan.TicksPerSecond));
return returnTime;
}
public DateTime GetLocal()
{
return GetUtc().ToLocalTime();
}
}
}