diff --git a/src/components/layout/Sidebar.vue b/src/components/layout/Sidebar.vue index 687530a..b9b9508 100644 --- a/src/components/layout/Sidebar.vue +++ b/src/components/layout/Sidebar.vue @@ -38,7 +38,18 @@ const menuItems = ref([ ], }, { label: 'Clasificaciones Comerciales', icon: 'pi pi-tags', to: '/catalog/classifications-comercial' }, - { label: 'Proveedores', icon: 'pi pi-briefcase', to: '/catalog/suppliers' }, + { + label: 'Proveedores', + icon: 'pi pi-briefcase', + to: '/catalog/suppliers', + permission: [ + 'suppliers.index', + 'suppliers.show', + 'suppliers.store', + 'suppliers.update', + 'suppliers.destroy', + ], + }, { label: 'Documentos del Modelo', icon: 'pi pi-file', to: '/catalog/model-documents' }, { label: 'Empresas', @@ -57,7 +68,14 @@ const menuItems = ref([ { label: 'Productos', icon: 'pi pi-shopping-cart', - to: '/products' + to: '/products', + permission: [ + 'products.index', + 'products.show', + 'products.store', + 'products.update', + 'products.destroy', + ], }, { label: 'Requisiciones', diff --git a/src/modules/auth/services/authService.ts b/src/modules/auth/services/authService.ts index 641befb..ba19e2f 100644 --- a/src/modules/auth/services/authService.ts +++ b/src/modules/auth/services/authService.ts @@ -166,6 +166,8 @@ class AuthService { async getUserPermissions(): Promise { try { const response = await api.get('/api/user/permissions'); + console.log('User permissions response:', response); + return this.normalizePermissions(response.data); } catch (error: any) { this.resolveAuthError(error, 'Error al obtener permisos del usuario'); diff --git a/src/modules/catalog/components/suppliers/Suppliers.vue b/src/modules/catalog/components/suppliers/Suppliers.vue index a6a3479..3069e59 100644 --- a/src/modules/catalog/components/suppliers/Suppliers.vue +++ b/src/modules/catalog/components/suppliers/Suppliers.vue @@ -1,6 +1,5 @@ + + + + diff --git a/src/modules/catalog/services/unit-equivalences.services.ts b/src/modules/catalog/services/unit-equivalences.services.ts new file mode 100644 index 0000000..95b9e8d --- /dev/null +++ b/src/modules/catalog/services/unit-equivalences.services.ts @@ -0,0 +1,74 @@ +import api from '@/services/api'; + +import type { + UnitEquivalencesListResponse, + UnitEquivalenceResponse, + CreateUnitEquivalenceDTO, + UpdateUnitEquivalenceDTO, + ConvertDTO, + ConvertResponse, +} from '../types/unit-equivalence.interfaces'; + +export class UnitEquivalencesService { + public async list(params?: Record): Promise { + try { + const response = await api.get('/api/catalogs/unit-equivalences', { params }); + console.log('Fetched unit equivalences:', response.data); + return response.data; + } catch (error) { + console.error('Error fetching unit equivalences:', error); + throw error; + } + } + + public async show(id: number): Promise { + try { + const response = await api.get(`/api/catalogs/unit-equivalences/${id}`); + return response.data; + } catch (error) { + console.error('Error fetching unit equivalence:', error); + throw error; + } + } + + public async create(data: CreateUnitEquivalenceDTO): Promise { + try { + const response = await api.post('/api/catalogs/unit-equivalences', data); + return response.data; + } catch (error) { + console.error('Error creating unit equivalence:', error); + throw error; + } + } + + public async update(id: number, data: UpdateUnitEquivalenceDTO): Promise { + try { + const response = await api.put(`/api/catalogs/unit-equivalences/${id}`, data); + return response.data; + } catch (error) { + console.error('Error updating unit equivalence:', error); + throw error; + } + } + + public async destroy(id: number): Promise { + try { + await api.delete(`/api/catalogs/unit-equivalences/${id}`); + } catch (error) { + console.error('Error deleting unit equivalence:', error); + throw error; + } + } + + public async convert(data: ConvertDTO): Promise { + try { + const response = await api.post('/api/catalogs/unit-equivalences/convert', data); + return response.data; + } catch (error) { + console.error('Error converting units:', error); + throw error; + } + } +} + +export const unitEquivalencesService = new UnitEquivalencesService(); diff --git a/src/modules/catalog/stores/unitEquivalenceStore.ts b/src/modules/catalog/stores/unitEquivalenceStore.ts new file mode 100644 index 0000000..043e0de --- /dev/null +++ b/src/modules/catalog/stores/unitEquivalenceStore.ts @@ -0,0 +1,78 @@ +import { defineStore } from 'pinia'; +import { ref } from 'vue'; +import { unitEquivalencesService } from '../services/unit-equivalences.services'; +import type { UnitEquivalence, CreateUnitEquivalenceDTO, UpdateUnitEquivalenceDTO } from '../types/unit-equivalence.interfaces'; + +export const useUnitEquivalenceStore = defineStore('unitEquivalence', () => { + const equivalences = ref([]); + const loading = ref(false); + const error = ref(null); + + const fetchEquivalences = async (params: Record = {}) => { + try { + loading.value = true; + error.value = null; +const response = await unitEquivalencesService.list(params); +equivalences.value = Array.isArray(response.data) ? response.data : []; + + } catch (err) { + console.error('Error loading equivalences:', err); + error.value = err instanceof Error ? err.message : 'Error loading equivalences'; + throw err; + } finally { + loading.value = false; + } + }; + + const createEquivalence = async (data: CreateUnitEquivalenceDTO) => { + try { + loading.value = true; + const response = await unitEquivalencesService.create(data); + // refresh list + await fetchEquivalences(); + return response.unit_equivalence; + } catch (err) { + console.error('Error creating equivalence:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const updateEquivalence = async (id: number, data: Partial) => { + try { + loading.value = true; + const response = await unitEquivalencesService.update(id, data); + await fetchEquivalences(); + return response.unit_equivalence; + } catch (err) { + console.error('Error updating equivalence:', err); + throw err; + } finally { + loading.value = false; + } + }; + + const deleteEquivalence = async (id: number) => { + try { + loading.value = true; + await unitEquivalencesService.destroy(id); + await fetchEquivalences(); + } catch (err) { + console.error('Error deleting equivalence:', err); + throw err; + } finally { + loading.value = false; + } + }; + + return { + equivalences, + loading, + error, + fetchEquivalences, + createEquivalence, + updateEquivalence, + deleteEquivalence, + }; +}); diff --git a/src/modules/catalog/types/unit-equivalence.interfaces.ts b/src/modules/catalog/types/unit-equivalence.interfaces.ts new file mode 100644 index 0000000..9c3863a --- /dev/null +++ b/src/modules/catalog/types/unit-equivalence.interfaces.ts @@ -0,0 +1,55 @@ +export interface UnitEquivalence { + id: number; + from_unit_id: number; + to_unit_id: number; + product_id: number | null; + factor: number; + is_active: boolean; + from_unit?: any; + to_unit?: any; + product?: any | null; + operator?: string; +} + +export interface PaginationMeta { + current_page: number; + per_page: number; + total: number; +} + +export interface UnitEquivalencesListResponse { + data: UnitEquivalence[]; +} + +export interface UnitEquivalenceResponse { + unit_equivalence: UnitEquivalence; +} + +export interface CreateUnitEquivalenceDTO { + from_unit_id: number; + to_unit_id: number; + factor: number; + is_active?: boolean; + product_id?: number | null; + operator?: string | null; +} + +export type UpdateUnitEquivalenceDTO = Partial; + +export interface ConvertDTO { + value: number; + from_unit_id: number; + to_unit_id: number; + product_id?: number | null; +} + +export interface ConvertResponse { + conversion: { + input_value: number; + result_value: number; + factor_used: number; + direction: string; + source: string; + unit_equivalence_id?: number; + }; +} diff --git a/src/modules/products/components/ProductForm.vue b/src/modules/products/components/ProductForm.vue index facc074..cf7352a 100644 --- a/src/modules/products/components/ProductForm.vue +++ b/src/modules/products/components/ProductForm.vue @@ -10,6 +10,10 @@ import { useComercialClassificationStore } from '../../catalog/stores/comercialC import { useUnitOfMeasureStore } from '../../catalog/stores/unitOfMeasureStore'; import { satCodeProductsService, type SatCodeProduct } from '../../catalog/services/sat-code-products.services'; import type { Product, CreateProductData } from '../types/product'; +import { useAuth } from '@/modules/auth/composables/useAuth'; + +// Auth/Permissions +const { hasPermission } = useAuth(); // Props interface Props { @@ -32,6 +36,11 @@ const emit = defineEmits<{ const clasificationsStore = useComercialClassificationStore(); const unitOfMeasureStore = useUnitOfMeasureStore(); +// Computed permission to store or update +const canSaveProduct = computed(() => { + return props.isEditing ? hasPermission('products.update') : hasPermission('products.store'); +}); + // Form data const formData = ref({ code: '', @@ -700,11 +709,12 @@ const onUpload = (event: any) => { outlined @click="handleCancel" /> -