$t->integer('from')->nullable()); $this->joint = $this->agent(); $this->equity = $this->agent(Agent::TYPE_EQUITY); $ids = []; foreach (['m1' => [$this->joint->id, 1, '2026-09-01 08:00:00'], 'm2' => [null, 1, '2026-09-02 08:00:00'], 'demo' => [null, 2, '2026-09-02 09:00:00']] as $memberId => [$agentId, $from, $at]) { $ids[$memberId] = DB::table('users')->insertGetId(['member_id' => $memberId, 'username' => $memberId, 'agent_id' => $agentId, 'from' => $from, 'created_at' => $at]); } foreach ([['m1', '2026-09-01', 100, 2, -50, 5], ['m1', '2026-09-07', 50, 1, 10, 0], ['m2', '2026-09-02', 200, 3, 20, 0], ['m2', '2026-09-03', 0, 1, 0, 0], ['demo', '2026-09-02', 999, 9, 0, 0]] as [$m, $date, $deposit, $bets, $winLoss, $share]) { DB::table('member_daily_reports')->insert(['report_date' => $date, 'user_id' => $ids[$m], 'member_id' => $m, 'agent_id' => $m === 'm1' ? $this->joint->id : null, 'deposit_amount' => $deposit, 'bonus_amount' => $m === 'm2' && $date === '2026-09-02' ? 10 : 0, 'bet_count' => $bets, 'bet_amount' => $bets * 10, 'win_loss' => $winLoss, 'agent_share' => $share, 'categories' => '{}', 'created_at' => now(), 'updated_at' => '2026-09-07 11:50:00']); } DB::table('share_bet_facts')->insert(['source' => 't', 'source_id' => '1', 'user_id' => $ids['m2'], 'member_id' => 'm2', 'category' => 'self:lottery', 'bet_at' => '2026-09-02 10:00:00', 'bet_date' => '2026-09-02', 'settled_at' => '2026-09-02 10:05:00', 'bet_amount' => 30, 'effective_amount' => 30, 'net_profit' => 20, 'settled' => 1, 'voided' => 0]); } public function test_equity_shareholder_gets_platform_totals_by_week_without_demo_accounts(): void { $this->seed(); $report = (new AgentPeriodReportService())->report($this->equity, ['period' => 'week', 'start_date' => '2026-08-31', 'end_date' => '2026-09-07']); $this->assertSame(['platform', 'week', '2026-09-07 11:50:00'], [$report['scope'], $report['period'], $report['refreshed_at']]); $this->assertSame(['2026-W37', '2026-W36'], array_column($report['list'], 'period_key'), 'newest period first'); [$current, $previous] = $report['list']; $this->assertSame(['2026-09-07', '2026-09-07', '09-07 ~ 09-07'], [$current['start_date'], $current['end_date'], $current['label']]); $this->assertSame(['2026-08-31', '2026-09-06'], [$previous['start_date'], $previous['end_date']]); $this->assertSame(['300.0000', 6, 2, 2], [$previous['deposit_amount'], $previous['bet_count'], $previous['active_members'], $previous['new_members']], 'demo account excluded; m2 bet on two days but counts once'); $this->assertSame('290.0000', $previous['company_profit'], '300 deposit - 10 bonus'); $this->assertSame([['category' => 'self:lottery', 'name' => $previous['categories'][0]['name'], 'bet_count' => 1, 'bet_amount' => '30.0000', 'valid_bet_amount' => '30.0000', 'win_loss' => '20.0000']], $previous['categories']); $this->assertSame(['50.0000', 1], [$current['deposit_amount'], $current['active_members']]); $this->assertSame(['350.0000', 2, 7], [$report['totals']['deposit_amount'], $report['totals']['active_members'], $report['totals']['bet_count']]); $this->assertArrayNotHasKey('agent_share', $report['totals'], 'shareholders do not see joint-venture share'); } public function test_joint_agent_sees_own_members_by_day_and_month_with_share(): void { $this->seed(); $service = new AgentPeriodReportService(); $days = $service->report($this->joint, ['period' => 'day', 'start_date' => '2026-09-01', 'end_date' => '2026-09-02']); $this->assertSame('own', $days['scope']); $this->assertSame(['2026-09-02', '2026-09-01'], array_column($days['list'], 'period_key'), 'empty days are still listed'); $this->assertSame(['0.0000', 0], [$days['list'][0]['deposit_amount'], $days['list'][0]['new_members']]); $this->assertSame(['100.0000', '-50.0000', '5.0000', 1, 1], [$days['list'][1]['deposit_amount'], $days['list'][1]['win_loss'], $days['list'][1]['agent_share'], $days['list'][1]['active_members'], $days['list'][1]['new_members']]); $months = $service->report($this->joint, ['period' => 'month', 'start_date' => '2026-08-15', 'end_date' => '2026-09-07']); $this->assertSame(['2026-09', '2026-08'], array_column($months['list'], 'period_key')); $this->assertSame(['2026年09月', '2026-09-01', '150.0000'], [$months['list'][0]['label'], $months['list'][0]['start_date'], $months['list'][0]['deposit_amount']]); $this->assertSame('2026-08-15', $months['list'][1]['start_date'], 'first month is clipped to the query range'); foreach ([['period' => 'year'], ['end_date' => '2026-09-08'], ['start_date' => '2025-01-01', 'end_date' => '2026-09-07']] as $bad) { try { $service->report($this->joint, $bad); $this->fail(json_encode($bad)); } catch (\InvalidArgumentException) { $this->addToAssertionCount(1); } } } public function test_equity_agents_cannot_open_member_level_pages(): void { $this->seed(); $request = Request::create('/agent/members', 'GET'); $request->attributes->set('agent', $this->equity); $this->app->instance('request', $request); $data = (new MemberController())->dailyReport($request, new MemberDailyReportService())->getData(true); $this->assertSame('入股代理不能查看会员明细,请使用周期报表', $data['msg']); $this->assertSame('入股代理不能查看会员明细,请使用周期报表', (new MemberController())->index($request)->getData(true)['msg']); $request = Request::create('/agent/reports/period', 'GET', ['period' => 'month']); $request->attributes->set('agent', $this->equity); $this->app->instance('request', $request); $result = (new ReportController())->period($request, new AgentPeriodReportService())->getData(true); $this->assertSame(0, $result['code'], (string) $result['msg']); $this->assertSame('platform', $result['data']['scope']); } }