feat(M08-A): 接入顾客端续费换房分享

This commit is contained in:
Codex
2026-06-25 11:34:23 +08:00
parent a4e13d911e
commit 874b9b8e29
7 changed files with 337 additions and 5 deletions
+42 -2
View File
@@ -1,4 +1,4 @@
import type { FastifyInstance, FastifyReply } from 'fastify';
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { z } from 'zod';
import type { AuthRepository } from '../auth/auth-repository.js';
import { authenticateAccessToken } from '../auth/authenticate.js';
@@ -27,7 +27,8 @@ const noteSchema = z.object({ note: z.string().min(1).max(512) }).strict();
export interface OrderManagementRouteOptions {
repository: Pick<OrderManagementRepository,
'renew' | 'changeRoom' | 'adjustTime' | 'note' | 'cancellationQuote'>;
'renew' | 'changeRoom' | 'adjustTime' | 'note' | 'cancellationQuote'
| 'customerRenew' | 'customerChangeRoom'>;
authRepository: Pick<AuthRepository, 'validateSession'>;
accessControl: { getAccessProfile(tenantId: string, userId: string): Promise<AccessProfile> };
jwtSecret: string;
@@ -36,6 +37,34 @@ export interface OrderManagementRouteOptions {
export async function registerOrderManagementRoutes(
app: FastifyInstance, options: OrderManagementRouteOptions
) {
app.post('/app-api/orders/:orderId/renew', async (request, reply) => {
const auth = await authenticate(request.headers.authorization, options);
const params = paramsSchema.safeParse(request.params);
const body = renewSchema.safeParse(request.body);
if (!auth) return unauthorized(reply, request.traceId);
if (!params.success || !body.success) return invalid(reply, request.traceId);
const actor = customerActor(auth, request);
return handle(reply, request.traceId, async () => ({
code: 0,
data: await options.repository.customerRenew(actor, params.data.orderId, body.data),
traceId: request.traceId
}));
});
app.post('/app-api/orders/:orderId/change-room', async (request, reply) => {
const auth = await authenticate(request.headers.authorization, options);
const params = paramsSchema.safeParse(request.params);
const body = roomSchema.safeParse(request.body);
if (!auth) return unauthorized(reply, request.traceId);
if (!params.success || !body.success) return invalid(reply, request.traceId);
const actor = customerActor(auth, request);
return handle(reply, request.traceId, async () => ({
code: 0,
data: await options.repository.customerChangeRoom(actor, params.data.orderId, body.data),
traceId: request.traceId
}));
});
app.get('/app-api/orders/:orderId/cancellation-quote', async (request, reply) => {
const auth = await authenticate(request.headers.authorization, options);
const params = paramsSchema.safeParse(request.params);
@@ -82,6 +111,17 @@ export async function registerOrderManagementRoutes(
}
}
function customerActor(
auth: { tenantId: string; userId: string; access: AccessProfile },
request: FastifyRequest
): OrderActor {
return {
tenantId: auth.tenantId, userId: auth.userId, actorType: 'USER',
source: 'APP', traceId: request.traceId, ip: request.ip,
userAgent: String(request.headers['user-agent'] ?? ''), access: auth.access
};
}
async function authenticate(
authorization: string | undefined, options: OrderManagementRouteOptions
) {