|
@@ -3,9 +3,13 @@
|
|
|
namespace Tests\Integration;
|
|
namespace Tests\Integration;
|
|
|
|
|
|
|
|
use App\Http\Controllers\admin\LhcOrder;
|
|
use App\Http\Controllers\admin\LhcOrder;
|
|
|
|
|
+use App\Http\Controllers\admin\JisuGame;
|
|
|
|
|
+use App\Http\Controllers\admin\GameplayRule;
|
|
|
|
|
+use App\Http\Middleware\CheckButtonPermission;
|
|
|
use App\Jobs\SendTelegramGroupMessageJob;
|
|
use App\Jobs\SendTelegramGroupMessageJob;
|
|
|
use App\Services\AdminRealtime\AdminRealtimeRows;
|
|
use App\Services\AdminRealtime\AdminRealtimeRows;
|
|
|
use App\Services\BetService;
|
|
use App\Services\BetService;
|
|
|
|
|
+use App\Services\LotteryOdds;
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
use Illuminate\Foundation\Testing\TestCase;
|
|
use Illuminate\Foundation\Testing\TestCase;
|
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\Request;
|
|
@@ -32,7 +36,9 @@ class LotteryBetSourceTest extends TestCase
|
|
|
DB::statement('CREATE TABLE bot_users (id INTEGER PRIMARY KEY, member_id TEXT, first_name TEXT, "from" INTEGER, is_banned INTEGER)');
|
|
DB::statement('CREATE TABLE bot_users (id INTEGER PRIMARY KEY, member_id TEXT, first_name TEXT, "from" INTEGER, is_banned INTEGER)');
|
|
|
DB::statement('CREATE TABLE bot_wallets (id INTEGER PRIMARY KEY, member_id TEXT, available_balance NUMERIC, updated_at TEXT)');
|
|
DB::statement('CREATE TABLE bot_wallets (id INTEGER PRIMARY KEY, member_id TEXT, available_balance NUMERIC, updated_at TEXT)');
|
|
|
DB::statement('CREATE TABLE bot_config (id INTEGER PRIMARY KEY, field TEXT, val TEXT)');
|
|
DB::statement('CREATE TABLE bot_config (id INTEGER PRIMARY KEY, field TEXT, val TEXT)');
|
|
|
- DB::statement('CREATE TABLE bot_gameplay_rules (id INTEGER PRIMARY KEY, keywords TEXT, odds NUMERIC, mininum NUMERIC, maxinum NUMERIC)');
|
|
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_gameplay_rules (id INTEGER PRIMARY KEY, keywords TEXT, groups TEXT, odds NUMERIC, mininum NUMERIC, maxinum NUMERIC, created_at TEXT, updated_at TEXT)');
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_jisu_gameplay (id INTEGER PRIMARY KEY, type INTEGER, gameplay TEXT, number TEXT, odds TEXT, mininum INTEGER, maxinum INTEGER)');
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_lhc_number (id INTEGER PRIMARY KEY, game TEXT, gameplay TEXT, number TEXT, odds TEXT, mininum INTEGER, maxinum INTEGER)');
|
|
|
DB::statement('CREATE TABLE bot_keyboard (id INTEGER PRIMARY KEY, button TEXT)');
|
|
DB::statement('CREATE TABLE bot_keyboard (id INTEGER PRIMARY KEY, button TEXT)');
|
|
|
foreach (['issues', 'pc_issues'] as $table) {
|
|
foreach (['issues', 'pc_issues'] as $table) {
|
|
|
DB::statement("CREATE TABLE bot_{$table} (id INTEGER PRIMARY KEY, issue_no TEXT, status INTEGER, end_time TEXT, winning_numbers TEXT, combo TEXT)");
|
|
DB::statement("CREATE TABLE bot_{$table} (id INTEGER PRIMARY KEY, issue_no TEXT, status INTEGER, end_time TEXT, winning_numbers TEXT, combo TEXT)");
|
|
@@ -46,7 +52,13 @@ class LotteryBetSourceTest extends TestCase
|
|
|
|
|
|
|
|
DB::table('users')->insert(['member_id' => '1001', 'first_name' => 'Alice', 'from' => -1, 'is_banned' => 0]);
|
|
DB::table('users')->insert(['member_id' => '1001', 'first_name' => 'Alice', 'from' => -1, 'is_banned' => 0]);
|
|
|
DB::table('wallets')->insert(['member_id' => '1001', 'available_balance' => 100]);
|
|
DB::table('wallets')->insert(['member_id' => '1001', 'available_balance' => 100]);
|
|
|
- DB::table('gameplay_rules')->insert(['keywords' => '大', 'odds' => 2, 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
|
|
+ DB::table('gameplay_rules')->insert(['keywords' => '大', 'groups' => '大小单双', 'odds' => 2, 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
+ foreach (range(1, 7) as $type) {
|
|
|
|
|
+ DB::table('jisu_gameplay')->insert(['type' => $type, 'gameplay' => '第一球', 'number' => '大', 'odds' => '1.95', 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
+ }
|
|
|
|
|
+ DB::table('lhc_number')->insert(['game' => '特码', 'gameplay' => '号码', 'number' => '07', 'odds' => '48.0', 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_11_11_120000_create_lottery_odds_templates.php')->up();
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_11_11_160000_add_sort_to_lottery_odds_templates.php')->up();
|
|
|
DB::table('config')->insert([
|
|
DB::table('config')->insert([
|
|
|
['field' => 'service_customer', 'val' => 'test'],
|
|
['field' => 'service_customer', 'val' => 'test'],
|
|
|
['field' => 'maintenance_switch', 'val' => '0'],
|
|
['field' => 'maintenance_switch', 'val' => '0'],
|
|
@@ -71,6 +83,252 @@ class LotteryBetSourceTest extends TestCase
|
|
|
return $response['data'];
|
|
return $response['data'];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_odds_and_28_catalog_writes_require_a_visible_granted_button(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_menus (id INTEGER PRIMARY KEY, uri TEXT, type INTEGER, status INTEGER,
|
|
|
|
|
+ parent_id INTEGER, title TEXT, permission_name TEXT, created_at TEXT, updated_at TEXT)');
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_roles (id INTEGER PRIMARY KEY, name TEXT)');
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_role_user (id INTEGER PRIMARY KEY, role_id INTEGER, user_id INTEGER)');
|
|
|
|
|
+ DB::statement('CREATE TABLE bot_role_menu (id INTEGER PRIMARY KEY, role_id INTEGER, menu_id INTEGER)');
|
|
|
|
|
+ DB::table('roles')->insert(['id' => 5, 'name' => 'operator']);
|
|
|
|
|
+ DB::table('role_user')->insert(['role_id' => 5, 'user_id' => 7]);
|
|
|
|
|
+
|
|
|
|
|
+ $check = function (string $path, array $input = [], int $userId = 7): int {
|
|
|
|
|
+ $request = Request::create($path, 'POST', $input);
|
|
|
|
|
+ $request->user = (object) ['id' => $userId];
|
|
|
|
|
+ $route = $this->app['router']->getRoutes()->match($request);
|
|
|
|
|
+ $request->setRouteResolver(fn () => $route);
|
|
|
|
|
+ $this->assertContains('admin.jwt', $route->middleware());
|
|
|
|
|
+ $this->assertContains('check.button.uri', $route->middleware());
|
|
|
|
|
+ return (new CheckButtonPermission())->handle($request, fn () => response()->json(['code' => 0]))->getData(true)['code'];
|
|
|
|
|
+ };
|
|
|
|
|
+ $odds = '/admin/jisuGame/setOdds';
|
|
|
|
|
+ $templates = '/admin/jisuGame/saveTemplate';
|
|
|
|
|
+ $lhc = ['game' => 'lhc'];
|
|
|
|
|
+ foreach ([[$odds, $lhc], [$templates, $lhc], [$odds, ['game' => 'canada28']], [$odds, []],
|
|
|
|
|
+ ['/admin/gameplayRule/submit', []], ['/admin/gameplayRule/delete', []]] as [$route, $input]) {
|
|
|
|
|
+ $this->assertSame(-1, $check($route, $input), $route . ' must reject missing permission');
|
|
|
|
|
+ $this->assertSame(0, $check($route, $input, 1));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $button = ['uri' => 'admin/lhcNumber/setOdds', 'type' => 2];
|
|
|
|
|
+ $hidden = DB::table('menus')->insertGetId($button + ['status' => 2]);
|
|
|
|
|
+ DB::table('role_menu')->insert(['role_id' => 5, 'menu_id' => $hidden]);
|
|
|
|
|
+ $this->assertSame(-1, $check($odds, $lhc));
|
|
|
|
|
+ $visible = DB::table('menus')->insertGetId($button + ['status' => 1]);
|
|
|
|
|
+ $this->assertSame(-1, $check($templates, $lhc), 'A visible duplicate does not grant a hidden button');
|
|
|
|
|
+ DB::table('role_menu')->insert(['role_id' => 5, 'menu_id' => $visible]);
|
|
|
|
|
+ $this->assertSame(0, $check($templates . '?game=jisu', $lhc));
|
|
|
|
|
+ $this->assertSame(-1, $check($odds . '?game=lhc', ['game' => 'jisu28']));
|
|
|
|
|
+ $this->assertSame(-1, $check($odds, ['game' => ['lhc']]));
|
|
|
|
|
+ $this->assertSame(-1, $check($odds));
|
|
|
|
|
+
|
|
|
|
|
+ $jisu = DB::table('menus')->insertGetId(['uri' => 'admin/jisuGame/setOdds', 'type' => 2, 'status' => 1]);
|
|
|
|
|
+ DB::table('role_menu')->insert(['role_id' => 5, 'menu_id' => $jisu]);
|
|
|
|
|
+ $this->assertSame(0, $check($odds), 'Authorized legacy Jisu requests may omit the game');
|
|
|
|
|
+ $pc28 = DB::table('menus')->insertGetId(['uri' => 'admin/gameplayRule/submit', 'type' => 2, 'status' => 1]);
|
|
|
|
|
+ DB::table('role_menu')->insert(['role_id' => 5, 'menu_id' => $pc28]);
|
|
|
|
|
+ $this->assertSame(0, $check($templates, ['game' => 'jisu28']));
|
|
|
|
|
+ $this->assertSame(0, $check('/admin/gameplayRule/submit'));
|
|
|
|
|
+ $this->assertSame(-1, $check('/admin/gameplayRule/delete'), 'Deletion requires its own grant');
|
|
|
|
|
+
|
|
|
|
|
+ $migration = require dirname(__DIR__, 2) . '/database/migrations/2026_11_11_150000_register_lottery_odds_write_permissions.php';
|
|
|
|
|
+ $migration->up();
|
|
|
|
|
+ $migration->up();
|
|
|
|
|
+ $deleteButtons = DB::table('menus')->where('uri', 'admin/gameplayRule/delete')->get();
|
|
|
|
|
+ $this->assertCount(1, $deleteButtons);
|
|
|
|
|
+ $this->assertEquals(0, $deleteButtons[0]->parent_id, 'Older installations can grant the button without the page menu');
|
|
|
|
|
+ $this->assertEquals(2, DB::table('menus')->where('id', $hidden)->value('status'));
|
|
|
|
|
+ $this->assertSame(-1, $check('/admin/gameplayRule/delete'), 'Provisioning does not grant a role permission');
|
|
|
|
|
+ DB::table('role_menu')->insert(['role_id' => 5, 'menu_id' => $deleteButtons[0]->id]);
|
|
|
|
|
+ $this->assertSame(0, $check('/admin/gameplayRule/delete'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_odds_templates_copy_and_edit_only_the_selected_game(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $this->assertSame(13, DB::table('lottery_odds_templates')->count());
|
|
|
|
|
+ foreach (LotteryOdds::gameKeys() as $key) {
|
|
|
|
|
+ $template = LotteryOdds::template($key);
|
|
|
|
|
+ $actual = LotteryOdds::items($template->id)->orderBy('item_id')->get();
|
|
|
|
|
+ $legacy = LotteryOdds::catalog($key)->orderBy('id')->get(['id', 'odds', 'mininum', 'maxinum']);
|
|
|
|
|
+ $this->assertSame($legacy->pluck('id')->all(), $actual->pluck('item_id')->all());
|
|
|
|
|
+ foreach (['odds', 'mininum', 'maxinum'] as $field) {
|
|
|
|
|
+ $this->assertEquals($legacy->pluck($field)->all(), $actual->pluck($field)->all());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $scope = ['game' => 'lhc', 'type' => 3];
|
|
|
|
|
+ $call = function (string $action, array $input) {
|
|
|
|
|
+ $this->app->instance('request', Request::create("/admin/jisuGame/{$action}", $action === 'list' ? 'GET' : 'POST', $input));
|
|
|
|
|
+ return (new JisuGame())->{$action}()->getData(true);
|
|
|
|
|
+ };
|
|
|
|
|
+ $created = $call('saveTemplate', $scope + ['names' => ['zh' => '测试', 'en' => 'Test']]);
|
|
|
|
|
+ $this->assertSame(0, $created['code'], $created['msg']);
|
|
|
|
|
+ $template = $created['data'];
|
|
|
|
|
+ $this->assertFalse($template['enabled']);
|
|
|
|
|
+ $selection = ['odds_template_id' => $template['id']];
|
|
|
|
|
+ $prices = ['group_game' => '特码', 'gameplay' => '号码', 'odds' => '49', 'mininum' => '2', 'maxinum' => '200'];
|
|
|
|
|
+ $this->assertNotSame(0, $call('setOdds', ['game' => 'lhc', 'type' => 2] + $selection + $prices)['code']);
|
|
|
|
|
+ $this->assertSame(0, $call('setOdds', $scope + $selection + $prices)['code']);
|
|
|
|
|
+ $enabled = $call('saveTemplate', $scope + $selection + ['enabled' => true, 'names' => ['zh' => '澳门盘']]);
|
|
|
|
|
+ $this->assertSame(['zh' => '澳门盘'], $enabled['data']['names']);
|
|
|
|
|
+ $this->assertTrue($enabled['data']['enabled']);
|
|
|
|
|
+ $this->assertGreaterThan($template['revision'], $enabled['data']['revision']);
|
|
|
|
|
+ $this->assertSame('49', $call('list', $scope + $selection)['data']['data'][0]['children'][0]['children'][0]['odds']);
|
|
|
|
|
+ $this->assertSame('48.0', $call('list', $scope)['data']['data'][0]['children'][0]['children'][0]['odds']);
|
|
|
|
|
+ $this->assertSame('48.0', $call('list', ['game' => 'lhc', 'type' => 2])['data']['data'][0]['children'][0]['children'][0]['odds']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_new_plays_stay_unpriced_until_the_selected_template_is_saved(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $draft = LotteryOdds::saveTemplate('lhc:2', ['names' => ['zh' => '香港测试']]);
|
|
|
|
|
+ $jisu = LotteryOdds::template('jisu:2');
|
|
|
|
|
+ $hongKong = LotteryOdds::template('lhc:2');
|
|
|
|
|
+ $newJisu = DB::table('jisu_gameplay')->insertGetId([
|
|
|
|
|
+ 'type' => 2, 'gameplay' => '后三', 'number' => '杂六', 'odds' => '2.8', 'mininum' => 10, 'maxinum' => 500,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $newMarkSix = DB::table('lhc_number')->insertGetId([
|
|
|
|
|
+ 'game' => '特码', 'gameplay' => '号码', 'number' => '08', 'odds' => '47', 'mininum' => 2, 'maxinum' => 300,
|
|
|
|
|
+ ]);
|
|
|
|
|
+ $this->assertSame([
|
|
|
|
|
+ 'id' => $newJisu, 'name' => '杂六', 'configured' => false, 'odds' => null, 'mininum' => null, 'maxinum' => null,
|
|
|
|
|
+ ], LotteryOdds::list('jisu:2', null)['data'][1]['children'][0]);
|
|
|
|
|
+ $markSixItems = LotteryOdds::list('lhc:2', $draft['id'])['data'][0]['children'][0]['children'];
|
|
|
|
|
+ $this->assertTrue($markSixItems[0]['configured']);
|
|
|
|
|
+ $this->assertFalse($markSixItems[1]['configured']);
|
|
|
|
|
+ $this->assertNull($markSixItems[1]['odds']);
|
|
|
|
|
+ $this->assertSame([$markSixItems[0]['id']], LotteryOdds::pricedCatalog('lhc:2', $draft['id'])->pluck('id')->all());
|
|
|
|
|
+ $this->assertSame($jisu->revision, LotteryOdds::template('jisu:2')->revision);
|
|
|
|
|
+
|
|
|
|
|
+ $fresh = LotteryOdds::saveTemplate('lhc:2', ['names' => ['zh' => '香港新模板']]);
|
|
|
|
|
+ $this->assertFalse(LotteryOdds::items($fresh['id'])->where('item_id', $newMarkSix)->exists());
|
|
|
|
|
+ LotteryOdds::setOdds('jisu:2', null, ['id' => $newJisu, 'odds' => '2.9', 'mininum' => 3, 'maxinum' => 400]);
|
|
|
|
|
+ LotteryOdds::setOdds('lhc:2', $draft['id'], [
|
|
|
|
|
+ 'group_game' => '特码', 'gameplay' => '号码', 'odds' => '49', 'mininum' => 5, 'maxinum' => 200,
|
|
|
|
|
+ ]);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertSame('2.9', LotteryOdds::items($jisu->id)->where('item_id', $newJisu)->value('odds'));
|
|
|
|
|
+ $this->assertFalse(LotteryOdds::items(LotteryOdds::template('jisu:3')->id)->where('item_id', $newJisu)->exists());
|
|
|
|
|
+ $this->assertSame($jisu->revision + 1, LotteryOdds::template('jisu:2')->revision);
|
|
|
|
|
+ $this->assertSame(['49', '49'], LotteryOdds::items($draft['id'])->orderBy('item_id')->pluck('odds')->all());
|
|
|
|
|
+ $this->assertSame($draft['revision'] + 1, LotteryOdds::template('lhc:2', $draft['id'])->revision);
|
|
|
|
|
+ $this->assertFalse(LotteryOdds::items($hongKong->id)->where('item_id', $newMarkSix)->exists());
|
|
|
|
|
+ $this->assertFalse(LotteryOdds::items(LotteryOdds::template('lhc:3')->id)->where('item_id', $newMarkSix)->exists());
|
|
|
|
|
+ $this->assertSame('48.0', LotteryOdds::items($hongKong->id)->where('item_id', 1)->value('odds'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_equivalent_enabled_values_do_not_invalidate_quotes(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $default = LotteryOdds::template('lhc:2');
|
|
|
|
|
+ $draft = LotteryOdds::saveTemplate('lhc:2', ['names' => ['zh' => '香港测试']]);
|
|
|
|
|
+ foreach ([true, 1, '1'] as $value) {
|
|
|
|
|
+ $this->assertSame($default->revision, LotteryOdds::saveTemplate('lhc:2', [
|
|
|
|
|
+ 'odds_template_id' => $default->id, 'enabled' => $value,
|
|
|
|
|
+ ])['revision']);
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach ([false, 0, '0'] as $value) {
|
|
|
|
|
+ $this->assertSame($draft['revision'], LotteryOdds::saveTemplate('lhc:2', [
|
|
|
|
|
+ 'odds_template_id' => $draft['id'], 'enabled' => $value,
|
|
|
|
|
+ ])['revision']);
|
|
|
|
|
+ }
|
|
|
|
|
+ $this->assertSame($draft['revision'] + 1, LotteryOdds::saveTemplate('lhc:2', [
|
|
|
|
|
+ 'odds_template_id' => $draft['id'], 'enabled' => '1',
|
|
|
|
|
+ ])['revision']);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_28_catalog_add_rename_and_delete_update_every_template(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ $extra = LotteryOdds::saveTemplate('jisu28', ['names' => ['zh' => '测试']]);
|
|
|
|
|
+ $setRequest = fn ($input) => $this->app->instance('request', Request::create('/admin/gameplayRule', 'POST', $input));
|
|
|
|
|
+ $setRequest(['keywords' => '小', 'groups' => '大小单双', 'odds' => '1.95', 'mininum' => 1, 'maxinum' => 20]);
|
|
|
|
|
+ $this->assertSame(0, (new GameplayRule())->store()->getData(true)['code']);
|
|
|
|
|
+ $itemId = DB::table('gameplay_rules')->where('keywords', '小')->value('id');
|
|
|
|
|
+ $templates = [LotteryOdds::template('canada28')->id, LotteryOdds::template('jisu28')->id, $extra['id']];
|
|
|
|
|
+ foreach ($templates as $id) {
|
|
|
|
|
+ $this->assertSame('1.95', LotteryOdds::items($id)->where('item_id', $itemId)->value('odds'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ $setRequest(['id' => $itemId, 'keywords' => '小单', 'groups' => '大小单双']);
|
|
|
|
|
+ $this->assertSame(0, (new GameplayRule())->store()->getData(true)['code']);
|
|
|
|
|
+ $this->assertSame('小单', DB::table('gameplay_rules')->where('id', $itemId)->value('keywords'));
|
|
|
|
|
+ $this->assertSame($extra['revision'] + 2, LotteryOdds::template('jisu28', $extra['id'])->revision);
|
|
|
|
|
+
|
|
|
|
|
+ $setRequest(['id' => $itemId]);
|
|
|
|
|
+ $this->assertSame(0, (new GameplayRule())->destroy()->getData(true)['code']);
|
|
|
|
|
+ $this->assertFalse(DB::table('lottery_odds_items')->whereIn('template_id', $templates)->where('item_id', $itemId)->exists());
|
|
|
|
|
+ $this->assertTrue(LotteryOdds::items(LotteryOdds::template('jisu:2')->id)->where('item_id', $itemId)->exists());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_telegram_uses_the_selected_default_regardless_of_template_sort(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_11_06_130000_add_bet_source_to_lhc_order.php')->up();
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_10_26_120000_create_maintenance_settings.php')->up();
|
|
|
|
|
+ $original = LotteryOdds::template('canada28');
|
|
|
|
|
+ $jisu = LotteryOdds::template('jisu28');
|
|
|
|
|
+ $save = function (array $input) {
|
|
|
|
|
+ $this->app->instance('request', Request::create('/admin/jisuGame/saveTemplate', 'POST', ['game' => 'canada28'] + $input));
|
|
|
|
|
+ return (new JisuGame())->saveTemplate()->getData(true);
|
|
|
|
|
+ };
|
|
|
|
|
+ $created = $save(['names' => ['zh' => '新模板'], 'sort' => 10]);
|
|
|
|
|
+ $this->assertSame(0, $created['code'], $created['msg']);
|
|
|
|
|
+ $alternate = $created['data'];
|
|
|
|
|
+ $this->assertFalse($alternate['enabled']);
|
|
|
|
|
+ $this->assertSame(10, $alternate['sort']);
|
|
|
|
|
+ $select = ['odds_template_id' => $alternate['id']];
|
|
|
|
|
+ LotteryOdds::setOdds('canada28', $alternate['id'], ['id' => 1, 'odds' => '3.25', 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
+ $this->assertNotSame(0, $save($select + ['make_default' => true])['code']);
|
|
|
|
|
+ $this->assertNotSame(0, $save(['odds_template_id' => $original->id, 'enabled' => false])['code']);
|
|
|
|
|
+ $originalList = LotteryOdds::list('canada28', null);
|
|
|
|
|
+ $this->assertSame([$alternate['id'], $original->id], array_column($originalList['odds_templates'], 'id'));
|
|
|
|
|
+ $this->assertSame($original->id, $originalList['odds_template_id']);
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大10')['text']);
|
|
|
|
|
+
|
|
|
|
|
+ $this->assertSame(0, $save($select + ['enabled' => true])['code']);
|
|
|
|
|
+ $revision = LotteryOdds::template('canada28', $alternate['id'])->revision;
|
|
|
|
|
+ $result = $save($select + ['make_default' => true, 'sort' => 2]);
|
|
|
|
|
+ $this->assertSame(0, $result['code'], $result['msg']);
|
|
|
|
|
+ $this->assertTrue($result['data']['is_default']);
|
|
|
|
|
+ $this->assertSame($revision, $result['data']['revision']);
|
|
|
|
|
+ $this->assertSame(1, DB::table('lottery_odds_templates')->where('game_key', 'canada28')->where('is_default', 1)->count());
|
|
|
|
|
+ $this->assertSame($jisu->id, LotteryOdds::template('jisu28')->id);
|
|
|
|
|
+ $this->assertSame(0, $save(['odds_template_id' => $original->id, 'enabled' => false])['code']);
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大10')['text']);
|
|
|
|
|
+ $orders = DB::table('lhc_order')->orderBy('id')->get();
|
|
|
|
|
+ $this->assertEquals([2, 3.25], $orders->pluck('odds')->all());
|
|
|
|
|
+ $this->assertSame([$original->id, $alternate['id']], $orders->pluck('odds_template_id')->all());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ #[RunInSeparateProcess]
|
|
|
|
|
+ #[PreserveGlobalState(false)]
|
|
|
|
|
+ public function test_telegram_default_price_changes_create_a_separate_order(): void
|
|
|
|
|
+ {
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_11_06_130000_add_bet_source_to_lhc_order.php')->up();
|
|
|
|
|
+ (require dirname(__DIR__, 2) . '/database/migrations/2026_10_26_120000_create_maintenance_settings.php')->up();
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大10')['text']);
|
|
|
|
|
+ LotteryOdds::setOdds('canada28', null, ['id' => 1, 'odds' => '2.50', 'mininum' => 1, 'maxinum' => 100]);
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大15')['text']);
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大20')['text']);
|
|
|
|
|
+ DB::table('config')->where('field', 'pc28_switch')->update(['val' => '1']);
|
|
|
|
|
+ $this->assertStringContainsString('下注成功', BetService::bet('1001', '大5')['text']);
|
|
|
|
|
+ $orders = DB::table('lhc_order')->orderBy('id')->get();
|
|
|
|
|
+ $this->assertEquals([2, 2.5, 2], $orders->pluck('odds')->all());
|
|
|
|
|
+ $this->assertEquals([10, 35, 5], $orders->pluck('total_amount')->all());
|
|
|
|
|
+ $this->assertSame([1, 2, 1], $orders->pluck('odds_template_revision')->all());
|
|
|
|
|
+ $this->assertEquals(50, DB::table('wallets')->value('available_balance'));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
#[RunInSeparateProcess]
|
|
#[RunInSeparateProcess]
|
|
|
#[PreserveGlobalState(false)]
|
|
#[PreserveGlobalState(false)]
|
|
|
public function test_orders_are_tagged_and_telegram_merges_only_its_own_bets(): void
|
|
public function test_orders_are_tagged_and_telegram_merges_only_its_own_bets(): void
|