package cn.iocoder.yudao.module.hrm.service.salary;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSalaryPaymentDetailPageReqVO;
|
import cn.iocoder.yudao.module.hrm.controller.admin.salary.vo.HrmSalaryPaymentPageReqVO;
|
import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryCalculationDO;
|
import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryPaymentDetailDO;
|
import cn.iocoder.yudao.module.hrm.dal.dataobject.salary.HrmSalaryPaymentDO;
|
import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryCalculationMapper;
|
import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryPaymentDetailMapper;
|
import cn.iocoder.yudao.module.hrm.dal.mysql.salary.HrmSalaryPaymentMapper;
|
import cn.iocoder.yudao.module.hrm.dal.redis.HrmNoRedisDAO;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.util.List;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.hrm.enums.ErrorCodeConstants.*;
|
|
/**
|
* 薪资发放 Service 实现类
|
*
|
* @author 芋道源码
|
*/
|
@Service
|
@Validated
|
public class HrmSalaryPaymentServiceImpl implements HrmSalaryPaymentService {
|
|
@Resource
|
private HrmSalaryPaymentMapper salaryPaymentMapper;
|
@Resource
|
private HrmSalaryPaymentDetailMapper salaryPaymentDetailMapper;
|
@Resource
|
private HrmSalaryCalculationMapper salaryCalculationMapper;
|
@Resource
|
private HrmNoRedisDAO noRedisDAO;
|
|
@Override
|
public PageResult<HrmSalaryPaymentDO> getSalaryPaymentPage(HrmSalaryPaymentPageReqVO pageReqVO) {
|
return salaryPaymentMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public HrmSalaryPaymentDO getSalaryPayment(Long id) {
|
return salaryPaymentMapper.selectById(id);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public Long generatePayment(String period) {
|
// 1. 检查是否已存在该周期的发放台账
|
HrmSalaryPaymentDO existPayment = salaryPaymentMapper.selectByPeriod(period);
|
if (existPayment != null) {
|
throw exception(SALARY_PAYMENT_EXISTS);
|
}
|
|
// 2. 查询该周期已确认的薪酬核算记录(状态=10)
|
List<HrmSalaryCalculationDO> calculationList = salaryCalculationMapper.selectListByPeriodAndStatus(period, 10);
|
if (CollUtil.isEmpty(calculationList)) {
|
throw exception(SALARY_CALCULATION_NO_CONFIRMED);
|
}
|
|
// 3. 生成发放台账
|
String no = generatePaymentNo();
|
BigDecimal totalAmount = calculationList.stream()
|
.map(c -> c.getActualSalary() != null ? c.getActualSalary() : BigDecimal.ZERO)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
Integer totalCount = calculationList.size();
|
|
HrmSalaryPaymentDO payment = HrmSalaryPaymentDO.builder()
|
.no(no)
|
.period(period)
|
.totalAmount(totalAmount)
|
.totalCount(totalCount)
|
.status(0) // 待发放
|
.build();
|
salaryPaymentMapper.insert(payment);
|
|
// 4. 生成发放明细(不更新核算状态)
|
for (HrmSalaryCalculationDO calculation : calculationList) {
|
HrmSalaryPaymentDetailDO detail = HrmSalaryPaymentDetailDO.builder()
|
.paymentId(payment.getId())
|
.calculationId(calculation.getId())
|
.userId(calculation.getUserId())
|
.deptId(calculation.getDeptId())
|
.actualSalary(calculation.getActualSalary())
|
.status(0) // 待发放
|
.build();
|
salaryPaymentDetailMapper.insert(detail);
|
}
|
|
return payment.getId();
|
}
|
|
private String generatePaymentNo() {
|
String no = noRedisDAO.generateSalaryPaymentNo();
|
while (salaryPaymentMapper.selectByNo(no) != null) {
|
no = noRedisDAO.generateSalaryPaymentNo();
|
}
|
return no;
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void paySalary(Long id) {
|
// 1. 校验发放台账存在
|
HrmSalaryPaymentDO payment = validateSalaryPaymentExists(id);
|
if (payment.getStatus() != 0) {
|
throw exception(SALARY_PAYMENT_ALREADY_PAY);
|
}
|
|
// 2. 查询待发放的明细
|
List<HrmSalaryPaymentDetailDO> detailList = salaryPaymentDetailMapper.selectListByPaymentIdAndStatus(id, 0);
|
if (CollUtil.isEmpty(detailList)) {
|
throw exception(SALARY_PAYMENT_DETAIL_NO_EXISTS);
|
}
|
|
// 3. 批量发放明细,并更新核算状态
|
LocalDateTime paymentTime = LocalDateTime.now();
|
for (HrmSalaryPaymentDetailDO detail : detailList) {
|
detail.setStatus(10); // 已发放
|
detail.setPaymentTime(paymentTime);
|
salaryPaymentDetailMapper.updateById(detail);
|
|
// 更新薪酬核算状态为已发放(20)
|
HrmSalaryCalculationDO calculation = salaryCalculationMapper.selectById(detail.getCalculationId());
|
if (calculation != null) {
|
calculation.setStatus(20);
|
calculation.setPaymentTime(paymentTime);
|
salaryCalculationMapper.updateById(calculation);
|
}
|
}
|
|
// 4. 更新发放台账状态
|
payment.setStatus(10); // 已发放
|
payment.setPaymentTime(paymentTime);
|
salaryPaymentMapper.updateById(payment);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void paySalaryDetail(List<Long> detailIds) {
|
if (CollUtil.isEmpty(detailIds)) {
|
return;
|
}
|
LocalDateTime paymentTime = LocalDateTime.now();
|
Long paymentId = null;
|
for (Long detailId : detailIds) {
|
HrmSalaryPaymentDetailDO detail = salaryPaymentDetailMapper.selectById(detailId);
|
if (detail == null) {
|
throw exception(SALARY_PAYMENT_DETAIL_NOT_EXISTS);
|
}
|
if (detail.getStatus() != 0) {
|
throw exception(SALARY_PAYMENT_DETAIL_ALREADY_PAY);
|
}
|
detail.setStatus(10); // 已发放
|
detail.setPaymentTime(paymentTime);
|
salaryPaymentDetailMapper.updateById(detail);
|
paymentId = detail.getPaymentId();
|
|
// 更新薪酬核算状态为已发放(20)
|
HrmSalaryCalculationDO calculation = salaryCalculationMapper.selectById(detail.getCalculationId());
|
if (calculation != null) {
|
calculation.setStatus(20);
|
calculation.setPaymentTime(paymentTime);
|
salaryCalculationMapper.updateById(calculation);
|
}
|
}
|
|
// 检查该台账下是否所有明细都已发放,如果是则更新台账状态
|
if (paymentId != null) {
|
updatePaymentStatusIfAllPaid(paymentId);
|
}
|
}
|
|
/**
|
* 检查该台账下是否所有明细都已发放,如果是则更新台账状态为已发放
|
*/
|
private void updatePaymentStatusIfAllPaid(Long paymentId) {
|
// 查询该台账下所有明细
|
List<HrmSalaryPaymentDetailDO> allDetails = salaryPaymentDetailMapper.selectListByPaymentId(paymentId);
|
if (CollUtil.isEmpty(allDetails)) {
|
return;
|
}
|
// 检查是否全部已发放
|
boolean allPaid = allDetails.stream().allMatch(d -> d.getStatus() == 10);
|
if (!allPaid) {
|
return;
|
}
|
// 更新台账状态为已发放
|
HrmSalaryPaymentDO payment = salaryPaymentMapper.selectById(paymentId);
|
if (payment != null && payment.getStatus() == 0) {
|
payment.setStatus(10);
|
payment.setPaymentTime(LocalDateTime.now());
|
salaryPaymentMapper.updateById(payment);
|
}
|
}
|
|
private HrmSalaryPaymentDO validateSalaryPaymentExists(Long id) {
|
HrmSalaryPaymentDO payment = salaryPaymentMapper.selectById(id);
|
if (payment == null) {
|
throw exception(SALARY_PAYMENT_NOT_EXISTS);
|
}
|
return payment;
|
}
|
|
@Override
|
public PageResult<HrmSalaryPaymentDetailDO> getSalaryPaymentDetailPage(HrmSalaryPaymentDetailPageReqVO pageReqVO) {
|
return salaryPaymentDetailMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public List<HrmSalaryPaymentDetailDO> getSalaryPaymentDetailListByPaymentId(Long paymentId) {
|
return salaryPaymentDetailMapper.selectListByPaymentId(paymentId);
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void revokeSalaryPaymentDetail(List<Long> detailIds) {
|
if (CollUtil.isEmpty(detailIds)) {
|
return;
|
}
|
Long paymentId = null;
|
for (Long detailId : detailIds) {
|
HrmSalaryPaymentDetailDO detail = salaryPaymentDetailMapper.selectById(detailId);
|
if (detail == null) {
|
throw exception(SALARY_PAYMENT_DETAIL_NOT_EXISTS);
|
}
|
// 校验状态必须是已发放(10)
|
if (detail.getStatus() != 10) {
|
throw exception(SALARY_PAYMENT_REVOKE_FAIL);
|
}
|
// 恢复明细状态为待发放
|
detail.setStatus(0);
|
detail.setPaymentTime(null);
|
salaryPaymentDetailMapper.updateById(detail);
|
paymentId = detail.getPaymentId();
|
|
// 恢复薪酬核算状态为已确认(10)
|
HrmSalaryCalculationDO calculation = salaryCalculationMapper.selectById(detail.getCalculationId());
|
if (calculation != null) {
|
calculation.setStatus(10);
|
calculation.setPaymentTime(null);
|
salaryCalculationMapper.updateById(calculation);
|
}
|
}
|
|
// 更新发放台账状态为待发放(如果有明细被撤销)
|
if (paymentId != null) {
|
HrmSalaryPaymentDO payment = salaryPaymentMapper.selectById(paymentId);
|
if (payment != null && payment.getStatus() == 10) {
|
payment.setStatus(0);
|
payment.setPaymentTime(null);
|
salaryPaymentMapper.updateById(payment);
|
}
|
}
|
}
|
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public void deleteSalaryPayment(Long id) {
|
HrmSalaryPaymentDO payment = validateSalaryPaymentExists(id);
|
// 仅待发放状态可删除
|
if (payment.getStatus() != 0) {
|
throw exception(SALARY_PAYMENT_DELETE_FAIL);
|
}
|
// 检查是否存在已发放明细
|
List<HrmSalaryPaymentDetailDO> details = salaryPaymentDetailMapper.selectListByPaymentId(id);
|
boolean hasPaidDetail = details.stream().anyMatch(d -> d.getStatus() == 10);
|
if (hasPaidDetail) {
|
throw exception(SALARY_PAYMENT_HAS_PAID_DETAIL);
|
}
|
// 删除所有明细
|
for (HrmSalaryPaymentDetailDO detail : details) {
|
salaryPaymentDetailMapper.deleteById(detail.getId());
|
}
|
// 删除发放台账
|
salaryPaymentMapper.deleteById(id);
|
}
|
|
}
|