feat(energy): integrate self-operated station customers and receipts
ci/woodpecker/push/woodpecker Pipeline was canceled
ci/woodpecker/push/woodpecker Pipeline was canceled
Co-authored-by: HiFox Agent <agents-noreply@hifox.com>
This commit is contained in:
@@ -588,6 +588,99 @@ test("单站看板过滤非指定零业务站并合并区间现结流水", async
|
||||
assert.match(calls[4].sql, /GROUP BY DATE_FORMAT\(payment_date/);
|
||||
});
|
||||
|
||||
test("单站外部客户按唯一标准化车牌聚合,进账保持租户客户级口径", async () => {
|
||||
const calls: QueryCall[] = [];
|
||||
const stationBoardApp = new Hono();
|
||||
registerHydrogenStationBoardRoute(stationBoardApp, {
|
||||
hydrogenPool: {
|
||||
query: createQueryMock(
|
||||
[
|
||||
[{ id: 341, name: "佛山南海羚牛加氢站", province: "广东省", city: "佛山市", kg: 10, fee: 300, recordCount: 1 }],
|
||||
[], [], [], [],
|
||||
[], [], [],
|
||||
[
|
||||
{
|
||||
month: "2026-09",
|
||||
customerName: "外部客户 A",
|
||||
kg: null,
|
||||
fee: null,
|
||||
recordCount: 1,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
id: "auto:9007199254740993",
|
||||
date: "2026-09-05",
|
||||
customerName: "外部客户 A",
|
||||
amount: 200,
|
||||
payMethod: "wechat",
|
||||
source: "spot_daily_auto",
|
||||
sourceRecordCount: 2,
|
||||
updatedAt: "2026-09-05 23:59:00",
|
||||
},
|
||||
{
|
||||
id: "manual:1",
|
||||
date: "2026-09-04",
|
||||
customerName: "外部客户 B",
|
||||
amount: 0,
|
||||
payMethod: "corporate",
|
||||
source: "external_recharge_manual",
|
||||
sourceRecordCount: 1,
|
||||
updatedAt: null,
|
||||
},
|
||||
],
|
||||
],
|
||||
calls,
|
||||
),
|
||||
},
|
||||
cached: createCachedMock([]),
|
||||
} as unknown as HydrogenStationBoardDependencies);
|
||||
|
||||
const response = await stationBoardApp.request(
|
||||
"/hydrogen/station-board?stationId=341&startDate=2026-09-01&endDate=2026-09-05",
|
||||
);
|
||||
assert.equal(response.status, 200);
|
||||
const payload = await response.json();
|
||||
assert.deepEqual(payload.selected.externalCustomerMonths, [{
|
||||
month: "2026-09", customerName: "外部客户 A", kg: 0, fee: 0, recordCount: 1,
|
||||
}]);
|
||||
assert.deepEqual(payload.selected.externalReceipts, {
|
||||
scope: "customer",
|
||||
reason: "当前租户全部外部客户进账,不按站点归属,不计入本单站经营收益或现结 KPI。",
|
||||
rows: [
|
||||
{
|
||||
id: "auto:9007199254740993", date: "2026-09-05", customerName: "外部客户 A", amount: 200,
|
||||
payMethod: "wechat", source: "spot_daily_auto", sourceRecordCount: 2, updatedAt: "2026-09-05 23:59:00",
|
||||
},
|
||||
{
|
||||
id: "manual:1", date: "2026-09-04", customerName: "外部客户 B", amount: 0,
|
||||
payMethod: "corporate", source: "external_recharge_manual", sourceRecordCount: 1, updatedAt: null,
|
||||
},
|
||||
],
|
||||
});
|
||||
assert.equal(calls.length, 10);
|
||||
for (const index of [0, 2, 3, 5, 7, 8, 9]) {
|
||||
assert.match(calls[index].sql, /tenant_id\s*=\s*\?/);
|
||||
assert.ok((calls[index].params as unknown[]).includes("000000"));
|
||||
}
|
||||
for (const index of [0, 2, 3, 5, 7, 8]) {
|
||||
assert.match(calls[index].sql, /record_source, ''\) <> \?/);
|
||||
assert.ok((calls[index].params as unknown[]).includes("external_recharge_manual"));
|
||||
}
|
||||
assert.match(calls[8].sql, /customerCount = 1/);
|
||||
// 自营站客户月度保留全部加氢事实:映射仅做补充,不过滤未匹配或内部车辆。
|
||||
assert.match(calls[7].sql, /LEFT JOIN external_vehicle_map/);
|
||||
assert.match(calls[7].sql, /COALESCE\(m.customerName/);
|
||||
assert.doesNotMatch(calls[7].sql.split('WHERE b.del_flag')[1], /vehicle_id IS NULL/);
|
||||
assert.match(calls[7].sql, /GROUP BY[\s\S]*customerName/);
|
||||
assert.match(calls[8].sql, /CONVERT\(UPPER\(REPLACE/);
|
||||
assert.match(calls[8].sql, /b\.vehicle_id IS NULL OR b\.vehicle_id = 0/);
|
||||
assert.match(calls[9].sql, /UNION ALL/);
|
||||
assert.match(calls[9].sql, /fee_total AS amount/);
|
||||
assert.match(calls[9].sql, /summary_date >= \?/);
|
||||
assert.match(calls[9].sql, /refuel_time < DATE_ADD\(\?, INTERVAL 1 DAY\)/);
|
||||
});
|
||||
|
||||
test("站日现结台账仅读取付款流水,并按最近有数据的 15 天聚合", async () => {
|
||||
const calls: QueryCall[] = [];
|
||||
const cacheCalls: CacheCall[] = [];
|
||||
@@ -807,18 +900,18 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
},
|
||||
]);
|
||||
|
||||
// 指纹来自拆分前的 13 条 SQL,连空白符变化也会使测试失败。
|
||||
// 指纹覆盖加氢事实专用过滤与既有查询结构,避免手工充值重新混入统计。
|
||||
assert.deepEqual(
|
||||
[...hydrogenCalls, ...electricCalls].map((call) => sqlHash(call.sql)),
|
||||
[
|
||||
"515acf4dbb2a",
|
||||
"de16af670e96",
|
||||
"1367eddb3b7f",
|
||||
"f125d4dde376",
|
||||
"c547b8e1318e",
|
||||
"0e3dfd8f4b81",
|
||||
"f1f69f275993",
|
||||
"688cfdb7a2bf",
|
||||
"4fa77c56a990",
|
||||
"ac6329507bc2",
|
||||
"e46a92ba851e",
|
||||
"0295b2deee31",
|
||||
"852b5b0b9fe1",
|
||||
"abad6dcf0b2f",
|
||||
"41cc73632c26",
|
||||
"1224ee38f710",
|
||||
"03fd669f8077",
|
||||
"6e4031b10926",
|
||||
"4fc77463294c",
|
||||
@@ -859,6 +952,9 @@ test("四个处理器继续使用原缓存语义、数据库、SQL 与参数", a
|
||||
],
|
||||
);
|
||||
assert.match(hydrogenCalls[7].sql, /b\.vehicle_id IS NULL/);
|
||||
assert.ok(hydrogenCalls.every((call) =>
|
||||
call.sql.includes("external_recharge_manual"),
|
||||
));
|
||||
assert.deepEqual(
|
||||
electricCalls.map((call) => call.params),
|
||||
[undefined, undefined, undefined, undefined, ["2025-01-01", "2025-01-02"]],
|
||||
|
||||
Reference in New Issue
Block a user