Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
49 changes: 47 additions & 2 deletions src/modules/users/cart/cart.controller.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { addCartItemService, getActiveCartsForUserService, getCartItemsByIdService } from "./cart.service.js";
import {
addCartItemService,
getActiveCartsForUserService,
getCartItemsByIdService,
removeCartItemService,
updatedCartItemQuantityService } from "./cart.service.js";

/**
* GET /api/users/:customerId/carts
Expand Down Expand Up @@ -67,4 +72,44 @@ export const getCartItemsById = async (req, res, next) => {
} catch (error) {
next(error);
}
}
}

/**
*
* DELETE /api/users/cart/items/:cartItemId - elimina un item del carrito de compras
*/
export const removeCartItem = async (req, res, next) => {
try {
if (!req.user?.id_user) {
return res.status(401).json({
message: "Usuario autenticado requerido"
});
}
const { cartItemId } = req.params;
const updatedCart = await removeCartItemService(req.user.id_user, cartItemId);
return res.status(200).json(updatedCart);
} catch (error) {
next(error);
}
};

/**
*
* PUT /api/users/cart/items/:cartItemId - actualiza la cantidad de un item del carrito de compras
* Body: { quantity }
*/
export const updateCartItemQuantity = async (req, res, next) => {
try {
if (!req.user?.id_user) {
return res.status(401).json({
message: "Usuario autenticado requerido"
});
}
const { cartItemId } = req.params;
const { quantity } = req.body;
const updatedCart = await updatedCartItemQuantityService(req.user.id_user, cartItemId, quantity);
return res.status(200).json(updatedCart);
} catch (error) {
next(error);
}
};
8 changes: 7 additions & 1 deletion src/modules/users/cart/cart.routes.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Router } from "express";
import authenticate from "../../../config/jwt.config.js";
import { getCarts, addCartItem, getCartItemsById } from "./cart.controller.js";
import { getCarts, addCartItem, getCartItemsById, removeCartItem, updateCartItemQuantity } from "./cart.controller.js";

const router = Router({ mergeParams: true });

Expand All @@ -13,4 +13,10 @@ router.post("/:customerId/cart/items", authenticate, addCartItem);
// GET /api/users/cart/:cartId/items - obtiene los items de un carrito especifico
router.get("/cart/:cartId/items", authenticate, getCartItemsById);

// DELETE /api/users/cart/items/:cartItemId - elimina un item del carrito de compras
router.delete("/cart/items/:cartItemId", authenticate, removeCartItem);


// PUT /api/users/cart/items/:cartItemId - actualiza la cantidad de un item del carrito de compras
router.put("/cart/items/:cartItemId", authenticate, updateCartItemQuantity);
export default router;
83 changes: 82 additions & 1 deletion src/modules/users/cart/cart.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,85 @@ export const getCartItemsByIdService = async (authenticatedUserId, cartId) => {
}
};
});
};
};

/**
* Elimina un item del carrito de compras
* DELETE /api/users/cart/items/:cartItemId
*
*/
export const removeCartItemService = async (authenticatedUserId, cartItemId) => {
const resolvedCartItemId = parsePositiveInteger(cartItemId, "cartItemId");
const resolvedUserId = parsePositiveInteger(authenticatedUserId, "authenticatedUserId");

//validar que el item existe, que el carrito al que pertenece es del user autenticado, y que ambos estén activos
const cartItem = await prisma.cartItems.findFirst({
where: {
id_cart_item: resolvedCartItemId,
status: true,
cart: {
fk_user: resolvedUserId,
status: true,
cart_status: "ACTIVE"
}
},
select: {id_cart_item: true, fk_cart: true }
});

if (!cartItem) throw new NotFoundError("Item de carrito no encontrado.");

//se aplica el borrado logico del item
const updated = await prisma.cartItems.update({
where: { id_cart_item: resolvedCartItemId },
data: { status: false }
});

const updatedCart = await getCartWithItems(cartItem.fk_cart);
return mapCartResponse(updatedCart);
};

/**
*
* Actualiza la cantidad de un item del carrito de compras
* PUT /api/users/cart/items/:cartItemId
*/
export const updatedCartItemQuantityService = async (authenticatedUserId, cartItemId, newQuantity) => {
const resolvedUserId = parsePositiveInteger(authenticatedUserId, "authenticatedUserId");
const resolvedCartItemId = parsePositiveInteger(cartItemId, "cartItemId");
const resolvedQuantity = Number(newQuantity);

if (!Number.isInteger(resolvedQuantity) || resolvedQuantity < 1) throw new ValidationError("La cantidad nueva debe ser un entero mayor a 0");

const cartItem = await prisma.cartItems.findFirst({
where: {
id_cart_item: resolvedCartItemId,
status: true,
cart: {
fk_user: resolvedUserId,
cart_status: "ACTIVE",
status: true
}
}, select: {
id_cart_item: true,
fk_cart: true,
product: {
select: { quantity: true }
}
}
});

if (!cartItem) throw new NotFoundError("Item de carrito no encontrado.");

//validar que el producto tenga stock suficiente para la cantidad nueva
const stock = cartItem.product.quantity;
if(stock != null && Number.isFinite(Number(stock)) && resolvedQuantity > Number(stock))
throw new ValidationError("No hay stock suficiente para esta cantidad");

await prisma.cartItems.update({
where: { id_cart_item: resolvedCartItemId },
data: { quantity: resolvedQuantity }
});

const updatedCart = await getCartWithItems(cartItem.fk_cart);
return mapCartResponse(updatedCart);
}
Loading
Loading