From aeea112abd0934c45a501f4a15e982a07d448926 Mon Sep 17 00:00:00 2001 From: Edgar Mendez Mendoza Date: Sat, 8 Nov 2025 09:39:19 -0600 Subject: [PATCH] feat: add unit of measure management with CRUD operations and routing --- components.d.ts | 1 + src/components/layout/Sidebar.vue | 7 + .../catalog/components/UnitOfMeasure.vue | 443 ++++++++++++++++++ .../catalog/services/unitOfMeasureService.ts | 53 +++ src/modules/catalog/services/unitsTypes.ts | 14 + .../catalog/stores/unitOfMeasureStore.ts | 149 ++++++ src/modules/catalog/types/unitOfMeasure.d.ts | 75 +++ src/modules/catalog/types/unitTypes.d.ts | 15 + src/router/index.ts | 20 + 9 files changed, 777 insertions(+) create mode 100644 src/modules/catalog/components/UnitOfMeasure.vue create mode 100644 src/modules/catalog/services/unitOfMeasureService.ts create mode 100644 src/modules/catalog/services/unitsTypes.ts create mode 100644 src/modules/catalog/stores/unitOfMeasureStore.ts create mode 100644 src/modules/catalog/types/unitOfMeasure.d.ts create mode 100644 src/modules/catalog/types/unitTypes.d.ts diff --git a/components.d.ts b/components.d.ts index df067ad..79833a3 100644 --- a/components.d.ts +++ b/components.d.ts @@ -45,5 +45,6 @@ declare module 'vue' { } export interface GlobalDirectives { StyleClass: typeof import('primevue/styleclass')['default'] + Tooltip: typeof import('primevue/tooltip')['default'] } } diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index 6e0bb30..8492db1 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -26,6 +26,13 @@ const menuItems = ref([ { label: 'Administrar Clasificaciones', icon: 'pi pi-sitemap', to: '/warehouse/classifications' } ] }, + { + label: 'Catálogo', + icon: 'pi pi-book', + items: [ + { label: 'Unidades de Medida', icon: 'pi pi-calculator', to: '/catalog/units-of-measure' } + ] + }, { label: 'Ventas', icon: 'pi pi-shopping-cart', diff --git a/src/modules/catalog/components/UnitOfMeasure.vue b/src/modules/catalog/components/UnitOfMeasure.vue new file mode 100644 index 0000000..61560f8 --- /dev/null +++ b/src/modules/catalog/components/UnitOfMeasure.vue @@ -0,0 +1,443 @@ + + + diff --git a/src/modules/catalog/services/unitOfMeasureService.ts b/src/modules/catalog/services/unitOfMeasureService.ts new file mode 100644 index 0000000..8ec93c5 --- /dev/null +++ b/src/modules/catalog/services/unitOfMeasureService.ts @@ -0,0 +1,53 @@ +import api from '../../../services/api'; +import type { + UnitOfMeasureResponse, + CreateUnitOfMeasureData, + UpdateUnitOfMeasureData, + SingleUnitOfMeasureResponse +} from '../types/unitOfMeasure'; + +export const unitOfMeasureService = { + /** + * Get all units of measure with pagination + */ + async getUnits(page = 1, perPage = 10): Promise { + const response = await api.get(`/api/catalogs/units-of-measure`, { + params: { page, per_page: perPage } + }); + + console.log('Units of Measure response:', response); + return response.data; + }, + + /** + * Get a single unit of measure by ID + */ + async getUnitById(id: number): Promise { + const response = await api.get(`/api/catalogs/units-of-measure/${id}`); + return response.data; + }, + + /** + * Create a new unit of measure + */ + async createUnit(data: CreateUnitOfMeasureData): Promise { + const response = await api.post(`/api/catalogs/units-of-measure`, data); + console.log('Create Unit response:', response); + return response.data; + }, + + /** + * Update an existing unit of measure + */ + async updateUnit(id: number, data: UpdateUnitOfMeasureData): Promise { + const response = await api.put(`/api/catalogs/units-of-measure/${id}`, data); + return response.data; + }, + + /** + * Delete a unit of measure + */ + async deleteUnit(id: number): Promise { + await api.delete(`/api/catalogs/units-of-measure/${id}`); + } +}; diff --git a/src/modules/catalog/services/unitsTypes.ts b/src/modules/catalog/services/unitsTypes.ts new file mode 100644 index 0000000..9a649c4 --- /dev/null +++ b/src/modules/catalog/services/unitsTypes.ts @@ -0,0 +1,14 @@ +import api from '../../../services/api'; +import type { UnitTypesResponse } from '../types/unitTypes'; + +export const unitTypesService = { + /** + * Get all unit types + * Returns the list of available unit types (Unidad, Peso, Volumen, Longitud, etc.) + */ + async getUnitTypes(): Promise { + const response = await api.get(`/api/catalogs/unit-types`); + console.log('Unit Types response:', response.data); + return response.data; + }, +}; diff --git a/src/modules/catalog/stores/unitOfMeasureStore.ts b/src/modules/catalog/stores/unitOfMeasureStore.ts new file mode 100644 index 0000000..388e891 --- /dev/null +++ b/src/modules/catalog/stores/unitOfMeasureStore.ts @@ -0,0 +1,149 @@ +import { defineStore } from 'pinia'; +import { ref, computed } from 'vue'; +import { unitOfMeasureService } from '../services/unitOfMeasureService'; +import type { UnitOfMeasure, CreateUnitOfMeasureData, UpdateUnitOfMeasureData } from '../types/unitOfMeasure'; + +export const useUnitOfMeasureStore = defineStore('unitOfMeasure', () => { + // State + const units = ref([]); + const loading = ref(false); + const loaded = ref(false); + const error = ref(null); + + // Getters + const activeUnits = computed(() => + units.value.filter(unit => unit.is_active === 1) + ); + + const inactiveUnits = computed(() => + units.value.filter(unit => unit.is_active === 0) + ); + + const unitCount = computed(() => units.value.length); + + const getUnitById = computed(() => { + return (id: number) => units.value.find(unit => unit.id === id); + }); + + const getUnitByAbbreviation = computed(() => { + return (abbreviation: string) => + units.value.find(unit => unit.abbreviation.toLowerCase() === abbreviation.toLowerCase()); + }); + + // Actions + const fetchUnits = async (force = false) => { + // Si ya están cargados y no se fuerza la recarga, no hacer nada + if (loaded.value && !force) { + console.log('Units of measure already loaded from store'); + return; + } + + try { + loading.value = true; + error.value = null; + + const response = await unitOfMeasureService.getUnits(); + units.value = response.data.units_of_measure.data; + loaded.value = true; + + console.log('Units of measure loaded into store:', units.value.length); + } catch (err) { + error.value = err instanceof Error ? err.message : 'Error loading units of measure'; + console.error('Error in unit of measure store:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const refreshUnits = () => { + return fetchUnits(true); + }; + + const createUnit = async (data: CreateUnitOfMeasureData) => { + try { + loading.value = true; + error.value = null; + + await unitOfMeasureService.createUnit(data); + + // Refrescar la lista después de crear + await refreshUnits(); + + console.log('Unit of measure created successfully'); + } catch (err) { + error.value = err instanceof Error ? err.message : 'Error creating unit of measure'; + console.error('Error creating unit of measure:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const updateUnit = async (id: number, data: UpdateUnitOfMeasureData) => { + try { + loading.value = true; + error.value = null; + + await unitOfMeasureService.updateUnit(id, data); + + // Refrescar la lista después de actualizar + await refreshUnits(); + + console.log('Unit of measure updated successfully'); + } catch (err) { + error.value = err instanceof Error ? err.message : 'Error updating unit of measure'; + console.error('Error updating unit of measure:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const deleteUnit = async (id: number) => { + try { + loading.value = true; + error.value = null; + + await unitOfMeasureService.deleteUnit(id); + + // Refrescar la lista después de eliminar + await refreshUnits(); + + console.log('Unit of measure deleted successfully'); + } catch (err) { + error.value = err instanceof Error ? err.message : 'Error deleting unit of measure'; + console.error('Error deleting unit of measure:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const clearUnits = () => { + units.value = []; + loaded.value = false; + error.value = null; + }; + + return { + // State + units, + loading, + loaded, + error, + // Getters + activeUnits, + inactiveUnits, + unitCount, + getUnitById, + getUnitByAbbreviation, + // Actions + fetchUnits, + refreshUnits, + createUnit, + updateUnit, + deleteUnit, + clearUnits, + }; +}); diff --git a/src/modules/catalog/types/unitOfMeasure.d.ts b/src/modules/catalog/types/unitOfMeasure.d.ts new file mode 100644 index 0000000..7f13497 --- /dev/null +++ b/src/modules/catalog/types/unitOfMeasure.d.ts @@ -0,0 +1,75 @@ +/** + * Unit of Measure Type Definitions + */ + +export interface UnitOfMeasure { + id: number; + code: string; + name: string; + type: number; + type_name: string; + abbreviation: string; + is_active: number; // API returns 0 or 1 + created_at: string; + updated_at: string; + deleted_at: string | null; +} + +export interface CreateUnitOfMeasureData { + code: string; + name: string; + type: number; + abbreviation: string; + is_active?: number; +} + +export interface UpdateUnitOfMeasureData { + code?: string; + name?: string; + type?: number; + abbreviation?: string; + is_active?: number; +} + +export interface UnitOfMeasurePagination { + current_page: number; + last_page: number; + per_page: number; + total: number; + from: number; + to: number; + first_page_url: string; + last_page_url: string; + next_page_url: string | null; + prev_page_url: string | null; + path: string; +} + +export interface UnitOfMeasureData { + current_page: number; + data: UnitOfMeasure[]; + first_page_url: string; + from: number; + last_page: number; + last_page_url: string; + next_page_url: string | null; + path: string; + per_page: number; + prev_page_url: string | null; + to: number; + total: number; +} + +export interface UnitOfMeasureResponse { + status: string; + data: { + units_of_measure: UnitOfMeasureData; + }; +} + +export interface SingleUnitOfMeasureResponse { + status: string; + data: { + unit_of_measure: UnitOfMeasure; + }; +} diff --git a/src/modules/catalog/types/unitTypes.d.ts b/src/modules/catalog/types/unitTypes.d.ts new file mode 100644 index 0000000..7a7c723 --- /dev/null +++ b/src/modules/catalog/types/unitTypes.d.ts @@ -0,0 +1,15 @@ +/** + * Unit Types Definitions + */ + +export interface UnitType { + id: number; + name: string; +} + +export interface UnitTypesResponse { + status: string; + data: { + unit_types: UnitType[]; + }; +} diff --git a/src/router/index.ts b/src/router/index.ts index de02bd1..864ab27 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -8,6 +8,7 @@ import WarehouseIndex from '../modules/warehouse/components/WarehouseIndex.vue'; import WarehouseForm from '../modules/warehouse/components/WarehouseForm.vue'; import WarehouseCategory from '../modules/warehouse/components/WarehouseCategory.vue'; import WarehouseClassification from '../modules/warehouse/components/WarehouseClassification.vue'; +import UnitOfMeasure from '../modules/catalog/components/UnitOfMeasure.vue'; const routes: RouteRecordRaw[] = [ { @@ -89,6 +90,25 @@ const routes: RouteRecordRaw[] = [ } } ] + }, + { + path: 'catalog', + name: 'Catalog', + meta: { + title: 'Catálogo', + requiresAuth: true + }, + children: [ + { + path: 'units-of-measure', + name: 'UnitsOfMeasure', + component: UnitOfMeasure, + meta: { + title: 'Unidades de Medida', + requiresAuth: true + } + } + ] } ] },