286 lines
12 KiB
PHP
286 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\EcommerceFinance;
|
|
|
|
use App\Business\UpstreamBusinessInformation;
|
|
use Closure;
|
|
use Mockery;
|
|
use Modules\EcommerceFinance\Repositories\BusinessInformationMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\StoreAccountMirrorRepository;
|
|
use Modules\EcommerceFinance\Repositories\StoreReportRepository;
|
|
use Modules\EcommerceFinance\Services\UpstreamQueryCache;
|
|
use Modules\EcommerceFinance\Services\UpstreamQueryCacheFactory;
|
|
use Tests\TestCase;
|
|
|
|
class UpstreamBusinessInformationTest extends TestCase
|
|
{
|
|
/**
|
|
* @dataProvider businessInformationPages
|
|
*/
|
|
public function test_local_direct_page_resolver_passes_pagination_to_its_fixed_snapshot(
|
|
string $section,
|
|
string $page,
|
|
string $scope,
|
|
): void {
|
|
config(['upstreams.local_configuration.enabled' => true]);
|
|
$cache = new class extends UpstreamQueryCache {
|
|
public array $calls = [];
|
|
|
|
public function __construct()
|
|
{
|
|
}
|
|
|
|
public function remember(string $scope, array $parameters, Closure $resolver): mixed
|
|
{
|
|
$this->calls[] = compact('scope', 'parameters');
|
|
|
|
return $resolver();
|
|
}
|
|
};
|
|
|
|
$caches = new class($cache) extends UpstreamQueryCacheFactory {
|
|
public function __construct(private readonly UpstreamQueryCache $cache)
|
|
{
|
|
}
|
|
|
|
public function forSource(string $source): UpstreamQueryCache
|
|
{
|
|
return $this->cache;
|
|
}
|
|
};
|
|
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->once()->with($scope)->andReturnFalse();
|
|
|
|
$information = new class($caches, $mirror) extends UpstreamBusinessInformation {
|
|
public array $snapshots = [];
|
|
|
|
public function snapshot(string $scope, array $parameters): array
|
|
{
|
|
$this->snapshots[] = compact('scope', 'parameters');
|
|
|
|
return ['data' => [], 'total' => 0];
|
|
}
|
|
};
|
|
|
|
$this->app['request']->merge(['page' => 3]);
|
|
|
|
$paginator = $information->paginate($section, $page, 25);
|
|
$expected = ['scope' => $scope, 'parameters' => ['page' => 3, 'perPage' => 25]];
|
|
|
|
$this->assertSame(3, $paginator->currentPage());
|
|
$this->assertSame($expected, $cache->calls[0]);
|
|
$this->assertSame($expected, $information->snapshots[0]);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider paginatedBusinessInformationPages
|
|
*/
|
|
public function test_ready_business_mirror_is_used_without_registering_a_page_snapshot(
|
|
string $section,
|
|
string $page,
|
|
string $scope,
|
|
): void {
|
|
config(['operations_replica.enabled' => false, 'upstreams.stored_configuration.enabled' => false]);
|
|
$cache = new class extends UpstreamQueryCache {
|
|
public function __construct() {}
|
|
|
|
public function remember(string $scope, array $parameters, Closure $resolver): mixed
|
|
{
|
|
throw new \RuntimeException('镜像就绪后不应再读取分页快照。');
|
|
}
|
|
};
|
|
$caches = new class($cache) extends UpstreamQueryCacheFactory {
|
|
public function __construct(private readonly UpstreamQueryCache $cache) {}
|
|
|
|
public function forSource(string $source): UpstreamQueryCache { return $this->cache; }
|
|
};
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->once()->with($scope)->andReturnTrue();
|
|
$mirror->shouldReceive('paginate')->once()->with($scope, 2, 25, [])->andReturn([
|
|
'data' => [['id' => 10]],
|
|
'total' => 51,
|
|
]);
|
|
|
|
$this->app['request']->merge(['page' => 2]);
|
|
$paginator = (new UpstreamBusinessInformation($caches, $mirror))
|
|
->paginate($section, $page, 25);
|
|
|
|
$this->assertSame(2, $paginator->currentPage());
|
|
$this->assertSame(51, $paginator->total());
|
|
$this->assertSame(10, $paginator->items()[0]->id);
|
|
}
|
|
|
|
public function test_store_basic_information_uses_account_owner_and_department_head(): void
|
|
{
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->once()->with('store-information.read')->andReturnTrue();
|
|
$mirror->shouldReceive('allStores')->once()->with([])->andReturn([
|
|
[
|
|
'id' => 7,
|
|
'erp_store_name' => '拼多多_测试店铺',
|
|
'store_manager' => '旧店铺负责人',
|
|
'department_manager' => '旧部门负责人',
|
|
'store_status' => '0',
|
|
'platform' => '拼多多',
|
|
],
|
|
[
|
|
'id' => 8,
|
|
'erp_store_name' => '拼多多-其他店铺',
|
|
'store_manager' => '其他负责人',
|
|
'department_manager' => '其他部门负责人',
|
|
'store_status' => '6',
|
|
'platform' => '拼多多',
|
|
],
|
|
]);
|
|
$accounts = Mockery::mock(StoreAccountMirrorRepository::class);
|
|
$accounts->shouldReceive('ownershipByStoreName')->once()->andReturn([
|
|
StoreAccountMirrorRepository::storeNameKey('拼多多-测试店铺') => [
|
|
'operation_owner' => '正确店铺负责人',
|
|
'operation_department_head' => '正确部门负责人',
|
|
'operation_director' => '运营总监',
|
|
'profit_center' => '运营中心A',
|
|
],
|
|
]);
|
|
|
|
$this->app['request']->merge([
|
|
'store_manager' => '正确店铺负责人',
|
|
'department_manager' => '正确部门负责人',
|
|
]);
|
|
$paginator = (new UpstreamBusinessInformation(
|
|
Mockery::mock(UpstreamQueryCacheFactory::class),
|
|
$mirror,
|
|
null,
|
|
$accounts,
|
|
))->paginate('store-management', 'basic-information', 50);
|
|
|
|
$this->assertSame(1, $paginator->total());
|
|
$this->assertSame('正确店铺负责人', $paginator->items()[0]->store_manager);
|
|
$this->assertSame('正确部门负责人', $paginator->items()[0]->department_manager);
|
|
$this->assertNotSame('运营总监', $paginator->items()[0]->department_manager);
|
|
$this->assertSame('正常', $paginator->items()[0]->store_status);
|
|
$summaryCards = collect($this->app['request']->attributes->get('business-page-summary-cards'))->keyBy('label');
|
|
$this->assertSame([], $summaryCards->all());
|
|
}
|
|
|
|
public function test_base_information_pages_do_not_render_summary_cards(): void
|
|
{
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->times(2)->andReturnUsing(
|
|
static fn (string $scope): bool => in_array($scope, ['company-information.read', 'trademark-information.read'], true),
|
|
);
|
|
$mirror->shouldReceive('paginate')->once()->with('company-information.read', 1, 50, [])->andReturn([
|
|
'data' => [],
|
|
'total' => 818,
|
|
'summary' => [
|
|
'total' => 818,
|
|
'normal' => 520,
|
|
'deregistered' => 298,
|
|
'general_taxpayer' => 123,
|
|
'small_taxpayer' => 606,
|
|
],
|
|
]);
|
|
$mirror->shouldReceive('paginate')->once()->with('trademark-information.read', 1, 50, [])->andReturn([
|
|
'data' => [],
|
|
'total' => 593,
|
|
'summary' => [
|
|
'total' => 593,
|
|
'enabled' => 548,
|
|
'disabled' => 45,
|
|
'holders' => 5,
|
|
'departments' => 6,
|
|
],
|
|
]);
|
|
|
|
$information = new UpstreamBusinessInformation(
|
|
Mockery::mock(UpstreamQueryCacheFactory::class),
|
|
$mirror,
|
|
null,
|
|
);
|
|
$information->paginate('company-management', 'basic-information', 50);
|
|
$companyCards = collect($this->app['request']->attributes->get('business-page-summary-cards'))->keyBy('label');
|
|
$this->assertSame([], $companyCards->all());
|
|
|
|
$information->paginate('trademark-management', 'information', 50);
|
|
$trademarkCards = collect($this->app['request']->attributes->get('business-page-summary-cards'))->keyBy('label');
|
|
$this->assertSame([], $trademarkCards->all());
|
|
}
|
|
|
|
public function test_bootstrap_without_mirror_explains_shared_connection_instead_of_requesting_upstream_credentials(): void
|
|
{
|
|
config(['system_database.mode' => 'bootstrap', 'upstreams.local_configuration.enabled' => false]);
|
|
$caches = Mockery::mock(UpstreamQueryCacheFactory::class);
|
|
$caches->shouldNotReceive('forSource');
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->once()->with('store-information.read')->andReturnFalse();
|
|
$this->expectException(\Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException::class);
|
|
$this->expectExceptionMessage('无需另配上游 SQL Server');
|
|
(new UpstreamBusinessInformation($caches, $mirror))
|
|
->paginate('store-management', 'basic-information');
|
|
}
|
|
|
|
public function test_subject_operating_report_hides_income_months_without_data_by_default(): void
|
|
{
|
|
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
|
$mirror->shouldReceive('ready')->with('store-information.read')->andReturnTrue();
|
|
$mirror->shouldReceive('allStores')->andReturn([['erp_store_name' => '测试店铺']]);
|
|
$mirror->shouldReceive('ready')->with('company-information.read')->andReturnTrue();
|
|
$mirror->shouldReceive('companiesByNames')->andReturn([]);
|
|
$mirror->shouldReceive('companyClassificationsByNames')->andReturn([]);
|
|
|
|
$storeReports = Mockery::mock(StoreReportRepository::class);
|
|
$storeReports->shouldReceive('rows')->andReturn([[
|
|
'entity' => '测试主体',
|
|
'company_type' => '店铺-普通公司',
|
|
'rolling_12m_income' => 188.5,
|
|
'income_01' => null,
|
|
'income_02' => 88.5,
|
|
'income_03' => 0.0,
|
|
'income_04' => null,
|
|
'income_05' => null,
|
|
'income_06' => null,
|
|
'income_07' => null,
|
|
'income_08' => null,
|
|
'income_09' => null,
|
|
'income_10' => null,
|
|
'income_11' => null,
|
|
'income_12' => null,
|
|
]]);
|
|
$storeAccounts = Mockery::mock(StoreAccountMirrorRepository::class);
|
|
$storeAccounts->shouldReceive('ownershipByStoreName')->andReturn([]);
|
|
|
|
$information = new UpstreamBusinessInformation(
|
|
Mockery::mock(UpstreamQueryCacheFactory::class),
|
|
$mirror,
|
|
$storeReports,
|
|
$storeAccounts,
|
|
);
|
|
|
|
$paginator = $information->paginate('company-management', 'subject-operating-report', 50);
|
|
|
|
$this->assertSame(
|
|
['income_01', 'income_04', 'income_05', 'income_06', 'income_07', 'income_08', 'income_09', 'income_10', 'income_11', 'income_12'],
|
|
$this->app['request']->attributes->get('subject-operating-report.default_hidden_columns'),
|
|
);
|
|
$this->assertSame(1, $paginator->total());
|
|
$this->assertSame('测试主体', $paginator->items()[0]->entity);
|
|
}
|
|
|
|
public static function businessInformationPages(): array
|
|
{
|
|
return [
|
|
'company' => ['company-management', 'basic-information', 'company-information.read'],
|
|
'store' => ['store-management', 'basic-information', 'store-information.read'],
|
|
'trademark' => ['trademark-management', 'information', 'trademark-information.read'],
|
|
];
|
|
}
|
|
|
|
public static function paginatedBusinessInformationPages(): array
|
|
{
|
|
return [
|
|
'company' => ['company-management', 'basic-information', 'company-information.read'],
|
|
'trademark' => ['trademark-management', 'information', 'trademark-information.read'],
|
|
];
|
|
}
|
|
}
|