You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

180 lines
6.0 KiB

import { Injectable, HttpException, HttpStatus, Inject, forwardRef } from "@nestjs/common";
import { InjectModel } from "@nestjs/sequelize";
import { Cart } from "./entities/cart.entity";
import { Product } from "src/products/entities/product.entity";
import { WalletService } from "src/wallet/wallet.service";
import { InvoiceService } from "src/invoice/invoice.service";
import { Invoice } from "src/invoice/entities/invoice.entity";
@Injectable()
export class CartService {
constructor(
@InjectModel(Cart) private readonly cartModel: typeof Cart,
@InjectModel(Invoice) private readonly invoiceModel: typeof Invoice,
@InjectModel(Product) private readonly productModel: typeof Product,
private readonly walletService: WalletService,
@Inject(forwardRef(() => InvoiceService))
private invoiceService: InvoiceService,
) {}
//create a cart and add item to cart
async createAndAddItemToCart(addToCartDto: { userId: number; productId: number; quantity: number }): Promise<{ message: string; cartItem: Cart }> {
const { userId, productId, quantity } = addToCartDto;
if (!userId || !productId || !quantity || isNaN(Number(quantity)) || Number(quantity) <= 0) {
throw new HttpException("Invalid parameters: userId, productId, and a positive quantity are required.", HttpStatus.BAD_REQUEST);
}
const product = await this.productModel.findByPk(productId);
if (!product) {
throw new HttpException("Product not found!", HttpStatus.NOT_FOUND);
}
let invoice = await this.invoiceModel.findOne({ where: { userId, status: "pending" } });
if (!invoice) {
invoice = await this.invoiceService.createInvoiceFromCart(userId);
}
const invoiceId = invoice.id;
let cart = await this.cartModel.findOne({ where: { userId, productId, status: "open" } });
console.log(cart);
if (!cart) {
cart = await this.cartModel.create({
userId,
productId,
invoiceId,
quantity,
productPrice: product.price,
status: "open",
});
await cart.save();
} else {
cart.quantity += Number(quantity);
await cart.save();
}
await this.invoiceService.updateTotalPayment(userId);
return {
message: cart.id ? "Product quantity updated in cart successfully!" : "Product added to cart successfully!",
cartItem: cart,
};
}
// Get user's cart
async getUserCart(userId: number): Promise<{ cartItems: Cart[]; totalPrice: number }> {
if (!userId) {
throw new HttpException("User ID is required.", HttpStatus.BAD_REQUEST);
}
const cartItems = await this.cartModel.findAll({
where: { userId },
include: [
{
model: Product,
attributes: [],
},
],
});
if (!cartItems || cartItems.length === 0) {
throw new HttpException("No cart items found for the specified user.", HttpStatus.NOT_FOUND);
}
const totalPrice = cartItems.reduce((sum, item) => sum + (Number(item.productPrice * item.quantity) || 0), 0);
return { cartItems, totalPrice };
}
// Update cart item quantity
async updateCart(userId: number, productId: number, quantity: number): Promise<Cart> {
const cartItem = await this.cartModel.findOne({ where: { userId, productId } });
if (!cartItem) {
throw new HttpException("Product not found in the cart.", HttpStatus.NOT_FOUND);
}
cartItem.quantity = quantity;
await cartItem.save();
await this.invoiceService.updateTotalPayment(userId);
return cartItem;
}
// Remove an item from cart
async removeFromCart(userId: number, productId: number): Promise<{ message: string }> {
const cartItem = await this.cartModel.findOne({ where: { userId, productId } });
if (!cartItem) {
throw new HttpException("Product not found in the cart.", HttpStatus.NOT_FOUND);
}
await cartItem.destroy();
await this.invoiceService.updateTotalPayment(userId);
return { message: "Item deleted from your cart successfully." };
}
//delete whole cart
async clearCart(userId: number): Promise<void> {
await this.cartModel.destroy({ where: { userId } });
}
//order(clearCart disable)
async processOrder(userId: number, totalAmount: number): Promise<{ message: string; invoice: Invoice }> {
try {
const carts = await this.cartModel.findAll({ where: { userId, status: "open" } });
if (!carts || carts.length === 0) {
throw new HttpException("No open carts found for this user.", HttpStatus.NOT_FOUND);
}
let invoice: Invoice | null = null;
for (const cart of carts) {
const invoiceId = cart.invoiceId;
invoice = await this.invoiceModel.findOne({ where: { id: invoiceId, userId } });
if (invoice && invoice.status === "paid") {
return {
message: `Order for cart ID ${cart.id} has already been processed.`,
invoice,
};
}
}
await this.walletService.processPayment(userId, totalAmount);
for (const cartItem of carts) {
const { productId, quantity } = cartItem;
const product = await this.productModel.findOne({ where: { id: productId } });
if (!product) {
throw new HttpException(`Product with ID ${productId} not found.`, HttpStatus.NOT_FOUND);
}
if (product.quantity < quantity) {
throw new HttpException(`Insufficient stock for product ID ${productId}.`, HttpStatus.BAD_REQUEST);
}
product.quantity -= quantity;
await product.save();
}
for (const cart of carts) {
cart.status = "closed";
await cart.save();
}
if (invoice) {
invoice.status = "paid";
await invoice.save();
}
return { message: "Order processed successfully!", invoice };
} catch (error) {
console.error(error);
if (error instanceof HttpException) {
throw error;
} else {
throw new HttpException(`An error occurred while processing the order: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
}
}