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发空包/赠品费用') ->assertSeeText('暂无数据') ->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直通车/钻展/快车等') ->assertSeeText('暂无数据') ->assertDontSee('class="business-blank-page"', false); } 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( '/]*data-header-row="(labels|fields)"[^>]*>(.*?)<\/tr>/s', $html, $headerRows, PREG_SET_ORDER, ); $headers = collect($headerRows)->mapWithKeys(function (array $row): array { $cells = []; preg_match_all('/]*>(.*?)<\/th>/s', $row[2], $cells); return [$row[1] => collect($cells[1])->map( fn (string $cell): string => trim(html_entity_decode(strip_tags($cell))) )->all()]; }); $this->assertSame([ '序号/主键ID', '退款日期', '售后单ID', '外部售后单号', '订单ID', '', '子订单ID', '类型', '节点', '是否自营', '店铺名称', '平台', '责任部门', '退款总金额', '原始邮编', '店铺商品ID', '店铺SKU编码', '商品ID', 'SKU编码', '买家实付金额', '数量', '商品单位成本', '明细退款金额', '退款类型', '退款数量', '退款商品成本', '退款回款金额', '售后金额', '创建时间', '状态', '店铺状态', '创建记录/创建时间', '确认日期', ], $headers->get('labels')); $this->assertSame([ 'Id', 'refundDate', 'as_id', 'outer_as_id', 'o_id', '', 'so_id', 'type', 'node', 'isZC', 'shop_name', 'platform', 'responsibleDepartment', 'totalRefundMoney', 'originPostcode', 'shop_i_id', 'shop_sku_id', 'i_id', 'sku_id', 'buyer_paid_amount', 'qty', 'unitCostGoods', 'detailRefundMoney', 'refundType', 'refundQty', 'refundCostGoods', 'RefundMoneyIncome', 'AfSalesMoney', 'createTime', 'status', 'shop_status', 'created', 'confirm_date', ], $headers->get('fields')); $this->withExceptionHandling()->loginAs()->get(route('business.pages.show', [ 'company_id' => $this->company->id, 'section' => 'refunds', 'page' => 'unknown-refund-page', ]))->assertNotFound(); } public function testPaperMaterialPagesRenderAsSeparateTables() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $pages = [ 'paper-prices' => '价格类型', 'paper-details' => '压贴厂金额', 'penalty-details' => '违约金', 'paper-factory-payables' => '2026年公司应付纸厂6月份货款', ]; foreach ($pages as $page => $expectedHeader) { $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'paper-materials', 'page' => $page, ])) ->assertOk() ->assertSee($expectedHeader) ->assertSee('class="paper-material-table', false) ->assertDontSee('class="business-blank-page"', false); } } public function testEdgeBandingMaterialPagesRenderAsSeparateTables() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $pages = [ 'edge-banding-prices' => '价格类型', 'details' => '封边条厂单价', 'compensation' => '最新出库日期', 'edge-banding-payables' => '2026年公司应付封边条厂6月份货款', ]; foreach ($pages as $page => $expectedHeader) { $response = $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'edge-banding-materials', 'page' => $page, ])) ->assertOk() ->assertSee($expectedHeader) ->assertSee('class="edge-banding-table', false) ->assertDontSee('class="business-blank-page"', false); if ($page !== 'compensation') { $response->assertSeeText('该上游数据同步尚未启用,请联系管理员。'); } } } public function testLaminationFactoryPayablePagesRenderAsSeparateTables() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $pages = [ 'lamination-prices' => '执行日期', 'finished-board-prices' => '最新价格', 'lamination-fees' => '单号类型', 'finished-board-freight' => '成品板规格', 'paper-stock-in' => '家具厂', 'paper-stock-out' => '压贴厂金额', 'factory-raw-boards' => '纸张合计', 'raw-board-freight' => '素板规格', 'invoice-tax-points' => '对账金额', 'factory-compensation' => '来源金额', 'factory-payables-details' => '成品板运费合计', 'factory-payables-report' => '2026年公司应付压贴厂5月份货款', ]; foreach ($pages as $page => $expectedHeader) { $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'lamination-factory-payables', 'page' => $page, ])) ->assertOk() ->assertSee($expectedHeader) ->assertSee('class="lamination-table', false) ->assertDontSee('class="business-blank-page"', false); } } public function testMergedFeaturePagesRenderTheirDedicatedContent() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $pages = [ ['supplier-payables', 'product-prices', '数据读取失败,请稍后重试。'], ['courier-payables', 'freight-reconciliation', '快递单号'], ['courier-payables', 'bookkeeping-details', '暂无记账明细'], ['courier-payables', 'compensation-details', '暂无赔偿明细'], ['courier-payables', 'advance-details', '暂无借支明细'], ['courier-payables', 'other-adjustments', '暂无其他扣款补款明细'], ['raw-board-payables', 'board-prices', '价格类型'], ['raw-board-payables', 'board-reconciliation', '运费(包含分摊运费)'], ['raw-board-payables', 'compensation-details', '暂无素板赔付明细'], ['raw-board-payables', 'board-payables-report', '暂无素板应付汇总数据'], ]; foreach ($pages as [$section, $page, $expectedText]) { $this->loginAs() ->get(route('business.pages.show', compact('section', 'page'))) ->assertOk() ->assertSeeText($expectedText) ->assertDontSee('class="business-blank-page"', false); } } public function testBoardInventoryDetailsRendersWorkbookColumnsAsItsOwnPage() { $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'inventory-management', 'page' => 'board-inventory-details', ])) ->assertOk() ->assertSee('class="upstream-data-table upstream-data-table--inventory"', false) ->assertSeeText('加权平均单价') ->assertSeeText('上月剩余价值') ->assertSeeText('出库金额') ->assertDontSee('class="business-data-page"', false) ->assertDontSee('class="business-blank-page"', false); } }