200 lines
5.2 KiB
TypeScript
200 lines
5.2 KiB
TypeScript
import { api } from '@/lib/api'
|
|
import type { PaginatedResponse } from '@/types/api'
|
|
|
|
import type { PageParams } from './master'
|
|
|
|
export interface ProductStockRow {
|
|
itemId: string
|
|
sku: string
|
|
name: string
|
|
brand: string | null
|
|
category: string
|
|
subCategory: string | null
|
|
uom: string
|
|
salePrice: number | null
|
|
costPrice: number | null
|
|
reorderLevel: number | null
|
|
warehouseQty: number
|
|
vehicleQty: number
|
|
totalQty: number
|
|
stockValue: number
|
|
isLowStock: boolean
|
|
isActive: boolean
|
|
}
|
|
|
|
export interface ProductSalesRow {
|
|
itemId: string
|
|
sku: string
|
|
name: string
|
|
orders: number
|
|
stores: number
|
|
qtyOrdered: number
|
|
qtyFulfilled: number
|
|
salesValue: number
|
|
costValue: number | null
|
|
margin: number | null
|
|
marginPercent: number | null
|
|
}
|
|
|
|
export interface ProductReturnRow {
|
|
itemId: string
|
|
sku: string
|
|
name: string
|
|
returnedQty: number
|
|
returnedValue: number
|
|
soldQty: number
|
|
returnPercent: number | null
|
|
qtyByReason: Record<string, number>
|
|
}
|
|
|
|
export interface ProductReportSummary {
|
|
itemCount: number
|
|
totalQty: number
|
|
totalValue: number
|
|
totalSales: number
|
|
}
|
|
|
|
export interface ProductReportParams extends PageParams {
|
|
brandId?: string
|
|
categoryId?: string
|
|
subCategoryId?: string
|
|
warehouseId?: string
|
|
regionId?: string
|
|
routeId?: string
|
|
storeId?: string
|
|
from?: string
|
|
to?: string
|
|
search?: string
|
|
}
|
|
|
|
export interface ProductStockParams extends ProductReportParams {
|
|
activeOnly?: boolean
|
|
lowStockOnly?: boolean
|
|
}
|
|
|
|
export interface StockOverview {
|
|
totalSkus: number
|
|
totalQty: number
|
|
totalValue: number
|
|
lowStockCount: number
|
|
outOfStockCount: number
|
|
expiringSoonCount: number
|
|
expiredCount: number
|
|
}
|
|
|
|
export type StockLedgerStatus = 'OK' | 'Low' | 'Out'
|
|
|
|
export interface StockLedgerRow {
|
|
itemId: string
|
|
sku: string
|
|
name: string
|
|
brand: string | null
|
|
category: string
|
|
uom: string
|
|
openingQty: number
|
|
qtyIn: number
|
|
qtyOut: number
|
|
closingQty: number
|
|
currentQty: number
|
|
costPrice: number | null
|
|
stockValue: number
|
|
reorderLevel: number | null
|
|
status: StockLedgerStatus
|
|
}
|
|
|
|
export interface StockExpiryRow {
|
|
itemId: string
|
|
sku: string
|
|
name: string
|
|
batchId: string
|
|
batchNumber: string | null
|
|
expiryDate: string
|
|
daysLeft: number
|
|
quantity: number
|
|
costPrice: number | null
|
|
value: number
|
|
locationId: string
|
|
locationType: string
|
|
locationName: string
|
|
}
|
|
|
|
export interface StockLedgerParams extends PageParams {
|
|
locationId?: string
|
|
categoryId?: string
|
|
brandId?: string
|
|
from?: string
|
|
to?: string
|
|
status?: 'low' | 'out'
|
|
activeOnly?: boolean
|
|
search?: string
|
|
}
|
|
|
|
export interface StockExpiryParams extends PageParams {
|
|
locationId?: string
|
|
days?: number
|
|
search?: string
|
|
}
|
|
|
|
export const stockReports = {
|
|
overview: (params?: { locationId?: string; expiryDays?: number }) =>
|
|
api.get<StockOverview>('/reports/stock/overview', { params }).then(r => r.data),
|
|
|
|
ledger: (params?: StockLedgerParams) =>
|
|
api.get<PaginatedResponse<StockLedgerRow>>('/reports/stock/ledger', { params }).then(r => r.data),
|
|
|
|
expiry: (params?: StockExpiryParams) =>
|
|
api.get<PaginatedResponse<StockExpiryRow>>('/reports/stock/expiry', { params }).then(r => r.data),
|
|
}
|
|
|
|
export const productReports = {
|
|
stock: (params?: ProductStockParams) =>
|
|
api.get<PaginatedResponse<ProductStockRow>>('/reports/products/stock', { params }).then(r => r.data),
|
|
|
|
sales: (params?: ProductReportParams) =>
|
|
api.get<PaginatedResponse<ProductSalesRow>>('/reports/products/sales', { params }).then(r => r.data),
|
|
|
|
returns: (params?: ProductReportParams) =>
|
|
api.get<PaginatedResponse<ProductReturnRow>>('/reports/products/returns', { params }).then(r => r.data),
|
|
|
|
summary: (params?: Pick<ProductReportParams, 'brandId' | 'categoryId' | 'warehouseId' | 'from' | 'to'>) =>
|
|
api.get<ProductReportSummary>('/reports/products/summary', { params }).then(r => r.data),
|
|
}
|
|
|
|
export interface SalesKpis {
|
|
grossSales: number
|
|
returnValue: number
|
|
netSales: number
|
|
orders: number
|
|
averageOrderValue: number
|
|
grossProfit: number
|
|
grossProfitMarginPercent: number | null
|
|
}
|
|
|
|
export interface DashboardSalesSummary {
|
|
from: string
|
|
to: string
|
|
granularity: 'day' | 'month'
|
|
kpis: { current: SalesKpis; previous: SalesKpis; previousFrom: string; previousTo: string }
|
|
trend: Array<{ period: string; sales: number; returns: number }>
|
|
byCategory: Array<{ id: string | null; name: string; amount: number }>
|
|
byRegion: Array<{ id: string | null; name: string; amount: number }>
|
|
byRep: Array<{ id: string | null; name: string; amount: number }>
|
|
}
|
|
|
|
export interface DashboardInventorySummary {
|
|
from: string
|
|
to: string
|
|
granularity: 'day' | 'month'
|
|
valueByCategory: Array<{ category: string; quantity: number; value: number }>
|
|
byWarehouse: Array<{ warehouseId: string; name: string; quantity: number; value: number }>
|
|
movementTrend: Array<{ period: string; received: number; issued: number; net: number }>
|
|
}
|
|
|
|
export const dashboardReports = {
|
|
sales: (params?: { from?: string; to?: string; regionId?: string; categoryId?: string }) =>
|
|
api.get<DashboardSalesSummary>('/reports/dashboard/sales', { params }).then(r => r.data),
|
|
|
|
inventory: (params?: { from?: string; to?: string; warehouseId?: string; categoryId?: string }) =>
|
|
api.get<DashboardInventorySummary>('/reports/dashboard/inventory', { params }).then(r => r.data),
|
|
}
|