|
|
@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSON;
|
|
|
import com.alibaba.fastjson2.JSONArray;
|
|
|
import com.alibaba.fastjson2.JSONObject;
|
|
|
import com.haha.common.config.CommonConfig;
|
|
|
+import com.haha.common.constant.PaymentConstants;
|
|
|
import com.haha.common.constant.RedisConstants;
|
|
|
import com.haha.common.enums.ApplyScopeEnum;
|
|
|
import com.haha.common.enums.CouponTypeEnum;
|
|
|
@@ -435,7 +436,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
logRecognizeResultDetails(resultStr, skuListStr, resourceInfoStr);
|
|
|
|
|
|
// 低置信度订单拉取开门前后图片供人工审核
|
|
|
- if (confidence != null && confidence.compareTo(new BigDecimal("0.8")) < 0) {
|
|
|
+ if (confidence != null && confidence.compareTo(PaymentConstants.CONFIDENCE_THRESHOLD) < 0) {
|
|
|
log.info("识别置信度较低({}),拉取订单图像供人工审核 - activityId: {}", confidence, activityId);
|
|
|
getOrderMedia(null, activityId);
|
|
|
}
|
|
|
@@ -516,7 +517,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
String orderName = extractParam(params, "order_name");
|
|
|
String orderGoodsStr = extractParam(params, "order_goods");
|
|
|
|
|
|
- log.info("订单信息 - 订单号: {}, 设备: {}, 活动: {}, 用户: {}, 金额: {}, 商品: {}",
|
|
|
+ log.info("订单信息 - 订单号: {}, 设备: {}, 活动ID: {}, 用户: {}, 金额: {}, 商品: {}",
|
|
|
orderId, deviceId, activityId, userId, orderMoney, orderName);
|
|
|
|
|
|
Order localOrder = null;
|
|
|
@@ -579,6 +580,20 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+ // 时间戳防重放攻击(5分钟有效期)
|
|
|
+ if (params.containsKey("timestamp")) {
|
|
|
+ try {
|
|
|
+ long ts = Long.parseLong(params.get("timestamp").toString());
|
|
|
+ long now = System.currentTimeMillis() / 1000;
|
|
|
+ if (Math.abs(now - ts) > 300) {
|
|
|
+ log.warn("回调时间戳超出有效期 - timestamp: {}, now: {}", ts, now);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ log.warn("回调时间戳格式错误: {}", params.get("timestamp"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// 哈哈平台回调签名规则(官方文档):
|
|
|
// 第一步:参数按键排序,值 URL 编码后拼接为 k1=v1&k2=v2&...
|
|
|
// 第二步:末尾直接拼接 ticket(无 & 或 = 分隔符)
|
|
|
@@ -613,14 +628,34 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
|
|
|
private String urlEncode(String value) {
|
|
|
try {
|
|
|
- return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
|
|
|
+ return URLEncoder.encode(value, StandardCharsets.UTF_8);
|
|
|
} catch (Exception e) {
|
|
|
return value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * SHA-256 加密(64位小写十六进制)
|
|
|
+ * 可用于后续升级验签算法,当前哈哈平台固定使用 MD5
|
|
|
+ */
|
|
|
+ private String sha256(String input) {
|
|
|
+ try {
|
|
|
+ java.security.MessageDigest digest = java.security.MessageDigest.getInstance("SHA-256");
|
|
|
+ byte[] bytes = digest.digest(input.getBytes(StandardCharsets.UTF_8));
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ for (byte b : bytes) {
|
|
|
+ sb.append(String.format("%02x", b));
|
|
|
+ }
|
|
|
+ return sb.toString();
|
|
|
+ } catch (java.security.NoSuchAlgorithmException e) {
|
|
|
+ throw new RuntimeException("SHA-256 算法不可用", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* MD5 加密(32位小写十六进制)
|
|
|
+ * ⚠️ 哈哈平台回调签名规则固定使用 MD5,不可单方面升级
|
|
|
+ * 补偿措施:签名验证前增加时间戳有效性校验
|
|
|
*/
|
|
|
private String md5(String str) {
|
|
|
try {
|
|
|
@@ -636,108 +671,78 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void saveDeviceStatusToRedis(String deviceId, String activityId, String doorStatus, String openType, String outUserId) {
|
|
|
- try {
|
|
|
- String statusKey = RedisConstants.HAHA_DEVICE_STATUS_KEY + deviceId;
|
|
|
- Map<String, String> statusData = new HashMap<>();
|
|
|
- statusData.put("deviceId", deviceId != null ? deviceId : "");
|
|
|
- statusData.put("activityId", activityId != null ? activityId : "");
|
|
|
- statusData.put("status", doorStatus != null ? doorStatus : "");
|
|
|
- statusData.put("openType", openType != null ? openType : "");
|
|
|
- statusData.put("userId", outUserId != null ? outUserId : "");
|
|
|
- statusData.put("doorStatus", doorStatus != null ? DeviceDoorStatus.convertToStatus(doorStatus) : "");
|
|
|
- statusData.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
-
|
|
|
- stringRedisTemplate.opsForHash().putAll(statusKey, statusData);
|
|
|
- stringRedisTemplate.expire(statusKey, 30, TimeUnit.MINUTES);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("保存设备状态到Redis失败 - deviceId: {}", deviceId, e);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
- * 保存识别结果到Redis
|
|
|
- * @param activityId
|
|
|
- * @param params
|
|
|
+ * 通用 Redis Hash 保存(putAll + expire)
|
|
|
*/
|
|
|
- private void saveRecognizeResultToRedis(String activityId, Map<String, Object> params) {
|
|
|
+ private void saveHashToRedis(String key, Map<String, String> data, long timeout, TimeUnit unit) {
|
|
|
try {
|
|
|
- String resultKey = RedisConstants.HAHA_RECOGNIZE_RESULT_KEY + activityId;
|
|
|
- Map<String, String> recognizeData = new HashMap<>();
|
|
|
- recognizeData.put("activityId", activityId != null ? activityId : "");
|
|
|
- recognizeData.put("deviceId", params.get("device_id") != null ? String.valueOf(params.get("device_id")) : "");
|
|
|
- recognizeData.put("userId", params.get("out_user_id") != null ? String.valueOf(params.get("out_user_id")) : "");
|
|
|
- recognizeData.put("nobuy", params.get("nobuy") != null ? String.valueOf(params.get("nobuy")) : "0");
|
|
|
- recognizeData.put("result", params.get("result") != null ? String.valueOf(params.get("result")) : "");
|
|
|
- recognizeData.put("skuList", params.get("sku_list") != null ? String.valueOf(params.get("sku_list")) : "");
|
|
|
- recognizeData.put("resourceInfo", params.get("resource_info") != null ? String.valueOf(params.get("resource_info")) : "");
|
|
|
- recognizeData.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
-
|
|
|
- stringRedisTemplate.opsForHash().putAll(resultKey, recognizeData);
|
|
|
- stringRedisTemplate.expire(resultKey, 30, TimeUnit.MINUTES);
|
|
|
+ stringRedisTemplate.opsForHash().putAll(key, data);
|
|
|
+ stringRedisTemplate.expire(key, timeout, unit);
|
|
|
} catch (Exception e) {
|
|
|
- log.error("保存识别结果到Redis失败 - activityId: {}", activityId, e);
|
|
|
+ log.error("保存数据到Redis失败 - key: {}", key, e);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 保存订单信息到Redis
|
|
|
- * @param order
|
|
|
- * @param activityId
|
|
|
- */
|
|
|
- private void saveOrderInfoToRedis(Order order, String activityId) {
|
|
|
- try {
|
|
|
- String orderKey = RedisConstants.HAHA_ORDER_INFO_KEY + activityId;
|
|
|
-
|
|
|
- stringRedisTemplate.delete(orderKey);
|
|
|
-
|
|
|
- Map<String, String> orderData = new HashMap<>();
|
|
|
- orderData.put("orderId", order.getId() != null ? order.getId().toString() : "");
|
|
|
- orderData.put("orderNo", order.getOrderNo() != null ? order.getOrderNo() : "");
|
|
|
- orderData.put("activityId", activityId != null ? activityId : "");
|
|
|
- orderData.put("deviceId", order.getDeviceId() != null ? order.getDeviceId() : "");
|
|
|
- orderData.put("userId", order.getUserId() != null ? order.getUserId().toString() : "");
|
|
|
- orderData.put("totalAmount", order.getTotalAmount() != null ? order.getTotalAmount().toString() : "0");
|
|
|
- orderData.put("items", order.getItems() != null ? order.getItems() : "");
|
|
|
- orderData.put("status", order.getStatus() != null ? order.getStatus().toString() : "");
|
|
|
- orderData.put("payStatus", order.getPayStatus() != null ? order.getPayStatus().toString() : "");
|
|
|
- orderData.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
-
|
|
|
- stringRedisTemplate.opsForHash().putAll(orderKey, orderData);
|
|
|
- stringRedisTemplate.expire(orderKey, 30, TimeUnit.MINUTES);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("保存订单信息到Redis失败 - activityId: {}", activityId, e);
|
|
|
- }
|
|
|
+ private static String nullToEmpty(Object val) {
|
|
|
+ return val != null ? val.toString() : "";
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 订单信息保存到Redis
|
|
|
- * @param order
|
|
|
- * @param activityId
|
|
|
- * @param orderId
|
|
|
- * @param orderMoney
|
|
|
- * @param orderDetail
|
|
|
- */
|
|
|
- private void saveOrderInfoToRedis(Order order, String activityId, String orderId, Object orderMoney, String orderDetail) {
|
|
|
- try {
|
|
|
- String orderKey = RedisConstants.HAHA_ORDER_INFO_KEY + activityId;
|
|
|
+ private void saveDeviceStatusToRedis(String deviceId, String activityId, String doorStatus, String openType, String outUserId) {
|
|
|
+ String key = RedisConstants.HAHA_DEVICE_STATUS_KEY + deviceId;
|
|
|
+ Map<String, String> data = new HashMap<>();
|
|
|
+ data.put("deviceId", nullToEmpty(deviceId));
|
|
|
+ data.put("activityId", nullToEmpty(activityId));
|
|
|
+ data.put("status", nullToEmpty(doorStatus));
|
|
|
+ data.put("openType", nullToEmpty(openType));
|
|
|
+ data.put("userId", nullToEmpty(outUserId));
|
|
|
+ data.put("doorStatus", nullToEmpty(DeviceDoorStatus.convertToStatus(doorStatus)));
|
|
|
+ data.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
+ saveHashToRedis(key, data, PaymentConstants.REDIS_DEFAULT_TIMEOUT_MINUTES, TimeUnit.MINUTES);
|
|
|
+ }
|
|
|
|
|
|
- stringRedisTemplate.delete(orderKey);
|
|
|
+ private void saveRecognizeResultToRedis(String activityId, Map<String, Object> params) {
|
|
|
+ String key = RedisConstants.HAHA_RECOGNIZE_RESULT_KEY + activityId;
|
|
|
+ Map<String, String> data = new HashMap<>();
|
|
|
+ data.put("activityId", nullToEmpty(activityId));
|
|
|
+ data.put("deviceId", nullToEmpty(params.get("device_id")));
|
|
|
+ data.put("userId", nullToEmpty(params.get("out_user_id")));
|
|
|
+ data.put("nobuy", params.get("nobuy") != null ? String.valueOf(params.get("nobuy")) : "0");
|
|
|
+ data.put("result", nullToEmpty(params.get("result")));
|
|
|
+ data.put("skuList", nullToEmpty(params.get("sku_list")));
|
|
|
+ data.put("resourceInfo", nullToEmpty(params.get("resource_info")));
|
|
|
+ data.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
+ saveHashToRedis(key, data, PaymentConstants.REDIS_DEFAULT_TIMEOUT_MINUTES, TimeUnit.MINUTES);
|
|
|
+ }
|
|
|
|
|
|
- Map<String, String> orderData = new HashMap<>();
|
|
|
- orderData.put("orderId", orderId != null ? orderId : "");
|
|
|
- orderData.put("activityId", activityId != null ? activityId : "");
|
|
|
- orderData.put("deviceId", order.getDeviceId() != null ? order.getDeviceId() : "");
|
|
|
- orderData.put("userId", order.getUserId() != null ? order.getUserId().toString() : "");
|
|
|
- orderData.put("totalAmount", orderMoney != null ? orderMoney.toString() : "0");
|
|
|
- orderData.put("products", orderDetail != null ? orderDetail : "");
|
|
|
- orderData.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
+ private void saveOrderInfoToRedis(Order order, String activityId) {
|
|
|
+ String key = RedisConstants.HAHA_ORDER_INFO_KEY + activityId;
|
|
|
+ stringRedisTemplate.delete(key);
|
|
|
+ Map<String, String> data = new HashMap<>();
|
|
|
+ data.put("orderId", nullToEmpty(order.getId()));
|
|
|
+ data.put("orderNo", nullToEmpty(order.getOrderNo()));
|
|
|
+ data.put("activityId", nullToEmpty(activityId));
|
|
|
+ data.put("deviceId", nullToEmpty(order.getDeviceId()));
|
|
|
+ data.put("userId", nullToEmpty(order.getUserId()));
|
|
|
+ data.put("totalAmount", order.getTotalAmount() != null ? order.getTotalAmount().toString() : "0");
|
|
|
+ data.put("items", nullToEmpty(order.getItems()));
|
|
|
+ data.put("status", nullToEmpty(order.getStatus()));
|
|
|
+ data.put("payStatus", nullToEmpty(order.getPayStatus()));
|
|
|
+ data.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
+ saveHashToRedis(key, data, PaymentConstants.REDIS_DEFAULT_TIMEOUT_MINUTES, TimeUnit.MINUTES);
|
|
|
+ }
|
|
|
|
|
|
- stringRedisTemplate.opsForHash().putAll(orderKey, orderData);
|
|
|
- stringRedisTemplate.expire(orderKey, 30, TimeUnit.MINUTES);
|
|
|
- } catch (Exception e) {
|
|
|
- log.error("保存订单信息到Redis失败 - activityId: {}", activityId, e);
|
|
|
- }
|
|
|
+ private void saveOrderInfoToRedis(Order order, String activityId, String orderId, Object orderMoney, String orderDetail) {
|
|
|
+ String key = RedisConstants.HAHA_ORDER_INFO_KEY + activityId;
|
|
|
+ stringRedisTemplate.delete(key);
|
|
|
+ Map<String, String> data = new HashMap<>();
|
|
|
+ data.put("orderId", nullToEmpty(orderId));
|
|
|
+ data.put("activityId", nullToEmpty(activityId));
|
|
|
+ data.put("deviceId", nullToEmpty(order.getDeviceId()));
|
|
|
+ data.put("userId", nullToEmpty(order.getUserId()));
|
|
|
+ data.put("totalAmount", orderMoney != null ? orderMoney.toString() : "0");
|
|
|
+ data.put("products", nullToEmpty(orderDetail));
|
|
|
+ data.put("timestamp", String.valueOf(System.currentTimeMillis()));
|
|
|
+ saveHashToRedis(key, data, PaymentConstants.REDIS_DEFAULT_TIMEOUT_MINUTES, TimeUnit.MINUTES);
|
|
|
}
|
|
|
|
|
|
private void updateDeviceDoorStatus(String deviceId, String doorStatus) {
|
|
|
@@ -776,7 +781,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
// 更新订单信息:只更新商品列表和视频URL,不更新金额
|
|
|
order.setItems(skuListStr);
|
|
|
// 注意:不更新totalAmount,保持为0,等待订单回调时更新
|
|
|
-
|
|
|
+
|
|
|
if (videoUrl != null) {
|
|
|
order.setVideoUrl(videoUrl);
|
|
|
}
|
|
|
@@ -830,7 +835,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
// 设备端传来的金额是已经计算过营销活动优惠后的金额
|
|
|
BigDecimal totalAmount = new BigDecimal(orderMoney.toString());
|
|
|
order.setTotalAmount(totalAmount);
|
|
|
-
|
|
|
+
|
|
|
// 初始化优惠金额和实付金额(后续会被processCouponDiscount更新)
|
|
|
order.setDiscountAmount(BigDecimal.ZERO);
|
|
|
order.setPaidAmount(totalAmount);
|
|
|
@@ -942,25 +947,6 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * 计算订单总金额
|
|
|
- *
|
|
|
- * 注意:
|
|
|
- * - AI识别结果(sku_list)不包含价格信息,只包含商品编码和数量
|
|
|
- * - 此方法目前已不使用,因为订单金额由设备端在回调时直接提供
|
|
|
- * - 保留此方法以备后续可能的服务端价格校验需求
|
|
|
- *
|
|
|
- * @param skuListStr 商品列表JSON字符串
|
|
|
- * @return 总金额,如果无法计算则返回0
|
|
|
- */
|
|
|
- @Deprecated
|
|
|
- private BigDecimal calculateTotalAmount(String skuListStr) {
|
|
|
- // 注意:AI识别结果不包含price字段,此方法无法正确计算金额
|
|
|
- // 订单金额应由设备端在回调时提供(order_money参数)
|
|
|
- log.warn("calculateTotalAmount方法已废弃,AI识别结果不包含价格信息");
|
|
|
- return BigDecimal.ZERO;
|
|
|
- }
|
|
|
-
|
|
|
private String parseVideoUrl(String resourceInfoStr) {
|
|
|
if (resourceInfoStr != null && !resourceInfoStr.isEmpty()) {
|
|
|
JSONObject resourceInfo = JSON.parseObject(resourceInfoStr);
|
|
|
@@ -1054,16 +1040,21 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
return null;
|
|
|
}
|
|
|
try {
|
|
|
- if (value instanceof Integer) {
|
|
|
- return (Integer) value;
|
|
|
- } else if (value instanceof String) {
|
|
|
- String str = (String) value;
|
|
|
- if (str.trim().isEmpty()) {
|
|
|
- return null;
|
|
|
+ switch (value) {
|
|
|
+ case Integer i -> {
|
|
|
+ return i;
|
|
|
+ }
|
|
|
+ case String str -> {
|
|
|
+ if (str.trim().isEmpty()) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return Integer.parseInt(str);
|
|
|
+ }
|
|
|
+ case Number number -> {
|
|
|
+ return number.intValue();
|
|
|
+ }
|
|
|
+ default -> {
|
|
|
}
|
|
|
- return Integer.parseInt(str);
|
|
|
- } else if (value instanceof Number) {
|
|
|
- return ((Number) value).intValue();
|
|
|
}
|
|
|
} catch (NumberFormatException e) {
|
|
|
log.warn("无法转换为整型: {}", value);
|
|
|
@@ -1085,7 +1076,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
|
|
|
/**
|
|
|
* 处理优惠券扣减
|
|
|
- *
|
|
|
+ *
|
|
|
* 业务流程:
|
|
|
* 1. 查询用户所有可用优惠券(未使用且未过期)
|
|
|
* 2. 按到期时间升序排序(优先使用最先到期的券)
|
|
|
@@ -1095,12 +1086,12 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
* 4. 使用第一张符合条件的优惠券
|
|
|
* 5. 计算优惠后的最终金额
|
|
|
* 6. 标记优惠券为已使用
|
|
|
- *
|
|
|
+ *
|
|
|
* 注意:
|
|
|
* - 一次订单只能使用一张优惠券
|
|
|
* - 优惠金额不能超过订单金额
|
|
|
* - 如果设备端已传来优惠后金额,不再使用优惠券
|
|
|
- *
|
|
|
+ *
|
|
|
* @param order 订单对象
|
|
|
* @param orderMoney 设备端传来的订单金额(可能已包含营销活动优惠)
|
|
|
* @return 最终实付金额(优惠后)
|
|
|
@@ -1127,7 +1118,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
return originalAmount;
|
|
|
}
|
|
|
|
|
|
- log.info("用户有 {} 张可用优惠券,开始筛选 - userId: {}, orderId: {}",
|
|
|
+ log.info("用户有 {} 张可用优惠券,开始筛选 - userId: {}, orderId: {}",
|
|
|
availableCoupons.size(), userId, order.getId());
|
|
|
|
|
|
// 3. 按到期时间升序排序(优先使用最先到期的券)
|
|
|
@@ -1152,7 +1143,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
if (isCouponApplicable(couponWithTemplate, order, originalAmount)) {
|
|
|
selectedCoupon = couponWithTemplate;
|
|
|
discountAmount = calculateCouponDiscount(couponWithTemplate, originalAmount);
|
|
|
- log.info("找到符合条件的优惠券 - couponId: {}, couponName: {}, discountAmount: {}",
|
|
|
+ log.info("找到符合条件的优惠券 - couponId: {}, couponName: {}, discountAmount: {}",
|
|
|
coupon.getId(), couponWithTemplate.getCouponName(), discountAmount);
|
|
|
break; // 只使用一张优惠券
|
|
|
}
|
|
|
@@ -1179,7 +1170,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
// 8. 使用优惠券(标记为已使用)
|
|
|
try {
|
|
|
userCouponService.useCoupon(selectedCoupon.getId(), userId, order.getId(), discountAmount);
|
|
|
- log.info("优惠券使用成功 - couponId: {}, orderId: {}, discountAmount: {}, finalAmount: {}",
|
|
|
+ log.info("优惠券使用成功 - couponId: {}, orderId: {}, discountAmount: {}, finalAmount: {}",
|
|
|
selectedCoupon.getId(), order.getId(), discountAmount, finalAmount);
|
|
|
} catch (Exception e) {
|
|
|
log.error("优惠券使用失败 - couponId: {}, orderId: {}", selectedCoupon.getId(), order.getId(), e);
|
|
|
@@ -1191,8 +1182,8 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
order.setDiscountAmount(discountAmount);
|
|
|
order.setPaidAmount(finalAmount);
|
|
|
orderService.updateById(order);
|
|
|
-
|
|
|
- log.info("订单优惠金额已更新 - orderId: {}, totalAmount: {}, discountAmount: {}, paidAmount: {}",
|
|
|
+
|
|
|
+ log.info("订单优惠金额已更新 - orderId: {}, totalAmount: {}, discountAmount: {}, paidAmount: {}",
|
|
|
order.getId(), originalAmount, discountAmount, finalAmount);
|
|
|
|
|
|
return finalAmount;
|
|
|
@@ -1206,7 +1197,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
|
|
|
/**
|
|
|
* 检查优惠券是否适用于当前订单
|
|
|
- *
|
|
|
+ *
|
|
|
* @param coupon 优惠券信息(包含模板信息)
|
|
|
* @param order 订单信息
|
|
|
* @param orderAmount 订单金额
|
|
|
@@ -1216,7 +1207,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
try {
|
|
|
// 1. 检查订单金额是否达到满减门槛
|
|
|
if (coupon.getMinAmount() != null && orderAmount.compareTo(coupon.getMinAmount()) < 0) {
|
|
|
- log.debug("订单金额未达到优惠券门槛 - couponId: {}, minAmount: {}, orderAmount: {}",
|
|
|
+ log.debug("订单金额未达到优惠券门槛 - couponId: {}, minAmount: {}, orderAmount: {}",
|
|
|
coupon.getId(), coupon.getMinAmount(), orderAmount);
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1236,13 +1227,6 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- if (applyScope == ApplyScopeEnum.SPECIFIED_SHOP.getCode()) {
|
|
|
- // 指定商品范围,检查订单商品是否匹配
|
|
|
- // TODO: 根据订单商品列表检查是否包含优惠券指定的商品
|
|
|
- log.debug("优惠券为指定商品范围,当前简化处理为适用 - couponId: {}", coupon.getId());
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
return true;
|
|
|
|
|
|
} catch (Exception e) {
|
|
|
@@ -1253,13 +1237,13 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
|
|
|
/**
|
|
|
* 计算优惠券优惠金额
|
|
|
- *
|
|
|
+ *
|
|
|
* 根据优惠券类型计算:
|
|
|
* - type=1 (满减券): 直接返回discountValue
|
|
|
* - type=2 (折扣券): orderAmount * (1 - discountValue/10)
|
|
|
* - type=3 (抵扣券): 直接返回discountValue
|
|
|
* - type=4 (兑换券): 不适用,返回0
|
|
|
- *
|
|
|
+ *
|
|
|
* @param coupon 优惠券信息
|
|
|
* @param orderAmount 订单金额
|
|
|
* @return 优惠金额
|
|
|
@@ -1281,7 +1265,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
|
|
|
if (couponType == CouponTypeEnum.DISCOUNT.getCode()) {
|
|
|
// discountValue 表示折扣,如8表示8折
|
|
|
// 优惠金额 = orderAmount * (1 - discountValue/10)
|
|
|
- BigDecimal discount = discountValue.divide(new BigDecimal("10"), 2, RoundingMode.HALF_UP);
|
|
|
+ BigDecimal discount = discountValue.divide(PaymentConstants.DISCOUNT_DIVISOR, 2, RoundingMode.HALF_UP);
|
|
|
BigDecimal discountAmount = orderAmount.multiply(BigDecimal.ONE.subtract(discount));
|
|
|
|
|
|
// 检查是否有最大优惠限制(需要从CouponTemplate获取)
|