首先引用一下微信官方文档的业务流程时序图,这是最简洁明了的:
商户系统和微信支付系统主要交互:
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;
}