diff --git a/src/admin/lib/queries/warehouse.ts b/src/admin/lib/queries/warehouse.ts new file mode 100644 index 0000000..9932009 --- /dev/null +++ b/src/admin/lib/queries/warehouse.ts @@ -0,0 +1,385 @@ +import { queryOptions } from "@tanstack/react-query"; +import { jsonQuery, paginatedJsonQuery } from "../apiAdapter"; + +// --- Types --- + +export interface WarehouseItem { + id: number; + item_number: string | null; + name: string; + description: string | null; + category_id: number | null; + unit: string; + min_quantity: number | null; + is_active: boolean; + notes: string | null; + category?: { id: number; name: string } | null; + total_quantity?: number; + available_quantity?: number; + stock_value?: number; + below_minimum?: boolean; +} + +export interface WarehouseReceipt { + id: number; + receipt_number: string | null; + supplier_id: number | null; + delivery_note_number: string | null; + delivery_note_date: string | null; + received_by: number | null; + notes: string | null; + status: "DRAFT" | "CONFIRMED" | "CANCELLED"; + created_at: string; + modified_at: string | null; + supplier?: { id: number; name: string } | null; + received_by_user?: { + id: number; + first_name: string; + last_name: string; + } | null; + lines?: WarehouseReceiptLine[]; + attachments?: WarehouseReceiptAttachment[]; +} + +export interface WarehouseReceiptLine { + id: number; + receipt_id: number; + item_id: number; + quantity: number; + unit_price: number; + location_id: number | null; + notes: string | null; + item?: WarehouseItem; + location?: { id: number; code: string; name: string } | null; +} + +export interface WarehouseReceiptAttachment { + id: number; + receipt_id: number; + file_name: string; + file_mime: string; + file_size: number; + file_path: string; + created_at: string; +} + +export interface WarehouseIssue { + id: number; + issue_number: string | null; + project_id: number; + issued_by: number | null; + notes: string | null; + status: "DRAFT" | "CONFIRMED" | "CANCELLED"; + created_at: string; + modified_at: string | null; + project?: { id: number; name: string; project_number: string } | null; + issued_by_user?: { id: number; first_name: string; last_name: string } | null; + lines?: WarehouseIssueLine[]; +} + +export interface WarehouseIssueLine { + id: number; + issue_id: number; + item_id: number; + batch_id: number; + quantity: number; + location_id: number | null; + reservation_id: number | null; + notes: string | null; + item?: WarehouseItem; + batch?: { + id: number; + quantity: number; + unit_price: number; + received_at: string; + } | null; + location?: { id: number; code: string; name: string } | null; + reservation?: { id: number; quantity: number; remaining_qty: number } | null; +} + +export interface WarehouseReservation { + id: number; + item_id: number; + project_id: number; + quantity: number; + remaining_qty: number; + reserved_by: number | null; + notes: string | null; + status: "ACTIVE" | "FULFILLED" | "CANCELLED"; + created_at: string; + modified_at: string | null; + item?: WarehouseItem; + project?: { id: number; name: string } | null; + reserved_by_user?: { + id: number; + first_name: string; + last_name: string; + } | null; +} + +export interface WarehouseInventorySession { + id: number; + session_number: string | null; + notes: string | null; + status: "DRAFT" | "CONFIRMED"; + created_at: string; + modified_at: string | null; + lines?: WarehouseInventoryLine[]; +} + +export interface WarehouseInventoryLine { + id: number; + session_id: number; + item_id: number; + location_id: number | null; + system_qty: number; + actual_qty: number; + difference: number; + notes: string | null; + item?: WarehouseItem; + location?: { id: number; code: string; name: string } | null; +} + +export interface WarehouseCategory { + id: number; + name: string; + description: string | null; + sort_order: number; +} + +export interface WarehouseLocation { + id: number; + code: string; + name: string; + description: string | null; + is_active: boolean; +} + +export interface WarehouseSupplier { + id: number; + name: string; + ico: string | null; + dic: string | null; + contact_person: string | null; + email: string | null; + phone: string | null; + address: string | null; + notes: string | null; + is_active: boolean; +} + +// --- Query Options --- + +export const warehouseItemListOptions = (filters: { + search?: string; + page?: number; + perPage?: number; + sort?: string; + order?: string; + category_id?: number; +}) => + queryOptions({ + queryKey: ["warehouse", "items", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.search) params.set("search", filters.search); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + if (filters.sort) params.set("sort", filters.sort); + if (filters.order) params.set("order", filters.order); + if (filters.category_id) + params.set("category_id", String(filters.category_id)); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/items${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseItemDetailOptions = (id: string | undefined) => + queryOptions({ + queryKey: ["warehouse", "items", id], + queryFn: () => jsonQuery(`/api/admin/warehouse/items/${id}`), + enabled: !!id, + }); + +export const warehouseCategoryListOptions = () => + queryOptions({ + queryKey: ["warehouse", "categories"], + queryFn: () => + jsonQuery("/api/admin/warehouse/categories"), + }); + +export const warehouseSupplierListOptions = (filters: { + search?: string; + page?: number; + perPage?: number; +}) => + queryOptions({ + queryKey: ["warehouse", "suppliers", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.search) params.set("search", filters.search); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/suppliers${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseLocationListOptions = () => + queryOptions({ + queryKey: ["warehouse", "locations"], + queryFn: () => + jsonQuery("/api/admin/warehouse/locations"), + }); + +export const warehouseReceiptListOptions = (filters: { + search?: string; + page?: number; + perPage?: number; + status?: string; + supplier_id?: number; + date_from?: string; + date_to?: string; +}) => + queryOptions({ + queryKey: ["warehouse", "receipts", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.search) params.set("search", filters.search); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + if (filters.status) params.set("status", filters.status); + if (filters.supplier_id) + params.set("supplier_id", String(filters.supplier_id)); + if (filters.date_from) params.set("date_from", filters.date_from); + if (filters.date_to) params.set("date_to", filters.date_to); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/receipts${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseReceiptDetailOptions = (id: string | undefined) => + queryOptions({ + queryKey: ["warehouse", "receipts", id], + queryFn: () => + jsonQuery(`/api/admin/warehouse/receipts/${id}`), + enabled: !!id, + }); + +export const warehouseIssueListOptions = (filters: { + search?: string; + page?: number; + perPage?: number; + status?: string; + project_id?: number; + date_from?: string; + date_to?: string; +}) => + queryOptions({ + queryKey: ["warehouse", "issues", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.search) params.set("search", filters.search); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + if (filters.status) params.set("status", filters.status); + if (filters.project_id) + params.set("project_id", String(filters.project_id)); + if (filters.date_from) params.set("date_from", filters.date_from); + if (filters.date_to) params.set("date_to", filters.date_to); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/issues${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseIssueDetailOptions = (id: string | undefined) => + queryOptions({ + queryKey: ["warehouse", "issues", id], + queryFn: () => + jsonQuery(`/api/admin/warehouse/issues/${id}`), + enabled: !!id, + }); + +export const warehouseReservationListOptions = (filters: { + page?: number; + perPage?: number; + item_id?: number; + project_id?: number; + status?: string; +}) => + queryOptions({ + queryKey: ["warehouse", "reservations", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + if (filters.item_id) params.set("item_id", String(filters.item_id)); + if (filters.project_id) + params.set("project_id", String(filters.project_id)); + if (filters.status) params.set("status", filters.status); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/reservations${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseInventoryListOptions = (filters: { + page?: number; + perPage?: number; + status?: string; +}) => + queryOptions({ + queryKey: ["warehouse", "inventory", "list", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters.page) params.set("page", String(filters.page)); + if (filters.perPage) params.set("per_page", String(filters.perPage)); + if (filters.status) params.set("status", filters.status); + const qs = params.toString(); + return paginatedJsonQuery( + `/api/admin/warehouse/inventory${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseInventoryDetailOptions = (id: string | undefined) => + queryOptions({ + queryKey: ["warehouse", "inventory", id], + queryFn: () => + jsonQuery( + `/api/admin/warehouse/inventory/${id}`, + ), + enabled: !!id, + }); + +export const warehouseStockStatusOptions = (filters?: { + category_id?: number; +}) => + queryOptions({ + queryKey: ["warehouse", "stock-status", filters], + queryFn: () => { + const params = new URLSearchParams(); + if (filters?.category_id) + params.set("category_id", String(filters.category_id)); + const qs = params.toString(); + return jsonQuery( + `/api/admin/warehouse/stock-status${qs ? `?${qs}` : ""}`, + ); + }, + }); + +export const warehouseBelowMinimumOptions = () => + queryOptions({ + queryKey: ["warehouse", "below-minimum"], + queryFn: () => + jsonQuery("/api/admin/warehouse/below-minimum"), + });