Commit 2137f928 authored by zhengjian's avatar zhengjian

Merge remote-tracking branch 'origin/zj-niwodai' into zj-niwodai

parents aaa3d448 88cc84b5
...@@ -71,20 +71,21 @@ public class ConsumerConfig implements RabbitListenerConfigurer { ...@@ -71,20 +71,21 @@ public class ConsumerConfig implements RabbitListenerConfigurer {
JSONObject jo = JSONObject.parseObject(ms); JSONObject jo = JSONObject.parseObject(ms);
String noticeType = jo.getString("noticeType"); String noticeType = jo.getString("noticeType");
if(FundingResult.REJECT.getCode().equals(noticeType) if(FundingResult.REJECT.getCode().equals(noticeType)
// || FundingResult.HANG_UP.getCode().equals(noticeType) || FundingResult.HANG_UP.getCode().equals(noticeType)
|| FundingResult.CANCEL_LOAN.getCode().equals(noticeType) || FundingResult.CANCEL_LOAN.getCode().equals(noticeType)
|| FundingResult.FUAD_ASSIGN_SUCC.getCode().equals(noticeType)){ || FundingResult.FUAD_ASSIGN_SUCC.getCode().equals(noticeType)){
log.info("助贷资金路由有效MQ消息接收, 消息内容 : {} ",ms); log.info("资金路由有效MQ消息接收, 消息内容 : {} ",ms);
String applyNo = jo.getJSONObject("data").getString("applyNo"); String applyNo = jo.getJSONObject("data").getString("applyNo");
String nextOperateDate = getNextOperateDate(jo, noticeType);
iAidFundRouteRecordService.fundingResultNotity(applyNo,FundingResult.fromCode(noticeType)); iAidFundRouteRecordService.fundingResultNotity(applyNo,FundingResult.fromCode(noticeType));
distributeService.receiveFundingResult(applyNo, FundingResult.fromCode(noticeType)); distributeService.receiveFundingResult(applyNo, FundingResult.fromCode(noticeType), nextOperateDate);
log.info("助贷资金路由有效MQ消息处理结束, bizNo : {} ,noticeType : {} , 耗时 : {} ",applyNo,noticeType,stopwatch.stop().elapsed(TimeUnit.MILLISECONDS)); log.info("资金路由有效MQ消息处理结束, bizNo : {} ,noticeType : {} , 耗时 : {} ",applyNo,noticeType,stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
} }
// 采用手动应答模式, 手动确认应答更为安全稳定 // 采用手动应答模式, 手动确认应答更为安全稳定
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true); channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}catch(IOException e){ }catch(IOException e){
log.error("助贷资金路由结果消息处理异常,消息 : {} ",ms,e); log.error("资金路由结果消息处理异常,消息 : {} ",ms,e);
//害怕队列堵住 暂放开 //害怕队列堵住 暂放开
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true); channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
...@@ -95,9 +96,21 @@ public class ConsumerConfig implements RabbitListenerConfigurer { ...@@ -95,9 +96,21 @@ public class ConsumerConfig implements RabbitListenerConfigurer {
} }
/**
* 获取下次可操作之间, 只有拒绝才有
* @param jo
* @return
*/
private String getNextOperateDate(JSONObject jo, String noticeType) {
try {
if (FundingResult.REJECT.getCode().equals(noticeType)) {
return jo.getJSONObject("extraData").getString("nextOperateDate");
}
return null;
} catch (Exception e) {
log.error("资金路由结果消息解析下次可操作时间异常!", e);
return null;
}
}
} }
package com.quantgroup.asset.distribution.constant;
/**
* @author : Hyuk
* @description : RuleConstants
* @date : 2020/3/5 4:57 下午
*/
public class RuleConstants {
public static final String CONDITION = "conditions";
public static final String OPERATOR = "operator";
public static final String AND = "and";
public static final String OR = "or";
public static final String KEY = "key";
public static final String VAL = "value";
public static final String DEC_TABLE_RESULT = "result";
public static final String DEC_TABLE_ELSE = "else";
}
...@@ -12,6 +12,7 @@ import com.google.common.base.Stopwatch; ...@@ -12,6 +12,7 @@ import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.constant.FundModuleConstants; import com.quantgroup.asset.distribution.constant.FundModuleConstants;
import com.quantgroup.asset.distribution.enums.response.FundModuleResponse; import com.quantgroup.asset.distribution.enums.response.FundModuleResponse;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleService; import com.quantgroup.asset.distribution.service.funding.IFundModuleService;
import com.quantgroup.asset.distribution.util.fund.module.ChannelFundConfigUtil; import com.quantgroup.asset.distribution.util.fund.module.ChannelFundConfigUtil;
...@@ -42,13 +43,76 @@ public class FundModuleController { ...@@ -42,13 +43,76 @@ public class FundModuleController {
public GlobalResponse getAllLimitInfo() { public GlobalResponse getAllLimitInfo() {
Stopwatch stopwatch = Stopwatch.createStarted(); Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.getAllLimitType(); GlobalResponse response = fundModuleService.getAllLimitType();
log.info("资方模块接口, 获取所有条件限制类型完成, 耗时 : {}, response : {}", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), response); log.info("资方模块接口, 获取所有条件限制类型完成, 耗时 : {}, response : {}", stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response; return response;
} }
@RequestMapping("save_channel_funds_config") @RequestMapping("save_channel_funds_config")
public GlobalResponse saveChannelFundsConfig(Integer type, Long id, String bizChannel, String funds, String remarks) { public GlobalResponse saveChannelFundsConfig(Integer type, Long id, String bizChannel, String funds, String remarks,
log.info("资方模块接口, 新增或修改资方配置开始, type : {}, id : {}, bizChannel : {}, funds : {}, remarks : {}", type, id, bizChannel, funds, remarks); String auditor, String proposer) {
return saveChannelFundsConfigCommon(type, id, bizChannel, funds, remarks, auditor, proposer, 1);
}
@RequestMapping("/get_channel_fund_configs")
public GlobalResponse getChannelFundConfigs(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
return getChannelFundsConfigCommon(bizChannel, fundId, pageNum, pageSize, 1);
}
@RequestMapping("/get_audit_infos")
public GlobalResponse getAuditInfos(String targetName, Integer auditStatus, Integer auditType, Integer auditTarget, String applyStartTime, String applyEndTime, String user, Integer pageNum, Integer pageSize) {
log.info("资方模块接口, 获取审批列表开始, targetName : {}, auditStatus : {}, auditType : {}, auditTarget : {}, applyStartTime : {}, applyEndTime : {}, user : {}, pageNum : {}, pageSize : {}", targetName, auditStatus, auditType, auditTarget, applyStartTime, applyEndTime, user, pageNum, pageSize);
if (pageNum == null || pageSize == null) {
return GlobalResponse.create(FundModuleResponse.PAGEING_CONDITIONS_IS_EMPTY);
}
if (StringUtils.isEmpty(user)) {
return GlobalResponse.create(FundModuleResponse.USER_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.getAuditInfos(targetName, auditStatus, auditType, auditTarget, applyStartTime, applyEndTime, user, pageNum, pageSize);
log.info("资方模块接口, 获取审批列表结束, targetName : {}, auditStatus : {}, auditType : {}, auditTarget : {}, applyStartTime : {}, applyEndTime : {}, user : {}, pageNum : {}, pageSize : {}, 耗时 : {}, response : {}", targetName, auditStatus, auditType, auditTarget, applyStartTime, applyEndTime, user, pageNum, pageSize, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response;
}
@RequestMapping("/find_channel_fund_config")
public GlobalResponse findChannelFundConfig(Long configId) {
return findChannelFundConfigCommon(configId, 1);
}
@RequestMapping("/audit")
public GlobalResponse audit(Long id, Integer auditStatus) {
log.info("资方模块接口,审批执行开始, id : {}, auditStatus : {}", id, auditStatus);
if (id == null) {
return GlobalResponse.create(FundModuleResponse.ID_IS_EMPTY);
}
if (auditStatus == null) {
return GlobalResponse.create(FundModuleResponse.AUDIT_STATUS_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.audit(id, auditStatus);
log.info("资方模块接口,审批执行开始, id : {}, auditStatus : {}, 耗时 : {}, response : {}", id, auditStatus, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response;
}
@RequestMapping("/save_channel_funds_config_new")
public GlobalResponse saveChannelFundsConfigNew(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer) {
return saveChannelFundsConfigCommon(type, id, bizChannel, funds, remarks, auditor, proposer, 2);
}
@RequestMapping("/get_channel_fund_configs_new")
public GlobalResponse getChannelFundConfigsNew(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
return getChannelFundsConfigCommon(bizChannel, fundId, pageNum, pageSize, 2);
}
@RequestMapping("/find_channel_fund_config_new")
public GlobalResponse findChannelFundConfigNew(Long configId) {
return findChannelFundConfigCommon(configId, 2);
}
private GlobalResponse saveChannelFundsConfigCommon(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer, int oldOrNew) {
log.info("资方模块接口, 新增或修改资方配置开始, type : {}, id : {}, bizChannel : {}, funds : {}, remarks : {}, auditor : {}, proposer : {}", type, id, bizChannel, funds, remarks, auditor, proposer);
// 参数校验 // 参数校验
if (type == null) { if (type == null) {
return GlobalResponse.create(FundModuleResponse.TYPE_IS_EMPTY); return GlobalResponse.create(FundModuleResponse.TYPE_IS_EMPTY);
...@@ -68,21 +132,54 @@ public class FundModuleController { ...@@ -68,21 +132,54 @@ public class FundModuleController {
if (!ChannelFundConfigUtil.checkFunds(funds)) { if (!ChannelFundConfigUtil.checkFunds(funds)) {
return GlobalResponse.create(FundModuleResponse.FUNDS_INFO_ERROR); return GlobalResponse.create(FundModuleResponse.FUNDS_INFO_ERROR);
} }
if (StringUtils.isEmpty(auditor) || StringUtils.isEmpty(proposer)) {
return GlobalResponse.create(FundModuleResponse.AUDITOR_OR_PROPOSER_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted(); Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.saveChannelFundConfig(type, id, bizChannel, funds, remarks); GlobalResponse response = null;
log.info("资方模块接口, 新增或修改资方配置结束, type : {}, id : {}, bizChannel : {}, funds : {}, remarks : {}, 耗时 : {}, reponse : {}", type, id, bizChannel, funds, remarks, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), response); if (oldOrNew == 1) {
// 老接口
response = fundModuleService.saveChannelFundConfig(type, id, bizChannel, funds, remarks, auditor, proposer);
} else {
// 新接口
response = fundModuleService.saveChannelFundConfigNew(type, id, bizChannel, funds, remarks, auditor, proposer);
}
log.info("资方模块接口, 新增或修改资方配置结束, type : {}, id : {}, bizChannel : {}, funds : {}, remarks : {}, auditor : {}, proposer : {}, 耗时 : {}, reponse : {}", type, id, bizChannel, funds, remarks, auditor, proposer, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response; return response;
} }
@RequestMapping("/get_channel_fund_configs") private GlobalResponse getChannelFundsConfigCommon(String bizChannel, Long fundId, Integer pageNum, Integer pageSize, int oldOrNew) {
public GlobalResponse getChannelFundConfigs(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
log.info("资方模块接口, 查询渠道资方配置信息开始, bizChannel : {}, fundId : {}, pageNum : {}, pageSize : {}", bizChannel, fundId, pageNum, pageSize); log.info("资方模块接口, 查询渠道资方配置信息开始, bizChannel : {}, fundId : {}, pageNum : {}, pageSize : {}", bizChannel, fundId, pageNum, pageSize);
if (pageNum == null || pageSize == null) { if (pageNum == null || pageSize == null) {
return GlobalResponse.create(FundModuleResponse.PAGEING_CONDITIONS_IS_EMPTY); return GlobalResponse.create(FundModuleResponse.PAGEING_CONDITIONS_IS_EMPTY);
} }
Stopwatch stopwatch = Stopwatch.createStarted(); Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.getChannelFundConfigs(bizChannel, fundId, pageNum, pageSize); GlobalResponse response = null;
log.info("资方模块接口, 查询渠道资方配置信息结束, bizChannel : {}, fundId : {}, pageNum : {}, pageSize : {}, 耗时 : {}, response : {}", bizChannel, fundId, pageNum, pageSize, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), response); if (oldOrNew == 1) {
// 老接口
response = fundModuleService.getChannelFundConfigs(bizChannel, fundId, pageNum, pageSize);
} else {
response = fundModuleService.getChannelFundConfigsNew(bizChannel, fundId, pageNum, pageSize);
}
log.info("资方模块接口, 查询渠道资方配置信息结束, bizChannel : {}, fundId : {}, pageNum : {}, pageSize : {}, 耗时 : {}, response : {}", bizChannel, fundId, pageNum, pageSize, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response;
}
private GlobalResponse findChannelFundConfigCommon(Long configId, int oldOrNew) {
log.info("资方模块接口,根据id获取资方配置, configId : {}", configId);
if (configId == null) {
return GlobalResponse.create(FundModuleResponse.ID_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = null;
if (oldOrNew == 1) {
// 老接口
response = fundModuleService.findChannelFundConfigById(configId);
} else {
response = fundModuleService.findChannelFundConfigNewById(configId);
}
log.info("资方模块接口, 根据id获取资方配置, configId : {} 耗时 : {}, response : {}", configId, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response; return response;
} }
} }
...@@ -5,6 +5,7 @@ import com.quantgroup.asset.distribution.model.response.GlobalResponse; ...@@ -5,6 +5,7 @@ import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService; import com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService;
import com.quantgroup.asset.distribution.service.authority.IAuthorityService; import com.quantgroup.asset.distribution.service.authority.IAuthorityService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleLimitTypeService;
import com.quantgroup.asset.distribution.service.redis.IRedisService; import com.quantgroup.asset.distribution.service.redis.IRedisService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -22,7 +23,7 @@ public class RedisFlushController { ...@@ -22,7 +23,7 @@ public class RedisFlushController {
private static String authKey="3ruhhdf9924hrodnfjkasdhf8209"; private final static String authKey="3ruhhdf9924hrodnfjkasdhf8209";
@Autowired @Autowired
...@@ -33,6 +34,8 @@ public class RedisFlushController { ...@@ -33,6 +34,8 @@ public class RedisFlushController {
private IAuthorityService authorityService; private IAuthorityService authorityService;
@Autowired @Autowired
private IAssetDistributeRuleConfigService assetDistributeRuleConfigService; private IAssetDistributeRuleConfigService assetDistributeRuleConfigService;
@Autowired
private IFundModuleLimitTypeService limitTypeService;
/** /**
* 助贷资金池刷新 * 助贷资金池刷新
...@@ -54,7 +57,7 @@ public class RedisFlushController { ...@@ -54,7 +57,7 @@ public class RedisFlushController {
@RequestMapping("/authority_flush") @RequestMapping("/authority_flush")
public GlobalResponse authorityFlush(String key, String authKey, String authPass) { public GlobalResponse authorityFlush(String key, String authKey, String authPass) {
if(authKey.equals(key)) { authorityService.clearCacheByAuthKeyAndAuthPass(authKey, authPass); } if(this.authKey.equals(key)) { authorityService.clearCacheByAuthKeyAndAuthPass(authKey, authPass); }
return GlobalResponse.success(); return GlobalResponse.success();
} }
...@@ -63,4 +66,10 @@ public class RedisFlushController { ...@@ -63,4 +66,10 @@ public class RedisFlushController {
if(authKey.equals(key)) { assetDistributeRuleConfigService.clearRuleConfigCache(); } if(authKey.equals(key)) { assetDistributeRuleConfigService.clearRuleConfigCache(); }
return GlobalResponse.success(); return GlobalResponse.success();
} }
@RequestMapping("/limit_type_flush")
public GlobalResponse limitTypeFlush(String key) {
if(authKey.equals(key)) { limitTypeService.clearCache(); }
return GlobalResponse.success();
}
} }
package com.quantgroup.asset.distribution.enums;
import lombok.Getter;
public enum ExecuteType {
TEST(0, "测试"),
ONLINE(1, "线上");
@Getter
private int code;
@Getter
private String description;
ExecuteType(int code, String description) {
this.code = code;
this.description = description;
}
}
package com.quantgroup.asset.distribution.enums;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
/**
* @author : Hyuk
* @description : RuleOperator
* @date : 2020/3/5 5:08 下午
*/
@Slf4j
public enum RuleOperator {
GreaterThan(">", "大于"),
GreaterThanOrEqual(">=", "大于"),
LessThan("<", "小于"),
Equal("=", "等于"),
In("in", "包含"),
NotIn("exclude", "不包含"),
NotEqual("!=", "不等于"),
LessThanOrEqual("<=", "小于");
private String code;
private String description;
RuleOperator(String code, String description) {
this.code = code;
this.description = description;
}
public static RuleOperator fromCode(String code) {
QGPreconditions.checkArgument(StringUtils.isNoneBlank(code), QGExceptionType.COMMON_STRING_PARAM_IS_ALL_NULL, "操作");
for (RuleOperator ruleOperator : RuleOperator.values()) {
if (StringUtils.equalsAnyIgnoreCase(code, ruleOperator.code)) {
return ruleOperator;
}
}
log.error("枚举不存在,code={}", code);
throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM);
}
}
package com.quantgroup.asset.distribution.enums;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@Slf4j
public enum UnionType {
And("and", "而且"), Or("or", "或者");
private String code;
private String description;
UnionType(String code, String description) {
this.code = code;
this.description = description;
}
public static UnionType fromCode(String code) {
QGPreconditions.checkArgument(StringUtils.isNoneBlank(code), QGExceptionType.COMMON_STRING_PARAM_IS_ALL_NULL, "条件组类型");
for (UnionType unionType : UnionType.values()) {
if (StringUtils.equalsAnyIgnoreCase(code, unionType.code)) {
return unionType;
}
}
log.error("枚举不存在, code = {}", code);
throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM);
}
}
package com.quantgroup.asset.distribution.enums.funding;
import java.util.HashSet;
import java.util.Set;
import lombok.Getter;
/**
* 审批状态枚举
* @author liwenbin
*
*/
public enum AuditStatusEnum {
WAIT(0, "待处理"),
PASS(1, "审批通过"),
REJECT(2, "审批拒绝"),
BACK(3, "撤销");
@Getter
private int code;
@Getter
private String title;
private static final Set<Integer> codeSet = new HashSet<>();
static {
for (AuditStatusEnum auditStatus : AuditStatusEnum.values()) {
codeSet.add(auditStatus.getCode());
}
}
AuditStatusEnum(int code, String title) {
this.code = code;
this.title = title;
}
public static boolean containsCode(int code) {
if (codeSet.contains(code)) {
return true;
} else {
return false;
}
}
}
package com.quantgroup.asset.distribution.enums.funding;
import lombok.Getter;
/**
* 审批对象枚举
* @author liwenbin
*
*/
public enum AuditTargetEnum {
FUND_CONFIG(1, "资金方配置");
@Getter
private int code;
@Getter
private String title;
AuditTargetEnum(int code, String title) {
this.code = code;
this.title = title;
}
}
package com.quantgroup.asset.distribution.enums.funding;
import lombok.Getter;
/**
* 申请类型枚举
* @author liwenbin
*
*/
public enum AuditTypeEnum {
ONLINE(1, "上线");
@Getter
private int code;
@Getter
private String title;
AuditTypeEnum(int code, String title) {
this.code = code;
this.title = title;
}
}
...@@ -19,7 +19,12 @@ public enum FundModuleResponse implements GlobalResponseEnum{ ...@@ -19,7 +19,12 @@ public enum FundModuleResponse implements GlobalResponseEnum{
CHANNEL_FUND_CONFIG_IS_EXIST(4007, "渠道资方配置已存在, 添加失败!"), CHANNEL_FUND_CONFIG_IS_EXIST(4007, "渠道资方配置已存在, 添加失败!"),
CHANNEL_FUND_CONFIG_NOT_EXIST(4008, "渠道资方配置修改失败, id不存在!"), CHANNEL_FUND_CONFIG_NOT_EXIST(4008, "渠道资方配置修改失败, id不存在!"),
PAGEING_CONDITIONS_IS_EMPTY(4009, "分页条件不能为空"), PAGEING_CONDITIONS_IS_EMPTY(4009, "分页条件不能为空"),
HAS_NO_DATA(4010, "未找到数据"); HAS_NO_DATA(4010, "未找到数据"),
AUDITOR_OR_PROPOSER_IS_EMPTY(4011, "申请人或审批人为空, 请检查!"),
USER_IS_EMPTY(4012, "用户信息为空"),
AUDIT_STATUS_IS_EMPTY(4013, "审批状态为空!"),
UKNOW_AUDIT_STATUS(4014, "未知的审批状态"),
CHANNEL_FUND_CONFIG_IS_AUDITING(4015, "该渠道资方配置正在审核中,不允许进行操作!");
@Getter @Getter
private int code; private int code;
......
...@@ -20,6 +20,7 @@ public enum QGExceptionType { ...@@ -20,6 +20,7 @@ public enum QGExceptionType {
COMMON_ILLEGAL_PARAM(1010, "参数异常"), COMMON_ILLEGAL_PARAM(1010, "参数异常"),
COMMON_THIRD_PARTY_TIMEOUT(1011, "第三方服务超时"), COMMON_THIRD_PARTY_TIMEOUT(1011, "第三方服务超时"),
COMMON_ENUM_NOT_EXIST(1012,"枚举不存在"), COMMON_ENUM_NOT_EXIST(1012,"枚举不存在"),
COMMON_STRING_PARAM_IS_ALL_NULL(1013, "参数不能为空", "%s不能为空"),
ASSET_IN_CODE_ERROR(2001, "资产入库code异常! uuid : %s, bizNo : %s, code : %s"), ASSET_IN_CODE_ERROR(2001, "资产入库code异常! uuid : %s, bizNo : %s, code : %s"),
GET_DEC_ATTRIBUTE_VALUE_ERROR(2002, "获取决策资产属性值异常, uuid : %s, keys : %s"), GET_DEC_ATTRIBUTE_VALUE_ERROR(2002, "获取决策资产属性值异常, uuid : %s, keys : %s"),
...@@ -32,6 +33,16 @@ public enum QGExceptionType { ...@@ -32,6 +33,16 @@ public enum QGExceptionType {
RULE_CALC_UNKNOW_RESULT(2024, "规则判断出现未知结果,请联系管理人员, expression : %s"), RULE_CALC_UNKNOW_RESULT(2024, "规则判断出现未知结果,请联系管理人员, expression : %s"),
UNKNOW_RULE_TYPE(2025, "未知的规则类型, %s"), UNKNOW_RULE_TYPE(2025, "未知的规则类型, %s"),
NO_DISTRIBUTE_NODE(2026, "未找到分发节点, uuid : %s, assetNo %s, records : %s"), NO_DISTRIBUTE_NODE(2026, "未找到分发节点, uuid : %s, assetNo %s, records : %s"),
RULE_EXPRESSION_IS_EMPTY(2027, "规则表达式未空"),
RULE_IS_NOT_JSON(2028, "规则不是json,解析失败"),
RULE_UNION_OPERATOR_NOT_EXIST(2029, "联合规则符不存在"),
DATA_NOT_EXIST_FOR_RULE(2030, "规则数据不存在,key:%s, operator:%s, value:%s"),
RULE_OPERATOR_IS_EMPTY(2031, "规则符为空"),
RULE_DATA_IS_EMPTY(2032, "规则数据为空,key:%s, operator:%s, value:%s"),
DATA_COMPARE_ERROR(2033, "数据比较出现错误"),
RULE_OPERATOR_NOT_EXIST(2034, "规则符不存在"),
CRATE_RULE_VO_ERROR(2035, "规则格式无法形成规则对象"),
NOTIFY_FUND_SERVER_ERROR(2041, "通知资金系统失败, uuid : %s, bizNo : %s, assetNo : %s"), NOTIFY_FUND_SERVER_ERROR(2041, "通知资金系统失败, uuid : %s, bizNo : %s, assetNo : %s"),
NOT_FOUND_FUND_SERVER_RESULT_BIZNO(2042, "未找到资金结果通知订单, bizNo : %s, status : %s"), NOT_FOUND_FUND_SERVER_RESULT_BIZNO(2042, "未找到资金结果通知订单, bizNo : %s, status : %s"),
...@@ -41,7 +52,9 @@ public enum QGExceptionType { ...@@ -41,7 +52,9 @@ public enum QGExceptionType {
GET_ALL_FUNDS_INFO_ERROR(3001, "拉取所有资方信息失败, res : %s"), GET_ALL_FUNDS_INFO_ERROR(3001, "拉取所有资方信息失败, res : %s"),
NO_FUND_INFO_BEEN_HIT(3002, "未命中任何资方, bizChannel : %s, amount : %s, term : %s"), NO_FUND_INFO_BEEN_HIT(3002, "未命中任何资方, bizChannel : %s, amount : %s, term : %s"),
FUND_PRIORITY_IS_ERROR(3003, "资方优先级不符合要求, bizChannel : %s, amount : %s, term : %s"), FUND_PRIORITY_IS_ERROR(3003, "资方优先级不符合要求, bizChannel : %s, amount : %s, term : %s"),
NOT_FOUNT_CHANNEL_FUNDS_INFO(3004, "未找到渠道资方配置, 请检查; bizChannel : %s"); NOT_FOUNT_CHANNEL_FUNDS_INFO(3004, "未找到渠道资方配置, 请检查; bizChannel : %s"),
CHANNEL_FUND_CONFIG_GREATER_THAN_TOW(3005, "渠道资方有效配置大于2条,请检查; bizChannel : % s"),
HIT_FUND_BUT_AMOUNT_OR_TERM_IS_EMPTY(3006, "命中资方但额度或期数为空, 请检查!");
......
package com.quantgroup.asset.distribution.model.entity.fund;
import lombok.Data;
import java.io.Serializable;
/**
* @author : Hyuk
* @description : ChannelFundConfigNew
* @date : 2020/3/5 3:49 下午
*/
@Data
public class ChannelFundConfigNew implements Serializable {
private static final long serialVersionUID = 1L;
private Integer fundId;
private Integer fundProductId;
private String fundName;
private String attentions;
private Limits limits;
private String rate;
private Integer feeType;
private Integer rateType;
private Integer priority;
@Data
public static class Limits implements Serializable{
private static final long serialVersionUID = 1L;
private String limitDetail;
private String limitTranslate;
}
}
...@@ -49,6 +49,10 @@ public class AssetForm implements Serializable{ ...@@ -49,6 +49,10 @@ public class AssetForm implements Serializable{
private int repeatCount = 0; private int repeatCount = 0;
private String refuseReason;
private String sceneId;
public Asset transToAsset() { public Asset transToAsset() {
Asset asset = new Asset(); Asset asset = new Asset();
asset.setAssetNo(this.assetNo); asset.setAssetNo(this.assetNo);
...@@ -75,6 +79,8 @@ public class AssetForm implements Serializable{ ...@@ -75,6 +79,8 @@ public class AssetForm implements Serializable{
notifyMap.put("bizType", this.bizType); notifyMap.put("bizType", this.bizType);
notifyMap.put("auditResult", this.auditResult); notifyMap.put("auditResult", this.auditResult);
notifyMap.put("amount", this.amount); notifyMap.put("amount", this.amount);
notifyMap.put("term", this.term);
notifyMap.put("sceneId",sceneId);
notifyMap.put("deadLine", this.deadLine); notifyMap.put("deadLine", this.deadLine);
notifyMap.put("exData", this.exData); notifyMap.put("exData", this.exData);
notifyMap.put("otherInformation", this.otherInformation); notifyMap.put("otherInformation", this.otherInformation);
......
package com.quantgroup.asset.distribution.service.approval;
import java.util.Map;
import com.quantgroup.asset.distribution.enums.funding.AuditTargetEnum;
import com.quantgroup.asset.distribution.enums.funding.AuditTypeEnum;
import com.quantgroup.asset.distribution.service.jpa.entity.ApprovalLog;
/**
*
* @author liwenbin
*
*/
public interface IApprovalLogService {
/**
* 创建审批记录
* @param auditType
* @param auditTarget
* @param targetName
* @param proposer
* @param auditor
* @param preConfigId
* @param auditConfigId
*/
public void createApprovalLog(AuditTypeEnum auditType, AuditTargetEnum auditTarget, String targetName,
String proposer, String auditor, Long preConfigId, Long auditConfigId);
/**
* 获取审批记录
* @param targetName
* @param auditStatus
* @param auditType
* @param auditTarget
* @param applyStartTime
* @param applyEndTime
* @param user
* @param pageNum
* @param pageSize
* @return
*/
public Map<String, Object> getApprovalLogs(String targetName, Integer auditStatus, Integer auditType, Integer auditTarget,
String applyStartTime, String applyEndTime, String user, Integer pageNum, Integer pageSize);
/**
* 审批接口
* @param id 审批记录id
* @param auditStatus
*/
public void audit(ApprovalLog approvalLog, Integer auditStatus);
/**
* 根据id获取审批记录
* @param id
* @return
*/
public ApprovalLog findById(Long id);
/**
* 查询渠道配置是否正在审批
* @param bizChannel
* @return
*/
public Boolean isAuditing(String bizChannel);
}
package com.quantgroup.asset.distribution.service.approval.impl;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Order;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.quantgroup.asset.distribution.enums.funding.AuditStatusEnum;
import com.quantgroup.asset.distribution.enums.funding.AuditTargetEnum;
import com.quantgroup.asset.distribution.enums.funding.AuditTypeEnum;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService;
import com.quantgroup.asset.distribution.service.jpa.entity.ApprovalLog;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.repository.IApprovalLogRepository;
import com.quantgroup.asset.distribution.util.DateUtil;
@Service
public class ApprovalLogServiceImpl implements IApprovalLogService{
@Autowired
private IApprovalLogRepository approvalLogRepository;
@Autowired
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Override
public void createApprovalLog(AuditTypeEnum auditType, AuditTargetEnum auditTarget, String targetName,
String proposer, String auditor, Long preConfigId, Long auditConfigId) {
ApprovalLog approvalLog = new ApprovalLog();
approvalLog.setAuditType(auditType.getCode());
approvalLog.setAuditTarget(auditTarget.getCode());
approvalLog.setTargetName(targetName);
approvalLog.setProposer(proposer);
approvalLog.setApplyTime(new Timestamp(System.currentTimeMillis()));
approvalLog.setAuditor(auditor);
approvalLog.setAuditStatus(AuditStatusEnum.WAIT.getCode());
approvalLog.setPreConfigId(preConfigId);
approvalLog.setAuditConfigId(auditConfigId);
approvalLog.setEnable(true);
approvalLogRepository.save(approvalLog);
}
@Override
public Map<String, Object> getApprovalLogs(String targetName, Integer auditStatus, Integer auditType,
Integer auditTarget, String applyStartTime, String applyEndTime, String user, Integer pageNum,
Integer pageSize) {
// 分页条件
Pageable pageable = new PageRequest(pageNum < 0 ? 0 : pageNum, pageSize);
Specification<ApprovalLog> specification = new Specification<ApprovalLog>() {
@Override
public Predicate toPredicate(Root<ApprovalLog> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicatesAnd = new ArrayList<>();
List<Predicate> predicatesOr = new ArrayList<>();
predicatesAnd.add(cb.equal(root.get("enable"), true));
if(auditStatus != null){
predicatesAnd.add(cb.equal(root.get("auditStatus"), auditStatus));
}
if(auditType != null){
predicatesAnd.add(cb.equal(root.get("auditType"), auditType));
}
if(auditTarget != null){
predicatesAnd.add(cb.equal(root.get("auditTarget"), auditTarget));
}
if(StringUtils.isNotEmpty(applyStartTime)){
predicatesAnd.add(cb.greaterThanOrEqualTo(root.get("applyTime").as(Timestamp.class), Timestamp.valueOf(applyStartTime)));
}
if(StringUtils.isNotEmpty(applyEndTime)){
predicatesAnd.add(cb.lessThan(root.get("applyTime").as(Timestamp.class), Timestamp.valueOf(applyEndTime)));
}
if(StringUtils.isNotEmpty(targetName)){
predicatesAnd.add(cb.like(root.get("targetName"), "%" + targetName + "%"));
}
if (StringUtils.isNotEmpty(user)) {
predicatesOr.add(cb.equal(root.get("proposer"), user));
predicatesOr.add(cb.equal(root.get("auditor"), user));
}
List<Order> orderList = new ArrayList<>();
orderList.add(cb.asc(root.get("auditStatus")));
return query.where(cb.and(predicatesAnd.toArray(new Predicate[predicatesAnd.size()])), cb.or(predicatesOr.toArray(new Predicate[predicatesOr.size()])))
.orderBy(orderList).getRestriction();
}
};
Page<ApprovalLog> channelFundConfigs = approvalLogRepository.findAll(specification, pageable);
Map<String, Object> result = new HashMap<>();
result.put("total", channelFundConfigs.getTotalElements());
result.put("pages", channelFundConfigs.getTotalPages());
result.put("pageSize", channelFundConfigs.getSize());
result.put("pageNum", channelFundConfigs.getNumber());
result.put("list", channelFundConfigs.getContent());
return result;
}
@Transactional(rollbackFor=Exception.class)
@Override
public void audit(ApprovalLog approvalLog, Integer auditStatus) {
if (auditStatus == AuditStatusEnum.PASS.getCode()) {
// 先更改审核记录, 这里返回的是新配置
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.auditPassConfig(approvalLog.getPreConfigId(), approvalLog.getAuditConfigId());
// 根据新配置清楚渠道缓存
fundModuleChannelFundConfigNewService.clearChannelFundConfigCache(config.getBizChannel());
}
updateApprovalLogAuditStatus(approvalLog, auditStatus);
}
@Override
public ApprovalLog findById(Long id) {
return approvalLogRepository.findByIdAndEnableIsTrue(id);
}
/**
* 更改审批记录状态和审批时间
* @param approvalLog
* @param auditStatus
*/
private void updateApprovalLogAuditStatus(ApprovalLog approvalLog, Integer auditStatus) {
approvalLog.setAuditTime(DateUtil.getCurDateTime());
approvalLog.setAuditStatus(auditStatus);
approvalLogRepository.save(approvalLog);
}
@Override
public Boolean isAuditing(String bizChannel) {
return approvalLogRepository.findByAuditTypeAndAuditTargetAndTargetNameAndAuditStatusAndEnableIsTrue(AuditTypeEnum.ONLINE.getCode(),
AuditTargetEnum.FUND_CONFIG.getCode(), bizChannel, AuditStatusEnum.WAIT.getCode()) != null;
}
}
package com.quantgroup.asset.distribution.service.asset.impl; package com.quantgroup.asset.distribution.service.asset.impl;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
...@@ -20,8 +8,6 @@ import com.quantgroup.asset.distribution.config.annotation.Attribute; ...@@ -20,8 +8,6 @@ import com.quantgroup.asset.distribution.config.annotation.Attribute;
import com.quantgroup.asset.distribution.enums.response.AssetResponse; import com.quantgroup.asset.distribution.enums.response.AssetResponse;
import com.quantgroup.asset.distribution.exception.QGException; import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType; import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfig;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.alarm.IAlarmService; import com.quantgroup.asset.distribution.service.alarm.IAlarmService;
...@@ -30,14 +16,19 @@ import com.quantgroup.asset.distribution.service.asset.IAssetAttributeService; ...@@ -30,14 +16,19 @@ import com.quantgroup.asset.distribution.service.asset.IAssetAttributeService;
import com.quantgroup.asset.distribution.service.asset.IAssetService; import com.quantgroup.asset.distribution.service.asset.IAssetService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService;
import com.quantgroup.asset.distribution.service.distribute.IDistributeFailLogService; import com.quantgroup.asset.distribution.service.distribute.IDistributeFailLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset; import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig; import com.quantgroup.asset.distribution.service.jpa.entity.AssetAttributeExtendConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.product.IFinanceProductHitLogService;
import com.quantgroup.asset.distribution.service.rule.IRuleService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* 资产Service * 资产Service
...@@ -58,12 +49,6 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -58,12 +49,6 @@ public class AssetServiceImpl implements IAssetService{
private IAlarmService alarmService; private IAlarmService alarmService;
@Autowired @Autowired
private IDistributeFailLogService distributeFailLogService; private IDistributeFailLogService distributeFailLogService;
@Autowired
private IFundModuleChannelFundConfigService fundModuleCHannelFundConfigService;
@Autowired
private IRuleService ruleService;
@Autowired
private IFinanceProductHitLogService financeProductHitLogService;
@Async @Async
...@@ -81,8 +66,6 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -81,8 +66,6 @@ public class AssetServiceImpl implements IAssetService{
assetAttributeService.saveAssetAttrubite(asset, assetAttributeExtendConfigList, data); assetAttributeService.saveAssetAttrubite(asset, assetAttributeExtendConfigList, data);
// 把资产基础属性值放入data // 把资产基础属性值放入data
data = addAssetAttributeToData(asset, data); data = addAssetAttributeToData(asset, data);
// 如果使用资方模块则去命中资方,创建金融产品集
hitFundIfUseFundModule(assetForm, data);
// 资产分发 // 资产分发
assetDistributeService.distribute(assetForm, asset, data); assetDistributeService.distribute(assetForm, asset, data);
log.info("资产分发完成, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, 耗时 : {}", assetForm.getUuid(), log.info("资产分发完成, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, 耗时 : {}", assetForm.getUuid(),
...@@ -207,92 +190,4 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -207,92 +190,4 @@ public class AssetServiceImpl implements IAssetService{
return sb.toString(); return sb.toString();
} }
/**
* 如果使用资方模块,需要去命中资方
* @param assetForm
*/
public void hitFundIfUseFundModule(AssetForm assetForm, Map<String, Object> data) {
if ("false".equals(assetForm.getAuditResult())) {
return;
}
// 如果auditResult为true, amount或term有一个为空, 那就不管是否是测试,都不能使用资方模块了
if ("true".equals(assetForm.getAuditResult()) && (StringUtils.isEmpty(assetForm.getAmount()) || StringUtils.isEmpty(assetForm.getTerm()))) {
return;
}
// 创建金融产品集,并初始化金额期数
JSONArray financeProductArray = new JSONArray();
JSONObject amountJSON = new JSONObject();
financeProductArray.add(amountJSON);
amountJSON.put("min", assetForm.getAmount());
amountJSON.put("max", assetForm.getAmount());
JSONArray termArray = new JSONArray();
amountJSON.put("terms", termArray);
JSONObject termJSON = new JSONObject();
termArray.add(termJSON);
try {
// 不能是string,否则资方那边会报错
termJSON.put("term", Integer.parseInt(assetForm.getTerm()));
} catch (Exception e) {
termJSON.put("term", Double.parseDouble(assetForm.getTerm()));
}
JSONArray fundArray = new JSONArray();
termJSON.put("fundInfo", fundArray);
FundModuleChannelFundConfig config = fundModuleCHannelFundConfigService.findByBizChannel(assetForm.getBizChannel());
QGPreconditions.checkArgument(config != null, QGExceptionType.NOT_FOUNT_CHANNEL_FUNDS_INFO, assetForm.getBizChannel());
List<ChannelFundConfig> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfig.class);
A : for (ChannelFundConfig channelFundConfig : fundConfigList) {
List<ChannelFundConfig.Limit> limits = channelFundConfig.getLimits();
if (CollectionUtils.isNotEmpty(limits)) {
for (ChannelFundConfig.Limit limit : limits) {
String expression = limit.getLimit();
if (!ruleService.valid(expression, data)) {
continue A;
}
}
}
log.info("资方模块用户命中资方条件, uuid : {}, assetNo : {}, bizNo : {}, fundId : {}, fundProductId : {}",
assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizNo(), channelFundConfig.getFundId(), channelFundConfig.getFundProductId());
// 创建并增加资方配置
JSONObject fundInfoJSON = new JSONObject();
fundInfoJSON.put("fundId", channelFundConfig.getFundId());
fundInfoJSON.put("fundProductId", channelFundConfig.getFundProductId());
fundInfoJSON.put("priority", channelFundConfig.getPriority());
fundInfoJSON.put("feeType", channelFundConfig.getFeeType());
fundInfoJSON.put("rateType", channelFundConfig.getRateType());
fundInfoJSON.put("rate", channelFundConfig.getRate());
fundArray.add(fundInfoJSON);
}
// 如果fundArray为空,未命中任何一个资方
QGPreconditions.checkArgument(fundArray.size() != 0, QGExceptionType.NO_FUND_INFO_BEEN_HIT, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
// 看命中优先级是否符合要求
boolean[] bucket = new boolean[fundArray.size() + 1];
for (int i = 0, len = fundArray.size(); i < len; i++) {
int priority = fundArray.getJSONObject(i).getIntValue("priority");
if (!(priority > 0 && priority <= len)) {
throw new QGException(QGExceptionType.FUND_PRIORITY_IS_ERROR, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
}
if (bucket[priority]) {
// 多个相同的优先级
throw new QGException(QGExceptionType.FUND_PRIORITY_IS_ERROR, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
}
bucket[priority] = true;
}
String hitFinanceProduct = JSON.toJSONString(financeProductArray);
log.info("资方模块组成金融产品集完成, uuid : {}, assetNo : {}, bizNo : {}, financeProduct : {}", assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizNo(), hitFinanceProduct);
// 如果金融产品集为空, 那就用hit的, 保证流程不会出错,并且没有比较
if (StringUtils.isEmpty(assetForm.getFinanceProducts())) {
// 装填金融产品集并返回
assetForm.setFinanceProducts(hitFinanceProduct);
} else {
String oldFinanceProduct = assetForm.getFinanceProducts();
// 原金融产品集不为空,如果不是测试,直接返回
if (config.getType() == 1) {
// 线上需要使用
assetForm.setFinanceProducts(hitFinanceProduct);
}
financeProductHitLogService.saveLog(assetForm, oldFinanceProduct, hitFinanceProduct);
}
}
} }
...@@ -27,5 +27,5 @@ public interface IAssetDistributeService { ...@@ -27,5 +27,5 @@ public interface IAssetDistributeService {
* @param bizNo * @param bizNo
* @param fundingResult * @param fundingResult
*/ */
public void receiveFundingResult(String bizNo, FundingResult fundingResult); public void receiveFundingResult(String bizNo, FundingResult fundingResult, String nextOperateDate);
} }
...@@ -5,6 +5,7 @@ import java.util.List; ...@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -34,6 +35,8 @@ public class AssetDistributeRecordServiceImpl implements IAssetDistributeRecordS ...@@ -34,6 +35,8 @@ public class AssetDistributeRecordServiceImpl implements IAssetDistributeRecordS
private IAssetDistributeRecordRepository assetDistributeRecordRepository; private IAssetDistributeRecordRepository assetDistributeRecordRepository;
@Autowired @Autowired
private IRedisService<Integer> redisService; private IRedisService<Integer> redisService;
@Value("${isDebug}")
private Boolean isDebug;
/** /**
* 不能改成异步,防止save的时候record被清空 * 不能改成异步,防止save的时候record被清空
...@@ -71,6 +74,7 @@ public class AssetDistributeRecordServiceImpl implements IAssetDistributeRecordS ...@@ -71,6 +74,7 @@ public class AssetDistributeRecordServiceImpl implements IAssetDistributeRecordS
public void updateAssetDistributeStatus(String bizNo, int status) { public void updateAssetDistributeStatus(String bizNo, int status) {
AssetDistributeRecord assetDistributeRecord = assetDistributeRecordRepository.findByBizNoOrderByCreatedAtDescLimitOne(bizNo); AssetDistributeRecord assetDistributeRecord = assetDistributeRecordRepository.findByBizNoOrderByCreatedAtDescLimitOne(bizNo);
if (assetDistributeRecord == null) { if (assetDistributeRecord == null) {
if (isDebug) { return; }
log.info("资产分发记录更改状态未找到订单, bizNo : {}, status : {}", bizNo, status); log.info("资产分发记录更改状态未找到订单, bizNo : {}, status : {}", bizNo, status);
throw new QGException(QGExceptionType.NOT_FOUND_FUND_SERVER_RESULT_BIZNO, bizNo, status); throw new QGException(QGExceptionType.NOT_FOUND_FUND_SERVER_RESULT_BIZNO, bizNo, status);
} else { } else {
......
package com.quantgroup.asset.distribution.service.distribute.impl; package com.quantgroup.asset.distribution.service.distribute.impl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
...@@ -20,10 +7,13 @@ import com.google.common.base.Stopwatch; ...@@ -20,10 +7,13 @@ import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.constant.DistributeConstants; import com.quantgroup.asset.distribution.constant.DistributeConstants;
import com.quantgroup.asset.distribution.constant.RedisKeyConstants; import com.quantgroup.asset.distribution.constant.RedisKeyConstants;
import com.quantgroup.asset.distribution.constant.StatusConstants; import com.quantgroup.asset.distribution.constant.StatusConstants;
import com.quantgroup.asset.distribution.enums.ExecuteType;
import com.quantgroup.asset.distribution.enums.funding.FundingResult; import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.exception.QGException; import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType; import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.entity.DistributeRecord; import com.quantgroup.asset.distribution.model.entity.DistributeRecord;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.alarm.IAlarmService; import com.quantgroup.asset.distribution.service.alarm.IAlarmService;
...@@ -31,14 +21,27 @@ import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeReco ...@@ -31,14 +21,27 @@ import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeReco
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRuleConfigService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService;
import com.quantgroup.asset.distribution.service.funding.IAidFundRouteService; import com.quantgroup.asset.distribution.service.funding.IAidFundRouteService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset; import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord; import com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRecord;
import com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig; import com.quantgroup.asset.distribution.service.jpa.entity.AssetDistributeRuleConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.notify.INotifyService; import com.quantgroup.asset.distribution.service.notify.INotifyService;
import com.quantgroup.asset.distribution.service.product.IFinanceProductHitLogService;
import com.quantgroup.asset.distribution.service.redis.IRedisService; import com.quantgroup.asset.distribution.service.redis.IRedisService;
import com.quantgroup.asset.distribution.service.rule.IRuleService; import com.quantgroup.asset.distribution.service.rule.IRuleService;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* 资产分发Service * 资产分发Service
...@@ -59,8 +62,6 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -59,8 +62,6 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
@Autowired @Autowired
private IRedisService<Integer> redisService; private IRedisService<Integer> redisService;
@Autowired @Autowired
private IRuleService ruleService;
@Autowired
private IAidFundRouteService aidFundRouteService; private IAidFundRouteService aidFundRouteService;
@Autowired @Autowired
private INotifyService notifyService; private INotifyService notifyService;
...@@ -68,6 +69,14 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -68,6 +69,14 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
private IAssetDistributeRecordService assetDistributeRecordService; private IAssetDistributeRecordService assetDistributeRecordService;
@Autowired @Autowired
private IAlarmService alarmService; private IAlarmService alarmService;
@Autowired
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Autowired
private IRuleService ruleService;
@Autowired
private IFinanceProductHitLogService financeProductHitLogService;
private static final ExecutorService executorPool = Executors.newFixedThreadPool(4);
/** /**
* 分发 * 分发
...@@ -126,14 +135,26 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -126,14 +135,26 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
try { try {
switch (ruleType) { switch (ruleType) {
case DistributeConstants.RuleType.FUND_ROUTE: case DistributeConstants.RuleType.FUND_ROUTE:
// 资方配置空跑
doTestExecute(JSON.parseObject(JSON.toJSONString(assetForm), AssetForm.class), data);
// 如果使用资方模块则去命中资方,创建金融产品集
String hitFinanceProduct = hitFundIfUseFundModule(assetForm, data, ExecuteType.ONLINE);
// 资方模块结果处理
checkFundResult(assetForm, hitFinanceProduct);
if(StringUtils.isNotEmpty(hitFinanceProduct)) {
notifyService.notifyFundServer(assetForm, data); notifyService.notifyFundServer(assetForm, data);
return StatusConstants.WAIT; return StatusConstants.WAIT;
}
return StatusConstants.FAIL;
case DistributeConstants.RuleType.AID_FUND_ROUTE: { case DistributeConstants.RuleType.AID_FUND_ROUTE: {
GlobalResponse response = aidFundRouteService.aidFundRoute(assetForm, asset.getUserLoanType(), data); GlobalResponse response = aidFundRouteService.aidFundRoute(assetForm, asset.getUserLoanType(), data);
int status = response.getCode() == 0 ? StatusConstants.SUCCESS : StatusConstants.FAIL; int status = response.getCode() == 0 ? StatusConstants.SUCCESS : StatusConstants.FAIL;
//助贷资金路由 分配失败没有 mq消息 成功有
if(status==0){
// 助贷资金路由目前不从mq里接受终态 // 助贷资金路由目前不从mq里接受终态
assetDistributeRecord.setAssetDistributeStatus(status); assetDistributeRecord.setAssetDistributeStatus(status);
assetDistributeRecordService.updateAssetDistribute(assetDistributeRecord); assetDistributeRecordService.updateAssetDistribute(assetDistributeRecord);
}
return status; return status;
} }
case DistributeConstants.RuleType.DIVERSION: case DistributeConstants.RuleType.DIVERSION:
...@@ -206,13 +227,13 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -206,13 +227,13 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
* 接收fundingResult消息 * 接收fundingResult消息
*/ */
@Override @Override
public void receiveFundingResult(String bizNo, FundingResult fundingResult) { public void receiveFundingResult(String bizNo, FundingResult fundingResult, String nextOperateDate) {
try { try {
Stopwatch stopwatch = Stopwatch.createStarted(); Stopwatch stopwatch = Stopwatch.createStarted();
// 1、更改分配记录状态 // 1、更改分配记录状态
assetDistributeRecordService.updateAssetDistributeStatus(bizNo, fundingResult == FundingResult.FUAD_ASSIGN_SUCC ? StatusConstants.SUCCESS : StatusConstants.FAIL); assetDistributeRecordService.updateAssetDistributeStatus(bizNo, fundingResult == FundingResult.FUAD_ASSIGN_SUCC ? StatusConstants.SUCCESS : StatusConstants.FAIL);
// 2、通知业务流系统 // 2、通知业务流系统
notifyService.notifyBusinessFlow(bizNo, fundingResult == FundingResult.FUAD_ASSIGN_SUCC ? StatusConstants.SUCCESS : StatusConstants.FAIL); notifyService.notifyBusinessFlow(bizNo, fundingResult, nextOperateDate);
// 3、重新进行分发, 目前还没有,等接了助贷资金路由以后再增加 // 3、重新进行分发, 目前还没有,等接了助贷资金路由以后再增加
log.info("资产分发接收资金结果处理结束, bizNo : {}, fundingResult : {}, 耗时 : {}", bizNo, fundingResult.getCode(), stopwatch.stop().elapsed(TimeUnit.MILLISECONDS)); log.info("资产分发接收资金结果处理结束, bizNo : {}, fundingResult : {}, 耗时 : {}", bizNo, fundingResult.getCode(), stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
} catch (QGException qe) { } catch (QGException qe) {
...@@ -225,4 +246,196 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -225,4 +246,196 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
" , 错误信息 : 未知错误"); " , 错误信息 : 未知错误");
} }
} }
/**
* 如果使用资方模块,需要去命中资方
* @param assetForm
*/
public String hitFundIfUseFundModule(AssetForm assetForm, Map<String, Object> data, ExecuteType executeType) {
// 如果auditResult为true, amount或term有一个为空, 那就不管是否是测试,都不能使用资方模块了
// 同时兼容量子魔方白名单,白名单的没有期数直接返回
if ("true".equals(assetForm.getAuditResult()) && (StringUtils.isEmpty(assetForm.getAmount()) || StringUtils.isEmpty(assetForm.getTerm()))) {
return null;
}
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findByBizChannel(assetForm.getBizChannel());
// 未找到资方渠道配置直接通知
if (config == null) {
return null;
}
JSONArray fundArray = new JSONArray();
// 资方去重, 可能存在多条件同一个资方
Set<String> fundSet = new HashSet<>();
List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
A : for (ChannelFundConfigNew channelFundConfig : fundConfigList) {
IRuleVO ruleVO = ruleService.getIRuleVo(channelFundConfig.getLimits());
if (ruleVO == null) { throw new QGException(QGExceptionType.CRATE_RULE_VO_ERROR); }
// 如果参数为空,直接不满足
Set<String> params = ruleVO.getParamNames();
for (String key : params) {
if (!data.containsKey(key)) {
continue A;
}
}
if (!ruleVO.valid(data)) {
continue A;
}
// 是否配了审核条件
boolean hasAuditResultLimit = params.contains("audit_result");
if (!hasAuditResultLimit) {
// 如果没配,自动过一层auditResult@true的条件
if (!ruleService.valid("audit_result==true", data)) {
continue A;
}
}
String key = channelFundConfig.getFundId() + "_" + channelFundConfig.getFundProductId() + "_" + channelFundConfig.getPriority();
if (!fundSet.contains(key)) {
// 创建并增加资方配置
JSONObject fundInfoJSON = new JSONObject();
fundInfoJSON.put("fundId", channelFundConfig.getFundId());
fundInfoJSON.put("fundProductId", channelFundConfig.getFundProductId());
fundInfoJSON.put("priority", channelFundConfig.getPriority());
fundInfoJSON.put("feeType", channelFundConfig.getFeeType());
fundInfoJSON.put("rateType", channelFundConfig.getRateType());
fundInfoJSON.put("rate", channelFundConfig.getRate());
fundArray.add(fundInfoJSON);
log.info("资方模块用户命中资方条件, uuid : {}, assetNo : {}, bizNo : {}, bizChannel : {}, fundId : {}, fundProductId : {}",
assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizNo(), assetForm.getBizChannel(), channelFundConfig.getFundId(), channelFundConfig.getFundProductId());
fundSet.add(key);
}
}
// 如果审核拒绝,也没命中任何资方, 直接返回
if ("false".equals(assetForm.getAuditResult()) && fundArray.size() == 0) {
return null;
}
QGPreconditions.checkArgument(fundArray.size() != 0, QGExceptionType.NO_FUND_INFO_BEEN_HIT, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
// 看命中优先级是否符合要求
boolean[] bucket = new boolean[fundArray.size() + 1];
for (int i = 0, len = fundArray.size(); i < len; i++) {
int priority = fundArray.getJSONObject(i).getIntValue("priority");
if (!(priority > 0 && priority <= len)) {
throw new QGException(QGExceptionType.FUND_PRIORITY_IS_ERROR, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
}
if (bucket[priority]) {
// 多个相同的优先级
throw new QGException(QGExceptionType.FUND_PRIORITY_IS_ERROR, assetForm.getBizChannel(), assetForm.getAmount(), assetForm.getTerm());
}
bucket[priority] = true;
}
String hitFinanceProduct = createFinancePro(assetForm, fundArray);
log.info("资方模块组成金融产品集完成, uuid : {}, assetNo : {}, bizNo : {}, bizChannel : {}, financeProduct : {}, executeType : {}", assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizNo(), assetForm.getBizChannel(), hitFinanceProduct, executeType.name());
return hitFinanceProduct;
}
/**
* 资方模块命中后结果处理
* @param assetForm
* @param hitFinanceProduct
* @return
*/
private AssetForm checkFundResult(AssetForm assetForm, String hitFinanceProduct) {
if (hitFinanceProduct == null) {
if ("false".equals(assetForm.getAuditResult())) {
// 把传过来的额度和期数处理为null
assetForm.setAmount(null);
assetForm.setTerm(null);
}
return assetForm;
}
// 金融产品集替换
String oldFinanceProduct = assetForm.getFinanceProducts();
assetForm.setFinanceProducts(hitFinanceProduct);
// 审核结果替换
String oldAuditResult = assetForm.getAuditResult();
if ("false".equals(oldAuditResult)) {
assetForm.setAuditResult("true");
}
// 保存日志
financeProductHitLogService.saveLog(assetForm, oldFinanceProduct, hitFinanceProduct, oldAuditResult, assetForm.getAuditResult(), ExecuteType.ONLINE);
log.info("资方命中后,审核最终结果, assetForm : {}", JSON.toJSONString(assetForm));
return assetForm;
}
/**
* 组建金融产品集
* @param assetForm
* @param fundArray
* @return
*/
private String createFinancePro(AssetForm assetForm, JSONArray fundArray) {
// 首先判断是否有额度期数
QGPreconditions.checkArgument(StringUtils.isNotEmpty(assetForm.getAmount()) && StringUtils.isNotEmpty(assetForm.getTerm()), QGExceptionType.HIT_FUND_BUT_AMOUNT_OR_TERM_IS_EMPTY);
JSONArray financeProductArray = new JSONArray();
JSONObject amountJSON = new JSONObject();
financeProductArray.add(amountJSON);
amountJSON.put("min", assetForm.getAmount());
amountJSON.put("max", assetForm.getAmount());
JSONArray termArray = new JSONArray();
amountJSON.put("terms", termArray);
JSONObject termJSON = new JSONObject();
termArray.add(termJSON);
try {
// 不能是string,否则资方那边会报错
termJSON.put("term", Integer.parseInt(assetForm.getTerm()));
} catch (Exception e) {
termJSON.put("term", Double.parseDouble(assetForm.getTerm()));
}
termJSON.put("fundInfo", fundArray);
return JSON.toJSONString(financeProductArray);
}
/**
* 资方配置空跑
* @param assetForm
* @param data
*/
private void doTestExecute(AssetForm assetForm, Map<String, Object> data) {
executorPool.execute(() -> {
try {
assetForm.setBizChannel("88888_" + assetForm.getBizChannel());
String hitFundPro = hitFundIfUseFundModule(assetForm, data, ExecuteType.TEST);
if (hitFundPro != null) {
// 如果命中了记录一下,并且如果审核状态为false改为true
String oldFundPro = assetForm.getFinanceProducts();
String oldAuditResult = assetForm.getAuditResult();
assetForm.setFinanceProducts(hitFundPro);
assetForm.setAuditResult("true");
financeProductHitLogService.saveLog(assetForm, oldFundPro, hitFundPro, oldAuditResult, assetForm.getAuditResult(), ExecuteType.TEST);
} else {
// 如果没命中,且审核结果未false
if ("false".equals(assetForm.getAuditResult())) {
// 把传过来的额度和期数处理为null
assetForm.setAmount(null);
assetForm.setTerm(null);
}
}
log.info("空跑审核最终结果, assetForm : {}", JSON.toJSONString(assetForm));
} catch (QGException qe) {
log.error("资方配置执行空跑出现错误 : {}, uuid : {}, bizChannel : {}, bizType : {}, bizNo : {}, assetNo : {} ",
qe.qgExceptionType.code + "->" + qe.detail, assetForm.getUuid(),
assetForm.getBizChannel(), assetForm.getBizType(),
assetForm.getBizNo(), assetForm.getAssetNo());
alarmService.dingtalkAlarm("Warn", "资方配置执行空跑出现错误", "bizChannel : " + assetForm.getBizChannel()
+ " , bizType : " + assetForm.getBizType() + " , bizNo : " + assetForm.getBizNo()
+ " , assetNo : " + assetForm.getAssetNo() + " , uuid : " + assetForm.getUuid()
+ " , 错误信息 : " + qe.qgExceptionType.code + "->" + qe.detail);
} catch (Exception ex) {
log.error("资方配置执行空跑出现异常, uuid : {}, bizChannel : {}, bizType : {}, bizNo : {}, assetNo : {} ", assetForm.getUuid(),
assetForm.getBizChannel(), assetForm.getBizType(),
assetForm.getBizNo(), assetForm.getAssetNo(), ex);
alarmService.dingtalkAlarm("Warn", "资方配置执行空跑出现异常", "bizChannel : " + assetForm.getBizChannel()
+ " , bizType : " + assetForm.getBizType() + " , bizNo : " + assetForm.getBizNo()
+ " , assetNo : " + assetForm.getAssetNo() + " , uuid : " + assetForm.getUuid()
+ " , 错误信息 : 未知错误.");
}
});
}
} }
package com.quantgroup.asset.distribution.service.funding;
import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import java.util.Map;
/**
* @author : Hyuk
* @description : IFundModuleChannelFundConfigNewService
* @date : 2020/2/26 5:31 下午
*/
public interface IFundModuleChannelFundConfigNewService {
public Map<String, Object> getChannelFundConfigsByChannelOrFundId(String bizChannel, Long fundId, Integer pageNum, Integer pageSize);
public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks, String proposer, String auditor);
public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks, String proposer, String auditor);
public FundModuleChannelFundConfigNew findByBizChannel(String bizChannel);
public FundModuleChannelFundConfigNew findById(Long id);
public FundModuleChannelFundConfigNew auditPassConfig(Long preId, Long auditId);
public void clearChannelFundConfigCache(String bizChannel);
}
...@@ -14,9 +14,15 @@ public interface IFundModuleChannelFundConfigService { ...@@ -14,9 +14,15 @@ public interface IFundModuleChannelFundConfigService {
public Map<String, Object> getChannelFundConfigsByChannelOrFundId(String bizChannel, Long fundId, Integer pageNum, Integer pageSize); public Map<String, Object> getChannelFundConfigsByChannelOrFundId(String bizChannel, Long fundId, Integer pageNum, Integer pageSize);
public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks); public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks, String proposer, String auditor);
public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks); public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks, String proposer, String auditor);
public FundModuleChannelFundConfig findByBizChannel(String bizChannel); public FundModuleChannelFundConfig findByBizChannel(String bizChannel);
public FundModuleChannelFundConfig findById(Long id);
public FundModuleChannelFundConfig auditPassConfig(Long preId, Long auditId);
public void clearChannelFundConfigCache(String bizChannel);
} }
...@@ -25,7 +25,22 @@ public interface IFundModuleService { ...@@ -25,7 +25,22 @@ public interface IFundModuleService {
* 保存或更改渠道资方配置 * 保存或更改渠道资方配置
* @return * @return
*/ */
public GlobalResponse saveChannelFundConfig(Integer type, Long id, String bizChannel, String funds, String remarks); public GlobalResponse saveChannelFundConfig(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer);
/**
* 保存或更改渠道资方配置(新)
* @param type
* @param id
* @param bizChannel
* @param funds
* @param remarks
* @param auditor
* @param proposer
* @return
*/
public GlobalResponse saveChannelFundConfigNew(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer);
/** /**
* 获取渠道资方配置信息 * 获取渠道资方配置信息
...@@ -36,4 +51,52 @@ public interface IFundModuleService { ...@@ -36,4 +51,52 @@ public interface IFundModuleService {
* @return * @return
*/ */
public GlobalResponse getChannelFundConfigs(String bizChannel, Long fundId, Integer pageNum, Integer pageSize); public GlobalResponse getChannelFundConfigs(String bizChannel, Long fundId, Integer pageNum, Integer pageSize);
/**
* 获取渠道资方配置信息(新)
* @param bizChannel
* @param fundId
* @param pageNum
* @param pageSize
* @return
*/
public GlobalResponse getChannelFundConfigsNew(String bizChannel, Long fundId, Integer pageNum, Integer pageSize);
/**
* 获取审批列表
* @param targetName
* @param auditStatus
* @param auditType
* @param auditTarget
* @param applyStartTime
* @param applyEndTime
* @param user
* @param pageNum
* @param pageSize
* @return
*/
public GlobalResponse getAuditInfos(String targetName, Integer auditStatus, Integer auditType, Integer auditTarget, String applyStartTime, String applyEndTime, String user, Integer pageNum, Integer pageSize);
/**
* 根据Id获取资方配置
* @param configId
* @return
*/
public GlobalResponse findChannelFundConfigById(Long configId);
/**
* 根据id获取资方配置(新)
* @param configId
* @return
*/
public GlobalResponse findChannelFundConfigNewById(Long configId);
/**
* 审批接口
* @param id 审理log id
* @param auditStatus
* @return
*/
public GlobalResponse audit(Long id, Integer auditStatus);
} }
...@@ -110,7 +110,7 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService { ...@@ -110,7 +110,7 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
//通知资方 //通知资方
Map<String,String> response = iHttpService.postHasResponse(assetForm.getCallbackUrl(), assetForm.transToNotifyMap(data)); Map<String,String> response = iHttpService.postHasResponse(assetForm.getCallbackUrl(), assetForm.transToNotifyMap(data));
log.info("助贷资金路由-通知资金系统结束,response :{}, uuid : {} , bizNo : {} , callbackUrl:{},params:{}", JSON.toJSONString(response),assetForm.getUuid(),assetForm.getBizNo(),assetForm.getCallbackUrl(), JSON.toJSONString(assetForm)); log.info("助贷资金路由-通知资金系统结束,response :{}, uuid : {} , bizNo : {} , callbackUrl:{},params:{}", JSON.toJSONString(response),assetForm.getUuid(),assetForm.getBizNo(),assetForm.getCallbackUrl(), JSON.toJSONString(assetForm.transToNotifyMap(data)));
if(response==null || response.size()==0 || !"200".equals(response.get("statusCode")) || "error".equals(response.get("response"))) { if(response==null || response.size()==0 || !"200".equals(response.get("statusCode")) || "error".equals(response.get("response"))) {
assetForm.setRepeatCount(assetForm.getRepeatCount() + 1); assetForm.setRepeatCount(assetForm.getRepeatCount() + 1);
redisServiceAssetForm.rightPushEx("AID.LOAN.FUND.ROUTE.NOTIFY.83IUE",assetForm,1, TimeUnit.DAYS); redisServiceAssetForm.rightPushEx("AID.LOAN.FUND.ROUTE.NOTIFY.83IUE",assetForm,1, TimeUnit.DAYS);
......
package com.quantgroup.asset.distribution.service.funding.impl;
import com.quantgroup.asset.distribution.enums.funding.AuditTargetEnum;
import com.quantgroup.asset.distribution.enums.funding.AuditTypeEnum;
import com.quantgroup.asset.distribution.enums.response.FundModuleResponse;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.jpa.repository.IFundModuleChannelFundConfigNewRepository;
import com.quantgroup.asset.distribution.util.fund.module.ChannelFundConfigUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.*;
/**
* @author : Hyuk
* @description : FundModuleChannelFundConfigNewServiceImpl
* @date : 2020/2/26 5:38 下午
*/
@Slf4j
@Service
public class FundModuleChannelFundConfigNewServiceImpl implements IFundModuleChannelFundConfigNewService {
@Autowired
private IFundModuleChannelFundConfigNewRepository fundModuleChannelFundConfigNewRepository;
@Autowired
private IApprovalLogService approvalLogService;
@Override
public Map<String, Object> getChannelFundConfigsByChannelOrFundId(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
// 分页条件
Pageable pageable = new PageRequest(pageNum < 0 ? 0 : pageNum, pageSize);
Specification<FundModuleChannelFundConfigNew> specification = new Specification<FundModuleChannelFundConfigNew>() {
@Override
public Predicate toPredicate(Root<FundModuleChannelFundConfigNew> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicates = new ArrayList<>();
predicates.add(cb.equal(root.get("enable"), true));
if(StringUtils.isNotEmpty(bizChannel)){
predicates.add(cb.equal(root.get("bizChannel"), bizChannel));
}
if(fundId != null){
predicates.add(cb.like(root.get("fundIds"), "%" + fundId + "%"));
}
query.where(predicates.toArray(new Predicate[predicates.size()]));
return query.getRestriction();
}
};
Page<FundModuleChannelFundConfigNew> channelFundConfigs = fundModuleChannelFundConfigNewRepository.findAll(specification, pageable);
Map<String, Object> result = new HashMap<>();
result.put("total", channelFundConfigs.getTotalElements());
result.put("pages", channelFundConfigs.getTotalPages());
result.put("pageSize", channelFundConfigs.getSize());
result.put("pageNum", channelFundConfigs.getNumber());
result.put("list", channelFundConfigs.getContent());
return result;
}
@Transactional(rollbackFor=Exception.class)
@Override
public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks, String proposer, String auditor) {
// 新增配置, 根据渠道查询如果库里已存在,返回异常;
FundModuleChannelFundConfigNew fundModuleChannelFundConfigNew = findByBizChannel(bizChannel);
if (fundModuleChannelFundConfigNew != null) {
log.info("资方模块, 渠道 : {}资方配置已存在, 添加失败!", bizChannel);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_EXIST);
}
// 渠道资方配置是否正在审核
if (approvalLogService.isAuditing(bizChannel)) {
log.info("资方模块, 渠道 : {} 资方配置正在审批中, 不允许修改", bizChannel);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_AUDITING);
}
FundModuleChannelFundConfigNew newConfig = createdNewChannelFundConfigNew(bizChannel, funds, remarks);
createdChannelFundConfigApprovalLog(bizChannel, proposer, auditor, null, newConfig.getId());
return GlobalResponse.create(FundModuleResponse.SUCCESS);
}
@Transactional(rollbackFor=Exception.class)
@Override
public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks, String proposer, String auditor) {
// 更改配置, 根据id查询如果库里不存在,返回异常
FundModuleChannelFundConfigNew configNew = fundModuleChannelFundConfigNewRepository.findByIdAndEnableIsTrue(id);
if (configNew == null) {
log.info("资方模块, 渠道 : {}, 配置id : {}, 资方配置不存在, 修改失败!", bizChannel, id);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_NOT_EXIST);
}
// 如果该条配置在审批,不允许更改
boolean isAuditing = approvalLogService.isAuditing(bizChannel);
if (isAuditing) {
log.info("资方模块, 渠道 : {}, 配置id : {}, 正在审批中, 不允许修改", bizChannel, id);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_AUDITING);
}
FundModuleChannelFundConfigNew newConfig = createdNewChannelFundConfigNew(bizChannel, funds, remarks);
createdChannelFundConfigApprovalLog(bizChannel, proposer, auditor, id, newConfig.getId());
return GlobalResponse.create(FundModuleResponse.SUCCESS);
}
@Cacheable(value="cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:CK9A_'+#bizChannel")
@Override
public FundModuleChannelFundConfigNew findByBizChannel(String bizChannel) {
List<FundModuleChannelFundConfigNew> configList = fundModuleChannelFundConfigNewRepository.findByBizChannelAndEnableIsTrue(bizChannel);
if (CollectionUtils.isEmpty(configList)) { return null; }
// 避免脏读
if (configList.size() > 2) {
throw new QGException(QGExceptionType.CHANNEL_FUND_CONFIG_GREATER_THAN_TOW, bizChannel);
}
Collections.sort(configList, (c1, c2) -> {
// 别直接把相减把long类型转成int,可能越界
if (c2.getId() > c1.getId()) {
return 1;
} else if (c2.getId() < c1.getId()) {
return -1;
} else {
return 0;
}
});
return configList.get(0);
}
@Override
public FundModuleChannelFundConfigNew findById(Long id) {
return fundModuleChannelFundConfigNewRepository.findById(id);
}
@Override
public FundModuleChannelFundConfigNew auditPassConfig(Long preId, Long auditId) {
FundModuleChannelFundConfigNew config = updateEnable(auditId, true);
if (preId != null) {
updateEnable(preId, false);
}
return config;
}
@CacheEvict(value = "cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:CK9A_'+#bizChannel")
@Override
public void clearChannelFundConfigCache(String bizChannel) {
log.info("渠道资方配置缓存清除, bizChannel : {}", bizChannel);
}
/**
* 更改配置enable状态
* @param id
* @param enable
*/
private FundModuleChannelFundConfigNew updateEnable(Long id, Boolean enable) {
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewRepository.findById(id);
config.setEnable(enable);
return fundModuleChannelFundConfigNewRepository.save(config);
}
/**
* 创建一条新配置记录
* @param bizChannel
* @param funds
* @param remarks
* @return
*/
private FundModuleChannelFundConfigNew createdNewChannelFundConfigNew(String bizChannel, String funds, String remarks) {
FundModuleChannelFundConfigNew config = new FundModuleChannelFundConfigNew();
config.setBizChannel(bizChannel);
config.setFunds(funds);
config.setRemarks(remarks);
config.setFundIds(ChannelFundConfigUtil.getAllFundIds(funds));
config.setFundLimitTranslate(ChannelFundConfigUtil.getFundLimitTranslate(funds));
config.setEnable(false);
return fundModuleChannelFundConfigNewRepository.save(config);
}
/**
* 创建渠道资方配置审批记录
* @param bizChannel
* @param proposer
* @param auditor
* @param preConfigId
* @param auditConfigId
*/
private void createdChannelFundConfigApprovalLog(String bizChannel, String proposer, String auditor, Long preConfigId, Long auditConfigId) {
approvalLogService.createApprovalLog(AuditTypeEnum.ONLINE, AuditTargetEnum.FUND_CONFIG, bizChannel, proposer, auditor, preConfigId, auditConfigId);
}
}
package com.quantgroup.asset.distribution.service.funding.impl; package com.quantgroup.asset.distribution.service.funding.impl;
import java.util.ArrayList; import java.util.*;
import java.util.HashMap; import java.util.stream.Collectors;
import java.util.List;
import java.util.Map;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfig;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.CacheEvict;
...@@ -19,9 +21,15 @@ import org.springframework.data.domain.PageRequest; ...@@ -19,9 +21,15 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.quantgroup.asset.distribution.enums.funding.AuditTargetEnum;
import com.quantgroup.asset.distribution.enums.funding.AuditTypeEnum;
import com.quantgroup.asset.distribution.enums.response.FundModuleResponse; import com.quantgroup.asset.distribution.enums.response.FundModuleResponse;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService; import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig; import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.repository.IFundModuleChannelFundConfigRepository; import com.quantgroup.asset.distribution.service.jpa.repository.IFundModuleChannelFundConfigRepository;
...@@ -35,6 +43,8 @@ public class FundModuleChannelFundConfigServiceImpl implements IFundModuleChanne ...@@ -35,6 +43,8 @@ public class FundModuleChannelFundConfigServiceImpl implements IFundModuleChanne
@Autowired @Autowired
private IFundModuleChannelFundConfigRepository fundModuleChannelFundConfigRepository; private IFundModuleChannelFundConfigRepository fundModuleChannelFundConfigRepository;
@Autowired
private IApprovalLogService approvalLogService;
/** /**
* 分页使用 * 分页使用
...@@ -69,48 +79,157 @@ public class FundModuleChannelFundConfigServiceImpl implements IFundModuleChanne ...@@ -69,48 +79,157 @@ public class FundModuleChannelFundConfigServiceImpl implements IFundModuleChanne
return result; return result;
} }
@CacheEvict(value = "cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:AC8A_'+#bizChannel") @Transactional(rollbackFor=Exception.class)
@Override @Override
public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks) { public GlobalResponse addChannelFundConfig(String bizChannel, String funds, String remarks, String proposer, String auditor) {
// 新增配置, 根据渠道查询如果库里已存在,返回异常; // 新增配置, 根据渠道查询如果库里已存在,返回异常;
FundModuleChannelFundConfig fundModuleChannelFundConfig = fundModuleChannelFundConfigRepository.findByBizChannelAndEnableIsTrue(bizChannel); FundModuleChannelFundConfig fundModuleChannelFundConfig = findByBizChannel(bizChannel);
if (fundModuleChannelFundConfig != null) { if (fundModuleChannelFundConfig != null) {
log.info("资方模块, 渠道 : {}资方配置已存在, 添加失败!", bizChannel); log.info("资方模块, 渠道 : {}资方配置已存在, 添加失败!", bizChannel);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_EXIST); return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_EXIST);
} }
fundModuleChannelFundConfig = new FundModuleChannelFundConfig(); FundModuleChannelFundConfig newConfig = createdNewChannelFundConfig(bizChannel, funds, remarks);
fundModuleChannelFundConfig.setBizChannel(bizChannel); createdChannelFundConfigApprovalLog(bizChannel, proposer, auditor, null, newConfig.getId());
fundModuleChannelFundConfig.setFunds(funds);
fundModuleChannelFundConfig.setRemarks(remarks);
fundModuleChannelFundConfig.setFundIds(ChannelFundConfigUtil.getAllFundIds(funds));
// 默认测试
fundModuleChannelFundConfig.setType(0);
fundModuleChannelFundConfig.setEnable(true);
fundModuleChannelFundConfigRepository.save(fundModuleChannelFundConfig);
return GlobalResponse.create(FundModuleResponse.SUCCESS); return GlobalResponse.create(FundModuleResponse.SUCCESS);
} }
@CacheEvict(value = "cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:AC8A_'+#bizChannel") @Transactional(rollbackFor=Exception.class)
@Override @Override
public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks) { public GlobalResponse updateChannelFundConfig(Long id, String bizChannel, String funds, String remarks, String proposer, String auditor) {
// 更改配置, 根据id查询如果库里不存在,返回异常 // 更改配置, 根据id查询如果库里不存在,返回异常
FundModuleChannelFundConfig fundModuleChannelFundConfig = fundModuleChannelFundConfigRepository.findByIdAndEnableIsTrue(id); FundModuleChannelFundConfig fundModuleChannelFundConfig = fundModuleChannelFundConfigRepository.findByIdAndEnableIsTrue(id);
if (fundModuleChannelFundConfig == null) { if (fundModuleChannelFundConfig == null) {
log.info("资方模块, 渠道 : {}, 配置id : {}, 资方配置不存在, 修改失败!", bizChannel, id); log.info("资方模块, 渠道 : {}, 配置id : {}, 资方配置不存在, 修改失败!", bizChannel, id);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_NOT_EXIST); return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_NOT_EXIST);
} }
// 如果该条配置在审批,不允许更改
boolean isAuditing = approvalLogService.isAuditing(bizChannel);
if (isAuditing) {
log.info("资方模块, 渠道 : {}, 配置id : {}, 正在审批中, 不允许修改", bizChannel, id);
return GlobalResponse.create(FundModuleResponse.CHANNEL_FUND_CONFIG_IS_AUDITING);
}
FundModuleChannelFundConfig auditConfig = createdNewChannelFundConfig(bizChannel, funds, remarks);
createdChannelFundConfigApprovalLog(bizChannel, proposer, auditor, fundModuleChannelFundConfig.getId(), auditConfig.getId());
return GlobalResponse.create(FundModuleResponse.SUCCESS);
}
@Cacheable(value="cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:AC8A_'+#bizChannel")
@Override
public FundModuleChannelFundConfig findByBizChannel(String bizChannel) {
List<FundModuleChannelFundConfig> configList = fundModuleChannelFundConfigRepository.findByBizChannelAndEnableIsTrue(bizChannel);
if (CollectionUtils.isEmpty(configList)) { return null; }
// 避免脏读
if (configList.size() > 2) {
throw new QGException(QGExceptionType.CHANNEL_FUND_CONFIG_GREATER_THAN_TOW, bizChannel);
}
Collections.sort(configList, (c1, c2) -> {
// 别直接把相减把long类型转成int,可能越界
if (c2.getId() > c1.getId()) {
return 1;
} else if (c2.getId() < c1.getId()) {
return -1;
} else {
return 0;
}
});
return configList.get(0);
}
@Override
public FundModuleChannelFundConfig findById(Long id) {
return fundModuleChannelFundConfigRepository.findById(id);
}
/**
* 增加一条配置记录,Enable先为false
* @param bizChannel
* @param funds
* @param remarks
* @return
*/
private FundModuleChannelFundConfig createdNewChannelFundConfig(String bizChannel, String funds, String remarks) {
FundModuleChannelFundConfig fundModuleChannelFundConfig = new FundModuleChannelFundConfig();
fundModuleChannelFundConfig.setBizChannel(bizChannel); fundModuleChannelFundConfig.setBizChannel(bizChannel);
fundModuleChannelFundConfig.setFunds(funds); fundModuleChannelFundConfig.setFunds(funds);
fundModuleChannelFundConfig.setRemarks(remarks); fundModuleChannelFundConfig.setRemarks(remarks);
fundModuleChannelFundConfig.setFundIds(ChannelFundConfigUtil.getAllFundIds(funds)); fundModuleChannelFundConfig.setFundIds(ChannelFundConfigUtil.getAllFundIds(funds));
fundModuleChannelFundConfig.setEnable(true); // 默认测试
fundModuleChannelFundConfigRepository.save(fundModuleChannelFundConfig); fundModuleChannelFundConfig.setType(0);
return GlobalResponse.create(FundModuleResponse.SUCCESS); fundModuleChannelFundConfig.setEnable(false);
return fundModuleChannelFundConfigRepository.save(fundModuleChannelFundConfig);
}
/**
* 创建渠道资方配置审批记录
* @param bizChannel
* @param proposer
* @param auditor
* @param preConfigId
* @param auditConfigId
*/
private void createdChannelFundConfigApprovalLog(String bizChannel, String proposer, String auditor, Long preConfigId, Long auditConfigId) {
approvalLogService.createApprovalLog(AuditTypeEnum.ONLINE, AuditTargetEnum.FUND_CONFIG, bizChannel, proposer, auditor, preConfigId, auditConfigId);
} }
@Cacheable(value="cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:AC8A_'+#bizChannel")
@Override @Override
public FundModuleChannelFundConfig findByBizChannel(String bizChannel) { public FundModuleChannelFundConfig auditPassConfig(Long preId, Long auditId) {
return fundModuleChannelFundConfigRepository.findByBizChannelAndEnableIsTrue(bizChannel); FundModuleChannelFundConfig config = updateEnable(auditId, true);
if (preId != null) {
updateEnable(preId, false);
}
return config;
}
/**
* 更改配置enable状态
* @param id
* @param enable
*/
private FundModuleChannelFundConfig updateEnable(Long id, Boolean enable) {
FundModuleChannelFundConfig config = fundModuleChannelFundConfigRepository.findById(id);
config.setEnable(enable);
return fundModuleChannelFundConfigRepository.save(config);
}
@CacheEvict(value = "cacheManager", key="'ASSET_DISTRIBUTION:FUND_MODULE:CHANNEL_FUND_CONFIG:AC8A_'+#bizChannel")
@Override
public void clearChannelFundConfigCache(String bizChannel) {
log.info("渠道资方配置缓存清除, bizChannel : {}", bizChannel);
}
/**
* 渠道资方配置按条件类型分组
* @param fundModuleChannelFundConfig
* @return
*/
private FundModuleChannelFundConfig groupByLimit(FundModuleChannelFundConfig fundModuleChannelFundConfig) {
List<ChannelFundConfig> fundConfigList = JSONArray.parseArray(fundModuleChannelFundConfig.getFunds(), ChannelFundConfig.class);
// 条件类型分组, key:条件类型
Map<String, List<ChannelFundConfig>> channelFundConfigMap = new LinkedHashMap<>();
for (ChannelFundConfig channelFundConfig : fundConfigList) {
List<ChannelFundConfig.Limit> limits = channelFundConfig.getLimits();
// 先把每个资方下的条件排序,保证多个条件下的条件顺序相同
Collections.sort(limits, Comparator.comparingInt(l -> l.getLimit().hashCode()));
StringBuilder key = new StringBuilder();
limits.forEach(limit -> key.append(limit.getLimit()));
if (channelFundConfigMap.get(key.toString()) == null) {
channelFundConfigMap.put(key.toString(), new ArrayList<>());
}
channelFundConfigMap.get(key.toString()).add(channelFundConfig);
}
// 分完组后,开始对组内优先级进行排序
channelFundConfigMap.entrySet().stream().forEach(entry -> {
Collections.sort(entry.getValue(), Comparator.comparingInt(config -> config.getPriority()));
});
// 重新组装
List<ChannelFundConfig> sortedList = new ArrayList<>();
channelFundConfigMap.entrySet().forEach(e -> {
sortedList.addAll(e.getValue());
});
fundModuleChannelFundConfig.setFunds(JSON.toJSONString(sortedList));
return fundModuleChannelFundConfig;
} }
} }
...@@ -5,6 +5,8 @@ import java.util.List; ...@@ -5,6 +5,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
...@@ -15,15 +17,19 @@ import com.alibaba.fastjson.JSONObject; ...@@ -15,15 +17,19 @@ import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.config.annotation.HandleException; import com.quantgroup.asset.distribution.config.annotation.HandleException;
import com.quantgroup.asset.distribution.constant.FundModuleConstants; import com.quantgroup.asset.distribution.constant.FundModuleConstants;
import com.quantgroup.asset.distribution.enums.funding.AuditStatusEnum;
import com.quantgroup.asset.distribution.enums.response.FundModuleResponse; import com.quantgroup.asset.distribution.enums.response.FundModuleResponse;
import com.quantgroup.asset.distribution.exception.QGExceptionType; import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions; import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.entity.fund.FundInfo; import com.quantgroup.asset.distribution.model.entity.fund.FundInfo;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.approval.IApprovalLogService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService; import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleLimitTypeService; import com.quantgroup.asset.distribution.service.funding.IFundModuleLimitTypeService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleService; import com.quantgroup.asset.distribution.service.funding.IFundModuleService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService; import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.ApprovalLog;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleLimitTypeConfig; import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleLimitTypeConfig;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -43,6 +49,10 @@ public class FundModuleServiceImpl implements IFundModuleService{ ...@@ -43,6 +49,10 @@ public class FundModuleServiceImpl implements IFundModuleService{
private IFundModuleLimitTypeService fundModuleLimitTypeService; private IFundModuleLimitTypeService fundModuleLimitTypeService;
@Autowired @Autowired
private IFundModuleChannelFundConfigService fundModuleChannelFundConfigService; private IFundModuleChannelFundConfigService fundModuleChannelFundConfigService;
@Autowired
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Autowired
private IApprovalLogService approvalLogService;
@Value("${clotho.url}") @Value("${clotho.url}")
private String clothoURL; private String clothoURL;
...@@ -78,14 +88,25 @@ public class FundModuleServiceImpl implements IFundModuleService{ ...@@ -78,14 +88,25 @@ public class FundModuleServiceImpl implements IFundModuleService{
@HandleException @HandleException
@Override @Override
public GlobalResponse saveChannelFundConfig(Integer type, Long id, String bizChannel, String funds, String remarks) { public GlobalResponse saveChannelFundConfig(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer) {
if (type == FundModuleConstants.CHANNEL_FUNDS_OPERAOTR_TYPE_ADD) { if (type == FundModuleConstants.CHANNEL_FUNDS_OPERAOTR_TYPE_ADD) {
return fundModuleChannelFundConfigService.addChannelFundConfig(bizChannel, funds, remarks); return fundModuleChannelFundConfigService.addChannelFundConfig(bizChannel, funds, remarks, proposer, auditor);
} else if (type == FundModuleConstants.CHANNEL_FUNDS_OPERATOR_TYPE_UPDATE) { } else if (type == FundModuleConstants.CHANNEL_FUNDS_OPERATOR_TYPE_UPDATE) {
return fundModuleChannelFundConfigService.updateChannelFundConfig(id, bizChannel, funds, remarks); return fundModuleChannelFundConfigService.updateChannelFundConfig(id, bizChannel, funds, remarks, proposer, auditor);
} else { }
return GlobalResponse.create(FundModuleResponse.SUCCESS); return GlobalResponse.create(FundModuleResponse.UNKNOW_TYPE);
}
@HandleException
@Override
public GlobalResponse saveChannelFundConfigNew(Integer type, Long id, String bizChannel, String funds, String remarks, String auditor, String proposer) {
if (type == FundModuleConstants.CHANNEL_FUNDS_OPERAOTR_TYPE_ADD) {
return fundModuleChannelFundConfigNewService.addChannelFundConfig(bizChannel, funds, remarks, proposer, auditor);
} else if (type == FundModuleConstants.CHANNEL_FUNDS_OPERATOR_TYPE_UPDATE) {
return fundModuleChannelFundConfigNewService.updateChannelFundConfig(id, bizChannel, funds, remarks, proposer, auditor);
} }
return GlobalResponse.create(FundModuleResponse.UNKNOW_TYPE);
} }
@HandleException @HandleException
...@@ -97,4 +118,62 @@ public class FundModuleServiceImpl implements IFundModuleService{ ...@@ -97,4 +118,62 @@ public class FundModuleServiceImpl implements IFundModuleService{
} }
return GlobalResponse.success(result); return GlobalResponse.success(result);
} }
@HandleException
@Override
public GlobalResponse getChannelFundConfigsNew(String bizChannel, Long fundId, Integer pageNum, Integer pageSize) {
Map<String, Object> result = fundModuleChannelFundConfigNewService.getChannelFundConfigsByChannelOrFundId(bizChannel, fundId, pageNum, pageSize);
if (result == null || result.size() == 0) {
return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
}
return GlobalResponse.success(result);
}
@HandleException
@Override
public GlobalResponse getAuditInfos(String targetName, Integer auditStatus, Integer auditType, Integer auditTarget,
String applyStartTime, String applyEndTime, String user, Integer pageNum, Integer pageSize) {
Map<String, Object> result = approvalLogService.getApprovalLogs(targetName, auditStatus, auditType, auditTarget, applyStartTime, applyEndTime, user, pageNum, pageSize);
if (result.size() == 0) {
return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
}
return GlobalResponse.success(result);
}
@HandleException
@Override
public GlobalResponse findChannelFundConfigById(Long configId) {
FundModuleChannelFundConfig config = fundModuleChannelFundConfigService.findById(configId);
if (config == null) {
return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
}
return GlobalResponse.success(config);
}
@HandleException
@Override
public GlobalResponse findChannelFundConfigNewById(Long configId) {
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
if (config == null) {
return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
}
return GlobalResponse.success(config);
}
@HandleException
@Override
public GlobalResponse audit(Long id, Integer auditStatus) {
// 先获取审批记录
ApprovalLog approvalLog = approvalLogService.findById(id);
if (approvalLog == null) {
return GlobalResponse.create(FundModuleResponse.HAS_NO_DATA);
}
if (AuditStatusEnum.containsCode(auditStatus)) {
approvalLogService.audit(approvalLog, auditStatus);
return GlobalResponse.success();
} else {
return GlobalResponse.create(FundModuleResponse.UKNOW_AUDIT_STATUS);
}
}
} }
package com.quantgroup.asset.distribution.service.jpa.entity;
import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Table;
import lombok.Data;
/**
* 审批日志表
* @author liwenbin
*
*/
@Table(name = "approval_log")
@Entity
@Data
public class ApprovalLog implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "audit_type")
private Integer auditType;
@Column(name = "audit_target")
private Integer auditTarget;
@Column(name = "target_name")
private String targetName;
@Column(name = "proposer")
private String proposer;
@Column(name = "apply_time")
private Timestamp applyTime;
@Column(name = "auditor")
private String auditor;
@Column(name = "audit_time")
private String auditTime;
@Column(name = "audit_status")
private Integer auditStatus;
@Column(name = "pre_config_id")
private Long preConfigId;
@Column(name = "audit_config_id")
private Long auditConfigId;
@Column(name = "enable")
private Boolean enable;
@Column(name = "created_at")
private Timestamp createdAt;
@Column(name = "updated_at")
private Timestamp updatedAt;
@PrePersist
public void prePersist() {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
createdAt = timestamp;
updatedAt = timestamp;
}
@PreUpdate
public void preUpdate() {
updatedAt = new Timestamp(System.currentTimeMillis());
}
}
...@@ -52,12 +52,21 @@ public class FinanceProductHitLog implements Serializable{ ...@@ -52,12 +52,21 @@ public class FinanceProductHitLog implements Serializable{
@Column(name = "new_finance_product") @Column(name = "new_finance_product")
private String newFinanceProduct; private String newFinanceProduct;
@Column(name = "old_audit_result")
private String oldAuditResult;
@Column(name = "new_audit_result")
private String newAuditResult;
@Column(name = "equals") @Column(name = "equals")
private Boolean equals; private Boolean equals;
@Column(name = "enable") @Column(name = "enable")
private Boolean enable; private Boolean enable;
@Column(name = "execute_type")
private Integer executeType;
@Column(name = "created_at") @Column(name = "created_at")
private Timestamp createdAt; private Timestamp createdAt;
......
package com.quantgroup.asset.distribution.service.jpa.entity;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* @author : Hyuk
* @description : FundModuleChannelFundConfigNew
* @date : 2020/2/26 5:40 下午
*/
@Data
@Table(name = "fund_module_channel_fund_config_new")
@Entity
public class FundModuleChannelFundConfigNew implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "biz_channel")
private String bizChannel;
@Column(name = "funds")
private String funds;
@Column(name = "remarks")
private String remarks;
@Column(name = "fund_ids")
private String fundIds;
@Column(name = "fund_limit_translate")
private String fundLimitTranslate;
@Column(name = "enable")
private Boolean enable;
@Column(name = "created_at")
private Timestamp createdAt;
@Column(name = "updated_at")
private Timestamp updatedAt;
@PrePersist
public void prePersist() {
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
createdAt = timestamp;
updatedAt = timestamp;
}
@PreUpdate
public void preUpdate() {
updatedAt = new Timestamp(System.currentTimeMillis());
}
}
...@@ -39,6 +39,9 @@ public class FundModuleLimitTypeConfig implements Serializable{ ...@@ -39,6 +39,9 @@ public class FundModuleLimitTypeConfig implements Serializable{
@Column(name = "code") @Column(name = "code")
private String code; private String code;
@Column(name = "type")
private String type;
@Column(name = "enable") @Column(name = "enable")
private Boolean enable; private Boolean enable;
......
package com.quantgroup.asset.distribution.service.jpa.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import com.quantgroup.asset.distribution.service.jpa.entity.ApprovalLog;
public interface IApprovalLogRepository extends JpaRepository<ApprovalLog, Long>, JpaSpecificationExecutor<ApprovalLog>{
public ApprovalLog findByIdAndEnableIsTrue(Long id);
public ApprovalLog findByAuditTypeAndAuditTargetAndTargetNameAndAuditStatusAndEnableIsTrue(Integer auditType,
Integer auditTarget,
String targetName,
Integer auditStatus);
}
package com.quantgroup.asset.distribution.service.jpa.repository;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
/**
* @author : Hyuk
* @description : IFundModuleChannelFundConfigNewRepository
* @date : 2020/2/26 5:53 下午
*/
public interface IFundModuleChannelFundConfigNewRepository extends JpaRepository<FundModuleChannelFundConfigNew, Long>, JpaSpecificationExecutor<FundModuleChannelFundConfigNew> {
/**
* 根据渠道号查询渠道资方配置
* @param bizChannel
* @return
*/
public List<FundModuleChannelFundConfigNew> findByBizChannelAndEnableIsTrue(String bizChannel);
/**
* 根据配置id查询资方配置
* @param id
* @return
*/
public FundModuleChannelFundConfigNew findByIdAndEnableIsTrue(Long id);
/**
* 根据id查询资方配置, 主要是审核部分用, 这时候配置还没应用到线上, enable还是false
* @param id
* @return
*/
public FundModuleChannelFundConfigNew findById(Long id);
}
package com.quantgroup.asset.distribution.service.jpa.repository; package com.quantgroup.asset.distribution.service.jpa.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
...@@ -17,7 +18,7 @@ public interface IFundModuleChannelFundConfigRepository extends JpaRepository<Fu ...@@ -17,7 +18,7 @@ public interface IFundModuleChannelFundConfigRepository extends JpaRepository<Fu
* @param bizChannel * @param bizChannel
* @return * @return
*/ */
public FundModuleChannelFundConfig findByBizChannelAndEnableIsTrue(String bizChannel); public List<FundModuleChannelFundConfig> findByBizChannelAndEnableIsTrue(String bizChannel);
/** /**
* 根据id查询渠道资方配置 * 根据id查询渠道资方配置
...@@ -25,4 +26,11 @@ public interface IFundModuleChannelFundConfigRepository extends JpaRepository<Fu ...@@ -25,4 +26,11 @@ public interface IFundModuleChannelFundConfigRepository extends JpaRepository<Fu
* @return * @return
*/ */
public FundModuleChannelFundConfig findByIdAndEnableIsTrue(Long id); public FundModuleChannelFundConfig findByIdAndEnableIsTrue(Long id);
/**
* 注意,这个是给渠道资方配置审批用的,慎用,这个不关注enable状态
* @param id
* @return
*/
public FundModuleChannelFundConfig findById(Long id);
} }
...@@ -2,6 +2,7 @@ package com.quantgroup.asset.distribution.service.notify; ...@@ -2,6 +2,7 @@ package com.quantgroup.asset.distribution.service.notify;
import java.util.Map; import java.util.Map;
import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
/** /**
...@@ -20,5 +21,5 @@ public interface INotifyService { ...@@ -20,5 +21,5 @@ public interface INotifyService {
/** /**
* 通知业务流系统 * 通知业务流系统
*/ */
public void notifyBusinessFlow(String bizNo, Integer status); public void notifyBusinessFlow(String bizNo, FundingResult fundResult, String nextOperateDate);
} }
...@@ -10,6 +10,7 @@ import org.springframework.stereotype.Service; ...@@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.exception.QGException; import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType; import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
...@@ -40,36 +41,55 @@ public class NotifyServiceImpl implements INotifyService{ ...@@ -40,36 +41,55 @@ public class NotifyServiceImpl implements INotifyService{
log.info("通知资金系统结果开始, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, notifyForm : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getCallbackUrl(), JSON.toJSONString(notifyMap)); log.info("通知资金系统结果开始, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, notifyForm : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getCallbackUrl(), JSON.toJSONString(notifyMap));
if (StringUtils.isEmpty(assetForm.getCallbackUrl())) { if (StringUtils.isEmpty(assetForm.getCallbackUrl())) {
log.info("通知资金系统结果失败,callbackUrl为空, uuid : {}, bizNo : {}, assetNo : {}, notifyForm : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), JSON.toJSONString(notifyMap)); log.info("通知资金系统结果失败,callbackUrl为空, uuid : {}, bizNo : {}, assetNo : {}, notifyForm : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), JSON.toJSONString(notifyMap));
return; throw new QGException(QGExceptionType.NOTIFY_FUND_SERVER_ERROR, assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo());
} }
Map<String, String> response = httpService.postHasResponse(assetForm.getCallbackUrl(), notifyMap); Map<String, String> response = httpService.postHasResponse(assetForm.getCallbackUrl(), notifyMap);
log.info("通知资金系统结果结束, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, notifyForm : {}, response : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getCallbackUrl(), JSON.toJSONString(notifyMap), JSON.toJSONString(response)); log.info("通知资金系统结果结束, uuid : {}, bizNo : {}, assetNo : {}, callbackUrl : {}, notifyForm : {}, response : {}", assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getCallbackUrl(), JSON.toJSONString(notifyMap), JSON.toJSONString(response));
if(response==null || response.size()==0 || !"200".equals(response.get("statusCode")) || "error".equals(response.get("response"))) { if(response==null || response.size()==0 || !"200".equals(response.get("statusCode")) || !"success".equals(response.get("response"))) {
throw new QGException(QGExceptionType.NOTIFY_FUND_SERVER_ERROR, assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo()); throw new QGException(QGExceptionType.NOTIFY_FUND_SERVER_ERROR, assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo());
} }
} }
@Override @Override
public void notifyBusinessFlow(String bizNo, Integer status) { public void notifyBusinessFlow(String bizNo, FundingResult fundingResult, String nextOperateDate) {
try { try {
if (isDebug) { return; } // if (isDebug) { return; } 测试环境也保证通知
log.info("通知业务流系统订单终态开始, bizNo : {}, status : {}", bizNo, status); log.info("通知业务流系统订单终态开始, bizNo : {}, fundingResult : {}, nextOperateDate : {}", bizNo, fundingResult.name(), nextOperateDate);
String response = httpService.post(businessFlowURL + "/ex/inner/accept_info", new HashMap<String, String>(){{ String response = httpService.post(businessFlowURL + "/ex/inner/accept_info", new HashMap<String, String>(){{
put("applyNo", bizNo); put("applyNo", bizNo);
put("status", status + ""); put("status", getNotifyBusinessFlowStatusByFundingResult(fundingResult) + "");
put("type", "5"); put("type", "5");
put("auditValidTime", nextOperateDate);
}}); }});
log.info("通知业务流系统订单终态结束, bizNo : {}, status : {}, response : {}", bizNo, status, response); log.info("通知业务流系统订单终态结束, bizNo : {}, fundingResult : {}, nextOperateDate : {}, response : {}", bizNo, fundingResult.name(), nextOperateDate, response);
JSONObject data = null; JSONObject data = null;
if (StringUtils.isEmpty(response) || (data = JSON.parseObject(response)).getInteger("code") != 0) { if (StringUtils.isEmpty(response) || (data = JSON.parseObject(response)).getInteger("code") != 0) {
throw new QGException(QGExceptionType.NOTIFY_BUSINESS_FLOW_ERROR, bizNo, status); throw new QGException(QGExceptionType.NOTIFY_BUSINESS_FLOW_ERROR, bizNo, fundingResult.name());
} }
} catch (QGException qe) { } catch (QGException qe) {
log.error("资产分发订单终态通知业务流系统出现错误, 错误信息 : {}, bizNo : {}, status : {}", qe.qgExceptionType.code + "->" + qe.detail, bizNo, status); log.error("资产分发订单终态通知业务流系统出现错误, 错误信息 : {}, bizNo : {}, fundingResult : {}", qe.qgExceptionType.code + "->" + qe.detail, bizNo, fundingResult.name());
alarmService.dingtalkAlarm("Warn", "通知业务流系统订单终态出现错误", "错误信息 : " + qe.qgExceptionType.code + "->" + qe.detail + " , bizNo : " + bizNo + " , " + "status : " + status); alarmService.dingtalkAlarm("Warn", "通知业务流系统订单终态出现错误", "错误信息 : " + qe.qgExceptionType.code + "->" + qe.detail + " , bizNo : " + bizNo + " , " + "status : " + fundingResult.name());
} catch (Exception e) { } catch (Exception e) {
log.error("资产分发订单终态通知业务流系统异常, bizNo : {}, status : {}", bizNo, status); log.error("资产分发订单终态通知业务流系统异常, bizNo : {}, fundingResult : {}", bizNo, fundingResult.name());
alarmService.dingtalkAlarm("Warn", "通知业务流系统订单终态异常", "bizNo : " + bizNo + " , " + "status : " + status); alarmService.dingtalkAlarm("Warn", "通知业务流系统订单终态异常", "bizNo : " + bizNo + " , " + "status : " + fundingResult.name());
}
}
/**
* @return
* @param fundingResult
*/
private int getNotifyBusinessFlowStatusByFundingResult(FundingResult fundingResult) {
if (fundingResult == FundingResult.FUAD_ASSIGN_SUCC) {
return 1;
} else if (fundingResult == FundingResult.REJECT) {
return 0;
} else if (fundingResult == FundingResult.CANCEL_LOAN) {
return 2;
} else if (fundingResult == FundingResult.HANG_UP) {
return 3;
} else {
return -1;
} }
} }
} }
package com.quantgroup.asset.distribution.service.product; package com.quantgroup.asset.distribution.service.product;
import com.quantgroup.asset.distribution.enums.ExecuteType;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
/** /**
...@@ -15,5 +16,6 @@ public interface IFinanceProductHitLogService { ...@@ -15,5 +16,6 @@ public interface IFinanceProductHitLogService {
* @param oldFinanceProduct * @param oldFinanceProduct
* @param newFinanceProduct * @param newFinanceProduct
*/ */
public void saveLog(AssetForm assetForm, String oldFinanceProduct, String newFinanceProduct); public void saveLog(AssetForm assetForm, String oldFinanceProduct, String newFinanceProduct,
String oldAuditResult, String newAuditResult, ExecuteType executeType);
} }
...@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; ...@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.quantgroup.asset.distribution.enums.ExecuteType;
import com.quantgroup.asset.distribution.model.form.AssetForm; import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.jpa.entity.FinanceProductHitLog; import com.quantgroup.asset.distribution.service.jpa.entity.FinanceProductHitLog;
import com.quantgroup.asset.distribution.service.jpa.repository.IFinanceProductHitLogRepository; import com.quantgroup.asset.distribution.service.jpa.repository.IFinanceProductHitLogRepository;
...@@ -34,7 +35,8 @@ public class FinanceProductHitLogServiceImpl implements IFinanceProductHitLogSer ...@@ -34,7 +35,8 @@ public class FinanceProductHitLogServiceImpl implements IFinanceProductHitLogSer
@Async @Async
@Override @Override
public void saveLog(AssetForm assetForm, String oldFinanceProduct, String newFinanceProduct) { public void saveLog(AssetForm assetForm, String oldFinanceProduct, String newFinanceProduct,
String oldAuditResult, String newAuditResult, ExecuteType executeType) {
try { try {
FinanceProductHitLog hitLog = new FinanceProductHitLog(); FinanceProductHitLog hitLog = new FinanceProductHitLog();
hitLog.setBizChannel(assetForm.getBizChannel()); hitLog.setBizChannel(assetForm.getBizChannel());
...@@ -43,8 +45,11 @@ public class FinanceProductHitLogServiceImpl implements IFinanceProductHitLogSer ...@@ -43,8 +45,11 @@ public class FinanceProductHitLogServiceImpl implements IFinanceProductHitLogSer
hitLog.setBizNo(assetForm.getBizNo()); hitLog.setBizNo(assetForm.getBizNo());
hitLog.setOldFinanceProduct(oldFinanceProduct); hitLog.setOldFinanceProduct(oldFinanceProduct);
hitLog.setNewFinanceProduct(newFinanceProduct); hitLog.setNewFinanceProduct(newFinanceProduct);
hitLog.setOldAuditResult(oldAuditResult);
hitLog.setNewAuditResult(newAuditResult);
hitLog.setEnable(true); hitLog.setEnable(true);
hitLog.setEquals(financeProducEquals(oldFinanceProduct, newFinanceProduct)); hitLog.setEquals(financeProducEquals(oldFinanceProduct, newFinanceProduct));
hitLog.setExecuteType(executeType.getCode());
financeProductHitLogRepository.save(hitLog); financeProductHitLogRepository.save(hitLog);
} catch (Exception e) { } catch (Exception e) {
log.error("金融产品集命中记录比较保存异常, uuid : {}, bizNo : {}, assetNo : {}, oldFInanceProduct : {}, newFinanceProduct : {}", log.error("金融产品集命中记录比较保存异常, uuid : {}, bizNo : {}, assetNo : {}, oldFInanceProduct : {}, newFinanceProduct : {}",
......
package com.quantgroup.asset.distribution.service.rule; package com.quantgroup.asset.distribution.service.rule;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import java.util.Map; import java.util.Map;
public interface IRuleService { public interface IRuleService {
...@@ -11,4 +14,19 @@ public interface IRuleService { ...@@ -11,4 +14,19 @@ public interface IRuleService {
* @return 返回true或者false * @return 返回true或者false
*/ */
public boolean valid(String expression, Map<String, Object> data); public boolean valid(String expression, Map<String, Object> data);
/**
* limitDetail表达式判断
* @param limits
* @param data
* @return
*/
public boolean validNew(ChannelFundConfigNew.Limits limits, Map<String, Object> data);
/**
* 获取IRuleVO规则对象
* @param limits
* @return
*/
public IRuleVO getIRuleVo(ChannelFundConfigNew.Limits limits);
} }
...@@ -3,6 +3,14 @@ package com.quantgroup.asset.distribution.service.rule.impl; ...@@ -3,6 +3,14 @@ package com.quantgroup.asset.distribution.service.rule.impl;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Map; import java.util.Map;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.quantgroup.asset.distribution.constant.RuleConstants;
import com.quantgroup.asset.distribution.enums.UnionType;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.BaseRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
import com.quantgroup.asset.distribution.service.rule.vo.UnionRuleVO;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -15,6 +23,7 @@ import com.quantgroup.asset.distribution.util.calc.Expression; ...@@ -15,6 +23,7 @@ import com.quantgroup.asset.distribution.util.calc.Expression;
import com.quantgroup.asset.distribution.util.calc.Expression.ExpressionException; import com.quantgroup.asset.distribution.util.calc.Expression.ExpressionException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
/** /**
* 规则判断 * 规则判断
...@@ -46,4 +55,91 @@ public class RuleServiceImpl implements IRuleService{ ...@@ -46,4 +55,91 @@ public class RuleServiceImpl implements IRuleService{
} }
} }
@Override
public boolean validNew(ChannelFundConfigNew.Limits limits, Map<String, Object> data) {
try {
if (StringUtils.isEmpty(limits.getLimitDetail())) { throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY); }
IRuleVO ruleVO = translateFromWebFrontJSON(limits.getLimitDetail());
return ruleVO.valid(data);
} catch (QGException qx) {
log.error("规则判断出现错误, limitDetail : {}, limitTranslate : {}, data : {}", limits.getLimitDetail(), limits.getLimitTranslate(), data);
throw qx;
} catch (Exception e) {
log.error("规则判断出现未知异常, limitDetail : {}, limitTranslate : {}, data : {}", limits.getLimitDetail(), limits.getLimitTranslate(), data);
throw new QGException(QGExceptionType.RULE_CALC_ERROR, limits.getLimitTranslate());
}
}
@Override
public IRuleVO getIRuleVo(ChannelFundConfigNew.Limits limits) {
if (StringUtils.isEmpty(limits.getLimitDetail())) { throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY); }
IRuleVO ruleVO = translateFromWebFrontJSON(limits.getLimitDetail());
return ruleVO;
}
/**
* JSON转IRuleVO
*
* @param json
* @return
*/
private IRuleVO translateFromWebFrontJSON(String json) {
try {
JSONObject jsonObject = JSON.parseObject(json);
if (!isUnionRule(jsonObject))
return jsonObject.toJavaObject(BaseRuleVO.class);
return translateUnionRuleVO(jsonObject);
} catch (Exception e) {
log.error("解析规则json出错,错误内容为 : {}", json, e);
throw new QGException(QGExceptionType.RULE_EXPRESSION_IS_EMPTY);
}
}
/**
* 检测是否组合规则
*
* @param jsonObject
* @return
*/
private boolean isUnionRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject != null, QGExceptionType.RULE_IS_NOT_JSON);
if (jsonObject.containsKey(RuleConstants.CONDITION)) {
checkUnionRule(jsonObject);
return true;
}
checkBaseRule(jsonObject);
return false;
}
/**
* JSON转UnionRuleVO
*
* @param jsonObject
* @return
*/
private UnionRuleVO translateUnionRuleVO(JSONObject jsonObject) {
JSONArray jsonArray = jsonObject.getJSONArray(RuleConstants.CONDITION);
UnionRuleVO unionRuleVO = new UnionRuleVO(UnionType.fromCode(jsonObject.getString(RuleConstants.OPERATOR)));
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject child = jsonArray.getJSONObject(i);
if (!isUnionRule(child)) {
unionRuleVO.getBaseRules().add(child.toJavaObject(BaseRuleVO.class));
} else {
unionRuleVO.getUnionRules().add(translateUnionRuleVO(child));
}
}
return unionRuleVO;
}
private void checkUnionRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.OPERATOR) && jsonObject.size() >= 2, QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(!CollectionUtils.isEmpty(jsonObject.getJSONArray(RuleConstants.CONDITION)), QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(StringUtils.equalsAnyIgnoreCase(jsonObject.getString(RuleConstants.OPERATOR), RuleConstants.AND, RuleConstants.OR), QGExceptionType.RULE_IS_NOT_JSON);
}
private void checkBaseRule(JSONObject jsonObject) {
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.OPERATOR) && jsonObject.size() >= 3, QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.KEY), QGExceptionType.RULE_IS_NOT_JSON);
QGPreconditions.checkArgument(jsonObject.containsKey(RuleConstants.VAL), QGExceptionType.RULE_IS_NOT_JSON);
}
} }
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.primitives.Doubles;
import com.quantgroup.asset.distribution.enums.RuleOperator;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
@Data
@AllArgsConstructor
@NoArgsConstructor
@JSONType(typeName = "base", serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
@Slf4j
public class BaseRuleVO implements IRuleVO, Serializable {
private static final long serialVersionUID = -1L;
public static final String IN_FORMAT = "%s in (%s)";
public static final String NOT_IN_FORMAT = "%s not in (%s)";
private String key;
private String operator;
@JSONField(name = "value")
private String value;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BaseRuleVO that = (BaseRuleVO) o;
return Objects.equal(key, that.key) &&
Objects.equal(operator, that.operator) &&
Objects.equal(value, that.value);
}
@Override
public String format() {
switch (RuleOperator.fromCode(operator)) {
case In:
return String.format(IN_FORMAT, key, value);
case NotIn:
return String.format(NOT_IN_FORMAT, key, value);
default:
return key + operator + value;
}
}
@Override
public boolean valid(Map<String, Object> data) {
if(data == null || !data.containsKey(key)){
log.info("规则数据不存在,key:{},operator:{},value:{}",key,operator,value);
throw new QGException(QGExceptionType.DATA_NOT_EXIST_FOR_RULE,key,operator,value);
}
if(operator == null){
log.info("规则符为空,key:{},value:{}",key,value);
throw new QGException(QGExceptionType.RULE_OPERATOR_IS_EMPTY);
}
Object object = data.get(key);
if(object == null){
log.info("规则数据为空,key:{},operator:{},value:{}",key,operator,value);
throw new QGException(QGExceptionType.RULE_DATA_IS_EMPTY,key,operator,value);
}
return compareCommon(object);
}
@Override
public Map<String, Boolean> valid2(Map<String, Object> data) {
return ImmutableMap.of(this.format(),compareCommon(data.get(key)));
}
/**
* 比较
* @param object
* @return
*/
private boolean compareCommon(Object object){
try {
if (object instanceof Integer)
return Doubles.tryParse(value) == null ? operateInt((Integer) object) : operateBigDecimal(BigDecimal.valueOf(((Integer) object)));
if (object instanceof Float)
return operateBigDecimal(BigDecimal.valueOf(((Float) object)));
if (object instanceof Double)
return operateBigDecimal(BigDecimal.valueOf(((Double) object)));
if (object instanceof BigDecimal)
return operateBigDecimal((BigDecimal) object);
//防止 仿真把数字传成字符串
try {
return operateBigDecimal(BigDecimal.valueOf((Double.parseDouble(String.valueOf(object)))));
} catch (NumberFormatException e) {
return operateString(String.valueOf(object));
}
} catch (Exception e) {
log.error("数据比较出现错误,key:{}, 配置数据:{}, 待比较的数据:{}", key, value, object, e);
throw new QGException(QGExceptionType.DATA_COMPARE_ERROR);
}
}
@Override
public String getId() {
return null;
}
private boolean operateInt(int data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return Integer.parseInt(value) == data;
case In:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(Integer::parseInt).anyMatch(i -> data == i);
case NotIn:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(Integer::parseInt).noneMatch(i -> data == i);
case LessThan:
return data < Integer.parseInt(value);
case NotEqual:
return data != Integer.parseInt(value);
case GreaterThan:
return data > Integer.parseInt(value);
case LessThanOrEqual:
return data <= Integer.parseInt(value);
case GreaterThanOrEqual:
return data >= Integer.parseInt(value);
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private boolean operateBigDecimal(BigDecimal data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return new BigDecimal(value).compareTo(data) == 0;
case In:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(BigDecimal::new).anyMatch(o -> o.compareTo(data) == 0);
case NotIn:
return Arrays.stream(StringUtils.split(value, ',')).filter(StringUtils::isNumeric).map(BigDecimal::new).noneMatch(o -> o.compareTo(data) == 0);
case LessThan:
return new BigDecimal(value).compareTo(data) > 0;
case NotEqual:
return new BigDecimal(value).compareTo(data) != 0;
case GreaterThan:
return new BigDecimal(value).compareTo(data) < 0;
case LessThanOrEqual:
return new BigDecimal(value).compareTo(data) >= 0;
case GreaterThanOrEqual:
return new BigDecimal(value).compareTo(data) <= 0;
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private boolean operateString(String data) {
switch (RuleOperator.fromCode(operator)) {
case Equal:
return StringUtils.equals(StringUtils.replaceAll(value, "\"", ""), data);
case In:
return Arrays.stream(StringUtils.split(StringUtils.replaceAll(value, "\"", ""), ',')).anyMatch(data::equals);
case NotIn:
return Arrays.stream(StringUtils.split(StringUtils.replaceAll(value, "\"", ""), ',')).noneMatch(data::equals);
case LessThan:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) < 0;
case NotEqual:
return !StringUtils.equals(data, StringUtils.replaceAll(value, "\"", ""));
case GreaterThan:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) > 0;
case LessThanOrEqual:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) <= 0;
case GreaterThanOrEqual:
return StringUtils.compare(data, StringUtils.replaceAll(value, "\"", "")) >= 0;
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
@Override
public void checkParams() {
}
@Override
public Set<String> getParamNames() {
return Sets.newHashSet(key);
}
}
\ No newline at end of file
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import java.util.Map;
import java.util.Set;
/**
* @author : Hyuk
* @description : IRuleVO
* @date : 2020/3/5 4:50 下午
*/
//支持fastjson
@JSONType(seeAlso = {BaseRuleVO.class, UnionRuleVO.class})
//支持jackson
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "@type")
@JsonSubTypes({
@JsonSubTypes.Type(value = BaseRuleVO.class, name = "base"),
@JsonSubTypes.Type(value = UnionRuleVO.class, name = "union")})
public interface IRuleVO {
boolean valid(Map<String, Object> data);
/**
* 记录拒绝规则 二次校验
*
* @param data
* @return
*/
Map<String, Boolean> valid2(Map<String, Object> data);
String getId();
void checkParams();
Set<String> getParamNames();
String format();
default String toJSONString() {
return JSON.toJSONString(this, SerializerFeature.WriteClassName, SerializerFeature.WriteEnumUsingName);
}
}
package com.quantgroup.asset.distribution.service.rule.vo;
import com.alibaba.fastjson.annotation.JSONType;
import com.google.common.base.Joiner;
import com.google.common.base.Objects;
import com.google.common.collect.Lists;
import com.quantgroup.asset.distribution.enums.UnionType;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.collections.MapUtils;
import org.springframework.util.CollectionUtils;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* {condition:[
* {key:’v5’, operator:’<‘, value:’0.2’},
* {key:’v4’, operator:’in‘, value:’100,200,4900’},
* {condition:[{key:’v5’, operator:’<‘, value:’0.2’},{key:’v4’, operator:’<‘, value:’100’}], operator:’or’}
* ], operator:’and’}
* <p>
* v5<0.2 && v4<100 && (v5<0.2 || v4<100)
* <p>
* {condition:[{key:’v5’,operator:’<‘,value:’0.2’},{key:’v4’,operator:’<‘,value:’100’}],operator:’and’}
*/
@Data
@NoArgsConstructor
@JSONType(typeName = "union")
public class UnionRuleVO implements IRuleVO, Serializable {
private static final long serialVersionUID = -1L;
private UnionType unionType;
private List<UnionRuleVO> unionRules = Lists.newArrayList();
private List<BaseRuleVO> baseRules = Lists.newArrayList();
public UnionRuleVO(UnionType unionType) {
this.unionType = unionType;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
UnionRuleVO that = (UnionRuleVO) o;
return unionType == that.unionType &&
Objects.equal(unionRules, that.unionRules) &&
Objects.equal(baseRules, that.baseRules);
}
@Override
public boolean valid(Map<String, Object> data) {
QGPreconditions.checkArgument(!(CollectionUtils.isEmpty(baseRules) && CollectionUtils.isEmpty(unionRules)), QGExceptionType.RULE_IS_NOT_JSON);
switch (unionType) {
case Or:
return unionRules.stream().anyMatch(r -> r.valid(data))
|| baseRules.stream().anyMatch(r -> r.valid(data));
case And:
return unionRules.stream().allMatch(r -> r.valid(data))
&& baseRules.stream().allMatch(r -> r.valid(data));
default:
throw new QGException(QGExceptionType.RULE_UNION_OPERATOR_NOT_EXIST);
}
}
@Override
public Map<String, Boolean> valid2(Map<String, Object> data) {
Map<String,Boolean> maps = new HashMap<>();
Map<String, Boolean> umap = unionRules.parallelStream().collect(Collectors.toMap(k -> k.format(), v -> v.valid(data)));
Map<String, Boolean> bmap = baseRules.parallelStream().collect(Collectors.toMap(k -> k.format(), v -> v.valid(data)));
if(MapUtils.isNotEmpty(umap))
maps.putAll(umap);
if(MapUtils.isNotEmpty(bmap))
maps.putAll(bmap);
return maps;
}
@Override
public String format() {
StringBuilder stringBuilder = new StringBuilder();
String operator = unionType == UnionType.And ? "&&" : "||";
stringBuilder.append(Joiner.on(operator).join(baseRules.parallelStream().map(BaseRuleVO::format).collect(Collectors.toList())));
if (!CollectionUtils.isEmpty(unionRules)) {
if (!CollectionUtils.isEmpty(baseRules))
stringBuilder.append(operator);
stringBuilder.append(Joiner.on(operator).join(unionRules.parallelStream().map(r -> "(" + r.format() + ")").collect(Collectors.toList())));
}
return stringBuilder.toString();
}
@Override
public String getId() {
return null;
}
@Override
public void checkParams() {
}
@Override
public Set<String> getParamNames() {
Set<String> keys = baseRules.parallelStream().map(BaseRuleVO::getKey).collect(Collectors.toSet());
if (!CollectionUtils.isEmpty(unionRules))
unionRules.parallelStream().forEach(unionRuleVO -> keys.addAll(unionRuleVO.getParamNames()));
return keys;
}
}
package com.quantgroup.asset.distribution.util; package com.quantgroup.asset.distribution.util;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date; import java.util.Date;
/** /**
...@@ -17,4 +19,12 @@ public class DateUtil { ...@@ -17,4 +19,12 @@ public class DateUtil {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd"); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.format(new Date()); return df.format(new Date());
} }
/**
* 获取当前时间 yyyy-MM-dd HH:mm:ss
* @return
*/
public static String getCurDateTime() {
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
}
} }
...@@ -461,7 +461,7 @@ public class Expression { ...@@ -461,7 +461,7 @@ public class Expression {
pos--; pos--;
} }
token.type = ch == '(' ? TokenType.FUNCTION token.type = ch == '(' ? TokenType.FUNCTION
: variables.containsKey(token.surface) ? TokenType.VARIABLE : TokenType.LITERAL; : TokenType.VARIABLE;
} else if (ch == '(' || ch == ')' || ch == ',') { } else if (ch == '(' || ch == ')' || ch == ',') {
if (ch == '(') { if (ch == '(') {
token.type = TokenType.OPEN_PAREN; token.type = TokenType.OPEN_PAREN;
...@@ -672,7 +672,7 @@ public class Expression { ...@@ -672,7 +672,7 @@ public class Expression {
if (v1 == null || v2 == null) { if (v1 == null || v2 == null) {
return BigDecimal.ZERO; return BigDecimal.ZERO;
} }
if (v1.equals(v2)) { if (v1.equalsIgnoreCase(v2)) {
return BigDecimal.ONE; return BigDecimal.ONE;
} else { } else {
return BigDecimal.ZERO; return BigDecimal.ZERO;
...@@ -1130,8 +1130,10 @@ public class Expression { ...@@ -1130,8 +1130,10 @@ public class Expression {
variables.put("e", CreateLazyNumber(e.toPlainString())); variables.put("e", CreateLazyNumber(e.toPlainString()));
variables.put("PI", CreateLazyNumber(PI.toPlainString())); variables.put("PI", CreateLazyNumber(PI.toPlainString()));
variables.put("NULL", null); variables.put("NULL", null);
variables.put("TRUE", CreateLazyNumber(BigDecimal.ONE.toPlainString())); variables.put("true", CreateLazyNumber("true"));
variables.put("FALSE", CreateLazyNumber(BigDecimal.ZERO.toPlainString())); variables.put("TRUE", CreateLazyNumber("TRUE"));
variables.put("false", CreateLazyNumber("false"));
variables.put("FALSE", CreateLazyNumber("FALSE"));
} }
private void assertNotNull(String v1) { private void assertNotNull(String v1) {
...@@ -1400,7 +1402,7 @@ public class Expression { ...@@ -1400,7 +1402,7 @@ public class Expression {
break; break;
case VARIABLE: case VARIABLE:
if (!variables.containsKey(token.surface)) { if (!variables.containsKey(token.surface)) {
throw new ExpressionException("Unknown operator or function: " + token); return BigDecimal.ZERO;
} }
stack.push(() -> { stack.push(() -> {
...@@ -1578,9 +1580,7 @@ public class Expression { ...@@ -1578,9 +1580,7 @@ public class Expression {
} else if (value.equalsIgnoreCase("null")) { } else if (value.equalsIgnoreCase("null")) {
variables.put(variable, null); variables.put(variable, null);
} else if (value.equalsIgnoreCase("e") || } else if (value.equalsIgnoreCase("e") ||
value.equalsIgnoreCase("PI") || value.equalsIgnoreCase("PI")) {
value.equalsIgnoreCase("TRUE")||
value.equalsIgnoreCase("FALSE")) {
final String expStr = value; final String expStr = value;
variables.put(variable, new LazyNumber() { variables.put(variable, new LazyNumber() {
private final Map<String, LazyNumber> outerVariables = variables; private final Map<String, LazyNumber> outerVariables = variables;
......
package com.quantgroup.asset.distribution.util.fund.module; package com.quantgroup.asset.distribution.util.fund.module;
import java.util.HashSet; import java.util.*;
import java.util.LinkedHashSet;
import java.util.Set;
import com.alibaba.fastjson.JSON;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONArray;
...@@ -71,4 +70,22 @@ public class ChannelFundConfigUtil { ...@@ -71,4 +70,22 @@ public class ChannelFundConfigUtil {
} }
return StringUtils.join(fundIdSet, ","); return StringUtils.join(fundIdSet, ",");
} }
/**
* 根据资方配置获取资方对应条件
* @param funds
* @return
*/
public static String getFundLimitTranslate(String funds) {
Map<String, String> map = new LinkedHashMap<>();
JSONArray array = JSONArray.parseArray(funds);
for (int i = 0, len = array.size(); i < len; i++) {
JSONObject data = array.getJSONObject(i);
String fundId = data.getString("fundId");
JSONObject limitObj = data.getJSONObject("limits");
String limitTranslate = limitObj.getString("limitTranslate");
map.put(fundId, limitTranslate);
}
return JSON.toJSONString(map);
}
} }
...@@ -19,6 +19,7 @@ import com.quantgroup.asset.distribution.AssetDistributionBootstrap; ...@@ -19,6 +19,7 @@ import com.quantgroup.asset.distribution.AssetDistributionBootstrap;
import com.quantgroup.asset.distribution.constant.StatusConstants; import com.quantgroup.asset.distribution.constant.StatusConstants;
import com.quantgroup.asset.distribution.enums.funding.FundingResult; import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.model.entity.DistributeRecord; import com.quantgroup.asset.distribution.model.entity.DistributeRecord;
import com.quantgroup.asset.distribution.service.asset.IAssetAttributeExtendConfigService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService; import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService; import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
...@@ -37,6 +38,8 @@ public class DistributeTest { ...@@ -37,6 +38,8 @@ public class DistributeTest {
private IHttpService httpService; private IHttpService httpService;
@Autowired @Autowired
private IAssetDistributeService distributeService; private IAssetDistributeService distributeService;
@Autowired
private IAssetAttributeExtendConfigService service;
@Test @Test
public void testEn() { public void testEn() {
...@@ -63,14 +66,15 @@ public class DistributeTest { ...@@ -63,14 +66,15 @@ public class DistributeTest {
@Test @Test
public void testHttp() { public void testHttp() {
String result = httpService.post("http://localhost:9050" + "/feature/get", new HashMap<String, String>(){{ // String result = httpService.post("http://localhost:9050" + "/feature/get", new HashMap<String, String>(){{
put("uuid", "123213"); // put("uuid", "123213");
put("bizChannel", "123213"); // put("bizChannel", "123213");
put("bizNo", "1232131"); // put("bizNo", "1232131");
put("bizType", "123213131"); // put("bizType", "123213131");
put("keys", "12321321"); // put("keys", "12321321");
put("method", "0"); // put("method", "0");
}}); // }});
service.clearAllExtendConfigCache();
} }
@Test @Test
...@@ -78,7 +82,7 @@ public class DistributeTest { ...@@ -78,7 +82,7 @@ public class DistributeTest {
// AssetDistributeRecord record = assetDistributeRecordRepository.findByBizNoOrderByCreatedAtDescLimitOne("1231231231231"); // AssetDistributeRecord record = assetDistributeRecordRepository.findByBizNoOrderByCreatedAtDescLimitOne("1231231231231");
// record.setAssetDistributeStatus(StatusConstants.SUCCESS); // record.setAssetDistributeStatus(StatusConstants.SUCCESS);
// assetDistributeRecordRepository.save(record); // assetDistributeRecordRepository.save(record);
distributeService.receiveFundingResult("SP499997499085250626417877", FundingResult.FUAD_ASSIGN_SUCC); distributeService.receiveFundingResult("SP499997499085250626417877", FundingResult.FUAD_ASSIGN_SUCC, System.currentTimeMillis() + "");
} }
public static void main(String[] args) { public static void main(String[] args) {
......
...@@ -7,6 +7,8 @@ import org.springframework.boot.test.context.SpringBootTest; ...@@ -7,6 +7,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.junit4.SpringRunner;
import com.quantgroup.asset.distribution.AssetDistributionBootstrap; import com.quantgroup.asset.distribution.AssetDistributionBootstrap;
import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.notify.INotifyService; import com.quantgroup.asset.distribution.service.notify.INotifyService;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
...@@ -15,9 +17,23 @@ public class NotifyTest { ...@@ -15,9 +17,23 @@ public class NotifyTest {
@Autowired @Autowired
private INotifyService notifyService; private INotifyService notifyService;
@Autowired
private IHttpService httpService;
@Test @Test
public void testBusinessFlow() { public void testBusinessFlow() {
notifyService.notifyBusinessFlow("SP527400898415178843596841", 0); notifyService.notifyBusinessFlow("SP527400898415178843596841", FundingResult.REJECT, System.currentTimeMillis() + "");
}
@Test
public void test() {
httpService.get("https://www.baidu.com");
}
public static void main(String[] args) {
String a = "2019-11-12 01:20:30";
String b = "2019-11-12 01:20:30";
System.out.println(a.length());
} }
} }
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