diff --git a/src/IOC/ioc.types.ts b/src/IOC/ioc.types.ts index 0ecd56d..c343176 100644 --- a/src/IOC/ioc.types.ts +++ b/src/IOC/ioc.types.ts @@ -71,9 +71,7 @@ export const IOCTYPES = { WarrantyRepository: Symbol.for("WarrantyRepository"), ShipmentRepository: Symbol.for("ShipmentRepository"), TokenRepository: Symbol.for("TokenRepository"), - ColorRepository: Symbol.for("ColorRepository"), - SizeRepository: Symbol.for("SizeRepository"), - MeterageRepository: Symbol.for("MeterageRepository"), + ThemeRepository: Symbol.for("ThemeRepository"), ThemeValueRepository: Symbol.for("ThemeValueRepository"), QuestionRepository: Symbol.for("QuestionRepository"), diff --git a/src/modules/admin/controllers/category.controller.ts b/src/modules/admin/controllers/category.controller.ts index e66a704..da04286 100644 --- a/src/modules/admin/controllers/category.controller.ts +++ b/src/modules/admin/controllers/category.controller.ts @@ -87,9 +87,7 @@ export class AdminCategoryController extends BaseController { @ApiResponse("successful", HttpStatus.Created) @ApiParam("id", "id of category", true) @ApiModel(CreateCategoryThemeDTO) - @ApiBody( - "the colors and sizes and meterage fields are optional and one of them should send and u can also send noColor_noSize too for no theme", - ) + @ApiBody("the ") @ApiAuth() @httpPost( "/:id/variants", @@ -177,6 +175,7 @@ export class AdminCategoryController extends BaseController { @ApiOperation("Update a theme ==> need to login as admin") @ApiResponse("theme updated successfully", HttpStatus.Ok) @ApiAuth() + @ApiModel(UpdateThemeDTO) @httpPut( "/theme", Guard.authAdmin(), @@ -242,15 +241,17 @@ export class AdminCategoryController extends BaseController { @ApiOperation("Update a theme value ==> need to login as admin") @ApiResponse("theme value updated successfully", HttpStatus.Ok) + @ApiParam("id", "id of the theme value", true) @ApiAuth() + @ApiModel(UpdateThemeValueDTO) @httpPut( - "/theme-value", + "/theme-value/:id", Guard.authAdmin(), Guard.checkAdminPermissions([PermissionEnum.ADMIN]), ValidationMiddleware.validateInput(UpdateThemeValueDTO), ) - public async updateThemeValue(@requestBody() updateDto: UpdateThemeValueDTO) { - const data = await this.themeService.updateThemeValue(updateDto); + public async updateThemeValue(@requestParam("id") id: string, @requestBody() updateDto: UpdateThemeValueDTO) { + const data = await this.themeService.updateThemeValue(id, updateDto); return this.response({ data }); } diff --git a/src/modules/cart/cart.repository.ts b/src/modules/cart/cart.repository.ts index 8da7391..a812e0f 100644 --- a/src/modules/cart/cart.repository.ts +++ b/src/modules/cart/cart.repository.ts @@ -20,7 +20,7 @@ class CartRepository extends BaseRepository { }) .populate({ path: "items.variant", - populate: ["color", "size", "meterage", "warranty", "shop"], + populate: [{ path: "warranty" }, { path: "shop" }, { path: "themeValue" }], }); } @@ -231,13 +231,9 @@ class CartRepository extends BaseRepository { { $lookup: { from: "productvariants", localField: "items.variant", foreignField: "_id", as: "variantDetails" } }, { $unwind: "$variantDetails" }, { $lookup: { from: "warranties", localField: "variantDetails.warranty", foreignField: "_id", as: "variantDetails.warranty" } }, - { $lookup: { from: "colors", localField: "variantDetails.color", foreignField: "_id", as: "variantDetails.color" } }, - { $lookup: { from: "sizes", localField: "variantDetails.size", foreignField: "_id", as: "variantDetails.size" } }, - { $lookup: { from: "meterages", localField: "variantDetails.meterage", foreignField: "_id", as: "variantDetails.meterage" } }, + { $lookup: { from: "themeValues", localField: "variantDetails.themeValue", foreignField: "_id", as: "variantDetails.themeValue" } }, { $unwind: { path: "$variantDetails.warranty", preserveNullAndEmptyArrays: true } }, - { $unwind: { path: "$variantDetails.color", preserveNullAndEmptyArrays: true } }, - { $unwind: { path: "$variantDetails.size", preserveNullAndEmptyArrays: true } }, - { $unwind: { path: "$variantDetails.meterage", preserveNullAndEmptyArrays: true } }, + { $unwind: { path: "$variantDetails.themeValue", preserveNullAndEmptyArrays: true } }, { $lookup: { from: "shops", localField: "variantDetails.shop", foreignField: "_id", as: "variantDetails.shop" } }, { $unwind: "$variantDetails.shop" }, { diff --git a/src/modules/category/DTO/CreateCategory.dto.ts b/src/modules/category/DTO/CreateCategory.dto.ts index 8d5b41d..e2e49c2 100644 --- a/src/modules/category/DTO/CreateCategory.dto.ts +++ b/src/modules/category/DTO/CreateCategory.dto.ts @@ -44,7 +44,7 @@ export class CreateCategoryDTO { @IsValidId(ThemeModel) @ApiProperty({ type: "string", - description: "the variation theme of a category ==> should be one of Color/Size/Meterage or noColor_noSize", + description: "the variation theme of a category ==> ", }) themeId: string; } diff --git a/src/modules/category/DTO/CreateThemeValue.dto.ts b/src/modules/category/DTO/CreateThemeValue.dto.ts index a6cfb2e..1bc3ff4 100644 --- a/src/modules/category/DTO/CreateThemeValue.dto.ts +++ b/src/modules/category/DTO/CreateThemeValue.dto.ts @@ -1,5 +1,5 @@ import { Expose } from "class-transformer"; -import { IsNotEmpty, IsString } from "class-validator"; +import { IsNotEmpty, IsOptional, IsString } from "class-validator"; import { ApiProperty } from "../../../common/decorator/swggerDocs"; import { IsValidId } from "../../../common/decorator/validation.decorator"; @@ -14,10 +14,10 @@ export class CreateThemeValueDTO { theme: string; @Expose() - @IsNotEmpty() + @IsOptional() @IsString() - @ApiProperty({ type: "string", description: "the name of theme value", example: "Red" }) - name: string; + @ApiProperty({ type: "string", description: "the name of theme value", example: "Red", required: false }) + name?: string; @Expose() @IsNotEmpty() diff --git a/src/modules/category/DTO/UpdateCategory.dto.ts b/src/modules/category/DTO/UpdateCategory.dto.ts index 6325609..7469701 100644 --- a/src/modules/category/DTO/UpdateCategory.dto.ts +++ b/src/modules/category/DTO/UpdateCategory.dto.ts @@ -57,8 +57,7 @@ export class UpdateCategoryDTO { @IsValidId(ThemeModel) @ApiProperty({ type: "string", - description: "the variation theme of a category ==> should be one of Color/Size/Meterage or noColor_noSize", - example: "Color", + description: "the variation theme of a category ==> ", }) themeId: string; } diff --git a/src/modules/category/DTO/UpdateThemeValue.dto.ts b/src/modules/category/DTO/UpdateThemeValue.dto.ts index de0a4ed..23d3787 100644 --- a/src/modules/category/DTO/UpdateThemeValue.dto.ts +++ b/src/modules/category/DTO/UpdateThemeValue.dto.ts @@ -1,19 +1,9 @@ import { Expose } from "class-transformer"; -import { IsNotEmpty, IsOptional, IsString, Length } from "class-validator"; +import { IsNotEmpty, IsOptional, IsString } from "class-validator"; import { ApiProperty } from "../../../common/decorator/swggerDocs"; -import { IsValidId } from "../../../common/decorator/validation.decorator"; -import { ThemeValueModel } from "../models/themeValue.model"; export class UpdateThemeValueDTO { - @Expose() - @IsNotEmpty() - @IsString() - @Length(24, 24) - @IsValidId(ThemeValueModel) - @ApiProperty({ type: "string", description: "theme value id", example: "66f3bcaee566db722a044c62" }) - themeValueId: string; - @Expose() @IsOptional() @IsNotEmpty() diff --git a/src/modules/category/DTO/category.dto.ts b/src/modules/category/DTO/category.dto.ts index 556c9da..d0fb53d 100644 --- a/src/modules/category/DTO/category.dto.ts +++ b/src/modules/category/DTO/category.dto.ts @@ -1,42 +1,17 @@ import { Expose, Transform, Type, plainToInstance } from "class-transformer"; +import { ThemeValueDTO } from "../../product/DTO/product.dto"; import { ICategory } from "../models/Abstraction/ICategory"; import { ICategoryAttribute } from "../models/Abstraction/ICategoryAttributes"; -export class Size_MeterageDTO { - @Expose() - _id: number; - @Expose() - value: string; -} -export class ColorDTO { - @Expose() - _id: number; - - @Expose() - name: string; - - @Expose() - hexColor: string; -} export class VariantDTO { @Expose() _id: string; @Expose() - @Type(() => ColorDTO) + @Type(() => ThemeValueDTO) @Transform(({ value }) => (value && value.length > 0 ? value : undefined) /*, { toClassOnly: true }*/) - colors: ColorDTO[]; - - @Expose() - @Type(() => Size_MeterageDTO) - @Transform(({ value }) => (value && value.length > 0 ? value : undefined) /*, { toClassOnly: true }*/) - sizes: Size_MeterageDTO[]; - - @Expose() - @Type(() => Size_MeterageDTO) - @Transform(({ value }) => (value && value.length > 0 ? value : undefined) /*, { toClassOnly: true }*/) - meterages: Size_MeterageDTO[]; + themeValues: ThemeValueDTO[]; } export class CategoryVariantDTO { diff --git a/src/modules/category/DTO/createCategoryTheme.dto.ts b/src/modules/category/DTO/createCategoryTheme.dto.ts index 23ffb53..d69070d 100644 --- a/src/modules/category/DTO/createCategoryTheme.dto.ts +++ b/src/modules/category/DTO/createCategoryTheme.dto.ts @@ -1,34 +1,11 @@ import { PartialType } from "@nestjs/mapped-types"; -import { Expose, Type } from "class-transformer"; -import { ArrayMinSize, IsHexColor, IsNotEmpty, IsOptional, ValidateNested } from "class-validator"; +import { Expose } from "class-transformer"; +import { IsOptional } from "class-validator"; import { ApiProperty } from "../../../common/decorator/swggerDocs"; import { IsValidId } from "../../../common/decorator/validation.decorator"; import { ThemeModel } from "../models/theme.model"; -export class CreateColorDTO { - @Expose() - @IsNotEmpty() - name: string; - - @Expose() - @IsNotEmpty() - @IsHexColor() - hexColor: string; -} - -export class CreateSizeDTO { - @Expose() - @IsNotEmpty() - value: string; -} - -export class CreateMeterageDTO { - @Expose() - @IsNotEmpty() - value: string; -} - export class CreateCategoryThemeDTO { @Expose() @IsOptional() @@ -38,46 +15,6 @@ export class CreateCategoryThemeDTO { description: "theme id", }) themeId?: string; - - @Expose() - @IsOptional() - @IsNotEmpty() - @ArrayMinSize(1) - @ValidateNested({ each: true }) - @Type(() => CreateColorDTO) - @ApiProperty({ - type: "Array", - required: true, - description: "the variation colors of a category theme", - example: [{ name: "مشکی", hexColor: "#000000" }], - }) - colors?: CreateColorDTO[]; - - @Expose() - @IsOptional() - @IsNotEmpty() - @ArrayMinSize(1) - @ValidateNested({ each: true }) - @Type(() => CreateSizeDTO) - @ApiProperty({ - type: "Array", - description: "the variation sizes of a category theme", - example: [{ value: "M" }, { value: "S" }, { value: "L" }], - }) - sizes?: CreateSizeDTO[]; - - @Expose() - @IsOptional() - @IsNotEmpty() - @ArrayMinSize(1) - @ValidateNested({ each: true }) - @Type(() => CreateSizeDTO) - @ApiProperty({ - type: "Array", - description: "the variation meterage of a category theme", - example: [{ value: "10" }, { value: "20" }, { value: "50" }], - }) - meterages?: CreateMeterageDTO[]; } export class UpdateCategoryVariantDTO extends PartialType(CreateCategoryThemeDTO) {} diff --git a/src/modules/category/category.repository.ts b/src/modules/category/category.repository.ts index f373c7f..a840903 100644 --- a/src/modules/category/category.repository.ts +++ b/src/modules/category/category.repository.ts @@ -149,7 +149,7 @@ class CategoryRepository extends BaseRepository { for (const category of categories) { if (!category?.theme || !category?.variants.length) continue; - const theme = `${category?.theme}s`.toLowerCase(); // e.g., 'colors', 'sizes', 'meterages' + const theme = `${category?.theme}s`.toLowerCase(); if (!themeVariantsMap.has(theme)) { themeVariantsMap.set(theme, new Set()); diff --git a/src/modules/category/category.service.ts b/src/modules/category/category.service.ts index 4f3b391..ea3138c 100644 --- a/src/modules/category/category.service.ts +++ b/src/modules/category/category.service.ts @@ -127,17 +127,20 @@ class CategoryService { createDto.title_en = slugify(createDto.title_en); const existTitle = await this.categoryRepository.findByTitle(createDto.title_en); - - const theme = await this.themeRepo.findById(createDto.themeId); - if (!theme) throw new BadRequestError(CommonMessage.NotFoundById); - if (existTitle) throw new BadRequestError(CategoryMessage.DuplicateTitle); + + let themeIdOrNull: any = null; + if (createDto.themeId) { + const themeDoc = await this.themeRepo.findById(createDto.themeId); + if (!themeDoc) throw new BadRequestError(CommonMessage.NotFoundById); + themeIdOrNull = themeDoc._id; + } //if parent exist first set parent leaf false if (createDto.parent) { await this.categoryRepository.model.findByIdAndUpdate(createDto.parent, { leaf: false }); } //we set the leaf to true - const category = await this.categoryRepository.model.create({ ...createDto, theme: theme._id }); + const category = await this.categoryRepository.model.create({ ...createDto, theme: themeIdOrNull }); return { message: CategoryMessage.Created, @@ -388,14 +391,12 @@ class CategoryService { // get category variants const categoryVariants = await this.categoryRepository.getCategoryVariants(categoryIds); - const colors = categoryVariants?.colors; - const sizes = categoryVariants?.sizes; - const meterages = categoryVariants?.meterages; + const themeValues = categoryVariants?.themeValues; // fetch products from the category and its children const { docs, count } = await this.productRepo.getProductsWithCategory(categoryIds, queries, userId); const products = docs.map((doc: IProduct) => ProductDTO.transformProduct(doc)); - const filters = { attributes: catAttributes?.attributes, priceRange, colors, sizes, meterages }; + const filters = { attributes: catAttributes?.attributes, priceRange, themeValues }; // fetch category breadcrumb const breadcrumb = await this.getCategoryBreadcrumb(category._id.toString()); diff --git a/src/modules/category/models/Abstraction/IThemeValue.ts b/src/modules/category/models/Abstraction/IThemeValue.ts index 88cd130..a358d31 100644 --- a/src/modules/category/models/Abstraction/IThemeValue.ts +++ b/src/modules/category/models/Abstraction/IThemeValue.ts @@ -3,6 +3,6 @@ import { Types } from "mongoose"; export interface IThemeValue { _id: Types.ObjectId; theme: Types.ObjectId; - name: string; - value: string; + name?: string; + value: string | number; } diff --git a/src/modules/category/models/themeValue.model.ts b/src/modules/category/models/themeValue.model.ts index 296e37b..1d7dfcd 100644 --- a/src/modules/category/models/themeValue.model.ts +++ b/src/modules/category/models/themeValue.model.ts @@ -5,7 +5,7 @@ import { IThemeValue } from "./Abstraction/IThemeValue"; const themeValueSchema = new Schema( { theme: { type: Schema.Types.ObjectId, ref: "Theme", required: true }, - name: { type: String, required: true }, + name: { type: String, required: false }, value: { type: Schema.Types.Mixed, required: true }, }, { timestamps: true, toJSON: { virtuals: true, versionKey: false }, id: false }, diff --git a/src/modules/category/theme.service.ts b/src/modules/category/theme.service.ts index ad193ab..6422724 100644 --- a/src/modules/category/theme.service.ts +++ b/src/modules/category/theme.service.ts @@ -109,10 +109,10 @@ class ThemeService { }; } - async updateThemeValue(updateDto: UpdateThemeValueDTO) { - if (!isValidObjectId(updateDto.themeValueId)) throw new BadRequestError(CommonMessage.NotValidId); + async updateThemeValue(id: string, updateDto: UpdateThemeValueDTO) { + if (!isValidObjectId(id)) throw new BadRequestError(CommonMessage.NotValidId); - const existingThemeValue = await this.themeValueRepository.findById(updateDto.themeValueId); + const existingThemeValue = await this.themeValueRepository.findById(id); if (!existingThemeValue) throw new BadRequestError(CommonMessage.NotFoundById); const updateData: Partial<{ name: string; value: string | number }> = {}; @@ -125,9 +125,7 @@ class ThemeService { updateData.value = updateDto.value; } - const updatedThemeValue = await this.themeValueRepository.model - .findByIdAndUpdate(updateDto.themeValueId, updateData, { new: true }) - .populate("theme"); + const updatedThemeValue = await this.themeValueRepository.model.findByIdAndUpdate(id, updateData, { new: true }).populate("theme"); return { message: CommonMessage.Updated, diff --git a/src/modules/order/DTO/userOrder.dto.ts b/src/modules/order/DTO/userOrder.dto.ts index 52ee893..005fe92 100644 --- a/src/modules/order/DTO/userOrder.dto.ts +++ b/src/modules/order/DTO/userOrder.dto.ts @@ -4,6 +4,7 @@ import { OrderItemDTO } from "./order.dto"; import { OrdersStatus } from "../../../common/enums/order.enum"; import { TimeService } from "../../../utils/time.service"; import { PaymentDTO } from "../../payment/DTO/payment.dto"; +import { ThemeValueDTO } from "../../product/DTO/product.dto"; import { UserDTO } from "../../user/DTO/user.dto"; import { IOrder } from "../models/Abstraction/IOrder"; @@ -54,6 +55,10 @@ export class UserOrderDTO { @Transform(({ value }) => TimeService.convertGregorianToPersian(new Date(value), true)) createdAt: string; + @Expose() + @Type(() => ThemeValueDTO) + themeValue: ThemeValueDTO; + public static transformOrder(data: IOrder): UserOrderDTO { const OrderDTO = plainToClass(UserOrderDTO, data, { excludeExtraneousValues: true, diff --git a/src/modules/order/order.repository.ts b/src/modules/order/order.repository.ts index c73d893..4a528ef 100644 --- a/src/modules/order/order.repository.ts +++ b/src/modules/order/order.repository.ts @@ -120,7 +120,7 @@ class OrderRepository extends BaseRepository { default: break; } - return this.model.aggregate([ + const orders = await this.model.aggregate([ { $match: matchQuery, }, @@ -207,6 +207,20 @@ class OrderRepository extends BaseRepository { { $unwind: "$shipmentItemVariant", }, + { + $lookup: { + from: "themevalues", + localField: "shipmentItemVariant.themeValue", + foreignField: "_id", + as: "shipmentItemVariant.themeValue", + }, + }, + { + $unwind: { + path: "$shipmentItemVariant.themeValue", + preserveNullAndEmptyArrays: true, + }, + }, { $group: { _id: "$orderItems._id", @@ -274,6 +288,7 @@ class OrderRepository extends BaseRepository { }, }, ]); + return orders; } async getUserOrderDetail(orderId: number, userId: string) { @@ -391,43 +406,15 @@ class OrderRepository extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "orderItems.shipmentItems.variant.color", + from: "themeValues", + localField: "orderItems.shipmentItems.variant.themeValue", foreignField: "_id", - as: "orderItems.shipmentItems.variant.color", + as: "orderItems.shipmentItems.variant.themeValue", }, }, { $unwind: { - path: "$orderItems.shipmentItems.variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "orderItems.shipmentItems.variant.size", - foreignField: "_id", - as: "orderItems.shipmentItems.variant.size", - }, - }, - { - $unwind: { - path: "$orderItems.shipmentItems.variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "orderItems.shipmentItems.variant.meterage", - foreignField: "_id", - as: "orderItems.shipmentItems.variant.meterage", - }, - }, - { - $unwind: { - path: "$orderItems.shipmentItems.variant.meterage", + path: "$orderItems.shipmentItems.variant.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -566,43 +553,15 @@ class OrderItemRepo extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "shipmentItems.variant.color", + from: "themeValues", + localField: "shipmentItems.variant.themeValue", foreignField: "_id", - as: "shipmentItems.variant.color", + as: "shipmentItems.variant.themeValue", }, }, { $unwind: { - path: "$shipmentItems.variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "shipmentItems.variant.size", - foreignField: "_id", - as: "shipmentItems.variant.size", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "shipmentItems.variant.meterage", - foreignField: "_id", - as: "shipmentItems.variant.meterage", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.meterage", + path: "$shipmentItems.variant.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -1521,43 +1480,15 @@ class OrderItemRepo extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "shipmentItems.variant.color", + from: "themeValues", + localField: "shipmentItems.variant.themeValue", foreignField: "_id", - as: "shipmentItems.variant.color", + as: "shipmentItems.variant.themeValue", }, }, { $unwind: { - path: "$shipmentItems.variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "shipmentItems.variant.size", - foreignField: "_id", - as: "shipmentItems.variant.size", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "shipmentItems.variant.meterage", - foreignField: "_id", - as: "shipmentItems.variant.meterage", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.meterage", + path: "$shipmentItems.variant.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -1730,43 +1661,15 @@ class OrderItemRepo extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "shipmentItems.variant.color", + from: "themeValues", + localField: "shipmentItems.variant.themeValue", foreignField: "_id", - as: "shipmentItems.variant.color", + as: "shipmentItems.variant.themeValue", }, }, { $unwind: { - path: "$shipmentItems.variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "shipmentItems.variant.size", - foreignField: "_id", - as: "shipmentItems.variant.size", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "shipmentItems.variant.meterage", - foreignField: "_id", - as: "shipmentItems.variant.meterage", - }, - }, - { - $unwind: { - path: "$shipmentItems.variant.meterage", + path: "$shipmentItems.variant.themeValue", preserveNullAndEmptyArrays: true, }, }, diff --git a/src/modules/product/DTO/product.dto.ts b/src/modules/product/DTO/product.dto.ts index 1526bb6..4645f23 100644 --- a/src/modules/product/DTO/product.dto.ts +++ b/src/modules/product/DTO/product.dto.ts @@ -4,7 +4,7 @@ import { IsString } from "class-validator"; import { ApiProperty } from "../../../common/decorator/swggerDocs"; import { ProductStatus } from "../../../common/enums/product.enum"; import { BrandDTO } from "../../brand/DTO/brand.dto"; -import { CategoryTreeDTO, ColorDTO, Size_MeterageDTO } from "../../category/DTO/category.dto"; +import { CategoryTreeDTO } from "../../category/DTO/category.dto"; import { ShipmentMethodDTO } from "../../shipment/DTO/shipment.dto"; import { ShopDTO } from "../../shop/DTO/shop.dto"; import { WarrantyDTO } from "../../warranty/DTO/warranty.dto"; @@ -83,6 +83,22 @@ class SaleFormatDTO { //################################# +export class ThemeValueDTO { + @Expose() + _id: string; + + @Expose() + theme: string; + + @Expose() + name?: string; + + @Expose() + value: string | number; +} + +//################################# + export class ProductDetailVariantDTO { @Expose() _id: string; @@ -126,16 +142,8 @@ export class ProductDetailVariantDTO { warranty: WarrantyDTO; @Expose() - @Type(() => ColorDTO) - color?: ColorDTO; - - @Expose() - @Type(() => Size_MeterageDTO) - size?: Size_MeterageDTO; - - @Expose() - @Type(() => Size_MeterageDTO) - meterage?: Size_MeterageDTO; + @Type(() => ThemeValueDTO) + themeValue?: ThemeValueDTO; } //################################# @@ -282,16 +290,8 @@ export class ProductVariantDTO { saleFormat: SaleFormatDTO; @Expose() - @Type(() => ColorDTO) - color?: ColorDTO; - - @Expose() - @Type(() => Size_MeterageDTO) - size?: Size_MeterageDTO; - - @Expose() - @Type(() => Size_MeterageDTO) - meterage?: Size_MeterageDTO; + @Type(() => ThemeValueDTO) + themeValue?: ThemeValueDTO; public static transformProduct(data: IProductVariant): ProductVariantDTO { const productVariantDTO = plainToInstance(ProductVariantDTO, data, { diff --git a/src/modules/product/Repository/incredibleOffers.ts b/src/modules/product/Repository/incredibleOffers.ts index 87d1016..f5f0611 100644 --- a/src/modules/product/Repository/incredibleOffers.ts +++ b/src/modules/product/Repository/incredibleOffers.ts @@ -117,43 +117,15 @@ export class IncredibleOffersRepo extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "product.default_variant.color", + from: "themeValues", + localField: "product.default_variant.themeValue", foreignField: "_id", - as: "product.default_variant.color", + as: "product.default_variant.themeValue", }, }, { $unwind: { - path: "$product.default_variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "product.default_variant.size", - foreignField: "_id", - as: "product.default_variant.size", - }, - }, - { - $unwind: { - path: "$product.default_variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "product.default_variant.meterage", - foreignField: "_id", - as: "product.default_variant.meterage", - }, - }, - { - $unwind: { - path: "$product.variant.meterage", + path: "$product.default_variant.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -251,43 +223,15 @@ export class IncredibleOffersRepo extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "variant.color", + from: "themeValues", + localField: "variant.themeValue", foreignField: "_id", - as: "variant.color", + as: "variant.themeValue", }, }, { $unwind: { - path: "$variant.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variant.size", - foreignField: "_id", - as: "variant.size", - }, - }, - { - $unwind: { - path: "$variant.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variant.meterage", - foreignField: "_id", - as: "variant.meterage", - }, - }, - { - $unwind: { - path: "$variant.meterage", + path: "$variant.themeValue", preserveNullAndEmptyArrays: true, }, }, diff --git a/src/modules/product/Repository/product.ts b/src/modules/product/Repository/product.ts index a5c6e23..5ffa3c1 100644 --- a/src/modules/product/Repository/product.ts +++ b/src/modules/product/Repository/product.ts @@ -1320,13 +1320,13 @@ export class ProductRepository extends BaseRepository { }, }, }, - { - $match: { - $expr: { - $or: [{ $gt: [{ $size: "$variants" }, 0] }, { $eq: ["$category.theme", "noColor_noSize"] }], - }, - }, - }, + // { + // $match: { + // $expr: { + // $or: [{ $gt: [{ $size: "$variants" }, 0] }, { $eq: ["$category.theme", "noColor_noSize"] }], + // }, + // }, + // }, { $unwind: { path: "$variants", @@ -1371,46 +1371,19 @@ export class ProductRepository extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "variants.color", + from: "themevalues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, + { $group: { _id: "$_id", @@ -1774,48 +1747,22 @@ export class ProductRepository extends BaseRepository { preserveNullAndEmptyArrays: true, }, }, + { $lookup: { - from: "colors", - localField: "variants.color", + from: "themeValues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, + { $group: { _id: "$_id", @@ -2064,43 +2011,15 @@ export class ProductRepository extends BaseRepository { }, { $lookup: { - from: "colors", - localField: "variants.color", + from: "themeValues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -2338,45 +2257,18 @@ export class ProductRepository extends BaseRepository { preserveNullAndEmptyArrays: true, }, }, + { $lookup: { - from: "colors", - localField: "variants.color", + from: "themeValues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -2513,45 +2405,18 @@ export class ProductRepository extends BaseRepository { preserveNullAndEmptyArrays: true, }, }, + { $lookup: { - from: "colors", - localField: "variants.color", + from: "themeValues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, @@ -2674,45 +2539,18 @@ export class ProductRepository extends BaseRepository { preserveNullAndEmptyArrays: true, }, }, + { $lookup: { - from: "colors", - localField: "variants.color", + from: "themeValues", + localField: "variants.themeValue", foreignField: "_id", - as: "variants.color", + as: "variants.themeValue", }, }, { $unwind: { - path: "$variants.color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "sizes", - localField: "variants.size", - foreignField: "_id", - as: "variants.size", - }, - }, - { - $unwind: { - path: "$variants.size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $lookup: { - from: "meterages", - localField: "variants.meterage", - foreignField: "_id", - as: "variants.meterage", - }, - }, - { - $unwind: { - path: "$variants.meterage", + path: "$variants.themeValue", preserveNullAndEmptyArrays: true, }, }, diff --git a/src/modules/product/Repository/productVarinat.ts b/src/modules/product/Repository/productVarinat.ts index 2dc24b7..27a3969 100644 --- a/src/modules/product/Repository/productVarinat.ts +++ b/src/modules/product/Repository/productVarinat.ts @@ -86,28 +86,13 @@ export class ProductVariantRepository extends BaseRepository { { $unwind: "$category", }, + { $lookup: { - from: "colors", - localField: "color", + from: "themeValues", + localField: "themeValue", foreignField: "_id", - as: "color", - }, - }, - { - $lookup: { - from: "sizes", - localField: "size", - foreignField: "_id", - as: "size", - }, - }, - { - $lookup: { - from: "meterages", - localField: "meterage", - foreignField: "_id", - as: "meterage", + as: "themeValue", }, }, { @@ -120,22 +105,11 @@ export class ProductVariantRepository extends BaseRepository { }, { $unwind: { - path: "$color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$meterage", + path: "$themeValue", preserveNullAndEmptyArrays: true, }, }, + { $addFields: { product_id: "$product._id", @@ -259,28 +233,13 @@ export class ProductVariantRepository extends BaseRepository { { $unwind: "$category", }, + { $lookup: { - from: "colors", - localField: "color", + from: "themeValues", + localField: "themeValue", foreignField: "_id", - as: "color", - }, - }, - { - $lookup: { - from: "sizes", - localField: "size", - foreignField: "_id", - as: "size", - }, - }, - { - $lookup: { - from: "meterages", - localField: "meterage", - foreignField: "_id", - as: "meterage", + as: "themeValue", }, }, { @@ -293,22 +252,11 @@ export class ProductVariantRepository extends BaseRepository { }, { $unwind: { - path: "$color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$meterage", + path: "$themeValue", preserveNullAndEmptyArrays: true, }, }, + { $addFields: { product_id: "$product._id", @@ -400,28 +348,13 @@ export class ProductVariantRepository extends BaseRepository { { $unwind: "$category", }, + { $lookup: { - from: "colors", - localField: "color", + from: "themeValues", + localField: "themeValue", foreignField: "_id", - as: "color", - }, - }, - { - $lookup: { - from: "sizes", - localField: "size", - foreignField: "_id", - as: "size", - }, - }, - { - $lookup: { - from: "meterages", - localField: "meterage", - foreignField: "_id", - as: "meterage", + as: "themeValue", }, }, { @@ -434,22 +367,11 @@ export class ProductVariantRepository extends BaseRepository { }, { $unwind: { - path: "$color", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$size", - preserveNullAndEmptyArrays: true, - }, - }, - { - $unwind: { - path: "$meterage", + path: "$themeValue", preserveNullAndEmptyArrays: true, }, }, + { $addFields: { product_id: "$product._id", diff --git a/src/modules/product/providers/product.service.ts b/src/modules/product/providers/product.service.ts index 41b6433..5089dc2 100644 --- a/src/modules/product/providers/product.service.ts +++ b/src/modules/product/providers/product.service.ts @@ -564,14 +564,14 @@ class ProductService { // Check if a variant with the same themeValue already exists // const query: FilterQuery = { product: product._id }; - // if (addVariantDto.themeValueId) { - // const existingVariant = await this.productVariantRepo.model.findOne({ - // product: product._id, - // themeValue: addVariantDto.themeValueId, - // }); + if (addVariantDto.themeValueId) { + const existingVariant = await this.productVariantRepo.model.findOne({ + product: product._id, + themeValue: addVariantDto.themeValueId, + }); - // if (existingVariant) throw new BadRequestError(ProductMessage.VariantAlreadyExists); - // } + if (existingVariant) throw new BadRequestError(ProductMessage.VariantAlreadyExists); + } const productVariant = await this.createProductVariant(addVariantDto, product._id, shop._id.toString(), session); @@ -961,9 +961,7 @@ class ProductService { async getProductDetails(productId: number) { await this.validateProduct(productId); const docs = await this.productRepo.getProductDetails(productId); - if ((!docs?.[0]?.variants || docs?.[0]?.variants.length === 0) && docs?.[0]?.category.theme !== "noColor_noSize") { - throw new BadRequestError(CommonMessage.NotEnoughVariant); - } + const product = ProductDTO.transformProduct(docs[0]); const stats = await this.commentRepo.getProductStats(productId); const categoryPath = await this.categoryRepo.getCategoryPath(product.category._id.toString());