259 lines
10 KiB
PHP
259 lines
10 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Business;
|
|
|
|
use App\Models\Auth\Permission;
|
|
use Illuminate\Support\Carbon;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Repositories\ThirdPartyWarehouseStorageMirrorRepository;
|
|
use Modules\EcommerceFinance\Services\ThirdPartyWarehouseStorageSettlementService;
|
|
use Tests\Feature\FeatureTestCase;
|
|
|
|
class ThirdPartyWarehouseStoragePageTest extends FeatureTestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$settlement = Mockery::mock(ThirdPartyWarehouseStorageSettlementService::class);
|
|
$settlement->shouldReceive('settle')->zeroOrMoreTimes()->andReturn([
|
|
'ready' => false,
|
|
'complete' => false,
|
|
'message' => null,
|
|
'inbound_fee' => null,
|
|
'outbound_fee' => null,
|
|
'storage_fee' => null,
|
|
'total_fee' => null,
|
|
]);
|
|
$this->app->instance(ThirdPartyWarehouseStorageSettlementService::class, $settlement);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Carbon::setTestNow();
|
|
parent::tearDown();
|
|
}
|
|
|
|
public function test_page_passes_a_daily_period_and_filters_to_the_mirror(): void
|
|
{
|
|
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
|
setting()->set('default.list_limit', 25);
|
|
|
|
$filters = [
|
|
'dimension' => 'day',
|
|
'period' => '2026-08-15',
|
|
'sku_code' => 'BG002950N956V01',
|
|
'product_name' => '餐椅',
|
|
'supplier' => '测试供应商',
|
|
'category' => '家具',
|
|
];
|
|
$repository = Mockery::mock(ThirdPartyWarehouseStorageMirrorRepository::class);
|
|
$repository->shouldReceive('available')->once()->andReturnTrue();
|
|
$repository->shouldReceive('ready')->once()->andReturnTrue();
|
|
$repository->shouldReceive('paginate')->once()->with($filters, 1, 25)->andReturn([
|
|
'data' => [$this->row()],
|
|
'total' => 1,
|
|
'summary' => [
|
|
'count' => 1,
|
|
'opening_qty' => 0,
|
|
'closing_qty' => 10,
|
|
],
|
|
'state' => ['status' => 'succeeded'],
|
|
'sync' => [
|
|
'code' => 'healthy',
|
|
'last_succeeded_at' => '2026-09-11 03:20:00',
|
|
'lag_minutes' => 10,
|
|
],
|
|
]);
|
|
$this->app->instance(ThirdPartyWarehouseStorageMirrorRepository::class, $repository);
|
|
|
|
$this->loginAs();
|
|
$this->get(route('business.pages.show', [
|
|
'section' => 'courier-payables',
|
|
'page' => 'third-party-warehouse-storage',
|
|
]) . '?' . http_build_query($filters))
|
|
->assertOk()
|
|
->assertSee('三方仓进销存')
|
|
->assertSee('查询维度:商品 + 按天')
|
|
->assertSee('value="day" checked', false)
|
|
->assertSee('type="date"', false)
|
|
->assertSee('value="2026-08-15"', false)
|
|
->assertSee('BG002950N956V01')
|
|
->assertSee('测试供应商')
|
|
->assertSee('每日 00:00 自动同步');
|
|
}
|
|
|
|
public function test_invalid_daily_period_falls_back_to_the_previous_complete_day(): void
|
|
{
|
|
Carbon::setTestNow('2026-09-11 16:00:00');
|
|
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
|
|
|
$repository = Mockery::mock(ThirdPartyWarehouseStorageMirrorRepository::class);
|
|
$repository->shouldReceive('available')->once()->andReturnTrue();
|
|
$repository->shouldReceive('ready')->once()->andReturnTrue();
|
|
$repository->shouldReceive('paginate')->once()->with(
|
|
Mockery::on(static fn (array $filters): bool => $filters['dimension'] === 'day'
|
|
&& $filters['period'] === '2026-09-10'),
|
|
1,
|
|
Mockery::type('int'),
|
|
)->andReturn($this->emptyResult());
|
|
$this->app->instance(ThirdPartyWarehouseStorageMirrorRepository::class, $repository);
|
|
|
|
$this->loginAs();
|
|
$this->get(route('business.pages.show', [
|
|
'section' => 'courier-payables',
|
|
'page' => 'third-party-warehouse-storage',
|
|
'dimension' => 'day',
|
|
'period' => '2026-02-31',
|
|
]))->assertOk()
|
|
->assertSee('value="2026-09-10"', false);
|
|
}
|
|
|
|
public function test_period_before_supported_start_date_is_clamped(): void
|
|
{
|
|
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
|
|
|
$repository = Mockery::mock(ThirdPartyWarehouseStorageMirrorRepository::class);
|
|
$repository->shouldReceive('available')->twice()->andReturnTrue();
|
|
$repository->shouldReceive('ready')->twice()->andReturnTrue();
|
|
$repository->shouldReceive('paginate')->once()->with(
|
|
Mockery::on(static fn (array $filters): bool => $filters['dimension'] === 'day'
|
|
&& $filters['period'] === '2026-08-01'),
|
|
1,
|
|
Mockery::type('int'),
|
|
)->andReturn($this->emptyResult());
|
|
$repository->shouldReceive('paginate')->once()->with(
|
|
Mockery::on(static fn (array $filters): bool => $filters['dimension'] === 'month'
|
|
&& $filters['period'] === '2026-08'),
|
|
1,
|
|
Mockery::type('int'),
|
|
)->andReturn($this->emptyResult());
|
|
$this->app->instance(ThirdPartyWarehouseStorageMirrorRepository::class, $repository);
|
|
|
|
$this->loginAs();
|
|
$route = route('business.pages.show', [
|
|
'section' => 'courier-payables',
|
|
'page' => 'third-party-warehouse-storage',
|
|
]);
|
|
$this->get($route . '?dimension=day&period=2026-07-31')
|
|
->assertOk()
|
|
->assertSee('value="2026-08-01"', false);
|
|
$this->get($route . '?dimension=month&period=2026-07')
|
|
->assertOk()
|
|
->assertSee('value="2026-08"', false);
|
|
}
|
|
|
|
public function test_export_keeps_daily_filters_and_only_accepts_declared_fields(): void
|
|
{
|
|
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
|
$filters = [
|
|
'dimension' => 'day',
|
|
'period' => '2026-08-15',
|
|
'sku_code' => 'BG002950N956V01',
|
|
'product_name' => '',
|
|
'supplier' => '',
|
|
'category' => '',
|
|
];
|
|
$repository = Mockery::mock(ThirdPartyWarehouseStorageMirrorRepository::class);
|
|
$repository->shouldReceive('available')->once()->andReturnTrue();
|
|
$repository->shouldReceive('ready')->once()->andReturnTrue();
|
|
$repository->shouldReceive('exportRows')->once()->with($filters)->andReturn((static function (): \Generator {
|
|
yield self::row();
|
|
})());
|
|
$this->app->instance(ThirdPartyWarehouseStorageMirrorRepository::class, $repository);
|
|
|
|
$response = $this->loginAs()->get(route(
|
|
'business.courier-payables.third-party-warehouse-storage.export',
|
|
$filters + ['fields' => 'sku_code,closing_qty,not_allowed'],
|
|
));
|
|
|
|
$response->assertOk();
|
|
$this->assertStringContainsString('text/csv', (string) $response->headers->get('content-type'));
|
|
$content = $response->streamedContent();
|
|
$this->assertStringStartsWith(chr(0xEF) . chr(0xBB) . chr(0xBF), $content);
|
|
$this->assertStringContainsString('商品编码,期末数量', $content);
|
|
$this->assertStringContainsString("'BG002950N956V01,10", $content);
|
|
$this->assertStringNotContainsString('货主', $content);
|
|
$this->assertStringNotContainsString('not_allowed', $content);
|
|
}
|
|
|
|
public function test_page_explains_that_an_uninitialized_mirror_is_not_empty_business_data(): void
|
|
{
|
|
$this->user->attachPermission(Permission::where('name', 'read-admin-panel')->firstOrFail());
|
|
$repository = Mockery::mock(ThirdPartyWarehouseStorageMirrorRepository::class);
|
|
$repository->shouldReceive('available')->once()->andReturnTrue();
|
|
$repository->shouldReceive('ready')->once()->andReturnFalse();
|
|
$repository->shouldReceive('state')->once()->andReturn(['status' => 'pending']);
|
|
$repository->shouldReceive('syncStatus')->once()->andReturn([
|
|
'code' => 'pending',
|
|
'last_succeeded_at' => null,
|
|
'lag_minutes' => null,
|
|
]);
|
|
$repository->shouldNotReceive('paginate');
|
|
$this->app->instance(ThirdPartyWarehouseStorageMirrorRepository::class, $repository);
|
|
|
|
$this->loginAs();
|
|
$this->get(route('business.pages.show', [
|
|
'section' => 'courier-payables',
|
|
'page' => 'third-party-warehouse-storage',
|
|
]))->assertOk()
|
|
->assertSee('首次同步尚未完成')
|
|
->assertSee('不会显示空白数据冒充正式结果');
|
|
}
|
|
|
|
/** @return array<string,mixed> */
|
|
private static function row(): array
|
|
{
|
|
return [
|
|
'owner' => '常州简尚家居有限公司',
|
|
'date' => '2026-08-15',
|
|
'sku_code' => 'BG002950N956V01',
|
|
'image_url' => '',
|
|
'product_name' => '测试餐椅',
|
|
'short_name' => '餐椅',
|
|
'supplier' => '测试供应商',
|
|
'category' => '家具',
|
|
'virtual_category' => '',
|
|
'supplier_style_no' => 'SUP-001',
|
|
'color_spec' => '原木色',
|
|
'brand' => '测试品牌',
|
|
'unit' => '件',
|
|
'opening_qty' => 0,
|
|
'closing_qty' => 10,
|
|
'processing_in' => 0,
|
|
'processing_out' => 0,
|
|
'purchase_in' => 34,
|
|
'purchase_return' => 0,
|
|
'other_in' => 0,
|
|
'other_return' => 0,
|
|
'sales_out' => -24,
|
|
'sales_return' => 0,
|
|
'stocktake' => 0,
|
|
'transfer_out' => 0,
|
|
'transfer_in' => 0,
|
|
'opening_aux' => 0,
|
|
'other_out' => 0,
|
|
];
|
|
}
|
|
|
|
/** @return array<string,mixed> */
|
|
private function emptyResult(): array
|
|
{
|
|
return [
|
|
'data' => [],
|
|
'total' => 0,
|
|
'summary' => [
|
|
'count' => 0,
|
|
'opening_qty' => 0,
|
|
'closing_qty' => 0,
|
|
],
|
|
'state' => ['status' => 'succeeded'],
|
|
'sync' => [
|
|
'code' => 'healthy',
|
|
'last_succeeded_at' => '2026-09-11 03:20:00',
|
|
'lag_minutes' => 10,
|
|
],
|
|
];
|
|
}
|
|
}
|