huminmin
10 小时以前 0bd6994efea85e468c06b58cd0395cd4066d31cd
src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java
@@ -164,91 +164,86 @@
            return; // 或返回空列表,根据业务需求调整
        }
        Long staffId = id.longValue();
        // 社保金额
        BigDecimal socialPersonal = new BigDecimal("0.00");
        // 公积金金额
        BigDecimal fundPersonal = new BigDecimal("0.00");
        // 基本工资
        BigDecimal basicSalary = new BigDecimal("0.00");
        map.put("fundPersonal", fundPersonal); // 公积金
        map.put("socialPersonal", socialPersonal); // 社保金额
        map.put("socialSupplementAmount", BigDecimal.ZERO); // 社保补缴金额
        map.put("basicSalary", basicSalary); // 基本工资
        // 个税金额
        BigDecimal salaryTax = new BigDecimal("0.00");
        map.put("salaryTax", salaryTax);
        // 计件工资
        BigDecimal pieceSalary = new BigDecimal("0.00");
        map.put("pieceSalary", pieceSalary);
        // 计时工资
        BigDecimal hourlySalary = new BigDecimal("0.00");
        map.put("hourlySalary", hourlySalary);
        // 其他收入
        BigDecimal otherIncome = new BigDecimal("0.00");
        map.put("otherIncome", otherIncome);
        // 其他支出
        BigDecimal otherDeduct = new BigDecimal("0.00");
        map.put("otherDeduct", otherDeduct);
        // 应发工资
        BigDecimal grossSalary = new BigDecimal("0.00");
        map.put("grossSalary", grossSalary);
        // 应扣工资
        BigDecimal deductSalary = new BigDecimal("0.00");
        map.put("deductSalary", deductSalary);
        // 实发工资
        BigDecimal netSalary = new BigDecimal("0.00");
        map.put("netSalary", netSalary);
        // 根据排班数据计算白班天数和夜班天数
        BigDecimal dayDays = new BigDecimal("0.00");
        BigDecimal nightDays = new BigDecimal("0.00");
        // 前端传入的可编辑值优先,其余字段由后端统一计算
        boolean hasBasicSalaryInput = hasValue(map, "basicSalary");
        boolean hasDayDaysInput = hasValue(map, "dayDays");
        boolean hasNightDaysInput = hasValue(map, "nightDays");
        boolean hasPieceSalaryInput = hasValue(map, "pieceSalary");
        boolean hasHourlySalaryInput = hasValue(map, "hourlySalary");
        boolean hasSocialPersonalInput = hasValue(map, "socialPersonal");
        boolean hasFundPersonalInput = hasValue(map, "fundPersonal");
        boolean hasSocialSupplementAmountInput = hasValue(map, "socialSupplementAmount");
        BigDecimal basicSalary = getBigDecimal(map, "basicSalary");
        BigDecimal dayDays = getBigDecimal(map, "dayDays");
        BigDecimal nightDays = getBigDecimal(map, "nightDays");
        BigDecimal pieceSalary = getBigDecimal(map, "pieceSalary");
        BigDecimal hourlySalary = getBigDecimal(map, "hourlySalary");
        BigDecimal otherIncome = getBigDecimal(map, "otherIncome");
        BigDecimal otherDeduct = getBigDecimal(map, "otherDeduct");
        BigDecimal socialPersonalInput = getBigDecimal(map, "socialPersonal");
        BigDecimal fundPersonalInput = getBigDecimal(map, "fundPersonal");
        BigDecimal socialSupplementAmountInput = getBigDecimal(map, "socialSupplementAmount");
        BigDecimal socialPersonal = BigDecimal.ZERO;
        BigDecimal fundPersonal = BigDecimal.ZERO;
        BigDecimal salaryTax = BigDecimal.ZERO;
        BigDecimal grossSalary = BigDecimal.ZERO;
        BigDecimal deductSalary = BigDecimal.ZERO;
        BigDecimal netSalary = BigDecimal.ZERO;
        BigDecimal dayDaysInput = dayDays;
        BigDecimal nightDaysInput = nightDays;
        otherIncome = defaultIfNull(otherIncome);
        otherDeduct = defaultIfNull(otherDeduct);
        map.put("socialSupplementAmount", BigDecimal.ZERO);
        // 查询当月排班记录
        List<PersonalShift> shiftList = personalShiftMapper.selectList(new LambdaQueryWrapper<PersonalShift>()
                .eq(PersonalShift::getStaffOnJobId, staffId)
                .like(PersonalShift::getWorkTime, date));
        BigDecimal computedDayDays = BigDecimal.ZERO;
        BigDecimal computedNightDays = BigDecimal.ZERO;
        if (!hasDayDaysInput || !hasNightDaysInput) {
            List<PersonalShift> shiftList = personalShiftMapper.selectList(new LambdaQueryWrapper<PersonalShift>()
                    .eq(PersonalShift::getStaffOnJobId, staffId)
                    .like(PersonalShift::getWorkTime, date));
        if(!CollectionUtils.isEmpty(shiftList)){
            // 收集所有班次配置ID
            List<Integer> configIds = shiftList.stream()
                    .map(PersonalShift::getPersonalAttendanceLocationConfigId)
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(shiftList)){
                // 收集所有班次配置ID
                List<Integer> configIds = shiftList.stream()
                        .map(PersonalShift::getPersonalAttendanceLocationConfigId)
                        .filter(Objects::nonNull)
                        .collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(configIds)){
                // 查询班次配置信息
                List<PersonalAttendanceLocationConfig> configList = personalAttendanceLocationConfigMapper.selectList(
                        new LambdaQueryWrapper<PersonalAttendanceLocationConfig>()
                                .in(PersonalAttendanceLocationConfig::getId, configIds));
                if(!CollectionUtils.isEmpty(configIds)){
                    // 查询班次配置信息
                    List<PersonalAttendanceLocationConfig> configList = personalAttendanceLocationConfigMapper.selectList(
                            new LambdaQueryWrapper<PersonalAttendanceLocationConfig>()
                                    .in(PersonalAttendanceLocationConfig::getId, configIds));
                // 构建班次配置映射
                Map<Integer, String> configMap = configList.stream()
                        .collect(Collectors.toMap(
                                PersonalAttendanceLocationConfig::getId,
                                PersonalAttendanceLocationConfig::getShift,
                                (a, b) -> a));
                    // 构建班次配置映射
                    Map<Integer, String> configMap = configList.stream()
                            .collect(Collectors.toMap(
                                    PersonalAttendanceLocationConfig::getId,
                                    PersonalAttendanceLocationConfig::getShift,
                                    (a, b) -> a));
                // 统计白班和夜班天数
                for (PersonalShift shift : shiftList) {
                    Integer configId = shift.getPersonalAttendanceLocationConfigId();
                    String shiftName = configMap.get(configId);
                    if(shiftName != null){
                        // 根据班次名称判断:包含"白"或"日"为白班,包含"夜"为夜班
                        if(shiftName.contains("白") || shiftName.contains("日")){
                            dayDays = dayDays.add(BigDecimal.ONE);
                        } else if(shiftName.contains("夜")){
                            nightDays = nightDays.add(BigDecimal.ONE);
                    // 统计白班和夜班天数
                    for (PersonalShift shift : shiftList) {
                        Integer configId = shift.getPersonalAttendanceLocationConfigId();
                        String shiftName = configMap.get(configId);
                        if(shiftName != null){
                            // 根据班次名称判断:包含"白"或"日"为白班,包含"夜"为夜班
                            if(shiftName.contains("白") || shiftName.contains("日")){
                                computedDayDays = computedDayDays.add(BigDecimal.ONE);
                            } else if(shiftName.contains("夜")){
                                computedNightDays = computedNightDays.add(BigDecimal.ONE);
                            }
                        }
                    }
                }
            }
        }
        dayDays = hasDayDaysInput ? defaultIfNull(dayDaysInput) : computedDayDays;
        nightDays = hasNightDaysInput ? defaultIfNull(nightDaysInput) : computedNightDays;
        map.put("dayDays", dayDays); // 白班天数
        map.put("nightDays", nightDays); // 夜班天数
        // 查询餐补和夜班补贴
        // 计算餐补(回族特有)和夜班补助
        BigDecimal mealAmount = new BigDecimal("0.00"); // 餐补
        BigDecimal nightAmount = new BigDecimal("0.00"); // 夜班补助
        // 获取餐补和夜班补贴标准(从补贴配置中获取)
        SubsidyConfiguration subsidyConfig = subsidyConfigurationMapper.selectOne(null);
@@ -265,7 +260,17 @@
            return;
        }
        if (!hasBasicSalaryInput) {
            basicSalary = defaultIfNull(staffOnJobDto.getBasicSalary());
        } else {
            basicSalary = defaultIfNull(basicSalary);
        }
        String nation = staffOnJobDto.getNation();
        // 查询餐补和夜班补贴
        // 计算餐补(回族特有)和夜班补助
        BigDecimal mealAmount = new BigDecimal("0.00"); // 餐补
        BigDecimal nightAmount = new BigDecimal("0.00"); // 夜班补助
        if("回族".equals(nation)){
            mealAmount = dayDays.add(nightDays).multiply(mealStandard);
        }
@@ -277,31 +282,37 @@
        map.put("nightAmount", nightAmount); // 夜班补助
        // 调用基本工资
        basicSalary = staffOnJobDto.getBasicSalary();
        map.put("basicSalary", basicSalary);
        // 应发工资(基本工资+餐补+夜班补助+其他收入)
        grossSalary = basicSalary.add(mealAmount).add(nightAmount).add(otherIncome);
        map.put("otherIncome", otherIncome);
        map.put("otherDeduct", otherDeduct);
        // 计时工资 计件工资
        if (!hasPieceSalaryInput || !hasHourlySalaryInput) {
            UserProductionAccountingDto userProductionAccountingDto = new UserProductionAccountingDto();
            userProductionAccountingDto.setUserId(getUidByStaffId(staffId));
            userProductionAccountingDto.setDate(date);
            UserAccountDto byUserId = salesLedgerProductionAccountingService.getByUserId(userProductionAccountingDto);
            if(byUserId != null){
                if (!hasPieceSalaryInput) {
                    pieceSalary = byUserId.getAccountBalance();
                }
                if (!hasHourlySalaryInput) {
                    hourlySalary = byUserId.getAccount();
                }
            }
        }
        map.put("pieceSalary", defaultIfNull(pieceSalary));
        map.put("hourlySalary", defaultIfNull(hourlySalary));
        // 应发工资(基本工资+餐补+夜班补助+计件工资+计时工资+其他收入)
        grossSalary = basicSalary
                .add(mealAmount)
                .add(nightAmount)
                .add(defaultIfNull(pieceSalary))
                .add(defaultIfNull(hourlySalary))
                .add(otherIncome);
        map.put("grossSalary", grossSalary);
        // 实发工资初始值
        netSalary = grossSalary;
        map.put("netSalary", netSalary);
        // 个税金额(无社保版)
        BigDecimal bigDecimal = TaxCalculator.calculateMonthlyTax(basicSalary, socialPersonal, fundPersonal);
        map.put("salaryTax", bigDecimal);
        // 计时工资 计件工资
        UserProductionAccountingDto userProductionAccountingDto = new UserProductionAccountingDto();
        userProductionAccountingDto.setUserId(getUidByStaffId(staffId));
        userProductionAccountingDto.setDate(date);
        UserAccountDto byUserId = salesLedgerProductionAccountingService.getByUserId(userProductionAccountingDto);
        if(byUserId != null){
            map.put("pieceSalary", byUserId.getAccountBalance());
            map.put("hourlySalary", byUserId.getAccount());
            // 应发 实发增加
            grossSalary = grossSalary.add(byUserId.getAccountBalance()).add(byUserId.getAccount());
            map.put("grossSalary", grossSalary);
            netSalary = netSalary.add(byUserId.getAccountBalance()).add(byUserId.getAccount());
            map.put("netSalary", netSalary);
        }
        // 2. 查询该人员对应的社保方案
        List<SchemeApplicableStaff> schemeList = schemeApplicableStaffMapper.selectSchemeByStaffId(staffId);
        if (CollectionUtils.isEmpty(schemeList)) {
@@ -323,32 +334,65 @@
                socialPersonal = socialPersonal.add(amount);
            }
        }
        BigDecimal currentMonthSocialPersonal = hasSocialPersonalInput ? defaultIfNull(socialPersonalInput) : socialPersonal;
        if (!hasSocialPersonalInput) {
            map.put("socialPersonal", currentMonthSocialPersonal);
        }
        BigDecimal resolvedFundPersonal = hasFundPersonalInput ? defaultIfNull(fundPersonalInput) : fundPersonal;
        if (!hasFundPersonalInput) {
            map.put("fundPersonal", resolvedFundPersonal);
        }
        BigDecimal socialSupplementAmount = calculateSocialSupplementAmount(
                staffId,
                staffOnJobDto,
                targetMonth,
                currentScheme,
                currentDetailList,
                socialPersonal
                currentMonthSocialPersonal
        );
        if (socialSupplementAmount.compareTo(BigDecimal.ZERO) > 0) {
            socialPersonal = socialPersonal.add(socialSupplementAmount);
        if (hasSocialSupplementAmountInput) {
            socialSupplementAmount = defaultIfNull(socialSupplementAmountInput);
        }
        map.put("socialPersonal", socialPersonal);
        map.put("fundPersonal", fundPersonal);
        BigDecimal totalSocialPersonal = currentMonthSocialPersonal.add(socialSupplementAmount);
        map.put("socialSupplementAmount", socialSupplementAmount);
        // 个税金额(社保版)
        bigDecimal = TaxCalculator.calculateMonthlyTax(basicSalary, socialPersonal, fundPersonal);
        BigDecimal bigDecimal = TaxCalculator.calculateMonthlyTax(grossSalary, totalSocialPersonal, resolvedFundPersonal);
        map.put("salaryTax", bigDecimal);
        // 应扣工资 = 个税 + 公积金个人 + 社保个人 + 其他支出
        deductSalary = bigDecimal.add(fundPersonal).add(socialPersonal).add(otherDeduct);
        // 应扣工资 = 个税 + 公积金个人 + 社保个人 + 社保补缴 + 其他支出
        deductSalary = bigDecimal.add(resolvedFundPersonal).add(totalSocialPersonal).add(otherDeduct);
        map.put("deductSalary", deductSalary);
        // 实发工资 = 应发工资 - 应扣工资
        netSalary = grossSalary.subtract(deductSalary);
        map.put("netSalary", netSalary);
    }
    private BigDecimal getBigDecimal(Map<String, Object> map, String key) {
        if (map == null || !map.containsKey(key) || map.get(key) == null) {
            return null;
        }
        Object value = map.get(key);
        if (value instanceof BigDecimal) {
            return (BigDecimal) value;
        }
        if (value instanceof Number) {
            return new BigDecimal(value.toString());
        }
        String text = String.valueOf(value).trim();
        if (text.isEmpty()) {
            return null;
        }
        return new BigDecimal(text);
    }
    private boolean hasValue(Map<String, Object> map, String key) {
        return map != null && map.containsKey(key) && map.get(key) != null;
    }
    private BigDecimal defaultIfNull(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
    /**
@@ -473,6 +517,7 @@
    /**
     * 统计员工当年1月到目标月份之前已缴纳的社保个人部分总额
     * 这里同时包含 socialPersonal 和 socialSupplementAmount,避免历史补缴情形被重复计算。
     *
     * 查询逻辑:
     * 1. 根据目标月份获取当年年份前缀(如 "2024-")
@@ -525,8 +570,8 @@
        // 6. 累加社保个人部分金额
        return detailList.stream()
                .map(StaffSalaryDetail::getSocialPersonal)  // 获取社保个人部分
                .filter(Objects::nonNull)
                .map(detail -> defaultZero(detail.getSocialPersonal())
                        .add(defaultZero(detail.getSocialSupplementAmount())))
                .reduce(BigDecimal.ZERO, BigDecimal::add);  // 累加求和
    }