gaoluyang
2026-11-04 ebe27b0d9f9cf990e34142e79ebc60ab4081f65a
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,6 +746,7 @@
                    .add(nvl(calculation.getFloatingPerformancePay()))
                    .setScale(2, RoundingMode.HALF_UP));
        }
        if (calculation.getAdditionTotal() == null) {
        BigDecimal additionTotal = nvl(calculation.getSeniorityPay())
                .add(nvl(calculation.getNightShiftAllowance()))
                .add(nvl(calculation.getEducationAllowance()))
@@ -760,19 +754,24 @@
                .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.setAdditionTotal(additionTotal.setScale(2, RoundingMode.HALF_UP));
        calculation.setDeductionTotal(deductionTotal.setScale(2, RoundingMode.HALF_UP));
        }
        if (calculation.getActualSalary() == null && calculation.getPayableSalary() != null) {
        calculation.setActualSalary(calculation.getPayableSalary()
                .add(calculation.getAdditionTotal())
                .subtract(calculation.getDeductionTotal())
                    .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));
    }
    }
    /**
     * 内部生成发放台账方法(供自动生成调用)