Codeunit 9030 Undo Transfer Shipment
- App
- Base Application
- Namespace
- Microsoft.Inventory.Transfer
- Versions
- 22-28
Versions171819202122232425262728
Source29
Source in 29
src/Layers/W1/BaseApp/Inventory/Transfer/UndoTransferShipment.Codeunit.al464 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.Transfer;
using Microsoft.Foundation.AuditCodes;
using Microsoft.Foundation.Enums;
using Microsoft.Inventory;
using Microsoft.Inventory.Analysis;
using Microsoft.Inventory.Costing;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Ledger;
using Microsoft.Inventory.Posting;
using Microsoft.Inventory.Setup;
using Microsoft.Warehouse.History;
using Microsoft.Warehouse.Journal;
codeunit 9030 "Undo Transfer Shipment"
{
Permissions = TableData "Transfer Line" = rimd,
TableData "Transfer Shipment Line" = rimd,
TableData "Item Application Entry" = rmd,
TableData "Item Entry Relation" = ri;
TableNo = "Transfer Shipment Line";
trigger OnRun()
var
UpdateItemAnalysisView: Codeunit "Update Item Analysis View";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeOnRun(Rec, IsHandled, HideDialog);
if IsHandled then
exit;
if not HideDialog then
if not Confirm(ReallyUndoQst) then
exit;
TransShptLine.Copy(Rec);
Code();
UpdateItemAnalysisView.UpdateAll(0, true);
Rec := TransShptLine;
end;
var
TransShptLine: Record "Transfer Shipment Line";
TempWhseJnlLine: Record "Warehouse Journal Line" temporary;
TempGlobalItemLedgEntry: Record "Item Ledger Entry" temporary;
TempGlobalItemEntryRelation: Record "Item Entry Relation" temporary;
UndoPostingMgt: Codeunit "Undo Posting Management";
ItemJnlPostLine: Codeunit "Item Jnl.-Post Line";
WhseUndoQty: Codeunit "Whse. Undo Quantity";
HideDialog: Boolean;
NextLineNo: Integer;
ReallyUndoQst: Label 'Do you really want to undo the selected Shipment lines?';
UndoQtyMsg: Label 'Undo quantity posting...';
NotEnoughLineSpaceErr: Label 'There is not enough space to insert correction lines.';
CheckingLinesMsg: Label 'Checking lines...';
AlreadyReversedErr: Label 'This shipment has already been reversed.';
AlreadyReceivedErr: Label 'This shipment has already been received. Undo Shipment can only be applied to posted, but not received Transfer Lines.';
NoDerivedTransOrderLineNoErr: Label 'The Transfer Shipment Line is missing a value in the field Derived Trans. Order Line No. This is automatically populated when posting new Transfer Shipments';
NoTransOrderLineNoErr: Label 'The Transfer Shipment Line is missing a value in the field Trans. Order Line No. This is automatically populated when posting new Transfer Shipments';
NoLinesToReverseErr: Label 'No lines with a quantity available for reversal were found among the selected lines. Select a line with a quantity that has not already been reversed, and try again.';
procedure SetHideDialog(NewHideDialog: Boolean)
begin
HideDialog := NewHideDialog;
end;
local procedure "Code"()
var
PostedWhseShptLine: Record "Posted Whse. Shipment Line";
TransferLine: Record "Transfer Line";
WhseJnlRegisterLine: Codeunit "Whse. Jnl.-Register Line";
Window: Dialog;
ItemShptEntryNo: Integer;
DocLineNo: Integer;
Direction: Enum "Transfer Direction";
PostedWhseShptLineFound: Boolean;
begin
Clear(ItemJnlPostLine);
TransShptLine.SetCurrentKey("Item Shpt. Entry No.");
TransShptLine.SetFilter(Quantity, '<>0');
TransShptLine.SetRange("Correction Line", false);
OnCodeOnAfterTransShptLineSetFilters(TransShptLine);
if TransShptLine.IsEmpty() then
Error(NoLinesToReverseErr);
TransShptLine.FindSet();
repeat
if not HideDialog then
Window.Open(CheckingLinesMsg);
CheckTransferShptLine(TransShptLine);
until TransShptLine.Next() = 0;
TransShptLine.FindSet();
repeat
OnCodeOnBeforeUndoLoop(TransShptLine);
if TransShptLine."Trans. Order Line No." = 0 then
Error(NoTransOrderLineNoErr);
TransferLine.Get(TransShptLine."Transfer Order No.", TransShptLine."Trans. Order Line No.");
if TransferLine."Qty. Received (Base)" > 0 then
Error(AlreadyReceivedErr);
if TransShptLine."Derived Trans. Order Line No." = 0 then
Error(NoDerivedTransOrderLineNoErr);
TempGlobalItemLedgEntry.Reset();
if not TempGlobalItemLedgEntry.IsEmpty() then
TempGlobalItemLedgEntry.DeleteAll();
TempGlobalItemEntryRelation.Reset();
if not TempGlobalItemEntryRelation.IsEmpty() then
TempGlobalItemEntryRelation.DeleteAll();
if not HideDialog then
Window.Open(UndoQtyMsg);
PostedWhseShptLineFound :=
WhseUndoQty.FindPostedWhseShptLine(
PostedWhseShptLine, Database::"Transfer Shipment Line", TransShptLine."Document No.",
Database::"Transfer Line", Direction::Outbound.AsInteger(), TransShptLine."Transfer Order No.", TransShptLine."Line No.");
// Undo derived transfer line and move tracking to current line
UndoPostingMgt.UpdateDerivedTransferLine(TransferLine, TransShptLine);
Clear(ItemJnlPostLine);
ItemShptEntryNo := PostItemJnlLine(TransShptLine, DocLineNo);
InsertNewShipmentLine(TransShptLine, ItemShptEntryNo, DocLineNo);
OnAfterInsertNewShipmentLine(TransShptLine, PostedWhseShptLine, PostedWhseShptLineFound, DocLineNo);
if PostedWhseShptLineFound then
WhseUndoQty.UndoPostedWhseShptLine(PostedWhseShptLine);
TempWhseJnlLine.SetRange("Source Line No.", TransShptLine."Line No.");
WhseUndoQty.PostTempWhseJnlLineCache(TempWhseJnlLine, WhseJnlRegisterLine);
OnCodeOnAfterPostTempWhseJnlLineCache(TransShptLine, ItemJnlPostLine, WhseJnlRegisterLine);
UpdateOrderLine(TransShptLine);
if PostedWhseShptLineFound then
WhseUndoQty.UpdateShptSourceDocLines(PostedWhseShptLine);
TransShptLine."Correction Line" := true;
OnBeforeModifyTransShptLine(TransShptLine);
TransShptLine.Modify();
until TransShptLine.Next() = 0;
MakeInventoryAdjustment();
OnAfterCode(TransShptLine);
end;
local procedure CheckTransferShptLine(TransShptLine: Record "Transfer Shipment Line")
var
TempItemLedgEntry: Record "Item Ledger Entry" temporary;
begin
if TransShptLine."Correction Line" then
Error(AlreadyReversedErr);
UndoPostingMgt.TestTransferShptLine(TransShptLine);
if NoItemLedgerEntriesCheckIsNeeded(TransShptLine) then // At posting transfer order line for WIP Items no Item Ledger Entries are created. Therefore no Item Ledger Entries could be collected (and checked) for undoing a transfer shipment.
exit;
UndoPostingMgt.CollectItemLedgEntries(
TempItemLedgEntry, Database::"Transfer Shipment Line", TransShptLine."Document No.", TransShptLine."Line No.", TransShptLine."Quantity (Base)", TransShptLine."Item Shpt. Entry No.");
UndoPostingMgt.CheckItemLedgEntries(TempItemLedgEntry, TransShptLine."Line No.", false);
end;
procedure GetCorrectionLineNo(TransferShptLine: Record "Transfer Shipment Line") Result: Integer;
var
TransferShptLine2: Record "Transfer Shipment Line";
LineSpacing: Integer;
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeGetCorrectionLineNo(TransferShptLine, Result, IsHandled);
if IsHandled then
exit(Result);
TransferShptLine2.SetRange("Document No.", TransferShptLine."Document No.");
TransferShptLine2.SetFilter("Line No.", '>%1', TransferShptLine."Line No.");
if TransferShptLine2.FindFirst() then begin
LineSpacing := (TransferShptLine2."Line No." - TransferShptLine."Line No.") div 2;
if LineSpacing = 0 then
Error(NotEnoughLineSpaceErr);
end else
LineSpacing := 10000;
Result := TransferShptLine."Line No." + LineSpacing;
OnAfterGetCorrectionLineNo(TransferShptLine, Result);
end;
local procedure PostItemJnlLine(TransShptLine: Record "Transfer Shipment Line"; var DocLineNo: Integer): Integer
var
ItemJnlLine: Record "Item Journal Line";
TransShptHeader: Record "Transfer Shipment Header";
SourceCodeSetup: Record "Source Code Setup";
TempApplyToEntryList: Record "Item Ledger Entry" temporary;
TempDummyItemEntryRelation: Record "Item Entry Relation" temporary;
ItemLedgEntry: Record "Item Ledger Entry";
Direction: Enum "Transfer Direction";
begin
DocLineNo := GetCorrectionLineNo(TransShptLine);
SourceCodeSetup.Get();
TransShptHeader.Get(TransShptLine."Document No.");
ItemJnlLine.Init();
ItemJnlLine."Entry Type" := ItemJnlLine."Entry Type"::Transfer;
ItemJnlLine."Order Type" := ItemJnlLine."Order Type"::Transfer;
ItemJnlLine."Item No." := TransShptLine."Item No.";
ItemJnlLine."Posting Date" := TransShptHeader."Posting Date";
ItemJnlLine."Document No." := TransShptLine."Document No.";
ItemJnlLine."Document Line No." := DocLineNo;
ItemJnlLine."Document Type" := ItemJnlLine."Document Type"::"Transfer Shipment";
ItemJnlLine."Gen. Prod. Posting Group" := TransShptLine."Gen. Prod. Posting Group";
ItemJnlLine."Inventory Posting Group" := TransShptLine."Inventory Posting Group";
ItemJnlLine."Location Code" := TransShptLine."Transfer-from Code";
ItemJnlLine."Source Code" := SourceCodeSetup.Transfer;
ItemJnlLine.Correction := true;
ItemJnlLine."Variant Code" := TransShptLine."Variant Code";
ItemJnlLine."Bin Code" := TransShptLine."Transfer-from Bin Code";
ItemJnlLine."Document Date" := TransShptHeader."Shipment Date";
ItemJnlLine."Unit of Measure Code" := TransShptLine."Unit of Measure Code";
OnAfterCopyItemJnlLineFromTransShpt(ItemJnlLine, TransShptHeader, TransShptLine);
WhseUndoQty.InsertTempWhseJnlLine(
ItemJnlLine,
Database::"Transfer Line", Direction::Outbound.AsInteger(), TransShptLine."Transfer Order No.", TransShptLine."Line No.",
TempWhseJnlLine."Reference Document"::"Posted T. Shipment".AsInteger(), TempWhseJnlLine, NextLineNo);
if GetShptEntries(TransShptLine, ItemLedgEntry) then begin
ItemLedgEntry.SetTrackingFilterBlank();
if ItemLedgEntry.FindSet() then begin
// First undo In-Transit item ledger entries
ItemLedgEntry.SetRange("Location Code", TransShptHeader."In-Transit Code");
ItemLedgEntry.FindSet();
PostCorrectiveItemLedgEntries(ItemJnlLine, ItemLedgEntry);
// Then undo from-location item ledger entries
ItemLedgEntry.SetRange("Location Code", TransShptHeader."Transfer-from Code");
ItemLedgEntry.FindSet();
PostCorrectiveItemLedgEntries(ItemJnlLine, ItemLedgEntry);
exit(ItemJnlLine."Item Shpt. Entry No.");
end
else begin
ItemLedgEntry.ClearTrackingFilter();
ItemLedgEntry.FindSet();
MoveItemLedgerEntriesToTempRec(ItemLedgEntry, TempApplyToEntryList);
// First undo In-Transit item ledger entries
TempApplyToEntryList.SetRange("Location Code", TransShptHeader."In-Transit Code");
TempApplyToEntryList.FindSet();
//Pass dummy ItemEntryRelation because, these are not used for In-Transit location
UndoPostingMgt.PostItemJnlLineAppliedToList(
ItemJnlLine, TempApplyToEntryList, TransShptLine.Quantity, TransShptLine."Quantity (Base)", TempGlobalItemLedgEntry, TempDummyItemEntryRelation, false);
// Then undo from-location item ledger entries
TempApplyToEntryList.SetRange("Location Code", TransShptHeader."Transfer-from Code");
TempApplyToEntryList.FindSet();
UndoPostingMgt.PostItemJnlLineAppliedToList(
ItemJnlLine, TempApplyToEntryList, TransShptLine.Quantity, TransShptLine."Quantity (Base)", TempGlobalItemLedgEntry, TempGlobalItemEntryRelation, false);
end;
end;
exit(0);
end;
local procedure MoveItemLedgerEntriesToTempRec(var ItemLedgerEntry: Record "Item Ledger Entry"; var TempItemLedgerEntry: Record "Item Ledger Entry" temporary)
begin
if ItemLedgerEntry.FindSet() then
repeat
TempItemLedgerEntry.TransferFields(ItemLedgerEntry);
TempItemLedgerEntry.Insert();
until ItemLedgerEntry.Next() = 0;
end;
local procedure PostCorrectiveItemLedgEntries(var ItemJnlLine: Record "Item Journal Line"; var ItemLedgEntry: Record "Item Ledger Entry")
var
IsHandled: Boolean;
begin
OnBeforePostCorrectiveItemLedgEntries(ItemJnlLine, ItemLedgEntry, IsHandled);
if IsHandled then
exit;
repeat
ItemJnlLine."Applies-to Entry" := ItemLedgEntry."Entry No.";
ItemJnlLine."Location Code" := ItemLedgEntry."Location Code";
ItemJnlLine.Quantity := ItemLedgEntry.Quantity;
ItemJnlLine."Quantity (Base)" := ItemLedgEntry.Quantity;
ItemJnlLine."Invoiced Quantity" := ItemLedgEntry."Invoiced Quantity";
ItemJnlLine."Invoiced Qty. (Base)" := ItemLedgEntry."Invoiced Quantity";
OnPostCorrectiveItemLedgEntriesOnBeforeRun(ItemJnlLine, ItemLedgEntry);
ItemJnlPostLine.Run(ItemJnlLine);
until ItemLedgEntry.Next() = 0;
end;
local procedure InsertNewShipmentLine(OldTransShptLine: Record "Transfer Shipment Line"; ItemShptEntryNo: Integer; DocLineNo: Integer)
var
NewTransShptLine: Record "Transfer Shipment Line";
begin
NewTransShptLine.Init();
NewTransShptLine.Copy(OldTransShptLine);
NewTransShptLine."Derived Trans. Order Line No." := 0;
NewTransShptLine."Line No." := DocLineNo;
NewTransShptLine."Item Shpt. Entry No." := ItemShptEntryNo;
NewTransShptLine.Quantity := -OldTransShptLine.Quantity;
NewTransShptLine."Quantity (Base)" := -OldTransShptLine."Quantity (Base)";
NewTransShptLine."Correction Line" := true;
NewTransShptLine."Dimension Set ID" := OldTransShptLine."Dimension Set ID";
OnBeforeInsertNewTransShptLine(NewTransShptLine, OldTransShptLine);
NewTransShptLine.Insert();
InsertItemEntryRelation(TempGlobalItemEntryRelation, NewTransShptLine, OldTransShptLine."Trans. Order Line No.");
end;
procedure UpdateOrderLine(TransShptLine: Record "Transfer Shipment Line")
var
TransferLine: Record "Transfer Line";
IsHandled: Boolean;
begin
IsHandled := false;
OnBeforeUpdateOrderLine(TransShptLine, IsHandled);
if IsHandled then
exit;
TransferLine.Get(TransShptLine."Transfer Order No.", TransShptLine."Line No.");
UndoPostingMgt.UpdateTransLine(
TransferLine, TransShptLine.Quantity,
TransShptLine."Quantity (Base)",
TempGlobalItemLedgEntry);
OnAfterUpdateOrderLine(TransferLine, TransShptLine);
end;
local procedure InsertItemEntryRelation(var TempItemEntryRelation: Record "Item Entry Relation" temporary; NewTransShptLine: Record "Transfer Shipment Line"; OrderLineNo: Integer)
var
ItemEntryRelation: Record "Item Entry Relation";
begin
if TempItemEntryRelation.FindFirst() then
repeat
ItemEntryRelation := TempItemEntryRelation;
ItemEntryRelation.TransferFieldsTransShptLine(NewTransShptLine);
ItemEntryRelation."Order Line No." := OrderLineNo;
ItemEntryRelation.Insert();
until TempItemEntryRelation.Next() = 0;
end;
local procedure GetShptEntries(TransShptLine: Record "Transfer Shipment Line"; var ItemLedgEntry: Record "Item Ledger Entry") Found: Boolean
begin
ItemLedgEntry.SetCurrentKey("Document No.", "Document Type", "Document Line No.");
ItemLedgEntry.SetRange("Document Type", ItemLedgEntry."Document Type"::"Transfer Shipment");
ItemLedgEntry.SetRange("Document No.", TransShptLine."Document No.");
ItemLedgEntry.SetRange("Document Line No.", TransShptLine."Line No.");
Found := ItemLedgEntry.FindSet();
if Found then
repeat
ItemJnlPostLine.MarkAppliedInboundItemEntriesForAdjustment(ItemLedgEntry."Entry No.");
until ItemLedgEntry.Next() = 0;
end;
local procedure MakeInventoryAdjustment()
var
InvtSetup: Record "Inventory Setup";
InvtAdjmtHandler: Codeunit "Inventory Adjustment Handler";
begin
InvtSetup.Get();
if InvtSetup."Automatic Cost Adjustment" <> InvtSetup."Automatic Cost Adjustment"::Never then begin
InvtAdjmtHandler.SetJobUpdateProperties(true);
InvtAdjmtHandler.MakeInventoryAdjustment(true, InvtSetup."Automatic Cost Posting");
end;
end;
local procedure NoItemLedgerEntriesCheckIsNeeded(TransferShipmentLine: Record "Transfer Shipment Line") NoCheckNeeded: Boolean
begin
OnNoItemLedgerEntriesCheckIsNeeded(TransferShipmentLine, NoCheckNeeded);
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeOnRun(var TransferShipmentLine: Record "Transfer Shipment Line"; var IsHandled: Boolean; var HideDialog: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCodeOnAfterTransShptLineSetFilters(var TransShptLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCodeOnBeforeUndoLoop(var TransShptLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterInsertNewShipmentLine(var TransShptLine: Record "Transfer Shipment Line"; PostedWhseShipmentLine: Record "Posted Whse. Shipment Line"; var PostedWhseShptLineFound: Boolean; DocLineNo: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCode(var TransShptLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeGetCorrectionLineNo(TransShptLine: Record "Transfer Shipment Line"; var Result: Integer; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterGetCorrectionLineNo(TransShptLine: Record "Transfer Shipment Line"; var Result: Integer)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeUpdateOrderLine(var TransShptLine: Record "Transfer Shipment Line"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterUpdateOrderLine(var TransferLine: Record "Transfer Line"; var TransShptLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeInsertNewTransShptLine(var TransferShipmentLineNew: Record "Transfer Shipment Line"; TransferShipmentLineOld: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforeModifyTransShptLine(var TransferShipmentLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnAfterCopyItemJnlLineFromTransShpt(var ItemJournalLine: Record "Item Journal Line"; TransferShipmentHeader: Record "Transfer Shipment Header"; TransferShipmentLine: Record "Transfer Shipment Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnPostCorrectiveItemLedgEntriesOnBeforeRun(var ItemJournalLine: Record "Item Journal Line"; var ItemLedgerEntry: Record "Item Ledger Entry")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnCodeOnAfterPostTempWhseJnlLineCache(var TransferShipmentLine: Record "Transfer Shipment Line"; var ItemJnlPostLine: Codeunit "Item Jnl.-Post Line"; var WhseJnlRegisterLine: Codeunit "Whse. Jnl.-Register Line")
begin
end;
[IntegrationEvent(false, false)]
local procedure OnBeforePostCorrectiveItemLedgEntries(var ItemJournalLine: Record "Item Journal Line"; var ItemLedgerEntry: Record "Item Ledger Entry"; var IsHandled: Boolean)
begin
end;
[IntegrationEvent(false, false)]
local procedure OnNoItemLedgerEntriesCheckIsNeeded(TransShptLine: Record "Transfer Shipment Line"; var NoCheckNeeded: Boolean)
begin
end;
}