Просмотр исходного кода

1、调整售后状态为展示
2、领取记录
3、调整直播微信0元购

yys 1 месяц назад
Родитель
Сommit
42d4536b9c

+ 80 - 57
fs-service/src/main/java/com/fs/live/service/impl/LiveCouponServiceImpl.java

@@ -243,6 +243,16 @@ public class LiveCouponServiceImpl implements ILiveCouponService
         }
 
         if (isShow) {
+            // 如果之前是"已领完"状态(-1),重新上架时恢复为正常状态
+            if (couponIssue.getStatus() != null && couponIssue.getStatus() == -1) {
+                couponIssue.setStatus(1);
+                liveCouponIssueService.updateLiveCouponIssue(couponIssue);
+                // 重新初始化Redis库存缓存
+                redisCache.setCacheObject(
+                        String.format(LiveKeysConstant.LIVE_COUPON_NUM, couponIssueId),
+                        couponIssue.getRemainCount().intValue(),
+                        30, java.util.concurrent.TimeUnit.MINUTES);
+            }
             // updateChangeShow 会自动收起其它券,仅保留当前展示的一张
             liveCouponMapper.updateChangeShow(liveId, couponIssueId);
             LiveConsoleOpLog opLog = liveConsoleOpLogService.saveCouponShowLog(
@@ -306,8 +316,15 @@ public class LiveCouponServiceImpl implements ILiveCouponService
     @Override
     @Transactional
     public R claimCoupon(CouponPO coupon) {
-        LiveCouponIssue issue = liveCouponMapper.selectLiveCouponIssueByLiveIdAndCouponId(coupon.getLiveId(), coupon.getCouponIssueId());
-        if (coupon == null || ObjectUtils.isEmpty(issue)||issue.getStatus() != 1) {
+        // 参数校验:先判空再使用,避免 NPE
+        if (coupon == null || coupon.getLiveId() == null
+                || coupon.getCouponIssueId() == null || coupon.getUserId() == null) {
+            return R.error("领取参数不完整!");
+        }
+
+        LiveCouponIssue issue = liveCouponMapper.selectLiveCouponIssueByLiveIdAndCouponId(
+                coupon.getLiveId(), coupon.getCouponIssueId());
+        if (ObjectUtils.isEmpty(issue) || issue.getStatus() == null || issue.getStatus() != 1) {
             return R.error("优惠券不存在或者已下架!");
         }
 
@@ -316,67 +333,73 @@ public class LiveCouponServiceImpl implements ILiveCouponService
             return R.error("优惠券配置不存在!");
         }
 
-        Long decrement = redisCache.decrement(String.format(LiveKeysConstant.LIVE_COUPON_NUM , coupon.getCouponIssueId()));
+        // Redis 预扣减库存,key 必须与展示/初始化时保持一致
+        String stockKey = String.format(LiveKeysConstant.LIVE_COUPON_NUM, coupon.getCouponIssueId());
+        Long decrement = redisCache.decrement(stockKey);
 
-        if (decrement < 0L) {
+        // 库存不足:回补 Redis 多扣的 1,并标记已领完
+        if (decrement == null || decrement < 0L) {
+            if (decrement != null) {
+                redisCache.incr(stockKey, 1L);
+            }
             issue.setStatus(-1);
             issue.setRemainCount(0L);
-            redisCache.deleteObject(String.valueOf(issue.getId()));
             liveCouponIssueService.updateLiveCouponIssue(issue);
             return R.error("此优惠券已领完");
         }
-        Date now = DateUtils.getNowDate();
-        LiveCouponIssueUser record = new LiveCouponIssueUser();
-        record.setUserId(coupon.getUserId());
-        record.setIssueId(issue.getId());
-        record.setCreateTime(now);
-        record.setUpdateTime(now);
-        record.setIsDel(0);
-        record.setGoodsId(coupon.getGoodsId());
-
-
-        LiveCouponUser userRecord = new LiveCouponUser();
-        userRecord.setCouponId(liveCoupon.getCouponId());
-        userRecord.setUserId(Math.toIntExact(coupon.getUserId()));
-        userRecord.setCouponTitle(liveCoupon.getTitle());
-        userRecord.setCouponPrice(liveCoupon.getCouponPrice());
-        userRecord.setUseMinPrice(liveCoupon.getUseMinPrice());
-        userRecord.setCreateTime(now);
-        userRecord.setUpdateTime(now);
-        userRecord.setStatus(0);
-        userRecord.setLimitTime(DateUtils.addDays(now, Math.toIntExact(liveCoupon.getCouponTime())));
-        userRecord.setIsFail(1);
-        userRecord.setIsDel(0);
-        userRecord.setIsDel(0);
-        userRecord.setGoodsId(coupon.getGoodsId());
-        userRecord.setType("live-"+coupon.getLiveId());
-        userRecord.setVerifyCode(generateVerifyCode());
-        //库存 remain_count
-        issue.setRemainCount(issue.getRemainCount()-1);
-        liveCouponIssueService.updateLiveCouponIssue(issue);
-
-        liveCouponUserService.insertLiveCouponUser(userRecord);
-        liveCouponIssueUserService.insertLiveCouponIssueUser(record);
-
-        Long opLogId = coupon.getOpLogId();
-        if (opLogId == null) {
-            opLogId = liveConsoleOpLogService.resolveLatestCouponShowOpLogId(coupon.getLiveId(), issue.getId());
-        }
-        liveConsoleOpLogService.bindOpLogUser(
-                opLogId, coupon.getLiveId(), coupon.getUserId(), userRecord.getId());
-
-        // 更新优惠卷数量
-        if (issue.getRemainCount() > 0) {
-            LiveCouponIssue liveCouponIssue = new LiveCouponIssue();
-            liveCouponIssue.setId(issue.getId());
-            liveCouponIssue.setRemainCount(issue.getRemainCount() - 1);
-            liveCouponIssueMapper.updateLiveCouponIssue(liveCouponIssue);
-        }
-
-
-        return R.ok("恭喜您抢到优惠券")
-                .put("opLogId", opLogId)
-                .put("couponUserId", userRecord.getId());
+
+        // Redis 扣减成功,执行 DB 操作;若 DB 异常则回补 Redis 库存
+        try {
+            Date now = DateUtils.getNowDate();
+            LiveCouponIssueUser record = new LiveCouponIssueUser();
+            record.setUserId(coupon.getUserId());
+            record.setIssueId(issue.getId());
+            record.setCreateTime(now);
+            record.setUpdateTime(now);
+            record.setIsDel(0);
+            record.setGoodsId(coupon.getGoodsId());
+
+            LiveCouponUser userRecord = new LiveCouponUser();
+            userRecord.setCouponId(liveCoupon.getCouponId());
+            userRecord.setUserId(Math.toIntExact(coupon.getUserId()));
+            userRecord.setCouponTitle(liveCoupon.getTitle());
+            userRecord.setCouponPrice(liveCoupon.getCouponPrice());
+            userRecord.setUseMinPrice(liveCoupon.getUseMinPrice());
+            userRecord.setCreateTime(now);
+            userRecord.setUpdateTime(now);
+            userRecord.setStatus(0);
+            userRecord.setLimitTime(DateUtils.addDays(now, Math.toIntExact(liveCoupon.getCouponTime())));
+            userRecord.setIsFail(1);
+            userRecord.setIsDel(0);
+            userRecord.setGoodsId(coupon.getGoodsId());
+            userRecord.setType("live-" + coupon.getLiveId());
+            userRecord.setVerifyCode(generateVerifyCode());
+
+            // 基于 Redis 扣减后的值同步 DB 库存,避免读后写并发丢失更新
+            issue.setRemainCount(decrement);
+            if (decrement == 0L) {
+                issue.setStatus(-1);
+            }
+            liveCouponIssueService.updateLiveCouponIssue(issue);
+
+            liveCouponUserService.insertLiveCouponUser(userRecord);
+            liveCouponIssueUserService.insertLiveCouponIssueUser(record);
+
+            Long opLogId = coupon.getOpLogId();
+            if (opLogId == null) {
+                opLogId = liveConsoleOpLogService.resolveLatestCouponShowOpLogId(coupon.getLiveId(), issue.getId());
+            }
+            liveConsoleOpLogService.bindOpLogUser(
+                    opLogId, coupon.getLiveId(), coupon.getUserId(), userRecord.getId());
+
+            return R.ok("恭喜您抢到优惠券")
+                    .put("opLogId", opLogId)
+                    .put("couponUserId", userRecord.getId());
+        } catch (Exception e) {
+            // DB 操作失败,回补 Redis 库存,避免库存丢失;重新抛出让事务回滚
+            redisCache.incr(stockKey, 1L);
+            throw e;
+        }
     }
 
     @Override

+ 32 - 9
fs-service/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -1192,16 +1192,35 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 List<LiveOrderItemVo> liveOrderItemVos = orderItemsMap.get(orderId);
                 if(CollectionUtils.isNotEmpty(liveOrderItemVos)) {
                     order.setOrderItemList(liveOrderItemVos);
-                    // 根据子订单的isAfterSales更新外层订单的isAfterSales
-                    // 只有当外层订单当前isAfterSales为1且所有子订单isAfterSales都为0时,才设置为0
-                    Integer orderIsAfterSales = order.getIsAfterSales();
-                    if (orderIsAfterSales != null && orderIsAfterSales == 1) {
-                        boolean anyAfterSales = liveOrderItemVos.stream()
-                                .anyMatch(item -> item.getIsAfterSales() != null && item.getIsAfterSales() == 1);
-                        if (!anyAfterSales) {
-                            order.setIsAfterSales(0);
+                    // 根据订单状态计算是否可申请售后(替代原有的基于子订单isAfterSales的判定)
+                    // 注意:live_order.is_after_sales(订单级)="可申请售后",live_order_item.is_after_sales(子订单级)="已申请售后"
+                    // 两者含义不同,原逻辑用子订单的"已申请"去覆盖订单的"可申请",会错误地把直播间下单订单的售后入口隐藏
+                    // 现参照 selectFsMyLiveOrderListVO 和 getMyStoreOrderById 的逻辑,基于订单状态+已完成时间判定
+                    order.setIsAfterSales(0);
+                    if (order.getStatus() != null && order.getStatus().equals(OrderInfoEnum.STATUS_3.getValue())) {
+                        // 已完成订单:在售后有效期内可申请售后(需核验 finishTime + 售后天数配置)
+                        order.setIsAfterSales(1);
+                        if (order.getFinishTime() != null) {
+                            try {
+                                String configJson = configService.selectConfigByKey("store.config");
+                                StoreConfig storeConfig = JSONUtil.toBean(configJson, StoreConfig.class);
+                                if (storeConfig.getStoreAfterSalesDay() != null && storeConfig.getStoreAfterSalesDay() > 0) {
+                                    Calendar calendar = new GregorianCalendar();
+                                    calendar.setTime(order.getFinishTime());
+                                    calendar.add(Calendar.DATE, storeConfig.getStoreAfterSalesDay());
+                                    if (calendar.getTime().getTime() < new Date().getTime()) {
+                                        order.setIsAfterSales(0);
+                                    }
+                                }
+                            } catch (Exception e) {
+                                log.warn("读取售后配置失败,orderId={}", order.getOrderId(), e);
+                            }
                         }
+                    } else if (order.getStatus() != null && (order.getStatus() == 1 || order.getStatus() == 2)) {
+                        // 待发货(1)、待收货(2):可申请售后
+                        order.setIsAfterSales(1);
                     }
+                    // status=0(待支付)、status<0(退款/已取消)等:不开放售后(含抽奖中奖订单)
                 }
             }
         }
@@ -3740,7 +3759,11 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                     }
                 }
             }
-//            else if(order.getPayType().equals("3")){
+            else if ((order.getPayType().equals("1") || order.getPayType().equals("2")) && order.getPayMoney().compareTo(new BigDecimal(0)) <= 0) {
+                // 支付金额为0,直接确认支付
+                this.payConfirm(2, order.getOrderId(), null, null, null, null);
+                return R.ok().put("payType", param.getPayType());
+            }
             else if (order.getPayType().equals("3") && order.getPayMoney().compareTo(new BigDecimal(0)) <= 0) {
                 //货到付款
                 this.payConfirm(2, order.getOrderId(), null, null, null, null);