浏览代码

ERP对接,优化页面选择参数

jingbo 3 月之前
父节点
当前提交
2ac5f27402
共有 22 个文件被更改,包括 734 次插入 和 215 次删除
  1. 43 6
      src/main/java/com/jeesite/modules/mes/erp/ErpPrdInStockSaveService.java
  2. 25 1
      src/main/java/com/jeesite/modules/mes/erp/ErpProductionOrderService.java
  3. 22 0
      src/main/java/com/jeesite/modules/mes/erp/KingdeeErpProperties.java
  4. 11 1
      src/main/java/com/jeesite/modules/mes/service/MesErpScheduleService.java
  5. 57 0
      src/main/java/com/jeesite/modules/mes/web/ErpInStockController.java
  6. 43 0
      src/main/java/com/jeesite/modules/mes/web/ErpPickMaterialBillController.java
  7. 123 0
      src/main/java/com/jeesite/modules/mes/web/ErpPrdInStockController.java
  8. 4 1
      src/main/java/com/jeesite/modules/mes/web/ErpProductionOrderController.java
  9. 238 188
      src/main/java/com/jeesite/modules/mes/web/ErpTransferDirectController.java
  10. 37 1
      src/main/java/com/jeesite/modules/mes/web/MesErpScheduleController.java
  11. 3 0
      src/main/resources/config/application.yml
  12. 21 1
      src/main/resources/views/modules/mes/erpInStockSelectDetail.html
  13. 8 4
      src/main/resources/views/modules/mes/erpPrdInStockForm.html
  14. 1 1
      src/main/resources/views/modules/mes/erpProductionOrderList.html
  15. 1 1
      src/main/resources/views/modules/mes/erpProductionOrderPushdown.html
  16. 16 2
      src/main/resources/views/modules/mes/erpProductionOrderScheduleSelect.html
  17. 5 3
      src/main/resources/views/modules/mes/erpTransferDirectForm.html
  18. 3 1
      src/main/resources/views/modules/mes/erpTransferDirectSelectOrder.html
  19. 1 1
      src/main/resources/views/modules/mes/mesErpScheduleBoard.html
  20. 9 1
      src/main/resources/views/modules/mes/mesErpScheduleList.html
  21. 61 0
      src/main/resources/views/modules/mes/mesErpScheduleSelectOrder.html
  22. 2 2
      src/main/resources/views/modules/mes/mesIntegratedScreen.html

+ 43 - 6
src/main/java/com/jeesite/modules/mes/erp/ErpPrdInStockSaveService.java

@@ -83,7 +83,8 @@ public class ErpPrdInStockSaveService {
 
 		List<MesBatchSn> batches = loadAndValidateBatches(request.getBatchIds(), moEntry.getMaterialNumber());
 		if (batches.isEmpty()) {
-			return ErpPrdInStockResult.fail("未找到有效的待入库批次码");
+			String batchError = diagnoseInvalidBatches(request.getBatchIds(), moEntry.getMaterialNumber());
+			return ErpPrdInStockResult.fail(StringUtils.isNotBlank(batchError) ? batchError : "未找到有效的待入库批次码");
 		}
 		BigDecimal totalQty = sumBatchQty(batches);
 		if (totalQty.compareTo(BigDecimal.ZERO) <= 0) {
@@ -134,21 +135,57 @@ public class ErpPrdInStockSaveService {
 		List<MesBatchSn> batches = mesBatchSnService.findByIds(batchIds);
 		List<MesBatchSn> valid = new ArrayList<>();
 		for (MesBatchSn batch : batches) {
+			if (isBatchValidForMaterial(batch, materialNumber)) {
+				valid.add(batch);
+			}
+		}
+		return valid;
+	}
+
+	/** 判断批次码是否可用于当前订单物料入库 */
+	private boolean isBatchValidForMaterial(MesBatchSn batch, String materialNumber) {
+		if (batch == null) {
+			return false;
+		}
+		if (batch.getNums() == null || batch.getNums() <= 0) {
+			return false;
+		}
+		if ("1".equals(StringUtils.trim(batch.getInstockStatus()))) {
+			return false;
+		}
+		return MesErpLineMaterialMapping.isLineAllowedForMaterial(batch.getLineSn(), materialNumber);
+	}
+
+	/** 批次无效时返回明确原因(扫码/提交共用规则) */
+	private String diagnoseInvalidBatches(List<String> batchIds, String materialNumber) {
+		if (batchIds == null || batchIds.isEmpty()) {
+			return "请至少选择一个 MES 批次码";
+		}
+		List<MesBatchSn> batches = mesBatchSnService.findByIds(batchIds);
+		if (batches.isEmpty()) {
+			return "未找到所选批次码记录";
+		}
+		boolean anyFound = false;
+		for (MesBatchSn batch : batches) {
 			if (batch == null) {
 				continue;
 			}
+			anyFound = true;
 			if (batch.getNums() == null || batch.getNums() <= 0) {
-				continue;
+				return "批次码 " + batch.getBatchSn() + " 绑定数量为 0,需产线扫码绑定工件后再入库";
 			}
 			if ("1".equals(StringUtils.trim(batch.getInstockStatus()))) {
-				continue;
+				return "批次码 " + batch.getBatchSn() + " 已入库,不能重复入库";
 			}
 			if (!MesErpLineMaterialMapping.isLineAllowedForMaterial(batch.getLineSn(), materialNumber)) {
-				continue;
+				return "批次码 " + batch.getBatchSn() + " 产线 " + StringUtils.trimToEmpty(batch.getLineSn())
+						+ " 与当前订单物料 " + materialNumber + " 不匹配,不能入库";
 			}
-			valid.add(batch);
 		}
-		return valid;
+		if (!anyFound) {
+			return "未找到所选批次码记录";
+		}
+		return "未找到有效的待入库批次码";
 	}
 
 	private BigDecimal sumBatchQty(List<MesBatchSn> batches) {

+ 25 - 1
src/main/java/com/jeesite/modules/mes/erp/ErpProductionOrderService.java

@@ -117,6 +117,17 @@ public class ErpProductionOrderService {
 	}
 
 	/**
+	 * ERP 排产选单:按配置的排产成品物料编码过滤。
+	 */
+	public List<ErpProductionOrder> findScheduleOrderPageList(String billNo, int startRow, int limit) {
+		List<String> materialNumbers = erpProperties.getScheduleMaterialNumbers();
+		if (!materialNumbers.isEmpty()) {
+			return findAggregatedPageListByMaterialNumbers(billNo, startRow, limit, materialNumbers);
+		}
+		return findPageList(billNo, startRow, limit);
+	}
+
+	/**
 	 * 生产入库选单:仍按配置 HEV/115 物料编码过滤。
 	 */
 	public List<ErpProductionOrder> findPrdInStockOrderPageList(String billNo, int startRow, int limit) {
@@ -154,7 +165,7 @@ public class ErpProductionOrderService {
 				break;
 			}
 			for (ErpProductionOrder detail : chunk) {
-				if (!erpProperties.isAllowedProductionOrderMaterial(detail.getMaterialNumber())) {
+				if (!isMaterialInConfiguredList(detail.getMaterialNumber(), materialNumbers)) {
 					continue;
 				}
 				ErpProductionOrder order = orderMap.get(detail.getBillNo());
@@ -205,6 +216,19 @@ public class ErpProductionOrderService {
 		return list;
 	}
 
+	private boolean isMaterialInConfiguredList(String materialNumber, List<String> materialNumbers) {
+		if (StringUtils.isBlank(materialNumber) || materialNumbers == null || materialNumbers.isEmpty()) {
+			return false;
+		}
+		String trimmed = materialNumber.trim();
+		for (String allowed : materialNumbers) {
+			if (allowed != null && trimmed.equals(allowed.trim())) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	private String buildMaterialNumberFilter(String billNo, List<String> materialNumbers) {
 		List<String> parts = new ArrayList<>();
 		for (String materialNumber : materialNumbers) {

+ 22 - 0
src/main/java/com/jeesite/modules/mes/erp/KingdeeErpProperties.java

@@ -168,6 +168,10 @@ public class KingdeeErpProperties {
 	@Value("${erp.k3cloud.prd-in-stock.default-stock-number:}")
 	private String prdInStockDefaultStockNumber;
 
+	/** ERP 排产计划下推选分录时的成品物料编码(HEV / 115) */
+	@Value("${erp.k3cloud.schedule.material-numbers:8.10.HEV.05.049025,8.35.115.05.5003146600021}")
+	private String scheduleMaterialNumbers;
+
 	public String getBaseUrl() {
 		if (baseUrl.endsWith("/")) {
 			return baseUrl.substring(0, baseUrl.length() - 1);
@@ -397,6 +401,24 @@ public class KingdeeErpProperties {
 		return false;
 	}
 
+	/** ERP 排产计划可选分录的成品物料编码 */
+	public java.util.List<String> getScheduleMaterialNumbers() {
+		return parseMaterialNumbers(scheduleMaterialNumbers);
+	}
+
+	public boolean isAllowedScheduleMaterial(String materialNumber) {
+		if (StringUtils.isBlank(materialNumber)) {
+			return false;
+		}
+		String trimmed = materialNumber.trim();
+		for (String allowed : getScheduleMaterialNumbers()) {
+			if (trimmed.equals(allowed)) {
+				return true;
+			}
+		}
+		return false;
+	}
+
 	public String getPrdInStockBillType() {
 		return prdInStockBillType;
 	}

+ 11 - 1
src/main/java/com/jeesite/modules/mes/service/MesErpScheduleService.java

@@ -12,6 +12,7 @@ import com.jeesite.modules.mes.entity.MesLineProcess;
 import com.jeesite.modules.mes.entity.MesProductRecord;
 import com.jeesite.modules.mes.erp.ErpProductionOrder;
 import com.jeesite.modules.mes.erp.ErpProductionOrderService;
+import com.jeesite.modules.mes.erp.KingdeeErpProperties;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.ObjectUtils;
@@ -58,17 +59,20 @@ public class MesErpScheduleService extends CrudService<MesErpScheduleDao, MesErp
 	private final MesLineProcessService mesLineProcessService;
 	private final MesProductRecordService mesProductRecordService;
 	private final ErpProductionOrderService erpProductionOrderService;
+	private final KingdeeErpProperties erpProperties;
 
 	public MesErpScheduleService(MesErpScheduleDao mesErpScheduleDao,
 			MesLineService mesLineService,
 			MesLineProcessService mesLineProcessService,
 			MesProductRecordService mesProductRecordService,
-			ErpProductionOrderService erpProductionOrderService) {
+			ErpProductionOrderService erpProductionOrderService,
+			KingdeeErpProperties erpProperties) {
 		this.mesErpScheduleDao = mesErpScheduleDao;
 		this.mesLineService = mesLineService;
 		this.mesLineProcessService = mesLineProcessService;
 		this.mesProductRecordService = mesProductRecordService;
 		this.erpProductionOrderService = erpProductionOrderService;
+		this.erpProperties = erpProperties;
 	}
 
 	@Override
@@ -114,6 +118,9 @@ public class MesErpScheduleService extends CrudService<MesErpScheduleDao, MesErp
 		if (erpLine == null) {
 			throw new ServiceException(text("未找到对应的ERP生产订单明细"));
 		}
+		if (!erpProperties.isAllowedScheduleMaterial(erpLine.getMaterialNumber())) {
+			throw new ServiceException(text("该分录物料不在排产范围内,仅支持配置的 HEV/115 成品物料"));
+		}
 
 		MesErpSchedule schedule = new MesErpSchedule();
 		schedule.setErpBillNo(erpLine.getBillNo());
@@ -459,6 +466,9 @@ public class MesErpScheduleService extends CrudService<MesErpScheduleDao, MesErp
 		}
 
 		MesErpSchedule erpInfo = buildFromErpEntry(mesErpSchedule.getErpBillNo(), mesErpSchedule.getErpEntryId());
+		if (!erpProperties.isAllowedScheduleMaterial(erpInfo.getMaterialNumber())) {
+			throw new ServiceException(text("该分录物料不在排产范围内,仅支持配置的 HEV/115 成品物料"));
+		}
 		if (StringUtils.isBlank(mesErpSchedule.getMaterialNumber())) {
 			mesErpSchedule.setMaterialNumber(erpInfo.getMaterialNumber());
 			mesErpSchedule.setMaterialName(erpInfo.getMaterialName());

+ 57 - 0
src/main/java/com/jeesite/modules/mes/web/ErpInStockController.java

@@ -331,7 +331,64 @@ public class ErpInStockController extends BaseController {
 
 	}
 
+	/**
+	 * PDA/前端:入库仓库列表(与来料检页 inspect 一致)。
+	 */
+	@RequiresPermissions("mes:erpInStock:view")
+	@GetMapping(value = "stockList")
+	@ResponseBody
+	public Map<String, Object> stockList() {
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		Map<String, Object> result = new HashMap<>(4);
+		result.put("stockList", stocks);
+		result.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		if (stocks.isEmpty()) {
+			result.put("stockHint", "未能从 ERP 加载仓库列表,请检查组织与 ERP 连接");
+		} else {
+			result.put("stockHint", "共 " + stocks.size() + " 个可用仓库");
+		}
+		return result;
+	}
 
+	/**
+	 * PDA/前端:来料检页初始化(勾选分录 + 仓库 + 批号信息一次返回)。
+	 */
+	@RequiresPermissions("mes:erpInStock:view")
+	@GetMapping(value = "inspectInit")
+	@ResponseBody
+	public Map<String, Object> inspectInit(String billNo, String entryIds, String entryId) {
+		Map<String, Object> result = new HashMap<>(8);
+		String poBillNo = billNo == null ? "" : billNo.trim();
+		result.put("billNo", poBillNo);
+		List<String> idList = parseEntryIds(entryIds, entryId);
+		if (StringUtils.isBlank(poBillNo)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "采购订单号不能为空");
+			result.put("lines", new ArrayList<>());
+			return result;
+		}
+		if (idList.isEmpty()) {
+			result.put("result", Global.FALSE);
+			result.put("message", "请至少选择一条待入分录");
+			result.put("lines", new ArrayList<>());
+			return result;
+		}
+		List<ErpPurchaseOrder> detailList = erpInStockService.findPendingPoDetails(poBillNo, idList);
+		if (detailList.isEmpty()) {
+			result.put("result", Global.FALSE);
+			result.put("message", "所选分录已无剩余可入数量");
+			result.put("lines", new ArrayList<>());
+		} else {
+			erpInStockService.enrichInspectLotInfo(detailList);
+			result.put("result", Global.TRUE);
+			result.put("message", "");
+			result.put("lines", detailList);
+		}
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		result.put("stockList", stocks);
+		result.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		return result;
+	}
 
 	@RequiresPermissions("mes:erpInStock:view")
 

+ 43 - 0
src/main/java/com/jeesite/modules/mes/web/ErpPickMaterialBillController.java

@@ -27,6 +27,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.math.BigDecimal;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -159,6 +160,48 @@ public class ErpPickMaterialBillController extends BaseController {
 		return page;
 	}
 
+	/**
+	 * PDA/前端:领料页初始化(订单分录 + 生产用料清单)。
+	 */
+	@RequiresPermissions("mes:erpPickMaterialBill:view")
+	@GetMapping(value = "materialInit")
+	@ResponseBody
+	public Map<String, Object> materialInit(String billNo, String entryId) {
+		Map<String, Object> result = new HashMap<>(8);
+		String moBillNo = StringUtils.trim(billNo);
+		String moEntryId = StringUtils.trim(entryId);
+		result.put("billNo", moBillNo);
+		result.put("entryId", moEntryId);
+		if (StringUtils.isBlank(moBillNo) || StringUtils.isBlank(moEntryId)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "生产订单号与分录内码不能为空");
+			result.put("moEntry", null);
+			result.put("materialList", Collections.emptyList());
+			return result;
+		}
+		ErpProductionOrder moEntry = null;
+		for (ErpProductionOrder detail : erpProductionOrderService.findDetailList(moBillNo)) {
+			if (detail != null && moEntryId.equals(StringUtils.trim(detail.getEntryId()))) {
+				moEntry = detail;
+				break;
+			}
+		}
+		if (moEntry == null) {
+			result.put("result", Global.FALSE);
+			result.put("message", "未找到生产订单分录");
+			result.put("moEntry", null);
+			result.put("materialList", Collections.emptyList());
+			return result;
+		}
+		List<ErpProductionMaterial> materialList = erpProductionMaterialService.findByProductionOrderEntry(
+				moBillNo, moEntryId, true);
+		result.put("result", Global.TRUE);
+		result.put("message", materialList.isEmpty() ? "未找到生产用料清单或已全部领完" : "");
+		result.put("moEntry", moEntry);
+		result.put("materialList", materialList);
+		return result;
+	}
+
 	@RequiresPermissions("mes:erpPickMaterialBill:view")
 	@GetMapping(value = "lotOptions")
 	@ResponseBody

+ 123 - 0
src/main/java/com/jeesite/modules/mes/web/ErpPrdInStockController.java

@@ -62,6 +62,10 @@ import javax.servlet.http.HttpServletRequest;
 
 import javax.servlet.http.HttpServletResponse;
 
+import java.util.ArrayList;
+
+import java.util.Collections;
+
 import java.util.HashMap;
 
 import java.util.List;
@@ -364,7 +368,126 @@ public class ErpPrdInStockController extends BaseController {
 
 	}
 
+	/**
+	 * PDA/前端:入库仓库列表。
+	 */
+	@RequiresPermissions("mes:erpPrdInStock:view")
+	@GetMapping(value = "stockList")
+	@ResponseBody
+	public Map<String, Object> stockList() {
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		Map<String, Object> result = new HashMap<>(4);
+		result.put("stockList", stocks);
+		result.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		result.put("stockHint", stocks.isEmpty() ? "未能从 ERP 加载仓库列表" : "共 " + stocks.size() + " 个可用仓库");
+		return result;
+	}
 
+	/**
+	 * PDA/前端:选批次入库页初始化(订单分录 + 待入库 MES 批次码 + 仓库)。
+	 */
+	@RequiresPermissions("mes:erpPrdInStock:view")
+	@GetMapping(value = "formInit")
+	@ResponseBody
+	public Map<String, Object> formInit(String moBillNo, String entryId) {
+		Map<String, Object> result = new HashMap<>(10);
+		String billNo = StringUtils.trim(moBillNo);
+		String moEntryId = StringUtils.trim(entryId);
+		result.put("moBillNo", billNo);
+		result.put("entryId", moEntryId);
+		if (StringUtils.isBlank(billNo) || StringUtils.isBlank(moEntryId)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "生产订单号与分录内码不能为空");
+			result.put("moEntry", null);
+			result.put("batchList", Collections.emptyList());
+			result.put("stockList", Collections.emptyList());
+			return result;
+		}
+		ErpProductionOrder moEntry = erpProductionOrderService.findInstockMoEntry(billNo, moEntryId);
+		if (moEntry == null) {
+			result.put("result", Global.FALSE);
+			result.put("message", "未找到生产订单分录");
+			result.put("moEntry", null);
+			result.put("batchList", Collections.emptyList());
+		} else {
+			erpPrdInStockService.enrichMoInstockProgress(billNo, Collections.singletonList(moEntry));
+			List<MesBatchSn> batchList = mesBatchSnService.findPendingInstockByMaterial(moEntry.getMaterialNumber());
+			result.put("result", Global.TRUE);
+			result.put("moEntry", moEntry);
+			result.put("batchList", batchList);
+			if (batchList.isEmpty()) {
+				List<String> lines = MesErpLineMaterialMapping.resolveLineSnList(moEntry.getMaterialNumber());
+				String lineHint = lines.isEmpty() ? "(该物料未配置产线映射)" : lines.toString();
+				result.put("message", "暂无待入库 MES 批次码。须产线 " + lineHint + "、nums>0、且未入库");
+			} else {
+				result.put("message", "");
+			}
+		}
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		result.put("stockList", stocks);
+		result.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		return result;
+	}
+
+	/**
+	 * PDA/前端:扫 MES 批次码校验(是否可入当前物料)。
+	 */
+	@RequiresPermissions("mes:erpPrdInStock:view")
+	@GetMapping(value = "batchScan")
+	@ResponseBody
+	public Map<String, Object> batchScan(String batchSn, String materialNumber) {
+		Map<String, Object> result = new HashMap<>(6);
+		String sn = StringUtils.trim(batchSn);
+		String material = StringUtils.trim(materialNumber);
+		if (StringUtils.isBlank(sn)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "批次码不能为空");
+			return result;
+		}
+		if (StringUtils.isBlank(material)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "物料编码不能为空");
+			return result;
+		}
+		MesBatchSn query = new MesBatchSn();
+		query.setBatchSn(sn);
+		List<MesBatchSn> found = mesBatchSnService.findList(query);
+		MesBatchSn batch = null;
+		for (MesBatchSn item : found) {
+			if (item != null && sn.equals(StringUtils.trim(item.getBatchSn()))) {
+				batch = item;
+				break;
+			}
+		}
+		if (batch == null) {
+			result.put("result", Global.FALSE);
+			result.put("message", "未找到该 MES 批次码");
+			return result;
+		}
+		if (batch.getNums() == null || batch.getNums() <= 0) {
+			result.put("result", Global.FALSE);
+			result.put("message", "该批次码绑定数量为 0,需产线扫码绑定工件后再入库");
+			result.put("batch", batch);
+			return result;
+		}
+		if ("1".equals(StringUtils.trim(batch.getInstockStatus()))) {
+			result.put("result", Global.FALSE);
+			result.put("message", "该批次码已入库");
+			result.put("batch", batch);
+			return result;
+		}
+		if (!MesErpLineMaterialMapping.isLineAllowedForMaterial(batch.getLineSn(), material)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "批次码产线 " + StringUtils.trimToEmpty(batch.getLineSn())
+					+ " 与当前物料 " + material + " 不匹配,不能入库");
+			result.put("batch", batch);
+			return result;
+		}
+		result.put("result", Global.TRUE);
+		result.put("message", "可以入库");
+		result.put("batch", batch);
+		return result;
+	}
 
 	@RequiresPermissions("mes:erpPrdInStock:view")
 

+ 4 - 1
src/main/java/com/jeesite/modules/mes/web/ErpProductionOrderController.java

@@ -103,6 +103,9 @@ public class ErpProductionOrderController extends BaseController {
 	@RequestMapping(value = "scheduleSelect")
 	public String scheduleSelect(ErpProductionOrder erpProductionOrder, Model model) {
 		model.addAttribute("erpProductionOrder", erpProductionOrder);
+		List<String> scheduleMaterialNumbers = erpProperties.getScheduleMaterialNumbers();
+		model.addAttribute("scheduleMaterialNumbers", scheduleMaterialNumbers);
+		model.addAttribute("scheduleMaterialNumbersText", String.join(" / ", scheduleMaterialNumbers));
 		return "modules/mes/erpProductionOrderScheduleSelect";
 	}
 
@@ -113,7 +116,7 @@ public class ErpProductionOrderController extends BaseController {
 			HttpServletRequest request, HttpServletResponse response) {
 		Page<ErpProductionOrder> page = new Page<>(request, response);
 		List<ErpProductionOrder> list = erpProductionOrderService.findDetailList(erpProductionOrder.getBillNo());
-		list.removeIf(row -> row == null || !erpProperties.isAllowedProductionOrderMaterial(row.getMaterialNumber()));
+		list.removeIf(row -> row == null || !erpProperties.isAllowedScheduleMaterial(row.getMaterialNumber()));
 		page.setList(list);
 		page.setCount(list.size());
 		return page;

+ 238 - 188
src/main/java/com/jeesite/modules/mes/web/ErpTransferDirectController.java

@@ -1,188 +1,238 @@
-package com.jeesite.modules.mes.web;

-

-import com.jeesite.common.config.Global;

-import com.jeesite.common.entity.Page;

-import com.jeesite.common.lang.StringUtils;

-import com.jeesite.common.web.BaseController;

-import com.jeesite.modules.mes.erp.ErpPrdInStock;

-import com.jeesite.modules.mes.erp.ErpPrdInStockService;

-import com.jeesite.modules.mes.erp.ErpProductionOrder;

-import com.jeesite.modules.mes.erp.ErpProductionOrderService;

-import com.jeesite.modules.mes.erp.ErpStockLocOption;

-import com.jeesite.modules.mes.erp.ErpStockLocService;

-import com.jeesite.modules.mes.erp.ErpStockOption;

-import com.jeesite.modules.mes.erp.ErpStockService;

-import com.jeesite.modules.mes.erp.ErpTransferDirect;

-import com.jeesite.modules.mes.erp.ErpTransferDirectResult;

-import com.jeesite.modules.mes.erp.ErpTransferDirectSaveService;

-import com.jeesite.modules.mes.erp.ErpTransferDirectService;

-import com.jeesite.modules.mes.erp.ErpTransferDirectSubmitRequest;

-import com.jeesite.modules.mes.erp.KingdeeErpProperties;

-import org.apache.shiro.authz.annotation.RequiresPermissions;

-import org.springframework.stereotype.Controller;

-import org.springframework.ui.Model;

-import org.springframework.web.bind.annotation.GetMapping;

-import org.springframework.web.bind.annotation.PostMapping;

-import org.springframework.web.bind.annotation.RequestBody;

-import org.springframework.web.bind.annotation.RequestMapping;

-import org.springframework.web.bind.annotation.ResponseBody;

-

-import javax.servlet.http.HttpServletRequest;

-import javax.servlet.http.HttpServletResponse;

-import java.util.HashMap;

-import java.util.List;

-import java.util.Map;

-

-/**

- * ERP 直接调拨单查询与新增。

- */

-@Controller

-@RequestMapping(value = "${adminPath}/mes/erpTransferDirect")

-public class ErpTransferDirectController extends BaseController {

-

-	private final ErpTransferDirectService erpTransferDirectService;

-	private final ErpTransferDirectSaveService erpTransferDirectSaveService;

-	private final ErpProductionOrderService erpProductionOrderService;

-	private final ErpPrdInStockService erpPrdInStockService;

-	private final ErpStockService erpStockService;

-	private final ErpStockLocService erpStockLocService;

-	private final KingdeeErpProperties erpProperties;

-

-	public ErpTransferDirectController(ErpTransferDirectService erpTransferDirectService,

-			ErpTransferDirectSaveService erpTransferDirectSaveService,

-			ErpProductionOrderService erpProductionOrderService,

-			ErpPrdInStockService erpPrdInStockService,

-			ErpStockService erpStockService,

-			ErpStockLocService erpStockLocService,

-			KingdeeErpProperties erpProperties) {

-		this.erpTransferDirectService = erpTransferDirectService;

-		this.erpTransferDirectSaveService = erpTransferDirectSaveService;

-		this.erpProductionOrderService = erpProductionOrderService;

-		this.erpPrdInStockService = erpPrdInStockService;

-		this.erpStockService = erpStockService;

-		this.erpStockLocService = erpStockLocService;

-		this.erpProperties = erpProperties;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = {"list", ""})

-	public String list(ErpTransferDirect erpTransferDirect, Model model) {

-		model.addAttribute("erpTransferDirect", erpTransferDirect);

-		return "modules/mes/erpTransferDirectList";

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "listData")

-	@ResponseBody

-	public Page<ErpTransferDirect> listData(ErpTransferDirect erpTransferDirect,

-			HttpServletRequest request, HttpServletResponse response) {

-		Page<ErpTransferDirect> page = new Page<>(request, response);

-		int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 20;

-		int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;

-		int startRow = (pageNo - 1) * pageSize;

-		List<ErpTransferDirect> list = erpTransferDirectService.findPageList(erpTransferDirect, startRow, pageSize);

-		page.setList(list);

-		page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0));

-		return page;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "detail")

-	public String detail(ErpTransferDirect erpTransferDirect, Model model) {

-		model.addAttribute("erpTransferDirect", erpTransferDirect);

-		return "modules/mes/erpTransferDirectDetail";

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "detailData")

-	@ResponseBody

-	public Page<ErpTransferDirect> detailData(ErpTransferDirect erpTransferDirect,

-			HttpServletRequest request, HttpServletResponse response) {

-		Page<ErpTransferDirect> page = new Page<>(request, response);

-		List<ErpTransferDirect> list = erpTransferDirectService.findDetailList(erpTransferDirect.getBillNo());

-		page.setList(list);

-		page.setCount(list.size());

-		return page;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "selectOrder")

-	public String selectOrder(ErpProductionOrder erpProductionOrder, Model model) {

-		model.addAttribute("erpProductionOrder", erpProductionOrder);

-		return "modules/mes/erpTransferDirectSelectOrder";

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "selectOrderData")

-	@ResponseBody

-	public Page<ErpProductionOrder> selectOrderData(ErpProductionOrder erpProductionOrder,

-			HttpServletRequest request, HttpServletResponse response) {

-		Page<ErpProductionOrder> page = new Page<>(request, response);

-		int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 20;

-		int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;

-		int startRow = (pageNo - 1) * pageSize;

-		List<ErpProductionOrder> list = erpProductionOrderService.findPageList(

-				erpProductionOrder.getBillNo(), startRow, pageSize);

-		page.setList(list);

-		page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0));

-		return page;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "form")

-	public String form(String moBillNo, Model model) {

-		String billNo = StringUtils.trim(moBillNo);

-		List<ErpPrdInStock> sourceList = erpPrdInStockService.findTransferSourceByMoBillNo(billNo);

-		List<ErpStockOption> stockList = erpStockService.findUsableStockList();

-		model.addAttribute("moBillNo", billNo);

-		model.addAttribute("sourceList", sourceList);

-		model.addAttribute("stockList", stockList);

-		model.addAttribute("defaultSrcStockNumber", erpStockService.resolveDefaultStockNumber(stockList));

-		model.addAttribute("defaultDestStockNumber", StringUtils.trim(erpProperties.getTransferDirectDefaultDestStockNumber()));

-		if (sourceList.isEmpty()) {

-			model.addAttribute("message", "该生产订单暂无 HEV/115 生产入库行,请先完成生产入库");

-		}

-		return "modules/mes/erpTransferDirectForm";

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@RequestMapping(value = "instockSourceData")

-	@ResponseBody

-	public Page<ErpPrdInStock> instockSourceData(String moBillNo,

-			HttpServletRequest request, HttpServletResponse response) {

-		Page<ErpPrdInStock> page = new Page<>(request, response);

-		List<ErpPrdInStock> list = erpPrdInStockService.findTransferSourceByMoBillNo(moBillNo);

-		page.setList(list);

-		page.setCount(list.size());

-		return page;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@GetMapping(value = "stockLocOptions")

-	@ResponseBody

-	public Map<String, Object> stockLocOptions(String stockNumber) {

-		List<ErpStockLocOption> locations = erpStockLocService.findLocationsByStock(stockNumber);

-		Map<String, Object> result = new HashMap<>(4);

-		boolean required = !locations.isEmpty();

-		result.put("required", required);

-		result.put("locations", locations);

-		result.put("defaultLocNumber", erpStockLocService.resolveDefaultLocNumber(stockNumber, locations));

-		if (locations.isEmpty()) {

-			result.put("locHint", "该仓库未启用仓位或未配置仓位值集");

-		} else {

-			result.put("locHint", "共 " + locations.size() + " 个仓位");

-		}

-		return result;

-	}

-

-	@RequiresPermissions("mes:erpTransferDirect:view")

-	@PostMapping(value = "submit")

-	@ResponseBody

-	public String submit(@RequestBody ErpTransferDirectSubmitRequest request) {

-		ErpTransferDirectResult result = erpTransferDirectSaveService.submit(request);

-		if (result.isSuccess()) {

-			return renderResult(Global.TRUE, text("直接调拨单保存成功,单号:{0}", result.getBillNo()));

-		}

-		return renderResult(Global.FALSE, result.getMessage());

-	}

-}

+package com.jeesite.modules.mes.web;
+
+import com.jeesite.common.config.Global;
+import com.jeesite.common.entity.Page;
+import com.jeesite.common.lang.StringUtils;
+import com.jeesite.common.web.BaseController;
+import com.jeesite.modules.mes.erp.ErpPrdInStock;
+import com.jeesite.modules.mes.erp.ErpPrdInStockService;
+import com.jeesite.modules.mes.erp.ErpProductionOrder;
+import com.jeesite.modules.mes.erp.ErpProductionOrderService;
+import com.jeesite.modules.mes.erp.ErpStockLocOption;
+import com.jeesite.modules.mes.erp.ErpStockLocService;
+import com.jeesite.modules.mes.erp.ErpStockOption;
+import com.jeesite.modules.mes.erp.ErpStockService;
+import com.jeesite.modules.mes.erp.ErpTransferDirect;
+import com.jeesite.modules.mes.erp.ErpTransferDirectResult;
+import com.jeesite.modules.mes.erp.ErpTransferDirectSaveService;
+import com.jeesite.modules.mes.erp.ErpTransferDirectService;
+import com.jeesite.modules.mes.erp.ErpTransferDirectSubmitRequest;
+import com.jeesite.modules.mes.erp.KingdeeErpProperties;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * ERP 直接调拨单查询与新增。
+ */
+@Controller
+@RequestMapping(value = "${adminPath}/mes/erpTransferDirect")
+public class ErpTransferDirectController extends BaseController {
+
+	private final ErpTransferDirectService erpTransferDirectService;
+	private final ErpTransferDirectSaveService erpTransferDirectSaveService;
+	private final ErpProductionOrderService erpProductionOrderService;
+	private final ErpPrdInStockService erpPrdInStockService;
+	private final ErpStockService erpStockService;
+	private final ErpStockLocService erpStockLocService;
+	private final KingdeeErpProperties erpProperties;
+
+	public ErpTransferDirectController(ErpTransferDirectService erpTransferDirectService,
+			ErpTransferDirectSaveService erpTransferDirectSaveService,
+			ErpProductionOrderService erpProductionOrderService,
+			ErpPrdInStockService erpPrdInStockService,
+			ErpStockService erpStockService,
+			ErpStockLocService erpStockLocService,
+			KingdeeErpProperties erpProperties) {
+		this.erpTransferDirectService = erpTransferDirectService;
+		this.erpTransferDirectSaveService = erpTransferDirectSaveService;
+		this.erpProductionOrderService = erpProductionOrderService;
+		this.erpPrdInStockService = erpPrdInStockService;
+		this.erpStockService = erpStockService;
+		this.erpStockLocService = erpStockLocService;
+		this.erpProperties = erpProperties;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = {"list", ""})
+	public String list(ErpTransferDirect erpTransferDirect, Model model) {
+		model.addAttribute("erpTransferDirect", erpTransferDirect);
+		return "modules/mes/erpTransferDirectList";
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "listData")
+	@ResponseBody
+	public Page<ErpTransferDirect> listData(ErpTransferDirect erpTransferDirect,
+			HttpServletRequest request, HttpServletResponse response) {
+		Page<ErpTransferDirect> page = new Page<>(request, response);
+		int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 20;
+		int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;
+		int startRow = (pageNo - 1) * pageSize;
+		List<ErpTransferDirect> list = erpTransferDirectService.findPageList(erpTransferDirect, startRow, pageSize);
+		page.setList(list);
+		page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0));
+		return page;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "detail")
+	public String detail(ErpTransferDirect erpTransferDirect, Model model) {
+		model.addAttribute("erpTransferDirect", erpTransferDirect);
+		return "modules/mes/erpTransferDirectDetail";
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "detailData")
+	@ResponseBody
+	public Page<ErpTransferDirect> detailData(ErpTransferDirect erpTransferDirect,
+			HttpServletRequest request, HttpServletResponse response) {
+		Page<ErpTransferDirect> page = new Page<>(request, response);
+		List<ErpTransferDirect> list = erpTransferDirectService.findDetailList(erpTransferDirect.getBillNo());
+		page.setList(list);
+		page.setCount(list.size());
+		return page;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "selectOrder")
+	public String selectOrder(ErpProductionOrder erpProductionOrder, Model model) {
+		model.addAttribute("erpProductionOrder", erpProductionOrder);
+		return "modules/mes/erpTransferDirectSelectOrder";
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "selectOrderData")
+	@ResponseBody
+	public Page<ErpProductionOrder> selectOrderData(ErpProductionOrder erpProductionOrder,
+			HttpServletRequest request, HttpServletResponse response) {
+		Page<ErpProductionOrder> page = new Page<>(request, response);
+		int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 20;
+		int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;
+		int startRow = (pageNo - 1) * pageSize;
+		// 与生产入库一致:仅展示配置 HEV/115 物料(.10)的生产订单
+		List<ErpProductionOrder> list = erpProductionOrderService.findPrdInStockOrderPageList(
+				erpProductionOrder.getBillNo(), startRow, pageSize);
+		page.setList(list);
+		page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0));
+		return page;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "form")
+	public String form(String moBillNo, Model model) {
+		String billNo = StringUtils.trim(moBillNo);
+		List<ErpPrdInStock> sourceList = erpPrdInStockService.findTransferSourceByMoBillNo(billNo);
+		List<ErpStockOption> stockList = erpStockService.findUsableStockList();
+		model.addAttribute("moBillNo", billNo);
+		model.addAttribute("sourceList", sourceList);
+		model.addAttribute("stockList", stockList);
+		model.addAttribute("defaultSrcStockNumber", erpStockService.resolveDefaultStockNumber(stockList));
+		model.addAttribute("defaultDestStockNumber", StringUtils.trim(erpProperties.getTransferDirectDefaultDestStockNumber()));
+		if (sourceList.isEmpty()) {
+			model.addAttribute("message", "该生产订单暂无 HEV/115 生产入库行,请先完成生产入库");
+		}
+		return "modules/mes/erpTransferDirectForm";
+	}
+
+	/**
+	 * PDA/前端:入库仓库列表。
+	 */
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@GetMapping(value = "stockList")
+	@ResponseBody
+	public Map<String, Object> stockList() {
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		Map<String, Object> result = new HashMap<>(4);
+		result.put("stockList", stocks);
+		result.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		result.put("defaultDestStockNumber", StringUtils.trim(erpProperties.getTransferDirectDefaultDestStockNumber()));
+		result.put("stockHint", stocks.isEmpty() ? "未能从 ERP 加载仓库列表" : "共 " + stocks.size() + " 个可用仓库");
+		return result;
+	}
+
+	/**
+	 * PDA/前端:新增调拨页初始化(生产入库源行 + 仓库)。
+	 */
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@GetMapping(value = "formInit")
+	@ResponseBody
+	public Map<String, Object> formInit(String moBillNo) {
+		Map<String, Object> result = new HashMap<>(10);
+		String billNo = StringUtils.trim(moBillNo);
+		result.put("moBillNo", billNo);
+		if (StringUtils.isBlank(billNo)) {
+			result.put("result", Global.FALSE);
+			result.put("message", "生产订单号不能为空");
+			result.put("sourceList", Collections.emptyList());
+			return result;
+		}
+		List<ErpPrdInStock> sourceList = erpPrdInStockService.findTransferSourceByMoBillNo(billNo);
+		result.put("result", Global.TRUE);
+		result.put("sourceList", sourceList);
+		if (sourceList.isEmpty()) {
+			result.put("message", "该生产订单暂无 HEV/115 生产入库行,请先完成生产入库");
+		} else {
+			result.put("message", "");
+		}
+		List<ErpStockOption> stocks = erpStockService.findUsableStockList();
+		result.put("stockList", stocks);
+		result.put("defaultSrcStockNumber", erpStockService.resolveDefaultStockNumber(stocks));
+		result.put("defaultDestStockNumber", StringUtils.trim(erpProperties.getTransferDirectDefaultDestStockNumber()));
+		return result;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@RequestMapping(value = "instockSourceData")
+	@ResponseBody
+	public Page<ErpPrdInStock> instockSourceData(String moBillNo,
+			HttpServletRequest request, HttpServletResponse response) {
+		Page<ErpPrdInStock> page = new Page<>(request, response);
+		List<ErpPrdInStock> list = erpPrdInStockService.findTransferSourceByMoBillNo(moBillNo);
+		page.setList(list);
+		page.setCount(list.size());
+		return page;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@GetMapping(value = "stockLocOptions")
+	@ResponseBody
+	public Map<String, Object> stockLocOptions(String stockNumber) {
+		List<ErpStockLocOption> locations = erpStockLocService.findLocationsByStock(stockNumber);
+		Map<String, Object> result = new HashMap<>(4);
+		boolean required = !locations.isEmpty();
+		result.put("required", required);
+		result.put("locations", locations);
+		result.put("defaultLocNumber", erpStockLocService.resolveDefaultLocNumber(stockNumber, locations));
+		if (locations.isEmpty()) {
+			result.put("locHint", "该仓库未启用仓位或未配置仓位值集");
+		} else {
+			result.put("locHint", "共 " + locations.size() + " 个仓位");
+		}
+		return result;
+	}
+
+	@RequiresPermissions("mes:erpTransferDirect:view")
+	@PostMapping(value = "submit")
+	@ResponseBody
+	public String submit(@RequestBody ErpTransferDirectSubmitRequest request) {
+		ErpTransferDirectResult result = erpTransferDirectSaveService.submit(request);
+		if (result.isSuccess()) {
+			return renderResult(Global.TRUE, text("直接调拨单保存成功,单号:{0}", result.getBillNo()));
+		}
+		return renderResult(Global.FALSE, result.getMessage());
+	}
+}

+ 37 - 1
src/main/java/com/jeesite/modules/mes/web/MesErpScheduleController.java

@@ -6,6 +6,9 @@ import com.jeesite.common.lang.StringUtils;
 import com.jeesite.common.web.BaseController;
 import com.jeesite.modules.mes.entity.MesErpSchedule;
 import com.jeesite.modules.mes.entity.MesLine;
+import com.jeesite.modules.mes.erp.ErpProductionOrder;
+import com.jeesite.modules.mes.erp.ErpProductionOrderService;
+import com.jeesite.modules.mes.erp.KingdeeErpProperties;
 import com.jeesite.modules.mes.service.MesErpScheduleService;
 import com.jeesite.modules.mes.service.MesLineService;
 import org.apache.shiro.authz.annotation.Logical;
@@ -34,11 +37,17 @@ public class MesErpScheduleController extends BaseController {
 
 	private final MesErpScheduleService mesErpScheduleService;
 	private final MesLineService mesLineService;
+	private final ErpProductionOrderService erpProductionOrderService;
+	private final KingdeeErpProperties erpProperties;
 
 	public MesErpScheduleController(MesErpScheduleService mesErpScheduleService,
-			MesLineService mesLineService) {
+			MesLineService mesLineService,
+			ErpProductionOrderService erpProductionOrderService,
+			KingdeeErpProperties erpProperties) {
 		this.mesErpScheduleService = mesErpScheduleService;
 		this.mesLineService = mesLineService;
+		this.erpProductionOrderService = erpProductionOrderService;
+		this.erpProperties = erpProperties;
 	}
 
 	@ModelAttribute
@@ -50,9 +59,36 @@ public class MesErpScheduleController extends BaseController {
 	@RequestMapping(value = {"list", ""})
 	public String list(MesErpSchedule mesErpSchedule, Model model) {
 		model.addAttribute("mesErpSchedule", mesErpSchedule);
+		List<String> scheduleMaterialNumbers = erpProperties.getScheduleMaterialNumbers();
+		model.addAttribute("scheduleMaterialNumbersText", String.join(" / ", scheduleMaterialNumbers));
 		return "modules/mes/mesErpScheduleList";
 	}
 
+	@RequiresPermissions(value = {"mes:mesErpSchedule:view", "mes:erpProductionOrder:view"}, logical = Logical.OR)
+	@RequestMapping(value = "selectOrder")
+	public String selectOrder(ErpProductionOrder erpProductionOrder, Model model) {
+		model.addAttribute("erpProductionOrder", erpProductionOrder);
+		List<String> scheduleMaterialNumbers = erpProperties.getScheduleMaterialNumbers();
+		model.addAttribute("scheduleMaterialNumbersText", String.join(" / ", scheduleMaterialNumbers));
+		return "modules/mes/mesErpScheduleSelectOrder";
+	}
+
+	@RequiresPermissions(value = {"mes:mesErpSchedule:view", "mes:erpProductionOrder:view"}, logical = Logical.OR)
+	@RequestMapping(value = "selectOrderData")
+	@ResponseBody
+	public Page<ErpProductionOrder> selectOrderData(ErpProductionOrder erpProductionOrder,
+			HttpServletRequest request, HttpServletResponse response) {
+		Page<ErpProductionOrder> page = new Page<>(request, response);
+		int pageSize = page.getPageSize() > 0 ? page.getPageSize() : 20;
+		int pageNo = page.getPageNo() > 0 ? page.getPageNo() : 1;
+		int startRow = (pageNo - 1) * pageSize;
+		List<ErpProductionOrder> list = erpProductionOrderService.findScheduleOrderPageList(
+				erpProductionOrder.getBillNo(), startRow, pageSize);
+		page.setList(list);
+		page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0));
+		return page;
+	}
+
 	@RequiresPermissions("mes:mesErpSchedule:view")
 	@RequestMapping(value = "listData")
 	@ResponseBody

+ 3 - 0
src/main/resources/config/application.yml

@@ -106,6 +106,9 @@ erp:
       owner-type: BD_OwnerOrg
       keeper-type: BD_KeeperOrg
       default-stock-number:
+    # ERP 排产计划:下推选分录时按以下成品物料编码过滤
+    schedule:
+      material-numbers: 8.10.HEV.05.049025,8.35.115.05.5003146600021
 
 #======================================#
 #========== Server settings ===========#

+ 21 - 1
src/main/resources/views/modules/mes/erpInStockSelectDetail.html

@@ -32,6 +32,12 @@
 
 			</div>
 
+			<div id="pendingEmptyTip" class="alert alert-warning hide" style="margin-bottom:10px;padding:8px 12px;">
+
+				<i class="fa fa-exclamation-circle"></i> ${text('该采购订单暂无剩余可入分录(分录可能已全部入库)。可在「ERP采购入库单查询」中查看历史入库记录。')}
+
+			</div>
+
 			<#form:form id="searchForm" model="${erpPurchaseOrder}" action="${ctx}/mes/erpInStock/selectDetailData" method="post" class="form-inline hide"
 
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
@@ -128,7 +134,21 @@ $('#dataGrid').dataGrid({
 
 	],
 
-	ajaxSuccess: function(){}
+	ajaxSuccess: function(data){
+
+		var rows = (data && data.list) ? data.list : [];
+
+		if (rows.length === 0) {
+
+			$('#pendingEmptyTip').removeClass('hide');
+
+		} else {
+
+			$('#pendingEmptyTip').addClass('hide');
+
+		}
+
+	}
 
 });
 

+ 8 - 4
src/main/resources/views/modules/mes/erpPrdInStockForm.html

@@ -18,13 +18,17 @@
 				<i class="fa fa-info-circle"></i>
 				${text('勾选 MES 托盘批次码,入库数量=已绑定数量(nums)合计;ERP 批号由 ERP 系统内部生成。产线:HEVXT→HEV,115XT→115;须 nums>0。')}
 			</div>
-			<% if(moEntry != null){ %>
+			<% if(moEntry != null){
+				var qtyText = @com.jeesite.modules.mes.erp.ErpKingdeeParseUtils.formatDisplayQty(moEntry.qty);
+				var instockQtyText = @com.jeesite.modules.mes.erp.ErpKingdeeParseUtils.formatDisplayQty(moEntry.instockQty);
+				var remainQtyText = @com.jeesite.modules.mes.erp.ErpKingdeeParseUtils.formatDisplayQty(moEntry.remainQty);
+			%>
 			<div class="row" style="margin-bottom:12px;">
 				<div class="col-xs-12 col-sm-6"><label class="control-label">${text('物料')}:</label> ${moEntry.materialNumber!} ${moEntry.materialName!}</div>
 				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('订单行号')}:</label> ${moEntry.seq!}</div>
-				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('订单数量')}:</label> ${moEntry.qty!}</div>
-				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('已入库')}:</label> ${moEntry.instockQty!0}</div>
-				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('未入库')}:</label> <strong class="text-danger">${moEntry.remainQty!0}</strong></div>
+				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('订单数量')}:</label> ${qtyText!}</div>
+				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('已入库')}:</label> ${instockQtyText!0}</div>
+				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('未入库')}:</label> <strong class="text-danger">${remainQtyText!0}</strong></div>
 				<div class="col-xs-6 col-sm-2"><label class="control-label">${text('本次合计')}:</label> <strong id="totalQtyLabel">0</strong></div>
 			</div>
 			<% } %>

+ 1 - 1
src/main/resources/views/modules/mes/erpProductionOrderList.html

@@ -147,7 +147,7 @@ $(document).on('click', '.btn-mo-pushdown', function(e) {
 				data-title="${text('ERP排产')}">
 			<i class="fa fa-calendar-plus-o fa-fw text-info"></i>
 			<strong>${text('新增ERP排产计划')}</strong>
-			<span class="text-muted" style="display:block;margin:4px 0 0 22px;font-size:12px;">${text('选择 HEV/115 分录后创建排产计划')}</span>
+			<span class="text-muted" style="display:block;margin:4px 0 0 22px;font-size:12px;">${text('选择配置成品物料分录后创建排产计划')}</span>
 		</a>
 		<% } %>
 	</div>

+ 1 - 1
src/main/resources/views/modules/mes/erpProductionOrderPushdown.html

@@ -39,7 +39,7 @@
 				<a href="${ctx}/mes/erpProductionOrder/scheduleSelect?billNo=${billNo!}" class="list-group-item mo-pushdown-link" data-title="${text('ERP排产')} - ${billNo!}">
 					<i class="fa fa-calendar-plus-o fa-fw text-info"></i>
 					<strong>${text('新增ERP排产计划')}</strong>
-					<span class="text-muted" style="display:block;margin:4px 0 0 22px;font-size:12px;">${text('选择 HEV/115 分录后创建排产计划')}</span>
+					<span class="text-muted" style="display:block;margin:4px 0 0 22px;font-size:12px;">${text('选择配置成品物料分录后创建排产计划')}</span>
 				</a>
 				<% } %>
 			</div>

+ 16 - 2
src/main/resources/views/modules/mes/erpProductionOrderScheduleSelect.html

@@ -12,7 +12,14 @@
 		<div class="box-body">
 			<div class="alert alert-info" style="margin-bottom:10px;">
 				<i class="fa fa-info-circle"></i>
-				${text('仅展示配置物料分录')}(8.10.HEV.10.047696 / 8.35.115.10.5003146600021),${text('选择分录后创建 ERP 排产计划。')}
+				${text('仅展示配置物料分录')}
+				<% if(isNotEmpty(scheduleMaterialNumbersText)){ %>
+					(${scheduleMaterialNumbersText})
+				<% } %>
+				,${text('选择分录后创建 ERP 排产计划。')}
+			</div>
+			<div id="scheduleEmptyTip" class="alert alert-warning hide" style="margin-bottom:10px;">
+				<i class="fa fa-exclamation-circle"></i> ${text('该生产订单暂无符合排产物料配置的分录,请确认订单明细是否含上述成品物料编码。')}
 			</div>
 			<#form:form id="searchForm" model="${erpProductionOrder}" action="${ctx}/mes/erpProductionOrder/scheduleSelectData" method="post" class="hide"
 					data-page-no="1" data-page-size="500">
@@ -42,6 +49,13 @@ $('#dataGrid').dataGrid({
 		{header:'${text("计划开工")}', name:'planStartDate', index:'planStartDate', width:120, align:"center"},
 		{header:'${text("计划完工")}', name:'planFinishDate', index:'planFinishDate', width:120, align:"center"}
 	],
-	ajaxSuccess: function(){}
+	ajaxSuccess: function(data){
+		var rows = (data && data.list) ? data.list : [];
+		if (rows.length === 0) {
+			$('#scheduleEmptyTip').removeClass('hide');
+		} else {
+			$('#scheduleEmptyTip').addClass('hide');
+		}
+	}
 });
 </script>

+ 5 - 3
src/main/resources/views/modules/mes/erpTransferDirectForm.html

@@ -43,10 +43,12 @@
 						<% if(sourceList.~size == 0){ %>
 						<tr><td colspan="9" class="text-center text-muted">${text('无可用生产入库行')}</td></tr>
 						<% }else{ %>
-						<% for(row in sourceList){ %>
+						<% for(row in sourceList){ 
+							var instockQtyText = @com.jeesite.modules.mes.erp.ErpKingdeeParseUtils.formatDisplayQty(row.realQty);
+						%>
 						<tr class="source-row" data-entry-id="${row.entryId!}" data-bill-no="${row.billNo!}"
 							data-material="${row.materialNumber!}" data-lot="${row.lotNumber!}"
-							data-qty="${row.realQty!}" data-stock="${row.stockNumber!}">
+							data-qty="${instockQtyText!}" data-stock="${row.stockNumber!}">
 							<td class="text-center">
 								<input type="radio" name="instockRow" class="instock-radio" value="${row.entryId!}"/>
 							</td>
@@ -55,7 +57,7 @@
 							<td>${row.materialNumber!}</td>
 							<td>${row.materialName!}</td>
 							<td><strong>${row.lotNumber!}</strong></td>
-							<td class="text-right">${row.realQty!}</td>
+							<td class="text-right">${instockQtyText!}</td>
 							<td class="text-center">${row.unitName!}</td>
 							<td>${row.stockName!} (${row.stockNumber!})</td>
 						</tr>

+ 3 - 1
src/main/resources/views/modules/mes/erpTransferDirectSelectOrder.html

@@ -14,7 +14,9 @@
 		<div class="box-body">
 			<div class="alert alert-info" style="margin-bottom:10px;">
 				<i class="fa fa-info-circle"></i>
-				${text('请选择生产订单,系统将加载该订单 HEV/115 生产入库行作为调拨批号来源。')}
+				${text('仅展示配置物料')} <strong>8.10.HEV.10.047696(HEV)</strong> ${text('与')}
+				<strong>8.35.115.10.5003146600021(115)</strong> ${text('的生产订单(与生产入库一致);')}
+				${text('选单后加载该订单 HEV/115 生产入库行作为调拨批号来源。')}
 			</div>
 			<#form:form id="searchForm" model="${erpProductionOrder}" action="${ctx}/mes/erpTransferDirect/selectOrderData" method="post" class="form-inline hide"
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">

+ 1 - 1
src/main/resources/views/modules/mes/mesErpScheduleBoard.html

@@ -7,7 +7,7 @@
 			</div>
 			<div class="box-tools pull-right">
 				<a href="${ctx}/mes/mesErpSchedule/list" class="btn btn-default btnTool" title="${text('列表视图')}"><i class="fa fa-list"></i> ${text('列表')}</a>
-				<a href="${ctx}/mes/erpProductionOrder/list" class="btn btn-default btnTool" title="${text('从ERP订单排产')}"><i class="fa fa-plus"></i> ${text('新增排产')}</a>
+				<a href="${ctx}/mes/mesErpSchedule/selectOrder" class="btn btn-default btnTool" title="${text('新增排产计划')}"><i class="fa fa-plus"></i> ${text('新增排产')}</a>
 			</div>
 		</div>
 		<div class="box-body">

+ 9 - 1
src/main/resources/views/modules/mes/mesErpScheduleList.html

@@ -7,12 +7,20 @@
 			</div>
 			<div class="box-tools pull-right">
 				<a href="${ctx}/mes/mesErpSchedule/board" class="btn btn-default btnTool" title="${text('甘特看板')}"><i class="fa fa-calendar"></i> ${text('看板')}</a>
+				<a href="${ctx}/mes/mesErpSchedule/selectOrder" class="btn btn-default btnTool" title="${text('新增排产计划')}"><i class="fa fa-plus"></i> ${text('新增')}</a>
 				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
-				<a href="${ctx}/mes/erpProductionOrder/list" class="btn btn-default btnTool" title="${text('从ERP订单排产')}"><i class="fa fa-list-alt"></i> ${text('ERP订单')}</a>
 				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
 			</div>
 		</div>
 		<div class="box-body">
+			<div class="alert alert-info" style="margin-bottom:10px;">
+				<i class="fa fa-info-circle"></i>
+				${text('新增排产时仅可选择配置成品物料')}
+				<% if(isNotEmpty(scheduleMaterialNumbersText)){ %>
+					(${scheduleMaterialNumbersText})
+				<% } %>
+				${text('对应的生产订单分录。')}
+			</div>
 			<#form:form id="searchForm" model="${mesErpSchedule}" action="${ctx}/mes/mesErpSchedule/listData" method="post" class="form-inline hide"
 					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
 				<div class="form-group">

+ 61 - 0
src/main/resources/views/modules/mes/mesErpScheduleSelectOrder.html

@@ -0,0 +1,61 @@
+<% layout('/layouts/default.html', {title: '选择生产订单', libs: ['dataGrid']}){ %>
+<div class="main-content">
+	<div class="box box-main">
+		<div class="box-header">
+			<div class="box-title">
+				<i class="fa fa-list-alt"></i> ${text('新增ERP排产计划 - 选择生产订单')}
+			</div>
+			<div class="box-tools pull-right">
+				<a href="${ctx}/mes/mesErpSchedule/list" class="btn btn-default" title="${text('返回')}"><i class="fa fa-mail-reply"></i> ${text('返回')}</a>
+				<a href="#" class="btn btn-default" id="btnSearch" title="${text('查询')}"><i class="fa fa-filter"></i> ${text('查询')}</a>
+				<a href="#" class="btn btn-default" id="btnSetting" title="${text('设置')}"><i class="fa fa-navicon"></i></a>
+			</div>
+		</div>
+		<div class="box-body">
+			<div class="alert alert-info" style="margin-bottom:10px;">
+				<i class="fa fa-info-circle"></i>
+				${text('仅展示含排产成品物料')}
+				<% if(isNotEmpty(scheduleMaterialNumbersText)){ %>
+					(${scheduleMaterialNumbersText})
+				<% } %>
+				${text('的生产订单;选择订单后进入分录选择页。')}
+			</div>
+			<#form:form id="searchForm" model="${erpProductionOrder}" action="${ctx}/mes/mesErpSchedule/selectOrderData" method="post" class="form-inline hide"
+					data-page-no="${parameter.pageNo}" data-page-size="${parameter.pageSize}" data-order-by="${parameter.orderBy}">
+				<div class="form-group">
+					<label class="control-label">${text('生产订单号')}:</label>
+					<div class="control-inline">
+						<#form:input path="billNo" maxlength="100" class="form-control width-180"/>
+					</div>
+				</div>
+				<div class="form-group">
+					<button type="submit" class="btn btn-primary btn-sm">${text('查询')}</button>
+					<button type="reset" class="btn btn-default btn-sm">${text('重置')}</button>
+				</div>
+			</#form:form>
+			<table id="dataGrid"></table>
+			<div id="dataGridPage"></div>
+		</div>
+	</div>
+</div>
+<% } %>
+<script>
+$('#dataGrid').dataGrid({
+	searchForm: $("#searchForm"),
+	columnModel: [
+		{header:'${text("操作")}', name:'actions', width:100, align:"center", frozen:true, formatter: function(val, obj, row){
+			return '<a href="${ctx}/mes/erpProductionOrder/scheduleSelect?billNo='+encodeURIComponent(row.billNo)+'" class="btnList addTabPage" data-title="${text("ERP排产")} - '+row.billNo+'">'+
+				'<i class="fa fa-check"></i> ${text("选择")}</a>';
+		}},
+		{header:'${text("生产订单号")}', name:'billNo', index:'billNo', width:180, align:"center", frozen:true},
+		{header:'${text("单据日期")}', name:'date', index:'date', width:120, align:"center"},
+		{header:'${text("单据状态")}', name:'documentStatusName', index:'documentStatusName', width:100, align:"center"},
+		{header:'${text("生产组织")}', name:'prdOrgName', index:'prdOrgName', width:180, align:"left"},
+		{header:'${text("存货类别")}', name:'inventoryCategory', index:'inventoryCategory', width:120, align:"center"},
+		{header:'${text("生产车间")}', name:'workshopName', index:'workshopName', width:140, align:"left"},
+		{header:'${text("排产分录数")}', name:'entryCount', index:'entryCount', width:100, align:"right"},
+		{header:'${text("排产数量合计")}', name:'totalQty', index:'totalQty', width:120, align:"right", formatter: formatErpQty}
+	],
+	ajaxSuccess: function(){}
+});
+</script>

+ 2 - 2
src/main/resources/views/modules/mes/mesIntegratedScreen.html

@@ -4,7 +4,7 @@
 	<meta charset="UTF-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
 	<meta http-equiv="X-UA-Compatible" content="ie=edge">
-	<title>MES系统综合数据大屏</title>
+	<title>MES系统智能中控大屏</title>
 	<style>
 		* { box-sizing: border-box; }
 		html, body {
@@ -520,7 +520,7 @@
 <body>
 <div class="screen">
 	<div class="header">
-		<div class="title">MES系统综合数据大屏</div>
+		<div class="title">MES系统智能中控大屏</div>
 		<div class="clock" id="clock"></div>
 	</div>