194 lines
8.3 KiB
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(),
|
|
);
|
|
}
|
|
}
|