Lae/app/Models/Subscription.php

173 lines
4.4 KiB
PHP
Raw Permalink Normal View History

2023-02-28 11:31:05 +00:00
<?php
namespace App\Models;
use App\Exceptions\User\BalanceNotEnoughException;
2023-02-28 13:37:23 +00:00
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
2023-02-28 11:31:05 +00:00
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Subscription extends Model
{
2023-02-28 13:37:23 +00:00
use Cachable;
2023-02-28 11:31:05 +00:00
public $fillable = [
'name',
'status',
'plan_id',
'configuration',
'price',
'expired_at',
'trial_ends_at',
'module_id',
'user_id',
'cancel_at_period_end',
'renew_price',
];
protected $casts = [
'configuration' => 'array',
'price' => 'decimal:2',
'renew_price' => 'decimal:2',
];
protected $dates = [
'expired_at',
'trial_ends_at',
];
public function scopeThisUser($query, $module_id = null)
{
$query = $query->where('user_id', auth()->id());
if ($module_id) {
$query = $query->where('module_id', $module_id);
}
return $query;
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function module(): BelongsTo
{
return $this->belongsTo(Module::class);
}
public function active(): bool
{
return $this->canActivate() && $this->renew();
}
public function canActivate(bool $ignore_activated = false): bool
{
if ($ignore_activated && $this->isActive()) {
return true;
}
// 检测 trial_ends_at 是否过期
if ($this->trial_ends_at && $this->trial_ends_at->isPast()) {
return false;
}
return true;
}
public function isActive(): bool
{
return $this->status === 'active';
}
public function renew(): bool
{
if ($this->isTrial()) {
$this->status = 'active';
}
// 如果过期时间距离今天超过了 7 天,那么就不能续费了
if ($this->expired_at && $this->expired_at->diffInDays(now()) > 7) {
return false;
}
$price = $this->price;
try {
$this->user->reduce($price, '订阅: '.$this->name, true, [
'module_id' => $this->module_id,
'user_id' => $this->user_id,
'subscription_id' => $this->id,
]);
$this->module->charge($price, 'module_balance', '订阅: '.$this->name.' 续费', [
'module_id' => $this->module_id,
'user_id' => $this->user_id,
'subscription_id' => $this->id,
]);
} catch (BalanceNotEnoughException) {
return false;
}
$this->renew_price = $price;
if (! $this->isTrial()) {
$this->expired_at = now()->addMonth();
}
$this->status = 'active';
$this->save();
return true;
}
public function isTrial(): bool
{
return $this->trial_ends_at !== null;
}
public function safeDelete()
{
// 如果是试用,那么就直接删除
if ($this->isTrial() || $this->isExpired() || $this->isDraft() || ! $this->renew_price) {
$this->delete();
return;
}
// 如果是正式订阅,那么就按使用天数计算退款
$days = $this->expired_at ? $this->expired_at->diffInDays(now()) : 27;
// 获取 create_at 当时的月份的天数
$daysInMonth = $this->created_at->daysInMonth;
// 按照使用天数计算退款(bcdiv 保留两位小数)
$refund = bcdiv($this->renew_price, $daysInMonth, 2) * $days;
// 如果退款金额大于 0那么就退款
if ($refund > 0) {
$this->user->charge($refund, 'balance', '订阅: '.$this->name.' 退款', [
'module_id' => $this->module_id,
'user_id' => $this->user_id,
'subscription_id' => $this->id,
]);
$this->module->reduce($refund, '订阅: '.$this->name.' 退款', false, [
'module_id' => $this->module_id,
'user_id' => $this->user_id,
'subscription_id' => $this->id,
]);
}
$this->delete();
}
public function isExpired(): bool
{
return $this->expired_at && $this->expired_at->isPast();
}
public function isDraft(): bool
{
return $this->status === 'draft';
}
}