feat: 切换 schema dump 基线并增强返点结算与管理校验

This commit is contained in:
2026-06-08 17:41:41 +08:00
parent 2d32f006c5
commit 8d5d7f5b17
130 changed files with 5746 additions and 6723 deletions

View File

@@ -910,6 +910,70 @@ test('ticket place sold out for second player after first consumes shared pool',
expect((int) $pool->remaining_amount)->toBe(2000);
});
test('ticket preview and place apply base rebate plus player add-on rebate for wallet player', function (): void {
$player = ticketPlayerWithWallet(500_000);
ticketOpenDraw();
$oddsVersionId = OddsVersion::query()
->where('status', ConfigVersionStatus::Active->value)
->value('id');
expect($oddsVersionId)->not->toBeNull();
DB::table('odds_items')
->where('version_id', $oddsVersionId)
->where('play_code', 'big')
->update(['rebate_rate' => 0.01]);
DB::table('player_rebate_profiles')->insert([
'player_id' => $player->id,
'game_type' => 'big',
'rebate_rate' => 0.005,
'extra_rebate_rate' => 0.002,
'inherit_from_agent' => false,
'created_at' => now(),
'updated_at' => now(),
]);
$payload = [
'draw_id' => '20260511-001',
'currency_code' => 'NPR',
'client_trace_id' => 'trace-wallet-rebate-stack',
'lines' => [
['number' => '1234', 'play_code' => 'big', 'amount' => 10_000],
],
];
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
->postJson('/api/v1/ticket/preview', $payload)
->assertOk()
->assertJsonPath('data.summary.total_bet_amount', 10_000)
->assertJsonPath('data.summary.total_actual_deduct', 9_830)
->assertJsonPath('data.summary.total_rebate_amount', 170)
->assertJsonPath('data.lines.0.rebate_rate', '0.0170')
->assertJsonPath('data.lines.0.rebate_amount', 170)
->assertJsonPath('data.lines.0.actual_deduct_amount', 9_830)
->assertJsonPath('data.lines.0.rule_snapshot_json.base_rebate_rate', '0.0100')
->assertJsonPath('data.lines.0.rule_snapshot_json.player_addon_rebate_rate', '0.0070')
->assertJsonPath('data.lines.0.rule_snapshot_json.rebate_inherited_from_agent', false);
$this->withHeader('Authorization', 'Bearer dev:'.$player->id)
->postJson('/api/v1/ticket/place', $payload)
->assertOk()
->assertJsonPath('data.summary.total_bet_amount', 10_000)
->assertJsonPath('data.summary.total_actual_deduct', 9_830);
$item = TicketItem::query()->where('play_code', 'big')->firstOrFail();
$ruleSnapshot = is_array($item->rule_snapshot_json) ? $item->rule_snapshot_json : [];
expect((string) $item->rebate_rate_snapshot)->toBe('0.0170')
->and((int) $item->actual_deduct_amount)->toBe(9_830)
->and($ruleSnapshot['base_rebate_rate'] ?? null)->toBe('0.0100')
->and($ruleSnapshot['player_addon_rebate_rate'] ?? null)->toBe('0.0070');
$wallet = PlayerWallet::query()->where('player_id', $player->id)->firstOrFail();
expect((int) $wallet->balance)->toBe(500_000 - 9_830);
});
test('ticket pending confirmation reconcile releases risk when wallet deduction is missing', function (): void {
$draw = ticketOpenDraw();
$player = ticketPlayerWithWallet();