feat: add bulk to cart add

This commit is contained in:
mahyargdz
2025-09-14 15:38:25 +03:30
parent be82059172
commit eb7305366c
3 changed files with 124 additions and 0 deletions
+52
View File
@@ -0,0 +1,52 @@
import { Expose, Type } from "class-transformer";
import { IsArray, IsNotEmpty, IsNumber, IsString, Min, ValidateNested } from "class-validator";
import { ApiProperty } from "../../../common/decorator/swggerDocs";
import { IsValidId } from "../../../common/decorator/validation.decorator";
import { ProductVariantModel } from "../../product/models/productVariant.model";
export class BulkCartItemDTO {
@Expose()
@IsNotEmpty()
@IsNumber()
@ApiProperty({ type: "number", description: "product id", example: 100000 })
productId: number;
@Expose()
@IsNotEmpty()
@IsString()
@IsValidId(ProductVariantModel)
@ApiProperty({ type: "string", description: "variant id of a product", example: "66c0d81ecc135bbc22fc44e3" })
variantId: string;
@Expose()
@IsNotEmpty()
@IsNumber()
@Min(1)
@ApiProperty({ type: "number", description: "quantity of a product", example: 2 })
quantity: number;
}
export class BulkAddToCartDTO {
@Expose()
@IsArray()
@ValidateNested({ each: true })
@Type(() => BulkCartItemDTO)
@ApiProperty({
type: "string",
description: "Array of items to add to cart",
example: [
{
productId: 100000,
variantId: "66c0d81ecc135bbc22fc44e3",
quantity: 2,
},
{
productId: 100001,
variantId: "66c0d81ecc135bbc22fc44e4",
quantity: 1,
},
],
})
items: BulkCartItemDTO[];
}
+12
View File
@@ -5,6 +5,7 @@ import { controller, httpGet, httpPost, request, requestBody } from "inversify-e
import { CartService } from "./cart.service";
import { HttpStatus } from "../../common";
import { AddToCartDTO } from "./DTO/addToCart.dto";
import { BulkAddToCartDTO } from "./DTO/bulkAddToCart.dto";
import { RemoveFromCartDTO } from "./DTO/removeFromCart.dto";
import { UpdateCartDTO } from "./DTO/updateCart.dto";
import { BaseController } from "../../common/base/controller";
@@ -41,6 +42,17 @@ class CartController extends BaseController {
return this.response(data, HttpStatus.Created);
}
@ApiOperation("add multiple products to user cart")
@ApiResponse("successful", HttpStatus.Created)
@ApiModel(BulkAddToCartDTO)
@ApiAuth()
@httpPost("/bulk-add", Guard.authUser(), ValidationMiddleware.validateInput(BulkAddToCartDTO))
public async bulkAddToCart(@requestBody() bulkAddToCartDto: BulkAddToCartDTO, @request() req: Request) {
const user = req.user as IUser;
const data = await this.cartService.bulkAddToCartS(bulkAddToCartDto, user._id.toString());
return this.response(data, HttpStatus.Created);
}
@ApiOperation("update the user cart")
@ApiResponse("successful", HttpStatus.Ok)
@ApiModel(UpdateCartDTO)
+60
View File
@@ -3,6 +3,7 @@ import { ClientSession, Types, startSession } from "mongoose";
import { CartRepository, CartShipItemRepo } from "./cart.repository";
import { AddToCartDTO } from "./DTO/addToCart.dto";
import { BulkAddToCartDTO } from "./DTO/bulkAddToCart.dto";
import { CartDTO } from "./DTO/cart.dto";
import { RemoveFromCartDTO } from "./DTO/removeFromCart.dto";
import { UpdateCartDTO } from "./DTO/updateCart.dto";
@@ -79,6 +80,65 @@ class CartService {
}
}
async bulkAddToCartS(bulkAddToCartDto: BulkAddToCartDTO, userId: string) {
const session = await startSession();
session.startTransaction();
try {
const { items } = bulkAddToCartDto;
// Get or create cart
let cart = await this.cartRepo.model.findOne({ user: userId });
if (!cart) {
cart = (await this.cartRepo.model.create([{ user: userId }], { session }))[0];
}
// Validate all products before making any changes
for (const item of items) {
const existingCartItem = cart.items.find(
(cartItem) => cartItem.product === item.productId && cartItem.variant.toString() === item.variantId,
);
const existingQuantity = existingCartItem ? existingCartItem.quantity : 0;
await this.validateProduct(item.productId, item.variantId, existingQuantity + item.quantity);
}
// Process each item
for (const item of items) {
const existingCartItem = cart.items.find(
(cartItem) => cartItem.product === item.productId && cartItem.variant.toString() === item.variantId,
);
if (existingCartItem) {
// Update quantity if item already exists in the cart
existingCartItem.quantity += item.quantity;
} else {
// Add new item to the cart
cart.items.push({
product: item.productId,
quantity: item.quantity,
variant: new Types.ObjectId(item.variantId),
});
}
}
await cart.save({ session });
// Commit the transaction
await session.commitTransaction();
session.endSession();
return {
message: CartMessage.ItemAdded,
cart: await this.getCartS(userId),
};
} catch (error) {
// Rollback any changes made in the transaction
await session.abortTransaction();
session.endSession();
throw error; // Re-throw the error to be handled by the calling errorHandler
}
}
async updateCartS(updateCartDto: UpdateCartDTO, userId: string) {
const { productId, variantId, quantity } = updateCartDto;