Dynamics 365 Business Central: How to create Item Tracking Lines automatically during an inbound transaction (Customization)

Dynamics 365 Business Central

Hi, Readers.
Today I would like to talk about Item Tracking Lines in Business Central.
As you know, companies may want to keep track of items from the moment they enter the company. In this situation, the purchase order is often the central document, although item tracking may be handled from any inbound document and its posted entries displayed in the related item ledger entries.

First, let’s take a look at how to use Item Tracking Lines briefly in Business Central.

1. Setup

Set up item tracking codes: An item tracking code reflects the different considerations a company has regarding the use of serial and lot numbers for items moving through the inventory.

Item Card: Item Tracking Code and Lot No./Serial No. must be set.

2. To assign serial or lot numbers during an inbound transaction

For example: Lot numbers on Purchase Order page.

Select the purchase order line and on the Lines FastTab, choose the Line action, and then choose the Item Tracking Lines action.

Automatically, by choosing Assign Serial No. or Assign Lot No. to assign serial/lot numbers from predefined number series.
Manually, by entering serial or lot numbers directly, for example, the vendor’s numbers.

Then choose Related -> Lot No. Information Card.

Choose New.

Add Lot No. Information.

Return to the Purchase Order page, the Item Tracking Line information in the first line is added. Therefore, if there are 1000 purchase order lines, the above assign operation must be done 1000 times.

3. How to create Item Tracking Lines automatically

Let’s go back to the topic.
If you see the information about Item Tracking Lines page, you will find the source table of this page is temporary. So where is this data stored?

The data is stored in table 337 “Reservation Entry”.

As shown below, I can find the Item Tracking Line I just added to the table.

OK, assume that one Purchase Order Line corresponds to only one Item Tracking Line.
I can process according to the following flow in the code.
1. Add a new action on Purchase Order page called Update Tracking lines.
2.1. If Reservation Entry of Purchase Line already exists, update it.
2.1. If Reservation Entry of Purchase Line does not exist, create a new one.
3. Assign a new Lot number from the Lot No. set in the Item card.
4.1. If Lot No. information of Reservation already exists, update it.
4.2. If Lot No. information of Reservation already does not exist, create a new one.

Test Video:

Source code: For reference only

pageextension 50111 PurchaseOrderExt extends "Purchase Order"
{
    actions
    {
        addlast(processing)
        {
            action(UpdateTrackingLines)
            {
                Caption = 'Update Tracking lines';
                Image = CreateDocument;
                ApplicationArea = All;
                PromotedCategory = Process;
                PromotedIsBig = true;
                Promoted = true;

                trigger OnAction()
                begin
                    UpdateItemTrackingLines();
                end;
            }
        }
    }

    local procedure UpdateItemTrackingLines()
    begin
        IsUpdated := false;
        LastEntryNo := 0;
        PurchaseLines.Reset();
        PurchaseLines.SetRange("Document Type", Rec."Document Type");
        PurchaseLines.SetRange("Document No.", Rec."No.");
        PurchaseLines.SetFilter("Qty. to Invoice", '<>0');
        if PurchaseLines.FindSet() then
            repeat
                if IsReservationEntryExist() then
                    ModifyReservationEntry()
                else
                    CreateReservationEntry();

                IF IsLotInfoExist() THEN
                    ModifyLotInfo()
                else
                    CreateLotNoInfo();
            until PurchaseLines.Next = 0;

        if IsUpdated then
            Message(ItemTrackinglinesHasUpdated)
        else
            Message(NothingUpdate);
    end;

    local procedure IsReservationEntryExist(): Boolean
    begin
        ReservationEntry.Reset();
        ReservationEntry.SetRange("Source Type", Database::"Purchase Line");
        ReservationEntry.SetRange("Source ID", PurchaseLines."Document No.");
        ReservationEntry.SetRange("Source Ref. No.", PurchaseLines."Line No.");
        if ReservationEntry.FindSet then
            exit(true);
        exit(false);
    end;

    local procedure ModifyReservationEntry()
    begin
        ReservationEntry.Description := PurchaseLines.Description;
        ReservationEntry.VALIDATE("Quantity (Base)", PurchaseLines."Qty. to Receive (Base)");
        ReservationEntry."Qty. per Unit of Measure" := PurchaseLines."Qty. per Unit of Measure";
        ReservationEntry."Expected Receipt Date" := PurchaseLines."Expected Receipt Date";
        ReservationEntry."Creation Date" := WorkDate();
        ReservationEntry."Created By" := UserId;
        ReservationEntry.Modify();
        IsUpdated := true;
    end;

    local procedure CreateReservationEntry()
    begin
        if not Item.Get(PurchaseLines."No.") then
            exit;
        Item.TestField("Item Tracking Code");
        Item.TestField("Lot Nos.");

        ReservationEntry.Init();
        ReservationEntry."Entry No." := NextEntryNo;
        ReservationEntry."Item No." := PurchaseLines."No.";
        ReservationEntry.Description := PurchaseLines.Description;
        ReservationEntry."Location Code" := PurchaseLines."Location Code";
        ReservationEntry."Variant Code" := PurchaseLines."Variant Code";
        ReservationEntry.Validate("Quantity (Base)", PurchaseLines."Qty. to Receive (Base)");
        ReservationEntry."Reservation Status" := ReservationEntry."Reservation Status"::Surplus;
        ReservationEntry."Source Type" := Database::"Purchase Line";
        ReservationEntry."Source Subtype" := ReservationEntry."Source Subtype"::"1";
        ReservationEntry."Source ID" := PurchaseLines."Document No.";
        ReservationEntry."Source Ref. No." := PurchaseLines."Line No.";
        ReservationEntry."Expected Receipt Date" := PurchaseLines."Expected Receipt Date";
        ReservationEntry."Qty. per Unit of Measure" := PurchaseLines."Qty. per Unit of Measure";
        ReservationEntry.VALIDATE("Lot No.", NoSeriesMgt.GetNextNo(Item."Lot Nos.", WorkDate(), true));
        ReservationEntry."Item Tracking" := ReservationEntry."Item Tracking"::"Lot No.";
        ReservationEntry."Created By" := UserId;
        ReservationEntry.Positive := true;
        ReservationEntry."Creation Date" := WorkDate();
        ReservationEntry.Insert();
    end;



    local procedure IsLotInfoExist(): Boolean
    var
        myInt: Integer;
    begin
        IF LotNoInfo.Get(ReservationEntry."Item No.", ReservationEntry."Variant Code", ReservationEntry."Lot No.") then
            exit(true);
        exit(false);
    end;

    local procedure ModifyLotInfo()
    var
        myInt: Integer;
    begin
        LotNoInfo.Description := ReservationEntry.Description;
        //You can add custom fields in Lot Information.
        LotNoInfo.Modify();

        IsUpdated := true;
    end;

    local procedure CreateLotNoInfo()
    var
        myInt: Integer;
    begin
        LotNoInfo.Init();
        LotNoInfo."Item No." := ReservationEntry."Item No.";
        LotNoInfo."Variant Code" := ReservationEntry."Variant Code";
        LotNoInfo."Lot No." := ReservationEntry."Lot No.";
        LotNoInfo.Description := ReservationEntry.Description;
        //You can add custom fields in Lot Information.
        LotNoInfo.Insert();
        IsUpdated := true;
    end;

    local procedure NextEntryNo(): Integer
    var
        ReserveEntry: Record "Reservation Entry";
    begin
        ReserveEntry.Reset();
        if LastEntryNo = 0 then
            if ReserveEntry.FindLast() then
                LastEntryNo := ReserveEntry."Entry No.";
        LastEntryNo += 1;
        exit(LastEntryNo);
    end;

    var
        PurchaseLines: Record "Purchase Line";
        IsUpdated: Boolean;
        ItemTrackinglinesHasUpdated: Label 'Item Tracking lines has been updated.';
        NothingUpdate: Label 'Nothing update.';
        ReservationEntry: Record "Reservation Entry";
        LotNoInfo: Record "Lot No. Information";
        Item: Record Item;
        LastEntryNo: Integer;
        NoSeriesMgt: Codeunit NoSeriesManagement;
}

Find out more about Work with Serial and Lot Numbers from Microsoft Docs.

END

Hope this will help.

Thanks for reading.

ZHU

コメント

Copied title and URL