feat(assets): align flow statistics and separate abnormal inventory
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/push/woodpecker Pipeline failed
Use operations signing times and delivery completion statuses; include replacement deliveries in delivery totals with range drilldowns and exports. Separate abnormal vehicles from inventory, add a date range picker, and enable CI for feature/asset-statistics.
This commit is contained in:
@@ -110,7 +110,52 @@ test('keeps weekly detail SQL selection and flow date parameters unchanged', asy
|
||||
{ sql: WEEKLY_DETAIL_SQL.new, values: undefined },
|
||||
{
|
||||
sql: FLOW_STATS_SQL,
|
||||
values: ['2026-08-01', '2026-08-13', '2026-08-01', '2026-08-13', '2026-08-01', '2026-08-13'],
|
||||
values: ['2026-08-01', '2026-08-13', '2026-08-01', '2026-08-13'],
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('flow dates and inclusive day boundaries use operations signing times, retaining creation time only for display', () => {
|
||||
for (const [alias, field] of [['dv', 'delivery_completion_processed_time'], ['r', 'return_completion_processed_time']]) {
|
||||
assert.ok(FLOW_STATS_SQL.includes(`DATE_FORMAT(${alias}.${field}, '%Y-%m-%d') AS stat_date`));
|
||||
assert.ok(FLOW_STATS_SQL.includes(`AND ${alias}.${field} IS NOT NULL`));
|
||||
assert.ok(FLOW_STATS_SQL.includes(`AND ${alias}.${field} >= ?`));
|
||||
assert.ok(FLOW_STATS_SQL.includes(`AND ${alias}.${field} < DATE_ADD(?, INTERVAL 1 DAY)`));
|
||||
assert.ok(FLOW_STATS_SQL.includes(`DATE_FORMAT(${alias}.create_time, '%Y-%m-%d %H:%i:%s') AS submit_time`));
|
||||
}
|
||||
assert.doesNotMatch(FLOW_STATS_SQL, /AND \w+\.create_time/);
|
||||
assert.ok(FLOW_STATS_SQL.includes('ORDER BY flow.event_time DESC, flow.id DESC'));
|
||||
});
|
||||
|
||||
test('flow retains multiple business events for the same vehicle', async () => {
|
||||
const events = [
|
||||
{ id: 'delivered-1', truck_id: '1', type: 'delivered', stat_date: '2026-09-16' },
|
||||
{ id: 'delivered-2', truck_id: '1', type: 'delivered', stat_date: '2026-09-16' },
|
||||
{ id: 'returned-1', truck_id: '1', type: 'returned', stat_date: '2026-09-16' },
|
||||
];
|
||||
const repository = new VehicleRepository(new FakeDatabase([events]));
|
||||
assert.deepEqual(await repository.getFlowDetailRows('2026-09-16', '2026-09-16'), events);
|
||||
});
|
||||
|
||||
|
||||
test('replacement trips come exclusively from linked delivery records', () => {
|
||||
assert.ok(FLOW_STATS_SQL.includes("CASE WHEN dv.vehicle_replacement_id IS NOT NULL THEN 'replaced' ELSE 'delivered' END AS type"));
|
||||
assert.ok(FLOW_STATS_SQL.includes("CASE WHEN dv.vehicle_replacement_id IS NOT NULL THEN '替换交车' ELSE '交车' END AS type_label"));
|
||||
assert.equal((FLOW_STATS_SQL.match(/FROM delivery_vehicle/g) || []).length, 1);
|
||||
assert.doesNotMatch(FLOW_STATS_SQL, /FROM vehicle_replacement|dv\.delivery_time|r\.arrival_time|vr\.replace_time/);
|
||||
});
|
||||
|
||||
test('completed delivery and replacement trips use vehicle status and exclude suspended subjects', () => {
|
||||
const [deliveries, returns] = FLOW_STATS_SQL.split('UNION ALL');
|
||||
assert.ok(deliveries.includes('AND dv.delivery_status IN (2,3,20)'));
|
||||
assert.ok(deliveries.includes('AND (dts.status IS NULL OR dts.status <> 10)'));
|
||||
assert.doesNotMatch(deliveries, /dts\.status\s*(?:=|IN)|dv\.delivery_status IN \(2,3,5\)/);
|
||||
assert.ok(returns.includes('AND r.status IN (2,3,5)'));
|
||||
});
|
||||
|
||||
test('return history includes completed, signed and awaiting-signature statuses without arrival or settlement requirements', () => {
|
||||
const returns = FLOW_STATS_SQL.split('UNION ALL')[1];
|
||||
assert.ok(returns.includes('AND r.status IN (2,3,5)'));
|
||||
assert.ok(returns.includes('AND r.return_completion_processed_time >= ?'));
|
||||
assert.doesNotMatch(returns, /r\.is_arrived|r\.arrival_time|settlement|AND dts\.status|AND \(dts\.status/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user