Browse Source

移库

master
han\hanst 5 months ago
parent
commit
92da8db8e2
  1. 2
      src/main/java/com/gaotao/modules/inspection/service/impl/InspectionInboundServiceImpl.java
  2. 18
      src/main/java/com/gaotao/modules/other/controller/OtherInboundController.java
  3. 38
      src/main/java/com/gaotao/modules/other/entity/InventoryMoveRequestDto.java
  4. 15
      src/main/java/com/gaotao/modules/other/service/InventoryMoveService.java
  5. 333
      src/main/java/com/gaotao/modules/other/service/impl/InventoryMoveServiceImpl.java
  6. 5
      src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java

2
src/main/java/com/gaotao/modules/inspection/service/impl/InspectionInboundServiceImpl.java

@ -426,8 +426,6 @@ public class InspectionInboundServiceImpl implements InspectionInboundService {
newStock.setLength(poReceiptDetail.getLength()); newStock.setLength(poReceiptDetail.getLength());
newStock.setWidth(poReceiptDetail.getWidth()); newStock.setWidth(poReceiptDetail.getWidth());
// 设置打印数量为1
newStock.setPrintQty(BigDecimal.ONE);
// 检验入库一般不设置HandlingUnitQty // 检验入库一般不设置HandlingUnitQty

18
src/main/java/com/gaotao/modules/other/controller/OtherInboundController.java

@ -1,8 +1,10 @@
package com.gaotao.modules.other.controller; package com.gaotao.modules.other.controller;
import com.gaotao.common.utils.R; import com.gaotao.common.utils.R;
import com.gaotao.modules.other.entity.InventoryMoveRequestDto;
import com.gaotao.modules.other.entity.OtherInboundRequestDto; import com.gaotao.modules.other.entity.OtherInboundRequestDto;
import com.gaotao.modules.other.entity.OtherOutboundRequestDto; import com.gaotao.modules.other.entity.OtherOutboundRequestDto;
import com.gaotao.modules.other.service.InventoryMoveService;
import com.gaotao.modules.other.service.OtherInboundService; import com.gaotao.modules.other.service.OtherInboundService;
import com.gaotao.modules.other.service.OtherOutboundService; import com.gaotao.modules.other.service.OtherOutboundService;
import com.gaotao.modules.warehouse.service.LocationService; import com.gaotao.modules.warehouse.service.LocationService;
@ -28,6 +30,9 @@ public class OtherInboundController {
@Autowired @Autowired
private OtherOutboundService otherOutboundService; private OtherOutboundService otherOutboundService;
@Autowired
private InventoryMoveService inventoryMoveService;
/** /**
* 确认其它入库 * 确认其它入库
*/ */
@ -66,6 +71,19 @@ public class OtherInboundController {
} }
} }
/**
* 确认库存移库
*/
@RequestMapping("/confirmInventoryMove")
public R confirmInventoryMove(@RequestBody InventoryMoveRequestDto dto) {
try {
inventoryMoveService.confirmInventoryMove(dto);
return R.ok("库存移库成功");
} catch (Exception e) {
return R.error(e.getMessage());
}
}
/** /**
* 验证库位是否有效测试接口 * 验证库位是否有效测试接口
*/ */

38
src/main/java/com/gaotao/modules/other/entity/InventoryMoveRequestDto.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;
}

15
src/main/java/com/gaotao/modules/other/service/InventoryMoveService.java

@ -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);
}

333
src/main/java/com/gaotao/modules/other/service/impl/InventoryMoveServiceImpl.java

@ -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 - 按sitepartNolocationNolotBatchNo合并后调用
*/
private void syncToIFSBatch(InventoryMoveRequestDto dto, List<HandlingUnit> handlingUnits) {
try {
// 按sitepartNo原库位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;
}
}

5
src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java

@ -363,14 +363,9 @@ public class PoServiceImpl extends ServiceImpl<PoMapper, PurchaseOrder> implemen
newStock.setLatestInDate(new Date()); newStock.setLatestInDate(new Date());
newStock.setActiveDate(new Date()); newStock.setActiveDate(new Date());
newStock.setWdr(wdr); newStock.setWdr(wdr);
// PoReceiptDetail 中获取长度和宽度 // PoReceiptDetail 中获取长度和宽度
newStock.setLength(receiptDetail.getLength()); newStock.setLength(receiptDetail.getLength());
newStock.setWidth(receiptDetail.getWidth()); newStock.setWidth(receiptDetail.getWidth());
// 设置打印数量为1
newStock.setPrintQty(BigDecimal.ONE);
if ("Y".equals(huFlag)) { if ("Y".equals(huFlag)) {
newStock.setHandlingUnitQty(transQty); newStock.setHandlingUnitQty(transQty);
} }

Loading…
Cancel
Save