· 6 years ago · May 06, 2019, 03:36 AM
1const _ = require('lodash')
2const qs = require('qs')
3const md5 = require('md5')
4const config = require('config')
5const passport = require('passport')
6const moment = require('moment')
7const generator = require('randomstring')
8
9const asyncMdw = require('@utils/async-mdw')
10const AppError = require('@utils/exception')
11const { sortObjectPropertyKey } = require('@utils/lib')
12const { createVNPayOrder } = require('@utils/vnp-order')
13const { initCourse } = require('@utils/online-course')
14
15const { validAndGetProduct } = require('@middleware/course-product')
16const { autoApplyCoupon } = require('@middleware/coupon')
17
18const appdb = require('@models/app')
19const VNPayTransaction = appdb.model('VNPayTransaction')
20const UserOnlineCourse = appdb.model('UserOnlineCourse')
21
22const mdw = [
23 passport.authenticate('user-jwt', { failWithError: true }),
24 validAndGetProduct('body', 'productId'),
25 autoApplyCoupon()
26]
27
28module.exports = router => {
29 router.post('/url', mdw, asyncMdw(async (req, res, next) => {
30 const now = moment()
31 const returnUrl = config.get('vnp.returnUrl')
32 const tmnCode = config.get('vnp.tmnCode')
33 const secretKey = config.get('vnp.secretKey')
34 const ip = req.userIp
35 const userId = req.user._id
36 const userPhone = req.user.phone
37 const product = req.product
38 const productName = _.join(product.courses, '+')
39 const coupon = req.coupon
40 const productAmount = req.body.amount
41
42 let vnpParams = {}
43 let vnpUrl = config.get('vnp.url')
44 let amount = 0
45
46 // Get user course
47 let userCourses = await UserOnlineCourse
48 .findOne({
49 user: userId
50 })
51 .lean()
52 if (!userCourses) {
53 userCourses = await initCourse(userId, userPhone)
54 }
55
56 // Check user owned course
57 _.forEach(['N5', 'N4', 'N3'], (course, index) => {
58 if (userCourses.activeCourses[index].activeStatus === 2 && product.courses.includes(course)) {
59 throw new AppError('E_USER_OWNED_COURSE', 403)
60 }
61 })
62
63 // Valid product price show in client with server
64 coupon.discountType === '%' ? amount = product.price * (100 - coupon.discount) : amount = (product - coupon.discount) * 100
65 if (amount !== productAmount) {
66 throw new AppError('E_PRODUCT_PRICE_INVALID', 403)
67 }
68
69 // Create VNPay params
70 vnpParams = {
71 vnp_Version: '2',
72 vnp_Command: 'pay',
73 vnp_TmnCode: tmnCode,
74 vnp_Amount: amount,
75 vnp_CreateDate: now.format('YYYYMMDDHHmmss'),
76 vnp_CurrCode: 'VND',
77 vnp_IpAddr: ip,
78 vnp_Locale: 'vn',
79 vnp_OrderInfo: `${userPhone}:${productName}:${amount / 100}`,
80 vnp_ReturnUrl: returnUrl,
81 vnp_TxnRef: generator.generate({ length: 6, charset: 'numeric' }) + now.format('YYMMDD')
82 }
83 vnpParams = sortObjectPropertyKey(vnpParams)
84 const signData = secretKey + qs.stringify(vnpParams, { encode: false })
85 vnpParams = _.assign(vnpParams, {
86 vnp_SecureHashType: 'MD5',
87 vnp_SecureHash: md5(signData)
88 })
89
90 vnpUrl += '?' + qs.stringify(vnpParams, { encode: true })
91
92 // Create new vnp transaction
93 const vnpTransaction = await VNPayTransaction
94 .create({
95 vnpVersion: vnpParams.vnp_Version,
96 vnpCurrCode: vnpParams.vnp_CurrCode,
97 vnpOrderInfo: vnpParams.vnp_OrderInfo,
98 vnpSecureHashType: vnpParams.vnp_SecureHashType,
99 vnpSecureHash: vnpParams.vnp_SecureHash,
100 vnpIpAddr: vnpParams.vnp_IpAddr,
101 vnpBankCode: vnpParams.vnp_BankCode,
102 transactionId: vnpParams.vnp_TxnRef,
103 user: req.user._id,
104 product: {
105 name: product.name,
106 courses: product.courses,
107 price: product.price,
108 activeExpire: product.activeExpire
109 },
110 coupon: coupon,
111 amount: amount / 100,
112 additionalInfo: ''
113 })
114
115 createVNPayOrder(`+${req.user.phone}`, vnpTransaction._id)
116
117 res.json({
118 vnpUrl
119 })
120 }))
121}