修改分区功能

This commit is contained in:
wuweihua
2026-09-15 16:55:11 +08:00
parent 7679a7d091
commit ccf85ebefc
17 changed files with 394 additions and 18 deletions
@@ -22,6 +22,7 @@ public class PrcQuote extends BaseEntity
private String productName;
private String countryCode;
private String countryName;
private String destPostcode;
private BigDecimal weight;
@JsonFormat(pattern = "yyyy-MM-dd")
private Date bizDate;
@@ -30,7 +30,6 @@ public class TmsPriceBillRequest extends TmsPriceQuoteRequest
private BigDecimal pkgHeight;
private String shipperName;
private String consigneeName;
private String destPostcode;
private String warehouseCode;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date orderTime;
@@ -19,11 +19,14 @@ public class TmsPriceQuoteRequest implements Serializable
@NotBlank(message = "productCode is required")
private String productCode;
/** ISO2;与 countryName 二选一 */
/** ISO2; countryName alternative */
private String countryCode;
/** 国家中文名;与 countryCode 二选一 */
/** country display name; countryCode alternative */
private String countryName;
/** Dest postcode; required when product-country has zones */
private String destPostcode;
@NotNull(message = "weight is required")
private BigDecimal weight;
@@ -30,6 +30,9 @@ public class TmsPriceQuoteResult implements Serializable
private String productName;
private String countryCode;
private String countryName;
private Long zoneId;
private String zoneCode;
private String zoneName;
private Long productCountryId;
private BigDecimal weightMin;
private BigDecimal weightMax;
@@ -42,13 +42,22 @@ public interface BmsProductCountryMapper
@Param("effectiveDate") Date effectiveDate);
/**
* Match by product + country + weight + bizDate.
* effective_date <= bizDate and (expire_date is null or expire_date > bizDate).
* Match by product + country + weight + bizDate (+ optional zoneCode).
* When zoneCode is empty, prefer rows without zone.
* When zoneCode is set, require matching zone_code.
*/
public BmsProductCountry selectMatchByProductCountryWeight(
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("zoneCode") String zoneCode,
@Param("weight") BigDecimal weight,
@Param("bizDate") Date bizDate);
/** Count product-country rows that have a zone for this product+country+bizDate */
public int countZonedByProductCountry(
@Param("productCode") String productCode,
@Param("countryCode") String countryCode,
@Param("countryName") String countryName,
@Param("bizDate") Date bizDate);
}
@@ -2,6 +2,7 @@ package com.ruoyi.price.mapper;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.domain.PrcZoneDetail;
public interface PrcZoneDetailMapper
@@ -25,4 +26,11 @@ public interface PrcZoneDetailMapper
public int deletePrcZoneDetailByZoneId(Long zoneId);
public int deletePrcZoneDetailByRegionId(Long regionId);
/**
* Resolve zone by country ISO2 + postcode (exact first, then longest prefix).
*/
public PrcZone selectZoneByCountryPostcode(
@Param("countryCode") String countryCode,
@Param("postcode") String postcode);
}
@@ -28,6 +28,8 @@ import com.ruoyi.price.domain.PrcPriceSetDetail;
import com.ruoyi.price.domain.PrcQuote;
import com.ruoyi.price.domain.PrcQuoteFee;
import com.ruoyi.price.domain.PrcSurchargeRel;
import com.ruoyi.price.domain.PrcZone;
import com.ruoyi.price.mapper.PrcZoneDetailMapper;
import com.ruoyi.price.domain.vo.TmsPriceQuoteFeeLine;
import com.ruoyi.price.domain.vo.TmsPriceQuoteRequest;
import com.ruoyi.price.domain.vo.TmsPriceQuoteResult;
@@ -87,6 +89,9 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
@Autowired
private PrcQuoteFeeMapper quoteFeeMapper;
@Autowired
private PrcZoneDetailMapper zoneDetailMapper;
@Autowired
private IBillSearchStore billSearchStore;
@@ -178,11 +183,55 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
}
BigDecimal weight = request.getWeight();
String destPostcode = emptyToNull(request.getDestPostcode());
String zoneCode = null;
PrcZone resolvedZone = null;
int zonedCount = productCountryMapper.countZonedByProductCountry(
productCode, countryCode, countryName, bizDate);
if (zonedCount > 0)
{
if (StringUtils.isEmpty(destPostcode))
{
throw new ServiceException(MessageUtils.message("price.quote.postcodeRequired"));
}
String iso2 = resolveCountryIso2(productCode, countryCode, countryName);
if (StringUtils.isEmpty(iso2))
{
throw new ServiceException(MessageUtils.message("price.quote.countryRequired"));
}
resolvedZone = zoneDetailMapper.selectZoneByCountryPostcode(iso2, normalizePostcode(destPostcode));
if (resolvedZone == null || StringUtils.isEmpty(resolvedZone.getZoneCode()))
{
throw new ServiceException(MessageUtils.message("price.quote.postcodeZoneNotFound"));
}
zoneCode = resolvedZone.getZoneCode();
if (countryCode == null)
{
countryCode = iso2;
}
}
BmsProductCountry base = productCountryMapper.selectMatchByProductCountryWeight(
productCode, countryCode, countryName, weight, bizDate);
productCode, countryCode, countryName, zoneCode, weight, bizDate);
if (base == null)
{
throw new ServiceException(MessageUtils.message("price.quote.priceNotHit"));
throw new ServiceException(MessageUtils.message(
zonedCount > 0 ? "price.quote.zonePriceNotHit" : "price.quote.priceNotHit"));
}
if (resolvedZone != null)
{
if (base.getZoneId() == null)
{
base.setZoneId(resolvedZone.getZoneId());
}
if (StringUtils.isEmpty(base.getZoneCode()))
{
base.setZoneCode(resolvedZone.getZoneCode());
}
if (StringUtils.isEmpty(base.getZoneName()))
{
base.setZoneName(resolvedZone.getZoneName());
}
}
String productName = resolveProductName(productCode, bizDate);
@@ -213,6 +262,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
TmsPriceQuoteResult hit = tryFixed(bind, set, base, productCode, productName, weight);
if (hit != null)
{
stampRequestMeta(request, hit);
return hit;
}
}
@@ -221,14 +271,67 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
TmsPriceQuoteResult hit = tryDiscount(bind, set, base, productCode, productName, weight);
if (hit != null)
{
stampRequestMeta(request, hit);
return hit;
}
}
}
}
return buildDefault(request.getCustomerId(), base, productCode, productName, weight,
TmsPriceQuoteResult fallback = buildDefault(request.getCustomerId(), base, productCode, productName, weight,
MessageUtils.message("price.quote.noCustomerPackageOverride"));
stampRequestMeta(request, fallback);
return fallback;
}
private void stampRequestMeta(TmsPriceQuoteRequest request, TmsPriceQuoteResult result)
{
if (result == null || request == null)
{
return;
}
if (StringUtils.isEmpty(result.getDestPostcode()))
{
result.setDestPostcode(emptyToNull(request.getDestPostcode()));
}
}
private String resolveCountryIso2(String productCode, String countryCode, String countryName)
{
if (StringUtils.isNotEmpty(countryCode))
{
return countryCode.toUpperCase();
}
BmsProductCountry query = new BmsProductCountry();
query.setProductCode(productCode);
query.setCountryName(countryName);
List<BmsProductCountry> rows = productCountryMapper.selectBmsProductCountryList(query);
if (rows == null)
{
return null;
}
for (BmsProductCountry row : rows)
{
if (StringUtils.isNotEmpty(row.getCountryCode()))
{
return row.getCountryCode().toUpperCase();
}
}
return null;
}
private static String normalizePostcode(String postcode)
{
if (StringUtils.isEmpty(postcode))
{
return postcode;
}
String n = postcode.trim().replace(" ", "");
if (n.endsWith(".0") && n.matches("\\d+\\.0"))
{
return n.substring(0, n.length() - 2);
}
return n;
}
private TmsPriceQuoteResult tryFixed(PrcCustomerPriceSet bind, PrcPriceSet set,
@@ -359,6 +462,9 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
r.setProductName(productName);
r.setCountryCode(base.getCountryCode());
r.setCountryName(base.getCountryName());
r.setZoneId(base.getZoneId());
r.setZoneCode(base.getZoneCode());
r.setZoneName(base.getZoneName());
r.setProductCountryId(base.getDetailId());
r.setWeightMin(base.getWeightMin());
r.setWeightMax(base.getWeightMax());
@@ -506,6 +612,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
quote.setProductName(result.getProductName());
quote.setCountryCode(result.getCountryCode());
quote.setCountryName(result.getCountryName());
quote.setDestPostcode(result.getDestPostcode());
quote.setWeight(weight);
quote.setBizDate(bizDate);
quote.setTmsId(request.getTmsId() == null ? null : Long.valueOf(request.getTmsId()));
@@ -637,6 +744,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
r.setProductName(quote.getProductName());
r.setCountryCode(quote.getCountryCode());
r.setCountryName(quote.getCountryName());
r.setDestPostcode(quote.getDestPostcode());
r.setProductCountryId(quote.getProductCountryId());
r.setWeightMin(quote.getWeightMin());
r.setWeightMax(quote.getWeightMax());
@@ -683,6 +791,10 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
to.setProductName(from.getProductName());
to.setCountryCode(from.getCountryCode());
to.setCountryName(from.getCountryName());
to.setDestPostcode(from.getDestPostcode());
to.setZoneId(from.getZoneId());
to.setZoneCode(from.getZoneCode());
to.setZoneName(from.getZoneName());
to.setProductCountryId(from.getProductCountryId());
to.setWeightMin(from.getWeightMin());
to.setWeightMax(from.getWeightMax());
@@ -716,6 +828,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
+ request.getProductCode().trim() + "|"
+ nvlStr(countryCode) + "|"
+ nvlStr(countryName) + "|"
+ nvlStr(emptyToNull(request.getDestPostcode())) + "|"
+ weight.toPlainString() + "|"
+ biz + "|"
+ (request.getTmsId() == null ? "" : request.getTmsId());