Laravel整合微信支付之Native 扫码支付模式二
发布时间:2018-01-06 编辑:小张个人博客 查看次数:6541
微信扫码支付模式二
模式二与模式一相比,流程更为简单,不依赖设置的回调支付URL。商户后台系统先调用微信支付的统一下单接口,微信后台系统返回链接参数code_url,商户后台系统将code_url值生成二维码图片,用户使用微信客户端扫码后发起支付。注意:code_url有效期为2小时,过期后扫码不能再发起支付。
微信扫码支付业务流程说明:
(1)商户后台系统根据用户选购的商品生成订单。
(2)用户确认支付后调用微信支付【统一下单API】生成预支付交易;
(3)微信支付系统收到请求后生成预支付交易单,并返回交易会话的二维码链接code_url。
(4)商户后台系统根据返回的code_url生成二维码。
(5)用户打开微信“扫一扫”扫描二维码,微信客户端将扫码内容发送到微信支付系统。
(6)微信支付系统收到客户端请求,验证链接有效性后发起用户支付,要求用户授权。
(7)用户在微信客户端输入密码,确认支付后,微信客户端提交授权。
(8)微信支付系统根据用户授权完成支付交易。
(9)微信支付系统完成支付交易后给微信客户端返回交易结果,并将交易结果通过短信、微信消息提示用户。微信客户端展示支付交易结果页面。
(10)微信支付系统通过发送异步消息通知商户后台系统支付结果。商户后台系统需回复接收情况,通知微信后台系统不再发送该单的支付通知。
(11)未收到支付通知的情况,商户后台系统调用【查询订单API】。
(12)商户确认订单已支付后给用户发货。
微信扫码支付配置项(WxPayConfig.php)
配置文件里面设置:微信支付分配的公众账号ID(企业号corpid即为此appId)、商户号(MCHID)异步接收微信支付结果通知的回调地址等
<?php return array ( // 微信支付配置项 'APPID' => 'wx426b3015555a46be', // 微信支付分配的公众账号ID(企业号corpid即为此appId) 'KEY' => '8934e7d15453e97507ef794cf7b0519d', 'MCHID' => '1900009851', // 微信支付分配的商户号 // 异步接收微信支付结果通知的回调地址,通知url必须为外网可访问的url,不能携带参数。 'NOTIFY_URL' => 'http://paysdk.weixin.qq.com/example/notify.php', 'CURL_PROXY_HOST' => '0.0.0.0', 'CURL_PROXY_PORT' => 0, 'REPORT_LEVENL' => 0, // 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报 //=======【证书路径设置】===================================== /** * TODO:设置商户证书路径 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载, * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书) * @var path */ 'SSLCERT_PATH' => app_path().'/Http/Controllers/Wxpay/cert/apiclient_cert.pem', 'SSLKEY_PATH' => app_path().'/Http/Controllers/Wxpay/cert/apiclient_key.pem', );
微信扫码支付-统一下单API(WxPayController.php)
除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPI、APP等不同场景生成交易串调起支付。
// 微信支付 public function WxPay(){ // 订单测试数据 $values['body'] = '老高:这次成功了吗?'; // 商品简单描述 $values['attach'] = 'test'; // 附加数据,在查询API和支付通知中原样返回 $values['out_trade_no'] = Config::get('WxPayConfig.MCHID').date("YmdHis"); // 商户订单号 $values['total_fee'] = '1'; // 订单总金额,单位为分 $values['time_start'] =date("YmdHis"); // 订单生成时间 $values['time_expire'] = date("YmdHis", time() + 600); // 交易结束时间 $values['goods_tag'] = 'test'; // 订单优惠标记,使用代金券或立减优惠功能时需要的参数 $values['trade_type'] = 'NATIVE'; // 交易类型 取值如下:JSAPI,NATIVE,APP等 $values['product_id'] = '123456789'; // 商品ID trade_type=NATIVE时,此参数必传。此参数为二维码中包含的商品ID $wx =new WxPay(); $wx -> setValues($values); $res = $wx ->unifiedOrder(); // 调用统一下单接口,发起支付请求 // 生成支付二维码 $qrcode = 'http://paysdk.weixin.qq.com/example/qrcode.php?data='.urlencode($res['code_url']); echo "订单号:". $values['out_trade_no'].'<br/>'; echo "<img src='$qrcode'/>".'<br/>'; echo "微信扫描二维码进行支付!"; dd($res); }
微信扫码支付-申请退款API(WxPayController.php)
当交易发生之后一段时间内,由于买家或者卖家的原因需要退款时,卖家可以通过退款接口将支付款退还给买家,微信支付将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家帐号上。
注意:
1、交易时间超过一年的订单无法提交退款
2、微信支付退款支持单笔交易分多次退款,多次退款需要提交原支付订单的商户订单号和设置不同的退款单号。申请退款总金额不能超过订单金额。 一笔退款失败后重新提交,请不要更换退款单号,请使用原商户退款单号
3、请求频率限制:150qps,即每秒钟正常的申请退款请求次数不超过150次
错误或无效请求频率限制:6qps,即每秒钟异常或错误的退款申请请求不超过6次
4、每个支付订单的部分退款次数不能超过50次
5、申请退款需要双向证书
// 申请退款 public function refund(){ $values['out_trade_no'] = '190000985120180105155111'; // 商户订单号 $values['transaction_id'] = '';// 微信订单号 $values['out_refund_no'] = Config::get('WxPayConfig.MCHID').date("YmdHis"); // 商户退款单号 $values['total_fee'] = '1'; // 订单总金额,单位为分 $values['refund_fee'] = '1'; // 退款总金额 $values['op_user_id'] = Config::get('WxPayConfig.MCHID'); // 判断操作员帐号, 默认为商户号是否存在 $wx =new WxPay(); $wx -> setValues($values); $res = $wx -> refund(); dd($res); }
微信扫码支付-退款结果通知API(WxPayController.php)
提交退款申请后,通过调用该接口查询退款状态。退款有一定延时,
用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。
WxPayRefundQuery中out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个
当商户申请的退款有结果后,微信会把相关结果发送给商户,商户需要接收处理,并返回应答。
对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,微信会通过一定的策略定期重新发起通知,尽可能提高通知的成功率,但微信不保证通知最终能成功。 (通知频率为15/15/30/180/1800/1800/1800/1800/3600,单位:秒)
注意:同样的通知可能会多次发送给商户系统。商户系统必须能够正确处理重复的通知。
推荐的做法是,当收到通知进行处理时,首先检查对应业务数据的状态,判断该通知是否已经处理过,如果没有处理过再进行处理,如果处理过直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。
// 退款查询 public function refundQuery(){ $values['out_trade_no'] = '190000985120180105155111'; // 商户订单号 $wx =new WxPay(); $wx -> setValues($values); $res = $wx -> refundQuery(); dd($res); }
class WxPay extends Model{ protected $values = []; public function setValues($value){ $this ->values = $value; } /** * * 统一下单,WxPayUnifiedOrder中out_trade_no、body、total_fee、trade_type必填 * appid、mchid、spbill_create_ip、nonce_str不需要填入 * @param WxPayUnifiedOrder $inputObj * @param int $timeOut * @throws WxPayException * @return 成功时返回,其他抛异常 */ public function unifiedOrder($timeOut = 6){ $url = "https://api.mch.weixin.qq.com/pay/unifiedorder"; //检测必填参数 if(!isset($this->values['out_trade_no'])) { exit("缺少统一支付接口必填参数out_trade_no!"); }else if(!isset($this->values['body'])){ exit("缺少统一支付接口必填参数body!"); }else if(!isset($this->values['total_fee'])) { exit("缺少统一支付接口必填参数total_fee!"); }else if(!isset($this ->values['trade_type'])) { exit("缺少统一支付接口必填参数trade_type!"); } //关联参数 if($this->values['trade_type'] == "JSAPI" && !isset($this->values['openid'])){ exit("统一支付接口中,缺少必填参数openid!trade_type为JSAPI时,openid为必填参数!"); } if($this->values['trade_type'] == "NATIVE" && !isset($this->values['product_id'])){ exit("统一支付接口中,缺少必填参数product_id!trade_type为JSAPI时,product_id为必填参数!"); } return $this ->WxConfig($url,'',6); } /** * * 申请退款,WxPayRefund中out_trade_no、transaction_id至少填一个且 * out_refund_no、total_fee、refund_fee、op_user_id为必填参数 * appid、mchid、spbill_create_ip、nonce_str不需要填入 * @param WxPayRefund $inputObj * @param int $timeOut * @throws WxPayException * @return 成功时返回,其他抛异常 */ public function refund($timeOut = 6){ $url = "https://api.mch.weixin.qq.com/secapi/pay/refund"; //检测必填参数 if(!isset($this -> values['out_trade_no']) && !isset($this -> values['transaction_id'])) { exit("退款申请接口中,out_trade_no、transaction_id至少填一个!"); }else if(!isset($this->values['out_refund_no'])){ exit("退款申请接口中,缺少必填参数out_refund_no!"); }else if(!isset($this -> values['total_fee'])){ exit("退款申请接口中,缺少必填参数total_fee!"); }else if(!isset($this -> values['refund_fee'])){ exit("退款申请接口中,缺少必填参数refund_fee!"); }else if(!isset($this->values['op_user_id'])){ exit("退款申请接口中,缺少必填参数op_user_id!"); } return $this ->WxConfig($url,true,6); } /** * 查询退款 * 提交退款申请后,通过调用该接口查询退款状态。退款有一定延时, * 用零钱支付的退款20分钟内到账,银行卡支付的退款3个工作日后重新查询退款状态。 * WxPayRefundQuery中out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个 * appid、mchid、spbill_create_ip、nonce_str不需要填入 * @param WxPayRefundQuery $inputObj * @param int $timeOut * @throws WxPayException * @return 成功时返回,其他抛异常 */ public function refundQuery($timeOut = 6) { $url = "https://api.mch.weixin.qq.com/pay/refundquery"; //检测必填参数 if(!isset($this -> values['out_refund_no']) && !isset($this -> values['out_trade_no']) && !isset($this -> values['transaction_id']) && !isset($this -> values['refund_id'])) { exit("退款查询接口中,out_refund_no、out_trade_no、transaction_id、refund_id四个参数必填一个!"); } return $this ->WxConfig($url,'',6); } // APPID\MCHID\签名等配置 public function WxConfig($url,$useCert = false,$timeOut){ if($url == "https://api.mch.weixin.qq.com/pay/unifiedorder"){ $this->values['notify_url'] = Config::get('WxPayConfig.NOTIFY_URL') ;//异步通知url $this -> values['spbill_create_ip'] = $_SERVER['REMOTE_ADDR']; //终端ip $this -> values['appid'] = Config::get('WxPayConfig.APPID'); //公众账号ID $this -> values['mch_id'] =Config::get('WxPayConfig.MCHID'); //商户号 $this -> values['nonce_str'] = $this -> getNonceStr() ;//随机字符串 //签名 $this->SetSign(); $xml = $this->ToXml(); // $startTimeStamp = self::getMillisecond();//请求开始时间 $response = $this -> postXmlCurl($xml, $url, $useCert, $timeOut); $result = $this -> Init($response); // self::reportCostTime($url, $startTimeStamp, $result);//上报请求花费时间 }else{ $this -> values['appid'] = Config::get('WxPayConfig.APPID'); //公众账号ID $this -> values['mch_id'] =Config::get('WxPayConfig.MCHID'); //商户号 $this -> values['nonce_str'] = $this -> getNonceStr() ;//随机字符串 //签名 $this->SetSign(); $xml = $this->ToXml(); $response = $this -> postXmlCurl($xml, $url, $useCert, $timeOut); $result = $this -> Init($response); } return $result; }
重要提示:WxPay.php文件中只是部分代码,点击查看完整代码: WxPay.php.txt
Copyright © 小张个人博客 All Rights Reserved 渝ICP备15006773号-1
联系方式:[email protected] | 本站文章仅供学习和参考