|
|
|
@ -34,7 +34,9 @@ import java.util.ArrayList; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.Collections; |
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.IdentityHashMap; |
|
|
|
import java.util.LinkedHashMap; |
|
|
|
import java.util.LinkedHashSet; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Set; |
|
|
|
@ -401,7 +403,7 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
|
|
|
|
/** |
|
|
|
* @author rqrq |
|
|
|
* @Description 拉取发货单及行项目:查询用大site,IFS工厂编码(contract)作为subsite来源 - rqrq |
|
|
|
* @Description 拉取发货单及行项目:头查询site按大site+'%'模糊;行查询按头返回的CONTRACT分别调用 - rqrq |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
public List<ShipmentAndShipmentLineVo> haiAnGetShipmentAndLineForIssure(ShipmentIssueDto data) throws Exception { |
|
|
|
@ -411,8 +413,11 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
if (StringUtils.isBlank(data.getOrderNo())) { |
|
|
|
throw new RuntimeException("发货单号不能为空"); |
|
|
|
} |
|
|
|
// 调用IFS发货单头接口,关键参数site+orderNo;失败会导致状态校验与基础信息缺失 - rqrq |
|
|
|
List<ShipmentVo> shipmentRows = ifsApiIssueAndReturnService.getShipment(data.getSite(), data.getOrderNo()); |
|
|
|
String baseSite = stripSiteFuzzySuffix(data.getSite()); |
|
|
|
String fuzzySite = baseSite + "%"; |
|
|
|
|
|
|
|
// 调用IFS发货单头接口:site使用模糊条件(大site+'%');失败会导致状态校验与基础信息缺失 - rqrq |
|
|
|
List<ShipmentVo> shipmentRows = ifsApiIssueAndReturnService.getShipment(fuzzySite, data.getOrderNo()); |
|
|
|
if (shipmentRows == null || shipmentRows.isEmpty()) { |
|
|
|
return new ArrayList<>(); |
|
|
|
} |
|
|
|
@ -424,16 +429,41 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
throw new Exception("SHIPMENT:" + data.getOrderNo() + "状态不允许发货,请检查!"); |
|
|
|
} |
|
|
|
|
|
|
|
// 调用IFS发货单行接口,关键参数site+orderNo;失败会导致发料行为空无法保存 - rqrq |
|
|
|
List<ShipmentLineVo> lineRows = ifsApiIssueAndReturnService.getShipmentLineVo(data.getSite(), data.getOrderNo()); |
|
|
|
if (lineRows == null || lineRows.isEmpty()) { |
|
|
|
// 头可能跨多个CONTRACT,行接口必须按CONTRACT逐个拉取,不能继续用大site - rqrq |
|
|
|
LinkedHashSet<String> contracts = new LinkedHashSet<>(); |
|
|
|
Map<String, ShipmentVo> headerByContract = new LinkedHashMap<>(); |
|
|
|
for (ShipmentVo row : validRows) { |
|
|
|
if (row == null || StringUtils.isBlank(row.getContract())) { |
|
|
|
continue; |
|
|
|
} |
|
|
|
contracts.add(row.getContract()); |
|
|
|
headerByContract.putIfAbsent(row.getContract(), row); |
|
|
|
} |
|
|
|
if (contracts.isEmpty()) { |
|
|
|
contracts.add(baseSite); |
|
|
|
} |
|
|
|
|
|
|
|
List<ShipmentLineVo> lineRows = new ArrayList<>(); |
|
|
|
for (String contract : contracts) { |
|
|
|
// 调用IFS发货单行接口,关键参数CONTRACT+shipmentId;失败会导致该工厂下行项目缺失 - rqrq |
|
|
|
List<ShipmentLineVo> partLines = ifsApiIssueAndReturnService.getShipmentLineVo(contract, data.getOrderNo()); |
|
|
|
if (partLines != null && !partLines.isEmpty()) { |
|
|
|
lineRows.addAll(partLines); |
|
|
|
} |
|
|
|
} |
|
|
|
if (lineRows.isEmpty()) { |
|
|
|
return new ArrayList<>(); |
|
|
|
} |
|
|
|
ShipmentVo header = validRows.get(0); |
|
|
|
|
|
|
|
ShipmentVo defaultHeader = validRows.get(0); |
|
|
|
List<ShipmentAndShipmentLineVo> joinedRows = new ArrayList<>(); |
|
|
|
for (ShipmentLineVo lineRow : lineRows) { |
|
|
|
ShipmentAndShipmentLineVo vo = new ShipmentAndShipmentLineVo(); |
|
|
|
BeanUtils.copyProperties(lineRow, vo); |
|
|
|
String lineContract = StringUtils.isNotBlank(lineRow.getContract()) ? lineRow.getContract() : null; |
|
|
|
ShipmentVo header = lineContract != null && headerByContract.containsKey(lineContract) |
|
|
|
? headerByContract.get(lineContract) |
|
|
|
: defaultHeader; |
|
|
|
vo.setState(header.getState()); |
|
|
|
vo.setNextStepFlow(header.getNextStepFlow()); |
|
|
|
vo.setSourceRefType(header.getSourceRefType()); |
|
|
|
@ -449,7 +479,11 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
vo.setCreatedDate(header.getCreatedDate()); |
|
|
|
vo.setPlannedShipDate(header.getPlannedShipDate()); |
|
|
|
vo.setPlannedDeliveryDate(header.getPlannedDeliveryDate()); |
|
|
|
vo.setSite(data.getSite()); |
|
|
|
// 回传大site给前端主单;工厂编码落在contract供subsite使用 - rqrq |
|
|
|
vo.setSite(baseSite); |
|
|
|
if (StringUtils.isBlank(vo.getContract()) && StringUtils.isNotBlank(lineContract)) { |
|
|
|
vo.setContract(lineContract); |
|
|
|
} |
|
|
|
vo.setPartNo(vo.getInventoryPartNo()); |
|
|
|
joinedRows.add(vo); |
|
|
|
} |
|
|
|
@ -472,8 +506,11 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
throw new RuntimeException("itemNo不能为空,无法定位发料明细"); |
|
|
|
} |
|
|
|
|
|
|
|
// 调用IFS发货单行接口拉取最新行项目,关键参数site+soorderNo;失败会影响明细完整性 - rqrq |
|
|
|
List<ShipmentLineVo> lineRows = ifsApiIssueAndReturnService.getShipmentLineVo(data.getSite(), data.getSoorderNo()); |
|
|
|
// 行接口site优先用父行subsite(CONTRACT);缺失时再回退大site - rqrq |
|
|
|
String lineSite = StringUtils.isNotBlank(data.getSubSite()) ? data.getSubSite() : stripSiteFuzzySuffix(data.getSite()); |
|
|
|
List<ShipmentLineVo> lineRows = ifsApiIssueAndReturnService.getShipmentLineVo(lineSite, data.getSoorderNo()); |
|
|
|
// 与保存前mergeShipmentRows口径一致:同料号先合并,避免明细页比库内多出行 - rqrq |
|
|
|
List<ShipmentLineVo> mergedLineRows = mergeShipmentLineRows(lineRows); |
|
|
|
HaiAnSOIssueNotifyHeaderData query = new HaiAnSOIssueNotifyHeaderData(); |
|
|
|
query.setSite(data.getSite()); |
|
|
|
query.setNotifyNo(data.getNotifyNo()); |
|
|
|
@ -485,36 +522,40 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
.filter(row -> sameItemNo(row.getItemNo(), data.getItemNo())) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
Map<String, HaiAnSOIssueNotifyOrderMaterialListData> savedRowMap = new LinkedHashMap<>(); |
|
|
|
Map<String, HaiAnSOIssueNotifyOrderMaterialListData> savedByPartMap = new LinkedHashMap<>(); |
|
|
|
for (HaiAnSOIssueNotifyOrderMaterialListData savedRow : savedRows) { |
|
|
|
savedRowMap.put(buildMaterialKey(savedRow.getBOMItemNo(), savedRow.getComponentPartNo(), savedRow.getSubSite()), savedRow); |
|
|
|
// 料号兜底索引:兼容BOM_item_no与IFS sourceRef3/shipmentLineNo不一致的历史数据 - rqrq |
|
|
|
if (StringUtils.isNotBlank(savedRow.getComponentPartNo()) && !savedByPartMap.containsKey(savedRow.getComponentPartNo())) { |
|
|
|
savedByPartMap.put(savedRow.getComponentPartNo(), savedRow); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
List<HaiAnSOIssueNotifyOrderMaterialListData> result = new ArrayList<>(); |
|
|
|
Set<String> ifsKeys = new HashSet<>(); |
|
|
|
if (lineRows != null) { |
|
|
|
for (ShipmentLineVo lineRow : lineRows) { |
|
|
|
HaiAnSOIssueNotifyOrderMaterialListData row = new HaiAnSOIssueNotifyOrderMaterialListData(); |
|
|
|
row.setSite(data.getSite()); |
|
|
|
row.setNotifyNo(data.getNotifyNo()); |
|
|
|
row.setItemNo(data.getItemNo()); |
|
|
|
row.setBOMItemNo(resolveShipmentBomItemNo(lineRow)); |
|
|
|
row.setComponentPartNo(lineRow.getInventoryPartNo()); |
|
|
|
row.setComponentPartDesc(lineRow.getSourcePartDescription()); |
|
|
|
row.setQtyRequired(lineRow.getInventoryQty()); |
|
|
|
row.setQtyOnHand(lineRow.getInventoryQty() == null ? null : lineRow.getInventoryQty().doubleValue()); |
|
|
|
row.setIssueType("BOM物料"); |
|
|
|
row.setOrderType("shipment"); |
|
|
|
row.setSubSite(StringUtils.isNotBlank(lineRow.getContract()) ? lineRow.getContract() : data.getSubSite()); |
|
|
|
String key = buildMaterialKey(row.getBOMItemNo(), row.getComponentPartNo(), row.getSubSite()); |
|
|
|
ifsKeys.add(key); |
|
|
|
fillSavedMaterialFields(row, savedRowMap.get(key)); |
|
|
|
result.add(row); |
|
|
|
Set<HaiAnSOIssueNotifyOrderMaterialListData> matchedSavedRows = Collections.newSetFromMap(new IdentityHashMap<>()); |
|
|
|
for (ShipmentLineVo lineRow : mergedLineRows) { |
|
|
|
HaiAnSOIssueNotifyOrderMaterialListData row = new HaiAnSOIssueNotifyOrderMaterialListData(); |
|
|
|
row.setSite(data.getSite()); |
|
|
|
row.setNotifyNo(data.getNotifyNo()); |
|
|
|
row.setItemNo(data.getItemNo()); |
|
|
|
row.setBOMItemNo(resolveShipmentBomItemNo(lineRow)); |
|
|
|
row.setComponentPartNo(lineRow.getInventoryPartNo()); |
|
|
|
row.setComponentPartDesc(lineRow.getSourcePartDescription()); |
|
|
|
row.setQtyRequired(lineRow.getInventoryQty()); |
|
|
|
row.setQtyOnHand(lineRow.getInventoryQty() == null ? null : lineRow.getInventoryQty().doubleValue()); |
|
|
|
row.setIssueType("BOM物料"); |
|
|
|
row.setOrderType("shipment"); |
|
|
|
row.setSubSite(StringUtils.isNotBlank(lineRow.getContract()) ? lineRow.getContract() : data.getSubSite()); |
|
|
|
HaiAnSOIssueNotifyOrderMaterialListData saved = findSavedShipmentMaterial(savedRowMap, savedByPartMap, lineRow, row); |
|
|
|
if (saved != null) { |
|
|
|
matchedSavedRows.add(saved); |
|
|
|
fillSavedMaterialFields(row, saved); |
|
|
|
} |
|
|
|
result.add(row); |
|
|
|
} |
|
|
|
|
|
|
|
for (HaiAnSOIssueNotifyOrderMaterialListData savedRow : savedRows) { |
|
|
|
String key = buildMaterialKey(savedRow.getBOMItemNo(), savedRow.getComponentPartNo(), savedRow.getSubSite()); |
|
|
|
if (!ifsKeys.contains(key)) { |
|
|
|
if (!matchedSavedRows.contains(savedRow)) { |
|
|
|
result.add(savedRow); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -527,7 +568,8 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
} |
|
|
|
Map<String, ShipmentAndShipmentLineVo> mergedMap = new LinkedHashMap<>(); |
|
|
|
for (ShipmentAndShipmentLineVo row : rows) { |
|
|
|
String key = defaultString(row.getShipmentId()) + "|" + defaultString(row.getSourcePartNo()); |
|
|
|
// 合并键加入contract,避免跨工厂同料号被错误汇总 - rqrq |
|
|
|
String key = defaultString(row.getShipmentId()) + "|" + defaultString(row.getContract()) + "|" + defaultString(row.getSourcePartNo()); |
|
|
|
if (!mergedMap.containsKey(key)) { |
|
|
|
mergedMap.put(key, copyShipmentRow(row)); |
|
|
|
continue; |
|
|
|
@ -571,20 +613,94 @@ public class HaiAnNewIssureServiceImpl implements HaiAnNewIssureService { |
|
|
|
return left.compareTo(right) == 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @author rqrq |
|
|
|
* @Description 发料明细BOM行号与保存链路对齐:优先shipmentLineNo(前端lineItemNo来源),再回退sourceRef3 - rqrq |
|
|
|
*/ |
|
|
|
private String resolveShipmentBomItemNo(ShipmentLineVo lineRow) { |
|
|
|
if (lineRow == null) { |
|
|
|
return ""; |
|
|
|
} |
|
|
|
if (lineRow.getShipmentLineNo() != null) { |
|
|
|
return String.valueOf(lineRow.getShipmentLineNo()); |
|
|
|
} |
|
|
|
if (StringUtils.isNotBlank(lineRow.getSourceRef3())) { |
|
|
|
return lineRow.getSourceRef3(); |
|
|
|
} |
|
|
|
return lineRow.getShipmentLineNo() == null ? "" : String.valueOf(lineRow.getShipmentLineNo()); |
|
|
|
return ""; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @author rqrq |
|
|
|
* @Description 按库存料号合并IFS发货行,保持与保存前mergeShipmentRows一致,避免同料多行撑开明细 - rqrq |
|
|
|
*/ |
|
|
|
private List<ShipmentLineVo> mergeShipmentLineRows(List<ShipmentLineVo> rows) { |
|
|
|
if (rows == null || rows.isEmpty()) { |
|
|
|
return new ArrayList<>(); |
|
|
|
} |
|
|
|
Map<String, ShipmentLineVo> mergedMap = new LinkedHashMap<>(); |
|
|
|
for (ShipmentLineVo row : rows) { |
|
|
|
// 合并键加入contract,避免跨工厂同料号被错误汇总 - rqrq |
|
|
|
String key = defaultString(row.getShipmentId()) + "|" + defaultString(row.getContract()) + "|" + defaultString(row.getInventoryPartNo()); |
|
|
|
if (!mergedMap.containsKey(key)) { |
|
|
|
ShipmentLineVo copied = new ShipmentLineVo(); |
|
|
|
BeanUtils.copyProperties(row, copied); |
|
|
|
mergedMap.put(key, copied); |
|
|
|
continue; |
|
|
|
} |
|
|
|
ShipmentLineVo merged = mergedMap.get(key); |
|
|
|
merged.setInventoryQty(addBigDecimal(merged.getInventoryQty(), row.getInventoryQty())); |
|
|
|
merged.setQtyAssigned(addBigDecimal(merged.getQtyAssigned(), row.getQtyAssigned())); |
|
|
|
} |
|
|
|
return new ArrayList<>(mergedMap.values()); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @author rqrq |
|
|
|
* @Description 查找已保存发料行:先按BOM+料号+subsite精确匹配,再试sourceRef3键,最后按料号兜底 - rqrq |
|
|
|
*/ |
|
|
|
private HaiAnSOIssueNotifyOrderMaterialListData findSavedShipmentMaterial( |
|
|
|
Map<String, HaiAnSOIssueNotifyOrderMaterialListData> savedRowMap, |
|
|
|
Map<String, HaiAnSOIssueNotifyOrderMaterialListData> savedByPartMap, |
|
|
|
ShipmentLineVo lineRow, |
|
|
|
HaiAnSOIssueNotifyOrderMaterialListData ifsRow) { |
|
|
|
String primaryKey = buildMaterialKey(ifsRow.getBOMItemNo(), ifsRow.getComponentPartNo(), ifsRow.getSubSite()); |
|
|
|
HaiAnSOIssueNotifyOrderMaterialListData saved = savedRowMap.get(primaryKey); |
|
|
|
if (saved != null) { |
|
|
|
return saved; |
|
|
|
} |
|
|
|
if (lineRow != null && StringUtils.isNotBlank(lineRow.getSourceRef3())) { |
|
|
|
String sourceRefKey = buildMaterialKey(lineRow.getSourceRef3(), ifsRow.getComponentPartNo(), ifsRow.getSubSite()); |
|
|
|
saved = savedRowMap.get(sourceRefKey); |
|
|
|
if (saved != null) { |
|
|
|
return saved; |
|
|
|
} |
|
|
|
} |
|
|
|
if (StringUtils.isNotBlank(ifsRow.getComponentPartNo())) { |
|
|
|
return savedByPartMap.get(ifsRow.getComponentPartNo()); |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
private String buildMaterialKey(String bomItemNo, String componentPartNo, String subSite) { |
|
|
|
return defaultString(bomItemNo) + "|" + defaultString(componentPartNo) + "|" + defaultString(subSite); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @author rqrq |
|
|
|
* @Description 去掉site模糊后缀'%',保证回写主单site与IFS CONTRACT调用参数干净 - rqrq |
|
|
|
*/ |
|
|
|
private String stripSiteFuzzySuffix(String site) { |
|
|
|
if (StringUtils.isBlank(site)) { |
|
|
|
return site; |
|
|
|
} |
|
|
|
String trimmed = site.trim(); |
|
|
|
while (trimmed.endsWith("%")) { |
|
|
|
trimmed = trimmed.substring(0, trimmed.length() - 1); |
|
|
|
} |
|
|
|
return trimmed; |
|
|
|
} |
|
|
|
|
|
|
|
private String defaultString(String value) { |
|
|
|
return value == null ? "" : value; |
|
|
|
} |
|
|
|
|