fix: 修复薪资编辑保存失败 + 应发计算丢失细化字段

两个问题:
1. 编辑保存 422 错误:updateEntrySchema 要求 min(0),但 bonus
   可能为负数(如扣款),导致 Zod 验证失败。放宽为 z.number().optional()
2. 应发不随编辑变化:编辑条目时 inputs 只合并 5 个基本字段,
   丢失了 positionSalary/performanceSalary 等细化字段,
   导致 calcBatchEntry 计算的 totalPay 不包含细化薪资项。
   修复:从 entry 中补全所有细化字段

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
selfrelease
2026-08-16 14:19:43 +08:00
parent ea2dfe3b4b
commit 2875965113
+18 -10
View File
@@ -520,15 +520,15 @@ router.post('/batches', async (req: AuthRequest, res: Response, next: NextFuncti
// 编辑批次条目(计算依据项 + 社保公积金手动覆盖) // 编辑批次条目(计算依据项 + 社保公积金手动覆盖)
const updateEntrySchema = z.object({ const updateEntrySchema = z.object({
baseSalary: z.number().min(0).optional(), baseSalary: z.number().optional(),
overtimePay: z.number().min(0).optional(), overtimePay: z.number().optional(),
allowance: z.number().min(0).optional(), allowance: z.number().optional(),
deduction: z.number().min(0).optional(), deduction: z.number().optional(),
bonus: z.number().min(0).optional(), bonus: z.number().optional(),
socialEmp: z.number().min(0).optional(), socialEmp: z.number().optional(),
socialOrg: z.number().min(0).optional(), socialOrg: z.number().optional(),
housingEmp: z.number().min(0).optional(), housingEmp: z.number().optional(),
housingOrg: z.number().min(0).optional(), housingOrg: z.number().optional(),
}) })
router.put('/batches/:batchId/entries/:employeeId', async (req: AuthRequest, res: Response, next: NextFunction) => { router.put('/batches/:batchId/entries/:employeeId', async (req: AuthRequest, res: Response, next: NextFunction) => {
@@ -546,13 +546,21 @@ router.put('/batches/:batchId/entries/:employeeId', async (req: AuthRequest, res
}) })
if (!entry) return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '条目不存在' } }) if (!entry) return res.status(404).json({ success: false, error: { code: 'NOT_FOUND', message: '条目不存在' } })
// 合并输入项 // 合并输入项(包含细化薪资字段,避免编辑时丢失岗位工资/绩效工资等)
const inputs = { const inputs = {
baseSalary: data.baseSalary ?? entry.baseSalary, baseSalary: data.baseSalary ?? entry.baseSalary,
overtimePay: data.overtimePay ?? entry.overtimePay, overtimePay: data.overtimePay ?? entry.overtimePay,
allowance: data.allowance ?? entry.allowance, allowance: data.allowance ?? entry.allowance,
deduction: data.deduction ?? entry.deduction, deduction: data.deduction ?? entry.deduction,
bonus: data.bonus ?? entry.bonus, bonus: data.bonus ?? entry.bonus,
positionSalary: entry.positionSalary || undefined,
performanceSalary: entry.performanceSalary || undefined,
senioritySalary: entry.senioritySalary || undefined,
transportAllowance: entry.transportAllowance || undefined,
mealAllowance: entry.mealAllowance || undefined,
housingAllowance: entry.housingAllowance || undefined,
communicationAllowance: entry.communicationAllowance || undefined,
otherDeduction: entry.otherDeduction || undefined,
} }
// 构建社保覆盖参数(如果请求中包含社保字段) // 构建社保覆盖参数(如果请求中包含社保字段)