Files
dsc-api/src/modules/users/providers/customers.service.ts
T
2025-04-19 09:46:10 +03:30

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 };
}
}