|
|
@@ -1,21 +1,20 @@ |
|
|
package com.iformall.schedule; |
|
|
package com.iformall.schedule; |
|
|
|
|
|
|
|
|
|
|
|
import com.alibaba.fastjson.JSONArray; |
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
import com.alibaba.fastjson.JSONObject; |
|
|
import com.iformall.common.ErrorCode; |
|
|
|
|
|
import com.iformall.domain.dto.WxCUserBasicInfoDto; |
|
|
import com.iformall.domain.dto.WxCUserBasicInfoDto; |
|
|
import com.iformall.domain.po.*; |
|
|
import com.iformall.domain.po.*; |
|
|
import com.iformall.domain.vo.WxCouponSendVo; |
|
|
import com.iformall.domain.vo.WxCouponSendVo; |
|
|
import com.iformall.enums.EnumCouponSendSendType; |
|
|
import com.iformall.enums.EnumCouponSendSendType; |
|
|
import com.iformall.enums.EnumCouponSendStatus; |
|
|
import com.iformall.enums.EnumCouponSendStatus; |
|
|
import com.iformall.exception.MallinkException; |
|
|
|
|
|
import com.iformall.mapper.*; |
|
|
import com.iformall.mapper.*; |
|
|
import com.iformall.service.WxCouponActionLogService; |
|
|
|
|
|
import com.iformall.service.WxCouponSendService; |
|
|
|
|
|
import com.iformall.service.WxLevelConfigService; |
|
|
|
|
|
import com.iformall.service.WxOrderService; |
|
|
|
|
|
import io.swagger.models.auth.In; |
|
|
|
|
|
|
|
|
import com.iformall.service.*; |
|
|
|
|
|
import com.iformall.utils.DateUtils; |
|
|
|
|
|
import org.apache.commons.collections.CollectionUtils; |
|
|
|
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
import org.slf4j.Logger; |
|
|
import org.slf4j.Logger; |
|
|
import org.slf4j.LoggerFactory; |
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
|
import org.springframework.beans.BeanUtils; |
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
import org.springframework.scheduling.annotation.Scheduled; |
|
|
import org.springframework.scheduling.annotation.Scheduled; |
|
|
import org.springframework.stereotype.Component; |
|
|
import org.springframework.stereotype.Component; |
|
|
@@ -56,6 +55,12 @@ public class CouponSendSchedule { |
|
|
@Autowired |
|
|
@Autowired |
|
|
private WxCouponActionLogService wxCouponActionLogService; |
|
|
private WxCouponActionLogService wxCouponActionLogService; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private WxCouponSendConfigMapper couponSendConfigMapper ; |
|
|
|
|
|
|
|
|
|
|
|
@Autowired |
|
|
|
|
|
private WxCouponMapper wxCouponMapper ; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//@Scheduled(cron = "0 0 6 1 * ?") // 每月1号发放会员的权益券 |
|
|
//@Scheduled(cron = "0 0 6 1 * ?") // 每月1号发放会员的权益券 |
|
|
@Scheduled(cron = "0 0 6 * * ?") // 测试每天6点发券 |
|
|
@Scheduled(cron = "0 0 6 * * ?") // 测试每天6点发券 |
|
|
@@ -79,9 +84,14 @@ public class CouponSendSchedule { |
|
|
.with(LocalTime.MAX) |
|
|
.with(LocalTime.MAX) |
|
|
.atZone(ZoneId.systemDefault()) |
|
|
.atZone(ZoneId.systemDefault()) |
|
|
.toInstant()); |
|
|
.toInstant()); |
|
|
|
|
|
|
|
|
|
|
|
//查找所有couponSendConfig |
|
|
|
|
|
Map<String, Integer> mallConfigMap = getAllCouponSendConfig(); |
|
|
mallList.stream().forEach(mall-> { |
|
|
mallList.stream().forEach(mall-> { |
|
|
|
|
|
|
|
|
|
|
|
//判断启用状态,状态为关闭时跳过不执行 |
|
|
|
|
|
if (isCouponSendDisable(mallConfigMap, mall)) { |
|
|
|
|
|
logger.info("定时发券: {}发券状态关闭,任务跳过不执行", mall.getName()); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
WxLevelConfig wxLevelConfig = new WxLevelConfig(); |
|
|
WxLevelConfig wxLevelConfig = new WxLevelConfig(); |
|
|
wxLevelConfig.setTenantId(mall.getTenantId()); |
|
|
wxLevelConfig.setTenantId(mall.getTenantId()); |
|
|
List<WxLevelConfig> levelConfigList = WxLevelConfigMapper.findList(wxLevelConfig); |
|
|
List<WxLevelConfig> levelConfigList = WxLevelConfigMapper.findList(wxLevelConfig); |
|
|
@@ -189,4 +199,181 @@ public class CouponSendSchedule { |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
* 生日券发放 |
|
|
|
|
|
*/ |
|
|
|
|
|
@Scheduled(cron = "0 0 4 * * ?") // 测试每天6点发券 |
|
|
|
|
|
public void birthdayCouponSendSchedule() { |
|
|
|
|
|
logger.info("生日发券任务开始"); |
|
|
|
|
|
List<WxMall> mallList = wxMallMapper.findList(new WxMall()); |
|
|
|
|
|
if (mallList.size() == 0) { |
|
|
|
|
|
logger.info("生日发券: No Mall info found"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
Date startTime = Date.from(LocalDateTime.now() |
|
|
|
|
|
.with(TemporalAdjusters.firstDayOfYear()) |
|
|
|
|
|
.with(LocalTime.MIN) |
|
|
|
|
|
.atZone(ZoneId.systemDefault()) |
|
|
|
|
|
.toInstant()); |
|
|
|
|
|
Date endTime = Date.from(LocalDateTime.now() |
|
|
|
|
|
.with(TemporalAdjusters.lastDayOfYear()) |
|
|
|
|
|
.with(LocalTime.MAX) |
|
|
|
|
|
.atZone(ZoneId.systemDefault()) |
|
|
|
|
|
.toInstant()); |
|
|
|
|
|
|
|
|
|
|
|
//查找所有couponSendConfig |
|
|
|
|
|
Map<String, Integer> mallConfigMap = getAllCouponSendConfig(); |
|
|
|
|
|
mallList.forEach(mall -> { |
|
|
|
|
|
//判断启用状态,状态为关闭时跳过不执行 |
|
|
|
|
|
if (isCouponSendDisable(mallConfigMap, mall)) { |
|
|
|
|
|
logger.info("生日发券: {} 发券状态关闭, 任务跳过不执行", mall.getName()); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WxCUserBasicInfoDto wxCUserBasicInfoDto = new WxCUserBasicInfoDto(); |
|
|
|
|
|
wxCUserBasicInfoDto.setTenantId(mall.getTenantId()); |
|
|
|
|
|
List<WxCUserBasicInfo> wxCUserBasicInfoList = wxCUserBasicInfoMapper.findBirthdayList(wxCUserBasicInfoDto); |
|
|
|
|
|
if (CollectionUtils.isEmpty(wxCUserBasicInfoList)) { |
|
|
|
|
|
logger.info("生日发券: 用户列表为空 wxCUserBasicInfoList = {}, 任务跳过不执行",wxCUserBasicInfoList); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
//每人可以发送几张生日券 |
|
|
|
|
|
final int sendCount = 2; |
|
|
|
|
|
wxCUserBasicInfoList.forEach(cu -> { |
|
|
|
|
|
WxCouponSend wxCouponSend = new WxCouponSend(); |
|
|
|
|
|
wxCouponSend.setTenantId(cu.getTenantId()); |
|
|
|
|
|
wxCouponSend.setSendType(EnumCouponSendSendType.BIRTHDAY.getCode()); |
|
|
|
|
|
wxCouponSend.setStatus(EnumCouponSendStatus.VALID.getCode()); |
|
|
|
|
|
List<WxCouponSendVo> couponSendList = wxCouponSendMapper.findListVo(wxCouponSend); |
|
|
|
|
|
if(CollectionUtils.isEmpty(couponSendList)) { |
|
|
|
|
|
logger.info("生日发券: 会员生日券配置列表为空 couponSendList = {}, 任务跳过不执行", couponSendList); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
int beforeDays; |
|
|
|
|
|
//获取生日券列表 |
|
|
|
|
|
List<WxCouponSendVo> newCouponSendList = new ArrayList<>() ; |
|
|
|
|
|
for(WxCouponSendVo wxCouponSendVo:couponSendList) { |
|
|
|
|
|
JSONObject conditions = JSONObject.parseObject(wxCouponSendVo.getConditions()); |
|
|
|
|
|
JSONArray couponIdArr = conditions.getJSONArray(WxCouponSend.KEY_COUPONIDS); |
|
|
|
|
|
if (Objects.isNull(couponIdArr) || couponIdArr.isEmpty()) { |
|
|
|
|
|
logger.info("生日发券: 会员生日券列表为空 couponIdArr = {}", couponIdArr); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
List<Long> couponIds = couponIdArr.toJavaList(Long.class); |
|
|
|
|
|
if (CollectionUtils.isEmpty(couponIds)) { |
|
|
|
|
|
logger.error("生日发券: 转换错误 couponIds ={}", couponIds); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
List<WxCoupon> wxCouponList = wxCouponMapper.selectByIds(StringUtils.join(couponIds, ",")); |
|
|
|
|
|
if (CollectionUtils.isEmpty(wxCouponList)) { |
|
|
|
|
|
logger.error("生日发券: 转换错误 wxCouponList ={}", wxCouponList); |
|
|
|
|
|
} |
|
|
|
|
|
//添加卡列表 |
|
|
|
|
|
wxCouponList.forEach(wxCoupon -> { |
|
|
|
|
|
WxCouponSendVo vo = new WxCouponSendVo(); |
|
|
|
|
|
BeanUtils.copyProperties(wxCouponSendVo, vo); |
|
|
|
|
|
vo.setRemainInventory(wxCoupon.getRemainInventory()); |
|
|
|
|
|
vo.setUseLimitQuantity(wxCoupon.getUseLimitQuantity()); |
|
|
|
|
|
vo.setInventory(wxCoupon.getInventory()); |
|
|
|
|
|
vo.setValidStartDate(wxCoupon.getValidStartDate()); |
|
|
|
|
|
vo.setValidEndDate(wxCoupon.getValidEndDate()); |
|
|
|
|
|
vo.setTitle(wxCoupon.getTitle()); |
|
|
|
|
|
newCouponSendList.add(vo); |
|
|
|
|
|
}); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (CollectionUtils.isEmpty(newCouponSendList)) { |
|
|
|
|
|
logger.error("生日发券: 会员生日券列表为空 newCouponSendList ={}, 任务跳过不执行", newCouponSendList); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int remain = newCouponSendList.stream().map(cs -> { |
|
|
|
|
|
int count = cs.getRemainInventory(); |
|
|
|
|
|
logger.info("定时发券:给[" + cu.getNickName() + |
|
|
|
|
|
"]券[" + cs.getTitle() + "]还剩" + |
|
|
|
|
|
count + "张"); |
|
|
|
|
|
return count; |
|
|
|
|
|
}).reduce(Integer::sum).get(); |
|
|
|
|
|
|
|
|
|
|
|
if (remain < sendCount) { |
|
|
|
|
|
logger.error("定时发券:库存不足[" + cu.getNickName() + "]应发" + sendCount + "张,总共剩" + remain + "张"); |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int sentCount = couponSendList.stream().map(cs -> { |
|
|
|
|
|
Map<String,Object> params = new HashMap<>(); |
|
|
|
|
|
params.put("tenantId", cs.getTenantId()); |
|
|
|
|
|
params.put("cUserId", cu.getId()); |
|
|
|
|
|
params.put("couponId", cs.getCouponId()); |
|
|
|
|
|
params.put("startTime", startTime); |
|
|
|
|
|
params.put("endTime", endTime); |
|
|
|
|
|
params.put("channelType", EnumCouponSendSendType.BIRTHDAY.getCode()); |
|
|
|
|
|
int count = wxCouponActionLogMapper.getCountByUserAndCouponAndDate(params); |
|
|
|
|
|
logger.info("生日发券:已经给[" + cu.getNickName() + |
|
|
|
|
|
"]券[" + cs.getTitle() + "] " + |
|
|
|
|
|
count + "张"); |
|
|
|
|
|
return count; |
|
|
|
|
|
}).reduce(Integer::sum).orElse(0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger.info("生日发券:给[" + cu.getNickName() + |
|
|
|
|
|
"]总共已发送券" + sentCount + "张,还需发" + (sendCount - sentCount) + "张"); |
|
|
|
|
|
|
|
|
|
|
|
for (int count = 0; count < sendCount - sentCount; count++) { |
|
|
|
|
|
boolean sent = false; |
|
|
|
|
|
for (int couponIndex = 0; couponIndex < couponSendList.size(); couponIndex++) { |
|
|
|
|
|
WxCouponSendVo cs = couponSendList.get(couponIndex); |
|
|
|
|
|
JSONObject condititions = JSONObject.parseObject(cs.getConditions()) ; |
|
|
|
|
|
beforeDays = condititions.getIntValue(WxCouponSend.KEY_BEFOREDAYS); |
|
|
|
|
|
//提前n天发送生日券,不满足跳过不执行 |
|
|
|
|
|
if(DateUtils.daysBetween(cu.getBirthdate(), new Date()) == beforeDays) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
if (cs.getRemainInventory() <= 0) |
|
|
|
|
|
continue; |
|
|
|
|
|
// 发放免费券 |
|
|
|
|
|
try { |
|
|
|
|
|
WxCouponOrder couponOrder = wxOrderService.sendFreeCouponToUser(cu.getId(), cs.getCouponId()); |
|
|
|
|
|
wxCouponActionLogService.addOne(cu.getTenantId(), cs.getCouponId(), couponOrder.getId(), cs.getSendType(), cs.getId()); |
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
logger.error("定时发券:发券失败 levelId=" + cu.getId() + " couponId=" + cs.getCouponId() + " userId=" + cu.getId() + e.getMessage()); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
logger.info("定时发券:商场[" + mall.getName() + |
|
|
|
|
|
"]会员生日[" + cu.getBirthdate().toInstant() + |
|
|
|
|
|
"]发送券[" + cs.getTitle() + |
|
|
|
|
|
"]给:" + cu.getNickName() + |
|
|
|
|
|
" 电话-" + cu.getPhone() + |
|
|
|
|
|
" id-" + cu.getId()); |
|
|
|
|
|
sent = true; |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
if (!sent) |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
logger.info("生日发券任务结束"); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Map<String, Integer> getAllCouponSendConfig() { |
|
|
|
|
|
WxCouponSendConfig queryConfig = new WxCouponSendConfig(); |
|
|
|
|
|
queryConfig.setSendType(EnumCouponSendSendType.TIMED.getCode()); |
|
|
|
|
|
List<WxCouponSendConfig> couponSendConfigList = couponSendConfigMapper.findList(queryConfig); |
|
|
|
|
|
Map<String, Integer> mallConfigMap = CollectionUtils.isNotEmpty(couponSendConfigList) ? |
|
|
|
|
|
couponSendConfigList.stream().collect(Collectors.toMap(WxCouponSendConfig::getTenantId, WxCouponSendConfig::getValue)) : null; |
|
|
|
|
|
return mallConfigMap; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private boolean isCouponSendDisable(Map<String, Integer> mallConfigMap, WxMall mall) { |
|
|
|
|
|
if (mallConfigMap != null && Objects.nonNull(mallConfigMap.get(mall.getTenantId()))) { |
|
|
|
|
|
Integer disable = mallConfigMap.get(mall.getTenantId()); |
|
|
|
|
|
return disable == 1; |
|
|
|
|
|
} |
|
|
|
|
|
return false; |
|
|
|
|
|
} |
|
|
} |
|
|
} |