0073

On Hand, Per Location

setrange
dictionary
item-ledger-entry
aggregation

On Hand, Per Location

The warehouse team keeps asking the same question: "how much of item X is sitting where?" The Item card's Inventory field only shows the grand total across the whole company, so they want one number per location, straight from the ledger — the same ledger every posted receipt, shipment and adjustment writes to.

Requirements

Create a codeunit named "Stock By Location" with a public procedure:

procedure OnHandByLocation(ItemNo: Code[20]): Dictionary of [Code[10], Decimal]

Rules:

  1. Every posted inventory movement of an item is recorded as an "Item Ledger Entry" carrying the item number, a "Location Code" and a signed Quantity — the on-hand quantity of ItemNo at a location is the sum of Quantity over the item's entries at that location, and negative entries subtract.
  2. The dictionary contains exactly one key per location code that appears on at least one of the item's ledger entries — a location where the item has never moved must not appear, even if the Location record exists.
  3. A location whose entries net to exactly 0 stays in the dictionary with value 0 — "we track it here and the shelf is currently empty" is information; dropping the key is not.
  4. Entries posted without a location code belong to no location: ignore them — the dictionary must never contain a blank key.
  5. An item with no ledger entries at all (or an item number that matches no item) yields an empty dictionary — never an error.

Pick object IDs in the range 50100–50199 and reference other objects by name, never by ID.

What the tests check

The tests create fresh items and fresh locations, post real item-journal adjustments across them — positive and negative, with quantities generated at run time, so no constant can pass — and compare your dictionary key by key: the exact key count, the exact on-hand quantity per location, a location whose postings net to exactly zero, entries of another item at the same location, the blank-location rule, and the empty-dictionary case. The tests run in a real company where other items and locations already have ledger entries, so your result must be driven purely by the given item's entries.

Learn More

Hint 1
Every posted movement — purchase, sale, adjustment, transfer — leaves an Item Ledger Entry with "Item No.", "Location Code" and a signed Quantity. The whole answer is one filtered read of that table: narrow it to the one item, and the per-location totals fall out of the entries you walk through.
Hint 2
Group as you go: for each entry, ContainsKey decides between Add (first entry for that location) and Set with the running sum plus the entry's Quantity. A net-zero location needs no special code — its key was added by its first entry, and later entries just bring the value back to 0.
Hint 3
Two details separate almost-right from right: skip entries whose "Location Code" is blank (a guard inside the loop, or exclude them up front with a not-equal filter), and never loop the Location table to prime the keys — only locations that actually occur on the item's entries may appear.
ALBusiness Central 28.5
Press Compile to check your code compiles — Submit runs the tests.
The code editor is desktop-only
Open this problem on a computer to write and run code. Reading the description, tests and discussion works fine here.