gaoluyang
5 天以前 ebe27b0d9f9cf990e34142e79ebc60ab4081f65a
九鸿:工资表所有数值字段支持自动计算后手工调整,保存以页面值为准

- 预览弹窗原先只有加项/扣款可改,现改为标准工资、岗位工资、加班工资(标准)、
安全环保奖(标准)、绩效(标准)、出勤天数/时长、各计算结果、合计、税后工资均可直接修改
- 改某一项时只重算它影响到的合计(构成项→应付工资、加项→加项合计、扣款→扣款合计、
其余→税后工资),不覆盖刚修改的列
- 保存时后端只补空值、不覆盖提交值,避免手工调整的金额被服务端重算掉

Co-Authored-By: Claude Code <noreply@anthropic.com>
已修改1个文件
61 ■■■■■ 文件已修改
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-hrm/src/main/java/cn/iocoder/yudao/module/hrm/service/salary/HrmSalaryCalculationServiceImpl.java
@@ -731,21 +731,14 @@
    }
    /**
     * 保存前按九泓工资表口径重算合计,避免前端漏算或旧客户端传入不一致的合计值。
     * 保存前补齐合计字段。
     *
     * 加项合计 = 工龄工资 + 夜班补助 + 学历补贴 + 体检 + 优秀员工奖 + 其他补助 + 部门绩效
     * 扣款合计 = 漏打卡 + 迟到早退 + 其他扣款
     * 税后工资 = 应付工资 + 加项合计 - 扣款合计 - 社保 - 公积金 - 个税
     *
     * 仅当本次记录带有「应付工资」时重算;只有旧字段的老数据保持原样,避免把未维护的新字段清成 0。
     * 工资表的每个数值字段都允许在自动计算后手工调整,因此这里**只补空值、不覆盖提交值**:
     * 前端预览页已经按同口径重算好应付工资/加项合计/扣款合计/税后工资并一起提交,
     * 直接落库才能保住用户手工改过的数;只有字段为空(旧客户端、接口直调)时才按口径补算。
     */
    private void normalizeSalaryTotals(HrmSalaryCalculationDO calculation) {
        if (calculation.getPayableSalary() == null) {
            return;
        }
        // 应付工资 = 标准出勤工资 + 加班工资 + 法定假工资 + 安全环保奖 + 浮动绩效工资
        // 仅当本次记录带新版标准项时重算,避免旧数据(无这些列)被清零
        if (calculation.getStandardAttendancePay() != null) {
        if (calculation.getPayableSalary() == null && calculation.getStandardAttendancePay() != null) {
            calculation.setPayableSalary(nvl(calculation.getStandardAttendancePay())
                    .add(nvl(calculation.getOvertimePay()))
                    .add(nvl(calculation.getLegalHolidayPay()))
@@ -753,25 +746,31 @@
                    .add(nvl(calculation.getFloatingPerformancePay()))
                    .setScale(2, RoundingMode.HALF_UP));
        }
        BigDecimal additionTotal = nvl(calculation.getSeniorityPay())
                .add(nvl(calculation.getNightShiftAllowance()))
                .add(nvl(calculation.getEducationAllowance()))
                .add(nvl(calculation.getHealthCheckAllowance()))
                .add(nvl(calculation.getExcellentEmployeeAward()))
                .add(nvl(calculation.getOtherSubsidy()))
                .add(nvl(calculation.getDeptPerformance()));
        BigDecimal deductionTotal = nvl(calculation.getMissedPunchDeduction())
                .add(nvl(calculation.getLateEarlyDeduction()))
                .add(nvl(calculation.getOtherDeduction()));
        calculation.setAdditionTotal(additionTotal.setScale(2, RoundingMode.HALF_UP));
        calculation.setDeductionTotal(deductionTotal.setScale(2, RoundingMode.HALF_UP));
        calculation.setActualSalary(calculation.getPayableSalary()
                .add(calculation.getAdditionTotal())
                .subtract(calculation.getDeductionTotal())
                .subtract(nvl(calculation.getSocialSecurityDeduction()))
                .subtract(nvl(calculation.getHousingFundDeduction()))
                .subtract(nvl(calculation.getTaxDeduction()))
                .setScale(2, RoundingMode.HALF_UP));
        if (calculation.getAdditionTotal() == null) {
            BigDecimal additionTotal = nvl(calculation.getSeniorityPay())
                    .add(nvl(calculation.getNightShiftAllowance()))
                    .add(nvl(calculation.getEducationAllowance()))
                    .add(nvl(calculation.getHealthCheckAllowance()))
                    .add(nvl(calculation.getExcellentEmployeeAward()))
                    .add(nvl(calculation.getOtherSubsidy()))
                    .add(nvl(calculation.getDeptPerformance()));
            calculation.setAdditionTotal(additionTotal.setScale(2, RoundingMode.HALF_UP));
        }
        if (calculation.getDeductionTotal() == null) {
            BigDecimal deductionTotal = nvl(calculation.getMissedPunchDeduction())
                    .add(nvl(calculation.getLateEarlyDeduction()))
                    .add(nvl(calculation.getOtherDeduction()));
            calculation.setDeductionTotal(deductionTotal.setScale(2, RoundingMode.HALF_UP));
        }
        if (calculation.getActualSalary() == null && calculation.getPayableSalary() != null) {
            calculation.setActualSalary(calculation.getPayableSalary()
                    .add(nvl(calculation.getAdditionTotal()))
                    .subtract(nvl(calculation.getDeductionTotal()))
                    .subtract(nvl(calculation.getSocialSecurityDeduction()))
                    .subtract(nvl(calculation.getHousingFundDeduction()))
                    .subtract(nvl(calculation.getTaxDeduction()))
                    .setScale(2, RoundingMode.HALF_UP));
        }
    }
    /**