Commit 1e6b317f by 王德峰

bb 项目初始化

    清理部分
    清理wk任务
parent da9236e7
/**
* abssqr.comInc.
* Copyright(c)2019-2019AllRightsReserved.
*/
package com.abssqr.plat.biz.api.report;
import com.abssqr.plat.biz.shared.report.wk.WkManagerReportBuilder;
import com.abssqr.plat.biz.support.ServiceSupport;
import com.abssqr.plat.common.facade.enums.CommonErrorCodeEnum;
import com.abssqr.plat.common.facade.enums.ReportTypeEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.report.DailyReportDateField;
import com.abssqr.plat.common.facade.model.report.MonthReportDateField;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.model.report.wk.WkManagerReport;
import com.abssqr.plat.common.facade.param.base.CommonPlanQryParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormAstParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormMgrParam;
import com.abssqr.plat.common.facade.service.report.ReportService;
import com.abssqr.plat.common.facade.validation.Valid;
import com.abssqr.plat.common.model.exception.AbssqrBizException;
import com.abssqr.plat.common.model.repo.plan.PlanRepo;
import com.abssqr.plat.common.model.repo.report.PlanReportRepo;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.SystemDateUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
*
* @author yangcheng
* @version ReportServiceImpl.java, v0.12019-07-0114:19 yangchengExp$
*/
@Component
public class ReportServiceImpl extends ServiceSupport implements ReportService {
//打印日志问题:需要打印错误日志,开启服务日志,日志服务需要展示什么参数,然后在去查询,拼接业务数据然后返回;,并且起事务;
//设置时间段问题当前日期情况
private static final Logger LOGGER = LoggerFactory.getLogger(ReportServiceImpl.class);
@Autowired
private PlanReportRepo planReportRepo;
@Autowired
private WkManagerReportBuilder wkManagerReportBuilder;
@Autowired
private PlanRepo planRepo;
/**
* 计划报表
* @param param
* @return
*/
@Override
public WkManagerReport getReportFormPlan(@Valid ReportFormMgrParam param) {
return this.doQry(param, () -> {
String begin = param.getBeginTime();
String end = param.getEndTime();
//检查能否解析日期字段
MonthReportDateField beginField = new MonthReportDateField();
beginField.parse(begin);
MonthReportDateField endField = new MonthReportDateField();
endField.parse(end);
Date beginDate = DateTimeUtil.parseInTolerance(begin);
Date endDate = DateTimeUtil.parseInTolerance(end);
dateJudge(beginDate, endDate);
//当判断通过的时候打印日志
LogUtil.info(LOGGER, "计划报表统计:计划编号={0}, 开始时间={1}, 结束时间={2},",
param.getPlanNo(), begin, end);
PlanBase planBase = planRepo.getPlanByNo(param.getPlanNo());
return wkManagerReportBuilder.getReport(planBase,begin,end);
});
}
/**
* 资产报表
* @param param
* @return
*/
@Override
public List<PlanReport> getReportFormAst(@Valid ReportFormAstParam param) {
return this.doQry(param, () -> {
Date beginDate = DateTimeUtil.parseInTolerance(param.getBeginDate());
Date endDate = DateTimeUtil.parseInTolerance(param.getEndDate());
dateJudge(beginDate, endDate);
LogUtil.info(LOGGER, "资产报表统计:计划编号={0}, 开始时间={1}, 结束时间={2},",
param.getPlanNo(), param.getBeginDate(), param.getEndDate());
DailyReportDateField beginField = new DailyReportDateField();
beginField.setRptDate(beginDate);
DailyReportDateField endField = new DailyReportDateField();
endField.setRptDate(endDate);
return planReportRepo.getPlansByDate(param.getPlanNo(), beginField.desc(), endField.desc(),
ReportTypeEnum.RPT001);
});
}
@Override
public List<PlanReport> getReportFormMonthEnd(@Valid CommonPlanQryParam param) {
return this.doQry(param, () -> {
LogUtil.info(LOGGER, "资产报表统计:计划编号={0}", param.getPlanNo());
PlanBase planBase = planRepo.getPlanByNo(param.getPlanNo());
Date effectDate = planBase.getEffectDate();
Date curDate = SystemDateUtil.getSystemDate();
List<String> monthEndDate = Lists.newArrayList();
Date startDate = DateTimeUtil.parseFromYMD(
DateTimeUtil.format(effectDate, DateTimeUtil.FORMAT_DATE_YYYYMM) + "01");
// 当前日期所在月,肯定没有月报产生
while (DateTimeUtil.calMonthDiff(startDate, curDate) > 0) {
startDate = DateTimeUtil.addMonths(startDate, 1);
monthEndDate.add(DateTimeUtil.formatYMD(DateTimeUtil.addDays(startDate, -1)));
}
if (CollectionUtils.isEmpty(monthEndDate)) {
throw new AbssqrBizException(
MessageUtil.formatMsg("计划生效日期[{0}]和当前日期[{1}]间,无法生成月末报表", effectDate, curDate));
}
return planReportRepo.getPlansByDateList(param.getPlanNo(), ReportTypeEnum.RPT001, monthEndDate);
});
}
private boolean dateJudge(Date begin, Date end) {
Date nowTime = DateTimeUtil.getStandardDate(SystemDateUtil.getSystemDate());
if (DateTimeUtil.calcDayDiff(end, begin) < 0) {
String errorText = MessageUtil.formatMsg("无法生成报表:结束时间{0}小于开始时间{1}", end, begin);
LogUtil.error(LOGGER, errorText);
throw new AbssqrBizException(errorText, CommonErrorCodeEnum.INVALID_PARAM);
}
if (DateTimeUtil.calcDayDiff(end, nowTime) >= 0) {
String errorText = MessageUtil.formatMsg("无法生成报表:结束时间[{0}]必须小于当前时间[{1}],否则报表还未生成", end, nowTime);
LogUtil.error(LOGGER, errorText);
throw new AbssqrBizException(errorText, CommonErrorCodeEnum.INVALID_PARAM);
}
return true;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyBackMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutorTemp;
import com.abssqr.plat.biz.shared.handler.LoanAstBuyBackMatchHandler;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.SystemDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 资产回购匹配执行器
*/
@Component
public class LoanAstBuyBackMatchExecutor extends DispatcherExecutorTemp<CommonTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(LoanAstBuyBackMatchExecutor.class);
@Autowired
private CommonTaskRepository commonTaskRepository;
@Autowired
private LoanAstBuyBackMatchHandler loanAstBuyBackMatchHandler;
@Override
public CommonTask doExecute(CommonTask node) {
LogUtil.info(LOGGER, "执行回购匹配任务[{0}]-start", node.getContext());
loanAstBuyBackMatchHandler.execute(node.getContext(), status -> {
if (TaskStatusEnum.SUCCESS == status) {
node.setTaskStatus(status);
markSuccess(node);
} else {
markFail(node, "执行回购匹配任务失败");
}
LogUtil.info(LOGGER, "执行回购匹配任务[{0}]-end,status=[{1}]", node.getContext(), status);
});
return node;
}
@Override
protected CommonTask markSuccess(CommonTask node) {
commonTaskRepository.updateTaskStatus(node.getId(), TaskStatusEnum.SUCCESS, TaskStatusEnum.EXECUTING, "");
return node;
}
@Override
protected CommonTask markFail(CommonTask node, String failMessage) {
// 因异常引起的重试
Date nextTime = DateTimeUtil.addSecond(SystemDateUtil.getSystemDate(), 60);
String msg = failMessage.length() > 2000 ? failMessage.substring(0, 2000) : failMessage;
commonTaskRepository.updateTaskExep(nextTime, node.getId(), msg);
return node;
}
@Override
protected CommonTask markException(CommonTask node, String failMessage) {
return markFail(node, failMessage);
}
@Override
protected String getName() {
return LoanAstBuyBackMatchStarter.JOB_NAME;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyBackMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.common.facade.enums.CommonTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.core.service.ast.LoanAstBuyBackManager;
import com.abssqr.plat.core.service.host.HostManager;
import com.general.system.common.util.SystemDateUtil;
import com.general.system.common.util.ThreadUtil;
import com.general.system.common.util.VarChecker;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.List;
import java.util.stream.Collectors;
/**
* 资产转让
*
* @author bangis.wangdf
* @version com.abssqr.plat.biz.shared.task.task: AstTrTaskLoader.java, v 0.1 2018-01-08 00:59 hongwei.wang Exp $
*/
@Component
public class LoanAstBuyBackMatchLoader implements DispatcherLoader<CommonTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(LoanAstBuyBackMatchLoader.class);
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private JobControlRepository jobControlRepository;
@Autowired
private CommonTaskRepository commonTaskRepository;
@Autowired
private HostManager hostManager;
private static long sleepTime = 1000 * 60;
/**
* 装载待分发节点
*
* @param size
* @return
*/
@Override
public List<CommonTask> loadToDoNodes(int size) {
ThreadUtil.sleep(sleepTime, LOGGER);
return transactionTemplate.execute(transactionStatus -> {
// job加锁
jobControlRepository.lockByJobName(LoanAstBuyBackMatchStarter.JOB_NAME);
// 获取回购筛选任务
List<CommonTask> existsTask = commonTaskRepository.selectUnifinishTaskByType(CommonTaskTypeEnum.BUY_BACK_MATCH);
// 过滤 排除非初始化的和下次执行时间大于当前时间的任务
existsTask = existsTask.stream()
.filter(item -> item.getTaskStatus() == TaskStatusEnum.INIT
&& SystemDateUtil.getSystemDate().compareTo(item.getNextExecTime()) > 0)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(existsTask)) {
int cnt = commonTaskRepository
.updateTaskExec(SystemDateUtil.getSystemDate(), hostManager.getHostInfo().getHostName(),
existsTask);
VarChecker.checkArgument(cnt==existsTask.size(),"[LoanAstBuyBackMatchLoader] - 更新条数与预期不符,可能存在并发问题");
}
return existsTask;
});
}
/**
* 设置休眠时间 测试用
* @param time
*/
public void setSleepTime(Long time){
sleepTime = time;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyBackMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutor;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherStarter;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.core.service.host.HostManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author bangis.wangdf
* @version com.abssqr.plat.biz.shared.task.task: AstTrTaskDispatcherManager.java, v 0.1 2018-01-08 02:42 hongwei
* .wang Exp $
*/
@Component
public class LoanAstBuyBackMatchStarter extends DispatcherStarter<CommonTask> {
@Autowired
private LoanAstBuyBackMatchExecutor loanAstBuyBackMatchExecutor;
@Autowired
private LoanAstBuyBackMatchLoader loanAstBuyBackMatchLoader;
@Autowired
private HostManager hostManager;
@Autowired
private CommonTaskRepository commonTaskRepository;
public static String JOB_NAME = "LoanAstBuyBackMatchStarter";
@Value("${dispatcher.buyBack.coreSize}")
private int coreSize;
@Value("${dispatcher.buyBack.maxSize}")
private int maxSize;
@Value("${dispatcher.buyBack.hungrySize}")
private int hungrySize;
@Value("${dispatcher.buyBack.queueSize}")
private int queueSize = 200;
@Override
protected void recovery() {
commonTaskRepository.updateHangTasksByIp(hostManager.getHostInfo().getHostName());
}
@Override
public String getName() {
return JOB_NAME;
}
@Override
protected int getCoreSize() {
return coreSize;
}
@Override
protected int getMaxSize() {
return maxSize;
}
@Override
protected int getQueueSize() {
return queueSize;
}
@Override
protected int getHungrySize() {
return hungrySize;
}
@Override
protected DispatcherLoader<CommonTask> getLoader() {
return loanAstBuyBackMatchLoader;
}
@Override
protected DispatcherExecutor<CommonTask> getExecutor() {
return loanAstBuyBackMatchExecutor;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyback;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutorTemp;
import com.abssqr.plat.biz.shared.handler.LoanAstBuyBackHandler;
import com.abssqr.plat.common.dal.mysql.auto.dao.TrTaskDAO;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.domain.task.TrTask;
import com.abssqr.plat.common.model.repo.tr.TrTaskRepo;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.SystemDateUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 资产回购交易执行器
*
* @author hanfei
* @version $Id: LoanAstBuyBackExecutor.java, v 0.1 2020-02-11 5:12 PM hanfei Exp $
*/
@Component
public class LoanAstBuyBackExecutor extends DispatcherExecutorTemp<TrTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(
LoanAstBuyBackExecutor.class);
// 单位(秒)
private final static int DEFAULT_STEP = 5;
@Autowired
private LoanAstBuyBackHandler loanAstBuyBackHandler;
@Autowired
private TrTaskRepo trTaskRepo;
@Override
public TrTask doExecute(TrTask node) {
LogUtil.info(LOGGER, "回购处理astNo[{0}]batchNo[{1}]packType[{2}]",
node.getAstNo(), node.getBatchNo(), node.getPackType());
boolean result = false;
Date befDt = SystemDateUtil.getSystemDate();
try {
// 加锁捞取 幂等判断
TrTask lockedNode = trTaskRepo.lockByIdNowait(node.getId());
if (null == lockedNode || lockedNode.getTaskStatus() != TaskStatusEnum.EXECUTING) {
LogUtil.warn(LOGGER, "资产回购任务[{0}]状态[{1}]不为执行中,可能存在并发问题", node.getId(),
(lockedNode != null) ? lockedNode.getTaskStatus() : "-");
return lockedNode;
}
// 执行回购交易操作
result = loanAstBuyBackHandler.astBuyBackExecute(node);
if (result) {
return markSuccess(node);
} else {
LogUtil.error(LOGGER, "资产回购任务[{0}]状态[{1}]执行失败", node.getAstNo(), node);
return markFail(node, "资产回购执行失败");
}
} finally {
Date endDt = SystemDateUtil.getSystemDate();
LogUtil.info(LOGGER, "[LoanAstBuyBackExecutor] astId=[{0}], res={1}, elipse={2}ms",
node.getAstNo(), result, (endDt.getTime() - befDt.getTime()));
}
}
@Autowired
private TrTaskDAO trTaskDAO;
/**
* 标记成功
*
* @param node
*/
@Override
protected TrTask markSuccess(TrTask node) {
node.setTaskStatus(TaskStatusEnum.SUCCESS);
trTaskDAO.updateTaskStatus(node.getId(), "", TaskStatusEnum.SUCCESS.getCode());
return node;
}
/**
* 标记失败
*
* @param node
* @param failMessage
*/
@Override
protected TrTask markFail(TrTask node, String failMessage) {
node.setTaskStatus(TaskStatusEnum.FAILURE);
trTaskDAO.updateTaskStatus(node.getId(), failMessage, TaskStatusEnum.FAILURE.getCode());
return node;
}
/**
* 标记异常
*
* @param node
* @param failMessage
*/
@Override
protected TrTask markException(TrTask node, String failMessage) {
if (StringUtils.isBlank(failMessage)) {
failMessage = "回购交易执行失败";
}
node.setTaskStatus(TaskStatusEnum.INIT);
trTaskDAO.updateTaskExep(DateTimeUtil.addSecond(SystemDateUtil.getSystemDate(), DEFAULT_STEP),
node.getId(),
failMessage.length() > 2000 ? failMessage.substring(0, 1990) : failMessage);
return node;
}
@Override
protected String getName() {
return LoanAstBuyBackStarter.BUY_BACK_NAME;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyback;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.common.dal.mysql.auto.dao.TrTaskDAO;
import com.abssqr.plat.common.dal.mysql.auto.dataobject.TrTaskDO;
import com.abssqr.plat.common.facade.enums.AstPackTradeTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.convertor.TrTaskConvert;
import com.abssqr.plat.common.model.domain.ast.LoanAstBuyBackPack;
import com.abssqr.plat.common.model.domain.task.TrCtrTask;
import com.abssqr.plat.common.model.domain.task.TrTask;
import com.abssqr.plat.common.model.repo.tr.TrCtrTaskRepo;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.ast.LoanAstBuyBackManager;
import com.abssqr.plat.core.service.host.HostManager;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.SystemDateUtil;
import com.general.system.common.util.VarChecker;
import com.general.system.tool.util.ToolUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
import java.util.List;
/**
* 回购转让交易任务捞取
* @author hanfei
* @version $Id: LoanAstBuyBackLoader.java, v 0.1 2020-02-11 5:15 PM hanfei Exp $
*/
@Component
public class LoanAstBuyBackLoader implements DispatcherLoader<TrTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(
LoanAstBuyBackLoader.class);
@Autowired
private TrTaskDAO trTaskDAO;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private HostManager hostManager;
@Autowired
private TrCtrTaskRepo trCtrTaskRepo;
@Autowired
private LoanAstBuyBackManager loanAstBuyBackManager;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
/**
* 装载待分发节点
*
* @param size
* @return
*/
@Override
public List<TrTask> loadToDoNodes(int size) {
Date curDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
// 1、捞取回购任务总控STATUS为init
List<TrCtrTask> trCtrTasks = trCtrTaskRepo.queryInitCtrTaskList(
curDate, TaskStatusEnum.INIT, AstPackTradeTypeEnum.BUY_BACK_BIZ);
if (ToolUtil.isEmpty(trCtrTasks)) {
return Lists.newArrayList();
}
TrCtrTask trCtrTask = null;
for(TrCtrTask one : trCtrTasks){
// 2、捞取对应回购筛选包校验 PACK_STATUS为SCEEN_FIS 和 APPROVE_STATUS为PASSED
LoanAstBuyBackPack pack = loanAstBuyBackManager.getByPackCode(one.getPackCode());
if (pack.canExec()){
trCtrTask = one;
break;
}
}
// 没有可执行任务
if (trCtrTask == null){
return Lists.newArrayList();
}
Long canExecId = trCtrTask.getId();
return transactionTemplate.execute(transactionStatus -> {
TrCtrTask lockedCtrTask = trCtrTaskRepo.lockById(canExecId);
if (lockedCtrTask.getTaskStatus() != TaskStatusEnum.INIT) {
return Lists.newArrayList();
}
Long undoCnt = trTaskDAO.cntInitTaskByBatchNo(lockedCtrTask.getBatchNo());
if (undoCnt == 0) {
LogUtil.info(LOGGER, "转让控制[{0}]无待转任务,标记结束", lockedCtrTask);
trCtrTaskRepo.updateStatus(lockedCtrTask.getId(), TaskStatusEnum.SUCCESS);
return Lists.newArrayList();
}
trCtrTaskRepo.updateExecTms(lockedCtrTask.getId(), lockedCtrTask.getExecTimes() + 1);
// 3、捞取回购资产任务TASK_STATUS为init
List<TrTaskDO> taskDOS = trTaskDAO.selectInitTask(SystemDateUtil.getSystemDate(), Long.valueOf(size),
lockedCtrTask.getBatchNo(), AstPackTradeTypeEnum.BUY_BACK_BIZ.getCode());
if (CollectionUtils.isEmpty(taskDOS)) {
return Lists.newArrayList();
}
// 4、更新任务TASK_STATUS为exec
int count = trTaskDAO.updateTaskExec(SystemDateUtil.getSystemDate(),
hostManager.getHostInfo().getHostName(),
taskDOS);
VarChecker.checkEquals(count, taskDOS.size(), "[TaskLoader.loadToDoNodes]更新任务数跟期望数不一致,实际更新:{0},期望更新:{1}",
count,
taskDOS.size());
LogUtil.info(LOGGER, "转让控制[{0}]捞取[{1}]待执行任务", lockedCtrTask, count);
return TrTaskConvert.convertDTOs(taskDOS);
});
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.dispatcher.buyback;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutor;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherStarter;
import com.abssqr.plat.common.dal.mysql.auto.dao.TrTaskDAO;
import com.abssqr.plat.common.facade.enums.AstPackTradeTypeEnum;
import com.abssqr.plat.common.model.domain.task.TrTask;
import com.abssqr.plat.core.service.host.HostManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* 回购转让交易任务组件绑定
* @author hanfei
* @version $Id: LoanAstBuyBackLoader.java, v 0.1 2020-02-11 5:15 PM hanfei Exp $
*/
@Component
public class LoanAstBuyBackStarter extends DispatcherStarter<TrTask> {
@Autowired
private LoanAstBuyBackExecutor loanAstBuyBackExecutor;
@Autowired
private LoanAstBuyBackLoader loanAstBuyBackLoader;
@Autowired
private HostManager hostManager;
@Autowired
private TrTaskDAO trTaskDAO;
@Value("${dispatcher.tr.coreSize}")
private int coreSize;
@Value("${dispatcher.tr.maxSize}")
private int maxSize;
@Value("${dispatcher.tr.hungrySize}")
private int hungrySize;
@Value("${dispatcher.tr.queueSize}")
private int queueSize = 200;
@Override
protected void recovery() {
trTaskDAO.updateHangTasksByIp(
hostManager.getHostInfo().getHostName(), AstPackTradeTypeEnum.BUY_BACK_BIZ.getCode());
}
public static String BUY_BACK_NAME = "LoanAstBuyBackStarter";
@Override
public String getName() {
return BUY_BACK_NAME;
}
@Override
protected int getCoreSize() {
return coreSize;
}
@Override
protected int getMaxSize() {
return maxSize;
}
@Override
protected int getQueueSize() {
return queueSize;
}
@Override
protected int getHungrySize() {
return hungrySize;
}
@Override
protected DispatcherLoader<TrTask> getLoader() {
return loanAstBuyBackLoader;
}
@Override
protected DispatcherExecutor<TrTask> getExecutor() {
return loanAstBuyBackExecutor;
}
}
package com.abssqr.plat.biz.shared.dispatcher.capitalAssetMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutorTemp;
import com.abssqr.plat.biz.shared.handler.CapitalAstMatchHandler;
import com.abssqr.plat.biz.shared.handler.CapitalAstUnMatchHandler;
import com.abssqr.plat.common.facade.enums.CommonErrorCodeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.exception.AbssqrBizException;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.general.system.common.model.exception.BaseCommonException;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.SystemDateUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
/**
* 资金资产绑定/解绑
*/
@Component
public class PlanCapitalAssertMatchExecutor extends DispatcherExecutorTemp<CommonTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(
PlanCapitalAssertMatchExecutor.class);
@Autowired
CommonTaskRepository commonTaskRepository;
@Autowired
CapitalAstMatchHandler capitalAstMatchHandler;
@Autowired
CapitalAstUnMatchHandler capitalAstUnMatchHandler;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
@Autowired
TransactionTemplate transactionTemplate;
@Override
protected CommonTask doExecute(CommonTask node) {
Date absAccountDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
StringBuilder failMessage=new StringBuilder();
boolean isSucc=true;
switch (node.getTaskType()) {
//解绑任务
case CAPTITALASSERT_UNMATCH: {
LogUtil.info(LOGGER, "执行资金资产解绑-start", node.getContext());
String allocNo = node.getBizNo();
String planNo = node.getContext();
try{
isSucc=transactionTemplate.execute(status -> {
return capitalAstUnMatchHandler.execute(planNo,allocNo,absAccountDate);
});
}catch (Exception e){
LogUtil.error(LOGGER, "计划编号[{0}],兑付单编号[{1}]执行资金资产解绑失败错误信息:[3]",planNo,allocNo,e.getMessage());
isSucc=false;
failMessage.append(e.getMessage());
}
markStatus(isSucc,node,failMessage.toString());
LogUtil.info(LOGGER, "执行资金资产解绑-end", node.getContext());
break;
}
//解绑匹配任务
case UNMATCH_CAPTITALASSERT_MATCH: {
try{
isSucc=transactionTemplate.execute(status -> {
return doMatch(node);
});
}catch (Exception e){
LogUtil.error(LOGGER, "计划编号[{0}]执行资金资产匹配败错误信息:[3]",node.getContext(),e.getMessage());
isSucc=false;
failMessage.append(e.getMessage());
}
markStatus(isSucc,node,failMessage.toString());
break;
}
//同步匹配任务
case SYNC_CAPTITALASSERT_MATCH: {
try{
isSucc=transactionTemplate.execute(status -> {
return doMatch(node);
});
}catch (Exception e){
LogUtil.error(LOGGER, "计划编号[{0}]执行资金资产匹配败错误信息:[3]",node.getContext(),e.getMessage());
isSucc=false;
failMessage.append(e.getMessage());
}
markStatus(isSucc,node,failMessage.toString());
break;
}
default:{
throw new BaseCommonException("不支持的任务类型:"+node.getTaskType().getCode());
}
}
return node;
}
private boolean doMatch(CommonTask node){
LogUtil.info(LOGGER, "执行解绑匹配-start", node.getContext());
String bizNo = node.getBizNo();
String[] split = bizNo.split("-");
if(split==null){
throw new AbssqrBizException(
MessageUtil.formatMsg("Id为[{0}]的CommonTaskBizNo有误 ", node.getId()),
CommonErrorCodeEnum.INVALID_PARAM, false);
}
String planNo=node.getContext();
String accDateStr=split[2];
Date acctDate = DateTimeUtil.parseFromYMD(accDateStr);
boolean ret= capitalAstMatchHandler.execute(planNo,acctDate);
LogUtil.info(LOGGER, "执行解绑匹配-end", node.getContext());
return ret;
}
private void markStatus(Boolean status,CommonTask node,String errorMessage){
if(status){
markSuccess(node);
return;
}
markFail(node,errorMessage);
}
@Override
protected CommonTask markSuccess(CommonTask node) {
//为保证数据一直性,讲成功设置
commonTaskRepository.updateTaskStatus(node.getId(), TaskStatusEnum.SUCCESS, TaskStatusEnum.EXECUTING, "");
return node;
}
@Override
protected CommonTask markFail(CommonTask node, String failMessage) {
Date nextTime = DateTimeUtil.addSecond(SystemDateUtil.getSystemDate(), 60);
String msg = failMessage.length() > 2000 ? failMessage.substring(0, 2000) : failMessage;
commonTaskRepository.updateTaskStatus(node.getId(), TaskStatusEnum.IGNORE, TaskStatusEnum.EXECUTING, "");
commonTaskRepository.updateTaskExep(nextTime, node.getId(), msg);
return node;
}
@Override
protected CommonTask markException(CommonTask node, String failMessage) {
return markFail(node, failMessage);
}
@Override
protected String getName() {
return "PlanCapitalAssertMatchExecutor";
}
}
package com.abssqr.plat.biz.shared.dispatcher.capitalAssetMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.plan.PlanRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.core.service.host.HostManager;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Component
public class PlanCapitalAssertMatchLoader implements DispatcherLoader<CommonTask> {
private final static Logger LOGGER = LoggerFactory.getLogger(PlanCapitalAssertMatchLoader.class);
@Autowired
PlanRepo planRepo;
@Autowired
CommonTaskRepository commonTaskRepository;
@Autowired
private HostManager hostManager;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
JobControlRepository jobControlRepository;
@Autowired
PlanCapitalAssertMatchExecutor planCapitalAssertMatchExecutor;
@Override
public List<CommonTask> loadToDoNodes(int size) {
List<CommonTask> commonTasksList=new ArrayList<>();
transactionTemplate.execute(transactionStatus->{
JobControl jobControl = jobControlRepository.lockByJobName(planCapitalAssertMatchExecutor.getName());
if(jobControl==null||jobControl.getIsEff()== YNEnum.N){
return false;
}
// LogUtil.info(LOGGER,"[PlanCapitalAssertMatchLoader] 捞取资金资产匹配/解绑任务开始");
List<PlanBase> plans = planRepo.getAllPlanAstByType(PlanTypeEnum.SPV.getCode());
for(PlanBase plan:plans){
String planNo = plan.getPlanNo();
//查询是否有正在执行中的解绑/匹配任务
List<CommonTask> runningCommonTask = commonTaskRepository.queryExecUnMatchOrMatchTaskByContext(planNo);
if(CollectionUtils.isNotEmpty(runningCommonTask)){
continue;
}
//查询初始化的匹配任务
List<CommonTask> initCommonTask = commonTaskRepository.queryInitUnMatchOrMatchTaskByContext(planNo);
if(CollectionUtils.isNotEmpty(initCommonTask)){
CommonTask commonTask = initCommonTask.get(0);
int cnt=commonTaskRepository.updateTaskExec(new Date(),hostManager.getHostInfo().getHostName(), Lists.newArrayList(commonTask));
if(cnt==1){
commonTasksList.add(commonTask);
}
}
}
// LogUtil.info(LOGGER,"[PlanCapitalAssertMatchLoader] 捞取资金资产匹配/解绑任务结束");
return true;
});
return commonTasksList;
}
}
package com.abssqr.plat.biz.shared.dispatcher.capitalAssetMatch;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherExecutor;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherLoader;
import com.abssqr.plat.biz.shared.dispatcher.DispatcherStarter;
import com.abssqr.plat.biz.shared.dispatcher.match.PlanAstMatchDispatcherExecutor;
import com.abssqr.plat.biz.shared.dispatcher.match.PlanAstMatchDispatcherLoader;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.core.service.host.HostManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
@Configuration
@Component
public class PlanCapitalAssertMatchStater extends DispatcherStarter<CommonTask> {
@Autowired
HostManager hostManager;
@Autowired
AstSyncTaskCtrRepo astSyncTaskCtrRepo;
@Autowired
CommonTaskRepository commonTaskRepository;
@Autowired
PlanCapitalAssertMatchLoader planCapitalAssertMatchLoader;
@Autowired
PlanCapitalAssertMatchExecutor planCapitalAssertMatchExecutor;
public static String JOB_NAME = "PlanCapitalAssertMatchStater";
private int coreSize = 2;
private int maxSize = 2;
private int hungrySize = 1;
private int queueSize = 2;
@Override
protected void recovery() {
commonTaskRepository.updateHangTasksByIp(hostManager.getHostInfo().getHostName());
}
@Override
public String getName() {
return JOB_NAME;
}
@Override
protected int getCoreSize() {
return coreSize;
}
@Override
protected int getMaxSize() {
return maxSize;
}
@Override
protected int getQueueSize() {
return queueSize;
}
@Override
protected int getHungrySize() {
return hungrySize;
}
@Override
protected DispatcherLoader getLoader() {
return planCapitalAssertMatchLoader;
}
@Override
protected DispatcherExecutor getExecutor() {
return planCapitalAssertMatchExecutor;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import javax.annotation.PostConstruct;
import com.abssqr.plat.biz.shared.dispatcher.commonTask.CommonTaskExecutor;
import com.abssqr.plat.common.dal.sync.auto.dao.WkAbsMfsBillCtrIgnoreDAO;
import com.abssqr.plat.common.facade.enums.CommonTaskTypeEnum;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.ast.LoanRepository;
import com.general.system.common.util.VarChecker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @author bangis.wangdf
* @version com.abssqr.plat.biz.shared.handler: AstModCheckCommonTaskHandler.java, v 0.1 2020-03-04 14:06 bangis
* .wangdf Exp $
*/
@Component
public class AstModCheckCommonTaskHandler implements CommonTaskHandler {
@Autowired
CommonTaskExecutor commonTaskExecutor;
@Autowired
WkAbsMfsBillCtrIgnoreDAO wkAbsMfsBillCtrIgnoreDAO;
@Autowired
LoanRepository loanRepository;
@PostConstruct
public void registerHandler() {
commonTaskExecutor.registerHandler(CommonTaskTypeEnum.AST_MOD_CHECK, this);
}
@Override
public CommonTask execute(CommonTask commonTask) {
VarChecker.checkEquals(commonTask.getTaskType(), CommonTaskTypeEnum.AST_MOD_CHECK,
"CommonTask类型不为AST_MOD_CHECK,taskType={0}", commonTask.getTaskType());
//loanRepository.
return null;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.dal.mysql.auto.paging.CapitalAstMatchPage;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.AstScale;
import com.abssqr.plat.common.facade.constants.LoanExtInfConstants;
import com.abssqr.plat.common.facade.enums.EventCodeEnum;
import com.abssqr.plat.common.facade.enums.OwnStatusEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.facade.enums.TransCodeEnum;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.facade.model.plan.InvestStructure;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.model.domain.ast.Loan;
import com.abssqr.plat.common.model.domain.ast.LoanAstGroup;
import com.abssqr.plat.common.model.domain.ast.LoanBak;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.loanTrans.LoanTransDetail;
import com.abssqr.plat.common.model.domain.loanTrans.TransInfoTemplate;
import com.abssqr.plat.common.model.repo.ast.LoanBakRepo;
import com.abssqr.plat.common.model.repo.ast.LoanRepository;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.loanTrans.LoanLogRepository;
import com.abssqr.plat.common.model.repo.plan.PlanAcctTitleRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAllocRepo;
import com.abssqr.plat.common.model.repo.tr.TrTaskRepo;
import com.abssqr.plat.common.model.seq.SequenceUtil;
import com.abssqr.plat.common.util.profiler.PerformTrace;
import com.abssqr.plat.common.util.profiler.PerformTraceContext;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.ast.LoanAstAssembler;
import com.abssqr.plat.core.service.plan.PlanInvestStructureManager;
import com.abssqr.plat.core.service.system.TimeStampUtil;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.SystemDateUtil;
import com.general.system.common.util.VarChecker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static com.abssqr.plat.common.model.enums.IdTypeEnum.CAP_AST_MATCH;
/**
* 资金资产匹配
*
* @author xiachenxiang
* @version com.abssqr.plat.biz.shared.handler: CapitalAstMatchHandler.java, v 0.1 2020-02-03 2:22 PM xiachenxiang Exp $
*/
@Component
public class CapitalAstMatchHandler {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Autowired
private TrTaskRepo trTaskRepo;
@Autowired
private PlanInvestStructureManager planInvestStructureManager;
@Autowired
private PlanAcctTitleRepo planAcctTitleRepo;
@Autowired
private LoanBakRepo loanBakRepo;
@Autowired
private LoanRepository loanRepository;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private LoanAstAssembler loanAstAssembler;
@Autowired
private LoanLogRepository loanLogRepository;
@Autowired
private PlanAllocRepo planAllocRepo;
@Autowired
private JobControlRepository jobControlRepository;
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
private int queryLimit = 2000;
/**
* @param planNo 计划编号
* @param taskCreateDay 任务创建日
* @return
*/
@PerformTrace(name = "CapitalAstMatchHandler")
public boolean execute(String planNo, Date taskCreateDay) {
// 1. 判断是否可进行资金匹配
// 判断转让、回购任务是否全部完成 ignore、init、exec
Long cnt = trTaskRepo.cntTrTaskByTfrOut(planNo, Lists.newArrayList(TaskStatusEnum.IGNORE.getCode(), TaskStatusEnum.INIT.getCode(), TaskStatusEnum.EXECUTING.getCode()), null);
VarChecker.checkArgument(cnt.equals(0L), "[CapitalAstMatchHandler] - [{0}]转让任务未完成", planNo);
// 判断会计日是否相等
Date standardDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
if (!DateTimeUtil.isSameDay(standardDate, taskCreateDay)) {
LogUtil.error(LOGGER, "[CapitalAstMatchHandler] - [{0}]资金匹配计划匹配日期为[{1}],当前会计日为[{2}],跳过", planNo, DateTimeUtil.formatYMD(taskCreateDay), DateTimeUtil.formatYMD(standardDate));
return true;
}
// LogUtil.info(LOGGER, "[CapitalAstMatchHandler] - [{0}]开始资金资产匹配", planNo);
// 2. 计算每个投资层级资金应该匹配多少资产
// 可用资金=投资层级规模-待分配本金金额(已审批)
// 获取投资结构信息
List<InvestStructure> investStructureList = planInvestStructureManager.selectByPlanNo(planNo);
// 升序
investStructureList.sort(Comparator.comparing(InvestStructure::getLayerEndDate));
Map<String, Money> needMatchBalMap = this.calcNeedMatchMap(planNo, investStructureList, taskCreateDay);
if (MapUtils.isEmpty(needMatchBalMap)) {
LogUtil.info(LOGGER, "[CapitalAstMatchHandler] - [{0}]计划剩余需匹配投资结构为0", planNo);
return true;
}
// 3. 执行资金资产匹配
boolean match = executeMatch(planNo, needMatchBalMap, investStructureList, taskCreateDay);
LogUtil.info(LOGGER, "[CapitalAstMatchHandler] - [{0}]结束资金资产匹配 - result [{1}]", planNo, match);
return match;
}
/**
* 执行资金匹配
*
* @param planNo 计划编号
* @param needMatchBalMap 应匹金额
* @param investStructureList 投资结构
* @param taskCreateDay 任务创建日期
* @return
*/
private boolean executeMatch(String planNo, Map<String, Money> needMatchBalMap, List<InvestStructure> investStructureList, Date taskCreateDay) {
try {
PerformTraceContext.enter("CapitalAstMatchHandler.executeMatch");
// 资金资产匹配
CapitalAstMatchPage capitalAstMatchPage = new CapitalAstMatchPage();
capitalAstMatchPage.setCurrPageNo(1);
capitalAstMatchPage.setLimit(queryLimit);
capitalAstMatchPage.setLenderOrgCode(planNo);
boolean match = true;
do {
match = this.capitalAstMatch(capitalAstMatchPage, needMatchBalMap, investStructureList, taskCreateDay, planNo);
if (!match) {
break;
}
} while (capitalAstMatchPage.hasNextPage());
// 判断是否存在未匹配的资产
capitalAstMatchPage = loanRepository.queryForCapitalAstMatch(capitalAstMatchPage);
if (capitalAstMatchPage.getTotal() > 0) {
LogUtil.warn(LOGGER, "[CapitalAstMatchHandler] - [{0}]结束资金资产匹配失败,剩余应批资产大于0", planNo);
match = false;
}
return match;
} finally {
PerformTraceContext.leave();
}
}
/**
* 计算每个投资层级资金应该匹配多少资产
*
* @param planNo 计划编号
* @param investStructureList 投资结构
* @param taskCreateDay 任务创建日期
* @return
*/
private Map<String, Money> calcNeedMatchMap(String planNo, List<InvestStructure> investStructureList, Date taskCreateDay) {
// 获取本金科目
List<PlanAcctTitle> planAcctTitleList = planAcctTitleRepo.getByEntityNo(planNo);
// 获取已审批未兑付的金额
Map<String, Money> willPayMoneyMap = planAllocRepo.queryApprovedNotPayMoneyGroupByLayerNo(planNo);
Map<String, Money> balMap = Maps.newHashMap();
Money investStructureBalSum = new Money();
planAcctTitleList.forEach(item -> {
if (item.getTitleType().isInvest()) {
Money money = item.getBal().clone();
Money willPayMoney = willPayMoneyMap.getOrDefault(item.getRefNo(), new Money());
money.subtractFrom(willPayMoney);
// 负保护
VarChecker.checkArgument(!money.isNegtive(), "[CapitalAstMatchHandler] - [{0}]投资结构剩余应匹规模小于0", item.getRefNo());
balMap.put(item.getRefNo(), money);
investStructureBalSum.addTo(money);
}
});
VarChecker.checkArgument(investStructureList.size() == balMap.size(), "[CapitalAstMatchHandler] - [{0}]投资结构与本金科目不一致", planNo);
// 2.2 计算资金比例
// 计算资金比例
Map<String, BigDecimal> rateMap = this.calcCapistalRate(investStructureList, balMap, investStructureBalSum, planNo);
Money astScaleSum = new Money();
// 获取信托资产规模
Map<String, Money> astScaleMap = this.getAstScaleMap(taskCreateDay, planNo, astScaleSum);
// 计算目标匹配余额
this.calcNeedMatchBal(investStructureList, astScaleSum, astScaleMap, rateMap, investStructureBalSum, planNo, balMap, true);
// 计算资金比例
rateMap = this.calcCapistalRate(investStructureList, balMap, investStructureBalSum, planNo);
// 计算目标匹配余额
Map<String, Money> needMatchBalMap = this.calcNeedMatchBal(investStructureList, astScaleSum, astScaleMap, rateMap, investStructureBalSum, planNo, balMap, false);
return needMatchBalMap;
}
/**
* @param taskCreateDay
* @param planNo
* @return
*/
private Map<String, Money> getAstScaleMap(Date taskCreateDay, String planNo, Money astScaleSum) {
List<AstScale> astScaleList = loanBakRepo.getAstScale(taskCreateDay, planNo);
Map<String, Money> astScaleMap = Maps.newHashMap();
astScaleList.forEach(item -> {
astScaleSum.addTo(item.getPrinBal());
astScaleMap.put(item.getCapitalNo(), item.getPrinBal());
});
return astScaleMap;
}
/**
* 资金资产匹配
*
* @param capitalAstMatchPage 分页
* @param needMatchBalMap 匹配余额
* @param investStructureList 投资结构信息
* @param execDate 任务生成的会计日
* @return 匹配结果
*/
private boolean capitalAstMatch(CapitalAstMatchPage capitalAstMatchPage, Map<String, Money> needMatchBalMap,
List<InvestStructure> investStructureList, Date execDate, String planNo) {
boolean match = true;
//增加Job控制
JobControl jobControl = jobControlRepository.selectByJobName(capitalAssertMatchJob.getJobName());
if (jobControl.getIsEff() == YNEnum.N) {
LogUtil.error(LOGGER, "计划[{0}]匹配失败,资金资产匹配任务运行中被关闭", planNo);
return false;
}
capitalAstMatchPage = loanRepository.queryForCapitalAstMatch(capitalAstMatchPage);
List<String> astNoList = capitalAstMatchPage.getDatas();
for (String astNo : astNoList) {
try {
PerformTraceContext.enter("CapitalAstMatchHandler.capitalAstmatch");
match = transactionTemplate.execute(status -> this.matchCapital(astNo, investStructureList, needMatchBalMap, execDate, planNo));
} finally {
PerformTraceContext.leave();
}
if (!match) {
break;
}
}
return match;
}
/**
* 匹配资金
*
* @param astNo 资产编号
* @param investStructureList 投资结构 按到期日升序
* @param needMatchBalMap 投资结构对应剩余应匹配金额
* @param execDate 任务生成日期
* @return
*/
private boolean matchCapital(String astNo, List<InvestStructure> investStructureList,
Map<String, Money> needMatchBalMap, Date execDate, String planNo) {
// 机构会计日
// Date trfDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
Loan loan = loanAstAssembler.lockByAstNo(astNo, execDate);
// 判断日期
if (DateTimeUtil.calcDayDiff(loan.getLastUpdateDate(), execDate) > 0) {
LogUtil.error(LOGGER, "[{0}]资金匹配失败,[{1}]资产更新日期[{2}]大于任务生成日期[{3}]", planNo, loan.getAstNo(), loan.getLastUpdateDate(), execDate);
return false;
}
// 判断是否全部转让
if (loan.getAstOrg().getAstOwnership().getOwnStatus() == OwnStatusEnum.TRANS_OUT) {
LogUtil.info(LOGGER, "[{0}]资金匹配跳过,[{1}]资产已全部转让,可能存在转让任务,跳过该资产", planNo, loan.getLastUpdateDate(), execDate);
return true;
}
for (InvestStructure investStructure : investStructureList) {
// 判断投资结构是否需要匹配
if (needMatchBalMap.get(investStructure.getLayerNo()) == null) {
continue;
}
Money needMatchBal = needMatchBalMap.get(investStructure.getLayerNo());
if (!needMatchBal.isGreaterThanZero()) {
continue;
}
Map<String, String> extInf = loan.getExtInf();
String bfCapitalNo = extInf.get(LoanExtInfConstants.BF_CAPITAL_NO);
if (StringUtils.isNotEmpty(bfCapitalNo) && StringUtils.equals(bfCapitalNo, investStructure.getLayerNo())) {
continue;
}
// 资产到期日 小于等于 投资结构到期日
if (DateTimeUtil.calcDayDiff(investStructure.getLayerEndDate(), loan.getAstPeriod().getEndDate()) >= 0) {
// 匹配成功
LoanAstGroup loanAstGroup = loan.filterLoanAstByOrg(loan.getAstOrg().getAstOwnership().getLenderOrgCode(), loan.getTermCnt());
Money loanAstBal = new Money();
loanAstGroup.getLoanAsts().forEach(item -> {
loanAstBal.addTo(item.getPrinBal());
});
// 更新目标匹配余额
needMatchBal.subtractFrom(loanAstBal);
String batchNo = SequenceUtil.genId(CAP_AST_MATCH);
String timeStamp = TimeStampUtil.getDefaultTimeStamp();
TransInfoTemplate transInTemplate = new TransInfoTemplate();
transInTemplate.setTransTime(SystemDateUtil.getSystemDate());
transInTemplate.setAccountDate(execDate);
transInTemplate.setEventCode(EventCodeEnum.CAP_AST_MATCH);
transInTemplate.setOutBizNo(batchNo);
transInTemplate.setBizNo(SequenceUtil.genSeqNo(TransCodeEnum.CAP_AST_MATCH));
transInTemplate.setTimestamp(timeStamp);
// 构造交易详情
LoanTransDetail loanTransDetail = LoanTransDetail.createLoanAstTxnDtl(loan, transInTemplate);
// 更新资金编号
loanTransDetail.setCapitalInfo(investStructure.getLayerNo(), investStructure.getLayerName());
loanTransDetail.processBeforeUpdate();
// 更新信息
loanAstAssembler.store(loan, execDate, false);
List<LoanBak> loanBaks = LoanTransDetail.buildBaks(loan, transInTemplate.getAccountDate());
loanRepository.backup(loanBaks);
return true;
}
}
return false;
}
/**
* 计算匹配余额
*
* @param investStructureList 投资结构列表
* @param astScaleSum 资产总规模
* @param astScaleMap 资产规模
* @param rateMap 资金比例
* @param investStructureBalSum 投资结构总余额
* @param planNo 计划编号
* @param balMap 投资结构资金余额
* @param removeIfNegtive 匹配余额小于等于0时是否移除 false 不移除 true 移除
* @return
*/
private Map<String, Money> calcNeedMatchBal(List<InvestStructure> investStructureList, Money astScaleSum, Map<String, Money> astScaleMap, Map<String, BigDecimal> rateMap, Money investStructureBalSum, String planNo, Map<String, Money> balMap, boolean removeIfNegtive) {
Map<String, Money> needMatchBalMap = Maps.newHashMap();
Iterator<InvestStructure> iterator = investStructureList.iterator();
while (iterator.hasNext()) {
InvestStructure investStructure = iterator.next();
if (balMap.get(investStructure.getLayerNo()) == null) {
continue;
}
Money needMatchBal = astScaleSum.multiply(rateMap.get(investStructure.getLayerNo()));
Money alreadyMatchMoney = astScaleMap.getOrDefault(investStructure.getLayerNo(), new Money());
// 判断目标匹配余额,这边会修改needMatchBal的值
needMatchBal.subtractFrom(alreadyMatchMoney);
if (!needMatchBal.isGreaterThanZero() && removeIfNegtive) {
investStructureBalSum.subtractFrom(balMap.get(investStructure.getLayerNo()));
balMap.remove(investStructure.getLayerNo());
continue;
}
needMatchBalMap.put(investStructure.getLayerNo(), needMatchBal);
}
return needMatchBalMap;
}
/**
* 计算资金比例
*
* @param investStructureList 投资结构
* @param balMap 余额
* @param sum 总额
* @return
*/
private Map<String, BigDecimal> calcCapistalRate(List<InvestStructure> investStructureList, Map<String, Money> balMap, Money sum, String planNo) {
// 非0保护
VarChecker.checkArgument(sum.isGreaterThanZero(), "[CapitalAstMatchHandler] - [{0}]投资结构总剩余规模为0", planNo);
Map<String, BigDecimal> rateMap = Maps.newHashMap();
investStructureList.forEach(item -> {
Money bal = balMap.getOrDefault(item.getLayerNo(), new Money(0));
BigDecimal rate = bal.getAmount().divide(sum.getAmount(), 2, BigDecimal.ROUND_HALF_UP);
rateMap.put(item.getLayerNo(), rate);
});
return rateMap;
}
}
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.dal.mysql.auto.paging.CapitalAstUnMatchPage;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.AstScale;
import com.abssqr.plat.common.facade.enums.*;
import com.abssqr.plat.common.facade.model.plan.InvestStructure;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.facade.model.plan.PlanAlloc;
import com.abssqr.plat.common.facade.model.plan.PlanAllocItem;
import com.abssqr.plat.common.model.domain.ast.Loan;
import com.abssqr.plat.common.model.domain.ast.LoanAstGroup;
import com.abssqr.plat.common.model.domain.ast.LoanBak;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.loanTrans.LoanTransDetail;
import com.abssqr.plat.common.model.domain.loanTrans.TransInfoTemplate;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.exception.AbssqrBizException;
import com.abssqr.plat.common.model.repo.ast.LoanBakRepo;
import com.abssqr.plat.common.model.repo.ast.LoanRepository;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.loanTrans.LoanLogRepository;
import com.abssqr.plat.common.model.repo.plan.PlanAcctTitleRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAllocRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.common.model.repo.tr.TrTaskRepo;
import com.abssqr.plat.common.model.seq.SequenceUtil;
import com.abssqr.plat.common.util.base.autoconfig.AbsConfig;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.ast.LoanAstAssembler;
import com.abssqr.plat.core.service.plan.PlanInvestStructureManager;
import com.abssqr.plat.core.service.system.TimeStampUtil;
import com.general.system.common.model.Money;
import com.general.system.common.util.*;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import static com.abssqr.plat.common.model.enums.IdTypeEnum.CAP_AST_UNMATCH;
/**
* 资金资产解除绑定
*/
@Component
public class CapitalAstUnMatchHandler {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Autowired
private TrTaskRepo trTaskRepo;
@Autowired
private PlanInvestStructureManager planInvestStructureManager;
@Autowired
private PlanAllocRepo planAllocRepo;
@Autowired
private PlanAcctTitleRepo planAcctTitleRepo;
@Autowired
private LoanBakRepo loanBakRepo;
@Autowired
LoanRepository loanRepository;
@Autowired
LoanLogRepository loanLogRepository;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private LoanAstAssembler loanAstAssembler;
@Autowired
private CommonTaskRepository commonTaskRepository;
@Autowired
private AbsConfig absConfig;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
@Autowired
private JobControlRepository jobControlRepository;
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
private int queryLimit = 2000;
/**
*
* @param planNo
* @param allocNo
* @param acctDate
* @return
*/
public boolean execute(String planNo, String allocNo,Date acctDate){
//判断存在ignore、init、exec状态的转让任务
Long cnt = trTaskRepo.cntTrTaskByTfrOut(planNo, Lists.newArrayList(TaskStatusEnum.IGNORE.getCode(), TaskStatusEnum.INIT.getCode(), TaskStatusEnum.EXECUTING.getCode()),
AstPackTradeTypeEnum.AST_TRF_BIZ);
VarChecker.checkArgument(cnt.intValue() == 0, "[CapitalAstUnMatchHandler] - [{0}]转让任务未完成", planNo);
LogUtil.info(LOGGER, "[CapitalAstUnMatchHandler] - [{0}]开始资金资产解绑兑付计划编号[{1}]", planNo,allocNo);
//获取该计划下的所有的科目信息
List<PlanAcctTitle> planAcctTitles = planAcctTitleRepo.getByEntityNo(planNo);
//获取该计划下的所有投资结构编号
List<InvestStructure> investStructureList = planInvestStructureManager.selectByPlanNo(planNo);
Set<String> allLayerNos = investStructureList.stream()
.collect(Collectors.groupingBy(InvestStructure::getLayerNo))
.keySet();
//通过兑付计划获取兑付计划对应的投资层级编号
PlanAlloc planAllocDetail = planAllocRepo.getPlanAllocDetail(allocNo);
VarChecker.checkArgument(planAllocDetail!= null, "[CapitalAstUnMatchHandler] - [{0}]兑付单不存在", allocNo);
//投资科目编号
Set<String> titleNos = planAllocDetail.getPlanAllocItemList().stream()
.filter(v->v.getConfirmAmt()!=null&&v.getConfirmAmt().isGreaterThanZero())
.collect(Collectors.groupingBy(PlanAllocItem::getTitleNo))
.keySet();
//兑付单对应的投资层级编号
Set<String> allocLayerNos = planAcctTitles.stream()
.filter(v->titleNos.contains(v.getTitleNo()))
.collect(Collectors.groupingBy(PlanAcctTitle::getRefNo))
.keySet();
//计算各个投资层级需要解绑的资产额度
final Map<String, Money> needUnMatchBalMap = caclNeedUnMatchCapitalBal(planNo, planAcctTitles, allLayerNos,allocLayerNos,acctDate);
needUnMatchBalMap.forEach((layerNo,needUnMatchMoney)->{
CapitalAstUnMatchPage capitalAstMatchPage = new CapitalAstUnMatchPage();
capitalAstMatchPage.setCurrPageNo(1);
capitalAstMatchPage.setLimit(queryLimit);
capitalAstMatchPage.setCapitalNo(layerNo);
do{
boolean b = unMatchCaptialAst(planNo,capitalAstMatchPage, needUnMatchMoney,acctDate);
if(!b) {
break;
}
}while(capitalAstMatchPage.hasNextPage());
});
;
//生成解绑重新匹配的Task
CommonTask commonTask = buildUnMatchMatchTask(planNo, generateBizNo(CommonTaskTypeEnum.UNMATCH_CAPTITALASSERT_MATCH,planNo,acctDate,allocNo));
commonTaskRepository.create(commonTask);
return true;
}
/**
* 计算需要解绑的金额
* @param planNo 计划编号
* @param planAcctTitles 科目
* @param allLayerNos 所有的投资层级编号
* @param acctDate 会计日
* @param allocLayerNos 兑付计划对应的投资层级编号
* @return
*/
private Map<String,Money> caclNeedUnMatchCapitalBal(String planNo,List<PlanAcctTitle> planAcctTitles,Set<String> allLayerNos,Set<String> allocLayerNos,Date acctDate){
//获取已审批未兑付的金额
Map<String, Money> willPayMoneyMap = planAllocRepo.queryApprovedNotPayMoneyGroupByLayerNo(planNo);
//计算所有投资结构持有的资金和资金总额
Money investStructureBalSum = new Money();
Map<String, Money> balMap=calcCaptial(willPayMoneyMap,investStructureBalSum,planAcctTitles);
if (!(allLayerNos.size() == balMap.size())) {
LogUtil.error(LOGGER, "[CapitalAstMatchHandler] - [{0}]投资结构与本金科目不一致", planNo);
throw new AbssqrBizException(
MessageUtil.formatMsg("[{0}]投资结构与本金科目不一致", planNo),
CommonErrorCodeEnum.INVALID_PARAM, false);
}
if(!investStructureBalSum.isGreaterThanZero()){
throw new AbssqrBizException(
MessageUtil.formatMsg("投资结构资金小于0", planNo),
CommonErrorCodeEnum.INVALID_PARAM, false);
}
// 计算资金比例
Map<String, BigDecimal> rateMap = this.calcCapistalRate(allLayerNos, balMap, investStructureBalSum);
//计算获取信托资产规模
List<AstScale> astScaleList = loanBakRepo.getAstScale(acctDate, planNo);
Money astScaleSum = new Money();
Map<String, Money> astScaleMap = Maps.newHashMap();
astScaleList.forEach(item -> {
astScaleSum.addTo(item.getPrinBal());
astScaleMap.put(item.getCapitalNo(), item.getPrinBal());
});
// 计算目标匹配余额并移除变更金额<0且不为兑付对应投资结构的投资结构
calcUnMatchMatchBal(allLayerNos, astScaleMap ,astScaleSum,rateMap,allocLayerNos,investStructureBalSum,balMap);
//重新计算资金比
calcCapistalRate(allLayerNos,balMap,astScaleSum);
//重新计算资产差额
Map<String, Money> allRebalanceBalMap = calcUnMatchMatchBal(allLayerNos, astScaleMap, astScaleSum, rateMap, allocLayerNos, investStructureBalSum, balMap);
Map<String,Money> needUnbinBalMap=new HashMap<>();
allRebalanceBalMap.forEach((layerNo,unBindBal)->{
if(allocLayerNos.contains(layerNo)&&unBindBal.isNegtive()){
needUnbinBalMap.put(layerNo,unBindBal);
}
});
return needUnbinBalMap;
}
/**
* 计算所有机构持有的资金
* @param willPayMoneyMap
* @param investStructureBalSum
* @param planAcctTitles
* @return
*/
private Map<String,Money> calcCaptial(Map<String, Money> willPayMoneyMap,Money investStructureBalSum,List<PlanAcctTitle> planAcctTitles){
Map<String,Money> balMap=new HashMap<>();
for(PlanAcctTitle planAcctTitle:planAcctTitles){
if (planAcctTitle.getTitleType() == TitleTypeEnum.INVESTED
|| planAcctTitle.getTitleType() == TitleTypeEnum.PRIOR_INVESTED
|| planAcctTitle.getTitleType() == TitleTypeEnum.SECND_INVESTED) {
Money money = planAcctTitle.getBal().clone();
Money willPayMoney = willPayMoneyMap.getOrDefault(planAcctTitle.getRefNo(),new Money());
money.subtractFrom(willPayMoney);
balMap.put(planAcctTitle.getRefNo(), money);
investStructureBalSum.addTo(money);
}
}
return balMap;
}
/**
* 计算资金比例
*
* @param layerNos 投资结构编号
* @param balMap 余额
* @param sum 总额
* @return
*/
private Map<String, BigDecimal> calcCapistalRate(Set<String> layerNos, Map<String, Money> balMap, Money sum) {
Map<String, BigDecimal> rateMap = Maps.newHashMap();
layerNos.forEach(item -> {
Money bal = balMap.get(item);
BigDecimal rate = bal.getAmount().divide(sum.getAmount(), 2, BigDecimal.ROUND_HALF_UP);
rateMap.put(item, rate);
});
return rateMap;
}
/**
* 计算资金资产差额
* @param allLayerNos 所有的投资层级编号
* @param astScaleMap 各投资结构的资产规模
* @param astScaleSum 所有投资结构的资产总额
* @param rateMap 各投资结构的资金比例
* @param allocLayerNos 兑付计划对应的投资层级编号
* @param investStructureBalSum 投资层级资金总额度
* @param balMap 各投资层级对应的资金
* @return
*/
private Map<String, Money> calcUnMatchMatchBal(Set<String> allLayerNos,Map<String, Money> astScaleMap ,Money astScaleSum,Map<String, BigDecimal> rateMap,Set<String> allocLayerNos,Money investStructureBalSum,Map<String, Money> balMap){
Map<String, Money> needUnMatchBalMap=new HashMap<>();
Iterator<String> iterator = allLayerNos.iterator();
while(iterator.hasNext()){
String layerNo = iterator.next();
BigDecimal balRate = rateMap.get(layerNo);
//目标兑付资产
Money targetBal = astScaleSum.multiply(balRate);
//持有的资产
Money matchedBal = astScaleMap.getOrDefault(layerNo,new Money());
//资产差额(目标兑付的资产-持有资产)
Money divide = targetBal.subtract(matchedBal);
//资产差额是负的且不属于兑付计划的移除
if(divide.isNegtive()&&!allocLayerNos.contains(layerNo)){
investStructureBalSum.subtractFrom(balMap.get(layerNo));
balMap.remove(layerNo);
iterator.remove();
continue;
}
needUnMatchBalMap.put(layerNo,divide);
}
return needUnMatchBalMap;
}
/**
* 进行解绑操作
* @param capitalAstUnMatchPage
* @param needUnMatchBal
* @param acctDate
* @return
*/
private boolean unMatchCaptialAst(String planNo,CapitalAstUnMatchPage capitalAstUnMatchPage,Money needUnMatchBal,Date acctDate){
boolean match = true;
//增加Job控制
JobControl jobControl = jobControlRepository.selectByJobName(capitalAssertMatchJob.getJobName());
if(jobControl.getIsEff()== YNEnum.N){
LogUtil.error(LOGGER, "计划[{0}]解绑失败,资金资产匹配任务运行中被关闭", planNo);
return false;
}
capitalAstUnMatchPage = loanRepository.queryForCapitalAstUnMatch(capitalAstUnMatchPage);
List<String> astNoList = capitalAstUnMatchPage.getDatas();
for (String astNo : astNoList) {
match=transactionTemplate.execute(status -> {
//判断资金是否为负
if(needUnMatchBal.isGreaterThanZero()){
return false;
}
Loan loan = loanAstAssembler.lockByAstNo(astNo, orgAcctDayComponent.getTrfAcctDay().getStandardDate());
// 判断是否全部转让
if (loan.getAstOrg().getAstOwnership().getOwnStatus() == OwnStatusEnum.TRANS_OUT) {
LogUtil.info(LOGGER, "[{0}]资产解绑跳过,[{1}]资产已全部转让,可能存在转让任务,跳过该资产", astNo, loan.getLastUpdateDate(), acctDate);
return false;
}
return this.unMatchCaptical(loan,needUnMatchBal,acctDate);
});
if(!match){
break;
}
}
return match;
}
/**
* 进行解绑操作
* @param loan
* @param needUnMatchBal
* @param acctDate
* @return
*/
private boolean unMatchCaptical(Loan loan,Money needUnMatchBal,Date acctDate){
LoanAstGroup loanAstGroup = loan.filterLoanAstByOrg(loan.getAstOrg().getAstOwnership().getLenderOrgCode(), loan.getTermCnt());
//计算资产额度
Money loanAstBal = new Money();
loanAstGroup.getLoanAsts().forEach(item -> {
loanAstBal.addTo(item.getPrinBal());
});
// 更新目标匹配余额
needUnMatchBal.addTo(loanAstBal);
//创建交易详情
String batchNo = SequenceUtil.genId(CAP_AST_UNMATCH);
String timeStamp = TimeStampUtil.getDefaultTimeStamp();
TransInfoTemplate transInTemplate = new TransInfoTemplate();
transInTemplate.setTransTime(SystemDateUtil.getSystemDate());
transInTemplate.setAccountDate(acctDate);
transInTemplate.setEventCode(EventCodeEnum.CAP_AST_UNMATCH);
transInTemplate.setOutBizNo(batchNo);
transInTemplate.setBizNo(SequenceUtil.genSeqNo(TransCodeEnum.CAP_AST_UNMATCH));
transInTemplate.setTimestamp(timeStamp);
// 构造交易详情
LoanTransDetail loanTransDetail = LoanTransDetail.createLoanAstTxnDtl(loan, transInTemplate);
// 更新资金编号
loanTransDetail.setCapitalInfo(CapitalAstMatchEnum.DEFAULT.getCode(),null);
loanTransDetail.processBeforeUpdate();
// 更新信息
loanAstAssembler.store(loan, acctDate, false);
List<LoanBak> loanBaks = LoanTransDetail.buildBaks(loan, transInTemplate.getAccountDate());
loanRepository.backup(loanBaks);
return true;
}
private CommonTask buildUnMatchMatchTask(String planNo,String bizNo){
CommonTask commonTask=new CommonTask();
commonTask.setContext(planNo);
commonTask.setTaskStatus(TaskStatusEnum.IGNORE);
commonTask.setTaskType(CommonTaskTypeEnum.UNMATCH_CAPTITALASSERT_MATCH);
commonTask.setEnv(absConfig.getEnv());
commonTask.setBizNo(bizNo);
commonTask.setExecTimes(0L);
return commonTask;
}
//生成解绑匹配业务码
private static String generateBizNo(CommonTaskTypeEnum commonTaskTypeEnum,String planNo,Date accountDate,String allocNo){
StringBuilder sb=new StringBuilder();
sb.append(commonTaskTypeEnum.getCode());
sb.append("-");
sb.append(planNo);
sb.append("-");
sb.append(DateTimeUtil.formatYMD(accountDate));
sb.append("-");
sb.append(allocNo);
return sb.toString();
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
/**
*
* @author hanfei
* @version $Id: FinSerFeeHandler.java, v 0.1 2020-03-09 2:01 PM hanfei Exp $
*/
public class FinSerFeeHandler {
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.common.facade.enums.AstPackTradeTypeEnum;
import com.abssqr.plat.common.model.domain.ast.Loan;
import com.abssqr.plat.common.model.domain.ast.LoanAstBuyBackPack;
import com.abssqr.plat.common.model.domain.task.TrTask;
import com.abssqr.plat.common.model.domain.trade.AstTradeParam;
import com.abssqr.plat.common.util.profiler.PerformTrace;
import com.abssqr.plat.core.service.ast.LoanAstAssembler;
import com.abssqr.plat.core.service.ast.LoanAstBuyBackManager;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.VarChecker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* 回购转让交易执行处理器
* @author hanfei
* @version $Id: LoanAstBuyBackHandler.java, v 0.1 2020-02-11 5:15 PM hanfei Exp $
*/
@Component
public class LoanAstBuyBackHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(
LoanAstBuyBackHandler.class);
@Autowired
private LoanAstAssembler loanAstAssembler;
@Autowired
private LoanAstBuyBackManager loanAstBuyBackManager;
/**
*
* @param trTask
* @return
*/
@PerformTrace
public boolean astBuyBackExecute(TrTask trTask) {
// 1 捞取加锁loan资产
Loan loan = loanAstAssembler.lockByAstNo(trTask.getAstNo(), trTask.getTfrDt());
if (loan == null) {
LogUtil.warn(LOGGER, "[astBuyBackExecute][{0}]捞不到待转借据", trTask.getAstNo());
return false;
}
// 查询资产包
LoanAstBuyBackPack pack = loanAstBuyBackManager.getByPackCode(trTask.getTfrPack());
VarChecker.checkNotNull(pack, "[astBuyBackExecute]-资产回购交易失败,没有对应的Pack");
AstTradeParam astTrade = new AstTradeParam();
astTrade.setPack(pack);
astTrade.setLoan(loan);
astTrade.setAstTradeType(AstPackTradeTypeEnum.BUY_BACK_BIZ);
// 11 成功回购后,回购资产任务更新TASK_STATUS为success
return loanAstBuyBackManager.astBuyBackTrade(trTask, astTrade);
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.biz.shared.dispatcher.buyBackMatch.LoanAstBuyBackMatchStarter;
import com.abssqr.plat.common.dal.mysql.auto.dataobject.LoanBakDO;
import com.abssqr.plat.common.dal.mysql.auto.paging.LoanBakListPage;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.AstPoolItem;
import com.abssqr.plat.common.facade.enums.*;
import com.abssqr.plat.common.facade.model.org.OrganizationEntity;
import com.abssqr.plat.common.facade.model.plan.Plan;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.rule.AstPriceRule;
import com.abssqr.plat.common.facade.model.rule.AstScreenRule;
import com.abssqr.plat.common.facade.model.rule.TradePriceRule;
import com.abssqr.plat.common.model.domain.ast.*;
import com.abssqr.plat.common.model.domain.contract.LoanContract;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.rule.LoanAstPriceCalcParam;
import com.abssqr.plat.common.model.domain.rule.LoanAstPriceResult;
import com.abssqr.plat.common.model.domain.task.TrCtrTask;
import com.abssqr.plat.common.model.domain.task.TrTask;
import com.abssqr.plat.common.model.enums.IdTypeEnum;
import com.abssqr.plat.common.model.repo.ast.LoanRepository;
import com.abssqr.plat.common.model.repo.ast.PackRepository;
import com.abssqr.plat.common.model.repo.contract.LoanContractRepository;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.model.repo.tr.TrCtrTaskRepo;
import com.abssqr.plat.common.model.repo.tr.TrTaskRepo;
import com.abssqr.plat.common.model.seq.SequenceUtil;
import com.abssqr.plat.common.model.utils.TextUtil;
import com.abssqr.plat.common.util.profiler.PerformTrace;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.ast.LoanAstAssembler;
import com.abssqr.plat.core.service.ast.LoanAstBuyBackManager;
import com.abssqr.plat.core.service.plan.PlanManager;
import com.abssqr.plat.core.service.rule.AstPriceRuleComponent;
import com.abssqr.plat.core.service.rule.AstScreenRuleComponent;
import com.general.system.common.util.*;
import com.general.system.tool.util.ToolUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Consumer;
import static com.abssqr.plat.common.model.enums.IdTypeEnum.ASTSCREENINGRULE;
/**
* 回购
*
* @author xiachenxiang
* @version com.abssqr.plat.biz.shared.handler: LoanAstBuyBackMatchHandler.java, v 0.1 2020-02-10 1:50 PM xiachenxiang Exp $
*/
@Component
public class LoanAstBuyBackMatchHandler {
private final Logger LOGGER = LoggerFactory.getLogger(getClass());
@Autowired
private TrTaskRepo trTaskRepo;
@Autowired
private PackRepository packRepository;
@Autowired
private LoanAstBuyBackManager loanAstBuyBackManager;
@Autowired
private AstSyncTaskCtrRepo astSyncTaskCtrRepo;
@Autowired
private LoanRepository loanRepository;
@Autowired
private LoanContractRepository loanContractRepository;
@Autowired
private TrCtrTaskRepo trCtrTaskRepo;
@Autowired
private AstScreenRuleComponent astScreenRuleComponent;
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private AstPriceRuleComponent astPriceRuleComponent;
@Autowired
private LoanAstAssembler loanAstAssembler;
@Autowired
private JobControlRepository jobControlRepository;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
@Autowired
private PlanManager planManager;
private final int limit = 2000;
private int batchInsertCnt = 500;
@PerformTrace(name = "LoanAstBuyBackMatchHandler")
public void execute(String packCode, Consumer<TaskStatusEnum> consumer) {
// 1.获取资产包
LoanAstBuyBackPack existPack = loanAstBuyBackManager.getByPackCode(packCode);
VarChecker.checkNotNull(existPack, "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,没有对应的Pack");
// 2.判断状态
VarChecker.checkEquals(existPack.getPackStatus(), AstPackStatusEnum.INIT, "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,Pack[{0}]的状态不为init", existPack.getPackCode());
// 3.清理历史TrTask
Date curDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
trTaskRepo.clearHisTrTask(existPack.getBackOutCode(), curDate, AstPackTradeTypeEnum.BUY_BACK_BIZ);
Map<String, TrCtrTask> trCtrTaskMap = Maps.newHashMap();
String batchNo = SequenceUtil.genId(ASTSCREENINGRULE);
LogUtil.info(LOGGER, "开始筛选[{0}]受让计划,批次号=[{1}]", existPack.getBackOutCode(), batchNo);
// 校验是否完成模型同步
this.checkAstModFinished(existPack, curDate);
// 4.分页遍历承接池机构资产
LoanBakListPage page = new LoanBakListPage();
page.setAccountDate(curDate);
page.setOwnOrg(existPack.getBackOutCode());
page.setStatuList(Lists.newArrayList(LoanStatusEnum.NORMAL.getCode(), LoanStatusEnum.OVERDUE.getCode()));
page.setLimit(limit);
page.setCurrPageNo(1);
do {
if (!this.canRun()) {
LogUtil.info(LOGGER, "[LoanAstBuyBackMatchHandler] - 检测到[{0}]任务已停止,跳出筛选", LoanAstBuyBackMatchStarter.JOB_NAME);
break;
}
LogUtil.info(LOGGER, "[LoanAstBuyBackMatchHandler]-[{0}]开始筛选[{0}]受让计划第[{1}]页", existPack.getBackOutCode(), page.getCurrentPage());
this.astMatch(page, existPack, trCtrTaskMap, curDate, batchNo);
page.setCurrPageNo(page.getCurrPageNo() + 1);
} while (page.hasNextPage());
LogUtil.info(LOGGER, "[LoanAstBuyBackMatchHandler] - 筛选结束");
// 5 更新转让数据状态
transactionTemplate.execute(status -> {
packRepository.updatePackStatus(Lists.newArrayList(existPack), AstPackStatusEnum.SCEEN_FIS, AstPackStatusEnum.INIT);
trTaskRepo.updateStatus(batchNo, TaskStatusEnum.INIT, TaskStatusEnum.IGNORE);
//插入转让控制表,可以开始转让
if (ToolUtil.isNotEmpty(trCtrTaskMap)) {
trCtrTaskRepo.insertBatch(Lists.newArrayList(trCtrTaskMap.values()));
}
consumer.accept(TaskStatusEnum.SUCCESS);
return status;
});
}
/**
* 判断当前机构是否完成模型同步
*
* @param pack 资产包
* @param curDate 会计日
*/
private void checkAstModFinished(LoanAstBuyBackPack pack, Date curDate) {
// 判断当日模型同步情况
List<String> orgCodes = astSyncTaskCtrRepo.getLastStatusFinishedOrgCodes(curDate, SyncTaskTypeEnum.AST_MOD);
VarChecker.checkNotEmpty(orgCodes, "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,当日没有机构完成模型同步");
// 判断当前转让会计日是否完成模型转换,未完成直接退出
PlanBase buybackPlan = planManager.getPlanFullByNo(pack.getPlanNo());
String OrgCode = null;
// 放款池回购受让池
if (buybackPlan.getPlanType() == PlanTypeEnum.SPV && buybackPlan instanceof OrganizationEntity) {
OrgCode = ((OrganizationEntity) buybackPlan).getManagerOrgCode();
} else { // 受让池回购受让池
// 判断两受让池对应的放款池是否一致
PlanBase outplan = planManager.getPlanFullByNo(pack.getBackOutCode());
VarChecker.checkArgument(outplan.getPlanType() == PlanTypeEnum.PLAN && outplan instanceof Plan, "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,不支持的回购类型受让池回购放款池");
Optional<AstScreenRule> outTrfScreenRuleOptional = ((Plan) outplan).getPlanTransferRule().getAstScreenRuleList().stream().filter(item -> item.getScreenType() == ScreenTypeEnum.AST_TRF).findFirst();
VarChecker.checkArgument(outTrfScreenRuleOptional.isPresent(), "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,转让筛选规则不存在");
AstScreenRule astScreenRule = outTrfScreenRuleOptional.get();
VarChecker.checkEquals(astScreenRule.getLenderOrgCode(), pack.getLoanProduct().getLenderOrgCode(), "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,两个受让计划不属于同一个放款池");
OrgCode = astScreenRule.getManagerOrgCode();
}
VarChecker.checkArgument(orgCodes.contains(OrgCode), "[LoanAstBuyBackMatchHandler]-回购筛选启动失败,机构[{0}]未完成模型同步", ((OrganizationEntity) buybackPlan).getManagerOrgCode());
}
/**
* 检测是否继续执行筛选
*
* @return
*/
public boolean canRun() {
JobControl jobControl = jobControlRepository.selectByJobName(LoanAstBuyBackMatchStarter.JOB_NAME);
return jobControl.getIsEff().isYes();
}
private void astMatch(LoanBakListPage page, LoanAstBuyBackPack pack, Map<String, TrCtrTask> trCtrTaskMap, Date curDate, String batchNo) {
page = loanRepository.getPageByOwnOrg(page);
List<LoanBakDO> datas = page.getDatas();
List<TrTask> trTasks = Lists.newArrayList();
for (LoanBakDO loanBakDO : datas) {
// 5.1.根据筛选规则进行匹配
TrTask trTask = null;
boolean isMatch = astScreenRuleComponent.astBuybackScreen(curDate, pack, () -> buildAstPoolItem(curDate, loanBakDO));
if (isMatch) {
// 5.2.匹配成功资产按照定价规则进行定价
LoanAstPriceResult result = this.makePrice(loanBakDO.getAstNo(), pack);
if (result == null) {
LogUtil.info(LOGGER, "[LoanAstBuyBackMatchHandler] - 计划[{0}]下机构资产[{1}]为0,跳过", loanBakDO.getOwnOrg(), loanBakDO.getAstNo());
continue;
}
TrCtrTask trCtrTask = trCtrTaskMap.get(pack.getPackCode());
if (trCtrTask == null) {
trCtrTask = new TrCtrTask();
trCtrTaskMap.put(pack.getPackCode(), trCtrTask);
trCtrTask.setTfrDate(curDate);
trCtrTask.setBatchNo(batchNo);
trCtrTask.setPackCode(pack.getPackCode());
trCtrTask.setPackType(pack.getPackType());
trCtrTask.setTaskStatus(TaskStatusEnum.INIT);
trCtrTask.setManagerOrgCode(pack.getManagerOrgCode());
trCtrTask.setPackType(AstPackTradeTypeEnum.BUY_BACK_BIZ);
}
if (MoneyUtil.compare(trCtrTask.getPreTrAmt().add(result.getPrice().getSum()), pack.getAvalAmt()) <= 0) {
trCtrTask.addPreTrAmt(result.getPrice().getSum());
trTask = dealTrTask(loanBakDO, batchNo, curDate, pack, result);
}
}
if (trTask != null) {
VarChecker.checkArgument(trTask.getTfrPrinBal().isGreaterThanZero(),
"Pack筛选到资产-待转金额为0,trTask[{0}]", trTask);
trTasks.add(trTask);
LogUtil.info(LOGGER, "[{0}]Pack筛选到资产,astNo=[{1}],batchNo=[{2}]", trTask.getTfrPack(),
trTask.getAstNo(), batchNo);
trySaveTrTask(trTasks, batchInsertCnt);
}
}
trySaveTrTask(trTasks, 0);
}
/**
* 计算定价
*
* @param astNo 资产编号
* @param pack 回购资产包
* @return
*/
private LoanAstPriceResult makePrice(String astNo, LoanAstBuyBackPack pack) {
Loan loan = loanRepository.getByAstNo(astNo);
loan = loanAstAssembler.assembleLoan(loan, orgAcctDayComponent.getTrfAcctDay().getStandardDate());
LoanAstGroup loanAstGroup = loan.filterLoanAstByOrg(pack.getBackOutCode(), loan.getTermCnt());
LoanAstPriceResult result = null;
for (LoanAst loanAst : loanAstGroup.getLoanAsts()) {
LoanAstPriceCalcParam param = new LoanAstPriceCalcParam();
param.setTransIn(pack.getPlanNo());
param.setTransOut(pack.getBackOutCode());
param.setLoanAst(loanAst);
param.setTradePriceRules(pack.getAstPriceRuleList());
param.setAstTradeType(AstPackTradeTypeEnum.BUY_BACK_BIZ);
// 资产五级分类
param.setCondition(loan.getLoanRisk().getRiskClass().getCode());
if (null == result) {
result = astPriceRuleComponent.execute(param);
} else {
result.merge(astPriceRuleComponent.execute(param));
}
}
return result;
}
/**
* 尝试保存
*
* @param trTasks
* @param minSize
*/
private void trySaveTrTask(List<TrTask> trTasks, int minSize) {
if (CollectionUtils.isNotEmpty(trTasks) && trTasks.size() >= minSize) {
LogUtil.info(LOGGER, "LoanAstBuyBackMatchHandler 回购TrTask入库size={0},minSize={1}", trTasks.size(), minSize);
trTaskRepo.insertBatch(trTasks);
trTasks.clear();
}
}
private TrTask dealTrTask(LoanBakDO loanBakDO, String batchNo, Date acctDate,
LoanAstBuyBackPack pack, LoanAstPriceResult result) {
TrTask task = new TrTask();
task.setExecTimes(0L);
task.setTfrDt(acctDate);
task.setBatchNo(batchNo);
task.setNextExecTime(SystemDateUtil.getSystemDate());
task.setAstNo(loanBakDO.getAstNo());
task.setTfrPack(pack.getPackCode());
task.setTermNo(loanBakDO.getTermCnt());
task.setAstDueDt(loanBakDO.getEndDate());
task.setTfrPrinBal(result.getBal().getAllPrin());
task.setTaskStatus(TaskStatusEnum.IGNORE);
task.setTfrOut(loanBakDO.getOwnOrg());
task.setSeqNo(SequenceUtil.genId(IdTypeEnum.SEQ));
task.setPackType(AstPackTradeTypeEnum.BUY_BACK_BIZ);
TradePriceRule tradePriceRule = result.getTradePriceRule();
VarChecker.checkArgument(tradePriceRule instanceof AstPriceRule, "[{0}]回购筛选交易定价类型有误", pack.getBackOutCode());
AstPriceRule astPriceRule = (AstPriceRule) tradePriceRule;
task.setTfrIntrBal(result.getBal().getAllIntr());
task.setTfrPenalFeeBal(result.getBal().getAllIntAndFee().subtract(result.getBal().getAllIntr()));
task.setRiskCl(astPriceRule.getRiskCl());
task.setIntrRate(astPriceRule.getIntrRate());
task.setPrinRate(astPriceRule.getPrinRate());
task.setPenalFeeRate(astPriceRule.getPenalFeeRate());
task.setTfrAmt(result.getPrice().getSum());
return task;
}
/**
* 构建资产条目
*
* @param curDate
* @param loanBakDO
* @return
*/
private AstPoolItem buildAstPoolItem(Date curDate, LoanBakDO loanBakDO) {
LoanContract contract = loanContractRepository.getByAstNo(loanBakDO.getAstNo());
// 需要
AstPoolItem astPoolItem = new AstPoolItem();
astPoolItem.setStatus(loanBakDO.getStatus());
astPoolItem.setAstNo(loanBakDO.getAstNo());
astPoolItem.setProdNo(loanBakDO.getProdNo());
astPoolItem.setTermNo(loanBakDO.getTermCnt());
astPoolItem.setStartDate(loanBakDO.getStartDate());
astPoolItem.setEndDate(loanBakDO.getEndDate());
astPoolItem.setRemainDays((int) DateTimeUtil.calcDayDiff(astPoolItem.getEndDate(), curDate));
astPoolItem.setPrinBal(loanBakDO.getPrinBal());
//astPoolItem.setIntrBal(loan.getBal().getAllIntr());
//astPoolItem.setPrinPenalBal(loan.getBal().getByFieldType(DebtMoneyFieldEnum.PRIN_ODUE_PNY));
//astPoolItem.setIntrPenalBal(loan.getBal().getByFieldType(DebtMoneyFieldEnum.INTR_ODUE_PNY));
astPoolItem.setManagerOrgCode(loanBakDO.getManagerOrgCode());
astPoolItem.setLenderOrgCode(loanBakDO.getLenderOrgCode());
astPoolItem.setTermCnt(loanBakDO.getTermCnt());
astPoolItem.setRiskCl(loanBakDO.getRiskCl());
Map<String, String> context = Maps.newHashMap();
context.put(AstConditions.CERT_NO, contract.getLoanCustInfo().getCertNo());
context.put(AstConditions.CERT_TYPE, contract.getLoanCustInfo().getCertType().getCode());
context.put(AstConditions.INTER_RATE, contract.getLoanProperty().getRate().toString());
context.put(AstConditions.RATE_TYPE, contract.getLoanProperty().getRateType().getCode());
astPoolItem.setContext(TextUtil.convertMap2Txt(context));
return astPoolItem;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.common.facade.enums.AstPackStatusEnum;
import com.abssqr.plat.common.facade.enums.TrCycleEnum;
import com.abssqr.plat.common.facade.enums.TransCodeEnum;
import com.abssqr.plat.common.facade.model.plan.PlanAst;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.plan.PlanTransferRule;
import com.abssqr.plat.common.facade.model.rule.AstScreenRule;
import com.abssqr.plat.common.model.domain.ast.Pack;
import com.abssqr.plat.common.model.repo.clearing.PlanClearingLogRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAstRepository;
import com.abssqr.plat.common.model.seq.SequenceUtil;
import com.abssqr.plat.core.service.ast.AstPackManager;
import com.abssqr.plat.core.service.plan.PlanInvestStructureManager;
import com.abssqr.plat.core.service.util.RptBuilderUtil;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.VarChecker;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 计划资产创建资产包
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.handler: PlanAstReqHandler.java, v 0.1 2019-06-19 01:34 zhenxuan.luo Exp $
*/
@Component
public class PlanAstReqHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(PlanAstReqHandler.class);
@Autowired
private PlanAstRepository planAstRepository;
@Autowired
private AstPackManager astPackManager;
@Autowired
private PlanClearingLogRepo planClearingLogRepo;
@Autowired
private PlanInvestStructureManager planInvestStructureManager;
public Pack execute(PlanBase planBase, PlanTransferRule transferRule, Date accountDate) {
Date tfrClearingDate = planClearingLogRepo.getMinUnStateAccountDate(planBase.getPlanNo(), null);
if (tfrClearingDate != null) {
LogUtil.info(LOGGER, "计划[{0}]创建资产包, 在[{1}]有未完成的转让任务待清算悬挂", planBase.getPlanNo(), tfrClearingDate);
return null;
}
VarChecker.checkNotNull(transferRule, "计划[{0}]创建资产包找不到对应转让规则", planBase.getPlanNo());
PlanAst planAst = planAstRepository.getByPlanNo(planBase.getPlanNo());
Pack pack = new Pack();
pack.setPlanNo(planBase.getPlanNo());
pack.setPackCode(SequenceUtil.genSeqNo(TransCodeEnum.OTHER.getCode()));
pack.setPackName(MessageUtil.formatMsg("{0}-{1}资产包",
planBase.getPlanName(), DateTimeUtil.formatYMD(accountDate)));
pack.setTransferRule(transferRule);
pack.setPackStatus(AstPackStatusEnum.INIT);
pack.setScenDate(accountDate);
pack.setMinEndDate(null);
pack.setMaxEndDate(planBase.getEndDate());
pack.setCalcIntrType(planBase.getCalcIntrType());
if (CollectionUtils.isNotEmpty(transferRule.getAstScreenRuleList())) {
AstScreenRule astScreenRule = transferRule.getAstScreenRuleList().stream().findFirst().get();
pack.setManagerOrgCode(astScreenRule.getManagerOrgCode());
}
boolean isNeedPack;
if (transferRule.getTrCycle() != TrCycleEnum.STATIC) {
isNeedPack = buildPackForCycle(transferRule, planAst, pack);
} else {
isNeedPack = buildPackForStatic(planBase, planAst, pack);
}
if (isNeedPack) {
return pack;
}
return null;
}
private boolean buildPackForStatic(PlanBase planBase, PlanAst planAst, final Pack pack) {
// 填充计划投资结构
planBase.setInvestStructureList(planInvestStructureManager.selectByPlanNo(planBase.getPlanNo()));
// 获取计划投资结构 投入资本金额总额
Money avalAmt = RptBuilderUtil.getInvestedAmt(planBase).subtract(planAst.getAccGrant());
if (avalAmt.isGreaterThanZero()) {
pack.setAvalAmt(avalAmt);
return true;
} else {
return false;
}
}
private boolean buildPackForCycle(PlanTransferRule transferRule, PlanAst planAst, final Pack pack) {
// 1. 转让周期判断 数量会越来越大,OOM风险
//List<Pack> packList = packRepository.getByPlanNo(transferRule.getPlanNo());
Date lastDate = null;
// 当天可以多次转让
//packList = packList.stream().filter(item -> !DateTimeUtil.isSameDay(item.getScenDate(), pack.getScenDate()))
// .collect(Collectors.toList());
//if (CollectionUtils.isNotEmpty(packList)) {
//
// Collections.sort(packList, Comparator.comparing(Pack::getScenDate));
// Pack lastPack = packList.get(packList.size() - 1);
// lastDate = lastPack.getScenDate();
//}
Money leastValAmt = new Money(0);
if (!isNeedTransAccdFreq(transferRule, leastValAmt, pack.getScenDate())) {
return false;
}
// 获取当前实际可用余额
Money ableCash = planAst.containClearAbleBal();
Money avalAmt = ableCash.subtract(transferRule.getResAmt());
if (avalAmt.isGreaterThanZero() && avalAmt.greaterThan(leastValAmt)) {
pack.setAvalAmt(avalAmt);
Date minEndDate = null;
Date maxEndDate = null;
for (AstScreenRule astScreenRule : transferRule.getAstScreenRuleList()) {
if (astScreenRule.getEarliestEndDate() != null) {
if (null == minEndDate
|| DateTimeUtil.calcDayDiff(minEndDate, astScreenRule.getEarliestEndDate()) > 0) {
minEndDate = astScreenRule.getEarliestEndDate();
}
}
if (astScreenRule.getLatestEndDate() != null) {
if (null == maxEndDate
|| DateTimeUtil.calcDayDiff(astScreenRule.getLatestEndDate(), maxEndDate) > 0) {
maxEndDate = astScreenRule.getLatestEndDate();
}
}
}
pack.setMinEndDate(minEndDate);
// 默认不能出头,填入值为计划到期日
if (null != maxEndDate) {
pack.setMaxEndDate(maxEndDate);
}
return true;
} else {
LogUtil.info(LOGGER, "Pack生成忽略PlanNo:{0},avalAmt:{1},leastValAmt:{2}", transferRule.getPlanNo(), avalAmt,
leastValAmt);
return false;
}
}
/**
* 目前一天资产同步一次,当资产每天同步多次时需要调整
* @param planTransferRule
* @param leastValAmt
* @param curDate
* @return
*/
private boolean isNeedTransAccdFreq(PlanTransferRule planTransferRule, Money leastValAmt, Date curDate) {
Pack lastPack = astPackManager.getLastDayPackByPlanNo(planTransferRule.getPlanNo(), curDate);
// 首次转让
if (lastPack == null) {
return true;
}
long dayDiff = DateTimeUtil.calcDayDiff(curDate, lastPack.getScenDate());
int compareDays = 0;
switch (planTransferRule.getTrCycle()) {
case D:
compareDays = 1;
break;
case W:
compareDays = 7;
break;
case M:
compareDays = 30;
break;
case Q:
compareDays = 90;
break;
case Y:
compareDays = 360;
break;
}
if (dayDiff >= compareDays) {
return true;
}
return false;
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import com.abssqr.plat.common.facade.enums.OrgAstStatStatusEnum;
import com.abssqr.plat.common.facade.enums.SyncTaskTypeEnum;
import com.abssqr.plat.common.facade.model.plan.PlanAst;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.model.domain.plan.PlanAstStatTask;
import com.abssqr.plat.common.model.repo.ast.PlanAstStatTaskRepo;
import com.abssqr.plat.common.model.repo.clearing.PlanClearingLogRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAstRepository;
import com.abssqr.plat.common.util.base.Day;
import com.abssqr.plat.core.service.plan.PlanManager;
import com.abssqr.plat.core.service.plan.PlanSyncTaskCtrManager;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.SystemDateUtil;
import com.general.system.common.util.VarChecker;
import com.general.system.tool.util.ToolUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 初始化每日统计清算流水任务
*
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.handler: PlanAstStatTaskHandler.java, v 0.1 2019-07-14 16:33 zhenxuan.luo Exp $
*/
@Component
public class PlanAstStatTaskHandler {
protected final Logger LOGGER = LoggerFactory.getLogger(PlanAstStatTaskHandler.class);
@Autowired
private PlanAstRepository planAstRepository;
@Autowired
private PlanClearingLogRepo planClearingLogRepo;
@Autowired
private PlanAstStatTaskRepo planAstStatTaskRepo;
@Autowired
private PlanSyncTaskCtrManager planSyncTaskCtrManager;
@Autowired
private PlanManager planManager;
/**
* 针对计划生成当日 统计任务
*
* @param planNo
*/
public void handle(String planNo, Day trfDate) {
// 查询锁水位表
PlanAst planAst = planAstRepository.lockByPlanNo(planNo);
VarChecker.checkNotNull(planAst, "计划[{0}]资产水位信息未初始化", planNo);
// 查询计划下的资产统计任务
PlanAstStatTask planAstStatTask = planAstStatTaskRepo.getPlanNo(planAst.getPlanNo());
boolean isNew = false;
// 1. 如果统计任务不存在,则新建
if (null == planAstStatTask) {
// 从未进行统计
planAstStatTask = this.initplanAstStatTask(planAst);
isNew = true;
} else if (planAstStatTask.getStatus() != OrgAstStatStatusEnum.WAIT) {
return;
}
// 2. 如果统计任务是新建的或者当前日期大于统计任务的会计日期,则重新捞取会计日期
if (isNeedResetAccountDate(planAstStatTask.getAccountDate(), planAstStatTask.getPlanNo(), trfDate)) {
Date minAcctDate = planClearingLogRepo.getMinUnStateAccountDate(planAstStatTask.getPlanNo(), null);
if (null == minAcctDate) {
// 没有待处理的流水,直接更新
planAstStatTask.setAccountDate(trfDate.getStandardDate());
planAst.setLastUpdateDate(planAstStatTask.getAccountDate());
planAstRepository.update(planAst);
} else {
// 注意:有可能仍然是原来的会计日期,因为有部分流水没处理完
if (DateTimeUtil.calcDayDiff(minAcctDate, planAstStatTask.getAccountDate()) <= 0) {
LogUtil.warn(LOGGER, "计划统计任务[{0}]初始化,重置日期后,仍然为当日,可能有部分任务阻塞", planAstStatTask);
}
planAstStatTask.setAccountDate(minAcctDate);
}
}
// 重置任务状态为活跃
resetTaskState(planAstStatTask);
// 4. 若任务不存在,则生成任务。若任务存在,则将任务状态修订为执行中,等待dispatcher捞起。(如果已经在执行中则忽略)
if (isNew) {
planAstStatTaskRepo.createTask(planAstStatTask);
} else {
planAstStatTaskRepo.updateTask(planAstStatTask);
}
}
private void resetTaskState(PlanAstStatTask planAstStatTask) {
planAstStatTask.setStatus(OrgAstStatStatusEnum.ACTIVE);
planAstStatTask.setLastExecTime(planAstStatTask.getNextExecTime());
planAstStatTask.setNextExecTime(SystemDateUtil.getSystemDate());
planAstStatTask.setLastHost(null);
planAstStatTask.setExecTimes(0L);
}
private PlanAstStatTask initplanAstStatTask(PlanAst planAst) {
PlanAstStatTask planAstStatTask = new PlanAstStatTask();
planAstStatTask.setPlanNo(planAst.getPlanNo());
planAstStatTask.setAccountDate(planAst.getLastUpdateDate());
// 时间戳字段不做消费,只做登记便于排查问题
planAstStatTask.setLastExecTms("");
planAstStatTask.setMinId(0L);
planAstStatTask.setMaxId(0L);
planAstStatTask.setCnt(0L);
return planAstStatTask;
}
/**
* 判断是否重置日期
*
* @param taskAccountDate
* @param planNo
* @return
*/
private boolean isNeedResetAccountDate(Date taskAccountDate, String planNo, Day trfDate) {
Date standardTaskDate = DateTimeUtil.getStandardDate(taskAccountDate);
// 当前转让会计日期 小于 任务日 不重置日期
if (ToolUtil.isNotEmpty(standardTaskDate)
&& DateTimeUtil.calcDayDiff(trfDate.getStandardDate(), standardTaskDate) <= 0) {
return false;
}
// 任务日跨天+10分钟 大于 转让会计日 不重置日期
Date refDate = DateTimeUtil.addMinutes(DateTimeUtil.addDays(standardTaskDate, 1), 10);
if (refDate.compareTo(trfDate.getDate()) > 0) {
return false;
}
// 取转让会计日-1 作为机构会计日判断是否完成模型转换
Date orgDate = trfDate.getYesterday().getStandardDate();
PlanBase planBase = planManager.getPlanFullByNo(planNo);
return planSyncTaskCtrManager.checkSyncFinishGtIsTrue(planBase, orgDate, SyncTaskTypeEnum.AST_MOD);
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.handler;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.abssqr.plat.common.facade.enums.AbssqrNoticeTypeEnum;
import com.abssqr.plat.common.facade.enums.PlanAllocStatusEnum;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.facade.model.plan.PlanAlloc;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.plan.PlanTransferRule;
import com.abssqr.plat.common.model.domain.plan.PlanAstLog;
import com.abssqr.plat.common.model.repo.plan.PlanAcctTitleRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAllocRepo;
import com.abssqr.plat.common.model.repo.plan.PlanTransferRuleRepo;
import com.abssqr.plat.core.service.notice.AbssqrNoticeManager;
import com.abssqr.plat.core.service.plan.PlanAllocAmtCalcManager;
import com.abssqr.plat.core.service.plan.PlanAstManager;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.tool.util.ToolUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
/**
* 计算计划每日为分配兑付 预留冻结金额
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.handler: PlanCashFrozenHandler.java, v 0.1 2019-06-13 15:39 zhenxuan.luo Exp $
*/
@Component
public class PlanCashFrozenHandler {
private final static Logger LOGGER = LoggerFactory.getLogger(PlanCashFrozenHandler.class);
private final static int DAY_OFFSET = 15;
@Autowired
private AbssqrNoticeManager abssqrNoticeManager;
@Autowired
private PlanAstManager planAstManager;
@Autowired
private PlanAllocRepo planAllocRepo;
@Autowired
private PlanTransferRuleRepo planTransferRuleRepo;
@Autowired
private PlanAllocAmtCalcManager planAllocAmtCalcManager;
@Autowired
private PlanAcctTitleRepo planAcctTitleRepo;
/**
* 资金冻结:需要在外部起事务,保证冻结和任务状态一致,避免重复冻结
* @param planEntity 计划
* @param curDate 转让会计日
*/
public void execute(PlanBase planEntity, Date curDate) {
LogUtil.info(LOGGER, "执行{0}[{1}]水位冻结任务", planEntity.getPlanType().getDesc(), planEntity.getPlanNo());
// 1. 查找未来最近的分配计划,考虑最近期限(15天)之内多个分配计划日期较近的全部进行判断处理
List<PlanAlloc> planAllocList = planAllocRepo.queryUnassigneAllocByPlanNo(planEntity.getPlanNo());
if (ToolUtil.isEmpty(planAllocList)) {
LogUtil.warn(LOGGER, "没有找到{0}[{1}]的最近未来分配计划, 当前时间[{1}]",
planEntity.getPlanType().getDesc(), planEntity.getPlanNo(), curDate);
return;
}
// 2. 判断分配当期是否处于循环期,若不属于循环期,不做资金预留
if (!this.filteNeedFrozenAllocs(curDate, planAllocList, planEntity)) {
return;
}
// 3. 计算分配日需要分配的资金 填充需要分配的本金 费用 等金额
List<PlanAcctTitle> planAcctTitles = planAcctTitleRepo.getByEntityNo(planEntity.getPlanNo());
planAllocAmtCalcManager.calcTriAmtByScheduler(planEntity, planAllocList, planAcctTitles, true);
// 计算合计总共需要兑付金额
Money totalAllocAmt = new Money();
// 多个分配兑付日
String clearDates = CollectionUtil.join(planAllocList.stream().map(alloc -> {
totalAllocAmt.addTo(alloc.calcTotalTrialAmt());
return DateUtil.formatDate(alloc.getClearDate());
}).collect(Collectors.toList()), ",");
// 计算并执行每日冻结水位资金
PlanAstLog planAstLog = planAstManager.calcFrozen(curDate, planEntity.getPlanNo(), planAllocList, clearDates);
// 4. 计算近30天的日均还款
Date startDate = DateTimeUtil.addDays(curDate, -31);
Date endDate = DateTimeUtil.addDays(curDate, -1);
startDate = (startDate.compareTo(planEntity.getEffectDate()) > 0) ? startDate : planEntity.getEffectDate();
/**
* 获取每日变更水位的还款金额
* 放款池计算还款包含了承接池的还款-- 因为承接池还会转让将资金转回放款池,所以暂时不计
*/
Money avgRepoAmt = planAstManager.getRepayTransAmtStat(
planEntity.getPlanNo(), startDate, endDate, true);
if (planAstLog.getFrozenCashAmt().greaterThan(avgRepoAmt)
&& planAstLog.getFrozenCash().greaterThan(planAstLog.getCash())) {
// 提醒优化,可能计划本来就有很多钱,这个时候还款金额是不是足够其实不重要
String msg = MessageUtil.formatMsg(
"分配计划日期为[{0}],存在兑付风险,待兑付金额{1}元。平均每日还款金额{2}元,今日冻结金额{3}元,计划资金余额{4}元,计划所有已冻结金额{5}元"
, clearDates, totalAllocAmt, avgRepoAmt, planAstLog.getFrozenCashAmt(),
planAstLog.getCash(), planAstLog.getFrozenCash());
// 插入一条通知,每日还款金额小于每日冻结金额
abssqrNoticeManager.sendBusinessNotice(planEntity, planEntity.getPlanNo(),
AbssqrNoticeTypeEnum.PlanAllocRisk, msg, null);
LogUtil.warn(LOGGER, msg);
}
}
/**
* 判断是否分配计划是否需要冻结资金
* @param curDate
* @param planAllocs
* @param planBase
* @return
*/
private boolean filteNeedFrozenAllocs(Date curDate, List<PlanAlloc> planAllocs, PlanBase planBase) {
String planNo = planBase.getPlanNo();
Date stopTrDate = null;
// 承接池进行判断循环结构及期限
if (planBase.getPlanType() == PlanTypeEnum.PLAN){
// 查询计划转让规则
PlanTransferRule transferRules = planTransferRuleRepo.getByPlanNo(planNo);
if (null == transferRules) {
LogUtil.warn(LOGGER, "没有找到计划[{0}]的转让规则", planNo);
return false;
}
// 非循环结构
if (!transferRules.getCycle()) {
LogUtil.info(LOGGER, "计划[{0}]不需要冻结预留资金水位,计划非循环结构[{1}]", planNo, transferRules.getCycle());
return false;
}
// 循环结果,判断循环期
if (DateTimeUtil.calcDayDiff(curDate, transferRules.getStopTrDate()) >= 0) {
// 当前日期已经停止循环
LogUtil.info(LOGGER, "计划[{0}]不需要冻结预留资金水位,当期日期[{1}]大于等于循环期[{2}]", planNo, curDate,
transferRules.getStopTrDate());
return false;
}
// 转让终止日
stopTrDate = transferRules.getStopTrDate();
}
Iterator<PlanAlloc> it = planAllocs.iterator();
while (it.hasNext()) {
PlanAlloc planAlloc = it.next();
if (planAlloc.getStatus() == PlanAllocStatusEnum.ASSIGNED) {
// 剔除已分配
it.remove();
continue;
}
if (DateTimeUtil.calcDayDiff(planAlloc.getClearDate(), curDate) > DAY_OFFSET) {
// 距离结算日提前15天预留资金
LogUtil.info(LOGGER, "计划[{0}]不需要冻结预留资金水位,当期日期[{1}]距离最近分配计划结算日[{2}]大于[{3}]天",
planNo, curDate,
planAlloc.getClearDate(),
DAY_OFFSET);
//移除该对象
it.remove();
continue;
}
if (stopTrDate != null && DateTimeUtil.calcDayDiff(stopTrDate, planAlloc.getClearDate()) < 0) {
// 分配计划结算日在循环期内,需要冻结
LogUtil.info(LOGGER, "计划[{0}]需要冻结预留资金水位,分配计划[{1}]结算日[{2}]小于循环期[{3}]", planNo,
planAlloc.getAllocNo(),
planAlloc.getClearDate(),
stopTrDate);
//移除该对象
it.remove();
continue;
}
}
if (ToolUtil.isNotEmpty(planAllocs)) {
// 剩余场景:停止循环日期大于当前日期 且 停止循环日期小于分配计划结算日。保险期间,做资金预留
return true;
} else {
return false;
}
}
}
\ No newline at end of file
/**
* abssqr.comInc.
* Copyright(c)2019-2019AllRightsReserved.
*/
package com.abssqr.plat.biz.shared.listener;
import com.abssqr.plat.common.facade.model.CommonPlanEntity;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import org.springframework.context.ApplicationEvent;
/**
*
* @author yangcheng
* @version PlanMonitorRecordEvent.java, v0.12019-07-0414:48 yangchengExp$
*/
public class PlanMonitorRecordEvent extends ApplicationEvent {
private PlanReport planReport;
private PlanBase planEntity;
public PlanMonitorRecordEvent(Object source, PlanReport planReport, PlanBase planEntity) {
super(source);
this.planReport = planReport;
this.planEntity = planEntity;
}
public PlanReport getPlanReport() {
return planReport;
}
public void setPlanReport(PlanReport planReport) {
this.planReport = planReport;
}
public PlanBase getPlanEntity() {
return planEntity;
}
public void setPlanEntity(PlanBase planEntity) {
this.planEntity = planEntity;
}
}
/**
* abssqr.comInc.
* Copyright(c)2019-2019AllRightsReserved.
*/
package com.abssqr.plat.biz.shared.listener;
import com.abssqr.plat.common.facade.enums.PlanIndicatorEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.plan.PlanMonitor;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.utils.CalcUtil;
import com.abssqr.plat.common.model.repo.plan.impl.PlanMonitorRecordRepoImpl;
import com.abssqr.plat.common.model.repo.plan.impl.PlanMonitorRepoImpl;
import com.abssqr.plat.core.service.notice.AbssqrNoticeManager;
import com.abssqr.plat.core.service.util.RptBuilderUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.VarChecker;
import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.math.BigDecimal;
import java.util.List;
/**
* @author yangcheng
* @version PlanMonitorRecordListener.java, v0.12019-07-0414:22 yangchengExp$
*/
@Component
public class PlanMonitorRecordListener {
private static final Logger LOGGER = LoggerFactory.getLogger(PlanMonitorRecordListener.class);
@Autowired
private PlanMonitorRepoImpl planMonitorRepo;
@Autowired
private PlanMonitorRecordRepoImpl planMonitorRecordRepo;
@Autowired
private AbssqrNoticeManager abssqrNoticeManager;
@Autowired
private TransactionTemplate transactionTemplate;
/**
* 更新每日监控事件触发情况
*
* @param orderEvent 监听事件
*/
@EventListener
public void planMonitorRecordListener(PlanMonitorRecordEvent orderEvent) {
PlanReport planReport = orderEvent.getPlanReport();
VarChecker.checkNotNull(planReport);
String planNo = planReport.getPlanNo();
List<PlanMonitor> planMonitorList = planMonitorRepo.getByPlan(planNo);
if(CollectionUtils.isNotEmpty(planMonitorList)) {
transactionTemplate.execute(status -> {
for (PlanMonitor planMonitor : planMonitorList) {
//获取文件名,报表信息
String reportFieldCode = planMonitor.getIndicator().getReportFieldCode();
BigDecimal nowVal = RptBuilderUtil.getReportVal(planReport, reportFieldCode);
// nowVal * 100
CalcUtil.calcPercRate(nowVal);
LogUtil.info(LOGGER, "该计划{0}监控指标{1}检测", planMonitor.getPlanNo(),
planMonitor.getIndicator().getDesc());
if (this.allowInsert(planMonitor.getIndicator(), planMonitor.getValue(), nowVal)) {
LogUtil.info(LOGGER, "该计划{0}监控指标{1}为{2}已违标{3}", planMonitor.getPlanNo(),
planMonitor.getIndicator(),
planMonitor.getValue(), nowVal);
//监控信息表新插入
planMonitorRecordRepo.insert(planMonitor, nowVal);
//消息通知表新插入
this.insertMess(orderEvent.getPlanEntity() , planMonitor, nowVal);
}
}
return null;
});
}
}
/**
* 插入消息通知
*
* @param param
*/
private void insertMess(PlanBase planBase, PlanMonitor param, BigDecimal nowVal) {
//插入消息通知数据
String bizCode = param.getPlanNo();
PlanIndicatorEnum bizType = param.getIndicator();
String content = MessageUtil.formatMsg("指标[{1}] 事项名称[{0}] 标准为[{2}]%,当前为[{3}]%,{}",
bizType.getDesc(), param.getName(), param.getValue(), nowVal, bizType.isTopLimit() ? "已超标" : "已不足");
abssqrNoticeManager.sendBusinessNotice(planBase, bizCode, bizType, content, null);
}
/**
* 上下限统一判断
*
* @param indicator
* @param repoVal
* @param nowVal
* @return
*/
private boolean allowInsert(PlanIndicatorEnum indicator, BigDecimal repoVal, BigDecimal nowVal) {
return indicator.isTopLimit() ? repoVal.compareTo(nowVal) < 1 : repoVal.compareTo(nowVal) > -1;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.report;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PlanAstReportStat;
import com.general.system.tool.util.ToolUtil;
import java.math.BigDecimal;
/**
* 统计金额字段计算工具
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.report: PlanAstStatAmtUtil.java, v 0.1 2019-06-28 16:22 zhenxuan.luo Exp $
*/
public class PlanAstStatAmtUtil {
/**
* 总发生额 = 本金总额 + 利息总额 + 罚息总额
* @param stat
* @return
*/
public static BigDecimal getAll(PlanAstReportStat stat) {
return getPrin(stat).add(getAllIntrWithPny(stat));
}
/**
* 本金金额
* @param stat
* @return
*/
public static BigDecimal getPrin(PlanAstReportStat stat) {
return stat.getPrinAmt().add(stat.getOvdPrinAmt()).getAmount();
}
/**
* 成本发生额
* @param stat
* @return
*/
public static BigDecimal getCost(PlanAstReportStat stat) {
return ToolUtil.isEmpty(stat.getCost()) ? BigDecimal.ZERO : stat.getCost().getAmount();
}
/**
* 金融服务费发生额
* @param stat
* @return
*/
public static BigDecimal getOrgDistPftAmt(PlanAstReportStat stat) {
return ToolUtil.isEmpty(stat.getOrgDistpftAmt()) ? BigDecimal.ZERO : stat.getOrgDistpftAmt().getAmount();
}
/**
* 金融服务费发生额
* @param stat
* @return
*/
public static BigDecimal getOtherFeeAmt(PlanAstReportStat stat) {
return ToolUtil.isEmpty(stat.getOtherFeeAmt()) ? BigDecimal.ZERO : stat.getOtherFeeAmt().getAmount();
}
/**
* 本罚+息罚+费罚
* @param stat
* @return
*/
public static BigDecimal getAllPny(PlanAstReportStat stat) {
return stat.getPrinPenalAmt().add(stat.getIntrPenalAmt()).add(stat.getFeePenalAmt()).getAmount();
}
/**
* 利息发生额+费用发生额
* @param stat
* @return
*/
public static BigDecimal getAllIntr(PlanAstReportStat stat) {
// 正常利息 + 逾期利息 + 费用
return stat.getIntrAmt().add(stat.getOvdIntrAmt()).add(stat.getFeeAmt()).getAmount();
}
/**
* 利息总额 + 罚息总额
* @param stat
* @return
*/
public static BigDecimal getAllIntrWithPny(PlanAstReportStat stat) {
return getAllIntr(stat).add(getAllPny(stat));
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.report;
import cn.hutool.core.util.NumberUtil;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PlanAstReportStat;
import com.abssqr.plat.common.facade.enums.EventCodeEnum;
import com.abssqr.plat.common.facade.enums.ReportAstStatTypeEnum;
import com.abssqr.plat.common.facade.model.report.ReportKey;
import com.abssqr.plat.common.model.convertor.ReportItemStatConvert;
import org.springframework.stereotype.Component;
/**
*
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.report: ReportItemFIlter.java, v 0.1 2019-06-28 02:27 zhenxuan.luo Exp $
*/
@Component
public class ReportItemFilter {
/**
* 合并统计项
* @param vals
* @return
*/
public PlanAstReportStat combine(PlanAstReportStat... vals) {
return ReportItemStatConvert.combine(vals);
}
/**
* 统计累计项
* @param reportStatMap
* @param eventCode
* @param type
* @param vals
* @return
*/
public PlanAstReportStat filter(ReportStatMap reportStatMap, EventCodeEnum eventCode, ReportAstStatTypeEnum type,
String... vals) {
PlanAstReportStat res = ReportItemStatConvert.createReportStat(type, eventCode, "");
for (String val : vals) {
PlanAstReportStat reportStat = filteForVal(reportStatMap, type, eventCode, val);
res.setAstChg(NumberUtil.add(res.getAstChg() , reportStat.getAstChg()).longValue());
res.setPrinAmt(ReportItemStatConvert.addWithNull(res.getPrinAmt(), reportStat.getPrinAmt()));
res.setOvdPrinAmt(ReportItemStatConvert.addWithNull(res.getOvdPrinAmt(), reportStat.getOvdPrinAmt()));
res.setIntrAmt(ReportItemStatConvert.addWithNull(res.getIntrAmt(), reportStat.getIntrAmt()));
res.setOvdIntrAmt(ReportItemStatConvert.addWithNull(res.getOvdIntrAmt(), reportStat.getOvdIntrAmt()));
res.setFeeAmt(ReportItemStatConvert.addWithNull(res.getFeeAmt(), reportStat.getFeeAmt()));
res.setOvdFeeAmt(ReportItemStatConvert.addWithNull(res.getOvdFeeAmt(), reportStat.getOvdFeeAmt()));
res.setPrinPenalAmt(ReportItemStatConvert.addWithNull(res.getPrinPenalAmt(), reportStat.getPrinPenalAmt()));
res.setIntrPenalAmt(ReportItemStatConvert.addWithNull(res.getIntrPenalAmt(), reportStat.getIntrPenalAmt()));
res.setFeePenalAmt(ReportItemStatConvert.addWithNull(res.getFeePenalAmt(), reportStat.getFeePenalAmt()));
// 费用
res.setOtherFeeAmt(ReportItemStatConvert.addWithNull(res.getOtherFeeAmt(), reportStat.getOtherFeeAmt()));
res.setOtherFeePenalAmt(ReportItemStatConvert.addWithNull(res.getOtherFeePenalAmt(), reportStat.getOtherFeePenalAmt()));
res.setCost(ReportItemStatConvert.addWithNull(res.getCost(), reportStat.getCost()));
}
return res;
}
private PlanAstReportStat filteForVal(ReportStatMap reportStatMap, ReportAstStatTypeEnum type,
EventCodeEnum eventCode, String val) {
ReportKey reportKey = new ReportKey(type.getCode(), val, eventCode);
PlanAstReportStat res = reportStatMap.get(reportKey);
if (res == null) {
res = ReportItemStatConvert.createReportStat(type, eventCode, val);
} else {
if (res.getAstChg() == null) {
res.setAstChg(0L);
}
}
return res;
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.report;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PlanAstReportStat;
import com.abssqr.plat.common.facade.model.report.ReportKey;
import java.util.HashMap;
import java.util.List;
/**
*
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.report: ReportStatMap.java, v 0.1 2019-06-28 02:54 zhenxuan.luo Exp $
*/
public class ReportStatMap extends HashMap<ReportKey, PlanAstReportStat> {
private static final long serialVersionUID = -2765549625728233654L;
public static ReportStatMap buildReportMap(List<PlanAstReportStat> planAstReportStatList) {
ReportStatMap reportStatMap = new ReportStatMap();
for (PlanAstReportStat planAstReportStat : planAstReportStatList) {
ReportKey key = new ReportKey(planAstReportStat.getStatType(), planAstReportStat.getStatVal(),
planAstReportStat.getEventCode());
reportStatMap.put(key, planAstReportStat);
}
return reportStatMap;
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.report.wk;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NumberUtil;
import com.abssqr.plat.biz.shared.report.PlanAstStatAmtUtil;
import com.abssqr.plat.biz.shared.report.ReportItemFilter;
import com.abssqr.plat.biz.shared.report.ReportStatMap;
import com.abssqr.plat.common.dal.mysql.auto.dao.LoanBakDAO;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.LoanAstProfitStat;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.LoanBakFormationItem;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PlanAstReportStat;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PlanStatItem;
import com.abssqr.plat.common.facade.enums.AstFlowTypeEnum;
import com.abssqr.plat.common.facade.enums.AstRiskClassEnum;
import com.abssqr.plat.common.facade.enums.CommonErrorCodeEnum;
import com.abssqr.plat.common.facade.enums.EventCodeEnum;
import com.abssqr.plat.common.facade.enums.LoanStatusEnum;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.enums.ReportAstStatTypeEnum;
import com.abssqr.plat.common.facade.enums.ReportDimTypeEnum;
import com.abssqr.plat.common.facade.enums.ReportTitleGroupEnum;
import com.abssqr.plat.common.facade.enums.ReportTypeEnum;
import com.abssqr.plat.common.facade.enums.StageChangeTypeEnum;
import com.abssqr.plat.common.facade.enums.TransCodeEnum;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.report.DailyReportDateField;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.model.report.PlanReportItem;
import com.abssqr.plat.common.facade.model.report.ReportField;
import com.abssqr.plat.common.facade.model.report.ReporterItemCodeKey;
import com.abssqr.plat.common.facade.model.report.Statistics;
import com.abssqr.plat.common.facade.model.report.wk.WkAstReportFields;
import com.abssqr.plat.common.facade.utils.CalcUtil;
import com.abssqr.plat.common.model.domain.plan.PlanAcctTitleLog;
import com.abssqr.plat.common.model.enums.OvdDaysTypeEnum;
import com.abssqr.plat.common.model.enums.TraderTypeEnum;
import com.abssqr.plat.common.model.exception.AbssqrBizException;
import com.abssqr.plat.common.model.repo.loanTrans.LoanAstProfitLogRepo;
import com.abssqr.plat.common.model.repo.report.PlanReportRepo;
import com.abssqr.plat.core.service.report.ReportItemHolder;
import com.abssqr.plat.core.service.report.calc.impl.CommonItemCalc;
import com.abssqr.plat.core.service.util.RptBuilderUtil;
import com.general.system.common.model.Money;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.VarChecker;
import com.general.system.tool.util.ToolUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* 日报表统计项生成
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.report: WkReportBuilder.java, v 0.1 2019-06-28 02:19 zhenxuan.luo Exp $
*/
@Component
public class WkAstReportBuilder {
@Autowired
private ReportItemFilter reportItemFilter;
@Autowired
private PlanReportRepo planReportRepo;
@Autowired
private LoanBakDAO loanBakDAO;
@Autowired
private LoanAstProfitLogRepo loanAstProfitLogRepo;
/**
* 资产日报
*
* @param planBase
* @param lastReport
* @param reportField
* @param statLoanBakBal
* @param statAmt
* @param planStatItems
* @param acctTitleLogMap
* @param spvDPlanNos spv计划对应的受让计划编号
* @return
*/
public List<PlanReportItem> buildReport(PlanBase planBase, PlanReport lastReport,
DailyReportDateField reportField,
List<PlanAstReportStat> statLoanBakBal,
List<PlanAstReportStat> statAmt,
List<PlanAstReportStat> statAccrued,
List<PlanStatItem> planStatItems,
Map<ReportTitleGroupEnum, List<PlanAcctTitleLog>> acctTitleLogMap,
List<String> spvDPlanNos) {
// 统计会计日
Date accountDate = reportField.getAccountDate();
// 余额
ReportStatMap statLoanBakBalMap = ReportStatMap.buildReportMap(statLoanBakBal);
// 发生额
ReportStatMap statAmtMap = ReportStatMap.buildReportMap(statAmt);
// 每日结息项统计
ReportStatMap statAccruedMap = ReportStatMap.buildReportMap(statAccrued);
// 清空初始化
ReportItemHolder.clearHolder();
//受让池报表放款池报表,不同区分开方便以后分开维护,目前能复用考虑的暂时考虑复用
if (planBase.getPlanType() == PlanTypeEnum.PLAN) {
//资金分析
ReportItemHolder.add(this.buildPlanCapitalReport(planBase, accountDate, planStatItems, lastReport));
//交易贷款分析
ReportItemHolder.add(
this.buildTfrPlanReport(planBase.getPlanNo(), accountDate, lastReport, statAmtMap));
} else if (planBase.getPlanType() == PlanTypeEnum.SPV) {
//查询受让计划报表
Map<ReporterItemCodeKey, Statistics> reportEntityMap = Maps.newHashMap();
if (CollectionUtils.isNotEmpty(spvDPlanNos)) {
spvDPlanNos.forEach(planNo -> {
PlanReport report = planReportRepo.getReport(planNo, ReportTypeEnum.RPT001, reportField.desc());
VarChecker.checkNotNull(report,"[{0}]SPV日报生成失败,找不到对应受让计划[{1}].[{2}]日报",
planBase.getPlanNo(),planNo,reportField.desc());
RptBuilderUtil.recordedData(report.getReportItems(), reportEntityMap);
});
}
//资金分析
ReportItemHolder.add(
this.buildSpvCapitalReport(planBase, accountDate, planStatItems, lastReport, statAmtMap, reportEntityMap, spvDPlanNos));
//交易贷款分析
ReportItemHolder.add(
this.buildTfrSpvReport(planBase.getPlanNo(), accountDate, lastReport, statAmtMap, reportEntityMap, spvDPlanNos));
}
// 资产分析 +核销分析 +逾期分析
ReportItemHolder.add(
this.buildAstReport(planBase.getPlanNo(), accountDate, lastReport, statLoanBakBalMap));
// 费用及兑付分析
ReportItemHolder.add(
this.buildFeeReport(planBase.getPlanNo(), accountDate, lastReport, acctTitleLogMap));
// 还款分析
ReportItemHolder.add(
this.buildRepoReport(planBase.getPlanNo(), accountDate, lastReport, statAmtMap, statAccruedMap));
// 五级分类余额统计
ReportItemHolder.add(
this.buildAstClzReport(planBase.getPlanNo(), accountDate, statLoanBakBalMap));
// 其余统计项计算
ReportItemHolder.add(
this.buildRestItemReport(planBase, accountDate, lastReport, acctTitleLogMap));
// 资产结构统计
ReportItemHolder.add(
this.buildAstFormationReport(planBase, accountDate));
return ReportItemHolder.getHolder();
}
/**
* 受让池资金分析
*
* @param planEntity
* @param accountDate
* @param planStatItems
* @param lastReport
* @return
*/
private List<PlanReportItem> buildPlanCapitalReport(PlanBase planEntity, Date accountDate,
List<PlanStatItem> planStatItems,
PlanReport lastReport) {
// 当日交易贷款资金发生额
BigDecimal WK003Amt = BigDecimal.ZERO;
// 当日还款资金发生额
BigDecimal WK004Amt = BigDecimal.ZERO;
// 兑付流出资金发生额
BigDecimal WK005Amt = BigDecimal.ZERO;
// 其他流出资金发生额
BigDecimal WK006Amt = BigDecimal.ZERO;
// 其他流入资金发生额
BigDecimal WK007Amt = BigDecimal.ZERO;
// 总流出资金发生额
BigDecimal WK008Amt = BigDecimal.ZERO;
// 总流入资金发生额
BigDecimal WK009Amt = BigDecimal.ZERO;
// 支付应付利息
BigDecimal WK100Amt = BigDecimal.ZERO;
// 放款冲正
BigDecimal WK101Amt = BigDecimal.ZERO;
// 冻结资金
BigDecimal WK000Amt = BigDecimal.ZERO;
// 资金流水上的回购资金流出
BigDecimal WK146Amt = BigDecimal.ZERO;
// 资金流水上的回购资金流入
BigDecimal WK147Amt = BigDecimal.ZERO;
// review一下金额计算逻辑 -- 应该是没影响,
for (PlanStatItem planStatItem : planStatItems) {
if (planStatItem.getPlanNo() == null) {
continue;
}
TransCodeEnum transCode = TransCodeEnum.getByCode(planStatItem.getTransCode());
BigDecimal frozenCashAmt = planStatItem.getFrozenCashAmt().getAmount();
//累计冻结发生额
WK000Amt = WK000Amt.add(frozenCashAmt);
// 获取变更水位完成交易的实际发生额,在途的交易金额 发生额都为0
BigDecimal amt = planStatItem.getCashAmt().getAmount();
if (BigDecimal.ZERO.compareTo(amt) == 0) {
continue;
}
if (transCode.getFundFlow() == AstFlowTypeEnum.FLOW_OUT) {
WK008Amt = WK008Amt.add(amt);
switch (transCode) {
case BUY_AST:
WK003Amt = WK003Amt.add(amt);
break;
case ALLOC:
WK005Amt = WK005Amt.add(amt);
break;
case PAY_HANG_INTR:
WK100Amt = WK100Amt.add(amt);
break;
case CAP_ADJ_SUB:
WK006Amt = WK006Amt.add(amt);
break;
case BUY_BACK_IN:
// 回购资产流入,资金流出
WK146Amt = WK146Amt.add(amt);
break;
default:
throw new AbssqrBizException(
MessageUtil.formatMsg("无法识别的计划[{0}]资金处理交易[{1}]", planEntity.getPlanNo(), transCode),
CommonErrorCodeEnum.INVALID_INTERNAL_MODEL);
}
} else if (transCode.getFundFlow() == AstFlowTypeEnum.FLOW_IN) {
WK009Amt = WK009Amt.add(amt);
switch (transCode) {
case REPO:
WK004Amt = WK004Amt.add(amt);
break;
case GRANT_REVERSE:
WK101Amt = WK101Amt.add(amt);
break;
case SELL_AST:
break;
case CAP_ADJ_ADD:
case CAP_INVEST:
WK007Amt = WK007Amt.add(amt);
break;
case BUY_BACK_OUT:
// 回购资产流出,资金流入
WK147Amt = WK147Amt.add(amt);
break;
default:
throw new AbssqrBizException(
MessageUtil.formatMsg("无法识别的计划[{0}]资金处理交易[{1}]", planEntity.getPlanNo(), transCode),
CommonErrorCodeEnum.INVALID_INTERNAL_MODEL);
}
}
}
// 上日闲置资金余额
BigDecimal lastWK001Amt = RptBuilderUtil.getReportVal(lastReport, WkAstReportFields.WK001.getCode());
// 闲置资金余额 = 上日闲置资金余额 + 总流入 - 总流出
BigDecimal WK001Amt = lastWK001Amt.add(WK009Amt).subtract(WK008Amt);
// 冻结金额 - 兑付流出资金发生额 = 冻结金额余额
WK000Amt = WK000Amt.subtract(WK005Amt);
List<PlanReportItem> ret = Lists.newArrayList();
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK000, 0L, WK000Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK001, 0L, WK001Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK003, 0L, WK003Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK004, 0L, WK004Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK005, 0L, WK005Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK006, 0L, WK006Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK007, 0L, WK007Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK008, 0L, WK008Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK009, 0L, WK009Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK100, 0L, WK100Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK101, 0L, WK101Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK135, 0L, WK005Amt, lastReport));
// 弃用: 转让当日应计挂帐利息
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK132, 0L, BigDecimal.ZERO));
// 回购金额的流出
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK146, 0L, WK146Amt));
// 回购金额的流入
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK147, 0L, WK147Amt));
return ret;
}
/**
* 放款池资金分析
*
* @param planEntity
* @param accountDate
* @param planStatItems
* @param lastReport
* @return
*/
private List<PlanReportItem> buildSpvCapitalReport(PlanBase planEntity, Date accountDate,
List<PlanStatItem> planStatItems,
PlanReport lastReport, ReportStatMap statAmtMap,
Map<ReporterItemCodeKey, Statistics> reportEntityMap,
List<String> planNos) {
// 冻结资金
BigDecimal WK000Amt = BigDecimal.ZERO;
//贷款还款资金发生额
BigDecimal WK004Amt = BigDecimal.ZERO;
//兑付流出资金发生额
BigDecimal WK005Amt = BigDecimal.ZERO;
//其他流出资金发生额
BigDecimal WK006Amt = BigDecimal.ZERO;
//其他流入资金发生额
BigDecimal WK007Amt = BigDecimal.ZERO;
// 支付应付利息
BigDecimal WK100Amt = BigDecimal.ZERO;
// 放款冲正
BigDecimal WK101Amt = BigDecimal.ZERO;
//转让贷款资金发生额
BigDecimal WK112Amt = BigDecimal.ZERO;
//新增资产发生额
BigDecimal WK111Amt = BigDecimal.ZERO;
// 回购资金发生额
BigDecimal WK146Amt = BigDecimal.ZERO;
for (PlanStatItem planStatItem : planStatItems) {
if (ToolUtil.isOneEmpty(planStatItem, planStatItem.getPlanNo())) {
continue;
}
StageChangeTypeEnum changeType = StageChangeTypeEnum.getByCode(planStatItem.getChangeType());
TraderTypeEnum traderType = TraderTypeEnum.getByCode(planStatItem.getTraderType());
TransCodeEnum transCode = TransCodeEnum.getByCode(planStatItem.getTransCode());
//累计冻结发生额
WK000Amt = WK000Amt.add(planStatItem.getFrozenCashAmt().getAmount());
// 获取变更水位完成交易的实际发生额,在途的交易金额 发生额都为0
BigDecimal amt = planStatItem.getCashAmt().getAmount();
if (BigDecimal.ZERO.compareTo(amt) == 0) {
continue;
}
switch (transCode) {
case BUY_AST:
// 放款池 资产交易兑付时只记增加
if (changeType == StageChangeTypeEnum.ADD) {
WK112Amt = WK112Amt.add(amt);
}
break;
case ALLOC:
WK005Amt = WK005Amt.add(amt);
break;
case PAY_HANG_INTR:
if (changeType == StageChangeTypeEnum.ADD) {
WK100Amt = WK100Amt.add(amt);
}
break;
case CAP_ADJ_SUB:
WK006Amt = WK006Amt.add(amt);
break;
case REPO:
if (changeType == StageChangeTypeEnum.ADD) {
// 放款池还款总金额 包含承接池还款金额
WK004Amt = WK004Amt.add(amt);
}else if (changeType == StageChangeTypeEnum.SUB
&& traderType == TraderTypeEnum.COUNTERPARTY) {
// 还款扣减并且为对手方时,还款兑付给承接池需要进行扣减还款金额
WK004Amt = WK004Amt.subtract(amt);
}
break;
//冲正发生额放款池无水位记录
case GRANT_REVERSE:
break;
case SELL_AST:
break;
case CAP_ADJ_ADD:
case CAP_INVEST:
WK007Amt = WK007Amt.add(amt);
break;
// case BUY_BACK_IN:
// // 针对放款池 从放款户进行回购资金交易,不产生资金流水,不进行统计处理
// break;
default:
throw new AbssqrBizException(
MessageUtil.formatMsg("无法识别的计划[{0}]资金处理交易[{1}]", planEntity.getPlanNo(), transCode),
CommonErrorCodeEnum.INVALID_INTERNAL_MODEL);
}
}
//放款池新增资产统计
PlanAstReportStat newStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.SYNC, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 还款补偿
PlanAstReportStat repoComponsateStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.REPAY_COMPONSATE, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 发放冲正
PlanAstReportStat grantStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.GRANT_REVERSE, ReportAstStatTypeEnum.ALL,CommonItemCalc.COMMON_VAL);
// 放款池回购登记 ReportEntity
PlanAstReportStat buybackStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.BACK_OUT, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
PlanAstReportStat allNewStat = reportItemFilter.combine(repoComponsateStat, newStat);
//新增贷款统计
WK111Amt = PlanAstStatAmtUtil.getPrin(allNewStat);
//放款冲统计
WK101Amt = PlanAstStatAmtUtil.getPrin(grantStat);
// 回购买入资产资金流出发生额
WK146Amt = PlanAstStatAmtUtil.getCost(buybackStat);
//计算总流入= 还款资金发生额+转让贷款资金发生额+其他流入资金发生额+放款冲正+应付利息
//计算总流入= 还款资金发生额+转让贷款资金发生额+其他流入资金发生额+放款冲正+转让资产应计应收利息+还款服务费
BigDecimal WK009Amt = WK112Amt.add(WK100Amt).add(WK007Amt).add(WK101Amt).add(WK004Amt);
//计算总流出=分配兑付+其他流出+放款 + 回购买入资产发生额
BigDecimal WK008Amt = WK005Amt.add(WK006Amt.add(WK111Amt).add(WK146Amt));
//冻结金额=上一日冻结金额+冻结发生额-分配兑付金额
WK000Amt = RptBuilderUtil.getReportVal(lastReport, WkAstReportFields.WK000.getCode()).add(WK000Amt).subtract(WK005Amt);
//统计回转服付金额=放款池还款+转让发生额+其他流入+应付利息-预冻结金额
BigDecimal WK110Amt = WK004Amt.add(WK100Amt).add(WK112Amt).subtract(WK000Amt);
List<PlanReportItem> ret = Lists.newArrayList();
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK000, 0L, WK000Amt));
//闲置资金余额=上一日闲置余额+总流入-总流出
BigDecimal lastWK001Amt = RptBuilderUtil.getReportVal(lastReport, WkAstReportFields.WK001.getCode());
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK001,
0L, lastWK001Amt.add(WK009Amt).subtract(WK008Amt)));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK004, 0L, WK004Amt));
// 兑付流出资金发生额
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK005, 0L, WK005Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK006, 0L, WK006Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK007, 0L, WK007Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK008, 0L, WK008Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK009, 0L, WK009Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK100, 0L, WK100Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK101, 0L, WK101Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK110, 0L, WK110Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK112, 0L, WK112Amt));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK111, 0L, WK111Amt));
// 弃用: 转让当日应计未收利息和 = 各承接池转让当日应计未付挂帐利息和
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK132, reportEntityMap, planNos));
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK135, 0L, WK005Amt, lastReport));
// 回购买入资产资金流出发生额
ret.add(buildReportItem(planEntity.getPlanNo(), accountDate, WkAstReportFields.WK146, 0L, WK146Amt));
return ret;
}
/**
* 资产分析 +核销分析 +逾期分析
*
* @param planNo
* @param accountDate
* @param lastPlanReport
* @param statBalMap 余额
* @return
*/
private List<PlanReportItem> buildAstReport(String planNo, Date accountDate, PlanReport lastPlanReport,
ReportStatMap statBalMap) {
// 正常贷款统计
PlanAstReportStat statusNorStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.STATUS,
LoanStatusEnum.NORMAL.getCode());
// 逾期贷款统计
PlanAstReportStat statusOvdStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.STATUS,
LoanStatusEnum.OVERDUE.getCode());
// 核销贷款统计
PlanAstReportStat statusWrtStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.WTF_STATUS,
YNEnum.Y.getCode());
// 逾期91天以上且核销贷款统计
PlanAstReportStat ovdWtfStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_WTF_STATUS,
CommonItemCalc.COMMON_VAL);
// 总贷款
PlanAstReportStat allStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.ALL,
CommonItemCalc.COMMON_VAL);
// 1-3 本金
PlanAstReportStat ovd01Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD01.getCode());
// 4-30 本金
PlanAstReportStat ovd02Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD02.getCode());
// 31-60 本金
PlanAstReportStat ovd03Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD03.getCode());
// 逾期61天-90天(含)本金余额
PlanAstReportStat ovd04Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD04.getCode());
// 逾期91天-179天本金余额
PlanAstReportStat ovd05Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD05.getCode());
// 逾期180天及以上本金余额
PlanAstReportStat ovd06Stat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.OVD_DAYS,
OvdDaysTypeEnum.OD06.getCode());
// 获取当日统计新增放款或转入贷款收益金额 通过loanBak的cost 获取所有资产成本
PlanAstReportStat profitAmt = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.ALL,
ReportDimTypeEnum.ACCRUED.getCode());
List<PlanReportItem> ret = Lists.newArrayList();
// 正常贷款本金余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK010,
statusNorStat.getAstChg(), PlanAstStatAmtUtil.getPrin(statusNorStat)));
// 正常贷款利息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK011,
statusNorStat.getAstChg(), PlanAstStatAmtUtil.getAllIntr(statusNorStat)));
// 逾期贷款本金余额
PlanReportItem ovdPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK012,
statusOvdStat.getAstChg(), PlanAstStatAmtUtil.getPrin(statusOvdStat));
ret.add(ovdPrin);
// 逾期贷款利息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK013,
statusOvdStat.getAstChg(), PlanAstStatAmtUtil.getAllIntr(statusOvdStat)));
// 逾期贷款罚息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK014,
statusOvdStat.getAstChg(), PlanAstStatAmtUtil.getAllPny(statusOvdStat)));
// 核销贷款本金余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK015,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getPrin(statusWrtStat)));
// 核销贷款利息余额(含罚息)
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK016,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getAllIntrWithPny(statusWrtStat)));
// 核销贷款利息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt002,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getAllIntr(statusWrtStat)));
// 核销贷款罚息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt003,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getAllPny(statusWrtStat)));
// 总贷款本金余额
PlanReportItem allPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK017,
allStat.getAstChg(), PlanAstStatAmtUtil.getPrin(allStat));
ret.add(allPrin);
// 总贷款利息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK018,
allStat.getAstChg(), PlanAstStatAmtUtil.getAllIntr(allStat)));
// 总贷款罚息余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK019,
allStat.getAstChg(), PlanAstStatAmtUtil.getAllPny(allStat)));
// 累计资产应计年化收益额
PlanReportItem profitItem = buildReportItem(planNo, accountDate, WkAstReportFields.WK128,
profitAmt.getAstChg(), PlanAstStatAmtUtil.getAllIntr(profitAmt));
ret.add(profitItem);
// 加权收益率 = WK128 Σ(每笔借据本金*该笔借据年化收益率)/ 对应资产总本金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK129, 0L,
CalcUtil.divide(profitItem.getAmt(), profitAmt.getPrinAmt().getAmount())));
// 逾期1天-3天(含)本金余额
PlanReportItem ovd01StatPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK021,
ovd01Stat.getAstChg(), PlanAstStatAmtUtil.getPrin(ovd01Stat));
ret.add(ovd01StatPrin);
// 逾期1天-30天(含)本金余额 1-3 加 4- 30
PlanReportItem ovd02StatPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK022,
NumberUtil.add(ovd01Stat.getAstChg(), ovd02Stat.getAstChg()).longValue(),
NumberUtil.add(PlanAstStatAmtUtil.getPrin(ovd01Stat), PlanAstStatAmtUtil.getPrin(ovd02Stat)));
ret.add(ovd02StatPrin);
// 逾期31天-60天(含)本金余额
PlanReportItem ovd03StatPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK023,
ovd03Stat.getAstChg(), PlanAstStatAmtUtil.getPrin(ovd03Stat));
ret.add(ovd03StatPrin);
// 逾期61天-90天(含)本金余额
PlanReportItem ovd04StatPrin =buildReportItem(planNo, accountDate, WkAstReportFields.WK024,
ovd04Stat.getAstChg(), PlanAstStatAmtUtil.getPrin(ovd04Stat));
ret.add(ovd04StatPrin);
// 逾期91天及以上本金余额 91-179 加 180以上
PlanReportItem ovd05StatPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WK025,
NumberUtil.add(ovd05Stat.getAstChg(), ovd06Stat.getAstChg()).longValue(),
NumberUtil.add(PlanAstStatAmtUtil.getPrin(ovd05Stat), PlanAstStatAmtUtil.getPrin(ovd06Stat)));
ret.add(ovd05StatPrin);
// 逾期180天及以上本金余额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK118,
ovd06Stat.getAstChg(), PlanAstStatAmtUtil.getPrin(ovd06Stat)));
// 逾期91天及以上非核销本金余额
PlanReportItem ovdWtfStatPrin = buildReportItem(planNo, accountDate, WkAstReportFields.WKExt001,
ovdWtfStat.getAstChg(), PlanAstStatAmtUtil.getPrin(ovdWtfStat));
ret.add(ovdWtfStatPrin);
/*** 计算分级逾期率 ***/
// 整体逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK020, ovdPrin.getAstCnt(),
CalcUtil.divide(ovdPrin.getAmt(), allPrin.getAmt())));
// M3+以上逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK026, ovd05StatPrin.getAstCnt(),
CalcUtil.divide(ovd05StatPrin.getAmt(), allPrin.getAmt())));
// 整体逾期率(不含宽限期)
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK120, ovdPrin.getAstCnt(),
CalcUtil.divide(ovdPrin.getAmt().subtract(ovd01StatPrin.getAmt()), allPrin.getAmt())));
// m0逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK121, ovd01StatPrin.getAstCnt(),
CalcUtil.divide(ovd01StatPrin.getAmt(), allPrin.getAmt())));
// m1逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK122, ovd02StatPrin.getAstCnt(),
CalcUtil.divide(ovd02StatPrin.getAmt(), allPrin.getAmt())));
// m1+逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK123,
NumberUtil.add(ovd03StatPrin.getAstCnt(), ovd04StatPrin.getAstCnt(), ovd05StatPrin.getAstCnt()).longValue(),
CalcUtil.divide(NumberUtil.add(ovd03StatPrin.getAmt(), ovd04StatPrin.getAmt(), ovd05StatPrin.getAmt()),
allPrin.getAmt())));
// m2逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK124, ovd03StatPrin.getAstCnt(),
CalcUtil.divide(ovd03StatPrin.getAmt(), allPrin.getAmt())));
// m3逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK125, ovd04StatPrin.getAstCnt(),
CalcUtil.divide(ovd04StatPrin.getAmt(), allPrin.getAmt())));
// M6+逾期率
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK126, ovd06Stat.getAstChg(),
CalcUtil.divide(PlanAstStatAmtUtil.getPrin(ovd06Stat), allPrin.getAmt())));
/**
* 发生额 = 今日余额 - 昨日报表余额
*/
// 当日逾期本金发生额
ret.add(RptBuilderUtil.buildDiffReportItem(planNo, accountDate, WkAstReportFields.WK049,
statusOvdStat.getAstChg(), PlanAstStatAmtUtil.getPrin(statusOvdStat), lastPlanReport));
// 当日逾期利息发生额
ret.add(RptBuilderUtil.buildDiffReportItem(planNo, accountDate, WkAstReportFields.WK050,
statusOvdStat.getAstChg(), PlanAstStatAmtUtil.getAllIntr(statusOvdStat), lastPlanReport));
// 当日核销本金发生额
ret.add(RptBuilderUtil.buildDiffReportItem(planNo, accountDate, WkAstReportFields.WK051,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getPrin(statusWrtStat), lastPlanReport));
// 当日核销利息发生额(含罚息)
ret.add(RptBuilderUtil.buildDiffReportItem(planNo, accountDate, WkAstReportFields.WK052,
statusWrtStat.getAstChg(), PlanAstStatAmtUtil.getAllIntrWithPny(statusWrtStat), lastPlanReport));
return ret;
}
/**
* 受让池交易贷款分析
*
* @param planNo
* @param accountDate
* @param lastPlanReport
* @param statAmtMap
* @return
*/
private List<PlanReportItem> buildTfrPlanReport(String planNo, Date accountDate, PlanReport lastPlanReport,
ReportStatMap statAmtMap) {
PlanAstReportStat tfrStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.TRANS_IN, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
/**
* 由于 LoanAstTrManager 中 使用TRANS_OUT 作为转让事件码 所有由原 TRANS_IN 改为 TRANS_OUT
* 兼容 如果 TRANS_OUT 没有时获取TRANS_IN
*/
if (BigDecimal.ZERO.compareTo(PlanAstStatAmtUtil.getPrin(tfrStat)) == 0){
tfrStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.TRANS_OUT, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
}
List<PlanReportItem> ret = Lists.newArrayList();
// 累计交易贷款发生
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK027, tfrStat.getAstChg(),
PlanAstStatAmtUtil.getCost(tfrStat), lastPlanReport));
// 当日交易贷款发生
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK028, tfrStat.getAstChg(),
PlanAstStatAmtUtil.getCost(tfrStat)));
// 累计交易贷款本金
PlanReportItem totalTrf = buildReportItem(planNo, accountDate, WkAstReportFields.WK102, tfrStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(tfrStat), lastPlanReport);
ret.add(totalTrf);
// 当日交易贷款本金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK103, tfrStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(tfrStat)));
// 回购卖出资产 对应发生额与本金
PlanAstReportStat buyBackStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.BACK_OUT, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 累计回购贷款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK144, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getCost(buyBackStat), lastPlanReport));
// 当日回购贷款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK145, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getCost(buyBackStat)));
// 累计回购贷款本金
ret.add( buildReportItem(planNo, accountDate, WkAstReportFields.WK142, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(buyBackStat), lastPlanReport));
// 当日回购贷款本金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK143, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(buyBackStat)));
return ret;
}
/**
* 放款池交易贷款分析
*
* @param spvNo
* @param accountDate
* @param lastPlanReport
* @param statAmtMap
* @param planNos 对应受让计划编号
* @return
*/
private List<PlanReportItem> buildTfrSpvReport(String spvNo, Date accountDate, PlanReport lastPlanReport,
ReportStatMap statAmtMap,
Map<ReporterItemCodeKey, Statistics> reportEntityMap,
List<String> planNos) {
//增量同步
PlanAstReportStat grantStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.SYNC, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
//还款补偿,当天放款当天还款数据
PlanAstReportStat repoComponsateStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.REPAY_COMPONSATE, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
//新增贷款发生额统计 = 增量同步 + 还款补偿
PlanAstReportStat allPreRepay = reportItemFilter.combine(grantStat, repoComponsateStat);
List<PlanReportItem> ret = Lists.newArrayList();
// 累计交易贷款发生
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK027, reportEntityMap, planNos));
// 当日交易贷款发生
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK028, reportEntityMap, planNos));
// 累计交易贷款本金
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK102, reportEntityMap, planNos));
// 当日交易贷款本金
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK103, reportEntityMap, planNos));
// 累计新增贷款
PlanReportItem totalGrant = buildReportItem(spvNo, accountDate, WkAstReportFields.WK116, grantStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allPreRepay), lastPlanReport);
ret.add(totalGrant);
// 当日新增资产
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK115, grantStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allPreRepay)));
// 回购买入资产 对应发生额与本金
PlanAstReportStat buyBackStat = reportItemFilter.filter(statAmtMap,
EventCodeEnum.BACK_OUT, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 累计回购贷款发生额
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK144, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getCost(buyBackStat), lastPlanReport));
// 当日回购贷款发生额
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK145, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getCost(buyBackStat)));
// 累计回购贷款本金
ret.add( buildReportItem(spvNo, accountDate, WkAstReportFields.WK142, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(buyBackStat), lastPlanReport));
// 当日回购贷款本金
ret.add(buildReportItem(spvNo, accountDate, WkAstReportFields.WK143, buyBackStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(buyBackStat)));
return ret;
}
/**
* 费用分析
* @param planNo
* @param accountDate
* @param lastReport
* @param acctTitleLogMap
* @return
*/
private List<PlanReportItem> buildFeeReport(String planNo, Date accountDate, PlanReport lastReport,
Map<ReportTitleGroupEnum, List<PlanAcctTitleLog>> acctTitleLogMap) {
List<PlanReportItem> ret = Lists.newArrayList();
// 获取金融服务费
Money finFeeAmt = RptBuilderUtil.getAcctTitleMoney(acctTitleLogMap, ReportTitleGroupEnum.FIN_SER_FEE);
// 当日金融服务费-->笔数逻辑
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK108, finFeeAmt.isZero() ? 0L : 1L,
finFeeAmt.getAmount()));
// 累计金融服务费-->如果发生则记一笔,如果没发生则不记一笔
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK109, finFeeAmt.isZero() ? 0L : 1L,
finFeeAmt.getAmount(), lastReport));
// 还款服务费 针对放款池统计时会有 , 承接池没有对应数据
LoanAstProfitStat repoFee = loanAstProfitLogRepo.getRepayOrgDistPftAmt(accountDate, planNo, null);
// 结息还款服务费
Money repayIntrFeeAmt = repoFee != null ? repoFee.getRepayIntrFeeAmt() : new Money();
// 实还还款服务费
Money fundRepayIntrFeeAmt = repoFee != null ? repoFee.getFundRepayIntrFeeAmt() : new Money();
// 当日结息还款服务费
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK136, 0L,
repayIntrFeeAmt.getAmount()));
// 累计结息还款服务费
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK137, 0L,
repayIntrFeeAmt.getAmount(), lastReport));
// 当日实还还款服务费
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK138, 0L,
fundRepayIntrFeeAmt.getAmount()));
// 累计实还还款服务费
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK139, 0L,
fundRepayIntrFeeAmt.getAmount(), lastReport));
return ret;
}
/**
* 还款分析
*
* @param planNo
* @param accountDate
* @param lastPlanReport
* @param statAmtMap
* @return
*/
private List<PlanReportItem> buildRepoReport(String planNo, Date accountDate, PlanReport lastPlanReport,
ReportStatMap statAmtMap, ReportStatMap statAccrued ) {
// 到期还款
PlanAstReportStat allDueRepayStat = reportItemFilter.filter(
statAmtMap, EventCodeEnum.DUE_REPAY, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 逾期还款
PlanAstReportStat allOvdRepayStat = reportItemFilter.filter(
statAmtMap, EventCodeEnum.ODUE_REPAY, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 提前还款
PlanAstReportStat allPreRepayStat = reportItemFilter.filter(
statAmtMap, EventCodeEnum.PRE_REPAY, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 还款补偿发生不分类
PlanAstReportStat allRepayComponsate = reportItemFilter.filter(
statAmtMap, EventCodeEnum.REPAY_COMPONSATE, ReportAstStatTypeEnum.ALL, CommonItemCalc.COMMON_VAL);
// 到期还款 核销
PlanAstReportStat wrtDueRepayStat = reportItemFilter.filter(
statAmtMap, EventCodeEnum.DUE_REPAY, ReportAstStatTypeEnum.WTF_STATUS, YNEnum.N.getCode());
PlanAstReportStat wrtOvdRepayStat = reportItemFilter
.filter(statAmtMap, EventCodeEnum.ODUE_REPAY,
ReportAstStatTypeEnum.WTF_STATUS,
YNEnum.N.getCode());
PlanAstReportStat wrtPreRepayStat = reportItemFilter
.filter(statAmtMap, EventCodeEnum.PRE_REPAY,
ReportAstStatTypeEnum.WTF_STATUS,
YNEnum.N.getCode());
//到期发生统计--》结息。转让-->增量记结息,存量记结息,同时可能发生转让
PlanAstReportStat allDueStat = reportItemFilter
.filter(statAccrued, null,
ReportAstStatTypeEnum.DUE,
LoanStatusEnum.OVERDUE.getCode(),
LoanStatusEnum.NORMAL.getCode());
//提前还款--内容组成:还款补偿+提前还款
PlanAstReportStat allPreRepay = reportItemFilter.combine(allRepayComponsate, allPreRepayStat);
//所有还款记录:到期还款,提前还款,逾期还款
PlanAstReportStat allRepay = reportItemFilter.combine(allDueRepayStat, allOvdRepayStat, allPreRepay);
//核销资产:到期还款,提前还款,逾期还款
PlanAstReportStat allWrtRepay = reportItemFilter.combine(wrtDueRepayStat, wrtOvdRepayStat, wrtPreRepayStat);
List<PlanReportItem> ret = Lists.newArrayList();
// 累计已还本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK029, allRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allRepay), lastPlanReport));
// 累计已还利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK030, allRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allRepay), lastPlanReport));
// 累计已还罚息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK031, allRepay.getAstChg(),
PlanAstStatAmtUtil.getAllPny(allRepay), lastPlanReport));
// 累计提前还款本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK032, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allPreRepay), lastPlanReport));
// 累计提前还款利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK033, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntrWithPny(allPreRepay), lastPlanReport));
// 累计逾期本金还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK034, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allOvdRepayStat), lastPlanReport));
// 累计逾期利息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK035, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allOvdRepayStat), lastPlanReport));
// 累计逾期罚息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK036, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(allOvdRepayStat), lastPlanReport));
// 累计核销本金还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK037, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allWrtRepay), lastPlanReport));
// 累计核销利息还款发生额(含罚息)
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK038, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntrWithPny(allWrtRepay), lastPlanReport));
// 当日已还本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK039, allRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allRepay)));
// 当日已还利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK040, allRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allRepay)));
// 当日已还罚息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK041, allRepay.getAstChg(),
PlanAstStatAmtUtil.getAllPny(allRepay)));
// 当日提前还款本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK042, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allPreRepay)));
// 当日提前还款利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK043, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntrWithPny(allPreRepay)));
// 当日逾期本金还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK044, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allOvdRepayStat)));
// 当日逾期利息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK045, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allOvdRepayStat)));
// 当日逾期罚息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK046, allOvdRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(allOvdRepayStat)));
// 当日核销本金还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK047, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getPrin(allWrtRepay)));
// 当日核销利息还款发生额(含罚息)
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK048, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntrWithPny(allWrtRepay)));
// 当日计划应还本金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK104, allDueStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allDueStat)));
// 当日计划应还利息
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK105, allDueStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allDueStat)));
// 当日应还已还本金发生额--》应还应该归属到期本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK106, allDueRepayStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allDueRepayStat)));
// 当日应还已还利息发生额--》应还应该归属到期利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK107, allDueRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allDueRepayStat)));
// 当日核销利息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt006, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(allWrtRepay)));
// 当日核销罚息还款发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt007, allWrtRepay.getAstChg(),
PlanAstStatAmtUtil.getAllPny(allWrtRepay)));
// 当日到期还款本金发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt004, allDueRepayStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(allDueRepayStat)));
// 当日到期还款利息发生额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKExt005, allDueRepayStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntrWithPny(allDueRepayStat)));
// 当日提前还款违约金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK140, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getOtherFeeAmt(allPreRepay)));
// 累计提前还款违约金
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK141, allPreRepay.getAstChg(),
PlanAstStatAmtUtil.getOtherFeeAmt(allPreRepay), lastPlanReport));
return ret;
}
/**
* 五级分类分析
*
* @param planNo
* @param accountDate
* @param statBalMap
* @return
*/
private List<PlanReportItem> buildAstClzReport(String planNo, Date accountDate, ReportStatMap statBalMap) {
// 正常贷款统计
PlanAstReportStat norlStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.AST_CLZ,
AstRiskClassEnum.NORMAL.getCode());
// 关注
PlanAstReportStat attnStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.AST_CLZ,
AstRiskClassEnum.ATTENTION.getCode());
// 次级
PlanAstReportStat secdStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.AST_CLZ,
AstRiskClassEnum.SECONDARY.getCode());
// 可疑
PlanAstReportStat suspStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.AST_CLZ,
AstRiskClassEnum.SUSPICIOUS.getCode());
// 损失
PlanAstReportStat lossStat = reportItemFilter.filter(statBalMap, null, ReportAstStatTypeEnum.AST_CLZ,
AstRiskClassEnum.LOSS.getCode());
List<PlanReportItem> ret = Lists.newArrayList();
// 正常
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK911, norlStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(norlStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK912, norlStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(norlStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK913, norlStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(norlStat)));
// 关注
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK921, attnStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(attnStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK922, attnStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(attnStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK923, attnStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(attnStat)));
// 次级
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK931, secdStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(secdStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK932, secdStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(secdStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK933, secdStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(secdStat)));
// 可疑
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK941, suspStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(suspStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK942, suspStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(suspStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK943, suspStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(suspStat)));
// 损失
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK951, lossStat.getAstChg(),
PlanAstStatAmtUtil.getPrin(lossStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK952, lossStat.getAstChg(),
PlanAstStatAmtUtil.getAllIntr(lossStat)));
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK953, lossStat.getAstChg(),
PlanAstStatAmtUtil.getAllPny(lossStat)));
return ret;
}
/**
* 其余统计项
* 通过线程暂存统计结果进行计算得出
* @param planBase
* @param accountDate
* @param lastPlanReport
* @return
*/
private List<PlanReportItem> buildRestItemReport(PlanBase planBase, Date accountDate, PlanReport lastPlanReport,
Map<ReportTitleGroupEnum, List<PlanAcctTitleLog>> acctTitleLogMap ) {
String planNo = planBase.getPlanNo();
PlanTypeEnum planType = planBase.getPlanType();
List<PlanReportItem> ret = Lists.newArrayList();
// 关于当日投入资本的兑付本金
Money allocPrin = RptBuilderUtil.getAcctTitleMoney(acctTitleLogMap, ReportTitleGroupEnum.INVESTED_DAY);
// 计划当日兑付本金金额
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WKPlan001,0L, allocPrin.getAmount()));
// 计划累计兑付本金金额
PlanReportItem WKPlan002AmtItem = buildReportItem(planNo, accountDate, WkAstReportFields.WKPlan002,
0L, allocPrin.getAmount(), lastPlanReport);
ret.add(WKPlan002AmtItem);
// 不良率 = WK025逾期91天及以上本金余额 / 承接池:WK102累计交易贷款本金|放款池:WK116累计新增贷款发生额
BigDecimal denominator = ReportItemHolder.getPlanReportItemHolder(planNo,
PlanTypeEnum.PLAN == planType ? WkAstReportFields.WK102 : WkAstReportFields.WK116);
BigDecimal ovd05StatPrin = ReportItemHolder.getPlanReportItemHolder(planNo, WkAstReportFields.WK025);
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK127, 0L,
CalcUtil.divide(ovd05StatPrin, denominator)));
// // 加权收益率 = WK128 Σ(每笔借据本金*该笔借据年化收益率)/ 承接池:WK102累计交易贷款本金|放款池:WK116累计新增贷款发生额
// BigDecimal profitAmt = ReportItemHolder.getPlanReportItemHolder(planNo, WkAstReportFields.WK128);
// ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK129, 0L,
// CalcUtil.divide(profitAmt, denominator)));
// 实际闲置率 = WK001账户余额 /(层级累计规模 - WKPlan002计划累计兑付本金金额)
BigDecimal WK001ItemAmt = ReportItemHolder.getPlanReportItemHolder(planNo, WkAstReportFields.WK001);
Money investedBal = RptBuilderUtil.getInvestedBal(planBase, WKPlan002AmtItem.getAmt());
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK002,
0L, CalcUtil.divide(WK001ItemAmt, investedBal.getAmount())));
// 已实现收益额
Money WK130Amt = PlanTypeEnum.PLAN == planType ?
RptBuilderUtil.getPlanProfitAmt(planBase) :
RptBuilderUtil.getSpvProfitAmt(planBase);
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK130, 0L, WK130Amt.getAmount()));
// 历史本金兑付流水
List<PlanAcctTitleLog> acctTitleLogs = acctTitleLogMap.get(ReportTitleGroupEnum.INVESTED_ALL);
// 废弃 ((已实现收益额-保证金)*365 + 保证金)/Σ(各信托层级*存续期)
// 已实现收益率 改为 ((已实现收益额)*365)/Σ((各信托层级-保证金)*对应层级存续期)
ret.add(buildReportItem(planNo, accountDate, WkAstReportFields.WK131, 0L,
CalcUtil.divide(WK130Amt.multiply(planBase.getCalcIntrType().getAnnualDays()).getAmount(),
RptBuilderUtil.getInvestedWeight(accountDate, planBase, acctTitleLogs, true).getAmount())));
return ret;
}
/**
* 资产结构统计
* @param planBase
* @param accountDate
* @return
*/
private List<PlanReportItem> buildAstFormationReport(PlanBase planBase, Date accountDate){
List<PlanReportItem> ret = Lists.newArrayList();
// 剩余结构
List<LoanBakFormationItem> astItems = loanBakDAO.queryAstFormation(accountDate, planBase.getPlanNo());
CollectionUtil.addAll(ret, RptBuilderUtil.convertFormation(
planBase.getPlanNo(), accountDate, astItems, false));
// 产品结构
List<LoanBakFormationItem> prodItems =loanBakDAO.queryProdFormation(accountDate, planBase.getPlanNo());
CollectionUtil.addAll(ret, RptBuilderUtil.convertFormation(
planBase.getPlanNo(), accountDate, prodItems, true));
return ret;
}
/**
* 构建统计项
*
* @param planNo
* @param accountDate
* @param field
* @param cnt
* @param amt
* @return
*/
private PlanReportItem buildReportItem(String planNo, Date accountDate, ReportField field,
Long cnt, BigDecimal amt) {
return RptBuilderUtil.buildReportItem(planNo, accountDate, field, cnt, amt);
}
/**
* 构建累计统计项
*
* @param planNo
* @param accountDate
* @param field
* @param cnt
* @param amt
* @param lastPlanReport
* @return
*/
private PlanReportItem buildReportItem(String planNo, Date accountDate, ReportField field, long cnt,
BigDecimal amt, PlanReport lastPlanReport) {
if (lastPlanReport != null) {
cnt = cnt + RptBuilderUtil.getReportCnt(lastPlanReport, field.getCode());
amt = amt.add(RptBuilderUtil.getReportVal(lastPlanReport, field.getCode()));
}
return buildReportItem(planNo, accountDate, field, cnt, amt);
}
/**
* 放款池对应承接池 统计项合并计算
* @param spv
* @param accountDate
* @param field
* @param reportEntityMap
* @param plans
* @return
*/
private PlanReportItem buildReportItem(String spv, Date accountDate, ReportField field,
Map<ReporterItemCodeKey, Statistics> reportEntityMap,
List<String> plans) {
BigDecimal amt = BigDecimal.ZERO;
Long cnt = 0L;
return buildReportItem(spv, accountDate, field, cnt, amt, reportEntityMap, plans, null);
}
/**
* 放款池对应承接池 统计项合并计算并累计
* @param spv
* @param accountDate
* @param field
* @param reportEntityMap
* @param plans
* @return
*/
private PlanReportItem buildReportItem(String spv, Date accountDate, ReportField field,
long cnt, BigDecimal amt,
Map<ReporterItemCodeKey, Statistics> reportEntityMap,
List<String> plans, PlanReport lastPlanReport) {
//1、需要构建key
//2、get values组成amt和cnt
//3、如果有多个受让计划,则需要循环求和
//4、循环结束后进行add,
//5、构建统计项
if (CollectionUtils.isNotEmpty(plans)) {
for (String plan : plans) {
ReporterItemCodeKey reporterKey = new ReporterItemCodeKey(plan, field.getCode());
Statistics value = reportEntityMap.get(reporterKey);
if (value != null) {
amt = amt.add(value.getAmt());
cnt = cnt + value.getCnt();
}
}
}
if(lastPlanReport != null){
return buildReportItem(spv, accountDate, field, cnt, amt, lastPlanReport);
}else{
return buildReportItem(spv, accountDate, field, cnt, amt);
}
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.report.wk;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.NumberUtil;
import com.abssqr.plat.common.dal.mysql.auto.dao.LoanBakDAO;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PropCntStat;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.PropDisbStat;
import com.abssqr.plat.common.facade.enums.EventCodeEnum;
import com.abssqr.plat.common.facade.enums.IntrTypeEnum;
import com.abssqr.plat.common.facade.enums.ReportTypeEnum;
import com.abssqr.plat.common.facade.enums.TitleTypeEnum;
import com.abssqr.plat.common.facade.model.plan.InvestStructure;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.model.report.PlanReportItem;
import com.abssqr.plat.common.facade.model.report.manRpt.AmtPropCnt;
import com.abssqr.plat.common.facade.model.report.manRpt.AmtPropCntGroup;
import com.abssqr.plat.common.facade.model.report.manRpt.AstRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.CashRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.CommonPropStat;
import com.abssqr.plat.common.facade.model.report.manRpt.CommonPropStatGroup;
import com.abssqr.plat.common.facade.model.report.manRpt.FeeRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.GrantRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.InvestInfoRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.PlanCommonRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.RepoRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.RiskClzRpt;
import com.abssqr.plat.common.facade.model.report.manRpt.TfrRpt;
import com.abssqr.plat.common.facade.model.report.wk.WkAstReportFields;
import com.abssqr.plat.common.facade.model.report.wk.WkManReportFields;
import com.abssqr.plat.common.facade.model.report.wk.WkManagerReport;
import com.abssqr.plat.common.facade.utils.CalcUtil;
import com.abssqr.plat.common.model.domain.plan.PlanAcctTitleLog;
import com.abssqr.plat.common.model.repo.report.PlanReportRepo;
import com.abssqr.plat.core.service.util.RptBuilderUtil;
import com.alibaba.fastjson.JSON;
import com.general.system.common.model.BaseEntity;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.VarChecker;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
*
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.report.wk: WkManagerReportBuilder.java, v 0.1 2019-07-01 01:39 zhenxuan.luo Exp $
*/
@Component
public class WkManagerReportBuilder {
private static List<Integer> AGE_SPLIT = Lists.newArrayList(22, 34, 44, 55);
private static Integer LOC_CNT = 10;
@Autowired
private PlanReportRepo planReportRepo;
@Autowired
private LoanBakDAO loanBakDAO;
/**
* 供报表下载用,合并跨周期的计划报表
*
* @param planBase
* @param startRptDt
* @param endRptDt
* @return
*/
public WkManagerReport getReport(PlanBase planBase, String startRptDt, String endRptDt) {
List<PlanReport> wkManagerReports = planReportRepo.getPlansByDate(planBase.getPlanNo(), startRptDt, endRptDt,
ReportTypeEnum.RPT002);
if (CollectionUtils.isEmpty(wkManagerReports)) {
return null;
}
WkManagerReport combinedReport = new WkManagerReport();
if (wkManagerReports.size() == 1) {
combinedReport = JSON.parseObject(wkManagerReports.get(0).getDetail(), WkManagerReport.class);
} else {
Collections.sort(wkManagerReports, Comparator.comparing(item -> item.getRptDate().desc()));
combinedReport.setPlanNo(planBase.getPlanNo());
combinedReport.setPlanName(planBase.getPlanName());
BigDecimal avgProfitTotal = BigDecimal.ZERO;
BigDecimal dailyAvgPrinTotal = BigDecimal.ZERO;
BigDecimal dailyAvgPrinExtTotal = BigDecimal.ZERO;
for (int i = 0; i < wkManagerReports.size(); i++) {
WkManagerReport wkManagerReport = JSON.parseObject(wkManagerReports.get(i).getDetail(),
WkManagerReport.class);
//日均收益率 日均贷款余额(含核销贷款)日均贷款余额(不含核销贷款)
avgProfitTotal = avgProfitTotal.add(wkManagerReport.getCommonRpt().getAvgProfit());
dailyAvgPrinTotal = dailyAvgPrinTotal.add(wkManagerReport.getCommonRpt().getDailyAvgPrin());
dailyAvgPrinExtTotal = dailyAvgPrinExtTotal.add(wkManagerReport.getCommonRpt().getDailyAvgPrinExt());
//兑付信息
Map<String, InvestInfoRpt> investInfoRptMap = wkManagerReport.getInvestRpts().stream().collect(
Collectors.toMap(InvestInfoRpt::getInvestNo, item -> item));
//资金使用情况 总流入 总流出
combinedReport.getCashRpt().combineAmt(wkManagerReport.getCashRpt());
//转让情况 期间转让金额 期间转让笔数
combinedReport.getTfrRpt().combineAmt(wkManagerReport.getTfrRpt());
//放款情况 期间放款金额 期间放款笔数
combinedReport.getGrantRpt().combineAmt(wkManagerReport.getGrantRpt());
//回收情况 到期还款 提前还款 逾期还款 核销还款
combinedReport.getRepoRpt().combineAmt(wkManagerReport.getRepoRpt());
//费用支出 费用名称 费用编号 科目编号 支出时间 费用金额 增值税金额
combinedReport.getFeeRpts().addAll(wkManagerReport.getFeeRpts());
if (i == 0) {
//报告开始日期
combinedReport.setRptStartDate(wkManagerReport.getRptStartDate());
//兑付信息
combinedReport.setInvestRpts(wkManagerReport.getInvestRpts());
//资金使用情况 期初余额
combinedReport.getCashRpt().copyPre(wkManagerReport.getCashRpt());
//转让情况 期初累计转让金额 期初累计转让笔数
combinedReport.getTfrRpt().copyPre(wkManagerReport.getTfrRpt());
//放款情况 期初累计放款金额 期初累计放款笔数
combinedReport.getGrantRpt().copyPre(wkManagerReport.getGrantRpt());
} else if (i == wkManagerReports.size() - 1) {
//结束时间
combinedReport.setRptEndDate(wkManagerReport.getRptEndDate());
//计划分析 合同不良率 静态不良率 报备不良率 实际不良率
combinedReport.getCommonRpt().copyAft(wkManagerReport.getCommonRpt());
//兑付信息
for (InvestInfoRpt infoRpt : combinedReport.getInvestRpts()) {
InvestInfoRpt lastInfoRpt = investInfoRptMap.get(infoRpt.getInvestNo());
infoRpt.combineAmt(lastInfoRpt);
infoRpt.copyAft(lastInfoRpt);
}
//资金使用情况 期末余额
combinedReport.getCashRpt().copyAft(wkManagerReport.getCashRpt());
//转让情况 期末累计转让金额 期末累计转让笔数
combinedReport.getTfrRpt().copyAft(wkManagerReport.getTfrRpt());
//放款情况 期末累计放款金额 期末累计放款笔数
combinedReport.getGrantRpt().copyAft(wkManagerReport.getGrantRpt());
//资产特征 正常 逾期 核销
combinedReport.setAstRpt(wkManagerReport.getAstRpt());
//五级分类
combinedReport.setRiskClzRpt(wkManagerReport.getRiskClzRpt());
//统计属性集合
combinedReport.setCommonPropStat(wkManagerReport.getCommonPropStat());
//计数属性集合
combinedReport.setPropCnt(wkManagerReport.getPropCnt());
} else {
for (InvestInfoRpt infoRpt : combinedReport.getInvestRpts()) {
InvestInfoRpt curInfoRpt = investInfoRptMap.get(infoRpt.getInvestNo());
infoRpt.combineAmt(curInfoRpt);
}
}
}
long days = DateTimeUtil.calcDayDiff(combinedReport.getRptEndDate(), combinedReport.getRptStartDate());
combinedReport.setRptDays(days);
combinedReport.getCommonRpt().setAvgProfit(CalcUtil.divide(avgProfitTotal, new BigDecimal(days)));
combinedReport.getCommonRpt().setDailyAvgPrin(CalcUtil.divide(dailyAvgPrinTotal, new BigDecimal(days)));
combinedReport.getCommonRpt()
.setDailyAvgPrinExt(CalcUtil.divide(dailyAvgPrinExtTotal, new BigDecimal(days)));
}
combinedReport.sumInvestRpt();
return combinedReport;
}
/**
* 生成管理报表
* @param plan
* @param startDate
* @param endDate
* @param lastReport
* @param planAcctTitles
* @param titleLogs
* @return
*/
public WkManagerReport buildReport(PlanBase plan, Date startDate, Date endDate, WkManagerReport lastReport,
List<PlanAcctTitle> planAcctTitles, List<PlanAcctTitleLog> titleLogs) {
WkManagerReport report = new WkManagerReport();
report.setPlanNo(plan.getPlanNo());
report.setPlanName(plan.getPlanName());
report.setCalcIntrType(plan.getCalcIntrType().getCode());
report.setRptEndDate(endDate);
report.setRptStartDate(startDate);
report.setRptDays(DateTimeUtil.calcDayDiff(report.getRptEndDate(), report.getRptStartDate()) + 1);
// 科目列表
Map<String, InvestItem> acctTitles = buildInvestItem(planAcctTitles);
// 科目流水
Map<AcctLogKey, AcctAmt> titleLogAmtSum = buildAcctAmtSum(titleLogs);
// 获取计划日期时间段报表数据
List<PlanReportItem> dailyReports = planReportRepo.getItemsByDate(plan.getPlanNo(), report.getRptStartDate(),
report.getRptEndDate());
Map<String, PlanReportItem> sumReportItemMap = buildSumReportItem(dailyReports);
Map<String, PlanReportItem> latestReportItemMap = buildReportItem(dailyReports, endDate);
// 计划分析
buildPlanCommonRpt(plan, report, sumReportItemMap, latestReportItemMap);
// 计划兑付分析
buildInvestRpt(plan, report, titleLogAmtSum, acctTitles, lastReport);
// 资金使用情况
buildCashRpt(plan, report, sumReportItemMap, lastReport);
// 转让报表
buildTfrReport(report, sumReportItemMap, lastReport);
// 资产放款情况
buildGrantReport(report, sumReportItemMap, lastReport);
// 资产特征
buildAstRpt(report, latestReportItemMap);
// 资产回收情况
buildRepoRpt(report, sumReportItemMap);
// 五级分类
buildRiskClzRpt(report, latestReportItemMap);
// 费用
buildFeeRpt(report, titleLogs);
// 资产统计特征
buildCommonStat(report, endDate);
// 资产属性统计
buildPropCntStat(report, endDate);
return report;
}
/**
* 计划分析
*
* @param plan
* @param report
* @param sumReportItemMap
* @param latestReportItemMap
*/
private void buildPlanCommonRpt(PlanBase plan, WkManagerReport report,
Map<String, PlanReportItem> sumReportItemMap,
Map<String, PlanReportItem> latestReportItemMap) {
BigDecimal rptDays = new BigDecimal(report.getRptDays());
PlanCommonRpt planCommonRpt = new PlanCommonRpt();
// 总收益=最新应还利息+最新应还罚息+期间累计已还利息+期间累计已还罚息
BigDecimal profit = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK018.getCode())
.add(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK019.getCode()))
.add(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK040.getCode()))
.add(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK041.getCode()));
BigDecimal profitRate = CalcUtil.divide(profit, RptBuilderUtil.getInvestedAmt(plan).getAmount());
planCommonRpt.setAvgProfit(CalcUtil.divide(profitRate, rptDays));
/**
当前月损失率=(近30天新增逾期90天以上的借据的未还剩余本金)/ 近30天平均剩余资产规模(包含核销);
(1-当前年化损失率) 当前年化损失率=当前月损失率*12
*/
BigDecimal lossYearRate = NumberUtil.sub(1, NumberUtil.mul(CalcUtil.divide(
RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK025.getCode()),
RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK017.getCode())), 12));
// (1-闲置率)闲置率=从成立到当前,每日闲置率的平均值
BigDecimal idleRate = NumberUtil.sub(1, CalcUtil.divide(
RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK002.getCode()), rptDays));
// 资产加权利率 累计维度,取准实时值 取最后一日的资产加权利率
BigDecimal astRate = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK129.getCode());
// (1-招联金融服务费率)招联金融服务费费率:在项目录入时输入
BigDecimal finSerFeeRate = NumberUtil.sub(1, plan.getFinSerFeeRate());
/**
* 信托实际收益率(税前) =(1-闲置率)*(1-当前年化损失率)*资产加权利率*(1-招联金融服务费率)+(1-当前年化损失率)
*/
planCommonRpt.setProfitRate(NumberUtil.mul(idleRate, lossYearRate, astRate, finSerFeeRate).add(lossYearRate));
// 报告期内,=sum(每日贷款余额(包含核销贷款))/统计天数
BigDecimal prinSum = RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK017.getCode());
planCommonRpt.setDailyAvgPrin(CalcUtil.divide(prinSum, rptDays));
// 报告期内,=sum(每日贷款余额(不包含核销贷款))/统计天数
BigDecimal prinExtSum = prinSum.subtract(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK015.getCode()));
planCommonRpt.setDailyAvgPrinExt(CalcUtil.divide(prinExtSum, rptDays));
// 91天以上逾期资产(含“181天以上核销”)
BigDecimal oduePrin = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK025.getCode());
// 91天以上逾期资产(不含“181天以上核销”)
BigDecimal odueExtPrin = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WKExt001.getCode());
// 贷款余额
BigDecimal totalPrin = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK017.getCode());
// 累计放款金额
BigDecimal totalAcctGrant = RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK027.getCode());
// 91天以上逾期资产(不含“181天以上核销”)/累计放款金额
planCommonRpt.setNplCont(CalcUtil.divide(odueExtPrin, totalAcctGrant));
planCommonRpt.setNplStatic(CalcUtil.divide(oduePrin, totalAcctGrant));
planCommonRpt.setNplReport(CalcUtil.divide(odueExtPrin, totalPrin));
planCommonRpt.setNplReal(CalcUtil.divide(oduePrin, totalPrin));
report.setCommonRpt(planCommonRpt);
}
/**
* 投资结构和计划兑付信息
* @param plan
* @param report
* @param titleLogAmtSum
* @param acctTitles
* @param lastReport
*/
private void buildInvestRpt(PlanBase plan, WkManagerReport report, Map<AcctLogKey, AcctAmt> titleLogAmtSum,
Map<String, InvestItem> acctTitles,
WkManagerReport lastReport) {
List<InvestInfoRpt> infoRpts = Lists.newArrayList();
Map<String, InvestInfoRpt> lastInfoRptMap = Maps.newHashMap();
if (null != lastReport) {
lastInfoRptMap = lastReport.getInvestRpts().stream().collect(
Collectors.toMap(InvestInfoRpt::getInvestNo, item -> item));
}
// 根据投资结构 计算分配兑付情况
for (InvestStructure investStrut : plan.getInvestStructureList()) {
// 上个周期的月报,可能为null,需要判断null处理
InvestInfoRpt lastInfoRpt = lastInfoRptMap.get(investStrut.getLayerNo());
// 对应该投资结构层级的各个科目,不能为null,为null说明科目未初始化,为系统异常
InvestItem investItem = acctTitles.get(investStrut.getLayerNo());
VarChecker.checkNotNull(investItem, "投资结构[{0}]的科目为初始化", investStrut);
InvestInfoRpt infoRpt = new InvestInfoRpt();
infoRpt.setInvestNo(investStrut.getLayerNo());
infoRpt.setInvestName(investStrut.getLayerName());
infoRpt.setInvestCost(investStrut.getLayerAmt().getAmount());
// 考虑无票面利率的情况
if (investStrut.getIntrType() == IntrTypeEnum.NOTICKET) {
infoRpt.setRate(null);
} else {
infoRpt.setRate(investStrut.getLayerIntr());
}
// 期初本金:上个报表的期末为这个报表的期初,默认为投入资本
infoRpt.setPrePrin((null == lastInfoRpt) ? investStrut.getLayerAmt().getAmount() : lastInfoRpt.getAftPrin());
// 期初收益:上个报表的期末为这个报表的期初,默认为0
infoRpt.setPreProfit((null == lastInfoRpt) ? BigDecimal.ZERO : lastInfoRpt.getAftProfit());
// 从科目流水中,汇总发生额,汇总结果可能为null(该月未发生相关交易),若为null,则作0处理
AcctAmt prinAcctAmt = titleLogAmtSum.get(new AcctLogKey(investItem.investTitle, EventCodeEnum.TITLE_ALLOC));
AcctAmt intrAllocAcctAmt = titleLogAmtSum.get(new AcctLogKey(investItem.intrTitle, EventCodeEnum.TITLE_ALLOC));
AcctAmt intrSettleAcctAmt = titleLogAmtSum.get(new AcctLogKey(investItem.intrTitle, EventCodeEnum.TITLE_SETTLE));
infoRpt.setAllocPrinAmt((prinAcctAmt == null) ? BigDecimal.ZERO : prinAcctAmt.amt);
infoRpt.setAllocProfitAmt((intrAllocAcctAmt == null) ? BigDecimal.ZERO : intrAllocAcctAmt.amt);
infoRpt.setAllocVtaxAmt((intrAllocAcctAmt == null) ? BigDecimal.ZERO : intrAllocAcctAmt.vtaxAmt);
infoRpt.setAddProfitAmt((intrSettleAcctAmt == null) ? BigDecimal.ZERO : intrSettleAcctAmt.amt);
// 期初 +/- 期间发生额 = 期末,不用考虑为null的情况
infoRpt.setAftPrin(infoRpt.getPrePrin().subtract(infoRpt.getAllocPrinAmt()));
infoRpt.setAftProfit(
infoRpt.getPreProfit().add(infoRpt.getAddProfitAmt()).subtract(infoRpt.getAllocProfitAmt()));
// 汇总本金,收益的累计分配,若上日报表为null,则直接采用当期发生额,否则累加上日报表的汇总金额
infoRpt.setTotAllocPrin((lastInfoRpt == null) ?
infoRpt.getAllocPrinAmt() :
infoRpt.getAllocPrinAmt().add(lastInfoRpt.getTotAllocPrin()));
infoRpt.setTotAllocProfit((lastInfoRpt == null) ?
infoRpt.getAllocProfitAmt() :
infoRpt.getAllocProfitAmt().add(lastInfoRpt.getTotAllocProfit()));
infoRpt.setTotAllocVtax((lastInfoRpt == null) ?
infoRpt.getAllocVtaxAmt() :
infoRpt.getAllocVtaxAmt().add(lastInfoRpt.getTotAllocVtax()));
infoRpts.add(infoRpt);
}
report.setInvestRpts(infoRpts);
}
/**
* 资金使用情况
* @param plan
* @param report
* @param sumReportItemMap
* @param lastReport
*/
private void buildCashRpt(PlanBase plan, WkManagerReport report, Map<String, PlanReportItem> sumReportItemMap,
WkManagerReport lastReport) {
CashRpt cashRpt = new CashRpt();
cashRpt.setPreBal((lastReport == null) ?
RptBuilderUtil.getInvestedAmt(plan).getAmount() : lastReport.getCashRpt().getAftBal());
cashRpt.setInAmt(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK009.getCode()));
cashRpt.setOutAmt(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK008.getCode()));
cashRpt.setAftBal(cashRpt.getPreBal().add(cashRpt.getInAmt()).subtract(cashRpt.getOutAmt()));
report.setCashRpt(cashRpt);
}
/**
* 资产转让情况
* @param report
* @param sumReportItemMap
* @param lastReport
*/
private void buildTfrReport(WkManagerReport report, Map<String, PlanReportItem> sumReportItemMap,
WkManagerReport lastReport) {
TfrRpt tfrRpt = new TfrRpt();
tfrRpt.setPreAccGrant((lastReport == null) ? BigDecimal.ZERO : lastReport.getTfrRpt().getAftAccGrant());
tfrRpt.setPreAccGrantCnt((lastReport == null) ? BigDecimal.ZERO : lastReport.getTfrRpt().getAftAccGrantCnt());
tfrRpt.setGrantAmt(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK028.getCode()));
tfrRpt.setGrantCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WK028.getCode())));
tfrRpt.setAftAccGrant(tfrRpt.getPreAccGrant().add(tfrRpt.getGrantAmt()));
tfrRpt.setAftAccGrantCnt(tfrRpt.getPreAccGrantCnt().add(tfrRpt.getGrantCnt()));
report.setTfrRpt(tfrRpt);
}
/**
* 资产放款情况
* @param report
* @param sumReportItemMap
* @param lastReport
*/
private void buildGrantReport(WkManagerReport report, Map<String, PlanReportItem> sumReportItemMap,
WkManagerReport lastReport) {
GrantRpt grantRpt = new GrantRpt();
grantRpt.setPreAccGrant((lastReport == null) ? BigDecimal.ZERO : lastReport.getGrantRpt().getAftAccGrant());
grantRpt.setPreAccGrantCnt((lastReport == null) ? BigDecimal.ZERO : lastReport.getGrantRpt().getAftAccGrantCnt());
grantRpt.setGrantAmt(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK115.getCode()));
grantRpt.setGrantCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WK115.getCode())));
grantRpt.setAftAccGrant(grantRpt.getPreAccGrant().add(grantRpt.getGrantAmt()));
grantRpt.setAftAccGrantCnt(grantRpt.getPreAccGrantCnt().add(grantRpt.getGrantCnt()));
report.setGrantRpt(grantRpt);
}
/**
* 资产特征
* @param report
* @param latestReportItemMap
*/
private void buildAstRpt(WkManagerReport report, Map<String, PlanReportItem> latestReportItemMap) {
AstRpt astRpt = new AstRpt();
AmtPropCnt normal = new AmtPropCnt();
AmtPropCnt overdue = new AmtPropCnt();
AmtPropCnt writeOff = new AmtPropCnt();
normal.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK010.getCode())));
normal.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK010.getCode()));
normal.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK011.getCode()));
normal.calTotal();
overdue.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK012.getCode())));
overdue.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK012.getCode()));
overdue.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK013.getCode()));
overdue.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK014.getCode()));
overdue.calTotal();
writeOff.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK015.getCode())));
writeOff.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK015.getCode()));
writeOff.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WKExt002.getCode()));
writeOff.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WKExt003.getCode()));
writeOff.calTotal();
astRpt.setNormal(normal);
astRpt.setOverdue(overdue);
astRpt.setWriteoff(writeOff);
report.setAstRpt(astRpt);
}
/**
* 资产回收情况
* @param report
* @param sumReportItemMap
*/
private void buildRepoRpt(WkManagerReport report, Map<String, PlanReportItem> sumReportItemMap) {
RepoRpt repoRpt = new RepoRpt();
AmtPropCnt dueRepo = new AmtPropCnt();
AmtPropCnt preRepo = new AmtPropCnt();
AmtPropCnt ovdRepo = new AmtPropCnt();
AmtPropCnt wrtRepo = new AmtPropCnt();
dueRepo.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WKExt004.getCode())));
dueRepo.setPrin(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WKExt004.getCode()));
dueRepo.setIntr(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WKExt005.getCode()));
dueRepo.calTotal();
preRepo.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WK042.getCode())));
preRepo.setPrin(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK042.getCode()));
preRepo.setIntr(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK043.getCode()));
preRepo.setOtherFee(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK140.getCode()));
preRepo.calTotal();
ovdRepo.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WK044.getCode())));
ovdRepo.setPrin(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK044.getCode()));
ovdRepo.setIntr(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK045.getCode()));
ovdRepo.setPenl(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK046.getCode()));
ovdRepo.calTotal();
wrtRepo.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(sumReportItemMap, WkAstReportFields.WK047.getCode())));
wrtRepo.setPrin(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WK047.getCode()));
wrtRepo.setIntr(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WKExt006.getCode()));
wrtRepo.setPenl(RptBuilderUtil.getReportVal(sumReportItemMap, WkAstReportFields.WKExt007.getCode()));
wrtRepo.calTotal();
repoRpt.setDueRepo(dueRepo);
repoRpt.setPreRepo(preRepo);
repoRpt.setOvdRepo(ovdRepo);
repoRpt.setWrtRepo(wrtRepo);
report.setRepoRpt(repoRpt);
}
/**
* 五级分类统计
*
* @param report
* @param latestReportItemMap
*/
private void buildRiskClzRpt(WkManagerReport report, Map<String, PlanReportItem> latestReportItemMap) {
RiskClzRpt riskClzRpt = new RiskClzRpt();
AmtPropCnt normal = new AmtPropCnt();
AmtPropCnt atten = new AmtPropCnt();
AmtPropCnt second = new AmtPropCnt();
AmtPropCnt suspic = new AmtPropCnt();
AmtPropCnt loss = new AmtPropCnt();
AmtPropCnt total = new AmtPropCnt();
normal.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK911.getCode())));
normal.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK911.getCode()));
normal.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK912.getCode()));
second.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK913.getCode()));
normal.calTotal();
atten.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK921.getCode())));
atten.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK921.getCode()));
atten.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK922.getCode()));
second.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK923.getCode()));
atten.calTotal();
second.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK931.getCode())));
second.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK931.getCode()));
second.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK932.getCode()));
second.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK933.getCode()));
second.calTotal();
suspic.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK941.getCode())));
suspic.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK941.getCode()));
suspic.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK942.getCode()));
suspic.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK943.getCode()));
suspic.calTotal();
loss.setCnt(new BigDecimal(RptBuilderUtil.getReportCnt(latestReportItemMap, WkAstReportFields.WK951.getCode())));
loss.setPrin(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK951.getCode()));
loss.setIntr(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK952.getCode()));
loss.setPenl(RptBuilderUtil.getReportVal(latestReportItemMap, WkAstReportFields.WK953.getCode()));
loss.calTotal();
total.addAllAmt(normal).addAllAmt(atten).addAllAmt(second).addAllAmt(suspic).addAllAmt(loss);
normal.calcRatio(total);
atten.calcRatio(total);
second.calcRatio(total);
suspic.calcRatio(total);
loss.calcRatio(total);
riskClzRpt.setNormal(normal);
riskClzRpt.setAtten(atten);
riskClzRpt.setSecond(second);
riskClzRpt.setSuspic(suspic);
riskClzRpt.setLoss(loss);
riskClzRpt.setTotal(total);
report.setRiskClzRpt(riskClzRpt);
}
/**
* 费用报表
*
* @param report
* @param acctTitleLogs
*/
private void buildFeeRpt(WkManagerReport report, List<PlanAcctTitleLog> acctTitleLogs) {
List<FeeRpt> feeRpts = Lists.newArrayList();
Collections.sort(acctTitleLogs, Comparator.comparing(PlanAcctTitleLog::getAccountDate));
for (PlanAcctTitleLog planAcctTitleLog : acctTitleLogs) {
if (planAcctTitleLog.getTitleType() != TitleTypeEnum.FEE) {
continue;
}
if (planAcctTitleLog.getEventCode() != EventCodeEnum.TITLE_ALLOC) {
continue;
}
FeeRpt feeRpt = new FeeRpt();
feeRpt.setFeeName(planAcctTitleLog.getTitleName());
feeRpt.setFeeNo(planAcctTitleLog.getRefNo());
feeRpt.setTitleNo(planAcctTitleLog.getTitleNo());
feeRpt.setDt(DateTimeUtil.formatY_M_D(planAcctTitleLog.getAccountDate()));
feeRpt.setFeeAmt(planAcctTitleLog.getAcctAmt().getAmount());
feeRpt.setVtaxAmt(planAcctTitleLog.getvTaxAmt().getAmount());
feeRpt.setMemo("");
feeRpts.add(feeRpt);
}
report.setFeeRpts(feeRpts);
}
private Map<AcctLogKey, AcctAmt> buildAcctAmtSum(List<PlanAcctTitleLog> planAcctTitleLogs) {
Map<AcctLogKey, AcctAmt> ret = Maps.newHashMap();
for (PlanAcctTitleLog planAcctTitleLog : planAcctTitleLogs) {
AcctLogKey key = new AcctLogKey(planAcctTitleLog.getTitleNo(), planAcctTitleLog.getEventCode());
AcctAmt amt = ret.get(key);
if (null == amt) {
amt = new AcctAmt();
ret.put(key, amt);
}
amt.amt = amt.amt.add(planAcctTitleLog.getAcctAmt().getAmount());
amt.vtaxAmt = amt.vtaxAmt.add(planAcctTitleLog.getvTaxAmt().getAmount());
}
return ret;
}
private Map<String, PlanReportItem> buildSumReportItem(List<PlanReportItem> dailyReports) {
return buildReportItem(dailyReports, null);
}
private Map<String, PlanReportItem> buildReportItem(List<PlanReportItem> dailyReports, Date accountDate) {
Map<String, PlanReportItem> reportItemMap = Maps.newHashMap();
for (PlanReportItem item : dailyReports) {
if (accountDate != null && DateTimeUtil.calcDayDiff(accountDate, item.getAccountDate()) != 0) {
continue;
}
PlanReportItem sumItem = reportItemMap.get(item.getRptItemCode());
if (null == sumItem) {
sumItem = new PlanReportItem();
sumItem.setRptItemCode(sumItem.getRptItemCode());
sumItem.setRptItemName(sumItem.getRptItemName());
sumItem.setAstCnt(item.getAstCnt());
sumItem.setAmt(item.getAmt());
reportItemMap.put(item.getRptItemCode(), sumItem);
}else{
sumItem.setAstCnt(sumItem.getAstCnt() + item.getAstCnt());
sumItem.setAmt(sumItem.getAmt().add(item.getAmt()));
}
}
return reportItemMap;
}
private Map<String, InvestItem> buildInvestItem(List<PlanAcctTitle> planAcctTitles) {
Map<String, InvestItem> ret = Maps.newHashMap();
for (PlanAcctTitle acctTitle : planAcctTitles) {
InvestItem item = ret.get(acctTitle.getRefNo());
if (null == item) {
item = new InvestItem();
ret.put(acctTitle.getRefNo(), item);
}
switch (acctTitle.getTitleType()) {
case INVEST_PROFIT:
item.intrTitle = acctTitle.getTitleNo();
break;
case PRIOR_INVESTED:
case SECND_INVESTED:
case INVESTED:
item.investTitle = acctTitle.getTitleNo();
break;
case FEE:
item.feeTitle = acctTitle.getTitleNo();
break;
}
}
return ret;
}
/**
* 资产特征分布
* @param report
* @param accountDate
*/
private void buildCommonStat(WkManagerReport report, Date accountDate) {
CommonPropStatGroup commonPropStatGroup = new CommonPropStatGroup();
report.setCommonPropStat(commonPropStatGroup);
// 资产合同金额特征
CommonPropStat wkm001 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM001.getCode(), wkm001);
//资产余额特征
CommonPropStat wkm002 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM002.getCode(), wkm002);
// 资产利率特征
CommonPropStat wkm003 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM003.getCode(), wkm003);
// 合同期限特征
CommonPropStat wkm004 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM004.getCode(), wkm004);
// 剩余期限特征
CommonPropStat wkm005 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM005.getCode(), wkm005);
// 账龄特征
CommonPropStat wkm006 = new CommonPropStat();
commonPropStatGroup.getCommonPropStat().put(WkManReportFields.WKM006.getCode(), wkm006);
PropDisbStat propDisbStat = loanBakDAO.statDisb(accountDate, report.getPlanNo());
if (propDisbStat != null) {
wkm001.setMin(getStatAmt(propDisbStat.getMinContAmt()));
wkm001.setMax(getStatAmt(propDisbStat.getMaxContAmt()));
wkm001.setAvg(getStatAmt(propDisbStat.getAvgContAmt()));
wkm002.setMin(getStatAmt(propDisbStat.getMinBal()));
wkm002.setMax(getStatAmt(propDisbStat.getMaxBal()));
wkm002.setAvg(getStatAmt(propDisbStat.getAvgBal()));
wkm003.setMin(propDisbStat.getMinRate());
wkm003.setMax(propDisbStat.getMaxRate());
wkm003.setAvg(propDisbStat.getAvgRate());
wkm003.setwAvg(propDisbStat.getWavgRate());
wkm004.setMin(new BigDecimal(propDisbStat.getMinContPeriod()));
wkm004.setMax(new BigDecimal(propDisbStat.getMaxContPeriod()));
wkm004.setAvg(propDisbStat.getAvgContPeriod());
wkm004.setwAvg(propDisbStat.getWavgContPeriod());
wkm005.setMin(new BigDecimal(propDisbStat.getMinRemPeriod()));
wkm005.setMax(new BigDecimal(propDisbStat.getMaxRemPeriod()));
wkm005.setAvg(propDisbStat.getAvgRemPeriod());
wkm005.setwAvg(propDisbStat.getWavgRemPeriod());
wkm006.setMin(new BigDecimal(propDisbStat.getMinAcctPeriod()));
wkm006.setMax(new BigDecimal(propDisbStat.getMaxAcctPeriod()));
wkm006.setAvg(propDisbStat.getAvgAcctPeriod());
wkm006.setwAvg(propDisbStat.getWavgAcctPeriod());
}
}
private void buildPropCntStat(WkManagerReport report, Date accountDate) {
AmtPropCntGroup amtPropCntGroup = new AmtPropCntGroup();
report.setPropCnt(amtPropCntGroup);
List<AmtPropCnt> locAmtProp = Lists.newArrayList();
List<AmtPropCnt> ageAmtProp = Lists.newArrayList();
List<AmtPropCnt> genAmtProp = Lists.newArrayList();
/**
ReportField WKM007 = new ReportField("WKM007", "性别");
ReportField WKM008 = new ReportField("WKM008", "年龄");
ReportField WKM009 = new ReportField("WKM009", "地区");
*/
amtPropCntGroup.getPropCntMap().put(WkManReportFields.WKM007.getCode(), genAmtProp);
amtPropCntGroup.getPropCntMap().put(WkManReportFields.WKM008.getCode(), ageAmtProp);
amtPropCntGroup.getPropCntMap().put(WkManReportFields.WKM009.getCode(), locAmtProp);
List<PropCntStat> ageStat = loanBakDAO.statAge(accountDate, report.getPlanNo());
List<PropCntStat> locStat = loanBakDAO.statLocation(accountDate, report.getPlanNo());
List<PropCntStat> genStat = loanBakDAO.statGender(accountDate, report.getPlanNo());
// 性别
AmtPropCnt maleProp = new AmtPropCnt();
AmtPropCnt femaleProp = new AmtPropCnt();
genAmtProp.add(maleProp);
genAmtProp.add(femaleProp);
Map<String, PropCntStat> genStatMap = genStat.stream()
.collect(Collectors.toMap(PropCntStat::getPropVal, item -> item));
PropCntStat maleStat = genStatMap.get("male");
PropCntStat femaleStat = genStatMap.get("female");
maleProp.setCnt(getPropCntStatCnt(maleStat));
maleProp.setPrin(getPropCntStatAmt(maleStat));
femaleProp.setCnt(getPropCntStatCnt(femaleStat));
femaleProp.setPrin(getPropCntStatAmt(femaleStat));
// 年龄
for (Integer age : AGE_SPLIT) {
ageAmtProp.add(new AmtPropCnt());
}
ageAmtProp.add(new AmtPropCnt());
for (PropCntStat ageCntStat : ageStat) {
int age = Integer.parseInt(ageCntStat.getPropVal());
int i = 0;
AmtPropCnt curProp = null;
for (; i < AGE_SPLIT.size(); i++) {
if (age <= AGE_SPLIT.get(i)) {
curProp = ageAmtProp.get(i);
break;
}
}
if (i == AGE_SPLIT.size()) {
curProp = ageAmtProp.get(i);
}
curProp.setCnt(curProp.getCnt().add(getPropCntStatCnt(ageCntStat)));
curProp.setPrin(curProp.getPrin().add(getPropCntStatAmt(ageCntStat)));
}
// 地区
for (int i = 0; i < LOC_CNT; i++) {
AmtPropCnt locProp = new AmtPropCnt();
locAmtProp.add(locProp);
if (i < locStat.size()) {
PropCntStat propStat = locStat.get(i);
String provinceCode = propStat.getPropVal();
String province = IdcardUtil.getProvinceByIdCard(provinceCode + "1234567890123456");
if (StringUtils.isBlank(province)) {
province = propStat.getPropVal();
}
locProp.setPropVal(province);
locProp.setCnt(getPropCntStatCnt(propStat));
locProp.setPrin(getPropCntStatAmt(propStat));
}
}
}
private BigDecimal getStatAmt(Money money) {
if (null == money) {
return BigDecimal.ZERO;
} else {
return money.getAmount();
}
}
private BigDecimal getPropCntStatCnt(PropCntStat propCntStat) {
if (null == propCntStat) {
return BigDecimal.ZERO;
} else {
return new BigDecimal(propCntStat.getCnt());
}
}
private BigDecimal getPropCntStatAmt(PropCntStat propCntStat) {
if (null == propCntStat) {
return BigDecimal.ZERO;
} else {
return propCntStat.getAmt().getAmount();
}
}
private class InvestItem {
String investTitle;
String intrTitle;
String feeTitle;
}
private class AcctAmt {
/**
*
*/
BigDecimal amt = BigDecimal.ZERO;
/**
*
*/
BigDecimal vtaxAmt = BigDecimal.ZERO;
}
private class AcctLogKey extends BaseEntity {
/**
* 科目编号
*/
String titleNo;
/**
* 事件类型
*/
EventCodeEnum eventCode;
public AcctLogKey(String titleNo, EventCodeEnum eventCode) {
this.titleNo = titleNo;
this.eventCode = eventCode;
}
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.scheduler.job;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import org.quartz.Job;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.endpoint.event.RefreshEvent;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.stereotype.Component;
/**
* 每五分钟刷新配置
* @author bangis.wangdf
* @version com.abssqr.plat.biz.shared.scheduler.job: ConfigRefreshJob.java, v 0.1 2019-08-29 18:06 bangis.wangdf Exp $
*/
@Component
@PersistJobDataAfterExecution
public class ConfigRefreshJob extends BaseQuartzJob implements Job {
@Autowired
private ConfigurableApplicationContext context;
@Override
public void doExecute() {
//context.publishEvent(new RefreshEvent("refresh","refresh","刷新配置"));
}
@Override
protected String getCronExpr() {
return "0 0/5 * * * ?";
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.scheduler.job.ast;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import com.abssqr.plat.common.dal.mysql.auto.dataobject.AstPackDO;
import com.abssqr.plat.common.facade.enums.AccountAttributeEnum;
import com.abssqr.plat.common.facade.enums.AccountTypeEnum;
import com.abssqr.plat.common.facade.enums.AstPackStatusEnum;
import com.abssqr.plat.common.facade.enums.AstPackTradeTypeEnum;
import com.abssqr.plat.common.facade.enums.CommonTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.PlanCapitalTransTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.facade.enums.TransCodeEnum;
import com.abssqr.plat.common.facade.model.account.Account;
import com.abssqr.plat.common.model.convertor.PacKConvert;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.domain.task.TrCtrTask;
import com.abssqr.plat.common.model.repo.ast.PackRepository;
import com.abssqr.plat.common.model.repo.clearing.PlanClearingLogRepo;
import com.abssqr.plat.common.model.repo.clearing.PlanClearingOrderRepo;
import com.abssqr.plat.common.model.repo.plan.PlanCapitalOrderRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.common.model.repo.tr.TrCtrTaskRepo;
import com.abssqr.plat.common.util.base.autoconfig.AbsConfig;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.acct.AcctManager;
import com.abssqr.plat.core.service.ast.AstPackManager;
import com.abssqr.plat.core.service.util.CommonTaskUtil;
import com.general.system.common.model.Money;
import com.general.system.common.util.LogUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
/**
* 自动回购
*
* @author bangis.wangdf
* @version com.abssqr.plat.biz.shared.scheduler.job.ast: AutoBackJob.java, v 0.1 2020-03-03 01:49 bangis.wangdf Exp $
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class AutoBackJob extends BaseQuartzJob {
private final static Logger LOGGER = LoggerFactory.getLogger(AutoBackJob.class);
@Autowired
PackRepository packRepository;
@Autowired
CommonTaskRepository commonTaskRepository;
@Autowired
TrCtrTaskRepo trCtrTaskRepo;
@Autowired
AstPackManager astPackManager;
@Autowired
PlanClearingLogRepo planClearingLogRepo;
@Autowired
PlanClearingOrderRepo planClearingOrderRepo;
@Autowired
PlanCapitalOrderRepo planCapitalOrderRepo;
@Autowired
AcctManager acctManager;
@Autowired
AbsConfig absConfig;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
@Override
protected String getCronExpr() {
return "0 1/5 * * * ?";
}
public static final String ORG_CODE = "WKXT";
public static final Money reserveAmt = new Money("2000000");
@Override
protected void doExecute() {
// 获取转让会计日
Date curDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
List<CommonTask> commonTasks = commonTaskRepository.selectUnifinishTaskByType(
CommonTaskTypeEnum.BUY_BACK_MATCH);
//没有未完成的回购任务
if (CollectionUtils.isNotEmpty(commonTasks)) {
LogUtil.info(LOGGER, "AutoBackJob 不执行,存在待回购的 commonTask");
return;
}
// 获取所有回购pack
List<AstPackDO> astPackDOS = packRepository.selectPackByStatus(curDate,
AstPackStatusEnum.WAIT,
AstPackTradeTypeEnum.BUY_BACK_BIZ);
if (CollectionUtils.isEmpty(astPackDOS)) {
LogUtil.info(LOGGER, "AutoBackJob 不执行,没有待回购包");
return;
}
List<TrCtrTask> activeBkCtrTasks = trCtrTaskRepo
.getByManagerOrgCode(ORG_CODE, curDate, TaskStatusEnum.INIT, AstPackTradeTypeEnum.BUY_BACK_BIZ);
if (CollectionUtils.isNotEmpty(activeBkCtrTasks)) {
LogUtil.info(LOGGER, "AutoBackJob 不执行,存在待回购的TrTask");
return;
}
//清算,结算,支付
Long clearingLogCnt = planClearingLogRepo.cntInitClearingLog(TransCodeEnum.BUY_BACK_OUT);
Long clearingOrderCnt = planClearingOrderRepo.cntInitClearingOrder(TransCodeEnum.BUY_BACK_OUT);
Long activeCnt = planCapitalOrderRepo.getActiveCntByType(PlanCapitalTransTypeEnum.NT_BUY_BACK);
if (clearingLogCnt + clearingOrderCnt + activeCnt > 0) {
LogUtil.info(LOGGER, "AutoBackJob 不执行,支付未完成");
return;
}
//判断账户余额是否满足
AstPackDO astPackDO = astPackDOS.get(0);
Money backAvalAmt = Money.createWithCent(astPackDO.getAvalAmt());
// 1、获取计划对应资金账户 平台虚拟户
List<Account> accounts = acctManager.getAcctByPlanNoAndType(astPackDO.getPlanNo(), AccountTypeEnum.PLAT_VIRTUAL,
true);
Money bankBal = new Money();
if (CollectionUtils.isNotEmpty(accounts)) {
for (Account account : accounts) {
if (account.getActAttr() == AccountAttributeEnum.PAY) {
bankBal = account.getBankBal();
}
}
}
//银行余额 - 回购金额 - 预留金额 > 0
if (bankBal.subtract(backAvalAmt).subtract(reserveAmt).isGreaterThanZero()) {
//开启本次回购
CommonTask commonTask = CommonTaskUtil.buildCommonTaskWithContext(astPackDO.getPackCode(),
CommonTaskTypeEnum.BUY_BACK_MATCH, astPackDO.getPackCode());
commonTaskRepository.create(commonTask);
packRepository.updatePackStatus(Lists.newArrayList(PacKConvert.do2Domain(astPackDO)), AstPackStatusEnum.INIT, AstPackStatusEnum.WAIT);
}else {
LogUtil.info(LOGGER,"AutoBackJob 不执行,账户余额-[{0}]小于 筛选包金额[{1}] + 预留金额[{2}]",bankBal,backAvalAmt,reserveAmt);
}
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2018 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.scheduler.job.ast;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import com.abssqr.plat.common.dal.mysql.auto.dao.PlanTranScreenRelDAO;
import com.abssqr.plat.common.facade.enums.SyncTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.model.domain.plan.PlanAcctTitleTransDetail;
import com.abssqr.plat.common.model.domain.task.ctr.AstSyncTaskCtr;
import com.abssqr.plat.common.model.domain.task.ctr.AstSyncTaskCtrLog;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.common.model.repo.loanTrans.LoanAstProfitLogRepo;
import com.abssqr.plat.common.model.repo.loanTrans.LoanInstalLogRepository;
import com.abssqr.plat.common.model.repo.plan.PlanAcctTitleRepo;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.util.base.Day;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.host.HostManager;
import com.abssqr.plat.core.service.plan.PlanAcctTitleManager;
import com.abssqr.plat.core.service.plan.PlanSettleManager;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.StringUtil;
import com.general.system.common.util.VarChecker;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* 招联金融服务费
*
* @author bangis.wangdf
* @version $Id: PlanAstStatJob.java, v 0.1 2018-01-06 上午12:39 Exp $
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class ZLFinSerFeeJob extends BaseQuartzJob {
@Autowired
HostManager hostManager;
@Autowired
AstSyncTaskCtrRepo astSyncTaskCtrRepo;
@Autowired
LoanInstalLogRepository loanInstalLogRepository;
@Autowired
LoanAstProfitLogRepo loanAstProfitLogRepo;
@Autowired
TransactionTemplate transactionTemplate;
@Autowired
PlanTranScreenRelDAO planTranScreenRelDAO;
@Autowired
PlanAcctTitleRepo planAcctTitleRepo;
@Autowired
PlanAcctTitleManager planAcctTitleManager;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
//20191128 前所有金融服务费 查询instalLog,之后instalLog仅获取11条无法支持数据的金融服务费分摊
private static Date FEE_OFFSET_DAY = DateTimeUtil.parseFromYMD("20191127");
/**
* 每天 0 1/5 * * * ?
*/
@Value("${sync.quartz.ast.ser.fee}")
private String cron;
@Value("${wkabs.astsync.zhaolian:1009}")
private String zlOrgCode;
@Override
protected String getCronExpr() {
return cron;
}
@Override
public void doExecute() {
AstSyncTaskCtr taskCtr = astSyncTaskCtrRepo.getAstSyncTaskCtr(zlOrgCode);
VarChecker.checkNotNull(taskCtr, "没有匹配的同步控制任务={0}", zlOrgCode);
OrgCodeEnum orgCodeEnum = OrgCodeEnum.getByCode(taskCtr.getOrgCode());
VarChecker.checkNotNull(orgCodeEnum, "不匹配的机构编码={0}", taskCtr.getOrgCode());
// 获取当前机构会计日
Day orgDate = orgAcctDayComponent.getAstAcctDay(orgCodeEnum);
// 判断对机构会计日的模型同步是否完成
AstSyncTaskCtrLog astModTask = astSyncTaskCtrRepo.getTaskLogByOrgDate(
orgDate.getStandardDate(), SyncTaskTypeEnum.AST_MOD, taskCtr.getOrgCode());
if (astModTask != null && astModTask.getStatus() == TaskStatusEnum.SUCCESS) {
if (astSyncTaskCtrRepo.checkCanRun(taskCtr.getOrgCode(),
taskCtr.getTaskCode(), SyncTaskTypeEnum.AST_SER_FEE, orgDate.getStandardDate())) {
// Date accountDate = SystemDayUtil.getDay().getYesterday().getStandardDate();
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算start", orgDate.getDateString());
Set<String> spvPlanNos = taskCtr.getExtData().getSpvPlanNos();
if (CollectionUtils.isNotEmpty(spvPlanNos)) {
List<PlanAcctTitleTransDetail> acctTitleTransDetails = Lists.newArrayList();
List<String> allPlanNos = Lists.newArrayList();
allPlanNos.addAll(spvPlanNos);
List<String> planNos = planTranScreenRelDAO.getPlanNosByManagerOrg(taskCtr.getOrgCode());
if (CollectionUtils.isNotEmpty(planNos)) {
allPlanNos.addAll(planNos);
}
//获取所有金融服务费科目
List<PlanAcctTitle> acctFinFeeTitles = planAcctTitleRepo.getAcctFinFeeTitles(allPlanNos);
if (CollectionUtils.isNotEmpty(acctFinFeeTitles)) {
acctFinFeeTitles.forEach(planAcctTitle -> {
Date beginDay = planAcctTitle.getLastSettleDate();
VarChecker.checkNotNull(beginDay, "招联金融服务费计算失败,未指定开始统计日期 acctTitle=[{0}]", planAcctTitle);
if (DateTimeUtil.calcDayDiff(orgDate.getStandardDate(), beginDay) > 0) {
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算-beginDay[{1}]", planAcctTitle,
beginDay);
List<Date> calcAccountDates = Lists.newArrayList();
// beginDay = DateTimeUtil.addDays(beginDay, 1);
while (DateTimeUtil.calcDayDiff(orgDate.getStandardDate(), beginDay) > 0) {
beginDay = DateTimeUtil.addDays(beginDay, 1);
calcAccountDates.add(beginDay);
}
calcAccountDates.sort(Date::compareTo);
calcAccountDates.forEach(calcAccountDate -> {
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算-calcAccountDate[{1}]",
planAcctTitle, calcAccountDate);
PlanAcctTitleTransDetail planAcctTitleTransDetail = PlanSettleManager
.buildPlanAcctTitleTransDetail(
calcAccountDate, planAcctTitle, true);
Money finFeeAmt =new Money();
if(DateTimeUtil.isBeforeOnDate(FEE_OFFSET_DAY,calcAccountDate)){
if(StringUtil.equals(planAcctTitle.getPlanNo(), "9805102")) {
finFeeAmt = loanInstalLogRepository.getOrgDistPftApporAmt(calcAccountDate,
planAcctTitle.getPlanNo());
}
Money newFinFeeAmt = loanAstProfitLogRepo.getOrgDistPftAmt(calcAccountDate,planAcctTitle.getPlanNo());
finFeeAmt.addTo(newFinFeeAmt);
}else{
//2019-11-28之前金融服务费 获取逻辑
finFeeAmt = loanInstalLogRepository.getOrgDistPftAmt(calcAccountDate,planAcctTitle.getPlanNo());
}
planAcctTitleTransDetail.entry(finFeeAmt.getAmount());
planAcctTitleTransDetail.setSettleDate(calcAccountDate);
// set afterBal
planAcctTitleTransDetail.processBeforeUpdate();
acctTitleTransDetails.add(planAcctTitleTransDetail);
});
}
});
}
// 获取当前转让会计日
Day trfDate = orgAcctDayComponent.getTrfAcctDay();
transactionTemplate.execute(status -> {
if (CollectionUtils.isNotEmpty(acctTitleTransDetails)) {
planAcctTitleManager.store(acctTitleTransDetails);
}
astSyncTaskCtrRepo.insertSyncLog(trfDate.getStandardDate(), orgDate, taskCtr,
SyncTaskTypeEnum.AST_SER_FEE,
TaskStatusEnum.SUCCESS, hostManager.getHostInfo().getHostName());
return status;
});
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算end", orgDate.getDateString());
}
} else {
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算-ignore,已执行", taskCtr.getOrgCode());
}
} else {
LogUtil.info(LOGGER, "[ZLFinSerFeeJob]-[{0}]招联金融服务费计算-ignore,AST_MOD未完成", taskCtr.getOrgCode());
}
}
public void setZlOrgCode(String zlOrgCode) {
this.zlOrgCode = zlOrgCode;
}
}
package com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import com.abssqr.plat.common.facade.enums.CommonTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.enums.SyncTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.facade.model.org.OrganizationEntity;
import com.abssqr.plat.common.facade.model.plan.Plan;
import com.abssqr.plat.common.facade.model.plan.PlanAcctTitle;
import com.abssqr.plat.common.facade.model.plan.PlanAlloc;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.domain.task.ctr.AstSyncTaskCtrLog;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.common.model.enums.OrgTypeEnum;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.common.model.repo.plan.PlanAcctTitleRepo;
import com.abssqr.plat.common.model.repo.plan.PlanAllocRepo;
import com.abssqr.plat.common.model.repo.plan.PlanRepo;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.abssqr.plat.common.util.base.autoconfig.AbsConfig;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.plan.PlanManager;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
* 资金资产解绑任务生成。顺序,解绑->解绑匹配->同步匹配
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class CapitalAssertMatchJob extends BaseQuartzJob {
@Autowired
PlanRepo planRepo;
@Autowired
PlanAllocRepo planAllocRepo;
@Autowired
CommonTaskRepository commonTaskRepository;
@Autowired
JobControlRepository jobControlRepository;
@Autowired
AstSyncTaskCtrRepo astSyncTaskCtrRepo;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
/**
* 间隔1分钟执行生成匹配和解绑任务
*/
@Value("${sync.quartz.plan.capitalAssertMatch}")
private String cron;
@Autowired
private AbsConfig absConfig;
@Autowired
private PlanAcctTitleRepo planAcctTitleRepo;
@Override
protected String getCronExpr() {
return cron;
}
@Override
public void doExecute() {
JobControl jobControl = jobControlRepository.lockByJobName(getJobName());
if (jobControl == null || jobControl.getIsEff() == YNEnum.N) {
return;
}
LogUtil.info(LOGGER, "[capitalAssetMatchJob] 生成资金资产解绑/匹配任务开始");
Date execDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
List<PlanBase> plans = planRepo.getAllPlanAstByType(PlanTypeEnum.SPV.getCode());
for (PlanBase planBase : plans) {
if (planBase.getPlanType() == PlanTypeEnum.SPV) {
OrganizationEntity plan = (OrganizationEntity)planRepo.getPlanByNo(planBase.getPlanNo());
String planNo = plan.getPlanNo();
List<CommonTask> initAndExecCommonTasks = commonTaskRepository.queryInitAndExecUnMatchOrMatchTaskByContext(planNo);
if (CollectionUtils.isNotEmpty(initAndExecCommonTasks)) {
LogUtil.info(LOGGER, "[capitalAssetMatchJob]计划[{1}] 存在[初始化/正在执行中]的[资产匹配/解绑任务任务]", planNo);
continue;
}
//查询是否有解绑匹配的Task
List<CommonTask> initAndIgnoreCommonTask = commonTaskRepository.queryIgnoreUnMatchOrMatchTaskByContext(planNo);
List<CommonTask> toMatchedCapticalTask = initAndIgnoreCommonTask.stream()
.filter(v -> v.getTaskType() == CommonTaskTypeEnum.UNMATCH_CAPTITALASSERT_MATCH)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(toMatchedCapticalTask)) {
CommonTask commonTask = toMatchedCapticalTask.get(0);
commonTaskRepository.updateIgnoreTaskStatus2Init(commonTask.getId());
LogUtil.info(LOGGER, "[capitalAssetMatchJob]计划[{1}] 存在状态为Ignore的解绑匹配任务[{2}]", planNo, commonTask.getBizNo());
continue;
}
//查询存在已审批通过未解绑的兑付计划
List<PlanAlloc> planAllocs = planAllocRepo.queryUnMatchedApprovedAlloc(planNo);
if (CollectionUtils.isNotEmpty(planAllocs)) {
PlanAlloc planAlloc = planAllocs.get(0);
LogUtil.info(LOGGER, "[capitalAssetMatchJob]计划[{1}] 存在已审批通过的兑付计划[{2}]", planNo, planAlloc.getAllocNo());
//生成解绑任务
CommonTask commonTask = buildUnMatchTask(planAlloc.getAllocNo(), planNo);
commonTaskRepository.create(commonTask);
continue;
}
//判断今日的模型转换是否已经完成
AstSyncTaskCtrLog lastTaskLog = astSyncTaskCtrRepo.getTaskLogByExecDate(execDate, SyncTaskTypeEnum.AST_MOD, plan.getManagerOrgCode());
if (lastTaskLog != null) {
String syncMatchBizNo = generateSyncMatchBizNo(CommonTaskTypeEnum.SYNC_CAPTITALASSERT_MATCH, execDate, planNo);
//查询今日是否已经生成了同步匹配任务
List<CommonTask> commonTasks = commonTaskRepository.queryByBizNo(syncMatchBizNo);
if (CollectionUtils.isNotEmpty(commonTasks)) {
continue;
}
//如果投资结构本机余额是0则不创建匹配任务
if (checkCanBuildMatchJob(planNo)) {
LogUtil.info(LOGGER, "[capitalAssetMatchJob]计划[{1}]生成同步匹配任务", planNo);
CommonTask commonTask = buildSyncMatchTask(syncMatchBizNo, planNo);
commonTaskRepository.create(commonTask);
}
}
}
}
LogUtil.info(LOGGER, "[capitalAssetMatchJob] 生成资金资产解绑/匹配任务结束");
}
private boolean checkCanBuildMatchJob(String planNo) {
// 获取本金科目
List<PlanAcctTitle> planAcctTitleList = planAcctTitleRepo.getByEntityNo(planNo);
Money totalMoney = new Money();
for (PlanAcctTitle planAcctTitle : planAcctTitleList) {
if (planAcctTitle.getTitleType().isInvest()) {
Money money = planAcctTitle.getBal().clone();
totalMoney.addTo(money);
}
}
if (!totalMoney.isGreaterThanZero()) {
LOGGER.info("计划[{0}]投资结构本金总额小于等于0不进行资金资产匹配任务", planNo);
return false;
}
return true;
}
private String generateSyncMatchBizNo(CommonTaskTypeEnum commonTaskTypeEnum, Date acctDate, String planNo) {
StringBuilder sb = new StringBuilder();
sb.append(commonTaskTypeEnum.getCode());
sb.append("-");
sb.append(planNo);
sb.append("-");
sb.append(DateTimeUtil.formatYMD(acctDate));
return sb.toString();
}
private CommonTask buildUnMatchTask(String bizNo, String planNo) {
CommonTask commonTask = buildBasicCommonTask(CommonTaskTypeEnum.CAPTITALASSERT_UNMATCH, planNo);
commonTask.setBizNo(bizNo);
return commonTask;
}
private CommonTask buildSyncMatchTask(String bizNo, String planNo) {
CommonTask commonTask = buildBasicCommonTask(CommonTaskTypeEnum.SYNC_CAPTITALASSERT_MATCH, planNo);
commonTask.setBizNo(bizNo);
return commonTask;
}
private CommonTask buildBasicCommonTask(CommonTaskTypeEnum planTaskTypeEnum, String planNo) {
CommonTask commonTask = new CommonTask();
commonTask.setContext(planNo);
commonTask.setTaskType(planTaskTypeEnum);
commonTask.setTaskStatus(TaskStatusEnum.INIT);
commonTask.setEnv(absConfig.getEnv());
commonTask.setExecTimes(0L);
return commonTask;
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.scheduler.job.keeper.node;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.facade.enums.AbssqrNoticeTypeEnum;
import com.abssqr.plat.common.facade.enums.CommonTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.PlanTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.model.domain.plan.PlanTaskLog;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.repo.plan.PlanTaskLogRepo;
import com.abssqr.plat.common.model.repo.task.CommonTaskRepository;
import com.general.system.common.model.IEnum;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.MessageUtil;
import com.general.system.common.util.SystemDateUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* 资金资产匹配监控
*
* @author xiachenxiang
* @version com.abssqr.plat.biz.shared.scheduler.job.keeper.node: AstMatchKeeper.java, v 0.1 2020-02-07 1:47 PM xiachenxiang Exp $
*/
@Component
public class CapitalAstMatchKeeper extends AbstractKeeperNode {
@Autowired
private CommonTaskRepository commonTaskRepository;
@Autowired
private PlanTaskLogRepo planTaskLogRepo;
@Value("${wkabs.org.zhaolian:1009}")
private String zhaolianOrgCode;
@Value("${wkabs.zhaolian.capitalAstMatchKeeper.deadline:10 0 0}")
private String deadline;
private Long second = 60L * 60L;
@Override
protected Void doHandle(Date date) {
Date sysday = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
// 判断当前时间是否大于10点
Date currentTime = getCurrentStanderDate();
Date deadlineTime = getDeadLineTime(currentTime, deadline);
if (currentTime.compareTo(deadlineTime) > 0) {
List<PlanTaskLog> tasks = planTaskLogRepo.getTasks(sysday, PlanTaskTypeEnum.CAP_AST_MATCH_KEEPER);
if (CollectionUtils.isEmpty(tasks)) {
LogUtil.info(LOGGER, "资金资产匹配监控 - start");
StringBuffer sb = new StringBuffer();
exec(sb, CommonTaskTypeEnum.SYNC_CAPTITALASSERT_MATCH);
exec(sb, CommonTaskTypeEnum.UNMATCH_CAPTITALASSERT_MATCH);
exec(sb, CommonTaskTypeEnum.CAPTITALASSERT_UNMATCH);
if (StringUtils.isNotEmpty(sb)) {
// 获取用户
LogUtil.info(LOGGER, sb.toString());
// 获取用户
Set<String> receivers = super.getAdminReceivers();
sendSystemNotice("资金资产匹配监控告警", zhaolianOrgCode, sb.toString(), receivers);
}
PlanTaskLog planTaskLog = new PlanTaskLog();
planTaskLog.setExecDate(sysday);
planTaskLog.setPlanNo(zhaolianOrgCode);
planTaskLog.setTaskType(PlanTaskTypeEnum.CAP_AST_MATCH_KEEPER);
planTaskLogRepo.createTask(planTaskLog);
LogUtil.info(LOGGER, "资金资产匹配监控 - end");
}
}
return null;
}
/**
* @param sb 提示消息
* @param typeEnum 任务类型
*/
private void exec(StringBuffer sb, CommonTaskTypeEnum typeEnum) {
// 判断是否存在失败的任务
List<CommonTask> commonTasks = commonTaskRepository.queryByTypesAndStatus(Lists.newArrayList(typeEnum.getCode()), Lists.newArrayList(TaskStatusEnum.FAILURE.getCode()));
if (CollectionUtils.isNotEmpty(commonTasks)) {
sb.append(MessageUtil.formatMsg("[{0}]存在{1}条失败任务\n", typeEnum.getDesc(), commonTasks.size()));
}
// 判断执行时间大于1小时
Long count = commonTaskRepository.countByTypesAndStatusAndRange(second, Lists.newArrayList(typeEnum.getCode()), Lists.newArrayList(TaskStatusEnum.EXECUTING.getCode()));
if (count.intValue() != 0) {
sb.append(MessageUtil.formatMsg("[{0}]存在{1}条执行超时任务\n", typeEnum.getDesc(), count));
}
// 判断执行次数大于1
count = commonTaskRepository.countUnFinishAndMultipleExecByTypes(Lists.newArrayList(typeEnum.getCode()));
if (count.intValue() != 0) {
sb.append(MessageUtil.formatMsg("[{0}]存在{1}条执行次数大于1的任务\n", typeEnum.getDesc(), count));
}
}
@Override
protected IEnum getBizType() {
return AbssqrNoticeTypeEnum.CapitalAstMatch;
}
@Override
protected String getWatchJob() {
return CapitalAssertMatchJob.class.getName();
}
}
......@@ -4,13 +4,16 @@
*/
package com.abssqr.plat.biz.shared.scheduler.job.plan;
import com.abssqr.plat.biz.shared.handler.PlanCashFrozenHandler;
import java.util.Date;
import java.util.List;
import com.abssqr.plat.biz.shared.handler.PlanSettleHandler;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import com.abssqr.plat.common.facade.enums.PlanStatusEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.model.repo.plan.PlanRepo;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.general.system.bpm.enums.ApproveStatusEnum;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.LogUtil;
......@@ -28,9 +31,6 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
import java.util.List;
/**
* 计划资产需求统计任务
*
......@@ -46,8 +46,6 @@ public class PlanDailyJob extends BaseQuartzJob {
private final static Logger LOGGER = LoggerFactory.getLogger(PlanDailyJob.class);
@Autowired
private PlanCashFrozenHandler planCashFrozenHandler;
@Autowired
private PlanSettleHandler planSettleHandler;
@Autowired
private TransactionTemplate transactionTemplate;
......@@ -149,8 +147,6 @@ public class PlanDailyJob extends BaseQuartzJob {
// 结息
planSettleHandler.execute(planEntity, curDate);
// 水位冻结
planCashFrozenHandler.execute(planEntity, curDate);
}
}
}
\ No newline at end of file
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.biz.shared.scheduler.job.plan;
import com.abssqr.plat.biz.shared.handler.PlanAstReqHandler;
import com.abssqr.plat.biz.shared.scheduler.BaseQuartzJob;
import com.abssqr.plat.common.dal.mysql.auto.dao.PlanTranScreenRelDAO;
import com.abssqr.plat.common.facade.enums.AstPackStatusEnum;
import com.abssqr.plat.common.facade.enums.AstPackTradeTypeEnum;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.enums.SyncTaskTypeEnum;
import com.abssqr.plat.common.facade.enums.TaskStatusEnum;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.model.plan.PlanTransferRule;
import com.abssqr.plat.common.model.domain.ast.Pack;
import com.abssqr.plat.common.model.domain.task.TrCtrTask;
import com.abssqr.plat.common.model.repo.ast.PackRepository;
import com.abssqr.plat.common.model.repo.plan.PlanRepo;
import com.abssqr.plat.common.model.repo.task.AstSyncTaskCtrRepo;
import com.abssqr.plat.common.model.repo.tr.TrCtrTaskRepo;
import com.abssqr.plat.core.service.accounting.OrgAcctDayComponent;
import com.abssqr.plat.core.service.ast.AstPackManager;
import com.abssqr.plat.core.service.plan.PlanManager;
import com.abssqr.plat.core.service.plan.PlanTransferRuleManager;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.DateTimeUtil.BetweenType;
import com.general.system.common.util.LogUtil;
import com.general.system.common.util.VarChecker;
import com.google.common.collect.Lists;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.PersistJobDataAfterExecution;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.Date;
import java.util.List;
/**
* 计划资产需求统计任务
*
* @author zhenxuan.luo
* @version com.abssqr.plat.biz.shared.scheduler.job.plan: PlanPackGenJob.java, v 0.1 2019-06-18 21:19 zhenxuan.luo
* Exp $
*/
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class PlanPackJob extends BaseQuartzJob {
private final static Logger LOGGER = LoggerFactory.getLogger(PlanPackJob.class);
@Autowired
AstSyncTaskCtrRepo astSyncTaskCtrRepo;
@Autowired
TransactionTemplate transactionTemplate;
@Autowired
PlanAstReqHandler planAstReqHandler;
@Autowired
PlanTranScreenRelDAO planTranScreenRelDAO;
@Autowired
PlanManager planManager;
@Autowired
PlanRepo planRepo;
@Autowired
PackRepository packRepository;
@Autowired
TrCtrTaskRepo trCtrTaskRepo;
@Autowired
AstPackManager astPackManager;
@Autowired
private PlanTransferRuleManager planTransferRuleManager;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
/**
* 每天 0 0/5 * * * ?
*/
@Value("${sync.quartz.plan.pack}")
private String cron;
@Override
protected String getCronExpr() {
return cron;
}
@Override
protected boolean isRequestRecovery() {
return true;
}
@Override
public void doExecute() {
// 转让会计日
Date curDate = orgAcctDayComponent.getTrfAcctDay().getStandardDate();
LogUtil.info(LOGGER, "[PlanPackJob]-[{0}]计划资产包任务start", curDate);
List<String> orgCodes = astSyncTaskCtrRepo.getLastStatusFinishedOrgCodes(curDate, SyncTaskTypeEnum.AST_MOD);
for (String orgCode : orgCodes) {
LogUtil.info(LOGGER, "[PlanPackJob]-[{0}]执行管理机构[{1}]相关的计划资产包生成", curDate, orgCode);
try {
List<TrCtrTask> activeTrCtrTasks = trCtrTaskRepo
.getByManagerOrgCode(orgCode, curDate, TaskStatusEnum.INIT, AstPackTradeTypeEnum.AST_TRF_BIZ);
List<Pack> activePacks = astPackManager.getByManagerOrgCode(orgCode, curDate, AstPackStatusEnum.INIT);
if (CollectionUtils.isNotEmpty(activeTrCtrTasks) || CollectionUtils.isNotEmpty(activePacks)) {
LogUtil.warn(LOGGER, "[PlanPackJob]-[{0}]执行管理机构[{1}]资产包生成,有执行中的资产包[{2}]或者转让任务[{3}]", curDate,
orgCode, activePacks.size(), activeTrCtrTasks.size());
continue;
}
List<String> planNos = planTranScreenRelDAO.getPlanNosByManagerOrg(orgCode);
List<Pack> packs = Lists.newArrayList();
for (String planNo : planNos) {
// 获取计划全量信息
PlanBase planBase = planRepo.getPlanByNo(planNo);
// 放款池跳出不生成资产包
if (planBase.getPlanType() == PlanTypeEnum.SPV) {
LogUtil.debug(LOGGER, "[PlanPackJob]-跳过放款计划[{0}]", planBase.getPlanNo());
continue;
}
// 对应转让规则 及 筛选规则
PlanTransferRule transferRule = planTransferRuleManager.getByPlanNo(planNo);
VarChecker.checkNotNull(transferRule, "计划[{0}]创建资产包找不到对应转让规则", planBase.getPlanNo());
boolean trCheck = DateTimeUtil.between(curDate, transferRule.getStartTrDate(),
transferRule.getStopTrDate(), BetweenType.se);
if (trCheck) {
// 构建资产包
Pack pack = planAstReqHandler.execute(planBase, transferRule, curDate);
if (null != pack) {
packs.add(pack);
}
}
}
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
for (Pack pack : packs) {
LogUtil.info(LOGGER, "[PlanPackJob]-[{0}]生成资产包[{1}]", curDate, pack);
packRepository.create(pack);
}
}
});
} catch (Throwable e) {
LogUtil.error(LOGGER, e, "[PlanPackJob]-[{0}]执行管理机构[{1}]相关的计划资产包异常", curDate, orgCode);
}
}
LogUtil.info(LOGGER, "[PlanPackJob]-[{0}]计划资产包任务End", curDate);
}
}
\ No newline at end of file
/**
* abssqr.comInc.
* Copyright(c)2019-2019AllRightsReserved.
*/
package com.abssqr.plat.common.facade.service.report;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.model.report.wk.WkManagerReport;
import com.abssqr.plat.common.facade.param.base.CommonPlanQryParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormAstParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormMgrParam;
import java.util.List;
/**
*
* @author yangcheng
* @version ReportService.java, v0.12019-07-0114:18 yangchengExp$
*/
public interface ReportService {
/**
* 计划报表查询
* @param param
* @return
*/
WkManagerReport getReportFormPlan(ReportFormMgrParam param);
/**
* 资产报表查询
* @param param
* @return
*/
List<PlanReport> getReportFormAst(ReportFormAstParam param);
/**
* 资产报表查询
* @param param
* @return
*/
List<PlanReport> getReportFormMonthEnd(CommonPlanQryParam param);
}
......@@ -6,27 +6,20 @@ package com.abssqr.plat.test;
import java.util.Date;
import com.abssqr.plat.biz.shared.handler.LoanAstBuyBackMatchHandler;
import com.abssqr.plat.biz.shared.scheduler.job.keeper.node.CapitalAstMatchKeeper;
import com.abssqr.plat.common.dal.mysql.auto.dao.AcctDateDAO;
import com.abssqr.plat.common.dal.sync.auto.dao.WkAbsMfsBillCtrDAO;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.model.domain.accounting.AcctDate;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.domain.task.ctr.AstSyncTaskCtr;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.common.model.repo.acct.AcctDateRepo;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import cn.hutool.core.date.DateUtil;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.SystemDateUtil;
import com.general.system.common.util.VarChecker;
import org.apache.commons.lang3.StringUtils;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.MockitoTestExecutionListener;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.test.context.TestExecutionListeners;
/**
......@@ -39,34 +32,11 @@ import org.springframework.test.context.TestExecutionListeners;
@TestExecutionListeners(listeners = MockitoTestExecutionListener.class)
public class BaseAutoTests extends BaseAutoWithOutMockTests {
// @MockBean
// protected JobControlRepository mockJobControlRepository;
//
//
// @BeforeMethod
// protected void stopJob(){
// JobControl jobControl = new JobControl();
// jobControl.setIsEff(YNEnum.N);
// when(mockJobControlRepository.selectByJobName(Mockito.anyString())).thenReturn(jobControl);
// when(mockJobControlRepository.lockByJobName(Mockito.anyString())).thenReturn(jobControl);
// }
//
// protected void mockJobEff(String jobName,YNEnum ynEnum){
// JobControl jobControl = new JobControl();
// jobControl.setIsEff(ynEnum);
// jobControl.setJobName(jobName);
// when(mockJobControlRepository.selectByJobName(jobName)).thenReturn(jobControl);
// when(mockJobControlRepository.lockByJobName(jobName)).thenReturn(jobControl);
// }
@Autowired
private WkAbsMfsBillCtrDAO wkAbsMfsBillCtrDAO;
@Autowired
private AcctDateDAO acctDateDAO;
@Autowired
private AcctDateRepo acctDateRepo;
......@@ -79,17 +49,18 @@ public class BaseAutoTests extends BaseAutoWithOutMockTests {
Date acctDate = DateUtil.parse(strDate);
this.updateDate(acctDate, orgCode);
}
protected void updateDate(Date acctDate, String orgCode) {
OrgCodeEnum org = OrgCodeEnum.getByCode(orgCode);
VarChecker.checkNotNull(org, "不匹配的机构编码={0}", orgCode);
AcctDate now = acctDateRepo.getAcctDate(org);
if (now == null){
if (now == null) {
now = new AcctDate();
now.setOrgCode(org);
now.setAcctDate(acctDate);
now.setEff(true);
acctDateRepo.addAcctDate(now);
}else if (!DateTimeUtil.isSameDay(now.getAcctDate(), acctDate)) {
} else if (!DateTimeUtil.isSameDay(now.getAcctDate(), acctDate)) {
now.setAcctDate(acctDate);
acctDateRepo.modifyAcctDate(now);
}
......@@ -100,6 +71,7 @@ public class BaseAutoTests extends BaseAutoWithOutMockTests {
/**
* 停止任务
*
* @param jobName
* @return
*/
......@@ -120,6 +92,7 @@ public class BaseAutoTests extends BaseAutoWithOutMockTests {
/**
* 开启任务
*
* @param jobName
*/
protected void validJobCtr(String jobName) {
......@@ -138,40 +111,4 @@ public class BaseAutoTests extends BaseAutoWithOutMockTests {
jobControlRepository.update(jobControl);
}
@SpyBean
private CapitalAstMatchKeeper capitalAstMatchKeeper;
protected void mockCapitalAstMatchKeeper(Date date) {
Mockito.doReturn(date).when(capitalAstMatchKeeper).getCurrentStanderDate();
}
@SpyBean
private LoanAstBuyBackMatchHandler loanAstBuyBackMatchHandler;
protected void mockLoanAstBuyBackMatchHandler(){
Mockito.doReturn(Boolean.TRUE).when(loanAstBuyBackMatchHandler).canRun();
}
protected void mockCurrentDate(Date date){
SystemDateUtil systemDateUtil = Mockito.mock(SystemDateUtil.class);
final Date date1 = Mockito.mock(Date.class);
Mockito.when(date1.getTime()).thenReturn(date.getTime());
// Mockito.
//Mockito.when(systemDateUtil).thenReturn(date);
//Mockito.doReturn(date).when(systemDateUtil);
}
protected void autoPartition(String orgCode) {
AstSyncTaskCtr astSyncTaskCtr=new AstSyncTaskCtr();
astSyncTaskCtr.setOrgCode(orgCode);
String partitionName = "BILL_CTR_"+astSyncTaskCtr.getOrgCode();
String pName = wkAbsMfsBillCtrDAO.queryPartitionForCheck(partitionName);
if(StringUtils.isBlank(pName)){
wkAbsMfsBillCtrDAO.updateCreatePartition(astSyncTaskCtr.getOrgCode(),partitionName);
}
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2019 All Rights Reserved.
*/
package com.abssqr.plat.test.testlink.ast;
import com.abssqr.plat.biz.shared.scheduler.job.ast.ZLFinSerFeeJob;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
/**
* @author bangis.wangdf
* @version com.abssqr.plat.test.testlink.ast: ZLFinSerFeeJobTest.java, v 0.1 2019-09-17 18:43 bangis.wangdf Exp $
*/
public class ZLFinSerFeeJobTest extends BaseAutoTests {
@Autowired
ZLFinSerFeeJob zlFinSerFeeJob;
@XTest(relatePath = "testlink/ast/finFee")
@Test(dataProvider = "YamlDataProvider", description = "金融服务费处理")
public void testFinSerFee(ICase iCase, String acctDate) {
try {
super.updateDate(acctDate, OrgCodeEnum.WK1009.getCode());
zlFinSerFeeJob.setZlOrgCode("1009");
zlFinSerFeeJob.doExecute();
}catch (Exception e){
e.printStackTrace();
} finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.test.unittest.capitalAstMatch;
import com.abssqr.plat.biz.shared.handler.CapitalAstMatchHandler;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import com.general.system.common.util.DateTimeUtil;
import com.general.system.common.util.VarChecker;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.util.Date;
/**
* 资金资产匹配测试
* @author xiachenxiang
* @version com.abssqr.plat.test.unittest.capitalAstMatch: CapitalAstMatchUnitTest.java, v 0.1 2020-02-04 6:21 PM xiachenxiang Exp $
*/
public class CapitalAstMatchUnitTest extends BaseAutoTests {
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
@Autowired
private CapitalAstMatchHandler capitalAstMatchHandler;
@XTest(relatePath = "unittest/capitalAstMatch/astMatch")
@Test(dataProvider = "YamlDataProvider", description = "资金资产匹配")
public void exec(ICase iCase,String planNo,String execDateString,String acctDay,boolean expectResult,boolean expectExp) {
super.validJobCtr(capitalAssertMatchJob.getJobName());
try {
Date execDate =DateTimeUtil.parseFromYMD(execDateString);
super.updateDate(acctDay, OrgCodeEnum.ABS.getCode());
boolean result = capitalAstMatchHandler.execute(planNo, execDate);
VarChecker.checkEquals(result,expectResult,"实际结果与期望不符");
}catch (Exception e){
if (!expectExp){
e.printStackTrace();
throw e;
}
}finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
package com.abssqr.plat.test.unittest.capitalAstUnMatch;
import com.abssqr.plat.biz.shared.handler.CapitalAstUnMatchHandler;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.dal.mysql.auto.resultmap.AstScale;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.common.model.repo.ast.LoanBakRepo;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import com.general.system.common.model.Money;
import com.general.system.common.util.DateTimeUtil;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class CapitalAstUnMatchTest extends BaseAutoTests {
@Autowired
CapitalAstUnMatchHandler capitalAstUnMatchHandler;
@Autowired
LoanBakRepo loanBakRepo;
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
@XTest(relatePath = "unittest/capitalAstUnMatch")
@Test(dataProvider = "YamlDataProvider", description = "资金资产解绑")
public void exec(ICase iCase, String planNo,String allocNo, String acctDay,String layerNo,Integer allOwnCapital) {
super.validJobCtr(capitalAssertMatchJob.getJobName());
try {
Date acctDate = DateTimeUtil.parseFromYMD(acctDay);
super.updateDate(acctDate, OrgCodeEnum.ABS.getCode());
capitalAstUnMatchHandler.execute(planNo,allocNo,acctDate);
List<AstScale> astScaleList = loanBakRepo.getAstScale(acctDate, planNo);
Map<String, List<AstScale>> capitalAstMap = astScaleList.stream()
.collect(Collectors.groupingBy(AstScale::getCapitalNo));
List<AstScale> astScales = capitalAstMap.get(layerNo);
Assert.notEmpty(astScales,"找不到投资层级"+layerNo+"对应的资产");
Money prinBal = astScales.get(0).getPrinBal();
Assert.isTrue(prinBal.getAmount().compareTo(new BigDecimal(allOwnCapital))<=0,"不符合预期资产规模");
}catch (Exception e){
e.printStackTrace();
throw e;
}finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
package com.abssqr.plat.test.unittest.job;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.common.facade.enums.YNEnum;
import com.abssqr.plat.common.model.domain.job.JobControl;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.common.model.repo.job.JobControlRepository;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.text.ParseException;
/*
前置条件: 不存在Init或者exec的任务
情况一,存在为Ignore的解绑匹配任务
情况二,存在已审批通过未解绑兑付计划
情况三,今日模型转换已完成且未生成同步匹配任务
*/
public class CapitalAssertMatchJobTest extends BaseAutoTests {
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
@Autowired
private JobControlRepository jobControlRepository;
@XTest(relatePath = "unittest/job/capitalAssetMatch")
@Test(dataProvider = "YamlDataProvider", description = "生成资产解绑和资产资金匹配的任务")
public void jobTest(ICase iCase, String strDate) throws ParseException {
try {
//开启CapitalAssertMatchJob任务
JobControl jobControl = jobControlRepository.selectByJobName(capitalAssertMatchJob.getJobName());
jobControl.setIsEff(YNEnum.Y);
jobControlRepository.update(jobControl);
// 更新会计日期
super.updateDate(strDate, OrgCodeEnum.ABS.getCode());
capitalAssertMatchJob.doExecute();
}catch (Exception e){
e.printStackTrace();
throw e;
}finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.test.unittest.job.keeper;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.biz.shared.scheduler.job.keeper.node.CapitalAstMatchKeeper;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 资金资产匹配监控测试
* @author xiachenxiang
* @version com.abssqr.plat.test.unittest.job.keeper: CapitalAstMatchKeeperTest.java, v 0.1 2020-02-07 4:59 PM xiachenxiang Exp $
*/
public class CapitalAstMatchKeeperTest extends BaseAutoTests {
@Autowired
private CapitalAstMatchKeeper capitalAstMatchKeeper;
@XTest(relatePath = "unittest/job/CapitalAstMatchKeeper")
@Test(dataProvider = "YamlDataProvider", description = "资金资产匹配监控测试")
public void jobTest(ICase iCase, String strDate) {
try {
// 更新会计日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = sdf.parse(strDate);
validJobCtr(CapitalAssertMatchJob.class.getName());
mockCapitalAstMatchKeeper(date);
capitalAstMatchKeeper.execute(date);
invalidJobCtr(CapitalAssertMatchJob.class.getName());
} catch (ParseException e) {
throw new RuntimeException(e.getMessage());
} finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
/**
* abssqr.com Inc.
* Copyright (c) 2017-2020 All Rights Reserved.
*/
package com.abssqr.plat.test.unittest.planBuyBack;
import com.abssqr.plat.biz.shared.dispatcher.buyBackMatch.LoanAstBuyBackMatchExecutor;
import com.abssqr.plat.biz.shared.dispatcher.buyBackMatch.LoanAstBuyBackMatchLoader;
import com.abssqr.plat.biz.shared.dispatcher.buyBackMatch.LoanAstBuyBackMatchStarter;
import com.abssqr.plat.common.model.domain.task.CommonTask;
import com.abssqr.plat.common.model.enums.OrgCodeEnum;
import com.abssqr.plat.test.BaseAutoTests;
import com.abssqr.test.annotation.XTest;
import com.abssqr.test.icase.ICase;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.annotations.Test;
import java.util.List;
/**
* 资产回购筛选测试
*
* @author xiachenxiang
* @version com.abssqr.plat.test.unittest.planBuyBack: PlanBuyBack.java, v 0.1 2020-02-12 2:10 PM xiachenxiang Exp $
*/
public class PlanBuyBackMatchTest extends BaseAutoTests {
@Autowired
private LoanAstBuyBackMatchLoader planBuyBackMatchLoader;
@Autowired
private LoanAstBuyBackMatchExecutor planBuyBackMatchExecutor;
@XTest(relatePath = "unittest/planBuyBack/match")
@Test(dataProvider = "YamlDataProvider", description = "资产回购筛选")
public void execute(ICase iCase, String acctDate) {
try {
// 更新会计日期
super.updateDate(acctDate, OrgCodeEnum.ABS.getCode());
// 设置任务关闭
this.invalidJobCtr(LoanAstBuyBackMatchStarter.JOB_NAME);
mockLoanAstBuyBackMatchHandler();
planBuyBackMatchLoader.setSleepTime(0L);
List<CommonTask> commonTasks = planBuyBackMatchLoader.loadToDoNodes(1);
planBuyBackMatchExecutor.execute(commonTasks.get(0));
} catch (Exception e) {
throw e;
} finally {
// 校验数据
super.checkDB(iCase);
super.clearDB(iCase);
}
}
}
......@@ -10,10 +10,7 @@ package com.abssqr.plat.web.controller.job;
import java.util.List;
import com.abssqr.plat.biz.shared.scheduler.job.ast.ZLFinSerFeeJob;
import com.abssqr.plat.biz.shared.scheduler.job.capitalAssertMatch.CapitalAssertMatchJob;
import com.abssqr.plat.biz.shared.scheduler.job.plan.PlanDailyJob;
import com.abssqr.plat.biz.shared.scheduler.job.plan.PlanPackJob;
import com.abssqr.plat.common.facade.model.account.Account;
import com.abssqr.plat.common.facade.model.plan.PlanBase;
import com.abssqr.plat.common.facade.service.AccountService;
......@@ -50,30 +47,14 @@ public class JobController {
@Autowired
private PlanDailyJob planDailyJob;
@Autowired
private PlanPackJob planPackJob;
@Autowired
private ZLFinSerFeeJob zlFinSerFeeJob;
@Autowired
private PlanReportRepo planReportRepo;
@Autowired
private AccountService accountService;
@Autowired
private CapitalAssertMatchJob capitalAssertMatchJob;
@Autowired
private OrgAcctDayComponent orgAcctDayComponent;
/**
* 计划资产包生成任务
*
* @return
* @description
*/
@RequestMapping(path = "/job/planPackJob.json", method = RequestMethod.GET)
public BaseResult<Boolean> planPackJob() {
planPackJob.doExecute();
return BaseResult.success(null);
}
/**
* 每日处理
......@@ -92,18 +73,6 @@ public class JobController {
/**
* 资金资产任务Task生成Job
*
* @return
* @description
*/
@RequestMapping(path = "/job/capitalAssetMatchJob.json", method = RequestMethod.GET)
public BaseResult<Boolean> capitalAssetMatchJob() {
capitalAssertMatchJob.doExecute();
return BaseResult.success(null);
}
/**
* 查询账户余额
*
* @return
......@@ -114,17 +83,6 @@ public class JobController {
return accountService.queryBalance();
}
/**
* 查询账户余额
*
* @return
* @description
*/
@RequestMapping(path = "/acct/zlFinSerFeeJob.json", method = RequestMethod.GET)
public BaseResult<Boolean> zlFinSerFeeJob() {
zlFinSerFeeJob.doExecute();
return BaseResult.success(null);
}
/**
* 初始化计划 日报基础数据
......
/**
* abssqr.comInc.
* Copyright(c)2019-2019AllRightsReserved.
*/
package com.abssqr.plat.web.controller.report;
import com.abssqr.plat.common.facade.enums.PlanTypeEnum;
import com.abssqr.plat.common.facade.enums.TimeStampTypeEnum;
import com.abssqr.plat.common.facade.model.report.MonthReportDateField;
import com.abssqr.plat.common.facade.model.report.PlanReport;
import com.abssqr.plat.common.facade.model.report.wk.WkManagerReport;
import com.abssqr.plat.common.facade.param.base.CommonPlanQryParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormAstParam;
import com.abssqr.plat.common.facade.param.reportForm.ReportFormMgrParam;
import com.abssqr.plat.common.facade.service.report.ReportService;
import com.abssqr.plat.common.model.exception.AbssqrBizException;
import com.abssqr.plat.web.fileExport.FileExportTypeEnum;
import com.abssqr.plat.web.fileExport.FileExportUtil;
import com.abssqr.plat.common.facade.utils.ListID;
import com.general.system.common.util.MessageUtil;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 报表中心
*
* @author yangcheng
* @version ReportFormController.java, v0.12019-06-2819:14 yangchengExp$
*/
@Controller
@RequestMapping(value = "/export")
public class ReportFormController {
@Autowired
private FileExportUtil fileExportUtil;
@Autowired
private ReportService reportService;
/**
* 管理报表
* @param param
* @return
* @description 查询计划报表
*/
@RequestMapping(path = "/reportForm/plan/months", method = RequestMethod.GET)
public void getReportFormPlan(ReportFormMgrParam param, HttpServletResponse response) throws IOException {
FileExportTypeEnum fileExportType= param.getPlanType().equals(PlanTypeEnum.SPV.getCode())?
FileExportTypeEnum.MANAGER_SPV_RPT:FileExportTypeEnum.MANAGER_PLAN_RPT;
WkManagerReport wkManagerReport=reportService.getReportFormPlan(param);
String begin = param.getBeginTime();
String end = param.getEndTime();
if (wkManagerReport == null) {
throw new AbssqrBizException(MessageUtil.formatMsg("计划[{0}]对应日期[{1}-{2}]的报表未生成"
, param.getPlanNo(),begin,end));
}
// 报表模型数据
Map<String, Object> model = new HashMap<>();
String rptDate = param.getYear() + TimeStampTypeEnum.getByCode(param.getTimeStamp()).getDesc();
model.put("rpt", wkManagerReport);
model.put("rptDate", rptDate);
model.put("investId", new ListID());
model.put("feeId", new ListID());
MonthReportDateField beginDays = new MonthReportDateField();
beginDays.parse(begin);
MonthReportDateField endDays = new MonthReportDateField();
endDays.parse(end);
String fileKey = param.getPlanNo() + "_" + beginDays.desc() + "-" + endDays.desc();
fileExportUtil.exportXls(response, fileExportType, fileKey, model);
}
/**
* 查询资产报表
* @param param
* @return
* @description 查询资产报表
*/
@RequestMapping(path = "/reportForm/ast/days", method = RequestMethod.GET)
public void getReportFormPlanAst(ReportFormAstParam param, HttpServletResponse response) throws IOException {
FileExportTypeEnum fileExportType= param.getPlanType().equals(PlanTypeEnum.SPV.getCode())?
FileExportTypeEnum.AST_SPV_RPT:FileExportTypeEnum.AST_PLAN_RPT;
List<PlanReport> reports = reportService.getReportFormAst(param);
if (CollectionUtils.isEmpty(reports)) {
throw new AbssqrBizException(MessageUtil.formatMsg("计划[{0}]对应日期[{1}-{2}]的报表未生成", param.getPlanNo(),
param.getBeginDate(), param.getEndDate()));
}
PlanReport firstRpt = reports.get(0);
PlanReport lastRpt = reports.get(reports.size() - 1);
// 报表模型数据
Map<String, Object> model = new HashMap<>();
model.put("reports", reports);
String fileKey = param.getPlanNo() + "_" + firstRpt.getRptDate().desc() + "-" + lastRpt.getRptDate().desc();
fileExportUtil.exportXls(response, fileExportType, fileKey, model);
}
/**
* 受让池资产月末报表
* @param param
* @return
* @description 查询资产报表
*/
@RequestMapping(path = "/reportForm/ast/monthEnd", method = RequestMethod.GET)
public void getReportFormAstMonth(CommonPlanQryParam param, HttpServletResponse response) throws IOException {
List<PlanReport> reports = reportService.getReportFormMonthEnd(param);
if (CollectionUtils.isEmpty(reports)) {
throw new AbssqrBizException(MessageUtil.formatMsg("计划[{0}]月末报表没有生成", param.getPlanNo()));
}
PlanReport firstRpt = reports.get(0);
PlanReport lastRpt = reports.get(reports.size() - 1);
// 报表模型数据
Map<String, Object> model = new HashMap<>();
model.put("reports", reports);
String fileKey = param.getPlanNo() + "_" + firstRpt.getRptDate().desc() + "-" + lastRpt.getRptDate().desc();
fileExportUtil.exportXls(response, FileExportTypeEnum.AST_ME_RPT, fileKey, model);
}
}
\ No newline at end of file
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