CaiWuXiTong/tests/Feature/Business/ShippingDataPageTest.php

194 lines
8.3 KiB
PHP

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use Mockery;
use Modules\EcommerceFinance\Repositories\ShippingOrderRepository;
use Tests\Feature\FeatureTestCase;
class ShippingDataPageTest extends FeatureTestCase
{
public function test_page_passes_all_filters_and_renders_export_and_date_pickers(): void
{
$this->grantPermission();
$repository = Mockery::mock(ShippingOrderRepository::class);
$repository->shouldReceive('paginate')->once()->withArgs(function (array $filters, int $page, int $limit, string $mode): bool {
return $filters === [
'express_no' => 'EXP-001',
'sourceno' => 'TRADE-001',
'barcode' => 'BAR-001',
'supplier_name' => ['新北供应商'],
'shop_name' => ['测试店铺'],
'warehouse_name' => ['一号仓'],
'express_company' => ['顺丰'],
'ship_from' => '2026-09-01',
'ship_to' => '2026-09-16',
] && $page === 1 && $limit > 0 && $mode === 'detail';
})->andReturn(['data' => [], 'total' => 0]);
$repository->shouldReceive('syncStatus')->once()->andReturn([
'code' => 'succeeded',
'last_succeeded_at' => '2026-09-16 10:16:36',
]);
$this->app->instance(ShippingOrderRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'shipping-data',
'express_no' => 'EXP-001',
'sourceno' => 'TRADE-001',
'barcode' => 'BAR-001',
'supplier_name' => '新北供应商',
'shop_name' => '测试店铺',
'warehouse_name' => '一号仓',
'express_company' => '顺丰',
'ship_from' => '2026-09-01',
'ship_to' => '2026-09-16',
'mode' => 'detail',
]))
->assertOk()
->assertSee('name="barcode"', false)
->assertSee('name="supplier_name[]"', false)
->assertSee('name="shop_name[]"', false)
->assertSee('name="warehouse_name[]"', false)
->assertSee('name="express_company[]"', false)
->assertSee('type="date" name="ship_from"', false)
->assertSee('data-date-picker-input="shipping-from"', false)
->assertSeeText('导出')
->assertSeeText('导出明细');
}
public function test_page_shows_partial_backfill_and_pending_freight_warning(): void
{
$this->grantPermission();
$repository = Mockery::mock(ShippingOrderRepository::class);
$repository->shouldReceive('paginate')->once()->andReturn(['data' => [], 'total' => 0]);
$repository->shouldReceive('syncStatus')->once()->andReturn([
'code' => 'partial',
'last_succeeded_at' => '2026-09-24 09:00:00',
'freight_pending' => true,
'warning' => '2 个日期窗口的运费和结算重量待补,空白不代表 0。',
]);
$this->app->instance(ShippingOrderRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'shipping-data',
'ship_from' => '2026-09-01',
'ship_to' => '2026-09-24',
]))
->assertOk()
->assertSeeText('部分数据已同步 · 运费待补')
->assertSeeText('最近成功同步 2026-09-24 09:00:00')
->assertSeeText('2 个日期窗口的运费和结算重量待补,空白不代表 0。')
->assertDontSeeText('数据新鲜');
}
public function test_page_distinguishes_pending_items_from_pending_freight(): void
{
$this->grantPermission();
$repository = Mockery::mock(ShippingOrderRepository::class);
$repository->shouldReceive('paginate')->once()->andReturn(['data' => [], 'total' => 0]);
$repository->shouldReceive('syncStatus')->once()->andReturn([
'code' => 'partial',
'last_succeeded_at' => null,
'freight_pending' => false,
'warning' => '1 个日期窗口的商品或金额待核对。',
]);
$this->app->instance(ShippingOrderRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'shipping-data',
]))
->assertOk()
->assertSeeText('部分数据已同步 · 商品或金额待核对')
->assertSeeText('1 个日期窗口的商品或金额待核对。')
->assertDontSeeText('运费待补');
}
public function test_page_hides_repository_sql_exception_details(): void
{
$this->grantPermission();
$repository = Mockery::mock(ShippingOrderRepository::class);
$repository->shouldReceive('paginate')->once()->andThrow(new \RuntimeException(
'SQLSTATE[42S02]: table SECRET_MIRROR_TABLE does not exist',
));
$repository->shouldNotReceive('syncStatus');
$this->app->instance(ShippingOrderRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'courier-payables',
'page' => 'shipping-data',
]))
->assertOk()
->assertSeeText('发货数据暂时无法读取(可能尚未运行迁移或同步)。')
->assertDontSee('SQLSTATE')
->assertDontSee('SECRET_MIRROR_TABLE');
}
public function test_export_uses_current_filters_and_keeps_identifiers_unprefixed(): void
{
$this->grantPermission();
$repository = Mockery::mock(ShippingOrderRepository::class);
$repository->shouldReceive('exportRows')->once()->withArgs(function (array $filters, int $batchSize, string $mode): bool {
return $filters['barcode'] === '6901234567890'
&& $filters['supplier_name'] === ['新北供应商']
&& $filters['shop_name'] === ['测试店铺']
&& $filters['warehouse_name'] === ['一号仓']
&& $filters['express_company'] === ['顺丰']
&& $filters['ship_from'] === '2026-09-01'
&& $filters['ship_to'] === '2026-09-16'
&& $batchSize === 1000
&& $mode === 'merged';
})->andReturn((static function (): \Generator {
yield [
'express_no' => '01234567890123456789',
'trade_no' => 'TRADE-001',
'barcode' => '6901234567890',
'product_name' => '测试商品',
'qty' => 2,
'shop_name' => '测试店铺',
'warehouse_name' => '一号仓',
'supplier_name' => '新北供应商',
'express_name1' => '顺丰速运',
'ship_time' => '2026-09-10 12:00:00',
];
})());
$this->app->instance(ShippingOrderRepository::class, $repository);
$response = $this->loginAs()->get(route('business.courier-payables.shipping-data.export', [
'barcode' => '6901234567890',
'supplier_name' => '新北供应商',
'shop_name' => '测试店铺',
'warehouse_name' => '一号仓',
'express_company' => '顺丰',
'ship_from' => '2026-09-01',
'ship_to' => '2026-09-16',
]));
$response->assertOk();
$this->assertStringContainsString('attachment;', (string) $response->headers->get('content-disposition'));
$content = $response->streamedContent();
$this->assertStringStartsWith(chr(0xEF) . chr(0xBB) . chr(0xBF), $content);
$this->assertStringContainsString('快递单号', $content);
$this->assertStringContainsString('01234567890123456789', $content);
$this->assertStringContainsString('6901234567890', $content);
$this->assertStringNotContainsString("'01234567890123456789", $content);
$this->assertStringNotContainsString("'6901234567890", $content);
$this->assertStringContainsString('新北供应商', $content);
}
private function grantPermission(): void
{
$this->user->attachPermission(
Permission::where('name', 'read-admin-panel')->firstOrFail(),
);
}
}