Historical Stock Balance
historical-stock-balance is the query behind the Stock Report applet’s balance-as-at-a-date screen — one row per item per location, computed as of a date_to you supply (“Date As” on the applet).
Path: POST /core2/tnt/dm/erp/reports/stock/historical-stock-balance/etl-ep
Request body: StockReportInputDto as JSON
Response envelope: StreamingPagingResponse — see the family page
See Applet Reports API for authentication and the shared envelope shapes.
Request fields
| Field | Type | Default | Applied by this query? |
|---|---|---|---|
location_guids | Set<UUID> | empty | Yes — also determines the companies searched, see below |
date_from | ZonedDateTime | now | No — send it if you like, it’s ignored. The applet itself hardcodes 2022-01-01T00:00:00.000Z and never varies it; there’s no lower bound in the query the value could affect anyway. |
date_to | ZonedDateTime | now | Yes — this is “Date As”. The query includes everything up to and including the full calendar day of date_to (internally: < date_to + 1 day), so a timestamp with a time-of-day component doesn’t trim same-day transactions. |
keyword | Optional<String> | empty | Yes |
item_from, item_to | Optional<String> each | empty | Yes — set both together for an item-code range |
item_type | Set<String> | empty | Yes |
item_status | Set<String> | empty | Yes |
item_category1_guids … item_category20_guids | Set<String> each | empty | Yes |
pre_order_item, require_delivery, require_production, consignment, free_shipping, basic_warranty | Optional<Boolean> each | empty (no filter) | Yes |
show_serial | Optional<Boolean> | empty | Yes — adds a serials array per row; slower, only request it if you’re using it |
company_guids | Set<UUID> | empty | No — read nowhere in this call path. The companies searched are derived from location_guids (LocationUow.grabCompanyGuidsBasedOnLocationGuids), not from this field. |
txn_type | Set<String> | empty | No — hardcoded. This method always filters to PNS, ETL_SYNC_STOCK_BALANCE_CALIBRATION and ETL_SYNC_STOCK_DELTA_REPLICATION for the balance figure and PNS/RESET_MA for the cost figure. Whatever you send here is never read. |
date_column | String | "txn_date" | No — not referenced by this query at all. |
hide_voided_documents, include_sn_adjustment, inv_item_guids, option_balance | various | empty | No — not referenced by this query. Present on the DTO for other StockReportController endpoints. |
date_from is not optional to get right — it’s fixed, and you should fix it the same way. Always send "2022-01-01T00:00:00.000Z", matching what the applet itself sends on every search, so a future reader of your integration’s code isn’t misled into thinking it does something. It is accepted and parsed, just never placed in a WHERE clause anywhere in this query.Server-side transforms already applied
Two things the applet does client-side are done for you before the response leaves the server:
- Zero-balance rows are dropped. The applet’s own default (
showZeroBalance = false) is applied unconditionally — there is no request field to turn this off and get zero-balance rows back. If your integration specifically needs them, you cannot get them from this endpoint; querybl_inv_current_company_stock_balancedirectly instead. hist_ma_amountandhist_ma_priceare added, computed ascost_ma_amountandcost_ma_amount / bal_qtyrespectively.
Cost basis: this is the one thing the endpoint does NOT replicate — you still have to
The applet’s “Calculate Base On” dropdown is never sent to the backend — same as on Sales Report By Document, it’s a purely client-side relabelling. But unlike that page, what it relabels here isn’t just a display fallback — it changes which raw field the applet’s hist_ma_amount/hist_ma_price columns actually show:
// what the applet does, client-side, for every row:
hist_ma_amount = row[selectedCostBasis + '_amount'] // e.g. row['cost_fifo_amount'] if FIFO is selected
hist_ma_price = hist_ma_amount / row.bal_qtywhere selectedCostBasis is cost_ma by default and one of cost_ma, cost_fifo, cost_wa, cost_lifo, cost_replacement, cost_manual depending on what the user picked.
hist_ma_amount/hist_ma_price are always MA-based (see above) — they match the applet’s output only when the applet’s “Calculate Base On” is left on its default, MA. If your integration needs to reproduce the applet under a different cost basis, ignore this endpoint’s hist_ma_* fields and compute your own from the raw cost_fifo_amount / cost_wa_amount / cost_lifo_amount fields, the same way the applet does. cost_replacement_amount and cost_manual_amount are not in this endpoint’s response at all — the underlying query never computes them — so “Replacement” and “Manual” cost bases cannot be reproduced from this endpoint under any circumstance; if a customer needs those, they need the raw bl_inv_current_company_stock_balance figures instead.Response fields
| Field | Notes |
|---|---|
guid, guid_fi_mst_item | Item identity. |
code, name, uom | Item code, name, unit of measure. |
category1_code … category10_code, category1_name … category10_name | Item category tree — 10 levels on this endpoint (the sales report joins 20). |
bal_qty | Balance quantity as of date_to. Always non-zero (see zero-balance filtering above). |
cost_ma_price | Current, live moving-average unit cost. Despite the report being “historical,” this specific field is not point-in-time — it reads today’s MA price, not the MA price as of date_to. |
cost_ma_amount, cost_fifo_amount, cost_wa_amount, cost_lifo_amount | Cost-basis amounts, each computed as bal_qty × the corresponding per-unit cost as of date_to in the query (unlike cost_ma_price, these ARE point-in-time). cost_replacement_amount and cost_manual_amount do not exist on this endpoint. |
hist_ma_amount, hist_ma_price | Added by this endpoint — see Server-side transforms and the cost-basis warning above for exactly what these are and aren’t. |
serials | Present only when show_serial: true. Array of {serial_no, quantity, location_guid}. |
Known data issue: some items have two conflicting balance rows
Some items can have two rows in bl_inv_current_company_stock_balance for the same item and company, under two different inv_item_guid values, with no deterministic ordering between them. This is a pre-existing condition in the source data — not something introduced by this endpoint, and not something this endpoint (or the applet itself) corrects, because the query this endpoint calls has no ROW_NUMBER()/dedup on that particular join, unlike every bl_inv_txn_line-based CTE earlier in the same method, which does. See this page’s sources: map for exactly where.
Practical effect: for an affected item, cost_ma_price (and anything derived from it) can come back as either of the two conflicting values on different calls, non-deterministically. This showed up during verification as the applet itself disagreeing with its own export across two pulls of the same item — so it is not specific to etl-ep; a frontend built on this endpoint has the same exposure the applet already has. There is nothing to work around on the client side; this needs a backend fix (add the missing ROW_NUMBER() partition) to resolve for good.
Filter dropdowns
POST /core2/tnt/dm/erp/drop-down/company/etl-ep (narrows the Location dropdown)
POST /core2/tnt/dm/erp/drop-down/location/etl-ep
POST /core2/tnt/dm/erp/drop-down/label/etl-ep
POST /core2/tnt/dm/erp/drop-down/label-list/etl-epBody and response shape: see Applet Reports API → dropdowns.
Example
curl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/reports/stock/historical-stock-balance/etl-ep" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{
"location_guids": ["6b8d1f42-7e35-4c09-ad81-1d4e8b2c5a70"],
"date_from": "2022-01-01T00:00:00.000Z",
"date_to": "2026-09-01T00:00:00.000Z"
}'Related
- Applet Reports API — shared auth, envelope shapes, dropdowns
- Sales Report By Document — same applet family, sales rather than stock
- Data API — hosts, headers, limits shared by every
etl-epcall