Laravel整合微信支付之Native 扫码支付模式二

发布时间:2018-01-06 编辑:小张个人博客 查看次数:5958

微信扫码支付模式二

模式二与模式一相比,流程更为简单,不依赖设置的回调支付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)

除被扫支付场景以外,商户系统先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再按扫码、JSAPIAPP等不同场景生成交易串调起支付。 

// 微信支付
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_noout_trade_notransaction_idrefund_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



出处:小张个人博客

网址:http://blog.023xs.cn/

您的支持是对博主最大的鼓励,感谢您的认真阅读。欢迎转载,但请保留该声明。

顶部

Copyright © 小张个人博客 All Rights Reserved 渝ICP备15006773号-1

联系方式:[email protected] | 本站文章仅供学习和参考

渝公网安备 50024102500267号