AnhLedger commited on
Commit
494e1c4
1 Parent(s): 1a3a9a4

change amount in payment service

Browse files
backend/src/modules/authentication/authentication.service.ts CHANGED
@@ -28,7 +28,7 @@ export class AuthenticationService {
28
  if (!compare) {
29
  throw new UnauthorizedException("Wrong password");
30
  }
31
- const payload = { sub: user.id, username: user.full_name, roles: user.role};
32
  return {
33
  access_token: await this.jwtService.signAsync(payload),
34
  };
 
28
  if (!compare) {
29
  throw new UnauthorizedException("Wrong password");
30
  }
31
+ const payload = { sub: user.id, username: user.full_name, role: user.role};
32
  return {
33
  access_token: await this.jwtService.signAsync(payload),
34
  };
backend/src/payment/dto/{create-payment.dto.ts → create-payment-url.dto.ts} RENAMED
@@ -1,6 +1,6 @@
1
  import { IsNumber, IsOptional, IsString } from "class-validator"
2
 
3
- export class CreatePaymentDto {
4
  @IsNumber()
5
  amount: number
6
 
@@ -8,6 +8,9 @@ export class CreatePaymentDto {
8
  @IsString()
9
  bankCode: string
10
 
 
 
 
11
  @IsString()
12
  orderDescription: string
13
 
 
1
  import { IsNumber, IsOptional, IsString } from "class-validator"
2
 
3
+ export class CreatePaymentUrlDto {
4
  @IsNumber()
5
  amount: number
6
 
 
8
  @IsString()
9
  bankCode: string
10
 
11
+ @IsString()
12
+ orderId: string
13
+
14
  @IsString()
15
  orderDescription: string
16
 
backend/src/payment/dto/create-payment.dto..ts ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { IsNumber, IsOptional, IsString } from 'class-validator';
2
+
3
+ export class CreatePaymentDto {
4
+ @IsNumber()
5
+ payment_method: number;
6
+
7
+ @IsNumber()
8
+ vnp_amount: number
9
+
10
+ @IsString()
11
+ vnp_bank_code: string
12
+
13
+ @IsString()
14
+ vnp_bank_tran_no: string
15
+
16
+ @IsNumber()
17
+ vnp_card_type: number
18
+
19
+ @IsString()
20
+ @IsOptional()
21
+ vnp_order_info: string //Nội dung giao dịch
22
+
23
+ @IsString()
24
+ @IsOptional()
25
+ vnp_paydate: string
26
+
27
+ @IsString()
28
+ @IsOptional()
29
+ vnp_response_code: number
30
+
31
+ @IsString()
32
+ @IsOptional()
33
+ vnp_transaction_no: string
34
+
35
+ @IsString()
36
+ @IsOptional()
37
+ vnp_transaction_status: number
38
+ }
backend/src/payment/dto/update-payment.dto.ts DELETED
@@ -1,4 +0,0 @@
1
- import { PartialType } from '@nestjs/mapped-types';
2
- import { CreatePaymentDto } from './create-payment.dto';
3
-
4
- export class UpdatePaymentDto extends PartialType(CreatePaymentDto) {}
 
 
 
 
 
backend/src/payment/payment.controller.ts CHANGED
@@ -3,7 +3,7 @@ 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';
6
- import { CreatePaymentDto } from './dto/create-payment.dto.js';
7
 
8
  @Controller('payment')
9
  export class PaymentController {
@@ -11,7 +11,7 @@ export class PaymentController {
11
 
12
  @Public()
13
  @Post('create_payment_url')
14
- async createPaymentUrl(@Req() req: Request, @Body() body: CreatePaymentDto) {
15
 
16
  const ipAddr =
17
  req.headers['x-forwarded-for'] ||
@@ -20,7 +20,7 @@ export class PaymentController {
20
 
21
  return await this.paymentService.createPaymentUrl(
22
  body.amount,
23
- body.bankCode,
24
  body.orderDescription,
25
  body.orderType,
26
  body.language,
 
3
  import { PaymentService } from './payment.service.js';
4
  import { Request, Response } from 'express';
5
  import { Public } from '../modules/authentication/authentication.decorator.js';
6
+ import { CreatePaymentUrlDto } from './dto/create-payment-url.dto.js';
7
 
8
  @Controller('payment')
9
  export class PaymentController {
 
11
 
12
  @Public()
13
  @Post('create_payment_url')
14
+ async createPaymentUrl(@Req() req: Request, @Body() body: CreatePaymentUrlDto) {
15
 
16
  const ipAddr =
17
  req.headers['x-forwarded-for'] ||
 
20
 
21
  return await this.paymentService.createPaymentUrl(
22
  body.amount,
23
+ body.orderId,
24
  body.orderDescription,
25
  body.orderType,
26
  body.language,
backend/src/payment/payment.module.ts CHANGED
@@ -1,9 +1,11 @@
1
  import { Module } from '@nestjs/common';
2
  import { PaymentService } from './payment.service.js';
3
  import { PaymentController } from './payment.controller.js';
 
 
4
 
5
  @Module({
6
  controllers: [PaymentController],
7
- providers: [PaymentService],
8
  })
9
  export class PaymentModule {}
 
1
  import { Module } from '@nestjs/common';
2
  import { PaymentService } from './payment.service.js';
3
  import { PaymentController } from './payment.controller.js';
4
+ import { OrderService } from '../modules/order/order.service.js';
5
+ import { BranchService } from '../modules/branch/branch.service.js';
6
 
7
  @Module({
8
  controllers: [PaymentController],
9
+ providers: [PaymentService, OrderService, BranchService],
10
  })
11
  export class PaymentModule {}
backend/src/payment/payment.service.ts CHANGED
@@ -3,12 +3,20 @@ import { HttpStatus, Injectable } from '@nestjs/common';
3
  import { ConfigService } from '@nestjs/config';
4
  import * as querystring from 'qs';
5
  import * as crypto from 'crypto';
 
 
 
 
 
6
 
7
  @Injectable()
8
  export class PaymentService {
9
- constructor(private readonly configService: ConfigService) {}
 
 
 
10
 
11
- async createPaymentUrl(amount: number, bankCode: string, orderDescription: string, orderType: string, language: string, ipAddr: string) {
12
 
13
  const tmnCode = this.configService.get<string>('vnp_TmnCode');
14
  const secretKey = this.configService.get<string>('vnp_HashSecret');
@@ -17,7 +25,6 @@ export class PaymentService {
17
 
18
  const date = new Date();
19
  const createDate = this.formatDate(date, 'yyyymmddHHmmss');
20
- const orderId = Date.now().toString();
21
  const locale = language || 'vn';
22
  const currCode = 'VND';
23
 
@@ -36,9 +43,6 @@ export class PaymentService {
36
  vnp_CreateDate: createDate,
37
  };
38
  console.log("3")
39
- if (bankCode) {
40
- vnp_Params['vnp_BankCode'] = bankCode;
41
- }
42
 
43
  const sortedParams = this.sortObject(vnp_Params);
44
 
@@ -55,11 +59,11 @@ export class PaymentService {
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
 
@@ -70,92 +74,122 @@ export class PaymentService {
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
- return {
90
- statusCode: HttpStatus.OK,
91
- message: 'Thành công!',
92
- data: { /* dữ liệu trả về nếu có */ },
93
- };
94
- }
95
- else {
96
- //that bai
97
- //paymentStatus = '2'
98
- // Ở đâ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
99
- return {
100
- statusCode: HttpStatus.OK,
101
- message: 'Thất bại',
102
- data: { /* dữ liệu trả về nếu có */ },
103
- };
104
- }
105
- }
106
- else{
107
- return {
108
- statusCode: HttpStatus.OK,
109
- message: 'This order has been updated to the payment status',
110
- data: { /* dữ liệu trả về nếu có */ },
111
- };
112
- }
 
113
  }
114
- else{
 
 
 
115
  return {
116
  statusCode: HttpStatus.OK,
117
- message: 'Amount invalid',
118
- data: { /* dữ liệu trả về nếu có */ },
119
  };
120
  }
121
- }
 
 
 
 
 
 
 
122
  else {
123
  return {
124
  statusCode: HttpStatus.OK,
125
- message: 'Order not found',
126
- data: { /* dữ liệu trả về nếu có */ },
127
  };
128
  }
 
 
 
 
 
 
 
129
  }
130
  else {
131
  return {
132
  statusCode: HttpStatus.OK,
133
  message: 'Checksum failed!',
134
- data: { /* dữ liệu trả về nếu có */ },
135
  };
136
  }
137
  }
138
 
139
- // Format date helper function
140
- formatDate(date: Date, format: string): string {
141
- const yyyymmdd = date.toISOString().slice(0, 10).replace(/-/g, ''); // YYYYMMDD
142
- const hhmmss = date.toTimeString().slice(0, 8).replace(/:/g, ''); // HHMMSS
143
- return format === 'yyyymmddHHmmss' ? yyyymmdd + hhmmss : hhmmss;
144
- }
145
-
146
- sortObject(obj) {
147
- let sorted = {};
148
- let str = [];
149
- let key;
150
- for (key in obj){
151
- if (obj.hasOwnProperty(key)) {
152
  str.push(encodeURIComponent(key));
153
- }
154
  }
155
- str.sort();
156
- for (key = 0; key < str.length; key++) {
157
- sorted[str[key]] = encodeURIComponent(obj[str[key]]).replace(/%20/g, "+");
158
- }
159
- return sorted;
160
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
161
  }
 
3
  import { ConfigService } from '@nestjs/config';
4
  import * as querystring from 'qs';
5
  import * as crypto from 'crypto';
6
+ import { OrderService } from '../modules/order/order.service.js';
7
+ import { PaymentEntity } from '../entities/payment.entity.js';
8
+ import { CreatePaymentUrlDto } from './dto/create-payment-url.dto.js';
9
+ import { CreatePaymentDto } from './dto/create-payment.dto..js';
10
+ import { VnpCardType } from '../common/enums/VnpCardType.enum.js';
11
 
12
  @Injectable()
13
  export class PaymentService {
14
+ constructor(
15
+ private readonly configService: ConfigService,
16
+ private readonly orderService: OrderService
17
+ ) { }
18
 
19
+ async createPaymentUrl(amount: number, orderId: string, orderDescription: string, orderType: string, language: string, ipAddr: string) {
20
 
21
  const tmnCode = this.configService.get<string>('vnp_TmnCode');
22
  const secretKey = this.configService.get<string>('vnp_HashSecret');
 
25
 
26
  const date = new Date();
27
  const createDate = this.formatDate(date, 'yyyymmddHHmmss');
 
28
  const locale = language || 'vn';
29
  const currCode = 'VND';
30
 
 
43
  vnp_CreateDate: createDate,
44
  };
45
  console.log("3")
 
 
 
46
 
47
  const sortedParams = this.sortObject(vnp_Params);
48
 
 
59
  }
60
 
61
 
62
+ async vnpayIpn(reqQuery) {
63
  console.log("helloooo")
64
  let vnp_Params = reqQuery;
65
  let secureHash = vnp_Params['vnp_SecureHash'];
66
+
67
  let orderId = vnp_Params['vnp_TxnRef'];
68
  let rspCode = vnp_Params['vnp_ResponseCode'];
69
 
 
74
  let secretKey = this.configService.get('vnp_HashSecret');
75
  let signData = querystring.stringify(vnp_Params, { encode: false });
76
  let hmac = crypto.createHmac("sha512", secretKey);
77
+ let signed = hmac.update(Buffer.from(signData, 'utf-8')).digest("hex");
78
+
79
  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.
80
  //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ó
81
  //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ó
82
+ //Kiểm tra có đúng order id không
83
+ let checkOrderId = true;
84
+ let order;
85
+ try {
86
+ order = await this.orderService.findOne(orderId)
87
+ } catch (error) {
88
+ checkOrderId = false;
89
+ }
90
+ // 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
91
+ let checkAmount = order.total_value == parseFloat(vnp_Params["vnp_Amount"])/100;
92
+ if (secureHash === signed) { //kiểm tra checksum
93
+ if (checkOrderId) {
94
+ if (checkAmount) {
95
+ 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
96
+ if (rspCode == "00") {
97
+ //thanh cong
98
+ //paymentStatus = '1'
99
+ // Ở đâ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
100
+ const payment = await this.create({
101
+ payment_method: 2,
102
+ vnp_amount: parseFloat(vnp_Params["vnp_Amount"])/100,
103
+ vnp_bank_code: vnp_Params['vnp_BankCode'],
104
+ vnp_bank_tran_no: vnp_Params['vnp_BankTranNo'],
105
+ vnp_card_type: VnpCardType[vnp_Params['vnp_CardType'] as keyof typeof VnpCardType],
106
+ vnp_order_info: vnp_Params['vnp_BankTranNo'],
107
+ vnp_paydate: vnp_Params['vnp_PayDate'],
108
+ vnp_response_code: vnp_Params['vnp_ResponseCode'],
109
+ vnp_transaction_no: vnp_Params['vnp_TransactionNo'],
110
+ vnp_transaction_status: vnp_Params['vnp_TransactionStatus'],
111
+ });
112
+ await PaymentEntity.save(payment);
113
+ this.orderService.updateOrderPayment(orderId, payment.id)
114
+ return {
115
+ statusCode: HttpStatus.OK,
116
+ message: 'Thành công!',
117
+ };
118
  }
119
+ else {
120
+ //that bai
121
+ //paymentStatus = '2'
122
+ // Ở đâ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
123
  return {
124
  statusCode: HttpStatus.OK,
125
+ message: 'Thất bại',
 
126
  };
127
  }
128
+ }
129
+ else {
130
+ return {
131
+ statusCode: HttpStatus.OK,
132
+ message: 'This order has been updated to the payment status',
133
+ };
134
+ }
135
+ }
136
  else {
137
  return {
138
  statusCode: HttpStatus.OK,
139
+ message: 'Amount invalid',
 
140
  };
141
  }
142
+ }
143
+ else {
144
+ return {
145
+ statusCode: HttpStatus.OK,
146
+ message: 'Order not found',
147
+ };
148
+ }
149
  }
150
  else {
151
  return {
152
  statusCode: HttpStatus.OK,
153
  message: 'Checksum failed!',
 
154
  };
155
  }
156
  }
157
 
158
+ // Format date helper function
159
+ formatDate(date: Date, format: string): string {
160
+ const yyyymmdd = date.toISOString().slice(0, 10).replace(/-/g, ''); // YYYYMMDD
161
+ const hhmmss = date.toTimeString().slice(0, 8).replace(/:/g, ''); // HHMMSS
162
+ return format === 'yyyymmddHHmmss' ? yyyymmdd + hhmmss : hhmmss;
163
+ }
164
+
165
+ sortObject(obj) {
166
+ let sorted = {};
167
+ let str = [];
168
+ let key;
169
+ for (key in obj) {
170
+ if (obj.hasOwnProperty(key)) {
171
  str.push(encodeURIComponent(key));
 
172
  }
 
 
 
 
 
173
  }
174
+ str.sort();
175
+ for (key = 0; key < str.length; key++) {
176
+ sorted[str[key]] = encodeURIComponent(obj[str[key]]).replace(/%20/g, "+");
177
+ }
178
+ return sorted;
179
+ }
180
+
181
+ async create(createPaymentDto: CreatePaymentDto): Promise<PaymentEntity | undefined> {
182
+ return PaymentEntity.create({
183
+ payment_method: 2,
184
+ vnp_amount: createPaymentDto.vnp_amount,
185
+ vnp_bank_code: createPaymentDto.vnp_bank_code,
186
+ vnp_bank_tran_no: createPaymentDto.vnp_bank_tran_no,
187
+ vnp_card_type: createPaymentDto.vnp_card_type,
188
+ vnp_order_info: createPaymentDto.vnp_order_info,
189
+ vnp_paydate: createPaymentDto.vnp_paydate,
190
+ vnp_response_code: createPaymentDto.vnp_response_code,
191
+ vnp_transaction_no: createPaymentDto.vnp_transaction_no,
192
+ vnp_transaction_status: createPaymentDto.vnp_transaction_status
193
+ })
194
+ }
195
  }