增加 主机计费周期
This commit is contained in:
parent
3abbc86951
commit
1424375a4b
@ -37,7 +37,8 @@ public function store(Request $request): Response|JsonResponse
|
||||
{
|
||||
// 存储计费项目
|
||||
$this->validate($request, [
|
||||
'status' => 'required|in:running,stopped,error,suspended,pending',
|
||||
'status' => 'required|in:draft,running,stopped,error,suspended,pending',
|
||||
'billing_cycle' => 'nullable|in:monthly,quarterly,semi-annually,annually,biennially,triennially',
|
||||
'price' => 'required|numeric',
|
||||
'user_id' => 'required|integer|exists:users,id',
|
||||
]);
|
||||
@ -55,11 +56,12 @@ public function store(Request $request): Response|JsonResponse
|
||||
|
||||
$data = [
|
||||
'name' => $name,
|
||||
'status' => $request->input('status'),
|
||||
'price' => $request->input('price'),
|
||||
'managed_price' => $request->input('managed_price'),
|
||||
'user_id' => $user->id,
|
||||
'module_id' => auth('module')->id(),
|
||||
'price' => $request->input('price'),
|
||||
'managed_price' => $request->input('managed_price'),
|
||||
'billing_cycle' => $request->input('billing_cycle'),
|
||||
'status' => $request->input('status'),
|
||||
];
|
||||
|
||||
$host = (new Host)->create($data);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Events\Users;
|
||||
use App\Exceptions\User\BalanceNotEnoughException;
|
||||
use App\Jobs\Host\HostJob;
|
||||
use App\Jobs\Host\UpdateOrDeleteHostJob;
|
||||
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
|
||||
@ -22,17 +22,20 @@ class Host extends Model
|
||||
'module_id',
|
||||
'user_id',
|
||||
'price',
|
||||
'managed_price',
|
||||
'configuration',
|
||||
'status',
|
||||
'managed_price',
|
||||
'billing_cycle',
|
||||
'next_due_at',
|
||||
'suspended_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
// 'configuration' => 'array',
|
||||
'suspended_at' => 'datetime',
|
||||
'price' => 'decimal:2',
|
||||
'managed_price' => 'decimal:2',
|
||||
'configuration' => 'array',
|
||||
'next_due_at' => 'datetime',
|
||||
'suspended_at' => 'datetime',
|
||||
];
|
||||
|
||||
/** @noinspection PhpUndefinedMethodInspection */
|
||||
@ -68,6 +71,21 @@ public function scopeActive($query)
|
||||
return $query->whereIn('status', ['running', 'stopped']);
|
||||
}
|
||||
|
||||
public function scopeDraft($query)
|
||||
{
|
||||
return $query->where('status', 'draft');
|
||||
}
|
||||
|
||||
public function scopeExpiring($query)
|
||||
{
|
||||
return $query->where('status', 'running')->where('next_due_at', '<=', now()->addDays(7));
|
||||
}
|
||||
|
||||
public function scopeSuspended($query)
|
||||
{
|
||||
return $query->where('status', 'suspended');
|
||||
}
|
||||
|
||||
public function scopeThisUser($query, $module = null)
|
||||
{
|
||||
if ($module) {
|
||||
@ -77,6 +95,88 @@ public function scopeThisUser($query, $module = null)
|
||||
}
|
||||
}
|
||||
|
||||
public function isDraft(): bool
|
||||
{
|
||||
return $this->status === 'draft';
|
||||
}
|
||||
|
||||
public function isRunning(): bool
|
||||
{
|
||||
return $this->status === 'running';
|
||||
}
|
||||
|
||||
public function isStopped(): bool
|
||||
{
|
||||
return $this->status === 'stopped';
|
||||
}
|
||||
|
||||
public function isSuspended(): bool
|
||||
{
|
||||
return $this->status === 'suspended';
|
||||
}
|
||||
|
||||
public function getNewDueDate(): string
|
||||
{
|
||||
$this->next_due_at = $this->next_due_at ?? now();
|
||||
|
||||
return match ($this->billing_cycle) {
|
||||
'monthly' => $this->next_due_at->addMonth(),
|
||||
'quarterly' => $this->next_due_at->addMonths(3),
|
||||
'semi-annually' => $this->next_due_at->addMonths(6),
|
||||
'annually' => $this->next_due_at->addYear(),
|
||||
'biennially' => $this->next_due_at->addYears(2),
|
||||
'triennially' => $this->next_due_at->addYears(3),
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
|
||||
public function getRenewPrice(): string
|
||||
{
|
||||
return match ($this->billing_cycle) {
|
||||
'monthly' => $this->getPrice(),
|
||||
'quarterly' => bcmul($this->getPrice(), 3),
|
||||
'semi-annually' => bcmul($this->getPrice(), 6),
|
||||
'annually' => bcmul($this->getPrice(), 12),
|
||||
'biennially' => bcmul($this->getPrice(), 24),
|
||||
'triennially' => bcmul($this->getPrice(), 36),
|
||||
default => 0,
|
||||
};
|
||||
}
|
||||
|
||||
public function renew(): bool
|
||||
{
|
||||
$price = $this->getRenewPrice();
|
||||
|
||||
$description = '续费 '.$this->name.' 周期: '.$this->billing_cycle;
|
||||
|
||||
try {
|
||||
$this->user->reduce($price, $description, true, [
|
||||
'host_id' => $this->id,
|
||||
'module_id' => $this->module_id,
|
||||
]);
|
||||
} catch (BalanceNotEnoughException) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->addLog($price);
|
||||
|
||||
$this->next_due_at = $this->getNewDueDate();
|
||||
|
||||
$this->save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isOverdue(): bool
|
||||
{
|
||||
return now()->gt($this->next_due_at);
|
||||
}
|
||||
|
||||
public function isCycle(): bool
|
||||
{
|
||||
return $this->billing_cycle !== null;
|
||||
}
|
||||
|
||||
public function safeDelete(): bool
|
||||
{
|
||||
// 如果创建时间大于大于 1 小时
|
||||
@ -116,7 +216,7 @@ public function cost(string $amount = null, $auto = true, $description = null):
|
||||
$append_description = '';
|
||||
if ($user_group) {
|
||||
if ($user_group->discount !== 100 && $user_group->discount !== null) {
|
||||
$real_price = bcmul($real_price, bcdiv($user_group->discount, '100', 4), 4);
|
||||
$real_price = $user_group->getCostPrice($real_price);
|
||||
|
||||
$append_description = ' (折扣 '.$user_group->discount.'%)';
|
||||
}
|
||||
@ -181,8 +281,6 @@ public function cost(string $amount = null, $auto = true, $description = null):
|
||||
|
||||
$this->addLog($real_price);
|
||||
|
||||
broadcast(new Users($this->user, 'balances.amount.reduced', $this->user));
|
||||
|
||||
if ($left < 0) {
|
||||
$this->update([
|
||||
'status' => 'suspended',
|
||||
|
@ -21,6 +21,10 @@ public function creating(Host $host): void
|
||||
if ($host->managed_price !== null) {
|
||||
$host->managed_price = bcdiv($host->managed_price, 1, 2);
|
||||
}
|
||||
|
||||
if ($host->billing_cycle !== null) {
|
||||
$host->next_due_at = $host->getNewDueDate();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
30
app/View/Components/BillingCycle.php
Normal file
30
app/View/Components/BillingCycle.php
Normal file
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class BillingCycle extends Component
|
||||
{
|
||||
public string $cycle = 'dynamic';
|
||||
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(null|string $cycle = 'dynamic')
|
||||
{
|
||||
$this->cycle = $cycle ?? 'dynamic';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function render(): string
|
||||
{
|
||||
return trans('hosts.' . $this->cycle);
|
||||
}
|
||||
}
|
13
lang/zh_CN/hosts.php
Normal file
13
lang/zh_CN/hosts.php
Normal file
@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
return [
|
||||
'monthly' => '每月',
|
||||
'quarterly' => '每季度',
|
||||
'semi-annually' => '每半年',
|
||||
'annually' => '每年',
|
||||
'biennially' => '每两年',
|
||||
'triennially' => '每三年',
|
||||
'dynamic' => '动态',
|
||||
];
|
3
resources/views/components/billing-cycle.blade.php
Normal file
3
resources/views/components/billing-cycle.blade.php
Normal file
@ -0,0 +1,3 @@
|
||||
<div>
|
||||
<!-- Simplicity is the consequence of refined emotions. - Jean D'Alembert -->
|
||||
</div>
|
Loading…
Reference in New Issue
Block a user