# 微信支付

微信云托管通过开放接口服务封装了微信支付原有的接口,所以在使用前需要开启「开放接口服务」

要了解微信支付接口的运作和使用理论,请前往使用指南

我们也给出了一个DEMO案例,具体可以前往查看学习。

如果在接口请求时出现302、400,返回空值等情况,可以在请求时加header content-type:'application/json' 解决。

如果在请求时返回 { return_code: 'FAIL', return _msg: '受理关系不存在} ,则需要前往微信云托管控制台 - 设置 - 其他设置 - 微信支付配置绑定商户号到已授权状态。

具体方法的详细文档如下:

# 一、支付接口

接口名称 接口 需要 OpenID
统一下单 http://api.weixin.qq.com/_/pay/unifiedorder
查询订单 http://api.weixin.qq.com/_/pay/queryorder
关闭订单 http://api.weixin.qq.com/_/pay/closeorder
下载对账单 http://api.weixin.qq.com/_/pay/downloadbill
申请退款 http://api.weixin.qq.com/_/pay/refund
查询退款 http://api.weixin.qq.com/_/pay/queryrefund

# 二、分账接口

接口名称 接口 需要 OpenID
添加分账接收方 http://api.weixin.qq.com/_/pay/profitsharingaddreceiver
删除分账接收方 http://api.weixin.qq.com/_/pay/profitsharingremovereceiver
请求单次分账 http://api.weixin.qq.com/_/pay/profitsharing
请求多次分账 http://api.weixin.qq.com/_/pay/multiprofitsharing
完结分账 http://api.weixin.qq.com/_/pay/profitsharingfinish
查询分账结果 http://api.weixin.qq.com/_/pay/profitsharingquery
分账回退 http://api.weixin.qq.com/_/pay/profitsharingreturn
回退结果查询 http://api.weixin.qq.com/_/pay/profitsharingreturnquery

# 三、结果回调

# 四、代码示例-Node.js

以下代码实现了下单到退款的基本业务逻辑,只是用于参考,实际接入请根据自己的业务情况改造,比如将触发订单由流程决定,添加校验逻辑等。

完整例子可以前往Github仓库

const express = require('express')
const request = require('request')

const app = express()
app.use(express.json())

const mchId = process.env.mch_id || '1XXXXXXXXX' // 这里商户号需要替换成自己的
// 也可以在部署时设定环境变量【mch_id】为商户号

// 统一下单
app.post('/unifiedOrder', async function (req, res) {
  const ip = req.headers['x-forwarded-for'] // 小程序直接 callcontainer 请求会存在
  const openid = req.headers['x-wx-openid'] // 小程序直接 callcontainer 请求会存在
  // 如果是业务异步流程需自己替换 openid 来源
  const { text, noid, fee } = req.body
  const payreq = {
    body: text, // 订单描述
    out_trade_no: noid, // 自定义订单号
    sub_mch_id: mchId, // 微信支付商户号
    total_fee: fee, // 金额,单位:分
    openid: openid, // 用户唯一身份ID
    spbill_create_ip: ip, // 用户客户端 IP 地址
    env_id: req.headers['x-wx-env'], // 接收回调的环境ID
    callback_type: 2, // 云托管服务接收回调,填2
    container: {
      service: req.headers['x-wx-service'], // 回调的服务名称
      path: '/' // 回调的路径
    }
  }
  console.log('[unifiedOrder]请求体', payreq)
  const info = await callpay('unifiedorder', payreq)
  console.log('[unifiedOrder]响应体', info)
  res.send(info)
})

// 查询订单
app.post('/queryorder', async function (req, res) {
  const { noid } = req.body
  const payreq = {
    out_trade_no: noid, // 自定义订单号
    sub_mch_id: mchId // 微信支付商户号
  }
  console.log('[queryorder]请求体', payreq)
  const info = await callpay('queryorder', payreq)
  console.log('[queryorder]响应体', info)
  res.send(info)
})

// 关闭订单
app.post('/closeorder', async function (req, res) {
  const { noid } = req.body
  const payreq = {
    out_trade_no: noid, // 自定义订单号
    sub_mch_id: mchId // 微信支付商户号
  }
  console.log('[closeorder]请求体', payreq)
  const info = await callpay('closeorder', payreq)
  console.log('[closeorder]响应体', info)
  res.send(info)
})

// 发起退款
app.post('/refund', async function (req, res) {
  const { text, noid, fee } = req.body
  const payreq = {
    body: text, // 订单描述
    out_trade_no: noid, // 自定义订单号
    out_refund_no: `R_${noid}`, // 自定义退款单号
    sub_mch_id: mchId, // 微信支付商户号
    total_fee: fee, // 订单金额,单位:分
    refund_fee: fee, // 退款金额,单位:分
    refund_desc: `${text}_退款`, // 订单退款描述
    env_id: req.headers['x-wx-env'], // 接收回调的环境ID
    callback_type: 2, // 云托管服务接收回调,填2
    container: {
      service: req.headers['x-wx-service'], // 回调的服务名称
      path: '/' // 回调的路径
    }
  }
  console.log('[refund]请求体', payreq)
  const info = await callpay('refund', payreq)
  console.log('[refund]响应体', info)
  res.send(info)
})

// 查询退款
app.post('/queryrefund', async function (req, res) {
  const { noid } = req.body
  const payreq = {
    out_trade_no: noid, // 自定义订单号
    sub_mch_id: mchId // 微信支付商户号
  }
  console.log('[queryrefund]请求体', payreq)
  const info = await callpay('queryrefund', payreq)
  console.log('[queryrefund]响应体', info)
  res.send(info)
})

// 接收回调信息
app.all('/', function (req, res) {
  console.log('回调请求头', req.headers)
  console.log('回调收到内容', req.body || req.query)
  res.send('success')
})

app.listen(80, function () {
  console.log('服务启动成功!')
})

function callpay (action, paybody) {
  return new Promise((resolve, reject) => {
    request({
      url: `http://api.weixin.qq.com/_/pay/${action}`,
      method: 'POST',
      headers: {
        'content-type': 'application/json'
      },
      body: JSON.stringify(paybody)
    }, function (error, res) {
      if (error) {
        resolve(error)
      } else {
        resolve(res.body)
      }
    })
  })
}

在小程序中调用

wx.cloud.callContainer({
  config: {
    env: "prod-xxxxxx" // 替换自己的环境ID
  },
  path: "/order",
  header: {
    "X-WX-SERVICE": "pay", // 替换自己的服务
    "content-type": "application/json"
  },
  method: "POST",
  data: {
    text: "测试支付", // 自定义
    noid: "2021WERUN1647840687637", // 自定义
    fee: 1 // 分,金额自定义
  }
})