Преглед на файлове

feat:管理人提醒功能

chenjianhua преди 1 седмица
родител
ревизия
42fef60c4c

+ 3 - 0
service-base/src/main/java/com/simuwang/base/mapper/daq/AssetMapper.java

@@ -5,6 +5,7 @@ import com.simuwang.base.pojo.vo.FundAssetVO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Date;
 import java.util.List;
 
 @Mapper
@@ -25,4 +26,6 @@ public interface AssetMapper {
     void batchDeleteAsset(@Param("fundId")String sourceFundId,@Param("priceDateList") List<String> priceDateList);
 
     Long countAssetTotal();
+
+    Date selectMaxPriceDate(@Param("channelId")Integer channelId, @Param("fundId")String fundId);
 }

+ 13 - 4
service-base/src/main/java/com/simuwang/base/mapper/daq/DeletionInfoMapper.java

@@ -1,9 +1,6 @@
 package com.simuwang.base.mapper.daq;
 
-import com.simuwang.base.pojo.dos.DeletionInfoDO;
-import com.simuwang.base.pojo.dos.EmailDeletionInfoDO;
-import com.simuwang.base.pojo.dos.FundDeletionInfoDO;
-import com.simuwang.base.pojo.dos.FundDeletionTypeDO;
+import com.simuwang.base.pojo.dos.*;
 import com.simuwang.base.pojo.dto.query.DeletionPageQuery;
 import com.simuwang.base.pojo.dto.query.FundDeletionPageQuery;
 import com.simuwang.base.pojo.vo.FundDeletionInfoVO;
@@ -67,4 +64,16 @@ public interface DeletionInfoMapper {
     Integer countChannelFundDeletion(@Param("fundId")String fundId, @Param("deletionType")Integer deletionType, @Param("channelId")Integer channelId, @Param("type")int type);
 
     String getLastDeletionDate(@Param("fundId")String fundId, @Param("deletionType")Integer deletionType, @Param("channelId")Integer channelId);
+
+    List<EmailDeletionInfoDO> selectNavDeletionInfoByFundId(@Param("fundId")String fundId);
+
+    List<EmailDeletionInfoDO> selectDistributeDeletionInfoByFundId(@Param("fundId")String fundId);
+
+    DistributeDeletionInfoDO getDistributeDeletionInfo(@Param("fundId")String fundId);
+
+    void saveDistributeFirstDeletion(DistributeDeletionInfoDO distributeDeletionInfoDO);
+
+    void updateDistributeDeletionInfoDO(DistributeDeletionInfoDO distributeDeletionInfoDO);
+
+    List<EmailDeletionInfoDO> selectAssetDeletionInfoByFundId(@Param("fundId")String fundId);
 }

+ 25 - 0
service-base/src/main/java/com/simuwang/base/mapper/daq/DeletionTaskLogInfoMapper.java

@@ -0,0 +1,25 @@
+package com.simuwang.base.mapper.daq;
+
+import com.simuwang.base.pojo.dos.*;
+import com.simuwang.base.pojo.dto.query.DeletionPageQuery;
+import com.simuwang.base.pojo.dto.query.FundDeletionPageQuery;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * FileName: DeletionInfoMapper
+ * Author:   chenjianhua
+ * Date:     2024/9/17 18:59
+ * Description: ${DESCRIPTION}
+ */
+@Mapper
+public interface DeletionTaskLogInfoMapper {
+
+    List<DeletionTaskLogInfoDO> selectDeletionTaskLogInfoDO(@Param("fundId") String fundId, @Param("channelId")Integer channelId,
+                                                      @Param("frequency")Integer frequency, @Param("priceDate")String priceDate,@Param("deletionType")Integer deletionType);
+
+    void saveDeletionTaskLogInfoDO(DeletionTaskLogInfoDO deletionTaskLogInfoDO);
+}

+ 3 - 0
service-base/src/main/java/com/simuwang/base/mapper/daq/NavMapper.java

@@ -4,6 +4,7 @@ import com.simuwang.base.pojo.dos.NavDO;
 import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Date;
 import java.util.List;
 
 @Mapper
@@ -38,4 +39,6 @@ public interface NavMapper {
     List<NavDO> selectNavByChannelId(@Param("channelId")Integer channelId);
 
     List<NavDO> selectNavByFundIdAndDate(@Param("fundId")String fundId, @Param("priceDate")String priceDate);
+
+    Date selectMaxPriceDate(@Param("channelId")Integer channelId, @Param("fundId")String fundId);
 }

+ 62 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/DeletionTaskLogInfoDO.java

@@ -0,0 +1,62 @@
+package com.simuwang.base.pojo.dos;
+
+import com.simuwang.base.pojo.vo.DeletionInfoVO;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * FileName: DeletionInfoDO
+ * Author:   chenjianhua
+ * Date:     2024/9/17 18:45
+ * Description: ${DESCRIPTION}
+ */
+@Data
+public class DeletionTaskLogInfoDO {
+    /**
+     * 主键Id
+     */
+    private Integer id;
+    /**
+     * 渠道Id
+     */
+    private Integer channelId;
+    /**
+     * 基金ID
+     */
+    private String fundId;
+    /**
+     * 缺失类型
+     */
+    private Integer deletionType;
+    /**
+     * 数据报送频率
+     */
+    private Integer frequency;
+    /**
+     * 最新净值日期
+     */
+    private String priceDate;
+
+    /**
+     * 是否有效:0-无效,1-有效
+     */
+    private Integer isvalid;
+    /**
+     * 创建者Id
+     */
+    private Integer creatorId;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    /**
+     * 修改者Id
+     */
+    private Integer updaterId;
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+
+}

+ 43 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/DistributeDeletionInfoDO.java

@@ -0,0 +1,43 @@
+package com.simuwang.base.pojo.dos;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * FileName: DeletionInfoDO
+ * Author:   chenjianhua
+ * Date:     2024/9/17 18:45
+ * Description: ${DESCRIPTION}
+ */
+@Data
+public class DistributeDeletionInfoDO {
+    /**
+     * 基金ID
+     */
+    private String fundId;
+    /**
+     * 缺失日期
+     */
+    private String deletionDate;
+    /**
+     * 是否有效:0-无效,1-有效
+     */
+    private Integer isvalid;
+    /**
+     * 创建者Id
+     */
+    private Integer creatorId;
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+    /**
+     * 修改者Id
+     */
+    private Integer updaterId;
+    /**
+     * 更新时间
+     */
+    private Date updateTime;
+}

+ 3 - 0
service-base/src/main/resources/mapper/daq/AssetMapper.xml

@@ -79,5 +79,8 @@
     <select id="countAssetTotal" resultType="java.lang.Long">
         select count(1) from asset where isvalid=1
     </select>
+    <select id="selectMaxPriceDate" resultType="java.util.Date">
+        select max(price_date) from asset where fund_id=#{fundId} and price_date=#{priceDate} and isvalid=1
+    </select>
 
 </mapper>

+ 46 - 1
service-base/src/main/resources/mapper/daq/DeletionInfoMapper.xml

@@ -30,6 +30,10 @@
             (#{itemDo.fundId},#{itemDo.deletionType},#{itemDo.deletionDate},#{itemDo.isvalid},#{itemDo.createTime},#{itemDo.updateTime},#{itemDo.isSend},#{itemDo.channelId})
         </foreach>
     </insert>
+    <insert id="saveDistributeFirstDeletion">
+        insert into distribute_first_deletion_info(fund_id,deletion_date,isvalid,createtime,updatetime)
+        values(#{fundId},#{deletionDate},#{isvalid},#{createTime},#{updateTime})
+    </insert>
     <update id="update" parameterType="com.simuwang.base.pojo.dos.FundDeletionInfoDO">
         update deletion_info set fund_id=#{fundId},deletion_type=#{deletionType},deletion_date=#{deletionDate},remark=#{remark},updatetime=#{updateTime}
         where id=#{id} and isvalid=1
@@ -267,7 +271,7 @@
     <select id="countFundDeletion" resultType="java.lang.Integer">
         select count(1) from deletion_info where isvalid=1 and fund_id =#{fundId} and remark is null
     </select>
-    <select id="selectDeletionDetailByFundId" resultType="com.simuwang.base.pojo.dos.EmailDeletionInfoDO">
+    <select id="selectDeletionDetailByFundId" resultMap="BaseEmailMap">
         select info.fund_id,info.fund_name,c.company_name,d.deletion_type,d.deletion_date,ci.id as channel_id,ci.channel_name
         from deletion_info d
         join pvn_fund_info info on d.fund_id=info.fund_id
@@ -292,6 +296,44 @@
     <select id="getLastDeletionDate" resultType="java.lang.String">
         select max(deletion_date) from PPW_EMAIL.deletion_info where isvalid=1 and fund_id=#{fundId} and deletion_type=#{deletionType} and channel_id=#{channelId} AND remark is null
     </select>
+    <select id="selectNavDeletionInfoByFundId"
+            resultMap="BaseEmailMap">
+        select info.fund_id,info.fund_name,c.company_name,d.deletion_type,d.deletion_date,ci.id as channel_id,ci.channel_name
+        from deletion_info d
+        join pvn_fund_info info on d.fund_id=info.fund_id
+        join pvn_company_info c on c.company_id=info.trust_id
+        left join channel_info ci on ci.id=d.channel_id and ci.isvalid=1
+        where d.isvalid=1 and info.isvalid=1 and c.isvalid=1 and d.remark is null and d.is_send=0
+        and d.deletion_type = 1
+        and d.fund_id = #{fundId}
+        order by d.deletion_type,d.deletion_date desc
+    </select>
+    <select id="selectDistributeDeletionInfoByFundId"
+            resultMap="BaseEmailMap">
+        select info.fund_id,info.fund_name,c.company_name,d.deletion_type,d.deletion_date,ci.id as channel_id,ci.channel_name
+        from deletion_info d
+        join pvn_fund_info info on d.fund_id=info.fund_id
+        join pvn_company_info c on c.company_id=info.trust_id
+        left join channel_info ci on ci.id=d.channel_id and ci.isvalid=1
+        where d.isvalid=1 and info.isvalid=1 and c.isvalid=1 and d.remark is null and d.is_send=0
+        and d.deletion_type = 3
+        and d.fund_id =#{fundId}
+        order by d.deletion_date
+    </select>
+    <select id="getDistributeDeletionInfo" resultType="com.simuwang.base.pojo.dos.DistributeDeletionInfoDO">
+        select id,fund_id as "fundId",deletion_date as "deletionDate" from distribute_first_deletion_info where fund_id=#{fundId} and isvalid=1
+    </select>
+    <select id="selectAssetDeletionInfoByFundId" resultMap="BaseResultMap">
+        select info.fund_id,info.fund_name,c.company_name,d.deletion_type,d.deletion_date,ci.id as channel_id,ci.channel_name
+        from deletion_info d
+                 join pvn_fund_info info on d.fund_id=info.fund_id
+                 join pvn_company_info c on c.company_id=info.trust_id
+                 left join channel_info ci on ci.id=d.channel_id and ci.isvalid=1
+        where d.isvalid=1 and info.isvalid=1 and c.isvalid=1 and d.remark is null and d.is_send=0
+          and d.deletion_type = 2
+          and d.fund_id = #{fundId}
+        order by d.deletion_type,d.deletion_date desc
+    </select>
     <update id="updateSendStatusByFundId">
         update deletion_info d set d.is_send=1,d.updatetime=now() where d.isvalid=1
         and d.fund_id in
@@ -331,5 +373,8 @@
             </if>
         </foreach>
     </update>
+    <update id="updateDistributeDeletionInfoDO">
+        update distribute_first_deletion_info set deletion_date=#{deletionDate},updatetime=now() where fund_id=#{fundId} and isvalid=1
+    </update>
 
 </mapper>

+ 29 - 0
service-base/src/main/resources/mapper/daq/DeletionTaskLogInfoMapper.xml

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.simuwang.base.mapper.daq.DeletionTaskLogInfoMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.DeletionTaskLogInfoDO">
+        <id column="id" property="id"/>
+        <result column="fund_id" property="fundId"/>
+        <result column="channel_id" property="channelId"/>
+        <result column="price_date" property="priceDate"/>
+        <result column="frequency" property="frequency"/>
+        <result column="deletion_type" property="deletionType"/>
+        <result column="isvalid" property="isvalid"/>
+        <result column="creatorid" property="creatorId"/>
+        <result column="createtime" property="createTime"/>
+        <result column="updaterid" property="updaterId"/>
+        <result column="updatetime" property="updateTime"/>
+    </resultMap>
+    <insert id="saveDeletionTaskLogInfoDO" parameterType="com.simuwang.base.pojo.dos.DeletionTaskLogInfoDO">
+        insert into deletion_task_log_info(fund_id,deletion_type,price_date,isvalid,createtime,updatetime,channel_id,frequency)
+        values (#{fundId},#{deletionType},#{priceDate},#{isvalid},#{createTime},#{updateTime},#{channelId},#{frequency})
+    </insert>
+    <select id="selectDeletionTaskLogInfoDO" resultMap="BaseResultMap">
+        select id,fund_id,deletion_type,price_date,isvalid,createtime,updatetime,channel_id,frequency from deletion_task_log_info
+        where isvalid=1 and fund_id=#{fundId} and deletion_type=#{deletionType} and channel_id=#{channelId} and price_date=#{priceDate}
+        and frequency = #{frequency}
+        order by createtime desc
+    </select>
+
+
+</mapper>

+ 4 - 0
service-base/src/main/resources/mapper/daq/NavMapper.xml

@@ -149,6 +149,10 @@
         from nav
         where isvalid = 1
           and fund_id = #{fundId} and price_date >= #{priceDate}
+        group by fund_id,price_date
+    </select>
+    <select id="selectMaxPriceDate" resultType="java.util.Date">
+        select max(price_date) from nav where channel_id = #{channelId} and fund_id = #{fundId} and isvalid=1
     </select>
 
 

+ 25 - 0
service-manage/src/main/java/com/simuwang/manage/init/CompleteScheduleConfig.java

@@ -54,6 +54,8 @@ public class CompleteScheduleConfig implements SchedulingConfigurer {
 
     @Autowired
     private ParseEmailFailTask parseEmailFailTask;
+    @Autowired
+    private SendDistributeDeletionEmailTask sendDistributeDeletionEmailTask;
     /**
      * 执行定时任务.
      */
@@ -236,6 +238,29 @@ public class CompleteScheduleConfig implements SchedulingConfigurer {
                     return new CronTrigger(cron).nextExecutionTime(triggerContext).toInstant();
                 }
         );
+
+        taskRegistrar.addTriggerTask(
+                //1.添加任务内容(Runnable)
+                () -> {
+                    try {
+                        logger.info("分红缺失邮件任务开始"+ DateUtils.getTime());
+                        sendDistributeDeletionEmailTask.sendEmail();
+                        logger.info("分红缺失邮件任务结束"+ DateUtils.getTime());
+                    } catch (Exception e) {
+                        logger.error("分红缺失邮件任务异常========="+e.getMessage()+"----" +DateUtils.getTime(),e);
+                    }
+                },
+                //2.设置执行周期(Trigger)
+                triggerContext -> {
+                    String cron = sysConfigMapper.selectConfigByKey("distribution_deletion_email_time");
+                    if(StringUtil.isEmpty(cron)){
+                        cron = "0 30 7 * * ?";
+                    }
+                    logger.info("分红缺失邮件定时任务执行时间:"+cron);
+                    //2.2 返回执行周期(Date)
+                    return new CronTrigger(cron).nextExecutionTime(triggerContext).toInstant();
+                }
+        );
     }
 
 }

+ 1 - 0
service-manage/src/main/java/com/simuwang/manage/service/CompanyEmailConfigService.java

@@ -24,4 +24,5 @@ public interface CompanyEmailConfigService {
 
     void sendEmail(String companyId, String emails);
 
+    void sendDistributeEmail(String companyId, String string);
 }

+ 248 - 6
service-manage/src/main/java/com/simuwang/manage/service/impl/CompanyEmailConfigServiceImpl.java

@@ -1,6 +1,7 @@
 package com.simuwang.manage.service.impl;
 
 import com.simuwang.base.common.enums.DeletionType;
+import com.simuwang.base.common.enums.Frequency;
 import com.simuwang.base.common.enums.OpenStatusType;
 import com.simuwang.base.common.enums.ResultCode;
 import com.simuwang.base.common.util.DateUtils;
@@ -9,9 +10,8 @@ import com.simuwang.base.common.util.ExcelUtil;
 import com.simuwang.base.common.util.StringUtil;
 import com.simuwang.base.mapper.daq.*;
 import com.simuwang.base.mapper.daq.system.SysConfigMapper;
-import com.simuwang.base.pojo.dos.CompanyEmailConfigDO;
-import com.simuwang.base.pojo.dos.CompanyEmailSendHistoryDO;
-import com.simuwang.base.pojo.dos.EmailDeletionInfoDO;
+import com.simuwang.base.pojo.dos.*;
+import com.simuwang.base.pojo.dto.EmailInfoDTO;
 import com.simuwang.base.pojo.dto.MailboxInfoDTO;
 import com.simuwang.base.pojo.vo.CompanyEmailConfigVO;
 import com.simuwang.manage.service.CompanyEmailConfigService;
@@ -50,6 +50,8 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
     private FundInfoMapper fundInfoMapper;
     @Autowired
     private DeletionInfoMapper deletionInfoMapper;
+    @Autowired
+    private DeletionTaskLogInfoMapper deletionTaskLogInfoMapper;
 
     @Autowired
     private SysConfigMapper sysConfigMapper;
@@ -58,6 +60,12 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
 
     @Value("${email.file.path}")
     private String path;
+    @Autowired
+    private FundReportFrequencyMapper fundReportFrequencyMapper;
+    @Autowired
+    private NavMapper navMapper;
+    @Autowired
+    private AssetMapper assetMapper;
 
     @Override
     public ResultVo saveCompanyEmailConfig(List<CompanyEmailConfigVO> companyEmailConfigVOS) {
@@ -149,9 +157,10 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
     //邮件校验处理
     public void sendEmail(String companyId, String emails) {
         List<String> fundIdList = fundInfoMapper.getFundIdByCompanyId(companyId);
-        List<EmailDeletionInfoDO> emailDeletionInfoDOS = deletionInfoMapper.selectDeletionInfoByFundId(fundIdList);
-        for(EmailDeletionInfoDO infoDO : emailDeletionInfoDOS){
-            infoDO.setDeletionType(DeletionType.getDeletionTypeByCode(Integer.valueOf(infoDO.getDeletionType())).getInfo());
+        List<EmailDeletionInfoDO> emailDeletionInfoDOS = new ArrayList<>();
+        for (String fundId : fundIdList) {
+            getNavDeletion(fundId,emailDeletionInfoDOS);
+            getAssetDeletion(fundId,emailDeletionInfoDOS);
         }
         if(emailDeletionInfoDOS.size() > 0){
             try {
@@ -182,6 +191,239 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
         }
     }
 
+    private void getNavDeletion(String fundId, List<EmailDeletionInfoDO> emailDeletionInfoDOS) {
+        List<EmailDeletionInfoDO> fundEmailDeletionInfoDOList = deletionInfoMapper.selectNavDeletionInfoByFundId(fundId);
+        if(fundEmailDeletionInfoDOList.isEmpty()){
+            return;
+        }
+        Map<Integer, List<EmailDeletionInfoDO>> channelDeletionMap = fundEmailDeletionInfoDOList.stream().collect(Collectors.groupingBy(EmailDeletionInfoDO::getChannelId));
+        FundReportFrequencyDO fundReportFrequencyDO = fundReportFrequencyMapper.getFrequencyByFundId(fundId);
+        if(fundReportFrequencyDO == null){
+            return;
+        }
+        for (Integer channelId : channelDeletionMap.keySet()) {
+            List<EmailDeletionInfoDO> channelEmailDeletionInfoDOList = channelDeletionMap.get(channelId);
+            if(channelEmailDeletionInfoDOList.isEmpty()){
+                continue;
+            }
+            //根据渠道ID和基金ID去查最新的净值日期
+            Date priceDate = navMapper.selectMaxPriceDate(channelId,fundId);
+            if(priceDate == null){
+                FundInfoDO fundInformationDO = fundInfoMapper.searchFundDetail(fundId);
+                if(fundInformationDO != null && fundInformationDO.getInceptionDate() == null){
+                    continue;
+                }
+                try{
+                    priceDate = DateUtils.parse(fundInformationDO.getInceptionDate(),"yyyy-MM-dd");
+                }catch (Exception e){
+                    logger.error(e.getMessage(),e);
+                }
+            }
+            if(Frequency.DAY.getCode().equals(fundReportFrequencyDO.getNavFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过五次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 5){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.NAV_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            if(Frequency.WEEK.getCode().equals(fundReportFrequencyDO.getNavFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过3次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 3){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.NAV_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            if(Frequency.MONTH.getCode().equals(fundReportFrequencyDO.getNavFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过1次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 1){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.NAV_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            for(EmailDeletionInfoDO infoDO : channelEmailDeletionInfoDOList){
+                infoDO.setDeletionType(DeletionType.getDeletionTypeByCode(Integer.valueOf(infoDO.getDeletionType())).getInfo());
+            }
+            emailDeletionInfoDOS.addAll(channelEmailDeletionInfoDOList);
+        }
+    }
+
+    private void getAssetDeletion(String fundId, List<EmailDeletionInfoDO> emailDeletionInfoDOS) {
+        List<EmailDeletionInfoDO> fundEmailDeletionInfoDOList = deletionInfoMapper.selectAssetDeletionInfoByFundId(fundId);
+        if(fundEmailDeletionInfoDOList.isEmpty()){
+            return;
+        }
+        Map<Integer, List<EmailDeletionInfoDO>> channelDeletionMap = fundEmailDeletionInfoDOList.stream().collect(Collectors.groupingBy(EmailDeletionInfoDO::getChannelId));
+        FundReportFrequencyDO fundReportFrequencyDO = fundReportFrequencyMapper.getFrequencyByFundId(fundId);
+        if(fundReportFrequencyDO == null){
+            return;
+        }
+        for (Integer channelId : channelDeletionMap.keySet()) {
+            List<EmailDeletionInfoDO> channelEmailDeletionInfoDOList = channelDeletionMap.get(channelId);
+            if(channelEmailDeletionInfoDOList.isEmpty()){
+                continue;
+            }
+            //根据渠道ID和基金ID去查最新的净值日期
+            Date priceDate = assetMapper.selectMaxPriceDate(channelId,fundId);
+            if(priceDate == null){
+                FundInfoDO fundInformationDO = fundInfoMapper.searchFundDetail(fundId);
+                if(fundInformationDO != null && fundInformationDO.getInceptionDate() == null){
+                    continue;
+                }
+                try{
+                    priceDate = DateUtils.parse(fundInformationDO.getInceptionDate(),"yyyy-MM-dd");
+                }catch (Exception e){
+                    logger.error(e.getMessage(),e);
+                }
+            }
+            if(Frequency.DAY.getCode().equals(fundReportFrequencyDO.getAssetFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过五次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 5){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.ASSET_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            if(Frequency.WEEK.getCode().equals(fundReportFrequencyDO.getAssetFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过3次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 3){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.ASSET_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            if(Frequency.MONTH.getCode().equals(fundReportFrequencyDO.getAssetFrequency())){
+                List<DeletionTaskLogInfoDO> deletionTaskLogInfoDOList = deletionTaskLogInfoMapper.selectDeletionTaskLogInfoDO(fundId,channelId,fundReportFrequencyDO.getNavFrequency(),DateUtils.format(priceDate,"yyyy-MM-dd"),DeletionType.NAV_DELETION.getCode());
+                //最新净值不再更新,超过1次就不再发送
+                if(deletionTaskLogInfoDOList.size() >= 1){
+                    continue;
+                }
+                DeletionTaskLogInfoDO deletionTaskLogInfoDO = new DeletionTaskLogInfoDO();
+                deletionTaskLogInfoDO.setChannelId(channelId);
+                deletionTaskLogInfoDO.setFundId(fundId);
+                deletionTaskLogInfoDO.setIsvalid(1);
+                deletionTaskLogInfoDO.setCreateTime(new Date());
+                deletionTaskLogInfoDO.setUpdateTime(new Date());
+                deletionTaskLogInfoDO.setPriceDate(DateUtils.format(priceDate,"yyyy-MM-dd"));
+                deletionTaskLogInfoDO.setFrequency(fundReportFrequencyDO.getNavFrequency());
+                deletionTaskLogInfoDO.setDeletionType(DeletionType.ASSET_DELETION.getCode());
+                deletionTaskLogInfoMapper.saveDeletionTaskLogInfoDO(deletionTaskLogInfoDO);
+            }
+            for(EmailDeletionInfoDO infoDO : channelEmailDeletionInfoDOList){
+                infoDO.setDeletionType(DeletionType.getDeletionTypeByCode(Integer.valueOf(infoDO.getDeletionType())).getInfo());
+            }
+            emailDeletionInfoDOS.addAll(channelEmailDeletionInfoDOList);
+        }
+    }
+    @Override
+    public void sendDistributeEmail(String companyId, String emails) {
+        List<String> fundIdList = fundInfoMapper.getFundIdByCompanyId(companyId);
+        List<EmailDeletionInfoDO> emailDeletionInfoDOS = new ArrayList<>();
+        for (String fundId : fundIdList) {
+            List<EmailDeletionInfoDO> distributeDeletionList = deletionInfoMapper.selectDistributeDeletionInfoByFundId(fundId);
+            if(distributeDeletionList.isEmpty()){
+                continue;
+            }
+            DistributeDeletionInfoDO distributeDeletionInfoDO = deletionInfoMapper.getDistributeDeletionInfo(fundId);
+            //查询第一次缺失日期,如果一样就不在发送,不一样才发生,同时更新最新的最小缺失日期
+            if(distributeDeletionInfoDO == null){
+                distributeDeletionInfoDO = new DistributeDeletionInfoDO();
+                distributeDeletionInfoDO.setFundId(fundId);
+                distributeDeletionInfoDO.setDeletionDate(distributeDeletionList.get(0).getDeletionDate());
+                distributeDeletionInfoDO.setIsvalid(1);
+                distributeDeletionInfoDO.setUpdateTime(new Date());
+                distributeDeletionInfoDO.setCreateTime(new Date());
+                deletionInfoMapper.saveDistributeFirstDeletion(distributeDeletionInfoDO);
+            }else{
+                String deletionDate = distributeDeletionInfoDO.getDeletionDate();
+                if(deletionDate.equals(distributeDeletionList.get(0).getDeletionDate())){
+                    continue;
+                }else{
+                    distributeDeletionInfoDO.setDeletionDate(distributeDeletionList.get(0).getDeletionDate());
+                    deletionInfoMapper.updateDistributeDeletionInfoDO(distributeDeletionInfoDO);
+                }
+            }
+            for(EmailDeletionInfoDO infoDO : distributeDeletionList){
+                infoDO.setDeletionType(DeletionType.getDeletionTypeByCode(Integer.valueOf(infoDO.getDeletionType())).getInfo());
+            }
+            emailDeletionInfoDOS.addAll(distributeDeletionList);
+        }
+        if(emailDeletionInfoDOS.size() > 0){
+            try {
+                //将数据写入excel文件
+                File file = writeExcelFile(emailDeletionInfoDOS);
+                file.setWritable(true);
+                file.setReadable(true);
+                file.setExecutable(true);
+                MailboxInfoDTO dto = getFromEmailInfo();
+                // "<p>您好,附件为产品的数据未发送到最新,麻烦尽快发送缺失的数据。若是产品清算或者有其他原因不再发送数据,还请将产品的清算日期或者不再发送数据的原因发送给我们,非常感谢~\n</p>";
+                String htmlText = sysConfigMapper.selectConfigByKey("deletion_distribute_email_body");
+                String emailTitle = sysConfigMapper.selectConfigByKey("deletion_distribute_email_title");
+                EmailUtil.senEmail(dto,emails,List.of(file),htmlText,sysConfigMapper.selectConfigByKey("email.host")==null?"":sysConfigMapper.selectConfigByKey("email.host"),emailTitle);
+                //发送成功之后修改数据为已发送
+                deletionInfoMapper.updateSendStatusByFundId(fundIdList);
+                //写入发送历史
+                String[] emailList = emails.split(";");
+                for(String email : emailList){
+                    saveCompanyEmailSendHistory(companyId,email,1,ResultCode.SEND_SUCCESS.getMsg());
+                }
+            } catch (Exception e) {
+                String[] emailList = emails.split(";");
+                for(String email : emailList){
+                    saveCompanyEmailSendHistory(companyId,email,0,e.getMessage());
+                }
+                logger.error(e.getMessage(),e);
+            }
+        }
+    }
+
 
     private void saveCompanyEmailSendHistory(String companyId, String email,Integer sendStatus,String msg) {
         CompanyEmailSendHistoryDO historyDO = new CompanyEmailSendHistoryDO();

+ 1 - 1
service-manage/src/main/java/com/simuwang/manage/task/SendCompanyEmailTask.java

@@ -51,7 +51,7 @@ public class SendCompanyEmailTask {
                 try{
                     String companyId = contactInformationDO.getCompanyId();
                     String email = contactInformationDO.getContactEmail();
-                    if(!companyIdEmailMap.containsKey(companyId)){
+                    if(companyIdEmailMap.containsKey(companyId)){
                         List<String> channelEmailList = companyIdEmailMap.get(companyId);
                         channelEmailList.add(email);
                         companyIdEmailMap.put(companyId,channelEmailList);

+ 112 - 0
service-manage/src/main/java/com/simuwang/manage/task/SendDistributeDeletionEmailTask.java

@@ -0,0 +1,112 @@
+package com.simuwang.manage.task;
+
+import com.simuwang.base.common.enums.TaskType;
+import com.simuwang.base.common.util.DateUtils;
+import com.simuwang.base.mapper.daq.ChannelEmailMapper;
+import com.simuwang.base.mapper.daq.ContactInformationMapper;
+import com.simuwang.base.mapper.daq.EmailTaskInfoMapper;
+import com.simuwang.base.pojo.dos.ContactInformationDO;
+import com.simuwang.base.pojo.dos.EmailTaskInfoDO;
+import com.simuwang.manage.service.CompanyEmailConfigService;
+import com.simuwang.shiro.utils.UserUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * FileName: SendCompanyEmailTask
+ * Author:   chenjianhua
+ * Date:     2024/9/20 22:45
+ * Description: ${DESCRIPTION}
+ */
+@Component
+public class SendDistributeDeletionEmailTask {
+    private static final Logger log = LoggerFactory.getLogger(SendDistributeDeletionEmailTask.class);
+    @Autowired
+    private ContactInformationMapper contactInformationMapper;
+    @Autowired
+    private CompanyEmailConfigService companyEmailConfigService;
+    @Autowired
+    private EmailTaskInfoMapper emailTaskInfoMapper;
+    public void sendEmail(){
+        EmailTaskInfoDO emailTaskInfoDO = startEmailTask(null, 1);
+        try{
+            List<ContactInformationDO> contactInformationDOList = contactInformationMapper.getAllRecords();
+            Map<String,List<String>> companyIdEmailMap = new HashMap<>();
+            //按渠道分组
+            for (ContactInformationDO contactInformationDO : contactInformationDOList) {
+                try{
+                    String companyId = contactInformationDO.getCompanyId();
+                    String email = contactInformationDO.getContactEmail();
+                    if(companyIdEmailMap.containsKey(companyId)){
+                        List<String> channelEmailList = companyIdEmailMap.get(companyId);
+                        channelEmailList.add(email);
+                        companyIdEmailMap.put(companyId,channelEmailList);
+                    }else{
+                        List<String> channelEmailList = new ArrayList<>();
+                        channelEmailList.add(email);
+                        companyIdEmailMap.put(companyId,channelEmailList);
+                    }
+                }catch (Exception e){
+                    log.error(e.getMessage(),e);
+                }
+            }
+            for(String companyId : companyIdEmailMap.keySet()){
+                List<String> emailList = companyIdEmailMap.get(companyId);
+                StringBuffer emails = new StringBuffer();
+                for(String email : emailList){
+                    emails.append(email).append(";");
+                }
+                companyEmailConfigService.sendDistributeEmail(companyId,emails.toString());
+            }
+        }catch (Exception e){
+            log.error(e.getMessage(),e);
+            endEmailTask(emailTaskInfoDO.getId(),-1);
+            return;
+        }
+        endEmailTask(emailTaskInfoDO.getId(),2);
+    }
+    private void endEmailTask(Integer id, Integer taskStatus) {
+        try{
+            EmailTaskInfoDO emailTaskInfoDO = new EmailTaskInfoDO();
+            emailTaskInfoDO.setId(id);
+            emailTaskInfoDO.setTaskStatus(taskStatus);
+            emailTaskInfoDO.setUpdateTime(DateUtils.getNowDate());
+            emailTaskInfoDO.setEndTime(DateUtils.getNowDate());
+            emailTaskInfoMapper.updateTaskStatusById(emailTaskInfoDO);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+    }
+
+    private EmailTaskInfoDO startEmailTask(String email,Integer taskStatus) {
+        EmailTaskInfoDO  emailTaskInfoDO = new EmailTaskInfoDO();
+        try{
+            emailTaskInfoDO.setTaskName(TaskType.DELETION_NOTIFICATIONS.getInfo());
+            emailTaskInfoDO.setTaskType(TaskType.DELETION_NOTIFICATIONS.getType());
+            emailTaskInfoDO.setTaskStatus(taskStatus);
+            emailTaskInfoDO.setStartTime(DateUtils.getNowDate());
+            emailTaskInfoDO.setIsvalid(1);
+            emailTaskInfoDO.setEmail(email);
+            emailTaskInfoDO.setCreateTime(DateUtils.getNowDate());
+            emailTaskInfoDO.setUpdateTime(DateUtils.getNowDate());
+            try{
+                emailTaskInfoDO.setCreatorId(UserUtils.getLoginUser().getUserId());
+                emailTaskInfoDO.setUpdaterId(UserUtils.getLoginUser().getUserId());
+            }catch (Exception e){
+                emailTaskInfoDO.setCreatorId(1);
+                emailTaskInfoDO.setUpdaterId(1);
+            }
+            emailTaskInfoMapper.insert(emailTaskInfoDO);
+        }catch (Exception e){
+            log.error(e.getMessage());
+        }
+        return emailTaskInfoDO;
+    }
+}