Merge pull request 'demand: 定时扫描漏组批次逻辑调整' (#76) from develop into master

Reviewed-on: http://git.xdadan.loc/tanex/emis-service/pulls/76
This commit is contained in:
heyu 2025-06-26 19:54:14 +08:00
commit 5b64bc0a9d
2 changed files with 86 additions and 67 deletions

View File

@ -4773,31 +4773,80 @@ public class EmisBaseService {
return hasCurrentLevelMatch && hasNextLevelMatch;
}
private void setMissRecords(List<EmisTmsSiteBatchMiss> missRecords, EmisTransPlanRule rule,
private void setMissRecords(List<EmisTmsSiteBatchMiss> missRecords,
EmisTransPlanRule rule,
List<EmisTransPlanRule> filterRules, EmisWaybill waybill) {
// 检查当前节点是否在filterRules中
boolean isMatched = filterRules.stream()
.anyMatch(filterRule -> filterRule.getStartSiteCode().equals(rule.getStartSiteCode()) &&
filterRule.getNextSiteCode().equals(rule.getNextSiteCode()) &&
compareSupplierCodes(filterRule.getSupplierCode(), rule.getSupplierCode()));
// 1. 递归收集所有节点,按ancestors长度分组
Map<Integer, List<EmisTransPlanRule>> levelMap = new HashMap<>();
collectByLevel(rule, levelMap);
if (!isMatched) {
// 创建漏组记录
EmisTmsSiteBatchMiss miss = createMissRecord(waybill);
miss.setMissReason(String.format("组批次有遗漏/错误,请根据推荐路线排查: %s-%s-%s",
rule.getStartSiteName(),
rule.getNextSiteName(),
rule.getSupplierName()));
setRule(rule, miss);
missRecords.add(miss);
// 2. 逐级处理
for (Map.Entry<Integer, List<EmisTransPlanRule>> entry : levelMap.entrySet())
{
List<EmisTransPlanRule> levelRules = entry.getValue();
boolean matched = false;
for (EmisTransPlanRule levelRule : levelRules) {
boolean isMatched = filterRules.stream()
.anyMatch(filterRule ->
filterRule.getStartSiteCode().equals(levelRule.getStartSiteCode()) &&
filterRule.getNextSiteCode().equals(levelRule.getNextSiteCode()) &&
compareSupplierCodes(filterRule.getSupplierCode(),
levelRule.getSupplierCode()));
if (isMatched) {
matched = true;
break;
}
}
if (!matched) {
// 该级无匹配,只生成一条漏组记录,字段用逗号拼接
String startSiteCodes =
levelRules.stream().map(EmisTransPlanRule::getStartSiteCode).distinct()
.collect(Collectors.joining(","));
String nextSiteCodes =
levelRules.stream().map(EmisTransPlanRule::getNextSiteCode).distinct()
.collect(Collectors.joining(","));
String supplierCodes =
levelRules.stream().map(EmisTransPlanRule::getSupplierCode).distinct()
.collect(Collectors.joining(","));
String managers =
levelRules.stream().map(EmisTransPlanRule::getManager).filter(Objects::nonNull)
.distinct().collect(Collectors.joining(","));
String missReason = levelRules.stream()
.map(r -> String.format("%s-%s-%s", r.getStartSiteName(),
r.getNextSiteName(), r.getSupplierName()))
.distinct()
.collect(Collectors.joining(" 或 "));
EmisTmsSiteBatchMiss miss = createMissRecord(waybill);
miss.setMissReason("组批次有遗漏/错误,请根据推荐路线排查: " + missReason);
miss.setStartSiteCode(startSiteCodes);
miss.setNextSiteCode(nextSiteCodes);
miss.setSupplierCode(supplierCodes);
miss.setManager(managers);
// 其他字段取第一个节点
EmisTransPlanRule first = levelRules.get(0);
miss.setTransPlanRuleId(first.getId());
miss.setLineCode(first.getLineCode());
miss.setProductType(first.getProductType());
miss.setStartDate(first.getStartDate());
miss.setEndDate(first.getEndDate());
miss.setMissType("0");
missRecords.add(miss);
}
}
}
List<EmisTransPlanRule> childrens = rule.getChildren();
if (CollectionUtil.isEmpty(childrens)) {
return;
// 辅助方法:递归收集所有节点,按ancestors长度分组
private void collectByLevel(EmisTransPlanRule node, Map<Integer, List<EmisTransPlanRule>> levelMap) {
int level = 0;
if (node.getAncestors() != null && !node.getAncestors().isEmpty()) {
level = node.getAncestors().split(",").length;
}
levelMap.computeIfAbsent(level, k -> new ArrayList<>()).add(node);
if (node.getChildren() != null && !node.getChildren().isEmpty()) {
for (EmisTransPlanRule child : node.getChildren()) {
collectByLevel(child, levelMap);
}
}
// 递归处理子节点
checkChildrens(missRecords, childrens, filterRules, waybill);
}
private static void setRule(EmisTransPlanRule rule, EmisTmsSiteBatchMiss miss) {
@ -4813,47 +4862,6 @@ public class EmisBaseService {
miss.setMissType("0");
}
private void checkChildrens(List<EmisTmsSiteBatchMiss> missRecords, List<EmisTransPlanRule> childrens,
List<EmisTransPlanRule> filterRules, EmisWaybill waybill) {
// 检查子节点是否至少有一个匹配
boolean hasMatchedChild = childrens.stream()
.anyMatch(childRule -> filterRules.stream()
.anyMatch(
filterRule -> filterRule.getStartSiteCode().equals(childRule.getStartSiteCode()) &&
filterRule.getNextSiteCode().equals(childRule.getNextSiteCode()) &&
compareSupplierCodes(filterRule.getSupplierCode(),
childRule.getSupplierCode())));
if (!hasMatchedChild) {
// 如果所有子节点都不匹配,为每个子节点创建漏组记录
StringBuilder missReason = new StringBuilder("组批次有遗漏/错误,请根据推荐路线排查: ");
for (int i = 0; i < childrens.size(); i++) {
EmisTransPlanRule childRule = childrens.get(i);
if (i > 0) {
missReason.append(" 或 ");
}
missReason.append(String.format("%s-%s-%s",
childRule.getStartSiteName(),
childRule.getNextSiteName(),
childRule.getSupplierName()));
}
// 创建漏组记录
EmisTmsSiteBatchMiss miss = createMissRecord(waybill);
miss.setMissReason(missReason.toString());
setRule(childrens.get(0), miss);
missRecords.add(miss);
}
// 递归处理所有子节点
for (EmisTransPlanRule child : childrens) {
List<EmisTransPlanRule> childList = child.getChildren();
if (!CollectionUtil.isEmpty(childList)) {
checkChildrens(missRecords, childList, filterRules, waybill);
}
}
}
public void handleVirtual(EmisWaybill emisWaybillSave,EmisWaybill emisWaybillOld) throws EmisBizError {
if (!"1".equals(emisWaybillSave.getBlVirtual())) {
return;

View File

@ -50,12 +50,19 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
select
m.id, m.bill_code, m.miss_reason, m.create_by, m.create_time, m.update_by, m.update_time, m.remark, m.del_flag,
m.line_code, m.product_type, m.start_site_code, m.next_site_code, m.supplier_code, m.start_date, m.end_date,m.miss_type,
w.send_site_code, s1.site_name as send_site_name,s2.site_name as start_site_name,s3.site_name as next_site_name, w.send_country, c1.name as send_country_name, w.destination_code, n.dest_name as destination_name,w.bl_is_question,
w.send_site_code, s1.site_name as send_site_name,
w.send_country, c1.name as send_country_name, w.destination_code, n.dest_name as destination_name,w.bl_is_question,
l.line_name as line_name,
w.receive_country, c2.name as receive_country_name, w.send_date, w.bl_sign, w.sign_date,
w.product_type,
w.payment_type, w.parcel_qty, w.bill_weight, w.total_volume, w.volume_weight,
w.settlement_weight, w.freight, w.remark as waybill_remark, w.fee_remark, m.manager, k.trans_manager,
(SELECT GROUP_CONCAT(s.name ORDER BY FIND_IN_SET(s.site_code, m.start_site_code))
FROM emis_site s
WHERE FIND_IN_SET(s.site_code, m.start_site_code) AND s.del_flag = 0) as start_site_name,
(SELECT GROUP_CONCAT(s.name ORDER BY FIND_IN_SET(s.site_code, m.next_site_code))
FROM emis_site s
WHERE FIND_IN_SET(s.site_code, m.next_site_code) AND s.del_flag = 0) as next_site_name,
(SELECT GROUP_CONCAT(s.name)
FROM emis_supplier s
WHERE FIND_IN_SET(s.code, m.supplier_code)
@ -67,8 +74,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from emis_tms_site_batch_miss m
left join emis_waybill w on m.bill_code = w.bill_code and w.del_flag='0'
left join emis_site s1 on w.send_site_code=s1.site_code and s1.del_flag=0
left join emis_site s2 on m.start_site_code=s2.site_code and s2.del_flag=0
left join emis_site s3 on m.next_site_code=s3.site_code and s3.del_flag=0
left join emis_country c1 on w.send_country=c1.code and c1.del_flag='0'
left join emis_country c2 on w.receive_country=c2.code and c2.del_flag='0'
left join emis_destination n on w.destination_code=n.dest_code and n.del_flag='0'
@ -160,7 +165,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND m.miss_reason like concat('%', #{missReason}, '%')
</if>
<if test="manager != null and manager != ''">
AND r.manager like concat('%', #{manager}, '%')
AND (
m.manager REGEXP REPLACE(#{manager}, ',', '|')
)
</if>
<if test="transManager != null and transManager != ''">
AND k.trans_manager like concat('%', #{transManager}, '%')
@ -175,10 +182,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
AND FIND_IN_SET(#{productType}, m.product_type)
</if>
<if test="startSiteCode != null and startSiteCode != ''">
AND m.start_site_code = #{startSiteCode}
AND (
m.start_site_code REGEXP REPLACE(#{startSiteCode}, ',', '|')
)
</if>
<if test="nextSiteCode != null and nextSiteCode != ''">
AND m.next_site_code = #{nextSiteCode}
AND (
m.next_site_code REGEXP REPLACE(#{nextSiteCode}, ',', '|')
)
</if>
<if test="supplierCode != null and supplierCode != ''">
AND FIND_IN_SET(#{supplierCode}, m.supplier_code)