From d645138679239fe86a39070857ed1d56555624bf Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Wed, 5 Aug 2026 14:42:02 +0530 Subject: [PATCH 01/11] Initial Commit --- .../ItemTrackingDataCollection.Codeunit.al | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al index 940022cd9b1..61d450f4cf1 100644 --- a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al +++ b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al @@ -11,6 +11,7 @@ using Microsoft.Projects.Project.Journal; using Microsoft.Projects.Project.Planning; using Microsoft.Purchases.Document; using Microsoft.Sales.Document; +using Microsoft.Warehouse.Activity; using Microsoft.Warehouse.Ledger; codeunit 6501 "Item Tracking Data Collection" @@ -455,6 +456,8 @@ codeunit 6501 "Item Tracking Data Collection" end; until TempTrackingSpecification.Next() = 0; + TransferUnregisteredPicksToTempRec(TempTrackingSpecification2); + OnRetrieveLookupDataOnAfterTransferToTempRec(TempGlobalEntrySummary, TempTrackingSpecification, ItemLedgEntry, LastSummaryEntryNo); TempGlobalEntrySummary.Reset(); @@ -539,6 +542,67 @@ codeunit 6501 "Item Tracking Data Collection" until TempReservEntry.Next() = 0; end; + local procedure TransferUnregisteredPicksToTempRec(var TrackingSpecification: Record "Tracking Specification" temporary) + var + WhseActivLine: Record "Warehouse Activity Line"; + IsHandled: Boolean; + begin + IsHandled := false; + OnBeforeTransferUnregisteredPicksToTempRec(TrackingSpecification, TempGlobalReservEntry, IsHandled); + if IsHandled then + exit; + + if TrackingSpecification."Item No." = '' then + exit; + + WhseActivLine.SetRange("Item No.", TrackingSpecification."Item No."); + WhseActivLine.SetRange("Variant Code", TrackingSpecification."Variant Code"); + WhseActivLine.SetRange("Location Code", TrackingSpecification."Location Code"); + WhseActivLine.SetRange("Activity Type", WhseActivLine."Activity Type"::Pick); + WhseActivLine.SetFilter("Action Type", '%1|%2', WhseActivLine."Action Type"::Take, WhseActivLine."Action Type"::" "); + WhseActivLine.SetRange("Breakbulk No.", 0); + WhseActivLine.SetFilter("Qty. Outstanding (Base)", '>%1', 0); + OnTransferUnregisteredPicksToTempRecOnAfterSetFilters(WhseActivLine, TrackingSpecification); + + if WhseActivLine.FindSet() then + repeat + if (WhseActivLine."Lot No." <> '') or (WhseActivLine."Serial No." <> '') or (WhseActivLine."Package No." <> '') then + if not PickBelongsToCurrentSource(WhseActivLine, TrackingSpecification) then begin + LastReservEntryNo -= 1; + TempGlobalReservEntry.Init(); + TempGlobalReservEntry."Entry No." := LastReservEntryNo; + TempGlobalReservEntry."Reservation Status" := TempGlobalReservEntry."Reservation Status"::Prospect; + TempGlobalReservEntry.Positive := false; + TempGlobalReservEntry."Item No." := WhseActivLine."Item No."; + TempGlobalReservEntry."Variant Code" := WhseActivLine."Variant Code"; + TempGlobalReservEntry."Location Code" := WhseActivLine."Location Code"; + TempGlobalReservEntry."Quantity (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; + TempGlobalReservEntry."Qty. to Handle (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; + TempGlobalReservEntry."Source Type" := Database::"Warehouse Activity Line"; + TempGlobalReservEntry."Source Subtype" := WhseActivLine."Activity Type".AsInteger(); + TempGlobalReservEntry."Source ID" := WhseActivLine."No."; + TempGlobalReservEntry."Source Ref. No." := WhseActivLine."Line No."; + TempGlobalReservEntry."Serial No." := WhseActivLine."Serial No."; + TempGlobalReservEntry."Lot No." := WhseActivLine."Lot No."; + TempGlobalReservEntry."Package No." := WhseActivLine."Package No."; + TempGlobalReservEntry."Shipment Date" := DMY2Date(31, 12, 9999); + if TempGlobalReservEntry.Insert() then + CreateEntrySummary(TrackingSpecification, TempGlobalReservEntry); + end; + until WhseActivLine.Next() = 0; + + OnAfterTransferUnregisteredPicksToTempRec(TrackingSpecification, TempGlobalReservEntry); + end; + + local procedure PickBelongsToCurrentSource(WhseActivLine: Record "Warehouse Activity Line"; TrackingSpecification: Record "Tracking Specification"): Boolean + begin + exit( + (WhseActivLine."Source Type" = TrackingSpecification."Source Type") and + (WhseActivLine."Source Subtype" = TrackingSpecification."Source Subtype") and + (WhseActivLine."Source No." = TrackingSpecification."Source ID") and + (WhseActivLine."Source Line No." = TrackingSpecification."Source Ref. No.")); + end; + local procedure CreateEntrySummary(TrackingSpecification: Record "Tracking Specification" temporary; TempReservEntry: Record "Reservation Entry" temporary) begin CreateEntrySummary2(TrackingSpecification, TempReservEntry, true); @@ -1537,6 +1601,21 @@ codeunit 6501 "Item Tracking Data Collection" begin end; + [IntegrationEvent(false, false)] + local procedure OnBeforeTransferUnregisteredPicksToTempRec(var TrackingSpecification: Record "Tracking Specification" temporary; var TempGlobalReservEntry: Record "Reservation Entry" temporary; var IsHandled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnTransferUnregisteredPicksToTempRecOnAfterSetFilters(var WhseActivLine: Record "Warehouse Activity Line"; TrackingSpecification: Record "Tracking Specification") + begin + end; + + [IntegrationEvent(false, false)] + local procedure OnAfterTransferUnregisteredPicksToTempRec(var TrackingSpecification: Record "Tracking Specification" temporary; var TempGlobalReservEntry: Record "Reservation Entry" temporary) + begin + end; + [IntegrationEvent(false, false)] local procedure OnAssistEditTrackingNoOnBeforeSetSources(var TempTrackingSpecification: Record "Tracking Specification" temporary; var TempGlobalEntrySummary: Record "Entry Summary" temporary; var MaxQuantity: Decimal); begin From 1b8d36d5a77cac427c9375651f4598cba71fc0f3 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Thu, 6 Aug 2026 12:45:06 +0530 Subject: [PATCH 02/11] Automation Added --- .../W1/Tests/SCM/SCMItemTracking.Codeunit.al | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al b/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al index ae22552282a..12d68c0d858 100644 --- a/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al +++ b/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al @@ -5691,6 +5691,93 @@ codeunit 137405 "SCM Item Tracking" LibraryVariableStorage.AssertEmpty(); end; + [Test] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler,MessageHandler')] + [Scope('OnPrem')] + procedure GetAvailableLotQtyExcludesUnregisteredWhsePickAllocation() + var + Item: Record Item; + Location: Record Location; + WarehouseActivityHeader: Record "Warehouse Activity Header"; + WarehouseActivityLine: Record "Warehouse Activity Line"; + TrackingSpecification: Record "Tracking Specification"; + ItemTrackingDataCollection: Codeunit "Item Tracking Data Collection"; + LotNo: Code[50]; + Qty: Integer; + begin + // [Bug 638344] Available lot quantity must exclude quantities committed to an unregistered warehouse pick + // [SCENARIO] A lot fully allocated to an unregistered warehouse-pick Take line is not reported as available for a different demand source + Initialize(); + + // [GIVEN] Lot-tracked item with lot warehouse tracking, in stock at a location for lot "L" with qty "Q" + Qty := LibraryRandom.RandIntInRange(20, 50); + LotNo := LibraryUtility.GenerateGUID(); + CreateLotTrackedItemAtLocation(Item, Location); + CreateAndPostLotStockForPick(Item."No.", Location.Code, LotNo, Qty); + + // [GIVEN] An unregistered warehouse pick Take line reserves the full lot quantity for a different sales line + CreateUnregisteredWhsePickTakeLine( + WarehouseActivityHeader, WarehouseActivityLine, Item."No.", Location.Code, LotNo, Qty, + Database::"Sales Line", 1, LibraryUtility.GenerateGUID(), 10000); + + // [WHEN] Available lot quantity is retrieved for a new demand on the same lot + SetTrackingSpecItemLotLocation(TrackingSpecification, Item."No.", Location.Code, LotNo); + + // [THEN] Available quantity is zero because the on-hand lot is fully committed to the unregistered pick + Assert.AreEqual( + 0, ItemTrackingDataCollection.GetAvailableLotQty(TrackingSpecification), + 'Available lot quantity must exclude quantities allocated to unregistered warehouse picks.'); + + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) + var + ItemTrackingCodeCode: Code[10]; + begin + LibraryWarehouse.CreateLocation(Location); + Location.Validate("Require Pick", true); + Location.Validate("Require Shipment", true); + Location.Modify(true); + + ItemTrackingCodeCode := CreateItemTrackingCodeLotSpecificWhseTracking(true); + CreateItem(Item, ItemTrackingCodeCode, '', LibraryUtility.GetGlobalNoSeriesCode()); + end; + + local procedure SetTrackingSpecItemLotLocation(var TrackingSpecification: Record "Tracking Specification"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]) + begin + Clear(TrackingSpecification); + TrackingSpecification."Item No." := ItemNo; + TrackingSpecification."Location Code" := LocationCode; + TrackingSpecification."Lot No." := LotNo; + end; + + local procedure CreateUnregisteredWhsePickTakeLine(var WarehouseActivityHeader: Record "Warehouse Activity Header"; var WarehouseActivityLine: Record "Warehouse Activity Line"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Decimal; SourceType: Integer; SourceSubtype: Integer; SourceNo: Code[20]; SourceLineNo: Integer) + begin + WarehouseActivityHeader.Init(); + WarehouseActivityHeader.Type := WarehouseActivityHeader.Type::Pick; + WarehouseActivityHeader."No." := LibraryUtility.GenerateGUID(); + WarehouseActivityHeader."Location Code" := LocationCode; + WarehouseActivityHeader.Insert(false); + + WarehouseActivityLine.Init(); + WarehouseActivityLine."Activity Type" := WarehouseActivityLine."Activity Type"::Pick; + WarehouseActivityLine."No." := WarehouseActivityHeader."No."; + WarehouseActivityLine."Line No." := 10000; + WarehouseActivityLine."Action Type" := WarehouseActivityLine."Action Type"::Take; + WarehouseActivityLine."Item No." := ItemNo; + WarehouseActivityLine."Location Code" := LocationCode; + WarehouseActivityLine."Lot No." := LotNo; + WarehouseActivityLine."Qty. Outstanding" := Qty; + WarehouseActivityLine."Qty. Outstanding (Base)" := Qty; + WarehouseActivityLine."Breakbulk No." := 0; + WarehouseActivityLine."Source Type" := SourceType; + WarehouseActivityLine."Source Subtype" := SourceSubtype; + WarehouseActivityLine."Source No." := SourceNo; + WarehouseActivityLine."Source Line No." := SourceLineNo; + WarehouseActivityLine.Insert(false); + end; + local procedure CreateAndPostLotStockForPick(ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Integer) var ItemJournalLine: Record "Item Journal Line"; From 039ea83ec7a9e881ddb74a5c6d69bcaf4f9b5d02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Aug 2026 07:33:10 +0000 Subject: [PATCH 03/11] Propagate SCMItemTracking test to RU layer for Miapp sync Co-authored-by: Shikhverma <241284522+Shikhverma@users.noreply.github.com> --- .../RU/Tests/SCM/SCMItemTracking.Codeunit.al | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/Layers/RU/Tests/SCM/SCMItemTracking.Codeunit.al b/src/Layers/RU/Tests/SCM/SCMItemTracking.Codeunit.al index e4556baf006..c3abf165a25 100644 --- a/src/Layers/RU/Tests/SCM/SCMItemTracking.Codeunit.al +++ b/src/Layers/RU/Tests/SCM/SCMItemTracking.Codeunit.al @@ -5697,6 +5697,93 @@ codeunit 137405 "SCM Item Tracking" LibraryVariableStorage.AssertEmpty(); end; + [Test] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler,MessageHandler')] + [Scope('OnPrem')] + procedure GetAvailableLotQtyExcludesUnregisteredWhsePickAllocation() + var + Item: Record Item; + Location: Record Location; + WarehouseActivityHeader: Record "Warehouse Activity Header"; + WarehouseActivityLine: Record "Warehouse Activity Line"; + TrackingSpecification: Record "Tracking Specification"; + ItemTrackingDataCollection: Codeunit "Item Tracking Data Collection"; + LotNo: Code[50]; + Qty: Integer; + begin + // [Bug 638344] Available lot quantity must exclude quantities committed to an unregistered warehouse pick + // [SCENARIO] A lot fully allocated to an unregistered warehouse-pick Take line is not reported as available for a different demand source + Initialize(); + + // [GIVEN] Lot-tracked item with lot warehouse tracking, in stock at a location for lot "L" with qty "Q" + Qty := LibraryRandom.RandIntInRange(20, 50); + LotNo := LibraryUtility.GenerateGUID(); + CreateLotTrackedItemAtLocation(Item, Location); + CreateAndPostLotStockForPick(Item."No.", Location.Code, LotNo, Qty); + + // [GIVEN] An unregistered warehouse pick Take line reserves the full lot quantity for a different sales line + CreateUnregisteredWhsePickTakeLine( + WarehouseActivityHeader, WarehouseActivityLine, Item."No.", Location.Code, LotNo, Qty, + Database::"Sales Line", 1, LibraryUtility.GenerateGUID(), 10000); + + // [WHEN] Available lot quantity is retrieved for a new demand on the same lot + SetTrackingSpecItemLotLocation(TrackingSpecification, Item."No.", Location.Code, LotNo); + + // [THEN] Available quantity is zero because the on-hand lot is fully committed to the unregistered pick + Assert.AreEqual( + 0, ItemTrackingDataCollection.GetAvailableLotQty(TrackingSpecification), + 'Available lot quantity must exclude quantities allocated to unregistered warehouse picks.'); + + LibraryVariableStorage.AssertEmpty(); + end; + + local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) + var + ItemTrackingCodeCode: Code[10]; + begin + LibraryWarehouse.CreateLocation(Location); + Location.Validate("Require Pick", true); + Location.Validate("Require Shipment", true); + Location.Modify(true); + + ItemTrackingCodeCode := CreateItemTrackingCodeLotSpecificWhseTracking(true); + CreateItem(Item, ItemTrackingCodeCode, '', LibraryUtility.GetGlobalNoSeriesCode()); + end; + + local procedure SetTrackingSpecItemLotLocation(var TrackingSpecification: Record "Tracking Specification"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]) + begin + Clear(TrackingSpecification); + TrackingSpecification."Item No." := ItemNo; + TrackingSpecification."Location Code" := LocationCode; + TrackingSpecification."Lot No." := LotNo; + end; + + local procedure CreateUnregisteredWhsePickTakeLine(var WarehouseActivityHeader: Record "Warehouse Activity Header"; var WarehouseActivityLine: Record "Warehouse Activity Line"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Decimal; SourceType: Integer; SourceSubtype: Integer; SourceNo: Code[20]; SourceLineNo: Integer) + begin + WarehouseActivityHeader.Init(); + WarehouseActivityHeader.Type := WarehouseActivityHeader.Type::Pick; + WarehouseActivityHeader."No." := LibraryUtility.GenerateGUID(); + WarehouseActivityHeader."Location Code" := LocationCode; + WarehouseActivityHeader.Insert(false); + + WarehouseActivityLine.Init(); + WarehouseActivityLine."Activity Type" := WarehouseActivityLine."Activity Type"::Pick; + WarehouseActivityLine."No." := WarehouseActivityHeader."No."; + WarehouseActivityLine."Line No." := 10000; + WarehouseActivityLine."Action Type" := WarehouseActivityLine."Action Type"::Take; + WarehouseActivityLine."Item No." := ItemNo; + WarehouseActivityLine."Location Code" := LocationCode; + WarehouseActivityLine."Lot No." := LotNo; + WarehouseActivityLine."Qty. Outstanding" := Qty; + WarehouseActivityLine."Qty. Outstanding (Base)" := Qty; + WarehouseActivityLine."Breakbulk No." := 0; + WarehouseActivityLine."Source Type" := SourceType; + WarehouseActivityLine."Source Subtype" := SourceSubtype; + WarehouseActivityLine."Source No." := SourceNo; + WarehouseActivityLine."Source Line No." := SourceLineNo; + WarehouseActivityLine.Insert(false); + end; + local procedure CreateAndPostLotStockForPick(ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Integer) var ItemJournalLine: Record "Item Journal Line"; From b28c5fd00a43b81d007b8700e533e19ce0ae4051 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Aug 2026 04:49:50 +0000 Subject: [PATCH 04/11] Fix missing Inventory Posting Setup in GetAvailableLotQtyExcludesUnregisteredWhsePickAllocation test Co-authored-by: Shikhverma <241284522+Shikhverma@users.noreply.github.com> --- .../RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al | 4 ++++ .../W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index c3abf165a25..26a0f0cf25c 100644 --- a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5739,6 +5739,7 @@ codeunit 137405 "SCM Item Tracking" local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) var + InventoryPostingSetup: Record "Inventory Posting Setup"; ItemTrackingCodeCode: Code[10]; begin LibraryWarehouse.CreateLocation(Location); @@ -5748,6 +5749,9 @@ codeunit 137405 "SCM Item Tracking" ItemTrackingCodeCode := CreateItemTrackingCodeLotSpecificWhseTracking(true); CreateItem(Item, ItemTrackingCodeCode, '', LibraryUtility.GetGlobalNoSeriesCode()); + + if not InventoryPostingSetup.Get(Location.Code, Item."Inventory Posting Group") then + LibraryInventory.CreateInventoryPostingSetup(InventoryPostingSetup, Location.Code, Item."Inventory Posting Group"); end; local procedure SetTrackingSpecItemLotLocation(var TrackingSpecification: Record "Tracking Specification"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]) diff --git a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index 12d68c0d858..c683fc80538 100644 --- a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5733,6 +5733,7 @@ codeunit 137405 "SCM Item Tracking" local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) var + InventoryPostingSetup: Record "Inventory Posting Setup"; ItemTrackingCodeCode: Code[10]; begin LibraryWarehouse.CreateLocation(Location); @@ -5742,6 +5743,9 @@ codeunit 137405 "SCM Item Tracking" ItemTrackingCodeCode := CreateItemTrackingCodeLotSpecificWhseTracking(true); CreateItem(Item, ItemTrackingCodeCode, '', LibraryUtility.GetGlobalNoSeriesCode()); + + if not InventoryPostingSetup.Get(Location.Code, Item."Inventory Posting Group") then + LibraryInventory.CreateInventoryPostingSetup(InventoryPostingSetup, Location.Code, Item."Inventory Posting Group"); end; local procedure SetTrackingSpecItemLotLocation(var TrackingSpecification: Record "Tracking Specification"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]) From 90811bc7eb7f012389ea7d198d9e84865779f79c Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Mon, 10 Aug 2026 10:33:50 +0530 Subject: [PATCH 05/11] fix --- src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al b/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al index 12d68c0d858..dfb9b159f71 100644 --- a/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al +++ b/src/Layers/W1/Tests/SCM/SCMItemTracking.Codeunit.al @@ -5735,7 +5735,7 @@ codeunit 137405 "SCM Item Tracking" var ItemTrackingCodeCode: Code[10]; begin - LibraryWarehouse.CreateLocation(Location); + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location); Location.Validate("Require Pick", true); Location.Validate("Require Shipment", true); Location.Modify(true); From ba8ff57416b15b9101a6cd26fa9dd8b376501448 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Mon, 10 Aug 2026 14:17:18 +0530 Subject: [PATCH 06/11] fix suggestion 1 --- .../Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al index 61d450f4cf1..4560348ed2d 100644 --- a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al +++ b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al @@ -559,6 +559,7 @@ codeunit 6501 "Item Tracking Data Collection" WhseActivLine.SetRange("Variant Code", TrackingSpecification."Variant Code"); WhseActivLine.SetRange("Location Code", TrackingSpecification."Location Code"); WhseActivLine.SetRange("Activity Type", WhseActivLine."Activity Type"::Pick); + // Blank Action Type covers Inventory Pick lines (single-step pick with no Take/Place split). WhseActivLine.SetFilter("Action Type", '%1|%2', WhseActivLine."Action Type"::Take, WhseActivLine."Action Type"::" "); WhseActivLine.SetRange("Breakbulk No.", 0); WhseActivLine.SetFilter("Qty. Outstanding (Base)", '>%1', 0); From 2b80a80e9b194b72e719384b0f127a368dc18de3 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Tue, 11 Aug 2026 09:24:04 +0530 Subject: [PATCH 07/11] update --- src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index 4e717f2546a..e59139639d0 100644 --- a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5692,7 +5692,7 @@ codeunit 137405 "SCM Item Tracking" end; [Test] - [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler,MessageHandler')] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler')] [Scope('OnPrem')] procedure GetAvailableLotQtyExcludesUnregisteredWhsePickAllocation() var From 177243cdb83011b3d38e5a8dda87916c79a83b18 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Tue, 11 Aug 2026 17:11:05 +0530 Subject: [PATCH 08/11] update RU Test --- src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index 26a0f0cf25c..f2857bf8063 100644 --- a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5698,7 +5698,7 @@ codeunit 137405 "SCM Item Tracking" end; [Test] - [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler,MessageHandler')] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler')] [Scope('OnPrem')] procedure GetAvailableLotQtyExcludesUnregisteredWhsePickAllocation() var From ed30724998eb26c67d51bca28ad3aaf1182bb8d6 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Thu, 13 Aug 2026 15:16:29 +0530 Subject: [PATCH 09/11] Update --- .../ItemTrackingDataCollection.Codeunit.al | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al index 4560348ed2d..7565ed47e76 100644 --- a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al +++ b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al @@ -555,6 +555,9 @@ codeunit 6501 "Item Tracking Data Collection" if TrackingSpecification."Item No." = '' then exit; + WhseActivLine.SetCurrentKey( + "Item No.", "Location Code", "Activity Type", "Bin Type Code", + "Unit of Measure Code", "Variant Code", "Breakbulk No.", "Action Type"); WhseActivLine.SetRange("Item No.", TrackingSpecification."Item No."); WhseActivLine.SetRange("Variant Code", TrackingSpecification."Variant Code"); WhseActivLine.SetRange("Location Code", TrackingSpecification."Location Code"); @@ -568,34 +571,38 @@ codeunit 6501 "Item Tracking Data Collection" if WhseActivLine.FindSet() then repeat if (WhseActivLine."Lot No." <> '') or (WhseActivLine."Serial No." <> '') or (WhseActivLine."Package No." <> '') then - if not PickBelongsToCurrentSource(WhseActivLine, TrackingSpecification) then begin - LastReservEntryNo -= 1; - TempGlobalReservEntry.Init(); - TempGlobalReservEntry."Entry No." := LastReservEntryNo; - TempGlobalReservEntry."Reservation Status" := TempGlobalReservEntry."Reservation Status"::Prospect; - TempGlobalReservEntry.Positive := false; - TempGlobalReservEntry."Item No." := WhseActivLine."Item No."; - TempGlobalReservEntry."Variant Code" := WhseActivLine."Variant Code"; - TempGlobalReservEntry."Location Code" := WhseActivLine."Location Code"; - TempGlobalReservEntry."Quantity (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; - TempGlobalReservEntry."Qty. to Handle (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; - TempGlobalReservEntry."Source Type" := Database::"Warehouse Activity Line"; - TempGlobalReservEntry."Source Subtype" := WhseActivLine."Activity Type".AsInteger(); - TempGlobalReservEntry."Source ID" := WhseActivLine."No."; - TempGlobalReservEntry."Source Ref. No." := WhseActivLine."Line No."; - TempGlobalReservEntry."Serial No." := WhseActivLine."Serial No."; - TempGlobalReservEntry."Lot No." := WhseActivLine."Lot No."; - TempGlobalReservEntry."Package No." := WhseActivLine."Package No."; - TempGlobalReservEntry."Shipment Date" := DMY2Date(31, 12, 9999); - if TempGlobalReservEntry.Insert() then - CreateEntrySummary(TrackingSpecification, TempGlobalReservEntry); - end; + if not PickBelongsToCurrentSource(WhseActivLine, TrackingSpecification) then + AddUnregisteredPickToTempRec(WhseActivLine, TrackingSpecification); until WhseActivLine.Next() = 0; OnAfterTransferUnregisteredPicksToTempRec(TrackingSpecification, TempGlobalReservEntry); end; - local procedure PickBelongsToCurrentSource(WhseActivLine: Record "Warehouse Activity Line"; TrackingSpecification: Record "Tracking Specification"): Boolean + local procedure AddUnregisteredPickToTempRec(var WhseActivLine: Record "Warehouse Activity Line"; var TrackingSpecification: Record "Tracking Specification" temporary) + begin + LastReservEntryNo -= 1; + TempGlobalReservEntry.Init(); + TempGlobalReservEntry."Entry No." := LastReservEntryNo; + TempGlobalReservEntry."Reservation Status" := TempGlobalReservEntry."Reservation Status"::Prospect; + TempGlobalReservEntry.Positive := false; + TempGlobalReservEntry."Item No." := WhseActivLine."Item No."; + TempGlobalReservEntry."Variant Code" := WhseActivLine."Variant Code"; + TempGlobalReservEntry."Location Code" := WhseActivLine."Location Code"; + TempGlobalReservEntry."Quantity (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; + TempGlobalReservEntry."Qty. to Handle (Base)" := -WhseActivLine."Qty. Outstanding (Base)"; + TempGlobalReservEntry."Source Type" := Database::"Warehouse Activity Line"; + TempGlobalReservEntry."Source Subtype" := WhseActivLine."Activity Type".AsInteger(); + TempGlobalReservEntry."Source ID" := WhseActivLine."No."; + TempGlobalReservEntry."Source Ref. No." := WhseActivLine."Line No."; + TempGlobalReservEntry."Serial No." := WhseActivLine."Serial No."; + TempGlobalReservEntry."Lot No." := WhseActivLine."Lot No."; + TempGlobalReservEntry."Package No." := WhseActivLine."Package No."; + TempGlobalReservEntry."Shipment Date" := DMY2Date(31, 12, 9999); + TempGlobalReservEntry.Insert(); + CreateEntrySummary(TrackingSpecification, TempGlobalReservEntry); + end; + + local procedure PickBelongsToCurrentSource(var WhseActivLine: Record "Warehouse Activity Line"; var TrackingSpecification: Record "Tracking Specification" temporary): Boolean begin exit( (WhseActivLine."Source Type" = TrackingSpecification."Source Type") and From e8d5e26714fa32dc0fe069a37c1b2041a52145e3 Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Thu, 13 Aug 2026 18:11:43 +0530 Subject: [PATCH 10/11] Update suggestion 5 --- .../SCMItemTracking.Codeunit.al | 66 +++++++++++++++++++ .../ItemTrackingDataCollection.Codeunit.al | 6 +- .../SCMItemTracking.Codeunit.al | 66 +++++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index f2857bf8063..01fd61a1450 100644 --- a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5737,6 +5737,46 @@ codeunit 137405 "SCM Item Tracking" LibraryVariableStorage.AssertEmpty(); end; + [Test] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler')] + [Scope('OnPrem')] + procedure GetAvailableLotQtyExcludesUnregisteredInvtPickAllocation() + var + Item: Record Item; + Location: Record Location; + WarehouseActivityHeader: Record "Warehouse Activity Header"; + WarehouseActivityLine: Record "Warehouse Activity Line"; + TrackingSpecification: Record "Tracking Specification"; + ItemTrackingDataCollection: Codeunit "Item Tracking Data Collection"; + LotNo: Code[50]; + Qty: Integer; + begin + // [Bug 638344] Available lot quantity must exclude quantities committed to an unregistered inventory pick + // [SCENARIO] A lot fully allocated to an unregistered Invt. Pick line (blank Action Type) is not reported as available for a different demand source + Initialize(); + + // [GIVEN] Lot-tracked item with lot warehouse tracking, in stock at a location for lot "L" with qty "Q" + Qty := LibraryRandom.RandIntInRange(20, 50); + LotNo := LibraryUtility.GenerateGUID(); + CreateLotTrackedItemAtLocation(Item, Location); + CreateAndPostLotStockForPick(Item."No.", Location.Code, LotNo, Qty); + + // [GIVEN] An unregistered inventory pick line reserves the full lot quantity for a different sales line + CreateUnregisteredInvtPickLine( + WarehouseActivityHeader, WarehouseActivityLine, Item."No.", Location.Code, LotNo, Qty, + Database::"Sales Line", 1, LibraryUtility.GenerateGUID(), 10000); + + // [WHEN] Available lot quantity is retrieved for a new demand on the same lot + SetTrackingSpecItemLotLocation(TrackingSpecification, Item."No.", Location.Code, LotNo); + + // [THEN] Available quantity is zero because the on-hand lot is fully committed to the unregistered inventory pick + Assert.AreEqual( + 0, ItemTrackingDataCollection.GetAvailableLotQty(TrackingSpecification), + 'Available lot quantity must exclude quantities allocated to unregistered inventory picks.'); + + LibraryVariableStorage.AssertEmpty(); + end; + local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) var InventoryPostingSetup: Record "Inventory Posting Setup"; @@ -5788,6 +5828,32 @@ codeunit 137405 "SCM Item Tracking" WarehouseActivityLine.Insert(false); end; + local procedure CreateUnregisteredInvtPickLine(var WarehouseActivityHeader: Record "Warehouse Activity Header"; var WarehouseActivityLine: Record "Warehouse Activity Line"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Decimal; SourceType: Integer; SourceSubtype: Integer; SourceNo: Code[20]; SourceLineNo: Integer) + begin + WarehouseActivityHeader.Init(); + WarehouseActivityHeader.Type := WarehouseActivityHeader.Type::"Invt. Pick"; + WarehouseActivityHeader."No." := LibraryUtility.GenerateGUID(); + WarehouseActivityHeader."Location Code" := LocationCode; + WarehouseActivityHeader.Insert(false); + + WarehouseActivityLine.Init(); + WarehouseActivityLine."Activity Type" := WarehouseActivityLine."Activity Type"::"Invt. Pick"; + WarehouseActivityLine."No." := WarehouseActivityHeader."No."; + WarehouseActivityLine."Line No." := 10000; + WarehouseActivityLine."Action Type" := WarehouseActivityLine."Action Type"::" "; + WarehouseActivityLine."Item No." := ItemNo; + WarehouseActivityLine."Location Code" := LocationCode; + WarehouseActivityLine."Lot No." := LotNo; + WarehouseActivityLine."Qty. Outstanding" := Qty; + WarehouseActivityLine."Qty. Outstanding (Base)" := Qty; + WarehouseActivityLine."Breakbulk No." := 0; + WarehouseActivityLine."Source Type" := SourceType; + WarehouseActivityLine."Source Subtype" := SourceSubtype; + WarehouseActivityLine."Source No." := SourceNo; + WarehouseActivityLine."Source Line No." := SourceLineNo; + WarehouseActivityLine.Insert(false); + end; + local procedure CreateAndPostLotStockForPick(ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Integer) var ItemJournalLine: Record "Item Journal Line"; diff --git a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al index 7565ed47e76..7a6742de8a8 100644 --- a/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al +++ b/src/Layers/W1/BaseApp/Inventory/Tracking/ItemTrackingDataCollection.Codeunit.al @@ -558,10 +558,14 @@ codeunit 6501 "Item Tracking Data Collection" WhseActivLine.SetCurrentKey( "Item No.", "Location Code", "Activity Type", "Bin Type Code", "Unit of Measure Code", "Variant Code", "Breakbulk No.", "Action Type"); + WhseActivLine.SetLoadFields( + "Item No.", "Variant Code", "Location Code", "Activity Type", "No.", "Line No.", + "Source Type", "Source Subtype", "Source No.", "Source Line No.", + "Lot No.", "Serial No.", "Package No.", "Qty. Outstanding (Base)"); WhseActivLine.SetRange("Item No.", TrackingSpecification."Item No."); WhseActivLine.SetRange("Variant Code", TrackingSpecification."Variant Code"); WhseActivLine.SetRange("Location Code", TrackingSpecification."Location Code"); - WhseActivLine.SetRange("Activity Type", WhseActivLine."Activity Type"::Pick); + WhseActivLine.SetFilter("Activity Type", '%1|%2', WhseActivLine."Activity Type"::Pick, WhseActivLine."Activity Type"::"Invt. Pick"); // Blank Action Type covers Inventory Pick lines (single-step pick with no Take/Place split). WhseActivLine.SetFilter("Action Type", '%1|%2', WhseActivLine."Action Type"::Take, WhseActivLine."Action Type"::" "); WhseActivLine.SetRange("Breakbulk No.", 0); diff --git a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index e59139639d0..53fccae701e 100644 --- a/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/W1/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5731,6 +5731,46 @@ codeunit 137405 "SCM Item Tracking" LibraryVariableStorage.AssertEmpty(); end; + [Test] + [HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler')] + [Scope('OnPrem')] + procedure GetAvailableLotQtyExcludesUnregisteredInvtPickAllocation() + var + Item: Record Item; + Location: Record Location; + WarehouseActivityHeader: Record "Warehouse Activity Header"; + WarehouseActivityLine: Record "Warehouse Activity Line"; + TrackingSpecification: Record "Tracking Specification"; + ItemTrackingDataCollection: Codeunit "Item Tracking Data Collection"; + LotNo: Code[50]; + Qty: Integer; + begin + // [Bug 638344] Available lot quantity must exclude quantities committed to an unregistered inventory pick + // [SCENARIO] A lot fully allocated to an unregistered Invt. Pick line (blank Action Type) is not reported as available for a different demand source + Initialize(); + + // [GIVEN] Lot-tracked item with lot warehouse tracking, in stock at a location for lot "L" with qty "Q" + Qty := LibraryRandom.RandIntInRange(20, 50); + LotNo := LibraryUtility.GenerateGUID(); + CreateLotTrackedItemAtLocation(Item, Location); + CreateAndPostLotStockForPick(Item."No.", Location.Code, LotNo, Qty); + + // [GIVEN] An unregistered inventory pick line reserves the full lot quantity for a different sales line + CreateUnregisteredInvtPickLine( + WarehouseActivityHeader, WarehouseActivityLine, Item."No.", Location.Code, LotNo, Qty, + Database::"Sales Line", 1, LibraryUtility.GenerateGUID(), 10000); + + // [WHEN] Available lot quantity is retrieved for a new demand on the same lot + SetTrackingSpecItemLotLocation(TrackingSpecification, Item."No.", Location.Code, LotNo); + + // [THEN] Available quantity is zero because the on-hand lot is fully committed to the unregistered inventory pick + Assert.AreEqual( + 0, ItemTrackingDataCollection.GetAvailableLotQty(TrackingSpecification), + 'Available lot quantity must exclude quantities allocated to unregistered inventory picks.'); + + LibraryVariableStorage.AssertEmpty(); + end; + local procedure CreateLotTrackedItemAtLocation(var Item: Record Item; var Location: Record Location) var InventoryPostingSetup: Record "Inventory Posting Setup"; @@ -5782,6 +5822,32 @@ codeunit 137405 "SCM Item Tracking" WarehouseActivityLine.Insert(false); end; + local procedure CreateUnregisteredInvtPickLine(var WarehouseActivityHeader: Record "Warehouse Activity Header"; var WarehouseActivityLine: Record "Warehouse Activity Line"; ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Decimal; SourceType: Integer; SourceSubtype: Integer; SourceNo: Code[20]; SourceLineNo: Integer) + begin + WarehouseActivityHeader.Init(); + WarehouseActivityHeader.Type := WarehouseActivityHeader.Type::"Invt. Pick"; + WarehouseActivityHeader."No." := LibraryUtility.GenerateGUID(); + WarehouseActivityHeader."Location Code" := LocationCode; + WarehouseActivityHeader.Insert(false); + + WarehouseActivityLine.Init(); + WarehouseActivityLine."Activity Type" := WarehouseActivityLine."Activity Type"::"Invt. Pick"; + WarehouseActivityLine."No." := WarehouseActivityHeader."No."; + WarehouseActivityLine."Line No." := 10000; + WarehouseActivityLine."Action Type" := WarehouseActivityLine."Action Type"::" "; + WarehouseActivityLine."Item No." := ItemNo; + WarehouseActivityLine."Location Code" := LocationCode; + WarehouseActivityLine."Lot No." := LotNo; + WarehouseActivityLine."Qty. Outstanding" := Qty; + WarehouseActivityLine."Qty. Outstanding (Base)" := Qty; + WarehouseActivityLine."Breakbulk No." := 0; + WarehouseActivityLine."Source Type" := SourceType; + WarehouseActivityLine."Source Subtype" := SourceSubtype; + WarehouseActivityLine."Source No." := SourceNo; + WarehouseActivityLine."Source Line No." := SourceLineNo; + WarehouseActivityLine.Insert(false); + end; + local procedure CreateAndPostLotStockForPick(ItemNo: Code[20]; LocationCode: Code[10]; LotNo: Code[50]; Qty: Integer) var ItemJournalLine: Record "Item Journal Line"; From 4f9c51f62ac90011f949c79dc0202657a02a9d6d Mon Sep 17 00:00:00 2001 From: v-shikhverma Date: Wed, 19 Aug 2026 19:01:19 +0530 Subject: [PATCH 11/11] update --- src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al index 01fd61a1450..1b76b69d19f 100644 --- a/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al +++ b/src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al @@ -5782,7 +5782,7 @@ codeunit 137405 "SCM Item Tracking" InventoryPostingSetup: Record "Inventory Posting Setup"; ItemTrackingCodeCode: Code[10]; begin - LibraryWarehouse.CreateLocation(Location); + LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location); Location.Validate("Require Pick", true); Location.Validate("Require Shipment", true); Location.Modify(true);