feat(pricing): 添加查询接口并优化配置管理

- 新增多个查询接口,包括商品配置、阶梯配置和一口价配置的查询- 优化配置管理逻辑,支持 default 配置的创建和使用
- 重构部分代码,提高可维护性和可扩展性
This commit is contained in:
2025-08-15 14:54:31 +08:00
parent af5c59dc67
commit 688459d2da
13 changed files with 236 additions and 36 deletions

View File

@@ -34,6 +34,13 @@ public interface IPriceBundleService {
*/
List<PriceBundleConfig> getActiveBundles();
/**
* 获取所有一口价配置(仅启用的)
*
* @return 一口价配置列表
*/
List<PriceBundleConfig> getAllBundles();
// ==================== 管理端接口(包含禁用的配置) ====================
/**

View File

@@ -44,6 +44,13 @@ public interface IProductConfigService {
*/
List<PriceProductConfig> getActiveProductConfigs();
/**
* 获取所有商品配置(仅启用的)
*
* @return 商品配置列表
*/
List<PriceProductConfig> getAllProductConfigs();
/**
* 根据商品类型获取所有阶梯配置
*

View File

@@ -2,6 +2,7 @@ package com.ycwl.basic.pricing.service.impl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ycwl.basic.pricing.dto.BundleProductItem;
import com.ycwl.basic.pricing.dto.ProductItem;
import com.ycwl.basic.pricing.entity.PriceBundleConfig;
import com.ycwl.basic.pricing.enums.ProductType;
@@ -76,6 +77,12 @@ public class PriceBundleServiceImpl implements IPriceBundleService {
return bundleConfigMapper.selectActiveBundles();
}
@Override
// @Cacheable(value = "all-bundles")
public List<PriceBundleConfig> getAllBundles() {
return bundleConfigMapper.selectActiveBundles();
}
// ==================== 管理端接口(包含禁用的配置) ====================
@Override
@@ -85,23 +92,27 @@ public class PriceBundleServiceImpl implements IPriceBundleService {
private boolean isProductsMatchBundle(Set<String> productTypes, PriceBundleConfig bundle) {
try {
List<String> includedProducts = objectMapper.readValue(
bundle.getIncludedProducts(), new TypeReference<List<String>>() {});
Set<String> requiredProducts = new HashSet<>(includedProducts);
// 检查包含的商品
if (bundle.getIncludedProducts() != null && !bundle.getIncludedProducts().isEmpty()) {
Set<String> requiredProducts = new HashSet<>();
for (BundleProductItem item : bundle.getIncludedProducts()) {
requiredProducts.add(item.getType());
}
if (!productTypes.containsAll(requiredProducts)) {
return false;
}
}
// 检查排除的商品
if (bundle.getExcludedProducts() != null && !bundle.getExcludedProducts().isEmpty()) {
List<String> excludedProducts = objectMapper.readValue(
bundle.getExcludedProducts(), new TypeReference<List<String>>() {});
for (String excludedProduct : excludedProducts) {
if (productTypes.contains(excludedProduct)) {
for (BundleProductItem item : bundle.getExcludedProducts()) {
if (productTypes.contains(item.getType())) {
return false;
}
}
}
return productTypes.containsAll(requiredProducts);
return true;
} catch (Exception e) {
log.error("解析一口价配置失败: bundleId={}", bundle.getId(), e);

View File

@@ -163,7 +163,21 @@ public class PriceCalculationServiceImpl implements IPriceCalculationService {
productType, productId);
}
// 兜底:使用通用配置(向后兼容)
// 兜底:使用default配置
try {
PriceProductConfig defaultConfig = productConfigService.getProductConfig(productType.getCode(), "default");
if (defaultConfig != null) {
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
return defaultConfig.getBasePrice().multiply(BigDecimal.valueOf(product.getQuantity()));
} else {
return defaultConfig.getBasePrice();
}
}
} catch (Exception e) {
log.warn("未找到default配置: productType={}", productType.getCode());
}
// 最后兜底:使用通用配置(向后兼容)
List<PriceProductConfig> configs = productConfigService.getProductConfig(productType.getCode());
if (!configs.isEmpty()) {
PriceProductConfig baseConfig = configs.get(0); // 使用第一个配置作为默认
@@ -214,21 +228,41 @@ public class PriceCalculationServiceImpl implements IPriceCalculationService {
log.warn("未找到具体商品配置: productType={}, productId={}, 尝试使用通用配置",
productType, productId);
// 兜底:使用通用配置(向后兼容)
List<PriceProductConfig> configs = productConfigService.getProductConfig(productType.getCode());
if (!configs.isEmpty()) {
PriceProductConfig baseConfig = configs.getFirst(); // 使用第一个配置作为默认
actualPrice = baseConfig.getBasePrice();
originalPrice = baseConfig.getOriginalPrice();
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
actualPrice = actualPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
if (originalPrice != null) {
originalPrice = originalPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
// 兜底:使用default配置
try {
PriceProductConfig defaultConfig = productConfigService.getProductConfig(productType.getCode(), "default");
if (defaultConfig != null) {
actualPrice = defaultConfig.getBasePrice();
originalPrice = defaultConfig.getOriginalPrice();
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
actualPrice = actualPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
if (originalPrice != null) {
originalPrice = originalPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
}
}
} else {
throw new PriceCalculationException("无法找到default配置");
}
} catch (Exception defaultEx) {
log.warn("未找到default配置: productType={}", productType.getCode());
// 最后兜底:使用通用配置(向后兼容)
List<PriceProductConfig> configs = productConfigService.getProductConfig(productType.getCode());
if (!configs.isEmpty()) {
PriceProductConfig baseConfig = configs.getFirst(); // 使用第一个配置作为默认
actualPrice = baseConfig.getBasePrice();
originalPrice = baseConfig.getOriginalPrice();
if (productType == ProductType.PHOTO_PRINT || productType == ProductType.MACHINE_PRINT) {
actualPrice = actualPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
if (originalPrice != null) {
originalPrice = originalPrice.multiply(BigDecimal.valueOf(product.getQuantity()));
}
}
} else {
throw new PriceCalculationException("无法计算商品价格: " + productType.getDescription() + ", productId: " + productId);
}
} else {
throw new PriceCalculationException("无法计算商品价格: " + productType.getDescription() + ", productId: " + productId);
}
}
}

View File

@@ -27,6 +27,14 @@ public class PricingManagementServiceImpl implements IPricingManagementService {
@Override
@Transactional
public Long createProductConfig(PriceProductConfig config) {
// 校验:如果是default配置,确保该商品类型只能有一个default配置
if ("default".equals(config.getProductId())) {
int existingCount = productConfigMapper.countDefaultConfigsByProductType(config.getProductType());
if (existingCount > 0) {
throw new IllegalArgumentException("商品类型 " + config.getProductType() + " 的default配置已存在,每种商品类型只能有一个default配置");
}
}
config.setCreatedTime(LocalDateTime.now());
config.setUpdatedTime(LocalDateTime.now());
productConfigMapper.insertProductConfig(config);
@@ -43,6 +51,13 @@ public class PricingManagementServiceImpl implements IPricingManagementService {
@Override
@Transactional
public Long createTierConfig(PriceTierConfig config) {
// 校验:如果是default配置,检查是否可以创建
if ("default".equals(config.getProductId())) {
// 对于阶梯配置,可以有多个default配置(不同数量区间),不需要限制
log.info("创建default阶梯配置: productType={}, quantity range: {}-{}",
config.getProductType(), config.getMinQuantity(), config.getMaxQuantity());
}
config.setCreatedTime(LocalDateTime.now());
config.setUpdatedTime(LocalDateTime.now());
tierConfigMapper.insertTierConfig(config);

View File

@@ -44,6 +44,18 @@ public class ProductConfigServiceImpl implements IProductConfigService {
// @Cacheable(value = "tier-config", key = "#productType + '_' + #productId + '_' + #quantity")
public PriceTierConfig getTierConfig(String productType, String productId, Integer quantity) {
PriceTierConfig config = tierConfigMapper.selectByProductTypeAndQuantity(productType, productId, quantity);
// 如果没有找到特定商品的阶梯配置,尝试使用default配置
if (config == null && !"default".equals(productId)) {
log.warn("阶梯定价配置未找到: productType={}, productId={}, quantity={}, 尝试使用default配置",
productType, productId, quantity);
config = tierConfigMapper.selectByProductTypeAndQuantity(productType, "default", quantity);
if (config != null) {
log.debug("使用default阶梯配置: productType={}, quantity={}, price={}",
productType, quantity, config.getPrice());
}
}
if (config == null) {
log.warn("阶梯定价配置未找到: productType={}, productId={}, quantity={}",
productType, productId, quantity);
@@ -57,6 +69,12 @@ public class ProductConfigServiceImpl implements IProductConfigService {
return productConfigMapper.selectActiveConfigs();
}
@Override
// @Cacheable(value = "all-product-configs")
public List<PriceProductConfig> getAllProductConfigs() {
return productConfigMapper.selectActiveConfigs();
}
@Override
// @Cacheable(value = "tier-configs", key = "#productType")
public List<PriceTierConfig> getTierConfigs(String productType) {