Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1ca3949
feat: regex y ya no se puede poner 0
Rodrig0at Jun 5, 2025
ecf7714
fix: duplicado de máximo de caracteres
Rodrig0at Jun 5, 2025
5725ce7
Merge branch 'MBI-1' of https://github.com/CodeAnd-Co/Frontend-Text-L…
Rodrig0at Jun 6, 2025
552c1c4
Merge branch 'develop' of https://github.com/CodeAnd-Co/Frontend-Text…
Rodrig0at Jun 6, 2025
33d95f9
fix: botón que te lleva al formulario producto
Rodrig0at Jun 6, 2025
1f37163
feat: agregué el modal para renderizar el formularioactualizarproducto
Rodrig0at Jun 6, 2025
eb81894
feat:implementacion del actualizar producto, falta las validaciones d…
Rodrig0at Jun 7, 2025
95180b8
feat: mejorar validaciones en formularios de producto y variantes
Rodrig0at Jun 7, 2025
d86ec13
feat: mejorar validaciones en formularios de producto y variantes, op…
Rodrig0at Jun 7, 2025
12318ce
Merge branch 'MBI-1' of https://github.com/CodeAnd-Co/Frontend-Text-L…
Rodrig0at Jun 7, 2025
1c8f1ad
Merge branch 'MBI-1' of https://github.com/CodeAnd-Co/Frontend-Text-L…
Rodrig0at Jun 7, 2025
7b15276
feat: Implementar funcionalidad de actualización de productos y varia…
Rodrig0at Jun 10, 2025
65d2292
refactor: Quitar consoles log
Rodrig0at Jun 10, 2025
ea99686
refactor: Mejorar la legibilidad del código al ajustar el formato de …
Rodrig0at Jun 10, 2025
55a849e
refactor: Ajustar formato de código para mejorar la legibilidad
Rodrig0at Jun 10, 2025
1eb28b9
refactor: Eliminar importación innecesaria de axios en useActualizarP…
Rodrig0at Jun 10, 2025
b00a736
refactor: Mejorar la legibilidad del código al ajustar el formato de …
Rodrig0at Jun 10, 2025
f2a6992
refactor: Simplificar la lógica de eliminación de opciones y limpiar …
Rodrig0at Jun 10, 2025
5b5d67c
refactor: Optimizar la gestión de imágenes variantes al asegurar la i…
Rodrig0at Jun 10, 2025
dd063f8
refactor: Mejorar la legibilidad del código al ajustar el formato de …
Rodrig0at Jun 10, 2025
b06e156
refactor: Simplificar la actualización de errores en el formulario de…
Rodrig0at Jun 11, 2025
1e0e0ec
Merge branch 'MBI-1' of https://github.com/CodeAnd-Co/Frontend-Text-L…
Rodrig0at Jun 11, 2025
f728ff4
refactor: Ajustar la asignación de MENSAJE_POPUP_EXPORTAR y mejorar l…
Rodrig0at Jun 11, 2025
554ff84
refactor: Deja actualizar producto sin tener que reesubir las imágenes
Rodrig0at Jun 12, 2025
65568df
refactor: Mejorar la legibilidad del código al ajustar la asignación …
Rodrig0at Jun 12, 2025
1f6754c
refactor: Ajustar el tamaño del título del proveedor y mejorar la leg…
Rodrig0at Jun 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 9 additions & 8 deletions src/Dominio/Modelos/Productos/InfoProducto.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export class InfoProducto {
this.envio = producto.envio ?? 0;
this.impuesto = producto.impuesto ?? 0;
this.descuento = producto.descuento ?? 0;
this.descripcion = producto.descripcion ?? '';

// Variantes del producto (puede ser un arreglo vacío)
this.variantes = Array.isArray(producto.variantes)
Expand All @@ -42,14 +43,14 @@ class VarianteProducto {

class OpcionVariante {
constructor({
estado,
cantidad,
descuento,
valorOpcion,
SKUcomercial,
SKUautomatico,
costoAdicional,
}) {
estado,
cantidad,
descuento,
valorOpcion,
SKUcomercial,
SKUautomatico,
costoAdicional,
}) {
this.estado = estado ?? null;
this.cantidad = cantidad ?? 0;
this.descuento = descuento ?? 0;
Expand Down
118 changes: 118 additions & 0 deletions src/Dominio/Repositorios/Productos/RepositorioActualizarProducto.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// RF [29] Actualiza Producto - [https://codeandco-wiki.netlify.app/docs/proyectos/textiles/documentacion/requisitos/RF29]
import axios from 'axios';
import { RUTAS_API } from '@Utilidades/Constantes/rutasAPI';
import ProductoCompleto from '@Modelos/Productos/ProductoCompleto';
import Variante from '@Modelos/Productos/Variante';
const API_KEY = import.meta.env.VITE_API_KEY;

export class RepositorioActualizarProducto {
/**
* Actualiza un producto y sus variantes en el backend.
* @param {Object} productoRaw - Datos del producto a actualizar.
* @param {Array} variantesRaw - Lista de variantes del producto.
* @param {File|null} imagenProducto - Imagen del producto.
* @param {Object} imagenesVariantes - Mapa de imágenes por variante.
* @returns {Promise<Object>} Respuesta del servidor.
*/ static async actualizarProducto({
productoRaw,
variantesRaw,
imagenProducto,
imagenesVariantes,
}) {
try {
const form = new FormData();

// Verificar que tengamos un ID de producto válido
if (!productoRaw.idProducto) {
console.error('Error: No se encontró el ID del producto en los datos recibidos');
throw new Error(
'El ID del producto es requerido para actualizar. Por favor, asegúrate de seleccionar un producto válido.'
);
}

// Asegurarnos de que el ID del producto sea un string
form.append('idProducto', String(productoRaw.idProducto)); // Limpiar el objeto producto antes de enviarlo
const productoLimpio = {
idProducto: productoRaw.idProducto, // Asegurarnos de incluir el idProducto
nombreComun: productoRaw.nombreComun,
nombreComercial: productoRaw.nombreComercial,
descripcion: productoRaw.descripcion,
marca: productoRaw.marca,
modelo: productoRaw.modelo,
tipoProducto: productoRaw.tipoProducto,
precioPuntos: Number(productoRaw.precioPuntos),
precioCliente: Number(productoRaw.precioCliente),
precioVenta: Number(productoRaw.precioVenta),
costo: Number(productoRaw.costo),
impuesto: Number(productoRaw.impuesto),
descuento: Number(productoRaw.descuento),
estado: Number(productoRaw.estado),
envio: Number(productoRaw.envio),
idProveedor: productoRaw.idProveedor, // Agregar también el idProveedor
};

// Agregar el producto como JSON string
form.append('producto', JSON.stringify(productoLimpio));

// Limpiar y formatear las variantes
const variantesLimpias = variantesRaw.map((variante) => ({
identificador: String(variante.identificador),
nombreVariante: variante.nombreVariante,
descripcion: variante.descripcion,
opciones: Array.isArray(variante.opciones)
? variante.opciones.map((opcion) => ({
valorOpcion: opcion.valorOpcion,
cantidad: Number(opcion.cantidad),
SKUautomatico: opcion.SKUautomatico,
SKUcomercial: opcion.SKUcomercial,
costoAdicional: Number(opcion.costoAdicional || 0),
descuento: Number(opcion.descuento || 0),
estado: Number(opcion.estado || 1),
}))
: [],
}));

// Agregar las variantes como JSON string
form.append('variantes', JSON.stringify(variantesLimpias));

// Agregar imagen del producto si existe
if (imagenProducto instanceof File) {
form.append('imagenProducto', imagenProducto);
} // Agregar imágenes de variantes y construir el mapa
const mapaImagenes = [];
if (imagenesVariantes && typeof imagenesVariantes === 'object') {
for (const [idVariante, imagenesArray] of Object.entries(imagenesVariantes)) {
if (Array.isArray(imagenesArray)) {
for (const img of imagenesArray) {
if (img && img.file instanceof File) {
form.append('imagenesVariante', img.file);
mapaImagenes.push({
filename: img.file.name,
idVariante: String(idVariante),
});
}
}
}
}
}

// Agregar el mapa de imágenes como JSON string
form.append('mapaImagenes', JSON.stringify(mapaImagenes)); // Log para depuración

const respuesta = await axios.post(RUTAS_API.PRODUCTOS.ACTUALIZAR_PRODUCTO, form, {
withCredentials: true,
headers: {
'x-api-key': API_KEY,
'Content-Type': 'multipart/form-data',
Accept: 'application/json',
},
transformRequest: [(data) => data], // Prevenir que axios transforme el FormData
});

return respuesta.data;
} catch (error) {
const mensaje = error?.response?.data?.mensaje || 'Error al actualizar el producto';
throw new Error(mensaje);
}
}
}
3 changes: 2 additions & 1 deletion src/Utilidades/Constantes/rutasAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export const RUTAS_API = {
ELIMINAR_PRODUCTO: `${BASE_PRODUCTOS}/eliminar`,
IMPORTAR: `${BASE_PRODUCTOS}/importar`,
LEER_PRODCUTO: `${BASE_PRODUCTOS}/leer-producto`,
EXPORTAR_PRODUCTOS: `${BASE_PRODUCTOS}/exportar-productos`
EXPORTAR_PRODUCTOS: `${BASE_PRODUCTOS}/exportar-productos`,
ACTUALIZAR_PRODUCTO: `${BASE_PRODUCTOS}/actualizar`,
},
PROVEEDORES: {
BASE: BASE_PROVEEDORES,
Expand Down
35 changes: 21 additions & 14 deletions src/Utilidades/Validaciones/validarProducto.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,28 +51,35 @@ export const validarProducto = (producto) => {
} else if (!/^[1-9]\d{0,7}(\.\d{1,2})?$/.test(producto.costo.toString())) {
errores.costo = 'El costo debe tener máximo 10 dígitos.';
}

// Validación de impuesto
if (producto.impuesto === false) {
errores.impuesto = 'El impuesto no es válido o el campo está vacío.';
}
if (typeof producto.impuesto === 'number') {
if (!/^(0|[1-9]\d{0,4})(\.\d{1,2})?$/.test(producto.impuesto.toString())) {
errores.impuesto = 'El impuesto debe ser un número válido con máximo 5 dígitos.';
} else if (producto.impuesto !== undefined && producto.impuesto !== null) {
if (typeof producto.impuesto !== 'number' && isNaN(Number(producto.impuesto))) {
errores.impuesto = 'El impuesto debe ser un número válido.';
} else if (Number(producto.impuesto) < 0) {
errores.impuesto = 'El impuesto no puede ser negativo.';
} else if (Number(producto.impuesto) > 99999.99) {
errores.impuesto = 'El impuesto no puede ser mayor a 99999.99.';
} else if (!/^(0|[1-9]\d{0,4})(\.\d{1,2})?$/.test(producto.impuesto.toString())) {
errores.impuesto
= 'El impuesto debe ser un número válido con máximo 5 dígitos enteros y 2 decimales.';
}
}
// Validación de descuento

if (producto.descuento > 100) {
errores.descuento = 'El descuento debe estar entre 0 y 100.';
}

// Validación de descuento
if (producto.descuento === false) {
errores.descuento = 'El descuento no es válido o el campo está vacío.';
}
if (typeof producto.descuento === 'number') {
if (!/^(0|[1-9]\d{0,4})(\.\d{1,2})?$/.test(producto.descuento.toString())) {
errores.descuento = 'El descuento debe ser un número válido con máximo 5 dígitos.';
} else if (producto.descuento !== undefined && producto.descuento !== null) {
if (typeof producto.descuento !== 'number' && isNaN(Number(producto.descuento))) {
errores.descuento = 'El descuento debe ser un número válido.';
} else if (Number(producto.descuento) < 0) {
errores.descuento = 'El descuento no puede ser negativo.';
} else if (Number(producto.descuento) > 100) {
errores.descuento = 'El descuento debe estar entre 0 y 100.';
} else if (!/^(0|[1-9]?\d|100)(\.\d{1,2})?$/.test(producto.descuento.toString())) {
errores.descuento
= 'El descuento debe ser un número válido entre 0 y 100 con hasta 2 decimales.';
}
}

Expand Down
44 changes: 30 additions & 14 deletions src/Utilidades/Validaciones/validarVariantes.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,17 @@ export const validarVariantes = (variantes) => {
erroresOpcion.valorOpcion = 'El valor de la opción es obligatorio';
} else if (opcion.valorOpcion.trim().length > 50) {
erroresOpcion.valorOpcion = 'El valor de la opción debe tener máximo 50 caracteres';
}

// Validación de cantidad
if (!Number.isFinite(opcion.cantidad) || opcion.cantidad <= 0) {
erroresOpcion.cantidad = 'La cantidad debe ser un número mayor a 0';
} else if (!/^\d{1,10}$/.test(opcion.cantidad.toString())) {
erroresOpcion.cantidad = 'La cantidad debe tener máximo 10 dígitos.';
} // Validación de cantidad
if (opcion.cantidad === undefined || opcion.cantidad === null || opcion.cantidad === '') {
erroresOpcion.cantidad = 'La cantidad es obligatoria';
} else {
const cantidadNum = Number(opcion.cantidad);
if (isNaN(cantidadNum) || cantidadNum <= 0) {
erroresOpcion.cantidad = 'La cantidad debe ser un número mayor a 0';
} else if (cantidadNum > 9999999999) {
// 10 dígitos máximo (10^10 - 1)
erroresOpcion.cantidad = 'La cantidad no puede ser mayor a 9,999,999,999';
}
}

// Validación de descuento
Expand All @@ -62,13 +66,25 @@ export const validarVariantes = (variantes) => {
if (!/^(0|[1-9]\d{0,4})(\.\d{1,2})?$/.test(opcion.descuento.toString())) {
erroresOpcion.descuento = 'El descuento debe ser un número válido con máximo 5 dígitos.';
}
}

// Validación de costo adicional con formato (10,2)
if (!Number.isFinite(opcion.costoAdicional) || opcion.costoAdicional < 0) {
erroresOpcion.costoAdicional = 'El costo adicional no es válido o el campo está vacío.';
} else if (!/^\d{1,8}(\.\d{1,2})?$/.test(opcion.costoAdicional.toString())) {
erroresOpcion.costoAdicional = 'El costo adicional debe tener máximo 10 dígitos.';
} // Validación de costo adicional con formato (10,2)
if (
opcion.costoAdicional !== undefined
&& opcion.costoAdicional !== null
&& opcion.costoAdicional !== ''
) {
const costoNum = Number(opcion.costoAdicional);
if (isNaN(costoNum)) {
erroresOpcion.costoAdicional = 'El costo adicional debe ser un número válido';
} else if (costoNum < 0) {
erroresOpcion.costoAdicional = 'El costo adicional no puede ser negativo';
} else {
const partes = costoNum.toString().split('.');
if (partes[0] && partes[0].length > 8) {
erroresOpcion.costoAdicional = 'El costo adicional debe tener máximo 8 dígitos enteros';
} else if (partes[1] && partes[1].length > 2) {
erroresOpcion.costoAdicional = 'El costo adicional debe tener máximo 2 decimales';
}
}
}

if (!opcion.SKUautomatico?.trim()) {
Expand Down
Loading