Commit bf7d94c2 by jianan

保费到期提醒23-保单邮件逐条通知

parent 15a970a0
...@@ -10,7 +10,7 @@ import com.yd.csf.service.component.TemplateStyleStrategy; ...@@ -10,7 +10,7 @@ import com.yd.csf.service.component.TemplateStyleStrategy;
import com.yd.csf.service.dto.PolicyFollowQueryRequest; import com.yd.csf.service.dto.PolicyFollowQueryRequest;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.service.PolicyFollowService; import com.yd.csf.service.service.PolicyFollowService;
import com.yd.csf.service.utils.RenewalDueDateCalculator; import com.yd.csf.service.component.renewal.RenewalDueDateCalculator;
import com.yd.csf.service.utils.SimpleDateUtils; import com.yd.csf.service.utils.SimpleDateUtils;
import com.yd.csf.service.vo.RenewalPolicyExportDTO; import com.yd.csf.service.vo.RenewalPolicyExportDTO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
......
...@@ -4,9 +4,10 @@ import com.yd.common.exception.BusinessException; ...@@ -4,9 +4,10 @@ import com.yd.common.exception.BusinessException;
import com.yd.common.utils.RandomStringGenerator; import com.yd.common.utils.RandomStringGenerator;
import com.yd.csf.api.service.RenewalDispatchService; import com.yd.csf.api.service.RenewalDispatchService;
import com.yd.csf.api.service.RenewalMailService; import com.yd.csf.api.service.RenewalMailService;
import com.yd.csf.service.component.RenewalPolicyReportService; import com.yd.csf.service.component.renewal.RenewalPolicyMailBuilder;
import com.yd.csf.service.dto.RenewalDuePolicy; import com.yd.csf.service.component.renewal.RenewalPolicyReportService;
import com.yd.csf.service.dto.RenewalReminderData; import com.yd.csf.service.component.renewal.RenewalDuePolicy;
import com.yd.csf.service.component.renewal.RenewalReminderData;
import com.yd.csf.service.enums.RenewalMailTypeEnum; import com.yd.csf.service.enums.RenewalMailTypeEnum;
import com.yd.csf.service.enums.RenewalRemindStatusEnum; import com.yd.csf.service.enums.RenewalRemindStatusEnum;
import com.yd.csf.service.model.RenewalRemindBatch; import com.yd.csf.service.model.RenewalRemindBatch;
......
package com.yd.csf.service.utils; package com.yd.csf.service.component.renewal;
import com.yd.csf.feign.enums.PaymentFrequencyEnum; import com.yd.csf.feign.enums.PaymentFrequencyEnum;
import lombok.Getter; import lombok.Getter;
......
package com.yd.csf.service.dto; package com.yd.csf.service.component.renewal;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
......
package com.yd.csf.api.service.impl; package com.yd.csf.service.component.renewal;
import com.yd.csf.service.dto.RenewalDuePolicy;
import com.yd.csf.service.enums.RenewalMailTypeEnum; import com.yd.csf.service.enums.RenewalMailTypeEnum;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.utils.RenewalPremiumUtils;
import com.yd.csf.service.utils.SimpleDateUtils; import com.yd.csf.service.utils.SimpleDateUtils;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
...@@ -19,6 +17,7 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -19,6 +17,7 @@ import java.util.concurrent.atomic.AtomicInteger;
/** /**
* 逐单续期保费通知邮件构建器:简繁双语 HTML(内联 CSS、无图片无外链)。 * 逐单续期保费通知邮件构建器:简繁双语 HTML(内联 CSS、无图片无外链)。
* 版式按需求稿:字段单列、开场句日期加粗下划线、应缴总保费与备注红色、底部日期加粗下划线。
* 静态标签简体段/繁体段各一份,数据值原样填充不做简繁转换,全部做 HTML 转义。 * 静态标签简体段/繁体段各一份,数据值原样填充不做简繁转换,全部做 HTML 转义。
*/ */
@Component @Component
...@@ -29,6 +28,14 @@ public class RenewalPolicyMailBuilder { ...@@ -29,6 +28,14 @@ public class RenewalPolicyMailBuilder {
private static final String FONT = "'Microsoft YaHei','PingFang SC',Arial,sans-serif"; private static final String FONT = "'Microsoft YaHei','PingFang SC',Arial,sans-serif";
private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy年MM月dd日"); private static final DateTimeFormatter DATE_FMT = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
private static final DecimalFormat MONEY_FMT = new DecimalFormat("#,##0.00"); private static final DecimalFormat MONEY_FMT = new DecimalFormat("#,##0.00");
/**
* 需求稿强调色:应缴总保费、备注整行红色
*/
private static final String EMPHASIS_RED = "#FF0000";
/**
* 标签对齐宽度(全角字符数,含冒号);最长标签「保单持有人:」为 6
*/
private static final int LABEL_WIDTH = 6;
/** /**
* grace_period 缺失时括注中的默认天数,与筛选侧同源配置 * grace_period 缺失时括注中的默认天数,与筛选侧同源配置
...@@ -72,15 +79,15 @@ public class RenewalPolicyMailBuilder { ...@@ -72,15 +79,15 @@ public class RenewalPolicyMailBuilder {
String effectiveText = effectiveDate == null ? null : effectiveDate.format(DATE_FMT); String effectiveText = effectiveDate == null ? null : effectiveDate.format(DATE_FMT);
String graceNoteSc = item.isGraceFallback() String graceNoteSc = item.isGraceFallback()
? "(宽限天数待核对(按默认 " + resolveDefaultGraceDays() + " 天估算))" ? "(宽限天数待核对(按默认 " + resolveDefaultGraceDays() + " 天估算))"
: "(保费到期日起计 " + item.getGraceDays() + " 天)"; : "(获取保费到期日起计" + item.getGraceDays() + "天)";
String graceNoteTc = item.isGraceFallback() String graceNoteTc = item.isGraceFallback()
? "(寬限天數待核對(按預設 " + resolveDefaultGraceDays() + " 天估算))" ? "(寬限天數待核對(按預設 " + resolveDefaultGraceDays() + " 天估算))"
: "(保費到期日起計 " + item.getGraceDays() + " 天)"; : "(获取保费到期日起计" + item.getGraceDays() + "天)";
String subject = (type == RenewalMailTypeEnum.R2 ? "【宽限期跟进】" : "") String subject = (type == RenewalMailTypeEnum.R2 ? "【宽限期跟进】" : "")
+ "续期保费通知-" + policyNo; + "续期保费通知-【" + policyNo + "】";
String html = "<div style=\"font-family:" + FONT + ";font-size:14px;color:#333333;line-height:1.9;\">" String html = "<div style=\"font-family:" + FONT + ";font-size:14px;color:#000000;line-height:1.9;\">"
+ segment(Labels.SC, MISSING_SC, type, company, product, esc(policyNo), holder, insured, + segment(Labels.SC, MISSING_SC, type, company, product, esc(policyNo), holder, insured,
money, effectiveText, dueDateText, graceEndText, graceNoteSc) money, effectiveText, dueDateText, graceEndText, graceNoteSc)
+ "<hr style=\"border:none;border-top:1px solid #dddddd;margin:18px 0;\">" + "<hr style=\"border:none;border-top:1px solid #dddddd;margin:18px 0;\">"
...@@ -104,55 +111,63 @@ public class RenewalPolicyMailBuilder { ...@@ -104,55 +111,63 @@ public class RenewalPolicyMailBuilder {
String money, String effectiveText, String dueDateText, String money, String effectiveText, String dueDateText,
String graceEndText, String graceNote) { String graceEndText, String graceNote) {
String opening; String opening;
String boldDue = boldUnderline(dueDateText);
if (type == RenewalMailTypeEnum.R2) { if (type == RenewalMailTypeEnum.R2) {
opening = l.openingR2Prefix + dueDateText + l.openingR2Middle + graceEndText + l.openingR2Suffix; opening = l.openingR2Prefix + boldDue + l.openingR2Middle
+ boldUnderline(graceEndText) + l.openingR2Suffix;
} else { } else {
opening = l.openingR1Prefix + dueDateText + l.openingR1Suffix; opening = l.openingR1Prefix + boldDue + l.openingR1Suffix;
} }
String companyV = markOrValue(company, missingMark);
String productV = markOrValue(product, missingMark);
String holderV = markOrValue(holder, missingMark);
String insuredV = markOrValue(insured, missingMark);
String moneyV = markOrValue(money, missingMark);
String effectiveV = markOrValue(effectiveText, missingMark);
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<p style=\"margin:0 0 6px 0;font-weight:bold;\">").append(l.segmentTitle).append("</p>"); sb.append("<p style=\"margin:0 0 8px 0;font-weight:bold;\">").append(l.segmentTitle).append("</p>");
sb.append("<p style=\"margin:0 0 12px 0;\">").append(opening).append("</p>"); sb.append("<p style=\"margin:0 0 10px 0;\">").append(opening).append("</p>");
sb.append("<table cellspacing=\"0\" cellpadding=\"4\" style=\"border-collapse:collapse;font-size:14px;\">"); // 保单资料:每字段单独一行,标签全角补齐对齐
sb.append(row4(l.company, companyV, l.product, productV)); sb.append("<div style=\"line-height:2;\">");
sb.append(row4(l.policyNo, policyNo, l.effectiveDate, effectiveV)); sb.append(fieldLine(l.company, markOrValue(company, missingMark)));
sb.append(row4(l.holder, holderV, l.insured, insuredV)); sb.append(fieldLine(l.product, markOrValue(product, missingMark)));
sb.append(row1(l.premiumAndLevy, moneyV, false)); sb.append(fieldLine(l.policyNo, policyNo));
sb.append(row1(l.totalPremium, moneyV, true)); sb.append(fieldLine(l.holder, markOrValue(holder, missingMark)));
sb.append("</table>"); sb.append(fieldLine(l.insured, markOrValue(insured, missingMark)));
sb.append("<p style=\"margin:10px 0 0 0;\">").append(l.remark).append("</p>"); sb.append(fieldLine(l.premiumAndLevy, markOrValue(money, missingMark)));
sb.append("<p style=\"margin:6px 0 0 0;\">") sb.append(fieldLine(l.effectiveDate, markOrValue(effectiveText, missingMark)));
.append(l.dueDateLabel).append(":<span style=\"font-weight:bold;text-decoration:underline;\">") sb.append("</div>");
.append(dueDateText).append("</span></p>"); // 应缴总保费:标签+金额整行红色加粗
sb.append("<p style=\"margin:6px 0 0 0;\">") sb.append("<div style=\"margin-top:14px;color:").append(EMPHASIS_RED)
.append(l.graceEndLabel).append(":<span style=\"font-weight:bold;text-decoration:underline;\">") .append(";font-weight:bold;\">")
.append(graceEndText).append("</span>").append(graceNote).append("</p>"); .append(l.totalPremium).append(":").append(markOrValue(money, missingMark))
.append("</div>");
// 备注:整行红色、常规字重(繁体段文案按需求稿原文)
sb.append("<div style=\"margin-top:4px;color:").append(EMPHASIS_RED).append(";\">")
.append(l.remark).append("</div>");
// 到期日区域与备注间空一行
sb.append("<div style=\"margin-top:22px;\">")
.append(l.dueDateLabel).append(":").append(boldDue)
.append("</div>");
sb.append("<div style=\"margin-top:6px;\">")
.append(l.graceEndLabel).append(":").append(boldUnderline(graceEndText))
.append("&nbsp;&nbsp;").append(graceNote)
.append("</div>");
return sb.toString(); return sb.toString();
} }
private String row4(String label1, String value1, String label2, String value2) { private String fieldLine(String label, String value) {
return "<tr>" return "<div>" + padLabel(label) + value + "</div>";
+ "<td style=\"white-space:nowrap;color:#666666;\">" + label1 + ":</td>" }
+ "<td style=\"padding-right:24px;\">" + value1 + "</td>"
+ "<td style=\"white-space:nowrap;color:#666666;\">" + label2 + ":</td>" private String boldUnderline(String text) {
+ "<td>" + value2 + "</td>" return "<span style=\"font-weight:bold;text-decoration:underline;\">" + text + "</span>";
+ "</tr>";
} }
private String row1(String label, String value, boolean total) { /**
String valueStyle = total * 标签(含全角冒号)右侧补全角空格到固定宽度,使各字段值纵向对齐
? "<span style=\"color:#D90000;font-weight:bold;\">" + value + "</span>" */
: value; private String padLabel(String labelWithColon) {
return "<tr>" StringBuilder sb = new StringBuilder(labelWithColon);
+ "<td style=\"white-space:nowrap;color:#666666;\">" + label + ":</td>" while (sb.length() < LABEL_WIDTH) {
+ "<td colspan=\"3\">" + valueStyle + "</td>" sb.append(' ');
+ "</tr>"; }
return sb.toString();
} }
/** /**
...@@ -284,19 +299,20 @@ public class RenewalPolicyMailBuilder { ...@@ -284,19 +299,20 @@ public class RenewalPolicyMailBuilder {
} }
private static final Labels SC = new Labels( private static final Labels SC = new Labels(
"【简体】", "产品公司", "计划名称", "保单号码", "保单生效日", "【简体】", "产品公司:", "计划名称:", "保单号码:", "保单生效日:",
"保单持有人", "受保人", "保费及征费", "应缴总保费", "保单持有人:", "受保人:", "保费及征费:", "应缴总保费",
"备注:此金额未计入保费优惠,保费优惠待确认后通知客户。", "备注:此金额未计入保费优惠,保费优惠待确认后通知客户。",
"保费到期日", "宽限期到期日", "保费到期日", "宽限期到期日",
"以下保单的保费将于 ", " 到期,请在此日期前缴付应缴保费。", "以下保单的保费将于", "到期,请在此日期前缴付应缴保费。保单资料如下:",
"以下保单的保费已于 ", " 到期,宽限期将于 ", " 届满,请尽快跟进确认缴费情况。"); "以下保单的保费已于", "到期,宽限期将于", "届满,请尽快跟进确认缴费情况。保单资料如下:");
private static final Labels TC = new Labels( private static final Labels TC = new Labels(
"【繁體】", "產品公司", "計劃名稱", "保單號碼", "保單生效日", "【繁體】", "產品公司:", "計劃名稱:", "保單號碼:", "保單生效日:",
"保單持有人", "受保人", "保費及征費", "應繳總保費", "保單持有人:", "受保人:", "保費及征費:", "應繳總保費",
"備註:此金額未計入保費優惠,保費優惠待確認後通知客戶。", // 繁体段备注按需求稿原文(「备注」「客户」保留稿中用字)
"备注:此金額未計入保費優惠,保費優惠待確認後通知客户。",
"保費到期日", "寬限期到期日", "保費到期日", "寬限期到期日",
"以下保單的保費將於 ", " 到期,請在此日期前繳付應繳保費。", "以下保單的保費將於", "到期,請在此日期前繳付應繳保費。保單資料如下:",
"以下保單的保費已於 ", " 到期,寬限期將於 ", " 屆滿,請盡快跟進確認繳費情況。"); "以下保單的保費已於", "到期,寬限期將於", "屆滿,請盡快跟進確認繳費情況。保單資料如下:");
} }
} }
package com.yd.csf.service.component; package com.yd.csf.service.component.renewal;
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.EasyExcel;
import com.yd.csf.service.dto.RenewalDuePolicy; import com.yd.csf.service.component.TemplateStyleStrategy;
import com.yd.csf.service.dto.RenewalReminderData;
import com.yd.csf.service.vo.RenewalPolicyExportDTO; import com.yd.csf.service.vo.RenewalPolicyExportDTO;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
......
package com.yd.csf.service.utils; package com.yd.csf.service.component.renewal;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
......
package com.yd.csf.service.dto; package com.yd.csf.service.component.renewal;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
......
package com.yd.csf.service.service; package com.yd.csf.service.service;
import com.yd.csf.service.dto.RenewalReminderData; import com.yd.csf.service.component.renewal.RenewalReminderData;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.YearMonth; import java.time.YearMonth;
......
...@@ -2,12 +2,12 @@ package com.yd.csf.service.service.impl; ...@@ -2,12 +2,12 @@ package com.yd.csf.service.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yd.csf.service.dao.PolicyFollowMapper; import com.yd.csf.service.dao.PolicyFollowMapper;
import com.yd.csf.service.dto.RenewalDuePolicy; import com.yd.csf.service.component.renewal.RenewalDuePolicy;
import com.yd.csf.service.dto.RenewalReminderData; import com.yd.csf.service.component.renewal.RenewalReminderData;
import com.yd.csf.service.enums.PolicyFollowStatusEnum; import com.yd.csf.service.enums.PolicyFollowStatusEnum;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import com.yd.csf.service.service.RenewalReminderQueryService; import com.yd.csf.service.service.RenewalReminderQueryService;
import com.yd.csf.service.utils.RenewalDueDateCalculator; import com.yd.csf.service.component.renewal.RenewalDueDateCalculator;
import com.yd.csf.service.utils.SimpleDateUtils; import com.yd.csf.service.utils.SimpleDateUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
......
...@@ -2,6 +2,7 @@ package com.yd.csf.service.vo; ...@@ -2,6 +2,7 @@ package com.yd.csf.service.vo;
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.yd.csf.service.component.renewal.RenewalPremiumUtils;
import com.yd.csf.service.model.PolicyFollow; import com.yd.csf.service.model.PolicyFollow;
import lombok.Data; import lombok.Data;
...@@ -152,10 +153,10 @@ public class RenewalPolicyExportDTO { ...@@ -152,10 +153,10 @@ public class RenewalPolicyExportDTO {
/** /**
* 总保费及征费 = 期交保费 + 保单征费;两者均无值时留空,征费为空或非数字按 0 处理。 * 总保费及征费 = 期交保费 + 保单征费;两者均无值时留空,征费为空或非数字按 0 处理。
* 口径与逐单邮件共用 {@link com.yd.csf.service.utils.RenewalPremiumUtils}。 * 口径与逐单邮件共用 {@link RenewalPremiumUtils}。
*/ */
private static String buildTotalPremiumAndLevy(PolicyFollow p) { private static String buildTotalPremiumAndLevy(PolicyFollow p) {
BigDecimal total = com.yd.csf.service.utils.RenewalPremiumUtils.totalPremiumAndLevy(p); BigDecimal total = RenewalPremiumUtils.totalPremiumAndLevy(p);
return total == null ? null : total.toPlainString(); return total == null ? null : total.toPlainString();
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment