Ver código fonte

批量发放优惠券逻辑完善

xdd 3 meses atrás
pai
commit
828a9c0e9d

+ 28 - 0
fs-admin/src/main/java/com/fs/task/CouponTask.java

@@ -0,0 +1,28 @@
+package com.fs.task;
+
+import com.fs.store.service.IFsCouponScheduleService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+/**
+ * 优惠券定时任务
+ */
+@RequiredArgsConstructor
+@Service("couponTask")
+@Slf4j
+public class CouponTask {
+
+    private final IFsCouponScheduleService fsCouponScheduleService;
+    /**
+     * 发放优惠券
+     */
+    public void issueCoupon(){
+        log.info("开始执行发放优惠券定时任务");
+        long startTime = System.currentTimeMillis();
+        fsCouponScheduleService.issueCoupon();
+        long endTime = System.currentTimeMillis();
+        log.info("发放优惠券定时任务执行完成,耗时:{}毫秒", endTime - startTime);
+    }
+
+}

+ 4 - 4
fs-admin/src/main/java/com/fs/task/MiniProgramSubTask.java

@@ -8,7 +8,7 @@ import com.fs.store.dto.ClientCredGrantReqDTO;
 import com.fs.store.dto.MiniGramSubsMsgResultDTO;
 import com.fs.store.dto.TemplateMessageSendRequestDTO;
 import com.fs.store.dto.WeXinAccessTokenDTO;
-import com.fs.store.enums.MiniAppNotifyTaskStatus;
+import com.fs.store.enums.MiniAppNotifyTaskStatusEnum;
 import com.fs.store.mapper.FsMiniprogramSubNotifyTaskMapper;
 import com.fs.store.service.IWechatMiniProgrService;
 import com.fs.wx.miniapp.config.WxMaProperties;
@@ -82,16 +82,16 @@ public class MiniProgramSubTask {
 
                // 如果推送消息成功
                if(miniGramSubsMsgResultDTO.getErrcode() == 0){
-                   pendingDatum.setStatus(MiniAppNotifyTaskStatus.SUCCESS.getValue());
+                   pendingDatum.setStatus(MiniAppNotifyTaskStatusEnum.SUCCESS.getValue());
                } else {
                    // 更新任务状态为执行失败
-                   pendingDatum.setStatus(MiniAppNotifyTaskStatus.FAILED.getValue());
+                   pendingDatum.setStatus(MiniAppNotifyTaskStatusEnum.FAILED.getValue());
                    pendingDatum.setErrorMessage(JSONObject.toJSONString(miniGramSubsMsgResultDTO));
                    pendingDatum.setRetryCount(pendingDatum.getRetryCount() +1);
                }
            }catch (Exception e){
                // 更新任务状态为执行失败
-               pendingDatum.setStatus(MiniAppNotifyTaskStatus.FAILED.getValue());
+               pendingDatum.setStatus(MiniAppNotifyTaskStatusEnum.FAILED.getValue());
                pendingDatum.setErrorMessage(ExceptionUtils.getStackTrace(e));
                pendingDatum.setRetryCount(pendingDatum.getRetryCount() +1);
                log.error("小程序订阅通知定时任务异常: {}", ExceptionUtils.getStackTrace(e));

+ 1 - 1
fs-service-system/src/main/java/com/fs/store/domain/FsMiniprogramSubNotifyTask.java

@@ -57,7 +57,7 @@ public class FsMiniprogramSubNotifyTask {
     private Integer maxRetries;
 
     /**
-     * 请求参数(JSON格式,主要记录 access_token 获取方式)
+     * 请求参数
      */
     private String requestParams;
 

+ 4 - 4
fs-service-system/src/main/java/com/fs/store/enums/MiniAppNotifyTaskStatus.java → fs-service-system/src/main/java/com/fs/store/enums/MiniAppNotifyTaskStatusEnum.java

@@ -4,7 +4,7 @@ package com.fs.store.enums;
 import lombok.Getter;
 
 @Getter
-public enum MiniAppNotifyTaskStatus {
+public enum MiniAppNotifyTaskStatusEnum {
     /**
      * 待执行
      */
@@ -28,13 +28,13 @@ public enum MiniAppNotifyTaskStatus {
 
     private final int value;
 
-    MiniAppNotifyTaskStatus(int value) {
+    MiniAppNotifyTaskStatusEnum(int value) {
         this.value = value;
     }
 
 
-    public static MiniAppNotifyTaskStatus fromValue(int value) {
-        for (MiniAppNotifyTaskStatus status : values()) {
+    public static MiniAppNotifyTaskStatusEnum fromValue(int value) {
+        for (MiniAppNotifyTaskStatusEnum status : values()) {
             if (status.getValue() == value) {
                 return status;
             }

+ 6 - 0
fs-service-system/src/main/java/com/fs/store/mapper/FsMiniprogramSubNotifyTaskMapper.java

@@ -72,4 +72,10 @@ public interface FsMiniprogramSubNotifyTaskMapper {
      * @param pendingData 更新的数据
      */
     void updateBatchById(@Param("list") List<FsMiniprogramSubNotifyTask> pendingData);
+
+    /**
+     * 批量插入数据
+     * @param subNotifyTasks 数据
+     */
+    void insertBatch(List<FsMiniprogramSubNotifyTask> subNotifyTasks);
 }

+ 8 - 0
fs-service-system/src/main/java/com/fs/store/mapper/FsStoreCouponIssueMapper.java

@@ -139,4 +139,12 @@ public interface FsStoreCouponIssueMapper
      * @return List<FsStoreCouponIssueVO>
      */
     List<FsStoreCouponIssueVO> listAllAvailable();
+
+    /**
+     * 根据优惠券id查询已发布的优惠券
+     * @param couponId
+     * @return
+     */
+    @Select("select * from fs_store_coupon_issue where coupon_id=${couponId} and status=1 and is_del=0 limit 1")
+    FsStoreCouponIssue selectFsStoreCouponIssueByCouponId(@Param("couponId") Long couponId);
 }

+ 9 - 0
fs-service-system/src/main/java/com/fs/store/mapper/FsStoreCouponMapper.java

@@ -1,7 +1,10 @@
 package com.fs.store.mapper;
 
 import java.util.List;
+import java.util.Set;
+
 import com.fs.store.domain.FsStoreCoupon;
+import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 
 /**
@@ -64,5 +67,11 @@ public interface FsStoreCouponMapper
     @Select("select * from fs_store_coupon where find_in_set(coupon_id,#{ids})")
     List<FsStoreCoupon> selectFsStoreCouponByIds(String ids);
 
+    /**
+     * 查询优惠券名称,通过ids
+     * @param couponId id
+     * @return List<String>
+     */
+    String selectFsStoreCouponNameById(@Param("couponId") Long couponId);
 
 }

+ 7 - 0
fs-service-system/src/main/java/com/fs/store/service/IFsStoreCouponIssueService.java

@@ -75,4 +75,11 @@ public interface IFsStoreCouponIssueService
     List<FsStoreCouponIssueVO> selectFsStoreCouponIssueListVO(FsStoreCouponIssue fsStoreCouponIssue);
 
     List<FsStoreCouponIssueVO> listAllAvailable();
+
+    /**
+     * 查询优惠券领取列表
+     * @param ids
+     * @return
+     */
+    FsStoreCouponIssue selectFsStoreCouponIssueByCouponId(Long couponId);
 }

+ 121 - 22
fs-service-system/src/main/java/com/fs/store/service/impl/FsCouponScheduleServiceImpl.java

@@ -3,21 +3,24 @@ package com.fs.store.service.impl;
 import java.time.LocalDateTime;
 import java.util.*;
 
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.fs.common.core.domain.R;
 import com.fs.common.utils.DateUtils;
-import com.fs.store.domain.FsCouponSchedule;
-import com.fs.store.domain.FsCouponScheduleLog;
+import com.fs.store.domain.*;
+import com.fs.store.dto.TemplateMessageSendRequestDTO;
 import com.fs.store.enums.IcgProcessStatusEnum;
 import com.fs.store.enums.IcgScheduleOperationTypeEnum;
-import com.fs.store.mapper.FsCouponScheduleLogMapper;
-import com.fs.store.mapper.FsCouponScheduleMapper;
+import com.fs.store.enums.MiniAppNotifyTaskStatusEnum;
+import com.fs.store.mapper.*;
 import com.fs.store.param.FsStoreCouponReceiveParam;
 import com.fs.store.service.IFsCouponScheduleService;
 import com.fs.store.service.IFsStoreCouponIssueService;
+import com.github.pagehelper.util.StringUtil;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Propagation;
 import org.springframework.transaction.annotation.Transactional;
@@ -29,7 +32,7 @@ import org.springframework.transaction.annotation.Transactional;
  * @date 2025-03-08
  */
 @Slf4j
-@Service("fsCouponScheduleService")
+@Service
 @RequiredArgsConstructor
 public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
 {
@@ -45,6 +48,36 @@ public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
      * 优惠券发放计划日志表Mapper接口
      */
     private final FsCouponScheduleLogMapper fsCouponScheduleLogMapper;
+    /**
+     * 优惠券表Mapper接口
+     */
+    private final FsStoreCouponMapper fsStoreCouponMapper;
+
+    /**
+     * 用户表Mapper接口
+     */
+    private final FsUserMapper fsUserMapper;
+
+    /**
+     * 优惠券发放计划日志表Mapper接口
+     */
+    private final FsMiniprogramSubNotifyTaskMapper fsMiniprogramSubNotifyTaskMapper;
+
+    /**
+     * 小程序消息通知任务名称
+     */
+    private final String WX_MINI_APP_NOTIFY_TASK_NAME = "优惠券发放";
+
+    /**
+     * 小程序消息通知模板ID
+     */
+    private final String WX_MINI_APP_NOTIFY_TEMPLATE_ID = "5ZSzz2nPmJo9EuenZa78mQPScoOMc84LnEfEpV0-i04";
+
+    /**
+     * 小程序消息通知跳转URL
+     */
+    private final String WX_MINI_APP_NOTIFY_GOTO_URL ="";
+
     /**
      * 查询定时发放优惠券队列
      *
@@ -141,18 +174,20 @@ public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
     public void issueCoupon() {
         List<FsCouponSchedule> fsCouponSchedules = fsCouponScheduleMapper.selectPendingCouponList();
         List<FsCouponScheduleLog> logList = new ArrayList<>();
+        List<FsMiniprogramSubNotifyTask> subNotifyTasks = new ArrayList<>();
+
         for (FsCouponSchedule fsCouponSchedule : fsCouponSchedules) {
 
-            FsCouponScheduleLog log = new FsCouponScheduleLog();
+            FsCouponScheduleLog scheduleLog = new FsCouponScheduleLog();
 
-            log.setScheduleId(fsCouponSchedule.getId());
-            log.setOrderId(fsCouponSchedule.getOrderId());
-            log.setUserId(fsCouponSchedule.getUserId());
-            log.setStatusBefore(fsCouponSchedule.getStatus());
-            log.setSendTimeBefore(fsCouponSchedule.getSendTime());
-            log.setRetryCountBefore(fsCouponSchedule.getRetryCount());
-            log.setOperator("SYSTEM");
-            log.setOperationTime(LocalDateTime.now());
+            scheduleLog.setScheduleId(fsCouponSchedule.getId());
+            scheduleLog.setOrderId(fsCouponSchedule.getOrderId());
+            scheduleLog.setUserId(fsCouponSchedule.getUserId());
+            scheduleLog.setStatusBefore(fsCouponSchedule.getStatus());
+            scheduleLog.setSendTimeBefore(fsCouponSchedule.getSendTime());
+            scheduleLog.setRetryCountBefore(fsCouponSchedule.getRetryCount());
+            scheduleLog.setOperator("SYSTEM");
+            scheduleLog.setOperationTime(LocalDateTime.now());
 
             FsStoreCouponReceiveParam param = new FsStoreCouponReceiveParam();
             Long userId = fsCouponSchedule.getUserId();
@@ -168,8 +203,8 @@ public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
                 fsCouponSchedule.setStatus(IcgProcessStatusEnum.FAILED.getCode());
                 fsCouponSchedule.setRetryCount(fsCouponSchedule.getRetryCount()+1);
 
-                log.setStatusAfter(IcgProcessStatusEnum.FAILED.getCode());
-                log.setErrorMessage(fsCouponSchedule.getErrorMessage());
+                scheduleLog.setStatusAfter(IcgProcessStatusEnum.FAILED.getCode());
+                scheduleLog.setErrorMessage(fsCouponSchedule.getErrorMessage());
 
                 operationTypeSet.add(IcgScheduleOperationTypeEnum.ERROR.getCode());
             } else {
@@ -178,21 +213,85 @@ public class FsCouponScheduleServiceImpl implements IFsCouponScheduleService
                 fsCouponSchedule.setSendTime(fsCouponSchedule.getActualSendTime().plusMonths(1));
                 fsCouponSchedule.setCount(fsCouponSchedule.getCount()+1);
 
-                log.setStatusAfter(IcgProcessStatusEnum.SUCCESS.getCode());
-                log.setActualSendTime(fsCouponSchedule.getActualSendTime());
-                log.setSendTimeAfter(fsCouponSchedule.getSendTime());
+                scheduleLog.setStatusAfter(IcgProcessStatusEnum.SUCCESS.getCode());
+                scheduleLog.setActualSendTime(fsCouponSchedule.getActualSendTime());
+                scheduleLog.setSendTimeAfter(fsCouponSchedule.getSendTime());
                 operationTypeSet.add(IcgScheduleOperationTypeEnum.NORMAL.getCode());
+
+
+                // 小程序消息通知
+                FsMiniprogramSubNotifyTask notifyTask = new FsMiniprogramSubNotifyTask();
+                notifyTask.setTaskName(WX_MINI_APP_NOTIFY_TASK_NAME);
+                notifyTask.setTemplateId(WX_MINI_APP_NOTIFY_TEMPLATE_ID);
+                FsUser fsUser = fsUserMapper.selectFsUserById(fsCouponSchedule.getUserId());
+                String maOpenId = fsUser.getMaOpenId();
+                notifyTask.setTouser(maOpenId);
+                notifyTask.setPage(WX_MINI_APP_NOTIFY_GOTO_URL);
+                notifyTask.setCreateTime(LocalDateTime.now());
+                // 状态等待执行
+                notifyTask.setStatus(MiniAppNotifyTaskStatusEnum.WAITING.getValue());
+                notifyTask.setRetryCount(0);
+                Map<String, TemplateMessageSendRequestDTO.TemplateDataValue> data = new HashMap<>();
+                // 获取优惠券名称
+                Set<Long> couponIds = fsCouponSchedule.getCouponId();
+                if(CollectionUtils.isEmpty(couponIds)){
+                    log.info("当前优惠券没有被选择!已经跳过");
+                    continue;
+                }
+                // 优惠券id (有多张这里只取第一张)
+                Long couponId = couponIds.stream().findFirst().get();
+
+                TemplateMessageSendRequestDTO.TemplateDataValue couponName = new TemplateMessageSendRequestDTO.TemplateDataValue();
+                FsStoreCoupon fsStoreCoupon = fsStoreCouponMapper.selectFsStoreCouponById(couponId);
+                if(ObjectUtil.isNotNull(fsStoreCoupon)){
+                    String couponNameById = fsStoreCoupon.getTitle();
+                    if(StringUtil.isNotEmpty(couponNameById)){
+                        couponName.setValue(couponNameById);
+                    }
+                }
+
+                // 获取优惠券时间范围
+                TemplateMessageSendRequestDTO.TemplateDataValue couponValidate = new TemplateMessageSendRequestDTO.TemplateDataValue();
+
+                FsStoreCouponIssue fsStoreCouponIssue = fsStoreCouponIssueService.selectFsStoreCouponIssueByCouponId(couponId);
+                if(ObjectUtil.isNotNull(fsStoreCouponIssue)){
+                    String beginTime = fsStoreCouponIssue.getBeginTime();
+                    String endTime = fsStoreCouponIssue.getEndTime();
+                    if(StringUtil.isNotEmpty(beginTime) && StringUtil.isNotEmpty(endTime)){
+                        couponValidate.setValue(beginTime + " ~ " + endTime);
+                    }
+                }
+                // 备注消息
+                TemplateMessageSendRequestDTO.TemplateDataValue couponMark = new TemplateMessageSendRequestDTO.TemplateDataValue();
+                couponMark.setValue("");
+
+                // 面值
+                TemplateMessageSendRequestDTO.TemplateDataValue couponPrice = new TemplateMessageSendRequestDTO.TemplateDataValue();
+                if(ObjectUtil.isNotNull(fsStoreCoupon)){
+                    if(ObjectUtil.isNotNull(fsStoreCoupon.getCouponPrice())){
+                        couponPrice.setValue(fsStoreCoupon.getCouponPrice().toPlainString());
+                    }
+                }
+
+                data.put("thing1",couponName);
+                data.put("time2",couponValidate);
+                data.put("thing3",couponMark);
+                data.put("amount4",couponPrice);
+
+                notifyTask.setData(JSON.toJSONString(data));
+
+                subNotifyTasks.add(notifyTask);
             }
             fsCouponSchedule.setUpdateTime(new Date());
 
-            log.setOperationType(String.join(",",operationTypeSet));
-            logList.add(log);
+            scheduleLog.setOperationType(String.join(",",operationTypeSet));
+            logList.add(scheduleLog);
         }
         // 批量更新发放优惠券队列表
         fsCouponScheduleMapper.updateBatchFsCouponSchedule(fsCouponSchedules);
         // 批量添加执行日志
         fsCouponScheduleLogMapper.batchInsert(logList);
         // 批量进行微信公众号消息通知
-
+        fsMiniprogramSubNotifyTaskMapper.insertBatch(subNotifyTasks);
     }
 }

+ 6 - 0
fs-service-system/src/main/java/com/fs/store/service/impl/FsStoreCouponIssueServiceImpl.java

@@ -1,6 +1,7 @@
 package com.fs.store.service.impl;
 
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.Date;
 import java.util.List;
 
@@ -186,4 +187,9 @@ public class FsStoreCouponIssueServiceImpl implements IFsStoreCouponIssueService
         return fsStoreCouponIssueMapper.listAllAvailable();
     }
 
+    @Override
+    public FsStoreCouponIssue selectFsStoreCouponIssueByCouponId(Long couponId) {
+        return fsStoreCouponIssueMapper.selectFsStoreCouponIssueByCouponId(couponId);
+    }
+
 }

+ 38 - 0
fs-service-system/src/main/resources/mapper/store/FsAdvMapper_.xml → fs-service-system/src/main/resources/mapper/store/FsMiniprogramSubNotifyTaskMapper.xml

@@ -3,6 +3,44 @@
 PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fs.store.mapper.FsMiniprogramSubNotifyTaskMapper">
+    <insert id="insertBatch">
+        INSERT INTO fs_miniprogram_sub_notify_task (
+        id,
+        task_name,
+        template_id,
+        touser,
+        page,
+        data,
+        status,
+        retry_count,
+        max_retries,
+        request_params,
+        request_body,
+        response_body,
+        error_message,
+        create_time,
+        update_time
+        ) VALUES
+        <foreach collection="list" item="item" separator=",">
+            (
+            #{item.id},
+            #{item.taskName},
+            #{item.templateId},
+            #{item.touser},
+            #{item.page},
+            #{item.data},
+            #{item.status},
+            #{item.retryCount},
+            #{item.maxRetries},
+            #{item.requestParams},
+            #{item.requestBody},
+            #{item.responseBody},
+            #{item.errorMessage},
+            #{item.createTime},
+            #{item.updateTime}
+            )
+        </foreach>
+    </insert>
 
     <update id="updateBatchById" parameterType="java.util.List">
         <foreach collection="list" item="item" separator=";">

+ 4 - 0
fs-service-system/src/main/resources/mapper/store/FsStoreCouponMapper.xml

@@ -51,6 +51,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         <include refid="selectFsStoreCouponVo"/>
         where coupon_id = #{couponId}
     </select>
+    <select id="selectFsStoreCouponNameById" resultType="java.lang.String">
+        select title from fs_store_coupon where id = ${couponId}
+
+    </select>
 
 
     <insert id="insertFsStoreCoupon" parameterType="FsStoreCoupon" useGeneratedKeys="true" keyProperty="couponId">