Lot and serial numbers are not fields on the document line. They live in Reservation Entry, keyed by a tracking specification, and anything that creates or ships tracked items from code has to write them there. How item tracking is stored, the codeunits that manage it, assigning tracking from code, and what goes wrong.
The first time an extension creates a sales line for a lot-tracked item and tries to post it, it fails: "You must assign a lot number". The lot is not on the line. It is in a separate structure that most developers meet only when something breaks. This is that structure.
Table 337 Reservation Entry holds, for each document line that needs it, one entry per lot/serial/package and quantity, with "Source Type", "Source Subtype", "Source ID", "Source Ref. No." pointing back at the line (table, document type, document no., line no.) and "Reservation Status" (Reservation, Tracking, Surplus, Prospect). The same table holds reservations against supply; tracking is the Surplus and Tracking status entries with lot or serial filled in. On posting, the item journal line is split by these entries and each becomes an Item Ledger Entry with the lot/serial, which is where the stock-by-lot comes from (Item Ledger Entry with "Lot No.", summarised through "Lot No. Information" and the availability pages).
The Item Tracking Code on the item says what is tracked (lot, serial, package) and when it is required (inbound, outbound, warehouse); the Tracking Specification table (336) is the temporary working shape used by the item tracking lines page and the codeunits.
Do not insert Reservation Entries by hand. Use the codeunits the base application uses:
var
CreateReservEntry: Codeunit "Create Reserv. Entry";
ReservEntry: Record "Reservation Entry";
begin
CreateReservEntry.CreateReservEntryFor(
Database::"Sales Line", SalesLine."Document Type".AsInteger(), SalesLine."Document No.", '', 0, SalesLine."Line No.",
SalesLine."Qty. per Unit of Measure", Qty, QtyBase, ReservEntry);
CreateReservEntry.SetNewTrackingFromNewTrackingSpecification(TempTrackingSpecification); // lot/serial set on the spec
CreateReservEntry.CreateEntry(SalesLine."No.", SalesLine."Variant Code", SalesLine."Location Code", SalesLine.Description,
SalesLine."Shipment Date", 0D, 0, ReservEntry."Reservation Status"::Surplus);
end;
For the common "assign this lot to this line" case, Codeunit "Item Tracking Management" and the "Item Tracking Lines" page's RegisterItemTrackingLines procedure, driven from a temporary Tracking Specification, is the supported path and handles quantity checks, serial uniqueness and availability. For receipts, "Item Tracking Doc. Management" helps copy tracking from one document to another (receipt to put-away, order to shipment).
To find the lots on a line: ReservEntry.SetSourceFilter(Database::"Sales Line", DocType, DocNo, LineNo, true) (the helper on the record) and read "Lot No.", "Serial No.", "Quantity (Base)". To find stock by lot: Item Ledger Entry filtered on item, location and lot with "Remaining Quantity", or the "Lot No. Information" FlowFields.
"Expiration Date") and must be set on inbound; outbound takes them from the lot.Delete(true), which calls the reservation management clean-up).For regulated industries (food, pharma) this table is the audit trail; the partner due diligence post has more on why the partner must know it.