package com.zy.asrs.service.impl;
|
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.core.common.Cools;
|
import com.core.common.R;
|
import com.zy.asrs.entity.param.MesToCombParam;
|
import com.zy.asrs.entity.param.OpenOrderPakoutExecuteParam;
|
import com.zy.asrs.entity.param.OutTaskParam;
|
import com.zy.asrs.service.ExternalTaskFacadeService;
|
import com.zy.asrs.service.LocDetlService;
|
import com.zy.asrs.service.OpenService;
|
import com.zy.asrs.service.WaitPakinService;
|
import com.zy.asrs.service.WrkDetlService;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
|
import java.util.Collections;
|
import java.util.Objects;
|
|
/**
|
* 对外任务门面。
|
* 把 Controller 里的校验和放行逻辑沉到 service,便于 HTTP 和 MQTT 两条入口共用。
|
*/
|
@Service
|
public class ExternalTaskFacadeServiceImpl implements ExternalTaskFacadeService {
|
|
@Autowired
|
private OpenService openService;
|
@Autowired
|
private LocDetlService locDetlService;
|
@Autowired
|
private WrkDetlService wrkDetlService;
|
@Autowired
|
private WaitPakinService waitPakinService;
|
|
/**
|
* 复用现有入库通知建档逻辑,并补充托盘重复校验。
|
*/
|
@Override
|
public R acceptInboundNotice(MesToCombParam param) {
|
if (param == null) {
|
return R.error("请求参数不能为空");
|
}
|
if (Cools.isEmpty(param.getPalletId())) {
|
return R.error("palletId不能为空");
|
}
|
if (Cools.isEmpty(param.getBizNo())) {
|
return R.error("bizNo不能为空");
|
}
|
|
int countLoc = locDetlService.selectCount(new EntityWrapper<com.zy.asrs.entity.LocDetl>().eq("zpallet", param.getPalletId()));
|
int countWrk = wrkDetlService.selectCount(new EntityWrapper<com.zy.asrs.entity.WrkDetl>().eq("zpallet", param.getPalletId()));
|
if (countLoc > 0 || countWrk > 0) {
|
return R.error("托盘已在库存中/已开始入库");
|
}
|
|
if (waitPakinService.selectCount(new EntityWrapper<com.zy.asrs.entity.WaitPakin>()
|
.eq("zpallet", param.getPalletId())
|
.eq("io_status", "N")) > 0) {
|
// 同托盘存在旧的待入库通知时,删除旧记录,保留最新一次预登记。
|
waitPakinService.delete(new EntityWrapper<com.zy.asrs.entity.WaitPakin>().eq("zpallet", param.getPalletId()));
|
}
|
|
R result = openService.mesToComb(param);
|
return result == null ? R.ok() : result;
|
}
|
|
/**
|
* 复用统一出库订单化逻辑。
|
*
|
* MQTT/IoT 入口不再绕过订单直接生成 WrkMast:
|
* - autoConfirm=false:只创建 status=0 的订单,等待外部调用执行接口;
|
* - autoConfirm=true:创建订单后立即走执行逻辑,生成当前批次任务并确认可下发。
|
*
|
* 这样做是为了让 HTTP /outOrder 和 MQTT/IoT 直调共享同一套:
|
* - 订单明细保存字段;
|
* - 批次键计算;
|
* - 中止取消和 work_qty 回滚;
|
* - pdcType 放行。
|
*/
|
@Override
|
public R createOutboundTask(OutTaskParam param, boolean autoConfirm) {
|
if (param == null) {
|
return R.error("请求参数不能为空");
|
}
|
if (Cools.isEmpty(param.getOrderId())) {
|
return R.error("出库单号不能为空");
|
}
|
if (Cools.isEmpty(param.getPalletId())) {
|
return R.error("palletId不能为空");
|
}
|
if (Cools.isEmpty(param.getStationId())) {
|
return R.error("stationId不能为空");
|
}
|
int countLoc = locDetlService.selectCount(new EntityWrapper<com.zy.asrs.entity.LocDetl>().eq("zpallet", param.getPalletId()));
|
if (countLoc == 0) {
|
return R.error("库存中不存在该托盘:" + param.getPalletId());
|
}
|
|
if (param.getSeq() == null) {
|
// 设备直调通常是单托盘出库,没有 ERP 顺序号;0 表示无序,和 /outOrder 的校验语义一致。
|
param.setSeq(0);
|
}
|
if (Cools.isEmpty(param.getBatchSeq())) {
|
// batchSeq 是接口原始字段,明细里会保存;实际生成任务时低站点仍按 orderId 作为批次键。
|
param.setBatchSeq(param.getOrderId());
|
}
|
if (isHighStation(param.getStationId()) && Cools.isEmpty(param.getEntryWmsCode())) {
|
// IoT 直调常见为单托盘任务,没有 ERP 进仓编号;用 orderId 作为批次键,
|
// 这样既满足高站点订单明细校验,也能让执行后 WrkMast.batchSeq 保持可追溯。
|
param.setEntryWmsCode(param.getOrderId());
|
}
|
|
// IoT/MQTT 默认只预创建订单,status=0 不会被定时器扫描。
|
// 只有 autoConfirm=true 或外部后续调用执行接口时,才会把 status 恢复为 1 并生成任务。
|
R orderResult = openService.outOrderCreatePakoutOrder(Collections.singletonList(param), false);
|
if (!Objects.equals(orderResult.get("code"), 200) || !autoConfirm) {
|
return orderResult;
|
}
|
|
// IoT pick 约定为“收到即执行”,因此建单后直接复用公开执行接口的服务逻辑。
|
OpenOrderPakoutExecuteParam executeParam = new OpenOrderPakoutExecuteParam();
|
executeParam.setOrderId(param.getOrderId());
|
executeParam.setExecute(1);
|
return openService.pakoutOrderExecute(executeParam);
|
}
|
|
private boolean isHighStation(String stationId) {
|
if (Cools.isEmpty(stationId)) {
|
return false;
|
}
|
try {
|
return Integer.valueOf(stationId) > 600;
|
} catch (NumberFormatException ignored) {
|
return false;
|
}
|
}
|
}
|