feat(M08-B): 补保洁结算发放记录
This commit is contained in:
@@ -54,6 +54,17 @@ const settlementGenerateSchema = z.object({
|
||||
const settlementConfirmSchema = z.object({
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const settlementPaidSchema = z.object({
|
||||
payoutChannel: z.string().trim().min(1).max(32),
|
||||
payoutReference: z.string().trim().min(1).max(128),
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const settlementPayoutFailureSchema = z.object({
|
||||
payoutChannel: z.string().trim().max(32).optional(),
|
||||
payoutReference: z.string().trim().max(128).optional(),
|
||||
error: z.string().trim().min(1).max(512),
|
||||
note: z.string().trim().max(512).optional()
|
||||
}).strict();
|
||||
const reclaimSchema = z.object({
|
||||
olderThanMinutes: z.coerce.number().int().min(5).max(1440).default(60),
|
||||
limit: z.coerce.number().int().min(1).max(100).default(20)
|
||||
@@ -63,7 +74,8 @@ export interface CleaningRouteOptions {
|
||||
repository: Pick<CleaningTaskRepository,
|
||||
'listHall' | 'listMine' | 'listManage' | 'claim' | 'start' | 'rework' | 'submit'
|
||||
| 'assign' | 'complete' | 'reject' | 'listMembers' | 'addMember' | 'removeMember' | 'settlementCandidates'
|
||||
| 'listSettlements' | 'generateSettlement' | 'confirmSettlement' | 'reclaimTimeouts'
|
||||
| 'listSettlements' | 'generateSettlement' | 'confirmSettlement' | 'markSettlementPaid'
|
||||
| 'recordSettlementPayoutFailure' | 'reclaimTimeouts'
|
||||
| 'assertCanUploadPhoto' | 'stats'>;
|
||||
mediaStorage?: MediaStorage;
|
||||
authRepository: Pick<AuthRepository, 'validateSession'>;
|
||||
@@ -373,6 +385,45 @@ export async function registerCleaningRoutes(
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
|
||||
app.post('/admin-api/cleaning/settlements/:settlementId/paid', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'write');
|
||||
if (!actor) return;
|
||||
const params = settlementParamsSchema.safeParse(request.params);
|
||||
const body = settlementPaidSchema.safeParse(request.body ?? {});
|
||||
if (!params.success || !body.success) return invalid(reply, request.traceId);
|
||||
return handle(reply, request.traceId, async () => ({
|
||||
code: 0,
|
||||
data: await options.repository.markSettlementPaid({
|
||||
...actor,
|
||||
settlementId: params.data.settlementId,
|
||||
payoutChannel: body.data.payoutChannel,
|
||||
payoutReference: body.data.payoutReference,
|
||||
note: body.data.note
|
||||
}),
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
|
||||
app.post('/admin-api/cleaning/settlements/:settlementId/payout-failure', async (request, reply) => {
|
||||
const actor = await requireActor(request, reply, options, 'write');
|
||||
if (!actor) return;
|
||||
const params = settlementParamsSchema.safeParse(request.params);
|
||||
const body = settlementPayoutFailureSchema.safeParse(request.body ?? {});
|
||||
if (!params.success || !body.success) return invalid(reply, request.traceId);
|
||||
return handle(reply, request.traceId, async () => ({
|
||||
code: 0,
|
||||
data: await options.repository.recordSettlementPayoutFailure({
|
||||
...actor,
|
||||
settlementId: params.data.settlementId,
|
||||
payoutChannel: body.data.payoutChannel,
|
||||
payoutReference: body.data.payoutReference,
|
||||
error: body.data.error,
|
||||
note: body.data.note
|
||||
}),
|
||||
traceId: request.traceId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
async function requireActor(
|
||||
|
||||
Reference in New Issue
Block a user