准备工作
申请沙箱环境账号,链接登录 - 支付宝,申请好就是这个样子。
配置好授权回调地址
申请好会有商家信息和买家信息,后面测试需要用到,金额是随便输入的。
下载官方sdk
我下载的是PHP版本;
thinkphp5 放在extend文件下
如图,我放在alipay文件下。就要这些文件就行了。
代码
定义个类Aliay.php,以下方法都在这个类中
namespace app\index\controller;
use think\Config;
use think\Log;
use app\common\model\Order;
class News extends BaseIndex
{
public function a(){
...
}
public function ab){
...
}
}
支付宝配置
需要这两个公钥和私钥,要选非java语言
'alipay' => [
//应用ID,您的APPID。
'app_id' => "9021000128631276",
//商户私钥
'merchant_private_key' => "去自己的沙箱环境复制",
//异步通知地址
'notify_url' => "https://suanfa.abc.top/notify_url",
//同步跳转
'return_url' => "https://suanfa.abc.top/return_url",
//编码格式
'charset' => "UTF-8",
//签名方式
'sign_type'=>"RSA2",
//支付宝网关
'gatewayUrl' => "https://openapi-sandbox.dl.alipaydev.com/gateway.do",
//支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
'alipay_public_key' => '去自己的沙箱环境复制',
//日志路径
'log_path' => "",
]
配置的异步地址和同步地址得能正常访问200。
异步通知:支付成功后会访问这个方法,再通过返回的状态码去更改订单状态。
同步跳转:支付成功后会跳转到这个地址,并且会把订单的信息以get的方式跟在连接上,例如:https://suanfa.abc.top/return_url?charset=UTF-8&out_trade_no=202108170100021&method=alipay.trade.page.pay.return&total_amount=0.01&sign=TRdEaGa9.........
订单生成
订单的生成、付款(手机,PC,APP)、查询订单状态、退款(我只写了PC和手机站的相关,因为没有APP),官方的文档链接:小程序文档 - 支付宝文档中心
详细文档和支付方式都在里面,很详细。
先创建订单方法,代码如下,需要注意的是有PC端和手机端。PC端的话直接跳转到一个支付链接,输入密码进行支付。手机端的话会自动跳转到支付宝APP进行支付。
注意:沙箱环境的话在手机上支付,会提示“支付超时的信息”。是因为得在手机上下载一个沙箱版的APP才能正常支付。目前仅支持安卓手机下载这个软件。
创建订单方法
public function pay(){
import('alipay.aop.AopClient', EXTEND_PATH);
//pc
import('alipay.aop.request.AlipayTradePagePayRequest', EXTEND_PATH);
//手机
import('alipay.aop.request.AlipayTradeWapPayRequest', EXTEND_PATH);
$alipayConfig = Config::get('alipay');
$aop = new \AopClient ();
$aop->gatewayUrl = $alipayConfig['gatewayUrl'];
$aop->appId = $alipayConfig['app_id'];
$aop->rsaPrivateKey = $alipayConfig['merchant_private_key'];
$aop->alipayrsaPublicKey=$alipayConfig['alipay_public_key'];
$aop->apiVersion = '1.0';
$aop->signType =$alipayConfig['sign_type'];
$aop->postCharset=$alipayConfig['charset'];;
$aop->format='json';
$request = request()->isMobile() ? new \AlipayTradeWapPayRequest() : new \AlipayTradePagePayRequest();
//异步接收地址,仅支持http/https,公网可访问
$request->setNotifyUrl($alipayConfig['notify_url']);
//同步跳转地址,仅支持http/https
$request->setReturnUrl($alipayConfig['return_url']);
/******必传参数******/
$object = new \stdClass();
//商户订单号,商家自定义,保持唯一性
$object->out_trade_no = '20210817010100021';
//支付金额,最小值0.01元
$object->total_amount = 0.01;
//订单标题,不可使用特殊符号
$object->subject = '测试商品';
//区分支付场景电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY手机端为QUICK_WAP_WAY
$object->product_code = request()->isMobile() ? 'QUICK_WAP_WAY' : 'FAST_INSTANT_TRADE_PAY';
/******可选参数******/
$object->time_expire = date('Y-m-d H:i:s',time()+120);
$json = json_encode($object);
$request->setBizContent($json);
return $aop->pageExecute($request);
// $responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_request";
// $resultCode = $result->$responseNode->code;
// if(!empty($resultCode)&&$resultCode == 10000){
// echo "成功";
// } else {
// echo "失败";
// }
}
支付页面,PC端,输入沙箱买家信息的用户名和密码还有支付密码
支付页面,手机端,
如果跳转到支付宝APP支付的话,得跳转到沙箱版的APP,跳转正式的支付宝APP会提示“超时”之类的。
也可以“继续浏览器付款”,那就和PC端一样了。输入沙箱的账密就可以支付。
异步通知
异步通知看不到结果,可以通过日志打印出来看结果
更新订单状态的时候最好把支付宝的交易单号更新进去,退款要用到这个字段。
//异步回调地址,用作逻辑处理,更改订单状态。
public function notify_url(){
import('alipay.pagepay.service.AlipayTradeService', EXTEND_PATH);
$arr=$_POST;
$alipaySevice = new \AlipayTradeService(Config::get('alipay'));
$alipaySevice->writeLog(var_export($_POST,true));
$result = $alipaySevice->check($arr);
if($result) {//验证成功
/
//请在这里加上商户的业务逻辑程序代
//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
//获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
//商户订单号
$out_trade_no = $_POST['out_trade_no'];
//支付宝交易号
$trade_no = $_POST['trade_no'];
//交易状态
$trade_status = $_POST['trade_status'];
if($_POST['trade_status'] == 'TRADE_FINISHED') {
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
//sjs--结束不做任何处理
}
else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
//sja支付成功后逻辑处理
if($order_info = Order::where(['out_trade_no'=>($_POST['out_trade_no'])])->find()){
if($order_info['state'] == 0){
$update = [
'state'=>1,
'trade_no'=>$trade_no,
];
Order::where(['out_trade_no'=>($_POST['out_trade_no'])])->update($update);
}
}
}
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
echo "success"; //请不要修改或删除
}else {
//验证失败
echo "fail";
}
}
同步跳转
支付成功会跳转到这个链接,同时会带上订单信息,get可以获取到。
//同步回调,支付成功跳转的地址,get方式获取订单信息
public function return_url(){
import('alipay.pagepay.service.AlipayTradeService', EXTEND_PATH);
$arr=$_GET;
$alipaySevice = new \AlipayTradeService(Config::get('alipay'));
$result = $alipaySevice->check($arr);
var_dump($result);
if($result) {//验证成功
/
//请在这里加上商户的业务逻辑程序代码
//——请根据您的业务逻辑来编写程序(以下代码仅作参考)——
//获取支付宝的通知返回参数,可参考技术文档中页面跳转同步通知参数列表
//商户订单号
$out_trade_no = htmlspecialchars($_GET['out_trade_no']);
//支付宝交易号
$trade_no = htmlspecialchars($_GET['trade_no']);
echo "验证成功<br />支付宝交易号:".$trade_no;
//——请根据您的业务逻辑来编写程序(以上代码仅作参考)——
//
echo '<pre>';
print_r($_GET);
echo '</pre>';
exit();
/
}
else {
//验证失败
echo "验证失败";
}
}
成功后页面打印信息
订单查询
以上图的数据为例,查询一个订单的支付状态,传入的是支付宝的交易单号。
//查询支付宝订单结果
public function checkOrder(){
$id = input('post.id/d') ? : 1;//查询订单
import('alipay.aop.AopClient', EXTEND_PATH);
import('alipay.aop.request.AlipayTradeQueryRequest', EXTEND_PATH);
$alipayConfig = Config::get('alipay');
$aop = new \AopClient ();
$aop->gatewayUrl = $alipayConfig['gatewayUrl'];
$aop->appId = $alipayConfig['app_id'];
$aop->rsaPrivateKey = $alipayConfig['merchant_private_key'];
$aop->alipayrsaPublicKey=$alipayConfig['alipay_public_key'];
$aop->apiVersion = '1.0';
$aop->signType =$alipayConfig['sign_type'];
$aop->postCharset=$alipayConfig['charset'];;
$aop->format='json';
$request = new \AlipayTradeQueryRequest();
$o_info = Order::get($id);
$setBizContent = [
'out_trade_no'=>$o_info['out_trade_no'],//可不传
'trade_no'=>$o_info['trade_no'],
];
$request->setBizContent(json_encode($setBizContent));
$result = $aop->execute($request);
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $result->$responseNode->code;
if(!empty($resultCode)&&$resultCode == 10000){
echo "成功";
//打印订单信息
echo '<pre>';
print_r($result);
echo '</pre>';
exit();
} else {
echo "失败";
}
}
结果打印
注意:查询订单的时候会报错
Class 'SignData' not found
此时修改 AopClient.php 顶部加入一行代码require_once 'SignData.php';
订单退款
//支付宝退款
public function tuikuan(){
$id = input('post.id/d') ? : 1;//查询订单
import('alipay.aop.AopClient', EXTEND_PATH);
import('alipay.aop.request.AlipayTradeRefundRequest', EXTEND_PATH);
$alipayConfig = Config::get('alipay');
$aop = new \AopClient ();
$aop->gatewayUrl = $alipayConfig['gatewayUrl'];
$aop->appId = $alipayConfig['app_id'];
$aop->rsaPrivateKey = $alipayConfig['merchant_private_key'];
$aop->alipayrsaPublicKey=$alipayConfig['alipay_public_key'];
$aop->apiVersion = '1.0';
$aop->signType =$alipayConfig['sign_type'];
$aop->postCharset=$alipayConfig['charset'];;
$aop->format='json';
$o_info = Order::get($id);
$object = new \stdClass();
$object->trade_no = $o_info['trade_no'];//订单号(支付宝订单号)
$object->refund_amount = $o_info['order_money'];//订单金额
// $object->out_request_no = 'HZ01RF001';
返回参数选项,按需传入
//$queryOptions =[
// 'refund_detail_item_list'
//];
//$object->query_options = $queryOptions;
$json = json_encode($object);
$request = new \AlipayTradeRefundRequest();
$request->setBizContent($json);
$result = $aop->execute ( $request);
$responseNode = str_replace(".", "_", $request->getApiMethodName()) . "_response";
$resultCode = $result->$responseNode->code;
if(!empty($resultCode)&&$resultCode == 10000){
echo "成功";
} else {
echo "失败";
}
}
需要传入支付宝交易号,执行退款操作前需要先查询订单状态是否能退款,订单查询后的“trade_status”为TRADE_SUCCESS才能退款。
超过三个月订单会变成TRADE_FINISHED就不能进行退款操作了,支付宝官方说的是三个月后就自动变成TRADE_FINISHED了。也可以执行修改订单状态接口进行修改订单的trade_status,接口文档都有。
退款成功后再次查询该订单时,trade_status会变成TRADE_CLOSED。
我用的是沙箱的账号测试的。正式上线的话把配置文件的信息改了就行了。
希望对大家有帮助,有错误的请评论指正。