修改比对规则
This commit is contained in:
+2
-1
@@ -180,7 +180,8 @@ public class BillingController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect package sales products (as of billing end time) missing from product catalog.
|
||||
* Compare local order-bill products vs customer bound package SALES products
|
||||
* (includes product_code_mapping).
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('price:orderBill:list')")
|
||||
@PostMapping("/orderBill/checkProducts")
|
||||
|
||||
+219
-11
@@ -3,35 +3,243 @@ package com.bms.price.domain.vo;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Order-bill product check: customer package (sales) products vs product catalog.
|
||||
* Local order-bill products vs customer bound package (SALES) comparison.
|
||||
* Matching also accepts product_code_mapping (upstream -> BMS).
|
||||
*/
|
||||
@Data
|
||||
public class OrderBillProductCheckResult implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/** Orders matched by search filters (customer + billing time). */
|
||||
private long orderTotal;
|
||||
private int distinctOrderProducts;
|
||||
private int packageProductCount;
|
||||
private int matchedCount;
|
||||
private int missingCount;
|
||||
private String asOfTime;
|
||||
private List<ProductRow> packageProducts = new ArrayList<ProductRow>();
|
||||
private List<ProductRow> missingProducts = new ArrayList<ProductRow>();
|
||||
private List<PackageProductRow> packageProducts = new ArrayList<PackageProductRow>();
|
||||
private List<OrderProductRow> orderProducts = new ArrayList<OrderProductRow>();
|
||||
private List<OrderProductRow> missingProducts = new ArrayList<OrderProductRow>();
|
||||
|
||||
@Data
|
||||
public static class ProductRow implements Serializable
|
||||
public long getOrderTotal()
|
||||
{
|
||||
return orderTotal;
|
||||
}
|
||||
|
||||
public void setOrderTotal(long orderTotal)
|
||||
{
|
||||
this.orderTotal = orderTotal;
|
||||
}
|
||||
|
||||
public int getDistinctOrderProducts()
|
||||
{
|
||||
return distinctOrderProducts;
|
||||
}
|
||||
|
||||
public void setDistinctOrderProducts(int distinctOrderProducts)
|
||||
{
|
||||
this.distinctOrderProducts = distinctOrderProducts;
|
||||
}
|
||||
|
||||
public int getPackageProductCount()
|
||||
{
|
||||
return packageProductCount;
|
||||
}
|
||||
|
||||
public void setPackageProductCount(int packageProductCount)
|
||||
{
|
||||
this.packageProductCount = packageProductCount;
|
||||
}
|
||||
|
||||
public int getMatchedCount()
|
||||
{
|
||||
return matchedCount;
|
||||
}
|
||||
|
||||
public void setMatchedCount(int matchedCount)
|
||||
{
|
||||
this.matchedCount = matchedCount;
|
||||
}
|
||||
|
||||
public int getMissingCount()
|
||||
{
|
||||
return missingCount;
|
||||
}
|
||||
|
||||
public void setMissingCount(int missingCount)
|
||||
{
|
||||
this.missingCount = missingCount;
|
||||
}
|
||||
|
||||
public String getAsOfTime()
|
||||
{
|
||||
return asOfTime;
|
||||
}
|
||||
|
||||
public void setAsOfTime(String asOfTime)
|
||||
{
|
||||
this.asOfTime = asOfTime;
|
||||
}
|
||||
|
||||
public List<PackageProductRow> getPackageProducts()
|
||||
{
|
||||
return packageProducts;
|
||||
}
|
||||
|
||||
public void setPackageProducts(List<PackageProductRow> packageProducts)
|
||||
{
|
||||
this.packageProducts = packageProducts;
|
||||
}
|
||||
|
||||
public List<OrderProductRow> getOrderProducts()
|
||||
{
|
||||
return orderProducts;
|
||||
}
|
||||
|
||||
public void setOrderProducts(List<OrderProductRow> orderProducts)
|
||||
{
|
||||
this.orderProducts = orderProducts;
|
||||
}
|
||||
|
||||
public List<OrderProductRow> getMissingProducts()
|
||||
{
|
||||
return missingProducts;
|
||||
}
|
||||
|
||||
public void setMissingProducts(List<OrderProductRow> missingProducts)
|
||||
{
|
||||
this.missingProducts = missingProducts;
|
||||
}
|
||||
|
||||
public static class PackageProductRow implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String customerCode;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
/** Whether product exists in catalog (effective at asOf). */
|
||||
private boolean inLibrary;
|
||||
/** Order count in search billing window for this product. */
|
||||
|
||||
public String getCustomerCode()
|
||||
{
|
||||
return customerCode;
|
||||
}
|
||||
|
||||
public void setCustomerCode(String customerCode)
|
||||
{
|
||||
this.customerCode = customerCode;
|
||||
}
|
||||
|
||||
public String getProductCode()
|
||||
{
|
||||
return productCode;
|
||||
}
|
||||
|
||||
public void setProductCode(String productCode)
|
||||
{
|
||||
this.productCode = productCode;
|
||||
}
|
||||
|
||||
public String getProductName()
|
||||
{
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName)
|
||||
{
|
||||
this.productName = productName;
|
||||
}
|
||||
}
|
||||
|
||||
public static class OrderProductRow implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String customerCode;
|
||||
private String upstreamCode;
|
||||
private String productName;
|
||||
private String mappedCode;
|
||||
private boolean inPackage;
|
||||
private boolean mappedInPackage;
|
||||
private boolean covered;
|
||||
private int orderCount;
|
||||
|
||||
public String getCustomerCode()
|
||||
{
|
||||
return customerCode;
|
||||
}
|
||||
|
||||
public void setCustomerCode(String customerCode)
|
||||
{
|
||||
this.customerCode = customerCode;
|
||||
}
|
||||
|
||||
public String getUpstreamCode()
|
||||
{
|
||||
return upstreamCode;
|
||||
}
|
||||
|
||||
public void setUpstreamCode(String upstreamCode)
|
||||
{
|
||||
this.upstreamCode = upstreamCode;
|
||||
}
|
||||
|
||||
public String getProductName()
|
||||
{
|
||||
return productName;
|
||||
}
|
||||
|
||||
public void setProductName(String productName)
|
||||
{
|
||||
this.productName = productName;
|
||||
}
|
||||
|
||||
public String getMappedCode()
|
||||
{
|
||||
return mappedCode;
|
||||
}
|
||||
|
||||
public void setMappedCode(String mappedCode)
|
||||
{
|
||||
this.mappedCode = mappedCode;
|
||||
}
|
||||
|
||||
public boolean isInPackage()
|
||||
{
|
||||
return inPackage;
|
||||
}
|
||||
|
||||
public void setInPackage(boolean inPackage)
|
||||
{
|
||||
this.inPackage = inPackage;
|
||||
}
|
||||
|
||||
public boolean isMappedInPackage()
|
||||
{
|
||||
return mappedInPackage;
|
||||
}
|
||||
|
||||
public void setMappedInPackage(boolean mappedInPackage)
|
||||
{
|
||||
this.mappedInPackage = mappedInPackage;
|
||||
}
|
||||
|
||||
public boolean isCovered()
|
||||
{
|
||||
return covered;
|
||||
}
|
||||
|
||||
public void setCovered(boolean covered)
|
||||
{
|
||||
this.covered = covered;
|
||||
}
|
||||
|
||||
public int getOrderCount()
|
||||
{
|
||||
return orderCount;
|
||||
}
|
||||
|
||||
public void setOrderCount(int orderCount)
|
||||
{
|
||||
this.orderCount = orderCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+123
-79
@@ -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();
|
||||
|
||||
+1
@@ -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())
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user