diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php
index d47f5d6..bcc53a9 100644
--- a/app/Console/Kernel.php
+++ b/app/Console/Kernel.php
@@ -5,7 +5,6 @@
use App\Jobs\Host\DeleteHostJob;
use App\Jobs\Host\DispatchHostCostQueueJob;
use App\Jobs\Host\ScanAllHostsJob;
-use App\Jobs\Host\SuspendOverdueHosts;
use App\Jobs\Module\DispatchFetchModuleJob;
use App\Jobs\Module\SendModuleEarningsJob;
use App\Jobs\User\CheckAndChargeBalanceJob;
@@ -61,9 +60,6 @@ protected function schedule(Schedule $schedule): void
// 设置生日用户组
$schedule->job(new SetBirthdayGroupJob())->dailyAt('00:00')->onOneServer()->name('设置生日用户组');
-
- // 暂停到期的循环计费主机
- $schedule->job(new SuspendOverdueHosts())->dailyAt('00:00')->onOneServer()->name('暂停到期的循环计费主机');
}
/**
diff --git a/app/Http/Controllers/Module/HostController.php b/app/Http/Controllers/Module/HostController.php
index c33cb23..3e587c0 100644
--- a/app/Http/Controllers/Module/HostController.php
+++ b/app/Http/Controllers/Module/HostController.php
@@ -66,12 +66,6 @@ public function store(Request $request): Response|JsonResponse
$host = (new Host)->create($data);
- if (! $user->hasBalance($host->getRenewPrice())) {
- $host->delete();
-
- return $this->error('此用户余额不足,无法开计费项目。');
- }
-
$host['host_id'] = $host->id;
return $this->created($host);
@@ -127,27 +121,6 @@ public function destroy($host): JsonResponse
$host = (new Host)->findOrFail($host);
}
- if ($host?->isCycle()) {
- $days = $host->next_due_at->diffInDays(now());
-
- // 算出 1 天的价格
- $price = bcdiv($host->getPrice(), 31, 4);
-
- // 算出退还的金额
- $amount = bcmul($price, $days, 4);
-
- $host->user->charge($amount, 'balance', '删除主机退款。', [
- 'module_id' => $this->module_id,
- 'host_id' => $this->id,
- 'user_id' => $this->user_id,
- ]);
-
- $host->module->reduce($amount, '删除主机退款。', false, [
- 'module_id' => $this->module_id,
- 'host_id' => $this->id,
- ]);
- }
-
$host?->delete();
return $this->deleted();
diff --git a/app/Http/Controllers/Web/AuthController.php b/app/Http/Controllers/Web/AuthController.php
index 9a25ba6..193a722 100644
--- a/app/Http/Controllers/Web/AuthController.php
+++ b/app/Http/Controllers/Web/AuthController.php
@@ -6,14 +6,14 @@
use App\Http\Controllers\Controller;
use App\Notifications\User\UserNotification;
+use function back;
+use function config;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
-use function back;
-use function config;
use function redirect;
use function session;
use function view;
@@ -33,13 +33,13 @@ public function index(Request $request): View|RedirectResponse
$dashboardHost = parse_url(config('settings.dashboard.base_url'), PHP_URL_HOST);
if ($callbackHost === $dashboardHost) {
- if (!$request->user('web')->isRealNamed()) {
+ if (! $request->user('web')->isRealNamed()) {
return redirect()->route('real_name.create')->with('status', '重定向已被打断,需要先实人认证。');
}
$token = $request->user()->createToken('Dashboard')->plainTextToken;
- return redirect($callback . '?token=' . $token);
+ return redirect($callback.'?token='.$token);
}
session(['referer.domain' => parse_url($request->header('referer'), PHP_URL_HOST)]);
@@ -121,7 +121,7 @@ public function exitSudo(): RedirectResponse
public function showAuthRequest($token): View|RedirectResponse
{
- $data = Cache::get('auth_request:' . $token);
+ $data = Cache::get('auth_request:'.$token);
if (empty($data)) {
return redirect()->route('index')->with('error', '登录请求的 Token 不存在或已过期。');
@@ -145,7 +145,7 @@ public function storeAuthRequest(Request $request): RedirectResponse
'token' => 'required|string|max:128',
]);
- $data = Cache::get('auth_request:' . $request->input('token'));
+ $data = Cache::get('auth_request:'.$request->input('token'));
if (empty($data)) {
return back()->with('error', '登录请求的 Token 不存在或已过期。');
@@ -169,7 +169,7 @@ public function storeAuthRequest(Request $request): RedirectResponse
$data['token'] = $user->createToken($data['meta']['description'] ?? Carbon::now()->toDateString(), $abilities)->plainTextToken;
}
- Cache::put('auth_request:' . $request->input('token'), $data, 60);
+ Cache::put('auth_request:'.$request->input('token'), $data, 60);
return redirect()->route('index')->with('success', '登录请求已确认。');
}
diff --git a/app/Http/Controllers/Web/HostController.php b/app/Http/Controllers/Web/HostController.php
index 6b85e9d..3f21c20 100644
--- a/app/Http/Controllers/Web/HostController.php
+++ b/app/Http/Controllers/Web/HostController.php
@@ -6,7 +6,6 @@
use App\Models\Host;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
-use Illuminate\Support\Facades\Cache;
use Illuminate\View\View;
class HostController extends Controller
@@ -19,9 +18,8 @@ class HostController extends Controller
public function index(): View
{
$hosts = (new Host)->thisUser()->with(['user', 'module'])->paginate(20);
- $times = config('settings.billing.cycle_delete_times_every_month') - Cache::get('host_delete_times:'.auth('web')->id(), 0);
- return view('hosts.index', compact('hosts', 'times'));
+ return view('hosts.index', compact('hosts'));
}
public function update(Request $request, Host $host): RedirectResponse
@@ -35,25 +33,6 @@ public function update(Request $request, Host $host): RedirectResponse
return $status ? back()->with('success', '修改成功。') : back()->with('error', '修改失败。');
}
- public function renew(Host $host): RedirectResponse
- {
- $price = $host->getRenewPrice();
-
- if ($price > auth()->user()->balance) {
- return back()->with('error', '余额不足,续费需要:'.$price.' 元,您还需要充值:'.($price - auth()->user()->balance).' 元');
- }
-
- if (! $host->isCycle()) {
- return back()->with('error', '该主机不是周期性付费,无法续费。');
- }
-
- if ($host->renew()) {
- return back()->with('success', '续费成功,新的到期时间为:'.$host->next_due_at.'。');
- }
-
- return back()->with('error', '续费失败,请检查是否有足够的余额。');
- }
-
/**
* Remove the specified resource from storage.
*
diff --git a/app/Jobs/Host/DispatchHostCostQueueJob.php b/app/Jobs/Host/DispatchHostCostQueueJob.php
index 5c2165a..04bfc63 100644
--- a/app/Jobs/Host/DispatchHostCostQueueJob.php
+++ b/app/Jobs/Host/DispatchHostCostQueueJob.php
@@ -43,7 +43,7 @@ public function handle(): void
$host = $host->where('minute_at', $this->minute);
}
- $host->whereIn('status', ['running', 'stopped'])->whereNull('billing_cycle')->with('user')->chunk(500, function ($hosts) {
+ $host->whereIn('status', ['running', 'stopped'])->with('user')->chunk(500, function ($hosts) {
foreach ($hosts as $host) {
dispatch(new self($this->minute, $host));
}
diff --git a/app/Jobs/Host/SuspendOverdueHosts.php b/app/Jobs/Host/SuspendOverdueHosts.php
deleted file mode 100644
index 808dd41..0000000
--- a/app/Jobs/Host/SuspendOverdueHosts.php
+++ /dev/null
@@ -1,47 +0,0 @@
-host = $host;
- }
-
- /**
- * Execute the job.
- *
- * @return void
- */
- public function handle(): void
- {
- if (! $this->host) {
- (new Host)->where('next_due_at', '<', now())
- ->where('status', '!=', 'suspended')
- ->chunk(100, function ($hosts) {
- foreach ($hosts as $host) {
- dispatch(new self($host));
- }
- });
- }
-
- $this->host?->suspend();
- }
-}
diff --git a/app/Models/Host.php b/app/Models/Host.php
index c8c80b7..5670b25 100644
--- a/app/Models/Host.php
+++ b/app/Models/Host.php
@@ -2,7 +2,6 @@
namespace App\Models;
-use App\Exceptions\User\BalanceNotEnoughException;
use App\Jobs\Host\HostJob;
use App\Jobs\Host\UpdateOrDeleteHostJob;
use GeneaLabs\LaravelModelCaching\Traits\Cachable;
@@ -47,26 +46,21 @@ public function getUserHosts($user_id = null): array|Collection
})->get();
}
- public function user(): BelongsToAlias
- {
- return $this->belongsTo(User::class);
- }
-
public function module(): BelongsToAlias
{
return $this->belongsTo(Module::class);
}
+ public function scopeActive($query)
+ {
+ return $query->whereIn('status', ['running', 'stopped']);
+ }
+
// public function workOrders(): HasManyAlias
// {
// return $this->hasMany(WorkOrder::class);
// }
- public function scopeActive($query)
- {
- return $query->whereIn('status', ['running', 'stopped']);
- }
-
public function scopeDraft($query)
{
return $query->where('status', 'draft');
@@ -91,11 +85,6 @@ public function scopeThisUser($query, $module = null)
}
}
- public function scopeExpiringDays($query, $days)
- {
- return $query->where('status', 'running')->where('next_due_at', '<=', now()->addDays($days));
- }
-
public function isDraft(): bool
{
return $this->status === 'draft';
@@ -116,175 +105,20 @@ public function isUnavailable(): bool
return $this->status === 'unavailable';
}
- public function renew($first = false): bool
- {
- if (! $this->isCycle()) {
- return false;
- }
-
- $price = $this->getRenewPrice();
-
- $description = ($first ? '新购' : '续费').' '.$this->name.',价格:'.$price.' 元。';
-
- try {
- $this->user->reduce($price, $description, true, [
- 'module_id' => $this->module_id,
- 'host_id' => $this->id,
- 'user_id' => $this->user_id,
- ]);
- $this->module->charge($price, 'balance', '用户'.$description, [
- 'module_id' => $this->module_id,
- 'host_id' => $this->id,
- ]);
- } catch (BalanceNotEnoughException) {
- return false;
- }
-
- $this->addLog($price);
-
- $this->next_due_at = $this->getNewDueDate();
- $this->last_paid = $price;
-
- if ($this->isSuspended()) {
- $this->run();
- }
-
- $this->save();
-
- return true;
- }
-
- public function isCycle(): bool
- {
- return $this->billing_cycle !== 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 getPrice(): float
{
return $this->managed_price ?? $this->price;
}
- public function addLog(string $amount = '0'): bool
- {
- if ($amount === '0') {
- return false;
- }
-
- /** 统计收益开始 */
- $current_month = now()->month;
- $current_year = now()->year;
-
- $cache_key = 'module_earning_'.$this->module_id;
-
- // 应支付的提成
- $commission = config('settings.billing.commission');
- $should_amount = bcmul($amount, $commission, 4);
-
- // 应得的余额
- $should_balance = bcsub($amount, $should_amount, 4);
- // 如果太小,则重置为 0.0001
- if ($should_balance < 0.0001) {
- $should_balance = 0.0001;
- }
-
- $earnings = Cache::get($cache_key, []);
-
- if (! isset($earnings[$current_year])) {
- $earnings[$current_year] = [];
- }
-
- if (isset($earnings[$current_year][$current_month])) {
- $earnings[$current_year][$current_month]['balance'] = bcadd($earnings[$current_year][$current_month]['balance'], $amount, 4);
- $earnings[$current_year][$current_month]['should_balance'] = bcadd($earnings[$current_year][$current_month]['should_balance'], $should_balance, 4);
- } else {
- $earnings[$current_year][$current_month] = [
- 'balance' => $amount,
- // 应得(交了手续费)
- 'should_balance' => $should_balance,
- ];
- }
-
- // 删除 前 3 年的数据
- if (count($earnings) > 3) {
- $earnings = array_slice($earnings, -3, 3, true);
- }
-
- $this->module->charge($amount, 'balance', null);
-
- // 保存 1 年
- Cache::forever($cache_key, $earnings);
-
- /** 统计收益结束 */
-
- return true;
- }
-
- 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 isSuspended(): bool
{
return $this->status === 'suspended';
}
- public function run(): bool
- {
- $this->update([
- 'status' => 'running',
- ]);
-
- return true;
- }
-
public function safeDelete(): bool
{
- $is_user = auth()->guard('sanctum')->check() || auth()->guard('web')->check();
-
- if ($this->isCycle() && $is_user) {
- // 周期性的,每个月只能删除固定次数
- $times = Cache::remember('host_delete_times:'.$this->user_id, 60 * 24 * 30, function () {
- return 0;
- });
-
- if ($times >= config('settings.billing.cycle_delete_times_every_month')) {
- return false;
- }
-
- Cache::increment('host_delete_times:'.$this->user_id);
-
- // 根据 next_due_at 来计算退还的金额
- if ($this->next_due_at === null) {
- $this->next_due_at = now();
- }
- }
-
// 如果创建时间大于 1 小时
- if (! $this->isCycle() && $this->created_at->diffInHours(now()) > 1) {
+ if ($this->created_at->diffInHours(now()) > 1) {
// 如果当前时间比扣费时间小,则说明没有扣费。执行扣费。
if (now()->minute < $this->minute_at) {
$this->cost();
@@ -396,6 +230,61 @@ public function cost(
return true;
}
+ public function addLog(string $amount = '0'): bool
+ {
+ if ($amount === '0') {
+ return false;
+ }
+
+ /** 统计收益开始 */
+ $current_month = now()->month;
+ $current_year = now()->year;
+
+ $cache_key = 'module_earning_'.$this->module_id;
+
+ // 应支付的提成
+ $commission = config('settings.billing.commission');
+ $should_amount = bcmul($amount, $commission, 4);
+
+ // 应得的余额
+ $should_balance = bcsub($amount, $should_amount, 4);
+ // 如果太小,则重置为 0.0001
+ if ($should_balance < 0.0001) {
+ $should_balance = 0.0001;
+ }
+
+ $earnings = Cache::get($cache_key, []);
+
+ if (! isset($earnings[$current_year])) {
+ $earnings[$current_year] = [];
+ }
+
+ if (isset($earnings[$current_year][$current_month])) {
+ $earnings[$current_year][$current_month]['balance'] = bcadd($earnings[$current_year][$current_month]['balance'], $amount, 4);
+ $earnings[$current_year][$current_month]['should_balance'] = bcadd($earnings[$current_year][$current_month]['should_balance'], $should_balance, 4);
+ } else {
+ $earnings[$current_year][$current_month] = [
+ 'balance' => $amount,
+ // 应得(交了手续费)
+ 'should_balance' => $should_balance,
+ ];
+ }
+
+ // 删除 前 3 年的数据
+ if (count($earnings) > 3) {
+ $earnings = array_slice($earnings, -3, 3, true);
+ }
+
+ $this->module->charge($amount, 'balance', null);
+
+ // 保存 1 年
+ Cache::forever($cache_key, $earnings);
+
+ /** 统计收益结束 */
+
+ return true;
+ }
+
public function changeStatus(
string $status
): bool {
@@ -406,14 +295,14 @@ public function changeStatus(
return false;
}
- if (! $this->isCycle() && ! $user->hasBalance('0.5')) {
+ if (! $user->hasBalance('0.5')) {
return false;
}
}
if ($status === 'running') {
return $this->run();
- } elseif (($status === 'suspended' || $status === 'suspend') && ! $this->isCycle()) {
+ } elseif (($status === 'suspended' || $status === 'suspend')) {
return $this->suspend();
} elseif ($status === 'stopped') {
return $this->stop();
@@ -422,6 +311,11 @@ public function changeStatus(
return false;
}
+ public function user(): BelongsToAlias
+ {
+ return $this->belongsTo(User::class);
+ }
+
public function isPending(): bool
{
return $this->status === 'pending';
@@ -432,6 +326,15 @@ public function isOverdue(): bool
return now()->gt($this->next_due_at);
}
+ public function run(): bool
+ {
+ $this->update([
+ 'status' => 'running',
+ ]);
+
+ return true;
+ }
+
public function suspend(): bool
{
$this->update([
diff --git a/app/Observers/HostObserver.php b/app/Observers/HostObserver.php
index 09516b4..2305181 100644
--- a/app/Observers/HostObserver.php
+++ b/app/Observers/HostObserver.php
@@ -38,10 +38,6 @@ public function created(Host $host): void
$host->user->notify(new WebNotification($host, 'hosts.created'));
- if ($host->isCycle()) {
- $host->renew(true);
- }
-
$host->save();
}
diff --git a/config/settings.php b/config/settings.php
index 98743fa..1611d3c 100644
--- a/config/settings.php
+++ b/config/settings.php
@@ -3,7 +3,6 @@
return [
'billing' => [
'commission' => '0.1',
- 'cycle_delete_times_every_month' => 2,
],
'wecom' => [
'robot_hook' => [
diff --git a/database/migrations/2023_02_19_235923_remove_cycle_billing_to_hosts.php b/database/migrations/2023_02_19_235923_remove_cycle_billing_to_hosts.php
new file mode 100644
index 0000000..d8cadda
--- /dev/null
+++ b/database/migrations/2023_02_19_235923_remove_cycle_billing_to_hosts.php
@@ -0,0 +1,31 @@
+dropColumn('next_due_at');
+ $table->dropColumn('billing_cycle');
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ *
+ * @return void
+ */
+ public function down(): void
+ {
+ echo 'This migration cannot be reversed.'.PHP_EOL;
+ }
+};
diff --git a/resources/views/hosts/index.blade.php b/resources/views/hosts/index.blade.php
index 9d4fa66..c472364 100644
--- a/resources/views/hosts/index.blade.php
+++ b/resources/views/hosts/index.blade.php
@@ -38,14 +38,6 @@
{{ $host->price }} 元
@endif
- @if($host->billing_cycle)
-
- 续费价格: {{ $host->getRenewPrice() }} 元
-
- 续费后到期时间: {{ $host->getNewDueDate() }}
- @endif
还剩下周期性计费删除次数: {{ $times }}。当次数用完后,您的周期性计费主机只能在到期后删除。
-当您的主机处于 "暂停" 状态时,计费会被终止。但是请注意,3 天后主机将会被删除,请合理使用。
- @endsection