Commit bd72559e authored by 郑建's avatar 郑建

量子魔方6.6第二期

parent b67fddea
...@@ -21,12 +21,9 @@ import com.alibaba.druid.pool.DruidDataSource; ...@@ -21,12 +21,9 @@ import com.alibaba.druid.pool.DruidDataSource;
@Configuration @Configuration
public class DataSourceConfig { public class DataSourceConfig {
@Value("${spring.datasource.primary.url}") private String dbUrl = "jdbc:mysql://172.17.5.9:31024/asset_distribution?useUnicode=true&characterEncoding=utf-8";
private String dbUrl; private String username = "qa";
@Value("${spring.datasource.primary.username}") private String password = "qatest";
private String username;
@Value("${spring.datasource.primary.password}")
private String password;
@Value("${spring.datasource.primary.driver-class-name}") @Value("${spring.datasource.primary.driver-class-name}")
private String driverClassName; private String driverClassName;
......
package com.quantgroup.asset.distribution.controller; package com.quantgroup.asset.distribution.controller;
import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
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.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
...@@ -109,6 +112,10 @@ public class FundModuleController { ...@@ -109,6 +112,10 @@ public class FundModuleController {
return findChannelFundConfigCommon(configId, 2); return findChannelFundConfigCommon(configId, 2);
} }
@RequestMapping("/simulation/conditions")
public GlobalResponse allConditions(Long configId){
return fundConfigConditions(configId);
}
private GlobalResponse saveChannelFundsConfigCommon(Integer type, Long id, String bizChannel, String funds, String remarks, private GlobalResponse saveChannelFundsConfigCommon(Integer type, Long id, String bizChannel, String funds, String remarks,
String auditor, String proposer, int oldOrNew) { String auditor, String proposer, int oldOrNew) {
...@@ -182,4 +189,26 @@ public class FundModuleController { ...@@ -182,4 +189,26 @@ public class FundModuleController {
log.info("资方模块接口, 根据id获取资方配置, configId : {} 耗时 : {}, response : {}", configId, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response)); log.info("资方模块接口, 根据id获取资方配置, configId : {} 耗时 : {}, response : {}", configId, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response; return response;
} }
private GlobalResponse fundConfigConditions(Long configId){
log.info("资方模块接口,根据id获取所有案例, configId : {}", configId);
if (configId == null) {
return GlobalResponse.create(FundModuleResponse.ID_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.getAllConditionsOfFundConfig(configId);
log.info("资方模块接口,根据id获取所有案例, configId : {} 耗时 : {}, response : {}", configId, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response;
}
private GlobalResponse simulation(List<FundConfigCondition> configConditions,Long configId){
log.info("资方模块接口,根据案例进行空泡, configConditions : {}", configConditions);
if (CollectionUtils.isEmpty(configConditions)) {
return GlobalResponse.create(FundModuleResponse.ID_IS_EMPTY);
}
Stopwatch stopwatch = Stopwatch.createStarted();
GlobalResponse response = fundModuleService.simulationCases(configConditions,configId);
log.info("资方模块接口,根据id获取所有案例, configConditions : {} 耗时 : {}, response : {}", configConditions, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS), JSON.toJSONString(response));
return response;
}
} }
...@@ -43,4 +43,8 @@ public enum RuleOperator { ...@@ -43,4 +43,8 @@ public enum RuleOperator {
log.error("枚举不存在,code={}", code); log.error("枚举不存在,code={}", code);
throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM); throw new QGException(QGExceptionType.COMMON_ILLEGAL_PARAM);
} }
public String getCode() {
return this.code;
}
} }
package com.quantgroup.asset.distribution.model.entity.fund;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class FundConfigCondition implements Serializable {
private static final long serialVersionUID = 1L;
private String conditionTempId;
private List<Condition> condition;
private Result result;
@Data
public static class Condition{
private String conditionCode;
private String conditionName;
private String conditionValue;
}
@Data
public static class Result{
private Boolean success;
private String fundInfo;
}
}
package com.quantgroup.asset.distribution.service.funding; package com.quantgroup.asset.distribution.service.funding;
import com.quantgroup.asset.distribution.config.annotation.HandleException;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
import com.quantgroup.asset.distribution.model.response.GlobalResponse; import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import java.util.List;
/** /**
* 资方模块Service * 资方模块Service
* @author liwenbin * @author liwenbin
...@@ -99,4 +103,8 @@ public interface IFundModuleService { ...@@ -99,4 +103,8 @@ public interface IFundModuleService {
* @return * @return
*/ */
public GlobalResponse audit(Long id, Integer auditStatus); public GlobalResponse audit(Long id, Integer auditStatus);
GlobalResponse getAllConditionsOfFundConfig(Long configId);
GlobalResponse simulationCases(List<FundConfigCondition> configConditions,Long configId);
} }
package com.quantgroup.asset.distribution.service.funding.impl; package com.quantgroup.asset.distribution.service.funding.impl;
import java.util.ArrayList; import java.math.BigDecimal;
import java.util.List; import java.math.RoundingMode;
import java.util.Map; import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import com.alibaba.fastjson.JSON;
import com.quantgroup.asset.distribution.enums.RuleOperator;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigSimulationVO;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService; import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew; import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.IRuleService;
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.collections.CollectionUtils;
import org.apache.commons.lang3.RandomUtils;
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;
...@@ -53,6 +66,8 @@ public class FundModuleServiceImpl implements IFundModuleService{ ...@@ -53,6 +66,8 @@ public class FundModuleServiceImpl implements IFundModuleService{
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService; private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Autowired @Autowired
private IApprovalLogService approvalLogService; private IApprovalLogService approvalLogService;
@Autowired
private IRuleService ruleService;
@Value("${clotho.url}") @Value("${clotho.url}")
private String clothoURL; private String clothoURL;
...@@ -176,4 +191,311 @@ public class FundModuleServiceImpl implements IFundModuleService{ ...@@ -176,4 +191,311 @@ public class FundModuleServiceImpl implements IFundModuleService{
return GlobalResponse.create(FundModuleResponse.UKNOW_AUDIT_STATUS); return GlobalResponse.create(FundModuleResponse.UKNOW_AUDIT_STATUS);
} }
} }
@HandleException
@Override
public GlobalResponse getAllConditionsOfFundConfig(Long configId){
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
// 未找到资方渠道配置直接通知
if (config == null) {
return GlobalResponse.error("未找到相关配置");
}
List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
List<FundModuleLimitTypeConfig> typeConfigs = fundModuleLimitTypeService.getAllLimitType();
Map<String,String> codeToNameMap = new HashMap<>();
for (FundModuleLimitTypeConfig typeConfig : typeConfigs){
codeToNameMap.put(typeConfig.getCode(),typeConfig.getName());
}
List<BaseRuleVO> baseRuleList = new ArrayList<>();
for (ChannelFundConfigNew channelFundConfig : fundConfigList) {
IRuleVO ruleVO = ruleService.getIRuleVo(channelFundConfig.getLimits());
baseRuleList.addAll(getAllBaseRule(ruleVO));
}
Map<String,List<String>> keyValueMap = collectValueMap(baseRuleList);
//去掉相同的值 例如 amount>3000 和amount>=3000在生成案例时 3001都可以满足 此时会有两个3001
for (Map.Entry<String,List<String>> entry : keyValueMap.entrySet()){
entry.setValue(new ArrayList<>(new LinkedHashSet<>(entry.getValue())));
}
List<FundConfigCondition> configConditions = createCondition(keyValueMap,codeToNameMap);
FundConfigSimulationVO vo = new FundConfigSimulationVO();
vo.setConditionsCase(configConditions);
List<FundConfigCondition.Condition> type = new ArrayList<>();
for (String key : keyValueMap.keySet()){
FundConfigCondition.Condition condition = new FundConfigCondition.Condition();
condition.setConditionCode(key);
condition.setConditionName(codeToNameMap.get(key));
type.add(condition);
}
vo.setConditionsType(type);
return GlobalResponse.success(vo);
}
@Override
public GlobalResponse simulationCases(List<FundConfigCondition> configConditions,Long configId) {
FundModuleChannelFundConfigNew config = fundModuleChannelFundConfigNewService.findById(configId);
if (config == null) {
return GlobalResponse.error("未找到相关配置");
}
List<ChannelFundConfigNew> fundConfigList = JSONArray.parseArray(config.getFunds(), ChannelFundConfigNew.class);
B:for (FundConfigCondition configCondition : configConditions){
Map<String,Object> data = new HashMap<>();
for (FundConfigCondition.Condition condition : configCondition.getCondition()){
String value = condition.getConditionValue();
Class<?> clazz = getType(value);
if (clazz.isAssignableFrom(BigDecimal.class)){
data.put(condition.getConditionCode(),new BigDecimal(value));
}else{
data.put(condition.getConditionCode(),value);
}
}
// 资方去重, 可能存在多条件同一个资方
Set<String> fundSet = new HashSet<>();
JSONArray fundArray = new JSONArray();
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;
}
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());
fundArray.add(fundInfoJSON);
fundSet.add(key);
}
}
FundConfigCondition.Result result = new FundConfigCondition.Result();
if (CollectionUtils.isEmpty(fundArray)){
result.setSuccess(false);
configCondition.setResult(result);
continue;
}
QGPreconditions.checkArgument(fundArray.size() != 0, QGExceptionType.NO_FUND_INFO_BEEN_HIT);
// 看命中优先级是否符合要求
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);
}
if (bucket[priority]) {
// 多个相同的优先级
throw new QGException(QGExceptionType.FUND_PRIORITY_IS_ERROR);
}
bucket[priority] = true;
}
result.setSuccess(true);
fundArray = JSONArray.parseArray(JSON.toJSONString(fundArray.stream().sorted(Comparator.comparingInt(o -> ((JSONObject) o).getInteger("priority"))).collect(Collectors.toList())));
String fundProductId = fundArray.getJSONObject(0).getString("fundProductId");
String fundId = fundArray.getJSONObject(0).getString("fundId");
result.setFundInfo(("null".equals(fundProductId) || StringUtils.isEmpty(fundProductId))?fundId:fundId+"_"+fundProductId);
configCondition.setResult(result);
}
FundConfigSimulationVO vo = new FundConfigSimulationVO();
vo.setConditionsCase(configConditions);
return GlobalResponse.success(vo);
}
private static List<BaseRuleVO> getAllBaseRule(IRuleVO ruleVO){
List<BaseRuleVO> baseRuleList = new ArrayList<>();
if (ruleVO.getClass().isAssignableFrom(UnionRuleVO.class)){
UnionRuleVO uRuleVo = (UnionRuleVO)ruleVO;
baseRuleList= uRuleVo.getBaseRules();
}else {
baseRuleList.add((BaseRuleVO)ruleVO);
}
return baseRuleList;
}
private static List<String> createValue(String operator,String value){
List<String> list = new ArrayList<>();
switch (RuleOperator.fromCode(operator)) {
case Equal:
case NotEqual:
list.add(getValue(RuleOperator.Equal.getCode(),value));
list.add(getValue(RuleOperator.NotEqual.getCode(),value));
return list;
case In:
case NotIn:
list.add(getValue(RuleOperator.In.getCode(),value));
list.add(getValue(RuleOperator.NotIn.getCode(),value));
return list;
case LessThan:
case GreaterThanOrEqual:
list.add(getValue(RuleOperator.LessThan.getCode(),value));
list.add(getValue(RuleOperator.GreaterThanOrEqual.getCode(),value));
return list;
case GreaterThan:
case LessThanOrEqual:
list.add(getValue(RuleOperator.GreaterThan.getCode(),value));
list.add(getValue(RuleOperator.LessThanOrEqual.getCode(),value));
return list;
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private static String getValue(String operator,String value){
Class<?> clazz = getType(value);
switch (RuleOperator.fromCode(operator)) {
case Equal:
return value;
case NotEqual:
if (clazz.isAssignableFrom(BigDecimal.class)) {
return new BigDecimal(value).add(new BigDecimal(1)).toString();
}else if (clazz.isAssignableFrom(Boolean.class)){
return Boolean.toString(!Boolean.valueOf(value));
}else {
if (value.length() == 1){
return String.valueOf((char) (value.charAt(0) + 1));
}else {
return value.substring(0,value.length() - 1) + String.valueOf((char) (value.charAt(value.length() -1 ) + 1));
}
}
case In:
if (value.contains(",")){
List<String> list = Arrays.asList(value.split(","));
return list.get(RandomUtils.nextInt(0,list.size()-1));
}else {
return value;
}
case NotIn:
if (value.contains(",")){
List<String> list = Arrays.asList(value.split(","));
if (BigDecimal.class.isAssignableFrom(list.get(0).getClass())){
Integer num = 1;
while (list.contains(String.valueOf(num))){
num ++;
}
return num.toString();
}else {
String start = getValue(operator,list.get(0));
while (list.contains(start)){
start = getValue(operator,start);
}
return start;
}
}else {
return value;
}
case LessThan:
if (BigDecimal.class.isAssignableFrom(clazz)){
if (new BigDecimal(value).doubleValue() < 1 && new BigDecimal(value).doubleValue() > 0){
return new BigDecimal(value).divide(new BigDecimal(10),value.split(".")[1].length(), RoundingMode.HALF_UP).toString();
}else {
return new BigDecimal(value).subtract(new BigDecimal(1)).toString();
}
}else {
throw new QGException(QGExceptionType.CRATE_RULE_VO_ERROR);
}
case GreaterThan:
if (BigDecimal.class.isAssignableFrom(clazz)){
return new BigDecimal(value).add(new BigDecimal(1)).toString();
}else {
throw new QGException(QGExceptionType.CRATE_RULE_VO_ERROR);
}
case LessThanOrEqual:
return getValue("<",value);
case GreaterThanOrEqual:
return getValue(">",value);
default:
throw new QGException(QGExceptionType.RULE_OPERATOR_NOT_EXIST);
}
}
private static Class<?> getType(String value){
if (StringUtils.isNumeric(value)){
return BigDecimal.class;
}
if ("true".equals(value) || "false".equals(value)){
return Boolean.class;
}
return String.class;
}
private static Map<String,List<String>> collectValueMap(List<BaseRuleVO> vos){
Map<String,List<String>> keyValueMap = new HashMap<>();
for (BaseRuleVO vo : vos){
if (keyValueMap.containsKey(vo.getKey())){
keyValueMap.get(vo.getKey()).addAll(createValue(vo.getOperator(),vo.getValue()));
}else {
keyValueMap.put(vo.getKey(),new ArrayList<>(createValue(vo.getOperator(),vo.getValue())));
}
}
return keyValueMap;
}
/**
* 对map中的每个key的list做笛卡儿积
* @param map
* @return
*/
private static List<FundConfigCondition> createCondition(Map<String,List<String>> map,Map<String,String> codeToNameMap){
List<FundConfigCondition> configConditions = new ArrayList<>();
List<String> keyList = new ArrayList<>(map.keySet());
List<List<String>> dimensionValue = new ArrayList<>();
for (String key:keyList){
dimensionValue.add(map.get(key));
}
List<List<String>> results = new ArrayList<>();
descartes(dimensionValue,results,0,new ArrayList<>());
for (int i = 0;i<results.size();i++){
FundConfigCondition configCondition = new FundConfigCondition();
List<FundConfigCondition.Condition> conditions = new ArrayList<>();
for (int j = 0;j<results.get(i).size();j++){
FundConfigCondition.Condition condition = new FundConfigCondition.Condition();
condition.setConditionCode(keyList.get(j));
condition.setConditionValue(results.get(i).get(j));
condition.setConditionName(codeToNameMap.get(keyList.get(j)));
conditions.add(condition);
}
configCondition.setConditionTempId(String.valueOf(i));
configCondition.setCondition(conditions);
configConditions.add(configCondition);
}
return configConditions;
}
/**
* 笛卡尔积演算
* @param dimensionValue
* @param result
* @param layer
* @param currentList
* @param <T>
*/
private static <T> void descartes(List<List<T>> dimensionValue, List<List<T>> result, int layer, List<T> currentList) {
if (layer < dimensionValue.size() - 1) {
if (dimensionValue.get(layer).size() == 0) {
descartes(dimensionValue, result, layer + 1, currentList);
} else {
for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
List<T> list = new ArrayList<>(currentList);
list.add(dimensionValue.get(layer).get(i));
descartes(dimensionValue, result, layer + 1, list);
}
}
} else if (layer == dimensionValue.size() - 1) {
if (dimensionValue.get(layer).size() == 0) {
result.add(currentList);
} else {
for (int i = 0; i < dimensionValue.get(layer).size(); i++) {
List<T> list = new ArrayList<>(currentList);
list.add(dimensionValue.get(layer).get(i));
result.add(list);
}
}
}
}
} }
...@@ -6,6 +6,9 @@ import cn.quantgroup.user.IUserSdkService; ...@@ -6,6 +6,9 @@ import cn.quantgroup.user.IUserSdkService;
import cn.quantgroup.user.UserSdkServiceFactory; import cn.quantgroup.user.UserSdkServiceFactory;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.quantgroup.asset.distribution.AssetDistributionBootstrap; import com.quantgroup.asset.distribution.AssetDistributionBootstrap;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigSimulationVO;
import com.quantgroup.asset.distribution.service.funding.IFundModuleService;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService; import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiService; import com.quantgroup.asset.distribution.service.niwodai.INiwodaiService;
import com.quantgroup.asset.distribution.service.niwodai.vo.*; import com.quantgroup.asset.distribution.service.niwodai.vo.*;
...@@ -21,6 +24,7 @@ import org.springframework.test.context.junit4.SpringRunner; ...@@ -21,6 +24,7 @@ import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List;
import java.util.Map; import java.util.Map;
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
...@@ -37,6 +41,8 @@ public class NiwodaiTest { ...@@ -37,6 +41,8 @@ public class NiwodaiTest {
@Value("${user.sdk.url}") @Value("${user.sdk.url}")
private String userSysUrl; private String userSysUrl;
private IUserSdkService userSdkService; private IUserSdkService userSdkService;
@Autowired
private IFundModuleService fundModuleService;
@PostConstruct @PostConstruct
private void init() { private void init() {
userSdkService = UserSdkServiceFactory.generateSDKService(userSysUrl, httpClient); userSdkService = UserSdkServiceFactory.generateSDKService(userSysUrl, httpClient);
...@@ -63,8 +69,25 @@ public class NiwodaiTest { ...@@ -63,8 +69,25 @@ public class NiwodaiTest {
@Test @Test
public void testIncoming() { public void testIncoming() {
NiwodaiIncomingResponseVO vo = niwodaiAssetService.incoming("ae7d04bf-1c5a-475b-98d2-b193be88cf2f","1028791648161","10000",12); NiwodaiIncomingResponseVO vo = niwodaiAssetService.incoming("2f0c65a8-c94e-4e03-87c6-b0ae99b100f0","AN000000135399103854755840","10000",12);
System.out.println(JSON.toJSONString(vo));
}
@Test
public void testResult(){
NiwodaiIncomingResultResponseVO vo = niwodaiAssetService.incomingResult("AN000000135399103854755840");
System.out.println(JSON.toJSONString(vo)); System.out.println(JSON.toJSONString(vo));
} }
@Test
public void testFund(){
fundModuleService.getAllConditionsOfFundConfig(1L);
}
@Test
public void testFundResult(){
List<FundConfigCondition> list = ((FundConfigSimulationVO)fundModuleService.getAllConditionsOfFundConfig(7L).getBody()).getConditionsCase();
fundModuleService.simulationCases(list,7L);
}
} }
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