feat: enhance player authentication and agent management features
Some checks failed
lotterLaravel CI / test (push) Has been cancelled

- Updated AGENTS.md to clarify player interface bindings and agent account restrictions.
- Improved PlayerAuthLoginController to include captcha verification for player login.
- Enhanced AdminPlayerIndexController with permission checks for admin users.
- Refactored AdminPlayerStoreController to enforce agent node restrictions for non-super admins.
- Introduced new error codes for player authentication failures and updated related services.
- Enhanced validation rules for agent profiles to include settlement cycle options.
- Improved AdminCaptchaService to support separate scopes for admin and player captcha handling.
- Updated various services to ensure proper credit management and settlement processes.
This commit is contained in:
2026-06-17 15:27:00 +08:00
parent b496a9457c
commit 2e0b257160
49 changed files with 714 additions and 334 deletions

View File

@@ -35,7 +35,7 @@ final class PlayerLedgerLogsService
/** PRD 对外类型 → credit_ledger.reason信用盘不用钱包「派彩」口径 */
private const CREDIT_TYPE_TO_REASON = [
'bet' => ['bet_hold', 'game_settlement_loss'],
'reversal' => ['bet_hold_release'],
'reversal' => ['bet_hold_release', 'game_settlement_reversal'],
'refund' => ['settlement_confirm'],
'win_credit' => ['game_settlement_win'],
'credit_release' => ['game_settlement_win', 'settlement_confirm', 'bet_hold_release'],
@@ -106,6 +106,7 @@ final class PlayerLedgerLogsService
'bet_hold_release',
'game_settlement_loss',
'game_settlement_win',
'game_settlement_reversal',
'settlement_confirm',
'settlement_payout',
]), 5000);
@@ -180,9 +181,26 @@ final class PlayerLedgerLogsService
$pageRows = array_slice($simplified, $offset, $perPage);
$runningMinor = $this->playerCreditService->availableCreditMinor($player, $currency);
foreach (array_slice($simplified, 0, $offset) as $priorRow) {
if (! $this->adminCreditRowAffectsAvailableBalance($priorRow)) {
continue;
}
$runningMinor -= $this->adminCreditRowSignedDelta($priorRow);
}
$items = [];
foreach ($pageRows as $formatted) {
$signed = (int) ($formatted['direction'] === 1 ? $formatted['amount'] : -$formatted['amount']);
if (! $this->adminCreditRowAffectsAvailableBalance($formatted)) {
$items[] = array_merge($formatted, [
'balance_after' => null,
'balance_after_formatted' => null,
'balance_before' => null,
'balance_before_formatted' => null,
]);
continue;
}
$signed = $this->adminCreditRowSignedDelta($formatted);
$items[] = array_merge($formatted, [
'balance_after' => $runningMinor,
'balance_after_formatted' => CurrencyFormatter::fromMinor($runningMinor),
@@ -414,7 +432,13 @@ final class PlayerLedgerLogsService
->paginate($perPage, ['*'], 'page', $page);
$currency = (string) $player->default_currency;
$runningMinor = $this->playerCreditService->availableCreditMinor($player, $currency);
$skipRows = max(0, ($paginator->currentPage() - 1) * $paginator->perPage());
$runningMinor = $this->advanceCreditLedgerRunningMinor(
(int) $player->id,
$reasonFilter,
$this->playerCreditService->availableCreditMinor($player, $currency),
$skipRows,
);
$items = $paginator->getCollection()
->map(function (object $row) use (&$runningMinor, $player, $currency): array {
$amount = (int) $row->amount;
@@ -587,6 +611,49 @@ final class PlayerLedgerLogsService
return $reason !== 'settlement_payout';
}
/**
* @param list<string>|null $reasonFilter
*/
private function advanceCreditLedgerRunningMinor(
int $playerId,
?array $reasonFilter,
int $runningMinor,
int $skipRows,
): int {
if ($skipRows <= 0) {
return $runningMinor;
}
$priorRows = $this->creditLedgerQuery($playerId, $reasonFilter)
->limit($skipRows)
->get();
foreach ($priorRows as $row) {
if (! $this->creditReasonAffectsAvailableBalance((string) $row->reason)) {
continue;
}
$runningMinor -= (int) $row->amount;
}
return $runningMinor;
}
/**
* @param array<string, mixed> $formatted
*/
private function adminCreditRowAffectsAvailableBalance(array $formatted): bool
{
return ($formatted['biz_type'] ?? '') !== 'settlement_payout';
}
/**
* @param array<string, mixed> $formatted
*/
private function adminCreditRowSignedDelta(array $formatted): int
{
return (int) ($formatted['direction'] === 1 ? $formatted['amount'] : -$formatted['amount']);
}
/**
* @return array<string, mixed>
*/
@@ -636,7 +703,7 @@ final class PlayerLedgerLogsService
{
return match ($reason) {
'bet_hold', 'game_settlement_loss' => 'bet',
'bet_hold_release' => 'reversal',
'bet_hold_release', 'game_settlement_reversal' => 'reversal',
'settlement_confirm' => 'refund',
'game_settlement_win' => 'win_credit',
'settlement_payout' => 'bill_settlement',