小言_互联网的博客

微信小程序支付 退款 订单查询 退款查询

491人阅读  评论(0)

基于thinkphp5框架

支付

/**
     * 预支付请求接口(POST)
     * @param string $openid openid
     * @param string $body 商品简单描述
     * @param string $order_sn 订单编号
     * @param string $total_fee 金额
     * @return  json的数据
     */
    public function prepay()
    {
        tp_log('预支付请求数据===>' . json_encode($_POST), 'prepay', request()->controller());
        $goods_user = db('tf_goods_user')->where(array('order_no' => $_POST['order_no']))->find();
        $goods = db('tf_goods')->where(array('id' => $goods_user['goods_id']))->find();
        //判断产品的数量
        if (($goods['sales_initial'] - $goods['sales_actual']) <= 0) {
            $return['status'] = 0;
            $return['info'] = '此产品已售完';
            exit(json_encode($return));
        }

        $order_no = $_POST['order_no']; //订单号
        $is_sale = $_POST['is_sale'];
        $openid = $_POST['openid'];
        $goods_name = $_POST['goods_name'];
        $pay_price = $_POST['price'];
        $attach['is_sale'] = $_POST['is_sale'];
        $attach['sale_id'] = $_POST['sale_id'];
        $nonce_str = $this->nonce_str();//随机字符串


        $order_no_ssh = $this->get_orderssh(); //商户订单号
//注意 订单号为自己创建的订单 和支付没有任何关系 商户订单号是支付单号 用来支付的 每当订单号发起支付 就会有新的商户订单号 商户订单号是不重复的  发起一次支付就要生成新的商户订单号 要保存下来 订单表要有对应的支付订单表 而订单号与商户订单号是一对多的关系 订单表最终保存的商户订单号是支付成功的那个 也可以 没调起支付就根据订单号去修改订单表的商户订单号 只有商户订单号才能发起退款 退款查询等操作  商户订单号(out_trade_no)

        //组装支付数据
        $data = [
            'appid' => config('pay.APPID'),
            'mch_id' => config('pay.MCHID'),
            'nonce_str' => $nonce_str,
            'body' => $goods_name,  //商品名称组合
            'attach' => json_encode($attach),
            'out_trade_no' => $order_no_ssh,//$order_no,        //订单号 商户订单号
            'total_fee' => intval($pay_price * 100),
            'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
            'notify_url' => config('pay.NOTIFY_URL'),
            'trade_type' => 'JSAPI',
            'openid' => $openid
        ];

        //订单支付表创建订单支付数据
        $p_o_data['createtime'] = time();
        $p_o_data['order_no'] = $order_no;
        $p_o_data['order_no_ssh'] = $order_no_ssh;
        $p_o_data['ready'] = json_encode($data);
        $p_o_return = db('tf_pay_order')->insert($p_o_data);
        if(!$p_o_return){
            //失败
            $return['status'] = -1;
            $return['info'] = $p_o_data;
            exit(json_encode($return));
        }

        // 获取签名
        $sign = $this->makeSign($data);
        $data['sign'] = $sign;
        $xml = $this->toXml($data);
        $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //发起支付接口链接
        //发起预支付请求
        $prepay_return_reslut_xml = $this->http_request($url, $xml);
        $xml_to_arr = $this->fromXml($prepay_return_reslut_xml);
        $return_result = json_encode($xml_to_arr, true);
        tp_log('预支付请求返回数据array===>' .$return_result , 'prepay', request()->controller());
        //记录预支付返回信息
        db('tf_goods_order')->where(array('order_no' => $order_no))
            ->update(array(
                'go_pay' => $return_result,
                'updatetime' => time(),
                'updateuser' => $openid
            ));
        if($xml_to_arr['return_code'] == 'SUCCESS' && $xml_to_arr['result_code'] == 'SUCCESS'){
            //成功

            $time = time();
            //临时数组用于签名
            $tmp = [
                'appId' => config('pay.APPID'),
                'nonceStr' => $nonce_str,
                'package' => 'prepay_id='.$xml_to_arr['prepay_id'],
                'signType' => 'MD5',
                'timeStamp' => "$time",
            ];
            $data['timeStamp'] = "$time";//时间戳
            $data['nonceStr'] = $nonce_str;//随机字符串
            $data['signType'] = 'MD5';//签名算法,暂支持 MD5
            $data['package'] = 'prepay_id='.$xml_to_arr['prepay_id'];//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
            $data['paySign'] = $this->makeSign($tmp);//签名,具体签名方案参见微信公众号支付帮助文档;$data['out_trade_no'] = $out_trade_no;


            $return['status'] = 1;
            $return['info'] = $data;
        }else{
            //失败
            $return['status'] = -1;
            $return['info'] = $xml_to_arr;
        }
        exit(json_encode($return));
    }

 //curl请求
    public function http_request($url, $data = null, $headers = array())
    {
        $curl = curl_init();
        if (count($headers) >= 1) {
            curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        }
        curl_setopt($curl, CURLOPT_URL, $url);


        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);


        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

退款

/**
     * 申请退款API
     * @param $transaction_id
     * @param  double $total_fee 账单总金额
     * @param  double $refund_fee 退款金额
     * @return bool
     * @throws BaseException
     */
    public function refund()
    {

        $transaction_id = '4200000712202007274705432240';
        $total_fee = '0.01';
        $refund_fee = '0.01';
        // 当前时间
        $time = time();
        // 生成随机字符串
        $nonceStr = md5($time . $transaction_id . $total_fee . $refund_fee);
        // API参数
        $params = [
            'appid' => config('pay.APPID'),
            'mch_id' => config('pay.MCHID'),
            'nonce_str' => $nonceStr,
            'transaction_id' => $transaction_id,
            'out_refund_no' => $time,
            'total_fee' => $total_fee * 100,
            'refund_fee' => $refund_fee * 100,
            'notify_url' => config('pay.NOTIFY_URL_REFUND'),//退款回调地址
        ];
        // 生成签名
        $params['sign'] = $this->makeSign($params);

        tp_log('退款请求数据===>' . json_encode($params), 'refund', request()->controller());

        // 请求API
        $url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        $result = $this->post($url, $this->toXml($params), true, $this->getCertPem());
        $prepay = $this->fromXml($result);
        // 请求失败
        if (empty($result)) {
            throw new BaseException(['msg' => '微信退款api请求失败']);
        }
        // 格式化返回结果
        $prepay = $this->fromXml($result);
        tp_log('退款返回数据===>' . json_encode($prepay), 'refund', request()->controller());
        // 请求失败
//        if ($prepay['return_code'] === 'FAIL') {
//            throw new BaseException(['msg' => 'return_msg: ' . $prepay['return_msg']]);
//        }
//        if ($prepay['result_code'] === 'FAIL') {
//            throw new BaseException(['msg' => 'err_code_des: ' . $prepay['err_code_des']]);
//        }
        return true;
    }
    /**
     * 模拟POST请求
     * @param $url
     * @param array $data
     * @param bool $useCert
     * @param array $sslCert
     * @return mixed
     */
    public function post($url, $data = [], $useCert = false, $sslCert = [])
    {
        $header = [
            'Content-type: application/json;'
        ];
        $curl = curl_init();
                //如果有配置代理这里就设置代理
//        if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0"
//            && WxPayConfig::CURL_PROXY_PORT != 0){
//            curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
//            curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
//        }

        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_POST, TRUE);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        if ($useCert == true) {
            // 设置证书:cert 与 key 分别属于两个.pem文件
            curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
            curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
            curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
            curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
        }
        $result = curl_exec($curl);
        curl_close($curl);
        return $result;
    }

订单查询

/**
     * 订单查询
     * @param $out_trade_no
     * @return mixed
     * @throws BaseException
     */
    public function orderquery()
    {
         $transaction_id = '4200000712202007274705432240';//微信订单号
        // 当前时间
        $time = time();
        // 生成随机字符串
        $nonce_str = md5($time . mt_rand(00000,99999));
        //API参数
        $params = [
            'appid'        => config('pay.APPID'),             //公众号ID
            'mch_id'       => config('pay.MCHID'),  //商户号
            'transaction_id' => $transaction_id,            //商户订单号
            'nonce_str'    => $nonce_str,             // 随机字符串
        ];
        //生成签名
        $params['sign'] = $this->makeSign($params);
        //请求API
        $url = 'https://api.mch.weixin.qq.com/pay/orderquery';
        $result = $this->post($url, $this->toXml($params));
        $prepay = $this->fromXml($result);
        // 请求失败
        if ($prepay['return_code'] === 'FAIL') {
            throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]);
        }
        if ($prepay['result_code'] === 'FAIL') {
            throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]);
        }
        return $prepay;
    }

退款查询

/**
     * 退款查询
     * @param $out_trade_no
     * @return mixed
     * @throws BaseException
     */
    public function refundquery()
    {
        $transaction_id = '4200000712202007274705432240';//微信订单号
        // 当前时间
        $time = time();
        // 生成随机字符串
        $nonce_str = md5($time . mt_rand(00000,99999));
        //API参数
        $params = [
            'appid'        => config('pay.APPID'),             //公众号ID
            'mch_id'       => config('pay.MCHID'),  //商户号
            'transaction_id' => $transaction_id,            //商户订单号
            'nonce_str'    => $nonce_str,             // 随机字符串
        ];
        //生成签名
        $params['sign'] = $this->makeSign($params);
        //请求API
        $url = 'https://api.mch.weixin.qq.com/pay/refundquery';
        $result = $this->post($url, $this->toXml($params));
        $prepay = $this->fromXml($result);
        dump($prepay);die;
        // 请求失败
        if ($prepay['return_code'] === 'FAIL') {
            throw new BaseException(['msg' => $prepay['return_msg'], 'code' => 0]);
        }
        if ($prepay['result_code'] === 'FAIL') {
            throw new BaseException(['msg' => $prepay['err_code_des'], 'code' => 0]);
        }
        return $prepay;
    }

支付成功,进行回调

public function index()
    {
        $data = file_get_contents('php://input');
        $data = $this->FromXml($data);
        tp_log('支付回调数据===>' . json_encode($data), 'index', request()->controller());
        // 保存微信服务器返回的签名sign
        $data_sign = $data['sign'];
        // sign不参与签名算法
        unset($data['sign']);
        $sign = $this->makeSign($data);//回调验证签名

        $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
        $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';

        if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
       // 支付成功 进行你的逻辑处理
        }
echo $str_success;//str_error  告知微信 你已的逻辑处理完毕 不用再推送或再次推送你结果
   }

退款成功 进行回调

/*
     * 小程序 退款结果通知
     */
    public function refund(){

        $data = file_get_contents('php://input');
        $data = $this->FromXml($data);
        tp_log('退款回调数据===>' . json_encode($data), 'refund', request()->controller());

        //对加密的字符串解密
        $req_info_xml = openssl_decrypt(base64_decode($data['req_info']), 'aes-256-ecb', md5(config('pay.KEY')),OPENSSL_RAW_DATA);
        $req_info = $this->FromXml($req_info_xml);

//        // 保存微信服务器返回的签名sign
//        $data_sign = $data['sign'];
//        // sign不参与签名算法
//        unset($data['sign']);
//        $sign = $this->makeSign($data);//回调验证签名
//
//        $str_success = '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
//        $str_error = '<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名失败]]></return_msg></xml>';
//
//
//
//        if (($sign === $data_sign) && ($data['return_code'] == 'SUCCESS') && ($data['result_code'] == 'SUCCESS')) {
//            tp_log('退款成功===>', 'refund', request()->controller());
//            //去修改订单的状态 和支付回调的一样 修改成功 告知微信 不在推送
//        }
    }

用到的方法

/**
     * 生成签名
     * @param $values
     * @return string 本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
     */
    private function makeSign($values)
    {
        //签名步骤一:按字典序排序参数
        ksort($values);
        $string = $this->toUrlParams($values);
        //签名步骤二:在string后加入KEY
        $string = $string . '&key=' . config('pay.KEY');
        //签名步骤三:MD5加密
        $string = md5($string);
        //签名步骤四:所有字符转为大写
        $result = strtoupper($string);
        return $result;
    }
    private function ToUrlParams($array)
    {
        $buff = "";
        foreach ($array as $k => $v) {
            if ($k != "sign" && $v != "" && !is_array($v)) {
                $buff .= $k . "=" . $v . "&";
            }
        }
        $buff = trim($buff, "&");
        return $buff;
    }

    /**
     * 输出xml字符
     * @param $values
     * @return bool|string
     */
    private function toXml($values)
    {
        if (!is_array($values)
            || count($values) <= 0
        ) {
            return false;
        }
        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * 将xml转为array
     * @param $xml
     * @return mixed
     */
    private function fromXml($xml)
    {
        // 禁止引用外部xml实体
        libxml_disable_entity_loader(true);
        return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
    }

    /**
     * 获取cert证书文件
     * @return array
     * @throws BaseException
     */
    private function getCertPem()
    {
//        if (empty($this->config['cert_pem']) || empty($this->config['key_pem'])) {
//            throw new BaseException(['msg' => '请先到后台小程序设置填写微信支付证书文件']);
//        }
        // cert目录
        $filePath = EXTEND_PATH.'wxpay/cert/';
        return [
            'certPem' => $filePath . 'apiclient_cert.pem',
            'keyPem' => $filePath . 'apiclient_key.pem'
        ];
    }
/**
     * 生成商户订单号
     */
    public function get_orderssh()
    {
        return date("YmdHis") . mt_rand(10000000, 99999999);
    }

证书路径

config配置


转载:https://blog.csdn.net/qq_37468919/article/details/107617288
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场