feat(M10-B): 完成可复算经营报表与日汇总
This commit is contained in:
@@ -24,11 +24,11 @@ if (!distOnly) {
|
||||
assert.doesNotMatch(app, /import\s+(?!AdminLoginPanel\b)\w+Panel\s+from/);
|
||||
|
||||
const router = read('admin/src/router.ts');
|
||||
for (const path of ['/overview', '/stores', '/orders', '/products', '/notifications', '/payments', '/third-party',
|
||||
for (const path of ['/overview', '/stores', '/orders', '/products', '/notifications', '/reports', '/payments', '/third-party',
|
||||
'/people', '/cleaning', '/devices', '/apps', '/content', '/franchise', '/system']) {
|
||||
assert.match(read('admin/src/navigation.mjs'), new RegExp(`path: '${path.replace('/', '\\/')}'`));
|
||||
}
|
||||
assert.equal((router.match(/\(\) => import\('/g) || []).length, 14);
|
||||
assert.equal((router.match(/\(\) => import\('/g) || []).length, 15);
|
||||
assert.match(router, /router\.beforeEach/);
|
||||
assert.match(router, /isNavigationAllowed/);
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ for (const pattern of [
|
||||
assert.doesNotMatch(app, /import\s+(?!AdminLoginPanel\b)\w+Panel\s+from/);
|
||||
|
||||
const router = read('admin/src/router.ts');
|
||||
assert.equal((router.match(/\(\) => import\('/g) || []).length, 14);
|
||||
assert.equal((router.match(/\(\) => import\('/g) || []).length, 15);
|
||||
assert.match(router, /router\.beforeEach/);
|
||||
const navigation = read('admin/src/navigation.mjs');
|
||||
for (const path of ['/overview', '/stores', '/orders', '/products', '/payments', '/third-party', '/people',
|
||||
'/cleaning', '/notifications', '/devices', '/apps', '/content', '/franchise', '/system']) assert.ok(navigation.includes(`path: '${path}'`));
|
||||
'/cleaning', '/notifications', '/reports', '/devices', '/apps', '/content', '/franchise', '/system']) assert.ok(navigation.includes(`path: '${path}'`));
|
||||
|
||||
const cleaningWorkspace = read('admin/src/components/CleaningWorkspace.vue');
|
||||
for (const pattern of ['CleaningTasksPanel', 'CleaningSettlementsPanel', 'CleaningStatisticsPanel',
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const root = dirname(dirname(fileURLToPath(import.meta.url)));
|
||||
const read = (path) => readFileSync(join(root, path), 'utf8');
|
||||
const service = read('backend/src/operations/business-report-service.ts');
|
||||
const routes = read('backend/src/routes/business-statistics.ts');
|
||||
const worker = read('backend/src/tasks/worker.ts');
|
||||
const migration = read('database/migrations/2026081111_m10b_business_reports.up.sql');
|
||||
const panel = read('admin/src/components/BusinessReportsPanel.vue');
|
||||
const navigation = read('admin/src/navigation.mjs');
|
||||
|
||||
for (const token of [
|
||||
'roomGrossCents', 'roomRefundCents', 'productGrossCents', 'productRefundCents',
|
||||
'cleaningCostCents', 'usedMinutes', 'capacityMinutes', 'utilizationBasisPoints',
|
||||
'zonedDateStart', 'sourceChecksum', 'reconciliation', 'enqueueDueAggregations'
|
||||
]) assert.ok(service.includes(token), `Missing report service contract: ${token}`);
|
||||
assert.ok(service.includes("'PARTIALLY_REFUNDED', 'REFUNDED'"));
|
||||
for (const channel of ['WECHAT', 'BALANCE', 'PACKAGE', 'GROUP_BUY', 'OTHER']) {
|
||||
assert.ok(service.includes(`'${channel}'`), `Missing payment channel: ${channel}`);
|
||||
}
|
||||
for (const path of [
|
||||
'/admin-api/reports/business', '/admin-api/reports/business/export',
|
||||
'/admin-api/reports/business/rebuild'
|
||||
]) assert.ok(routes.includes(path), `Missing report route: ${path}`);
|
||||
assert.ok(routes.includes('text/csv; charset=utf-8'));
|
||||
assert.ok(worker.includes("['statistics.aggregate'"));
|
||||
assert.ok(worker.includes('reports.enqueueDueAggregations()'));
|
||||
assert.ok(migration.includes('qipai_business_daily_summaries'));
|
||||
for (const permission of ['report.read', 'report.export', 'report.manage']) assert.ok(migration.includes(permission));
|
||||
for (const label of ['今日', '近 7 日', '全部授权门店', '重算日汇总', '经营明细']) assert.ok(panel.includes(label));
|
||||
assert.ok(navigation.includes("menuKey: 'reports'"));
|
||||
|
||||
console.log('PASS: M10-B timezone reporting, refunds, usage, channels, daily reconciliation and export gates are present.');
|
||||
@@ -50,6 +50,8 @@ node scripts/check-m09-regression.mjs
|
||||
Assert-NativeSuccess "check-m09-regression"
|
||||
node scripts/check-m10-a-notifications.mjs
|
||||
Assert-NativeSuccess "check-m10-a-notifications"
|
||||
node scripts/check-m10-b-business-reports.mjs
|
||||
Assert-NativeSuccess "check-m10-b-business-reports"
|
||||
|
||||
if (Test-Path "admin/package.json") {
|
||||
Push-Location admin
|
||||
|
||||
@@ -107,6 +107,6 @@ export QIPAI_MYSQL_USER="${username}"
|
||||
export QIPAI_MYSQL_PASSWORD="${password}"
|
||||
export QIPAI_MYSQL_CONNECTION_LIMIT=2
|
||||
|
||||
echo "INFO: MySQL ${mysql_version}; running M01-B through M10-A integration roundtrip in a temporary database."
|
||||
echo "INFO: MySQL ${mysql_version}; running M01-B through M10-B integration roundtrip in a temporary database."
|
||||
npm --prefix backend run test:mysql:migration
|
||||
echo "PASS: M01-B through M10-A live MySQL integration roundtrip completed."
|
||||
echo "PASS: M01-B through M10-B live MySQL integration roundtrip completed."
|
||||
|
||||
Reference in New Issue
Block a user