feature-comercial-module-ts #13
1
components.d.ts
vendored
1
components.d.ts
vendored
@ -40,6 +40,7 @@ declare module 'vue' {
|
||||
Sidebar: typeof import('./src/components/layout/Sidebar.vue')['default']
|
||||
Tag: typeof import('primevue/tag')['default']
|
||||
Textarea: typeof import('primevue/textarea')['default']
|
||||
Toast: typeof import('primevue/toast')['default']
|
||||
TopBar: typeof import('./src/components/layout/TopBar.vue')['default']
|
||||
}
|
||||
export interface GlobalDirectives {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted } from 'vue';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import Button from 'primevue/button';
|
||||
@ -13,11 +13,12 @@ import InputText from 'primevue/inputtext';
|
||||
import Textarea from 'primevue/textarea';
|
||||
import ProgressSpinner from 'primevue/progressspinner';
|
||||
import Toast from 'primevue/toast';
|
||||
import { warehouseClassificationService } from '../services/warehouseClasificationService';
|
||||
import { useClassificationStore } from '../stores/classificationStore';
|
||||
import type { Classification } from '../types/warehouse.clasification';
|
||||
|
||||
const confirm = useConfirm();
|
||||
const toast = useToast();
|
||||
const classificationStore = useClassificationStore();
|
||||
|
||||
interface Category {
|
||||
id: number;
|
||||
@ -29,14 +30,16 @@ interface Category {
|
||||
subcategories: Category[];
|
||||
}
|
||||
|
||||
const categories = ref<Category[]>([]);
|
||||
const selectedCategory = ref<Category | null>(null);
|
||||
const showCreateModal = ref(false);
|
||||
const isSubmitting = ref(false);
|
||||
const loading = ref(false);
|
||||
const isEditMode = ref(false);
|
||||
const editingId = ref<number | null>(null);
|
||||
|
||||
// Computed properties from store
|
||||
const loading = computed(() => classificationStore.loading);
|
||||
const categories = computed(() => transformClassifications(classificationStore.classifications));
|
||||
|
||||
// Form data
|
||||
const formData = ref({
|
||||
code: '',
|
||||
@ -68,10 +71,7 @@ const transformClassifications = (classifications: Classification[]): Category[]
|
||||
|
||||
const loadClassifications = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await warehouseClassificationService.getClassifications();
|
||||
const classificationsData = response.data.data.warehouse_classifications.data;
|
||||
categories.value = transformClassifications(classificationsData);
|
||||
await classificationStore.fetchClassifications();
|
||||
|
||||
// Select first category by default
|
||||
if (categories.value.length > 0 && categories.value[0]) {
|
||||
@ -79,8 +79,12 @@ const loadClassifications = async () => {
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading classifications:', error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'No se pudieron cargar las clasificaciones.',
|
||||
life: 3000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -113,7 +117,7 @@ const createClassification = async () => {
|
||||
|
||||
if (isEditMode.value && editingId.value) {
|
||||
// Update existing classification
|
||||
await warehouseClassificationService.updateClassification(editingId.value, formData.value);
|
||||
await classificationStore.updateClassification(editingId.value, formData.value);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
@ -123,7 +127,7 @@ const createClassification = async () => {
|
||||
});
|
||||
} else {
|
||||
// Create new classification
|
||||
await warehouseClassificationService.createClassification(formData.value);
|
||||
await classificationStore.createClassification(formData.value);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
@ -133,9 +137,6 @@ const createClassification = async () => {
|
||||
});
|
||||
}
|
||||
|
||||
// Reload classifications
|
||||
await loadClassifications();
|
||||
|
||||
showCreateModal.value = false;
|
||||
isEditMode.value = false;
|
||||
editingId.value = null;
|
||||
@ -203,7 +204,7 @@ const deleteCategory = () => {
|
||||
accept: async () => {
|
||||
try {
|
||||
const categoryName = selectedCategory.value!.name;
|
||||
await warehouseClassificationService.deleteClassification(selectedCategory.value!.id);
|
||||
await classificationStore.deleteClassification(selectedCategory.value!.id);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
@ -214,9 +215,6 @@ const deleteCategory = () => {
|
||||
|
||||
// Clear selection
|
||||
selectedCategory.value = null;
|
||||
|
||||
// Reload classifications
|
||||
await loadClassifications();
|
||||
} catch (error) {
|
||||
console.error('Error deleting classification:', error);
|
||||
toast.add({
|
||||
@ -253,7 +251,7 @@ const deleteSubcategory = (subcategory: Category) => {
|
||||
acceptClass: 'p-button-danger',
|
||||
accept: async () => {
|
||||
try {
|
||||
await warehouseClassificationService.deleteClassification(subcategory.id);
|
||||
await classificationStore.deleteClassification(subcategory.id);
|
||||
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
@ -261,9 +259,6 @@ const deleteSubcategory = (subcategory: Category) => {
|
||||
detail: `La subclasificación "${subcategory.name}" ha sido eliminada exitosamente.`,
|
||||
life: 3000
|
||||
});
|
||||
|
||||
// Reload classifications
|
||||
await loadClassifications();
|
||||
} catch (error) {
|
||||
console.error('Error deleting subcategory:', error);
|
||||
toast.add({
|
||||
|
||||
@ -1,8 +1,23 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import Breadcrumb from 'primevue/breadcrumb';
|
||||
import Button from 'primevue/button';
|
||||
import Card from 'primevue/card';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import InputSwitch from 'primevue/inputswitch';
|
||||
import Textarea from 'primevue/textarea';
|
||||
import Dropdown from 'primevue/dropdown';
|
||||
import Chip from 'primevue/chip';
|
||||
import Avatar from 'primevue/avatar';
|
||||
import Toast from 'primevue/toast';
|
||||
import { warehouseService } from '../services/warehouseService';
|
||||
import { useClassificationStore } from '../stores/classificationStore';
|
||||
|
||||
const router = useRouter();
|
||||
const toast = useToast();
|
||||
const classificationStore = useClassificationStore();
|
||||
|
||||
const breadcrumbItems = ref([
|
||||
{ label: 'Almacenes', route: '/warehouse' },
|
||||
@ -18,41 +33,88 @@ const home = ref({
|
||||
const formData = ref({
|
||||
name: '',
|
||||
code: '',
|
||||
description: '',
|
||||
address: '',
|
||||
status: 'active',
|
||||
capacity: null,
|
||||
is_active: true,
|
||||
phone: '',
|
||||
email: ''
|
||||
});
|
||||
|
||||
const statusOptions = [
|
||||
{ label: 'Activo', value: 'active' },
|
||||
{ label: 'Inactivo', value: 'inactive' },
|
||||
{ label: 'En Mantenimiento', value: 'maintenance' }
|
||||
];
|
||||
const isSubmitting = ref(false);
|
||||
|
||||
// Categories from store
|
||||
const availableClassifications = computed(() => {
|
||||
return classificationStore.activeClassifications.map(cls => ({
|
||||
id: cls.id,
|
||||
name: cls.name,
|
||||
code: cls.code,
|
||||
parent_id: cls.parent_id,
|
||||
children: cls.children || []
|
||||
}));
|
||||
});
|
||||
|
||||
// Get root classifications (categories without parent)
|
||||
const rootClassifications = computed(() =>
|
||||
availableClassifications.value.filter(c => c.parent_id === null)
|
||||
);
|
||||
|
||||
// Categories
|
||||
const assignedCategories = ref([
|
||||
{ id: 1, name: 'Almacenamiento a Granel', color: 'info' },
|
||||
{ id: 2, name: 'Mercancía General', color: 'success' },
|
||||
{ id: 3, name: 'Control de Temperatura > Refrigerado', color: 'warn' }
|
||||
]);
|
||||
const assignedCategories = ref<any[]>([]);
|
||||
|
||||
// Get classification IDs from assigned categories
|
||||
const getClassificationIds = () => {
|
||||
return assignedCategories.value.map(cat => cat.id);
|
||||
};
|
||||
|
||||
const selectedParentCategory = ref(null);
|
||||
const selectedSubCategory = ref(null);
|
||||
const newCategoryName = ref('');
|
||||
const newCategoryParent = ref(null);
|
||||
|
||||
const parentCategories = [
|
||||
{ label: 'Control de Temperatura', value: 'temp' },
|
||||
{ label: 'Materiales Peligrosos', value: 'hazmat' },
|
||||
{ label: 'Alto Valor', value: 'high-value' }
|
||||
];
|
||||
// Get subcategories for selected parent
|
||||
const availableSubcategories = computed(() => {
|
||||
if (!selectedParentCategory.value) return [];
|
||||
const parent = availableClassifications.value.find(c => c.id === selectedParentCategory.value);
|
||||
return parent?.children || [];
|
||||
});
|
||||
|
||||
const subCategories = [
|
||||
{ label: 'Refrigerado', value: 'refrigerated' },
|
||||
{ label: 'Congelado', value: 'frozen' }
|
||||
];
|
||||
const addSelectedCategory = () => {
|
||||
if (!selectedParentCategory.value) return;
|
||||
|
||||
const parent = availableClassifications.value.find(c => c.id === selectedParentCategory.value);
|
||||
if (!parent) return;
|
||||
|
||||
let categoryToAdd = parent;
|
||||
let categoryName = parent.name;
|
||||
|
||||
// If subcategory is selected, use it instead
|
||||
if (selectedSubCategory.value) {
|
||||
const subcat = parent.children?.find((c: any) => c.id === selectedSubCategory.value);
|
||||
if (subcat) {
|
||||
categoryToAdd = subcat;
|
||||
categoryName = `${parent.name} > ${subcat.name}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if already added
|
||||
if (assignedCategories.value.some(c => c.id === categoryToAdd.id)) {
|
||||
toast.add({
|
||||
severity: 'warn',
|
||||
summary: 'Categoría ya agregada',
|
||||
detail: 'Esta categoría ya está asignada al almacén.',
|
||||
life: 3000
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
assignedCategories.value.push({
|
||||
id: categoryToAdd.id,
|
||||
name: categoryName,
|
||||
code: categoryToAdd.code
|
||||
});
|
||||
|
||||
// Reset selections
|
||||
selectedParentCategory.value = null;
|
||||
selectedSubCategory.value = null;
|
||||
};
|
||||
|
||||
// Staff
|
||||
const assignedStaff = ref([
|
||||
@ -76,25 +138,12 @@ const assignedStaff = ref([
|
||||
}
|
||||
]);
|
||||
|
||||
const saveDisabled = ref(true);
|
||||
const saveDisabled = ref(false);
|
||||
|
||||
const removeCategory = (id: number) => {
|
||||
assignedCategories.value = assignedCategories.value.filter(cat => cat.id !== id);
|
||||
};
|
||||
|
||||
const addCategory = () => {
|
||||
if (newCategoryName.value) {
|
||||
const newId = Math.max(...assignedCategories.value.map(c => c.id), 0) + 1;
|
||||
assignedCategories.value.push({
|
||||
id: newId,
|
||||
name: newCategoryName.value,
|
||||
color: 'info'
|
||||
});
|
||||
newCategoryName.value = '';
|
||||
newCategoryParent.value = null;
|
||||
}
|
||||
};
|
||||
|
||||
const addStaff = () => {
|
||||
console.log('Add staff');
|
||||
};
|
||||
@ -111,13 +160,50 @@ const cancel = () => {
|
||||
router.push('/warehouse');
|
||||
};
|
||||
|
||||
const save = () => {
|
||||
console.log('Save warehouse:', formData.value);
|
||||
const save = async () => {
|
||||
try {
|
||||
isSubmitting.value = true;
|
||||
|
||||
const warehouseData = {
|
||||
code: formData.value.code,
|
||||
name: formData.value.name,
|
||||
description: formData.value.description,
|
||||
classifications: getClassificationIds()
|
||||
};
|
||||
|
||||
await warehouseService.createWarehouse(warehouseData);
|
||||
|
||||
// Redirect to warehouse list with success message
|
||||
router.push({
|
||||
path: '/warehouse',
|
||||
query: {
|
||||
created: 'true',
|
||||
name: formData.value.name
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error creating warehouse:', error);
|
||||
toast.add({
|
||||
severity: 'error',
|
||||
summary: 'Error',
|
||||
detail: 'No se pudo crear el almacén. Por favor, intenta nuevamente.',
|
||||
life: 3000
|
||||
});
|
||||
} finally {
|
||||
isSubmitting.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
await classificationStore.fetchClassifications();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Toast Notifications -->
|
||||
<Toast position="bottom-right" />
|
||||
|
||||
<!-- Header con Breadcrumb y Acciones -->
|
||||
<div class="flex flex-wrap items-center justify-between gap-4">
|
||||
<div class="flex flex-col gap-2">
|
||||
@ -150,10 +236,12 @@ const save = () => {
|
||||
label="Cancelar"
|
||||
outlined
|
||||
@click="cancel"
|
||||
:disabled="isSubmitting"
|
||||
/>
|
||||
<Button
|
||||
label="Guardar Cambios"
|
||||
:disabled="saveDisabled"
|
||||
:disabled="saveDisabled || !formData.name || !formData.code"
|
||||
:loading="isSubmitting"
|
||||
@click="save"
|
||||
/>
|
||||
</div>
|
||||
@ -191,8 +279,20 @@ const save = () => {
|
||||
v-model="formData.code"
|
||||
class="w-full"
|
||||
placeholder="WH-001"
|
||||
disabled
|
||||
:class="'bg-surface-100 dark:bg-surface-700'"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Description -->
|
||||
<div class="col-span-full">
|
||||
<label for="description" class="block text-sm font-medium mb-2">
|
||||
Descripción
|
||||
</label>
|
||||
<Textarea
|
||||
id="description"
|
||||
v-model="formData.description"
|
||||
rows="3"
|
||||
class="w-full"
|
||||
placeholder="Descripción general del almacén"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -215,54 +315,15 @@ const save = () => {
|
||||
<label for="status" class="block text-sm font-medium mb-2">
|
||||
Estado
|
||||
</label>
|
||||
<Dropdown
|
||||
id="status"
|
||||
v-model="formData.status"
|
||||
:options="statusOptions"
|
||||
optionLabel="label"
|
||||
optionValue="value"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Capacity -->
|
||||
<div class="sm:col-span-3">
|
||||
<label for="capacity" class="block text-sm font-medium mb-2">
|
||||
Capacidad (Metros Cuadrados)
|
||||
</label>
|
||||
<InputNumber
|
||||
id="capacity"
|
||||
v-model="formData.capacity"
|
||||
class="w-full"
|
||||
:min="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Contact Phone -->
|
||||
<div class="sm:col-span-3">
|
||||
<label for="phone" class="block text-sm font-medium mb-2">
|
||||
Teléfono de Contacto
|
||||
</label>
|
||||
<InputText
|
||||
id="phone"
|
||||
v-model="formData.phone"
|
||||
class="w-full"
|
||||
placeholder="555-0101"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Contact Email -->
|
||||
<div class="sm:col-span-3">
|
||||
<label for="email" class="block text-sm font-medium mb-2">
|
||||
Correo de Contacto
|
||||
</label>
|
||||
<InputText
|
||||
id="email"
|
||||
v-model="formData.email"
|
||||
type="email"
|
||||
class="w-full"
|
||||
placeholder="almacen@empresa.com"
|
||||
/>
|
||||
<div class="flex items-center gap-3">
|
||||
<InputSwitch
|
||||
id="status"
|
||||
v-model="formData.is_active"
|
||||
/>
|
||||
<span class="text-sm font-medium">
|
||||
{{ formData.is_active ? 'Activo' : 'Inactivo' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -301,10 +362,12 @@ const save = () => {
|
||||
<Dropdown
|
||||
id="parent-category"
|
||||
v-model="selectedParentCategory"
|
||||
:options="parentCategories"
|
||||
optionLabel="label"
|
||||
:options="rootClassifications"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
placeholder="Selecciona una categoría..."
|
||||
class="w-full"
|
||||
showClear
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -315,43 +378,28 @@ const save = () => {
|
||||
<Dropdown
|
||||
id="sub-category"
|
||||
v-model="selectedSubCategory"
|
||||
:options="subCategories"
|
||||
optionLabel="label"
|
||||
:options="availableSubcategories"
|
||||
optionLabel="name"
|
||||
optionValue="id"
|
||||
placeholder="Selecciona una subcategoría..."
|
||||
class="w-full"
|
||||
showClear
|
||||
:disabled="!selectedParentCategory"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Create New Category -->
|
||||
<!-- Add Category Button -->
|
||||
<div>
|
||||
<label for="new-category" class="block text-sm font-medium mb-2">
|
||||
O Crear Nueva Categoría
|
||||
</label>
|
||||
<div class="flex gap-2">
|
||||
<div class="flex-1 space-y-2">
|
||||
<InputText
|
||||
id="new-category"
|
||||
v-model="newCategoryName"
|
||||
class="w-full"
|
||||
placeholder="Ej: Farmacéutico"
|
||||
/>
|
||||
<Dropdown
|
||||
v-model="newCategoryParent"
|
||||
:options="parentCategories"
|
||||
optionLabel="label"
|
||||
placeholder="Selecciona categoría padre (opcional)..."
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
icon="pi pi-plus"
|
||||
severity="secondary"
|
||||
outlined
|
||||
@click="addCategory"
|
||||
class="self-start"
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
label="Agregar Categoría Seleccionada"
|
||||
icon="pi pi-plus"
|
||||
severity="secondary"
|
||||
outlined
|
||||
@click="addSelectedCategory"
|
||||
:disabled="!selectedParentCategory"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -359,8 +407,8 @@ const save = () => {
|
||||
</div>
|
||||
|
||||
<!-- Sidebar - 1 column -->
|
||||
<div class="lg:col-span-1">
|
||||
<!-- Assigned Staff Card -->
|
||||
<!-- <div class="lg:col-span-1">
|
||||
|
||||
<Card>
|
||||
<template #title>
|
||||
<div class="flex items-center justify-between">
|
||||
@ -418,7 +466,7 @@ const save = () => {
|
||||
</div>
|
||||
</template>
|
||||
</Card>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -1,9 +1,13 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useRouter, useRoute } from 'vue-router';
|
||||
import { useToast } from 'primevue/usetoast';
|
||||
import Toast from 'primevue/toast';
|
||||
import { useWarehouseStore } from '../../../stores/warehouseStore';
|
||||
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
const toast = useToast();
|
||||
const warehouseStore = useWarehouseStore();
|
||||
|
||||
const searchQuery = ref('');
|
||||
@ -47,17 +51,31 @@ const createWarehouse = () => {
|
||||
router.push({ name: 'WarehouseCreate' });
|
||||
};
|
||||
|
||||
const loadWarehouses = async () => {
|
||||
await warehouseStore.fetchWarehouses();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
loadWarehouses();
|
||||
onMounted(async () => {
|
||||
// Reload warehouses to show new data
|
||||
await warehouseStore.refreshWarehouses();
|
||||
|
||||
// Check if we just created a warehouse
|
||||
if (route.query.created === 'true') {
|
||||
const warehouseName = route.query.name as string || 'el almacén';
|
||||
toast.add({
|
||||
severity: 'success',
|
||||
summary: 'Almacén Creado',
|
||||
detail: `El almacén "${warehouseName}" ha sido creado exitosamente.`,
|
||||
life: 4000
|
||||
});
|
||||
|
||||
// Clean up the query params
|
||||
router.replace({ path: '/warehouse' });
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="space-y-6">
|
||||
<!-- Toast Notifications -->
|
||||
<Toast position="bottom-right" />
|
||||
|
||||
<!-- Header -->
|
||||
<div class="flex flex-wrap justify-between gap-4 items-center">
|
||||
<div class="flex min-w-72 flex-col gap-1">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import api from '../../../services/api';
|
||||
import type { WarehousesResponse } from '../types/warehouse';
|
||||
import type { WarehousesResponse, CreateWarehouseData } from '../types/warehouse';
|
||||
|
||||
export const warehouseService = {
|
||||
async getWarehouses() {
|
||||
@ -11,5 +11,16 @@ export const warehouseService = {
|
||||
console.error('Error fetching warehouses:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
async createWarehouse(data: CreateWarehouseData) {
|
||||
try {
|
||||
const response = await api.post('/api/warehouses', data);
|
||||
console.log('Warehouse created:', response);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Error creating warehouse:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
115
src/modules/warehouse/stores/classificationStore.ts
Normal file
115
src/modules/warehouse/stores/classificationStore.ts
Normal file
@ -0,0 +1,115 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { ref, computed } from 'vue';
|
||||
import { warehouseClassificationService } from '../services/warehouseClasificationService';
|
||||
import type { Classification } from '../types/warehouse.clasification';
|
||||
|
||||
export const useClassificationStore = defineStore('warehouseClassifications', () => {
|
||||
// State
|
||||
const classifications = ref<Classification[]>([]);
|
||||
const loading = ref(false);
|
||||
const loaded = ref(false);
|
||||
const error = ref<string | null>(null);
|
||||
|
||||
// Getters
|
||||
const rootClassifications = computed(() =>
|
||||
classifications.value.filter(c => c.parent_id === null)
|
||||
);
|
||||
|
||||
const activeClassifications = computed(() =>
|
||||
classifications.value.filter(c => c.is_active)
|
||||
);
|
||||
|
||||
const getClassificationById = computed(() => {
|
||||
return (id: number) => classifications.value.find(c => c.id === id);
|
||||
});
|
||||
|
||||
const getChildrenOf = computed(() => {
|
||||
return (parentId: number) =>
|
||||
classifications.value.filter(c => c.parent_id === parentId);
|
||||
});
|
||||
|
||||
// Actions
|
||||
const fetchClassifications = async (force = false) => {
|
||||
if (loaded.value && !force) {
|
||||
return classifications.value;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
const response = await warehouseClassificationService.getClassifications();
|
||||
classifications.value = response.data.data.warehouse_classifications.data;
|
||||
loaded.value = true;
|
||||
return classifications.value;
|
||||
} catch (err) {
|
||||
error.value = 'Error al cargar las clasificaciones';
|
||||
console.error('Error fetching classifications:', err);
|
||||
throw err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
const refreshClassifications = async () => {
|
||||
return fetchClassifications(true);
|
||||
};
|
||||
|
||||
const clearClassifications = () => {
|
||||
classifications.value = [];
|
||||
loaded.value = false;
|
||||
error.value = null;
|
||||
};
|
||||
|
||||
const createClassification = async (data: any) => {
|
||||
try {
|
||||
const response = await warehouseClassificationService.createClassification(data);
|
||||
await refreshClassifications();
|
||||
return response;
|
||||
} catch (err) {
|
||||
error.value = 'Error al crear la clasificación';
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const updateClassification = async (id: number, data: any) => {
|
||||
try {
|
||||
const response = await warehouseClassificationService.updateClassification(id, data);
|
||||
await refreshClassifications();
|
||||
return response;
|
||||
} catch (err) {
|
||||
error.value = 'Error al actualizar la clasificación';
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
const deleteClassification = async (id: number) => {
|
||||
try {
|
||||
const response = await warehouseClassificationService.deleteClassification(id);
|
||||
await refreshClassifications();
|
||||
return response;
|
||||
} catch (err) {
|
||||
error.value = 'Error al eliminar la clasificación';
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
// State
|
||||
classifications,
|
||||
loading,
|
||||
loaded,
|
||||
error,
|
||||
// Getters
|
||||
rootClassifications,
|
||||
activeClassifications,
|
||||
getClassificationById,
|
||||
getChildrenOf,
|
||||
// Actions
|
||||
fetchClassifications,
|
||||
refreshClassifications,
|
||||
clearClassifications,
|
||||
createClassification,
|
||||
updateClassification,
|
||||
deleteClassification
|
||||
};
|
||||
});
|
||||
7
src/modules/warehouse/types/warehouse.d.ts
vendored
7
src/modules/warehouse/types/warehouse.d.ts
vendored
@ -11,6 +11,13 @@ export interface Warehouse {
|
||||
classifications: any[];
|
||||
}
|
||||
|
||||
export interface CreateWarehouseData {
|
||||
code: string;
|
||||
name: string;
|
||||
description: string;
|
||||
classifications: number[];
|
||||
}
|
||||
|
||||
export interface WarehousePagination {
|
||||
current_page: number;
|
||||
data: Warehouse[];
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user