Merge pull request #18 from Danakcorp/mrtz

Mrtz
This commit is contained in:
morteza-mortezai
2025-10-24 20:47:16 +03:30
committed by GitHub
6 changed files with 169 additions and 24 deletions
+4
View File
@@ -92,6 +92,7 @@ export const enum CategoryMessage {
AttAlreadyExist = "ویژگی‌های این دسته بندی قبلا ساخته شده است", AttAlreadyExist = "ویژگی‌های این دسته بندی قبلا ساخته شده است",
VariantCreated = "تنوع‌های دسته بندی با موفقیت ساخته شدند", VariantCreated = "تنوع‌های دسته بندی با موفقیت ساخته شدند",
AttributeCreated = "ویژگی‌های دسته بندی با موفقیت ساخته شدند", AttributeCreated = "ویژگی‌های دسته بندی با موفقیت ساخته شدند",
AttributeUpdated = "ویژگی‌های دسته بندی با موفقیت بروزرسانی شدند",
NotValidId = "آیدی کتگوری صحیح نمی باشد", NotValidId = "آیدی کتگوری صحیح نمی باشد",
MissingColors = "داده‌های رنگ برای تم انتخاب شده موجود نیست.", MissingColors = "داده‌های رنگ برای تم انتخاب شده موجود نیست.",
MissingSizes = "داده‌های سایز برای تم انتخاب شده موجود نیست.", MissingSizes = "داده‌های سایز برای تم انتخاب شده موجود نیست.",
@@ -105,6 +106,9 @@ export const enum CategoryMessage {
CategoryNotValidToChose = "کتگوری برای انتخاب مجاز نمی‌باشد", CategoryNotValidToChose = "کتگوری برای انتخاب مجاز نمی‌باشد",
AttributeDeleted = "ویژگی با موفقیت حذف شد", AttributeDeleted = "ویژگی با موفقیت حذف شد",
} }
export const enum CategoryAttrMessage {
NotValidId = "آیدی صحیح نمی باشد",
}
export const enum BrandMessage { export const enum BrandMessage {
NotFound = "برندی با این اسم یافت نشد", NotFound = "برندی با این اسم یافت نشد",
+4 -4
View File
@@ -6,8 +6,8 @@ import mongoose from "mongoose";
import { Logger } from "../../core/logging/logger"; import { Logger } from "../../core/logging/logger";
import { connectMongo } from "../connection"; import { connectMongo } from "../connection";
// import { backfillHierarchy } from "./backfillHierarchy"; // import { backfillHierarchy } from "./backfillHierarchy";
import { blogCategorySeeder } from "./blogCategorySeeder"; // import { blogCategorySeeder } from "./blogCategorySeeder";
import { blogSeeder } from "./blogSeeder"; // import { blogSeeder } from "./blogSeeder";
import { contractSeeder } from "./contractSeeder"; import { contractSeeder } from "./contractSeeder";
// import { seedMedia } from "./mediaSeeder"; // import { seedMedia } from "./mediaSeeder";
import { seedCityAndProvince } from "./iranCityseeder"; import { seedCityAndProvince } from "./iranCityseeder";
@@ -32,8 +32,8 @@ const seedDatabase = async () => {
logger.info("connected to mongodb"); logger.info("connected to mongodb");
await clearDatabase(logger); await clearDatabase(logger);
await backfillHierarchy(); await backfillHierarchy();
await blogCategorySeeder(logger); // await blogCategorySeeder(logger);
await blogSeeder(logger); // await blogSeeder(logger);
await contractSeeder(logger); await contractSeeder(logger);
await createDefaultAdmin(logger); await createDefaultAdmin(logger);
await seedFaqs(logger); await seedFaqs(logger);
+19 -19
View File
@@ -6,25 +6,25 @@ import { WarrantyModel } from "../../modules/warranty/models/warranty.model";
const warrantyNames = [ const warrantyNames = [
"Iran Warranty Co.", "Iran Warranty Co.",
"Pars Guarantee", // "Pars Guarantee",
"Tehran Warranty Services", // "Tehran Warranty Services",
"Safir Warranty", // "Safir Warranty",
"Farda Warranty Solutions", // "Farda Warranty Solutions",
"Aryan Protection", // "Aryan Protection",
"Mehr Warranty", // "Mehr Warranty",
"Saman Warranty Group", // "Saman Warranty Group",
"Persian Warranty Solutions", // "Persian Warranty Solutions",
"Shahab After Sales", // "Shahab After Sales",
"Payam Warranty", // "Payam Warranty",
"Kavir Protection", // "Kavir Protection",
"Tajrish Warranty", // "Tajrish Warranty",
"Sina Warranty", // "Sina Warranty",
"Atlas Warranty Services", // "Atlas Warranty Services",
"Sepahan Warranty", // "Sepahan Warranty",
"Kish Warranty Group", // "Kish Warranty Group",
"Navid Warranty Solutions", // "Navid Warranty Solutions",
"Alborz Protection Services", // "Alborz Protection Services",
"Raha Warranty Solutions", // "Raha Warranty Solutions",
]; ];
export const seedWarranty = async (logger: Logger) => { export const seedWarranty = async (logger: Logger) => {
@@ -13,6 +13,7 @@ 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 { UpdateCategoryDTO } from "../../category/DTO/UpdateCategory.dto"; import { UpdateCategoryDTO } from "../../category/DTO/UpdateCategory.dto";
import { UpdateCategoryAttDTO } from "../../category/DTO/updateCategoryAtt.dto";
import { PermissionEnum } from "../models/Abstraction/IPermission"; import { PermissionEnum } from "../models/Abstraction/IPermission";
@ApiTags("Admin Category") @ApiTags("Admin Category")
@@ -122,4 +123,15 @@ export class AdminCategoryController extends BaseController {
const data = await this.categoryService.createCategoryAttributeS(createAttributeDto, catId); const data = await this.categoryService.createCategoryAttributeS(createAttributeDto, catId);
return this.response({ data }, HttpStatus.Created); return this.response({ data }, HttpStatus.Created);
} }
@ApiOperation("update category attributes ")
@ApiResponse("successful", HttpStatus.Created)
@ApiModel(UpdateCategoryAttDTO)
@ApiAuth()
@ApiBody("the attribute type can be text|select|number|checkbox|input ")
@httpPatch("/attributes", Guard.authAdmin(), ValidationMiddleware.validateInput(UpdateCategoryAttDTO))
public async updateCategoryAttribute(@requestBody() createAttributeDto: UpdateCategoryAttDTO) {
const data = await this.categoryService.updateCategoryAttributeS(createAttributeDto);
return this.response({ data }, HttpStatus.Created);
}
} }
@@ -0,0 +1,68 @@
import { Expose, Type } from "class-transformer";
import { ArrayMinSize, IsArray, IsBoolean, IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, ValidateNested } from "class-validator";
import { ApiProperty } from "../../../common/decorator/swggerDocs";
import { IsValidId } from "../../../common/decorator/validation.decorator";
import { categoryAttType } from "../../../common/enums/category.enum";
import { CategoryAttributeModel } from "../models/CategoryAttribute.model";
class AttributeValue {
@Expose()
@IsNotEmpty()
@IsString()
@ApiProperty({ type: "string", description: "Text of the attribute value", example: "ابریشم" })
text: string;
}
export class UpdateCategoryAttDTO {
@Expose()
@IsNotEmpty()
@IsInt()
@IsValidId(CategoryAttributeModel)
@ApiProperty({ type: "number", description: "category attribute id", example: 5 })
attrId: number;
@Expose()
@IsNotEmpty()
@ApiProperty({ type: "string", description: "Title of the attribute", example: "جنس" })
title: string;
@Expose()
@IsNotEmpty()
@IsEnum(categoryAttType)
@ApiProperty({ type: "string", description: "Type of the attribute", example: "checkbox" })
type: categoryAttType;
@Expose()
@IsOptional()
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ type: "boolean", description: "if this be true then attribute can be selected many times", example: false })
multiple: boolean;
@Expose()
@IsOptional()
@IsNotEmpty()
@IsString()
@ApiProperty({ type: "string", description: "hint of the attribute", example: "نوع پارچه" })
hint: string;
@Expose()
@IsNotEmpty()
@IsBoolean()
@ApiProperty({ type: "boolean", description: "Specifies if the attribute is required", example: true })
required: boolean;
@Expose()
@IsNotEmpty()
@IsArray()
@ArrayMinSize(1)
@ValidateNested({ each: true })
@Type(() => AttributeValue)
@ApiProperty({
type: "Array",
description: "If the attribute allows multiple values (e.g., checkbox or select), provide the values here",
example: [{ text: "ابریشم" }, { text: "اسفنجی" }],
})
values: AttributeValue[];
}
+62 -1
View File
@@ -23,12 +23,13 @@ import {
UpdateCategoryVariantDTO, UpdateCategoryVariantDTO,
} from "./DTO/createCategoryTheme.dto"; } from "./DTO/createCategoryTheme.dto";
import { UpdateCategoryDTO } from "./DTO/UpdateCategory.dto"; import { UpdateCategoryDTO } from "./DTO/UpdateCategory.dto";
import { UpdateCategoryAttDTO } from "./DTO/updateCategoryAtt.dto";
import { IColor } from "./models/Abstraction/IColor"; import { IColor } from "./models/Abstraction/IColor";
import { IMeterage } from "./models/Abstraction/IMeterage"; import { IMeterage } from "./models/Abstraction/IMeterage";
import { ISize } from "./models/Abstraction/ISize"; import { ISize } from "./models/Abstraction/ISize";
import { BaseRepository } from "../../common/base/repository"; import { BaseRepository } from "../../common/base/repository";
import { CategoryThemeEnum } from "../../common/enums/category.enum"; import { CategoryThemeEnum } from "../../common/enums/category.enum";
import { 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 { ProductDTO } from "../product/DTO/product.dto"; import { ProductDTO } from "../product/DTO/product.dto";
@@ -289,6 +290,66 @@ class CategoryService {
} }
} }
async updateCategoryAttributeS(dto: UpdateCategoryAttDTO) {
const session = await startSession();
session.startTransaction();
try {
const { attrId, title, type, multiple, required, values, hint } = dto;
// Validate the existence of the category
const existCategoryAttr = await this.categoryAttRepo.findById(attrId);
if (!existCategoryAttr) {
throw new BadRequestError(CategoryAttrMessage.NotValidId);
}
// Check if attribute already exists for the category
const existAttribute = await this.categoryAttRepo.model.exists({
category: existCategoryAttr.category._id,
_id: { $ne: attrId },
title,
});
if (existAttribute) {
throw new BadRequestError(CategoryMessage.AttAlreadyExist);
}
// Create the category attribute
const updated = await this.categoryAttRepo.model.findByIdAndUpdate(
attrId,
{
category: existCategoryAttr.category._id,
title,
type,
multiple,
hint,
required,
},
{ session },
);
// delete attribute value
await this.attributeValueRepo.model.deleteMany({ attribute: attrId }, { session });
for (const value of values) {
await this.attributeValueRepo.model.create([{ text: value.text, attribute: attrId }], { session });
}
// Commit the transaction
await session.commitTransaction();
session.endSession();
return {
message: CategoryMessage.AttributeUpdated,
attribute: updated,
};
} catch (error) {
// Rollback any changes made in the transaction
await session.abortTransaction();
session.endSession();
throw error; // Re-throw the error to be handled by the calling errorHandler
}
}
async getCategoryAttributeS(catId: string) { async getCategoryAttributeS(catId: string) {
await this.checkCategoryId(catId); await this.checkCategoryId(catId);