From c35a4a4e76b27359b19974033258f2969a10a19a Mon Sep 17 00:00:00 2001 From: maxim-saltanov-skuvault <80940351+maxim-saltanov-skuvault@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:45:52 +0400 Subject: [PATCH] PBL-9157 Shopify Orders Partial Refund (#45) PBL-9157 shopify orders partial refund on orders sync implemented, unit tests added --- .build.ps1 | 2 +- src/Global/GlobalAssemblyInfo.cs | 2 +- src/ShopifyAccess/ShopifyService.cs | 70 +++++-------------- .../ShopifyAccessTests/Orders/OrdersTests.cs | 70 +++++++++++++++++++ .../ShopifyAccessTests.csproj | 1 + 5 files changed, 92 insertions(+), 53 deletions(-) create mode 100644 src/ShopifyAccessTests/ShopifyAccessTests/Orders/OrdersTests.cs diff --git a/.build.ps1 b/.build.ps1 index 00ff33a..84de51e 100644 --- a/.build.ps1 +++ b/.build.ps1 @@ -76,7 +76,7 @@ task NuGet Package, Version, { $project_name - $Version + $Version-alpha SkuVault SkuVault https://github.com/agileharbor/$project_name diff --git a/src/Global/GlobalAssemblyInfo.cs b/src/Global/GlobalAssemblyInfo.cs index d92475d..043b96f 100644 --- a/src/Global/GlobalAssemblyInfo.cs +++ b/src/Global/GlobalAssemblyInfo.cs @@ -22,4 +22,4 @@ // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[ assembly : AssemblyVersion( "1.12.0.0" ) ] \ No newline at end of file +[ assembly : AssemblyVersion( "1.13.0.0" ) ] \ No newline at end of file diff --git a/src/ShopifyAccess/ShopifyService.cs b/src/ShopifyAccess/ShopifyService.cs index 83101c6..e88513e 100644 --- a/src/ShopifyAccess/ShopifyService.cs +++ b/src/ShopifyAccess/ShopifyService.cs @@ -152,7 +152,7 @@ private async Task< ShopifyOrders > CollectOrdersFromAllPagesAsync( string mainU break; foreach( var order in updatedOrdersWithinPage.Response.Orders ) - this.RemoveCancelledOrderItems( order ); + ProcessRefundOrderLineItems( order ); orders.Orders.AddRange( updatedOrdersWithinPage.Response.Orders ); @@ -162,7 +162,7 @@ private async Task< ShopifyOrders > CollectOrdersFromAllPagesAsync( string mainU return orders; } - private void RemoveCancelledOrderItems( ShopifyOrder order ) + internal static void ProcessRefundOrderLineItems( ShopifyOrder order ) { if ( order.Refunds == null || !order.Refunds.Any() ) return; @@ -170,52 +170,36 @@ private void RemoveCancelledOrderItems( ShopifyOrder order ) var actualOrderItems = new List< ShopifyOrderItem >(); foreach( var orderItem in order.OrderItems ) { - bool isCancelled = false; - int cancelledQuantity = 0; + var isCancelled = false; + var cancelledQuantity = 0; foreach( var refund in order.Refunds ) { var refundLineItem = refund.RefundLineItems.FirstOrDefault( rl => rl.LineItemId.ToString().Equals( orderItem.Id ) ); + if( refundLineItem == null ) + continue; - if ( refundLineItem != null && refundLineItem.RestockType.Equals( "cancel" ) ) + // remove order item + if ( orderItem.Quantity == refundLineItem.Quantity && refundLineItem.RestockType.Equals( "cancel" ) ) { - // remove order item - if ( orderItem.Quantity == refundLineItem.Quantity ) - { - isCancelled = true; - break; - } - - // adjust quantity - cancelledQuantity += refundLineItem.Quantity; + isCancelled = true; + break; } + + // adjust quantity + cancelledQuantity += refundLineItem.Quantity; } - if ( !isCancelled ) - { - orderItem.Quantity -= cancelledQuantity; - actualOrderItems.Add( orderItem ); - } + if( isCancelled ) + continue; + + orderItem.Quantity -= cancelledQuantity; + actualOrderItems.Add( orderItem ); } order.OrderItems = actualOrderItems; } - private int GetOrdersCount( string updatedOrdersEndpoint, Mark mark, CancellationToken token ) - { - var count = ActionPolicies.GetPolicy( mark, this._shopName, token ).Get( - () => this._throttler.Execute( - () => this._webRequestServices.GetResponse< OrdersCount >( _shopifyCommandFactory.CreateGetOrdersCountCommand(), updatedOrdersEndpoint, token, mark, this._timeouts[ ShopifyOperationEnum.GetOrdersCount ] ).Count ) ); - return count; - } - - private Task< int > GetOrdersCountAsync( string updatedOrdersEndpoint, Mark mark, CancellationToken token ) - { - var count = ActionPolicies.GetPolicyAsync( mark, this._shopName, token ).Get( - () => this._throttlerAsync.ExecuteAsync( - async () => ( await this._webRequestServices.GetResponseAsync< OrdersCount >( _shopifyCommandFactory.CreateGetOrdersCountCommand(), updatedOrdersEndpoint, token, mark, this._timeouts[ ShopifyOperationEnum.GetOrdersCount ] ) ).Count ) ); - return count; - } #endregion #region Products @@ -463,23 +447,7 @@ private static bool FilterProductVariants( ProductVariant variant ) { return variant.InventoryItem.Tracked && !string.IsNullOrEmpty( variant.Sku ); } - - private int GetProductsCount( Mark mark, CancellationToken token ) - { - var count = ActionPolicies.GetPolicy( mark, this._shopName, token ).Get( - () => this._throttler.Execute( - () => this._webRequestServices.GetResponse< ProductsCount >( _shopifyCommandFactory.CreateGetProductsCountCommand(), EndpointsBuilder.EmptyEndpoint, token, mark, this._timeouts[ ShopifyOperationEnum.GetProductsCount ] ).Count ) ); - return count; - } - - private Task< int > GetProductsCountAsync( Mark mark, CancellationToken token ) - { - var count = ActionPolicies.GetPolicyAsync( mark, this._shopName, token ).Get( - () => this._throttlerAsync.ExecuteAsync( - async () => ( await this._webRequestServices.GetResponseAsync< ProductsCount >( _shopifyCommandFactory.CreateGetProductsCountCommand(), EndpointsBuilder.EmptyEndpoint, token, mark, this._timeouts[ ShopifyOperationEnum.GetProductsCount ] ) ).Count ) ); - return count; - } - + private ShopifyProducts CollectProductsFromAllPages( CancellationToken token, Mark mark, int timeout ) { var products = new ShopifyProducts(); diff --git a/src/ShopifyAccessTests/ShopifyAccessTests/Orders/OrdersTests.cs b/src/ShopifyAccessTests/ShopifyAccessTests/Orders/OrdersTests.cs new file mode 100644 index 0000000..a6408cb --- /dev/null +++ b/src/ShopifyAccessTests/ShopifyAccessTests/Orders/OrdersTests.cs @@ -0,0 +1,70 @@ +using NUnit.Framework; +using NUnit.Framework.Internal; +using ServiceStack.Text; +using ShopifyAccess; +using ShopifyAccess.Models.Order; + +namespace ShopifyAccessTests.Orders +{ + [ TestFixture ] + public class OrderTests + { + private static readonly Randomizer _randomizer = new Randomizer(); + + [ Test ] + public void ProcessRefundOrderLineItems_ReturnLineItemQuantityRefundDeducted_WhenIsRefundQuantityLessThanLineItemQuantity() + { + // Arrange + var quantity = _randomizer.Next( 2, int.MaxValue ); + var refundQuantity = _randomizer.Next( 1, quantity - 1 ); + var shopifyOrderJson = GenerateShopifyOrderJsonWithRefund( quantity, refundQuantity ); + var shopifyOrder = JsonSerializer.DeserializeFromString< ShopifyOrder >( shopifyOrderJson ); + + // Act + ShopifyService.ProcessRefundOrderLineItems( shopifyOrder ); + + // Assert + Assert.That( shopifyOrder.OrderItems[ 0 ].Quantity, Is.EqualTo( quantity - refundQuantity ) ); + } + + [ Test ] + public void ProcessRefundOrderLineItems_LineItemRemovedFromOrder_WhenIsRefundQuantityEqualsToLineItemQuantity_andRestockTypeIsCancel() + { + // Arrange + var quantity = _randomizer.Next( 2, int.MaxValue ); + var shopifyOrderJson = GenerateShopifyOrderJsonWithRefund( quantity, quantity, restockType: "cancel" ); + var shopifyOrder = JsonSerializer.DeserializeFromString< ShopifyOrder >( shopifyOrderJson ); + + // Act + ShopifyService.ProcessRefundOrderLineItems( shopifyOrder ); + + // Assert + Assert.That( shopifyOrder.OrderItems.Count, Is.EqualTo( 0 ) ); + } + + private static string GenerateShopifyOrderJsonWithRefund( int orderQuantity, int refundQuantity, string restockType = "" ) + { + var lineItemId = _randomizer.Next(); + return @" + { + ""line_items"": [ + { + ""id"": " + lineItemId + @", + ""quantity"": " + orderQuantity + @" + } + ], + ""refunds"": [ + { + ""refund_line_items"": [ + { + ""line_item_id"": " + lineItemId + @", + ""quantity"": " + refundQuantity + @", + ""restock_type"": " + restockType + @" + } + ] + } + ] + }"; + } + } +} \ No newline at end of file diff --git a/src/ShopifyAccessTests/ShopifyAccessTests/ShopifyAccessTests.csproj b/src/ShopifyAccessTests/ShopifyAccessTests/ShopifyAccessTests.csproj index 832dd5d..44a8cd0 100644 --- a/src/ShopifyAccessTests/ShopifyAccessTests/ShopifyAccessTests.csproj +++ b/src/ShopifyAccessTests/ShopifyAccessTests/ShopifyAccessTests.csproj @@ -110,6 +110,7 @@ +