准备工作:

1、已认证的服务号(apppid、appsecret、token、aes_key)

2、微信支付商户(商户号、密钥)

3、两者互相绑定

原理解析:

1、前台商品页面:点击支付按钮,js获取商品id和数量(价格和用户ID尽量在后台获取,防止用户恶意操作)

2、点击按钮后ajax把商品id和数量传递给后台(后台地址为  /wxPay)

3、后台根据商品id查找价格等信息,创建订单(订单价格,订单号,是否支付等信息)创建订单时是未支付状态。然后把总价×100和订单号通过easywechat的unify下单,拿到返回值(包含时间戳 prepayid等信息)

4、再把返回值传到前台,这个返回值就是支付配置,

5、前台根据这个返回值发起支付

6、用户进行支付操作(可能成功也可能失败)

7、支付结果由微信服务器异步通知到设定的回调地址,在回调方法里面,如果成功支付,则根据支付结果的订单id找到相应订单更新为已支付状态

代码演示

1、前台页面(对应原理1、2、5、6)

<button onclick="prePay()">支付</button>

<script>
const config; //定义全局变量
function prePay(){
$.post('/wxPay',{product_id:***,count:***},function(res){//获取到后台返回的支付配置
config = res; //将配置信息赋值给config
callpay();
});
}

function jsApiCall() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', config, //此处使用配置发起jsapi支付
function (res) {
WeixinJSBridge.log(res.err_msg);
if (res.err_msg == 'get_brand_wcpay_request:ok') {
$.toast("充值成功");
} else {
$.toast("您取消了充值",'text');
}
}
);
}
function callpay() {
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
} else {
jsApiCall();
}
}
</script>

2、后台逻辑1:接收product_id、count等信息(对应原理3、4)

function callWxPay(Request $request){
$user = $this->getUserInfo();
$app = app('wechat.official_account');
$payment = Factory::payment(config('wechat.payment.default'));

$billnum = date('YmdHis') . rand(100000,999999);
Bill::create([
'user_id'=>$user->id,
'ispay' => 0,
'money'=> $request->money,
'billnum' => $billnum
]);

//(对应原理3)
$result = $payment->order->unify([
'body' => '微信支付',
'out_trade_no' => $billnum,
'total_fee' => $request->money * 100, //注意:微信支付单位是分
'notify_url' => 'http://**.com/wx/notify', //回调地址,用于接收微信支付结果,如果用laravel,需要对/wx/notify路由去掉csrf验证
'trade_type' => 'JSAPI',
'openid' => $user->wxopenid,
]);

if ($result['result_code'] == 'SUCCESS' && $result['return_code'] == 'SUCCESS') {
$prepayId = $result['prepay_id'];
$jssdk = $payment->jssdk;
$config = $jssdk->sdkConfig($prepayId);
$config['timeStamp'] = $config['timestamp'];//此处需要将小写s变为大写
return $config;//(对应原理4)
} else {
return $result;
}

}

3、后台逻辑2:接收回调、更新订单信息(对应原理7)

 public function wxNotify()
{
$payment = \EasyWeChat::payment();
$response = $payment->handlePaidNotify(function ($message, $fail) {
if ($message['return_code'] === 'SUCCESS' && $message['result_code'] === 'SUCCESS') {

// DB::beginTransaction(); 如果要更改余额表等信息,应该使用事务
DB::table('bill')->where('billno',$message['out_trade_no'])->update([ 'updated_at' => date('Y-m-d H:i:s'),'ispay'=>1]);
// DB::commit();
return true;
} else {
return $fail('失败');
}
});
return $response;
}

重要部分

1、获取prepayid

$result = $payment->order->unify([
                'body' => '微信支付',
                'out_trade_no' => $billnum,
                'total_fee' => $request->money * 100, //注意:微信支付单位是分
                'notify_url' => 'http://**.com/wx/notify', //回调地址,用于接收微信支付结果,如果用laravel,需要对/wx/notify路由去掉csrf验证
                'trade_type' => 'JSAPI',
                'openid' => $user->wxopenid,
        ]);

2、生成支付配置
$config = $jssdk->sdkConfig($prepayId);