From 80565030789f5f6e7bc4f8c75f967ff979924be9 Mon Sep 17 00:00:00 2001 From: Mahdi Date: Mon, 11 May 2026 15:30:04 +0330 Subject: [PATCH] add business owner assignment --- .../businesses/businesses.controller.ts | 11 +++++ src/modules/businesses/businesses.module.ts | 3 +- src/modules/businesses/businesses.service.ts | 44 ++++++++++++++++++- .../dto/assign-business-owner.dto.ts | 4 ++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 src/modules/businesses/dto/assign-business-owner.dto.ts diff --git a/src/modules/businesses/businesses.controller.ts b/src/modules/businesses/businesses.controller.ts index e6d52cf..3650e8e 100644 --- a/src/modules/businesses/businesses.controller.ts +++ b/src/modules/businesses/businesses.controller.ts @@ -17,6 +17,7 @@ import { Roles } from '../auth/decorators/roles.decorator'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { RolesGuard } from '../auth/guards/roles.guard'; import { BusinessesService } from './businesses.service'; +import { AssignBusinessOwnerDto } from './dto/assign-business-owner.dto'; import { CreateBusinessDto } from './dto/create-business.dto'; import { UpdateBusinessDto } from './dto/update-business.dto'; @@ -50,6 +51,16 @@ export class BusinessesController { return this.service.create(payload); } + @Post(':id/assign-owner') + @UseGuards(JwtAuthGuard, RolesGuard) + @Roles(UserRole.ADMIN) + assignOwner( + @Param('id') id: string, + @Body() payload: AssignBusinessOwnerDto, + ): Promise { + return this.service.assignOwner(id, payload); + } + @Patch(':id') @UseGuards(JwtAuthGuard, RolesGuard) @Roles(UserRole.ADMIN, UserRole.BUSINESS_OWNER) diff --git a/src/modules/businesses/businesses.module.ts b/src/modules/businesses/businesses.module.ts index 4bff12f..ae407ec 100644 --- a/src/modules/businesses/businesses.module.ts +++ b/src/modules/businesses/businesses.module.ts @@ -2,13 +2,14 @@ import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { BusinessCategoryEntity } from '../../entities/business-category.entity'; import { BusinessEntity } from '../../entities/business.entity'; +import { UserEntity } from '../../entities/user.entity'; import { AuthModule } from '../auth/auth.module'; import { BusinessesController } from './businesses.controller'; import { BusinessesService } from './businesses.service'; @Module({ imports: [ - TypeOrmModule.forFeature([BusinessEntity, BusinessCategoryEntity]), + TypeOrmModule.forFeature([BusinessEntity, BusinessCategoryEntity, UserEntity]), AuthModule, ], controllers: [BusinessesController], diff --git a/src/modules/businesses/businesses.service.ts b/src/modules/businesses/businesses.service.ts index a070503..2d4ae40 100644 --- a/src/modules/businesses/businesses.service.ts +++ b/src/modules/businesses/businesses.service.ts @@ -1,4 +1,5 @@ import { + BadRequestException, ConflictException, ForbiddenException, Injectable, @@ -8,8 +9,9 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { BusinessCategoryEntity } from '../../entities/business-category.entity'; import { BusinessEntity } from '../../entities/business.entity'; -import { UserRole } from '../../entities/user.entity'; +import { UserEntity, UserRole } from '../../entities/user.entity'; import { AuthUser } from '../auth/auth.types'; +import { AssignBusinessOwnerDto } from './dto/assign-business-owner.dto'; import { CreateBusinessDto } from './dto/create-business.dto'; import { UpdateBusinessDto } from './dto/update-business.dto'; @@ -25,6 +27,8 @@ export class BusinessesService { private readonly repo: Repository, @InjectRepository(BusinessCategoryEntity) private readonly categoryRepo: Repository, + @InjectRepository(UserEntity) + private readonly userRepo: Repository, ) {} async findAll(filters: FindAllFilters): Promise { @@ -113,6 +117,36 @@ export class BusinessesService { } } + async assignOwner( + id: string, + dto: AssignBusinessOwnerDto, + ): Promise { + const business = await this.findOne(id); + const mobile = this.normalizeMobile(dto.mobile); + + let user = await this.userRepo.findOne({ where: { mobile } }); + if (!user) { + user = this.userRepo.create({ + mobile, + fullName: dto.fullName ?? null, + role: UserRole.BUSINESS_OWNER, + isActive: true, + }); + } else { + if (user.role !== UserRole.ADMIN) { + user.role = UserRole.BUSINESS_OWNER; + } + if (dto.fullName !== undefined) { + user.fullName = dto.fullName; + } + user.isActive = true; + } + + const savedUser = await this.userRepo.save(user); + business.ownerId = savedUser.id; + return this.repo.save(business); + } + private async ensureCategoryExists(categoryId: string): Promise { const category = await this.categoryRepo.findOne({ where: { id: categoryId } }); if (!category) { @@ -120,6 +154,14 @@ export class BusinessesService { } } + private normalizeMobile(mobile: string): string { + const normalized = String(mobile ?? '').trim(); + if (!/^(\+?\d{10,15}|09\d{9})$/.test(normalized)) { + throw new BadRequestException('Invalid mobile number'); + } + return normalized; + } + private assertCanUpdateBusiness( business: BusinessEntity, payload: UpdateBusinessDto, diff --git a/src/modules/businesses/dto/assign-business-owner.dto.ts b/src/modules/businesses/dto/assign-business-owner.dto.ts new file mode 100644 index 0000000..2c16c03 --- /dev/null +++ b/src/modules/businesses/dto/assign-business-owner.dto.ts @@ -0,0 +1,4 @@ +export class AssignBusinessOwnerDto { + mobile!: string; + fullName?: string | null; +}