CaiWuXiTong/tests/Feature/Business/ProductCatalogPageTest.php
limeng d87ca96593 普通商品增加1688代发采购单价来源 (#74)
保留并标注普通商品采购价,接入已完成1688代发采购单价的只读共享业务镜像。
2026-08-21 14:49:16 +08:00

277 lines
11 KiB
PHP

<?php
namespace Tests\Feature\Business;
use App\Models\Auth\Permission;
use Modules\EcommerceFinance\Repositories\ProductCatalogMirrorRepository;
use Tests\Feature\FeatureTestCase;
class ProductCatalogPageTest extends FeatureTestCase
{
protected function grantAdminPermission(): void
{
$this->user->attachPermission(
Permission::where('name', 'read-admin-panel')->firstOrFail()
);
}
public function test_normal_products_page_renders_mirror_rows_and_filters(): void
{
$this->grantAdminPermission();
$state = [
'status' => 'succeeded',
'last_succeeded_at' => '2026-08-15 17:51:03',
'last_full_succeeded_at' => '2026-08-10 03:15:00',
'mirror_row_count' => 547217,
];
$repository = \Mockery::mock(ProductCatalogMirrorRepository::class);
$repository->shouldReceive('available')->once()->andReturnTrue();
$repository->shouldReceive('state')->once()->andReturn($state);
$repository->shouldReceive('syncStatus')->once()->with($state)->andReturn([
'code' => 'healthy',
'lag_minutes' => 4,
]);
$repository->shouldReceive('ready')->once()->andReturnTrue();
$repository->shouldReceive('paginate')
->once()
->withArgs(static function (array $filters, int $page, int $limit): bool {
return $filters['i_id'] === 'STYLE-001'
&& $filters['sku_id'] === 'SKU-001'
&& $filters['keyword'] === '胡桃'
&& $filters['enabled'] === '1'
&& $filters['stock_disabled'] === '0'
&& $filters['sale_price_min'] === '800'
&& $filters['sale_price_max'] === '900'
&& $page === 1
&& $limit <= 50;
})
->andReturn([
'data' => [(object) [
'autoid' => 1001,
'i_id' => 'STYLE-001',
'sku_id' => 'SKU-001',
'name' => '岩板餐桌',
'short_name' => '餐桌',
'properties_value' => '1.4米',
'color' => '胡桃色',
'sale_price' => 899,
'cost_price' => 500,
'purchase_price' => 480,
'product_purchase_price_source' => '商品及库存管理(普通商品资料)',
'purchase_order_unit_price' => 65,
'purchase_order_finished_at' => '2026-08-20 11:03:05',
'purchase_order_id' => 827380,
'purchase_order_price_source' => '采购单管理-1688代发单价',
'market_price' => 1099,
'brand' => '北木',
'category' => '住宅家具',
'supplier_name' => '新北供应商',
'enabled' => 1,
'stock_disabled' => 0,
'modified' => '2026-08-15 10:00:00',
]],
'total' => 1,
'purchase_price_sync_status' => [
'code' => 'ready',
'initialized' => true,
'last_succeeded_at' => '2026-08-21 12:00:00',
],
]);
$this->app->instance(ProductCatalogMirrorRepository::class, $repository);
$response = $this->loginAs()->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
'i_id' => 'STYLE-001',
'sku_id' => 'SKU-001',
'keyword' => '胡桃',
'enabled' => '1',
'stock_disabled' => '0',
'sale_price_min' => '900',
'sale_price_max' => '800',
]));
$response
->assertOk()
->assertSee('data-product-catalog-page', false)
->assertSeeText('普通商品资料')
->assertSee('data-sync-state="healthy"', false)
->assertSeeText('同步正常')
->assertSeeText('最近同步 2026-08-15 17:51:03')
->assertSeeText('数据延迟 4 分钟')
->assertSeeText('最近校准 2026-08-10 03:15:00')
->assertSeeText('STYLE-001')
->assertSeeText('SKU-001')
->assertSeeText('岩板餐桌')
->assertSeeText('899.00')
->assertSeeText('普通商品采购价')
->assertSeeText('1688 代发单价')
->assertSeeText('商品及库存管理(普通商品资料)')
->assertSeeText('采购单管理-1688代发单价')
->assertSeeText('65.00')
->assertDontSeeText('1688 代发单价尚未完成首次同步')
->assertSeeText('正常同步')
->assertDontSee('pic_url');
}
public function test_normal_products_page_marks_purchase_prices_as_not_yet_synchronized(): void
{
$this->grantAdminPermission();
$state = [
'status' => 'succeeded',
'initial_completed_at' => '2026-08-14 21:15:36',
'last_succeeded_at' => '2026-08-21 12:00:00',
'mirror_row_count' => 547217,
];
$repository = \Mockery::mock(ProductCatalogMirrorRepository::class);
$repository->shouldReceive('available')->once()->andReturnTrue();
$repository->shouldReceive('state')->once()->andReturn($state);
$repository->shouldReceive('syncStatus')->once()->with($state)->andReturn([
'code' => 'healthy',
'lag_minutes' => 1,
]);
$repository->shouldReceive('ready')->once()->andReturnTrue();
$repository->shouldReceive('paginate')->once()->andReturn([
'data' => [],
'total' => 0,
'purchase_price_sync_status' => [
'code' => 'pending',
'initialized' => false,
'last_succeeded_at' => null,
],
]);
$this->app->instance(ProductCatalogMirrorRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
]))
->assertOk()
->assertSee('data-purchase-price-sync-state="pending"', false)
->assertSeeText('1688 代发单价尚未完成首次同步')
->assertSeeText('当前仅显示普通商品采购价');
}
public function test_normal_products_page_does_not_treat_initial_sync_as_empty_data(): void
{
$this->grantAdminPermission();
$state = ['status' => 'running'];
$repository = \Mockery::mock(ProductCatalogMirrorRepository::class);
$repository->shouldReceive('available')->once()->andReturnTrue();
$repository->shouldReceive('state')->once()->andReturn($state);
$repository->shouldReceive('syncStatus')->once()->with($state)->andReturn([
'code' => 'initializing',
'lag_minutes' => null,
]);
$repository->shouldReceive('ready')->once()->andReturnFalse();
$repository->shouldNotReceive('paginate');
$this->app->instance(ProductCatalogMirrorRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
]))
->assertOk()
->assertSeeText('普通商品资料正在执行首次全量同步')
->assertSeeText('首次同步中')
->assertDontSeeText('当前镜像中没有普通商品资料。');
}
public function test_normal_products_page_reports_an_unavailable_mirror(): void
{
$this->grantAdminPermission();
$repository = \Mockery::mock(ProductCatalogMirrorRepository::class);
$repository->shouldReceive('available')->once()->andReturnFalse();
$repository->shouldNotReceive('state');
$repository->shouldNotReceive('syncStatus');
$repository->shouldNotReceive('ready');
$repository->shouldNotReceive('paginate');
$this->app->instance(ProductCatalogMirrorRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
]))
->assertOk()
->assertSeeText('共享业务镜像尚未建立')
->assertDontSeeText('当前镜像中没有普通商品资料。');
}
public function test_normal_products_page_keeps_old_rows_visible_after_a_sync_failure(): void
{
$this->grantAdminPermission();
$state = [
'status' => 'failed',
'run_mode' => 'incremental',
'initial_completed_at' => '2026-08-14 21:15:36',
'last_succeeded_at' => '2026-08-15 17:51:03',
'mirror_row_count' => 547217,
];
$repository = \Mockery::mock(ProductCatalogMirrorRepository::class);
$repository->shouldReceive('available')->once()->andReturnTrue();
$repository->shouldReceive('state')->once()->andReturn($state);
$repository->shouldReceive('syncStatus')->once()->with($state)->andReturn([
'code' => 'failed',
'lag_minutes' => 18,
]);
$repository->shouldReceive('ready')->once()->andReturnTrue();
$repository->shouldReceive('paginate')->once()->andReturn([
'data' => [(object) [
'autoid' => 1001,
'i_id' => 'STYLE-OLD',
'sku_id' => 'SKU-OLD',
'name' => '最近成功同步的商品',
'short_name' => null,
'properties_value' => null,
'color' => null,
'sale_price' => 100,
'cost_price' => null,
'purchase_price' => null,
'market_price' => null,
'brand' => null,
'category' => null,
'supplier_name' => null,
'enabled' => 1,
'stock_disabled' => 0,
'modified' => '2026-08-15 17:45:00',
]],
'total' => 1,
]);
$this->app->instance(ProductCatalogMirrorRepository::class, $repository);
$this->loginAs()->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
]))
->assertOk()
->assertSee('data-sync-state="failed"', false)
->assertSeeText('同步失败,显示最近数据')
->assertSeeText('最近成功同步的商品');
}
public function test_normal_products_page_rejects_users_without_sidebar_permission(): void
{
$subject = 'user_' . $this->user->id;
setting()->set('system.sidebar_permissions', json_encode([
'configured' => [$subject],
'subjects' => [
$subject => ['company-management/basic-information'],
],
], JSON_UNESCAPED_UNICODE));
$this->withExceptionHandling()
->loginAs()
->get(route('business.pages.show', [
'section' => 'product-inventory',
'page' => 'normal-products',
]))
->assertForbidden();
}
}