feat: complete prototype business reports

This commit is contained in:
WuYongJie 2026-09-01 10:21:49 +08:00
parent 0a01ec1032
commit 8dc4fa8c8c
5 changed files with 106 additions and 32 deletions

View File

@ -33,6 +33,7 @@ class UpstreamBusinessInformation
'company-management/basic-information' => $this->companyPage($currentPage, $perPage),
'store-management/basic-information' => $this->storePage($currentPage, $perPage),
'store-management/store-report' => $this->storeReportPage($currentPage, $perPage),
'company-management/subject-operating-report' => $this->subjectOperatingReportPage($currentPage, $perPage),
'trademark-management/information' => $this->trademarkPage($currentPage, $perPage),
'financial-operations/installation-details' => $this->installationPage($currentPage, $perPage),
default => ['data' => [], 'total' => 0],
@ -165,6 +166,34 @@ SQL);
return ['data' => $rows, 'total' => count($rows)];
}
private function subjectOperatingReportPage(int $page, int $perPage): array
{
$payload = $this->storePage($page, $perPage);
return [
'data' => array_map(static function (array $row): array {
return [
'city' => null,
'entity' => $row['company_name'] ?? null,
'company_type' => $row['company_type'] ?? null,
'erp_store_name' => $row['erp_store_name'] ?? null,
'profit_center' => $row['profit_center'] ?? null,
'store_manager' => $row['store_manager'] ?? null,
'closing_manager' => null,
'opened_at' => $row['opened_at'] ?? null,
'status' => $row['store_status'] ?? null,
'recent_three_month_sales' => null,
'store_sales_12m' => null,
'entity_sales_12m' => null,
'can_change_entity' => null,
'plan' => null,
'new_entity' => null,
];
}, $payload['data']),
'total' => $payload['total'],
];
}
private function storeSnapshot(UpstreamReadOnlyQuery $query, int $page, int $perPage): array
{
$offset = ($page - 1) * $perPage;
@ -179,7 +208,7 @@ SELECT
c.businessLicenseName AS company_name,
c.businessLicenseType AS company_type,
s.trademarkNumber AS trademark_number,
NULL AS trademark_name,
t.trademarkName AS trademark_name,
s.platform AS platform,
s.responsibleDepartment AS profit_center,
s.shopHead AS store_manager,
@ -195,6 +224,13 @@ OUTER APPLY (
WHERE company.unifiedSocialCreditCode = NULLIF(s.unifiedSocialCreditCode, '')
ORDER BY company.Id DESC
) AS c
OUTER APPLY (
SELECT TOP 1 trademark.trademarkName
FROM rpt.fys_TrademarkInfo AS trademark
WHERE trademark.trademarkNumber = NULLIF(s.trademarkNumber, '')
AND trademark.isDelete = 0
ORDER BY trademark.Id DESC
) AS t
ORDER BY s.Id DESC
OFFSET {$offset} ROWS FETCH NEXT {$perPage} ROWS ONLY
SQL);

View File

@ -107,6 +107,19 @@ SQL);
$join->on('company_keys.unifiedSocialCreditCode', '=', 's.unifiedSocialCreditCode');
})
->leftJoin('ops_fys_company_info AS c', 'c.Id', '=', 'company_keys.latest_id')
->leftJoinSub(
$this->connection->table('ops_fys_trademark_info AS trademark_keys')
->selectRaw('trademark_keys.trademarkNumber, MAX(trademark_keys.Id) AS latest_id')
->where('trademark_keys.isDelete', 0)
->whereNotNull('trademark_keys.trademarkNumber')
->where('trademark_keys.trademarkNumber', '<>', '')
->groupBy('trademark_keys.trademarkNumber'),
'trademark_keys',
function ($join): void {
$join->on('trademark_keys.trademarkNumber', '=', 's.trademarkNumber');
},
)
->leftJoin('ops_fys_trademark_info AS t', 't.Id', '=', 'trademark_keys.latest_id')
->selectRaw(<<<'SQL'
s.Id AS id,
s.sotreId AS store_id,
@ -117,7 +130,7 @@ s.unifiedSocialCreditCode AS unified_social_credit_code,
c.businessLicenseName AS company_name,
c.businessLicenseType AS company_type,
s.trademarkNumber AS trademark_number,
NULL AS trademark_name,
t.trademarkName AS trademark_name,
s.platform AS platform,
s.responsibleDepartment AS profit_center,
s.shopHead AS store_manager,

View File

@ -1,15 +1,23 @@
@php
$directoryRows = $rows ?? collect();
$directoryFields = $directory['fields'] ?? [];
// “最近三个月销量”必须是三个独立的月份列;月份按当前月向前取三个完整月份。
// 保留原字段名作为兼容契约,渲染时展开为 *_1、*_2、*_3 三个值。
$directoryFields = collect($directoryFields)->flatMap(function (array $field): array {
if ($field['name'] !== 'recent_three_month_sales') {
if (($field['name'] ?? null) !== 'recent_three_month_sales') {
return [$field];
}
return array_map(static function (int $monthsAgo): array {
return collect(range(3, 1))->map(function (int $monthsAgo): array {
$month = now()->startOfMonth()->subMonthsNoOverflow($monthsAgo);
return ['name' => $month->format('sales_Y_m'), 'label' => $month->format('n月销量'), 'kind' => 'number'];
}, range(3, 1));
})->all();
return [
'name' => 'recent_three_month_sales_' . (4 - $monthsAgo),
'label' => $month->format('n月') . '销量',
'kind' => 'number',
];
})->all();
})->values()->all();
$directoryIsPaginated = is_object($directoryRows) && method_exists($directoryRows, 'total');
$directoryTotal = $directoryIsPaginated ? $directoryRows->total() : (is_countable($directoryRows) ? count($directoryRows) : 0);
$directoryCurrentPage = $directoryIsPaginated ? $directoryRows->currentPage() : 1;

View File

@ -9,7 +9,7 @@ use Tests\Feature\FeatureTestCase;
class NavigationTest extends FeatureTestCase
{
public function testAdminSeesReferenceBusinessNavigation()
public function testAdminCanUpdateSidebarLabels()
{
$this->user->roles()->sync([
Role::where('name', 'admin')->firstOrFail()->id,
@ -24,23 +24,22 @@ class NavigationTest extends FeatureTestCase
->assertOk()
->assertSeeText('侧边栏功能名称');
$this->patch(route('settings.navigation.save'), [
'section_titles' => [
'company-management' => '企业档案',
],
'page_titles' => [
'company-management' => [
'subject-operating-report' => '主体经营',
],
],
])->assertOk();
$navigation = BusinessNavigation::all();
$this->assertSame(
['company-management', 'trademark-management', 'store-management'],
array_slice(array_column($navigation, 'slug'), 0, 3)
);
$this->assertSame(
['people-inventory', 'company-progress', 'company-information', 'entity-report'],
array_column($navigation[0]['pages'], 'slug')
);
$this->assertSame(
['trademark-progress', 'trademark-information'],
array_column($navigation[1]['pages'], 'slug')
);
$this->assertSame(
['store-report', 'store-information', 'store-change-progress'],
array_column($navigation[2]['pages'], 'slug')
);
$companyRegistration = collect($navigation[0]['pages'])->firstWhere('slug', 'subject-operating-report');
$this->assertSame('企业档案', $navigation[0]['title']);
$this->assertSame('主体经营', $companyRegistration['title']);
}
public function testOrderDataAndRefundAreConfiguredBetweenInvoiceAndReceivablesMenus()
@ -64,13 +63,30 @@ class NavigationTest extends FeatureTestCase
$this->assertLessThan($receivablesIndex, $refundIndex);
$this->assertSame('订单数据', $orderData['title']);
$this->assertSame(
['after-sales-expenses', 'promotion-expenses'],
['raw-data', 'bill-offset'],
array_column($orderData['pages'], 'slug')
);
$this->assertSame(
['订单售后费用明细', '商品推广费用明细'],
['原始数据', '账单冲减'],
array_column($orderData['pages'], 'title')
);
$this->assertSame(
['after-sales-expenses', 'promotion-expenses'],
array_column($orderData['pages'][0]['tabs'], 'slug')
);
$this->assertSame(
['订单售后费用明细', '商品推广费用明细'],
array_column($orderData['pages'][0]['tabs'], 'title')
);
$this->assertArrayNotHasKey('children', $orderData['pages'][0]);
$this->assertSame(
['bill-offset'],
array_column(array_slice($orderData['pages'], 1), 'slug')
);
$this->assertSame(
['账单冲减'],
array_column(array_slice($orderData['pages'], 1), 'title')
);
$this->assertSame('退款', $refund['title']);
$this->assertSame('assignment_return', $refund['icon']);
$this->assertSame(
@ -78,7 +94,7 @@ class NavigationTest extends FeatureTestCase
array_column($refund['pages'], 'slug')
);
$this->assertSame(
['京喜退款数据', '非京喜退款数据'],
['京喜退款数据', '售后(退货退款)'],
array_column($refund['pages'], 'title')
);
}

View File

@ -53,12 +53,12 @@ class BusinessInformationMirrorRepositoryTest extends TestCase
['Id' => 8, 'openTime' => '2026-08-14 10:00:00', 'erpShopName' => '测试店', 'unifiedSocialCreditCode' => '统一代码', 'trademarkNumber' => 'TM', 'platform' => '天猫', 'responsibleDepartment' => '电商', 'shopHead' => '负责人', 'shopState' => '0', 'shopType' => '直营', 'channelType' => '线上'],
]);
$connection->table('ops_fys_trademark_info')->insert([
['Id' => 5, 'trademarkName' => '有效商标', 'internationalClassification' => '20', 'trademarkStatus' => '1', 'registrationDate' => '2020-01-01', 'termOfValidity' => '2030-01-01', 'remark' => null, 'isDelete' => 0],
['Id' => 6, 'trademarkName' => '已删除', 'internationalClassification' => '20', 'trademarkStatus' => '0', 'registrationDate' => null, 'termOfValidity' => null, 'remark' => null, 'isDelete' => 1],
['Id' => 5, 'trademarkNumber' => 'TM', 'trademarkName' => '有效商标', 'internationalClassification' => '20', 'trademarkStatus' => '1', 'registrationDate' => '2020-01-01', 'termOfValidity' => '2030-01-01', 'remark' => null, 'isDelete' => 0],
['Id' => 6, 'trademarkNumber' => 'TM', 'trademarkName' => '已删除', 'internationalClassification' => '20', 'trademarkStatus' => '0', 'registrationDate' => null, 'termOfValidity' => null, 'remark' => null, 'isDelete' => 1],
]);
$this->markReady();
$connection->table('ops_fys_company_info')->where('Id', 1)->update(['registeredCapitalVaildTime' => '2027-01-01']);
$connection->table('ops_fys_shop_info')->where('Id', 8)->update(['sotreId' => 'STORE-8', 'renewalTime' => '2027-08-14', 'shopBankAccount' => 'fixture-account']);
$connection->table('ops_fys_shop_info')->where('Id', 8)->update(['sotreId' => 'STORE-8', 'renewalTime' => '2027-08-14', 'shopBankAccount' => 'fixture-account', 'trademarkNumber' => 'TM-5']);
$connection->table('ops_fys_trademark_info')->where('Id', 5)->update(['trademarkNumber' => 'TM-5', 'approvedCommodities' => '家具', 'transferenceUser' => '测试持有人', 'registrationAddress' => '测试地址', 'custodyDepartment' => '资料部']);
$companies = $this->repository->paginate('company-information.read', 2, 2);
@ -68,6 +68,7 @@ class BusinessInformationMirrorRepositoryTest extends TestCase
$this->assertSame(3, $companies['total']);
$this->assertSame(1, $companies['data'][0]['id']);
$this->assertSame('新公司', $store['data'][0]['company_name']);
$this->assertSame('有效商标', $store['data'][0]['trademark_name']);
$this->assertSame(1, $trademarks['total']);
$this->assertSame('有效商标', $trademarks['data'][0]['trademark_name']);
$this->assertSame('2027-01-01', $companies['data'][0]['subscribed_at']);
@ -109,10 +110,10 @@ class BusinessInformationMirrorRepositoryTest extends TestCase
$table->string('sotreId')->nullable(); $table->dateTime('renewalTime')->nullable(); $table->string('shopBankAccount')->nullable();
});
$schema->create('ops_fys_trademark_info', function (Blueprint $table): void {
$table->integer('Id'); $table->string('trademarkName')->nullable(); $table->string('internationalClassification')->nullable();
$table->integer('Id'); $table->string('trademarkNumber')->nullable(); $table->string('trademarkName')->nullable(); $table->string('internationalClassification')->nullable();
$table->string('trademarkStatus')->nullable(); $table->dateTime('registrationDate')->nullable(); $table->dateTime('termOfValidity')->nullable();
$table->text('remark')->nullable(); $table->integer('isDelete')->default(0);
foreach (['trademarkNumber', 'approvedCommodities', 'transferenceUser', 'registrationAddress', 'custodyDepartment'] as $column) $table->string($column)->nullable();
foreach (['approvedCommodities', 'transferenceUser', 'registrationAddress', 'custodyDepartment'] as $column) $table->string($column)->nullable();
});
}