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.entity.MesBatchSn; import com.jeesite.modules.mes.erp.ErpPrdInStock; import com.jeesite.modules.mes.erp.ErpPrdInStockResult; import com.jeesite.modules.mes.erp.ErpPrdInStockSaveService; import com.jeesite.modules.mes.erp.ErpPrdInStockService; import com.jeesite.modules.mes.erp.ErpPrdInStockSubmitRequest; import com.jeesite.modules.mes.erp.ErpProductionOrder; import com.jeesite.modules.mes.erp.ErpProductionOrderService; import com.jeesite.modules.mes.erp.ErpStockPdaService; import com.jeesite.modules.mes.erp.ErpStockOption; import com.jeesite.modules.mes.erp.ErpStockService; import com.jeesite.modules.mes.erp.KingdeeErpProperties; import com.jeesite.modules.mes.erp.ErpPdaRespHelper; import com.jeesite.modules.mes.erp.MesErpLineMaterialMapping; import com.jeesite.modules.mes.resp.CommonResp; import com.jeesite.modules.mes.service.MesBatchSnService; import com.jeesite.modules.mes.service.MesLogService; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; 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 生产入库单查询与新增(MES 批次码驱动数量)。 */ @Controller @RequestMapping(value = "${adminPath}/mes/erpPrdInStock") public class ErpPrdInStockController extends BaseController { private final ErpPrdInStockService erpPrdInStockService; private final ErpPrdInStockSaveService erpPrdInStockSaveService; private final ErpProductionOrderService erpProductionOrderService; private final MesBatchSnService mesBatchSnService; private final ErpStockService erpStockService; private final ErpStockPdaService erpStockPdaService; private final KingdeeErpProperties erpProperties; private final MesLogService mesLogService; public ErpPrdInStockController(ErpPrdInStockService erpPrdInStockService, ErpPrdInStockSaveService erpPrdInStockSaveService, ErpProductionOrderService erpProductionOrderService, MesBatchSnService mesBatchSnService, ErpStockService erpStockService, ErpStockPdaService erpStockPdaService, KingdeeErpProperties erpProperties, MesLogService mesLogService) { this.erpPrdInStockService = erpPrdInStockService; this.erpPrdInStockSaveService = erpPrdInStockSaveService; this.erpProductionOrderService = erpProductionOrderService; this.mesBatchSnService = mesBatchSnService; this.erpStockService = erpStockService; this.erpStockPdaService = erpStockPdaService; this.erpProperties = erpProperties; this.mesLogService = mesLogService; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = {"list", ""}) public String list(ErpPrdInStock erpPrdInStock, Model model) { model.addAttribute("erpPrdInStock", erpPrdInStock); return "modules/mes/erpPrdInStockList"; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "listData") @ResponseBody public Page listData(ErpPrdInStock erpPrdInStock, HttpServletRequest request, HttpServletResponse response) { Page 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 list = erpPrdInStockService.findPageList(erpPrdInStock, startRow, pageSize); page.setList(list); page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0)); return page; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "detail") public String detail(ErpPrdInStock erpPrdInStock, Model model) { model.addAttribute("erpPrdInStock", erpPrdInStock); return "modules/mes/erpPrdInStockDetail"; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "detailData") @ResponseBody public Page detailData(ErpPrdInStock erpPrdInStock, HttpServletRequest request, HttpServletResponse response) { Page page = new Page<>(request, response); List list = erpPrdInStockService.findDetailList(erpPrdInStock.getBillNo()); page.setList(list); page.setCount(list.size()); return page; } /** * PDA:查看生产入库单明细行。 */ @RequiresPermissions("mes:erpPrdInStock:view") @PostMapping(value = "pda/detailData") @ResponseBody public CommonResp> pdaDetailData(ErpPrdInStock erpPrdInStock, HttpServletRequest request, HttpServletResponse response) { mesLogService.apisave(request); List list = erpPrdInStockService.findDetailList(erpPrdInStock.getBillNo()); return ErpPdaRespHelper.pageAllOk(request, response, list); } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "selectOrder") public String selectOrder(ErpProductionOrder erpProductionOrder, Model model) { model.addAttribute("erpProductionOrder", erpProductionOrder); return "modules/mes/erpPrdInStockSelectOrder"; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "selectOrderData") @ResponseBody public Page selectOrderData(ErpProductionOrder erpProductionOrder, HttpServletRequest request, HttpServletResponse response) { Page 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 list = erpProductionOrderService.findPrdInStockOrderPageList( erpProductionOrder.getBillNo(), startRow, pageSize); page.setList(list); page.setCount(startRow + list.size() + (list.size() == pageSize ? 1 : 0)); return page; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "selectDetail") public String selectDetail(ErpProductionOrder erpProductionOrder, Model model) { model.addAttribute("erpProductionOrder", erpProductionOrder); return "modules/mes/erpPrdInStockSelectDetail"; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "selectDetailData") @ResponseBody public Page selectDetailData(ErpProductionOrder erpProductionOrder, HttpServletRequest request, HttpServletResponse response) { Page page = new Page<>(request, response); List list = erpProductionOrderService.findDetailList(erpProductionOrder.getBillNo()); // 仅保留 HEV/115 物料分录 list.removeIf(row -> row == null || !erpProperties.isAllowedPrdInStockMaterial(row.getMaterialNumber())); erpPrdInStockService.enrichMoInstockProgress(erpProductionOrder.getBillNo(), list); page.setList(list); page.setCount(list.size()); return page; } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "form") public String form(String moBillNo, String entryId, Model model) { String billNo = StringUtils.trim(moBillNo); String moEntryId = StringUtils.trim(entryId); ErpProductionOrder moEntry = erpProductionOrderService.findInstockMoEntry(billNo, moEntryId); if (moEntry != null) { erpPrdInStockService.enrichMoInstockProgress(billNo, java.util.Collections.singletonList(moEntry)); } List batchList = moEntry == null ? java.util.Collections.emptyList() : mesBatchSnService.findPendingInstockByMaterial(moEntry.getMaterialNumber()); List stockList = erpStockService.findUsableStockList(); model.addAttribute("moBillNo", billNo); model.addAttribute("entryId", moEntryId); model.addAttribute("moEntry", moEntry); model.addAttribute("batchList", batchList); model.addAttribute("stockList", stockList); model.addAttribute("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stockList)); if (moEntry == null) { model.addAttribute("message", "未找到生产订单分录"); } else if (batchList.isEmpty()) { model.addAttribute("message", "暂无待入库 MES 批次码。须同时满足:产线含 HEV/115(如 HEVXT、HEVX1、115XT)" + "、已绑定数量 nums>0、且未入库。" + " 若批次码记录表有条目但 nums=0,需产线扫码绑定工件后再入库。"); } return "modules/mes/erpPrdInStockForm"; } /** * PDA:生产入库单列表。 */ @RequiresPermissions("mes:erpPrdInStock:view") @PostMapping(value = "pda/listData") @ResponseBody public CommonResp> pdaListData(ErpPrdInStock erpPrdInStock, HttpServletRequest request, HttpServletResponse response) { mesLogService.apisave(request); Page 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 list = erpPrdInStockService.findPageList(erpPrdInStock, startRow, pageSize); return ErpPdaRespHelper.pageOk(request, response, list, startRow, pageSize); } /** * PDA:生产订单列表。 */ @RequiresPermissions("mes:erpPrdInStock:view") @PostMapping(value = "pda/selectOrderData") @ResponseBody public CommonResp> pdaSelectOrderData(ErpProductionOrder erpProductionOrder, HttpServletRequest request, HttpServletResponse response) { mesLogService.apisave(request); Page 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 list = erpProductionOrderService.findPrdInStockOrderPageList( erpProductionOrder.getBillNo(), startRow, pageSize); return ErpPdaRespHelper.pageOk(request, response, list, startRow, pageSize); } /** * PDA:生产订单分录列表。 */ @RequiresPermissions("mes:erpPrdInStock:view") @PostMapping(value = "pda/selectDetailData") @ResponseBody public CommonResp> pdaSelectDetailData(ErpProductionOrder erpProductionOrder, HttpServletRequest request, HttpServletResponse response) { mesLogService.apisave(request); List list = erpProductionOrderService.findDetailList(erpProductionOrder.getBillNo()); list.removeIf(row -> row == null || !erpProperties.isAllowedPrdInStockMaterial(row.getMaterialNumber())); erpPrdInStockService.enrichMoInstockProgress(erpProductionOrder.getBillNo(), list); return ErpPdaRespHelper.pageAllOk(request, response, list); } /** * PDA:入库仓库列表。 */ @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "stockList", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public CommonResp> stockList(HttpServletRequest request) { mesLogService.apisave(request); return ErpPdaRespHelper.ok("成功", erpStockPdaService.buildStockListData()); } /** * PDA:选批次入库页初始化(订单分录 + 待入库 MES 批次码 + 仓库)。 */ @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "formInit", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public CommonResp> formInit(String moBillNo, String entryId, HttpServletRequest request) { mesLogService.apisave(request); Map data = new HashMap<>(10); String billNo = StringUtils.trim(moBillNo); String moEntryId = StringUtils.trim(entryId); data.put("moBillNo", billNo); data.put("entryId", moEntryId); if (StringUtils.isBlank(billNo) || StringUtils.isBlank(moEntryId)) { data.put("moEntry", null); data.put("batchList", Collections.emptyList()); data.put("stockList", Collections.emptyList()); return ErpPdaRespHelper.fail("生产订单号与分录内码不能为空", data); } ErpProductionOrder moEntry = erpProductionOrderService.findInstockMoEntry(billNo, moEntryId); if (moEntry == null) { data.put("moEntry", null); data.put("batchList", Collections.emptyList()); List stocks = erpStockService.findUsableStockList(); data.put("stockList", stocks); data.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks)); return ErpPdaRespHelper.fail("未找到生产订单分录", data); } erpPrdInStockService.enrichMoInstockProgress(billNo, Collections.singletonList(moEntry)); List batchList = mesBatchSnService.findPendingInstockByMaterial(moEntry.getMaterialNumber()); data.put("moEntry", moEntry); data.put("batchList", batchList); String message = ""; if (batchList.isEmpty()) { message = "暂无待入库 MES 批次码。须产线含 HEV/115(如 HEVXT、HEVX1、115XT)、nums>0、且未入库"; } List stocks = erpStockService.findUsableStockList(); data.put("stockList", stocks); data.put("defaultStockNumber", erpStockService.resolveDefaultStockNumber(stocks)); return ErpPdaRespHelper.ok(message, data); } /** * PDA:扫 MES 批次码校验(是否可入当前物料)。 */ @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "batchScan", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public CommonResp> batchScan(String batchSn, String materialNumber, HttpServletRequest request) { mesLogService.apisave(request); Map data = new HashMap<>(4); String sn = StringUtils.trim(batchSn); String material = StringUtils.trim(materialNumber); if (StringUtils.isBlank(sn)) { return ErpPdaRespHelper.fail("批次码不能为空", data); } if (StringUtils.isBlank(material)) { return ErpPdaRespHelper.fail("物料编码不能为空", data); } MesBatchSn batch = mesBatchSnService.findByBatchSn(sn); if (batch == null) { return ErpPdaRespHelper.fail("未找到该 MES 批次码", data); } data.put("batch", batch); if (batch.getNums() == null || batch.getNums() <= 0) { return ErpPdaRespHelper.fail("该批次码绑定数量为 0,需产线扫码绑定工件后再入库", data); } if ("1".equals(StringUtils.trim(batch.getInstockStatus())) || MesBatchSn.BATCH_STATUS_QUALIFIED.equals(batch.getBatchStatus()) || MesBatchSn.BATCH_STATUS_SHIPPED.equals(batch.getBatchStatus())) { return ErpPdaRespHelper.fail("该批次码已在仓库中,不能重复入库", data); } if (!MesErpLineMaterialMapping.isLineAllowedForMaterialLoose(batch.getLineSn(), material)) { return ErpPdaRespHelper.fail("批次码产线 " + StringUtils.trimToEmpty(batch.getLineSn()) + " 与当前物料 " + material + " 不匹配,不能入库", data); } return ErpPdaRespHelper.ok("可以入库", data); } /** * 仓位选项(PDA / PC 共用,统一 CommonResp)。 */ @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "pda/stockLocOptions", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public CommonResp> pdaStockLocOptions(String stockNumber, HttpServletRequest request) { return stockLocOptions(stockNumber, request); } @RequiresPermissions("mes:erpPrdInStock:view") @RequestMapping(value = "stockLocOptions", method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public CommonResp> stockLocOptions(String stockNumber, HttpServletRequest request) { mesLogService.apisave(request); if (StringUtils.isBlank(stockNumber)) { return ErpPdaRespHelper.fail("仓库编码不能为空"); } return ErpPdaRespHelper.ok("成功", erpStockPdaService.buildStockLocOptionsData(stockNumber)); } @RequiresPermissions("mes:erpPrdInStock:view") @PostMapping(value = "submit") @ResponseBody public CommonResp> submit(HttpServletRequest httpRequest) { mesLogService.apisave(httpRequest); ErpPrdInStockSubmitRequest request; try { request = ErpPrdInStockSubmitRequest.resolveFromHttpRequest(httpRequest); } catch (IllegalArgumentException ex) { return ErpPdaRespHelper.fail(ex.getMessage()); } catch (Exception ex) { return ErpPdaRespHelper.fail("参数格式错误:" + ex.getMessage()); } try { ErpPrdInStockResult result = erpPrdInStockSaveService.submit(request); if (result.isSuccess()) { String lotMsg = StringUtils.isNotBlank(result.getLotNumber()) ? ",ERP批号:" + result.getLotNumber() : ""; String message = text("生产入库单保存成功,单号:{0};合计数量 {1},绑定批次 {2} 个{3}", result.getBillNo(), result.getTotalQty() == null ? "0" : result.getTotalQty().stripTrailingZeros().toPlainString(), String.valueOf(result.getBatchCount()), lotMsg); Map data = new HashMap<>(4); data.put("billNo", result.getBillNo()); data.put("totalQty", result.getTotalQty()); data.put("batchCount", result.getBatchCount()); data.put("lotNumber", result.getLotNumber()); return ErpPdaRespHelper.ok(message, data); } return ErpPdaRespHelper.fail(result.getMessage()); } catch (Exception e) { return ErpPdaRespHelper.fail(e.getMessage()); } } }