Skip to content
Open
157 changes: 157 additions & 0 deletions src/Layers/RU/Tests/SCM-Reservation/SCMItemTracking.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -5697,6 +5697,163 @@ codeunit 137405 "SCM Item Tracking"
LibraryVariableStorage.AssertEmpty();
end;

[Test]
Comment thread
Shikhverma marked this conversation as resolved.
[HandlerFunctions('ItemTrackingLinesLotSNQtyModalPageHandler')]
[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;

[Test]
Comment thread
Shikhverma marked this conversation as resolved.
[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";
ItemTrackingCodeCode: Code[10];
begin
LibraryWarehouse.CreateLocationWithInventoryPostingSetup(Location);
Location.Validate("Require Pick", true);
Location.Validate("Require Shipment", true);
Location.Modify(true);

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])
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)
Comment thread
Shikhverma marked this conversation as resolved.
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 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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -455,6 +456,8 @@ codeunit 6501 "Item Tracking Data Collection"
end;
until TempTrackingSpecification.Next() = 0;

TransferUnregisteredPicksToTempRec(TempTrackingSpecification2);
Comment thread
Shikhverma marked this conversation as resolved.

OnRetrieveLookupDataOnAfterTransferToTempRec(TempGlobalEntrySummary, TempTrackingSpecification, ItemLedgEntry, LastSummaryEntryNo);

TempGlobalEntrySummary.Reset();
Expand Down Expand Up @@ -539,6 +542,79 @@ codeunit 6501 "Item Tracking Data Collection"
until TempReservEntry.Next() = 0;
end;

local procedure TransferUnregisteredPicksToTempRec(var TrackingSpecification: Record "Tracking Specification" temporary)
Comment thread
Shikhverma marked this conversation as resolved.
var
WhseActivLine: Record "Warehouse Activity Line";
IsHandled: Boolean;
begin
IsHandled := false;
Comment thread
Shikhverma marked this conversation as resolved.
OnBeforeTransferUnregisteredPicksToTempRec(TrackingSpecification, TempGlobalReservEntry, IsHandled);
if IsHandled then
exit;

if TrackingSpecification."Item No." = '' then
exit;

WhseActivLine.SetCurrentKey(
Comment thread
Shikhverma marked this conversation as resolved.
Comment thread
Shikhverma marked this conversation as resolved.
"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.");
Comment thread
Shikhverma marked this conversation as resolved.
WhseActivLine.SetRange("Variant Code", TrackingSpecification."Variant Code");
WhseActivLine.SetRange("Location Code", TrackingSpecification."Location Code");
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);
WhseActivLine.SetFilter("Qty. Outstanding (Base)", '>%1', 0);
OnTransferUnregisteredPicksToTempRecOnAfterSetFilters(WhseActivLine, TrackingSpecification);

if WhseActivLine.FindSet() then
Comment thread
Shikhverma marked this conversation as resolved.
repeat
if (WhseActivLine."Lot No." <> '') or (WhseActivLine."Serial No." <> '') or (WhseActivLine."Package No." <> '') then
if not PickBelongsToCurrentSource(WhseActivLine, TrackingSpecification) then
AddUnregisteredPickToTempRec(WhseActivLine, TrackingSpecification);
until WhseActivLine.Next() = 0;

OnAfterTransferUnregisteredPicksToTempRec(TrackingSpecification, TempGlobalReservEntry);
end;

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
(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);
Expand Down Expand Up @@ -1537,6 +1613,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)
Comment thread
Shikhverma marked this conversation as resolved.
begin
end;

[IntegrationEvent(false, false)]
local procedure OnTransferUnregisteredPicksToTempRecOnAfterSetFilters(var WhseActivLine: Record "Warehouse Activity Line"; TrackingSpecification: Record "Tracking Specification")
Comment thread
Shikhverma marked this conversation as resolved.
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
Expand Down
Loading
Loading