Files
daily_console_web/src/api/customers.ts
2026-08-26 18:37:28 +05:30

75 lines
2.5 KiB
TypeScript

import { api, WEB } from './client';
/**
* Customers, as one branch sees them.
*
* `gettenantcustomers` genuinely branches on `locationid`: with one it INNER
* JOINs `tenantcustomers` and returns only the people registered against that
* outlet; without one it returns the tenant's whole book. So this is one of the
* few reads where the branch scope is honoured server-side rather than by us.
*
* The pagination is the trap. The controller supplies NO defaults — a missing
* `pageno`/`pagesize` becomes `LIMIT 0 OFFSET 0`, which returns an empty list
* rather than an error, and reads on screen as "this shop has no customers".
* Both are therefore always sent from here, never left to the caller.
*/
export interface CustomerInfo {
customerid: number;
firstname?: string;
lastname?: string;
contactno?: string;
email?: string;
address?: string;
suburb?: string;
city?: string;
state?: string;
landmark?: string;
doorno?: string;
postcode?: string;
deliverylocationid?: number;
tenantlocationid?: number;
applocationid?: number;
status?: string;
}
export interface CustomerQuery {
tenantid: number;
/** Omit for the tenant's whole book. */
locationid?: number;
keyword?: string;
pageno?: number;
pagesize?: number;
}
export const customersApi = {
list: (query: CustomerQuery) =>
api.list<CustomerInfo>(`${WEB}/customers/gettenantcustomers`, {
tenantid: query.tenantid,
locationid: query.locationid,
keyword: query.keyword || undefined,
pageno: query.pageno ?? 1,
pagesize: query.pagesize ?? 100,
}),
};
/** A display name that never renders as an empty string. */
export function customerName(customer: CustomerInfo): string {
const name = [customer.firstname, customer.lastname].filter(Boolean).join(' ').trim();
return name || customer.contactno || `Customer ${customer.customerid}`;
}
/**
* Where they are, in the shortest true form.
*
* Door numbers are dropped: "12B" tells a shopkeeper nothing, and the old
* console's fallback of "Coimbatore" for anyone without an address invented a
* locality for every record that had none.
*/
export function customerLocality(customer: CustomerInfo): string {
const parts = [customer.suburb, customer.city].filter(Boolean) as string[];
if (parts.length > 0) return parts.join(', ');
const address = (customer.address ?? '').split(',').map((part) => part.trim());
const meaningful = address.find((part) => part.length > 3 && !/^\d/.test(part));
return meaningful ?? '—';
}