Codeunit 5406 Output Jnl.-Expl. Route

App
Base Application
Namespace
Microsoft.Manufacturing.Journal
Versions
17-28

Events, 16

Versions171819202122232425262728

Source29

Source in 29

src/Layers/W1/BaseApp/Manufacturing/Journal/OutputJnlExplRoute.Codeunit.al364 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.Manufacturing.Journal;

using Microsoft.Finance.Dimension;
using Microsoft.Inventory.Costing;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Journal;
using Microsoft.Inventory.Tracking;
using Microsoft.Manufacturing.Document;

codeunit 5406 "Output Jnl.-Expl. Route"
{
    Permissions = TableData "Item Journal Line" = rimd,
                  TableData "Prod. Order Line" = r,
                  TableData "Prod. Order Routing Line" = r;
    TableNo = "Item Journal Line";

    trigger OnRun()
    var
        ProdOrderLine: Record "Prod. Order Line";
        ProdOrderRtngLine: Record "Prod. Order Routing Line";
        ItemJnlLine: Record "Item Journal Line";
        MfgCostCalcMgt: Codeunit "Mfg. Cost Calculation Mgt.";
        ItemJnlLineReserve: Codeunit "Item Jnl. Line-Reserve";
        NextLineNo: Integer;
        LineSpacing: Integer;
        BaseQtyToPost: Decimal;
        SkipRecord: Boolean;
        IsLastOperation: Boolean;
        SplitForTracking: Boolean;
        IsHandled: Boolean;
    begin
        IsHandled := false;
        OnBeforeOnRun(Rec, IsHandled, LastItemJnlLine);
        if IsHandled then
            exit;

        if (Rec."Order Type" <> Rec."Order Type"::Production) or (Rec."Order No." = '') then
            exit;

        if not ItemJnlLineReserve.DeleteLineConfirm(Rec) then
            exit;

        ProdOrderLine.Reset();
        ProdOrderLine.SetRange(Status, ProdOrderLine.Status::Released);
        ProdOrderLine.SetRange("Prod. Order No.", Rec."Order No.");
        if Rec."Order Line No." <> 0 then
            ProdOrderLine.SetRange("Line No.", Rec."Order Line No.");
        if Rec."Item No." <> '' then
            ProdOrderLine.SetRange("Item No.", Rec."Item No.");
        if Rec."Routing Reference No." <> 0 then
            ProdOrderLine.SetRange("Routing Reference No.", Rec."Routing Reference No.");
        if Rec."Routing No." <> '' then
            ProdOrderLine.SetRange("Routing No.", Rec."Routing No.");

        ProdOrderRtngLine.SetRange(Status, ProdOrderRtngLine.Status::Released);
        ProdOrderRtngLine.SetRange("Prod. Order No.", Rec."Order No.");
        if Rec."Operation No." <> '' then
            ProdOrderRtngLine.SetRange("Operation No.", Rec."Operation No.");
        ProdOrderRtngLine.SetFilter("Routing Status", '<> %1', ProdOrderRtngLine."Routing Status"::Finished);
        ProdOrderRtngLine.SetRange("Flushing Method", ProdOrderRtngLine."Flushing Method"::Manual);
        OnRunOnAfterProdOrderRtngLineSetFiltersBeforeLoop(ProdOrderRtngLine, ProdOrderLine);

        // Clear fields in xRec to ensure that validation code regarding dimensions is executed:
        Rec."Order Line No." := 0;
        Rec."Item No." := '';
        Rec."Routing Reference No." := 0;
        Rec."Routing No." := '';

        ItemJnlLine := Rec;

        ItemJnlLine.SetRange(
          "Journal Template Name", Rec."Journal Template Name");
        ItemJnlLine.SetRange(
          "Journal Batch Name", Rec."Journal Batch Name");
        OnRunOnAfterItemJnlLineSetFilters(Rec, ProdOrderLine, ProdOrderRtngLine, ItemJnlLine);

        if ItemJnlLine.Find('>') then begin
            LineSpacing :=
              (ItemJnlLine."Line No." - Rec."Line No.") div
              (1 + ProdOrderLine.Count * ProdOrderRtngLine.Count);
            if LineSpacing = 0 then
                Error(Text000);
        end else
            LineSpacing := 10000;

        NextLineNo := Rec."Line No.";

        if not ProdOrderLine.Find('-') then
            Error(Text001);

        repeat
            ProdOrderRtngLine.SetRange("Routing No.", ProdOrderLine."Routing No.");
            ProdOrderRtngLine.SetRange("Routing Reference No.", ProdOrderLine."Routing Reference No.");
            OnRunOnAfterProdOrderRtngLineSetFilters(ProdOrderRtngLine);
            if ProdOrderRtngLine.Find('-') then
                repeat
                    BaseQtyToPost :=
                      MfgCostCalcMgt.CalcQtyAdjdForRoutingScrap(
                        ProdOrderLine."Quantity (Base)",
                        ProdOrderRtngLine."Scrap Factor % (Accumulated)",
                        ProdOrderRtngLine."Fixed Scrap Qty. (Accum.)") -
                      MfgCostCalcMgt.CalcActOutputQtyBase(ProdOrderLine, ProdOrderRtngLine);
                    OnAfterCalcBaseQtyToPost(ProdOrderRtngLine, BaseQtyToPost);
                    if BaseQtyToPost > 0 then begin
                        SkipRecord := false;
                        IsLastOperation := ProdOrderRtngLine."Next Operation No." = '';
                        OnBeforeInsertOutputJnlLineWithRtngLine(Rec, ProdOrderLine, SkipRecord, IsLastOperation, ProdOrderRtngLine);
                        if not SkipRecord then begin
                            SplitForTracking := ShouldSplitLinesForSNTracking(Rec, ProdOrderLine."Item No.", IsLastOperation);
                            InsertOutputJnlLine(
                              Rec, NextLineNo, LineSpacing,
                              ProdOrderLine."Line No.",
                              ProdOrderLine."Item No.",
                              ProdOrderLine."Variant Code",
                              ProdOrderLine."Location Code",
                              ProdOrderLine."Bin Code",
                              ProdOrderLine."Routing No.", ProdOrderLine."Routing Reference No.",
                              ProdOrderRtngLine."Operation No.",
                              ProdOrderLine."Unit of Measure Code",
                              BaseQtyToPost / ProdOrderLine."Qty. per Unit of Measure",
                              IsLastOperation,
                              SplitForTracking,
                              ProdOrderLine);
                            OnRunOnAfterInsertOutputJnlLineWithRtngLine(ItemJnlLine, ProdOrderLine, ProdOrderRtngLine, NextLineNo);
                            if IsLastOperation and not SplitForTracking then
                                ItemTrackingMgt.CopyItemTracking(ProdOrderLine.RowID1(), LastItemJnlLine.RowID1(), false);
                            OnAfterCopyItemTracking(LastItemJnlLine, IsLastOperation, NextLineNo);
                        end;
                    end;
                    OnRunOnProdRtngLineLoopEnd(ProdOrderRtngLine, ProdOrderLine, ItemJnlLine, NextLineNo, LineSpacing, LastItemJnlLine);
                until ProdOrderRtngLine.Next() = 0
            else
                if ProdOrderLine."Remaining Quantity" > 0 then begin
                    SplitForTracking := ShouldSplitLinesForSNTracking(Rec, ProdOrderLine."Item No.", true);
                    IsHandled := false;
                    OnBeforeInsertOutputJnlLineWithoutRtngLine(Rec, ProdOrderLine, IsHandled);
                    if not IsHandled then begin
                        InsertOutputJnlLine(
                          Rec, NextLineNo, LineSpacing,
                          ProdOrderLine."Line No.",
                          ProdOrderLine."Item No.",
                          ProdOrderLine."Variant Code",
                          ProdOrderLine."Location Code",
                          ProdOrderLine."Bin Code",
                          ProdOrderLine."Routing No.", ProdOrderLine."Routing Reference No.", '',
                          ProdOrderLine."Unit of Measure Code",
                          ProdOrderLine."Remaining Quantity",
                          true,
                          SplitForTracking,
                          ProdOrderLine);
                        OnAfterInsertOutputJnlLineWithoutRtngLine(ItemJnlLine, ProdOrderLine, ProdOrderRtngLine, NextLineNo);
                        if not SplitForTracking then
                            ItemTrackingMgt.CopyItemTracking(ProdOrderLine.RowID1(), LastItemJnlLine.RowID1(), false);
                        OnAfterCopyItemTracking(LastItemJnlLine, IsLastOperation, NextLineNo);
                    end;
                end;
        until ProdOrderLine.Next() = 0;

        ItemJnlLineReserve.DeleteLine(Rec);

        OnBeforeDeleteItemJnlLine(Rec);
        Rec.Delete();
    end;

    var
#pragma warning disable AA0074
        Text000: Label 'There are not enough free line numbers to explode the route.';
        Text001: Label 'There is nothing to explode.';
#pragma warning restore AA0074
        LastItemJnlLine: Record "Item Journal Line";
        ItemTrackingMgt: Codeunit "Item Tracking Management";

    local procedure InsertOutputJnlLine(ItemJnlLine: Record "Item Journal Line"; var NextLineNo: Integer; LineSpacing: Integer; ProdOrderLineNo: Integer; ItemNo: Code[20]; VariantCode: Code[10]; LocationCode: Code[10]; BinCode: Code[20]; RoutingNo: Code[20]; RoutingRefNo: Integer; OperationNo: Code[10]; UnitOfMeasureCode: Code[10]; QtyToPost: Decimal; LastOperation: Boolean; SplitForTracking: Boolean; ProdOrderLine: Record "Prod. Order Line")
    var
        TempProdOrderTracking: Record "Reservation Entry" temporary;
        DimMgt: Codeunit DimensionManagement;
        i: Integer;
        LinesToInsert: Integer;
        QtyPerLine: Decimal;
    begin
        LinesToInsert := 1;
        QtyPerLine := QtyToPost;
        if SplitForTracking then begin
            LinesToInsert := QtyToPost;
            QtyPerLine := 1;
            CollectProdOrderTracking(ProdOrderLine, TempProdOrderTracking);
        end;

        for i := 1 to LinesToInsert do begin
            NextLineNo := NextLineNo + LineSpacing;
            ItemJnlLine."Line No." := NextLineNo;
            ItemJnlLine.Validate("Entry Type", ItemJnlLine."Entry Type"::Output);
            ItemJnlLine.Validate("Order Line No.", ProdOrderLineNo);
            ItemJnlLine.Validate("Item No.", ItemNo);
            ItemJnlLine.Validate("Variant Code", VariantCode);
            ItemJnlLine.Validate("Location Code", LocationCode);
            if BinCode <> '' then
                ItemJnlLine.Validate("Bin Code", BinCode);
            ItemJnlLine.Validate("Routing No.", RoutingNo);
            ItemJnlLine.Validate("Routing Reference No.", RoutingRefNo);
            ItemJnlLine.Validate("Operation No.", OperationNo);
            ItemJnlLine.Validate("Unit of Measure Code", UnitOfMeasureCode);
            ItemJnlLine.Validate("Setup Time", 0);
            ItemJnlLine.Validate("Run Time", 0);
            if (LocationCode <> '') and LastOperation then
                ItemJnlLine.CheckWhse(LocationCode, QtyPerLine);
            if ItemJnlLine.SubcontractingWorkCenterUsed() then
                ItemJnlLine.Validate("Output Quantity", 0)
            else
                ItemJnlLine.Validate("Output Quantity", QtyPerLine);

            if SplitForTracking then
                AssignNextTrackingEntry(ItemJnlLine, TempProdOrderTracking);

            OnBeforeOutputItemJnlLineInsert(ItemJnlLine, LastOperation);
            DimMgt.UpdateGlobalDimFromDimSetID(
              ItemJnlLine."Dimension Set ID", ItemJnlLine."Shortcut Dimension 1 Code", ItemJnlLine."Shortcut Dimension 2 Code");
            ItemJnlLine.Insert();

            OnAfterInsertItemJnlLine(ItemJnlLine);

            LastItemJnlLine := ItemJnlLine;
        end;
    end;

    local procedure CollectProdOrderTracking(ProdOrderLine: Record "Prod. Order Line"; var TempProdOrderTracking: Record "Reservation Entry" temporary)
    var
        ProdOrderReservEntry: Record "Reservation Entry";
    begin
        TempProdOrderTracking.Reset();
        TempProdOrderTracking.DeleteAll();

        ProdOrderReservEntry.SetPointer(ProdOrderLine.RowID1());
        ProdOrderReservEntry.SetPointerFilter();
        if not ProdOrderReservEntry.FindSet() then
            exit;

        repeat
            TempProdOrderTracking := ProdOrderReservEntry;
            TempProdOrderTracking.Insert();
        until ProdOrderReservEntry.Next() = 0;

        TempProdOrderTracking.FindSet();
    end;

    local procedure AssignNextTrackingEntry(var ItemJnlLine: Record "Item Journal Line"; var TempProdOrderTracking: Record "Reservation Entry" temporary)
    var
        SingleReservEntry: Record "Reservation Entry";
    begin
        if TempProdOrderTracking.IsEmpty() then
            exit;

        ItemJnlLine."Serial No." := TempProdOrderTracking."Serial No.";

        SingleReservEntry := TempProdOrderTracking;
        SingleReservEntry.SetRecFilter();
        ItemTrackingMgt.CopyItemTracking(SingleReservEntry, ItemJnlLine.RowID1(), false);

        if TempProdOrderTracking.Next() = 0 then;
    end;

    local procedure ShouldSplitLinesForSNTracking(ItemJnlLine: Record "Item Journal Line"; ItemNo: Code[20]; LastOperation: Boolean): Boolean
    var
        Item: Record Item;
        ItemTrackingCode: Record "Item Tracking Code";
        ItemJnlBatch: Record "Item Journal Batch";
    begin
        if not LastOperation then
            exit(false);

        if not ItemJnlBatch.Get(ItemJnlLine."Journal Template Name", ItemJnlLine."Journal Batch Name") then
            exit(false);

        if not ItemJnlBatch."Item Tracking on Lines" then
            exit(false);

        if not Item.Get(ItemNo) then
            exit(false);

        if Item."Item Tracking Code" = '' then
            exit(false);

        if not ItemTrackingCode.Get(Item."Item Tracking Code") then
            exit(false);

        exit(ItemTrackingCode."SN Specific Tracking");
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCalcBaseQtyToPost(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var BaseQty: Decimal)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterCopyItemTracking(var ItemJournalLine: Record "Item Journal Line"; LastOperation: Boolean; var NextLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertItemJnlLine(var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnAfterInsertOutputJnlLineWithoutRtngLine(var ItemJournalLine: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var NextLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeDeleteItemJnlLine(var ItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertOutputJnlLineWithRtngLine(ItemJournalLine: Record "Item Journal Line"; ProdOrderLine: Record "Prod. Order Line"; var SkipRecord: Boolean; var IsLastOperation: Boolean; ProdOrderRoutingLine: Record "Prod. Order Routing Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeInsertOutputJnlLineWithoutRtngLine(ItemJournalLine: Record "Item Journal Line"; ProdOrderLine: Record "Prod. Order Line"; var IsHandled: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeOnRun(var ItemJournalLine: Record "Item Journal Line"; var IsHandled: Boolean; var LastItemJournalLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnBeforeOutputItemJnlLineInsert(var ItemJournalLine: Record "Item Journal Line"; LastOperation: Boolean)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnAfterInsertOutputJnlLineWithRtngLine(var ItemJournalLine: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var NextLineNo: Integer)
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnAfterProdOrderRtngLineSetFilters(var ProdOrderRoutingLine: Record "Prod. Order Routing Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnAfterProdOrderRtngLineSetFiltersBeforeLoop(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ProdOrderLine: Record "Prod. Order Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnProdRtngLineLoopEnd(var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ProdOrderLine: Record "Prod. Order Line"; var ItemJnlLine: Record "Item Journal Line"; var NextLineNo: Integer; LineSpacing: Integer; var LastItemJnlLine: Record "Item Journal Line")
    begin
    end;

    [IntegrationEvent(false, false)]
    local procedure OnRunOnAfterItemJnlLineSetFilters(var ItemJournalLineRec: Record "Item Journal Line"; var ProdOrderLine: Record "Prod. Order Line"; var ProdOrderRoutingLine: Record "Prod. Order Routing Line"; var ItemJournalLine: Record "Item Journal Line")
    begin
    end;
}