feat(M08-B): 增加保洁结算单和超时回收

This commit is contained in:
Codex
2026-06-26 15:51:50 +08:00
parent 704dca7bcf
commit 2ec4376b1c
16 changed files with 613 additions and 20 deletions
+78 -1
View File
@@ -41,7 +41,10 @@ const app = await buildApp({
return userId === '31'
? {
roles: ['CLEANER'],
capabilities: ['cleaning.task.read', 'cleaning.task.write', 'cleaning.statistics.read'],
capabilities: [
'cleaning.task.read', 'cleaning.task.write', 'cleaning.statistics.read',
'cleaning.settlement.read', 'cleaning.settlement.write'
],
storeIds: ['11']
}
: { roles: ['CUSTOMER'], capabilities: ['profile.read'], storeIds: [] };
@@ -95,6 +98,22 @@ const app = await buildApp({
calls.push(['settlementCandidates', input]);
return { items: [task('COMPLETED')], total: 1, page: input.page, pageSize: input.pageSize };
},
async listSettlements(input) {
calls.push(['listSettlements', input]);
return { items: [settlementResponse(input.status || 'DRAFT')], total: 1, page: input.page, pageSize: input.pageSize };
},
async generateSettlement(input) {
calls.push(['generateSettlement', input]);
return settlementResponse('DRAFT');
},
async confirmSettlement(input) {
calls.push(['confirmSettlement', input]);
return settlementResponse('CONFIRMED');
},
async reclaimTimeouts(input) {
calls.push(['reclaimTimeouts', input]);
return { reclaimed: 2, taskIds: ['101', '102'] };
},
async stats(input) {
calls.push(['stats', input]);
return { byStatus: { SUBMITTED: 2 }, pendingSettlementCents: 1200 };
@@ -232,6 +251,45 @@ const settlement = await app.inject({
assert.equal(settlement.statusCode, 200);
assert.equal(calls.at(-1)[0], 'settlementCandidates');
const settlementList = await app.inject({
method: 'GET',
url: '/admin-api/cleaning/settlements?status=DRAFT',
headers: { authorization: `Bearer ${token}` }
});
assert.equal(settlementList.statusCode, 200);
assert.equal(calls.at(-1)[0], 'listSettlements');
assert.equal(calls.at(-1)[1].status, 'DRAFT');
const generatedSettlement = await app.inject({
method: 'POST',
url: '/admin-api/cleaning/settlements',
headers: { authorization: `Bearer ${token}` },
payload: { cleanerUserId: '31', storeId: '11', note: 'weekly settlement' }
});
assert.equal(generatedSettlement.statusCode, 201);
assert.equal(calls.at(-1)[0], 'generateSettlement');
assert.equal(calls.at(-1)[1].cleanerUserId, '31');
const confirmedSettlement = await app.inject({
method: 'POST',
url: '/admin-api/cleaning/settlements/501/confirm',
headers: { authorization: `Bearer ${token}` },
payload: { note: 'confirmed' }
});
assert.equal(confirmedSettlement.statusCode, 200);
assert.equal(calls.at(-1)[0], 'confirmSettlement');
assert.equal(calls.at(-1)[1].settlementId, '501');
const reclaimed = await app.inject({
method: 'POST',
url: '/admin-api/cleaning/reclaim-timeouts',
headers: { authorization: `Bearer ${token}` },
payload: { olderThanMinutes: 30, limit: 10 }
});
assert.equal(reclaimed.statusCode, 200);
assert.equal(calls.at(-1)[0], 'reclaimTimeouts');
assert.equal(calls.at(-1)[1].olderThanMinutes, 30);
const stats = await app.inject({
method: 'GET',
url: '/app-api/cleaning/stats',
@@ -269,3 +327,22 @@ function task(status) {
photoUrls: []
};
}
function settlementResponse(status) {
return {
id: '501',
settlementNo: 'CLS-20260626-0001',
cleanerUserId: '31',
cleanerName: 'Cleaner',
storeId: '11',
storeName: 'Test Store',
status,
taskCount: 2,
totalRewardCents: 1200,
periodStart: new Date(),
periodEnd: new Date(),
confirmedAt: status === 'CONFIRMED' ? new Date() : null,
paidAt: null,
note: ''
};
}