Commit d0a6c0fb authored by liwenbin's avatar liwenbin

新橙项目上线前准备

parent e56866e9
package com.quantgroup.asset.distribution.constant.aid;
/**
* 助贷风控属性常量
* @author : Hyuk
* @description : AidRiskInfoConstants
* @date : 2020/7/15 5:58 下午
*/
public class AidRiskInfoConstants {
/**
* 量子分3
*/
public static final String QG_SCORE3 = "model_exec_data_source#xinyan_v5";
/**
* 量子分5
*/
public static final String QG_SCORE5 = "model_exec_data_source#bairong_v3_1";
/**
* 偿债能力
*/
public static final String QG_DEBT_PAYING_SCORE = "third_data_source#zs_consumeLevel";
/**
* 手机号风险等级
*/
public static final String QG_RISK_LEVEL_PHONE = "third_data_source#lhp_hit_by_phone";
/**
* 身份证号风险等级
*/
public static final String QG_RISK_LEVEL_IDNO = "third_data_source#lhp_hit_by_idNo";
}
......@@ -66,9 +66,6 @@ public class AidCommonCallbackController {
@Autowired
private INotifyService notifyService;
// private IAidAssetCommonService
@RequestMapping("/{fund_id}/{fund_product_id}/audit_result_callback")
public MiddleOfficeResponse auditResultCallback(@PathVariable("fund_id") String fundId,
@PathVariable("fund_product_id") String fundProId,
......
......@@ -71,6 +71,7 @@ public enum QGExceptionType {
AID_COMMON_PRE_AUDIT_ERROR(3022, "助贷通用预审出现错误, uuid : %s, bizNo : %s, fundId : %s"),
AID_COMMON_AUDIT_ERROR(3023, "助贷通用进件接口出现错误, uuid : %s, bizNo : %s, fundId : %s"),
AID_COMMON_AUDIT_RESULT_ERROR(3024, "助贷回调URL或content内容错误, fundId : %s, fundProductId : %s, content : %s"),
AID_COMMON_QUERY_AUDIT_RESULT_ERROR(3025, "助贷资方审核结果查询结果出现错误, uuid : %s, bizNo : %s, fundId : %s"),
AID_COMMON_AUDIT_RESULT_ORDER_ERROR(3026, "通用助贷结果接收订单状态异常, orderNo : %s, fundId : %s, orderStatus : %s"),
USER_OCR_INFO_IS_EMPTY(3019, "用户OCR信息为空, uuid : %s"),
......
......@@ -22,27 +22,27 @@ public class AidRiskInfo implements Serializable {
/**
* 量子分3
*/
private BigDecimal qgScore3;
private Object qgScore3;
/**
* 量子分5
*/
private BigDecimal qgScore5;
private Object qgScore5;
/**
* 偿债能力评分
*/
private BigDecimal qgDebtPayingScore;
private Object qgDebtPayingScore;
/**
* 量子风险等级手机号命中
*/
private String qgRiskLevelPhone;
private Object qgRiskLevelPhone;
/**
* 量子风险等级身份证号命中
*/
private String qgRiskLevelIdNo;
private Object qgRiskLevelIdNo;
public AidRiskInfo() {}
......
......@@ -7,6 +7,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.service.feature.IFeatureService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
......@@ -43,15 +44,13 @@ import lombok.extern.slf4j.Slf4j;
@Service
public class AssetAttributeServiceImpl implements IAssetAttributeService {
@Autowired
private IHttpService httpService;
@Autowired
private IAssetRepository assetRepository;
@Autowired
private IAssetAttributeExtendRepository assetAttributeExtendRepository;
@Autowired
private IFeatureService featureService;
@Value("${rule.engine.url}")
private String ruleEngineURL;
/**
* 获取所有资产扩展属性value
......@@ -85,7 +84,7 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
Map<String, Object> decAttributeValue = getDecAttributeValue(decKeys, assetForm);
data.putAll(decAttributeValue);
// 必填特征, 慎用....
Map<String, Object> necAttributeValue = getDecNecAttributeValue(necessaryKeys, assetForm, data);
Map<String, Object> necAttributeValue = getDecNecAttributeValue(necessaryKeys, assetForm);
data.putAll(necAttributeValue);
// 自有属性
Map<String, Object> propertyValue = getPropertyAttributeValue(propertyKeys, assetForm);
......@@ -98,11 +97,10 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
* 获取必填特征
* @param necessaryKeys
* @param assetForm
* @param data
* @return
*/
public Map<String, Object> getDecNecAttributeValue(Set<String> necessaryKeys, AssetForm assetForm, Map<String, Object> data) {
return getDecFeatureValueCommon(necessaryKeys, assetForm, 1);
public Map<String, Object> getDecNecAttributeValue(Set<String> necessaryKeys, AssetForm assetForm) {
return featureService.getFeatureData(necessaryKeys, assetForm, 1);
}
/**
......@@ -112,34 +110,9 @@ public class AssetAttributeServiceImpl implements IAssetAttributeService {
* @return
*/
public Map<String, Object> getDecAttributeValue(Set<String> decKeys, AssetForm assetForm) {
return getDecFeatureValueCommon(decKeys, assetForm, 0);
return featureService.getFeatureData(decKeys, assetForm, 0);
}
/**
*
* @param keys
* @param assetForm
* @param type
* @return
*/
public Map<String, Object> getDecFeatureValueCommon(Set<String> keys, AssetForm assetForm, int type) {
if (CollectionUtils.isEmpty(keys)) { return MapUtils.EMPTY_MAP; }
Stopwatch stopwatch = Stopwatch.createStarted();
String result = httpService.post(ruleEngineURL + "/feature/get", new HashMap<String, String>(){{
put("uuid", assetForm.getUuid());
put("bizChannel", assetForm.getBizChannel());
put("bizNo", assetForm.getBizNo());
put("bizType", assetForm.getBizType());
put("keys", StringUtils.join(keys, ","));
put("method", "0");
put("type", type + "");
}});
JSONObject resultJSON = null;
QGPreconditions.checkArgument(StringUtils.isNotEmpty(result) && (resultJSON = JSON.parseObject(result)).getInteger("code") == 0, QGExceptionType.GET_DEC_ATTRIBUTE_VALUE_ERROR, assetForm.getUuid(), JSON.toJSONString(keys));
Map<String, Object > data = resultJSON.getJSONObject("body");
log.info("决策特征属性获取完成, uuid : {}, assetNo : {}, bizChannel : {}, bizNo : {}, bizType : {}, type : {}, data : {}, 耗时 : {}", assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizChannel(), assetForm.getBizNo(), assetForm.getBizType(), type, JSON.toJSONString(data), stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
return data;
}
/**
* 获取自有属性值
......
package com.quantgroup.asset.distribution.service.feature;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Map;
import java.util.Set;
/**
* @author : Hyuk
* @description : IFeatureService
* @date : 2020/7/15 5:45 下午
*/
public interface IFeatureService {
/**
* 这个是调用量子魔方接口
* @param keys
* @param assetForm
* @param type 0: 缓存拿特证,没有null 1: 必有特征,缓存没有就去特征平台请求
* @return
*/
Map<String, Object> getFeatureData(Set<String> keys, AssetForm assetForm, int type);
}
package com.quantgroup.asset.distribution.service.feature.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.exception.QGPreconditions;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.feature.IFeatureService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
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.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @author : Hyuk
* @description : FeatureServiceImpl
* @date : 2020/7/15 5:47 下午
*/
@Slf4j
@Service
public class FeatureServiceImpl implements IFeatureService {
@Value("${rule.engine.url}")
private String ruleEngineURL;
@Autowired
private IHttpService httpService;
@Override
public Map<String, Object> getFeatureData(Set<String> keys, AssetForm assetForm, int type) {
if (CollectionUtils.isEmpty(keys)) { return MapUtils.EMPTY_MAP; }
Stopwatch stopwatch = Stopwatch.createStarted();
String result = httpService.post(ruleEngineURL + "/feature/get", new HashMap<String, String>(){{
put("uuid", assetForm.getUuid());
put("bizChannel", assetForm.getBizChannel());
put("bizNo", assetForm.getBizNo());
put("bizType", assetForm.getBizType());
put("keys", StringUtils.join(keys, ","));
put("method", "0");
put("type", type + "");
}});
JSONObject resultJSON = null;
QGPreconditions.checkArgument(StringUtils.isNotEmpty(result) && (resultJSON = JSON.parseObject(result)).getInteger("code") == 0, QGExceptionType.GET_DEC_ATTRIBUTE_VALUE_ERROR, assetForm.getUuid(), JSON.toJSONString(keys));
Map<String, Object > data = resultJSON.getJSONObject("body");
log.info("决策特征属性获取完成, uuid : {}, assetNo : {}, bizChannel : {}, bizNo : {}, bizType : {}, type : {}, data : {}, 耗时 : {}", assetForm.getUuid(), assetForm.getAssetNo(), assetForm.getBizChannel(), assetForm.getBizNo(), assetForm.getBizType(), type, JSON.toJSONString(data), stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
return data;
}
}
......@@ -9,6 +9,7 @@ import com.alibaba.fastjson.JSONObject;
import com.lkb.data.hbase.dataservice.verify.OCRIdCardDataService;
import com.lkb.data.hbase.row.verify.OCRIdCardRow;
import com.quantgroup.asset.distribution.constant.CodeConstants;
import com.quantgroup.asset.distribution.constant.aid.AidRiskInfoConstants;
import com.quantgroup.asset.distribution.constant.aid.PreAuditTypeConstants;
import com.quantgroup.asset.distribution.enums.user.EducationEnum;
import com.quantgroup.asset.distribution.enums.user.IncomeRangeEnum;
......@@ -26,6 +27,7 @@ import com.quantgroup.asset.distribution.model.entity.user.UserContactInfo;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.model.response.MiddleOfficeResponse;
import com.quantgroup.asset.distribution.service.aid.IAidFundInfoConfigService;
import com.quantgroup.asset.distribution.service.feature.IFeatureService;
import com.quantgroup.asset.distribution.service.funding.IAidAssetCommonService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidFundInfoConfig;
......@@ -47,10 +49,7 @@ import org.springframework.util.CollectionUtils;
import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
/**
* @author : Hyuk
......@@ -62,7 +61,6 @@ import java.util.Map;
public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
//TODO
@Value("${opearotr.server.domain}")
private String operatorDomain;
......@@ -72,15 +70,21 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
private IHttpService httpService;
@Autowired
private IUserCenterService userCenterService;
@Autowired
private IFeatureService featureService;
@Override
public boolean preAudit(AssetForm assetForm, String fundId, String fundProductId, Map<String, Object> data) {
try {
AidFundInfoConfig aidFundInfoConfig = aidFundInfoConfigService.findAidFundInfo(fundId, fundProductId);
String preAuditUrl = aidFundInfoConfig.getPreAuditUrl();
int preAuditType = PreAuditTypeConstants.PHONE_NO_OR_ID_CARD_NO_MD5;
int preAuditType = aidFundInfoConfig.getPreAuditType().intValue();
Map<String, String> requestParams = getPreAuditParams(assetForm.getUuid(), fundId, fundProductId, preAuditType);
MiddleOfficeResponse response = request(preAuditUrl, JSON.toJSONString(requestParams), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
MiddleOfficeResponse response = request(preAuditUrl, aidFundInfoConfig.getFundId(), JSON.toJSONString(requestParams), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
log.info("通用助贷资方预审完成, uuid : {}, bizNo : {}, bizType : {}, bizChannel : {}, fundId : {}, fundProductId : {}, response : {}",
assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizType(), assetForm.getBizChannel(), aidFundInfoConfig.getFundId(),
aidFundInfoConfig.getFundProductId(), JSON.toJSONString(response));
if (CodeConstants.SUCCESS.equals(response.getCode())) {
return true;
}
......@@ -106,9 +110,13 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
aidIncomingEntity.setUserInfo(createdAidUserInfo(userInfo, sdkUserInfo, assetForm.getUuid()));
aidIncomingEntity.setContactsInfo(createdAidContactsInfo(sdkUserInfo.getContactList(), assetForm.getUuid()));
aidIncomingEntity.setLoanInfo(createdAidLoanInfo(assetForm.getUuid()));
aidIncomingEntity.setRiskInfo(createdAidRiskInfo(assetForm.getUuid(), data));
aidIncomingEntity.setRiskInfo(createdAidRiskInfo(assetForm, data));
MiddleOfficeResponse response = request(requestURL, aidFundInfoConfig.getFundId(), JSON.toJSONString(aidIncomingEntity), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
log.info("通用助贷资方进件完成, uuid : {}, bizNo : {}, bizType : {}, bizChannel : {}, fundId : {}, fundProductId : {}, response : {}",
assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizType(), assetForm.getBizChannel(), aidFundInfoConfig.getFundId(),
aidFundInfoConfig.getFundProductId(), JSON.toJSONString(response));
MiddleOfficeResponse response = request(requestURL, JSON.toJSONString(aidIncomingEntity), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
if (CodeConstants.SUCCESS.equals(response.getCode())) {
return true;
}
......@@ -123,13 +131,16 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
@Override
public void auditResult(AssetForm assetForm, Asset asset, String fundId, String fundProductId) {
try {
String url = "https://sit02-third.n-orange.com/webservice/api/lhp/v1/credit/applyResult";
AidFundInfoConfig aidFundInfoConfig = aidFundInfoConfigService.findAidFundInfo(fundId, fundProductId);
Map<String, String> params = new HashMap<>();
params.put("orderNo", assetForm.getBizNo());
MiddleOfficeResponse response = request(url, JSON.toJSONString(params), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
MiddleOfficeResponse response = request(aidFundInfoConfig.getAuditResultUrl(), aidFundInfoConfig.getFundId(), JSON.toJSONString(params), aidFundInfoConfig.getPrivateKey(), aidFundInfoConfig.getPublicKey());
log.info("助贷资方通用审核结果查询接口完成, uuid : {}, bizNo : {}, bizChannel : {}, bizType : {}, fundId : {}, fundProductId : {}, response : {}",
assetForm.getUuid(), assetForm.getBizNo(), assetForm.getBizChannel(), assetForm.getBizType(), fundId, fundProductId);
} catch (Exception e) {
log.error("111", e);
log.error("助贷资方通用审核结果查询接口出现错误, uuid : {}, bizNo : {}, fundId : {}", assetForm.getUuid(), assetForm.getBizNo(), fundId);
throw new QGException(QGExceptionType.AID_COMMON_QUERY_AUDIT_RESULT_ERROR, assetForm.getUuid(), assetForm.getBizNo(), fundId);
}
}
......@@ -259,19 +270,30 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
/**
* 创建助贷通用风控信息
* @param uuid
* @param assetForm
* @param data
* @return
*/
private AidRiskInfo createdAidRiskInfo(String uuid, Map<String, Object> data) {
// TODO
private AidRiskInfo createdAidRiskInfo(AssetForm assetForm, Map<String, Object> data) {
String[] riskInfoKeys = {AidRiskInfoConstants.QG_SCORE3, AidRiskInfoConstants.QG_SCORE5, AidRiskInfoConstants.QG_DEBT_PAYING_SCORE,
AidRiskInfoConstants.QG_RISK_LEVEL_PHONE, AidRiskInfoConstants.QG_RISK_LEVEL_IDNO};
Set<String> keys = new HashSet<>();
for (String riskInfoKey : riskInfoKeys) {
if (data.get(riskInfoKey) == null) { keys.add(riskInfoKey); }
}
Map<String, Object> riskInfoData = featureService.getFeatureData(keys, assetForm, 1);
data.putAll(riskInfoData);
// 写死自然流量
return AidRiskInfo.builder()
.label(1)
.qgScore3(new BigDecimal("0.3484291211465728"))
.qgScore5(new BigDecimal("0.4391283915198491"))
.qgDebtPayingScore(new BigDecimal("42"))
.qgRiskLevelPhone("B1")
.qgRiskLevelIdNo("B1")
.qgScore3(data.get(AidRiskInfoConstants.QG_SCORE3))
.qgScore5(data.get(AidRiskInfoConstants.QG_SCORE5))
.qgDebtPayingScore(data.get(AidRiskInfoConstants.QG_DEBT_PAYING_SCORE))
.qgRiskLevelPhone(data.get(AidRiskInfoConstants.QG_RISK_LEVEL_PHONE))
.qgRiskLevelIdNo(data.get(AidRiskInfoConstants.QG_RISK_LEVEL_IDNO))
.build();
}
......@@ -294,18 +316,20 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
if ("0".equals(data.getString("code")) && "0".equals(data.getString("business_code"))) {
return JSON.parseObject(data.getString("data"), TencentLiveEntity.class);
}
return null;
// 这里为空抛一下异常, 理论上来说是不正常的, 因为都是自己的渠道, 之后增加其他活体类型, 再放到前筛里面去
throw new QGException(QGExceptionType.LIVE_DATA_ERROR, uuid);
}
/**
* 创建包装助贷资方对象
* @param fundId
* @param data
* @param privateKey
* @return
*/
private String createRequestParams(String data, String privateKey) throws Exception {
private String createRequestParams(String fundId, String data, String privateKey) throws Exception {
AidRsaParams aidRsaParams = AidRsaParams.builder()
.appId("1050")
.appId(fundId)
.content(RsaUtils.encryptByPrivateKey(data, privateKey))
.build();
return JSON.toJSONString(aidRsaParams);
......@@ -314,21 +338,16 @@ public class AidAssetCommonServiceImpl implements IAidAssetCommonService {
/**
* 通用请求,包装加密和解密
* @param url
* @param fundId
* @param data
* @return
*/
private MiddleOfficeResponse request(String url, String data, String privateKey, String publicKey) throws Exception {
String text = httpService.postJson(url, createRequestParams(data, privateKey));
private MiddleOfficeResponse request(String url, String fundId, String data, String privateKey, String publicKey) throws Exception {
String text = httpService.postJson(url, createRequestParams(fundId, data, privateKey));
AidRsaParams aidRsaParams = JSON.parseObject(text, AidRsaParams.class);
String result = RsaUtils.decryptByPublicKey(aidRsaParams.getContent(), publicKey);
log.info("通用助贷资方请求结束, url : {}, data : {}, result : {}", url, data, result);
MiddleOfficeResponse response = JSON.parseObject(result, MiddleOfficeResponse.class);
return response;
}
public static void main(String[] args) {
String text = "{\"content\":\"cCdElnqK1w3GRfuz9seRmo7fY3iJQNFoDRvpBdg8maIhJ/IzOBQQdeqxhxT14cJ1oT/4pHazsTNK\\r\\ngmGARtFR1SPi9kSa7/MdVTibOp1p+rzbe1tVHSL/GFuQPgglgQakZ1EnoiLj5jTwRBA29n4EgN4+\\r\\nalq95YC1Y+Rq1k4RyrU=\\r\\n\"}";
AidRsaParams aidRsaParams = JSON.parseObject(text, AidRsaParams.class);
System.out.println(aidRsaParams);
}
}
......@@ -113,7 +113,7 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
}
//助贷资金分配规则校验
if(ruleService.valid(aidLoanFundConfig.getFundRuleEl(), data)){
// 分配规则二次校验, md主要是ligeng的需求无法用表达式去满足, 特征值为null的居然让结果为true
// 分配规则二次校验, md主要是风控的需求无法用表达式去满足, 特征值为null的居然让结果为true
if (!secondValid(data, aidLoanFundConfig, asset)) { continue; }
// 助贷资金准入接口调用
boolean accessResult = false;
......@@ -209,6 +209,7 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
* @return
*/
private boolean secondValid(Map<String, Object> data, AidLoanFundConfig aidLoanFundConfig, Asset asset) {
boolean valid = true;
if ("970".equals(aidLoanFundConfig.getFundId()) && "1052".equals(aidLoanFundConfig.getFundProductId())) {
// 你我贷助贷资方
QGPreconditions.checkArgument(asset.getUserLoanType() != null, QGExceptionType.USER_LOAN_TYPE_IS_EMPTY, asset.getUuid());
......@@ -223,7 +224,25 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
}
}
}
} else if ("1050".equals(aidLoanFundConfig.getFundId()) && "1062".equals(aidLoanFundConfig.getFundProductId())) {
// 新橙
// 1、年龄22-55限制
Integer age = (Integer)data.get("user_age");
if (age == null || age.intValue() < 22 || age.intValue() > 55) {
valid = false;
}
return true;
// 2、新疆、青海、西藏、福建不导
String province = (String)data.get("user_province_code");
if (province == null || "65".equals(province) || "63".equals(province) || "54".equals(province) || "35".equals(province)) {
valid = false;
}
// 这里针对每个助贷资方单独打印一下为啥不导的日志
if (!valid) {
log.info("助贷资方导流, 用户命中二次校验规则, 不进行导流, uuid : {}, fundId : {}, fundProductId : {}, userAge : {}, province : {}",
asset.getUuid(), aidLoanFundConfig.getFundId(), aidLoanFundConfig.getFundProductId(), age, province);
}
}
return valid;
}
}
......@@ -44,6 +44,9 @@ public class AidFundInfoConfig implements Serializable {
@Column(name = "audit_url")
private String auditUrl;
@Column(name = "audit_result_url")
private String auditResultUrl;
@Column(name = "enable")
private Boolean enable;
......
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