393 lines
15 KiB
TypeScript
Executable File
393 lines
15 KiB
TypeScript
Executable File
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
|
import { DataSource, Not } from "typeorm";
|
|
|
|
import { CommonMessage, UserMessage } from "../../../common/enums/message.enum";
|
|
import { Address } from "../../address/entities/address.entity";
|
|
import { AddressService } from "../../address/providers/address.service";
|
|
import { UserSettingsService } from "../../settings/providers/user-settings.service";
|
|
import { PasswordService } from "../../utils/providers/password.service";
|
|
import { WalletsService } from "../../wallets/providers/wallets.service";
|
|
import { CreateCustomerDto } from "../DTO/create-customer.dto";
|
|
import { CreateLegalUserDto } from "../DTO/create-legal-user.dto";
|
|
import { CreateRealUserDto } from "../DTO/create-real-user.dto";
|
|
import { SearchCustomersDto } from "../DTO/search-customers.dto";
|
|
import { UpdateCustomerDto } from "../DTO/update-customer.dto";
|
|
import { FinancialType } from "../enums/financial-type.enum";
|
|
import { RoleEnum } from "../enums/role.enum";
|
|
import { LegalUserRepository } from "../repositories/legal-user.repository";
|
|
import { RealUserRepository } from "../repositories/real-user.repository";
|
|
import { RoleRepository } from "../repositories/roles.repository";
|
|
import { UserRepository } from "../repositories/users.repository";
|
|
|
|
@Injectable()
|
|
export class CustomersService {
|
|
private readonly logger = new Logger(CustomersService.name);
|
|
constructor(
|
|
private readonly addressService: AddressService,
|
|
private readonly dataSource: DataSource,
|
|
private readonly userRepository: UserRepository,
|
|
private readonly legalUserRepository: LegalUserRepository,
|
|
private readonly realUserRepository: RealUserRepository,
|
|
private readonly passwordService: PasswordService,
|
|
private readonly userSettingsService: UserSettingsService,
|
|
private readonly rolesRepository: RoleRepository,
|
|
private readonly walletsService: WalletsService,
|
|
) {}
|
|
|
|
async createCustomer(createDto: CreateCustomerDto) {
|
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
|
|
try {
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
|
|
const [existingEmail, existingNationalCode, existingPhone, userRole] = await Promise.all([
|
|
queryRunner.manager.findOne(this.userRepository.target, { where: { email: createDto.email } }),
|
|
queryRunner.manager.findOne(this.userRepository.target, { where: { nationalCode: createDto.nationalCode } }),
|
|
queryRunner.manager.findOne(this.userRepository.target, { where: { phone: createDto.phone } }),
|
|
queryRunner.manager.findOne(this.rolesRepository.target, { where: { name: RoleEnum.USER } }),
|
|
]);
|
|
|
|
if (existingEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
|
|
if (existingNationalCode) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
|
if (existingPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
|
if (!userRole) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND);
|
|
|
|
const user = queryRunner.manager.create(this.userRepository.target, {
|
|
...createDto,
|
|
password: await this.passwordService.hashPassword(createDto.password),
|
|
roles: [userRole],
|
|
});
|
|
await queryRunner.manager.save(user);
|
|
|
|
await Promise.all([
|
|
this.userSettingsService.createUserSettings(user.id, queryRunner),
|
|
this.walletsService.createUserWallet(user.id, queryRunner),
|
|
]);
|
|
|
|
await this.createLegalUserData(createDto, user.id, queryRunner);
|
|
|
|
await queryRunner.commitTransaction();
|
|
return { message: CommonMessage.CREATED, user };
|
|
} catch (error) {
|
|
await queryRunner.rollbackTransaction();
|
|
this.logger.error("Error in create customer", error);
|
|
throw error;
|
|
} finally {
|
|
await queryRunner.release();
|
|
}
|
|
}
|
|
//************************************************ */
|
|
async updateCustomer(customerId: string, updateDto: UpdateCustomerDto) {
|
|
const queryRunner = this.dataSource.createQueryRunner();
|
|
try {
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
|
|
const {
|
|
registrationName,
|
|
economicCode,
|
|
nationalIdentity,
|
|
registrationCode,
|
|
postalCode,
|
|
nationalCode,
|
|
address,
|
|
cityId,
|
|
birthDate,
|
|
email,
|
|
firstName,
|
|
lastName,
|
|
password,
|
|
phone,
|
|
} = updateDto;
|
|
|
|
const legalUserUpdateData = {
|
|
registrationName,
|
|
economicCode,
|
|
nationalIdentity,
|
|
registrationCode,
|
|
phone,
|
|
};
|
|
|
|
const userUpdateData = {
|
|
email,
|
|
firstName,
|
|
lastName,
|
|
password,
|
|
phone,
|
|
birthDate,
|
|
};
|
|
|
|
// const addressUpdateData = {
|
|
// postalCode,
|
|
// address,
|
|
// cityId,
|
|
// };
|
|
|
|
const user = await queryRunner.manager.findOne(this.userRepository.target, { where: { id: customerId } });
|
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
|
|
|
if (email) {
|
|
const existingEmail = await queryRunner.manager.findOne(this.userRepository.target, {
|
|
where: { email, id: Not(user.id) },
|
|
});
|
|
if (existingEmail) throw new BadRequestException(UserMessage.EMAIL_EXIST);
|
|
}
|
|
|
|
if (nationalCode) {
|
|
const existingNationalCode = await queryRunner.manager.findOne(this.userRepository.target, {
|
|
where: { nationalCode: nationalCode, id: Not(user.id) },
|
|
});
|
|
if (existingNationalCode) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
|
}
|
|
|
|
if (phone) {
|
|
const existingPhone = await queryRunner.manager.findOne(this.userRepository.target, {
|
|
where: { phone: phone, id: Not(user.id) },
|
|
});
|
|
if (existingPhone) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
|
}
|
|
|
|
if (nationalCode) {
|
|
const existingNationalCode = await queryRunner.manager.findOne(this.realUserRepository.target, {
|
|
where: { nationalCode: nationalCode, id: Not(user.id) },
|
|
});
|
|
if (existingNationalCode) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
|
}
|
|
|
|
await queryRunner.manager.update(this.userRepository.target, { id: customerId }, userUpdateData);
|
|
if (password) {
|
|
const hashPassword = await this.passwordService.hashPassword(password);
|
|
await queryRunner.manager.update(this.userRepository.target, { id: customerId }, { password: hashPassword });
|
|
}
|
|
|
|
const legalUser = await queryRunner.manager.findOne(this.legalUserRepository.target, {
|
|
where: { user: { id: customerId } },
|
|
relations: { address: true },
|
|
});
|
|
|
|
if (!legalUser) throw new BadRequestException(UserMessage.LEGAL_DATA_NOT_FOUND);
|
|
|
|
if (economicCode) {
|
|
const existingEconomicCode = await queryRunner.manager.findOne(this.legalUserRepository.target, {
|
|
where: { economicCode, id: Not(legalUser.id) },
|
|
});
|
|
if (existingEconomicCode) throw new BadRequestException(UserMessage.ECONOMIC_CODE_EXIST);
|
|
}
|
|
|
|
if (registrationCode) {
|
|
const existingRegistrationCode = await queryRunner.manager.findOne(this.legalUserRepository.target, {
|
|
where: { registrationCode, id: Not(legalUser.id) },
|
|
});
|
|
if (existingRegistrationCode) throw new BadRequestException(UserMessage.REGISTRATION_CODE_EXIST);
|
|
}
|
|
|
|
if (nationalIdentity) {
|
|
const existingNationalIdentity = await queryRunner.manager.findOne(this.legalUserRepository.target, {
|
|
where: { nationalIdentity, id: Not(legalUser.id) },
|
|
});
|
|
if (existingNationalIdentity) throw new BadRequestException(UserMessage.NATIONAL_IDENTITY_EXIST);
|
|
}
|
|
|
|
if (registrationName) {
|
|
const existingRegistrationName = await queryRunner.manager.findOne(this.legalUserRepository.target, {
|
|
where: { registrationName, id: Not(legalUser.id) },
|
|
});
|
|
if (existingRegistrationName) throw new BadRequestException(UserMessage.REGISTRATION_NAME_EXIST);
|
|
}
|
|
|
|
await queryRunner.manager.update(this.legalUserRepository.target, { id: legalUser.id }, legalUserUpdateData);
|
|
|
|
// Update address if needed
|
|
if (cityId || address || postalCode) {
|
|
// Get the address entity
|
|
const addressEntity = legalUser.address;
|
|
|
|
if (!addressEntity) throw new BadRequestException(UserMessage.ADDRESS_NOT_FOUND);
|
|
|
|
// Prepare address updates
|
|
const addressUpdates: Record<string, unknown> = {};
|
|
|
|
if (cityId) {
|
|
const { city } = await this.addressService.getCity(+cityId);
|
|
addressUpdates.city = city;
|
|
}
|
|
|
|
if (address) {
|
|
addressUpdates.fullAddress = address;
|
|
}
|
|
|
|
if (postalCode) {
|
|
addressUpdates.postalCode = postalCode;
|
|
}
|
|
|
|
await queryRunner.manager.update(Address, { id: addressEntity.id }, addressUpdates);
|
|
}
|
|
|
|
await queryRunner.commitTransaction();
|
|
|
|
return {
|
|
message: CommonMessage.UPDATE_SUCCESS,
|
|
};
|
|
} catch (error) {
|
|
await queryRunner.rollbackTransaction();
|
|
this.logger.error("Error in update customer", error);
|
|
throw error;
|
|
} finally {
|
|
await queryRunner.release();
|
|
}
|
|
}
|
|
|
|
/************************************************************ */
|
|
|
|
async getCustomersCount() {
|
|
const count = await this.userRepository.count({ where: { roles: { name: RoleEnum.USER } } });
|
|
return count;
|
|
}
|
|
|
|
/************************************************************ */
|
|
async createRealUserData(createDto: CreateRealUserDto, userId: string, queryRunner = this.dataSource.createQueryRunner()) {
|
|
let transactionStarted = false;
|
|
|
|
try {
|
|
if (!queryRunner.isTransactionActive) {
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
transactionStarted = true;
|
|
}
|
|
|
|
const user = await queryRunner.manager.findOne(this.userRepository.target, { where: { id: userId } });
|
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
|
|
|
if (user.financialType && user.financialType === FinancialType.LEGAL)
|
|
throw new BadRequestException(UserMessage.FINANCIAL_TYPE_IS_LEGAL);
|
|
|
|
const existingRealUser = await queryRunner.manager.findOne(this.realUserRepository.target, { where: { user: { id: userId } } });
|
|
if (existingRealUser) throw new BadRequestException(UserMessage.REAL_DATA_EXIST);
|
|
|
|
const duplicateChecks = await Promise.all([
|
|
queryRunner.manager.findOne(this.realUserRepository.target, { where: { nationalCode: createDto.nationalCode } }),
|
|
queryRunner.manager.findOne(this.realUserRepository.target, { where: { phone: createDto.phone } }),
|
|
]);
|
|
|
|
if (duplicateChecks[0]) throw new BadRequestException(UserMessage.NATIONAL_CODE_EXIST);
|
|
if (duplicateChecks[1]) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
|
|
|
const { city } = await this.addressService.getCity(+createDto.cityId);
|
|
|
|
const realUser = queryRunner.manager.create(this.realUserRepository.target, {
|
|
...createDto,
|
|
user,
|
|
address: {
|
|
fullAddress: createDto.address,
|
|
city,
|
|
postalCode: createDto.postalCode,
|
|
},
|
|
});
|
|
|
|
await queryRunner.manager.save(realUser);
|
|
|
|
user.financialType = FinancialType.REAL;
|
|
await queryRunner.manager.save(user);
|
|
|
|
if (transactionStarted) await queryRunner.commitTransaction();
|
|
|
|
return {
|
|
message: CommonMessage.CREATED,
|
|
realUser,
|
|
};
|
|
} catch (error) {
|
|
if (transactionStarted) await queryRunner.rollbackTransaction();
|
|
|
|
throw error;
|
|
} finally {
|
|
if (transactionStarted) await queryRunner.release();
|
|
}
|
|
}
|
|
|
|
// /************************************************************ */
|
|
|
|
async createLegalUserData(createDto: CreateLegalUserDto, userId: string, queryRunner = this.dataSource.createQueryRunner()) {
|
|
let transactionStarted = false;
|
|
|
|
try {
|
|
if (!queryRunner.isTransactionActive) {
|
|
await queryRunner.connect();
|
|
await queryRunner.startTransaction();
|
|
transactionStarted = true;
|
|
}
|
|
|
|
const user = await queryRunner.manager.findOne(this.userRepository.target, { where: { id: userId } });
|
|
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
|
|
|
if (user.financialType && user.financialType === FinancialType.REAL)
|
|
throw new BadRequestException(UserMessage.FINANCIAL_TYPE_IS_REAL);
|
|
|
|
const existingLegalUser = await queryRunner.manager.findOne(this.legalUserRepository.target, { where: { user: { id: user.id } } });
|
|
|
|
if (existingLegalUser) throw new BadRequestException(UserMessage.LEGAL_DATA_EXIST);
|
|
|
|
const duplicateChecks = await Promise.all([
|
|
queryRunner.manager.findOne(this.legalUserRepository.target, { where: { economicCode: createDto.economicCode } }),
|
|
queryRunner.manager.findOne(this.legalUserRepository.target, { where: { phone: createDto.phone } }),
|
|
queryRunner.manager.findOne(this.legalUserRepository.target, { where: { registrationCode: createDto.registrationCode } }),
|
|
queryRunner.manager.findOne(this.legalUserRepository.target, { where: { nationalIdentity: createDto.nationalIdentity } }),
|
|
]);
|
|
|
|
if (duplicateChecks[0]) throw new BadRequestException(UserMessage.ECONOMIC_CODE_EXIST);
|
|
if (duplicateChecks[1]) throw new BadRequestException(UserMessage.PHONE_EXIST);
|
|
if (duplicateChecks[2]) throw new BadRequestException(UserMessage.REGISTRATION_CODE_EXIST);
|
|
if (duplicateChecks[3]) throw new BadRequestException(UserMessage.NATIONAL_IDENTITY_EXIST);
|
|
|
|
const { city } = await this.addressService.getCity(+createDto.cityId);
|
|
|
|
const legalUser = queryRunner.manager.create(this.legalUserRepository.target, {
|
|
...createDto,
|
|
user,
|
|
address: {
|
|
fullAddress: createDto.address,
|
|
city,
|
|
postalCode: createDto.postalCode,
|
|
},
|
|
});
|
|
|
|
await queryRunner.manager.save(legalUser);
|
|
|
|
user.financialType = FinancialType.LEGAL;
|
|
await queryRunner.manager.save(user);
|
|
|
|
if (transactionStarted) await queryRunner.commitTransaction();
|
|
|
|
return {
|
|
message: CommonMessage.CREATED,
|
|
legalUser,
|
|
};
|
|
} catch (error) {
|
|
if (transactionStarted) await queryRunner.rollbackTransaction();
|
|
|
|
throw error;
|
|
} finally {
|
|
if (transactionStarted) await queryRunner.release();
|
|
}
|
|
}
|
|
|
|
/************************************************************ */
|
|
|
|
async getCustomers(queryDto: SearchCustomersDto) {
|
|
const [customers, count] = await this.userRepository.getCustomer(queryDto);
|
|
|
|
return { customers, count };
|
|
}
|
|
|
|
/************************************************************ */
|
|
|
|
async getCustomerById(userId: string) {
|
|
const customer = await this.userRepository.findOne({
|
|
where: { id: userId, roles: { name: RoleEnum.USER } },
|
|
relations: { legalUser: { address: { city: { province: true } } }, realUser: { address: { city: { province: true } } } },
|
|
});
|
|
|
|
return { customer };
|
|
}
|
|
}
|