修改套餐价格
This commit is contained in:
+70
-1
@@ -349,7 +349,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
List<BmsRegion> euRegions = loadEuRegions(regionByNameCn);
|
||||
Map<String, PrcZone> zoneByCountryAndCode = loadZoneByCountryAndCode();
|
||||
// Pre-check: same product cannot have duplicate country + weight band in Excel
|
||||
// Pre-check: any price sheet with duplicate country+weight fails the whole import.
|
||||
assertAllPriceSheetsNoDupCountryWeight(workbook, regionByNameCn, euRegions, zoneByCountryAndCode);
|
||||
assertImportProductsNoDupCountryWeight(workbook, products, regionByNameCn, euRegions,
|
||||
zoneByCountryAndCode);
|
||||
|
||||
@@ -632,6 +633,8 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
Map<String, BmsRegion> regionByNameCn = loadRegionByNameCn();
|
||||
List<BmsRegion> euRegions = loadEuRegions(regionByNameCn);
|
||||
Map<String, PrcZone> zoneByCountryAndCode = loadZoneByCountryAndCode();
|
||||
// Fail whole import when any price sheet has duplicate country+weight (incl. unmatched sheets).
|
||||
assertAllPriceSheetsNoDupCountryWeight(workbook, regionByNameCn, euRegions, zoneByCountryAndCode);
|
||||
Set<String> unmatchedCountries = new HashSet<>();
|
||||
Map<String, List<BmsProductCountry>> out = new LinkedHashMap<>();
|
||||
for (BmsProduct product : products)
|
||||
@@ -1166,6 +1169,12 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
{
|
||||
score = 80;
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(nameKey) && sheetNameBase(nameKey).equals(sheetNameBase(key))
|
||||
&& sheetNameBase(nameKey).length() >= 2)
|
||||
{
|
||||
// e.g. catalog name suffix differs from sheet (tax/cargo label)
|
||||
score = 70;
|
||||
}
|
||||
else if (StringUtils.isNotEmpty(codeKey) && key.contains(codeKey))
|
||||
{
|
||||
score = 60;
|
||||
@@ -1192,6 +1201,21 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return out;
|
||||
}
|
||||
|
||||
/** Base name before last '-' (catalog/sheet suffix may differ). */
|
||||
private static String sheetNameBase(String normalizedKey)
|
||||
{
|
||||
if (StringUtils.isEmpty(normalizedKey))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
int idx = normalizedKey.lastIndexOf('-');
|
||||
if (idx <= 0)
|
||||
{
|
||||
return normalizedKey;
|
||||
}
|
||||
return normalizedKey.substring(0, idx);
|
||||
}
|
||||
|
||||
private List<BmsRegion> loadEuRegions(Map<String, BmsRegion> regionByNameCn)
|
||||
{
|
||||
List<BmsRegion> list = new ArrayList<>();
|
||||
@@ -2119,6 +2143,51 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan every price sheet (not only catalog-matched ones).
|
||||
* Duplicate country+weight on any sheet fails the whole import
|
||||
* (e.g. same country twice for different last-mile carriers).
|
||||
*/
|
||||
private void assertAllPriceSheetsNoDupCountryWeight(Workbook workbook,
|
||||
Map<String, BmsRegion> regionByNameCn, List<BmsRegion> euRegions,
|
||||
Map<String, PrcZone> zoneByCountryAndCode)
|
||||
{
|
||||
if (workbook == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<String> tips = new ArrayList<String>();
|
||||
Set<String> unmatchedCountries = new HashSet<String>();
|
||||
for (int i = 0; i < workbook.getNumberOfSheets(); i++)
|
||||
{
|
||||
String sheetName = workbook.getSheetName(i);
|
||||
if (shouldSkipCountryPriceSheet(sheetName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Sheet sheet = workbook.getSheetAt(i);
|
||||
if (sheet == null || findHeaderCell(sheet, "\u56fd\u5bb6") == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
BmsProduct stub = new BmsProduct();
|
||||
stub.setProductCode(sheetName);
|
||||
stub.setProductName(sheetName);
|
||||
List<BmsProductCountry> rows = parseProductSheet(sheet, stub,
|
||||
regionByNameCn, euRegions, zoneByCountryAndCode, unmatchedCountries);
|
||||
String tip = buildDuplicateCountryWeightTip(stub, rows);
|
||||
if (StringUtils.isNotEmpty(tip))
|
||||
{
|
||||
tips.add(tip);
|
||||
}
|
||||
}
|
||||
if (!tips.isEmpty())
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.dupCountry",
|
||||
String.join("<br/>", tips)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Workbook pre-check for full import: reject before any write when a product sheet
|
||||
* has duplicate country + weight band (same zone) rows.
|
||||
|
||||
+74
-2
@@ -3018,6 +3018,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
/**
|
||||
* Draft only: when priceBuildMode changes (PULL/IMPORT), delete this version's
|
||||
* product / detail / SALES surcharge rel rows. Same mode or non-draft: no-op.
|
||||
* IMPORT: after wipe, copy products+details from latest prior version (if any).
|
||||
*/
|
||||
private void clearDraftVersionChildrenIfBuildModeChanged(PrcPriceSetVersion db, PrcPriceSetVersion incoming)
|
||||
{
|
||||
@@ -3043,9 +3044,80 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
deleteSalesRelsByPsvId(psvId);
|
||||
detailMapper.deletePrcPriceSetDetailByPsvId(psvId);
|
||||
setProductMapper.deleteByPsvId(psvId);
|
||||
if ("IMPORT".equalsIgnoreCase(newMode))
|
||||
{
|
||||
copyLatestPriorVersionChildren(db.getPriceSetId(), psvId);
|
||||
}
|
||||
}
|
||||
|
||||
/** Prefer same effective_time, else draft, else first version of the set. */
|
||||
/**
|
||||
* Copy products + details from latest prior version into the draft (Excel build-price base).
|
||||
* Prefer EFFECT, then PENDING, then highest versionSeq.
|
||||
*/
|
||||
private void copyLatestPriorVersionChildren(Long priceSetId, Long targetPsvId)
|
||||
{
|
||||
Long srcPsvId = findLatestPriorPsvId(priceSetId, targetPsvId);
|
||||
if (srcPsvId == null || targetPsvId == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
setProductMapper.copyFromVersion(srcPsvId, targetPsvId);
|
||||
int detailRows = detailMapper.copyDetailsFromVersion(srcPsvId, targetPsvId);
|
||||
if (detailRows > 0)
|
||||
{
|
||||
setProductMapper.bindDetailPspByPsvId(targetPsvId);
|
||||
}
|
||||
}
|
||||
|
||||
private Long findLatestPriorPsvId(Long priceSetId, Long excludePsvId)
|
||||
{
|
||||
if (priceSetId == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PrcPriceSetVersion q = new PrcPriceSetVersion();
|
||||
q.setPriceSetId(priceSetId);
|
||||
List<PrcPriceSetVersion> list = versionMapper.selectPrcPriceSetVersionList(q);
|
||||
if (list == null || list.isEmpty())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
PrcPriceSetVersion effect = null;
|
||||
PrcPriceSetVersion pending = null;
|
||||
PrcPriceSetVersion best = null;
|
||||
for (PrcPriceSetVersion v : list)
|
||||
{
|
||||
if (v == null || v.getPsvId() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (excludePsvId != null && excludePsvId.equals(v.getPsvId()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (VER_EFFECT.equals(v.getStatus()) && effect == null)
|
||||
{
|
||||
effect = v;
|
||||
}
|
||||
else if (VER_PENDING.equals(v.getStatus()) && pending == null)
|
||||
{
|
||||
pending = v;
|
||||
}
|
||||
if (best == null || (v.getVersionSeq() != null && best.getVersionSeq() != null
|
||||
&& v.getVersionSeq().intValue() > best.getVersionSeq().intValue())
|
||||
|| (best.getVersionSeq() == null && v.getVersionSeq() != null))
|
||||
{
|
||||
best = v;
|
||||
}
|
||||
}
|
||||
PrcPriceSetVersion pick = effect != null ? effect : (pending != null ? pending : best);
|
||||
return pick == null ? null : pick.getPsvId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefer same effective_time, else an existing draft.
|
||||
* Never fall back to EFFECT/EXPIRED — that would overwrite a live version when creating a new one.
|
||||
*/
|
||||
private PrcPriceSetVersion findReusableVersion(Long priceSetId, Date effectiveTime)
|
||||
{
|
||||
PrcPriceSetVersion q = new PrcPriceSetVersion();
|
||||
@@ -3072,7 +3144,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
return v;
|
||||
}
|
||||
}
|
||||
return list.get(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user