From ea184c643b1a54316cc31194e1e104fb828ab36d Mon Sep 17 00:00:00 2001 From: mahyargdz Date: Tue, 4 Mar 2025 12:41:27 +0330 Subject: [PATCH] chore: add update and delete for services and category and ads --- .../danak-services/DTO/update-category.dto.ts | 5 ++ .../danak-services/DTO/update-service.dto.ts | 5 ++ .../danak-services.controller.ts | 41 +++++++-- .../entities/danak-service-category.entity.ts | 7 +- .../entities/danak-service.entity.ts | 11 +-- .../providers/danak-services.service.ts | 86 +++++++++++++++++-- .../danak-services-category.repository.ts | 8 +- .../repositories/danak-services.repository.ts | 10 ++- .../payments/entities/bank-account.entity.ts | 2 +- 9 files changed, 144 insertions(+), 31 deletions(-) create mode 100644 src/modules/danak-services/DTO/update-category.dto.ts create mode 100644 src/modules/danak-services/DTO/update-service.dto.ts diff --git a/src/modules/danak-services/DTO/update-category.dto.ts b/src/modules/danak-services/DTO/update-category.dto.ts new file mode 100644 index 0000000..a6a7055 --- /dev/null +++ b/src/modules/danak-services/DTO/update-category.dto.ts @@ -0,0 +1,5 @@ +import { PartialType } from "@nestjs/swagger"; + +import { CreateCategoryDto } from "./create-category.dto"; + +export class UpdateCategoryDto extends PartialType(CreateCategoryDto) {} diff --git a/src/modules/danak-services/DTO/update-service.dto.ts b/src/modules/danak-services/DTO/update-service.dto.ts new file mode 100644 index 0000000..9b16f20 --- /dev/null +++ b/src/modules/danak-services/DTO/update-service.dto.ts @@ -0,0 +1,5 @@ +import { PartialType } from "@nestjs/swagger"; + +import { CreateServiceDto } from "./create-service.dto"; + +export class UpdateServiceDto extends PartialType(CreateServiceDto) {} diff --git a/src/modules/danak-services/danak-services.controller.ts b/src/modules/danak-services/danak-services.controller.ts index b22e29c..0b38358 100755 --- a/src/modules/danak-services/danak-services.controller.ts +++ b/src/modules/danak-services/danak-services.controller.ts @@ -1,4 +1,4 @@ -import { Body, Controller, Get, HttpCode, HttpStatus, Param, Patch, Post, Query } from "@nestjs/common"; +import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Patch, Post, Query } from "@nestjs/common"; import { ApiOperation, ApiTags } from "@nestjs/swagger"; import { AddReviewDto } from "./DTO/add-review.dto"; @@ -7,7 +7,9 @@ import { CreateCategoryDto } from "./DTO/create-category.dto"; import { CreateServiceDto } from "./DTO/create-service.dto"; import { DanakServiceReviewQueryDto } from "./DTO/danak-service-review-query.dto"; import { DanakServicesQueryDto, DanakServicesSearchQueryDto } from "./DTO/danak-services-search-query.dto"; +import { UpdateCategoryDto } from "./DTO/update-category.dto"; import { UpdateReviewStatusDto } from "./DTO/update-review-status.dto"; +import { UpdateServiceDto } from "./DTO/update-service.dto"; import { DanakServicesService } from "./providers/danak-services.service"; import { AuthGuards } from "../../common/decorators/auth-guard.decorator"; import { Pagination } from "../../common/decorators/pagination.decorator"; @@ -54,12 +56,21 @@ export class DanakServicesController { return this.danakServicesService.getCategoriesUserSide(); } - // @AuthGuards() - // @ApiOperation({ summary: "get category services with category id" }) - // @Get("categories/:id/services") - // getCategoryServices(@Param() paramDto: ParamDto) { - // return this.danakServicesService.getCategoryServices(paramDto.id); - // } + @AuthGuards() + @PermissionsDec(PermissionEnum.SERVICES) + @ApiOperation({ summary: "update category by id => admin route" }) + @Patch("categories/:id") + updateCategory(@Param() paramDto: ParamDto, @Body() updateDto: UpdateCategoryDto) { + return this.danakServicesService.updateCategory(paramDto.id, updateDto); + } + + @AuthGuards() + @PermissionsDec(PermissionEnum.SERVICES) + @ApiOperation({ summary: "delete category by id => admin route" }) + @Delete("categories/:id") + deleteCategoryById(@Param() paramDto: ParamDto) { + return this.danakServicesService.deleteCategoryById(paramDto.id); + } @AuthGuards() @PermissionsDec(PermissionEnum.SERVICES) @@ -116,6 +127,22 @@ export class DanakServicesController { return this.danakServicesService.getDanakServiceByIdWithSubs(paramDto.id, isAdmin, userId); } + @ApiOperation({ summary: "update danak service" }) + @AuthGuards() + @PermissionsDec(PermissionEnum.SERVICES) + @Patch(":id") + updateDanakService(@Param() paramDto: ParamDto, @Body() updateDto: UpdateServiceDto) { + return this.danakServicesService.updateDanakService(paramDto.id, updateDto); + } + + @ApiOperation({ summary: "delete danak service" }) + @AuthGuards() + @PermissionsDec(PermissionEnum.SERVICES) + @Delete(":id") + deleteServiceById(@Param() paramDto: ParamDto) { + return this.danakServicesService.deleteServiceById(paramDto.id); + } + @ApiOperation({ summary: "get service users" }) @AuthGuards() @PermissionsDec(PermissionEnum.SERVICES) diff --git a/src/modules/danak-services/entities/danak-service-category.entity.ts b/src/modules/danak-services/entities/danak-service-category.entity.ts index 6839c06..de0a853 100755 --- a/src/modules/danak-services/entities/danak-service-category.entity.ts +++ b/src/modules/danak-services/entities/danak-service-category.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; +import { Column, DeleteDateColumn, Entity, JoinColumn, ManyToOne, OneToMany } from "typeorm"; import { DanakService } from "./danak-service.entity"; import { BaseEntity } from "../../../common/entities/base.entity"; @@ -22,8 +22,11 @@ export class DanakServiceCategory extends BaseEntity { children: DanakServiceCategory[]; @Column({ nullable: true }) - parentId: string | null; + parentId?: string; @OneToMany(() => DanakService, (danakService) => danakService.category) danakServices: DanakService[]; + + @DeleteDateColumn() + deletedAt?: Date; } diff --git a/src/modules/danak-services/entities/danak-service.entity.ts b/src/modules/danak-services/entities/danak-service.entity.ts index 91a9f8c..539a42f 100755 --- a/src/modules/danak-services/entities/danak-service.entity.ts +++ b/src/modules/danak-services/entities/danak-service.entity.ts @@ -1,4 +1,4 @@ -import { Column, Entity, ManyToOne, OneToMany } from "typeorm"; +import { Column, DeleteDateColumn, Entity, ManyToOne, OneToMany } from "typeorm"; import { DanakServiceCategory } from "./danak-service-category.entity"; import { DanakServiceImage } from "./danak-service-image.entity"; @@ -51,12 +51,6 @@ export class DanakService extends BaseEntity { @Column({ type: "varchar", length: 255, nullable: false }) icon: string; - // @Column({ type: "int", nullable: false }) - // count: number; - - // @Column({ type: "float", nullable: false }) - // averageRating: number; - //------------------------------------- @ManyToOne(() => DanakServiceCategory, (danakServiceCategory) => danakServiceCategory.danakServices, { nullable: false, @@ -81,4 +75,7 @@ export class DanakService extends BaseEntity { @OneToMany(() => DanakServiceReview, (danakServiceReview) => danakServiceReview.service) reviews: DanakServiceReview[]; + + @DeleteDateColumn() + deletedAt?: Date; } diff --git a/src/modules/danak-services/providers/danak-services.service.ts b/src/modules/danak-services/providers/danak-services.service.ts index 12459d9..2c4e933 100755 --- a/src/modules/danak-services/providers/danak-services.service.ts +++ b/src/modules/danak-services/providers/danak-services.service.ts @@ -11,8 +11,11 @@ import { CreateCategoryDto } from "../DTO/create-category.dto"; import { CreateServiceDto } from "../DTO/create-service.dto"; import { DanakServiceReviewQueryDto } from "../DTO/danak-service-review-query.dto"; import { DanakServicesQueryDto, DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto"; +import { UpdateCategoryDto } from "../DTO/update-category.dto"; import { UpdateReviewStatusDto } from "../DTO/update-review-status.dto"; +import { UpdateServiceDto } from "../DTO/update-service.dto"; import { DanakServiceCategory } from "../entities/danak-service-category.entity"; +import { DanakServiceImage } from "../entities/danak-service-image.entity"; import { ReviewStatus } from "../enums/review-status.enum"; import { DanakServicesCategoryRepository } from "../repositories/danak-services-category.repository"; import { DanakServiceReviewRepository } from "../repositories/danak-services-review.repository"; @@ -39,6 +42,32 @@ export class DanakServicesService { }; } /******************************************** */ + + async updateCategory(categoryId: string, updateDto: UpdateCategoryDto) { + const category = await this.danakServicesCategoryRepository.findOneById(categoryId); + if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST); + + if (updateDto.title) { + const existCategory = await this.danakServicesCategoryRepository.findOneByTitle(updateDto.title, categoryId); + if (existCategory) throw new BadRequestException(CategoryMessage.TITLE_EXIST); + } + + await this.danakServicesCategoryRepository.save({ ...category, ...updateDto }); + return { + message: CommonMessage.UPDATE_SUCCESS, + }; + } + + async deleteCategoryById(categoryId: string) { + const category = await this.danakServicesCategoryRepository.findOneById(categoryId); + if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST); + // + await this.danakServicesCategoryRepository.softDelete(categoryId); + return { + message: CommonMessage.DELETED, + }; + } + /******************************************** */ async getCategories(queryDto: CategorySearchQueryDto) { const where: FindOptionsWhere = { isActive: true, @@ -64,6 +93,8 @@ export class DanakServicesService { const { limit, skip } = PaginationUtils(queryDto); const queryBuilder = this.danakServicesCategoryRepository .createQueryBuilder("category") + .where("service.deletedAt = :deletedAt", { deletedAt: IsNull() }) + // .where("category.deletedAt IS NULL") .loadRelationCountAndMap("category.servicesCount", "category.danakServices") .loadRelationCountAndMap("category.childrenCount", "category.children"); @@ -88,7 +119,7 @@ export class DanakServicesService { async getCategoriesUserSide() { const categories = await this.danakServicesCategoryRepository.find({ - where: { isActive: true }, + where: { isActive: true, deletedAt: IsNull() }, order: { createdAt: "DESC" }, }); return { @@ -99,7 +130,7 @@ export class DanakServicesService { async getCategoryServices(categoryId?: string) { const category = await this.danakServicesCategoryRepository.findOne({ - where: { id: categoryId, isActive: true, danakServices: { isActive: true } }, + where: { id: categoryId, isActive: true, deletedAt: IsNull(), danakServices: { isActive: true } }, relations: { danakServices: true, }, @@ -161,6 +192,47 @@ export class DanakServicesService { }; } /******************************************** */ + async updateDanakService(serviceId: string, updateDto: UpdateServiceDto) { + const service = await this.findServiceById(serviceId); + + let images: DanakServiceImage[] = []; + + if (updateDto.categoryId) { + const category = await this.danakServicesCategoryRepository.findOneById(updateDto.categoryId); + if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST); + service.category = category; + } + // + if (updateDto.name) { + const existService = await this.danakServicesRepository.findOneByName(updateDto.name, serviceId); + if (existService) throw new BadRequestException(ServiceMessage.NAME_EXIST); + } + // + if (updateDto.images) { + images = updateDto.images.map((image) => { + const serviceImage = new DanakServiceImage(); + serviceImage.imageUrl = image; + serviceImage.danakService = service; + return serviceImage; + }); + } + + await this.danakServicesRepository.save({ ...service, ...updateDto, images: images.length ? images : service.images }); + return { + message: CommonMessage.UPDATE_SUCCESS, + service, + }; + } + /******************************************** */ + + async deleteServiceById(serviceId: string) { + await this.findServiceById(serviceId); + await this.danakServicesRepository.softDelete(serviceId); + return { + message: CommonMessage.DELETED, + }; + } + /******************************************** */ async getServicesList(queryDto: DanakServicesSearchQueryDto) { return this.danakServicesRepository.getServicesForAdmin(queryDto); @@ -175,7 +247,7 @@ export class DanakServicesService { async getDanakSuggestServices() { const danakServices = await this.danakServicesRepository.find({ - where: { isDanakSuggest: true, isActive: true }, + where: { isDanakSuggest: true, isActive: true, deletedAt: IsNull() }, order: { createdAt: "DESC" }, }); return { @@ -187,6 +259,7 @@ export class DanakServicesService { async getDanakServiceByIdWithSubs(serviceId: string, isAdmin: boolean, userId: string) { const serviceQueryBuilder = this.danakServicesRepository .createQueryBuilder("service") + .where("service.deletedAt = :deletedAt", { deletedAt: IsNull() }) .leftJoinAndSelect("service.images", "images") .leftJoinAndSelect("service.subscriptionPlans", "subscriptionPlans") .leftJoin("service.reviews", "reviews", "reviews.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }) @@ -213,7 +286,7 @@ export class DanakServicesService { // .andWhere("r.status = :reviewStatus", { reviewStatus: ReviewStatus.APPROVED }), // "averageRating", // ) - .where("service.id = :serviceId", { serviceId }) + .andWhere("service.id = :serviceId", { serviceId }) .groupBy("service.id, images.id, subscriptionPlans.id, reviews.id, user.id"); if (!isAdmin) { @@ -314,7 +387,7 @@ export class DanakServicesService { /******************************************** */ async findServiceById(id: string) { - const service = await this.danakServicesRepository.findOneBy({ id }); + const service = await this.danakServicesRepository.findOneBy({ id, deletedAt: IsNull() }); if (!service) throw new BadRequestException(ServiceMessage.SERVICE_NOT_EXIST); return service; } @@ -322,7 +395,7 @@ export class DanakServicesService { /******************************************** */ async findServicesByIds(ids: string[]) { - const services = await this.danakServicesRepository.findBy({ id: In(ids) }); + const services = await this.danakServicesRepository.findBy({ id: In(ids), deletedAt: IsNull() }); return services; } @@ -396,6 +469,7 @@ export class DanakServicesService { const count = await this.danakServicesRepository.count({ where: { isActive: true, + deletedAt: IsNull(), }, }); diff --git a/src/modules/danak-services/repositories/danak-services-category.repository.ts b/src/modules/danak-services/repositories/danak-services-category.repository.ts index 3337db0..23c36c7 100755 --- a/src/modules/danak-services/repositories/danak-services-category.repository.ts +++ b/src/modules/danak-services/repositories/danak-services-category.repository.ts @@ -1,6 +1,6 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; -import { Repository } from "typeorm"; +import { IsNull, Not, Repository } from "typeorm"; import { DanakServiceCategory } from "../entities/danak-service-category.entity"; @@ -10,11 +10,11 @@ export class DanakServicesCategoryRepository extends Repository { - return this.findOneBy({ title }); + async findOneByTitle(title: string, id?: string): Promise { + return this.findOneBy({ title, ...(id && { id: Not(id) }), deletedAt: IsNull() }); } async findOneById(id: string): Promise { - return this.findOneBy({ id }); + return this.findOneBy({ id, deletedAt: IsNull() }); } } diff --git a/src/modules/danak-services/repositories/danak-services.repository.ts b/src/modules/danak-services/repositories/danak-services.repository.ts index eaf32b8..2325493 100755 --- a/src/modules/danak-services/repositories/danak-services.repository.ts +++ b/src/modules/danak-services/repositories/danak-services.repository.ts @@ -1,6 +1,6 @@ import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; -import { Brackets, Repository } from "typeorm"; +import { Brackets, IsNull, Not, Repository } from "typeorm"; import { PaginationUtils } from "../../utils/providers/pagination.utils"; import { DanakServicesQueryDto, DanakServicesSearchQueryDto } from "../DTO/danak-services-search-query.dto"; @@ -12,12 +12,12 @@ export class DanakServicesRepository extends Repository { super(danakServicesRepository.target, danakServicesRepository.manager, danakServicesRepository.queryRunner); } - async findOneByName(name: string): Promise { - return this.findOneBy({ name }); + async findOneByName(name: string, id?: string): Promise { + return this.findOneBy({ name, deletedAt: IsNull(), ...(id && { id: Not(id) }) }); } async findServiceById(id: string): Promise { - return this.findOneBy({ id }); + return this.findOneBy({ id, deletedAt: IsNull() }); } //+******************** async getServicesForAdmin(queryDto: DanakServicesSearchQueryDto) { @@ -27,6 +27,7 @@ export class DanakServicesRepository extends Repository { .leftJoinAndSelect("service.category", "category") .loadRelationCountAndMap("service.subscriptionCount", "service.subscriptionPlans") .orderBy("service.createdAt", "DESC") + .where("service.deletedAt = :deletedAt", { deletedAt: IsNull() }) .skip(skip) .take(limit); @@ -68,6 +69,7 @@ export class DanakServicesRepository extends Repository { .innerJoin("service.subscriptionPlans", "subscriptionPlans", "subscriptionPlans.isActive = :isActive", { isActive: true }) .leftJoinAndSelect("service.category", "category") .where("service.isActive = :isActive", { isActive: true }) + .andWhere("service.deletedAt = :deletedAt", { deletedAt: IsNull() }) .andWhere("service.isDanakSuggest = :isDanakSuggest", { isDanakSuggest: true }) .orderBy("service.createdAt", "DESC") .skip(skip) diff --git a/src/modules/payments/entities/bank-account.entity.ts b/src/modules/payments/entities/bank-account.entity.ts index 6f3329e..95cbea2 100755 --- a/src/modules/payments/entities/bank-account.entity.ts +++ b/src/modules/payments/entities/bank-account.entity.ts @@ -24,5 +24,5 @@ export class BankAccount extends BaseEntity { depositRequests: DepositRequest[]; @DeleteDateColumn() - deletedAt: Date; + deletedAt?: Date; }