package com.xiaopeng.account.util; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.xiaopeng.account.constant.I18nKeyConstant; import com.xiaopeng.account.service.IXpAppUserCouponService; import com.xiaopeng.account.service.impl.XpAppUserCouponServiceImpl; import com.xiaopeng.api.dto.account.UcUserInfo; import com.xiaopeng.api.dto.operation.SmsDto; import com.xiaopeng.api.feignClient.account.UserResourcesClient; import com.xiaopeng.api.feignClient.account.XpAppUserCouponClient; import com.xiaopeng.api.feignClient.operation.SmsClient; import com.xiaopeng.api.feignClient.operation.XpActicityClient; import com.xiaopeng.api.feignClient.operation.XpCouponClient; import com.xiaopeng.api.feignClient.order.XpOrderClient; import com.xiaopeng.api.feignClient.pushMessage.SubscribeMessageClient; import com.xiaopeng.api.feignClient.pushMessage.WebSocketMessageClient; import com.xiaopeng.api.model.account.XpAppUserCoupon; import com.xiaopeng.api.model.operation.XpActicityStrategy; import com.xiaopeng.api.model.operation.XpActivity; import com.xiaopeng.api.model.operation.XpCoupon; import com.xiaopeng.api.vo.operation.SmsVo; import com.xiaopeng.api.vo.pushMessage.SendCouponMessageVo; import com.xiaopeng.api.vo.pushMessage.SendSubscribeMessageVo; import com.xiaopeng.common.core.constant.Constants; import com.xiaopeng.common.core.domain.R; import com.xiaopeng.common.core.enums.MessageTemplateEnum; import com.xiaopeng.common.core.exception.ServiceException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.List; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @Slf4j @Component public class UserCouponTask { @Resource private IXpAppUserCouponService xpAppUserCouponService; @Resource private XpActicityClient acticityClient; @Resource private SubscribeMessageClient subscribeMessageClient; @Resource private XpCouponClient xpCouponClient; @Resource private SmsClient smsClient; @Value("${sms.appid}") private String sms_appid; @Resource private UserResourcesClient userResourcesClient; @Resource private WebSocketMessageClient webSocketMessageClient; private static final ThreadPoolExecutor RETRY_EXECUTOR = new ThreadPoolExecutor( 4, 16, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(512), new ThreadFactory() { private final AtomicInteger counter = new AtomicInteger(0); @Override public Thread newThread(Runnable r) { Thread t = new Thread(r, "route-push-retry-" + counter.incrementAndGet()); t.setDaemon(true); return t; } }, new ThreadPoolExecutor.CallerRunsPolicy() ); /** * 定时任务发送优惠券通知 */ @Scheduled(fixedDelay = 30000) public void taskOrder() { List activityList = acticityClient.getAllEffectiveActivity().getData(); List collect1 = activityList.stream().filter(xpActivity -> null != xpActivity.getWechatNotification() && xpActivity.getWechatNotification() == 1).collect(Collectors.toList()); pushWxCouponMessage(collect1); List collect2 = activityList.stream().filter(xpActivity -> null != xpActivity.getSmsNotification() && xpActivity.getSmsNotification() == 1).collect(Collectors.toList()); pushSmsCouponMessage(collect2); List collect3 = activityList.stream().filter(xpActivity -> null != xpActivity.getMiniProgramNotification() && xpActivity.getMiniProgramNotification() == 1).collect(Collectors.toList()); pushMiniProgramCouponMessage(collect3); editUserCouponStatus(); } /** * 微信通知 */ private void pushWxCouponMessage(List activityList) { log.info("开始执行优惠券微信提醒消息发送 {}", activityList.size()); for (XpActivity xpActivity : activityList) { //微信通知活动开始提醒(0=否,1=是) Integer wechatActicityStart = xpActivity.getWechatActicityStart(); if(null != wechatActicityStart && 1 == wechatActicityStart){ RETRY_EXECUTOR.execute(() -> { //即将到期提前通知 Integer wechatActicityStartMinutes = xpActivity.getWechatActicityStartMinutes(); //获取满足微信通知的即将生效的优惠券 long time = LocalDateTime.now().plusMinutes(wechatActicityStartMinutes).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(effective_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(effective_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行生效前优惠券微信提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { XpCoupon coupon = xpCouponClient.getCouponById(xpAppUserCoupon.getCouponId()).getData(); SendSubscribeMessageVo vo = new SendSubscribeMessageVo(); vo.setUserId(xpAppUserCoupon.getAppUserId()); vo.setTemplateId(MessageTemplateEnum.C.getTemplateId()); String json = MessageTemplateEnum.C.getRemarks(); json = json.replace("活动名称", xpAppUserCoupon.getCouponName()); json = json.replace("温馨提示", coupon.getCouponDescription()); vo.setJson(json); R r = subscribeMessageClient.sendSubscribeMessage(vo); } }); } //微信通知即将过期提醒(0=否,1=是) Integer wechatAboutExpireReminder = xpActivity.getWechatAboutExpireReminder(); if(null != wechatAboutExpireReminder && 1 == wechatAboutExpireReminder){ RETRY_EXECUTOR.execute(() -> { //即将到期提前通知 Integer wechatAboutExpireDays = xpActivity.getWechatAboutExpireDays(); //微信通知即将过期天数 long time = LocalDateTime.now().plusDays(wechatAboutExpireDays).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(expiration_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(expiration_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行优惠券即将过期微信提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { XpCoupon coupon = xpCouponClient.getCouponById(xpAppUserCoupon.getCouponId()).getData(); SendSubscribeMessageVo vo = new SendSubscribeMessageVo(); vo.setUserId(xpAppUserCoupon.getAppUserId()); vo.setTemplateId(MessageTemplateEnum.F.getTemplateId()); String json = MessageTemplateEnum.F.getRemarks(); json = json.replace("优惠券名称", xpAppUserCoupon.getCouponName()); json = json.replace("券过期时间", xpAppUserCoupon.getExpirationTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))); json = json.replace("使用规则", coupon.getCouponDescription()); vo.setJson(json); R r = subscribeMessageClient.sendSubscribeMessage(vo); } }); } } } /** * 短信通知 * @param activityList */ private void pushSmsCouponMessage(List activityList) { log.info("开始执行优惠券短信提醒消息发送 {}", activityList.size()); aa: for (XpActivity xpActivity : activityList) { Integer now = Integer.valueOf(LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmm"))); Integer smsAboutExpireReminder = xpActivity.getSmsAboutExpireReminder(); if(StringUtils.hasLength(xpActivity.getSmsStartBlockingTime())){ String[] smsStartBlockingTime = xpActivity.getSmsStartBlockingTime().split(","); String[] smsEndBlockingTime = xpActivity.getSmsEndBlockingTime().split(","); for (int i = 0; i < smsStartBlockingTime.length; i++) { Integer start = Integer.valueOf(smsStartBlockingTime[i].replace(":", "")); Integer end = Integer.valueOf(smsEndBlockingTime[i].replace(":", "")); if(start <= now && now <= end){ log.info("当前时间在短信发送时间区间内,不发送短信"); continue aa; } } } //微信通知活动开始提醒(0=否,1=是) Integer smsActicityStart = xpActivity.getSmsActicityStart(); if(null != smsActicityStart && 1 == smsActicityStart){ RETRY_EXECUTOR.execute(() -> { //短信通知临近券生效前X分钟通知 Integer smsActicityStartMinutes = xpActivity.getSmsActicityStartMinutes(); //获取满足微信通知的即将生效的优惠券 long time = LocalDateTime.now().plusMinutes(smsActicityStartMinutes).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(effective_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(effective_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行生效前优惠券短信提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { UcUserInfo ucUserInfo = userResourcesClient.getBaseUserByUid(xpAppUserCoupon.getAppUserId().toString()); if(null == ucUserInfo || !StringUtils.hasLength(ucUserInfo.getMobile())){ log.info("用户信息不存在,跳过"); continue; } XpCoupon coupon = xpCouponClient.getCouponById(xpAppUserCoupon.getCouponId()).getData(); SmsVo vo = new SmsVo(); vo.setAppId(sms_appid); vo.setPushType(1); vo.setReceivers(ucUserInfo.getMobile()); vo.setTemplateCode("RTActivityStartTpl"); vo.setAppPushConfigCode("RTActivityStartSms"); vo.setParams(new HashMap<>()); vo.getParams().put("name", xpAppUserCoupon.getCouponName()); SmsDto smsDto = smsClient.pushSms(vo); if(null == smsDto || smsDto.getCode() != 200){ log.info("短信发送失败"); } } }); } //短信通知即将过期提醒(0=否,1=是) if(null != smsAboutExpireReminder && 1 == smsAboutExpireReminder){ RETRY_EXECUTOR.execute(() -> { //即将到期提前通知 Integer smsAboutExpireDays = xpActivity.getSmsAboutExpireDays(); //微信通知即将过期天数 long time = LocalDateTime.now().plusDays(smsAboutExpireDays).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(expiration_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(expiration_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行优惠券即将过期短信提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { UcUserInfo ucUserInfo = userResourcesClient.getBaseUserByUid(xpAppUserCoupon.getAppUserId().toString()); if(null == ucUserInfo || !StringUtils.hasLength(ucUserInfo.getMobile())){ log.info("用户信息不存在,跳过"); continue; } SmsVo vo = new SmsVo(); vo.setAppId(sms_appid); vo.setPushType(1); vo.setReceivers(ucUserInfo.getMobile()); vo.setTemplateCode("RTCouponExpireSoonTpl"); vo.setAppPushConfigCode("RTCouponExpireSoonSms"); vo.setParams(new HashMap<>()); vo.getParams().put("name", xpAppUserCoupon.getCouponName()); SmsDto smsDto = smsClient.pushSms(vo); if(null == smsDto || smsDto.getCode() != 200){ log.info("短信发送失败"); } } }); } } } /** * 小程序通知 * @param activityList */ private void pushMiniProgramCouponMessage(List activityList) { log.info("开始执行优惠券小程序提醒消息发送 {}", activityList.size()); for (XpActivity xpActivity : activityList) { //小程序弹窗券到账提醒(0=否,1=是) Integer miniProgramReceivedReminder = xpActivity.getMiniProgramReceivedReminder(); String expireMinutesNotificationContent = xpActivity.getExpireMinutesNotificationContent(); if(null != miniProgramReceivedReminder && 1 == miniProgramReceivedReminder){ RETRY_EXECUTOR.execute(() -> { //即将到期提前通知 Integer miniProgramAboutExpireMinutes = xpActivity.getMiniProgramAboutExpireMinutes(); //获取满足微信通知的即将生效的优惠券 long time = LocalDateTime.now().plusMinutes(miniProgramAboutExpireMinutes).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(effective_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(effective_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行生效前优惠券小程序提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { SendCouponMessageVo vo = new SendCouponMessageVo(); vo.setAppUserId(xpAppUserCoupon.getAppUserId()); JSONObject message = new JSONObject(); message.put("type", "COUPON_MESSAGE"); message.put("content", expireMinutesNotificationContent); message.put("timestamp", System.currentTimeMillis()); vo.setMessage(message.toString()); webSocketMessageClient.sendCouponMessage(vo); } }); } //小程序弹窗即将过期提醒(0=否,1=是) Integer miniProgramAboutExpireReminder = xpActivity.getMiniProgramAboutExpireReminder(); String expireDaysNotificationContent = xpActivity.getExpireDaysNotificationContent(); if(null != miniProgramAboutExpireReminder && 1 == miniProgramAboutExpireReminder){ RETRY_EXECUTOR.execute(() -> { //即将到期提前通知 Integer aboutExpireDays = xpActivity.getAboutExpireDays(); //微信通知即将过期天数 long time = LocalDateTime.now().plusDays(aboutExpireDays).toEpochSecond(ZoneOffset.of("+8")); List list = xpAppUserCouponService.list(new LambdaUpdateWrapper() .eq(XpAppUserCoupon::getActivityId, xpActivity.getId()).eq(XpAppUserCoupon::getStatus, 1) .last(" and UNIX_TIMESTAMP(expiration_time) >= " + time + " and " + time + "> UNIX_TIMESTAMP(expiration_time) - 100")); if(list.isEmpty()){ return; } log.info("开始执行优惠券即将过期小程序提醒消息发送"); for (XpAppUserCoupon xpAppUserCoupon : list) { SendCouponMessageVo vo = new SendCouponMessageVo(); vo.setAppUserId(xpAppUserCoupon.getAppUserId()); JSONObject message = new JSONObject(); message.put("type", "COUPON_MESSAGE"); message.put("content", expireDaysNotificationContent); message.put("timestamp", System.currentTimeMillis()); vo.setMessage(message.toString()); webSocketMessageClient.sendCouponMessage(vo); } }); } } } private void editUserCouponStatus(){ log.info("开始执行编辑用户优惠券状态"); RETRY_EXECUTOR.execute(() -> { xpAppUserCouponService.update(new LambdaUpdateWrapper() .set(XpAppUserCoupon::getStatus, 3) .eq(XpAppUserCoupon::getStatus, 1) .le(XpAppUserCoupon::getExpirationTime, LocalDateTime.now())); }); } }