|
|
@@ -1,6 +1,8 @@
|
|
|
package com.ylx.massage.service.impl;
|
|
|
|
|
|
+import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.collection.CollectionUtil;
|
|
|
+import cn.hutool.core.util.ObjectUtil;
|
|
|
import cn.hutool.json.JSONUtil;
|
|
|
import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
@@ -14,20 +16,30 @@ import com.ylx.common.constant.MassageConstants;
|
|
|
import com.ylx.common.core.domain.R;
|
|
|
import com.ylx.common.exception.ServiceException;
|
|
|
import com.ylx.common.utils.SecurityUtils;
|
|
|
+import com.ylx.lottery.domain.LotteryCountLog;
|
|
|
+import com.ylx.lottery.domain.vo.LocalActivityTableVO;
|
|
|
+import com.ylx.lottery.domain.vo.LotteryActivityRulesProductVO;
|
|
|
+import com.ylx.lottery.domain.vo.LotteryActivityVO;
|
|
|
+import com.ylx.lottery.domain.vo.LotteryStatVO;
|
|
|
+import com.ylx.lottery.service.LotteryCountLogService;
|
|
|
+import com.ylx.lottery.service.LotteryCountService;
|
|
|
import com.ylx.massage.domain.*;
|
|
|
import com.ylx.massage.domain.vo.*;
|
|
|
import com.ylx.massage.enums.BillTypeEnum;
|
|
|
-import com.ylx.massage.enums.DiscountTypeEnum;
|
|
|
import com.ylx.massage.enums.JsStatusEnum;
|
|
|
import com.ylx.massage.enums.OrderStatusEnum;
|
|
|
import com.ylx.massage.mapper.TOrderMapper;
|
|
|
import com.ylx.massage.service.*;
|
|
|
import com.ylx.massage.utils.*;
|
|
|
import com.ylx.point.service.IPointUserActivityTaskCompletionService;
|
|
|
+import com.ylx.usercenter.domain.dto.UnifiedUserCenterDTO;
|
|
|
+import com.ylx.usercenter.service.UnifiedUserCenterService;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.apache.commons.compress.utils.Lists;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
+import org.springframework.transaction.support.TransactionSynchronization;
|
|
|
+import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
import java.math.BigDecimal;
|
|
|
@@ -106,6 +118,12 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
|
|
|
@Resource
|
|
|
private CancelOrderApplicationService cancelOrderApplicationService;
|
|
|
+ @Resource
|
|
|
+ private UnifiedUserCenterService unifiedUserCenterService;
|
|
|
+ @Resource
|
|
|
+ private LotteryCountService lotteryCountService;
|
|
|
+ @Resource
|
|
|
+ private LotteryCountLogService lotteryCountLogService;
|
|
|
|
|
|
/**
|
|
|
* 判断是否免车费
|
|
|
@@ -163,12 +181,12 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
}
|
|
|
Integer techType = js.getTechType();
|
|
|
// 虚拟技师
|
|
|
- if(techType.equals(1)){
|
|
|
+ if (techType.equals(1)) {
|
|
|
//虚拟技师订单
|
|
|
order.setVirtualOrderFlag(1);
|
|
|
//虚拟技师订单未分配
|
|
|
order.setVirtualOrderAllocation(1);
|
|
|
- }else{
|
|
|
+ } else {
|
|
|
//真实订单
|
|
|
order.setVirtualOrderFlag(0);
|
|
|
order.setVirtualOrderAllocation(0);
|
|
|
@@ -435,9 +453,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
}
|
|
|
oldTechnicianStatusAfter = JsStatusEnum.JS_SERVICEABLE.getCode();
|
|
|
|
|
|
- log.info("更新技师状态完成 - 新技师:{} {}→{}, 原技师:{} {}→{}",
|
|
|
- newTechnicianName, getStatusName(newTechnicianStatusBefore), getStatusName(newTechnicianStatusAfter),
|
|
|
- oldTechnicianName, getStatusName(oldTechnicianStatusBefore), getStatusName(oldTechnicianStatusAfter));
|
|
|
+ log.info("更新技师状态完成 - 新技师:{} {}→{}, 原技师:{} {}→{}", newTechnicianName, getStatusName(newTechnicianStatusBefore), getStatusName(newTechnicianStatusAfter), oldTechnicianName, getStatusName(oldTechnicianStatusBefore), getStatusName(oldTechnicianStatusAfter));
|
|
|
|
|
|
// ========== 第8步:获取操作人信息 ==========
|
|
|
operatorId = SecurityUtils.getUserId() != null ? SecurityUtils.getUserId().toString() : "ADMIN";
|
|
|
@@ -463,8 +479,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
try {
|
|
|
// 只有在获取到基本信息后才记录日志
|
|
|
if (orderId != null && orderNo != null && oldTechnicianId != null && newTechnicianId != null) {
|
|
|
- allocationLogService.recordTransferOrder(
|
|
|
- orderId, // orderId
|
|
|
+ allocationLogService.recordTransferOrder(orderId, // orderId
|
|
|
orderNo, // orderNo
|
|
|
oldTechnicianId, // oldTechnicianId
|
|
|
oldTechnicianName, // oldTechnicianName
|
|
|
@@ -639,7 +654,6 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
}
|
|
|
|
|
|
|
|
|
-
|
|
|
/**
|
|
|
* 新订单通知
|
|
|
*
|
|
|
@@ -697,7 +711,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
if (orderNew.getPayType().equals(MassageConstants.INTEGER_TWO)) {
|
|
|
tConsumptionLog.setBillType(BillTypeEnum.BALANCE_PAYMENT.getCode());
|
|
|
tConsumptionLog.setNote("余额支付");
|
|
|
- } else if(orderNew.getPayType().equals(MassageConstants.INTEGER_ONE)){
|
|
|
+ } else if (orderNew.getPayType().equals(MassageConstants.INTEGER_ONE)) {
|
|
|
tConsumptionLog.setBillType(BillTypeEnum.WX_PAY.getCode());
|
|
|
tConsumptionLog.setNote("微信支付");
|
|
|
} else {
|
|
|
@@ -736,6 +750,12 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
//电话通知
|
|
|
TJs js = jsService.getById(orderNew.getcJsId());
|
|
|
Sendvoice.sendPhone(js.getcPhone());
|
|
|
+
|
|
|
+ // 任务奖励 或者 消费奖励 —— 发放抽奖次数日志
|
|
|
+ grantLotteryCountForPay(user, orderParam);
|
|
|
+
|
|
|
+ // 已绑定一账通 → 异步同步抽奖次数
|
|
|
+ syncLotteryCountIfNeeded(user);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -833,9 +853,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
jsParam.setId(orderNew.getcJsId());
|
|
|
jsParam.setnStatus(JsStatusEnum.JS_SERVICEABLE.getCode());
|
|
|
//判断热度标识
|
|
|
- List<TOrder> list = list(new LambdaQueryWrapper<TOrder>().eq(TOrder::getcJsId, orderNew.getcJsId())
|
|
|
- .ge(TOrder::getDtCreateTime, DateTimeUtils.addDays(new Date(), -3))
|
|
|
- .ge(TOrder::getnStatus, OrderStatusEnum.WAIT_EVALUATE.getCode()));
|
|
|
+ List<TOrder> list = list(new LambdaQueryWrapper<TOrder>().eq(TOrder::getcJsId, orderNew.getcJsId()).ge(TOrder::getDtCreateTime, DateTimeUtils.addDays(new Date(), -3)).ge(TOrder::getnStatus, OrderStatusEnum.WAIT_EVALUATE.getCode()));
|
|
|
if (list.size() >= 2) {
|
|
|
// 设置热度标识:1
|
|
|
jsParam.setnB3(MassageConstants.INTEGER_ONE);
|
|
|
@@ -888,20 +906,20 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
|
|
|
// 添加订单完成消息通知(用户侧)
|
|
|
orderNotificationService.sendCompletedNotification(orderNew);
|
|
|
-
|
|
|
+
|
|
|
// 完成积分任务(按照新手活动、每日活动、每月活动的优先级顺序)
|
|
|
try {
|
|
|
this.pointUserActivityTaskCompletionService.completeOrderTaskByPriority(orderNew.getcOpenId());
|
|
|
} catch (Exception e) {
|
|
|
log.error("完成积分任务失败 - 订单号:{}, 错误信息:{}", orderNew.getOrderNo(), e.getMessage(), e);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
private void extracted(TOrder orderNew, TWxUser jsUp) {
|
|
|
log.info("TOrderServiceImpl->extracted->jsUp,{}", JSONUtil.toJsonStr(jsUp));
|
|
|
- log.info("TOrderServiceImpl->extracted->orderNew,{}",JSONUtil.toJsonStr(orderNew));
|
|
|
+ log.info("TOrderServiceImpl->extracted->orderNew,{}", JSONUtil.toJsonStr(orderNew));
|
|
|
BigDecimal up = orderNew.getdTotalMoney().multiply(new BigDecimal("10"));
|
|
|
up = up.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP);
|
|
|
// 更新余额
|
|
|
@@ -925,7 +943,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
* 获取技师当天可预约时间
|
|
|
*
|
|
|
* @param technicianId 技师ID
|
|
|
- * @param dateStr 查询日期(格式:yyyy-MM-dd),为null则查询当天
|
|
|
+ * @param dateStr 查询日期(格式:yyyy-MM-dd),为null则查询当天
|
|
|
* @return TechnicianAvailabilityVo 技师当天可预约时间VO
|
|
|
*/
|
|
|
@Override
|
|
|
@@ -957,14 +975,8 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
List<TimeSlotVo> timeSlots = new ArrayList<>();
|
|
|
for (int hour = 0; hour < 24; hour++) {
|
|
|
// 每小时生成两个时间段:xx:00 和 xx:30
|
|
|
- timeSlots.add(TimeSlotVo.builder()
|
|
|
- .time(String.format("%02d:00", hour))
|
|
|
- .available(true)
|
|
|
- .build());
|
|
|
- timeSlots.add(TimeSlotVo.builder()
|
|
|
- .time(String.format("%02d:30", hour))
|
|
|
- .available(true)
|
|
|
- .build());
|
|
|
+ timeSlots.add(TimeSlotVo.builder().time(String.format("%02d:00", hour)).available(true).build());
|
|
|
+ timeSlots.add(TimeSlotVo.builder().time(String.format("%02d:30", hour)).available(true).build());
|
|
|
}
|
|
|
|
|
|
// 5. 查询技师当天所有进行中的订单
|
|
|
@@ -975,15 +987,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
log.info("开始时间:{},结束时间:{}", startOfDay, endOfDay);
|
|
|
|
|
|
LambdaQueryWrapper<TOrder> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(TOrder::getcJsId, technicianId)
|
|
|
- .in(TOrder::getnStatus, OrderStatusEnum.WAIT_JD.getCode(),
|
|
|
- OrderStatusEnum.RECEIVED_ORDER.getCode(),
|
|
|
- OrderStatusEnum.DEPART.getCode(),
|
|
|
- OrderStatusEnum.ARRIVED.getCode(),
|
|
|
- OrderStatusEnum.SERVICE.getCode())
|
|
|
- .ge(TOrder::getDtCreateTime, startOfDay)
|
|
|
- .lt(TOrder::getDtCreateTime, endOfDay)
|
|
|
- .eq(TOrder::getIsDelete, 0);
|
|
|
+ queryWrapper.eq(TOrder::getcJsId, technicianId).in(TOrder::getnStatus, OrderStatusEnum.WAIT_JD.getCode(), OrderStatusEnum.RECEIVED_ORDER.getCode(), OrderStatusEnum.DEPART.getCode(), OrderStatusEnum.ARRIVED.getCode(), OrderStatusEnum.SERVICE.getCode()).ge(TOrder::getDtCreateTime, startOfDay).lt(TOrder::getDtCreateTime, endOfDay).eq(TOrder::getIsDelete, 0);
|
|
|
|
|
|
List<TOrder> orders = this.list(queryWrapper);
|
|
|
log.info("技师{},在{}天共有 {} 个进行中的订单", technicianId, queryDate, orders.size());
|
|
|
@@ -1018,21 +1022,16 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
}
|
|
|
// 查询日期是未来的日期,所有时间段默认可预约,无需处理
|
|
|
// 8. 构建返回结果
|
|
|
- return TechnicianAvailabilityVo.builder()
|
|
|
- .date(queryDate.toString())
|
|
|
- .technicianId(technicianId)
|
|
|
- .technicianName(js.getcName())
|
|
|
- .timeSlots(timeSlots)
|
|
|
- .build();
|
|
|
+ return TechnicianAvailabilityVo.builder().date(queryDate.toString()).technicianId(technicianId).technicianName(js.getcName()).timeSlots(timeSlots).build();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 标记指定时间范围内的时间段为不可预约
|
|
|
*
|
|
|
* @param timeSlots 时间段列表
|
|
|
- * @param start 开始时间
|
|
|
- * @param end 结束时间
|
|
|
- * @param orderNo 订单号
|
|
|
+ * @param start 开始时间
|
|
|
+ * @param end 结束时间
|
|
|
+ * @param orderNo 订单号
|
|
|
*/
|
|
|
private void markTimeSlotsUnavailable(List<TimeSlotVo> timeSlots, LocalDateTime start, LocalDateTime end, String orderNo) {
|
|
|
LocalTime startTime = start.toLocalTime();
|
|
|
@@ -1055,7 +1054,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
* 标记所有时间段为不可预约
|
|
|
*
|
|
|
* @param timeSlots 时间段列表
|
|
|
- * @param reason 不可预约原因
|
|
|
+ * @param reason 不可预约原因
|
|
|
*/
|
|
|
private void markAllTimeSlotsUnavailable(List<TimeSlotVo> timeSlots, String reason) {
|
|
|
for (TimeSlotVo slot : timeSlots) {
|
|
|
@@ -1069,7 +1068,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
* 标记过去的时间段为不可预约
|
|
|
*
|
|
|
* @param timeSlots 时间段列表
|
|
|
- * @param now 当前时间
|
|
|
+ * @param now 当前时间
|
|
|
*/
|
|
|
private void markPastTimeSlotsUnavailable(List<TimeSlotVo> timeSlots, LocalDateTime now) {
|
|
|
LocalTime currentTime = now.toLocalTime();
|
|
|
@@ -1291,6 +1290,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
|
|
|
/**
|
|
|
* 更新技师状态
|
|
|
+ *
|
|
|
* @param orderNew
|
|
|
*/
|
|
|
private void updateJs(TOrder orderNew) {
|
|
|
@@ -1317,7 +1317,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
|
|
|
/**
|
|
|
* 申请取消订单(退单申请)
|
|
|
- *
|
|
|
+ * <p>
|
|
|
* 业务流程:
|
|
|
* 1. 校验订单状态(仅进行中的订单可申请退单)
|
|
|
* 2. 创建退单申请记录
|
|
|
@@ -1366,7 +1366,7 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
/**
|
|
|
* 取消退单申请
|
|
|
* 用户主动取消退单申请,恢复订单状态
|
|
|
- *
|
|
|
+ * <p>
|
|
|
* 业务流程:
|
|
|
* 1. 参数校验(订单ID不能为空)
|
|
|
* 2. 查询订单和退单申请记录
|
|
|
@@ -1441,11 +1441,193 @@ public class TOrderServiceImpl extends ServiceImpl<TOrderMapper, TOrder> impleme
|
|
|
// 统计用户在指定时间之前完成的订单数量
|
|
|
// 完成状态包括:4-待评价(已完成)和5-已完成(已评价)
|
|
|
LambdaQueryWrapper<TOrder> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
- queryWrapper.eq(TOrder::getcOpenId, openId)
|
|
|
- .in(TOrder::getnStatus, OrderStatusEnum.WAIT_EVALUATE.getCode(), OrderStatusEnum.COMPLETE.getCode())
|
|
|
- .lt(TOrder::getEndTime, queryTime);
|
|
|
-
|
|
|
+ queryWrapper.eq(TOrder::getcOpenId, openId).in(TOrder::getnStatus, OrderStatusEnum.WAIT_EVALUATE.getCode(), OrderStatusEnum.COMPLETE.getCode()).lt(TOrder::getEndTime, queryTime);
|
|
|
+
|
|
|
return Math.toIntExact(this.count(queryWrapper));
|
|
|
}
|
|
|
|
|
|
+ private void grantLotteryCountForPay(TWxUser user, TOrder orderParam) {
|
|
|
+
|
|
|
+ // 获取按摩订单中的商品ID
|
|
|
+ JSONArray array = orderParam.getcGoods();
|
|
|
+ JSONObject obj = array.getJSONObject(0);
|
|
|
+ String cId = obj.getString("cId");
|
|
|
+
|
|
|
+ List<LotteryActivityVO> activityList = lotteryCountService.queryActivityRules();
|
|
|
+ if (CollUtil.isEmpty(activityList)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 查询抽奖次数统计
|
|
|
+ LambdaQueryWrapper<LotteryCountLog> queryWrapper = new LambdaQueryWrapper<>();
|
|
|
+ queryWrapper.eq(LotteryCountLog::getUserId, user.getId());
|
|
|
+ queryWrapper.eq(LotteryCountLog::getIsDelete, 0);
|
|
|
+ List<LotteryStatVO> lotteryStatVOS = lotteryCountLogService.selectSumByGroup(queryWrapper);
|
|
|
+
|
|
|
+ // 生成活动ID -> 已获次数 的 Map
|
|
|
+ Map<String, Integer> activityGrantedCountMap = new HashMap<>();
|
|
|
+ if (CollUtil.isNotEmpty(lotteryStatVOS)) {
|
|
|
+ for (LotteryStatVO statVO : lotteryStatVOS) {
|
|
|
+ activityGrantedCountMap.put(statVO.getLocalActivityTableId(), statVO.getTotalNum());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (LotteryActivityVO activity : activityList) {
|
|
|
+
|
|
|
+ String activityId = activity.getId();
|
|
|
+
|
|
|
+ // 用户获取的最大抽奖次数
|
|
|
+ Integer productUserMaxNum = activity.getProductUserMaxNum();
|
|
|
+
|
|
|
+ // 检查 productUserMaxNum 是否为 null,如果是,则认为无限制
|
|
|
+ boolean hasLimit = !ObjectUtil.isNull(productUserMaxNum);
|
|
|
+
|
|
|
+ if (ObjectUtil.equals(activity.getParticipationRules(), 3)) { // 任务奖励类型
|
|
|
+
|
|
|
+ List<LocalActivityTableVO> localTables = activity.getLocalActivityTables();
|
|
|
+ if (CollUtil.isEmpty(localTables)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 类型=2 → 支付有礼
|
|
|
+ for (LocalActivityTableVO table : localTables) {
|
|
|
+ if (ObjectUtil.equals(table.getType(), 2) && ObjectUtil.equals(table.getIsProduct(), 1)) {
|
|
|
+ if (ObjectUtil.equals(table.getProductId(), cId)) {
|
|
|
+
|
|
|
+ Integer userLotteryCount = activityGrantedCountMap.getOrDefault(activityId, 0);
|
|
|
+
|
|
|
+ // 本次请求发放的数量
|
|
|
+ Integer requestedLotteryNum = 1;
|
|
|
+
|
|
|
+ // 计算实际可发放的数量
|
|
|
+ int actualLotteryNumToGrant = calculateActualGrant(hasLimit, userLotteryCount, requestedLotteryNum, productUserMaxNum);
|
|
|
+
|
|
|
+ if (actualLotteryNumToGrant > 0) {
|
|
|
+ // 发放计算后的数量
|
|
|
+ saveLotteryLog(user, activityId, actualLotteryNumToGrant, 2);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else if (ObjectUtil.equals(activity.getParticipationRules(), 4)) { // 消费奖励类型
|
|
|
+ if (ObjectUtil.isNull(activity.getProductRestriction())) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ Integer requestedLotteryNum = null;
|
|
|
+ boolean conditionMet = false;
|
|
|
+
|
|
|
+ if (ObjectUtil.equals(activity.getProductRestriction(), 1)) {
|
|
|
+ List<LotteryActivityRulesProductVO> lotteryActivityRulesProducts = activity.getLotteryActivityRulesProducts();
|
|
|
+ if (CollUtil.isEmpty(lotteryActivityRulesProducts)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ requestedLotteryNum = activity.getProductLotteryNum();
|
|
|
+
|
|
|
+ if (!ObjectUtil.isNull(requestedLotteryNum)) {
|
|
|
+ for (LotteryActivityRulesProductVO activityRulesProduct : lotteryActivityRulesProducts) {
|
|
|
+ if (ObjectUtil.equals(activityRulesProduct.getProductId(), cId)) {
|
|
|
+ conditionMet = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if (ObjectUtil.equals(activity.getProductRestriction(), 2)) {
|
|
|
+
|
|
|
+ // 用户消费满几元
|
|
|
+ Integer consumeAmount = activity.getConsumeAmount();
|
|
|
+ // 消费奖励 消费满几元的几次抽奖机会
|
|
|
+ requestedLotteryNum = activity.getConsumeAmountLottery();
|
|
|
+
|
|
|
+ if (!ObjectUtil.isNull(consumeAmount) && !ObjectUtil.isNull(requestedLotteryNum) && !ObjectUtil.isNull(orderParam.getdTotalMoney())) {
|
|
|
+ BigDecimal thresholdAmount = new BigDecimal(consumeAmount);
|
|
|
+ BigDecimal totalMoney = orderParam.getdTotalMoney();
|
|
|
+ conditionMet = totalMoney.compareTo(thresholdAmount) >= 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果条件满足,则进行次数检查并发放
|
|
|
+ if (conditionMet && !ObjectUtil.isNull(requestedLotteryNum)) {
|
|
|
+ // --- 修复: 使用 getOrDefault 避免 NPE ---
|
|
|
+ Integer userLotteryCount = activityGrantedCountMap.getOrDefault(activityId, 0);
|
|
|
+
|
|
|
+ // --- 新增: 计算实际可发放的数量 ---
|
|
|
+ int actualLotteryNumToGrant = calculateActualGrant(hasLimit, userLotteryCount, requestedLotteryNum, productUserMaxNum);
|
|
|
+
|
|
|
+ if (actualLotteryNumToGrant > 0) {
|
|
|
+ saveLotteryLog(user, activityId, actualLotteryNumToGrant, 3);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void syncLotteryCountIfNeeded(TWxUser user) {
|
|
|
+ if (ObjectUtil.equals(user.getIsBind(), 1) && com.ylx.common.utils.StringUtils.isNotBlank(user.getLocalLiveUserId())) {
|
|
|
+
|
|
|
+ UnifiedUserCenterDTO dto = new UnifiedUserCenterDTO();
|
|
|
+ dto.setTargetUserId(user.getLocalLiveUserId());
|
|
|
+ dto.setSourceUserId(user.getId());
|
|
|
+
|
|
|
+ // 👇 事务提交后再执行异步
|
|
|
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
|
|
+ @Override
|
|
|
+ public void afterCommit() {
|
|
|
+ // 事务提交完成!现在调用异步,一定能查到数据
|
|
|
+ unifiedUserCenterService.syncLotteryCount(dto);
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 统一保存抽奖次数日志
|
|
|
+ */
|
|
|
+ private void saveLotteryLog(TWxUser user, String activityId, Integer lotteryNum, Integer activityType) {
|
|
|
+ LotteryCountLog log = new LotteryCountLog();
|
|
|
+ log.setOpenId(user.getcOpenid());
|
|
|
+ log.setUserId(user.getId());
|
|
|
+ log.setUserPhone(user.getcPhone());
|
|
|
+ log.setActivityType(activityType);
|
|
|
+ log.setLocalActivityTableId(activityId);
|
|
|
+ log.setLotteryNum(lotteryNum);
|
|
|
+ log.setReceiveTime(new Date());
|
|
|
+ log.setIsDelete("0");
|
|
|
+ log.setStatus(0); // 未同步
|
|
|
+ log.setIsLottery(0);
|
|
|
+ log.setType(1);
|
|
|
+ lotteryCountLogService.save(log);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据已有次数、请求发放次数和最大次数限制,计算实际可发放的次数
|
|
|
+ * @param hasLimit 是否有限制
|
|
|
+ * @param currentCount 当前已获得次数
|
|
|
+ * @param requestedCount 请求发放次数
|
|
|
+ * @param maxCount 最大次数限制
|
|
|
+ * @return 实际可发放次数
|
|
|
+ */
|
|
|
+ private int calculateActualGrant(boolean hasLimit, Integer currentCount, Integer requestedCount, Integer maxCount) {
|
|
|
+ if (!hasLimit) {
|
|
|
+ // 如果没有限制,直接返回请求的次数
|
|
|
+ return requestedCount;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果有限制
|
|
|
+ int current = currentCount != null ? currentCount : 0;
|
|
|
+ int max = maxCount != null ? maxCount : 0;
|
|
|
+ int requested = requestedCount != null ? requestedCount : 0;
|
|
|
+
|
|
|
+ // 计算还能发放多少次
|
|
|
+ int remainingQuota = max - current;
|
|
|
+
|
|
|
+ // 实际发放次数为:请求次数 和 剩余配额 的较小值
|
|
|
+ return Math.max(0, Math.min(requested, remainingQuota));
|
|
|
+ }
|
|
|
+
|
|
|
}
|