feat(reimbursement-small-team-form-validation): 完善小团队报销填报校验
这个提交包含在:
@@ -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({
|
||||
|
||||
在新工单中引用
屏蔽一个用户