6 changed files with 404 additions and 7 deletions
-
2src/main/java/com/gaotao/modules/inspection/service/impl/InspectionInboundServiceImpl.java
-
18src/main/java/com/gaotao/modules/other/controller/OtherInboundController.java
-
38src/main/java/com/gaotao/modules/other/entity/InventoryMoveRequestDto.java
-
15src/main/java/com/gaotao/modules/other/service/InventoryMoveService.java
-
333src/main/java/com/gaotao/modules/other/service/impl/InventoryMoveServiceImpl.java
-
5src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java
@ -0,0 +1,38 @@ |
|||||
|
package com.gaotao.modules.other.entity; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 库存移库请求DTO |
||||
|
*/ |
||||
|
@Data |
||||
|
public class InventoryMoveRequestDto { |
||||
|
|
||||
|
/** |
||||
|
* 站点 |
||||
|
*/ |
||||
|
private String site; |
||||
|
|
||||
|
/** |
||||
|
* 移库原因 |
||||
|
*/ |
||||
|
private String moveReason; |
||||
|
|
||||
|
/** |
||||
|
* 目标库位 |
||||
|
*/ |
||||
|
private String targetLocationId; |
||||
|
|
||||
|
/** |
||||
|
* HandlingUnit ID列表 |
||||
|
*/ |
||||
|
private List<String> handlingUnitIds; |
||||
|
|
||||
|
/** |
||||
|
* 扫描的物料信息列表 |
||||
|
*/ |
||||
|
private List<Map<String, Object>> scannedItems; |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
package com.gaotao.modules.other.service; |
||||
|
|
||||
|
import com.gaotao.modules.other.entity.InventoryMoveRequestDto; |
||||
|
|
||||
|
/** |
||||
|
* 库存移库服务接口 |
||||
|
*/ |
||||
|
public interface InventoryMoveService { |
||||
|
|
||||
|
/** |
||||
|
* 确认库存移库 |
||||
|
* @param dto 移库请求数据 |
||||
|
*/ |
||||
|
void confirmInventoryMove(InventoryMoveRequestDto dto); |
||||
|
} |
||||
@ -0,0 +1,333 @@ |
|||||
|
package com.gaotao.modules.other.service.impl; |
||||
|
|
||||
|
import com.gaotao.common.exception.XJException; |
||||
|
import com.gaotao.common.utils.HttpUtils; |
||||
|
import com.gaotao.modules.api.service.IfsApiIssueAndReturnService; |
||||
|
import com.gaotao.modules.handlingunit.entity.HandlingUnit; |
||||
|
import com.gaotao.modules.handlingunit.service.HandlingUnitService; |
||||
|
import com.gaotao.modules.other.entity.InventoryMoveRequestDto; |
||||
|
import com.gaotao.modules.other.service.InventoryMoveService; |
||||
|
import com.gaotao.modules.sys.entity.SysUserEntity; |
||||
|
import com.gaotao.modules.trans.entity.TransDetail; |
||||
|
import com.gaotao.modules.trans.entity.TransHeader; |
||||
|
import com.gaotao.modules.trans.service.TransDetailService; |
||||
|
import com.gaotao.modules.trans.service.TransHeaderService; |
||||
|
import com.gaotao.modules.trans.service.TransNoControlService; |
||||
|
import com.gaotao.modules.warehouse.entity.Location; |
||||
|
import com.gaotao.modules.warehouse.service.InventoryStockService; |
||||
|
import com.gaotao.modules.warehouse.service.LocationService; |
||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||
|
import lombok.extern.slf4j.Slf4j; |
||||
|
import org.apache.shiro.SecurityUtils; |
||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||
|
import org.springframework.beans.factory.annotation.Value; |
||||
|
import org.springframework.stereotype.Service; |
||||
|
import org.springframework.transaction.annotation.Transactional; |
||||
|
|
||||
|
import java.math.BigDecimal; |
||||
|
import java.util.Date; |
||||
|
import java.util.HashMap; |
||||
|
import java.util.List; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
/** |
||||
|
* 库存移库服务实现类 |
||||
|
*/ |
||||
|
@Slf4j |
||||
|
@Service |
||||
|
public class InventoryMoveServiceImpl implements InventoryMoveService { |
||||
|
|
||||
|
@Autowired |
||||
|
private HandlingUnitService handlingUnitService; |
||||
|
|
||||
|
@Autowired |
||||
|
private TransHeaderService transHeaderService; |
||||
|
|
||||
|
@Autowired |
||||
|
private TransDetailService transDetailService; |
||||
|
|
||||
|
@Autowired |
||||
|
private TransNoControlService transNoControlService; |
||||
|
|
||||
|
@Autowired |
||||
|
private InventoryStockService inventoryStockService; |
||||
|
|
||||
|
@Autowired |
||||
|
private LocationService locationService; |
||||
|
|
||||
|
@Value("${custom.ifs-url}") |
||||
|
private String ifsUrl; |
||||
|
|
||||
|
@Value("${custom.ifs-ifsDBName}") |
||||
|
private String ifsDBName; |
||||
|
|
||||
|
@Value("${custom.ifs-domainUserID}") |
||||
|
private String domainUserID; |
||||
|
|
||||
|
@Override |
||||
|
@Transactional |
||||
|
public void confirmInventoryMove(InventoryMoveRequestDto dto) { |
||||
|
try { |
||||
|
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); |
||||
|
|
||||
|
// 1. 验证目标库位 |
||||
|
//validateTargetLocation(dto.getSite(), dto.getTargetLocationId()); |
||||
|
|
||||
|
// 2. 验证HandlingUnit |
||||
|
List<HandlingUnit> handlingUnits = validateHandlingUnits(dto); |
||||
|
|
||||
|
// 3. 先保存原库位信息用于IFS同步,然后处理每个HandlingUnit |
||||
|
Map<String, String> originalLocations = new HashMap<>(); |
||||
|
for (HandlingUnit hu : handlingUnits) { |
||||
|
originalLocations.put(hu.getUnitId(), hu.getLocationId()); |
||||
|
} |
||||
|
|
||||
|
// 4. 合并相同条件的HandlingUnit后调用IFS接口(在更新HU之前) |
||||
|
syncToIFSBatch(dto, handlingUnits); |
||||
|
|
||||
|
// 5. 为每个HandlingUnit创建出库和入库事务记录并更新数据 |
||||
|
for (HandlingUnit hu : handlingUnits) { |
||||
|
String originalLocationId = originalLocations.get(hu.getUnitId()); |
||||
|
|
||||
|
// 创建出库事务记录 |
||||
|
createOutboundTransaction(dto, hu, currentUser, originalLocationId); |
||||
|
|
||||
|
// 创建入库事务记录 |
||||
|
createInboundTransaction(dto, hu, currentUser); |
||||
|
|
||||
|
/*// 更新库存:从原库位出库 |
||||
|
inventoryStockService.changeInventoryStock( |
||||
|
hu.getSite(), |
||||
|
hu.getWarehouseId(), |
||||
|
hu.getPartNo(), |
||||
|
hu.getBatchNo(), |
||||
|
originalLocationId, // 使用原库位 |
||||
|
hu.getQty(), |
||||
|
hu.getWdr(), |
||||
|
"OUT" |
||||
|
); |
||||
|
|
||||
|
// 更新库存:到目标库位入库 |
||||
|
inventoryStockService.changeInventoryStock( |
||||
|
hu.getSite(), |
||||
|
hu.getWarehouseId(), |
||||
|
hu.getPartNo(), |
||||
|
hu.getBatchNo(), |
||||
|
dto.getTargetLocationId(), |
||||
|
hu.getQty(), |
||||
|
hu.getWdr(), |
||||
|
"IN" |
||||
|
);*/ |
||||
|
|
||||
|
// 更新HandlingUnit库位 |
||||
|
hu.setLocationId(dto.getTargetLocationId()); |
||||
|
hu.setModifiedDate(new Date()); |
||||
|
hu.setModifiedBy(currentUser.getUserDisplay()); |
||||
|
handlingUnitService.updateById(hu); |
||||
|
} |
||||
|
|
||||
|
log.info("库存移库完成,处理了{}个HandlingUnit", handlingUnits.size()); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("库存移库失败", e); |
||||
|
throw new XJException("库存移库失败: " + e.getMessage()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 验证目标库位 |
||||
|
*/ |
||||
|
/* private void validateTargetLocation(String site, String targetLocationId) { |
||||
|
Location location = locationService.lambdaQuery() |
||||
|
.eq(Location::getSite, site) |
||||
|
.eq(Location::getLocationId, targetLocationId) |
||||
|
.one(); |
||||
|
|
||||
|
if (location == null) { |
||||
|
throw new XJException("目标库位不存在: " + targetLocationId); |
||||
|
} |
||||
|
|
||||
|
if (!"ACTIVE".equals(location.getStatus())) { |
||||
|
throw new XJException("目标库位状态不可用: " + targetLocationId); |
||||
|
} |
||||
|
} |
||||
|
*/ |
||||
|
/** |
||||
|
* 验证HandlingUnit |
||||
|
*/ |
||||
|
private List<HandlingUnit> validateHandlingUnits(InventoryMoveRequestDto dto) { |
||||
|
List<HandlingUnit> handlingUnits = handlingUnitService.lambdaQuery() |
||||
|
.eq(HandlingUnit::getSite, dto.getSite()) |
||||
|
.in(HandlingUnit::getUnitId, dto.getHandlingUnitIds()) |
||||
|
.list(); |
||||
|
|
||||
|
if (handlingUnits.size() != dto.getHandlingUnitIds().size()) { |
||||
|
throw new XJException("部分HandlingUnit不存在或站点不匹配"); |
||||
|
} |
||||
|
|
||||
|
/* for (HandlingUnit hu : handlingUnits) { |
||||
|
if (!"Y".equals(hu.getInStockFlag())) { |
||||
|
throw new XJException("HandlingUnit不在库,无法移库: " + hu.getUnitId()); |
||||
|
} |
||||
|
|
||||
|
if (dto.getTargetLocationId().equals(hu.getLocationId())) { |
||||
|
throw new XJException("目标库位不能与当前库位相同: " + hu.getUnitId()); |
||||
|
} |
||||
|
}*/ |
||||
|
|
||||
|
return handlingUnits; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建出库事务记录 |
||||
|
*/ |
||||
|
private void createOutboundTransaction(InventoryMoveRequestDto dto, HandlingUnit hu, SysUserEntity currentUser, String originalLocationId) { |
||||
|
// 创建出库事务头 |
||||
|
TransHeader outboundHeader = new TransHeader(); |
||||
|
outboundHeader.setSite(dto.getSite()); |
||||
|
outboundHeader.setTransNo(transNoControlService.getTransNo(dto.getSite(), "MOV", 12).getNewTransNo()); |
||||
|
outboundHeader.setTransDate(new Date()); |
||||
|
outboundHeader.setTransTypeDb("MOV"); // 移库出库 |
||||
|
outboundHeader.setWarehouseId(hu.getWarehouseId()); |
||||
|
outboundHeader.setUserId(currentUser.getUserId().toString()); |
||||
|
outboundHeader.setUserName(currentUser.getUserDisplay()); |
||||
|
outboundHeader.setRemark("移库出库 - " + dto.getMoveReason()); |
||||
|
outboundHeader.setStatus("COMPLETED"); |
||||
|
outboundHeader.setStatusDb("C"); |
||||
|
outboundHeader.setEnterDate(new Date()); |
||||
|
outboundHeader.setIfsFlag("N"); |
||||
|
transHeaderService.save(outboundHeader); |
||||
|
|
||||
|
// 创建出库事务明细 |
||||
|
TransDetail outboundDetail = new TransDetail(); |
||||
|
outboundDetail.setSite(dto.getSite()); |
||||
|
outboundDetail.setTransNo(outboundHeader.getTransNo()); |
||||
|
outboundDetail.setItemNo(1.0); |
||||
|
outboundDetail.setPartNo(hu.getPartNo()); |
||||
|
outboundDetail.setBatchNo(hu.getBatchNo()); |
||||
|
outboundDetail.setLocationId(originalLocationId); // 原库位 |
||||
|
outboundDetail.setTransQty(hu.getQty()); |
||||
|
outboundDetail.setWdrNo(hu.getWdr()); |
||||
|
outboundDetail.setOrderRef4(hu.getWarehouseId()); |
||||
|
outboundDetail.setDirection("-"); |
||||
|
transDetailService.save(outboundDetail); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建入库事务记录 |
||||
|
*/ |
||||
|
private void createInboundTransaction(InventoryMoveRequestDto dto, HandlingUnit hu, SysUserEntity currentUser) { |
||||
|
// 创建入库事务头 |
||||
|
TransHeader inboundHeader = new TransHeader(); |
||||
|
inboundHeader.setSite(dto.getSite()); |
||||
|
inboundHeader.setTransNo(transNoControlService.getTransNo(dto.getSite(), "MOV", 12).getNewTransNo()); |
||||
|
inboundHeader.setTransDate(new Date()); |
||||
|
inboundHeader.setTransTypeDb("MOV"); // 移库入库 |
||||
|
inboundHeader.setWarehouseId(hu.getWarehouseId()); |
||||
|
inboundHeader.setUserId(currentUser.getUserId().toString()); |
||||
|
inboundHeader.setUserName(currentUser.getUserDisplay()); |
||||
|
inboundHeader.setRemark("移库入库 - " + dto.getMoveReason()); |
||||
|
inboundHeader.setStatus("COMPLETED"); |
||||
|
inboundHeader.setStatusDb("C"); |
||||
|
inboundHeader.setEnterDate(new Date()); |
||||
|
inboundHeader.setIfsFlag("N"); |
||||
|
transHeaderService.save(inboundHeader); |
||||
|
|
||||
|
// 创建入库事务明细 |
||||
|
TransDetail inboundDetail = new TransDetail(); |
||||
|
inboundDetail.setSite(dto.getSite()); |
||||
|
inboundDetail.setTransNo(inboundHeader.getTransNo()); |
||||
|
inboundDetail.setItemNo(1.0); |
||||
|
inboundDetail.setPartNo(hu.getPartNo()); |
||||
|
inboundDetail.setBatchNo(hu.getBatchNo()); |
||||
|
inboundDetail.setLocationId(dto.getTargetLocationId()); // 目标库位 |
||||
|
inboundDetail.setTransQty(hu.getQty()); |
||||
|
inboundDetail.setWdrNo(hu.getWdr()); |
||||
|
inboundDetail.setOrderRef4(hu.getWarehouseId()); |
||||
|
inboundDetail.setDirection("+"); |
||||
|
transDetailService.save(inboundDetail); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 批量同步到IFS - 按site、partNo、locationNo、lotBatchNo合并后调用 |
||||
|
*/ |
||||
|
private void syncToIFSBatch(InventoryMoveRequestDto dto, List<HandlingUnit> handlingUnits) { |
||||
|
try { |
||||
|
// 按site、partNo、原库位、lotBatchNo分组合并数量 |
||||
|
Map<String, MoveGroup> moveGroups = new HashMap<>(); |
||||
|
|
||||
|
for (HandlingUnit hu : handlingUnits) { |
||||
|
String groupKey = String.format("%s|%s|%s|%s", |
||||
|
hu.getSite(), hu.getPartNo(), hu.getLocationId(), hu.getBatchNo()); |
||||
|
|
||||
|
MoveGroup group = moveGroups.computeIfAbsent(groupKey, k -> { |
||||
|
MoveGroup newGroup = new MoveGroup(); |
||||
|
newGroup.site = hu.getSite(); |
||||
|
newGroup.partNo = hu.getPartNo(); |
||||
|
newGroup.sourceLocationNo = hu.getLocationId(); // 注意:这里使用的是更新前的原库位 |
||||
|
newGroup.destLocationNo = dto.getTargetLocationId(); |
||||
|
newGroup.lotBatchNo = hu.getBatchNo(); |
||||
|
newGroup.totalQty = BigDecimal.ZERO; |
||||
|
return newGroup; |
||||
|
}); |
||||
|
|
||||
|
group.totalQty = group.totalQty.add(hu.getQty()); |
||||
|
} |
||||
|
|
||||
|
// 为每个分组调用IFS接口 |
||||
|
for (MoveGroup group : moveGroups.values()) { |
||||
|
syncSingleGroupToIFS(group); |
||||
|
} |
||||
|
|
||||
|
log.info("IFS批量移库同步完成,共{}个分组", moveGroups.size()); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("IFS批量移库同步异常", e); |
||||
|
// 不抛异常,允许WMS内部移库成功但IFS同步失败 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 同步单个分组到IFS |
||||
|
*/ |
||||
|
private void syncSingleGroupToIFS(MoveGroup group) { |
||||
|
try { |
||||
|
Map<String, Object> params = new HashMap<>(); |
||||
|
params.put("ifsDBName", ifsDBName); |
||||
|
params.put("domainUserID", domainUserID); |
||||
|
params.put("ifsSiteID", group.site); |
||||
|
params.put("partNo", group.partNo); |
||||
|
params.put("qtyToIssue", group.totalQty.intValue()); |
||||
|
params.put("locationNo", group.sourceLocationNo); // 原库位 |
||||
|
params.put("destLocationNo", group.destLocationNo); // 目标库位 |
||||
|
params.put("lotBatchNo", group.lotBatchNo); |
||||
|
|
||||
|
ObjectMapper objectMapper = new ObjectMapper(); |
||||
|
String jsonBody = objectMapper.writeValueAsString(params); |
||||
|
String ifsResponse = HttpUtils.doPost(ifsUrl + "MoveInventoryPart", jsonBody, null); |
||||
|
|
||||
|
if ("IFSUpdated".equals(ifsResponse) || "\"IFSUpdated\"".equals(ifsResponse)) { |
||||
|
log.info("IFS移库同步成功 - 物料: {}, 批次: {}, 数量: {}, 从 {} 到 {}", |
||||
|
group.partNo, group.lotBatchNo, group.totalQty, group.sourceLocationNo, group.destLocationNo); |
||||
|
} else { |
||||
|
log.warn("IFS移库同步失败 - 物料: {}, 批次: {}, 响应: {}", |
||||
|
group.partNo, group.lotBatchNo, ifsResponse); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
log.error("IFS移库同步异常 - 物料: {}, 批次: {}", group.partNo, group.lotBatchNo, e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 移库分组内部类 |
||||
|
*/ |
||||
|
private static class MoveGroup { |
||||
|
String site; |
||||
|
String partNo; |
||||
|
String sourceLocationNo; |
||||
|
String destLocationNo; |
||||
|
String lotBatchNo; |
||||
|
BigDecimal totalQty; |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue