新增微信支付

This commit is contained in:
2026-04-13 17:25:33 +08:00
parent dca43a2d0d
commit d060e1b797
8 changed files with 165 additions and 29 deletions
@@ -16,6 +16,10 @@ use Illuminate\Http\Request;
use Illuminate\Http\Response;
use RuntimeException;
/**
* 前台 VIP 支付控制器
* 负责接收用户选择的支付渠道,下发支付中心订单并处理回调结果。
*/
class VipPaymentController extends Controller
{
/**
@@ -41,10 +45,11 @@ class VipPaymentController extends Controller
}
$vipLevel = VipLevel::query()->findOrFail((int) $request->validated('vip_level_id'));
$provider = (string) $request->validated('provider');
try {
// 先创建本地订单,再向支付中心发起下单,确保回调时有本地单据可追踪。
$vipPaymentOrder = $this->vipPaymentService->createLocalOrder($request->user(), $vipLevel);
$vipPaymentOrder = $this->vipPaymentService->createLocalOrder($request->user(), $vipLevel, $provider);
$remoteOrder = $this->vipPaymentService->createRemoteOrder($vipPaymentOrder);
$payUrl = (string) ($remoteOrder['pay_url'] ?? '');
@@ -8,7 +8,12 @@
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
/**
* 创建 VIP 支付订单请求
* 负责校验会员购买等级与支付渠道,确保下单时明确指定支付方式。
*/
class CreateVipPaymentOrderRequest extends FormRequest
{
/**
@@ -28,16 +33,14 @@ class CreateVipPaymentOrderRequest extends FormRequest
{
return [
'vip_level_id' => ['required', 'integer', 'exists:vip_levels,id'],
'provider' => ['required', 'string', 'in:alipay,wechat'],
];
}
/**
* 配置验证器实例。
*
* @param \Illuminate\Validation\Validator $validator
* @return void
*/
public function withValidator($validator): void
public function withValidator(Validator $validator): void
{
$validator->after(function ($validator) {
$user = $this->user();
@@ -71,6 +74,8 @@ class CreateVipPaymentOrderRequest extends FormRequest
return [
'vip_level_id.required' => '请选择要购买的 VIP 等级',
'vip_level_id.exists' => '所选 VIP 等级不存在或已被删除',
'provider.required' => '请选择支付方式',
'provider.in' => '当前支付方式不受支持,请重新选择',
];
}
}
+6 -1
View File
@@ -13,6 +13,10 @@ use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use RuntimeException;
/**
* NovaLink 支付中心客户端
* 负责构建开放接口签名请求,并与远端支付中心完成下单和查单通信。
*/
class VipPaymentCenterClient
{
/**
@@ -65,7 +69,8 @@ class VipPaymentCenterClient
'subject' => $vipPaymentOrder->subject,
'body' => '聊天室 VIP 会员购买:'.$vipPaymentOrder->vip_name,
'amount' => number_format((float) $vipPaymentOrder->amount, 2, '.', ''),
'channel' => 'web',
// 支付中心要求商户显式指定 provider,不能依赖平台自动推断。
'provider' => $vipPaymentOrder->provider,
'business_type' => 'chatroom_vip',
'sync_return_url' => $syncReturnUrl,
'async_notify_url' => $asyncNotifyUrl,
+21 -2
View File
@@ -40,11 +40,13 @@ class VipPaymentService
*
* @param User $user 购买用户
* @param VipLevel $vipLevel 目标 VIP 等级
* @param string $provider 用户选择的支付渠道
*/
public function createLocalOrder(User $user, VipLevel $vipLevel): VipPaymentOrder
public function createLocalOrder(User $user, VipLevel $vipLevel, string $provider): VipPaymentOrder
{
$currentVip = $user->isVip() ? $user->vipLevel : null;
$isUpgrade = $currentVip && $vipLevel->isHigherThan($currentVip);
$provider = $this->normalizeProvider($provider);
// 如果已经是该等级或更高级别,且不是永久会员续费(逻辑上续费应该用原价,但此处 user 需求是升级补差价)
// 这里我们主要处理补差价升级逻辑。
@@ -73,7 +75,8 @@ class VipPaymentService
'status' => 'created',
'amount' => $price,
'subject' => ($isUpgrade ? '【升级】' : '购买').' VIP 会员 - '.$vipLevel->name,
'provider' => 'alipay',
// 下单时必须固化用户选择的支付渠道,避免支付中心拒绝未指定 provider 的请求。
'provider' => $provider,
'vip_name' => $vipLevel->name,
'vip_duration_days' => (int) $vipLevel->duration_days,
'meta' => [
@@ -250,6 +253,22 @@ class VipPaymentService
return 'VPO'.date('YmdHis').random_int(1000, 9999);
}
/**
* 规范化并校验支付渠道
*
* @param string $provider 前端提交的支付渠道
*/
private function normalizeProvider(string $provider): string
{
$provider = trim(strtolower($provider));
if (! in_array($provider, ['alipay', 'wechat'], true)) {
throw new RuntimeException('当前支付方式不受支持。');
}
return $provider;
}
/**
* 向用户当前在线的聊天室广播 VIP 购买成功喜报与烟花特效。
*