功能说明
自动投标功能是P2P产品的业务扩展功能,根据用户定制的多个删选项,进行自动投标的功能。此模块包括两个功能:自动投标参数设置、查询自动投标交易。
用户可调节的参数包括:投标的金额(只输入一个数字),招标的金额(可输入范围)、利率范围(可输入范围)、借款期限(可选择范围)、标的种类(可选择多个)。
自动投标规则:
1、自动投标是VIP会员可以使用的功能。
2、每个用户一次只能定义一条投标规则。
3、用户设定的投标的金额大于余额,在发生自动投标的时候,将只投可用余额。
4、用户的余额足够,这时设定的投标金额如果小于标所剩的金额,将按照设定的金额投标;如果大于标所剩的金额,将只投标剩下的金额。
5、项目发布后系统根据用户设定的自动投标规则进行投标。
6、在标还未招满时,用户可随时撤回自动投的标。
自动投标排名计算:
1、首先按照用户所发生的自动投标次数排序,次数少的排在前面。
2、如果自动投标次数相同,按照用户上次自动投标的时间排序,时间较早的排在前面。
3、如果用户上次自动投标的时间相同,按照注册时间排序,注册时间较早的排在前面。
4、用户每发生一次自动投标,不论这个标最后是流标还是正常放款,都算作一次自动投标,都对用户在自动投标里的排名发生影响。
5、自动投标排名是实时统计的,每当有用户触发了自动投标,排名就会发生变化。
自动投标流程图:
代码实例如下:
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void autoInvest(String loanId) {
System.out.println("开启调度");
log.info("开启自动投标调度"+loanId);
boolean isOpenAutoInvest = false;
try {
String isOpenStr = configService
.getConfigValue(ConfigConstants.AutoInvest.IS_OPEN);
if (isOpenStr.equals("1")) {
isOpenAutoInvest = true;
log.info("检测是否开启自动投标功能:开启!");
}else{
log.info("检测是否开启自动投标功能:未开启!");
}
} catch (ObjectNotFoundException onfe) {
// 如果找不到该config
isOpenAutoInvest = false;
}
if (!isOpenAutoInvest) {
log.info("未开启!自动投标结束!");
return;
}
Loan loan = ht.get(Loan.class, loanId);
// FIXME:loan为空 验证
// FIXME:得判断loan的类型,起码竞标借款,肯定不能自动投标
if (loan.getType().equals(LoanConstants.LoanType.BIDDING_LOAN)) {
log.info("借款类型为竞标借款,关闭自动投标!");
return;
}
// 自动投标开始时间
Integer delayTime = Integer.parseInt(configService
.getConfigValue(ConfigConstants.AutoInvest.DELAY_TIME));
// 如果借款满足自动投标的设定条件
// 遍历所有自动投标用户
List<AutoInvest> ais = ht
.find("from AutoInvest ai where ai.status = '"
+ InvestConstants.AutoInvest.Status.ON
+ "' order by ai.lastAutoInvestTime");
log.info("符合自动投标人数:"+ais.size());
for (int i = 0; i < ais.size(); i++) {
Double endPercent = Double.parseDouble(configService
.getConfigValue(ConfigConstants.AutoInvest.END_PERCENT));
log.info("自动投标结束百分比:"+endPercent);
double rcPercent;
try {
rcPercent = loanService.calculateRaiseCompletedRate(loan.getId());
log.info("自动投标完成百分比:"+rcPercent);
} catch (NoMatchingObjectsException e1) {
throw new RuntimeException(e1);
}
// 距离到达募集上限的金额( (结束百分比-已经募集的百分比)/100*借款总金额 )
Double remainRaisingMoney = ArithUtil.mul(
ArithUtil.div(ArithUtil.sub(endPercent, rcPercent), 100.0),
loan.getMoney());
log.info("自动投标剩余金额:"+remainRaisingMoney);
AutoInvest ai = ais.get(i);
log.info("投标人数队列角标"+i);
// 取得分最高的,进行投标
// 判断此借款是否满足此人设置的投标条件(风险等级之类)
Double balance=userBillBO.getBalance(ai.getUserId());
if(balance==null||ai==null){
log.info("金额或投资数据为空:"+balance+"|"+ai);
continue;
}
if(ai.getRemainMoney()==null){
ai.setRemainMoney(0.0);
}
if (ai.getInvestMoney()==null) {
ai.setInvestMoney(0.0);
}
if (ai.getMinRate()==null) {
ai.setMinRate(0.01);
}
if (ai.getMaxRate()==null) {
ai.setMaxRate(0.5);
}
if (
// // 用户余额-保留余额>=用户每次投标金额
//
balance - ai.getRemainMoney() >= ai.getInvestMoney()
&& ai.getMaxRate() >= loan.getRate()
&& ai.getMinRate() <= loan.getRate()
// 自动投标不能投自己的项目
&& ai.getUser().getId() != loan.getUser().getId()
) {
log.info("自动投标:"+ai.getUser().getId()+"用户满足条件准备投标");
Double tbmoney; //自动投标金额
if(ai.getIsAutoMoney()!=null&&ai.getIsAutoMoney()==1){
tbmoney=new Double(ArithUtil.convertsToInt(balance));
if(balance>remainRaisingMoney){
tbmoney=remainRaisingMoney;
log.info("如果是自动全额投标当前投标账户余额大于剩余金额,投标金额等于账户余额");
}
}else if(ai.getInvestMoney() > remainRaisingMoney){
continue;
}else{
log.info("投标金额为限定额度投标");
tbmoney=ai.getInvestMoney();
}
log.info("自动投标:投标金额"+tbmoney+"元");
//用户的自动投标金额为50元的整数倍
if (tbmoney%50!=0) {
Double yu=tbmoney%50;
tbmoney=ArithUtil.sub(tbmoney, yu);
}
double booMoney=0.0;
if (booMoney==tbmoney) {
System.out.println("账户没钱了"+tbmoney);
continue;
}
// 投标对象数据保存
Invest invest = new Invest();
invest.setIsAutoInvest(true);
invest.setLoan(loan);
invest.setMoney(tbmoney);
invest.setUser(ai.getUser());
try {
log.info("自动投标:准备保存invest数据");
investService.create(invest);
invest.setStatus(InvestConstants.InvestStatus.WAIT_AFFIRM);
log.info("自动投标:准备修改invest数据");
ht.saveOrUpdate(invest);
// log.info("自动投标:修改invest数据完成,准备创建第三方投标订单");
// this.createInvestOrder(invest, FacesContext.getCurrentInstance());
// log.info("自动投标:成功!");
} catch (ExceedMoneyNeedRaised e) {
e.printStackTrace();
continue;
} catch (InsufficientBalance e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ExceedMaxAcceptableRate e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
// 放到自动投标队列的队尾
ai.setLastAutoInvestTime(new Date());
ht.update(ai);
}
String hql = "from Invest where loan.id = '" + loan.getId()
+ "' and isAutoInvest='1'";
List<Invest> sendAutoList = ht.find(hql);
// System.out.println(aisAdd.size()+"=====需要发送的数量:"+sendAutoList.size());
if (sendAutoList.size() > 0) {
Invest inv = new Invest();
for (int i = 0; i < sendAutoList.size(); i++) {
inv = sendAutoList.get(i);
this.createInvestOrder(inv,FacesContext.getCurrentInstance());//createInvestOrder创建订单方法设计保密信息暂时不公开
smsService.send("尊敬的会员:您有一笔充值已成功,金额为"+inv.getMoney()+" xxx",inv.getUser().getMobileNumber());
log.info("自动投标:成功!"+inv.getUser().getUsername());
}
}
System.out.println("已经发送成功~");
// } else {
// throw new RuntimeException("autoInvestRule setting occur an error");
// }
}
产品经理Luke
互联网产品负责人/Leader
-----------------------------------------------------