Initial commit
This commit is contained in:
159
src/api/insights.ts
Normal file
159
src/api/insights.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Order, delivery and POS reads — the numbers behind store performance.
|
||||
*
|
||||
* Note the split: online orders come from `/web/orders/*` and counter sales
|
||||
* from `/pos/*`, which is the ONLY part of the API carrying auth middleware.
|
||||
* Any figure that blends the two is eventually consistent by construction, so
|
||||
* screens that show one must also show its freshness.
|
||||
*/
|
||||
|
||||
import { api, POS, WEB } from './client';
|
||||
import type {
|
||||
DeliveryRow,
|
||||
DeliverySummary,
|
||||
LocationOrderSummary,
|
||||
OrderRow,
|
||||
OrderSummary,
|
||||
PosLocationHealth,
|
||||
PosSalesPage,
|
||||
PosSalesSummary,
|
||||
} from './types';
|
||||
|
||||
export interface DateRange {
|
||||
fromdate?: string;
|
||||
todate?: string;
|
||||
}
|
||||
|
||||
export interface OrderQuery extends DateRange {
|
||||
tenantid: number;
|
||||
/** Omit for every branch of the tenant. */
|
||||
locationid?: number;
|
||||
status?: string;
|
||||
keyword?: string;
|
||||
pageno?: number;
|
||||
pagesize?: number;
|
||||
}
|
||||
|
||||
export const insightsApi = {
|
||||
/**
|
||||
* The order rows themselves.
|
||||
*
|
||||
* `/orders/tenant/getorders` rather than the bare `/orders/getorders`: the
|
||||
* controller routes on which ids are present, and passing a tenant with no
|
||||
* partner, customer or app-user reaches `GetTenantOrders`. Passing a
|
||||
* `locationid` as well reaches `GetTenantLocationOrders`, which is the
|
||||
* branch-scoped read — so one call covers both "all branches" and "one
|
||||
* branch" by presence alone.
|
||||
*
|
||||
* `pageno` is 1-based here. The controller floors anything <= 0 to 1, so
|
||||
* sending 0 silently gives page one rather than an error.
|
||||
*/
|
||||
orders: (query: OrderQuery) =>
|
||||
api.get<OrderRow[]>(`${WEB}/orders/tenant/getorders`, {
|
||||
tenantid: query.tenantid,
|
||||
locationid: query.locationid,
|
||||
status: query.status,
|
||||
keyword: query.keyword,
|
||||
fromdate: query.fromdate,
|
||||
todate: query.todate,
|
||||
pageno: query.pageno ?? 1,
|
||||
pagesize: query.pagesize ?? 50,
|
||||
}),
|
||||
|
||||
/**
|
||||
* The delivery jobs.
|
||||
*
|
||||
* A separate read from the orders list, NOT a filter over it. The rows are a
|
||||
* different struct with different fields — rider name, planned vs actual
|
||||
* distance, rider charge vs job value, notes — and a different status ladder.
|
||||
* Deriving deliveries from orders, which is what this page did first, loses
|
||||
* every one of those.
|
||||
*
|
||||
* The controller 400s unless one of tenantid/partnerid/customerid/
|
||||
* applocationid/userid/appuserid is present, so `tenantid` is required here.
|
||||
*/
|
||||
deliveries: (query: OrderQuery) =>
|
||||
api.get<DeliveryRow[]>(`${WEB}/deliveries/getdeliveries`, {
|
||||
tenantid: query.tenantid,
|
||||
locationid: query.locationid,
|
||||
status: query.status,
|
||||
keyword: query.keyword,
|
||||
fromdate: query.fromdate,
|
||||
todate: query.todate,
|
||||
pageno: query.pageno ?? 1,
|
||||
pagesize: query.pagesize ?? 50,
|
||||
}),
|
||||
|
||||
orderSummary: (tenantid: number, range: DateRange = {}) =>
|
||||
api.get<OrderSummary>(`${WEB}/orders/getordersummary`, { tenantid, ...range }),
|
||||
|
||||
/** Per-branch order totals for one tenant. `tenantid` is required. */
|
||||
locationSummary: (tenantid: number, range: DateRange = {}) =>
|
||||
api.get<LocationOrderSummary[]>(`${WEB}/orders/getlocationsummary`, { tenantid, ...range }),
|
||||
|
||||
revenueSummary: (tenantid: number, range: DateRange = {}) =>
|
||||
api.get<OrderSummary>(`${WEB}/orders/getrevenuesummary`, { tenantid, ...range }),
|
||||
|
||||
timeSeries: (tenantid: number, range: DateRange = {}) =>
|
||||
api.get<Record<string, unknown>[]>(`${WEB}/orders/gettimeseries`, { tenantid, ...range }),
|
||||
|
||||
deliverySummary: (tenantid: number, range: DateRange = {}) =>
|
||||
api.get<DeliverySummary>(`${WEB}/deliveries/deliverysummary`, { tenantid, ...range }),
|
||||
|
||||
/**
|
||||
* Counter sales for ONE outlet.
|
||||
*
|
||||
* `locationid` is required and singular — there is no tenant-wide POS call,
|
||||
* so a multi-branch view fans out one request per branch.
|
||||
*/
|
||||
posSales: (
|
||||
locationid: number,
|
||||
params: DateRange & {
|
||||
pageno?: number;
|
||||
pagesize?: number;
|
||||
/** The three server-side filters the old console's bills tab offers. */
|
||||
terminalid?: string;
|
||||
cashiername?: string;
|
||||
paymentmode?: string;
|
||||
} = {},
|
||||
) =>
|
||||
api.get<PosSalesPage>(`${POS}/sales`, {
|
||||
locationid,
|
||||
pageno: params.pageno ?? 0,
|
||||
pagesize: params.pagesize ?? 50,
|
||||
fromdate: params.fromdate,
|
||||
todate: params.todate,
|
||||
terminalid: params.terminalid,
|
||||
cashiername: params.cashiername,
|
||||
paymentmode: params.paymentmode,
|
||||
}),
|
||||
|
||||
/**
|
||||
* One counter bill in full, with its lines.
|
||||
*
|
||||
* `reference` accepts the till's order UUID, the invoice number, or this
|
||||
* backend's posorderid — a support call starts from whichever the person is
|
||||
* looking at, so the endpoint takes all three.
|
||||
*/
|
||||
posSaleDetail: (locationid: number, reference: string) =>
|
||||
api.get<unknown>(`${POS}/sales/detail`, { locationid, reference }),
|
||||
|
||||
/**
|
||||
* Counter-sales totals for ONE outlet.
|
||||
*
|
||||
* The richest read in the API: bill count, gross, tax, discount, roundoff and
|
||||
* average bill, already broken down by payment mode, by day and by terminal.
|
||||
* Reports gets its offline half from this and nothing else.
|
||||
*
|
||||
* Kept apart from the order summaries above on purpose. These are `posorders`
|
||||
* rows; those are `orders` rows. The two are never added together — see
|
||||
* `store-admin-backend-gap.md` §3.1 for why that would double-count a branch
|
||||
* that both runs a till and uploads a spreadsheet.
|
||||
*/
|
||||
posSalesSummary: (locationid: number, range: DateRange = {}) =>
|
||||
api.get<PosSalesSummary>(`${POS}/sales/summary`, { locationid, ...range }),
|
||||
|
||||
/** Till presence for one outlet — how many are online, how many bills are stranded. */
|
||||
posHealth: (locationid: number) =>
|
||||
api.get<PosLocationHealth>(`${POS}/health/location`, { location_id: locationid }),
|
||||
};
|
||||
Reference in New Issue
Block a user