vip会员支持补差升级

This commit is contained in:
2026-04-12 14:17:01 +08:00
parent 00b9396dea
commit 82e29753b8
4 changed files with 155 additions and 47 deletions
+29 -5
View File
@@ -35,8 +35,26 @@ class VipPaymentService
*/
public function createLocalOrder(User $user, VipLevel $vipLevel): VipPaymentOrder
{
if ((float) $vipLevel->price <= 0) {
throw new RuntimeException('当前 VIP 等级未设置在线支付价格,暂不支持直接购买。');
$currentVip = $user->isVip() ? $user->vipLevel : null;
$isUpgrade = $currentVip && $vipLevel->isHigherThan($currentVip);
// 如果已经是该等级或更高级别,且不是永久会员续费(逻辑上续费应该用原价,但此处 user 需求是升级补差价)
// 这里我们主要处理补差价升级逻辑。
$price = $isUpgrade
? $vipLevel->getUpgradePrice($currentVip)
: (float) $vipLevel->price;
if ($price < 0.01) {
// 如果差价极小或为 0(例如同级或降级),抛出异常或根据业务逻辑处理
if ($isUpgrade) {
throw new RuntimeException('当前等级差价不足 0.01 元,无法发起升级。');
}
if ($user->vip_level_id === $vipLevel->id) {
// 续费逻辑保持原价
$price = (float) $vipLevel->price;
} else {
throw new RuntimeException('不支持降级购买会员。');
}
}
return VipPaymentOrder::create([
@@ -45,13 +63,15 @@ class VipPaymentService
'user_id' => $user->id,
'vip_level_id' => $vipLevel->id,
'status' => 'created',
'amount' => $vipLevel->price,
'subject' => '购买 VIP 会员 - '.$vipLevel->name,
'amount' => $price,
'subject' => ($isUpgrade ? '【升级】' : '购买') . ' VIP 会员 - ' . $vipLevel->name,
'provider' => 'alipay',
'vip_name' => $vipLevel->name,
'vip_duration_days' => (int) $vipLevel->duration_days,
'meta' => [
'username' => $user->username,
'is_upgrade' => $isUpgrade,
'old_vip_level_id' => $currentVip?->id,
],
]);
}
@@ -188,7 +208,11 @@ class VipPaymentService
if (! $lockedOrder->isVipOpened()) {
// 只在首次成功支付时开通会员,防止重复回调导致会员时长重复叠加。
$user = User::query()->lockForUpdate()->findOrFail($lockedOrder->user_id);
$this->vipService->grantVip($user, $lockedOrder->vip_level_id, (int) $lockedOrder->vip_duration_days);
// 从 meta 中提取是否是升级
$isUpgrade = (bool) ($lockedOrder->meta['is_upgrade'] ?? false);
$this->vipService->grantVip($user, $lockedOrder->vip_level_id, (int) $lockedOrder->vip_duration_days, $isUpgrade);
$lockedOrder->update([
'opened_vip_at' => now(),
+13 -6
View File
@@ -46,17 +46,24 @@ class VipService
* @param User $user 目标用户
* @param int $vipLevelId VIP 等级 ID
* @param int $days 天数(0=永久)
* @param bool $isUpgrade 是否为补差价升级
*/
public function grantVip(User $user, int $vipLevelId, int $days = 30): void
public function grantVip(User $user, int $vipLevelId, int $days = 30, bool $isUpgrade = false): void
{
$oldVipId = $user->vip_level_id;
$user->vip_level_id = $vipLevelId;
if ($days > 0) {
// 如果用户已有未过期的会员,在现有到期时间上延长
$baseTime = ($user->hy_time && $user->hy_time->isFuture())
? $user->hy_time
: now();
$user->hy_time = $baseTime->addDays($days);
if ($isUpgrade && $oldVipId && $user->hy_time && $user->hy_time->isFuture()) {
// 如果是升级,到期日期保持不变,除非新等级是永久(days=0)
// 此时只需更新等级 ID,无需修改 hy_time。
} else {
// 如果是新购或续费,在现有到期时间上延长
$baseTime = ($user->hy_time && $user->hy_time->isFuture())
? $user->hy_time
: now();
$user->hy_time = $baseTime->addDays($days);
}
} else {
// 永久会员
$user->hy_time = null;