← Back to blog

Assembly orders with item tracking via OData API

Posting assembly orders with lot or serial number tracking through Business Central's OData API requires two custom API pages working in concert: one that exposes the Assembly Header and its lines, and one that handles the item tracking entries via the Reservation Entry temporary table. The examples below are intentionally simplified to illustrate the pattern — in a production extension you would add validation, error handling, and more complete field exposure.

API page: Assembly Orders

This page exposes the Assembly Header as an API endpoint. It includes a lines subpart for Assembly Lines and a PostAssemblyOrder action that triggers the standard posting codeunit. A client can create an order, patch its lines, assign tracking, and then call the action to post — all via REST.

page 50130 "Assembly Orders API"
{
    PageType = API;
    APIPublisher = 'myCompany';
    APIGroup = 'assembly';
    APIVersion = 'v1.0';
    EntityName = 'assemblyOrder';
    EntitySetName = 'assemblyOrders';
    SourceTable = "Assembly Header";
    DelayedInsert = true;

    layout
    {
        area(Content)
        {
            repeater(Group)
            {
                field(id; Rec.SystemId) { }
                field(no; Rec."No.") { }
                field(itemNo; Rec."Item No.") { }
                field(quantity; Rec.Quantity) { }
                field(dueDate; Rec."Due Date") { }
                field(locationCode; Rec."Location Code") { }

                part(lines; "Assembly Lines API")
                {
                    Caption = 'lines';
                    EntityName = 'assemblyLine';
                    EntitySetName = 'assemblyLines';
                    SubPageLink = "Document Type" = field("Document Type"),
                                  "Document No." = field("No.");
                }
            }
        }
    }

    actions
    {
        area(Processing)
        {
            action(PostAssemblyOrder)
            {
                Caption = 'Post Assembly Order';
                ApplicationArea = All;

                trigger OnAction()
                var
                    AssemblyPost: Codeunit "Assembly-Post";
                begin
                    AssemblyPost.Run(Rec);
                end;
            }
        }
    }
}

API page: Item Tracking

Item tracking entries in Business Central live in the Reservation Entry table. Because the API client needs to insert tracking records that are immediately associated with a specific assembly order line, this page uses the table in temporary mode and implements OnInsertRecord to create the real reservation entries with the correct source fields filled in for lot tracking.

page 50131 "Item Tracking API"
{
    PageType = API;
    APIPublisher = 'myCompany';
    APIGroup = 'assembly';
    APIVersion = 'v1.0';
    EntityName = 'itemTracking';
    EntitySetName = 'itemTrackings';
    SourceTable = "Reservation Entry";
    SourceTableTemporary = true;
    DelayedInsert = true;

    layout
    {
        area(Content)
        {
            repeater(Group)
            {
                field(id; Rec.SystemId) { }
                field(itemNo; Rec."Item No.") { }
                field(lotNo; Rec."Lot No.") { }
                field(quantity; Rec.Quantity) { }
                field(sourceType; Rec."Source Type") { }
                field(sourceSubtype; Rec."Source Subtype") { }
                field(sourceID; Rec."Source ID") { }
                field(sourceRefNo; Rec."Source Ref. No.") { }
            }
        }
    }

    trigger OnInsertRecord(BelowxRec: Boolean): Boolean
    var
        ReservationEntry: Record "Reservation Entry";
        EntryNo: Integer;
    begin
        ReservationEntry.LockTable();
        if ReservationEntry.FindLast() then
            EntryNo := ReservationEntry."Entry No." + 1
        else
            EntryNo := 1;

        ReservationEntry.Init();
        ReservationEntry."Entry No." := EntryNo;
        ReservationEntry."Item No." := Rec."Item No.";
        ReservationEntry."Lot No." := Rec."Lot No.";
        ReservationEntry.Quantity := Rec.Quantity;
        ReservationEntry."Quantity (Base)" := Rec.Quantity;
        ReservationEntry."Source Type" := Rec."Source Type";
        ReservationEntry."Source Subtype" := Rec."Source Subtype";
        ReservationEntry."Source ID" := Rec."Source ID";
        ReservationEntry."Source Ref. No." := Rec."Source Ref. No.";
        ReservationEntry."Reservation Status" := ReservationEntry."Reservation Status"::Surplus;
        ReservationEntry."Tracking Specification" := false;
        ReservationEntry.Positive := false;
        ReservationEntry.Insert(true);

        exit(false);
    end;
}

These are simplistic examples intended to illustrate the approach. A real implementation would need to handle both positive and negative reservation entry pairs, serial number tracking, expiration dates, and proper validation of source document references before inserting entries.