diff --git a/README.md b/README.md index c9b583db..a82cef2a 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Install-Package CSharpAmazonSpAPI ### Tasks #### Seller +- [x] [OrdersV2026-01-01](https://developer-docs.amazon.com/sp-api/reference/orders-v2026-01-01) - [x] [OrdersV0](https://developer-docs.amazon.com/sp-api/docs/orders-api-v0-reference) - [x] [Reports](https://developer-docs.amazon.com/sp-api/docs/reports-api-v2021-06-30-reference) - [x] [FinancesV0](https://developer-docs.amazon.com/sp-api/docs/finances-api-reference) @@ -141,86 +142,67 @@ Please see [here](https://github.com/abuzuhri/Amazon-SP-API-CSharp/blob/main/Sou ### Order List For more order samples, please check [Here](https://github.com/abuzuhri/Amazon-SP-API-CSharp/blob/main/Source/FikaAmazonAPI.SampleCode/OrdersSample.cs). ```CSharp -ParameterOrderList searchOrderList = new ParameterOrderList(); -searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); -searchOrderList.OrderStatuses = new List(); -searchOrderList.OrderStatuses.Add(OrderStatuses.Canceled); -var orders = amazonConnection.Orders.GetOrders(searchOrderList); - + ParameterSearchOrders searchOrderList = new ParameterSearchOrders{ + CreatedAfter = DateTime.UtcNow.AddMinutes(-600000), + MaxNumberOfPages = 1 + }; + var orders = amazonConnection.Orders.SearchOrders(searchOrderList); ``` ### Order List with parameter ```CSharp -ParameterOrderList searchOrderList = new ParameterOrderList(); -searchOrderList.CreatedAfter = DateTime.UtcNow.AddHours(-24); -searchOrderList.OrderStatuses = new List(); -searchOrderList.OrderStatuses.Add(OrderStatuses.Unshipped); -searchOrderList.MarketplaceIds = new List { MarketPlace.UnitedArabEmirates.ID }; -var orders = amazonConnection.Orders.GetOrders(searchOrderList); +ParameterSearchOrders searchOrderList = new ParameterSearchOrders{ + CreatedAfter = DateTime.UtcNow.AddHours(-24), + MaxNumberOfPages = 1, + FulfillmentStatuses = new List + { + FulfillmentStatus20260101.UNSHIPPED + } + MarketplaceIds = new List + { + MarketPlace.Germany.ID, + MarketPlace.Australia.ID, + MarketPlace.France.ID + } + }; +var orders = amazonConnection.Orders.SearchOrders(searchOrderList); ``` +#### ParameterSearchOrders (v2026-01-01) Class -### Order List with parameter including PII data Simple ```CSharp -var parameterOrderList = new ParameterOrderList - { - CreatedAfter = DateTime.UtcNow.AddHours(-24), - OrderStatuses = new List { OrderStatuses.Unshipped }, - MarketplaceIds = new List { MarketPlace.UnitedArabEmirates.ID }, - IsNeedRestrictedDataToken = true - }; - -var orders = _amazonConnection.Orders.GetOrders(parameterOrderList); +ParameterSearchOrders searchOrderList = new ParameterSearchOrders{ + public ICollection MarketplaceIds { get; set; } + public DateTime? LastUpdatedAfter { get; set; } + public DateTime? LastUpdatedBefore { get; set; } + public DateTime? CreatedAfter { get; set; } + public DateTime? CreatedBefore { get; set; } + public int? MaxResultsPerPage { get; set; } = 100; + public string PaginationToken { get; set; } + public ICollection FulfillmentStatuses { get; set; } + public ICollection FulfilledBy { get; set; } + public ICollection AmazonOrderIds { get; set; } + public ICollection IncludedData { get; set; } + // ClientSide + public int? MaxNumberOfPages { get; set; } +}; ``` -### Order List with parameter including PII data — Advanced (if you want to get specific data elements only) -```CSharp -var parameterOrderList = new ParameterOrderList - { - CreatedAfter = DateTime.UtcNow.AddHours(-24), - OrderStatuses = new List { OrderStatuses.Unshipped }, - MarketplaceIds = new List { MarketPlace.UnitedArabEmirates.ID }, - IsNeedRestrictedDataToken = true, - RestrictedDataTokenRequest = new CreateRestrictedDataTokenRequest - { - restrictedResources = new List - { - new RestrictedResource - { - method = Method.GET.ToString(), - path = ApiUrls.OrdersApiUrls.Orders, - dataElements = new List { "buyerInfo", "shippingAddress" } - } - } - } - }; -var orders = _amazonConnection.Orders.GetOrders(parameterOrderList); +#### ParameterGetOrder20260101 Class +```CSharp +ParameterGetOrder20260101 GetOrderParam = new ParameterGetOrder20260101{ + public string OrderId { get; set; } + public ICollection IncludedData { get; set; } +}; ``` -### Order List data from Sandbox -```CSharp -AmazonConnection amazonConnection = new AmazonConnection(new AmazonCredential() -{ - ClientId = "amzn1.application-XXX-client.XXXXXXXXXXXXXXXXXXXXXXXXXXXX", - ClientSecret = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - RefreshToken= "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", - Environment=Environments.Sandbox -}); -var orders = amazonConnection.Orders.GetOrders -( - new FikaAmazonAPI.Parameter.Order.ParameterOrderList - { - TestCase = Constants.TestCase200 - } -); -``` ### Report List For more report samples, please check [Here](https://github.com/abuzuhri/Amazon-SP-API-CSharp/blob/main/Source/FikaAmazonAPI.SampleCode/ReportsSample.cs). diff --git a/Source/FikaAmazonAPI.SampleCode/OrdersSample.cs b/Source/FikaAmazonAPI.SampleCode/OrdersSample.cs index b2b75af9..09b790c7 100644 --- a/Source/FikaAmazonAPI.SampleCode/OrdersSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/OrdersSample.cs @@ -1,8 +1,12 @@ using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders; +using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101; using FikaAmazonAPI.AmazonSpApiSDK.Models.Token; using FikaAmazonAPI.AmazonSpApiSDK.Services; using FikaAmazonAPI.Parameter; using FikaAmazonAPI.Parameter.Order; +using FikaAmazonAPI.Utils; +using System.Linq; +using System.Net.WebSockets; using static FikaAmazonAPI.Utils.Constants; namespace FikaAmazonAPI.SampleCode @@ -15,49 +19,295 @@ public OrdersSample(AmazonConnection amazonConnection) this.amazonConnection = amazonConnection; } + /// + /// Only retrieve one page of results and manually paginate with PaginationToken. + /// PaginationToken replaces NextToken from v0, but note that it expires after 24 hours. + /// + /// v0-Version of: GetOrders with MaxNumberOfPages=1, then GetGetOrdersByNextToken + /// + public void SearchOrdersOnePageWithPaginationToken() + { + var parameter = new ParameterSearchOrders + { + CreatedAfter = DateTime.UtcNow.AddMinutes(-600000), + MaxNumberOfPages = 1, + FulfillmentStatuses = new List + { + FulfillmentStatus20260101.SHIPPED + } + }; - public void GetOrdersOnePageWithNextPageToken() + // Get First Page + var firstPage = amazonConnection.Orders.SearchOrdersPage(parameter); + + Console.WriteLine($"First Page: {firstPage.Orders?.Count} Orders"); + + // Manually paginate with PaginationToken + var paginationToken = firstPage.PaginationToken; + while (!string.IsNullOrEmpty(paginationToken)) + { + parameter.PaginationToken = paginationToken; + var nextPage = amazonConnection.Orders.SearchOrdersPage(parameter); + + Console.WriteLine($"Next Page: {nextPage.Orders?.Count} Orders"); + paginationToken = nextPage.PaginationToken; + } + } + + + // ------------------------------------------------------------------ + // SearchOrders - v2026-01-01 + // ------------------------------------------------------------------ + + /// + /// Simple Example: Retrieve all shipped orders from the last 7 days. + /// Library automatically paginates through all pages. + /// + /// v0-version of: GetOrders mit OrderStatuses = Shipped + /// + public void SearchOrders() { - // ONLY USE THIS SAMPLE IF YOU NEED TO GET ONE PAGE EACH TIME other wise remove parameter 'MaxNumberOfPages' and libaray will fetch all orders to you - ParameterOrderList searchOrderList = new ParameterOrderList(); - searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); - searchOrderList.MaxNumberOfPages = 1; - searchOrderList.OrderStatuses = new List(); - searchOrderList.OrderStatuses.Add(OrderStatuses.Shipped); + var parameter = new ParameterSearchOrders + { + CreatedAfter = DateTime.UtcNow.AddDays(-7), + FulfillmentStatuses = new List + { + FulfillmentStatus20260101.SHIPPED + }, + AmazonOrderIds = new List + { + "403-1710607-6240347", + "403-5583945-7236361", + "403-3320829-4528316", + "406-2574982-2047546" + } + }; - searchOrderList.AmazonOrderIds = new List(); + var orders = amazonConnection.Orders.SearchOrders(parameter); - var orders = amazonConnection.Orders.GetOrders(searchOrderList); - var nextPageToken = orders.NextToken; - while (!string.IsNullOrEmpty(nextPageToken)) + foreach (var order in orders) { - var moreOrders = amazonConnection.Orders.GetGetOrdersByNextToken(nextPageToken, searchOrderList); - nextPageToken = moreOrders.NextToken; + Console.WriteLine($"Order: {order.OrderId}, Status: {order.Fulfillment?.FulfillmentStatus}"); } + } + /// + /// Lookup of Orders by their AmazonOrderIds + /// v0-version of: GetOrders mit AmazonOrderIds + /// + public void SearchOrdersByIds() + { + var parameter = new ParameterSearchOrders + { + CreatedAfter = DateTime.UtcNow.AddDays(-30), + AmazonOrderIds = new List() { "403-1710607-6240347" } + }; + + var orders = amazonConnection.Orders.SearchOrders(parameter); } - public void GetOrders() + + /// + /// PII access in v2026-01-01 – NO RDT needed! + /// Easily include buyer and recipient data by setting includedData=BUYER,RECIPIENT. Access is role-based. + /// + /// v0-version of: GetOrders with IsNeedRestrictedDataToken=true + RDT-Creation + /// + public void SearchOrdersPII() { - ParameterOrderList searchOrderList = new ParameterOrderList(); - searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); + // No RDT, no IsNeedRestrictedDataToken – just request the data directly. + // Access to PII data is now role-based, so make sure your app has the appropriate PII roles assigned. + var parameter = new ParameterSearchOrders + { + CreatedAfter = DateTime.UtcNow.AddDays(-1), + FulfillmentStatuses = new List + { + FulfillmentStatus20260101.UNSHIPPED + }, + IncludedData = new List + { + IncludedData20260101.BUYER, + IncludedData20260101.RECIPIENT + } + }; - searchOrderList.OrderStatuses = new List(); - searchOrderList.OrderStatuses.Add(OrderStatuses.Shipped); + var orders = amazonConnection.Orders.SearchOrders(parameter); + } - searchOrderList.AmazonOrderIds = new List(); - searchOrderList.AmazonOrderIds.Add("403-1710607-6240347"); - searchOrderList.AmazonOrderIds.Add("403-5583945-7236361"); - searchOrderList.AmazonOrderIds.Add("403-3320829-4528316"); - searchOrderList.AmazonOrderIds.Add("406-2574982-2047546"); + // ------------------------------------------------------------------ + // GetOrder - v2026-01-01 + // ------------------------------------------------------------------ - var orders = amazonConnection.Orders.GetOrders(searchOrderList); + /// + /// Single order retrieval – items are ALWAYS included in the response. + /// Added "Single" to give the Original GetOrder a deprication Msg + Error. + /// v0-version of: GetOrder + GetOrderItems (2 Calls → 1 Call) + /// + public void GetSingleOrder() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + }; + var order = amazonConnection.Orders.GetOrder(parameter); + } + + /// + /// Single order retrieval – added FilfillmentInfos. + /// + public void GetOrderFulfillmentInfo() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + IncludedData = new List + { + IncludedData20260101.FULFILLMENT + } + }; + var order = amazonConnection.Orders.GetOrder(parameter); + var FulfillmentBy = order?.Fulfillment?.FulfilledBy; + var FulfillmentStatus = order?.Fulfillment?.FulfillmentStatus; + } + + /// + /// All data at once – convenience method to retrieve all available data in one call. Just set all IncludedData values. + /// v0-version of: GetOrder + GetOrderItems + GetOrderBuyerInfo + GetOrderAddress + GetOrderItemsBuyerInfo (5 Calls → 1 Call) + /// + public void GetOrderFull() + { + var order = amazonConnection.Orders.GetOrderFull("402-0467973-4229120"); + Buyer? BuyerInfo = order?.Buyer; + Recipient? RecipientInfo = order?.Recipient; + OrderFulfillment? FulfillmentInfo = order?.Fulfillment; + OrderProceeds? ProceedsInfo = order?.Proceeds; + // Expenses are infos that gets added to the Order and OrderItems, they are not in a separate node in the response like the other includedData, so you can find them directly in the Order and OrderItems objects. + // Attached to OrderItems: + OrderItemExpense? Expenses = order?.OrderItems.FirstOrDefault()?.Expense; + OrderItemPromotion? PromotionInfo = order?.OrderItems.FirstOrDefault()?.Promotion; + OrderItemCancellation? CancellationInfo = order?.OrderItems.FirstOrDefault()?.Cancellation; + List? PackagesList = order?.Packages.ToList(); + + OrderConverter.OrderProgramInfo allProgramsInfos = OrderConverter.OrderProgramInfoEx(order); + List AllOrderItemInfos = allProgramsInfos.orderItems; + } + + /// + /// Easy to Use Converters for order programs. Just pass the Order object to the constructor and it will parse the program information for you and give you easy to use boolean properties. + /// + public void GetProgramsFromOrder() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + }; + var order = amazonConnection.Orders.GetOrder(parameter); + + OrderConverter.OrderProgramInfo ProgramInfos = new OrderConverter.OrderProgramInfo(order); + + bool isPrime = ProgramInfos.isPrime; + bool isPremium = ProgramInfos.isPremium; + bool isInStorePickUp = ProgramInfos.isInStorePickUp; + bool isFBMShipPlus = ProgramInfos.isFBMShipPlus; + bool isDeliveryByAmazon = ProgramInfos.isDeliveryByAmazon; + bool isAmazonHaul = ProgramInfos.isAmazonHaul; + bool isAmazonEasyShip = ProgramInfos.isAmazonEasyShip; + bool isAmazonBusiness = ProgramInfos.isAmazonBusiness; + bool isAmazonBazaar = ProgramInfos.isAmazonBazaar; + bool isPreorder = ProgramInfos.isPreorder; + } + + /// + /// Easy to Use Converters for order item programs. Just pass the Order object to the constructor and it will parse the program information for each order item and give you easy to use boolean properties. + /// + public void GetProgramsFromOrderItems() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + }; + var order = amazonConnection.Orders.GetOrder(parameter); + + OrderConverter.OrderProgramInfo allProgramsInfos = OrderConverter.OrderProgramInfoEx(order); + + List AllOrderItemInfos = allProgramsInfos.orderItems; + + foreach (OrderConverter.OrderItemProgramInfo item in allProgramsInfos.orderItems) + { + bool isTransparent = item.isTransparency; + bool isSubscribeAndSave = item.isSubscribe_And_Save; + } + } + + + // ------------------------------------------------------------------ + // Reworked GetOrderFunctions to fit the new GetOrder endpoint with includedData parameter + // ------------------------------------------------------------------ + + public void GetOrderBuyerInfo() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + IncludedData = new List + { + IncludedData20260101.BUYER + } + }; + var order = amazonConnection.Orders.GetOrder(parameter); + var BuyerInfo = order?.Buyer; } + public void GetOrderAddress() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + IncludedData = new List + { + IncludedData20260101.RECIPIENT, + IncludedData20260101.BUYER, + } + }; + var order = amazonConnection.Orders.GetOrder(parameter); + var BuyerCompanyName = order?.Buyer?.BuyerCompanyName; + var ShippingAddress = order?.Recipient?.DeliveryAddress; + var DeliveryPreferences = order?.Recipient?.DeliveryPreference; + } + + public void GetOrderItems() + { + var parameter = new ParameterGetOrder20260101 + { + OrderId = "402-0467973-4229120", + // No need to specify IncludedData to get order items – they are always included in the response. + }; + var order = amazonConnection.Orders.GetOrder(parameter); + var orderItems = order?.OrderItems; + } + + public List GetOrderListFulfillmentChannels() + { + var parameter = new ParameterSearchOrders + { + CreatedAfter = DateTime.UtcNow.AddDays(-24), + FulfillmentStatuses = new List { FulfillmentStatus20260101.SHIPPED } + }; + var orders = amazonConnection.Orders.SearchOrders(parameter); + + return orders.ToList(); + } + + + + #region Obsolete v0 methods + /// /// You must have valid PII developer to be able to call this method /// + [Obsolete("This method is using GetOrders which is deprecated, please use SearchOrdersPII instead.")] public void GetOrdersPIISimple() { + /* ParameterOrderList searchOrderList = new ParameterOrderList(); searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); @@ -68,9 +318,14 @@ public void GetOrdersPIISimple() searchOrderList.IsNeedRestrictedDataToken = true; var orders = amazonConnection.Orders.GetOrders(searchOrderList); + */ + throw new NotImplementedException("This method is using GetOrders which is deprecated, please use SearchOrdersPII instead."); } + + [Obsolete("This method is using GetOrders which is deprecated, please use SearchOrdersPII instead.")] public void GetOrdersPIIAdvance() { + /* ParameterOrderList searchOrderList = new ParameterOrderList(); searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); @@ -92,47 +347,32 @@ public void GetOrdersPIIAdvance() searchOrderList.IsNeedRestrictedDataToken = true; var orders = amazonConnection.Orders.GetOrders(searchOrderList); - } - - public void GetOrderBuyerInfo() - { - var BuyerInfo = amazonConnection.Orders.GetOrderBuyerInfo("402-0467973-4229120"); - } - - - public void GetOrderAddress() - { - // This method has been changed and is a breaking change - // If you would like the default behavior please reference the - // ShippingAddress variable - var Address = amazonConnection.Orders.GetOrderAddress("402-0467973-4229120"); - var BuyerCompanyName = Address.BuyerCompanyName; - var ShippingAddress = Address.ShippingAddress; - var DeliveryPreferences = Address.DeliveryPreferences; - } - - - public void GetOrderItems() - { - var Items = amazonConnection.Orders.GetOrderItems("402-0467973-4229120"); + */ + throw new NotImplementedException("This method is using GetOrders which is deprecated, please use SearchOrdersPII instead."); } /// /// You must have valid PII developer to be able to call this method /// + [Obsolete("GetOrderItemsPIISimple is depricated, use GetOrder")] public void GetOrderItemsPIISimple() { + /* ParameterBasedPII parameterBasedPII = new ParameterBasedPII(); parameterBasedPII.IsNeedRestrictedDataToken = true; var order = amazonConnection.Orders.GetOrderItems("405-0426616-1636335", parameterBasedPII); + */ + throw new NotImplementedException("GetOrderItemsPIISimple is depricated, use GetOrderItems"); } /// /// You must have valid PII developer to be able to call this method /// + [Obsolete("GetOrderItemsPII is depricated, use GetOrder")] public void GetOrderItemsPII() { + /* var restrictedResource = new RestrictedResource(); restrictedResource.method = Method.GET.ToString(); restrictedResource.path = ApiUrls.OrdersApiUrls.OrderItems("405-0426616-1636335"); @@ -149,25 +389,66 @@ public void GetOrderItemsPII() parameterBasedPII.RestrictedDataTokenRequest = createRDT; var order = amazonConnection.Orders.GetOrderItems("405-0426616-1636335", parameterBasedPII); + */ + throw new NotImplementedException("GetOrderItemsPII is depricated, use GetOrderItems"); } - public OrderList GetOrderListFulfillmentChannels() + [Obsolete("GetOrdersOnePageWithNextPageToken is using NextToken which is deprecated, please use SearchOrdersOnePageWithPaginationToken instead which uses PaginationToken and note that PaginationToken expires after 24 hours.")] + public void GetOrdersOnePageWithNextPageToken() { - var parameterOrderList = new ParameterOrderList + // ONLY USE THIS SAMPLE IF YOU NEED TO GET ONE PAGE EACH TIME other wise remove parameter 'MaxNumberOfPages' and libaray will fetch all orders to you + /* + ParameterOrderList searchOrderList = new ParameterOrderList(); + searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); + searchOrderList.MaxNumberOfPages = 1; + searchOrderList.OrderStatuses = new List(); + searchOrderList.OrderStatuses.Add(OrderStatuses.Shipped); + + searchOrderList.AmazonOrderIds = new List(); + + var orders = amazonConnection.Orders.GetOrders(searchOrderList); + var nextPageToken = orders.NextToken; + while (!string.IsNullOrEmpty(nextPageToken)) { - CreatedAfter = DateTime.UtcNow.AddDays(-24), - //FulfillmentChannels = new List { FulfillmentChannels.AFN }, - OrderStatuses = new List { OrderStatuses.Shipped } - }; + var moreOrders = amazonConnection.Orders.GetGetOrdersByNextToken(nextPageToken, searchOrderList); + nextPageToken = moreOrders.NextToken; + } + */ + throw new NotImplementedException("GetOrdersOnePageWithNextPageToken is using NextToken which is deprecated, please use SearchOrdersOnePageWithPaginationToken instead which uses PaginationToken and note that PaginationToken expires after 24 hours."); + } - var orders = amazonConnection.Orders.GetOrders(parameterOrderList); + [Obsolete("This method is using GetOrders which is deprecated, please use SearchOrders instead.")] + public void GetOrders() + { + /* + ParameterOrderList searchOrderList = new ParameterOrderList(); + searchOrderList.CreatedAfter = DateTime.UtcNow.AddMinutes(-600000); + + searchOrderList.OrderStatuses = new List(); + searchOrderList.OrderStatuses.Add(OrderStatuses.Shipped); - return orders; + searchOrderList.AmazonOrderIds = new List(); + searchOrderList.AmazonOrderIds.Add("403-1710607-6240347"); + searchOrderList.AmazonOrderIds.Add("403-5583945-7236361"); + searchOrderList.AmazonOrderIds.Add("403-3320829-4528316"); + searchOrderList.AmazonOrderIds.Add("406-2574982-2047546"); + + var orders = amazonConnection.Orders.GetOrders(searchOrderList); + */ + throw new NotImplementedException("This method is using GetOrders which is deprecated, please use SearchOrders instead."); } + [Obsolete("This method is using GetOrderItems which is deprecated, please use GetOrder instead with IncludedData=BUYER to get buyer info together with order items.")] public void GetOrderItemsBuyerInfo() { + + /* var ItemsBuyerInfo = amazonConnection.Orders.GetOrderItemsBuyerInfo("402-0467973-4229120"); + */ + throw new NotImplementedException("This method is using GetOrderItems which is deprecated, please use GetOrder instead with IncludedData=BUYER to get buyer info together with order items."); } + + #endregion + } } diff --git a/Source/FikaAmazonAPI.SampleCode/SandboxOrderSample.cs b/Source/FikaAmazonAPI.SampleCode/SandboxOrderSample.cs index b4ae6b7c..7d477a76 100644 --- a/Source/FikaAmazonAPI.SampleCode/SandboxOrderSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/SandboxOrderSample.cs @@ -17,13 +17,15 @@ public SandboxOrderSample(AmazonConnection amazonConnection) public void GetOrderTestCase200() { - var orders = amazonConnection.Orders.GetOrders + /* + var orders = amazonConnection.Orders.GetOrder ( - new FikaAmazonAPI.Parameter.Order.ParameterOrderList + new FikaAmazonAPI.Parameter.Order.ParameterGetOrder { TestCase = Constants.TestCase200 } ); + */ } } } diff --git a/Source/FikaAmazonAPI.SampleCode/TokenSample.cs b/Source/FikaAmazonAPI.SampleCode/TokenSample.cs index a9c1bab7..4bd88ee7 100644 --- a/Source/FikaAmazonAPI.SampleCode/TokenSample.cs +++ b/Source/FikaAmazonAPI.SampleCode/TokenSample.cs @@ -21,11 +21,13 @@ public TokenSample(AmazonConnection amazonConnection) } + [Obsolete("PII is not a thing anymore (OrderAPIv2026-01-01) -> Just Use Normal GetOrder")] public void OrderPII() { + throw new NotImplementedException("PII is not a thing anymore (OrderAPIv2026-01-01) -> Just Use Normal GetOrder"); var restrictedResource = new RestrictedResource(); restrictedResource.method = Method.GET.ToString(); - restrictedResource.path = ApiUrls.OrdersApiUrls.OrderItems("404-7777403-8594716"); + //restrictedResource.path = ApiUrls.OrdersApiUrls.OrderItems("404-7777403-8594716"); //restrictedResource.dataElements = new List { "buyerInfo", "shippingAddress" }; @@ -38,14 +40,16 @@ public void OrderPII() parameterBasedPII.IsNeedRestrictedDataToken = true; parameterBasedPII.RestrictedDataTokenRequest = createRDT; - var order= amazonConnection.Orders.GetOrderItems("404-7777403-8594716", parameterBasedPII); + //var order= amazonConnection.Orders.GetOrderItems("404-7777403-8594716", parameterBasedPII); } + [Obsolete("PII is not a thing anymore (OrderAPIv2026-01-01) -> Just Use Normal GetOrder")] public void OrdersPII() { + throw new NotImplementedException("PII is not a thing anymore (OrderAPIv2026-01-01) -> Just Use Normal GetOrder"); var restrictedResource = new RestrictedResource(); restrictedResource.method = Method.GET.ToString(); - restrictedResource.path = ApiUrls.OrdersApiUrls.OrderItems("404-7777403-8594716"); + //restrictedResource.path = ApiUrls.OrdersApiUrls.OrderItems("404-7777403-8594716"); //restrictedResource.dataElements = new List { "buyerInfo", "shippingAddress" }; @@ -63,7 +67,7 @@ public void OrdersPII() searchOrderList.RestrictedDataTokenRequest = createRDT; searchOrderList.IsNeedRestrictedDataToken = true; - var orders = amazonConnection.Orders.GetOrders(searchOrderList); + //var orders = amazonConnection.Orders.GetOrders(searchOrderList); } diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/BuyerRecipient20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/BuyerRecipient20260101.cs new file mode 100644 index 00000000..928aea13 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/BuyerRecipient20260101.cs @@ -0,0 +1,84 @@ +using Newtonsoft.Json; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Buyer information. Requires includedData=BUYER. + /// + public class Buyer + { + [JsonProperty("buyerEmail")] + public string BuyerEmail { get; set; } + + [JsonProperty("buyerName")] + public string BuyerName { get; set; } + + [JsonProperty("buyerCompanyName")] + public string BuyerCompanyName { get; set; } + + [JsonProperty("buyerPurchaseOrderNumber")] + public string BuyerPurchaseOrderNumber { get; set; } + } + + /// + /// Recipient/delivery address information. Requires includedData=RECIPIENT. + /// + public class Recipient + { + [JsonProperty("deliveryAddress")] + public DeliveryAddress DeliveryAddress { get; set; } + + [JsonProperty("deliveryPreference")] + public object DeliveryPreference { get; set; } + } + + public class DeliveryAddress + { + [JsonProperty("name")] + public string Name { get; set; } + + [JsonProperty("addressLine1")] + public string AddressLine1 { get; set; } + + [JsonProperty("addressLine2")] + public string AddressLine2 { get; set; } + + [JsonProperty("addressLine3")] + public string AddressLine3 { get; set; } + + [JsonProperty("city")] + public string City { get; set; } + + [JsonProperty("county")] + public string County { get; set; } + + [JsonProperty("district")] + public string District { get; set; } + + [JsonProperty("stateOrRegion")] + public string StateOrRegion { get; set; } + + [JsonProperty("municipality")] + public string Municipality { get; set; } + + [JsonProperty("postalCode")] + public string PostalCode { get; set; } + + [JsonProperty("countryCode")] + public string CountryCode { get; set; } + + [JsonProperty("phone")] + public string Phone { get; set; } + + [JsonProperty("addressType")] + public string AddressType { get; set; } + + [JsonProperty("companyName")] + public string CompanyName { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Enums20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Enums20260101.cs new file mode 100644 index 00000000..c8e63c79 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Enums20260101.cs @@ -0,0 +1,88 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System.Runtime.Serialization; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Values for the includedData query parameter in the Orders API v2026-01-01. + /// Controls which data is returned in the response. + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum IncludedData20260101 + { + [EnumMember(Value = "BUYER")] + BUYER, + + [EnumMember(Value = "RECIPIENT")] + RECIPIENT, + + [EnumMember(Value = "FULFILLMENT")] + FULFILLMENT, + + [EnumMember(Value = "PROCEEDS")] + PROCEEDS, + + [EnumMember(Value = "EXPENSE")] + EXPENSE, + + [EnumMember(Value = "PROMOTION")] + PROMOTION, + + [EnumMember(Value = "CANCELLATION")] + CANCELLATION, + + [EnumMember(Value = "PACKAGES")] + PACKAGES + } + + /// + /// Fulfillment status values in v2026-01-01 (replaces OrderStatuses from v0). + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum FulfillmentStatus20260101 + { + [EnumMember(Value = "UNSHIPPED")] + UNSHIPPED, + + [EnumMember(Value = "PARTIALLY_SHIPPED")] + PARTIALLY_SHIPPED, + + [EnumMember(Value = "SHIPPED")] + SHIPPED, + + [EnumMember(Value = "CANCELLED")] + CANCELLED, + + [EnumMember(Value = "PENDING")] + PENDING, + + [EnumMember(Value = "UNFULFILLABLE")] + UNFULFILLABLE, + + [EnumMember(Value = "PENDING_AVAILABILITY")] + PENDING_AVAILABILITY, + + [EnumMember(Value = "INVOICE_UNCONFIRMED")] + INVOICE_UNCONFIRMED + } + + /// + /// FulfilledBy values in v2026-01-01 (replaces FulfillmentChannels from v0). + /// MFN -> MERCHANT, AFN -> AMAZON. + /// + [JsonConverter(typeof(StringEnumConverter))] + public enum FulfilledBy20260101 + { + [EnumMember(Value = "MERCHANT")] + MERCHANT, + + [EnumMember(Value = "AMAZON")] + AMAZON + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Fulfillment20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Fulfillment20260101.cs new file mode 100644 index 00000000..9262039b --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Fulfillment20260101.cs @@ -0,0 +1,95 @@ +using Newtonsoft.Json; +using System; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Fulfillment information at the order level. + /// Requires includedData=FULFILLMENT. + /// + public class OrderFulfillment + { + [JsonProperty("fulfillmentStatus")] + public string FulfillmentStatus { get; set; } + + [JsonProperty("fulfilledBy")] + public string FulfilledBy { get; set; } + + [JsonProperty("fulfillmentServiceLevel")] + public string FulfillmentServiceLevel { get; set; } + + [JsonProperty("shipByWindow")] + public DateTimeWindow ShipByWindow { get; set; } + + [JsonProperty("deliverByWindow")] + public DateTimeWindow DeliverByWindow { get; set; } + } + + /// + /// Fulfillment information at the order item level. + /// + public class OrderItemFulfillment + { + [JsonProperty("quantityFulfilled")] + public int? QuantityFulfilled { get; set; } + + [JsonProperty("packing")] + public PackingInfo Packing { get; set; } + + [JsonProperty("shipping")] + public ShippingInfo Shipping { get; set; } + + [JsonProperty("picking")] + public PickingInfo Picking { get; set; } + } + + public class DateTimeWindow + { + [JsonProperty("earliestDateTime")] + public DateTime? EarliestDateTime { get; set; } + + [JsonProperty("latestDateTime")] + public DateTime? LatestDateTime { get; set; } + } + + public class PackingInfo + { + [JsonProperty("giftOption")] + public bool? GiftOption { get; set; } + + [JsonProperty("giftMessage")] + public string GiftMessage { get; set; } + + [JsonProperty("giftWrapLevel")] + public string GiftWrapLevel { get; set; } + } + + public class ShippingInfo + { + [JsonProperty("scheduledDeliveryWindow")] + public DateTimeWindow ScheduledDeliveryWindow { get; set; } + + [JsonProperty("internationalShipping")] + public InternationalShipping InternationalShipping { get; set; } + + [JsonProperty("shippingConstraints")] + public object ShippingConstraints { get; set; } + } + + public class InternationalShipping + { + [JsonProperty("iossNumber")] + public string IossNumber { get; set; } + } + + public class PickingInfo + { + [JsonProperty("substitutionPreference")] + public object SubstitutionPreference { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Money20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Money20260101.cs new file mode 100644 index 00000000..c349db8d --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Money20260101.cs @@ -0,0 +1,18 @@ +using Newtonsoft.Json; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + public class Money + { + [JsonProperty("currencyCode")] + public string CurrencyCode { get; set; } + + [JsonProperty("amount")] + public string Amount { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Order20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Order20260101.cs new file mode 100644 index 00000000..45535d76 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Order20260101.cs @@ -0,0 +1,83 @@ +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Represents an order in the Orders API v2026-01-01. + /// + public class Order20260101 + { + [JsonProperty("orderId")] + public string OrderId { get; set; } + + [JsonProperty("orderAliases")] + public IList OrderAliases { get; set; } + + [JsonProperty("salesChannel")] + public SalesChannel SalesChannel { get; set; } + + [JsonProperty("createdTime")] + public DateTime? CreatedTime { get; set; } + + [JsonProperty("lastUpdatedTime")] + public DateTime? LastUpdatedTime { get; set; } + + [JsonProperty("programs")] + public IList Programs { get; set; } + + [JsonProperty("associatedOrders")] + public IList AssociatedOrders { get; set; } + + [JsonProperty("fulfillment")] + public OrderFulfillment Fulfillment { get; set; } + + [JsonProperty("buyer")] + public Buyer Buyer { get; set; } + + [JsonProperty("recipient")] + public Recipient Recipient { get; set; } + + [JsonProperty("proceeds")] + public OrderProceeds Proceeds { get; set; } + + [JsonProperty("packages")] + public IList Packages { get; set; } + + [JsonProperty("orderItems")] + public IList OrderItems { get; set; } + } + + public class OrderAlias + { + [JsonProperty("aliasType")] + public string AliasType { get; set; } + + [JsonProperty("aliasId")] + public string AliasId { get; set; } + } + + public class SalesChannel + { + [JsonProperty("marketplaceId")] + public string MarketplaceId { get; set; } + + [JsonProperty("marketplaceName")] + public string MarketplaceName { get; set; } + } + + public class AssociatedOrder + { + [JsonProperty("associationType")] + public string AssociationType { get; set; } + + [JsonProperty("orderId")] + public string OrderId { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/OrderItem20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/OrderItem20260101.cs new file mode 100644 index 00000000..688411c9 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/OrderItem20260101.cs @@ -0,0 +1,139 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Represents an order item in the Orders API v2026-01-01. + /// + public class OrderItem20260101 + { + [JsonProperty("orderItemId")] + public string OrderItemId { get; set; } + + [JsonProperty("quantityOrdered")] + public int? QuantityOrdered { get; set; } + + [JsonProperty("product")] + public Product Product { get; set; } + + [JsonProperty("programs")] + public IList Programs { get; set; } + + [JsonProperty("fulfillment")] + public OrderItemFulfillment Fulfillment { get; set; } + + [JsonProperty("proceeds")] + public OrderItemProceeds Proceeds { get; set; } + + [JsonProperty("expense")] + public OrderItemExpense Expense { get; set; } + + [JsonProperty("promotion")] + public OrderItemPromotion Promotion { get; set; } + + [JsonProperty("cancellation")] + public OrderItemCancellation Cancellation { get; set; } + + [JsonProperty("measurement")] + public object Measurement { get; set; } + } + + public class Product + { + [JsonProperty("asin")] + public string Asin { get; set; } + + [JsonProperty("sellerSku")] + public string SellerSku { get; set; } + + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("condition")] + public ProductCondition Condition { get; set; } + + [JsonProperty("price")] + public ProductPrice Price { get; set; } + + [JsonProperty("customization")] + public ProductCustomization Customization { get; set; } + + [JsonProperty("serialNumbers")] + public IList SerialNumbers { get; set; } + } + + public class ProductCondition + { + [JsonProperty("conditionType")] + public string ConditionType { get; set; } + + [JsonProperty("conditionSubtype")] + public string ConditionSubtype { get; set; } + + [JsonProperty("conditionNote")] + public string ConditionNote { get; set; } + } + + public class ProductPrice + { + [JsonProperty("unitPrice")] + public Money UnitPrice { get; set; } + + [JsonProperty("priceDesignation")] + public string PriceDesignation { get; set; } + } + + public class ProductCustomization + { + [JsonProperty("customizedUrl")] + public string CustomizedUrl { get; set; } + } + + public class OrderItemExpense + { + [JsonProperty("pointsCost")] + public PointsCost PointsCost { get; set; } + } + + public class PointsCost + { + [JsonProperty("pointsGranted")] + public PointsGranted PointsGranted { get; set; } + } + + public class PointsGranted + { + [JsonProperty("pointsNumber")] + public int? PointsNumber { get; set; } + + [JsonProperty("pointsMonetaryValue")] + public Money PointsMonetaryValue { get; set; } + } + + public class OrderItemPromotion + { + [JsonProperty("breakdowns")] + public IList Breakdowns { get; set; } + } + + public class PromotionBreakdown + { + [JsonProperty("promotionId")] + public string PromotionId { get; set; } + } + + public class OrderItemCancellation + { + [JsonProperty("requester")] + public string Requester { get; set; } + + [JsonProperty("cancelReason")] + public string CancelReason { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Package20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Package20260101.cs new file mode 100644 index 00000000..2803e914 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Package20260101.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json; +using System; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Shipping package information. New in v2026-01-01. + /// Requires includedData=PACKAGES. + /// + public class Package + { + [JsonProperty("packageReferenceId")] + public string PackageReferenceId { get; set; } + + [JsonProperty("carrier")] + public string Carrier { get; set; } + + [JsonProperty("trackingNumber")] + public string TrackingNumber { get; set; } + + [JsonProperty("shippingService")] + public string ShippingService { get; set; } + + [JsonProperty("packageStatus")] + public PackageStatus PackageStatus { get; set; } + + [JsonProperty("createdTime")] + public DateTime? CreatedTime { get; set; } + + [JsonProperty("shipTime")] + public DateTime? ShipTime { get; set; } + + [JsonProperty("shipFromAddress")] + public DeliveryAddress ShipFromAddress { get; set; } + } + + public class PackageStatus + { + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("detailedStatus")] + public string DetailedStatus { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Proceeds20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Proceeds20260101.cs new file mode 100644 index 00000000..6bbf8869 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Proceeds20260101.cs @@ -0,0 +1,59 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Order-level proceeds. Requires includedData=PROCEEDS. + /// + public class OrderProceeds + { + [JsonProperty("grandTotal")] + public Money GrandTotal { get; set; } + } + + /// + /// Order item-level proceeds with breakdown structure. + /// Requires includedData=PROCEEDS. + /// + public class OrderItemProceeds + { + [JsonProperty("proceedsTotal")] + public Money ProceedsTotal { get; set; } + + [JsonProperty("breakdowns")] + public IList Breakdowns { get; set; } + } + + /// + /// A financial breakdown entry. Type can be: ITEM, SHIPPING, DISCOUNT, TAX, COD_FEE, GIFT_WRAP. + /// + public class ProceedsBreakdown + { + [JsonProperty("type")] + public string Type { get; set; } + + [JsonProperty("subtotal")] + public Money Subtotal { get; set; } + + [JsonProperty("detailedBreakdowns")] + public IList DetailedBreakdowns { get; set; } + } + + /// + /// A detailed sub-breakdown. Subtype can be: ITEM, SHIPPING, DISCOUNT, COD_FEE, GIFT_WRAP. + /// + public class DetailedBreakdown + { + [JsonProperty("subtype")] + public string Subtype { get; set; } + + [JsonProperty("value")] + public Money Value { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Responses20260101.cs b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Responses20260101.cs new file mode 100644 index 00000000..c1a31112 --- /dev/null +++ b/Source/FikaAmazonAPI/AmazonSpApiSDK/Models/Orders20260101/Responses20260101.cs @@ -0,0 +1,58 @@ +using Newtonsoft.Json; +using System.Collections.Generic; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101 +{ + /// + /// Response wrapper for searchOrders. + /// + public class SearchOrdersResponse + { + [JsonProperty("orders")] + public IList Orders { get; set; } + + [JsonProperty("paginationToken")] + public string PaginationToken { get; set; } + + [JsonProperty("lastUpdatedBefore")] + public string LastUpdatedBefore { get; set; } + } + + /// + /// Response wrapper for getOrder. + /// + public class GetOrderResponse20260101 + { + [JsonProperty("order")] + public Order20260101 Order { get; set; } + } + + /// + /// Error response model. + /// + public class OrdersError20260101 + { + [JsonProperty("code")] + public string Code { get; set; } + + [JsonProperty("message")] + public string Message { get; set; } + + [JsonProperty("details")] + public string Details { get; set; } + } + + /// + /// Envelope for error responses from the Orders API v2026-01-01. + /// + public class ErrorList20260101 + { + [JsonProperty("errors")] + public IList Errors { get; set; } + } +} diff --git a/Source/FikaAmazonAPI/Parameter/Order/ParameterGetOrder.cs b/Source/FikaAmazonAPI/Parameter/Order/ParameterGetOrder.cs index 91859cda..9d43de87 100644 --- a/Source/FikaAmazonAPI/Parameter/Order/ParameterGetOrder.cs +++ b/Source/FikaAmazonAPI/Parameter/Order/ParameterGetOrder.cs @@ -1,12 +1,82 @@ -using FikaAmazonAPI.AmazonSpApiSDK.Models.Token; +using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101; +using FikaAmazonAPI.AmazonSpApiSDK.Models.Token; using FikaAmazonAPI.Search; +using FikaAmazonAPI.Utils; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Reflection; namespace FikaAmazonAPI.Parameter.Order { + [Obsolete("This class is deprecated. Please use ParameterGetOrder20260101 instead.")] public class ParameterGetOrder : ParameterBased, IParameterBasedPII { public string OrderId { get; set; } public bool IsNeedRestrictedDataToken { get; set; } public CreateRestrictedDataTokenRequest RestrictedDataTokenRequest { get; set; } } + + /// + /// Parameters for the getOrder endpoint (Orders API v2026-01-01). + /// Replaces ParameterGetOrder from v0. + /// + /// Key differences from v0: + /// - No RDT required: PII access is role-based. + /// - includedData parameter replaces separate GetOrderBuyerInfo/GetOrderAddress/GetOrderItems calls. + /// - Order items are always included in the response. + /// + /// + [CamelCase] + public class ParameterGetOrder20260101 : ParameterBased + { + /// + /// The Amazon order identifier (path parameter). + /// + [PathParameter] + public string OrderId { get; set; } + + /// + /// Specifies which additional data to include in the response. + /// Values: BUYER, RECIPIENT, FULFILLMENT, PROCEEDS, EXPENSE, PROMOTION, CANCELLATION, PACKAGES. + /// Order items are always included regardless of this parameter. + /// + [IgnoreToAddParameter] + public ICollection IncludedData { get; set; } + + + public List> getParameters() + { + var parameter = new List>(); + + if (string.IsNullOrEmpty(OrderId)) + throw new ArgumentException("OrderID needs to be set for a getOrder call to Work... i mean what Order do you try to get?"); + + parameter.Add(new KeyValuePair("orderID", OrderId)); + + if(IncludedData != null && IncludedData.Count > 0) + { + parameter.Add(new KeyValuePair("includedData",JoinEnums(IncludedData))); + } + + return parameter; + } + + + // Helpers + private static string JoinEnums(ICollection values) where T : Enum + { + return string.Join(",", values.Select(GetEnumMemberValue)); + } + + private static string GetEnumMemberValue(T enumValue) where T : Enum + { + var member = typeof(T).GetMember(enumValue.ToString()).FirstOrDefault(); + var attr = member?.GetCustomAttribute(); + return attr?.Value ?? enumValue.ToString(); + } + } } diff --git a/Source/FikaAmazonAPI/Parameter/Order/ParameterOrderList.cs b/Source/FikaAmazonAPI/Parameter/Order/ParameterOrderList.cs index 765b0884..ce76ccea 100644 --- a/Source/FikaAmazonAPI/Parameter/Order/ParameterOrderList.cs +++ b/Source/FikaAmazonAPI/Parameter/Order/ParameterOrderList.cs @@ -8,6 +8,7 @@ namespace FikaAmazonAPI.Parameter.Order { + [Obsolete("This class is deprecated. Please use ParameterSearchOrders instead.")] public class ParameterOrderList : ParameterBased, IParameterBasedPII { public ParameterOrderList() diff --git a/Source/FikaAmazonAPI/Parameter/Order/ParameterSearchOrders.cs b/Source/FikaAmazonAPI/Parameter/Order/ParameterSearchOrders.cs new file mode 100644 index 00000000..f5ae4f0c --- /dev/null +++ b/Source/FikaAmazonAPI/Parameter/Order/ParameterSearchOrders.cs @@ -0,0 +1,211 @@ +using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101; +using FikaAmazonAPI.RestSharp; +using FikaAmazonAPI.Search; +using FikaAmazonAPI.Utils; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +/// +/// Code Generated then Edited from: +/// https://github.com/amzn/selling-partner-api-models/blob/main/models/orders-api-model/orders_2026-01-01.json +/// + +namespace FikaAmazonAPI.Parameter.Order +{ + /// + /// Parameters for the searchOrders endpoint (Orders API v2026-01-01). + /// Replaces ParameterOrderList from v0. + /// + /// Key differences from v0 ParameterOrderList: + /// - NextToken -> paginationToken (expires 24 hours) + /// - OrderStatuses -> fulfillmentStatuses (upper snake case values) (Still SCREAMING_SNAKE_CASE for me) + /// - FulfillmentChannels -> fulfilledBy (MERCHANT/AMAZON instead of MFN/AFN) + /// - PaymentMethods, BuyerEmail, EasyShipShipmentStatuses removed + /// - includedData parameter for flexible data retrieval + /// - No RDT required for PII access (role-based instead) + /// + [CamelCase] + public class ParameterSearchOrders : ParameterBased + { + /// + /// A list of marketplace identifiers. Max count: 50. + /// + public ICollection MarketplaceIds { get; set; } + + /// + /// A date used for selecting orders that were last updated after (or at) a specified time. + /// The date must be in ISO 8601 format. + /// + public DateTime? LastUpdatedAfter { get; set; } + + /// + /// A date used for selecting orders that were last updated before (or at) a specified time. + /// The date must be in ISO 8601 format. + /// + public DateTime? LastUpdatedBefore { get; set; } + + /// + /// A date used for selecting orders created after (or at) a specified time. + /// The date must be in ISO 8601 format. + /// + public DateTime? CreatedAfter { get; set; } + + /// + /// A date used for selecting orders created before (or at) a specified time. + /// The date must be in ISO 8601 format. + /// + public DateTime? CreatedBefore { get; set; } + + /// + /// Maximum number of results per page. + /// + public int? MaxResultsPerPage { get; set; } = 100; + + /// + /// Pagination token from a previous response. Expires after 24 hours. + /// Replaces NextToken from v0. + /// + public string PaginationToken { get; set; } + + /// + /// A list of fulfillment status values used to filter the results. + /// Replaces OrderStatuses from v0. + /// Values: UNSHIPPED, PARTIALLY_SHIPPED, SHIPPED, CANCELLED, PENDING, + /// UNFULFILLABLE, PENDING_AVAILABILITY, INVOICE_UNCONFIRMED. + /// + [IgnoreToAddParameter] + public ICollection FulfillmentStatuses { get; set; } + + /// + /// A list that indicates how an order was fulfilled. + /// Replaces FulfillmentChannels from v0. + /// Values: MERCHANT (was MFN), AMAZON (was AFN). + /// + [IgnoreToAddParameter] + public ICollection FulfilledBy { get; set; } + + /// + /// A list of AmazonOrderId values. Max count: 50. + /// + public ICollection AmazonOrderIds { get; set; } + + /// + /// Specifies which data to include in the response. + /// Values: BUYER, RECIPIENT, FULFILLMENT, PROCEEDS, EXPENSE, PROMOTION, CANCELLATION, PACKAGES. + /// The less data requested, the better the performance. + /// + [IgnoreToAddParameter] + public ICollection IncludedData { get; set; } + + /// + /// Maximum number of pages to retrieve (client-side pagination control, not sent to API). + /// + [IgnoreToAddParameter] + public int? MaxNumberOfPages { get; set; } + + + //?createdAfter=2025-01-01T00%3A00%3A00Z& + //createdBefore=2025-01-01T00%3A00%3A00Z& + //lastUpdatedAfter=2025-01-01T00%3A00%3A00Z& + //lastUpdatedBefore=2025-01-01T00%3A00%3A00Z& + //fulfillmentStatuses=PENDING,UNSHIPPED& + //marketplaceIds=ATVPDKIKX0DER,ATV2222222222& + //fulfilledBy=MERCHANT,AMAZON& + //includedData=BUYER,RECIPIENT' \ + + //fulfillmentStatuses=PENDING,UNSHIPPED& + //marketplaceIds=ATVPDKIKX0DER,ATV2222222222& + //fulfilledBy=MERCHANT,AMAZON& + //includedData=BUYER,RECIPIENT' \ + + public List> getParameters() + { + List> parameters = new List>(); + + //DataTimes + if(LastUpdatedAfter.HasValue) + { + string timeURL = ParameterSearchOrders.FormatDate(LastUpdatedAfter.GetValueOrDefault()); + parameters.Add(new KeyValuePair("lastUpdatedAfter", timeURL)); + } + + if(LastUpdatedBefore.HasValue) + { + string timeURL = ParameterSearchOrders.FormatDate(LastUpdatedBefore.GetValueOrDefault()); + parameters.Add(new KeyValuePair("lastUpdatedBefore", timeURL)); + } + + if (CreatedAfter.HasValue) + { + string timeURL = ParameterSearchOrders.FormatDate(CreatedAfter.GetValueOrDefault()); + parameters.Add(new KeyValuePair("createdAfter", timeURL)); + } + + if (CreatedBefore.HasValue) + { + string timeURL = ParameterSearchOrders.FormatDate(CreatedBefore.GetValueOrDefault()); + parameters.Add(new KeyValuePair("createdBefore", timeURL)); + } + + // Basic Types + if(MaxResultsPerPage != null) + { + parameters.Add(new KeyValuePair("maxResultsPerPage", MaxResultsPerPage.Value.ToString())); + } + + if(! /* NOT */ string.IsNullOrEmpty(PaginationToken)) + { + parameters.Add(new KeyValuePair("paginationToken",PaginationToken)); + } + + // Enums + if (FulfillmentStatuses != null && FulfillmentStatuses.Count > 0) + { + parameters.Add(new KeyValuePair("fulfillmentStatuses", JoinEnums(FulfillmentStatuses))); + } + + if (IncludedData != null && IncludedData.Count > 0) + { + parameters.Add(new KeyValuePair("includedData", JoinEnums(IncludedData))); + } + + if (FulfilledBy != null && FulfilledBy.Count > 0) + { + parameters.Add(new KeyValuePair("fulfilledBy", JoinEnums(FulfilledBy))); + } + + // List/Collections + if (MarketplaceIds != null && MarketplaceIds.Count > 0) + { + parameters.Add(new KeyValuePair("marketplaceIds", string.Join(",", MarketplaceIds))); + } + + return parameters; + + } + + // Helpers + + private static string FormatDate(DateTime dt) + { + return dt.ToUniversalTime().ToString(Constants.DateISO8601Format); + } + + private static string JoinEnums(ICollection values) where T : Enum + { + return string.Join(",", values.Select(GetEnumMemberValue)); + } + + private static string GetEnumMemberValue(T enumValue) where T : Enum + { + var member = typeof(T).GetMember(enumValue.ToString()).FirstOrDefault(); + var attr = member?.GetCustomAttribute(); + return attr?.Value ?? enumValue.ToString(); + } + } +} \ No newline at end of file diff --git a/Source/FikaAmazonAPI/Services/ApiUrls.cs b/Source/FikaAmazonAPI/Services/ApiUrls.cs index 761f5370..41122073 100644 --- a/Source/FikaAmazonAPI/Services/ApiUrls.cs +++ b/Source/FikaAmazonAPI/Services/ApiUrls.cs @@ -628,15 +628,13 @@ public static string GetInventorySummaries public class OrdersApiUrls { private readonly static string _resourceBaseUrl = "/orders/v0"; - public static string Orders - { - get => $"{_resourceBaseUrl}/orders"; - } - public static string Order(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}"; - public static string OrderItems(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/orderItems"; - public static string OrderBuyerInfo(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/buyerInfo"; - public static string OrderItemsBuyerInfo(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/orderItems/buyerInfo"; - public static string OrderShipmentInfo(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/address"; + private static readonly string _resourceBaseUrl20260101 = "/orders/2026-01-01"; + + /*v2026-01-01*/ + public static string SearchOrders => $"{_resourceBaseUrl20260101}/orders"; + public static string GetOrder(string orderId) => $"{_resourceBaseUrl20260101}/orders/{orderId}"; + + /*v0*/ public static string UpdateShipmentStatus(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/shipment"; public static string GetOrderRegulatedInfo(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/regulatedInfo"; public static string UpdateVerificationStatus(string orderId) => $"{_resourceBaseUrl}/orders/{orderId}/regulatedInfo"; diff --git a/Source/FikaAmazonAPI/Services/OrderService.cs b/Source/FikaAmazonAPI/Services/OrderService.cs index 0d50f25f..eb083593 100644 --- a/Source/FikaAmazonAPI/Services/OrderService.cs +++ b/Source/FikaAmazonAPI/Services/OrderService.cs @@ -1,15 +1,46 @@ using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders; -using FikaAmazonAPI.AmazonSpApiSDK.Models.Token; +using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101; using FikaAmazonAPI.Parameter.Order; -using FikaAmazonAPI.Search; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Linq; +using System.Text; using System.Threading; using System.Threading.Tasks; namespace FikaAmazonAPI.Services { + /// + /// Order service for the Orders API v2026-01-01. + /// + /// Migration summary + /// ------------------------------------------------------------------------- + /// v0 Operation | v2026-01-01 Operation + /// ------------------------------------------------------------------------- + /// GetOrders -> SearchOrders + /// GetOrder -> GetOrder (with includedData) + /// GetOrderItems -> GetOrder (items always included) + /// GetOrderBuyerInfo -> GetOrder +includedData=BUYER + /// GetOrderAddress -> GetOrder + includedData= RECIPIENT + /// GetOrderItemsBuyerInfo -> GetOrder + includedData= BUYER + /// ------------------------------------------------------------------------- + /// + /// + /// Main-Changes: + /// - No Restricted Data Tokens (RDT) required for PII access. + /// - Use includedData parameter for flexible data retrieval. + /// - FulfillmentChannels MFN/AFN replaced with MERCHANT/AMAZON. + /// - OrderStatuses replaced with FulfillmentStatuses (upper snake case) (I personaly knows it as SCREAMING_SNAKE_CASE). + /// - New features: Package tracking, programs array, structured proceeds. + /// + /// Infos from: + /// https://developer-docs.amazon.com/sp-api/docs/orders-api-migration-guide + /// https://developer-docs.amazon.com/sp-api/reference/searchorders + /// https://developer-docs.amazon.com/sp-api/reference/getorder-3 + /// + Some inspiration from the code of the Python Respository: + /// https://github.com/saleweaver/python-amazon-sp-api/tree/master + /// public class OrderService : RequestService { public OrderService(AmazonCredential amazonCredential, ILoggerFactory? loggerFactory) : base(amazonCredential, loggerFactory) @@ -17,263 +48,206 @@ public OrderService(AmazonCredential amazonCredential, ILoggerFactory? loggerFac } - #region GetOrders - - public OrderList GetOrders(ParameterOrderList searchOrderList) => - Task.Run(() => GetOrdersAsync(searchOrderList)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrdersAsync(ParameterOrderList searchOrderList, CancellationToken cancellationToken = default) + /* v2026-01-01 API */ + + #region SearchOrders + + /// + /// Synchronous wrapper for SearchOrdersAsync. + /// Replaces GetOrders from v0. + /// + public IList SearchOrders(ParameterSearchOrders parameter) => + Task.Run(() => SearchOrdersAsync(parameter)).ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Returns orders that are created or updated during the specified time period. + /// Automatically handles pagination (respects MaxNumberOfPages if set). + /// + /// Replaces GetOrdersAsync from v0. + /// Also replaces the need for separate GetOrderBuyerInfo/GetOrderAddress calls + /// when includedData contains BUYER/RECIPIENT. + /// + public async Task> SearchOrdersAsync(ParameterSearchOrders parameter, CancellationToken cancellationToken = default) { + var allOrders = new List(); - var orderList = new OrderList(); - - if (searchOrderList.MarketplaceIds == null || searchOrderList.MarketplaceIds.Count == 0) + if (parameter.MarketplaceIds == null || parameter.MarketplaceIds.Count == 0) { - searchOrderList.MarketplaceIds = new List(); - searchOrderList.MarketplaceIds.Add(AmazonCredential.MarketPlace.ID); + parameter.MarketplaceIds = new List { AmazonCredential.MarketPlace.ID }; } - if (searchOrderList.IsNeedRestrictedDataToken && searchOrderList.RestrictedDataTokenRequest == null) - { - var restrictedResource = new RestrictedResource(); - restrictedResource.method = Method.GET.ToString(); - restrictedResource.path = OrdersApiUrls.Orders; - restrictedResource.dataElements = new List { "buyerInfo", "shippingAddress" }; + var queryParameters = parameter.getParameters(); + await CreateAuthorizedRequestAsync( + OrdersApiUrls.SearchOrders, + RestSharp.Method.Get, + queryParameters, + cancellationToken: cancellationToken); - var createRDT = new CreateRestrictedDataTokenRequest() - { - restrictedResources = new List { restrictedResource } - }; - searchOrderList.RestrictedDataTokenRequest = createRDT; - } - - var queryParameters = searchOrderList.getParameters(); - await CreateAuthorizedRequestAsync(OrdersApiUrls.Orders, RestSharp.Method.Get, queryParameters, parameter: searchOrderList, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrders, cancellationToken); - var nextToken = response.Payload.NextToken; - orderList = response.Payload.Orders; - if (!string.IsNullOrWhiteSpace(response.Payload.LastUpdatedBefore)) - orderList.LastUpdatedBefore = DateTime.Parse(response.Payload.LastUpdatedBefore); + var response = await ExecuteRequestAsync(Utils.RateLimitType.Order20260101_SearchOrders, cancellationToken); - int PageCount = 1; - if (searchOrderList.MaxNumberOfPages.HasValue && searchOrderList.MaxNumberOfPages.Value == 1) - { - orderList.NextToken = nextToken; - } - else + if (response?.Orders != null) { - while (!string.IsNullOrEmpty(nextToken)) - { - var orderPayload = await GetGetOrdersByNextTokenAsync(nextToken, searchOrderList, cancellationToken); - orderList.AddRange(orderPayload.Orders); - nextToken = orderPayload.NextToken; - - if (searchOrderList.MaxNumberOfPages.HasValue) - { - PageCount++; - if (PageCount >= searchOrderList.MaxNumberOfPages.Value) - break; - } - } + allOrders.AddRange(response.Orders); } - return orderList; - } + var paginationToken = response?.PaginationToken; + int pageCount = 1; - public OrdersList GetGetOrdersByNextToken(string nextToken, ParameterOrderList searchOrderList) => - Task.Run(() => GetGetOrdersByNextTokenAsync(nextToken, searchOrderList)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetGetOrdersByNextTokenAsync(string nextToken, ParameterOrderList searchOrderList, CancellationToken cancellationToken = default) - { - List> queryParameters = new List>(); - queryParameters.Add(new KeyValuePair("NextToken", nextToken)); - queryParameters.Add(new KeyValuePair("MarketplaceIds", string.Join(",", searchOrderList.MarketplaceIds))); + if (parameter.MaxNumberOfPages.HasValue && parameter.MaxNumberOfPages.Value == 1) + { + // Caller only wants one page; return results as-is + return allOrders; + } - await CreateAuthorizedRequestAsync(OrdersApiUrls.Orders, RestSharp.Method.Get, queryParameters, parameter: searchOrderList, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrders, cancellationToken); - return response.Payload; - } + while (!string.IsNullOrEmpty(paginationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); - #endregion - #region GetOrders + var nextPageResponse = await SearchOrdersByPaginationTokenAsync(paginationToken, parameter, cancellationToken); + if (nextPageResponse?.Orders != null) + { + allOrders.AddRange(nextPageResponse.Orders); + } - public async Task GetOrdersAsync(ParameterOrderList searchOrderList) - { - var orderList = new OrderList(); + paginationToken = nextPageResponse?.PaginationToken; - if (searchOrderList.MarketplaceIds == null || searchOrderList.MarketplaceIds.Count == 0) - { - searchOrderList.MarketplaceIds = new List(); - searchOrderList.MarketplaceIds.Add(AmazonCredential.MarketPlace.ID); - } - var queryParameters = searchOrderList.getParameters(); - - await CreateAuthorizedRequestAsync(OrdersApiUrls.Orders, RestSharp.Method.Get, queryParameters, parameter: searchOrderList); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrders); - var nextToken = response.Payload.NextToken; - orderList = response.Payload.Orders; - int PageCount = 1; - if (searchOrderList.MaxNumberOfPages.HasValue && searchOrderList.MaxNumberOfPages.Value == 1) - { - orderList.NextToken = nextToken; - } - else - { - while (!string.IsNullOrEmpty(nextToken)) + if (parameter.MaxNumberOfPages.HasValue) { - var orderPayload = GetGetOrdersByNextToken(nextToken, searchOrderList); - orderList.AddRange(orderPayload.Orders); - nextToken = orderPayload.NextToken; - - if (searchOrderList.MaxNumberOfPages.HasValue) - { - PageCount++; - if (PageCount >= searchOrderList.MaxNumberOfPages.Value) - break; - } + pageCount++; + if (pageCount >= parameter.MaxNumberOfPages.Value) + break; } } - return orderList; + return allOrders; } - public async Task GetGetOrdersByNextTokenAsync(string nextToken, ParameterOrderList searchOrderList) + /// + /// Synchronous wrapper for SearchOrdersPageAsync. + /// Returns a single page of results (no auto-pagination). + /// + public SearchOrdersResponse SearchOrdersPage(ParameterSearchOrders parameter) => + Task.Run(() => SearchOrdersPageAsync(parameter)).ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Returns a single page of searchOrders results without automatic pagination. + /// Replaces GetOrdersListAsync from v0. + /// + public async Task SearchOrdersPageAsync(ParameterSearchOrders parameter, CancellationToken cancellationToken = default) { - var parameterOrderList = new ParameterOrderList + if (parameter.MarketplaceIds == null || parameter.MarketplaceIds.Count == 0) { - MarketplaceIds = searchOrderList.MarketplaceIds, - NextToken = nextToken, - IsNeedRestrictedDataToken = searchOrderList.IsNeedRestrictedDataToken, - RestrictedDataTokenRequest = searchOrderList.RestrictedDataTokenRequest - }; - - List> queryParameters = parameterOrderList.getParameters(); + parameter.MarketplaceIds = new List { AmazonCredential.MarketPlace.ID }; + } - await CreateAuthorizedRequestAsync(OrdersApiUrls.Orders, RestSharp.Method.Get, queryParameters, parameter: parameterOrderList); + var queryParameters = parameter.getParameters(); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrders); + await CreateAuthorizedRequestAsync( + OrdersApiUrls.SearchOrders, + RestSharp.Method.Get, + queryParameters, + cancellationToken: cancellationToken); - return response.Payload; + return await ExecuteRequestAsync(Utils.RateLimitType.Order20260101_SearchOrders, cancellationToken); } - public OrdersList GetOrdersList(ParameterOrderList searchOrderList) => - Task.Run(() => GetOrdersListAsync(searchOrderList)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrdersListAsync(ParameterOrderList searchOrderList) + /// + /// Fetches the next page of results using a pagination token. + /// Note: Pagination tokens expire after 24 hours in v2026-01-01. + /// + private async Task SearchOrdersByPaginationTokenAsync(string paginationToken, ParameterSearchOrders originalParameter, CancellationToken cancellationToken = default) { - if (searchOrderList.MarketplaceIds == null || searchOrderList.MarketplaceIds.Count == 0) + var queryParameters = new List> { - searchOrderList.MarketplaceIds = new List(); - searchOrderList.MarketplaceIds.Add(AmazonCredential.MarketPlace.ID); - } - var queryParameters = searchOrderList.getParameters(); + new KeyValuePair("paginationToken", paginationToken), + new KeyValuePair("marketplaceIds", string.Join(",", originalParameter.MarketplaceIds)) + }; - await CreateAuthorizedRequestAsync(OrdersApiUrls.Orders, RestSharp.Method.Get, queryParameters, parameter: searchOrderList); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrders); - return response.Payload; + await CreateAuthorizedRequestAsync( + OrdersApiUrls.SearchOrders, + RestSharp.Method.Get, + queryParameters, + cancellationToken: cancellationToken); + + return await ExecuteRequestAsync(Utils.RateLimitType.Order20260101_SearchOrders, cancellationToken); } #endregion - public Order GetOrder(ParameterGetOrder parameter) => - Task.Run(() => GetOrderAsync(parameter)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderAsync(ParameterGetOrder parameter, CancellationToken cancellationToken = default) - { - if (parameter.IsNeedRestrictedDataToken && parameter.RestrictedDataTokenRequest == null) - { - var restrictedResource = new RestrictedResource(); - restrictedResource.method = Method.GET.ToString(); - restrictedResource.path = OrdersApiUrls.Order(parameter.OrderId); - restrictedResource.dataElements = new List { "buyerInfo", "shippingAddress" }; + #region GetOrder - var createRDT = new CreateRestrictedDataTokenRequest() - { - restrictedResources = new List { restrictedResource } - }; - parameter.RestrictedDataTokenRequest = createRDT; - } + /// + /// Synchronous wrapper for GetOrderAsync. + /// + public Order20260101 GetOrder(ParameterGetOrder20260101 parameter) => + Task.Run(() => GetOrderAsync(parameter)).ConfigureAwait(false).GetAwaiter().GetResult(); - await CreateAuthorizedRequestAsync(OrdersApiUrls.Order(parameter.OrderId), RestSharp.Method.Get, parameter: parameter, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrder, cancellationToken); - if (response != null && response.Payload != null) - return response.Payload; - else return null; - } - public OrderItemList GetOrderItems(string orderId, IParameterBasedPII parameterBasedPII = null) => - Task.Run(() => GetOrderItemsAsync(orderId, parameterBasedPII)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderItemsAsync(string orderId, IParameterBasedPII ParameterBasedPII = null, CancellationToken cancellationToken = default) + /// + /// Returns detailed order information for the specified order ID. + /// + /// Replaces the following v0 operations (consolidated into one call): + /// - GetOrder + /// - GetOrderItems (items are always included) + /// - GetOrderBuyerInfo (use includedData=BUYER) + /// - GetOrderAddress (use includedData=RECIPIENT) + /// - GetOrderItemsBuyerInfo (use includedData=BUYER) + /// + /// No RDT required for PII access. Use appropriate application roles instead. + /// + public async Task GetOrderAsync(ParameterGetOrder20260101 parameter, CancellationToken cancellationToken = default) { - var orderItemList = new OrderItemList(); + var queryParameters = parameter.getParameters(); - if (ParameterBasedPII != null && ParameterBasedPII.IsNeedRestrictedDataToken && ParameterBasedPII.RestrictedDataTokenRequest == null) - { - var restrictedResource = new RestrictedResource(); - restrictedResource.method = Method.GET.ToString(); - restrictedResource.path = OrdersApiUrls.OrderItems(orderId); - restrictedResource.dataElements = new List { "buyerInfo", "shippingAddress" }; + await CreateAuthorizedRequestAsync( + OrdersApiUrls.GetOrder(parameter.OrderId), + RestSharp.Method.Get, + queryParameters, + cancellationToken: cancellationToken); - var createRDT = new CreateRestrictedDataTokenRequest() - { - restrictedResources = new List { restrictedResource } - }; - ParameterBasedPII.RestrictedDataTokenRequest = createRDT; - } - - await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderItems(orderId), RestSharp.Method.Get, parameter: ParameterBasedPII, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderItems, cancellationToken); - var nextToken = response.Payload.NextToken; - orderItemList.AddRange(response.Payload.OrderItems); - while (!string.IsNullOrEmpty(nextToken)) - { - var orderItemPayload = await GetOrderItemsNextTokenAsync(orderId, nextToken, cancellationToken); - orderItemList.AddRange(orderItemPayload.OrderItems); - nextToken = orderItemPayload.NextToken; + var response = await ExecuteRequestAsync(Utils.RateLimitType.Order20260101_GetOrder, cancellationToken); - cancellationToken.ThrowIfCancellationRequested(); - } - return orderItemList; + return response?.Order; } - public OrderItemsList GetOrderItemsNextToken(string orderId, string nextToken) => - Task.Run(() => GetOrderItemsNextTokenAsync(orderId, nextToken)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderItemsNextTokenAsync(string orderId, string nextToken, CancellationToken cancellationToken = default) + /// + /// Synchronous wrapper for GetOrderFullAsync. + /// + public Order20260101 GetOrderFull(string orderId) => + Task.Run(() => GetOrderFullAsync(orderId)).ConfigureAwait(false).GetAwaiter().GetResult(); + + /// + /// Convenience method: GetOrder with all available data included. + /// Equivalent to calling getOrder with includedData=BUYER,RECIPIENT,FULFILLMENT,PROCEEDS,EXPENSE,PROMOTION,CANCELLATION,PACKAGES + /// + public async Task GetOrderFullAsync(string orderId, CancellationToken cancellationToken = default) { - List> queryParameters = new List>(); - queryParameters.Add(new KeyValuePair("NextToken", nextToken)); - - - await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderItems(orderId), RestSharp.Method.Get, queryParameters, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderItems, cancellationToken); - return response.Payload; - } + var parameter = new ParameterGetOrder20260101 + { + OrderId = orderId, + IncludedData = new List + { + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.BUYER, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.RECIPIENT, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.FULFILLMENT, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.PROCEEDS, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.EXPENSE, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.PROMOTION, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.CANCELLATION, + AmazonSpApiSDK.Models.Orders20260101.IncludedData20260101.PACKAGES + } + }; - public OrderBuyerInfo GetOrderBuyerInfo(string orderId, List> queryParameters = null) => - Task.Run(() => GetOrderBuyerInfoAsync(orderId, queryParameters)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderBuyerInfoAsync(string orderId, List> queryParameters = null, CancellationToken cancellationToken = default) - { - await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderBuyerInfo(orderId), RestSharp.Method.Get, queryParameters, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderBuyerInfo, cancellationToken); - return response.Payload; + return await GetOrderAsync(parameter, cancellationToken); } - public OrderItemsBuyerInfoList GetOrderItemsBuyerInfo(string orderId) => - Task.Run(() => GetOrderItemsBuyerInfoAsync(orderId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderItemsBuyerInfoAsync(string orderId, CancellationToken cancellationToken = default) - { - await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderItemsBuyerInfo(orderId), RestSharp.Method.Get, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderItemsBuyerInfo, cancellationToken); - return response.Payload; - } + #endregion - public OrderAddress GetOrderAddress(string orderId) => - Task.Run(() => GetOrderAddressAsync(orderId)).ConfigureAwait(false).GetAwaiter().GetResult(); - public async Task GetOrderAddressAsync(string orderId, CancellationToken cancellationToken = default) - { - await CreateAuthorizedRequestAsync(OrdersApiUrls.OrderShipmentInfo(orderId), RestSharp.Method.Get, cancellationToken: cancellationToken); - var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderAddress, cancellationToken); - return response.Payload; - } + /* v0 API*/ + #region UpdateShipmentStatus public bool UpdateShipmentStatus(string orderId, UpdateShipmentStatusRequest updateShipmentStatusRequest) => Task.Run(() => UpdateShipmentStatusAsync(orderId, updateShipmentStatusRequest)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task UpdateShipmentStatusAsync(string orderId, UpdateShipmentStatusRequest updateShipmentStatusRequest, CancellationToken cancellationToken = default) @@ -283,8 +257,9 @@ public async Task UpdateShipmentStatusAsync(string orderId, UpdateShipment var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_UpdateShipmentStatus, cancellationToken); return true; } + #endregion - + #region GetOrderRegulatedInfo public OrderRegulatedInfo GetOrderRegulatedInfo(string orderId) => Task.Run(() => GetOrderRegulatedInfoAsync(orderId)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task GetOrderRegulatedInfoAsync(string orderId, CancellationToken cancellationToken = default) @@ -293,7 +268,9 @@ public async Task GetOrderRegulatedInfoAsync(string orderId, var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderRegulatedInfo, cancellationToken); return response.Payload; } + #endregion + #region UpdateVerificationStatus public bool UpdateVerificationStatus(string orderId, UpdateVerificationStatusRequest updateVerificationStatusRequest) => Task.Run(() => UpdateVerificationStatusAsync(orderId, updateVerificationStatusRequest)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task UpdateVerificationStatusAsync(string orderId, UpdateVerificationStatusRequest updateVerificationStatusRequest, CancellationToken cancellationToken = default) @@ -303,8 +280,9 @@ public async Task UpdateVerificationStatusAsync(string orderId, UpdateVeri var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_UpdateShipmentStatus, cancellationToken); return true; } + #endregion - + #region GetOrderItemsApprovals public OrderApprovalsResponse GetOrderItemsApprovals(ParameterGetOrderItemsApprovals parameterGetOrderItemsApprovals) => Task.Run(() => GetOrderItemsApprovalsAsync(parameterGetOrderItemsApprovals)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task GetOrderItemsApprovalsAsync(ParameterGetOrderItemsApprovals parameterGetOrderItemsApprovals, CancellationToken cancellationToken = default) @@ -315,8 +293,9 @@ public async Task GetOrderItemsApprovalsAsync(ParameterG var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_GetOrderRegulatedInfo, cancellationToken); return response.Payload; } + #endregion - + #region ConfirmShipment public bool ConfirmShipment(string orderId, ConfirmShipmentRequest confirmShipmentRequest) => Task.Run(() => ConfirmShipmentAsync(orderId, confirmShipmentRequest)).ConfigureAwait(false).GetAwaiter().GetResult(); public async Task ConfirmShipmentAsync(string orderId, ConfirmShipmentRequest confirmShipmentRequest, CancellationToken cancellationToken = default) @@ -326,5 +305,6 @@ public async Task ConfirmShipmentAsync(string orderId, ConfirmShipmentRequ var response = await ExecuteRequestAsync(Utils.RateLimitType.Order_UpdateShipmentStatus, cancellationToken); return true; } + #endregion } } diff --git a/Source/FikaAmazonAPI/Services/RequestService.cs b/Source/FikaAmazonAPI/Services/RequestService.cs index f486c00d..1d5a0a7a 100644 --- a/Source/FikaAmazonAPI/Services/RequestService.cs +++ b/Source/FikaAmazonAPI/Services/RequestService.cs @@ -96,6 +96,7 @@ protected async Task CreateAuthorizedRequestAsync(string url, RestSharp.Method m if (postJsonObj != null) AddJsonBody(postJsonObj); if (queryParameters != null) + AddQueryParameters(queryParameters); } @@ -133,6 +134,7 @@ protected async Task ExecuteRequestTry(RateLimitType rateLimitType = RateL LogRequest(currentRequest, response); SaveLastRequestHeader(response.Headers); await SleepForRateLimit(response.Headers, rateLimitType, cancellationToken); + ParseResponse(response); if (response.StatusCode == HttpStatusCode.OK && !string.IsNullOrEmpty(response.Content) && diff --git a/Source/FikaAmazonAPI/Utils/OrderConverter.cs b/Source/FikaAmazonAPI/Utils/OrderConverter.cs new file mode 100644 index 00000000..7a29987c --- /dev/null +++ b/Source/FikaAmazonAPI/Utils/OrderConverter.cs @@ -0,0 +1,91 @@ +using FikaAmazonAPI.AmazonSpApiSDK.Models.Finances; +using FikaAmazonAPI.AmazonSpApiSDK.Models.Orders20260101; +using System; +using System.Collections.Generic; +using System.Text; + + +namespace FikaAmazonAPI.Utils +{ + public class OrderConverter + { + public class OrderProgramInfo + { + public OrderProgramInfo(Order20260101 order) + { + if (order?.Programs == null) + { + throw new ArgumentNullException(nameof(order.Programs), "Order programs list cannot be null."); + } + this.isPrime = order?.Programs.Contains("PRIME") == true; + this.isPreorder = order?.Programs.Contains("PREORDER") == true; + this.isPremium = order?.Programs.Contains("PREMIUM") == true; + this.isInStorePickUp = order?.Programs.Contains("IN_STORE_PICK_UP") == true; + this.isFBMShipPlus = order?.Programs.Contains("FBM_SHIP_PLUS") == true; + this.isDeliveryByAmazon = order?.Programs.Contains("DELIVERY_BY_AMAZON") == true; + this.isAmazonHaul = order?.Programs.Contains("AMAZON_HAUL") == true; + this.isAmazonEasyShip = order?.Programs.Contains("AMAZON_EASY_SHIP") == true; + this.isAmazonBusiness = order?.Programs.Contains("AMAZON_BUSINESS") == true; + this.isAmazonBazaar = order?.Programs.Contains("AMAZON_BAZAAR") == true; + } + + public bool isPrime { get; set; } = false; + public bool isPreorder { get; set; } = false; + public bool isPremium { get; set; } = false; + public bool isInStorePickUp { get; set; } = false; + public bool isFBMShipPlus { get; set; } = false; + public bool isDeliveryByAmazon { get; set; } = false; + public bool isAmazonHaul { get; set; } = false; + public bool isAmazonEasyShip { get; set; } = false; + public bool isAmazonBusiness { get; set; } = false; + public bool isAmazonBazaar { get; set; } = false; + + + public List orderItems { get; set; } = new List(); + } + public class OrderItemProgramInfo + { + public OrderItemProgramInfo() { } + public string OrderItemId { get; set; } = string.Empty; + public bool isTransparency { get; set; } = false; + public bool isSubscribe_And_Save { get; set; } = false; + } + + public static OrderProgramInfo OrderProgramInfoEx(Order20260101 order) + { + OrderProgramInfo info = new OrderProgramInfo(order); + + if (order?.OrderItems == null) + { + throw new ArgumentNullException(nameof(order.Programs), "Order Item list cannot be null."); + } + if (order?.OrderItems.Count == 0) + { + throw new ArgumentException("Order must contain at least one Order Item.", nameof(order.OrderItems)); + } + info.orderItems = new List(); + foreach (OrderItem20260101 item in order.OrderItems) + { + if (item?.Programs == null) + { + continue; // Skip items with null Programs list + } + if (item?.Programs.Count == 0) + { + continue; // Skip items with empty Programs list + } + if (item?.OrderItemId == null) + { + continue; // Skip items with null OrderItemId + } + info.orderItems.Add(new OrderItemProgramInfo() + { + OrderItemId = item.OrderItemId, + isTransparency = item.Programs.Contains("PRIME") == true, + isSubscribe_And_Save = item.Programs.Contains("PREORDER") == true + }); + } + return info; + } + } +} \ No newline at end of file diff --git a/Source/FikaAmazonAPI/Utils/RateLimitType.cs b/Source/FikaAmazonAPI/Utils/RateLimitType.cs index b44fafde..383d4b25 100644 --- a/Source/FikaAmazonAPI/Utils/RateLimitType.cs +++ b/Source/FikaAmazonAPI/Utils/RateLimitType.cs @@ -20,6 +20,10 @@ public enum RateLimitType Order_UpdateOrderItemsApprovals, Order_ShipmentConfirmation, + /*Order V2026-01-01*/ + Order20260101_GetOrder, + Order20260101_SearchOrders, + Report_GetReports, Report_GetReport, Report_CreateReport, diff --git a/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs b/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs index 5b5a79b3..ce8531fb 100644 --- a/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs +++ b/Source/FikaAmazonAPI/Utils/RateLimitsDefinitions.cs @@ -25,6 +25,10 @@ internal static Dictionary RateLimitsTime() { RateLimitType.Order_UpdateOrderItemsApprovals, new RateLimits(5M, 15) }, { RateLimitType.Order_ShipmentConfirmation, new RateLimits(2M, 10) }, + /*Order V2026-01-01*/ + { RateLimitType.Order20260101_GetOrder, new RateLimits(0.0056M, 20) }, + { RateLimitType.Order20260101_SearchOrders, new RateLimits(0.5M, 30) }, + { RateLimitType.Report_GetReports, new RateLimits(0.0222M, 10) }, { RateLimitType.Report_GetReport, new RateLimits(2.0M, 15) }, { RateLimitType.Report_CreateReport, new RateLimits(0.0167M, 15) },