chore: complete payment service but not tested
This commit is contained in:
@@ -2,3 +2,7 @@
|
||||
export const AUTH_THROTTLE_TTL = 5 * 60 * 1000;
|
||||
export const AUTH_THROTTLE_LIMIT = 5;
|
||||
export const JWT_STRATEGY_NAME = "jwt_Strategy";
|
||||
|
||||
export const PAYMENT = Object.freeze({
|
||||
PAYMENT_QUEUE: "payment",
|
||||
});
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import { OnWorkerEvent, WorkerHost } from "@nestjs/bullmq";
|
||||
import { Logger } from "@nestjs/common";
|
||||
import { Job } from "bullmq";
|
||||
|
||||
export abstract class WorkerProcessor extends WorkerHost {
|
||||
protected readonly logger = new Logger(WorkerProcessor.name);
|
||||
|
||||
@OnWorkerEvent("completed")
|
||||
onCompleted(job: Job) {
|
||||
const { id, name, queueName, finishedOn, returnvalue } = job;
|
||||
const completionTime = finishedOn ? new Date(finishedOn).toISOString() : "";
|
||||
this.logger.log(`Job id: ${id}, name: ${name} completed in queue ${queueName} on ${completionTime}. Result: ${returnvalue}`);
|
||||
}
|
||||
|
||||
@OnWorkerEvent("progress")
|
||||
onProgress(job: Job) {
|
||||
const { id, name, progress } = job;
|
||||
this.logger.log(`Job id: ${id}, name: ${name} completes ${progress}%`);
|
||||
}
|
||||
|
||||
@OnWorkerEvent("failed")
|
||||
onFailed(job: Job) {
|
||||
const { id, name, queueName, failedReason } = job;
|
||||
this.logger.error(`Job id: ${id}, name: ${name} failed in queue ${queueName}. Failed reason: ${failedReason}`);
|
||||
}
|
||||
|
||||
@OnWorkerEvent("active")
|
||||
onActive(job: Job) {
|
||||
const { id, name, queueName, timestamp } = job;
|
||||
const startTime = timestamp ? new Date(timestamp).toISOString() : "";
|
||||
this.logger.log(`Job id: ${id}, name: ${name} starts in queue ${queueName} on ${startTime}.`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { SharedBullAsyncConfiguration } from "@nestjs/bullmq";
|
||||
import { ConfigService } from "@nestjs/config";
|
||||
|
||||
export function bullMqConfig(): SharedBullAsyncConfiguration {
|
||||
return {
|
||||
inject: [ConfigService],
|
||||
useFactory: async (configService: ConfigService) => ({
|
||||
connection: {
|
||||
url: configService.getOrThrow<string>("REDIS_URI"),
|
||||
},
|
||||
defaultJobOptions: {
|
||||
removeOnComplete: 1000,
|
||||
removeOnFail: 5000,
|
||||
attempts: 3,
|
||||
},
|
||||
}),
|
||||
};
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import { BadRequestException, Injectable, Logger } from "@nestjs/common";
|
||||
import { DataSource } from "typeorm";
|
||||
|
||||
import { TokensService } from "./tokens.service";
|
||||
import { AuthMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||
@@ -20,6 +21,7 @@ export class AuthService {
|
||||
private readonly passwordService: PasswordService,
|
||||
private readonly otpService: OTPService,
|
||||
private readonly tokensService: TokensService,
|
||||
private readonly dataSource: DataSource,
|
||||
) {}
|
||||
//****************** */
|
||||
//****************** */
|
||||
@@ -48,20 +50,33 @@ export class AuthService {
|
||||
//****************** */
|
||||
async completeRegistration(completeRegistrationDto: CompleteRegistrationDto) {
|
||||
const { phone, code } = completeRegistrationDto;
|
||||
const isValid = await this.otpService.verifyOtp(phone, code, "REGISTER");
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
|
||||
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
try {
|
||||
const isValid = await this.otpService.verifyOtp(phone, code, "REGISTER");
|
||||
|
||||
await this.otpService.delOtpFormCache(phone, "REGISTER");
|
||||
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
|
||||
const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword);
|
||||
if (!isValid) throw new BadRequestException(AuthMessage.INVALID_OTP);
|
||||
|
||||
const tokens = this.tokensService.generateAccessAndRefreshToken({ sub: user.id, role: user.role.name });
|
||||
await this.otpService.delOtpFormCache(phone, "REGISTER");
|
||||
const hashedPassword = await this.passwordService.hashPassword(completeRegistrationDto.password);
|
||||
const user = await this.usersService.createUser(completeRegistrationDto, hashedPassword, queryRunner);
|
||||
|
||||
return {
|
||||
message: AuthMessage.USER_REGISTER_SUCCESS,
|
||||
...tokens,
|
||||
};
|
||||
const tokens = this.tokensService.generateAccessAndRefreshToken({ sub: user.id, role: user.role.name });
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return {
|
||||
message: AuthMessage.USER_REGISTER_SUCCESS,
|
||||
...tokens,
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
//****************** */
|
||||
//****************** */
|
||||
|
||||
@@ -3,17 +3,8 @@ import { Column, Entity, ManyToOne } from "typeorm";
|
||||
import { BankAccount } from "./bank-account.entity";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
|
||||
export enum PaymentMethodType {
|
||||
CARD_TO_CARD = "CARD_TO_CARD",
|
||||
GATEWAY = "GATEWAY",
|
||||
SHEBA = "SHEBA",
|
||||
}
|
||||
|
||||
@Entity()
|
||||
export class PaymentMethod extends BaseEntity {
|
||||
@Column({ type: "enum", enum: PaymentMethodType, default: PaymentMethodType.GATEWAY })
|
||||
type: PaymentMethodType;
|
||||
|
||||
@ManyToOne(() => BankAccount, { nullable: true, onDelete: "SET NULL" })
|
||||
bankAccount?: BankAccount;
|
||||
|
||||
@@ -22,7 +13,4 @@ export class PaymentMethod extends BaseEntity {
|
||||
|
||||
@Column({ type: "text", nullable: true })
|
||||
description?: string;
|
||||
|
||||
@Column({ type: "boolean", default: true })
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PaymentMethod } from "./payment-method.entity";
|
||||
import { BaseEntity } from "../../../common/entities/base.entity";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
import { PaymentStatus } from "../enums/payment-status.enum";
|
||||
import { PaymentType } from "../enums/payment-type.enum";
|
||||
|
||||
@Entity()
|
||||
export class Payment extends BaseEntity {
|
||||
@@ -19,6 +20,9 @@ export class Payment extends BaseEntity {
|
||||
@Column({ type: "enum", enum: PaymentStatus, default: PaymentStatus.PENDING })
|
||||
status: PaymentStatus;
|
||||
|
||||
@Column({ type: "enum", enum: PaymentType, nullable: false })
|
||||
type: PaymentType;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.payments, { nullable: false, onDelete: "RESTRICT" })
|
||||
user: User;
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
export enum PaymentType {
|
||||
CARD_TO_CARD = "CARD_TO_CARD",
|
||||
GATEWAY = "GATEWAY",
|
||||
SHEBA = "SHEBA",
|
||||
}
|
||||
@@ -15,4 +15,7 @@ export class PaymentsController {
|
||||
getAvailableGateways() {
|
||||
return this.paymentsService.getAvailableGateways();
|
||||
}
|
||||
|
||||
@Get("verify")
|
||||
verifyPayment() {}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { QueryRunner } from "typeorm";
|
||||
|
||||
import { WalletMessage } from "../../../common/enums/message.enum";
|
||||
import { User } from "../../users/entities/user.entity";
|
||||
// import { PaymentMethod } from "../entities/payment-method.entity";
|
||||
import { PaymentMethod } from "../entities/payment-method.entity";
|
||||
import { Payment } from "../entities/payment.entity";
|
||||
import { PaymentType } from "../enums/payment-type.enum";
|
||||
import { PaymentGatewayFactory } from "../factories/payment.factory";
|
||||
// import { PaymentsRepository } from "../repositories/payments.repository";
|
||||
import { GatewayType } from "../types/gateway.type";
|
||||
@@ -22,13 +24,20 @@ export class PaymentsService {
|
||||
}
|
||||
//*********************************** */
|
||||
//*********************************** */
|
||||
async createPaymentForUser(user: User, amount: number, reference: string, queryRunner: QueryRunner) {
|
||||
// const paymentMethod = queryRunner.manager.create(PaymentMethod, {});
|
||||
async createPaymentForUser(user: User, amount: number, reference: string, gateway: GatewayType, queryRunner: QueryRunner) {
|
||||
const paymentMethod = queryRunner.manager.create(PaymentMethod, {
|
||||
gatewayName: gateway,
|
||||
description: WalletMessage.DEPOSIT_WALLET_IPG,
|
||||
});
|
||||
|
||||
await queryRunner.manager.save(PaymentMethod, paymentMethod);
|
||||
|
||||
const payment = queryRunner.manager.create(Payment, {
|
||||
type: PaymentType.GATEWAY,
|
||||
amount,
|
||||
reference,
|
||||
user,
|
||||
paymentMethod,
|
||||
});
|
||||
|
||||
await queryRunner.manager.save(Payment, payment);
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Processor } from "@nestjs/bullmq";
|
||||
import { Logger } from "@nestjs/common";
|
||||
import { Job } from "bullmq";
|
||||
|
||||
import { PAYMENT } from "../../../common/constants";
|
||||
import { WorkerProcessor } from "../../../common/queues/worker.processor";
|
||||
|
||||
@Processor(PAYMENT.PAYMENT_QUEUE)
|
||||
export class PaymentProcessor extends WorkerProcessor {
|
||||
protected readonly logger = new Logger(PaymentProcessor.name);
|
||||
|
||||
process(job: Job, token?: string) {
|
||||
this.logger.log(job, token);
|
||||
return Promise.resolve("test");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
export enum NotifSettingsEnum {
|
||||
ANNOUNCE_NOTIF = "ANNOUNCE_NOTIF",
|
||||
BILL_PAYMENT = "BILL_PAYMENT",
|
||||
CREATE_SERIVCE = "CREATE_SERIVCE",
|
||||
CREATE_SERVICE = "CREATE_SERVICE",
|
||||
UNBLOCKING_SERVICE = "UNBLOCKING_SERVICE",
|
||||
ANSWER_TICKET = "ANSWER_TICKET",
|
||||
CREATE_INVOICE = "CREATE_INVOICE",
|
||||
@@ -13,7 +13,7 @@ export enum NotifSettingsEnum {
|
||||
export enum FarsiNotifSettingsEnum {
|
||||
ANNOUNCE_NOTIF = "اعلانات و اطلاعیه ها",
|
||||
BILL_PAYMENT = "پرداخت صورت حساب",
|
||||
CREATE_SERIVCE = "ایجاد سرویس",
|
||||
CREATE_SERVICE = "ایجاد سرویس",
|
||||
UNBLOCKING_SERVICE = "رفع انسداد سرویس",
|
||||
ANSWER_TICKET = "پاسخ تیکت",
|
||||
CREATE_INVOICE = "ایجاد صورت حساب",
|
||||
|
||||
@@ -44,7 +44,7 @@ export const userSettings = [
|
||||
},
|
||||
},
|
||||
{
|
||||
title: NotifSettingsEnum.CREATE_SERIVCE,
|
||||
title: NotifSettingsEnum.CREATE_SERVICE,
|
||||
fields: {
|
||||
sms: true,
|
||||
email: false,
|
||||
|
||||
@@ -12,31 +12,31 @@ import { UserSettingsRepository } from "../repositories/user-settings.repository
|
||||
@Injectable()
|
||||
export class UserSettingsService {
|
||||
constructor(private readonly userSettingsRepository: UserSettingsRepository) {}
|
||||
//*+*******************************************
|
||||
|
||||
async createUserSettings(userId: string, queryRunner: QueryRunner) {
|
||||
const user = await queryRunner.manager.findOneBy(User, {
|
||||
id: userId,
|
||||
});
|
||||
if (!user) throw new BadRequestException(UserMessage.USER_NOT_FOUND);
|
||||
|
||||
for (const setting of userSettings) {
|
||||
const notifSetting = await queryRunner.manager.findOneBy(NotifSetting, {
|
||||
title: setting.title,
|
||||
});
|
||||
console.log({ notifSetting });
|
||||
if (!notifSetting) throw new BadRequestException(SettingMessageEnum.NOTIF_NOT_FOUND);
|
||||
const userSetting = queryRunner.manager.create(UserSetting, {
|
||||
...setting,
|
||||
notifSetting,
|
||||
user,
|
||||
});
|
||||
console.log({ userSetting });
|
||||
await queryRunner.manager.save(userSetting);
|
||||
}
|
||||
return {
|
||||
message: CommonMessage.CREATED,
|
||||
};
|
||||
}
|
||||
|
||||
//*+*******************************************
|
||||
async getSettings(userId: string) {
|
||||
const settings = await this.userSettingsRepository.find({
|
||||
where: {
|
||||
@@ -51,6 +51,7 @@ export class UserSettingsService {
|
||||
});
|
||||
return { settings };
|
||||
}
|
||||
//*+*******************************************
|
||||
|
||||
async updateUserSetting(settingId: string, updateDto: UpdateUserSettingsDto) {
|
||||
const setting = await this.userSettingsRepository.findOne({
|
||||
|
||||
@@ -14,7 +14,7 @@ import { TicketMessageAttachment } from "./entities/ticket-message-attachment";
|
||||
import { TicketMessageAttachmentsRepository } from "./repositories/ticket-message-attachment.repository";
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Ticket, TicketCategory, TicketMessage, TicketMessageAttachment]), UsersModule],
|
||||
imports: [TypeOrmModule.forFeature([Ticket, TicketCategory, TicketMessageAttachment, TicketMessage]), UsersModule],
|
||||
providers: [TicketsService, TicketsRepository, TicketCategoryRepository, TicketMessagesRepository, TicketMessageAttachmentsRepository],
|
||||
controllers: [TicketsController],
|
||||
exports: [TicketsService],
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { BadRequestException, Injectable } from "@nestjs/common";
|
||||
import slugify from "slugify";
|
||||
import { DataSource, In, Not } from "typeorm";
|
||||
import { In, Not, QueryRunner } from "typeorm";
|
||||
|
||||
// import { roles } from "../../../../database/seeders/role.seeder";
|
||||
import { CommonMessage, UserMessage } from "../../../common/enums/message.enum";
|
||||
import { CompleteRegistrationDto } from "../../auth/DTO/complete-register.dto";
|
||||
import { UserSettingsService } from "../../settings/providers/user-settings.service";
|
||||
import { WalletsService } from "../../wallets/providers/wallets.service";
|
||||
import { CheckValidityDTO } from "../DTO/check-validity.dto";
|
||||
import { UpdateProfileDto } from "../DTO/update-profile.dto";
|
||||
import { CreateUserGroupDto } from "../DTO/user-group.dto";
|
||||
@@ -33,10 +33,10 @@ export class UsersService {
|
||||
},
|
||||
};
|
||||
constructor(
|
||||
private userRepository: UserRepository,
|
||||
private userGroupRepository: UserGroupRepository,
|
||||
private readonly userRepository: UserRepository,
|
||||
private readonly userGroupRepository: UserGroupRepository,
|
||||
private readonly userSettingsService: UserSettingsService,
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly walletsService: WalletsService,
|
||||
) {}
|
||||
|
||||
/************************************************************ */
|
||||
@@ -91,37 +91,22 @@ export class UsersService {
|
||||
|
||||
/************************************************************ */
|
||||
|
||||
async createUser(registerDto: CompleteRegistrationDto, hashedPassword: string): Promise<User> {
|
||||
const queryRunner = this.dataSource.createQueryRunner();
|
||||
async createUser(registerDto: CompleteRegistrationDto, hashedPassword: string, queryRunner: QueryRunner): Promise<User> {
|
||||
const role = await queryRunner.manager.findOne(Role, { where: { name: RoleEnum.USER } });
|
||||
if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND);
|
||||
|
||||
await queryRunner.connect();
|
||||
await queryRunner.startTransaction();
|
||||
const user = queryRunner.manager.create(User, {
|
||||
...registerDto,
|
||||
password: hashedPassword,
|
||||
role,
|
||||
});
|
||||
await queryRunner.manager.save(user);
|
||||
|
||||
try {
|
||||
const role = await queryRunner.manager.findOne(Role, {
|
||||
where: { name: RoleEnum.USER },
|
||||
});
|
||||
if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND);
|
||||
await this.userSettingsService.createUserSettings(user.id, queryRunner);
|
||||
|
||||
const user = queryRunner.manager.create(User, {
|
||||
...registerDto,
|
||||
password: hashedPassword,
|
||||
role,
|
||||
});
|
||||
await queryRunner.manager.save(user);
|
||||
|
||||
await this.userSettingsService.createUserSettings(user.id, queryRunner);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
|
||||
return user;
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
throw error;
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
await this.walletsService.createUserWallet(user.id, queryRunner);
|
||||
|
||||
return user;
|
||||
// const role = await this.roleRepository.findOneBy({ name: RoleEnum.USER });
|
||||
// if (!role) throw new BadRequestException(UserMessage.ROLE_NOT_FOUND);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Module, OnApplicationBootstrap } from "@nestjs/common";
|
||||
import { Module } from "@nestjs/common";
|
||||
import { TypeOrmModule } from "@nestjs/typeorm";
|
||||
|
||||
import { Role } from "./entities/role.entity";
|
||||
@@ -12,16 +12,12 @@ import { UsersController } from "./users.controller";
|
||||
import { UserSetting } from "../settings/entities/user-setting.entity";
|
||||
import { UserSettingsService } from "../settings/providers/user-settings.service";
|
||||
import { UserSettingsRepository } from "../settings/repositories/user-settings.repository";
|
||||
import { WalletsModule } from "../wallets/wallets.module";
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([User, Role, UserGroup, UserSetting])],
|
||||
imports: [TypeOrmModule.forFeature([User, Role, UserGroup, UserSetting]), WalletsModule],
|
||||
providers: [UsersService, UserRepository, RoleRepository, UserGroupRepository, UserSettingsRepository, UserSettingsService],
|
||||
controllers: [UsersController],
|
||||
exports: [UsersService],
|
||||
})
|
||||
export class UsersModule implements OnApplicationBootstrap {
|
||||
// constructor(private userService: UsersService) {}
|
||||
async onApplicationBootstrap() {
|
||||
// await this.userService.roleSeeder();
|
||||
}
|
||||
}
|
||||
export class UsersModule {}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { BadRequestException, HttpException, Injectable, InternalServerErrorException } from "@nestjs/common";
|
||||
import { DataSource } from "typeorm";
|
||||
import { DataSource, QueryRunner } from "typeorm";
|
||||
|
||||
import { WalletMessage } from "../../../common/enums/message.enum";
|
||||
import { PaymentsService } from "../../payments/providers/payments.service";
|
||||
@@ -42,9 +42,14 @@ export class WalletsService {
|
||||
wallet.user.phone,
|
||||
);
|
||||
|
||||
const payment = await this.paymentsService.createPaymentForUser(wallet.user, amount, gatewayData.reference, queryRunner);
|
||||
console.log(gatewayData);
|
||||
|
||||
const payment = await this.paymentsService.createPaymentForUser(wallet.user, amount, gatewayData.reference, gateway, queryRunner);
|
||||
|
||||
await queryRunner.commitTransaction();
|
||||
return {
|
||||
payment,
|
||||
...gatewayData,
|
||||
};
|
||||
} catch (error) {
|
||||
await queryRunner.rollbackTransaction();
|
||||
@@ -54,4 +59,12 @@ export class WalletsService {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************** */
|
||||
async createUserWallet(userId: string, queryRunner: QueryRunner) {
|
||||
const wallet = queryRunner.manager.create(Wallet, { balance: 0, user: { id: userId } });
|
||||
await queryRunner.manager.save(Wallet, wallet);
|
||||
//
|
||||
return wallet;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user