package com.chinaztt.mes.production.service.impl;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.chinaztt.mes.production.dto.ComputationDTO;
|
import com.chinaztt.mes.production.dto.PersonBoardDTO;
|
import com.chinaztt.mes.production.entity.Computation;
|
import com.chinaztt.mes.production.entity.DutyRecord;
|
import com.chinaztt.mes.production.mapper.ComputationMapper;
|
import com.chinaztt.mes.production.mapper.DutyRecordMapper;
|
import com.chinaztt.mes.production.mapper.PersonBoardMapper;
|
import com.chinaztt.mes.production.service.ComputationService;
|
import lombok.AllArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.math.BigDecimal;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.stream.Collectors;
|
|
/**
|
* 工时计算
|
*
|
* @author cxf
|
* @date 2021-03-10 15:00:08
|
*/
|
@Service
|
@AllArgsConstructor
|
@Transactional(rollbackFor = Exception.class)
|
public class ComputationServiceImpl extends ServiceImpl<ComputationMapper, Computation> implements ComputationService {
|
public static final BigDecimal TWELVE = new BigDecimal(12);
|
public static final BigDecimal SIX = new BigDecimal(6);
|
public static final BigDecimal ONE_HUNDRED_AND_SEVENTY_FOUR = new BigDecimal(174);
|
public static final BigDecimal ONE_THOUSAND_EIGHT_HUNDRED_AND_NINETY = new BigDecimal(1890);
|
public static final String PRODUCT_DEPARTMENT = "生产部";
|
public static final String EQUIPMENT_DEPARTMENT = "设备部";
|
public static final String QUALITY_DEPARTMENT = "质量部";
|
private DutyRecordMapper dutyRecordMapper;
|
private PersonBoardMapper personBoardMapper;
|
|
@Override
|
public synchronized boolean computeByDutyRecordId(Long dutyRecordId) {
|
// 1.产品工资
|
List<ComputationDTO> computationDTOList = computeProductWages(dutyRecordId);
|
// 2.加班费和津贴
|
computeOvertimePayAndSubsidy(dutyRecordId, computationDTOList);
|
// 3.刷新主表的待处理字段
|
dutyRecordMapper.refreshPendingById(dutyRecordId);
|
return true;
|
}
|
|
@Override
|
public void computeComingByDutyRecordId(Long dutyRecordId) {
|
// 把当前班次之后确认计算的数据再重新算一下,防止加班费计算误差
|
List<Long> comingDutyRecordIds = dutyRecordMapper.selectComingByDutyRecordId(dutyRecordId);
|
if (CollectionUtil.isNotEmpty(comingDutyRecordIds)) {
|
for (Long id : comingDutyRecordIds) {
|
computeByDutyRecordId(id);
|
}
|
}
|
}
|
|
private List<ComputationDTO> computeProductWages(Long dutyRecordId) {
|
// 1.先查询班次对应的人工记录
|
List<ComputationDTO> computationDTOList = baseMapper.getComputationByDutyRecordId(dutyRecordId);
|
// 2.删除原来的
|
baseMapper.delete(Wrappers.<Computation>lambdaQuery().eq(Computation::getDutyRecordId, dutyRecordId));
|
// 3.根据不同类型计算人工工资(系数*定额工时*工作量)
|
for (ComputationDTO computationDTO : computationDTOList) {
|
baseMapper.delete(Wrappers.<Computation>lambdaQuery().eq(Computation::getArtificialInformationId, computationDTO.getArtificialInformationId()));
|
String loadType = computationDTO.getLoadType();
|
BigDecimal conversionCoefficient = computationDTO.getConversionCoefficient();
|
BigDecimal standardHourWage = computationDTO.getStandardHourWage();
|
BigDecimal workLoad = BigDecimal.ZERO;
|
BigDecimal laborCost = BigDecimal.ZERO;
|
BigDecimal productiveSalary = BigDecimal.ZERO;
|
BigDecimal productiveHandymanSalary = BigDecimal.ZERO;
|
BigDecimal unproductiveHandymanSalary = BigDecimal.ZERO;
|
if ("1".equals(loadType)) {
|
// 生产杂工
|
workLoad = computationDTO.getWorkingHours();
|
if (workLoad != null) {
|
laborCost = conversionCoefficient.multiply(standardHourWage).multiply(workLoad).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveHandymanSalary = laborCost;
|
}
|
} else if ("2".equals(loadType)) {
|
// 非生产杂工
|
workLoad = computationDTO.getWorkingHours();
|
if (workLoad != null) {
|
laborCost = conversionCoefficient.multiply(standardHourWage).multiply(workLoad).setScale(2, BigDecimal.ROUND_DOWN);
|
unproductiveHandymanSalary = laborCost;
|
}
|
} else {
|
// 产量
|
workLoad = computationDTO.getPersonOutput();
|
if (workLoad != null) {
|
laborCost = conversionCoefficient.multiply(standardHourWage).multiply(workLoad).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveSalary = laborCost;
|
}
|
}
|
computationDTO.setWorkLoad(workLoad);
|
computationDTO.setLaborCost(laborCost);
|
computationDTO.setProductiveSalary(productiveSalary);
|
computationDTO.setProductiveHandymanSalary(productiveHandymanSalary);
|
computationDTO.setUnproductiveHandymanSalary(unproductiveHandymanSalary);
|
baseMapper.insert(computationDTO);
|
}
|
return computationDTOList;
|
}
|
|
private void computeOvertimePayAndSubsidy(Long dutyRecordId, List<ComputationDTO> computationDTOList) {
|
List<PersonBoardDTO> personBoardDTOList = personBoardMapper.getPersonByDutyRecordId(dutyRecordId);
|
DutyRecord dutyRecord = dutyRecordMapper.selectById(dutyRecordId);
|
// 1.夜班费(8小时夜班8元/天、12小时夜班12元/天),夜班津贴(12小时5.5)
|
BigDecimal nightDifferential = BigDecimal.ZERO;
|
BigDecimal mealSubsidy = BigDecimal.ZERO;
|
if (dutyRecord.getIsNight()) {
|
nightDifferential = dutyRecord.getDutyTime();
|
if (dutyRecord.getDutyTime().compareTo(TWELVE) != -1) {
|
mealSubsidy = new BigDecimal(5.5);
|
}
|
}
|
for (PersonBoardDTO personBoardDTO : personBoardDTOList) {
|
personBoardDTO.setNightDifferential(nightDifferential);
|
personBoardDTO.setMealSubsidy(mealSubsidy);
|
personBoardDTO.setOvertimePay(BigDecimal.ZERO);
|
}
|
// 2.加班费(超过174小时,按当天产品工资1.5倍计算)
|
Map<Long, List<ComputationDTO>> mapList = computationDTOList.stream().collect(Collectors.groupingBy(ComputationDTO::getStaffId));
|
personBoardDTOList.stream().forEach(personBoardDTO -> {
|
BigDecimal salary = BigDecimal.ZERO;
|
BigDecimal overtimePay = BigDecimal.ZERO;
|
BigDecimal productiveSalary = BigDecimal.ZERO;
|
BigDecimal productiveHandymanSalary = BigDecimal.ZERO;
|
BigDecimal unproductiveHandymanSalary = BigDecimal.ZERO;
|
// 人工正常计算出来的工资
|
List<ComputationDTO> computationList = mapList.get(personBoardDTO.getStaffId());
|
if (CollectionUtil.isNotEmpty(computationList)) {
|
salary = computationList.stream().map(ComputationDTO::getLaborCost).reduce(BigDecimal.ZERO, BigDecimal::add);
|
productiveSalary = computationList.stream().map(ComputationDTO::getProductiveSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
|
productiveHandymanSalary = computationList.stream().map(ComputationDTO::getProductiveHandymanSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
|
unproductiveHandymanSalary = computationList.stream().map(ComputationDTO::getUnproductiveHandymanSalary).reduce(BigDecimal.ZERO, BigDecimal::add);
|
}
|
if (personBoardDTO.getBeforeTotalDutyTime().add(personBoardDTO.getDutyTime()).compareTo(ONE_HUNDRED_AND_SEVENTY_FOUR) == 1) {
|
// 计算加班时长
|
BigDecimal overtimeHours = BigDecimal.ZERO;
|
if (personBoardDTO.getBeforeTotalDutyTime().compareTo(ONE_HUNDRED_AND_SEVENTY_FOUR) == -1) {
|
overtimeHours = personBoardDTO.getBeforeTotalDutyTime().add(personBoardDTO.getDutyTime()).subtract(ONE_HUNDRED_AND_SEVENTY_FOUR);
|
} else {
|
overtimeHours = personBoardDTO.getDutyTime();
|
}
|
// 根据加班时长计算加班费
|
String divisionName = personBoardDTO.getDivisionName();
|
if (StringUtils.isNotBlank(divisionName)) {
|
if (divisionName.contains(PRODUCT_DEPARTMENT)) {
|
// 2.1 生产部(生产人员):超过174小时的按当天工资1.5倍计算,其中1.0算基本工资,0.5算加班费
|
if (CollectionUtil.isNotEmpty(computationList)) {
|
overtimePay = salary.multiply(new BigDecimal(0.5)).multiply(overtimeHours)
|
.divide(personBoardDTO.getDutyTime(), 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
}
|
} else if (divisionName.contains(EQUIPMENT_DEPARTMENT)) {
|
// 2.2 设备部(维修):超过174小时的,每小时*1890/174*1.1*1.5
|
overtimePay = ONE_THOUSAND_EIGHT_HUNDRED_AND_NINETY.multiply(new BigDecimal(1.1)).multiply(new BigDecimal(1.5))
|
.multiply(overtimeHours).divide(ONE_HUNDRED_AND_SEVENTY_FOUR, 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
} else if (divisionName.contains(QUALITY_DEPARTMENT)) {
|
// 2.3 质量部(检测):超过174小时的,每小时额外加6块钱
|
overtimePay = overtimeHours.multiply(SIX);
|
}
|
// 计算未超出加班时间的正常工资(暂时按当天工作总量百分比算)
|
BigDecimal withinTime = personBoardDTO.getDutyTime().subtract(overtimeHours);
|
if (personBoardDTO.getDutyTime().compareTo(BigDecimal.ZERO) == 1) {
|
// 如果是生产部门工资,不需要去处理了
|
if (divisionName.contains(PRODUCT_DEPARTMENT)) {
|
} else {
|
salary = salary.multiply(withinTime).divide(personBoardDTO.getDutyTime(), 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveSalary = productiveSalary.multiply(withinTime).divide(personBoardDTO.getDutyTime(), 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveHandymanSalary = productiveHandymanSalary.multiply(withinTime).divide(personBoardDTO.getDutyTime(), 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
unproductiveHandymanSalary = unproductiveHandymanSalary.multiply(withinTime).divide(personBoardDTO.getDutyTime(), 4, BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN);
|
}
|
}
|
}
|
}
|
// 工资或者加班费都需要乘上人员系数(如果系数是0,就是试用期/实习生/合同工,处理为1)
|
BigDecimal personnelFactor = personBoardDTO.getPersonnelFactor();
|
if (personnelFactor.compareTo(BigDecimal.ZERO) == 0) {
|
personnelFactor = BigDecimal.ONE;
|
}
|
salary = salary.multiply(personnelFactor).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveSalary = productiveSalary.multiply(personnelFactor).setScale(2, BigDecimal.ROUND_DOWN);
|
productiveHandymanSalary = productiveHandymanSalary.multiply(personnelFactor).setScale(2, BigDecimal.ROUND_DOWN);
|
unproductiveHandymanSalary = unproductiveHandymanSalary.multiply(personnelFactor).setScale(2, BigDecimal.ROUND_DOWN);
|
overtimePay = overtimePay.multiply(personnelFactor).setScale(2, BigDecimal.ROUND_DOWN);
|
personBoardDTO.setSalary(salary);
|
personBoardDTO.setProductiveSalary(productiveSalary);
|
personBoardDTO.setProductiveHandymanSalary(productiveHandymanSalary);
|
personBoardDTO.setUnproductiveHandymanSalary(unproductiveHandymanSalary);
|
personBoardDTO.setOvertimePay(overtimePay);
|
});
|
personBoardDTOList.stream().forEach(personBoardDTO -> personBoardMapper.updateById(personBoardDTO));
|
}
|
|
|
@Override
|
public void checkDutyRecordSubmit(List<Long> dutyRecordIdList) {
|
List<DutyRecord> dutyRecordList = dutyRecordMapper.selectBatchIds(dutyRecordIdList);
|
List<Boolean> BooleanList = dutyRecordList.stream().map(DutyRecord::getIsConfirm).collect(Collectors.toList());
|
if(BooleanList.contains(false)){
|
throw new RuntimeException("存在未确认的班次,无法计算");
|
}
|
}
|
}
|