Commit 24559d5c by jianan

feat(转介人门户): 前端改版接口补全 + 佣金弹窗口径调整

对接前端 BACKEND-API-CHANGES v1.0,全部为新增字段,已在 local-prod
核对环境实测通过:

- 月结单详情:新增 mpfRemark/otherRemark/remark 与 payouts[] 打款
  细项(salary_remittance 全量,过滤批量生成的空白占位行);
  items[] 新增 referrerName/periodPremium/paymentFrequency/
  paymentTerm/remark
- 保单列表:新增 paymentFrequency/nextPremiumDate(取续保日期)/
  effectiveDate
- 佣金弹窗:保留名目粒度(销售佣金/管理奖等分行、带预计/实际出账
  日),失效段不再混入明细行,新增头部合计 paidTotal/pipelineTotal/
  retainedTotal/lapsedTotal
- paymentFrequency 出口统一 ANNUAL/SEMI_ANNUAL/QUARTERLY/MONTHLY/
  SINGLE(趸缴)
- brokerRatio/myRatio 出口统一 0~1 小数(兼容库里三种脏格式)
- salary 表新增 mpf_remark 列(DDL 见 sql/salary_add_mpf_remark.sql,
  生产已执行)
parent 05599dc3
...@@ -96,6 +96,12 @@ public class Salary implements Serializable { ...@@ -96,6 +96,12 @@ public class Salary implements Serializable {
private BigDecimal mpfAmount; private BigDecimal mpfAmount;
/** /**
* MPF事项的备注
*/
@TableField("mpf_remark")
private String mpfRemark;
/**
* 其他调整总金额(单位:HKD) * 其他调整总金额(单位:HKD)
*/ */
@TableField("other_amount") @TableField("other_amount")
......
...@@ -35,6 +35,7 @@ import com.yd.csf.service.vo.ReferrerPolicyListVO; ...@@ -35,6 +35,7 @@ import com.yd.csf.service.vo.ReferrerPolicyListVO;
import com.yd.csf.service.vo.ReferrerPolicyVO; import com.yd.csf.service.vo.ReferrerPolicyVO;
import com.yd.csf.service.vo.ReferrerStatementDetailVO; import com.yd.csf.service.vo.ReferrerStatementDetailVO;
import com.yd.csf.service.vo.ReferrerStatementItemVO; import com.yd.csf.service.vo.ReferrerStatementItemVO;
import com.yd.csf.service.vo.ReferrerStatementPayoutVO;
import com.yd.csf.service.vo.ReferrerStatementVO; import com.yd.csf.service.vo.ReferrerStatementVO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -205,7 +206,10 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -205,7 +206,10 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
vo.setSalaryNo(salary.getSalaryNo()); vo.setSalaryNo(salary.getSalaryNo());
vo.setGrossAmount(n2(salary.getGrossAmount())); vo.setGrossAmount(n2(salary.getGrossAmount()));
vo.setMpfAmount(n2(salary.getMpfAmount())); vo.setMpfAmount(n2(salary.getMpfAmount()));
vo.setMpfRemark(salary.getMpfRemark());
vo.setOtherAmount(n2(salary.getOtherAmount())); vo.setOtherAmount(n2(salary.getOtherAmount()));
vo.setOtherRemark(salary.getOtherRemark());
vo.setRemark(salary.getRemark());
vo.setPaidAmount(n2(salary.getPaidAmount())); vo.setPaidAmount(n2(salary.getPaidAmount()));
// 发放日 / 银行尾号 // 发放日 / 银行尾号
...@@ -215,10 +219,28 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -215,10 +219,28 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
vo.setPayoutDate(toLocalDate(accounts.get(0).getFortuneAccountDate())); vo.setPayoutDate(toLocalDate(accounts.get(0).getFortuneAccountDate()));
} }
List<SalaryRemittance> remittances = salaryRemittanceService.queryList(salaryBizId); List<SalaryRemittance> remittances = salaryRemittanceService.queryList(salaryBizId);
// 批量生成时固定写两条,第二条常为空白占位行,过滤掉
if (remittances != null) {
remittances = remittances.stream()
.filter(r -> StringUtils.isNotBlank(r.getBankName())
|| (r.getAmount() != null && r.getAmount().signum() != 0))
.collect(Collectors.toList());
}
if (remittances != null && !remittances.isEmpty()) { if (remittances != null && !remittances.isEmpty()) {
// 顶层 bankName/accountEndNo 保留兼容(取首笔);完整列表走 payouts
SalaryRemittance remittance = remittances.get(0); SalaryRemittance remittance = remittances.get(0);
vo.setBankName(remittance.getBankName()); vo.setBankName(remittance.getBankName());
vo.setAccountEndNo(remittance.getAccountEndNo()); vo.setAccountEndNo(remittance.getAccountEndNo());
vo.setPayouts(remittances.stream().map(rem -> {
ReferrerStatementPayoutVO payout = new ReferrerStatementPayoutVO();
payout.setBankName(rem.getBankName());
payout.setAccountEndNo(rem.getAccountEndNo());
payout.setCurrency(rem.getCurrency());
payout.setPaidAmount(n4(rem.getAmount()));
payout.setExchangeRate(n4(rem.getExchangeRate()));
payout.setRemark(rem.getRemark());
return payout;
}).collect(Collectors.toList()));
} }
vo.setItems(buildStatementItems(brokerBizId, salary.getMonth())); vo.setItems(buildStatementItems(brokerBizId, salary.getMonth()));
...@@ -270,6 +292,14 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -270,6 +292,14 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
for (ExpectedFortune row : rows) { for (ExpectedFortune row : rows) {
appendCommissionSegments(items, row); appendCommissionSegments(items, row);
} }
// 失效段不混入明细行(名目粒度保留),金额单独合计交代去向
BigDecimal lapsedTotal = items.stream()
.filter(it -> ReferrerCommissionStage.LAPSED.name().equals(it.getStage()))
.map(it -> defaultZero(it.getAmount()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
items = items.stream()
.filter(it -> !ReferrerCommissionStage.LAPSED.name().equals(it.getStage()))
.collect(Collectors.toList());
ReferrerPolicyCommissionVO vo = new ReferrerPolicyCommissionVO(); ReferrerPolicyCommissionVO vo = new ReferrerPolicyCommissionVO();
vo.setPolicyNo(policyNo); vo.setPolicyNo(policyNo);
...@@ -284,6 +314,10 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -284,6 +314,10 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
.filter(it -> !ReferrerCommissionStage.LAPSED.name().equals(it.getStage())) .filter(it -> !ReferrerCommissionStage.LAPSED.name().equals(it.getStage()))
.map(ReferrerPolicyCommissionItemVO::getAmount) .map(ReferrerPolicyCommissionItemVO::getAmount)
.reduce(BigDecimal.ZERO, BigDecimal::add))); .reduce(BigDecimal.ZERO, BigDecimal::add)));
vo.setPaidTotal(n2(sumStage(items, ReferrerCommissionStage.PAID)));
vo.setPipelineTotal(n2(sumStage(items, ReferrerCommissionStage.PIPELINE)));
vo.setRetainedTotal(n2(sumStage(items, ReferrerCommissionStage.RETAINED)));
vo.setLapsedTotal(n2(lapsedTotal));
return vo; return vo;
} }
...@@ -433,7 +467,11 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -433,7 +467,11 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
vo.setCurrency(policy.getCurrency()); vo.setCurrency(policy.getCurrency());
vo.setFullPremium(n4(policy.getTotalPaymentPremium())); vo.setFullPremium(n4(policy.getTotalPaymentPremium()));
vo.setFullPremiumHkd(n4(policy.getTotalPaymentPremiumHkd())); vo.setFullPremiumHkd(n4(policy.getTotalPaymentPremiumHkd()));
vo.setMyRatio(policyBroker == null ? null : policyBroker.getBrokerRatio()); vo.setMyRatio(policyBroker == null ? null : ratioText(policyBroker.getBrokerRatio()));
vo.setPaymentFrequency(mapPaymentFrequency(policy.getPaymentFrequency()));
// 下次缴费日取续保日期(同事前端口径,见 BACKEND-API-CHANGES v1.0)
vo.setNextPremiumDate(toLocalDate(policy.getRenewalDate()));
vo.setEffectiveDate(toLocalDate(policy.getEffectiveDate()));
vo.setStatus(policy.getStatus()); vo.setStatus(policy.getStatus());
return vo; return vo;
} }
...@@ -497,15 +535,20 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -497,15 +535,20 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
return fortunes.stream().map(fortune -> { return fortunes.stream().map(fortune -> {
ReferrerStatementItemVO item = new ReferrerStatementItemVO(); ReferrerStatementItemVO item = new ReferrerStatementItemVO();
item.setPolicyNo(fortune.getPolicyNo()); item.setPolicyNo(fortune.getPolicyNo());
item.setReferrerName(fortune.getBroker());
Policy policy = policyMap.get(fortune.getPolicyNo()); Policy policy = policyMap.get(fortune.getPolicyNo());
if (policy != null) { if (policy != null) {
item.setPolicyHolder(policy.getPolicyHolder()); item.setPolicyHolder(policy.getPolicyHolder());
item.setInsuranceCompany(policy.getInsuranceCompany()); item.setInsuranceCompany(policy.getInsuranceCompany());
item.setProductName(policy.getProductName()); item.setProductName(policy.getProductName());
item.setPeriodPremium(n4(policy.getPaymentPremium()));
item.setPaymentFrequency(mapPaymentFrequency(policy.getPaymentFrequency()));
item.setPaymentTerm(toPaymentTerm(policy.getPaymentTerm()));
} }
item.setFortunePeriod(fortune.getFortunePeriod()); item.setFortunePeriod(fortune.getFortunePeriod());
item.setFortuneName(fortune.getFortuneName()); item.setFortuneName(fortune.getFortuneName());
item.setBrokerRatio(ratioMap.get(fortune.getExpectedFortuneBizId())); // brokerRatio 出口统一 0~1 小数(库里有 "60"/"60%"/"0.6" 三种写法)
item.setBrokerRatio(ratioText(ratioMap.get(fortune.getExpectedFortuneBizId())));
item.setOriginalCurrency(fortune.getOriginalCurrency()); item.setOriginalCurrency(fortune.getOriginalCurrency());
item.setOriginalAmount(n4(fortune.getOriginalAmount())); item.setOriginalAmount(n4(fortune.getOriginalAmount()));
item.setOriginalToHkdRate(n4(fortune.getOriginalToHkdRate())); item.setOriginalToHkdRate(n4(fortune.getOriginalToHkdRate()));
...@@ -599,6 +642,67 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService { ...@@ -599,6 +642,67 @@ public class ReferrerPortalServiceImpl implements IReferrerPortalService {
} }
} }
/**
* 指定阶段的金额合计。
*/
private BigDecimal sumStage(List<ReferrerPolicyCommissionItemVO> items, ReferrerCommissionStage stage) {
return items.stream()
.filter(it -> stage.name().equals(it.getStage()))
.map(it -> defaultZero(it.getAmount()))
.reduce(BigDecimal.ZERO, BigDecimal::add);
}
/**
* 缴费频率出口统一为前端约定枚举:ANNUAL / SEMI_ANNUAL / QUARTERLY / MONTHLY / SINGLE(趸缴)。
* 库内 MONTH/SEASON/YEAR/FULL_PAYMENT 之外的值不下发(null)。
*/
private String mapPaymentFrequency(String freq) {
if (StringUtils.isBlank(freq)) {
return null;
}
if (PaymentFrequencyEnum.YEAR.getItemValue().equals(freq)) {
return "ANNUAL";
}
if (PaymentFrequencyEnum.SEASON.getItemValue().equals(freq)) {
return "QUARTERLY";
}
if (PaymentFrequencyEnum.MONTH.getItemValue().equals(freq)) {
return "MONTHLY";
}
if (PaymentFrequencyEnum.FULL_PAYMENT.getItemValue().equals(freq)) {
return "SINGLE";
}
return null;
}
/**
* 缴费年期(年)。policy.payment_term 为 Object,兼容 "5" / "5年" / 数字;解析不出返回 null。
*/
private Integer toPaymentTerm(Object term) {
if (term == null) {
return null;
}
String digits = term.toString().replaceAll("[^0-9.]", "");
if (digits.isEmpty()) {
return null;
}
try {
return new BigDecimal(digits).intValue();
} catch (NumberFormatException e) {
return null;
}
}
/**
* 分成比例出口统一为 0~1 小数字符串(库里有 "60" / "60%" / "0.6" 三种写法),空值返回 null。
*/
private String ratioText(String ratio) {
if (StringUtils.isBlank(ratio)) {
return null;
}
return ratioMultiplier(ratio).stripTrailingZeros().toPlainString();
}
private ReferrerPolicyCommissionItemVO buildCommissionSegment( private ReferrerPolicyCommissionItemVO buildCommissionSegment(
ReferrerCommissionStage stage, ExpectedFortune row, BigDecimal amount) { ReferrerCommissionStage stage, ExpectedFortune row, BigDecimal amount) {
ReferrerPolicyCommissionItemVO it = new ReferrerPolicyCommissionItemVO(); ReferrerPolicyCommissionItemVO it = new ReferrerPolicyCommissionItemVO();
......
...@@ -11,7 +11,8 @@ import java.time.LocalDate; ...@@ -11,7 +11,8 @@ import java.time.LocalDate;
* 转介人保单佣金段:一个保单年度的钱按「钱的位置」(D4.1) 拆分后的一段。 * 转介人保单佣金段:一个保单年度的钱按「钱的位置」(D4.1) 拆分后的一段。
* *
* <p>部分出账的年度会产出两段:{@code PAID(已出账金额)} + {@code PIPELINE(待出账金额)}, * <p>部分出账的年度会产出两段:{@code PAID(已出账金额)} + {@code PIPELINE(待出账金额)},
* 保证各段金额相加恒等于该年度应得。</p> * 保证各段金额相加恒等于该年度应得。失效段不下发明细行,
* 由 {@code ReferrerPolicyCommissionVO.lapsedTotal} 单独交代。</p>
*/ */
@Data @Data
public class ReferrerPolicyCommissionItemVO implements Serializable { public class ReferrerPolicyCommissionItemVO implements Serializable {
......
...@@ -29,7 +29,27 @@ public class ReferrerPolicyCommissionVO implements Serializable { ...@@ -29,7 +29,27 @@ public class ReferrerPolicyCommissionVO implements Serializable {
private java.math.BigDecimal renewalCommission; private java.math.BigDecimal renewalCommission;
/** /**
* 各年度佣金明细 * 已发合计(HKD)
*/
private java.math.BigDecimal paidTotal;
/**
* 在途合计(HKD)
*/
private java.math.BigDecimal pipelineTotal;
/**
* 保留合计(HKD)
*/
private java.math.BigDecimal retainedTotal;
/**
* 失效合计(HKD,单独交代去向,不混入明细行)
*/
private java.math.BigDecimal lapsedTotal;
/**
* 各年度佣金明细(名目粒度,失效段不在其中)
*/ */
private List<ReferrerPolicyCommissionItemVO> items; private List<ReferrerPolicyCommissionItemVO> items;
} }
\ No newline at end of file
package com.yd.csf.service.vo; package com.yd.csf.service.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDate;
/** /**
* 转介人名下保单。 * 转介人名下保单。
...@@ -54,11 +56,28 @@ public class ReferrerPolicyVO implements Serializable { ...@@ -54,11 +56,28 @@ public class ReferrerPolicyVO implements Serializable {
private BigDecimal fullPremiumHkd; private BigDecimal fullPremiumHkd;
/** /**
* 我的介绍费占比 * 我的介绍费占比(统一 0~1 小数,0.35 表示 35%)
*/ */
private String myRatio; private String myRatio;
/** /**
* 缴费频率:ANNUAL / SEMI_ANNUAL / QUARTERLY / MONTHLY / SINGLE(趸缴)
*/
private String paymentFrequency;
/**
* 下次缴费日(取续保日期)
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDate nextPremiumDate;
/**
* 保单生效日
*/
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private LocalDate effectiveDate;
/**
* 保单状态 * 保单状态
*/ */
private String status; private String status;
......
...@@ -42,11 +42,26 @@ public class ReferrerStatementDetailVO implements Serializable { ...@@ -42,11 +42,26 @@ public class ReferrerStatementDetailVO implements Serializable {
private BigDecimal mpfAmount; private BigDecimal mpfAmount;
/** /**
* MPF事项的说明(如「強積金法定供款」)
*/
private String mpfRemark;
/**
* 其他调整总金额(HKD) * 其他调整总金额(HKD)
*/ */
private BigDecimal otherAmount; private BigDecimal otherAmount;
/** /**
* 其他调整的说明
*/
private String otherRemark;
/**
* 整张结单级别的其他备注
*/
private String remark;
/**
* 实发总金额(HKD) * 实发总金额(HKD)
*/ */
private BigDecimal paidAmount; private BigDecimal paidAmount;
...@@ -68,6 +83,11 @@ public class ReferrerStatementDetailVO implements Serializable { ...@@ -68,6 +83,11 @@ public class ReferrerStatementDetailVO implements Serializable {
private String accountEndNo; private String accountEndNo;
/** /**
* 打款细项:一笔到账一条
*/
private List<ReferrerStatementPayoutVO> payouts;
/**
* 逐笔保单明细 * 逐笔保单明细
*/ */
private List<ReferrerStatementItemVO> items; private List<ReferrerStatementItemVO> items;
......
...@@ -24,6 +24,31 @@ public class ReferrerStatementItemVO implements Serializable { ...@@ -24,6 +24,31 @@ public class ReferrerStatementItemVO implements Serializable {
private String policyHolder; private String policyHolder;
/** /**
* 该保单的转介人姓名(收款转介人,非投保人)
*/
private String referrerName;
/**
* 期交保费(每期保费,以 originalCurrency 计价)
*/
private BigDecimal periodPremium;
/**
* 缴费频率:ANNUAL / SEMI_ANNUAL / QUARTERLY / MONTHLY / SINGLE(趸缴)
*/
private String paymentFrequency;
/**
* 缴费年期(年);终身缴费/不适用为 null
*/
private Integer paymentTerm;
/**
* 该条佣金明细的备注
*/
private String remark;
/**
* 保险公司 * 保险公司
*/ */
private String insuranceCompany; private String insuranceCompany;
......
package com.yd.csf.service.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 转介人月结单打款细项:一笔到账一条(salary_remittance)。
*/
@Data
public class ReferrerStatementPayoutVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 收款银行名称
*/
private String bankName;
/**
* 账户尾号
*/
private String accountEndNo;
/**
* 该笔到账币种(ISO 4217)
*/
private String currency;
/**
* 该笔发放金额(以 currency 计价)
*/
private BigDecimal paidAmount;
/**
* 汇率(原币 → HKD);HKD 时为 1
*/
private BigDecimal exchangeRate;
/**
* 该笔打款备注
*/
private String remark;
}
-- 转介人门户月结单详情:MPF 事项说明(同事前端改版 BACKEND-API-CHANGES v1.0)
-- 上线时在生产 salary 表执行;test/prod 结构需同步
ALTER TABLE salary ADD COLUMN mpf_remark varchar(255) NULL COMMENT 'MPF事项的备注' AFTER mpf_amount;
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