Merge branch 'main' of https://github.com/Danakcorp/Dlearn_backEnd
This commit is contained in:
@@ -41,8 +41,4 @@ export class CreatePaymentDto {
|
|||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
@ApiProperty({ type: "string", description: "the course id ", example: "66d9ab8b45818616a48bc322" })
|
@ApiProperty({ type: "string", description: "the course id ", example: "66d9ab8b45818616a48bc322" })
|
||||||
courseId: string;
|
courseId: string;
|
||||||
|
|
||||||
@IsNotEmpty()
|
|
||||||
@ApiProperty({ type: Number, description: "the amount of payment", example: 10000 })
|
|
||||||
amount: number;
|
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ export class PaymentController {
|
|||||||
@Post()
|
@Post()
|
||||||
@HttpCode(HttpStatus.CREATED)
|
@HttpCode(HttpStatus.CREATED)
|
||||||
async create(@Body() createPaymentDto: CreatePaymentDto, @CurrentUser() user) {
|
async create(@Body() createPaymentDto: CreatePaymentDto, @CurrentUser() user) {
|
||||||
return this.paymentService.createPayment(user.id, createPaymentDto.amount, createPaymentDto.courseId);
|
return this.paymentService.createPayment(user.id, createPaymentDto.courseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation({
|
@ApiOperation({
|
||||||
@@ -53,7 +53,7 @@ export class PaymentController {
|
|||||||
description: 'get authority',
|
description: 'get authority',
|
||||||
})
|
})
|
||||||
@ApiQuery({
|
@ApiQuery({
|
||||||
name: 'status',
|
name: 'Status',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
description: 'get status',
|
description: 'get status',
|
||||||
})
|
})
|
||||||
@@ -63,4 +63,29 @@ export class PaymentController {
|
|||||||
return this.paymentService.verifyPayment(authority, status);
|
return this.paymentService.verifyPayment(authority, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'دریافت لیست پرداخت ها ==> Login as admin',
|
||||||
|
})
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Roles(Role.Admin)
|
||||||
|
@Get('/admin')
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
async getPayments() {
|
||||||
|
return this.paymentService.getPayments();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ApiOperation({
|
||||||
|
summary: 'دریافت لیست پرداخت ها ==> Login as user',
|
||||||
|
})
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Roles(Role.User)
|
||||||
|
@Get('/user')
|
||||||
|
@HttpCode(HttpStatus.OK)
|
||||||
|
async getPaymentsByUser(@CurrentUser() user) {
|
||||||
|
const userId = user.id;
|
||||||
|
return this.paymentService.getPaymentsByUser(userId);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import { Logger, Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
import { UserModule } from '../user/user.module';
|
import { UserModule } from '../user/user.module';
|
||||||
import { UserDataAccess } from '../../dataAccess/user.dataAccess';
|
import { UserDataAccess } from '../../dataAccess/user.dataAccess';
|
||||||
import { PaymentService } from './payment.service';
|
import { PaymentService } from './payment.service';
|
||||||
import { PaymentController } from './payment.controller';
|
import { PaymentController } from './payment.controller';
|
||||||
import { PaymentDataAccess } from 'src/dataAccess/payment.dataAccess';
|
import { PaymentDataAccess } from '../../dataAccess/payment.dataAccess';
|
||||||
import { PaymentGateway } from '../IPG/PaymentGateway';
|
import { PaymentGateway } from '../IPG/PaymentGateway';
|
||||||
import { ZarinPalGateway } from '../IPG/gateways/zarinpal';
|
import { ZarinPalGateway } from '../IPG/gateways/zarinpal';
|
||||||
|
import { PurchaseDataAccess } from '../../dataAccess/purchase.dataAccess';
|
||||||
|
import { CourseDataAccess } from '../../dataAccess/course.dataAccess';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -15,9 +17,11 @@ import { ZarinPalGateway } from '../IPG/gateways/zarinpal';
|
|||||||
providers: [
|
providers: [
|
||||||
ZarinPalGateway,
|
ZarinPalGateway,
|
||||||
PaymentDataAccess,
|
PaymentDataAccess,
|
||||||
|
PurchaseDataAccess,
|
||||||
PaymentGateway,
|
PaymentGateway,
|
||||||
PaymentService,
|
PaymentService,
|
||||||
UserDataAccess,
|
UserDataAccess,
|
||||||
|
CourseDataAccess
|
||||||
],
|
],
|
||||||
exports: []
|
exports: []
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import { Injectable, Logger } from "@nestjs/common";
|
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
|
||||||
import { PaymentDataAccess } from "../../dataAccess/payment.dataAccess";
|
import { PaymentDataAccess } from "../../dataAccess/payment.dataAccess";
|
||||||
import { startSession } from "mongoose";
|
import mongoose, { Mongoose, startSession } from "mongoose";
|
||||||
import { PaymentGateway } from "../IPG/PaymentGateway";
|
import { PaymentGateway } from "../IPG/PaymentGateway";
|
||||||
import { UserDataAccess } from "../../dataAccess/user.dataAccess";
|
import { UserDataAccess } from "../../dataAccess/user.dataAccess";
|
||||||
|
import { PurchaseDataAccess } from "../../dataAccess/purchase.dataAccess";
|
||||||
|
import { CourseDataAccess } from "../../dataAccess/course.dataAccess";
|
||||||
|
import { PaymentStatus } from "../../common/eNums/paymentStatus.enum";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class PaymentService {
|
export class PaymentService {
|
||||||
@@ -11,26 +14,94 @@ export class PaymentService {
|
|||||||
private readonly paymentDataAccess: PaymentDataAccess,
|
private readonly paymentDataAccess: PaymentDataAccess,
|
||||||
private readonly paymentGateway: PaymentGateway,
|
private readonly paymentGateway: PaymentGateway,
|
||||||
private readonly userDataAccess: UserDataAccess,
|
private readonly userDataAccess: UserDataAccess,
|
||||||
|
private readonly purchaseDataAccess: PurchaseDataAccess,
|
||||||
|
private readonly courseDataAccess: CourseDataAccess
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async createPayment(userId: string, amount: number, courseId: string) {
|
async createPayment(userId: string, courseId: string) {
|
||||||
const session = await startSession();
|
const session = await startSession();
|
||||||
session.startTransaction();
|
session.startTransaction();
|
||||||
try {
|
try {
|
||||||
const paymentData = await this.paymentGateway.requestPayment({ amount, userId, callbackPath: "cart" });
|
const user = await this.userDataAccess.findOne(userId);
|
||||||
console.log(paymentData)
|
const course = await this.courseDataAccess.getOneCourse(courseId);
|
||||||
if (!paymentData) {
|
if (!course) {
|
||||||
throw new Error("Error in payment process");
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
status: HttpStatus.BAD_REQUEST,
|
||||||
|
error: 'دوره مورد نظر یافت نشد',
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
const courseExists = user.courseIds.find(id => id.equals(courseId));
|
||||||
|
if (courseExists) {
|
||||||
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
status: HttpStatus.BAD_REQUEST,
|
||||||
|
error: 'شما قبلا این دوره را خریداری کرده اید',
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (course.price === 0) {
|
||||||
|
// Handle free course registration
|
||||||
|
const transactionNumber = `FREE-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
|
||||||
|
const payment = await this.paymentDataAccess.createPayment(
|
||||||
|
userId,
|
||||||
|
0,
|
||||||
|
courseId,
|
||||||
|
transactionNumber,
|
||||||
|
'FREE',
|
||||||
|
session
|
||||||
|
);
|
||||||
|
|
||||||
|
await session.commitTransaction();
|
||||||
|
|
||||||
|
await this.purchaseDataAccess.createPurchase(payment.userId.toString(), payment.courseId.toString(), payment._id.toString());
|
||||||
|
|
||||||
|
payment.paymentStatus = PaymentStatus.Completed;
|
||||||
|
await this.paymentDataAccess.updatePaymentStatus(payment._id.toString(), PaymentStatus.Completed);
|
||||||
|
|
||||||
|
const registerCourse = await this.userDataAccess.registerCourse(payment.userId, payment.courseId);
|
||||||
|
if (!registerCourse.success) {
|
||||||
|
if (!payment) {
|
||||||
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
status: HttpStatus.BAD_REQUEST,
|
||||||
|
error: 'درخواست خرید دوره با مشکل مواجه شد',
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await session.commitTransaction();
|
||||||
|
await session.endSession();
|
||||||
|
|
||||||
|
return { success: true, payment: payment }
|
||||||
|
}
|
||||||
|
|
||||||
|
const paymentData = await this.paymentGateway.requestPayment({ amount: course.price, userId, callbackPath: "cart" });
|
||||||
|
if (!paymentData) {
|
||||||
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
status: HttpStatus.BAD_REQUEST,
|
||||||
|
error: 'درخواست خرید دوره با مشکل مواجه شد',
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const transactionNumber = `DLR-${Date.now()}-${Math.floor(Math.random() * 10000)}`;
|
||||||
|
|
||||||
const payment = await this.paymentDataAccess.createPayment(
|
const payment = await this.paymentDataAccess.createPayment(
|
||||||
userId,
|
userId,
|
||||||
amount,
|
course.price, //amount
|
||||||
courseId,
|
courseId,
|
||||||
|
transactionNumber,
|
||||||
paymentData.authority,
|
paymentData.authority,
|
||||||
session
|
session
|
||||||
);
|
);
|
||||||
console.log({ payment })
|
|
||||||
await session.commitTransaction();
|
await session.commitTransaction();
|
||||||
await session.endSession();
|
await session.endSession();
|
||||||
return { payment: payment, paymentData }
|
return { payment: payment, paymentData }
|
||||||
@@ -38,6 +109,7 @@ export class PaymentService {
|
|||||||
await session.abortTransaction();
|
await session.abortTransaction();
|
||||||
await session.endSession();
|
await session.endSession();
|
||||||
this.logger.warn(error);
|
this.logger.warn(error);
|
||||||
|
return error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,13 +123,32 @@ export class PaymentService {
|
|||||||
}
|
}
|
||||||
const verifyData = await this.paymentGateway.verifyPayment({ authority, amount: paymentData.amount });
|
const verifyData = await this.paymentGateway.verifyPayment({ authority, amount: paymentData.amount });
|
||||||
if (verifyData.code === 100 || verifyData.code === 101) {
|
if (verifyData.code === 100 || verifyData.code === 101) {
|
||||||
|
await this.purchaseDataAccess.createPurchase(paymentData.userId.toString(), paymentData.courseId.toString(), paymentData._id.toString());
|
||||||
|
paymentData.paymentStatus = PaymentStatus.Completed;
|
||||||
|
await paymentData.save();
|
||||||
const registerCourse = await this.userDataAccess.registerCourse(paymentData.userId, paymentData.courseId);
|
const registerCourse = await this.userDataAccess.registerCourse(paymentData.userId, paymentData.courseId);
|
||||||
console.log(registerCourse)
|
|
||||||
if (!registerCourse.success) {
|
if (!registerCourse.success) {
|
||||||
throw new Error("error in register course");
|
if (!paymentData) {
|
||||||
|
throw new HttpException(
|
||||||
|
{
|
||||||
|
status: HttpStatus.BAD_REQUEST,
|
||||||
|
error: 'درخواست خرید دوره با مشکل مواجه شد',
|
||||||
|
},
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return { success: true, payment: paymentData, verifyData }
|
return { success: true, payment: paymentData, verifyData }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getPayments() {
|
||||||
|
return this.paymentDataAccess.getPayments();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getPaymentsByUser(userId: string) {
|
||||||
|
return this.paymentDataAccess.getPaymentsByUserId(userId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ export class UserService {
|
|||||||
await this.courseHeadlineDataAccess.getCourseHeadlines(item._id);
|
await this.courseHeadlineDataAccess.getCourseHeadlines(item._id);
|
||||||
const totalHeadlines = courseHeadlines.length;
|
const totalHeadlines = courseHeadlines.length;
|
||||||
let completionPercentage = 0;
|
let completionPercentage = 0;
|
||||||
console.log(result.courseHeadlineProgress);
|
|
||||||
if (result.courseHeadlineProgress) {
|
if (result.courseHeadlineProgress) {
|
||||||
const completedHeadlines = result.courseHeadlineProgress.filter(
|
const completedHeadlines = result.courseHeadlineProgress.filter(
|
||||||
(progress) =>
|
(progress) =>
|
||||||
@@ -46,7 +45,6 @@ export class UserService {
|
|||||||
arr.push({ item, completionPercentage });
|
arr.push({ item, completionPercentage });
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
console.log(arr);
|
|
||||||
|
|
||||||
return { user: userObj(result), com: arr };
|
return { user: userObj(result), com: arr };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,20 @@
|
|||||||
|
import mongoose from "mongoose";
|
||||||
import Models from "../models";
|
import Models from "../models";
|
||||||
import Payment from "../models/payment.model";
|
import Payment from "../models/payment.model";
|
||||||
|
|
||||||
export class PaymentDataAccess {
|
export class PaymentDataAccess {
|
||||||
async createPayment(userId: string, amount: number, courseId: string, authority: string, session: any): Promise<Payment> {
|
async createPayment(userId: string, amount: number, courseId: string,transactionNumber:string ,authority: string, session: any): Promise<Payment> {
|
||||||
const paymentDoc = await Models.Payment.create([{ userId, amount, courseId, authority }], { session });
|
const paymentDoc = await Models.Payment.create([{ userId, amount, courseId, transactionNumber, authority }], { session });
|
||||||
console.log({ paymentDoc });
|
console.log({ paymentDoc });
|
||||||
const payment = paymentDoc.map(doc => doc.toObject())[0];
|
const payment = paymentDoc.map(doc => doc.toObject())[0];
|
||||||
return payment;
|
return payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updatePaymentStatus(paymentId: string,status: string) {
|
||||||
|
const updatedPayment = await Models.Payment.findByIdAndUpdate(paymentId, { paymentStatus: status }, { new: true });
|
||||||
|
return updatedPayment;
|
||||||
|
}
|
||||||
|
|
||||||
async getPayment(paymentId: string): Promise<Payment | null> {
|
async getPayment(paymentId: string): Promise<Payment | null> {
|
||||||
const payment = await Models.Payment.findById(paymentId);
|
const payment = await Models.Payment.findById(paymentId);
|
||||||
return payment;
|
return payment;
|
||||||
@@ -20,13 +26,73 @@ export class PaymentDataAccess {
|
|||||||
console.log(payment, "ssssss")
|
console.log(payment, "ssssss")
|
||||||
return payment;
|
return payment;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPaymentsByUserId(userId: string): Promise<Payment[]> {
|
async getPaymentsByUserId(userId: string): Promise<Payment[]> {
|
||||||
const payments = await Models.Payment.find({ userId });
|
const payments = await Models.Payment.aggregate([
|
||||||
|
{
|
||||||
|
$match: { userId: new mongoose.Types.ObjectId(userId) }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "courses",
|
||||||
|
localField: "courseId",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "course",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$unwind: "$course",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$sort: { createdAt: -1 }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$project: {
|
||||||
|
_id:1,
|
||||||
|
authority: 1,
|
||||||
|
amount: 1,
|
||||||
|
transactionNumber: 1,
|
||||||
|
paymentStatus: 1,
|
||||||
|
course: {
|
||||||
|
name: 1,
|
||||||
|
slug: 1,
|
||||||
|
image: 1,
|
||||||
|
price: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]);
|
||||||
return payments;
|
return payments;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPayments(): Promise<Payment[]> {
|
async getPayments(): Promise<Payment[]> {
|
||||||
const payments = await Models.Payment.find();
|
const payments = await Models.Payment.aggregate([
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "users",
|
||||||
|
localField: "userId",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "user",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$unwind: "$user",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$lookup: {
|
||||||
|
from: "courses",
|
||||||
|
localField: "courseId",
|
||||||
|
foreignField: "_id",
|
||||||
|
as: "course",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$unwind: "$course",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$sort: { createdAt: -1 }
|
||||||
|
}
|
||||||
|
]);
|
||||||
return payments;
|
return payments;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@ import UserDiscount from './userDiscount.model';
|
|||||||
import Rate from './rate.model';
|
import Rate from './rate.model';
|
||||||
import Payment from './payment.model';
|
import Payment from './payment.model';
|
||||||
import Settings from './settings.model';
|
import Settings from './settings.model';
|
||||||
import Purchase from './Purchase.model';
|
import Purchase from './purchase.model';
|
||||||
|
|
||||||
const Models = {
|
const Models = {
|
||||||
User,
|
User,
|
||||||
|
|||||||
Reference in New Issue
Block a user