chore: add order to the service category
This commit is contained in:
@@ -134,6 +134,10 @@ export const enum CategoryMessage {
|
|||||||
IS_ACTIVE_SHOULD_BE_1_0 = "وضعیت دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
|
IS_ACTIVE_SHOULD_BE_1_0 = "وضعیت دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
|
||||||
IS_SUGGEST_SHOULD_BE_1_0 = "وضعیت پیشنهادی بودن دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
|
IS_SUGGEST_SHOULD_BE_1_0 = "وضعیت پیشنهادی بودن دسته بندی باید یکی از مقادیر ۰ و ۱ باشد",
|
||||||
CATEGORY_NOT_EXIST_OR_HAS_NO_SERVICE = "دسته بندی مورد نظر یافت نشد یا هیچ سرویسی در این دسته بندی وجود ندارد",
|
CATEGORY_NOT_EXIST_OR_HAS_NO_SERVICE = "دسته بندی مورد نظر یافت نشد یا هیچ سرویسی در این دسته بندی وجود ندارد",
|
||||||
|
ORDER_REQUIRED = "ترتیب دسته بندی مورد نیاز است",
|
||||||
|
ORDER_SHOULD_BE_INT = "ترتیب دسته بندی باید یک عدد صحیح باشد",
|
||||||
|
CREATION_FAILED = "ایجاد دسته بندی موفیقیت آمیز نبود",
|
||||||
|
UPDATE_FAILED = "به روز رسانی دسته بندی موفیقیت آمیز نبود",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum ServiceMessage {
|
export const enum ServiceMessage {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||||
import { IsBoolean, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
|
import { IsBoolean, IsInt, IsNotEmpty, IsOptional, IsString, IsUUID, IsUrl, Length } from "class-validator";
|
||||||
|
|
||||||
import { CategoryMessage } from "../../../common/enums/message.enum";
|
import { CategoryMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
@@ -25,4 +25,9 @@ export class CreateCategoryDto {
|
|||||||
@IsUUID("4", { message: CategoryMessage.PARENT_ID_SHOULD_BE_UUID })
|
@IsUUID("4", { message: CategoryMessage.PARENT_ID_SHOULD_BE_UUID })
|
||||||
@ApiPropertyOptional({ description: "Parent category id", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" })
|
@ApiPropertyOptional({ description: "Parent category id", example: "8b1e8b1e-8b1e-8b1e-8b1e-8b1e8b1e8b1e" })
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
|
|
||||||
|
@IsNotEmpty({ message: CategoryMessage.ORDER_REQUIRED })
|
||||||
|
@IsInt({ message: CategoryMessage.ORDER_SHOULD_BE_INT })
|
||||||
|
@ApiProperty({ description: "Category order", example: 1 })
|
||||||
|
order: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ export class DanakServiceCategory extends BaseEntity {
|
|||||||
@Column({ type: "boolean", default: true })
|
@Column({ type: "boolean", default: true })
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|
||||||
|
@Column({ type: "int", default: 1 })
|
||||||
|
order: number;
|
||||||
|
|
||||||
@ManyToOne(() => DanakServiceCategory, (category) => category.children)
|
@ManyToOne(() => DanakServiceCategory, (category) => category.children)
|
||||||
@JoinColumn({ name: "parentId" })
|
@JoinColumn({ name: "parentId" })
|
||||||
parent: DanakServiceCategory;
|
parent: DanakServiceCategory;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||||
import { FindOptionsWhere, In, IsNull } from "typeorm";
|
import { DataSource, FindOptionsWhere, In, IsNull, Not, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
import { ParamDto } from "../../../common/DTO/param.dto";
|
import { ParamDto } from "../../../common/DTO/param.dto";
|
||||||
import { CategoryMessage, CommonMessage, ServiceMessage, SubscriptionMessage } from "../../../common/enums/message.enum";
|
import { CategoryMessage, CommonMessage, ServiceMessage, SubscriptionMessage } from "../../../common/enums/message.enum";
|
||||||
@@ -24,24 +24,67 @@ import { DanakServicesRepository } from "../repositories/danak-services.reposito
|
|||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class DanakServicesService {
|
export class DanakServicesService {
|
||||||
// private readonly logger = new Logger(DanakServicesService.name);
|
private readonly logger = new Logger(DanakServicesService.name);
|
||||||
constructor(
|
constructor(
|
||||||
private readonly danakServicesRepository: DanakServicesRepository,
|
private readonly danakServicesRepository: DanakServicesRepository,
|
||||||
private readonly danakServicesCategoryRepository: DanakServicesCategoryRepository,
|
private readonly danakServicesCategoryRepository: DanakServicesCategoryRepository,
|
||||||
private readonly danakServiceReviewRepository: DanakServiceReviewRepository,
|
private readonly danakServiceReviewRepository: DanakServiceReviewRepository,
|
||||||
private readonly danakServicesImageRepository: DanakServicesImageRepository,
|
private readonly danakServicesImageRepository: DanakServicesImageRepository,
|
||||||
|
private readonly dataSource: DataSource,
|
||||||
) {}
|
) {}
|
||||||
/******************************************** */
|
/******************************************** */
|
||||||
|
|
||||||
async createCategory(createDto: CreateCategoryDto) {
|
async createCategory(createDto: CreateCategoryDto) {
|
||||||
const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(createDto.title);
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
|
await queryRunner.connect();
|
||||||
const category = this.danakServicesCategoryRepository.create(createDto);
|
await queryRunner.startTransaction();
|
||||||
await this.danakServicesCategoryRepository.save(category);
|
|
||||||
return {
|
try {
|
||||||
message: CommonMessage.CREATED,
|
const existCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
|
||||||
category,
|
where: { title: createDto.title },
|
||||||
};
|
});
|
||||||
|
|
||||||
|
if (existCategory) {
|
||||||
|
throw new BadRequestException(CategoryMessage.TITLE_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
const category = queryRunner.manager.create(this.danakServicesCategoryRepository.target, createDto);
|
||||||
|
await queryRunner.manager.save(this.danakServicesCategoryRepository.target, category);
|
||||||
|
|
||||||
|
await this.handleOrderCollision(queryRunner, category);
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
|
return {
|
||||||
|
message: CommonMessage.CREATED,
|
||||||
|
category,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
this.logger.error("Error in create category", error);
|
||||||
|
throw new BadRequestException(CategoryMessage.CREATION_FAILED);
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//*********************************** */
|
||||||
|
private async handleOrderCollision(queryRunner: QueryRunner, newCategory: DanakServiceCategory): Promise<void> {
|
||||||
|
const conflictingCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
|
||||||
|
where: {
|
||||||
|
order: newCategory.order,
|
||||||
|
id: Not(newCategory.id),
|
||||||
|
deletedAt: IsNull(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (conflictingCategory) {
|
||||||
|
const highestOrderCategory = await queryRunner.manager.findOne(this.danakServicesCategoryRepository.target, {
|
||||||
|
order: { order: "DESC" },
|
||||||
|
where: { deletedAt: IsNull() },
|
||||||
|
});
|
||||||
|
|
||||||
|
const newOrder = highestOrderCategory ? highestOrderCategory.order + 1 : newCategory.order + 1;
|
||||||
|
await queryRunner.manager.update(this.danakServicesCategoryRepository.target, conflictingCategory.id, { order: newOrder });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/******************************************** */
|
/******************************************** */
|
||||||
|
|
||||||
@@ -56,20 +99,42 @@ export class DanakServicesService {
|
|||||||
/******************************************** */
|
/******************************************** */
|
||||||
|
|
||||||
async updateCategory(categoryId: string, updateDto: UpdateCategoryDto) {
|
async updateCategory(categoryId: string, updateDto: UpdateCategoryDto) {
|
||||||
const category = await this.danakServicesCategoryRepository.findOneById(categoryId);
|
const queryRunner = this.dataSource.createQueryRunner();
|
||||||
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
await queryRunner.connect();
|
||||||
|
await queryRunner.startTransaction();
|
||||||
|
|
||||||
if (updateDto.title) {
|
try {
|
||||||
const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(updateDto.title, categoryId);
|
const category = await queryRunner.manager.findOne(DanakServiceCategory, { where: { id: categoryId } });
|
||||||
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
|
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
||||||
|
|
||||||
|
if (updateDto.title) {
|
||||||
|
const existCategory = await queryRunner.manager.findOne(DanakServiceCategory, {
|
||||||
|
where: { title: updateDto.title, id: Not(categoryId) },
|
||||||
|
});
|
||||||
|
if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.manager.update(DanakServiceCategory, categoryId, updateDto);
|
||||||
|
|
||||||
|
if (updateDto.order !== undefined && updateDto.order !== category.order) {
|
||||||
|
await this.handleOrderCollision(queryRunner, { ...category, ...updateDto });
|
||||||
|
}
|
||||||
|
|
||||||
|
await queryRunner.commitTransaction();
|
||||||
|
return {
|
||||||
|
message: CommonMessage.UPDATE_SUCCESS,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
this.logger.error("Error in update category", error);
|
||||||
|
throw new BadRequestException(CategoryMessage.UPDATE_FAILED);
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.danakServicesCategoryRepository.save({ ...category, ...updateDto });
|
|
||||||
return {
|
|
||||||
message: CommonMessage.UPDATE_SUCCESS,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/******************************************** */
|
||||||
|
|
||||||
async deleteCategoryById(categoryId: string) {
|
async deleteCategoryById(categoryId: string) {
|
||||||
const category = await this.danakServicesCategoryRepository.findOneById(categoryId);
|
const category = await this.danakServicesCategoryRepository.findOneById(categoryId);
|
||||||
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
|
||||||
@@ -131,7 +196,7 @@ export class DanakServicesService {
|
|||||||
async getCategoriesUserSide() {
|
async getCategoriesUserSide() {
|
||||||
const categories = await this.danakServicesCategoryRepository.find({
|
const categories = await this.danakServicesCategoryRepository.find({
|
||||||
where: { isActive: true, deletedAt: IsNull() },
|
where: { isActive: true, deletedAt: IsNull() },
|
||||||
order: { createdAt: "DESC" },
|
order: { order: "DESC" },
|
||||||
});
|
});
|
||||||
return {
|
return {
|
||||||
categories,
|
categories,
|
||||||
|
|||||||
Reference in New Issue
Block a user