R19/R20: 项目主域进 OA 并打通报销差旅周报待办

这个提交包含在:
2026-03-22 08:34:18 +08:00
父节点 0235ccb968
当前提交 3f9738ac9c
共修改 28 个文件,包含 3236 行新增和 21 行删除
+59
查看文件
@@ -76,6 +76,7 @@ const TRAVEL_SUMMARY_SELECT = {
legal_entity_id: true,
cost_center_id: true,
budget_pool_id: true,
project_id: true,
purpose: true,
trip_type: true,
start_date: true,
@@ -126,6 +127,13 @@ const TRAVEL_SUMMARY_SELECT = {
name: true,
},
},
project: {
select: {
id: true,
project_no: true,
name: true,
},
},
};
const TRAVEL_DETAIL_SELECT = {
@@ -418,6 +426,7 @@ function mapTravelRequestSummary(item) {
legalEntityId: item.legal_entity_id,
costCenterId: item.cost_center_id,
budgetPoolId: item.budget_pool_id ?? null,
projectId: item.project_id ?? null,
purpose: item.purpose,
tripType: item.trip_type,
startDate: toIsoDate(item.start_date),
@@ -456,6 +465,13 @@ function mapTravelRequestSummary(item) {
name: item.budget_pool.name,
}
: null,
project: item.project
? {
id: item.project.id,
projectNo: item.project.project_no,
name: item.project.name,
}
: null,
};
}
@@ -1201,6 +1217,49 @@ async function createTravelRequestsRoutes(fastify) {
},
);
fastify.post(
"/travel-requests/:id/link-project",
{
preHandler: fastify.authenticate,
},
async (request, reply) => {
const gate = await evaluateFeatureFlag({
prisma: fastify.prisma,
config: fastify.config,
flagKey: FEATURE_FLAG_KEYS.projectLinking,
departmentId: request.employee.department_id ?? null,
strictDepartment: false,
});
if (!gate.enabled) {
throw buildValidationError({ featureFlag: "project_linking_v1_disabled", reason: gate.reason }, 409);
}
const travelRequestId = parseUuid(request.params?.id, "id");
const body = parseBody(z.object({ projectId: UUID_SCHEMA.nullable() }).strict(), request.body);
const current = await fastify.prisma.travelRequest.findUnique({
where: { id: travelRequestId },
select: { id: true, applicant_employee_id: true, submitter_id: true, status: true },
});
if (!current) {
throw new AppError({ code: "SYS_404", message: "Not Found", statusCode: 404 });
}
if (!canReadTravelRequest(request, current)) {
throw new AppError({ code: "PERM_001", message: "无权限", statusCode: 403, details: { permission: "travel.view_own" } });
}
const updated = await fastify.prisma.travelRequest.update({
where: { id: travelRequestId },
data: { project_id: body.projectId ?? null, updated_by: request.employee.id },
select: { id: true, project_id: true, project: { select: { id: true, project_no: true, name: true } } },
});
return sendData(reply, request, {
item: {
travelRequestId: updated.id,
projectId: updated.project_id ?? null,
project: updated.project ? { id: updated.project.id, projectNo: updated.project.project_no, name: updated.project.name } : null,
},
});
},
);
fastify.post(
"/travel-requests/:id/withdraw",
{