智能排产 3 封版

master
guochaojie 2 months ago
parent 920ca7b8b4
commit d59d9aa5fd

@ -40,4 +40,7 @@ public interface YysClassesService extends IService<YysClassesEntity> {
* @return
*/
YysClassesEntity getInfoById(String id);
List<YysClassesEntity> getListByIdsAndStatus(List<String> shifts, String s);
List<YysClassesEntity> getAllList();
}

@ -48,4 +48,6 @@ public interface YysDeviceService extends IService<YysDeviceEntity> {
* @return
*/
String bandMaterial(YysDeviceForm yysDeviceForm);
List<YysDeviceEntity> getAllList();
}

@ -198,6 +198,7 @@ public class YysCalendarServiceImpl extends ServiceImpl<YysCalendarMapper, YysCa
QueryWrapper<YysCalendarEntity> wrapper = new QueryWrapper<>();
wrapper.lambda().eq(YysCalendarEntity::getYears, month);
wrapper.lambda().eq(YysCalendarEntity::getIsHoliday, "2");//非节假日
wrapper.lambda().orderByAsc(YysCalendarEntity::getDay);
return this.list(wrapper);
}
}

@ -317,4 +317,25 @@ public class YysClassesServiceImpl extends ServiceImpl<YysClassesMapper, YysClas
public YysClassesEntity getInfoById(String id) {
return this.getById(id);
}
@Override
public List<YysClassesEntity> getListByIdsAndStatus(List<String> shifts, String status) {
QueryWrapper<YysClassesEntity> wrapper = new QueryWrapper<>();
wrapper.lambda().in(YysClassesEntity::getId, shifts)
.isNull(YysClassesEntity::getDeleteMark);
if (StringUtil.isNotEmpty(status))
wrapper.lambda().eq(YysClassesEntity::getEnabledStatus, status);
wrapper.lambda().orderByAsc(YysClassesEntity::getStartTime)
.orderByAsc(YysClassesEntity::getClassesType);
return this.list(wrapper);
}
@Override
public List<YysClassesEntity> getAllList() {
QueryWrapper<YysClassesEntity> wrapper = new QueryWrapper<>();
wrapper.lambda()
.eq(YysClassesEntity::getEnabledStatus, "1")
.isNull(YysClassesEntity::getDeleteMark);
return this.list(wrapper);
}
}

@ -362,4 +362,9 @@ public class YysDeviceServiceImpl extends ServiceImpl<YysDeviceMapper, YysDevice
}
return yysDeviceMaterialService.saveData(yysDeviceForm.getDeviceCode(), yysDeviceForm.getData());
}
@Override
public List<YysDeviceEntity> getAllList() {
return this.list();
}
}

@ -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);
}
}

@ -20,6 +20,8 @@ public class YysClassesEntity {
private String id;
@TableField(value = "CLASSES_NAME" , updateStrategy = FieldStrategy.IGNORED)
private String classesName;
@TableField(value = "CLASSES_TYPE" , updateStrategy = FieldStrategy.IGNORED)
private String classesType;
@TableField(value = "START_TIME" , updateStrategy = FieldStrategy.IGNORED)
private String startTime;
@TableField(value = "END_TIME" , updateStrategy = FieldStrategy.IGNORED)

@ -0,0 +1,13 @@
package jnpf.model.yysdaywork;
import lombok.Data;
import java.util.Date;
@Data
public class WorkShiftVO {
private String shiftId; //班次id
private String shiftType; //班次类型
private Date date; //班次日期
}

@ -2,14 +2,16 @@ package jnpf.model.yysmonthlyproduction;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class AvailableShiftVO {
private String id;// 班次ID
private String date;// 日期
private Date startTime;// 开始时间
private Date endTime;// 结束时间
private Integer length;// 时长
private String shiftId; // 班次ID
private String shiftType; // 班次类型
private String date; // 日期
private String startTime; // 开始时间
private String endTime; // 结束时间
private Integer length; // 时长
}

@ -0,0 +1,19 @@
package jnpf.model.yysmonthlyproduction;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class ConformityVO {
private String shiftId; // 班次ID
private String shiftType; // 班次类型
private String date; // 日期
private String startTime; // 开始时间
private String endTime; // 结束时间
private Integer length; // 时长
private BigDecimal capacity;// 产能
private String lineCode; // 产线编码
private BigDecimal eightProduction;// 8小时产量
private BigDecimal twelveProduction;// 12小时产量
}

@ -3,14 +3,12 @@ package jnpf.model.yysmonthlyproduction;
import lombok.Data;
import java.math.BigDecimal;
import java.util.Date;
// 可用查线信息
@Data
public class AvailableLineVO {
public class LineCapacity {
private String lineCode;// 产线编码
private BigDecimal eightProduction;// 8小时产量
private BigDecimal twelveProduction;// 12小时产量
private Date availableDate;// 可用日期
}
Loading…
Cancel
Save