implemented the sales and revenue report

This commit is contained in:
2026-06-23 19:18:01 +05:30
parent 8707004405
commit 93df333df1
17 changed files with 2410 additions and 712 deletions

View File

@@ -784,6 +784,65 @@ export async function getMasterCatalog(opts: {
);
}
export interface CreateProductLocationInput {
tenantid: number;
locationid: number;
productid: number;
qty: number;
status?: string;
}
/** POST /products/createproductlocation — Add a product to a store catalogue / inventory. */
export async function createProductLocation(input: CreateProductLocationInput): Promise<Row> {
return fiestaSend<Row>('products/createproductlocation', 'POST', input);
}
export interface StockRequestInput {
tenantid: number;
locationid: number;
productid: number;
qty: number;
status?: string;
}
/** POST /products/createstockrequest — Store user requests stock. */
export async function createStockRequest(input: StockRequestInput): Promise<Row> {
return fiestaSend<Row>('products/createstockrequest', 'POST', input);
}
/** /products/getstockrequests?tenantid=&locationid=&status=&pageno=&pagesize= —
* Fetch pending/approved stock requests. */
export async function getStockRequests(opts: {
tenantid: number;
locationid?: number;
status?: string;
pageno?: number;
pagesize?: number;
}): Promise<Row[]> {
return toRows(
await fiestaGet('products/getstockrequests', {
tenantid: opts.tenantid,
locationid: opts.locationid,
status: opts.status ?? '',
pageno: opts.pageno ?? 1,
pagesize: opts.pagesize ?? 50,
}),
);
}
export interface UpdateStockRequestInput {
requestid?: number;
tenantid?: number;
locationid?: number;
productid?: number;
status: string;
}
/** PUT /products/updatestockrequest — Admin approves or rejects a stock request. */
export async function updateStockRequest(input: UpdateStockRequestInput): Promise<Row> {
return fiestaSend<Row>('products/updatestockrequest', 'PUT', input);
}
/** /products/getproductcategories — global product categories. */
export async function getProductCategories(): Promise<Row[]> {
return toRows(await fiestaGet('products/getproductcategories', {}));

View File

@@ -61,6 +61,13 @@ import {
CreateTenantLocationInput,
updateTenantLocation,
UpdateTenantLocationInput,
createProductLocation,
createStockRequest,
getStockRequests,
updateStockRequest,
CreateProductLocationInput,
StockRequestInput,
UpdateStockRequestInput,
} from './fiestaApi';
export const fiestaKeys = {
@@ -97,6 +104,7 @@ export const fiestaKeys = {
fleetSummary: (params: Record<string, unknown>) => ['fiesta', 'fleetSummary', params] as const,
users: (params: Record<string, unknown>) => ['fiesta', 'users', params] as const,
user: (userid: number) => ['fiesta', 'user', userid] as const,
stockRequests: (params: Record<string, unknown>) => ['fiesta', 'stockRequests', params] as const,
};
// ── Orders ──────────────────────────────────────────────────────────────────
@@ -685,6 +693,52 @@ export function useFiestaProductSubcategories(opts: { categoryid: number; tenant
});
}
export function useFiestaGetStockRequests(opts: {
tenantid: number;
locationid?: number;
status?: string;
pageno?: number;
pagesize?: number;
}) {
return useQuery({
queryKey: fiestaKeys.stockRequests(opts),
queryFn: () => getStockRequests(opts),
enabled: Boolean(opts.tenantid),
});
}
export function useFiestaCreateProductLocation() {
const qc = useQueryClient();
return useMutation({
mutationFn: (input: CreateProductLocationInput) => createProductLocation(input),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['fiesta', 'productLocations'] });
},
});
}
export function useFiestaCreateStockRequest() {
const qc = useQueryClient();
return useMutation({
mutationFn: (input: StockRequestInput) => createStockRequest(input),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['fiesta', 'stockRequests'] });
},
});
}
export function useFiestaUpdateStockRequest() {
const qc = useQueryClient();
return useMutation({
mutationFn: (input: UpdateStockRequestInput) => updateStockRequest(input),
onSuccess: () => {
qc.invalidateQueries({ queryKey: ['fiesta', 'stockRequests'] });
qc.invalidateQueries({ queryKey: ['fiesta', 'stockStatement'] });
qc.invalidateQueries({ queryKey: ['fiesta', 'productStocks'] });
},
});
}
// ── Users ─────────────────────────────────────────────────────────────────────
export function useFiestaUsers(opts: {
tenantid: number;

View File

@@ -18,6 +18,7 @@
*/
import { useEffect, useState } from 'react';
import { createProductLocation, FIESTA_TENANT_ID, FIESTA_PRIMARY_LOCATION_ID } from './fiestaApi';
export interface StoreCatalogueItem {
productid: string;
@@ -72,10 +73,28 @@ export function useStoreCatalogue() {
const has = (id: string) => items.some((i) => i.productid === id);
const getQty = (id: string) => items.find((i) => i.productid === id)?.qty ?? 0;
const add = (item: StoreCatalogueItem) => write([...read().filter((i) => i.productid !== item.productid), item]);
const add = (item: StoreCatalogueItem) => {
write([...read().filter((i) => i.productid !== item.productid), item]);
createProductLocation({
tenantid: FIESTA_TENANT_ID,
locationid: FIESTA_PRIMARY_LOCATION_ID,
productid: Number(item.productid),
qty: item.qty,
status: 'Active'
}).catch(e => console.error('API createProductLocation failed:', e));
};
const remove = (id: string) => write(read().filter((i) => i.productid !== id));
const setQty = (id: string, qty: number) =>
write(read().map((i) => (i.productid === id ? { ...i, qty: Math.max(1, Math.round(qty) || 1) } : i)));
const setQty = (id: string, qty: number) => {
const safeQty = Math.max(1, Math.round(qty) || 1);
write(read().map((i) => (i.productid === id ? { ...i, qty: safeQty } : i)));
createProductLocation({
tenantid: FIESTA_TENANT_ID,
locationid: FIESTA_PRIMARY_LOCATION_ID,
productid: Number(id),
qty: safeQty,
status: 'Active'
}).catch(e => console.error('API updateProductLocation failed:', e));
};
return { items, has, getQty, add, remove, setQty };
}