首先引用一下微信官方文档的业务流程时序图,这是最简洁明了的:
商户系统和微信支付系统主要交互:
1、小程序内调用登录接口,获取到用户的openid,api参见公共api【小程序登录API】
2、商户server调用支付统一下单,api参见公共api【统一下单API】
3、商户server调用再次签名,api参见公共api【再次签名】
4、商户server接收支付通知,api参见公共api【支付结果通知API】
5、商户server查询支付结果,api参见公共api【查询订单API】
其次,我们需要使用小程序提供的API,发起微信支付。以下是详细的接口文档:
wx.requestPayment(OBJECT)
Object参数说明:
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
timeStamp | String | 是 | 时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间 |
nonceStr | String | 是 | 随机字符串,长度为32个字符以下。 |
package | String | 是 | 统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=* |
signType | String | 是 | 签名算法,暂支持 MD5 |
paySign | String | 是 | 签名,具体签名方案参见小程序支付接口文档; |
success | Function | 否 | 接口调用成功的回调函数 |
fail | Function | 否 | 接口调用失败的回调函数 |
complete | Function | 否 | 接口调用结束的回调函数(调用成功、失败都会执行) |
了解更多信息,请查看微信支付接口文档
回调结果:
回调类型 | errMsg | 说明 |
---|---|---|
success | requestPayment:ok | 调用支付成功 |
fail | requestPayment:fail cancel | 用户取消支付 |
fail | requestPayment:fail (detail message) | 调用支付失败,其中 detail message 为后台返回的详细失败原因 |
示例代码:
wx.requestPayment({
'timeStamp': '',
'nonceStr': '',
'package': '',
'signType': 'MD5',
'paySign': '',
'success':function(res){
},
'fail':function(res){
}
})
Bug & Tip
bug
: 6.5.2 及之前版本中,用户取消支付不会触发 fail 回调,只会触发 complete 回调,回调 errMsg 为 'requestPayment:cancel'
现在给出实际开发代码的一个例子:
①:小程序发起微信支付与回调处理的代码:
//购买 pay: function (e) { var id = e.currentTarget.dataset.id; var that = this; request.post({ url: '/api/mime/createOrder', data: { id: id, }, success: function (res) { console.log(res); var result = res.data.result; wx.requestPayment({ timeStamp: result.time.toString(), nonceStr: result.nonce_str, package: 'prepay_id=' + result.prepay_id, signType: 'MD5', paySign: result.sign, success: function (res) { that.confirmOrder(result.orderNo); }, fail: function (res) { console.log(res); } }) }, fail: function (e) { wx.showToast({ title: '请求失败!', duration: 2000 }); }, }); }, //付款成功 confirmOrder: function () { var that = this; request.post({ url: '/api/mime/confirmOrder', data: {}, success: function (res) { wx.showToast({ title: '成功开通会员', duration: 2000 }); setTimeout(function(){ wx.switchTab({ url: '../mine/mine' }) },2000); }, fail: function (e) { wx.showToast({ title: '请求失败!', duration: 2000 }); }, }); },
②:然后是用php写的处理生成订单的接口,这里我使用的是jiaweixs的组件
在composer的配置文件中加入配置,也可以直接用composer命令直接添加
/** * 微信统一下单 * */ public function createOrder() { $id = trim($_POST['id']); $config = MemberCostConfig::get($id); $userId = $this->user->id; //生成订单 $memberRecord = new MemberRecord(); $data = array(); $orderNo = 'W'.date('YmdHis',time()).mt_rand(10000, 99999); $data['orderNo'] = $orderNo; $data['status'] = 0; $data['user_id'] = $userId; $data['star_id'] = 0; $data['money'] = $config['price']; $data['duration'] = $config['duration']; $data['vip_day'] = $config['days']; $data['create_time'] = date("Y-m-d H:i:s"); $data['update_time'] = date("Y-m-d H:i:s"); $memberRecord->save($data); $money = (float)$config['price']*100; $unifiedorder = new Unifiedorder(APPID, MCHID, KEY); //Unifiedorder是jiaweixs封装可以直接使用的 $openid = $this->user->openid; // 必填 $unifiedorder->set('body', '充值会员'); $unifiedorder->set('total_fee', $money); $unifiedorder->set('openid', $openid); $unifiedorder->set('trade_type', 'JSAPI'); $unifiedorder->set('out_trade_no', date('YmdHis').mt_rand(10000, 99999)); $unifiedorder->set('notify_url', BUY_MEMBER_URL); //这里是微信支付回调地址 // 选填 $unifiedorder->set('attach', $orderNo); $unifiedorder->set('time_start', date("YmdHis")); //订单生成时间 $unifiedorder->set('time_expire', date("YmdHis", time() + 600)); //订单失效时间 $response = $unifiedorder->getResponse(); $res = $response->toArray(); $time = Time(); $str = 'appId='.$res['appid'].'&nonceStr='.$res['nonce_str'].'&package=prepay_id='.$res['prepay_id'].'&signType=MD5&timeStamp='.$time; //重新生成签名 $res['sign']=strtoupper(md5($str.'&key='.KEY)); $res['time'] = $time; $res['orderNo'] =$orderNo; // 下单结果 return $this->api_success('success', 200, $res); } /** * 修改订单状态 * */ public function confirmOrder() { $orderNo = trim($_POST['orderNo']); //修改订单状态 $rechargeRecord = new RechargeRecord(); $order = $rechargeRecord->where('orderNo', 'eq', $orderNo)->find(); if ($order) { $data['number'] = $order['love_number']; return $this->api_success('success', 200, $data); } else { return $this->api_error('订单不存在',100); } }
③:最后就是微信支付的回调通知:
/** * 开通会员成功支付回调 接口 */ public function member() { $post = file_get_contents("php://input"); $post_data = $this->xml_to_array($post); //微信支付成功,返回回调地址url的数据:XML转数组Array $postSign = $post_data['sign']; unset($post_data['sign']); $record = new MemberRecord(); $order = $record->where('orderNo', 'eq', $post_data['attach'])->find(); if ($post_data['return_code'] == 'SUCCESS' && $postSign) { if ($order['status'] == '0') { $record->save(array('status' => 1,'update_time'=>date('Y-m-d H:i:s')), array('orderNo' => $post_data['attach'])); $user = User::get($order['user_id']); $user['recharge_times'] = $user['recharge_times'] + 1; $user['recharge_money'] = $user['recharge_money'] + $order['money']; $user->save(); $memberRecord = new MemberRecord(); $record = $memberRecord->field('') ->where('user_id','eq',$user->id) ->where('end_time','>',date('Y-m-d H:i:s')) ->order('end_time desc') ->limit(1) ->select(); $order['start_time'] = count($record) > 0 ? $record[0]['end_time'] : date("Y-m-d H:i:s"); $order['end_time'] = date("Y-m-d H:i:s",(strtotime($order['start_time']) + 3600*24*$order['vip_day'])); //天数 $order['update_time'] = date("Y-m-d H:i:s"); $order['status'] = '1'; $order->save(); // 对应的渠道增加佣金 $channel = Channel::get(['id'=> $user['channel_id']]); if ($channel) { $brokerage = $channel['brokerage']; $channel['total_brokerage'] = $channel['total_brokerage'] + ( $order['money'] * ($brokerage / 100)); $channel->save(); } } $this->return_success(); } else { echo '微信支付失败'; } } /** * 将xml转为array */ public function xml_to_array($xml) { if (!$xml) { return false; } //将XML转为array //禁止引用外部xml实体 libxml_disable_entity_loader(true); $data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $data; } /** * 给微信发送确认订单金额和签名正确,SUCCESS信息 -xzz0521 */ private function return_success() { $return['return_code'] = 'SUCCESS'; $return['return_msg'] = 'OK'; $xml_post = '<xml> <return_code>' . $return['return_code'] . '</return_code> <return_msg>' . $return['return_msg'] . '</return_msg> </xml>'; echo $xml_post; exit; }