payapi.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. 'use strict';
  2. const Controller = require('egg').Controller;
  3. const Payment = require('../../lib/wxpay');
  4. const { readFileSync } = require('fs');
  5. const uuid = require('uuid');
  6. class WxpayController extends Controller {
  7. // 预支付交易单 # description = 商品描述, out_trade_no = 自定义订单号
  8. async book_order() {
  9. const { openid, description, out_trade_no, money } = this.ctx.request.body;
  10. const { wxconfig } = this.app.config;
  11. const paymnet = new Payment({
  12. appid: wxconfig.appid,
  13. mchid: wxconfig.mchid,
  14. private_key: readFileSync(wxconfig.wxKey).toString(), // 或者直接复制证书文件内容
  15. serial_no: wxconfig.certid,
  16. apiv3_private_key: wxconfig.v3key,
  17. });
  18. const host = this.ctx.header.referer.split('/')[2];
  19. const backUrl = encodeURI(`${this.ctx.protocol}://${host}${this.ctx.path}`);
  20. // jsapi 支付下单
  21. const result = await paymnet.jsapi({
  22. description,
  23. out_trade_no,
  24. notify_url: backUrl,
  25. amount: {
  26. total: money * 100,
  27. currency: 'CNY',
  28. },
  29. payer: {
  30. openid,
  31. },
  32. });
  33. // 如果请求成功 redis存数据
  34. if (result.status === 200) {
  35. const { prepay_id } = JSON.parse(result.data);
  36. const order = JSON.stringify({ openid, prepay_id, out_trade_no });
  37. await this.app.redis.set(out_trade_no, order, 'EX', 6000 * 5);
  38. return { errcode: 0, errmsg: '', data: 'book_order' };
  39. }
  40. }
  41. // 跳转发起支付页面
  42. async pay() {
  43. const { out_trade_no, redirect_uri } = this.ctx.request.body;
  44. const { wxconfig } = this.app.config;
  45. const orderPay = await this.app.redis.get(out_trade_no);
  46. const orderinfo = JSON.parse(orderPay);
  47. const appid = wxconfig.appid;
  48. // 商户密钥证书
  49. const privateKey = readFileSync(wxconfig.wxKey).toString();
  50. // 32位随机字符串
  51. const payment = new Payment({
  52. appid: wxconfig.appid,
  53. mchid: wxconfig.mchid,
  54. private_key: readFileSync(wxconfig.wxKey).toString(), // 或者直接复制证书文件内容
  55. serial_no: wxconfig.certid,
  56. apiv3_private_key: wxconfig.v3key,
  57. });
  58. const payNonceStr = payment.generate();
  59. // 时间戳
  60. const payTimestamp = new Date().getTime();
  61. // 签名
  62. const data = `${appid}\n${payTimestamp}\n${payNonceStr}\nprepay_id=${orderinfo.prepay_id}\n`;
  63. const createSign = payment.rsaSign(data, privateKey);
  64. // TODO: 重定向到支付页面
  65. await this.ctx.render('pay.njk', { appid, payNonceStr, payTimestamp, createSign, redirect_uri, ...orderinfo });
  66. }
  67. // 关闭订单
  68. async orderClose() {
  69. const { out_trade_no } = this.ctx.request.body;
  70. const { wxconfig } = this.app.config;
  71. const payment = new Payment({
  72. appid: wxconfig.appid,
  73. mchid: wxconfig.mchid,
  74. private_key: readFileSync(wxconfig.wxKey).toString(),
  75. serial_no: wxconfig.certid,
  76. apiv3_private_key: wxconfig.v3key,
  77. });
  78. const res = await payment.close({ out_trade_no });
  79. if (res.status === 204) {
  80. // 订单关闭成功
  81. return { errcode: 0, errmsg: '', data: '' };
  82. }
  83. return { errcode: -2001, errmsg: '订单关闭失败', data: '' };
  84. }
  85. /* 取消订单
  86. * out_trade_no = 原订单号, refundMoney = 退款单号, reason = 退款原因, money = 原商品总金额, refundMoney = 退款金额
  87. */
  88. async refund() {
  89. const { out_trade_no, reason, refundMoney, money } = this.ctx.request.body;
  90. const { wxconfig } = this.app.config;
  91. const payment = new Payment({
  92. appid: wxconfig.appid,
  93. mchid: wxconfig.mchid,
  94. private_key: readFileSync(wxconfig.wxKey).toString(),
  95. serial_no: wxconfig.certid,
  96. apiv3_private_key: wxconfig.v3key,
  97. });
  98. let out_refund_no = uuid.v1();
  99. out_refund_no = out_refund_no.replace(/-/g, '');
  100. const res = await payment.refund({
  101. out_trade_no,
  102. reason,
  103. out_refund_no,
  104. amount: {
  105. refund: refundMoney * 100,
  106. total: money * 100,
  107. currency: 'CNY',
  108. },
  109. });
  110. return { errcode: 0, errmsg: '', data: res };
  111. }
  112. }
  113. module.exports = WxpayController;