| | |
| | | import java.time.LocalDate; |
| | | import java.time.LocalDateTime; |
| | | import java.time.YearMonth; |
| | | import java.time.temporal.ChronoUnit; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | BigDecimal totalLeaveDeduction = BigDecimal.ZERO; |
| | | for (HrmLeaveApplicationDO application : leaveApplications) { |
| | | Integer leaveType = application.getLeaveType(); |
| | | BigDecimal duration = application.getDuration() != null ? application.getDuration() : BigDecimal.ZERO; |
| | | // 跨月请假按落在本核算月内的天数折算,避免整条请假被跳过或被重复计入 |
| | | BigDecimal duration = resolveDurationInMonth(application, monthStart, monthEnd); |
| | | BigDecimal deductionRatio = configMap.getOrDefault(leaveType, BigDecimal.ZERO); |
| | | |
| | | // 请假扣款 = 日工资 × 请假天数 × 扣款比例 |
| | |
| | | } |
| | | |
| | | /** |
| | | * 计算一笔请假落在本核算月内的请假时长 |
| | | * |
| | | * 1)请假整段都在本月内:直接取请假单上的时长; |
| | | * 2)请假跨月:按「本月内占用的自然日 / 请假总自然日」折算,例如 10-28 ~ 11-03 共 7 天, |
| | | * 其中 10 月占 4 天,则 10 月核算按 时长 × 4 / 7 计,11 月按 时长 × 3 / 7 计,避免重复或漏算。 |
| | | */ |
| | | private BigDecimal resolveDurationInMonth(HrmLeaveApplicationDO application, |
| | | LocalDateTime monthStart, LocalDateTime monthEnd) { |
| | | BigDecimal duration = application.getDuration() != null ? application.getDuration() : BigDecimal.ZERO; |
| | | LocalDateTime start = application.getStartTime(); |
| | | LocalDateTime end = application.getEndTime(); |
| | | if (start == null || end == null) { |
| | | return duration; |
| | | } |
| | | // 整段都在本月内 |
| | | if (!start.isBefore(monthStart) && !end.isAfter(monthEnd)) { |
| | | return duration; |
| | | } |
| | | long totalDays = ChronoUnit.DAYS.between(start.toLocalDate(), end.toLocalDate()) + 1; |
| | | if (totalDays <= 0) { |
| | | return duration; |
| | | } |
| | | LocalDateTime overlapStart = start.isBefore(monthStart) ? monthStart : start; |
| | | LocalDateTime overlapEnd = end.isAfter(monthEnd) ? monthEnd : end; |
| | | if (overlapStart.isAfter(overlapEnd)) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | long overlapDays = ChronoUnit.DAYS.between(overlapStart.toLocalDate(), overlapEnd.toLocalDate()) + 1; |
| | | return duration.multiply(BigDecimal.valueOf(overlapDays)) |
| | | .divide(BigDecimal.valueOf(totalDays), 4, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | /** |
| | | * 汇总当月审批通过的加班申请。小时工资按基本工资 / 21.75 / 8 计算; |
| | | * 工作日默认 1.5 倍、休息日默认 2 倍、法定节假日默认 3 倍,均可由薪酬结构覆盖。 |
| | | */ |