From 22d4306b2a24f5f245f148f645d2615d91aa46d2 Mon Sep 17 00:00:00 2001 From: vahidrezvani Date: Sat, 23 Aug 2025 14:16:53 +0330 Subject: [PATCH] test --- .vscode/settings.json | 3 + catalog-service/src/app/app.module.ts | 2 + .../src/app/language/language.service.ts | 2 +- .../dto/creat-shop-category-document.dto.ts | 25 ++++ .../dto/update-shop-category-document.dto.ts | 19 +++ .../shop-category-document.controller.spec.ts | 20 +++ .../shop-category-document.controller.ts | 4 + .../shop-category-document.module.ts | 16 ++ .../shop-category-document.service.spec.ts | 20 +++ .../shop-category-document.service.ts | 129 ++++++++++++++++ .../dto/create-shop-category.dto.ts | 6 +- .../app/shop-category/shop-category.module.ts | 6 +- .../shop-category/shop-category.service.ts | 139 ++++++++++++++---- .../src/schemas/shopCategory.schema.ts | 2 +- .../src/schemas/shopCategoryDocument.ts | 2 +- 15 files changed, 358 insertions(+), 37 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 catalog-service/src/app/shop-category-document/dto/creat-shop-category-document.dto.ts create mode 100644 catalog-service/src/app/shop-category-document/dto/update-shop-category-document.dto.ts create mode 100644 catalog-service/src/app/shop-category-document/shop-category-document.controller.spec.ts create mode 100644 catalog-service/src/app/shop-category-document/shop-category-document.controller.ts create mode 100644 catalog-service/src/app/shop-category-document/shop-category-document.module.ts create mode 100644 catalog-service/src/app/shop-category-document/shop-category-document.service.spec.ts create mode 100644 catalog-service/src/app/shop-category-document/shop-category-document.service.ts diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f88d7b8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "nxConsole.generateAiAgentRules": true +} \ No newline at end of file diff --git a/catalog-service/src/app/app.module.ts b/catalog-service/src/app/app.module.ts index a66dbce..b4440d8 100644 --- a/catalog-service/src/app/app.module.ts +++ b/catalog-service/src/app/app.module.ts @@ -10,6 +10,7 @@ import { AppController } from './app.controller'; import { AppService } from './app.service'; import { LanguageController } from './language/language.controller'; import { I18nextModule } from './i18next/i18next.module'; +import { ShopCategoryDocumentModule } from './shop-category-document/shop-category-document.module'; @Module({ imports: [ @@ -28,6 +29,7 @@ import { I18nextModule } from './i18next/i18next.module'; ShopCategoryModule, LanguageModule, I18nextModule, + ShopCategoryDocumentModule, ], controllers: [AppController, LanguageController], providers: [AppService], diff --git a/catalog-service/src/app/language/language.service.ts b/catalog-service/src/app/language/language.service.ts index 9cddfa9..a8f95a2 100644 --- a/catalog-service/src/app/language/language.service.ts +++ b/catalog-service/src/app/language/language.service.ts @@ -84,7 +84,7 @@ export class LanguageService { } /** Find One by ID */ - async findOneWithID(id: string, lang: string): Promise> { + async findOneWithID(id: string, lang: string): Promise> { try { const language = await this.languageModel.findOne({ ID: id }).exec(); if (!language) { diff --git a/catalog-service/src/app/shop-category-document/dto/creat-shop-category-document.dto.ts b/catalog-service/src/app/shop-category-document/dto/creat-shop-category-document.dto.ts new file mode 100644 index 0000000..1ffb48f --- /dev/null +++ b/catalog-service/src/app/shop-category-document/dto/creat-shop-category-document.dto.ts @@ -0,0 +1,25 @@ +import { IsString, IsOptional, IsNumber, Min, Max, IsNotEmpty } from 'class-validator'; +import { Types } from 'mongoose'; +import { i18nValidationMessage } from 'nestjs-i18n'; +import { IsMongoId } from 'class-validator'; + +export class CreateShopCategoryDocumentDto { + + @IsString({ message: i18nValidationMessage('validation.isString') }) + @IsNotEmpty({ message: i18nValidationMessage('validation.notEmpty') }) + Name?: string; + + + @IsString({ message: i18nValidationMessage('validation.isString') }) + @IsNotEmpty({ message: i18nValidationMessage('validation.notEmpty') }) + Description?: string; + + + @IsString({ message: i18nValidationMessage('validation.isMongoId') }) + @IsNotEmpty({ message: i18nValidationMessage('validation.notEmpty') }) + ShopCategory?:string; + + @IsString({ message: i18nValidationMessage('validation.isString') }) + @IsNotEmpty({ message: i18nValidationMessage('validation.notEmpty') }) + Language?: string +} diff --git a/catalog-service/src/app/shop-category-document/dto/update-shop-category-document.dto.ts b/catalog-service/src/app/shop-category-document/dto/update-shop-category-document.dto.ts new file mode 100644 index 0000000..d62371d --- /dev/null +++ b/catalog-service/src/app/shop-category-document/dto/update-shop-category-document.dto.ts @@ -0,0 +1,19 @@ +import { IsString, IsOptional, IsMongoId, IsNumber, Min, Max } from 'class-validator'; +import { Types } from 'mongoose'; +import { i18nValidationMessage } from 'nestjs-i18n'; + +export class UpdateShopCategoryDocumentDto { + @IsString({ message: i18nValidationMessage('validation.isString') }) + @IsOptional() + Name?: string; + + @IsString({ message: i18nValidationMessage('validation.isString') }) + @IsOptional() + Description?: string; + + @IsString({ message: i18nValidationMessage('validation.isMongoId') }) + @IsOptional() + Language?: string; + + +} diff --git a/catalog-service/src/app/shop-category-document/shop-category-document.controller.spec.ts b/catalog-service/src/app/shop-category-document/shop-category-document.controller.spec.ts new file mode 100644 index 0000000..135ab1c --- /dev/null +++ b/catalog-service/src/app/shop-category-document/shop-category-document.controller.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ShopCategoryDocumentController } from './shop-category-document.controller'; + +describe('ShopCategoryDocumentController', () => { + let controller: ShopCategoryDocumentController; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + controllers: [ShopCategoryDocumentController], + }).compile(); + + controller = module.get( + ShopCategoryDocumentController + ); + }); + + it('should be defined', () => { + expect(controller).toBeDefined(); + }); +}); diff --git a/catalog-service/src/app/shop-category-document/shop-category-document.controller.ts b/catalog-service/src/app/shop-category-document/shop-category-document.controller.ts new file mode 100644 index 0000000..98d42bd --- /dev/null +++ b/catalog-service/src/app/shop-category-document/shop-category-document.controller.ts @@ -0,0 +1,4 @@ +import { Controller } from '@nestjs/common'; + +@Controller('shop-category-document') +export class ShopCategoryDocumentController {} diff --git a/catalog-service/src/app/shop-category-document/shop-category-document.module.ts b/catalog-service/src/app/shop-category-document/shop-category-document.module.ts new file mode 100644 index 0000000..98ec049 --- /dev/null +++ b/catalog-service/src/app/shop-category-document/shop-category-document.module.ts @@ -0,0 +1,16 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { ShopCategoryDocumentService } from './shop-category-document.service'; +import { ShopCategoryDocumentController } from './shop-category-document.controller'; +import { MongooseModule } from '@nestjs/mongoose'; +import { ShopCategoryDocument, ShopCategoryDocumentSchema } from '../../schemas/shopCategoryDocument'; +import { ShopCategoryService } from '../shop-category/shop-category.service'; +import { ShopCategoryModule } from '../shop-category/shop-category.module'; +import { LanguageModule } from '../language/language.module'; + +@Module({ + imports:[MongooseModule.forFeature([{ name:ShopCategoryDocument.name, schema:ShopCategoryDocumentSchema }]), +forwardRef(() => ShopCategoryModule),LanguageModule], + providers: [ShopCategoryDocumentService], + controllers: [ShopCategoryDocumentController], +}) +export class ShopCategoryDocumentModule {} diff --git a/catalog-service/src/app/shop-category-document/shop-category-document.service.spec.ts b/catalog-service/src/app/shop-category-document/shop-category-document.service.spec.ts new file mode 100644 index 0000000..60666db --- /dev/null +++ b/catalog-service/src/app/shop-category-document/shop-category-document.service.spec.ts @@ -0,0 +1,20 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { ShopCategoryDocumentService } from './shop-category-document.service'; + +describe('ShopCategoryDocumentService', () => { + let service: ShopCategoryDocumentService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [ShopCategoryDocumentService], + }).compile(); + + service = module.get( + ShopCategoryDocumentService + ); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/catalog-service/src/app/shop-category-document/shop-category-document.service.ts b/catalog-service/src/app/shop-category-document/shop-category-document.service.ts new file mode 100644 index 0000000..434b78e --- /dev/null +++ b/catalog-service/src/app/shop-category-document/shop-category-document.service.ts @@ -0,0 +1,129 @@ +import { forwardRef, Inject, Injectable } from '@nestjs/common'; +import { InjectModel } from '@nestjs/mongoose'; +import { ShopCategoryDoc } from '../../schemas/shopCategory.schema'; +import { ShopCategoryDocument, ShopCategoryDocumentSchema } from '../../schemas/shopCategoryDocument'; +import { Model } from 'mongoose'; +import { v4 as uuidv4 } from 'uuid'; +import { I18nService } from 'nestjs-i18n'; +import { CreateShopCategoryDocumentDto } from './dto/creat-shop-category-document.dto'; +import { ApiResponse, LanguageService } from '../language/language.service'; +import i18next from 'i18next'; +import { UpdateShopCategoryDocumentDto } from './dto/update-shop-category-document.dto'; +import { ShopCategoryService } from '../shop-category/shop-category.service'; + +@Injectable() +export class ShopCategoryDocumentService { + + constructor(@InjectModel(ShopCategoryDocument.name) private shopCategoryDocumentModel: Model, + private readonly languageService: LanguageService, + @Inject(forwardRef(() => ShopCategoryService)) private readonly shopCategoryService: ShopCategoryService, + @Inject('I18NEXT') private readonly i18n: typeof i18next) { } + + async create( + createShopCategoryDocumentDto: CreateShopCategoryDocumentDto, + lang: string + ): Promise { + try { + // بررسی زبان + const language = await this.languageService.findOneWithID( + createShopCategoryDocumentDto.Language, + lang + ); + + if (!language.success) { + return { + success: false, + message: await this.i18n.t('not_found', { lng: lang, ns: 'shopCategoryDocument' }), + data: null + }; + } + + const shopCategory = await this.shopCategoryService.findOne(createShopCategoryDocumentDto.ShopCategory, lang) + if (!shopCategory.success) { + return { + success: false, + message: await this.i18n.t('not_found', { lng: lang, ns: 'shopCategoryDocument' }), + data: null + }; + } + const createdDoc = new this.shopCategoryDocumentModel({ + Name: createShopCategoryDocumentDto.Name, + Description: createShopCategoryDocumentDto.Description, + Language: language.data._id, + ID: uuidv4(), + Status: true, + Tags: [], + ShopCategory: shopCategory.data._id, + createdAt: new Date(), + updatedAt: new Date(), + }); + + const result = await createdDoc.save(); + + const message = await this.i18n.t('created', { lng: lang, ns: 'shopCategoryDocument' }); + + return { success: true, message, data: result }; + } catch (error) { + const message = await this.i18n.t('create_error', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, errors: error.message }; + } + } + async update( + id: string, + updateShopCategoryDocumentDto: UpdateShopCategoryDocumentDto, + lang: string + ): Promise { + try { + + const existingDoc = await this.shopCategoryDocumentModel.findOne({ ID: id }).exec(); + if (!existingDoc) { + const message = await this.i18n.t('not_found', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, data: null }; + } + + if (updateShopCategoryDocumentDto.Language) { + const language = await this.languageService.findOneWithID(updateShopCategoryDocumentDto.Language, 'en'); + if (!language.success) { + const message = await this.i18n.t('not_found', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, data: null }; + } + updateShopCategoryDocumentDto.Language = language.data._id; + } + + // آپدیت فیلدها + Object.assign(existingDoc, updateShopCategoryDocumentDto, { updatedAt: new Date() }); + + const updatedDoc = await existingDoc.save(); + + const message = await this.i18n.t('updated', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: true, message, data: updatedDoc }; + } catch (error) { + const message = await this.i18n.t('update_error', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, errors: error.message }; + } + } + async toggleStatus( + id: string, + lang: string + ): Promise { + try { + const existingDoc = await this.shopCategoryDocumentModel.findOne({ ID: id }).exec(); + if (!existingDoc) { + const message = await this.i18n.t('not_found', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, data: null }; + } + existingDoc.Status = !existingDoc.Status; + existingDoc.updatedAt = new Date(); + + const updatedDoc = await existingDoc.save(); + + const message = await this.i18n.t('status_toggled', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: true, message, data: updatedDoc }; + } catch (error) { + const message = await this.i18n.t('update_error', { lng: lang, ns: 'shopCategoryDocument' }); + return { success: false, message, errors: error.message }; + } + } + + +} diff --git a/catalog-service/src/app/shop-category/dto/create-shop-category.dto.ts b/catalog-service/src/app/shop-category/dto/create-shop-category.dto.ts index 0083b05..1ac2b5e 100644 --- a/catalog-service/src/app/shop-category/dto/create-shop-category.dto.ts +++ b/catalog-service/src/app/shop-category/dto/create-shop-category.dto.ts @@ -6,7 +6,7 @@ import { IsMongoId } from 'class-validator'; export class CreateShopCategoryDto { @IsString({ message: i18nValidationMessage('validation.isString') }) @IsNotEmpty({ message: i18nValidationMessage('validation.notEmpty') }) - @IsOptional() // اگر اجباری است، این را حذف کنید + @IsOptional() Name?: string; @IsString({ message: i18nValidationMessage('validation.isString') }) @@ -21,7 +21,7 @@ export class CreateShopCategoryDto { @IsOptional() ParentCategory?: Types.ObjectId; - @IsMongoId({ message: i18nValidationMessage('validation.isMongoId') }) + @IsString({ message: i18nValidationMessage('validation.isString') }) @IsOptional() - Language?: Types.ObjectId; + Language?: string } diff --git a/catalog-service/src/app/shop-category/shop-category.module.ts b/catalog-service/src/app/shop-category/shop-category.module.ts index 3e6d1ab..dd18ebd 100644 --- a/catalog-service/src/app/shop-category/shop-category.module.ts +++ b/catalog-service/src/app/shop-category/shop-category.module.ts @@ -1,12 +1,16 @@ -import { Module } from '@nestjs/common'; +import { forwardRef, Module } from '@nestjs/common'; import { ShopCategoryController } from './shop-category.controller'; import { ShopCategoryService } from './shop-category.service'; import { MongooseModule } from '@nestjs/mongoose'; import { ShopCategory, ShopCategorySchema } from '../../schemas/shopCategory.schema'; +import { LanguageModule } from '../language/language.module'; +import { ShopCategoryDocument } from '../../schemas/shopCategoryDocument'; +import { ShopCategoryDocumentModule } from '../shop-category-document/shop-category-document.module'; @Module({ imports: [ MongooseModule.forFeature([{ name: ShopCategory.name, schema: ShopCategorySchema }]), + LanguageModule,forwardRef(() => ShopCategoryDocumentModule) ], controllers: [ShopCategoryController], providers: [ShopCategoryService], diff --git a/catalog-service/src/app/shop-category/shop-category.service.ts b/catalog-service/src/app/shop-category/shop-category.service.ts index 93efd1b..f89d509 100644 --- a/catalog-service/src/app/shop-category/shop-category.service.ts +++ b/catalog-service/src/app/shop-category/shop-category.service.ts @@ -1,47 +1,126 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { forwardRef, Inject, Injectable } from '@nestjs/common'; import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; -import { ShopCategory,ShopCategoryDoc } from '../../schemas/shopCategory.schema'; +import { v4 as uuidv4 } from 'uuid'; +import { ShopCategory, ShopCategoryDoc } from '../../schemas/shopCategory.schema'; import { CreateShopCategoryDto } from './dto/create-shop-category.dto'; -import { I18n, I18nContext } from 'nestjs-i18n'; - - +import { LanguageService, ApiResponse } from '../language/language.service'; +import { ShopCategoryDocumentService } from '../shop-category-document/shop-category-document.service'; +import { I18nService } from 'nestjs-i18n'; +import i18next from 'i18next'; @Injectable() export class ShopCategoryService { constructor( @InjectModel(ShopCategory.name) private shopCategoryModel: Model, + private readonly languageService: LanguageService, + private readonly shopCategoryDocumentService: ShopCategoryDocumentService, + @Inject('I18NEXT') private readonly i18n: typeof i18next ) {} - async create(createShopCategoryDto: CreateShopCategoryDto): Promise { + async create(createShopCategoryDto: CreateShopCategoryDto, lang: string): Promise { + try { + const language = await this.languageService.findOneWithID(createShopCategoryDto.Language, lang); + if (!language.success) { + return { success: false, message: await this.i18n.t('not_found', { lng: lang, ns: 'shopCategory' }), data: null }; + } + let parent = null; + if (createShopCategoryDto.ParentCategory) { + parent = await this.shopCategoryModel.findOne({ ID: createShopCategoryDto.ParentCategory }).exec(); + if (!parent) { + return { success: false, message: await this.i18n.t('parent_not_found', { lng: lang, ns: 'shopCategory' }), data: null }; + } + } - } + const newShopCategory = new this.shopCategoryModel({ + ID: uuidv4(), + Name: createShopCategoryDto.Name, + Description: createShopCategoryDto.Description, + Icon: createShopCategoryDto.Icon, + ParentCategory: parent ? parent._id : null, + Status: true, + Document: null, + createdAt: new Date(), + updatedAt: new Date(), + Tags: [] + }); - async findAll(): Promise { - return this.shopCategoryModel.find() - .populate('Tags') - .populate('ParentCategory') - .populate('Document') - .exec(); - } + const result = await newShopCategory.save(); - async findOne(id: string): Promise { - const category = await this.shopCategoryModel.findOne({ ID: id }) - .populate('Tags') - .populate('ParentCategory') - .populate('Document') - .exec(); - if (!category) { - throw new NotFoundException(`ShopCategory with ID ${id} not found`); - } - return category; - } + const createdDocument = await this.shopCategoryDocumentService.create( + { + Name: createShopCategoryDto.Name, + Description: createShopCategoryDto.Description, + Language: createShopCategoryDto.Language, + ShopCategory: result.ID + }, + lang + ); + if (!createdDocument.success) { + return { success: false, message: createdDocument.message, data: null, errors: createdDocument.errors }; + } - async remove(id: string): Promise { - const result = await this.shopCategoryModel.deleteOne({ ID: id }).exec(); - if (result.deletedCount === 0) { - throw new NotFoundException(`ShopCategory with ID ${id} not found`); + await this.shopCategoryModel.updateOne( + { _id: result._id }, + { $set: { Document: createdDocument.data._id } } + ); + + const message = await this.i18n.t('created', { lng: lang, ns: 'shopCategory' }); + return { success: true, message, data: { ...result.toObject(), Document: createdDocument.data } }; + + } catch (error) { + const message = await this.i18n.t('create_error', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, errors: error.message }; } } -} \ No newline at end of file + + async findAll(lang: string): Promise { + try { + const categories = await this.shopCategoryModel.find() + .populate('Tags') + .populate('ParentCategory') + .populate('Document') + .exec(); + + const message = await this.i18n.t('retrieved_all', { lng: lang, ns: 'shopCategory' }); + return { success: true, message, data: categories }; + } catch (error) { + const message = await this.i18n.t('retrieve_error', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, errors: error.message }; + } + } + + async findOne(id: string, lang: string): Promise { + try { + const category = await this.shopCategoryModel.findOne({ ID: id }) + .exec(); + + if (!category) { + const message = await this.i18n.t('not_found', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, data: null }; + } + + const message = await this.i18n.t('retrieved', { lng: lang, ns: 'shopCategory' }); + return { success: true, message, data: category }; + } catch (error) { + const message = await this.i18n.t('retrieve_error', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, errors: error.message }; + } + } + + async remove(id: string, lang: string): Promise { + try { + const result = await this.shopCategoryModel.deleteOne({ ID: id }).exec(); + if (result.deletedCount === 0) { + const message = await this.i18n.t('not_found', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, data: null }; + } + const message = await this.i18n.t('deleted', { lng: lang, ns: 'shopCategory' }); + return { success: true, message, data: null }; + } catch (error) { + const message = await this.i18n.t('delete_error', { lng: lang, ns: 'shopCategory' }); + return { success: false, message, errors: error.message }; + } + } +} diff --git a/catalog-service/src/schemas/shopCategory.schema.ts b/catalog-service/src/schemas/shopCategory.schema.ts index ed23439..60348ee 100644 --- a/catalog-service/src/schemas/shopCategory.schema.ts +++ b/catalog-service/src/schemas/shopCategory.schema.ts @@ -28,7 +28,7 @@ export class ShopCategory { Document: Types.ObjectId; @Prop() - Status: string; + Status: boolean; @Prop({ type: Date, default: Date.now }) createdAt: Date; diff --git a/catalog-service/src/schemas/shopCategoryDocument.ts b/catalog-service/src/schemas/shopCategoryDocument.ts index 0f3bd90..f4a29a5 100644 --- a/catalog-service/src/schemas/shopCategoryDocument.ts +++ b/catalog-service/src/schemas/shopCategoryDocument.ts @@ -21,7 +21,7 @@ export class ShopCategoryDocument { Tags: Types.ObjectId[]; @Prop() - Status: string; + Status: boolean; @Prop({ type: Types.ObjectId, ref: 'Language' }) Language: Types.ObjectId;