diff --git a/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpIssueServiceImpl.java b/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpIssueServiceImpl.java
index 8b2fc686..72cf3985 100644
--- a/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpIssueServiceImpl.java
+++ b/src/main/java/com/xujie/sys/modules/erf/service/impl/ErfExpIssueServiceImpl.java
@@ -38,7 +38,7 @@ import java.util.stream.Collectors;
*
* - 创建领料单复用 newSoIssueNotify 同一套表:SOIssueNotifyHeader / SOIssueNotifyOrderList / SOIssueNotifyOrderMaterialList
* - ERF试验单领料每次单独创建领料单,创建后默认状态=已下达,并写入单据类型标记
- * - ERF领料创建时按原材料逐条落地:1条原材料对应1条SOIssueNotifyOrderList和1条SOIssueNotifyOrderMaterialList
+ * - ERF领料按工序落地:同一试验单的同一工序只建1条SOIssueNotifyOrderList,该工序下每条原材料对应1条SOIssueNotifyOrderMaterialList,并共用同一个ItemNo
*
*
* @author System
@@ -197,19 +197,40 @@ public class ErfExpIssueServiceImpl implements ErfExpIssueService {
String finalUserName = StringUtils.hasText(userName) ? userName : "system";
String notifyNo = createErfNotifyNo(site, finalUserName, data.getRemark(), planIssueDate);
- int createdOrderCount = 0;
- int createdMaterialCount = 0;
+ // 同一试验单的同一工序只建一条工单行。按原材料逐条建会把同一工序拆成多条 SOIssueNotifyOrderList。
+ Map> processGroupMap = new LinkedHashMap<>();
for (ErfExpIssueMaterialData materialItem : validatedMaterialList) {
if (materialItem == null || materialItem.getRawMaterialId() == null) {
continue;
}
- BigDecimal issueQty = safeDecimal(issueQtyMap.get(materialItem.getRawMaterialId()));
+ String groupKey = buildProcessGroupKey(materialItem);
+ List groupList = processGroupMap.get(groupKey);
+ if (groupList == null) {
+ groupList = new ArrayList<>();
+ processGroupMap.put(groupKey, groupList);
+ }
+ groupList.add(materialItem);
+ }
+
+ int createdOrderCount = 0;
+ int createdMaterialCount = 0;
+ for (List processMaterials : processGroupMap.values()) {
+ if (CollectionUtils.isEmpty(processMaterials)) {
+ continue;
+ }
+ ErfExpIssueMaterialData headerMaterial = processMaterials.get(0);
+ // 工单行领取数量是该工序下各原材料本次领料数量的合计,物料行仍各自保存自己的数量。
+ BigDecimal orderIssueQty = resolveProcessIssueQty(processMaterials, issueQtyMap);
- SOIssueNotifyOrderList orderData = buildNotifyOrderList(notifyNo, site, materialItem, issueQty);
+ SOIssueNotifyOrderList orderData = buildNotifyOrderList(notifyNo, site, headerMaterial, orderIssueQty);
Double itemNo = issureNotifyService.saveSOIssueNotifyOrderList(orderData);
- List saveMaterialList =
- buildNotifyMaterialList(notifyNo, site, itemNo, materialItem, issueQty);
+ // saveMaterialDetail 会先按 ItemNo 删掉已有物料再整批插入,必须一次提交该工序的全部物料。
+ List saveMaterialList = new ArrayList<>();
+ for (ErfExpIssueMaterialData materialItem : processMaterials) {
+ BigDecimal issueQty = safeDecimal(issueQtyMap.get(materialItem.getRawMaterialId()));
+ saveMaterialList.addAll(buildNotifyMaterialList(notifyNo, site, itemNo, materialItem, issueQty));
+ }
issureNotifyService.saveMaterialDetail(saveMaterialList);
createdOrderCount++;
@@ -220,7 +241,7 @@ public class ErfExpIssueServiceImpl implements ErfExpIssueService {
throw new XJException("未生成任何领料明细,请检查后重试");
}
- log.info("创建试验单领料单成功(复用SOIssueNotify表): notifyNo={}, 派工单条数={}, 物料条数={}, 操作人ID={}",
+ log.info("创建试验单领料单成功(复用SOIssueNotify表): notifyNo={}, 工序条数={}, 物料条数={}, 操作人ID={}",
notifyNo, createdOrderCount, createdMaterialCount, userId);
return notifyNo;
}
@@ -277,7 +298,37 @@ public class ErfExpIssueServiceImpl implements ErfExpIssueService {
}
/**
- * 组装SOIssueNotifyOrderList(按原材料一条一建)
+ * 同一试验单、同一工序共用一条工单行。
+ * 不同试验单即使工序名称相同也不能合并,工单号和成品料号都按试验单取。
+ * 工序为空时按原材料拆开,避免未维护工序的物料被误合并。
+ */
+ private String buildProcessGroupKey(ErfExpIssueMaterialData materialItem) {
+ String applyNo = materialItem.getApplyNo() == null ? "" : materialItem.getApplyNo().trim();
+ String processStep = materialItem.getProcessStep() == null ? "" : materialItem.getProcessStep().trim();
+ if (!StringUtils.hasText(processStep)) {
+ return applyNo + "||__RM__||" + materialItem.getRawMaterialId();
+ }
+ return applyNo + "||" + processStep;
+ }
+
+ /**
+ * 工单行领取数量等于该工序下原材料本次领料数量之和。
+ * 物料行 QtyToIssue 仍按各自数量写入,不因为合并工单行而改掉单物料数量。
+ */
+ private BigDecimal resolveProcessIssueQty(List processMaterials,
+ Map issueQtyMap) {
+ BigDecimal processIssueQty = BigDecimal.ZERO;
+ for (ErfExpIssueMaterialData materialItem : processMaterials) {
+ if (materialItem == null || materialItem.getRawMaterialId() == null) {
+ continue;
+ }
+ processIssueQty = processIssueQty.add(safeDecimal(issueQtyMap.get(materialItem.getRawMaterialId())));
+ }
+ return processIssueQty;
+ }
+
+ /**
+ * 组装SOIssueNotifyOrderList(按工序一条一建)
*/
private SOIssueNotifyOrderList buildNotifyOrderList(String notifyNo,
String site,
@@ -303,7 +354,7 @@ public class ErfExpIssueServiceImpl implements ErfExpIssueService {
}
/**
- * 组装SOIssueNotifyOrderMaterialList(按原材料一条一建)
+ * 组装SOIssueNotifyOrderMaterialList(同一工序下每条原材料一行,ItemNo 与工单行一致)
*/
private List buildNotifyMaterialList(String notifyNo,
String site,