diff --git a/app/Http/Controllers/Business/Pages.php b/app/Http/Controllers/Business/Pages.php index 448419f3..2c3915fd 100644 --- a/app/Http/Controllers/Business/Pages.php +++ b/app/Http/Controllers/Business/Pages.php @@ -90,6 +90,12 @@ class Pages extends Controller protected const MARKETING_PLATFORMS = [ 'taobao-alipay', 'taobao-wechat', 'pinduoduo', 'jd-wallet', 'douyin', 'dewu', 'vipshop', + 'jd-promotion', 'douyin-promotion', 'dewu-promotion', 'vip-promotion', + ]; + + /** @var list 推广账户流水已合并到营销账户账单页的四个平台页签 */ + protected const PROMOTION_MARKETING_TABS = [ + 'jd-promotion', 'douyin-promotion', 'dewu-promotion', 'vip-promotion', ]; public function home() @@ -501,7 +507,6 @@ class Pages extends Controller 'supplier-payables-report' => $this->contentForSupplierPayablesReport(), 'payable-cloud-warehouse-vehicle-fee' => $this->contentForDingPayableWorkflows(), 'courier-surcharge' => $this->contentForCourierSurcharge(), - 'platform-promotion-accounts' => app(PlatformPromotionAccountPageData::class)->content($tab), default => null, }; } @@ -1071,11 +1076,11 @@ class Pages extends Controller $pageConfig = collect($sectionConfig['pages'] ?? [])->firstWhere('slug', $page); abort_if(empty($pageConfig), 403, '当前账号没有该页面权限。'); - if ($page === 'platform-promotion-accounts') { - return $this->exportPlatformPromotionAccounts($request); - } - if ($page === 'marketing-account-bills') { + if (in_array($tab, self::PROMOTION_MARKETING_TABS, true)) { + return $this->exportPlatformPromotionAccounts($request, $section, $page, $tab); + } + return $this->exportMarketingAccountBills($request, $section, $page, $tab); } @@ -1144,8 +1149,16 @@ class Pages extends Controller ]); } - private function exportPlatformPromotionAccounts(Request $request) + private function exportPlatformPromotionAccounts( + Request $request, + string $section = 'billing-transactions', + string $page = 'marketing-account-bills', + ?string $tab = null, + ) { + $platform = PlatformPromotionAccountPageData::platformForTab($tab); + abort_if($platform === null, 404); + $month = trim((string) $request->query('month', '')); $month = preg_match('/^\d{4}-\d{2}$/', $month) === 1 ? $month : null; $filters = [ @@ -1161,13 +1174,15 @@ class Pages extends Controller } catch (Throwable $exception) { report($exception); - return redirect()->route('business.pages.show', [ - 'section' => 'billing-transactions', - 'page' => 'platform-promotion-accounts', - ])->with('error', '推广账户数据导出暂时无法完成,请稍后重试。'); + return redirect()->route('business.pages.show', array_filter([ + 'section' => $section, + 'page' => $page, + 'tab' => $tab, + ], static fn (mixed $value): bool => $value !== null && $value !== '')) + ->with('error', '推广账户数据导出暂时无法完成,请稍后重试。'); } - return response()->streamDownload(function () use ($data): void { + return response()->streamDownload(function () use ($data, $platform): void { $csv = fopen('php://output', 'w'); fputs($csv, chr(0xEF) . chr(0xBB) . chr(0xBF)); fputcsv($csv, ['平台', '店铺/账户', '日期', '类型', '金额(元)', '余额(元)', '备注']); @@ -1184,12 +1199,17 @@ class Pages extends Controller ]); } }; - $emit('京东京准通', $data['jd'] ?? [], ['name' => fn ($row) => $row['shop_name'] . ' / ' . $row['account'], 'date' => fn ($row) => $row['show_date'] ?? $row['settle_datetime'], 'type' => fn ($row) => $row['trade_type_name'] ?? $row['in_out_type_name'], 'amount' => fn ($row) => $row['amount'] ?? '', 'balance' => fn ($row) => $row['balance_amount'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); - $emit('抖音千川', $data['dy'] ?? [], ['name' => fn ($row) => $row['shopName'] . ' / ' . $row['account'] . ' / ' . $row['qianchuanAavid'], 'date' => fn ($row) => $row['statDate'] ?? '', 'type' => fn () => '花费', 'amount' => fn ($row) => $row['cost'] ?? '', 'balance' => fn ($row) => $row['balance'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); - $emit('得物推广', $data['dw'] ?? [], ['name' => fn ($row) => $row['shop_name'] . ' / ' . $row['account'], 'date' => fn ($row) => $row['trade_date'] ?? $row['date_time'], 'type' => fn ($row) => $row['flow_type'] ?? '', 'amount' => fn ($row) => $row['trade_amount_yuan'] ?? '', 'balance' => fn ($row) => $row['balance_yuan'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); - $emit('VIP营销', $data['vipMarketing'] ?? [], ['name' => fn ($row) => $row['accountName'] . ' / ' . $row['advertiserId'], 'date' => fn ($row) => $row['dataMonth'], 'type' => fn () => '月度花费', 'amount' => fn ($row) => $row['totalCostYuan'] ?? '', 'balance' => fn () => '', 'remark' => fn ($row) => '曝光 ' . $row['totalImpressionCount']]); + if ($platform === 'jd') { + $emit('京东京准通', $data['jd'] ?? [], ['name' => fn ($row) => $row['shop_name'] . ' / ' . $row['account'], 'date' => fn ($row) => $row['show_date'] ?? $row['settle_datetime'], 'type' => fn ($row) => $row['trade_type_name'] ?? $row['in_out_type_name'], 'amount' => fn ($row) => $row['amount'] ?? '', 'balance' => fn ($row) => $row['balance_amount'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); + } elseif ($platform === 'douyin') { + $emit('抖音千川', $data['dy'] ?? [], ['name' => fn ($row) => $row['shopName'] . ' / ' . $row['account'] . ' / ' . $row['qianchuanAavid'], 'date' => fn ($row) => $row['statDate'] ?? '', 'type' => fn () => '花费', 'amount' => fn ($row) => $row['cost'] ?? '', 'balance' => fn ($row) => $row['balance'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); + } elseif ($platform === 'dewu') { + $emit('得物推广', $data['dw'] ?? [], ['name' => fn ($row) => $row['shop_name'] . ' / ' . $row['account'], 'date' => fn ($row) => $row['trade_date'] ?? $row['date_time'], 'type' => fn ($row) => $row['flow_type'] ?? '', 'amount' => fn ($row) => $row['trade_amount_yuan'] ?? '', 'balance' => fn ($row) => $row['balance_yuan'] ?? '', 'remark' => fn ($row) => $row['remark'] ?? '']); + } else { + $emit('VIP营销', $data['vipMarketing'] ?? [], ['name' => fn ($row) => $row['accountName'] . ' / ' . $row['advertiserId'], 'date' => fn ($row) => $row['dataMonth'], 'type' => fn () => '月度花费', 'amount' => fn ($row) => $row['totalCostYuan'] ?? '', 'balance' => fn () => '', 'remark' => fn ($row) => '曝光 ' . $row['totalImpressionCount']]); + } fclose($csv); - }, '平台推广账户流水_' . $filters['month'] . '.csv', [ + }, '店铺营销账户账单_' . $platform . '_' . $filters['month'] . '.csv', [ 'Content-Type' => 'text/csv; charset=UTF-8', ]); } @@ -2289,6 +2309,10 @@ class Pages extends Controller return null; } + if (in_array($tab, self::PROMOTION_MARKETING_TABS, true)) { + return app(PlatformPromotionAccountPageData::class)->content($tab); + } + // Alibaba 页面沿用历史 taobao-wechat 路由,数据来自 JianSun.dbo.alibaba_bill。 if ($tab === 'taobao-wechat') { $request = request(); diff --git a/config/business_navigation.php b/config/business_navigation.php index 6282e03d..c9468466 100644 --- a/config/business_navigation.php +++ b/config/business_navigation.php @@ -359,16 +359,10 @@ return [ ['slug' => 'douyin', 'title' => '抖音账户'], ['slug' => 'dewu', 'title' => '得物账户'], ['slug' => 'vipshop', 'title' => '唯品会账户'], - ], - ], - [ - 'slug' => 'platform-promotion-accounts', - 'title' => '平台推广账户流水', - 'tabs' => [ - ['slug' => 'jd', 'title' => '京东京准通'], - ['slug' => 'douyin', 'title' => '抖音千川'], - ['slug' => 'dewu', 'title' => '得物推广账户'], - ['slug' => 'vip', 'title' => 'VIP(唯品会)'], + ['slug' => 'jd-promotion', 'title' => '京东京准通'], + ['slug' => 'douyin-promotion', 'title' => '抖音千川'], + ['slug' => 'dewu-promotion', 'title' => '得物推广账户'], + ['slug' => 'vip-promotion', 'title' => '唯品会推广'], ], ], ['slug' => 'deposit-account-balance', 'title' => '店铺保证金账户余额'], diff --git a/modules/EcommerceFinance/View/PlatformPromotionAccountPageData.php b/modules/EcommerceFinance/View/PlatformPromotionAccountPageData.php index 889c21f4..7d1b80a9 100644 --- a/modules/EcommerceFinance/View/PlatformPromotionAccountPageData.php +++ b/modules/EcommerceFinance/View/PlatformPromotionAccountPageData.php @@ -10,12 +10,22 @@ use Throwable; class PlatformPromotionAccountPageData { + private const TAB_PLATFORMS = [ + 'jd-promotion' => 'jd', + 'douyin-promotion' => 'douyin', + 'dewu-promotion' => 'dewu', + 'vip-promotion' => 'vip', + ]; + public function __construct(private readonly PlatformPromotionAccountRepository $repository) { } public function content(?string $tab = null): array { + $platform = self::platformForTab($tab); + abort_if($platform === null, 404); + $requestedMonth = $this->month(request('month')); $month = $requestedMonth ?: now()->format('Y-m'); $filters = [ @@ -23,8 +33,6 @@ class PlatformPromotionAccountPageData 'shop_name' => $this->text(request('shop_name')), 'account' => $this->text(request('account')), ]; - $tab = in_array($tab, ['jd', 'douyin', 'dewu', 'vip'], true) ? $tab : 'jd'; - try { if ($requestedMonth === '') { $month = $this->repository->latestMonth() ?: $month; @@ -33,19 +41,21 @@ class PlatformPromotionAccountPageData $data = $this->repository->dashboard($filters, 5000); return [ - 'view' => 'business.pages.billing-transactions.platform-promotion-accounts', + 'view' => 'banking.marketing_platform_promotion_bills.partials.embedded-table', 'filters' => $filters, 'data' => $data, - 'platform' => $tab, - 'rows' => $this->paginateRows($data, $tab), + 'platform' => $platform, + 'marketingTab' => $tab, + 'rows' => $this->paginateRows($data, $platform), 'error' => null, ]; } catch (ServiceUnavailableHttpException $exception) { return [ - 'view' => 'business.pages.billing-transactions.platform-promotion-accounts', + 'view' => 'banking.marketing_platform_promotion_bills.partials.embedded-table', 'filters' => $filters, 'data' => [], - 'platform' => $tab, + 'platform' => $platform, + 'marketingTab' => $tab, 'rows' => $this->emptyPaginator(), 'error' => $exception->getMessage(), ]; @@ -53,16 +63,22 @@ class PlatformPromotionAccountPageData report($exception); return [ - 'view' => 'business.pages.billing-transactions.platform-promotion-accounts', + 'view' => 'banking.marketing_platform_promotion_bills.partials.embedded-table', 'filters' => $filters, 'data' => [], - 'platform' => $tab, + 'platform' => $platform, + 'marketingTab' => $tab, 'rows' => $this->emptyPaginator(), 'error' => '推广账户数据暂时无法读取,请稍后重试。', ]; } } + public static function platformForTab(?string $tab): ?string + { + return self::TAB_PLATFORMS[$tab] ?? null; + } + private function paginateRows(array $data, string $tab): LengthAwarePaginator { $key = ['jd' => 'jd', 'douyin' => 'dy', 'dewu' => 'dw', 'vip' => 'vipSales'][$tab]; diff --git a/resources/views/banking/marketing_platform_promotion_bills/partials/embedded-table.blade.php b/resources/views/banking/marketing_platform_promotion_bills/partials/embedded-table.blade.php new file mode 100644 index 00000000..2dd1220c --- /dev/null +++ b/resources/views/banking/marketing_platform_promotion_bills/partials/embedded-table.blade.php @@ -0,0 +1,108 @@ +@php + $data = $data ?? []; + $platform = $platform ?? 'jd'; + $marketingTab = $marketingTab ?? null; + $summary = match ($platform) { + 'jd' => $data['jdSummary'] ?? [], + 'douyin' => $data['dySummary'] ?? [], + 'dewu' => $data['dwSummary'] ?? [], + default => $data['vipSummary'] ?? [], + }; + $titles = ['jd' => '京东京准通', 'douyin' => '抖音千川', 'dewu' => '得物推广账户', 'vip' => '唯品会推广']; + $columns = match ($platform) { + 'jd' => [['shop_name', '店铺'], ['account', '账户'], ['show_date', '日期'], ['trade_type_name', '交易类型'], ['amount', '金额'], ['balance_amount', '余额'], ['remark', '备注']], + 'douyin' => [['shopName', '店铺'], ['account', '账户'], ['qianchuanAavid', '广告账户'], ['statDate', '日期'], ['cost', '花费'], ['income', '收入'], ['transferIn', '转入'], ['transferOut', '转出'], ['balance', '余额'], ['status', '状态'], ['remark', '备注']], + 'dewu' => [['shop_name', '店铺'], ['account', '账户'], ['trade_date', '日期'], ['amount_type', '金额类型'], ['flow_type', '收支类型'], ['trade_amount_yuan', '金额'], ['balance_yuan', '余额'], ['remark', '备注']], + default => [['shopName', '店铺'], ['storeName', '平台店铺'], ['accountName', '营销账户'], ['dataMonth', '月份'], ['actualSalesAmount', '实际销售额'], ['reportAmount', '申报金额'], ['totalCostYuan', '营销花费']], + }; + $moneyFields = ['amount', 'balance_amount', 'cost', 'income', 'transferIn', 'transferOut', 'balance', 'trade_amount_yuan', 'balance_yuan', 'actualSalesAmount', 'reportAmount', 'totalCostYuan']; +@endphp + + +
+
+ + + + + 导出 CSV +
+ + @if (! empty($error)) + + @endif + +
+ @if ($platform === 'jd') +
入账金额(元)
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
+
出账金额(元)
{{ number_format((float) ($summary['expense'] ?? 0), 2) }}
+
净额(元)
{{ number_format((float) ($summary['income'] ?? 0) - (float) ($summary['expense'] ?? 0), 2) }}
+
流水笔数
{{ number_format((int) ($summary['record_count'] ?? 0)) }}
+ @elseif ($platform === 'douyin') +
总花费(元)
{{ number_format((float) ($summary['cost'] ?? 0), 2) }}
+
收入(元)
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
+
转入(元)
{{ number_format((float) ($summary['transfer_in'] ?? 0), 2) }}
+
账户数
{{ number_format((int) ($summary['account_count'] ?? 0)) }}
+ @elseif ($platform === 'dewu') +
总收入(元)
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
+
总支出(元)
{{ number_format((float) ($summary['expense'] ?? 0), 2) }}
+
净额(元)
{{ number_format((float) ($summary['net'] ?? 0), 2) }}
+
流水笔数
{{ number_format((int) ($summary['record_count'] ?? 0)) }}
+ @else +
实际销售额(元)
{{ number_format((float) ($summary['sales'] ?? 0), 2) }}
+
销售目标(元)
{{ number_format((float) ($summary['target'] ?? 0), 2) }}
+
涉税申报(元)
{{ number_format((float) ($summary['tax'] ?? 0), 2) }}
+
营销花费(元)
{{ number_format((float) ($summary['marketing_cost'] ?? 0), 2) }}
+ @endif +
+ +
+
{{ $titles[$platform] }}明细
{{ number_format($rows->total()) }} 条
+
@foreach ($columns as $column)@endforeach + @forelse ($rows as $row) + @foreach ($columns as $column) + @php($value = $row[$column[0]] ?? null) + + @endforeach + @empty + + @endforelse +
{{ $column[1] }}
{{ in_array($column[0], $moneyFields, true) && is_numeric($value) ? number_format((float) $value, 2) : ($value ?? '—') }}
该月份暂无数据
+
每页最多 50 条 · 共 {{ number_format($rows->total()) }} 条
+
+
diff --git a/resources/views/business/pages/billing-transactions/platform-promotion-accounts.blade.php b/resources/views/business/pages/billing-transactions/platform-promotion-accounts.blade.php deleted file mode 100644 index 86f1f311..00000000 --- a/resources/views/business/pages/billing-transactions/platform-promotion-accounts.blade.php +++ /dev/null @@ -1,89 +0,0 @@ -@php - $data = $data ?? []; - $platform = $platform ?? 'jd'; - $summary = match ($platform) { - 'jd' => $data['jdSummary'] ?? [], - 'douyin' => $data['dySummary'] ?? [], - 'dewu' => $data['dwSummary'] ?? [], - default => $data['vipSummary'] ?? [], - }; - $titles = ['jd' => '京东京准通', 'douyin' => '抖音千川', 'dewu' => '得物推广账户', 'vip' => 'VIP(唯品会)']; - $columns = match ($platform) { - 'jd' => [['shop_name', '店铺'], ['account', '账户'], ['show_date', '日期'], ['trade_type_name', '交易类型'], ['amount', '金额'], ['balance_amount', '余额'], ['remark', '备注']], - 'douyin' => [['shopName', '店铺'], ['account', '账户'], ['qianchuanAavid', '广告账户'], ['statDate', '日期'], ['cost', '花费'], ['balance', '余额'], ['status', '状态'], ['remark', '备注']], - 'dewu' => [['shop_name', '店铺'], ['account', '账户'], ['trade_date', '日期'], ['flow_type', '收支类型'], ['trade_amount_yuan', '金额'], ['balance_yuan', '余额'], ['remark', '备注']], - default => [['shopName', '店铺'], ['storeName', '平台店铺'], ['accountName', '营销账户'], ['dataMonth', '月份'], ['actualSalesAmount', '实际销售额'], ['reportAmount', '申报金额'], ['totalCostYuan', '营销花费']], - }; - $moneyFields = ['amount', 'balance_amount', 'cost', 'balance', 'trade_amount_yuan', 'balance_yuan', 'actualSalesAmount', 'reportAmount', 'totalCostYuan']; -@endphp - -
-
- - - - - 导出 CSV -
- - @if (! empty($error)) - - @endif - -
- @if ($platform === 'jd') -
入账金额
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
-
出账金额
{{ number_format((float) ($summary['expense'] ?? 0), 2) }}
-
净额
{{ number_format((float) ($summary['income'] ?? 0) - (float) ($summary['expense'] ?? 0), 2) }}
-
流水笔数
{{ number_format((int) ($summary['record_count'] ?? 0)) }}
- @elseif ($platform === 'douyin') -
总花费
{{ number_format((float) ($summary['cost'] ?? 0), 2) }}
-
收入
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
-
转入
{{ number_format((float) ($summary['transfer_in'] ?? 0), 2) }}
-
账户数
{{ number_format((int) ($summary['account_count'] ?? 0)) }}
- @elseif ($platform === 'dewu') -
总收入
{{ number_format((float) ($summary['income'] ?? 0), 2) }}
-
总支出
{{ number_format((float) ($summary['expense'] ?? 0), 2) }}
-
净额
{{ number_format((float) ($summary['net'] ?? 0), 2) }}
-
流水笔数
{{ number_format((int) ($summary['record_count'] ?? 0)) }}
- @else -
实际销售额
{{ number_format((float) ($summary['sales'] ?? 0), 2) }}
-
销售目标
{{ number_format((float) ($summary['target'] ?? 0), 2) }}
-
涉税申报
{{ number_format((float) ($summary['tax'] ?? 0), 2) }}
-
营销花费
{{ number_format((float) ($summary['marketing_cost'] ?? 0), 2) }}
- @endif -
- -
-
{{ $titles[$platform] }}明细
{{ number_format($rows->total()) }} 条
-
@foreach ($columns as $column)@endforeach - @forelse ($rows as $row) - @foreach ($columns as $column) - @php($value = $row[$column[0]] ?? null) - - @endforeach - @empty - - @endforelse -
{{ $column[1] }}
{{ in_array($column[0], $moneyFields, true) && is_numeric($value) ? number_format((float) $value, 2) : ($value ?? '—') }}
该月份暂无数据
-
每页最多 50 条 · 共 {{ number_format($rows->total()) }} 条
-
-
diff --git a/tests/Feature/Business/PlatformPromotionAccountPageTest.php b/tests/Feature/Business/MarketingPlatformPromotionBillsTest.php similarity index 57% rename from tests/Feature/Business/PlatformPromotionAccountPageTest.php rename to tests/Feature/Business/MarketingPlatformPromotionBillsTest.php index a7b42be5..127c28a0 100644 --- a/tests/Feature/Business/PlatformPromotionAccountPageTest.php +++ b/tests/Feature/Business/MarketingPlatformPromotionBillsTest.php @@ -7,10 +7,12 @@ use Mockery; use Modules\EcommerceFinance\Repositories\PlatformPromotionAccountRepository; use Tests\Feature\FeatureTestCase; -class PlatformPromotionAccountPageTest extends FeatureTestCase +class MarketingPlatformPromotionBillsTest extends FeatureTestCase { - public function test_platform_promotion_page_remains_available_with_bill_offset_navigation(): void + public function test_promotion_platform_is_a_tab_inside_marketing_account_bills(): void { + $this->allowMarketingAccountBillsPage(); + $repository = Mockery::mock(PlatformPromotionAccountRepository::class); $repository->shouldReceive('latestMonth')->once()->andReturn('2026-08'); $repository->shouldReceive('dashboard')->once()->with([ @@ -20,29 +22,30 @@ class PlatformPromotionAccountPageTest extends FeatureTestCase ], 5000)->andReturn($this->dashboardData()); $this->app->instance(PlatformPromotionAccountRepository::class, $repository); - $this->user->attachPermission( - Permission::where('name', 'read-admin-panel')->firstOrFail() - ); - $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'billing-transactions', - 'page' => 'platform-promotion-accounts', - 'tab' => 'jd', + 'page' => 'marketing-account-bills', + 'tab' => 'jd-promotion', ])) ->assertOk() - ->assertSeeText('平台推广账户流水') ->assertSeeText('京东京准通') + ->assertSee('aria-label="京东京准通推广账户筛选"', false) ->assertSeeText('测试店铺') ->assertSeeText('导出 CSV') + ->assertSee('class="my-6 business-page--marketing-account-bills"', false) ->assertSee(route('business.pages.show', [ - 'section' => 'order-data', - 'page' => 'bill-offset', - ]), false); + 'section' => 'billing-transactions', + 'page' => 'marketing-account-bills', + 'tab' => 'taobao-alipay', + ]), false) + ->assertDontSeeText('平台推广账户流水'); } - public function test_platform_promotion_export_keeps_the_complete_filtered_month(): void + public function test_promotion_platform_export_uses_merged_marketing_account_bills_route(): void { + $this->allowMarketingAccountBillsPage(); + $repository = Mockery::mock(PlatformPromotionAccountRepository::class); $repository->shouldReceive('latestMonth')->never(); $repository->shouldReceive('dashboard')->once()->with([ @@ -52,27 +55,34 @@ class PlatformPromotionAccountPageTest extends FeatureTestCase ], 5000)->andReturn($this->dashboardData()); $this->app->instance(PlatformPromotionAccountRepository::class, $repository); - $this->user->attachPermission( - Permission::where('name', 'read-admin-panel')->firstOrFail() - ); - $response = $this->loginAs()->get(route('business.pages.export', [ 'section' => 'billing-transactions', - 'page' => 'platform-promotion-accounts', - 'tab' => 'jd', + 'page' => 'marketing-account-bills', + 'tab' => 'jd-promotion', 'month' => '2026-08', 'shop_name' => '测试', 'account' => 'account-01', ])); - $response->assertOk(); - $response->assertHeader('Content-Type', 'text/csv; charset=UTF-8'); - $disposition = (string) $response->headers->get('Content-Disposition'); - $this->assertStringContainsString("filename*=utf-8''", $disposition); - $this->assertStringContainsString('2026-08.csv', $disposition); + $response->assertOk() + ->assertHeader('Content-Type', 'text/csv; charset=UTF-8') + ->assertDownload('店铺营销账户账单_jd_2026-08.csv'); $this->assertStringContainsString('测试店铺', $response->streamedContent()); } + public function test_removed_platform_promotion_directory_is_not_available(): void + { + $this->allowMarketingAccountBillsPage(); + + $this->loginAs() + ->get(route('business.pages.show', [ + 'section' => 'billing-transactions', + 'page' => 'platform-promotion-accounts', + 'tab' => 'jd', + ])) + ->assertNotFound(); + } + private function dashboardData(): array { return [ @@ -97,4 +107,18 @@ class PlatformPromotionAccountPageTest extends FeatureTestCase 'vipSummary' => [], ]; } + + private function allowMarketingAccountBillsPage(): void + { + $this->user->update(['locale' => 'zh-CN']); + $this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail()); + + $subject = 'user_' . $this->user->id; + setting()->set('system.sidebar_permissions', json_encode([ + 'configured' => [$subject], + 'subjects' => [ + $subject => ['billing-transactions/marketing-account-bills'], + ], + ], JSON_UNESCAPED_UNICODE)); + } }