diff --git a/src/Apps/W1/Shopify/App/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al b/src/Apps/W1/Shopify/App/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al
index 91682b1d2a..864386938b 100644
--- a/src/Apps/W1/Shopify/App/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al
+++ b/src/Apps/W1/Shopify/App/src/Order handling/Codeunits/ShpfyImportOrder.Codeunit.al
@@ -151,6 +151,7 @@ codeunit 30161 "Shpfy Import Order"
var
OrderLine: Record "Shpfy Order Line";
DataCapture: Record "Shpfy Data Capture";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
Hash: Codeunit "Shpfy Hash";
JOrderLine: JsonToken;
LineIds: Text;
@@ -172,7 +173,7 @@ codeunit 30161 "Shpfy Import Order"
OrderLine.Copy(TempOrderLine);
UpdateLocationIdAndDeliveryMethodOnOrderLine(OrderLine);
OrderLine.Insert();
- AddTaxLines(OrderLine."Line Id", JsonHelper.GetJsonArray(JOrderLine, 'taxLines'));
+ OrderTaxLine.ImportFromJson(OrderLine."Line Id", JsonHelper.GetJsonArray(JOrderLine, 'taxLines'));
ImportCustomAttributtes(OrderLine."Shopify Order Id", OrderLine.SystemId, JsonHelper.GetJsonArray(JOrderLine, 'customAttributes'));
end;
DataCapture.Add(Database::"Shpfy Order Line", OrderLine.SystemId, Format(JOrderLine));
@@ -268,6 +269,7 @@ codeunit 30161 "Shpfy Import Order"
local procedure SetAndCreateRelatedRecords(JOrder: JsonObject; var OrderHeader: Record "Shpfy Order Header")
var
+ OrderTaxLine: Record "Shpfy Order Tax Line";
FulfillmentOrdersAPI: Codeunit "Shpfy Fulfillment Orders API";
ShippingCharges: Codeunit "Shpfy Shipping Charges";
Transactions: Codeunit "Shpfy Transactions";
@@ -275,7 +277,7 @@ codeunit 30161 "Shpfy Import Order"
RefundsAPI: Codeunit "Shpfy Refunds API";
IReturnRefundProcess: Interface "Shpfy IReturnRefund Process";
begin
- AddTaxLines(OrderHeader."Shopify Order Id", JsonHelper.GetJsonArray(JOrder, 'taxLines'));
+ OrderTaxLine.ImportFromJson(OrderHeader."Shopify Order Id", JsonHelper.GetJsonArray(JOrder, 'taxLines'));
OrderHeader.SetWorkDescription(JsonHelper.GetValueAsText(JOrder, 'note'));
ImportCustomAttributtes(OrderHeader."Shopify Order Id", JsonHelper.GetJsonArray(JOrder, 'customAttributes'));
OrderHeader.UpdateTags(JsonHelper.GetArrayAsText(JOrder, 'tags'));
@@ -794,35 +796,6 @@ codeunit 30161 "Shpfy Import Order"
OrderHeaderRecordRef.Field(OrderHeader.FieldNo("Salesperson Code")).Value := StaffMember."Salesperson Code";
end;
- ///
- /// Add Tax Lines.
- ///
- /// Parameter of type BigInteger.
- /// Parameter of type JsonArray.
- local procedure AddTaxLines(ParentId: BigInteger; JTaxLines: JsonArray)
- var
- OrderTaxLine: Record "Shpfy Order Tax Line";
- RecordRef: RecordRef;
- JToken: JsonToken;
- begin
- OrderTaxLine.SetRange("Parent Id", ParentId);
- if not OrderTaxLine.IsEmpty() then
- OrderTaxLine.DeleteAll();
- foreach JToken in JTaxLines do begin
- RecordRef.Open(Database::"Shpfy Order Tax Line");
- RecordRef.Init();
- RecordRef.Field(OrderTaxLine.FieldNo("Parent Id")).Value := ParentId;
- JsonHelper.GetValueIntoField(JToken, 'title', RecordRef, OrderTaxLine.FieldNo(Title));
- JsonHelper.GetValueIntoField(JToken, 'rate', RecordRef, OrderTaxLine.FieldNo(Rate));
- JsonHelper.GetValueIntoField(JToken, 'ratePercentage', RecordRef, OrderTaxLine.FieldNo("Rate %"));
- JsonHelper.GetValueIntoField(JToken, 'priceSet.shopMoney.amount', RecordRef, OrderTaxLine.FieldNo(Amount));
- JsonHelper.GetValueIntoField(JToken, 'priceSet.presentmentMoney.amount', RecordRef, OrderTaxLine.FieldNo("Presentment Amount"));
- JsonHelper.GetValueIntoField(JToken, 'channelLiable', RecordRef, OrderTaxLine.FieldNo("Channel Liable"));
- RecordRef.Insert(true);
- RecordRef.Close();
- end;
- end;
-
///
/// Description for GetName.
///
diff --git a/src/Apps/W1/Shopify/App/src/Order handling/Pages/ShpfyOrderTaxLines.Page.al b/src/Apps/W1/Shopify/App/src/Order handling/Pages/ShpfyOrderTaxLines.Page.al
index a59953d374..6f91cb79de 100644
--- a/src/Apps/W1/Shopify/App/src/Order handling/Pages/ShpfyOrderTaxLines.Page.al
+++ b/src/Apps/W1/Shopify/App/src/Order handling/Pages/ShpfyOrderTaxLines.Page.al
@@ -74,12 +74,19 @@ page 30168 "Shpfy Order Tax Lines"
var
OrderHeader: Record "Shpfy Order Header";
OrderLine: Record "Shpfy Order Line";
+ OrderShippingCharges: Record "Shpfy Order Shipping Charges";
begin
OrderLine.SetRange("Line Id", Rec."Parent Id");
- if not OrderLine.FindFirst() then
- exit;
- if not OrderHeader.Get(OrderLine."Shopify Order Id") then
- exit;
+ if OrderLine.FindFirst() then begin
+ if not OrderHeader.Get(OrderLine."Shopify Order Id") then
+ exit;
+ end else
+ if OrderShippingCharges.Get(Rec."Parent Id") then begin
+ if not OrderHeader.Get(OrderShippingCharges."Shopify Order Id") then
+ exit;
+ end else
+ if not OrderHeader.Get(Rec."Parent Id") then
+ exit;
PresentmentCurrencyVisible := OrderHeader.IsPresentmentCurrencyOrder();
end;
diff --git a/src/Apps/W1/Shopify/App/src/Order handling/Tables/ShpfyOrderTaxLine.Table.al b/src/Apps/W1/Shopify/App/src/Order handling/Tables/ShpfyOrderTaxLine.Table.al
index 516b6f46b6..901b5340c0 100644
--- a/src/Apps/W1/Shopify/App/src/Order handling/Tables/ShpfyOrderTaxLine.Table.al
+++ b/src/Apps/W1/Shopify/App/src/Order handling/Tables/ShpfyOrderTaxLine.Table.al
@@ -103,23 +103,64 @@ table 30122 "Shpfy Order Tax Line"
end;
end;
+ internal procedure ImportFromJson(ParentId: BigInteger; JTaxLines: JsonArray)
+ var
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ JsonHelper: Codeunit "Shpfy Json Helper";
+ RecordRef: RecordRef;
+ JToken: JsonToken;
+ begin
+ OrderTaxLine.SetRange("Parent Id", ParentId);
+ if not OrderTaxLine.IsEmpty() then
+ OrderTaxLine.DeleteAll(false);
+ foreach JToken in JTaxLines do begin
+ RecordRef.Open(Database::"Shpfy Order Tax Line");
+ RecordRef.Init();
+ RecordRef.Field(OrderTaxLine.FieldNo("Parent Id")).Value := ParentId;
+ JsonHelper.GetValueIntoField(JToken, 'title', RecordRef, OrderTaxLine.FieldNo(Title));
+ JsonHelper.GetValueIntoField(JToken, 'rate', RecordRef, OrderTaxLine.FieldNo(Rate));
+ JsonHelper.GetValueIntoField(JToken, 'ratePercentage', RecordRef, OrderTaxLine.FieldNo("Rate %"));
+ JsonHelper.GetValueIntoField(JToken, 'priceSet.shopMoney.amount', RecordRef, OrderTaxLine.FieldNo(Amount));
+ JsonHelper.GetValueIntoField(JToken, 'priceSet.presentmentMoney.amount', RecordRef, OrderTaxLine.FieldNo("Presentment Amount"));
+ JsonHelper.GetValueIntoField(JToken, 'channelLiable', RecordRef, OrderTaxLine.FieldNo("Channel Liable"));
+ RecordRef.Insert(true);
+ RecordRef.Close();
+ end;
+ end;
+
local procedure OrderCurrencyCode(): Code[10]
var
OrderHeader: Record "Shpfy Order Header";
OrderLine: Record "Shpfy Order Line";
+ OrderShippingCharges: Record "Shpfy Order Shipping Charges";
begin
- if OrderLine.Get("Parent Id") then
+ if OrderLine.Get("Parent Id") then begin
if OrderHeader.Get(OrderLine."Shopify Order Id") then
exit(OrderHeader."Currency Code");
+ end else
+ if OrderShippingCharges.Get("Parent Id") then begin
+ if OrderHeader.Get(OrderShippingCharges."Shopify Order Id") then
+ exit(OrderHeader."Currency Code");
+ end else
+ if OrderHeader.Get("Parent Id") then
+ exit(OrderHeader."Currency Code");
end;
local procedure OrderPresentmentCurrencyCode(): Code[10]
var
OrderHeader: Record "Shpfy Order Header";
OrderLine: Record "Shpfy Order Line";
+ OrderShippingCharges: Record "Shpfy Order Shipping Charges";
begin
- if OrderLine.Get("Parent Id") then
+ if OrderLine.Get("Parent Id") then begin
if OrderHeader.Get(OrderLine."Shopify Order Id") then
exit(OrderHeader."Presentment Currency Code");
+ end else
+ if OrderShippingCharges.Get("Parent Id") then begin
+ if OrderHeader.Get(OrderShippingCharges."Shopify Order Id") then
+ exit(OrderHeader."Presentment Currency Code");
+ end else
+ if OrderHeader.Get("Parent Id") then
+ exit(OrderHeader."Presentment Currency Code");
end;
}
\ No newline at end of file
diff --git a/src/Apps/W1/Shopify/App/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al b/src/Apps/W1/Shopify/App/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al
index e4f7f64c61..73404ce556 100644
--- a/src/Apps/W1/Shopify/App/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al
+++ b/src/Apps/W1/Shopify/App/src/Shipping/Codeunits/ShpfyShippingCharges.Codeunit.al
@@ -53,6 +53,7 @@ codeunit 30191 "Shpfy Shipping Charges"
OrderShippingCharges: Record "Shpfy Order Shipping Charges";
ShipmentMethodMapping: Record "Shpfy Shipment Method Mapping";
DataCapture: Record "Shpfy Data Capture";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
RecordRef: RecordRef;
Id: BigInteger;
JToken: JsonToken;
@@ -83,6 +84,7 @@ codeunit 30191 "Shpfy Shipping Charges"
else
OrderShippingCharges.Modify();
RecordRef.Close();
+ OrderTaxLine.ImportFromJson(OrderShippingCharges."Shopify Shipping Line Id", JsonHelper.GetJsonArray(JToken, 'taxLines'));
DataCapture.Add(Database::"Shpfy Order Shipping Charges", OrderShippingCharges.SystemId, JToken);
if not ShipmentMethodMapping.Get(OrderHeader."Shop Code", OrderShippingCharges.Title) then begin
Clear(ShipmentMethodMapping);
diff --git a/src/Apps/W1/Shopify/App/src/Shipping/Pages/ShpfyOrderShippingCharges.Page.al b/src/Apps/W1/Shopify/App/src/Shipping/Pages/ShpfyOrderShippingCharges.Page.al
index 33c1b2b2cc..e51cb3e27c 100644
--- a/src/Apps/W1/Shopify/App/src/Shipping/Pages/ShpfyOrderShippingCharges.Page.al
+++ b/src/Apps/W1/Shopify/App/src/Shipping/Pages/ShpfyOrderShippingCharges.Page.al
@@ -16,7 +16,6 @@ page 30128 "Shpfy Order Shipping Charges"
InsertAllowed = false;
ModifyAllowed = false;
PageType = List;
- PromotedActionCategories = 'New,Process,Report,Inspect';
SourceTable = "Shpfy Order Shipping Charges";
UsageCategory = None;
@@ -87,15 +86,26 @@ page 30128 "Shpfy Order Shipping Charges"
{
area(Processing)
{
+ action(TaxLines)
+ {
+ ApplicationArea = All;
+ Caption = 'Tax Lines';
+ Image = TaxDetail;
+ ToolTip = 'View the tax lines for the selected shipping charge.';
+
+ trigger OnAction();
+ var
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ begin
+ OrderTaxLine.SetRange("Parent Id", Rec."Shopify Shipping Line Id");
+ Page.Run(Page::"Shpfy Order Tax Lines", OrderTaxLine);
+ end;
+ }
action(RetrievedShopifyData)
{
ApplicationArea = All;
Caption = 'Retrieved Shopify Data';
Image = Entry;
- Promoted = true;
- PromotedCategory = Category4;
- PromotedIsBig = true;
- PromotedOnly = true;
ToolTip = 'View the data retrieved from Shopify.';
trigger OnAction();
@@ -109,6 +119,11 @@ page 30128 "Shpfy Order Shipping Charges"
end;
}
}
+ area(Promoted)
+ {
+ actionref(TaxLines_Promoted; TaxLines) { }
+ actionref(RetrievedShopifyData_Promoted; RetrievedShopifyData) { }
+ }
}
var
diff --git a/src/Apps/W1/Shopify/App/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al b/src/Apps/W1/Shopify/App/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al
index 2c51fd79f0..12e9e0fd96 100644
--- a/src/Apps/W1/Shopify/App/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al
+++ b/src/Apps/W1/Shopify/App/src/Shipping/Tables/ShpfyOrderShippingCharges.Table.al
@@ -91,8 +91,13 @@ table 30130 "Shpfy Order Shipping Charges"
trigger OnDelete()
var
+ OrderTaxLine: Record "Shpfy Order Tax Line";
DataCapture: Record "Shpfy Data Capture";
begin
+ OrderTaxLine.SetRange("Parent Id", Rec."Shopify Shipping Line Id");
+ if not OrderTaxLine.IsEmpty() then
+ OrderTaxLine.DeleteAll(false);
+
DataCapture.SetRange("Linked To Table", Database::"Shpfy Order Shipping Charges");
DataCapture.SetRange("Linked To Id", Rec.SystemId);
if not DataCapture.IsEmpty then
diff --git a/src/Apps/W1/Shopify/Test/Shipping/ShpfyShippingChargesTest.Codeunit.al b/src/Apps/W1/Shopify/Test/Shipping/ShpfyShippingChargesTest.Codeunit.al
index f32abf44c8..0db27930bb 100644
--- a/src/Apps/W1/Shopify/Test/Shipping/ShpfyShippingChargesTest.Codeunit.al
+++ b/src/Apps/W1/Shopify/Test/Shipping/ShpfyShippingChargesTest.Codeunit.al
@@ -33,6 +33,7 @@ codeunit 139546 "Shpfy Shipping Charges Test"
CommunicationMgt: Codeunit "Shpfy Communication Mgt.";
InitializeTest: Codeunit "Shpfy Initialize Test";
IsInitialized: Boolean;
+ ShippingLineGIdTok: Label 'gid://shopify/ShippingLine/%1', Locked = true, Comment = '%1 = Shipping line id';
trigger OnRun()
begin
@@ -353,6 +354,209 @@ codeunit 139546 "Shpfy Shipping Charges Test"
ShpfyShipmentMethodMapping."Shipping Charges No."
);
end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestImportShippingTaxLineWithChannelLiableTrue()
+ var
+ OrderHeader: Record "Shpfy Order Header";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ ShippingCharges: Codeunit "Shpfy Shipping Charges";
+ JShippingLines: JsonArray;
+ JTaxLines: JsonArray;
+ ShippingLineId: BigInteger;
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] The tax line of a shipping line is persisted against the shipping charge with all values preserved and Channel Liable = true.
+ Initialize();
+
+ // [GIVEN] Shopify Shop and an imported Shopify order
+ Shop := CommunicationMgt.GetShopRecord();
+ CreateImportedOrderHeader(OrderHeader);
+
+ // [GIVEN] A shipping line with a single tax line where channelLiable is true
+ ShippingLineId := LibraryRandom.RandInt(100000);
+ Clear(JTaxLines);
+ AddTaxLineToArray(JTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddShippingLine(JShippingLines, ShippingLineId, JTaxLines);
+
+ // [WHEN] Shipping cost infos are imported
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ // [THEN] A single tax line is stored against the shipping charge with all values preserved
+ OrderTaxLine.SetRange("Parent Id", ShippingLineId);
+ LibraryAssert.AreEqual(1, OrderTaxLine.Count(), 'Exactly one shipping tax line must be stored.');
+ OrderTaxLine.FindFirst();
+ LibraryAssert.AreEqual('TAX1', OrderTaxLine.Title, 'Shipping tax line title must be preserved.');
+ LibraryAssert.AreEqual(0.1, OrderTaxLine.Rate, 'Shipping tax line rate must be preserved.');
+ LibraryAssert.AreEqual(10, OrderTaxLine."Rate %", 'Shipping tax line rate percentage must be preserved.');
+ LibraryAssert.AreEqual(5, OrderTaxLine.Amount, 'Shipping tax line shop amount must be preserved.');
+ LibraryAssert.AreEqual(6, OrderTaxLine."Presentment Amount", 'Shipping tax line presentment amount must be preserved.');
+ LibraryAssert.IsTrue(OrderTaxLine."Channel Liable", 'Shipping tax line Channel Liable must be true.');
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestImportShippingTaxLineWithChannelLiableFalse()
+ var
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] The Channel Liable flag of a shipping tax line is imported as false when explicitly set to false.
+ VerifyShippingTaxLineChannelLiable(ChannelLiableScenario::FalseValue, false);
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestImportShippingTaxLineWithChannelLiableNull()
+ var
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] A null channelLiable on a shipping tax line defaults to false.
+ VerifyShippingTaxLineChannelLiable(ChannelLiableScenario::NullValue, false);
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestImportShippingTaxLineWithChannelLiableMissing()
+ var
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] A missing channelLiable on a shipping tax line defaults to false.
+ VerifyShippingTaxLineChannelLiable(ChannelLiableScenario::Missing, false);
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestImportShippingTaxLinesForMultipleShippingLinesAreSeparated()
+ var
+ OrderHeader: Record "Shpfy Order Header";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ ShippingCharges: Codeunit "Shpfy Shipping Charges";
+ JShippingLines: JsonArray;
+ JFirstTaxLines: JsonArray;
+ JSecondTaxLines: JsonArray;
+ FirstShippingLineId: BigInteger;
+ SecondShippingLineId: BigInteger;
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] Tax lines of multiple shipping lines are kept separated per shipping charge.
+ Initialize();
+
+ // [GIVEN] Shopify Shop and an imported Shopify order
+ Shop := CommunicationMgt.GetShopRecord();
+ CreateImportedOrderHeader(OrderHeader);
+
+ // [GIVEN] Two shipping lines: the first with two tax lines, the second with one
+ FirstShippingLineId := LibraryRandom.RandInt(100000);
+ SecondShippingLineId := LibraryRandom.RandInt(100000);
+
+ AddTaxLineToArray(JFirstTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddTaxLineToArray(JFirstTaxLines, 'TAX2', ChannelLiableScenario::FalseValue);
+ AddShippingLine(JShippingLines, FirstShippingLineId, JFirstTaxLines);
+
+ AddTaxLineToArray(JSecondTaxLines, 'TAX3', ChannelLiableScenario::TrueValue);
+ AddShippingLine(JShippingLines, SecondShippingLineId, JSecondTaxLines);
+
+ // [WHEN] Shipping cost infos are imported
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ // [THEN] Each shipping charge keeps its own tax lines
+ OrderTaxLine.SetRange("Parent Id", FirstShippingLineId);
+ LibraryAssert.AreEqual(2, OrderTaxLine.Count(), 'First shipping line must keep both tax lines.');
+ OrderTaxLine.SetRange("Parent Id", SecondShippingLineId);
+ LibraryAssert.AreEqual(1, OrderTaxLine.Count(), 'Second shipping line must keep its single tax line.');
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestReimportShippingTaxLinesReplacesWithoutDuplicates()
+ var
+ OrderHeader: Record "Shpfy Order Header";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ ShippingCharges: Codeunit "Shpfy Shipping Charges";
+ JShippingLines: JsonArray;
+ JTaxLines: JsonArray;
+ ShippingLineId: BigInteger;
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] Reimporting the same shipping line replaces its tax lines without duplicates or stale rows.
+ Initialize();
+
+ // [GIVEN] Shopify Shop and an imported Shopify order
+ Shop := CommunicationMgt.GetShopRecord();
+ CreateImportedOrderHeader(OrderHeader);
+
+ // [GIVEN] A shipping line with two tax lines is imported
+ ShippingLineId := LibraryRandom.RandInt(100000);
+ Clear(JTaxLines);
+ AddTaxLineToArray(JTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddTaxLineToArray(JTaxLines, 'TAX2', ChannelLiableScenario::FalseValue);
+ AddShippingLine(JShippingLines, ShippingLineId, JTaxLines);
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ OrderTaxLine.SetRange("Parent Id", ShippingLineId);
+ LibraryAssert.AreEqual(2, OrderTaxLine.Count(), 'Two tax lines must be stored after the first import.');
+
+ // [WHEN] The same shipping line is reimported with a single tax line
+ Clear(JShippingLines);
+ Clear(JTaxLines);
+ AddTaxLineToArray(JTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddShippingLine(JShippingLines, ShippingLineId, JTaxLines);
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ // [THEN] The stale tax line is removed and no duplicates remain
+ OrderTaxLine.SetRange("Parent Id", ShippingLineId);
+ LibraryAssert.AreEqual(1, OrderTaxLine.Count(), 'Reimport must replace the tax lines without duplicates or stale rows.');
+ OrderTaxLine.FindFirst();
+ LibraryAssert.AreEqual('TAX1', OrderTaxLine.Title, 'The remaining tax line must be the reimported one.');
+ end;
+
+ [Test]
+ [HandlerFunctions('ShippingChargesHttpHandler')]
+ procedure UnitTestShippingTaxLinesRemovedWhenShippingLineRemoved()
+ var
+ OrderHeader: Record "Shpfy Order Header";
+ OrderShippingCharges: Record "Shpfy Order Shipping Charges";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ ShippingCharges: Codeunit "Shpfy Shipping Charges";
+ JShippingLines: JsonArray;
+ JFirstTaxLines: JsonArray;
+ JSecondTaxLines: JsonArray;
+ JReimportShippingLines: JsonArray;
+ JReimportTaxLines: JsonArray;
+ FirstShippingLineId: BigInteger;
+ SecondShippingLineId: BigInteger;
+ ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue;
+ begin
+ // [SCENARIO] When a shipping line is no longer returned by Shopify, its shipping charge and tax lines are removed.
+ Initialize();
+
+ // [GIVEN] Shopify Shop and an imported Shopify order
+ Shop := CommunicationMgt.GetShopRecord();
+ CreateImportedOrderHeader(OrderHeader);
+
+ // [GIVEN] Two shipping lines, each with a tax line, are imported
+ FirstShippingLineId := LibraryRandom.RandInt(100000);
+ SecondShippingLineId := LibraryRandom.RandInt(100000);
+
+ AddTaxLineToArray(JFirstTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddShippingLine(JShippingLines, FirstShippingLineId, JFirstTaxLines);
+ AddTaxLineToArray(JSecondTaxLines, 'TAX2', ChannelLiableScenario::FalseValue);
+ AddShippingLine(JShippingLines, SecondShippingLineId, JSecondTaxLines);
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ // [WHEN] Only the first shipping line is returned on reimport
+ AddTaxLineToArray(JReimportTaxLines, 'TAX1', ChannelLiableScenario::TrueValue);
+ AddShippingLine(JReimportShippingLines, FirstShippingLineId, JReimportTaxLines);
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JReimportShippingLines);
+
+ // [THEN] The removed shipping charge and its tax lines are deleted
+ LibraryAssert.IsFalse(OrderShippingCharges.Get(SecondShippingLineId), 'The removed shipping charge must be deleted.');
+ OrderTaxLine.SetRange("Parent Id", SecondShippingLineId);
+ LibraryAssert.AreEqual(0, OrderTaxLine.Count(), 'Tax lines of the removed shipping line must be deleted.');
+ OrderTaxLine.SetRange("Parent Id", FirstShippingLineId);
+ LibraryAssert.AreEqual(1, OrderTaxLine.Count(), 'The remaining shipping line must keep its tax line.');
+ end;
#endregion
[HttpClientHandler]
@@ -467,6 +671,96 @@ codeunit 139546 "Shpfy Shipping Charges Test"
OrderShippingCharges.Insert(true);
end;
+ local procedure CreateImportedOrderHeader(var OrderHeader: Record "Shpfy Order Header")
+ var
+ ImportOrder: Codeunit "Shpfy Import Order";
+ begin
+ ImportOrder.SetShop(Shop.Code);
+ ImportShopifyOrder(Shop, OrderHeader, ImportOrder, false);
+ end;
+
+ local procedure VerifyShippingTaxLineChannelLiable(ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue; ExpectedChannelLiable: Boolean)
+ var
+ OrderHeader: Record "Shpfy Order Header";
+ OrderTaxLine: Record "Shpfy Order Tax Line";
+ ShippingCharges: Codeunit "Shpfy Shipping Charges";
+ JShippingLines: JsonArray;
+ JTaxLines: JsonArray;
+ ShippingLineId: BigInteger;
+ begin
+ Initialize();
+
+ // [GIVEN] Shopify Shop and an imported Shopify order
+ Shop := CommunicationMgt.GetShopRecord();
+ CreateImportedOrderHeader(OrderHeader);
+
+ // [GIVEN] A shipping line with a single tax line for the given channelLiable scenario
+ ShippingLineId := LibraryRandom.RandInt(100000);
+ Clear(JTaxLines);
+ AddTaxLineToArray(JTaxLines, 'TAX1', ChannelLiableScenario);
+ AddShippingLine(JShippingLines, ShippingLineId, JTaxLines);
+
+ // [WHEN] Shipping cost infos are imported
+ ShippingCharges.UpdateShippingCostInfos(OrderHeader, JShippingLines);
+
+ // [THEN] A tax line is stored with the expected Channel Liable value
+ OrderTaxLine.SetRange("Parent Id", ShippingLineId);
+ LibraryAssert.AreEqual(1, OrderTaxLine.Count(), 'Exactly one shipping tax line must be stored.');
+ OrderTaxLine.FindFirst();
+ LibraryAssert.AreEqual(ExpectedChannelLiable, OrderTaxLine."Channel Liable", 'Shipping tax line Channel Liable is not as expected.');
+ end;
+
+ local procedure AddShippingLine(var JShippingLines: JsonArray; ShippingLineId: BigInteger; JTaxLines: JsonArray)
+ var
+ JShippingLine: JsonObject;
+ JPriceSet: JsonObject;
+ JShopMoney: JsonObject;
+ JPresentmentMoney: JsonObject;
+ begin
+ JShippingLine.Add('id', StrSubstNo(ShippingLineGIdTok, ShippingLineId));
+ JShippingLine.Add('title', StrSubstNo('Shipping %1', ShippingLineId));
+ JShippingLine.Add('code', 'STD');
+ JShippingLine.Add('source', 'shopify');
+ JShopMoney.Add('amount', '20');
+ JPriceSet.Add('shopMoney', JShopMoney);
+ JPresentmentMoney.Add('amount', '24');
+ JPriceSet.Add('presentmentMoney', JPresentmentMoney);
+ JShippingLine.Add('originalPriceSet', JPriceSet);
+ JShippingLine.Add('taxLines', JTaxLines);
+ JShippingLines.Add(JShippingLine);
+ end;
+
+ local procedure AddTaxLineToArray(var JTaxLines: JsonArray; Title: Text; ChannelLiableScenario: Option Missing,TrueValue,FalseValue,NullValue)
+ var
+ JTaxLine: JsonObject;
+ JPriceSet: JsonObject;
+ JShopMoney: JsonObject;
+ JPresentmentMoney: JsonObject;
+ JNull: JsonValue;
+ begin
+ JTaxLine.Add('title', Title);
+ JTaxLine.Add('rate', 0.1);
+ JTaxLine.Add('ratePercentage', 10);
+ JShopMoney.Add('amount', '5');
+ JPriceSet.Add('shopMoney', JShopMoney);
+ JPresentmentMoney.Add('amount', '6');
+ JPriceSet.Add('presentmentMoney', JPresentmentMoney);
+ JTaxLine.Add('priceSet', JPriceSet);
+ case ChannelLiableScenario of
+ ChannelLiableScenario::TrueValue:
+ JTaxLine.Add('channelLiable', true);
+ ChannelLiableScenario::FalseValue:
+ JTaxLine.Add('channelLiable', false);
+ ChannelLiableScenario::NullValue:
+ begin
+ JNull.SetValueToNull();
+ JTaxLine.Add('channelLiable', JNull);
+ end;
+ // Missing: channelLiable is intentionally not added
+ end;
+ JTaxLines.Add(JTaxLine);
+ end;
+
local procedure CreateGLAccount(var GLAccount: Record "G/L Account")
var
VATPostingSetup: Record "VAT Posting Setup";