updateOrInsert( ['player_id' => $player->id], [ 'credit_limit' => $limit, 'used_credit' => DB::raw('COALESCE(used_credit, 0)'), 'frozen_credit' => DB::raw('COALESCE(frozen_credit, 0)'), 'updated_at' => now(), 'created_at' => now(), ], ); } public function availableCredit(Player $player): int { $row = DB::table('player_credit_accounts')->where('player_id', $player->id)->first(); if ($row === null) { return 0; } return max(0, (int) $row->credit_limit - (int) $row->used_credit - (int) $row->frozen_credit); } public function holdForBet(Player $player, int $amount): void { if ($amount <= 0) { return; } if (! \App\Support\CreditLineMode::isEnabledForSiteCode((string) $player->site_code)) { return; } $available = $this->availableCredit($player); if ($amount > $available) { throw ValidationException::withMessages([ 'credit' => ['insufficient'], ]); } DB::table('player_credit_accounts') ->where('player_id', $player->id) ->update([ 'used_credit' => DB::raw('used_credit + '.$amount), 'updated_at' => now(), ]); DB::table('credit_ledger')->insert([ 'owner_type' => 'player', 'owner_id' => $player->id, 'amount' => -$amount, 'reason' => 'bet_hold', 'ref_type' => 'bet', 'ref_id' => null, 'created_at' => now(), 'updated_at' => now(), ]); } public function releaseFromSettlement(Player $player, int $amount, int $billId): void { if ($amount <= 0) { return; } DB::table('player_credit_accounts') ->where('player_id', $player->id) ->update([ 'used_credit' => DB::raw('GREATEST(0, used_credit - '.$amount.')'), 'updated_at' => now(), ]); DB::table('credit_ledger')->insert([ 'owner_type' => 'player', 'owner_id' => $player->id, 'amount' => $amount, 'reason' => 'settlement_confirm', 'ref_type' => 'settlement_bill', 'ref_id' => $billId, 'created_at' => now(), 'updated_at' => now(), ]); } }