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'; @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) { userData.superior = superior; } 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; 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 (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, id: 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.isActive', 'user.createdAt', 'roles.id', 'roles.name', 'user_detail', 'coa.amount', ]); const data = await baseQuery .orderBy('user.createdAt', 'DESC') .skip(page * 10) .take(10) .getMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } 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) { 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.isActive', 'roles.id', 'roles.name', 'user_detail', 'coa.amount', ]); const data = await baseQuery .skip(page * 10) .take(10) .getMany(); const totalData = await baseQuery.getCount(); return { data, count: totalData, }; } async findExist(id: string) { try { return 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; } } } 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) { const coa = await this.coaService.findByUser(id, coaType.WALLET); 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.isActive', 'users.createdAt', 'roles.id', 'roles.name', 'superior.id', 'superior.username', 'userDetail.id', 'userDetail.name', 'userDetail.phone_number', ]) .getOne(); return { ...userData, wallet: coa.amount, }; } 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; await this.connection.transaction(async (manager) => { await manager.save(userData); await manager.save(userDetailData); }); return userData; } async updatePassword( id: string, updateUserDto: UpdateUserDto, currentUser: any, ) { 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; } } } setStatus = async (id: string, type: string) => { const userData = new User(); if (type === 'active') { userData.isActive = true; } else { userData.isActive = 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, isActive: 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; } } } }