Spaces:
Sleeping
Sleeping
Add vnpay ipn
Browse files
backend/src/payment/payment.controller.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
// payment.controller.ts
|
2 |
-
import { Controller, Post, Body, Req, Res } from '@nestjs/common';
|
3 |
import { PaymentService } from './payment.service.js';
|
4 |
import { Request, Response } from 'express';
|
5 |
import { Public } from '../modules/authentication/authentication.decorator.js';
|
@@ -27,4 +27,11 @@ export class PaymentController {
|
|
27 |
ipAddr as string,
|
28 |
);
|
29 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
}
|
|
|
1 |
// payment.controller.ts
|
2 |
+
import { Controller, Post, Body, Req, Res, Get } from '@nestjs/common';
|
3 |
import { PaymentService } from './payment.service.js';
|
4 |
import { Request, Response } from 'express';
|
5 |
import { Public } from '../modules/authentication/authentication.decorator.js';
|
|
|
27 |
ipAddr as string,
|
28 |
);
|
29 |
}
|
30 |
+
|
31 |
+
@Public()
|
32 |
+
@Get('vnpay_ipn')
|
33 |
+
vnpayIpn(@Req() req: Request, @Body() body: any){
|
34 |
+
const reqQuery = req.query;
|
35 |
+
return this.paymentService.vnpayIpn(reqQuery)
|
36 |
+
}
|
37 |
}
|
backend/src/payment/payment.service.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
// payment.service.ts
|
2 |
-
import { Injectable } from '@nestjs/common';
|
3 |
import { ConfigService } from '@nestjs/config';
|
4 |
import * as querystring from 'qs';
|
5 |
import * as crypto from 'crypto';
|
@@ -53,26 +53,111 @@ export class PaymentService {
|
|
53 |
|
54 |
return res;
|
55 |
}
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
}
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
if (obj.hasOwnProperty(key)) {
|
69 |
-
str.push(encodeURIComponent(key));
|
70 |
-
}
|
71 |
}
|
72 |
-
|
73 |
-
|
74 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
}
|
76 |
-
|
77 |
-
|
|
|
|
|
|
|
|
|
78 |
}
|
|
|
1 |
// payment.service.ts
|
2 |
+
import { HttpStatus, Injectable } from '@nestjs/common';
|
3 |
import { ConfigService } from '@nestjs/config';
|
4 |
import * as querystring from 'qs';
|
5 |
import * as crypto from 'crypto';
|
|
|
53 |
|
54 |
return res;
|
55 |
}
|
56 |
+
|
57 |
+
|
58 |
+
vnpayIpn(reqQuery){
|
59 |
+
console.log("helloooo")
|
60 |
+
let vnp_Params = reqQuery;
|
61 |
+
let secureHash = vnp_Params['vnp_SecureHash'];
|
62 |
+
|
63 |
+
let orderId = vnp_Params['vnp_TxnRef'];
|
64 |
+
let rspCode = vnp_Params['vnp_ResponseCode'];
|
65 |
+
|
66 |
+
delete vnp_Params['vnp_SecureHash'];
|
67 |
+
delete vnp_Params['vnp_SecureHashType'];
|
68 |
+
|
69 |
+
vnp_Params = this.sortObject(vnp_Params);
|
70 |
+
let secretKey = this.configService.get('vnp_HashSecret');
|
71 |
+
let signData = querystring.stringify(vnp_Params, { encode: false });
|
72 |
+
let hmac = crypto.createHmac("sha512", secretKey);
|
73 |
+
let signed = hmac.update(Buffer.from(signData, 'utf-8')).digest("hex");
|
74 |
+
|
75 |
+
let paymentStatus = '0'; // Giả sử '0' là trạng thái khởi tạo giao dịch, chưa có IPN. Trạng thái này được lưu khi yêu cầu thanh toán chuyển hướng sang Cổng thanh toán VNPAY tại đầu khởi tạo đơn hàng.
|
76 |
+
//let paymentStatus = '1'; // Giả sử '1' là trạng thái thành công bạn cập nhật sau IPN được gọi và trả kết quả về nó
|
77 |
+
//let paymentStatus = '2'; // Giả sử '2' là trạng thái thất bại bạn cập nhật sau IPN được gọi và trả kết quả về nó
|
78 |
+
|
79 |
+
let checkOrderId = true; // Mã đơn hàng "giá trị của vnp_TxnRef" VNPAY phản hồi tồn tại trong CSDL của bạn
|
80 |
+
let checkAmount = true; // Kiểm tra số tiền "giá trị của vnp_Amout/100" trùng khớp với số tiền của đơn hàng trong CSDL của bạn
|
81 |
+
if(secureHash === signed){ //kiểm tra checksum
|
82 |
+
if(checkOrderId){
|
83 |
+
if(checkAmount){
|
84 |
+
if(paymentStatus=="0"){ //kiểm tra tình trạng giao dịch trước khi cập nhật tình trạng thanh toán
|
85 |
+
if(rspCode=="00"){
|
86 |
+
//thanh cong
|
87 |
+
//paymentStatus = '1'
|
88 |
+
// Ở đây cập nhật trạng thái giao dịch thanh toán thành công vào CSDL của bạn
|
89 |
+
console.log("Thành công")
|
90 |
+
return {
|
91 |
+
statusCode: HttpStatus.OK,
|
92 |
+
message: 'Thành công!',
|
93 |
+
data: { /* dữ liệu trả về nếu có */ },
|
94 |
+
};
|
95 |
+
}
|
96 |
+
else {
|
97 |
+
//that bai
|
98 |
+
//paymentStatus = '2'
|
99 |
+
// Ở đây cập nhật trạng thái giao dịch thanh toán thất bại vào CSDL của bạn
|
100 |
+
console.log("thất bại");
|
101 |
+
return {
|
102 |
+
statusCode: HttpStatus.OK,
|
103 |
+
message: 'Thất bại',
|
104 |
+
data: { /* dữ liệu trả về nếu có */ },
|
105 |
+
};
|
106 |
+
}
|
107 |
+
}
|
108 |
+
else{
|
109 |
+
return {
|
110 |
+
statusCode: HttpStatus.OK,
|
111 |
+
message: 'This order has been updated to the payment status',
|
112 |
+
data: { /* dữ liệu trả về nếu có */ },
|
113 |
+
};
|
114 |
+
}
|
115 |
+
}
|
116 |
+
else{
|
117 |
+
return {
|
118 |
+
statusCode: HttpStatus.OK,
|
119 |
+
message: 'Amount invalid',
|
120 |
+
data: { /* dữ liệu trả về nếu có */ },
|
121 |
+
};
|
122 |
+
}
|
123 |
+
}
|
124 |
+
else {
|
125 |
+
return {
|
126 |
+
statusCode: HttpStatus.OK,
|
127 |
+
message: 'Order not found',
|
128 |
+
data: { /* dữ liệu trả về nếu có */ },
|
129 |
+
};
|
130 |
+
}
|
131 |
+
}
|
132 |
+
else {
|
133 |
+
return {
|
134 |
+
statusCode: HttpStatus.OK,
|
135 |
+
message: 'Checksum failed!',
|
136 |
+
data: { /* dữ liệu trả về nếu có */ },
|
137 |
+
};
|
138 |
+
}
|
139 |
}
|
140 |
|
141 |
+
// Format date helper function
|
142 |
+
formatDate(date: Date, format: string): string {
|
143 |
+
const yyyymmdd = date.toISOString().slice(0, 10).replace(/-/g, ''); // YYYYMMDD
|
144 |
+
const hhmmss = date.toTimeString().slice(0, 8).replace(/:/g, ''); // HHMMSS
|
145 |
+
return format === 'yyyymmddHHmmss' ? yyyymmdd + hhmmss : hhmmss;
|
|
|
|
|
|
|
146 |
}
|
147 |
+
|
148 |
+
sortObject(obj) {
|
149 |
+
let sorted = {};
|
150 |
+
let str = [];
|
151 |
+
let key;
|
152 |
+
for (key in obj){
|
153 |
+
if (obj.hasOwnProperty(key)) {
|
154 |
+
str.push(encodeURIComponent(key));
|
155 |
+
}
|
156 |
}
|
157 |
+
str.sort();
|
158 |
+
for (key = 0; key < str.length; key++) {
|
159 |
+
sorted[str[key]] = encodeURIComponent(obj[str[key]]).replace(/%20/g, "+");
|
160 |
+
}
|
161 |
+
return sorted;
|
162 |
+
}
|
163 |
}
|