@@ -39,17 +39,16 @@ import {
|
|||||||
AttributeValueRepo,
|
AttributeValueRepo,
|
||||||
CategoryAttributeRepo,
|
CategoryAttributeRepo,
|
||||||
CategoryRepository,
|
CategoryRepository,
|
||||||
ColorRepository,
|
ThemeRepository,
|
||||||
MeterageRepository,
|
ThemeValueRepository,
|
||||||
SizeRepository,
|
|
||||||
createAttributeValueRepo,
|
createAttributeValueRepo,
|
||||||
createCategoryAttributeRepo,
|
createCategoryAttributeRepo,
|
||||||
createCategoryRepo,
|
createCategoryRepo,
|
||||||
createColorRepo,
|
createThemeRepo,
|
||||||
createMeterageRepo,
|
createThemeValueRepo,
|
||||||
createSizeRepo,
|
|
||||||
} from "../modules/category/category.repository";
|
} from "../modules/category/category.repository";
|
||||||
import { CategoryService } from "../modules/category/category.service";
|
import { CategoryService } from "../modules/category/category.service";
|
||||||
|
import { ThemeService } from "../modules/category/theme.service";
|
||||||
import { ChatGateway } from "../modules/chat/chat.gateway";
|
import { ChatGateway } from "../modules/chat/chat.gateway";
|
||||||
import { ChatService } from "../modules/chat/chat.service";
|
import { ChatService } from "../modules/chat/chat.service";
|
||||||
import { ChatRepo, createChatRepo } from "../modules/chat/repository/chat.repository";
|
import { ChatRepo, createChatRepo } from "../modules/chat/repository/chat.repository";
|
||||||
@@ -158,6 +157,7 @@ const containerModules = new AsyncContainerModule(async (bind) => {
|
|||||||
bind<AsanPardakhtGateway>(IOCTYPES.AsanPardakhtGateway).to(AsanPardakhtGateway).inSingletonScope();
|
bind<AsanPardakhtGateway>(IOCTYPES.AsanPardakhtGateway).to(AsanPardakhtGateway).inSingletonScope();
|
||||||
// #region services
|
// #region services
|
||||||
bind<CategoryService>(IOCTYPES.CategoryService).to(CategoryService).inSingletonScope();
|
bind<CategoryService>(IOCTYPES.CategoryService).to(CategoryService).inSingletonScope();
|
||||||
|
bind<ThemeService>(IOCTYPES.ThemeService).to(ThemeService).inSingletonScope();
|
||||||
bind<AuthService>(IOCTYPES.AuthService).to(AuthService).inSingletonScope();
|
bind<AuthService>(IOCTYPES.AuthService).to(AuthService).inSingletonScope();
|
||||||
bind<ChatGateway>(IOCTYPES.ChatGateway).to(ChatGateway).inSingletonScope();
|
bind<ChatGateway>(IOCTYPES.ChatGateway).to(ChatGateway).inSingletonScope();
|
||||||
bind<ChatService>(IOCTYPES.ChatService).to(ChatService).inSingletonScope();
|
bind<ChatService>(IOCTYPES.ChatService).to(ChatService).inSingletonScope();
|
||||||
@@ -217,9 +217,8 @@ const containerModules = new AsyncContainerModule(async (bind) => {
|
|||||||
bind<ProductRepository>(IOCTYPES.ProductRepository).toDynamicValue(createProductRepo).inSingletonScope();
|
bind<ProductRepository>(IOCTYPES.ProductRepository).toDynamicValue(createProductRepo).inSingletonScope();
|
||||||
bind<ShipmentRepository>(IOCTYPES.ShipmentRepository).toDynamicValue(createShipmentRepository).inSingletonScope();
|
bind<ShipmentRepository>(IOCTYPES.ShipmentRepository).toDynamicValue(createShipmentRepository).inSingletonScope();
|
||||||
bind<ProductVariantRepository>(IOCTYPES.ProductVariantRepository).toDynamicValue(createProductVariantRepo).inSingletonScope();
|
bind<ProductVariantRepository>(IOCTYPES.ProductVariantRepository).toDynamicValue(createProductVariantRepo).inSingletonScope();
|
||||||
bind<ColorRepository>(IOCTYPES.ColorRepository).toDynamicValue(createColorRepo).inSingletonScope();
|
bind<ThemeRepository>(IOCTYPES.ThemeRepository).toDynamicValue(createThemeRepo).inSingletonScope();
|
||||||
bind<SizeRepository>(IOCTYPES.SizeRepository).toDynamicValue(createSizeRepo).inSingletonScope();
|
bind<ThemeValueRepository>(IOCTYPES.ThemeValueRepository).toDynamicValue(createThemeValueRepo).inSingletonScope();
|
||||||
bind<MeterageRepository>(IOCTYPES.MeterageRepository).toDynamicValue(createMeterageRepo).inSingletonScope();
|
|
||||||
bind<QuestionRepository>(IOCTYPES.QuestionRepository).toDynamicValue(createQuestionRepo).inSingletonScope();
|
bind<QuestionRepository>(IOCTYPES.QuestionRepository).toDynamicValue(createQuestionRepo).inSingletonScope();
|
||||||
bind<CommentRepository>(IOCTYPES.CommentRepository).toDynamicValue(createCommentRepo).inSingletonScope();
|
bind<CommentRepository>(IOCTYPES.CommentRepository).toDynamicValue(createCommentRepo).inSingletonScope();
|
||||||
bind<CartRepository>(IOCTYPES.CartRepository).toDynamicValue(createCartRepo).inSingletonScope();
|
bind<CartRepository>(IOCTYPES.CartRepository).toDynamicValue(createCartRepo).inSingletonScope();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const IOCTYPES = {
|
|||||||
PassportAuth: Symbol.for("PassportAuth"),
|
PassportAuth: Symbol.for("PassportAuth"),
|
||||||
AuthService: Symbol.for("AuthService"),
|
AuthService: Symbol.for("AuthService"),
|
||||||
CategoryService: Symbol.for("CategoryService"),
|
CategoryService: Symbol.for("CategoryService"),
|
||||||
|
ThemeService: Symbol.for("ThemeService"),
|
||||||
UserService: Symbol.for("UserService"),
|
UserService: Symbol.for("UserService"),
|
||||||
AdminService: Symbol.for("AdminService"),
|
AdminService: Symbol.for("AdminService"),
|
||||||
SellerService: Symbol.for("SellerService"),
|
SellerService: Symbol.for("SellerService"),
|
||||||
@@ -68,6 +69,8 @@ export const IOCTYPES = {
|
|||||||
ColorRepository: Symbol.for("ColorRepository"),
|
ColorRepository: Symbol.for("ColorRepository"),
|
||||||
SizeRepository: Symbol.for("SizeRepository"),
|
SizeRepository: Symbol.for("SizeRepository"),
|
||||||
MeterageRepository: Symbol.for("MeterageRepository"),
|
MeterageRepository: Symbol.for("MeterageRepository"),
|
||||||
|
ThemeRepository: Symbol.for("ThemeRepository"),
|
||||||
|
ThemeValueRepository: Symbol.for("ThemeValueRepository"),
|
||||||
QuestionRepository: Symbol.for("QuestionRepository"),
|
QuestionRepository: Symbol.for("QuestionRepository"),
|
||||||
CommentRepository: Symbol.for("CommentRepository"),
|
CommentRepository: Symbol.for("CommentRepository"),
|
||||||
ProductRequestRepo: Symbol.for("ProductRequestRepo"),
|
ProductRequestRepo: Symbol.for("ProductRequestRepo"),
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
export enum CategoryThemeEnum {
|
|
||||||
Sized = "Size",
|
|
||||||
Colored = "Color",
|
|
||||||
Meterage = "Meterage",
|
|
||||||
No_color_No_sized = "noColor_noSize",
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum categoryAttType {
|
export enum categoryAttType {
|
||||||
Text = "text",
|
Text = "text",
|
||||||
Select = "select",
|
Select = "select",
|
||||||
|
|||||||
@@ -1,53 +1,57 @@
|
|||||||
import { Logger } from "../../core/logging/logger";
|
import { Logger } from "../../core/logging/logger";
|
||||||
import { ColorModel } from "../../modules/category/models/color.model";
|
import { InputTypeEnum, ThemeModel } from "../../modules/category/models/theme.model";
|
||||||
import { MeterageModel } from "../../modules/category/models/meterage.model";
|
import { ThemeValueModel } from "../../modules/category/models/themeValue.model";
|
||||||
import { SizeModel } from "../../modules/category/models/size.model";
|
|
||||||
|
|
||||||
const colors = [
|
const colors = [
|
||||||
{ name: "قرمز", hexColor: "#FF0000" },
|
{ name: "قرمز", value: "#FF0000" },
|
||||||
{ name: "سبز", hexColor: "#00FF00" },
|
{ name: "سبز", value: "#00FF00" },
|
||||||
{ name: "آبی", hexColor: "#0000FF" },
|
{ name: "آبی", value: "#0000FF" },
|
||||||
{ name: "مشکی", hexColor: "#000000" },
|
{ name: "مشکی", value: "#000000" },
|
||||||
{ name: "سفید", hexColor: "#FFFFFF" },
|
{ name: "سفید", value: "#FFFFFF" },
|
||||||
{ name: "زرد", hexColor: "#FFFF00" },
|
{ name: "زرد", value: "#FFFF00" },
|
||||||
{ name: "بنفش", hexColor: "#800080" },
|
{ name: "بنفش", value: "#800080" },
|
||||||
{ name: "نارنجی", hexColor: "#FFA500" },
|
{ name: "نارنجی", value: "#FFA500" },
|
||||||
{ name: "صورتی", hexColor: "#FFC0CB" },
|
{ name: "صورتی", value: "#FFC0CB" },
|
||||||
{ name: "خاکستری", hexColor: "#808080" },
|
{ name: "خاکستری", value: "#808080" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const sizes = [
|
const sizes = [
|
||||||
{ value: "XS" },
|
{ name: "XS", value: "XS" },
|
||||||
{ value: "S" },
|
{ name: "S", value: "S" },
|
||||||
{ value: "M" },
|
{ name: "M", value: "M" },
|
||||||
{ value: "L" },
|
{ name: "L", value: "L" },
|
||||||
{ value: "XL" },
|
{ name: "XL", value: "XL" },
|
||||||
{ value: "XXL" },
|
{ name: "XXL", value: "XXL" },
|
||||||
{ value: "3XL" },
|
{ name: "3XL", value: "3XL" },
|
||||||
{ value: "4XL" },
|
{ name: "4XL", value: "4XL" },
|
||||||
{ value: "5XL" },
|
{ name: "5XL", value: "5XL" },
|
||||||
{ value: "6XL" },
|
{ name: "6XL", value: "6XL" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const meterages = [
|
const meterages = [
|
||||||
{ value: "1" },
|
{ name: "1", value: "1" },
|
||||||
{ value: "2" },
|
{ name: "2", value: "2" },
|
||||||
{ value: "3" },
|
{ name: "3", value: "3" },
|
||||||
{ value: "4" },
|
{ name: "4", value: "4" },
|
||||||
{ value: "5" },
|
{ name: "5", value: "5" },
|
||||||
{ value: "10" },
|
{ name: "10", value: "10" },
|
||||||
{ value: "15" },
|
{ name: "15", value: "15" },
|
||||||
{ value: "20" },
|
{ name: "20", value: "20" },
|
||||||
{ value: "25" },
|
{ name: "25", value: "25" },
|
||||||
{ value: "30" },
|
{ name: "30", value: "30" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const seedColors = async () => {
|
const seedColors = async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Seeding colors...");
|
console.log("Seeding colors...");
|
||||||
await ColorModel.deleteMany({});
|
let colorTheme = await ThemeModel.findOne({ title: "رنگ" });
|
||||||
|
if (!colorTheme) {
|
||||||
|
colorTheme = await ThemeModel.create({ title: "رنگ", inputType: InputTypeEnum.Color });
|
||||||
|
}
|
||||||
|
|
||||||
|
await ThemeValueModel.deleteMany({ theme: colorTheme._id });
|
||||||
for (const color of colors) {
|
for (const color of colors) {
|
||||||
await ColorModel.create(color);
|
await ThemeValueModel.create({ theme: colorTheme._id, name: color.name, value: color.value });
|
||||||
}
|
}
|
||||||
console.log("Colors seeded successfully");
|
console.log("Colors seeded successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -58,10 +62,14 @@ const seedColors = async () => {
|
|||||||
const seedSizes = async () => {
|
const seedSizes = async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Seeding sizes...");
|
console.log("Seeding sizes...");
|
||||||
await SizeModel.deleteMany({});
|
let sizeTheme = await ThemeModel.findOne({ title: "سایز" });
|
||||||
|
if (!sizeTheme) {
|
||||||
|
sizeTheme = await ThemeModel.create({ title: "سایز", inputType: InputTypeEnum.Text });
|
||||||
|
}
|
||||||
|
|
||||||
|
await ThemeValueModel.deleteMany({ theme: sizeTheme._id });
|
||||||
for (const size of sizes) {
|
for (const size of sizes) {
|
||||||
await SizeModel.create(size);
|
await ThemeValueModel.create({ theme: sizeTheme._id, name: size.name, value: size.value });
|
||||||
}
|
}
|
||||||
console.log("Sizes seeded successfully");
|
console.log("Sizes seeded successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -72,9 +80,14 @@ const seedSizes = async () => {
|
|||||||
const seedMeterages = async () => {
|
const seedMeterages = async () => {
|
||||||
try {
|
try {
|
||||||
console.log("Seeding meterages...");
|
console.log("Seeding meterages...");
|
||||||
await MeterageModel.deleteMany({});
|
let meterageTheme = await ThemeModel.findOne({ title: "متراژ" });
|
||||||
|
if (!meterageTheme) {
|
||||||
|
meterageTheme = await ThemeModel.create({ title: "متراژ", inputType: InputTypeEnum.Number });
|
||||||
|
}
|
||||||
|
|
||||||
|
await ThemeValueModel.deleteMany({ theme: meterageTheme._id });
|
||||||
for (const meterage of meterages) {
|
for (const meterage of meterages) {
|
||||||
await MeterageModel.create(meterage);
|
await ThemeValueModel.create({ theme: meterageTheme._id, name: meterage.name, value: meterage.value });
|
||||||
}
|
}
|
||||||
console.log("Meterages seeded successfully");
|
console.log("Meterages seeded successfully");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -2,14 +2,12 @@ import { faker } from "@faker-js/faker";
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
faker.locale = "fa";
|
faker.locale = "fa";
|
||||||
import { CategoryThemeEnum } from "../../common/enums/category.enum";
|
|
||||||
import { Logger } from "../../core/logging/logger";
|
import { Logger } from "../../core/logging/logger";
|
||||||
import { AttributeValueModel } from "../../modules/category/models/attributeValue.model";
|
import { AttributeValueModel } from "../../modules/category/models/attributeValue.model";
|
||||||
import { CategoryModel } from "../../modules/category/models/category.model";
|
import { CategoryModel } from "../../modules/category/models/category.model";
|
||||||
import { CategoryAttributeModel } from "../../modules/category/models/CategoryAttribute.model";
|
import { CategoryAttributeModel } from "../../modules/category/models/CategoryAttribute.model";
|
||||||
import { ColorModel } from "../../modules/category/models/color.model";
|
import { ThemeModel } from "../../modules/category/models/theme.model";
|
||||||
import { MeterageModel } from "../../modules/category/models/meterage.model";
|
import { ThemeValueModel } from "../../modules/category/models/themeValue.model";
|
||||||
import { SizeModel } from "../../modules/category/models/size.model";
|
|
||||||
|
|
||||||
interface ICategorySeed {
|
interface ICategorySeed {
|
||||||
title_fa: string;
|
title_fa: string;
|
||||||
@@ -18,7 +16,7 @@ interface ICategorySeed {
|
|||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
description: string;
|
description: string;
|
||||||
leaf: boolean;
|
leaf: boolean;
|
||||||
theme?: CategoryThemeEnum;
|
themeType?: "color" | "size" | "meterage" | null;
|
||||||
parent?: Types.ObjectId;
|
parent?: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +121,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
title_en: "mobile-phones",
|
title_en: "mobile-phones",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title_fa: "تبلت",
|
title_fa: "تبلت",
|
||||||
@@ -131,7 +129,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع تبلت ها",
|
description: "انواع تبلت ها",
|
||||||
title_en: "tablets",
|
title_en: "tablets",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -140,7 +138,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع ساعت هوشمند",
|
description: "انواع ساعت هوشمند",
|
||||||
title_en: "smart-watch",
|
title_en: "smart-watch",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -149,7 +147,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع پاور بانک",
|
description: "انواع پاور بانک",
|
||||||
title_en: "power-banks",
|
title_en: "power-banks",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -160,7 +158,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع خودکار و خودنویس",
|
description: "انواع خودکار و خودنویس",
|
||||||
title_en: "pens",
|
title_en: "pens",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -169,7 +167,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع دفتر و کاغذ",
|
description: "انواع دفتر و کاغذ",
|
||||||
title_en: "paper-notebooks",
|
title_en: "paper-notebooks",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -180,7 +178,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لامپ ها",
|
description: "انواع لامپ ها",
|
||||||
title_en: "bulbs",
|
title_en: "bulbs",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -189,7 +187,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع کابل و سیم",
|
description: "انواع کابل و سیم",
|
||||||
title_en: "cables-wires",
|
title_en: "cables-wires",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -200,7 +198,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع آچار و پیچ گوشتی",
|
description: "انواع آچار و پیچ گوشتی",
|
||||||
title_en: "wrenches-screwdrivers",
|
title_en: "wrenches-screwdrivers",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -209,7 +207,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع دریل ها",
|
description: "انواع دریل ها",
|
||||||
title_en: "drills",
|
title_en: "drills",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -220,7 +218,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع تلویزیون",
|
description: "انواع تلویزیون",
|
||||||
title_en: "televisions",
|
title_en: "televisions",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -229,7 +227,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع اسپیکر",
|
description: "انواع اسپیکر",
|
||||||
title_en: "speakers",
|
title_en: "speakers",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -238,7 +236,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع هدفون",
|
description: "انواع هدفون",
|
||||||
title_en: "headphones",
|
title_en: "headphones",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Colored,
|
themeType: "color",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -247,7 +245,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع دوربین عکاسی",
|
description: "انواع دوربین عکاسی",
|
||||||
title_en: "cameras",
|
title_en: "cameras",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -258,7 +256,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لپ تاپ",
|
description: "انواع لپ تاپ",
|
||||||
title_en: "laptops",
|
title_en: "laptops",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -267,7 +265,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع موس و کیبورد",
|
description: "انواع موس و کیبورد",
|
||||||
title_en: "mouse-keyboards",
|
title_en: "mouse-keyboards",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -278,7 +276,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع پلی استیشن",
|
description: "انواع پلی استیشن",
|
||||||
title_en: "playstations",
|
title_en: "playstations",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -287,7 +285,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع ایکس باکس",
|
description: "انواع ایکس باکس",
|
||||||
title_en: "xbox",
|
title_en: "xbox",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -298,7 +296,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع تجهیزات ورزشی",
|
description: "انواع تجهیزات ورزشی",
|
||||||
title_en: "sports-equipment",
|
title_en: "sports-equipment",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -307,7 +305,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لوازم سفر",
|
description: "انواع لوازم سفر",
|
||||||
title_en: "travel-equipment",
|
title_en: "travel-equipment",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -318,7 +316,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لباس زنانه",
|
description: "انواع لباس زنانه",
|
||||||
title_en: "women-clothing",
|
title_en: "women-clothing",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Sized,
|
themeType: "size",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -327,7 +325,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لباس مردانه",
|
description: "انواع لباس مردانه",
|
||||||
title_en: "men-clothing",
|
title_en: "men-clothing",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.Sized,
|
themeType: "size",
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -338,7 +336,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لوازم آشپزخانه",
|
description: "انواع لوازم آشپزخانه",
|
||||||
title_en: "kitchen-appliances",
|
title_en: "kitchen-appliances",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -347,7 +345,7 @@ const subcategories: { [key: string]: ICategorySeed[] } = {
|
|||||||
description: "انواع لوازم نظافت",
|
description: "انواع لوازم نظافت",
|
||||||
title_en: "cleaning-appliances",
|
title_en: "cleaning-appliances",
|
||||||
leaf: true,
|
leaf: true,
|
||||||
theme: CategoryThemeEnum.No_color_No_sized,
|
themeType: null,
|
||||||
imageUrl: faker.image.imageUrl(),
|
imageUrl: faker.image.imageUrl(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -461,9 +459,13 @@ export const seedCategories = async (logger: Logger) => {
|
|||||||
try {
|
try {
|
||||||
logger.info("Categories seeding started");
|
logger.info("Categories seeding started");
|
||||||
|
|
||||||
const colors = (await ColorModel.find()).map((color) => color._id);
|
const colorTheme = await ThemeModel.findOne({ title: "رنگ" });
|
||||||
const sizes = (await SizeModel.find()).map((size) => size._id);
|
const sizeTheme = await ThemeModel.findOne({ title: "سایز" });
|
||||||
const meterages = (await MeterageModel.find()).map((meterage) => meterage._id);
|
const meterageTheme = await ThemeModel.findOne({ title: "متراژ" });
|
||||||
|
|
||||||
|
const colors = colorTheme ? (await ThemeValueModel.find({ theme: colorTheme._id })).map((color) => color._id) : [];
|
||||||
|
const sizes = sizeTheme ? (await ThemeValueModel.find({ theme: sizeTheme._id })).map((size) => size._id) : [];
|
||||||
|
const meterages = meterageTheme ? (await ThemeValueModel.find({ theme: meterageTheme._id })).map((meterage) => meterage._id) : [];
|
||||||
|
|
||||||
const createdCategories: { [key: string]: Types.ObjectId } = {};
|
const createdCategories: { [key: string]: Types.ObjectId } = {};
|
||||||
const createdSubCategories: { [key: string]: Types.ObjectId } = {};
|
const createdSubCategories: { [key: string]: Types.ObjectId } = {};
|
||||||
@@ -483,16 +485,22 @@ export const seedCategories = async (logger: Logger) => {
|
|||||||
const parentId = createdCategories[rootName];
|
const parentId = createdCategories[rootName];
|
||||||
if (parentId) {
|
if (parentId) {
|
||||||
for (const subcategory of subs) {
|
for (const subcategory of subs) {
|
||||||
const { title_fa, icon, description, title_en, leaf, theme, imageUrl } = subcategory;
|
const { title_fa, icon, description, title_en, leaf, themeType, imageUrl } = subcategory;
|
||||||
|
|
||||||
const catVariants =
|
// Map themeType to theme ID and variants
|
||||||
theme === CategoryThemeEnum.Colored
|
let themeId: Types.ObjectId | undefined;
|
||||||
? [...colors]
|
let catVariants: Types.ObjectId[] = [];
|
||||||
: theme === CategoryThemeEnum.Meterage
|
|
||||||
? [...meterages]
|
if (themeType === "color" && colorTheme) {
|
||||||
: theme === CategoryThemeEnum.Sized
|
themeId = colorTheme._id;
|
||||||
? [...sizes]
|
catVariants = [...colors];
|
||||||
: [];
|
} else if (themeType === "size" && sizeTheme) {
|
||||||
|
themeId = sizeTheme._id;
|
||||||
|
catVariants = [...sizes];
|
||||||
|
} else if (themeType === "meterage" && meterageTheme) {
|
||||||
|
themeId = meterageTheme._id;
|
||||||
|
catVariants = [...meterages];
|
||||||
|
}
|
||||||
|
|
||||||
const subCategoryDoc = new CategoryModel({
|
const subCategoryDoc = new CategoryModel({
|
||||||
title_fa,
|
title_fa,
|
||||||
@@ -501,7 +509,7 @@ export const seedCategories = async (logger: Logger) => {
|
|||||||
title_en,
|
title_en,
|
||||||
description,
|
description,
|
||||||
leaf,
|
leaf,
|
||||||
theme,
|
theme: themeId,
|
||||||
variants: catVariants,
|
variants: catVariants,
|
||||||
parent: parentId,
|
parent: parentId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,9 +7,8 @@ import { BrandModel } from "../../modules/brand/models/brand.model";
|
|||||||
import { AttributeValueModel } from "../../modules/category/models/attributeValue.model";
|
import { AttributeValueModel } from "../../modules/category/models/attributeValue.model";
|
||||||
import { CategoryModel } from "../../modules/category/models/category.model";
|
import { CategoryModel } from "../../modules/category/models/category.model";
|
||||||
import { CategoryAttributeModel } from "../../modules/category/models/CategoryAttribute.model";
|
import { CategoryAttributeModel } from "../../modules/category/models/CategoryAttribute.model";
|
||||||
import { ColorModel } from "../../modules/category/models/color.model";
|
import { ThemeModel } from "../../modules/category/models/theme.model";
|
||||||
import { MeterageModel } from "../../modules/category/models/meterage.model";
|
import { ThemeValueModel } from "../../modules/category/models/themeValue.model";
|
||||||
import { SizeModel } from "../../modules/category/models/size.model";
|
|
||||||
import { ISpecifications } from "../../modules/product/models/Abstraction/IProduct";
|
import { ISpecifications } from "../../modules/product/models/Abstraction/IProduct";
|
||||||
import { ProductModel } from "../../modules/product/models/product.model";
|
import { ProductModel } from "../../modules/product/models/product.model";
|
||||||
import { ProductVariantModel } from "../../modules/product/models/productVariant.model";
|
import { ProductVariantModel } from "../../modules/product/models/productVariant.model";
|
||||||
@@ -205,22 +204,13 @@ const getBrandAndCategoryForProduct = async (product: (typeof fakeProductsData)[
|
|||||||
return { brand, category };
|
return { brand, category };
|
||||||
};
|
};
|
||||||
|
|
||||||
const createFakeProductVariant = (
|
const createFakeProductVariant = (productId: number, shopId: string, warrantyId: number, themeValueId?: string) => {
|
||||||
productId: number,
|
|
||||||
shopId: string,
|
|
||||||
warrantyId: number,
|
|
||||||
colorId?: number,
|
|
||||||
sizeId?: number,
|
|
||||||
meterageId?: number,
|
|
||||||
) => {
|
|
||||||
return new ProductVariantModel({
|
return new ProductVariantModel({
|
||||||
product: productId,
|
product: productId,
|
||||||
rate: faker.datatype.float({ min: 1, max: 5 }),
|
rate: faker.datatype.float({ min: 1, max: 5 }),
|
||||||
warranty: warrantyId,
|
warranty: warrantyId,
|
||||||
shop: shopId,
|
shop: shopId,
|
||||||
color: colorId,
|
themeValue: themeValueId,
|
||||||
size: sizeId,
|
|
||||||
meterage: meterageId,
|
|
||||||
sellerSpecialCode: crypto.randomUUID().slice(0, 6).toUpperCase(),
|
sellerSpecialCode: crypto.randomUUID().slice(0, 6).toUpperCase(),
|
||||||
market_status: faker.helpers.arrayElement([ProductMarketStatus.Marketable]),
|
market_status: faker.helpers.arrayElement([ProductMarketStatus.Marketable]),
|
||||||
postingTime: faker.datatype.number({ min: 1, max: 10 }),
|
postingTime: faker.datatype.number({ min: 1, max: 10 }),
|
||||||
@@ -258,9 +248,14 @@ export const seedProduct = async (logger: Logger) => {
|
|||||||
// Fetch warranties and shipment methods
|
// Fetch warranties and shipment methods
|
||||||
const warranties = await WarrantyModel.find().limit(10);
|
const warranties = await WarrantyModel.find().limit(10);
|
||||||
const shipments = (await ShipmentModel.find()).map((shipper) => shipper._id);
|
const shipments = (await ShipmentModel.find()).map((shipper) => shipper._id);
|
||||||
const colors = (await ColorModel.find()).map((color) => color._id);
|
|
||||||
const sizes = (await SizeModel.find()).map((size) => size._id);
|
const colorTheme = await ThemeModel.findOne({ title: "رنگ" });
|
||||||
const meterages = (await MeterageModel.find()).map((meterage) => meterage._id);
|
const sizeTheme = await ThemeModel.findOne({ title: "سایز" });
|
||||||
|
const meterageTheme = await ThemeModel.findOne({ title: "متراژ" });
|
||||||
|
|
||||||
|
const colors = colorTheme ? (await ThemeValueModel.find({ theme: colorTheme._id })).map((color) => color._id) : [];
|
||||||
|
const sizes = sizeTheme ? (await ThemeValueModel.find({ theme: sizeTheme._id })).map((size) => size._id) : [];
|
||||||
|
const meterages = meterageTheme ? (await ThemeValueModel.find({ theme: meterageTheme._id })).map((meterage) => meterage._id) : [];
|
||||||
|
|
||||||
if (!warranties.length) {
|
if (!warranties.length) {
|
||||||
throw new Error("No warranties found in the database. Please seed them first.");
|
throw new Error("No warranties found in the database. Please seed them first.");
|
||||||
@@ -302,13 +297,21 @@ export const seedProduct = async (logger: Logger) => {
|
|||||||
}).save();
|
}).save();
|
||||||
|
|
||||||
for (let k = 0; k < 3; k++) {
|
for (let k = 0; k < 3; k++) {
|
||||||
|
// Select a theme value based on product data
|
||||||
|
let themeValueId: string | undefined;
|
||||||
|
if (productData.color && colors.length > 0) {
|
||||||
|
themeValueId = faker.helpers.arrayElement(colors).toString();
|
||||||
|
} else if (productData.size && sizes.length > 0) {
|
||||||
|
themeValueId = faker.helpers.arrayElement(sizes).toString();
|
||||||
|
} else if (productData.meterage && meterages.length > 0) {
|
||||||
|
themeValueId = faker.helpers.arrayElement(meterages).toString();
|
||||||
|
}
|
||||||
|
|
||||||
const variant = await createFakeProductVariant(
|
const variant = await createFakeProductVariant(
|
||||||
product._id,
|
product._id,
|
||||||
shop._id.toString(),
|
shop._id.toString(),
|
||||||
faker.helpers.arrayElement(warranties)._id,
|
faker.helpers.arrayElement(warranties)._id,
|
||||||
productData.color ? faker.helpers.arrayElement(colors) : undefined,
|
themeValueId,
|
||||||
productData.size ? faker.helpers.arrayElement(sizes) : undefined,
|
|
||||||
productData.meterage ? faker.helpers.arrayElement(meterages) : undefined,
|
|
||||||
).save();
|
).save();
|
||||||
product.variants.push(variant._id);
|
product.variants.push(variant._id);
|
||||||
await product.save();
|
await product.save();
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import { EventEmitter } from "events";
|
|||||||
|
|
||||||
import { HydratedDocument, Types } from "mongoose";
|
import { HydratedDocument, Types } from "mongoose";
|
||||||
|
|
||||||
import { ColorModel } from "../modules/category/models/color.model";
|
import { ThemeValueModel } from "../modules/category/models/themeValue.model";
|
||||||
import { MeterageModel } from "../modules/category/models/meterage.model";
|
|
||||||
import { SizeModel } from "../modules/category/models/size.model";
|
|
||||||
import { IPriceHistory } from "../modules/product/models/Abstraction/IPriceHistory";
|
import { IPriceHistory } from "../modules/product/models/Abstraction/IPriceHistory";
|
||||||
import { PriceHistoryModel } from "../modules/product/models/priceHistory.model";
|
import { PriceHistoryModel } from "../modules/product/models/priceHistory.model";
|
||||||
import { ProductObserveModel } from "../modules/product/models/productObserve.model";
|
import { ProductObserveModel } from "../modules/product/models/productObserve.model";
|
||||||
@@ -24,9 +22,7 @@ type PriceDetails = {
|
|||||||
retail_price: number;
|
retail_price: number;
|
||||||
variantId: string;
|
variantId: string;
|
||||||
isSpecial?: boolean;
|
isSpecial?: boolean;
|
||||||
colorId?: number;
|
themeValueId?: string;
|
||||||
sizeId?: number;
|
|
||||||
meterageId?: number;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type historyDetail = { shop: string; selling_price: number; retail_price: number };
|
type historyDetail = { shop: string; selling_price: number; retail_price: number };
|
||||||
@@ -66,7 +62,7 @@ class PriceChangeEventService extends EventEmitter {
|
|||||||
try {
|
try {
|
||||||
const title = await this.findVariantTitle(priceDetails);
|
const title = await this.findVariantTitle(priceDetails);
|
||||||
const now = TimeService.getCurrentPersianDate();
|
const now = TimeService.getCurrentPersianDate();
|
||||||
const { colorId, sizeId, meterageId, product, ...history } = priceDetails;
|
const { themeValueId, product, ...history } = priceDetails;
|
||||||
|
|
||||||
const existingHistory = await PriceHistoryModel.findOne({ title, product });
|
const existingHistory = await PriceHistoryModel.findOne({ title, product });
|
||||||
|
|
||||||
@@ -137,15 +133,9 @@ class PriceChangeEventService extends EventEmitter {
|
|||||||
}
|
}
|
||||||
//**** */
|
//**** */
|
||||||
private async findVariantTitle(priceDetails: PriceDetails): Promise<string> {
|
private async findVariantTitle(priceDetails: PriceDetails): Promise<string> {
|
||||||
if (priceDetails.colorId) {
|
if (priceDetails.themeValueId) {
|
||||||
const color = await ColorModel.findById(priceDetails.colorId).lean();
|
const themeValue = await ThemeValueModel.findById(priceDetails.themeValueId).lean();
|
||||||
return color?.name || "Unknown color";
|
return themeValue?.name || "Unknown variant";
|
||||||
} else if (priceDetails.sizeId) {
|
|
||||||
const size = await SizeModel.findById(priceDetails.sizeId).lean();
|
|
||||||
return size?.value || "Unknown size";
|
|
||||||
} else if (priceDetails.meterageId) {
|
|
||||||
const meterage = await MeterageModel.findById(priceDetails.meterageId).lean();
|
|
||||||
return meterage?.value || "Unknown meterage";
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { inject } from "inversify";
|
import { inject } from "inversify";
|
||||||
import { controller, httpDelete, httpPatch, httpPost, requestBody, requestParam } from "inversify-express-utils";
|
import { controller, httpDelete, httpGet, httpPatch, httpPost, httpPut, requestBody, requestParam } from "inversify-express-utils";
|
||||||
|
|
||||||
import { HttpStatus } from "../../../common";
|
import { HttpStatus } from "../../../common";
|
||||||
import { BaseController } from "../../../common/base/controller";
|
import { BaseController } from "../../../common/base/controller";
|
||||||
@@ -12,14 +12,20 @@ import { CategoryService } from "../../category/category.service";
|
|||||||
import { CreateCategoryDTO } from "../../category/DTO/CreateCategory.dto";
|
import { CreateCategoryDTO } from "../../category/DTO/CreateCategory.dto";
|
||||||
import { CreateCategoryAttDTO } from "../../category/DTO/createCategoryAtt.dto";
|
import { CreateCategoryAttDTO } from "../../category/DTO/createCategoryAtt.dto";
|
||||||
import { CreateCategoryThemeDTO, UpdateCategoryVariantDTO } from "../../category/DTO/createCategoryTheme.dto";
|
import { CreateCategoryThemeDTO, UpdateCategoryVariantDTO } from "../../category/DTO/createCategoryTheme.dto";
|
||||||
|
import { CreateThemeDTO } from "../../category/DTO/CreateTheme.dto";
|
||||||
|
import { CreateThemeValueDTO } from "../../category/DTO/CreateThemeValue.dto";
|
||||||
import { UpdateCategoryDTO } from "../../category/DTO/UpdateCategory.dto";
|
import { UpdateCategoryDTO } from "../../category/DTO/UpdateCategory.dto";
|
||||||
import { UpdateCategoryAttDTO } from "../../category/DTO/updateCategoryAtt.dto";
|
import { UpdateCategoryAttDTO } from "../../category/DTO/updateCategoryAtt.dto";
|
||||||
|
import { UpdateThemeDTO } from "../../category/DTO/UpdateTheme.dto";
|
||||||
|
import { UpdateThemeValueDTO } from "../../category/DTO/UpdateThemeValue.dto";
|
||||||
|
import { ThemeService } from "../../category/theme.service";
|
||||||
import { PermissionEnum } from "../models/Abstraction/IPermission";
|
import { PermissionEnum } from "../models/Abstraction/IPermission";
|
||||||
|
|
||||||
@ApiTags("Admin Category")
|
@ApiTags("Admin Category")
|
||||||
@controller("/admin/category")
|
@controller("/admin/category")
|
||||||
export class AdminCategoryController extends BaseController {
|
export class AdminCategoryController extends BaseController {
|
||||||
@inject(IOCTYPES.CategoryService) private categoryService: CategoryService;
|
@inject(IOCTYPES.CategoryService) private categoryService: CategoryService;
|
||||||
|
@inject(IOCTYPES.ThemeService) private themeService: ThemeService;
|
||||||
|
|
||||||
@ApiOperation("create a category ")
|
@ApiOperation("create a category ")
|
||||||
@ApiResponse("return created category", HttpStatus.Created)
|
@ApiResponse("return created category", HttpStatus.Created)
|
||||||
@@ -134,4 +140,127 @@ export class AdminCategoryController extends BaseController {
|
|||||||
const data = await this.categoryService.updateCategoryAttributeS(createAttributeDto);
|
const data = await this.categoryService.updateCategoryAttributeS(createAttributeDto);
|
||||||
return this.response({ data }, HttpStatus.Created);
|
return this.response({ data }, HttpStatus.Created);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#########################################theme endpoints
|
||||||
|
@ApiOperation("Get all themes")
|
||||||
|
@ApiResponse("get all themes", HttpStatus.Ok)
|
||||||
|
@httpGet("/theme")
|
||||||
|
public async getAllThemes() {
|
||||||
|
const data = await this.themeService.getAllThemes();
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Get a theme with id")
|
||||||
|
@ApiResponse("get a theme", HttpStatus.Ok)
|
||||||
|
@ApiParam("id", "id of the theme", true)
|
||||||
|
@httpGet("/theme/:id")
|
||||||
|
public async getThemeById(@requestParam("id") id: string) {
|
||||||
|
const data = await this.themeService.getThemeById(id);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Create a new theme ==> need to login as admin")
|
||||||
|
@ApiResponse("theme created successfully", HttpStatus.Created)
|
||||||
|
@ApiModel(CreateThemeDTO)
|
||||||
|
@ApiAuth()
|
||||||
|
@httpPost(
|
||||||
|
"/theme",
|
||||||
|
Guard.authAdmin(),
|
||||||
|
Guard.checkAdminPermissions([PermissionEnum.ADMIN]),
|
||||||
|
ValidationMiddleware.validateInput(CreateThemeDTO),
|
||||||
|
)
|
||||||
|
public async createTheme(@requestBody() createDto: CreateThemeDTO) {
|
||||||
|
const data = await this.themeService.createTheme(createDto);
|
||||||
|
return this.response({ data }, HttpStatus.Created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Update a theme ==> need to login as admin")
|
||||||
|
@ApiResponse("theme updated successfully", HttpStatus.Ok)
|
||||||
|
@ApiAuth()
|
||||||
|
@httpPut(
|
||||||
|
"/theme",
|
||||||
|
Guard.authAdmin(),
|
||||||
|
Guard.checkAdminPermissions([PermissionEnum.ADMIN]),
|
||||||
|
ValidationMiddleware.validateInput(UpdateThemeDTO),
|
||||||
|
)
|
||||||
|
public async updateTheme(@requestBody() updateDto: UpdateThemeDTO) {
|
||||||
|
const data = await this.themeService.updateTheme(updateDto);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Delete a theme ==> need to login as admin")
|
||||||
|
@ApiResponse("theme deleted successfully", HttpStatus.Ok)
|
||||||
|
@ApiParam("id", "id of the theme", true)
|
||||||
|
@ApiAuth()
|
||||||
|
@httpDelete("/theme/:id", Guard.authAdmin(), Guard.checkAdminPermissions([PermissionEnum.ADMIN]))
|
||||||
|
public async deleteTheme(@requestParam("id") id: string) {
|
||||||
|
const data = await this.themeService.deleteTheme(id);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
//#########################################theme value endpoints
|
||||||
|
@ApiOperation("Get all theme values")
|
||||||
|
@ApiResponse("get all theme values", HttpStatus.Ok)
|
||||||
|
@httpGet("/theme-value")
|
||||||
|
public async getAllThemeValues() {
|
||||||
|
const data = await this.themeService.getAllThemeValues();
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Get theme values by theme id")
|
||||||
|
@ApiResponse("get theme values by theme id", HttpStatus.Ok)
|
||||||
|
@ApiParam("themeId", "id of the theme", true)
|
||||||
|
@httpGet("/theme-value/:themeId/values")
|
||||||
|
public async getThemeValuesByThemeId(@requestParam("themeId") themeId: string) {
|
||||||
|
const data = await this.themeService.getThemeValuesByThemeId(themeId);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Get a theme value with id")
|
||||||
|
@ApiResponse("get a theme value", HttpStatus.Ok)
|
||||||
|
@ApiParam("id", "id of the theme value", true)
|
||||||
|
@httpGet("/theme-value/:id")
|
||||||
|
public async getThemeValueById(@requestParam("id") id: string) {
|
||||||
|
const data = await this.themeService.getThemeValueById(id);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Create a new theme value ==> need to login as admin")
|
||||||
|
@ApiResponse("theme value created successfully", HttpStatus.Created)
|
||||||
|
@ApiAuth()
|
||||||
|
@ApiModel(CreateThemeValueDTO)
|
||||||
|
@httpPost(
|
||||||
|
"/theme-value",
|
||||||
|
Guard.authAdmin(),
|
||||||
|
Guard.checkAdminPermissions([PermissionEnum.ADMIN]),
|
||||||
|
ValidationMiddleware.validateInput(CreateThemeValueDTO),
|
||||||
|
)
|
||||||
|
public async createThemeValue(@requestBody() createDto: CreateThemeValueDTO) {
|
||||||
|
const data = await this.themeService.createThemeValue(createDto);
|
||||||
|
return this.response({ data }, HttpStatus.Created);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Update a theme value ==> need to login as admin")
|
||||||
|
@ApiResponse("theme value updated successfully", HttpStatus.Ok)
|
||||||
|
@ApiAuth()
|
||||||
|
@httpPut(
|
||||||
|
"/theme-value",
|
||||||
|
Guard.authAdmin(),
|
||||||
|
Guard.checkAdminPermissions([PermissionEnum.ADMIN]),
|
||||||
|
ValidationMiddleware.validateInput(UpdateThemeValueDTO),
|
||||||
|
)
|
||||||
|
public async updateThemeValue(@requestBody() updateDto: UpdateThemeValueDTO) {
|
||||||
|
const data = await this.themeService.updateThemeValue(updateDto);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation("Delete a theme value ==> need to login as admin")
|
||||||
|
@ApiResponse("theme value deleted successfully", HttpStatus.Ok)
|
||||||
|
@ApiParam("id", "id of the theme value", true)
|
||||||
|
@ApiAuth()
|
||||||
|
@httpDelete("/theme-value/:id", Guard.authAdmin(), Guard.checkAdminPermissions([PermissionEnum.ADMIN]))
|
||||||
|
public async deleteThemeValue(@requestParam("id") id: string) {
|
||||||
|
const data = await this.themeService.deleteThemeValue(id);
|
||||||
|
return this.response({ data });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Expose } from "class-transformer";
|
import { Expose } from "class-transformer";
|
||||||
import { IsEnum, IsNotEmpty, IsOptional } from "class-validator";
|
import { IsNotEmpty, IsOptional } from "class-validator";
|
||||||
|
|
||||||
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
import { CategoryModel } from "../models/category.model";
|
import { CategoryModel } from "../models/category.model";
|
||||||
|
import { ThemeModel } from "../models/theme.model";
|
||||||
|
|
||||||
export class CreateCategoryDTO {
|
export class CreateCategoryDTO {
|
||||||
@Expose()
|
@Expose()
|
||||||
@@ -40,12 +40,11 @@ export class CreateCategoryDTO {
|
|||||||
parent?: string;
|
parent?: string;
|
||||||
|
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsNotEmpty()
|
@IsOptional()
|
||||||
@IsEnum(CategoryThemeEnum)
|
@IsValidId(ThemeModel)
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: "string",
|
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 ==> should be one of Color/Size/Meterage or noColor_noSize",
|
||||||
example: "Color",
|
|
||||||
})
|
})
|
||||||
theme: CategoryThemeEnum;
|
themeId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { Expose } from "class-transformer";
|
||||||
|
import { IsEnum, IsNotEmpty } from "class-validator";
|
||||||
|
|
||||||
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
|
import { InputTypeEnum } from "../models/theme.model";
|
||||||
|
|
||||||
|
export class CreateThemeDTO {
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ type: "string", description: "the title of theme", example: "Color" })
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsEnum(InputTypeEnum)
|
||||||
|
@ApiProperty({
|
||||||
|
type: "string",
|
||||||
|
description: "the input type of theme",
|
||||||
|
example: InputTypeEnum.Color,
|
||||||
|
})
|
||||||
|
inputType: InputTypeEnum;
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Expose } from "class-transformer";
|
||||||
|
import { IsNotEmpty, IsString } from "class-validator";
|
||||||
|
|
||||||
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
|
import { ThemeModel } from "../models/theme.model";
|
||||||
|
|
||||||
|
export class CreateThemeValueDTO {
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@IsValidId(ThemeModel)
|
||||||
|
@ApiProperty({ type: "string", description: "the theme id", example: "66f3bcaee566db722a044c62" })
|
||||||
|
theme: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@ApiProperty({ type: "string", description: "the name of theme value", example: "Red" })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ type: "string", description: "the value of theme value (can be string, number, or color hex)", example: "#FF0000" })
|
||||||
|
value: string | number;
|
||||||
|
}
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import { Expose } from "class-transformer";
|
import { Expose } from "class-transformer";
|
||||||
import { IsEnum, IsNotEmpty, IsOptional, IsString, Length } from "class-validator";
|
import { IsNotEmpty, IsOptional, IsString, Length } from "class-validator";
|
||||||
|
|
||||||
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
import { CategoryModel } from "../models/category.model";
|
import { CategoryModel } from "../models/category.model";
|
||||||
|
import { ThemeModel } from "../models/theme.model";
|
||||||
|
|
||||||
export class UpdateCategoryDTO {
|
export class UpdateCategoryDTO {
|
||||||
@Expose()
|
@Expose()
|
||||||
@@ -54,12 +54,11 @@ export class UpdateCategoryDTO {
|
|||||||
|
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNotEmpty()
|
@IsValidId(ThemeModel)
|
||||||
@IsEnum(CategoryThemeEnum)
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: "string",
|
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 ==> should be one of Color/Size/Meterage or noColor_noSize",
|
||||||
example: "Color",
|
example: "Color",
|
||||||
})
|
})
|
||||||
theme: CategoryThemeEnum;
|
themeId: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
import { Expose } from "class-transformer";
|
||||||
|
import { IsEnum, IsNotEmpty, IsOptional, IsString, Length } from "class-validator";
|
||||||
|
|
||||||
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
|
import { InputTypeEnum, ThemeModel } from "../models/theme.model";
|
||||||
|
|
||||||
|
export class UpdateThemeDTO {
|
||||||
|
@Expose()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
@Length(24, 24)
|
||||||
|
@IsValidId(ThemeModel)
|
||||||
|
@ApiProperty({ type: "string", description: "theme id", example: "66f3bcaee566db722a044c62" })
|
||||||
|
themeId: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsOptional()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ type: "string", description: "the title of theme", example: "Color" })
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsOptional()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsEnum(InputTypeEnum)
|
||||||
|
@ApiProperty({
|
||||||
|
type: "string",
|
||||||
|
description: "the input type of theme",
|
||||||
|
example: InputTypeEnum.Color,
|
||||||
|
})
|
||||||
|
inputType?: InputTypeEnum;
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import { Expose } from "class-transformer";
|
||||||
|
import { IsNotEmpty, IsOptional, IsString, Length } 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()
|
||||||
|
@IsString()
|
||||||
|
@ApiProperty({ type: "string", description: "the name of theme value", example: "Red" })
|
||||||
|
name?: string;
|
||||||
|
|
||||||
|
@Expose()
|
||||||
|
@IsOptional()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ type: "string", description: "the value of theme value (can be string, number, or color hex)", example: "#FF0000" })
|
||||||
|
value?: string | number;
|
||||||
|
}
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
import { PickType } from "@nestjs/mapped-types";
|
import { PartialType } from "@nestjs/mapped-types";
|
||||||
import { Expose, Type } from "class-transformer";
|
import { Expose, Type } from "class-transformer";
|
||||||
import { ArrayMinSize, IsEnum, IsHexColor, IsNotEmpty, IsOptional, ValidateNested } from "class-validator";
|
import { ArrayMinSize, IsHexColor, IsNotEmpty, IsOptional, ValidateNested } from "class-validator";
|
||||||
|
|
||||||
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
|
import { ThemeModel } from "../models/theme.model";
|
||||||
|
|
||||||
export class CreateColorDTO {
|
export class CreateColorDTO {
|
||||||
@Expose()
|
@Expose()
|
||||||
@@ -30,14 +31,13 @@ export class CreateMeterageDTO {
|
|||||||
|
|
||||||
export class CreateCategoryThemeDTO {
|
export class CreateCategoryThemeDTO {
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsNotEmpty()
|
@IsOptional()
|
||||||
@IsEnum(CategoryThemeEnum)
|
@IsValidId(ThemeModel)
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
type: "string",
|
type: "string",
|
||||||
description: "the variation theme of a category ==> should be one of Color/Size/Meterage or noColor_noSize",
|
description: "theme id",
|
||||||
example: "Color",
|
|
||||||
})
|
})
|
||||||
theme: CategoryThemeEnum;
|
themeId?: string;
|
||||||
|
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@@ -80,4 +80,4 @@ export class CreateCategoryThemeDTO {
|
|||||||
meterages?: CreateMeterageDTO[];
|
meterages?: CreateMeterageDTO[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class UpdateCategoryVariantDTO extends PickType(CreateCategoryThemeDTO, ["colors", "sizes", "meterages"] as const) {}
|
export class UpdateCategoryVariantDTO extends PartialType(CreateCategoryThemeDTO) {}
|
||||||
|
|||||||
@@ -4,15 +4,13 @@ import { SellerCategorySearchDTO } from "./DTO/category-sarch.dto";
|
|||||||
import { IAttributeValue } from "./models/Abstraction/IAttributeValue";
|
import { IAttributeValue } from "./models/Abstraction/IAttributeValue";
|
||||||
import { ICategory } from "./models/Abstraction/ICategory";
|
import { ICategory } from "./models/Abstraction/ICategory";
|
||||||
import { ICategoryAttribute } from "./models/Abstraction/ICategoryAttributes";
|
import { ICategoryAttribute } from "./models/Abstraction/ICategoryAttributes";
|
||||||
import { IColor } from "./models/Abstraction/IColor";
|
import { ITheme } from "./models/Abstraction/ITheme";
|
||||||
import { IMeterage } from "./models/Abstraction/IMeterage";
|
import { IThemeValue } from "./models/Abstraction/IThemeValue";
|
||||||
import { ISize } from "./models/Abstraction/ISize";
|
|
||||||
import { AttributeValueModel } from "./models/attributeValue.model";
|
import { AttributeValueModel } from "./models/attributeValue.model";
|
||||||
import { CategoryModel } from "./models/category.model";
|
import { CategoryModel } from "./models/category.model";
|
||||||
import { CategoryAttributeModel } from "./models/CategoryAttribute.model";
|
import { CategoryAttributeModel } from "./models/CategoryAttribute.model";
|
||||||
import { ColorModel } from "./models/color.model";
|
import { ThemeModel } from "./models/theme.model";
|
||||||
import { MeterageModel } from "./models/meterage.model";
|
import { ThemeValueModel } from "./models/themeValue.model";
|
||||||
import { SizeModel } from "./models/size.model";
|
|
||||||
import { BaseRepository } from "../../common/base/repository";
|
import { BaseRepository } from "../../common/base/repository";
|
||||||
import { BadRequestError } from "../../core/app/app.errors";
|
import { BadRequestError } from "../../core/app/app.errors";
|
||||||
const { ObjectId } = Types;
|
const { ObjectId } = Types;
|
||||||
@@ -167,21 +165,21 @@ class CategoryRepository extends BaseRepository<ICategory> {
|
|||||||
const result: Record<string, any[]> = {};
|
const result: Record<string, any[]> = {};
|
||||||
|
|
||||||
// Step 4: Perform a single lookup per theme
|
// Step 4: Perform a single lookup per theme
|
||||||
for (const [theme, variantIdsSet] of themeVariantsMap.entries()) {
|
// for (const [theme, variantIdsSet] of themeVariantsMap.entries()) {
|
||||||
const variantIds = Array.from(variantIdsSet).map((id) => +id);
|
// const variantIds = Array.from(variantIdsSet).map((id) => +id);
|
||||||
|
|
||||||
if (variantIds.length > 0) {
|
// // if (variantIds.length > 0) {
|
||||||
let variantsData;
|
// // let variantsData;
|
||||||
// Fetch the variants from the corresponding theme collection
|
// // // Fetch the variants from the corresponding theme collection
|
||||||
if (theme === "colors") variantsData = await ColorModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
// // if (theme === "colors") variantsData = await ColorModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
||||||
if (theme === "sizes") variantsData = await SizeModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
// // if (theme === "sizes") variantsData = await SizeModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
||||||
if (theme === "meterages") variantsData = await MeterageModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
// // if (theme === "meterages") variantsData = await MeterageModel.find({ _id: { $in: variantIds } }, { __v: 0 }).lean();
|
||||||
// throw new Error("theme not valid");
|
// // // throw new Error("theme not valid");
|
||||||
|
|
||||||
// Store the result for this theme
|
// // // Store the result for this theme
|
||||||
result[theme] = variantsData as any;
|
// // result[theme] = variantsData as any;
|
||||||
}
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -356,48 +354,38 @@ function createAttributeValueRepo(): AttributeValueRepo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//=====================>size model repository
|
//=====================>size model repository
|
||||||
class SizeRepository extends BaseRepository<ISize> {
|
|
||||||
|
//=====================>theme model repo
|
||||||
|
class ThemeRepository extends BaseRepository<ITheme> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(SizeModel);
|
super(ThemeModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createSizeRepo(): SizeRepository {
|
function createThemeRepo(): ThemeRepository {
|
||||||
return new SizeRepository();
|
return new ThemeRepository();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=====================>color model repo
|
//=====================>theme value model repo
|
||||||
class ColorRepository extends BaseRepository<IColor> {
|
class ThemeValueRepository extends BaseRepository<IThemeValue> {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(ColorModel);
|
super(ThemeValueModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function createColorRepo(): ColorRepository {
|
function createThemeValueRepo(): ThemeValueRepository {
|
||||||
return new ColorRepository();
|
return new ThemeValueRepository();
|
||||||
}
|
|
||||||
|
|
||||||
//=====================>meterage model repo
|
|
||||||
class MeterageRepository extends BaseRepository<IMeterage> {
|
|
||||||
constructor() {
|
|
||||||
super(MeterageModel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function createMeterageRepo(): MeterageRepository {
|
|
||||||
return new MeterageRepository();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createCategoryRepo,
|
createCategoryRepo,
|
||||||
createCategoryAttributeRepo,
|
createCategoryAttributeRepo,
|
||||||
createSizeRepo,
|
|
||||||
createMeterageRepo,
|
|
||||||
createColorRepo,
|
|
||||||
createAttributeValueRepo,
|
createAttributeValueRepo,
|
||||||
|
createThemeRepo,
|
||||||
|
createThemeValueRepo,
|
||||||
AttributeValueRepo,
|
AttributeValueRepo,
|
||||||
CategoryRepository,
|
CategoryRepository,
|
||||||
CategoryAttributeRepo,
|
CategoryAttributeRepo,
|
||||||
SizeRepository,
|
ThemeRepository,
|
||||||
ColorRepository,
|
ThemeValueRepository,
|
||||||
MeterageRepository,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// async getCategoryVariant(catId: string) {
|
// async getCategoryVariant(catId: string) {
|
||||||
|
|||||||
@@ -1,42 +1,31 @@
|
|||||||
import { inject, injectable } from "inversify";
|
import { inject, injectable } from "inversify";
|
||||||
import { ClientSession, FilterQuery, isValidObjectId, startSession } from "mongoose";
|
import { FilterQuery, Types, isValidObjectId, startSession } from "mongoose";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AttributeValueRepo,
|
AttributeValueRepo,
|
||||||
CategoryAttributeRepo,
|
CategoryAttributeRepo,
|
||||||
CategoryRepository,
|
CategoryRepository,
|
||||||
ColorRepository,
|
ThemeRepository,
|
||||||
MeterageRepository,
|
ThemeValueRepository,
|
||||||
SizeRepository,
|
|
||||||
} from "./category.repository";
|
} from "./category.repository";
|
||||||
import { BrandRepository } from "../brand/brand.repository";
|
import { BrandRepository } from "../brand/brand.repository";
|
||||||
import { CategoryQueryDto, CategorySearchQueryDTO, SellerCategorySearchDTO } from "./DTO/category-sarch.dto";
|
import { CategoryQueryDto, CategorySearchQueryDTO, SellerCategorySearchDTO } from "./DTO/category-sarch.dto";
|
||||||
import { CategoryAttributeDTO, CategoryTreeDTO, CategoryVariantDTO } from "./DTO/category.dto";
|
import { CategoryAttributeDTO, CategoryTreeDTO, CategoryVariantDTO } from "./DTO/category.dto";
|
||||||
import { CreateCategoryDTO } from "./DTO/CreateCategory.dto";
|
import { CreateCategoryDTO } from "./DTO/CreateCategory.dto";
|
||||||
import { CreateCategoryAttDTO } from "./DTO/createCategoryAtt.dto";
|
import { CreateCategoryAttDTO } from "./DTO/createCategoryAtt.dto";
|
||||||
import {
|
import { CreateCategoryThemeDTO, UpdateCategoryVariantDTO } from "./DTO/createCategoryTheme.dto";
|
||||||
CreateCategoryThemeDTO,
|
|
||||||
CreateColorDTO,
|
|
||||||
CreateMeterageDTO,
|
|
||||||
CreateSizeDTO,
|
|
||||||
UpdateCategoryVariantDTO,
|
|
||||||
} from "./DTO/createCategoryTheme.dto";
|
|
||||||
import { UpdateCategoryDTO } from "./DTO/UpdateCategory.dto";
|
import { UpdateCategoryDTO } from "./DTO/UpdateCategory.dto";
|
||||||
import { UpdateCategoryAttDTO } from "./DTO/updateCategoryAtt.dto";
|
import { UpdateCategoryAttDTO } from "./DTO/updateCategoryAtt.dto";
|
||||||
import { IColor } from "./models/Abstraction/IColor";
|
import { ICategory } from "./models/Abstraction/ICategory";
|
||||||
import { IMeterage } from "./models/Abstraction/IMeterage";
|
import { ThemeModel } from "./models/theme.model";
|
||||||
import { ISize } from "./models/Abstraction/ISize";
|
|
||||||
import { BaseRepository } from "../../common/base/repository";
|
|
||||||
import { CategoryThemeEnum } from "../../common/enums/category.enum";
|
|
||||||
import { CategoryAttrMessage, CategoryMessage, CommonMessage } from "../../common/enums/message.enum";
|
import { CategoryAttrMessage, CategoryMessage, CommonMessage } from "../../common/enums/message.enum";
|
||||||
import { BadRequestError, ForbiddenError } from "../../core/app/app.errors";
|
import { BadRequestError, ForbiddenError } from "../../core/app/app.errors";
|
||||||
import { IOCTYPES } from "../../IOC/ioc.types";
|
import { IOCTYPES } from "../../IOC/ioc.types";
|
||||||
|
import { paginationUtils } from "../../utils/pagination.utils";
|
||||||
import { ProductDTO } from "../product/DTO/product.dto";
|
import { ProductDTO } from "../product/DTO/product.dto";
|
||||||
import { IProduct } from "../product/models/Abstraction/IProduct";
|
import { IProduct } from "../product/models/Abstraction/IProduct";
|
||||||
import { ProductRepository } from "../product/Repository/product";
|
import { ProductRepository } from "../product/Repository/product";
|
||||||
import { ICategory } from "./models/Abstraction/ICategory";
|
|
||||||
import { paginationUtils } from "../../utils/pagination.utils";
|
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
class CategoryService {
|
class CategoryService {
|
||||||
@@ -45,9 +34,8 @@ class CategoryService {
|
|||||||
@inject(IOCTYPES.BrandRepository) brandRepo: BrandRepository;
|
@inject(IOCTYPES.BrandRepository) brandRepo: BrandRepository;
|
||||||
@inject(IOCTYPES.CategoryAttributeRepository) categoryAttRepo: CategoryAttributeRepo;
|
@inject(IOCTYPES.CategoryAttributeRepository) categoryAttRepo: CategoryAttributeRepo;
|
||||||
@inject(IOCTYPES.AttributeValueRepository) attributeValueRepo: AttributeValueRepo;
|
@inject(IOCTYPES.AttributeValueRepository) attributeValueRepo: AttributeValueRepo;
|
||||||
@inject(IOCTYPES.ColorRepository) colorRepo: ColorRepository;
|
@inject(IOCTYPES.ThemeRepository) themeRepo: ThemeRepository;
|
||||||
@inject(IOCTYPES.SizeRepository) sizeRepo: SizeRepository;
|
@inject(IOCTYPES.ThemeValueRepository) themeValueRepo: ThemeValueRepository;
|
||||||
@inject(IOCTYPES.MeterageRepository) meterageRepo: MeterageRepository;
|
|
||||||
|
|
||||||
async getCategories() {
|
async getCategories() {
|
||||||
return this.categoryRepository.model.find({ parent: null });
|
return this.categoryRepository.model.find({ parent: null });
|
||||||
@@ -102,8 +90,10 @@ class CategoryService {
|
|||||||
|
|
||||||
if (existTitle) throw new BadRequestError(CategoryMessage.DuplicateTitle);
|
if (existTitle) throw new BadRequestError(CategoryMessage.DuplicateTitle);
|
||||||
//TODO: check if parent is valid for update theme
|
//TODO: check if parent is valid for update theme
|
||||||
if (updateDto.theme) {
|
let theme: typeof ThemeModel | null = null;
|
||||||
await this.categoryRepository.model.findOneAndUpdate({ _id: category._id.toString() }, { theme: updateDto.theme, variants: [] });
|
if (updateDto.themeId) {
|
||||||
|
theme = await this.themeRepo.model.findById(updateDto.themeId);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
}
|
}
|
||||||
if (updateDto.parent) {
|
if (updateDto.parent) {
|
||||||
// Set the parent category to leaf: false (since it now has a child)
|
// Set the parent category to leaf: false (since it now has a child)
|
||||||
@@ -120,7 +110,12 @@ class CategoryService {
|
|||||||
updatedCategory,
|
updatedCategory,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const updatedCategory = await this.categoryRepository.model.findByIdAndUpdate(category._id.toString(), updateDto, { new: true });
|
|
||||||
|
const updatedCategory = await this.categoryRepository.model.findByIdAndUpdate(
|
||||||
|
category._id.toString(),
|
||||||
|
{ ...updateDto, theme: updateDto.themeId },
|
||||||
|
{ new: true },
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
message: CategoryMessage.Updated,
|
message: CategoryMessage.Updated,
|
||||||
updatedCategory,
|
updatedCategory,
|
||||||
@@ -133,13 +128,16 @@ class CategoryService {
|
|||||||
|
|
||||||
const existTitle = await this.categoryRepository.findByTitle(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);
|
if (existTitle) throw new BadRequestError(CategoryMessage.DuplicateTitle);
|
||||||
//if parent exist first set parent leaf false
|
//if parent exist first set parent leaf false
|
||||||
if (createDto.parent) {
|
if (createDto.parent) {
|
||||||
await this.categoryRepository.model.findByIdAndUpdate(createDto.parent, { leaf: false });
|
await this.categoryRepository.model.findByIdAndUpdate(createDto.parent, { leaf: false });
|
||||||
}
|
}
|
||||||
//we set the leaf to true
|
//we set the leaf to true
|
||||||
const category = await this.categoryRepository.model.create(createDto);
|
const category = await this.categoryRepository.model.create({ ...createDto, theme: theme._id });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
message: CategoryMessage.Created,
|
message: CategoryMessage.Created,
|
||||||
@@ -177,68 +175,44 @@ class CategoryService {
|
|||||||
//################################
|
//################################
|
||||||
|
|
||||||
async updateCategoryVariantS(updateDto: UpdateCategoryVariantDTO, id: string) {
|
async updateCategoryVariantS(updateDto: UpdateCategoryVariantDTO, id: string) {
|
||||||
const session = await startSession();
|
const { themeId } = updateDto;
|
||||||
session.startTransaction();
|
|
||||||
try {
|
|
||||||
const { colors, sizes, meterages } = updateDto;
|
|
||||||
|
|
||||||
const category = await this.checkCategoryId(id);
|
const category = await this.checkCategoryId(id);
|
||||||
|
|
||||||
// Ensure the theme matches the provided attributes and create variants
|
if (themeId) {
|
||||||
const variantRefs = await this.createVariantsBasedOnTheme(session, category.theme, colors, sizes, meterages);
|
const theme = await this.themeRepo.findById(themeId);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
// Update the category with the theme and variants
|
category.theme = new Types.ObjectId(themeId);
|
||||||
category.variants = variantRefs;
|
|
||||||
await category.save({ session });
|
|
||||||
|
|
||||||
await session.commitTransaction();
|
|
||||||
|
|
||||||
return {
|
|
||||||
message: CommonMessage.Updated,
|
|
||||||
category,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
await session.abortTransaction();
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
await session.endSession();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Updated,
|
||||||
|
category,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
//################################
|
//################################
|
||||||
async createCategoryThemeS(createCategoryThemeDto: CreateCategoryThemeDTO, catId: string) {
|
async createCategoryThemeS(createCategoryThemeDto: CreateCategoryThemeDTO, catId: string) {
|
||||||
const session = await startSession();
|
const { themeId } = createCategoryThemeDto;
|
||||||
session.startTransaction();
|
|
||||||
try {
|
|
||||||
const { theme, colors, sizes, meterages } = createCategoryThemeDto;
|
|
||||||
|
|
||||||
// Validate category ID
|
// Validate category ID
|
||||||
const category = await this.checkCategoryId(catId);
|
const category = await this.checkCategoryId(catId);
|
||||||
|
// Check if the theme already exists
|
||||||
// Check if the theme already exists
|
if (themeId) {
|
||||||
// if (category.theme) throw new BadRequestError(CategoryMessage.AlreadyExist);
|
const theme = await this.themeRepo.findById(themeId);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
// Ensure the theme matches the provided attributes and create variants
|
|
||||||
const variantRefs = await this.createVariantsBasedOnTheme(session, theme, colors, sizes, meterages);
|
|
||||||
|
|
||||||
// Update the category with the theme and variants
|
|
||||||
category.theme = theme;
|
|
||||||
category.variants = variantRefs;
|
|
||||||
await category.save({ session });
|
|
||||||
|
|
||||||
// Commit the transaction
|
|
||||||
await session.commitTransaction();
|
|
||||||
session.endSession();
|
|
||||||
|
|
||||||
return {
|
|
||||||
message: CategoryMessage.VariantCreated,
|
|
||||||
variant: category,
|
|
||||||
};
|
|
||||||
} 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the category with the theme and variants
|
||||||
|
if (themeId) {
|
||||||
|
// Cast themeId to ObjectId if necessary to satisfy category.theme type
|
||||||
|
category.theme = new Types.ObjectId(themeId);
|
||||||
|
}
|
||||||
|
await category.save();
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CategoryMessage.VariantCreated,
|
||||||
|
variant: category,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async createCategoryAttributeS(createAttributeDto: CreateCategoryAttDTO, categoryId: string) {
|
async createCategoryAttributeS(createAttributeDto: CreateCategoryAttDTO, categoryId: string) {
|
||||||
@@ -481,61 +455,6 @@ class CategoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Helper method to Create variants based on the provided theme
|
//Helper method to Create variants based on the provided theme
|
||||||
public async createVariantsBasedOnTheme(
|
|
||||||
session: ClientSession,
|
|
||||||
theme: CategoryThemeEnum,
|
|
||||||
colors?: CreateColorDTO[],
|
|
||||||
sizes?: CreateSizeDTO[],
|
|
||||||
meterages?: CreateMeterageDTO[],
|
|
||||||
): Promise<number[]> {
|
|
||||||
const variantRefs: number[] = [];
|
|
||||||
|
|
||||||
if (theme === CategoryThemeEnum.Colored) {
|
|
||||||
if (colors && colors.length > 0) {
|
|
||||||
await this.processVariants(this.colorRepo, "name", colors, session, variantRefs);
|
|
||||||
} else {
|
|
||||||
throw new BadRequestError(CategoryMessage.MissingColors);
|
|
||||||
}
|
|
||||||
} else if (theme === CategoryThemeEnum.Sized) {
|
|
||||||
if (sizes && sizes.length > 0) {
|
|
||||||
await this.processVariants(this.sizeRepo, "value", sizes, session, variantRefs);
|
|
||||||
} else {
|
|
||||||
throw new BadRequestError(CategoryMessage.MissingSizes);
|
|
||||||
}
|
|
||||||
} else if (theme === CategoryThemeEnum.Meterage) {
|
|
||||||
if (meterages && meterages.length > 0) {
|
|
||||||
await this.processVariants(this.meterageRepo, "value", meterages, session, variantRefs);
|
|
||||||
} else {
|
|
||||||
throw new BadRequestError(CategoryMessage.MissingMeterages);
|
|
||||||
}
|
|
||||||
} else if (theme === CategoryThemeEnum.No_color_No_sized) {
|
|
||||||
return [];
|
|
||||||
} else {
|
|
||||||
throw new BadRequestError(CategoryMessage.InvalidTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
return variantRefs;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic function to process create variants
|
|
||||||
private async processVariants<V extends IColor | ISize | IMeterage, T>(
|
|
||||||
repo: BaseRepository<V>,
|
|
||||||
field: keyof T,
|
|
||||||
items: T[],
|
|
||||||
session: ClientSession,
|
|
||||||
variantRefs: number[],
|
|
||||||
) {
|
|
||||||
for (const item of items) {
|
|
||||||
const query = { [field]: item[field] } as FilterQuery<V>;
|
|
||||||
const existingItem = await repo.model.exists({ ...query });
|
|
||||||
if (existingItem) {
|
|
||||||
variantRefs.push(existingItem._id);
|
|
||||||
} else {
|
|
||||||
const newItem = await repo.model.create([{ ...item }], { session });
|
|
||||||
variantRefs.push(newItem[0]._id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export { CategoryService };
|
export { CategoryService };
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
import { CategoryThemeEnum } from "../../../../common/enums/category.enum";
|
|
||||||
|
|
||||||
export interface ICategory {
|
export interface ICategory {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
title_fa: string;
|
title_fa: string;
|
||||||
@@ -9,8 +7,8 @@ export interface ICategory {
|
|||||||
icon: string;
|
icon: string;
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
description: string;
|
description: string;
|
||||||
theme: CategoryThemeEnum;
|
theme: Types.ObjectId;
|
||||||
variants: number[];
|
variants: Types.ObjectId[];
|
||||||
leaf: boolean;
|
leaf: boolean;
|
||||||
parent: Types.ObjectId;
|
parent: Types.ObjectId;
|
||||||
url: string;
|
url: string;
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
export interface IColor {
|
|
||||||
_id: number;
|
|
||||||
name: string;
|
|
||||||
hexColor: string;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export interface IMeterage {
|
|
||||||
_id: number;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export interface ISize {
|
|
||||||
_id: number;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
export interface ITheme {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
title: string;
|
||||||
|
inputType: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
export interface IThemeValue {
|
||||||
|
_id: Types.ObjectId;
|
||||||
|
theme: Types.ObjectId;
|
||||||
|
name: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import { CallbackError, Schema, model } from "mongoose";
|
import { CallbackError, Schema, model } from "mongoose";
|
||||||
|
|
||||||
import { ICategory } from "./Abstraction/ICategory";
|
import { ICategory } from "./Abstraction/ICategory";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
|
|
||||||
const categorySchema = new Schema<ICategory>(
|
const categorySchema = new Schema<ICategory>(
|
||||||
{
|
{
|
||||||
@@ -10,8 +9,8 @@ const categorySchema = new Schema<ICategory>(
|
|||||||
icon: { type: String, default: "/images/icons/default.png" },
|
icon: { type: String, default: "/images/icons/default.png" },
|
||||||
imageUrl: { type: String, required: true },
|
imageUrl: { type: String, required: true },
|
||||||
description: { type: String, required: true },
|
description: { type: String, required: true },
|
||||||
theme: { type: String, enum: CategoryThemeEnum },
|
theme: { type: Schema.Types.ObjectId, ref: "Theme" },
|
||||||
variants: [{ type: Number, refPath: "theme" }],
|
variants: [{ type: Schema.Types.ObjectId, ref: "ThemeValue" }],
|
||||||
hierarchy: [{ type: Schema.Types.ObjectId, ref: "Category" }],
|
hierarchy: [{ type: Schema.Types.ObjectId, ref: "Category" }],
|
||||||
leaf: { type: Boolean, default: true },
|
leaf: { type: Boolean, default: true },
|
||||||
parent: { type: Schema.Types.ObjectId, ref: "Category", default: null },
|
parent: { type: Schema.Types.ObjectId, ref: "Category", default: null },
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
import mongoose, { Schema, model } from "mongoose";
|
|
||||||
|
|
||||||
import { IColor } from "./Abstraction/IColor";
|
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
|
||||||
const AutoIncrement = require("mongoose-sequence")(mongoose);
|
|
||||||
|
|
||||||
const ColorSchema = new Schema<IColor>(
|
|
||||||
{
|
|
||||||
_id: Number,
|
|
||||||
name: { type: String, unique: true, required: true },
|
|
||||||
hexColor: { type: String, unique: true, required: true },
|
|
||||||
},
|
|
||||||
{ timestamps: false, _id: false, toJSON: { versionKey: false } },
|
|
||||||
);
|
|
||||||
|
|
||||||
ColorSchema.plugin(AutoIncrement, { id: "color_id", inc_field: "_id" });
|
|
||||||
const ColorModel = model<IColor>(CategoryThemeEnum.Colored, ColorSchema);
|
|
||||||
|
|
||||||
export { ColorModel };
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import mongoose, { Schema, model } from "mongoose";
|
|
||||||
|
|
||||||
import { IMeterage } from "./Abstraction/IMeterage";
|
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires
|
|
||||||
const AutoIncrement = require("mongoose-sequence")(mongoose);
|
|
||||||
|
|
||||||
const MeterageSchema = new Schema<IMeterage>(
|
|
||||||
{
|
|
||||||
_id: Number,
|
|
||||||
value: { type: String, unique: true, required: true },
|
|
||||||
},
|
|
||||||
{ timestamps: false, _id: false, toJSON: { versionKey: false } },
|
|
||||||
);
|
|
||||||
|
|
||||||
MeterageSchema.plugin(AutoIncrement, { id: "meterage_id", inc_field: "_id" });
|
|
||||||
const MeterageModel = model<IMeterage>(CategoryThemeEnum.Meterage, MeterageSchema);
|
|
||||||
|
|
||||||
export { MeterageModel };
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import mongoose, { Schema, model } from "mongoose";
|
|
||||||
|
|
||||||
import { ISize } from "./Abstraction/ISize";
|
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports
|
|
||||||
const AutoIncrement = require("mongoose-sequence")(mongoose);
|
|
||||||
|
|
||||||
const SizeSchema = new Schema<ISize>(
|
|
||||||
{
|
|
||||||
_id: Number,
|
|
||||||
value: { type: String, unique: true, required: true },
|
|
||||||
},
|
|
||||||
{ timestamps: false, _id: false, toJSON: { versionKey: false } },
|
|
||||||
);
|
|
||||||
|
|
||||||
SizeSchema.plugin(AutoIncrement, { id: "size_id", inc_field: "_id" });
|
|
||||||
const SizeModel = model<ISize>(CategoryThemeEnum.Sized, SizeSchema);
|
|
||||||
|
|
||||||
export { SizeModel };
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
import { ITheme } from "./Abstraction/ITheme";
|
||||||
|
export enum InputTypeEnum {
|
||||||
|
Text = "text",
|
||||||
|
Number = "number",
|
||||||
|
Color = "color",
|
||||||
|
}
|
||||||
|
const themeSchema = new Schema<ITheme>(
|
||||||
|
{
|
||||||
|
title: { type: String, required: true },
|
||||||
|
inputType: { type: String, enum: InputTypeEnum, required: true },
|
||||||
|
},
|
||||||
|
{ timestamps: true, toJSON: { virtuals: true, versionKey: false }, id: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
const ThemeModel = model<ITheme>("Theme", themeSchema);
|
||||||
|
export { ThemeModel };
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
|
import { IThemeValue } from "./Abstraction/IThemeValue";
|
||||||
|
|
||||||
|
const themeValueSchema = new Schema<IThemeValue>(
|
||||||
|
{
|
||||||
|
theme: { type: Schema.Types.ObjectId, ref: "Theme", required: true },
|
||||||
|
name: { type: String, required: true },
|
||||||
|
value: { type: Schema.Types.Mixed, required: true },
|
||||||
|
},
|
||||||
|
{ timestamps: true, toJSON: { virtuals: true, versionKey: false }, id: false },
|
||||||
|
);
|
||||||
|
|
||||||
|
const ThemeValueModel = model<IThemeValue>("ThemeValue", themeValueSchema);
|
||||||
|
export { ThemeValueModel };
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
import { inject, injectable } from "inversify";
|
||||||
|
import { isValidObjectId } from "mongoose";
|
||||||
|
|
||||||
|
import { ThemeRepository, ThemeValueRepository } from "./category.repository";
|
||||||
|
import { CreateThemeDTO } from "./DTO/CreateTheme.dto";
|
||||||
|
import { CreateThemeValueDTO } from "./DTO/CreateThemeValue.dto";
|
||||||
|
import { UpdateThemeDTO } from "./DTO/UpdateTheme.dto";
|
||||||
|
import { UpdateThemeValueDTO } from "./DTO/UpdateThemeValue.dto";
|
||||||
|
import { CommonMessage } from "../../common/enums/message.enum";
|
||||||
|
import { BadRequestError } from "../../core/app/app.errors";
|
||||||
|
import { IOCTYPES } from "../../IOC/ioc.types";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
class ThemeService {
|
||||||
|
@inject(IOCTYPES.ThemeRepository) private themeRepository: ThemeRepository;
|
||||||
|
@inject(IOCTYPES.ThemeValueRepository) private themeValueRepository: ThemeValueRepository;
|
||||||
|
|
||||||
|
async getAllThemes() {
|
||||||
|
return this.themeRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getThemeById(id: string) {
|
||||||
|
if (!isValidObjectId(id)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
const theme = await this.themeRepository.findById(id);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
return theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTheme(createDto: CreateThemeDTO) {
|
||||||
|
const existingTheme = await this.themeRepository.model.findOne({ title: createDto.title });
|
||||||
|
if (existingTheme) throw new BadRequestError(CommonMessage.DuplicateName);
|
||||||
|
|
||||||
|
const theme = await this.themeRepository.model.create(createDto);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Created,
|
||||||
|
theme,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateTheme(updateDto: UpdateThemeDTO) {
|
||||||
|
if (!isValidObjectId(updateDto.themeId)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
|
||||||
|
const existingTheme = await this.themeRepository.findById(updateDto.themeId);
|
||||||
|
if (!existingTheme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
|
||||||
|
const updateData: Partial<{ title: string; inputType: string }> = {};
|
||||||
|
|
||||||
|
if (updateDto.title) {
|
||||||
|
const duplicateTheme = await this.themeRepository.model.findOne({
|
||||||
|
title: updateDto.title,
|
||||||
|
_id: { $ne: updateDto.themeId },
|
||||||
|
});
|
||||||
|
if (duplicateTheme) throw new BadRequestError(CommonMessage.DuplicateName);
|
||||||
|
updateData.title = updateDto.title;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateDto.inputType) {
|
||||||
|
updateData.inputType = updateDto.inputType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedTheme = await this.themeRepository.model.findByIdAndUpdate(updateDto.themeId, updateData, { new: true });
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Updated,
|
||||||
|
theme: updatedTheme,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteTheme(id: string) {
|
||||||
|
if (!isValidObjectId(id)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
|
||||||
|
const theme = await this.themeRepository.findById(id);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
|
||||||
|
await this.themeRepository.delete(id);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Deleted,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//#########################################ThemeValue methods
|
||||||
|
async getAllThemeValues() {
|
||||||
|
return this.themeValueRepository.model.find().populate("theme");
|
||||||
|
}
|
||||||
|
|
||||||
|
async getThemeValueById(id: string) {
|
||||||
|
if (!isValidObjectId(id)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
const themeValue = await this.themeValueRepository.model.findById(id).populate("theme");
|
||||||
|
if (!themeValue) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
return themeValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getThemeValuesByThemeId(themeId: string) {
|
||||||
|
if (!isValidObjectId(themeId)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
const theme = await this.themeRepository.findById(themeId);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
return this.themeValueRepository.model.find({ theme: themeId }).populate("theme");
|
||||||
|
}
|
||||||
|
|
||||||
|
async createThemeValue(createDto: CreateThemeValueDTO) {
|
||||||
|
if (!isValidObjectId(createDto.theme)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
const theme = await this.themeRepository.findById(createDto.theme);
|
||||||
|
if (!theme) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
|
||||||
|
const themeValue = await this.themeValueRepository.model.create(createDto);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Created,
|
||||||
|
themeValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateThemeValue(updateDto: UpdateThemeValueDTO) {
|
||||||
|
if (!isValidObjectId(updateDto.themeValueId)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
|
||||||
|
const existingThemeValue = await this.themeValueRepository.findById(updateDto.themeValueId);
|
||||||
|
if (!existingThemeValue) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
|
||||||
|
const updateData: Partial<{ name: string; value: string | number }> = {};
|
||||||
|
|
||||||
|
if (updateDto.name) {
|
||||||
|
updateData.name = updateDto.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateDto.value !== undefined) {
|
||||||
|
updateData.value = updateDto.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedThemeValue = await this.themeValueRepository.model
|
||||||
|
.findByIdAndUpdate(updateDto.themeValueId, updateData, { new: true })
|
||||||
|
.populate("theme");
|
||||||
|
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Updated,
|
||||||
|
themeValue: updatedThemeValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteThemeValue(id: string) {
|
||||||
|
if (!isValidObjectId(id)) throw new BadRequestError(CommonMessage.NotValidId);
|
||||||
|
|
||||||
|
const themeValue = await this.themeValueRepository.findById(id);
|
||||||
|
if (!themeValue) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
|
|
||||||
|
await this.themeValueRepository.delete(id);
|
||||||
|
return {
|
||||||
|
message: CommonMessage.Deleted,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { ThemeService };
|
||||||
@@ -3,9 +3,7 @@ import { IsNotEmpty, IsNumber, IsOptional, Min } from "class-validator";
|
|||||||
|
|
||||||
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
import { ApiProperty } from "../../../common/decorator/swggerDocs";
|
||||||
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
import { IsValidId } from "../../../common/decorator/validation.decorator";
|
||||||
import { ColorModel } from "../../category/models/color.model";
|
import { ThemeValueModel } from "../../category/models/themeValue.model";
|
||||||
import { MeterageModel } from "../../category/models/meterage.model";
|
|
||||||
import { SizeModel } from "../../category/models/size.model";
|
|
||||||
import { WarrantyModel } from "../../warranty/models/warranty.model";
|
import { WarrantyModel } from "../../warranty/models/warranty.model";
|
||||||
// import { ShipmentModel } from "../../../models/shipment.model";
|
// import { ShipmentModel } from "../../../models/shipment.model";
|
||||||
|
|
||||||
@@ -19,23 +17,9 @@ export class AddVariantDTO {
|
|||||||
@Expose()
|
@Expose()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@IsValidId(ColorModel)
|
@IsValidId(ThemeValueModel)
|
||||||
@ApiProperty({ type: "number", description: "color id ==> one of color,size or meterage should send", example: 1 })
|
@ApiProperty({ type: "string", description: "theme value id" })
|
||||||
colorId?: number;
|
themeValueId?: string;
|
||||||
|
|
||||||
@Expose()
|
|
||||||
@IsOptional()
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsValidId(SizeModel)
|
|
||||||
@ApiProperty({ type: "number", description: "size id ==> one of color,size or meterage should send", example: 5 })
|
|
||||||
sizeId?: number;
|
|
||||||
|
|
||||||
@Expose()
|
|
||||||
@IsOptional()
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsValidId(MeterageModel)
|
|
||||||
@ApiProperty({ type: "number", description: "meterage id ==> one of color,size or meterage should send", example: 5 })
|
|
||||||
meterageId?: number;
|
|
||||||
|
|
||||||
@Expose()
|
@Expose()
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
import { CategoryThemeEnum } from "../../../../common/enums/category.enum";
|
|
||||||
import { ProductDiscountType, ProductMarketStatus } from "../../../../common/enums/product.enum";
|
import { ProductDiscountType, ProductMarketStatus } from "../../../../common/enums/product.enum";
|
||||||
|
|
||||||
// Dynamic type for category theme fields
|
// Dynamic type for category theme fields
|
||||||
type CategoryThemeFields = {
|
|
||||||
[K in Lowercase<Exclude<CategoryThemeEnum, CategoryThemeEnum.No_color_No_sized>>]?: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface IProductVariant extends CategoryThemeFields {
|
export interface IProductVariant {
|
||||||
_id: Types.ObjectId;
|
_id: Types.ObjectId;
|
||||||
product: number;
|
product: number;
|
||||||
statistics: IStatistics;
|
statistics: IStatistics;
|
||||||
@@ -25,6 +21,7 @@ export interface IProductVariant extends CategoryThemeFields {
|
|||||||
saleFormat: ISaleFormat;
|
saleFormat: ISaleFormat;
|
||||||
dimensions: IDimensions;
|
dimensions: IDimensions;
|
||||||
sellerSpecialCode: string;
|
sellerSpecialCode: string;
|
||||||
|
themeValue: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPrice {
|
export interface IPrice {
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { Schema, model } from "mongoose";
|
import { Schema, model } from "mongoose";
|
||||||
|
|
||||||
import { IDimensions, IPrice, IProductVariant, ISaleFormat, IStatistics } from "./Abstraction/IProductVariant";
|
import { IDimensions, IPrice, IProductVariant, ISaleFormat, IStatistics } from "./Abstraction/IProductVariant";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
import { ProductMarketStatus } from "../../../common/enums/product.enum";
|
import { ProductMarketStatus } from "../../../common/enums/product.enum";
|
||||||
|
|
||||||
const productStatisticsSchema = new Schema<IStatistics>(
|
const productStatisticsSchema = new Schema<IStatistics>(
|
||||||
@@ -45,24 +44,6 @@ const productPriceSchema = new Schema<IPrice>(
|
|||||||
{ _id: false },
|
{ _id: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
// Utility function to generate dynamic category theme fields
|
|
||||||
const generateCategoryThemeFields = () => {
|
|
||||||
const fields: Record<string, { type: NumberConstructor; ref: string; required: boolean }> = {};
|
|
||||||
|
|
||||||
Object.values(CategoryThemeEnum).forEach((theme) => {
|
|
||||||
if (theme !== CategoryThemeEnum.No_color_No_sized) {
|
|
||||||
const fieldName = theme.toLowerCase();
|
|
||||||
fields[fieldName] = {
|
|
||||||
type: Number,
|
|
||||||
ref: theme,
|
|
||||||
required: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
const productVariantSchema = new Schema<IProductVariant>(
|
const productVariantSchema = new Schema<IProductVariant>(
|
||||||
{
|
{
|
||||||
product: { type: Number, ref: "Product", required: true },
|
product: { type: Number, ref: "Product", required: true },
|
||||||
@@ -78,7 +59,7 @@ const productVariantSchema = new Schema<IProductVariant>(
|
|||||||
saleFormat: { type: productSaleFormat },
|
saleFormat: { type: productSaleFormat },
|
||||||
dimensions: { type: productDimensionsSchema, required: true },
|
dimensions: { type: productDimensionsSchema, required: true },
|
||||||
sellerSpecialCode: { type: String },
|
sellerSpecialCode: { type: String },
|
||||||
...generateCategoryThemeFields(),
|
themeValue: { type: Schema.Types.ObjectId, ref: "ThemeValue", required: true },
|
||||||
},
|
},
|
||||||
{ timestamps: true, toObject: { virtuals: true, versionKey: false }, toJSON: { virtuals: true, versionKey: false }, id: false },
|
{ timestamps: true, toObject: { virtuals: true, versionKey: false }, toJSON: { virtuals: true, versionKey: false }, id: false },
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import { inject, injectable } from "inversify";
|
import { inject, injectable } from "inversify";
|
||||||
import { ClientSession, FilterQuery, isValidObjectId, startSession } from "mongoose";
|
import { ClientSession, Types, isValidObjectId, startSession } from "mongoose";
|
||||||
import slugify from "slugify";
|
import slugify from "slugify";
|
||||||
|
|
||||||
import { PaginationDTO } from "../../../common/dto/pagination.dto";
|
import { PaginationDTO } from "../../../common/dto/pagination.dto";
|
||||||
import { CategoryThemeEnum } from "../../../common/enums/category.enum";
|
|
||||||
import {
|
import {
|
||||||
AdMessage,
|
AdMessage,
|
||||||
AttributeMessage,
|
AttributeMessage,
|
||||||
@@ -29,7 +28,7 @@ import { paginationUtils } from "../../../utils/pagination.utils";
|
|||||||
import { TimeService } from "../../../utils/time.service";
|
import { TimeService } from "../../../utils/time.service";
|
||||||
import { AddIncredibleOffersParamDto } from "../../admin/DTO/product-param.dto";
|
import { AddIncredibleOffersParamDto } from "../../admin/DTO/product-param.dto";
|
||||||
import { BrandDTO } from "../../brand/DTO/brand.dto";
|
import { BrandDTO } from "../../brand/DTO/brand.dto";
|
||||||
import { AttributeValueRepo, CategoryAttributeRepo, CategoryRepository } from "../../category/category.repository";
|
import { AttributeValueRepo, CategoryAttributeRepo, CategoryRepository, ThemeValueRepository } from "../../category/category.repository";
|
||||||
import { CategoryTreeDTO } from "../../category/DTO/category.dto";
|
import { CategoryTreeDTO } from "../../category/DTO/category.dto";
|
||||||
import { NotificationService } from "../../notification/notification.service";
|
import { NotificationService } from "../../notification/notification.service";
|
||||||
import { PricingRepository } from "../../pricing/pricing.repository";
|
import { PricingRepository } from "../../pricing/pricing.repository";
|
||||||
@@ -96,6 +95,7 @@ class ProductService {
|
|||||||
@inject(IOCTYPES.ShopRepo) shopeRepo: ShopRepo;
|
@inject(IOCTYPES.ShopRepo) shopeRepo: ShopRepo;
|
||||||
@inject(IOCTYPES.IncredibleOffersRepo) incredibleOffersRepo: IncredibleOffersRepo;
|
@inject(IOCTYPES.IncredibleOffersRepo) incredibleOffersRepo: IncredibleOffersRepo;
|
||||||
@inject(IOCTYPES.NotificationService) notificationService: NotificationService;
|
@inject(IOCTYPES.NotificationService) notificationService: NotificationService;
|
||||||
|
@inject(IOCTYPES.ThemeValueRepository) themeValueRepo: ThemeValueRepository;
|
||||||
|
|
||||||
//###############################################################
|
//###############################################################
|
||||||
async searchProducts(q: string) {
|
async searchProducts(q: string) {
|
||||||
@@ -557,41 +557,30 @@ class ProductService {
|
|||||||
if (!shop) throw new BadRequestError(ShopMessage.ShopNotFound);
|
if (!shop) throw new BadRequestError(ShopMessage.ShopNotFound);
|
||||||
|
|
||||||
this.ensureProductIsNotInDraft(product);
|
this.ensureProductIsNotInDraft(product);
|
||||||
const category = await this.ensureCategoryTheme(product.category.toString(), addVariantDto);
|
await this.ensureCategoryTheme(product.category.toString(), addVariantDto);
|
||||||
|
|
||||||
await this.checkVariantCount(product, category.theme);
|
// await this.checkVariantCount(product, category.theme);
|
||||||
|
|
||||||
// Check if a variant with the same colorId, meterageId, or sizeId already exists
|
// Check if a variant with the same themeValue already exists
|
||||||
// Check if a variant with the same colorId, meterageId, or sizeId already exists
|
// const query: FilterQuery<IProductVariant> = { product: product._id };
|
||||||
const query: FilterQuery<IProductVariant> = { product: product._id };
|
|
||||||
|
|
||||||
if (addVariantDto.colorId) {
|
// if (addVariantDto.themeValueId) {
|
||||||
query.color = addVariantDto.colorId;
|
// const existingVariant = await this.productVariantRepo.model.findOne({
|
||||||
}
|
// product: product._id,
|
||||||
if (addVariantDto.meterageId) {
|
// themeValue: addVariantDto.themeValueId,
|
||||||
query.meterage = addVariantDto.meterageId;
|
// });
|
||||||
}
|
|
||||||
if (addVariantDto.sizeId) {
|
|
||||||
query.size = addVariantDto.sizeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (category.toString() !== CategoryThemeEnum.No_color_No_sized) {
|
// if (existingVariant) throw new BadRequestError(ProductMessage.VariantAlreadyExists);
|
||||||
const existingVariant = await this.productVariantRepo.model.findOne(query);
|
// }
|
||||||
|
|
||||||
if (existingVariant) throw new BadRequestError(ProductMessage.VariantAlreadyExists);
|
|
||||||
}
|
|
||||||
|
|
||||||
const productVariant = await this.createProductVariant(addVariantDto, product._id, shop._id.toString(), session);
|
const productVariant = await this.createProductVariant(addVariantDto, product._id, shop._id.toString(), session);
|
||||||
|
|
||||||
await this.productRepo.model.findByIdAndUpdate(product._id, { $push: { variants: productVariant } }, { session });
|
await this.productRepo.model.findByIdAndUpdate(product._id, { $push: { variants: productVariant } }, { session });
|
||||||
// product.variants.push(productVariant[0]._id);
|
// product.variants.push(productVariant[0]._id);
|
||||||
// await product.save({ session });
|
// await product.save({ session });
|
||||||
const { colorId, sizeId, meterageId } = addVariantDto;
|
|
||||||
|
|
||||||
PriceChangeEvent.emitPriceChange({
|
PriceChangeEvent.emitPriceChange({
|
||||||
colorId,
|
themeValueId: addVariantDto.themeValueId,
|
||||||
sizeId,
|
|
||||||
meterageId,
|
|
||||||
product: productId,
|
product: productId,
|
||||||
variantId: productVariant[0]._id.toString(),
|
variantId: productVariant[0]._id.toString(),
|
||||||
shop: shop._id.toString(),
|
shop: shop._id.toString(),
|
||||||
@@ -654,9 +643,6 @@ class ProductService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
PriceChangeEvent.emitPriceChange({
|
PriceChangeEvent.emitPriceChange({
|
||||||
colorId: updatedVariant?.color,
|
|
||||||
sizeId: updatedVariant?.size,
|
|
||||||
meterageId: updatedVariant?.meterage,
|
|
||||||
product: productId,
|
product: productId,
|
||||||
variantId: updatedVariant?._id.toString() as string,
|
variantId: updatedVariant?._id.toString() as string,
|
||||||
shop: shop._id.toString(),
|
shop: shop._id.toString(),
|
||||||
@@ -1447,33 +1433,10 @@ class ProductService {
|
|||||||
throw new BadRequestError(CategoryMessage.NotValidId);
|
throw new BadRequestError(CategoryMessage.NotValidId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the category theme is color, size, or meterage
|
if (addVariantDto.themeValueId) {
|
||||||
if (category.theme === CategoryThemeEnum.Colored) {
|
const themeValue = await this.themeValueRepo.findById(addVariantDto.themeValueId);
|
||||||
if (addVariantDto.sizeId || addVariantDto.meterageId) {
|
if (!themeValue) throw new BadRequestError(CommonMessage.NotFoundById);
|
||||||
throw new BadRequestError(AttributeMessage.SizeNotAllowedForColoredTheme);
|
category.variants = [themeValue._id];
|
||||||
}
|
|
||||||
if (!addVariantDto.colorId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.ColorRequiredForColoredTheme);
|
|
||||||
}
|
|
||||||
} else if (category.theme === CategoryThemeEnum.Sized) {
|
|
||||||
if (addVariantDto.colorId || addVariantDto.meterageId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.ColorNotAllowedForSizedTheme);
|
|
||||||
}
|
|
||||||
if (!addVariantDto.sizeId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.SizeRequiredForSizedTheme);
|
|
||||||
}
|
|
||||||
} else if (category.theme === CategoryThemeEnum.Meterage) {
|
|
||||||
if (addVariantDto.colorId || addVariantDto.sizeId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.ColorOrSizeNotAllowedForMeterageTheme);
|
|
||||||
}
|
|
||||||
if (!addVariantDto.meterageId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.MeterageRequiredForMeterageTheme);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// For other themes that are neither color, size, nor meterage
|
|
||||||
if (addVariantDto.sizeId || addVariantDto.colorId || addVariantDto.meterageId) {
|
|
||||||
throw new BadRequestError(AttributeMessage.ThemeIsNoColorNoSizeNoMeterage);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return category;
|
return category;
|
||||||
@@ -1549,9 +1512,7 @@ class ProductService {
|
|||||||
shop: shopId,
|
shop: shopId,
|
||||||
warranty: addVariantDto.warrantyId,
|
warranty: addVariantDto.warrantyId,
|
||||||
// shipmentMethod: addVariantDto.shipmentsId,
|
// shipmentMethod: addVariantDto.shipmentsId,
|
||||||
color: addVariantDto.colorId,
|
themeValue: new Types.ObjectId(addVariantDto.themeValueId),
|
||||||
size: addVariantDto.sizeId,
|
|
||||||
meterage: addVariantDto.meterageId,
|
|
||||||
dimensions,
|
dimensions,
|
||||||
market_status: ProductMarketStatus.Marketable,
|
market_status: ProductMarketStatus.Marketable,
|
||||||
price: product_price,
|
price: product_price,
|
||||||
@@ -1611,16 +1572,6 @@ class ProductService {
|
|||||||
return totalCost;
|
return totalCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async checkVariantCount(product: IProduct, categoryTheme: CategoryThemeEnum) {
|
|
||||||
if (categoryTheme !== CategoryThemeEnum.No_color_No_sized) return true;
|
|
||||||
|
|
||||||
const variantCount = product.variants.length;
|
|
||||||
console.log("variantCount", variantCount);
|
|
||||||
if (!variantCount) return true;
|
|
||||||
console.log("pro", product, categoryTheme);
|
|
||||||
throw new BadRequestError(ProductMessage.ProductWithNoVariantCategoryTheme);
|
|
||||||
}
|
|
||||||
|
|
||||||
//###############################################################
|
//###############################################################
|
||||||
//###################### popular product ############################
|
//###################### popular product ############################
|
||||||
|
|
||||||
@@ -1744,6 +1695,16 @@ class ProductService {
|
|||||||
|
|
||||||
// return searchCost;
|
// return searchCost;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// private async checkVariantCount(product: IProduct, categoryTheme: Types.ObjectId | undefined) {
|
||||||
|
// if (categoryTheme) return true;
|
||||||
|
|
||||||
|
// const variantCount = product.variants.length;
|
||||||
|
// console.log("variantCount", variantCount);
|
||||||
|
// if (!variantCount) return true;
|
||||||
|
// console.log("pro", product, categoryTheme);
|
||||||
|
// throw new BadRequestError(ProductMessage.ProductWithNoVariantCategoryTheme);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
export { ProductService };
|
export { ProductService };
|
||||||
|
|||||||
+16
-2
@@ -221,8 +221,22 @@ export function setupSwagger(app: Application, rootPath: string = "") {
|
|||||||
|
|
||||||
// Setup public Swagger docs
|
// Setup public Swagger docs
|
||||||
app.use("/api-docs", basicAuth({ users: { admin: "admin" }, challenge: true }));
|
app.use("/api-docs", basicAuth({ users: { admin: "admin" }, challenge: true }));
|
||||||
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(generalSwaggerSpec));
|
app.use(
|
||||||
|
"/api-docs",
|
||||||
|
swaggerUi.serve,
|
||||||
|
swaggerUi.setup(generalSwaggerSpec, {
|
||||||
|
swaggerOptions: {
|
||||||
|
persistAuthorization: true,
|
||||||
|
defaultModelsExpandDepth: -1, // Hide schemas section
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
// Setup admin Swagger docs
|
// Setup admin Swagger docs
|
||||||
// app.use("/api-docs/admin", swaggerUi.serve, swaggerUi.setup(adminSwaggerSpec));
|
// app.use("/api-docs/admin", swaggerUi.serve, swaggerUi.setup(adminSwaggerSpec, {
|
||||||
|
// swaggerOptions: {
|
||||||
|
// persistAuthorization: true,
|
||||||
|
// defaultModelsExpandDepth: -1, // Hide schemas section
|
||||||
|
// }
|
||||||
|
// }));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user