/** * Typed domain API client — wraps `apiRequest` with OpenAPI-generated types. * * Usage: * import { inventoryApi } from '@/shared/api-client' * const products = await inventoryApi.listProducts({ item_type: 'finished' }) * // products is typed as Schema<'ProductResponse'>[] */ import { apiRequest } from './api' import type { Schema } from '@/types/schemas' // ── Auth ─────────────────────────────────────────────────────── export const authApi = { login(username: string, password: string) { const body = new URLSearchParams({ username, password }) return apiRequest>('/api/auth/login', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: body.toString(), }) }, loginJson(username: string, password: string) { return apiRequest>('/api/auth/login/json', { method: 'POST', body: JSON.stringify({ username, password } satisfies Schema<'LoginRequest'>), }) }, me() { return apiRequest>('/api/auth/me') }, logout() { return apiRequest('/api/auth/logout', { method: 'POST' }) }, // Users listUsers() { return apiRequest[]>('/api/auth/users') }, createUser(data: Schema<'UserCreate'>) { return apiRequest>('/api/auth/users', { method: 'POST', body: JSON.stringify(data), }) }, updateUser(userId: number, data: Schema<'UserUpdate'>) { return apiRequest>(`/api/auth/users/${userId}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteUser(userId: number) { return apiRequest(`/api/auth/users/${userId}`, { method: 'DELETE' }) }, resetPassword(userId: number, newPassword: string) { return apiRequest(`/api/auth/users/${userId}/reset-password`, { method: 'PUT', body: JSON.stringify({ new_password: newPassword }), }) }, // Roles listRoles() { return apiRequest[]>('/api/auth/roles') }, createRole(data: Schema<'RoleCreate'>) { return apiRequest>('/api/auth/roles', { method: 'POST', body: JSON.stringify(data), }) }, updateRole(roleId: number, data: Schema<'RoleCreate'>) { return apiRequest>(`/api/auth/roles/${roleId}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteRole(roleId: number) { return apiRequest(`/api/auth/roles/${roleId}`, { method: 'DELETE' }) }, setRolePermissions(roleId: number, permissionIds: number[]) { return apiRequest(`/api/auth/roles/${roleId}/permissions`, { method: 'PUT', body: JSON.stringify({ permission_ids: permissionIds }), }) }, // Permissions listPermissions() { return apiRequest[]>('/api/auth/permissions') }, } // ── Inventory / ERP ──────────────────────────────────────────── export const inventoryApi = { // Dashboard dashboard() { return apiRequest('/api/dashboard') }, // Products listProducts(params?: { item_type?: string; limit?: number }) { const q = new URLSearchParams() if (params?.item_type) q.set('item_type', params.item_type) if (params?.limit) q.set('limit', String(params.limit)) const qs = q.toString() return apiRequest[]>(`/api/products${qs ? `?${qs}` : ''}`) }, createProduct(data: Schema<'ProductCreate'>) { return apiRequest>('/api/products', { method: 'POST', body: JSON.stringify(data), }) }, updateProduct(id: number, data: Partial>) { return apiRequest>(`/api/products/${id}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteProduct(id: number) { return apiRequest(`/api/products/${id}`, { method: 'DELETE' }) }, getProductMaterials(productId: number) { return apiRequest<{ items: Schema<'ProductMaterialItemResponse'>[] }>(`/api/products/${productId}/materials`) }, // from-task (mold analysis → product) createProductFromTask(taskId: string) { return apiRequest>(`/api/products/from-task/${taskId}`, { method: 'POST', }) }, // Warehouses listWarehouses() { return apiRequest[]>('/api/warehouses') }, createWarehouse(data: Schema<'WarehouseCreate'>) { return apiRequest>('/api/warehouses', { method: 'POST', body: JSON.stringify(data), }) }, // Inventory listInventory() { return apiRequest<{ items: Schema<'InventoryResponse'>[] }>('/api/inventory') }, // Stock Movements listStockMovements(params?: { limit?: number }) { const q = params?.limit ? `?limit=${params.limit}` : '' return apiRequest<{ items: Schema<'StockMovementResponse'>[] }>(`/api/stock-movements${q}`) }, // Suppliers listSuppliers() { return apiRequest[]>('/api/suppliers') }, createSupplier(data: Schema<'SupplierCreate'>) { return apiRequest>('/api/suppliers', { method: 'POST', body: JSON.stringify(data), }) }, updateSupplier(id: number, data: Partial>) { return apiRequest>(`/api/suppliers/${id}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteSupplier(id: number) { return apiRequest(`/api/suppliers/${id}`, { method: 'DELETE' }) }, // Customers listCustomers() { return apiRequest[]>('/api/customers') }, createCustomer(data: Schema<'CustomerCreate'>) { return apiRequest>('/api/customers', { method: 'POST', body: JSON.stringify(data), }) }, updateCustomer(id: number, data: Partial>) { return apiRequest>(`/api/customers/${id}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteCustomer(id: number) { return apiRequest(`/api/customers/${id}`, { method: 'DELETE' }) }, // Purchase Orders listPurchaseOrders(params?: { limit?: number }) { const q = params?.limit ? `?limit=${params.limit}` : '' return apiRequest<{ items: Schema<'PurchaseOrderResponse'>[] }>(`/api/purchase-orders${q}`) }, createPurchaseOrder(data: Schema<'PurchaseOrderCreate'>) { return apiRequest>('/api/purchase-orders', { method: 'POST', body: JSON.stringify(data), }) }, updatePurchaseOrder(id: number, data: Partial>) { return apiRequest>(`/api/purchase-orders/${id}`, { method: 'PUT', body: JSON.stringify(data), }) }, receivePurchaseOrder(id: number, data: Schema<'PurchaseOrderReceiveRequest'>) { return apiRequest>(`/api/purchase-orders/${id}/receive`, { method: 'POST', body: JSON.stringify(data), }) }, updatePurchaseOrderStatus(id: number, status: string) { return apiRequest>(`/api/purchase-orders/${id}/status`, { method: 'PATCH', body: JSON.stringify({ status }), }) }, // Sales Orders listSalesOrders(params?: { limit?: number }) { const q = params?.limit ? `?limit=${params.limit}` : '' return apiRequest<{ items: Schema<'SalesOrderResponse'>[] }>(`/api/sales-orders${q}`) }, getSalesOrder(id: number) { return apiRequest>(`/api/sales-orders/${id}`) }, createSalesOrder(data: Schema<'SalesOrderCreate'>) { return apiRequest>('/api/sales-orders', { method: 'POST', body: JSON.stringify(data), }) }, updateSalesOrder(id: number, data: Partial>) { return apiRequest>(`/api/sales-orders/${id}`, { method: 'PUT', body: JSON.stringify(data), }) }, deleteSalesOrder(id: number) { return apiRequest(`/api/sales-orders/${id}`, { method: 'DELETE' }) }, // Purchase Demands (采购需求推导) calculatePurchaseDemands(salesOrderIds: number[]) { return apiRequest>('/api/purchase-demands/calculate', { method: 'POST', body: JSON.stringify({ sales_order_ids: salesOrderIds } satisfies Schema<'PurchaseDemandCalculateRequest'>), }) }, // Finance financeSummary(params?: { year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest>(`/api/finance/summary?${q}`) }, financeTransactions(params?: { status?: string; limit?: number; year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.status) q.set('status', params.status) if (params?.limit) q.set('limit', String(params.limit)) if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest<{ items: Schema<'FinanceTransactionResponse'>[] }>(`/api/finance/transactions?${q}`) }, financeReceivables(params?: { limit?: number; year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.limit) q.set('limit', String(params.limit)) if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest[]>(`/api/finance/receivables?${q}`) }, financePayables(params?: { limit?: number; year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.limit) q.set('limit', String(params.limit)) if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest[]>(`/api/finance/payables?${q}`) }, financePartnerStatement(partnerType: 'customer' | 'supplier', params?: { year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest>(`/api/finance/partner-statement/${partnerType}?${q}`) }, financePartnerProductStatement(partnerType: 'customer' | 'supplier', params?: { year?: number; quarter?: number }) { const q = new URLSearchParams() if (params?.year) q.set('year', String(params.year)) if (params?.quarter) q.set('quarter', String(params.quarter)) return apiRequest>(`/api/finance/partner-product-statement/${partnerType}?${q}`) }, } // ── MoldInsight ──────────────────────────────────────────────── export const moldinsightApi = { uploadStp(formData: FormData) { return apiRequest<{ task_id: string }>('/api/upload', { method: 'POST', body: formData, }) }, getStatus(taskId: string) { return apiRequest<{ task_id: string status: string progress: number result?: Record error?: string }>(`/api/status/${taskId}`) }, batchUpload(formData: FormData) { return apiRequest<{ batch_id: string accepted: number rejected: number task_ids: string[] }>('/api/batch-upload', { method: 'POST', body: formData, }) }, getBatchStatus(batchId: string) { return apiRequest<{ batch_id: string total: number completed: number failed: number processing: number progress_percent: number tasks: Array<{ task_id: string filename: string status: string progress?: number error?: string html_file?: string }> }>(`/api/batch/${batchId}`) }, estimateCost(data: { task_id?: string material?: string mold_type?: string cavity_count?: number weight?: number dimensions?: { length: number; width: number; height: number } }) { return apiRequest<{ mold_cost?: number part_cost?: number total_mold_cost?: number confidence?: number assumptions?: string[] currency?: string }>('/api/cost-estimate', { method: 'POST', body: JSON.stringify(data), }) }, getAluminumPrice() { return apiRequest<{ price: number; unit: string; updated_at: string }>('/api/aluminum-price/current') }, }