Skip to content

Commit 6febe7b

Browse files
authored
[Shopify] Change fulfillment service callback URL and update existing ones on open shop (#5208)
<!-- Thank you for submitting a Pull Request. If you're new to contributing to BCApps please read our pull request guideline below * https://github.com/microsoft/BCApps/Contributing.md --> #### Summary <!-- Provide a general summary of your changes --> Change fulfillment service callback URL and update existing ones on open shop #### Work Item(s) <!-- Add the issue number here after the #. The issue needs to be open and approved. Submitting PRs with no linked issues or unapproved issues is highly discouraged. --> Fixes [AB#609960](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/609960)
1 parent 286cad2 commit 6febe7b

15 files changed

+302
-15
lines changed

src/Apps/W1/Shopify/App/src/Base/Pages/ShpfyShopCard.Page.al

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,9 @@ page 30101 "Shpfy Shop Card"
12521252
Rec.Enabled := false;
12531253
Rec.Modify();
12541254
end;
1255+
#if not CLEAN28
1256+
Rec.UpdateFulfillmentService();
1257+
#endif
12551258
end;
12561259
end;
12571260

src/Apps/W1/Shopify/App/src/Base/Tables/ShpfyShop.Table.al

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,22 @@ table 30102 "Shpfy Shop"
805805
ToolTip = 'Specifies if fully fulfilled Shopify orders should be created as sales invoices.';
806806
InitValue = true;
807807
}
808+
#if not CLEANSCHEMA31
809+
field(206; "Fulfillment Service Updated"; Boolean)
810+
{
811+
Caption = 'Fulfillment Service Updated';
812+
DataClassification = SystemMetadata;
813+
Description = 'Indicates whether the Shopify Fulfillment Service has been updated to the latest version.';
814+
ObsoleteReason = 'This field is no longer used.';
815+
#if CLEAN28
816+
ObsoleteState = Removed;
817+
ObsoleteTag = '31.0';
818+
#else
819+
ObsoleteState = Pending;
820+
ObsoleteTag = '28.0';
821+
#endif
822+
}
823+
#endif
808824
}
809825

810826
keys
@@ -1049,4 +1065,24 @@ table 30102 "Shpfy Shop"
10491065
Session.LogMessage('0000KO0', ExpirationNotificationTxt, Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', CategoryTok);
10501066
end;
10511067
end;
1068+
1069+
#if not CLEAN28
1070+
#pragma warning disable AL0432
1071+
internal procedure UpdateFulfillmentService()
1072+
var
1073+
SyncShopLocations: Codeunit "Shpfy Sync Shop Locations";
1074+
begin
1075+
if Rec."Fulfillment Service Updated" then
1076+
exit;
1077+
1078+
if Rec."Fulfillment Service Activated" then begin
1079+
SyncShopLocations.SetShop(Rec);
1080+
SyncShopLocations.UpdateFulfillmentServiceCallbackUrl();
1081+
end;
1082+
1083+
Rec."Fulfillment Service Updated" := true;
1084+
Rec.Modify();
1085+
end;
1086+
#pragma warning restore AL0432
1087+
#endif
10521088
}

src/Apps/W1/Shopify/App/src/GraphQL/Codeunits/ShpfyGQLCreateFulfillmentSvc.Codeunit.al

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ codeunit 30233 "Shpfy GQL CreateFulfillmentSvc" implements "Shpfy IGraphQL"
1515
/// <returns>Return value of type Text.</returns>
1616
internal procedure GetGraphQL(): Text
1717
begin
18-
exit('{"query": "mutation { fulfillmentServiceCreate(name: \"Business Central Fulfillment Service\", callbackUrl: \"https://www.shopifyconnector.com/callback_url\") {fulfillmentService {id}}}"}');
18+
exit('{"query": "mutation { fulfillmentServiceCreate(name: \"{{Name}}\", callbackUrl: \"{{CallbackUrl}}\") {fulfillmentService {id}}}"}');
1919
end;
2020

2121
/// <summary>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ------------------------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License. See License.txt in the project root for license information.
4+
// ------------------------------------------------------------------------------------------------
5+
6+
namespace Microsoft.Integration.Shopify;
7+
8+
/// <summary>
9+
/// Codeunit Shpfy GQL Location (ID 30411).
10+
/// Implements the IGraphQL interface for retrieving Shopify location using GraphQL.
11+
/// </summary>
12+
codeunit 30411 "Shpfy GQL Location" implements "Shpfy IGraphQL"
13+
{
14+
Access = Internal;
15+
16+
/// <summary>
17+
/// GetGraphQL.
18+
/// </summary>
19+
/// <returns>Return value of type Text.</returns>
20+
internal procedure GetGraphQL(): Text
21+
begin
22+
exit('{"query": "{ location(id: \"gid://shopify/Location/{{Id}}\") { fulfillmentService { id callbackUrl } } }"}');
23+
end;
24+
25+
/// <summary>
26+
/// GetExpectedCost.
27+
/// </summary>
28+
/// <returns>Return value of type Integer.</returns>
29+
internal procedure GetExpectedCost(): Integer
30+
begin
31+
exit(2);
32+
end;
33+
}

src/Apps/W1/Shopify/App/src/GraphQL/Codeunits/ShpfyGQLLocations.Codeunit.al

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ codeunit 30100 "Shpfy GQL Locations" implements "Shpfy IGraphQL"
1818
/// <returns>Return value of type Text.</returns>
1919
internal procedure GetGraphQL(): Text
2020
begin
21-
exit('{"query":"{ locations(first: 20, includeLegacy: true) { pageInfo { hasNextPage endCursor } nodes { legacyResourceId isActive isPrimary name fulfillmentService { serviceName }}}}"}');
21+
exit('{"query":"{ locations(first: 20, includeLegacy: true) { pageInfo { hasNextPage endCursor } nodes { legacyResourceId isActive isPrimary name fulfillmentService { id callbackUrl }}}}"}');
2222
end;
2323

2424
/// <summary>

src/Apps/W1/Shopify/App/src/GraphQL/Codeunits/ShpfyGQLNextLocations.Codeunit.al

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ codeunit 30214 "Shpfy GQL Next Locations" implements "Shpfy IGraphQL"
1818
/// <returns>Return value of type Text.</returns>
1919
internal procedure GetGraphQL(): Text
2020
begin
21-
exit('{"query":"{ locations(first: 20, after:\"{{After}}\", includeLegacy: true) { pageInfo { hasNextPage endCursor } nodes { legacyResourceId isActive isPrimary name fulfillmentService { serviceName }}}}"}');
21+
exit('{"query":"{ locations(first: 20, after:\"{{After}}\", includeLegacy: true) { pageInfo { hasNextPage endCursor } nodes { legacyResourceId isActive isPrimary name fulfillmentService { id callbackUrl }}}}"}');
2222
end;
2323

2424
/// <summary>
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// ------------------------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All rights reserved.
3+
// Licensed under the MIT License. See License.txt in the project root for license information.
4+
// ------------------------------------------------------------------------------------------------
5+
6+
namespace Microsoft.Integration.Shopify;
7+
8+
/// <summary>
9+
/// Codeunit Shpfy GQL UpdateFulfillmentSvc (ID 30410).
10+
/// Implements the IGraphQL interface for updating Shopify fulfillment service using GraphQL.
11+
/// </summary>
12+
codeunit 30410 "Shpfy GQL UpdateFulfillmentSvc" implements "Shpfy IGraphQL"
13+
{
14+
Access = Internal;
15+
16+
/// <summary>
17+
/// GetGraphQL.
18+
/// </summary>
19+
/// <returns>Return value of type Text.</returns>
20+
internal procedure GetGraphQL(): Text
21+
begin
22+
exit('{"query": "mutation { fulfillmentServiceUpdate( id: \"gid://shopify/FulfillmentService/{{Id}}\" callbackUrl: \"{{CallbackUrl}}\" ) { userErrors { field message } fulfillmentService { callbackUrl } } }"}');
23+
end;
24+
25+
/// <summary>
26+
/// GetExpectedCost.
27+
/// </summary>
28+
/// <returns>Return value of type Integer.</returns>
29+
internal procedure GetExpectedCost(): Integer
30+
begin
31+
exit(10);
32+
end;
33+
}

src/Apps/W1/Shopify/App/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,4 +660,14 @@ enum 30111 "Shpfy GraphQL Type" implements "Shpfy IGraphQL"
660660
Caption = 'Get Company Location';
661661
Implementation = "Shpfy IGraphQL" = "Shpfy GQL CompLocation";
662662
}
663+
value(134; UpdateFulfillmentService)
664+
{
665+
Caption = 'Update Fulfillment Service';
666+
Implementation = "Shpfy IGraphQL" = "Shpfy GQL UpdateFulfillmentSvc";
667+
}
668+
value(135; GetLocation)
669+
{
670+
Caption = 'Get Location';
671+
Implementation = "Shpfy IGraphQL" = "Shpfy GQL Location";
672+
}
663673
}

src/Apps/W1/Shopify/App/src/Inventory/Codeunits/ShpfySyncShopLocations.Codeunit.al

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@ codeunit 30198 "Shpfy Sync Shop Locations"
1818
Shop := Rec;
1919
CommunicationMgt.SetShop(Rec);
2020
SyncLocations();
21+
UpdateFulfillmentServiceCallbackUrl();
2122
end;
2223

2324
var
2425
Shop: record "Shpfy Shop";
2526
CommunicationMgt: Codeunit "Shpfy Communication Mgt.";
2627
JsonHelper: Codeunit "Shpfy Json Helper";
28+
FulfillmentServiceNameLbl: Label 'Business Central Fulfillment Service', Locked = true;
29+
FulfillmentServiceCallbackUrlLbl: Label 'https://businesscentral.dynamics.com/shopify/webhooks', Locked = true;
2730

2831
/// <summary>
2932
/// Import Location.
@@ -35,6 +38,7 @@ codeunit 30198 "Shpfy Sync Shop Locations"
3538
ShopLocation: Record "Shpfy Shop Location";
3639
IsNew: Boolean;
3740
JValue: JsonValue;
41+
JFulfillmentService: JsonToken;
3842
begin
3943
if JsonHelper.GetJsonValue(JLocation, JValue, 'legacyResourceId') then begin
4044
if not ShopLocation.Get(Shop.Code, JValue.AsBigInteger()) then begin
@@ -48,7 +52,12 @@ codeunit 30198 "Shpfy Sync Shop Locations"
4852
#pragma warning restore AA0139
4953
ShopLocation.Active := JsonHelper.GetValueAsBoolean(JLocation, 'isActive');
5054
ShopLocation."Is Primary" := JsonHelper.GetValueAsBoolean(JLocation, 'isPrimary');
51-
ShopLocation."Is Fulfillment Service" := JsonHelper.GetJsonToken(JLocation.AsToken(), 'fulfillmentService').IsObject;
55+
JFulfillmentService := JsonHelper.GetJsonToken(JLocation.AsToken(), 'fulfillmentService');
56+
ShopLocation."Is Fulfillment Service" := JFulfillmentService.IsObject();
57+
if ShopLocation."Is Fulfillment Service" then begin
58+
ShopLocation."Fulfillment Service Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JFulfillmentService, 'id'));
59+
ShopLocation."Fulfillment Srv. Callback Url" := CopyStr(JsonHelper.GetValueAsText(JFulfillmentService, 'callbackUrl'), 1, MaxStrLen(ShopLocation."Fulfillment Srv. Callback Url"));
60+
end;
5261
if IsNew then
5362
ShopLocation.Insert()
5463
else begin
@@ -103,6 +112,56 @@ codeunit 30198 "Shpfy Sync Shop Locations"
103112
until TempShopLocation.Next() = 0;
104113
end;
105114

115+
internal procedure UpdateFulfillmentServiceCallbackUrl()
116+
var
117+
ShopLocation: Record "Shpfy Shop Location";
118+
GraphQLType: Enum "Shpfy GraphQL Type";
119+
Parameters: Dictionary of [Text, Text];
120+
JResponse: JsonToken;
121+
JValue: JsonValue;
122+
begin
123+
ShopLocation.SetRange("Shop Code", Shop.Code);
124+
ShopLocation.SetRange("Is Fulfillment Service", true);
125+
ShopLocation.SetRange(Name, GetFulfillmentServiceName());
126+
if not ShopLocation.FindFirst() then
127+
exit;
128+
129+
if ShopLocation."Fulfillment Service Id" = 0 then
130+
GetFulfillmentService(ShopLocation);
131+
132+
if ShopLocation."Fulfillment Srv. Callback Url" = GetFulfillmentServiceCallbackUrl() then
133+
exit;
134+
135+
GraphQLType := "Shpfy GraphQL Type"::UpdateFulfillmentService;
136+
Parameters.Add('Id', Format(ShopLocation."Fulfillment Service Id"));
137+
Parameters.Add('CallbackUrl', GetFulfillmentServiceCallbackUrl());
138+
JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType, Parameters);
139+
140+
if JsonHelper.GetJsonValue(JResponse, JValue, 'data.fulfillmentServiceUpdate.fulfillmentService.callbackUrl') then begin
141+
ShopLocation."Fulfillment Srv. Callback Url" := CopyStr(JValue.AsText(), 1, MaxStrLen(ShopLocation."Fulfillment Srv. Callback Url"));
142+
ShopLocation.Modify();
143+
end;
144+
end;
145+
146+
local procedure GetFulfillmentService(var ShopLocation: Record "Shpfy Shop Location")
147+
var
148+
GraphQLType: Enum "Shpfy GraphQL Type";
149+
Parameters: Dictionary of [Text, Text];
150+
JResponse: JsonToken;
151+
JFulfillmentService: JsonObject;
152+
begin
153+
GraphQLType := "Shpfy GraphQL Type"::GetLocation;
154+
Parameters.Add('Id', Format(ShopLocation.Id));
155+
JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType, Parameters);
156+
157+
if not JsonHelper.GetJsonObject(JResponse, JFulfillmentService, 'data.location.fulfillmentService') then
158+
exit;
159+
160+
ShopLocation."Fulfillment Service Id" := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JFulfillmentService, 'id'));
161+
ShopLocation."Fulfillment Srv. Callback Url" := CopyStr(JsonHelper.GetValueAsText(JFulfillmentService, 'callbackUrl'), 1, MaxStrLen(ShopLocation."Fulfillment Srv. Callback Url"));
162+
ShopLocation.Modify();
163+
end;
164+
106165
local procedure HasNextResults(JObject: JsonObject): Boolean
107166
begin
108167
exit(JsonHelper.GetValueAsBoolean(JObject, 'hasNextPage'));
@@ -111,6 +170,16 @@ codeunit 30198 "Shpfy Sync Shop Locations"
111170
internal procedure SetShop(ShopifyShop: Record "Shpfy Shop")
112171
begin
113172
Shop := ShopifyShop;
173+
CommunicationMgt.SetShop(Shop);
114174
end;
115175

176+
internal procedure GetFulfillmentServiceName(): Text
177+
begin
178+
exit(FulfillmentServiceNameLbl);
179+
end;
180+
181+
internal procedure GetFulfillmentServiceCallbackUrl(): Text
182+
begin
183+
exit(FulfillmentServiceCallbackUrlLbl);
184+
end;
116185
}

src/Apps/W1/Shopify/App/src/Inventory/Tables/ShpfyShopLocation.Table.al

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,20 @@ table 30113 "Shpfy Shop Location"
147147
end;
148148
end;
149149
}
150+
field(13; "Fulfillment Service Id"; BigInteger)
151+
{
152+
Caption = 'Fulfillment Service Id';
153+
DataClassification = SystemMetadata;
154+
Editable = false;
155+
Description = 'The Id of the fulfillment service in Shopify.';
156+
}
157+
field(14; "Fulfillment Srv. Callback Url"; Text[500])
158+
{
159+
Caption = 'Fulfillment Service Callback Url';
160+
DataClassification = SystemMetadata;
161+
Editable = false;
162+
Description = 'The callback URL of the fulfillment service in Shopify.';
163+
}
150164
}
151165

152166
keys

0 commit comments

Comments
 (0)