instance('config', new Repository(['app' => ['timezone' => 'Asia/Shanghai', 'url' => 'http://x']])); Facade::setFacadeApplication($app); $db = new Manager($app); $db->addConnection(['driver' => 'sqlite', 'database' => ':memory:', 'prefix' => 'bot_']); $db->setAsGlobal(); $db->bootEloquent(); $app->instance('db', $db->getDatabaseManager()); $app->bind('db.schema', fn () => $db->schema()); $schema = $db->schema(); $schema->create('users', function (Blueprint $t) { $t->id(); $t->string('member_id'); $t->string('account')->nullable(); $t->string('username')->nullable(); $t->string('first_name')->nullable(); $t->string('admin_note')->nullable(); $t->integer('status')->default(0); $t->string('phone')->nullable(); $t->string('visitor_id')->nullable(); $t->string('register_ip')->nullable(); $t->timestamps(); }); $schema->create('rebates', function (Blueprint $t) { $t->id(); $t->string('member_id'); $t->date('date'); $t->integer('status')->default(0); $t->decimal('betting_amount', 20, 2)->default(0); $t->timestamps(); }); $schema->create('backflow', function (Blueprint $t) { $t->id(); $t->string('member_id'); $t->string('date'); $t->integer('status')->default(0); $t->decimal('amount', 20, 2)->default(0); $t->decimal('granted_amount', 20, 2)->default(0); $t->timestamps(); }); $schema->create('recharges', function (Blueprint $t) { $t->id(); $t->string('member_id'); $t->string('coin')->default('CNY'); $t->decimal('amount', 20, 2)->default(0); $t->integer('status')->default(0); $t->timestamps(); }); DB::table('users')->insert([ ['member_id' => 'm1', 'account' => 'alice'], ['member_id' => 'm2', 'account' => 'bob'], ['member_id' => 'm3', 'account' => null], ]); } protected function tearDown(): void { DB::disconnect(); Facade::clearResolvedInstances(); parent::tearDown(); } public function test_rebate_list_shows_and_filters_account(): void { foreach (['m1', 'm2', 'm3'] as $m) { DB::table('rebates')->insert(['member_id' => $m, 'date' => '2026-01-01']); } $rows = $this->accounts(RebateService::paginate(['limit' => 10])['data']); $this->assertSame(['m1' => 'alice', 'm2' => 'bob', 'm3' => ''], $rows); $this->assertSame(['m1' => 'alice'], $this->accounts(RebateService::paginate(['account' => 'lic'])['data'])); $this->assertSame(0, RebateService::paginate(['account' => 'nobody'])['total']); } public function test_rebate_list_shows_the_current_day_but_only_past_unpaid_days_can_be_granted(): void { \Carbon\Carbon::setTestNow(\Carbon\Carbon::parse('2026-11-05 15:00:00', 'Asia/Shanghai')); // 纽约 2026-11-05 02:00 try { DB::table('rebates')->insert([ ['member_id' => 'm1', 'date' => '2026-11-05', 'status' => 0], ['member_id' => 'm2', 'date' => '2026-11-04', 'status' => 0], ['member_id' => 'm3', 'date' => '2026-11-04', 'status' => 1], ]); $rows = []; foreach (json_decode(json_encode(RebateService::paginate(['limit' => 10])['data']), true) as $row) { $rows[$row['member_id']] = [$row['date'], $row['can_grant']]; } $this->assertSame(['m1' => ['2026-11-05', false], 'm2' => ['2026-11-04', true], 'm3' => ['2026-11-04', false]], $rows); } finally { \Carbon\Carbon::setTestNow(); } } public function test_backflow_list_shows_and_filters_account(): void { foreach (['m1', 'm2'] as $m) { DB::table('backflow')->insert(['member_id' => $m, 'date' => '2026-01']); } $this->assertSame(['m1' => 'alice', 'm2' => 'bob'], $this->accounts(BackflowService::paginate(['limit' => 10])['data'])); $this->assertSame(['m2' => 'bob'], $this->accounts(BackflowService::paginate(['limit' => 10, 'account' => 'bo'])['data'])); } public function test_backflow_list_shows_granted_pending_and_whether_more_can_be_granted(): void { \Carbon\Carbon::setTestNow(\Carbon\Carbon::parse('2026-11-05 15:00:00', 'Asia/Shanghai')); try { DB::table('backflow')->insert([ ['member_id' => 'm1', 'date' => '2026-11', 'status' => 0, 'amount' => 8, 'granted_amount' => 0], // 当月未发 ['member_id' => 'm2', 'date' => '2026-11', 'status' => 2, 'amount' => 50, 'granted_amount' => 8], // 当月部分发放,可补发 ['member_id' => 'm3', 'date' => '2026-11', 'status' => 2, 'amount' => 8, 'granted_amount' => 8], // 当月已发完,暂无差额 ['member_id' => 'm1', 'date' => '2026-10', 'status' => 0, 'amount' => 0, 'granted_amount' => 0], // 往月未结清 ['member_id' => 'm2', 'date' => '2026-10', 'status' => 1, 'amount' => 35, 'granted_amount' => 35], // 已发放 ['member_id' => 'm1', 'date' => '2026-12', 'status' => 0, 'amount' => 0, 'granted_amount' => 0], // 未来月份不展示 ]); $rows = []; foreach (json_decode(json_encode(BackflowService::paginate(['limit' => 10])['data']), true) as $row) { $rows[$row['member_id'] . '|' . $row['date']] = [$row['granted_amount'], $row['pending_amount'], $row['can_grant'], $row['status_text']]; } ksort($rows); $this->assertSame([ 'm1|2026-10' => ['0.00', '0.00', true, '未发放'], 'm1|2026-11' => ['0.00', '8.00', true, '未发放'], 'm2|2026-10' => ['35.00', '0.00', false, '已发放'], 'm2|2026-11' => ['8.00', '42.00', true, '部分发放'], 'm3|2026-11' => ['8.00', '0.00', false, '部分发放'], ], $rows); $this->assertSame(2, BackflowService::paginate(['limit' => 10, 'status' => 2])['total']); } finally { \Carbon\Carbon::setTestNow(); } } public function test_recharge_list_shows_and_filters_account(): void { foreach (['m1', 'm2'] as $m) { DB::table('recharges')->insert(['member_id' => $m, 'amount' => 1, 'created_at' => '2026-01-01 00:00:00']); } $this->assertSame(['m1' => 'alice', 'm2' => 'bob'], $this->accounts(RechargeService::paginate([])['data'])); $this->assertSame(['m1' => 'alice'], $this->accounts(RechargeService::paginate(['account' => 'ALI'])['data'])); } private function accounts(array $rows): array { $out = []; foreach (json_decode(json_encode($rows), true) as $row) { $out[$row['member_id']] = $row['account']; } ksort($out); return $out; } }