diff --git a/app/Console/Commands/UserAddBalance.php b/app/Console/Commands/UserAddBalance.php index f72e239..3ffa14e 100644 --- a/app/Console/Commands/UserAddBalance.php +++ b/app/Console/Commands/UserAddBalance.php @@ -7,6 +7,7 @@ use App\Models\User\Balance; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; +use App\Exceptions\ChargeException; class UserAddBalance extends Command { @@ -53,8 +54,9 @@ public function handle() $balance = new Balance(); - $this->info($user->name . ', 当前余额: ' . $user->balance); + $this->info($user->name . ', 当前余额: ' . $user->balance . ' 元'); + $this->info('充值后余额: ' . ($user->balance + $amount) . ' 元'); if (!$this->confirm('确认充值 ' . $amount . ' 元?')) { $this->info('已取消。'); return; @@ -70,30 +72,18 @@ public function handle() $transaction = new Transaction(); - DB::beginTransaction(); + $description = '控制台充值 ' . $amount . ' 元'; + try { - $balance->user->increment('balance', $amount); - - $description = '控制台充值 ' . $amount . ' 元'; - $transaction->addIncomeBalance($balance->user_id, 'console', $amount, $description); - - $balance->update([ - 'paid_at' => now(), - ]); - - DB::commit(); + $transaction->addAmount($user->id, 'console', $amount, $description); $this->info('充值成功。'); $user->refresh(); $this->info($user->name . ', 当前余额: ' . $user->balance); + } catch (ChargeException $e) { - } catch (\Exception $e) { - DB::rollBack(); - - $this->error('充值失败。' . $e->getMessage()); - - return; + return $this->error($e->getMessage()); } } } diff --git a/app/Exceptions/ChargeException.php b/app/Exceptions/ChargeException.php new file mode 100644 index 0000000..4accfbf --- /dev/null +++ b/app/Exceptions/ChargeException.php @@ -0,0 +1,10 @@ +id; return $this->created($host); - } /** @@ -86,15 +84,24 @@ public function update(Request $request, Host $host) // 如果是立即扣费 'cost_once' => 'sometimes|numeric|nullable', + + 'cost_balance' => 'sometimes|numeric|nullable', ]); // if has cost_once if ($request->has('cost_once')) { - $host->cost($request->cost_once, false); + $host->cost($request->cost_once ?? 0, false); - return $this->updated($request->cost_once); + return $this->updated(); } + if ($request->has('cost_balance')) { + $host->costBalance($request->cost_balance ?? 0); + + return $this->updated(); + } + + $update = $request->all(); // module_id 不能被更新 unset($update['module_id']); diff --git a/app/Http/Controllers/User/BalanceController.php b/app/Http/Controllers/User/BalanceController.php index 43995c6..319d76a 100644 --- a/app/Http/Controllers/User/BalanceController.php +++ b/app/Http/Controllers/User/BalanceController.php @@ -3,15 +3,16 @@ namespace App\Http\Controllers\User; use Exception; +use App\Models\Transaction; use App\Models\User\Balance; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; +use App\Exceptions\ChargeException; use Illuminate\Support\Facades\Log; use App\Http\Controllers\Controller; use Illuminate\Support\Facades\Cache; use Alipay\EasySDK\Kernel\Util\ResponseChecker; use Alipay\EasySDK\Kernel\Factory as AlipayFactory; -use App\Models\Transaction; class BalanceController extends Controller { @@ -161,16 +162,9 @@ public function checkAndCharge(Balance $balance) $transaction = new Transaction(); - DB::beginTransaction(); try { - $balance->user->increment('balance', $trade->totalAmount); - - $description = '充值 ' . $trade->totalAmount . ' 元'; - $transaction->addIncomeBalance($balance->user_id, 'alipay', $trade->totalAmount, $description); - - DB::commit(); - } catch (\Exception $e) { - DB::rollBack(); + $transaction->addAmount($balance->user_id, 'alipay', $trade->totalAmount); + } catch (ChargeException $e) { AlipayFactory::payment()->common()->refund($balance->order_id, $trade->totalAmount); return $this->error($e->getMessage()); } diff --git a/app/Models/Host.php b/app/Models/Host.php index 01e2d72..78574ce 100644 --- a/app/Models/Host.php +++ b/app/Models/Host.php @@ -152,6 +152,24 @@ public function cost($price = null, $auto = true) return true; } + + public function costBalance($amount = 1) + { + $transaction = new Transaction(); + + $left = $transaction->reduceAmount($this->user_id, $amount); + + broadcast(new UserEvent($this->user_id, 'balances.amount.reduced', $this->user)); + + if ($left < 0) { + $this->update([ + 'status' => 'suspended', + ]); + } + + return true; + } + protected static function boot() { parent::boot(); diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index be54f52..82cb876 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -2,9 +2,11 @@ namespace App\Models; -use Jenssegers\Mongodb\Eloquent\Model; -use Illuminate\Support\Facades\Cache; +use App\Exceptions\ChargeException; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Cache; +use Jenssegers\Mongodb\Eloquent\Model; +use Illuminate\Contracts\Cache\LockTimeoutException; class Transaction extends Model { @@ -203,27 +205,61 @@ public function addPayoutBalance($user_id, $amount, $description) return $this->addLog($user_id, $data); } + + public function reduceAmount($user_id, $amount = 0, $description = '扣除费用请求。') { - $user = User::findOrFail($user_id); - if ($user) { + $lock = Cache::lock("user_balance_lock_" . $user_id, 10); + try { + + $lock->block(5); + + $user = User::findOrFail($user_id); + $user->balance -= $amount; - $user->save(); + + $this->addPayoutBalance($user_id, $amount, $description); + + return $user->balance; + } finally { + optional($lock)->release(); } - $data = [ - 'type' => 'payout', - 'payment' => 'balance', - 'description' => $description, - 'income' => 0, - 'income_drops' => 0, - 'outcome' => $amount, - 'outcome_drops' => 0 - ]; + return false; + } - return $this->addLog($user_id, $data); + public function addAmount($user_id, $payment = 'console', $amount = 0, $description = null) + { + $lock = Cache::lock("user_balance_lock_" . $user_id, 10); + try { + + $lock->block(5); + + $user = User::findOrFail($user_id); + + $left_balance = $user->balance + $amount; + + $user->increment('balance', $amount); + + if (!$description) { + $description = '充值金额。'; + } else { + $description = '充值 ' . $amount . ' 元'; + } + + $this->addIncomeBalance($user_id, $payment, $amount, $description); + + return $left_balance; + } catch (LockTimeoutException $e) { + Log::error($e); + throw new ChargeException('充值失败,请稍后再试。'); + } finally { + optional($lock)->release(); + } + + return false; } diff --git a/app/Models/User.php b/app/Models/User.php index ee4b3ba..3adce98 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -96,14 +96,14 @@ public function toDrops($amount = 1) return $this; } - // when update - // protected static function boot() - // { - // parent::boot(); + protected static function boot() + { + parent::boot(); - // // when update - // static::updating(function ($model) { + static::updating(function ($model) { - // }); - // } + // balance 四舍五入 + $model->balance = round($model->balance, 2); + }); + } }