odoo 对接微信支付

前段时间,我们对接了支付宝,这次我们来对接微信支付。

沙箱环境

微信支付没有沙箱环境,要想测试就必须有营业执照。

Python SDK

这里我们使用的是开源SDK库 WechatPy

微信支付

要使用微信支付,你必须要满足一下条件

  • APPID: 一个绑定了微信支付的公众号APPID
  • API KEY: 在申请微信支付后可以设置,用于调用微信接口
  • 商户号: 开通了微信支付的商户编号
  • 商户证书文件: 开通了微信支付的商户证书
  • 商户密钥文件: 跟商户证书匹配的密钥文件

有了这几个参数才可以正确的调用微信支付的接口

1
2
3
4
5
6
7
8
9
10
11
12
def _get_wechatpay(self):
"""获取微信支付客户端"""
try:
# WeChatPay has no sandbox enviroment.
wechatpay = WeChatPay(self.wechatpay_appid,
self.wechatpay_app_key,
self.wechatpay_mch_id,
mch_cert=self.wechatpay_mch_cert,
mch_key=self.wechatpay_mch_key)
return wechatpay
except Exception as err:
_logger.exception(f"生成微信支付客户端失败:{err}")

odoo的官方商城支付,对应的微信支付是Navtive方式。

微信与支付不同的是,官方并没有给我们提供一个收银台页面,因此,我们需要自己实现一个,并持续监听,等到客户付款完成后再跳转验证页面。

微信的验证也是两种方式,一种是微信官方的推送消息,一种是我们自己根据订单去微信支付服务器查询。(这点不同于支付宝)。

主动查询

主动查询,用到的是wechatpy的query接口,查询起来比较简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@api.model
def wechatpy_query_pay(self, order):
"""
主动去微信支付查询支付结果
用户支付前没有transcation_id因此,只能用商户自有订单号去查
只有SUCCESS支付成功,其他状态均不成功
"""
wechatpay = self._get_wechatpay()
res = wechatpay.order.query(out_trade_no=order)
_logger.info("主动查询微信支付结果:{}".format(res))
if res["return_code"] == "SUCCESS" and res["result_code"] == "SUCCESS":
if res["trade_state"] == "SUCCESS":
transaction = self.env["payment.transaction"].sudo().search(
[('reference', '=', order)], limit=1)
if transaction.state in ('draft', 'pending', 'authorized'):
# 将支付结果设置完成
result = {
"acquirer_reference": res['transaction_id']
}
transaction.write(result)
transaction._set_transaction_done()
return True
elif transaction.state == 'done':
return True
else:
return False
return False

需要说明的是,我们再验证了支付之后,需要将对应的支付事务完成。

微信消息处理

客户在支付完成后,微信官方会给我们传入的回调地址发送业务通知。这点wechatpy也帮我们封装好了方法,使用起来也很方便:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def _verify_wechatpay(self, data):
"""验证微信支付服务器返回的信息"""
try:
wechatpay = self._get_wechatpay()
result = wechatpay.parse_payment_result(data)
_logger.info("解析微信支付返回结果:{}".format(result))
if result['result_code'] == 'SUCCESS' and result['return_code'] == 'SUCCESS':
# 支付校验成功
transaction = self.env["payment.transaction"].sudo().search(
[('reference', '=', result["out_trade_no"])], limit=1)
if transaction.state in ('draft', 'pending', 'authorized'):
# 将支付结果设置完成
result = {
"acquirer_reference": result['transaction_id']
}
transaction.write(result)
transaction._set_transaction_done()
return True
elif transaction.state == 'done':
return True
else:
return False
return False
except Exception as err:
_logger.error("解析微信支付推送消息失败:{}".format(traceback.format_exc()))
return False

在验证了微信的消息之后,同样也要将支付事务设置为完成状态。

完整示例

模块开源,下载地址

你的支持我的动力