E-commerce Project - Part 2
Implement cart, orders and payments.
Cart Service
typescript
// src/modules/cart/cart.service.tsexport class CartService { async getCart(userId: string) { const cart = await prisma.cart.findUnique({ where: { userId }, include: { items: { include: { product: true } } }, }); const subtotal = cart.items.reduce((acc, item) => acc + Number(item.product.price) * item.quantity, 0); return { ...cart, subtotal }; } async addItem(userId: string, productId: string, quantity: number) { const product = await prisma.product.findUnique({ where: { id: productId } }); if (!product) throw new AppError('Product not found', 404); if (product.stock < quantity) throw new AppError('Insufficient stock', 400); const cart = await prisma.cart.findUnique({ where: { userId } }); const existingItem = await prisma.cartItem.findUnique({ where: { cartId_productId: { cartId: cart.id, productId } }, }); if (existingItem) { await prisma.cartItem.update({ where: { id: existingItem.id }, data: { quantity: existingItem.quantity + quantity }, }); } else { await prisma.cartItem.create({ data: { cartId: cart.id, productId, quantity }, }); } return this.getCart(userId); } async removeItem(userId: string, productId: string) { const cart = await prisma.cart.findUnique({ where: { userId } }); await prisma.cartItem.delete({ where: { cartId_productId: { cartId: cart.id, productId } }, }); return this.getCart(userId); }}Order Service
typescript
// src/modules/orders/order.service.tsexport class OrderService { async create(userId: string, data: CreateOrderDTO) { const cart = await cartService.getCart(userId); if (!cart.items.length) throw new AppError('Cart is empty', 400); // Validate stock for (const item of cart.items) { if (item.product.stock < item.quantity) { throw new AppError(`Insufficient stock for ${item.product.name}`, 400); } } // Create order with transaction const order = await prisma.$transaction(async (tx) => { const newOrder = await tx.order.create({ data: { userId, total: cart.subtotal, items: { create: cart.items.map(item => ({ productId: item.productId, name: item.product.name, price: item.product.price, quantity: item.quantity, })), }, }, }); // Update stock for (const item of cart.items) { await tx.product.update({ where: { id: item.productId }, data: { stock: { decrement: item.quantity } }, }); } // Clear cart await tx.cartItem.deleteMany({ where: { cartId: cart.id } }); return newOrder; }); await mailService.sendOrderConfirmation(user, order); return order; } async findByUser(userId: string) { return prisma.order.findMany({ where: { userId }, include: { items: true }, orderBy: { createdAt: 'desc' }, }); }}Cart Routes
typescript
router.use(authenticate);router.get('/', controller.show);router.post('/items', controller.addItem);router.delete('/items/:productId', controller.removeItem);Summary
- ✅ Complete cart service
- ✅ Order creation with transaction
- ✅ Stock validation
- ✅ Email notification
Next lesson: E-commerce Project - Part 3! 🚀