'use strict'; const Controller = require('egg').Controller; const Payment = require('../../lib/wxpay'); const { readFileSync } = require('fs'); const uuid = require('uuid'); class WxpayController extends Controller { // 预支付交易单 # description = 商品描述, out_trade_no = 自定义订单号 async book_order() { const { openid, description, out_trade_no, money } = this.ctx.request.body; const { wxconfig } = this.app.config; const paymnet = new Payment({ appid: wxconfig.appid, mchid: wxconfig.mchid, private_key: readFileSync(wxconfig.wxKey).toString(), // 或者直接复制证书文件内容 serial_no: wxconfig.certid, apiv3_private_key: wxconfig.v3key, }); const host = this.ctx.header.referer.split('/')[2]; const backUrl = encodeURI(`${this.ctx.protocol}://${host}${this.ctx.path}`); // jsapi 支付下单 const result = await paymnet.jsapi({ description, out_trade_no, notify_url: backUrl, amount: { total: money * 100, currency: 'CNY', }, payer: { openid, }, }); // 如果请求成功 redis存数据 if (result.status === 200) { const { prepay_id } = JSON.parse(result.data); const order = JSON.stringify({ openid, prepay_id, out_trade_no }); await this.app.redis.set(out_trade_no, order, 'EX', 6000 * 5); return { errcode: 0, errmsg: '', data: 'book_order' }; } } // 跳转发起支付页面 async pay() { const { out_trade_no, redirect_uri } = this.ctx.request.body; const { wxconfig } = this.app.config; const orderPay = await this.app.redis.get(out_trade_no); const orderinfo = JSON.parse(orderPay); const appid = wxconfig.appid; // 商户密钥证书 const privateKey = readFileSync(wxconfig.wxKey).toString(); // 32位随机字符串 const payment = new Payment({ appid: wxconfig.appid, mchid: wxconfig.mchid, private_key: readFileSync(wxconfig.wxKey).toString(), // 或者直接复制证书文件内容 serial_no: wxconfig.certid, apiv3_private_key: wxconfig.v3key, }); const payNonceStr = payment.generate(); // 时间戳 const payTimestamp = new Date().getTime(); // 签名 const data = `${appid}\n${payTimestamp}\n${payNonceStr}\nprepay_id=${orderinfo.prepay_id}\n`; const createSign = payment.rsaSign(data, privateKey); // TODO: 重定向到支付页面 await this.ctx.render('pay.njk', { appid, payNonceStr, payTimestamp, createSign, redirect_uri, ...orderinfo }); } // 关闭订单 async orderClose() { const { out_trade_no } = this.ctx.request.body; const { wxconfig } = this.app.config; const payment = new Payment({ appid: wxconfig.appid, mchid: wxconfig.mchid, private_key: readFileSync(wxconfig.wxKey).toString(), serial_no: wxconfig.certid, apiv3_private_key: wxconfig.v3key, }); const res = await payment.close({ out_trade_no }); if (res.status === 204) { // 订单关闭成功 return { errcode: 0, errmsg: '', data: '' }; } return { errcode: -2001, errmsg: '订单关闭失败', data: '' }; } /* 取消订单 * out_trade_no = 原订单号, refundMoney = 退款单号, reason = 退款原因, money = 原商品总金额, refundMoney = 退款金额 */ async refund() { const { out_trade_no, reason, refundMoney, money } = this.ctx.request.body; const { wxconfig } = this.app.config; const payment = new Payment({ appid: wxconfig.appid, mchid: wxconfig.mchid, private_key: readFileSync(wxconfig.wxKey).toString(), serial_no: wxconfig.certid, apiv3_private_key: wxconfig.v3key, }); let out_refund_no = uuid.v1(); out_refund_no = out_refund_no.replace(/-/g, ''); const res = await payment.refund({ out_trade_no, reason, out_refund_no, amount: { refund: refundMoney * 100, total: money * 100, currency: 'CNY', }, }); return { errcode: 0, errmsg: '', data: res }; } } module.exports = WxpayController;