FE-001: Products Feature (16 archivos) - types/index.ts - Interfaces TypeScript - api/products.api.ts, categories.api.ts - Clientes Axios - hooks/useProducts, useCategories, useProductPricing - components/ProductForm, ProductCard, CategoryTree, VariantSelector, PricingTable - pages/ProductsPage, ProductDetailPage, CategoriesPage FE-002: Warehouses Feature (15 archivos) - types/index.ts - Interfaces TypeScript - api/warehouses.api.ts - Cliente Axios - hooks/useWarehouses, useLocations - components/WarehouseCard, LocationGrid, WarehouseLayout, ZoneCard, badges - pages/WarehousesPage, WarehouseDetailPage, LocationsPage, ZonesPage Ambos siguen patrones de inventory y React Query + react-hook-form + zod Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
162 lines
5.6 KiB
TypeScript
162 lines
5.6 KiB
TypeScript
import api from '@services/api/axios-instance';
|
|
import type { ApiResponse } from '@shared/types/api.types';
|
|
import type {
|
|
Warehouse,
|
|
WarehouseLocation,
|
|
CreateWarehouseDto,
|
|
UpdateWarehouseDto,
|
|
CreateLocationDto,
|
|
UpdateLocationDto,
|
|
WarehouseFilters,
|
|
LocationFilters,
|
|
WarehousesResponse,
|
|
LocationsResponse,
|
|
} from '../types';
|
|
|
|
const BASE_URL = '/api/v1/warehouses';
|
|
|
|
// ==================== Warehouses API ====================
|
|
|
|
export const warehousesApi = {
|
|
// List all warehouses with filters
|
|
list: async (filters?: WarehouseFilters): Promise<WarehousesResponse> => {
|
|
const response = await api.get<ApiResponse<Warehouse[]> & { total?: number }>(BASE_URL, {
|
|
params: filters,
|
|
});
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al obtener almacenes');
|
|
}
|
|
return {
|
|
data: response.data.data || [],
|
|
total: response.data.total || response.data.data?.length || 0,
|
|
};
|
|
},
|
|
|
|
// Get warehouse by ID
|
|
getById: async (id: string): Promise<Warehouse> => {
|
|
const response = await api.get<ApiResponse<Warehouse>>(`${BASE_URL}/${id}`);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Almacen no encontrado');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Get warehouse by code
|
|
getByCode: async (code: string): Promise<Warehouse> => {
|
|
const response = await api.get<ApiResponse<Warehouse>>(`${BASE_URL}/code/${code}`);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Almacen no encontrado');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Get default warehouse
|
|
getDefault: async (): Promise<Warehouse> => {
|
|
const response = await api.get<ApiResponse<Warehouse>>(`${BASE_URL}/default`);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'No hay almacen por defecto');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Get active warehouses
|
|
getActive: async (): Promise<Warehouse[]> => {
|
|
const response = await api.get<ApiResponse<Warehouse[]> & { total?: number }>(`${BASE_URL}/active`);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al obtener almacenes activos');
|
|
}
|
|
return response.data.data || [];
|
|
},
|
|
|
|
// Create warehouse
|
|
create: async (data: CreateWarehouseDto): Promise<Warehouse> => {
|
|
const response = await api.post<ApiResponse<Warehouse>>(BASE_URL, data);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al crear almacen');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Update warehouse
|
|
update: async (id: string, data: UpdateWarehouseDto): Promise<Warehouse> => {
|
|
const response = await api.patch<ApiResponse<Warehouse>>(`${BASE_URL}/${id}`, data);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al actualizar almacen');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Delete warehouse
|
|
delete: async (id: string): Promise<void> => {
|
|
const response = await api.delete<ApiResponse>(`${BASE_URL}/${id}`);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al eliminar almacen');
|
|
}
|
|
},
|
|
};
|
|
|
|
// ==================== Locations API ====================
|
|
|
|
export const locationsApi = {
|
|
// List all locations with filters
|
|
list: async (filters?: LocationFilters): Promise<LocationsResponse> => {
|
|
const response = await api.get<ApiResponse<WarehouseLocation[]> & { total?: number }>(
|
|
`${BASE_URL}/locations`,
|
|
{ params: filters }
|
|
);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al obtener ubicaciones');
|
|
}
|
|
return {
|
|
data: response.data.data || [],
|
|
total: response.data.total || response.data.data?.length || 0,
|
|
};
|
|
},
|
|
|
|
// Get location by ID
|
|
getById: async (id: string): Promise<WarehouseLocation> => {
|
|
const response = await api.get<ApiResponse<WarehouseLocation>>(`${BASE_URL}/locations/${id}`);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Ubicacion no encontrada');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Get locations by warehouse
|
|
getByWarehouse: async (warehouseId: string): Promise<WarehouseLocation[]> => {
|
|
const response = await api.get<ApiResponse<WarehouseLocation[]> & { total?: number }>(
|
|
`${BASE_URL}/${warehouseId}/locations`
|
|
);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al obtener ubicaciones del almacen');
|
|
}
|
|
return response.data.data || [];
|
|
},
|
|
|
|
// Create location
|
|
create: async (data: CreateLocationDto): Promise<WarehouseLocation> => {
|
|
const response = await api.post<ApiResponse<WarehouseLocation>>(`${BASE_URL}/locations`, data);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al crear ubicacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Update location
|
|
update: async (id: string, data: UpdateLocationDto): Promise<WarehouseLocation> => {
|
|
const response = await api.patch<ApiResponse<WarehouseLocation>>(`${BASE_URL}/locations/${id}`, data);
|
|
if (!response.data.success || !response.data.data) {
|
|
throw new Error(response.data.error || 'Error al actualizar ubicacion');
|
|
}
|
|
return response.data.data;
|
|
},
|
|
|
|
// Delete location
|
|
delete: async (id: string): Promise<void> => {
|
|
const response = await api.delete<ApiResponse>(`${BASE_URL}/locations/${id}`);
|
|
if (!response.data.success) {
|
|
throw new Error(response.data.error || 'Error al eliminar ubicacion');
|
|
}
|
|
},
|
|
};
|