PHP微信支付开发(2)-退款

一、概述

本系列博客将讨论基于微信支付的项目开发中,涉及到的下单与支付、退款、以及订单查询的后端代码实现。在本系列博客中,将以代码片段作为示例,来讨论ThinkPHP 后端接口实现的过程。

在本系列的接口示例中,返回的状态码标识如下:

0: 业务成功
-1: 业务失败

开发环境如果:

  • ThinkPHP 6 或者 ThinkPHP 5 / 5.1
  • PHP 7 运行环境

本文是第二篇,我们讨论退款。

二、退款申请

订单支付成功之后即可退款,退款的金额可以小于或者等于订单的下单金额。请求参数相对下单接口略有变化,如下代码:

$order = Order::where('id',request()->params('id'))->find();
$order['out_refund_no'] = date('YmdHis').mt_rand(1000, 9999);
$params = [
    'appid' => config('wx.app_id'),
    'mch_id' => config('wx.mch_id'),
    'nonce_str' => md5(time()),
    'sign_type' => 'MD5',
    'transaction_id' => $order['transaction_id'],
    'out_trade_no' => $order['out_trade_no'],
    'out_refund_no' => $order['out_refund_no'],
    'total_fee' => $order['fee'] * 100,
    'refund_fee' => $order['fee'] * 100,
    'refund_desc' => $params['refund_desc'],
    'notify_url' => 'https://test.com/orders/callback_refund',//通知地址
];

构造xml

//创建xml
$xml = '<?xml version="1.0" encoding="utf-8"?>';
$xml .= '<xml>';
//遍历参数
$stringA = '';
//根据键名对参数进行字典排序
ksort($params);
foreach ($params as $key => $value) {
    $stringA .= $key . '=' . $value . '&';
    $xml .= '<' . $key . '>' . $value . '</' . $key . '>';
}
$signTmp = $stringA . 'key=' . config('wx.mch_key');//与商户API秘钥进行拼接
$sign = strtoupper(md5($signTmp));//签名后的32位字符

//将签名添加到请求参数中
$xml .= '<sign>' . $sign . '</sign>';
$xml .= '</xml>';

退款申请需要安全证书(在微信商户号里申请),我们重新定义在common.php一个用于请求的方法

function order_refund_request($url, $data = null)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    if (!empty($data)) {
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    //证书设置
    curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
    curl_setopt($curl, CURLOPT_SSLCERT, dirname(__FILE__) . '/cert/apiclient_cert.pem');//客户端cert路径
    curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
    curl_setopt($curl, CURLOPT_SSLKEY, dirname(__FILE__) . '/cert/apiclient_key.pem');//客户端key路径

    $output = curl_exec($curl);
    curl_close($curl);
    return $output;
}

这里要注意证书的路径,一定要匹配。接着发送退款请求

$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$res_xml = order_refund_request($url, $xml);
trace('微信中台申请退款,返回信息');
trace($res_xml);
$simpleXMLElement = simplexml_load_string($res_xml, 'SimpleXMLElement', LIBXML_NOCDATA);
//将SimpleXMLElement转为数组
$jsonStr = json_encode($simpleXMLElement);
$jsonArray = json_decode($jsonStr, true);
if (isset($jsonArray['return_code']) && $jsonArray['return_code'] == 'SUCCESS') {
    // 退款申请成功,更新订单状态
    $order['status'] = 2;
    return json(['code'=>0,'msg'=>'成功']);
} else {
    //响应失败
    return json(['code'=>-1,'msg'=>'响应失败']);
}

三、退款回调

退款回调返回的数据是加密的,回调地址是退款申请中的通知地址。我们需要先解密返回数据,再根据返回数据去更新订单状态。首先在当前类里定义解密方法

private function refundDecrypt($str, $key)
{
    $key = md5($key);
    $str = base64_decode($str);
    return openssl_decrypt($str, 'aes-256-ecb', $key, OPENSSL_RAW_DATA);
}

接下来,获取参数并解密

$xml = file_get_contents('php://input');
if (!$xml) {
    exit(0);
}
$simpleXMLElement = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
//将SimpleXMLElement转为数组
$jsonStr = json_encode($simpleXMLElement);
$jsonArray = json_decode($jsonStr, true);

// 中台返回数据解密
if (!isset($jsonArray['req_info'])) {
    exit(0);
}
$decryptStr = $this->refundDecrypt($jsonArray['req_info'], 
//将xml解析为array
$simpleXMLElement = simplexml_load_string($decryptStr, 'SimpleXMLElement', LIBXML_NOCDATA);
//将SimpleXMLElement对象转为数组
$jsonStr = json_encode($simpleXMLElement);
// 解析字段
$jsonResArr = json_decode($jsonStr, true);
// 验证参数
if (!(isset($jsonResArr['out_refund_no']) && isset($jsonResArr['refund_status']) && (strval($jsonResArr['refund_status']) === 'SUCCESS'))) {
    exit(0);//参数错误,终止程序
}
// 通过退款订单号查询订单
$order = Order::where('out_refund_no',$jsonResArr['out_refund_no'])->find();
if (!$order) {
    exit(0);//查询不到相应订单,终止程序
}
// 更新订单状态
if ($order['status'] !== 3) {
    // 更新订单状态
    trace('微信退款回调,正在更新订单状态');
    $order['status'] = 3;
    $order['transaction_id'] = $jsonResArr['transaction_id'];
    $order['refund_fee'] = round($jsonResArr['refund_fee'] / 100, 2);
    $order['refund_time'] = time();
    $saveOrder = $order->save();
}
// 给微信返回数据
$xml = '<xml>';
$xml .= '<return_code>' . '<![CDATA[SUCCESS]]>' . '</return_code>';
$xml .= '<return_msg>' . '<![CDATA[OK]]>' . '</return_msg>';
$xml .= '</xml>';
return response($xml, 200, [], 'xml');
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: Uni-app是一种跨平台的开发框架,可以方便地开发出适用于多个终端的应用程序,包括Web、iOS、Android等。在开发过程中,我们可以使用uni-app提供的API实现多种功能,比如调用微信支付。 首先,我们需要在应用程序内引入微信支付所需的SDK,在Uni-app中可以使用插件机制,自己开发一个插件或者使用已有的插件,如uni-wxpay等。然后,在APP内调用微信支付的流程如下: 1.在创建支付订单时,需要将订单信息传递给服务端,由服务端生成订单号、调用微信支付API生成预支付订单,并返回给APP。 2.APP拿到预支付订单后,调用微信SDK内置的API进行支付,主要包括支付参数的配置和支付的发起。 3.支付完成后,微信会回调我们在服务端注册的回调地址,服务端通过请求微信的API对支付结果进行核对,确认支付是否成功,并作出相应的处理。 需要注意的是,在调用微信支付API时需要在微信开放平台申请开发者账号,并完成相应的配置,包括设置支付回调地址、支付授权目录等等。 总之,通过调用微信支付API,我们可以为APP添加支付功能,实现线上商品购买、捐赠赞赏等功能。而在Uni-app中,使用插件机制可以更加方便快捷地完成这个流程。 ### 回答2: uni-app 是一个可以跨平台开发的框架,它支持开发微信小程序、支付宝小程序、H5 等多个平台。在 uni-app 中内调用微信支付可以实现用户在应用内进行支付,下面我将具体介绍 uni-app 中如何进行内调用微信支付。 1. 首先需要在应用中安装微信支付插件,打开 HBuilderX,选择菜单栏中的“插件市场”,搜索“微信支付”,选择安装。 2. 在应用中使用微信支付的页面中引入微信支付插件: ```javascript import $payment from "@/uni_modules/yk-payment/js_sdk/uni-payment.js"; // 引入插件 ``` 3. 在需要支付的位置,调用微信支付方法: ```javascript uni.showLoading({ title: '加载中' }); $payment.weixinPay({ timeStamp: '1603388794', nonceStr: '5pnskrq5060pt2lljndzpta9hzqmxrsq', package: 'prepay_id=wx30163954528026d7bf482abf2becd37124', signType: 'MD5', paySign: '3ACA84580DD8C32D8478B4BBF3688A1D', success: function (res) { console.log('success:' + JSON.stringify(res)); }, fail: function (err) { console.log('fail:' + JSON.stringify(err)); }, complete: function (res) { uni.hideLoading(); } }); ``` 其中,微信支付需要提供以下参数: - timeStamp:时间戳,单位为秒 - nonceStr:随机字符串,不长于 32 位 - package:统一下单接口返回的 prepay_id,参考[微信支付开发文档](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1)中获取订单号 - signType:签名算法,目前支持 MD5 和 HMAC-SHA256 - paySign:签名,具体签名方式详见[微信支付开发文档](https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1) 微信支付成功后会回调 success 回调函数,失败则回调 fail 回调函数。 4. 在微信支付的后端接口中,需要根据微信支付返回的结果进行签名校验,确保订单的真实性。 综上所述,使用 uni-app 内调用微信支付步骤相对简单,只需安装微信支付插件,调用支付方法即可,但支付过程中需要注意时间戳、随机字符串、签名等参数的正确性,同时在后端接口中校验微信支付的签名以确保支付的真实性。 ### 回答3: Uni-app是一个跨平台开发框架,它可以让开发者一次编代码,同时在多个平台上运行。微信支付是一个广为人知的移动支付平台,它可以提供便捷的支付服务。在实践中,我们可以使用Uni-app中的支付插件来在应用程序中调用微信支付。下面是如何实现Uni-app应用程序内调用微信支付: 1. 首先,安装支付插件在Uni-app开发环境中,可以通过npm安装。 2. 在支付插件内部,我们需要引用微信支付的API,以便在我们的应用程序中调用这些API来实现支付。这些API包括支付API、查询订单API、退款API等等。 3. 接下来,我们需要在我们的代码中调用支付API,这个API用于请求加载微信支付。当用户点击订单支付按钮时,我们可以在后台发送一个请求,请求加载微信支付页面和所需的支付参数。 4. 在向微信支付发送请求后,我们需要接收来自微信支付的响应,然后将结果传递给我们的应用程序。通常,微信支付会将支付结果返回给我们的后台服务器,然后我们可以将结果传递给我们的应用程序。我们可以使用Uni-app的API来轮询服务器以获取结果。 5. 最后,我们需要在我们的应用程序中向用户显示支付结果。如果支付成功,我们可以向用户显示订单确认信息。如果支付失败,我们可以向用户显示错误信息。 总之,Uni-app应用程序的开发者可以使用插件实现在应用程序中调用微信支付开发者需要在插件内部引用微信支付API,然后在代码中调用它们来实现支付。最后,我们需要接收来自微信支付的响应,并在我们的应用程序中向用户显示支付结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极客开发者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值