修改比对规则
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')")
|
@PreAuthorize("@ss.hasPermi('price:orderBill:list')")
|
||||||
@PostMapping("/orderBill/checkProducts")
|
@PostMapping("/orderBill/checkProducts")
|
||||||
|
|||||||
+219
-11
@@ -3,35 +3,243 @@ package com.bms.price.domain.vo;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
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
|
public class OrderBillProductCheckResult implements Serializable
|
||||||
{
|
{
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/** Orders matched by search filters (customer + billing time). */
|
|
||||||
private long orderTotal;
|
private long orderTotal;
|
||||||
|
private int distinctOrderProducts;
|
||||||
private int packageProductCount;
|
private int packageProductCount;
|
||||||
private int matchedCount;
|
private int matchedCount;
|
||||||
private int missingCount;
|
private int missingCount;
|
||||||
private String asOfTime;
|
private String asOfTime;
|
||||||
private List<ProductRow> packageProducts = new ArrayList<ProductRow>();
|
private List<PackageProductRow> packageProducts = new ArrayList<PackageProductRow>();
|
||||||
private List<ProductRow> missingProducts = new ArrayList<ProductRow>();
|
private List<OrderProductRow> orderProducts = new ArrayList<OrderProductRow>();
|
||||||
|
private List<OrderProductRow> missingProducts = new ArrayList<OrderProductRow>();
|
||||||
|
|
||||||
@Data
|
public long getOrderTotal()
|
||||||
public static class ProductRow implements Serializable
|
{
|
||||||
|
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 static final long serialVersionUID = 1L;
|
||||||
private String customerCode;
|
private String customerCode;
|
||||||
private String productCode;
|
private String productCode;
|
||||||
private String productName;
|
private String productName;
|
||||||
/** Whether product exists in catalog (effective at asOf). */
|
|
||||||
private boolean inLibrary;
|
public String getCustomerCode()
|
||||||
/** Order count in search billing window for this product. */
|
{
|
||||||
|
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;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+113
-69
@@ -3,6 +3,7 @@ package com.bms.price.service;
|
|||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -17,16 +18,17 @@ import org.springframework.stereotype.Service;
|
|||||||
import com.bms.common.annotation.DataScope;
|
import com.bms.common.annotation.DataScope;
|
||||||
import com.bms.common.exception.ServiceException;
|
import com.bms.common.exception.ServiceException;
|
||||||
import com.bms.common.utils.StringUtils;
|
import com.bms.common.utils.StringUtils;
|
||||||
import com.bms.price.domain.BmsProduct;
|
|
||||||
import com.bms.price.domain.PrcOrderBill;
|
import com.bms.price.domain.PrcOrderBill;
|
||||||
import com.bms.price.domain.PrcPriceSetProduct;
|
import com.bms.price.domain.PrcPriceSetProduct;
|
||||||
import com.bms.price.domain.vo.OrderBillProductCheckResult;
|
import com.bms.price.domain.vo.OrderBillProductCheckResult;
|
||||||
import com.bms.price.domain.vo.OrderBillProductCheckResult.ProductRow;
|
import com.bms.price.domain.vo.OrderBillProductCheckResult.OrderProductRow;
|
||||||
import com.bms.price.mapper.BmsProductMapper;
|
import com.bms.price.domain.vo.OrderBillProductCheckResult.PackageProductRow;
|
||||||
import com.bms.price.mapper.PrcOrderBillMapper;
|
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
|
@Service
|
||||||
public class OrderBillProductCheckService
|
public class OrderBillProductCheckService
|
||||||
@@ -37,7 +39,7 @@ public class OrderBillProductCheckService
|
|||||||
private ITmsPriceQuoteService tmsPriceQuoteService;
|
private ITmsPriceQuoteService tmsPriceQuoteService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private BmsProductMapper productMapper;
|
private IBmsProductCodeMappingService productCodeMappingService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PrcOrderBillMapper orderBillMapper;
|
private PrcOrderBillMapper orderBillMapper;
|
||||||
@@ -51,74 +53,125 @@ public class OrderBillProductCheckService
|
|||||||
OrderBillProductCheckResult result = new OrderBillProductCheckResult();
|
OrderBillProductCheckResult result = new OrderBillProductCheckResult();
|
||||||
result.setAsOfTime(formatAsOf(asOf));
|
result.setAsOfTime(formatAsOf(asOf));
|
||||||
|
|
||||||
List<String> customerCodes = normalizeCodes(query.getCustomerCodes());
|
List<Map<String, Object>> groups = orderBillMapper.selectDistinctProductGroups(query);
|
||||||
Map<String, Integer> orderCountByKey = loadOrderCounts(query);
|
if (groups == null || groups.isEmpty())
|
||||||
|
{
|
||||||
|
result.setOrderTotal(0L);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
long orderTotal = 0L;
|
long orderTotal = 0L;
|
||||||
for (Integer c : orderCountByKey.values())
|
Set<String> customerCodes = new HashSet<String>();
|
||||||
|
for (Map<String, Object> g : groups)
|
||||||
{
|
{
|
||||||
if (c != null)
|
String customerCode = trim(str(g, "customer_code"));
|
||||||
{
|
String productCode = trim(str(g, "product_code"));
|
||||||
orderTotal += c.intValue();
|
if (StringUtils.isEmpty(customerCode) || StringUtils.isEmpty(productCode))
|
||||||
}
|
|
||||||
}
|
|
||||||
result.setOrderTotal(orderTotal);
|
|
||||||
|
|
||||||
List<ProductRow> packageRows = new ArrayList<ProductRow>();
|
|
||||||
List<ProductRow> missingRows = new ArrayList<ProductRow>();
|
|
||||||
int matched = 0;
|
|
||||||
|
|
||||||
for (String customerCode : customerCodes)
|
|
||||||
{
|
|
||||||
List<PrcPriceSetProduct> products = tmsPriceQuoteService.listAllBoundPackageProducts(customerCode, asOf);
|
|
||||||
Set<String> seen = new HashSet<String>();
|
|
||||||
if (products == null)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
for (PrcPriceSetProduct p : products)
|
for (PrcPriceSetProduct p : products)
|
||||||
{
|
{
|
||||||
if (p == null || StringUtils.isEmpty(p.getProductCode()))
|
if (p == null || StringUtils.isEmpty(p.getProductCode()))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String code = p.getProductCode().trim();
|
if (!isSalesProduct(p))
|
||||||
String upper = code.toUpperCase(Locale.ROOT);
|
|
||||||
if (!seen.add(upper))
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
boolean inLibrary = existsInLibrary(code, asOf);
|
String code = p.getProductCode().trim();
|
||||||
ProductRow row = new ProductRow();
|
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.setCustomerCode(customerCode);
|
||||||
row.setProductCode(code);
|
row.setUpstreamCode(productCode);
|
||||||
row.setProductName(trim(p.getProductName()));
|
row.setProductName(trim(str(g, "product_name")));
|
||||||
row.setInLibrary(inLibrary);
|
row.setMappedCode(mappedCode);
|
||||||
Integer oc = orderCountByKey.get(key(customerCode, upper));
|
row.setInPackage(inPackage);
|
||||||
row.setOrderCount(oc == null ? 0 : oc.intValue());
|
row.setMappedInPackage(mappedInPackage);
|
||||||
packageRows.add(row);
|
row.setCovered(covered);
|
||||||
if (inLibrary)
|
row.setOrderCount((int) Math.min(Integer.MAX_VALUE, longValue(g, "order_count")));
|
||||||
|
orderProducts.add(row);
|
||||||
|
if (covered)
|
||||||
{
|
{
|
||||||
matched++;
|
matched++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
missingRows.add(row);
|
missingProducts.add(row);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packageRows.sort(Comparator
|
orderProducts.sort(Comparator
|
||||||
.comparing(ProductRow::getCustomerCode, nullSafe())
|
.comparing(OrderProductRow::isCovered)
|
||||||
.thenComparing(ProductRow::getProductCode, nullSafe()));
|
.thenComparing(OrderProductRow::getCustomerCode, nullSafe())
|
||||||
missingRows.sort(Comparator
|
.thenComparing(OrderProductRow::getUpstreamCode, nullSafe()));
|
||||||
.comparing(ProductRow::getCustomerCode, nullSafe())
|
missingProducts.sort(Comparator
|
||||||
.thenComparing(ProductRow::getProductCode, nullSafe()));
|
.comparing(OrderProductRow::getCustomerCode, nullSafe())
|
||||||
|
.thenComparing(OrderProductRow::getUpstreamCode, nullSafe()));
|
||||||
|
|
||||||
|
result.setOrderTotal(orderTotal);
|
||||||
|
result.setDistinctOrderProducts(orderProducts.size());
|
||||||
result.setPackageProductCount(packageRows.size());
|
result.setPackageProductCount(packageRows.size());
|
||||||
result.setMatchedCount(matched);
|
result.setMatchedCount(matched);
|
||||||
result.setMissingCount(missingRows.size());
|
result.setMissingCount(missingProducts.size());
|
||||||
result.setPackageProducts(packageRows);
|
result.setPackageProducts(packageRows);
|
||||||
result.setMissingProducts(missingRows);
|
result.setOrderProducts(orderProducts);
|
||||||
|
result.setMissingProducts(missingProducts);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,32 +189,28 @@ public class OrderBillProductCheckService
|
|||||||
return rows == null ? new ArrayList<PrcOrderBill>() : rows;
|
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);
|
if (productCodeMappingService == null || StringUtils.isEmpty(upstreamCode))
|
||||||
Map<String, Integer> map = new HashMap<String, Integer>();
|
|
||||||
if (groups == null)
|
|
||||||
{
|
{
|
||||||
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"));
|
return null;
|
||||||
String productCode = trim(str(g, "product_code"));
|
|
||||||
if (StringUtils.isEmpty(customerCode) || StringUtils.isEmpty(productCode))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
map.put(key(customerCode, productCode.toUpperCase(Locale.ROOT)),
|
return mapped.trim();
|
||||||
Integer.valueOf((int) Math.min(Integer.MAX_VALUE, longValue(g, "order_count"))));
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean existsInLibrary(String productCode, Date asOf)
|
private static boolean isSalesProduct(PrcPriceSetProduct p)
|
||||||
{
|
{
|
||||||
BmsProduct hit = productMapper.selectEffectiveBmsProductByCode(productCode, asOf);
|
if (p == null)
|
||||||
return hit != null && StringUtils.isNotEmpty(hit.getProductCode());
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String type = p.getPriceType();
|
||||||
|
return StringUtils.isEmpty(type) || "SALES".equalsIgnoreCase(type.trim());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validate(PrcOrderBill query)
|
private void validate(PrcOrderBill query)
|
||||||
@@ -248,11 +297,6 @@ public class OrderBillProductCheckService
|
|||||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(asOf);
|
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)
|
private static String trim(String s)
|
||||||
{
|
{
|
||||||
return StringUtils.isEmpty(s) ? null : s.trim();
|
return StringUtils.isEmpty(s) ? null : s.trim();
|
||||||
|
|||||||
+1
@@ -359,6 +359,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
|||||||
}
|
}
|
||||||
PrcPriceSetProduct q = new PrcPriceSetProduct();
|
PrcPriceSetProduct q = new PrcPriceSetProduct();
|
||||||
q.setPsvId(psvId);
|
q.setPsvId(psvId);
|
||||||
|
q.setPriceType("SALES");
|
||||||
List<PrcPriceSetProduct> rows = setProductMapper.selectPrcPriceSetProductList(q);
|
List<PrcPriceSetProduct> rows = setProductMapper.selectPrcPriceSetProductList(q);
|
||||||
if (rows == null || rows.isEmpty())
|
if (rows == null || rows.isEmpty())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-drawer v-model="visible" size="920px" title="产品库比对(套餐销售价)" append-to-body destroy-on-close>
|
<el-drawer v-model="visible" size="920px" title="产品套餐比对" append-to-body destroy-on-close>
|
||||||
<div v-loading="loading">
|
<div v-loading="loading">
|
||||||
<el-empty v-if="!loading && !result" description="暂无结果" />
|
<el-empty v-if="!loading && !result" description="暂无结果" />
|
||||||
<template v-else-if="result">
|
<template v-else-if="result">
|
||||||
@@ -7,7 +7,8 @@
|
|||||||
<el-descriptions-item label="筛选订单数">{{ result.orderTotal ?? 0 }}</el-descriptions-item>
|
<el-descriptions-item label="筛选订单数">{{ result.orderTotal ?? 0 }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="套餐截止时间">{{ result.asOfTime || '-' }}</el-descriptions-item>
|
<el-descriptions-item label="套餐截止时间">{{ result.asOfTime || '-' }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="套餐产品数">{{ result.packageProductCount ?? 0 }}</el-descriptions-item>
|
<el-descriptions-item label="套餐产品数">{{ result.packageProductCount ?? 0 }}</el-descriptions-item>
|
||||||
<el-descriptions-item label="库内/缺失">
|
<el-descriptions-item label="订单产品数">{{ result.distinctOrderProducts ?? 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="命中/缺失">
|
||||||
<el-tag type="success" size="small">{{ result.matchedCount ?? 0 }}</el-tag>
|
<el-tag type="success" size="small">{{ result.matchedCount ?? 0 }}</el-tag>
|
||||||
<span class="sep">/</span>
|
<span class="sep">/</span>
|
||||||
<el-tag type="danger" size="small">{{ result.missingCount ?? 0 }}</el-tag>
|
<el-tag type="danger" size="small">{{ result.missingCount ?? 0 }}</el-tag>
|
||||||
@@ -18,33 +19,49 @@
|
|||||||
<el-tab-pane :label="missingTabLabel" name="missing">
|
<el-tab-pane :label="missingTabLabel" name="missing">
|
||||||
<el-table :data="result.missingProducts || []" border size="small" max-height="520">
|
<el-table :data="result.missingProducts || []" border size="small" max-height="520">
|
||||||
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
|
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
|
||||||
<el-table-column prop="productCode" label="套餐产品代码" min-width="130" show-overflow-tooltip />
|
<el-table-column prop="upstreamCode" label="上游产品代码" min-width="120" show-overflow-tooltip />
|
||||||
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
|
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="mappedCode" label="映射后代码" min-width="120" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">{{ row.mappedCode || '-' }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="orderCount" label="订单数" width="100" align="center">
|
<el-table-column prop="orderCount" label="订单数" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button link type="primary" :title="'点击查订单'" @click="openOrders(row)">{{ row.orderCount ?? 0 }}</el-button>
|
<el-button link type="primary" :title="'点击查订单'" @click="openOrders(row)">{{ row.orderCount ?? 0 }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
<el-empty v-if="!(result.missingProducts || []).length" description="未发现产品库缺失" />
|
<el-empty v-if="!(result.missingProducts || []).length" description="未发现缺失产品" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane :label="packageTabLabel" name="package">
|
<el-tab-pane label="全部比对" name="all">
|
||||||
<el-table :data="result.packageProducts || []" border size="small" max-height="520">
|
<el-table :data="result.orderProducts || []" border size="small" max-height="520">
|
||||||
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
|
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
|
||||||
<el-table-column prop="productCode" label="套餐产品代码" min-width="130" show-overflow-tooltip />
|
<el-table-column prop="upstreamCode" label="上游产品代码" min-width="120" show-overflow-tooltip />
|
||||||
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
|
<el-table-column prop="productName" label="产品名称" min-width="140" show-overflow-tooltip />
|
||||||
<el-table-column label="产品库" width="110" align="center">
|
<el-table-column prop="mappedCode" label="映射后代码" min-width="120" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">{{ row.mappedCode || '-' }}</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="是否在套餐" width="120" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-tag v-if="row.inLibrary" size="small" type="success">在库</el-tag>
|
<el-tag v-if="row.covered" size="small" type="success">在套餐</el-tag>
|
||||||
<el-tag v-else size="small" type="danger">不在库</el-tag>
|
<el-tag v-else size="small" type="danger">不在套餐</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column label="命中方式" min-width="140" show-overflow-tooltip>
|
||||||
|
<template #default="{ row }">{{ hitText(row) }}</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column prop="orderCount" label="订单数" width="100" align="center">
|
<el-table-column prop="orderCount" label="订单数" width="100" align="center">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<el-button link type="primary" @click="openOrders(row)">{{ row.orderCount ?? 0 }}</el-button>
|
<el-button link type="primary" @click="openOrders(row)">{{ row.orderCount ?? 0 }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="packageTabLabel" name="package">
|
||||||
|
<el-table :data="result.packageProducts || []" border size="small" max-height="520">
|
||||||
|
<el-table-column prop="customerCode" label="客户代码" min-width="110" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="productCode" label="套餐产品代码" min-width="130" show-overflow-tooltip />
|
||||||
|
<el-table-column prop="productName" label="产品名称" min-width="160" show-overflow-tooltip />
|
||||||
|
</el-table>
|
||||||
<el-empty v-if="!(result.packageProducts || []).length" description="客户未绑定套餐产品" />
|
<el-empty v-if="!(result.packageProducts || []).length" description="客户未绑定套餐产品" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
@@ -87,17 +104,25 @@ const packageTabLabel = computed(() => {
|
|||||||
return '套餐产品 (' + n + ')'
|
return '套餐产品 (' + n + ')'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function hitText(row) {
|
||||||
|
if (!row) return '-'
|
||||||
|
if (row.inPackage) return '直接命中'
|
||||||
|
if (row.mappedInPackage) return '映射后命中'
|
||||||
|
if (row.mappedCode) return '有映射但仍不在套餐'
|
||||||
|
return '无映射'
|
||||||
|
}
|
||||||
|
|
||||||
function openOrders(row) {
|
function openOrders(row) {
|
||||||
if (!row || !row.productCode || !lastQuery.value) {
|
if (!row || !row.upstreamCode || !lastQuery.value) {
|
||||||
ElMessage.warning('请先选择客户并选择计费时间')
|
ElMessage.warning('请先选择客户并选择计费时间')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const q = {
|
const q = {
|
||||||
...lastQuery.value,
|
...lastQuery.value,
|
||||||
customerCodes: row.customerCode ? [row.customerCode] : lastQuery.value.customerCodes,
|
customerCodes: row.customerCode ? [row.customerCode] : lastQuery.value.customerCodes,
|
||||||
productCode: row.productCode
|
productCode: row.upstreamCode
|
||||||
}
|
}
|
||||||
orderDialogTitle.value = '产品订单: ' + row.productCode
|
orderDialogTitle.value = '产品订单: ' + row.upstreamCode
|
||||||
orderDialogVisible.value = true
|
orderDialogVisible.value = true
|
||||||
orderRows.value = []
|
orderRows.value = []
|
||||||
orderLoading.value = true
|
orderLoading.value = true
|
||||||
@@ -128,7 +153,7 @@ function open(query) {
|
|||||||
if ((result.value?.missingCount || 0) > 0) {
|
if ((result.value?.missingCount || 0) > 0) {
|
||||||
activeTab.value = 'missing'
|
activeTab.value = 'missing'
|
||||||
} else {
|
} else {
|
||||||
activeTab.value = 'package'
|
activeTab.value = 'all'
|
||||||
}
|
}
|
||||||
}).catch(() => {
|
}).catch(() => {
|
||||||
result.value = null
|
result.value = null
|
||||||
|
|||||||
Reference in New Issue
Block a user