Codeunit 8510 Over-Receipt Mgt., source in 29
Source29
src/Layers/W1/BaseApp/Purchases/Document/OverReceiptMgt.Codeunit.al295 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.Purchases.Document;
using Microsoft.Foundation.UOM;
using Microsoft.Inventory.Item;
using Microsoft.Purchases.Vendor;
using Microsoft.Warehouse.Activity;
using Microsoft.Warehouse.Document;
using Microsoft.Warehouse.Request;
using System.Environment.Configuration;
using System.Utilities;
codeunit 8510 "Over-Receipt Mgt."
{
trigger OnRun()
begin
end;
var
OverReceiptQuantityErrTitleTxt: Label 'Qty. to Receive isn''t valid.';
OverReceiptQuantityErrDescriptionTxt: Label 'The selected Over-Receipt Code - %1, allows you to receive up to %2 units.', Comment = '%1 = Over Receipt Code, %2 = numbers of allowed quantity to receive.';
OverReceiptNotificationTxt: Label 'An over-receipt quantity is recorded on purchase order %1.', Comment = '%1 - document number';
QtyToSetCustomDimKeyTxt: Label 'Qty. to Set', Locked = true;
OverReceiptSetQtyActionCaptionTxt: Label 'Set value to %1', Comment = '%1 = Quantity to set';
#pragma warning disable AA0470
OverReceiptSetQtyActionTooltipTxt: Label 'Corrects %1 value to %2.';
#pragma warning restore AA0470
procedure IsOverReceiptAllowed() OverReceiptAllowed: Boolean
begin
OverReceiptAllowed := true;
OnIsOverReceiptAllowed(OverReceiptAllowed);
end;
procedure IsQuantityUpdatedFromWarehouseOverReceipt(PurchaseLine: Record "Purchase Line"): Boolean
var
WarehouseReceiptLine: Record "Warehouse Receipt Line";
WhseManagement: Codeunit "Whse. Management";
begin
if not IsOverReceiptAllowed() then
exit(false);
WhseManagement.SetSourceFilterForWhseRcptLine(
WarehouseReceiptLine, Database::"Purchase Line", PurchaseLine."Document Type".AsInteger(), PurchaseLine."Document No.", PurchaseLine."Line No.", true);
if not WarehouseReceiptLine.FindFirst() then
exit(false);
exit(PurchaseLine.Quantity = WarehouseReceiptLine.Quantity);
end;
procedure IsOverReceiptPendingOnWarehouseReceiptLine(PurchaseLine: Record "Purchase Line"): Boolean
var
WarehouseReceiptLine: Record "Warehouse Receipt Line";
WhseManagement: Codeunit "Whse. Management";
begin
if not IsOverReceiptAllowed() then
exit(false);
if PurchaseLine."Over-Receipt Quantity" = 0 then
exit(false);
WhseManagement.SetSourceFilterForWhseRcptLine(
WarehouseReceiptLine, Database::"Purchase Line", PurchaseLine."Document Type".AsInteger(),
PurchaseLine."Document No.", PurchaseLine."Line No.", false);
WarehouseReceiptLine.SetFilter("Over-Receipt Quantity", '>0');
exit(not WarehouseReceiptLine.IsEmpty());
end;
procedure IsQuantityUpdatedFromInvtPutAwayOverReceipt(PurchaseLine: Record "Purchase Line"): Boolean
var
WarehouseActivityLine: Record "Warehouse Activity Line";
WhseManagement: Codeunit "Whse. Management";
begin
if not IsOverReceiptAllowed() then
exit(false);
WhseManagement.SetSourceFilterForWhseActivityLine(
WarehouseActivityLine, Database::"Purchase Line", PurchaseLine."Document Type".AsInteger(), PurchaseLine."Document No.", PurchaseLine."Line No.", true);
WarehouseActivityLine.CalcSums(Quantity);
exit(PurchaseLine.Quantity = WarehouseActivityLine.Quantity);
end;
procedure UpdatePurchaseLineOverReceiptQuantityFromWarehouseReceiptLine(WarehouseReceiptLine: Record "Warehouse Receipt Line")
begin
UpdatePurchaseLineOverReceiptQuantityFromWarehouseReceiptLine(WarehouseReceiptLine, 0);
end;
internal procedure UpdatePurchaseLineOverReceiptQuantityFromWarehouseReceiptLine(WarehouseReceiptLine: Record "Warehouse Receipt Line"; CalledFromFieldNo: Integer)
var
PurchaseLine: Record "Purchase Line";
begin
if not IsOverReceiptAllowed() then
exit;
if PurchaseLine.Get(WarehouseReceiptLine."Source Subtype", WarehouseReceiptLine."Source No.", WarehouseReceiptLine."Source Line No.") then begin
if CalledFromFieldNo <> 0 then begin
PurchaseLine.ClearFieldCausedPriceCalculation();
PurchaseLine.PlanPriceCalcByField(CalledFromFieldNo);
end;
PurchaseLine.Validate("Over-Receipt Code", WarehouseReceiptLine."Over-Receipt Code");
PurchaseLine.Validate("Over-Receipt Quantity", WarehouseReceiptLine."Over-Receipt Quantity");
PurchaseLine.Modify();
end;
end;
procedure UpdatePurchaseLineOverReceiptQuantityFromWarehouseActivityLine(WarehouseActivityLine: Record "Warehouse Activity Line")
begin
UpdatePurchaseLineOverReceiptQuantityFromWarehouseActivityLine(WarehouseActivityLine, 0)
end;
internal procedure UpdatePurchaseLineOverReceiptQuantityFromWarehouseActivityLine(WarehouseActivityLine: Record "Warehouse Activity Line"; CalledFromFieldNo: Integer)
var
PurchaseLine: Record "Purchase Line";
begin
if not IsOverReceiptAllowed() then
exit;
PurchaseLine.SetLoadFields(PurchaseLine."Over-Receipt Code", PurchaseLine."Over-Receipt Quantity");
if PurchaseLine.Get(WarehouseActivityLine."Source Subtype", WarehouseActivityLine."Source No.", WarehouseActivityLine."Source Line No.") then begin
WarehouseActivityLine.SetRange("Activity Type", WarehouseActivityLine."Activity Type");
WarehouseActivityLine.SetRange("No.", WarehouseActivityLine."No.");
WarehouseActivityLine.SetSourceFilter(
WarehouseActivityLine."Source Type", WarehouseActivityLine."Source Subtype", WarehouseActivityLine."Source No.",
WarehouseActivityLine."Source Line No.", 0, false);
WarehouseActivityLine.CalcSums("Over-Receipt Quantity");
if (PurchaseLine."Over-Receipt Code" <> WarehouseActivityLine."Over-Receipt Code") or (PurchaseLine."Over-Receipt Quantity" <> WarehouseActivityLine."Over-Receipt Quantity") then begin
if CalledFromFieldNo <> 0 then begin
PurchaseLine.ClearFieldCausedPriceCalculation();
PurchaseLine.PlanPriceCalcByField(CalledFromFieldNo);
end;
PurchaseLine.Validate("Over-Receipt Code", WarehouseActivityLine."Over-Receipt Code");
PurchaseLine.Validate("Over-Receipt Quantity", WarehouseActivityLine."Over-Receipt Quantity");
PurchaseLine.Modify();
end;
end;
end;
procedure VerifyOverReceiptQuantity(PurchaseLine: Record "Purchase Line"; xPurchaseLine: Record "Purchase Line")
var
OverReceiptCode: Record "Over-Receipt Code";
UoMMgt: Codeunit "Unit of Measure Management";
ErrorMessageManagement: Codeunit "Error Message Management";
OverReceiptQtyBase: Decimal;
LineBaseQty: Decimal;
MaxOverReceiptBaseQtyAllowed: Decimal;
MaxQtyAllowed: Decimal;
IsHandled: Boolean;
ShouldCallError: Boolean;
ActionableErrorInfo: ErrorInfo;
begin
IsHandled := false;
OnBeforeVerifyOverReceiptQuantity(PurchaseLine, xPurchaseLine, IsHandled);
if IsHandled then
exit;
if not IsOverReceiptAllowed() then
exit;
OverReceiptCode.Get(PurchaseLine."Over-Receipt Code");
OverReceiptQtyBase := UOMMgt.CalcBaseQty(PurchaseLine."Over-Receipt Quantity", PurchaseLine."Qty. per Unit of Measure");
LineBaseQty := UoMMgt.CalcBaseQty(xPurchaseLine.Quantity - xPurchaseLine."Over-Receipt Quantity", xPurchaseLine."Qty. per Unit of Measure");
MaxOverReceiptBaseQtyAllowed := UOMMgt.RoundQty(LineBaseQty / 100 * OverReceiptCode."Over-Receipt Tolerance %");
MaxQtyAllowed := (xPurchaseLine.Quantity - xPurchaseLine."Over-Receipt Quantity") * (1 + OverReceiptCode."Over-Receipt Tolerance %" / 100);
MaxQtyAllowed := UoMMgt.RoundQty(MaxQtyAllowed, xPurchaseLine."Qty. Rounding Precision", '<');
ShouldCallError := OverReceiptQtyBase > MaxOverReceiptBaseQtyAllowed;
OnVerifyOverReceiptQuantityOnAfterCalcShouldCallError(PurchaseLine, OverReceiptQtyBase, MaxOverReceiptBaseQtyAllowed, ShouldCallError);
if ShouldCallError then
if MaxQtyAllowed = xPurchaseLine."Qty. to Receive" then
Error(OverReceiptQuantityErrTitleTxt)
else begin
ActionableErrorInfo := ErrorMessageManagement.BuildActionableErrorInfo(OverReceiptQuantityErrTitleTxt,
StrSubstNo(OverReceiptQuantityErrDescriptionTxt, OverReceiptCode.Code, MaxQtyAllowed),
PurchaseLine.SystemId,
StrSubstNo(OverReceiptSetQtyActionCaptionTxt, MaxQtyAllowed),
Codeunit::"Over-Receipt Mgt.",
'SetMaxAllowedOverReceiptQtyOnPurchaseLine',
StrSubstNo(OverReceiptSetQtyActionTooltipTxt, PurchaseLine.FieldCaption("Qty. to Receive"), MaxQtyAllowed));
ActionableErrorInfo.CustomDimensions.Add(QtyToSetCustomDimKeyTxt, Format(MaxQtyAllowed));
Error(ActionableErrorInfo);
end;
end;
procedure GetDefaultOverReceiptCode(PurchaseLine: Record "Purchase Line") DefaultOverReceiptCode: Code[20]
var
Item: Record Item;
Vendor: Record Vendor;
OverReceiptCode: Record "Over-Receipt Code";
IsHandled: Boolean;
begin
DefaultOverReceiptCode := '';
OnGetDefaultOverReceiptCode(PurchaseLine, DefaultOverReceiptCode, IsHandled);
if IsHandled then
exit;
PurchaseLine.TestField(Type, PurchaseLine.Type::Item);
Item.Get(PurchaseLine."No.");
if Item."Over-Receipt Code" <> '' then begin
DefaultOverReceiptCode := Item."Over-Receipt Code";
exit;
end;
Vendor.Get(PurchaseLine.GetPurchHeader()."Buy-from Vendor No.");
if Vendor."Over-Receipt Code" <> '' then begin
DefaultOverReceiptCode := Vendor."Over-Receipt Code";
exit;
end;
OverReceiptCode.SetRange(Default, true);
if OverReceiptCode.FindFirst() then
DefaultOverReceiptCode := OverReceiptCode.Code;
end;
procedure RecallOverReceiptNotification(PurchaseHeaderRecordId: RecordId)
var
NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
begin
NotificationLifecycleMgt.RecallNotificationsForRecord(PurchaseHeaderRecordId, false);
end;
local procedure ShowOverReceiptNotification(PurchaseHeaderRecordId: RecordId; NotificationMessage: Text)
var
NotificationLifecycleMgt: Codeunit "Notification Lifecycle Mgt.";
OverReceiptNotification: Notification;
begin
OverReceiptNotification.Id := GetOverReceiptNotificationId();
OverReceiptNotification.Scope(NotificationScope::LocalScope);
OverReceiptNotification.Message(NotificationMessage);
NotificationLifecycleMgt.SendNotification(OverReceiptNotification, PurchaseHeaderRecordId);
end;
procedure ShowOverReceiptNotificationFromLine(DocumentNo: Code[20])
var
PurchaseHeader: Record "Purchase Header";
begin
if not IsOverReceiptAllowed() then
exit;
PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, DocumentNo);
ShowOverReceiptNotification(PurchaseHeader.RecordId(), StrSubstNo(OverReceiptNotificationTxt, PurchaseHeader."No."));
end;
procedure ShowOverReceiptNotificationFromOrder(DocumentNo: Code[20])
var
PurchaseHeader: Record "Purchase Header";
PurchaseLine: Record "Purchase Line";
begin
if not IsOverReceiptAllowed() then
exit;
if not PurchaseHeader.Get(PurchaseHeader."Document Type"::Order, DocumentNo) then
exit;
PurchaseLine.SetRange("Document Type", PurchaseHeader."Document Type");
PurchaseLine.SetRange("Document No.", PurchaseHeader."No.");
PurchaseLine.SetFilter("Over-Receipt Quantity", '<>0');
if not PurchaseLine.IsEmpty() then
ShowOverReceiptNotification(PurchaseHeader.RecordId(), StrSubstNo(OverReceiptNotificationTxt, PurchaseHeader."No."));
end;
internal procedure SetMaxAllowedOverReceiptQtyOnPurchaseLine(ErrorInfo: ErrorInfo)
var
PurchaseLine: Record "Purchase Line";
QtyToReceive: Decimal;
begin
Evaluate(QtyToReceive, ErrorInfo.CustomDimensions.Get(QtyToSetCustomDimKeyTxt));
PurchaseLine.GetBySystemId(ErrorInfo.SystemId);
PurchaseLine.Validate("Qty. to Receive", QtyToReceive);
PurchaseLine.Modify(true);
end;
local procedure GetOverReceiptNotificationId(): Guid
begin
exit('ea49207f-4275-45d1-804e-508dea5ae8dc');
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeVerifyOverReceiptQuantity(PurchaseLine: Record "Purchase Line"; xPurchaseLine: Record "Purchase Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnIsOverReceiptAllowed(var OverReceiptAllowed: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnGetDefaultOverReceiptCode(PurchaseLine: Record "Purchase Line"; var DefaultOverReceipCode: Code[20]; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnVerifyOverReceiptQuantityOnAfterCalcShouldCallError(PurchaseLine: Record "Purchase Line"; OverReceiptQtyBase: Decimal; MaxOverReceiptQtyAllowed: Decimal; var ShouldCallError: Boolean)
begin
end;
}