731 lines
28 KiB
PHP
731 lines
28 KiB
PHP
|
|
<?php
|
||
|
|
namespace app\api\controller;
|
||
|
|
|
||
|
|
use support\Request;
|
||
|
|
use support\Response;
|
||
|
|
use Yansongda\Pay\Pay;
|
||
|
|
use Yansongda\Pay\Log;
|
||
|
|
use think\facade\Db;
|
||
|
|
use support\Log as WebmanLog;
|
||
|
|
use hg\apidoc\annotation as Apidoc;
|
||
|
|
use app\enum\Payment\Method;
|
||
|
|
use app\enum\Payment\Status;
|
||
|
|
use app\enum\Payment\Type;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 支付控制器
|
||
|
|
* @Apidoc\Title("支付管理")
|
||
|
|
* @Apidoc\Group("payment")
|
||
|
|
*/
|
||
|
|
class PaymentController extends BaseController
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* 支付宝支付下单
|
||
|
|
* @Apidoc\Title("支付宝支付下单")
|
||
|
|
* @Apidoc\Url("/api/payment/alipay/order")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("amount", "float", "支付金额", true, "0.01")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("subject", "string", "订单标题", true, "测试商品")
|
||
|
|
* @Apidoc\Param("body", "string", "订单描述", false, "测试商品描述")
|
||
|
|
* @Apidoc\Param("type", "string", "订单类型: recharge(充值), goods(商品), service(服务), other(其他)", false, "goods")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "pay_url|string|支付链接,order_no|string|订单号")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function alipay_order(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
// 验证参数
|
||
|
|
if (!isset($params['amount']) || !isset($params['order_no']) || !isset($params['subject'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
$amount = $params['amount'];
|
||
|
|
$orderNo = $params['order_no'];
|
||
|
|
$subject = $params['subject'];
|
||
|
|
$body = $params['body'] ?? $subject;
|
||
|
|
$type = $params['type'] ?? 'goods';
|
||
|
|
|
||
|
|
// 获取支付宝配置
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
|
||
|
|
// 构建支付参数
|
||
|
|
$payOrder = [
|
||
|
|
'out_trade_no' => $orderNo,
|
||
|
|
'total_amount' => $amount,
|
||
|
|
'subject' => $subject,
|
||
|
|
'body' => $body,
|
||
|
|
];
|
||
|
|
|
||
|
|
// 发起支付
|
||
|
|
$result = Pay::alipay($config)->web($payOrder);
|
||
|
|
|
||
|
|
// 记录支付订单
|
||
|
|
$this->record_payment_order($orderNo, 'alipay', $amount, $subject, $type);
|
||
|
|
|
||
|
|
return $this->success('ok',[
|
||
|
|
'pay_url' => $result->getTargetUrl(),
|
||
|
|
'order_no' => $orderNo
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('支付宝支付下单失败: ' . $e->getMessage());
|
||
|
|
return $this->error('支付下单失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 支付宝同步回调
|
||
|
|
* @Apidoc\Title("支付宝同步回调")
|
||
|
|
* @Apidoc\Url("/api/payment/alipay/return")
|
||
|
|
* @Apidoc\Method("GET")
|
||
|
|
* @Apidoc\Param("out_trade_no", "string", "订单号", true)
|
||
|
|
* @Apidoc\Param("trade_no", "string", "支付宝交易号", true)
|
||
|
|
* @Apidoc\Param("trade_status", "string", "交易状态", true)
|
||
|
|
* @Apidoc\Return("redirect", "string", "跳转到成功或失败页面")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function alipay_return(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
$data = $request->all();
|
||
|
|
|
||
|
|
// 验证回调数据
|
||
|
|
$result = Pay::alipay($config)->verify($data);
|
||
|
|
|
||
|
|
// 处理支付结果
|
||
|
|
$orderNo = $result->out_trade_no;
|
||
|
|
$tradeNo = $result->trade_no;
|
||
|
|
$status = $result->trade_status;
|
||
|
|
|
||
|
|
// 更新订单状态
|
||
|
|
$this->update_payment_order($orderNo, $tradeNo, $status);
|
||
|
|
|
||
|
|
// 跳转到成功页面
|
||
|
|
return redirect('/api/payment/success?order_no=' . $orderNo);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('支付宝同步回调失败: ' . $e->getMessage());
|
||
|
|
return redirect('/api/payment/fail?error=' . urlencode($e->getMessage()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 支付宝异步回调
|
||
|
|
* @Apidoc\Title("支付宝异步回调")
|
||
|
|
* @Apidoc\Url("/api/payment/alipay/notify")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("out_trade_no", "string", "订单号", true)
|
||
|
|
* @Apidoc\Param("trade_no", "string", "支付宝交易号", true)
|
||
|
|
* @Apidoc\Param("trade_status", "string", "交易状态", true)
|
||
|
|
* @Apidoc\Return("string", "string", "返回success或fail")
|
||
|
|
* @param Request $request
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function alipay_notify(Request $request): string
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
$data = $request->all();
|
||
|
|
|
||
|
|
// 验证回调数据
|
||
|
|
$result = Pay::alipay($config)->verify($data);
|
||
|
|
|
||
|
|
// 处理支付结果
|
||
|
|
$orderNo = $result->out_trade_no;
|
||
|
|
$tradeNo = $result->trade_no;
|
||
|
|
$status = $result->trade_status;
|
||
|
|
|
||
|
|
// 更新订单状态
|
||
|
|
$this->update_payment_order($orderNo, $tradeNo, $status);
|
||
|
|
|
||
|
|
// 返回成功
|
||
|
|
return 'success';
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('支付宝异步回调失败: ' . $e->getMessage());
|
||
|
|
return 'fail';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 微信支付下单
|
||
|
|
* @Apidoc\Title("微信支付下单")
|
||
|
|
* @Apidoc\Url("/api/payment/wechat/order")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("amount", "float", "支付金额", true, "0.01")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("body", "string", "订单描述", true, "测试商品描述")
|
||
|
|
* @Apidoc\Param("trade_type", "string", "交易类型: JSAPI, NATIVE, APP, MWEB", false, "JSAPI")
|
||
|
|
* @Apidoc\Param("openid", "string", "微信用户openid(JSAPI模式需要)", false, "o123456")
|
||
|
|
* @Apidoc\Param("type", "string", "订单类型: recharge(充值), goods(商品), service(服务), other(其他)", false, "goods")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "pay_data|object|支付数据,order_no|string|订单号")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function wechat_order(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
// 验证参数
|
||
|
|
if (!isset($params['amount']) || !isset($params['order_no']) || !isset($params['body'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
$amount = $params['amount'];
|
||
|
|
$orderNo = $params['order_no'];
|
||
|
|
$body = $params['body'];
|
||
|
|
$tradeType = $params['trade_type'] ?? 'JSAPI';
|
||
|
|
$openid = $params['openid'] ?? '';
|
||
|
|
$type = $params['type'] ?? 'goods';
|
||
|
|
|
||
|
|
// 获取微信支付配置
|
||
|
|
$config = config('payment.wechat.default');
|
||
|
|
|
||
|
|
// 构建支付参数
|
||
|
|
$payOrder = [
|
||
|
|
'out_trade_no' => $orderNo,
|
||
|
|
'total_fee' => $amount * 100, // 微信支付金额单位为分
|
||
|
|
'body' => $body,
|
||
|
|
'trade_type' => $tradeType,
|
||
|
|
];
|
||
|
|
|
||
|
|
// JSAPI支付需要openid
|
||
|
|
if ($tradeType === 'JSAPI' && $openid) {
|
||
|
|
$payOrder['openid'] = $openid;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 发起支付
|
||
|
|
$result = Pay::wechat($config)->order($payOrder);
|
||
|
|
|
||
|
|
// 记录支付订单
|
||
|
|
$this->record_payment_order($orderNo, 'wechat', $amount, $body, $type);
|
||
|
|
|
||
|
|
return $this->success('ok',[
|
||
|
|
'pay_data' => $result->toArray(),
|
||
|
|
'order_no' => $orderNo
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('微信支付下单失败: ' . $e->getMessage());
|
||
|
|
return $this->error('支付下单失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 微信支付回调
|
||
|
|
* @Apidoc\Title("微信支付回调")
|
||
|
|
* @Apidoc\Url("/api/payment/wechat/notify")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("out_trade_no", "string", "订单号", true)
|
||
|
|
* @Apidoc\Param("transaction_id", "string", "微信交易号", true)
|
||
|
|
* @Apidoc\Param("result_code", "string", "业务结果", true)
|
||
|
|
* @Apidoc\Return("xml", "string", "返回XML格式的成功或失败响应")
|
||
|
|
* @param Request $request
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
public function wechat_notify(Request $request): string
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$config = config('payment.wechat.default');
|
||
|
|
$data = $request->all();
|
||
|
|
|
||
|
|
// 验证回调数据
|
||
|
|
$result = Pay::wechat($config)->verify($data);
|
||
|
|
|
||
|
|
// 处理支付结果
|
||
|
|
$orderNo = $result->out_trade_no;
|
||
|
|
$tradeNo = $result->transaction_id;
|
||
|
|
$status = $result->result_code === 'SUCCESS' ? 'SUCCESS' : 'FAIL';
|
||
|
|
|
||
|
|
// 更新订单状态
|
||
|
|
$this->update_payment_order($orderNo, $tradeNo, $status);
|
||
|
|
|
||
|
|
// 返回成功
|
||
|
|
return Pay::wechat($config)->success();
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('微信支付回调失败: ' . $e->getMessage());
|
||
|
|
return Pay::wechat(config('payment.wechat.default'))->fail();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 记录支付订单
|
||
|
|
* @param string $orderNo
|
||
|
|
* @param string $payType
|
||
|
|
* @param float $amount
|
||
|
|
* @param string $subject
|
||
|
|
* @param string $type
|
||
|
|
*/
|
||
|
|
private function record_payment_order(string $orderNo, string $payType, float $amount, string $subject, string $type = 'goods'): void
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
Db::name('payment_order')->insert([
|
||
|
|
'order_no' => $orderNo,
|
||
|
|
'pay_type' => $payType,
|
||
|
|
'type' => $type,
|
||
|
|
'amount' => $amount,
|
||
|
|
'subject' => $subject,
|
||
|
|
'status' => Status::CREATED->value,
|
||
|
|
'created_at' => time(),
|
||
|
|
'updated_at' => time()
|
||
|
|
]);
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('记录支付订单失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 更新支付订单状态
|
||
|
|
* @param string $orderNo
|
||
|
|
* @param string $tradeNo
|
||
|
|
* @param string $status
|
||
|
|
*/
|
||
|
|
private function update_payment_order(string $orderNo, string $tradeNo, string $status): void
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
// 映射支付状态到我们的状态枚举
|
||
|
|
$mappedStatus = $this->map_payment_status($status);
|
||
|
|
|
||
|
|
Db::name('payment_order')->where('order_no', $orderNo)->update([
|
||
|
|
'trade_no' => $tradeNo,
|
||
|
|
'status' => $mappedStatus,
|
||
|
|
'updated_at' => time()
|
||
|
|
]);
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('更新支付订单状态失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 映射支付状态到枚举
|
||
|
|
* @param string $status
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private function map_payment_status(string $status): string
|
||
|
|
{
|
||
|
|
// 支付宝状态映射
|
||
|
|
$alipayStatusMap = [
|
||
|
|
'TRADE_SUCCESS' => Status::SUCCESS->value,
|
||
|
|
'TRADE_FINISHED' => Status::COMPLETE->value,
|
||
|
|
'TRADE_CLOSED' => Status::FAIL->value,
|
||
|
|
'WAIT_BUYER_PAY' => Status::CREATED->value
|
||
|
|
];
|
||
|
|
|
||
|
|
// 微信支付状态映射
|
||
|
|
$wechatStatusMap = [
|
||
|
|
'SUCCESS' => Status::SUCCESS->value,
|
||
|
|
'FAIL' => Status::FAIL->value,
|
||
|
|
'REFUND' => Status::REFUNDED->value
|
||
|
|
];
|
||
|
|
|
||
|
|
// 先尝试支付宝映射
|
||
|
|
if (isset($alipayStatusMap[$status])) {
|
||
|
|
return $alipayStatusMap[$status];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 再尝试微信映射
|
||
|
|
if (isset($wechatStatusMap[$status])) {
|
||
|
|
return $wechatStatusMap[$status];
|
||
|
|
}
|
||
|
|
|
||
|
|
// 默认返回成功
|
||
|
|
return Status::SUCCESS->value;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 查询支付订单状态
|
||
|
|
* @Apidoc\Title("查询支付订单状态")
|
||
|
|
* @Apidoc\Url("/api/payment/order/query")
|
||
|
|
* @Apidoc\Method("GET")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("pay_type", "string", "支付类型: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "order|object|订单信息,pay_status|object|支付状态")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function query_order(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$orderNo = $request->get('order_no');
|
||
|
|
$payType = $request->get('pay_type');
|
||
|
|
|
||
|
|
if (!$orderNo || !$payType) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 查询订单
|
||
|
|
$order = Db::name('payment_order')->where('order_no', $orderNo)->find();
|
||
|
|
if (!$order) {
|
||
|
|
return $this->error('订单不存在');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 根据支付类型查询支付状态
|
||
|
|
if ($payType === \app\enum\Payment\Method::ALIPAY->value) {
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
$result = Pay::alipay($config)->find($orderNo);
|
||
|
|
} elseif ($payType === \app\enum\Payment\Method::WECHAT->value) {
|
||
|
|
$config = config('payment.wechat.default');
|
||
|
|
$result = Pay::wechat($config)->find($orderNo);
|
||
|
|
} else {
|
||
|
|
return $this->error('不支持的支付类型');
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->success('ok',[
|
||
|
|
'order' => $order,
|
||
|
|
'pay_status' => $result->toArray()
|
||
|
|
]);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('查询支付订单失败: ' . $e->getMessage());
|
||
|
|
return $this->error('查询失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 关闭支付订单
|
||
|
|
* @Apidoc\Title("关闭支付订单")
|
||
|
|
* @Apidoc\Url("/api/payment/order/close")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("pay_type", "string", "支付类型: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "msg|string|成功信息")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function close_order(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$orderNo = $request->post('order_no');
|
||
|
|
$payType = $request->post('pay_type');
|
||
|
|
|
||
|
|
if (!$orderNo || !$payType) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 关闭订单
|
||
|
|
if ($payType === 'alipay') {
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
$result = Pay::alipay($config)->close($orderNo);
|
||
|
|
} elseif ($payType === 'wechat') {
|
||
|
|
$config = config('payment.wechat.default');
|
||
|
|
$result = Pay::wechat($config)->close($orderNo);
|
||
|
|
} else {
|
||
|
|
return $this->error('不支持的支付类型');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新订单状态
|
||
|
|
Db::name('payment_order')->where('order_no', $orderNo)->update([
|
||
|
|
'status' => \app\enum\Payment\Status::COMPLETE->value,
|
||
|
|
'updated_at' => time()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->success('订单关闭成功');
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('关闭支付订单失败: ' . $e->getMessage());
|
||
|
|
return $this->error('关闭失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 退款
|
||
|
|
* @Apidoc\Title("退款")
|
||
|
|
* @Apidoc\Url("/api/payment/refund")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("pay_type", "string", "支付类型: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Param("amount", "float", "退款金额", true, "0.01")
|
||
|
|
* @Apidoc\Param("refund_no", "string", "退款单号", false, "20260409001_refund")
|
||
|
|
* @Apidoc\Param("reason", "string", "退款原因", false, "退款")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "msg|string|成功信息")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function refund(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
if (!isset($params['order_no']) || !isset($params['pay_type']) || !isset($params['amount'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
$orderNo = $params['order_no'];
|
||
|
|
$payType = $params['pay_type'];
|
||
|
|
$amount = $params['amount'];
|
||
|
|
$refundNo = $params['refund_no'] ?? $orderNo . '_' . time();
|
||
|
|
$reason = $params['reason'] ?? '退款';
|
||
|
|
|
||
|
|
// 发起退款
|
||
|
|
if ($payType === Method::ALIPAY->value) {
|
||
|
|
$config = config('payment.alipay.default');
|
||
|
|
$result = Pay::alipay($config)->refund([
|
||
|
|
'out_trade_no' => $orderNo,
|
||
|
|
'refund_amount' => $amount,
|
||
|
|
'out_request_no' => $refundNo,
|
||
|
|
'refund_reason' => $reason,
|
||
|
|
]);
|
||
|
|
} elseif ($payType === Method::WECHAT->value) {
|
||
|
|
$config = config('payment.wechat.default');
|
||
|
|
$result = Pay::wechat($config)->refund([
|
||
|
|
'out_trade_no' => $orderNo,
|
||
|
|
'out_refund_no' => $refundNo,
|
||
|
|
'total_fee' => $amount * 100,
|
||
|
|
'refund_fee' => $amount * 100,
|
||
|
|
'refund_desc' => $reason,
|
||
|
|
]);
|
||
|
|
} else {
|
||
|
|
return $this->error('不支持的支付类型');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 记录退款信息
|
||
|
|
Db::name('payment_refund')->insert([
|
||
|
|
'order_no' => $orderNo,
|
||
|
|
'refund_no' => $refundNo,
|
||
|
|
'pay_type' => $payType,
|
||
|
|
'amount' => $amount,
|
||
|
|
'reason' => $reason,
|
||
|
|
'status' => 'SUCCESS',
|
||
|
|
'created_at' => time()
|
||
|
|
]);
|
||
|
|
|
||
|
|
// 更新订单状态
|
||
|
|
Db::name('payment_order')->where('order_no', $orderNo)->update([
|
||
|
|
'status' => Status::REFUNDED->value,
|
||
|
|
'updated_at' => time()
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $this->success('退款成功');
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('退款失败: ' . $e->getMessage());
|
||
|
|
return $this->error('退款失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 统一支付接口
|
||
|
|
* @Apidoc\Title("统一支付接口")
|
||
|
|
* @Apidoc\Url("/api/payment/unified/order")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("payment", "string", "支付方式: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Param("amount", "float", "支付金额", true, "0.01")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("subject", "string", "订单标题", true, "测试商品")
|
||
|
|
* @Apidoc\Param("body", "string", "订单描述", false, "测试商品描述")
|
||
|
|
* @Apidoc\Param("type", "string", "订单类型: recharge(充值), goods(商品), service(服务), other(其他)", false, "goods")
|
||
|
|
* @Apidoc\Param("trade_type", "string", "交易类型(微信支付需要): JSAPI, NATIVE, APP, MWEB", false, "JSAPI")
|
||
|
|
* @Apidoc\Param("openid", "string", "微信用户openid(JSAPI模式需要)", false, "o123456")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "pay_url|string|支付宝支付链接,pay_data|object|微信支付数据,order_no|string|订单号")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function unified_order(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
// 验证必要参数
|
||
|
|
if (!isset($params['payment']) || !isset($params['amount']) || !isset($params['order_no']) || !isset($params['subject'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
$payment = strtolower($params['payment']);
|
||
|
|
$amount = $params['amount'];
|
||
|
|
$orderNo = $params['order_no'];
|
||
|
|
$subject = $params['subject'];
|
||
|
|
$body = $params['body'] ?? $subject;
|
||
|
|
$type = $params['type'] ?? 'goods';
|
||
|
|
|
||
|
|
// 根据payment参数选择支付方式
|
||
|
|
switch ($payment) {
|
||
|
|
case Method::ALIPAY->value:
|
||
|
|
// 调用支付宝支付
|
||
|
|
return $this->alipay_order($request);
|
||
|
|
|
||
|
|
case Method::WECHAT->value:
|
||
|
|
// 调用微信支付
|
||
|
|
return $this->wechat_order($request);
|
||
|
|
|
||
|
|
default:
|
||
|
|
return $this->error('不支持的支付方式');
|
||
|
|
}
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('统一支付接口失败: ' . $e->getMessage());
|
||
|
|
return $this->error('支付失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 统一支付回调接口
|
||
|
|
* @Apidoc\Title("统一支付回调接口")
|
||
|
|
* @Apidoc\Url("/api/payment/unified/notify")
|
||
|
|
* @Apidoc\Method("ANY")
|
||
|
|
* @Apidoc\Param("payment", "string", "支付方式: alipay, wechat", false)
|
||
|
|
* @Apidoc\Param("out_trade_no", "string", "订单号", true)
|
||
|
|
* @Apidoc\Param("trade_no|transaction_id", "string", "支付交易号", true)
|
||
|
|
* @Apidoc\Param("trade_status|result_code", "string", "交易状态", true)
|
||
|
|
* @Apidoc\Return("string", "string", "返回success/fail或XML格式响应")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function unified_notify(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$payment = $request->get('payment') ?? $request->post('payment');
|
||
|
|
|
||
|
|
if (!$payment) {
|
||
|
|
// 尝试从请求参数中自动识别
|
||
|
|
$data = $request->all();
|
||
|
|
if (isset($data['app_id']) && strpos($data['app_id'], '20') === 0) {
|
||
|
|
$payment = 'alipay';
|
||
|
|
} elseif (isset($data['mch_id'])) {
|
||
|
|
$payment = 'wechat';
|
||
|
|
} else {
|
||
|
|
return $this->error('无法识别支付方式');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$payment = strtolower($payment);
|
||
|
|
|
||
|
|
// 根据payment参数选择回调处理
|
||
|
|
switch ($payment) {
|
||
|
|
case Method::ALIPAY->value:
|
||
|
|
// 调用支付宝回调
|
||
|
|
return $this->alipay_notify($request);
|
||
|
|
|
||
|
|
case Method::WECHAT->value:
|
||
|
|
// 调用微信回调
|
||
|
|
return $this->wechat_notify($request);
|
||
|
|
|
||
|
|
default:
|
||
|
|
return $this->error('不支持的支付方式');
|
||
|
|
}
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('统一支付回调接口失败: ' . $e->getMessage());
|
||
|
|
return $this->error('回调处理失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 统一支付查询接口
|
||
|
|
* @Apidoc\Title("统一支付查询接口")
|
||
|
|
* @Apidoc\Url("/api/payment/unified/query")
|
||
|
|
* @Apidoc\Method("GET")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("payment", "string", "支付方式: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "order|object|订单信息,pay_status|object|支付状态")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function unified_query(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->all();
|
||
|
|
|
||
|
|
// 验证必要参数
|
||
|
|
if (!isset($params['order_no']) || !isset($params['payment'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置pay_type参数
|
||
|
|
$request->withAddedHeader('pay_type', $params['payment']);
|
||
|
|
|
||
|
|
// 调用查询接口
|
||
|
|
return $this->query_order($request);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('统一支付查询接口失败: ' . $e->getMessage());
|
||
|
|
return $this->error('查询失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 统一支付关闭接口
|
||
|
|
* @Apidoc\Title("统一支付关闭接口")
|
||
|
|
* @Apidoc\Url("/api/payment/unified/close")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("payment", "string", "支付方式: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "msg|string|成功信息")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function unified_close(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
// 验证必要参数
|
||
|
|
if (!isset($params['order_no']) || !isset($params['payment'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置pay_type参数
|
||
|
|
$request->withAddedHeader('pay_type', $params['payment']);
|
||
|
|
|
||
|
|
// 调用关闭接口
|
||
|
|
return $this->close_order($request);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('统一支付关闭接口失败: ' . $e->getMessage());
|
||
|
|
return $this->error('关闭失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 统一退款接口
|
||
|
|
* @Apidoc\Title("统一退款接口")
|
||
|
|
* @Apidoc\Url("/api/payment/unified/refund")
|
||
|
|
* @Apidoc\Method("POST")
|
||
|
|
* @Apidoc\Param("order_no", "string", "订单号", true, "20260409001")
|
||
|
|
* @Apidoc\Param("payment", "string", "支付方式: alipay, wechat", true, "alipay")
|
||
|
|
* @Apidoc\Param("amount", "float", "退款金额", true, "0.01")
|
||
|
|
* @Apidoc\Param("refund_no", "string", "退款单号", false, "20260409001_refund")
|
||
|
|
* @Apidoc\Param("reason", "string", "退款原因", false, "退款")
|
||
|
|
* @Apidoc\Return("success", "object", "成功响应", "msg|string|成功信息")
|
||
|
|
* @Apidoc\Return("error", "object", "失败响应", "code|int|错误码,msg|string|错误信息")
|
||
|
|
* @param Request $request
|
||
|
|
* @return Response
|
||
|
|
*/
|
||
|
|
public function unified_refund(Request $request): Response
|
||
|
|
{
|
||
|
|
try {
|
||
|
|
$params = $request->post();
|
||
|
|
|
||
|
|
// 验证必要参数
|
||
|
|
if (!isset($params['order_no']) || !isset($params['payment']) || !isset($params['amount'])) {
|
||
|
|
return $this->error('缺少必要参数');
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置pay_type参数
|
||
|
|
$params['pay_type'] = $params['payment'];
|
||
|
|
$request->withAddedHeader('pay_type', $params['payment']);
|
||
|
|
|
||
|
|
// 调用退款接口
|
||
|
|
return $this->refund($request);
|
||
|
|
|
||
|
|
} catch (\Exception $e) {
|
||
|
|
WebmanLog::error('统一退款接口失败: ' . $e->getMessage());
|
||
|
|
return $this->error('退款失败: ' . $e->getMessage());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|