feat: 店铺维度报表无业绩月份列默认隐藏
- 所有店铺当月都没有业绩的销量月份列默认隐藏,仍保留在「筛选字段」中可手动勾选显示 - 无数据月份列计算统一为 columnsWithoutData:收入以 null/空表示无账单、0 算有账单,销量 0 视为无业绩 - 补充单元测试与页面测试;页面测试断言改为只匹配表头标签,避免命中内联样式中的同名字符串
This commit is contained in:
parent
5ef4119a3d
commit
b8175cfb00
@ -152,6 +152,13 @@ SQL);
|
||||
{
|
||||
$filters = StoreReportRepository::requestFilters();
|
||||
$rows = $this->storeReportRows($filters);
|
||||
|
||||
// 所有店铺该月都没有业绩的月份列默认隐藏;「筛选字段」中仍保留勾选项,可手动选出来。
|
||||
request()->attributes->set(
|
||||
'store-report.default_hidden_columns',
|
||||
$this->columnsWithoutData($rows, 'sales_', zeroCountsAsData: false),
|
||||
);
|
||||
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
return ['data' => array_slice($rows, $offset, $perPage), 'total' => count($rows)];
|
||||
@ -299,7 +306,7 @@ SQL);
|
||||
// 所有主体该月收入均为空时,该月份列在页面上默认隐藏;「筛选字段」中仍保留勾选项,可手动选出来。
|
||||
request()->attributes->set(
|
||||
'subject-operating-report.default_hidden_columns',
|
||||
$this->subjectReportColumnsWithoutData($rows),
|
||||
$this->columnsWithoutData($rows, 'income_', zeroCountsAsData: true),
|
||||
);
|
||||
|
||||
$rows = array_values(array_filter($rows, fn (array $row): bool => $this->subjectMatchesFilters($row, $filters)));
|
||||
@ -311,23 +318,28 @@ SQL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 没有数据的月份列:全部主体该月收入都为空(null/空字符串)时才视为没有数据。
|
||||
* 金额为 0 的月份代表当月有账单,不隐藏。
|
||||
* 没有数据的月份列:所有行该月都没有数值时返回该列名,页面据此默认隐藏。
|
||||
*
|
||||
* 收入(income_)以 null/空字符串表示无账单,金额 0 也算有账单;
|
||||
* 销量(sales_)没有空值标记,数值 0 视为当月没有业绩。
|
||||
*
|
||||
* @param array<int,array<string,mixed>> $rows
|
||||
* @return array<int,string>
|
||||
*/
|
||||
private function subjectReportColumnsWithoutData(array $rows): array
|
||||
private function columnsWithoutData(array $rows, string $prefix, bool $zeroCountsAsData): array
|
||||
{
|
||||
$columns = [];
|
||||
|
||||
for ($month = 1; $month <= 12; $month++) {
|
||||
$key = sprintf('income_%02d', $month);
|
||||
$key = sprintf('%s%02d', $prefix, $month);
|
||||
foreach ($rows as $row) {
|
||||
$value = $row[$key] ?? null;
|
||||
if ($value === null || $value === '') {
|
||||
continue;
|
||||
}
|
||||
if (! $zeroCountsAsData && (float) $value === 0.0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
continue 2;
|
||||
}
|
||||
|
||||
@ -1125,12 +1125,17 @@
|
||||
array_filter(explode(',', (string) request('columns', ''))),
|
||||
$directoryColumnNames,
|
||||
));
|
||||
// 主体维度经营报表:没有数据的月份列默认隐藏,仍保留在「筛选字段」中供手动勾选显示。
|
||||
// 主体维度经营报表、店铺维度报表:没有数据的月份列默认隐藏,仍保留在「筛选字段」中供手动勾选显示。
|
||||
$directoryDefaultColumns = $directoryColumnNames;
|
||||
if ($directoryPageKey === 'company-management/subject-operating-report') {
|
||||
$directoryDefaultHiddenColumns = match ($directoryPageKey) {
|
||||
'company-management/subject-operating-report' => request()->attributes->get('subject-operating-report.default_hidden_columns', []),
|
||||
'store-management/store-report' => request()->attributes->get('store-report.default_hidden_columns', []),
|
||||
default => [],
|
||||
};
|
||||
if ((array) $directoryDefaultHiddenColumns !== []) {
|
||||
$directoryDefaultColumns = array_values(array_diff(
|
||||
$directoryColumnNames,
|
||||
(array) request()->attributes->get('subject-operating-report.default_hidden_columns', []),
|
||||
(array) $directoryDefaultHiddenColumns,
|
||||
));
|
||||
}
|
||||
$visibleDirectoryColumns = request()->has('columns') ? $requestedDirectoryColumns : $directoryDefaultColumns;
|
||||
|
||||
@ -177,9 +177,9 @@ class PrototypePageTest extends FeatureTestCase
|
||||
$html = $response->getContent();
|
||||
|
||||
// 没有数据的月份默认隐藏,但表头和「筛选字段」勾选项仍在页面中。
|
||||
$this->assertMatchesRegularExpression('/data-column-key="income_01"[^>]*is-column-hidden/', $html);
|
||||
$this->assertMatchesRegularExpression('/data-column-key="income_02"[^>]*is-column-hidden/', $html);
|
||||
$this->assertDoesNotMatchRegularExpression('/data-column-key="income_03"[^>]*is-column-hidden/', $html);
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="income_01"[^>]*is-column-hidden/', $html);
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="income_02"[^>]*is-column-hidden/', $html);
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="income_03"[^>]*is-column-hidden/', $html);
|
||||
$this->assertStringContainsString('value="income_01" data-directory-query-column', $html);
|
||||
$this->assertStringNotContainsString('value="income_01" data-directory-query-column checked', $html);
|
||||
$this->assertStringContainsString('value="income_03" data-directory-query-column checked', $html);
|
||||
@ -194,8 +194,64 @@ class PrototypePageTest extends FeatureTestCase
|
||||
|
||||
$restored->assertOk();
|
||||
$restoredHtml = $restored->getContent();
|
||||
$this->assertDoesNotMatchRegularExpression('/data-column-key="income_01"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertDoesNotMatchRegularExpression('/data-column-key="income_03"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertMatchesRegularExpression('/data-column-key="income_04"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="income_01"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="income_03"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="income_04"[^>]*is-column-hidden/', $restoredHtml);
|
||||
}
|
||||
|
||||
public function testStoreReportHidesSalesMonthsWithoutDataAndKeepsThemSelectable(): void
|
||||
{
|
||||
$service = Mockery::mock(UpstreamBusinessInformation::class);
|
||||
$service->shouldReceive('paginate')->with('store-management', 'store-report', 50)
|
||||
->andReturnUsing(function (): LengthAwarePaginator {
|
||||
request()->attributes->set(
|
||||
'store-report.default_hidden_columns',
|
||||
['sales_01', 'sales_08'],
|
||||
);
|
||||
|
||||
return new LengthAwarePaginator([(object) [
|
||||
'erp_store_name' => 'ERP测试店铺',
|
||||
'store_name' => '前台测试店铺',
|
||||
'store_id' => 'SHOP-001',
|
||||
'status' => '开店中',
|
||||
'entity' => '测试主体',
|
||||
'company_type' => '普通公司',
|
||||
'period_sales' => 100,
|
||||
'sales_01' => 0,
|
||||
'sales_07' => 100,
|
||||
'sales_08' => 0,
|
||||
]], 1, 50, 1, ['path' => '/']);
|
||||
});
|
||||
$this->app->instance(UpstreamBusinessInformation::class, $service);
|
||||
|
||||
$response = $this->loginAs()->get(route('business.pages.show', [
|
||||
'section' => 'store-management',
|
||||
'page' => 'store-report',
|
||||
]));
|
||||
|
||||
$response->assertOk();
|
||||
$html = $response->getContent();
|
||||
|
||||
// 没有业绩的月份默认隐藏,但表头和「筛选字段」勾选项仍在页面中。
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="sales_01"[^>]*is-column-hidden/', $html);
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="sales_08"[^>]*is-column-hidden/', $html);
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="sales_07"[^>]*is-column-hidden/', $html);
|
||||
$this->assertStringContainsString('value="sales_01" data-directory-query-column', $html);
|
||||
$this->assertStringNotContainsString('value="sales_01" data-directory-query-column checked', $html);
|
||||
$this->assertStringContainsString('value="sales_07" data-directory-query-column checked', $html);
|
||||
$this->assertStringContainsString('筛选字段 24/26', $html);
|
||||
|
||||
// 手动勾选(columns 参数)后,对应月份列恢复显示。
|
||||
$restored = $this->get(route('business.pages.show', [
|
||||
'section' => 'store-management',
|
||||
'page' => 'store-report',
|
||||
'columns' => 'erp_store_name,store_name,store_id,status,entity,period_sales,sales_01,sales_07',
|
||||
]));
|
||||
|
||||
$restored->assertOk();
|
||||
$restoredHtml = $restored->getContent();
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="sales_01"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertDoesNotMatchRegularExpression('/<th[^>]*data-column-key="sales_07"[^>]*is-column-hidden/', $restoredHtml);
|
||||
$this->assertMatchesRegularExpression('/<th[^>]*data-column-key="sales_08"[^>]*is-column-hidden/', $restoredHtml);
|
||||
}
|
||||
}
|
||||
|
||||
@ -238,6 +238,36 @@ class StoreReportRepositoryTest extends TestCase
|
||||
$this->assertSame(60.0, $paginator->items()[0]->period_sales);
|
||||
}
|
||||
|
||||
public function test_store_report_hides_sales_months_without_data_by_default(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-09-15 10:00:00');
|
||||
$this->insertBill('店铺A', '2026-07-05', 60);
|
||||
$mirror = Mockery::mock(BusinessInformationMirrorRepository::class);
|
||||
$mirror->shouldReceive('ready')->with('store-information.read')->andReturnTrue();
|
||||
$mirror->shouldReceive('allStores')->once()->andReturn([[
|
||||
'erp_store_name' => '店铺A', 'company_name' => '主体甲', 'store_status' => '0',
|
||||
]]);
|
||||
$accounts = Mockery::mock(StoreAccountMirrorRepository::class);
|
||||
$accounts->shouldReceive('ownershipByStoreName')->andReturn([]);
|
||||
$service = new UpstreamBusinessInformation(
|
||||
Mockery::mock(UpstreamQueryCacheFactory::class),
|
||||
$mirror,
|
||||
Mockery::mock(InstallationDetailMirrorRepository::class),
|
||||
$this->repository,
|
||||
$accounts,
|
||||
);
|
||||
|
||||
$paginator = $service->paginate('store-management', 'store-report', 50);
|
||||
|
||||
// 只有 7 月有业绩,其余月份列默认隐藏。
|
||||
$this->assertSame(
|
||||
['sales_01', 'sales_02', 'sales_03', 'sales_04', 'sales_05', 'sales_06', 'sales_08', 'sales_09', 'sales_10', 'sales_11', 'sales_12'],
|
||||
$this->app['request']->attributes->get('store-report.default_hidden_columns'),
|
||||
);
|
||||
$this->assertSame(1, $paginator->total());
|
||||
$this->assertSame(60.0, (float) $paginator->items()[0]->sales_07);
|
||||
}
|
||||
|
||||
public function test_subject_operating_report_aggregates_income_by_entity(): void
|
||||
{
|
||||
Carbon::setTestNow('2026-09-01 10:00:00');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user