Codeunit 935 Asm. Item Tracking Mgt., source in 29

Source29

src/Layers/W1/BaseApp/Assembly/Inventory/Tracking/AsmItemTrackingMgt.Codeunit.al286 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.Tracking;

using Microsoft.Assembly.Document;
using Microsoft.Assembly.History;
using Microsoft.Inventory.Item;
using Microsoft.Inventory.Ledger;
using Microsoft.Sales.Document;
using Microsoft.Sales.History;
using Microsoft.Warehouse.Activity;

codeunit 935 "Asm. Item Tracking Mgt."
{
    var
        ItemTrackingMgt: Codeunit "Item Tracking Management";

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Management", 'OnGetItemTrackingSetupOnSetSerialNoRequired', '', false, false)]
    local procedure OnGetItemTrackingSetupOnSetSerialNoRequired(var ItemTrackingSetup: Record "Item Tracking Setup"; ItemTrackingCode: Record "Item Tracking Code"; EntryType: Enum "Item Ledger Entry Type"; Inbound: Boolean)
    begin
        case EntryType of
            EntryType::"Assembly Consumption", EntryType::"Assembly Output":
                if Inbound then
                    ItemTrackingSetup."Serial No. Required" := ItemTrackingCode."SN Assembly Inbound Tracking"
                else
                    ItemTrackingSetup."Serial No. Required" := ItemTrackingCode."SN Assembly Outbound Tracking";
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Management", 'OnGetItemTrackingSetupOnSetLotNoRequired', '', false, false)]
    local procedure OnGetItemTrackingSetupOnSetLotNoRequired(var ItemTrackingSetup: Record "Item Tracking Setup"; ItemTrackingCode: Record "Item Tracking Code"; EntryType: Enum "Item Ledger Entry Type"; Inbound: Boolean)
    begin
        case EntryType of
            EntryType::"Assembly Consumption", EntryType::"Assembly Output":
                if Inbound then
                    ItemTrackingSetup."Lot No. Required" := ItemTrackingCode."Lot Assembly Inbound Tracking"
                else
                    ItemTrackingSetup."Lot No. Required" := ItemTrackingCode."Lot Assembly Outbound Tracking";
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Management", 'OnGetItemTrackingSetupOnSetPackageNoRequired', '', false, false)]
    local procedure OnGetItemTrackingSetupOnSetPackageNoRequired(var ItemTrackingSetup: Record "Item Tracking Setup"; ItemTrackingCode: Record "Item Tracking Code"; EntryType: Enum "Item Ledger Entry Type"; Inbound: Boolean)
    begin
        case EntryType of
            EntryType::"Assembly Consumption", EntryType::"Assembly Output":
                if Inbound then
                    ItemTrackingSetup."Package No. Required" := ItemTrackingCode."Package Assembly Inb. Tracking"
                else
                    ItemTrackingSetup."Package No. Required" := ItemTrackingCode."Package Assembly Out. Tracking";
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Management", 'OnAfterIsResEntryReservedAgainstInventory', '', false, false)]
    local procedure OnAfterIsResEntryReservedAgainstInventory(ReservationEntry: Record "Reservation Entry"; var Result: Boolean)
    begin
        Result := IsResEntryReservedAgainstATO(ReservationEntry);
    end;

    local procedure IsResEntryReservedAgainstATO(ReservationEntry: Record "Reservation Entry"): Boolean
    var
        ReservationEntry2: Record "Reservation Entry";
        SalesLine: Record "Sales Line";
        AssembleToOrderLink: Record "Assemble-to-Order Link";
    begin
        if (ReservationEntry."Source Type" <> Database::"Sales Line") or
           (ReservationEntry."Source Subtype" <> SalesLine."Document Type"::Order.AsInteger()) or
           (not SalesLine.Get(ReservationEntry."Source Subtype", ReservationEntry."Source ID", ReservationEntry."Source Ref. No.")) or
           (not AssembleToOrderLink.AsmExistsForSalesLine(SalesLine))
        then
            exit(false);

        ReservationEntry2.Get(ReservationEntry."Entry No.", not ReservationEntry.Positive);
        if (ReservationEntry2."Source Type" <> Database::"Assembly Header") or
           (ReservationEntry2."Source Subtype" <> AssembleToOrderLink."Assembly Document Type".AsInteger()) or
           (ReservationEntry2."Source ID" <> AssembleToOrderLink."Assembly Document No.")
        then
            exit(false);

        exit(true);
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Management", 'OnSynchronizeWhseActivItemTrkgAssembly', '', false, false)]
    local procedure OnSynchronizeWhseActivItemTrkgAssembly(var WhseActivLine: Record "Warehouse Activity Line"; var ToRowID: Text[250])
    var
        ATOSalesLine: Record "Sales Line";
        AsmHeader: Record "Assembly Header";
    begin
        ATOSalesLine.Get(WhseActivLine."Source Subtype", WhseActivLine."Source No.", WhseActivLine."Source Line No.");
        ATOSalesLine.AsmToOrderExists(AsmHeader);
        ToRowID :=
            ItemTrackingMgt.ComposeRowID(Database::"Assembly Header", AsmHeader."Document Type".AsInteger(), AsmHeader."No.", '', 0, 0);
    end;

    // Item Tracking Code

    [EventSubscriber(ObjectType::Table, Database::"Item Tracking Code", 'OnValidateSNSpecificTrackingOnAfterSet', '', false, false)]
    local procedure OnValidateSNSpecificTrackingOnAfterSet(var ItemTrackingCode: Record "Item Tracking Code")
    begin
        ItemTrackingCode."SN Assembly Inbound Tracking" := true;
        ItemTrackingCode."SN Assembly Outbound Tracking" := true;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Item Tracking Code", 'OnValidateLotSpecificTrackingOnAfterSet', '', false, false)]
    local procedure OnValidateLotSpecificTrackingOnAfterSet(var ItemTrackingCode: Record "Item Tracking Code")
    begin
        ItemTrackingCode."Lot Assembly Inbound Tracking" := true;
        ItemTrackingCode."Lot Assembly Outbound Tracking" := true;
    end;

    [EventSubscriber(ObjectType::Table, Database::"Item Tracking Code", 'OnValidatePackageSpecificTrackingOnAfterSet', '', false, false)]
    local procedure OnValidatePackageSpecificTrackingOnAfterSet(var ItemTrackingCode: Record "Item Tracking Code")
    begin
        ItemTrackingCode."Package Assembly Inb. Tracking" := true;
        ItemTrackingCode."Package Assembly Out. Tracking" := true;
    end;

    // Report Carry Out Reservation
    [EventSubscriber(ObjectType::Report, Report::"Carry Out Reservation", 'OnCarryOutReservationOtherDemandType', '', false, false)]
    local procedure OnCarryOutReservationOtherDemandType(var ReservationWkshLine: Record "Reservation Wksh. Line"; DemandType: Enum "Reservation Demand Type")
    begin
        case DemandType of
            DemandType::"Assembly Components":
                ReservationWkshLine.SetRange("Source Type", Database::"Assembly Line");
        end;
    end;

    // Codeunit "Item Tracing Mgt."

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracing Mgt.", 'OnInsertRecordOnBeforeSetDescription', '', false, false)]
    local procedure OnInsertRecordOnBeforeSetDescription(var TempTrackEntry: Record "Item Tracing Buffer"; var RecRef: RecordRef; var Description2: Text[100])
    begin
        if RecRef.Get(TempTrackEntry."Record Identifier") then
            case RecRef.Number of
                Database::"Posted Assembly Header":
                    Description2 := StrSubstNo('%1 %2', TempTrackEntry."Entry Type", TempTrackEntry."Document No.");
            end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracing Mgt.", 'OnAfterSetRecordID', '', false, false)]
    local procedure OnAfterSetRecordID(var TrackingEntry: Record "Item Tracing Buffer"; RecRef: RecordRef)
    var
        PostedAssemblyHeader: Record "Posted Assembly Header";
    begin
        case TrackingEntry."Entry Type" of
            TrackingEntry."Entry Type"::"Assembly Consumption",
            TrackingEntry."Entry Type"::"Assembly Output":
                if PostedAssemblyHeader.Get(TrackingEntry."Document No.") then begin
                    RecRef.GetTable(PostedAssemblyHeader);
                    TrackingEntry."Record Identifier" := RecRef.RecordId;
                end;
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracing Mgt.", 'OnShowDocument', '', false, false)]
    local procedure OnShowDocument(RecRef: RecordRef; RecID: RecordId)
    var
        PostedAssemblyHeader: Record "Posted Assembly Header";
    begin
        case RecID.TableNo of
            Database::"Posted Assembly Line",
            Database::"Posted Assembly Header":
                begin
                    RecRef.SetTable(PostedAssemblyHeader);
                    PAGE.RunModal(PAGE::"Posted Assembly Order", PostedAssemblyHeader);
                end;
        end;
    end;

    // Page Item Tracking Lines

    [EventSubscriber(ObjectType::Page, Page::"Item Tracking Lines", 'OnSetSourceSpecOnCollectTrackingData', '', false, false)]
    local procedure OnSetSourceSpecOnCollectTrackingData(var TrackingSpecification: Record "Tracking Specification"; var TempTrackingSpecification: Record "Tracking Specification" temporary; ExcludePostedEntries: Boolean; CurrentSignFactor: Integer; var SourceQuantity: Decimal; var sender: Page "Item Tracking Lines")
    begin
        if not ExcludePostedEntries then
            if (TrackingSpecification."Source Type" = Database::"Assembly Line") or
               (TrackingSpecification."Source Type" = Database::"Assembly Header")
            then
                CollectPostedAssemblyEntries(TrackingSpecification, TempTrackingSpecification, CurrentSignFactor, SourceQuantity, sender);
    end;

    local procedure CollectPostedAssemblyEntries(TrackingSpecification: Record "Tracking Specification"; var TempTrackingSpecification: Record "Tracking Specification" temporary; CurrentSignFactor: Integer; SourceQuantity: Decimal; var sender: Page "Item Tracking Lines")
    var
        ItemEntryRelation: Record "Item Entry Relation";
        ItemLedgerEntry: Record "Item Ledger Entry";
        CurrentQtyBase: Decimal;
        MaxQtyBase: Decimal;
    begin
        // Used for collecting information about posted Assembly Lines from the created Item Ledger Entries.
        if (TrackingSpecification."Source Type" <> Database::"Assembly Line") and
           (TrackingSpecification."Source Type" <> Database::"Assembly Header")
        then
            exit;

        TempTrackingSpecification.CalcSums("Quantity (Base)");
        CurrentQtyBase := TempTrackingSpecification."Quantity (Base)";
        MaxQtyBase := CurrentSignFactor * SourceQuantity;
        if CurrentQtyBase = MaxQtyBase then
            exit;

        ItemEntryRelation.SetCurrentKey("Order No.", "Order Line No.");
        ItemEntryRelation.SetRange("Order No.", TrackingSpecification."Source ID");
        ItemEntryRelation.SetRange("Order Line No.", TrackingSpecification."Source Ref. No.");
        if TrackingSpecification."Source Type" = Database::"Assembly Line" then
            ItemEntryRelation.SetRange("Source Type", Database::"Posted Assembly Line")
        else
            ItemEntryRelation.SetRange("Source Type", Database::"Posted Assembly Header");

        if ItemEntryRelation.Find('-') then
            repeat
                ItemLedgerEntry.Get(ItemEntryRelation."Item Entry No.");
                TempTrackingSpecification := TrackingSpecification;
                TempTrackingSpecification."Entry No." := ItemLedgerEntry."Entry No.";
                TempTrackingSpecification."Item No." := ItemLedgerEntry."Item No.";
                TempTrackingSpecification.CopyTrackingFromItemLedgEntry(ItemLedgerEntry);
                TempTrackingSpecification."Quantity (Base)" := ItemLedgerEntry.Quantity;
                TempTrackingSpecification."Quantity Handled (Base)" := ItemLedgerEntry.Quantity;
                TempTrackingSpecification."Quantity Invoiced (Base)" := ItemLedgerEntry.Quantity;
                TempTrackingSpecification."Qty. per Unit of Measure" := ItemLedgerEntry."Qty. per Unit of Measure";
                TempTrackingSpecification.InitQtyToShip();

                CurrentQtyBase += TempTrackingSpecification."Quantity (Base)";

                sender.RunOnBeforeCollectTempTrackingSpecificationInsert(TempTrackingSpecification, ItemLedgerEntry, TrackingSpecification);
                TempTrackingSpecification.Insert();
            until ItemEntryRelation.Next() = 0;
    end;

    [EventSubscriber(ObjectType::Page, Page::"Item Tracking Lines", 'OnCheckItemTrackingLineIsBoundForBarcodeScanning', '', false, false)]
    local procedure OnCheckItemTrackingLineISBoundForBarcodeScanning(var TrackingSpecification: Record "Tracking Specification"; var Result: Boolean; IsHandled: Boolean)
    begin
        if TrackingSpecification."Source Type" = Database::"Assembly Line" then begin
            if TrackingSpecification."Source Subtype" in [Enum::"Assembly Document Type"::Order.AsInteger(), Enum::"Assembly Document Type"::Quote.AsInteger(), Enum::"Assembly Document Type"::"Blanket Order".AsInteger()] then
                Result := TrackingSpecification."Quantity (Base)" < 0
            else
                Result := false;
            IsHandled := true;
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Doc. Management", 'OnRetrieveTrackingSalesShipmentForAssembly', '', false, false)]
    local procedure OnRetrieveTrackingSalesShipmentForAssembly(SalesShipmentLine: Record "Sales Shipment Line"; var TempTrackingSpecBuffer: Record "Tracking Specification" temporary; sender: Codeunit "Item Tracking Doc. Management")
    var
        PostedAsmHeader: Record "Posted Assembly Header";
        PostedAsmLine: Record "Posted Assembly Line";
        Descr: Text[100];
    begin
        if SalesShipmentLine.AsmToShipmentExists(PostedAsmHeader) then begin
            PostedAsmLine.SetRange("Document No.", PostedAsmHeader."No.");
            if PostedAsmLine.FindSet() then
                repeat
                    Descr := PostedAsmLine.Description;
                    sender.FindShptRcptEntries(
                        TempTrackingSpecBuffer,
                        Database::"Posted Assembly Line", 0, PostedAsmLine."Document No.", '', 0, PostedAsmLine."Line No.", Descr);
                until PostedAsmLine.Next() = 0;
        end;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Item Tracking Doc. Management", 'OnAfterTableSignFactor', '', false, false)]
    local procedure OnAfterTableSignFactor(TableNo: Integer; var Sign: Integer);
    begin
        if TableNo = Database::"Posted Assembly Line" then
            Sign := -1;
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Inventory Profile Offsetting", OnCheckIsSNSpecificTracking, '', false, false)]
    local procedure OnCheckIsSNSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"; var SNSepecificTracking: Boolean)
    begin
        if SNSepecificTracking then
            exit;

        SNSepecificTracking := ItemTrackingCode."SN Assembly Inbound Tracking" or ItemTrackingCode."SN Assembly Outbound Tracking";
    end;

    [EventSubscriber(ObjectType::Codeunit, Codeunit::"Inventory Profile Offsetting", OnCheckIsLotSpecificTracking, '', false, false)]
    local procedure OnCheckIsLotSpecificTracking(ItemTrackingCode: Record "Item Tracking Code"; var LotSepecificTracking: Boolean)
    begin
        if LotSepecificTracking then
            exit;

        LotSepecificTracking := ItemTrackingCode."Lot Assembly Inbound Tracking" or ItemTrackingCode."Lot Assembly Outbound Tracking";
    end;
}