From df0b707064aba4fa22bdd63d0beff3955538bc25 Mon Sep 17 00:00:00 2001 From: "edgar.mendez" Date: Mon, 16 Feb 2026 14:34:18 -0600 Subject: [PATCH] CTL-51: feat(catalog): implement model document service and store - Added model-document.services.ts for handling API interactions related to model documents. - Created modelDocumentStore.ts using Pinia for state management of model documents, including actions for fetching, creating, updating, and deleting documents. - Defined model document types in modelDocument.interface.ts for better type safety and clarity. - Removed obsolete index.html file from warehouse components. - Updated router to include a new route for model documents. --- components.d.ts | 2 + src/components/layout/Sidebar.vue | 1 + .../catalog/components/ModelDocuments.vue | 193 ++++++++ src/modules/catalog/components/index.html | 378 +++++++++++++++ .../services/model-document.services.ts | 44 ++ .../catalog/stores/modelDocumentStore.ts | 115 +++++ .../catalog/types/modelDocument.interface.ts | 64 +++ src/modules/warehouse/components/index.html | 448 ------------------ src/router/index.ts | 11 + 9 files changed, 808 insertions(+), 448 deletions(-) create mode 100644 src/modules/catalog/components/ModelDocuments.vue create mode 100644 src/modules/catalog/components/index.html create mode 100644 src/modules/catalog/services/model-document.services.ts create mode 100644 src/modules/catalog/stores/modelDocumentStore.ts create mode 100644 src/modules/catalog/types/modelDocument.interface.ts delete mode 100644 src/modules/warehouse/components/index.html diff --git a/components.d.ts b/components.d.ts index bd79570..544ac24 100644 --- a/components.d.ts +++ b/components.d.ts @@ -31,6 +31,7 @@ declare module 'vue' { InputGroupAddon: typeof import('primevue/inputgroupaddon')['default'] InputIcon: typeof import('primevue/inputicon')['default'] InputNumber: typeof import('primevue/inputnumber')['default'] + InputSwitch: typeof import('primevue/inputswitch')['default'] InputText: typeof import('primevue/inputtext')['default'] KpiCard: typeof import('./src/components/shared/KpiCard.vue')['default'] Menu: typeof import('primevue/menu')['default'] @@ -39,6 +40,7 @@ declare module 'vue' { ProgressSpinner: typeof import('primevue/progressspinner')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + Select: typeof import('primevue/select')['default'] Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default'] Tag: typeof import('primevue/tag')['default'] Textarea: typeof import('primevue/textarea')['default'] diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index 2731b1c..48108a8 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -25,6 +25,7 @@ const menuItems = ref([ { label: 'Unidades de Medida', icon: 'pi pi-calculator', to: '/catalog/units-of-measure' }, { label: 'Clasificaciones Comerciales', icon: 'pi pi-tags', to: '/catalog/classifications-comercial' }, { label: 'Proveedores', icon: 'pi pi-briefcase', to: '/catalog/suppliers' }, + { label: 'Documentos del Modelo', icon: 'pi pi-file', to: '/catalog/model-documents' } ] }, { diff --git a/src/modules/catalog/components/ModelDocuments.vue b/src/modules/catalog/components/ModelDocuments.vue new file mode 100644 index 0000000..6a6434c --- /dev/null +++ b/src/modules/catalog/components/ModelDocuments.vue @@ -0,0 +1,193 @@ + + + diff --git a/src/modules/catalog/components/index.html b/src/modules/catalog/components/index.html new file mode 100644 index 0000000..11804bd --- /dev/null +++ b/src/modules/catalog/components/index.html @@ -0,0 +1,378 @@ + + + + + + + + System Document Types Management + + + + + + + + + +
+ + + +
+ +
+
+ menu +

Administración de Documentos

+
+
+ + +
+
+ +
+ +
+
+ +

Tipos de Documento

+

Gestione los formatos y folios permitidos para los + módulos de almacén y producción.

+
+ +
+ +
+
+ +
+ search + +
+
+
+ + +
+ + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID + + Nombre + Módulo IDTipo + ID + Folio Actual + Fecha Creación + Acciones
#1024 +
+ + Cotización +
+
+ ALM-01 + CT-DOC00054212/10/2023 +
+ + +
+
#1025 +
+ + Orden de Compra +
+
+ PRO-05 + OC-PRO00012815/10/2023 +
+ + +
+
#1026 +
+ + Vale de Salida +
+
+ ALM-01 + VS-INV00089118/10/2023 +
+ + +
+
#1027 +
+ + Ticket de + Mantenimiento +
+
+ PRO-02 + TM-MAI00004220/10/2023 +
+ + +
+
+
+ +
+

Mostrando 1-4 de + 24 tipos de documento

+
+ + + + + ... + + +
+
+
+ +
+
+
+ description +
+
+

Total Activos

+

24

+
+
+
+
+ update +
+
+

Último Folio Emitido

+

ALM-542

+
+
+
+
+ archive +
+
+

Archivados

+

12

+
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/src/modules/catalog/services/model-document.services.ts b/src/modules/catalog/services/model-document.services.ts new file mode 100644 index 0000000..bd2e0e5 --- /dev/null +++ b/src/modules/catalog/services/model-document.services.ts @@ -0,0 +1,44 @@ +import api from '../../../services/api'; +import type { + ModelDocument, + ModelDocumentPaginatedResponse, + CreateModelDocumentData, + UpdateModelDocumentData +} from '../types/modelDocument.interface'; + +export const modelDocumentService = { + // Obtener todos los documentos con paginación + getDocuments: async (page = 1, perPage = 15) => { + const response = await api.get('/api/catalogs/document-models', { + params: { + page, + per_page: perPage + } + }); + return response.data; + }, + + // Obtener un documento por ID + getDocumentById: async (id: number) => { + const response = await api.get<{ data: ModelDocument }>(`/api/catalogs/document-models/${id}`); + return response.data; + }, + + // Crear nuevo documento + createDocument: async (data: CreateModelDocumentData) => { + const response = await api.post<{ data: ModelDocument }>('/api/catalogs/document-models', data); + return response.data; + }, + + // Actualizar documento + updateDocument: async (id: number, data: UpdateModelDocumentData) => { + const response = await api.put<{ data: ModelDocument }>(`/api/catalogs/document-models/${id}`, data); + return response.data; + }, + + // Eliminar documento (soft delete) + deleteDocument: async (id: number) => { + const response = await api.delete(`/api/catalogs/document-models/${id}`); + return response.data; + } +}; diff --git a/src/modules/catalog/stores/modelDocumentStore.ts b/src/modules/catalog/stores/modelDocumentStore.ts new file mode 100644 index 0000000..d37e3f5 --- /dev/null +++ b/src/modules/catalog/stores/modelDocumentStore.ts @@ -0,0 +1,115 @@ +import { defineStore } from 'pinia'; +import { ref, computed } from 'vue'; +import { modelDocumentService } from '../services/model-document.services'; +import type { ModelDocument, CreateModelDocumentData, UpdateModelDocumentData } from '../types/modelDocument.interface'; + +export const useModelDocumentStore = defineStore('modelDocument', () => { + // State + const documents = ref([]); + const pagination = ref({ + currentPage: 1, + perPage: 15, + total: 0, + lastPage: 1 + }); + const loading = ref(false); + const error = ref(null); + + // Getters + const activeDocuments = computed(() => + documents.value.filter(doc => doc.deleted_at === null) + ); + + const deletedDocuments = computed(() => + documents.value.filter(doc => doc.deleted_at !== null) + ); + + // Actions + const fetchDocuments = async (page = 1) => { + loading.value = true; + error.value = null; + try { + const response = await modelDocumentService.getDocuments(page, pagination.value.perPage); + documents.value = response.data; + pagination.value = { + currentPage: response.current_page, + perPage: response.per_page, + total: response.total, + lastPage: response.last_page + }; + } catch (err: any) { + error.value = err.message || 'Error al cargar documentos'; + console.error('Error fetching documents:', err); + } finally { + loading.value = false; + } + }; + + const createDocument = async (data: CreateModelDocumentData) => { + loading.value = true; + error.value = null; + try { + await modelDocumentService.createDocument(data); + // Recargar la lista después de crear + await fetchDocuments(pagination.value.currentPage); + } catch (err: any) { + error.value = err.message || 'Error al crear documento'; + throw err; + } finally { + loading.value = false; + } + }; + + const updateDocument = async (id: number, data: UpdateModelDocumentData) => { + loading.value = true; + error.value = null; + try { + const response = await modelDocumentService.updateDocument(id, data); + const index = documents.value.findIndex(doc => doc.id === id); + if (index !== -1) { + documents.value[index] = response.data; + } + } catch (err: any) { + error.value = err.message || 'Error al actualizar documento'; + throw err; + } finally { + loading.value = false; + } + }; + + const deleteDocument = async (id: number) => { + loading.value = true; + error.value = null; + try { + await modelDocumentService.deleteDocument(id); + // Recargar la lista después de eliminar + await fetchDocuments(pagination.value.currentPage); + } catch (err: any) { + error.value = err.message || 'Error al eliminar documento'; + throw err; + } finally { + loading.value = false; + } + }; + + const changePage = async (page: number) => { + await fetchDocuments(page); + }; + + return { + // State + documents, + pagination, + loading, + error, + // Getters + activeDocuments, + deletedDocuments, + // Actions + fetchDocuments, + createDocument, + updateDocument, + deleteDocument, + changePage + }; +}); diff --git a/src/modules/catalog/types/modelDocument.interface.ts b/src/modules/catalog/types/modelDocument.interface.ts new file mode 100644 index 0000000..ff283f3 --- /dev/null +++ b/src/modules/catalog/types/modelDocument.interface.ts @@ -0,0 +1,64 @@ +// Tipos para Documentos del Sistema +export interface ModelDocument { + id: number; + name: string; + module: number; + type: number; + num_folio: number; + created_at: string; + updated_at: string; + deleted_at: string | null; +} + +export interface PaginationLink { + url: string | null; + label: string; + active: boolean; +} + +export interface ModelDocumentPaginatedResponse { + current_page: number; + data: ModelDocument[]; + first_page_url: string; + from: number; + last_page: number; + last_page_url: string; + links: PaginationLink[]; + next_page_url: string | null; + path: string; + per_page: number; + prev_page_url: string | null; + to: number; + total: number; +} + +export interface CreateModelDocumentData { + name: string; + module: number; + type: number; + num_folio?: number; +} + +export interface UpdateModelDocumentData extends Partial { +} + +export interface ModelDocumentStats { + total_active: number; + last_folio: string; + archived: number; +} + +// Module mapping +export const MODULE_NAMES: Record = { + 1: 'Ventas', + 2: 'Compras', + 3: 'Clientes', + 4: 'Proveedores', + 5: 'Inventarios' +}; + +// Type mapping +export const TYPE_NAMES: Record = { + 0: 'Sin Folio', + 1: 'Con Folio' +}; diff --git a/src/modules/warehouse/components/index.html b/src/modules/warehouse/components/index.html deleted file mode 100644 index 2f2ace4..0000000 --- a/src/modules/warehouse/components/index.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - Multi-Warehouse Goods Receipt Entry | Logistics Pro - - - - - - - - -
- -
-
-
-
- Inicio - chevron_right - Órdenes de Compra - chevron_right - Registrar Entrada (Multialmacén) -
-
-
-
- search - -
- - -
-
-
-
-
-
-

Registrar - Entrada de Mercancía

-

- receipt_long - Purchase Order #ORD-2023-001 | Distribución - Multi-Almacén -

-
-
-
-
-

Total Items - PO

-

12

-
-
-
-

Recibidos -

-

0

-
-
- -
-
-
-
-

Productos de la Orden

- - info - Seleccione el almacén de destino por cada producto - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ProductoSKU / RefCant. PORecibidaAlmacén de DestinoAcciones
-
-
- inventory -
-
- Cables - de Red Cat6 2m - Accesorios Networking -
-
-
NET-C62M-WH - - 50 -
- -
-
- - - Estándar -
-
-
- laptop_mac -
-
- MacBook - Pro M2 14" - Equipos de Cómputo -
-
-
LAP-MBP14-M2 - - 5 - 1 / 5 - -
Asignación por número de serie -
-
- -
-
-
-
-

- Entrada de Números de Serie (4 Pendientes)

-

Defina el almacén para - cada equipo escaneado

-
-
- barcode - Listo para escanear -
-
-
-
-
- -
- qr_code_scanner - -
-
-
- - -
- -
-
-
- - - - - - - - - - - - - - - - - - -
- Nº Serie - Almacén Destino
- SN-LAP-M2-00192 - - - Almacén - Principal (CDMX) - - - -
- Escanee el siguiente equipo para asignar - almacén... -
-
-
-
-
-
-
-
- print -
-
- Impresora - Zebra ZT411 - Hardware Almacén -
-
-
PRN-ZB411-IND - - 20 / 2 -
Asignación por serie requerida -
-
- -
-
-
-
-
- warning -
-

Pendiente de Validación - y Distribución

-

Faltan registrar 6 números de - serie y asignar almacén de destino a 1 item de tipo estándar antes de confirmar.

-
-
-
-

Resumen de - Destinos

-
-
- Almacén Principal (CDMX) - 1 Unidad -
-
- Bodega Regional (MTY) - 0 Unidades -
-
- CEDIS (GDL) - 0 Unidades -
-
-
-
-
-
- -
-
- - - - \ No newline at end of file diff --git a/src/router/index.ts b/src/router/index.ts index f8e6f2c..fb695ae 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -27,6 +27,8 @@ import Purchases from '../modules/purchases/components/Purchases.vue'; import PurchaseDetails from '../modules/purchases/components/PurchaseDetails.vue'; import PurchaseForm from '../modules/purchases/components/PurchaseForm.vue'; import WarehouseAddInventory from '../modules/warehouse/components/WarehouseAddInventory.vue'; +import ModelDocuments from '../modules/catalog/components/ModelDocuments.vue'; + const routes: RouteRecordRaw[] = [ { path: '/login', @@ -161,6 +163,15 @@ const routes: RouteRecordRaw[] = [ requiresAuth: true } }, + { + path: 'model-documents', + name: 'ModelDocuments', + component: ModelDocuments, + meta: { + title: 'Documentos del Modelo', + requiresAuth: true + } + } ] }, {