stock request

This commit is contained in:
2026-07-04 17:46:30 +05:30
parent c6a3ea51da
commit 7cd0ae85ef
23 changed files with 1293 additions and 570 deletions

View File

@@ -208,11 +208,18 @@ export async function checkEmailRequest(email: string): Promise<boolean> {
/** Find a user in the tenant user list by email or authname (case-insensitive). */
export function matchTenantUser(users: Row[], email: string): Row | null {
const target = email.toLowerCase();
const prefix = target.split('@')[0] + '@';
return (
users.find(
(u) =>
str(u[RESPONSE_FIELDS.email]).toLowerCase() === target ||
str(u.authname).toLowerCase() === target,
str(u.authname).toLowerCase() === target
) ??
users.find(
(u) =>
str(u[RESPONSE_FIELDS.email]).toLowerCase().startsWith(prefix) ||
str(u.authname).toLowerCase().startsWith(prefix)
) ?? null
);
}

View File

@@ -1029,6 +1029,10 @@ export interface CreateTenantLocationInput {
latitude?: string;
longitude?: string;
status?: string;
moduleid?: number;
applocationid?: number;
partnerid?: number;
roleid?: number;
}
/** POST /tenants/createtenantlocation — Create a new store location under a tenant. */
@@ -1043,6 +1047,8 @@ export interface UpdateTenantLocationInput {
contactno?: string;
email?: string;
status?: string;
suburb?: string;
city?: string;
}
/** PUT /tenants/updatetenantlocation — Update store location details/status. */
@@ -1136,3 +1142,71 @@ export async function reassignDeliveries(opts: {
return fiestaSend<Row>('riders/reassigndeliveries', 'POST', opts);
}
/** POST /v1/web/tenants/createlocation — Create a new tenant location (outlet). */
export async function createLocation(opts: {
tenantid: number;
locationname: string;
suburb: string;
contactno?: string;
status?: string;
}): Promise<Row> {
// Use fiestaSend, note that we include /v1/web explicitly here as the FIESTA_BASE is likely just the root.
// Wait, let's look at FIESTA_BASE in the file.
// Actually, I'll just use the full endpoint path.
return fiestaSend<Row>('v1/web/tenants/createlocation', 'POST', opts);
}
/** PUT /v1/web/tenants/updatelocation — Update an existing tenant location (outlet). */
export async function updateLocation(opts: {
tenantid: number;
locationid: number;
locationname?: string;
suburb?: string;
contactno?: string;
status?: string;
}): Promise<Row> {
return fiestaSend<Row>('v1/web/tenants/updatelocation', 'PUT', opts);
}
/** DELETE /v1/web/tenants/deletelocation — Delete an existing tenant location (outlet). */
export async function deleteLocation(opts: {
tenantid: number;
locationid: number;
}) {
const qs = new URLSearchParams({
tenantid: String(opts.tenantid),
locationid: String(opts.locationid),
}).toString();
return await fiestaSend(`tenants/deletelocation?${qs}`, 'POST');
}
export interface SalesSummaryChartData {
date: string;
revenue: number;
orders: number;
}
export interface SalesSummaryTopLocation {
locationname: string;
revenue: number;
}
export interface SalesSummaryResponse {
totalRevenue: number;
totalOrders: number;
averageOrderValue: number;
chartData: SalesSummaryChartData[];
topLocations: SalesSummaryTopLocation[];
}
/** GET /v1/web/reports/sales-summary — Fetches aggregated sales and revenue data. */
export async function getSalesSummary(opts: {
tenantid: number;
locationid?: number;
fromdate: string;
todate: string;
}): Promise<SalesSummaryResponse> {
// Use fiestaGet wrapper which parses standard responses
const res = await fiestaGet<{ details: SalesSummaryResponse }>('v1/web/reports/sales-summary', opts);
return res.details;
}

View File

@@ -20,6 +20,7 @@ import {
FIESTA_APPLOCATION_ID,
FIESTA_PRIMARY_LOCATION_ID,
getOrderSummary,
getSalesSummary,
getRevenueSummary,
getTimeSeries,
getLocationSummary,
@@ -61,6 +62,7 @@ import {
CreateTenantLocationInput,
updateTenantLocation,
UpdateTenantLocationInput,
deleteLocation,
createProductLocation,
createStockRequest,
getStockRequests,
@@ -73,6 +75,8 @@ import {
export const fiestaKeys = {
orderSummary: (tenantid: number, fromdate: string, todate: string, locationid?: number) =>
['fiesta', 'orderSummary', tenantid, fromdate, todate, locationid ?? 0] as const,
salesSummary: (tenantid: number, locationid: number | undefined, fromdate: string, todate: string) =>
['fiesta', 'salesSummary', tenantid, locationid, fromdate, todate] as const,
revenueSummary: (params: Record<string, unknown>) => ['fiesta', 'revenueSummary', params] as const,
timeSeries: (params: Record<string, unknown>) => ['fiesta', 'timeSeries', params] as const,
locationSummary: (tenantid: number) => ['fiesta', 'locationSummary', tenantid] as const,
@@ -143,6 +147,19 @@ export function useFiestaTimeSeries(opts: {
});
}
export function useFiestaSalesSummary(opts: {
tenantid: number;
locationid?: number;
fromdate: string;
todate: string;
}) {
return useQuery({
queryKey: fiestaKeys.salesSummary(opts.tenantid, opts.locationid, opts.fromdate, opts.todate),
queryFn: () => getSalesSummary(opts),
enabled: Boolean(opts.tenantid && opts.fromdate && opts.todate),
});
}
export function useFiestaLocationSummary(tenantid: number = FIESTA_TENANT_ID) {
return useQuery({
queryKey: fiestaKeys.locationSummary(tenantid),
@@ -848,4 +865,15 @@ export function useLogin() {
});
}
export function useFiestaDeleteLocation() {
const qc = useQueryClient();
return useMutation({
mutationFn: (input: { tenantid: number; locationid: number }) => deleteLocation(input),
onSuccess: (_, variables) => {
qc.invalidateQueries({ queryKey: fiestaKeys.tenantLocations(variables.tenantid) });
qc.invalidateQueries({ queryKey: fiestaKeys.locationSummary(variables.tenantid) });
},
});
}
export { FIESTA_TENANT_ID, FIESTA_APPLOCATION_ID, FIESTA_PRIMARY_LOCATION_ID };