|
|
|
@ -53,6 +53,9 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
@Autowired |
|
|
|
private TransDetailService transDetailService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private TransDetailSubService transDetailSubService; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private InventoryStockMapper inventoryStockMapper; |
|
|
|
|
|
|
|
@ -69,267 +72,10 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
@Autowired |
|
|
|
private HandlingUnitService handlingUnitService; |
|
|
|
|
|
|
|
@Value("${custom.ifs-url}") |
|
|
|
private String ifsUrl; |
|
|
|
@Value("${custom.ifs-ifsDBName}") |
|
|
|
private String ifsDBName; |
|
|
|
@Value("${custom.ifs-domainUserID}") |
|
|
|
private String domainUserID; |
|
|
|
|
|
|
|
@Value("${ldap-control.control-flag:false}") |
|
|
|
private Boolean ldapFlag; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private IfsInspectionHistoryService ifsInspectionHistoryService; |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取当前用户的域控账号,如果开启了域控账号则获取用户的域控账号,否则使用配置的默认值 |
|
|
|
*/ |
|
|
|
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 List<QualifiedInspectionDto> getQualifiedInspectionList(QualifiedInspectionDto qualifiedInspectionDto) { |
|
|
|
// 直接查询po_receipt_detail表中状态为ARRIVED的记录 |
|
|
|
QueryWrapper<PoReceiptDetail> detailWrapper = new QueryWrapper<>(); |
|
|
|
detailWrapper.eq("status", "ARRIVED"); // 状态为已到货 |
|
|
|
|
|
|
|
if (qualifiedInspectionDto.getSite() != null) { |
|
|
|
detailWrapper.eq("site", qualifiedInspectionDto.getSite()); |
|
|
|
} |
|
|
|
|
|
|
|
// 支持根据接收单号或采购单号查找 |
|
|
|
if (qualifiedInspectionDto.getTransNo() != null) { |
|
|
|
detailWrapper.and(wrapper -> wrapper |
|
|
|
.eq("receipt_no", qualifiedInspectionDto.getTransNo()) // 接收单号 |
|
|
|
.or() |
|
|
|
.eq("order_no", qualifiedInspectionDto.getTransNo()) // 采购单号 |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
detailWrapper.orderByDesc("receipt_no"); |
|
|
|
|
|
|
|
List<PoReceiptDetail> details = poReceiptDetailService.list(detailWrapper); |
|
|
|
List<QualifiedInspectionDto> result = new ArrayList<>(); |
|
|
|
|
|
|
|
for (PoReceiptDetail detail : details) { |
|
|
|
// 获取对应的接收单主记录 |
|
|
|
QueryWrapper<PoReceipt> receiptWrapper = new QueryWrapper<>(); |
|
|
|
receiptWrapper.eq("site", detail.getSite()); |
|
|
|
receiptWrapper.eq("receipt_no", detail.getReceiptNo()); |
|
|
|
PoReceipt receipt = poReceiptService.getOne(receiptWrapper); |
|
|
|
|
|
|
|
if (receipt != null) { |
|
|
|
QualifiedInspectionDto dto = new QualifiedInspectionDto(); |
|
|
|
dto.setSite(detail.getSite()); |
|
|
|
dto.setTransNo(detail.getReceiptNo()); // 使用接收单号作为事务号 |
|
|
|
dto.setItemNo(String.valueOf(detail.getItemNo())); |
|
|
|
dto.setPartNo(detail.getPartNo()); |
|
|
|
dto.setPartDesc(detail.getPartDesc()); |
|
|
|
dto.setTransQty(detail.getArriveQty()); |
|
|
|
dto.setQualifiedQty(detail.getQtyToInspect()); // 待检验数量 |
|
|
|
dto.setBatchNo(detail.getBatchNo()); |
|
|
|
dto.setLocationId(detail.getLocationId()); |
|
|
|
dto.setWarehouseId(receipt.getWarehouseId()); |
|
|
|
dto.setOrderRef1(detail.getOrderNo()); // 采购单号 |
|
|
|
dto.setOrderRef2(""); |
|
|
|
dto.setOrderRef3(""); |
|
|
|
dto.setTransDate(receipt.getReceiveDate()); |
|
|
|
dto.setInspectionDate(detail.getInspectionTime()); |
|
|
|
dto.setInspectionUser(detail.getInspector()); |
|
|
|
dto.setStatus("A"); // ARRIVED状态 |
|
|
|
dto.setUserName(receipt.getReceiver()); |
|
|
|
dto.setRemark(receipt.getRemark()); |
|
|
|
|
|
|
|
result.add(dto); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional |
|
|
|
public void confirmQualifiedInbound(InboundConfirmDto inboundConfirm) { |
|
|
|
try { |
|
|
|
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); |
|
|
|
|
|
|
|
// 1. 获取采购接收单信息 |
|
|
|
PoReceipt poReceipt = poReceiptService.lambdaQuery() |
|
|
|
.eq(PoReceipt::getSite, inboundConfirm.getSite()) |
|
|
|
.eq(PoReceipt::getReceiptNo, inboundConfirm.getTransNo()) |
|
|
|
.one(); |
|
|
|
|
|
|
|
if (poReceipt == null) { |
|
|
|
throw new RuntimeException("采购接收单不存在: " + inboundConfirm.getTransNo()); |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 获取采购接收单明细 |
|
|
|
PoReceiptDetail poReceiptDetail = poReceiptDetailService.lambdaQuery() |
|
|
|
.eq(PoReceiptDetail::getSite, inboundConfirm.getSite()) |
|
|
|
.eq(PoReceiptDetail::getReceiptNo, inboundConfirm.getTransNo()) |
|
|
|
.eq(PoReceiptDetail::getItemNo, Double.valueOf(inboundConfirm.getItemNo())) |
|
|
|
.one(); |
|
|
|
|
|
|
|
if (poReceiptDetail == null) { |
|
|
|
throw new RuntimeException("采购接收单明细不存在"); |
|
|
|
} |
|
|
|
|
|
|
|
// 3. 创建入库事务头记录 |
|
|
|
TransNoControl transNoControl = transNoControlService.getTransNo(inboundConfirm.getSite(), "INB", 12); |
|
|
|
String inboundTransNo = transNoControl.getNewTransNo(); |
|
|
|
|
|
|
|
TransHeader inboundHeader = new TransHeader(); |
|
|
|
inboundHeader.setSite(inboundConfirm.getSite()); |
|
|
|
inboundHeader.setTransNo(inboundTransNo); |
|
|
|
inboundHeader.setTransDate(inboundConfirm.getInboundDate()); |
|
|
|
inboundHeader.setTransTypeDb("INB"); // 检验合格入库 |
|
|
|
inboundHeader.setWarehouseId(poReceipt.getWarehouseId()); |
|
|
|
inboundHeader.setUserId(currentUser.getUserId().toString()); |
|
|
|
inboundHeader.setUserName(currentUser.getUserDisplay()); |
|
|
|
inboundHeader.setRemark("检验合格入库 - 接收单号: " + inboundConfirm.getTransNo()); |
|
|
|
inboundHeader.setOrderRef1(poReceiptDetail.getOrderNo()); // PO号 |
|
|
|
inboundHeader.setStatus("COMPLETED"); |
|
|
|
inboundHeader.setStatusDb("C"); |
|
|
|
inboundHeader.setEnterDate(new Date()); |
|
|
|
inboundHeader.setIfsFlag("N"); |
|
|
|
|
|
|
|
transHeaderService.save(inboundHeader); |
|
|
|
|
|
|
|
// 4. 创建入库事务明细记录 |
|
|
|
TransDetail inboundDetail = new TransDetail(); |
|
|
|
inboundDetail.setSite(inboundConfirm.getSite()); |
|
|
|
inboundDetail.setTransNo(inboundTransNo); |
|
|
|
inboundDetail.setItemNo(Double.valueOf(inboundConfirm.getItemNo())); |
|
|
|
inboundDetail.setPartNo(poReceiptDetail.getPartNo()); |
|
|
|
inboundDetail.setTransQty(inboundConfirm.getInboundQty()); |
|
|
|
inboundDetail.setBatchNo(poReceiptDetail.getBatchNo()); |
|
|
|
inboundDetail.setLocationId(inboundConfirm.getTargetLocationId()); |
|
|
|
inboundDetail.setDirection("+"); // 入库方向 |
|
|
|
inboundDetail.setOrderRef1(poReceipt.getOrderref1()); // PO号 |
|
|
|
inboundDetail.setOrderRef2(inboundConfirm.getTransNo()); // 接收单号 |
|
|
|
inboundDetail.setOrderRef3(""); |
|
|
|
inboundDetail.setOrderRef4(""); |
|
|
|
inboundDetail.setOrderRef5(""); |
|
|
|
inboundDetail.setRemark("检验合格入库"); |
|
|
|
transDetailService.save(inboundDetail); |
|
|
|
|
|
|
|
// 5. 根据接收记录查找HU,根据HU的数量来决定sub的数量 |
|
|
|
// HandlingUnit的orderRef2就是接收单号,可以根据site+orderRef2来查HU数量 |
|
|
|
List<HandlingUnit> handlingUnits = handlingUnitService.getHandlingUnitsBySiteAndOrderRef2( |
|
|
|
inboundConfirm.getSite(), inboundConfirm.getTransNo()); |
|
|
|
|
|
|
|
if (handlingUnits != null && !handlingUnits.isEmpty()) { |
|
|
|
// 根据HU数量创建对应数量的TransDetailSub记录 |
|
|
|
for (int i = 0; i < handlingUnits.size(); i++) { |
|
|
|
HandlingUnit hu = handlingUnits.get(i); |
|
|
|
TransDetailSub transDetailSub = new TransDetailSub(); |
|
|
|
transDetailSub.setSite(inboundConfirm.getSite()); |
|
|
|
transDetailSub.setTransNo(inboundTransNo); |
|
|
|
transDetailSub.setItemNo((double) (i + 1)); // 从1开始编号 |
|
|
|
transDetailSub.setHandlingUnitId(hu.getUnitId()); |
|
|
|
transDetailSub.setSeqNo(poReceiptDetail.getItemNo()); |
|
|
|
// 每个HU的数量 |
|
|
|
transDetailSub.setSubQty(hu.getQty() != null ? hu.getQty().doubleValue() : 0.0); |
|
|
|
transDetailSub.setOrderRef1(poReceiptDetail.getOrderNo()); |
|
|
|
transDetailSub.setOrderRef2(inboundConfirm.getTransNo()); // 接收单号 |
|
|
|
transDetailSub.setLocationId(poReceiptDetail.getLocationId()); |
|
|
|
transDetailSub.setBatchNo(poReceiptDetail.getBatchNo()); |
|
|
|
transDetailSub.setPartNo(poReceiptDetail.getPartNo()); |
|
|
|
transDetailSub.setSubNo(hu.getUnitId()); // 使用HU的unitId作为subNo |
|
|
|
transDetailSub.setDirection("+"); // 入库方向 |
|
|
|
transDetailSub.setRemark("检验合格入库 - HU: " + hu.getUnitId()); |
|
|
|
subService.save(transDetailSub); |
|
|
|
} |
|
|
|
// 将HU状态更新为已入库,inStockFlag = 'Y' |
|
|
|
QueryWrapper<HandlingUnit> huWrapper = new QueryWrapper<>(); |
|
|
|
huWrapper.in("unit_id", handlingUnits.stream().map(HandlingUnit::getUnitId).toList()); |
|
|
|
HandlingUnit huUpdate = new HandlingUnit(); |
|
|
|
huUpdate.setStatus("ACTIVE"); // 设置为失效状态 |
|
|
|
huUpdate.setInStockFlag("Y"); |
|
|
|
huUpdate.setModifiedDate(new Date()); |
|
|
|
handlingUnitService.update(huUpdate, huWrapper); |
|
|
|
} |
|
|
|
// 6. 更新采购接收单明细的状态 |
|
|
|
poReceiptDetailService.lambdaUpdate() |
|
|
|
.set(PoReceiptDetail::getStatus, "RECEIVED") // 检验合格 |
|
|
|
.set(PoReceiptDetail::getQtyReceived, |
|
|
|
poReceiptDetail.getQtyReceived() == null ? inboundConfirm.getInboundQty() : |
|
|
|
poReceiptDetail.getQtyReceived().add(inboundConfirm.getInboundQty())) |
|
|
|
.eq(PoReceiptDetail::getSite, inboundConfirm.getSite()) |
|
|
|
.eq(PoReceiptDetail::getReceiptNo, inboundConfirm.getTransNo()) |
|
|
|
.eq(PoReceiptDetail::getItemNo, Double.valueOf(inboundConfirm.getItemNo())) |
|
|
|
.update(); |
|
|
|
|
|
|
|
// 7. 更新库存 |
|
|
|
updateInventoryStock(inboundHeader, inboundDetail, inboundConfirm, poReceiptDetail); |
|
|
|
// 同步ifs |
|
|
|
syncToIFS(inboundConfirm,poReceiptDetail); |
|
|
|
} catch (Exception e) { |
|
|
|
throw new RuntimeException("检验合格入库失败: " + e.getMessage(), e); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 同步到IFS |
|
|
|
*/ |
|
|
|
private void syncToIFS(InboundConfirmDto inboundConfirm,PoReceiptDetail poReceiptDetail) { |
|
|
|
try { |
|
|
|
Map<String, Object> params = Map.ofEntries( |
|
|
|
Map.entry("ifsDBName", ifsDBName), |
|
|
|
Map.entry("domainUserID", getCurrentDomainUserID()), |
|
|
|
Map.entry("ifsSiteID", inboundConfirm.getSite()), |
|
|
|
Map.entry("ifsReceiptSequence", Integer.parseInt(inboundConfirm.getTransNo())), // 接收单号 |
|
|
|
Map.entry("ifsSourceRef1", poReceiptDetail.getOrderNo()), // PO号 |
|
|
|
Map.entry("ifsSourceRef2", poReceiptDetail.getOrderItemNo()), // 明细行号 |
|
|
|
Map.entry("ifsSourceRef3", poReceiptDetail.getOrderReleaseNo()), // 版本号 |
|
|
|
Map.entry("ifsSourceRef4", ""), // 空 |
|
|
|
Map.entry("ifsReceiptNo", poReceiptDetail.getItemNo()), // 接收单号 |
|
|
|
Map.entry("ifsPartNo", inboundConfirm.getPartNo()), |
|
|
|
Map.entry("ifsConfigurationID", "*"), // 固定为* |
|
|
|
Map.entry("ifsLocationNo", poReceiptDetail.getLocationId()), // 原库位 |
|
|
|
Map.entry("ifsLotBatchNo", poReceiptDetail.getBatchNo()), |
|
|
|
Map.entry("ifsNewLotBatchNo", poReceiptDetail.getBatchNo()), |
|
|
|
Map.entry("ifsSerialNo", "*"), // 固定为* |
|
|
|
Map.entry("ifsEngChgLevel", "1"), // 固定为1 |
|
|
|
Map.entry("ifsWDR", poReceiptDetail.getWdr()), // WDR |
|
|
|
Map.entry("ifsToLocationNo", inboundConfirm.getTargetLocationId()), // 目标库位 |
|
|
|
Map.entry("ifsHandlingUnitID", 0), // 固定为0 |
|
|
|
Map.entry("ifsSourceQtyToMove", inboundConfirm.getInboundQty().intValue()), // 入库数量 |
|
|
|
Map.entry("ifsInQtyToMove", inboundConfirm.getInboundQty().intValue()), // 入库数量 |
|
|
|
Map.entry("ifsCatchQtyToMove", 0) // 固定为0 |
|
|
|
); |
|
|
|
ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
String jsonBody = objectMapper.writeValueAsString(params); |
|
|
|
String ifsResponse = HttpUtils.doPost(ifsUrl+"PurchaseOrderMoveToStockOneLocation",jsonBody,null); |
|
|
|
log.info("同步检验合格入库接收记录到IFS,PO号: {}", poReceiptDetail.getOrderNo()); |
|
|
|
if ("IFSUpdated".equals(ifsResponse) || "\"IFSUpdated\"".equals(ifsResponse)) { |
|
|
|
log.info("IFS同步检验合格入库成功,PO号: {}", poReceiptDetail.getOrderNo()); |
|
|
|
} else { |
|
|
|
log.error("IFS同步检验合格入库失败,PO号: {}, 响应: {}", poReceiptDetail.getOrderNo(), ifsResponse); |
|
|
|
// 同步失败需要回滚前面所有的数据库操作 |
|
|
|
throw new XJException("IFS同步检验合格入库失败,响应: " + ifsResponse); |
|
|
|
} |
|
|
|
} catch (XJException e) { |
|
|
|
// 重新抛出业务异常,确保事务回滚 |
|
|
|
throw e; |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("IFS同步检验合格入库失败,PO号: {}, 错误: {}", poReceiptDetail.getOrderNo(), e.getMessage()); |
|
|
|
// 同步异常需要回滚前面所有的数据库操作 |
|
|
|
throw new XJException("IFS同步异常: " + e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public List<QualifiedInspectionDto> getInboundHistory(QualifiedInspectionDto qualifiedInspectionDto) { |
|
|
|
@ -379,214 +125,98 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 更新库存 |
|
|
|
*/ |
|
|
|
private void updateInventoryStock(TransHeader transHeader, TransDetail transDetail, InboundConfirmDto inboundConfirm, PoReceiptDetail poReceiptDetail) { |
|
|
|
// 直接在此方法中实现库存创建逻辑,使用带行锁的库存操作,防止并发 |
|
|
|
String site = transDetail.getSite(); |
|
|
|
String warehouseId = transHeader.getWarehouseId(); |
|
|
|
String partNo = transDetail.getPartNo(); |
|
|
|
String batchNo = transDetail.getBatchNo(); |
|
|
|
String locationId = inboundConfirm.getTargetLocationId(); |
|
|
|
String wdr = poReceiptDetail.getWdr() != null ? poReceiptDetail.getWdr() : "*"; |
|
|
|
BigDecimal transQty = inboundConfirm.getInboundQty(); |
|
|
|
|
|
|
|
// 使用行锁查询现有库存 |
|
|
|
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, poReceiptDetail, inboundConfirm); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 更新现有库存(检验入库) |
|
|
|
*/ |
|
|
|
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, PoReceiptDetail poReceiptDetail, |
|
|
|
InboundConfirmDto inboundConfirm) { |
|
|
|
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(poReceiptDetail.getManuFactureDate()); |
|
|
|
newStock.setExpiredDate(poReceiptDetail.getExpiredDate()); |
|
|
|
|
|
|
|
newStock.setFreezeFlag("N"); |
|
|
|
newStock.setFirstInDate(inboundConfirm.getInboundDate()); |
|
|
|
newStock.setLatestInDate(inboundConfirm.getInboundDate()); |
|
|
|
newStock.setActiveDate(inboundConfirm.getInboundDate()); |
|
|
|
newStock.setWdr(wdr); |
|
|
|
|
|
|
|
// 从 PoReceiptDetail 中获取长度和宽度 |
|
|
|
newStock.setLength(poReceiptDetail.getLength()); |
|
|
|
newStock.setWidth(poReceiptDetail.getWidth()); |
|
|
|
|
|
|
|
|
|
|
|
// 检验入库一般不设置HandlingUnitQty |
|
|
|
|
|
|
|
int insertResult = inventoryStockMapper.insert(newStock); |
|
|
|
if (insertResult == 0) { |
|
|
|
throw new XJException("库存记录创建失败"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
public List<UnqualifiedInspectionDto> getUnqualifiedInspectionList(UnqualifiedInspectionDto unqualifiedInspectionDto) { |
|
|
|
// 查询po_receipt_detail表中所有不合格状态的记录 |
|
|
|
QueryWrapper<PoReceiptDetail> detailWrapper = new QueryWrapper<>(); |
|
|
|
|
|
|
|
// 查询所有不合格状态 |
|
|
|
detailWrapper.in("status", "RETCREDIT", "RETWORK", "INVSCRAP", "SCPCREDIT", "EXCHANGE", "REWORK"); |
|
|
|
|
|
|
|
if (unqualifiedInspectionDto.getSite() != null) { |
|
|
|
detailWrapper.eq("site", unqualifiedInspectionDto.getSite()); |
|
|
|
} |
|
|
|
|
|
|
|
// 支持根据接收单号或采购单号查找 |
|
|
|
if (unqualifiedInspectionDto.getTransNo() != null) { |
|
|
|
detailWrapper.and(wrapper -> wrapper |
|
|
|
.eq("receipt_no", unqualifiedInspectionDto.getTransNo()) // 接收单号 |
|
|
|
.or() |
|
|
|
.eq("order_no", unqualifiedInspectionDto.getTransNo()) // 采购单号 |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
detailWrapper.orderByDesc("receipt_no"); |
|
|
|
|
|
|
|
List<PoReceiptDetail> details = poReceiptDetailService.list(detailWrapper); |
|
|
|
List<UnqualifiedInspectionDto> result = new ArrayList<>(); |
|
|
|
|
|
|
|
for (PoReceiptDetail detail : details) { |
|
|
|
// 获取对应的接收单主记录 |
|
|
|
QueryWrapper<PoReceipt> receiptWrapper = new QueryWrapper<>(); |
|
|
|
receiptWrapper.eq("site", detail.getSite()); |
|
|
|
receiptWrapper.eq("receipt_no", detail.getReceiptNo()); |
|
|
|
PoReceipt receipt = poReceiptService.getOne(receiptWrapper); |
|
|
|
|
|
|
|
if (receipt != null) { |
|
|
|
String status = detail.getStatus(); |
|
|
|
String processType = mapStatusToProcessType(status); |
|
|
|
BigDecimal unqualifiedQty = getUnqualifiedQtyByStatus(detail, status); |
|
|
|
@Transactional |
|
|
|
public void confirmUnqualifiedProcess(String site,String transNo, String processType, List<String> handlingUnitIds) { |
|
|
|
try { |
|
|
|
// 获取当前用户 |
|
|
|
SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); |
|
|
|
|
|
|
|
// 只有数量大于0的记录才添加到结果中 |
|
|
|
if (unqualifiedQty != null && unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
|
|
|
UnqualifiedInspectionDto dto = new UnqualifiedInspectionDto(); |
|
|
|
dto.setSite(detail.getSite()); |
|
|
|
dto.setTransNo(detail.getReceiptNo()); // 使用接收单号作为事务号 |
|
|
|
dto.setItemNo(String.valueOf(detail.getItemNo())); |
|
|
|
dto.setPartNo(detail.getPartNo()); |
|
|
|
dto.setPartDesc(detail.getPartDesc()); |
|
|
|
dto.setTransQty(detail.getArriveQty()); |
|
|
|
dto.setUnqualifiedQty(unqualifiedQty); // 根据状态获取对应的数量 |
|
|
|
dto.setBatchNo(detail.getBatchNo()); |
|
|
|
dto.setLocationId(detail.getLocationId()); |
|
|
|
dto.setWarehouseId(receipt.getWarehouseId()); |
|
|
|
dto.setOrderRef1(detail.getOrderNo()); // 采购单号 |
|
|
|
dto.setOrderRef2(""); |
|
|
|
dto.setOrderRef3(""); |
|
|
|
dto.setTransDate(receipt.getReceiveDate()); |
|
|
|
dto.setInspectionDate(detail.getInspectionTime()); |
|
|
|
dto.setInspectionUser(detail.getInspector()); |
|
|
|
dto.setStatus(status); // 原始状态 |
|
|
|
dto.setUserName(receipt.getReceiver()); |
|
|
|
dto.setRemark(receipt.getRemark()); |
|
|
|
dto.setProcessType(processType); // 处理类型 |
|
|
|
if (handlingUnitIds != null && !handlingUnitIds.isEmpty()) { |
|
|
|
// 1. 获取HandlingUnit信息 |
|
|
|
QueryWrapper<HandlingUnit> huQueryWrapper = new QueryWrapper<>(); |
|
|
|
huQueryWrapper.in("unit_id", handlingUnitIds); |
|
|
|
List<HandlingUnit> handlingUnits = handlingUnitService.list(huQueryWrapper); |
|
|
|
|
|
|
|
result.add(dto); |
|
|
|
if (handlingUnits.isEmpty()) { |
|
|
|
throw new RuntimeException("未找到对应的HandlingUnit记录"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据状态获取对应的不合格数量 |
|
|
|
*/ |
|
|
|
private BigDecimal getUnqualifiedQtyByStatus(PoReceiptDetail detail, String status) { |
|
|
|
if (status == null) { |
|
|
|
return BigDecimal.ZERO; |
|
|
|
} |
|
|
|
|
|
|
|
switch (status) { |
|
|
|
case "RETCREDIT": |
|
|
|
case "RETWORK": |
|
|
|
// 退货数量 |
|
|
|
return detail.getQtyReturned() != null ? detail.getQtyReturned() : BigDecimal.ZERO; |
|
|
|
case "INVSCRAP": |
|
|
|
case "SCPCREDIT": |
|
|
|
// 报废数量 |
|
|
|
return detail.getQtyScrapt()!= null ? detail.getQtyScrapt() : BigDecimal.ZERO; |
|
|
|
case "EXCHANGE": |
|
|
|
case "REWORK": |
|
|
|
// 换货/返工数量 - 可能需要根据实际字段调整 |
|
|
|
return detail.getQtyReplace() != null ? detail.getQtyReplace() : BigDecimal.ZERO; |
|
|
|
default: |
|
|
|
return BigDecimal.ZERO; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 根据状态映射处理类型 |
|
|
|
*/ |
|
|
|
private String mapStatusToProcessType(String status) { |
|
|
|
if (status == null) { |
|
|
|
return "UNKNOWN"; |
|
|
|
} |
|
|
|
|
|
|
|
switch (status) { |
|
|
|
case "RETWORK": |
|
|
|
return "RETURN"; // 退货 |
|
|
|
case "INVSCRAP": |
|
|
|
case "SCPCREDIT": |
|
|
|
return "SCRAP"; // 报废 |
|
|
|
case "EXCHANGE": |
|
|
|
case "REWORK": |
|
|
|
case "RETCREDIT": |
|
|
|
return "EXCHANGE"; // 换货 |
|
|
|
default: |
|
|
|
return "UNKNOWN"; |
|
|
|
} |
|
|
|
} |
|
|
|
// 计算HandlingUnit总数量 |
|
|
|
BigDecimal totalScannedQty = handlingUnits.stream() |
|
|
|
.map(hu -> hu.getQty() != null ? hu.getQty() : BigDecimal.ZERO) |
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add); |
|
|
|
|
|
|
|
// 从第一个HandlingUnit获取基本信息 |
|
|
|
HandlingUnit firstHu = handlingUnits.get(0); |
|
|
|
String partNo = firstHu.getPartNo(); |
|
|
|
String batchNo = firstHu.getBatchNo(); |
|
|
|
String locationId = firstHu.getLocationId(); |
|
|
|
String warehouseId = "WH01"; // 默认仓库 |
|
|
|
|
|
|
|
// 2. 创建出库事务头记录 |
|
|
|
TransNoControl transNoControl = transNoControlService.getTransNo(site, "CRR", 10); |
|
|
|
String outboundTransNo = transNoControl.getNewTransNo(); |
|
|
|
|
|
|
|
TransHeader outboundHeader = new TransHeader(); |
|
|
|
outboundHeader.setSite(site); |
|
|
|
outboundHeader.setTransNo(outboundTransNo); |
|
|
|
outboundHeader.setTransDate(new Date()); |
|
|
|
outboundHeader.setTransTypeDb("CRR"); // 不合格处理出库 |
|
|
|
outboundHeader.setWarehouseId(warehouseId); |
|
|
|
outboundHeader.setUserId(currentUser.getUserId().toString()); |
|
|
|
outboundHeader.setUserName(currentUser.getUserDisplay()); |
|
|
|
outboundHeader.setRemark("不合格处理出库 - " + getProcessTypeDesc(processType) + " - 原单据: " + transNo); |
|
|
|
outboundHeader.setOrderRef1(firstHu.getOrderNo()); // 采购单号 |
|
|
|
outboundHeader.setOrderRef2(transNo); // 原单据号 |
|
|
|
outboundHeader.setOrderRef3(processType); // 处理类型 |
|
|
|
outboundHeader.setStatus("COMPLETED"); |
|
|
|
outboundHeader.setStatusDb("C"); |
|
|
|
outboundHeader.setEnterDate(new Date()); |
|
|
|
outboundHeader.setIfsFlag("N"); |
|
|
|
|
|
|
|
transHeaderService.save(outboundHeader); |
|
|
|
|
|
|
|
// 3. 创建出库事务明细记录 |
|
|
|
TransDetail outboundDetail = new TransDetail(); |
|
|
|
outboundDetail.setSite(site); |
|
|
|
outboundDetail.setTransNo(outboundTransNo); |
|
|
|
outboundDetail.setItemNo(1.0); |
|
|
|
outboundDetail.setPartNo(partNo); |
|
|
|
outboundDetail.setTransQty(totalScannedQty); |
|
|
|
outboundDetail.setBatchNo(batchNo); |
|
|
|
outboundDetail.setLocationId(locationId); |
|
|
|
outboundDetail.setDirection("-"); // 出库方向 |
|
|
|
outboundDetail.setOrderRef1(firstHu.getOrderNo()); // 原单据号 |
|
|
|
outboundDetail.setOrderRef2(transNo); |
|
|
|
outboundDetail.setOrderRef3(processType); |
|
|
|
outboundDetail.setOrderRef4(""); |
|
|
|
outboundDetail.setOrderRef5(""); |
|
|
|
outboundDetail.setRemark("不合格处理出库 - " + getProcessTypeDesc(processType)); |
|
|
|
transDetailService.save(outboundDetail); |
|
|
|
|
|
|
|
// 4. 创建HandlingUnit子记录 |
|
|
|
for (int i = 0; i < handlingUnits.size(); i++) { |
|
|
|
HandlingUnit hu = handlingUnits.get(i); |
|
|
|
TransDetailSub transDetailSub = new TransDetailSub(); |
|
|
|
transDetailSub.setSite(site); |
|
|
|
transDetailSub.setTransNo(outboundTransNo); |
|
|
|
transDetailSub.setItemNo((double) (i + 1)); |
|
|
|
transDetailSub.setSeqNo(1.0); |
|
|
|
transDetailSub.setSubQty(hu.getQty() != null ? hu.getQty().doubleValue() : 0.0); |
|
|
|
transDetailSub.setOrderRef1(transNo); |
|
|
|
transDetailSub.setOrderRef2(processType); |
|
|
|
transDetailSub.setLocationId(locationId); |
|
|
|
transDetailSub.setBatchNo(batchNo); |
|
|
|
transDetailSub.setPartNo(partNo); |
|
|
|
transDetailSub.setSubNo(hu.getUnitId()); |
|
|
|
transDetailSub.setDirection("-"); |
|
|
|
transDetailSub.setRemark("不合格处理出库 - " + getProcessTypeDesc(processType) + " - HU: " + hu.getUnitId()); |
|
|
|
transDetailSubService.save(transDetailSub); |
|
|
|
} |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional |
|
|
|
public void confirmUnqualifiedProcess(String transNo, String processType, List<String> handlingUnitIds) { |
|
|
|
try { |
|
|
|
// 1. 更新HandlingUnit状态为失效 |
|
|
|
if (handlingUnitIds != null && !handlingUnitIds.isEmpty()) { |
|
|
|
// 6. 更新HandlingUnit状态 |
|
|
|
QueryWrapper<HandlingUnit> huWrapper = new QueryWrapper<>(); |
|
|
|
huWrapper.in("unit_id", handlingUnitIds); |
|
|
|
|
|
|
|
@ -599,24 +229,11 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
if (!huResult) { |
|
|
|
throw new RuntimeException("更新HandlingUnit状态失败"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 更新PoReceiptDetail状态为已处理 |
|
|
|
QueryWrapper<PoReceiptDetail> detailWrapper = new QueryWrapper<>(); |
|
|
|
detailWrapper.eq("receipt_no", transNo); |
|
|
|
|
|
|
|
PoReceiptDetail detailUpdate = new PoReceiptDetail(); |
|
|
|
detailUpdate.setStatus("PROCESSED"); // 设置为已处理状态 |
|
|
|
//detailUpdate.setUpdateTime(new Date()); |
|
|
|
|
|
|
|
boolean detailResult = poReceiptDetailService.update(detailUpdate, detailWrapper); |
|
|
|
if (!detailResult) { |
|
|
|
throw new RuntimeException("更新接收单详情状态失败"); |
|
|
|
log.info("不合格处理确认成功 - 出库事务号: {}, 原单据号: {}, 处理类型: {}, HandlingUnit数量: {}, 总数量: {}", |
|
|
|
outboundTransNo, transNo, processType, handlingUnits.size(), totalScannedQty); |
|
|
|
} |
|
|
|
|
|
|
|
log.info("不合格处理确认成功 - 单据号: {}, 处理类型: {}, HandlingUnit数量: {}", |
|
|
|
transNo, processType, handlingUnitIds != null ? handlingUnitIds.size() : 0); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
log.error("确认不合格处理失败 - 单据号: {}, 错误: {}", transNo, e.getMessage(), e); |
|
|
|
throw new RuntimeException("确认不合格处理失败: " + e.getMessage()); |
|
|
|
@ -648,7 +265,8 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
if (unqualifiedQty != null && unqualifiedQty.compareTo(BigDecimal.ZERO) > 0) { |
|
|
|
UnqualifiedInspectionDto dto = new UnqualifiedInspectionDto(); |
|
|
|
dto.setSite(ifsHistory.getContract()); // 使用contract作为site |
|
|
|
dto.setTransNo(ifsHistory.getOrderNo() + "-" + ifsHistory.getReceiptNo()); // 组合单据号 |
|
|
|
dto.setTransNo(ifsHistory.getOrderNo() + "-"+ifsHistory.getLineNo()+ "-"+ifsHistory.getReleaseNo() |
|
|
|
+ "-" + ifsHistory.getReceiptNo()); // 组合单据号 |
|
|
|
dto.setItemNo(ifsHistory.getLineNo()); |
|
|
|
dto.setPartNo(ifsHistory.getSourcePartNo()); |
|
|
|
dto.setPartDesc(ifsHistory.getPartDesc()); |
|
|
|
@ -742,4 +360,25 @@ public class InspectionInboundServiceImpl implements InspectionInboundService { |
|
|
|
|
|
|
|
return remark.toString(); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 获取处理类型描述 |
|
|
|
*/ |
|
|
|
private String getProcessTypeDesc(String processType) { |
|
|
|
if (processType == null) { |
|
|
|
return "未知处理"; |
|
|
|
} |
|
|
|
|
|
|
|
switch (processType.toUpperCase()) { |
|
|
|
case "RETURN": |
|
|
|
return "退货"; |
|
|
|
case "SCRAP": |
|
|
|
return "报废"; |
|
|
|
case "EXCHANGE": |
|
|
|
return "换货"; |
|
|
|
default: |
|
|
|
return "未知处理"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |