Files
lotteryLaravel/tests/Feature/CreditHoldConcurrencyTest.php
kang b496a9457c
Some checks failed
lotterLaravel CI / test (push) Has been cancelled
feat: enhance configuration and logging for admin services
- Updated .env.example to enable Redis Lua for lottery risk pool and added configuration for agent settlement.
- Improved AGENTS.md to clarify site operations and admin roles.
- Enhanced PHPUnit configuration with memory limit and cache directory settings.
- Refactored AdminReportQueryService and related services to utilize LimitedQuery for better data handling and truncation warnings.
- Added logging for draw settlement failures in DrawTickService.
- Introduced credit preflight checks and reverse bet hold functionality in PlayerCreditService.
- Improved risk pool management with new Redis lock handling in RiskPoolService and TicketPlacementService.
2026-06-16 17:08:10 +08:00

100 lines
3.2 KiB
PHP

<?php
use App\Models\Player;
use App\Services\Player\PlayerCreditService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
uses(RefreshDatabase::class);
test('credit hold rejects second hold when available credit exhausted', function (): void {
$site = DB::table('admin_sites')->where('is_default', true)->first();
$player = Player::query()->create([
'site_code' => (string) $site->code,
'agent_node_id' => (int) DB::table('agent_nodes')->where('depth', 0)->value('id'),
'site_player_id' => 'cl-race',
'auth_source' => 'lottery_native',
'funding_mode' => 'credit',
'username' => 'clr1',
'nickname' => null,
'default_currency' => 'NPR',
'status' => 0,
]);
DB::table('player_credit_accounts')->insert([
'player_id' => $player->id,
'credit_limit' => 10,
'used_credit' => 0,
'frozen_credit' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
$credit = app(PlayerCreditService::class);
$credit->holdForBet($player, 800);
expect(fn () => $credit->holdForBet($player, 300))
->toThrow(ValidationException::class);
expect((int) DB::table('player_credit_accounts')->where('player_id', $player->id)->value('used_credit'))
->toBe(8);
});
test('credit preflight rejects hold when overdue bill exists', function (): void {
$site = DB::table('admin_sites')->where('is_default', true)->first();
$periodId = (int) DB::table('settlement_periods')->insertGetId([
'admin_site_id' => (int) $site->id,
'period_start' => now()->subWeek(),
'period_end' => now()->subDay(),
'status' => 'closed',
'created_at' => now(),
'updated_at' => now(),
]);
$player = Player::query()->create([
'site_code' => (string) $site->code,
'agent_node_id' => (int) DB::table('agent_nodes')->where('depth', 0)->value('id'),
'site_player_id' => 'cl-od',
'auth_source' => 'lottery_native',
'funding_mode' => 'credit',
'username' => 'clod1',
'nickname' => null,
'default_currency' => 'NPR',
'status' => 0,
]);
DB::table('player_credit_accounts')->insert([
'player_id' => $player->id,
'credit_limit' => 10000,
'used_credit' => 0,
'frozen_credit' => 0,
'created_at' => now(),
'updated_at' => now(),
]);
DB::table('settlement_bills')->insert([
'settlement_period_id' => $periodId,
'bill_type' => 'player',
'owner_type' => 'player',
'owner_id' => $player->id,
'counterparty_type' => 'agent',
'counterparty_id' => $player->agent_node_id,
'gross_win_loss' => 1000,
'rebate_amount' => 0,
'adjustment_amount' => 0,
'net_amount' => 1000,
'paid_amount' => 0,
'unpaid_amount' => 1000,
'status' => 'overdue',
'created_at' => now(),
'updated_at' => now(),
]);
$credit = app(PlayerCreditService::class);
expect(fn () => $credit->assertCreditPreflight($player, 100))
->toThrow(ValidationException::class);
});