Sales Report By Document
sales-report-by-document is the query behind the Sales Report applet’s SR By Document screen — one row per sales document line, the level of detail the applet’s advance search filters down to before the grid renders it.
Path: POST /core2/tnt/dm/erp/reports/sales/sales-report-by-document/etl-ep
Request body: SalesReportByItemCodeInputDto as JSON
Response envelope: StreamingPagingResponse — see the family page
See Applet Reports API for authentication and the shared envelope shapes, and Data API for hosts and headers common to every etl-ep call.
Required target
A request that omits branch_guids, company_guids and location_guids entirely is rejected before the query runs, with a 400 and the message “Need to provide at least one target guid” — send at least one of the three.
Request fields
Defaults below are the DTO’s no-arg constructor; anything you omit takes that value. Optional fields default to empty (treated as no filter); Set fields default to empty (also no filter, except server_doc_type, which defaults to a non-empty set).
| Field | Type | Default | Applied by the applet’s advance search? |
|---|---|---|---|
branch_guids | Set<UUID> | empty | Yes |
company_guids | Set<UUID> | empty | No — the applet never sends this; it’s implied by which branches you pick |
location_guids | Set<UUID> | empty | No — not on this screen’s search panel |
date_from, date_to | ZonedDateTime | now | Yes — required in practice |
keyword | Optional<String> | empty | Yes — matches item code/name/description/scan code/alt codes/remarks |
item_guids | Set<UUID> | empty | No |
customer_guids | Set<UUID> | empty | Yes |
customer_category_guids | Set<UUID> | empty | Yes |
salesman_guids | Set<UUID> | empty | Yes — fed by the employee dropdown |
shipping_recipient_entity_hdr_guids | Set<UUID> | empty | Yes |
sales_lead_label_guids | Set<String> | empty | Yes |
created_by_guids | Set<UUID> | empty | No |
item_type | Set<String> | empty | Yes — BASIC_ITEM, GROUPED_ITEM, NSTI, BUNDLE, COUPON, SERVICE, WARRANTY, GL_CODE, DOC_HEADER_ADJUSTMENT, MEMBERSHIP, MADE_TO_ORDER, DIGITAL_GOODS |
item_status | Set<String> | empty | Yes — ACTIVE, INACTIVE, DELETED |
item_category1_guids … item_category20_guids | Set<String> each | empty | Yes |
server_doc_type | Set<String> | INTERNAL_SALES_CASHBILL, INTERNAL_SALES_INVOICE, INTERNAL_SALES_ORDER | Not directly — the applet never overrides this default, so leave it unset unless you specifically need a different document mix |
server_doc_1 | Set<String> | empty | Yes — invoice/document number, exact match, one or more |
pricing_scheme_hdr_guid | Optional<UUID> | empty | No |
doc_remarks | Optional<String> | empty | No |
report_period | DAILY / WEEKLY / MONTHLY enum | DAILY | No — irrelevant to this endpoint, used by the daily/weekly/monthly summary endpoints on the same controller |
group_by, optional | Set<String> | empty | No — used by other endpoints on this controller, not this one |
timeZone | String | Asia/Kuala_Lumpur | No |
server_doc_type has a non-empty default. Unlike every other Set field on this DTO, omitting server_doc_type does not mean “no filter” — it means “cashbills, invoices and orders only,” because that’s what the no-arg constructor fills in. If you need sales returns, credit notes, or other document types the applet’s own default doesn’t show, you must send server_doc_type explicitly.Company is implied by which branches you pick — don’t send company_guids unless you specifically want to filter branches out that way; the applet itself never does.
Cost basis: replicate the applet’s fallback yourself
The response carries every cost-type amount regardless of what the applet’s “Calculate Base On” dropdown shows, because that control is a client-side display choice, not something sent to the backend at all. To reproduce the number the applet displays as “Cost Amt” for a line, apply this fallback in your own frontend:
cost_amt = cost_ma_amount
?? (nonzero) cost_fifo_amount
?? (nonzero) cost_wa_amount
?? (nonzero) cost_replacement_amounti.e. use cost_ma_amount if it is present and non-zero; otherwise fall through the list in that order. This was reverse-engineered from the applet’s own line-construction code and confirmed by matching totals against a live export — it is not documented anywhere in the backend.
Response fields
The response is one flat object per sales document line (not per document — a multi-line invoice produces multiple rows sharing the same server_doc_1). The query joins in the full item-category tree, pricing, and customer/salesman detail, so a single row carries well over a hundred fields; below are the ones you’re likely to actually need. Field names only — no data from the verification capture is reproduced here (see this page’s sources: map).
| Field | Notes |
|---|---|
line_guid | Unique per line. |
server_doc_1 | The BigLedger document number (what server_doc_1 in the request filters on). |
date_txn | Transaction date. |
doc_ccy | Document currency. |
type | Item type, one of the item_type values. |
item_code, item_name, item_descr, fi_item_guid | Item identity. |
category1_code … category20_code, category1_name … category20_name | Item category tree, paired code/name per level. Levels a tenant does not use come back null. |
branch_code, branch_guid, location_code, loc_guid | Where the sale happened. |
customer_code, customer_name, customer_phone | Customer identity — PII, handle accordingly. |
salesman_code | |
qty_sold | |
amount_std, amount_discount, amount_net, amount_txn | Standard sales amount fields — see the generic document for what each means on a document line generally. |
cost_ma_amount, cost_fifo_amount, cost_wa_amount, cost_replacement_amount, cost_lifo_amount | Cost basis by method. See Cost basis above for which one the applet actually shows. |
uom | Unit of measure. |
serial_no | {"serialNumbers": [...]} when the item is serial-tracked. |
pricing_scheme_code |
Filter dropdowns
Populate the applet-equivalent filters from these. See Applet Reports API → dropdowns.
POST /core2/tnt/dm/erp/drop-down/company/etl-ep
POST /core2/tnt/dm/erp/drop-down/branch/etl-ep
POST /core2/tnt/dm/erp/drop-down/location/etl-ep
POST /core2/tnt/dm/erp/drop-down/customer/etl-ep
POST /core2/tnt/dm/erp/drop-down/employee/etl-epBody for each: {"keyword": "", "filters": {}, "limit": 50} (DropDownInputDto — keyword, filters, filterLogical, limit default 50, orderBy, order default "ASC"). Response: {"guid": "...", "code": "...", "name": "..."} per row, in the standard StreamingPagingResponse envelope.
Example
curl -X POST "https://api-etl.akaun.com/core2/tnt/dm/erp/reports/sales/sales-report-by-document/etl-ep" \
-H "AccessId: YOUR_ACCESS_ID" \
-H "AccessKey: YOUR_ACCESS_KEY" \
-H "tenantCode: YOUR_TENANT_CODE" \
-H "Content-Type: application/json" \
-d '{
"branch_guids": ["3f2a7c10-9b4e-4d61-8a22-1c5e7f9d0b33"],
"date_from": "2026-08-01T00:00:00+08:00",
"date_to": "2026-08-31T23:59:59+08:00",
"item_status": ["ACTIVE"]
}'server_doc_type was left unset here, so the response is cashbills, invoices and orders only — send it explicitly to widen that.
Related
- Applet Reports API — shared auth, envelope shapes, dropdowns
- Historical Stock Balance — same applet family, stock rather than sales
- Reports — the generated page this route will join once merged
- Data API — hosts, headers, limits shared by every
etl-epcall