/** * @Project: hehenian-biz-service * @Package com.hehenian.biz.component.trade.impl * @Title: DefaultRepayment.java * @Description: TODO * @author: zhangyunhmf * @date 2014年9月28日 上午8:43:00 * @Copyright: HEHENIAN Co.,Ltd. All rights reserved. * @version V1.0 */ package com.hehenian.biz.component.trade.impl; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import com.hehenian.biz.common.account.dataobject.AccountUserDo; import com.hehenian.biz.common.account.dataobject.PersonDo; import com.hehenian.biz.common.base.constant.Constants; import com.hehenian.biz.common.base.result.IResult; import com.hehenian.biz.common.base.result.ResultSupport; import com.hehenian.biz.common.exception.BusinessException; import com.hehenian.biz.common.fund.dataobject.FundDo; import com.hehenian.biz.common.notify.dataobject.MessageType; import com.hehenian.biz.common.notify.dataobject.SMSNotifyDo; import com.hehenian.biz.common.notify.dataobject.SmsType; import com.hehenian.biz.common.trade.dataobject.AssignmentDebtDo; import com.hehenian.biz.common.trade.dataobject.BorrowDo; import com.hehenian.biz.common.trade.dataobject.ChinapnrAccount; import com.hehenian.biz.common.trade.dataobject.FundrecordDo; import com.hehenian.biz.common.trade.dataobject.InvestDo; import com.hehenian.biz.common.trade.dataobject.InvestRepaymentDo; import com.hehenian.biz.common.trade.dataobject.InvestRepaymentWrap; import com.hehenian.biz.common.trade.dataobject.RepaymentContext; import com.hehenian.biz.common.trade.dataobject.RepaymentDo; import com.hehenian.biz.common.trade.dataobject.RepaymentFeeDo; import com.hehenian.biz.common.trade.dataobject.RiskDetailDo; import com.hehenian.biz.common.util.CalculateUtils; import com.hehenian.biz.common.util.DateUtil; import com.hehenian.biz.common.util.NotifyTemplateUtil; import com.hehenian.biz.common.util.NumberUtil; import com.hehenian.biz.component.account.IPersonComponent; import com.hehenian.biz.component.account.IUserComponent; import com.hehenian.biz.component.fund.dao.IFundDao; import com.hehenian.biz.component.notify.INotifyDao; import com.hehenian.biz.component.trade.IAssignmentDebtComponent; import com.hehenian.biz.component.trade.IBorrowComponent; import com.hehenian.biz.component.trade.IFundrecordComponent; import com.hehenian.biz.component.trade.IGuaranteeInstitutionsComponent; import com.hehenian.biz.component.trade.IInvestComponent; import com.hehenian.biz.component.trade.IInvestRepaymentComponent; import com.hehenian.biz.component.trade.IRepaymentComponent; import com.hehenian.biz.component.trade.IRepaymentManagerComponent; import com.hehenian.biz.component.trade.IRiskDetailComponent; import com.hehenian.biz.facade.account.AccountType; import com.hehenian.biz.facade.account.IAccountManagerService; import com.hehenian.biz.facade.account.chinapnr.ChinaPnrConfig; import com.hehenian.biz.facade.account.parameter.InParameter; import com.hehenian.biz.facade.account.parameter.OutParameter; /** * * @author: zhangyunhmf * @date 2014年9月28日 上午8:43:00 */ public abstract class DefaultAbstractRepayComponent implements IRepaymentManagerComponent { protected final Logger logger = Logger.getLogger(this.getClass()); @Autowired protected IRepaymentComponent repaymentComponent; @Autowired protected IAccountManagerService accountManagerService; @Autowired protected ChinaPnrConfig chinaPnrConfig; @Autowired protected IPersonComponent personComponent; @Autowired protected IBorrowComponent borrowComponent; @Autowired protected IGuaranteeInstitutionsComponent guaranteeInstitutionsComponent; @Autowired protected IRiskDetailComponent riskDetailComponent; @Autowired protected INotifyDao smsDao; // 短信 @Autowired protected INotifyDao mailNotifyDao; // 邮件 @Autowired protected IUserComponent userComponent; @Autowired protected IFundrecordComponent fundrecordComponent; @Autowired protected IFundDao fundDao; @Autowired protected IInvestComponent investComponent; @Autowired protected IInvestRepaymentComponent investRepaymentComponent; @Autowired protected IAssignmentDebtComponent assignmentDebtComponent; /** * 费用分摊账号映射 */ private Map<String, ChinapnrAccount> feeAccountMap; /** * 更新标的的状态, 和还款期数 * * @param borrowId * 标的ID * @author: zhangyunhmf * @date: 2014年9月24日下午4:50:01 */ public abstract void updateBorrow(long borrowId); /** * 构建还款列表 * * @author: zhangyunhmf * @date: 2014年10月8日下午1:58:05 */ public abstract int buildInvestList(RepaymentContext rc); /** * 将回款对象转成 还款对象包装对象 * * @param investRepaymentList * @return */ public List<InvestRepaymentWrap> convertInvestRepaymentWrap(List<InvestRepaymentDo> investRepaymentList) { if (null == investRepaymentList) { return null; } List<InvestRepaymentWrap> listWrap = new ArrayList<InvestRepaymentWrap>(); for (InvestRepaymentDo irDo : investRepaymentList) { InvestRepaymentWrap investWrap = new InvestRepaymentWrap(); investWrap.setInvestRepaymentDO(irDo); listWrap.add(investWrap); } return listWrap; } /** * 更新还款状态, 更新已收本金,利息,罚金= 所有费用和 * * 代偿 @see * {@link com.hehenian.biz.component.trade.impl.CompRepayComponentImpl#updateRepaymentStatus()} * 提前结清 @see * {@link com.hehenian.biz.component.trade.impl.PreSettleRepayComponentImpl#updateRepaymentStatus()} * * @param needPI * 本金 * @param lateFI * 罚金 * @param repayId * 还款ID * @param version * 还款记录version * @param borrowId * 标的ID * * @author: zhangyunhmf * @date: 2014年9月24日下午4:45:34 */ public void updateRepaymentStatus(RepaymentContext rc) { RepaymentDo repaymentDo = rc.getRepaymentDo(); RepaymentDo newRepaymentDo = new RepaymentDo(); newRepaymentDo.setRepayStatus(2); newRepaymentDo.setId(repaymentDo.getId()); newRepaymentDo.setRealRepayDate(new Date()); newRepaymentDo.setExecuteTime(new Date()); repaymentComponent.updateRepaymentById(newRepaymentDo); } /** * 查询费用子表 代偿 @see * {@link com.hehenian.biz.component.trade.impl.CompRepayComponentImpl#buildRepaymentFee()} * 提前结清 @see * {@link com.hehenian.biz.component.trade.impl.PreSettleRepayComponentImpl#buildRepaymentFee()} * * @author: zhangyunhmf * @date: 2014年10月22日下午4:25:31 */ public void buildRepaymentFee(RepaymentDo repayDo,Integer paymentMode) { // 构建应还费用 repayDo.buildRepaymentFee(); // 查询实还金额 List<RepaymentFeeDo> feeList = this.repaymentComponent.getByRepaymentId(repayDo.getId()); // put已收费用 if (null != feeList) { for (RepaymentFeeDo rpf : feeList) { RepaymentFeeDo tmpFee = repayDo.getRepaymentFee(rpf.getFeeCode()); if (tmpFee == null) { repayDo.addRepaymentFee(rpf); } else { tmpFee.setHasAmount(rpf.getHasAmount()); } } } } /** * 根据用户ID 获取用户对象, 如果是代偿, 代偿子类会覆盖这个方法根据,配置文件里的代偿账号查询用户对象 * * @return * @author: zhangyunhmf * @date: 2014年10月22日下午6:22:47 */ public int buildPubisher(RepaymentContext rc) { AccountUserDo user = this.userComponent.getById(rc.getUserId()); if (null == user) { throw new BusinessException("找不到借款人"); } rc.setUserDo(user); rc.setUsername(user.getUsername()); return 0; } /** * 构建还款记录对象根据还款ID 查询一个还款记录, 提前结清是汇总的一个还款对象具体看提前结清的实现 * * @see com.hehenian.biz.component.trade.impl.PreSettleRepayComponentImpl#buildRepayment() * @see com.hehenian.biz.component.trade.impl.CompRepayComponentImpl#buildRepayment() * @return * @author: zhangyunhmf * @date: 2014年9月30日上午9:42:19 */ public RepaymentDo buildRepayment(RepaymentContext rc) { long repayId = rc.getRepaymentId(); RepaymentDo repaymentDo = this.repaymentComponent.getById(repayId); rc.setRepaymentDo(repaymentDo); return repaymentDo; } /** * 根据费用分摊到不同的子账户 * * @param feeCode * @return * @author: zhangyunhmf * @date: 2014年10月23日上午9:58:24 */ public Map<String, ChinapnrAccount> buildFeeAccountMap() { Map<String, ChinapnrAccount> feeAccountMap = new HashMap<String, ChinapnrAccount>(); // 901 提前结清手续费 ChinapnrAccount cAccount = new ChinapnrAccount(); cAccount.setAccountId(this.chinaPnrConfig.getConsFeeAccount()); cAccount.setCustId(this.chinaPnrConfig.getConsFeeCustId()); feeAccountMap.put(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_PRE, cAccount); // 603 扣除逾期罚息 ChinapnrAccount cAccount1 = new ChinapnrAccount(); cAccount1.setAccountId(this.chinaPnrConfig.getFxAccount()); cAccount1.setCustId(this.chinaPnrConfig.getMerCustId()); feeAccountMap.put(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_FX, cAccount1); // consult 咨询费 ChinapnrAccount cAccount2 = new ChinapnrAccount(); cAccount2.setAccountId(this.chinaPnrConfig.getConsFeeAccount()); cAccount2.setCustId(this.chinaPnrConfig.getConsFeeCustId()); feeAccountMap.put(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_CONSULT, cAccount2); // 还款手续费 ChinapnrAccount cAccount3 = new ChinapnrAccount(); cAccount3.setAccountId(this.chinaPnrConfig.getFeeAccount()); cAccount3.setCustId(this.chinaPnrConfig.getFeeCustId()); feeAccountMap.put(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_SERVICE_CHARGE, cAccount3); return feeAccountMap; } public void finishedInvestRepay(RepaymentContext rc) { // RepaymentContext rc = this.getContext(); // 查询所有投资人的投资信息 List<InvestRepaymentWrap> investList = rc.getInvestList(); for (InvestRepaymentWrap irWrap : investList) { InvestRepaymentDo investRepay = irWrap.getInvestRepaymentDO(); // 取收益用户 AccountUserDo inUser = this.userComponent.getById(investRepay.getOwner()); investRepay.setOwnerUser(inUser); // 取投资 InvestDo investDo = this.investComponent.getById(investRepay.getInvestId()); // 因为getById 取出来的投资investDo是被重 sqlsession的缓存中获取,他们将是统一一个对象, // 这相同的事务中(即这个for循环中) InvestDo cloneInvestDo = new InvestDo(); BeanUtils.copyProperties(investDo, cloneInvestDo); investRepay.setInvestDo(cloneInvestDo); // 取债券转让 AssignmentDebtDo adebt = assignmentDebtComponent.getLastAssignmentDebtByInvestId(cloneInvestDo.getId(), investRepay.getOwner()); if (null != adebt) { // 如果发生了代偿,此时的owner 是代偿账户,根据投资和代偿找不到债券转让, // 但是经测试,还代偿人的时候,这个subordId没有限制 // 如果不加这个不等于 null // 的判断,会把之前找到的债券转让记录覆盖,导致资金流向不对的异常, // 这是因为investDo 对象在这个for里ibatis返回的是同一个对象 cloneInvestDo.setAssignDebtDo(adebt); } } } /** * 检查还款期数 * * @param deadline * 借款期数 * @param hasDeadline * 已还款期数 * @return * @author: zhangyunhmf * @date: 2014年9月24日上午9:12:00 */ protected boolean checkDeadline(int deadline, int hasDeadline) { return deadline > hasDeadline; } /** * 获取接口人, 如果是代偿获取代偿账号对应的用户 * * @return * @author: zhangyunhmf * @date: 2014年9月29日下午4:09:27 */ public AccountUserDo getPublisher(RepaymentContext rc) { AccountUserDo user = rc.getUserDo(); return user; } /** * 从上下文中取还款记录 * * @return * @author: zhangyunhmf * @date: 2014年9月29日下午4:09:27 */ protected RepaymentDo getRepaymentDo(RepaymentContext rc) { // RepaymentContext rc = context.get(); RepaymentDo repaymentDo = rc.getRepaymentDo(); if (null == repaymentDo) { repaymentDo = this.buildRepayment(rc); rc.setRepaymentDo(repaymentDo); } return repaymentDo; } /** * 构建还款的 所需的数据上下文 * * @param repaymentId * 还款ID * @param borrowId * 标的ID * @param userId * 当期用户ID * @param username * 用户名 * @param operationType * 还款操作种类 * @param outCustId * 出资汇付ID * @param webURL * 系统URL * @author: zhangyunhmf * @date: 2014年9月30日上午9:06:16 */ public RepaymentContext buildContext(long repaymentId, long borrowId, long userId, String username, String operationType, String outCustId, String webURL) { RepaymentContext rc; rc = new RepaymentContext(repaymentId, borrowId, userId, username, operationType, outCustId, webURL); this.feeAccountMap = buildFeeAccountMap(); RepaymentDo repaymentDo = this.buildRepayment(rc); this.buildPubisher(rc); BorrowDo borrow = borrowComponent.getById(borrowId); this.buildRepaymentFee(repaymentDo, borrow.getPaymentMode()); rc.setBorrow(borrow); // 构建还款列表 this.buildInvestList(rc); // 分摊费用 rc.splitFee(); // 根据回款列表取投资和债券转让 this.finishedInvestRepay(rc); return rc; } /** * * updateRepayVersion更新版本 * * @param newVersion * 新版本 * @param status * 状态 * @param repaymentId * 还款id * @return boolean * @exception * @since 1.0.0 */ protected boolean updateRepayVersion(int newVersion, int status, long repaymentId) { return repaymentComponent.upRepaymentVersionById(newVersion, status, repaymentId); } /** * * checkUser 检查用户合法性 * * @return boolean * @exception * @since 1.0.0 */ protected boolean checkUser(RepaymentContext rc) { BorrowDo borrow = rc.getBorrow(); long userId = rc.getUserDo().getId(); return borrow.getPublisher().longValue() == userId; } /** * * checkRepaymentStatus 检查还款记录的状态 * * @return boolean * @exception * @since 1.0.0 */ protected boolean checkRepaymentStatus(RepaymentDo repay) { return repay.getRepayStatus() == 1; } protected boolean checkRepaymentAmount(double needAmount) { return needAmount > 0; } /** * 出资账户,如果代偿是代偿方,从配置文件读取, 否则就是借款人 */ public String getOutCustId(RepaymentContext rc) { return String.valueOf(rc.getUserDo().getUsrCustId()); } /** * 出资账户,如果代偿是代偿方,从配置文件读取, 否则就是借款人 */ public String getOutAcctId() { return ""; } /** * * checkAmount 检查用户账户金额是否足够 * * @return boolean * @exception * @since 1.0.0 */ protected boolean checkAmount(long userId, double needAmount) { AccountUserDo user = userComponent.getById(userId); return user.getUsableSum() >= needAmount; } /** * 构建投资人资金变动记录的remark * * @param fundrecordRemarkTemplate * @param fundName * 费用名称 * @param amount * 还款金额 * @return * @author: zhangyunhmf * @date: 2014年10月9日上午9:43:14 */ public String buildInvestorFundRecordRemark(RepaymentContext rc, String fundrecordRemarkTemplate, String fundName, double amount) { try { // RepaymentContext rc = this.getContext(); BorrowDo borrow = rc.getBorrow(); Map<String, Object> messageObject = new HashMap<String, Object>(); messageObject.put("webURL", rc.getWebURL()); messageObject.put("borrowTitle", borrow.getBorrowTitle()); messageObject.put("borrowId", borrow.getId()); messageObject.put("needAmount", NumberUtil.formatDouble(amount)); messageObject.put("fundMode", fundName); return NotifyTemplateUtil.getContentByTemplate(fundrecordRemarkTemplate, messageObject); } catch (Throwable e) { logger.error(e); return ""; } } /** * 构建投资人短信通知的内容 * * @param notifyTemplate * @return * @author: zhangyunhmf * @date: 2014年10月8日下午5:34:56 */ public String buildInvestorSmsContent(RepaymentContext rc, String notifyTemplate, String username, double recivedPrincipal, double recivedInterest, double recivedFI, double investFee) { // 尊敬的[${userName}]: // 您投资的借款[${borrowTitle}],第[${repayPeriod}]期还款已经完成.<br/>[${fundMode}]本期应得总额:¥[${recivedSum}],其中本金部分为:[${hasP}]元,利息部分:[${hasI}]元,实得逾期罚息:[${hasFI}]元<br/>扣除投资管理费:¥[${mFee}]元<br/>实得总额:¥[${msFee}]元 try { BorrowDo borrow = rc.getBorrow(); RepaymentDo repayDo = rc.getRepaymentDo(); Map<String, Object> messageObject = new HashMap<String, Object>(); double recivedSum = recivedInterest + recivedPrincipal + recivedFI; messageObject.put("userName", username); messageObject.put("borrowTitle", borrow.getBorrowTitle()); messageObject.put("repayPeriod", repayDo.getRepayPeriod()); messageObject.put("fundMode", ""); messageObject.put("hasP", NumberUtil.formatDouble(recivedPrincipal));// 本金 messageObject.put("hasI", NumberUtil.formatDouble(recivedInterest));// 利息 messageObject.put("hasFI", NumberUtil.formatDouble(recivedFI));// 逾期罚息 messageObject.put("mFee", NumberUtil.formatDouble(investFee));// 投资管理费 messageObject.put("msFee", NumberUtil.formatDouble(recivedSum - investFee));// 实得总额 messageObject.put("recivedSum", NumberUtil.formatDouble(recivedSum));// 本期应得总额 return NotifyTemplateUtil.getContentByTemplate(notifyTemplate, messageObject); } catch (Throwable e) { logger.error(e); return ""; } } /** * 构建借款人资金变动记录的remark * * @return * @author: zhangyunhmf * @date: 2014年10月8日下午5:29:43 */ public String buildPublisherFundRecordRemark(RepaymentContext rc, String fundrecordRemarkTemplate, String fundMode) { try { // RepaymentContext rc = this.getContext(); String userName = rc.getUsername(); BorrowDo borrow = rc.getBorrow(); RepaymentDo repayDo = rc.getRepaymentDo(); Map<String, Object> messageObject = new HashMap<String, Object>(); messageObject.put("userName", userName); messageObject.put("borrowTitle", borrow.getBorrowTitle()); messageObject.put("repayPeriod", repayDo.getRepayPeriod()); messageObject.put("borrowId", borrow.getId()); messageObject.put("fundMode", fundMode); messageObject.put("webURL", rc.getWebURL()); messageObject.put("lateFI", repayDo.getLateFi()); messageObject.put("fee", repayDo.getRepayFee()); messageObject.put("consultFee", repayDo.getConsultFee()); messageObject.put( "needAmount", NumberUtil.formatDouble(repayDo.getStillInterest() + repayDo.getStillPrincipal() + repayDo.getRepayFee() + repayDo.getConsultFee())); messageObject.put("hasPi", NumberUtil.formatDouble(repayDo.getStillInterest() + repayDo.getStillPrincipal())); return NotifyTemplateUtil.getContentByTemplate(fundrecordRemarkTemplate, messageObject); } catch (Throwable e) { logger.error(e); return ""; } } /** * 构建借款人短信通知的内容 * * @param notifyTemplate * @return * @author: zhangyunhmf * @date: 2014年10月8日下午5:34:56 */ public String buildPubliserSmsContent(RepaymentContext rc, String notifyTemplate) { try { String userName = rc.getUsername(); BorrowDo borrow = rc.getBorrow(); RepaymentDo repayDo = rc.getRepaymentDo(); Map<String, Object> messageObject = new HashMap<String, Object>(); messageObject.put("userName", userName); messageObject.put("borrowTitle", borrow.getBorrowTitle()); messageObject.put("repayPeriod", repayDo.getRepayPeriod()); messageObject.put("needAmount", NumberUtil.formatDouble(repayDo.getStillInterest() + repayDo.getStillPrincipal())); messageObject.put("fee", NumberUtil.formatDouble(repayDo.getRepayFee())); messageObject.put("consultFee", NumberUtil.formatDouble(repayDo.getConsultFee())); return NotifyTemplateUtil.getContentByTemplate(notifyTemplate, messageObject); } catch (Throwable e) { logger.error(e); return ""; } } /** * 插入通知 * * @author: zhangyunhmf * @date: 2014年9月24日上午10:04:58 */ protected void addNotify(String userPhone, String messageContent) { try { SMSNotifyDo msg = new SMSNotifyDo(); msg.setAsync(false); msg.setRecievers(userPhone); msg.setSendFlag("F"); msg.setValidate("T"); msg.setSmsType(SmsType.YOUXUNTONG.name()); msg.setMessageType(MessageType.SMS.name()); msg.setSimpleMessage(messageContent); smsDao.addMessage(msg); } catch (Throwable e) { logger.error(e); } } /** * 更新借款人金额 * * @author: zhangyunhmf * @date: 2014年10月8日下午6:47:41 */ public void updatePublisherAmount(RepaymentContext rc) { // 跟新成功的金额 rc.freshRepaymentAmount(); RepaymentDo repaymentDo = rc.getRepaymentDo(); String userAmountChangeDirect = "-"; FundDo fund = fundDao.getById(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_REPAY); String url = this .buildPublisherFundRecordRemark(rc, RepaymentContext.fundrecord_remark_url, fund.getFundName()); long userId = rc.getUserId(); double pi = repaymentDo.getHasPi(); // 扣除还款金额 本金和利息 userComponent.updateUsableSum(pi, userAmountChangeDirect, userId); FundrecordDo repayFundrecord = new FundrecordDo(); repayFundrecord.setRemarks(url + fund.getFundName() + "[" + pi + "]元"); repayFundrecord.setBorrowId(repaymentDo.getBorrowId()); repayFundrecord.setHandleSum(pi); repayFundrecord.setUserId(userId); repayFundrecord.setFundMode(fund.getFundName()); repayFundrecord.setRepaymentId(repaymentDo.getId()); repayFundrecord.setPaynumber(repaymentDo.getId() + ""); repayFundrecord.setOperateType(new Integer(com.hehenian.biz.common.base.constant.Constants.FEE_CODE_REPAY)); repayFundrecord.setSpending(pi); fundrecordComponent.addFundByRepay(repayFundrecord); // 扣除各种费用 List<RepaymentFeeDo> feeList = repaymentDo.getFeeList(); if (null != feeList) { for (RepaymentFeeDo rf : feeList) { double feeAmount = rf.getHasAmount(); if (feeAmount <= 0) { continue; } userComponent.updateUsableSum(feeAmount, userAmountChangeDirect, userId); fund = fundDao.getById(rf.getFeeCode()); String fundRemark = url + fund.getFundName() + "[" + feeAmount + "]元"; repayFundrecord = new FundrecordDo(); repayFundrecord.setRemarks(fundRemark); repayFundrecord.setBorrowId(repaymentDo.getBorrowId()); repayFundrecord.setHandleSum(feeAmount); repayFundrecord.setUserId(userId); repayFundrecord.setFundMode(fund.getFundName()); repayFundrecord.setRepaymentId(repaymentDo.getId()); repayFundrecord.setPaynumber(repaymentDo.getId() + ""); repayFundrecord.setOperateType(Integer.valueOf(rf.getFeeCode())); repayFundrecord.setSpending(feeAmount); fundrecordComponent.addFundByRepay(repayFundrecord); } } } public void updateInvestorAmount(RepaymentContext rc, long repaymentId, long investId, long borrowId, double recivedPrincipal, double recivedInterest, double recivedFI, double investFee, long investor, int isWebRepay) { double recivedSum = recivedPrincipal + recivedInterest; FundDo fund = fundDao.getById("151"); String fundRemark = this.buildInvestorFundRecordRemark(rc, RepaymentContext.fundrecord_remark_template_invest, fund.getFundName(), recivedSum); // 扣除还款金额 userComponent.updateUsableSum(recivedSum, "+", investor); FundrecordDo repayFundrecord = new FundrecordDo(); repayFundrecord.setRemarks(fundRemark); repayFundrecord.setBorrowId(borrowId); repayFundrecord.setHandleSum(recivedSum); repayFundrecord.setUserId(investor); repayFundrecord.setFundMode(fund.getFundName()); repayFundrecord.setRepaymentId(repaymentId); repayFundrecord.setPaynumber(repaymentId + ""); repayFundrecord.setOperateType(151); repayFundrecord.setIncome(recivedSum); fundrecordComponent.addFundByRepay(repayFundrecord); // 罚息收入 if (isWebRepay == 1) { if (recivedFI > 0) { fund = fundDao.getById("156"); fundRemark = this.buildInvestorFundRecordRemark(rc, RepaymentContext.fundrecord_remark_template_invest, fund.getFundName(), recivedFI); // 扣除还款金额 userComponent.updateUsableSum(recivedFI, "+", investor); FundrecordDo fundrecordFI = new FundrecordDo(); fundrecordFI.setRemarks(fundRemark); fundrecordFI.setBorrowId(borrowId); fundrecordFI.setHandleSum(recivedFI); fundrecordFI.setUserId(investor); fundrecordFI.setFundMode(fund.getFundName()); fundrecordFI.setRepaymentId(repaymentId); fundrecordFI.setPaynumber(repaymentId + ""); fundrecordFI.setOperateType(156); fundrecordFI.setIncome(recivedFI); fundrecordComponent.addFundByRepay(fundrecordFI); } } // 投资人扣除投资管理费 if (investFee > 0) { fund = fundDao.getById("651"); fundRemark = this.buildInvestorFundRecordRemark(rc, RepaymentContext.fundrecord_remark_template_invest, fund.getFundName(), investFee); // 扣除还款金额 userComponent.updateUsableSum(investFee, "-", investor); FundrecordDo fundrecordFee = new FundrecordDo(); fundrecordFee.setRemarks(fundRemark); fundrecordFee.setBorrowId(borrowId); fundrecordFee.setHandleSum(investFee); fundrecordFee.setUserId(investor); fundrecordFee.setFundMode(fund.getFundName()); fundrecordFee.setRepaymentId(repaymentId); fundrecordFee.setPaynumber(repaymentId + ""); fundrecordFee.setOperateType(651); fundrecordFee.setSpending(investFee); fundrecordComponent.addFundByRepay(fundrecordFee); // 投资手续费累加到风险保障金 insertRiskDetail(borrowId, investor, "投资管理费", "收入", investFee, 0); } // 插入短信通知 try { AccountUserDo user = this.userComponent.getById(investor); String smsContent = this.buildInvestorSmsContent(rc, RepaymentContext.sms_invest_template, user.getUsername(), recivedPrincipal, recivedInterest, recivedFI, investFee); PersonDo person = personComponent.getByUserId(investor); String userPhone = person.getCellPhone(); addNotify(userPhone, smsContent); } catch (Exception e) { logger.error("构建短信信息失败"); logger.error(e); } // end 插入短信通知 } /** * 处理代偿:更新担保公司的资金; 并登记风险保障金变动过程 * * @param needAmount * 还款金额 * @param newRiskDetailDo * 风险保障对象 * @author: zhangyunhmf * @date: 2014年9月24日下午4:44:42 */ protected void insertRiskDetail(long borrowId, long userId, String resource, String riskType, double riskInCome, double riskSpending) { RiskDetailDo newRiskDetailDo = new RiskDetailDo(); newRiskDetailDo.setBorrowId(borrowId); newRiskDetailDo.setTrader(userId); newRiskDetailDo.setResource(resource); newRiskDetailDo.setRiskType(riskType); newRiskDetailDo.setRiskInCome(riskInCome); newRiskDetailDo.setRiskSpending(riskSpending); // 偿还给网站累加到风险保障金中 riskDetailComponent.addRiskAndSumBalance(newRiskDetailDo); } /** * 数据和权限检查 * * @author: zhangyunhmf * @return 返回0表示调用成功 * @date: 2014年10月22日上午10:24:03 */ public int doCheck(RepaymentContext rc) { boolean checkResult = false; try { // 获取还款对象 RepaymentDo repaymentDo = this.getRepaymentDo(rc); if (null == repaymentDo) { return 1; } // 检查回款记录 if (null == rc.getInvestList() || rc.getInvestList().size() < 1) { return 8; } // 获取总还款金额 double needSum = repaymentDo.getStillTotalAmount(); checkResult = checkRepaymentAmount(needSum); if (!checkResult) { return 2; } long userId = rc.getUserId(); // 不检查金额了 // checkResult = checkAmount(userId, needSum); // if (!checkResult) { // return 3; // } // 检查状态还款记录 checkResult = checkRepaymentStatus(repaymentDo); if (!checkResult) { return 5; } checkResult = checkUser(rc); if (!checkResult) { return 6; } // 通过还款id获取 标的 BorrowDo borrow = rc.getBorrow(); // 检查还款期数, 如果已还款期数>= 借款期数 表示已经还款完毕 /* * 2015-02-07 集团贷的 deadline 期数不太正确 checkResult = * checkDeadline(borrow.getDeadline(), borrow.getHasDeadline()); if * (!checkResult) { return 7; } */ return 0; } catch (Throwable e) { logger.error("还款失败", e); return 9; } } /** * 还款之前把需要还款的记录状态更新成还款中 * * @return */ public boolean lock(RepaymentDo repaymentDo) { // 更新版本 int repayVersion = repaymentDo.getVersion(); repayVersion = repayVersion + 1; repaymentDo.setVersion(repayVersion); return updateRepayVersion(repayVersion, 3, repaymentDo.getId());// 还款中 } /** * 如果还款过程中失败, 还款状态可能会被处理成 还款中的, 营运将操作不了,所以要解锁 */ public void unLock(RepaymentDo repaymentDo) { // 更新版本 int repayVersion = repaymentDo.getVersion(); repayVersion = repayVersion + 1; repaymentDo.setVersion(repayVersion); repaymentComponent.unLock(repayVersion, 1, repaymentDo.getId()); // 解锁 } /** * * callManagerService 调用汇付 * * @param list * @return OutParameter * @exception * @since 1.0.0 */ public IResult callChinaPnrService(RepaymentContext rc) { // RepaymentContext rc = this.getContext(); String outCustId = this.getOutCustId(rc); String divDetails = ""; // 包装咨询费和手续费json字符 double transAmt = 0; // 投资者应收总额 String inAcctId = ""; String outAcctId = this.getOutAcctId(); List<InvestRepaymentWrap> investList = rc.getInvestList(); // String[][] feeDiv = rc.getFeeDiv(); for (int i = 0, size = investList.size(); i < size; i++) { InvestRepaymentWrap irWrap = investList.get(i); InvestRepaymentDo investRepayDo = irWrap.getInvestRepaymentDO(); transAmt = investRepayDo.getRecivedTotalAmount(); divDetails = irWrap.getDivDetails(this.feeAccountMap); String ordId = String.valueOf(investRepayDo.getId()); String inCustId = String.valueOf(investRepayDo.getOwnerUser().getUsrCustId()); String subOrdId = String.valueOf(investRepayDo.getInvestDo().getSubOrdId()); String subOrdDate = DateUtil.dateToYMD(investRepayDo.getInvestDo().getSubOrdDate()); // 如果该记录已代偿,收款人为担保公司,inCustId为商户子账户 if (investRepayDo.getIsWebRepay() == 2) { inCustId = chinaPnrConfig.getCompCustId(); // 代偿账户汇付ID inAcctId = chinaPnrConfig.getCompAccount(); // 代偿账户 transAmt = investRepayDo.getRecivedPI(); } // 累加罚息 // transAmt = CalculateUtils.add(transAmt, fi); InParameter inParameter = new InParameter(); inParameter.setOrdId(ordId); inParameter.setVersion("20"); inParameter.getParams().put("OutCustId", outCustId);// 出账客户号 inParameter.getParams().put("OutAcctId", outAcctId);// 出账子账户 inParameter.getParams().put("InCustId", inCustId);// 入账客户号 inParameter.getParams().put("InAcctId", inAcctId);// 入账子账户 inParameter.getParams().put("SubOrdId", subOrdId);// 订单号 变长 20 位 // 由商户的系统生成,必须保证唯一。 inParameter.getParams().put("SubOrdDate", subOrdDate);// 关联投标订单流水日期是 inParameter.getParams().put("TransAmt", NumberUtil.formatDouble(transAmt));// 金额 // Fee 扣款手续费, 放款或扣款的手续费 String totalInvestorFee = CalculateUtils.round(irWrap.getFeeSum()); inParameter.getParams().put("Fee", totalInvestorFee); inParameter.getParams().put("DivDetails", divDetails);// 分账账户串 变长 inParameter.getParams().put("MerPriv", "Repayment"); OutParameter outParameter = accountManagerService.repayment(inParameter, AccountType.CHINAPNR); // 保存汇付调用信息 irWrap.setSuccess(outParameter.isSuccess()); if (outParameter.isSuccess()) {// 调用成功更新数据 this.updateInVestor(rc, irWrap); } else { // 调用汇付失败下标号 rc.setCallChinapnrErrorIndex(i); return new ResultSupport<Object>(false, "错误的订单号:" + inParameter.getOrdId() + outParameter.getRespDesc()); } } return new ResultSupport<Object>(true, "调用汇付成功"); } /** * 更新投资人金额 * * @author: zhangyunhmf * @date: 2014年9月24日上午9:58:13 */ public void updateInVestor(RepaymentContext rc, InvestRepaymentWrap irWrap) { RepaymentDo repaymentDo = this.getRepaymentDo(rc); int isWebRepay = repaymentDo.getIsWebRepay(); // 是否代偿 long borrowId = repaymentDo.getBorrowId(); // 标的ID InvestRepaymentDo investDo = irWrap.getInvestRepaymentDO(); double hasfi = irWrap.getFeeByFeeCode(Constants.FEE_CODE_FX); // 判断该还款记录是否被代偿过 // if (2 == isWebRepay) { // // 更新担保公司的资金 // guaranteeInstitutionsComponent.updateOrganMoney(investDo.getRecivedTotalAmount()); // insertRiskDetail(borrowId, rc.getUserId(), "逾期垫付网站收入", "收入", needSum, // 0); // } // 更新投资收款信息 updateInvestRepayment(rc, investDo); // 记录交易费用 repaymentComponent.addRepaymentFee(irWrap.getProportionFeeList()); if (!"COMP_REPAY".equals(rc.getOperationType())) { // 记录已还本金和利息 RepaymentDo newRepaymentDo = new RepaymentDo(); newRepaymentDo.setId(repaymentDo.getId()); newRepaymentDo.setHasFi(hasfi); newRepaymentDo.setHasPi(investDo.getRecivedPI()); repaymentComponent.updateRepaymentHasAmountById(newRepaymentDo); } if (2 != isWebRepay) { // 代偿的时候已经更新过投资记录,所以这里不重复更新 // 更新投资记录还款信息 InvestDo newInvestDo = new InvestDo(); newInvestDo.setId(investDo.getInvestId()); newInvestDo.setHasInterest(investDo.getRecivedInterest()); newInvestDo.setHasPrincipal(investDo.getRecivedPrincipal()); newInvestDo.setHasFI(hasfi); newInvestDo.setManageFee(investDo.getImanageFee()); investComponent.updateHasAmount(newInvestDo); } // 获取owner long investor = investDo.getOwner(); if (2 == isWebRepay) { // 如果代偿修改代偿用户的可用资金 AccountUserDo accountUser = this.userComponent.getUserByCustId(this.chinaPnrConfig.getCompCustId()); if (null != accountUser) { investor = accountUser.getId(); } } // 修改投资人资金收入 updateInvestorAmount(rc, repaymentDo.getId(), investDo.getInvestId(), borrowId, investDo.getRecivedPrincipal(), investDo.getRecivedInterest(), investDo.getRecivedFi(), investDo.getImanageFee(), investor, isWebRepay); } /** * * 更新回款表 , 如果是代偿操作isWebPay = 2 ,并且要加一条新的还款记录表示代偿 * * @param investDo * @author: zhangyunhmf * @date: 2014年10月23日上午10:53:41 */ public void updateInvestRepayment(RepaymentContext rc, InvestRepaymentDo investDo) { InvestRepaymentDo newInvestRepaymentDo = new InvestRepaymentDo(); newInvestRepaymentDo.setInterestOwner(investDo.getOwner()); // 如果是代偿操作这里应该设置成2 newInvestRepaymentDo.setIsWebRepay(investDo.getIsWebRepay()); newInvestRepaymentDo.setRecivedFi(investDo.getRecivedFi()); newInvestRepaymentDo.setOwner(investDo.getOwner()); newInvestRepaymentDo.setInvestId(investDo.getInvestId()); newInvestRepaymentDo.setRepayId(investDo.getRepayId()); newInvestRepaymentDo.setId(investDo.getId()); newInvestRepaymentDo.setRecivedPrincipal(investDo.getRecivedPrincipal()); newInvestRepaymentDo.setRecivedInterest(investDo.getRecivedInterest()); investRepaymentComponent.updateRecievedAmount(newInvestRepaymentDo); } /** * * 更改数据库的相关记录的金额 * * @author: zhangyunhmf * @return 0 表示调用成功 * @date: 2014年9月28日下午3:55:30 */ public int updateStatus(RepaymentContext rc) { RepaymentDo repaymentDo = rc.getRepaymentDo(); // 更新还款状态 updateRepaymentStatus(rc); // 更新担保公司 // updateGuarantee(rc); // start 更新借款人的可用资金 // 更新投资状态 updateInvestStatus(repaymentDo.getBorrowId()); // 更新标的的状态, 和还款期数 updateBorrow(repaymentDo.getBorrowId()); return 0; } /** * 更新投资状态 * * @author: zhangyunhmf * @date: 2014年10月23日上午11:35:26 */ public void updateInvestStatus(long borrowId) { investComponent.updateRepayStatusByBorrowId(borrowId); } /** * 更新风险保障金 * * @author: zhangyunhmf * @date: 2014年10月23日上午11:29:56 */ protected void updateGuarantee(RepaymentContext rc) { // TODO Auto-generated method stub } }