提交价格功能绑定
This commit is contained in:
@@ -24,6 +24,10 @@ public class BmsProductCountry implements Serializable
|
||||
private BigDecimal weightMin;
|
||||
/** 重量段最大值 KG */
|
||||
private BigDecimal weightMax;
|
||||
/** 运费 RMB/KG */
|
||||
private BigDecimal freightPrice;
|
||||
/** 挂号费 RMB/票 */
|
||||
private BigDecimal registrationFee;
|
||||
private String sizeLimit;
|
||||
private String lastMile;
|
||||
private String leadTime;
|
||||
@@ -46,6 +50,10 @@ public class BmsProductCountry implements Serializable
|
||||
public void setWeightMin(BigDecimal weightMin) { this.weightMin = weightMin; }
|
||||
public BigDecimal getWeightMax() { return weightMax; }
|
||||
public void setWeightMax(BigDecimal weightMax) { this.weightMax = weightMax; }
|
||||
public BigDecimal getFreightPrice() { return freightPrice; }
|
||||
public void setFreightPrice(BigDecimal freightPrice) { this.freightPrice = freightPrice; }
|
||||
public BigDecimal getRegistrationFee() { return registrationFee; }
|
||||
public void setRegistrationFee(BigDecimal registrationFee) { this.registrationFee = registrationFee; }
|
||||
public String getSizeLimit() { return sizeLimit; }
|
||||
public void setSizeLimit(String sizeLimit) { this.sizeLimit = sizeLimit; }
|
||||
public String getLastMile() { return lastMile; }
|
||||
@@ -69,6 +77,8 @@ public class BmsProductCountry implements Serializable
|
||||
.append("countryCode", getCountryCode())
|
||||
.append("weightMin", getWeightMin())
|
||||
.append("weightMax", getWeightMax())
|
||||
.append("freightPrice", getFreightPrice())
|
||||
.append("registrationFee", getRegistrationFee())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ public interface IBmsProductService
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode);
|
||||
|
||||
/**
|
||||
* 导入威狮B2C小包价表:产品目录 + 各产品 sheet 国家服务属性(不含运费/挂号费)
|
||||
* 导入威狮B2C小包价表:产品目录 + 各产品 sheet 国家×重量段(含运费/挂号费/尺寸/尾程/时效)
|
||||
*
|
||||
* @param file 上传的 xlsx/xls
|
||||
* @param updateSupport 是否更新已存在产品
|
||||
|
||||
+146
-14
@@ -198,6 +198,14 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
updateNum++;
|
||||
countryNum += countries.size();
|
||||
}
|
||||
else if (!countries.isEmpty())
|
||||
{
|
||||
// Product already exists and "update" unchecked: still refresh country/fee rows from Excel.
|
||||
countryMapper.deleteByProductCode(product.getProductCode());
|
||||
saveCountries(product.getProductCode(), countries);
|
||||
updateNum++;
|
||||
countryNum += countries.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
skipNum++;
|
||||
@@ -216,7 +224,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
String msg = "\u5bfc\u5165\u6210\u529f\uff1a\u65b0\u589e " + successNum + " \u4e2a\u4ea7\u54c1\uff0c\u66f4\u65b0 " + updateNum + " \u4e2a\uff0c\u8df3\u8fc7 "
|
||||
+ skipNum + " \u4e2a\uff1b\u5199\u5165\u56fd\u5bb6/\u91cd\u91cf\u6bb5\u660e\u7ec6 " + countryNum + " \u884c\u3002"
|
||||
+ "<br/>\u8303\u56f4\uff1a\u4ea7\u54c1\u76ee\u5f55 + \u91cd\u91cf\u6bb5min/max + \u5c3a\u5bf8/\u5c3e\u7a0b/\u65f6\u6548\uff1b\u56fd\u5bb6\u7801\u6765\u81ea bms_region.country_name_cn / country_code_2\u3002";
|
||||
+ "<br/>\u8303\u56f4\uff1a\u4ea7\u54c1\u76ee\u5f55 + \u91cd\u91cf\u6bb5 + \u8fd0\u8d39/\u6302\u53f7\u8d39 + \u5c3a\u5bf8/\u5c3e\u7a0b/\u65f6\u6548\uff1b\u56fd\u5bb6\u7801\u6765\u81ea bms_region\u3002";
|
||||
if (!unmatchedCountries.isEmpty())
|
||||
{
|
||||
msg += "<br/>\u672a\u5339\u914d\u56fd\u5bb6\u8868\uff08country_code \u4e3a\u7a7a\uff09\uff1a" + String.join("\u3001", unmatchedCountries);
|
||||
@@ -230,7 +238,20 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
for (BmsProductCountry c : countries)
|
||||
{
|
||||
c.setProductCode(productCode);
|
||||
countryMapper.insertBmsProductCountry(c);
|
||||
try
|
||||
{
|
||||
countryMapper.insertBmsProductCountry(c);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String tip = e.getMessage() == null ? "" : e.getMessage();
|
||||
if (tip.contains("freight_price") || tip.contains("registration_fee") || tip.contains("Unknown column"))
|
||||
{
|
||||
throw new ServiceException(
|
||||
"\u8bf7\u5148\u6267\u884c SQL\uff1abms-back/sql/price/product_country_fee_alter.sql\uff08\u7f3a\u5c11\u8fd0\u8d39/\u6302\u53f7\u8d39\u5b57\u6bb5\uff09");
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,24 +329,60 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
Date sheetEffective = parseSheetEffectiveDate(sheet);
|
||||
List<BmsProductCountry> list = new ArrayList<>();
|
||||
// Product sheets also often start at column B.
|
||||
int[] header = findHeaderCell(sheet, "\u56fd\u5bb6");
|
||||
int baseCol = header != null ? header[1] : 0;
|
||||
int startRow = header != null ? header[0] + 1 : 0;
|
||||
int[] countryHeader = findHeaderCell(sheet, "\u56fd\u5bb6");
|
||||
if (countryHeader == null)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
int headerRowIdx = countryHeader[0];
|
||||
Row headerRow = sheet.getRow(headerRowIdx);
|
||||
int colCountry = countryHeader[1];
|
||||
int colWeight = findColByHeader(headerRow, "\u91cd\u91cf", colCountry + 1);
|
||||
int colFreight = findColByHeader(headerRow, "\u8fd0\u8d39", colCountry + 1);
|
||||
int colRegister = findColByHeader(headerRow, "\u6302\u53f7", colCountry + 1);
|
||||
int colSize = findColByHeader(headerRow, "\u5c3a\u5bf8", colCountry + 1);
|
||||
int colLastMile = findColByHeader(headerRow, "\u5c3e\u7a0b", colCountry + 1);
|
||||
int colLeadTime = findColByHeader(headerRow, "\u65f6\u6548", colCountry + 1);
|
||||
// Fallback offsets when header text missing (Weishi layout: B=country ... H=lead time)
|
||||
if (colWeight < 0)
|
||||
{
|
||||
colWeight = colCountry + 1;
|
||||
}
|
||||
if (colFreight < 0)
|
||||
{
|
||||
colFreight = colCountry + 2;
|
||||
}
|
||||
if (colRegister < 0)
|
||||
{
|
||||
colRegister = colCountry + 3;
|
||||
}
|
||||
if (colSize < 0)
|
||||
{
|
||||
colSize = colCountry + 4;
|
||||
}
|
||||
if (colLastMile < 0)
|
||||
{
|
||||
colLastMile = colCountry + 5;
|
||||
}
|
||||
if (colLeadTime < 0)
|
||||
{
|
||||
colLeadTime = colCountry + 6;
|
||||
}
|
||||
|
||||
String currentCountry = null;
|
||||
String currentSize = null;
|
||||
String currentLastMile = null;
|
||||
String currentLeadTime = null;
|
||||
int lastRow = sheet.getLastRowNum();
|
||||
for (int i = startRow; i <= lastRow; i++)
|
||||
for (int i = headerRowIdx + 1; i <= lastRow; i++)
|
||||
{
|
||||
Row row = sheet.getRow(i);
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
String countryCell = cellString(row.getCell(baseCol));
|
||||
String weightLabel = cellString(row.getCell(baseCol + 1));
|
||||
String countryCell = cellString(row.getCell(colCountry));
|
||||
String weightLabel = cellString(row.getCell(colWeight));
|
||||
if ("\u56fd\u5bb6".equals(countryCell) || weightLabel.contains("\u91cd\u91cf\u6bb5"))
|
||||
{
|
||||
continue;
|
||||
@@ -333,9 +390,9 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
if (StringUtils.isNotEmpty(countryCell))
|
||||
{
|
||||
currentCountry = countryCell.trim();
|
||||
currentSize = emptyToNull(cellString(row.getCell(baseCol + 4)));
|
||||
currentLastMile = emptyToNull(cellString(row.getCell(baseCol + 5)));
|
||||
currentLeadTime = emptyToNull(cellString(row.getCell(baseCol + 6)));
|
||||
currentSize = emptyToNull(cellString(row.getCell(colSize)));
|
||||
currentLastMile = emptyToNull(cellString(row.getCell(colLastMile)));
|
||||
currentLeadTime = emptyToNull(cellString(row.getCell(colLeadTime)));
|
||||
}
|
||||
if (StringUtils.isEmpty(currentCountry))
|
||||
{
|
||||
@@ -361,6 +418,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
c.setWeightMin(range[0]);
|
||||
c.setWeightMax(range[1]);
|
||||
c.setFreightPrice(cellDecimal(row.getCell(colFreight)));
|
||||
c.setRegistrationFee(cellDecimal(row.getCell(colRegister)));
|
||||
c.setSizeLimit(currentSize);
|
||||
c.setLastMile(currentLastMile);
|
||||
c.setLeadTime(currentLeadTime);
|
||||
@@ -371,7 +430,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
/**
|
||||
* ???? bms_region??country_name_cn -> ????? country_code_2??
|
||||
* Load bms_region map: country_name_cn -> region (for country_code_2).
|
||||
*/
|
||||
private Map<String, BmsRegion> loadRegionByNameCn()
|
||||
{
|
||||
@@ -395,7 +454,7 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
|
||||
/**
|
||||
* ????? country_name_cn ?????????????????????????? ??? / ?????????
|
||||
* Exact country_name_cn match first; single contains match as fallback (e.g. Czech / Czech Republic).
|
||||
*/
|
||||
private BmsRegion resolveRegion(String excelName, Map<String, BmsRegion> regionByNameCn)
|
||||
{
|
||||
@@ -507,6 +566,28 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return "TAX_INCLUDED";
|
||||
}
|
||||
|
||||
/**
|
||||
* Find column index on header row whose text contains keyword; -1 if not found.
|
||||
*/
|
||||
private static int findColByHeader(Row headerRow, String keyword, int fromCol)
|
||||
{
|
||||
if (headerRow == null || StringUtils.isEmpty(keyword))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
int last = Math.max(headerRow.getLastCellNum(), fromCol + 12);
|
||||
last = Math.min(last, 30);
|
||||
for (int c = Math.max(fromCol, 0); c < last; c++)
|
||||
{
|
||||
String v = cellString(headerRow.getCell(c));
|
||||
if (StringUtils.isNotEmpty(v) && v.contains(keyword))
|
||||
{
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String emptyToNull(String s)
|
||||
{
|
||||
return StringUtils.isEmpty(s) ? null : s;
|
||||
@@ -595,6 +676,57 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
}
|
||||
|
||||
private static BigDecimal cellDecimal(Cell cell)
|
||||
{
|
||||
if (cell == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
CellType type = cell.getCellType();
|
||||
if (type == CellType.FORMULA)
|
||||
{
|
||||
type = cell.getCachedFormulaResultType();
|
||||
}
|
||||
try
|
||||
{
|
||||
if (type == CellType.NUMERIC)
|
||||
{
|
||||
return BigDecimal.valueOf(cell.getNumericCellValue());
|
||||
}
|
||||
String s = cellString(cell);
|
||||
if (StringUtils.isEmpty(s))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
// strip currency / unit suffixes: 56、56元、56 RMB
|
||||
s = s.replace(",", "").replace("\uffe5", "").replace("\u5143", "")
|
||||
.replace("RMB", "").replace("rmb", "").trim();
|
||||
if (s.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int cut = -1;
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
char ch = s.charAt(i);
|
||||
if (!(ch == '.' || ch == '-' || (ch >= '0' && ch <= '9')))
|
||||
{
|
||||
cut = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cut > 0)
|
||||
{
|
||||
s = s.substring(0, cut).trim();
|
||||
}
|
||||
return new BigDecimal(s);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Date cellDate(Cell cell)
|
||||
{
|
||||
if (cell == null)
|
||||
|
||||
+14
-8
@@ -332,7 +332,8 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
int incomplete = 0;
|
||||
for (PrcPriceSetDetail d : details)
|
||||
{
|
||||
if (StringUtils.isEmpty(d.getProductCode()) || StringUtils.isEmpty(d.getCountryCode())
|
||||
boolean noCountry = StringUtils.isEmpty(d.getCountryCode()) && StringUtils.isEmpty(d.getCountryName());
|
||||
if (StringUtils.isEmpty(d.getProductCode()) || noCountry
|
||||
|| (d.getWsdId() == null && StringUtils.isEmpty(d.getWeightLabel()))
|
||||
|| d.getFvValue() == null || d.getFvRegistrationFee() == null)
|
||||
{
|
||||
@@ -341,15 +342,16 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
}
|
||||
if (details.isEmpty())
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "FAIL", "固定价模式至少需要 1 条明细"));
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "PASS",
|
||||
"\u65e0\u5957\u9910\u660e\u7ec6\uff1a\u8ba1\u8d39\u53d6 bms_product / bms_product_country \u9ed8\u8ba4\u8fd0\u8d39\u4e0e\u6302\u53f7\u8d39"));
|
||||
}
|
||||
else if (incomplete > 0)
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "FAIL", incomplete + " 条明细缺少产品/国家/重量段/运费/挂号费"));
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "FAIL", incomplete + " \u6761\u660e\u7ec6\u7f3a\u5c11\u4ea7\u54c1/\u56fd\u5bb6/\u91cd\u91cf\u6bb5/\u8fd0\u8d39/\u6302\u53f7\u8d39"));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "PASS", details.size() + " 条明细,运费与挂号费均填写"));
|
||||
items.add(new PrcPriceSetCheckItem("FIXED 明细完整性", "PASS", details.size() + " \u6761\u8986\u76d6\u660e\u7ec6\uff08\u672a\u8986\u76d6\u7684\u4ea7\u54c1\u56fd\u5bb6\u91cd\u91cf\u6bb5\u4ecd\u8d70\u9ed8\u8ba4\u4ef7\uff09"));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -418,11 +420,15 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
|
||||
if (TYPE_FIXED.equals(setType) && !details.isEmpty())
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("运费单价 vs 默认等级价偏差", "INFO", "默认等级价对照将在计费试算上线后自动计算"));
|
||||
items.add(new PrcPriceSetCheckItem("\u8fd0\u8d39\u5355\u4ef7 vs \u9ed8\u8ba4\u7b49\u7ea7\u4ef7\u504f\u5dee", "INFO", "\u6709\u8986\u76d6\u660e\u7ec6\u65f6\u4f18\u5148\u53d6\u5957\u9910\u56fa\u5b9a\u4ef7\uff1b\u672a\u547d\u4e2d\u5219\u56de\u9000 bms_product_country"));
|
||||
}
|
||||
else if (TYPE_FIXED.equals(setType))
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("\u8fd0\u8d39\u5355\u4ef7 vs \u9ed8\u8ba4\u7b49\u7ea7\u4ef7\u504f\u5dee", "INFO", "\u65e0\u5957\u9910\u660e\u7ec6\uff0c\u5168\u90e8\u8d70 bms_product_country \u9ed8\u8ba4\u8fd0\u8d39/\u6302\u53f7\u8d39"));
|
||||
}
|
||||
else if (TYPE_DISCOUNT.equals(setType))
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("运费单价 vs 默认等级价偏差", "INFO", "折扣模式按下单时默认等级价 × 折扣计费"));
|
||||
items.add(new PrcPriceSetCheckItem("\u8fd0\u8d39\u5355\u4ef7 vs \u9ed8\u8ba4\u7b49\u7ea7\u4ef7\u504f\u5dee", "INFO", "\u6298\u6263\u6a21\u5f0f\u6309\u4e0b\u5355\u65f6\u9ed8\u8ba4\u7b49\u7ea7\u4ef7 \u00d7 \u6298\u6263\u8ba1\u8d39"));
|
||||
}
|
||||
|
||||
return items;
|
||||
@@ -599,9 +605,9 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
}
|
||||
if (TYPE_FIXED.equals(set.getSetType()))
|
||||
{
|
||||
if (StringUtils.isEmpty(detail.getCountryCode()))
|
||||
if (StringUtils.isEmpty(detail.getCountryCode()) && StringUtils.isEmpty(detail.getCountryName()))
|
||||
{
|
||||
throw new ServiceException("固定价明细必须填写国家");
|
||||
throw new ServiceException("\u56fa\u5b9a\u4ef7\u660e\u7ec6\u5fc5\u987b\u586b\u5199\u56fd\u5bb6");
|
||||
}
|
||||
if (detail.getWsdId() == null && StringUtils.isEmpty(detail.getWeightLabel()))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user