|
|
|
@ -6,6 +6,7 @@ import cn.afterturn.easypoi.excel.entity.ExportParams;
|
|
|
|
|
import cn.afterturn.easypoi.excel.entity.ImportParams;
|
|
|
|
|
import cn.afterturn.easypoi.excel.entity.enmus.ExcelType;
|
|
|
|
|
import cn.afterturn.easypoi.excel.entity.params.ExcelExportEntity;
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
|
|
import cn.hutool.core.lang.UUID;
|
|
|
|
|
import cn.hutool.core.util.NumberUtil;
|
|
|
|
|
import cn.xuyanwu.spring.file.storage.FileInfo;
|
|
|
|
@ -21,6 +22,7 @@ import jnpf.base.vo.PaginationVO;
|
|
|
|
|
import jnpf.config.ConfigValueUtil;
|
|
|
|
|
import jnpf.entity.*;
|
|
|
|
|
import jnpf.model.visualJson.config.HeaderModel;
|
|
|
|
|
import jnpf.model.yysdaywork.WorkShiftVO;
|
|
|
|
|
import jnpf.model.yysmonthlyproduction.*;
|
|
|
|
|
import jnpf.onlinedev.model.ExcelImFieldModel;
|
|
|
|
|
import jnpf.onlinedev.model.OnlineImport.ExcelImportModel;
|
|
|
|
@ -34,6 +36,7 @@ import lombok.extern.slf4j.Slf4j;
|
|
|
|
|
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
|
|
|
|
|
import org.apache.poi.ss.usermodel.Workbook;
|
|
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
|
|
import org.springframework.context.annotation.Bean;
|
|
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
@ -43,6 +46,7 @@ import javax.validation.Valid;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.math.RoundingMode;
|
|
|
|
|
import java.text.ParseException;
|
|
|
|
|
import java.text.SimpleDateFormat;
|
|
|
|
|
import java.util.*;
|
|
|
|
@ -94,6 +98,8 @@ public class YysMonthlyProductionController {
|
|
|
|
|
@Resource
|
|
|
|
|
private YysCalendarService calendarService;
|
|
|
|
|
@Resource
|
|
|
|
|
private YysClassesService classesService;
|
|
|
|
|
@Resource
|
|
|
|
|
private YysDeviceService deviceService;
|
|
|
|
|
@Autowired
|
|
|
|
|
private ConfigValueUtil configValueUtil;
|
|
|
|
@ -604,7 +610,7 @@ public class YysMonthlyProductionController {
|
|
|
|
|
YysMaterialRequirementPlanEntity plan = new YysMaterialRequirementPlanEntity();//物料需求计划
|
|
|
|
|
String planNumber = generaterSwapUtil.getBillNumber("plannumber", false);
|
|
|
|
|
|
|
|
|
|
// todo 生成物料需求计划
|
|
|
|
|
// 生成物料需求计划
|
|
|
|
|
List<YysMaterialRequirementItemEntity> planItems = new ArrayList<>();//物料需求详情
|
|
|
|
|
|
|
|
|
|
// 计算一个计划的物料需求量
|
|
|
|
@ -855,7 +861,8 @@ public class YysMonthlyProductionController {
|
|
|
|
|
@PostMapping("/scheduling")
|
|
|
|
|
@Operation(summary = "生产排产")
|
|
|
|
|
public ActionResult ProductionScheduling(@RequestBody YysMonthlyProductionStrategyVO strategyVO) {
|
|
|
|
|
String month = strategyVO.getMonth();
|
|
|
|
|
String month = strategyVO.getMonth();//月份
|
|
|
|
|
List<String> shifts = strategyVO.getShifts();//班次
|
|
|
|
|
if (StringUtil.isNotEmpty(month)) {
|
|
|
|
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
|
|
|
|
|
try {
|
|
|
|
@ -873,7 +880,7 @@ public class YysMonthlyProductionController {
|
|
|
|
|
}
|
|
|
|
|
Map<String, YysMonthlyProductionEntity> planMaps = new HashMap<>();
|
|
|
|
|
unSchedulePlans.forEach(plan -> planMaps.put(plan.getId(), plan));
|
|
|
|
|
// 计划 计量单位转换为片
|
|
|
|
|
// 计划 计量单位转换为片 // 计算每个计划还需要排产的数量
|
|
|
|
|
Map<String, Map<String, BigDecimal>> planSlice = transferPlan(unSchedulePlans);//未排产计划片数
|
|
|
|
|
|
|
|
|
|
Map<String, Map<String, BigDecimal>> incompleteSlice = new HashMap<>();// 已排产 未生产 未冻结 片数
|
|
|
|
@ -906,14 +913,28 @@ public class YysMonthlyProductionController {
|
|
|
|
|
incompleteSlice.put(monthId, temp);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
planSlice.putAll(incompleteSlice); // 合并计划需要排产的数量
|
|
|
|
|
|
|
|
|
|
List<String> monthIds = unStartWork.stream().map(work -> work.getMonthId()).distinct().collect(Collectors.toList());
|
|
|
|
|
List<YysMonthlyProductionEntity> incompletePlans = yysMonthlyProductionService.getListByIds(monthIds);
|
|
|
|
|
// 未排产计划 与 已排产未生产完成 计划合并 排序
|
|
|
|
|
unSchedulePlans.addAll(incompletePlans);
|
|
|
|
|
// 排序 根据交期
|
|
|
|
|
unSchedulePlans.sort(Comparator.comparing(YysMonthlyProductionEntity::getDeliveryTime));
|
|
|
|
|
// 计算每个计划还需要排产的数量
|
|
|
|
|
|
|
|
|
|
// 获取可用班次
|
|
|
|
|
Map<String, List<AvailableShiftVO>> availableShift = getAvailableShift(month, shifts);
|
|
|
|
|
|
|
|
|
|
for (YysMonthlyProductionEntity plan : unSchedulePlans) {
|
|
|
|
|
String productId = plan.getProductId();
|
|
|
|
|
// 获取可用产线产量
|
|
|
|
|
// Map<String, List<LineCapacity>> lineCapacity = getLineCapacity(productId);
|
|
|
|
|
// 要排产的数量
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取物料需求量
|
|
|
|
|
|
|
|
|
|
// 获取BOM清单
|
|
|
|
|
// 根据计划生成的物料 获取BOM清单
|
|
|
|
|
// 计算一个计划的物料需求量
|
|
|
|
@ -931,22 +952,6 @@ public class YysMonthlyProductionController {
|
|
|
|
|
else return ActionResult.success("未排产");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//转换为半成品
|
|
|
|
|
private Map<String, String> transferUnit(String productId, String unit) {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 拆分为片
|
|
|
|
|
// private Map<String, List<YysSubsetMaterialEntity>> extractBom(String productId) {
|
|
|
|
|
// YysBillMaterialEntity bom = billMaterialService.getByProductId(productId);
|
|
|
|
|
// String pieceId = bom.getPieceId(); //物料
|
|
|
|
|
// List<YysSubsetMaterialEntity> list = expandSubset(pieceId);
|
|
|
|
|
//
|
|
|
|
|
// return null;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
// 展开子集 转换成片
|
|
|
|
|
|
|
|
|
|
private Map<String, BigDecimal> transferToSlice(String pieceId, BigDecimal planNum) {
|
|
|
|
|
List<YysSubsetMaterialEntity> subsetList = subsetMaterialService.getListByPieceId(pieceId);
|
|
|
|
@ -977,11 +982,12 @@ public class YysMonthlyProductionController {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 根据物料 获取可用的产线 及产量 只查询一个班次
|
|
|
|
|
private Map<String, List<AvailableLineVO>> getAvailableLine(String productId) {
|
|
|
|
|
private List<LineCapacity> getLineCapacity(String productId) {
|
|
|
|
|
// 首先查询物料可以在哪些产线上生产
|
|
|
|
|
List<YysDeviceMaterialEntity> list = deviceMaterialService.getByProductId(productId);
|
|
|
|
|
List<LineCapacity> list1 = new ArrayList<>();
|
|
|
|
|
for (YysDeviceMaterialEntity material : list) {
|
|
|
|
|
AvailableLineVO lineVO = new AvailableLineVO();
|
|
|
|
|
LineCapacity lineVO = new LineCapacity();
|
|
|
|
|
String deviceCode = material.getDeviceCode();
|
|
|
|
|
String eightOutput = material.getEightOutput();
|
|
|
|
|
BigDecimal eight = BigDecimal.valueOf(Long.parseLong(eightOutput));
|
|
|
|
@ -991,34 +997,171 @@ public class YysMonthlyProductionController {
|
|
|
|
|
lineVO.setEightProduction(eight);
|
|
|
|
|
lineVO.setTwelveProduction(twelve);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
return list1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取每条产线的可用班次
|
|
|
|
|
private Map<String, List<AvailableShiftVO>> getAvailableShift(String month,List<String> shifts) {
|
|
|
|
|
private Map<String, List<AvailableShiftVO>> getAvailableShift(String month, List<String> shifts) {
|
|
|
|
|
List<YysClassesEntity> shiftList = classesService.getListByIdsAndStatus(shifts, "1");
|
|
|
|
|
// 全部产线
|
|
|
|
|
List<YysDeviceEntity> allLine = getAllLine();
|
|
|
|
|
// 工厂日历
|
|
|
|
|
List<YysCalendarEntity> listByMonth = calendarService.getListByMonth(month);
|
|
|
|
|
// 总共有多少个班次
|
|
|
|
|
// 返回结果
|
|
|
|
|
HashMap<String, List<AvailableShiftVO>> result = new HashMap<>();
|
|
|
|
|
for (YysDeviceEntity device : allLine) {
|
|
|
|
|
String code = device.getDeviceCode();
|
|
|
|
|
List<AvailableShiftVO> list = result.getOrDefault(code, new ArrayList<>());
|
|
|
|
|
for (YysCalendarEntity calender : listByMonth) {
|
|
|
|
|
String day = calender.getDay();
|
|
|
|
|
for (YysClassesEntity shift : shiftList) {
|
|
|
|
|
AvailableShiftVO shiftVO = new AvailableShiftVO();
|
|
|
|
|
shiftVO.setShiftId(shift.getId());
|
|
|
|
|
shiftVO.setDate(day);
|
|
|
|
|
shiftVO.setStartTime(shift.getStartTime());
|
|
|
|
|
shiftVO.setShiftType(shift.getClassesType());
|
|
|
|
|
shiftVO.setEndTime(shift.getEndTime());
|
|
|
|
|
shiftVO.setLength(NumberUtil.parseInt(shift.getClassesDuration()));
|
|
|
|
|
list.add(shiftVO);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
result.put(code, list);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 去除掉占用的班次
|
|
|
|
|
// 占用的班次
|
|
|
|
|
Map<String, List<WorkShiftVO>> occupyShift = getOccupyShift(month);
|
|
|
|
|
|
|
|
|
|
// 删除已占用的班次
|
|
|
|
|
Iterator<String> iterator = result.keySet().iterator();
|
|
|
|
|
while (iterator.hasNext()) {
|
|
|
|
|
String key = iterator.next();
|
|
|
|
|
List<AvailableShiftVO> avList = result.get(key);
|
|
|
|
|
List<WorkShiftVO> occList = occupyShift.getOrDefault(key, Collections.emptyList());
|
|
|
|
|
if (Collections.emptyList().equals(occList) || occList.size() == 0) continue;
|
|
|
|
|
for (WorkShiftVO workShiftVO : occList) {
|
|
|
|
|
String post = workShiftVO.getShiftId();
|
|
|
|
|
String type = workShiftVO.getShiftType();
|
|
|
|
|
String date = cn.hutool.core.date.DateUtil.format(workShiftVO.getDate(), "yyyy-MM-dd");
|
|
|
|
|
avList = avList.stream().filter(shift -> {
|
|
|
|
|
String shiftId = shift.getShiftId();
|
|
|
|
|
String shiftType = shift.getShiftType();
|
|
|
|
|
String shiftDate = shift.getDate();
|
|
|
|
|
return !(shiftId.equals(post) && shiftType.equals(type)
|
|
|
|
|
|| shiftDate.equals(date) && shiftType.equals(type));
|
|
|
|
|
}).collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 返回剩余的可用班次
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 返回剩余的班次
|
|
|
|
|
return null;
|
|
|
|
|
// 查询全部产线
|
|
|
|
|
private List<YysDeviceEntity> getAllLine() {
|
|
|
|
|
return deviceService.getAllList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取工厂日历
|
|
|
|
|
private Map<String, List<YysCalendarEntity>> getCalendar(String month) {
|
|
|
|
|
// 获取占用的班次
|
|
|
|
|
private Map<String, List<WorkShiftVO>> getOccupyShift(String month) {
|
|
|
|
|
// 查询日历
|
|
|
|
|
List<YysCalendarEntity> list = calendarService.getListByMonth(month);
|
|
|
|
|
List<YysDayWorkEntity> list = dayWorkService.getOccupyShift();//被冻结的班次
|
|
|
|
|
List<YysClassesEntity> clazzList = classesService.getAllList();//全部班次
|
|
|
|
|
Map<String, String> shiftInfo = new HashMap<>();
|
|
|
|
|
for (YysClassesEntity clazz : clazzList) {
|
|
|
|
|
shiftInfo.put(clazz.getId(), clazz.getClassesType());
|
|
|
|
|
}
|
|
|
|
|
Map<String, List<WorkShiftVO>> result = new HashMap<>();
|
|
|
|
|
for (YysDayWorkEntity dayWork : list) {
|
|
|
|
|
String line = dayWork.getDeviceCode();
|
|
|
|
|
List<WorkShiftVO> orDefault = result.getOrDefault(line, new ArrayList<>());
|
|
|
|
|
WorkShiftVO shiftVO = new WorkShiftVO();
|
|
|
|
|
shiftVO.setDate(dayWork.getManufactureTime());
|
|
|
|
|
String post = dayWork.getPost();
|
|
|
|
|
String type = shiftInfo.get(post);
|
|
|
|
|
shiftVO.setShiftType(type);
|
|
|
|
|
shiftVO.setShiftId(post);
|
|
|
|
|
orDefault.add(shiftVO);
|
|
|
|
|
result.put(line, orDefault);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 排产策略 优先原料齐套
|
|
|
|
|
private List<YysDayWorkEntity> materialCompleteFirst() {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取占用的班次
|
|
|
|
|
private Map<String, List<YysDayWorkEntity>> getOccupyShift(String month) {
|
|
|
|
|
// 查询日历
|
|
|
|
|
List<YysDayWorkEntity> list = dayWorkService.getOccupyShift();
|
|
|
|
|
// 优先低库存 单线
|
|
|
|
|
private List<YysDayWorkEntity> lowInventoryFirst() {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 优先换线少 单线
|
|
|
|
|
private List<YysDayWorkEntity> lessChangeFirst(List<YysMonthlyProductionEntity> unSchedulePlans,//未排产计划
|
|
|
|
|
Map<String, List<AvailableShiftVO>> availableShift,//可用的班次
|
|
|
|
|
Map<String, Map<String, BigDecimal>> planSlice//计划切片
|
|
|
|
|
) {
|
|
|
|
|
unSchedulePlans.sort(Comparator.comparing(YysMonthlyProductionEntity::getDeliveryTime));//按照交期排序
|
|
|
|
|
List<YysDayWorkEntity> workList = new ArrayList<>();
|
|
|
|
|
for (YysMonthlyProductionEntity plan : unSchedulePlans) {
|
|
|
|
|
String productId = plan.getProductId();
|
|
|
|
|
String planId = plan.getId();
|
|
|
|
|
List<LineCapacity> lineCapacity = getLineCapacity(productId);
|
|
|
|
|
// 筛选首选产线
|
|
|
|
|
if (lineCapacity.size() == 0) continue;// 产品没有产线可生产 跳过排产
|
|
|
|
|
List<ConformityVO> conformity = conformity(availableShift, lineCapacity);
|
|
|
|
|
BigDecimal num = planSlice.get(planId).get(productId);//计划数量
|
|
|
|
|
// 排产
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return workList;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 优先交期快 并线排产
|
|
|
|
|
private List<YysDayWorkEntity> deliveryFastFirst() {
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将产线与可用排班整合
|
|
|
|
|
private List<ConformityVO> conformity(Map<String, List<AvailableShiftVO>> avShift,
|
|
|
|
|
List<LineCapacity> lineCapacity) {
|
|
|
|
|
List<ConformityVO> result = new ArrayList<>();
|
|
|
|
|
for (LineCapacity capacity : lineCapacity) {
|
|
|
|
|
String line = capacity.getLineCode();
|
|
|
|
|
List<AvailableShiftVO> shifts = avShift.get(line);
|
|
|
|
|
for (AvailableShiftVO shift : shifts) {
|
|
|
|
|
ConformityVO conformityVO = new ConformityVO();
|
|
|
|
|
BeanUtil.copyProperties(shift, conformityVO);
|
|
|
|
|
BeanUtil.copyProperties(capacity, conformityVO);
|
|
|
|
|
Integer length = shift.getLength();//时长
|
|
|
|
|
BigDecimal eight = capacity.getEightProduction();//8小时产量
|
|
|
|
|
BigDecimal twelve = capacity.getTwelveProduction();//12小时产量
|
|
|
|
|
if (length < 8) {
|
|
|
|
|
conformityVO.setCapacity(eight.divide(new BigDecimal(8), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(length)));
|
|
|
|
|
} else if (length == 8) {
|
|
|
|
|
conformityVO.setCapacity(eight);
|
|
|
|
|
} else if ((length > 8 && length < 12) || length > 12) {
|
|
|
|
|
conformityVO.setCapacity(twelve.divide(new BigDecimal(12), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(length)));
|
|
|
|
|
} else if (length == 12) {
|
|
|
|
|
conformityVO.setCapacity(twelve);
|
|
|
|
|
}
|
|
|
|
|
result.add(conformityVO);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 筛选出最早可用的产线
|
|
|
|
|
private ConformityVO getOptimalLine(List<ConformityVO> list) {
|
|
|
|
|
list.sort(Comparator.comparing(ConformityVO::getStartTime));
|
|
|
|
|
return list.get(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|