PHP之 微信支付 "查询企业付款银行卡API" 或 "查询给企业付款是否到账" 功能业务处理

一、情景简述

之前做了微信付款到企业银行卡的功能,但是,给客户打款后,次日才能到账,为及时进行反馈,于是又做了"查询给企业付款是否到账"的功能。这块,我直接写了一个类,进行处理,下面,就是整个类的代码!

微信文档:https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=24_3

二、相关注意

1、这里涉及到一些敏感配置的,都在配置文件里,还有,"查询给企业付款是否到账"需要用到证书,这个需要提前准备,切记!
2、partner_trade_no参数,是在打款给客户银行卡账号时生成的一串字符,你可以自己存储,也可以从微信端返回的结果数据中获取。
3、查询是否到账,到账的情况是return_code、result_code、err_code全为true时,pay_succ_time不为空,表示已到账!

三、核心代码

<?php  defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * 查询给企业付款是否到账 - Service
 *
 * @desc 查看打款到银行卡的钱是否到账,如果,到账,更新distribute_log表 is_received 为 1
 * @author NangongYi
 * @time 2019/09/28 01:38:59
 *
 */

class Check_account_service extends FIT_Service
{

    /**
     * 字符池
     */
    const STING_POOL = '23456789ABCDEFGHJKLMNPQRSTUVWXYabcdefghijkmnpqrstuvwxy';

    /**
     * 字符长度
     */
    const STR_LENGTH = 18;

    /**
     * 构造方法 - 继承父类
     */
    public function __construct ()
    {
        parent::__construct();
    }

    /**
     * 微信 API - 配置参数
     */
    private function get_api_config_param()
    {
        $this->load->config('dict/dict_distribute.php');
        return $this->config->item('API_CONFIG');
    }

    /**
     * 查看订单分账是否到账
     * @param string $partner_trade_no : 分账时生成的唯一码
     * @return bool
     */
    private function check_order_distribute_is_received($partner_trade_no)
    {
        // 配置参数
        $api_config = $this->get_api_config_param();
        // 随机字符串
        $nonce_str = $this->product_random_str();
        // 准备数据
        $data = ['mch_id'=>$api_config['mch_id'], 'partner_trade_no'=>$partner_trade_no, 'nonce_str'=>$nonce_str];
        // 签名
        $sign = $this->product_sign_str($data);
        // xml数据整合
        $xmlData = $this->xml($data, $sign);
        // 数据请求
        $result = $this->curl_post_we_chat($api_config['query_bank'], $xmlData, true);
        // 结果处理
        if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' && $result['err_code'] == 'SUCCESS'){
            $success = ['is_received'=>1, 'received_time'=>$result['pay_succ_time']]; // 成功,返回到账时间,状态为 1
            return !empty($result['pay_succ_time']) ? $success : false;
        }else{
            $error = ['is_received'=>-1, 'rec_error_reason'=>$result['reason']]; // 失败,返回失败原因,状态为 -1,异常
            return $error;
        }
    }

    /**
     * xml数据 - 整合
     * @param array $data : 微信配置参数
     * @param string $sign : 生成签名
     * @return string
     */
    private function xml($data, $sign)
    {
        $xmlData="<xml>
    <mch_id>".$data['mch_id']."</mch_id>
    <nonce_str>".$data['nonce_str']."</nonce_str>
    <partner_trade_no>".$data['partner_trade_no']."</partner_trade_no>
    <sign>".$sign."</sign>
    </xml>";
        return $xmlData;
    }

    /**
     * 遍历所有的分账日志表中未付款记录,并进行标记
     * @desc 判断,如果到账,更新 distribute_log 表 is_received = 1
     */
    public function process_no_received_orders()
    {
        $this->load->dao("order_dao");
        $no_received_orders = $this->order_dao->get_no_received_orders();
        if(!$no_received_orders){
            return [];
        }
        $no_received_orders = $this->process_partner_trade_no($no_received_orders);
        $w_orderids = array_column($no_received_orders, null, 'partner_trade_no');
        $flag = 1;
        foreach ($w_orderids as $key=>$val) {
            // 过滤掉微信订单id为空的数据
            if(empty($val['partner_trade_no'])) continue;
            // 查看分账是否到账
            $res = $this->check_order_distribute_is_received($key);
            if(!$res) continue;
            // 如果到账,更改分账订单的状态为已分账 1
            $up_log = $this->order_dao->update_distribute_log_received($val['orderid'], $res);
            if(!$up_log) $flag --;
        }
        return $flag;
    }

    /**
     * 处理返回数据,返回 partner_trade_no
     * @param array $data : 订单数据
     * @return array
     */
    private function process_partner_trade_no($data)
    {
        foreach ($data as $key=>$val) {
            $data[$key]['partner_trade_no'] = $this->get_partner_trade_no($val['plg_log_info']);
        }
        return $data;
    }

    /**
     * 从json对象字符串中,返回 partner_trade_no
     * @param string $string : json对象
     * @return string
     */
    private function get_partner_trade_no($string)
    {
        $result = json_decode(substr($string,strrpos($string, '=')+1),true);
        return $result['partner_trade_no'];
    }

    /**
     * cURL方式POST数据到微信
     * @param string $url : 请求地址
     * @param array $data : 发送数据
     * @return mixed
     */
    private function curl_post_we_chat($url, $data, $ssl = false)
    {
        $api_config = $this->get_api_config_param();
        $ch = curl_init ();
        curl_setopt ( $ch, CURLOPT_URL, $url );
        curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
        curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
        if($ssl) {
            curl_setopt ( $ch,CURLOPT_SSLCERT,$api_config['sslcert']);
            curl_setopt ( $ch,CURLOPT_SSLKEY,$api_config['sslkey']);
        }
        curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
        curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
        curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
        curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            return 'Errno: '.curl_error($ch);
        }
        curl_close($ch);
        return $this->xmlToArray($result);
    }

    /**
     * 生成签名
     * @param array $paramArray : 微信请求参数
     * @param bool $isencode
     * @return mixed
     */
    private function product_sign_str($paramArray, $isencode=false)
    {
        $api_config = $this->get_api_config_param();
        $paramStr = '';
        ksort($paramArray);
        $i = 0;
        foreach ($paramArray as $key => $value)
        {
            if ($key == 'Signature'){
                continue;
            }
            if ($i == 0){
                $paramStr .= '';
            }else{
                $paramStr .= '&';
            }
            $paramStr .= $key . '=' . ($isencode?urlencode($value):$value);
            ++$i;
        }
        $stringSignTemp=$paramStr."&key=".$api_config['key'];
        $sign=strtoupper(md5($stringSignTemp));
        return $sign;
    }

    /**
     * 生成的随机字符串(小于32位)
     * @return string $randStr : 返回32位的字符
     */
    private function product_random_str()
    {
        $string = self::STING_POOL;
        $length = self::STR_LENGTH;
        $randStr = '';
        for($i = 0; $i < $length; $i++){
            $randStr .= $string[mt_rand(0, strlen($string)-1)];
        }
        return $randStr;
    }

    /**
     * 将xml转换成数组
     * @params xml $xml : xml数据
     * return array $data : 返回数组
     */
    private function xmlToArray($xml)
    {
        libxml_disable_entity_loader(true);//禁止引用外部xml实体
        $xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
        return json_decode(json_encode($xmlstring),true);
    }
}

四、写在最后

一开始看文档的时候,感觉微信的文档,写的还是不那么尽人意,所以,读了好几遍,才有所理解,其关键点,在于“签名的生成”,这里需要注意,另外,通过Curl函数传输数据的时候,会用到证书,这里文档有提到,但还是在这个地方,纠结了好久!总之,涉及到支付这块的,微信都比较严谨,需要细心理解、处理!
发布了59 篇原创文章 · 获赞 2 · 访问量 5579

猜你喜欢

转载自blog.csdn.net/LDR1109/article/details/102592608