From 116aedb897ec4ded1c1f422d9693bcc099d17b6a Mon Sep 17 00:00:00 2001 From: Bobbie Hodgetts Date: Mon, 24 Jun 2019 16:01:50 +0100 Subject: [PATCH] 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 --- bnhtrade.sln | 48 ++- src/bnhtrade.ComTypeLib/Ebay/EbayListing.cs | 2 +- .../Data/AmazonMWS/CredentialMws.cs | 19 ++ .../Data/AmazonMWS/CurrentDateTime.cs | 47 +++ .../FBAInbound/ListInboundShipmentItems.cs | 189 +++++++++++ .../FBAInbound/ListInboundShipments.cs | 223 +++++++++++++ src/bnhtrade.Core/Data/AmazonMWS/Service.cs | 74 +++++ src/bnhtrade.Core/Data/Database/Connection.cs | 20 ++ .../FBAInbound/GetShipmentHeaderInfo.cs | 157 ++++++++++ .../FBAInbound/GetShipmentPrimaryKey.cs | 113 +++++++ .../Database/FBAInbound/SetShipmentInfo.cs | 246 +++++++++++++++ .../Data/Database/SKU/GetSKUId.cs | 100 ++++++ .../AmazonFBAInbound/ShipmentAddByFnsku.cs | 35 +++ .../UpdateDatabaseShipmentInfo.cs | 113 +++++++ src/bnhtrade.Core/Logic/Sku/GetSkuIdByType.cs | 121 +++++++ .../Model/AmazonFBAInbound/ShipmentInfo.cs | 179 +++++++++++ .../AmazonFBAInbound/ShipmentItemInfo.cs | 83 +++++ src/bnhtrade.Core/Model/SKU/SKUInfo.cs | 15 + src/bnhtrade.Core/Program.cs | 296 +++++------------- .../Properties/Settings.Designer.cs | 4 +- src/bnhtrade.Core/SQL Connection.cs | 40 --- src/bnhtrade.Core/Test/InboundShipmentInfo.cs | 83 +++++ .../Test/InboundShipmentInfoSync.cs | 17 + src/bnhtrade.Core/Test/SQLLoop.cs | 80 +++++ .../UI/Utility/ConsoleProgressBar.cs | 125 ++++++++ src/bnhtrade.Core/bnhtrade.Core.csproj | 49 ++- src/bnhtrade.ScheduledTasks/Program.cs | 47 +-- 27 files changed, 2236 insertions(+), 289 deletions(-) create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/CurrentDateTime.cs create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs create mode 100644 src/bnhtrade.Core/Data/AmazonMWS/Service.cs create mode 100644 src/bnhtrade.Core/Data/Database/Connection.cs create mode 100644 src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs create mode 100644 src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs create mode 100644 src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs create mode 100644 src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs create mode 100644 src/bnhtrade.Core/Logic/AmazonFBAInbound/ShipmentAddByFnsku.cs create mode 100644 src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs create mode 100644 src/bnhtrade.Core/Logic/Sku/GetSkuIdByType.cs create mode 100644 src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs create mode 100644 src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs create mode 100644 src/bnhtrade.Core/Model/SKU/SKUInfo.cs delete mode 100644 src/bnhtrade.Core/SQL Connection.cs create mode 100644 src/bnhtrade.Core/Test/InboundShipmentInfo.cs create mode 100644 src/bnhtrade.Core/Test/InboundShipmentInfoSync.cs create mode 100644 src/bnhtrade.Core/Test/SQLLoop.cs create mode 100644 src/bnhtrade.Core/UI/Utility/ConsoleProgressBar.cs diff --git a/bnhtrade.sln b/bnhtrade.sln index a6c123d..442995e 100644 --- a/bnhtrade.sln +++ b/bnhtrade.sln @@ -1,9 +1,9 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.27428.2037 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.202 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CF330C30-8231-4D54-B60C-FF0644713502}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{CF330C30-8231-4D54-B60C-FF0644713502}" ProjectSection(SolutionItems) = preProject build\bnhtrade.ComTypeLib.RegAsmInstall.bat = build\bnhtrade.ComTypeLib.RegAsmInstall.bat build\bnhtrade.ComTypeLib.RegAsmRefresh.bat = build\bnhtrade.ComTypeLib.RegAsmRefresh.bat @@ -16,6 +16,20 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bnhtrade.Core", "src\bnhtra EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "bnhtrade.ComTypeLib", "src\bnhtrade.ComTypeLib\bnhtrade.ComTypeLib.csproj", "{C3405E9D-B47A-4569-B6A3-BC9E7AA71EE5}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{3D90C0F5-02E7-44E5-A89D-F5E217C6602F}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWSClientCsRuntime", "..\..\AmazonMWSCsClient\src\MWSClientCsRuntime\MWSClientCsRuntime.csproj", "{BDE52371-CAD4-4809-B8F7-9A218EE02464}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FBAInboundServiceMWS", "..\..\AmazonMWSCsClient\src\FBAInboundServiceMWS\FBAInboundServiceMWS.csproj", "{9C7D6775-4F06-4881-87A0-B9514F2F3033}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarketplaceWebServiceProducts", "..\..\AmazonMWSCsClient\src\MarketplaceWebServiceProducts\MarketplaceWebServiceProducts.csproj", "{FE2FE872-F92E-4B47-BCC2-E41B9C10EB96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MWSFinancesService", "..\..\AmazonMWSCsClient\src\MWSFinancesService\MWSFinancesService.csproj", "{1FE13EF5-AABF-4080-B790-990B9069C634}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MarketplaceWebService", "..\..\AmazonMWSCsClient\src\MarketplaceWebService\MarketplaceWebService.csproj", "{52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AmazonMWS", "AmazonMWS", "{09C5A59A-8917-4D5C-BA80-D38B8C9EDECC}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -34,10 +48,38 @@ Global {C3405E9D-B47A-4569-B6A3-BC9E7AA71EE5}.Debug|Any CPU.Build.0 = Debug|Any CPU {C3405E9D-B47A-4569-B6A3-BC9E7AA71EE5}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3405E9D-B47A-4569-B6A3-BC9E7AA71EE5}.Release|Any CPU.Build.0 = Release|Any CPU + {BDE52371-CAD4-4809-B8F7-9A218EE02464}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BDE52371-CAD4-4809-B8F7-9A218EE02464}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BDE52371-CAD4-4809-B8F7-9A218EE02464}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BDE52371-CAD4-4809-B8F7-9A218EE02464}.Release|Any CPU.Build.0 = Release|Any CPU + {9C7D6775-4F06-4881-87A0-B9514F2F3033}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9C7D6775-4F06-4881-87A0-B9514F2F3033}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9C7D6775-4F06-4881-87A0-B9514F2F3033}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9C7D6775-4F06-4881-87A0-B9514F2F3033}.Release|Any CPU.Build.0 = Release|Any CPU + {FE2FE872-F92E-4B47-BCC2-E41B9C10EB96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE2FE872-F92E-4B47-BCC2-E41B9C10EB96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE2FE872-F92E-4B47-BCC2-E41B9C10EB96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE2FE872-F92E-4B47-BCC2-E41B9C10EB96}.Release|Any CPU.Build.0 = Release|Any CPU + {1FE13EF5-AABF-4080-B790-990B9069C634}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1FE13EF5-AABF-4080-B790-990B9069C634}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1FE13EF5-AABF-4080-B790-990B9069C634}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1FE13EF5-AABF-4080-B790-990B9069C634}.Release|Any CPU.Build.0 = Release|Any CPU + {52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {BDE52371-CAD4-4809-B8F7-9A218EE02464} = {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} + {9C7D6775-4F06-4881-87A0-B9514F2F3033} = {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} + {FE2FE872-F92E-4B47-BCC2-E41B9C10EB96} = {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} + {1FE13EF5-AABF-4080-B790-990B9069C634} = {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} + {52B09E65-F1B4-4B99-B8E2-4A0B2E3201C2} = {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} + {09C5A59A-8917-4D5C-BA80-D38B8C9EDECC} = {3D90C0F5-02E7-44E5-A89D-F5E217C6602F} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {9CE53A62-9E0C-460F-9C09-B7DDB3B7F0EA} EndGlobalSection diff --git a/src/bnhtrade.ComTypeLib/Ebay/EbayListing.cs b/src/bnhtrade.ComTypeLib/Ebay/EbayListing.cs index 833b001..0326c6d 100644 --- a/src/bnhtrade.ComTypeLib/Ebay/EbayListing.cs +++ b/src/bnhtrade.ComTypeLib/Ebay/EbayListing.cs @@ -1,8 +1,8 @@ using bnhtrade.ComTypeLib.Credential; using System; using System.Runtime.InteropServices; -using Core.EbayQuery; using System.IO; +using bnhtrade.Core.EbayQuery; namespace bnhtrade.ComTypeLib.Ebay { diff --git a/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs b/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs new file mode 100644 index 0000000..5bc8d77 --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/CredentialMws.cs @@ -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"; } } + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/CurrentDateTime.cs b/src/bnhtrade.Core/Data/AmazonMWS/CurrentDateTime.cs new file mode 100644 index 0000000..735f4e5 --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/CurrentDateTime.cs @@ -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(); + } + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs new file mode 100644 index 0000000..71a30ef --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipmentItems.cs @@ -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 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 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 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(); + + // 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(); + 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; + } + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs new file mode 100644 index 0000000..8d13c3b --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/FBAInbound/ListInboundShipments.cs @@ -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 + { + /// + /// List of Shipment Status' to return. Default is all status' returned. + /// + public List ShipmentStatusList { get; set; } + /// + /// List of Shipment Id to return. + /// + public List 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 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(); + 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(); + //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; + } + } +} diff --git a/src/bnhtrade.Core/Data/AmazonMWS/Service.cs b/src/bnhtrade.Core/Data/AmazonMWS/Service.cs new file mode 100644 index 0000000..7eb0773 --- /dev/null +++ b/src/bnhtrade.Core/Data/AmazonMWS/Service.cs @@ -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; + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/Connection.cs b/src/bnhtrade.Core/Data/Database/Connection.cs new file mode 100644 index 0000000..53a2578 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/Connection.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database +{ + public class Connection + { + protected readonly string sqlConnectionString; + public Connection(string sqlConnectionString) + { + // setup sql parameters + if (sqlConnectionString.Length == 0) + { throw new Exception("Zero length sql connectionstring passed"); } + this.sqlConnectionString = sqlConnectionString; + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs b/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs new file mode 100644 index 0000000..607aaf5 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentHeaderInfo.cs @@ -0,0 +1,157 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.FBAInbound +{ + public class GetShipmentHeaderInfo : Connection + { + private List shipmentIdList; + public GetShipmentHeaderInfo(string sqlConnectionString) : base(sqlConnectionString) { } + /// + /// Return active shipments only. Default is false. + /// + public bool ActiveShipments { get; set; } = false; + public bool IsSetActiveShipments { get { return true; } } + public bool IsSetShipmentIdList + { + get + { + if (ShipmentIdList == null || !ShipmentIdList.Any()) { return false; } + else { return true; } + } + } + /// + /// Filter results by Amazon's shipment Id. + /// + public List ShipmentIdList + { + get { return shipmentIdList; } + set + { + if (value != null) + { + // clean list + shipmentIdList = new List(); + foreach (string item in value) + { + if (item.Length > 0) + { + shipmentIdList.Add(item); + } + } + if (!ShipmentIdList.Any()) + { + shipmentIdList = null; + throw new Exception("Invalid shipment Id set"); + } + } + } + } + /// + /// Retrives table primary key 'AmazonShipmentID' for tblAmazonShipment + /// + /// Amazon's inbound FBA shipment Id. + /// Primary key or -1 if match isn't found. + public List Execute() + { + // build the sql string + int countShipId = 0; + string sqlString = @" + SELECT + AmazonShipmentID + ,ShipmentName + ,ShipmentId + ,CenterId + ,ShipmentStatus + ,LastUpdated + ,IsClosed + FROM + tblAmazonShipment + WHERE + 1 = 1"; + if (ActiveShipments) + { + sqlString = sqlString + @" + AND IsClosed = 0"; + } + var dicShipIdByParameterString = new Dictionary(); + if (IsSetShipmentIdList) + { + foreach (string item in ShipmentIdList) + { + countShipId = countShipId + 1; + string parameterString = "@shipmentId" + countShipId.ToString().PadLeft(6, '0'); + dicShipIdByParameterString.Add(parameterString, item); + if (countShipId == 1) + { + sqlString = sqlString + @" + AND ( ShipmentId = " + parameterString; + } + else + { + sqlString = sqlString + @" + OR ShipmentId = " + parameterString; + } + } + if (countShipId > 0) + { + sqlString = sqlString + " )"; + } + } + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(sqlString, conn)) + { + // add shipId parameters + if (ShipmentIdList.Any()) + { + foreach (var item in dicShipIdByParameterString) + { + cmd.Parameters.AddWithValue(item.Key, item.Value); + } + } + + using (var reader = cmd.ExecuteReader()) + { + if (!reader.HasRows) + { + // no records + return null; + } + + var infoList = new List(); + while (reader.Read()) + { + var info = new Model.AmazonFBAInbound.ShipmentInfo(); + + int tablePK = reader.GetInt32(0); + info.ShipmentName = reader.GetString(1); + info.AmazonShipmentId = reader.GetString(2); + info.DestinationFulfillmentCenterId = reader.GetString(3); + info.ShipmentStatus = reader.GetString(4); + info.LastUpdatedUtc = reader.GetDateTime(5); + bool dbIsClosed = reader.GetBoolean(6); + + // db consistancy check + if (dbIsClosed != info.ShipmentIsClosed) + { + throw new Exception("Data inconstitancy in database: check shipment IsClosed where AmazonShipmentID=" + tablePK); + } + + // update cache + infoList.Add(info); + } + return infoList; + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs b/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs new file mode 100644 index 0000000..044d03b --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/FBAInbound/GetShipmentPrimaryKey.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Data.Database.FBAInbound +{ + public class GetShipmentPrimaryKey : Connection + { + private bool enableCache = false; + private Dictionary shipmentPKByAmazonShipmentIdDic; + private Dictionary amazonShipmentIdByShipmentPKDic; + public GetShipmentPrimaryKey(string sqlConnectionString) : base(sqlConnectionString) { } + public bool CacheEnabled + { + get { return enableCache; } + set + { + if (value && enableCache == false) + { + shipmentPKByAmazonShipmentIdDic = new Dictionary(); + amazonShipmentIdByShipmentPKDic = new Dictionary(); + } + else + { + shipmentPKByAmazonShipmentIdDic = null; + amazonShipmentIdByShipmentPKDic = null; + } + } + } + private void ClearCache() + { + if (CacheEnabled) + { + shipmentPKByAmazonShipmentIdDic.Clear(); + amazonShipmentIdByShipmentPKDic.Clear(); + } + } + private void DeleteCachedShipmentPK(int shipmentPrimaryKey) + { + if (CacheEnabled) + { + if (amazonShipmentIdByShipmentPKDic.ContainsKey(shipmentPrimaryKey)) + { + string amazonShipmentId = amazonShipmentIdByShipmentPKDic[shipmentPrimaryKey]; + shipmentPKByAmazonShipmentIdDic.Remove(amazonShipmentId); + amazonShipmentIdByShipmentPKDic.Remove(shipmentPrimaryKey); + } + } + } + /// + /// Retrives table primary key 'AmazonShipmentID' for tblAmazonShipment + /// + /// Amazon's inbound FBA shipment Id. + /// Forces a database query when cache is enabled. + /// Primary key or -1 if match isn't found. + public int ByAmazonShipmentId(string amazonShipmentId, bool forceDBQuery = false) + { + if (amazonShipmentId.Length < 5) + { + throw new Exception("Incorrect Amazon shipment if supplied '" + amazonShipmentId + "'"); + } + + // first, query class dictionary before sql call + if (CacheEnabled + && forceDBQuery == false + && shipmentPKByAmazonShipmentIdDic.ContainsKey(amazonShipmentId)) + { + return shipmentPKByAmazonShipmentIdDic[amazonShipmentId]; + } + + int shipmentPK = -1; + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT AmazonShipmentID + FROM tblAmazonShipment + WHERE (((tblAmazonShipment.ShipmentId)=@amazonShipmentId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@amazonShipmentId", amazonShipmentId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null || obj == DBNull.Value) + { + return shipmentPK; + } + else + { + shipmentPK = (int)obj; + } + } + } + UpdateCache(shipmentPK, amazonShipmentId); + return shipmentPK; + } + private void UpdateCache(int shipmentPK, string amazonShipmentId) + { + if (CacheEnabled) + { + DeleteCachedShipmentPK(shipmentPK); + + shipmentPKByAmazonShipmentIdDic.Add(amazonShipmentId, shipmentPK); + amazonShipmentIdByShipmentPKDic.Add(shipmentPK, amazonShipmentId); + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs b/src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs new file mode 100644 index 0000000..f54a770 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/FBAInbound/SetShipmentInfo.cs @@ -0,0 +1,246 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Data.Database.FBAInbound +{ + public class SetShipmentInfo : Connection + { + private GetShipmentPrimaryKey getPK; + private Data.Database.SKU.GetSKUId skuIdLoopkup; + public SetShipmentInfo(string sqlConnectionString) : base(sqlConnectionString) { } + private GetShipmentPrimaryKey GetPK + { + get + { + if (getPK == null) + { + getPK = new GetShipmentPrimaryKey(sqlConnectionString); + } + return getPK; + } + set + { + getPK = value; + } + } + private Data.Database.SKU.GetSKUId SkuIdLoopkup + { + get + { + if (skuIdLoopkup == null) + { + skuIdLoopkup = new SKU.GetSKUId(sqlConnectionString); + } + return skuIdLoopkup; + } + } + public void Excecute(Model.AmazonFBAInbound.ShipmentInfo info) + { + using (var scope = new TransactionScope()) + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // input checks + if (!info.IsSetAll()) + { + throw new Exception("Insurficent ShipmentInfo parameters."); + } + + // get tablePK + int shipmentPK = GetPK.ByAmazonShipmentId(info.AmazonShipmentId); + + // add or update shipment header info + if (shipmentPK == -1) + { + shipmentPK = InsertShipmentHeaderInfo(info); + } + else + { + UpdateShipmentHeaderInfo(info); + DeleteShipmentItems(shipmentPK); + } + + // insert new shipment item info + foreach (var item in info.ShipmentItemInfoList) + { + int skuId = SkuIdLoopkup.BySKUNumber(item.SKUNumber); + + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAmazonShipmentItem ( + AmazonShipmentID + ,SkuID + ,QuantityAllocated + ,QuantityReceived + ) + VALUES ( + @amazonShipmentID + ,@skuID + ,@quantityAllocated + ,@quantityReceived + ) + ", conn)) + { + cmd.Parameters.AddWithValue("@amazonShipmentID", shipmentPK); + cmd.Parameters.AddWithValue("@skuID", skuId); + cmd.Parameters.AddWithValue("@quantityAllocated", item.QuantityAllocated); + cmd.Parameters.AddWithValue("@quantityReceived", item.QuantityReceived); + + int effected = (int)cmd.ExecuteNonQuery(); + + if (effected == 0) + { + throw new Exception("Error, no tblAmazonShipment was not updated."); + } + } + } + + } + scope.Complete(); + } + } + + public void ExcecuteByList(List infoList) + { + using (var scope = new TransactionScope()) + { + foreach (var item in infoList) + { + Excecute(item); + } + scope.Complete(); + } + } + + private void DeleteShipmentItems(int shipmentId) + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + DELETE FROM + tblAmazonShipmentItem + WHERE + AmazonShipmentId = @shipmentId + ", conn)) + { + cmd.Parameters.AddWithValue("@shipmentId", shipmentId); + + cmd.ExecuteNonQuery(); + } + } + } + + private int InsertShipmentHeaderInfo(Model.AmazonFBAInbound.ShipmentInfo info) + { + if (!info.IsSetAll()) + { + throw new Exception("Unsuficent properties set in Shipment Header Info."); + } + + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + if (GetPK.ByAmazonShipmentId(info.AmazonShipmentId) != -1) + { + throw new Exception("Shipment insert failed, shipment with same Amazon Id already exists."); + } + + // get next shipment Number in sequence and create shipment name + int sequenceNumber; + using (SqlCommand cmd = new SqlCommand(@" + SELECT NEXT VALUE FOR dbo.ShipmentCountSequence AS SequenceNumber + ", conn)) + { + sequenceNumber = (int)cmd.ExecuteScalar(); + } + // info.ShipmentName = "FBA_Shipment_" + sequenceNumber.ToString().PadLeft(4, '0') + "_" + info.DestinationFulfillmentCenterId; + + // make the insert + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblAmazonShipment ( + AmazonShipmentCount + ,ShipmentName + ,ShipmentId + ,CenterId + ,ShipmentStatus + ,LastUpdated + ,IsClosed + ) + OUTPUT INSERTED.AmazonShipmentID + VALUES ( + @amazonShipmentCount + ,@shipmentName + ,@shipmentId + ,@centerId + ,@shipmentStatus + ,@lastUpdated + ,@isClosed + ) + ", conn)) + { + cmd.Parameters.AddWithValue("@amazonShipmentCount", sequenceNumber); + cmd.Parameters.AddWithValue("@shipmentName", info.ShipmentName); + cmd.Parameters.AddWithValue("@shipmentId", info.AmazonShipmentId); + cmd.Parameters.AddWithValue("@centerId", info.DestinationFulfillmentCenterId); + cmd.Parameters.AddWithValue("@shipmentStatus", info.ShipmentStatus); + cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdatedUtc); + cmd.Parameters.AddWithValue("@isClosed", info.ShipmentIsClosed); + + int tablePk = (int)cmd.ExecuteScalar(); + + // update cache and return + return tablePk; + } + } + } + + private void UpdateShipmentHeaderInfo(Model.AmazonFBAInbound.ShipmentInfo info) + { + int tablePK = GetPK.ByAmazonShipmentId(info.AmazonShipmentId); + if (tablePK == -1) + { + throw new Exception("Shipment insert failed, shipment with same Amazon Id already exists."); + } + + // make the update + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + using (SqlCommand cmd = new SqlCommand(@" + UPDATE tblAmazonShipment + SET + ShipmentName = @shipmentName + ,ShipmentStatus = @shipmentStatus + ,LastUpdated = @lastUpdated + ,IsClosed = @isClosed + WHERE + AmazonShipmentID = @tablePK + ", conn)) + { + cmd.Parameters.AddWithValue("@shipmentName", info.ShipmentName); + cmd.Parameters.AddWithValue("@shipmentStatus", info.ShipmentStatus); + cmd.Parameters.AddWithValue("@lastUpdated", info.LastUpdatedUtc); + cmd.Parameters.AddWithValue("@isClosed", info.ShipmentIsClosed); + cmd.Parameters.AddWithValue("@tablePK", tablePK); + + int count = cmd.ExecuteNonQuery(); + + if (count == 0) + { + throw new Exception("No records updated"); + } + } + } + } + } +} diff --git a/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs b/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs new file mode 100644 index 0000000..f508758 --- /dev/null +++ b/src/bnhtrade.Core/Data/Database/SKU/GetSKUId.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace bnhtrade.Core.Data.Database.SKU +{ + public class GetSKUId + { + private Dictionary SKUIdBySKUNumber { get; set; } + private Dictionary SKUNumberBySKUId { get; set; } + private string SqlConnectionString { get; set; } + public GetSKUId(string sqlConnectionString) + { + // setup sql parameters + if (sqlConnectionString.Length == 0) + { + throw new Exception("Zero length sql connectionstring passed"); + } + SqlConnectionString = sqlConnectionString; + + // set paramters + SKUIdBySKUNumber = new Dictionary(); + SKUNumberBySKUId = new Dictionary(); + } + + /// + /// Get SKUId by SKU number. + /// + /// SKU Number to lookup Id + /// If SKUId is can not be retrived, function will attempt to lookup value by sku count. + /// Results are chached, option forces database requery. + /// Database SKUId or Exception if not found. + public int BySKUNumber(string skuNumber, bool enableLegacy = false, bool forceRequery = false) + { + if (forceRequery == false && SKUIdBySKUNumber.ContainsKey(skuNumber)) + { + return SKUIdBySKUNumber[skuNumber]; + } + + int skuId = 0; + using (SqlConnection conn = new SqlConnection(SqlConnectionString)) + { + conn.Open(); + using (SqlCommand cmd = new SqlCommand(@" + SELECT skuSkuID + FROM tblSku + WHERE skuSkuNumber=@skuNumber; + ", conn)) + { + cmd.Parameters.AddWithValue("@skuNumber", skuNumber); + + object obj = cmd.ExecuteScalar(); + if (!(obj == null) || !(obj == DBNull.Value)) + { + skuId = Convert.ToInt32(obj); + } + } + // if that didn't work, lookup buy sku count + if (skuId == 0 && skuNumber.Length == 6 && enableLegacy == true) + { + int skucount; + bool okay = int.TryParse(skuNumber, out skucount); + if (okay) + { + using (SqlCommand cmd = new SqlCommand( + "SELECT skuSkuID FROM tblSku WHERE skuSkuCount=@skuCount;" + , conn)) + { + cmd.Parameters.AddWithValue("@skuCount", skucount); + + object obj = cmd.ExecuteScalar(); + if (!(obj == null) || !(obj == DBNull.Value)) + { + skuId = Convert.ToInt32(obj); + } + } + } + } + } + + // update cache + if (skuId > 0) + { + if (SKUIdBySKUNumber.ContainsKey(skuNumber)) + { SKUIdBySKUNumber.Remove(skuNumber); } + SKUIdBySKUNumber.Add(skuNumber, skuId); + + if (SKUNumberBySKUId.ContainsKey(skuId)) + { SKUNumberBySKUId.Remove(skuId); } + SKUNumberBySKUId.Add(skuId, skuNumber); + } + else + { + throw new Exception("Unable to retrive an SkuID for SKU#" + skuNumber); + } + + return skuId; + } + } +} diff --git a/src/bnhtrade.Core/Logic/AmazonFBAInbound/ShipmentAddByFnsku.cs b/src/bnhtrade.Core/Logic/AmazonFBAInbound/ShipmentAddByFnsku.cs new file mode 100644 index 0000000..5543ea3 --- /dev/null +++ b/src/bnhtrade.Core/Logic/AmazonFBAInbound/ShipmentAddByFnsku.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Logic.AmazonFBAInbound +{ + public class ShipmentSkuAddByFNSKU + { + public string fnsku { get; private set; } + public int skuId { get; private set; } + public string skuProductTitle { get; private set; } + public string fbaCenterId { get; private set; } + public string fbaShipmentId { get; private set; } + public bool errorFlag { get; private set; } = false; + public string errorMessage { get; private set; } = ""; + + // add method here + public ShipmentSkuAddByFNSKU Request(string fnsku) + { + var repsonce = new ShipmentSkuAddByFNSKU(); + + // checks + if (fnsku.Length != 10) + { + throw new Exception("Incorrect FNSKU supplied."); + } + + repsonce.fnsku = fnsku; + + return repsonce; + } + } +} \ No newline at end of file diff --git a/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs b/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs new file mode 100644 index 0000000..c80adad --- /dev/null +++ b/src/bnhtrade.Core/Logic/AmazonFBAInbound/UpdateDatabaseShipmentInfo.cs @@ -0,0 +1,113 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; +using bnhtrade.Core.Data; + +namespace bnhtrade.Core.Logic.AmazonFBAInbound +{ + public class UpdateDatabaseShipmentInfo + { + private string sqlConnectionString; + private readonly string logDateTimeId = "FbaInboundShipmentNewCheck"; + public int TotalUpdated { get; private set; } = 0; + public UpdateDatabaseShipmentInfo(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + public void GetNew() + { + TotalUpdated = 0; + + // get time frame to check + DateTime dateTimeBefore = new Data.AmazonMWS.CurrentDateTime().GetUtc(); + DateTime dateTimeAfter = new Data.Database.Log.DateTimeLog(sqlConnectionString).GetDateTimeUtc(logDateTimeId); + + //var objGetUtc = new Data.AmazonMWS.CurrentDateTime(); + //DateTime dateTimeBefore = objGetUtc.GetUtc(); + + //var objDateTimeCheck = new Data.Database.Log.DateTimeLog(sqlConnectionString); + //DateTime dateTimeAfter = objDateTimeCheck.GetDateTimeUtc(logDateTimeId); + + // + var shipmentRequest = new Data.AmazonMWS.FBAInbound.ListInboundShipments(); + shipmentRequest.LastUpdatedAfter = dateTimeAfter.AddDays(-14); + shipmentRequest.LastUpdatedBefore = dateTimeBefore; + + List shipmentInfoList = shipmentRequest.GetShipmentInfo(); + + // build list of shipments returned from mws + var dicShipExistsInDb = new Dictionary(); + foreach (var item in shipmentInfoList) + { + dicShipExistsInDb.Add(item.AmazonShipmentId, false); + } + + // build list of shipmentId that do not exist in database + int complete = 0; + using (TransactionScope scope = new TransactionScope()) + { + List newShipmentInfoList = null; + if (dicShipExistsInDb.Any()) + { + var newShipmentId = new List(); + + // query db for shipment header info + var requestHeader = new Data.Database.FBAInbound.GetShipmentHeaderInfo(sqlConnectionString); + requestHeader.ShipmentIdList = dicShipExistsInDb.Keys.ToList(); + var resultHeader = requestHeader.Execute(); + + // compare db and mws result + foreach (var item in resultHeader) + { + dicShipExistsInDb[item.AmazonShipmentId] = true; + } + foreach (var item in dicShipExistsInDb) + { + if (item.Value == false) + { + newShipmentId.Add(item.Key); + } + } + + // query mws for new shipment info + if (newShipmentId.Any()) + { + shipmentRequest.ShipmentIdList = newShipmentId; + newShipmentInfoList = shipmentRequest.GetShipmentInfo(); + + foreach (var item in newShipmentInfoList) + { + var shipmentItemInfoRequest = new Data.AmazonMWS.FBAInbound.ListInboundShipmentItems(); + item.ShipmentItemInfoList = shipmentItemInfoRequest.GetByAmazonShipmentId(item.AmazonShipmentId); + } + } + + // write to db + if (newShipmentInfoList != null) + { + foreach (var item in newShipmentInfoList) + { + // add the update date + item.LastUpdatedUtc = dateTimeBefore; + + // write to db + var dbWrite = new Data.Database.FBAInbound.SetShipmentInfo(sqlConnectionString); + dbWrite.Excecute(item); + complete = complete + 1; + } + } + } + + // update datetime log + new Data.Database.Log.DateTimeLog(sqlConnectionString).SetDateTimeUtc(logDateTimeId, dateTimeBefore); + //objDateTimeCheck.SetDateTimeUtc(logDateTimeId, dateTimeBefore); + + scope.Complete(); + } + TotalUpdated = complete; + } + } +} diff --git a/src/bnhtrade.Core/Logic/Sku/GetSkuIdByType.cs b/src/bnhtrade.Core/Logic/Sku/GetSkuIdByType.cs new file mode 100644 index 0000000..281a1d6 --- /dev/null +++ b/src/bnhtrade.Core/Logic/Sku/GetSkuIdByType.cs @@ -0,0 +1,121 @@ +using System; +using System.Data.SqlClient; +using System.Transactions; + +namespace bnhtrade.Core.Logic.Sku +{ + class GetSkuIdByType + { + // used for retriving SKU that matched parameters, creates new if required, returns 0 if not found + public static int Request(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, bool noMatchInsertNew) + { + using (TransactionScope scope = new TransactionScope()) + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + conn.Open(); + + // look for existing entry + using (SqlCommand cmd = new SqlCommand(@" + SELECT + tblSku.skuSkuID + FROM + tblSku + WHERE + (((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + object obj = cmd.ExecuteScalar(); + if (obj != null) + { + return (int)obj; + } + } + + // value check insert bool + if (noMatchInsertNew == false) + { + return 0; + } + else + { + // get this far, check tax code id is a valid for SKU + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblAccountTaxCode.InvoiceSales + FROM tblAccountTaxCode + WHERE (((tblAccountTaxCode.AccountTaxCodeID)=@accountTaxCodeId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + object obj = cmd.ExecuteScalar(); + + if (obj == null) + { + throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!"); + } + else + { + bool result = (bool)obj; + if (result == false) + { + throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU."); + } + } + } + + // get info to create sku number + int skuCount; + int skuSuffix; + using (SqlCommand cmd = new SqlCommand("SELECT NEXT VALUE FOR SkuCountSequence;", conn)) + { + skuCount = (int)cmd.ExecuteScalar(); + } + using (SqlCommand cmd = new SqlCommand(@" + SELECT tblSkuCondition.scnSkuNumberSuffix + FROM tblSkuCondition + WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId)); + ", conn)) + { + cmd.Parameters.AddWithValue("@conditionId", conditionId); + + try + { + skuSuffix = (int)cmd.ExecuteScalar(); + } + catch (Exception ex) + { + throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." + + System.Environment.NewLine + "Error Message: " + ex.Message); + } + } + string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2"); + + // insert new sku + int skuId; + using (SqlCommand cmd = new SqlCommand(@" + INSERT INTO tblSku + (skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID) + OUTPUT INSERTED.skuSkuID + VALUES + (@skuNumber, @productId, @conditionId, @accountTaxCodeId) + ", conn)) + { + cmd.Parameters.AddWithValue("@skuNumber", skuNumber); + cmd.Parameters.AddWithValue("@productId", productId); + cmd.Parameters.AddWithValue("@conditionId", conditionId); + cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); + + skuId = (int)cmd.ExecuteScalar(); + } + + scope.Complete(); + return skuId; + } + } + } + } +} diff --git a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs b/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs new file mode 100644 index 0000000..67d3bb2 --- /dev/null +++ b/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentInfo.cs @@ -0,0 +1,179 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.AmazonFBAInbound +{ + public class ShipmentInfo + { + private string destinationFulfillmentCenterId; + private List shipmentItemInfoList; + private string shipmentStatus; + private DateTime lastUpdatedUtc; + private Dictionary shipmentStatusToIsClosed; + + public string AmazonShipmentId { get; set; } + public string ShipmentName { get; set; } + public string DestinationFulfillmentCenterId + { + get { return destinationFulfillmentCenterId; } + set + { + if (value.Length != 4) + { + throw new Exception("incorrect Fulfillment Center Id"); + } + else + { + destinationFulfillmentCenterId = value; + } + } + } + public string ShipmentStatus + { + get + { + return shipmentStatus; + } + set + { + string status = value.ToUpper(); + if (!shipmentStatusToIsClosed.ContainsKey(status)) + { + throw new Exception("Invalid shipment status '" + status + "' parameter set as per Amazon MWS definitions."); + } + shipmentStatus = status; + } + } + public DateTime LastUpdatedUtc + { + get + { + return lastUpdatedUtc; + } + set + { + lastUpdatedUtc = DateTime.SpecifyKind(value, DateTimeKind.Utc); + } + } + public bool ShipmentIsClosed + { + get + { + if (IsSetShipmentStatus()) + { + return shipmentStatusToIsClosed[shipmentStatus]; + } + else + { + return false; + } + } + } + public List ShipmentItemInfoList + { + get { return shipmentItemInfoList; } + set + { + var skuCheck = new Dictionary(); + var fnskuCheck = new Dictionary(); + foreach (var item in value) + { + if (!item.IsSetAll()) + { throw new Exception("Infomation missing from Shipment Item list"); } + + if (item.AmazonShipmentId != AmazonShipmentId) + { throw new Exception("Amazon shipment id in item list does not match header information."); } + + if (skuCheck.ContainsKey(item.SKUNumber)) + { throw new Exception("Duplicated SKU number in item list."); } + skuCheck.Add(item.SKUNumber, "0000"); + + if (fnskuCheck.ContainsKey(item.AmazonFNSKU)) + { throw new Exception("Duplicated SKU number in item list."); } + fnskuCheck.Add(item.AmazonFNSKU, "0000"); + + if (item.QuantityAllocated < 0 || item.QuantityReceived < 0) + { throw new Exception("Quantites cannot be less than zero."); } + + if ((item.QuantityAllocated + item.QuantityReceived ) < 1) + { throw new Exception("Quantites cannot be zero"); } + } + shipmentItemInfoList = value; + } + } + public bool IsSetAll() + { + if (IsSetAllHeaderInfo() && IsSetListShipmentItemInfo()) + { + return true; + } + else + { + return false; + } + } + public bool IsSetAllHeaderInfo() + { + if (IsSetAmazonShipmentId() + && IsSetShipmentName() + && IsSetDestinationFulfillmentCenterId() + && IsSetShipmentStatus() + && IsSetLastUpdated() + && IsSetShipmentIsClosed()) + { + return true; + } + else + { + return false; + } + } + public bool IsSetAmazonShipmentId() + { + return AmazonShipmentId != null; + } + public bool IsSetShipmentName() + { + return ShipmentName != null; + } + public bool IsSetDestinationFulfillmentCenterId() + { + return DestinationFulfillmentCenterId != null; + } + public bool IsSetLastUpdated() + { + return LastUpdatedUtc != default(DateTime); + } + public bool IsSetListShipmentItemInfo() + { + return ShipmentItemInfoList != null; + } + public bool IsSetShipmentIsClosed() + { + return ShipmentStatus != null; + } + public bool IsSetShipmentStatus() + { + return ShipmentStatus != null; + } + + public ShipmentInfo() + { + shipmentStatusToIsClosed = new Dictionary(); + + shipmentStatusToIsClosed.Add("WORKING", false); + shipmentStatusToIsClosed.Add("SHIPPED", false); + shipmentStatusToIsClosed.Add("IN_TRANSIT", false); + shipmentStatusToIsClosed.Add("DELIVERED", false); + shipmentStatusToIsClosed.Add("CHECKED_IN", false); + shipmentStatusToIsClosed.Add("RECEIVING", false); + shipmentStatusToIsClosed.Add("CLOSED", true); + shipmentStatusToIsClosed.Add("CANCELLED", true); + shipmentStatusToIsClosed.Add("DELETED", true); + shipmentStatusToIsClosed.Add("ERROR", false); + } + } +} diff --git a/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs b/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs new file mode 100644 index 0000000..1173a98 --- /dev/null +++ b/src/bnhtrade.Core/Model/AmazonFBAInbound/ShipmentItemInfo.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.AmazonFBAInbound +{ + public class ShipmentItemInfo + { + private int quantityAllocated; + private int quantityReceived; + + private bool isSetQuantityAllocated; + private bool isSetQuantityReceived; + + /// + /// Gets and sets the AmazonShipmentId property. + /// + public string AmazonShipmentId { get; set; } + /// + /// Gets and sets the SKUNumber property. + /// + public string SKUNumber { get; set; } + /// + /// Gets and sets the FulfillmentNetworkSKU property. + /// + public string AmazonFNSKU { get; set; } + /// + /// Gets and sets the QuantityAllocated property. + /// + public int QuantityAllocated + { + get { return quantityAllocated; } + set { quantityAllocated = value; isSetQuantityAllocated = true; } + } + /// + /// Gets and sets the QuantityReceived property. + /// + public int QuantityReceived + { + get { return quantityReceived; } + set { quantityReceived = value; isSetQuantityReceived = true; } + } + + public bool IsSetAll() + { + if (IsSetAmazonShipmentId() + && IsSetSKUNumber() + && IsSetFulfillmentNetworkSKU() + && IsSetQuantityAllocated() + && IsSetQuantityReceived() + ) + { + return true; + } + else + { + return false; + } + } + public bool IsSetAmazonShipmentId() + { + return AmazonShipmentId != null; + } + public bool IsSetSKUNumber() + { + return SKUNumber != null; + } + public bool IsSetFulfillmentNetworkSKU() + { + return AmazonFNSKU != null; + } + public bool IsSetQuantityAllocated() + { + return isSetQuantityAllocated; + } + public bool IsSetQuantityReceived() + { + return isSetQuantityReceived; + } + } +} diff --git a/src/bnhtrade.Core/Model/SKU/SKUInfo.cs b/src/bnhtrade.Core/Model/SKU/SKUInfo.cs new file mode 100644 index 0000000..e281118 --- /dev/null +++ b/src/bnhtrade.Core/Model/SKU/SKUInfo.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Model.SKU +{ + class SKUInfo + { + public string SkuNumber { get; set; } + public string AmazonFNSKU { get; set; } + public bool IsActive { get; set; } + } +} diff --git a/src/bnhtrade.Core/Program.cs b/src/bnhtrade.Core/Program.cs index a6d0301..01928b7 100644 --- a/src/bnhtrade.Core/Program.cs +++ b/src/bnhtrade.Core/Program.cs @@ -19,9 +19,12 @@ using MarketplaceWebServiceProducts.Model; using MarketplaceWebServiceProducts; using System.Data.SqlTypes; using System.Security.Cryptography; -using Core.AmazonMWS; +using bnhtrade.Core.AmazonAPI; +using bnhtrade.Core.Order; +using bnhtrade.Core.Data.AmazonMWS; +using bnhtrade.Core.Logic.Sku; -namespace Core +namespace bnhtrade.Core { namespace Database { @@ -2064,7 +2067,7 @@ namespace Core } // get/set an skuId - int skuId = Core.Sku.SkuQuery.WIP_SkuGetSet(sqlConnectionString, productId, conditionId, accountTaxCodeId, true); + int skuId = Logic.Sku.GetSkuIdByType.Request(sqlConnectionString, productId, conditionId, accountTaxCodeId, true); // add the entry to the stock table (minus stockJournalId) int stockId = 0; @@ -4232,7 +4235,8 @@ namespace Core transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); int importTableId = reader.GetInt32(index01); string sku = reader.GetString(index03); - int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; @@ -4428,15 +4432,16 @@ namespace Core transactionDate = DateTime.SpecifyKind(transactionDate, DateTimeKind.Utc); int importTableId = reader.GetInt32(index01); string sku = reader.GetString(index03); - int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } int quantity = reader.GetInt32(index04); - int orderChannelId = Order.OrderQuery.GetSaleChannelIdByName(sqlConnectionString, reader.GetString(index05), true); + int orderChannelId = OrderQuery.GetSaleChannelIdByName(sqlConnectionString, reader.GetString(index05), true); string amazonOrderId = reader.GetString(index06); - int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, amazonOrderId, true); + int orderId = OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, amazonOrderId, true); string amazonOrderItemId = reader.GetString(index07); - int orderItemId = Order.OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); + int orderItemId = OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); if (quantity > 0 && transactionTypeId == 0) { transposeSkip = transposeSkip + 1; continue; } @@ -4520,13 +4525,13 @@ namespace Core string sku = reader.GetString(index04); // get orderchannelId - int salesChannelId = Order.OrderQuery.GetSaleChannelIdByName(sqlConnectionString, salesChannel); + int salesChannelId = OrderQuery.GetSaleChannelIdByName(sqlConnectionString, salesChannel); // get/set order ref - int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, salesChannelId, amazonOrderId, true); + int orderId = OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, salesChannelId, amazonOrderId, true); // get/set order item ref - int orderItemId = Order.OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); + int orderItemId = OrderQuery.GetOrderItemIdBySaleChannelRef(sqlConnectionString, orderId, amazonOrderItemId, true); // } Console.Write("\r"); @@ -4611,8 +4616,8 @@ namespace Core string sku = reader.GetString(index03); int quantity = reader.GetInt32(index04); string reference = reader.GetString(index05); - int orderChannelId = Order.OrderQuery.GetSaleChannelIdByAmazonOrderId(sqlConnectionString, reference); - int orderId = Order.OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, reference, true); + int orderChannelId = OrderQuery.GetSaleChannelIdByAmazonOrderId(sqlConnectionString, reference); + int orderId = OrderQuery.GetOrderIdBySaleChannelRef(sqlConnectionString, orderChannelId, reference, true); string detail = "Amazon Assessment: " + disposition + Environment.NewLine + "Status: " + reader.GetString(index07) + Environment.NewLine + @@ -4620,7 +4625,8 @@ namespace Core if (!reader.IsDBNull(index09)) { detail = detail + Environment.NewLine + "Customer Comments: " + reader.GetString(index09); } - int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } @@ -4776,7 +4782,8 @@ namespace Core if (quantity < 0) { quantity = quantity * -1; } string reference = reader.GetString(index05); - int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } using (TransactionScope scope = new TransactionScope()) @@ -5120,7 +5127,8 @@ namespace Core string reference = reader.GetString(index03); int quantityTotal = reader.GetInt32(index06); - int skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, reader.GetString(index05), true); + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + int skuId = skuData.BySKUNumber(sku, true); if (skuId < 1) { transposeSkip = transposeSkip + 1; @@ -5251,7 +5259,10 @@ namespace Core if (quantity == 0) { transactionTypeId = -1; } else - { skuId = Sku.SkuQuery.SkuLookupId(sqlConnectionString, sku, true); } + { + var skuData = new Data.Database.SKU.GetSKUId(sqlConnectionString); + skuId = skuData.BySKUNumber(sku, true); + } if (skuId < 1) { transposeSkip = transposeSkip + 1; continue; } @@ -5656,171 +5667,7 @@ namespace Core } } - namespace Sku - { - public class SkuQuery - { - public static int SkuLookupId(string sqlConnectionString, string sku, bool enableLegacy = false) - { - // if enableLegacy = true, function will attempt to lookup value by sku count - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - using (SqlCommand cmd = new SqlCommand(@" - SELECT skuSkuID FROM tblSku WHERE skuSkuNumber=@sku; - ", conn)) - { - cmd.Parameters.AddWithValue("@sku", sku); - - object obj = cmd.ExecuteScalar(); - if (!(obj == null)) - { - return Convert.ToInt32(obj); - } - } - // if that didn't work, lookup buy sku count - if (sku.Length == 6 & enableLegacy == true) - { - int skucount; - bool okay = int.TryParse(sku, out skucount); - if (okay) - { - using (SqlCommand cmd = new SqlCommand( - "SELECT skuSkuID FROM tblSku WHERE skuSkuCount=@skuCount;" - , conn)) - { - cmd.Parameters.AddWithValue("@skuCount", skucount); - - object obj = cmd.ExecuteScalar(); - if (!(obj == null)) - { - return Convert.ToInt32(obj); - } - else - { - return -1; - } - } - } - } - } - return -1; - } - - // used for retriving SKU that matched parameters, creates new if required, returns 0 if not found - public static int WIP_SkuGetSet(string sqlConnectionString, int productId, int conditionId, int accountTaxCodeId, bool noMatchInsertNew) - { - using (TransactionScope scope = new TransactionScope()) - using (SqlConnection conn = new SqlConnection(sqlConnectionString)) - { - conn.Open(); - - // look for existing entry - using (SqlCommand cmd = new SqlCommand(@" - SELECT - tblSku.skuSkuID - FROM - tblSku - WHERE - (((tblSku.skuProductID)=@productId) AND ((tblSku.skuSkuConditionID)=@conditionId) AND ((tblSku.AccountTaxCodeID)=@accountTaxCodeId)); - ", conn)) - { - cmd.Parameters.AddWithValue("@productId", productId); - cmd.Parameters.AddWithValue("@conditionId", conditionId); - cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); - - object obj = cmd.ExecuteScalar(); - if (obj != null) - { - return (int)obj; - } - } - - // value check insert bool - if (noMatchInsertNew == false) - { - return 0; - } - else - { - // get this far, check tax code id is a valid for SKU - using (SqlCommand cmd = new SqlCommand(@" - SELECT tblAccountTaxCode.InvoiceSales - FROM tblAccountTaxCode - WHERE (((tblAccountTaxCode.AccountTaxCodeID)=@accountTaxCodeId)); - ", conn)) - { - cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); - - object obj = cmd.ExecuteScalar(); - - if (obj == null) - { - throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " doesn't exist!"); - } - else - { - bool result = (bool)obj; - if (result == false) - { - throw new Exception("AccountTaxCodeID=" + accountTaxCodeId + " is not a valid type for an SKU."); - } - } - } - - // get info to create sku number - int skuCount; - int skuSuffix; - using (SqlCommand cmd = new SqlCommand("SELECT NEXT VALUE FOR SkuCountSequence;", conn)) - { - skuCount = (int)cmd.ExecuteScalar(); - } - using (SqlCommand cmd = new SqlCommand(@" - SELECT tblSkuCondition.scnSkuNumberSuffix - FROM tblSkuCondition - WHERE (((tblSkuCondition.scnSkuConditionID)=@conditionId)); - ", conn)) - { - cmd.Parameters.AddWithValue("@conditionId", conditionId); - - try - { - skuSuffix = (int)cmd.ExecuteScalar(); - } - catch (Exception ex) - { - throw new Exception("Error retriving SKU number suffix for SkuConditionID=" + conditionId + "." + - System.Environment.NewLine + "Error Message: " + ex.Message); - } - } - string skuNumber = skuCount.ToString("D6") + "-" + skuSuffix.ToString("D2"); - - // insert new sku - int skuId; - using (SqlCommand cmd = new SqlCommand(@" - INSERT INTO tblSku - (skuSkuNumber, skuProductID, skuSkuConditionID, AccountTaxCodeID) - OUTPUT INSERTED.skuSkuID - VALUES - (@skuNumber, @productId, @conditionId, @accountTaxCodeId) - ", conn)) - { - cmd.Parameters.AddWithValue("@skuNumber", skuNumber); - cmd.Parameters.AddWithValue("@productId", productId); - cmd.Parameters.AddWithValue("@conditionId", conditionId); - cmd.Parameters.AddWithValue("@accountTaxCodeId", accountTaxCodeId); - - skuId = (int)cmd.ExecuteScalar(); - } - - scope.Complete(); - return skuId; - } - } - } - } - } namespace Inventory { public class InventoryPricing @@ -6421,24 +6268,13 @@ namespace Core } } - namespace AmazonMWS + namespace AmazonAPI { - public class AmazonMwsCredential - { - 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 Database Client"; } } - public string applicationVersion { get { return "0.1"; } } - public string serviceURL { get { return "https://mws.amazonservices.co.uk"; } } - } - public class AmazonMwsService { public MarketplaceWebService.MarketplaceWebService GetAmazonMwsService() { - AmazonMwsCredential cred = new AmazonMwsCredential(); + CredentialMws cred = new CredentialMws(); MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient( @@ -6457,7 +6293,7 @@ namespace Core { public MarketplaceWebServiceProducts.MarketplaceWebServiceProducts GetAmazonMwsServiceProduct() { - AmazonMwsCredential cred = new AmazonMwsCredential(); + CredentialMws cred = new CredentialMws(); MarketplaceWebServiceProductsConfig config = new MarketplaceWebServiceProductsConfig(); config.ServiceURL = cred.serviceURL; @@ -6478,7 +6314,7 @@ namespace Core /// public List WIP_GetProductEstimateFee( FeesEstimateRequestList requestList) { - AmazonMwsCredential cred = new AmazonMwsCredential(); + CredentialMws cred = new CredentialMws(); AmazonMwsProduct mwsProduct = new AmazonMwsProduct(); MarketplaceWebServiceProducts.MarketplaceWebServiceProducts service = mwsProduct.GetAmazonMwsServiceProduct(); @@ -6549,30 +6385,46 @@ namespace Core } public class AmazonReport { - string merchantId = "A3RUYNKLWWM5KW"; - string marketplaceId = "A1F83G8C2ARO7P"; // Amazon.co.uk - string accessKeyId = "AKIAJU45WSYVINEN45UA"; - string secretAccessKey = "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"; - string applicationName = "AmazonApiApp"; - string applicationVersion = "0.1"; - string serviceURL = "https://mws.amazonservices.co.uk"; - public MarketplaceWebService.MarketplaceWebService GetMwsService() + 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 AmazonReport() { - MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); + CredentialMws cred = new CredentialMws(); - MarketplaceWebService.MarketplaceWebService service = new MarketplaceWebServiceClient( - accessKeyId, - secretAccessKey, - applicationName, - applicationVersion, - config); - - config.ServiceURL = serviceURL; - return service; + 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 GetMwsClient() + //{ + // MarketplaceWebServiceConfig config = new MarketplaceWebServiceConfig(); + + // MarketplaceWebService.MarketplaceWebService client = new MarketplaceWebServiceClient( + // accessKeyId, + // secretAccessKey, + // applicationName, + // applicationVersion, + // config); + + // config.ServiceURL = serviceURL; + // return client; + //} + public List GetMwsReportList(GetReportListRequest requestList) { - MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + var service = new Data.AmazonMWS.Service().MarketPlaceWeb; //define the list GetReportListResult getReportListResult = new GetReportListResult(); @@ -6613,11 +6465,12 @@ namespace Core } while (true); } + public string GetMwsReportById(string reportId) { // retrives report by reportId, saves to disk, and returns filepath - MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + var service = new Service().MarketPlaceWeb; string filePath = MiscFunction.GetTempFilePath(reportId + ".txt"); @@ -6669,12 +6522,13 @@ namespace Core } while (true); return ""; } + public string GetMwsReportByRequest(RequestReportRequest requestReport) { try { string targetRptType = requestReport.ReportType.ToString(); - MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + var service = new Service().MarketPlaceWeb; string status; RequestReportResponse requestResponse = new RequestReportResponse(); @@ -6811,6 +6665,7 @@ namespace Core return ""; } } + public List GetMwsReportByPeriod(string mwsReportEnum, DateTime startTime, DateTime endTime, int maxReportCount = 12, int reportMaxPeriod = 30) { // method downloads reports and returns a list of filePaths @@ -6902,9 +6757,10 @@ namespace Core return reportIdList; } + public bool SetMwsReportAcknowledgement(string reportId, bool acknowledged = true) { - MarketplaceWebService.MarketplaceWebService service = GetMwsService(); + var service = new Service().MarketPlaceWeb; do { @@ -6957,6 +6813,7 @@ namespace Core } while (true); return false; } + public bool ImportReportSettlementData(string sqlConnectionString, string filePath) { try @@ -7224,6 +7081,7 @@ namespace Core } return true; } + public bool ImportReportFbaInventoryReceipt(string sqlConnectionString, string filePath, DateTime startDate) { SqlConnection sqlConn; @@ -9543,7 +9401,7 @@ namespace Core } else { - Console.WriteLine("\r[" + DateTime.Now.ToString("HH:mm:ss") + "] " + consoleText); + Console.Write("\r[" + DateTime.Now.ToString("HH:mm:ss") + "] " + consoleText); } } public static string GetTempFilePath(string fileName) diff --git a/src/bnhtrade.Core/Properties/Settings.Designer.cs b/src/bnhtrade.Core/Properties/Settings.Designer.cs index ac224ae..cf68fff 100644 --- a/src/bnhtrade.Core/Properties/Settings.Designer.cs +++ b/src/bnhtrade.Core/Properties/Settings.Designer.cs @@ -8,11 +8,11 @@ // //------------------------------------------------------------------------------ -namespace Core.Properties { +namespace bnhtrade.Core.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.6.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/src/bnhtrade.Core/SQL Connection.cs b/src/bnhtrade.Core/SQL Connection.cs deleted file mode 100644 index a819dbb..0000000 --- a/src/bnhtrade.Core/SQL Connection.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Data.SqlClient; -using System.Runtime.InteropServices; - -namespace DatabaseConnection -{ - //[ComVisible(true)] - //[Guid("8bebe939-7a73-4ba3-877b-50cd2a7e4586")] - //[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)] - public interface bnhtradeDbInterface - { - SqlConnection Connection(string DataSource, string InitialCatalog, string UserId, string Password, bool PersistSecurityInfo = true, bool MultipleActiveResultSets = true); - } - - //[ComVisible(true)] - //[Guid("b0e29c9e-d353-4d3a-83dd-5278b520af54")] - //[ClassInterface(ClassInterfaceType.None)] - ////[ProgId("MyNameSpace.Criteria")] - public class bnhtradeDb : bnhtradeDbInterface - { - public SqlConnection Connection(string DataSource, string InitialCatalog, string UserId, string Password, bool PersistSecurityInfo = true, bool MultipleActiveResultSets = true) - { - if (InitialCatalog == "" || DataSource == "" || UserId == "" || Password == "") - { - throw new Exception("Insuficent info supplied for sql connection string"); - } - string connString = - "Data Source=" + DataSource + ";Initial Catalog=" + InitialCatalog + ";Persist Security Info=" + PersistSecurityInfo.ToString() + ";" + - "User ID=" + UserId + ";Password=" + Password + ";MultipleActiveResultSets=" + MultipleActiveResultSets.ToString() + ""; - - SqlConnection sqlConn = new SqlConnection(connString); - - return sqlConn; - } - } -} \ No newline at end of file diff --git a/src/bnhtrade.Core/Test/InboundShipmentInfo.cs b/src/bnhtrade.Core/Test/InboundShipmentInfo.cs new file mode 100644 index 0000000..31da059 --- /dev/null +++ b/src/bnhtrade.Core/Test/InboundShipmentInfo.cs @@ -0,0 +1,83 @@ +using FBAInboundServiceMWS.Model; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Test +{ + public class InboundShipmentInfo + { + private string sqlConnectionString; + public InboundShipmentInfo(string sqlConnectionString) + { + this.sqlConnectionString = sqlConnectionString; + } + public void SetDatabase() + { + var info = new Model.AmazonFBAInbound.ShipmentInfo(); + info.AmazonShipmentId = "BOBBIE2"; + info.DestinationFulfillmentCenterId = "HODG"; + info.LastUpdatedUtc = DateTime.UtcNow; + info.ShipmentName = "the one"; + info.ShipmentStatus = "WORKING"; + + bool all = info.IsSetAll(); + bool allHead = info.IsSetAllHeaderInfo(); + + var itemInfoList = new List(); + + var itemInfo01 = new Model.AmazonFBAInbound.ShipmentItemInfo(); + itemInfo01.AmazonFNSKU = "Z0000000"; + itemInfo01.AmazonShipmentId = "BOBBIE2"; + itemInfo01.QuantityReceived = 4; + itemInfo01.QuantityAllocated = 2; + itemInfo01.SKUNumber = "000291-10"; + itemInfoList.Add(itemInfo01); + + var itemInfo02 = new Model.AmazonFBAInbound.ShipmentItemInfo(); + itemInfo02.AmazonFNSKU = "Z0000001"; + itemInfo02.AmazonShipmentId = "BOBBIE2"; + itemInfo02.QuantityReceived = 3; + itemInfo02.QuantityAllocated = 5; + itemInfo02.SKUNumber = "000292-10"; + + itemInfoList.Add(itemInfo02); + + info.ShipmentItemInfoList = itemInfoList; + + //foreach (var item in itemInfoList) + //{ + // Console.WriteLine("Qty Allocated: " + item.SKUNumber); + // Console.WriteLine("Qty Allocated: " + item.QuantityAllocated); + // Console.WriteLine("Qty Received: " + item.QuantityReceived); + //} + + var howto = new Data.Database.FBAInbound.SetShipmentInfo(sqlConnectionString); + howto.Excecute(info); + + var testkkkk = new Data.Database.FBAInbound.GetShipmentPrimaryKey(sqlConnectionString); + int pknumber = testkkkk.ByAmazonShipmentId("FBA15CJCZ12"); + Console.WriteLine("ShipmentPK: " + pknumber); + } + public void GetMWSInfo() + { + var request = new ListInboundShipmentsRequest(); + + request.LastUpdatedBefore = new DateTime(2019, 06, 21); + request.LastUpdatedAfter = new DateTime(2019, 01, 01); + + var task = new Data.AmazonMWS.FBAInbound.ListInboundShipments(); + task.LastUpdatedBefore = new DateTime(2019, 06, 25); + task.LastUpdatedAfter = new DateTime(2018, 01, 01); + var result = task.GetShipmentInfo(); + + } + public void Test() + { + var job = new Logic.AmazonFBAInbound.UpdateDatabaseShipmentInfo(sqlConnectionString); + job.GetNew(); + } + } +} diff --git a/src/bnhtrade.Core/Test/InboundShipmentInfoSync.cs b/src/bnhtrade.Core/Test/InboundShipmentInfoSync.cs new file mode 100644 index 0000000..a5594a9 --- /dev/null +++ b/src/bnhtrade.Core/Test/InboundShipmentInfoSync.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace bnhtrade.Core.Test +{ + class InboundShipmentInfoSync + { + public InboundShipmentInfoSync(string sqlConnectionString) + { + //var request = new Logic.AmazonFBAInbound.ShipmentInfoUpdateDatabase(sqlConnectionString); + } + + } +} diff --git a/src/bnhtrade.Core/Test/SQLLoop.cs b/src/bnhtrade.Core/Test/SQLLoop.cs new file mode 100644 index 0000000..f9718e1 --- /dev/null +++ b/src/bnhtrade.Core/Test/SQLLoop.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Transactions; + +namespace bnhtrade.Core.Test +{ + public class SQLLoop + { + public void Go(string sqlConnectionString) + { + using (TransactionScope scope = new TransactionScope()) + { + using (SqlConnection conn = new SqlConnection(sqlConnectionString)) + { + MiscFunction.ConsoleUpdate("Starting....."); + conn.Open(); + + int count = 0; + int total; + + using (SqlCommand cmd = new SqlCommand(@" + SELECT COUNT(StockJournalID) + FROM tblStockJournal + ", conn)) + { + total = (int)cmd.ExecuteScalar(); + } + + var progress = new UI.Utility.ConsoleProgressBar(total, "Processing " + total + " records..."); + + using (SqlCommand cmd = new SqlCommand(@" + SELECT * FROM tblStockJournal + ", conn)) + { + using (SqlDataReader reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + count = count + 1; + //progress.Report(2677); + progress.Report(count); + + int journalId = reader.GetInt32(0); + DateTime entryDate = DateTime.SpecifyKind(reader.GetDateTime(3), DateTimeKind.Utc); + DateTime modifiedDate = DateTime.SpecifyKind(reader.GetDateTime(5), DateTimeKind.Utc); + DateTime postDate = entryDate; + DateTime minPostDate = DateTime.SpecifyKind(new DateTime(2015, 06, 24), DateTimeKind.Utc); + + if (modifiedDate < entryDate) + { postDate = entryDate; } + if (postDate < minPostDate) + { postDate = minPostDate; } + + using ( + SqlCommand updateCmd = new SqlCommand(@" + UPDATE tblStockJournal + SET PostDate = @postDate + WHERE StockJournalID = @journalId; + ", conn)) + { + updateCmd.Parameters.AddWithValue("@journalId", journalId); + updateCmd.Parameters.AddWithValue("@postDate", postDate.ToUniversalTime()); + + updateCmd.ExecuteNonQuery(); + + } + } + } + } + progress.Dispose(); + scope.Complete(); + } + } + } + } +} diff --git a/src/bnhtrade.Core/UI/Utility/ConsoleProgressBar.cs b/src/bnhtrade.Core/UI/Utility/ConsoleProgressBar.cs new file mode 100644 index 0000000..ea8af46 --- /dev/null +++ b/src/bnhtrade.Core/UI/Utility/ConsoleProgressBar.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; + +namespace bnhtrade.Core.UI.Utility +{ + class ConsoleProgressBar : IDisposable, IProgress + { + private int MaxProgress { get; set; } + private string PostfixMessge { get; set; } + private DateTime Started { get; set; } + + private const int blockCount = 10; + private readonly TimeSpan animationInterval = TimeSpan.FromSeconds(1.0 / 8); + private const string animation = @"|/-\"; + + private readonly Timer timer; + + private double currentProgress = 0; + private string currentText = string.Empty; + private bool disposed = false; + private int animationIndex = 0; + + public ConsoleProgressBar(int maxProgress, string postfixMessge = "") + { + MaxProgress = maxProgress; + PostfixMessge = postfixMessge; + Started = DateTime.Now; + + timer = new Timer(TimerHandler); + + // A progress bar is only for temporary display in a console window. + // If the console output is redirected to a file, draw nothing. + // Otherwise, we'll end up with a lot of garbage in the target file. + if (!Console.IsOutputRedirected) + { + ResetTimer(); + } + } + + public void Report(int progress) + { + // Make sure value is in [0..1] range + double value = (double) progress / MaxProgress; + + if (progress == 18739) + { + return; + } + + value = Math.Max(0, Math.Min(1, value)); + Interlocked.Exchange(ref currentProgress, value); + } + + private void TimerHandler(object state) + { + lock (timer) + { + if (disposed) return; + + int progressBlockCount = (int)(currentProgress * blockCount); + int percent = (int)(currentProgress * 100); + string text = string.Format("[{0}] [{1}{2}] {3,3}% {4} {5}", + Started.ToString("HH:mm:ss"), + new string('#', progressBlockCount), + new string('-', blockCount - progressBlockCount), + percent, + animation[animationIndex++ % animation.Length], + PostfixMessge + ); + UpdateText(text); + + ResetTimer(); + + // "[" + DateTime.Now.ToString("HH:mm:ss") + "] " + } + } + + private void UpdateText(string text) + { + // Get length of common portion + int commonPrefixLength = 0; + int commonLength = Math.Min(currentText.Length, text.Length); + while (commonPrefixLength < commonLength && text[commonPrefixLength] == currentText[commonPrefixLength]) + { + commonPrefixLength++; + } + + // Backtrack to the first differing character + StringBuilder outputBuilder = new StringBuilder(); + outputBuilder.Append('\b', currentText.Length - commonPrefixLength); + + // Output new suffix + outputBuilder.Append(text.Substring(commonPrefixLength)); + + // If the new text is shorter than the old one: delete overlapping characters + int overlapCount = currentText.Length - text.Length; + if (overlapCount > 0) + { + outputBuilder.Append(' ', overlapCount); + outputBuilder.Append('\b', overlapCount); + } + + Console.Write(outputBuilder); + currentText = text; + } + + private void ResetTimer() + { + timer.Change(animationInterval, TimeSpan.FromMilliseconds(-1)); + } + + public void Dispose() + { + lock (timer) + { + disposed = true; + UpdateText(string.Empty); + } + } + + } +} diff --git a/src/bnhtrade.Core/bnhtrade.Core.csproj b/src/bnhtrade.Core/bnhtrade.Core.csproj index c1db37a..a9d52e3 100644 --- a/src/bnhtrade.Core/bnhtrade.Core.csproj +++ b/src/bnhtrade.Core/bnhtrade.Core.csproj @@ -7,7 +7,7 @@ {339D7413-3DA7-46EA-A55C-255A9A6B95EB} Library Properties - bnhtradeDatabaseClient + bnhtrade.Core bnhtrade.Core v4.7.1 512 @@ -37,9 +37,6 @@ - - ..\..\packages\ABrain.AmazonMWS.1.0.1.6\lib\ABrain.AmazonMWS.dll - @@ -52,6 +49,25 @@ + + + + + + + + + + + + + + + + + + + @@ -59,7 +75,8 @@ True Settings.settings - + + @@ -70,6 +87,28 @@ + + + {9c7d6775-4f06-4881-87a0-b9514f2f3033} + FBAInboundServiceMWS + + + {fe2fe872-f92e-4b47-bcc2-e41b9c10eb96} + MarketplaceWebServiceProducts + + + {52b09e65-f1b4-4b99-b8e2-4a0b2e3201c2} + MarketplaceWebService + + + {bde52371-cad4-4809-b8f7-9a218ee02464} + MWSClientCsRuntime + + + {1fe13ef5-aabf-4080-b790-990b9069c634} + MWSFinancesService + +