Codeunit 311 Item-Check Avail.
- App
- Base Application
- Namespace
- Microsoft.Inventory.Availability
- Versions
- 17-28
Procedures, 28Events, 36Obsolete, 5
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/Inventory/Availability/ItemCheckAvail.Codeunit.al922 lines, Copyright (c) Microsoft Corporation. MIT
// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------
namespace Microsoft.Inventory.Availability;
using Microsoft.Assembly.Document;
using Microsoft.Foundation.Company;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory.Document;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Transfer;
using Microsoft.Projects.Project.Planning;
using Microsoft.Sales.Document;
using Microsoft.Sales.Setup;
using System.Environment.Configuration;
codeunit 311 "Item-Check Avail."
{
Permissions = TableData "My Notifications" = rimd;
trigger OnRun()
begin
end;
var
AvailableToPromise: Codeunit "Available to Promise";
NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
UOMMgt: Codeunit "Unit of Measure Management";
AssemblyLineDueDateGlobal: Date;
ItemNo: Code[20];
UnitOfMeasureCode: Code[10];
ItemLocationCode: Code[10];
VariantCode: Code[10];
NewItemNetChange: Decimal;
OldItemNetChange: Decimal;
OldItemNetResChange: Decimal;
NewItemNetResChange: Decimal;
ItemNetChange: Decimal;
QtyPerUnitOfMeasure: Decimal;
InitialQtyAvailable: Decimal;
UseOrderPromise: Boolean;
GrossReq: Decimal;
ReservedReq: Decimal;
SchedRcpt: Decimal;
ReservedRcpt: Decimal;
EarliestAvailDate: Date;
InventoryQty: Decimal;
OldItemShipmentDate: Date;
ContextInfo: Dictionary of [Text, Text];
#pragma warning disable AA0074
Text000: Label 'The update has been interrupted to respect the warning.';
#pragma warning restore AA0074
NotificationMsg: Label 'The available inventory for item %1 is lower than the entered quantity at this location.', Comment = '%1=Item No.';
DetailsTxt: Label 'Show details';
ItemAvailabilityNotificationTxt: Label 'Item availability is low.';
ItemAvailabilityNotificationDescriptionTxt: Label 'Show a warning when someone creates a sales order or sales invoice for an item that is out of stock.';
DontShowAgainTxt: Label 'Don''t show again';
procedure ItemJnlCheckLine(ItemJnlLine: Record "Item Journal Line") Rollback: Boolean
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeItemJnlCheckLine(ItemJnlLine, Rollback, IsHandled);
if IsHandled then
exit(Rollback);
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
ItemJnlLine.RecordId, GetItemAvailabilityNotificationId(), true);
if ItemJnlLineShowWarning(ItemJnlLine) then
Rollback := ShowAndHandleAvailabilityPage(ItemJnlLine.RecordId);
end;
procedure SalesLineCheck(SalesLine: Record "Sales Line") Rollback: Boolean
var
TempAsmHeader: Record "Assembly Header" temporary;
TempAsmLine: Record "Assembly Line" temporary;
ATOLink: Record "Assemble-to-Order Link";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSalesLineCheck(SalesLine, Rollback, IsHandled);
if IsHandled then
exit(Rollback);
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
SalesLine.RecordId, GetItemAvailabilityNotificationId(), true);
if SalesLineShowWarning(SalesLine) then
Rollback := ShowAndHandleAvailabilityPage(SalesLine.RecordId);
OnSalesLineCheckOnAfterSalesLineShowWarning(SalesLine, Rollback);
if not Rollback then
if ATOLink.SalesLineCheckAvailShowWarning(SalesLine, TempAsmHeader, TempAsmLine) then
Rollback := ShowAsmWarningYesNo(TempAsmHeader, TempAsmLine);
end;
procedure TransferLineCheck(TransLine: Record "Transfer Line") Rollback: Boolean
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTransferLineCheck(TransLine, Rollback, IsHandled);
if IsHandled then
exit(Rollback);
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
TransLine.RecordId, GetItemAvailabilityNotificationId(), true);
if TransferLineShowWarning(TransLine) then
Rollback := ShowAndHandleAvailabilityPage(TransLine.RecordId);
end;
procedure JobPlanningLineCheck(JobPlanningLine: Record "Job Planning Line") Rollback: Boolean
begin
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
JobPlanningLine.RecordId, GetItemAvailabilityNotificationId(), true);
if JobPlanningLineShowWarning(JobPlanningLine) then
Rollback := ShowAndHandleAvailabilityPage(JobPlanningLine.RecordId);
end;
procedure AssemblyLineCheck(AssemblyLine: Record "Assembly Line") Rollback: Boolean
begin
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
AssemblyLine.RecordId, GetItemAvailabilityNotificationId(), true);
if AsmOrderLineShowWarning(AssemblyLine) then
Rollback := ShowAndHandleAvailabilityPage(AssemblyLine.RecordId);
end;
procedure ShowAsmWarningYesNo(var AsmHeader: Record "Assembly Header"; var AsmLine: Record "Assembly Line") Rollback: Boolean
var
AsmLineMgt: Codeunit "Assembly Line Management";
begin
Rollback := AsmLineMgt.ShowAvailability(false, AsmHeader, AsmLine);
end;
procedure ItemJnlLineShowWarning(ItemJnlLine: Record "Item Journal Line"): Boolean
var
IsHandled: Boolean;
begin
if not ShowWarningForThisItem(ItemJnlLine."Item No.") then
exit(false);
case ItemJnlLine."Entry Type" of
ItemJnlLine."Entry Type"::Purchase, ItemJnlLine."Entry Type"::"Positive Adjmt.":
ItemNetChange := ItemJnlLine.Quantity;
ItemJnlLine."Entry Type"::Sale, ItemJnlLine."Entry Type"::"Negative Adjmt.", ItemJnlLine."Entry Type"::Transfer:
ItemNetChange := -ItemJnlLine.Quantity;
end;
IsHandled := false;
OnAfterItemJnlLineShowWarning(ItemJnlLine, ItemNetChange, IsHandled);
if IsHandled then
exit(false);
exit(
ShowWarning(
ItemJnlLine."Item No.",
ItemJnlLine."Variant Code",
ItemJnlLine."Location Code",
ItemJnlLine."Unit of Measure Code",
ItemJnlLine."Qty. per Unit of Measure",
ItemNetChange,
0,
0D,
0D));
end;
procedure SalesLineShowWarning(SalesLine: Record "Sales Line"): Boolean
var
OldSalesLine: Record "Sales Line";
CompanyInfo: Record "Company Information";
LookAheadDate: Date;
IsHandled: Boolean;
IsWarning: Boolean;
begin
IsHandled := false;
OnBeforeSalesLineShowWarning(SalesLine, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
if SalesLine."Drop Shipment" then
exit(false);
if SalesLine.IsNonInventoriableItem() then
exit(false);
if SalesLine.FullQtyIsForAsmToOrder() then
exit(false);
if not ShowWarningForThisItem(SalesLine."No.") then
exit(false);
Clear(AvailableToPromise);
OldItemNetChange := 0;
OldSalesLine := SalesLine;
if OldSalesLine.Find() then begin // Find previous quantity within Check-Avail. Period
CompanyInfo.SetLoadFields("Check-Avail. Period Calc.", "Check-Avail. Time Bucket");
CompanyInfo.Get();
LookAheadDate :=
AvailableToPromise.GetForwardPeriodEndDate(
CompanyInfo."Check-Avail. Period Calc.", CompanyInfo."Check-Avail. Time Bucket", SalesLine."Shipment Date");
if (OldSalesLine."Document Type" = OldSalesLine."Document Type"::Order) and
(OldSalesLine."No." = SalesLine."No.") and
(OldSalesLine."Variant Code" = SalesLine."Variant Code") and
(OldSalesLine."Location Code" = SalesLine."Location Code") and
(OldSalesLine."Bin Code" = SalesLine."Bin Code") and
not OldSalesLine."Drop Shipment" and
(OldSalesLine."Shipment Date" <= LookAheadDate)
then begin
IsHandled := false;
OnSalesLineShowWarningOnAfterFindingPrevSalesLineQtyWithinPeriod(SalesLine, OldSalesLine, IsHandled);
if not IsHandled then
if OldSalesLine."Shipment Date" > SalesLine."Shipment Date" then
AvailableToPromise.SetChangedSalesLine(OldSalesLine)
else begin
OldItemNetChange := -OldSalesLine."Outstanding Qty. (Base)";
OldSalesLine.CalcFields("Reserved Qty. (Base)");
OldItemNetResChange := -OldSalesLine."Reserved Qty. (Base)";
end;
end;
end;
NewItemNetResChange := -(SalesLine."Qty. to Asm. to Order (Base)" - OldSalesLine.QtyBaseOnATO());
if SalesLine."Document Type" = SalesLine."Document Type"::Order then
UseOrderPromise := true;
IsHandled := false;
OnSalesLineShowWarningOnBeforeShowWarning(SalesLine, ContextInfo, OldSalesLine, IsWarning, IsHandled, OldItemNetChange);
if IsHandled then
exit(IsWarning);
exit(
ShowWarning(
SalesLine."No.",
SalesLine."Variant Code",
SalesLine."Location Code",
SalesLine."Unit of Measure Code",
SalesLine."Qty. per Unit of Measure",
-SalesLine."Outstanding Quantity",
OldItemNetChange,
SalesLine."Shipment Date",
OldSalesLine."Shipment Date"));
end;
procedure ShowWarning(ItemNoArg: Code[20]; ItemVariantCodeArg: Code[10]; ItemLocationCodeArg: Code[10]; UnitOfMeasureCodeArg: Code[10]; QtyPerUnitOfMeasureArg: Decimal; NewItemNetChangeArg: Decimal; OldItemNetChangeArg: Decimal; ShipmentDateArg: Date; OldShipmentDateArg: Date) Result: Boolean
var
Item: Record Item;
IsHandled: Boolean;
begin
ItemNo := ItemNoArg;
UnitOfMeasureCode := UnitOfMeasureCodeArg;
QtyPerUnitOfMeasure := QtyPerUnitOfMeasureArg;
NewItemNetChange := NewItemNetChangeArg;
OldItemNetChange := ConvertQty(OldItemNetChangeArg);
OldItemShipmentDate := OldShipmentDateArg;
ItemLocationCode := ItemLocationCodeArg;
VariantCode := ItemVariantCodeArg;
if NewItemNetChange >= 0 then
exit(false);
SetFilterOnItem(Item, ItemNo, ItemVariantCodeArg, ItemLocationCode, ShipmentDateArg);
Calculate(Item);
IsHandled := false;
OnShowWarningOnAfterCalculate(ItemNo, InventoryQty, ItemNetChange, InitialQtyAvailable, OldItemNetResChange, Result, IsHandled);
if IsHandled then
exit(Result);
exit(InitialQtyAvailable + ItemNetChange < 0);
end;
local procedure SetFilterOnItem(var Item: Record Item; ItemNo: Code[20]; ItemVariantCode: Code[10]; ItemLocationCode: Code[10]; ShipmentDate: Date)
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeSetFilterOnItem(Item, ItemNo, ItemVariantCode, ItemLocationCode, ShipmentDate, UseOrderPromise, IsHandled, UnitOfMeasureCode);
if IsHandled then
exit;
Item.Get(ItemNo);
Item.SetRange("No.", ItemNo);
Item.SetRange("Variant Filter", ItemVariantCode);
Item.SetRange("Location Filter", ItemLocationCode);
Item.SetRange("Drop Shipment Filter", false);
if UseOrderPromise then
Item.SetRange("Date Filter", 0D, ShipmentDate)
else
Item.SetRange("Date Filter", 0D, WorkDate());
end;
local procedure Calculate(var Item: Record Item)
var
CompanyInfo: Record "Company Information";
begin
CompanyInfo.Get();
QtyAvailToPromise(Item, CompanyInfo);
EarliestAvailDate := EarliestAvailabilityDate(Item, CompanyInfo);
if not UseOrderPromise then
SchedRcpt := 0;
OldItemNetResChange := ConvertQty(OldItemNetResChange);
NewItemNetResChange := ConvertQty(NewItemNetResChange);
ItemNetChange := 0;
if Item."No." = ItemNo then begin
ItemNetChange := NewItemNetChange;
if GrossReq + OldItemNetChange >= 0 then
GrossReq := GrossReq + OldItemNetChange;
end;
OnCalculateOnBeforeCalcInitialQtyAvailable(Item, SchedRcpt, ReservedRcpt, GrossReq, ReservedReq, OldItemNetResChange, NewItemNetResChange, ContextInfo, InventoryQty);
InitialQtyAvailable :=
InventoryQty +
(SchedRcpt - ReservedRcpt) - (GrossReq - ReservedReq) -
NewItemNetResChange;
OnAfterCalculate(Item, InitialQtyAvailable, OldItemNetChange, QtyPerUnitOfMeasure, ContextInfo);
end;
local procedure QtyAvailToPromise(var Item: Record Item; CompanyInfo: Record "Company Information")
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeQtyAvailToPromise(Item, CompanyInfo, InventoryQty, GrossReq, ReservedReq, OldItemNetResChange, SchedRcpt, ReservedRcpt, IsHandled);
if IsHandled then
exit;
AvailableToPromise.CalcQtyAvailabletoPromise(Item, GrossReq, SchedRcpt, CheckAvailabilityDate(Item, AssemblyLineDueDateGlobal),
CompanyInfo."Check-Avail. Time Bucket", CompanyInfo."Check-Avail. Period Calc.");
InventoryQty := ConvertQty(AvailableToPromise.CalcAvailableInventory(Item) - OldItemNetResChange);
GrossReq := ConvertQty(GrossReq);
ReservedReq := ConvertQty(AvailableToPromise.CalcReservedRequirement(Item) + OldItemNetResChange);
SchedRcpt := ConvertQty(SchedRcpt);
ReservedRcpt := ConvertQty(AvailableToPromise.CalcReservedReceipt(Item));
end;
local procedure EarliestAvailabilityDate(var Item: Record Item; CompanyInfo: Record "Company Information"): Date
var
AvailableQty: Decimal;
NewItemNetChangeBase: Decimal;
OldItemNetChangeBase: Decimal;
begin
NewItemNetChangeBase := ConvertQtyToBaseQty(NewItemNetChange);
OldItemNetChangeBase := ConvertQtyToBaseQty(OldItemNetChange);
exit(
AvailableToPromise.CalcEarliestAvailabilityDate(
Item, -NewItemNetChangeBase, Item.GetRangeMax("Date Filter"), -OldItemNetChangeBase, OldItemShipmentDate, AvailableQty,
CompanyInfo."Check-Avail. Time Bucket", CompanyInfo."Check-Avail. Period Calc."));
end;
local procedure ConvertQty(Qty: Decimal) Result: Decimal
begin
if QtyPerUnitOfMeasure = 0 then
QtyPerUnitOfMeasure := 1;
Result := Round(Qty / QtyPerUnitOfMeasure, UOMMgt.QtyRndPrecision());
OnAfterConvertQty(ItemNo, Qty, QtyPerUnitOfMeasure, Result);
end;
local procedure ConvertQtyToBaseQty(Qty: Decimal) Result: Decimal
begin
if QtyPerUnitOfMeasure = 0 then
QtyPerUnitOfMeasure := 1;
Result := Round(Qty * QtyPerUnitOfMeasure, UOMMgt.QtyRndPrecision());
OnAfterConvertQtyToBaseQty(ItemNo, Qty, QtyPerUnitOfMeasure, Result);
end;
procedure TransferLineShowWarning(TransLine: Record "Transfer Line") IsWarning: Boolean
var
OldTransLine: Record "Transfer Line";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeTransferLineShowWarning(TransLine, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
if not ShowWarningForThisItem(TransLine."Item No.") then
exit(false);
UseOrderPromise := true;
OldTransLine := TransLine;
if OldTransLine.Find() then // Find previous quantity
if (OldTransLine."Item No." = TransLine."Item No.") and
(OldTransLine."Variant Code" = TransLine."Variant Code") and
(OldTransLine."Transfer-from Code" = TransLine."Transfer-from Code")
then begin
OldItemNetChange := -OldTransLine."Outstanding Qty. (Base)";
OldTransLine.CalcFields("Reserved Qty. Outbnd. (Base)");
OldItemNetResChange := -OldTransLine."Reserved Qty. Outbnd. (Base)";
end;
IsHandled := false;
OnTransferLineShowWarningOnBeforeShowWarning(TransLine, ContextInfo, OldTransLine, OldItemNetChange, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
exit(
ShowWarning(
TransLine."Item No.",
TransLine."Variant Code",
TransLine."Transfer-from Code",
TransLine."Unit of Measure Code",
TransLine."Qty. per Unit of Measure",
-TransLine."Outstanding Quantity",
OldItemNetChange,
TransLine."Shipment Date",
OldTransLine."Shipment Date"));
end;
procedure JobPlanningLineShowWarning(JobPlanningLine: Record "Job Planning Line") IsWarning: Boolean
var
OldJobPlanningLine: Record "Job Planning Line";
IsHandled: Boolean;
begin
if not ShowWarningForThisItem(JobPlanningLine."No.") then
exit(false);
OldItemNetChange := 0;
OldJobPlanningLine := JobPlanningLine;
if OldJobPlanningLine.Find() then // Find previous quantity
if (OldJobPlanningLine.Type = OldJobPlanningLine.Type::Item) and
(OldJobPlanningLine."No." = JobPlanningLine."No.") and
(OldJobPlanningLine."Variant Code" = JobPlanningLine."Variant Code") and
(OldJobPlanningLine."Location Code" = JobPlanningLine."Location Code") and
(OldJobPlanningLine."Bin Code" = JobPlanningLine."Bin Code")
then begin
IsHandled := false;
OnJobPlanningLineShowWarningOnAfterFindingPrevJobPlanningLineQtyWithinPeriod(JobPlanningLine, OldJobPlanningLine, IsHandled);
if not IsHandled then begin
OldItemNetChange := -OldJobPlanningLine."Quantity (Base)";
OldJobPlanningLine.CalcFields("Reserved Qty. (Base)");
OldItemNetResChange := -OldJobPlanningLine."Reserved Qty. (Base)";
end;
end;
UseOrderPromise := true;
IsHandled := false;
OnJobPlanningLineShowWarningOnBeforeShowWarning(JobPlanningLine, ContextInfo, OldJobPlanningLine, OldItemNetChange, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
exit(
ShowWarning(
JobPlanningLine."No.",
JobPlanningLine."Variant Code",
JobPlanningLine."Location Code",
JobPlanningLine."Unit of Measure Code",
JobPlanningLine."Qty. per Unit of Measure",
-JobPlanningLine."Remaining Qty.",
OldItemNetChange,
JobPlanningLine."Planning Date",
OldJobPlanningLine."Planning Date"));
end;
procedure AsmOrderLineShowWarning(AssemblyLine: Record "Assembly Line") IsWarning: Boolean
var
OldAssemblyLine: Record "Assembly Line";
ShouldCheckQty, IsHandled : Boolean;
begin
if not ShowWarningForThisItem(AssemblyLine."No.") then
exit(false);
Clear(AvailableToPromise);
OldItemNetChange := 0;
OldAssemblyLine := AssemblyLine;
AssemblyLineDueDateGlobal := OldAssemblyLine."Due Date";
if OldAssemblyLine.Find() then begin // Find previous quantity
ShouldCheckQty :=
(OldAssemblyLine."Document Type" = OldAssemblyLine."Document Type"::Order) and
(OldAssemblyLine.Type = OldAssemblyLine.Type::Item) and
(OldAssemblyLine."No." = AssemblyLine."No.") and
(OldAssemblyLine."Variant Code" = AssemblyLine."Variant Code") and
(OldAssemblyLine."Location Code" = AssemblyLine."Location Code") and
(OldAssemblyLine."Bin Code" = AssemblyLine."Bin Code");
OnAsmOrderLineShowWarningOnAfterFindPreviousAssemblyOrderLineWithinPeriod(AssemblyLine, OldAssemblyLine, ShouldCheckQty, OldItemNetChange, OldItemNetResChange);
if ShouldCheckQty then
if OldAssemblyLine."Due Date" > AssemblyLine."Due Date" then
AvailableToPromise.SetChangedAsmLine(OldAssemblyLine)
else begin
OldItemNetChange := -OldAssemblyLine."Remaining Quantity (Base)";
OldAssemblyLine.CalcFields("Reserved Qty. (Base)");
OldItemNetResChange := -OldAssemblyLine."Reserved Qty. (Base)";
end;
end;
UseOrderPromise := true;
IsHandled := false;
OnAsmOrderLineShowWarningOnBeforeShowWarning(AssemblyLine, ContextInfo, OldAssemblyLine, OldItemNetChange, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
exit(
ShowWarning(
AssemblyLine."No.",
AssemblyLine."Variant Code",
AssemblyLine."Location Code",
AssemblyLine."Unit of Measure Code",
AssemblyLine."Qty. per Unit of Measure",
-AssemblyLine."Remaining Quantity",
OldItemNetChange,
AssemblyLine."Due Date",
OldAssemblyLine."Due Date"));
end;
procedure AsmOrderCalculate(AssemblyHeader: Record "Assembly Header"; var InventoryQty2: Decimal; var GrossReq2: Decimal; var ReservedReq2: Decimal; var SchedRcpt2: Decimal; var ReservedRcpt2: Decimal)
var
OldAssemblyHeader: Record "Assembly Header";
Item: Record Item;
CompanyInfo: Record "Company Information";
IsHandled: Boolean;
begin
UseOrderPromise := true;
if AssemblyHeader."Due Date" = 0D then
AssemblyHeader."Due Date" := WorkDate();
SetFilterOnItem(Item, AssemblyHeader."Item No.", AssemblyHeader."Variant Code", AssemblyHeader."Location Code", AssemblyHeader."Due Date");
CompanyInfo.Get();
QtyAvailToPromise(Item, CompanyInfo);
OldAssemblyHeader := AssemblyHeader;
if OldAssemblyHeader.Find() then
// Find previous quantity
if (OldAssemblyHeader."Document Type" = OldAssemblyHeader."Document Type"::Order) and
(OldAssemblyHeader."No." = AssemblyHeader."No.") and
(OldAssemblyHeader."Item No." = AssemblyHeader."Item No.") and
(OldAssemblyHeader."Variant Code" = AssemblyHeader."Variant Code") and
(OldAssemblyHeader."Location Code" = AssemblyHeader."Location Code") and
(OldAssemblyHeader."Bin Code" = AssemblyHeader."Bin Code")
then begin
IsHandled := false;
OnAsmOrderCalculateOnAfterFindingPrevAsmOrderCalculateWithinPeriod(AssemblyHeader, OldAssemblyHeader, IsHandled);
if not IsHandled then begin
OldAssemblyHeader.CalcFields("Reserved Qty. (Base)");
SchedRcpt :=
SchedRcpt - ConvertQty(OldAssemblyHeader."Remaining Quantity (Base)" - OldAssemblyHeader."Reserved Qty. (Base)");
end;
end;
FetchCalculation2(InventoryQty2, GrossReq2, ReservedReq2, SchedRcpt2, ReservedRcpt2);
end;
procedure FetchCalculation(var ItemNo2: Code[20]; var UnitOfMeasureCode2: Code[10]; var InventoryQty2: Decimal; var GrossReq2: Decimal; var ReservedReq2: Decimal; var SchedRcpt2: Decimal; var ReservedRcpt2: Decimal; var CurrentQuantity2: Decimal; var CurrentReservedQty2: Decimal; var TotalQuantity2: Decimal; var EarliestAvailDate2: Date)
begin
ItemNo2 := ItemNo;
UnitOfMeasureCode2 := UnitOfMeasureCode;
FetchCalculation2(InventoryQty2, GrossReq2, ReservedReq2, SchedRcpt2, ReservedRcpt2);
CurrentQuantity2 := -NewItemNetChange;
CurrentReservedQty2 := -(NewItemNetResChange + OldItemNetResChange);
TotalQuantity2 := InitialQtyAvailable + ItemNetChange;
EarliestAvailDate2 := EarliestAvailDate;
end;
local procedure FetchCalculation2(var InventoryQty2: Decimal; var GrossReq2: Decimal; var ReservedReq2: Decimal; var SchedRcpt2: Decimal; var ReservedRcpt2: Decimal)
begin
InventoryQty2 := InventoryQty;
GrossReq2 := GrossReq;
ReservedReq2 := ReservedReq;
SchedRcpt2 := SchedRcpt;
ReservedRcpt2 := ReservedRcpt;
end;
procedure RaiseUpdateInterruptedError()
var
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeRaiseUpdateInterruptedError(IsHandled, ContextInfo);
if IsHandled then
exit;
Error(Text000);
end;
procedure ShowAndHandleAvailabilityPage(RecordId: RecordID) Rollback: Boolean
var
ItemNo2: Code[20];
UnitOfMeasureCode2: Code[10];
InventoryQty2: Decimal;
GrossReq2: Decimal;
ReservedReq2: Decimal;
SchedRcpt2: Decimal;
ReservedRcpt2: Decimal;
CurrentQuantity2: Decimal;
CurrentReservedQty2: Decimal;
TotalQuantity2: Decimal;
EarliestAvailDate2: Date;
begin
if not GuiAllowed then
exit(false);
FetchCalculation(
ItemNo2, UnitOfMeasureCode2, InventoryQty2,
GrossReq2, ReservedReq2, SchedRcpt2, ReservedRcpt2,
CurrentQuantity2, CurrentReservedQty2, TotalQuantity2, EarliestAvailDate2);
Rollback := CreateAndSendNotification(UnitOfMeasureCode2, InventoryQty2,
GrossReq2, ReservedReq2, SchedRcpt2, ReservedRcpt2,
CurrentQuantity2, CurrentReservedQty2, TotalQuantity2, EarliestAvailDate2, RecordId, ItemLocationCode);
OnAfterShowAndHandleAvailabilityPage(ItemNo2, UnitOfMeasureCode2, InventoryQty2, GrossReq2, ReservedReq2, SchedRcpt2, ReservedRcpt2, CurrentQuantity2, CurrentReservedQty2, TotalQuantity2, EarliestAvailDate2, Rollback);
end;
procedure ShowNotificationDetails(AvailabilityCheckNotification: Notification)
var
ItemAvailabilityCheck: Page "Item Availability Check";
begin
ItemAvailabilityCheck.InitializeFromNotification(AvailabilityCheckNotification);
ItemAvailabilityCheck.SetHeading(AvailabilityCheckNotification.Message);
ItemAvailabilityCheck.RunModal();
end;
local procedure CreateAndSendNotification(UnitOfMeasureCode: Code[20]; InventoryQty: Decimal; GrossReq: Decimal; ReservedReq: Decimal; SchedRcpt: Decimal; ReservedRcpt: Decimal; CurrentQuantity: Decimal; CurrentReservedQty: Decimal; TotalQuantity: Decimal; EarliestAvailDate: Date; RecordId: RecordID; LocationCode: Code[10]) Rollback: Boolean
var
ItemAvailabilityCheck: Page "Item Availability Check";
AvailabilityCheckNotification: Notification;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeCreateAndSendNotification(
ItemNo, UnitOfMeasureCode, InventoryQty, GrossReq, ReservedReq, SchedRcpt, ReservedRcpt, CurrentQuantity,
CurrentReservedQty, TotalQuantity, EarliestAvailDate, RecordId, ItemLocationCode, ContextInfo, Rollback, IsHandled);
if IsHandled then
exit(Rollback);
AvailabilityCheckNotification.Id(CreateGuid());
AvailabilityCheckNotification.Message(StrSubstNo(NotificationMsg, ItemNo));
AvailabilityCheckNotification.Scope(NOTIFICATIONSCOPE::LocalScope);
AvailabilityCheckNotification.AddAction(DetailsTxt, CODEUNIT::"Item-Check Avail.", 'ShowNotificationDetails');
AvailabilityCheckNotification.AddAction(DontShowAgainTxt, CODEUNIT::"Item-Check Avail.", 'DeactivateNotification');
ItemAvailabilityCheck.PopulateDataOnNotification(AvailabilityCheckNotification, ItemNo, UnitOfMeasureCode,
InventoryQty, GrossReq, ReservedReq, SchedRcpt, ReservedRcpt, CurrentQuantity, CurrentReservedQty,
TotalQuantity, EarliestAvailDate, LocationCode);
ItemAvailabilityCheck.PopulateDataOnNotification(AvailabilityCheckNotification, 'VariantCode', VariantCode);
NotificationLifecycleMgt.SendNotificationWithAdditionalContext(
AvailabilityCheckNotification, RecordId, GetItemAvailabilityNotificationId());
exit(false);
end;
procedure ShowWarningForThisItem(ItemNo: Code[20]): Boolean
var
Item: Record Item;
SalesSetup: Record "Sales & Receivables Setup";
IsHandled: Boolean;
ShowWarning: Boolean;
begin
IsHandled := false;
OnBeforeShowWarningForThisItemOnBeforeItemGet(ItemNo, ShowWarning, IsHandled);
if IsHandled then
exit(ShowWarning);
Item.SetLoadFields(Type, "Stockout Warning");
if not Item.Get(ItemNo) then
exit(false);
IsHandled := false;
OnBeforeShowWarningForThisItem(Item, ShowWarning, IsHandled);
if IsHandled then
exit(ShowWarning);
if Item.IsNonInventoriableType() then
exit(false);
if not IsItemAvailabilityNotificationEnabled(Item) then
exit(false);
case Item."Stockout Warning" of
Item."Stockout Warning"::No:
exit(false);
Item."Stockout Warning"::Yes:
exit(true);
Item."Stockout Warning"::Default:
begin
SalesSetup.Get();
if SalesSetup."Stockout Warning" then
exit(true);
exit(false);
end;
end;
end;
procedure InvtDocCheckLine(InvtDocLine: Record "Invt. Document Line") Rollback: Boolean
begin
NotificationLifecycleMgt.RecallNotificationsForRecordWithAdditionalContext(
InvtDocLine.RecordId, GetItemAvailabilityNotificationId(), true);
if ItemDocLineShowWarning(InvtDocLine) then
Rollback := ShowAndHandleAvailabilityPage(InvtDocLine.RecordId);
end;
procedure ItemDocLineShowWarning(InvtDocLine: Record "Invt. Document Line") IsWarning: Boolean
var
SalesSetup: Record "Sales & Receivables Setup";
IsHandled: Boolean;
begin
SalesSetup.Get();
if not SalesSetup."Stockout Warning" then
exit(false);
case InvtDocLine."Document Type" of
InvtDocLine."Document Type"::Receipt:
ItemNetChange := InvtDocLine.Quantity;
InvtDocLine."Document Type"::Shipment:
ItemNetChange := -InvtDocLine.Quantity;
end;
IsHandled := false;
OnItemDocLineShowWarningOnBeforeShowWarning(InvtDocLine, ContextInfo, OldItemNetChange, IsWarning, IsHandled);
if IsHandled then
exit(IsWarning);
exit(
ShowWarning(
InvtDocLine."Item No.",
InvtDocLine."Variant Code",
InvtDocLine."Location Code",
InvtDocLine."Unit of Measure Code",
InvtDocLine."Qty. per Unit of Measure",
ItemNetChange,
0,
0D,
0D));
end;
procedure GetItemAvailabilityNotificationId(): Guid
begin
exit('2712AD06-C48B-4C20-820E-347A60C9AD00');
end;
procedure DeactivateNotification(SetupNotification: Notification)
var
MyNotifications: Record "My Notifications";
begin
// Insert notification in case the My Notifications page has not been opened yet
OnInitializingNotificationWithDefaultState();
MyNotifications.Disable(GetItemAvailabilityNotificationId())
end;
local procedure IsItemAvailabilityNotificationEnabled(Item: Record Item): Boolean
var
MyNotifications: Record "My Notifications";
begin
exit(MyNotifications.IsEnabledForRecord(GetItemAvailabilityNotificationId(), Item));
end;
procedure SetUseOrderPromise(NewUseOrderPromise: Boolean)
begin
UseOrderPromise := NewUseOrderPromise;
end;
local procedure CheckAvailabilityDate(var Item: Record Item; AssemblyLineDueDate: Date): Date
begin
if AssemblyLineDueDate = 0D then
exit(Item.GetRangeMax("Date Filter"))
else
exit(0D);
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCalculate(var Item: Record Item; var InitialQtyAvailable: Decimal; OldItemNetChange: Decimal; QtyPerUnitOfMeasure: Decimal; var ContextInfo: Dictionary of [Text, Text])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertQty(ItemNo: Code[20]; Qty: Decimal; var QtyPerUnitOfMeasure: Decimal; var Result: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterConvertQtyToBaseQty(ItemNo: Code[20]; QtyBase: Decimal; var QtyPerUnitOfMeasure: Decimal; var Result: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterItemJnlLineShowWarning(var ItemJournalLine: Record "Item Journal Line"; var ItemNetChange: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeItemJnlCheckLine(var ItemJournalLine: Record "Item Journal Line"; var Rollback: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeQtyAvailToPromise(var Item: Record Item; var CompanyInfo: Record "Company Information"; var InventoryQty: Decimal; var GrossReq: Decimal; var ReservedReq: Decimal; var OldItemNetResChange: Decimal; var SchedRcpt: Decimal; var ReservedRcpt: Decimal; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeCreateAndSendNotification(ItemNo: Code[20]; UnitOfMeasureCode: Code[20]; InventoryQty: Decimal; GrossReq: Decimal; ReservedReq: Decimal; SchedRcpt: Decimal; ReservedRcpt: Decimal; CurrentQuantity: Decimal; CurrentReservedQty: Decimal; TotalQuantity: Decimal; EarliestAvailDate: Date; RecordId: RecordID; LocationCode: Code[10]; ContextInfo: Dictionary of [Text, Text]; var Rollback: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeRaiseUpdateInterruptedError(var IsHandled: Boolean; ContextInfo: Dictionary of [Text, Text])
begin
end;
[IntegrationEvent(true, false)]
local procedure OnBeforeSalesLineCheck(SalesLine: Record "Sales Line"; var Rollback: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSalesLineShowWarning(SalesLine: Record "Sales Line"; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeSetFilterOnItem(var Item: Record Item; ItemNo: Code[20]; ItemVariantCode: Code[10]; ItemLocationCode: Code[10]; ShipmentDate: Date; UseOrderPromise: Boolean; var IsHandled: Boolean; UnitOfMeasureCode: Code[10])
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeShowWarningForThisItem(Item: Record Item; var ShowWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeShowWarningForThisItemOnBeforeItemGet(ItemNo: Code[20]; var ShowWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTransferLineCheck(TransferLine: Record "Transfer Line"; var Rollback: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeTransferLineShowWarning(TransferLine: Record "Transfer Line"; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAsmOrderLineShowWarningOnBeforeShowWarning(AssemblyLine: Record "Assembly Line"; var ContextInfo: Dictionary of [Text, Text]; OldAssemblyLine: Record "Assembly Line"; var OldItemNetChange: Decimal; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnItemDocLineShowWarningOnBeforeShowWarning(InvtDocLine: Record "Invt. Document Line"; var ContextInfo: Dictionary of [Text, Text]; var OldItemNetChange: Decimal; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnJobPlanningLineShowWarningOnBeforeShowWarning(JobPlanningLine: Record "Job Planning Line"; var ContextInfo: Dictionary of [Text, Text]; OldJobPlanningLine: Record "Job Planning Line"; var OldItemNetChange: Decimal; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnSalesLineShowWarningOnBeforeShowWarning(SalesLine: Record "Sales Line"; var ContextInfo: Dictionary of [Text, Text]; OldSalesLine: Record "Sales Line"; var IsWarning: Boolean; var IsHandled: Boolean; var OldItemNetChange: Decimal)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnTransferLineShowWarningOnBeforeShowWarning(TransLine: Record "Transfer Line"; var ContextInfo: Dictionary of [Text, Text]; OldTransLine: Record "Transfer Line"; var OldItemNetChange: Decimal; var IsWarning: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCalculateOnBeforeCalcInitialQtyAvailable(Item: Record Item; var SchedRcpt: Decimal; var ReservedRcpt: Decimal; var GrossReq: Decimal; var ReservedReq: Decimal; OldItemNetResChange: Decimal; NewItemNetResChange: Decimal; ContextInfo: Dictionary of [Text, Text]; var InventoryQty: Decimal)
begin
end;
[EventSubscriber(ObjectType::Page, Page::"My Notifications", 'OnInitializingNotificationWithDefaultState', '', false, false)]
local procedure OnInitializingNotificationWithDefaultState()
var
MyNotifications: Record "My Notifications";
begin
MyNotifications.InsertDefaultWithTableNum(GetItemAvailabilityNotificationId(),
ItemAvailabilityNotificationTxt,
ItemAvailabilityNotificationDescriptionTxt,
DATABASE::Item);
end;
[IntegrationEvent(false, false)]
local procedure OnShowWarningOnAfterCalculate(ItemNo: Code[20]; InventoryQty: Decimal; ItemNetChange: Decimal; InitialQtyAvailable: Decimal; OldItemNetResChange: Decimal; var Result: Boolean; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterShowAndHandleAvailabilityPage(ItemNo2: Code[20]; UnitOfMeasureCode2: Code[10]; InventoryQty2: Decimal; GrossReq2: Decimal; ReservedReq2: Decimal; SchedRcpt2: Decimal; ReservedRcpt2: Decimal; CurrentQuantity2: Decimal; CurrentReservedQty2: Decimal; TotalQuantity2: Decimal; EarliestAvailDate2: Date; var Rollback: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnSalesLineShowWarningOnAfterFindingPrevSalesLineQtyWithinPeriod(SalesLine: Record "Sales Line"; OldSalesLine: Record "Sales Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAsmOrderCalculateOnAfterFindingPrevAsmOrderCalculateWithinPeriod(AssemblyHeader: Record "Assembly Header"; OldAssemblyHeader: Record "Assembly Header"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnJobPlanningLineShowWarningOnAfterFindingPrevJobPlanningLineQtyWithinPeriod(JobPlanningLine: Record "Job Planning Line"; OldJobPlanningLine: Record "Job Planning Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnSalesLineCheckOnAfterSalesLineShowWarning(var SalesLine: Record "Sales Line"; var Rollback: Boolean);
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAsmOrderLineShowWarningOnAfterFindPreviousAssemblyOrderLineWithinPeriod(AssemblyLine: Record "Assembly Line"; OldAssemblyLine: Record "Assembly Line"; var ShouldCheckQty: Boolean; var OldItemNetChange: Decimal; var OldItemNetResChange: Decimal);
begin
end;
}