75 lines
2.5 KiB
TypeScript
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 ?? '—';
|
|
}
|