Răsfoiți Sursa

小程序调试

skyline 2 luni în urmă
părinte
comite
8fd3f559d0

+ 10 - 5
haha-entity/src/main/java/com/haha/entity/User.java

@@ -21,15 +21,20 @@ public class User implements Serializable {
     private String phone;
 
     private String nickname;
-
+    
     private String avatar;
-
+    
     private Integer creditScore;
-
+    
     private Integer status;
-
+    
+    /**
+     * 微信支付分开通状态:0-未开通,1-已开通
+     */
+    private Integer payscoreEnabled;
+    
     private LocalDateTime createTime;
-
+    
     private LocalDateTime updateTime;
     
     // ========== 以下为非数据库字段,用于前端展示 ==========

+ 35 - 11
haha-miniapp/src/main/java/com/haha/miniapp/controller/OrderController.java

@@ -68,16 +68,16 @@ public class OrderController {
 
                 if (order.getItems() != null && !order.getItems().isEmpty()) {
                     try {
-                        JSONArray items = JSON.parseArray(order.getItems());
+                        JSONArray items = parseItemsArray(order.getItems());
                         List<Map<String, Object>> products = new ArrayList<>();
                         for (int i = 0; i < items.size(); i++) {
                             JSONObject item = items.getJSONObject(i);
                             Map<String, Object> product = new HashMap<>();
-                            product.put("id", item.getString("goodsId"));
-                            product.put("name", item.getString("goodsName"));
+                            product.put("id", item.getString("product_id"));
+                            product.put("name", item.getString("product_name"));
                             product.put("price", item.getDouble("price"));
-                            product.put("quantity", item.getInteger("quantity"));
-                            product.put("image", item.getString("image"));
+                            product.put("quantity", item.getInteger("product_num"));
+                            product.put("image", item.getString("pic"));
                             products.add(product);
                         }
                         orderMap.put("products", products);
@@ -163,17 +163,19 @@ public class OrderController {
 
             if (order.getItems() != null && !order.getItems().isEmpty()) {
                 try {
-                    JSONArray items = JSON.parseArray(order.getItems());
+                    JSONArray items = parseItemsArray(order.getItems());
                     List<Map<String, Object>> products = new ArrayList<>();
                     for (int i = 0; i < items.size(); i++) {
                         JSONObject item = items.getJSONObject(i);
                         Map<String, Object> product = new HashMap<>();
-                        product.put("id", item.getString("goodsId"));
-                        product.put("name", item.getString("goodsName"));
+                        product.put("id", item.getString("product_id"));
+                        product.put("name", item.getString("product_name"));
                         product.put("price", item.getDouble("price"));
-                        product.put("quantity", item.getInteger("quantity"));
-                        product.put("image", item.getString("image"));
-                        product.put("subtotal", item.getDouble("price") * item.getInteger("quantity"));
+                        product.put("quantity", item.getInteger("product_num"));
+                        product.put("image", item.getString("pic"));
+                        Double price = item.getDouble("price");
+                        Integer quantity = item.getInteger("product_num");
+                        product.put("subtotal", price != null && quantity != null ? price * quantity : 0);
                         products.add(product);
                     }
                     orderDetail.put("products", products);
@@ -243,6 +245,28 @@ public class OrderController {
         }
     }
 
+    /**
+     * 解析商品列表数组
+     * 支持两种格式:
+     * 1. {"goods":[...]} - 回调数据格式
+     * 2. [...] - 直接数组格式
+     */
+    private JSONArray parseItemsArray(String itemsStr) {
+        if (itemsStr == null || itemsStr.isEmpty()) {
+            return new JSONArray();
+        }
+        
+        String trimmed = itemsStr.trim();
+        if (trimmed.startsWith("{")) {
+            JSONObject obj = JSON.parseObject(itemsStr);
+            JSONArray goods = obj.getJSONArray("goods");
+            return goods != null ? goods : new JSONArray();
+        } else if (trimmed.startsWith("[")) {
+            return JSON.parseArray(itemsStr);
+        }
+        return new JSONArray();
+    }
+
     /**
      * 获取订单状态文本
      */

+ 110 - 0
haha-miniapp/src/main/java/com/haha/miniapp/controller/PayScoreController.java

@@ -5,7 +5,9 @@ import cn.dev33.satoken.stp.StpUtil;
 import com.alibaba.fastjson2.JSON;
 import com.haha.common.vo.Result;
 import com.haha.entity.Order;
+import com.haha.entity.User;
 import com.haha.service.OrderService;
+import com.haha.service.UserService;
 import com.haha.service.payment.payscore.*;
 import com.haha.service.payment.payscore.PayScoreCreateRequest.PostPayment;
 import com.haha.service.payment.payscore.PayScoreCompleteRequest.PostDiscount;
@@ -30,8 +32,116 @@ import java.util.Map;
 @RequiredArgsConstructor
 public class PayScoreController {
 
+    private static final int PAYSCORE_ENABLED = 1;
+
     private final PayScoreService payScoreService;
     private final OrderService orderService;
+    private final UserService userService;
+
+    /**
+     * 检查用户是否已开通微信支付分
+     * GET /api/payscore/check-enable
+     *
+     * @return 开通状态
+     */
+    @GetMapping("/check-enable")
+    public Result<Map<String, Object>> checkPayscoreEnabled() {
+        Long userId = StpUtil.getLoginIdAsLong();
+        log.info("用户 {} 查询支付分开通状态", userId);
+
+        try {
+            User user = userService.getById(userId);
+            if (user == null) {
+                return Result.error(404, "用户不存在");
+            }
+
+            boolean isEnabled = isPayscoreEnabled(user);
+            Map<String, Object> data = buildEnableStatusData(isEnabled, userId);
+            
+            log.info("用户 {} 支付分开通状态:{}", userId, isEnabled ? "已开通" : "未开通");
+            return Result.success("查询成功", data);
+
+        } catch (Exception e) {
+            log.error("查询支付分开通状态失败 - userId: {}", userId, e);
+            return Result.error("查询失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 标记用户已开通微信支付分
+     * POST /api/payscore/enable
+     *
+     * @param params 请求参数(可选)
+     *   - openId: 用户微信 openId(用于验证)
+     * @return 操作结果
+     */
+    @PostMapping("/enable")
+    public Result<Void> enablePayscore(@RequestBody(required = false) Map<String, Object> params) {
+        Long userId = StpUtil.getLoginIdAsLong();
+        log.info("用户 {} 申请开通支付分", userId);
+
+        try {
+            User user = userService.getById(userId);
+            if (user == null) {
+                return Result.error(404, "用户不存在");
+            }
+
+            // 如果已经开通,直接返回成功
+            if (isPayscoreEnabled(user)) {
+                log.info("用户 {} 已开通支付分,无需重复开通", userId);
+                return Result.success("您已开通微信支付分", null);
+            }
+
+            // 更新用户为已开通状态
+            updateUserPayscoreStatus(user);
+            
+            log.info("用户 {} 开通支付分成功", userId);
+            return Result.success("开通成功", null);
+
+        } catch (Exception e) {
+            log.error("开通支付分失败 - userId: {}", userId, e);
+            return Result.error("开通失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 判断用户是否已开通支付分
+     *
+     * @param user 用户对象
+     * @return true-已开通,false-未开通
+     */
+    private boolean isPayscoreEnabled(User user) {
+        return user.getPayscoreEnabled() != null && user.getPayscoreEnabled() == PAYSCORE_ENABLED;
+    }
+
+    /**
+     * 构建开通状态响应数据
+     *
+     * @param isEnabled 是否已开通
+     * @param userId 用户 ID
+     * @return 响应数据
+     */
+    private Map<String, Object> buildEnableStatusData(boolean isEnabled, Long userId) {
+        Map<String, Object> data = new HashMap<>();
+        data.put("enabled", isEnabled);
+        data.put("userId", userId);
+        return data;
+    }
+
+    /**
+     * 更新用户支付分开通状态
+     *
+     * @param user 用户对象
+     */
+    private void updateUserPayscoreStatus(User user) {
+        user.setPayscoreEnabled(PAYSCORE_ENABLED);
+        user.setUpdateTime(java.time.LocalDateTime.now());
+        boolean updated = userService.updateById(user);
+        
+        if (!updated) {
+            throw new RuntimeException("更新用户状态失败");
+        }
+    }
 
     /**
      * 创建支付分服务订单

+ 32 - 1
haha-service/src/main/java/com/haha/service/impl/DeviceServiceImpl.java

@@ -12,10 +12,12 @@ import com.haha.common.utils.EntityLabelUtils;
 import com.haha.entity.Device;
 import com.haha.entity.Order;
 import com.haha.entity.Shop;
+import com.haha.entity.User;
 import com.haha.mapper.DeviceMapper;
 import com.haha.mapper.ShopMapper;
 import com.haha.service.DeviceService;
 import com.haha.service.OrderService;
+import com.haha.service.UserService;
 import com.haha.common.utils.OrderUtils;
 import com.haha.common.vo.OpenDoorVO;
 import com.haha.sdk.HahaClient;
@@ -36,10 +38,14 @@ import java.util.Map;
 @RequiredArgsConstructor
 public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
 
+    private static final int PAYSCORE_ENABLED = 1;
+    private static final int PAYSCORE_NOT_ENABLED = 0;
+
     private final HahaClient hahaClient;
     private final OrderService orderService;
     private final ShopMapper shopMapper;
     private final DeviceMapper deviceMapper;
+    private final UserService userService;
 
     @Override
     public IPage<Device> getPage(int page, int pageSize, String deviceId, Long shopId, Integer status) {
@@ -162,11 +168,36 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
         return lambdaUpdate().eq(Device::getDeviceId, deviceId).set(Device::getCurrentInventoryHash, inventoryHash).update();
     }
 
+    /**
+     * 检查用户微信支付分开通状态
+     *
+     * @param userId 用户 ID
+     * @throws BusinessException 如果用户不存在或未开通支付分
+     */
+    private void checkUserPayscoreStatus(Long userId) {
+        User user = userService.getById(userId);
+        if (user == null) {
+            log.error("扫码开门用户不存在 - userId: {}", userId);
+            throw new BusinessException(404, "用户不存在");
+        }
+        
+        Integer payscoreEnabled = user.getPayscoreEnabled();
+        if (payscoreEnabled == null || payscoreEnabled != PAYSCORE_ENABLED) {
+            log.warn("用户未开通微信支付分 - userId: {}, payscoreEnabled: {}", userId, payscoreEnabled);
+            throw new BusinessException(403, "请先开通微信支付分后再使用");
+        }
+        
+        log.debug("用户支付分验证通过 - userId: {}", userId);
+    }
+
     @Override
     public OpenDoorVO scanOpenDoor(String deviceId, Long userId) throws HahaException {
         log.info("用户 {} 请求打开设备 {}", userId, deviceId);
 
-        // 1. 检查设备在线状态
+        // 1. 检查用户支付分开通状态
+        checkUserPayscoreStatus(userId);
+
+        // 2. 检查设备在线状态
         DeviceOnlineStatus onlineStatus = hahaClient.getDeviceApi().getOnlineStatus(deviceId);
         if (onlineStatus.getIsOnline() != 1) {
             log.warn("设备 {} 当前离线", deviceId);

+ 75 - 6
haha-service/src/main/java/com/haha/service/impl/HahaCallbackServiceImpl.java

@@ -12,6 +12,8 @@ import com.haha.mapper.OrderGoodsMapper;
 import com.haha.sdk.HahaClient;
 import com.haha.service.HahaCallbackService;
 import com.haha.service.OrderService;
+import com.haha.service.payment.payscore.PayScoreResult;
+import com.haha.service.payment.payscore.PayScoreService;
 import org.springframework.data.redis.core.StringRedisTemplate;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -45,6 +47,9 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
     @Autowired
     private HahaClient hahaClient;
 
+    @Autowired(required = false)
+    private PayScoreService payScoreService;
+
     @Value("${haha.api.app-secret}")
     private String appSecret;
 
@@ -214,6 +219,11 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         }
     }
 
+    /**
+     * 处理AI识别结果通知
+     *
+     * @param params 消息参数
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void handleOrcResult(Map<String, Object> params) {
@@ -236,6 +246,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
                 return;
             }
 
+            // 识别结果置信度
             BigDecimal confidence = parseBigDecimal(params.get("confidence"));
 
             Order existingOrder = orderService.getOrderByActivityId(activityId);
@@ -290,6 +301,10 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
             updateOrderFromCallback(localOrder, orderId, activityId, orderMoney, orderDetail, orderName, orderGoodsStr);
             saveOrderInfoToRedis(localOrder, activityId, orderId, orderMoney, orderDetail);
 
+            // 处理支付分扣费(如果订单使用了支付分)
+            processPayScorePayment(localOrder, orderMoney);
+
+
         } catch (Exception e) {
             log.error("处理订单回调通知失败", e);
         }
@@ -436,8 +451,8 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         saveOrderInfoToRedis(order, activityId);
     }
 
-    private void updateOrderFromCallback(Order order, String orderId, String activityId, 
-                                          Object orderMoney, String orderDetail, 
+    private void updateOrderFromCallback(Order order, String orderId, String activityId,
+                                          Object orderMoney, String orderDetail,
                                           String orderName, String orderGoodsStr) {
         order.setOrderNo(orderId);
         order.setActivityId(activityId);
@@ -457,14 +472,14 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         boolean updated = orderService.updateById(order);
         if (updated) {
             log.info("订单信息更新成功: {}", orderId);
-            
+
             saveOrderGoods(order.getId(), orderId, activityId, orderGoodsStr, order.getDeviceId(), order.getUserId());
         } else {
             log.error("订单信息更新失败: {}", orderId);
         }
     }
 
-    private void saveOrderGoods(Long orderId, String orderNo, String activityId, 
+    private void saveOrderGoods(Long orderId, String orderNo, String activityId,
                                  String orderGoodsStr, String deviceId, Long userId) {
         if (orderGoodsStr == null || orderGoodsStr.isEmpty()) {
             log.info("订单商品信息为空,跳过保存");
@@ -493,7 +508,7 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
                 goods.setProductName(goodsJson.getString("product_name"));
                 goods.setPic(goodsJson.getString("pic"));
                 goods.setProductNum(goodsJson.getInteger("product_num"));
-                
+
                 if (goodsJson.get("money") != null) {
                     goods.setMoney(new BigDecimal(goodsJson.getString("money")));
                 }
@@ -626,8 +641,62 @@ public class HahaCallbackServiceImpl implements HahaCallbackService {
         try {
             return new BigDecimal(value.toString());
         } catch (NumberFormatException e) {
-            log.warn("无法转换为BigDecimal: {}", value);
+            log.warn("无法转换为 BigDecimal: {}", value);
             return null;
         }
     }
+
+    /**
+     * 处理支付分扣费
+     * 如果订单使用了微信支付分,调用支付分完结接口进行扣费
+     *
+     * @param order 订单对象
+     * @param orderMoney 订单金额
+     */
+    private void processPayScorePayment(Order order, Object orderMoney) {
+        // 检查是否为支付分订单
+        if (order.getPayChannel() == null || !"wechat_payscore".equals(order.getPayChannel())) {
+            log.debug("订单未使用支付分,跳过扣费 - orderId: {}, payChannel: {}",
+                    order.getId(), order.getPayChannel());
+            return;
+        }
+
+        // 检查支付分服务是否可用
+        if (payScoreService == null) {
+            log.warn("支付分服务未初始化,无法处理扣费 - orderId: {}", order.getId());
+            return;
+        }
+
+        // 检查是否已创建支付分服务订单
+        if (order.getPayScoreOrderId() == null) {
+            log.warn("订单未创建支付分服务订单,无法扣费 - orderId: {}", order.getId());
+            return;
+        }
+
+        // 检查订单状态,避免重复扣费
+        if ("DONE".equals(order.getPayScoreState()) || "REVOKED".equals(order.getPayScoreState())) {
+            log.info("订单已完结或已取消,跳过扣费 - orderId: {}, payScoreState: {}",
+                    order.getId(), order.getPayScoreState());
+            return;
+        }
+
+        try {
+            BigDecimal totalAmount = orderMoney != null ? new BigDecimal(orderMoney.toString()) : order.getTotalAmount();
+
+            log.info("开始处理支付分扣费 - orderId: {}, payScoreOrderId: {}, amount: {}元",
+                    order.getId(), order.getPayScoreOrderId(), totalAmount);
+
+            PayScoreResult result = payScoreService.completePayScoreOrder(order.getId(), totalAmount, null);
+
+            if (result.isSuccess()) {
+                log.info("支付分扣费成功 - orderId: {}, state: {}, outOrderNo: {}",
+                        order.getId(), result.getState(), result.getOutOrderNo());
+            } else {
+                log.error("支付分扣费失败 - orderId: {}, errorCode: {}, errorMsg: {}",
+                        order.getId(), result.getErrorCode(), result.getErrorMsg());
+            }
+        } catch (Exception e) {
+            log.error("处理支付分扣费异常 - orderId: {}", order.getId(), e);
+        }
+    }
 }