firstWhere('slug', 'billing-transactions')['pages']; $receivingTabs = collect($pages)->firstWhere('slug', 'store-receiving-bills')['tabs']; $marketingTabs = collect($pages)->firstWhere('slug', 'marketing-account-bills')['tabs']; $this->assertNotContains('promotion-marketing', array_column($receivingTabs, 'slug')); $this->assertSame('promotion-marketing', $marketingTabs[0]['slug'] ?? null); $this->assertSame('推广费(营销账户)', $marketingTabs[0]['title'] ?? null); $this->assertSame('taobao-alipay', $marketingTabs[1]['slug'] ?? null); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'billing-transactions', 'page' => 'marketing-account-bills', 'tab' => 'promotion-marketing', ])) ->assertOk() ->assertSeeText('推广费(营销账户)') ->assertSee('class="business-blank-page"', false); } public function test_promotion_marketing_page_and_details_share_contract(): void { $repository = Mockery::mock(PromotionMarketingExpenseRepository::class); $result = [ 'rows' => [[ 'id' => 'row-1', 'store_name' => '测试推广店', 'occurred_at' => '2026-10-23 09:00:00', 'notes' => '商品推广', 'income' => 2.66, 'expense' => 12.34, 'balance' => -9.68, ]], 'total' => 1, 'current_page' => 1, 'last_page' => 1, 'per_page' => 20, 'summary' => ['income' => 2.66, 'expense' => 12.34, 'balance' => -9.68, 'count' => 1], 'platform_summary' => [['platform' => '淘系', 'amount' => 12.34]], ]; $repository->shouldReceive('paginate')->once()->ordered()->with([ 'start' => '', 'end' => '', 'store_name' => '', 'note' => '', ], 1, 10)->andReturn($result); $repository->shouldReceive('storeSummary')->once()->ordered()->with([ 'start' => '2026-10-01', 'end' => '2026-10-31', 'store_name' => '', 'note' => '推广', ])->andReturn([ 'store_summary' => [[ 'platform' => '淘系', 'store_name' => '测试推广店', 'amount' => 12.34, ]], 'platform_summary' => [['platform' => '淘系', 'amount' => 12.34]], 'total' => 12.34, ]); $this->app->instance(PromotionMarketingExpenseRepository::class, $repository); $this->loginAs() ->getJson(route('ecommerce-finance.account-bills.index', [ 'bill_type' => 'promotion-marketing', ])) ->assertOk() ->assertJsonPath('total', 1) ->assertJsonPath('summary.income', 2.66) ->assertJsonPath('summary.expense', 12.34) ->assertJsonPath('summary.balance', -9.68) ->assertJsonPath('columns.title', '推广费(营销账户)') ->assertJsonPath('data.0.store_name', '测试推广店') ->assertJsonPath('data.0.income', 2.66) ->assertJsonPath('data.0.expense', 12.34) ->assertJsonPath('data.0.balance', -9.68) ->assertJsonPath('columns.columns.0.label', '店铺名称') ->assertJsonPath('columns.columns.1.label', '交易时间') ->assertJsonPath('columns.columns.2.label', '备注') ->assertJsonPath('columns.columns.3.label', '收入金额') ->assertJsonPath('columns.columns.4.label', '支出金额') ->assertJsonPath('columns.columns.5.label', '余额'); $this->loginAs() ->getJson(route('ecommerce-finance.account-bills.promotion-expense-details', [ 'bill_type' => 'promotion-marketing', 'start' => '2026-10-01', 'end' => '2026-10-31', 'note' => '推广', ])) ->assertOk() ->assertJsonPath('total', 1) ->assertJsonPath('summary.expense', 12.34) ->assertJsonPath('summary.count', 1) ->assertJsonPath('platform_summary.0.platform', '淘系') ->assertJsonPath('store_summary.0.platform', '淘系') ->assertJsonPath('store_summary.0.store_name', '测试推广店') ->assertJsonPath('store_summary.0.amount', 12.34); } public function test_taobao_alipay_tab_mounts_the_promotion_card_before_income(): void { $repository = Mockery::mock(TmallTaobaoSpreadBillRepository::class); $repository->shouldReceive('usesBusinessMirror')->andReturnTrue(); $repository->shouldReceive('paginate')->once()->andReturn(['rows' => [], 'total' => 0]); $repository->shouldReceive('summary')->once()->andReturn([ 'income_total' => 100, 'expense_total' => 0, 'net' => 100, 'count' => 1, ]); $repository->shouldReceive('storeOptions')->once()->andReturn([]); $this->app->instance(TmallTaobaoSpreadBillRepository::class, $repository); $response = $this->loginAs()->get(route('business.pages.show', [ 'section' => 'billing-transactions', 'page' => 'marketing-account-bills', 'tab' => 'taobao-alipay', ]))->assertOk(); $html = $response->getContent(); $promotionPosition = strpos($html, 'data-promotion-expense-summary'); $incomePosition = strpos($html, '收入合计(万元)'); $this->assertNotFalse($promotionPosition); $this->assertNotFalse($incomePosition); $this->assertLessThan($incomePosition, $promotionPosition); $response ->assertSee('public/js/business/pages.min.js', false) ->assertSee(route('ecommerce-finance.account-bills.index', [ 'bill_type' => 'promotion-marketing', ]), false); } public function test_promotion_marketing_store_options_come_from_the_same_date_range(): void { $repository = Mockery::mock(PromotionMarketingExpenseRepository::class); $repository->shouldReceive('storeOptions')->once()->with([ 'start' => '2026-10-01', 'end' => '2026-10-31', 'store_name' => '', 'note' => '', ])->andReturn(['测试推广店', '另一推广店']); $this->app->instance(PromotionMarketingExpenseRepository::class, $repository); $this->loginAs() ->getJson(route('ecommerce-finance.account-bills.filter-options', [ 'bill_type' => 'promotion-marketing', 'start' => '2026-10-01', 'end' => '2026-10-31', ])) ->assertOk() ->assertJsonPath('shops.0', '测试推广店') ->assertJsonPath('shops.1', '另一推广店'); } }