Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -25,16 +25,18 @@ public class BmsProduct extends BaseEntity
|
||||
private String taxMode;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date effectiveDate;
|
||||
/** 0启用(按日期展示已生效/待生效) 1已失效 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date expireDate;
|
||||
/** 0 pending, 1 active, 2 expired */
|
||||
public static final String STATUS_PENDING = "0";
|
||||
public static final String STATUS_ACTIVE = "1";
|
||||
public static final String STATUS_EXPIRED = "2";
|
||||
private String status;
|
||||
private String sourceSheet;
|
||||
private Long tmsId;
|
||||
private Integer countryCount;
|
||||
private Integer surchargeCount;
|
||||
private List<BmsProductCountry> countries;
|
||||
/**
|
||||
* 查询用:ACTIVE已生效 / PENDING待生效 / EXPIRED已失效
|
||||
* (非表字段,由生效日期+status 推导)
|
||||
*/
|
||||
/** query alias of status (0/1/2) */
|
||||
private String effectStatus;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ public class BmsProductCountry implements Serializable
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long detailId;
|
||||
/** FK to bms_product.product_id (one country version belongs to one product row) */
|
||||
private Long productId;
|
||||
private String productCode;
|
||||
private String countryName;
|
||||
private String countryCode;
|
||||
@@ -28,10 +30,14 @@ public class BmsProductCountry implements Serializable
|
||||
/** null=open; closed to next import effective_date */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date expireDate;
|
||||
/** 0 pending, 1 active, 2 expired */
|
||||
private String status;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createdAt;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updatedAt;
|
||||
/** query only: true = expire_date is null */
|
||||
private Boolean openOnly;
|
||||
/** query alias of status (0/1/2) */
|
||||
private String effectStatus;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.ruoyi.price.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.ruoyi.common.core.domain.BaseEntity;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/** billing quote header prc_quote */
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PrcQuote extends BaseEntity
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long quoteId;
|
||||
private String quoteKey;
|
||||
private Long customerId;
|
||||
private String productCode;
|
||||
private String productName;
|
||||
private String countryCode;
|
||||
private String countryName;
|
||||
private BigDecimal weight;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date bizDate;
|
||||
private Long tmsId;
|
||||
|
||||
private String matchSource;
|
||||
private String matchMessage;
|
||||
private Long priceSetId;
|
||||
private String priceSetCode;
|
||||
private String priceSetName;
|
||||
private String setType;
|
||||
private Integer bindPriority;
|
||||
private Long customerPricesetId;
|
||||
private Long productCountryId;
|
||||
private BigDecimal weightMin;
|
||||
private BigDecimal weightMax;
|
||||
private String weightLabel;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private Date effectiveDate;
|
||||
private BigDecimal chargeWeight;
|
||||
private BigDecimal freightRate;
|
||||
private BigDecimal baseFreightRate;
|
||||
private BigDecimal discountPercent;
|
||||
private BigDecimal registrationFee;
|
||||
private BigDecimal freightAmount;
|
||||
private BigDecimal surchargeAmount;
|
||||
private BigDecimal payableTotal;
|
||||
private String currency;
|
||||
private String roundMode;
|
||||
|
||||
private List<PrcQuoteFee> fees;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ruoyi.price.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
|
||||
/** billing quote fee detail prc_quote_fee, one row per bms_fee_type */
|
||||
@Data
|
||||
public class PrcQuoteFee implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long feeId;
|
||||
private Long quoteId;
|
||||
/** bms_fee_type: BASIC_FREIGHT / REGISTRATION_FEE / SURCHARGE */
|
||||
private String feeType;
|
||||
private String feeName;
|
||||
/** prc_surcharge.sc_id, 0 for freight/registration */
|
||||
private Long scId;
|
||||
private BigDecimal amount;
|
||||
private String currency;
|
||||
private String roundMode;
|
||||
private String remark;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createdAt;
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.ruoyi.price.domain.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
|
||||
/** quote fee line keyed by bms_fee_type */
|
||||
@Data
|
||||
public class TmsPriceQuoteFeeLine implements Serializable
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String feeType;
|
||||
private String feeName;
|
||||
/** surcharge config id, 0 for freight/registration */
|
||||
private Long scId;
|
||||
private BigDecimal amount;
|
||||
private String currency;
|
||||
private String roundMode;
|
||||
private String remark;
|
||||
}
|
||||
+9
-1
@@ -3,6 +3,7 @@ package com.ruoyi.price.domain.vo;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@@ -43,8 +44,15 @@ public class TmsPriceQuoteResult implements Serializable
|
||||
private BigDecimal discountPercent;
|
||||
private BigDecimal registrationFee;
|
||||
private BigDecimal freightAmount;
|
||||
/** 附加费合计(按产品关联命中后汇总) */
|
||||
private BigDecimal surchargeAmount;
|
||||
private BigDecimal payableTotal;
|
||||
private String currency = "RMB";
|
||||
private String currency = "CNY";
|
||||
/** UP / DOWN / HALF_UP */
|
||||
private String roundMode;
|
||||
/** 费用明细:运费/挂号费各一行,附加费按具体名称各一行 */
|
||||
private List<TmsPriceQuoteFeeLine> feeDetails;
|
||||
private Long quoteId;
|
||||
/** true=命中已落库试算 */
|
||||
private Boolean fromCache;
|
||||
}
|
||||
|
||||
+8
-1
@@ -17,9 +17,13 @@ public interface BmsProductCountryMapper
|
||||
|
||||
public int insertBmsProductCountry(BmsProductCountry country);
|
||||
|
||||
public int deleteByProductId(Long productId);
|
||||
|
||||
public int deleteByProductCode(String productCode);
|
||||
|
||||
public int deleteByProductCodes(String[] productCodes);
|
||||
public int deleteByProductCodeAndEffectiveDate(
|
||||
@Param("productCode") String productCode,
|
||||
@Param("effectiveDate") Date effectiveDate);
|
||||
|
||||
/** Max open (expire_date is null) effective_date for product */
|
||||
public Date selectMaxOpenEffectiveDate(@Param("productCode") String productCode);
|
||||
@@ -29,6 +33,9 @@ public interface BmsProductCountryMapper
|
||||
@Param("productCode") String productCode,
|
||||
@Param("newEffectiveDate") Date newEffectiveDate);
|
||||
|
||||
/** Recompute status from effective_date / expire_date vs today */
|
||||
public int refreshStatusByDates();
|
||||
|
||||
/** Replace same-day version only */
|
||||
public int deleteOpenByProductCodeAndEffectiveDate(
|
||||
@Param("productCode") String productCode,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package com.ruoyi.price.mapper;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.price.domain.BmsProduct;
|
||||
|
||||
/**
|
||||
@@ -12,8 +14,17 @@ public interface BmsProductMapper
|
||||
{
|
||||
public BmsProduct selectBmsProductById(Long productId);
|
||||
|
||||
/** Latest row by product_code (effective_date desc) */
|
||||
public BmsProduct selectBmsProductByCode(String productCode);
|
||||
|
||||
/** Unique business key: product_code + effective_date */
|
||||
public BmsProduct selectBmsProductByCodeAndDate(@Param("productCode") String productCode,
|
||||
@Param("effectiveDate") Date effectiveDate);
|
||||
|
||||
/** Product version effective on bizDate */
|
||||
public BmsProduct selectEffectiveBmsProductByCode(@Param("productCode") String productCode,
|
||||
@Param("bizDate") Date bizDate);
|
||||
|
||||
public List<BmsProduct> selectBmsProductList(BmsProduct product);
|
||||
|
||||
public int insertBmsProduct(BmsProduct product);
|
||||
@@ -21,4 +32,13 @@ public interface BmsProductMapper
|
||||
public int updateBmsProduct(BmsProduct product);
|
||||
|
||||
public int deleteBmsProductByIds(Long[] productIds);
|
||||
|
||||
/** Close previous open versions: expire_date = newEffectiveDate */
|
||||
public int expireOpenByProductCode(
|
||||
@Param("productCode") String productCode,
|
||||
@Param("newEffectiveDate") Date newEffectiveDate,
|
||||
@Param("excludeId") Long excludeId);
|
||||
|
||||
/** Recompute status from effective_date / expire_date vs today */
|
||||
public int refreshStatusByDates();
|
||||
}
|
||||
|
||||
+5
@@ -25,6 +25,11 @@ public interface PrcCustomerPriceSetMapper
|
||||
|
||||
public int countByPriceSetId(Long priceSetId);
|
||||
|
||||
/** Count binds of this customer; optional exclude current bind or current set */
|
||||
public int countByCustomerId(@Param("customerId") Long customerId,
|
||||
@Param("excludeId") Long excludeId,
|
||||
@Param("excludePriceSetId") Long excludePriceSetId);
|
||||
|
||||
public int countOverlap(@Param("customerId") Long customerId,
|
||||
@Param("priceSetId") Long priceSetId,
|
||||
@Param("beginDate") java.util.Date beginDate,
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.ruoyi.price.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.price.domain.PrcQuoteFee;
|
||||
|
||||
/** billing quote fee detail mapper */
|
||||
public interface PrcQuoteFeeMapper
|
||||
{
|
||||
public List<PrcQuoteFee> selectByQuoteId(Long quoteId);
|
||||
|
||||
public int insertPrcQuoteFee(PrcQuoteFee fee);
|
||||
|
||||
public int insertBatch(@Param("list") List<PrcQuoteFee> fees);
|
||||
|
||||
public int deleteByQuoteId(Long quoteId);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ruoyi.price.mapper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import com.ruoyi.price.domain.PrcQuote;
|
||||
|
||||
/** billing quote header mapper */
|
||||
public interface PrcQuoteMapper
|
||||
{
|
||||
public PrcQuote selectPrcQuoteByKey(String quoteKey);
|
||||
|
||||
public PrcQuote selectPrcQuoteById(Long quoteId);
|
||||
|
||||
public List<PrcQuote> selectPrcQuoteList(PrcQuote quote);
|
||||
|
||||
public int insertPrcQuote(PrcQuote quote);
|
||||
|
||||
public int updateQuoteAmounts(@Param("quoteId") Long quoteId,
|
||||
@Param("surchargeAmount") BigDecimal surchargeAmount,
|
||||
@Param("payableTotal") BigDecimal payableTotal);
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.ruoyi.price.service;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.price.domain.BmsProduct;
|
||||
@@ -24,11 +25,15 @@ public interface IBmsProductService
|
||||
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode);
|
||||
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode, Date effectiveDate);
|
||||
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode, Date effectiveDate, Long productId);
|
||||
|
||||
/**
|
||||
* 导入威狮B2C小包价表:产品目录 + 各产品 sheet 国家×重量段(含运费/挂号费/尺寸/尾程/时效)
|
||||
*
|
||||
* @param file 上传的 xlsx/xls
|
||||
* @param updateSupport 是否更新已存在产品
|
||||
* @param updateSupport unused; same code+date never overwrites, different date always inserts
|
||||
* @param operName 操作人
|
||||
* @return 导入结果说明(可含 HTML 换行)
|
||||
*/
|
||||
|
||||
@@ -1,17 +1,24 @@
|
||||
package com.ruoyi.price.service;
|
||||
|
||||
import com.ruoyi.price.domain.PrcQuote;
|
||||
import com.ruoyi.price.domain.vo.TmsPriceQuoteRequest;
|
||||
import com.ruoyi.price.domain.vo.TmsPriceQuoteResult;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TMS freight quote service.
|
||||
*
|
||||
* Match order: effective customer package (bind_priority ASC) FIXED override
|
||||
* then DISCOUNT, else bms_product_country default freight/registration.
|
||||
* After calc, persist fee lines by bms_fee_type; same trial params return stored result.
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public interface ITmsPriceQuoteService
|
||||
{
|
||||
TmsPriceQuoteResult quote(TmsPriceQuoteRequest request);
|
||||
|
||||
List<PrcQuote> selectQuoteList(PrcQuote query);
|
||||
|
||||
TmsPriceQuoteResult getQuote(Long quoteId);
|
||||
}
|
||||
|
||||
+276
-76
@@ -26,6 +26,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.BmsProduct;
|
||||
import com.ruoyi.price.domain.BmsProductCountry;
|
||||
@@ -50,6 +51,10 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
private static final Pattern EFFECTIVE_DATE_PATTERN = Pattern.compile(
|
||||
"\u751f\u6548\u65e5\u671f[\uff1a:]\\s*(\\d{4})[/.-](\\d{1,2})[/.-](\\d{1,2})");
|
||||
private static final Pattern EFFECTIVE_DATE_YMD = Pattern.compile(
|
||||
"(\\d{4})[/.-](\\d{1,2})[/.-](\\d{1,2})");
|
||||
private static final Pattern EFFECTIVE_DATE_CN = Pattern.compile(
|
||||
"(\\d{4})\\s*\u5e74\\s*(\\d{1,2})\\s*\u6708\\s*(\\d{1,2})");
|
||||
|
||||
/** Parse 0.01\u2264W\u22640.3 / 0.3<W\u22641 */
|
||||
private static final Pattern WEIGHT_RANGE_PATTERN = Pattern.compile(
|
||||
@@ -77,26 +82,44 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
@Override
|
||||
public List<BmsProduct> selectBmsProductList(BmsProduct product)
|
||||
{
|
||||
productMapper.refreshStatusByDates();
|
||||
countryMapper.refreshStatusByDates();
|
||||
if (product != null)
|
||||
{
|
||||
product.setStatus(normalizeStatusCode(product.getStatus()));
|
||||
product.setEffectStatus(normalizeStatusCode(product.getEffectStatus()));
|
||||
}
|
||||
return productMapper.selectBmsProductList(product);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int insertBmsProduct(BmsProduct product)
|
||||
{
|
||||
if (StringUtils.isEmpty(product.getStatus()))
|
||||
{
|
||||
product.setStatus("0");
|
||||
}
|
||||
if (StringUtils.isEmpty(product.getTaxMode()))
|
||||
{
|
||||
product.setTaxMode(resolveTaxMode(product.getProductName()));
|
||||
}
|
||||
return productMapper.insertBmsProduct(product);
|
||||
if (product.getEffectiveDate() == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.effectiveDate.empty"));
|
||||
}
|
||||
applyProductStatus(product);
|
||||
assertCodeDateUnique(product, null);
|
||||
int rows = productMapper.insertBmsProduct(product);
|
||||
productMapper.expireOpenByProductCode(product.getProductCode(), product.getEffectiveDate(), product.getProductId());
|
||||
productMapper.refreshStatusByDates();
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int updateBmsProduct(BmsProduct product)
|
||||
{
|
||||
if (product.getEffectiveDate() == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.effectiveDate.empty"));
|
||||
}
|
||||
applyProductStatus(product);
|
||||
assertCodeDateUnique(product, product.getProductId());
|
||||
return productMapper.updateBmsProduct(product);
|
||||
}
|
||||
|
||||
@@ -108,44 +131,94 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
List<String> codes = new ArrayList<>();
|
||||
List<String> codesNoRemain = new ArrayList<>();
|
||||
for (Long id : productIds)
|
||||
{
|
||||
BmsProduct p = productMapper.selectBmsProductById(id);
|
||||
if (p != null && StringUtils.isNotEmpty(p.getProductCode()))
|
||||
if (p == null || StringUtils.isEmpty(p.getProductCode()))
|
||||
{
|
||||
codes.add(p.getProductCode());
|
||||
continue;
|
||||
}
|
||||
if (p.getProductId() != null)
|
||||
{
|
||||
countryMapper.deleteByProductId(p.getProductId());
|
||||
}
|
||||
countryMapper.deleteByProductCodeAndEffectiveDate(p.getProductCode(), p.getEffectiveDate());
|
||||
codesNoRemain.add(p.getProductCode());
|
||||
}
|
||||
int rows = productMapper.deleteBmsProductByIds(productIds);
|
||||
List<String> orphanCodes = new ArrayList<>();
|
||||
for (String code : codesNoRemain)
|
||||
{
|
||||
if (productMapper.selectBmsProductByCode(code) == null)
|
||||
{
|
||||
orphanCodes.add(code);
|
||||
}
|
||||
}
|
||||
if (!codes.isEmpty())
|
||||
if (!orphanCodes.isEmpty())
|
||||
{
|
||||
countryMapper.deleteByProductCodes(codes.toArray(new String[0]));
|
||||
surchargeRelService.deleteRelByProductCodes(codes.toArray(new String[0]));
|
||||
surchargeRelService.deleteRelByProductCodes(orphanCodes.toArray(new String[0]));
|
||||
}
|
||||
return productMapper.deleteBmsProductByIds(productIds);
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode)
|
||||
{
|
||||
return selectCountryListByProductCode(productCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode, Date effectiveDate)
|
||||
{
|
||||
return selectCountryListByProductCode(productCode, effectiveDate, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BmsProductCountry> selectCountryListByProductCode(String productCode, Date effectiveDate, Long productId)
|
||||
{
|
||||
if (productId != null)
|
||||
{
|
||||
BmsProductCountry byId = new BmsProductCountry();
|
||||
byId.setProductId(productId);
|
||||
List<BmsProductCountry> list = countryMapper.selectBmsProductCountryList(byId);
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
return list;
|
||||
}
|
||||
}
|
||||
BmsProductCountry query = new BmsProductCountry();
|
||||
query.setProductCode(productCode);
|
||||
query.setEffectiveDate(effectiveDate);
|
||||
return countryMapper.selectBmsProductCountryList(query);
|
||||
}
|
||||
|
||||
private void assertCodeDateUnique(BmsProduct product, Long excludeId)
|
||||
{
|
||||
if (product == null || StringUtils.isEmpty(product.getProductCode()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
BmsProduct dup = productMapper.selectBmsProductByCodeAndDate(product.getProductCode(), product.getEffectiveDate());
|
||||
if (dup != null && (excludeId == null || !excludeId.equals(dup.getProductId())))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.codeDate.exists"));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public String importProductExcel(MultipartFile file, boolean updateSupport, String operName) throws Exception
|
||||
{
|
||||
if (file == null || file.isEmpty())
|
||||
{
|
||||
throw new ServiceException("\u4e0a\u4f20\u6587\u4ef6\u4e0d\u80fd\u4e3a\u7a7a");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.fileEmpty"));
|
||||
}
|
||||
String filename = file.getOriginalFilename();
|
||||
if (filename == null || !(filename.toLowerCase(Locale.ROOT).endsWith(".xlsx")
|
||||
|| filename.toLowerCase(Locale.ROOT).endsWith(".xls")))
|
||||
{
|
||||
throw new ServiceException("\u4ec5\u652f\u6301 xls / xlsx \u6587\u4ef6");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.fileType"));
|
||||
}
|
||||
|
||||
try (InputStream is = file.getInputStream(); Workbook workbook = WorkbookFactory.create(is))
|
||||
@@ -153,23 +226,22 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
Sheet catalog = workbook.getSheet(CATALOG_SHEET);
|
||||
if (catalog == null)
|
||||
{
|
||||
throw new ServiceException("\u672a\u627e\u5230\u300c\u4ea7\u54c1\u76ee\u5f55\u300dsheet\uff0c\u8bf7\u4e0a\u4f20\u5a01\u72eeB2C\u5c0f\u5305\u4ef7\u8868\u683c\u5f0f\u6587\u4ef6");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.sheetNotFound"));
|
||||
}
|
||||
|
||||
List<BmsProduct> products = parseCatalog(catalog);
|
||||
if (products.isEmpty())
|
||||
{
|
||||
throw new ServiceException("\u4ea7\u54c1\u76ee\u5f55\u65e0\u6709\u6548\u6570\u636e\u884c");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.noData"));
|
||||
}
|
||||
|
||||
Map<String, BmsRegion> regionByNameCn = loadRegionByNameCn();
|
||||
if (regionByNameCn.isEmpty())
|
||||
{
|
||||
throw new ServiceException("bms_region \u65e0\u53ef\u7528\u56fd\u5bb6\u6570\u636e\uff0c\u8bf7\u5148\u540c\u6b65/\u7ef4\u62a4\u56fd\u5bb6\u8868\u540e\u518d\u5bfc\u5165");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.regionEmpty"));
|
||||
}
|
||||
|
||||
int successNum = 0;
|
||||
int updateNum = 0;
|
||||
int skipNum = 0;
|
||||
int countryNum = 0;
|
||||
Set<String> unmatchedCountries = new HashSet<>();
|
||||
@@ -184,31 +256,42 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
product.setUpdateBy(operName);
|
||||
|
||||
List<BmsProductCountry> countries = parseProductSheet(workbook, product, regionByNameCn, unmatchedCountries);
|
||||
BmsProduct existing = productMapper.selectBmsProductByCode(product.getProductCode());
|
||||
// Sheet header date is the price version; catalog column is often stale
|
||||
Date sheetEff = resolveImportEffectiveDate(countries);
|
||||
Date newEff = toDateOnly(sheetEff != null ? sheetEff : product.getEffectiveDate());
|
||||
product.setEffectiveDate(newEff);
|
||||
if (newEff == null)
|
||||
{
|
||||
failureMsg.append("<br/>").append(product.getProductCode()).append("\uff1a")
|
||||
.append(MessageUtils.message("price.product.import.effEmpty"));
|
||||
continue;
|
||||
}
|
||||
BmsProduct existing = productMapper.selectBmsProductByCodeAndDate(
|
||||
product.getProductCode(), newEff);
|
||||
|
||||
if (existing == null)
|
||||
if (existing != null)
|
||||
{
|
||||
product.setStatus("0");
|
||||
productMapper.insertBmsProduct(product);
|
||||
countryNum += saveCountriesVersioned(product.getProductCode(), countries);
|
||||
successNum++;
|
||||
}
|
||||
else if (updateSupport)
|
||||
{
|
||||
product.setProductId(existing.getProductId());
|
||||
productMapper.updateBmsProduct(product);
|
||||
countryNum += saveCountriesVersioned(product.getProductCode(), countries);
|
||||
updateNum++;
|
||||
}
|
||||
else if (!countries.isEmpty())
|
||||
{
|
||||
// Keep product master; version country rows by effective_date
|
||||
countryNum += saveCountriesVersioned(product.getProductCode(), countries);
|
||||
updateNum++;
|
||||
skipNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
skipNum++;
|
||||
applyProductStatus(product);
|
||||
try
|
||||
{
|
||||
productMapper.insertBmsProduct(product);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (isProductCodeUniqueViolation(e))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.needCodeEffUnique"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
productMapper.expireOpenByProductCode(product.getProductCode(), newEff, product.getProductId());
|
||||
productMapper.refreshStatusByDates();
|
||||
countryNum += saveCountriesVersioned(product, countries);
|
||||
successNum++;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -219,16 +302,15 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
if (failureMsg.length() > 0)
|
||||
{
|
||||
throw new ServiceException("\u5bfc\u5165\u5b8c\u6210\u4f46\u5b58\u5728\u5931\u8d25\u9879\uff1a\u65b0\u589e " + successNum + "\uff0c\u66f4\u65b0 " + updateNum
|
||||
+ "\uff0c\u8df3\u8fc7 " + skipNum + "\uff1b\u5931\u8d25\u660e\u7ec6\uff1a" + failureMsg);
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.partialFail",
|
||||
successNum, skipNum, failureMsg.toString()));
|
||||
}
|
||||
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/>\u56fd\u5bb6\u660e\u7ec6\uff1a\u82e5\u65b0\u751f\u6548\u65e5\u665a\u4e8e\u4e0a\u6b21\uff0c\u4fdd\u7559\u5386\u53f2\u7248\u4e14\u4e0a\u6b21\u5931\u6548\u65e5=\u672c\u6b21\u751f\u6548\u65e5\uff1b\u540c\u65e5\u5219\u66ff\u6362\u5f53\u524d\u5f00\u653e\u7248\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";
|
||||
String msg = MessageUtils.message("price.product.import.success", successNum, skipNum, countryNum)
|
||||
+ "<br/>" + MessageUtils.message("price.product.import.success.detail1")
|
||||
+ "<br/>" + MessageUtils.message("price.product.import.success.detail2");
|
||||
if (!unmatchedCountries.isEmpty())
|
||||
{
|
||||
msg += "<br/>\u672a\u5339\u914d\u56fd\u5bb6\u8868\uff08country_code \u4e3a\u7a7a\uff09\uff1a" + String.join("\u3001", unmatchedCountries);
|
||||
msg += "<br/>" + MessageUtils.message("price.product.import.success.unmatched", String.join("\u3001", unmatchedCountries));
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
@@ -236,45 +318,49 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
/**
|
||||
* Versioned country save:
|
||||
* - newEff > last open eff: close old (expire_date = newEff), insert new (keep history)
|
||||
* - newEff equals last open: replace that open version only
|
||||
* - newEff > last open: close old (expire_date = newEff), insert new (keep history)
|
||||
* - newEff equals last open: skip (never overwrite)
|
||||
* - newEff < last open: reject
|
||||
*/
|
||||
private int saveCountriesVersioned(String productCode, List<BmsProductCountry> countries)
|
||||
private int saveCountriesVersioned(BmsProduct product, List<BmsProductCountry> countries)
|
||||
{
|
||||
if (countries == null || countries.isEmpty())
|
||||
if (product == null || countries == null || countries.isEmpty())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
String productCode = product.getProductCode();
|
||||
Long productId = product.getProductId();
|
||||
Date newEff = resolveImportEffectiveDate(countries);
|
||||
Date lastOpenEff = countryMapper.selectMaxOpenEffectiveDate(productCode);
|
||||
|
||||
if (lastOpenEff != null && newEff != null && newEff.before(lastOpenEff))
|
||||
{
|
||||
throw new ServiceException("\u751f\u6548\u65e5\u671f "
|
||||
+ formatDate(newEff) + " \u65e9\u4e8e\u5f53\u524d\u5f00\u653e\u7248 "
|
||||
+ formatDate(lastOpenEff) + "\uff0c\u8bf7\u4f7f\u7528\u66f4\u665a\u7684\u751f\u6548\u65e5\u671f\u5bfc\u5165");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.effTooEarly",
|
||||
formatDate(newEff), formatDate(lastOpenEff)));
|
||||
}
|
||||
|
||||
if (lastOpenEff != null && newEff != null && newEff.after(lastOpenEff))
|
||||
{
|
||||
// Previous open version expire_date = this effective_date; keep old rows
|
||||
countryMapper.expireOpenByProductCode(productCode, newEff);
|
||||
countryMapper.refreshStatusByDates();
|
||||
}
|
||||
else if (lastOpenEff != null)
|
||||
{
|
||||
// Same effective day (or both null): replace current open version only
|
||||
countryMapper.deleteOpenByProductCodeAndEffectiveDate(productCode, newEff);
|
||||
// Same effective day: never overwrite existing country rows
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (BmsProductCountry c : countries)
|
||||
{
|
||||
c.setProductId(productId);
|
||||
c.setProductCode(productCode);
|
||||
c.setExpireDate(null);
|
||||
if (c.getEffectiveDate() == null)
|
||||
{
|
||||
c.setEffectiveDate(newEff);
|
||||
}
|
||||
c.setStatus(resolveStoredStatus(c.getEffectiveDate(), c.getExpireDate()));
|
||||
try
|
||||
{
|
||||
countryMapper.insertBmsProductCountry(c);
|
||||
@@ -284,13 +370,11 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
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 new ServiceException(MessageUtils.message("price.product.import.needFeeAlter"));
|
||||
}
|
||||
if (tip.contains("expire_date") || tip.contains("uk_product_country_weight"))
|
||||
{
|
||||
throw new ServiceException(
|
||||
"\u8bf7\u5148\u6267\u884c SQL\uff1abms-back/sql/price/product_country_expire_alter.sql\uff08\u7f3a\u5c11\u5931\u6548\u65e5\u671f/\u7248\u672c\u552f\u4e00\u952e\uff09");
|
||||
throw new ServiceException(MessageUtils.message("price.product.import.needExpireAlter"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
@@ -324,9 +408,93 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
return new SimpleDateFormat("yyyy-MM-dd").format(d);
|
||||
}
|
||||
|
||||
private Date toDateOnly(Date d)
|
||||
{
|
||||
if (d == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(formatDate(d));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
/** 0 pending / 1 active / 2 expired from dates vs today */
|
||||
private String resolveStoredStatus(Date effectiveDate, Date expireDate)
|
||||
{
|
||||
Date today = toDateOnly(new Date());
|
||||
Date expire = toDateOnly(expireDate);
|
||||
Date eff = toDateOnly(effectiveDate);
|
||||
if (expire != null && today != null && !expire.after(today))
|
||||
{
|
||||
return BmsProduct.STATUS_EXPIRED;
|
||||
}
|
||||
if (eff == null || (today != null && eff.after(today)))
|
||||
{
|
||||
return BmsProduct.STATUS_PENDING;
|
||||
}
|
||||
return BmsProduct.STATUS_ACTIVE;
|
||||
}
|
||||
|
||||
private void applyProductStatus(BmsProduct product)
|
||||
{
|
||||
if (product == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
product.setStatus(resolveStoredStatus(product.getEffectiveDate(), product.getExpireDate()));
|
||||
}
|
||||
|
||||
/** Map ACTIVE/PENDING/EXPIRED or 0/1/2 to stored status code. */
|
||||
private String normalizeStatusCode(String status)
|
||||
{
|
||||
if (status == null || status.isEmpty())
|
||||
{
|
||||
return status;
|
||||
}
|
||||
if ("ACTIVE".equalsIgnoreCase(status) || BmsProduct.STATUS_ACTIVE.equals(status))
|
||||
{
|
||||
return BmsProduct.STATUS_ACTIVE;
|
||||
}
|
||||
if ("PENDING".equalsIgnoreCase(status) || BmsProduct.STATUS_PENDING.equals(status))
|
||||
{
|
||||
return BmsProduct.STATUS_PENDING;
|
||||
}
|
||||
if ("EXPIRED".equalsIgnoreCase(status) || BmsProduct.STATUS_EXPIRED.equals(status))
|
||||
{
|
||||
return BmsProduct.STATUS_EXPIRED;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
private boolean isProductCodeUniqueViolation(Throwable e)
|
||||
{
|
||||
while (e != null)
|
||||
{
|
||||
String m = e.getMessage();
|
||||
if (m != null && m.contains("uk_product_code") && !m.contains("uk_product_code_eff"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (m != null && m.contains("Duplicate") && m.contains("product_code") && !m.contains("effective"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
e = e.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void saveCountries(String productCode, List<BmsProductCountry> countries)
|
||||
{
|
||||
saveCountriesVersioned(productCode, countries);
|
||||
BmsProduct p = new BmsProduct();
|
||||
p.setProductCode(productCode);
|
||||
saveCountriesVersioned(p, countries);
|
||||
}
|
||||
|
||||
private List<BmsProduct> parseCatalog(Sheet sheet)
|
||||
@@ -593,35 +761,67 @@ public class BmsProductServiceImpl implements IBmsProductService
|
||||
|
||||
private Date parseSheetEffectiveDate(Sheet sheet)
|
||||
{
|
||||
Row row0 = sheet.getRow(0);
|
||||
if (row0 == null)
|
||||
int lastRow = Math.min(sheet.getLastRowNum(), 4);
|
||||
for (int r = 0; r <= lastRow; r++)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
for (int c = 0; c < 12; c++)
|
||||
{
|
||||
String text = cellString(row0.getCell(c));
|
||||
if (StringUtils.isEmpty(text))
|
||||
Row row = sheet.getRow(r);
|
||||
if (row == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Matcher m = EFFECTIVE_DATE_PATTERN.matcher(text);
|
||||
if (m.find())
|
||||
int lastCell = Math.max(row.getLastCellNum(), 12);
|
||||
lastCell = Math.min(lastCell, 20);
|
||||
for (int c = 0; c < lastCell; c++)
|
||||
{
|
||||
try
|
||||
Date parsed = parseEffectiveDateText(cellString(row.getCell(c)));
|
||||
if (parsed != null)
|
||||
{
|
||||
String d = m.group(1) + "-" + pad2(m.group(2)) + "-" + pad2(m.group(3));
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(d);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
return null;
|
||||
return parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Date parseEffectiveDateText(String text)
|
||||
{
|
||||
if (StringUtils.isEmpty(text))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Matcher labeled = EFFECTIVE_DATE_PATTERN.matcher(text);
|
||||
if (labeled.find())
|
||||
{
|
||||
return parseYmd(labeled.group(1), labeled.group(2), labeled.group(3));
|
||||
}
|
||||
Matcher cn = EFFECTIVE_DATE_CN.matcher(text);
|
||||
if (cn.find())
|
||||
{
|
||||
return parseYmd(cn.group(1), cn.group(2), cn.group(3));
|
||||
}
|
||||
if (text.contains("\u751f\u6548"))
|
||||
{
|
||||
Matcher ymd = EFFECTIVE_DATE_YMD.matcher(text);
|
||||
if (ymd.find())
|
||||
{
|
||||
return parseYmd(ymd.group(1), ymd.group(2), ymd.group(3));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Date parseYmd(String y, String m, String d)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(y + "-" + pad2(m) + "-" + pad2(d));
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static String pad2(String n)
|
||||
{
|
||||
return n.length() == 1 ? "0" + n : n;
|
||||
|
||||
+101
-40
@@ -11,6 +11,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.DateUtils;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.BmsProductCountry;
|
||||
import com.ruoyi.price.domain.PrcCustomerPriceSet;
|
||||
@@ -139,12 +140,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(id);
|
||||
if (!STATUS_DRAFT.equals(db.getStatus()) && !STATUS_REJECT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("仅草稿或驳回状态的套餐允许删除:" + displayName(db));
|
||||
throw new ServiceException(MessageUtils.message("price.set.delete.statusNotAllowed", displayName(db)));
|
||||
}
|
||||
int bound = customerMapper.countByPriceSetId(id);
|
||||
if (bound > 0)
|
||||
{
|
||||
throw new ServiceException("套餐【" + displayName(db) + "】已绑定客户,请先解绑后再删除");
|
||||
throw new ServiceException(MessageUtils.message("price.set.delete.boundCustomer", displayName(db)));
|
||||
}
|
||||
detailMapper.deletePrcPriceSetDetailByPriceSetId(id);
|
||||
}
|
||||
@@ -157,7 +158,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(priceSetId);
|
||||
if (!STATUS_DRAFT.equals(db.getStatus()) && !STATUS_REJECT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("当前状态不允许提交审核");
|
||||
throw new ServiceException(MessageUtils.message("price.set.submit.statusNotAllowed"));
|
||||
}
|
||||
PrcPriceSet payload = selectPrcPriceSetById(priceSetId);
|
||||
List<PrcPriceSetCheckItem> items = validate(payload);
|
||||
@@ -175,7 +176,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(priceSetId);
|
||||
if (!STATUS_AUDIT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("仅审核中的套餐可以生效");
|
||||
throw new ServiceException(MessageUtils.message("price.set.approve.statusNotAllowed"));
|
||||
}
|
||||
PrcPriceSet upd = new PrcPriceSet();
|
||||
upd.setPriceSetId(priceSetId);
|
||||
@@ -190,7 +191,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(priceSetId);
|
||||
if (!STATUS_AUDIT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("仅审核中的套餐可以驳回");
|
||||
throw new ServiceException(MessageUtils.message("price.set.reject.statusNotAllowed"));
|
||||
}
|
||||
PrcPriceSet upd = new PrcPriceSet();
|
||||
upd.setPriceSetId(priceSetId);
|
||||
@@ -205,7 +206,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(priceSetId);
|
||||
if (!STATUS_EFFECT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("仅生效中的套餐可以停用");
|
||||
throw new ServiceException(MessageUtils.message("price.set.disable.statusNotAllowed"));
|
||||
}
|
||||
PrcPriceSet upd = new PrcPriceSet();
|
||||
upd.setPriceSetId(priceSetId);
|
||||
@@ -221,7 +222,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet src = selectPrcPriceSetById(priceSetId);
|
||||
if (src == null)
|
||||
{
|
||||
throw new ServiceException("套餐不存在");
|
||||
throw new ServiceException(MessageUtils.message("price.set.notExists"));
|
||||
}
|
||||
PrcPriceSet copy = new PrcPriceSet();
|
||||
copy.setPriceSetName(src.getPriceSetName() + "-副本");
|
||||
@@ -405,24 +406,37 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
}
|
||||
|
||||
List<PrcCustomerPriceSet> customers = filterCustomers(set.getCustomers());
|
||||
int overlap = 0;
|
||||
Set<Long> seenCustomers = new HashSet<Long>();
|
||||
int bound = 0;
|
||||
boolean dupInSet = false;
|
||||
for (PrcCustomerPriceSet c : customers)
|
||||
{
|
||||
overlap += customerMapper.countOverlap(c.getCustomerId(), set.getPriceSetId(),
|
||||
c.getPrBegindate() != null ? c.getPrBegindate() : set.getEffectiveDate(),
|
||||
c.getPrEnddate() != null ? c.getPrEnddate() : set.getExpireDate());
|
||||
if (c.getCustomerId() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!seenCustomers.add(c.getCustomerId()))
|
||||
{
|
||||
dupInSet = true;
|
||||
continue;
|
||||
}
|
||||
bound += customerMapper.countByCustomerId(c.getCustomerId(), c.getCustomerPricesetId(),
|
||||
set.getPriceSetId());
|
||||
}
|
||||
if (overlap > 0)
|
||||
if (dupInSet || bound > 0)
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("与同客户现有套餐是否冲突", "WARN", "存在 " + overlap + " 条与已生效套餐日期重叠的客户绑定,可共存但需确认优先级"));
|
||||
items.add(new PrcPriceSetCheckItem("\u4e00\u4e2a\u5ba2\u6237\u53ea\u80fd\u7ed1\u5b9a\u4e00\u4e2a\u5957\u9910", "FAIL",
|
||||
MessageUtils.message("price.set.customer.alreadyBound")));
|
||||
}
|
||||
else if (customers.isEmpty())
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("与同客户现有套餐是否冲突", "INFO", "暂未绑定客户,可后续补充"));
|
||||
items.add(new PrcPriceSetCheckItem("\u4e00\u4e2a\u5ba2\u6237\u53ea\u80fd\u7ed1\u5b9a\u4e00\u4e2a\u5957\u9910", "INFO",
|
||||
"\u6682\u672a\u7ed1\u5b9a\u5ba2\u6237\uff0c\u53ef\u540e\u7eed\u8865\u5145"));
|
||||
}
|
||||
else
|
||||
{
|
||||
items.add(new PrcPriceSetCheckItem("与同客户现有套餐是否冲突", "PASS", "未发现与已生效套餐的日期重叠"));
|
||||
items.add(new PrcPriceSetCheckItem("\u4e00\u4e2a\u5ba2\u6237\u53ea\u80fd\u7ed1\u5b9a\u4e00\u4e2a\u5957\u9910", "PASS",
|
||||
"\u5ba2\u6237\u672a\u7ed1\u5b9a\u5176\u4ed6\u5957\u9910"));
|
||||
}
|
||||
|
||||
if (TYPE_FIXED.equals(setType) && !details.isEmpty())
|
||||
@@ -462,7 +476,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSetDetail old = detailMapper.selectPrcPriceSetDetailById(detail.getPsdId());
|
||||
if (old == null)
|
||||
{
|
||||
throw new ServiceException("套餐明细不存在");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.notExists"));
|
||||
}
|
||||
PrcPriceSet db = requireSet(old.getPriceSetId());
|
||||
assertChildEditable(db);
|
||||
@@ -503,7 +517,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
customer.setBindPriority(1);
|
||||
}
|
||||
return customerMapper.insertPrcCustomerPriceSet(customer);
|
||||
try
|
||||
{
|
||||
return customerMapper.insertPrcCustomerPriceSet(customer);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (isCustomerUniqueViolation(e))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.alreadyBound"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -512,7 +537,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcCustomerPriceSet old = customerMapper.selectPrcCustomerPriceSetById(customer.getCustomerPricesetId());
|
||||
if (old == null)
|
||||
{
|
||||
throw new ServiceException("客户绑定不存在");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.notExists"));
|
||||
}
|
||||
PrcPriceSet db = requireSet(old.getPriceSetId());
|
||||
assertChildEditable(db);
|
||||
@@ -534,7 +559,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = requireSet(old.getPriceSetId());
|
||||
if (STATUS_AUDIT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("审核中的套餐不允许解绑客户");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.unbindAudit"));
|
||||
}
|
||||
}
|
||||
return customerMapper.deletePrcCustomerPriceSetByIds(customerPricesetIds);
|
||||
@@ -556,8 +581,13 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
if (set.getCustomers() != null)
|
||||
{
|
||||
customerMapper.deletePrcCustomerPriceSetByPriceSetId(set.getPriceSetId());
|
||||
Set<Long> seenCustomers = new HashSet<Long>();
|
||||
for (PrcCustomerPriceSet c : filterCustomers(set.getCustomers()))
|
||||
{
|
||||
if (c.getCustomerId() != null && !seenCustomers.add(c.getCustomerId()))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.alreadyBound"));
|
||||
}
|
||||
validateCustomer(c, set);
|
||||
c.setCustomerPricesetId(null);
|
||||
c.setPriceSetId(set.getPriceSetId());
|
||||
@@ -566,7 +596,18 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
c.setBindPriority(1);
|
||||
}
|
||||
customerMapper.insertPrcCustomerPriceSet(c);
|
||||
try
|
||||
{
|
||||
customerMapper.insertPrcCustomerPriceSet(c);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (isCustomerUniqueViolation(e))
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.alreadyBound"));
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,15 +616,15 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
if (StringUtils.isEmpty(set.getPriceSetName()))
|
||||
{
|
||||
throw new ServiceException("套餐名称不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.set.name.empty"));
|
||||
}
|
||||
if (set.getEffectiveDate() == null)
|
||||
{
|
||||
throw new ServiceException("生效日期不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.set.effectiveDate.empty"));
|
||||
}
|
||||
if (set.getExpireDate() != null && set.getEffectiveDate().after(set.getExpireDate()))
|
||||
{
|
||||
throw new ServiceException("生效日期不能晚于失效日期");
|
||||
throw new ServiceException(MessageUtils.message("price.set.date.invalid"));
|
||||
}
|
||||
if (TYPE_DISCOUNT.equals(set.getSetType()))
|
||||
{
|
||||
@@ -591,12 +632,12 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
|| set.getDefaultDiscount().compareTo(BigDecimal.ONE) < 0
|
||||
|| set.getDefaultDiscount().compareTo(new BigDecimal("99")) > 0)
|
||||
{
|
||||
throw new ServiceException("折扣模式默认折扣需在 1~99");
|
||||
throw new ServiceException(MessageUtils.message("price.set.discount.range"));
|
||||
}
|
||||
}
|
||||
if (setMapper.countByName(set) > 0)
|
||||
{
|
||||
throw new ServiceException("套餐名称已存在");
|
||||
throw new ServiceException(MessageUtils.message("price.set.name.exists"));
|
||||
}
|
||||
if (strictSubmit)
|
||||
{
|
||||
@@ -608,25 +649,25 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
if (StringUtils.isEmpty(detail.getProductCode()))
|
||||
{
|
||||
throw new ServiceException("明细产品代码不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.productCode.empty"));
|
||||
}
|
||||
if (TYPE_FIXED.equals(set.getSetType()))
|
||||
{
|
||||
if (StringUtils.isEmpty(detail.getCountryCode()) && StringUtils.isEmpty(detail.getCountryName()))
|
||||
{
|
||||
throw new ServiceException("\u56fa\u5b9a\u4ef7\u660e\u7ec6\u5fc5\u987b\u586b\u5199\u56fd\u5bb6");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.country.empty"));
|
||||
}
|
||||
if (detail.getWsdId() == null && StringUtils.isEmpty(detail.getWeightLabel()))
|
||||
{
|
||||
throw new ServiceException("固定价明细必须填写重量段");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.weight.empty"));
|
||||
}
|
||||
if (detail.getFvValue() == null)
|
||||
{
|
||||
throw new ServiceException("固定价明细必须填写运费单价");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.freight.empty"));
|
||||
}
|
||||
if (detail.getFvRegistrationFee() == null)
|
||||
{
|
||||
throw new ServiceException("固定价明细必须填写挂号费");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.registration.empty"));
|
||||
}
|
||||
fillProductCountryId(detail);
|
||||
}
|
||||
@@ -639,7 +680,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
String mode = detail.getRoundMode().trim().toUpperCase();
|
||||
if (!"UP".equals(mode) && !"DOWN".equals(mode) && !"HALF_UP".equals(mode))
|
||||
{
|
||||
throw new ServiceException("取值方式仅支持 UP / DOWN / HALF_UP");
|
||||
throw new ServiceException(MessageUtils.message("price.set.detail.roundMode.invalid"));
|
||||
}
|
||||
detail.setRoundMode(mode);
|
||||
}
|
||||
@@ -720,7 +761,7 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
if (customer.getCustomerId() == null || customer.getCustomerId().longValue() <= 0)
|
||||
{
|
||||
throw new ServiceException("客户ID不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.customerId.empty"));
|
||||
}
|
||||
if (customer.getPrBegindate() == null)
|
||||
{
|
||||
@@ -728,15 +769,21 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
}
|
||||
if (customer.getPrBegindate() == null)
|
||||
{
|
||||
throw new ServiceException("客户绑定生效日期不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.beginDate.empty"));
|
||||
}
|
||||
if (customer.getPrEnddate() != null && customer.getPrBegindate().after(customer.getPrEnddate()))
|
||||
{
|
||||
throw new ServiceException("客户绑定生效日期不能晚于失效日期");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.date.invalid"));
|
||||
}
|
||||
if (customer.getBindPriority() != null && customer.getBindPriority().intValue() < 1)
|
||||
{
|
||||
throw new ServiceException("优先级必须大于等于 1");
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.priority.invalid"));
|
||||
}
|
||||
int exists = customerMapper.countByCustomerId(customer.getCustomerId(),
|
||||
customer.getCustomerPricesetId(), null);
|
||||
if (exists > 0)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.set.customer.alreadyBound"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,11 +791,11 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
if (STATUS_AUDIT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("审核中的套餐不允许修改");
|
||||
throw new ServiceException(MessageUtils.message("price.set.edit.audit"));
|
||||
}
|
||||
if (STATUS_STOP.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("已停用的套餐不允许修改,请使用复用新建");
|
||||
throw new ServiceException(MessageUtils.message("price.set.edit.stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,11 +803,11 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
{
|
||||
if (STATUS_AUDIT.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("审核中的套餐不允许改明细或客户");
|
||||
throw new ServiceException(MessageUtils.message("price.set.childEdit.audit"));
|
||||
}
|
||||
if (STATUS_STOP.equals(db.getStatus()))
|
||||
{
|
||||
throw new ServiceException("已停用的套餐不允许改明细或客户");
|
||||
throw new ServiceException(MessageUtils.message("price.set.childEdit.stopped"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -780,11 +827,25 @@ public class PrcPriceSetServiceImpl implements IPrcPriceSetService
|
||||
PrcPriceSet db = setMapper.selectPrcPriceSetById(priceSetId);
|
||||
if (db == null)
|
||||
{
|
||||
throw new ServiceException("套餐不存在");
|
||||
throw new ServiceException(MessageUtils.message("price.set.notExists"));
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
private boolean isCustomerUniqueViolation(Throwable e)
|
||||
{
|
||||
while (e != null)
|
||||
{
|
||||
String m = e.getMessage();
|
||||
if (m != null && (m.contains("uk_customer_one_set") || m.contains("Duplicate")))
|
||||
{
|
||||
return m.contains("uk_customer_one_set") || m.contains("customer_id");
|
||||
}
|
||||
e = e.getCause();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void fillExpired(PrcPriceSet set)
|
||||
{
|
||||
Date today = DateUtils.parseDate(DateUtils.getDate());
|
||||
|
||||
+4
-3
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.PrcSurchargeRel;
|
||||
import com.ruoyi.price.mapper.PrcSurchargeRelMapper;
|
||||
@@ -65,15 +66,15 @@ public class PrcSurchargeRelServiceImpl implements IPrcSurchargeRelService
|
||||
{
|
||||
if (rel.getScId() == null)
|
||||
{
|
||||
throw new ServiceException("附加费ID不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surchargeRel.scId.empty"));
|
||||
}
|
||||
if (rel.getProductId() == null)
|
||||
{
|
||||
throw new ServiceException("产品ID不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surchargeRel.productId.empty"));
|
||||
}
|
||||
if (StringUtils.isEmpty(rel.getProductCode()))
|
||||
{
|
||||
throw new ServiceException("产品代码不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surchargeRel.productCode.empty"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-4
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.PrcSurcharge;
|
||||
import com.ruoyi.price.mapper.PrcSurchargeMapper;
|
||||
@@ -68,19 +69,19 @@ public class PrcSurchargeServiceImpl implements IPrcSurchargeService
|
||||
{
|
||||
if (StringUtils.isEmpty(surcharge.getScName()))
|
||||
{
|
||||
throw new ServiceException("附加费名称不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surcharge.scName.empty"));
|
||||
}
|
||||
if (StringUtils.isEmpty(surcharge.getChargeType()))
|
||||
{
|
||||
throw new ServiceException("计费方式不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surcharge.chargeType.empty"));
|
||||
}
|
||||
if (surcharge.getChargeValue() == null)
|
||||
{
|
||||
throw new ServiceException("计费数值不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.surcharge.chargeValue.empty"));
|
||||
}
|
||||
if (surcharge.getChargeValue().compareTo(java.math.BigDecimal.ZERO) < 0)
|
||||
{
|
||||
throw new ServiceException("计费数值不能为负数");
|
||||
throw new ServiceException(MessageUtils.message("price.surcharge.chargeValue.negative"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-2
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.PrcWeightSectionDetail;
|
||||
import com.ruoyi.price.domain.PrcWeightSectionTemplate;
|
||||
@@ -106,11 +107,11 @@ public class PrcWeightServiceImpl implements IPrcWeightService
|
||||
{
|
||||
if (detail.getWlStartweight() == null || detail.getWlEndweight() == null)
|
||||
{
|
||||
throw new ServiceException("起始重量和结束重量不能为空");
|
||||
throw new ServiceException(MessageUtils.message("price.weight.range.empty"));
|
||||
}
|
||||
if (detail.getWlStartweight().compareTo(detail.getWlEndweight()) >= 0)
|
||||
{
|
||||
throw new ServiceException("起始重量必须小于结束重量");
|
||||
throw new ServiceException(MessageUtils.message("price.weight.range.invalid"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+500
-19
@@ -4,17 +4,28 @@ import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.common.utils.sign.Md5Utils;
|
||||
import com.ruoyi.price.domain.BmsProduct;
|
||||
import com.ruoyi.price.domain.BmsProductCountry;
|
||||
import com.ruoyi.price.domain.PrcCustomerPriceSet;
|
||||
import com.ruoyi.price.domain.PrcPriceSet;
|
||||
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.vo.TmsPriceQuoteFeeLine;
|
||||
import com.ruoyi.price.domain.vo.TmsPriceQuoteRequest;
|
||||
import com.ruoyi.price.domain.vo.TmsPriceQuoteResult;
|
||||
import com.ruoyi.price.mapper.BmsProductCountryMapper;
|
||||
@@ -22,10 +33,14 @@ import com.ruoyi.price.mapper.BmsProductMapper;
|
||||
import com.ruoyi.price.mapper.PrcCustomerPriceSetMapper;
|
||||
import com.ruoyi.price.mapper.PrcPriceSetDetailMapper;
|
||||
import com.ruoyi.price.mapper.PrcPriceSetMapper;
|
||||
import com.ruoyi.price.mapper.PrcQuoteFeeMapper;
|
||||
import com.ruoyi.price.mapper.PrcQuoteMapper;
|
||||
import com.ruoyi.price.mapper.PrcSurchargeRelMapper;
|
||||
import com.ruoyi.price.service.ITmsPriceQuoteService;
|
||||
|
||||
/**
|
||||
* TMS freight quote: customer package first, then product default.
|
||||
* After calc: persist fee lines by bms_fee_type; same trial params return stored rows.
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@@ -38,6 +53,10 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
private static final String SRC_DISCOUNT = "PACKAGE_DISCOUNT";
|
||||
private static final String SRC_DEFAULT = "PRODUCT_DEFAULT";
|
||||
|
||||
private static final String FEE_BASIC = "BASIC_FREIGHT";
|
||||
private static final String FEE_REG = "REGISTRATION_FEE";
|
||||
private static final String FEE_SUR = "SURCHARGE";
|
||||
|
||||
@Autowired
|
||||
private PrcCustomerPriceSetMapper customerPriceSetMapper;
|
||||
|
||||
@@ -53,11 +72,69 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
@Autowired
|
||||
private BmsProductMapper productMapper;
|
||||
|
||||
@Autowired
|
||||
private PrcSurchargeRelMapper surchargeRelMapper;
|
||||
|
||||
@Autowired
|
||||
private PrcQuoteMapper quoteMapper;
|
||||
|
||||
@Autowired
|
||||
private PrcQuoteFeeMapper quoteFeeMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public TmsPriceQuoteResult quote(TmsPriceQuoteRequest request)
|
||||
{
|
||||
validateRequest(request);
|
||||
Date bizDate = resolveBizDate(request.getBizDate());
|
||||
BigDecimal weight = request.getWeight().setScale(3, RoundingMode.HALF_UP);
|
||||
String quoteKey = buildQuoteKey(request, weight, bizDate);
|
||||
|
||||
PrcQuote cached = quoteMapper.selectPrcQuoteByKey(quoteKey);
|
||||
if (cached != null)
|
||||
{
|
||||
List<PrcQuoteFee> fees = quoteFeeMapper.selectByQuoteId(cached.getQuoteId());
|
||||
if (!isStaleSurchargeFees(fees))
|
||||
{
|
||||
return toResult(cached, fees, true);
|
||||
}
|
||||
TmsPriceQuoteResult refreshed = doQuote(request, bizDate);
|
||||
applySurchargesAndFees(refreshed);
|
||||
replaceQuoteFees(cached.getQuoteId(), refreshed);
|
||||
refreshed.setQuoteId(cached.getQuoteId());
|
||||
refreshed.setFromCache(false);
|
||||
return refreshed;
|
||||
}
|
||||
|
||||
TmsPriceQuoteResult result = doQuote(request, bizDate);
|
||||
applySurchargesAndFees(result);
|
||||
persistQuote(quoteKey, request, weight, bizDate, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrcQuote> selectQuoteList(PrcQuote query)
|
||||
{
|
||||
return quoteMapper.selectPrcQuoteList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TmsPriceQuoteResult getQuote(Long quoteId)
|
||||
{
|
||||
if (quoteId == null)
|
||||
{
|
||||
throw new ServiceException(MessageUtils.message("price.quote.quoteIdRequired"));
|
||||
}
|
||||
PrcQuote quote = quoteMapper.selectPrcQuoteById(quoteId);
|
||||
if (quote == null)
|
||||
{
|
||||
throw new ServiceException("QUOTE_NOT_FOUND: quoteId=" + quoteId);
|
||||
}
|
||||
return toResult(quote, quoteFeeMapper.selectByQuoteId(quoteId), true);
|
||||
}
|
||||
|
||||
private TmsPriceQuoteResult doQuote(TmsPriceQuoteRequest request, Date bizDate)
|
||||
{
|
||||
String productCode = request.getProductCode().trim();
|
||||
String countryCode = emptyToNull(request.getCountryCode());
|
||||
String countryName = emptyToNull(request.getCountryName());
|
||||
@@ -66,16 +143,15 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
countryCode = countryCode.toUpperCase();
|
||||
}
|
||||
BigDecimal weight = request.getWeight();
|
||||
Date bizDate = resolveBizDate(request.getBizDate());
|
||||
|
||||
BmsProductCountry base = productCountryMapper.selectMatchByProductCountryWeight(
|
||||
productCode, countryCode, countryName, weight, bizDate);
|
||||
if (base == null)
|
||||
{
|
||||
throw new ServiceException("PRICE_NOT_HIT: no bms_product_country band for product/country/weight");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.priceNotHit"));
|
||||
}
|
||||
|
||||
String productName = resolveProductName(productCode);
|
||||
String productName = resolveProductName(productCode, bizDate);
|
||||
List<PrcCustomerPriceSet> binds = customerPriceSetMapper.selectEffectiveByCustomer(
|
||||
request.getCustomerId(), bizDate);
|
||||
|
||||
@@ -109,7 +185,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
}
|
||||
|
||||
return buildDefault(request.getCustomerId(), base, productCode, productName, weight,
|
||||
"no customer package override; use product default freight/registration");
|
||||
MessageUtils.message("price.quote.noCustomerPackageOverride"));
|
||||
}
|
||||
|
||||
private TmsPriceQuoteResult tryFixed(PrcCustomerPriceSet bind, PrcPriceSet set,
|
||||
@@ -121,7 +197,8 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
TmsPriceQuoteResult r = buildFromRates(SRC_DEFAULT, base.getFreightPrice(), null, null,
|
||||
base.getRegistrationFee(), base, productCode, productName, weight, null);
|
||||
fillPackage(r, bind, set);
|
||||
r.setMatchMessage("FIXED package has no details; use bms_product_country default");
|
||||
// 套餐固定价格没有明细,使用产品默认价格
|
||||
r.setMatchMessage(MessageUtils.message("price.quote.fixedPackageNoDetails"));
|
||||
r.setCustomerId(bind.getCustomerId());
|
||||
return r;
|
||||
}
|
||||
@@ -153,7 +230,8 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
{
|
||||
r.setProductCountryId(detail.getProductCountryId());
|
||||
}
|
||||
r.setMatchMessage("hit customer FIXED package detail");
|
||||
// 命中客户套餐固定价格明细
|
||||
r.setMatchMessage(MessageUtils.message("price.quote.hitCustomerFixedPackageDetail"));
|
||||
r.setCustomerId(bind.getCustomerId());
|
||||
return r;
|
||||
}
|
||||
@@ -185,7 +263,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
}
|
||||
if (base.getFreightPrice() == null)
|
||||
{
|
||||
throw new ServiceException("FREIGHT_VALUE_MISSING: product default freight rate is null");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.freightMissing1"));
|
||||
}
|
||||
BigDecimal baseRate = base.getFreightPrice();
|
||||
RoundingMode rm = resolveRoundingMode(roundMode);
|
||||
@@ -204,7 +282,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
{
|
||||
if (base.getFreightPrice() == null || base.getRegistrationFee() == null)
|
||||
{
|
||||
throw new ServiceException("FREIGHT_VALUE_MISSING: product default freight or registration is null");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.freightMissing2"));
|
||||
}
|
||||
TmsPriceQuoteResult r = buildFromRates(SRC_DEFAULT, base.getFreightPrice(), null, null,
|
||||
base.getRegistrationFee(), base, productCode, productName, weight, null);
|
||||
@@ -220,7 +298,7 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
{
|
||||
if (freightRate == null)
|
||||
{
|
||||
throw new ServiceException("FREIGHT_VALUE_MISSING: freight rate is null");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.freightMissing3"));
|
||||
}
|
||||
if (registrationFee == null)
|
||||
{
|
||||
@@ -249,12 +327,393 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
r.setDiscountPercent(discountPercent);
|
||||
r.setRegistrationFee(registrationFee);
|
||||
r.setFreightAmount(freightAmount);
|
||||
r.setSurchargeAmount(BigDecimal.ZERO);
|
||||
r.setPayableTotal(payable);
|
||||
r.setCurrency("RMB");
|
||||
r.setCurrency("CNY");
|
||||
r.setRoundMode(mode);
|
||||
r.setFromCache(false);
|
||||
return r;
|
||||
}
|
||||
|
||||
private void applySurchargesAndFees(TmsPriceQuoteResult result)
|
||||
{
|
||||
BigDecimal freightAmount = nvl(result.getFreightAmount());
|
||||
BigDecimal registrationFee = nvl(result.getRegistrationFee());
|
||||
RoundingMode rm = resolveRoundingMode(result.getRoundMode());
|
||||
String currency = normalizeCurrency(result.getCurrency());
|
||||
|
||||
List<PrcSurchargeRel> rels = loadMatchedSurcharges(result);
|
||||
List<TmsPriceQuoteFeeLine> lines = new ArrayList<TmsPriceQuoteFeeLine>();
|
||||
lines.add(feeLine(FEE_BASIC, feeNameOf(FEE_BASIC), 0L, freightAmount, currency, result.getRoundMode(), null));
|
||||
lines.add(feeLine(FEE_REG, feeNameOf(FEE_REG), 0L, registrationFee, currency, result.getRoundMode(), null));
|
||||
|
||||
BigDecimal surchargeTotal = BigDecimal.ZERO;
|
||||
Map<Long, TmsPriceQuoteFeeLine> surchargeLines = new LinkedHashMap<Long, TmsPriceQuoteFeeLine>();
|
||||
for (PrcSurchargeRel rel : rels)
|
||||
{
|
||||
BigDecimal itemAmount = calcSurchargeAmount(rel, result.getWeight(), freightAmount);
|
||||
if (itemAmount == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
Long scId = rel.getScId() == null ? 0L : rel.getScId();
|
||||
TmsPriceQuoteFeeLine exist = surchargeLines.get(scId);
|
||||
if (exist != null)
|
||||
{
|
||||
exist.setAmount(nvl(exist.getAmount()).add(itemAmount));
|
||||
continue;
|
||||
}
|
||||
String feeType = StringUtils.isEmpty(rel.getFeeType()) ? FEE_SUR : rel.getFeeType();
|
||||
String feeName = StringUtils.isEmpty(rel.getScName()) ? feeNameOf(FEE_SUR) : rel.getScName();
|
||||
String itemCcy = normalizeCurrency(StringUtils.isEmpty(rel.getCurrency()) ? currency : rel.getCurrency());
|
||||
String itemRound = StringUtils.isEmpty(rel.getRoundMode()) ? result.getRoundMode() : rel.getRoundMode();
|
||||
surchargeLines.put(scId, feeLine(feeType, feeName, scId, itemAmount, itemCcy, itemRound, rel.getScNote()));
|
||||
}
|
||||
for (TmsPriceQuoteFeeLine line : surchargeLines.values())
|
||||
{
|
||||
line.setAmount(nvl(line.getAmount()).setScale(2, rm));
|
||||
surchargeTotal = surchargeTotal.add(nvl(line.getAmount()));
|
||||
lines.add(line);
|
||||
}
|
||||
surchargeTotal = surchargeTotal.setScale(2, rm);
|
||||
result.setSurchargeAmount(surchargeTotal);
|
||||
result.setPayableTotal(freightAmount.add(registrationFee).add(surchargeTotal).setScale(2, rm));
|
||||
result.setFeeDetails(lines);
|
||||
}
|
||||
|
||||
private List<PrcSurchargeRel> loadMatchedSurcharges(TmsPriceQuoteResult result)
|
||||
{
|
||||
List<PrcSurchargeRel> matched = new ArrayList<PrcSurchargeRel>();
|
||||
if (result == null || StringUtils.isEmpty(result.getProductCode()))
|
||||
{
|
||||
return matched;
|
||||
}
|
||||
PrcSurchargeRel query = new PrcSurchargeRel();
|
||||
query.setProductCode(result.getProductCode());
|
||||
List<PrcSurchargeRel> rels = surchargeRelMapper.selectPrcSurchargeRelList(query);
|
||||
if (rels == null)
|
||||
{
|
||||
return matched;
|
||||
}
|
||||
for (PrcSurchargeRel rel : rels)
|
||||
{
|
||||
if (surchargeApplies(rel, result))
|
||||
{
|
||||
matched.add(rel);
|
||||
}
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
|
||||
private boolean surchargeApplies(PrcSurchargeRel rel, TmsPriceQuoteResult result)
|
||||
{
|
||||
if (rel == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(rel.getSsCode()) && !"on".equalsIgnoreCase(rel.getSsCode()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (StringUtils.isNotEmpty(rel.getCountryCode()) && StringUtils.isNotEmpty(result.getCountryCode())
|
||||
&& !rel.getCountryCode().equalsIgnoreCase(result.getCountryCode()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (rel.getDetailId() == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return result.getProductCountryId() != null && rel.getDetailId().equals(result.getProductCountryId());
|
||||
}
|
||||
|
||||
private BigDecimal calcSurchargeAmount(PrcSurchargeRel rel, BigDecimal weight, BigDecimal freightAmount)
|
||||
{
|
||||
if (rel.getChargeValue() == null)
|
||||
{
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
RoundingMode rm = resolveRoundingMode(rel.getRoundMode());
|
||||
String chargeType = rel.getChargeType() == null ? "FIXED" : rel.getChargeType().toUpperCase();
|
||||
BigDecimal amount;
|
||||
if ("WEIGHT".equals(chargeType))
|
||||
{
|
||||
amount = rel.getChargeValue().multiply(nvl(weight));
|
||||
}
|
||||
else if ("RATE".equals(chargeType))
|
||||
{
|
||||
amount = nvl(freightAmount).multiply(rel.getChargeValue());
|
||||
}
|
||||
else
|
||||
{
|
||||
amount = rel.getChargeValue();
|
||||
}
|
||||
return amount.setScale(2, rm);
|
||||
}
|
||||
|
||||
private void persistQuote(String quoteKey, TmsPriceQuoteRequest request, BigDecimal weight,
|
||||
Date bizDate, TmsPriceQuoteResult result)
|
||||
{
|
||||
PrcQuote quote = new PrcQuote();
|
||||
quote.setQuoteKey(quoteKey);
|
||||
quote.setCustomerId(request.getCustomerId());
|
||||
quote.setProductCode(result.getProductCode());
|
||||
quote.setProductName(result.getProductName());
|
||||
quote.setCountryCode(result.getCountryCode());
|
||||
quote.setCountryName(result.getCountryName());
|
||||
quote.setWeight(weight);
|
||||
quote.setBizDate(bizDate);
|
||||
quote.setTmsId(request.getTmsId() == null ? null : Long.valueOf(request.getTmsId()));
|
||||
quote.setMatchSource(result.getMatchSource());
|
||||
quote.setMatchMessage(result.getMatchMessage());
|
||||
quote.setPriceSetId(result.getPriceSetId());
|
||||
quote.setPriceSetCode(result.getPriceSetCode());
|
||||
quote.setPriceSetName(result.getPriceSetName());
|
||||
quote.setSetType(result.getSetType());
|
||||
quote.setBindPriority(result.getBindPriority());
|
||||
quote.setCustomerPricesetId(result.getCustomerPricesetId());
|
||||
quote.setProductCountryId(result.getProductCountryId());
|
||||
quote.setWeightMin(result.getWeightMin());
|
||||
quote.setWeightMax(result.getWeightMax());
|
||||
quote.setWeightLabel(result.getWeightLabel());
|
||||
quote.setEffectiveDate(result.getEffectiveDate());
|
||||
quote.setChargeWeight(result.getChargeWeight());
|
||||
quote.setFreightRate(result.getFreightRate());
|
||||
quote.setBaseFreightRate(result.getBaseFreightRate());
|
||||
quote.setDiscountPercent(result.getDiscountPercent());
|
||||
quote.setRegistrationFee(result.getRegistrationFee());
|
||||
quote.setFreightAmount(result.getFreightAmount());
|
||||
quote.setSurchargeAmount(result.getSurchargeAmount());
|
||||
quote.setPayableTotal(result.getPayableTotal());
|
||||
quote.setCurrency(result.getCurrency());
|
||||
quote.setRoundMode(result.getRoundMode());
|
||||
try
|
||||
{
|
||||
quoteMapper.insertPrcQuote(quote);
|
||||
}
|
||||
catch (DuplicateKeyException ex)
|
||||
{
|
||||
PrcQuote existed = quoteMapper.selectPrcQuoteByKey(quoteKey);
|
||||
if (existed == null)
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
TmsPriceQuoteResult cached = toResult(existed, quoteFeeMapper.selectByQuoteId(existed.getQuoteId()), true);
|
||||
copyResult(cached, result);
|
||||
return;
|
||||
}
|
||||
|
||||
List<PrcQuoteFee> fees = toFeeRows(quote.getQuoteId(), result);
|
||||
if (!fees.isEmpty())
|
||||
{
|
||||
quoteFeeMapper.insertBatch(fees);
|
||||
}
|
||||
result.setQuoteId(quote.getQuoteId());
|
||||
result.setFromCache(false);
|
||||
}
|
||||
|
||||
private boolean isStaleSurchargeFees(List<PrcQuoteFee> fees)
|
||||
{
|
||||
if (fees == null || fees.isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
for (PrcQuoteFee fee : fees)
|
||||
{
|
||||
if (!FEE_SUR.equals(fee.getFeeType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (fee.getScId() == null || fee.getScId().longValue() == 0L)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
String name = fee.getFeeName() == null ? "" : fee.getFeeName().trim();
|
||||
if (name.isEmpty() || "SURCHARGE".equalsIgnoreCase(name)
|
||||
|| "\u9644\u52a0\u8d39".equals(name))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void replaceQuoteFees(Long quoteId, TmsPriceQuoteResult result)
|
||||
{
|
||||
quoteFeeMapper.deleteByQuoteId(quoteId);
|
||||
List<PrcQuoteFee> fees = toFeeRows(quoteId, result);
|
||||
if (!fees.isEmpty())
|
||||
{
|
||||
quoteFeeMapper.insertBatch(fees);
|
||||
}
|
||||
quoteMapper.updateQuoteAmounts(quoteId, result.getSurchargeAmount(), result.getPayableTotal());
|
||||
}
|
||||
|
||||
private List<PrcQuoteFee> toFeeRows(Long quoteId, TmsPriceQuoteResult result)
|
||||
{
|
||||
List<PrcQuoteFee> fees = new ArrayList<PrcQuoteFee>();
|
||||
if (result.getFeeDetails() == null)
|
||||
{
|
||||
return fees;
|
||||
}
|
||||
for (TmsPriceQuoteFeeLine line : result.getFeeDetails())
|
||||
{
|
||||
PrcQuoteFee fee = new PrcQuoteFee();
|
||||
fee.setQuoteId(quoteId);
|
||||
fee.setFeeType(line.getFeeType());
|
||||
fee.setFeeName(line.getFeeName());
|
||||
fee.setScId(line.getScId() == null ? 0L : line.getScId());
|
||||
fee.setAmount(nvl(line.getAmount()));
|
||||
fee.setCurrency(line.getCurrency());
|
||||
fee.setRoundMode(line.getRoundMode());
|
||||
fee.setRemark(line.getRemark());
|
||||
fees.add(fee);
|
||||
}
|
||||
return fees;
|
||||
}
|
||||
|
||||
private TmsPriceQuoteResult toResult(PrcQuote quote, List<PrcQuoteFee> fees, boolean fromCache)
|
||||
{
|
||||
TmsPriceQuoteResult r = new TmsPriceQuoteResult();
|
||||
r.setQuoteId(quote.getQuoteId());
|
||||
r.setFromCache(fromCache);
|
||||
r.setMatchSource(quote.getMatchSource());
|
||||
r.setMatchMessage(quote.getMatchMessage());
|
||||
r.setCustomerId(quote.getCustomerId());
|
||||
r.setPriceSetId(quote.getPriceSetId());
|
||||
r.setPriceSetCode(quote.getPriceSetCode());
|
||||
r.setPriceSetName(quote.getPriceSetName());
|
||||
r.setSetType(quote.getSetType());
|
||||
r.setBindPriority(quote.getBindPriority());
|
||||
r.setCustomerPricesetId(quote.getCustomerPricesetId());
|
||||
r.setProductCode(quote.getProductCode());
|
||||
r.setProductName(quote.getProductName());
|
||||
r.setCountryCode(quote.getCountryCode());
|
||||
r.setCountryName(quote.getCountryName());
|
||||
r.setProductCountryId(quote.getProductCountryId());
|
||||
r.setWeightMin(quote.getWeightMin());
|
||||
r.setWeightMax(quote.getWeightMax());
|
||||
r.setWeightLabel(quote.getWeightLabel());
|
||||
r.setEffectiveDate(quote.getEffectiveDate());
|
||||
r.setWeight(quote.getWeight());
|
||||
r.setChargeWeight(quote.getChargeWeight());
|
||||
r.setFreightRate(quote.getFreightRate());
|
||||
r.setBaseFreightRate(quote.getBaseFreightRate());
|
||||
r.setDiscountPercent(quote.getDiscountPercent());
|
||||
r.setRegistrationFee(quote.getRegistrationFee());
|
||||
r.setFreightAmount(quote.getFreightAmount());
|
||||
r.setSurchargeAmount(quote.getSurchargeAmount());
|
||||
r.setPayableTotal(quote.getPayableTotal());
|
||||
r.setCurrency(normalizeCurrency(quote.getCurrency()));
|
||||
r.setRoundMode(quote.getRoundMode());
|
||||
List<TmsPriceQuoteFeeLine> lines = new ArrayList<TmsPriceQuoteFeeLine>();
|
||||
if (fees != null)
|
||||
{
|
||||
for (PrcQuoteFee fee : fees)
|
||||
{
|
||||
lines.add(feeLine(fee.getFeeType(), fee.getFeeName(), fee.getScId(), fee.getAmount(),
|
||||
fee.getCurrency(), fee.getRoundMode(), fee.getRemark()));
|
||||
}
|
||||
}
|
||||
r.setFeeDetails(lines);
|
||||
return r;
|
||||
}
|
||||
|
||||
private void copyResult(TmsPriceQuoteResult from, TmsPriceQuoteResult to)
|
||||
{
|
||||
to.setQuoteId(from.getQuoteId());
|
||||
to.setFromCache(from.getFromCache());
|
||||
to.setMatchSource(from.getMatchSource());
|
||||
to.setMatchMessage(from.getMatchMessage());
|
||||
to.setCustomerId(from.getCustomerId());
|
||||
to.setPriceSetId(from.getPriceSetId());
|
||||
to.setPriceSetCode(from.getPriceSetCode());
|
||||
to.setPriceSetName(from.getPriceSetName());
|
||||
to.setSetType(from.getSetType());
|
||||
to.setBindPriority(from.getBindPriority());
|
||||
to.setCustomerPricesetId(from.getCustomerPricesetId());
|
||||
to.setProductCode(from.getProductCode());
|
||||
to.setProductName(from.getProductName());
|
||||
to.setCountryCode(from.getCountryCode());
|
||||
to.setCountryName(from.getCountryName());
|
||||
to.setProductCountryId(from.getProductCountryId());
|
||||
to.setWeightMin(from.getWeightMin());
|
||||
to.setWeightMax(from.getWeightMax());
|
||||
to.setWeightLabel(from.getWeightLabel());
|
||||
to.setEffectiveDate(from.getEffectiveDate());
|
||||
to.setWeight(from.getWeight());
|
||||
to.setChargeWeight(from.getChargeWeight());
|
||||
to.setFreightRate(from.getFreightRate());
|
||||
to.setBaseFreightRate(from.getBaseFreightRate());
|
||||
to.setDiscountPercent(from.getDiscountPercent());
|
||||
to.setRegistrationFee(from.getRegistrationFee());
|
||||
to.setFreightAmount(from.getFreightAmount());
|
||||
to.setSurchargeAmount(from.getSurchargeAmount());
|
||||
to.setPayableTotal(from.getPayableTotal());
|
||||
to.setCurrency(from.getCurrency());
|
||||
to.setRoundMode(from.getRoundMode());
|
||||
to.setFeeDetails(from.getFeeDetails());
|
||||
}
|
||||
|
||||
private String buildQuoteKey(TmsPriceQuoteRequest request, BigDecimal weight, Date bizDate)
|
||||
{
|
||||
String countryCode = emptyToNull(request.getCountryCode());
|
||||
if (countryCode != null)
|
||||
{
|
||||
countryCode = countryCode.toUpperCase();
|
||||
}
|
||||
String countryName = emptyToNull(request.getCountryName());
|
||||
String biz = new SimpleDateFormat("yyyy-MM-dd").format(bizDate);
|
||||
String raw = request.getCustomerId() + "|"
|
||||
+ request.getProductCode().trim() + "|"
|
||||
+ nvlStr(countryCode) + "|"
|
||||
+ nvlStr(countryName) + "|"
|
||||
+ weight.toPlainString() + "|"
|
||||
+ biz + "|"
|
||||
+ (request.getTmsId() == null ? "" : request.getTmsId());
|
||||
return Md5Utils.hash(raw);
|
||||
}
|
||||
|
||||
private static TmsPriceQuoteFeeLine feeLine(String feeType, String feeName, Long scId, BigDecimal amount,
|
||||
String currency, String roundMode, String remark)
|
||||
{
|
||||
TmsPriceQuoteFeeLine line = new TmsPriceQuoteFeeLine();
|
||||
line.setFeeType(feeType);
|
||||
line.setFeeName(feeName);
|
||||
line.setScId(scId == null ? 0L : scId);
|
||||
line.setAmount(nvl(amount));
|
||||
line.setCurrency(normalizeCurrency(currency));
|
||||
line.setRoundMode(roundMode);
|
||||
line.setRemark(remark);
|
||||
return line;
|
||||
}
|
||||
|
||||
private static String normalizeCurrency(String currency)
|
||||
{
|
||||
if (StringUtils.isEmpty(currency) || "RMB".equalsIgnoreCase(currency))
|
||||
{
|
||||
return "CNY";
|
||||
}
|
||||
return currency.trim().toUpperCase();
|
||||
}
|
||||
|
||||
private static String feeNameOf(String feeType)
|
||||
{
|
||||
if (FEE_BASIC.equals(feeType))
|
||||
{
|
||||
return "\u57fa\u7840\u8fd0\u8d39";
|
||||
}
|
||||
if (FEE_REG.equals(feeType))
|
||||
{
|
||||
return "\u6302\u53f7\u8d39";
|
||||
}
|
||||
if (FEE_SUR.equals(feeType))
|
||||
{
|
||||
return "\u9644\u52a0\u8d39";
|
||||
}
|
||||
return feeType;
|
||||
}
|
||||
|
||||
private static String normalizeRoundMode(String roundMode)
|
||||
{
|
||||
if (StringUtils.isEmpty(roundMode))
|
||||
@@ -297,23 +756,23 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
{
|
||||
if (request == null)
|
||||
{
|
||||
throw new ServiceException("request body is required");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.requestBodyRequired"));
|
||||
}
|
||||
if (request.getCustomerId() == null)
|
||||
{
|
||||
throw new ServiceException("customerId is required");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.customerIdRequired"));
|
||||
}
|
||||
if (StringUtils.isEmpty(request.getProductCode()))
|
||||
{
|
||||
throw new ServiceException("productCode is required");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.productCodeRequired"));
|
||||
}
|
||||
if (StringUtils.isEmpty(request.getCountryCode()) && StringUtils.isEmpty(request.getCountryName()))
|
||||
{
|
||||
throw new ServiceException("countryCode or countryName is required");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.countryRequired"));
|
||||
}
|
||||
if (request.getWeight() == null || request.getWeight().compareTo(BigDecimal.ZERO) <= 0)
|
||||
{
|
||||
throw new ServiceException("weight must be > 0");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.weightInvalid"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +780,15 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
{
|
||||
if (StringUtils.isEmpty(bizDate))
|
||||
{
|
||||
return new Date();
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("yyyy-MM-dd").parse(
|
||||
new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
return new Date();
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
@@ -329,13 +796,17 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new ServiceException("bizDate format must be yyyy-MM-dd");
|
||||
throw new ServiceException(MessageUtils.message("price.quote.bizDateInvalid"));
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveProductName(String productCode)
|
||||
private String resolveProductName(String productCode, Date bizDate)
|
||||
{
|
||||
BmsProduct p = productMapper.selectBmsProductByCode(productCode);
|
||||
BmsProduct p = productMapper.selectEffectiveBmsProductByCode(productCode, bizDate);
|
||||
if (p == null)
|
||||
{
|
||||
p = productMapper.selectBmsProductByCode(productCode);
|
||||
}
|
||||
return p == null ? null : p.getProductName();
|
||||
}
|
||||
|
||||
@@ -344,6 +815,16 @@ public class TmsPriceQuoteServiceImpl implements ITmsPriceQuoteService
|
||||
return StringUtils.isEmpty(s) ? null : s.trim();
|
||||
}
|
||||
|
||||
private static String nvlStr(String s)
|
||||
{
|
||||
return s == null ? "" : s;
|
||||
}
|
||||
|
||||
private static BigDecimal nvl(BigDecimal v)
|
||||
{
|
||||
return v == null ? BigDecimal.ZERO : v;
|
||||
}
|
||||
|
||||
private static String formatWeightLabel(BigDecimal min, BigDecimal max)
|
||||
{
|
||||
return strip(min) + "\u2264W\u2264" + strip(max);
|
||||
|
||||
+2
-1
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.exception.ServiceException;
|
||||
import com.ruoyi.common.utils.MessageUtils;
|
||||
import com.ruoyi.common.utils.StringUtils;
|
||||
import com.ruoyi.price.domain.XtdZoneCountry;
|
||||
import com.ruoyi.price.domain.XtdZoneDivision;
|
||||
@@ -78,7 +79,7 @@ public class XtdZoneServiceImpl implements IXtdZoneService
|
||||
{
|
||||
XtdZoneScheme scheme = schemeMapper.selectXtdZoneSchemeById(zsId);
|
||||
String name = scheme != null ? scheme.getZsName() : String.valueOf(zsId);
|
||||
throw new ServiceException("分区方案【" + name + "】存在区划明细,不允许删除");
|
||||
throw new ServiceException(MessageUtils.message("price.zone.delete.hasDivision", name));
|
||||
}
|
||||
}
|
||||
return schemeMapper.deleteXtdZoneSchemeByIds(zsIds);
|
||||
|
||||
@@ -6,6 +6,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<resultMap type="BmsProductCountry" id="BmsProductCountryResult">
|
||||
<id property="detailId" column="detail_id" />
|
||||
<result property="productId" column="product_id" />
|
||||
<result property="productCode" column="product_code" />
|
||||
<result property="countryName" column="country_name" />
|
||||
<result property="countryCode" column="country_code" />
|
||||
@@ -18,20 +19,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="leadTime" column="lead_time" />
|
||||
<result property="effectiveDate" column="effective_date" />
|
||||
<result property="expireDate" column="expire_date" />
|
||||
<result property="status" column="status" />
|
||||
<result property="createdAt" column="created_at" />
|
||||
<result property="updatedAt" column="updated_at" />
|
||||
<result property="effectStatus" column="status" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectVo">
|
||||
select detail_id, product_code, country_name, country_code, weight_min, weight_max,
|
||||
select detail_id, product_id, product_code, country_name, country_code, weight_min, weight_max,
|
||||
freight_price, registration_fee, size_limit, last_mile, lead_time,
|
||||
effective_date, expire_date, created_at, updated_at
|
||||
effective_date, expire_date, status, created_at, updated_at
|
||||
from bms_product_country
|
||||
</sql>
|
||||
|
||||
<select id="selectBmsProductCountryList" parameterType="BmsProductCountry" resultMap="BmsProductCountryResult">
|
||||
<include refid="selectVo"/>
|
||||
<where>
|
||||
<if test="productId != null">
|
||||
AND product_id = #{productId}
|
||||
</if>
|
||||
<if test="productCode != null and productCode != ''">
|
||||
AND product_code = #{productCode}
|
||||
</if>
|
||||
@@ -53,22 +59,32 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="openOnly != null and openOnly">
|
||||
AND expire_date is null
|
||||
</if>
|
||||
<if test="status != null and status != ''">
|
||||
AND status = #{status}
|
||||
</if>
|
||||
<if test="effectStatus != null and effectStatus != ''">
|
||||
AND status = #{effectStatus}
|
||||
</if>
|
||||
</where>
|
||||
order by effective_date desc, country_name asc, weight_min asc, detail_id asc
|
||||
</select>
|
||||
|
||||
<insert id="insertBmsProductCountry" parameterType="BmsProductCountry" useGeneratedKeys="true" keyProperty="detailId">
|
||||
insert into bms_product_country (
|
||||
product_code, country_name, country_code, weight_min, weight_max,
|
||||
product_id, product_code, country_name, country_code, weight_min, weight_max,
|
||||
freight_price, registration_fee, size_limit, last_mile, lead_time,
|
||||
effective_date, expire_date, created_at
|
||||
effective_date, expire_date, status, created_at
|
||||
) values (
|
||||
#{productCode}, #{countryName}, #{countryCode}, #{weightMin}, #{weightMax},
|
||||
#{productId}, #{productCode}, #{countryName}, #{countryCode}, #{weightMin}, #{weightMax},
|
||||
#{freightPrice}, #{registrationFee}, #{sizeLimit}, #{lastMile}, #{leadTime},
|
||||
#{effectiveDate}, #{expireDate}, sysdate()
|
||||
#{effectiveDate}, #{expireDate}, IFNULL(#{status}, '0'), sysdate()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByProductId" parameterType="Long">
|
||||
delete from bms_product_country where product_id = #{productId}
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByProductCode" parameterType="String">
|
||||
delete from bms_product_country where product_code = #{productCode}
|
||||
</delete>
|
||||
@@ -80,6 +96,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<delete id="deleteByProductCodeAndEffectiveDate">
|
||||
delete from bms_product_country
|
||||
where product_code = #{productCode}
|
||||
and (
|
||||
(#{effectiveDate} is null and effective_date is null)
|
||||
or effective_date = #{effectiveDate}
|
||||
)
|
||||
</delete>
|
||||
|
||||
<select id="selectMaxOpenEffectiveDate" resultType="java.util.Date">
|
||||
select max(effective_date) from bms_product_country
|
||||
where product_code = #{productCode}
|
||||
@@ -95,6 +120,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
and (effective_date is null or effective_date < #{newEffectiveDate})
|
||||
</update>
|
||||
|
||||
<update id="refreshStatusByDates">
|
||||
update bms_product_country
|
||||
set status = case
|
||||
when expire_date is not null and expire_date <= curdate() then '2'
|
||||
when effective_date is null or effective_date > curdate() then '0'
|
||||
else '1'
|
||||
end
|
||||
</update>
|
||||
|
||||
<delete id="deleteOpenByProductCodeAndEffectiveDate">
|
||||
delete from bms_product_country
|
||||
where product_code = #{productCode}
|
||||
|
||||
@@ -14,6 +14,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateNote" column="update_note" />
|
||||
<result property="taxMode" column="tax_mode" />
|
||||
<result property="effectiveDate" column="effective_date" />
|
||||
<result property="expireDate" column="expire_date" />
|
||||
<result property="status" column="status" />
|
||||
<result property="sourceSheet" column="source_sheet" />
|
||||
<result property="remark" column="remark" />
|
||||
@@ -28,9 +29,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<sql id="selectBmsProductVo">
|
||||
select p.product_id, p.product_code, p.product_name, p.service_level, p.cargo_attr,
|
||||
p.dest_region, p.update_note, p.tax_mode, p.effective_date, p.status,
|
||||
p.dest_region, p.update_note, p.tax_mode, p.effective_date, p.expire_date, p.status,
|
||||
p.source_sheet, p.remark, p.tms_id, p.created_by, p.created_at, p.updated_by, p.updated_at,
|
||||
(select count(distinct c.country_name) from bms_product_country c where c.product_code = p.product_code) as country_count,
|
||||
(select count(distinct c.country_name) from bms_product_country c
|
||||
where c.product_id = p.product_id
|
||||
or (c.product_id is null and c.product_code = p.product_code
|
||||
and (
|
||||
(p.effective_date is null and c.effective_date is null)
|
||||
or c.effective_date = p.effective_date
|
||||
))
|
||||
) as country_count,
|
||||
(select count(*) from prc_surcharge_rel r where r.product_id = p.product_id) as surcharge_count
|
||||
from bms_product p
|
||||
</sql>
|
||||
@@ -43,6 +51,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<select id="selectBmsProductByCode" parameterType="String" resultMap="BmsProductResult">
|
||||
<include refid="selectBmsProductVo"/>
|
||||
where p.product_code = #{productCode}
|
||||
order by p.effective_date desc, p.product_id desc
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectBmsProductByCodeAndDate" resultMap="BmsProductResult">
|
||||
<include refid="selectBmsProductVo"/>
|
||||
where p.product_code = #{productCode}
|
||||
<choose>
|
||||
<when test="effectiveDate != null">
|
||||
AND p.effective_date = #{effectiveDate}
|
||||
</when>
|
||||
<otherwise>
|
||||
AND p.effective_date is null
|
||||
</otherwise>
|
||||
</choose>
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectEffectiveBmsProductByCode" resultMap="BmsProductResult">
|
||||
<include refid="selectBmsProductVo"/>
|
||||
where p.product_code = #{productCode}
|
||||
and (p.effective_date is null or #{bizDate} is null or p.effective_date <= #{bizDate})
|
||||
and (p.expire_date is null or #{bizDate} is null or p.expire_date > #{bizDate})
|
||||
order by p.effective_date desc, p.product_id desc
|
||||
limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectBmsProductList" parameterType="BmsProduct" resultMap="BmsProductResult">
|
||||
@@ -61,20 +94,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
AND p.status = #{status}
|
||||
</if>
|
||||
<if test="effectStatus != null and effectStatus != ''">
|
||||
<choose>
|
||||
<when test="effectStatus == 'EXPIRED'">
|
||||
AND p.status = '1'
|
||||
</when>
|
||||
<when test="effectStatus == 'PENDING'">
|
||||
AND p.status = '0'
|
||||
AND (p.effective_date is null or p.effective_date > curdate())
|
||||
</when>
|
||||
<when test="effectStatus == 'ACTIVE'">
|
||||
AND p.status = '0'
|
||||
AND p.effective_date is not null
|
||||
AND p.effective_date <= curdate()
|
||||
</when>
|
||||
</choose>
|
||||
AND p.status = #{effectStatus}
|
||||
</if>
|
||||
<if test="cargoAttr != null and cargoAttr != ''">
|
||||
AND p.cargo_attr like concat('%', #{cargoAttr}, '%')
|
||||
@@ -84,7 +104,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
OR p.product_name like concat('%', #{params.keyword}, '%'))
|
||||
</if>
|
||||
</where>
|
||||
order by p.product_id desc
|
||||
order by p.product_code asc, p.effective_date desc, p.product_id desc
|
||||
</select>
|
||||
|
||||
<insert id="insertBmsProduct" parameterType="BmsProduct" useGeneratedKeys="true" keyProperty="productId">
|
||||
@@ -97,6 +117,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="updateNote != null">update_note,</if>
|
||||
<if test="taxMode != null and taxMode != ''">tax_mode,</if>
|
||||
<if test="effectiveDate != null">effective_date,</if>
|
||||
<if test="expireDate != null">expire_date,</if>
|
||||
<if test="status != null and status != ''">status,</if>
|
||||
<if test="sourceSheet != null">source_sheet,</if>
|
||||
<if test="remark != null">remark,</if>
|
||||
@@ -112,6 +133,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="updateNote != null">#{updateNote},</if>
|
||||
<if test="taxMode != null and taxMode != ''">#{taxMode},</if>
|
||||
<if test="effectiveDate != null">#{effectiveDate},</if>
|
||||
<if test="expireDate != null">#{expireDate},</if>
|
||||
<if test="status != null and status != ''">#{status},</if>
|
||||
<if test="sourceSheet != null">#{sourceSheet},</if>
|
||||
<if test="remark != null">#{remark},</if>
|
||||
@@ -132,6 +154,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="updateNote != null">update_note = #{updateNote},</if>
|
||||
<if test="taxMode != null and taxMode != ''">tax_mode = #{taxMode},</if>
|
||||
<if test="effectiveDate != null">effective_date = #{effectiveDate},</if>
|
||||
expire_date = #{expireDate},
|
||||
<if test="status != null and status != ''">status = #{status},</if>
|
||||
<if test="sourceSheet != null">source_sheet = #{sourceSheet},</if>
|
||||
<if test="remark != null">remark = #{remark},</if>
|
||||
@@ -149,4 +172,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</delete>
|
||||
|
||||
<update id="expireOpenByProductCode">
|
||||
update bms_product
|
||||
set expire_date = #{newEffectiveDate},
|
||||
updated_at = sysdate()
|
||||
where product_code = #{productCode}
|
||||
and expire_date is null
|
||||
and (effective_date is null or effective_date < #{newEffectiveDate})
|
||||
<if test="excludeId != null">
|
||||
and product_id <> #{excludeId}
|
||||
</if>
|
||||
</update>
|
||||
|
||||
<update id="refreshStatusByDates">
|
||||
update bms_product
|
||||
set status = case
|
||||
when expire_date is not null and expire_date <= curdate() then '2'
|
||||
when effective_date is null or effective_date > curdate() then '0'
|
||||
else '1'
|
||||
end
|
||||
</update>
|
||||
|
||||
</mapper>
|
||||
|
||||
@@ -51,6 +51,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
select count(1) from prc_customer_price_set where price_set_id = #{priceSetId}
|
||||
</select>
|
||||
|
||||
<select id="countByCustomerId" resultType="int">
|
||||
select count(1) from prc_customer_price_set
|
||||
where customer_id = #{customerId}
|
||||
<if test="excludeId != null">
|
||||
AND customer_priceset_id <> #{excludeId}
|
||||
</if>
|
||||
<if test="excludePriceSetId != null">
|
||||
AND price_set_id <> #{excludePriceSetId}
|
||||
</if>
|
||||
</select>
|
||||
|
||||
<select id="countOverlap" resultType="int">
|
||||
select count(1)
|
||||
from prc_customer_price_set c
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.price.mapper.PrcQuoteFeeMapper">
|
||||
|
||||
<resultMap type="PrcQuoteFee" id="PrcQuoteFeeResult">
|
||||
<id property="feeId" column="fee_id" />
|
||||
<result property="quoteId" column="quote_id" />
|
||||
<result property="feeType" column="fee_type" />
|
||||
<result property="feeName" column="fee_name" />
|
||||
<result property="scId" column="sc_id" />
|
||||
<result property="amount" column="amount" />
|
||||
<result property="currency" column="currency" />
|
||||
<result property="roundMode" column="round_mode" />
|
||||
<result property="remark" column="remark" />
|
||||
<result property="createdAt" column="created_at" />
|
||||
</resultMap>
|
||||
|
||||
<select id="selectByQuoteId" parameterType="Long" resultMap="PrcQuoteFeeResult">
|
||||
select fee_id, quote_id, fee_type, fee_name, sc_id, amount, currency, round_mode, remark, created_at
|
||||
from prc_quote_fee
|
||||
where quote_id = #{quoteId}
|
||||
order by field(fee_type, 'BASIC_FREIGHT', 'REGISTRATION_FEE', 'SURCHARGE'), fee_id
|
||||
</select>
|
||||
|
||||
<insert id="insertPrcQuoteFee" parameterType="PrcQuoteFee" useGeneratedKeys="true" keyProperty="feeId">
|
||||
insert into prc_quote_fee (
|
||||
quote_id, fee_type, fee_name, sc_id, amount, currency, round_mode, remark, created_at
|
||||
) values (
|
||||
#{quoteId}, #{feeType}, #{feeName}, #{scId}, #{amount}, #{currency}, #{roundMode}, #{remark}, sysdate()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertBatch" parameterType="java.util.List">
|
||||
insert into prc_quote_fee (
|
||||
quote_id, fee_type, fee_name, sc_id, amount, currency, round_mode, remark, created_at
|
||||
) values
|
||||
<foreach collection="list" item="item" separator=",">
|
||||
(#{item.quoteId}, #{item.feeType}, #{item.feeName}, #{item.scId}, #{item.amount},
|
||||
#{item.currency}, #{item.roundMode}, #{item.remark}, sysdate())
|
||||
</foreach>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByQuoteId" parameterType="Long">
|
||||
delete from prc_quote_fee where quote_id = #{quoteId}
|
||||
</delete>
|
||||
</mapper>
|
||||
@@ -0,0 +1,132 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.price.mapper.PrcQuoteMapper">
|
||||
|
||||
<resultMap type="PrcQuote" id="PrcQuoteResult">
|
||||
<id property="quoteId" column="quote_id" />
|
||||
<result property="quoteKey" column="quote_key" />
|
||||
<result property="customerId" column="customer_id" />
|
||||
<result property="productCode" column="product_code" />
|
||||
<result property="productName" column="product_name" />
|
||||
<result property="countryCode" column="country_code" />
|
||||
<result property="countryName" column="country_name" />
|
||||
<result property="weight" column="weight" />
|
||||
<result property="bizDate" column="biz_date" />
|
||||
<result property="tmsId" column="tms_id" />
|
||||
<result property="matchSource" column="match_source" />
|
||||
<result property="matchMessage" column="match_message" />
|
||||
<result property="priceSetId" column="price_set_id" />
|
||||
<result property="priceSetCode" column="price_set_code" />
|
||||
<result property="priceSetName" column="price_set_name" />
|
||||
<result property="setType" column="set_type" />
|
||||
<result property="bindPriority" column="bind_priority" />
|
||||
<result property="customerPricesetId" column="customer_priceset_id" />
|
||||
<result property="productCountryId" column="product_country_id" />
|
||||
<result property="weightMin" column="weight_min" />
|
||||
<result property="weightMax" column="weight_max" />
|
||||
<result property="weightLabel" column="weight_label" />
|
||||
<result property="effectiveDate" column="effective_date" />
|
||||
<result property="chargeWeight" column="charge_weight" />
|
||||
<result property="freightRate" column="freight_rate" />
|
||||
<result property="baseFreightRate" column="base_freight_rate" />
|
||||
<result property="discountPercent" column="discount_percent" />
|
||||
<result property="registrationFee" column="registration_fee" />
|
||||
<result property="freightAmount" column="freight_amount" />
|
||||
<result property="surchargeAmount" column="surcharge_amount" />
|
||||
<result property="payableTotal" column="payable_total" />
|
||||
<result property="currency" column="currency" />
|
||||
<result property="roundMode" column="round_mode" />
|
||||
<result property="createBy" column="created_by" />
|
||||
<result property="createTime" column="created_at" />
|
||||
<result property="updateBy" column="updated_by" />
|
||||
<result property="updateTime" column="updated_at" />
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectPrcQuoteVo">
|
||||
select quote_id, quote_key, customer_id, product_code, product_name,
|
||||
country_code, country_name, weight, biz_date, tms_id,
|
||||
match_source, match_message, price_set_id, price_set_code, price_set_name,
|
||||
set_type, bind_priority, customer_priceset_id, product_country_id,
|
||||
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
||||
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
||||
freight_amount, surcharge_amount, payable_total, currency, round_mode,
|
||||
created_by, created_at, updated_by, updated_at
|
||||
from prc_quote
|
||||
</sql>
|
||||
|
||||
<select id="selectPrcQuoteByKey" parameterType="String" resultMap="PrcQuoteResult">
|
||||
<include refid="selectPrcQuoteVo"/>
|
||||
where quote_key = #{quoteKey}
|
||||
</select>
|
||||
|
||||
<select id="selectPrcQuoteById" parameterType="Long" resultMap="PrcQuoteResult">
|
||||
<include refid="selectPrcQuoteVo"/>
|
||||
where quote_id = #{quoteId}
|
||||
</select>
|
||||
|
||||
<select id="selectPrcQuoteList" parameterType="PrcQuote" resultMap="PrcQuoteResult">
|
||||
<include refid="selectPrcQuoteVo"/>
|
||||
<where>
|
||||
<if test="customerId != null">
|
||||
AND customer_id = #{customerId}
|
||||
</if>
|
||||
<if test="productCode != null and productCode != ''">
|
||||
AND product_code like concat('%', #{productCode}, '%')
|
||||
</if>
|
||||
<if test="productName != null and productName != ''">
|
||||
AND product_name like concat('%', #{productName}, '%')
|
||||
</if>
|
||||
<if test="countryCode != null and countryCode != ''">
|
||||
AND country_code = #{countryCode}
|
||||
</if>
|
||||
<if test="priceSetName != null and priceSetName != ''">
|
||||
AND price_set_name like concat('%', #{priceSetName}, '%')
|
||||
</if>
|
||||
<if test="matchSource != null and matchSource != ''">
|
||||
AND match_source = #{matchSource}
|
||||
</if>
|
||||
<if test="bizDate != null">
|
||||
AND biz_date = #{bizDate}
|
||||
</if>
|
||||
<if test="params.beginTime != null and params.beginTime != ''">
|
||||
AND date_format(created_at,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d')
|
||||
</if>
|
||||
<if test="params.endTime != null and params.endTime != ''">
|
||||
AND date_format(created_at,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
|
||||
</if>
|
||||
</where>
|
||||
order by quote_id desc
|
||||
</select>
|
||||
|
||||
<insert id="insertPrcQuote" parameterType="PrcQuote" useGeneratedKeys="true" keyProperty="quoteId">
|
||||
insert into prc_quote (
|
||||
quote_key, customer_id, product_code, product_name,
|
||||
country_code, country_name, weight, biz_date, tms_id,
|
||||
match_source, match_message, price_set_id, price_set_code, price_set_name,
|
||||
set_type, bind_priority, customer_priceset_id, product_country_id,
|
||||
weight_min, weight_max, weight_label, effective_date, charge_weight,
|
||||
freight_rate, base_freight_rate, discount_percent, registration_fee,
|
||||
freight_amount, surcharge_amount, payable_total, currency, round_mode,
|
||||
created_at
|
||||
) values (
|
||||
#{quoteKey}, #{customerId}, #{productCode}, #{productName},
|
||||
#{countryCode}, #{countryName}, #{weight}, #{bizDate}, #{tmsId},
|
||||
#{matchSource}, #{matchMessage}, #{priceSetId}, #{priceSetCode}, #{priceSetName},
|
||||
#{setType}, #{bindPriority}, #{customerPricesetId}, #{productCountryId},
|
||||
#{weightMin}, #{weightMax}, #{weightLabel}, #{effectiveDate}, #{chargeWeight},
|
||||
#{freightRate}, #{baseFreightRate}, #{discountPercent}, #{registrationFee},
|
||||
#{freightAmount}, #{surchargeAmount}, #{payableTotal}, #{currency}, #{roundMode},
|
||||
sysdate()
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateQuoteAmounts">
|
||||
update prc_quote
|
||||
set surcharge_amount = #{surchargeAmount},
|
||||
payable_total = #{payableTotal},
|
||||
updated_at = sysdate()
|
||||
where quote_id = #{quoteId}
|
||||
</update>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user