ccdv

本文中使用的编程语言是PHP,PHP框架是thinkPHP3.2.3.

一、支付类,含有支付、退款等接口。

<?php
/**
 * 微信支付类
 * Created by PhpStorm.
 * User: 科技
 * Date: 2020/4/26
 * Time: 10:30
 */

namespace Api;


class WxPayController
{
    /**
     * 小程序appid
     * @var string
     */
    private $appId;

    /**
     * 小程序secret
     * @var string
     */
    private $appSecret;

    /**
     * 商户平台商户id
     * @var string
     */
    private $mchId;

    /**
     * 商户平台密钥key
     * @var string
     */
    private $key;

    /**
     * 支付回掉地址
     * @var string
     */
    private $notifyUrl;

    /**
     * 获取用户唯一标识open_id api 接口地址
     * @var string
     */
    private $code2SessionApiUrl;

    /**
     * 统一下单api 接口地址
     * @var string
     */
    private $unifiedOrderApiUrl;

    /**
     * 错误信息
     * @var string
     */
    public $errorInfo;

    /**
     * WxPay constructor.
     */
    public function __construct()
    {
        $this->appId = C(\'APP_ID\');
        $this->appSecret = C("APP_SECRET");
        $this->mchId = C("MCH_ID");
        $this->key = C("KEY");
        $this->notifyUrl = (isset($_SERVER[\'REQUEST_SCHEME\']) ? ($_SERVER[\'REQUEST_SCHEME\'] . \'://\') : \'\') . $_SERVER[\'HTTP_HOST\'].\'/Api/Pay/notifyPay.html\';
        $this->code2SessionApiUrl = \'https://api.weixin.qq.com/sns/jscode2session\';
        $this->unifiedOrderApiUrl = \'https://api.mch.weixin.qq.com/pay/unifiedorder\';
    }

    /**
     * 添加错误信息
     * @param $err
     */
    public function setError($err)
    {
        $this->errorInfo = $err;
    }

    /**
     * 获取错误信息
     * @return string
     */
    public function getError()
    {
        return $this->errorInfo;
    }

    /**
     * 获取支付签名
     * @param $open_id
     * @param $order_no
     * @param $money
     * @return array
     */
    public function paySign($open_id, $order_no, $money)
    {
        if (!$open_id || !$order_no || !$money) {
            $this->setError(\'参数错误\');
            return [];
        }

        $prepay_id = $this->unifiedorder($open_id, $order_no, $money);

        if (!$prepay_id) {
            return [];
        }

        $params = array(
            \'appId\' => $this->appId,
            \'timeStamp\' => time(),
            \'nonceStr\' => encrypt(16),
            \'package\' => \'prepay_id=\' . $prepay_id,
            \'signType\' => \'MD5\',
        );

        $params[\'paySign\'] = $this->getSign($params);

        return $params;
    }

    /**
     * 异步签名验证
     * @param $data
     * @return bool
     */
    public function checkNotifySign($data)
    {
        if (!$data) {
            return false;
        }

        $sign = $data[\'sign\'];

        unset($data[\'sign\']);

        if ($sign == $this->getSign($data)) {
            return true;
        }

        return false;
    }

    /**
     * 异步回调处理成功时返回内容
     * @param $msg
     * @return string
     */
    public function notifyReturnSuccess($msg = \'OK\')
    {
        return \'<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[\' . $msg . \']]></return_msg></xml>\';
    }

    /**
     * 异步回调处理失败时返回内容
     * @param $msg
     * @return string
     */
    public function notifyReturnFail($msg = \'FAIL\')
    {
        return \'<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[\' . $msg . \']]></return_msg></xml>\';
    }

    /**
     * 统一下单
     * @param $open_id
     * @param $order_no
     * @param $money
     * @return string
     */
    private function unifiedOrder($open_id, $order_no, $money)
    {
        $params = [
            \'appid\' => $this->appId,
            \'mch_id\' => $this->mchId,
            \'nonce_str\' => encrypt(16),
            \'body\' => \'食品-订单\', //商品简单描述
            \'out_trade_no\' => $order_no, //商户系统内部订单号
            \'total_fee\' => priceyuantofen($money), //订单总金额,单位为分
            \'spbill_create_ip\' => get_client_ip(), //用户端ips
            \'notify_url\' => $this->notifyUrl, //通知地址
            \'trade_type\' => \'JSAPI\', //交易类型
            \'openid\' => $open_id, //用户标识
        ];

        $params[\'sign\'] = $this->getSign($params);

        $xmlData = arrayToXml($params);


        $returnXml = postXml($xmlData, $this->unifiedOrderApiUrl);

        $returnArr = xmlToArray($returnXml);


        if ($returnArr[\'return_code\'] == \'FAIL\') {

            $this->setError($returnArr[\'return_msg\']);
            return \'\';
        }

        return $returnArr[\'prepay_id\'];

    }

    /**
     * 获取签名
     * @param $params
     * @return string
     */
    private function getSign($params)
    {
        if (!$params) {
            return \'\';
        }

        //step1: 排序
        ksort($params);

        //step2:格式化参数
        $paramUrl = formatParams($params, false);

        //step3:追加key
        $paramUrl = $paramUrl . \'&key=\' . $this->key;

        //step4: md5加密
        $paramUrl = md5($paramUrl);

        //step5:转化为大写
        $sign = strtoupper($paramUrl);

        return $sign;
    }


    /*
     * 查询支付结果
     * @param $params
     * @return string
     *
     * */
    public function query($out_trade_no)
    {
        //对外暴露的退款接口
        $result = $this->wxQueryApi($out_trade_no);
        return $result;
    }


    /*
     * 查询支付结果
     * */
    private function wxQueryApi($out_trade_no)
    {
        //通过微信api进行退款流程
        $parma = array(
            \'appid\' => $this->appId,
            \'mch_id\' => $this->mchId,
            \'nonce_str\' => encrypt(16),
            \'out_trade_no\' => $out_trade_no,
        );

        $parma[\'sign\'] = $this->getSign($parma);
        $xmldata = arrayToXml($parma);

        $returnXml = postXml($xmldata, \'https://api.mch.weixin.qq.com/pay/orderquery\');
        $result = xmlToArray($returnXml);
        return $result;
    }


    /*
     * 微信退款
     * @param $params
     * @return string
     *
     * */
    public function refund($out_trade_no, $total_fee, $refund_fee, $out_refund_no)
    {
        //对外暴露的退款接口
        $result = $this->wxRefundApi($out_trade_no, $total_fee, $refund_fee, $out_refund_no);
        return $result;
    }

    /*
     * 退款接口
     * */
    private function wxRefundApi($out_trade_no, $total_fee, $refund_fee, $out_refund_no)
    {
        //通过微信api进行退款流程
        $parma = array(
            \'appid\' => $this->appId,
            \'mch_id\' => $this->mchId,
            \'nonce_str\' => encrypt(16),
            \'out_refund_no\' => $out_refund_no,
            \'out_trade_no\' => $out_trade_no,
            \'total_fee\' => priceyuantofen($total_fee),
            \'refund_fee\' => priceyuantofen($refund_fee),
            \'notify_url\' => (isset($_SERVER[\'REQUEST_SCHEME\']) ? ($_SERVER[\'REQUEST_SCHEME\'] . \'://\') : \'\') . $_SERVER[\'HTTP_HOST\'].\'/Api/Pay/notifyRefund.html\',
        );

        $parma[\'sign\'] = $this->getSign($parma);
        $xmldata = arrayToXml($parma);
        $xmlresult = curl_post_ssl(\'https://api.mch.weixin.qq.com/secapi/pay/refund\', $xmldata,  \'/apiclient_cert.pem\', \'/apiclient_key.pem\');

        $result = xmlToArray($xmlresult);
        return $result;
    }


    /*
  * 查看微信退款
  * @param $params
  * @return string
  *
  * */
    public function seeRefund($order_number)
    {
        //对外暴露的退款接口
        $result = $this->wxSeeRefundApi($order_number);
        return $result;
    }


    /*
     * 查看微信退款接口
     * */
    private function wxSeeRefundApi($order_number)
    {
        //通过微信api进行退款流程
        $parma = array(
            \'appid\' => $this->appId,
            \'mch_id\' => $this->mchId,
            \'nonce_str\' => encrypt(16),
            \'out_trade_no\' => $order_number,

        );

        $parma[\'sign\'] = $this->getSign($parma);
        $xmldata = arrayToXml($parma);

        $returnXml = postXml($xmldata, \'https://api.mch.weixin.qq.com/pay/refundquery\');

        $result = xmlToArray($returnXml);
        return $result;
    }



}

二、以上方法中所用的一些工具方法。


/**
 * PHP精确计算  主要用于货币的计算用
 * @param $n1 第一个数
 * @param $symbol 计算符号 + - * / %
 * @param $n2 第二个数
 * @param string $scale 精度 默认为小数点后两位
 * @return  string
 */

function pricecalc($n1, $symbol, $n2, $scale = \'2\')
{
    $res = "";
    switch ($symbol) {
        case "+"://加法
            $res = bcadd($n1, $n2, $scale);
            break;
        case "-"://减法
            $res = bcsub($n1, $n2, $scale);
            break;
        case "*"://乘法
            $res = bcmul($n1, $n2, $scale);
            break;
        case "/"://除法
            $res = bcdiv($n1, $n2, $scale);
            break;
        case "%"://求余、取模
            $res = bcmod($n1, $n2, $scale);
            break;
        default:
            $res = "";
            break;
    }
    return $res;
}

/**
 * 价格由元转分(用于微信支付单位转换)
 * @param $price 金额
 * @return int
 */
function priceyuantofen($price)
{
    $price = intval(pricecalc(100, "*", $price));
    return $price;
}

/**
 * 价格由分转元
 * @param $price 金额
 * @return float
 */
function pricefentoyuan($price)
{
    $price = pricecalc(priceformat($price), "/", 100);
    return $price;
}

/**
 * 价格格式化
 *
 * @param int $price
 * @return string    $price_format
 */
function priceformat($price)
{
    $price_format = number_format($price, 2, \'.\', \'\');
    return $price_format;

}
/**
 * array to xml
 * @param $arr
 * @return string
 */
function arrayToXml($arr)
{
    $xml = "<xml>";
    foreach ($arr as $key => $val) {
        if (is_array($val)) {
            $xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
        } else {
            $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
        }
    }
    $xml .= "</xml>";
    return $xml;
}

/**
 * xml to array
 * @param $xml
 * @return mixed
 */
function xmlToArray($xml)
{
    //禁止引用外部xml实体
    libxml_disable_entity_loader(true);

    $xmlstring = simplexml_load_string($xml, \'SimpleXMLElement\', LIBXML_NOCDATA);

    $val = json_decode(json_encode($xmlstring), true);

    return $val;
}

/**
 * 格式化参数 array to key1=valve1&key2=value2
 * @param $params
 * @param $url_encode
 * @return string
 */
function formatParams($params, $url_encode)
{
    if (!$params) {
        return \'\';
    }

    $paramUrl = "";

    ksort($params);

    foreach ($params as $k => $v) {
        if ($url_encode) {
            $v = urlencode($v);
        }

        $paramUrl .= $k . "=" . $v . "&";
    }

    if (strlen($paramUrl) > 0) {
        $paramUrl = substr($paramUrl, 0, strlen($paramUrl) - 1);
    }

    return $paramUrl;
}

/**
 * curl post xml
 * @param $xml 参数
 * @param $url 请求地址
 * @param int $second 设置超时
 * @return mixed
 */
function postXml($xml, $url, $second = 60)
{
    $ch = curl_init();
    //设置超时
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
    //设置header
    curl_setopt($ch, CURLOPT_HEADER, FALSE);
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
    //post提交方式
    curl_setopt($ch, CURLOPT_POST, TRUE);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);

    curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
    curl_setopt($ch, CURLOPT_TIMEOUT, 40);
    set_time_limit(0);

    //运行curl
    $data = curl_exec($ch);
    curl_close($ch);
    return $data;
}

//需要使用证书的请求
//file_cert_pem,file_key_pem两个退款必须的文件
function curl_post_ssl($url, $vars, $file_cert_pem, $file_key_pem, $second = 30, $aHeader = array())
{
    $ch = curl_init();
    //超时时间
    curl_setopt($ch, CURLOPT_TIMEOUT, $second);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    //这里设置代理,如果有的话
    //curl_setopt($ch,CURLOPT_PROXY, \'10.206.30.98\');
    //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

    //以下两种方式需选择一种

    //第一种方法,cert 与 key 分别属于两个.pem文件
    //默认格式为PEM,可以注释
    curl_setopt($ch, CURLOPT_SSLCERTTYPE, \'PEM\');
//        curl_setopt($ch,CURLOPT_SSLCERT,getcwd().\'/cert.pem\');
    curl_setopt($ch, CURLOPT_SSLCERT, __DIR__.$file_cert_pem);
    //默认格式为PEM,可以注释
    curl_setopt($ch, CURLOPT_SSLKEYTYPE, \'PEM\');
//        curl_setopt($ch,CURLOPT_SSLKEY,getcwd().\'/private.pem\');
    curl_setopt($ch, CURLOPT_SSLKEY, __DIR__.$file_key_pem);

    //第二种方式,两个文件合成一个.pem文件
//        curl_setopt($ch, CURLOPT_SSLCERT, getcwd() . \'/all.pem\');
    //要求结果为字符串且输出到屏幕上
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
    if (count($aHeader) >= 1) {
        curl_setopt($ch, CURLOPT_HTTPHEADER, $aHeader);
    }


    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);
    $data = curl_exec($ch);
    if ($data) {
        curl_close($ch);
        return $data;
    } else {
        $error = curl_errno($ch);
//            echo "call faild, errorCode:$error\n";

//        echo "curl出错,错误码:$error";
        curl_close($ch);
        return false;
    }
}

要说明的是退款接口wxRefundApi调用的curl_post_ssl方法需要传两个以pem结尾的文件,这两个文件需要传绝对路径,根据代码中的写法,只有把这两个文件放到curl_post_ssl所在文件同一级目录下面,才能正确的找到。

三、支付回调类。

<?php
/**
 * Created by PhpStorm.
 * User: 科技
 * Date: 2020/4/26
 * Time: 10:52
 */

namespace Api\Controller;

use Api\WxPayController;
use Common\Model\OrderModel;


class PayController
{

    /**
     *   状态 0已取消 1已下单 2已支付 3用户申请退款 4订单已完成 5商家同意退款  6微信平台接受退款异步返回申请成功 7异步返回退款申请失败  8统一下单异步返回支付失败  9退款成功  10统一下单异步返回成功
     */
    const STATUS_WAITING = 1;
    const STATUS_FAILED = 2;
    const STATUS_SUCCESS = 3;
    const STATUS_LOSE = 4;
    const STATUS_OTHER = 5;
    const STATUS_PROCESSING = 6;

    /**
     * 错误信息
     * @var string
     */
    public $errorInfo;

    /**
     * 小程序支付异步回调
     *
     */
    public function notifyPay()
    {

        $xml = file_get_contents(\'php://input\', \'r\');
        $resData = xmlToArray($xml);
        $wxPay = new WxPayController();

        M(\'pay_log\')->add([\'type\'=>1,\'data\'=>json_encode($resData),\'create_time\'=>time()]);

        if ($wxPay->checkNotifySign($resData)) {


            $result = $this->updateNotifyPayOrder($resData[\'return_code\'], $resData[\'openid\'], $resData[\'out_trade_no\'], pricefentoyuan($resData[\'total_fee\']), $resData[\'transaction_id\'], $resData);

            if ($result) {
                $resStr = $wxPay->notifyReturnSuccess();
            } else {
                $resStr = $wxPay->notifyReturnFail($this->errorInfo);
            }
        } else {
            $resStr = $wxPay->notifyReturnFail(\'签名验证失败\');
        }
        echo $resStr;
    }


    /**
     * 支付成功修改数据库
     * @param $result 支付状态
     * @param $open_id open_id
     * @param $out_trade_no 客户订单号
     * @param $money 金额
     * @param $wx_trade_no 微信支付订单号
     * @param $data
     * @return bool
     * @throws \Exception
     */
    public function updateNotifyPayOrder($result, $open_id, $out_trade_no, $money, $wx_trade_no, $data)
    {

        //记录异步通知日志


        //订单查询

        $orderInfo = (new orderModel())->getorderInfo([\'order_number\' => $out_trade_no], \'id,order_number,shop_id,pay_money,status,user_id\');

        if (empty($orderInfo)) {
            $this->errorInfo = \'订单不存在\';
            return false;

        }


        //如果订单状态为成功直接返回
        if (in_array($orderInfo[\'status\'],[2,10,4])) {
            return true;
        }


        //订单支付状态为未处理
        if ($orderInfo[\'status\'] == 1 || $orderInfo[\'status\'] == 8) {

            //验证金额
            if (bccomp($orderInfo[\'pay_money\'],$money,2)) {
                $this->errorInfo = \'订单金额有误\';
                return false;
            }


            //判断订单支付状态
            if ($result == \'SUCCESS\') {

                $model = new OrderModel();

                //开启事务处理机制
                $model->startTrans();

                //修改订单状态为成功
                $res_success = (new orderModel())->editOrder([\'status\' => 10], [\'id\' => $orderInfo[\'id\']]);

                if ($res_success) {
                    //如果都成立就提交
                    $model->commit();

                    return true;
                }else {

                    //先将原先的预处理进行回滚
                    $model->rollback();
                    $this->errorInfo = \'订单状态修改失败\';
                    return false;
                }
            } else {

                //修改订单状态为支付失败
                $res = (new orderModel())->editOrder([\'status\' => 8], [\'id\' => $orderInfo[\'id\']]);

                if (!$res) {

                    $this->errorInfo = \'订单状态修改失败\';
                    return false;

                }

            }
        }

        $this->errorInfo = \'订单处理失败!\';
        return false;
    }




    /**
     * 小程序申请退款异步回调
     *
     */
    public function notifyRefund()
    {
        $xml = file_get_contents(\'php://input\', \'r\');
        $resData = xmlToArray($xml);
        $wxPay = new WxPayController();

        M(\'pay_log\')->add([\'type\'=>2,\'data\'=>json_encode($resData),\'create_time\'=>time()]);

        if ($wxPay->checkNotifySign($resData)) {


            $result = $this->updateNotifyRefundOrder($resData[\'return_code\'], $resData[\'out_trade_no\'], pricefentoyuan($resData[\'total_fee\']), $resData[\'transaction_id\'], $resData);

            if ($result) {
                $resStr = $wxPay->notifyReturnSuccess();
            } else {
                $resStr = $wxPay->notifyReturnFail($this->errorInfo);
            }
        } else {
            $resStr = $wxPay->notifyReturnFail(\'签名验证失败\');
        }
        echo $resStr;
    }

    /**
     * 退款成功修改数据库
     * @param $result 支付状态
     * @param $open_id open_id
     * @param $out_trade_no 客户订单号
     * @param $money 金额
     * @param $wx_trade_no 微信支付订单号
     * @param $data
     * @return bool
     * @throws \Exception
     */
    public function updateNotifyRefundOrder($result, $out_trade_no, $money, $wx_trade_no, $data)
    {

        //记录异步通知日志


        //订单查询

        $orderInfo = (new orderModel())->getorderInfo([\'order_number\' => $out_trade_no], \'id,order_number,pay_money,status,user_id\');

        if (empty($orderInfo)) {
            $this->errorInfo = \'订单不存在\';
            return false;

        }


        //如果订单状态为成功直接返回
        if (in_array($orderInfo[\'status\'],[5,6,4])) {
            return true;
        }

        //订单支付状态为用户已经申请退款
        if ($orderInfo[\'status\'] == 3 ||$orderInfo[\'status\'] == 7) {


            //验证金额
            if (bccomp($orderInfo[\'pay_money\'],$money,2)) {
                $this->errorInfo = \'订单金额有误\';
                return false;
            }


            //判断订单支付状态
            if ($result == \'SUCCESS\') {

                $model = new OrderModel();

                //开启事务处理机制
                $model->startTrans();

                //修改订单状态为成功
                $res_success = (new orderModel())->editOrder([\'status\' => 6], [\'id\' => $orderInfo[\'id\']]);

                if ($res_success) {
                    //如果都成立就提交
                    $model->commit();

                    return true;
                }else {

                    //先将原先的预处理进行回滚
                    $model->rollback();
                    $this->errorInfo = \'订单状态修改失败\';
                    return false;
                }


            } else {


                //修改订单状态为退款申请失败
                $res = (new orderModel())->editOrder([\'status\' => 7], [\'id\' => $orderInfo[\'id\']]);

                if (!$res) {

                    $this->errorInfo = \'订单状态修改失败\';
                    return false;

                }

            }
        }

        $this->errorInfo = \'订单处理失败!\';
        return false;
    }


}

四、接口调用。

  /**
     * 订单支付,统一下单接口,获取支付签名
     * @access public
     * @param string $orderId 订单id
     * @param string $token
     * @return array
     */
    public function pay()
    {

        try {

            $orderInfo = $this->orderHandelCheck($this->data[\'orderId\']);

            if ($orderInfo[\'status\'] != 1 ) {
                $this->json(201, \'订单不是待支付状态\');

            }

            //调用支付类
            $wxPay = new WxPayController();

            //获取签名
            $paySign = $wxPay->paySign($this->openid, $orderInfo[\'order_number\'], $orderInfo[\'pay_money\']);

            if (!$paySign) {
                $this->json(201, $wxPay->getError());
            }

            $this->json(200, \'请求成功\', $paySign);


        } catch (\Exception $e) {
//            $this->json($e->getMessage());
            $this->json(0);
        }
    }

 /**
     * 查询订单支付结果,以进行下一步动作
     * @access public
     * @param int $orderId 订单id
     * @param string $token
     * @return array
     */
    public function payResult()
    {

        try {

            $orderInfo = $this->orderHandelCheck($this->data[\'orderId\']);

            if (!in_array($orderInfo[\'status\'],[1,10])) {
                if($orderInfo[\'status\']==8){
                    $this->json(201, \'统一下单接口返回失败\');
                }

                $this->json(201, \'订单不是待支付状态\');

            }

            //调用支付类
            $wxPay = new WxPayController();

            //获取查询结果
            $query_res = $wxPay->query($orderInfo[\'order_number\']);

            if ($query_res[\'return_code\']==\'SUCCESS\') {  //请求成功
            if ($query_res[\'result_code\']==\'SUCCESS\') {  //订单接收成功
            if ($query_res[\'trade_state\']==\'SUCCESS\') {  //交易状态

                $model = new OrderModel();

                //开启事务处理机制
                $model->startTrans();


                $ModelThink = new \Think\Model(); // 实例化一个model对象 没有对应任何数据表


                $sql = sprintf("SELECT `id`,`order_number`,`shop_id`,`create_time`,`pay_money`,`status` FROM `pre_order` WHERE `id` = %s FOR UPDATE ", $orderInfo[\'id\']);//查询语句

                $orderInfo=$ModelThink->query($sql)[0];


                //修改订单状态为成功
                $res_success = (new orderModel())->editOrder([\'pay_status\' => 1, \'status\' => 2], [\'id\' => $orderInfo[\'id\']]);

                if (!$res_success) {
                    //先将原先的预处理进行回滚
                    $model->rollback();
                    $this->json(201,\'订单状态修改失败\');

                }

                //保存账户余额表

                $walletModel = new ShopWalletModel();

                $shopWallet = $walletModel->getShopWalletInfo([\'shop_id\' => $orderInfo[\'shop_id\']], \'account\');

                if ($shopWallet) {

                    if ($walletModel->editShopWallet([\'account\' => bcadd($shopWallet[\'account\'], $orderInfo[\'pay_money\'], 2)], [\'shop_id\' => $orderInfo[\'shop_id\']])) {   //修改钱包金额

                        if ((new ShopWalletFlowModel())->addShopWalletFlow([\'shop_id\' => $orderInfo[\'shop_id\'], \'account\' => $orderInfo[\'pay_money\'], \'create_time\' => time(), \'order_id\' => $orderInfo[\'id\']])) { //添加钱包流水
                            //如果都成立就提交
                            $model->commit();

                            $this->json(200, \'支付成功\');
                        } else {
                            //先将原先的预处理进行回滚
                            $model->rollback();
                            $this->json(201,\'商户钱包流水添加失败!\');

                        }


                    } else {
                        //先将原先的预处理进行回滚
                        $model->rollback();
                        $this->json(201,\'账户信息保存失败!\');

                    }

                } else {

                    //先将原先的预处理进行回滚

                    $model->rollback();
                    $this->json(201,\'商户钱包有误!\');

                }


            }elseif($query_res[\'trade_state\']==\'REFUND\'){
                $this->json(201, \'转入退款\');
            }elseif($query_res[\'trade_state\']==\'NOTPAY\'){
                $this->json(201, \'未支付\');
            }elseif($query_res[\'trade_state\']==\'CLOSED\'){
                $this->json(201, \'已关闭\');
            }elseif($query_res[\'trade_state\']==\'USERPAYING\'){
                $this->json(201, \'用户支付中\');
            }elseif($query_res[\'trade_state\']==\'PAYERROR\'){
                $this->json(201, \'支付失败\');
            }else{
                $this->json(201, \'交易状态未知\');
            }

            }else{
                $this->json(201, $query_res[\'err_code_des\']);
            }

            }else{
                $this->json(201, $query_res[\'return_msg\']);
            }




        } catch (\Exception $e) {
            $this->json(0);
        }
    }

  /**
     * 请求退款
     * @access public
     * @param string $orderId 订单id
     * @param string $token
     * @return array
     */

public function refund(){

   $wxPay = new WxPayController();

    //申请退款
    $res_refund = $wxPay->refund($Order_info[\'order_number\'], $Order_info[\'pay_money\'], $Order_info[\'pay_money\'], $Order_info[\'refund_number\']);


    if ($res_refund[\'return_code\'] == \'SUCCESS\') { //接口请求成功
        if ($res_refund[\'result_code\'] == \'SUCCESS\') { //退款申请接受成功

            if ($model->editOrder([\'status\' => 5, \'Refund\' => [\'status\' => 2, \'handle_time\' => time()]], [\'id\' => $id], \'Refund\')) {
                $this->success("提交成功,等待微信平台审核通过!", \'\', true);

            }else{

                $this->error("修改订单状态失败,请尽快联系管理员处理!!!", \'\', true);
            }


        } else {

            $this->error("申请失败,微信接受退款失败," . $res_refund[\'err_code_des\'], \'\', true);
        }

    }else{
        $this->error("请求失败," . $res_refund[\'return_msg\'], \'\', true);
    }

}

 /**
     * 查询订单退款结果,以进行下一步动作
     * @access public
     * @param int $orderId 订单id
     * @param string $token
     * @return array
     */
function checkRefund(){

   $wxPay = new WxPayController();

     //退款进度
     $see_res = $wxPay->seeRefund($order_info[\'order_number\']);

     if($see_res[\'return_code\']==\'SUCCESS\'){  //请求成功

         if($see_res[\'result_code\']==\'SUCCESS\'){ //退款申请接收成功

         if($see_res[\'refund_status_0\']==\'SUCCESS\'){ //退款状态

             $model = new OrderModel();

             //由于要计算流水,开启事务
             //开启事务处理机制
             $model->startTrans();

             $ModelThink = new \Think\Model(); // 实例化一个model对象 没有对应任何数据表


             $sql = sprintf("SELECT `id`,`order_number`,`shop_id`,`create_time`,`pay_money`,`status` FROM `pre_order` WHERE `id` = %s FOR UPDATE ", $order_info[\'id\']);//查询语句

             $order_info=$ModelThink->query($sql)[0];

             if ($model->editOrder([\'status\' => 9], [\'id\' => $id])) {

                 $walletModel = new ShopWalletModel();

                 $shopWallet = $walletModel->getShopWalletInfo([\'shop_id\' => $order_info[\'shop_id\']], \'account\');


                 if ($shopWallet) {

                     if ($walletModel->editShopWallet([\'account\' => bcsub($shopWallet[\'account\'], $order_info[\'pay_money\'], 2)], [\'shop_id\' => $order_info[\'shop_id\']])) {

                         if ((new ShopWalletFlowModel())->addShopWalletFlow([\'shop_id\' => $order_info[\'shop_id\'], \'account\' => -$order_info[\'pay_money\'], \'create_time\' => time(), \'order_id\' => $id, \'scene\' => 2])) {
                             //如果都成立就提交
                             $model->commit();
                             $this->success("退款成功!", \'\', true);

                         } else {
                             //先将原先的预处理进行回滚
                             $model->rollback();
                             $this->error("流水添加失败,请重试或尽快联系管理员处理!!!", \'\', true);
                         }


                     } else {
                         //先将原先的预处理进行回滚
                         $model->rollback();
                         $this->error("钱包操作失败,请重试或尽快联系管理员处理!!!", \'\', true);
                     }

                 } else {

                     //先将原先的预处理进行回滚
                     $model->rollback();
                     $this->error("钱包有误,请重试或尽快联系管理员处理!!!", \'\', true);
                 }


             } else {
                 //先将原先的预处理进行回滚
                 $model->rollback();
                 $this->error("修改订单状态失败!请重试或尽快联系管理员处理!!", \'\', true);

             }


         }elseif($see_res[\'refund_status_0\']==\'REFUNDCLOSE\'){

             $this->success("退款关闭,请尽快联系管理员处理!!!", \'\', true);
         }elseif($see_res[\'refund_status_0\']==\'PROCESSING\'){

             $this->success("退款处理中!", \'\', true);
         }elseif($see_res[\'refund_status_0\']==\'CHANGE\'){

             $this->success("退款退款异常,请尽快联系管理员处理!!!", \'\', true);
         }


         }else{


             $this->error(\'退款申请接收失败,\'.$see_res[\'err_code_des\'], \'\', true);

         }
     }else{

         $this->error(\'请求失败,\'.$see_res[\'return_msg\'], \'\', true);

     }

}

接口使用的返回方法:

 protected function json($code=0,$message=\'\',$data=[])
    {

        if (empty($message)) {
            //通用提示信息
            switch ($code) {
                case 200:
                    $message = \'请求成功\';
                    break;
                case 0:
                    $message = \'请求失败\';
                    break;
                case -2:
                    $message = \'参数缺失\';
                    break;
                default:
                    $message = $message;
                    break;

            }
        }

        return $this -> ajaxReturn([\'code\' => $code, \'message\' => $message, \'data\' => $data]);

    }

本文参考的主要文章有:

PHP 微信小程序退款

分类:

技术点:

相关文章: