import { forwardRef, HttpException, HttpStatus, Inject, Injectable, } from '@nestjs/common'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; import { Connection, EntityNotFoundError, Not, Repository } from 'typeorm'; import { User } from './entities/user.entity'; import { InjectRepository } from '@nestjs/typeorm'; import { randomStringGenerator } from '@nestjs/common/utils/random-string-generator.util'; import { hashPassword } from '../helper/hash_password'; import { CoaService } from 'src/transaction/coa.service'; import { balanceType, coaType } from 'src/helper/enum-list'; import { RoleService } from 'src/configurable/roles.service'; import { InputCoaDto } from 'src/transaction/dto/input-coa.dto'; import * as uuid from 'uuid'; import { UserDetail } from './entities/user_detail.entity'; import { COA } from '../transaction/entities/coa.entity'; import { mapSeries } from 'bluebird'; @Injectable() export class UsersService { constructor( @InjectRepository(User) private usersRepository: Repository, @InjectRepository(UserDetail) private userDetailRepository: Repository, @Inject( forwardRef(() => { return CoaService; }), ) private coaService: CoaService, private roleService: RoleService, private connection: Connection, ) {} async create(createUserDto: CreateUserDto, currentUser: any) { const roles = await this.roleService.findOne(createUserDto.roleId); const superior = await this.findByUsername(currentUser.username); const check = await this.usersRepository.findOne({ username: createUserDto.username, }); if (check) { throw new HttpException( { statusCode: HttpStatus.NOT_ACCEPTABLE, error: 'Username Already Exist', }, HttpStatus.NOT_FOUND, ); } const salt = randomStringGenerator(); const userData = new User(); userData.id = uuid.v4(); userData.username = createUserDto.username; userData.password = await hashPassword(createUserDto.password, salt); userData.salt = salt; if (createUserDto.superior) { let approvalRole = ''; if (superior.superior) { if(superior.roles.name == 'Sales'){ approvalRole = 'Supervisor'; } else { approvalRole = 'Admin'; } userData.superior = superior; userData.status_approval = superior.superior.id; userData.is_active = false; } else { userData.superior = superior; userData.is_active = true; } } else { userData.superior = null; userData.partner = createUserDto.partner; } userData.roles = roles; await this.connection.transaction(async (manager) => { const result = await manager.insert(User, userData); const userDetailData = new UserDetail(); userDetailData.name = createUserDto.name; userDetailData.phone_number = createUserDto.phone_number; userDetailData.user = userData; userDetailData.identity_number = createUserDto.identity_number; userDetailData.image_identity = createUserDto.image_identity; userDetailData.image_store = createUserDto.image_store; const user_detail = await manager.insert(UserDetail, userDetailData); const dataCoaWallet = new InputCoaDto(); dataCoaWallet.user = userData; dataCoaWallet.balanceType = balanceType.CREDIT; dataCoaWallet.type = coaType.WALLET; dataCoaWallet.coaEntityManager = manager; await this.coaService.create(dataCoaWallet); const dataCoaAR = new InputCoaDto(); dataCoaAR.user = userData; dataCoaAR.balanceType = balanceType.DEBIT; dataCoaAR.relatedUserId = superior.id; dataCoaAR.type = coaType.ACCOUNT_RECEIVABLE; dataCoaAR.coaEntityManager = manager; await this.coaService.create(dataCoaAR); if (roles.name == 'Supervisor' || roles.name == 'Sales') { const dataCOAProfit = new InputCoaDto(); dataCOAProfit.user = userData; dataCOAProfit.balanceType = balanceType.CREDIT; dataCOAProfit.type = coaType.PROFIT; dataCOAProfit.coaEntityManager = manager; await this.coaService.create(dataCOAProfit); } if (createUserDto.superior) { const dataCoaAP = new InputCoaDto(); dataCoaAP.user = userData; dataCoaAP.balanceType = balanceType.CREDIT; dataCoaAP.relatedUserId = superior.id; dataCoaAP.type = coaType.ACCOUNT_PAYABLE; dataCoaAP.coaEntityManager = manager; await this.coaService.create(dataCoaAP); } }); return userData; } async findAll( page: number, pageSize: number, id: string, superior: string, type: string, ) { const baseQuery = this.usersRepository .createQueryBuilder('user') .where('user.id != :id', { id: id, }) .leftJoinAndSelect('user.roles', 'roles', `roles.id = user.roles_id`) .leftJoinAndMapOne( 'user.user_detail', UserDetail, 'user_detail', `user_detail.user = user.id`, ) .leftJoinAndMapOne( 'user.coa', COA, 'coa', `coa.user = user.id and coa.type = '0'`, ) .select([ 'user.id', 'user.username', 'user.is_active', 'user.createdAt', 'roles.id', 'roles.name', 'user_detail', 'coa.amount', ]); if (superior) { baseQuery.where('user.superior = :id_supperior', { id_supperior: superior, }); } if (type) { if (type == 'partner') { baseQuery.where('user.partner_id is not null'); } else { baseQuery.where('user.partner_id is null'); } } const data = await baseQuery .orderBy('user.createdAt', 'DESC') .skip(page * pageSize) .take(pageSize) .getMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findAllSubordinate(id: string, role: number) { let listUser = []; let listToFind = []; const baseQuery = await this.usersRepository.find({ where: { superior: id, }, }); const listId = baseQuery.map((x) => { return x.id; }); listUser = listUser.concat(listId); listToFind = listId; if (role == 1) { return listUser; } for (let it = 2; it <= role; it++) { let newListToFind = []; await mapSeries(listToFind, async (ltf) => { const getListUser = await this.usersRepository.find({ where: { superior: ltf, }, }); if (getListUser.length > 0) { const listId = getListUser.map((x) => { return x.id; }); newListToFind = newListToFind.concat(listId); listUser = listUser.concat(listId); } }); listToFind = newListToFind; } return listUser; } findByRoles(relationId: string, page: number, pageSize?: number) { return this.usersRepository.findAndCount({ skip: page * (pageSize || 10), take: pageSize || 10, where: { roles: relationId, }, order: { updatedAt: 'DESC', }, }); } async findBySuperrior(superriorId: string, page: number, pageSize: number) { const baseQuery = this.usersRepository .createQueryBuilder('user') .where('user.id != :id and user.superior_id = :superior', { id: superriorId, superior: superriorId, }) .leftJoinAndSelect('user.roles', 'roles', `roles.id = user.roles_id`) .leftJoinAndMapOne( 'user.user_detail', UserDetail, 'user_detail', `user_detail.user = user.id`, ) .leftJoinAndMapOne( 'user.coa', COA, 'coa', `coa.user = user.id and coa.type = '0'`, ) .select([ 'user.id', 'user.username', 'user.is_active', 'roles.id', 'roles.name', 'user_detail', 'coa.amount', ]); const data = await baseQuery .skip(page * pageSize) .take(pageSize) .getMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findApproval(superrior, page: number, pageSize: number) { const dataUser = await this.findByUsername(superrior.username); const baseQuery = this.usersRepository .createQueryBuilder('user') .where( 'user.id != :id and status_approval = :status and is_rejected is false', { id: superrior.userId, status: superrior.userId, }, ) .leftJoinAndSelect('user.roles', 'roles', `roles.id = user.roles_id`) .leftJoinAndMapOne( 'user.user_detail', UserDetail, 'user_detail', `user_detail.user = user.id`, ) .leftJoinAndMapOne( 'user.coa', COA, 'coa', `coa.user = user.id and coa.type = '0'`, ) .select([ 'user.id', 'user.username', 'user.is_active', 'roles.id', 'roles.name', 'user_detail', 'coa.amount', ]); const data = await baseQuery .skip(page * pageSize) .take(pageSize) .getMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findExist(id: string) { try { return await this.usersRepository.findOneOrFail({ where: { id: id, }, relations: ['superior', 'roles'], }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async findByUsername(username: string) { try { return await this.usersRepository.findOneOrFail({ where: { username: username, }, relations: ['superior', 'roles', 'partner'], }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async findOne(id: string) { try { const userData = await this.usersRepository .createQueryBuilder('users') .leftJoinAndSelect('users.roles', 'roles') .leftJoinAndSelect('users.superior', 'superior') .leftJoinAndSelect('users.userDetail', 'userDetail') .where('users.id = :id', { id: id, }) .select([ 'users.id', 'users.username', 'users.is_active', 'users.is_rejected', 'users.createdAt', 'roles.id', 'roles.name', 'superior.id', 'superior.username', 'userDetail.id', 'userDetail.name', 'userDetail.phone_number', 'userDetail.identity_number', 'userDetail.image_identity', 'userDetail.image_store', ]) .getOne(); const coa = await this.coaService.findByUser(id, coaType.WALLET); let coaProfit; if ( userData.roles.id != 'e4dfb6a3-2338-464a-8fb8-5cbc089d4209' && userData.roles.id != '21dceea2-416e-4b55-b74c-12605e1f8d1b' ) { coaProfit = await this.coaService.findByUser(id, coaType.PROFIT); } return { ...userData, wallet: coa.amount, profit: coaProfit ? coaProfit.amount : coaProfit, }; } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async update(id: string, updateUserDto: UpdateUserDto, currentUser: any) { let userData; let userDetailData; try { userData = await this.usersRepository.findOneOrFail(id); userDetailData = await this.userDetailRepository.findOneOrFail({ where: { user: userData, }, }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } const check = await this.usersRepository.findOne({ username: updateUserDto.username, id: Not(id), }); if (check) { throw new HttpException( { statusCode: HttpStatus.NOT_ACCEPTABLE, error: 'Username Already Exist', }, HttpStatus.NOT_FOUND, ); } userData.username = updateUserDto.username; userData.partner = updateUserDto.partner; userDetailData.name = updateUserDto.name; userDetailData.phone_number = updateUserDto.phone_number; userDetailData.identity_number = updateUserDto.identity_number; userDetailData.image_identity = updateUserDto.image_identity; userDetailData.image_store = updateUserDto.image_store; await this.connection.transaction(async (manager) => { await manager.save(userData); await manager.save(userDetailData); }); return userData; } async updatePassword(id: string, updateUserDto: UpdateUserDto) { try { const dataUser = await this.usersRepository.findOneOrFail(id); dataUser.password = await hashPassword( updateUserDto.password, dataUser.salt, ); const result = await this.usersRepository.save(dataUser); return dataUser; } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async updatePasswordPartner(id: string, password) { try { const dataUser = await this.usersRepository.findOneOrFail({ where: { partner: id, }, }); dataUser.password = await hashPassword(password, dataUser.salt); const result = await this.usersRepository.save(dataUser); return dataUser; } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } async confirmationUser(id: string, user: string, status: string) { try { const dataUser = await this.usersRepository.findOneOrFail(id); const supervisorUser = await this.findExist(user); if (status == 'approved') { if (supervisorUser.roles.name == 'Admin') { dataUser.status_approval = 'Done'; dataUser.is_active = true; } else { dataUser.status_approval = supervisorUser.superior.id; } } else if (status == 'resend') { dataUser.is_rejected = false; } else { dataUser.is_rejected = true; } const result = await this.usersRepository.save(dataUser); return dataUser; } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } setStatus = async (id: string, type: string) => { const userData = new User(); if (type === 'active') { userData.is_active = true; } else { userData.is_active = false; } await this.connection.transaction(async (manager) => { await manager.update(User, { id: id }, userData); }); return userData; }; async remove(id: string) { try { await this.usersRepository.findOneOrFail(id); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } await this.usersRepository.delete(id); } async findOneByUsername(username: string) { return this.usersRepository.findOneOrFail({ where: { username, is_active: true, }, relations: ['roles', 'partner'], }); } async findOneByPartner(partnerId: string) { try { return this.usersRepository.findOneOrFail({ relations: ['roles'], where: { partner: partnerId, }, }); } catch (e) { if (e instanceof EntityNotFoundError) { throw new HttpException( { statusCode: HttpStatus.NOT_FOUND, error: 'User not found', }, HttpStatus.NOT_FOUND, ); } else { throw e; } } } }