diff --git a/Apps/W1/Shopify/app/app.json b/Apps/W1/Shopify/app/app.json
index 0be3e1f856..3ddb14510c 100644
--- a/Apps/W1/Shopify/app/app.json
+++ b/Apps/W1/Shopify/app/app.json
@@ -21,7 +21,7 @@
"idRanges": [
{
"from": 30100,
- "to": 30350
+ "to": 30360
}
],
"internalsVisibleTo": [
diff --git a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyMetafield.Table.al b/Apps/W1/Shopify/app/src/Base/Tables/ShpfyMetafield.Table.al
deleted file mode 100644
index f368c2ab82..0000000000
--- a/Apps/W1/Shopify/app/src/Base/Tables/ShpfyMetafield.Table.al
+++ /dev/null
@@ -1,103 +0,0 @@
-namespace Microsoft.Integration.Shopify;
-
-///
-/// Table Shpfy Metafield (ID 30101).
-///
-table 30101 "Shpfy Metafield"
-{
- Access = Internal;
- Caption = 'Shopify Metafield';
- DataClassification = CustomerContent;
-
- fields
- {
- field(1; Id; BigInteger)
- {
- Caption = 'Id';
- DataClassification = SystemMetadata;
- Editable = false;
- }
-
- field(2; Namespace; Text[100])
- {
- Caption = 'Namespace';
- DataClassification = SystemMetadata;
- }
-
- field(3; "Owner Resource"; Text[50])
- {
- Caption = 'Owner Resource';
- DataClassification = SystemMetadata;
-
- trigger OnValidate()
- begin
- case "Owner Resource" of
- 'customer':
- "Parent Table No." := Database::"Shpfy Customer";
- end;
- end;
- }
-
- field(4; "Owner Id"; BigInteger)
- {
- Caption = 'Owner Id';
- DataClassification = SystemMetadata;
- }
-
-
- field(5; Name; Text[30])
- {
- Caption = 'Key';
- DataClassification = CustomerContent;
- }
-
- field(6; "Value Type"; enum "Shpfy Metafield Value Type")
- {
- Caption = 'Value Type';
- DataClassification = CustomerContent;
- }
-
- field(7; Value; Text[250])
- {
- Caption = 'Value';
- DataClassification = CustomerContent;
- }
-
- field(101; "Parent Table No."; Integer)
- {
- Caption = 'Parent Table No.';
- DataClassification = SystemMetadata;
- Editable = false;
-
- trigger OnValidate()
- begin
- case "Parent Table No." of
- Database::"Shpfy Customer":
- "Owner Resource" := 'customer';
- end;
- end;
- }
- }
-
- keys
- {
- key(PK; Id)
- {
- Clustered = true;
- }
- }
-
-
- trigger OnInsert()
- var
- Metafield: Record "Shpfy Metafield";
- begin
- if Namespace = '' then
- Namespace := 'Microsoft.Dynamics365.BusinessCentral';
- if Id = 0 then
- if Metafield.FindFirst() and (Metafield.Id < 0) then
- Id := Metafield.Id - 1
- else
- Id := -1;
- end;
-}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerExport.Codeunit.al b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerExport.Codeunit.al
index ec62eec90b..363fe23448 100644
--- a/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerExport.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/Customers/Codeunits/ShpfyCustomerExport.Codeunit.al
@@ -64,7 +64,7 @@ codeunit 30116 "Shpfy Customer Export"
Metafield.Namespace := 'Microsoft.Dynamics365.BusinessCentral';
Metafield.Validate("Parent Table No.", Database::"Shpfy Customer");
Metafield."Owner Id" := ShopifyCustomer.Id;
- Metafield."Value Type" := Metafield."Value Type"::String;
+ Metafield.Type := Metafield.Type::string;
Metafield.Value := Format(MetadataFieldRef.Value);
end;
end;
diff --git a/Apps/W1/Shopify/app/src/Customers/Tables/ShpfyCustomer.Table.al b/Apps/W1/Shopify/app/src/Customers/Tables/ShpfyCustomer.Table.al
index b8ad162bec..c194c2e1a0 100644
--- a/Apps/W1/Shopify/app/src/Customers/Tables/ShpfyCustomer.Table.al
+++ b/Apps/W1/Shopify/app/src/Customers/Tables/ShpfyCustomer.Table.al
@@ -148,6 +148,7 @@ table 30105 "Shpfy Customer"
if not Tag.IsEmpty() then
Tag.DeleteAll();
+ Metafield.SetRange("Parent Table No.", Database::"Shpfy Customer");
Metafield.SetRange("Owner Id", Id);
if not Metafield.IsEmpty then
Metafield.DeleteAll();
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLMetafieldsSet.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLMetafieldsSet.Codeunit.al
new file mode 100644
index 0000000000..f04cfc1cab
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLMetafieldsSet.Codeunit.al
@@ -0,0 +1,27 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Codeunit Shpfy GQL MetafieldSet (ID 30168) implements Interface Shpfy IGraphQL.
+///
+codeunit 30350 "Shpfy GQL MetafieldsSet" implements "Shpfy IGraphQL"
+{
+ Access = Internal;
+
+ ///
+ /// GetGraphQL.
+ ///
+ /// Return value of type Text.
+ internal procedure GetGraphQL(): Text
+ begin
+ exit('{"query": "mutation { metafieldsSet(metafields: [{{Metafields}}]) { metafields {legacyResourceId namespace key} userErrors {field, message}}}"}');
+ end;
+
+ ///
+ /// GetExpectedCost.
+ ///
+ /// Return value of type Integer.
+ internal procedure GetExpectedCost(): Integer
+ begin
+ exit(10);
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductById.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductById.Codeunit.al
index 183fcc8147..a8a559b5c2 100644
--- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductById.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductById.Codeunit.al
@@ -13,7 +13,7 @@ codeunit 30146 "Shpfy GQL ProductById" implements "Shpfy IGraphQL"
/// Return value of type Text.
internal procedure GetGraphQL(): Text
begin
- exit('{"query":"{product(id: \"gid://shopify/Product/{{ProductId}}\") {createdAt updatedAt hasOnlyDefaultVariant description(truncateAt: {{MaxLengthDescription}}) descriptionHtml onlineStorePreviewUrl onlineStoreUrl productType status tags title vendor seo{description, title} images(first: 1) {edges{node{id}}} metafields(namespace: \"Microsoft.Dynamics365.BusinessCentral\", first: 10) {edges {node {id namespace type legacyResourceId key value}}}}}"}');
+ exit('{"query":"{product(id: \"gid://shopify/Product/{{ProductId}}\") {createdAt updatedAt hasOnlyDefaultVariant description(truncateAt: {{MaxLengthDescription}}) descriptionHtml onlineStorePreviewUrl onlineStoreUrl productType status tags title vendor seo{description, title} images(first: 1) {edges{node{id}}} metafields(first: 50) {edges {node {id namespace type legacyResourceId key value}}}}}"}');
end;
///
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductMetafieldIds.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductMetafieldIds.Codeunit.al
new file mode 100644
index 0000000000..f70ba9b255
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLProductMetafieldIds.Codeunit.al
@@ -0,0 +1,28 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Codeunit Shpfy GQL ProductMetafieldIds (ID 30332) implements Interface Shpfy IGraphQL.
+///
+codeunit 30332 "Shpfy GQL ProductMetafieldIds" implements "Shpfy IGraphQL"
+{
+ Access = Internal;
+
+ ///
+ /// GetGraphQL.
+ ///
+ /// Return value of type Text.
+ internal procedure GetGraphQL(): Text
+ begin
+ exit('{"query":"{product(id: \"gid://shopify/Product/{{ProductId}}\") { metafields(first: 50) {edges{node{legacyResourceId updatedAt}}}}}"}');
+ end;
+
+ ///
+ /// GetExpectedCost.
+ ///
+ /// Return value of type Integer.
+ internal procedure GetExpectedCost(): Integer
+ begin
+ exit(50);
+ end;
+
+}
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantById.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantById.Codeunit.al
index 3973390897..8bb1d2c9c4 100644
--- a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantById.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantById.Codeunit.al
@@ -13,7 +13,7 @@ codeunit 30150 "Shpfy GQL VariantById" implements "Shpfy IGraphQL"
/// Return value of type Text.
internal procedure GetGraphQL(): Text
begin
- exit('{"query":"{productVariant(id: \"gid://shopify/ProductVariant/{{VariantId}}\") {createdAt updatedAt availableForSale barcode compareAtPrice displayName inventoryPolicy position price sku taxCode taxable title weight product{id}selectedOptions{name value} inventoryItem{countryCodeOfOrigin createdAt id inventoryHistoryUrl legacyResourceId provinceCodeOfOrigin requiresShipping sku tracked updatedAt unitCost { amount currencyCode }} metafields(namespace: \"Microsoft.Dynamics365.BusinessCentral\", first: 10) {edges {node {id namespace ownerType legacyResourceId key value}}}}}"}');
+ exit('{"query":"{productVariant(id: \"gid://shopify/ProductVariant/{{VariantId}}\") {createdAt updatedAt availableForSale barcode compareAtPrice displayName inventoryPolicy position price sku taxCode taxable title weight product{id}selectedOptions{name value} inventoryItem{countryCodeOfOrigin createdAt id inventoryHistoryUrl legacyResourceId provinceCodeOfOrigin requiresShipping sku tracked updatedAt unitCost { amount currencyCode }} metafields(first: 50) {edges {node {id namespace ownerType legacyResourceId key value}}}}}"}');
end;
///
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantMetafieldIds.Codeunit.al b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantMetafieldIds.Codeunit.al
new file mode 100644
index 0000000000..4bf3e281b7
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/GraphQL/Codeunits/ShpfyGQLVariantMetafieldIds.Codeunit.al
@@ -0,0 +1,28 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Codeunit Shpfy GQL VariantMetafieldIds (ID 30336) implements Interface Shpfy IGraphQL.
+///
+codeunit 30336 "Shpfy GQL VariantMetafieldIds" implements "Shpfy IGraphQL"
+{
+ Access = Internal;
+
+ ///
+ /// GetGraphQL.
+ ///
+ /// Return value of type Text.
+ internal procedure GetGraphQL(): Text
+ begin
+ exit('{"query":"{productVariant(id: \"gid://shopify/ProductVariant/{{VariantId}}\") { metafields(first: 50) {edges{ node{legacyResourceId updatedAt}}}}}"}');
+ end;
+
+ ///
+ /// GetExpectedCost.
+ ///
+ /// Return value of type Integer.
+ internal procedure GetExpectedCost(): Integer
+ begin
+ exit(50);
+ end;
+
+}
diff --git a/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al b/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al
index 3157f92a53..8c9626b419 100644
--- a/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al
+++ b/Apps/W1/Shopify/app/src/GraphQL/Enums/ShpfyGraphQLType.Enum.al
@@ -405,6 +405,21 @@ enum 30111 "Shpfy GraphQL Type" implements "Shpfy IGraphQL"
Caption = 'Get Order Transactions';
Implementation = "Shpfy IGraphQL" = "Shpfy GQL OrderTransactions";
}
+ value(79; MetafieldSet)
+ {
+ Caption = 'MetfieldSet';
+ Implementation = "Shpfy IGraphQL" = "Shpfy GQL MetafieldsSet";
+ }
+ value(80; ProductMetafieldIds)
+ {
+ Caption = 'Product Metafield Ids';
+ Implementation = "Shpfy IGraphQL" = "Shpfy GQL ProductMetafieldIds";
+ }
+ value(81; VariantMetafieldIds)
+ {
+ Caption = 'Variant Metafield Ids';
+ Implementation = "Shpfy IGraphQL" = "Shpfy GQL VariantMetafieldIds";
+ }
value(85; ProductVariantDelete)
{
Caption = 'Product Variant Delete';
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeBoolean.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeBoolean.Codeunit.al
new file mode 100644
index 0000000000..9b1b65d3a7
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeBoolean.Codeunit.al
@@ -0,0 +1,27 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30338 "Shpfy Mtfld Type Boolean" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ DummyBoolean: Boolean;
+ begin
+ exit(Evaluate(DummyBoolean, Value, 9));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('true');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeCollectRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeCollectRef.Codeunit.al
new file mode 100644
index 0000000000..25e78a3bdd
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeCollectRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30321 "Shpfy Mtfld Type Collect. Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/Collection\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/Collection/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeColor.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeColor.Codeunit.al
new file mode 100644
index 0000000000..55759bda36
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeColor.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30319 "Shpfy Mtfld Type Color" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^#[0-9A-Fa-f]{6}$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('#fff123');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDate.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDate.Codeunit.al
new file mode 100644
index 0000000000..96b530e90c
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDate.Codeunit.al
@@ -0,0 +1,27 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30318 "Shpfy Mtfld Type Date" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ DummyDate: Date;
+ begin
+ exit(Evaluate(DummyDate, Value, 9));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('2022-02-02');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDateTime.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDateTime.Codeunit.al
new file mode 100644
index 0000000000..e83ed841ed
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDateTime.Codeunit.al
@@ -0,0 +1,27 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30315 "Shpfy Mtfld Type DateTime" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ DummyDateTime: DateTime;
+ begin
+ exit(Evaluate(DummyDateTime, Value, 9));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('2022-01-01T12:30:00');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDimension.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDimension.Codeunit.al
new file mode 100644
index 0000000000..107cac0063
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeDimension.Codeunit.al
@@ -0,0 +1,70 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30351 "Shpfy Mtfld Type Dimension" implements "Shpfy IMetafield Type"
+{
+ var
+ DimensionJsonTemplateTxt: Label '{"value": %1, "unit": "%2"}', Locked = true;
+
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Dimension: Decimal;
+ Unit: Enum "Shpfy Metafield Dimension Type";
+ begin
+ exit(TryExtractValues(Value, Dimension, Unit));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ var
+ MetafieldAssistEdit: Page "Shpfy Metafield Assist Edit";
+ Dimension: Decimal;
+ Unit: Enum "Shpfy Metafield Dimension Type";
+ begin
+ if Value <> '' then
+ if not TryExtractValues(Value, Dimension, Unit) then begin
+ Clear(Dimension);
+ Clear(Unit);
+ end;
+
+ if MetafieldAssistEdit.OpenForDimension(Dimension, Unit) then begin
+ MetafieldAssistEdit.GetDimensionValue(Dimension, Unit);
+ Value := StrSubstNo(DimensionJsonTemplateTxt, Format(Dimension, 0, 9), GetDimensionTypeName(Unit));
+ end else
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit(StrSubstNo(DimensionJsonTemplateTxt, '1.5', 'cm'));
+ end;
+
+ [TryFunction]
+ local procedure TryExtractValues(Value: Text; var Dimension: Decimal; var Unit: Enum "Shpfy Metafield Dimension Type")
+ var
+ JToken: JsonToken;
+ JObject: JsonObject;
+ begin
+ JObject.ReadFrom(Value);
+ JObject.SelectToken('value', JToken);
+ Dimension := JToken.AsValue().AsDecimal();
+ JObject.SelectToken('unit', JToken);
+ Unit := ConvertToDimensionType(JToken.AsValue().AsText());
+
+ if JObject.Keys.Count() <> 2 then
+ Error('');
+ end;
+
+ local procedure GetDimensionTypeName(DimensionType: Enum "Shpfy Metafield Dimension Type"): Text
+ begin
+ exit(DimensionType.Names().Get(DimensionType.Ordinals().IndexOf(DimensionType.AsInteger())));
+ end;
+
+ local procedure ConvertToDimensionType(Value: Text) Type: Enum "Shpfy Metafield Dimension Type"
+ begin
+ exit(Enum::"Shpfy Metafield Dimension Type".FromInteger(Type.Ordinals().Get(Type.Names().IndexOf(Value))));
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeFileRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeFileRef.Codeunit.al
new file mode 100644
index 0000000000..9e5c357782
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeFileRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30322 "Shpfy Mtfld Type File Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/(GenericFile|MediaImage|Video)\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/MediaImage/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeInteger.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeInteger.Codeunit.al
new file mode 100644
index 0000000000..28a7406b37
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeInteger.Codeunit.al
@@ -0,0 +1,37 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30339 "Shpfy Mtfld Type Integer" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ DummyInteger: BigInteger;
+ MinInt: BigInteger;
+ MaxInt: BigInteger;
+ begin
+ if not Evaluate(DummyInteger, Value, 9) then
+ exit(false);
+
+ Evaluate(MinInt, '-9007199254740991', 9);
+ Evaluate(MaxInt, '9007199254740991', 9);
+ if (DummyInteger < MinInt) or (DummyInteger > MaxInt) then
+ exit(false);
+
+ exit(true);
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('123');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeJson.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeJson.Codeunit.al
new file mode 100644
index 0000000000..95d5732b99
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeJson.Codeunit.al
@@ -0,0 +1,27 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30353 "Shpfy Mtfld Type Json" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ JsonObject: JsonObject;
+ begin
+ exit(JsonObject.ReadFrom(Value));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('{"ingredient": "flour", "amount": 0.3}');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMetaobjRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMetaobjRef.Codeunit.al
new file mode 100644
index 0000000000..9053ac668d
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMetaobjRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30327 "Shpfy Mtfld Type Metaobj. Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/Metaobject\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/Metaobject/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMixedRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMixedRef.Codeunit.al
new file mode 100644
index 0000000000..ca7dca2ed4
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMixedRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30331 "Shpfy Mtfld Type Mixed Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/[A-Za-z]+\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/Product/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMoney.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMoney.Codeunit.al
new file mode 100644
index 0000000000..2acb6640d6
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMoney.Codeunit.al
@@ -0,0 +1,74 @@
+namespace Microsoft.Integration.Shopify;
+
+using Microsoft.Finance.Currency;
+
+codeunit 30317 "Shpfy Mtfld Type Money" implements "Shpfy IMetafield Type"
+{
+ var
+ MoneyJsonTemplateTxt: Label '{"amount": "%1", "currency_code": "%2"}', Locked = true;
+
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Amount: Decimal;
+ CurrencyCode: Code[10];
+ begin
+ exit(TryExtractValues(Value, Amount, CurrencyCode));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ var
+ MetafieldAssistEdit: Page "Shpfy Metafield Assist Edit";
+ Amount: Decimal;
+ CurrencyCode: Code[10];
+ begin
+ if Value <> '' then
+ if not TryExtractValues(Value, Amount, CurrencyCode) then begin
+ Clear(Amount);
+ Clear(CurrencyCode);
+ end;
+
+ if MetafieldAssistEdit.OpenForMoney(Amount, CurrencyCode) then begin
+ MetafieldAssistEdit.GetMoneyValue(Amount, CurrencyCode);
+ Value := StrSubstNo(MoneyJsonTemplateTxt, Format(Amount, 0, 9), CurrencyCode);
+ exit(true);
+ end else
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit(StrSubstNo(MoneyJsonTemplateTxt, '5.99', 'CAD'));
+ end;
+
+ ///
+ /// Tried to extract the amount and currency code from the JSON string.
+ ///
+ /// JSON string with the following format: {"amount": "5.99", "currency_code": "CAD"}
+ /// Return value: the amount extracted from the JSON string.
+ /// Return value: the currency code extracted from the JSON string.
+ /// True if no errors occurred during the extraction.
+ [TryFunction]
+ internal procedure TryExtractValues(Value: Text; var Amount: Decimal; var CurrencyCode: Code[10])
+ var
+ Currency: Record Currency;
+ JToken: JsonToken;
+ JObject: JsonObject;
+ begin
+ JObject.ReadFrom(Value);
+ JObject.SelectToken('amount', JToken);
+ Amount := JToken.AsValue().AsDecimal();
+ JObject.SelectToken('currency_code', JToken);
+#pragma warning disable AA0139
+ CurrencyCode := JToken.AsValue().AsText();
+#pragma warning restore AA0139
+ Currency.Get(CurrencyCode);
+
+ if JObject.Keys.Count() <> 2 then
+ Error('');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMultiText.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMultiText.Codeunit.al
new file mode 100644
index 0000000000..5ddb65e64f
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeMultiText.Codeunit.al
@@ -0,0 +1,30 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30352 "Shpfy Mtfld Type Multi Text" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ var
+ MetafieldAssistEdit: Page "Shpfy Metafield Assist Edit";
+ begin
+ if MetafieldAssistEdit.OpenForMultiLineText(Value) then begin
+ MetafieldAssistEdit.GetMultiLineText(Value);
+ exit(true);
+ end else
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('Ingredients\Flour\Water\Milk\Eggs');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumDecimal.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumDecimal.Codeunit.al
new file mode 100644
index 0000000000..7d6b11c8d6
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumDecimal.Codeunit.al
@@ -0,0 +1,30 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30354 "Shpfy Mtfld Type Num Decimal" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ // +/-9999999999999.999999999
+ exit(Regex.IsMatch(Value, '^[-+]?\d{1,13}(?:\.\d{1,9})?$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('123.45');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumInteger.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumInteger.Codeunit.al
new file mode 100644
index 0000000000..dbce1c839b
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeNumInteger.Codeunit.al
@@ -0,0 +1,37 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30320 "Shpfy Mtfld Type Num Integer" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ DummyInteger: BigInteger;
+ MinInt: BigInteger;
+ MaxInt: BigInteger;
+ begin
+ if not Evaluate(DummyInteger, Value, 9) then
+ exit(false);
+
+ Evaluate(MinInt, '-9007199254740991', 9);
+ Evaluate(MaxInt, '9007199254740991', 9);
+ if (DummyInteger < MinInt) or (DummyInteger > MaxInt) then
+ exit(false);
+
+ exit(true);
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('123');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypePageRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypePageRef.Codeunit.al
new file mode 100644
index 0000000000..81401c2ee1
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypePageRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30328 "Shpfy Mtfld Type Page Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/OnlinePage\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/OnlinePage/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeProductRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeProductRef.Codeunit.al
new file mode 100644
index 0000000000..e9c765c5d6
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeProductRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30329 "Shpfy Mtfld Type Product Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/Product\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/Product/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeSingleText.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeSingleText.Codeunit.al
new file mode 100644
index 0000000000..5a207003f6
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeSingleText.Codeunit.al
@@ -0,0 +1,25 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30323 "Shpfy Mtfld Type Single Text" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('VIP shipping method');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeString.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeString.Codeunit.al
new file mode 100644
index 0000000000..ddb25456f8
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeString.Codeunit.al
@@ -0,0 +1,25 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30337 "Shpfy Mtfld Type String" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('Example');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeUrl.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeUrl.Codeunit.al
new file mode 100644
index 0000000000..bbb87ff1fc
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeUrl.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30324 "Shpfy Mtfld Type Url" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^(http|https|mailto|sms|tel)://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('https://www.shopify.com');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVariantRef.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVariantRef.Codeunit.al
new file mode 100644
index 0000000000..e3fe97876d
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVariantRef.Codeunit.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+using System.Utilities;
+
+codeunit 30330 "Shpfy Mtfld Type Variant Ref" implements "Shpfy IMetafield Type"
+{
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(false);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Regex: Codeunit Regex;
+ begin
+ exit(Regex.IsMatch(Value, '^gid:\/\/shopify\/Variant\/\d+$'));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ begin
+ Value := Value;
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit('gid://shopify/Variant/1234567890');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVolume.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVolume.Codeunit.al
new file mode 100644
index 0000000000..18faa414ef
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeVolume.Codeunit.al
@@ -0,0 +1,72 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30325 "Shpfy Mtfld Type Volume" implements "Shpfy IMetafield Type"
+{
+ var
+ VolumeJsonTemplateTxt: Label '{"value": %1,"unit":"%2"}', Locked = true;
+
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Volume: Decimal;
+ Unit: Enum "Shpfy Metafield Volume Type";
+ begin
+ exit(TryExtractValues(Value, Volume, Unit));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ var
+ MetafieldAssistEdit: Page "Shpfy Metafield Assist Edit";
+ Volume: Decimal;
+ Unit: Enum "Shpfy Metafield Volume Type";
+ begin
+ if Value <> '' then
+ if not TryExtractValues(Value, Volume, Unit) then begin
+ Clear(Volume);
+ Clear(Unit);
+ end;
+
+ if MetafieldAssistEdit.OpenForVolume(Volume, Unit) then begin
+ MetafieldAssistEdit.GetVolumeValue(Volume, Unit);
+ Value := StrSubstNo(VolumeJsonTemplateTxt, Format(Volume, 0, 9), GetVolumeTypeName(Unit));
+ exit(true);
+ end else
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit(StrSubstNo(VolumeJsonTemplateTxt, '20.0', 'ml'));
+ end;
+
+
+ [TryFunction]
+ local procedure TryExtractValues(Value: Text; var Volume: Decimal; var Unit: Enum "Shpfy Metafield Volume Type")
+ var
+ JToken: JsonToken;
+ JObject: JsonObject;
+ begin
+ JObject.ReadFrom(Value);
+ JObject.SelectToken('value', JToken);
+ Volume := JToken.AsValue().AsDecimal();
+ JObject.SelectToken('unit', JToken);
+ Unit := ConvertToVolumeType(JToken.AsValue().AsText());
+
+ if JObject.Keys.Count() <> 2 then
+ Error('');
+ end;
+
+ local procedure GetVolumeTypeName(VolumeType: Enum "Shpfy Metafield Volume Type"): Text
+ begin
+ exit(VolumeType.Names().Get(VolumeType.Ordinals().IndexOf(VolumeType.AsInteger())));
+ end;
+
+ local procedure ConvertToVolumeType(Value: Text) Type: Enum "Shpfy Metafield Volume Type"
+ begin
+ exit(Enum::"Shpfy Metafield Volume Type".FromInteger(Type.Ordinals().Get(Type.Names().IndexOf(Value))));
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeWeight.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeWeight.Codeunit.al
new file mode 100644
index 0000000000..5bf2777206
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IMetafieldType/ShpfyMtfldTypeWeight.Codeunit.al
@@ -0,0 +1,72 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30326 "Shpfy Mtfld Type Weight" implements "Shpfy IMetafield Type"
+{
+ var
+ WeightJsonTemplateTxt: Label '{"value": %1,"unit":"%2"}', Locked = true;
+
+ procedure HasAssistEdit(): Boolean
+ begin
+ exit(true);
+ end;
+
+ procedure IsValidValue(Value: Text): Boolean
+ var
+ Weight: Decimal;
+ Unit: Enum "Shpfy Metafield Weight Type";
+ begin
+ exit(TryExtractValues(Value, Weight, Unit));
+ end;
+
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+ var
+ MetafieldAssistEdit: Page "Shpfy Metafield Assist Edit";
+ Weight: Decimal;
+ Unit: Enum "Shpfy Metafield Weight Type";
+ begin
+ if Value <> '' then
+ if not TryExtractValues(Value, Weight, Unit) then begin
+ Clear(Weight);
+ Clear(Unit);
+ end;
+
+ if MetafieldAssistEdit.OpenForWeight(Weight, Unit) then begin
+ MetafieldAssistEdit.GetWeightValue(Weight, Unit);
+ Value := StrSubstNo(WeightJsonTemplateTxt, Format(Weight, 0, 9), GetWeightTypeName(Unit));
+ exit(true);
+ end else
+ exit(false);
+ end;
+
+ procedure GetExampleValue(): Text
+ begin
+ exit(StrSubstNo(WeightJsonTemplateTxt, '2.5', 'kg'));
+ end;
+
+
+ [TryFunction]
+ local procedure TryExtractValues(Value: Text; var Weight: Decimal; var Unit: Enum "Shpfy Metafield Weight Type")
+ var
+ JToken: JsonToken;
+ JObject: JsonObject;
+ begin
+ JObject.ReadFrom(Value);
+ JObject.SelectToken('value', JToken);
+ Weight := JToken.AsValue().AsDecimal();
+ JObject.SelectToken('unit', JToken);
+ Unit := ConvertToWeightType(JToken.AsValue().AsText());
+
+ if JObject.Keys.Count() <> 2 then
+ Error('');
+ end;
+
+ local procedure GetWeightTypeName(WeightType: Enum "Shpfy Metafield Weight Type"): Text
+ begin
+ exit(WeightType.Names().Get(WeightType.Ordinals().IndexOf(WeightType.AsInteger())));
+ end;
+
+ local procedure ConvertToWeightType(Value: Text) Type: Enum "Shpfy Metafield Weight Type"
+ begin
+ exit(Enum::"Shpfy Metafield Weight Type".FromInteger(Type.Ordinals().Get(Type.Names().IndexOf(Value))));
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerCustomer.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerCustomer.Codeunit.al
new file mode 100644
index 0000000000..98646f1731
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerCustomer.Codeunit.al
@@ -0,0 +1,19 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30333 "Shpfy Metafield Owner Customer" implements "Shpfy IMetafield Owner Type"
+{
+ procedure GetTableId(): Integer
+ begin
+ exit(Database::"Shpfy Customer");
+ end;
+
+ procedure RetrieveMetafieldIdsFromShopify(OwnerId: BigInteger): Dictionary of [BigInteger, DateTime]
+ begin
+ Error('Not implemented');
+ end;
+
+ procedure GetShopCode(OwnerId: BigInteger): Code[20]
+ begin
+ exit('Not implemented');
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerProduct.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerProduct.Codeunit.al
new file mode 100644
index 0000000000..3998b83f29
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerProduct.Codeunit.al
@@ -0,0 +1,42 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30334 "Shpfy Metafield Owner Product" implements "Shpfy IMetafield Owner Type"
+{
+ procedure GetTableId(): Integer
+ begin
+ exit(Database::"Shpfy Product");
+ end;
+
+ procedure RetrieveMetafieldIdsFromShopify(OwnerId: BigInteger) MetafieldIds: Dictionary of [BigInteger, DateTime]
+ var
+ CommunicationMgt: Codeunit "Shpfy Communication Mgt.";
+ JsonHelper: Codeunit "Shpfy Json Helper";
+ Parameters: Dictionary of [Text, Text];
+ GraphQLType: Enum "Shpfy GraphQL Type";
+ JResponse: JsonToken;
+ JMetafields: JsonArray;
+ JNode: JsonObject;
+ JItem: JsonToken;
+ Id: BigInteger;
+ UpdatedAt: DateTime;
+ begin
+ Parameters.Add('ProductId', Format(OwnerId));
+ GraphQLType := GraphQLType::ProductMetafieldIds;
+ JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType, Parameters);
+ if JsonHelper.GetJsonArray(JResponse, JMetafields, 'data.product.metafields.edges') then
+ foreach JItem in JMetafields do
+ if JsonHelper.GetJsonObject(JItem.AsObject(), JNode, 'node') then begin
+ Id := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'legacyResourceId'));
+ UpdatedAt := JsonHelper.GetValueAsDateTime(JNode, 'updatedAt');
+ MetafieldIds.Add(Id, UpdatedAt);
+ end;
+ end;
+
+ procedure GetShopCode(OwnerId: BigInteger): Code[20]
+ var
+ Product: Record "Shpfy Product";
+ begin
+ Product.Get(OwnerId);
+ exit(Product."Shop Code");
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerVariant.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerVariant.Codeunit.al
new file mode 100644
index 0000000000..3a9ff1e4b0
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/IOwnerType/ShpfyMetafieldOwnerVariant.Codeunit.al
@@ -0,0 +1,42 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30335 "Shpfy Metafield Owner Variant" implements "Shpfy IMetafield Owner Type"
+{
+ procedure GetTableId(): Integer
+ begin
+ exit(Database::"Shpfy Variant");
+ end;
+
+ procedure RetrieveMetafieldIdsFromShopify(OwnerId: BigInteger) MetafieldIds: Dictionary of [BigInteger, DateTime]
+ var
+ CommunicationMgt: Codeunit "Shpfy Communication Mgt.";
+ JsonHelper: Codeunit "Shpfy Json Helper";
+ Parameters: Dictionary of [Text, Text];
+ GraphQLType: Enum "Shpfy GraphQL Type";
+ JResponse: JsonToken;
+ JMetafields: JsonArray;
+ JNode: JsonObject;
+ JItem: JsonToken;
+ Id: BigInteger;
+ UpdatedAt: DateTime;
+ begin
+ Parameters.Add('VariantId', Format(OwnerId));
+ GraphQLType := GraphQLType::VariantMetafieldIds;
+ JResponse := CommunicationMgt.ExecuteGraphQL(GraphQLType, Parameters);
+ if JsonHelper.GetJsonArray(JResponse, JMetafields, 'data.product.metafields.edges') then
+ foreach JItem in JMetafields do
+ if JsonHelper.GetJsonObject(JItem.AsObject(), JNode, 'node') then begin
+ Id := CommunicationMgt.GetIdOfGId(JsonHelper.GetValueAsText(JNode, 'legacyResourceId'));
+ UpdatedAt := JsonHelper.GetValueAsDateTime(JNode, 'updatedAt');
+ MetafieldIds.Add(Id, UpdatedAt);
+ end;
+ end;
+
+ procedure GetShopCode(OwnerId: BigInteger): Code[20]
+ var
+ Variant: Record "Shpfy Variant";
+ begin
+ Variant.Get(OwnerId);
+ exit(Variant."Shop Code");
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Codeunits/ShpfyMetafieldAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Metafields/Codeunits/ShpfyMetafieldAPI.Codeunit.al
new file mode 100644
index 0000000000..bd3ba3ad8d
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Codeunits/ShpfyMetafieldAPI.Codeunit.al
@@ -0,0 +1,237 @@
+namespace Microsoft.Integration.Shopify;
+
+codeunit 30316 "Shpfy Metafield API"
+{
+ Access = Internal;
+
+ var
+ JsonHelper: Codeunit "Shpfy Json Helper";
+
+ #region To Shopify
+ ///
+ /// Creates or updates the metafields in Shopify.
+ ///
+ ///
+ /// Only metafields that have been updated in BC since last update in Shopify will be updated.
+ /// MetafieldSet mutation only accepts 25 metafields at a time, so the function will create multiple queries if needed.
+ ///
+ ///
+ ///
+ internal procedure CreateOrUpdateMetafieldsInShopify(ParentTableId: Integer; OwnerId: BigInteger)
+ var
+ TempMetafieldSet: Record "Shpfy Metafield" temporary;
+ MetafieldIds: Dictionary of [BigInteger, DateTime];
+ Continue: Boolean;
+ Count: Integer;
+ GraphQuery: TextBuilder;
+ begin
+ MetafieldIds := RetrieveMetafieldsFromShopify(ParentTableId, OwnerId);
+ CollectMetafieldsInBC(ParentTableId, OwnerId, TempMetafieldSet, MetafieldIds);
+
+ // MetafieldsSet mutation only accepts 25 metafields at a time
+ Continue := true;
+ if TempMetafieldSet.FindSet() then
+ while Continue do begin
+ Count := 0;
+ Continue := false;
+ GraphQuery.Clear();
+
+ repeat
+ if Count = GetMaxMetafieldsToUpdate() then begin
+ Continue := true;
+ Clear(Count);
+ break;
+ end;
+
+ CreateMetafieldQuery(TempMetafieldSet, GraphQuery);
+ Count += 1;
+ until TempMetafieldSet.Next() = 0;
+
+ UpdateMetafields(GraphQuery.ToText());
+ end;
+ end;
+
+ local procedure GetMaxMetafieldsToUpdate(): Integer
+ begin
+ exit(25);
+ end;
+
+ local procedure RetrieveMetafieldsFromShopify(ParentTableId: Integer; OwnerId: BigInteger): Dictionary of [BigInteger, DateTime]
+ var
+ Metafield: Record "Shpfy Metafield";
+ IMetafieldOwnerType: Interface "Shpfy IMetafield Owner Type";
+ begin
+ IMetafieldOwnerType := Metafield.GetOwnerType(ParentTableId);
+ exit(IMetafieldOwnerType.RetrieveMetafieldIdsFromShopify(OwnerId));
+ end;
+
+ local procedure CollectMetafieldsInBC(ParentTableId: Integer; OwnerId: BigInteger; var TempMetafieldSet: Record "Shpfy Metafield" temporary; MetafieldIds: Dictionary of [BigInteger, DateTime])
+ var
+ Metafield: Record "Shpfy Metafield";
+ UpdatedAt: DateTime;
+ begin
+ Metafield.SetRange("Parent Table No.", ParentTableId);
+ Metafield.SetRange("Owner Id", OwnerId);
+ if Metafield.FindSet() then
+ repeat
+ if MetafieldIds.Get(Metafield.Id, UpdatedAt) then begin
+ if Metafield."Last Updated by BC" > UpdatedAt then begin
+ TempMetafieldSet := Metafield;
+ TempMetafieldSet.Insert(false);
+ end;
+ end else begin
+ TempMetafieldSet := Metafield;
+ TempMetafieldSet.Insert(false);
+ end;
+ until Metafield.Next() = 0;
+ end;
+
+ ///
+ /// Updates the metafields in Shopify.
+ ///
+ /// GraphQL query for the metafields.
+ internal procedure UpdateMetafields(MetafieldsQuery: Text) JResponse: JsonToken
+ var
+ CommunicationMgt: Codeunit "Shpfy Communication Mgt.";
+ Parameters: Dictionary of [Text, Text];
+ begin
+ Parameters.Add('Metafields', MetafieldsQuery);
+ JResponse := CommunicationMgt.ExecuteGraphQL(Enum::"Shpfy GraphQL Type"::MetafieldSet, Parameters);
+ end;
+
+ ///
+ /// Creates a GraphQL query for a metafield.
+ ///
+ /// Metafield record to create the query for.
+ /// Return value: TextBuilder to append the query to.
+ internal procedure CreateMetafieldQuery(MetafieldSet: Record "Shpfy Metafield"; GraphQuery: TextBuilder)
+ begin
+ GraphQuery.Append('{');
+ GraphQuery.Append('key: \"');
+ GraphQuery.Append(MetafieldSet.Name);
+ GraphQuery.Append('\",');
+ GraphQuery.Append('namespace: \"');
+ GraphQuery.Append(MetafieldSet."Namespace");
+ GraphQuery.Append('\",');
+ GraphQuery.Append('ownerId: \"gid://shopify/');
+ GraphQuery.Append(MetafieldSet.GetOwnerTypeName());
+ GraphQuery.Append('/');
+ GraphQuery.Append(Format(MetafieldSet."Owner Id"));
+ GraphQuery.Append('\",');
+ GraphQuery.Append('value: \"');
+ GraphQuery.Append(EscapeGrapQLData(MetafieldSet.Value));
+ GraphQuery.Append('\",');
+ GraphQuery.Append('type: \"');
+ GraphQuery.Append(GetTypeName(MetafieldSet.Type));
+ GraphQuery.Append('\"');
+ GraphQuery.Append('},');
+ end;
+
+ local procedure EscapeGrapQLData(Data: Text): Text
+ begin
+ exit(Data.Replace('\', '\\\\').Replace('"', '\\\"'));
+ end;
+
+ local procedure GetTypeName(Type: Enum "Shpfy Metafield Type"): Text
+ begin
+ exit(Enum::"Shpfy Metafield Type".Names().Get(Enum::"Shpfy Metafield Type".Ordinals().IndexOf(Type.AsInteger())));
+ end;
+ #endregion
+
+ #region From Shopify
+ ///
+ /// Updates the metafields in Business Central from Shopify.
+ ///
+ ///
+ /// Metafields with a value longer than 2048 characters will not be imported.
+ /// Some metafield types are unsupported in Business Central (i.e. Rating).
+ ///
+ /// JSON array of metafields from Shopify.
+ /// Table id of the parent resource.
+ /// Id of the parent resource.
+ internal procedure UpdateMetafieldsFromShopify(JMetafields: JsonArray; ParentTableNo: Integer; OwnerId: BigInteger)
+ var
+ JNode: JsonObject;
+ JItem: JsonToken;
+ MetafieldIds: List of [BigInteger];
+ MetafieldId: BigInteger;
+ begin
+ CollectMetafieldIds(OwnerId, MetafieldIds);
+
+ foreach JItem in JMetafields do begin
+ JsonHelper.GetJsonObject(JItem.AsObject(), JNode, 'node');
+ MetafieldId := UpdateMetadataField(ParentTableNo, OwnerId, JNode);
+ MetafieldIds.Remove(MetafieldId);
+ end;
+
+ DeleteUnusedMetafields(MetafieldIds);
+ end;
+
+ local procedure UpdateMetadataField(ParentTableNo: Integer; OwnerId: BigInteger; JNode: JsonObject): BigInteger
+ var
+ Metafield: Record "Shpfy Metafield";
+ ValueText: Text;
+ Type: Enum "Shpfy Metafield Type";
+ begin
+ // Shopify has no limit on the length of the value, but Business Central has a limit of 2048 characters.
+ // If the value is longer than 2048 characters, Metafield is not imported.
+ ValueText := JsonHelper.GetValueAsText(JNode, 'value');
+ if StrLen(ValueText) > MaxStrLen(Metafield.Value) then
+ exit(0);
+
+ // Some metafield types are unsupported in Business Central (i.e. Rating)
+ if not ConvertToMetafieldType(JsonHelper.GetValueAsText(JNode, 'type'), Type) then
+ exit(0);
+
+
+ Metafield.Validate("Parent Table No.", ParentTableNo);
+ Metafield."Owner Id" := OwnerId;
+ Metafield.Id := JsonHelper.GetValueAsBigInteger(JNode, 'legacyResourceId');
+ Metafield.Type := Type;
+#pragma warning disable AA0139
+ Metafield."Namespace" := JsonHelper.GetValueAsText(JNode, 'namespace');
+ Metafield.Name := JsonHelper.GetValueAsText(JNode, 'key');
+ Metafield.Value := ValueText;
+#pragma warning restore AA0139
+ if not Metafield.Modify(false) then
+ Metafield.Insert(false);
+
+ exit(Metafield.Id);
+ end;
+
+ local procedure ConvertToMetafieldType(Value: Text; var Type: Enum "Shpfy Metafield Type"): Boolean
+ var
+ EnumOrdinal: Integer;
+ begin
+ // Some metafield types are unsupported in Business Central (i.e. Rating)
+ if not Enum::"Shpfy Metafield Type".Ordinals().Get(Enum::"Shpfy Metafield Type".Names().IndexOf(Value), EnumOrdinal) then
+ exit(false);
+
+ Type := Enum::"Shpfy Metafield Type".FromInteger(EnumOrdinal);
+ exit(true);
+ end;
+
+ local procedure CollectMetafieldIds(ProductId: BigInteger; MetafieldIds: List of [BigInteger])
+ var
+ Metafield: Record "Shpfy Metafield";
+ begin
+ MetaField.SetRange("Parent Table No.", Database::"Shpfy Product");
+ Metafield.SetRange("Owner Id", ProductId);
+ if Metafield.FindSet() then
+ repeat
+ MetafieldIds.Add(Metafield.Id);
+ until Metafield.Next() = 0;
+ end;
+
+ local procedure DeleteUnusedMetafields(MetafieldIds: List of [BigInteger])
+ var
+ Metafield: Record "Shpfy Metafield";
+ MetafieldId: BigInteger;
+ begin
+ foreach MetafieldId in MetafieldIds do begin
+ Metafield.Get(MetafieldId);
+ Metafield.Delete(false);
+ end;
+ end;
+ #endregion
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldDimensionType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldDimensionType.Enum.al
new file mode 100644
index 0000000000..1c3c72cb46
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldDimensionType.Enum.al
@@ -0,0 +1,35 @@
+namespace Microsoft.Integration.Shopify;
+
+enum 30160 "Shpfy Metafield Dimension Type"
+{
+ Access = Internal;
+
+ value(0; in)
+ {
+ Caption = 'in';
+ }
+
+ value(1; ft)
+ {
+ Caption = 'ft';
+ }
+
+ value(2; yd)
+ {
+ Caption = 'yd';
+ }
+ value(3; mm)
+ {
+ Caption = 'mm';
+ }
+
+ value(4; cm)
+ {
+ Caption = 'cm';
+ }
+
+ value(5; m)
+ {
+ Caption = 'm';
+ }
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldOwnerType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldOwnerType.Enum.al
new file mode 100644
index 0000000000..71d42d21c1
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldOwnerType.Enum.al
@@ -0,0 +1,24 @@
+namespace Microsoft.Integration.Shopify;
+
+enum 30156 "Shpfy Metafield Owner Type" implements "Shpfy IMetafield Owner Type"
+{
+ Access = Internal;
+
+ value(0; Customer)
+ {
+ Caption = 'Customer';
+ Implementation = "Shpfy IMetafield Owner Type" = "Shpfy Metafield Owner Customer";
+ }
+
+ value(1; Product)
+ {
+ Caption = 'Product';
+ Implementation = "Shpfy IMetafield Owner Type" = "Shpfy Metafield Owner Product";
+ }
+
+ value(2; ProductVariant)
+ {
+ Caption = 'Variant';
+ Implementation = "Shpfy IMetafield Owner Type" = "Shpfy Metafield Owner Variant";
+ }
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldType.Enum.al
new file mode 100644
index 0000000000..b4c21fb5b4
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldType.Enum.al
@@ -0,0 +1,161 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Enum Shpfy Metafield Type (ID 30159).
+///
+enum 30159 "Shpfy Metafield Type" implements "Shpfy IMetafield Type"
+{
+ Access = Internal;
+ Caption = 'Shopify Metafield Type';
+
+ Extensible = false;
+
+ value(0; string)
+ {
+ Caption = 'String';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type String";
+ }
+
+ value(1; integer)
+ {
+ Caption = 'Integer';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Integer";
+ }
+
+ value(2; json)
+ {
+ Caption = 'JSON';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type JSON";
+ }
+
+ value(3; boolean)
+ {
+ Caption = 'True or false';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Boolean";
+ }
+
+ value(4; color)
+ {
+ Caption = 'Color';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Color";
+ }
+
+ value(5; date)
+ {
+ Caption = 'Date';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Date";
+ }
+
+ value(6; date_time)
+ {
+ Caption = 'Date and time';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type DateTime";
+ }
+
+ value(7; dimension)
+ {
+ Caption = 'Dimension';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Dimension";
+ }
+
+ value(8; money)
+ {
+ Caption = 'Money';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Money";
+ }
+
+ value(9; multi_line_text_field)
+ {
+ Caption = 'Multi-line text';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Multi Text";
+ }
+
+ value(10; number_decimal)
+ {
+ Caption = 'Decimal';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Num Decimal";
+ }
+
+ value(11; number_integer)
+ {
+ Caption = 'Integer';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Num Integer";
+ }
+
+ // Intentionally commented out as we are not supporting this type at the moment
+ // value(12; rating)
+ // {
+ // Caption = 'Rating';
+ // }
+
+ // Intentionally commented out as we are not supporting this type at the moment
+ // value(13; rich_text_field)
+ // {
+ // Caption = 'Rich text';
+ // }
+
+ value(14; single_line_text_field)
+ {
+ Caption = 'Single line text';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Single Text";
+ }
+
+ value(15; url)
+ {
+ Caption = 'URL';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type URL";
+ }
+
+ value(16; volume)
+ {
+ Caption = 'Volume';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Volume";
+ }
+
+ value(17; weight)
+ {
+ Caption = 'Weight';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Weight";
+ }
+ value(18; collection_reference)
+ {
+ Caption = 'Collection reference';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Collect. Ref";
+ }
+
+ value(19; file_reference)
+ {
+ Caption = 'File';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type File Ref";
+ }
+
+ value(20; metaobject_reference)
+ {
+ Caption = 'Metaobject';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Metaobj. Ref";
+ }
+
+ value(21; mixed_reference)
+ {
+ Caption = 'Mixed reference';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Mixed Ref";
+ }
+
+ value(22; page_reference)
+ {
+ Caption = 'Page';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Page Ref";
+ }
+
+ value(23; product_reference)
+ {
+ Caption = 'Product';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Product Ref";
+ }
+
+ value(24; variant_reference)
+ {
+ Caption = 'Variant';
+ Implementation = "Shpfy IMetafield Type" = "Shpfy Mtfld Type Variant Ref";
+ }
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Base/Enums/ShpfyMetafieldValueType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldValueType.Enum.al
similarity index 75%
rename from Apps/W1/Shopify/app/src/Base/Enums/ShpfyMetafieldValueType.Enum.al
rename to Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldValueType.Enum.al
index dc3bb8acd4..fcf76e44aa 100644
--- a/Apps/W1/Shopify/app/src/Base/Enums/ShpfyMetafieldValueType.Enum.al
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldValueType.Enum.al
@@ -8,6 +8,9 @@ enum 30102 "Shpfy Metafield Value Type"
Access = Internal;
Caption = 'Shopify Metafield Value Type';
Extensible = false;
+ ObsoleteState = Pending;
+ ObsoleteReason = 'Value Type is obsolete in Shopify API. Use Metafield Type instead.';
+ ObsoleteTag = '25.0';
value(0; String)
{
diff --git a/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldVolumeType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldVolumeType.Enum.al
new file mode 100644
index 0000000000..c1b87eb4ea
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldVolumeType.Enum.al
@@ -0,0 +1,59 @@
+namespace Microsoft.Integration.Shopify;
+
+enum 30158 "Shpfy Metafield Volume Type"
+{
+ Access = Internal;
+
+ value(0; ml)
+ {
+ Caption = 'ml';
+ }
+
+ value(1; cl)
+ {
+ Caption = 'cl';
+ }
+
+ value(2; l)
+ {
+ Caption = 'L';
+ }
+ value(3; m3)
+ {
+ Caption = 'm3';
+ }
+
+ value(4; us_fl_oz)
+ {
+ Caption = 'fl oz';
+ }
+
+ value(5; us_pt)
+ {
+ Caption = 'pt';
+ }
+ value(6; us_qt)
+ {
+ Caption = 'qt';
+ }
+ value(7; us_gal)
+ {
+ Caption = 'gal';
+ }
+ value(8; imp_fl_oz)
+ {
+ Caption = 'imp fl oz';
+ }
+ value(9; imp_pt)
+ {
+ Caption = 'imp pt';
+ }
+ value(10; imp_qt)
+ {
+ Caption = 'imp qt';
+ }
+ value(11; imp_gal)
+ {
+ Caption = 'imp gal';
+ }
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldWeightType.Enum.al b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldWeightType.Enum.al
new file mode 100644
index 0000000000..2581e24b3a
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Enums/ShpfyMetafieldWeightType.Enum.al
@@ -0,0 +1,26 @@
+namespace Microsoft.Integration.Shopify;
+
+enum 30157 "Shpfy Metafield Weight Type"
+{
+ Access = Internal;
+
+ value(0; kg)
+ {
+ Caption = 'kg';
+ }
+
+ value(1; g)
+ {
+ Caption = 'g';
+ }
+
+ value(2; lb)
+ {
+ Caption = 'lb';
+ }
+
+ value(3; oz)
+ {
+ Caption = 'oz';
+ }
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldOwnerType.Interface.al b/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldOwnerType.Interface.al
new file mode 100644
index 0000000000..f11f3540f7
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldOwnerType.Interface.al
@@ -0,0 +1,29 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Interface used to for metafield operations related to metafield owner resource.
+///
+interface "Shpfy IMetafield Owner Type"
+{
+ Access = Internal;
+
+ ///
+ /// Returns the table id where the owner record is stored in BC.
+ ///
+ /// Table id.
+ procedure GetTableId(): Integer
+
+ ///
+ /// Retrieves metafields belonging to the owner resource in a dictionary with the last updated at timestamp.
+ ///
+ /// Id of the owner resource.
+ /// Dictionary of metafield ids and last updated at timestamp.
+ procedure RetrieveMetafieldIdsFromShopify(OwnerId: BigInteger): Dictionary of [BigInteger, DateTime]
+
+ ///
+ /// Retrieves the shop code from the owner resource.
+ ///
+ /// Id of the owner resource.
+ /// Shop code.
+ procedure GetShopCode(OwnerId: BigInteger): Code[20]
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldType.Interface.al b/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldType.Interface.al
new file mode 100644
index 0000000000..47dc65200d
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Interfaces/ShpfyIMetafieldType.Interface.al
@@ -0,0 +1,35 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Interface used for validating and editing values of a Shopify Metafield.
+///
+interface "Shpfy IMetafield Type"
+{
+ Access = Internal;
+
+ ///
+ /// Determines if Type defines an Assist Edit dialog.
+ ///
+ /// True if Type defines an Assist Edit dialog, otherwise false.
+ procedure HasAssistEdit(): Boolean
+
+ ///
+ /// Determines if provided value is valid for Type.
+ ///
+ /// Value to validate.
+ /// True if value is valid, otherwise False.
+ procedure IsValidValue(Value: Text): Boolean
+
+ ///
+ /// Opens a dialog to assist in editing the value.
+ ///
+ /// Value to edit. Value may be modified.
+ /// True if value was edited, otherwise False.
+ procedure AssistEdit(var Value: Text[2048]): Boolean
+
+ ///
+ /// Returns an example value for the Type.
+ ///
+ /// Example value.
+ procedure GetExampleValue(): Text
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafieldAssistEdit.Page.al b/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafieldAssistEdit.Page.al
new file mode 100644
index 0000000000..623fcd5ffc
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafieldAssistEdit.Page.al
@@ -0,0 +1,264 @@
+namespace Microsoft.Integration.Shopify;
+
+using Microsoft.Finance.Currency;
+
+page 30164 "Shpfy Metafield Assist Edit"
+{
+ Caption = 'Metafield Assist Edit';
+ PageType = StandardDialog;
+ ApplicationArea = All;
+ UsageCategory = Administration;
+
+ layout
+ {
+ area(Content)
+ {
+ group(MoneyGroup)
+ {
+ Visible = IsMoneyVisible;
+ ShowCaption = false;
+
+ field(MoneyValue; MoneyValue)
+ {
+ Caption = 'Value';
+ ToolTip = 'Enter the amount.';
+ }
+ field(MoneyCurrency; MoneyCurrency)
+ {
+ Caption = 'Currency';
+ ToolTip = 'Enter the currency code.';
+ TableRelation = Currency;
+ }
+ }
+ group(DimensionGroup)
+ {
+ Visible = IsDimensionVisible;
+ ShowCaption = false;
+
+ field(DimensionValue; DimensionValue)
+ {
+ Caption = 'Value';
+ ToolTip = 'Enter the value.';
+ }
+ field(DimensionUnit; DimensionUnit)
+ {
+ Caption = 'Unit';
+ ToolTip = 'Enter the unit of measure.';
+ }
+ }
+ group(VolumeGroup)
+ {
+ Visible = IsVolumeVisible;
+ ShowCaption = false;
+
+ field(VolumeValue; VolumeValue)
+ {
+ Caption = 'Value';
+ ToolTip = 'Enter the value.';
+ }
+ field(VolumeUnit; VolumeUnit)
+ {
+ Caption = 'Unit';
+ ToolTip = 'Enter the unit of measure.';
+ }
+ }
+ group(WeightGroup)
+ {
+ Visible = IsWeightVisible;
+ ShowCaption = false;
+
+ field(WeightValue; WeightValue)
+ {
+ Caption = 'Value';
+ ToolTip = 'Enter the value.';
+ }
+ field(WeightUnit; WeightUnit)
+ {
+ Caption = 'Unit';
+ ToolTip = 'Enter the unit of measure.';
+ }
+ }
+ group(MultiLineTextGroup)
+ {
+ Visible = IsMultiLineTextVisible;
+ ShowCaption = false;
+
+ field(MultiLineText; MultiLineText)
+ {
+ Caption = 'Text';
+ ToolTip = 'Enter the text.';
+ MultiLine = true;
+ ExtendedDatatype = RichContent;
+
+ trigger OnValidate()
+ var
+ TextTooLongErr: Label 'The text is too long. The maximum length is 2048 characters.';
+ begin
+ if StrLen(MultiLineText) > 2048 then
+ Error(ErrorInfo.Create(TextTooLongErr));
+ end;
+ }
+ }
+ }
+ }
+
+ #region Money
+ var
+ IsMoneyVisible: Boolean;
+ MoneyValue: Decimal;
+ MoneyCurrency: Code[10];
+
+ ///
+ /// Opens the page for assisting with input of money values.
+ ///
+ /// The amount to preset on the page.
+ /// The currency code to preset on the page.
+ /// True if the user clicks OK; otherwise, false.
+ internal procedure OpenForMoney(Amount: Decimal; CurrencyCode: Code[10]): Boolean
+ begin
+ IsMoneyVisible := true;
+ MoneyValue := Amount;
+ MoneyCurrency := CurrencyCode;
+
+ exit(CurrPage.RunModal() = Action::OK);
+ end;
+
+ ///
+ /// Gets the money value and currency code.
+ ///
+ /// Return value: The money value.
+ /// Return value: The currency code.
+ internal procedure GetMoneyValue(var Amount: Decimal; var Currency: Code[10])
+ begin
+ Amount := MoneyValue;
+ Currency := MoneyCurrency;
+ end;
+ #endregion
+
+ #region Dimension
+ var
+ IsDimensionVisible: Boolean;
+ DimensionValue: Decimal;
+ DimensionUnit: Enum "Shpfy Metafield Dimension Type";
+
+ ///
+ /// Opens the page for assisting with input of dimension values.
+ ///
+ /// The dimension to preset on the page.
+ /// The unit of measure to preset on the page.
+ /// True if the user clicks OK; otherwise, false.
+ internal procedure OpenForDimension(Dimension: Decimal; Unit: Enum "Shpfy Metafield Dimension Type"): Boolean
+ begin
+ IsDimensionVisible := true;
+ DimensionValue := Dimension;
+ DimensionUnit := Unit;
+
+ exit(CurrPage.RunModal() = Action::OK);
+ end;
+
+ ///
+ /// Gets the dimension value and unit of measure.
+ ///
+ /// Return value: The dimension value.
+ /// Return value: The unit of measure.
+ internal procedure GetDimensionValue(var Value: Decimal; var Unit: Enum "Shpfy Metafield Dimension Type")
+ begin
+ Value := DimensionValue;
+ Unit := DimensionUnit;
+ end;
+ #endregion
+
+ #region Volume
+ var
+ IsVolumeVisible: Boolean;
+ VolumeValue: Decimal;
+ VolumeUnit: Enum "Shpfy Metafield Volume Type";
+
+ ///
+ /// Opens the page for assisting with input of volume values.
+ ///
+ /// The volume to preset on the page.
+ /// The unit of measure to preset on the page.
+ /// True if the user clicks OK; otherwise, false.
+ internal procedure OpenForVolume(Volume: Decimal; Unit: Enum "Shpfy Metafield Volume Type"): Boolean
+ begin
+ IsVolumeVisible := true;
+ VolumeValue := Volume;
+ VolumeUnit := Unit;
+
+ exit(CurrPage.RunModal() = Action::OK);
+ end;
+
+ ///
+ /// Gets the volume value and unit of measure.
+ ///
+ /// Return value: The volume value.
+ /// Return value: The unit of measure.
+ internal procedure GetVolumeValue(var Volume: Decimal; var Unit: Enum "Shpfy Metafield Volume Type")
+ begin
+ Volume := VolumeValue;
+ Unit := VolumeUnit;
+ end;
+ #endregion
+
+ #region Weight
+ var
+ IsWeightVisible: Boolean;
+ WeightValue: Decimal;
+ WeightUnit: Enum "Shpfy Metafield Weight Type";
+
+ ///
+ /// Opens the page for assisting with input of weight values.
+ ///
+ /// The weight to preset on the page.
+ /// The unit of measure to preset on the page.
+ /// True if the user clicks OK; otherwise, false.
+ internal procedure OpenForWeight(Weight: Decimal; Unit: Enum "Shpfy Metafield Weight Type"): Boolean
+ begin
+ IsWeightVisible := true;
+ WeightValue := Weight;
+ WeightUnit := Unit;
+
+ exit(CurrPage.RunModal() = Action::OK);
+ end;
+
+ ///
+ /// Gets the weight value and unit of measure.
+ ///
+ /// Return value: The weight value.
+ /// Return value: The unit of measure.
+ internal procedure GetWeightValue(var Value: Decimal; var Unit: Enum "Shpfy Metafield Weight Type")
+ begin
+ Value := WeightValue;
+ Unit := WeightUnit;
+ end;
+ #endregion
+
+ #region MultiLineText
+ var
+ IsMultiLineTextVisible: Boolean;
+ MultiLineText: Text;
+
+ ///
+ /// Opens the page for assisting with input of multi-line text.
+ ///
+ /// The text to preset on the page.
+ /// True if the user clicks OK; otherwise, false.
+ internal procedure OpenForMultiLineText(Text: Text[2048]): Boolean
+ begin
+ IsMultiLineTextVisible := true;
+ MultiLineText := Text;
+
+ exit(CurrPage.RunModal() = Action::OK);
+ end;
+
+ ///
+ /// Gets the multi-line text.
+ ///
+ /// Return value: The multi-line text.
+ internal procedure GetMultiLineText(var Text: Text[2048])
+ begin
+ Text := CopyStr(MultiLineText, 1, MaxStrLen(Text));
+ end;
+ #endregion
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafields.Page.al b/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafields.Page.al
new file mode 100644
index 0000000000..2029380a48
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Pages/ShpfyMetafields.Page.al
@@ -0,0 +1,130 @@
+namespace Microsoft.Integration.Shopify;
+
+///
+/// Page Shpfy Metafields (ID 30163).
+///
+page 30163 "Shpfy Metafields"
+{
+ Caption = 'Shopify Metafields';
+ Extensible = false;
+ PageType = List;
+ SourceTable = "Shpfy Metafield";
+ UsageCategory = None;
+ ApplicationArea = All;
+ DelayedInsert = true;
+
+ layout
+ {
+ area(Content)
+ {
+ repeater(Metafields)
+ {
+ Editable = IsPageEditable;
+
+ field(Namespace; Rec.Namespace)
+ {
+ ToolTip = 'Specifies the namespace of the metafield.';
+ }
+ field(Type; Rec.Type)
+ {
+ ToolTip = 'Specifies the type of value for the metafield.';
+ }
+ field(Name; Rec.Name)
+ {
+ ToolTip = 'Specifies the key of the metafield.';
+ }
+ field(Value; Rec.Value)
+ {
+ ToolTip = 'Specifies the value of the metafield.';
+ Editable = IsValueEditable;
+
+ trigger OnAssistEdit()
+ var
+ IMetafieldType: Interface "Shpfy IMetafield Type";
+ begin
+ IMetafieldType := Rec.Type;
+
+ if IMetafieldType.HasAssistEdit() then
+ if IMetafieldType.AssistEdit(Rec.Value) then
+ Rec.Validate(Value);
+ end;
+ }
+ }
+ }
+ }
+
+ trigger OnNewRecord(BelowxRec: Boolean)
+ begin
+ Evaluate(Rec."Parent Table No.", Rec.GetFilter("Parent Table No."));
+ Rec.Validate("Parent Table No.");
+ Evaluate(Rec."Owner Id", Rec.GetFilter("Owner Id"));
+ end;
+
+ trigger OnAfterGetCurrRecord()
+ var
+ IMetafieldType: Interface "Shpfy IMetafield Type";
+ begin
+ IMetafieldType := Rec.Type;
+ IsValueEditable := not IMetafieldType.HasAssistEdit();
+ end;
+
+ trigger OnInsertRecord(BelowxRec: Boolean): Boolean
+ begin
+ Rec.TestField(Namespace);
+ Rec.TestField(Name);
+ Rec.Validate(Value);
+
+ Rec.Id := SendMetafieldToShopify();
+ end;
+
+ var
+ Shop: Record "Shpfy Shop";
+ IsPageEditable: Boolean;
+ IsValueEditable: Boolean;
+
+ ///
+ /// Opens the page displaying metafields for the specified resource.
+ ///
+ /// Table id of the resource.
+ /// System Id of the resource.
+ internal procedure RunForResource(ParentTableId: Integer; OwnerId: BigInteger; ShopCode: Code[20])
+ var
+ Metafield: Record "Shpfy Metafield";
+ begin
+ Shop.Get(ShopCode);
+ IsPageEditable := (Shop."Sync Item" = Shop."Sync Item"::"To Shopify") and (Shop."Can Update Shopify Products");
+
+ Metafield.SetRange("Parent Table No.", ParentTableId);
+ Metafield.SetRange("Owner Id", OwnerId);
+
+ CurrPage.SetTableView(Metafield);
+ CurrPage.RunModal();
+ end;
+
+ local procedure SendMetafieldToShopify(): BigInteger
+ var
+ JsonHelper: Codeunit "Shpfy Json Helper";
+ MetafieldAPI: Codeunit "Shpfy Metafield API";
+ ShpfyCommunicationMgt: Codeunit "Shpfy Communication Mgt.";
+ UserErrorOnShopifyErr: Label 'Something went wrong while sending the metafield to Shopify. Check Shopify Log Entries for more details.';
+ GraphQuery: TextBuilder;
+ JResponse: JsonToken;
+ JMetafields: JsonArray;
+ JUserErrors: JsonArray;
+ JItem: JsonToken;
+ begin
+ ShpfyCommunicationMgt.SetShop(Shop);
+
+ MetafieldAPI.CreateMetafieldQuery(Rec, GraphQuery);
+ JResponse := MetafieldAPI.UpdateMetafields(GraphQuery.ToText());
+
+ JsonHelper.GetJsonArray(JResponse, JUserErrors, 'data.metafieldsSet.userErrors');
+
+ if JUserErrors.Count() = 0 then begin
+ JsonHelper.GetJsonArray(JResponse, JMetafields, 'data.metafieldsSet.metafields');
+ JMetafields.Get(0, JItem);
+ exit(JsonHelper.GetValueAsBigInteger(JItem, 'legacyResourceId'));
+ end else
+ Error(UserErrorOnShopifyErr);
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Metafields/Tables/ShpfyMetafield.Table.al b/Apps/W1/Shopify/app/src/Metafields/Tables/ShpfyMetafield.Table.al
new file mode 100644
index 0000000000..6e7955daa8
--- /dev/null
+++ b/Apps/W1/Shopify/app/src/Metafields/Tables/ShpfyMetafield.Table.al
@@ -0,0 +1,219 @@
+namespace Microsoft.Integration.Shopify;
+
+using Microsoft.Finance.GeneralLedger.Setup;
+
+///
+/// Table Shpfy Metafield (ID 30101).
+///
+table 30101 "Shpfy Metafield"
+{
+ Access = Internal;
+ Caption = 'Shopify Metafield';
+ DataClassification = CustomerContent;
+ DrillDownPageId = "Shpfy Metafields";
+ LookupPageId = "Shpfy Metafields";
+
+ fields
+ {
+ field(1; Id; BigInteger)
+ {
+ Caption = 'Id';
+ DataClassification = SystemMetadata;
+ Editable = false;
+ }
+
+#pragma warning disable AS0086 // false positive on extending the field length on internal table
+ field(2; Namespace; Text[255])
+ {
+ Caption = 'Namespace';
+ DataClassification = SystemMetadata;
+ }
+#pragma warning restore AS0086
+
+ field(3; "Owner Resource"; Text[50])
+ {
+ Caption = 'Owner Resource';
+ DataClassification = SystemMetadata;
+ ObsoleteState = Pending;
+ ObsoleteReason = 'Owner Resource is obsolete. Use Owner Type instead.';
+ ObsoleteTag = '25.0';
+
+ trigger OnValidate()
+ begin
+ case "Owner Resource" of
+ 'Customer':
+ Validate("Owner Type", "Owner Type"::Customer);
+ 'Product':
+ Validate("Owner Type", "Owner Type"::Product);
+ 'Variant':
+ Validate("Owner Type", "Owner Type"::ProductVariant);
+ end;
+ end;
+ }
+
+ field(4; "Owner Id"; BigInteger)
+ {
+ Caption = 'Owner Id';
+ DataClassification = SystemMetadata;
+ }
+
+#pragma warning disable AS0086 // false positive on extending the field length on internal table
+ field(5; Name; Text[64])
+ {
+ Caption = 'Key';
+ DataClassification = CustomerContent;
+ }
+#pragma warning restore AS0086
+
+ field(6; "Value Type"; Enum "Shpfy Metafield Value Type")
+ {
+ Caption = 'Value Type';
+ DataClassification = CustomerContent;
+ ObsoleteState = Pending;
+ ObsoleteReason = 'Value Type is obsolete in Shopify API. Use Type instead.';
+ ObsoleteTag = '25.0';
+ }
+
+#pragma warning disable AS0086 // false positive on extending the field length on internal table
+ field(7; Value; Text[2048])
+ {
+ Caption = 'Value';
+ DataClassification = CustomerContent;
+
+ trigger OnValidate()
+ var
+ ValueNotValidErr: Label 'The value is not valid for the type. Example value: ';
+ IMetafieldType: Interface "Shpfy IMetafield Type";
+ begin
+ IMetafieldType := Rec.Type;
+ if not IMetafieldType.IsValidValue(Value) then
+ Error(ErrorInfo.Create(ValueNotValidErr + IMetafieldType.GetExampleValue()));
+
+ if Rec.Type = Rec.Type::money then
+ CheckShopCurrency(Value);
+ end;
+ }
+#pragma warning restore AS0086
+ field(8; Type; Enum "Shpfy Metafield Type")
+ {
+ Caption = 'Type';
+ DataClassification = CustomerContent;
+ }
+ field(9; "Last Updated by BC"; DateTime)
+ {
+ Caption = 'Last Updated by BC';
+ DataClassification = SystemMetadata;
+ }
+ field(10; "Owner Type"; Enum "Shpfy Metafield Owner Type")
+ {
+ Caption = 'Owner Type';
+ DataClassification = SystemMetadata;
+
+ trigger OnValidate()
+ var
+ IMetafieldOwnerType: Interface "Shpfy IMetafield Owner Type";
+ begin
+ IMetafieldOwnerType := Rec."Owner Type";
+ "Parent Table No." := IMetafieldOwnerType.GetTableId();
+ end;
+ }
+
+ field(101; "Parent Table No."; Integer)
+ {
+ Caption = 'Parent Table No.';
+ DataClassification = SystemMetadata;
+ Editable = false;
+
+ trigger OnValidate()
+ begin
+ "Owner Type" := GetOwnerType("Parent Table No.");
+ end;
+ }
+ }
+
+ keys
+ {
+ key(PK; Id)
+ {
+ Clustered = true;
+ }
+ key(Idx1; "Parent Table No.", "Owner Id")
+ {
+ }
+ }
+
+ trigger OnInsert()
+ var
+ Metafield: Record "Shpfy Metafield";
+ begin
+ if Namespace = '' then
+ Namespace := 'Microsoft.Dynamics365.BusinessCentral';
+ if Id = 0 then
+ if Metafield.FindFirst() and (Metafield.Id < 0) then
+ Id := Metafield.Id - 1
+ else
+ Id := -1;
+ end;
+
+ trigger OnModify()
+ begin
+ "Last Updated by BC" := CurrentDateTime;
+ end;
+
+ ///
+ /// Get the owner type based on the resources's owner table number.
+ ///
+ /// The owning resource table number.
+ internal procedure GetOwnerType(ParentTableNo: Integer): Enum "Shpfy Metafield Owner Type"
+ begin
+ case ParentTableNo of
+ Database::"Shpfy Customer":
+ exit("Owner Type"::Customer);
+ Database::"Shpfy Product":
+ exit("Owner Type"::Product);
+ Database::"Shpfy Variant":
+ exit("Owner Type"::ProductVariant);
+ end;
+ end;
+
+ ///
+ /// Returns the name of the enum value for the owner type. Used when the full owner resource id needs to be built.
+ ///
+ /// The name of the owner type.
+ internal procedure GetOwnerTypeName(): Text
+ begin
+ exit("Owner Type".Names().Get("Owner Type".Ordinals().IndexOf("Owner Type".AsInteger())));
+ end;
+
+ local procedure CheckShopCurrency(MetafieldValue: Text[2048])
+ var
+ ShpfyMtfldTypeMoney: Codeunit "Shpfy Mtfld Type Money";
+ CurrencyCode: Code[10];
+ ShopCurrencyCode: Code[10];
+ Amount: Decimal;
+ CurrencyCodeMismatchErr: Label 'The currency code must match the shop currency code. Shop currency code: %1', Comment = '%1 - Shop currency code';
+ begin
+ ShopCurrencyCode := GetShopCurrencyCode();
+
+ ShpfyMtfldTypeMoney.TryExtractValues(MetafieldValue, Amount, CurrencyCode);
+ if CurrencyCode <> ShopCurrencyCode then
+ Error(ErrorInfo.Create(StrSubstNo(CurrencyCodeMismatchErr, ShopCurrencyCode)));
+ end;
+
+ local procedure GetShopCurrencyCode(): Code[10]
+ var
+ GeneralLedgerSetup: Record "General Ledger Setup";
+ Shop: Record "Shpfy Shop";
+ IMetafieldOwnerType: Interface "Shpfy IMetafield Owner Type";
+ begin
+ IMetafieldOwnerType := Rec."Owner Type";
+ Shop.Get(IMetafieldOwnerType.GetShopCode(Rec."Owner Id"));
+
+ if Shop."Currency Code" <> '' then
+ exit(Shop."Currency Code")
+ else begin
+ GeneralLedgerSetup.Get();
+ exit(GeneralLedgerSetup."LCY Code");
+ end;
+ end;
+}
\ No newline at end of file
diff --git a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductAPI.Codeunit.al
index 3878464a4b..2ae6043bf5 100644
--- a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductAPI.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductAPI.Codeunit.al
@@ -564,7 +564,9 @@ codeunit 30176 "Shpfy Product API"
/// Return variable "Result" of type Boolean.
internal procedure UpdateShopifyProductFields(var ShopifyProduct: record "Shpfy Product"; JProduct: JsonObject) Result: Boolean
var
+ MetafieldAPI: Codeunit "Shpfy Metafield API";
UpdatedAt: DateTime;
+ JMetafields: JsonArray;
begin
UpdatedAt := JsonHelper.GetValueAsDateTime(JProduct, 'updatedAt');
if UpdatedAt < ShopifyProduct."Updated At" then
@@ -584,7 +586,7 @@ codeunit 30176 "Shpfy Product API"
ShopifyProduct."Product Type" := JsonHelper.GetValueAsText(JProduct, 'productType', MaxStrLen(ShopifyProduct."Product Type"));
#pragma warning restore AA0139
ShopifyProduct.UpdateTags(JsonHelper.GetArrayAsText(JProduct, 'tags'));
-#pragma warning disable AA0139
+#pragma warning disable AA0139
ShopifyProduct.Title := JsonHelper.GetValueAsText(JProduct, 'title', MaxStrLen(ShopifyProduct.Title));
ShopifyProduct.Vendor := JsonHelper.GetValueAsText(JProduct, 'vendor', MaxStrLen(ShopifyProduct.Vendor));
ShopifyProduct."SEO Description" := JsonHelper.GetValueAsText(JProduct, 'seo.description', MaxStrLen(ShopifyProduct."SEO Description"));
@@ -592,8 +594,10 @@ codeunit 30176 "Shpfy Product API"
#pragma warning restore AA0139
ShopifyProduct.Status := ConvertToProductStatus(JsonHelper.GetValueAsText(JProduct, 'status'));
ShopifyProduct.Modify(false);
- end;
+ if JsonHelper.GetJsonArray(JProduct, JMetafields, 'metafields.edges') then
+ MetafieldAPI.UpdateMetafieldsFromShopify(JMetafields, Database::"Shpfy Product", ShopifyProduct.Id);
+ end;
local procedure ConvertToProductStatus(Value: Text): Enum "Shpfy Product Status"
begin
diff --git a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductExport.Codeunit.al b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductExport.Codeunit.al
index 911006d55b..2ac5c9fb87 100644
--- a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductExport.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductExport.Codeunit.al
@@ -693,10 +693,27 @@ codeunit 30178 "Shpfy Product Export"
end;
until ItemUnitofMeasure.Next() = 0;
end;
- UpdateProductTranslations(ShopifyProduct.Id, Item)
+
+ UpdateMetafields(ShopifyProduct.Id);
+ UpdateProductTranslations(ShopifyProduct.Id, Item);
end;
end;
+ local procedure UpdateMetafields(ProductId: BigInteger)
+ var
+ ShpfyVariant: Record "Shpfy Variant";
+ MetafieldAPI: Codeunit "Shpfy Metafield API";
+ begin
+ MetafieldAPI.CreateOrUpdateMetafieldsInShopify(Database::"Shpfy Product", ProductId);
+
+ ShpfyVariant.SetRange("Product Id", ProductId);
+ ShpfyVariant.ReadIsolation := IsolationLevel::ReadCommitted;
+ if ShpfyVariant.FindSet() then
+ repeat
+ MetafieldAPI.CreateOrUpdateMetafieldsInShopify(Database::"Shpfy Variant", ShpfyVariant.Id);
+ until ShpfyVariant.Next() = 0;
+ end;
+
///
/// Updates a product variant in Shopify. Used when item variant does not exist in BC, but variants per UoM are maintained in Shopify.
///
diff --git a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyVariantAPI.Codeunit.al b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyVariantAPI.Codeunit.al
index 340ed848a6..edc6d2ff57 100644
--- a/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyVariantAPI.Codeunit.al
+++ b/Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyVariantAPI.Codeunit.al
@@ -500,6 +500,7 @@ codeunit 30189 "Shpfy Variant API"
/// Return variable "Result" of type Boolean.
internal procedure UpdateShopifyVariantFields(ShopifyProduct: Record "Shpfy Product"; var ShopifyVariant: Record "Shpfy Variant"; var ShopifyInventoryItem: Record "Shpfy Inventory Item"; JVariant: JsonObject) Result: Boolean
var
+ MetafieldAPI: Codeunit "Shpfy Metafield API";
RecordRef: RecordRef;
UpdatedAt: DateTime;
JMetafields: JsonArray;
@@ -595,7 +596,7 @@ codeunit 30189 "Shpfy Variant API"
end;
if JsonHelper.GetJsonObject(JVariant, JNode, 'metafields') then
if JsonHelper.GetJsonArray(JNode, JMetafields, 'edges') then
- foreach JItem in JMetafields do;
+ MetafieldAPI.UpdateMetafieldsFromShopify(JMetafields, Database::"Shpfy Variant", ShopifyVariant.Id);
end;
///
diff --git a/Apps/W1/Shopify/app/src/Products/Pages/ShpfyProducts.Page.al b/Apps/W1/Shopify/app/src/Products/Pages/ShpfyProducts.Page.al
index 29ce2f2628..3635ac301a 100644
--- a/Apps/W1/Shopify/app/src/Products/Pages/ShpfyProducts.Page.al
+++ b/Apps/W1/Shopify/app/src/Products/Pages/ShpfyProducts.Page.al
@@ -315,6 +315,24 @@ page 30126 "Shpfy Products"
Tags.RunModal();
end;
}
+ action(Metafields)
+ {
+ ApplicationArea = All;
+ Caption = 'Metafields';
+ Image = PriceAdjustment;
+ Promoted = true;
+ PromotedCategory = Process;
+ PromotedIsBig = true;
+ PromotedOnly = true;
+ ToolTip = 'Add metafields to a product. This can be used for adding custom data fields to products in Shopify.';
+
+ trigger OnAction()
+ var
+ Metafields: Page "Shpfy Metafields";
+ begin
+ Metafields.RunForResource(Database::"Shpfy Product", Rec.Id, Rec."Shop Code");
+ end;
+ }
group(Sync)
{
action(SyncProducts)
diff --git a/Apps/W1/Shopify/app/src/Products/Pages/ShpfyVariants.Page.al b/Apps/W1/Shopify/app/src/Products/Pages/ShpfyVariants.Page.al
index 3291b4e345..39b3107e07 100644
--- a/Apps/W1/Shopify/app/src/Products/Pages/ShpfyVariants.Page.al
+++ b/Apps/W1/Shopify/app/src/Products/Pages/ShpfyVariants.Page.al
@@ -213,6 +213,20 @@ page 30127 "Shpfy Variants"
end;
end;
}
+ action(Metafields)
+ {
+ ApplicationArea = All;
+ Caption = 'Metafields';
+ Image = PriceAdjustment;
+ ToolTip = 'Add metafields to a variant. This can be used for adding custom data fields to variants in Shopify.';
+
+ trigger OnAction()
+ var
+ Metafields: Page "Shpfy Metafields";
+ begin
+ Metafields.RunForResource(Database::"Shpfy Variant", Rec.Id, Rec."Shop Code");
+ end;
+ }
action(AddItemsAsVariants)
{
ApplicationArea = All;
diff --git a/Apps/W1/Shopify/app/src/Products/Tables/ShpfyProduct.Table.al b/Apps/W1/Shopify/app/src/Products/Tables/ShpfyProduct.Table.al
index 751923005f..aa699d3747 100644
--- a/Apps/W1/Shopify/app/src/Products/Tables/ShpfyProduct.Table.al
+++ b/Apps/W1/Shopify/app/src/Products/Tables/ShpfyProduct.Table.al
@@ -152,6 +152,7 @@ table 30127 "Shpfy Product"
var
Shop: Record "Shpfy Shop";
ShopifyVariant: Record "Shpfy Variant";
+ Metafield: Record "Shpfy Metafield";
IRemoveProduct: Interface "Shpfy IRemoveProductAction";
begin
if Shop.Get(Rec."Shop Code") then begin
@@ -161,6 +162,11 @@ table 30127 "Shpfy Product"
ShopifyVariant.SetRange("Product Id", Id);
if not ShopifyVariant.IsEmpty then
ShopifyVariant.DeleteAll(true);
+
+ Metafield.SetRange("Parent Table No.", Database::"Shpfy Product");
+ Metafield.SetRange("Owner Id", Id);
+ if not Metafield.IsEmpty then
+ Metafield.DeleteAll();
end;
///
diff --git a/Apps/W1/Shopify/app/src/Products/Tables/ShpfyVariant.Table.al b/Apps/W1/Shopify/app/src/Products/Tables/ShpfyVariant.Table.al
index 85032e64c5..500f760cbd 100644
--- a/Apps/W1/Shopify/app/src/Products/Tables/ShpfyVariant.Table.al
+++ b/Apps/W1/Shopify/app/src/Products/Tables/ShpfyVariant.Table.al
@@ -192,9 +192,15 @@ table 30129 "Shpfy Variant"
trigger OnDelete()
var
InventoryItem: Record "Shpfy Inventory Item";
+ Metafield: Record "Shpfy Metafield";
begin
InventoryItem.SetRange("Variant Id", Id);
if not InventoryItem.IsEmpty then
InventoryItem.DeleteAll();
+
+ Metafield.SetRange("Parent Table No.", Database::"Shpfy Variant");
+ Metafield.SetRange("Owner Id", Id);
+ if not Metafield.IsEmpty then
+ Metafield.DeleteAll();
end;
}