diff --git a/dataset/bcbench.jsonl b/dataset/bcbench.jsonl index 54796b9fb..03efb6e02 100644 --- a/dataset/bcbench.jsonl +++ b/dataset/bcbench.jsonl @@ -99,3 +99,18 @@ {"metadata": {"area": "inventory", "image_count": 0}, "repo": "microsoftInternal/NAV", "instance_id": "microsoftInternal__NAV-178045", "base_commit": "22d8978231eb8792d03f150d61431d485d3c92a9", "created_at": "2024-03-11", "environment_setup_version": "24.0", "project_paths": ["App\\Layers\\W1\\BaseApp", "App\\Layers\\W1\\Tests\\TestLibraries", "App\\Layers\\W1\\Tests\\SCM"], "FAIL_TO_PASS": [{"codeunitID": 137404, "functionName": ["ConsumptionIsPostedForMultipleILEsOfSameLotNo"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/App/Layers/W1/Tests/SCM/SCMManufacturing.Codeunit.al b/App/Layers/W1/Tests/SCM/SCMManufacturing.Codeunit.al\nindex 9467380d9f9b..e1036e0420d9 100644\n--- a/App/Layers/W1/Tests/SCM/SCMManufacturing.Codeunit.al\n+++ b/App/Layers/W1/Tests/SCM/SCMManufacturing.Codeunit.al\n@@ -47,6 +47,7 @@ codeunit 137404 \"SCM Manufacturing\"\n Capacity2: Decimal;\n GLB_ItemTrackingQty: Integer;\n GLB_SerialNo: Code[50];\n+ ItemTrackingMode: Option \" \",\"Assign Lot No.\",\"Select Entries\",\"Update Quantity\",\"Manual Lot No.\"; \n DocumentNoDoesNotExistErr: Label 'Document No. %1 does not exist.', Comment = '%1: Document number (Code)';\n ExpectedQuantityErr: Label 'Quantity must be %1.', Comment = '%1: Quantity (decimal value)';\n ModifyRtngErr: Label 'You cannot modify Routing No. %1 because there is at least one %2 associated with it.';\n@@ -80,6 +81,7 @@ codeunit 137404 \"SCM Manufacturing\"\n DidntExpectWhsePickMsg: Label 'Did not expect a Warehouse Pick Request associated with the Production Order Component Line, since the line doesn''t have a postitive remaining quantity';\n ProdOrderNoHandlerErr: Label 'Prod. Order No. must be %1, actual value is %2.', Comment = '%1: Expected Prod. Order No. Value; %2: Actual Prod. Order No. Value.';\n ProdOrderStatusHandlerErr: Label 'Prod. Order Status must be %1, actual value is %2.', Comment = '%1: Expected Prod. Order Status Value; %2: Actual Prod. Order Status Value.';\n+ ItemLedgerEntryMustBeFoundErr: Label 'Item Ledger Entry must be found.';\n \n [Test]\n [HandlerFunctions('ConfirmHandlerTrue,OutputJournalItemtrackingPageHandler,MessageHandler')]\n@@ -4149,6 +4151,104 @@ codeunit 137404 \"SCM Manufacturing\"\n LibraryInventory.PostItemJournalLine(ItemJournalBatch.\"Journal Template Name\", ItemJournalBatch.Name);\n end;\n \n+ [Test]\n+ [Scope('OnPrem')]\n+ [HandlerFunctions('ItemTrackingAssignLotNoPageHandler,ProductionJournalPageHandlerOnlyConsumption,ConfirmHandlerTrue,MessageHandler')]\n+ procedure ConsumptionIsPostedForMultipleILEsOfSameLotNo()\n+ var\n+ CompItem, ProdItem : Record Item;\n+ Location: Record Location;\n+ UnitOfMeasure: Record \"Unit of Measure\";\n+ ItemUnitOfMeasure: Record \"Item Unit of Measure\";\n+ ItemTrackingCode: Record \"Item Tracking Code\";\n+ ProductionBOMHeader: Record \"Production BOM Header\";\n+ ProductionBOMLine: Record \"Production BOM Line\";\n+ ProductionOrder: Record \"Production Order\";\n+ ItemLedgerEntry: Record \"Item Ledger Entry\";\n+ LotNo: Code[10];\n+ Quantity: Decimal;\n+ ReleasedProdOrder: TestPage \"Released Production Order\";\n+ begin\n+ // [SCENARIO 501830] Consumption is posted against multiple Item Ledger Entries of same Lot No. when you post Production Journal from a Released Production Order.\n+ Initialize();\n+\n+ // [GIVEN] Create Item Tracking Code.\n+ LibraryItemTracking.CreateItemTrackingCode(ItemTrackingCode, false, true);\n+\n+ // [GIVEN] Create Unit of Measure.\n+ LibraryInventory.CreateUnitOfMeasureCode(UnitOfMeasure);\n+\n+ // [GIVEN] Create Component Item with Unit of Measure.\n+ CreateItemWithUOM(CompItem, UnitOfMeasure, ItemUnitOfMeasure);\n+ CompItem.Validate(\"Replenishment System\", CompItem.\"Replenishment System\"::Purchase);\n+ CompItem.Validate(Reserve, CompItem.Reserve::Always);\n+ CompItem.Validate(\"Flushing Method\", CompItem.\"Flushing Method\"::Manual);\n+ CompItem.Validate(\"Item Tracking Code\", ItemTrackingCode.Code);\n+ CompItem.Modify(true);\n+\n+ // [GIVEN] Create Location with Inventory Posting Setup.\n+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);\n+\n+ // [GIVEN] Create Production Item with Unit of Measure.\n+ CreateItemWithUOM(ProdItem, UnitOfMeasure, ItemUnitOfMeasure);\n+\n+ // [GIVEN] Generate and save Lot No. and Quantity in two different Variable.\n+ LotNo := Format(LibraryRandom.RandText(4));\n+ Quantity := LibraryRandom.RandIntInRange(35, 35);\n+\n+ // [GIVEN] Create and Post three Item Journal Lines with same Lot No.\n+ CreateAndPostItemJournalLineWithLotNo(CompItem.\"No.\", LibraryRandom.RandIntInRange(5, 5), LotNo, '', Location.Code, true);\n+ CreateAndPostItemJournalLineWithLotNo(CompItem.\"No.\", LibraryRandom.RandIntInRange(10, 10), LotNo, '', Location.Code, true);\n+ CreateAndPostItemJournalLineWithLotNo(CompItem.\"No.\", LibraryRandom.RandIntInRange(20, 20), LotNo, '', Location.Code, true);\n+\n+ // [GIVEN] Create a production BOM for the Production Item.\n+ LibraryManufacturing.CreateProductionBOMHeader(ProductionBOMHeader, ItemUnitOfMeasure.Code);\n+ LibraryManufacturing.CreateProductionBOMLine(\n+ ProductionBOMHeader,\n+ ProductionBOMLine,\n+ '',\n+ ProductionBOMLine.Type::Item,\n+ CompItem.\"No.\",\n+ LibraryRandom.RandIntInRange(1, 1));\n+\n+ // [GIVEN] Validate Unit of Measure in Production BOM.\n+ ProductionBOMLine.Validate(\"Unit of Measure Code\", ItemUnitOfMeasure.Code);\n+ ProductionBOMLine.Modify(true);\n+\n+ // [GIVEN] Change Status of Production BOM.\n+ LibraryManufacturing.UpdateProductionBOMStatus(ProductionBOMHeader, ProductionBOMHeader.Status::Certified);\n+\n+ // [GIVEN] Validate Replenishment System and Production BOM No. in Production Item.\n+ ProdItem.Validate(\"Replenishment System\", ProdItem.\"Replenishment System\"::\"Prod. Order\");\n+ ProdItem.Validate(\"Production BOM No.\", ProductionBOMHeader.\"No.\");\n+ ProdItem.Modify(true);\n+\n+ // [GIVEN] Create and Refresh Production Order.\n+ CreateAndRefreshProdOrder(\n+ ProductionOrder,\n+ ProductionOrder.Status::Released,\n+ ProdItem.\"No.\",\n+ Quantity,\n+ Location.Code,\n+ '');\n+\n+ // [GIVEN] Open Released Production Order page and run Production Journal action.\n+ ReleasedProdOrder.OpenEdit();\n+ ReleasedProdOrder.GoToRecord(ProductionOrder);\n+ LibraryVariableStorage.Enqueue(Quantity);\n+ LibraryVariableStorage.Enqueue(ItemTrackingMode::\"Assign Lot No.\");\n+ LibraryVariableStorage.Enqueue(LotNo);\n+ LibraryVariableStorage.Enqueue(Quantity);\n+ ReleasedProdOrder.ProdOrderLines.ProductionJournal.Invoke();\n+\n+ // [WHEN] Find Item Ledger Entry.\n+ ItemLedgerEntry.SetRange(\"Item No.\", CompItem.\"No.\");\n+ ItemLedgerEntry.SetRange(Quantity, -Quantity);\n+\n+ // [VERIFY] Item Ledger Entry is found.\n+ Assert.IsFalse(ItemLedgerEntry.IsEmpty(), ItemLedgerEntryMustBeFoundErr);\n+ end;\n+\n local procedure Initialize()\n var\n LibraryERMCountryData: Codeunit \"Library - ERM Country Data\";\n@@ -6772,6 +6872,39 @@ codeunit 137404 \"SCM Manufacturing\"\n ReservationPage.OK().Invoke();\n end;\n \n+ [ModalPageHandler]\n+ [Scope('OnPrem')]\n+ procedure ItemTrackingAssignLotNoPageHandler(var ItemTrackingLines: TestPage \"Item Tracking Lines\")\n+ var\n+ DequeueVariable: Variant;\n+ begin\n+ LibraryVariableStorage.Dequeue(DequeueVariable);\n+ ItemTrackingMode := DequeueVariable;\n+ case ItemTrackingMode of\n+ ItemTrackingMode::\"Assign Lot No.\":\n+ begin\n+ ItemTrackingLines.\"Lot No.\".SetValue(LibraryVariableStorage.DequeueText());\n+ LibraryVariableStorage.Dequeue(DequeueVariable);\n+ ItemTrackingLines.\"Quantity (Base)\".SetValue(DequeueVariable);\n+ end;\n+ end;\n+ ItemTrackingLines.OK().Invoke();\n+ end;\n+\n+ [ModalPageHandler]\n+ [Scope('OnPrem')]\n+ procedure ProductionJournalPageHandlerOnlyConsumption(var ProductionJournal: TestPage \"Production Journal\")\n+ var\n+ EntryType: Enum \"Item Ledger Entry Type\";\n+ begin\n+ Assert.IsTrue(ProductionJournal.FindFirstField(ProductionJournal.\"Entry Type\", EntryType::Output), '');\n+ ProductionJournal.\"Output Quantity\".SetValue(0);\n+ Assert.IsTrue(ProductionJournal.FindFirstField(ProductionJournal.\"Entry Type\", EntryType::Consumption), '');\n+ ProductionJournal.Quantity.SetValue(LibraryVariableStorage.DequeueDecimal());\n+ ProductionJournal.ItemTrackingLines.Invoke();\n+ ProductionJournal.Post.Invoke();\n+ end;\n+\n [PageHandler]\n procedure BOMStructurePageHandler(var BOMStructure: TestPage \"BOM Structure\")\n begin\n@@ -6840,5 +6973,74 @@ codeunit 137404 \"SCM Manufacturing\"\n DT2Time(ExpStartDateTime), DT2Time(ProdOrderLine.\"Starting Date-Time\"), StrSubstNo(WrongDateTimeErr, ProdOrderLine.FieldCaption(\"Starting Time\")));\n until ProdOrderLine.Next() = 0;\n end;\n+\n+ local procedure CreateItemWithUOM(\n+ var Item: Record Item;\n+ var UnitOfMeasure: Record \"Unit of Measure\";\n+ var ItemUnitOfMeasure: Record \"Item Unit of Measure\")\n+ begin\n+ LibraryInventory.CreateItem(Item);\n+\n+ LibraryInventory.CreateItemUnitOfMeasure(\n+ ItemUnitOfMeasure,\n+ Item.\"No.\",\n+ UnitOfMeasure.Code,\n+ LibraryRandom.RandInt(0));\n+\n+ Item.Validate(\"Base Unit of Measure\", UnitOfMeasure.Code);\n+ Item.Modify(true);\n+ end;\n+\n+ local procedure CreateAndPostItemJournalLineWithLotNo(\n+ ItemNo: Code[20];\n+ Quantity: Decimal;\n+ LotNo: Code[50];\n+ BinCode: Code[20];\n+ LocationCode: Code[10];\n+ Tracking: Boolean)\n+ var\n+ ItemJournalLine: Record \"Item Journal Line\";\n+ begin\n+ CreateItemJournalLine(ItemJournalLine, ItemNo, Quantity, BinCode, LocationCode);\n+ if Tracking then begin\n+ LibraryVariableStorage.Enqueue(ItemTrackingMode::\"Assign Lot No.\");\n+ LibraryVariableStorage.Enqueue(LotNo);\n+ LibraryVariableStorage.Enqueue(Quantity);\n+ ItemJournalLine.OpenItemTrackingLines(false);\n+ end;\n+ LibraryInventory.PostItemJournalLine(ItemJournalLine.\"Journal Template Name\", ItemJournalLine.\"Journal Batch Name\");\n+ end;\n+\n+ local procedure CreateItemJournalLine(var ItemJournalLine: Record \"Item Journal Line\"; ItemNo: Code[20]; Quantity: Decimal; BinCode: Code[20]; LocationCode: Code[10])\n+ var\n+ ItemJournalTemplate: Record \"Item Journal Template\";\n+ ItemJournalBatch: Record \"Item Journal Batch\";\n+ begin\n+ LibraryInventory.ClearItemJournal(ItemJournalTemplate, ItemJournalBatch);\n+ LibraryInventory.CreateItemJournalTemplate(ItemJournalTemplate);\n+ LibraryInventory.CreateItemJournalBatch(ItemJournalBatch, ItemJournalTemplate.Name);\n+ LibraryInventory.CreateItemJournalLine(\n+ ItemJournalLine,\n+ ItemJournalBatch.\"Journal Template Name\",\n+ ItemJournalBatch.Name,\n+ ItemJournalLine.\"Entry Type\"::\"Positive Adjmt.\",\n+ ItemNo,\n+ Quantity);\n+\n+ ItemJournalLine.Validate(\"Unit Cost\", LibraryRandom.RandDec(10, 2));\n+ ItemJournalLine.Validate(\"Location Code\", LocationCode);\n+ ItemJournalLine.Validate(\"Bin Code\", BinCode);\n+ ItemJournalLine.Modify(true);\n+ end;\n+\n+ local procedure CreateAndRefreshProdOrder(var ProductionOrder: Record \"Production Order\"; Status: Enum \"Production Order Status\"; SourceNo: Code[20]; Quantity: Decimal; LocationCode: Code[10]; BinCode: Code[20])\n+ begin\n+ LibraryManufacturing.CreateProductionOrder(ProductionOrder, Status, ProductionOrder.\"Source Type\"::Item, SourceNo, Quantity);\n+ ProductionOrder.Validate(\"Location Code\", LocationCode);\n+ ProductionOrder.Validate(\"Bin Code\", BinCode);\n+ ProductionOrder.Modify(true);\n+\n+ LibraryManufacturing.RefreshProdOrder(ProductionOrder, false, true, true, true, false);\n+ end;\n }\n \n", "patch": "diff --git a/App/Layers/W1/BaseApp/Inventory/Posting/ItemJnlPostLine.Codeunit.al b/App/Layers/W1/BaseApp/Inventory/Posting/ItemJnlPostLine.Codeunit.al\nindex 7e739c297201..ffe0b880ce8d 100644\n--- a/App/Layers/W1/BaseApp/Inventory/Posting/ItemJnlPostLine.Codeunit.al\n+++ b/App/Layers/W1/BaseApp/Inventory/Posting/ItemJnlPostLine.Codeunit.al\n@@ -1946,8 +1946,11 @@ codeunit 22 \"Item Jnl.-Post Line\"\n Abs(ItemLedgEntry.\"Remaining Quantity\" - ItemLedgEntry.\"Reserved Quantity\")\n then\n AppliedQty := ItemLedgEntry.\"Remaining Quantity\" - ItemLedgEntry.\"Reserved Quantity\"\n- else\n+ else begin\n AppliedQty := -(OldItemLedgEntry.\"Remaining Quantity\" - OldItemLedgEntry.\"Reserved Quantity\");\n+ if AppliedQty = 0 then\n+ AppliedQty := UpdateAppliedQtyIfConsumptionEntry(ItemLedgEntry, OldItemLedgEntry);\n+ end;\n \n OnApplyItemLedgEntryOnAfterCalcAppliedQty(OldItemLedgEntry, ItemLedgEntry, AppliedQty);\n \n@@ -5908,6 +5911,17 @@ codeunit 22 \"Item Jnl.-Post Line\"\n (ItemJournalLine.\"Applies-to Entry\" <> 0)));\n end;\n \n+ local procedure UpdateAppliedQtyIfConsumptionEntry(ItemLedgerEntry: Record \"Item Ledger Entry\"; OldItemLedgerEntry: Record \"Item Ledger Entry\"): Decimal\n+ begin\n+ if ItemLedgerEntry.\"Entry Type\" <> ItemLedgerEntry.\"Entry Type\"::Consumption then\n+ exit(0);\n+\n+ if (ItemLedgerEntry.\"Remaining Quantity\" + OldItemLedgerEntry.\"Remaining Quantity\") > 0 then\n+ exit(0);\n+\n+ exit(-Abs(OldItemLedgerEntry.\"Reserved Quantity\"));\n+ end;\n+\n [IntegrationEvent(false, false)]\n local procedure OnBeforeAllowProdApplication(OldItemLedgerEntry: Record \"Item Ledger Entry\"; ItemLedgerEntry: Record \"Item Ledger Entry\"; var AllowApplication: Boolean)\n begin\n"} {"metadata": {"area": "inventory", "image_count": 7}, "repo": "microsoftInternal/NAV", "instance_id": "microsoftInternal__NAV-176082", "base_commit": "cb30d50fe1ed2c716c6349370fdc31c6bd0ce956", "created_at": "2024-02-23", "environment_setup_version": "24.0", "project_paths": ["App\\Layers\\W1\\BaseApp", "App\\Layers\\W1\\Tests\\TestLibraries", "App\\Layers\\W1\\Tests\\SCM"], "FAIL_TO_PASS": [{"codeunitID": 137038, "functionName": ["GetReceiptLinesShowListOfPostedPurchRcptsHavingTransferFromCodeInLocationCodeOfPurchRcptLines"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/App/Layers/W1/Tests/SCM/SCMTransfers.Codeunit.al b/App/Layers/W1/Tests/SCM/SCMTransfers.Codeunit.al\nindex e0b3ba5f0bf7..ffa98cfbb351 100644\n--- a/App/Layers/W1/Tests/SCM/SCMTransfers.Codeunit.al\n+++ b/App/Layers/W1/Tests/SCM/SCMTransfers.Codeunit.al\n@@ -48,6 +48,7 @@\n UndoneTransLineQtyErr: Label 'Expected Quantity to be 0 after Transfer Shipment was undone';\n DerivedTransLineErr: Label 'Expected no Derived Transfer Line i.e. line with \"Derived From Line No.\" equal to original transfer line.';\n IncorrectSNUndoneErr: Label 'The Serial No. of the item on the transfer shipment line that was undone was different from the SN on the corresponding transfer line.';\n+ ApplToItemEntryErr: Label '%1 must be %2 in %3.', Comment = '%1 is Appl-to Item Entry, %2 is Item Ledger Entry No. and %3 is Transfer Line';\n \n [Test]\n [HandlerFunctions('MessageHandler')]\n@@ -3655,6 +3656,99 @@\n ItemLedgerEntry.TestField(\"Cost Amount (Actual)\", NewCost);\n end;\n \n+ [Test]\n+ [Scope('OnPrem')]\n+ [HandlerFunctions('PostedPurchaseReceiptsModalPageHandler,PostedPurchRcptLinesModalPageHandler')]\n+ procedure GetReceiptLinesShowListOfPostedPurchRcptsHavingTransferFromCodeInLocationCodeOfPurchRcptLines()\n+ var\n+ Item: Record Item;\n+ Vendor: Record Vendor;\n+ Location: Record Location;\n+ Location2: Record Location;\n+ Location3: Record Location;\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseHeader2: Record \"Purchase Header\";\n+ PurchaseHeader3: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ PurchaseLine2: Record \"Purchase Line\";\n+ PurchaseLine3: Record \"Purchase Line\";\n+ ItemLedgerEntry: Record \"Item Ledger Entry\";\n+ TransferHeader: Record \"Transfer Header\";\n+ TransferLine: Record \"Transfer Line\";\n+ PurchRcptLine: Record \"Purch. Rcpt. Line\";\n+ ItemLedgerEntryNo: Integer;\n+ PurchaseReceiptNo: Code[20];\n+ TransferOrder: TestPage \"Transfer Order\";\n+ begin\n+ // [SCENARIO 500597] Get Receipt Lines action on Transfer Order shows list of Posted Purchase Receipts having Transfer-from Code in Location Code of Purch Rcpt Lines and after selecting it populates Appl-to Item Entry field in Transfer Lines.\n+ Initialize();\n+\n+ // [GIVEN] Create an Item and Validate Costing Method.\n+ LibraryInventory.CreateItem(Item);\n+ Item.Validate(\"Costing Method\", Item.\"Costing Method\"::FIFO);\n+ Item.Modify(true);\n+\n+ // [GIVEN] Create two Locations with Inventory Posting Setup.\n+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);\n+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location2);\n+\n+ // [GIVEN] Create another Location with Inventory Posting Setup \n+ // And Validate Use As In-Transit.\n+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location3);\n+ Location3.Validate(\"Use As In-Transit\", true);\n+ Location3.Modify(true);\n+\n+ // [GIVEN] Create a Vendor.\n+ LibraryPurchase.CreateVendor(Vendor);\n+\n+ // [GIVEN] Create and Post Purchase Receipt with Location Code on Header.\n+ CreateAndPostPurchRcptWithLocationCodeInPurchHeader(PurchaseHeader, PurchaseLine, Vendor, Item, Location);\n+\n+ // [GIVEN] Create and Post Purchase Receipt 2 with Location Code on Header.\n+ CreateAndPostPurchRcptWithLocationCodeInPurchHeader(PurchaseHeader2, PurchaseLine2, Vendor, Item, Location);\n+\n+ // [GIVEN] Create and Post Purchase Receipt 3 with Location Code on Line.\n+ PurchaseReceiptNo := CreateAndPostPurchRcptWithLocationCodeInPurchLine(\n+ PurchaseHeader3,\n+ PurchaseLine3,\n+ Vendor,\n+ Item,\n+ Location);\n+\n+ // [GIVEN] Find and save Item Ledger Entry No. in a Variable.\n+ ItemLedgerEntry.SetRange(\"Document No.\", PurchaseReceiptNo);\n+ ItemLedgerEntry.FindFirst();\n+ ItemLedgerEntryNo := ItemLedgerEntry.\"Entry No.\";\n+\n+ // [GIVEN] Find Purch. Rcpt Line.\n+ FindRandomReceiptLine(PurchaseReceiptNo, PurchRcptLine);\n+\n+ // [GIVEN] Create Transfer Header.\n+ LibraryInventory.CreateTransferHeader(TransferHeader, Location.Code, Location2.Code, Location3.Code);\n+\n+ // [GIVEN] Open Transfer Order page and run Get Receipt Line action.\n+ TransferOrder.OpenEdit();\n+ TransferOrder.GoToRecord(TransferHeader);\n+ LibraryVariableStorage.Enqueue(PurchaseReceiptNo);\n+ LibraryVariableStorage.Enqueue(PurchaseReceiptNo);\n+ LibraryVariableStorage.Enqueue(PurchRcptLine.\"No.\");\n+ TransferOrder.GetReceiptLines.Invoke();\n+\n+ // [WHEN] Find Transfer Line.\n+ TransferLine.SetRange(\"Document No.\", TransferHeader.\"No.\");\n+ TransferLine.FindFirst();\n+\n+ // [VERIFY] Appl-to Item Entry and Item Ledger Entry No. are same.\n+ Assert.AreEqual(\n+ ItemLedgerEntryNo,\n+ TransferLine.\"Appl.-to Item Entry\",\n+ StrSubstNo(\n+ ApplToItemEntryErr,\n+ TransferLine.FieldCaption(\"Appl.-to Item Entry\"),\n+ ItemLedgerEntryNo,\n+ TransferLine.TableCaption));\n+ end;\n+\n local procedure Initialize()\n var\n LibraryERMCountryData: Codeunit \"Library - ERM Country Data\";\n@@ -5168,6 +5262,52 @@\n Assert.AreEqual(LineCount, TransferReceiptLine.Count(), '');\n end;\n \n+ local procedure CreateAndPostPurchRcptWithLocationCodeInPurchHeader(\n+ var PurchaseHeader: Record \"Purchase Header\";\n+ var PurchaseLine: Record \"Purchase Line\";\n+ Vendor: Record Vendor;\n+ Item: Record Item;\n+ Location: Record Location)\n+ begin\n+ LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader.\"Document Type\"::Order, Vendor.\"No.\");\n+ PurchaseHeader.Validate(\"Location Code\", Location.Code);\n+ PurchaseHeader.Modify(true);\n+\n+ LibraryPurchase.CreatePurchaseLine(\n+ PurchaseLine,\n+ PurchaseHeader,\n+ PurchaseLine.Type::Item,\n+ Item.\"No.\",\n+ LibraryRandom.RandIntInRange(10, 10));\n+\n+ PurchaseLine.Validate(\"Direct Unit Cost\", LibraryRandom.RandInt(15000));\n+ PurchaseLine.Modify(true);\n+\n+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false);\n+ end;\n+\n+ local procedure CreateAndPostPurchRcptWithLocationCodeInPurchLine(\n+ var PurchaseHeader: Record \"Purchase Header\";\n+ var PurchaseLine: Record \"Purchase Line\";\n+ Vendor: Record Vendor;\n+ Item: Record Item;\n+ Location: Record Location): Code[20]\n+ begin\n+ LibraryPurchase.CreatePurchHeader(PurchaseHeader, PurchaseHeader.\"Document Type\"::Order, Vendor.\"No.\");\n+ LibraryPurchase.CreatePurchaseLine(\n+ PurchaseLine,\n+ PurchaseHeader,\n+ PurchaseLine.Type::Item,\n+ Item.\"No.\",\n+ LibraryRandom.RandIntInRange(10, 10));\n+\n+ PurchaseLine.Validate(\"Location Code\", Location.Code);\n+ PurchaseLine.Validate(\"Direct Unit Cost\", LibraryRandom.RandInt(15000));\n+ PurchaseLine.Modify(true);\n+\n+ exit(LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false));\n+ end;\n+\n [MessageHandler]\n [Scope('OnPrem')]\n procedure MessageHandler(Message: Text[1024])\n@@ -5394,5 +5534,19 @@\n // 0 = Item.Type::Inventory\n Assert.AreEqual('0', ItemList.Filter.GetFilter(\"Type\"), 'Item List contains non-inventory items.');\n end;\n+\n+ [ModalPageHandler]\n+ [Scope('OnPrem')]\n+ procedure PostedPurchRcptLinesModalPageHandler(var PostedPurchaseReceiptLines: Page \"Posted Purchase Receipt Lines\"; var Response: Action)\n+ var\n+ PurchRcptLine: Record \"Purch. Rcpt. Line\";\n+ begin\n+ PurchRcptLine.SetRange(\"Document No.\", LibraryVariableStorage.DequeueText());\n+ PurchRcptLine.SetRange(\"No.\", LibraryVariableStorage.DequeueText());\n+ PurchRcptLine.FindFirst();\n+ PostedPurchaseReceiptLines.SetRecord(PurchRcptLine);\n+\n+ Response := ACTION::LookupOK;\n+ end;\n }\n \n", "patch": "diff --git a/App/Layers/W1/BaseApp/Inventory/Transfer/TransferHeader.Table.al b/App/Layers/W1/BaseApp/Inventory/Transfer/TransferHeader.Table.al\nindex 5fe44b4568d1..c16ab8669925 100644\n--- a/App/Layers/W1/BaseApp/Inventory/Transfer/TransferHeader.Table.al\n+++ b/App/Layers/W1/BaseApp/Inventory/Transfer/TransferHeader.Table.al\n@@ -1304,7 +1304,7 @@ table 5740 \"Transfer Header\"\n TempPurchRcptHeader: Record \"Purch. Rcpt. Header\" temporary;\n PostedPurchaseReceipts: Page \"Posted Purchase Receipts\";\n begin\n- PurchRcptHeader.SetRange(\"Location Code\", \"Transfer-from Code\");\n+ FindPurchRcptHeader(PurchRcptHeader);\n PostedPurchaseReceipts.SetTableView(PurchRcptHeader);\n PostedPurchaseReceipts.LookupMode := true;\n if PostedPurchaseReceipts.RunModal() = ACTION::LookupOK then begin\n@@ -1376,6 +1376,8 @@ table 5740 \"Transfer Header\"\n PurchRcptLine.FilterPstdDocLnItemLedgEntries(ItemLedgerEntry);\n ItemTrackingDocMgt.CopyItemLedgerEntriesToTemp(TempItemLedgerEntry, ItemLedgerEntry);\n ItemTrackingMgt.CopyItemLedgEntryTrkgToTransferLine(TempItemLedgerEntry, TransferLine);\n+ TransferLine.\"Appl.-to Item Entry\" := ItemLedgerEntry.\"Entry No.\";\n+ TransferLine.Modify(true);\n \n OnAfterAddTransferLineFromReceiptLine(TransferLine, PurchRcptLine, TempItemLedgerEntry, Rec);\n end;\n@@ -1546,6 +1548,31 @@ table 5740 \"Transfer Header\"\n end;\n end;\n \n+ local procedure FindPurchRcptHeader(var PurchRcptHeader: Record \"Purch. Rcpt. Header\")\n+ var\n+ PurchRcptLine: Record \"Purch. Rcpt. Line\";\n+ DocumentNo: Code[20];\n+ begin\n+ PurchRcptLine.SetLoadFields(\"Document No.\", \"Location Code\");\n+ PurchRcptLine.SetCurrentKey(\"Document No.\");\n+ PurchRcptLine.SetRange(\"Location Code\", \"Transfer-from Code\");\n+ if PurchRcptLine.FindSet() then\n+ repeat\n+ GetPurchRcptHeader(PurchRcptHeader, PurchRcptLine, DocumentNo);\n+ until PurchRcptLine.Next() = 0;\n+ PurchRcptHeader.MarkedOnly(true);\n+ end;\n+\n+ local procedure GetPurchRcptHeader(var PurchRcptHeader: Record \"Purch. Rcpt. Header\"; PurchRcptLine: Record \"Purch. Rcpt. Line\"; var DocumentNo: Code[20])\n+ begin\n+ if PurchRcptLine.\"Document No.\" = DocumentNo then\n+ exit;\n+\n+ PurchRcptHeader.Get(PurchRcptLine.\"Document No.\");\n+ PurchRcptHeader.Mark(true);\n+ DocumentNo := PurchRcptLine.\"Document No.\";\n+ end;\n+\n [IntegrationEvent(false, false)]\n local procedure OnAddTransferLineFromReceiptLineOnBeforeTransferLineInsert(var TransferLine: Record \"Transfer Line\"; PurchRcptLine: Record \"Purch. Rcpt. Line\"; var TransferHeader: Record \"Transfer Header\")\n begin\n"} {"metadata": {"area": "crm", "image_count": 8}, "repo": "microsoftInternal/NAV", "instance_id": "microsoftInternal__NAV-174087", "base_commit": "74a0b7c175da3f9a272745bd34453a4712b73e7b", "created_at": "2024-02-02", "environment_setup_version": "24.0", "project_paths": ["App\\Layers\\W1\\BaseApp", "App\\Layers\\W1\\Tests\\TestLibraries", "App\\Layers\\W1\\Tests\\Marketing"], "FAIL_TO_PASS": [{"codeunitID": 136208, "functionName": ["PopulateEvaluationFieldInInteractionLogEntry"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/App/Layers/W1/Tests/Marketing/MarketingInteraction.Codeunit.al b/App/Layers/W1/Tests/Marketing/MarketingInteraction.Codeunit.al\nindex 4c4c73700d2a..59fff6e2be93 100644\n--- a/App/Layers/W1/Tests/Marketing/MarketingInteraction.Codeunit.al\n+++ b/App/Layers/W1/Tests/Marketing/MarketingInteraction.Codeunit.al\n@@ -45,6 +45,7 @@ codeunit 136208 \"Marketing Interaction\"\n LoggedSegemntEntriesCreateMsg: Label 'Logged Segment entry was created';\n AttachmentFileShouldNotBeBlankErr: Label 'Attachment File should not be blank.';\n TxtFileExt: Label 'txt';\n+ EvaluationErr: Label '%1 must be %2 in %3', Comment = '%1 = Evaluation, %2 = Positive, %3 = Interaction Log Entry';\n \n [Test]\n [Scope('OnPrem')]\n@@ -2998,6 +2999,50 @@ codeunit 136208 \"Marketing Interaction\"\n VerifyAttachmentFileIsNotBlankOnInteractionLogEntry(Contact.\"No.\");\n end;\n \n+ [Test]\n+ [Scope('OnPrem')]\n+ [HandlerFunctions('CreateInteractionFromContactPageHandler')]\n+ procedure PopulateEvaluationFieldInInteractionLogEntry()\n+ var\n+ Contact: Record Contact;\n+ InteractionTemplate: Record \"Interaction Template\";\n+ InteractionLogEntry: Record \"Interaction Log Entry\";\n+ ContactCard: TestPage \"Contact Card\";\n+ InteractionEvaluation: Enum \"Interaction Evaluation\";\n+ begin\n+ // [SCENARIO 498395] When stan creates an Interaction using Create Interaction action from Contact, Evaluation field should be populated in Interaction Log Entry.\n+ Initialize();\n+\n+ // [GIVEN] Create a Contact.\n+ LibraryMarketing.CreateCompanyContact(Contact);\n+\n+ // [GIVEN] Create an Interaction Template and Validate Information Flow.\n+ LibraryMarketing.CreateInteractionTemplate(InteractionTemplate);\n+ InteractionTemplate.Validate(\"Information Flow\", InteractionTemplate.\"Information Flow\"::Outbound);\n+ InteractionTemplate.Modify(true);\n+\n+ // [GIVEN] Open Contact Card and Create Interaction.\n+ ContactCard.OpenEdit();\n+ ContactCard.GoToRecord(Contact);\n+ LibraryVariableStorage.Enqueue(InteractionTemplate.Code);\n+ LibraryVariableStorage.Enqueue(Format(InteractionEvaluation::Positive));\n+ ContactCard.\"Create &Interaction\".Invoke();\n+\n+ // [WHEN] Find Interaction Log Entry.\n+ InteractionLogEntry.SetRange(\"Contact No.\", Contact.\"No.\");\n+ InteractionLogEntry.FindFirst();\n+\n+ // [VERIFY] Interaction Log Entry has Evaluation field populated as Positive.\n+ Assert.AreEqual(\n+ InteractionEvaluation::Positive,\n+ InteractionLogEntry.Evaluation,\n+ StrSubstNo(\n+ EvaluationErr,\n+ InteractionLogEntry.FieldCaption(Evaluation),\n+ InteractionEvaluation::Positive,\n+ InteractionLogEntry.TableCaption));\n+ end;\n+\n local procedure Initialize()\n var\n LibrarySales: Codeunit \"Library - Sales\";\n@@ -4309,5 +4354,16 @@ CopyStr(StorageLocation, 1, MaxStrLen(MarketingSetup.\"Attachment Storage Locatio\n CreateInteraction.NextInteraction.Invoke();\n CreateInteraction.Finish.Invoke();\n end;\n+\n+ [ModalPageHandler]\n+ [Scope('OnPrem')]\n+ procedure CreateInteractionFromContactPageHandler(var CreateInteraction: TestPage \"Create Interaction\")\n+ begin\n+ CreateInteraction.\"Interaction Template Code\".SetValue(LibraryVariableStorage.DequeueText());\n+ CreateInteraction.NextInteraction.Invoke();\n+ CreateInteraction.NextInteraction.Invoke();\n+ CreateInteraction.Evaluation.SetValue(LibraryVariableStorage.DequeueText());\n+ CreateInteraction.FinishInteraction.Invoke();\n+ end;\n }\n \n", "patch": "diff --git a/App/Layers/W1/BaseApp/CRM/Segment/CreateInteraction.Page.al b/App/Layers/W1/BaseApp/CRM/Segment/CreateInteraction.Page.al\nindex ff43f4ff6a7b..05a21a6196bf 100644\n--- a/App/Layers/W1/BaseApp/CRM/Segment/CreateInteraction.Page.al\n+++ b/App/Layers/W1/BaseApp/CRM/Segment/CreateInteraction.Page.al\n@@ -694,6 +694,7 @@ page 5077 \"Create Interaction\"\n end;\n Step::\"Step 4\":\n begin\n+ InteractionLogEntry.CopyFromSegment(Rec);\n InteractionLogEntry.Modify();\n CurrPage.Close();\n end;\n"} +{"metadata": {"area": "peppol", "image_count": 1}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8059", "base_commit": "396e3bb12d0593738c9368371d6273a6d41c6826", "created_at": "2026-05-08T09:31:42Z", "environment_setup_version": "28.1", "project_paths": ["src\\Apps\\W1\\PEPPOL\\App", "src\\Apps\\W1\\PEPPOL\\Test"], "patch": "diff --git a/src/Apps/W1/PEPPOL/App/src/Common/PEPPOL30Impl.Codeunit.al b/src/Apps/W1/PEPPOL/App/src/Common/PEPPOL30Impl.Codeunit.al\nindex 30f5f792bd..c7981a46fa 100644\n--- a/src/Apps/W1/PEPPOL/App/src/Common/PEPPOL30Impl.Codeunit.al\n+++ b/src/Apps/W1/PEPPOL/App/src/Common/PEPPOL30Impl.Codeunit.al\n@@ -798,6 +798,8 @@ codeunit 37201 \"PEPPOL30 Impl.\"\n InvoiceLineNote := DelChr(Format(SalesLine.Type), '<>');\n InvoicedQuantity := Format(SalesLine.Quantity, 0, 9);\n SalesLineLineAmount := SalesLine.\"Line Amount\";\n+ if SalesHeader.\"Prices Including VAT\" and (SalesLine.\"VAT %\" <> 0) then\n+ SalesLineLineAmount := Round(SalesLineLineAmount / (1 + SalesLine.\"VAT %\" / 100), 0.01);\n InvoiceLineExtensionAmount := Format(SalesLineLineAmount, 0, 9);\n LineExtensionAmountCurrencyID := GetSalesDocCurrencyCode(SalesHeader);\n InvoiceLineAccountingCost := '';\n@@ -869,7 +871,10 @@ codeunit 37201 \"PEPPOL30 Impl.\"\n \n InvLnAllowanceChargeIndicator := 'false';\n InvLnAllowanceChargeReason := LineDisAmtTxt;\n- InvLnAllowanceChargeAmount := Format(SalesLine.\"Line Discount Amount\", 0, 9);\n+ if SalesHeader.\"Prices Including VAT\" and (SalesLine.\"VAT %\" <> 0) then\n+ InvLnAllowanceChargeAmount := Format(Round(SalesLine.\"Line Discount Amount\" / (1 + SalesLine.\"VAT %\" / 100), 0.01), 0, 9)\n+ else\n+ InvLnAllowanceChargeAmount := Format(SalesLine.\"Line Discount Amount\", 0, 9);\n InvLnAllowanceChargeAmtCurrID := GetSalesDocCurrencyCode(SalesHeader);\n end;\n \n", "FAIL_TO_PASS": [{"codeunitID": 139235, "functionName": ["LineAmountsConsistentWhenPricesInclVATNoDiscount"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/PEPPOL/Test/src/PEPPOL30ManagementTests.Codeunit.al b/src/Apps/W1/PEPPOL/Test/src/PEPPOL30ManagementTests.Codeunit.al\nindex 36931d56ed..cd237011d5 100644\n--- a/src/Apps/W1/PEPPOL/Test/src/PEPPOL30ManagementTests.Codeunit.al\n+++ b/src/Apps/W1/PEPPOL/Test/src/PEPPOL30ManagementTests.Codeunit.al\n@@ -3349,6 +3349,68 @@ codeunit 139235 \"PEPPOL30 Management Tests\"\n Assert.AreEqual('', CustTaxSchemeID, 'Tax Scheme ID should be empty for Tax Category O.');\n end;\n \n+ [Test]\n+ [Scope('OnPrem')]\n+ procedure LineAmountsConsistentWhenPricesInclVATNoDiscount()\n+ var\n+ SalesHeader: Record \"Sales Header\";\n+ SalesLine: Record \"Sales Line\";\n+ Customer: Record Customer;\n+ Item: Record Item;\n+ SalesInvoiceHeader: Record \"Sales Invoice Header\";\n+ SalesInvoiceLine: Record \"Sales Invoice Line\";\n+ PEPPOLLineInfoProvider: Interface \"PEPPOL Line Info Provider\";\n+ InvoiceLineID: Text;\n+ InvoiceLineNote: Text;\n+ InvoicedQuantity: Text;\n+ InvoiceLineExtensionAmount: Text;\n+ LineExtensionAmountCurrencyID: Text;\n+ InvoiceLineAccountingCost: Text;\n+ InvoiceLinePriceAmount: Text;\n+ InvLinePriceAmountCurrencyID: Text;\n+ BaseQuantity: Text;\n+ UnitCode: Text;\n+ PriceAmount: Decimal;\n+ LineExtensionAmt: Decimal;\n+ SalesInvoiceNo: Code[20];\n+ begin\n+ // [FEATURE] [AI test 0.4]\n+ // [SCENARIO 630795] PEPPOL LineExtensionAmount equals PriceAmount times Quantity when Prices Including VAT is used\n+ Initialize();\n+\n+ // [GIVEN] Customer \"C\" with PEPPOL identifier\n+ LibrarySales.CreateCustomer(Customer);\n+ AddCustPEPPOLIdentifier(Customer.\"No.\");\n+\n+ // [GIVEN] Sales Invoice for \"C\" with \"Prices Including VAT\" = TRUE and Quantity = 7\n+ CreateItemWithPrice(Item, 139);\n+ LibrarySales.CreateSalesHeader(SalesHeader, SalesHeader.\"Document Type\"::Invoice, Customer.\"No.\");\n+ SalesHeader.Validate(\"Prices Including VAT\", true);\n+ SalesHeader.Modify(true);\n+ LibrarySales.CreateSalesLine(SalesLine, SalesHeader, SalesLine.Type::Item, Item.\"No.\", 7);\n+\n+ // [WHEN] Post the Sales Invoice and retrieve PEPPOL line amounts\n+ SalesInvoiceNo := LibrarySales.PostSalesDocument(SalesHeader, true, true);\n+ SalesInvoiceHeader.Get(SalesInvoiceNo);\n+ SalesHeader.TransferFields(SalesInvoiceHeader);\n+ FindSalesInvoiceLine(SalesInvoiceLine, SalesInvoiceNo);\n+ SalesLine.TransferFields(SalesInvoiceLine);\n+\n+ PEPPOLLineInfoProvider := GetFormat();\n+ PEPPOLLineInfoProvider.GetLineGeneralInfo(\n+ SalesLine, SalesHeader, InvoiceLineID, InvoiceLineNote, InvoicedQuantity,\n+ InvoiceLineExtensionAmount, LineExtensionAmountCurrencyID, InvoiceLineAccountingCost);\n+ PEPPOLLineInfoProvider.GetLinePriceInfo(\n+ SalesLine, SalesHeader, InvoiceLinePriceAmount, InvLinePriceAmountCurrencyID,\n+ BaseQuantity, UnitCode);\n+\n+ // [THEN] LineExtensionAmount equals PriceAmount times Quantity per PEPPOL BIS 3.0\n+ Evaluate(PriceAmount, InvoiceLinePriceAmount, 9);\n+ Evaluate(LineExtensionAmt, InvoiceLineExtensionAmount, 9);\n+ Assert.AreEqual(PriceAmount * SalesInvoiceLine.Quantity, LineExtensionAmt,\n+ 'LineExtensionAmount must equal PriceAmount * Quantity per PEPPOL BIS 3.0');\n+ end;\n+\n var\n local procedure Initialize()\n var\n@@ -3993,6 +4055,8 @@ codeunit 139235 \"PEPPOL30 Management Tests\"\n Assert.AreEqual(UnitOfMeasure.\"International Standard Code\", unitCode, '');\n Assert.AreEqual('UNECERec20', unitCodeListID, '');\n SalesInvoiceLineLineAmount := SalesInvoiceLine.\"Line Amount\";\n+ if SalesHeader.\"Prices Including VAT\" and (SalesLine.\"VAT %\" <> 0) then\n+ SalesInvoiceLineLineAmount := Round(SalesInvoiceLineLineAmount / (1 + SalesLine.\"VAT %\" / 100), 0.01);\n Assert.AreEqual(Format(SalesInvoiceLineLineAmount, 0, 9), InvoiceLineExtensionAmount, '');\n Assert.AreEqual(SalesHeader.\"Currency Code\", LineExtensionAmountCurrencyID, '');\n Assert.AreEqual('', InvoiceLineAccountingCost, '');\n"} +{"metadata": {"area": null, "image_count": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8293", "base_commit": "01e67dc5ff263b26101f7f2db6caa1b346f090a6", "created_at": "2026-05-25T21:31:15Z", "environment_setup_version": "28.1", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcProdOFactboxMgmt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcProdOFactboxMgmt.Codeunit.al\nindex 8d5c75124c..056de67a1c 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcProdOFactboxMgmt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcProdOFactboxMgmt.Codeunit.al\n@@ -15,12 +15,13 @@ using System.Reflection;\n codeunit 99001559 \"Subc. ProdO. Factbox Mgmt.\"\n {\n /// \n- /// Opens the Released Production Order page for the production order linked to the given variant record.\n+ /// Opens the appropriate Production Order page (Released or Finished) for the production order linked to the given variant record.\n /// \n /// A record variant of a purchase or transfer document line.\n procedure ShowProductionOrder(RecRelatedVariant: Variant)\n var\n ProductionOrder: Record \"Production Order\";\n+ FinishedProductionOrder: Page \"Finished Production Order\";\n ReleasedProductionOrder: Page \"Released Production Order\";\n OperationNo: Code[10];\n ProdOrderNo: Code[20];\n@@ -29,11 +30,26 @@ codeunit 99001559 \"Subc. ProdO. Factbox Mgmt.\"\n begin\n if not SetProdOrderInformationByVariant(RecRelatedVariant, ProdOrderNo, ProdOrderLineNo, RoutingNo, OperationNo) then\n exit;\n- ProductionOrder.SetRange(Status, ProductionOrder.Status::Released);\n+ ProductionOrder.SetFilter(Status, '>=%1', ProductionOrder.Status::Released);\n ProductionOrder.SetRange(\"No.\", ProdOrderNo);\n- ReleasedProductionOrder.SetTableView(ProductionOrder);\n- ReleasedProductionOrder.Editable := false;\n- ReleasedProductionOrder.Run();\n+ if not ProductionOrder.FindFirst() then\n+ exit;\n+ case ProductionOrder.Status of\n+ ProductionOrder.Status::Released:\n+ begin\n+ ProductionOrder.SetRange(Status, ProductionOrder.Status::Released);\n+ ReleasedProductionOrder.SetTableView(ProductionOrder);\n+ ReleasedProductionOrder.Editable := false;\n+ ReleasedProductionOrder.Run();\n+ end;\n+ ProductionOrder.Status::Finished:\n+ begin\n+ ProductionOrder.SetRange(Status, ProductionOrder.Status::Finished);\n+ FinishedProductionOrder.SetTableView(ProductionOrder);\n+ FinishedProductionOrder.Editable := false;\n+ FinishedProductionOrder.Run();\n+ end;\n+ end;\n end;\n \n /// \n@@ -77,9 +93,9 @@ codeunit 99001559 \"Subc. ProdO. Factbox Mgmt.\"\n exit(ProdOrderRoutingLine.Count());\n end;\n \n-local procedure SetFilterProductionOrderRouting(var ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; ProdOrderNo: Code[20]; ProdOrderLineNo: Integer; RoutingNo: Code[20]; OperationNo: Code[10])\n+ local procedure SetFilterProductionOrderRouting(var ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; ProdOrderNo: Code[20]; ProdOrderLineNo: Integer; RoutingNo: Code[20]; OperationNo: Code[10])\n begin\n- ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released);\n+ ProdOrderRoutingLine.SetFilter(Status, '>=%1', ProdOrderRoutingLine.Status::Released);\n ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProdOrderNo);\n ProdOrderRoutingLine.SetRange(\"Routing Reference No.\", ProdOrderLineNo);\n ProdOrderRoutingLine.SetRange(\"Routing No.\", RoutingNo);\n@@ -130,7 +146,7 @@ local procedure SetFilterProductionOrderRouting(var ProdOrderRoutingLine: Record\n ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n begin\n ProdOrderRoutingLine.SetLoadFields(\"Routing Link Code\");\n- ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released);\n+ ProdOrderRoutingLine.SetFilter(Status, '>=%1', ProdOrderRoutingLine.Status::Released);\n ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProdOrderNo);\n ProdOrderRoutingLine.SetRange(\"Routing Reference No.\", ProdOrderLineNo);\n ProdOrderRoutingLine.SetRange(\"Routing No.\", RoutingNo);\n@@ -138,7 +154,7 @@ local procedure SetFilterProductionOrderRouting(var ProdOrderRoutingLine: Record\n if ProdOrderRoutingLine.FindFirst() then\n ProdOrderComponent.SetRange(\"Routing Link Code\", ProdOrderRoutingLine.\"Routing Link Code\");\n \n- ProdOrderComponent.SetRange(Status, ProdOrderComponent.Status::Released);\n+ ProdOrderComponent.SetFilter(Status, '>=%1', ProdOrderComponent.Status::Released);\n ProdOrderComponent.SetRange(\"Prod. Order No.\", ProdOrderNo);\n ProdOrderComponent.SetRange(\"Prod. Order Line No.\", ProdOrderLineNo);\n end;\n", "FAIL_TO_PASS": [{"codeunitID": 139989, "functionName": ["ProdOFactboxMgmtShowsDataAfterProdOrderFinished"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\nindex 68c7fff2af..c6c56da2b8 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n@@ -1875,6 +1875,57 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n 'CalcNoOfProductionOrderComponents should return a positive count for an Item Ledger Entry from a subcontracting receipt.');\n end;\n \n+ [Test]\n+ [HandlerFunctions('ConfirmArchiveOrderHandler,HandlePurchaseOrderPage')]\n+ procedure ProdOFactboxMgmtShowsDataAfterProdOrderFinished()\n+ var\n+ Item: Record Item;\n+ ProductionOrder: Record \"Production Order\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ SubcWorkCenter: Record \"Work Center\";\n+ SubcProdOFactboxMgmt: Codeunit \"Subc. ProdO. Factbox Mgmt.\";\n+ begin\n+ // [SCENARIO 634953] Subcontracting factbox drilldowns should work after production order is finished.\n+ Initialize();\n+\n+ // [GIVEN] A released production order with a subcontracting routing operation and a subcontracting purchase order\n+ Subcontracting := true;\n+ UnitCostCalculation := UnitCostCalculation::Units;\n+\n+ CreateItemWithSingleSubcontractingOperation(Item, SubcWorkCenter);\n+ SubcontractingMgmtLibrary.UpdateVendorWithSubcontractingLocationCode(SubcWorkCenter);\n+ SubcontractingMgmtLibrary.CreateAndRefreshProductionOrder(\n+ ProductionOrder, \"Production Order Status\"::Released, ProductionOrder.\"Source Type\"::Item, Item.\"No.\", LibraryRandom.RandInt(10) + 5);\n+ UpdateSubMgmtSetupWithReqWkshTemplate();\n+\n+ SubcontractingMgmtLibrary.CreateSubcontractingOrderFromProdOrderRtngPage(Item.\"Routing No.\", SubcWorkCenter.\"No.\");\n+ PurchaseLine.SetRange(\"Document Type\", PurchaseLine.\"Document Type\"::Order);\n+ PurchaseLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+#pragma warning disable AA0210\n+ PurchaseLine.SetRange(\"Work Center No.\", SubcWorkCenter.\"No.\");\n+#pragma warning restore AA0210\n+ PurchaseLine.FindFirst();\n+ PurchaseHeader.Get(PurchaseLine.\"Document Type\", PurchaseLine.\"Document No.\");\n+ EnsureGeneralPostingSetupIsValid(PurchaseLine.\"Gen. Bus. Posting Group\", PurchaseLine.\"Gen. Prod. Posting Group\");\n+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false);\n+\n+ // [GIVEN] The production order is changed to Finished status\n+ LibraryManufacturing.ChangeProdOrderStatus(ProductionOrder, \"Production Order Status\"::Finished, WorkDate(), true);\n+\n+ // Re-read purchase line (the order still exists because only receipt was posted)\n+ PurchaseLine.FindFirst();\n+\n+ // [WHEN] CalcNoOfProductionOrderRoutings / CalcNoOfProductionOrderComponents are called with the Purchase Line\n+ // [THEN] Both return a positive count even though the production order is now Finished\n+ Assert.IsTrue(\n+ SubcProdOFactboxMgmt.CalcNoOfProductionOrderRoutings(PurchaseLine) > 0,\n+ 'CalcNoOfProductionOrderRoutings should return a positive count after the production order is finished.');\n+ Assert.IsTrue(\n+ SubcProdOFactboxMgmt.CalcNoOfProductionOrderComponents(PurchaseLine) > 0,\n+ 'CalcNoOfProductionOrderComponents should return a positive count after the production order is finished.');\n+ end;\n+\n [Test]\n [HandlerFunctions('ConfirmHandler')]\n procedure RoutingFactboxMgmtFiltersPurchOrderQtyByRoutingReferenceNo()\n@@ -3430,6 +3481,7 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n \n SubSetupLibrary.InitSetupFields();\n LibraryERMCountryData.CreateVATData();\n+ LibraryERMCountryData.UpdateGeneralPostingSetup();\n SubSetupLibrary.InitialSetupForGenProdPostingGroup();\n \n IsInitialized := true;\n"} +{"metadata": {"area": null, "image_count": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8287", "base_commit": "ad39c988e2565d1ea1a8cb538a5b9a6ec4107eb4", "created_at": "2026-05-22T17:02:35Z", "environment_setup_version": "28.1", "project_paths": ["src\\Apps\\W1\\Quality Management\\app", "src\\Apps\\W1\\Quality Management\\test"], "patch": "diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al\nindex b8a5c1d869..c1b2942c55 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Result/QltyResultEvaluation.Codeunit.al\n@@ -22,6 +22,7 @@ codeunit 20410 \"Qlty. Result Evaluation\"\n IsDefaultTextTok: Label '<>''''', Locked = true;\n InvalidDataTypeErr: Label 'The value \"%1\" is not allowed for %2, it is not a %3.', Comment = '%1=the value, %2=field name,%3=field type.';\n NotInAllowableValuesErr: Label 'The value \"%1\" is not allowed for %2, it must be in the range of \"%3\".', Comment = '%1=the value, %2=field name,%3=field type.';\n+ InvalidAllowableValuesFormatErr: Label 'The allowable values \"%1\" are not a valid filter expression for %2 of type %3.', Comment = '%1=the allowable values, %2=field name, %3=field type.';\n \n trigger OnRun()\n var\n@@ -324,6 +325,110 @@ codeunit 20410 \"Qlty. Result Evaluation\"\n ValidateAllowableValuesOnText(TestNameForError, QltyTest.\"Default Value\", QltyTest.\"Allowable Values\", QltyTest.\"Test Value Type\", TempBufferQltyTestLookupValue, QltyCaseSensitivity);\n end;\n \n+ /// \n+ /// Validates that the allowable values expression is a valid filter for the given test value type.\n+ /// \n+ /// The test whose allowable values expression should be validated.\n+ internal procedure ValidateAllowableValuesFormat(var QltyTest: Record \"Qlty. Test\")\n+ var\n+ TestNameForError: Text;\n+ begin\n+ if QltyTest.Description <> '' then\n+ TestNameForError := QltyTest.Description\n+ else\n+ TestNameForError := QltyTest.Code;\n+\n+ ValidateAllowableValuesFormat(TestNameForError, QltyTest.\"Allowable Values\", QltyTest.\"Test Value Type\");\n+ end;\n+\n+ /// \n+ /// Validates that the allowable values expression is a valid filter for the given test value type.\n+ /// \n+ /// Friendly identifier used in error messages.\n+ /// The allowable values filter expression to validate.\n+ /// The test value type that the filter expression must match.\n+ local procedure ValidateAllowableValuesFormat(NumberOrNameOfTestNameForError: Text; AllowableValues: Text; QltyTestValueType: Enum \"Qlty. Test Value Type\")\n+ var\n+ IsValid: Boolean;\n+ begin\n+ if AllowableValues = '' then\n+ exit;\n+\n+ if IsBlankOrEmptyCondition(AllowableValues) then\n+ exit;\n+\n+ if IsAnythingExceptEmptyCondition(AllowableValues) then\n+ exit;\n+\n+ // Allowable values may contain inline expressions like [Field] that are resolved at evaluation time.\n+ // Defer validation until resolution.\n+ if AllowableValues.Contains('[') then\n+ exit;\n+\n+ IsValid := true;\n+ case QltyTestValueType of\n+ QltyTestValueType::\"Value Type Decimal\":\n+ IsValid := TryApplyDecimalFilter(AllowableValues);\n+ QltyTestValueType::\"Value Type Integer\":\n+ IsValid := TryApplyIntegerFilter(AllowableValues);\n+ QltyTestValueType::\"Value Type Boolean\":\n+ IsValid := TryApplyBooleanFilter(AllowableValues);\n+ QltyTestValueType::\"Value Type Date\":\n+ IsValid := TryApplyDateFilter(AllowableValues);\n+ QltyTestValueType::\"Value Type DateTime\":\n+ IsValid := TryApplyDateTimeFilter(AllowableValues);\n+ end;\n+\n+ if not IsValid then\n+ Error(InvalidAllowableValuesFormatErr, AllowableValues, NumberOrNameOfTestNameForError, QltyTestValueType);\n+ end;\n+\n+ [TryFunction]\n+ local procedure TryApplyDecimalFilter(FilterExpression: Text)\n+ var\n+ TempQltyInspectionLine: Record \"Qlty. Inspection Line\" temporary;\n+ begin\n+ TempQltyInspectionLine.SetFilter(\"Derived Numeric Value\", FilterExpression);\n+ if TempQltyInspectionLine.IsEmpty() then;\n+ end;\n+\n+ [TryFunction]\n+ local procedure TryApplyIntegerFilter(FilterExpression: Text)\n+ var\n+ TempInteger: Record \"Integer\" temporary;\n+ begin\n+ TempInteger.SetFilter(Number, FilterExpression);\n+ if TempInteger.IsEmpty() then;\n+ end;\n+\n+ [TryFunction]\n+ local procedure TryApplyBooleanFilter(FilterExpression: Text)\n+ var\n+ QltyBooleanParsing: Codeunit \"Qlty. Boolean Parsing\";\n+ begin\n+ // Valid boolean allowable values are: Yes, No, True, False, 1, 0, On, Off (and variations)\n+ if not QltyBooleanParsing.CanTextBeInterpretedAsBooleanIsh(FilterExpression) then\n+ Error(InvalidAllowableValuesFormatErr, FilterExpression, '', 'Boolean');\n+ end;\n+\n+ [TryFunction]\n+ local procedure TryApplyDateFilter(FilterExpression: Text)\n+ var\n+ TempDateLookupBuffer: Record \"Date Lookup Buffer\" temporary;\n+ begin\n+ TempDateLookupBuffer.SetFilter(\"Period Start\", FilterExpression);\n+ if TempDateLookupBuffer.IsEmpty() then;\n+ end;\n+\n+ [TryFunction]\n+ local procedure TryApplyDateTimeFilter(FilterExpression: Text)\n+ var\n+ TempQltyInspectionHeader: Record \"Qlty. Inspection Header\" temporary;\n+ begin\n+ TempQltyInspectionHeader.SetFilter(\"Finished Date\", FilterExpression);\n+ if TempQltyInspectionHeader.IsEmpty() then;\n+ end;\n+\n local procedure ValidateAllowableValuesOnText(NumberOrNameOfTestNameForError: Text; var TextToValidate: Text[250]; AllowableValues: Text; QltyTestValueType: Enum \"Qlty. Test Value Type\"; var TempBufferQltyTestLookupValue: Record \"Qlty. Test Lookup Value\" temporary; QltyCaseSensitivity: Enum \"Qlty. Case Sensitivity\")\n var\n QltyBooleanParsing: Codeunit \"Qlty. Boolean Parsing\";\n@@ -393,9 +498,8 @@ codeunit 20410 \"Qlty. Result Evaluation\"\n if not (IsBlankOrEmptyCondition(AllowableValues) and (TextToValidate = '')) then\n if not QltyResultEvaluation.CheckIfValueIsString(TextToValidate, ConvertStr(AllowableValues, ',', '|'), QltyCaseSensitivity) then\n Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues);\n-\n QltyTestValueType::\"Value Type Option\",\n- QltyTestValueType::\"Value Type Table Lookup\":\n+ QltyTestValueType::\"Value Type Table Lookup\":\n begin\n TextToValidate := CopyStr(TextToValidate.Trim(), 1, MaxStrLen(TextToValidate));\n \n@@ -419,6 +523,7 @@ codeunit 20410 \"Qlty. Result Evaluation\"\n Error(NotInAllowableValuesErr, TextToValidate, NumberOrNameOfTestNameForError, AllowableValues);\n end;\n end;\n+\n OnAfterValidateAllowableValuesOnText(NumberOrNameOfTestNameForError, TextToValidate, AllowableValues, QltyTestValueType, TempBufferQltyTestLookupValue, QltyCaseSensitivity);\n end;\n \n", "FAIL_TO_PASS": [{"codeunitID": 139963, "functionName": ["ValidateAllowableValuesFormat_Boolean_ValidFormats", "ValidateAllowableValuesFormat_NonValidatedTypes", "ValidateAllowableValuesFormat_Boolean_InvalidFormats", "ValidateAllowableValuesFormat_DateTime_InvalidFormats", "ValidateAllowableValuesFormat_Integer_ValidFormats", "ValidateAllowableValuesFormat_Integer_InvalidFormats", "ValidateAllowableValuesFormat_Date_InvalidFormats", "ValidateAllowableValuesFormat_Decimal_ValidFormats", "ValidateAllowableValuesFormat_Date_ValidFormats", "ValidateAllowableValuesFormat_DateTime_ValidFormats", "ValidateAllowableValuesFormat_Decimal_InvalidFormats"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\nindex 9f4cbf3006..66e4c203fc 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\n@@ -54,8 +54,11 @@ table 20401 \"Qlty. Test\"\n {\n Caption = 'Allowable Values';\n ToolTip = 'Specifies an expression for the range of values you can enter or select for the Test. Depending on the Test Value Type, the expression format varies. For example if you want a measurement such as a percentage that collects between 0 and 100 you would enter 0..100. This is not the pass or acceptable condition, these are just the technically possible values that the inspector can enter. You would then enter a passing condition in your result conditions. If you had a result of Pass being 80 to 100, you would then configure 80..100 for that result.';\n+\n trigger OnValidate()\n begin\n+ Rec.ValidateAllowableValuesFormat();\n+\n if Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Option\", Rec.\"Test Value Type\"::\"Value Type Table Lookup\"] then\n Rec.\"Allowable Values\" := CopyStr(Rec.\"Allowable Values\".Replace(', ', ','), 1, MaxStrLen(Rec.\"Allowable Values\"));\n end;\n@@ -472,6 +475,16 @@ table 20401 \"Qlty. Test\"\n QltyResultEvaluation.ValidateAllowableValuesOnTest(Rec);\n end;\n \n+ /// \n+ /// Validates that the allowable values expression is a valid filter for the test value type.\n+ /// \n+ procedure ValidateAllowableValuesFormat()\n+ var\n+ QltyResultEvaluation: Codeunit \"Qlty. Result Evaluation\";\n+ begin\n+ QltyResultEvaluation.ValidateAllowableValuesFormat(Rec);\n+ end;\n+\n /// \n /// Code = the unique code\n /// Description = raw description.\ndiff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al\nindex 91159fca6e..05f7d8a17a 100644\n--- a/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsResultEval.Codeunit.al\n@@ -2071,6 +2071,440 @@ codeunit 139963 \"Qlty. Tests - Result Eval.\"\n LibraryAssert.ExpectedError(StrSubstNo(Expected4Err, OptionListQltyInspectionLine.\"Test Code\"));\n end;\n \n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Decimal_ValidFormats()\n+ var\n+ DecimalQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid decimal filter expressions\n+\n+ // [GIVEN] A quality test with decimal type is created\n+ DecimalQltyTest.Init();\n+ DecimalQltyTest.Code := 'TESTDEC';\n+ DecimalQltyTest.Description := 'Test Decimal';\n+ DecimalQltyTest.\"Test Value Type\" := DecimalQltyTest.\"Test Value Type\"::\"Value Type Decimal\";\n+ DecimalQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to range expression \"0..100\"\n+ DecimalQltyTest.\"Allowable Values\" := '0..100';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to greater than expression \">0\"\n+ DecimalQltyTest.\"Allowable Values\" := '>0';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to less than or equal expression \"<=50\"\n+ DecimalQltyTest.\"Allowable Values\" := '<=50';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to exact value \"25.5\"\n+ DecimalQltyTest.\"Allowable Values\" := '25.5';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to list of values \"10|20|30\"\n+ DecimalQltyTest.\"Allowable Values\" := '10|20|30';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are blank\n+ DecimalQltyTest.\"Allowable Values\" := '';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values contain expression with brackets \"[Field]\"\n+ DecimalQltyTest.\"Allowable Values\" := '0..[Field]';\n+ // [THEN] ValidateAllowableValuesFormat is deferred and passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to not empty condition \"<>''\"\n+ DecimalQltyTest.\"Allowable Values\" := '<>''''';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DecimalQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Decimal_InvalidFormats()\n+ var\n+ DecimalQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid decimal filter expressions\n+\n+ // [GIVEN] A quality test with decimal type is created\n+ DecimalQltyTest.Init();\n+ DecimalQltyTest.Code := 'TESTDEC2';\n+ DecimalQltyTest.Description := 'Test Decimal Invalid';\n+ DecimalQltyTest.\"Test Value Type\" := DecimalQltyTest.\"Test Value Type\"::\"Value Type Decimal\";\n+ DecimalQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to invalid text \"not a number\"\n+ DecimalQltyTest.\"Allowable Values\" := 'not a number';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DecimalQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid operator \"==5\"\n+ DecimalQltyTest.\"Allowable Values\" := '==5';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DecimalQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Integer_ValidFormats()\n+ var\n+ IntegerQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid integer filter expressions\n+\n+ // [GIVEN] A quality test with integer type is created\n+ IntegerQltyTest.Init();\n+ IntegerQltyTest.Code := 'TESTINT';\n+ IntegerQltyTest.Description := 'Test Integer';\n+ IntegerQltyTest.\"Test Value Type\" := IntegerQltyTest.\"Test Value Type\"::\"Value Type Integer\";\n+ IntegerQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to range expression \"0..100\"\n+ IntegerQltyTest.\"Allowable Values\" := '0..100';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to greater than expression \">0\"\n+ IntegerQltyTest.\"Allowable Values\" := '>0';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to less than or equal expression \"<=50\"\n+ IntegerQltyTest.\"Allowable Values\" := '<=50';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to exact value \"25\"\n+ IntegerQltyTest.\"Allowable Values\" := '25';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to list of values \"1|2|3|4|5\"\n+ IntegerQltyTest.\"Allowable Values\" := '1|2|3|4|5';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are blank\n+ IntegerQltyTest.\"Allowable Values\" := '';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values contain expression with brackets \"[Field]\"\n+ IntegerQltyTest.\"Allowable Values\" := '1..[Field]';\n+ // [THEN] ValidateAllowableValuesFormat is deferred and passes without error\n+ IntegerQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Integer_InvalidFormats()\n+ var\n+ IntegerQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid integer filter expressions\n+\n+ // [GIVEN] A quality test with integer type is created\n+ IntegerQltyTest.Init();\n+ IntegerQltyTest.Code := 'TESTINT2';\n+ IntegerQltyTest.Description := 'Test Integer Invalid';\n+ IntegerQltyTest.\"Test Value Type\" := IntegerQltyTest.\"Test Value Type\"::\"Value Type Integer\";\n+ IntegerQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to decimal value \"1.5\"\n+ IntegerQltyTest.\"Allowable Values\" := '1.5';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror IntegerQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid text \"not an integer\"\n+ IntegerQltyTest.\"Allowable Values\" := 'not an integer';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror IntegerQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Date_ValidFormats()\n+ var\n+ DateQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid date filter expressions\n+\n+ // [GIVEN] A quality test with date type is created\n+ DateQltyTest.Init();\n+ DateQltyTest.Code := 'TESTDATE';\n+ DateQltyTest.Description := 'Test Date';\n+ DateQltyTest.\"Test Value Type\" := DateQltyTest.\"Test Value Type\"::\"Value Type Date\";\n+ DateQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to exact date \"2024-01-01\"\n+ DateQltyTest.\"Allowable Values\" := '2024-01-01';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to date range \"2024-01-01..2024-12-31\"\n+ DateQltyTest.\"Allowable Values\" := '2024-01-01..2024-12-31';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to greater than date \">2024-01-01\"\n+ DateQltyTest.\"Allowable Values\" := '>2024-01-01';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are blank\n+ DateQltyTest.\"Allowable Values\" := '';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values contain expression with brackets \"[Field]\"\n+ DateQltyTest.\"Allowable Values\" := '>[Field]';\n+ // [THEN] ValidateAllowableValuesFormat is deferred and passes without error\n+ DateQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Date_InvalidFormats()\n+ var\n+ DateQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid date filter expressions\n+\n+ // [GIVEN] A quality test with date type is created\n+ DateQltyTest.Init();\n+ DateQltyTest.Code := 'TESTDATE2';\n+ DateQltyTest.Description := 'Test Date Invalid';\n+ DateQltyTest.\"Test Value Type\" := DateQltyTest.\"Test Value Type\"::\"Value Type Date\";\n+ DateQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to invalid date \"99/99/9999\"\n+ DateQltyTest.\"Allowable Values\" := '99/99/9999';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DateQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid text \"not a date\"\n+ DateQltyTest.\"Allowable Values\" := 'not a date';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DateQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_DateTime_ValidFormats()\n+ var\n+ DateTimeQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid datetime filter expressions\n+\n+ // [GIVEN] A quality test with datetime type is created\n+ DateTimeQltyTest.Init();\n+ DateTimeQltyTest.Code := 'TESTDT';\n+ DateTimeQltyTest.Description := 'Test DateTime';\n+ DateTimeQltyTest.\"Test Value Type\" := DateTimeQltyTest.\"Test Value Type\"::\"Value Type DateTime\";\n+ DateTimeQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to exact datetime \"2024-01-01 10:30:00\"\n+ DateTimeQltyTest.\"Allowable Values\" := '2024-01-01 10:30:00';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateTimeQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to datetime range \"2024-01-01 00:00:00..2024-12-31 23:59:59\"\n+ DateTimeQltyTest.\"Allowable Values\" := '2024-01-01 00:00:00..2024-12-31 23:59:59';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateTimeQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to greater than datetime \">2024-01-01 10:00:00\"\n+ DateTimeQltyTest.\"Allowable Values\" := '>2024-01-01 10:00:00';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateTimeQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are blank\n+ DateTimeQltyTest.\"Allowable Values\" := '';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ DateTimeQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values contain expression with brackets \"[Field]\"\n+ DateTimeQltyTest.\"Allowable Values\" := '<[Field]';\n+ // [THEN] ValidateAllowableValuesFormat is deferred and passes without error\n+ DateTimeQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_DateTime_InvalidFormats()\n+ var\n+ DateTimeQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid datetime filter expressions\n+\n+ // [GIVEN] A quality test with datetime type is created\n+ DateTimeQltyTest.Init();\n+ DateTimeQltyTest.Code := 'TESTDT2';\n+ DateTimeQltyTest.Description := 'Test DateTime Invalid';\n+ DateTimeQltyTest.\"Test Value Type\" := DateTimeQltyTest.\"Test Value Type\"::\"Value Type DateTime\";\n+ DateTimeQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to invalid datetime \"99/99/9999 99:99:99\"\n+ DateTimeQltyTest.\"Allowable Values\" := '99/99/9999 99:99:99';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DateTimeQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid text \"not a datetime\"\n+ DateTimeQltyTest.\"Allowable Values\" := 'not a datetime';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror DateTimeQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Boolean_ValidFormats()\n+ var\n+ BooleanQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat accepts valid boolean values\n+\n+ // [GIVEN] A quality test with boolean type is created\n+ BooleanQltyTest.Init();\n+ BooleanQltyTest.Code := 'TESTBOOL';\n+ BooleanQltyTest.Description := 'Test Boolean';\n+ BooleanQltyTest.\"Test Value Type\" := BooleanQltyTest.\"Test Value Type\"::\"Value Type Boolean\";\n+ BooleanQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to \"Yes\"\n+ BooleanQltyTest.\"Allowable Values\" := 'Yes';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"No\"\n+ BooleanQltyTest.\"Allowable Values\" := 'No';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"True\"\n+ BooleanQltyTest.\"Allowable Values\" := 'True';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"False\"\n+ BooleanQltyTest.\"Allowable Values\" := 'False';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"1\"\n+ BooleanQltyTest.\"Allowable Values\" := '1';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"0\"\n+ BooleanQltyTest.\"Allowable Values\" := '0';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"On\"\n+ BooleanQltyTest.\"Allowable Values\" := 'On';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to \"Off\"\n+ BooleanQltyTest.\"Allowable Values\" := 'Off';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to single-letter \"Y\"\n+ BooleanQltyTest.\"Allowable Values\" := 'Y';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to single-letter \"N\"\n+ BooleanQltyTest.\"Allowable Values\" := 'N';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are blank\n+ BooleanQltyTest.\"Allowable Values\" := '';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values contain expression with brackets \"[Field]\"\n+ BooleanQltyTest.\"Allowable Values\" := '[Field]';\n+ // [THEN] ValidateAllowableValuesFormat is deferred and passes without error\n+ BooleanQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_Boolean_InvalidFormats()\n+ var\n+ BooleanQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat rejects invalid boolean values\n+\n+ // [GIVEN] A quality test with boolean type is created\n+ BooleanQltyTest.Init();\n+ BooleanQltyTest.Code := 'TESTBOOL2';\n+ BooleanQltyTest.Description := 'Test Boolean Invalid';\n+ BooleanQltyTest.\"Test Value Type\" := BooleanQltyTest.\"Test Value Type\"::\"Value Type Boolean\";\n+ BooleanQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to invalid text \"Maybe\"\n+ BooleanQltyTest.\"Allowable Values\" := 'Maybe';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid number \"2\"\n+ BooleanQltyTest.\"Allowable Values\" := '2';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid text \"not a boolean\"\n+ BooleanQltyTest.\"Allowable Values\" := 'not a boolean';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror BooleanQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to invalid text \"abc\"\n+ BooleanQltyTest.\"Allowable Values\" := 'abc';\n+ // [THEN] ValidateAllowableValuesFormat raises an error\n+ asserterror BooleanQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+ [Test]\n+ procedure ValidateAllowableValuesFormat_NonValidatedTypes()\n+ var\n+ TextQltyTest: Record \"Qlty. Test\";\n+ OptionQltyTest: Record \"Qlty. Test\";\n+ begin\n+ // [SCENARIO] Validate that ValidateAllowableValuesFormat does not validate non-numeric/non-date types\n+\n+ // [GIVEN] A quality test with text type is created\n+ TextQltyTest.Init();\n+ TextQltyTest.Code := 'TESTTEXT';\n+ TextQltyTest.Description := 'Test Text';\n+ TextQltyTest.\"Test Value Type\" := TextQltyTest.\"Test Value Type\"::\"Value Type Text\";\n+ TextQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to any text value \"A|B|C\"\n+ TextQltyTest.\"Allowable Values\" := 'A|B|C';\n+ // [THEN] ValidateAllowableValuesFormat passes without error (no validation for text type)\n+ TextQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [WHEN] Allowable values are set to any arbitrary text\n+ TextQltyTest.\"Allowable Values\" := 'any text value';\n+ // [THEN] ValidateAllowableValuesFormat passes without error\n+ TextQltyTest.ValidateAllowableValuesFormat();\n+\n+ // [GIVEN] A quality test with option type is created\n+ OptionQltyTest.Init();\n+ OptionQltyTest.Code := 'TESTOPT';\n+ OptionQltyTest.Description := 'Test Option';\n+ OptionQltyTest.\"Test Value Type\" := OptionQltyTest.\"Test Value Type\"::\"Value Type Option\";\n+ OptionQltyTest.Insert();\n+\n+ // [WHEN] Allowable values are set to comma-separated options \"Option1,Option2,Option3\"\n+ OptionQltyTest.\"Allowable Values\" := 'Option1,Option2,Option3';\n+ // [THEN] ValidateAllowableValuesFormat passes without error (no validation for option type)\n+ OptionQltyTest.ValidateAllowableValuesFormat();\n+ end;\n+\n+\n local procedure GetTemplateLineConfigFilters(var QltyInspectionTemplateLine: Record \"Qlty. Inspection Template Line\"; var OutTemplateLineQltyIResultConditConf: Record \"Qlty. I. Result Condit. Conf.\")\n begin\n OutTemplateLineQltyIResultConditConf.SetRange(\"Condition Type\", OutTemplateLineQltyIResultConditConf.\"Condition Type\"::Template);\n"} +{"metadata": {"area": null, "image_count": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8286", "base_commit": "70fd0246a0a4dbc72cb183ca719106722c03be4d", "created_at": "2026-05-22T13:07:41Z", "environment_setup_version": "28.1", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPriceManagement.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPriceManagement.Codeunit.al\nindex dfb07f0502..a005fa7b7c 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPriceManagement.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPriceManagement.Codeunit.al\n@@ -436,7 +436,7 @@ codeunit 99001508 \"Subc. Price Management\"\n \n GetPriceByUOM(SubcontractorPrice, PriceListQty, PriceListCost);\n if PriceListCost <> 0 then begin\n- ConvertPriceToUOM(RequisitionLine.\"Unit of Measure Code\", RequisitionLine.GetQuantityBase(), PriceListUOM, PriceListQtyPerUOM, PriceListCost, DirectCost);\n+ ConvertPriceToUOM(RequisitionLine.\"Unit of Measure Code\", RequisitionLine.GetQuantityForUOM(), PriceListUOM, PriceListQtyPerUOM, PriceListCost, DirectCost);\n ConvertPriceToCurrency(RequisitionLine.\"Currency Code\", SubcontractorPrice.\"Currency Code\", PriceListCost, DirectCost);\n end;\n RequisitionLine.\"Direct Unit Cost\" := DirectCost;\n", "FAIL_TO_PASS": [{"codeunitID": 139989, "functionName": ["WorksheetDirectUnitCostUsesQtyPerUoMNotBaseQtyForUoMConversion"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\nindex 51ef985d36..73e138fe61 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n@@ -3401,6 +3401,77 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n Assert.AreEqual('', ToPurchaseHeader.\"Subc. Location Code\", 'Subc. Location Code should not be copied from archive by Copy Document');\n end;\n \n+ [Test]\n+ procedure WorksheetDirectUnitCostUsesQtyPerUoMNotBaseQtyForUoMConversion()\n+ var\n+ Item: Record Item;\n+ ItemUOM: Record \"Item Unit of Measure\";\n+ Vendor: Record Vendor;\n+ WorkCenter: Record \"Work Center\";\n+ SubcontractorPrice: Record \"Subcontractor Price\";\n+ RequisitionLine: Record \"Requisition Line\";\n+ SubcPriceManagement: Codeunit \"Subc. Price Management\";\n+ QtyPerSet: Integer;\n+ PriceListUnitCost: Decimal;\n+ begin\n+ // [SCENARIO 636078] Calculate Subcontracts must compute Direct Unit Cost on the Subcontracting\n+ // Worksheet using the per-UoM conversion factor (GetQuantityForUOM()), not the total base\n+ // quantity (GetQuantityBase()) of the order.\n+\n+ // [GIVEN] Item with PCS base UoM and a SET alternative UoM (10 PCS per SET).\n+ Initialize();\n+ LibraryInventory.CreateItem(Item);\n+ QtyPerSet := 10;\n+ LibraryInventory.CreateItemUnitOfMeasureCode(ItemUOM, Item.\"No.\", QtyPerSet);\n+\n+ // [GIVEN] Vendor and Work Center with the vendor as its subcontractor.\n+ LibraryPurchase.CreateVendor(Vendor);\n+ LibraryManufacturing.CreateWorkCenter(WorkCenter);\n+ WorkCenter.Validate(\"Subcontractor No.\", Vendor.\"No.\");\n+ WorkCenter.Modify(true);\n+\n+ // [GIVEN] A subcontractor price in PCS with Minimum Quantity 1 and Direct Unit Cost 1000.\n+ PriceListUnitCost := 1000;\n+ SubcontractingMgmtLibrary.CreateSubContractingPrice(\n+ SubcontractorPrice, WorkCenter.\"No.\", Vendor.\"No.\", Item.\"No.\", '', '', WorkDate(), Item.\"Base Unit of Measure\", 1, '');\n+ SubcontractorPrice.Validate(\"Direct Unit Cost\", PriceListUnitCost);\n+ SubcontractorPrice.Modify(true);\n+\n+ // [GIVEN] A staged Requisition Line for 3 SET (= 30 PCS in base UoM).\n+ RequisitionLine.Init();\n+ RequisitionLine.\"No.\" := Item.\"No.\";\n+ RequisitionLine.\"Unit of Measure Code\" := ItemUOM.Code;\n+ RequisitionLine.\"Vendor No.\" := Vendor.\"No.\";\n+ RequisitionLine.\"Work Center No.\" := WorkCenter.\"No.\";\n+ RequisitionLine.\"Order Date\" := WorkDate();\n+ RequisitionLine.Quantity := 3;\n+\n+ // [WHEN] The subcontractor price is applied to the requisition line.\n+ SubcPriceManagement.GetSubcPriceForReqLine(RequisitionLine, '');\n+\n+ // [THEN] Direct Unit Cost = price-list cost * Qty-per-UoM (1000 * 10 = 10000),\n+ // not price-list cost * total base quantity (1000 * 30 = 30000 — the pre-fix behavior).\n+ Assert.AreEqual(\n+ PriceListUnitCost * QtyPerSet, RequisitionLine.\"Direct Unit Cost\",\n+ 'Direct Unit Cost on the Subcontracting Worksheet must be derived from Qty. per Unit of Measure, not from total base quantity.');\n+\n+ // [WHEN] The same price is applied to a Requisition Line using the base UoM (no conversion needed).\n+ Clear(RequisitionLine);\n+ RequisitionLine.Init();\n+ RequisitionLine.\"No.\" := Item.\"No.\";\n+ RequisitionLine.\"Unit of Measure Code\" := Item.\"Base Unit of Measure\";\n+ RequisitionLine.\"Vendor No.\" := Vendor.\"No.\";\n+ RequisitionLine.\"Work Center No.\" := WorkCenter.\"No.\";\n+ RequisitionLine.\"Order Date\" := WorkDate();\n+ RequisitionLine.Quantity := 30;\n+ SubcPriceManagement.GetSubcPriceForReqLine(RequisitionLine, '');\n+\n+ // [THEN] Direct Unit Cost equals the price-list cost (the same-UoM path is unchanged by the fix).\n+ Assert.AreEqual(\n+ PriceListUnitCost, RequisitionLine.\"Direct Unit Cost\",\n+ 'Direct Unit Cost must equal the price-list cost when the worksheet UoM matches the price-list UoM.');\n+ end;\n+\n local procedure Initialize()\n begin\n LibraryTestInitialize.OnTestInitialize(Codeunit::\"Subc. Subcontracting Test\");\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8313", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-05-26T11:20:20Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\EDocument\\App", "src\\Apps\\W1\\EDocument\\Test"], "patch": "diff --git a/src/Apps/W1/EDocument/App/src/Processing/EDocImport.Codeunit.al b/src/Apps/W1/EDocument/App/src/Processing/EDocImport.Codeunit.al\nindex ffcc3aedf5..c2d3853933 100644\n--- a/src/Apps/W1/EDocument/App/src/Processing/EDocImport.Codeunit.al\n+++ b/src/Apps/W1/EDocument/App/src/Processing/EDocImport.Codeunit.al\n@@ -840,7 +840,7 @@ codeunit 6140 \"E-Doc. Import\"\n EDocumentPurchaseLine.Quantity := PurchaseLine.Quantity;\n EDocumentPurchaseLine.\"Unit Price\" := PurchaseLine.\"Direct Unit Cost\";\n EDocumentPurchaseLine.\"Unit of Measure\" := PurchaseLine.\"Unit of Measure Code\";\n- EDocumentPurchaseLine.\"Sub Total\" := PurchaseLine.\"Direct Unit Cost\" * PurchaseLine.Quantity;\n+ EDocumentPurchaseLine.\"Sub Total\" := PurchaseLine.Amount;\n EDocumentPurchaseLine.\"Total Discount\" := PurchaseLine.\"Line Discount Amount\";\n EDocumentPurchaseLine.\"VAT Rate\" := PurchaseLine.\"VAT %\";\n EDocumentPurchaseLine.\"Currency Code\" := PurchaseLine.\"Currency Code\";\n", "FAIL_TO_PASS": [{"codeunitID": 139628, "functionName": ["ReceivePeppolInvoice_LineSubTotalFromXml"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/EDocument/Test/.resources/peppol/PEPPOL_LineRounding.xml b/src/Apps/W1/EDocument/Test/.resources/peppol/PEPPOL_LineRounding.xml\nnew file mode 100644\nindex 0000000000..6857d05fdd\n--- /dev/null\n+++ b/src/Apps/W1/EDocument/Test/.resources/peppol/PEPPOL_LineRounding.xml\n@@ -0,0 +1,89 @@\n+\n+\n+ urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0\n+ urn:fdc:peppol.eu:2017:poacc:billing:01:1.0\n+ INV-ROUNDING-001\n+ 2026-01-22\n+ 2026-02-22\n+ 380\n+ GBP\n+ \n+ \n+ GB123456789\n+ \n+ Test Supplier\n+ \n+ \n+ 1 Test Street\n+ London\n+ England\n+ \n+ GB\n+ \n+ \n+ \n+ GB123456789\n+ \n+ VAT\n+ \n+ \n+ \n+ Test Supplier Ltd\n+ 12345678\n+ \n+ \n+ \n+ \n+ \n+ \n+ Test Customer\n+ \n+ \n+ \n+ \n+ 2.35\n+ \n+ 11.20\n+ 2.35\n+ \n+ S\n+ 21.00\n+ \n+ VAT\n+ \n+ \n+ \n+ \n+ \n+ 11.20\n+ 11.20\n+ 13.55\n+ 0.00\n+ 13.55\n+ \n+ \n+ 1\n+ 1.65000\n+ 11.20\n+ \n+ RECDN2550\n+ REMOVAL SERVICE\n+ \n+ RECDN2550\n+ \n+ \n+ S\n+ 21.00\n+ \n+ VAT\n+ \n+ \n+ \n+ \n+ 6.79000\n+ 1\n+ \n+ \n+\ndiff --git a/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveFiles.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveFiles.Codeunit.al\nindex ae2782ed87..a264f22f25 100644\n--- a/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveFiles.Codeunit.al\n+++ b/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveFiles.Codeunit.al\n@@ -11,4 +11,9 @@ codeunit 139635 \"E-Doc. Receive Files\"\n exit(NavApp.GetResourceAsText('peppol/PEPPOL1.xml'));\n end;\n \n+ procedure GetLineRoundingDocument(): Text\n+ begin\n+ exit(NavApp.GetResourceAsText('peppol/PEPPOL_LineRounding.xml'));\n+ end;\n+\n }\n\\ No newline at end of file\ndiff --git a/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveTest.Codeunit.al b/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveTest.Codeunit.al\nindex 0469586d2e..d7326c28d5 100644\n--- a/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveTest.Codeunit.al\n+++ b/src/Apps/W1/EDocument/Test/src/Receive/EDocReceiveTest.Codeunit.al\n@@ -7,6 +7,7 @@ namespace Microsoft.eServices.EDocument.Test;\n using Microsoft.eServices.EDocument;\n using Microsoft.eServices.EDocument.Integration;\n using Microsoft.eServices.EDocument.IO.Peppol;\n+using Microsoft.eServices.EDocument.Processing.Import.Purchase;\n using Microsoft.Finance.GeneralLedger.Journal;\n using Microsoft.Finance.VAT.Setup;\n using Microsoft.Foundation.Address;\n@@ -60,6 +61,7 @@ codeunit 139628 \"E-Doc. Receive Test\"\n VATRegistrationLbl: Label 'GB123456789';\n ImportDataExchDefLbl: Label 'EDOCPEPPOLINVIMP';\n EndpointPathLbl: label '/Invoice/cac:AccountingSupplierParty/cac:Party/cbc:EndpointID';\n+ SubTotalMismatchErr: Label 'Sub Total should be %1 from XML LineExtensionAmount, not %2 (Qty*Price)', Comment = '%1 = expected Sub Total, %2 = actual Qty*Price', Locked = true;\n \n [Test]\n procedure ReceiveSinglePurchaseInvoice()\n@@ -258,6 +260,64 @@ codeunit 139628 \"E-Doc. Receive Test\"\n Assert.RecordCount(DocumentAttachment, 2);\n end;\n \n+ [Test]\n+ procedure ReceivePeppolInvoice_LineSubTotalFromXml()\n+ var\n+ EDocService: Record \"E-Document Service\";\n+ EDocument: Record \"E-Document\";\n+ EDocumentPurchaseLine: Record \"E-Document Purchase Line\";\n+ VATPostingSetup: Record \"VAT Posting Setup\";\n+ EDocServicePage: TestPage \"E-Document Service\";\n+ ExpectedSubTotal: Decimal;\n+ begin\n+ // [SCENARIO] V1 PEPPOL import stores LineExtensionAmount as Sub Total, not recalculated Qty*Price\n+ // Regression for: Qty=1.65, Price=6.79, LineExtensionAmount=11.20 -> was stored as 1.65*6.79=11.2035\n+ Initialize();\n+ BindSubscription(EDocImplState);\n+\n+ // [GIVEN] E-Document service with PEPPOL BIS 3.0 format and V1 import, all item lookups disabled\n+ LibraryEDoc.CreateTestReceiveServiceForEDoc(EDocService, Enum::\"Service Integration\"::\"Mock\");\n+ EDocService.\"Document Format\" := \"E-Document Format\"::\"PEPPOL BIS 3.0\";\n+ EDocService.\"Lookup Account Mapping\" := false;\n+ EDocService.\"Lookup Item GTIN\" := false;\n+ EDocService.\"Lookup Item Reference\" := false;\n+ EDocService.\"Resolve Unit Of Measure\" := false;\n+ EDocService.\"Validate Line Discount\" := false;\n+ EDocService.\"Verify Totals\" := false;\n+ EDocService.\"Validate Receiving Company\" := false;\n+ EDocService.\"Use Batch Processing\" := false;\n+ EDocService.Modify();\n+\n+ // [GIVEN] Vendor matching the XML supplier VAT registration\n+ LibraryPurchase.CreateVendorWithVATRegNo(Vendor);\n+ LibraryERM.CreateVATPostingSetupWithAccounts(VATPostingSetup, Enum::\"Tax Calculation Type\"::\"Normal VAT\", 1);\n+ Vendor.\"VAT Bus. Posting Group\" := VATPostingSetup.\"VAT Bus. Posting Group\";\n+ Vendor.\"VAT Registration No.\" := VATRegistrationLbl;\n+ Vendor.\"Receive E-Document To\" := Vendor.\"Receive E-Document To\"::\"Purchase Invoice\";\n+ Vendor.\"Country/Region Code\" := CountryRegion.Code;\n+ Vendor.Modify();\n+\n+ // [GIVEN] PEPPOL XML: Qty=1.65, PriceAmount=6.79, LineExtensionAmount=11.20 (vendor-rounded value)\n+ LibraryVariableStorage.Clear();\n+ LibraryVariableStorage.Enqueue(EDocReceiveFiles.GetLineRoundingDocument());\n+ LibraryVariableStorage.Enqueue(1);\n+ EDocImplState.SetVariableStorage(LibraryVariableStorage);\n+\n+ // [WHEN] Receive is invoked\n+ EDocServicePage.OpenView();\n+ EDocServicePage.Filter.SetFilter(Code, EDocService.Code);\n+ EDocServicePage.Receive.Invoke();\n+\n+ // [THEN] EDocumentPurchaseLine.\"Sub Total\" = 11.20 (from XML LineExtensionAmount), not 11.2035 (Qty*Price)\n+ EDocument.FindLast();\n+ EDocumentPurchaseLine.SetRange(\"E-Document Entry No.\", EDocument.\"Entry No\");\n+ Assert.IsTrue(EDocumentPurchaseLine.FindFirst(), 'Expected at least one E-Document purchase line');\n+ ExpectedSubTotal := 11.20;\n+ Assert.AreEqual(ExpectedSubTotal, EDocumentPurchaseLine.\"Sub Total\",\n+ StrSubstNo(SubTotalMismatchErr,\n+ ExpectedSubTotal, EDocumentPurchaseLine.Quantity * EDocumentPurchaseLine.\"Unit Price\"));\n+ end;\n+\n [Test]\n procedure ReceiveSinglePurchaseInvoice_PEPPOLDataExch_WithAttachment()\n var\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8380", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-05-29T16:14:31Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Quality Management\\app", "src\\Apps\\W1\\Quality Management\\test"], "patch": "diff --git a/src/Apps/W1/Quality Management/app/src/Workflow/QltyWorkflowSetup.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Workflow/QltyWorkflowSetup.Codeunit.al\nindex 0c1462d3a5..537b996632 100644\n--- a/src/Apps/W1/Quality Management/app/src/Workflow/QltyWorkflowSetup.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Workflow/QltyWorkflowSetup.Codeunit.al\n@@ -319,8 +319,8 @@ codeunit 20423 \"Qlty. Workflow Setup\"\n WorkflowSetup: Codeunit \"Workflow Setup\";\n begin\n WorkflowSetup.InsertTableRelation(Database::\"User\", User.FieldNo(\"User Name\"), Database::\"Qlty. Inspection Header\", QltyInspectionHeader.FieldNo(\"Assigned User ID\"));\n- WorkflowSetup.InsertTableRelation(Database::\"Qlty. Inspection Header\", QltyInspectionHeader.FieldNo(\"No.\"), database::\"Approval Entry\", ApprovalEntry.FieldNo(\"Document No.\"));\n- WorkflowSetup.InsertTableRelation(Database::\"Qlty. Inspection Line\", QltyInspectionLine.FieldNo(\"Inspection No.\"), database::\"Approval Entry\", ApprovalEntry.FieldNo(\"Document No.\"));\n+ WorkflowSetup.InsertTableRelation(Database::\"Qlty. Inspection Header\", QltyInspectionHeader.FieldNo(\"No.\"), Database::\"Approval Entry\", ApprovalEntry.FieldNo(\"Document No.\"));\n+ WorkflowSetup.InsertTableRelation(Database::\"Qlty. Inspection Line\", QltyInspectionLine.FieldNo(\"Inspection No.\"), Database::\"Approval Entry\", ApprovalEntry.FieldNo(\"Document No.\"));\n end;\n \n [EventSubscriber(ObjectType::Codeunit, Codeunit::\"Workflow Event Handling\", 'OnAddWorkflowEventsToLibrary', '', true, true)]\n@@ -397,12 +397,8 @@ codeunit 20423 \"Qlty. Workflow Setup\"\n OptionalSuffix: Text;\n begin\n WorkflowResponse.SetFilter(\"Function Name\", QltyPrefixTok + '*');\n- if WorkflowResponse.FindSet() then\n- repeat\n- WorkflowResponse.MakeDependentOnAllEvents();\n- until WorkflowResponse.Next() = 0;\n-\n WorkflowResponse.DeleteAll(false);\n+\n WorkflowResponse.Reset();\n WorkflowResponse.SetRange(Description, QMWorkflowResponseDescriptionCreateAQltyInspectionLbl);\n if not WorkflowResponse.IsEmpty() then\n@@ -413,43 +409,109 @@ codeunit 20423 \"Qlty. Workflow Setup\"\n QualityEventIds.Add(GetInspectionHasChangedEvent());\n QualityEventIds.Add(GetInspectionReopenedEvent());\n \n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateInspection(), 1, 128), 0, QMWorkflowResponseDescriptionCreateAQltyInspectionLbl + OptionalSuffix, CopyStr(GetWorkflowResponseCreateInspection(), 1, 20));\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateInspection(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreateAQltyInspectionLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseCreateInspection(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseCreateInspection(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseFinishInspection(), 1, 128), 0, QMWorkflowResponseDescriptionFinishTheQltyInspectionLbl + OptionalSuffix, CopyStr(GetWorkflowResponseFinishInspection(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseFinishInspection(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionFinishTheQltyInspectionLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseFinishInspection(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseFinishInspection(), 1, 128));\n \n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseReopenInspection(), 1, 128), 0, QMWorkflowResponseDescriptionReopenTheQltyInspectionLbl + OptionalSuffix, CopyStr(GetWorkflowResponseReopenInspection(), 1, 20));\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseReopenInspection(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionReopenTheQltyInspectionLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseReopenInspection(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseReopenInspection(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateReinspection(), 1, 128), 0, QMWorkflowResponseDescriptionCreateReinspectionLbl + OptionalSuffix, CopyStr(GetWorkflowResponseCreateReinspection(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateReinspection(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreateReinspectionLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseCreateReinspection(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseCreateReinspection(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockLot(), 1, 128), 0, QMWorkflowResponseDescriptionBlockLotLbl + OptionalSuffix, CopyStr(GetWorkflowResponseBlockLot(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockLot(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionBlockLotLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseBlockLot(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseBlockLot(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockSerial(), 1, 128), 0, QMWorkflowResponseDescriptionBlockSerialLbl + OptionalSuffix, CopyStr(GetWorkflowResponseBlockSerial(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockSerial(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionBlockSerialLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseBlockSerial(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseBlockSerial(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockLot(), 1, 128), 0, QMWorkflowResponseDescriptionUnblockLotLbl + OptionalSuffix, CopyStr(GetWorkflowResponseUnblockLot(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockLot(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionUnblockLotLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseUnblockLot(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseUnblockLot(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockSerial(), 1, 128), 0, QMWorkflowResponseDescriptionUnblockSerialLbl + OptionalSuffix, CopyStr(GetWorkflowResponseUnblockSerial(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockSerial(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionUnblockSerialLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseUnblockSerial(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseUnblockSerial(), 1, 128));\n \n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseMoveInventory(), 1, 128), 0, QMWorkflowResponseDescriptionMoveInventoryLbl + OptionalSuffix, CopyStr(GetWorkflowResponseMoveInventory(), 1, 20));\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseMoveInventory(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionMoveInventoryLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseMoveInventory(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseMoveInventory(), 1, 128));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseUnQuarantineLicensePlate(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseInternalPutAway(), 1, 128), 0, QMWorkflowResponseDescriptionCreateInternalPutAwayLbl + OptionalSuffix, CopyStr(GetWorkflowResponseInternalPutAway(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseInternalPutAway(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreateInternalPutAwayLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseInternalPutAway(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseInternalPutAway(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseSetDatabaseValue(), 1, 128), 0, QMWorkflowResponseDescriptionSetDatabaseValueLbl + OptionalSuffix, CopyStr(GetWorkflowResponseSetDatabaseValue(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseSetDatabaseValue(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionSetDatabaseValueLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseSetDatabaseValue(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseSetDatabaseValue(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseInventoryAdjustment(), 1, 128), 0, QMWorkflowResponseDescriptionCreateNegativeAdjustmentLbl + OptionalSuffix, CopyStr(GetWorkflowResponseInventoryAdjustment(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseInventoryAdjustment(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreateNegativeAdjustmentLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseInventoryAdjustment(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseInventoryAdjustment(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseChangeItemTracking(), 1, 128), 0, QMWorkflowResponseDescriptionChangeItemTrackingInformationLbl + OptionalSuffix, CopyStr(GetWorkflowResponseChangeItemTracking(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseChangeItemTracking(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionChangeItemTrackingInformationLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseChangeItemTracking(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseChangeItemTracking(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateTransfer(), 1, 128), 0, QMWorkflowResponseDescriptionCreateTransferOrderLbl + OptionalSuffix, CopyStr(GetWorkflowResponseCreateTransfer(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreateTransfer(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreateTransferOrderLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseCreateTransfer(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseCreateTransfer(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreatePurchaseReturn(), 1, 128), 0, QMWorkflowResponseDescriptionCreatePurchaseReturnOrderLbl + OptionalSuffix, CopyStr(GetWorkflowResponseCreatePurchaseReturn(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseCreatePurchaseReturn(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionCreatePurchaseReturnOrderLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseCreatePurchaseReturn(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseCreatePurchaseReturn(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockPackage(), 1, 128), 0, QMWorkflowResponseDescriptionBlockPackageLbl + OptionalSuffix, CopyStr(GetWorkflowResponseBlockPackage(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseBlockPackage(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionBlockPackageLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseBlockPackage(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseBlockPackage(), 1, 128));\n- WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockPackage(), 1, 128), 0, QMWorkflowResponseDescriptionUnblockPackageLbl + OptionalSuffix, CopyStr(GetWorkflowResponseUnblockPackage(), 1, 20));\n+\n+ WorkflowResponseHandling.AddResponseToLibrary(CopyStr(GetWorkflowResponseUnblockPackage(), 1, 128),\n+ 0,\n+ CopyStr(QMWorkflowResponseDescriptionUnblockPackageLbl + OptionalSuffix, 1, 250),\n+ CopyStr(GetWorkflowResponseUnblockPackage(), 1, 20));\n QualityResponseIdsToAdd.Add(CopyStr(GetWorkflowResponseUnblockPackage(), 1, 128));\n+\n foreach QualityResponse in QualityResponseIdsToAdd do\n foreach QualityEvent in QualityEventIds do\n WorkflowResponseHandling.AddResponsePredecessor(CopyStr(QualityResponse, 1, 128), CopyStr(QualityEvent, 1, 128));\n", "FAIL_TO_PASS": [{"codeunitID": 139969, "functionName": ["QltyResponsesAreNotPredecessorsOfNonQltyEvents"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsWorkflows.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsWorkflows.Codeunit.al\nindex fcbdfbf3de..0d99bb2332 100644\n--- a/src/Apps/W1/Quality Management/test/src/QltyTestsWorkflows.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsWorkflows.Codeunit.al\n@@ -53,8 +53,42 @@ codeunit 139969 \"Qlty. Tests - Workflows\"\n EventFilterTok: Label 'Where(\"Result Code\"=Filter(%1))', Comment = '%1=result code.';\n DefaultResult1FailCodeTok: Label 'FAIL', Locked = true;\n DefaultResult2PassCodeTok: Label 'PASS', Locked = true;\n+ QMResponseNotPredecessorOfNonQMEventErr: Label 'QM response %1 should not be a predecessor of non-QM event %2.', Comment = '%1=response function name, %2=predecessor function name.';\n IsInitialized: Boolean;\n \n+ [Test]\n+ procedure QltyResponsesAreNotPredecessorsOfNonQltyEvents()\n+ var\n+ WFEventResponseCombination: Record \"WF Event/Response Combination\";\n+ WorkflowEventHandling: Codeunit \"Workflow Event Handling\";\n+ WorkflowResponseHandling: Codeunit \"Workflow Response Handling\";\n+ QltyPrefix: Text;\n+ begin\n+ // [SCENARIO] QM workflow responses should only be predecessors of QM events, not of any unrelated event\n+ Initialize();\n+\n+ // [GIVEN] The workflow events and responses libraries are initialized\n+ WorkflowEventHandling.CreateEventsLibrary();\n+ WorkflowResponseHandling.CreateResponsesLibrary();\n+\n+ // [WHEN] We look at all event/response combinations where the response is a QM response\n+ QltyPrefix := 'QLTY-*';\n+ WFEventResponseCombination.SetFilter(\"Function Name\", QltyPrefix);\n+ WFEventResponseCombination.FindSet();\n+\n+ // [THEN] Every linked predecessor event must also be a QM event\n+ repeat\n+ LibraryAssert.IsTrue(\n+ WFEventResponseCombination.\"Predecessor Type\" = WFEventResponseCombination.\"Predecessor Type\"::\"Event\",\n+ 'Expected predecessor type to be Event.');\n+ LibraryAssert.IsTrue(\n+ CopyStr(WFEventResponseCombination.\"Predecessor Function Name\", 1, 5) = 'QLTY-',\n+ StrSubstNo(QMResponseNotPredecessorOfNonQMEventErr,\n+ WFEventResponseCombination.\"Function Name\",\n+ WFEventResponseCombination.\"Predecessor Function Name\"));\n+ until WFEventResponseCombination.Next() = 0;\n+ end;\n+\n [Test]\n procedure PurchaseReturnWorkflow_OnInspectionFinished()\n var\n@@ -1780,11 +1814,7 @@ codeunit 139969 \"Qlty. Tests - Workflows\"\n var\n Workflow: Record Workflow;\n begin\n- Workflow.FindSet();\n- repeat\n- Workflow.Enabled := false;\n- Workflow.Modify();\n- until Workflow.Next() = 0;\n+ Workflow.ModifyAll(Enabled, false);\n Workflow.DeleteAll();\n end;\n \n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8564", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-10T10:49:42Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchPostExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchPostExt.Codeunit.al\nindex 6af5392a0f..fbca120f85 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchPostExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchPostExt.Codeunit.al\n@@ -17,6 +17,22 @@ using Microsoft.Purchases.History;\n using Microsoft.Purchases.Posting;\n codeunit 99001535 \"Subc. Purch. Post Ext\"\n {\n+ var\n+ CancelNotSupportedErr: Label 'You cannot cancel or correct posted purchase invoice %1 because it contains item charges assigned to a subcontracting order receipt.\\Create a purchase credit memo manually and assign the item charge to the posted subcontracting receipt line.', Comment = '%1 = Posted Purchase Invoice No.';\n+\n+ [EventSubscriber(ObjectType::Codeunit, Codeunit::\"Correct Posted Purch. Invoice\", OnAfterTestCorrectInvoiceIsAllowed, '', false, false)]\n+ local procedure BlockCancelIfHasSubcontractingItemChargeValueEntry(var PurchInvHeader: Record \"Purch. Inv. Header\"; Cancelling: Boolean)\n+ var\n+ ValueEntry: Record \"Value Entry\";\n+ begin\n+ ValueEntry.SetRange(\"Document Type\", ValueEntry.\"Document Type\"::\"Purchase Invoice\");\n+ ValueEntry.SetRange(\"Document No.\", PurchInvHeader.\"No.\");\n+ ValueEntry.SetFilter(\"Item Charge No.\", '<>%1', '');\n+ ValueEntry.SetFilter(\"Capacity Ledger Entry No.\", '<>%1', 0);\n+ if not ValueEntry.IsEmpty() then\n+ Error(CancelNotSupportedErr, PurchInvHeader.\"No.\");\n+ end;\n+\n [EventSubscriber(ObjectType::Codeunit, Codeunit::\"Purch.-Post\", OnBeforeItemJnlPostLine, '', false, false)]\n local procedure \"Purch.-Post_OnBeforeItemJnlPostLine\"(var ItemJournalLine: Record \"Item Journal Line\"; TempItemChargeAssignmentPurch: Record \"Item Charge Assignment (Purch)\" temporary)\n begin\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/SubcItemJnlPostLineExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/SubcItemJnlPostLineExt.Codeunit.al\nindex ab66a998e9..1e4c5d17ba 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/SubcItemJnlPostLineExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/SubcItemJnlPostLineExt.Codeunit.al\n@@ -41,6 +41,7 @@ codeunit 99001515 \"Subc. ItemJnlPostLine Ext\"\n local procedure \"Item Jnl.-Post Line_OnBeforeInsertCapValueEntry\"(var ValueEntry: Record \"Value Entry\"; ItemJnlLine: Record \"Item Journal Line\")\n begin\n ClearInvoicedQuantityForItemChargeSubAssign(ValueEntry, ItemJnlLine);\n+ CopyItemChargeNoForItemChargeSubAssign(ValueEntry, ItemJnlLine);\n end;\n \n local procedure UpdateProdOrderRoutingLine(var ProdOrderLine: Record \"Prod. Order Line\"; var ItemJournalLine: Record \"Item Journal Line\")\n@@ -90,4 +91,10 @@ codeunit 99001515 \"Subc. ItemJnlPostLine Ext\"\n if ItemJournalLine.\"Subc. Item Charge Assign.\" and (ValueEntry.\"Entry Type\" = \"Cost Entry Type\"::\"Direct Cost\") then\n ValueEntry.\"Invoiced Quantity\" := 0;\n end;\n+\n+ local procedure CopyItemChargeNoForItemChargeSubAssign(var ValueEntry: Record \"Value Entry\"; ItemJournalLine: Record \"Item Journal Line\")\n+ begin\n+ if ItemJournalLine.\"Subc. Item Charge Assign.\" and (ItemJournalLine.\"Item Charge No.\" <> '') then\n+ ValueEntry.\"Item Charge No.\" := ItemJournalLine.\"Item Charge No.\";\n+ end;\n }\n\\ No newline at end of file\n", "FAIL_TO_PASS": [{"codeunitID": 139989, "functionName": ["CancelInvoiceWithSubcontractingItemChargeIsBlocked"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\nindex 4a5ff0f97b..f6a4093535 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n@@ -28,6 +28,7 @@ using Microsoft.Manufacturing.WorkCenter;\n using Microsoft.Purchases.Archive;\n using Microsoft.Purchases.Comment;\n using Microsoft.Purchases.Document;\n+using Microsoft.Purchases.History;\n using Microsoft.Purchases.Vendor;\n using Microsoft.Sales.Customer;\n using Microsoft.Sales.Document;\n@@ -3548,6 +3549,99 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n exit(UnitOfMeasure.Code);\n end;\n \n+ [Test]\n+ [HandlerFunctions('ConfirmHandler')]\n+ procedure CancelInvoiceWithSubcontractingItemChargeIsBlocked()\n+ var\n+ Item: Record Item;\n+ RegularItem: Record Item;\n+ ProductionOrder: Record \"Production Order\";\n+ SubcWorkCenter: Record \"Work Center\";\n+ SubcPurchaseHeader: Record \"Purchase Header\";\n+ SubcPurchaseLine: Record \"Purchase Line\";\n+ RegularPurchaseHeader: Record \"Purchase Header\";\n+ RegularPurchaseLine: Record \"Purchase Line\";\n+ SubcPurchRcptLine: Record \"Purch. Rcpt. Line\";\n+ RegPurchRcptLine: Record \"Purch. Rcpt. Line\";\n+ ItemCharge: Record \"Item Charge\";\n+ ItemChargeInvHeader: Record \"Purchase Header\";\n+ ItemChargeInvLine: Record \"Purchase Line\";\n+ PurchInvHeader: Record \"Purch. Inv. Header\";\n+ CorrectPostedPurchInvoice: Codeunit \"Correct Posted Purch. Invoice\";\n+ PostedInvoiceNo: Code[20];\n+ SubcVendorNo: Code[20];\n+ begin\n+ // [SCENARIO 637502] Cancelling a Posted Purchase Invoice whose Item Charge is split between a regular item receipt\n+ // line and a subcontracting service receipt line must be blocked. Letting the cancel run today silently skips the\n+ // capacity portion (Value Entry has Item Ledger Entry No. = 0) and redistributes it to inventory, corrupting cost.\n+ // Until a proper reversal path exists, the Subcontracting App blocks the cancel with a clear error so the user\n+ // creates a corrective credit memo manually.\n+\n+ // [GIVEN] Subcontracting setup with a single-operation subcontracting routing on Item\n+ Initialize();\n+ Subcontracting := true;\n+ UnitCostCalculation := UnitCostCalculation::Units;\n+ CreateItemWithSingleSubcontractingOperation(Item, SubcWorkCenter);\n+ SubcontractingMgmtLibrary.UpdateVendorWithSubcontractingLocationCode(SubcWorkCenter);\n+\n+ // [GIVEN] Released production order and a subcontracting purchase order received in full\n+ SubcontractingMgmtLibrary.CreateAndRefreshProductionOrder(\n+ ProductionOrder, \"Production Order Status\"::Released, ProductionOrder.\"Source Type\"::Item, Item.\"No.\", LibraryRandom.RandIntInRange(5, 10));\n+ UpdateSubMgmtSetupWithReqWkshTemplate();\n+ SubcontractingMgmtLibrary.CreateSubcontractingOrderFromProdOrderRtngPage(Item.\"Routing No.\", SubcWorkCenter.\"No.\");\n+\n+ SubcPurchaseLine.SetRange(\"Document Type\", SubcPurchaseLine.\"Document Type\"::Order);\n+ SubcPurchaseLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+#pragma warning disable AA0210\n+ SubcPurchaseLine.SetRange(\"Work Center No.\", SubcWorkCenter.\"No.\");\n+#pragma warning restore AA0210\n+ SubcPurchaseLine.FindFirst();\n+ SubcPurchaseHeader.Get(SubcPurchaseLine.\"Document Type\", SubcPurchaseLine.\"Document No.\");\n+ EnsureGeneralPostingSetupIsValid(SubcPurchaseLine.\"Gen. Bus. Posting Group\", SubcPurchaseLine.\"Gen. Prod. Posting Group\");\n+ SubcVendorNo := SubcPurchaseHeader.\"Buy-from Vendor No.\";\n+\n+ LibraryPurchase.PostPurchaseDocument(SubcPurchaseHeader, true, false);\n+\n+ SubcPurchRcptLine.SetRange(\"Order No.\", SubcPurchaseHeader.\"No.\");\n+ SubcPurchRcptLine.SetRange(\"Order Line No.\", SubcPurchaseLine.\"Line No.\");\n+ SubcPurchRcptLine.FindFirst();\n+\n+ // [GIVEN] A separate regular purchase order for the same vendor that receives a normal inventory item\n+ LibraryInventory.CreateItem(RegularItem);\n+ LibraryPurchase.CreatePurchHeader(RegularPurchaseHeader, RegularPurchaseHeader.\"Document Type\"::Order, SubcVendorNo);\n+ LibraryPurchase.CreatePurchaseLineWithUnitCost(\n+ RegularPurchaseLine, RegularPurchaseHeader, RegularItem.\"No.\",\n+ LibraryRandom.RandDecInRange(50, 100, 2), LibraryRandom.RandIntInRange(2, 5));\n+ EnsureGeneralPostingSetupIsValid(RegularPurchaseLine.\"Gen. Bus. Posting Group\", RegularPurchaseLine.\"Gen. Prod. Posting Group\");\n+ LibraryPurchase.PostPurchaseDocument(RegularPurchaseHeader, true, false);\n+\n+ RegPurchRcptLine.SetRange(\"Order No.\", RegularPurchaseHeader.\"No.\");\n+ RegPurchRcptLine.SetRange(\"Order Line No.\", RegularPurchaseLine.\"Line No.\");\n+ RegPurchRcptLine.FindFirst();\n+\n+ // [GIVEN] A purchase invoice with a single Item Charge line of quantity 2 allocated 1:1 across both receipt lines\n+ LibraryInventory.CreateItemCharge(ItemCharge);\n+ LibraryPurchase.CreatePurchHeader(ItemChargeInvHeader, ItemChargeInvHeader.\"Document Type\"::Invoice, SubcVendorNo);\n+ LibraryPurchase.CreatePurchaseLine(ItemChargeInvLine, ItemChargeInvHeader, ItemChargeInvLine.Type::\"Charge (Item)\", ItemCharge.\"No.\", 2);\n+ ItemChargeInvLine.Validate(\"Direct Unit Cost\", LibraryRandom.RandDecInRange(100, 200, 2));\n+ ItemChargeInvLine.Modify(true);\n+ EnsureGeneralPostingSetupIsValid(ItemChargeInvLine.\"Gen. Bus. Posting Group\", ItemChargeInvLine.\"Gen. Prod. Posting Group\");\n+\n+ AssignItemChargeToReceiptLine(ItemChargeInvLine, RegPurchRcptLine, 1);\n+ AssignItemChargeToReceiptLine(ItemChargeInvLine, SubcPurchRcptLine, 1);\n+\n+ // [GIVEN] The invoice is posted\n+ PostedInvoiceNo := LibraryPurchase.PostPurchaseDocument(ItemChargeInvHeader, false, true);\n+ PurchInvHeader.Get(PostedInvoiceNo);\n+ Commit();\n+\n+ // [WHEN] The user tries to cancel the posted invoice\n+ asserterror CorrectPostedPurchInvoice.CancelPostedInvoice(PurchInvHeader);\n+\n+ // [THEN] The Subcontracting App blocks the cancel with the dedicated error\n+ Assert.ExpectedError('contains item charges assigned to a subcontracting order receipt');\n+ end;\n+\n local procedure Initialize()\n begin\n LibraryTestInitialize.OnTestInitialize(Codeunit::\"Subc. Subcontracting Test\");\n@@ -3640,6 +3734,18 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n exit(ReqWkshTemplate.Name);\n end;\n \n+ local procedure AssignItemChargeToReceiptLine(ItemChargeInvLine: Record \"Purchase Line\"; PurchRcptLine: Record \"Purch. Rcpt. Line\"; QtyToAssign: Decimal)\n+ var\n+ ItemChargeAssignmentPurch: Record \"Item Charge Assignment (Purch)\";\n+ begin\n+ LibraryInventory.CreateItemChargeAssignPurchase(\n+ ItemChargeAssignmentPurch, ItemChargeInvLine,\n+ ItemChargeAssignmentPurch.\"Applies-to Doc. Type\"::Receipt,\n+ PurchRcptLine.\"Document No.\", PurchRcptLine.\"Line No.\", PurchRcptLine.\"No.\");\n+ ItemChargeAssignmentPurch.Validate(\"Qty. to Assign\", QtyToAssign);\n+ ItemChargeAssignmentPurch.Modify(true);\n+ end;\n+\n procedure UpdateProdOrderComponentWithComponentSupplyMethod(ProductionOrder: Record \"Production Order\"; ComponentSupplyMethod: Enum \"Component Supply Method\")\n var\n ProdOrderComp: Record \"Prod. Order Component\";\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8555", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-09T19:29:14Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Quality Management\\app", "src\\Apps\\W1\\Quality Management\\test"], "patch": "diff --git a/src/Apps/W1/Quality Management/app/src/API/QltyInspectionsAPI.Page.al b/src/Apps/W1/Quality Management/app/src/API/QltyInspectionsAPI.Page.al\nindex 40d41f573e..05fd363c58 100644\n--- a/src/Apps/W1/Quality Management/app/src/API/QltyInspectionsAPI.Page.al\n+++ b/src/Apps/W1/Quality Management/app/src/API/QltyInspectionsAPI.Page.al\n@@ -470,7 +470,7 @@ page 20414 \"Qlty. Inspections API\"\n /// When left blank this assumes the same location as the from location.\n /// The target bin to move to.\n /// Quantity to move, if updating a specific quantity\n- /// When set to TRUE this will post journals immediately or create the warehouse movement. Verify you have sufficient licensing to use this flag.\n+ /// When set to TRUE this will post journals immediately or create the warehouse movement. Verify you have sufficient licensing to use this flag.\n /// Optionally restrict the locations to move from. \n /// Optionally restrict the specific bins to move from.\n /// When set to TRUE, will use the Movement Worksheet instead of a reclassification journal.\ndiff --git a/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/JobQueue/QltyScheduleInspection.Report.al b/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/JobQueue/QltyScheduleInspection.Report.al\nindex 4d477e53c9..810d8e7390 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/JobQueue/QltyScheduleInspection.Report.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/GenerationRule/JobQueue/QltyScheduleInspection.Report.al\n@@ -70,9 +70,11 @@ report 20412 \"Qlty. Schedule Inspection\"\n QltyManagementSetup: Record \"Qlty. Management Setup\";\n QltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\";\n ShowWarningIfCreateInspection: Boolean;\n- CreatedQltyInspectionIds: List of [Code[20]];\n- ZeroInspectionsCreatedMsg: Label 'No inspections were created.';\n- SomeInspectionsWereCreatedQst: Label '%1 inspections were created. Do you want to see them?', Comment = '%1=the count of inspections that were created.';\n+ NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds : List of [Code[20]];\n+ ZeroInspectionsCreatedOrMatchedMsg: Label 'No inspections were created or existing inspections matched.';\n+ SomeInspectionsCreatedQst: Label '%1 inspections were created. Do you want to see them?', Comment = '%1=the count of inspections that were newly created.';\n+ SomeInspectionsMatchedQst: Label 'No new inspections were created, but %1 existing inspections matched. Do you want to see them?', Comment = '%1=the count of existing inspections that were matched (reused).';\n+ SomeInspectionsCreatedOrMatchedQst: Label '%1 inspections were created and %2 existing inspections matched. Do you want to see all of them?', Comment = '%1=the count of newly created inspections, %2=the count of existing inspections that were matched (reused).';\n NoSourceConfigForScheduleErr: Label 'Cannot schedule inspections because no enabled source configuration with a table filter exists for source table %1. Navigate to the Quality Inspection Source Configuration page and ensure at least one enabled configuration exists for this table with a From Table Filter defined.', Comment = '%1=the source table number';\n \n trigger OnInitReport()\n@@ -85,17 +87,39 @@ report 20412 \"Qlty. Schedule Inspection\"\n trigger OnPreReport()\n begin\n Clear(QltyInspectionCreate);\n- Clear(CreatedQltyInspectionIds);\n+ Clear(NewlyCreatedQltyInspectionIds);\n+ Clear(AllResolvedQltyInspectionIds);\n end;\n \n trigger OnPostReport()\n+ var\n+ NewlyCreatedCount, ExistingMatchedCount : Integer;\n+ ShouldDisplay: Boolean;\n begin\n- if GuiAllowed() then\n- if CreatedQltyInspectionIds.Count() = 0 then\n- Message(ZeroInspectionsCreatedMsg)\n+ if not GuiAllowed() then\n+ exit;\n+\n+ if AllResolvedQltyInspectionIds.Count() = 0 then begin\n+ Message(ZeroInspectionsCreatedOrMatchedMsg);\n+ exit;\n+ end;\n+\n+ NewlyCreatedCount := NewlyCreatedQltyInspectionIds.Count();\n+ ExistingMatchedCount := AllResolvedQltyInspectionIds.Count() - NewlyCreatedCount;\n+ if ExistingMatchedCount < 0 then\n+ ExistingMatchedCount := 0;\n+\n+ case true of\n+ (NewlyCreatedCount > 0) and (ExistingMatchedCount > 0):\n+ ShouldDisplay := Confirm(StrSubstNo(SomeInspectionsCreatedOrMatchedQst, NewlyCreatedCount, ExistingMatchedCount), true);\n+ NewlyCreatedCount > 0:\n+ ShouldDisplay := Confirm(StrSubstNo(SomeInspectionsCreatedQst, NewlyCreatedCount), true);\n else\n- if Confirm(StrSubstNo(SomeInspectionsWereCreatedQst, CreatedQltyInspectionIds.Count())) then\n- QltyInspectionCreate.DisplayInspectionsIfConfigured(true, CreatedQltyInspectionIds);\n+ ShouldDisplay := Confirm(StrSubstNo(SomeInspectionsMatchedQst, ExistingMatchedCount), true);\n+ end;\n+\n+ if ShouldDisplay then\n+ QltyInspectionCreate.DisplayInspectionsIfConfigured(true, AllResolvedQltyInspectionIds);\n end;\n \n /// \n@@ -140,7 +164,7 @@ report 20412 \"Qlty. Schedule Inspection\"\n SourceRecordRef.SetView(QltyInspectSourceConfig.\"From Table Filter\");\n SourceRecordRef.FilterGroup(0);\n if SourceRecordRef.FindSet() then\n- QltyInspectionCreate.CreateMultipleInspectionsWithoutDisplaying(SourceRecordRef, GuiAllowed(), QltyInspectionGenRule, CreatedQltyInspectionIds);\n+ QltyInspectionCreate.CreateMultipleInspectionsWithoutDisplaying(SourceRecordRef, GuiAllowed(), QltyInspectionGenRule, NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds);\n until QltyInspectSourceConfig.Next() = 0;\n end;\n }\n\\ No newline at end of file\ndiff --git a/src/Apps/W1/Quality Management/app/src/Dispositions/Move/QltyDispMoveAutoChoose.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Dispositions/Move/QltyDispMoveAutoChoose.Codeunit.al\nindex ea364e569a..c887da3c28 100644\n--- a/src/Apps/W1/Quality Management/app/src/Dispositions/Move/QltyDispMoveAutoChoose.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Dispositions/Move/QltyDispMoveAutoChoose.Codeunit.al\n@@ -84,7 +84,7 @@ codeunit 20442 \"Qlty. Disp. Move Auto Choose\" implements \"Qlty. Disposition\"\n end;\n \n /// \n- /// Do not use directly for net new code. This method is an interim shim to help with obsoletions and refactoring for dispositions.\n+ /// Do not use directly for net new code. This method is an interim shim to help with obsoletions and refactoring for dispositions.\n /// Instead use the new dispositions directly.\n /// \n /// \ndiff --git a/src/Apps/W1/Quality Management/app/src/Dispositions/PutAway/QltyDispWarehousePutAway.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Dispositions/PutAway/QltyDispWarehousePutAway.Codeunit.al\nindex 531f392913..c5d721633f 100644\n--- a/src/Apps/W1/Quality Management/app/src/Dispositions/PutAway/QltyDispWarehousePutAway.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Dispositions/PutAway/QltyDispWarehousePutAway.Codeunit.al\n@@ -30,7 +30,7 @@ codeunit 20453 \"Qlty. Disp. Warehouse Put-away\" implements \"Qlty. Disposition\"\n /// You must be in a directed pick and put location, and you must be using lot warehouse tracking to use this feature.\n /// \n /// The inspection to create the internal put-away from\n- /// Optional quantity. Leave blank to use the entire lot or the quantity from the inspection.\n+ /// Optional quantity. Leave blank to use the entire lot or the quantity from the inspection.\n /// Optional limitations on the source location.\n /// Optional limitations on the source bin.\n /// The quantity behavior\ndiff --git a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionCreate.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionCreate.Codeunit.al\nindex 17b0f93181..7361a83742 100644\n--- a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionCreate.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionCreate.Codeunit.al\n@@ -36,6 +36,7 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n LastQltyInspectionCreateStatus: Enum \"Qlty. Inspection Create Status\";\n PreventShowingGeneratedInspectionEvenIfConfigured: Boolean;\n AvoidThrowingErrorWhenPossible: Boolean;\n+ LastInspectionIsNewlyCreated: Boolean;\n ProgrammerErrNotARecordRefErr: Label 'Cannot find inspections with %1. Please supply a \"Record\" or \"RecordRef\".', Comment = '%1=the variant being supplied that is not a RecordRef. Your system might have an extension or customization that needs to be re-configured.';\n CannotFindTemplateErr: Label 'Cannot find a Quality Inspection Template or Quality Inspection Generation Rule to match %1. Ensure there is a Quality Inspection Generation Rule that will match this record.', Comment = '%1=The record identifier';\n UnableToCreateInspectionForErr: Label 'Unable to create an inspection for the record [%1], please review the Quality Inspection Source Configuration and also the Quality Inspection Generation Rules, you likely need additional configuration to work with this record.', Comment = '%1=the record id of what is being attempted to have an inspection created for.';\n@@ -43,9 +44,10 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n MultiRecordInspectionSourceFieldErr: Label 'Inspection %1 has been created, however neither %2 nor %4 had applicable source fields to map to the inspection. Navigate to the Quality Source Configuration for table %3 and apply source field mapping.', Comment = '%1=the inspection, %2=target record, %3=the number to set configuration for,%4=triggering record';\n RegisteredLogEventIDTok: Label 'QMERR0001', Locked = true;\n DetailRecordTok: Label 'Target', Locked = true;\n- UnableToCreateInspectionForParentOrChildErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. Two tables involved are %1 and %2.', Comment = '%1=the parent table, %2=the child and original table.';\n- UnableToCreateInspectionForRecordErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. The table involved is %1.', Comment = '%1=the table involved.';\n+ UnableToCreateInspectionForParentOrChildErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. Two tables involved are %1 and %2.', Comment = '%1=the parent table, %2=the child and original table.';\n+ UnableToCreateInspectionForRecordErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. The table involved is %1.', Comment = '%1=the table involved.';\n RecordShouldBeTemporaryErr: Label 'This code is only intended to run in a temporary fashion. This error is likely occurring from an integration issue.';\n+ SomeInspectionsMatchedQst: Label 'No new inspections were created, but %1 existing inspections matched. Do you want to see them?', Comment = '%1=the count of existing inspections that were matched (reused).';\n UnknownRecordTok: Label 'Unknown record', Locked = true;\n \n /// \n@@ -280,6 +282,8 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n OriginalRecordTableNo: Integer;\n IsNewlyCreatedInspection: Boolean;\n begin\n+ LastInspectionIsNewlyCreated := false;\n+\n case true of\n TargetRecordRef.Number() = 0,\n not QltyManagementSetup.GetSetupRecord():\n@@ -354,17 +358,22 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n \n QltyInspectionHeader.SetIsCreating(false);\n LastCreatedQltyInspectionHeader := QltyInspectionHeader;\n+ LastInspectionIsNewlyCreated := IsNewlyCreatedInspection;\n \n if IsNewlyCreatedInspection then\n QltyStartWorkflow.StartWorkflowInspectionCreated(QltyInspectionHeader);\n \n- if GuiAllowed() and not PreventShowingGeneratedInspectionEvenIfConfigured\n- and (QltyInspectionHeader.\"No.\" <> '') then\n+ if GuiAllowed() and\n+ not PreventShowingGeneratedInspectionEvenIfConfigured and\n+ (QltyInspectionHeader.\"No.\" <> '')\n+ then\n if IsManualCreation then\n Page.Run(Page::\"Qlty. Inspection\", QltyInspectionHeader)\n else\n- QltyNotificationMgmt.NotifyInspectionCreated(QltyInspectionHeader);\n+ if IsNewlyCreatedInspection then\n+ QltyNotificationMgmt.NotifyInspectionCreated(QltyInspectionHeader);\n end else begin\n+ LastInspectionIsNewlyCreated := false;\n LogCreateInspectionProblem(TargetRecordRef, UnableToCreateInspectionForErr, Format(OriginalRecordId));\n if IsManualCreation and (not AvoidThrowingErrorWhenPossible) then\n Error(UnableToCreateInspectionForErr, Format(OriginalRecordId));\n@@ -775,6 +784,21 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n exit(LastQltyInspectionCreateStatus);\n end;\n \n+ /// \n+ /// Indicates whether the inspection returned by the last create call was newly inserted\n+ /// or whether an existing matching inspection was reused (e.g. when the Inspection Creation\n+ /// Option is configured to use an existing inspection if available).\n+ /// Only valid immediately after a successful CreateInspection* call on this instance.\n+ /// \n+ /// True when the last inspection was newly created; false when it was reused, no inspection was returned.\n+ internal procedure IsLastInspectionNewlyCreated(): Boolean\n+ begin\n+ if LastCreatedQltyInspectionHeader.\"No.\" = '' then\n+ exit(false);\n+\n+ exit(LastInspectionIsNewlyCreated);\n+ end;\n+\n /// \n /// Use this to log QMERR0001\n /// \n@@ -835,15 +859,25 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n \n internal procedure CreateMultipleInspectionsForMultipleRecords(var SetOfRecordsRecordRef: RecordRef; IsManualCreation: Boolean; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary)\n var\n- CreatedQltyInspectionIds: List of [Code[20]];\n+ NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds : List of [Code[20]];\n+ NewlyCreatedCount, ExistingMatchedCount : Integer;\n begin\n- CreateMultipleInspectionsWithoutDisplaying(SetOfRecordsRecordRef, IsManualCreation, TempFiltersQltyInspectionGenRule, CreatedQltyInspectionIds);\n-\n- if IsManualCreation and GuiAllowed() then\n- DisplayInspectionsIfConfigured(IsManualCreation, CreatedQltyInspectionIds);\n+ CreateMultipleInspectionsWithoutDisplaying(SetOfRecordsRecordRef, IsManualCreation, TempFiltersQltyInspectionGenRule, NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds);\n+\n+ if IsManualCreation and GuiAllowed() then begin\n+ NewlyCreatedCount := NewlyCreatedQltyInspectionIds.Count();\n+ if NewlyCreatedCount > 0 then\n+ DisplayInspectionsIfConfigured(IsManualCreation, NewlyCreatedQltyInspectionIds)\n+ else begin\n+ ExistingMatchedCount := AllResolvedQltyInspectionIds.Count();\n+ if ExistingMatchedCount > 0 then\n+ if Confirm(StrSubstNo(SomeInspectionsMatchedQst, ExistingMatchedCount), true) then\n+ DisplayInspectionsIfConfigured(IsManualCreation, AllResolvedQltyInspectionIds);\n+ end;\n+ end;\n end;\n \n- internal procedure DisplayInspectionsIfConfigured(IsManualCreation: Boolean; var CreatedQltyInspectionIds: List of [Code[20]])\n+ internal procedure DisplayInspectionsIfConfigured(IsManualCreation: Boolean; var ToDisplayQltyInspectionIds: List of [Code[20]])\n var\n CreatedQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n QltyNotificationMgmt: Codeunit \"Qlty. Notification Mgmt.\";\n@@ -856,7 +890,7 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n MaxSafeFilterLength := 1024;\n \n if GuiAllowed() then begin\n- foreach InspectionNo in CreatedQltyInspectionIds do\n+ foreach InspectionNo in ToDisplayQltyInspectionIds do\n if InspectionNo <> '' then begin\n if StrLen(PipeSeparatedFilter) > 1 then\n PipeSeparatedFilter += '|';\n@@ -868,12 +902,12 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n end;\n \n if FilterExceedsMaxLength then begin\n- QltyNotificationMgmt.NotifyMultipleInspectionsCreatedByCount(CreatedQltyInspectionIds.Count());\n+ QltyNotificationMgmt.NotifyMultipleInspectionsCreatedByCount(ToDisplayQltyInspectionIds.Count());\n exit;\n end;\n \n CreatedQltyInspectionHeader.SetFilter(\"No.\", PipeSeparatedFilter);\n- if CreatedQltyInspectionIds.Count() = 1 then begin\n+ if ToDisplayQltyInspectionIds.Count() = 1 then begin\n CreatedQltyInspectionHeader.SetCurrentKey(\"No.\", \"Re-inspection No.\");\n CreatedQltyInspectionHeader.FindLast();\n if IsManualCreation then\n@@ -892,17 +926,18 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n \n /// \n /// Use this if you need to keep track of multiple inspections without displaying the results.\n+ /// Distinguishes inspections that were newly inserted from inspections that were reused\n+ /// (matched an existing open inspection).\n /// \n /// \n /// \n- /// \n- /// \n- internal procedure CreateMultipleInspectionsWithoutDisplaying(var SetOfRecordsRecordRef: RecordRef; IsManualCreation: Boolean; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary; var CreatedQltyInspectionIds: List of [Code[20]])\n+ /// \n+ /// Receives only inspections that were newly inserted by this call.\n+ /// Receives every inspection that was either newly inserted or reused (matched an existing open inspection).\n+ internal procedure CreateMultipleInspectionsWithoutDisplaying(var SetOfRecordsRecordRef: RecordRef; IsManualCreation: Boolean; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary; var NewlyCreatedQltyInspectionIds: List of [Code[20]]; var AllResolvedQltyInspectionIds: List of [Code[20]])\n var\n TempCopyOfSingleRecordRecordRef: RecordRef;\n ParentRecordRef: RecordRef;\n- FailedInspectionIds: List of [Text];\n- CountOfInspectionsCreatedForLine: Integer;\n begin\n QltyManagementSetup.Get();\n \n@@ -915,18 +950,18 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n \n TempCopyOfSingleRecordRecordRef.Copy(SetOfRecordsRecordRef, false);\n TempCopyOfSingleRecordRecordRef.Insert(false);\n- CountOfInspectionsCreatedForLine := CreateInspectionForSelfOrDirectParent(\n+ CreateInspectionForSelfOrDirectParent(\n TempCopyOfSingleRecordRecordRef,\n TempFiltersQltyInspectionGenRule,\n ParentRecordRef,\n- CreatedQltyInspectionIds,\n+ NewlyCreatedQltyInspectionIds,\n+ AllResolvedQltyInspectionIds,\n true,\n IsManualCreation);\n- if CountOfInspectionsCreatedForLine = 0 then\n- FailedInspectionIds.Add(Format(SetOfRecordsRecordRef.RecordId()));\n until SetOfRecordsRecordRef.Next() = 0;\n \n- if CreatedQltyInspectionIds.Count() = 0 then begin\n+ // Error only when no inspection was resolved at all (neither newly created nor matching ones reused).\n+ if AllResolvedQltyInspectionIds.Count() = 0 then begin\n if AvoidThrowingErrorWhenPossible then\n exit;\n \n@@ -937,9 +972,8 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n end;\n end;\n \n- local procedure CreateInspectionForSelfOrDirectParent(var TempSelfRecordRef: RecordRef; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary; var FoundParentRecordRef: RecordRef; var CreatedQltyInspectionIds: List of [Code[20]]; PreventInspectionFromDisplayingEvenIfConfigured: Boolean; IsManualCreation: Boolean) InspectionCreatedCount: Integer\n+ local procedure CreateInspectionForSelfOrDirectParent(var TempSelfRecordRef: RecordRef; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary; var FoundParentRecordRef: RecordRef; var NewlyCreatedQltyInspectionIds: List of [Code[20]]; var AllResolvedQltyInspectionIds: List of [Code[20]]; PreventInspectionFromDisplayingEvenIfConfigured: Boolean; IsManualCreation: Boolean)\n var\n- LastCreatedQltyInspectionHeader2: Record \"Qlty. Inspection Header\";\n Item: Record Item;\n TempTrackingSpecification: Record \"Tracking Specification\" temporary;\n LocalQltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\";\n@@ -949,8 +983,6 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n VariantEmptyOrTrackingSpecification: Variant;\n Dummy4Variant: Variant;\n begin\n- InspectionCreatedCount := 0;\n-\n LocalQltyInspectionCreate.SetPreventDisplayingInspectionEvenIfConfigured(PreventInspectionFromDisplayingEvenIfConfigured);\n \n Clear(FoundParentRecordRef);\n@@ -1013,11 +1045,7 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n end;\n \n if LocalQltyInspectionCreate.CreateInspectionWithMultiVariants(ParentRecordRef, TempSelfRecordRef, VariantEmptyOrTrackingSpecification, Dummy4Variant, IsManualCreation, TempFiltersQltyInspectionGenRule) then\n- if LocalQltyInspectionCreate.GetCreatedInspection(LastCreatedQltyInspectionHeader2) then begin\n- InspectionCreatedCount += 1;\n- if not CreatedQltyInspectionIds.Contains(LastCreatedQltyInspectionHeader2.\"No.\") then\n- CreatedQltyInspectionIds.Add(LastCreatedQltyInspectionHeader2.\"No.\");\n- end;\n+ TrackResolvedInspection(LocalQltyInspectionCreate, NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds);\n until RelatedReservFilterReservationEntry.Next() = 0;\n end else begin\n if TempFiltersQltyInspectionGenRule.\"Item Filter\" <> '' then begin\n@@ -1027,21 +1055,38 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n end;\n \n if LocalQltyInspectionCreate.CreateInspectionWithMultiVariants(TempSelfRecordRef, ParentRecordRef, Dummy4Variant, Dummy4Variant, IsManualCreation, TempFiltersQltyInspectionGenRule) then\n- if LocalQltyInspectionCreate.GetCreatedInspection(LastCreatedQltyInspectionHeader2) then begin\n- InspectionCreatedCount += 1;\n- if not CreatedQltyInspectionIds.Contains(LastCreatedQltyInspectionHeader2.\"No.\") then\n- CreatedQltyInspectionIds.Add(LastCreatedQltyInspectionHeader2.\"No.\");\n- end;\n+ TrackResolvedInspection(LocalQltyInspectionCreate, NewlyCreatedQltyInspectionIds, AllResolvedQltyInspectionIds);\n end;\n end;\n \n+ /// \n+ /// Records the inspection returned by the last create call on in the\n+ /// supplied tracking lists, deduplicating by inspection \"No.\". The all-resolved list captures both newly created\n+ /// and reused matching inspections so callers can detect reuse; the newly-created list only captures inspections that were\n+ /// actually inserted and is used to drive \"created inspections\" notifications and display.\n+ /// \n+ local procedure TrackResolvedInspection(var LocalQltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\"; var NewlyCreatedQltyInspectionIds: List of [Code[20]]; var AllResolvedQltyInspectionIds: List of [Code[20]])\n+ var\n+ LastResolvedQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ begin\n+ if not LocalQltyInspectionCreate.GetCreatedInspection(LastResolvedQltyInspectionHeader) then\n+ exit;\n+\n+ if not AllResolvedQltyInspectionIds.Contains(LastResolvedQltyInspectionHeader.\"No.\") then\n+ AllResolvedQltyInspectionIds.Add(LastResolvedQltyInspectionHeader.\"No.\");\n+\n+ if LocalQltyInspectionCreate.IsLastInspectionNewlyCreated() then\n+ if not NewlyCreatedQltyInspectionIds.Contains(LastResolvedQltyInspectionHeader.\"No.\") then\n+ NewlyCreatedQltyInspectionIds.Add(LastResolvedQltyInspectionHeader.\"No.\");\n+ end;\n+\n internal procedure SetPreventDisplayingInspectionEvenIfConfigured(PreventDisplayingInspectionEvenIfConfigured: Boolean)\n begin\n PreventShowingGeneratedInspectionEvenIfConfigured := PreventDisplayingInspectionEvenIfConfigured;\n end;\n \n /// \n- /// Stubs in and filles the source config fields.\n+ /// Stubs in and fills the source config fields.\n /// \n /// \n /// \n@@ -1189,9 +1234,9 @@ codeunit 20404 \"Qlty. Inspection - Create\"\n /// OnBeforeFindExistingInspection provides an opportunity to override how an existing inspection is found.\n /// \n /// The main target record that the inspection will be created against\n- /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n- /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n- /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n+ /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n+ /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n+ /// Optional. Some events, typically automatic events, will have multiple records to assist with setting source details.\n /// The found inspection\n /// Set to true if you found the record. If you set to true you must also supply QltyInspectionHeader\n /// Set to true to replace the default behavior\ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Assembly/QltyAssemblyIntegration.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Assembly/QltyAssemblyIntegration.Codeunit.al\nindex d0e09fcd50..f1a04da682 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Assembly/QltyAssemblyIntegration.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Assembly/QltyAssemblyIntegration.Codeunit.al\n@@ -56,7 +56,7 @@ codeunit 20412 \"Qlty. Assembly Integration\"\n if QltyInspectionHeader.\"No.\" <> '' then begin\n QltyInspectionHeader.\"Source Quantity (Base)\" := TempSpecTrackingSpecification.\"Quantity (Base)\";\n QltyInspectionHeader.Modify(false);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n end;\n OnAfterAttemptCreateInspectionFromPostedAssembly(AssemblyHeader, PostedAssemblyHeader, TempSpecTrackingSpecification, QltyInspectionHeader);\n@@ -69,7 +69,7 @@ codeunit 20412 \"Qlty. Assembly Integration\"\n HasInspection := QltyInspectionCreate.CreateInspectionWithMultiVariants(PostedAssemblyHeader, AssemblyHeader, UnusedVariant1, UnusedVariant2, false, TempQltyInspectionGenRule);\n if HasInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n OnAfterAttemptCreateInspectionFromPostedAssembly(AssemblyHeader, PostedAssemblyHeader, TempSpecTrackingSpecification, QltyInspectionHeader);\n end;\ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyInventoryAvailability.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyInventoryAvailability.Codeunit.al\nindex e3f2663337..ee7b0421c7 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyInventoryAvailability.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyInventoryAvailability.Codeunit.al\n@@ -43,7 +43,7 @@ codeunit 20445 \"Qlty. Inventory Availability\"\n /// If multiple locations/bins are determined then those multiple locations/bins are supplied in TempBinContent\n /// \n /// Record \"Qlty. Inspection Header\".\n- /// Temporary var Record \"Bin Content\". Multiple bin locations could be available.\n+ /// Temporary var Record \"Bin Content\". Multiple bin locations could be available.\n /// Return variable of type Boolean.\n internal procedure GetCurrentLocationOfTrackedInventory(QltyInspectionHeader: Record \"Qlty. Inspection Header\"; var TempBinContent: Record \"Bin Content\" temporary): Boolean\n begin\ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyItemTrackingMgmt.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyItemTrackingMgmt.Codeunit.al\nindex 2ba99aee7c..7a55bd4499 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyItemTrackingMgmt.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Inventory/QltyItemTrackingMgmt.Codeunit.al\n@@ -465,7 +465,7 @@ codeunit 20439 \"Qlty. Item Tracking Mgmt.\"\n end;\n \n /// \n- /// Adds/Removes Purchase Return Line item tracking entries. When used with serial numbers only one serial number can be created at a time.\n+ /// Adds/Removes Purchase Return Line item tracking entries. When used with serial numbers only one serial number can be created at a time.\n /// \n /// \n /// \ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Manufacturing/QltyManufacturIntegration.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Manufacturing/QltyManufacturIntegration.Codeunit.al\nindex fbd26b1822..8343732866 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Manufacturing/QltyManufacturIntegration.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Manufacturing/QltyManufacturIntegration.Codeunit.al\n@@ -390,7 +390,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n if MadeInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n ListOfInspectionIds.Add(QltyInspectionHeader.RecordId());\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n CreatedAtLeastOneInspectionForRoutingLine := true;\n end;\n until ReservationEntry.Next() = 0;\n@@ -400,7 +400,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n if MadeInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n ListOfInspectionIds.Add(QltyInspectionHeader.RecordId());\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n CreatedAtLeastOneInspectionForRoutingLine := true;\n end;\n end;\n@@ -421,7 +421,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n if MadeInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n ListOfInspectionIds.Add(QltyInspectionHeader.RecordId());\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n CreatedAtLeastOneInspectionForOrderLine := true;\n end;\n \n@@ -431,7 +431,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n if MadeInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n ListOfInspectionIds.Add(QltyInspectionHeader.RecordId());\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n CreatedAtLeastOneInspectionForOrderLine := true;\n end;\n end;\n@@ -442,7 +442,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n if MadeInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n ListOfInspectionIds.Add(QltyInspectionHeader.RecordId());\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n CreatedInspectionForProdOrder := MadeInspection;\n end;\n end;\n@@ -492,7 +492,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n /// Typically the 'main' record the inspections are associated against.\n /// The item ledger entry related to this sequence of events\n /// The production order line involved in this sequence of events\n- /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n+ /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n /// Set to true to replace the default behavior\n [IntegrationEvent(false, false)]\n local procedure OnBeforeProductionAttemptCreatePostAutomaticInspection(var ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; var ItemLedgerEntry: Record \"Item Ledger Entry\"; var ProdOrderLine: Record \"Prod. Order Line\"; var ItemJournalLine: Record \"Item Journal Line\"; var IsHandled: Boolean)\n@@ -505,7 +505,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n /// Typically the 'main' record the inspections are associated against.\n /// The item ledger entry related to this sequence of events\n /// The production order line involved in this sequence of events\n- /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n+ /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n [IntegrationEvent(false, false)]\n local procedure OnAfterProductionAttemptCreateAutomaticInspection(var ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; var ItemLedgerEntry: Record \"Item Ledger Entry\"; var ProdOrderLine: Record \"Prod. Order Line\"; var ItemJournalLine: Record \"Item Journal Line\")\n begin\n@@ -541,7 +541,7 @@ codeunit 20407 \"Qlty. Manufactur. Integration\"\n /// \n /// The item ledger entry related to this sequence of events\n /// The production order line involved in this sequence of events\n- /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n+ /// The item journal line record involved in this transaction. Important: this record may no longer exist, and should not be altered.\n /// Set to true to replace the default behavior\n [IntegrationEvent(false, false)]\n local procedure OnBeforeProductionHandleOnAfterPostOutput(var ItemLedgerEntry: Record \"Item Ledger Entry\"; var ProdOrderLine: Record \"Prod. Order Line\"; var ItemJournalLine: Record \"Item Journal Line\"; var IsHandled: Boolean)\ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Receiving/QltyReceivingIntegration.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Receiving/QltyReceivingIntegration.Codeunit.al\nindex 4fb106bf37..1c4dbef6cd 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Receiving/QltyReceivingIntegration.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Receiving/QltyReceivingIntegration.Codeunit.al\n@@ -170,14 +170,14 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(SalesLine, TempTrackingSpecification, DummyVariant, DummyVariant, false, QltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n until TempTrackingSpecification.Next() = 0\n else\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(SalesLine, DummyVariant, DummyVariant, DummyVariant, false, QltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n QltyBatchNotifHelper.EndBatch();\n end;\n@@ -306,7 +306,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseReceiptLine, OptionalSourceLineVariant, WarehouseReceiptHeader, TempTrackingSpecification, false, TempQltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n until TempTrackingSpecification.Next() = 0\n else begin\n@@ -314,7 +314,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseReceiptLine, OptionalSourceLineVariant, WarehouseReceiptHeader, DummyVariant, false, TempQltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n end;\n \n@@ -350,7 +350,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseJournalLine, OptionalSourceRecordVariant, PostedWhseReceiptHeader, TempTrackingSpecification, false, TempQltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n until TempTrackingSpecification.Next() = 0\n else begin\n@@ -358,7 +358,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseJournalLine, OptionalSourceRecordVariant, PostedWhseReceiptHeader, DummyVariant, false, TempQltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n end;\n \n@@ -384,7 +384,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n HasInspection := QltyInspectionCreate.CreateInspectionWithMultiVariants(PurchaseLine, PurchaseHeader, TempTrackingSpecification, DummyVariant, false, TempQltyInspectionGenRule);\n if HasInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n \n OnAfterPurchaseAttemptCreateInspectionWithPurchaseLine(HasInspection, QltyInspectionHeader, PurchaseLine, PurchaseHeader, TempTrackingSpecification);\n@@ -423,7 +423,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n \n if HasInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n until TempTrackingSpecification.Next() = 0\n else begin\n@@ -436,7 +436,7 @@ codeunit 20411 \"Qlty. Receiving Integration\"\n \n if HasInspection then begin\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n end;\n OnAfterTransferAttemptCreateInspectionWithInboundTransferLine(TransTransferLine, OptionalTransferReceiptHeader, OptionalDirectTransHeader, TempTrackingSpecification, QltyInspectionHeader, HasInspection);\ndiff --git a/src/Apps/W1/Quality Management/app/src/Integration/Warehouse/QltyWarehouseIntegration.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Integration/Warehouse/QltyWarehouseIntegration.Codeunit.al\nindex df7071bab4..61111f4e45 100644\n--- a/src/Apps/W1/Quality Management/app/src/Integration/Warehouse/QltyWarehouseIntegration.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Integration/Warehouse/QltyWarehouseIntegration.Codeunit.al\n@@ -70,14 +70,14 @@ codeunit 20438 \"Qlty. Warehouse Integration\"\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseEntry, WarehouseJournalLine, TempTrackingSpecification, DummyVariant, false, QltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n until TempTrackingSpecification.Next() = 0\n else\n if QltyInspectionCreate.CreateInspectionWithMultiVariants(WarehouseEntry, WarehouseJournalLine, DummyVariant, DummyVariant, false, QltyInspectionGenRule) then begin\n HasInspection := true;\n QltyInspectionCreate.GetCreatedInspection(QltyInspectionHeader);\n- QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\");\n+ QltyBatchNotifHelper.TrackCreatedInspection(QltyInspectionHeader.\"No.\", QltyInspectionCreate.IsLastInspectionNewlyCreated());\n end;\n QltyBatchNotifHelper.EndBatch();\n \ndiff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyBatchNotifHelper.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyBatchNotifHelper.Codeunit.al\nindex 4269b2b85b..573549f905 100644\n--- a/src/Apps/W1/Quality Management/app/src/Utilities/QltyBatchNotifHelper.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyBatchNotifHelper.Codeunit.al\n@@ -9,12 +9,12 @@ using Microsoft.QualityManagement.Document;\n codeunit 20456 \"Qlty. Batch Notif. Helper\"\n {\n var\n- BatchCreatedInspectionIds: List of [Code[20]];\n+ BatchCreatedQltyInspectionIds: List of [Code[20]];\n IsBatchActive: Boolean;\n \n internal procedure BeginBatch()\n begin\n- Clear(BatchCreatedInspectionIds);\n+ Clear(BatchCreatedQltyInspectionIds);\n IsBatchActive := true;\n end;\n \n@@ -26,23 +26,26 @@ codeunit 20456 \"Qlty. Batch Notif. Helper\"\n exit;\n \n IsBatchActive := false;\n- if BatchCreatedInspectionIds.Count() = 0 then\n+ if BatchCreatedQltyInspectionIds.Count() = 0 then\n exit;\n \n- QltyInspectionCreate.DisplayInspectionsIfConfigured(false, BatchCreatedInspectionIds);\n- Clear(BatchCreatedInspectionIds);\n+ QltyInspectionCreate.DisplayInspectionsIfConfigured(false, BatchCreatedQltyInspectionIds);\n+ Clear(BatchCreatedQltyInspectionIds);\n end;\n \n- internal procedure TrackCreatedInspection(InspectionNo: Code[20])\n+ internal procedure TrackCreatedInspection(InspectionNo: Code[20]; IsNewlyCreated: Boolean)\n begin\n if not IsBatchActive then\n exit;\n \n+ if not IsNewlyCreated then\n+ exit;\n+\n if InspectionNo = '' then\n exit;\n \n- if not BatchCreatedInspectionIds.Contains(InspectionNo) then\n- BatchCreatedInspectionIds.Add(InspectionNo);\n+ if not BatchCreatedQltyInspectionIds.Contains(InspectionNo) then\n+ BatchCreatedQltyInspectionIds.Add(InspectionNo);\n end;\n \n internal procedure ConfigureForBatch(var QltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\")\ndiff --git a/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al\nindex fffa286fab..87a723a23c 100644\n--- a/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Utilities/QltyMiscHelpers.Codeunit.al\n@@ -80,7 +80,7 @@ codeunit 20599 \"Qlty. Misc Helpers\"\n /// This will evaluate expressions!\n /// \n /// \n- /// Optional. Leave empty if you do not want search/replace fields. Supply an inspection context if you want the lookup table filter to have square bracket [FIELDNAME] replacements \n+ /// Optional. Leave empty if you do not want search/replace fields. Supply an inspection context if you want the lookup table filter to have square bracket [FIELDNAME] replacements \n /// \n internal procedure GetRecordsForTableField(var QltyTest: Record \"Qlty. Test\"; var OptionalContextQltyInspectionHeader: Record \"Qlty. Inspection Header\"; var TempBufferQltyTestLookupValue: Record \"Qlty. Test Lookup Value\" temporary)\n var\n", "FAIL_TO_PASS": [{"codeunitID": 139959, "functionName": ["CreateInspection_ReusedExisting_NotReportedAsNewlyCreated", "CreateInspection_NewInsertion_ReportedAsNewlyCreated", "CreateMultipleInspections_ReusedExisting_ExcludedFromCreatedIdsList"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Quality Management/Test Library/src/QltyInspectionUtility.Codeunit.al b/src/Apps/W1/Quality Management/Test Library/src/QltyInspectionUtility.Codeunit.al\nindex 3385ee112c..14c1d2a042 100644\n--- a/src/Apps/W1/Quality Management/Test Library/src/QltyInspectionUtility.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/Test Library/src/QltyInspectionUtility.Codeunit.al\n@@ -1336,6 +1336,47 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n exit(Result);\n end;\n \n+ /// \n+ /// Wrapper for QltyInspectionCreate.CreateInspection that also reports whether the returned inspection was newly created or reused.\n+ /// Use this in tests that verify the \"newly created vs reused\" distinction (e.g., to assert the inspection-created notification\n+ /// is only raised for newly created inspections).\n+ /// \n+ /// The source record to create an inspection from.\n+ /// True when user manually creates inspection; False for automatic/triggered creation.\n+ /// Output: the created or reused inspection header.\n+ /// Output: true when the inspection was newly inserted; false when an existing inspection was reused.\n+ /// True if an inspection was created or found/reused.\n+ internal procedure CreateInspectionAndReportIfNewlyCreated(TargetRecordRef: RecordRef; IsManualCreation: Boolean; var OutQltyInspectionHeader: Record \"Qlty. Inspection Header\"; var OutIsNewlyCreated: Boolean): Boolean\n+ var\n+ QltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\";\n+ Result: Boolean;\n+ begin\n+ Result := QltyInspectionCreate.CreateInspection(TargetRecordRef, IsManualCreation);\n+ OutIsNewlyCreated := false;\n+ if Result then begin\n+ QltyInspectionCreate.GetCreatedInspection(OutQltyInspectionHeader);\n+ OutIsNewlyCreated := QltyInspectionCreate.IsLastInspectionNewlyCreated();\n+ end;\n+ exit(Result);\n+ end;\n+\n+ /// \n+ /// Wrapper for internal QltyInspectionCreate.CreateMultipleInspectionsWithoutDisplaying.\n+ /// Returns both the inspections that were newly created and the full set of inspections that were resolved\n+ /// (new + reused).\n+ /// \n+ /// RecordRef containing the records to create inspections for.\n+ /// Whether this is a manual creation (affects display behavior).\n+ /// Temporary record with filters that constrain which generation rules apply.\n+ /// Output: list of inspection \"No.\" values for inspections that were newly inserted.\n+ /// Output: list of inspection \"No.\" values for every inspection that was newly inserted or reused.\n+ internal procedure CreateMultipleInspectionsWithoutDisplaying(var SetOfRecordsRecordRef: RecordRef; IsManualCreation: Boolean; var TempFiltersQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary; var OutNewlyCreatedQltyInspectionIds: List of [Code[20]]; var OutAllResolvedQltyInspectionIds: List of [Code[20]])\n+ var\n+ QltyInspectionCreate: Codeunit \"Qlty. Inspection - Create\";\n+ begin\n+ QltyInspectionCreate.CreateMultipleInspectionsWithoutDisplaying(SetOfRecordsRecordRef, IsManualCreation, TempFiltersQltyInspectionGenRule, OutNewlyCreatedQltyInspectionIds, OutAllResolvedQltyInspectionIds);\n+ end;\n+\n /// \n /// Wrapper for QltyInspectionCreate.CreateInspectionWithVariant.\n /// Creates a quality inspection from a variant using generation rule configuration.\n@@ -1527,7 +1568,7 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n exit(QltyInspectionCreate.FindExistingInspectionWithVariant(TargetRecordRef, OptionalVariant2, OptionalVariant3, OptionalVariant4, TempQltyInspectionGenRule, OutQltyInspectionHeader, FindAll));\n end;\n \n- #endregion Qlty. Inspection - Create Wrappers\n+ #endregion Qlty. Inspection - Create Wrappers \n \n #region Qlty. Disposition Wrappers\n \n@@ -1536,10 +1577,10 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n /// Performs disposition and returns the created purchase return buffer.\n /// \n internal procedure PerformPurchaseReturnDisposition(var QltyInspectionHeader: Record \"Qlty. Inspection Header\"; QltyQuantityBehavior: Enum \"Qlty. Quantity Behavior\"; OptionalSpecificQuantity: Decimal;\n- OptionalSourceLocationFilter: Text;\n- OptionalSourceBinFilter: Text;\n- ReasonCode: Code[10];\n- ExternalDocumentNo: Code[35]; var TempCreatedBufferPurchaseHeader: Record \"Purchase Header\" temporary): Boolean\n+ OptionalSourceLocationFilter: Text;\n+ OptionalSourceBinFilter: Text;\n+ ReasonCode: Code[10];\n+ ExternalDocumentNo: Code[35]; var TempCreatedBufferPurchaseHeader: Record \"Purchase Header\" temporary): Boolean\n var\n QltyDispPurchaseReturn: Codeunit \"Qlty. Disp. Purchase Return\";\n Result: Boolean;\n@@ -1553,9 +1594,9 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n /// Wrapper for internal QltyDispNegAdjustInv.PerformDisposition (7-argument version).\n /// \n internal procedure PerformNegAdjustInvDisposition(var QltyInspectionHeader: Record \"Qlty. Inspection Header\"; OptionalSpecificQuantity: Decimal; QltyQuantityBehavior: Enum \"Qlty. Quantity Behavior\"; OptionalSourceLocationFilter: Text;\n- OptionalSourceBinFilter: Text;\n- PostingBehavior: Enum \"Qlty. Item Adj. Post Behavior\";\n- Reason: Code[10]): Boolean\n+ OptionalSourceBinFilter: Text;\n+ PostingBehavior: Enum \"Qlty. Item Adj. Post Behavior\";\n+ Reason: Code[10]): Boolean\n var\n QltyDispNegAdjustInv: Codeunit \"Qlty. Disp. Neg. Adjust Inv.\";\n begin\n@@ -1566,9 +1607,9 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n /// Wrapper for internal QltyDispTransfer.PerformDisposition (7-argument version).\n /// \n internal procedure PerformTransferDisposition(QltyInspectionHeader: Record \"Qlty. Inspection Header\"; OptionalSpecificQuantity: Decimal; QltyQuantityBehavior: Enum \"Qlty. Quantity Behavior\"; OptionalSourceLocationFilter: Text;\n- OptionalSourceBinFilter: Text;\n- DestinationLocationCode: Code[10];\n- OptionalInTransitLocationCode: Code[10]): Boolean\n+ OptionalSourceBinFilter: Text;\n+ DestinationLocationCode: Code[10];\n+ OptionalInTransitLocationCode: Code[10]): Boolean\n var\n QltyDispTransfer: Codeunit \"Qlty. Disp. Transfer\";\n begin\n@@ -3102,7 +3143,8 @@ codeunit 139940 \"Qlty. Inspection Utility\"\n /// \n /// Wrapper for QltyResultEvaluation.EvaluateResult\n /// \n- internal procedure EvaluateResult(var OptionalQltyInspectionHeader: Record \"Qlty. Inspection Header\"; var OptionalQltyInspectionLine: Record \"Qlty. Inspection Line\"; var QltyIResultConditConf: Record \"Qlty. I. Result Condit. Conf.\"; QltyTestValueType: Enum \"Qlty. Test Value Type\"; TestValue: Text; QltyCaseSensitivity: Enum \"Qlty. Case Sensitivity\"): Code[20]\n+ internal procedure EvaluateResult(var OptionalQltyInspectionHeader: Record \"Qlty. Inspection Header\"; var OptionalQltyInspectionLine: Record \"Qlty. Inspection Line\"; var QltyIResultConditConf: Record \"Qlty. I. Result Condit. Conf.\"; QltyTestValueType: Enum \"Qlty. Test Value Type\"; TestValue: Text;\n+ QltyCaseSensitivity: Enum \"Qlty. Case Sensitivity\"): Code[20]\n var\n QltyResultEvaluation: Codeunit \"Qlty. Result Evaluation\";\n begin\ndiff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsCreateInspect.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsCreateInspect.Codeunit.al\nindex cedf4c0eef..e7cb04f0e7 100644\n--- a/src/Apps/W1/Quality Management/test/src/QltyTestsCreateInspect.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsCreateInspect.Codeunit.al\n@@ -33,8 +33,8 @@ codeunit 139959 \"Qlty. Tests - Create Inspect.\"\n QltyInspectionUtility: Codeunit \"Qlty. Inspection Utility\";\n CannotFindTemplateErr: Label 'Cannot find a Quality Inspection Template or Quality Inspection Generation Rule to match %1. Ensure there is a Quality Inspection Generation Rule that will match this record.', Comment = '%1=The record identifier';\n ProgrammerErrNotARecordRefErr: Label 'Cannot find inspections with %1. Please supply a \"Record\" or \"RecordRef\".', Comment = '%1=the variant being supplied that is not a RecordRef. Your system might have an extension or customization that needs to be re-configured.';\n- UnableToCreateInspectionForRecordErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. The table involved is %1.', Comment = '%1=the table involved.';\n- UnableToCreateInspectionForParentOrChildErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. Two tables involved are %1 and %2.', Comment = '%1=the parent table, %2=the child and original table.';\n+ UnableToCreateInspectionForRecordErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. The table involved is %1.', Comment = '%1=the table involved.';\n+ UnableToCreateInspectionForParentOrChildErr: Label 'Cannot find enough details to make an inspection for your record(s). Try making sure that there is a source configuration for your record, and then also make sure there is sufficient information in your inspection generation rules. Two tables involved are %1 and %2.', Comment = '%1=the parent table, %2=the child and original table.';\n IsInitialized: Boolean;\n \n [Test]\n@@ -2485,6 +2485,174 @@ codeunit 139959 \"Qlty. Tests - Create Inspect.\"\n LibraryAssert.ExpectedError(StrSubstNo(UnableToCreateInspectionForParentOrChildErr, ProdOrderLine.TableName, ProdOrderRoutingLineRecordRef.Name));\n end;\n \n+ [Test]\n+ procedure CreateInspection_NewInsertion_ReportedAsNewlyCreated()\n+ var\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\";\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ ProdProductionOrder: Record \"Production Order\";\n+ Item: Record Item;\n+ CreatedQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ ProdOrderRoutingLineRecordRef: RecordRef;\n+ ClaimedInspectionWasFoundOrCreated: Boolean;\n+ IsNewlyCreated: Boolean;\n+ begin\n+ // [SCENARIO] When CreateInspection inserts a new inspection, IsLastInspectionNewlyCreated must report true (so the inspection-created notification is raised).\n+\n+ Initialize();\n+\n+ // [GIVEN] A quality inspection template, generation rule, item, and production order with routing line are set up\n+ SetupCreateInspectionProductionOrder(QltyInspectionTemplateHdr, QltyInspectionGenRule, Item, ProdProductionOrder, ProdOrderRoutingLine);\n+\n+ ProdOrderRoutingLineRecordRef.GetTable(ProdOrderRoutingLine);\n+\n+ // [WHEN] CreateInspection is called for the routing line for the first time\n+ ClaimedInspectionWasFoundOrCreated := QltyInspectionUtility.CreateInspectionAndReportIfNewlyCreated(ProdOrderRoutingLineRecordRef, false, CreatedQltyInspectionHeader, IsNewlyCreated);\n+\n+ QltyInspectionGenRule.Delete();\n+\n+ // [THEN] The inspection is created and reported as newly created so the \"Quality Inspection created\" notification is raised\n+ LibraryAssert.IsTrue(ClaimedInspectionWasFoundOrCreated, 'Should claim an inspection has been found/created.');\n+ LibraryAssert.IsTrue(IsNewlyCreated, 'A newly inserted inspection must be reported as newly created so the inspection-created notification is raised.');\n+ end;\n+\n+ [Test]\n+ procedure CreateInspection_ReusedExisting_NotReportedAsNewlyCreated()\n+ var\n+ QltyManagementSetup: Record \"Qlty. Management Setup\";\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\";\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ ProdProductionOrder: Record \"Production Order\";\n+ Item: Record Item;\n+ QltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ FirstCreatedQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ SecondQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ ProdOrderRoutingLineRecordRef: RecordRef;\n+ PreviousQltyCreateInspectBehavior: Enum \"Qlty. Inspect. Creation Option\";\n+ ClaimedInspectionWasFoundOrCreated: Boolean;\n+ IsNewlyCreated: Boolean;\n+ BeforeCount: Integer;\n+ AfterCount: Integer;\n+ begin\n+ // [SCENARIO] When CreateInspection reuses an existing inspection (Inspection Creation Option = \"Use existing open inspection if available\"),\n+ // IsLastInspectionNewlyCreated must report false so the inspection-created notification is suppressed.\n+\n+ Initialize();\n+\n+ // [GIVEN] A quality inspection template, generation rule, item, and production order with routing line are set up\n+ SetupCreateInspectionProductionOrder(QltyInspectionTemplateHdr, QltyInspectionGenRule, Item, ProdProductionOrder, ProdOrderRoutingLine);\n+\n+ // [GIVEN] A first inspection is created and left open\n+ ProdOrderRoutingLineRecordRef.GetTable(ProdOrderRoutingLine);\n+ QltyInspectionUtility.CreateInspection(ProdOrderRoutingLineRecordRef, false, FirstCreatedQltyInspectionHeader);\n+\n+ // [GIVEN] The Inspection Creation Option is set to \"Use existing open inspection if available\"\n+ QltyManagementSetup.Get();\n+ PreviousQltyCreateInspectBehavior := QltyManagementSetup.\"Inspection Creation Option\";\n+ QltyManagementSetup.\"Inspection Creation Option\" := QltyManagementSetup.\"Inspection Creation Option\"::\"Use existing open inspection if available\";\n+ QltyManagementSetup.Modify();\n+\n+ QltyInspectionHeader.Reset();\n+ BeforeCount := QltyInspectionHeader.Count();\n+\n+ // [WHEN] CreateInspection is called again for the same routing line while the first inspection is still open\n+ ClaimedInspectionWasFoundOrCreated := QltyInspectionUtility.CreateInspectionAndReportIfNewlyCreated(ProdOrderRoutingLineRecordRef, false, SecondQltyInspectionHeader, IsNewlyCreated);\n+\n+ QltyManagementSetup.\"Inspection Creation Option\" := PreviousQltyCreateInspectBehavior;\n+ QltyManagementSetup.Modify();\n+ QltyInspectionGenRule.Delete();\n+\n+ QltyInspectionHeader.Reset();\n+ AfterCount := QltyInspectionHeader.Count();\n+\n+ // [THEN] No new inspection is inserted, the existing inspection is returned, and the call is reported as a reuse so the inspection-created notification is suppressed\n+ LibraryAssert.IsTrue(ClaimedInspectionWasFoundOrCreated, 'Should claim an inspection has been found/created.');\n+ LibraryAssert.AreEqual(BeforeCount, AfterCount, 'No new inspection should have been inserted when reusing.');\n+ LibraryAssert.AreEqual(FirstCreatedQltyInspectionHeader.\"No.\", SecondQltyInspectionHeader.\"No.\", 'Should have returned the existing inspection.');\n+ LibraryAssert.IsFalse(IsNewlyCreated, 'A reused inspection must not be reported as newly created so the inspection-created notification is suppressed.');\n+ end;\n+\n+ [Test]\n+ procedure CreateMultipleInspections_ReusedExisting_ExcludedFromCreatedIdsList()\n+ var\n+ QltyManagementSetup: Record \"Qlty. Management Setup\";\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\";\n+ TempFilterQltyInspectionGenRule: Record \"Qlty. Inspection Gen. Rule\" temporary;\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ QltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ FirstCreatedQltyInspectionHeader: Record \"Qlty. Inspection Header\";\n+ QltyProdOrderGenerator: Codeunit \"Qlty. Prod. Order Generator\";\n+ FirstRoutingLineRecordRef: RecordRef;\n+ AllRoutingLinesRecordRef: RecordRef;\n+ CreatedQltyInspectionIds, AllResolvedQltyInspectionIds : List of [Code[20]];\n+ OrdersList: List of [Code[20]];\n+ ProductionOrder: Code[20];\n+ PreviousQltyCreateInspectBehavior: Enum \"Qlty. Inspect. Creation Option\";\n+ BeforeCount: Integer;\n+ AfterCount: Integer;\n+ begin\n+ // [SCENARIO] CreateMultipleInspectionsWithoutDisplaying should only include newly inserted inspection numbers in the returned list of created inspection ids;\n+ // inspections that were merely reused must not inflate the \"created\" list that drives the inspection-created notifications/display.\n+\n+ Initialize();\n+ QltyInspectionUtility.EnsureSetupExists();\n+ QltyInspectionUtility.CreateTemplate(QltyInspectionTemplateHdr, 3);\n+ QltyInspectionUtility.CreatePrioritizedRule(QltyInspectionTemplateHdr, Database::\"Prod. Order Routing Line\", QltyInspectionGenRule);\n+\n+ // [GIVEN] 3 production orders, each with a routing line\n+ QltyProdOrderGenerator.Init(100);\n+ QltyProdOrderGenerator.ToggleAllSources(false);\n+ QltyProdOrderGenerator.ToggleSourceType(\"Prod. Order Source Type\"::Item, true);\n+ QltyProdOrderGenerator.Generate(3, OrdersList);\n+\n+ // [GIVEN] An inspection is pre-created for the first production order so it will be reused on the next call\n+ ProdOrderRoutingLine.SetRange(Status, ProdOrderRoutingLine.Status::Released);\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", OrdersList.Get(1));\n+ ProdOrderRoutingLine.FindLast();\n+ FirstRoutingLineRecordRef.GetTable(ProdOrderRoutingLine);\n+ QltyInspectionUtility.CreateInspection(FirstRoutingLineRecordRef, false, FirstCreatedQltyInspectionHeader);\n+\n+ // [GIVEN] The Inspection Creation Option is set to \"Use existing open inspection if available\" so the first routing line reuses, the other two create new\n+ QltyManagementSetup.Get();\n+ PreviousQltyCreateInspectBehavior := QltyManagementSetup.\"Inspection Creation Option\";\n+ QltyManagementSetup.\"Inspection Creation Option\" := QltyManagementSetup.\"Inspection Creation Option\"::\"Use existing open inspection if available\";\n+ QltyManagementSetup.Modify();\n+\n+ // [GIVEN] A RecordRef containing the routing lines of all three production orders\n+ AllRoutingLinesRecordRef.Open(Database::\"Prod. Order Routing Line\", true);\n+ foreach ProductionOrder in OrdersList do begin\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProductionOrder);\n+ ProdOrderRoutingLine.FindLast();\n+ AllRoutingLinesRecordRef.Copy(ProdOrderRoutingLine, false);\n+ AllRoutingLinesRecordRef.Insert();\n+ end;\n+\n+ QltyInspectionHeader.Reset();\n+ BeforeCount := QltyInspectionHeader.Count();\n+\n+ // [WHEN] CreateMultipleInspectionsWithoutDisplaying is called for all three routing lines\n+ QltyInspectionUtility.CreateMultipleInspectionsWithoutDisplaying(AllRoutingLinesRecordRef, false, TempFilterQltyInspectionGenRule, CreatedQltyInspectionIds, AllResolvedQltyInspectionIds);\n+\n+ QltyManagementSetup.\"Inspection Creation Option\" := PreviousQltyCreateInspectBehavior;\n+ QltyManagementSetup.Modify();\n+ QltyInspectionGenRule.Delete();\n+\n+ QltyInspectionHeader.Reset();\n+ AfterCount := QltyInspectionHeader.Count();\n+\n+ // [THEN] Only 2 new inspections were inserted (for production orders 2 and 3)\n+ LibraryAssert.AreEqual((BeforeCount + 2), AfterCount, 'Only the two non-reused routing lines should have inserted new inspections.');\n+ // [THEN] The returned list of created inspection ids excludes the reused inspection so the \"created inspections\" notification is not falsely inflated\n+ LibraryAssert.AreEqual(2, CreatedQltyInspectionIds.Count(), 'The created inspection ids list must exclude reused inspections.');\n+ LibraryAssert.IsFalse(CreatedQltyInspectionIds.Contains(FirstCreatedQltyInspectionHeader.\"No.\"), 'A reused inspection must not appear in the created inspection ids list.');\n+ // [THEN] The all-resolved list includes both the 2 newly created inspections and the 1 reused inspection\n+ LibraryAssert.AreEqual(3, AllResolvedQltyInspectionIds.Count(), 'The all-resolved list must include every inspection that was newly created or reused.');\n+ LibraryAssert.IsTrue(AllResolvedQltyInspectionIds.Contains(FirstCreatedQltyInspectionHeader.\"No.\"), 'The all-resolved list must include the reused inspection.');\n+ end;\n+\n local procedure CreateInspectionWithTracking(var PurOrdPurchaseLine: Record \"Purchase Line\"; var TempSpecTrackingSpecification: Record \"Tracking Specification\" temporary; var OutQltyInspectionHeader: Record \"Qlty. Inspection Header\")\n var\n PurchaseLineRecordRef: RecordRef;\ndiff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsDispositions.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsDispositions.Codeunit.al\nindex 22897ed285..866d0afe64 100644\n--- a/src/Apps/W1/Quality Management/test/src/QltyTestsDispositions.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsDispositions.Codeunit.al\n@@ -49,7 +49,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n QltyPurOrderGenerator: Codeunit \"Qlty. Pur. Order Generator\";\n LibraryWarehouse: Codeunit \"Library - Warehouse\";\n QltyInspectionUtility: Codeunit \"Qlty. Inspection Utility\";\n- ReUsedLibraryItemTracking: Codeunit \"Library - Item Tracking\";\n+ LibraryItemTracking: Codeunit \"Library - Item Tracking\";\n NoPurchRcptLineErr: Label 'Could not find a related purchase receipt line with sufficient quantity for %1 from Quality Inspection %2,%3. Confirm the inspection source is a Purchase Line and that it has been received prior to creating a return.', Comment = '%1=item,%2=inspection,%3=re-inspection';\n WriteOffEntireItemTrackingErr: Label 'Reducing inventory using the item tracked quantity for inspection %1 was requested, however the item associated with this inspection does not require tracking.', Comment = '%1=the inspection';\n MissingAdjBatchErr: Label 'There is missing setup on the Quality Management Setup Card defining the adjustment batch.';\n@@ -304,7 +304,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.\"New Lot No.\" := ReclassWarehouseJournalLine.\"Lot No.\";\n ReclassWarehouseJournalLine.Modify();\n // [GIVEN] Item tracking is created for the reclassification journal line\n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', PurOrdReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', PurOrdReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.Modify();\n // [GIVEN] The warehouse journal is registered to complete the movement\n@@ -765,7 +765,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, NegativeAdjustmentItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with lot number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n \n // [GIVEN] Item ledger entry filters are set up for validation\n ItemLedgerEntry.SetRange(\"Item No.\", InitialInspectionInventoryJnlItemJournalLine.\"Item No.\");\n@@ -888,7 +888,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(LotNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n LibraryInventory.CreateTrackedItem(Item, LotNoSeries.Code, '', LotItemTrackingCode.Code);\n \n // [GIVEN] Bin contents are created for all bins in the location\n@@ -1218,7 +1218,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.\"New Lot No.\" := ReclassWarehouseJournalLine.\"Lot No.\";\n ReclassWarehouseJournalLine.Modify();\n \n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', PurOrdReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', PurOrdReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.Modify();\n \n@@ -1822,7 +1822,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(LotNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n LibraryInventory.CreateTrackedItem(Item, LotNoSeries.Code, '', LotItemTrackingCode.Code);\n \n // [GIVEN] Non-directed pick location with bins is created\n@@ -1857,7 +1857,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, InitialInventoryItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with original lot number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n \n // [GIVEN] Item ledger entry filters are set up and journal is posted\n ItemLedgerEntry.SetRange(\"Item No.\", InitialInspectionInventoryJnlItemJournalLine.\"Item No.\");\n@@ -1973,7 +1973,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(LotNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n LibraryInventory.CreateTrackedItem(Item, LotNoSeries.Code, '', LotItemTrackingCode.Code);\n \n // [GIVEN] Full WMS location is created with bins and bin content for the item\n@@ -2136,7 +2136,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(SerialNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(SerialNoSeriesLine, SerialNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(SerialItemTrackingCode, true, false, false);\n+ LibraryItemTracking.CreateItemTrackingCode(SerialItemTrackingCode, true, false, false);\n LibraryInventory.CreateTrackedItem(Item, '', SerialNoSeries.Code, SerialItemTrackingCode.Code);\n \n // [GIVEN] Non-directed pick location with bins is created\n@@ -2172,7 +2172,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, InitialInventoryItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with original serial number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, OriginalSerialNo, '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, OriginalSerialNo, '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n \n // [GIVEN] Item ledger entry filters are set up and journal is posted\n ItemLedgerEntry.SetRange(\"Item No.\", InitialInspectionInventoryJnlItemJournalLine.\"Item No.\");\n@@ -2292,7 +2292,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeriesLine(SerialNoSeriesLine, SerialNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n // [GIVEN] Item tracking code is created for serial tracking\n- ReUsedLibraryItemTracking.CreateItemTrackingCode(SerialItemTrackingCode, true, false, false);\n+ LibraryItemTracking.CreateItemTrackingCode(SerialItemTrackingCode, true, false, false);\n \n // [GIVEN] Serial-tracked item is created with item tracking code\n LibraryInventory.CreateTrackedItem(Item, '', SerialNoSeries.Code, SerialItemTrackingCode.Code);\n@@ -2484,7 +2484,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(PackageNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(PackageNoSeriesLine, PackageNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n+ LibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n InventorySetup.Get();\n InventorySetup.Validate(\"Package Nos.\", PackageNoSeries.Code);\n InventorySetup.Modify(true);\n@@ -2523,7 +2523,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, InitialInventoryItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with original package number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n ReservationEntry.Validate(\"Package No.\", OriginalPackageNo);\n ReservationEntry.Validate(\"New Package No.\", OriginalPackageNo);\n ReservationEntry.Modify();\n@@ -2638,7 +2638,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(PackageNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(PackageNoSeriesLine, PackageNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n+ LibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n InventorySetup.Get();\n InventorySetup.Validate(\"Package Nos.\", PackageNoSeries.Code);\n InventorySetup.Modify(true);\n@@ -2814,7 +2814,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n // [GIVEN] Item tracking code is created for lot tracking\n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n \n // [GIVEN] Item tracking code is configured to use expiration dates\n LotItemTrackingCode.\"Use Expiration Dates\" := true;\n@@ -2868,7 +2868,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, InitialInventoryItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with lot number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', OriginalLotNo, InitialInspectionInventoryJnlItemJournalLine.Quantity);\n \n // [GIVEN] Expiration date is set to work date for the reservation entry\n ReservationEntry.\"Expiration Date\" := WorkDate();\n@@ -3012,7 +3012,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(LotNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n LotItemTrackingCode.\"Use Expiration Dates\" := true;\n LotItemTrackingCode.Modify();\n \n@@ -3168,7 +3168,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeriesLine(LotNoSeriesLine, LotNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n // [GIVEN] Lot-tracked item tracking code and item are created\n- ReUsedLibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n+ LibraryItemTracking.CreateItemTrackingCode(LotItemTrackingCode, false, true, false);\n LibraryInventory.CreateTrackedItem(Item, LotNoSeries.Code, '', LotItemTrackingCode.Code);\n \n // [GIVEN] A full WMS location with bins and bin content is created\n@@ -3373,7 +3373,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.Modify();\n \n // [GIVEN] Warehouse item tracking line is created with lot and expiration information\n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.\"Expiration Date\" := ReservationEntry.\"Expiration Date\";\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Expiration Date\" := ReservationEntry.\"Expiration Date\";\n@@ -3489,7 +3489,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryUtility.CreateNoSeries(PackageNoSeries, true, true, false);\n LibraryUtility.CreateNoSeriesLine(PackageNoSeriesLine, PackageNoSeries.Code, PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '0'), PadStr(Format(CurrentDateTime(), 0, 'A'), 19, '9'));\n \n- ReUsedLibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n+ LibraryItemTracking.CreateItemTrackingCode(PackageItemTrackingCode, false, false, true);\n InventorySetup.Get();\n InventorySetup.Validate(\"Package Nos.\", PackageNoSeries.Code);\n InventorySetup.Modify(true);\n@@ -3530,7 +3530,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n LibraryAssert.AreEqual(1, InitialInventoryItemJournalLine.Count(), 'test setup failed, should be only 1 line after a modify');\n \n // [GIVEN] Item tracking with original package number is assigned to the journal line\n- ReUsedLibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n+ LibraryItemTracking.CreateItemJournalLineItemTracking(ReservationEntry, InitialInspectionInventoryJnlItemJournalLine, '', '', InitialInspectionInventoryJnlItemJournalLine.Quantity);\n ReservationEntry.Validate(\"Package No.\", OriginalPackageNo);\n ReservationEntry.Validate(\"New Package No.\", OriginalPackageNo);\n ReservationEntry.Modify();\n@@ -4304,7 +4304,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.\"Lot No.\" := ReservationEntry.\"Lot No.\";\n ReclassWarehouseJournalLine.\"New Lot No.\" := ReclassWarehouseJournalLine.\"Lot No.\";\n ReclassWarehouseJournalLine.Modify();\n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.Modify();\n LibraryWarehouse.RegisterWhseJournalLine(ReclassWhseItemWarehouseJournalTemplate.Name, ReclassWarehouseJournalBatch.Name, Location.Code, true);\n@@ -4909,7 +4909,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.\"Lot No.\" := ReservationEntry.\"Lot No.\";\n ReclassWarehouseJournalLine.\"New Lot No.\" := ReclassWarehouseJournalLine.\"Lot No.\";\n ReclassWarehouseJournalLine.Modify();\n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.Modify();\n LibraryWarehouse.RegisterWhseJournalLine(ReclassWhseItemWarehouseJournalTemplate.Name, ReclassWarehouseJournalBatch.Name, Location.Code, true);\n@@ -5521,7 +5521,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassItemJournalLine.\"New Bin Code\" := InitialChangeBin;\n ReclassItemJournalLine.Modify();\n \n- ReUsedLibraryItemTracking.CreateItemReclassJnLineItemTracking(ReclassReservationEntry, ReclassItemJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateItemReclassJnLineItemTracking(ReclassReservationEntry, ReclassItemJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassReservationEntry.\"New Lot No.\" := ReclassReservationEntry.\"Lot No.\";\n ReclassReservationEntry.Modify();\n LibraryInventory.PostItemJournalBatch(ReclassItemJournalBatch);\n@@ -6043,7 +6043,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassWarehouseJournalLine.\"Lot No.\" := ReservationEntry.\"Lot No.\";\n ReclassWarehouseJournalLine.\"New Lot No.\" := ReclassWarehouseJournalLine.\"Lot No.\";\n ReclassWarehouseJournalLine.Modify();\n- ReUsedLibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateWhseJournalLineItemTracking(ReclassWarehouseJournalWhseItemTrackingLine, ReclassWarehouseJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassWarehouseJournalWhseItemTrackingLine.\"New Lot No.\" := ReclassWarehouseJournalWhseItemTrackingLine.\"Lot No.\";\n ReclassWarehouseJournalWhseItemTrackingLine.Modify();\n LibraryWarehouse.RegisterWhseJournalLine(ReclassWhseItemWarehouseJournalTemplate.Name, ReclassWarehouseJournalBatch.Name, Location.Code, true);\n@@ -6316,7 +6316,7 @@ codeunit 139960 \"Qlty. Tests - Dispositions\"\n ReclassItemJournalLine.\"New Bin Code\" := InitialChangeBin;\n ReclassItemJournalLine.Modify();\n \n- ReUsedLibraryItemTracking.CreateItemReclassJnLineItemTracking(ReclassReservationEntry, ReclassItemJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n+ LibraryItemTracking.CreateItemReclassJnLineItemTracking(ReclassReservationEntry, ReclassItemJournalLine, '', ReservationEntry.\"Lot No.\", 50);\n ReclassReservationEntry.\"New Lot No.\" := ReclassReservationEntry.\"Lot No.\";\n ReclassReservationEntry.Modify();\n LibraryInventory.PostItemJournalBatch(ReclassItemJournalBatch);\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8524", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-08T21:42:31Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Quality Management\\app", "src\\Apps\\W1\\Quality Management\\test"], "patch": "diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateLine.Table.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateLine.Table.al\nindex d868fbf50a..e19e4d3dfb 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateLine.Table.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateLine.Table.al\n@@ -48,6 +48,7 @@ table 20403 \"Qlty. Inspection Template Line\"\n if QltyTest.Get(\"Test Code\") then begin\n Rec.Description := QltyTest.Description;\n Rec.\"Unit of Measure Code\" := QltyTest.\"Unit of Measure Code\";\n+ Rec.\"Expression Formula\" := QltyTest.\"Expression Formula\";\n end;\n \n EnsureResultsExist(Rec.\"Test Code\" <> xRec.\"Test Code\");\n@@ -97,7 +98,7 @@ table 20403 \"Qlty. Inspection Template Line\"\n Rec.CalcFields(\"Test Value Type\");\n if Rec.\"Expression Formula\" <> '' then begin\n if not (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Text Expression\"]) then\n- Error(OnlyFieldExpressionErr);\n+ Error(ExpressionFormulaOnlyForTextExpressionErr);\n \n ValidateExpressionFormula();\n end;\n@@ -123,7 +124,7 @@ table 20403 \"Qlty. Inspection Template Line\"\n }\n \n var\n- OnlyFieldExpressionErr: Label 'The Expression Formula can only be used with fields that are a type of Expression';\n+ ExpressionFormulaOnlyForTextExpressionErr: Label 'The Expression Formula can only be used with tests that are a type of Text Expression';\n \n trigger OnInsert()\n begin\ndiff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateSubf.Page.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateSubf.Page.al\nindex 672e18ea4c..2ee3bad573 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateSubf.Page.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/QltyInspectionTemplateSubf.Page.al\n@@ -65,6 +65,12 @@ page 20403 \"Qlty. Inspection Template Subf\"\n {\n StyleExpr = RowStyleText;\n }\n+ field(\"Expression Formula\"; Rec.\"Expression Formula\")\n+ {\n+ StyleExpr = RowStyleText;\n+ Editable = IsExpressionFormulaEditable;\n+ Visible = false;\n+ }\n field(\"Unit of Measure Code\"; Rec.\"Unit of Measure Code\")\n {\n StyleExpr = RowStyleText;\n@@ -503,6 +509,7 @@ page 20403 \"Qlty. Inspection Template Subf\"\n MatrixArrayCaptionSet: array[10] of Text;\n Visible1, Visible2, Visible3, Visible4, Visible5, Visible6, Visible7, Visible8, Visible9, Visible10 : Boolean;\n Editable1, Editable2, Editable3, Editable4, Editable5, Editable6, Editable7, Editable8, Editable9, Editable10 : Boolean;\n+ IsExpressionFormulaEditable: Boolean;\n DescriptionLbl: Label '%1 Description', Comment = '%1 = Matrix field caption';\n ConditionLbl: Label '%1 Condition', Comment = '%1 = Matrix field caption';\n \n@@ -573,6 +580,8 @@ page 20403 \"Qlty. Inspection Template Subf\"\n Editable8 := Visible8 and not RowIsLabel;\n Editable9 := Visible9 and not RowIsLabel;\n Editable10 := Visible10 and not RowIsLabel;\n+\n+ IsExpressionFormulaEditable := Rec.\"Test Value Type\" = Rec.\"Test Value Type\"::\"Value Type Text Expression\";\n end;\n \n local procedure UpdateMatrixDataCondition(Matrix: Integer)\ndiff --git a/src/Apps/W1/Quality Management/app/src/Document/QltyInspection.Page.al b/src/Apps/W1/Quality Management/app/src/Document/QltyInspection.Page.al\nindex f4f87e34e2..d309c3ac76 100644\n--- a/src/Apps/W1/Quality Management/app/src/Document/QltyInspection.Page.al\n+++ b/src/Apps/W1/Quality Management/app/src/Document/QltyInspection.Page.al\n@@ -27,6 +27,8 @@ page 20406 \"Qlty. Inspection\"\n {\n UsageCategory = None;\n Caption = 'Quality Inspection';\n+ AboutTitle = 'About Quality Inspection document';\n+ AboutText = 'The Quality Inspection document is used to manage quality inspections for items, including recording inspection results, taking pictures, and navigating to related documents. The header contains general information about the inspection, while the lines contain details about each quality test performed. You can also create re-inspections, print reports, and perform actions like moving inventory or changing item tracking information based on the inspection results.';\n DataCaptionExpression = GetDataCaptionExpression();\n InsertAllowed = false;\n PageType = Card;\ndiff --git a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionLine.Table.al b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionLine.Table.al\nindex 819ca649ca..4b86c3e549 100644\n--- a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionLine.Table.al\n+++ b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionLine.Table.al\n@@ -409,6 +409,8 @@ table 20406 \"Qlty. Inspection Line\"\n if not GetInspection() then\n exit;\n \n+ EvaluateSelfIfOnlyLineIsTextExpression();\n+\n OthersInSameQltyInspectionLine.SetRange(\"Inspection No.\", Rec.\"Inspection No.\");\n OthersInSameQltyInspectionLine.SetRange(\"Re-inspection No.\", Rec.\"Re-inspection No.\");\n OthersInSameQltyInspectionLine.SetFilter(\"Test Value Type\", '%1', QltyInspectionTemplateLine.\"Test Value Type\"::\"Value Type Text Expression\");\n@@ -465,6 +467,21 @@ table 20406 \"Qlty. Inspection Line\"\n until OthersInSameQltyInspectionLine.Next() = 0;\n end;\n \n+ local procedure EvaluateSelfIfOnlyLineIsTextExpression()\n+ var\n+ OtherQltyInspectionLine: Record \"Qlty. Inspection Line\";\n+ begin\n+ Rec.CalcFields(\"Test Value Type\");\n+ if Rec.\"Test Value Type\" <> Rec.\"Test Value Type\"::\"Value Type Text Expression\" then\n+ exit;\n+\n+ OtherQltyInspectionLine.SetRange(\"Inspection No.\", Rec.\"Inspection No.\");\n+ OtherQltyInspectionLine.SetRange(\"Re-inspection No.\", Rec.\"Re-inspection No.\");\n+ OtherQltyInspectionLine.SetFilter(\"Line No.\", '<>%1', Rec.\"Line No.\");\n+ if OtherQltyInspectionLine.IsEmpty() then\n+ Rec.EvaluateTextExpression(QltyInspectionHeader);\n+ end;\n+\n internal procedure EvaluateTextExpression(var EvaluateAgainstQltyInspectionHeader: Record \"Qlty. Inspection Header\")\n var\n QltyExpressionMgmt: Codeunit \"Qlty. Expression Mgmt.\";\ndiff --git a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionSubform.Page.al b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionSubform.Page.al\nindex 844802977b..01dc04810b 100644\n--- a/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionSubform.Page.al\n+++ b/src/Apps/W1/Quality Management/app/src/Document/QltyInspectionSubform.Page.al\n@@ -59,7 +59,7 @@ page 20407 \"Qlty. Inspection Subform\"\n trigger OnAssistEdit()\n begin\n Rec.CalcFields(\"Test Value Type\");\n- if Rec.\"Test Value Type\" = Rec.\"Test Value Type\"::\"Value Type Label\" then\n+ if Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Label\", Rec.\"Test Value Type\"::\"Value Type Text Expression\"] then\n exit;\n UpdateRowData();\n \n@@ -371,10 +371,10 @@ page 20407 \"Qlty. Inspection Subform\"\n begin\n OnBeforeCanEditTestValue(Rec, Result, IsHandled);\n if IsHandled then\n- exit;\n+ exit(Result);\n \n Rec.CalcFields(\"Test Value Type\");\n- exit(not (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Label\"]));\n+ exit(not (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Label\", Rec.\"Test Value Type\"::\"Value Type Text Expression\"]));\n end;\n \n /// \ndiff --git a/src/Apps/W1/Quality Management/app/src/Reports/QltyCertificateOfAnalysis.docx b/src/Apps/W1/Quality Management/app/src/Reports/QltyCertificateOfAnalysis.docx\nindex 9202b267d8..db577ad259 100644\nBinary files a/src/Apps/W1/Quality Management/app/src/Reports/QltyCertificateOfAnalysis.docx and b/src/Apps/W1/Quality Management/app/src/Reports/QltyCertificateOfAnalysis.docx differ\ndiff --git a/src/Apps/W1/Quality Management/app/src/Reports/QltyGeneralPurposeInspection.docx b/src/Apps/W1/Quality Management/app/src/Reports/QltyGeneralPurposeInspection.docx\nindex c71945827a..694a6d6621 100644\nBinary files a/src/Apps/W1/Quality Management/app/src/Reports/QltyGeneralPurposeInspection.docx and b/src/Apps/W1/Quality Management/app/src/Reports/QltyGeneralPurposeInspection.docx differ\ndiff --git a/src/Apps/W1/Quality Management/app/src/Reports/QltyNonConformance.docx b/src/Apps/W1/Quality Management/app/src/Reports/QltyNonConformance.docx\nindex c1465f0f1c..abf5c06f36 100644\nBinary files a/src/Apps/W1/Quality Management/app/src/Reports/QltyNonConformance.docx and b/src/Apps/W1/Quality Management/app/src/Reports/QltyNonConformance.docx differ\ndiff --git a/src/Apps/W1/Quality Management/app/src/Setup/QltyManagementSetup.Table.al b/src/Apps/W1/Quality Management/app/src/Setup/QltyManagementSetup.Table.al\nindex 4e8cecbbef..492e58410e 100644\n--- a/src/Apps/W1/Quality Management/app/src/Setup/QltyManagementSetup.Table.al\n+++ b/src/Apps/W1/Quality Management/app/src/Setup/QltyManagementSetup.Table.al\n@@ -43,7 +43,7 @@ table 20400 \"Qlty. Management Setup\"\n field(4; \"Inspection Creation Option\"; Enum \"Qlty. Inspect. Creation Option\")\n {\n Caption = 'Inspection Creation Option';\n- ToolTip = 'Specifies how the system handles inspection creation when existing inspections exist.';\n+ ToolTip = 'Specifies handling of inspection creation when existing inspections are found.';\n InitValue = \"Use existing open inspection if available\";\n }\n field(5; \"Inspection Search Criteria\"; Enum \"Qlty. Inspect. Search Criteria\")\ndiff --git a/src/Apps/W1/Quality Management/app/src/Setup/SetupGuide/QltyGuidedExperience.Codeunit.al b/src/Apps/W1/Quality Management/app/src/Setup/SetupGuide/QltyGuidedExperience.Codeunit.al\nindex 9395d22992..f0e5f37d38 100644\n--- a/src/Apps/W1/Quality Management/app/src/Setup/SetupGuide/QltyGuidedExperience.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/app/src/Setup/SetupGuide/QltyGuidedExperience.Codeunit.al\n@@ -28,13 +28,13 @@ codeunit 20419 \"Qlty. Guided Experience\"\n DemoDataDescriptionTxt: Label 'Install or explore Contoso demo data for Quality Management with sample quality tests, templates, generation rules, and inspections. This lets you learn how quality checks work without setting up your own data.';\n QualityResultsShortTitleTxt: Label 'Inspection results';\n QualityResultsTitleTxt: Label 'Set up quality inspection results';\n- QualityResultsDescriptionTxt: Label 'Define possible outcomes for quality inspections, like Pass, Fail, or In Progress. Create custom results and set priorities to match your organization''s standards. These results control how inspections are evaluated and how items are blocked or released.';\n+ QualityResultsDescriptionTxt: Label 'Define custom grades for quality inspections, to match your organization''s standards. You can decide evaluation priorities and set conditions for allowed transactions.';\n QualityTestsShortTitleTxt: Label 'Quality tests';\n QualityTestsTitleTxt: Label 'Understand quality tests';\n QualityTestsDescriptionTxt: Label 'Quality tests define what is measured. Visit the Quality Tests list to see available tests, then open a test card to review parameters, limits, and expected values used during inspections.';\n QualityTemplatesShortTitleTxt: Label 'Quality templates';\n QualityTemplatesTitleTxt: Label 'Reuse inspection templates';\n- QualityTemplatesDescriptionTxt: Label 'With templates you can group and reuse quality tests so you can apply consistent inspection standards across items, processes, or scenarios. From the list you can create a new template card to understand its structure and purpose.';\n+ QualityTemplatesDescriptionTxt: Label 'With templates you can group and reuse quality tests to ensure consistent inspection standards. Try creating a new template card to understand its structure and purpose.';\n GenerationRulesShortTitleTxt: Label 'Generation rules';\n GenerationRulesTitleTxt: Label 'Set up inspection generation rules';\n GenerationRulesDescriptionTxt: Label 'Inspection generation rules define when quality inspections are created automatically, such as during receiving, production, or assembly.';\n", "FAIL_TO_PASS": [{"codeunitID": 139965, "functionName": ["TemplateLine_ExpressionFormulaUpdatedWhenTestCodeChanges", "TemplateLine_ExpressionFormulaEmptyWhenTestHasNoFormula", "TemplateLine_ExpressionFormulaCopiedFromTest", "TestTable_DefaultValueNotAllowedForTextExpression"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\nindex 38a8889c60..6df2e749cc 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTest.Table.al\n@@ -154,13 +154,16 @@ table 20401 \"Qlty. Test\"\n \n trigger OnValidate()\n begin\n+ if (Rec.\"Default Value\" <> '') and (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Text Expression\"]) then\n+ Error(DefaultValueNotAllowedForTextExpressionErr);\n+\n Rec.ValidateAllowableValuesOnDefault();\n end;\n }\n field(17; \"Case Sensitive\"; Enum \"Qlty. Case Sensitivity\")\n {\n Caption = 'Case Sensitivity';\n- ToolTip = 'Specifies if case sensitivity will be enabled for text-based fields.';\n+ ToolTip = 'Specifies if case sensitivity will be enabled for text-based tests.';\n }\n field(18; \"Expression Formula\"; Text[500])\n {\n@@ -170,7 +173,7 @@ table 20401 \"Qlty. Test\"\n trigger OnValidate()\n begin\n if (Rec.\"Expression Formula\" <> '') and not (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Text Expression\"]) then\n- Error(OnlyFieldExpressionErr);\n+ Error(ExpressionFormulaOnlyForTextExpressionErr);\n end;\n }\n field(22; \"Unit of Measure Code\"; Code[10])\n@@ -204,7 +207,8 @@ table 20401 \"Qlty. Test\"\n GenericTestTok: Label 'MYTEST', Locked = true;\n ThereIsNoResultErr: Label 'There is no result called \"%1\". Please add the result, or change the existing result conditions.', Comment = '%1=the result';\n ReviewResultsErr: Label 'Advanced configuration required. Please review the result configurations for test \"%1\", for result \"%2\".', Comment = '%1=the test, %2=the result';\n- OnlyFieldExpressionErr: Label 'The Expression Formula can only be used with fields that are a type of Expression';\n+ ExpressionFormulaOnlyForTextExpressionErr: Label 'The Expression Formula can only be used with tests that are a type of Text Expression';\n+ DefaultValueNotAllowedForTextExpressionErr: Label 'The Default Value cannot be set on tests that are a type of Text Expression. The value is computed from the Expression Formula.';\n BooleanChoiceListLbl: Label 'No,Yes';\n ExistingInspectionErr: Label 'The test %1 exists on %2 inspections (such as %3 with template %4). The test cannot be deleted if it is being used on a quality inspection.', Comment = '%1=the test, %2=count of inspections, %3=one example inspection, %4=example template.';\n DeleteQst: Label 'The test %3 exists on %1 Quality Inspection Template(s) (such as template %2) that will be deleted. Do you wish to proceed?', Comment = '%1 = the lines, %2= the Template Code, %3=the test';\n@@ -601,7 +605,7 @@ table 20401 \"Qlty. Test\"\n Expression: Text;\n begin\n if not (Rec.\"Test Value Type\" in [Rec.\"Test Value Type\"::\"Value Type Text Expression\"]) then\n- Error(OnlyFieldExpressionErr);\n+ Error(ExpressionFormulaOnlyForTextExpressionErr);\n \n Expression := Rec.\"Expression Formula\";\n \ndiff --git a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestCard.Page.al b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestCard.Page.al\nindex 95c568a137..4418f7a53c 100644\n--- a/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestCard.Page.al\n+++ b/src/Apps/W1/Quality Management/app/src/Configuration/Template/Test/QltyTestCard.Page.al\n@@ -77,6 +77,8 @@ page 20479 \"Qlty. Test Card\"\n }\n field(\"Default Value\"; Rec.\"Default Value\")\n {\n+ Editable = not IsExpressionFormulaEditable;\n+\n trigger OnAssistEdit()\n begin\n Rec.AssistEditDefaultValue();\n@@ -652,7 +654,7 @@ page 20479 \"Qlty. Test Card\"\n \n EditableResult := (Rec.Code <> '') and (CurrPage.Editable) and (Visible1) and (MatrixArrayCaptionSet[1] <> '');\n \n- IsExpressionFormulaEditable := (Rec.\"Test Value Type\" = Rec.\"Test Value Type\"::\"Value Type Text Expression\");\n+ IsExpressionFormulaEditable := Rec.\"Test Value Type\" = Rec.\"Test Value Type\"::\"Value Type Text Expression\";\n end;\n \n local procedure UpdateMatrixDataCondition(Matrix: Integer)\ndiff --git a/src/Apps/W1/Quality Management/test/src/QltyTestsMoreTests.Codeunit.al b/src/Apps/W1/Quality Management/test/src/QltyTestsMoreTests.Codeunit.al\nindex 70e318c1ef..69d0029499 100644\n--- a/src/Apps/W1/Quality Management/test/src/QltyTestsMoreTests.Codeunit.al\n+++ b/src/Apps/W1/Quality Management/test/src/QltyTestsMoreTests.Codeunit.al\n@@ -61,7 +61,7 @@ codeunit 139965 \"Qlty. Tests - More Tests\"\n DefaultScheduleGroupTok: Label 'QM', Locked = true;\n ExpressionFormulaTok: Label '[No.]';\n TestValueTypeChangeErrInfoMsg: Label 'Consider replacing this test in the template with a new one, or deleting existing inspections (if allowed). The test was last used on Inspection %1, Re-inspection %2.', Comment = '%1 = Quality Inspection No., %2 = Re-inspection No.';\n- OnlyFieldExpressionErr: Label 'The Expression Formula can only be used with fields that are a type of Expression';\n+ ExpressionFormulaOnlyForTextExpressionErr: Label 'The Expression Formula can only be used with tests that are a type of Text Expression';\n VendorFilterCountryTok: Label 'WHERE(Country/Region Code=FILTER(CA))', Locked = true;\n VendorFilterNoTok: Label 'WHERE(No.=FILTER(%1))', Comment = '%1 = Vendor No.', Locked = true;\n ThereIsNoResultErr: Label 'There is no result called \"%1\". Please add the result, or change the existing result conditions.', Comment = '%1=the result';\n@@ -105,7 +105,7 @@ codeunit 139965 \"Qlty. Tests - More Tests\"\n asserterror ToLoadQltyTest.Validate(\"Expression Formula\", ExpressionFormulaTok);\n \n // [THEN] An error is raised indicating Expression Formula is only for Expression test value types\n- LibraryAssert.ExpectedError(OnlyFieldExpressionErr);\n+ LibraryAssert.ExpectedError(ExpressionFormulaOnlyForTextExpressionErr);\n end;\n \n [Test]\n@@ -612,7 +612,7 @@ codeunit 139965 \"Qlty. Tests - More Tests\"\n asserterror ConfigurationToLoadQltyInspectionTemplateLine.Validate(\"Expression Formula\", ExpressionFormulaTok);\n \n // [THEN] An error is raised indicating Expression Formula is only for Expression field types\n- LibraryAssert.ExpectedError(OnlyFieldExpressionErr);\n+ LibraryAssert.ExpectedError(ExpressionFormulaOnlyForTextExpressionErr);\n end;\n \n [Test]\n@@ -2271,6 +2271,139 @@ codeunit 139965 \"Qlty. Tests - More Tests\"\n LibraryAssert.AreEqual(LotNo, QltyInspectionHeader.\"Source Lot No.\", 'Inspection should have the correct lot number.');\n end;\n \n+ [Test]\n+ procedure TestTable_DefaultValueNotAllowedForTextExpression()\n+ var\n+ QltyTest: Record \"Qlty. Test\";\n+ TestCode: Text;\n+ begin\n+ // [SCENARIO] Default Value cannot be set on tests that are a type of Text Expression\n+ Initialize();\n+\n+ // [GIVEN] A random test code is generated\n+ QltyInspectionUtility.GenerateRandomCharacters(20, TestCode);\n+\n+ // [GIVEN] A new quality test with Test Value Type \"Value Type Text Expression\" is created\n+ QltyTest.Validate(Code, CopyStr(TestCode, 1, MaxStrLen(QltyTest.Code)));\n+ QltyTest.Validate(Description, LibraryUtility.GenerateRandomText(MaxStrLen(QltyTest.Description)));\n+ QltyTest.Validate(\"Test Value Type\", QltyTest.\"Test Value Type\"::\"Value Type Text Expression\");\n+ QltyTest.Insert();\n+\n+ // [WHEN] Attempting to set Default Value on a Text Expression test\n+ asserterror QltyTest.Validate(\"Default Value\", 'some text');\n+\n+ // [THEN] An error is raised indicating Default Value is not allowed for Text Expression tests\n+ LibraryAssert.ExpectedError('The Default Value cannot be set on tests that are a type of Text Expression.');\n+ end;\n+\n+ [Test]\n+ procedure TemplateLine_ExpressionFormulaCopiedFromTest()\n+ var\n+ QltyTest: Record \"Qlty. Test\";\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionTemplateLine: Record \"Qlty. Inspection Template Line\";\n+ TestCode: Text;\n+ begin\n+ // [SCENARIO] Expression Formula is copied from the test to the template line when the test is added\n+ Initialize();\n+\n+ // [GIVEN] A random test code is generated\n+ QltyInspectionUtility.GenerateRandomCharacters(20, TestCode);\n+\n+ // [GIVEN] A quality test with Test Value Type \"Value Type Text Expression\" and an Expression Formula is created\n+ QltyTest.Validate(Code, CopyStr(TestCode, 1, MaxStrLen(QltyTest.Code)));\n+ QltyTest.Validate(Description, LibraryUtility.GenerateRandomText(MaxStrLen(QltyTest.Description)));\n+ QltyTest.Validate(\"Test Value Type\", QltyTest.\"Test Value Type\"::\"Value Type Text Expression\");\n+ QltyTest.Insert();\n+ QltyTest.Validate(\"Expression Formula\", ExpressionFormulaTok);\n+ QltyTest.Modify();\n+\n+ // [GIVEN] A template is created\n+ QltyInspectionUtility.CreateTemplate(QltyInspectionTemplateHdr, 0);\n+\n+ // [WHEN] A template line is created with the test code\n+ QltyInspectionTemplateLine.Init();\n+ QltyInspectionTemplateLine.\"Template Code\" := QltyInspectionTemplateHdr.Code;\n+ QltyInspectionTemplateLine.InitLineNoIfNeeded();\n+ QltyInspectionTemplateLine.Validate(\"Test Code\", QltyTest.Code);\n+ QltyInspectionTemplateLine.Insert(true);\n+\n+ // [THEN] The Expression Formula is copied from the test to the template line\n+ LibraryAssert.AreEqual(ExpressionFormulaTok, QltyInspectionTemplateLine.\"Expression Formula\", 'Expression Formula should be copied from the test to the template line.');\n+ end;\n+\n+ [Test]\n+ procedure TemplateLine_ExpressionFormulaEmptyWhenTestHasNoFormula()\n+ var\n+ QltyTest: Record \"Qlty. Test\";\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionTemplateLine: Record \"Qlty. Inspection Template Line\";\n+ TestCode: Text;\n+ begin\n+ // [SCENARIO] Expression Formula on template line is empty when the test has no formula\n+ Initialize();\n+\n+ // [GIVEN] A random test code is generated\n+ QltyInspectionUtility.GenerateRandomCharacters(20, TestCode);\n+\n+ // [GIVEN] A quality test with Test Value Type \"Value Type Text Expression\" but no Expression Formula is created\n+ QltyTest.Validate(Code, CopyStr(TestCode, 1, MaxStrLen(QltyTest.Code)));\n+ QltyTest.Validate(Description, LibraryUtility.GenerateRandomText(MaxStrLen(QltyTest.Description)));\n+ QltyTest.Validate(\"Test Value Type\", QltyTest.\"Test Value Type\"::\"Value Type Text Expression\");\n+ QltyTest.Insert();\n+\n+ // [GIVEN] A template is created\n+ QltyInspectionUtility.CreateTemplate(QltyInspectionTemplateHdr, 0);\n+\n+ // [WHEN] A template line is created with the test code\n+ QltyInspectionTemplateLine.Init();\n+ QltyInspectionTemplateLine.\"Template Code\" := QltyInspectionTemplateHdr.Code;\n+ QltyInspectionTemplateLine.InitLineNoIfNeeded();\n+ QltyInspectionTemplateLine.Validate(\"Test Code\", QltyTest.Code);\n+ QltyInspectionTemplateLine.Insert(true);\n+\n+ // [THEN] The Expression Formula on the template line is empty\n+ LibraryAssert.AreEqual('', QltyInspectionTemplateLine.\"Expression Formula\", 'Expression Formula should be empty when the test has no formula.');\n+ end;\n+\n+ [Test]\n+ procedure TemplateLine_ExpressionFormulaUpdatedWhenTestCodeChanges()\n+ var\n+ QltyTest1: Record \"Qlty. Test\";\n+ QltyTest2: Record \"Qlty. Test\";\n+ QltyInspectionTemplateHdr: Record \"Qlty. Inspection Template Hdr.\";\n+ QltyInspectionTemplateLine: Record \"Qlty. Inspection Template Line\";\n+ ExpressionFormula2Tok: Label '[Source Item No.]', Locked = true;\n+ begin\n+ // [SCENARIO] Expression Formula is updated when the Test Code on a template line is changed to a different test\n+ Initialize();\n+\n+ // [GIVEN] A first quality test with an Expression Formula is created\n+ QltyInspectionUtility.CreateTest(QltyTest1, QltyTest1.\"Test Value Type\"::\"Value Type Text Expression\");\n+ QltyTest1.Validate(\"Expression Formula\", ExpressionFormulaTok);\n+ QltyTest1.Modify();\n+\n+ // [GIVEN] A second quality test with a different Expression Formula is created\n+ QltyInspectionUtility.CreateTest(QltyTest2, QltyTest2.\"Test Value Type\"::\"Value Type Text Expression\");\n+ QltyTest2.Validate(\"Expression Formula\", ExpressionFormula2Tok);\n+ QltyTest2.Modify();\n+\n+ // [GIVEN] A template is created with the first test\n+ QltyInspectionUtility.CreateTemplate(QltyInspectionTemplateHdr, 0);\n+ QltyInspectionTemplateLine.Init();\n+ QltyInspectionTemplateLine.\"Template Code\" := QltyInspectionTemplateHdr.Code;\n+ QltyInspectionTemplateLine.InitLineNoIfNeeded();\n+ QltyInspectionTemplateLine.Validate(\"Test Code\", QltyTest1.Code);\n+ QltyInspectionTemplateLine.Insert(true);\n+\n+ // [WHEN] The Test Code on the template line is changed to the second test\n+ QltyInspectionTemplateLine.Validate(\"Test Code\", QltyTest2.Code);\n+ QltyInspectionTemplateLine.Modify(true);\n+\n+ // [THEN] The Expression Formula is updated to the second test's formula\n+ LibraryAssert.AreEqual(ExpressionFormula2Tok, QltyInspectionTemplateLine.\"Expression Formula\", 'Expression Formula should be updated when the test code is changed.');\n+ end;\n+\n local procedure Initialize()\n begin\n if IsInitialized then\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8423", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-02T14:24:52Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\ExcelReports\\App", "src\\Apps\\W1\\ExcelReports\\Test"], "patch": "diff --git a/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccPayableExcel.Report.al b/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccPayableExcel.Report.al\nindex a09b3759b3..7dc8662512 100644\n--- a/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccPayableExcel.Report.al\n+++ b/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccPayableExcel.Report.al\n@@ -84,8 +84,9 @@ report 4403 \"EXR Aged Acc Payable Excel\"\n {\n IncludeCaption = true;\n }\n- column(CurrencyCode; CurrencyCodeDisplayCode)\n+ column(CurrencyCode; \"Currency Code\")\n {\n+ IncludeCaption = true;\n }\n column(PostingDate; \"Posting Date\")\n {\n@@ -126,11 +127,7 @@ report 4403 \"EXR Aged Acc Payable Excel\"\n Clear(AgingData);\n AgingData.DeleteAll();\n InsertAgingData(VendorAgingData);\n-\n- if AgingData.\"Currency Code\" = '' then\n- CurrencyCodeDisplayCode := GeneralLedgerSetup.GetCurrencyCode('')\n- else\n- CurrencyCodeDisplayCode := AgingData.\"Currency Code\";\n+ CurrencyCodeDisplayCode := AgingData.\"Currency Code\";\n end;\n }\n \n@@ -271,7 +268,6 @@ report 4403 \"EXR Aged Acc Payable Excel\"\n DueByCurrencies = 'Due by Currencies', MaxLength = 31, Comment = 'Excel worksheet name.';\n OpenByFCY = 'Open by (FCY)';\n DataRetrieved = 'Data retrieved:';\n- CurrencyCodeDisplay = 'Currency Code';\n AgedAsOf = 'Aged as of:';\n AgedAccountsPayable = 'Aged Accounts Payable';\n AgedAccountsPayablePrint = 'Aged Accounts Payable (Print)', MaxLength = 31, Comment = 'Excel worksheet name.';\n@@ -322,6 +318,9 @@ report 4403 \"EXR Aged Acc Payable Excel\"\n if PeriodCount = 0 then\n PeriodCount := 5;\n \n+ if not GeneralLedgerSetup.Get() then\n+ Clear(GeneralLedgerSetup);\n+\n WorkingEndDate := EndingDate;\n WorkingStartDate := CalcDate(PeriodLength, WorkingEndDate);\n repeat\n@@ -366,7 +365,10 @@ report 4403 \"EXR Aged Acc Payable Excel\"\n AgingData.\"Document Type\" := VendorLedgerEntry.\"Document Type\";\n AgingData.\"Dimension 1 Code\" := VendorLedgerEntry.\"Global Dimension 1 Code\";\n AgingData.\"Dimension 2 Code\" := VendorLedgerEntry.\"Global Dimension 2 Code\";\n- AgingData.\"Currency Code\" := VendorLedgerEntry.\"Currency Code\";\n+ if VendorLedgerEntry.\"Currency Code\" = '' then\n+ AgingData.\"Currency Code\" := GeneralLedgerSetup.GetCurrencyCode('')\n+ else\n+ AgingData.\"Currency Code\" := VendorLedgerEntry.\"Currency Code\";\n AgingData.\"Posting Date\" := VendorLedgerEntry.\"Posting Date\";\n AgingData.\"Document Date\" := VendorLedgerEntry.\"Document Date\";\n AgingData.\"Due Date\" := VendorLedgerEntry.\"Due Date\";\ndiff --git a/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccountsRecExcel.Report.al b/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccountsRecExcel.Report.al\nindex b16e1ca692..e07ca9a845 100644\n--- a/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccountsRecExcel.Report.al\n+++ b/src/Apps/W1/ExcelReports/App/src/Financials/EXRAgedAccountsRecExcel.Report.al\n@@ -83,8 +83,9 @@ report 4402 \"EXR Aged Accounts Rec Excel\"\n {\n IncludeCaption = true;\n }\n- column(CurrencyCode; CurrencyCodeDisplayCode)\n+ column(CurrencyCode; \"Currency Code\")\n {\n+ IncludeCaption = true;\n }\n column(PostingDate; \"Posting Date\")\n {\n@@ -125,11 +126,7 @@ report 4402 \"EXR Aged Accounts Rec Excel\"\n Clear(AgingData);\n AgingData.DeleteAll();\n InsertAgingData(CustomerAgingData);\n-\n- if AgingData.\"Currency Code\" = '' then\n- CurrencyCodeDisplayCode := GeneralLedgerSetup.GetCurrencyCode('')\n- else\n- CurrencyCodeDisplayCode := AgingData.\"Currency Code\";\n+ CurrencyCodeDisplayCode := AgingData.\"Currency Code\";\n end;\n }\n \n@@ -270,7 +267,6 @@ report 4402 \"EXR Aged Accounts Rec Excel\"\n DueByCurrencies = 'Due by Currencies', MaxLength = 31, Comment = 'Excel worksheet name.';\n OpenByFCY = 'Open by (FCY)';\n DataRetrieved = 'Data retrieved:';\n- CurrencyCodeDisplay = 'Currency Code';\n AgedAsOf = 'Aged as of:';\n AgedAccountsReceivable = 'Aged Accounts Receivable';\n AgedAccountsReceivablePrint = 'Aged Accounts Rec. (Print)', MaxLength = 31, Comment = 'Excel worksheet name.';\n@@ -321,6 +317,9 @@ report 4402 \"EXR Aged Accounts Rec Excel\"\n if PeriodCount = 0 then\n PeriodCount := 5;\n \n+ if not GeneralLedgerSetup.Get() then\n+ Clear(GeneralLedgerSetup);\n+\n WorkingEndDate := EndingDate;\n WorkingStartDate := CalcDate(PeriodLength, WorkingEndDate);\n repeat\n@@ -365,7 +364,10 @@ report 4402 \"EXR Aged Accounts Rec Excel\"\n AgingData.\"Document Type\" := CustLedgerEntry.\"Document Type\";\n AgingData.\"Dimension 1 Code\" := CustLedgerEntry.\"Global Dimension 1 Code\";\n AgingData.\"Dimension 2 Code\" := CustLedgerEntry.\"Global Dimension 2 Code\";\n- AgingData.\"Currency Code\" := CustLedgerEntry.\"Currency Code\";\n+ if CustLedgerEntry.\"Currency Code\" = '' then\n+ AgingData.\"Currency Code\" := GeneralLedgerSetup.GetCurrencyCode('')\n+ else\n+ AgingData.\"Currency Code\" := CustLedgerEntry.\"Currency Code\";\n AgingData.\"Posting Date\" := CustLedgerEntry.\"Posting Date\";\n AgingData.\"Document Date\" := CustLedgerEntry.\"Document Date\";\n AgingData.\"Due Date\" := CustLedgerEntry.\"Due Date\";\n", "FAIL_TO_PASS": [{"codeunitID": 139555, "functionName": ["AgedAccountsPayableReportAgesByPostingDate", "AgedAccountsPayableRendersCurrencyCodePerEntry", "AgedAccountsPayableExportsDocumentTypeAndNo", "AgedAccountsRecExportsDocumentTypeAndNo", "AgedAccountsRecRendersCurrencyCodePerEntry"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/ExcelReports/Test/app.json b/src/Apps/W1/ExcelReports/Test/app.json\nindex 826a16204e..b08abb1f27 100644\n--- a/src/Apps/W1/ExcelReports/Test/app.json\n+++ b/src/Apps/W1/ExcelReports/Test/app.json\n@@ -38,6 +38,10 @@\n {\n \"from\": 139543,\n \"to\": 139547\n+ },\n+ {\n+ \"from\": 139555,\n+ \"to\": 139555\n }\n ],\n \"resourceExposurePolicy\": {\ndiff --git a/src/Apps/W1/ExcelReports/Test/src/AgedAccountsExcelReports.Codeunit.al b/src/Apps/W1/ExcelReports/Test/src/AgedAccountsExcelReports.Codeunit.al\nnew file mode 100644\nindex 0000000000..6442d2d2a8\n--- /dev/null\n+++ b/src/Apps/W1/ExcelReports/Test/src/AgedAccountsExcelReports.Codeunit.al\n@@ -0,0 +1,391 @@\n+// ------------------------------------------------------------------------------------------------\n+// Copyright (c) Microsoft Corporation. All rights reserved.\n+// Licensed under the MIT License. See License.txt in the project root for license information.\n+// ------------------------------------------------------------------------------------------------\n+\n+namespace Microsoft.Finance.ExcelReports.Test;\n+\n+using Microsoft.Finance.ExcelReports;\n+using Microsoft.Finance.GeneralLedger.Journal;\n+using Microsoft.Finance.GeneralLedger.Setup;\n+using Microsoft.Purchases.Payables;\n+using Microsoft.Purchases.Vendor;\n+using Microsoft.Sales.Customer;\n+using Microsoft.Sales.Receivables;\n+\n+codeunit 139555 \"Aged Accounts Excel Reports\"\n+{\n+ Subtype = Test;\n+ RequiredTestIsolation = Disabled;\n+ TestPermissions = Disabled;\n+\n+ var\n+ LibraryRandom: Codeunit \"Library - Random\";\n+ LibraryReportDataset: Codeunit \"Library - Report Dataset\";\n+ Assert: Codeunit Assert;\n+ DocumentTypeShouldBeInvoiceErr: Label 'Document Type should be Invoice';\n+ DocumentNoShouldMatchErr: Label 'Document No should match the ledger entry';\n+\n+ [Test]\n+ [HandlerFunctions('EXRAgedAccPayableExcelHandler')]\n+ procedure AgedAccountsPayableExportsDocumentTypeAndNo()\n+ var\n+ Vendor: Record Vendor;\n+ VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n+ Variant: Variant;\n+ RequestPageXml: Text;\n+ ReportDocumentType: Text;\n+ ReportDocumentNo: Text;\n+ begin\n+ // [FEATURE] [AI test]\n+ // [SCENARIO 622247] Aged Accounts Payable Excel report exports Document Type and Document No fields correctly for Invoice entries\n+ InitializeAgingData();\n+\n+ // [GIVEN] Vendor \"V\" with an open vendor ledger entry of type Invoice\n+ // Create vendor directly to avoid VAT posting setup requirements in some localizations\n+ CreateMinimalVendor(Vendor);\n+ CreateVendorLedgerEntry(VendorLedgerEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n+ Commit();\n+\n+ // [WHEN] Running the Aged Accounts Payable Excel report\n+ RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Acc Payable Excel\", RequestPageXml);\n+ LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Acc Payable Excel\", Variant, RequestPageXml);\n+\n+ // [THEN] The exported data contains the Document Type \"Invoice\" and the correct Document No\n+ LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n+ Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n+ LibraryReportDataset.GetNextRow();\n+ LibraryReportDataset.FindCurrentRowValue('DocumentType', Variant);\n+ ReportDocumentType := Variant;\n+ Assert.AreEqual(Format(\"Gen. Journal Document Type\"::Invoice), ReportDocumentType, DocumentTypeShouldBeInvoiceErr);\n+ LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n+ ReportDocumentNo := Variant;\n+ Assert.AreEqual(VendorLedgerEntry.\"Document No.\", ReportDocumentNo, DocumentNoShouldMatchErr);\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('EXRAgedAccountsRecExcelHandler')]\n+ procedure AgedAccountsRecExportsDocumentTypeAndNo()\n+ var\n+ Customer: Record Customer;\n+ CustLedgerEntry: Record \"Cust. Ledger Entry\";\n+ Variant: Variant;\n+ RequestPageXml: Text;\n+ ReportDocumentType: Text;\n+ ReportDocumentNo: Text;\n+ begin\n+ // [FEATURE] [AI test]\n+ // [SCENARIO 622247] Aged Accounts Receivable Excel report exports Document Type and Document No fields correctly for Invoice entries\n+ InitializeAgingData();\n+\n+ // [GIVEN] Customer \"C\" with an open customer ledger entry of type Invoice\n+ // Create customer directly to avoid VAT posting setup requirements in some localizations\n+ CreateMinimalCustomer(Customer);\n+ CreateCustLedgerEntry(CustLedgerEntry, Customer.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n+ Commit();\n+\n+ // [WHEN] Running the Aged Accounts Receivable Excel report\n+ RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Accounts Rec Excel\", RequestPageXml);\n+ LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Accounts Rec Excel\", Variant, RequestPageXml);\n+\n+ // [THEN] The exported data contains the Document Type \"Invoice\" and the correct Document No\n+ LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n+ Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n+ LibraryReportDataset.GetNextRow();\n+ LibraryReportDataset.FindCurrentRowValue('DocumentType', Variant);\n+ ReportDocumentType := Variant;\n+ Assert.AreEqual(Format(\"Gen. Journal Document Type\"::Invoice), ReportDocumentType, DocumentTypeShouldBeInvoiceErr);\n+ LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n+ ReportDocumentNo := Variant;\n+ Assert.AreEqual(CustLedgerEntry.\"Document No.\", ReportDocumentNo, DocumentNoShouldMatchErr);\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('EXRAgedAccPayablePostingDateHandler')]\n+ procedure AgedAccountsPayableReportAgesByPostingDate()\n+ var\n+ Vendor: Record Vendor;\n+ VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n+ Variant: Variant;\n+ RequestPageXml: Text;\n+ ReportingDateText: Text;\n+ ReportingDate: Date;\n+ begin\n+ // [FEATURE] [AI test 0.4]\n+ // [SCENARIO] Aged Accounts Payable report uses Posting Date as Reporting Date when aging by Posting Date\n+ InitializeAgingData();\n+\n+ // [GIVEN] Vendor \"V\" with an open ledger entry where Posting Date, Document Date, and Due Date are distinct\n+ CreateMinimalVendor(Vendor);\n+ CreateVendorLedgerEntry(VendorLedgerEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n+ VendorLedgerEntry.\"Document Date\" := WorkDate() - 10;\n+ VendorLedgerEntry.Modify();\n+ Commit();\n+\n+ // [WHEN] Running the Aged Accounts Payable Excel report with Aging By = Posting Date\n+ RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Acc Payable Excel\", RequestPageXml);\n+ LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Acc Payable Excel\", Variant, RequestPageXml);\n+\n+ // [THEN] The Reporting Date matches the Posting Date of the vendor ledger entry\n+ LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n+ Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n+ LibraryReportDataset.GetNextRow();\n+ LibraryReportDataset.FindCurrentRowValue('ReportingDate', Variant);\n+ ReportingDateText := Variant;\n+ Evaluate(ReportingDate, ReportingDateText);\n+ Assert.AreEqual(VendorLedgerEntry.\"Posting Date\", ReportingDate, 'Reporting Date should match the Posting Date when aging by Posting Date');\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('EXRAgedAccountsRecExcelHandler')]\n+ procedure AgedAccountsRecRendersCurrencyCodePerEntry()\n+ var\n+ Customer: Record Customer;\n+ GeneralLedgerSetup: Record \"General Ledger Setup\";\n+ UsdEntry, LcyEntry : Record \"Cust. Ledger Entry\";\n+ Variant: Variant;\n+ RequestPageXml: Text;\n+ LcyCode: Code[10];\n+ ForeignCurrencyCode: Code[10];\n+ DocNo, CurrencyCode : Text;\n+ i: Integer;\n+ UsdRowSeen, LcyRowSeen : Boolean;\n+ begin\n+ // [SCENARIO 637444] Aged Accounts Receivable Excel renders each row's own Currency Code, not a single per-customer value\n+ InitializeAgingData();\n+\n+ // [GIVEN] G/L Setup with a distinct LCY Code\n+ LcyCode := 'LCY';\n+ ForeignCurrencyCode := 'USD';\n+ if not GeneralLedgerSetup.Get() then\n+ GeneralLedgerSetup.Insert();\n+ GeneralLedgerSetup.\"LCY Code\" := LcyCode;\n+ GeneralLedgerSetup.Modify();\n+\n+ // [GIVEN] A customer with one foreign-currency entry and one LCY (empty Currency Code) entry\n+ CreateMinimalCustomer(Customer);\n+ CreateCustLedgerEntry(UsdEntry, Customer.\"No.\", \"Gen. Journal Document Type\"::Invoice, ForeignCurrencyCode);\n+ CreateCustLedgerEntry(LcyEntry, Customer.\"No.\", \"Gen. Journal Document Type\"::Invoice, '');\n+ Commit();\n+\n+ // [WHEN] Running the Aged Accounts Receivable Excel report\n+ RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Accounts Rec Excel\", RequestPageXml);\n+ LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Accounts Rec Excel\", Variant, RequestPageXml);\n+\n+ // [THEN] The foreign-currency row shows the foreign code and the LCY row shows the LCY code\n+ LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n+ Assert.AreEqual(2, LibraryReportDataset.RowCount(), 'Two aging entries should be exported');\n+ for i := 1 to 2 do begin\n+ LibraryReportDataset.GetNextRow();\n+ LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n+ DocNo := Variant;\n+ LibraryReportDataset.FindCurrentRowValue('CurrencyCode', Variant);\n+ CurrencyCode := Variant;\n+ if DocNo = UsdEntry.\"Document No.\" then begin\n+ Assert.AreEqual(ForeignCurrencyCode, CurrencyCode, 'Foreign-currency row should show its own currency code');\n+ UsdRowSeen := true;\n+ end else\n+ if DocNo = LcyEntry.\"Document No.\" then begin\n+ Assert.AreEqual(LcyCode, CurrencyCode, 'LCY (empty Currency Code) row should fall back to G/L Setup LCY Code');\n+ LcyRowSeen := true;\n+ end;\n+ end;\n+ Assert.IsTrue(UsdRowSeen, 'Foreign-currency row should be present');\n+ Assert.IsTrue(LcyRowSeen, 'LCY row should be present');\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('EXRAgedAccPayableExcelHandler')]\n+ procedure AgedAccountsPayableRendersCurrencyCodePerEntry()\n+ var\n+ Vendor: Record Vendor;\n+ GeneralLedgerSetup: Record \"General Ledger Setup\";\n+ UsdEntry, LcyEntry : Record \"Vendor Ledger Entry\";\n+ Variant: Variant;\n+ RequestPageXml: Text;\n+ LcyCode: Code[10];\n+ ForeignCurrencyCode: Code[10];\n+ DocNo, CurrencyCode : Text;\n+ i: Integer;\n+ UsdRowSeen, LcyRowSeen : Boolean;\n+ begin\n+ // [SCENARIO 637444] Aged Accounts Payable Excel renders each row's own Currency Code, not a single per-vendor value\n+ InitializeAgingData();\n+\n+ // [GIVEN] G/L Setup with a distinct LCY Code\n+ LcyCode := 'LCY';\n+ ForeignCurrencyCode := 'USD';\n+ if not GeneralLedgerSetup.Get() then\n+ GeneralLedgerSetup.Insert();\n+ GeneralLedgerSetup.\"LCY Code\" := LcyCode;\n+ GeneralLedgerSetup.Modify();\n+\n+ // [GIVEN] A vendor with one foreign-currency entry and one LCY (empty Currency Code) entry\n+ CreateMinimalVendor(Vendor);\n+ CreateVendorLedgerEntry(UsdEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice, ForeignCurrencyCode);\n+ CreateVendorLedgerEntry(LcyEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice, '');\n+ Commit();\n+\n+ // [WHEN] Running the Aged Accounts Payable Excel report\n+ RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Acc Payable Excel\", RequestPageXml);\n+ LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Acc Payable Excel\", Variant, RequestPageXml);\n+\n+ // [THEN] The foreign-currency row shows the foreign code and the LCY row shows the LCY code\n+ LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n+ Assert.AreEqual(2, LibraryReportDataset.RowCount(), 'Two aging entries should be exported');\n+ for i := 1 to 2 do begin\n+ LibraryReportDataset.GetNextRow();\n+ LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n+ DocNo := Variant;\n+ LibraryReportDataset.FindCurrentRowValue('CurrencyCode', Variant);\n+ CurrencyCode := Variant;\n+ if DocNo = UsdEntry.\"Document No.\" then begin\n+ Assert.AreEqual(ForeignCurrencyCode, CurrencyCode, 'Foreign-currency row should show its own currency code');\n+ UsdRowSeen := true;\n+ end else\n+ if DocNo = LcyEntry.\"Document No.\" then begin\n+ Assert.AreEqual(LcyCode, CurrencyCode, 'LCY (empty Currency Code) row should fall back to G/L Setup LCY Code');\n+ LcyRowSeen := true;\n+ end;\n+ end;\n+ Assert.IsTrue(UsdRowSeen, 'Foreign-currency row should be present');\n+ Assert.IsTrue(LcyRowSeen, 'LCY row should be present');\n+ end;\n+\n+ local procedure InitializeAgingData()\n+ var\n+ Vendor: Record Vendor;\n+ Customer: Record Customer;\n+ VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n+ CustLedgerEntry: Record \"Cust. Ledger Entry\";\n+ DetailedVendorLedgEntry: Record \"Detailed Vendor Ledg. Entry\";\n+ DetailedCustLedgEntry: Record \"Detailed Cust. Ledg. Entry\";\n+ begin\n+ DetailedVendorLedgEntry.DeleteAll();\n+ DetailedCustLedgEntry.DeleteAll();\n+ VendorLedgerEntry.DeleteAll();\n+ CustLedgerEntry.DeleteAll();\n+ Vendor.DeleteAll();\n+ Customer.DeleteAll();\n+ end;\n+\n+ local procedure CreateMinimalVendor(var Vendor: Record Vendor)\n+ begin\n+ Vendor.Init();\n+ Vendor.\"No.\" := CopyStr(Format(CreateGuid()), 1, MaxStrLen(Vendor.\"No.\"));\n+ Vendor.Name := Vendor.\"No.\";\n+ Vendor.Insert();\n+ end;\n+\n+ local procedure CreateMinimalCustomer(var Customer: Record Customer)\n+ begin\n+ Customer.Init();\n+ Customer.\"No.\" := CopyStr(Format(CreateGuid()), 1, MaxStrLen(Customer.\"No.\"));\n+ Customer.Name := Customer.\"No.\";\n+ Customer.Insert();\n+ end;\n+\n+ local procedure CreateVendorLedgerEntry(var VendorLedgerEntry: Record \"Vendor Ledger Entry\"; VendorNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\")\n+ begin\n+ CreateVendorLedgerEntry(VendorLedgerEntry, VendorNo, DocumentType, '');\n+ end;\n+\n+ local procedure CreateVendorLedgerEntry(var VendorLedgerEntry: Record \"Vendor Ledger Entry\"; VendorNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\"; CurrencyCode: Code[10])\n+ var\n+ DetailedVendorLedgEntry: Record \"Detailed Vendor Ledg. Entry\";\n+ EntryNo: Integer;\n+ Amount: Decimal;\n+ begin\n+ if VendorLedgerEntry.FindLast() then;\n+ EntryNo := VendorLedgerEntry.\"Entry No.\" + 1;\n+\n+ VendorLedgerEntry.Init();\n+ VendorLedgerEntry.\"Entry No.\" := EntryNo;\n+ VendorLedgerEntry.\"Vendor No.\" := VendorNo;\n+ VendorLedgerEntry.\"Vendor Name\" := VendorNo;\n+ VendorLedgerEntry.\"Document Type\" := DocumentType;\n+ VendorLedgerEntry.\"Document No.\" := 'DOC' + Format(EntryNo);\n+ VendorLedgerEntry.\"Posting Date\" := WorkDate();\n+ VendorLedgerEntry.\"Document Date\" := WorkDate();\n+ VendorLedgerEntry.\"Due Date\" := WorkDate() + 30;\n+ VendorLedgerEntry.\"Currency Code\" := CurrencyCode;\n+ VendorLedgerEntry.Open := true;\n+ VendorLedgerEntry.Insert();\n+\n+ // Create detailed vendor ledger entry for remaining amount\n+ Amount := -LibraryRandom.RandDec(1000, 2);\n+ if DetailedVendorLedgEntry.FindLast() then;\n+ DetailedVendorLedgEntry.Init();\n+ DetailedVendorLedgEntry.\"Entry No.\" := DetailedVendorLedgEntry.\"Entry No.\" + 1;\n+ DetailedVendorLedgEntry.\"Vendor Ledger Entry No.\" := VendorLedgerEntry.\"Entry No.\";\n+ DetailedVendorLedgEntry.\"Vendor No.\" := VendorNo;\n+ DetailedVendorLedgEntry.\"Posting Date\" := WorkDate();\n+ DetailedVendorLedgEntry.\"Entry Type\" := DetailedVendorLedgEntry.\"Entry Type\"::\"Initial Entry\";\n+ DetailedVendorLedgEntry.Amount := Amount;\n+ DetailedVendorLedgEntry.\"Amount (LCY)\" := Amount;\n+ DetailedVendorLedgEntry.Insert();\n+ end;\n+\n+ local procedure CreateCustLedgerEntry(var CustLedgerEntry: Record \"Cust. Ledger Entry\"; CustomerNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\")\n+ begin\n+ CreateCustLedgerEntry(CustLedgerEntry, CustomerNo, DocumentType, '');\n+ end;\n+\n+ local procedure CreateCustLedgerEntry(var CustLedgerEntry: Record \"Cust. Ledger Entry\"; CustomerNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\"; CurrencyCode: Code[10])\n+ var\n+ DetailedCustLedgEntry: Record \"Detailed Cust. Ledg. Entry\";\n+ EntryNo: Integer;\n+ Amount: Decimal;\n+ begin\n+ if CustLedgerEntry.FindLast() then;\n+ EntryNo := CustLedgerEntry.\"Entry No.\" + 1;\n+\n+ CustLedgerEntry.Init();\n+ CustLedgerEntry.\"Entry No.\" := EntryNo;\n+ CustLedgerEntry.\"Customer No.\" := CustomerNo;\n+ CustLedgerEntry.\"Customer Name\" := CustomerNo;\n+ CustLedgerEntry.\"Document Type\" := DocumentType;\n+ CustLedgerEntry.\"Document No.\" := 'DOC' + Format(EntryNo);\n+ CustLedgerEntry.\"Posting Date\" := WorkDate();\n+ CustLedgerEntry.\"Document Date\" := WorkDate();\n+ CustLedgerEntry.\"Due Date\" := WorkDate() + 30;\n+ CustLedgerEntry.\"Currency Code\" := CurrencyCode;\n+ CustLedgerEntry.Open := true;\n+ CustLedgerEntry.Insert();\n+\n+ // Create detailed customer ledger entry for remaining amount\n+ Amount := LibraryRandom.RandDec(1000, 2);\n+ if DetailedCustLedgEntry.FindLast() then;\n+ DetailedCustLedgEntry.Init();\n+ DetailedCustLedgEntry.\"Entry No.\" := DetailedCustLedgEntry.\"Entry No.\" + 1;\n+ DetailedCustLedgEntry.\"Cust. Ledger Entry No.\" := CustLedgerEntry.\"Entry No.\";\n+ DetailedCustLedgEntry.\"Customer No.\" := CustomerNo;\n+ DetailedCustLedgEntry.\"Posting Date\" := WorkDate();\n+ DetailedCustLedgEntry.\"Entry Type\" := DetailedCustLedgEntry.\"Entry Type\"::\"Initial Entry\";\n+ DetailedCustLedgEntry.Amount := Amount;\n+ DetailedCustLedgEntry.\"Amount (LCY)\" := Amount;\n+ DetailedCustLedgEntry.Insert();\n+ end;\n+\n+ [RequestPageHandler]\n+ procedure EXRAgedAccPayableExcelHandler(var EXRAgedAccPayableExcel: TestRequestPage \"EXR Aged Acc Payable Excel\")\n+ begin\n+ EXRAgedAccPayableExcel.AgedAsOfOption.SetValue(WorkDate());\n+ EXRAgedAccPayableExcel.OK().Invoke();\n+ end;\n+\n+ [RequestPageHandler]\n+ procedure EXRAgedAccountsRecExcelHandler(var EXRAgedAccountsRecExcel: TestRequestPage \"EXR Aged Accounts Rec Excel\")\n+ begin\n+ EXRAgedAccountsRecExcel.AgedAsOfOption.SetValue(WorkDate());\n+ EXRAgedAccountsRecExcel.OK().Invoke();\n+ end;\n+\n+ [RequestPageHandler]\n+ procedure EXRAgedAccPayablePostingDateHandler(var EXRAgedAccPayableExcel: TestRequestPage \"EXR Aged Acc Payable Excel\")\n+ begin\n+ EXRAgedAccPayableExcel.AgedAsOfOption.SetValue(WorkDate());\n+ EXRAgedAccPayableExcel.AgingbyOption.SetValue('Posting Date');\n+ EXRAgedAccPayableExcel.OK().Invoke();\n+ end;\n+}\ndiff --git a/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al b/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al\nindex b7bb3a1e21..b2468f3b9a 100644\n--- a/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al\n+++ b/src/Apps/W1/ExcelReports/Test/src/TrialBalanceExcelReports.Codeunit.al\n@@ -10,12 +10,7 @@ using Microsoft.Finance.Dimension;\n using Microsoft.Finance.ExcelReports;\n using Microsoft.Finance.GeneralLedger.Account;\n using Microsoft.Finance.GeneralLedger.Budget;\n-using Microsoft.Finance.GeneralLedger.Journal;\n using Microsoft.Finance.GeneralLedger.Ledger;\n-using Microsoft.Purchases.Payables;\n-using Microsoft.Purchases.Vendor;\n-using Microsoft.Sales.Customer;\n-using Microsoft.Sales.Receivables;\n \n codeunit 139544 \"Trial Balance Excel Reports\"\n {\n@@ -26,11 +21,8 @@ codeunit 139544 \"Trial Balance Excel Reports\"\n \n var\n LibraryERM: Codeunit \"Library - ERM\";\n- LibraryRandom: Codeunit \"Library - Random\";\n LibraryReportDataset: Codeunit \"Library - Report Dataset\";\n Assert: Codeunit Assert;\n- DocumentTypeShouldBeInvoiceErr: Label 'Document Type should be Invoice';\n- DocumentNoShouldMatchErr: Label 'Document No should match the ledger entry';\n \n [Test]\n [HandlerFunctions('EXRTrialBalanceExcelHandler')]\n@@ -667,116 +659,6 @@ codeunit 139544 \"Trial Balance Excel Reports\"\n Assert.AreEqual(0, TempTrialBalanceData.\"Starting Balance\", 'Starting Balance should be zero after closing entries')\n end;\n \n- [Test]\n- [HandlerFunctions('EXRAgedAccPayableExcelHandler')]\n- procedure AgedAccountsPayableExportsDocumentTypeAndNo()\n- var\n- Vendor: Record Vendor;\n- VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n- Variant: Variant;\n- RequestPageXml: Text;\n- ReportDocumentType: Text;\n- ReportDocumentNo: Text;\n- begin\n- // [FEATURE] [AI test]\n- // [SCENARIO 622247] Aged Accounts Payable Excel report exports Document Type and Document No fields correctly for Invoice entries\n- InitializeAgingData();\n-\n- // [GIVEN] Vendor \"V\" with an open vendor ledger entry of type Invoice\n- // Create vendor directly to avoid VAT posting setup requirements in some localizations\n- CreateMinimalVendor(Vendor);\n- CreateVendorLedgerEntry(VendorLedgerEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n- Commit();\n-\n- // [WHEN] Running the Aged Accounts Payable Excel report\n- RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Acc Payable Excel\", RequestPageXml);\n- LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Acc Payable Excel\", Variant, RequestPageXml);\n-\n- // [THEN] The exported data contains the Document Type \"Invoice\" and the correct Document No\n- LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n- Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n- LibraryReportDataset.GetNextRow();\n- LibraryReportDataset.FindCurrentRowValue('DocumentType', Variant);\n- ReportDocumentType := Variant;\n- Assert.AreEqual(Format(\"Gen. Journal Document Type\"::Invoice), ReportDocumentType, DocumentTypeShouldBeInvoiceErr);\n- LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n- ReportDocumentNo := Variant;\n- Assert.AreEqual(VendorLedgerEntry.\"Document No.\", ReportDocumentNo, DocumentNoShouldMatchErr);\n- end;\n-\n- [Test]\n- [HandlerFunctions('EXRAgedAccountsRecExcelHandler')]\n- procedure AgedAccountsRecExportsDocumentTypeAndNo()\n- var\n- Customer: Record Customer;\n- CustLedgerEntry: Record \"Cust. Ledger Entry\";\n- Variant: Variant;\n- RequestPageXml: Text;\n- ReportDocumentType: Text;\n- ReportDocumentNo: Text;\n- begin\n- // [FEATURE] [AI test]\n- // [SCENARIO 622247] Aged Accounts Receivable Excel report exports Document Type and Document No fields correctly for Invoice entries\n- InitializeAgingData();\n-\n- // [GIVEN] Customer \"C\" with an open customer ledger entry of type Invoice\n- // Create customer directly to avoid VAT posting setup requirements in some localizations\n- CreateMinimalCustomer(Customer);\n- CreateCustLedgerEntry(CustLedgerEntry, Customer.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n- Commit();\n-\n- // [WHEN] Running the Aged Accounts Receivable Excel report\n- RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Accounts Rec Excel\", RequestPageXml);\n- LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Accounts Rec Excel\", Variant, RequestPageXml);\n-\n- // [THEN] The exported data contains the Document Type \"Invoice\" and the correct Document No\n- LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n- Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n- LibraryReportDataset.GetNextRow();\n- LibraryReportDataset.FindCurrentRowValue('DocumentType', Variant);\n- ReportDocumentType := Variant;\n- Assert.AreEqual(Format(\"Gen. Journal Document Type\"::Invoice), ReportDocumentType, DocumentTypeShouldBeInvoiceErr);\n- LibraryReportDataset.FindCurrentRowValue('DocumentNo', Variant);\n- ReportDocumentNo := Variant;\n- Assert.AreEqual(CustLedgerEntry.\"Document No.\", ReportDocumentNo, DocumentNoShouldMatchErr);\n- end;\n-\n- [Test]\n- [HandlerFunctions('EXRAgedAccPayablePostingDateHandler')]\n- procedure AgedAccountsPayableReportAgesByPostingDate()\n- var\n- Vendor: Record Vendor;\n- VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n- Variant: Variant;\n- RequestPageXml: Text;\n- ReportingDateText: Text;\n- ReportingDate: Date;\n- begin\n- // [FEATURE] [AI test 0.4]\n- // [SCENARIO] Aged Accounts Payable report uses Posting Date as Reporting Date when aging by Posting Date\n- InitializeAgingData();\n-\n- // [GIVEN] Vendor \"V\" with an open ledger entry where Posting Date, Document Date, and Due Date are distinct\n- CreateMinimalVendor(Vendor);\n- CreateVendorLedgerEntry(VendorLedgerEntry, Vendor.\"No.\", \"Gen. Journal Document Type\"::Invoice);\n- VendorLedgerEntry.\"Document Date\" := WorkDate() - 10;\n- VendorLedgerEntry.Modify();\n- Commit();\n-\n- // [WHEN] Running the Aged Accounts Payable Excel report with Aging By = Posting Date\n- RequestPageXml := Report.RunRequestPage(Report::\"EXR Aged Acc Payable Excel\", RequestPageXml);\n- LibraryReportDataset.RunReportAndLoad(Report::\"EXR Aged Acc Payable Excel\", Variant, RequestPageXml);\n-\n- // [THEN] The Reporting Date matches the Posting Date of the vendor ledger entry\n- LibraryReportDataset.SetXmlNodeList('DataItem[@name=\"AgingData\"]');\n- Assert.AreEqual(1, LibraryReportDataset.RowCount(), 'One aging entry should be exported');\n- LibraryReportDataset.GetNextRow();\n- LibraryReportDataset.FindCurrentRowValue('ReportingDate', Variant);\n- ReportingDateText := Variant;\n- Evaluate(ReportingDate, ReportingDateText);\n- Assert.AreEqual(VendorLedgerEntry.\"Posting Date\", ReportingDate, 'Reporting Date should match the Posting Date when aging by Posting Date');\n- end;\n-\n local procedure CreateSampleBusinessUnits(HowMany: Integer)\n var\n BusinessUnit: Record \"Business Unit\";\n@@ -900,109 +782,6 @@ codeunit 139544 \"Trial Balance Excel Reports\"\n GLEntry.Insert();\n end;\n \n- local procedure InitializeAgingData()\n- var\n- Vendor: Record Vendor;\n- Customer: Record Customer;\n- VendorLedgerEntry: Record \"Vendor Ledger Entry\";\n- CustLedgerEntry: Record \"Cust. Ledger Entry\";\n- DetailedVendorLedgEntry: Record \"Detailed Vendor Ledg. Entry\";\n- DetailedCustLedgEntry: Record \"Detailed Cust. Ledg. Entry\";\n- begin\n- DetailedVendorLedgEntry.DeleteAll();\n- DetailedCustLedgEntry.DeleteAll();\n- VendorLedgerEntry.DeleteAll();\n- CustLedgerEntry.DeleteAll();\n- Vendor.DeleteAll();\n- Customer.DeleteAll();\n- end;\n-\n- local procedure CreateMinimalVendor(var Vendor: Record Vendor)\n- begin\n- Vendor.Init();\n- Vendor.\"No.\" := CopyStr(Format(CreateGuid()), 1, MaxStrLen(Vendor.\"No.\"));\n- Vendor.Name := Vendor.\"No.\";\n- Vendor.Insert();\n- end;\n-\n- local procedure CreateMinimalCustomer(var Customer: Record Customer)\n- begin\n- Customer.Init();\n- Customer.\"No.\" := CopyStr(Format(CreateGuid()), 1, MaxStrLen(Customer.\"No.\"));\n- Customer.Name := Customer.\"No.\";\n- Customer.Insert();\n- end;\n-\n- local procedure CreateVendorLedgerEntry(var VendorLedgerEntry: Record \"Vendor Ledger Entry\"; VendorNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\")\n- var\n- DetailedVendorLedgEntry: Record \"Detailed Vendor Ledg. Entry\";\n- EntryNo: Integer;\n- Amount: Decimal;\n- begin\n- if VendorLedgerEntry.FindLast() then;\n- EntryNo := VendorLedgerEntry.\"Entry No.\" + 1;\n-\n- VendorLedgerEntry.Init();\n- VendorLedgerEntry.\"Entry No.\" := EntryNo;\n- VendorLedgerEntry.\"Vendor No.\" := VendorNo;\n- VendorLedgerEntry.\"Vendor Name\" := VendorNo;\n- VendorLedgerEntry.\"Document Type\" := DocumentType;\n- VendorLedgerEntry.\"Document No.\" := 'DOC' + Format(EntryNo);\n- VendorLedgerEntry.\"Posting Date\" := WorkDate();\n- VendorLedgerEntry.\"Document Date\" := WorkDate();\n- VendorLedgerEntry.\"Due Date\" := WorkDate() + 30;\n- VendorLedgerEntry.Open := true;\n- VendorLedgerEntry.Insert();\n-\n- // Create detailed vendor ledger entry for remaining amount\n- Amount := -LibraryRandom.RandDec(1000, 2);\n- if DetailedVendorLedgEntry.FindLast() then;\n- DetailedVendorLedgEntry.Init();\n- DetailedVendorLedgEntry.\"Entry No.\" := DetailedVendorLedgEntry.\"Entry No.\" + 1;\n- DetailedVendorLedgEntry.\"Vendor Ledger Entry No.\" := VendorLedgerEntry.\"Entry No.\";\n- DetailedVendorLedgEntry.\"Vendor No.\" := VendorNo;\n- DetailedVendorLedgEntry.\"Posting Date\" := WorkDate();\n- DetailedVendorLedgEntry.\"Entry Type\" := DetailedVendorLedgEntry.\"Entry Type\"::\"Initial Entry\";\n- DetailedVendorLedgEntry.Amount := Amount;\n- DetailedVendorLedgEntry.\"Amount (LCY)\" := Amount;\n- DetailedVendorLedgEntry.Insert();\n- end;\n-\n- local procedure CreateCustLedgerEntry(var CustLedgerEntry: Record \"Cust. Ledger Entry\"; CustomerNo: Code[20]; DocumentType: Enum \"Gen. Journal Document Type\")\n- var\n- DetailedCustLedgEntry: Record \"Detailed Cust. Ledg. Entry\";\n- EntryNo: Integer;\n- Amount: Decimal;\n- begin\n- if CustLedgerEntry.FindLast() then;\n- EntryNo := CustLedgerEntry.\"Entry No.\" + 1;\n-\n- CustLedgerEntry.Init();\n- CustLedgerEntry.\"Entry No.\" := EntryNo;\n- CustLedgerEntry.\"Customer No.\" := CustomerNo;\n- CustLedgerEntry.\"Customer Name\" := CustomerNo;\n- CustLedgerEntry.\"Document Type\" := DocumentType;\n- CustLedgerEntry.\"Document No.\" := 'DOC' + Format(EntryNo);\n- CustLedgerEntry.\"Posting Date\" := WorkDate();\n- CustLedgerEntry.\"Document Date\" := WorkDate();\n- CustLedgerEntry.\"Due Date\" := WorkDate() + 30;\n- CustLedgerEntry.Open := true;\n- CustLedgerEntry.Insert();\n-\n- // Create detailed customer ledger entry for remaining amount\n- Amount := LibraryRandom.RandDec(1000, 2);\n- if DetailedCustLedgEntry.FindLast() then;\n- DetailedCustLedgEntry.Init();\n- DetailedCustLedgEntry.\"Entry No.\" := DetailedCustLedgEntry.\"Entry No.\" + 1;\n- DetailedCustLedgEntry.\"Cust. Ledger Entry No.\" := CustLedgerEntry.\"Entry No.\";\n- DetailedCustLedgEntry.\"Customer No.\" := CustomerNo;\n- DetailedCustLedgEntry.\"Posting Date\" := WorkDate();\n- DetailedCustLedgEntry.\"Entry Type\" := DetailedCustLedgEntry.\"Entry Type\"::\"Initial Entry\";\n- DetailedCustLedgEntry.Amount := Amount;\n- DetailedCustLedgEntry.\"Amount (LCY)\" := Amount;\n- DetailedCustLedgEntry.Insert();\n- end;\n-\n [RequestPageHandler]\n procedure EXRTrialBalanceExcelHandler(var EXRTrialBalanceExcel: TestRequestPage \"EXR Trial Balance Excel\")\n begin\n@@ -1032,28 +811,6 @@ codeunit 139544 \"Trial Balance Excel Reports\"\n EXRConsolidatedTrialBalance.OK().Invoke();\n end;\n \n- [RequestPageHandler]\n- procedure EXRAgedAccPayableExcelHandler(var EXRAgedAccPayableExcel: TestRequestPage \"EXR Aged Acc Payable Excel\")\n- begin\n- EXRAgedAccPayableExcel.AgedAsOfOption.SetValue(WorkDate());\n- EXRAgedAccPayableExcel.OK().Invoke();\n- end;\n-\n- [RequestPageHandler]\n- procedure EXRAgedAccountsRecExcelHandler(var EXRAgedAccountsRecExcel: TestRequestPage \"EXR Aged Accounts Rec Excel\")\n- begin\n- EXRAgedAccountsRecExcel.AgedAsOfOption.SetValue(WorkDate());\n- EXRAgedAccountsRecExcel.OK().Invoke();\n- end;\n-\n- [RequestPageHandler]\n- procedure EXRAgedAccPayablePostingDateHandler(var EXRAgedAccPayableExcel: TestRequestPage \"EXR Aged Acc Payable Excel\")\n- begin\n- EXRAgedAccPayableExcel.AgedAsOfOption.SetValue(WorkDate());\n- EXRAgedAccPayableExcel.AgingbyOption.SetValue('Posting Date');\n- EXRAgedAccPayableExcel.OK().Invoke();\n- end;\n-\n #if not CLEAN27\n #pragma warning disable AL0432\n [EventSubscriber(ObjectType::Codeunit, Codeunit::\"Trial Balance\", OnIsPerformantTrialBalanceFeatureActive, '', false, false)]\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8632", "base_commit": "b3d3921ad18ebb9ae148c196ba465a7af8abb91f", "created_at": "2026-06-16T06:33:07Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchFactboxMgmt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchFactboxMgmt.Codeunit.al\nindex a3dce9b95a..42b769b1c0 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchFactboxMgmt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchFactboxMgmt.Codeunit.al\n@@ -376,6 +376,41 @@ codeunit 99001560 \"Subc. Purch. Factbox Mgmt.\"\n end;\n end;\n \n+ /// \n+ /// Opens the subcontracting transfer order(s) linked to the given production order.\n+ /// \n+ /// The production order to show the related subcontracting transfer orders for.\n+ procedure ShowTransferOrdersFromProductionOrder(ProductionOrder: Record \"Production Order\")\n+ var\n+ TransferHeader: Record \"Transfer Header\";\n+ TransferHeaderToOpen: Record \"Transfer Header\";\n+ TransferLine: Record \"Transfer Line\";\n+ PageManagement: Codeunit \"Page Management\";\n+ SelectionFilterMgt: Codeunit SelectionFilterManagement;\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ TransferLine.SetCurrentKey(\"Subc. Prod. Order No.\", \"Subc. Prod. Order Line No.\", \"Subc. Routing Reference No.\", \"Subc. Routing No.\", \"Subc. Operation No.\");\n+ TransferLine.SetRange(\"Subc. Prod. Order No.\", ProductionOrder.\"No.\");\n+ TransferLine.SetRange(\"Derived From Line No.\", 0);\n+ if TransferLine.FindSet() then\n+ repeat\n+ if TransferHeader.Get(TransferLine.\"Document No.\") then\n+ TransferHeader.Mark(true);\n+ until TransferLine.Next() = 0;\n+ TransferHeader.MarkedOnly(true);\n+\n+ if TransferHeader.IsEmpty() then\n+ TransferHeaderToOpen.SetRange(\"No.\", '')\n+ else\n+ TransferHeaderToOpen.SetFilter(\"No.\", SelectionFilterMgt.GetSelectionFilterForTransferHeader(TransferHeader));\n+ PageManagement.PageRunList(TransferHeaderToOpen);\n+ end;\n+\n /// \n /// Returns the number of subcontractor prices matching the given purchase line.\n /// \ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrder.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrder.PageExt.al\nindex 3fe5eb00ce..9305138f0c 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrder.PageExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrder.PageExt.al\n@@ -1,55 +1,69 @@\n-// ------------------------------------------------------------------------------------------------\n-// Copyright (c) Microsoft Corporation. All rights reserved.\n-// Licensed under the MIT License. See License.txt in the project root for license information.\n-// ------------------------------------------------------------------------------------------------\n-namespace Microsoft.Manufacturing.Subcontracting;\n-\n-using Microsoft.Inventory.Ledger;\n-using Microsoft.Manufacturing.Document;\n-using Microsoft.Purchases.Document;\n-\n-pageextension 99001548 \"Subc. Finished Prod. Order\" extends \"Finished Production Order\"\n-{\n- actions\n- {\n- addafter(\"Registered Put-away Lines\")\n- {\n- action(\"Subcontracting Purchase Lines\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting Order Lines';\n- Image = SubcontractingWorksheet;\n- RunObject = page \"Purchase Lines\";\n- RunPageLink = \"Document Type\" = const(Order), \"Prod. Order No.\" = field(\"No.\");\n- ToolTip = 'Show purchase order lines for subcontracting.';\n- }\n- }\n- addafter(\"&Warehouse Entries\")\n- {\n- action(\"Subc. Transfer Entries\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting Transfer Entries';\n- Image = ItemLedger;\n- RunObject = page \"Item Ledger Entries\";\n- RunPageLink = \"Entry Type\" = const(Transfer), \"Subc. Prod. Order No.\" = field(\"No.\");\n- RunPageView = sorting(\"Order Type\", \"Order No.\");\n- ToolTip = 'View the list of subcontracting transfers.';\n- }\n- action(\"WIP Ledger Entries\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting WIP Entries';\n- Image = LedgerEntries;\n- RunObject = page \"Subc. WIP Ledger Entries\";\n- RunPageLink = \"Prod. Order Status\" = field(Status), \"Prod. Order No.\" = field(\"No.\");\n- ToolTip = 'View the Subcontracting WIP Entries for this production order.';\n- }\n- }\n- addlast(Category_Entries)\n- {\n- actionref(\"Subc. Transfer Entries_Promoted\"; \"Subc. Transfer Entries\") { }\n- actionref(\"WIP Ledger Entries_Promoted\"; \"WIP Ledger Entries\") { }\n- }\n- }\n+// ------------------------------------------------------------------------------------------------\n+// Copyright (c) Microsoft Corporation. All rights reserved.\n+// Licensed under the MIT License. See License.txt in the project root for license information.\n+// ------------------------------------------------------------------------------------------------\n+namespace Microsoft.Manufacturing.Subcontracting;\n+\n+using Microsoft.Inventory.Ledger;\n+using Microsoft.Manufacturing.Document;\n+using Microsoft.Purchases.Document;\n+\n+pageextension 99001548 \"Subc. Finished Prod. Order\" extends \"Finished Production Order\"\n+{\n+ actions\n+ {\n+ addafter(\"Registered Put-away Lines\")\n+ {\n+ action(\"Subcontracting Purchase Lines\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Order Lines';\n+ Image = SubcontractingWorksheet;\n+ RunObject = page \"Purchase Lines\";\n+ RunPageLink = \"Document Type\" = const(Order), \"Prod. Order No.\" = field(\"No.\");\n+ ToolTip = 'Show purchase order lines for subcontracting.';\n+ }\n+ }\n+ addafter(\"&Warehouse Entries\")\n+ {\n+ action(\"Subc. Transfer Orders\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Orders';\n+ Image = TransferOrder;\n+ ToolTip = 'View the subcontracting transfer orders related to this production order.';\n+\n+ trigger OnAction()\n+ var\n+ SubcPurchFactboxMgmt: Codeunit \"Subc. Purch. Factbox Mgmt.\";\n+ begin\n+ SubcPurchFactboxMgmt.ShowTransferOrdersFromProductionOrder(Rec);\n+ end;\n+ }\n+ action(\"Subc. Transfer Entries\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Entries';\n+ Image = ItemLedger;\n+ RunObject = page \"Item Ledger Entries\";\n+ RunPageLink = \"Entry Type\" = const(Transfer), \"Subc. Prod. Order No.\" = field(\"No.\");\n+ RunPageView = sorting(\"Order Type\", \"Order No.\");\n+ ToolTip = 'View the list of subcontracting transfers.';\n+ }\n+ action(\"WIP Ledger Entries\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting WIP Entries';\n+ Image = LedgerEntries;\n+ RunObject = page \"Subc. WIP Ledger Entries\";\n+ RunPageLink = \"Prod. Order Status\" = field(Status), \"Prod. Order No.\" = field(\"No.\");\n+ ToolTip = 'View the Subcontracting WIP Entries for this production order.';\n+ }\n+ }\n+ addlast(Category_Entries)\n+ {\n+ actionref(\"Subc. Transfer Entries_Promoted\"; \"Subc. Transfer Entries\") { }\n+ actionref(\"WIP Ledger Entries_Promoted\"; \"WIP Ledger Entries\") { }\n+ }\n+ }\n }\n\\ No newline at end of file\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrders.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrders.PageExt.al\nindex d6753ba257..ff954e609e 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrders.PageExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcFinishedProdOrders.PageExt.al\n@@ -1,50 +1,64 @@\n-// ------------------------------------------------------------------------------------------------\n-// Copyright (c) Microsoft Corporation. All rights reserved.\n-// Licensed under the MIT License. See License.txt in the project root for license information.\n-// ------------------------------------------------------------------------------------------------\n-namespace Microsoft.Manufacturing.Subcontracting;\n-\n-using Microsoft.Inventory.Ledger;\n-using Microsoft.Manufacturing.Document;\n-using Microsoft.Purchases.Document;\n-\n-pageextension 99001543 \"Subc. Finished Prod. Orders\" extends \"Finished Production Orders\"\n-{\n- actions\n- {\n- addafter(\"E&ntries\")\n- {\n- action(\"Subcontracting Purchase Lines\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting Order Lines';\n- Image = SubcontractingWorksheet;\n- RunObject = page \"Purchase Lines\";\n- RunPageLink = \"Document Type\" = const(Order), \"Prod. Order No.\" = field(\"No.\");\n- ToolTip = 'Show purchase order lines for subcontracting.';\n- }\n- }\n- addafter(\"&Warehouse Entries\")\n- {\n- action(\"Subc. Transfer Entries\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting Transfer Entries';\n- Image = ItemLedger;\n- RunObject = page \"Item Ledger Entries\";\n- RunPageLink = \"Entry Type\" = const(Transfer), \"Subc. Prod. Order No.\" = field(\"No.\");\n- RunPageView = sorting(\"Order Type\", \"Order No.\");\n- ToolTip = 'View the list of subcontracting transfers.';\n- }\n- action(\"WIP Ledger Entries\")\n- {\n- ApplicationArea = Subcontracting;\n- Caption = 'Subcontracting WIP Entries';\n- Image = LedgerEntries;\n- RunObject = page \"Subc. WIP Ledger Entries\";\n- RunPageLink = \"Prod. Order Status\" = field(Status), \"Prod. Order No.\" = field(\"No.\");\n- ToolTip = 'View the Subcontracting WIP Entries for this production order.';\n- }\n- }\n- }\n+// ------------------------------------------------------------------------------------------------\n+// Copyright (c) Microsoft Corporation. All rights reserved.\n+// Licensed under the MIT License. See License.txt in the project root for license information.\n+// ------------------------------------------------------------------------------------------------\n+namespace Microsoft.Manufacturing.Subcontracting;\n+\n+using Microsoft.Inventory.Ledger;\n+using Microsoft.Manufacturing.Document;\n+using Microsoft.Purchases.Document;\n+\n+pageextension 99001543 \"Subc. Finished Prod. Orders\" extends \"Finished Production Orders\"\n+{\n+ actions\n+ {\n+ addafter(\"E&ntries\")\n+ {\n+ action(\"Subcontracting Purchase Lines\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Order Lines';\n+ Image = SubcontractingWorksheet;\n+ RunObject = page \"Purchase Lines\";\n+ RunPageLink = \"Document Type\" = const(Order), \"Prod. Order No.\" = field(\"No.\");\n+ ToolTip = 'Show purchase order lines for subcontracting.';\n+ }\n+ }\n+ addafter(\"&Warehouse Entries\")\n+ {\n+ action(\"Subc. Transfer Orders\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Orders';\n+ Image = TransferOrder;\n+ ToolTip = 'View the subcontracting transfer orders related to this production order.';\n+\n+ trigger OnAction()\n+ var\n+ SubcPurchFactboxMgmt: Codeunit \"Subc. Purch. Factbox Mgmt.\";\n+ begin\n+ SubcPurchFactboxMgmt.ShowTransferOrdersFromProductionOrder(Rec);\n+ end;\n+ }\n+ action(\"Subc. Transfer Entries\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Entries';\n+ Image = ItemLedger;\n+ RunObject = page \"Item Ledger Entries\";\n+ RunPageLink = \"Entry Type\" = const(Transfer), \"Subc. Prod. Order No.\" = field(\"No.\");\n+ RunPageView = sorting(\"Order Type\", \"Order No.\");\n+ ToolTip = 'View the list of subcontracting transfers.';\n+ }\n+ action(\"WIP Ledger Entries\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting WIP Entries';\n+ Image = LedgerEntries;\n+ RunObject = page \"Subc. WIP Ledger Entries\";\n+ RunPageLink = \"Prod. Order Status\" = field(Status), \"Prod. Order No.\" = field(\"No.\");\n+ ToolTip = 'View the Subcontracting WIP Entries for this production order.';\n+ }\n+ }\n+ }\n }\n\\ No newline at end of file\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrder.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrder.PageExt.al\nindex fae7afb0ca..7612fdcf78 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrder.PageExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrder.PageExt.al\n@@ -25,6 +25,20 @@ pageextension 99001504 \"Subc. Rel. Prod. Order\" extends \"Released Production Ord\n }\n addafter(\"&Warehouse Entries\")\n {\n+ action(\"Subc. Transfer Orders\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Orders';\n+ Image = TransferOrder;\n+ ToolTip = 'View the subcontracting transfer orders related to this production order.';\n+\n+ trigger OnAction()\n+ var\n+ SubcPurchFactboxMgmt: Codeunit \"Subc. Purch. Factbox Mgmt.\";\n+ begin\n+ SubcPurchFactboxMgmt.ShowTransferOrdersFromProductionOrder(Rec);\n+ end;\n+ }\n action(\"Subc. Transfer Entries\")\n {\n ApplicationArea = Subcontracting;\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrders.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrders.PageExt.al\nindex a6a74dc3d3..0446a28a16 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrders.PageExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/Manufacturing/SubcRelProdOrders.PageExt.al\n@@ -25,6 +25,20 @@ pageextension 99001505 \"Subc. Rel. Prod. Orders\" extends \"Released Production Or\n }\n addafter(\"&Warehouse Entries\")\n {\n+ action(\"Subc. Transfer Orders\")\n+ {\n+ ApplicationArea = Subcontracting;\n+ Caption = 'Subcontracting Transfer Orders';\n+ Image = TransferOrder;\n+ ToolTip = 'View the subcontracting transfer orders related to this production order.';\n+\n+ trigger OnAction()\n+ var\n+ SubcPurchFactboxMgmt: Codeunit \"Subc. Purch. Factbox Mgmt.\";\n+ begin\n+ SubcPurchFactboxMgmt.ShowTransferOrdersFromProductionOrder(Rec);\n+ end;\n+ }\n action(\"Subc. Transfer Entries\")\n {\n ApplicationArea = Subcontracting;\n", "FAIL_TO_PASS": [{"codeunitID": 139989, "functionName": ["SubcTransferOrdersActionOnProductionOrdersListOpensRelatedTransferOrder", "SubcTransferOrdersActionOnProductionOrderOpensRelatedTransferOrder"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\nindex c2ad504090..ef56e4265d 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n@@ -164,6 +164,72 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n Assert.RecordIsNotEmpty(TransferLine);\n end;\n \n+ [Test]\n+ [HandlerFunctions('ConfirmHandler,HandleTransferOrder,HandleSubcTransferOrdersList')]\n+ procedure SubcTransferOrdersActionOnProductionOrderOpensRelatedTransferOrder()\n+ var\n+ Item: Record Item;\n+ ProductionOrder: Record \"Production Order\";\n+ UnrelatedProductionOrder: Record \"Production Order\";\n+ ProductionLocation: Record Location;\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ ExpectedTransferOrderNo: Code[20];\n+ ReleasedProductionOrder: TestPage \"Released Production Order\";\n+ begin\n+ // [SCENARIO 638532] The Released Production Order card provides a navigation action to view only its related subcontracting transfer orders.\n+\n+ // [GIVEN] Subcontracting setup with two released production orders, each ending up with its own subcontracting purchase order and transfer order.\n+ // The transfer route is location-based (component location -> subcontractor location), so it is created only for the first order and reused by the second.\n+ SetupSubcontractingForTransferOrderTests(Item, WorkCenter, ProductionLocation);\n+ ExpectedTransferOrderNo := CreateProductionOrderWithSubcTransferOrder(Item, WorkCenter, ProductionLocation.Code, true, ProductionOrder);\n+ CreateProductionOrderWithSubcTransferOrder(Item, WorkCenter, ProductionLocation.Code, false, UnrelatedProductionOrder);\n+\n+ // [WHEN] Invoking the \"Subcontracting Transfer Orders\" action on the first production order card\n+ OpenedTransferOrderListNo := '';\n+ ReleasedProductionOrder.OpenView();\n+ ReleasedProductionOrder.GoToRecord(ProductionOrder);\n+ ReleasedProductionOrder.\"Subc. Transfer Orders\".Invoke();\n+ ReleasedProductionOrder.Close();\n+\n+ // [THEN] Only the related transfer order is shown - the handler asserts exactly one record, so the unrelated order is excluded\n+ Assert.AreEqual(\n+ ExpectedTransferOrderNo, OpenedTransferOrderListNo,\n+ 'The production order card action must open only the related subcontracting transfer order.');\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('ConfirmHandler,HandleTransferOrder,HandleSubcTransferOrdersList')]\n+ procedure SubcTransferOrdersActionOnProductionOrdersListOpensRelatedTransferOrder()\n+ var\n+ Item: Record Item;\n+ ProductionOrder: Record \"Production Order\";\n+ UnrelatedProductionOrder: Record \"Production Order\";\n+ ProductionLocation: Record Location;\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ ExpectedTransferOrderNo: Code[20];\n+ ReleasedProductionOrders: TestPage \"Released Production Orders\";\n+ begin\n+ // [SCENARIO 638532] The Released Production Orders list provides a navigation action to view only the related subcontracting transfer orders.\n+\n+ // [GIVEN] Subcontracting setup with two released production orders, each ending up with its own subcontracting purchase order and transfer order.\n+ // The transfer route is location-based (component location -> subcontractor location), so it is created only for the first order and reused by the second.\n+ SetupSubcontractingForTransferOrderTests(Item, WorkCenter, ProductionLocation);\n+ ExpectedTransferOrderNo := CreateProductionOrderWithSubcTransferOrder(Item, WorkCenter, ProductionLocation.Code, true, ProductionOrder);\n+ CreateProductionOrderWithSubcTransferOrder(Item, WorkCenter, ProductionLocation.Code, false, UnrelatedProductionOrder);\n+\n+ // [WHEN] Invoking the \"Subcontracting Transfer Orders\" action on the first production order in the list\n+ OpenedTransferOrderListNo := '';\n+ ReleasedProductionOrders.OpenView();\n+ ReleasedProductionOrders.GoToRecord(ProductionOrder);\n+ ReleasedProductionOrders.\"Subc. Transfer Orders\".Invoke();\n+ ReleasedProductionOrders.Close();\n+\n+ // [THEN] Only the related transfer order is shown - the handler asserts exactly one record, so the unrelated order is excluded\n+ Assert.AreEqual(\n+ ExpectedTransferOrderNo, OpenedTransferOrderListNo,\n+ 'The production orders list action must open only the related subcontracting transfer order.');\n+ end;\n+\n [Test]\n [HandlerFunctions('ConfirmHandler,HandleTransferOrder')]\n procedure CannotDeleteSubcontractingOrderWithAssociatedTransferOrder()\n@@ -3013,6 +3079,15 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n TransfOrderPage.OK().Invoke();\n end;\n \n+ [PageHandler]\n+ procedure HandleSubcTransferOrdersList(var TransferOrders: TestPage \"Transfer Orders\")\n+ begin\n+ Assert.IsTrue(TransferOrders.First(), 'Expected at least one subcontracting transfer order in the list.');\n+ OpenedTransferOrderListNo := CopyStr(TransferOrders.\"No.\".Value(), 1, MaxStrLen(OpenedTransferOrderListNo));\n+ Assert.IsFalse(TransferOrders.Next(), 'Expected exactly one subcontracting transfer order in the list.');\n+ TransferOrders.OK().Invoke();\n+ end;\n+\n [ConfirmHandler]\n procedure ConfirmYesShowSubcontractingPurchOrders(Question: Text[1024]; var Reply: Boolean)\n begin\n@@ -3131,6 +3206,65 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n exit(RoutingLine.\"Operation No.\");\n end;\n \n+ local procedure SetupSubcontractingForTransferOrderTests(var Item: Record Item; var WorkCenter: array[2] of Record \"Work Center\"; var ProductionLocation: Record Location)\n+ var\n+ MachineCenter: array[2] of Record \"Machine Center\";\n+ begin\n+ Initialize();\n+ SubcontractingMgmtLibrary.UpdateManufacturingSetupWithSubcontractingLocation();\n+ SubcontractingMgmtLibrary.SetupInventorySetup();\n+\n+ Subcontracting := true;\n+ UnitCostCalculation := UnitCostCalculation::Units;\n+ CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter);\n+ CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter);\n+ UpdateProdBomAndRoutingWithRoutingLink(Item, WorkCenter[2].\"No.\");\n+ SubcontractingMgmtLibrary.UpdateProdBomWithComponentSupplyMethod(Item, \"Component Supply Method\"::\"Transfer to Vendor\");\n+ UpdateVendorWithSubcontractingLocationCode(WorkCenter[2]);\n+ LibraryWarehouse.CreateLocationWithInventoryPostingSetup(ProductionLocation);\n+ UpdateSubMgmtSetupWithReqWkshTemplate();\n+ end;\n+\n+ local procedure CreateProductionOrderWithSubcTransferOrder(Item: Record Item; var WorkCenter: array[2] of Record \"Work Center\"; ProductionLocationCode: Code[10]; CreateTransferRouteForOrder: Boolean; var ProductionOrder: Record \"Production Order\"): Code[20]\n+ var\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ TransferHeader: Record \"Transfer Header\";\n+ ReleasedProdOrderRtng: TestPage \"Prod. Order Routing\";\n+ PurchaseHeaderPage: TestPage \"Purchase Order\";\n+ begin\n+ SubcontractingMgmtLibrary.CreateAndRefreshProductionOrder(\n+ ProductionOrder, \"Production Order Status\"::Released, ProductionOrder.\"Source Type\"::Item, Item.\"No.\", LibraryRandom.RandInt(10) + 5);\n+ SetAllProdOrderTransferComponentLocations(ProductionOrder.\"No.\", ProductionLocationCode);\n+ // The transfer route is keyed by from/to location, so it must be created only once for a given location pair.\n+ // Callers that reuse the same locations pass false for subsequent orders to reuse the existing route.\n+ if CreateTransferRouteForOrder then\n+ SubcontractingMgmtLibrary.CreateTransferRoute(WorkCenter[2], ProductionOrder);\n+\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+ ProdOrderRoutingLine.SetRange(\"Work Center No.\", WorkCenter[2].\"No.\");\n+ ProdOrderRoutingLine.FindFirst();\n+ ReleasedProdOrderRtng.OpenView();\n+ ReleasedProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ ReleasedProdOrderRtng.CreateSubcontracting.Invoke();\n+ ReleasedProdOrderRtng.Close();\n+\n+ PurchaseLine.SetRange(\"Document Type\", PurchaseLine.\"Document Type\"::Order);\n+ PurchaseLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+ PurchaseLine.FindFirst();\n+ PurchaseHeader.Get(PurchaseLine.\"Document Type\", PurchaseLine.\"Document No.\");\n+\n+ PurchaseHeaderPage.OpenView();\n+ PurchaseHeaderPage.GoToRecord(PurchaseHeader);\n+ PurchaseHeaderPage.CreateTransfOrdToSubcontractor.Invoke();\n+ PurchaseHeaderPage.Close();\n+\n+ TransferHeader.SetRange(\"Subcontr. Purch. Order No.\", PurchaseHeader.\"No.\");\n+ Assert.IsTrue(TransferHeader.FindFirst(), 'Expected a subcontracting transfer order for the production order.');\n+ exit(TransferHeader.\"No.\");\n+ end;\n+\n local procedure CreateAndCalculateNeededWorkAndMachineCenter(var WorkCenter: array[2] of Record \"Work Center\"; var MachineCenter: array[2] of Record \"Machine Center\")\n var\n CapacityUnitOfMeasure: Record \"Capacity Unit of Measure\";\n@@ -3983,6 +4117,7 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n IsInitialized: Boolean;\n Subcontracting: Boolean;\n OpenedTransferOrderNo: Code[20];\n+ OpenedTransferOrderListNo: Code[20];\n PurchaseOrderPageOpened: Boolean;\n PurchaseLinesPageOpened: Boolean;\n UnitCostCalculation: Option Time,Units;\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8616", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-15T21:29:21Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Install/SubcontractingInstall.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Install/SubcontractingInstall.Codeunit.al\nindex 2631e38aec..8af3d51e41 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Install/SubcontractingInstall.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Install/SubcontractingInstall.Codeunit.al\n@@ -4,7 +4,6 @@\n // ------------------------------------------------------------------------------------------------\n namespace Microsoft.Manufacturing.Subcontracting;\n \n-using Microsoft.QualityManagement.Setup.ApplicationAreas;\n using System.Upgrade;\n \n codeunit 99001501 \"Subcontracting Install\"\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Permissions/SubcontractObjs.PermissionSet.al b/src/Apps/W1/Subcontracting/App/src/Permissions/SubcontractObjs.PermissionSet.al\nindex 74a24a8bf0..42b5428962 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Permissions/SubcontractObjs.PermissionSet.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Permissions/SubcontractObjs.PermissionSet.al\n@@ -3,8 +3,8 @@\n // Licensed under the MIT License. See License.txt in the project root for license information.\n // ------------------------------------------------------------------------------------------------\n namespace Microsoft.Manufacturing.Subcontracting;\n+\n using Microsoft.Manufacturing.Planning;\n-using Microsoft.QualityManagement.Setup.ApplicationAreas;\n \n permissionset 99001501 \"Subcontract. - Objs\"\n {\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/SubcILEntries.PageExt.al b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/SubcILEntries.PageExt.al\nindex 260fe4b050..d1d232c956 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/SubcILEntries.PageExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Pageextensions/SubcILEntries.PageExt.al\n@@ -49,6 +49,7 @@ pageextension 99001501 \"Subc. ILEntries\" extends \"Item Ledger Entries\"\n {\n ApplicationArea = Subcontracting;\n Caption = 'Production Order';\n+ Enabled = Rec.\"Subc. Prod. Order No.\" <> '';\n Image = Production;\n ToolTip = 'View the related production order.';\n trigger OnAction()\n@@ -60,6 +61,7 @@ pageextension 99001501 \"Subc. ILEntries\" extends \"Item Ledger Entries\"\n {\n ApplicationArea = Subcontracting;\n Caption = 'Production Order Routing';\n+ Enabled = Rec.\"Subc. Prod. Order No.\" <> '';\n Image = Route;\n ToolTip = 'View the related production order routing.';\n trigger OnAction()\n@@ -71,6 +73,7 @@ pageextension 99001501 \"Subc. ILEntries\" extends \"Item Ledger Entries\"\n {\n ApplicationArea = Subcontracting;\n Caption = 'Production Order Components';\n+ Enabled = Rec.\"Subc. Prod. Order No.\" <> '';\n Image = Components;\n ToolTip = 'View the related production order components.';\n trigger OnAction()\n@@ -82,6 +85,7 @@ pageextension 99001501 \"Subc. ILEntries\" extends \"Item Ledger Entries\"\n {\n ApplicationArea = Subcontracting;\n Caption = 'Subcontracting Purchase Order';\n+ Enabled = Rec.\"Subc. Purch. Order No.\" <> '';\n Image = Order;\n ToolTip = 'View the related subcontracting purchase order.';\n trigger OnAction()\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaMgmt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaMgmt.Codeunit.al\nindex 3449fe2689..88abec2181 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaMgmt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaMgmt.Codeunit.al\n@@ -2,7 +2,7 @@\n // Copyright (c) Microsoft Corporation. All rights reserved.\n // Licensed under the MIT License. See License.txt in the project root for license information.\n // ------------------------------------------------------------------------------------------------\n-namespace Microsoft.QualityManagement.Setup.ApplicationAreas;\n+namespace Microsoft.Manufacturing.Subcontracting;\n \n #if not CLEAN29\n using Microsoft.Manufacturing.Setup;\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaSetup.TableExt.al b/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaSetup.TableExt.al\nindex 109321363f..6551dec314 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaSetup.TableExt.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Setup/ApplicationAreas/SubcApplicationAreaSetup.TableExt.al\n@@ -2,7 +2,7 @@\n // Copyright (c) Microsoft Corporation. All rights reserved.\n // Licensed under the MIT License. See License.txt in the project root for license information.\n // ------------------------------------------------------------------------------------------------\n-namespace Microsoft.QualityManagement.Setup.ApplicationAreas;\n+namespace Microsoft.Manufacturing.Subcontracting;\n \n using System.Environment.Configuration;\n \n", "FAIL_TO_PASS": [{"codeunitID": 139990, "functionName": ["ItemLedgerEntriesSubcActionsEnabledWhenSubcontracting", "ItemLedgerEntriesSubcActionsDisabledWhenNotSubcontracting"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingUITest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingUITest.Codeunit.al\nindex 46606182df..c598c8c43c 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingUITest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingUITest.Codeunit.al\n@@ -4,6 +4,7 @@\n // ------------------------------------------------------------------------------------------------\n namespace Microsoft.Manufacturing.Subcontracting.Test;\n \n+using Microsoft.Inventory.Ledger;\n using Microsoft.Inventory.Planning;\n using Microsoft.Inventory.Requisition;\n using Microsoft.Manufacturing.Capacity;\n@@ -588,6 +589,91 @@ codeunit 139990 \"Subc. Subcontracting UI Test\"\n PurchaseOrder.Close();\n end;\n \n+ [Test]\n+ procedure ItemLedgerEntriesSubcActionsDisabledWhenNotSubcontracting()\n+ var\n+ ItemLedgerEntry: Record \"Item Ledger Entry\";\n+ ItemLedgerEntries: TestPage \"Item Ledger Entries\";\n+ begin\n+ // [SCENARIO 638458] Subcontracting actions on Item Ledger Entries are disabled when the entry has no subcontracting production order or purchase order.\n+ Initialize();\n+\n+ // [GIVEN] An Item Ledger Entry that is NOT related to subcontracting (no Subc. Prod. Order No. or Subc. Purch. Order No.)\n+ ItemLedgerEntry.Init();\n+ ItemLedgerEntry.\"Entry No.\" := GetNextItemLedgerEntryNo();\n+ ItemLedgerEntry.\"Item No.\" := 'TEST-ITEM';\n+ ItemLedgerEntry.\"Entry Type\" := ItemLedgerEntry.\"Entry Type\"::Purchase;\n+ ItemLedgerEntry.\"Subc. Prod. Order No.\" := '';\n+ ItemLedgerEntry.\"Subc. Purch. Order No.\" := '';\n+ ItemLedgerEntry.Insert();\n+\n+ // [WHEN] The Item Ledger Entries page is opened for that entry\n+ ItemLedgerEntries.OpenView();\n+ ItemLedgerEntries.GoToRecord(ItemLedgerEntry);\n+\n+ // [THEN] The Production Order action is disabled\n+ Assert.IsFalse(ItemLedgerEntries.\"Production Order\".Enabled(), ILEProdActionsEnabledErr);\n+ // [THEN] The Production Order Routing action is disabled\n+ Assert.IsFalse(ItemLedgerEntries.\"Production Order Routing\".Enabled(), ILEProdActionsEnabledErr);\n+ // [THEN] The Production Order Components action is disabled\n+ Assert.IsFalse(ItemLedgerEntries.\"Production Order Components\".Enabled(), ILEProdActionsEnabledErr);\n+ // [THEN] The Purchase Order action is disabled\n+ Assert.IsFalse(ItemLedgerEntries.\"Purchase Order\".Enabled(), ILEPurchActionsEnabledErr);\n+\n+ ItemLedgerEntries.Close();\n+\n+ // Cleanup\n+ ItemLedgerEntry.Delete();\n+ end;\n+\n+ [Test]\n+ procedure ItemLedgerEntriesSubcActionsEnabledWhenSubcontracting()\n+ var\n+ ItemLedgerEntry: Record \"Item Ledger Entry\";\n+ ItemLedgerEntries: TestPage \"Item Ledger Entries\";\n+ begin\n+ // [SCENARIO 638458] Subcontracting actions on Item Ledger Entries are enabled when the entry is related to a subcontracting production order and purchase order.\n+ Initialize();\n+\n+ // [GIVEN] An Item Ledger Entry that IS related to subcontracting\n+ ItemLedgerEntry.Init();\n+ ItemLedgerEntry.\"Entry No.\" := GetNextItemLedgerEntryNo();\n+ ItemLedgerEntry.\"Item No.\" := 'TEST-ITEM';\n+ ItemLedgerEntry.\"Entry Type\" := ItemLedgerEntry.\"Entry Type\"::Purchase;\n+ ItemLedgerEntry.\"Subc. Prod. Order No.\" := 'PO-SUBC-001';\n+ ItemLedgerEntry.\"Subc. Prod. Order Line No.\" := 10000;\n+ ItemLedgerEntry.\"Subc. Purch. Order No.\" := 'PURCH-SUBC-001';\n+ ItemLedgerEntry.\"Subc. Purch. Order Line No.\" := 10000;\n+ ItemLedgerEntry.Insert();\n+\n+ // [WHEN] The Item Ledger Entries page is opened for that entry\n+ ItemLedgerEntries.OpenView();\n+ ItemLedgerEntries.GoToRecord(ItemLedgerEntry);\n+\n+ // [THEN] The Production Order action is enabled\n+ Assert.IsTrue(ItemLedgerEntries.\"Production Order\".Enabled(), ILEProdActionsNotEnabledErr);\n+ // [THEN] The Production Order Routing action is enabled\n+ Assert.IsTrue(ItemLedgerEntries.\"Production Order Routing\".Enabled(), ILEProdActionsNotEnabledErr);\n+ // [THEN] The Production Order Components action is enabled\n+ Assert.IsTrue(ItemLedgerEntries.\"Production Order Components\".Enabled(), ILEProdActionsNotEnabledErr);\n+ // [THEN] The Purchase Order action is enabled\n+ Assert.IsTrue(ItemLedgerEntries.\"Purchase Order\".Enabled(), ILEPurchActionsNotEnabledErr);\n+\n+ ItemLedgerEntries.Close();\n+\n+ // Cleanup\n+ ItemLedgerEntry.Delete();\n+ end;\n+\n+ local procedure GetNextItemLedgerEntryNo(): Integer\n+ var\n+ ItemLedgerEntry: Record \"Item Ledger Entry\";\n+ begin\n+ if ItemLedgerEntry.FindLast() then\n+ exit(ItemLedgerEntry.\"Entry No.\" + 1);\n+ exit(1);\n+ end;\n+\n var\n Assert: Codeunit Assert;\n LibraryERMCountryData: Codeunit \"Library - ERM Country Data\";\n@@ -602,4 +688,8 @@ codeunit 139990 \"Subc. Subcontracting UI Test\"\n SubcontractingActionsEnabledErr: Label 'Subcontractor Prices action should not be enabled for a non-subcontracting Work Center.';\n SubcontractingActionsNotVisibleErr: Label 'Subcontractor Prices action should be visible for a subcontracting Work Center.';\n SubcontractingActionsNotEnabledErr: Label 'Subcontractor Prices action should be enabled for a subcontracting Work Center.';\n+ ILEProdActionsEnabledErr: Label 'Production actions should not be enabled for a non-subcontracting Item Ledger Entry.';\n+ ILEProdActionsNotEnabledErr: Label 'Production actions should be enabled for a subcontracting Item Ledger Entry.';\n+ ILEPurchActionsEnabledErr: Label 'Purchase Order action should not be enabled for a non-subcontracting Item Ledger Entry.';\n+ ILEPurchActionsNotEnabledErr: Label 'Purchase Order action should be enabled for a subcontracting Item Ledger Entry.';\n }\n\\ No newline at end of file\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8612", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-15T14:26:39Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al\nindex b6de5b5ea0..6a958ce4b4 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcPurchaseOrderCreator.Codeunit.al\n@@ -39,7 +39,6 @@ codeunit 99001557 \"Subc. Purchase Order Creator\"\n PurchOrderCreatedPluralTxt: Label '%1 purchase orders were created.\\\\Do you want to view them?', Comment = '%1 = number of purchase orders created';\n PurchOrderAlreadyCreatedQst: Label 'Purchase orders have already been created.\\\\Do you want to view them?';\n CreationOfSubcontractingOrderIsNotAllowedErr: Label 'You cannot create Subcontracting Order, because the Production Order %1 is not released.', Comment = '%1=Production Order No.';\n- NoProdOrderLineWithRemQtyErr: Label 'No Prod. Order Line with Remaining Quantity.';\n BlankLocationConfirmQst: Label 'One or more Prod. Order Components with Component Supply Method Transfer to Vendor have a blank Location Code. Without a Location Code, you will not be able to create a transfer order to send the components to the subcontractor.\\\\Do you want to create the Subcontracting Order anyway?';\n SameAsSubcLocConfirmQst: Label 'One or more Prod. Order Components with Component Supply Method Transfer to Vendor have Location Code %1, which is the same as the Subcontracting Location Code of vendor %2. A transfer order cannot be created from and to the same location.\\\\Do you want to create the Subcontracting Order anyway?', Comment = '%1=Component Location Code, %2=Vendor No.';\n NotEnoughSpaceErr: Label 'There is not enough space to insert the subcontracting info line.';\n@@ -61,7 +60,8 @@ codeunit 99001557 \"Subc. Purchase Order Creator\"\n ManufacturingSetup.TestField(\"Subcontracting Template Name\");\n ManufacturingSetup.TestField(\"Subcontracting Batch Name\");\n \n- CheckProdOrderRtngLine(ProdOrderRoutingLine, ProdOrderLine);\n+ if not CheckProdOrderRtngLine(ProdOrderRoutingLine, ProdOrderLine) then\n+ exit(0);\n \n if not CheckProdOrderComponentLines(ProdOrderRoutingLine) then\n exit;\n@@ -259,7 +259,7 @@ codeunit 99001557 \"Subc. Purchase Order Creator\"\n Clear(RoutingReferenceNo);\n end;\n \n- local procedure CheckProdOrderRtngLine(ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; var ProdOrderLine: Record \"Prod. Order Line\")\n+ local procedure CheckProdOrderRtngLine(ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"; var ProdOrderLine: Record \"Prod. Order Line\"): Boolean\n var\n WorkCenter: Record \"Work Center\";\n begin\n@@ -273,12 +273,13 @@ codeunit 99001557 \"Subc. Purchase Order Creator\"\n ProdOrderLine.SetRange(\"Routing Reference No.\", ProdOrderRoutingLine.\"Routing Reference No.\");\n ProdOrderLine.SetFilter(\"Remaining Quantity\", '<>%1', 0);\n if ProdOrderLine.IsEmpty() then\n- Error(NoProdOrderLineWithRemQtyErr);\n+ exit(false);\n \n WorkCenter.SetLoadFields(\"Gen. Prod. Posting Group\", \"Subcontractor No.\");\n WorkCenter.Get(ProdOrderRoutingLine.\"Work Center No.\");\n WorkCenter.TestField(\"Subcontractor No.\");\n WorkCenter.TestField(\"Gen. Prod. Posting Group\");\n+ exit(true);\n end;\n \n internal procedure ShowExistingPurchaseOrdersForRoutingLines(var ProdOrderRoutingLine: Record \"Prod. Order Routing Line\")\n", "FAIL_TO_PASS": [{"codeunitID": 139989, "functionName": ["ShowExistingPurchOrdersAfterReceiptDoesNotError"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\nindex 950c628cf5..c2ad504090 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcSubcontractingTest.Codeunit.al\n@@ -2774,6 +2774,50 @@ codeunit 139989 \"Subc. Subcontracting Test\"\n Assert.IsFalse(PurchaseOrderPageOpened, 'Purchase Order card should not open when purchase orders already exist.');\n end;\n \n+ [Test]\n+ [HandlerFunctions('ConfirmYesShowSubcontractingPurchOrders,HandlePurchaseOrderPage,HandlePurchaseLinesPage')]\n+ procedure ShowExistingPurchOrdersAfterReceiptDoesNotError()\n+ var\n+ Item: Record Item;\n+ MachineCenter: array[2] of Record \"Machine Center\";\n+ ProductionOrder: Record \"Production Order\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ begin\n+ // [SCENARIO 637777] Re-running Create Subcontracting Order after fully receiving the existing subcontracting purchase order should offer to view the existing order instead of raising \"No Prod. Order Line with Remaining Quantity.\"\n+\n+ // [GIVEN] Manufacturing setup with subcontracting work center, item with routing/BOM, released production order, and a created subcontracting purchase order\n+ Initialize();\n+ Subcontracting := true;\n+ UnitCostCalculation := UnitCostCalculation::Units;\n+ CreateAndCalculateNeededWorkAndMachineCenter(WorkCenter, MachineCenter);\n+ CreateItemForProductionIncludeRoutingAndProdBOM(Item, WorkCenter, MachineCenter);\n+ SubcontractingMgmtLibrary.CreateAndRefreshProductionOrder(\n+ ProductionOrder, \"Production Order Status\"::Released, ProductionOrder.\"Source Type\"::Item, Item.\"No.\", LibraryRandom.RandInt(10) + 5);\n+ UpdateSubMgmtSetupWithReqWkshTemplate();\n+ SubcontractingMgmtLibrary.CreateSubcontractingOrderFromProdOrderRtngPage(Item.\"Routing No.\", WorkCenter[2].\"No.\");\n+\n+ PurchaseLine.SetRange(\"Document Type\", PurchaseLine.\"Document Type\"::Order);\n+ PurchaseLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+#pragma warning disable AA0210\n+ PurchaseLine.SetRange(\"Work Center No.\", WorkCenter[2].\"No.\");\n+#pragma warning restore AA0210\n+ PurchaseLine.FindFirst();\n+ PurchaseHeader.Get(PurchaseLine.\"Document Type\", PurchaseLine.\"Document No.\");\n+ EnsureGeneralPostingSetupIsValid(PurchaseLine.\"Gen. Bus. Posting Group\", PurchaseLine.\"Gen. Prod. Posting Group\");\n+\n+ // [GIVEN] The existing subcontracting purchase order is fully received\n+ LibraryPurchase.PostPurchaseDocument(PurchaseHeader, true, false);\n+\n+ // [WHEN] Create Subcontracting Order is invoked again from the same routing line\n+ PurchaseLinesPageOpened := false;\n+ SubcontractingMgmtLibrary.CreateSubcontractingOrderFromProdOrderRtngPage(Item.\"Routing No.\", WorkCenter[2].\"No.\");\n+\n+ // [THEN] The existing purchase lines are shown and no raw remaining-quantity error is raised\n+ Assert.IsTrue(PurchaseLinesPageOpened, 'Purchase Lines list should open when the subcontracting purchase order already exists after full receipt.');\n+ end;\n+\n [Test]\n procedure StandardTaskCodePropagatedAndDrivesSubcPriceLookup()\n var\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8600", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-12T15:07:44Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Subcontracting\\App", "src\\Apps\\W1\\Subcontracting\\Test"], "patch": "diff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderCompExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderCompExt.Codeunit.al\nindex 3d906b1720..bb2d4555e8 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderCompExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderCompExt.Codeunit.al\n@@ -25,6 +25,8 @@ codeunit 99001524 \"Subc. Prod. Order Comp. Ext.\"\n ExistingPurchLineErr: Label 'You cannot change this field because the component is already assigned to subcontracting purchase order %1.\\\\Updating the quantity is only allowed through the purchase order.', Comment = '%1=Document No';\n ExistingTransferLineQst: Label 'The component has already been assigned to the subcontracting transfer order %1.\\\\The quantity may only be updated via the purchase order and processing of the stock transfer.', Comment = '%1=Transfer Order No';\n ExistingTransferLineErr: Label 'You cannot open Tracking Specification because this component is already specified in Transfer Order %1.', Comment = '%1=Document No.';\n+ CannotModifyCompTransferExistsErr: Label 'You cannot change this component because transfer orders exist for the linked production order %1, purchase order %2.', Comment = '%1=Production Order No., %2=Purchase Order No.';\n+ CannotModifyCompStockAtSubcErr: Label 'You cannot change this component because there are remaining components or WIP items transferred to the subcontractor for production order %1, purchase order %2.', Comment = '%1=Production Order No., %2=Purchase Order No.';\n \n [EventSubscriber(ObjectType::Codeunit, Codeunit::\"Prod. Order Comp.-Reserve\", OnAfterInitFromProdOrderComp, '', false, false)]\n local procedure OnAfterInitFromProdOrderComp(ProdOrderComponent: Record \"Prod. Order Component\")\n@@ -92,6 +94,65 @@ codeunit 99001524 \"Subc. Prod. Order Comp. Ext.\"\n if Rec.IsTemporary then\n exit;\n CheckExistingSubcontractingTransferOrder(Rec, xRec, CurrFieldNo);\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Location Code\" <> xRec.\"Location Code\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Bin Code\", false, false)]\n+ local procedure OnBeforeValidateBinCode(var Rec: Record \"Prod. Order Component\"; var xRec: Record \"Prod. Order Component\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Bin Code\" <> xRec.\"Bin Code\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Item No.\", false, false)]\n+ local procedure OnBeforeValidateItemNo(var Rec: Record \"Prod. Order Component\"; var xRec: Record \"Prod. Order Component\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Item No.\" <> xRec.\"Item No.\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Variant Code\", false, false)]\n+ local procedure OnBeforeValidateVariantCode(var Rec: Record \"Prod. Order Component\"; var xRec: Record \"Prod. Order Component\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Variant Code\" <> xRec.\"Variant Code\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n end;\n \n [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Quantity per\", false, false)]\n@@ -106,6 +167,65 @@ codeunit 99001524 \"Subc. Prod. Order Comp. Ext.\"\n if Rec.IsTemporary then\n exit;\n CheckExistingDocumentsForSubcontracting(Rec, xRec, CurrFieldNo);\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Quantity per\" <> xRec.\"Quantity per\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Expected Quantity\", false, false)]\n+ local procedure OnBeforeValidateExpectedQuantity(var Rec: Record \"Prod. Order Component\"; var xRec: Record \"Prod. Order Component\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Expected Quantity\" <> xRec.\"Expected Quantity\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeValidateEvent, \"Component Supply Method\", false, false)]\n+ local procedure OnBeforeValidateComponentSupplyMethod(var Rec: Record \"Prod. Order Component\"; var xRec: Record \"Prod. Order Component\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if Rec.\"Component Supply Method\" <> xRec.\"Component Supply Method\" then\n+ if xRec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Component\", OnBeforeDeleteEvent, '', false, false)]\n+ local procedure OnBeforeDeleteProdOrderComponent(var Rec: Record \"Prod. Order Component\"; RunTrigger: Boolean)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+ if not RunTrigger then\n+ exit;\n+\n+ if Rec.\"Component Supply Method\" = Rec.\"Component Supply Method\"::\"Transfer to Vendor\" then\n+ CheckUncompletedSubcontractingDocumentsExist(Rec);\n end;\n \n local procedure CheckExistingPostedSubcontractingTransferOrder(ProdOrderComponent: Record \"Prod. Order Component\"): Boolean\n@@ -364,4 +484,66 @@ codeunit 99001524 \"Subc. Prod. Order Comp. Ext.\"\n CheckExistingSubcontractingPurchaseOrder(ProdOrderComponent);\n end;\n end;\n+\n+ local procedure CheckUncompletedSubcontractingDocumentsExist(ProdOrderComponent: Record \"Prod. Order Component\")\n+ var\n+ ProdOrderLine: Record \"Prod. Order Line\";\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ begin\n+ ProdOrderLine.SetLoadFields(\"Routing Reference No.\", \"Routing No.\");\n+ if not ProdOrderLine.Get(ProdOrderComponent.Status, ProdOrderComponent.\"Prod. Order No.\", ProdOrderComponent.\"Prod. Order Line No.\") then\n+ exit;\n+\n+ PurchaseLine.SetCurrentKey(\"Document Type\", Type, \"Prod. Order No.\", \"Prod. Order Line No.\");\n+ PurchaseLine.SetRange(\"Document Type\", PurchaseLine.\"Document Type\"::Order);\n+ PurchaseLine.SetRange(\"Prod. Order No.\", ProdOrderComponent.\"Prod. Order No.\");\n+ PurchaseLine.SetRange(\"Prod. Order Line No.\", ProdOrderComponent.\"Prod. Order Line No.\");\n+\n+ if ProdOrderComponent.\"Routing Link Code\" <> '' then begin\n+ ProdOrderRoutingLine.SetRange(Status, ProdOrderLine.Status);\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProdOrderLine.\"Prod. Order No.\");\n+ ProdOrderRoutingLine.SetRange(\"Routing Reference No.\", ProdOrderLine.\"Routing Reference No.\");\n+ ProdOrderRoutingLine.SetRange(\"Routing Link Code\", ProdOrderComponent.\"Routing Link Code\");\n+ ProdOrderRoutingLine.SetLoadFields(\"Operation No.\");\n+ if ProdOrderRoutingLine.FindFirst() then\n+ PurchaseLine.SetRange(\"Operation No.\", ProdOrderRoutingLine.\"Operation No.\");\n+ end;\n+\n+ if PurchaseLine.FindSet() then\n+ repeat\n+ if HasSubcTransferForPurchLine(PurchaseLine, ProdOrderComponent) then\n+ Error(CannotModifyCompTransferExistsErr, PurchaseLine.\"Prod. Order No.\", PurchaseLine.\"Document No.\");\n+\n+ ProdOrderComponent.SetRange(\"Subc. Purchase Order Filter\", PurchaseLine.\"Document No.\");\n+ if HasStockAtSubcLocationForComponentForPurchLine(ProdOrderComponent) then\n+ Error(CannotModifyCompStockAtSubcErr, PurchaseLine.\"Prod. Order No.\", PurchaseLine.\"Document No.\");\n+ until PurchaseLine.Next() = 0;\n+ end;\n+\n+ local procedure HasSubcTransferForPurchLine(PurchaseLine: Record \"Purchase Line\"; ProdOrderComponent: Record \"Prod. Order Component\"): Boolean\n+ var\n+ TransferLine: Record \"Transfer Line\";\n+ begin\n+ TransferLine.SetCurrentKey(\"Subc. Purch. Order No.\", \"Subc. Prod. Order No.\", \"Subc. Prod. Order Line No.\", \"Subc. Operation No.\");\n+ TransferLine.SetRange(\"Subc. Purch. Order No.\", PurchaseLine.\"Document No.\");\n+ TransferLine.SetRange(\"Subc. Prod. Order No.\", ProdOrderComponent.\"Prod. Order No.\");\n+ TransferLine.SetRange(\"Subc. Prod. Order Line No.\", ProdOrderComponent.\"Prod. Order Line No.\");\n+ TransferLine.SetRange(\"Subc. Prod. Ord. Comp Line No.\", ProdOrderComponent.\"Line No.\");\n+ exit(not TransferLine.IsEmpty());\n+ end;\n+\n+ local procedure HasStockAtSubcLocationForComponentForPurchLine(ProdOrderComponent: Record \"Prod. Order Component\"): Boolean\n+ var\n+ SubcTransferManagement: Codeunit \"Subc. Transfer Management\";\n+ NetStockAtSubcLocation: Decimal;\n+ begin\n+ ProdOrderComponent.CalcFields(\"Subc. Qty. transf. to Subcontr\");\n+ if ProdOrderComponent.\"Subc. Qty. transf. to Subcontr\" = 0 then\n+ exit(false);\n+\n+ NetStockAtSubcLocation := ProdOrderComponent.\"Subc. Qty. transf. to Subcontr\";\n+ NetStockAtSubcLocation -= SubcTransferManagement.CalcConsumedQtyAtSubcLocation(ProdOrderComponent);\n+ exit(NetStockAtSubcLocation > 0);\n+ end;\n }\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderRtngExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderRtngExt.Codeunit.al\nindex e7e85257d3..0c886fc5ec 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderRtngExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcProdOrderRtngExt.Codeunit.al\n@@ -1,22 +1,45 @@\n-// ------------------------------------------------------------------------------------------------\n+// ------------------------------------------------------------------------------------------------\n // Copyright (c) Microsoft Corporation. All rights reserved.\n // Licensed under the MIT License. See License.txt in the project root for license information.\n // ------------------------------------------------------------------------------------------------\n namespace Microsoft.Manufacturing.Subcontracting;\n \n+using Microsoft.Inventory.Transfer;\n using Microsoft.Manufacturing.Document;\n using Microsoft.Manufacturing.Routing;\n using Microsoft.Manufacturing.WorkCenter;\n+using Microsoft.Purchases.Document;\n \n codeunit 99001520 \"Subc. Prod. Order Rtng. Ext.\"\n {\n-#if not CLEAN29\n var\n+#if not CLEAN29\n #pragma warning disable AL0432\n SubcFeatureFlagHandler: Codeunit \"Subc. Feature Flag Handler\";\n #pragma warning restore AL0432\n+#endif\n+ CannotModifyRtngLineTransferExistsErr: Label 'You cannot change this routing line because transfer orders exist for the linked production order %1, purchase order %2.', Comment = '%1=Production Order No., %2=Purchase Order No.';\n+ CannotModifyRtngLineStockAtSubcErr: Label 'You cannot change this routing line because there are remaining components or WIP items transferred to the subcontractor for production order %1, purchase order %2.', Comment = '%1=Production Order No., %2=Purchase Order No.';\n \n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnBeforeDeleteEvent, '', false, false)]\n+ local procedure OnBeforeDeleteProdOrderRtngLine(var Rec: Record \"Prod. Order Routing Line\"; RunTrigger: Boolean)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n #endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if not RunTrigger then\n+ exit;\n+\n+ if Rec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(Rec);\n+ end;\n+\n [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnAfterDeleteEvent, '', false, false)]\n local procedure OnAfterDeleteProdOrderRtngLine(var Rec: Record \"Prod. Order Routing Line\"; RunTrigger: Boolean)\n begin\n@@ -49,10 +72,82 @@ codeunit 99001520 \"Subc. Prod. Order Rtng. Ext.\"\n if Rec.IsTemporary then\n exit;\n \n+ if CurrFieldNo <> 0 then\n+ if (xRec.\"No.\" <> Rec.\"No.\") and xRec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(xRec);\n+\n if (xRec.\"No.\" <> Rec.\"No.\") and (Rec.\"Routing Link Code\" <> '') then\n SubcontractingManagement.UpdLinkedComponents(Rec, true);\n end;\n \n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnBeforeValidateEvent, \"Operation No.\", false, false)]\n+ local procedure OnBeforeValidateOperationNo(var Rec: Record \"Prod. Order Routing Line\"; var xRec: Record \"Prod. Order Routing Line\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if (xRec.\"Operation No.\" <> Rec.\"Operation No.\") and xRec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnBeforeValidateEvent, \"Routing Link Code\", false, false)]\n+ local procedure OnBeforeValidateRoutingLinkCode(var Rec: Record \"Prod. Order Routing Line\"; var xRec: Record \"Prod. Order Routing Line\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if (xRec.\"Routing Link Code\" <> Rec.\"Routing Link Code\") and xRec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnBeforeValidateEvent, \"Type\", false, false)]\n+ local procedure OnBeforeValidateType(var Rec: Record \"Prod. Order Routing Line\"; var xRec: Record \"Prod. Order Routing Line\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if (xRec.Type <> Rec.Type) and xRec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(xRec);\n+ end;\n+\n+ [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnBeforeValidateEvent, \"Transfer WIP Item\", false, false)]\n+ local procedure OnBeforeValidateTransferWIPItem(var Rec: Record \"Prod. Order Routing Line\"; var xRec: Record \"Prod. Order Routing Line\"; CurrFieldNo: Integer)\n+ begin\n+#if not CLEAN29\n+#pragma warning disable AL0432\n+ if not SubcFeatureFlagHandler.IsSubcontractingEnabled() then\n+#pragma warning restore AL0432\n+ exit;\n+#endif\n+ if Rec.IsTemporary then\n+ exit;\n+\n+ if CurrFieldNo <> 0 then\n+ if (xRec.\"Transfer WIP Item\" <> Rec.\"Transfer WIP Item\") and xRec.\"Transfer WIP Item\" then\n+ CheckSubcRtngLineDocumentsExist(xRec);\n+ end;\n+\n [EventSubscriber(ObjectType::Table, Database::\"Prod. Order Routing Line\", OnAfterValidateEvent, \"Routing Link Code\", false, false)]\n local procedure OnAfterValidateRoutingLinkCode(var Rec: Record \"Prod. Order Routing Line\"; var xRec: Record \"Prod. Order Routing Line\"; CurrFieldNo: Integer)\n begin\n@@ -150,4 +245,73 @@ codeunit 99001520 \"Subc. Prod. Order Rtng. Ext.\"\n SubcontractingManagement.DelLocationLinkedComponents(ProdOrderRoutingLine, false);\n end;\n end;\n-}\n\\ No newline at end of file\n+\n+ local procedure CheckSubcRtngLineDocumentsExist(ProdOrderRoutingLine: Record \"Prod. Order Routing Line\")\n+ var\n+ PurchaseLine: Record \"Purchase Line\";\n+ begin\n+ PurchaseLine.SetCurrentKey(\"Document Type\", Type, \"Prod. Order No.\", \"Prod. Order Line No.\");\n+ PurchaseLine.SetRange(\"Document Type\", PurchaseLine.\"Document Type\"::Order);\n+ PurchaseLine.SetRange(\"Prod. Order No.\", ProdOrderRoutingLine.\"Prod. Order No.\");\n+ PurchaseLine.SetRange(\"Routing No.\", ProdOrderRoutingLine.\"Routing No.\");\n+ PurchaseLine.SetRange(\"Routing Reference No.\", ProdOrderRoutingLine.\"Routing Reference No.\");\n+ PurchaseLine.SetRange(\"Operation No.\", ProdOrderRoutingLine.\"Operation No.\");\n+ if PurchaseLine.FindSet() then\n+ repeat\n+ if HasSubcTransferForPurchLine(PurchaseLine) then\n+ Error(CannotModifyRtngLineTransferExistsErr, PurchaseLine.\"Prod. Order No.\", PurchaseLine.\"Document No.\");\n+ if HasStockAtSubcLocation(PurchaseLine, ProdOrderRoutingLine) then\n+ Error(CannotModifyRtngLineStockAtSubcErr, PurchaseLine.\"Prod. Order No.\", PurchaseLine.\"Document No.\");\n+ until PurchaseLine.Next() = 0;\n+ end;\n+\n+ local procedure HasSubcTransferForPurchLine(PurchaseLine: Record \"Purchase Line\"): Boolean\n+ var\n+ TransferLine: Record \"Transfer Line\";\n+ begin\n+ TransferLine.SetRange(\"Subc. Purch. Order No.\", PurchaseLine.\"Document No.\");\n+ TransferLine.SetRange(\"Subc. Purch. Order Line No.\", PurchaseLine.\"Line No.\");\n+ TransferLine.SetRange(\"Subc. Prod. Order No.\", PurchaseLine.\"Prod. Order No.\");\n+ exit(not TransferLine.IsEmpty());\n+ end;\n+\n+ local procedure HasStockAtSubcLocation(PurchaseLine: Record \"Purchase Line\"; ProdOrderRoutingLine: Record \"Prod. Order Routing Line\"): Boolean\n+ var\n+ ProdOrderComponent: Record \"Prod. Order Component\";\n+ SubcWIPLedgerEntry: Record \"Subcontractor WIP Ledger Entry\";\n+ SubcTransferManagement: Codeunit \"Subc. Transfer Management\";\n+ NetStockAtSubcLocation: Decimal;\n+ begin\n+ ProdOrderComponent.SetCurrentKey(Status, \"Prod. Order No.\", \"Routing Link Code\");\n+ ProdOrderComponent.SetRange(Status, \"Production Order Status\"::Released);\n+ ProdOrderComponent.SetRange(\"Prod. Order No.\", PurchaseLine.\"Prod. Order No.\");\n+ ProdOrderComponent.SetRange(\"Prod. Order Line No.\", PurchaseLine.\"Prod. Order Line No.\");\n+ ProdOrderComponent.SetRange(\"Component Supply Method\", ProdOrderComponent.\"Component Supply Method\"::\"Transfer to Vendor\");\n+ ProdOrderComponent.SetRange(\"Subc. Purchase Order Filter\", PurchaseLine.\"Document No.\");\n+ ProdOrderComponent.SetRange(\"Routing Link Code\", ProdOrderRoutingLine.\"Routing Link Code\");\n+ ProdOrderComponent.SetAutoCalcFields(\"Subc. Qty. transf. to Subcontr\");\n+ if ProdOrderComponent.FindSet() then\n+ repeat\n+ if ProdOrderComponent.\"Subc. Qty. transf. to Subcontr\" <> 0 then begin\n+ NetStockAtSubcLocation := ProdOrderComponent.\"Subc. Qty. transf. to Subcontr\";\n+ NetStockAtSubcLocation -= SubcTransferManagement.CalcConsumedQtyAtSubcLocation(ProdOrderComponent);\n+ if NetStockAtSubcLocation > 0 then\n+ exit(true);\n+ end;\n+ until ProdOrderComponent.Next() = 0;\n+\n+ SubcWIPLedgerEntry.SetCurrentKey(\"Prod. Order No.\", \"Prod. Order Status\", \"Prod. Order Line No.\", \"Routing Reference No.\", \"Routing No.\", \"Operation No.\", \"Location Code\");\n+ SubcWIPLedgerEntry.SetRange(\"Prod. Order No.\", PurchaseLine.\"Prod. Order No.\");\n+ SubcWIPLedgerEntry.SetRange(\"Prod. Order Status\", \"Production Order Status\"::Released);\n+ SubcWIPLedgerEntry.SetRange(\"Prod. Order Line No.\", PurchaseLine.\"Prod. Order Line No.\");\n+ SubcWIPLedgerEntry.SetRange(\"Routing Reference No.\", ProdOrderRoutingLine.\"Routing Reference No.\");\n+ SubcWIPLedgerEntry.SetRange(\"Routing No.\", ProdOrderRoutingLine.\"Routing No.\");\n+ SubcWIPLedgerEntry.SetRange(\"Operation No.\", ProdOrderRoutingLine.\"Operation No.\");\n+ SubcWIPLedgerEntry.SetRange(\"In Transit\", false);\n+ SubcWIPLedgerEntry.CalcSums(\"Quantity (Base)\");\n+ if SubcWIPLedgerEntry.\"Quantity (Base)\" <> 0 then\n+ exit(true);\n+\n+ exit(false);\n+ end;\n+}\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcReqWkshMakeOrd.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcReqWkshMakeOrd.Codeunit.al\nindex 40d3598456..41e67eba1c 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcReqWkshMakeOrd.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Manufacturing/SubcReqWkshMakeOrd.Codeunit.al\n@@ -104,6 +104,7 @@ codeunit 99001516 \"Subc. Req. Wksh. Make Ord.\"\n ProdOrderComponent.SetRange(\"Prod. Order Line No.\", RequisitionLine.\"Prod. Order Line No.\");\n ProdOrderComponent.SetRange(\"Routing Link Code\", ProdOrderRoutingLine.\"Routing Link Code\");\n ProdOrderComponent.SetRange(\"Component Supply Method\", \"Component Supply Method\"::\"Vendor-Supplied\");\n+ ProdOrderComponent.SetLoadFields(\"Item No.\", \"Variant Code\", \"Remaining Quantity\");\n if ProdOrderComponent.FindSet() then\n repeat\n PurchaseLineComp.SetRange(\"Document Type\", PurchaseLine.\"Document Type\");\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchaseLineExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchaseLineExt.Codeunit.al\nindex c84eace729..e90d3f7160 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchaseLineExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Purchase/SubcPurchaseLineExt.Codeunit.al\n@@ -134,7 +134,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(Quantity) then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.Quantity = xRec.Quantity then\n@@ -160,7 +160,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"No.\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"No.\" = xRec.\"No.\" then\n@@ -186,7 +186,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Location Code\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Location Code\" = xRec.\"Location Code\" then\n@@ -212,7 +212,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Bin Code\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Bin Code\" = xRec.\"Bin Code\" then\n@@ -238,7 +238,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Variant Code\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Variant Code\" = xRec.\"Variant Code\" then\n@@ -264,7 +264,7 @@ codeunit 99001534 \"Subc. Purchase Line Ext\"\n if Rec.\"Prod. Order No.\" = '' then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Unit of Measure Code\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Unit of Measure Code\" = xRec.\"Unit of Measure Code\" then\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Transfer/SubcTransferLineExt.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Transfer/SubcTransferLineExt.Codeunit.al\nindex 11e9867475..0918e43ef0 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Transfer/SubcTransferLineExt.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/Extensions/Transfer/SubcTransferLineExt.Codeunit.al\n@@ -62,7 +62,7 @@ codeunit 99001544 \"Subc. Transfer Line Ext.\"\n if Rec.IsTemporary() then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Item No.\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Item No.\" = xRec.\"Item No.\" then\n@@ -85,7 +85,7 @@ codeunit 99001544 \"Subc. Transfer Line Ext.\"\n if Rec.IsTemporary() then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(\"Variant Code\") then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.\"Variant Code\" = xRec.\"Variant Code\" then\n@@ -108,7 +108,7 @@ codeunit 99001544 \"Subc. Transfer Line Ext.\"\n if Rec.IsTemporary() then\n exit;\n \n- if CurrFieldNo <> Rec.FieldNo(Quantity) then\n+ if CurrFieldNo = 0 then\n exit;\n \n if Rec.Quantity = xRec.Quantity then\ndiff --git a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcTransferManagement.Codeunit.al b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcTransferManagement.Codeunit.al\nindex f6150f7b04..b6246cfb5d 100644\n--- a/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcTransferManagement.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/App/src/Process/Codeunits/SubcTransferManagement.Codeunit.al\n@@ -389,6 +389,7 @@ codeunit 99001504 \"Subc. Transfer Management\"\n ProdOrderComponent.SetRange(\"Subc. Purchase Order Filter\", PurchaseLine.\"Document No.\");\n ProdOrderComponent.SetRange(\"Routing Link Code\", ProdOrderRoutingLine.\"Routing Link Code\");\n ProdOrderComponent.SetRange(\"Component Supply Method\", ProdOrderComponent.\"Component Supply Method\"::\"Transfer to Vendor\");\n+ ProdOrderComponent.SetLoadFields(\"Subc. Qty. transf. to Subcontr\", \"Location Code\");\n ProdOrderComponent.SetAutoCalcFields(\"Subc. Qty. transf. to Subcontr\");\n if ProdOrderComponent.FindSet() then\n repeat\n@@ -407,7 +408,6 @@ codeunit 99001504 \"Subc. Transfer Management\"\n SubcWIPLedgerEntry.SetRange(\"Routing Reference No.\", PurchaseLine.\"Routing Reference No.\");\n SubcWIPLedgerEntry.SetRange(\"Routing No.\", PurchaseLine.\"Routing No.\");\n SubcWIPLedgerEntry.SetRange(\"Operation No.\", PurchaseLine.\"Operation No.\");\n-\n SubcWIPLedgerEntry.SetRange(\"In Transit\", false);\n SubcWIPLedgerEntry.CalcSums(\"Quantity (Base)\");\n if SubcWIPLedgerEntry.\"Quantity (Base)\" <> 0 then\n@@ -427,6 +427,7 @@ codeunit 99001504 \"Subc. Transfer Management\"\n ItemLedgerEntry.SetRange(\"Entry Type\", ItemLedgerEntry.\"Entry Type\"::Consumption);\n ItemLedgerEntry.SetRange(\"Prod. Order Comp. Line No.\", ProdOrderComponent.\"Line No.\");\n ItemLedgerEntry.SetRange(\"Location Code\", ProdOrderComponent.\"Location Code\");\n+ ItemLedgerEntry.SetLoadFields(Quantity);\n ItemLedgerEntry.CalcSums(Quantity);\n exit(-ItemLedgerEntry.Quantity);\n end;\n", "FAIL_TO_PASS": [{"codeunitID": 139991, "functionName": ["CannotModifyOrDeleteRoutingLineWhenTransferOrderExistsWithTransferToVendor", "CannotModifyOrDeleteRoutingLineWhenTransferOrderExistsWithVendorSupplied"]}, {"codeunitID": 149915, "functionName": ["CannotModifyOrDeleteProdOrderComponentWhenTransferOrderExists"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al\nindex f07c0afb34..0f6b7901b3 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcPurchSubcontTest.Codeunit.al\n@@ -510,6 +510,118 @@ codeunit 139991 \"Subc. Purch. Subcont. Test\"\n PostDirectTransferOrder(ReturnTransferHeader);\n end;\n \n+ [Test]\n+ [HandlerFunctions('DoConfirmCreateProdOrderForSubcontractingProcess,HandleTransferOrder')]\n+ procedure CannotModifyOrDeleteRoutingLineWhenTransferOrderExistsWithTransferToVendor()\n+ var\n+ Item: Record Item;\n+ HomeLocation: Record Location;\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ ProductionOrder: Record \"Production Order\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ MachineCenter: array[2] of Record \"Machine Center\";\n+ ProdOrderRtng: TestPage \"Prod. Order Routing\";\n+ begin\n+ // [SCENARIO] Modifying key fields or deleting a Prod. Order Routing Line must be blocked\n+ // when subcontracting transfer orders exist for Transfer to Vendor components.\n+ Initialize();\n+\n+ // [GIVEN] A subcontracting purchase order with a linked transfer order\n+ SetupSubContractingProdOrder(Item, HomeLocation, WorkCenter, MachineCenter, ProductionOrder, \"Component Supply Method\"::\"Transfer to Vendor\", LibraryRandom.RandIntInRange(1, 10));\n+ CreateSubcontractingPurchaseOrderForProdOrder(PurchaseHeader, PurchaseLine, Item, WorkCenter, ProductionOrder);\n+ CreateTransferOrderForPurchaseOrder(PurchaseHeader);\n+\n+ // [GIVEN] Find routing line for the subcontracting work center\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+#pragma warning disable AA0210\n+ ProdOrderRoutingLine.SetRange(\"Transfer WIP Item\", true);\n+#pragma warning restore AA0210\n+ ProdOrderRoutingLine.FindFirst();\n+\n+ // [THEN] Changing No. is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.\"No.\".SetValue(WorkCenter[1].\"No.\");\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Changing Type is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.Type.SetValue(ProdOrderRoutingLine.Type::\"Machine Center\");\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Changing Routing Link Code is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.\"Routing Link Code\".SetValue('');\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Deleting the routing line is blocked\n+ asserterror ProdOrderRoutingLine.Delete(true);\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ end;\n+\n+ [Test]\n+ [HandlerFunctions('DoConfirmCreateProdOrderForSubcontractingProcess,HandleTransferOrder')]\n+ procedure CannotModifyOrDeleteRoutingLineWhenTransferOrderExistsWithVendorSupplied()\n+ var\n+ Item: Record Item;\n+ HomeLocation: Record Location;\n+ ProdOrderRoutingLine: Record \"Prod. Order Routing Line\";\n+ ProductionOrder: Record \"Production Order\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ MachineCenter: array[2] of Record \"Machine Center\";\n+ ProdOrderRtng: TestPage \"Prod. Order Routing\";\n+ begin\n+ // [SCENARIO] Modifying key fields or deleting a Prod. Order Routing Line must be blocked\n+ // when subcontracting transfer orders exist for Transfer to Vendor components.\n+ Initialize();\n+\n+ // [GIVEN] A subcontracting purchase order with a linked transfer order\n+ SetupSubContractingProdOrder(Item, HomeLocation, WorkCenter, MachineCenter, ProductionOrder, \"Component Supply Method\"::\"Vendor-Supplied\", LibraryRandom.RandIntInRange(1, 10));\n+ CreateSubcontractingPurchaseOrderForProdOrder(PurchaseHeader, PurchaseLine, Item, WorkCenter, ProductionOrder);\n+ CreateTransferOrderForPurchaseOrder(PurchaseHeader);\n+\n+ // [GIVEN] Find routing line for the subcontracting work center\n+ ProdOrderRoutingLine.SetRange(\"Prod. Order No.\", ProductionOrder.\"No.\");\n+#pragma warning disable AA0210\n+ ProdOrderRoutingLine.SetRange(\"Transfer WIP Item\", true);\n+#pragma warning restore AA0210\n+ ProdOrderRoutingLine.FindFirst();\n+\n+ // [THEN] Changing No. is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.\"No.\".SetValue(WorkCenter[1].\"No.\");\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Changing Type is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.Type.SetValue(ProdOrderRoutingLine.Type::\"Machine Center\");\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Changing Routing Link Code is blocked\n+ ProdOrderRtng.OpenEdit();\n+ ProdOrderRtng.GoToRecord(ProdOrderRoutingLine);\n+ asserterror ProdOrderRtng.\"Routing Link Code\".SetValue('');\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ ProdOrderRtng.Close();\n+\n+ // [THEN] Deleting the routing line is blocked\n+ asserterror ProdOrderRoutingLine.Delete(true);\n+ Assert.ExpectedError('You cannot change this routing line because transfer orders exist');\n+ end;\n+\n [ModalPageHandler]\n procedure ItemTrackingLinesSimpleHandler(var ItemTrackingLines: TestPage \"Item Tracking Lines\")\n begin\ndiff --git a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcTransOrdReservTest.Codeunit.al b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcTransOrdReservTest.Codeunit.al\nindex ca4426c340..79a2777217 100644\n--- a/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcTransOrdReservTest.Codeunit.al\n+++ b/src/Apps/W1/Subcontracting/Test/src/Codeunits/Tests/SubcTransOrdReservTest.Codeunit.al\n@@ -341,6 +341,58 @@ codeunit 149915 \"Subc. TransOrd. Reserv. Test\"\n Assert.AreEqual(30, TransferLine.\"Quantity (Base)\", 'Recreated transfer line must have the full component quantity');\n end;\n \n+ [Test]\n+ [HandlerFunctions('DoNotConfirmShowCreatedPurchOrderForSubcontracting,HandleTransferOrder')]\n+ procedure CannotModifyOrDeleteProdOrderComponentWhenTransferOrderExists()\n+ var\n+ Item: Record Item;\n+ NewItem: Record Item;\n+ ProdOrderComponent: Record \"Prod. Order Component\";\n+ ProductionOrder: Record \"Production Order\";\n+ PurchaseHeader: Record \"Purchase Header\";\n+ PurchaseLine: Record \"Purchase Line\";\n+ WorkCenter: array[2] of Record \"Work Center\";\n+ MachineCenter: array[2] of Record \"Machine Center\";\n+ ProdOrderCompPage: TestPage \"Prod. Order Components\";\n+ begin\n+ // [SCENARIO] Modifying key fields or deleting a Prod. Order Component with Component Supply Method = Transfer to Vendor\n+ // must be blocked when a subcontracting transfer order exists.\n+ Initialize();\n+\n+ // [GIVEN] A subcontracting transfer order linked to a production order with Transfer to Vendor components\n+ SetupTransferReservationScenario(Item, WorkCenter, MachineCenter, ProductionOrder, ProdOrderComponent, 10, 3, false);\n+ CreateSubcontractingPurchaseOrderAndReduceQuantity(Item, WorkCenter[2], ProductionOrder, PurchaseHeader, PurchaseLine, 0);\n+ CreateTransferOrder(PurchaseHeader);\n+\n+ // [GIVEN] Create another item to use for Item No. change\n+ LibraryInventory.CreateItem(NewItem);\n+\n+ // [THEN] Changing Item No. is blocked\n+ ProdOrderCompPage.OpenEdit();\n+ ProdOrderCompPage.GoToRecord(ProdOrderComponent);\n+ asserterror ProdOrderCompPage.\"Item No.\".SetValue(NewItem.\"No.\");\n+ Assert.ExpectedError('You cannot change this component because transfer orders exist');\n+ ProdOrderCompPage.Close();\n+\n+ // [THEN] Changing Quantity per is blocked\n+ ProdOrderCompPage.OpenEdit();\n+ ProdOrderCompPage.GoToRecord(ProdOrderComponent);\n+ asserterror ProdOrderCompPage.\"Quantity per\".SetValue(ProdOrderComponent.\"Quantity per\" + 1);\n+ Assert.ExpectedError('You cannot change this component because transfer orders exist');\n+ ProdOrderCompPage.Close();\n+\n+ // [THEN] Changing Component Supply Method is blocked\n+ ProdOrderCompPage.OpenEdit();\n+ ProdOrderCompPage.GoToRecord(ProdOrderComponent);\n+ asserterror ProdOrderCompPage.\"Component Supply Method\".SetValue(\"Component Supply Method\"::Empty);\n+ Assert.ExpectedError('You cannot change this component because transfer orders exist');\n+ ProdOrderCompPage.Close();\n+\n+ // [THEN] Deleting the component is blocked\n+ asserterror ProdOrderComponent.Delete(true);\n+ Assert.ExpectedError('You cannot change this component because transfer orders exist');\n+ end;\n+\n local procedure Initialize()\n begin\n LibraryTestInitialize.OnTestInitialize(Codeunit::\"Subc. TransOrd. Reserv. Test\");\n"} +{"metadata": {"area": null, "image_count": null, "persona": null}, "repo": "microsoft/BCApps", "instance_id": "microsoft__BCApps-8386", "base_commit": "f7a8a18571b1c99a30bad8d749474336f1c8c60a", "created_at": "2026-06-01T09:42:51Z", "environment_setup_version": "28.2", "project_paths": ["src\\Apps\\W1\\Shopify\\App", "src\\Apps\\W1\\Shopify\\Test"], "patch": "diff --git a/src/Apps/W1/Shopify/App/src/Bulk Operations/Codeunits/ShpfyBulkUpdateProductPrice.Codeunit.al b/src/Apps/W1/Shopify/App/src/Bulk Operations/Codeunits/ShpfyBulkUpdateProductPrice.Codeunit.al\nindex b4508e5546..884b8bdd71 100644\n--- a/src/Apps/W1/Shopify/App/src/Bulk Operations/Codeunits/ShpfyBulkUpdateProductPrice.Codeunit.al\n+++ b/src/Apps/W1/Shopify/App/src/Bulk Operations/Codeunits/ShpfyBulkUpdateProductPrice.Codeunit.al\n@@ -88,7 +88,8 @@ codeunit 30281 \"Shpfy Bulk UpdateProductPrice\" implements \"Shpfy IBulk Operation\n ShopifyVariant.Price := JVariant.GetDecimal('price');\n ShopifyVariant.\"Compare at Price\" := JVariant.GetDecimal('compareAtPrice');\n ShopifyVariant.\"Updated At\" := JVariant.GetDateTime('updatedAt');\n- ShopifyVariant.\"Unit Cost\" := JVariant.GetDecimal('unitCost');\n+ if JVariant.Contains('unitCost') then\n+ ShopifyVariant.\"Unit Cost\" := JVariant.GetDecimal('unitCost');\n ShopifyVariant.Modify();\n end;\n end;\ndiff --git a/src/Apps/W1/Shopify/App/src/Products/Codeunits/ShpfyProductExport.Codeunit.al b/src/Apps/W1/Shopify/App/src/Products/Codeunits/ShpfyProductExport.Codeunit.al\nindex cee48d5400..91bcde34a8 100644\n--- a/src/Apps/W1/Shopify/App/src/Products/Codeunits/ShpfyProductExport.Codeunit.al\n+++ b/src/Apps/W1/Shopify/App/src/Products/Codeunits/ShpfyProductExport.Codeunit.al\n@@ -894,7 +894,8 @@ codeunit 30178 \"Shpfy Product Export\"\n ShopifyVariant.Price := JVariant.GetDecimal('price');\n ShopifyVariant.\"Compare at Price\" := JVariant.GetDecimal('compareAtPrice');\n ShopifyVariant.\"Updated At\" := JVariant.GetDateTime('updatedAt');\n- ShopifyVariant.\"Unit Cost\" := JVariant.GetDecimal('unitCost');\n+ if JVariant.Contains('unitCost') then\n+ ShopifyVariant.\"Unit Cost\" := JVariant.GetDecimal('unitCost');\n ShopifyVariant.Modify();\n end;\n exit;\n", "FAIL_TO_PASS": [{"codeunitID": 139633, "functionName": ["TestBulkOperationRevertFailedWithLegacyRequestDataMissingUnitCost"]}], "PASS_TO_PASS": [], "test_patch": "diff --git a/src/Apps/W1/Shopify/Test/Bulk Operations/Codeunits/ShpfyBulkOperationsTest.Codeunit.al b/src/Apps/W1/Shopify/Test/Bulk Operations/Codeunits/ShpfyBulkOperationsTest.Codeunit.al\nindex 86c7a952fd..6a6e049ec0 100644\n--- a/src/Apps/W1/Shopify/Test/Bulk Operations/Codeunits/ShpfyBulkOperationsTest.Codeunit.al\n+++ b/src/Apps/W1/Shopify/Test/Bulk Operations/Codeunits/ShpfyBulkOperationsTest.Codeunit.al\n@@ -314,6 +314,70 @@ codeunit 139633 \"Shpfy Bulk Operations Test\"\n ClearSetup();\n end;\n \n+ [Test]\n+ [HandlerFunctions('BulkOperationHttpHandler')]\n+ procedure TestBulkOperationRevertFailedWithLegacyRequestDataMissingUnitCost()\n+ var\n+ ShopifyVariant: Record \"Shpfy Variant\";\n+ BulkOperation: Record \"Shpfy Bulk Operation\";\n+ BulkOperationType: Enum \"Shpfy Bulk Operation Type\";\n+ ProductId: BigInteger;\n+ VariantId: BigInteger;\n+ VariantIds: List of [BigInteger];\n+ Index: Integer;\n+ begin\n+ // [SCENARIO] A bulk operation persisted before the unitCost key was added still\n+ // completes its revert without throwing, leaving Unit Cost untouched.\n+ // Regression for bug 637250.\n+\n+ // [GIVEN] A bulk operation whose request data was written by the pre-unitCost code\n+ // (i.e. the JSON objects only contain id/price/compareAtPrice/updatedAt) and four variants\n+ Initialize();\n+ for Index := 1 to 4 do begin\n+ ProductId := Any.IntegerInRange(100000, 555555);\n+ VariantId := Any.IntegerInRange(100000, 555555);\n+ VariantIds.Add(VariantId);\n+ ShopifyVariant.\"Product Id\" := ProductId;\n+ ShopifyVariant.Id := VariantId;\n+ ShopifyVariant.Price := 200;\n+ ShopifyVariant.\"Compare at Price\" := 250;\n+ ShopifyVariant.\"Unit Cost\" := 75;\n+ ShopifyVariant.Insert();\n+ end;\n+ BulkOperationUrl := 'https://storage.googleapis.com/shopify-bulk-result/' + Any.AlphabeticText(20);\n+ BulkOperation := CreateBulkOperation(BulkOperationId1, BulkOperationType::UpdateProductPrice, Shop.Code, BulkOperationUrl, GenerateLegacyRequestDataWithoutUnitCost(VariantIds, 100, 150));\n+\n+ // [WHEN] Bulk operation is completed\n+ BulkOperationIdCurrent := BulkOperationId1;\n+ VariantId1 := VariantIds.Get(1);\n+ VariantId2 := VariantIds.Get(4);\n+ BulkOperation.Status := BulkOperation.Status::Completed;\n+ BulkOperation.Modify(true);\n+\n+ // [THEN] The bulk operation is processed without throwing on the missing unitCost key,\n+ // failed variants have their Price/Compare at Price reverted, and Unit Cost is left\n+ // untouched on every variant (since the legacy blob doesn't know the pre-update value).\n+ BulkOperation.Get(BulkOperationId1, Shop.Code, BulkOperation.Type::mutation);\n+ LibraryAssert.IsTrue(BulkOperation.Processed, 'Bulk operation should be processed.');\n+ ShopifyVariant.Get(VariantIds.Get(1));\n+ LibraryAssert.AreEqual(200, ShopifyVariant.Price, 'Variant price should not be reverted.');\n+ LibraryAssert.AreEqual(250, ShopifyVariant.\"Compare at Price\", 'Variant compare at price should not be reverted.');\n+ LibraryAssert.AreEqual(75, ShopifyVariant.\"Unit Cost\", 'Variant unit cost should be left untouched when legacy blob lacks unitCost.');\n+ ShopifyVariant.Get(VariantIds.Get(2));\n+ LibraryAssert.AreEqual(100, ShopifyVariant.Price, 'Variant price should be reverted.');\n+ LibraryAssert.AreEqual(150, ShopifyVariant.\"Compare at Price\", 'Variant compare at price should be reverted.');\n+ LibraryAssert.AreEqual(75, ShopifyVariant.\"Unit Cost\", 'Variant unit cost should be left untouched when legacy blob lacks unitCost.');\n+ ShopifyVariant.Get(VariantIds.Get(3));\n+ LibraryAssert.AreEqual(100, ShopifyVariant.Price, 'Variant price should be reverted.');\n+ LibraryAssert.AreEqual(150, ShopifyVariant.\"Compare at Price\", 'Variant compare at price should be reverted.');\n+ LibraryAssert.AreEqual(75, ShopifyVariant.\"Unit Cost\", 'Variant unit cost should be left untouched when legacy blob lacks unitCost.');\n+ ShopifyVariant.Get(VariantIds.Get(4));\n+ LibraryAssert.AreEqual(200, ShopifyVariant.Price, 'Variant price should not be reverted.');\n+ LibraryAssert.AreEqual(250, ShopifyVariant.\"Compare at Price\", 'Variant compare at price should not be reverted.');\n+ LibraryAssert.AreEqual(75, ShopifyVariant.\"Unit Cost\", 'Variant unit cost should be left untouched when legacy blob lacks unitCost.');\n+ ClearSetup();\n+ end;\n+\n [Test]\n procedure TestBulkUpdateProductPriceClearsCompareAtPriceAsNull()\n var\n@@ -495,6 +559,26 @@ codeunit 139633 \"Shpfy Bulk Operations Test\"\n exit(RequestData);\n end;\n \n+ local procedure GenerateLegacyRequestDataWithoutUnitCost(VariantIds: List of [BigInteger]; Price: Decimal; CompareAtPrice: Decimal): JsonArray\n+ var\n+ RequestData: JsonArray;\n+ VariantId: BigInteger;\n+ Data: JsonObject;\n+ begin\n+ // Simulates the request-data layout written by the connector before the unitCost key\n+ // was added to the bulk-operation rollback bookkeeping. Used to test that the revert\n+ // tolerates legacy blobs persisted before the upgrade.\n+ foreach VariantId in VariantIds do begin\n+ Clear(Data);\n+ Data.Add('id', VariantId);\n+ Data.Add('price', Price);\n+ Data.Add('compareAtPrice', CompareAtPrice);\n+ Data.Add('updatedAt', '2025-02-25T13:40:15.6530000Z');\n+ RequestData.Add(Data);\n+ end;\n+ exit(RequestData);\n+ end;\n+\n local procedure EnqueueGraphQLResponsesForSendBulkMutation()\n begin\n GraphQLResponses.Enqueue('StagedUpload');\n"} diff --git a/dataset/problemstatement/microsoft__BCApps-7831/README.md b/dataset/problemstatement/microsoft__BCApps-7831/README.md new file mode 100644 index 000000000..2a39d36fa --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-7831/README.md @@ -0,0 +1,36 @@ +# Title: [Subcontracting] Standard Task not propagated from Routing to Prod. Order Routing or Subcontracting Worksheet; prices not picked up +## Repro Steps: +![Image](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_apis/wit/attachments/10f744c3-9170-4590-8dd3-cf148b602b4a?fileName=image.png) + +## Hints: +### Repro Steps +**Summary**: The Subcontracting app needs to be aligned with changes made to the "Description 2" field on various tables. The bug description contains inline screenshots showing the field changes but minimal textual detail. + +#### Steps to Reproduce +1. Open Business Central with the Subcontracting module enabled. +2. Identify all tables in the Subcontracting app that reference or use the "Description 2" field (e.g., Item, Production Order Line, Purchase Line, or other related tables). +3. Check that the Subcontracting app properly reads, writes, and displays the "Description 2" field wherever it is used in the base BC application. +4. If "Description 2" has been modified (renamed, repositioned, or had its properties changed) in the base tables, verify that: + - All Subcontracting page extensions show the updated "Description 2" correctly. + - All Subcontracting codeunits that reference "Description 2" are aligned with the new field definition. + - All API queries or pages that expose "Description 2" reflect the changes. +5. Look for compilation errors or runtime issues caused by the misalignment. + +#### Expected Result +- The Subcontracting app should be fully aligned with any changes to the "Description 2" field in the base BC application. +- No compilation errors or data integrity issues related to this field. +- +#### Actual Result +- The Subcontracting app references are not aligned with the "Description 2" field changes, as shown in the inline screenshots. +- +#### Additional Context +- Related to +620425 [Subcontracting] "Single Instance Dictionary" is a very generic name. Rename & refactor it appropriately (SingleInstanceDictionary naming/refactoring). + +#### Self-Review +- The repro steps cover the general alignment concern but specific tables/pages affected are documented in the screenshots only. +- This is a code alignment/compatibility issue following upstream changes. + +**Score: 5/10** - The bug description is primarily screenshots with limited textual context. Steps provide a reasonable framework for verification. + +[AI-REPRO] score=5 | workItemId=620556 | generated=2026-03-25 | sources=Title,Description (inline images) diff --git a/dataset/problemstatement/microsoft__BCApps-8059/README.md b/dataset/problemstatement/microsoft__BCApps-8059/README.md new file mode 100644 index 000000000..6fdaf7b36 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8059/README.md @@ -0,0 +1,38 @@ +# Title: [master][All-e]Peppol E-Invoice cannot be validated when price incl VAT is used in a document +## Repro Steps: +1. Go to Company Information and add a SWIFT Code (you need to created a new one, but it can be any number) +2. Go to E-Document Services and open the E-DOCUMENTS + Document Format should be PEPPOL BIS 3.0 +3. In the E-Document Service use buton "Configure documents to export" and add the sales invoice +4. Go to Electronic Document Formats and make sure you have the setup for PEPPOL BIS3 / Sales Invoice / Codeunit 1610 +5. Go to Workflows and make sure you have the default workflow for "Send E-Documents to one Service" enabled +6. Go to Document Sending Profiles, check E-DOCUMENTS and make sure this uses + Electronic Document = E-Document Workflow + E-Document Workflow = MS-EDOCSTOS-01 (the one from step 5) +7. Open Customer Card 10000 and change the following: + Document Sending Profile = E-DOCUMENTS + VAT Registration No = GB123456789 +8. Create a new Sales Invoice for customer 10000 + Posting / Document Date = (use the suggested ones) + Your Reference = TEST + Price Incl VAT = YES +9. Now add a new line to the sales invoice: + 1x item 1896-S +10. Post the Sales invoice with option Post and Send +11. Go to E-Documents  + The newest entry should be the one that we just created by posting the sales invoice with post and send + Highlight that entry, then go to Actions -> E-Document Logs +12. From the E-Document Logs you can download the e-invoice with button Export File, an XML file is now exported +13. Open a Peppol Validator (e.g. [Free Online Peppol Validator. Validate UBL & XML Invoices Instantly](https://peppolvalidator.com/)), upload and validate the e-invoice downloaded in step 12 + +**Expected Outcome:** +The file should validate without error messages + +**Actual Outcome:** +The file cannot be validated without error messages: +![Image](./error_message.png) + +**Troubleshooting Actions Taken:** +When you post a sales invoice that does not have option Price incl VAT enabled, the created e-document can be validated without error message. + +## Description: diff --git a/dataset/problemstatement/microsoft__BCApps-8059/error_message.png b/dataset/problemstatement/microsoft__BCApps-8059/error_message.png new file mode 100644 index 000000000..7ca525507 Binary files /dev/null and b/dataset/problemstatement/microsoft__BCApps-8059/error_message.png differ diff --git a/dataset/problemstatement/microsoft__BCApps-8253/README.md b/dataset/problemstatement/microsoft__BCApps-8253/README.md new file mode 100644 index 000000000..ffbd4dd13 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8253/README.md @@ -0,0 +1,74 @@ +# Title: [Subcontracting] Standard Task not propagated from Routing to Prod. Order Routing or Subcontracting Worksheet; prices not picked up +## Repro Steps: +**Issues:** + +1. **Standard Task not propagated from Routing:** When a routing line has a Standard Task set, that value is not copied to the corresponding Prod. Order Routing line. +2. **Standard Task not propagated to Subcontracting Worksheet:** The Standard Task from the routing line is also not populated in the Subcontracting Worksheet when lines are pulled. +3. **Standard Task not editable in Subcontracting Worksheet:** Even if the field were present, it is not editable in the Subcontracting Worksheet, preventing manual correction. +4. **Prices not picked up:** If the user has configured prices tied to a Standard Task, those prices are not used because the Standard Task is missing from the subcontracting flow. + +**Expected:** Standard Task should be propagated from Routing to Prod. Order Routing and to the Subcontracting Worksheet. The field should be editable in the worksheet. Prices bound to Standard Task should be applied correctly. + +## Description: + + +## Hints + +### Repro Steps Clarity Score: 6/10 ++Specificity +Determinism +-Missing environment -Unverified UI references +-Missing data values (no concrete Standard Task / item / routing combo named in the bug) + +The bug enumerates 4 related symptoms but provides no concrete data combination. Steps below pick concrete demo values and a sequenced repro for each symptom. +---- +### Detailed Repro Steps +#### Environment +- Build: Master — Subcontracting feature dev build (target branch master). +- Localization: W1 (any localization should reproduce). +- Functional area: SCM / Manufacturing — Subcontracting (Standard Task propagation, Subcontracting Worksheet editing, Subcontracting price lookup). + +#### Prerequisites +- Subcontracting feature available with: a Subcontractor vendor, a Subcontracting Work Center, an item with a Production BOM and a Routing. +- A Standard Task code defined (e.g., STD-PAINT) — choose Search > Standard Tasks > + New to add one. +- A Routing that includes the Subcontracting Work Center, with at least one Routing Line whose Standard Task Code is set to STD-PAINT. +- A Subcontracting price (e.g., on the Standard Task card or on the Subcontracting Work Center / Subcontractor Vendor) that is specifically tied to Standard Task STD-PAINT (so that when STD-PAINT is present on the line, the price applies; when absent, it does not). +- A Released Production Order created from the manufacturing item with the routing above. + +#### Steps — Issue 1: Routing → Prod. Order Routing propagation +1. Choose Search > Routings, open the routing used by the manufacturing item, and confirm the Subcontracting routing line has Standard Task Code = STD-PAINT. +2. Choose Search > Released Production Orders, open the order created in prerequisites. +3. Drill into Lines > Routing to open Prod. Order Routing. +4. Observe Issue 1: the Prod. Order Routing line corresponding to the Subcontracting operation has Standard Task Code = blank (it was not copied from the source Routing). + +#### Steps — Issue 2: Routing → Subcontracting Worksheet propagation +5. Choose Search > Subcontracting Worksheet, choose the related link. +6. Choose Calculate Subcontracts…, accept defaults, run. +7. Observe Issue 2: the worksheet line for the production order's subcontracting operation has Standard Task Code = blank, even though the routing line has STD-PAINT set. + +#### Steps — Issue 3: Standard Task not editable in Subcontracting Worksheet +8. On the worksheet line from step 7, attempt to set Standard Task Code = STD-PAINT either by typing or via the lookup. +9. Observe Issue 3: the field is read-only / not editable, so the missing value cannot be corrected manually before Carry Out Action Message. + +#### Steps — Issue 4: Prices not picked up because Standard Task is missing +Without correcting the Standard Task (since you cannot, per Issue 3), choose Carry Out Action Message… to create the Subcontracting Purchase Order. +Open the resulting Subcontracting Purchase Order line. +Observe Issue 4: the Direct Unit Cost / line price is the work-center default price, not the price tied to Standard Task STD-PAINT. Because the Standard Task is missing from both the routing line and the worksheet, the price-lookup step never matches the standard-task-specific price and the wrong (or default) price is applied. + +#### Expected Result +- Routing → Prod. Order Routing → Subcontracting Worksheet → Subcontracting Purchase Order all preserve Standard Task Code end-to-end. +- The Standard Task Code field is editable in the Subcontracting Worksheet so users can correct or override. +- Subcontracting price lookup uses the Standard Task Code as a key, so prices defined per Standard Task are applied to the resulting PO line. + +#### Actual Result +- Standard Task Code is dropped at the Routing → Prod. Order Routing step, and remains missing on the Subcontracting Worksheet and the resulting Subcontracting PO. Prices tied to Standard Task are therefore never selected. + +#### Notes +- Severity 3, Priority 2. Issue type: Code Defect. Found by Manual Testing: Other Test Pass on 2026-04-30 by Chethan Thopaiah. +- Likely fix surfaces: + - Refresh production order routine (Codeunit "Prod. Order Routing Mgt." or equivalent) — copy Standard Task Code from Routing Line to Prod. Order Routing Line. + - Calculate Subcontracts (Codeunit "Subcontracting Worksheet Mgt." / similar) — copy Standard Task Code from Prod. Order Routing Line into the worksheet line. + - Page extension on Subcontracting Worksheet — set the Standard Task Code field Editable = true (subject to UX review). + - Subcontracting price lookup — extend the price-source lookup to include Standard Task Code as a key so prices tied to a Standard Task are matched. +- Sibling Subcontracting bugs that touch the routing → worksheet → PO chain: #633223, #633224, #633227, #633228, #633229. + +[AI-REPRO] score=6 | workItemId=633226 | generated=2026-04-30 | sources=repro_steps,documentation diff --git a/dataset/problemstatement/microsoft__BCApps-8286/README.md b/dataset/problemstatement/microsoft__BCApps-8286/README.md new file mode 100644 index 000000000..3ce37bb85 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8286/README.md @@ -0,0 +1,31 @@ +# (Bug 636078): [Subcontracting] Worksheet pricing passes total base qty instead of qty-per-UoM to ConvertPriceToUOM — wrong Direct Unit Cost + +## Summary + +Fixes the Subcontracting Worksheet **Direct Unit Cost** when the production order UoM differs from the subcontractor price-list UoM. + +`Subc. Price Management.GetSubcPriceForReqLine` passed `RequisitionLine.GetQuantityBase()` (total base quantity of the order) as the per-UoM conversion factor to `ConvertPriceToUOM`. Because `ConvertPriceToUOM` computes `DirectCost := PriceListCost / PriceListQtyPerUOM * ProdQtyPerUoM`, the result was multiplied by the order quantity instead of the UoM conversion factor. The Carry-Out Action Message-created Purchase Order then inherited the inflated cost. + +Comparison of the three call sites (only the worksheet path was wrong): + +| Path | 2nd param | Correct? | +|------|-----------|----------| +| Routing (`SetRoutingPriceListCost`) | `ProdQtyPerUom` | Yes | +| **Worksheet (`GetSubcPriceForReqLine`)** | **`RequisitionLine.GetQuantityBase()`** | **No (fixed here)** | +| Purchase Order (`GetSubcPriceForPurchLine`) | `PurchaseLine.GetQuantityPerUOM()` | Yes | + +### Fix + +Pass `RequisitionLine.GetQuantityForUOM()` instead, matching the routing and purchase paths. + +### Test + +Added `WorksheetDirectUnitCostUsesQtyPerUoMNotBaseQtyForUoMConversion` in `SubcSubcontractingTest`: + +- Item with PCS base UoM + SET alternative UoM (10 PCS per SET), vendor and work center with that vendor as subcontractor, subcontractor price of 1000 / PCS. +- Stages a Requisition Line for 3 SET (= 30 PCS base) and asserts `Direct Unit Cost = 10000` (price * Qty-per-UoM), not 30000 (pre-fix behavior). +- Also asserts the same-UoM (PCS) path still returns 1000 - guards against regression. + +### Work Item + +[AB#636078](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/636078) diff --git a/dataset/problemstatement/microsoft__BCApps-8287/README.md b/dataset/problemstatement/microsoft__BCApps-8287/README.md new file mode 100644 index 000000000..b8355667b --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8287/README.md @@ -0,0 +1,10 @@ +# [Quality Management] Add missing validation of "Allowable Values" in Quality Test card + +## What & why + +image + + +## Linked work + +Fixes [AB#624240](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/624240) diff --git a/dataset/problemstatement/microsoft__BCApps-8293/README.md b/dataset/problemstatement/microsoft__BCApps-8293/README.md new file mode 100644 index 000000000..65c2f4053 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8293/README.md @@ -0,0 +1,17 @@ +# Bug 634953: Fix factbox drilldowns for finished production orders + +## Summary +- **Bug**: Subcontracting factbox drilldowns in Purchase Order and Transfer Order break after the linked production order is finished. +- **Root cause**: \Subc. ProdO. Factbox Mgmt.\ (CU 99001559) hardcodes \SetRange(Status, ::Released)\ in all 5 procedures, so no data is returned once status moves to Finished. +- **Fix**: Replace \SetRange(Status, ::Released)\ with \SetFilter(Status, '>=%1', ::Released)\ across all filter procedures so that both Released and Finished production orders are found. \ShowProductionOrder\ now opens the correct page (\Released Production Order\ or \Finished Production Order\) based on the resolved status. + +## Changes +- \SubcProdOFactboxMgmt.Codeunit.al\ — Fixed all 5 affected procedures +- \SubcSubcontractingTest.Codeunit.al\ — Added \ProdOFactboxMgmtShowsDataAfterProdOrderFinished\ test ([SCENARIO 634953]) + +## Test +Added \ProdOFactboxMgmtShowsDataAfterProdOrderFinished\ in codeunit 139989 — verifies that \CalcNoOfProductionOrderRoutings\ and \CalcNoOfProductionOrderComponents\ return positive counts after the production order is finished. + +Fixes [AB#634953](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/634953) + +:robot: Generated with GitHub Copilot diff --git a/dataset/problemstatement/microsoft__BCApps-8313/README.md b/dataset/problemstatement/microsoft__BCApps-8313/README.md new file mode 100644 index 000000000..03b104bce --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8313/README.md @@ -0,0 +1,53 @@ +# Fix E-Doc V1 PEPPOL import: Sub Total uses LineExtensionAmount from XML + +## Summary + + + +- **`EDocImport.Codeunit.al:843`** — `V1_CopyFromPurchaseLine` was setting `"Sub Total"` as `Direct Unit Cost * Quantity` instead of using `PurchaseLine.Amount` which holds the `LineExtensionAmount` parsed directly from the PEPPOL XML. + +- **`EDocReceiveTest.Codeunit.al`** — Added regression test `ReceivePeppolInvoice_LineSubTotalFromXml` that verifies `"Sub Total"` = 11.20 for a line with Qty=1.65, Price=6.79, LineExtensionAmount=11.20. + +- **`PEPPOL_LineRounding.xml`** — Minimal PEPPOL BIS 3.0 test invoice with rounding-sensitive quantities. + + + +## Root cause + + + +In the V1 import path, `EDocImportPEPPOLBIS30` reads `LineExtensionAmount` (the vendor-rounded line total) into `PurchaseLine.Amount`. But `V1_CopyFromPurchaseLine` ignored it and recalculated: + + + +```al + +// Before (bug): + +EDocumentPurchaseLine."Sub Total" := PurchaseLine."Direct Unit Cost" * PurchaseLine.Quantity; + +// 6.79 * 1.65 = 11.2035 — wrong, shows unrounded value on E-Document Purchase Draft page + + + +// After (fix): + +EDocumentPurchaseLine."Sub Total" := PurchaseLine.Amount; + +// 11.20 — correct, preserves vendor-rounded value from XML + +``` + + + +`PurchaseLine.Amount` is set from the XML via `Evaluate(PurchaseLine.Amount, Value, 9)` at `EDocImportPEPPOLBIS30:503` and is preserved through `MapEDocument` (which copies all fields and only transforms Text/Code types, not Decimal). + + + +## Test plan + +- [ ] `ReceivePeppolInvoice_LineSubTotalFromXml` passes: asserts `EDocumentPurchaseLine."Sub Total"` = 11.20 + + + +Fixes bug [AB#613698](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/613698) diff --git a/dataset/problemstatement/microsoft__BCApps-8380/README.md b/dataset/problemstatement/microsoft__BCApps-8380/README.md new file mode 100644 index 000000000..be41e29d3 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8380/README.md @@ -0,0 +1,15 @@ +# [Quality Management] Workflow responses are marked as default for any event + +## What & why + + + +Quality Management responses are nominally valid only for Quality Management events. + + + +## Linked work + + + +Fixes [AB#626774](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/626774) diff --git a/dataset/problemstatement/microsoft__BCApps-8386/README.md b/dataset/problemstatement/microsoft__BCApps-8386/README.md new file mode 100644 index 000000000..35976ad13 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8386/README.md @@ -0,0 +1,34 @@ +# [Shopify] Tolerate legacy bulk-operation request data missing unitCost key + +## Summary +Bulk variant price updates persist a JSON `Request Data` blob on `Shpfy Bulk Operation` so the rollback path can restore the previous Price / Compare-at-Price / Updated At / Unit Cost values when Shopify's async callback reports failure. + +PR #6155 added a new `unitCost` key to that blob and a matching reader on the rollback path, but the reader uses `JsonObject.GetDecimal` which throws if the key is missing. Any bulk operation queued **before** the upgrade (no `unitCost` in the blob) and reverted **after** the upgrade crashes with: + +> There are no properties with the key 'unitCost' on the JSON object + +The same stale rows can keep retrying, so the error surfaces repeatedly even though the upgrade happened once. + +The Shopify API payload itself is unaffected — it still correctly sends `inventoryItem.cost`. The crash is purely on the BC-side rollback reader. + +## Changes + +**Production code** +- `ShpfyBulkUpdateProductPrice.RevertRequests` and `ShpfyProductExport.RevertVariantChanges`: guard the `unitCost` read with `JsonObject.Contains('unitCost')`. If absent (legacy blob), Unit Cost is left untouched, matching the pre-PR-#6155 behaviour. + +**Test code** +- `TestBulkOperationRevertFailedWithLegacyRequestDataMissingUnitCost`: new regression test that builds a request-data blob without the `unitCost` key (via a `GenerateLegacyRequestDataWithoutUnitCost` helper) and asserts that the rollback completes without throwing, reverts Price / Compare-at-Price correctly, and leaves Unit Cost untouched. + +## Why only `unitCost` is gated, not every field +The other keys (`id`, `price`, `compareAtPrice`, `updatedAt`) have been written by `ShpfyVariantAPI.UpdateProductPrice` since the connector was first migrated to BCApps — there is no version that ever persisted a `Request Data` blob without them. A missing `price`/`compareAtPrice`/`updatedAt`/`id` is therefore not a legitimate "legacy blob" scenario; it would be a real upstream bug (regressed writer, corrupted blob, forgotten `JRequest.Add`). `GetDecimal`'s throw is the correct behaviour there — surfacing the bug loudly is better than silently skipping a rollback (which would leave variants showing the wrong price in BC, or no-op the revert with zero diagnostic). + +`unitCost` is the one and only key that was added later, so it's the one key where a key-missing scenario has both a legitimate root cause (legacy persisted blob) and a safe fallback (leave the field untouched). + +## Customer mitigation (no patch required) +Customers hitting this on the current BC28 build can self-mitigate by opening the **Shopify Bulk Operations** page and running **Delete Entries Older Than 7 Days**. The deletion bypasses the rollback trigger, removing the stale pre-upgrade rows without re-throwing. Bulk operations queued after the upgrade are written in the new layout and are unaffected. + +## Scope +Main only — rare upgrade-window race condition with a self-service mitigation available. Not backported. + +#### Work Item(s) +Fixes [AB#637250](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637250) diff --git a/dataset/problemstatement/microsoft__BCApps-8423/README.md b/dataset/problemstatement/microsoft__BCApps-8423/README.md new file mode 100644 index 000000000..ae3b18ad6 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8423/README.md @@ -0,0 +1,29 @@ +# Render per-row Currency Code in Aged Accounts Receivable/Payable Excel + +## Summary + + + +The `CurrencyCode` column in Aged Accounts Receivable Excel (report 4402) and Aged Accounts Payable Excel (report 4403) was bound to a single AgingData-buffer-wide variable (`CurrencyCodeDisplayCode`) computed once after `InsertAgingData`. Every row of a given customer/vendor displayed the same currency — the last one inserted into the buffer. Customers/vendors with entries in multiple currencies saw foreign-currency rows mislabeled with the LCY code (or vice versa). + + + +This change: + +- Binds the `CurrencyCode` column directly to `AgingData."Currency Code"` so each row renders its own currency. + +- Falls back to G/L Setup's LCY Code at insertion time when the ledger entry's `Currency Code` is empty. + +- Splits the Aged Accounts tests out of `TrialBalanceExcelReports.Codeunit.al` into a new dedicated `AgedAccountsExcelReports.Codeunit.al` (139547), and adds per-row currency rendering tests for both reports. + + + +Fixes [AB#637444](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637444) + + + +## Test plan + +- [x] New tests `AgedAccountsRecRendersCurrencyCodePerEntry` and `AgedAccountsPayableRendersCurrencyCodePerEntry` cover the multi-currency rendering case + +- [x] Existing Aged Accounts tests continue to pass after relocation diff --git a/dataset/problemstatement/microsoft__BCApps-8524/README.md b/dataset/problemstatement/microsoft__BCApps-8524/README.md new file mode 100644 index 000000000..bd5bcdc80 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8524/README.md @@ -0,0 +1,35 @@ +# [Quality Management] Improvements in "Value Type Text Expression" and tooltips + +## What & why + + + +Fixes: + +1. Expression Formula not copied to template, not visible on template subform, Default Value not guarded for Text Expression tests + +2. Text Expression test value is editable - manual overrides silently lost on re-evaluation + +3. Single-line text expression inspection never evaluates the expression + + + +Improvements: + +1. Quality Inspection document teaching tips + +2. Setup guide text + + + +## Linked work + + + +Fixes [AB#634074](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/634074) + +Fixes [AB#634080](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/634080) + +Fixes [AB#634083](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/634083) + +Fixes [AB#622439](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/622439) diff --git a/dataset/problemstatement/microsoft__BCApps-8555/README.md b/dataset/problemstatement/microsoft__BCApps-8555/README.md new file mode 100644 index 000000000..ad0f79655 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8555/README.md @@ -0,0 +1,13 @@ +# [Quality Management] Do not show notification when inspections are not created + +## What & why + + + +Do not show notifications when new inspections are not created, for example due to setup that instructs to use existing inspections. + + + +## Linked work + +Fixes [AB#624741](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/624741) diff --git a/dataset/problemstatement/microsoft__BCApps-8564/README.md b/dataset/problemstatement/microsoft__BCApps-8564/README.md new file mode 100644 index 000000000..98e114f4b --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8564/README.md @@ -0,0 +1,19 @@ +# [Subcontracting] Block Cancel of purchase invoice with subcontracting item charge (Bug 637502) + +Fixes [AB#637502](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637502) + + + +Cancelling a Posted Purchase Invoice whose Item Charge is split between a regular item receipt line and a subcontracting service receipt line silently skipped the capacity portion. `CopyDocumentMgt.CopyFromPurchLineItemChargeAssign` rebuilds assignments by iterating Value Entries and looking up the linked Item Ledger Entry; subcontracting item-charge Value Entries have `Item Ledger Entry No. = 0` (only `Capacity Ledger Entry No.` is set), so they were dropped and the orphaned amount was redistributed to inventory entries, corrupting inventory cost. + + + +Until a proper reversal path exists in BaseApp, this PR narrows the blast radius from the Subcontracting App: + + + +- `SubcItemJnlPostLineExt`: in `OnBeforeInsertCapValueEntry`, populate `ValueEntry."Item Charge No."` from `ItemJnlLine."Item Charge No."` when `ItemJnlLine."Subc. Item Charge Assign."` is set, so capacity-side Value Entries carry the item charge they came from. + +- `SubcPurchPostExt`: subscribe to `Correct Posted Purch. Invoice.OnAfterTestCorrectInvoiceIsAllowed` and block Cancel/Correct when the posted invoice has any Value Entry with `Item Charge No. <> ''` AND `Capacity Ledger Entry No. <> 0`. Plain subcontracting invoices are unaffected. + +- Add integration test `CancelInvoiceWithSubcontractingItemChargeIsBlocked` reproducing the bug repro (mixed regular + subcontracting receipt charge assignment) and asserting the block fires. diff --git a/dataset/problemstatement/microsoft__BCApps-8600/README.md b/dataset/problemstatement/microsoft__BCApps-8600/README.md new file mode 100644 index 000000000..8a6eb8b30 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8600/README.md @@ -0,0 +1,13 @@ +# [Subcontracting] Block changing Prod Order Routing and Components when Subcontracting Transfers exist + +## What & why + +Prevent unsafe changes when subcontracting transfers are in progress + +When a production order has active transfer orders sending components to a subcontractor, users could previously change or delete the related components and routing lines — potentially causing data mismatches between the transfer orders and the production order. + +This PR blocks modifications to key fields (item, quantity, supply method, location, etc.) on Prod. Order Components and Prod. Order Routing Lines when transfer orders or stock at the subcontractor location exist. + +## Linked work + +Fixes [AB#634269](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/634269) diff --git a/dataset/problemstatement/microsoft__BCApps-8612/README.md b/dataset/problemstatement/microsoft__BCApps-8612/README.md new file mode 100644 index 000000000..8dec00a70 --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8612/README.md @@ -0,0 +1,48 @@ +# Bug 637777: Handle rerun after subcontracting receipt + +Treat routing lines with no remaining quantity as a no-op so rerunning Create Subcontracting Order after full receipt shows existing purchase lines instead of surfacing a raw error. + + + +## What & why + + + +## Linked work + + + +Fixes [AB#637777](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637777) + +## How I validated this + +- [ ] I read the full diff and it contains only changes I intended. +- [ ] I built the affected app(s) locally with no new analyzer warnings. +- [ ] I ran the change in Business Central and confirmed it behaves as expected. +- [ ] I added or updated tests for the new behavior, or explained below why none are needed. + +**What I tested and the outcome** *(required — be specific: scenarios, commands, screenshots for UI changes)* + + + +## Risk & compatibility + + + +Fixes [AB#637777](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637777) diff --git a/dataset/problemstatement/microsoft__BCApps-8616/README.md b/dataset/problemstatement/microsoft__BCApps-8616/README.md new file mode 100644 index 000000000..cec038c6d --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8616/README.md @@ -0,0 +1,15 @@ +# Bug 638458: Disable subcontracting actions on Item Ledger Entries when not applicable + +## Summary +- **Bug:** Item Ledger Entries subcontracting actions (Production Order, Production Order Routing, Production Order Components, Subcontracting Purchase Order) are always enabled and silently do nothing when clicked on non-subcontracting entries. +- **Root cause:** The four actions in `SubcILEntries.PageExt.al` had no `Enabled` property, so they were always clickable regardless of whether the entry was subcontracting-related. +- **Fix:** Added inline `Enabled` expressions: + - `Enabled = Rec."Subc. Prod. Order No." <> ''` on Production Order, Production Order Routing, and Production Order Components actions + - `Enabled = Rec."Subc. Purch. Order No." <> ''` on Subcontracting Purchase Order action + +## Test +Added `ItemLedgerEntriesSubcActionsDisabledWhenNotSubcontracting` and `ItemLedgerEntriesSubcActionsEnabledWhenSubcontracting` in `SubcSubcontractingUITest` (codeunit 139990) — [SCENARIO 638458]. + +Fixes [AB#638458](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/638458) + +:robot: Generated with GitHub Copilot diff --git a/dataset/problemstatement/microsoft__BCApps-8632/README.md b/dataset/problemstatement/microsoft__BCApps-8632/README.md new file mode 100644 index 000000000..fe2a4baea --- /dev/null +++ b/dataset/problemstatement/microsoft__BCApps-8632/README.md @@ -0,0 +1,3 @@ +# [Subcontracting] Add action to view subcontracting transfer orders from production orders + +Fixes [AB#638532](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/638532)