Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2911,6 +2911,12 @@ codeunit 99000854 "Inventory Profile Offsetting"
ReqLine.Validate(
Quantity,
Round(SupplyInventoryProfile."Remaining Quantity (Base)" / SupplyInventoryProfile."Qty. per Unit of Measure", UOMMgt.QtyRndPrecision()));

if Abs(ReqLine."Quantity (Base)" - SupplyInventoryProfile."Remaining Quantity (Base)") <= UOMMgt.QtyRndPrecision() then
if ReqLine."Quantity (Base)" <> SupplyInventoryProfile."Remaining Quantity (Base)" then begin
ReqLine."Remaining Qty. (Base)" += SupplyInventoryProfile."Remaining Quantity (Base)" - ReqLine."Quantity (Base)";
ReqLine."Quantity (Base)" := SupplyInventoryProfile."Remaining Quantity (Base)";
end;
end;

local procedure UpdateReqLineOriginalQuantity(var SupplyInventoryProfile: Record "Inventory Profile")
Expand Down
82 changes: 82 additions & 0 deletions src/Layers/W1/Tests/SCM/SCMPlanningNTFtests.Codeunit.al
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,50 @@ codeunit 137021 "SCM Planning - NTF tests"
LibraryJob.CreateJobTask(Job, JobTask);
end;

local procedure CreateItemWithNonBasePurchUoM(var Item: Record Item; var ItemUnitOfMeasure: Record "Item Unit of Measure"; QtyPerUoM: Decimal)
begin
ItemSetup(Item, Item."Replenishment System"::Purchase, '<0D>');
Item.Validate("Reordering Policy", Item."Reordering Policy"::"Lot-for-Lot");
Item.Validate("Vendor No.", LibraryPurchase.CreateVendorNo());
LibraryInventory.CreateItemUnitOfMeasureCode(ItemUnitOfMeasure, Item."No.", QtyPerUoM);
Item.Validate("Purch. Unit of Measure", ItemUnitOfMeasure.Code);
Item.Modify(true);
end;

local procedure AcceptAndCarryOutActionMessage(ItemNo: Code[20])
var
RequisitionLine: Record "Requisition Line";
begin
RequisitionLine.SetRange(Type, RequisitionLine.Type::Item);
RequisitionLine.SetRange("No.", ItemNo);
RequisitionLine.FindSet(true);
repeat
RequisitionLine.Validate("Accept Action Message", true);
RequisitionLine.Modify(true);
until RequisitionLine.Next() = 0;
LibraryPlanning.CarryOutActionMsgPlanWksh(RequisitionLine);
end;

local procedure FindPurchaseLineByItemNo(var PurchaseLine: Record "Purchase Line"; ItemNo: Code[20])
begin
PurchaseLine.SetRange("Document Type", PurchaseLine."Document Type"::Order);
PurchaseLine.SetRange(Type, PurchaseLine.Type::Item);
PurchaseLine.SetRange("No.", ItemNo);
PurchaseLine.FindFirst();
end;

local procedure VerifyReservEntryQtyBase(SourceType: Integer; SourceSubtype: Integer; SourceID: Code[20]; ExpectedQtyBase: Decimal)
var
ReservationEntry: Record "Reservation Entry";
begin
ReservationEntry.SetRange("Source Type", SourceType);
ReservationEntry.SetRange("Source Subtype", SourceSubtype);
ReservationEntry.SetRange("Source ID", SourceID);
ReservationEntry.FindFirst();
Assert.AreEqual(ExpectedQtyBase, Abs(ReservationEntry."Quantity (Base)"),
'Reservation Entry Quantity (Base) must match demand.');
end;

local procedure CreateSaleDocType(var SalesHeader: Record "Sales Header"; DocumentType: Enum "Sales Document Type"; Item: Record Item; SalesQty: Integer; ShipmentDate: Date; LocationCode: Code[10])
var
SalesLine: Record "Sales Line";
Expand Down Expand Up @@ -3647,6 +3691,44 @@ codeunit 137021 "SCM Planning - NTF tests"
RequisitionLine."Ref. Order Type"::Transfer, LocationTwo.Code, 1);
end;

[Test]
[Scope('OnPrem')]
procedure JobPlanLineNonBaseUoMCarryOutDeletePlanLine()
var
Item: Record Item;
ItemUnitOfMeasure: Record "Item Unit of Measure";
JobTask: Record "Job Task";
JobPlanningLine: Record "Job Planning Line";
PurchaseHeader: Record "Purchase Header";
PurchaseLine: Record "Purchase Line";
QtyPerUoM: Decimal;
JobQuantity: Decimal;
begin
// [SCENARIO 640455] Cannot delete Project Planning Line due to incorrect reservation entries

Initialize();

// [GIVEN] Item "I" with non-base Purchase UoM "U" with random Qty per UoM, Reordering Policy = Lot-for-Lot, and Job Planning Line "J" with random quantity.
TestSetup();
QtyPerUoM := LibraryRandom.RandIntInRange(2, 5);
JobQuantity := LibraryRandom.RandIntInRange(1, 5);
CreateItemWithNonBasePurchUoM(Item, ItemUnitOfMeasure, QtyPerUoM);
CreateJobAndPlanningLine(JobTask, JobPlanningLine, Item."No.", JobQuantity, true);

// [WHEN] Calculate Regenerative Plan is run and Action Message is carried out to create a Purchase Order "P".
LibraryPlanning.CalcRegenPlanForPlanWksh(Item, WorkDate(), CalcDate(PlanningEndDate, WorkDate()));
AcceptAndCarryOutActionMessage(Item."No.");

// [THEN] Reservation entries linked to "P" have correct Quantity (Base) matching "J" quantity, and deleting "P" and then "J" succeeds without error.
FindPurchaseLineByItemNo(PurchaseLine, Item."No.");
PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, PurchaseLine."Document No.");
VerifyReservEntryQtyBase(
Database::"Purchase Line", PurchaseHeader."Document Type".AsInteger(), PurchaseHeader."No.", JobQuantity);
PurchaseHeader.Delete(true);
JobPlanningLine.Find();
JobPlanningLine.Delete(true);
end;

[ModalPageHandler]
[Scope('OnPrem')]
procedure ItemTrackingPageHandler(var ItemTrackingLines: TestPage "Item Tracking Lines")
Expand Down
Loading