/* eslint-disable eqeqeq */ 'use strict'; const Service = require('egg').Service; const WxPay = require('wechatpay-node-v3'); const fs = require('fs'); const path = require('path'); // 微信支付操作类 class WxPayService extends Service { /** * 发起商家转账到零钱 * @return {Promise} */ async transfer(data) { const that = this; const userInfo = await that.app.model.Users.findOne({ where: { user_id: data.user_id }, attributes: [ 'openid' ], raw: true, }); const keys = [ 'wx_pay_serial_no', 'wechat_account_appid', 'wechat_pay_key', 'wx_pay_mchid' ]; const config = await that.service.configs.getConfigMoreValue(keys); // 2023/1/11 微信支付配置初始化 const wxPay = new WxPay({ appid: config.wechat_account_appid, // 公众号appid mchid: config.wx_pay_mchid, // 微信支付商户号 serial_no: config.wx_pay_serial_no, // 微信支付证书序列号 key: config.wechat_pay_key, // APIv3密钥 // publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥 publicKey: fs.readFileSync(path.join(__dirname, './apiclient_cert.pem'), 'utf8'), // 公钥 // privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥 privateKey: fs.readFileSync(path.join(__dirname, './apiclient_key.pem'), 'utf8'), // 秘钥 }); const certificates = await wxPay.get_certificates(config.wechat_pay_key); // 取最后一个 const certificate = certificates.pop(); // 当前时间戳作为商家批次单号 const timestamp = parseInt(+new Date() + '') .toString(); // 2023/1/12 构造转账参数 const cashAmount = Math.floor(data.cash_amount * 100); const bodyData = { out_batch_no: 'cash' + timestamp, batch_name: '佣金提现', batch_remark: data.remark ? data.remark : '佣金提现', total_amount: cashAmount, total_num: 1, wx_serial_no: certificate.serial_no, // 当你需要传user_name时 需要传当前参数 transfer_detail_list: [ { out_detail_no: 'cashd' + timestamp, transfer_amount: cashAmount, transfer_remark: data.remark ? data.remark : '佣金提现', openid: userInfo.openid, // user_name: wxPay.publicEncrypt('name', Buffer.from(certificate.publicKey)), // 真实姓名转换 }, ], }; const res = await wxPay.batches_transfer(bodyData); if (res.status == 200) { // 2023/2/1 成功发起转账 // 2023/2/1 提现记录 const logData = { out_batch_no: bodyData.out_batch_no, out_detail_no: 'cashd' + timestamp, batch_id: res.data.batch_id, detail_status: 'INIT', batch_name: '佣金提现', batch_remark: data.remark ? data.remark : '佣金提现', user_id: data.user_id, cash: data.cash_amount, type: 2, // 提现中 create_time: that.app.szjcomo.date('Y-m-d H:i:s'), }; await that.service.cash.addCashLog(logData); // 2023/2/1 佣金变化记录(提现转帐中) const commParams = { user_id: data.user_id, type: 2, commission: -data.cash_amount, log_desc: '提现转帐中...', out_batch_no: logData.out_batch_no, out_detail_no: logData.out_detail_no, }; await that.service.commission.addCommissionChangeLog(commParams); setTimeout(() => { // 请等待批次处理完成后再查询明细单据 大约9s左右后可以查询转账结果 that.getTransferResult(logData); }, 12000); } else { that.logger.error('用户提现失败:status %s ,errorCode:%s ,msg:%s', res.status, res.error.code, res.error.message); } return res; } /** * 查询提现状态 并 更新状态 * @return {Promise} */ async getTransferResult(param) { const that = this; const keys = [ 'wx_pay_serial_no', 'wechat_account_appid', 'wechat_pay_key', 'wx_pay_mchid' ]; const config = await that.service.configs.getConfigMoreValue(keys); // 2023/1/11 微信支付配置初始化 const wxPay = new WxPay({ appid: config.wechat_account_appid, // 公众号appid mchid: config.wx_pay_mchid, // 微信支付商户号 serial_no: config.wx_pay_serial_no, // 微信支付证书序列号 key: config.wechat_pay_key, // APIv3密钥 // publicKey: fs.readFileSync('./apiclient_cert.pem'), // 公钥 publicKey: fs.readFileSync(path.join(__dirname, './apiclient_cert.pem'), 'utf8'), // 公钥 // privateKey: fs.readFileSync('./apiclient_key.pem'), // 秘钥 privateKey: fs.readFileSync(path.join(__dirname, './apiclient_key.pem'), 'utf8'), // 秘钥 }); // 商家明细单号查询明细单API const res = await wxPay.query_batches_transfer_detail({ out_batch_no: param.out_batch_no, out_detail_no: param.out_detail_no, }); if (res.status == 200) { let cashType; let commissionType; let log_desc; if (res.data.detail_status == 'SUCCESS') { cashType = 1; commissionType = 0; log_desc = '提现成功'; // 2023/2/2 更新分佣账户余额 const updateBean = await that.app.comoBean.instance({ commission: that.app.Sequelize.literal('commission - ' + param.cash), update_time: that.app.szjcomo.date('Y-m-d H:i:s'), }, { where: { user_id: param.user_id } }); await that.app.comoBean.update(updateBean, that.app.model.Users, '用户分佣金额更新失败,请稍候重试'); } else if (res.data.detail_status == 'FAIL') { cashType = 0; commissionType = -1; log_desc = '提现失败'; } else { cashType = 2; commissionType = 2; log_desc = '提现转账中...'; } // 2023/2/1 更新提现记录 const updateBean = await that.app.comoBean.instance({ type: cashType, // 2023/2/1 提现转账状态 detail_id: res.data.detail_id, detail_status: res.data.detail_status, fail_reason: res.data.fail_reason, update_time: that.app.szjcomo.date('Y-m-d H:i:s'), }, { where: { out_batch_no: param.out_batch_no, out_detail_no: param.out_detail_no, }, }); await that.service.base.update(updateBean, that.app.model.UsersCashLogs, '更新提现记录失败'); // 2023/2/1 更新佣金变化状态记录 const commBean = await that.app.comoBean.instance({ type: commissionType, log_desc, }, { where: { out_batch_no: param.out_batch_no, out_detail_no: param.out_detail_no, }, }); await that.service.base.update(commBean, that.app.model.UsersCommissionLogs, '更新佣金变化失败'); } else { that.logger.error('提现状态查询失败:status %s ,msg:400 PARAM_ERROR参数错误;404 NOT_FOUND记录不存在;429 FREQUENCY_LIMITED频率超限', res.status); } return res; } } module.exports = WxPayService;