create([ 'draw_no' => '20260709-001', 'business_date' => '2026-07-09', 'sequence_no' => 1, 'status' => 'open', 'start_time' => now()->subHour(), 'close_time' => now()->addHour(), 'draw_time' => now()->addHours(2), 'cooling_end_time' => null, 'result_source' => null, 'current_result_version' => 0, 'settle_version' => 0, 'is_reopened' => false, ]); RiskPool::query()->create([ 'draw_id' => $draw->id, 'provider_code' => 'SG', 'normalized_number' => '1234', 'total_cap_amount' => 1_000, 'locked_amount' => 1_000, 'remaining_amount' => 0, 'sold_out_status' => 1, 'version' => 1, ]); RiskPool::query()->create([ 'draw_id' => $draw->id, 'provider_code' => 'MY', 'normalized_number' => '1234', 'total_cap_amount' => 1_000, 'locked_amount' => 100, 'remaining_amount' => 900, 'sold_out_status' => 0, 'version' => 1, ]); $service = app(RiskPoolService::class); expect(fn () => $service->preview($draw->id, 'SG', [['number_4d' => '1234', 'amount' => 1]])) ->toThrow(\App\Exceptions\TicketOperationException::class, 'risk_sold_out'); expect($service->preview($draw->id, 'MY', [['number_4d' => '1234', 'amount' => 200]])) ->toBe([ ['number_4d' => '1234', 'amount' => 200, 'warning' => false], ]); expect($service->acquire($draw->id, 'MY', null, [['number_4d' => '1234', 'amount' => 200]])) ->toBe(200); $this->assertDatabaseHas('risk_pools', [ 'draw_id' => $draw->id, 'provider_code' => 'SG', 'normalized_number' => '1234', 'locked_amount' => 1_000, 'remaining_amount' => 0, 'sold_out_status' => 1, ]); $this->assertDatabaseHas('risk_pools', [ 'draw_id' => $draw->id, 'provider_code' => 'MY', 'normalized_number' => '1234', 'locked_amount' => 300, 'remaining_amount' => 700, 'sold_out_status' => 0, ]); }); test('risk cap resolver prefers provider-specific item and falls back to global', function (): void { $version = RiskCapVersion::query()->create([ 'version_no' => 1, 'status' => ConfigVersionStatus::Active->value, 'effective_at' => now(), ]); RiskCapItem::query()->create([ 'version_id' => $version->id, 'provider_code' => 'GLOBAL', 'draw_id' => null, 'normalized_number' => '0000', 'cap_amount' => 12_345, 'cap_type' => 'default', ]); RiskCapItem::query()->create([ 'version_id' => $version->id, 'provider_code' => 'GLOBAL', 'draw_id' => null, 'normalized_number' => '1234', 'cap_amount' => 777, 'cap_type' => 'per_number', ]); RiskCapItem::query()->create([ 'version_id' => $version->id, 'provider_code' => 'MY', 'draw_id' => null, 'normalized_number' => '1234', 'cap_amount' => 555, 'cap_type' => 'per_number', ]); $resolver = app(PlayCatalogResolver::class); expect($resolver->resolveCapAmount(9999, '1234', 'MY'))->toBe(555) ->and($resolver->resolveCapAmount(9999, '1234', 'SG'))->toBe(777) ->and($resolver->resolveCapAmount(9999, '5678', 'TH'))->toBe(12_345); });