feat(reimbursement-small-team-form-validation): 完善小团队报销填报校验

这个提交包含在:
2026-08-04 23:28:56 +08:00
父节点 f33c67eb20
当前提交 50c14c1b85
共修改 28 个文件,包含 1095 行新增和 30 行删除
+34 -4
查看文件
@@ -928,12 +928,12 @@ function parseItemBody(body) {
}
const amountNumber = Number(parsed.data.amount);
if (!Number.isFinite(amountNumber) || amountNumber < 0) {
if (!Number.isFinite(amountNumber) || amountNumber <= 0) {
throw new AppError({
code: "VALID_001",
message: "参数校验失败",
statusCode: 400,
details: { amount: "invalid" },
details: { amount: "must_be_positive" },
});
}
@@ -3712,12 +3712,12 @@ async function reimbursementRoutes(fastify) {
if (typeof parsedBody.data.amount === "string") {
const amountNumber = Number(parsedBody.data.amount);
if (!Number.isFinite(amountNumber) || amountNumber < 0) {
if (!Number.isFinite(amountNumber) || amountNumber <= 0) {
throw new AppError({
code: "VALID_001",
message: "参数校验失败",
statusCode: 400,
details: { amount: "invalid" },
details: { amount: "must_be_positive" },
});
}
}
@@ -3952,6 +3952,36 @@ async function reimbursementRoutes(fastify) {
});
}
const reimbursementItems = await tx.reimbursementItem.findMany({
where: { reimbursement_id: reimbursementId },
orderBy: [{ created_at: "asc" }, { id: "asc" }],
select: { id: true, amount: true },
});
if (!reimbursementItems.length) {
throw new AppError({
code: "VALID_001",
message: "参数校验失败",
statusCode: 400,
details: { items: "at_least_one_required" },
});
}
const invalidAmountItems = reimbursementItems
.filter((item) => !Number.isFinite(Number(item.amount)) || Number(item.amount) <= 0)
.map((item) => item.id);
if (invalidAmountItems.length) {
throw new AppError({
code: "VALID_001",
message: "参数校验失败",
statusCode: 400,
details: { items: "positive_amount_required", itemIds: invalidAmountItems },
});
}
reimbursement.total_amount = await recomputeTotalAmount(
tx,
reimbursementId,
request.employee.id,
);
ensureNonNegativeAmount(reimbursement.total_amount);
const travelItem = await tx.reimbursementItem.findFirst({