diff --git a/src/main/java/com/ycwl/basic/order/enums/DiscountType.java b/src/main/java/com/ycwl/basic/order/enums/DiscountType.java index 82730df..6ccf1f0 100644 --- a/src/main/java/com/ycwl/basic/order/enums/DiscountType.java +++ b/src/main/java/com/ycwl/basic/order/enums/DiscountType.java @@ -18,7 +18,7 @@ public enum DiscountType { /** * 限时立减 */ - FLASH_SALE("FLASH_SALE", "限时立减"), + LIMITED_TIME("LIMITED_TIME", "限时立减"), /** * 套餐优惠 diff --git a/src/main/java/com/ycwl/basic/order/service/impl/OrderServiceImpl.java b/src/main/java/com/ycwl/basic/order/service/impl/OrderServiceImpl.java index a3f3539..471bc9b 100644 --- a/src/main/java/com/ycwl/basic/order/service/impl/OrderServiceImpl.java +++ b/src/main/java/com/ycwl/basic/order/service/impl/OrderServiceImpl.java @@ -109,10 +109,10 @@ public class OrderServiceImpl implements IOrderService { orderItem.setProductType(product.getProductType().name()); orderItem.setProductId(product.getProductId()); orderItem.setProductName(getProductName(product)); // 根据商品类型和ID获取商品名称 - orderItem.setQuantity(product.getQuantity()); - orderItem.setUnitPrice(product.getUnitPrice()); - orderItem.setOriginalAmount(product.getOriginalPrice()); - orderItem.setFinalAmount(product.getSubtotal()); + orderItem.setQuantity(product.getQuantity() != null ? product.getQuantity() : 1); + orderItem.setUnitPrice(product.getUnitPrice() != null ? product.getUnitPrice() : BigDecimal.ZERO); + orderItem.setOriginalAmount(product.getOriginalPrice() != null ? product.getOriginalPrice() : BigDecimal.ZERO); + orderItem.setFinalAmount(product.getSubtotal() != null ? product.getSubtotal() : BigDecimal.ZERO); orderItem.setCreateTime(now); orderItem.setUpdateTime(now); diff --git a/src/main/java/com/ycwl/basic/pricing/CLAUDE.md b/src/main/java/com/ycwl/basic/pricing/CLAUDE.md index c1c0ebf..03c701a 100644 --- a/src/main/java/com/ycwl/basic/pricing/CLAUDE.md +++ b/src/main/java/com/ycwl/basic/pricing/CLAUDE.md @@ -438,7 +438,7 @@ public interface IDiscountDetectionService { @Component public class FlashSaleDiscountProvider implements IDiscountProvider { @Override - public String getProviderType() { return "FLASH_SALE"; } + public String getProviderType() { return "LIMITED_TIME"; } @Override public int getPriority() { return 90; } // 介于券码和优惠券之间 diff --git a/src/main/java/com/ycwl/basic/pricing/service/IDiscountProvider.java b/src/main/java/com/ycwl/basic/pricing/service/IDiscountProvider.java index 4d2a562..28c6d07 100644 --- a/src/main/java/com/ycwl/basic/pricing/service/IDiscountProvider.java +++ b/src/main/java/com/ycwl/basic/pricing/service/IDiscountProvider.java @@ -14,7 +14,7 @@ public interface IDiscountProvider { /** * 获取提供者类型 - * @return 提供者类型标识,如 "COUPON", "VOUCHER", "FLASH_SALE" 等 + * @return 提供者类型标识,如 "COUPON", "VOUCHER", "LIMITED_TIME" 等 */ String getProviderType(); diff --git a/src/main/java/com/ycwl/basic/service/PriceCacheService.java b/src/main/java/com/ycwl/basic/service/PriceCacheService.java index 8743e20..6962b8e 100644 --- a/src/main/java/com/ycwl/basic/service/PriceCacheService.java +++ b/src/main/java/com/ycwl/basic/service/PriceCacheService.java @@ -48,19 +48,25 @@ public class PriceCacheService { /** * 计算商品列表的哈希值 - * 基于商品类型、ID、数量等信息生成唯一哈希 + * 基于商品类型、ID、购买数量等必传字段生成唯一哈希,忽略可选的quantity字段 * * @param products 商品列表 * @return 哈希值 */ private String calculateProductsHash(List products) { try { - // 将商品列表转换为JSON字符串 - String productsJson = objectMapper.writeValueAsString(products); + // 构建缓存用的商品信息字符串,只包含必传字段 + StringBuilder cacheInfo = new StringBuilder(); + for (ProductItem product : products) { + cacheInfo.append(product.getProductType()).append(":") + .append(product.getProductId()).append(":") + .append(product.getPurchaseCount() != null ? product.getPurchaseCount() : 1).append(":") + .append(product.getScenicId()).append(";"); + } // 计算SHA-256哈希 MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(productsJson.getBytes()); + byte[] hash = digest.digest(cacheInfo.toString().getBytes()); // 转换为16进制字符串 StringBuilder hexString = new StringBuilder(); @@ -75,10 +81,16 @@ public class PriceCacheService { // 返回前16位作为哈希值(足够避免冲突) return hexString.substring(0, 16); - } catch (JsonProcessingException | NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { log.error("计算商品列表哈希值失败", e); - // 降级策略:使用商品列表的hashCode - return String.valueOf(products.hashCode()); + // 降级策略:使用关键字段的hashCode + StringBuilder fallback = new StringBuilder(); + for (ProductItem product : products) { + fallback.append(product.getProductType()).append(":") + .append(product.getProductId()).append(":") + .append(product.getPurchaseCount() != null ? product.getPurchaseCount() : 1).append(";"); + } + return String.valueOf(fallback.toString().hashCode()); } } diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/ScenicServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/ScenicServiceImpl.java index 8a7171d..232299e 100644 --- a/src/main/java/com/ycwl/basic/service/pc/impl/ScenicServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/pc/impl/ScenicServiceImpl.java @@ -17,6 +17,7 @@ import com.ycwl.basic.util.TtlCacheMap; import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.JacksonUtil; import lombok.extern.slf4j.Slf4j; +import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -60,7 +61,7 @@ public class ScenicServiceImpl implements ScenicService { return scenicStorageAdapterCache.computeIfAbsent(scenicId, (key) -> { IStorageAdapter adapter; ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); - if (scenicConfig.getString("store_type") != null) { + if (Strings.isNotBlank(scenicConfig.getString("store_type"))) { try { adapter = StorageFactory.get(scenicConfig.getString("store_type")); adapter.loadConfig(scenicConfig.getObject("store_config_json", Map.class)); @@ -78,7 +79,7 @@ public class ScenicServiceImpl implements ScenicService { return scenicTmpStorageAdapterCache.computeIfAbsent(scenicId, (key) -> { IStorageAdapter adapter; ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); - if (scenicConfig.getString("tmp_store_type") != null) { + if (Strings.isNotBlank(scenicConfig.getString("tmp_store_type"))) { try { adapter = StorageFactory.get(scenicConfig.getString("tmp_store_type")); adapter.loadConfig(scenicConfig.getObject("tmp_store_config_json", Map.class)); @@ -96,7 +97,7 @@ public class ScenicServiceImpl implements ScenicService { return scenicLocalStorageAdapterCache.computeIfAbsent(scenicId, (key) -> { IStorageAdapter adapter; ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); - if (scenicConfig.getString("local_store_type") != null) { + if (Strings.isNotBlank(scenicConfig.getString("local_store_type"))) { try { adapter = StorageFactory.get(scenicConfig.getString("local_store_type")); adapter.loadConfig(scenicConfig.getObject("local_store_config_json", Map.class)); @@ -115,7 +116,7 @@ public class ScenicServiceImpl implements ScenicService { return scenicFaceBodyAdapterCache.computeIfAbsent(scenicId, (key) -> { IFaceBodyAdapter adapter; ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); - if (scenicConfig.getString("face_type") != null) { + if (Strings.isNotBlank(scenicConfig.getString("face_type"))) { adapter = FaceBodyFactory.getAdapter(scenicConfig.getString("face_type")); adapter.loadConfig(scenicConfig.getObject("face_config_json", Map.class)); } else { @@ -130,7 +131,7 @@ public class ScenicServiceImpl implements ScenicService { return scenicPayAdapterCache.computeIfAbsent(scenicId, (key) -> { IPayAdapter adapter; ScenicConfigManager scenicConfig = scenicRepository.getScenicConfigManager(scenicId); - if (scenicConfig.getString("pay_type") != null) { + if (Strings.isNotBlank(scenicConfig.getString("pay_type"))) { adapter = PayFactory.getAdapter(scenicConfig.getString("pay_type")); adapter.loadConfig(scenicConfig.getObject("pay_config_json", Map.class)); } else {