|
|
@@ -1,5 +1,8 @@
|
|
|
package com.jeesite.modules.mes.service;
|
|
|
|
|
|
+import java.text.SimpleDateFormat;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
import java.util.List;
|
|
|
|
|
|
import com.jeesite.common.lang.StringUtils;
|
|
|
@@ -8,6 +11,8 @@ import com.jeesite.common.service.ServiceException;
|
|
|
import com.jeesite.modules.mes.entity.MesProduct;
|
|
|
import com.jeesite.modules.mes.entity.MesProductOrder;
|
|
|
import com.jeesite.modules.mes.entity.MesShift;
|
|
|
+import com.jeesite.modules.mes.resp.MesCurrentPlanItemResp;
|
|
|
+import com.jeesite.modules.mes.resp.MesCurrentPlanResp;
|
|
|
import com.jeesite.modules.mes.resp.MesShiftDataResp;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
@@ -101,16 +106,12 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
throw new ServiceException(text("只有已下发的生产订单才能排产"));
|
|
|
}
|
|
|
|
|
|
- String bomCateSn = null;
|
|
|
- if(StringUtils.isNotBlank(mesProductOrder.getBomId())){
|
|
|
- WmsBom wmsBom = wmsBomService.get(new WmsBom(mesProductOrder.getBomId()));
|
|
|
- if(wmsBom != null){
|
|
|
- bomCateSn = wmsBom.getProductCateId();
|
|
|
- }
|
|
|
- }
|
|
|
+ String bomCateSn = resolveProductCate(mesProductOrder);
|
|
|
if(StringUtils.isBlank(bomCateSn)){
|
|
|
- throw new ServiceException(text("生产订单的BOM未维护工件类型,无法排产"));
|
|
|
+ throw new ServiceException(text("生产订单未维护产品类型(工件类型),无法排产"));
|
|
|
}
|
|
|
+ // 计划显式记录产品类型,保证 订单->计划->产品 链路一致
|
|
|
+ mesProductPlan.setProductCateId(bomCateSn);
|
|
|
|
|
|
MesProductPlan query = new MesProductPlan();
|
|
|
query.setOrderId(mesProductPlan.getOrderId());
|
|
|
@@ -125,7 +126,7 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
MesProductPlan slotQuery = new MesProductPlan();
|
|
|
slotQuery.setDay(mesProductPlan.getDay());
|
|
|
slotQuery.setShiftId(mesProductPlan.getShiftId());
|
|
|
- slotQuery.setBomProductCateId(bomCateSn);
|
|
|
+ slotQuery.setProductCateId(bomCateSn);
|
|
|
slotQuery.getSqlMap().getWhere().and("a.status", QueryType.EQ, "0");
|
|
|
if(!findList(slotQuery).isEmpty()){
|
|
|
throw new ServiceException(text("同一日期、班次、产品已存在生产计划,不能重复排产"));
|
|
|
@@ -146,9 +147,38 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
}
|
|
|
|
|
|
mesProductPlan.setIsPick("0");
|
|
|
+ }else{
|
|
|
+ // 编辑计划时,产品类型跟随生产订单同步
|
|
|
+ MesProductOrder mesProductOrder = mesProductOrderService.get(new MesProductOrder(mesProductPlan.getOrderId()));
|
|
|
+ String productCateSn = resolveProductCate(mesProductOrder);
|
|
|
+ if(StringUtils.isNotBlank(productCateSn)){
|
|
|
+ mesProductPlan.setProductCateId(productCateSn);
|
|
|
+ }
|
|
|
}
|
|
|
super.save(mesProductPlan);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 解析生产订单的产品类型:优先取订单选择的产品类型,订单未维护时用 BOM 的工件类型兜底。
|
|
|
+ *
|
|
|
+ * @param mesProductOrder 生产订单
|
|
|
+ * @return 产品类型编号(mes_product_cate.sn)
|
|
|
+ */
|
|
|
+ private String resolveProductCate(MesProductOrder mesProductOrder){
|
|
|
+ if(mesProductOrder == null){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ if(StringUtils.isNotBlank(mesProductOrder.getProductCateId())){
|
|
|
+ return mesProductOrder.getProductCateId();
|
|
|
+ }
|
|
|
+ if(StringUtils.isNotBlank(mesProductOrder.getBomId())){
|
|
|
+ WmsBom wmsBom = wmsBomService.get(new WmsBom(mesProductOrder.getBomId()));
|
|
|
+ if(wmsBom != null){
|
|
|
+ return wmsBom.getProductCateId();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
|
|
|
/**
|
|
|
* 更新状态
|
|
|
@@ -182,7 +212,7 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
*
|
|
|
* 计划日期以“班次开始日期”为准,因此跨零点的夜班在次日凌晨仍然匹配前一天的计划。
|
|
|
*
|
|
|
- * @param cateSn 产品工件类型(对应 wms_bom.product_cate_id)
|
|
|
+ * @param cateSn 产品工件类型(对应 mes_product_cate.sn / 计划product_cate_id)
|
|
|
* @return 唯一计划;没有计划时返回 null
|
|
|
*/
|
|
|
public MesProductPlan getCurrentPlan(String cateSn){
|
|
|
@@ -202,7 +232,7 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
MesProductPlan query = new MesProductPlan();
|
|
|
query.setShiftId(mesShiftDataResp.getMesShift().getId());
|
|
|
query.setDay(java.sql.Date.valueOf(planDay));
|
|
|
- query.setBomProductCateId(cateSn);
|
|
|
+ query.setProductCateId(cateSn);
|
|
|
query.getSqlMap().getWhere().and("a.status", QueryType.EQ, "0");
|
|
|
query.getSqlMap().getWhere().and("c.state", QueryType.EQ, "1");
|
|
|
|
|
|
@@ -300,5 +330,145 @@ public class MesProductPlanService extends CrudService<MesProductPlanDao, MesPro
|
|
|
product.setPlanId(planId);
|
|
|
mesProductService.save(product);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前班次的全部有效生产计划(订单已下发、计划未删除)。
|
|
|
+ *
|
|
|
+ * 计划日期以“班次开始日期”为准,跨零点的夜班在次日凌晨仍然匹配前一天的计划。
|
|
|
+ *
|
|
|
+ * @return 当前班次的计划列表;没有匹配到班次时返回空列表
|
|
|
+ */
|
|
|
+ public List<MesProductPlan> getCurrentShiftPlans(){
|
|
|
+ List<MesProductPlan> plans = new ArrayList<>();
|
|
|
+ MesShiftDataResp mesShiftDataResp = mesShiftService.getCurShift();
|
|
|
+ if(mesShiftDataResp == null
|
|
|
+ || mesShiftDataResp.getMesShift() == null
|
|
|
+ || StringUtils.isBlank(mesShiftDataResp.getStart())
|
|
|
+ || mesShiftDataResp.getStart().length() < 10){
|
|
|
+ return plans;
|
|
|
+ }
|
|
|
+ String planDay = mesShiftDataResp.getStart().substring(0, 10);
|
|
|
+ MesProductPlan query = new MesProductPlan();
|
|
|
+ query.setShiftId(mesShiftDataResp.getMesShift().getId());
|
|
|
+ query.setDay(java.sql.Date.valueOf(planDay));
|
|
|
+ query.getSqlMap().getWhere().and("a.status", QueryType.EQ, "0");
|
|
|
+ query.getSqlMap().getWhere().and("c.state", QueryType.EQ, "1");
|
|
|
+ List<MesProductPlan> list = findList(query);
|
|
|
+ if(list != null){
|
|
|
+ plans.addAll(list);
|
|
|
+ }
|
|
|
+ return plans;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前班次正在生产的产品(工件类型)。
|
|
|
+ * 当前班次只有一个产品类型时返回该类型;存在多个时返回 null。
|
|
|
+ *
|
|
|
+ * @return 产品类型编号(mes_product_cate.sn)
|
|
|
+ */
|
|
|
+ public String getCurrentProductCate(){
|
|
|
+ List<MesProductPlan> plans = getCurrentShiftPlans();
|
|
|
+ if(plans.isEmpty()){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ String cateSn = null;
|
|
|
+ for(MesProductPlan plan : plans){
|
|
|
+ if(StringUtils.isBlank(plan.getProductCateId())){
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if(cateSn == null){
|
|
|
+ cateSn = plan.getProductCateId();
|
|
|
+ }else if(!cateSn.equals(plan.getProductCateId())){
|
|
|
+ // 当前班次存在多个产品类型,无法唯一判断
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return cateSn;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前班次的生产计划与当前产品(工件类型),供客户端/下单页面使用。
|
|
|
+ *
|
|
|
+ * @return 当前计划数据
|
|
|
+ */
|
|
|
+ public MesCurrentPlanResp getCurrentPlanData(){
|
|
|
+ MesCurrentPlanResp resp = new MesCurrentPlanResp();
|
|
|
+ MesShiftDataResp shift = mesShiftService.getCurShift();
|
|
|
+ if(shift != null && shift.getMesShift() != null){
|
|
|
+ resp.setShiftId(shift.getMesShift().getId());
|
|
|
+ resp.setShiftTitle(shift.getMesShift().getTitle());
|
|
|
+ resp.setShiftStart(shift.getStart());
|
|
|
+ resp.setShiftEnd(shift.getEnd());
|
|
|
+ if(StringUtils.isNotBlank(shift.getStart()) && shift.getStart().length() >= 10){
|
|
|
+ resp.setDay(shift.getStart().substring(0, 10));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ List<MesCurrentPlanItemResp> items = new ArrayList<>();
|
|
|
+ int planNums = 0;
|
|
|
+ int producedNums = 0;
|
|
|
+ for(MesProductPlan plan : getCurrentShiftPlans()){
|
|
|
+ MesCurrentPlanItemResp item = new MesCurrentPlanItemResp();
|
|
|
+ item.setPlanId(plan.getId());
|
|
|
+ item.setOrderId(plan.getOrderId());
|
|
|
+ item.setOrderSn(plan.getOrderSn());
|
|
|
+ item.setBomTitle(plan.getBomTitle());
|
|
|
+ item.setCateSn(plan.getProductCateId());
|
|
|
+ item.setCateTitle(plan.getProductCateTitle());
|
|
|
+ item.setDay(formatPlanDay(plan.getDay()));
|
|
|
+ item.setShiftTitle(plan.getShiftTitle());
|
|
|
+ item.setNums(plan.getNums());
|
|
|
+ int produced = countProduced(plan.getId());
|
|
|
+ item.setProduced(produced);
|
|
|
+ if(plan.getNums() != null){
|
|
|
+ planNums += plan.getNums();
|
|
|
+ }
|
|
|
+ producedNums += produced;
|
|
|
+ items.add(item);
|
|
|
+ }
|
|
|
+ resp.setPlans(items);
|
|
|
+ resp.setPlanNums(planNums);
|
|
|
+ resp.setProducedNums(producedNums);
|
|
|
+
|
|
|
+ String cateSn = getCurrentProductCate();
|
|
|
+ resp.setCateSn(cateSn);
|
|
|
+ if(cateSn != null){
|
|
|
+ for(MesCurrentPlanItemResp item : items){
|
|
|
+ if(cateSn.equals(item.getCateSn())){
|
|
|
+ resp.setCateTitle(item.getCateTitle());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return resp;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统计计划下已生产的件数。
|
|
|
+ *
|
|
|
+ * @param planId 生产计划id
|
|
|
+ * @return 已生产件数
|
|
|
+ */
|
|
|
+ private int countProduced(String planId){
|
|
|
+ if(StringUtils.isBlank(planId)){
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ MesProduct query = new MesProduct();
|
|
|
+ query.setPlanId(planId);
|
|
|
+ return (int) mesProductService.findCount(query);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 格式化计划日期。
|
|
|
+ *
|
|
|
+ * @param day 计划日期
|
|
|
+ * @return yyyy-MM-dd
|
|
|
+ */
|
|
|
+ private String formatPlanDay(Date day){
|
|
|
+ if(day == null){
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return new SimpleDateFormat("yyyy-MM-dd").format(day);
|
|
|
+ }
|
|
|
|
|
|
}
|