Browse Source

合格入库

master
han\hanst 9 months ago
parent
commit
f82b6ac02f
  1. 162
      src/main/java/com/gaotao/common/utils/IfsErrorMessageUtils.java
  2. 34
      src/main/java/com/gaotao/modules/api/entity/issueAndReturnVo/PurchaseOrderMoveToStockDto.java
  3. 38
      src/main/java/com/gaotao/modules/api/entity/issueAndReturnVo/PurchaseOrderReceiptVo.java
  4. 10
      src/main/java/com/gaotao/modules/api/service/IfsApiIssueAndReturnService.java
  5. 71
      src/main/java/com/gaotao/modules/api/service/impl/IfsApiIssueAndReturnServiceImpl.java
  6. 63
      src/main/java/com/gaotao/modules/inspection/controller/QualifiedStorageController.java
  7. 26
      src/main/java/com/gaotao/modules/inspection/service/QualifiedStorageService.java
  8. 448
      src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java
  9. 12
      src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java

162
src/main/java/com/gaotao/common/utils/IfsErrorMessageUtils.java

@ -0,0 +1,162 @@
package com.gaotao.common.utils;
import org.apache.commons.lang.StringUtils;
import lombok.extern.slf4j.Slf4j;
/**
* IFS错误信息处理工具类
*/
@Slf4j
public class IfsErrorMessageUtils {
/**
* 提取Oracle错误信息中的关键内容
* 从第一个 "ORA-20110:" 到第一个 ".\r\n" 之间的内容
*
* @param fullErrorMessage 完整的错误信息
* @return 提取后的关键错误信息
*/
public static String extractOracleErrorMessage(String fullErrorMessage) {
if (StringUtils.isBlank(fullErrorMessage)) {
return "未知错误";
}
try {
// 查找第一个 ORA-20110: 的位置
String oraPattern = "ORA-20110:";
int startIndex = fullErrorMessage.indexOf(oraPattern);
if (startIndex == -1) {
// 如果没有找到 ORA-20110尝试查找其他 ORA 错误
oraPattern = "ORA-";
startIndex = fullErrorMessage.indexOf(oraPattern);
if (startIndex == -1) {
return fullErrorMessage; // 如果没有找到任何 ORA 错误返回原始信息
}
}
// 查找第一个 .\r\n 的位置
String endPattern = ".\\r\\n";
int endIndex = fullErrorMessage.indexOf(endPattern, startIndex);
if (endIndex == -1) {
// 如果没有找到 .\r\n返回原始信息
return fullErrorMessage;
}
// 提取错误信息 ORA-20110: 开始到第一个 .\r\n 之前不包含 .\r\n
String errorMessage = fullErrorMessage.substring(startIndex, endIndex).trim();
// 去掉 ORA-20110: 前缀只保留具体的错误内容
if (errorMessage.startsWith("ORA-20110:")) {
errorMessage = errorMessage.substring("ORA-20110:".length()).trim();
} else if (errorMessage.startsWith("ORA-")) {
// 处理其他ORA错误去掉ORA-xxxxx:前缀
int colonIndex = errorMessage.indexOf(":");
if (colonIndex != -1) {
errorMessage = errorMessage.substring(colonIndex + 1).trim();
}
}
// 如果提取的信息为空或太短返回原始信息
if (StringUtils.isBlank(errorMessage) || errorMessage.length() < 5) {
return fullErrorMessage;
}
return errorMessage;
} catch (Exception e) {
log.warn("提取Oracle错误信息失败: {}", e.getMessage());
return fullErrorMessage; // 提取失败时返回原始信息
}
}
/**
* 提取IFS错误信息中的关键内容
* 支持多种IFS错误格式的提取
*
* @param fullErrorMessage 完整的错误信息
* @return 提取后的关键错误信息
*/
public static String extractIfsErrorMessage(String fullErrorMessage) {
if (StringUtils.isBlank(fullErrorMessage)) {
return "未知错误";
}
// 首先尝试提取Oracle错误
String oracleError = extractOracleErrorMessage(fullErrorMessage);
if (!oracleError.equals(fullErrorMessage)) {
return oracleError; // 如果成功提取到Oracle错误直接返回
}
try {
// 尝试提取其他IFS错误格式
String[] ifsErrorPatterns = {
"Exception:",
"Error:",
"Fault:",
"ServerFaultException:"
};
for (String pattern : ifsErrorPatterns) {
int startIndex = fullErrorMessage.indexOf(pattern);
if (startIndex != -1) {
int messageStart = startIndex + pattern.length();
// 查找结束位置
String[] endPatterns = {"\r\n", "\n", "at ", "\\s+at\\s+"};
int endIndex = fullErrorMessage.length();
for (String endPattern : endPatterns) {
int tempEndIndex = fullErrorMessage.indexOf(endPattern, messageStart);
if (tempEndIndex != -1 && tempEndIndex < endIndex) {
endIndex = tempEndIndex;
break;
}
}
String errorMessage = fullErrorMessage.substring(messageStart, endIndex).trim();
if (StringUtils.isNotBlank(errorMessage) && errorMessage.length() > 5) {
return errorMessage;
}
}
}
return fullErrorMessage;
} catch (Exception e) {
log.warn("提取IFS错误信息失败: {}", e.getMessage());
return fullErrorMessage;
}
}
/**
* 清理错误信息移除不必要的技术细节
*
* @param errorMessage 原始错误信息
* @return 清理后的错误信息
*/
public static String cleanErrorMessage(String errorMessage) {
if (StringUtils.isBlank(errorMessage)) {
return "未知错误";
}
try {
// 移除时间戳和技术参数
String cleaned = errorMessage.replaceAll("\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}\\.\\d+\\(Timestamp\\),?\\s*", "");
cleaned = cleaned.replaceAll("\\d+\\(BigDecimal\\),?\\s*", "");
cleaned = cleaned.replaceAll("\\w+\\(String\\),?\\s*", "");
cleaned = cleaned.replaceAll("\\s*Exception:\\s*", "");
cleaned = cleaned.replaceAll("\\s*at\\s+.*", "");
// 移除多余的空白字符
cleaned = cleaned.replaceAll("\\s+", " ").trim();
return StringUtils.isNotBlank(cleaned) ? cleaned : errorMessage;
} catch (Exception e) {
log.warn("清理错误信息失败: {}", e.getMessage());
return errorMessage;
}
}
}

34
src/main/java/com/gaotao/modules/api/entity/issueAndReturnVo/PurchaseOrderMoveToStockDto.java

@ -0,0 +1,34 @@
package com.gaotao.modules.api.entity.issueAndReturnVo;
import lombok.Data;
import java.math.BigDecimal;
/**
* 采购订单移库到库存DTO
*/
@Data
public class PurchaseOrderMoveToStockDto {
private String ifsDBName;
private String domainUserID;
private String ifsSiteID;
private Long ifsReceiptSequence;
private String ifsSourceRef1;
private String ifsSourceRef2;
private String ifsSourceRef3;
private String ifsSourceRef4;
private Integer ifsReceiptNo;
private String ifsPartNo;
private String ifsConfigurationID;
private String ifsLocationNo;
private String ifsLotBatchNo;
private String ifsNewLotBatchNo;
private String ifsSerialNo;
private String ifsEngChgLevel;
private String ifsWDR;
private String ifsToLocationNo;
private Integer ifsHandlingUnitID;
private Integer ifsSourceQtyToMove;
private Integer ifsInQtyToMove;
private Integer ifsCatchQtyToMove;
}

38
src/main/java/com/gaotao/modules/api/entity/issueAndReturnVo/PurchaseOrderReceiptVo.java

@ -0,0 +1,38 @@
package com.gaotao.modules.api.entity.issueAndReturnVo;
import lombok.Data;
/**
* 采购订单接收记录VO
*/
@Data
public class PurchaseOrderReceiptVo {
private String sourceRef1;
private String sourceRef2;
private String sourceRef3;
private String sourceRef4;
private Integer receiptNo;
private String sourceRefType;
private String contract;
private String state;
private String sourcePartNo;
private String description;
private Double qtyArrived;
private Double qtyToInspect;
private Double qtyInspected;
private String uom;
private Integer noOfInspections;
private String receiver;
private String receiptReference;
private String deliverDate;
private String arrivalDate;
private String approvedDate;
private Double scrappedQty;
private Double returnedQty;
private Double invQtyArrived;
private String sender;
private String senderName;
private String senderType;
private Long receiptSequence;
}

10
src/main/java/com/gaotao/modules/api/service/IfsApiIssueAndReturnService.java

@ -63,4 +63,14 @@ public interface IfsApiIssueAndReturnService {
List<IssueForPurchaseOrderVo> getIssueForPurchaseOrder(String orderNo, String site, String releaseNo,String sequenceNo,String lineItemNo);
String addPurchaseOrderUnIssueComponent(PurchaseOrderUnIssueComponentDto purchaseOrderUnIssueComponentDto);
/**
* 获取采购订单接收记录
*/
List<PurchaseOrderReceiptVo> getPurchaseOrderReceipt(String purchaseOrderNo, String site);
/**
* 采购订单移库到库存
*/
String purchaseOrderMoveToStockOneLocation(PurchaseOrderMoveToStockDto purchaseOrderMoveToStockDto);
}

71
src/main/java/com/gaotao/modules/api/service/impl/IfsApiIssueAndReturnServiceImpl.java

@ -3,6 +3,7 @@ package com.gaotao.modules.api.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gaotao.common.exception.XJException;
import com.gaotao.common.utils.IfsErrorMessageUtils;
import com.gaotao.common.utils.HttpUtils;
import com.gaotao.modules.api.entity.issueAndReturnVo.*;
import com.gaotao.modules.api.service.IfsApiIssueAndReturnService;
@ -39,12 +40,12 @@ public class IfsApiIssueAndReturnServiceImpl implements IfsApiIssueAndReturnServ
private String ifsDBName;
@Value("${custom.ifs-domainUserID}")
private String domainUserID;
@Value("${ldap-control.control-flag:false}")
private Boolean ldapFlag;
private Logger logger = LogManager.getLogger(getClass());
/**
* 获取当前用户的域控账号如果开启了域控账号则获取用户的域控账号否则使用配置的默认值
*/
@ -678,4 +679,70 @@ public class IfsApiIssueAndReturnServiceImpl implements IfsApiIssueAndReturnServ
throw new XJException("UnIssue委外退料同步IFS失败");
}
}
@Override
public List<PurchaseOrderReceiptVo> getPurchaseOrderReceipt(String purchaseOrderNo, String site) {
try {
Map<String, Object> params = Map.of(
"ifsDBName", ifsDBName,
"domainUserID", getCurrentDomainUserID(),
"ifsSiteID", site,
"ifsPurchaseOrderNo", purchaseOrderNo
);
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(params);
String ifsResponse = HttpUtils.doGetWithBody(ifsUrl + "PurchaseOrderReceipt", jsonBody, null);
return objectMapper.readValue(ifsResponse, new TypeReference<List<PurchaseOrderReceiptVo>>() {});
} catch (Exception e) {
log.error("获取采购订单接收记录失败: {}", e.getMessage());
throw new XJException("获取采购订单接收记录失败: " + e.getMessage());
}
}
@Override
public String purchaseOrderMoveToStockOneLocation(PurchaseOrderMoveToStockDto dto) {
try {
Map<String, Object> params = new HashMap<>();
params.put("ifsDBName", dto.getIfsDBName());
params.put("domainUserID", dto.getDomainUserID());
params.put("ifsSiteID", dto.getIfsSiteID());
params.put("ifsReceiptSequence", dto.getIfsReceiptSequence());
params.put("ifsSourceRef1", dto.getIfsSourceRef1());
params.put("ifsSourceRef2", dto.getIfsSourceRef2());
params.put("ifsSourceRef3", dto.getIfsSourceRef3());
params.put("ifsSourceRef4", dto.getIfsSourceRef4() != null ? dto.getIfsSourceRef4() : "");
params.put("ifsReceiptNo", dto.getIfsReceiptNo());
params.put("ifsPartNo", dto.getIfsPartNo());
params.put("ifsConfigurationID", dto.getIfsConfigurationID() != null ? dto.getIfsConfigurationID() : "*");
params.put("ifsLocationNo", dto.getIfsLocationNo());
params.put("ifsLotBatchNo", dto.getIfsLotBatchNo());
params.put("ifsNewLotBatchNo", dto.getIfsNewLotBatchNo());
params.put("ifsSerialNo", dto.getIfsSerialNo() != null ? dto.getIfsSerialNo() : "*");
params.put("ifsEngChgLevel", dto.getIfsEngChgLevel() != null ? dto.getIfsEngChgLevel() : "1");
params.put("ifsWDR", dto.getIfsWDR());
params.put("ifsToLocationNo", dto.getIfsToLocationNo());
params.put("ifsHandlingUnitID", dto.getIfsHandlingUnitID() != null ? dto.getIfsHandlingUnitID() : 0);
params.put("ifsSourceQtyToMove", dto.getIfsSourceQtyToMove());
params.put("ifsInQtyToMove", dto.getIfsInQtyToMove());
params.put("ifsCatchQtyToMove", dto.getIfsCatchQtyToMove() != null ? dto.getIfsCatchQtyToMove() : 0);
ObjectMapper objectMapper = new ObjectMapper();
String jsonBody = objectMapper.writeValueAsString(params);
String ifsResponse = HttpUtils.doPost(ifsUrl + "PurchaseOrderMoveToStockOneLocation", jsonBody, null);
if ("IFSUpdated".equals(ifsResponse) || "\"IFSUpdated\"".equals(ifsResponse)) {
log.info("IFS采购订单移库成功");
return ifsResponse;
} else {
log.error("IFS采购订单移库失败,响应: {}", ifsResponse);
// 提取Oracle错误信息中的关键内容
String errorMessage = IfsErrorMessageUtils.extractOracleErrorMessage(ifsResponse);
throw new XJException(errorMessage);
}
} catch (Exception e) {
log.error("采购订单移库失败: {}", e.getMessage());
throw new XJException(e.getMessage());
}
}
}

63
src/main/java/com/gaotao/modules/inspection/controller/QualifiedStorageController.java

@ -0,0 +1,63 @@
package com.gaotao.modules.inspection.controller;
import com.gaotao.common.utils.R;
import com.gaotao.modules.inspection.service.QualifiedStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
/**
* 检验合格入库控制器
*/
@RestController
@RequestMapping("/qualified-storage")
public class QualifiedStorageController {
@Autowired
private QualifiedStorageService qualifiedStorageService;
/**
* 获取采购订单接收记录列表只显示ARRIVED状态
*/
@PostMapping("/getPurchaseOrderReceiptList")
public R getPurchaseOrderReceiptList(@RequestBody Map<String, Object> params) {
try {
String purchaseOrderNo = (String) params.get("purchaseOrderNo");
String site = (String) params.get("site");
return qualifiedStorageService.getPurchaseOrderReceiptList(purchaseOrderNo, site);
} catch (Exception e) {
return R.error("获取采购订单接收记录失败: " + e.getMessage());
}
}
/**
* 校验并获取HandlingUnit信息用于检验合格入库
*/
@PostMapping("/validateHandlingUnit")
public R validateHandlingUnit(@RequestBody Map<String, Object> params) {
try {
String unitId = (String) params.get("unitId");
String site = (String) params.get("site");
String expectedPartNo = (String) params.get("expectedPartNo");
String expectedBatchNo = (String) params.get("expectedBatchNo");
return qualifiedStorageService.validateHandlingUnitForQualifiedStorage(unitId, site, expectedPartNo, expectedBatchNo);
} catch (Exception e) {
return R.error("HandlingUnit校验失败: " + e.getMessage());
}
}
/**
* 确认检验合格入库
*/
@PostMapping("/confirmQualifiedStorage")
public R confirmQualifiedStorage(@RequestBody Map<String, Object> params) {
try {
return qualifiedStorageService.confirmQualifiedStorage(params);
} catch (Exception e) {
return R.error("检验合格入库失败: " + e.getMessage());
}
}
}

26
src/main/java/com/gaotao/modules/inspection/service/QualifiedStorageService.java

@ -0,0 +1,26 @@
package com.gaotao.modules.inspection.service;
import com.gaotao.common.utils.R;
import java.util.Map;
/**
* 检验合格入库服务接口
*/
public interface QualifiedStorageService {
/**
* 获取采购订单接收记录列表只显示ARRIVED状态
*/
R getPurchaseOrderReceiptList(String purchaseOrderNo, String site);
/**
* 校验并获取HandlingUnit信息用于检验合格入库
*/
R validateHandlingUnitForQualifiedStorage(String unitId, String site, String expectedPartNo, String expectedBatchNo);
/**
* 确认检验合格入库
*/
R confirmQualifiedStorage(Map<String, Object> params);
}

448
src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java

@ -0,0 +1,448 @@
package com.gaotao.modules.inspection.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.gaotao.common.exception.XJException;
import com.gaotao.common.utils.IfsErrorMessageUtils;
import com.gaotao.common.utils.R;
import com.gaotao.modules.api.entity.issueAndReturnVo.PurchaseOrderMoveToStockDto;
import com.gaotao.modules.api.entity.issueAndReturnVo.PurchaseOrderReceiptVo;
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.inspection.entity.InboundConfirmDto;
import com.gaotao.modules.inspection.service.QualifiedStorageService;
import com.gaotao.modules.warehouse.entity.InventoryStock;
import com.gaotao.modules.warehouse.dao.InventoryStockMapper;
import com.gaotao.modules.po.entity.PoReceipt;
import com.gaotao.modules.po.entity.PoReceiptDetail;
import com.gaotao.modules.po.service.PoReceiptDetailService;
import com.gaotao.modules.po.service.PoReceiptService;
import com.gaotao.modules.trans.entity.TransDetail;
import com.gaotao.modules.trans.entity.TransDetailSub;
import com.gaotao.modules.trans.entity.TransHeader;
import com.gaotao.modules.trans.entity.TransNoControl;
import com.gaotao.modules.trans.service.TransDetailService;
import com.gaotao.modules.trans.service.TransDetailSubService;
import com.gaotao.modules.trans.service.TransHeaderService;
import com.gaotao.modules.trans.service.TransNoControlService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
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 com.gaotao.modules.sys.entity.SysUserEntity;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 检验合格入库服务实现类
*/
@Slf4j
@Service
public class QualifiedStorageServiceImpl implements QualifiedStorageService {
@Autowired
private IfsApiIssueAndReturnService ifsApiIssueAndReturnService;
@Autowired
private HandlingUnitService handlingUnitService;
@Autowired
private PoReceiptService poReceiptService;
@Autowired
private PoReceiptDetailService poReceiptDetailService;
@Autowired
private TransHeaderService transHeaderService;
@Autowired
private TransDetailService transDetailService;
@Autowired
private TransDetailSubService transDetailSubService;
@Autowired
private TransNoControlService transNoControlService;
@Autowired
private InventoryStockMapper inventoryStockMapper;
@Value("${custom.ifs-ifsDBName}")
private String ifsDBName;
@Value("${custom.ifs-domainUserID}")
private String domainUserID;
@Value("${ldap-control.control-flag:false}")
private Boolean ldapFlag;
/**
* 获取当前用户的域控账号
*/
private String getCurrentDomainUserID() {
if (ldapFlag) {
try {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
if (currentUser != null && StringUtils.isNotBlank(currentUser.getDomainAccount())) {
return currentUser.getDomainAccount();
}
} catch (Exception e) {
// 如果获取当前用户失败使用默认配置
}
}
return domainUserID;
}
@Override
public R getPurchaseOrderReceiptList(String purchaseOrderNo, String site) {
try {
// 调用IFS接口获取采购订单接收记录
List<PurchaseOrderReceiptVo> allReceipts = ifsApiIssueAndReturnService.getPurchaseOrderReceipt(purchaseOrderNo, site);
// 只保留状态为ARRIVED的记录
List<PurchaseOrderReceiptVo> arrivedReceipts = allReceipts.stream()
.filter(receipt -> "ARRIVED".equals(receipt.getState()) && receipt.getQtyToInspect() == 0)
.collect(Collectors.toList());
return R.ok().put("rows", arrivedReceipts);
} catch (Exception e) {
log.error("获取采购订单接收记录失败: {}", e.getMessage());
return R.error("获取采购订单接收记录失败: " + e.getMessage());
}
}
@Override
public R validateHandlingUnitForQualifiedStorage(String unitId, String site, String expectedPartNo, String expectedBatchNo) {
try {
// 1. 基础参数校验
if (StringUtils.isBlank(unitId)) {
return R.error("HandlingUnit条码不能为空");
}
if (StringUtils.isBlank(site)) {
return R.error("站点不能为空");
}
if (StringUtils.isBlank(expectedPartNo)) {
return R.error("期望物料编码不能为空");
}
// 2. 查询HandlingUnit
HandlingUnit handlingUnit = handlingUnitService.lambdaQuery()
.eq(HandlingUnit::getUnitId, unitId)
.one();
if (handlingUnit == null) {
return R.error("HandlingUnit不存在: " + unitId);
}
// 3. 站点匹配校验
if (!site.equals(handlingUnit.getSite())) {
return R.error("HandlingUnit站点不匹配,期望: " + site + ",实际: " + handlingUnit.getSite());
}
// 4. 物料编码匹配校验
if (!expectedPartNo.equals(handlingUnit.getPartNo())) {
return R.error("HandlingUnit物料编码不匹配,期望: " + expectedPartNo + ",实际: " + handlingUnit.getPartNo());
}
// 5. 批次号匹配校验
if (StringUtils.isNotBlank(expectedBatchNo)) {
String actualBatchNo = handlingUnit.getBatchNo();
if (!expectedBatchNo.equals(actualBatchNo)) {
return R.error("HandlingUnit批次号不匹配,期望: " + expectedBatchNo + ",实际: " + actualBatchNo);
}
}
// 7. 在库状态校验检验合格入库通常要求HU已经在库
if (!"X".equals(handlingUnit.getInStockFlag())) {
return R.error("HandlingUnit不是未入库状态,无法进行检验合格入库");
}
// 8. 返回HandlingUnit信息
Map<String, Object> huInfo = Map.ofEntries(
Map.entry("unitId", handlingUnit.getUnitId()),
Map.entry("partNo", handlingUnit.getPartNo()),
Map.entry("partDesc", handlingUnit.getPartDesc() != null ? handlingUnit.getPartDesc() : ""),
Map.entry("qty", handlingUnit.getQty() != null ? handlingUnit.getQty() : BigDecimal.ZERO),
Map.entry("unit", handlingUnit.getUmId()!= null ? handlingUnit.getUmId() : "个"),
Map.entry("batchNo", handlingUnit.getBatchNo() != null ? handlingUnit.getBatchNo() : ""),
Map.entry("locationId", handlingUnit.getLocationId() != null ? handlingUnit.getLocationId() : ""),
Map.entry("wdr", handlingUnit.getWdr() != null ? handlingUnit.getWdr() : "*"),
Map.entry("site", handlingUnit.getSite()),
Map.entry("status", handlingUnit.getStatus()),
Map.entry("inStockFlag", handlingUnit.getInStockFlag())
);
return R.ok().put("data", huInfo);
} catch (Exception e) {
log.error("HandlingUnit校验失败: {}", e.getMessage());
return R.error("HandlingUnit校验失败: " + e.getMessage());
}
}
@Override
@Transactional
public R confirmQualifiedStorage(Map<String, Object> params) {
try {
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal();
// 解析参数
String site = (String) params.get("site");
Long receiptSequence = Long.valueOf(params.get("receiptSequence").toString());
String sourceRef1 = (String) params.get("sourceRef1");
String sourceRef2 = (String) params.get("sourceRef2");
String sourceRef3 = (String) params.get("sourceRef3");
String sourceRef4 = (String) params.get("sourceRef4");
Integer receiptNo = Integer.valueOf(params.get("receiptNo").toString());
String partNo = (String) params.get("partNo");
String locationNo = (String) params.get("locationNo");
String lotBatchNo = (String) params.get("lotBatchNo");
String wdr = (String) params.get("wdr");
String toLocationNo = (String) params.get("toLocationNo");
Integer qtyToMove = Integer.valueOf(params.get("qtyToMove").toString());
@SuppressWarnings("unchecked")
List<String> handlingUnitIds = (List<String>) params.get("handlingUnitIds");
// 1. 获取HandlingUnit信息并校验
List<HandlingUnit> handlingUnits = handlingUnitService.lambdaQuery()
.in(HandlingUnit::getUnitId, handlingUnitIds)
.eq(HandlingUnit::getSite, site)
.list();
if (handlingUnits.size() != handlingUnitIds.size()) {
return R.error("部分HandlingUnit不存在或站点不匹配");
}
// 计算HandlingUnit总数量
BigDecimal totalScannedQty = handlingUnits.stream()
.map(hu -> hu.getQty() != null ? hu.getQty() : BigDecimal.ZERO)
.reduce(BigDecimal.ZERO, BigDecimal::add);
// 计算可用数量 (qtyArrived - scrappedQty - returnedQty)
Double qtyArrived = Double.valueOf(params.get("qtyArrived").toString());
Double scrappedQty = Double.valueOf(params.get("scrappedQty").toString());
Double returnedQty = Double.valueOf(params.get("returnedQty").toString());
double availableQty = qtyArrived - scrappedQty - returnedQty;
if (totalScannedQty.doubleValue() > availableQty) {
return R.error("扫描的HandlingUnit总数量不能大于可用数量");
}
// 从第一个HandlingUnit获取批次号和WDR信息如果前端没有传递
HandlingUnit firstHu = handlingUnits.get(0);
if (lotBatchNo == null || lotBatchNo.isEmpty()) {
lotBatchNo = firstHu.getBatchNo();
}
if (wdr == null || wdr.isEmpty()) {
wdr = firstHu.getWdr() != null ? firstHu.getWdr() : "*";
}
if (locationNo == null || locationNo.isEmpty()) {
locationNo = firstHu.getLocationId(); // 原库位
}
// 2. 创建入库事务头记录
TransNoControl transNoControl = transNoControlService.getTransNo(site, "INB", 12);
String inboundTransNo = transNoControl.getNewTransNo();
TransHeader inboundHeader = new TransHeader();
inboundHeader.setSite(site);
inboundHeader.setTransNo(inboundTransNo);
inboundHeader.setTransDate(new Date());
inboundHeader.setTransTypeDb("INB"); // 检验合格入库
inboundHeader.setWarehouseId("WH01"); // 默认仓库可以从参数中获取
inboundHeader.setUserId(currentUser.getUserId().toString());
inboundHeader.setUserName(currentUser.getUserDisplay());
inboundHeader.setRemark("检验合格入库 - 接收序列号: " + receiptSequence);
inboundHeader.setOrderRef1(sourceRef1); // PO号
inboundHeader.setStatus("COMPLETED");
inboundHeader.setStatusDb("C");
inboundHeader.setEnterDate(new Date());
inboundHeader.setIfsFlag("N");
transHeaderService.save(inboundHeader);
// 3. 创建入库事务明细记录
TransDetail inboundDetail = new TransDetail();
inboundDetail.setSite(site);
inboundDetail.setTransNo(inboundTransNo);
inboundDetail.setItemNo(1.0);
inboundDetail.setPartNo(partNo);
inboundDetail.setTransQty(totalScannedQty);
inboundDetail.setBatchNo(lotBatchNo);
inboundDetail.setLocationId(toLocationNo);
inboundDetail.setDirection("+"); // 入库方向
inboundDetail.setOrderRef1(sourceRef1); // PO号
inboundDetail.setOrderRef2(receiptSequence.toString()); // 接收序列号
inboundDetail.setOrderRef3("");
inboundDetail.setOrderRef4("");
inboundDetail.setOrderRef5("");
inboundDetail.setRemark("检验合格入库");
transDetailService.save(inboundDetail);
// 4. 创建HandlingUnit子记录
for (int i = 0; i < handlingUnits.size(); i++) {
HandlingUnit hu = handlingUnits.get(i);
TransDetailSub transDetailSub = new TransDetailSub();
transDetailSub.setSite(site);
transDetailSub.setTransNo(inboundTransNo);
transDetailSub.setItemNo((double) (i + 1));
//transDetailSub.setHandlingUnitId(hu.getUnitId());
transDetailSub.setSeqNo(1.0);
transDetailSub.setSubQty(hu.getQty() != null ? hu.getQty().doubleValue() : 0.0);
transDetailSub.setOrderRef1(sourceRef1);
transDetailSub.setOrderRef2(receiptSequence.toString());
transDetailSub.setLocationId(toLocationNo);
transDetailSub.setBatchNo(lotBatchNo);
transDetailSub.setPartNo(partNo);
transDetailSub.setSubNo(hu.getUnitId());
transDetailSub.setDirection("+");
transDetailSub.setRemark("检验合格入库 - HU: " + hu.getUnitId());
transDetailSubService.save(transDetailSub);
}
// 5. 更新HandlingUnit状态
QueryWrapper<HandlingUnit> huWrapper = new QueryWrapper<>();
huWrapper.in("unit_id", handlingUnitIds);
HandlingUnit huUpdate = new HandlingUnit();
huUpdate.setStatus("ACTIVE");
huUpdate.setInStockFlag("Y");
huUpdate.setLocationId(toLocationNo); // 更新库位
huUpdate.setModifiedDate(new Date());
handlingUnitService.update(huUpdate, huWrapper);
// 6. 更新库存
updateInventoryStock(inboundHeader, inboundDetail, qtyToMove, firstHu);
// 7. 调用IFS接口进行移库
PurchaseOrderMoveToStockDto moveDto = new PurchaseOrderMoveToStockDto();
moveDto.setIfsDBName(ifsDBName);
moveDto.setDomainUserID(getCurrentDomainUserID());
moveDto.setIfsSiteID(site);
moveDto.setIfsReceiptSequence(receiptSequence);
moveDto.setIfsSourceRef1(sourceRef1);
moveDto.setIfsSourceRef2(sourceRef2);
moveDto.setIfsSourceRef3(sourceRef3);
moveDto.setIfsSourceRef4(sourceRef4);
moveDto.setIfsReceiptNo(receiptNo);
moveDto.setIfsPartNo(partNo);
moveDto.setIfsConfigurationID("*");
moveDto.setIfsLocationNo(locationNo);
moveDto.setIfsLotBatchNo(lotBatchNo);
moveDto.setIfsNewLotBatchNo(lotBatchNo);
moveDto.setIfsSerialNo("*");
moveDto.setIfsEngChgLevel("1");
moveDto.setIfsWDR(wdr);
moveDto.setIfsToLocationNo(toLocationNo);
moveDto.setIfsHandlingUnitID(0);
moveDto.setIfsSourceQtyToMove(qtyToMove);
moveDto.setIfsInQtyToMove(qtyToMove);
moveDto.setIfsCatchQtyToMove(0);
String result = ifsApiIssueAndReturnService.purchaseOrderMoveToStockOneLocation(moveDto);
if ("IFSUpdated".equals(result) || "\"IFSUpdated\"".equals(result)) {
log.info("检验合格入库成功,事务号: {}, HandlingUnit数量: {}", inboundTransNo, handlingUnits.size());
return R.ok("检验合格入库成功");
} else {
// 提取Oracle错误信息中的关键内容
String errorMessage = IfsErrorMessageUtils.extractOracleErrorMessage(result);
throw new XJException("IFS移库失败: " + errorMessage);
}
} catch (Exception e) {
log.error("检验合格入库失败: {}", e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
}
/**
* 更新库存
*/
private void updateInventoryStock(TransHeader transHeader, TransDetail transDetail,Integer qty,
HandlingUnit firstHu) {
// 直接在此方法中实现库存创建逻辑使用带行锁的库存操作防止并发
String site = transDetail.getSite();
String warehouseId = transHeader.getWarehouseId();
String partNo = transDetail.getPartNo();
String batchNo = transDetail.getBatchNo();
String locationId = transDetail.getLocationId();
String wdr = firstHu.getWdr() != null ? firstHu.getWdr() : "*";
BigDecimal transQty = BigDecimal.valueOf(qty);
// 使用行锁查询现有库存
InventoryStock existingStock = inventoryStockMapper.selectForUpdate(site, warehouseId, partNo, batchNo, locationId, wdr);
if (existingStock != null) {
// 库存存在更新库存检验入库一般不涉及HandlingUnit
updateExistingStockForInspection(site, warehouseId, partNo, batchNo, locationId, wdr, transQty);
} else {
// 库存不存在创建新库存记录
createNewStockForInspection(site, warehouseId, partNo, batchNo, locationId, wdr, transQty, firstHu);
}
}
/**
* 更新现有库存检验入库
*/
private void updateExistingStockForInspection(String site, String warehouseId, String partNo,
String batchNo, String locationId, String wdr,
BigDecimal addQty) {
// 检验入库一般不更新HandlingUnit数量
int updateResult = inventoryStockMapper.updateStockWithoutHandlingUnit(
site, warehouseId, partNo, batchNo, locationId, wdr, addQty);
if (updateResult == 0) {
throw new XJException("库存更新失败,可能记录已被删除或修改");
}
}
/**
* 创建新库存记录检验入库
*/
private void createNewStockForInspection(String site, String warehouseId, String partNo,
String batchNo, String locationId, String wdr,
BigDecimal transQty, HandlingUnit firstHu) {
InventoryStock newStock = new InventoryStock();
newStock.setSite(site);
newStock.setWarehouseId(warehouseId);
newStock.setPartNo(partNo);
newStock.setBatchNo(batchNo);
newStock.setLocationId(locationId);
newStock.setInQty(transQty);
newStock.setInStandardValue(transQty);
newStock.setInActualValue(transQty);
newStock.setQtyOnHand(transQty);
newStock.setOutQty(BigDecimal.ZERO);
newStock.setQtyReserved(BigDecimal.ZERO);
// PoReceiptDetail 中获取制造日期和失效日期
newStock.setManufactureDate(firstHu.getManufactureDate());
newStock.setExpiredDate(firstHu.getExpiredDate());
newStock.setFreezeFlag("N");
newStock.setFirstInDate(firstHu.getReceiveDate());
newStock.setLatestInDate(firstHu.getReceiveDate());
newStock.setActiveDate(firstHu.getReceiveDate());
newStock.setWdr(wdr);
// PoReceiptDetail 中获取长度和宽度
newStock.setLength(firstHu.getLength());
newStock.setWidth(firstHu.getWidth());
// 检验入库一般不设置HandlingUnitQty
int insertResult = inventoryStockMapper.insert(newStock);
if (insertResult == 0) {
throw new XJException("库存记录创建失败");
}
}
}

12
src/main/java/com/gaotao/modules/warehouse/service/impl/IfsInventoryInitServiceImpl.java

@ -81,7 +81,7 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService {
handlingUnit.setStatusDb("ACTIVE");
handlingUnit.setFreezeFlag("N");
handlingUnit.setMergedFlag("N");
handlingUnit.setInStockFlag("X");
handlingUnit.setInStockFlag("Y");
handlingUnit.setCreatedDate(new Date());
handlingUnit.setCreatedBy("SYSTEM");
handlingUnit.setSourceType("IFS_INIT");
@ -113,7 +113,7 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService {
handlingUnit.setWidth(width);
handlingUnit.setLength(length);
handlingUnit.setModifiedDate(ifsStock.getManufactureDate());
handlingUnit.setManufactureDate(ifsStock.getManufactureDate());
handlingUnit.setExpiredDate(ifsStock.getExpiredDate());
handlingUnit.setUmId(request.getUmid());
@ -135,13 +135,13 @@ public class IfsInventoryInitServiceImpl implements IfsInventoryInitService {
}
// 校验打印数量不能超过入库数量
if (ifsStock.getInQty() != null) {
if (ifsStock.getQtyOnHand() != null) {
Integer currentPrintQty = ifsStock.getPrintQty() != null ? ifsStock.getPrintQty().intValue() : 0;
int newPrintQty = currentPrintQty + totalPrintQty;
if (newPrintQty > ifsStock.getInQty().intValue()) {
if (newPrintQty > ifsStock.getQtyOnHand().intValue()) {
throw new RuntimeException(String.format(
"打印数量不能超过库数量!当前已打印:%d,本次打印:%d,库数量:%d",
currentPrintQty, totalPrintQty, ifsStock.getInQty().intValue()));
"打印数量不能超过库数量!当前已打印:%d,本次打印:%d,库数量:%d",
currentPrintQty, totalPrintQty, ifsStock.getQtyOnHand().intValue()));
}
}

Loading…
Cancel
Save