@@ -92,6 +92,41 @@ export interface Reminder {
|
||||
status: string;
|
||||
}
|
||||
|
||||
export type StockAdjustmentType = 'add' | 'set';
|
||||
export type StockAdjustmentStatus = 'pending' | 'applied' | 'rejected' | 'cancelled';
|
||||
|
||||
export interface StockAdjustment {
|
||||
id: string;
|
||||
productId: string;
|
||||
productName: string;
|
||||
/** add: the stock changes by quantity (negative takes stock out); set: the stock is now quantity */
|
||||
type: StockAdjustmentType;
|
||||
quantity: number;
|
||||
note: string | null;
|
||||
requestedBy: string;
|
||||
status: StockAdjustmentStatus;
|
||||
/** The terminal's stock right after applying it */
|
||||
stockAfter: number | null;
|
||||
/** Why the terminal rejected it */
|
||||
result: string | null;
|
||||
createdAt: string;
|
||||
processedAt: string | null;
|
||||
}
|
||||
|
||||
export interface Product {
|
||||
productId: string;
|
||||
name: string;
|
||||
category: string | null;
|
||||
priceInCents: number;
|
||||
/** Null when the terminal doesn't track stock for this product; can be negative */
|
||||
stock: number | null;
|
||||
lowStockThreshold: number | null;
|
||||
reportedAt: string;
|
||||
pendingAdjustments: StockAdjustment[];
|
||||
}
|
||||
|
||||
export type NewStockAdjustment = { productId: string; type: StockAdjustmentType; quantity: number; note?: string };
|
||||
|
||||
export function getCookie(name: string): string | null {
|
||||
if (typeof document === 'undefined') return null;
|
||||
return document.cookie
|
||||
@@ -294,6 +329,32 @@ export const remindersApi = {
|
||||
api<{ ok: boolean; email: string; customerName: string }>(`/venues/${venueId}/reminders/test/${plannedTabId}`, { method: 'POST' }),
|
||||
};
|
||||
|
||||
// Stock API
|
||||
export const stockApi = {
|
||||
list: (venueId: string) =>
|
||||
api<{ products: Product[]; reportedAt: string | null }>(`/venues/${venueId}/stock`),
|
||||
history: (venueId: string, params?: { productId?: string; limit?: number; offset?: number }) => {
|
||||
const searchParams = new URLSearchParams();
|
||||
if (params?.productId) searchParams.set('productId', params.productId);
|
||||
if (params?.limit) searchParams.set('limit', String(params.limit));
|
||||
if (params?.offset) searchParams.set('offset', String(params.offset));
|
||||
const qs = searchParams.toString();
|
||||
return api<{ adjustments: StockAdjustment[]; total: number }>(`/venues/${venueId}/stock/adjustments${qs ? `?${qs}` : ''}`);
|
||||
},
|
||||
adjust: (venueId: string, adjustments: NewStockAdjustment[]) =>
|
||||
api<{ adjustments: StockAdjustment[] }>(`/venues/${venueId}/stock/adjustments`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ adjustments }),
|
||||
}),
|
||||
cancel: (venueId: string, id: string) =>
|
||||
api(`/venues/${venueId}/stock/adjustments/${id}/cancel`, { method: 'POST' }),
|
||||
setLowStockThreshold: (venueId: string, productId: string, lowStockThreshold: number | null) =>
|
||||
api(`/venues/${venueId}/stock/products/${encodeURIComponent(productId)}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ lowStockThreshold }),
|
||||
}),
|
||||
};
|
||||
|
||||
export { setTokens, clearTokens, refreshAccessToken };
|
||||
|
||||
export function getAccessToken(): string | null {
|
||||
|
||||
Reference in New Issue
Block a user