feat: Add is_active field and classifications management to product and commercial classification components
This commit is contained in:
parent
73fb017ca6
commit
f98c2ba580
@ -11,6 +11,7 @@ import Dialog from 'primevue/dialog';
|
|||||||
import Dropdown from 'primevue/dropdown';
|
import Dropdown from 'primevue/dropdown';
|
||||||
import InputText from 'primevue/inputtext';
|
import InputText from 'primevue/inputtext';
|
||||||
import Textarea from 'primevue/textarea';
|
import Textarea from 'primevue/textarea';
|
||||||
|
import InputSwitch from 'primevue/inputswitch';
|
||||||
import ProgressSpinner from 'primevue/progressspinner';
|
import ProgressSpinner from 'primevue/progressspinner';
|
||||||
import Toast from 'primevue/toast';
|
import Toast from 'primevue/toast';
|
||||||
import { useComercialClassificationStore } from '../stores/comercialClassificationStore';
|
import { useComercialClassificationStore } from '../stores/comercialClassificationStore';
|
||||||
@ -26,6 +27,7 @@ interface Category {
|
|||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
parent_id: number | null;
|
parent_id: number | null;
|
||||||
|
is_active: number;
|
||||||
created_at: string;
|
created_at: string;
|
||||||
subcategories: Category[];
|
subcategories: Category[];
|
||||||
}
|
}
|
||||||
@ -45,7 +47,16 @@ const formData = ref({
|
|||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
parent_id: null as number | null
|
parent_id: null as number | null,
|
||||||
|
is_active: 1 as number
|
||||||
|
});
|
||||||
|
|
||||||
|
// Computed para el switch (convierte number a boolean y viceversa)
|
||||||
|
const isActiveSwitch = computed({
|
||||||
|
get: () => formData.value.is_active === 1,
|
||||||
|
set: (value: boolean) => {
|
||||||
|
formData.value.is_active = value ? 1 : 0;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Transform API data to component structure
|
// Transform API data to component structure
|
||||||
@ -56,6 +67,7 @@ const transformClassifications = (classifications: ComercialClassification[]): C
|
|||||||
name: cls.name,
|
name: cls.name,
|
||||||
description: cls.description || '',
|
description: cls.description || '',
|
||||||
parent_id: cls.parent_id,
|
parent_id: cls.parent_id,
|
||||||
|
is_active: cls.is_active,
|
||||||
created_at: cls.created_at,
|
created_at: cls.created_at,
|
||||||
subcategories: cls.children ? cls.children.map(child => ({
|
subcategories: cls.children ? cls.children.map(child => ({
|
||||||
id: child.id,
|
id: child.id,
|
||||||
@ -63,6 +75,7 @@ const transformClassifications = (classifications: ComercialClassification[]): C
|
|||||||
name: child.name,
|
name: child.name,
|
||||||
description: child.description || '',
|
description: child.description || '',
|
||||||
parent_id: child.parent_id,
|
parent_id: child.parent_id,
|
||||||
|
is_active: child.is_active,
|
||||||
created_at: child.created_at,
|
created_at: child.created_at,
|
||||||
subcategories: []
|
subcategories: []
|
||||||
})) : []
|
})) : []
|
||||||
@ -100,7 +113,8 @@ const addNewCategory = () => {
|
|||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
parent_id: null
|
parent_id: null,
|
||||||
|
is_active: 1
|
||||||
};
|
};
|
||||||
showCreateModal.value = true;
|
showCreateModal.value = true;
|
||||||
};
|
};
|
||||||
@ -161,7 +175,8 @@ const createClassification = async () => {
|
|||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
parent_id: null
|
parent_id: null,
|
||||||
|
is_active: 1
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error saving classification:', error);
|
console.error('Error saving classification:', error);
|
||||||
@ -186,7 +201,8 @@ const addSubcategory = () => {
|
|||||||
code: '',
|
code: '',
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
parent_id: selectedCategory.value.id
|
parent_id: selectedCategory.value.id,
|
||||||
|
is_active: 1
|
||||||
};
|
};
|
||||||
showCreateModal.value = true;
|
showCreateModal.value = true;
|
||||||
}
|
}
|
||||||
@ -201,7 +217,8 @@ const editCategory = () => {
|
|||||||
code: selectedCategory.value.code,
|
code: selectedCategory.value.code,
|
||||||
name: selectedCategory.value.name,
|
name: selectedCategory.value.name,
|
||||||
description: selectedCategory.value.description,
|
description: selectedCategory.value.description,
|
||||||
parent_id: selectedCategory.value.parent_id
|
parent_id: selectedCategory.value.parent_id,
|
||||||
|
is_active: selectedCategory.value.is_active
|
||||||
};
|
};
|
||||||
showCreateModal.value = true;
|
showCreateModal.value = true;
|
||||||
};
|
};
|
||||||
@ -256,7 +273,8 @@ const editSubcategory = (subcategory: Category) => {
|
|||||||
code: subcategory.code,
|
code: subcategory.code,
|
||||||
name: subcategory.name,
|
name: subcategory.name,
|
||||||
description: subcategory.description,
|
description: subcategory.description,
|
||||||
parent_id: subcategory.parent_id
|
parent_id: subcategory.parent_id,
|
||||||
|
is_active: subcategory.is_active
|
||||||
};
|
};
|
||||||
showCreateModal.value = true;
|
showCreateModal.value = true;
|
||||||
};
|
};
|
||||||
@ -600,6 +618,24 @@ onMounted(() => {
|
|||||||
Deja vacío para crear una clasificación raíz
|
Deja vacío para crear una clasificación raíz
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Active Status -->
|
||||||
|
<div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<div>
|
||||||
|
<label for="is_active" class="block text-sm font-medium mb-1">
|
||||||
|
Estado
|
||||||
|
</label>
|
||||||
|
<small class="text-surface-500 dark:text-surface-400">
|
||||||
|
Activa o desactiva esta clasificación comercial
|
||||||
|
</small>
|
||||||
|
</div>
|
||||||
|
<InputSwitch
|
||||||
|
id="is_active"
|
||||||
|
v-model="isActiveSwitch"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template #footer>
|
<template #footer>
|
||||||
|
|||||||
@ -11,7 +11,7 @@ export const comercialClassificationService = {
|
|||||||
* Get all comercial classifications with pagination
|
* Get all comercial classifications with pagination
|
||||||
* GET /api/comercial-classifications
|
* GET /api/comercial-classifications
|
||||||
*/
|
*/
|
||||||
async getClassifications(page = 1, perPage = 10): Promise<ComercialClassificationResponse> {
|
async getClassifications(page = 1, perPage = 100): Promise<ComercialClassificationResponse> {
|
||||||
const response = await api.get(`/api/comercial-classifications`, {
|
const response = await api.get(`/api/comercial-classifications`, {
|
||||||
params: { page, per_page: perPage }
|
params: { page, per_page: perPage }
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, computed, watch } from 'vue';
|
import { ref, computed, watch, onMounted } from 'vue';
|
||||||
|
import Card from 'primevue/card';
|
||||||
import InputText from 'primevue/inputtext';
|
import InputText from 'primevue/inputtext';
|
||||||
import Textarea from 'primevue/textarea';
|
import Textarea from 'primevue/textarea';
|
||||||
import Button from 'primevue/button';
|
import Button from 'primevue/button';
|
||||||
import Dropdown from 'primevue/dropdown';
|
|
||||||
import FileUpload from 'primevue/fileupload';
|
import FileUpload from 'primevue/fileupload';
|
||||||
|
import { useComercialClassificationStore } from '../../catalog/stores/comercialClassificationStore';
|
||||||
|
import { useUnitOfMeasureStore } from '../../catalog/stores/unitOfMeasureStore';
|
||||||
import type { Product, CreateProductData } from '../types/product';
|
import type { Product, CreateProductData } from '../types/product';
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
@ -24,6 +26,10 @@ const emit = defineEmits<{
|
|||||||
cancel: [];
|
cancel: [];
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
// Stores
|
||||||
|
const clasificationsStore = useComercialClassificationStore();
|
||||||
|
const unitOfMeasureStore = useUnitOfMeasureStore();
|
||||||
|
|
||||||
// Form data
|
// Form data
|
||||||
const formData = ref<CreateProductData>({
|
const formData = ref<CreateProductData>({
|
||||||
code: '',
|
code: '',
|
||||||
@ -34,7 +40,8 @@ const formData = ref<CreateProductData>({
|
|||||||
unit_of_measure_id: 0,
|
unit_of_measure_id: 0,
|
||||||
suggested_sale_price: 0,
|
suggested_sale_price: 0,
|
||||||
attributes: {},
|
attributes: {},
|
||||||
is_active: true
|
is_active: true,
|
||||||
|
classifications: []
|
||||||
});
|
});
|
||||||
|
|
||||||
// Temporary string for price input
|
// Temporary string for price input
|
||||||
@ -54,33 +61,90 @@ interface AttributeField {
|
|||||||
|
|
||||||
const attributes = ref<AttributeField[]>([]);
|
const attributes = ref<AttributeField[]>([]);
|
||||||
|
|
||||||
// Categories (placeholder - should come from a store)
|
// Units of measure from store
|
||||||
const categories = ref([
|
const unitsOfMeasure = computed(() => {
|
||||||
{ label: 'Selecciona una categoría', value: null },
|
return unitOfMeasureStore.activeUnits.map(unit => ({
|
||||||
{ label: 'Electrónicos', value: 1 },
|
label: unit.name,
|
||||||
{ label: 'Ropa', value: 2 },
|
value: unit.id
|
||||||
{ label: 'Hogar', value: 3 },
|
}));
|
||||||
{ label: 'Oficina', value: 4 }
|
});
|
||||||
]);
|
|
||||||
|
|
||||||
const selectedCategory = ref(null);
|
// Search classifications
|
||||||
|
const searchClassification = ref('');
|
||||||
|
|
||||||
const subcategories = ref([
|
// Computed para clasificaciones filtradas por búsqueda
|
||||||
{ label: 'Selecciona una subcategoría', value: null },
|
const filteredClassifications = computed(() => {
|
||||||
{ label: 'Ratones y Teclados', value: 1 },
|
const search = searchClassification.value.toLowerCase().trim();
|
||||||
{ label: 'Monitores', value: 2 },
|
|
||||||
{ label: 'Cables y Adaptadores', value: 3 }
|
|
||||||
]);
|
|
||||||
|
|
||||||
const selectedSubcategory = ref(null);
|
if (!search) {
|
||||||
|
// Retornar solo clasificaciones padre (sin parent_id)
|
||||||
|
return clasificationsStore.classifications.filter(cls => cls.parent_id === null);
|
||||||
|
}
|
||||||
|
|
||||||
// Unit of measure (placeholder - should come from a store)
|
// Filtrar clasificaciones que coincidan con la búsqueda
|
||||||
const unitsOfMeasure = ref([
|
return clasificationsStore.classifications
|
||||||
{ label: 'Unidad', value: 1 },
|
.filter(cls => cls.parent_id === null)
|
||||||
{ label: 'Kilogramo', value: 2 },
|
.map(parent => {
|
||||||
{ label: 'Metro', value: 3 },
|
// Filtrar hijos que coincidan con la búsqueda
|
||||||
{ label: 'Litro', value: 4 }
|
const matchingChildren = parent.children?.filter(child =>
|
||||||
]);
|
child.name.toLowerCase().includes(search) ||
|
||||||
|
child.code.toLowerCase().includes(search)
|
||||||
|
) || [];
|
||||||
|
|
||||||
|
// Incluir el padre si coincide o tiene hijos que coincidan
|
||||||
|
const parentMatches = parent.name.toLowerCase().includes(search) ||
|
||||||
|
parent.code.toLowerCase().includes(search);
|
||||||
|
|
||||||
|
if (parentMatches || matchingChildren.length > 0) {
|
||||||
|
return {
|
||||||
|
...parent,
|
||||||
|
children: matchingChildren.length > 0 ? matchingChildren : parent.children
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
})
|
||||||
|
.filter(cls => cls !== null);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Verificar si una clasificación está seleccionada
|
||||||
|
const isClassificationSelected = (classificationId: number) => {
|
||||||
|
return formData.value.classifications?.includes(classificationId) || false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle clasificación (agregar o quitar)
|
||||||
|
const toggleClassification = (classificationId: number) => {
|
||||||
|
if (!formData.value.classifications) {
|
||||||
|
formData.value.classifications = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = formData.value.classifications.indexOf(classificationId);
|
||||||
|
if (index > -1) {
|
||||||
|
// Quitar clasificación
|
||||||
|
formData.value.classifications.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
// Agregar clasificación
|
||||||
|
formData.value.classifications.push(classificationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📋 Classifications updated:', formData.value.classifications);
|
||||||
|
};
|
||||||
|
|
||||||
|
const loadingClassifications = computed(() => clasificationsStore.loading);
|
||||||
|
|
||||||
|
// Load classifications on mount
|
||||||
|
onMounted(async () => {
|
||||||
|
console.log('🔄 ProductForm mounted, loading classifications and units of measure...');
|
||||||
|
try {
|
||||||
|
await Promise.all([
|
||||||
|
clasificationsStore.fetchClassifications(),
|
||||||
|
unitOfMeasureStore.fetchUnits()
|
||||||
|
]);
|
||||||
|
console.log('✅ Classifications loaded:', clasificationsStore.classifications.length);
|
||||||
|
console.log('✅ Units of measure loaded:', unitOfMeasureStore.units.length);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Error loading data:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Watch for product changes (when editing)
|
// Watch for product changes (when editing)
|
||||||
watch(() => props.product, (newProduct) => {
|
watch(() => props.product, (newProduct) => {
|
||||||
@ -94,7 +158,8 @@ watch(() => props.product, (newProduct) => {
|
|||||||
unit_of_measure_id: newProduct.unit_of_measure_id,
|
unit_of_measure_id: newProduct.unit_of_measure_id,
|
||||||
suggested_sale_price: newProduct.suggested_sale_price,
|
suggested_sale_price: newProduct.suggested_sale_price,
|
||||||
attributes: newProduct.attributes || {},
|
attributes: newProduct.attributes || {},
|
||||||
is_active: newProduct.is_active
|
is_active: newProduct.is_active,
|
||||||
|
classifications: newProduct.classifications?.map(c => c.id) || []
|
||||||
};
|
};
|
||||||
|
|
||||||
priceInput.value = newProduct.suggested_sale_price.toString();
|
priceInput.value = newProduct.suggested_sale_price.toString();
|
||||||
@ -165,6 +230,9 @@ const handleSubmit = () => {
|
|||||||
|
|
||||||
formData.value.attributes = attributesObject;
|
formData.value.attributes = attributesObject;
|
||||||
|
|
||||||
|
// Log the data being sent
|
||||||
|
console.log('📤 Datos enviados al servidor:', JSON.stringify(formData.value, null, 2));
|
||||||
|
|
||||||
emit('save', formData.value);
|
emit('save', formData.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -248,15 +316,20 @@ const onUpload = (event: any) => {
|
|||||||
<label for="unit-measure" class="block text-sm font-medium mb-2">
|
<label for="unit-measure" class="block text-sm font-medium mb-2">
|
||||||
Unidad de Medida *
|
Unidad de Medida *
|
||||||
</label>
|
</label>
|
||||||
<Dropdown
|
<select
|
||||||
id="unit-measure"
|
id="unit-measure"
|
||||||
v-model="formData.unit_of_measure_id"
|
v-model="formData.unit_of_measure_id"
|
||||||
:options="unitsOfMeasure"
|
class="w-full rounded-lg border border-surface-300 dark:border-surface-600 bg-surface-0 dark:bg-surface-900 text-surface-900 dark:text-surface-0 px-3 py-2 focus:outline-none focus:ring-2 focus:ring-primary/50"
|
||||||
optionLabel="label"
|
>
|
||||||
optionValue="value"
|
<option value="0" disabled>Selecciona una unidad</option>
|
||||||
class="w-full"
|
<option
|
||||||
placeholder="Selecciona una unidad"
|
v-for="unit in unitsOfMeasure"
|
||||||
/>
|
:key="unit.value"
|
||||||
|
:value="unit.value"
|
||||||
|
>
|
||||||
|
{{ unit.label }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Suggested Sale Price -->
|
<!-- Suggested Sale Price -->
|
||||||
@ -408,40 +481,90 @@ const onUpload = (event: any) => {
|
|||||||
<!-- Organization Card -->
|
<!-- Organization Card -->
|
||||||
<Card>
|
<Card>
|
||||||
<template #title>
|
<template #title>
|
||||||
<h3 class="text-lg font-bold">Organización</h3>
|
<h3 class="text-lg font-bold">Clasificaciones de Producto</h3>
|
||||||
</template>
|
</template>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div class="space-y-6">
|
<div>
|
||||||
<!-- Category -->
|
<!-- Search input -->
|
||||||
<div>
|
<div class="relative mb-4">
|
||||||
<label for="category" class="block text-sm font-medium mb-2">
|
<InputText
|
||||||
Categoría
|
v-model="searchClassification"
|
||||||
</label>
|
type="search"
|
||||||
<Dropdown
|
class="w-full pl-10"
|
||||||
id="category"
|
placeholder="Buscar clasificaciones..."
|
||||||
v-model="selectedCategory"
|
|
||||||
:options="categories"
|
|
||||||
optionLabel="label"
|
|
||||||
optionValue="value"
|
|
||||||
class="w-full"
|
|
||||||
placeholder="Selecciona una categoría"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Subcategory -->
|
<!-- Classifications tree -->
|
||||||
<div>
|
<div class="space-y-2 h-96 overflow-y-auto pr-2">
|
||||||
<label for="subcategory" class="block text-sm font-medium mb-2">
|
<div
|
||||||
Subcategoría
|
v-for="classification in filteredClassifications"
|
||||||
</label>
|
:key="classification.id"
|
||||||
<Dropdown
|
class="space-y-1"
|
||||||
id="subcategory"
|
>
|
||||||
v-model="selectedSubcategory"
|
<!-- Parent classification -->
|
||||||
:options="subcategories"
|
<label class="flex items-center space-x-3 p-2 rounded-md hover:bg-surface-50 dark:hover:bg-surface-800/50 cursor-pointer">
|
||||||
optionLabel="label"
|
<input
|
||||||
optionValue="value"
|
type="checkbox"
|
||||||
class="w-full"
|
:value="classification.id"
|
||||||
placeholder="Selecciona una subcategoría"
|
:checked="isClassificationSelected(classification.id)"
|
||||||
/>
|
@change="toggleClassification(classification.id)"
|
||||||
|
class="w-5 h-5 rounded border-surface-300 dark:border-surface-600 text-primary focus:ring-primary/50"
|
||||||
|
/>
|
||||||
|
<span class="text-surface-700 dark:text-surface-300">
|
||||||
|
{{ classification.name }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<!-- Children classifications -->
|
||||||
|
<div
|
||||||
|
v-if="classification.children && classification.children.length > 0"
|
||||||
|
class="ml-6 pl-4 border-l-2 border-surface-200 dark:border-surface-700 space-y-1"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
v-for="child in classification.children"
|
||||||
|
:key="child.id"
|
||||||
|
class="flex items-center space-x-3 p-2 rounded-md hover:bg-surface-50 dark:hover:bg-surface-800/50 cursor-pointer"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:value="child.id"
|
||||||
|
:checked="isClassificationSelected(child.id)"
|
||||||
|
@change="toggleClassification(child.id)"
|
||||||
|
class="w-5 h-5 rounded border-surface-300 dark:border-surface-600 text-primary focus:ring-primary/50"
|
||||||
|
/>
|
||||||
|
<span class="text-surface-700 dark:text-surface-300">
|
||||||
|
{{ child.name }}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Empty state -->
|
||||||
|
<div
|
||||||
|
v-if="filteredClassifications.length === 0 && !loadingClassifications"
|
||||||
|
class="text-center py-8 text-surface-500"
|
||||||
|
>
|
||||||
|
<i class="pi pi-inbox text-4xl mb-2"></i>
|
||||||
|
<p>No se encontraron clasificaciones</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Loading state -->
|
||||||
|
<div
|
||||||
|
v-if="loadingClassifications"
|
||||||
|
class="text-center py-8 text-surface-500"
|
||||||
|
>
|
||||||
|
<i class="pi pi-spin pi-spinner text-4xl mb-2"></i>
|
||||||
|
<p>Cargando clasificaciones...</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Selected count -->
|
||||||
|
<div class="mt-4 pt-4 border-t border-surface-200 dark:border-surface-700">
|
||||||
|
<div class="text-sm text-surface-600 dark:text-surface-400">
|
||||||
|
<span class="font-medium">{{ formData.classifications?.length || 0 }}</span>
|
||||||
|
{{ (formData.classifications?.length || 0) === 1 ? 'clasificación seleccionada' : 'clasificaciones seleccionadas' }}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
2
src/modules/products/types/product.d.ts
vendored
2
src/modules/products/types/product.d.ts
vendored
@ -30,6 +30,7 @@ export interface CreateProductData {
|
|||||||
suggested_sale_price: number;
|
suggested_sale_price: number;
|
||||||
attributes?: Record<string, string[]>;
|
attributes?: Record<string, string[]>;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
|
classifications?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateProductData {
|
export interface UpdateProductData {
|
||||||
@ -42,6 +43,7 @@ export interface UpdateProductData {
|
|||||||
suggested_sale_price?: number;
|
suggested_sale_price?: number;
|
||||||
attributes?: Record<string, string[]>;
|
attributes?: Record<string, string[]>;
|
||||||
is_active?: boolean;
|
is_active?: boolean;
|
||||||
|
classifications?: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ProductPagination {
|
export interface ProductPagination {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user