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

Merge branch 'develop' of http://112.74.196.215:3000/Tech2/data-daq into develop

wangzaijun преди 7 месеца
родител
ревизия
d0901c97ae
променени са 37 файла, в които са добавени 1009 реда и са изтрити 79 реда
  1. 8 0
      service-base/src/main/java/com/simuwang/base/common/conts/EmailFieldConst.java
  2. 15 0
      service-base/src/main/java/com/simuwang/base/common/conts/EmailParseStatusConst.java
  3. 30 0
      service-base/src/main/java/com/simuwang/base/common/conts/NavParseStatusConst.java
  4. 4 4
      service-base/src/main/java/com/simuwang/base/common/util/EmailUtil.java
  5. 47 0
      service-base/src/main/java/com/simuwang/base/common/util/ExcelUtil.java
  6. 8 1
      service-base/src/main/java/com/simuwang/base/common/util/StringUtil.java
  7. 3 0
      service-base/src/main/java/com/simuwang/base/config/ShiroConfig.java
  8. 6 0
      service-base/src/main/java/com/simuwang/base/mapper/CompanyEmailConfigMapper.java
  9. 12 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailFileInfoMapper.java
  10. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailFundAssetMapper.java
  11. 14 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailFundNavMapper.java
  12. 13 0
      service-base/src/main/java/com/simuwang/base/mapper/EmailParseInfoMapper.java
  13. 16 0
      service-base/src/main/java/com/simuwang/base/mapper/FundAliasMapper.java
  14. 6 0
      service-base/src/main/java/com/simuwang/base/mapper/FundInfomationMapper.java
  15. 5 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFileInfoDO.java
  16. 5 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundAssetDO.java
  17. 9 4
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundNavDO.java
  18. 2 2
      service-base/src/main/java/com/simuwang/base/pojo/dos/EmailParseInfoDO.java
  19. 68 0
      service-base/src/main/java/com/simuwang/base/pojo/dos/FundAliasDO.java
  20. 10 0
      service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFundNavDTO.java
  21. 1 0
      service-base/src/main/java/com/simuwang/base/pojo/vo/CompanyEmailConfigVO.java
  22. 65 0
      service-base/src/main/resources/mapper/CompanyEmailConfigMapper.xml
  23. 7 6
      service-base/src/main/resources/mapper/CompanyEmailHistoryMapper.xml
  24. 3 3
      service-base/src/main/resources/mapper/CompanyInformationMapper.xml
  25. 25 0
      service-base/src/main/resources/mapper/EmailFileInfoMapper.xml
  26. 32 0
      service-base/src/main/resources/mapper/EmailFundAssetMapper.xml
  27. 36 0
      service-base/src/main/resources/mapper/EmailFundNavMapper.xml
  28. 33 0
      service-base/src/main/resources/mapper/EmailParseInfoMapper.xml
  29. 41 0
      service-base/src/main/resources/mapper/FundAliasMapper.xml
  30. 22 0
      service-base/src/main/resources/mapper/FundInformationMapper.xml
  31. 1 1
      service-base/src/main/resources/mapper/system/SysConfigMapper.xml
  32. 25 0
      service-daq/src/main/java/com/simuwang/daq/service/AbstractEmailParser.java
  33. 278 14
      service-daq/src/main/java/com/simuwang/daq/service/EmailParseService.java
  34. 135 34
      service-daq/src/main/java/com/simuwang/daq/service/NavEmailParser.java
  35. 4 4
      service-deploy/src/main/test/java/com/simuwang/datadaq/DataTrusteeApplicationTests.java
  36. 2 2
      service-manage/src/main/java/com/simuwang/manage/api/company/CompanyEmailSendHistoryController.java
  37. 4 4
      service-manage/src/main/java/com/simuwang/manage/service/impl/CompanyEmailConfigServiceImpl.java

+ 8 - 0
service-base/src/main/java/com/simuwang/base/common/conts/EmailFieldConst.java

@@ -11,4 +11,12 @@ public class EmailFieldConst {
     public final static String ASSET_SHARE = "assetShare";
     public final static String ASSET_NET = "assetNet";
 
+    public final static String PARENT_FUND_NAME = "parentFundName";
+    public final static String PARENT_REGISTER_NUMBER = "parentRegisterNumber";
+    public final static String PARENT_NAV = "parentNav";
+    public final static String PARENT_CUMULATIVE_NAV_WITHDRAWAL = "parentCumulativeNavWithdrawal";
+    public final static String PARENT_VIRTUAL_NAV = "parentVirtualNav";
+    public final static String PARENT_ASSET_SHARE = "parentAssetShare";
+    public final static String PARENT_ASSET_NET = "parentAssetNet";
+
 }

+ 15 - 0
service-base/src/main/java/com/simuwang/base/common/conts/EmailParseStatusConst.java

@@ -0,0 +1,15 @@
+package com.simuwang.base.common.conts;
+
+public class EmailParseStatusConst {
+
+    /**
+     * 成功
+     */
+    public final static Integer SUCCESS = 1;
+
+    /**
+     * 失败
+     */
+    public final static Integer FAIL = 2;
+
+}

+ 30 - 0
service-base/src/main/java/com/simuwang/base/common/conts/NavParseStatusConst.java

@@ -0,0 +1,30 @@
+package com.simuwang.base.common.conts;
+
+public class NavParseStatusConst {
+
+    /**
+     * 成功
+     */
+    public final static Integer SUCCESS = 1;
+
+    /**
+     * 净值缺失
+     */
+    public final static Integer NAV_DEFICIENCY = 2;
+
+    /**
+     * 未匹配基金
+     */
+    public final static Integer NOT_MATCH = 3;
+
+    /**
+     * 净值不大于0
+     */
+    public final static Integer NAV_NEGATIVE = 4;
+
+    /**
+     * 资产净值不大于0
+     */
+    public final static Integer ASSET_NET_NEGATIVE = 5;
+
+}

+ 4 - 4
service-base/src/main/java/com/simuwang/base/common/util/EmailUtil.java

@@ -67,7 +67,7 @@ public class EmailUtil {
                 emailContentInfoDTO = collectTextPart(part, partContent, filePath, fileName);
             } else if ("BASE64DecoderStream".equals(contentClass)) {
                 if (StrUtil.isNotBlank(part.getFileName())) {
-                    String fileName = emailDate + MimeUtility.decodeText(part.getFileName());
+                    String fileName = MimeUtility.decodeText(part.getFileName());
                     emailContentInfoDTO.setFileName(fileName);
 
                     File savefile = new File(filePath + fileName);
@@ -101,7 +101,7 @@ public class EmailUtil {
             }
             emailContentInfoDTO.setEmailAddress(emailAddress);
             emailContentInfoDTO.setEmailTitle(emailTitle);
-            emailContentInfoDTO.setEmailDate((emailDate));
+            emailContentInfoDTO.setEmailDate(DateUtil.format(message.getSentDate(), DateConst.YYYY_MM_DD_HH_MM_SS));
             emailContentInfoDTOList.add(emailContentInfoDTO);
         }
 
@@ -158,9 +158,9 @@ public class EmailUtil {
                             savefile.getParentFile().setExecutable(true);
                         }
                         FileUtil.writeFile(savePath, partContent.toString());
-                        emailContentInfoDTO.setFileName(fileName);
-                        emailContentInfoDTO.setFilePath(savePath);
                     }
+                    emailContentInfoDTO.setFileName(fileName);
+                    emailContentInfoDTO.setFilePath(savePath);
                 }
             }
         } catch (MessagingException e) {

+ 47 - 0
service-base/src/main/java/com/simuwang/base/common/util/ExcelUtil.java

@@ -2,6 +2,7 @@ package com.simuwang.base.common.util;
 
 import cn.hutool.core.util.StrUtil;
 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Sheet;
 import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
@@ -9,6 +10,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.*;
+import java.text.NumberFormat;
 
 public class ExcelUtil {
 
@@ -133,4 +135,49 @@ public class ExcelUtil {
             return null;
         }
     }
+
+    public static String getCellValue(Cell cell) {
+        if (cell == null) {
+            return null;
+        }
+        String cellValue = "";
+
+        switch (cell.getCellTypeEnum()) {
+            case STRING:
+                cellValue = cell.getStringCellValue();
+                break;
+            case NUMERIC:
+                if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
+                    // 如果是日期格式的数字
+                    cellValue = cell.getDateCellValue().toString();
+                } else {
+                    // 否则是纯数字
+                    NumberFormat numberFormat = NumberFormat.getNumberInstance();
+                    numberFormat.setMaximumFractionDigits(15);
+                    double formulaResult = cell.getNumericCellValue();
+                    cellValue = numberFormat.format(formulaResult).replaceAll(",","");
+                }
+                break;
+            case BOOLEAN:
+                cellValue = String.valueOf(cell.getBooleanCellValue());
+                break;
+            case FORMULA:
+                // 处理公式结果
+                try {
+                    cellValue = String.valueOf(cell.getNumericCellValue());
+                } catch (IllegalStateException e) {
+                    cellValue = cell.getStringCellValue();
+                }
+                break;
+            case BLANK:
+                break;
+            case ERROR:
+                cellValue = "ERROR: " + cell.getErrorCellValue();
+                break;
+            default:
+                cellValue = "";
+                break;
+        }
+        return cellValue;
+    }
 }

+ 8 - 1
service-base/src/main/java/com/simuwang/base/common/util/StringUtil.java

@@ -48,12 +48,19 @@ public class StringUtil {
                 sdf.parse(dateString);
                 return true;
             } catch (Exception e) {
-                e.printStackTrace();
+                return false;
             }
         }
         return false;
     }
 
+    public static boolean isNumeric(String value) {
+        if (StrUtil.isBlank(value)) {
+            return false;
+        }
+        return value.matches("^[-+]?[0-9]*\\.?[0-9]+$");
+    }
+
 
     /**
      * 获取参数不为空值

+ 3 - 0
service-base/src/main/java/com/simuwang/base/config/ShiroConfig.java

@@ -146,6 +146,9 @@ public class ShiroConfig {
         map.put("/v1/login", "anon");
         map.put("/v1/rsa-key", "anon");
         map.put("/test/**", "anon");
+        map.put("/company/**", "anon");
+        map.put("/fund/**", "anon");
+        map.put("/email/**", "anon");
         map.put("/v1/**", "jwt");
         map.put("/**", "jwt");
         return map;

+ 6 - 0
service-base/src/main/java/com/simuwang/base/mapper/CompanyEmailConfigMapper.java

@@ -13,4 +13,10 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface CompanyEmailConfigMapper extends BaseMapper<CompanyEmailConfigDO> {
     void deleteCompanyEmailConfig(String email);
+
+    void saveCompanyEmailConfig(CompanyEmailConfigDO emailConfigDO);
+
+    void updateCompanyEmailConfig(CompanyEmailConfigDO emailConfigDO);
+
+    CompanyEmailConfigDO selectCompanyEmailConfigById(Integer id);
 }

+ 12 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailFileInfoMapper.java

@@ -0,0 +1,12 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.EmailFileInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface EmailFileInfoMapper {
+
+    Integer insert(@Param("itemDo") EmailFileInfoDO emailFileInfoDO);
+
+}

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailFundAssetMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.EmailFundAssetDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface EmailFundAssetMapper {
+
+    void batchInsert(@Param("itemDoList") List<EmailFundAssetDO> emailFundAssetDOList);
+
+}

+ 14 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailFundNavMapper.java

@@ -0,0 +1,14 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.EmailFundNavDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface EmailFundNavMapper {
+
+    void batchInsert(@Param("itemDoList") List<EmailFundNavDO> emailFundNavDOList);
+
+}

+ 13 - 0
service-base/src/main/java/com/simuwang/base/mapper/EmailParseInfoMapper.java

@@ -0,0 +1,13 @@
+package com.simuwang.base.mapper;
+
+import com.simuwang.base.pojo.dos.EmailParseInfoDO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+@Mapper
+public interface EmailParseInfoMapper {
+
+    Integer insert(@Param("itemDo") EmailParseInfoDO emailParseInfoDO);
+
+    void updateParseStatus(@Param("id") Integer id, @Param("parseStatus") int parseStatus);
+}

+ 16 - 0
service-base/src/main/java/com/simuwang/base/mapper/FundAliasMapper.java

@@ -0,0 +1,16 @@
+package com.simuwang.base.mapper;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+@Mapper
+public interface FundAliasMapper {
+
+    List<String> queryFundByNameAndRegisterNumber(@Param("fundName") String fundName, @Param("registerNumber") String registerNumber);
+
+    List<String> queryFundByName(@Param("fundName") String fundName);
+
+    List<String> queryFundByRegisterNumber(@Param("registerNumber") String registerNumber);
+}

+ 6 - 0
service-base/src/main/java/com/simuwang/base/mapper/FundInfomationMapper.java

@@ -21,4 +21,10 @@ public interface FundInfomationMapper {
                                                @Param("companyName") String companyName, @Param("navFrequency") Integer navFrequency,
                                                @Param("assetFrequency") Integer assetFrequency,@Param("startDate") Integer startDate,
                                                @Param("endDate")Integer endDate);
+
+    List<String> queryFundByNameAndRegisterNumber(@Param("fundName")String fundName, @Param("registerNumber")String registerNumber);
+
+    List<String> queryFundByName(@Param("fundName") String fundName);
+
+    List<String> queryFundByRegisterNumber(@Param("registerNumber") String registerNumber);
 }

+ 5 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFileInfoDO.java

@@ -21,6 +21,11 @@ public class EmailFileInfoDO {
     @TableField(value = "email_id")
     private Integer emailId;
     /**
+     * 基金id
+     */
+    @TableField(value = "fund_id")
+    private Integer fundId;
+    /**
      * 附件名称
      */
     @TableField(value = "file_name")

+ 5 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundAssetDO.java

@@ -17,6 +17,11 @@ public class EmailFundAssetDO {
     @TableId(value = "id")
     private Integer id;
     /**
+     * 文件id(email_file_info.id)
+     */
+    @TableField(value = "file_id")
+    private Integer fileId;
+    /**
      * 基金id
      */
     @TableField(value = "fund_id")

+ 9 - 4
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailFundNavDO.java

@@ -17,10 +17,15 @@ public class EmailFundNavDO {
     @TableId(value = "id")
     private Integer id;
     /**
-     * 邮件id(email_parse_info.id)
+     * 邮件id(email_file_info.id)
      */
-    @TableField(value = "email_id")
-    private Integer emailId;
+    @TableField(value = "file_id")
+    private Integer fileId;
+    /**
+     * 基金id
+     */
+    @TableField(value = "fund_id")
+    private String fundId;
     /**
      * 邮件解析的基金名称
      */
@@ -45,7 +50,7 @@ public class EmailFundNavDO {
      * 累计单位净值
      */
     @TableField(value = "cumulative_nav")
-    private BigDecimal cumulativeNav;
+    private BigDecimal cumulativeNavWithdrawal;
     /**
      * 是否入库 0-没有,1-有
      */

+ 2 - 2
service-base/src/main/java/com/simuwang/base/pojo/dos/EmailParseInfoDO.java

@@ -24,12 +24,12 @@ public class EmailParseInfoDO {
      * 邮箱日期
      */
     @TableField(value = "email_date")
-    private String emailDate;
+    private Date emailDate;
     /**
      * 解析日期
      */
     @TableField(value = "parse_date")
-    private String parseDate;
+    private Date parseDate;
     /**
      * 邮件主题
      */

+ 68 - 0
service-base/src/main/java/com/simuwang/base/pojo/dos/FundAliasDO.java

@@ -0,0 +1,68 @@
+package com.simuwang.base.pojo.dos;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("fund_alias")
+public class FundAliasDO {
+    /**
+     * 主键Id
+     */
+    @TableId(value = "id")
+    private Integer id;
+    /**
+     * 邮件解析基金名称
+     */
+    @TableField(value = "source_fund_name")
+    private String sourceFundName;
+    /**
+     * 邮件解析基金的备案编码
+     */
+    @TableField(value = "source_register_number")
+    private String sourceRegisterNumber;
+    /**
+     * 匹配的源数据基金名称
+     */
+    @TableField(value = "target_fund_name")
+    private String targetFundName;
+    /**
+     * 匹配的源基金ID
+     */
+    @TableField(value = "target_fund_id")
+    private String targetFundId;
+    /**
+     * 匹配的源备案编码
+     */
+    @TableField(value = "target_register_number")
+    private String targetRegisterNumber;
+    /**
+     * 记录的有效性;1-有效;0-无效;
+     */
+    @TableField(value = "isvalid")
+    private Integer isvalid;
+    /**
+     * 创建者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+     */
+    @TableField(value = "creatorid")
+    private Integer creatorId;
+    /**
+     * 修改者Id;第一次创建时与Creator值相同,修改时与修改人值相同
+     */
+    @TableField(value = "updaterid")
+    private Integer updaterId;
+    /**
+     * 创建时间,默认第一次创建的getdate()时间
+     */
+    @TableField(value = "createtime")
+    private Date createTime;
+    /**
+     * 修改时间;第一次创建时与CreatTime值相同,修改时与修改时间相同
+     */
+    @TableField(value = "updatetime")
+    private Date updateTime;
+}

+ 10 - 0
service-base/src/main/java/com/simuwang/base/pojo/dto/EmailFundNavDTO.java

@@ -2,6 +2,8 @@ package com.simuwang.base.pojo.dto;
 
 import lombok.Data;
 
+import java.util.List;
+
 @Data
 public class EmailFundNavDTO {
     /**
@@ -36,4 +38,12 @@ public class EmailFundNavDTO {
      * 资产净值(基金规模)
      */
     private String assetNet;
+    /**
+     * 匹配上的基金id
+     */
+    private List<String> fundIdList;
+    /**
+     * 解析状态:1-成功,2-净值缺失,3-未匹配基金,4-净值<=0,5-资产净值<=0
+     */
+    private Integer parseStatus;
 }

+ 1 - 0
service-base/src/main/java/com/simuwang/base/pojo/vo/CompanyEmailConfigVO.java

@@ -15,6 +15,7 @@ import java.util.Date;
  * Description: ${DESCRIPTION}
  */
 @Data
+@TableName("company_email_config")
 public class CompanyEmailConfigVO {
     /**
      * ID

+ 65 - 0
service-base/src/main/resources/mapper/CompanyEmailConfigMapper.xml

@@ -1,8 +1,73 @@
 <?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.CompanyEmailConfigMapper">
+    <insert id="saveCompanyEmailConfig">
+        insert into PPW_EMAIL.company_email_config(
+        <if test="companyId != null and companyId != ''">company_id,</if>
+        <if test="companyName != null and companyName != ''">company_name,</if>
+        <if test="email != null and email != ''">email,</if>
+        <if test="openStatus != null and openStatus != ''">open_status,</if>
+        <if test="creatorId != null and creatorId != ''">creatorid,</if>
+        <if test="updaterId != null and updaterId != ''">updaterId,</if>
+        isvalid,
+        createtime,
+        updatetime
+        )values(
+        <if test="companyId != null and companyId != ''">#{companyId},</if>
+        <if test="companyName != null and companyName != ''">#{companyName},</if>
+        <if test="email != null and email != ''">#{email},</if>
+        <if test="openStatus != null and openStatus != ''">#{openStatus},</if>
+        <if test="creatorId != null and creatorId != ''">#{creatorId},</if>
+        <if test="updaterId != null and updaterId != ''">#{updaterId},</if>
+        1,
+        sysdate(),
+        sysdate()
+        )
+    </insert>
+
+    <update id="updateCompanyEmailConfig">
+        update PPW_EMAIL.company_email_config
+        <set>
+            <if test="companyId != null and companyId != ''">company_id=#{companyId},</if>
+            <if test="companyName != null and companyName != ''">company_name=#{companyName},</if>
+            <if test="email != null and email != ''">email=#{email},</if>
+            <if test="openStatus != null and openStatus != ''">open_status=#{openStatus},</if>
+            <if test="updaterId != null and updaterId != ''">updaterid=#{updaterId},</if>
+            <if test="updateTime != null">updatetime=#{updateTime},</if>
+        </set>
+        where id = #{id} and isvalid=1
+    </update>
 
     <update id="deleteCompanyEmailConfig">
         update PPW_EMAIL.company_email_config set isvalid =0 where email=#{email}
     </update>
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.CompanyEmailConfigDO">
+        <id column="id" property="id"/>
+        <result column="company_id" property="companyId"/>
+        <result column="company_name" property="companyName"/>
+        <result column="email" property="email"/>
+        <result column="open_status" property="openStatus"/>
+        <result column="creatorid" property="creatorId"/>
+        <result column="updaterid" property="updaterId"/>
+        <result column="createtime" property="createTime"/>
+        <result column="updatetime" property="updateTime"/>
+        <result column="isvalid" property="isvalid"/>
+    </resultMap>
+    <sql id="selectConfigDo">
+        select company_id, company_name, email, open_status, creatorid, createtime, updaterid, updatetime,isvalid
+        from PPW_EMAIL.company_email_config
+    </sql>
+    <!-- 查询条件 -->
+    <sql id="sqlwhereSearch">
+        <where>
+            isvalid=1
+            <if test="id !=null">
+                and id = #{id}
+            </if>
+        </where>
+    </sql>
+    <select id="selectCompanyEmailConfigById" resultMap="BaseResultMap">
+        <include refid="selectConfigDo"/>
+        <include refid="sqlwhereSearch"/>
+    </select>
 </mapper>

+ 7 - 6
service-base/src/main/resources/mapper/CompanyEmailHistoryMapper.xml

@@ -11,10 +11,10 @@
         <result column="send_remark" property="sendRemark"/>
     </resultMap>
     <update id="deleteEmailHistory">
-        update company_email_send_history set isvalid =0,updatetime=sysdate() where email=#{email}
+        update PPW_EMAIL.company_email_send_history set isvalid =0,updatetime=sysdate() where email=#{email}
     </update>
     <update id="deleteEmailHistoryByIds">
-        update company_email_send_history set isvalid =0,updatetime=sysdate() where id in
+        update PPW_EMAIL.company_email_send_history set isvalid =0,updatetime=sysdate() where id in
         <foreach item="id" collection="ids" open="(" separator="," close=")">
             #{id}
         </foreach>
@@ -34,9 +34,8 @@
                 JOIN PPW_EMAIL.company_information c
                      ON cec.company_id = c.company_id
                 LEFT JOIN PPW_EMAIL.company_email_send_history cesh
-                     ON cec.email = cesh.email
-        WHERE cec.isvalid = 1
-          AND cesh.isvalid = 1 and c.isvalid=1
+                     ON cec.email = cesh.email AND cesh.isvalid = 1
+        WHERE cec.isvalid = 1 and c.isvalid=1
         <if test="companyName != null and companyName !=''">
             and (c.company_name like concat('',#{companyName},'') or c.company_short_name like concat('',#{companyName},''))
         </if>
@@ -59,9 +58,11 @@
         FROM
             PPW_EMAIL.company_email_send_history cesh
             JOIN PPW_EMAIL.company_email_config cec
+            JOIN PPW_EMAIL.company_information c
+            ON cec.company_id = c.company_id
             ON cec.email = cesh.email
         WHERE cec.isvalid = 1
-        AND cesh.isvalid = 1
+        AND cesh.isvalid = 1 and c.isvalid =1
         <if test="email != null and email !=''">
             and cec.email=#{email}
         </if>

+ 3 - 3
service-base/src/main/resources/mapper/CompanyInformationMapper.xml

@@ -41,9 +41,9 @@
         <result column="isvalid" property="isvalid"/>
     </resultMap>
     <select id="searchCompanyInfoByKeyword" resultType="java.util.Map" parameterType="java.lang.String">
-        select c.company_id as companyId,
-        c.company_name as companyName
-        c.register_number as registerNumber
+        select c.company_id as `companyId`,
+        c.company_name as `companyName`,
+        c.register_number as `registerNumber`
         from PPW_EMAIL.company_information c where c.isvalid =1
         <if test="keyword != null and keyword !=''">
             and (c.company_name like concat('%',#{keyword},'%') or c.company_short_name like concat('%',#{keyword},'%') or c.register_number like concat('%',#{keyword},'%'))

+ 25 - 0
service-base/src/main/resources/mapper/EmailFileInfoMapper.xml

@@ -0,0 +1,25 @@
+<?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.EmailFileInfoMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.EmailFileInfoDO">
+        <id column="id" property="id"/>
+        <result column="email_id" property="emailId"/>
+        <result column="file_name" property="fileName"/>
+        <result column="file_path" property="filePath"/>
+        <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="insert" parameterType="com.simuwang.base.pojo.dos.EmailFileInfoDO" useGeneratedKeys="true"
+            keyProperty="id" keyColumn="id">
+        insert into PPW_EMAIL.email_file_info(email_id, file_name, file_path,
+                                              isvalid, creatorid, createtime, updaterid, updatetime)
+        values (#{itemDo.emailId}, #{itemDo.fileName}, #{itemDo.filePath},
+                #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+    </insert>
+
+
+</mapper>

+ 32 - 0
service-base/src/main/resources/mapper/EmailFundAssetMapper.xml

@@ -0,0 +1,32 @@
+<?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.EmailFundAssetMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.EmailFundAssetDO">
+        <id column="id" property="id"/>
+        <result column="file_id" property="fileId"/>
+        <result column="fund_id" property="fundId"/>
+        <result column="fund_name" property="fundName"/>
+        <result column="register_number" property="registerNumber"/>
+        <result column="price_date" property="priceDate"/>
+        <result column="asset_net" property="assetNet"/>
+        <result column="asset_share" property="assetShare"/>
+        <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="batchInsert" parameterType="com.simuwang.base.pojo.dos.EmailFundAssetDO">
+        insert into PPW_EMAIL.email_fund_asset(file_id, fund_id, fund_name,register_number,price_date,asset_net,asset_share,
+                                              isvalid, creatorid, createtime, updaterid, updatetime)
+        values
+        <foreach collection="itemDoList" item="itemDo" index="index" separator=",">
+            (#{itemDo.fileId},#{itemDo.fundId},#{itemDo.fundName},#{itemDo.registerNumber},#{itemDo.priceDate},#{itemDo.assetNet},#{itemDo.assetShare},
+            #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+
+    </insert>
+
+
+</mapper>

+ 36 - 0
service-base/src/main/resources/mapper/EmailFundNavMapper.xml

@@ -0,0 +1,36 @@
+<?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.EmailFundNavMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.EmailFundNavDO">
+        <id column="id" property="id"/>
+        <result column="file_id" property="fileId"/>
+        <result column="fund_id" property="fundId"/>
+        <result column="fund_name" property="fundName"/>
+        <result column="register_number" property="registerNumber"/>
+        <result column="price_date" property="priceDate"/>
+        <result column="nav" property="nav"/>
+        <result column="cumulative_nav_withdrawal" property="cumulativeNavWithdrawal"/>
+        <result column="is_stored" property="isStored"/>
+        <result column="exception_status" property="exceptionStatus"/>
+        <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="batchInsert" parameterType="com.simuwang.base.pojo.dos.EmailFundNavDO">
+        insert into PPW_EMAIL.email_fund_nav(file_id, fund_id, fund_name,register_number,price_date,
+                                              nav,cumulative_nav_withdrawal,is_stored,exception_status,
+                                              isvalid, creatorid, createtime, updaterid, updatetime)
+        values
+        <foreach collection="itemDoList" item="itemDo" index="index" separator=",">
+            (#{itemDo.fileId},#{itemDo.fundId},#{itemDo.fundName},#{itemDo.registerNumber},#{itemDo.priceDate},
+             #{itemDo.nav},#{itemDo.cumulativeNavWithdrawal},#{itemDo.isStored},#{itemDo.exceptionStatus},
+            #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+        </foreach>
+
+    </insert>
+
+
+</mapper>

+ 33 - 0
service-base/src/main/resources/mapper/EmailParseInfoMapper.xml

@@ -0,0 +1,33 @@
+<?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.EmailParseInfoMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.EmailParseInfoDO">
+        <id column="id" property="id"/>
+        <result column="email" property="email"/>
+        <result column="email_date" property="emailDate" />
+        <result column="parse_date" property="parseDate" />
+        <result column="email_title" property="emailTitle"/>
+        <result column="email_type" property="emailType"/>
+        <result column="parse_status" property="parseStatus"/>
+        <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="insert" parameterType="com.simuwang.base.pojo.dos.EmailParseInfoDO" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
+        insert into PPW_EMAIL.email_parse_info(email, email_date, parse_date, email_title, email_type, parse_status,
+                                     isvalid, creatorid, createtime, updaterid, updatetime)
+        values (#{itemDo.email}, #{itemDo.emailDate}, #{itemDo.parseDate}, #{itemDo.emailTitle}, #{itemDo.emailType}, #{itemDo.parseStatus},
+                #{itemDo.isvalid}, #{itemDo.creatorId}, #{itemDo.createTime}, #{itemDo.updaterId}, #{itemDo.updateTime})
+    </insert>
+
+    <update id="updateParseStatus">
+        update PPW_EMAIL.email_parse_info
+        set parse_status = #{parseStatus}
+        where isvalid = 1
+          and id = #{id}
+    </update>
+
+</mapper>

+ 41 - 0
service-base/src/main/resources/mapper/FundAliasMapper.xml

@@ -0,0 +1,41 @@
+<?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.FundAliasMapper">
+    <resultMap id="BaseResultMap" type="com.simuwang.base.pojo.dos.FundAliasDO">
+        <id column="id" property="id"/>
+        <result column="source_fund_name" property="sourceFundName"/>
+        <result column="source_register_number" property="sourceRegisterNumber"/>
+        <result column="target_fund_id" property="targetFundId"/>
+        <result column="target_fund_name" property="targetFundName"/>
+        <result column="target_register_number" property="targetRegisterNumber"/>
+        <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>
+
+
+    <select id="queryFundByNameAndRegisterNumber" resultType="java.lang.String">
+        select target_fund_id
+        from PPW_EMAIL.fund_alias
+        where isvalid = 1
+          and source_fund_name = #{fundName}
+          and source_register_number = #{registerNumber}
+    </select>
+
+    <select id="queryFundByName" resultType="java.lang.String">
+        select target_fund_id
+        from PPW_EMAIL.fund_alias
+        where isvalid = 1
+          and source_fund_name = #{fundName}
+    </select>
+
+    <select id="queryFundByRegisterNumber" resultType="java.lang.String">
+        select target_fund_id
+        from PPW_EMAIL.fund_alias
+        where isvalid = 1
+          and source_register_number = #{registerNumber}
+    </select>
+
+</mapper>

+ 22 - 0
service-base/src/main/resources/mapper/FundInformationMapper.xml

@@ -74,4 +74,26 @@
         </if>
     </select>
 
+    <select id="queryFundByNameAndRegisterNumber" resultType="java.lang.String">
+        select fund_id
+        from PPW_EMAIL.fund_information
+        where isvalid = 1
+          and fund_name = #{fundName}
+          and register_number = #{registerNumber}
+    </select>
+
+    <select id="queryFundByName" resultType="java.lang.String">
+        select fund_id
+        from PPW_EMAIL.fund_information
+        where isvalid = 1
+          and fund_name = #{fundName}
+    </select>
+
+    <select id="queryFundByRegisterNumber" resultType="java.lang.String">
+        select fund_id
+        from PPW_EMAIL.fund_information
+        where isvalid = 1
+          and register_number = #{registerNumber}
+    </select>
+
 </mapper>

+ 1 - 1
service-base/src/main/resources/mapper/system/SysConfigMapper.xml

@@ -19,7 +19,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     
     <sql id="selectConfigDo">
         select config_id, config_name, config_key, config_value, config_type, creatorid, createtime, updaterid, updatetime, remark,isvalid
-		from sys_config
+		from PPW_EMAIL.sys_config
     </sql>
     
     <!-- 查询条件 -->

+ 25 - 0
service-daq/src/main/java/com/simuwang/daq/service/AbstractEmailParser.java

@@ -1,17 +1,42 @@
 package com.simuwang.daq.service;
 
+import cn.hutool.core.util.StrUtil;
+import com.simuwang.base.common.util.StringUtil;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
 import com.simuwang.base.pojo.dto.EmailFundNavDTO;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.util.List;
 import java.util.Map;
 
 public abstract class AbstractEmailParser {
 
+    private static final Logger log = LoggerFactory.getLogger(AbstractEmailParser.class);
+
     public boolean isSupport(Integer emailType) {
         return false;
     }
 
     public abstract List<EmailFundNavDTO> parse(EmailContentInfoDTO emailContentInfoDTO, Map<String, List<String>> emailFieldMap);
 
+    public boolean dataFormat(EmailFundNavDTO fundNavDTO) {
+        // 净值日期格式校验
+        boolean isvalidDate = StringUtil.isValidDate(fundNavDTO.getPriceDate());
+        if (!isvalidDate) {
+            log.warn("净值日期格式不正确 -> 解析到的数据:{}", fundNavDTO);
+            return false;
+        }
+        // 单位净值,累计单位净值,资产净值,资产份额数字格式校验
+        boolean isvalidNumericFormat = (StrUtil.isBlank(fundNavDTO.getNav()) || StringUtil.isNumeric(fundNavDTO.getNav()))
+                && (StrUtil.isBlank(fundNavDTO.getCumulativeNavWithdrawal()) || StringUtil.isNumeric(fundNavDTO.getCumulativeNavWithdrawal()))
+                && (StrUtil.isBlank(fundNavDTO.getAssetNet()) || StringUtil.isNumeric(fundNavDTO.getAssetNet()))
+                && (StrUtil.isBlank(fundNavDTO.getAssetShare()) || StringUtil.isNumeric(fundNavDTO.getAssetShare()));
+        if (!isvalidNumericFormat) {
+            log.warn("单位净值或累计净值或资产净值或资产份额格式不正确 -> 解析到的数据:{}", fundNavDTO);
+            return false;
+        }
+        log.info("数据格式验证通过 -> {}", fundNavDTO);
+        return true;
+    }
 }

+ 278 - 14
service-daq/src/main/java/com/simuwang/daq/service/EmailParseService.java

@@ -6,14 +6,14 @@ import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
 import com.simuwang.base.common.conts.DateConst;
+import com.simuwang.base.common.conts.EmailParseStatusConst;
+import com.simuwang.base.common.conts.NavParseStatusConst;
 import com.simuwang.base.common.conts.EmailTypeConst;
 import com.simuwang.base.common.util.EmailUtil;
 import com.simuwang.base.common.util.FileUtil;
 import com.simuwang.base.config.EmailRuleConfig;
-import com.simuwang.base.mapper.EmailFieldMappingMapper;
-import com.simuwang.base.mapper.EmailTypeRuleMapper;
-import com.simuwang.base.pojo.dos.EmailFieldMappingDO;
-import com.simuwang.base.pojo.dos.EmailTypeRuleDO;
+import com.simuwang.base.mapper.*;
+import com.simuwang.base.pojo.dos.*;
 import com.simuwang.base.pojo.dto.EmailContentInfoDTO;
 import com.simuwang.base.pojo.dto.EmailFundNavDTO;
 import com.simuwang.base.pojo.dto.MailboxInfoDTO;
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
+import java.math.BigDecimal;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -46,13 +47,28 @@ public class EmailParseService {
     private final EmailRuleConfig emailRuleConfig;
     private final EmailFieldMappingMapper emailFieldMapper;
     private final EmailParserFactory emailParserFactory;
+    private final EmailParseInfoMapper emailParseInfoMapper;
+    private final FundInfomationMapper fundInfomationMapper;
+    private final EmailFileInfoMapper emailFileInfoMapper;
+    private final EmailFundNavMapper emailFundNavMapper;
+    private final EmailFundAssetMapper emailFundAssetMapper;
+    private final FundAliasMapper fundAliasMapper;
 
     public EmailParseService(EmailTypeRuleMapper emailTypeRuleMapper, EmailRuleConfig emailRuleConfig,
-                             EmailFieldMappingMapper emailFieldMapper, EmailParserFactory emailParserFactory) {
+                             EmailFieldMappingMapper emailFieldMapper, EmailParserFactory emailParserFactory,
+                             EmailParseInfoMapper emailParseInfoMapper, FundInfomationMapper fundInfomationMapper,
+                             EmailFileInfoMapper emailFileInfoMapper, EmailFundNavMapper emailFundNavMapper,
+                             EmailFundAssetMapper emailFundAssetMapper, FundAliasMapper fundAliasMapper) {
         this.emailTypeRuleMapper = emailTypeRuleMapper;
         this.emailRuleConfig = emailRuleConfig;
         this.emailFieldMapper = emailFieldMapper;
         this.emailParserFactory = emailParserFactory;
+        this.emailParseInfoMapper = emailParseInfoMapper;
+        this.fundInfomationMapper = fundInfomationMapper;
+        this.emailFileInfoMapper = emailFileInfoMapper;
+        this.emailFundNavMapper = emailFundNavMapper;
+        this.emailFundAssetMapper = emailFundAssetMapper;
+        this.fundAliasMapper = fundAliasMapper;
     }
 
     /**
@@ -78,22 +94,22 @@ public class EmailParseService {
             List<EmailContentInfoDTO> emailContentInfoDTOList = emailEntry.getValue();
             if (CollUtil.isEmpty(emailContentInfoDTOList)) {
                 log.warn("未采集到正文或附件");
+                continue;
             }
+            log.info("开始解析邮件数据 -> 邮件主题:{},邮件日期:{}", emailContentInfoDTOList.get(0).getEmailTitle(), emailContentInfoDTOList.get(0).getEmailDate());
             List<EmailFundNavDTO> emailFundNavDTOList = CollUtil.newArrayList();
+            Map<EmailContentInfoDTO, List<EmailFundNavDTO>> fileNameNavMap = MapUtil.newHashMap();
             for (EmailContentInfoDTO emailContentInfoDTO : emailContentInfoDTOList) {
                 try {
                     List<EmailFundNavDTO> fundNavDTOList = parseEmail(emailContentInfoDTO, emailFieldMap);
+                    fileNameNavMap.put(emailContentInfoDTO, fundNavDTOList);
                     emailFundNavDTOList.addAll(fundNavDTOList);
                 } catch (Exception e) {
                     log.error("堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
                 }
             }
-            if (CollUtil.isEmpty(emailFundNavDTOList)) {
-                log.warn("未解析到净值 -> 邮件主题:{},邮件日期:{}", emailContentInfoDTOList.get(0).getEmailTitle(), emailContentInfoDTOList.get(0).getEmailDate());
-                continue;
-            }
-            // todo 邮件信息表,邮件文件表,邮件净值表,邮件规模表,基金净值表
-
+            // 保存相关信息 -> 邮件信息表,邮件文件表,邮件净值表,邮件规模表,基金净值表
+            saveRelatedTable(mailboxInfoDTO.getAccount(), emailContentInfoDTOList, fileNameNavMap);
         }
     }
 
@@ -103,6 +119,254 @@ public class EmailParseService {
         return emailParser.parse(emailContentInfoDTO, emailFieldMap);
     }
 
+    private void saveRelatedTable(String emailAddress, List<EmailContentInfoDTO> emailContentInfoDTOList, Map<EmailContentInfoDTO, List<EmailFundNavDTO>> fileNameNavMap) {
+        String emailTitle = CollUtil.isNotEmpty(emailContentInfoDTOList) ? emailContentInfoDTOList.get(0).getEmailTitle() : null;
+        String emailDate = CollUtil.isNotEmpty(emailContentInfoDTOList) ? emailContentInfoDTOList.get(0).getEmailDate() : null;
+        Integer emailType = CollUtil.isNotEmpty(emailContentInfoDTOList) ? emailContentInfoDTOList.get(0).getEmailType() : null;
+
+        Date parseDate = new Date();
+        int emailParseStatus = EmailParseStatusConst.SUCCESS;
+        EmailParseInfoDO emailParseInfoDO = buildEmailParseInfo(emailAddress, emailDate, emailTitle, emailType, emailParseStatus, parseDate);
+        Integer emailId = saveEmailParseInfo(emailParseInfoDO);
+
+        for (Map.Entry<EmailContentInfoDTO, List<EmailFundNavDTO>> fileNameNavEntry : fileNameNavMap.entrySet()) {
+            // 保存邮件文件表
+            EmailContentInfoDTO emailContentInfoDTO = fileNameNavEntry.getKey();
+            Integer fileId = saveEmailFileInfo(emailId, emailContentInfoDTO.getFileName(), emailContentInfoDTO.getFilePath(), parseDate);
+
+            List<EmailFundNavDTO> fundNavDTOList = fileNameNavEntry.getValue();
+            if (CollUtil.isEmpty(fundNavDTOList)) {
+                continue;
+            }
+            for (EmailFundNavDTO fundNavDTO : fundNavDTOList) {
+                // 设置净值数据的解析状态
+                setNavParseStatus(fundNavDTO, emailTitle, emailDate);
+            }
+            // 保存净值表和规模表
+            saveNavAndAssetNet(fileId, fundNavDTOList, parseDate);
+        }
+
+        // 更新邮件解析结果 -> 存在一条成功解析的净值数据就认为解析成功
+        long successNavCount = fileNameNavMap.values().stream().flatMap(List::stream).filter(e -> e.getParseStatus().equals(NavParseStatusConst.SUCCESS)).count();
+        emailParseStatus = successNavCount >= 1 ? EmailParseStatusConst.SUCCESS : EmailParseStatusConst.FAIL;
+        emailParseInfoMapper.updateParseStatus(emailId, emailParseStatus);
+    }
+
+    private void saveNavAndAssetNet(Integer fileId, List<EmailFundNavDTO> fundNavDTOList, Date parseDate) {
+        if (CollUtil.isEmpty(fundNavDTOList)) {
+            return;
+        }
+        // 净值数据
+        List<EmailFundNavDO> emailFundNavDOList = fundNavDTOList.stream()
+                .map(e -> buildEmailFundNavDo(fileId, e, parseDate)).flatMap(List::stream).collect(Collectors.toList());
+        if (CollUtil.isNotEmpty(emailFundNavDOList)) {
+            emailFundNavMapper.batchInsert(emailFundNavDOList);
+        }
+        // 保存规模数据
+        List<EmailFundAssetDO> emailFundAssetDOList = fundNavDTOList.stream()
+                .map(e -> buildEmailFundAssetDo(fileId, e, parseDate)).flatMap(List::stream).collect(Collectors.toList());
+        if (CollUtil.isNotEmpty(emailFundAssetDOList)) {
+            emailFundAssetMapper.batchInsert(emailFundAssetDOList);
+        }
+    }
+
+    private List<EmailFundAssetDO> buildEmailFundAssetDo(Integer fileId, EmailFundNavDTO fundNavDTO, Date parseDate) {
+        List<EmailFundAssetDO> fundAssetDOList = CollUtil.newArrayList();
+        BigDecimal assetNet = StrUtil.isNotBlank(fundNavDTO.getAssetNet()) ? new BigDecimal(fundNavDTO.getAssetNet()) : null;
+        BigDecimal assetShare = StrUtil.isNotBlank(fundNavDTO.getAssetShare()) ? new BigDecimal(fundNavDTO.getAssetShare()) : null;
+        if (assetNet == null) {
+            return fundAssetDOList;
+        }
+        Date priceDate = DateUtil.parse(fundNavDTO.getPriceDate(), DateConst.YYYY_MM_DD);
+        if (CollUtil.isNotEmpty(fundNavDTO.getFundIdList())) {
+            for (String fundId : fundNavDTO.getFundIdList()) {
+                EmailFundAssetDO emailFundAssetDO = new EmailFundAssetDO();
+                emailFundAssetDO.setFileId(fileId);
+                emailFundAssetDO.setPriceDate(priceDate);
+                emailFundAssetDO.setFundId(fundId);
+                emailFundAssetDO.setFundName(fundNavDTO.getFundName());
+                emailFundAssetDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
+                emailFundAssetDO.setAssetNet(assetNet);
+                emailFundAssetDO.setAssetShare(assetShare);
+                emailFundAssetDO.setIsvalid(1);
+                emailFundAssetDO.setCreatorId(0);
+                emailFundAssetDO.setCreateTime(parseDate);
+                emailFundAssetDO.setUpdaterId(0);
+                emailFundAssetDO.setUpdateTime(parseDate);
+                fundAssetDOList.add(emailFundAssetDO);
+            }
+        } else {
+            EmailFundAssetDO emailFundAssetDO = new EmailFundAssetDO();
+            emailFundAssetDO.setFileId(fileId);
+            emailFundAssetDO.setPriceDate(priceDate);
+            emailFundAssetDO.setFundName(fundNavDTO.getFundName());
+            emailFundAssetDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
+            emailFundAssetDO.setAssetNet(assetNet);
+            emailFundAssetDO.setAssetShare(assetShare);
+            emailFundAssetDO.setIsvalid(1);
+            emailFundAssetDO.setCreatorId(0);
+            emailFundAssetDO.setCreateTime(parseDate);
+            emailFundAssetDO.setUpdaterId(0);
+            emailFundAssetDO.setUpdateTime(parseDate);
+            fundAssetDOList.add(emailFundAssetDO);
+        }
+        return fundAssetDOList;
+    }
+
+    private List<EmailFundNavDO> buildEmailFundNavDo(Integer fileId, EmailFundNavDTO fundNavDTO, Date parseDate) {
+        List<EmailFundNavDO> fundNavDOList = CollUtil.newArrayList();
+        Date priceDate = DateUtil.parse(fundNavDTO.getPriceDate(), DateConst.YYYY_MM_DD);
+        BigDecimal nav = StrUtil.isNotBlank(fundNavDTO.getNav()) ? new BigDecimal(fundNavDTO.getNav()) : null;
+        BigDecimal cumulativeNavWithdrawal = StrUtil.isNotBlank(fundNavDTO.getCumulativeNavWithdrawal()) ? new BigDecimal(fundNavDTO.getCumulativeNavWithdrawal()) : null;
+        Integer isStored = fundNavDTO.getParseStatus() != null && !fundNavDTO.getParseStatus().equals(NavParseStatusConst.NAV_DEFICIENCY)
+                && !fundNavDTO.getParseStatus().equals(NavParseStatusConst.NOT_MATCH) ? 1 : 0;
+        if (CollUtil.isNotEmpty(fundNavDTO.getFundIdList())) {
+            for (String fundId : fundNavDTO.getFundIdList()) {
+                EmailFundNavDO emailFundNavDO = new EmailFundNavDO();
+                emailFundNavDO.setFileId(fileId);
+                emailFundNavDO.setIsStored(isStored);
+                emailFundNavDO.setPriceDate(priceDate);
+                emailFundNavDO.setNav(nav);
+                emailFundNavDO.setFundId(fundId);
+                emailFundNavDO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
+                emailFundNavDO.setFundName(fundNavDTO.getFundName());
+                emailFundNavDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
+                emailFundNavDO.setExceptionStatus(fundNavDTO.getParseStatus());
+                emailFundNavDO.setIsvalid(1);
+                emailFundNavDO.setCreatorId(0);
+                emailFundNavDO.setCreateTime(parseDate);
+                emailFundNavDO.setUpdaterId(0);
+                emailFundNavDO.setUpdateTime(parseDate);
+                fundNavDOList.add(emailFundNavDO);
+            }
+        } else {
+            EmailFundNavDO emailFundNavDO = new EmailFundNavDO();
+            emailFundNavDO.setFileId(fileId);
+            emailFundNavDO.setPriceDate(priceDate);
+            emailFundNavDO.setNav(nav);
+            emailFundNavDO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
+            emailFundNavDO.setFundName(fundNavDTO.getFundName());
+            emailFundNavDO.setRegisterNumber(fundNavDTO.getRegisterNumber());
+            emailFundNavDO.setExceptionStatus(fundNavDTO.getParseStatus());
+            emailFundNavDO.setIsStored(isStored);
+            emailFundNavDO.setIsvalid(1);
+            emailFundNavDO.setCreatorId(0);
+            emailFundNavDO.setCreateTime(parseDate);
+            emailFundNavDO.setUpdaterId(0);
+            emailFundNavDO.setUpdateTime(parseDate);
+            fundNavDOList.add(emailFundNavDO);
+        }
+        return fundNavDOList;
+    }
+
+    private Integer saveEmailFileInfo(Integer emailId, String fileName, String filePath, Date parseDate) {
+        EmailFileInfoDO emailFileInfoDO = buildEmailFileInfoDO(emailId, fileName, filePath, parseDate);
+        return emailFileInfoMapper.insert(emailFileInfoDO);
+    }
+
+    private EmailFileInfoDO buildEmailFileInfoDO(Integer emailId, String fileName, String filePath, Date parseDate) {
+        EmailFileInfoDO emailFileInfoDO = new EmailFileInfoDO();
+        emailFileInfoDO.setEmailId(emailId);
+        emailFileInfoDO.setFileName(fileName);
+        emailFileInfoDO.setFilePath(filePath);
+        emailFileInfoDO.setIsvalid(1);
+        emailFileInfoDO.setCreatorId(0);
+        emailFileInfoDO.setCreateTime(parseDate);
+        emailFileInfoDO.setUpdaterId(0);
+        emailFileInfoDO.setUpdateTime(parseDate);
+        return emailFileInfoDO;
+    }
+
+    private void setNavParseStatus(EmailFundNavDTO fundNavDTO, String emailTitle, String emailDate) {
+        Integer navParseStatus = getDataParseStatus(fundNavDTO);
+        fundNavDTO.setParseStatus(navParseStatus);
+        if (navParseStatus.equals(NavParseStatusConst.NAV_DEFICIENCY)) {
+            log.info("判断数据的解析状态 -> 邮件主题:{},邮件日期:{},数据解析状态:{}", emailTitle, emailDate, fundNavDTO.getParseStatus());
+            return;
+        }
+        // 2.匹配基金
+        List<String> fundIdList = matchFund(fundNavDTO.getFundName(), fundNavDTO.getRegisterNumber());
+        if (CollUtil.isEmpty(fundIdList)) {
+            fundNavDTO.setParseStatus(NavParseStatusConst.NOT_MATCH);
+        }
+        log.info("判断数据的解析状态 -> 邮件主题:{},邮件日期:{},数据解析状态:{}", emailTitle, emailDate, fundNavDTO.getParseStatus());
+        fundNavDTO.setFundIdList(fundIdList);
+    }
+
+    private List<String> matchFund(String fundName, String registerNumber) {
+        // 1.基金名称 + 备案编码 一起进行匹配
+        List<String> fundIdList = fundInfomationMapper.queryFundByNameAndRegisterNumber(fundName, registerNumber);
+        if (CollUtil.isNotEmpty(fundIdList)) {
+            return fundIdList;
+        }
+        fundIdList = fundAliasMapper.queryFundByNameAndRegisterNumber(fundName, registerNumber);
+        if (CollUtil.isNotEmpty(fundIdList)) {
+            return fundIdList;
+        }
+        // 2.基金名称匹配
+        if (StrUtil.isNotBlank(fundName)) {
+            List<String> fundIds = fundInfomationMapper.queryFundByName(fundName);
+            if (CollUtil.isNotEmpty(fundIds)) {
+                return fundIdList;
+            }
+            fundIds = fundAliasMapper.queryFundByName(fundName);
+            if (CollUtil.isNotEmpty(fundIds)) {
+                return fundIds;
+            }
+        }
+        // 3.备案编码匹配
+        if (StrUtil.isNotBlank(fundName)) {
+            List<String> fundIds = fundInfomationMapper.queryFundByRegisterNumber(registerNumber);
+            if (CollUtil.isNotEmpty(fundIds)) {
+                return fundIds;
+            }
+            fundIds = fundAliasMapper.queryFundByRegisterNumber(registerNumber);
+            if (CollUtil.isNotEmpty(fundIds)) {
+                return fundIds;
+            }
+        }
+        return CollUtil.newArrayList();
+    }
+
+    private Integer saveEmailParseInfo(EmailParseInfoDO emailParseInfoDO) {
+        if (emailParseInfoDO == null) {
+            return null;
+        }
+        return emailParseInfoMapper.insert(emailParseInfoDO);
+    }
+
+    private EmailParseInfoDO buildEmailParseInfo(String emailAddress, String emailDate, String emailTitle, Integer emailType, Integer parseStatus, Date parseDate) {
+        EmailParseInfoDO emailParseInfoDO = new EmailParseInfoDO();
+        emailParseInfoDO.setEmail(emailAddress);
+        emailParseInfoDO.setEmailDate(DateUtil.parse(emailDate, DateConst.YYYY_MM_DD_HH_MM_SS));
+        emailParseInfoDO.setParseDate(parseDate);
+        emailParseInfoDO.setEmailTitle(emailTitle);
+        emailParseInfoDO.setEmailType(emailType);
+        emailParseInfoDO.setParseStatus(parseStatus);
+        emailParseInfoDO.setIsvalid(1);
+        emailParseInfoDO.setCreatorId(0);
+        emailParseInfoDO.setCreateTime(parseDate);
+        emailParseInfoDO.setUpdaterId(0);
+        emailParseInfoDO.setUpdateTime(parseDate);
+        return emailParseInfoDO;
+    }
+
+    private Integer getDataParseStatus(EmailFundNavDTO fundNavDTO) {
+        // 1.单位净值或累计净值缺失
+        if (StrUtil.isBlank(fundNavDTO.getNav()) || StrUtil.isBlank(fundNavDTO.getCumulativeNavWithdrawal())) {
+            return NavParseStatusConst.NAV_DEFICIENCY;
+        }
+        // 3.单位净值或累计净值不大于0
+        if (fundNavDTO.getNav().compareTo("0") <= 0 || fundNavDTO.getCumulativeNavWithdrawal().compareTo("0") <= 0) {
+            return NavParseStatusConst.NAV_NEGATIVE;
+        }
+        // 4.资产净值不大于0
+        if (StrUtil.isNotBlank(fundNavDTO.getAssetNet()) && fundNavDTO.getAssetNet().compareTo("0") <= 0) {
+            return NavParseStatusConst.ASSET_NET_NEGATIVE;
+        }
+        return NavParseStatusConst.SUCCESS;
+    }
+
     public Map<String, List<String>> getEmailFieldMapping() {
         List<EmailFieldMappingDO> emailFieldMappingDOList = emailFieldMapper.getEmailFieldMapping();
         return emailFieldMappingDOList.stream()
@@ -142,7 +406,7 @@ public class EmailParseService {
         // 获取邮件日期大于等于startDate的邮件(搜索条件只支持按天)
         SearchTerm startDateTerm = new ReceivedDateTerm(ComparisonTerm.GE, startDate);
         Message[] messages = folder.search(startDateTerm);
-        String path = "/data/file/";
+        String path = "/data/file";
         Map<String, List<EmailContentInfoDTO>> emailMessageMap = MapUtil.newHashMap();
         for (Message message : messages) {
             List<EmailContentInfoDTO> emailContentInfoDTOList = CollUtil.newArrayList();
@@ -181,9 +445,9 @@ public class EmailParseService {
                             savefile.getParentFile().mkdirs();
                             savefile.getParentFile().setExecutable(true);
                         }
-                        FileUtil.writeFile(filePath, content.toString());
-                        emailContentInfoDTO.setFilePath(filePath);
                     }
+                    FileUtil.writeFile(filePath, content.toString());
+                    emailContentInfoDTO.setFilePath(filePath);
                     emailContentInfoDTOList.add(emailContentInfoDTO);
                 }
                 if (CollUtil.isNotEmpty(emailContentInfoDTOList)) {

+ 135 - 34
service-daq/src/main/java/com/simuwang/daq/service/NavEmailParser.java

@@ -2,6 +2,7 @@ package com.simuwang.daq.service;
 
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.exceptions.ExceptionUtil;
 import cn.hutool.core.lang.Pair;
 import cn.hutool.core.map.MapUtil;
 import cn.hutool.core.util.StrUtil;
@@ -15,6 +16,8 @@ import com.simuwang.base.pojo.dto.EmailFundNavDTO;
 import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Row;
 import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
@@ -24,9 +27,13 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 /**
  * @author mozuwen
@@ -54,13 +61,17 @@ public class NavEmailParser extends AbstractEmailParser {
         String emailContent = emailContentInfoDTO.getEmailContent();
         // 1.解析邮件正文
         if (StrUtil.isNotBlank(emailContent)) {
-            emailFundNavDTOList = parseEmailContent(emailContent, emailFieldMap);
+            emailFundNavDTOList = parseEmailContent(emailContentInfoDTO, emailContent, emailFieldMap);
         }
         // 2.解析邮件excel附件
         if (StrUtil.isNotBlank(emailContentInfoDTO.getFilePath()) && ExcelUtil.isExcel(emailContentInfoDTO.getFileName())) {
             List<EmailFundNavDTO> fundNavDTOList = parseExcelFile(emailContentInfoDTO.getFilePath(), emailFieldMap);
             emailFundNavDTOList.addAll(fundNavDTOList);
         }
+        // 校验净值数据格式
+        if (CollUtil.isNotEmpty(emailFundNavDTOList)) {
+            emailFundNavDTOList = emailFundNavDTOList.stream().filter(super::dataFormat).collect(Collectors.toList());
+        }
         return emailFundNavDTOList;
     }
 
@@ -99,7 +110,7 @@ public class NavEmailParser extends AbstractEmailParser {
             // 遍历可能的数据行
             for (int rowNum = initRow + 1; rowNum <= lastRowNum; rowNum++) {
                 Row sheetRow = sheet.getRow(rowNum);
-                Optional.ofNullable(readSheetRowData(sheetRow, fieldColumnMap)).ifPresent(fundNavDTOList::add);
+                Optional.ofNullable(readSheetRowData(sheetRow, fieldColumnMap)).ifPresent(fundNavDTOList::addAll);
             }
         }
         if (dataDirectionType.equals(COLUMN_DIRECTION_TYPE)) {
@@ -180,57 +191,105 @@ public class NavEmailParser extends AbstractEmailParser {
         fundNavDTO.setNav(fieldValueMap.get(EmailFieldConst.NAV));
         fundNavDTO.setCumulativeNavWithdrawal(fieldValueMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL));
         String assetNet = fieldValueMap.get(EmailFieldConst.ASSET_NET);
-        if (StrUtil.isBlank(assetNet) || !StrUtil.isNumeric(assetNet)) {
+        if (StrUtil.isBlank(assetNet)) {
             assetNet = null;
         }
         fundNavDTO.setAssetNet(assetNet);
         String assetShares = fieldValueMap.get(EmailFieldConst.ASSET_NET);
-        if (StrUtil.isBlank(assetShares) || !StrUtil.isNumeric(assetShares)) {
+        if (StrUtil.isBlank(assetShares)) {
             assetShares = null;
         }
         fundNavDTO.setAssetShare(assetShares);
         return fundNavDTO;
     }
 
-
-    private EmailFundNavDTO readSheetRowData(Row sheetRow, Map<String, Integer> columnFieldMap) {
+    private List<EmailFundNavDTO> readSheetRowData(Row sheetRow, Map<String, Integer> columnFieldMap) {
         if (sheetRow == null) {
             return null;
         }
         String nav = columnFieldMap.get(EmailFieldConst.NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.NAV)) != null
-                ? sheetRow.getCell(columnFieldMap.get(EmailFieldConst.NAV)).getStringCellValue() : null;
+                ? ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.NAV))) : null;
         String cumulativeNavWithdrawal = columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL)).getStringCellValue() : null;
-        if (StrUtil.isBlank(nav) || StrUtil.isBlank(cumulativeNavWithdrawal)) {
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.CUMULATIVE_NAV_WITHDRAWAL))) : null;
+        if (StrUtil.isBlank(nav) && StrUtil.isBlank(cumulativeNavWithdrawal)) {
             return null;
         }
+        List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
         EmailFundNavDTO emailFundNavDTO = new EmailFundNavDTO();
         String priceDate = columnFieldMap.get(EmailFieldConst.PRICE_DATE) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PRICE_DATE)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PRICE_DATE)).getStringCellValue() : null;
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PRICE_DATE))) : null;
+
+        // 份额基金净值文件格式
+        long parentFiledCount = columnFieldMap.keySet().stream().filter(e -> e.contains("parent")).count();
+        if (parentFiledCount >= 1) {
+            Optional.ofNullable(buildParentNav(sheetRow, columnFieldMap, priceDate)).ifPresent(fundNavDTOList::add);
+        }
+        // 正常净值文件格式
         if (StrUtil.isNotBlank(priceDate) && !priceDate.contains("-")) {
             // 处理日期yyyyMMdd格式 -> 转成yyyy-MM-dd
             priceDate = DateUtil.format(DateUtil.parse(priceDate, DateConst.YYYYMMDD), DateConst.YYYY_MM_DD);
         }
         emailFundNavDTO.setPriceDate(priceDate);
         String fundName = columnFieldMap.get(EmailFieldConst.FUND_NAME) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.FUND_NAME)).getStringCellValue() != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.FUND_NAME)).getStringCellValue() : null;
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.FUND_NAME))) : null;
         emailFundNavDTO.setFundName(fundName);
         String registerNumber = columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER)).getStringCellValue() : null;
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.REGISTER_NUMBER))) : null;
         emailFundNavDTO.setRegisterNumber(registerNumber);
         emailFundNavDTO.setNav(nav);
         emailFundNavDTO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
         String virtualNav = columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV)).getStringCellValue() : null;
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.VIRTUAL_NAV))) : null;
         emailFundNavDTO.setVirtualNav(virtualNav);
         String assetNet = columnFieldMap.get(EmailFieldConst.ASSET_NET) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_NET)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_NET)).getStringCellValue() : null;
-        if (StrUtil.isBlank(assetNet) || !StrUtil.isNumeric(assetNet)) {
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_NET))) : null;
+        if (StrUtil.isBlank(assetNet)) {
             assetNet = null;
         }
         emailFundNavDTO.setAssetNet(assetNet);
         String assetShares = columnFieldMap.get(EmailFieldConst.ASSET_SHARE) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_SHARE)) != null ?
-                sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_SHARE)).getStringCellValue() : null;
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.ASSET_SHARE))) : null;
+        if (StrUtil.isBlank(assetShares)) {
+            assetShares = null;
+        }
+        emailFundNavDTO.setAssetShare(assetShares);
+        fundNavDTOList.add(emailFundNavDTO);
+        return fundNavDTOList;
+    }
+
+    private EmailFundNavDTO buildParentNav(Row sheetRow, Map<String, Integer> columnFieldMap, String priceDate) {
+        EmailFundNavDTO emailFundNavDTO = new EmailFundNavDTO();
+        String nav = columnFieldMap.get(EmailFieldConst.PARENT_NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_NAV)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_NAV))) : null;
+        String cumulativeNavWithdrawal = columnFieldMap.get(EmailFieldConst.PARENT_CUMULATIVE_NAV_WITHDRAWAL) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_CUMULATIVE_NAV_WITHDRAWAL)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_CUMULATIVE_NAV_WITHDRAWAL))) : null;
+        if (StrUtil.isBlank(nav) && StrUtil.isBlank(cumulativeNavWithdrawal)) {
+            return null;
+        }
+        if (StrUtil.isNotBlank(priceDate) && !priceDate.contains("-")) {
+            // 处理日期yyyyMMdd格式 -> 转成yyyy-MM-dd
+            priceDate = DateUtil.format(DateUtil.parse(priceDate, DateConst.YYYYMMDD), DateConst.YYYY_MM_DD);
+        }
+        emailFundNavDTO.setPriceDate(priceDate);
+        String fundName = columnFieldMap.get(EmailFieldConst.PARENT_FUND_NAME) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_FUND_NAME)).getStringCellValue() != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_FUND_NAME))) : null;
+        emailFundNavDTO.setFundName(fundName);
+        String registerNumber = columnFieldMap.get(EmailFieldConst.PARENT_REGISTER_NUMBER) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_REGISTER_NUMBER)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_REGISTER_NUMBER))) : null;
+        emailFundNavDTO.setRegisterNumber(registerNumber);
+        emailFundNavDTO.setNav(nav);
+        emailFundNavDTO.setCumulativeNavWithdrawal(cumulativeNavWithdrawal);
+        String virtualNav = columnFieldMap.get(EmailFieldConst.PARENT_VIRTUAL_NAV) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_VIRTUAL_NAV)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_VIRTUAL_NAV))) : null;
+        emailFundNavDTO.setVirtualNav(virtualNav);
+        String assetNet = columnFieldMap.get(EmailFieldConst.PARENT_ASSET_NET) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_ASSET_NET)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_ASSET_NET))) : null;
+        if (StrUtil.isBlank(assetNet) || !StrUtil.isNumeric(assetNet)) {
+            assetNet = null;
+        }
+        emailFundNavDTO.setAssetNet(assetNet);
+        String assetShares = columnFieldMap.get(EmailFieldConst.PARENT_ASSET_SHARE) != null && sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_ASSET_SHARE)) != null ?
+                ExcelUtil.getCellValue(sheetRow.getCell(columnFieldMap.get(EmailFieldConst.PARENT_ASSET_SHARE))) : null;
         if (StrUtil.isBlank(assetShares) || !StrUtil.isNumeric(assetShares)) {
             assetShares = null;
         }
@@ -283,7 +342,7 @@ public class NavEmailParser extends AbstractEmailParser {
      * @return excel中表头所在的位置(行, 列)
      */
     private Map<String, Pair<Integer, Integer>> getFieldPosition(Sheet sheet, Map<String, List<String>> emailFieldMap) {
-        Map<String, Pair<Integer, Integer>> fieldPositionMap = MapUtil.newHashMap(8);
+        Map<String, List<Pair<Integer, Integer>>> tempFieldPositionMap = MapUtil.newHashMap();
         int lastRowNum = sheet.getLastRowNum();
         for (int rowNum = 0; rowNum < lastRowNum; rowNum++) {
             Row sheetRow = sheet.getRow(rowNum);
@@ -296,14 +355,36 @@ public class NavEmailParser extends AbstractEmailParser {
                 if (cell == null) {
                     continue;
                 }
-                String cellValue = cell.getStringCellValue();
+                String cellValue = ExcelUtil.getCellValue(cell);
                 String field = fieldMatch(cellValue, emailFieldMap);
-                // todo 考虑份额基金净值文件格式
                 if (StrUtil.isNotBlank(field)) {
-                    fieldPositionMap.put(field, new Pair<>(rowNum, cellNum));
+                    List<Pair<Integer, Integer>> pairList = tempFieldPositionMap.getOrDefault(field, new ArrayList<>());
+                    pairList.add(Pair.of(rowNum, cellNum));
+                    tempFieldPositionMap.put(field, pairList);
                 }
             }
         }
+        // 判断是不是份额基金净值文件格式(同时存在两个备案编码字段)
+        return handlerFieldPosition(tempFieldPositionMap);
+    }
+
+    private Map<String, Pair<Integer, Integer>> handlerFieldPosition(Map<String, List<Pair<Integer, Integer>>> tempFieldPositionMap) {
+        Map<String, Pair<Integer, Integer>> fieldPositionMap = MapUtil.newHashMap();
+        boolean hasParentField = tempFieldPositionMap.keySet().stream().anyMatch(e -> e.contains("parent"));
+        for (Map.Entry<String, List<Pair<Integer, Integer>>> entry : tempFieldPositionMap.entrySet()) {
+            List<Pair<Integer, Integer>> pairList = entry.getValue();
+            if (pairList.size() == 1) {
+                fieldPositionMap.put(entry.getKey(), pairList.get(0));
+                continue;
+            }
+            if ((!hasParentField && pairList.size() > 1)) {
+                fieldPositionMap.put(entry.getKey(), pairList.get(pairList.size() - 1));
+                continue;
+            }
+            if ((hasParentField && pairList.size() > 1)) {
+                fieldPositionMap.put(entry.getKey(), pairList.get(0));
+            }
+        }
         return fieldPositionMap;
     }
 
@@ -330,24 +411,44 @@ public class NavEmailParser extends AbstractEmailParser {
         return null;
     }
 
-    /**
-     * 解析邮件正文
-     *
-     * @param emailContent  邮件excel附件地址
-     * @param emailFieldMap 邮件字段识别规则映射表
-     * @return 解析到的净值数据
-     */
-    private List<EmailFundNavDTO> parseEmailContent(String emailContent, Map<String, List<String>> emailFieldMap) {
-        List<EmailFundNavDTO> fundNavDTOList = CollUtil.newArrayList();
+    private List<EmailFundNavDTO> parseEmailContent(EmailContentInfoDTO emailContentInfoDTO, String emailContent, Map<String, List<String>> emailFieldMap) {
         Document doc = Jsoup.parse(emailContent);
         Element table = doc.select("table").first();
         Elements rows = table.select("tr");
-        for (Element row : rows) {
-            Elements cells = row.select("td");
-            int cellSize = cells.size();
-            // todo 后续补充
+        String excelFilePath = "/data/file/content/" + emailContentInfoDTO.getEmailDate().substring(0, 10).replaceAll("-","")
+                + "/" + emailContentInfoDTO.getFileName().replace(".html", ".xlsx");
+        File savefile = new File(excelFilePath);
+        if (!savefile.exists()) {
+            if (!savefile.getParentFile().exists()) {
+                savefile.getParentFile().mkdirs();
+                savefile.getParentFile().setExecutable(true);
+            }
         }
-        return fundNavDTOList;
+        try (OutputStream outputStream = new FileOutputStream(savefile)) {
+            // 创建一个新的Excel工作簿
+            Workbook workbook = new XSSFWorkbook();
+            Sheet sheet = workbook.createSheet("Sheet1");
+            writeDataToSheet(sheet, rows);
+            // 将Excel工作簿写入输出流
+            workbook.write(outputStream);
+        } catch (Exception e) {
+            log.error("解析正文报错 -> 堆栈信息:{}", ExceptionUtil.stacktraceToString(e));
+        }
+        return parseExcelFile(excelFilePath, emailFieldMap);
     }
 
+    private void writeDataToSheet(Sheet sheet, Elements rows) {
+        int rowSize = rows.size();
+        for (int rowNum = 0; rowNum < rowSize; rowNum++) {
+            Row sheetRow = sheet.createRow(rowNum);
+
+            Element elementRow = rows.get(rowNum);
+            Elements cells = elementRow.select("td");
+            int cellSize = cells.size();
+            for (int cellNum = 0; cellNum< cellSize; cellNum++) {
+                Cell sheetRowCell = sheetRow.createCell(cellNum);
+                sheetRowCell.setCellValue(cells.get(cellNum).text());
+            }
+        }
+    }
 }

+ 4 - 4
service-deploy/src/main/test/java/com/simuwang/datadaq/DataTrusteeApplicationTests.java

@@ -1,4 +1,4 @@
-package com.simuwang.datadaq;
+package java.com.simuwang.datadaq;
 
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.map.MapUtil;
@@ -17,7 +17,7 @@ import java.util.Map;
 class DataTrusteeApplicationTests {
 
     @Autowired
-    EmailParseService emailParseService;
+    private EmailParseService emailParseService;
 
     @Test
     public void test() {
@@ -32,8 +32,8 @@ class DataTrusteeApplicationTests {
         emailInfoDTO.setProtocol("imap");
         Map<Integer, List<String>> emailTypeMap = MapUtil.newHashMap();
         emailTypeMap.put(1, List.of("净值"));
-        Date startDate = DateUtil.parse("2024-09-06 18:40:00", DateConst.YYYY_MM_DD_HH_MM_SS);
-        Date endDate = DateUtil.parse("2024-09-06 19:00:00", DateConst.YYYY_MM_DD_HH_MM_SS);
+        Date startDate = DateUtil.parse("2024-09-10 09:40:00", DateConst.YYYY_MM_DD_HH_MM_SS);
+        Date endDate = DateUtil.parse("2024-09-10 10:00:00", DateConst.YYYY_MM_DD_HH_MM_SS);
         try {
             emailParseService.parseEmail(emailInfoDTO, startDate, endDate);
         } catch (Exception e) {

+ 2 - 2
service-manage/src/main/java/com/simuwang/manage/api/company/CompanyEmailSendHistoryController.java

@@ -88,7 +88,7 @@ public class CompanyEmailSendHistoryController extends BaseController {
         try{
             companyEmailConfigService.saveCompanyEmailConfig(companyEmailConfigVOS);
         }catch (Exception e){
-            vo = new ResultVo(ResultCode.SAVE_SUCCESS);
+            vo = new ResultVo(ResultCode.SAVE_FAILED);
             logger.error(e.getMessage(),e);
         }
         return vo;
@@ -105,7 +105,7 @@ public class CompanyEmailSendHistoryController extends BaseController {
         try{
             companyEmailConfigService.updateCompanyEmailConfig(companyEmailConfigVO);
         }catch (Exception e){
-            vo = new ResultVo(ResultCode.SAVE_SUCCESS);
+            vo = new ResultVo(ResultCode.SAVE_FAILED);
             logger.error(e.getMessage(),e);
         }
         return vo;

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

@@ -33,10 +33,10 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
             emailConfigDO.setUpdateTime(new Date());
             if(emailConfigVO.getId() != null){
                 emailConfigDO.setId(emailConfigVO.getId());
-                companyEmailConfigMapper.updateById(emailConfigDO);
+                companyEmailConfigMapper.updateCompanyEmailConfig(emailConfigDO);
             }else{
                 emailConfigDO.setCreateTime(new Date());
-                companyEmailConfigMapper.insert(emailConfigDO);
+                companyEmailConfigMapper.saveCompanyEmailConfig(emailConfigDO);
             }
         }
     }
@@ -53,13 +53,13 @@ public class CompanyEmailConfigServiceImpl implements CompanyEmailConfigService
 
     @Override
     public void updateCompanyEmailConfig(CompanyEmailConfigVO companyEmailConfigVO) {
-        CompanyEmailConfigDO configDO = companyEmailConfigMapper.selectById(companyEmailConfigVO.getId());
+        CompanyEmailConfigDO configDO = companyEmailConfigMapper.selectCompanyEmailConfigById(companyEmailConfigVO.getId());
         if(configDO != null){
             configDO.setEmail(companyEmailConfigVO.getEmail());
             configDO.setCompanyId(companyEmailConfigVO.getCompanyId());
             configDO.setCompanyName(companyEmailConfigVO.getCompanyName());
             configDO.setUpdateTime(new Date());
-            companyEmailConfigMapper.updateById(configDO);
+            companyEmailConfigMapper.updateCompanyEmailConfig(configDO);
         }
     }
 }