Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shopify return location on refunds #6

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Microsoft.Integration.Shopify;

enum 30156 "Shpfy Return Location Priority"
{
Extensible = true;

value(0; "Default Return Location")
{
Caption = 'Default Return Location';
}
value(1; "Original -> Default Location")
{
Caption = 'Original -> Default Location';
}
}
6 changes: 6 additions & 0 deletions Apps/W1/Shopify/app/src/Base/Pages/ShpfyShopCard.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -540,6 +540,12 @@ page 30101 "Shpfy Shop Card"
ShowCaption = false;
Visible = IsReturnRefundsVisible;

field("Return Location Priority"; Rec."Return Location Priority")
{
ApplicationArea = All;
Caption = 'Return Location Priority';
ToolTip = 'Specifies the priority of the return location.';
}
field("Location Code of Returns"; Rec."Return Location")
{
ApplicationArea = All;
Expand Down
11 changes: 8 additions & 3 deletions Apps/W1/Shopify/app/src/Base/Tables/ShpfyShop.Table.al
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@ table 30102 "Shpfy Shop"
ObsoleteState = Pending;
ObsoleteTag = '24.0';
#else
ObsoleteState = Removed;
ObsoleteTag = '27.0';
ObsoleteState = Removed;
ObsoleteTag = '27.0';
#endif
}
field(30; "Shopify Can Update Customer"; Boolean)
Expand Down Expand Up @@ -511,7 +511,7 @@ table 30102 "Shpfy Shop"
}
field(73; "Return Location"; Code[10])
{
Caption = 'Return Location';
Caption = 'Default Return Location';
DataClassification = CustomerContent;
TableRelation = Location where("Use As In-Transit" = const(false));
}
Expand Down Expand Up @@ -778,6 +778,11 @@ table 30102 "Shpfy Shop"
end;
#endif
}
field(128; "Return Location Priority"; Enum "Shpfy Return Location Priority")
{
Caption = 'Return Location Priority';
DataClassification = CustomerContent;
}
field(200; "Shop Id"; Integer)
{
DataClassification = SystemMetadata;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ codeunit 30232 "Shpfy GQL NextRefundLines" implements "Shpfy IGraphQL"

internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ refund(id: \"gid://shopify/Refund/{{RefundId}}\") { refundLineItems(first: 10, after:\"{{After}}\") { pageInfo { endCursor hasNextPage } nodes { lineItem { id } quantity restockType restocked priceSet { presentmentMoney { amount } shopMoney { amount }} subtotalSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }}}}}}"}');
exit('{"query":"{ refund(id: \"gid://shopify/Refund/{{RefundId}}\") { refundLineItems(first: 10, after:\"{{After}}\") { pageInfo { endCursor hasNextPage } nodes { lineItem { id } quantity restockType location { legacyResourceId } restocked priceSet { presentmentMoney { amount } shopMoney { amount }} subtotalSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }}}}}}"}');
end;

internal procedure GetExpectedCost(): Integer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Microsoft.Integration.Shopify;

/// <summary>
/// Codeunit Shpfy GQL NextRevFulfillOrdLns (ID 30213) implements Interface Shpfy IGraphQL.
/// </summary>
codeunit 30213 "Shpfy GQL NextRevFulfillOrdLns" implements "Shpfy IGraphQL"
{
Access = Internal;

/// <summary>
/// GetGraphQL.
/// </summary>
/// <returns>Return value of type Text.</returns>
internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ reverseFulfillmentOrder(id: \"{{FulfillOrderId}}\") { lineItems(first: 10, after:\"{{After}}\") { pageInfo { endCursor hasNextPage } nodes { id fulfillmentLineItem { id lineItem { id name } } dispositions { id quantity type location { id legacyResourceId } } } } } }"}');
end;

/// <summary>
/// GetExpectedCost.
/// </summary>
/// <returns>Return value of type Integer.</returns>
internal procedure GetExpectedCost(): Integer
begin
exit(15);
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Microsoft.Integration.Shopify;

/// <summary>
/// Codeunit Shpfy GQL NextRevFulfillOrders (ID 30159) implements Interface Shpfy IGraphQL.
/// </summary>
codeunit 30159 "Shpfy GQL NextRevFulfillOrders" implements "Shpfy IGraphQL"
{
Access = Internal;

/// <summary>
/// GetGraphQL.
/// </summary>
/// <returns>Return value of type Text.</returns>
internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ return(id: \"gid://shopify/Return/{{ReturnId}}\") { reverseFulfillmentOrders(first: 10, after:\"{{After}}\") { pageInfo { endCursor hasNextPage } nodes { id } } } }"}');

end;

/// <summary>
/// GetExpectedCost.
/// </summary>
/// <returns>Return value of type Integer.</returns>
internal procedure GetExpectedCost(): Integer
begin
exit(7);
end;
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ codeunit 30230 "Shpfy GQL RefundLines" implements "Shpfy IGraphQL"

internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ refund(id: \"gid://shopify/Refund/{{RefundId}}\") { refundLineItems(first: 10) { pageInfo { endCursor hasNextPage } nodes { lineItem { id } quantity restockType restocked priceSet { presentmentMoney { amount } shopMoney { amount }} subtotalSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }}}}}}"}');
exit('{"query":"{ refund(id: \"gid://shopify/Refund/{{RefundId}}\") { refundLineItems(first: 10) { pageInfo { endCursor hasNextPage } nodes { lineItem { id } quantity restockType location { legacyResourceId } restocked priceSet { presentmentMoney { amount } shopMoney { amount }} subtotalSet { presentmentMoney { amount } shopMoney { amount }} totalTaxSet { presentmentMoney { amount } shopMoney { amount }}}}}}"}');
end;

internal procedure GetExpectedCost(): Integer
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
namespace Microsoft.Integration.Shopify;

/// <summary>
/// Codeunit Shpfy GQL RevFulfillOrders (ID 30105) implements Interface Shpfy IGraphQL.
/// </summary>
codeunit 30168 "Shpfy GQL RevFulfillOrderLines" implements "Shpfy IGraphQL"
{
Access = Internal;

/// <summary>
/// GetGraphQL.
/// </summary>
/// <returns>Return value of type Text.</returns>
internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ reverseFulfillmentOrder(id: \"{{FulfillOrderId}}\") { id lineItems(first: 10) { nodes { id fulfillmentLineItem { id lineItem { id name } } dispositions { id quantity type location { id legacyResourceId } } } } } }"}');
end;

/// <summary>
/// GetExpectedCost.
/// </summary>
/// <returns>Return value of type Integer.</returns>
internal procedure GetExpectedCost(): Integer
begin
exit(15);
end;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace Microsoft.Integration.Shopify;

/// <summary>
/// Codeunit Shpfy GQL RevFulfillOrders (ID 30105) implements Interface Shpfy IGraphQL.
/// </summary>
codeunit 30105 "Shpfy GQL RevFulfillOrders" implements "Shpfy IGraphQL"
{
Access = Internal;

/// <summary>
/// GetGraphQL.
/// </summary>
/// <returns>Return value of type Text.</returns>
internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ return(id: \"gid://shopify/Return/{{ReturnId}}\") { reverseFulfillmentOrders(first: 10) { pageInfo { endCursor hasNextPage } nodes { id } } } }"}');

end;
Comment on lines +14 to +18
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! But consider improving readability of the query string.

The method correctly returns a GraphQL query string. For better readability and maintainability, consider formatting the query string.

- exit('{"query":"{ return(id: \"gid://shopify/Return/{{ReturnId}}\") { reverseFulfillmentOrders(first: 10) { pageInfo { endCursor hasNextPage } nodes { id } } } }"}');
+ exit(
+   '{
+     "query": "{ 
+       return(id: \"gid://shopify/Return/{{ReturnId}}\") { 
+         reverseFulfillmentOrders(first: 10) { 
+           pageInfo { endCursor hasNextPage } 
+           nodes { id } 
+         } 
+       } 
+     }"
+   }'
+ );
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
internal procedure GetGraphQL(): Text
begin
exit('{"query":"{ return(id: \"gid://shopify/Return/{{ReturnId}}\") { reverseFulfillmentOrders(first: 10) { pageInfo { endCursor hasNextPage } nodes { id } } } }"}');
end;
internal procedure GetGraphQL(): Text
begin
exit(
'{
"query": "{
return(id: \"gid://shopify/Return/{{ReturnId}}\") {
reverseFulfillmentOrders(first: 10) {
pageInfo { endCursor hasNextPage }
nodes { id }
}
}
}"
}'
);
end;


/// <summary>
/// GetExpectedCost.
/// </summary>
/// <returns>Return value of type Integer.</returns>
internal procedure GetExpectedCost(): Integer
begin
exit(7);
end;
}
20 changes: 20 additions & 0 deletions Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al
Original file line number Diff line number Diff line change
Expand Up @@ -400,4 +400,24 @@ enum 30111 "Shpfy GraphQL Type" implements "Shpfy IGraphQL"
Caption = 'Get Next Catalog Products';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL NextCatalogProducts";
}
value(78; GetReverseFulfillmentOrders)
{
Caption = 'Get Reverse Fulfillment Orders';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL RevFulfillOrders";
}
value(79; GetNextReverseFulfillmentOrders)
{
Caption = 'Get Next Reverse Fulfillment Orders';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL NextRevFulfillOrders";
}
value(80; GetReverseFulfillmentOrderLines)
{
Caption = 'Get Reverse Fulfillment Order Lines';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL RevFulfillOrderLines";
}
value(81; GetNextReverseFulfillmentOrderLines)
{
Caption = 'Get Next Reverse Fulfillment Order Lines';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL NextRevFulfillOrdLns";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ codeunit 30228 "Shpfy Refunds API"
RefundHeader: Record "Shpfy Refund Header";
GraphQLType: Enum "Shpfy GraphQL Type";
Parameters: Dictionary of [text, Text];
ReturnLocations: Dictionary of [BigInteger, BigInteger];
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling for CollectReturnLocations.

The CollectReturnLocations method should handle cases where the ReturnId is zero.

+  if ReturnId = 0 then
+      Error('Invalid Return ID provided.');
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ReturnLocations: Dictionary of [BigInteger, BigInteger];
ReturnLocations: Dictionary of [BigInteger, BigInteger];
+ if ReturnId = 0 then
+ Error('Invalid Return ID provided.');

JResponse: JsonToken;
JLines: JsonArray;
JLine: JsonToken;
begin
GetRefundHeader(RefundId, UpdatedAt, RefundHeader);
ReturnLocations := CollectReturnLocations(RefundHeader."Return Id");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor suggestion for repeated code in GetRefund procedure.

The GetRefund procedure has been updated to handle return locations. However, the repeated call to JsonHelper.GetValueAsText for the 'After' cursor in the GraphQL pagination can be refactored into a helper procedure to reduce duplication and improve maintainability.

+ private procedure GetCursor(JResponse: JsonToken): Text
+ begin
+     exit(JsonHelper.GetValueAsText(JResponse, 'data.refund.refundLineItems.pageInfo.endCursor'));
+ end;
...
- Parameters.Set('After', JsonHelper.GetValueAsText(JResponse, 'data.refund.refundLineItems.pageInfo.endCursor'));
+ Parameters.Set('After', GetCursor(JResponse));

Also applies to: 54-54


Parameters.Add('RefundId', Format(RefundId));
GraphQLType := "Shpfy GraphQL Type"::GetRefundLines;
repeat
Expand All @@ -46,8 +49,9 @@ codeunit 30228 "Shpfy Refunds API"
Parameters.Set('After', JsonHelper.GetValueAsText(JResponse, 'data.refund.refundLineItems.pageInfo.endCursor'))
else
Parameters.Add('After', JsonHelper.GetValueAsText(JResponse, 'data.refund.refundLineItems.pageInfo.endCursor'));

foreach JLine in JLines do
FillInRefundLine(RefundId, JLine.AsObject(), RefundHeader."Total Refunded Amount" > 0);
FillInRefundLine(RefundId, JLine.AsObject(), RefundHeader."Total Refunded Amount" > 0, ReturnLocations);
until not JsonHelper.GetValueAsBoolean(JResponse, 'data.refund.refundLineItems.pageInfo.hasNextPage');
end;

Expand Down Expand Up @@ -88,21 +92,34 @@ codeunit 30228 "Shpfy Refunds API"
DataCapture.Add(Database::"Shpfy Refund Header", RefundHeader.SystemId, JResponse);
end;

local procedure FillInRefundLine(RefundId: BigInteger; JLine: JsonObject; NonZeroRefund: Boolean)

local procedure CollectReturnLocations(ReturnId: BigInteger): Dictionary of [BigInteger, BigInteger]
var
ReturnsAPI: Codeunit "Shpfy Returns API";
begin
if ReturnId <> 0 then
exit(ReturnsAPI.GetReturnLocations(ReturnId));
end;
Comment on lines +96 to +102
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add error handling for invalid ReturnId.

The CollectReturnLocations method should handle cases where the ReturnId is zero to prevent potential issues.

+  if ReturnId = 0 then
+      Error('Invalid Return ID provided.');
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
local procedure CollectReturnLocations(ReturnId: BigInteger): Dictionary of [BigInteger, BigInteger]
var
ReturnsAPI: Codeunit "Shpfy Returns API";
begin
if ReturnId <> 0 then
exit(ReturnsAPI.GetReturnLocations(ReturnId));
end;
local procedure CollectReturnLocations(ReturnId: BigInteger): Dictionary of [BigInteger, BigInteger]
var
ReturnsAPI: Codeunit "Shpfy Returns API";
begin
if ReturnId = 0 then
Error('Invalid Return ID provided.');
if ReturnId <> 0 then
exit(ReturnsAPI.GetReturnLocations(ReturnId));
end;


local procedure FillInRefundLine(RefundId: BigInteger; JLine: JsonObject; NonZeroRefund: Boolean; ReturnLocations: Dictionary of [BigInteger, BigInteger])
var
DataCapture: Record "Shpfy Data Capture";
RefundLine: Record "Shpfy Refund Line";
RefundLineRecordRef: RecordRef;
Id: BigInteger;
ReturnLocation: BigInteger;
begin
Id := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JLine, 'lineItem.id'));

if not RefundLine.Get(RefundId, Id) then begin
RefundLine."Refund Line Id" := Id;
RefundLine."Refund Id" := RefundId;
RefundLine."Order Line Id" := Id;
RefundLine.Insert();
end;

RefundLine."Restock Type" := RefundEnumConvertor.ConvertToReStockType(JsonHelper.GetValueAsText(JLine, 'restockType'));

RefundLineRecordRef.GetTable(RefundLine);
JsonHelper.GetValueIntoField(JLine, 'quantity', RefundLineRecordRef, RefundLine.FieldNo(Quantity));
JsonHelper.GetValueIntoField(JLine, 'restocked', RefundLineRecordRef, RefundLine.FieldNo(Restocked));
Expand All @@ -113,8 +130,17 @@ codeunit 30228 "Shpfy Refunds API"
JsonHelper.GetValueIntoField(JLine, 'totalTaxSet.shopMoney.amount', RefundLineRecordRef, RefundLine.FieldNo("Total Tax Amount"));
JsonHelper.GetValueIntoField(JLine, 'totalTaxSet.presentmentMoney.amount', RefundLineRecordRef, RefundLine.FieldNo("Presentment Total Tax Amount"));
RefundLineRecordRef.SetTable(RefundLine);

RefundLine."Can Create Credit Memo" := NonZeroRefund;
RefundLine."Location Id" := JsonHelper.GetValueAsBigInteger(JLine, 'location.legacyResourceId');

// If refund was created from a return, the location needs to come from the return
// If Item was restocked to multiple locations, the return location is not known
if (RefundLine."Location Id" = 0) and (ReturnLocations.Get(RefundLine."Order Line Id", ReturnLocation)) then
RefundLine."Location Id" := ReturnLocation;

RefundLine.Modify();

RefundLineRecordRef.Close();
DataCapture.Add(Database::"Shpfy Refund Line", RefundLine.SystemId, JLine);
end;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ table 30145 "Shpfy Refund Line"
CalcFormula = lookup("Shpfy Order Line"."Gift Card" where("Line Id" = field("Order Line Id")));
Editable = false;
}
field(105; "Location Id"; BigInteger)
{
Caption = 'Location Id';
DataClassification = SystemMetadata;
Editable = false;
}
}
keys
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,6 @@ codeunit 30246 "Shpfy Create Sales Doc. Refund"
SalesHeader.Validate("Document Date", DT2Date(RefundHeader."Created At"));
if OrderMgt.FindTaxArea(OrderHeader, ShopifyTaxArea) and (ShopifyTaxArea."Tax Area Code" <> '') then
SalesHeader.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code");
SalesHeader.Validate("Location Code", Shop."Return Location");
end;
SalesHeader."Shpfy Refund Id" := RefundHeader."Refund Id";
SalesHeader.Modify(true);
Expand Down Expand Up @@ -143,6 +142,7 @@ codeunit 30246 "Shpfy Create Sales Doc. Refund"
RefundLine: Record "Shpfy Refund Line";
ReturnLine: Record "Shpfy Return Line";
GiftCard: Record "Shpfy Gift Card";
ShopLocation: Record "Shpfy Shop Location";
LineNo: Integer;
OpenAmount: Decimal;
IsHandled: Boolean;
Expand Down Expand Up @@ -181,7 +181,13 @@ codeunit 30246 "Shpfy Create Sales Doc. Refund"
SalesLine.Validate("No.", RefundLine."Item No.");
if RefundLine."Variant Code" <> '' then
SalesLine.Validate("Variant Code", RefundLine."Variant Code");
SalesLine.Validate("Location Code", Shop."Return Location");

if ShopLocation.Get(Shop.Code, RefundLine."Location Id") then
SalesLine.Validate("Location Code", ShopLocation."Default Location Code");

If (Shop."Return Location Priority" = "Shpfy Return Location Priority"::"Default Return Location") or (SalesLine."Location Code" = '') then
SalesLine.Validate("Location Code", Shop."Return Location");

end;
SalesLine.Validate(Quantity, RefundLine.Quantity);
SalesLine.Validate("Unit Price", RefundLine.Amount);
Expand Down Expand Up @@ -233,7 +239,13 @@ codeunit 30246 "Shpfy Create Sales Doc. Refund"
SalesLine.Validate("No.", ReturnLine."Item No.");
if ReturnLine."Variant Code" <> '' then
SalesLine.Validate("Variant Code", ReturnLine."Variant Code");
SalesLine.Validate("Location Code", Shop."Return Location");

if ShopLocation.Get(Shop.Code, ReturnLine."Location Id") then
SalesLine.Validate("Location Code", ShopLocation."Default Location Code");

If (Shop."Return Location Priority" = "Shpfy Return Location Priority"::"Default Return Location") or (SalesLine."Location Code" = '') then
SalesLine.Validate("Location Code", Shop."Return Location");

SalesLine.Validate(Quantity, ReturnLine.Quantity);
SalesLine.Validate("Unit Price", ReturnLine."Discounted Total Amount" / ReturnLine.Quantity);
end;
Expand Down
Loading