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 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 computationDTOList = computeProductWages(dutyRecordId); // 2.加班费和津贴 computeOvertimePayAndSubsidy(dutyRecordId, computationDTOList); // 3.刷新主表的待处理字段 dutyRecordMapper.refreshPendingById(dutyRecordId); return true; } @Override public void computeComingByDutyRecordId(Long dutyRecordId) { // 把当前班次之后确认计算的数据再重新算一下,防止加班费计算误差 List comingDutyRecordIds = dutyRecordMapper.selectComingByDutyRecordId(dutyRecordId); if (CollectionUtil.isNotEmpty(comingDutyRecordIds)) { for (Long id : comingDutyRecordIds) { computeByDutyRecordId(id); } } } private List computeProductWages(Long dutyRecordId) { // 1.先查询班次对应的人工记录 List computationDTOList = baseMapper.getComputationByDutyRecordId(dutyRecordId); // 2.删除原来的 baseMapper.delete(Wrappers.lambdaQuery().eq(Computation::getDutyRecordId, dutyRecordId)); // 3.根据不同类型计算人工工资(系数*定额工时*工作量) for (ComputationDTO computationDTO : computationDTOList) { baseMapper.delete(Wrappers.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 computationDTOList) { List 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> 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 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 dutyRecordIdList) { List dutyRecordList = dutyRecordMapper.selectBatchIds(dutyRecordIdList); List BooleanList = dutyRecordList.stream().map(DutyRecord::getIsConfirm).collect(Collectors.toList()); if(BooleanList.contains(false)){ throw new RuntimeException("存在未确认的班次,无法计算"); } } }