CallBack.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. const API = require("../../lib/API.js")
  2. const db = require("../../plugin/DataBase/db.js")
  3. const { BaseStdResponse } = require("../../BaseStdResponse.js")
  4. const config = require('../../config.json')
  5. const crypto = require("crypto")
  6. const { insertLedgerRecord } = require('../../lib/Lepao/CountLedger')
  7. const { releaseUsageForOrder } = require('../../lib/CouponService')
  8. const PAYMENT_KEY = config.pay.key
  9. async function writePurchaseLedger(orderId, userUuid, addCount, logger) {
  10. const delta = Number(addCount || 0)
  11. if (!orderId || !userUuid || delta === 0) return
  12. try {
  13. const userRows = await db.query('SELECT lepao_count FROM users WHERE uuid = ?', [userUuid])
  14. if (!userRows || userRows.length !== 1) return
  15. const afterCount = Number(userRows[0].lepao_count || 0)
  16. const beforeCount = afterCount - delta
  17. await insertLedgerRecord({
  18. userUuid,
  19. delta,
  20. balanceBefore: beforeCount,
  21. balanceAfter: afterCount,
  22. bizType: 'purchase',
  23. bizId: orderId,
  24. remark: `订单号:${orderId}`
  25. })
  26. } catch (error) {
  27. logger?.error?.(`写入购买次数流水失败 ${orderId}: ${error.stack || error}`)
  28. }
  29. }
  30. class CallBack extends API {
  31. constructor() {
  32. super()
  33. this.noEncrypt()
  34. this.setPath('/Order/CallBack')
  35. this.setMethod('GET')
  36. }
  37. async onRequest(req, res) {
  38. const {
  39. pid, trade_no, out_trade_no, type, name, money,
  40. trade_status, sign, sign_type
  41. } = req.query
  42. // 参数校验
  43. if ([pid, trade_no, out_trade_no, type, name, money, trade_status, sign, sign_type].some(v => v === undefined)) {
  44. return res.json({
  45. ...BaseStdResponse.MISSING_PARAMETER
  46. })
  47. }
  48. this.logger.info(`收到支付回调。订单号:${out_trade_no}`)
  49. // 签名校验
  50. const rawParams = {
  51. money, name, out_trade_no, pid, trade_no, trade_status, type
  52. }
  53. const sortedKeys = Object.keys(rawParams).sort()
  54. const preSignStr = sortedKeys.map(key => `${key}=${rawParams[key]}`).join('&') + PAYMENT_KEY
  55. const localSign = crypto.createHash('md5').update(preSignStr, 'utf8').digest('hex')
  56. if (localSign.toLowerCase() !== sign.toLowerCase()) {
  57. this.logger.error(`签名校验失败,订单号:${out_trade_no}`)
  58. return res.send('签名验证失败')
  59. }
  60. // 支付未成功,标记为失败
  61. if (trade_status !== 'TRADE_SUCCESS') {
  62. const sql = 'UPDATE orders SET state = 3, pay_id = ? WHERE orderId = ? AND state = 0'
  63. const updateRes = await db.query(sql, [trade_no, out_trade_no])
  64. if (updateRes?.affectedRows > 0) {
  65. await releaseUsageForOrder(out_trade_no)
  66. }
  67. this.logger.info(`支付未成功。订单号:${out_trade_no}`)
  68. return res.send('success')
  69. }
  70. try {
  71. // 更新订单状态为已支付(state=1)
  72. const time = new Date().getTime()
  73. let sql = 'UPDATE orders SET state = 1, pay_type = ?, pay_id = ?, pay_time = ? WHERE orderId = ? AND state = 0'
  74. const result = await db.query(sql, [type, trade_no, time, out_trade_no])
  75. if (result.affectedRows > 0) {
  76. // 查询订单与商品信息
  77. sql = `
  78. SELECT
  79. g.lepao_count,
  80. g.ic_count,
  81. g.vip,
  82. a.create_user
  83. FROM
  84. orders a
  85. LEFT JOIN
  86. goods g
  87. ON
  88. a.goods_id = g.id
  89. WHERE
  90. a.orderId = ?
  91. `
  92. const rows = await db.query(sql, [out_trade_no])
  93. if (!rows || rows.length !== 1) {
  94. this.logger.error(`订单商品信息异常,订单号:${out_trade_no}`)
  95. await db.query('UPDATE orders SET state = 4 WHERE orderId = ?', [out_trade_no])
  96. return res.send('fail')
  97. }
  98. const { lepao_count, ic_count, vip, create_user } = rows[0]
  99. // 更新用户剩余次数
  100. sql = 'UPDATE users SET lepao_count = lepao_count + ?, ic_count = ic_count + ?, vip = ? WHERE uuid = ?'
  101. const updateUser = await db.query(sql, [lepao_count, ic_count, vip, create_user])
  102. if (!updateUser || updateUser.affectedRows !== 1) {
  103. this.logger.error(`更新用户失败,UUID: ${create_user}`)
  104. await db.query('UPDATE orders SET state = 4 WHERE orderId = ?', [out_trade_no])
  105. return res.send('fail')
  106. }
  107. sql = 'UPDATE orders SET state = 2 WHERE orderId = ?'
  108. await db.query(sql, [out_trade_no])
  109. await writePurchaseLedger(out_trade_no, create_user, lepao_count, this.logger)
  110. this.logger.info(`支付成功,订单处理完毕。订单号:${out_trade_no}`)
  111. return res.send('success')
  112. } else {
  113. this.logger.warn(`订单不存在或已处理,订单号:${out_trade_no}`)
  114. return res.send('订单不存在或已处理')
  115. }
  116. } catch (err) {
  117. this.logger.error(`支付回调处理异常:${err.stack}`)
  118. return res.send('服务器错误')
  119. }
  120. }
  121. }
  122. module.exports.CallBack = CallBack