chore: add company request
This commit is contained in:
@@ -548,6 +548,7 @@ export const enum CompanyMessage {
|
|||||||
ADDRESS_MUST_BE_STRING = "آدرس شرکت باید یک رشته باشد",
|
ADDRESS_MUST_BE_STRING = "آدرس شرکت باید یک رشته باشد",
|
||||||
ADDRESS_REQUIRED = "آدرس شرکت مورد نیاز است",
|
ADDRESS_REQUIRED = "آدرس شرکت مورد نیاز است",
|
||||||
CHIEF_EXECUTIVE_MUST_BE_STRING = "نام مدیرعامل باید یک رشته باشد",
|
CHIEF_EXECUTIVE_MUST_BE_STRING = "نام مدیرعامل باید یک رشته باشد",
|
||||||
|
CHIEF_EXECUTIVE_LENGTH = "نام مدیرعامل باید بین ۳ تا ۲۵۵ کاراکتر باشد",
|
||||||
CHIEF_EXECUTIVE_REQUIRED = "نام مدیرعامل مورد نیاز است",
|
CHIEF_EXECUTIVE_REQUIRED = "نام مدیرعامل مورد نیاز است",
|
||||||
COVER_IMAGE_URL_MUST_BE_URL = "آدرس تصویر کاور شرکت باید یک URL معتبر باشد",
|
COVER_IMAGE_URL_MUST_BE_URL = "آدرس تصویر کاور شرکت باید یک URL معتبر باشد",
|
||||||
COVER_IMAGE_URL_REQUIRED = "آدرس تصویر کاور شرکت مورد نیاز است",
|
COVER_IMAGE_URL_REQUIRED = "آدرس تصویر کاور شرکت مورد نیاز است",
|
||||||
@@ -574,7 +575,6 @@ export const enum CompanyMessage {
|
|||||||
WEBSITE_URL_MUST_BE_URL = "آدرس وبسایت شرکت باید یک URL معتبر باشد",
|
WEBSITE_URL_MUST_BE_URL = "آدرس وبسایت شرکت باید یک URL معتبر باشد",
|
||||||
WEBSITE_URL_REQUIRED = "آدرس وبسایت شرکت مورد نیاز است",
|
WEBSITE_URL_REQUIRED = "آدرس وبسایت شرکت مورد نیاز است",
|
||||||
NAME_LENGTH = "نام شرکت باید بین ۳ تا ۱۰۰ کاراکتر باشد",
|
NAME_LENGTH = "نام شرکت باید بین ۳ تا ۱۰۰ کاراکتر باشد",
|
||||||
CHIEF_EXECUTIVE_LENGTH = "نام مدیرعامل باید بین ۳ تا ۱۰۰ کاراکتر باشد",
|
|
||||||
COMPANY_CREATED_SUCCESSFULLY = "شرکت با موفقیت ایجاد شد",
|
COMPANY_CREATED_SUCCESSFULLY = "شرکت با موفقیت ایجاد شد",
|
||||||
COMPANY_ALREADY_EXISTS = "این شرکت قبلا ثبت شده است",
|
COMPANY_ALREADY_EXISTS = "این شرکت قبلا ثبت شده است",
|
||||||
COMPANY_ALREADY_EXISTS_NAME = "این نام شرکت قبلا ثبت شده است",
|
COMPANY_ALREADY_EXISTS_NAME = "این نام شرکت قبلا ثبت شده است",
|
||||||
@@ -600,9 +600,14 @@ export const enum CompanyMessage {
|
|||||||
SERVICES_MUST_BE_ARRAY = "خدمات باید آرایه باشد",
|
SERVICES_MUST_BE_ARRAY = "خدمات باید آرایه باشد",
|
||||||
COMPANY_ID_REQUIRED = "شرکت مورد نیاز است",
|
COMPANY_ID_REQUIRED = "شرکت مورد نیاز است",
|
||||||
COMPANY_ID_SHOULD_BE_A_UUID = "شناسه شرکت باید یک UUID معتبر باشد",
|
COMPANY_ID_SHOULD_BE_A_UUID = "شناسه شرکت باید یک UUID معتبر باشد",
|
||||||
|
COMPANY_REQUEST_STATUS_REQUIRED = "وضعیت درخواست الزامی است",
|
||||||
|
COMPANY_REQUEST_STATUS_MUST_BE_ENUM = "وضعیت درخواست باید یک عنصر از جعبه انتخابی وضعیت درخواست باشد",
|
||||||
|
COMPANY_REQUEST_ALREADY_EXISTS = "درخواست شرکت قبلا ثبت شده است",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const enum BusinessMessage {
|
export const enum BusinessMessage {
|
||||||
NOT_FOUND = "کسب و کار یافت نشد",
|
NOT_FOUND = "کسب و کار یافت نشد",
|
||||||
BUSINESS_ID_REQUIRED = "شناسه کسب و کار مورد نیاز است",
|
BUSINESS_ID_REQUIRED = "شناسه کسب و کار مورد نیاز است",
|
||||||
|
SLUG_REQUIRED = "اسلاگ مورد نیاز است",
|
||||||
|
SLUG_MUST_BE_STRING = "اسلاگ باید یک رشته باشد",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { Observable } from "rxjs";
|
|||||||
|
|
||||||
import { BusinessMessage } from "../../common/enums/message.enum";
|
import { BusinessMessage } from "../../common/enums/message.enum";
|
||||||
import { Business } from "../../modules/businesses/entities/business.entity";
|
import { Business } from "../../modules/businesses/entities/business.entity";
|
||||||
import { BusinessService } from "../../modules/businesses/services/businesses.service";
|
import { BusinessesService } from "../../modules/businesses/services/businesses.service";
|
||||||
|
|
||||||
declare module "fastify" {
|
declare module "fastify" {
|
||||||
interface FastifyRequest {
|
interface FastifyRequest {
|
||||||
@@ -25,7 +25,7 @@ export class BusinessInterceptor implements NestInterceptor {
|
|||||||
private readonly headerName = "x-business-id";
|
private readonly headerName = "x-business-id";
|
||||||
private readonly logger = new Logger(BusinessInterceptor.name);
|
private readonly logger = new Logger(BusinessInterceptor.name);
|
||||||
|
|
||||||
constructor(private readonly businessService: BusinessService) {}
|
constructor(private readonly businessesService: BusinessesService) {}
|
||||||
|
|
||||||
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
|
async intercept(context: ExecutionContext, next: CallHandler): Promise<Observable<any>> {
|
||||||
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
const request = context.switchToHttp().getRequest<FastifyRequest>();
|
||||||
@@ -34,7 +34,7 @@ export class BusinessInterceptor implements NestInterceptor {
|
|||||||
|
|
||||||
if (businessId) {
|
if (businessId) {
|
||||||
try {
|
try {
|
||||||
const business = await this.businessService.getBusinessByDanakSubscriptionId(businessId);
|
const business = await this.businessesService.getBusinessByDanakSubscriptionId(businessId);
|
||||||
|
|
||||||
request.business = business;
|
request.business = business;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Body, Controller, HttpCode, HttpStatus, Patch, Post, UseGuards } from "@nestjs/common";
|
import { Body, Controller, HttpCode, HttpStatus, Patch, Post, UseGuards, UseInterceptors } from "@nestjs/common";
|
||||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||||
import { Throttle, ThrottlerGuard } from "@nestjs/throttler";
|
import { Throttle, ThrottlerGuard } from "@nestjs/throttler";
|
||||||
|
|
||||||
@@ -11,54 +11,58 @@ import { VerifyOtpDto } from "./DTO/verify-otp.dto";
|
|||||||
import { AuthService } from "./providers/auth.service";
|
import { AuthService } from "./providers/auth.service";
|
||||||
import { AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL, AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL } from "../../common/constants";
|
import { AUTH_THROTTLE_LIMIT, AUTH_THROTTLE_TTL, AUTH__REFRESH_THROTTLE_LIMIT, AUTH__REFRESH_THROTTLE_TTL } from "../../common/constants";
|
||||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||||
|
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||||
import { UserDec } from "../../common/decorators/user.decorator";
|
import { UserDec } from "../../common/decorators/user.decorator";
|
||||||
|
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||||
|
import { Business } from "../businesses/entities/business.entity";
|
||||||
|
|
||||||
@ApiTags("Auth")
|
@ApiTags("Auth")
|
||||||
@Controller("auth")
|
@Controller("auth")
|
||||||
@Throttle({ default: { limit: AUTH_THROTTLE_LIMIT, ttl: AUTH_THROTTLE_TTL } })
|
@Throttle({ default: { limit: AUTH_THROTTLE_LIMIT, ttl: AUTH_THROTTLE_TTL } })
|
||||||
@UseGuards(ThrottlerGuard)
|
@UseGuards(ThrottlerGuard)
|
||||||
|
@UseInterceptors(BusinessInterceptor)
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
constructor(private readonly authService: AuthService) {}
|
constructor(private readonly authService: AuthService) {}
|
||||||
|
|
||||||
@ApiOperation({ summary: "Initiate registration" })
|
@ApiOperation({ summary: "Initiate registration" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("register/initiate")
|
@Post("register/initiate")
|
||||||
register(@Body() registerDto: RequestOtpDto) {
|
register(@Body() registerDto: RequestOtpDto, @BusinessDec("id") businessId: string) {
|
||||||
return this.authService.initiateRegistration(registerDto);
|
return this.authService.initiateRegistration(registerDto, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "complete registration ==> step 2" })
|
@ApiOperation({ summary: "complete registration ==> step 2" })
|
||||||
@Post("register/complete")
|
@Post("register/complete")
|
||||||
completeRegistration(@Body() completeRegistrationDto: CompleteRegistrationDto) {
|
completeRegistration(@Body() completeRegistrationDto: CompleteRegistrationDto, @BusinessDec() business: Business) {
|
||||||
return this.authService.completeRegistration(completeRegistrationDto);
|
return this.authService.completeRegistration(completeRegistrationDto, business);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "request to login with otp" })
|
@ApiOperation({ summary: "request to login with otp" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("otp/send")
|
@Post("otp/send")
|
||||||
sendOtp(@Body() requestOtpDto: RequestOtpDto) {
|
sendOtp(@Body() requestOtpDto: RequestOtpDto, @BusinessDec("id") businessId: string) {
|
||||||
return this.authService.requestLoginOtp(requestOtpDto);
|
return this.authService.requestLoginOtp(requestOtpDto, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "verify otp for login" })
|
@ApiOperation({ summary: "verify otp for login" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("otp/verify")
|
@Post("otp/verify")
|
||||||
verifyOtp(@Body() verifyOtpDto: VerifyOtpDto) {
|
verifyOtp(@Body() verifyOtpDto: VerifyOtpDto, @BusinessDec("id") businessId: string) {
|
||||||
return this.authService.verifyLoginOtp(verifyOtpDto);
|
return this.authService.verifyLoginOtp(verifyOtpDto, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "check if user email exist" })
|
@ApiOperation({ summary: "check if user email exist" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("check")
|
@Post("check")
|
||||||
checkUserExist(@Body() checkUserExistDto: CheckUserExistDto) {
|
checkUserExist(@Body() checkUserExistDto: CheckUserExistDto, @BusinessDec("id") businessId: string) {
|
||||||
return this.authService.checkUserExist(checkUserExistDto);
|
return this.authService.checkUserExist(checkUserExistDto, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({ summary: "login with password" })
|
@ApiOperation({ summary: "login with password" })
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("login/password")
|
@Post("login/password")
|
||||||
loginWithPassword(@Body() loginPasswordDto: LoginPasswordDTO) {
|
loginWithPassword(@Body() loginPasswordDto: LoginPasswordDTO, @BusinessDec("id") businessId: string) {
|
||||||
return this.authService.loginWithPassword(loginPasswordDto);
|
return this.authService.loginWithPassword(loginPasswordDto, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import { NotificationModule } from "../notifications/notifications.module";
|
|||||||
import { UsersModule } from "../users/users.module";
|
import { UsersModule } from "../users/users.module";
|
||||||
import { ConsoleJwtStrategy } from "./strategies/console-jwt.strategy";
|
import { ConsoleJwtStrategy } from "./strategies/console-jwt.strategy";
|
||||||
import { LocalJwtStrategy } from "./strategies/local-jwt.strategy";
|
import { LocalJwtStrategy } from "./strategies/local-jwt.strategy";
|
||||||
|
import { BusinessesModule } from "../businesses/businesses.module";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [UtilsModule, UsersModule, PassportModule, JwtModule.registerAsync(jwtConfig()), NotificationModule],
|
imports: [UtilsModule, UsersModule, PassportModule, JwtModule.registerAsync(jwtConfig()), NotificationModule, BusinessesModule],
|
||||||
controllers: [AuthController],
|
controllers: [AuthController],
|
||||||
providers: [AuthService, TokensService, LocalJwtStrategy, ConsoleJwtStrategy],
|
providers: [AuthService, TokensService, LocalJwtStrategy, ConsoleJwtStrategy],
|
||||||
exports: [AuthService],
|
exports: [AuthService],
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { BadRequestException, Injectable } from "@nestjs/common";
|
|||||||
|
|
||||||
import { TokensService } from "./tokens.service";
|
import { TokensService } from "./tokens.service";
|
||||||
import { AuthMessage, UserMessage } from "../../../common/enums/message.enum";
|
import { AuthMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
import { NotificationQueue } from "../../notifications/queue/notification.queue";
|
import { NotificationQueue } from "../../notifications/queue/notification.queue";
|
||||||
import { Role } from "../../users/entities/role.entity";
|
import { Role } from "../../users/entities/role.entity";
|
||||||
import { RoleEnum } from "../../users/enums/role.enum";
|
import { RoleEnum } from "../../users/enums/role.enum";
|
||||||
@@ -15,7 +16,6 @@ import { CompleteRegistrationDto } from "../DTO/complete-register.dto";
|
|||||||
import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto";
|
import { CheckUserExistDto, LoginPasswordDTO } from "../DTO/loginPassword.dto";
|
||||||
import { RequestOtpDto } from "../DTO/request-otp.dto";
|
import { RequestOtpDto } from "../DTO/request-otp.dto";
|
||||||
import { VerifyOtpDto } from "../DTO/verify-otp.dto";
|
import { VerifyOtpDto } from "../DTO/verify-otp.dto";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -29,9 +29,9 @@ export class AuthService {
|
|||||||
) {}
|
) {}
|
||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
async initiateRegistration(requestOtpDto: RequestOtpDto) {
|
async initiateRegistration(requestOtpDto: RequestOtpDto, businessId: string) {
|
||||||
const { phone } = requestOtpDto;
|
const { phone } = requestOtpDto;
|
||||||
const existUser = await this.usersService.findOneWithPhone(phone);
|
const existUser = await this.usersService.findOneWithPhone(phone, businessId);
|
||||||
if (existUser) throw new BadRequestException(AuthMessage.PHONE_EXISTS);
|
if (existUser) throw new BadRequestException(AuthMessage.PHONE_EXISTS);
|
||||||
|
|
||||||
const existCode = await this.otpService.checkExistOtp(phone, "REGISTER");
|
const existCode = await this.otpService.checkExistOtp(phone, "REGISTER");
|
||||||
@@ -52,7 +52,7 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
async completeRegistration(completeRegistrationDto: CompleteRegistrationDto) {
|
async completeRegistration(completeRegistrationDto: CompleteRegistrationDto, business: Business) {
|
||||||
const { phone, code } = completeRegistrationDto;
|
const { phone, code } = completeRegistrationDto;
|
||||||
|
|
||||||
const entityManager = this.em.fork();
|
const entityManager = this.em.fork();
|
||||||
@@ -67,7 +67,7 @@ export class AuthService {
|
|||||||
await this.otpService.delOtpFormCache(phone, "REGISTER");
|
await this.otpService.delOtpFormCache(phone, "REGISTER");
|
||||||
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
|
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
|
||||||
|
|
||||||
const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword, entityManager);
|
const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword, business, entityManager);
|
||||||
|
|
||||||
const tokens = await this.tokensService.generateTokens(user, entityManager);
|
const tokens = await this.tokensService.generateTokens(user, entityManager);
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ export class AuthService {
|
|||||||
}
|
}
|
||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
async loginWithPassword(loginDto: LoginPasswordDTO) {
|
async loginWithPassword(loginDto: LoginPasswordDTO, businessId: string) {
|
||||||
const { email, password } = loginDto;
|
const { email, password } = loginDto;
|
||||||
|
|
||||||
const user = await this.checkUserLoginCredentialWithEmail(email, password);
|
const user = await this.checkUserLoginCredentialWithEmail(email, password, businessId);
|
||||||
|
|
||||||
if (this.checkUserIsAdmin(user.role)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
|
if (this.checkUserIsAdmin(user.role)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
|
||||||
|
|
||||||
@@ -104,8 +104,8 @@ export class AuthService {
|
|||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
async checkUserExist(checkUserExistDto: CheckUserExistDto) {
|
async checkUserExist(checkUserExistDto: CheckUserExistDto, businessId: string) {
|
||||||
const user = await this.usersService.findOneWithEmail(checkUserExistDto.email);
|
const user = await this.usersService.findOneWithEmail(checkUserExistDto.email, businessId);
|
||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
return { message: UserMessage.USER_EXISTS };
|
return { message: UserMessage.USER_EXISTS };
|
||||||
}
|
}
|
||||||
@@ -113,9 +113,9 @@ export class AuthService {
|
|||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
async requestLoginOtp(requestOtpDto: RequestOtpDto, isAdmin: boolean = false) {
|
async requestLoginOtp(requestOtpDto: RequestOtpDto, businessId: string, isAdmin: boolean = false) {
|
||||||
const { phone } = requestOtpDto;
|
const { phone } = requestOtpDto;
|
||||||
const user = await this.usersService.findOneWithPhone(phone);
|
const user = await this.usersService.findOneWithPhone(phone, businessId);
|
||||||
if (!user) throw new BadRequestException(AuthMessage.PHONE_NOT_FOUND);
|
if (!user) throw new BadRequestException(AuthMessage.PHONE_NOT_FOUND);
|
||||||
|
|
||||||
//check the if the method call is from admin or not
|
//check the if the method call is from admin or not
|
||||||
@@ -144,10 +144,10 @@ export class AuthService {
|
|||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
async verifyLoginOtp(verifyOtpDto: VerifyOtpDto) {
|
async verifyLoginOtp(verifyOtpDto: VerifyOtpDto, businessId: string) {
|
||||||
const { code, phone } = verifyOtpDto;
|
const { code, phone } = verifyOtpDto;
|
||||||
|
|
||||||
const user = await this.checkUserLoginCredentialWithPhone(phone, code);
|
const user = await this.checkUserLoginCredentialWithPhone(phone, code, businessId);
|
||||||
|
|
||||||
if (this.checkUserIsAdmin(user.role)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
|
if (this.checkUserIsAdmin(user.role)) throw new BadRequestException(AuthMessage.ADMIN_CAN_NOT_LOGIN);
|
||||||
|
|
||||||
@@ -193,8 +193,8 @@ export class AuthService {
|
|||||||
|
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
private async checkUserLoginCredentialWithEmail(email: string, password: string) {
|
private async checkUserLoginCredentialWithEmail(email: string, password: string, businessId: string) {
|
||||||
const user = await this.usersService.findOneWithEmail(email);
|
const user = await this.usersService.findOneWithEmail(email, businessId);
|
||||||
if (!user) throw new BadRequestException(AuthMessage.INVALID_PASSWORD);
|
if (!user) throw new BadRequestException(AuthMessage.INVALID_PASSWORD);
|
||||||
|
|
||||||
const passCompare = await this.passwordService.comparePassword(password, user.password);
|
const passCompare = await this.passwordService.comparePassword(password, user.password);
|
||||||
@@ -205,13 +205,13 @@ export class AuthService {
|
|||||||
//****************** */
|
//****************** */
|
||||||
//****************** */
|
//****************** */
|
||||||
|
|
||||||
private async checkUserLoginCredentialWithPhone(phone: string, otpCode: string) {
|
private async checkUserLoginCredentialWithPhone(phone: string, otpCode: string, businessId: string) {
|
||||||
const isValid = await this.otpService.verifyOtp(phone, otpCode, "LOGIN");
|
const isValid = await this.otpService.verifyOtp(phone, otpCode, "LOGIN");
|
||||||
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
||||||
|
|
||||||
await this.otpService.delOtpFormCache(phone, "LOGIN");
|
await this.otpService.delOtpFormCache(phone, "LOGIN");
|
||||||
|
|
||||||
const user = await this.usersService.findOneWithPhone(phone);
|
const user = await this.usersService.findOneWithPhone(phone, businessId);
|
||||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsNotEmpty, IsString } from "class-validator";
|
||||||
|
|
||||||
|
import { BusinessMessage } from "../../../common/enums/message.enum";
|
||||||
|
|
||||||
|
export class BusinessSlugParamDto {
|
||||||
|
@IsNotEmpty({ message: BusinessMessage.SLUG_REQUIRED })
|
||||||
|
@IsString({ message: BusinessMessage.SLUG_MUST_BE_STRING })
|
||||||
|
@ApiProperty({ description: "The slug of the business", example: "example-business" })
|
||||||
|
slug: string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Controller, Get, Param } from "@nestjs/common";
|
||||||
|
|
||||||
|
import { BusinessSlugParamDto } from "./DTO/business-slug-param.dto";
|
||||||
|
import { BusinessesService } from "./services/businesses.service";
|
||||||
|
|
||||||
|
@Controller("business")
|
||||||
|
export class BusinessesController {
|
||||||
|
constructor(private readonly businessesService: BusinessesService) {}
|
||||||
|
|
||||||
|
@Get("slug/:slug")
|
||||||
|
async getBusinessBySlug(@Param() params: BusinessSlugParamDto) {
|
||||||
|
return this.businessesService.getBusinessBySlug(params.slug);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,10 +2,11 @@ import { MikroOrmModule } from "@mikro-orm/nestjs";
|
|||||||
import { BullModule } from "@nestjs/bullmq";
|
import { BullModule } from "@nestjs/bullmq";
|
||||||
import { Module } from "@nestjs/common";
|
import { Module } from "@nestjs/common";
|
||||||
|
|
||||||
|
import { BusinessesController } from "./businesses.controller";
|
||||||
import { SUBSCRIPTIONS } from "./constant";
|
import { SUBSCRIPTIONS } from "./constant";
|
||||||
import { Business } from "./entities/business.entity";
|
import { Business } from "./entities/business.entity";
|
||||||
import { BusinessProvisioningProcessor } from "./queue/business-provisioning.processor";
|
import { BusinessProvisioningProcessor } from "./queue/business-provisioning.processor";
|
||||||
import { BusinessService } from "./services/businesses.service";
|
import { BusinessesService } from "./services/businesses.service";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -15,7 +16,8 @@ import { BusinessService } from "./services/businesses.service";
|
|||||||
prefix: SUBSCRIPTIONS.PROVISIONING_QUEUE_PREFIX,
|
prefix: SUBSCRIPTIONS.PROVISIONING_QUEUE_PREFIX,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
providers: [BusinessService, BusinessProvisioningProcessor],
|
providers: [BusinessesService, BusinessProvisioningProcessor],
|
||||||
exports: [BusinessService],
|
exports: [BusinessesService],
|
||||||
|
controllers: [BusinessesController],
|
||||||
})
|
})
|
||||||
export class BusinessesModule {}
|
export class BusinessesModule {}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { Industry } from "../../industries/entities/industry.entity";
|
|||||||
import { Invoice } from "../../invoices/entities/invoice.entity";
|
import { Invoice } from "../../invoices/entities/invoice.entity";
|
||||||
import { TicketCategory } from "../../tickets/entities/ticket-category.entity";
|
import { TicketCategory } from "../../tickets/entities/ticket-category.entity";
|
||||||
import { Ticket } from "../../tickets/entities/ticket.entity";
|
import { Ticket } from "../../tickets/entities/ticket.entity";
|
||||||
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { BusinessRepository } from "../repositories/business.repository";
|
import { BusinessRepository } from "../repositories/business.repository";
|
||||||
|
|
||||||
@Entity({ repository: () => BusinessRepository })
|
@Entity({ repository: () => BusinessRepository })
|
||||||
@@ -19,9 +20,17 @@ export class Business extends BaseEntity {
|
|||||||
@Property({ type: "varchar", length: 255, nullable: false })
|
@Property({ type: "varchar", length: 255, nullable: false })
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, nullable: false })
|
||||||
|
slug!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, nullable: true })
|
||||||
|
domain?: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 255, nullable: true })
|
@Property({ type: "varchar", length: 255, nullable: true })
|
||||||
logoUrl?: string;
|
logoUrl?: string;
|
||||||
|
|
||||||
|
//=========================
|
||||||
|
|
||||||
@OneToMany(() => Company, (company) => company.business, { cascade: [Cascade.ALL] })
|
@OneToMany(() => Company, (company) => company.business, { cascade: [Cascade.ALL] })
|
||||||
companies = new Collection<Company>(this);
|
companies = new Collection<Company>(this);
|
||||||
|
|
||||||
@@ -43,5 +52,8 @@ export class Business extends BaseEntity {
|
|||||||
@OneToMany(() => Criticism, (criticism) => criticism.business)
|
@OneToMany(() => Criticism, (criticism) => criticism.business)
|
||||||
criticisms = new Collection<Criticism>(this);
|
criticisms = new Collection<Criticism>(this);
|
||||||
|
|
||||||
|
@OneToMany(() => User, (user) => user.business)
|
||||||
|
users = new Collection<User>(this);
|
||||||
|
|
||||||
[EntityRepositoryType]?: BusinessRepository;
|
[EntityRepositoryType]?: BusinessRepository;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export class BusinessProvisioningProcessor extends WorkerProcessor {
|
|||||||
|
|
||||||
private async handleBusinessCreated(job: Job<IBusinessProvisioningJob>) {
|
private async handleBusinessCreated(job: Job<IBusinessProvisioningJob>) {
|
||||||
const em = this.em.fork();
|
const em = this.em.fork();
|
||||||
const { subscriptionId, serviceId, serviceName, businessName } = job.data;
|
const { subscriptionId, serviceId, serviceName, businessName, slug } = job.data;
|
||||||
|
|
||||||
// Only act if the event is for this service
|
// Only act if the event is for this service
|
||||||
if (serviceId !== SUBSCRIPTIONS.SERVICE_ID) {
|
if (serviceId !== SUBSCRIPTIONS.SERVICE_ID) {
|
||||||
@@ -43,7 +43,7 @@ export class BusinessProvisioningProcessor extends WorkerProcessor {
|
|||||||
business = em.create(Business, {
|
business = em.create(Business, {
|
||||||
danakSubscriptionId: subscriptionId,
|
danakSubscriptionId: subscriptionId,
|
||||||
name: businessName,
|
name: businessName,
|
||||||
// logoUrl: job.data.logoUrl, // Uncomment if logoUrl is provided in job data
|
slug: slug,
|
||||||
});
|
});
|
||||||
await em.persistAndFlush(business);
|
await em.persistAndFlush(business);
|
||||||
this.logger.log(`Created business for subscription ${subscriptionId}`);
|
this.logger.log(`Created business for subscription ${subscriptionId}`);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { BusinessMessage } from "../../../common/enums/message.enum";
|
|||||||
import { BusinessRepository } from "../repositories/business.repository";
|
import { BusinessRepository } from "../repositories/business.repository";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BusinessService {
|
export class BusinessesService {
|
||||||
constructor(private readonly businessRepository: BusinessRepository) {}
|
constructor(private readonly businessRepository: BusinessRepository) {}
|
||||||
|
|
||||||
async getBusinessByDanakSubscriptionId(danakSubscriptionId: string) {
|
async getBusinessByDanakSubscriptionId(danakSubscriptionId: string) {
|
||||||
@@ -13,4 +13,11 @@ export class BusinessService {
|
|||||||
|
|
||||||
return business;
|
return business;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getBusinessBySlug(slug: string) {
|
||||||
|
const business = await this.businessRepository.findOne({ slug, deletedAt: null });
|
||||||
|
if (!business) throw new BadRequestException(BusinessMessage.NOT_FOUND);
|
||||||
|
|
||||||
|
return { business };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,3 +38,10 @@ export class CompanyListQueryDto extends PaginationDto {
|
|||||||
@ApiPropertyOptional({ description: "تاریخ ثبت", example: "2021-01-01" })
|
@ApiPropertyOptional({ description: "تاریخ ثبت", example: "2021-01-01" })
|
||||||
registrationDate?: string;
|
registrationDate?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CompanyListPublicQueryDto {
|
||||||
|
@IsOptional()
|
||||||
|
@IsString({ message: CompanyMessage.INDUSTRY_ID_SHOULD_BE_UUID })
|
||||||
|
@ApiPropertyOptional({ description: "شناسه صنعت" })
|
||||||
|
industryId?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsDateString,
|
IsDateString,
|
||||||
IsEmail,
|
IsEmail,
|
||||||
|
IsEnum,
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
@@ -19,6 +20,7 @@ import { CreateCompanyProductDto } from "./create-company-product.dto";
|
|||||||
import { CreateCompanyServiceDto } from "./create-company-service.dto";
|
import { CreateCompanyServiceDto } from "./create-company-service.dto";
|
||||||
import { CompanyMessage } from "../../../common/enums/message.enum";
|
import { CompanyMessage } from "../../../common/enums/message.enum";
|
||||||
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
||||||
|
import { CompanyRequestStatus } from "../enums/company-request-status.enum";
|
||||||
|
|
||||||
export class CreateCompanyDto extends PickType(CompleteRegistrationDto, ["phone", "firstName", "lastName", "password", "nationalCode"]) {
|
export class CreateCompanyDto extends PickType(CompleteRegistrationDto, ["phone", "firstName", "lastName", "password", "nationalCode"]) {
|
||||||
@IsNotEmpty({ message: CompanyMessage.NAME_REQUIRED })
|
@IsNotEmpty({ message: CompanyMessage.NAME_REQUIRED })
|
||||||
@@ -99,3 +101,36 @@ export class CreateCompanyDto extends PickType(CompleteRegistrationDto, ["phone"
|
|||||||
@ApiProperty({ description: "خدمات شرکت", type: [CreateCompanyServiceDto], required: false })
|
@ApiProperty({ description: "خدمات شرکت", type: [CreateCompanyServiceDto], required: false })
|
||||||
services: CreateCompanyServiceDto[];
|
services: CreateCompanyServiceDto[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class CreateCompanyRequestDto extends PickType(CreateCompanyDto, [
|
||||||
|
"name",
|
||||||
|
"email",
|
||||||
|
"phone",
|
||||||
|
"identificationNumber",
|
||||||
|
"dateOfEstablishment",
|
||||||
|
"address",
|
||||||
|
"mapAddressLink",
|
||||||
|
"description",
|
||||||
|
"websiteUrl",
|
||||||
|
"profileImageUrl",
|
||||||
|
"coverImageUrl",
|
||||||
|
"industryId",
|
||||||
|
"products",
|
||||||
|
"services",
|
||||||
|
]) {
|
||||||
|
@IsNotEmpty({ message: CompanyMessage.CHIEF_EXECUTIVE_REQUIRED })
|
||||||
|
@IsString({ message: CompanyMessage.CHIEF_EXECUTIVE_MUST_BE_STRING })
|
||||||
|
@Length(3, 255, { message: CompanyMessage.CHIEF_EXECUTIVE_MUST_BE_STRING })
|
||||||
|
@ApiProperty({ description: "نام مدیر عامل", example: "محمد حسین حسینی" })
|
||||||
|
chiefExecutiveOfficer: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ApproveCompanyRequestDto {
|
||||||
|
@IsNotEmpty({ message: CompanyMessage.COMPANY_REQUEST_STATUS_REQUIRED })
|
||||||
|
@IsEnum(CompanyRequestStatus)
|
||||||
|
@ApiProperty({ enum: CompanyRequestStatus, description: "وضعیت درخواست" })
|
||||||
|
requestStatus: CompanyRequestStatus;
|
||||||
|
|
||||||
|
@ApiProperty({ required: false, description: "دلیل رد درخواست" })
|
||||||
|
rejectReason?: string;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,15 +1,18 @@
|
|||||||
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseInterceptors } from "@nestjs/common";
|
import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseInterceptors } from "@nestjs/common";
|
||||||
import { ApiOperation } from "@nestjs/swagger";
|
import { ApiOperation } from "@nestjs/swagger";
|
||||||
|
|
||||||
import { CompanyListQueryDto } from "./DTO/company-list-query.dto";
|
import { CompanyListPublicQueryDto, CompanyListQueryDto } from "./DTO/company-list-query.dto";
|
||||||
import { CreateCompanyDto } from "./DTO/create-company.dto";
|
import { ApproveCompanyRequestDto, CreateCompanyDto, CreateCompanyRequestDto } from "./DTO/create-company.dto";
|
||||||
import { UpdateCompanyDto } from "./DTO/update-company.dto";
|
import { UpdateCompanyDto } from "./DTO/update-company.dto";
|
||||||
import { CompaniesService } from "./services/companies.service";
|
import { CompaniesService } from "./services/companies.service";
|
||||||
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
|
||||||
import { BusinessDec } from "../../common/decorators/business.decorator";
|
import { BusinessDec } from "../../common/decorators/business.decorator";
|
||||||
|
import { UserDec } from "../../common/decorators/user.decorator";
|
||||||
import { ParamDto } from "../../common/DTO/param.dto";
|
import { ParamDto } from "../../common/DTO/param.dto";
|
||||||
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
import { BusinessInterceptor } from "../../core/interceptors/business.interceptor";
|
||||||
import { Business } from "../businesses/entities/business.entity";
|
import { Business } from "../businesses/entities/business.entity";
|
||||||
|
import { User } from "../users/entities/user.entity";
|
||||||
|
|
||||||
@Controller("companies")
|
@Controller("companies")
|
||||||
@UseInterceptors(BusinessInterceptor)
|
@UseInterceptors(BusinessInterceptor)
|
||||||
export class CompaniesController {
|
export class CompaniesController {
|
||||||
@@ -43,6 +46,18 @@ export class CompaniesController {
|
|||||||
return this.companiesService.getCompaniesList(query, businessId);
|
return this.companiesService.getCompaniesList(query, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get("list/public")
|
||||||
|
@ApiOperation({ summary: "get companies list (public)" })
|
||||||
|
getCompaniesListPublic(@Query() queryDto: CompanyListPublicQueryDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.companiesService.getCompaniesListPublic(queryDto, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("public/:id")
|
||||||
|
@ApiOperation({ summary: "get company by id (public)" })
|
||||||
|
getCompanyByIdPublic(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.companiesService.getCompanyByIdPublic(paramDto.id, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@ApiOperation({ summary: "get company by id" })
|
@ApiOperation({ summary: "get company by id" })
|
||||||
@@ -56,4 +71,31 @@ export class CompaniesController {
|
|||||||
toggleStatus(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
toggleStatus(@Param() paramDto: ParamDto, @BusinessDec("id") businessId: string) {
|
||||||
return this.companiesService.toggleStatus(paramDto.id, businessId);
|
return this.companiesService.toggleStatus(paramDto.id, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post("/company-requests")
|
||||||
|
@AuthGuards()
|
||||||
|
@ApiOperation({ summary: "submit company registration request (user)" })
|
||||||
|
createCompanyRequest(@Body() createDto: CreateCompanyRequestDto, @UserDec() user: User, @BusinessDec() business: Business) {
|
||||||
|
return this.companiesService.createCompanyRequest(createDto, user, business);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("/company-requests/user")
|
||||||
|
@ApiOperation({ summary: "get all company registration requests (user)" })
|
||||||
|
getCompanyRequestsUser(@UserDec("id") userId: string, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.companiesService.getCompanyRequestsUser(userId, businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Get("/company-requests")
|
||||||
|
@AuthGuards()
|
||||||
|
@ApiOperation({ summary: "get all company registration requests (admin)" })
|
||||||
|
getCompanyRequests(@BusinessDec("id") businessId: string) {
|
||||||
|
return this.companiesService.getCompanyRequests(businessId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Patch("/company-requests/:id/approve")
|
||||||
|
@AuthGuards()
|
||||||
|
@ApiOperation({ summary: "approve/reject company registration request (admin)" })
|
||||||
|
approveCompanyRequest(@Param() paramDto: ParamDto, @Body() approveDto: ApproveCompanyRequestDto, @BusinessDec("id") businessId: string) {
|
||||||
|
return this.companiesService.approveCompanyRequest(paramDto.id, approveDto, businessId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Module } from "@nestjs/common";
|
|||||||
|
|
||||||
import { CompaniesController } from "./companies.controller";
|
import { CompaniesController } from "./companies.controller";
|
||||||
import { CompanyProduct } from "./entities/company-product.entity";
|
import { CompanyProduct } from "./entities/company-product.entity";
|
||||||
|
import { CompanyRequest } from "./entities/company-request.enitiy";
|
||||||
import { CompanyService } from "./entities/company-service.entity";
|
import { CompanyService } from "./entities/company-service.entity";
|
||||||
import { Company } from "./entities/company.entity";
|
import { Company } from "./entities/company.entity";
|
||||||
import { CompaniesService } from "./services/companies.service";
|
import { CompaniesService } from "./services/companies.service";
|
||||||
@@ -11,7 +12,12 @@ import { Industry } from "../industries/entities/industry.entity";
|
|||||||
import { UsersModule } from "../users/users.module";
|
import { UsersModule } from "../users/users.module";
|
||||||
import { UtilsModule } from "../utils/utils.module";
|
import { UtilsModule } from "../utils/utils.module";
|
||||||
@Module({
|
@Module({
|
||||||
imports: [MikroOrmModule.forFeature([Company, Industry, CompanyProduct, CompanyService]), UsersModule, UtilsModule, BusinessesModule],
|
imports: [
|
||||||
|
MikroOrmModule.forFeature([Company, Industry, CompanyProduct, CompanyService, CompanyRequest]),
|
||||||
|
UsersModule,
|
||||||
|
UtilsModule,
|
||||||
|
BusinessesModule,
|
||||||
|
],
|
||||||
providers: [CompaniesService],
|
providers: [CompaniesService],
|
||||||
controllers: [CompaniesController],
|
controllers: [CompaniesController],
|
||||||
exports: [CompaniesService],
|
exports: [CompaniesService],
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import { Entity, EntityRepositoryType, Enum, ManyToOne, Opt, Property } from "@mikro-orm/core";
|
||||||
|
|
||||||
|
import { Company } from "./company.entity";
|
||||||
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
|
import { User } from "../../users/entities/user.entity";
|
||||||
|
import { CompanyRequestStatus } from "../enums/company-request-status.enum";
|
||||||
|
import { CompanyRequestRepository } from "../repositories/company-request.repository";
|
||||||
|
|
||||||
|
@Entity({ repository: () => CompanyRequestRepository })
|
||||||
|
export class CompanyRequest extends BaseEntity {
|
||||||
|
@Property({ type: "text", nullable: true })
|
||||||
|
rejectReason?: string;
|
||||||
|
|
||||||
|
@Enum({ items: () => CompanyRequestStatus, nativeEnumName: "company_request_status", default: CompanyRequestStatus.PENDING })
|
||||||
|
requestStatus!: CompanyRequestStatus & Opt;
|
||||||
|
|
||||||
|
@ManyToOne(() => Company, { nullable: false })
|
||||||
|
company!: Company;
|
||||||
|
|
||||||
|
@ManyToOne(() => Business, { nullable: false })
|
||||||
|
business!: Business;
|
||||||
|
|
||||||
|
@ManyToOne(() => User, { nullable: false })
|
||||||
|
user!: User;
|
||||||
|
|
||||||
|
[EntityRepositoryType]?: CompanyRequestRepository;
|
||||||
|
}
|
||||||
@@ -1,4 +1,16 @@
|
|||||||
import { Cascade, Collection, Entity, EntityRepositoryType, Enum, Formula, ManyToOne, OneToMany, Opt, Property } from "@mikro-orm/core";
|
import {
|
||||||
|
Cascade,
|
||||||
|
Collection,
|
||||||
|
Entity,
|
||||||
|
EntityRepositoryType,
|
||||||
|
Enum,
|
||||||
|
Formula,
|
||||||
|
ManyToOne,
|
||||||
|
OneToMany,
|
||||||
|
OneToOne,
|
||||||
|
Opt,
|
||||||
|
Property,
|
||||||
|
} from "@mikro-orm/core";
|
||||||
|
|
||||||
import { CompanyProduct } from "./company-product.entity";
|
import { CompanyProduct } from "./company-product.entity";
|
||||||
import { CompanyService } from "./company-service.entity";
|
import { CompanyService } from "./company-service.entity";
|
||||||
@@ -15,6 +27,15 @@ export class Company extends BaseEntity {
|
|||||||
@Property({ type: "varchar", length: 255, unique: true })
|
@Property({ type: "varchar", length: 255, unique: true })
|
||||||
name!: string;
|
name!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255 })
|
||||||
|
chiefExecutiveOfficer!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, unique: true })
|
||||||
|
email!: string;
|
||||||
|
|
||||||
|
@Property({ type: "varchar", length: 255, unique: true })
|
||||||
|
phone!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 255, unique: true })
|
@Property({ type: "varchar", length: 255, unique: true })
|
||||||
identificationNumber!: string;
|
identificationNumber!: string;
|
||||||
|
|
||||||
@@ -45,6 +66,9 @@ export class Company extends BaseEntity {
|
|||||||
@Enum({ items: () => CompanyStatus, nativeEnumName: "company_status", nullable: false })
|
@Enum({ items: () => CompanyStatus, nativeEnumName: "company_status", nullable: false })
|
||||||
status!: CompanyStatus;
|
status!: CompanyStatus;
|
||||||
|
|
||||||
|
@Formula((alias) => `(SELECT COUNT(*)::int FROM invoice i WHERE i.company_id = ${alias}.id)`, { persist: false })
|
||||||
|
invoiceCount?: number;
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
@OneToMany(() => CompanyProduct, (product) => product.company, { cascade: [Cascade.ALL] })
|
@OneToMany(() => CompanyProduct, (product) => product.company, { cascade: [Cascade.ALL] })
|
||||||
@@ -56,19 +80,18 @@ export class Company extends BaseEntity {
|
|||||||
@OneToMany(() => Invoice, (invoice) => invoice.company, { cascade: [Cascade.ALL] })
|
@OneToMany(() => Invoice, (invoice) => invoice.company, { cascade: [Cascade.ALL] })
|
||||||
invoices = new Collection<Invoice>(this);
|
invoices = new Collection<Invoice>(this);
|
||||||
|
|
||||||
@Formula((alias) => `(SELECT COUNT(*)::int FROM invoice i WHERE i.company_id = ${alias}.id)`, { persist: false })
|
|
||||||
invoiceCount?: number;
|
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
@ManyToOne(() => Industry, { deleteRule: "restrict" })
|
@ManyToOne(() => Industry, { deleteRule: "restrict" })
|
||||||
industry!: Industry;
|
industry!: Industry;
|
||||||
|
|
||||||
@ManyToOne(() => User, { deleteRule: "restrict" })
|
|
||||||
user!: User;
|
|
||||||
|
|
||||||
@ManyToOne(() => Business, { deleteRule: "restrict" })
|
@ManyToOne(() => Business, { deleteRule: "restrict" })
|
||||||
business!: Business;
|
business!: Business;
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
@OneToOne(() => User, (user) => user.company, { owner: true })
|
||||||
|
user!: User;
|
||||||
|
|
||||||
[EntityRepositoryType]?: CompanyRepository;
|
[EntityRepositoryType]?: CompanyRepository;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export enum CompanyRequestStatus {
|
||||||
|
PENDING = "PENDING",
|
||||||
|
APPROVED = "APPROVED",
|
||||||
|
REJECTED = "REJECTED",
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { EntityRepository } from "@mikro-orm/postgresql";
|
||||||
|
|
||||||
|
import { CompanyRequest } from "../entities/company-request.enitiy";
|
||||||
|
|
||||||
|
export class CompanyRequestRepository extends EntityRepository<CompanyRequest> {}
|
||||||
@@ -1,9 +1,9 @@
|
|||||||
import { EntityRepository, FilterQuery } from "@mikro-orm/postgresql";
|
import { EntityRepository, FilterQuery } from "@mikro-orm/postgresql";
|
||||||
|
|
||||||
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
import { PaginationUtils } from "../../utils/providers/pagination.utils";
|
||||||
import { CompanyListQueryDto } from "../DTO/company-list-query.dto";
|
import { CompanyListPublicQueryDto, CompanyListQueryDto } from "../DTO/company-list-query.dto";
|
||||||
import { Company } from "../entities/company.entity";
|
import { Company } from "../entities/company.entity";
|
||||||
|
import { CompanyStatus } from "../enums/company-status.enum";
|
||||||
export class CompanyRepository extends EntityRepository<Company> {
|
export class CompanyRepository extends EntityRepository<Company> {
|
||||||
//
|
//
|
||||||
async getCompaniesListForAdmin(queryDto: CompanyListQueryDto, businessId: string) {
|
async getCompaniesListForAdmin(queryDto: CompanyListQueryDto, businessId: string) {
|
||||||
@@ -48,6 +48,7 @@ export class CompanyRepository extends EntityRepository<Company> {
|
|||||||
"dateOfEstablishment",
|
"dateOfEstablishment",
|
||||||
"status",
|
"status",
|
||||||
"invoiceCount",
|
"invoiceCount",
|
||||||
|
"chiefExecutiveOfficer",
|
||||||
"createdAt",
|
"createdAt",
|
||||||
"industry.id",
|
"industry.id",
|
||||||
"industry.title",
|
"industry.title",
|
||||||
@@ -58,4 +59,23 @@ export class CompanyRepository extends EntityRepository<Company> {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getCompaniesListForPublic(queryDto: CompanyListPublicQueryDto, businessId: string) {
|
||||||
|
const where: FilterQuery<Company> = {
|
||||||
|
deletedAt: null,
|
||||||
|
business: { id: businessId },
|
||||||
|
isActive: true,
|
||||||
|
status: CompanyStatus.APPROVED,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (queryDto.industryId) {
|
||||||
|
where.industry = queryDto.industryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.find(where, {
|
||||||
|
populate: ["industry"],
|
||||||
|
orderBy: { createdAt: "DESC" },
|
||||||
|
fields: ["id", "name", "description", "profileImageUrl", "coverImageUrl", "industry.id", "industry.title", "createdAt"],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,16 @@ import { Industry } from "../../industries/entities/industry.entity";
|
|||||||
import { User } from "../../users/entities/user.entity";
|
import { User } from "../../users/entities/user.entity";
|
||||||
import { UsersService } from "../../users/services/users.service";
|
import { UsersService } from "../../users/services/users.service";
|
||||||
import { PasswordService } from "../../utils/providers/password.service";
|
import { PasswordService } from "../../utils/providers/password.service";
|
||||||
import { CompanyListQueryDto } from "../DTO/company-list-query.dto";
|
import { CompanyListPublicQueryDto, CompanyListQueryDto } from "../DTO/company-list-query.dto";
|
||||||
import { CreateCompanyDto } from "../DTO/create-company.dto";
|
import { ApproveCompanyRequestDto, CreateCompanyDto, CreateCompanyRequestDto } from "../DTO/create-company.dto";
|
||||||
import { UpdateCompanyDto } from "../DTO/update-company.dto";
|
import { UpdateCompanyDto } from "../DTO/update-company.dto";
|
||||||
import { CompanyProduct } from "../entities/company-product.entity";
|
import { CompanyProduct } from "../entities/company-product.entity";
|
||||||
|
import { CompanyRequest } from "../entities/company-request.enitiy";
|
||||||
import { CompanyService } from "../entities/company-service.entity";
|
import { CompanyService } from "../entities/company-service.entity";
|
||||||
import { Company } from "../entities/company.entity";
|
import { Company } from "../entities/company.entity";
|
||||||
|
import { CompanyRequestStatus } from "../enums/company-request-status.enum";
|
||||||
import { CompanyStatus } from "../enums/company-status.enum";
|
import { CompanyStatus } from "../enums/company-status.enum";
|
||||||
|
import { CompanyRequestRepository } from "../repositories/company-request.repository";
|
||||||
import { CompanyRepository } from "../repositories/company.repository";
|
import { CompanyRepository } from "../repositories/company.repository";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -24,6 +27,7 @@ export class CompaniesService {
|
|||||||
private readonly usersService: UsersService,
|
private readonly usersService: UsersService,
|
||||||
private readonly passwordService: PasswordService,
|
private readonly passwordService: PasswordService,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
|
private readonly companyRequestRepository: CompanyRequestRepository,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async create(createDto: CreateCompanyDto, business: Business) {
|
async create(createDto: CreateCompanyDto, business: Business) {
|
||||||
@@ -31,45 +35,12 @@ export class CompaniesService {
|
|||||||
try {
|
try {
|
||||||
await em.begin();
|
await em.begin();
|
||||||
|
|
||||||
const industry = await em.findOne(Industry, { id: createDto.industryId, deletedAt: null });
|
|
||||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
|
||||||
|
|
||||||
const [existingCompany, existIdentityNumber] = await Promise.all([
|
|
||||||
em.findOne(Company, { name: createDto.name, business: { id: business.id } }),
|
|
||||||
em.findOne(Company, { identificationNumber: createDto.identificationNumber, business: { id: business.id } }),
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (existingCompany) throw new BadRequestException(CompanyMessage.COMPANY_ALREADY_EXISTS_NAME);
|
|
||||||
if (existIdentityNumber) throw new BadRequestException(CompanyMessage.COMPANY_ALREADY_EXISTS_IDENTITY_NUMBER);
|
|
||||||
|
|
||||||
const hashedPassword = await this.passwordService.hashPassword(createDto.password);
|
const hashedPassword = await this.passwordService.hashPassword(createDto.password);
|
||||||
const user = await this.usersService.createUser(createDto, hashedPassword, em);
|
const user = await this.usersService.createUser(createDto, hashedPassword, business, em);
|
||||||
|
|
||||||
const products = createDto.products.map((productData) => {
|
const company = await this.createCompany(createDto, user, business, em);
|
||||||
const product = new CompanyProduct();
|
|
||||||
product.title = productData.title;
|
|
||||||
product.imageUrl = productData.imageUrl;
|
|
||||||
return product;
|
|
||||||
});
|
|
||||||
|
|
||||||
const services = createDto.services.map((serviceData) => {
|
await em.flush();
|
||||||
const service = new CompanyService();
|
|
||||||
service.title = serviceData.title;
|
|
||||||
service.imageUrl = serviceData.imageUrl;
|
|
||||||
return service;
|
|
||||||
});
|
|
||||||
|
|
||||||
const company = em.create(Company, {
|
|
||||||
...createDto,
|
|
||||||
industry,
|
|
||||||
status: CompanyStatus.APPROVED,
|
|
||||||
products,
|
|
||||||
services,
|
|
||||||
user,
|
|
||||||
business,
|
|
||||||
});
|
|
||||||
|
|
||||||
await em.persistAndFlush(company);
|
|
||||||
await em.commit();
|
await em.commit();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -192,6 +163,19 @@ export class CompaniesService {
|
|||||||
const company = await this.findCompanyById(id, businessId);
|
const company = await this.findCompanyById(id, businessId);
|
||||||
return { company };
|
return { company };
|
||||||
}
|
}
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async getCompanyByIdPublic(id: string, businessId: string) {
|
||||||
|
const company = await this.companyRepository.findOne(
|
||||||
|
{ id, deletedAt: null, isActive: true, status: CompanyStatus.APPROVED, business: { id: businessId } },
|
||||||
|
{
|
||||||
|
populate: ["industry", "user", "products", "services"],
|
||||||
|
fields: ["*", "industry.id", "industry.title", "user.id"],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!company) throw new BadRequestException(CompanyMessage.COMPANY_NOT_FOUND);
|
||||||
|
return { company };
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
@@ -203,7 +187,12 @@ export class CompaniesService {
|
|||||||
paginate: true,
|
paginate: true,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async getCompaniesListPublic(queryDto: CompanyListPublicQueryDto, businessId: string) {
|
||||||
|
const companies = await this.companyRepository.getCompaniesListForPublic(queryDto, businessId);
|
||||||
|
return { companies };
|
||||||
|
}
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
async deleteCompanyById(id: string, businessId: string) {
|
async deleteCompanyById(id: string, businessId: string) {
|
||||||
@@ -253,4 +242,136 @@ export class CompaniesService {
|
|||||||
if (!company) throw new BadRequestException(CompanyMessage.COMPANY_NOT_FOUND);
|
if (!company) throw new BadRequestException(CompanyMessage.COMPANY_NOT_FOUND);
|
||||||
return company;
|
return company;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async createCompanyRequest(createDto: CreateCompanyRequestDto, user: User, business: Business) {
|
||||||
|
const em = this.em.fork();
|
||||||
|
try {
|
||||||
|
await em.begin();
|
||||||
|
|
||||||
|
const existRequest = await em.findOne(CompanyRequest, {
|
||||||
|
user: { id: user.id },
|
||||||
|
business: { id: business.id },
|
||||||
|
requestStatus: CompanyRequestStatus.PENDING,
|
||||||
|
deletedAt: null,
|
||||||
|
});
|
||||||
|
if (existRequest) throw new BadRequestException(CompanyMessage.COMPANY_REQUEST_ALREADY_EXISTS);
|
||||||
|
|
||||||
|
const company = await this.createCompany(createDto, user, business, em);
|
||||||
|
company.status = CompanyStatus.PENDING;
|
||||||
|
|
||||||
|
const companyRequest = em.create(CompanyRequest, {
|
||||||
|
user,
|
||||||
|
business,
|
||||||
|
company,
|
||||||
|
});
|
||||||
|
|
||||||
|
await em.persistAndFlush(companyRequest);
|
||||||
|
|
||||||
|
await em.flush();
|
||||||
|
await em.commit();
|
||||||
|
return { message: CompanyMessage.COMPANY_CREATED_SUCCESSFULLY, companyId: company.id, requestId: companyRequest.id };
|
||||||
|
} catch (error) {
|
||||||
|
await em.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async getCompanyRequestsUser(userId: string, businessId: string) {
|
||||||
|
const requests = await this.companyRequestRepository.find(
|
||||||
|
{ user: { id: userId }, business: { id: businessId }, deletedAt: null },
|
||||||
|
{ populate: ["company"], orderBy: { createdAt: "DESC" } },
|
||||||
|
);
|
||||||
|
return { requests };
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async getCompanyRequests(businessId: string) {
|
||||||
|
const requests = await this.companyRequestRepository.find(
|
||||||
|
{ business: { id: businessId }, deletedAt: null },
|
||||||
|
{
|
||||||
|
populate: ["user", "company"],
|
||||||
|
orderBy: { createdAt: "DESC" },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return { requests };
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
async approveCompanyRequest(id: string, dto: ApproveCompanyRequestDto, businessId: string) {
|
||||||
|
const em = this.em.fork();
|
||||||
|
try {
|
||||||
|
await em.begin();
|
||||||
|
const request = await em.findOneOrFail(CompanyRequest, { id, business: { id: businessId } }, { populate: ["company"] });
|
||||||
|
|
||||||
|
request.requestStatus = dto.requestStatus;
|
||||||
|
|
||||||
|
if (dto.requestStatus === CompanyRequestStatus.REJECTED) {
|
||||||
|
request.rejectReason = dto.rejectReason || "";
|
||||||
|
request.company.status = CompanyStatus.REJECTED;
|
||||||
|
} else {
|
||||||
|
request.rejectReason = undefined;
|
||||||
|
request.company.status = CompanyStatus.APPROVED;
|
||||||
|
}
|
||||||
|
|
||||||
|
await em.persistAndFlush(request);
|
||||||
|
await em.flush();
|
||||||
|
await em.commit();
|
||||||
|
return { message: CompanyMessage.UPDATED_SUCCESSFULLY, status: request.requestStatus };
|
||||||
|
} catch (error) {
|
||||||
|
await em.rollback();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
private async createCompany(createDto: CreateCompanyDto | CreateCompanyRequestDto, user: User, business: Business, em: EntityManager) {
|
||||||
|
const industry = await em.findOne(Industry, { id: createDto.industryId, deletedAt: null });
|
||||||
|
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||||
|
|
||||||
|
const [existingCompany, existIdentityNumber] = await Promise.all([
|
||||||
|
em.findOne(Company, { name: createDto.name, business: { id: business.id } }),
|
||||||
|
em.findOne(Company, { identificationNumber: createDto.identificationNumber, business: { id: business.id } }),
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (existingCompany) throw new BadRequestException(CompanyMessage.COMPANY_ALREADY_EXISTS_NAME);
|
||||||
|
if (existIdentityNumber) throw new BadRequestException(CompanyMessage.COMPANY_ALREADY_EXISTS_IDENTITY_NUMBER);
|
||||||
|
|
||||||
|
const products = createDto.products.map((productData) => {
|
||||||
|
const product = new CompanyProduct();
|
||||||
|
product.title = productData.title;
|
||||||
|
product.imageUrl = productData.imageUrl;
|
||||||
|
return product;
|
||||||
|
});
|
||||||
|
|
||||||
|
const services = createDto.services.map((serviceData) => {
|
||||||
|
const service = new CompanyService();
|
||||||
|
service.title = serviceData.title;
|
||||||
|
service.imageUrl = serviceData.imageUrl;
|
||||||
|
return service;
|
||||||
|
});
|
||||||
|
|
||||||
|
const company = em.create(Company, {
|
||||||
|
...createDto,
|
||||||
|
industry,
|
||||||
|
status: CompanyStatus.APPROVED,
|
||||||
|
products,
|
||||||
|
services,
|
||||||
|
user,
|
||||||
|
business,
|
||||||
|
chiefExecutiveOfficer:
|
||||||
|
"chiefExecutiveOfficer" in createDto ? createDto.chiefExecutiveOfficer : `${createDto.firstName} ${createDto.lastName}`,
|
||||||
|
email: createDto.email,
|
||||||
|
phone: createDto.phone,
|
||||||
|
});
|
||||||
|
|
||||||
|
await em.persistAndFlush(company);
|
||||||
|
|
||||||
|
return company;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ export class IndustriesController {
|
|||||||
return this.industriesService.getIndustriesListForAdmin(query, businessId);
|
return this.industriesService.getIndustriesListForAdmin(query, businessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Get("list/public")
|
||||||
|
@ApiOperation({ summary: "get industries list for public" })
|
||||||
|
getIndustriesForPublic(@BusinessDec("id") businessId: string) {
|
||||||
|
return this.industriesService.getIndustriesListForPublic(businessId);
|
||||||
|
}
|
||||||
|
|
||||||
@Patch(":id/toggle-status")
|
@Patch(":id/toggle-status")
|
||||||
@AuthGuards()
|
@AuthGuards()
|
||||||
@ApiOperation({ summary: "toggle industry status" })
|
@ApiOperation({ summary: "toggle industry status" })
|
||||||
|
|||||||
@@ -25,4 +25,11 @@ export class IndustryRepository extends EntityRepository<Industry> {
|
|||||||
|
|
||||||
return queryBuilder.getResultAndCount();
|
return queryBuilder.getResultAndCount();
|
||||||
}
|
}
|
||||||
|
//-----------------------------------
|
||||||
|
async getIndustriesListForPublic(businessId: string) {
|
||||||
|
return this.find(
|
||||||
|
{ deletedAt: null, business: { id: businessId }, isActive: true },
|
||||||
|
{ orderBy: { createdAt: "DESC" }, fields: ["id", "title", "iconUrl", "createdAt"] },
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -78,6 +78,12 @@ export class IndustriesService {
|
|||||||
}
|
}
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
|
async getIndustriesListForPublic(businessId: string) {
|
||||||
|
const industries = await this.industryRepository.getIndustriesListForPublic(businessId);
|
||||||
|
return { industries };
|
||||||
|
}
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
async toggleStatus(id: string, businessId: string) {
|
async toggleStatus(id: string, businessId: string) {
|
||||||
const industry = await this.industryRepository.findOne({ id, deletedAt: null, business: { id: businessId } });
|
const industry = await this.industryRepository.findOne({ id, deletedAt: null, business: { id: businessId } });
|
||||||
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
if (!industry) throw new BadRequestException(IndustryMessage.INDUSTRY_NOT_FOUND);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export class RefreshToken extends BaseEntity {
|
|||||||
@Property({ type: "varchar", length: 255 })
|
@Property({ type: "varchar", length: 255 })
|
||||||
token!: string;
|
token!: string;
|
||||||
|
|
||||||
@ManyToOne(() => User, { deleteRule: "restrict" })
|
@ManyToOne(() => User, { deleteRule: "cascade" })
|
||||||
user!: User;
|
user!: User;
|
||||||
|
|
||||||
@Property({ type: "timestamptz", nullable: true })
|
@Property({ type: "timestamptz", nullable: true })
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { Collection, Entity, EntityRepositoryType, ManyToOne, OneToMany, Opt, Property } from "@mikro-orm/core";
|
import { Collection, Entity, EntityRepositoryType, ManyToOne, OneToMany, OneToOne, Opt, Property, Unique } from "@mikro-orm/core";
|
||||||
|
|
||||||
import { RefreshToken } from "./refresh-token.entity";
|
import { RefreshToken } from "./refresh-token.entity";
|
||||||
import { Role } from "./role.entity";
|
import { Role } from "./role.entity";
|
||||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||||
import { UserAnnouncement } from "../../announcements/entities/user-announcement.entity";
|
import { UserAnnouncement } from "../../announcements/entities/user-announcement.entity";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
import { Company } from "../../companies/entities/company.entity";
|
import { Company } from "../../companies/entities/company.entity";
|
||||||
import { UserRepository } from "../repositories/user.repository";
|
import { UserRepository } from "../repositories/user.repository";
|
||||||
|
|
||||||
@Entity({ repository: () => UserRepository })
|
@Entity({ repository: () => UserRepository })
|
||||||
|
@Unique({ properties: ["phone", "business", "userName", "nationalCode"] })
|
||||||
export class User extends BaseEntity {
|
export class User extends BaseEntity {
|
||||||
@Property({ type: "varchar", length: 150 })
|
@Property({ type: "varchar", length: 150 })
|
||||||
firstName!: string;
|
firstName!: string;
|
||||||
@@ -18,10 +20,10 @@ export class User extends BaseEntity {
|
|||||||
@Property({ type: "varchar", length: 150, nullable: true })
|
@Property({ type: "varchar", length: 150, nullable: true })
|
||||||
email?: string;
|
email?: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 11, unique: true, nullable: false })
|
@Property({ type: "varchar", length: 11, nullable: false })
|
||||||
phone!: string;
|
phone!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 50, unique: true, nullable: true })
|
@Property({ type: "varchar", length: 50, nullable: true })
|
||||||
userName!: string;
|
userName!: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 150 })
|
@Property({ type: "varchar", length: 150 })
|
||||||
@@ -30,7 +32,7 @@ export class User extends BaseEntity {
|
|||||||
@Property({ type: "varchar", length: 12, nullable: true })
|
@Property({ type: "varchar", length: 12, nullable: true })
|
||||||
birthDate?: string;
|
birthDate?: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 100, unique: true, nullable: true })
|
@Property({ type: "varchar", length: 100, nullable: true })
|
||||||
nationalCode?: string;
|
nationalCode?: string;
|
||||||
|
|
||||||
@Property({ type: "varchar", length: 100, nullable: true })
|
@Property({ type: "varchar", length: 100, nullable: true })
|
||||||
@@ -49,14 +51,19 @@ export class User extends BaseEntity {
|
|||||||
@ManyToOne(() => Role, { deleteRule: "restrict" })
|
@ManyToOne(() => Role, { deleteRule: "restrict" })
|
||||||
role!: Role;
|
role!: Role;
|
||||||
|
|
||||||
|
@ManyToOne(() => Business, { deleteRule: "restrict" })
|
||||||
|
business!: Business;
|
||||||
|
|
||||||
|
//-----------------------------------
|
||||||
|
|
||||||
|
@OneToOne(() => Company, (company) => company.user, { orphanRemoval: true })
|
||||||
|
company!: Company & Opt;
|
||||||
|
|
||||||
//-----------------------------------
|
//-----------------------------------
|
||||||
|
|
||||||
@OneToMany(() => RefreshToken, (token) => token.user)
|
@OneToMany(() => RefreshToken, (token) => token.user)
|
||||||
refreshTokens = new Collection<RefreshToken>(this);
|
refreshTokens = new Collection<RefreshToken>(this);
|
||||||
|
|
||||||
@OneToMany(() => Company, (company) => company.user)
|
|
||||||
companies = new Collection<Company>(this);
|
|
||||||
|
|
||||||
@OneToMany(() => UserAnnouncement, (userAnnouncement) => userAnnouncement.user)
|
@OneToMany(() => UserAnnouncement, (userAnnouncement) => userAnnouncement.user)
|
||||||
userAnnouncements = new Collection<UserAnnouncement>(this);
|
userAnnouncements = new Collection<UserAnnouncement>(this);
|
||||||
|
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ import slugify from "slugify";
|
|||||||
|
|
||||||
import { UserMessage } from "../../../common/enums/message.enum";
|
import { UserMessage } from "../../../common/enums/message.enum";
|
||||||
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
||||||
|
import { Business } from "../../businesses/entities/business.entity";
|
||||||
import { CreateCompanyDto } from "../../companies/DTO/create-company.dto";
|
import { CreateCompanyDto } from "../../companies/DTO/create-company.dto";
|
||||||
import { Role } from "../entities/role.entity";
|
import { Role } from "../entities/role.entity";
|
||||||
import { User } from "../entities/user.entity";
|
import { User } from "../entities/user.entity";
|
||||||
import { RoleEnum } from "../enums/role.enum";
|
import { RoleEnum } from "../enums/role.enum";
|
||||||
import { UserRepository } from "../repositories/user.repository";
|
import { UserRepository } from "../repositories/user.repository";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class UsersService {
|
export class UsersService {
|
||||||
constructor(
|
constructor(
|
||||||
@@ -19,14 +19,14 @@ export class UsersService {
|
|||||||
|
|
||||||
/*******************************/
|
/*******************************/
|
||||||
|
|
||||||
async findOneWithEmail(email: string) {
|
async findOneWithEmail(email: string, businessId: string) {
|
||||||
const user = await this.userRepository.findOne({ email }, { populate: ["role"] });
|
const user = await this.userRepository.findOne({ email, business: { id: businessId } }, { populate: ["role"] });
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
/*******************************/
|
/*******************************/
|
||||||
|
|
||||||
async findOneWithPhone(phone: string) {
|
async findOneWithPhone(phone: string, businessId: string) {
|
||||||
const user = await this.userRepository.findOne({ phone }, { populate: ["role"] });
|
const user = await this.userRepository.findOne({ phone, business: { id: businessId } }, { populate: ["role"] });
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
/*******************************/
|
/*******************************/
|
||||||
@@ -85,7 +85,7 @@ export class UsersService {
|
|||||||
}
|
}
|
||||||
/*******************************/
|
/*******************************/
|
||||||
|
|
||||||
async createUser(registerDto: CompleteRegistrationDto | CreateCompanyDto, hashedPassword: string, em: EntityManager) {
|
async createUser(registerDto: CompleteRegistrationDto | CreateCompanyDto, hashedPassword: string, business: Business, em: EntityManager) {
|
||||||
const [role, existPhone, existUser] = await Promise.all([
|
const [role, existPhone, existUser] = await Promise.all([
|
||||||
em.findOne(Role, { name: RoleEnum.USER }),
|
em.findOne(Role, { name: RoleEnum.USER }),
|
||||||
em.findOne(User, { phone: registerDto.phone }),
|
em.findOne(User, { phone: registerDto.phone }),
|
||||||
@@ -108,6 +108,7 @@ export class UsersService {
|
|||||||
userName,
|
userName,
|
||||||
password: hashedPassword,
|
password: hashedPassword,
|
||||||
role,
|
role,
|
||||||
|
business,
|
||||||
});
|
});
|
||||||
|
|
||||||
await em.persistAndFlush(user);
|
await em.persistAndFlush(user);
|
||||||
|
|||||||
Reference in New Issue
Block a user