feat(cleaning): close settlement integrity and reconciliation

This commit is contained in:
Codex
2026-08-11 02:07:59 +08:00
parent 5e0f5e39ee
commit 1f1071501f
23 changed files with 1562 additions and 208 deletions
+41 -1
View File
@@ -160,11 +160,21 @@ const app = await buildApp({
calls.push(['listSettlements', input]);
return { items: [settlementResponse(input.status || 'DRAFT')], total: 1, page: input.page, pageSize: input.pageSize };
},
async exportSettlements(input) {
calls.push(['exportSettlements', input]);
return { items: [settlementResponse(input.status || 'DRAFT')], total: 1, exported: 1, truncated: false };
},
async getSettlementDetail(input) {
calls.push(['getSettlementDetail', input]);
return {
settlement: settlementResponse('DRAFT'),
items: [settlementItemResponse()]
items: [settlementItemResponse()],
events: [{
id: '701', settlementId: input.settlementId, fromStatus: null, toStatus: 'DRAFT',
action: 'GENERATE', actorId: input.userId, traceId: input.traceId,
note: '', createdAt: new Date()
}],
reversals: []
};
},
async generateSettlement(input) {
@@ -175,6 +185,15 @@ const app = await buildApp({
calls.push(['confirmSettlement', input]);
return settlementResponse('CONFIRMED');
},
async cancelSettlement(input) {
calls.push(['cancelSettlement', input]);
return {
...settlementResponse('CANCELLED'),
cancelledBy: input.userId,
cancelledAt: new Date(),
note: input.reason
};
},
async markSettlementPaid(input) {
calls.push(['markSettlementPaid', input]);
return {
@@ -385,6 +404,16 @@ assert.equal(calls.at(-1)[1].status, 'SUBMITTED');
assert.equal(calls.at(-1)[1].storeId, '11');
assert.equal(calls.at(-1)[1].cleanerUserId, '31');
const settlementExport = await app.inject({
method: 'GET',
url: '/admin-api/cleaning/settlements/export?status=DRAFT&payoutState=FAIL&storeId=11&cleanerUserId=31',
headers: { authorization: `Bearer ${token}` }
});
assert.equal(settlementExport.statusCode, 200);
assert.equal(calls.at(-1)[0], 'exportSettlements');
assert.equal(calls.at(-1)[1].status, 'DRAFT');
assert.equal(settlementExport.json().data.exported, 1);
const appManageList = await app.inject({
method: 'GET',
url: '/app-api/management/cleaning/tasks?status=SUBMITTED&storeId=11',
@@ -643,6 +672,17 @@ assert.equal(confirmedSettlement.statusCode, 200);
assert.equal(calls.at(-1)[0], 'confirmSettlement');
assert.equal(calls.at(-1)[1].settlementId, '501');
const cancelledSettlement = await app.inject({
method: 'POST',
url: '/admin-api/cleaning/settlements/501/cancel',
headers: { authorization: `Bearer ${token}` },
payload: { reason: 'duplicate weekly batch' }
});
assert.equal(cancelledSettlement.statusCode, 200);
assert.equal(cancelledSettlement.json().data.status, 'CANCELLED');
assert.equal(calls.at(-1)[0], 'cancelSettlement');
assert.equal(calls.at(-1)[1].reason, 'duplicate weekly batch');
const failedPayout = await app.inject({
method: 'POST',
url: '/admin-api/cleaning/settlements/501/payout-failure',