user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); AlipayBill::create([ 'company_id' => $this->company->id, 'record_code' => 'time-format-test', 'store_name' => '测试店铺', 'bill_item' => '交易收款', 'business_type' => '交易付款', 'alipay_account' => '2088000000000000', 'counterparty_account' => '测试账号', 'account_order_no' => 'account-order-test', 'business_serial_no' => 'business-serial-test', 'goods_name' => '测试商品', 'income' => 1, 'expense' => 0, 'balance' => 1, 'occurred_at' => '2026-07-15 23:59:12', ]); $this->loginAs() ->withHeader('X-Requested-With', 'XMLHttpRequest') ->get(route('ecommerce-finance.alipay-bills.index')) ->assertOk() ->assertJsonStructure([ 'current_page', 'data', 'total', 'summary' => ['income', 'expense', 'count', 'balance'], ]) ->assertJsonPath('data.0.occurred_at', '2026-07-15 23:59:12'); } public function testTaobaoAlipayBillsPageProvidesTheVueMountPoint() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'billing-transactions', 'page' => 'store-receiving-bills', 'tab' => 'taobao-alipay', ])) ->assertOk() ->assertSee('class="biz-card mt-6 business-blank-page"', false) ->assertSee('public/js/business/pages.min.js', false); } public function testSupplierPayablesPageRendersItsSpecificContent() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'supplier-payables', 'page' => 'payment-reconciliation', ])) ->assertOk() ->assertSee('id="goods-reconciliation-app"', false) ->assertSee('public/js/ecommerce-finance/goods-reconciliations.min.js', false) ->assertDontSee('class="business-blank-page"', false); } public function testOrderDataTablesRenderAsRawDataPageTabs() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $this->loginAs() ->get(route('business.pages.show', ['section' => 'order-data'])) ->assertRedirect(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'after-sales-expenses', ])); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', ])) ->assertRedirect(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'after-sales-expenses', ])); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'after-sales-expenses', ])) ->assertOk() ->assertSeeText('订单售后费用明细') ->assertSee('aria-label="订单售后费用明细"', false) ->assertSeeText('内部订单号') ->assertSeeText('800503发空包/赠品费用') ->assertSee('class="business-tab-bar"', false) ->assertSee(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'after-sales-expenses', ]), false) ->assertSee(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'promotion-expenses', ]), false) ->assertDontSee(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'after-sales-expenses', ]), false) ->assertDontSee('class="business-blank-page"', false); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'promotion-expenses', ])) ->assertOk() ->assertSeeText('商品推广费用明细') ->assertSee('aria-label="商品推广费用明细"', false) ->assertSeeText('店铺') ->assertSeeText('8001201直通车/钻展/快车等') ->assertDontSee('class="business-blank-page"', false); } public function testOrderDataIncludesTheConfiguredBillOffsetSubpage(): void { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $this->loginAs(); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'bill-offset', ])) ->assertOk() ->assertSeeInOrder([ route('business.pages.show', [ 'section' => 'order-data', 'page' => 'raw-data', 'tab' => 'after-sales-expenses', ]), route('business.pages.show', [ 'section' => 'order-data', 'page' => 'bill-offset', ]), ], false); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'bill-offset', ])) ->assertOk() ->assertSeeText('账单冲减') ->assertSeeText('该页面暂未配置数据表,敬请期待。'); $this->withExceptionHandling(); foreach (['national-subsidy', 'hundred-subsidy', 'consumption-coupon'] as $removedSlug) { $this->withHeader('X-Requested-With', 'XMLHttpRequest') ->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => $removedSlug, ])) ->assertNotFound(); } } public function testFinancialAfterSalesPageRendersMirroredJushuitanWorkOrders(): void { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $workOrders = \Mockery::mock(WorkOrderMirrorRepository::class); $workOrders->shouldReceive('paginateAfterSales')->once()->withArgs(function (int $page, int $limit, array $filters): bool { return $page === 1 && $limit === 10 && $filters['from'] === '2026-08-24' && $filters['to'] === '2026-08-24' && $filters['shop_name'] === '天猫旗舰店'; })->andReturn([ 'data' => [[ 'order_no' => 'WO-FIN-005', 'work_type_name' => '天猫_售后超标', 'title' => '售后超标提醒', 'status' => '待处理', 'create_user' => '运营一组', 'create_time' => '2026-08-24 10:00:00', 'form_values' => [['field_name' => '店铺名称', 'field_value' => '天猫旗舰店']], ]], 'total' => 1, 'page' => 1, 'per_page' => 10, 'last_page' => 1, 'ready' => true, 'sync_status' => ['ready' => true, 'code' => 'ready', 'last_succeeded_at' => '2026-08-24 12:00:00', 'datasets' => []], ]); $this->app->instance(WorkOrderMirrorRepository::class, $workOrders); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'financial-operations', 'page' => 'after-sales-expenses', 'from' => '2026-08-24', 'to' => '2026-08-24', 'shop_name' => '天猫旗舰店', ])) ->assertOk() ->assertSeeText('聚水潭售后工单') ->assertSeeText('WO-FIN-005') ->assertSeeText('天猫_售后超标') ->assertSeeText('天猫旗舰店') ->assertSeeText('费用金额仍以订单售后费用明细的金额字段为准'); } public function testRefundPagesUseTheGenericBusinessPageRoute() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $repository = \Mockery::mock(NonJingxiRefundMirrorRepository::class); $repository->shouldReceive('available')->once()->andReturnFalse(); $repository->shouldNotReceive('states'); $repository->shouldNotReceive('syncStatus'); $repository->shouldNotReceive('ready'); $repository->shouldNotReceive('queryReady'); $repository->shouldNotReceive('paginate'); $this->app->instance(NonJingxiRefundMirrorRepository::class, $repository); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'refunds', ])) ->assertRedirect(route('business.pages.show', [ 'section' => 'refunds', 'page' => 'jingxi-refund-data', ])); $this->get(route('business.pages.show', [ 'section' => 'refunds', 'page' => 'jingxi-refund-data', ])) ->assertOk() ->assertSeeText('京喜退款数据') ->assertSeeText('该页面暂未配置数据表,敬请期待。') ->assertSee('class="biz-empty"', false); $response = $this->get(route('business.pages.show', [ 'section' => 'refunds', 'page' => 'non-jingxi-refund-data', ])); $response ->assertOk() ->assertSeeText('售后(退货退款)') ->assertSee('aria-label="售后(退货退款)"', false) ->assertSee('aria-label="售后(退货退款)分页"', false) ->assertDontSeeText('非京喜退款数据') ->assertSeeText('共享业务镜像尚未建立') ->assertSeeText('数据暂时无法读取') ->assertSee('class="upstream-data-table refund-data-table refund-data-table--wide"', false) ->assertSee('data-header-row="labels"', false) ->assertSee('data-header-row="fields"', false) ->assertDontSee('class="biz-empty"', false); $html = $response->getContent(); $headerRows = []; preg_match_all( '/