php 微信小程序 V3 支付结果通知 小程序退款V3 退款结果通知

小程序支付&&退款前配置

  • 用商户平台上设置的APIv3密钥 【微信商户平台—>账户设置—>API安全—>设置APIv3密钥】;(不设置收不到回调)
  • 在商户平台的产品中心进行支付配置;
  • 用商户平台上设置的API密钥 证书 查看证书可以看到证书序列号 记为serial_no
  • 支付地址中不能带参数 例如tp的 index.php?a=index&m=main 做成 index/main
  • [商户平台]—>交易中心—>退款管理-》退款配置 中提交退款notify_url设置

支付结果通知 && 退款结果通知

AysController 接收回调信息控制器
<?php
/**
 * Created by PhpStorm.
 * User: zhaowenhui
 * Date: 2020/5/19
 * Time: 10:06
 */
namespace Wap\Controller;
use Org\Util\Wxnotifyv3;
use Think\Log;
use Org\Util\AesUtil;
class AysController extends CommonController{
   public function __construct()
   {
       parent::__construct();
   }

    /**
     * 微信异步通知接收
     */
   public function notify_url()
   {
       $notifiedData = file_get_contents('php://input');
       Log::write('微信支付异步通知input:'.print_r($notifiedData,true));
       $data_j = json_decode($notifiedData,true);

       $return = $this->wx_pay_notify_decrypt($data_j);
       $data_s = json_decode($return,true);

       Log::write('wx_pay_notify_decrypt_array'.print_r($data_s,true));
       if(empty($data_s['out_trade_no'])){
           exit;
       }else{
           if($data_s['trade_state']=='SUCCESS'){
               //支付成功
               //@todo 此处做自己的逻辑处理
               //返回给微信的成功通知  不返回微信会一直调用这个接口
               $return["code"]="SUCCESS";
               $return["message"]="成功";
               $ext = json_encode($return);
               echo $ext;
           }
       }
   }

    /**
     * 微信退款异步通知接收
     */
    public function refunds_notify_url()
    {
        $notifiedData = file_get_contents('php://input');
        //Log::write('微信退款异步通知input:'.print_r($notifiedData,true));
        $data_j = json_decode($notifiedData,true);

        $return = $this->wx_pay_notify_decrypt($data_j);
        $data_s = json_decode($return,true);

        Log::write('wx_pay_notify_decrypt_array'.print_r($data_s,true));
        if(empty($data_s['out_refund_no'])){
            exit;
        }else{
            if($data_s['refund_status']=='SUCCESS'){
                //退款成功
                //@todo 此处做自己的逻辑处理
                //返回给微信的成功通知  不返回微信会一直调用这个接口
                $return["code"]="SUCCESS";
                $return["message"]="成功";
                $ext = json_encode($return);
                echo $ext;
            }
        }
    }

    /**
     * 处理小程序微信支付异步通知返回来的加密数据
     * @param $notifiedData 微信小程序直接返回的数据
     * @return bool|string
     */
    private function wx_pay_notify_decrypt($notifiedData){
        $mi = C('APIV3KEY');
        $aes = new AesUtil($mi);
        $return = $aes->decryptToString($notifiedData['resource']['associated_data'],$notifiedData['resource']['nonce'],
            $notifiedData['resource']['ciphertext']);
        return $return;
    }

}
AesUtil 处理加密数据
<?php
namespace Org\Util;
use http\Exception\InvalidArgumentException;

class AesUtil
{
    /**
     * AES key
     *
     * @var string
     */
    private $aesKey;

    const KEY_LENGTH_BYTE = 32;
    const AUTH_TAG_LENGTH_BYTE = 16;

    /**
     * Constructor
     */
    public function __construct($aesKey)
    {
        if (strlen($aesKey) != self::KEY_LENGTH_BYTE) {
            throw new InvalidArgumentException('无效的ApiV3Key,长度应为32个字节');
        }
        $this->aesKey = $aesKey;
    }

    /**
     * Decrypt AEAD_AES_256_GCM ciphertext
     *
     * @param string    $associatedData     AES GCM additional authentication data
     * @param string    $nonceStr           AES GCM nonce
     * @param string    $ciphertext         AES GCM cipher text
     *
     * @return string|bool      Decrypted string on success or FALSE on failure
     */
    public function decryptToString($associatedData, $nonceStr, $ciphertext)
    {
        $ciphertext = \base64_decode($ciphertext);
        if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) {
            return false;
        }

        // ext-sodium (default installed on >= PHP 7.2)
        if (function_exists('\sodium_crypto_aead_aes256gcm_is_available') &&
            \sodium_crypto_aead_aes256gcm_is_available()) {
            return \sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
        }

        // ext-libsodium (need install libsodium-php 1.x via pecl)
        if (function_exists('\Sodium\crypto_aead_aes256gcm_is_available') &&
            \Sodium\crypto_aead_aes256gcm_is_available()) {
            return \Sodium\crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $this->aesKey);
        }

        // openssl (PHP >= 7.1 support AEAD)
        if (PHP_VERSION_ID >= 70100 && in_array('aes-256-gcm', \openssl_get_cipher_methods())) {
            $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE);
            $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE);

            return \openssl_decrypt($ctext, 'aes-256-gcm', $this->aesKey, \OPENSSL_RAW_DATA, $nonceStr,
                $authTag, $associatedData);
        }

        throw new \RuntimeException('AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php');
    }
}
?>

小程序退款提交V3

写在公共方法里的退款方法 function.php
/**
 * 订单退款-小程序退款
 * 小程序退款
 */
if(!function_exists('wxPayRefundAmount')) {
    function wxPayRefundAmount($orderid,$reason)
    {
        $log['code'] = 0;

        $info = M('order')->where(['order_id'=>$orderid])
            ->field('order_id,order_sn,amount_w')->find();

        $transaction_id = M('wxpay_log')->where(['order_id'=>$orderid])->getField('transaction_id');
        if(!empty($transaction_id)){
            $orderSn   = 'TK'.ltrim($info['order_sn'],'YY').mt_rand(1000,9999);
            $data['wx_refund_sn'] = $orderSn;
            $data['order_sn'] = $info['order_sn'];
            $data['order_id'] = $info['order_id'];
            $data['reason'] = $reason;
            $data['refund'] = $info['amount_w'];
            $data['total'] = $info['amount_w'];
            $data['transaction_id'] = $transaction_id;
            $data['add_time'] = date('Y-m-d H:i:s',time());
            $data['refund_status'] = 0;
            $res = M('wxrefund')->add($data);
            if($res){
                $return = wxrefunds($data);
                $cort = json_decode($return,true);
                if(!empty($cort['code'])){
                    $log['msg'] = '小程序退款提交微信失败!'.$cort['message'];
                }else{
                    //\Think\Log::write('微信小程序退款已成功提交!');
                    $log['code'] = 1;
                    $log['msg'] = '微信小程序退款已成功提交!';
                }
            }else{
                $log['msg'] = '微信退款单生成超时 稍后再试!';
            }

        }else{
            $log['msg'] = '未找到微信小程序支付信息!';
        }
        return $log;
    }
}



/**
 * 公共方法
 * 小程序支付退款
 * 申请退款API
 */
function wxrefunds($data){
    $url = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
    $url_parts = parse_url($url);
    $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
    $timeStamp = time();
    $noncestr = createNoncestr();

    $params['transaction_id'] = $data['transaction_id'];
    $params['out_refund_no'] = $data['wx_refund_sn'];
    $params['reason'] = $data['reason'];
    $params['notify_url'] = APP_URL.'/wap/ays/refunds_notify_url';
    $params['amount']['refund'] = intval($data['refund']);//退款金额
    $params['amount']['total'] = intval($data['total']);//订单总额
    $params['amount']['currency'] = 'CNY';
    \Think\Log::write(print_r($params,true));
    $json = json_encode($params);

    $nn = new Wxpayv3();
    //Wxpayv3 CLass 在链接https://blog.csdn.net/qq_32550561/article/details/115301917 里
    
    $key = $nn->getSign_v3($json, $canonical_url, $noncestr, $timeStamp);//签名
    $mchid = WX_MCHID;//商户ID
    $serial_no = WX_CA_NUM;
    $token = sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',
        $mchid, $noncestr, $timeStamp, $serial_no, $key);
    $header = array(
        'Content-Type:' . 'application/json; charset=UTF-8',
        'Accept:application/json',
        'User-Agent:*/*',
        'Authorization: WECHATPAY2-SHA256-RSA2048 '.$token
    );
    $result = $nn->curl_post_https($url,$json,$header);
    \Think\Log::write('wxrefunds '.$result);
    return $result;
}

/**
 * v3统一下单调用
 * @param int $length
 * @return string
 */
if(!function_exists('createNoncestr')) {
    function createNoncestr($length = 32)
    {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
}

问题解决

未收到支付结果通知回调信息,请按照以下几点进行排查

  • 请确认apiv3密钥是否有设置
  • 如果已经设置了apiv3密钥,请确认是否有相关的白名单IP限制
  • 如果上述2条都没有问题,请确认回调通知地址是否可以正常访问,格式是否按照文档的要求进行填写
  • 开发文档地址:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml
  • V3接口签名文档:https://pay.weixin.qq.com/wiki/doc/apiv3_partner/wechatpay/wechatpay4_0.shtml

使用到的文件

_Application\Common\Common\function.php
_Application_Core\Library\Org\Util\Wxpayv3.class.php
_Application_Core\Library\Org\Util\AesUtil.class.php
_Application\Wap\Controller\AysController.class.php
如有缺少请留言

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值