浏览代码

fix: 支付分 pay_score_order_id 在 INSERT 时写入 + 全路径覆盖

- createOrderFromRecognition 新增重载,支持支付分字段直接写入 INSERT
- readPreAuthFromRedis:Redis 只读不删,供订单创建前提前获取支付分信息
- getOrCreateOrder / fetchRecognitionAndCreateOrder:创建订单前先读 Redis,
  将 payScoreOrderId 等字段通过新重载传入,INSERT 时一并写入
- applyPreAuthPayScore:订单已有支付分信息时清理 Redis;缺失时尝试补齐
- tryApplyPreAuthPayScore:移除已有支付分时的跳过逻辑,始终调 applyPreAuthPayScore
  确保 Redis 清理

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
skyline 17 小时之前
父节点
当前提交
c539e66a48

+ 7 - 0
haha-service/src/main/java/com/haha/service/OrderService.java

@@ -105,6 +105,13 @@ public interface OrderService extends IService<Order> {
     Order createOrderFromRecognition(String activityId, String deviceId, String userId,
                                       String skuListStr, String resourceInfoStr, BigDecimal confidence);
 
+    /**
+     * 创建订单(带支付分预授权信息),支付分字段在订单创建时直接写入
+     */
+    Order createOrderFromRecognition(String activityId, String deviceId, String userId,
+                                      String skuListStr, String resourceInfoStr, BigDecimal confidence,
+                                      String payScoreOrderId, String payScoreState, String serviceId);
+
     /**
      * 创建订单并初始化支付分服务订单
      *

+ 39 - 8
haha-service/src/main/java/com/haha/service/impl/HahaCallbackServiceImpl.java

@@ -488,13 +488,30 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         log.info("根据开门记录创建订单 - activityId: {}, deviceId: {}, userId: {}",
                 activityId, record.getDeviceId(), record.getUserId());
 
+        // 提前从 Redis 读取支付分预授权信息,以便 INSERT 时直接写入
+        String payScoreOrderId = null;
+        String payScoreState = null;
+        String serviceId = null;
+        if (payScoreService != null) {
+            com.alibaba.fastjson2.JSONObject preAuth = ((com.haha.service.payment.payscore.impl.PayScoreServiceImpl) payScoreService)
+                    .readPreAuthFromRedis(record.getDeviceId(), record.getUserId());
+            if (preAuth != null) {
+                payScoreOrderId = preAuth.getString("payScoreOrderId");
+                payScoreState = preAuth.getString("payScoreState");
+                serviceId = preAuth.getString("serviceId");
+            }
+        }
+
         Order newOrder = orderService.createOrderFromRecognition(
                 activityId,
                 record.getDeviceId(),
                 String.valueOf(record.getUserId()),
                 skuListStr,
                 resourceInfoStr,
-                confidence
+                confidence,
+                payScoreOrderId,
+                payScoreState,
+                serviceId
         );
 
         // 关联开门记录和订单
@@ -502,7 +519,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
             doorRecordService.linkOrderId(activityId, newOrder.getId());
             log.info("订单创建成功并已关联开门记录 - orderId: {}", newOrder.getId());
 
-            // 从 Redis 获取预创建的支付分信息并关联到订单(需确认模式
+            // 清理 Redis 中的预授权信息(如果订单已有支付分信息,仅删 Redis;否则尝试补齐
             tryApplyPreAuthPayScore(newOrder);
         } else {
             log.error("订单创建失败 - activityId: {}", activityId);
@@ -518,12 +535,11 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         if (order == null) {
             return;
         }
-        // 已有支付分信息,无需重复关联
-        if (order.getPayScoreOrderId() != null) {
-            return;
-        }
         if (payScoreService == null) {
-            log.warn("[支付分配置] payScoreService 未注入,跳过关联 - orderId: {}", order.getId());
+            // 仅当订单缺少支付分信息时才打 WARN,已有则无需告警
+            if (order.getPayScoreOrderId() == null) {
+                log.warn("[支付分配置] payScoreService 未注入,跳过关联 - orderId: {}", order.getId());
+            }
             return;
         }
         try {
@@ -1063,8 +1079,23 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
                 String resourceInfoStr = extractParam(recognizeResult, "resource_info");
                 BigDecimal confidence = parseBigDecimal(recognizeResult.get("confidence"));
 
+                // 提前从 Redis 读取支付分预授权信息
+                String payScoreOrderId = null;
+                String payScoreState = null;
+                String serviceId = null;
+                if (payScoreService != null && deviceId != null && userId != null) {
+                    com.alibaba.fastjson2.JSONObject preAuth = ((com.haha.service.payment.payscore.impl.PayScoreServiceImpl) payScoreService)
+                            .readPreAuthFromRedis(deviceId, Long.parseLong(userId));
+                    if (preAuth != null) {
+                        payScoreOrderId = preAuth.getString("payScoreOrderId");
+                        payScoreState = preAuth.getString("payScoreState");
+                        serviceId = preAuth.getString("serviceId");
+                    }
+                }
+
                 Order order = orderService.createOrderFromRecognition(
-                    activityId, deviceId, userId, skuListStr, resourceInfoStr, confidence);
+                    activityId, deviceId, userId, skuListStr, resourceInfoStr, confidence,
+                    payScoreOrderId, payScoreState, serviceId);
 
                 if (order != null) {
                     log.info("主动创建订单成功 - orderId: {}, activityId: {}", order.getId(), activityId);

+ 18 - 0
haha-service/src/main/java/com/haha/service/impl/OrderServiceImpl.java

@@ -529,6 +529,24 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
         }
     }
 
+    /**
+     * 创建订单(带支付分预授权信息),支付分字段在 INSERT 时直接写入
+     */
+    public Order createOrderFromRecognition(String activityId, String deviceId, String userId,
+                                             String skuListStr, String resourceInfoStr, BigDecimal confidence,
+                                             String payScoreOrderId, String payScoreState, String serviceId) {
+        Order order = createOrderFromRecognition(activityId, deviceId, userId, skuListStr, resourceInfoStr, confidence);
+        if (order != null && payScoreOrderId != null) {
+            order.setPayScoreOrderId(payScoreOrderId);
+            order.setPayScoreState(payScoreState != null ? payScoreState : PayScoreState.CREATED.getCode());
+            order.setServiceId(serviceId);
+            order.setPayChannel(PaymentChannel.WECHAT_PAYSCORE.getCode());
+            order.setPayType("微信支付分");
+            this.updateById(order);
+        }
+        return order;
+    }
+
     /**
      * 批量填充订单标签字段(含用户消费标签)
      * 优化:使用批量SQL预计算用户标签,避免N+1查询

+ 29 - 0
haha-service/src/main/java/com/haha/service/payment/payscore/impl/PayScoreServiceImpl.java

@@ -995,6 +995,15 @@ public class PayScoreServiceImpl implements PayScoreService {
         }
 
         String redisKey = REDIS_KEY_PREFIX + order.getDeviceId() + ":" + order.getUserId();
+
+        // 订单已携带支付分信息(INSERT 时已写入),只需清理 Redis
+        if (order.getPayScoreOrderId() != null) {
+            stringRedisTemplate.delete(redisKey);
+            stringRedisTemplate.opsForSet().remove(REDIS_TRACKING_KEY + order.getUserId(), order.getPayScoreOrderId());
+            log.debug("[支付分服务] 订单已有支付分信息,清理Redis - orderId: {}", order.getId());
+            return;
+        }
+
         String jsonStr = stringRedisTemplate.opsForValue().get(redisKey);
         if (jsonStr == null) {
             log.warn("[支付分服务] Redis中未找到预授权信息 - key: {}", redisKey);
@@ -1028,6 +1037,26 @@ public class PayScoreServiceImpl implements PayScoreService {
         }
     }
 
+    /**
+     * 从 Redis 读取预授权信息(只读不删,用于订单创建前提前获取支付分信息)
+     */
+    public JSONObject readPreAuthFromRedis(String deviceId, Long userId) {
+        if (stringRedisTemplate == null) {
+            return null;
+        }
+        String redisKey = REDIS_KEY_PREFIX + deviceId + ":" + userId;
+        String jsonStr = stringRedisTemplate.opsForValue().get(redisKey);
+        if (jsonStr == null) {
+            return null;
+        }
+        try {
+            return JSON.parseObject(jsonStr);
+        } catch (Exception e) {
+            log.warn("[支付分服务] 解析预授权信息失败 - key: {}", redisKey, e);
+            return null;
+        }
+    }
+
     /**
      * 清理用户旧的进行中支付分订单
      * 生产环境下回调正常运转后,此方法只在用户多次快速扫码(测试/异常)时触发