修改比对规则

This commit is contained in:
wuweihua
2026-10-21 11:01:59 +08:00
parent 36837f94bf
commit 8f1cf5c755
5 changed files with 384 additions and 105 deletions
@@ -3,6 +3,7 @@ package com.bms.price.service;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
@@ -17,16 +18,17 @@ import org.springframework.stereotype.Service;
import com.bms.common.annotation.DataScope;
import com.bms.common.exception.ServiceException;
import com.bms.common.utils.StringUtils;
import com.bms.price.domain.BmsProduct;
import com.bms.price.domain.PrcOrderBill;
import com.bms.price.domain.PrcPriceSetProduct;
import com.bms.price.domain.vo.OrderBillProductCheckResult;
import com.bms.price.domain.vo.OrderBillProductCheckResult.ProductRow;
import com.bms.price.mapper.BmsProductMapper;
import com.bms.price.domain.vo.OrderBillProductCheckResult.OrderProductRow;
import com.bms.price.domain.vo.OrderBillProductCheckResult.PackageProductRow;
import com.bms.price.mapper.PrcOrderBillMapper;
import com.bms.system.service.IBmsProductCodeMappingService;
/**
* Detect package sales products (as of billing end time) that are missing from product catalog.
* Compare local order-bill product codes against customer bound package SALES products.
* Also accepts product_code_mapping (upstream -> BMS).
*/
@Service
public class OrderBillProductCheckService
@@ -37,7 +39,7 @@ public class OrderBillProductCheckService
private ITmsPriceQuoteService tmsPriceQuoteService;
@Autowired
private BmsProductMapper productMapper;
private IBmsProductCodeMappingService productCodeMappingService;
@Autowired
private PrcOrderBillMapper orderBillMapper;
@@ -51,74 +53,125 @@ public class OrderBillProductCheckService
OrderBillProductCheckResult result = new OrderBillProductCheckResult();
result.setAsOfTime(formatAsOf(asOf));
List<String> customerCodes = normalizeCodes(query.getCustomerCodes());
Map<String, Integer> orderCountByKey = loadOrderCounts(query);
long orderTotal = 0L;
for (Integer c : orderCountByKey.values())
List<Map<String, Object>> groups = orderBillMapper.selectDistinctProductGroups(query);
if (groups == null || groups.isEmpty())
{
if (c != null)
{
orderTotal += c.intValue();
}
result.setOrderTotal(0L);
return result;
}
result.setOrderTotal(orderTotal);
List<ProductRow> packageRows = new ArrayList<ProductRow>();
List<ProductRow> missingRows = new ArrayList<ProductRow>();
int matched = 0;
for (String customerCode : customerCodes)
long orderTotal = 0L;
Set<String> customerCodes = new HashSet<String>();
for (Map<String, Object> g : groups)
{
List<PrcPriceSetProduct> products = tmsPriceQuoteService.listAllBoundPackageProducts(customerCode, asOf);
Set<String> seen = new HashSet<String>();
if (products == null)
String customerCode = trim(str(g, "customer_code"));
String productCode = trim(str(g, "product_code"));
if (StringUtils.isEmpty(customerCode) || StringUtils.isEmpty(productCode))
{
continue;
}
for (PrcPriceSetProduct p : products)
customerCodes.add(customerCode);
orderTotal += longValue(g, "order_count");
}
Map<String, Set<String>> packageCodeByCustomer = new HashMap<String, Set<String>>();
List<PackageProductRow> packageRows = new ArrayList<PackageProductRow>();
for (String customerCode : customerCodes)
{
List<PrcPriceSetProduct> products = tmsPriceQuoteService.listAllBoundPackageProducts(customerCode, asOf);
Set<String> codes = new HashSet<String>();
if (products != null)
{
if (p == null || StringUtils.isEmpty(p.getProductCode()))
for (PrcPriceSetProduct p : products)
{
continue;
}
String code = p.getProductCode().trim();
String upper = code.toUpperCase(Locale.ROOT);
if (!seen.add(upper))
{
continue;
}
boolean inLibrary = existsInLibrary(code, asOf);
ProductRow row = new ProductRow();
row.setCustomerCode(customerCode);
row.setProductCode(code);
row.setProductName(trim(p.getProductName()));
row.setInLibrary(inLibrary);
Integer oc = orderCountByKey.get(key(customerCode, upper));
row.setOrderCount(oc == null ? 0 : oc.intValue());
packageRows.add(row);
if (inLibrary)
{
matched++;
}
else
{
missingRows.add(row);
if (p == null || StringUtils.isEmpty(p.getProductCode()))
{
continue;
}
if (!isSalesProduct(p))
{
continue;
}
String code = p.getProductCode().trim();
String upper = code.toUpperCase(Locale.ROOT);
if (!codes.add(upper))
{
continue;
}
PackageProductRow pr = new PackageProductRow();
pr.setCustomerCode(customerCode);
pr.setProductCode(code);
pr.setProductName(trim(p.getProductName()));
packageRows.add(pr);
}
}
packageCodeByCustomer.put(customerCode, codes);
}
packageRows.sort(Comparator
.comparing(PackageProductRow::getCustomerCode, nullSafe())
.thenComparing(PackageProductRow::getProductCode, nullSafe()));
List<OrderProductRow> orderProducts = new ArrayList<OrderProductRow>();
List<OrderProductRow> missingProducts = new ArrayList<OrderProductRow>();
int matched = 0;
for (Map<String, Object> g : groups)
{
String customerCode = trim(str(g, "customer_code"));
String productCode = trim(str(g, "product_code"));
if (StringUtils.isEmpty(customerCode) || StringUtils.isEmpty(productCode))
{
continue;
}
Set<String> pkg = packageCodeByCustomer.get(customerCode);
if (pkg == null)
{
pkg = Collections.emptySet();
}
boolean inPackage = pkg.contains(productCode.toUpperCase(Locale.ROOT));
String mappedCode = resolveMappedIfDifferent(productCode);
boolean mappedInPackage = false;
if (StringUtils.isNotEmpty(mappedCode))
{
mappedInPackage = pkg.contains(mappedCode.toUpperCase(Locale.ROOT));
}
boolean covered = inPackage || mappedInPackage;
OrderProductRow row = new OrderProductRow();
row.setCustomerCode(customerCode);
row.setUpstreamCode(productCode);
row.setProductName(trim(str(g, "product_name")));
row.setMappedCode(mappedCode);
row.setInPackage(inPackage);
row.setMappedInPackage(mappedInPackage);
row.setCovered(covered);
row.setOrderCount((int) Math.min(Integer.MAX_VALUE, longValue(g, "order_count")));
orderProducts.add(row);
if (covered)
{
matched++;
}
else
{
missingProducts.add(row);
}
}
packageRows.sort(Comparator
.comparing(ProductRow::getCustomerCode, nullSafe())
.thenComparing(ProductRow::getProductCode, nullSafe()));
missingRows.sort(Comparator
.comparing(ProductRow::getCustomerCode, nullSafe())
.thenComparing(ProductRow::getProductCode, nullSafe()));
orderProducts.sort(Comparator
.comparing(OrderProductRow::isCovered)
.thenComparing(OrderProductRow::getCustomerCode, nullSafe())
.thenComparing(OrderProductRow::getUpstreamCode, nullSafe()));
missingProducts.sort(Comparator
.comparing(OrderProductRow::getCustomerCode, nullSafe())
.thenComparing(OrderProductRow::getUpstreamCode, nullSafe()));
result.setOrderTotal(orderTotal);
result.setDistinctOrderProducts(orderProducts.size());
result.setPackageProductCount(packageRows.size());
result.setMatchedCount(matched);
result.setMissingCount(missingRows.size());
result.setMissingCount(missingProducts.size());
result.setPackageProducts(packageRows);
result.setMissingProducts(missingRows);
result.setOrderProducts(orderProducts);
result.setMissingProducts(missingProducts);
return result;
}
@@ -136,32 +189,28 @@ public class OrderBillProductCheckService
return rows == null ? new ArrayList<PrcOrderBill>() : rows;
}
private Map<String, Integer> loadOrderCounts(PrcOrderBill query)
private String resolveMappedIfDifferent(String upstreamCode)
{
List<Map<String, Object>> groups = orderBillMapper.selectDistinctProductGroups(query);
Map<String, Integer> map = new HashMap<String, Integer>();
if (groups == null)
if (productCodeMappingService == null || StringUtils.isEmpty(upstreamCode))
{
return map;
return null;
}
for (Map<String, Object> g : groups)
String mapped = productCodeMappingService.resolveBmsProductCode(upstreamCode);
if (StringUtils.isEmpty(mapped) || mapped.equalsIgnoreCase(upstreamCode.trim()))
{
String customerCode = trim(str(g, "customer_code"));
String productCode = trim(str(g, "product_code"));
if (StringUtils.isEmpty(customerCode) || StringUtils.isEmpty(productCode))
{
continue;
}
map.put(key(customerCode, productCode.toUpperCase(Locale.ROOT)),
Integer.valueOf((int) Math.min(Integer.MAX_VALUE, longValue(g, "order_count"))));
return null;
}
return map;
return mapped.trim();
}
private boolean existsInLibrary(String productCode, Date asOf)
private static boolean isSalesProduct(PrcPriceSetProduct p)
{
BmsProduct hit = productMapper.selectEffectiveBmsProductByCode(productCode, asOf);
return hit != null && StringUtils.isNotEmpty(hit.getProductCode());
if (p == null)
{
return false;
}
String type = p.getPriceType();
return StringUtils.isEmpty(type) || "SALES".equalsIgnoreCase(type.trim());
}
private void validate(PrcOrderBill query)
@@ -248,11 +297,6 @@ public class OrderBillProductCheckService
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(asOf);
}
private static String key(String customerCode, String productUpper)
{
return customerCode + "|" + productUpper;
}
private static String trim(String s)
{
return StringUtils.isEmpty(s) ? null : s.trim();
@@ -359,6 +359,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
}
PrcPriceSetProduct q = new PrcPriceSetProduct();
q.setPsvId(psvId);
q.setPriceType("SALES");
List<PrcPriceSetProduct> rows = setProductMapper.selectPrcPriceSetProductList(q);
if (rows == null || rows.isEmpty())
{