Commit fce613a7 authored by liwenbin's avatar liwenbin

fix conflict

parents 1dc15f97 089c6ecc
...@@ -297,12 +297,11 @@ ...@@ -297,12 +297,11 @@
<version>2.1.5</version> <version>2.1.5</version>
</dependency> </dependency>
<!-- protobuf依赖--> <!-- protobuf依赖-->
<dependency> <dependency>
<groupId>com.google.protobuf</groupId> <groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId> <artifactId>protobuf-java</artifactId>
<version>3.6.0</version> <version>2.5.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.googlecode.protobuf-java-format</groupId> <groupId>com.googlecode.protobuf-java-format</groupId>
...@@ -319,7 +318,17 @@ ...@@ -319,7 +318,17 @@
<artifactId>druid</artifactId> <artifactId>druid</artifactId>
<version>1.1.10</version> <version>1.1.10</version>
</dependency> </dependency>
<!-- ocr hbase -->
<dependency>
<groupId>com.lkb.data</groupId>
<artifactId>lkb-data-service</artifactId>
<version>1.7.8.4-3c-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies> </dependencies>
</project> </project>
...@@ -11,19 +11,24 @@ import org.apache.http.conn.ConnectionKeepAliveStrategy; ...@@ -11,19 +11,24 @@ import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory; import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy; import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.util.ClassUtils;
import javax.net.ssl.*; import javax.net.ssl.*;
import java.io.IOException; import java.io.*;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.security.KeyManagementException; import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
...@@ -37,6 +42,9 @@ import java.security.cert.X509Certificate; ...@@ -37,6 +42,9 @@ import java.security.cert.X509Certificate;
@Configuration @Configuration
public class HttpClientConfig { public class HttpClientConfig {
@Value("${isDebug}")
private Boolean isDebug;
@Bean(name = "httpClient") @Bean(name = "httpClient")
public CloseableHttpClient httpClient() throws NoSuchAlgorithmException, KeyManagementException { public CloseableHttpClient httpClient() throws NoSuchAlgorithmException, KeyManagementException {
/** /**
...@@ -100,5 +108,71 @@ public class HttpClientConfig { ...@@ -100,5 +108,71 @@ public class HttpClientConfig {
.build(); .build();
} }
@Bean("niwodaiHttpsClient")
public CloseableHttpClient niwodaiHttpsClient() throws Exception {
/**
* 创建TrustManager
*/
X509TrustManager xtm = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
String classesPath = "/niwodai";
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(HttpClientConfig.class.getResourceAsStream(classesPath + "/qg-keystore" + (isDebug ? "-test" : "") +".jks"), "password".toCharArray());
KeyStore trustStore = KeyStore.getInstance("JKS");
trustStore.load(HttpClientConfig.class.getResourceAsStream(classesPath + "/qg-truststore" + (isDebug ? "-test" : "") +".jks"), "password".toCharArray());
SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
.loadKeyMaterial(keyStore, "password".toCharArray())
.build();
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslcontext,
new String[]{"TLSv1.2"},
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslConnectionSocketFactory)
.build();
// connection manager
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
connectionManager.setMaxTotal(10000);
connectionManager.setDefaultMaxPerRoute(1000);
HttpRequestRetryHandler retryHandler = new HttpRequestRetryHandler() {
@Override
public boolean retryRequest(IOException arg0, int retryTimes, HttpContext arg2) {
if (retryTimes >= 2)
return false;
if (arg0 instanceof UnknownHostException || arg0 instanceof ConnectTimeoutException
|| !(arg0 instanceof SSLException) || arg0 instanceof SocketTimeoutException)
return true;
HttpClientContext clientContext = HttpClientContext.adapt(arg2);
HttpRequest request = clientContext.getRequest();
if (!(request instanceof HttpEntityEnclosingRequest)) // 如果请求被认为是幂等的,那么就重试。即重复执行不影响程序其他效果的
return true;
return false;
}
};
// keep alive strategy
ConnectionKeepAliveStrategy keepAliveStrategy = new DefaultConnectionKeepAliveStrategy();
return HttpClients.custom()
.setConnectionManager(connectionManager)
.setRetryHandler(retryHandler)
.setKeepAliveStrategy(keepAliveStrategy)
.build();
}
} }
...@@ -77,7 +77,7 @@ public class ConsumerConfig implements RabbitListenerConfigurer { ...@@ -77,7 +77,7 @@ public class ConsumerConfig implements RabbitListenerConfigurer {
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); String nextOperateDate = getNextOperateDate(jo, noticeType);
iAidFundRouteRecordService.fundingResultNotity(applyNo,FundingResult.fromCode(noticeType)); // iAidFundRouteRecordService.fundingResultNotity(applyNo,FundingResult.fromCode(noticeType));
distributeService.receiveFundingResult(applyNo, FundingResult.fromCode(noticeType), nextOperateDate); 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));
} }
......
package com.quantgroup.asset.distribution.constant;
/**
* @author : Hyuk
* @description : AidFundConstants
* @date : 2020/3/27 5:09 下午
*/
public class AidFundConstants {
public static class FundId {
/**
* 你我贷
*/
public static final String NIWODAI = "970";
}
}
package com.quantgroup.asset.distribution.constant;
/**
* @author : Hyuk
* @description : AidFundIncomingStatus
* @date : 2020/3/30 11:04 上午
*/
public class AidFundStatus {
/**
* 进件状态
*/
public static class Incoming {
public static int REJECT = 0;
public static int PASS = 1;
// 资方审核中
public static int WAIT = 2;
// 保留状态,如果资方进件成功改为WAIT
public static int PRE = 3;
}
/**
* 路由状态
*/
public static class Route {
// 1-准入成功
public static int PRE_PASS = 1;
// 2-准入失败
public static int PRE_REJECT = 2;
// 3-进件完成
public static int INCOMING_COMPLETE = 3;
}
}
...@@ -26,4 +26,18 @@ public class RedisKeyConstants { ...@@ -26,4 +26,18 @@ public class RedisKeyConstants {
* 分发失败节点记录 * 分发失败节点记录
*/ */
public final static String DISTRIBUTE_FAIL_TYPE_RECORD = "ASSET.DISTRIBUTE.DISTRIBUTE.FAIL.TYPE.KEY.8SAWNB_"; public final static String DISTRIBUTE_FAIL_TYPE_RECORD = "ASSET.DISTRIBUTE.DISTRIBUTE.FAIL.TYPE.KEY.8SAWNB_";
/**
* 你我贷token
*/
public static final String NI_WO_DAI_TOKEN_KEY = "ASSET.DISTRIBUTE:NIWODAI:TOKEN:YHABEA";
/**
* 完成路由的资方缓存KEY
*/
public static final String FINISH_ROUTE_AID_FUND_KEY="ASSET.DISTRIBUTE:FINISH.ROUTE.AID.FUND.KEY.IJN9_";
/**
* 助贷资方审核订单缓存KEY
*/
public static final String AID_FUND_AUDIT_ORDER_KEY = "ASSET.DISTRIBUTE:AID_FUND_AUDIT_ORDER:BY_BIZ_NO_AND_FUND_ID:AKVVS3:";
} }
...@@ -3,20 +3,17 @@ package com.quantgroup.asset.distribution.controller; ...@@ -3,20 +3,17 @@ package com.quantgroup.asset.distribution.controller;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition; import com.quantgroup.asset.distribution.model.entity.fund.FundConfigCondition;
import org.apache.commons.collections.CollectionUtils; 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;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.google.common.base.Stopwatch; 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;
......
package com.quantgroup.asset.distribution.controller;
import com.alibaba.fastjson.JSON;
import com.quantgroup.asset.distribution.constant.AidFundConstants;
import com.quantgroup.asset.distribution.constant.AidFundStatus;
import com.quantgroup.asset.distribution.constant.StatusConstants;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.model.response.GlobalResponse;
import com.quantgroup.asset.distribution.service.alarm.IAlarmService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeRecordService;
import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeService;
import com.quantgroup.asset.distribution.service.funding.IAidFundAuditOrderService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiCostant;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiIncomingCallbackResponseVO;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiIncomingResultResponseVO;
import com.quantgroup.asset.distribution.service.notify.INotifyService;
import com.quantgroup.asset.distribution.service.product.IFinanceProductService;
import com.quantgroup.asset.distribution.service.redis.IRedisService;
import com.quantgroup.asset.distribution.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileNotFoundException;
import java.util.Map;
/**
* @author : Hyuk
* @description : NiWoDaiContraoller
* @date : 2020/3/27 2:12 下午
*/
@RestController
@Slf4j
@RequestMapping("/niwodai")
public class NiWoDaiController {
@Autowired
private IAidFundAuditOrderService aidFundAuditOrderService;
@Autowired
private IAlarmService alarmService;
@Autowired
private IAssetDistributeService assetDistributeService;
@Autowired
private IAssetDistributeRecordService assetDistributeRecordService;
@Autowired
private IFinanceProductService financeProductService;
@Autowired
private INotifyService notifyService;
@RequestMapping("/incoming/callback")
public GlobalResponse auditResultCallback(@RequestBody NiwodaiIncomingCallbackResponseVO responseVO) {
String orderId = responseVO.getOrderId();
String type = responseVO.getType();
Integer code = responseVO.getCode();
Long timestamp = responseVO.getTimestamp();
String data = responseVO.getData();
log.info("你我贷审核进件回调收到结果, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId,
type, code, timestamp, data);
AidLoanFundAuditOrder aidLoanFundAuditOrder = aidFundAuditOrderService.findByBizNoAndFundId(orderId, AidFundConstants.FundId.NIWODAI);
if (aidLoanFundAuditOrder == null) {
log.info("你我贷审核进件回调结果未找到订单, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId, type, code, timestamp, data);
alarmService.dingtalkAlarm("Error", "你我贷资方审核回调结果未找到订单", "bizNo : " + orderId + " , type : " + type + " , code : " + code + " , timestamp : " + timestamp + " , data : " + data);
return GlobalResponse.success();
}
if (aidLoanFundAuditOrder.getAuditResult().intValue() != AidFundStatus.Incoming.WAIT && aidLoanFundAuditOrder.getAuditResult().intValue() != AidFundStatus.Incoming.PRE) {
log.info("你我贷进件回调结果订单重复通知结果, 请查看, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId, type, code, timestamp, data);
return GlobalResponse.success();
}
if (!"APPLY".equals(type)) {
log.info("你我贷审核进件回调结果type出现错误, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId, type, code, timestamp , data);
alarmService.dingtalkAlarm("Error", "你我贷审核结果回调type错误", "bizNo : " + orderId + " , type : " + type + " , code : " + code + " , timestamp : " + timestamp + " , data : " + data);
return GlobalResponse.success();
}
if (code == null || (code.intValue() != 300005 && code.intValue() != 300006)) {
log.info("你我贷审核进件回调结果code出现错误, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId, type, code, timestamp , data);
alarmService.dingtalkAlarm("Error", "你我贷审核结果回调code出现错误", "bizNo : " + orderId + " , type : " + type + " , code : " + code + " , timestamp : " + timestamp + " , data : " + data);
return GlobalResponse.success();
}
AssetForm assetForm = JSON.parseObject(aidLoanFundAuditOrder.getAssetFormText(), AssetForm.class);
Asset asset = JSON.parseObject(aidLoanFundAuditOrder.getAssetText(), Asset.class);
Map<String, Object> dataMap = JSON.parseObject(aidLoanFundAuditOrder.getDataText(), Map.class);
if (300005 == code.intValue()) {
// 将助贷审核订单状态改为拒绝
aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.REJECT);
// 将分发记录改为失败
assetDistributeRecordService.updateAssetDistributeStatus(orderId, StatusConstants.FAIL);
// 重新进行分发
assetDistributeService.distribute(assetForm, asset, dataMap);
} else {
NiwodaiIncomingResultResponseVO vo = JSON.parseObject(data, NiwodaiIncomingResultResponseVO.class);
if (!checkIncomingResult(vo)) {
log.info("你我贷审核进件回调结果data出现错误, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId, type, code, timestamp, JSON.toJSONString(vo));
alarmService.dingtalkAlarm("Error", "你我贷审核结果回调data出现错误", "bizNo : " + orderId + " , type : " + type + " , code : " + code + " , timestamp : " + timestamp + " , data : " + data);
return GlobalResponse.success();
}
// 通过了直接通知资金系统
String finance = financeProductService.createSingletonFinanceProduct(vo.getApprovedAmount().toString(), String.valueOf(vo.getApproveTerm()), aidLoanFundAuditOrder.getFundId(), aidLoanFundAuditOrder.getFundProductId());
assetForm = financeProductService.checkFundResult(assetForm, finance, Long.parseLong(vo.getValidBefore()));
assetForm.setAmount(vo.getApprovedAmount().toString());
assetForm.setTerm(String.valueOf(vo.getApproveTerm()));
// 将助贷审核订单状态改为成功
aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.PASS);
notifyService.notifyFundServer(assetForm, dataMap);
}
log.info("你我贷审核进件回调结果处理完成, orderId : {}, type : {}, code : {}, timestamp : {}, data : {}", orderId,
type, code, timestamp, data);
return GlobalResponse.success();
}
/**
* 审核通过,检验参数
* @param vo
* @return
*/
private boolean checkIncomingResult(NiwodaiIncomingResultResponseVO vo) {
if (vo == null || vo.getApprovedAmount() == null || vo.getValidBefore() == null || vo.getApproveTerm() == null) {
return false;
}
return true;
}
public static void main(String[] args) throws FileNotFoundException {
System.out.println(ResourceUtils.getURL("classpath:").getPath());
}
}
...@@ -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.IAidLoanFundConfigService;
import com.quantgroup.asset.distribution.service.funding.IFundModuleLimitTypeService; 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;
...@@ -36,6 +37,8 @@ public class RedisFlushController { ...@@ -36,6 +37,8 @@ public class RedisFlushController {
private IAssetDistributeRuleConfigService assetDistributeRuleConfigService; private IAssetDistributeRuleConfigService assetDistributeRuleConfigService;
@Autowired @Autowired
private IFundModuleLimitTypeService limitTypeService; private IFundModuleLimitTypeService limitTypeService;
@Autowired
private IAidLoanFundConfigService aidLoanFundConfigService;
/** /**
* 助贷资金池刷新 * 助贷资金池刷新
...@@ -72,4 +75,13 @@ public class RedisFlushController { ...@@ -72,4 +75,13 @@ public class RedisFlushController {
if(authKey.equals(key)) { limitTypeService.clearCache(); } if(authKey.equals(key)) { limitTypeService.clearCache(); }
return GlobalResponse.success(); return GlobalResponse.success();
} }
@RequestMapping("/aid_loan_pool_flush")
public GlobalResponse AidLoanPoolFlush(String key) {
if(authKey.equals(key)) {
aidLoanFundConfigService.clearCache();
return GlobalResponse.success();
}
return GlobalResponse.error("authKey验证失败");
}
} }
package com.quantgroup.asset.distribution.enums;
import lombok.Getter;
/**
* @author : Hyuk
* @description : UserLoanType
* @date : 2020/3/26 7:10 下午
*/
public enum UserLoanType {
FIRST_APPLY(0, "首申"),
RE_APPLY(1, "复申"),
RE_LOAN(2, "复贷");
@Getter
private Integer code;
@Getter
private String title;
UserLoanType(Integer code, String title) {
this.code = code;
this.title = title;
}
}
...@@ -53,8 +53,19 @@ public enum QGExceptionType { ...@@ -53,8 +53,19 @@ public enum QGExceptionType {
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"), CHANNEL_FUND_CONFIG_GREATER_THAN_TOW(3005, "渠道资方有效配置大于2条,请检查; bizChannel : %s"),
HIT_FUND_BUT_AMOUNT_OR_TERM_IS_EMPTY(3006, "命中资方但额度或期数为空, 请检查!"); HIT_FUND_BUT_AMOUNT_OR_TERM_IS_EMPTY(3006, "命中资方但额度或期数为空, 请检查!"),
GET_USER_INFO_ERROR(3007, "用户中心获取用户信息异常!"),
USER_PHONE_NO_EMPTY(3008, "用户手机号为空"),
USER_ID_NO_EMPTY(3009, "用户身份证为空"),
USER_NAME_EMPTY(3010, "用户姓名为空"),
GET_NIWODAI_TOKEN_ERROR(3011, "获取你我贷token异常"),
NIWODAI_PRE_AUDIT_RESULAT_ERROR(3012, "你我贷准入接口返回结果异常, resposne : %s"),
NIWODAI_INCOMING_RESULT_ERROR(3013, "你我贷进件返回结果异常, resposne : % s"),
NIWODAI_INCOMING_AUDIT_RESULT_ERROR(3014, "你我贷进件审核返回结果异常, response : %s"),
OCR_DATA_MISS(3015,"OCR信息数据缺失,请核查"),
UNKNOW_AID_FUND_ID(3016, "未知的助贷资方, fundId : %s");
......
...@@ -25,8 +25,8 @@ public class AlarmServiceImpl implements IAlarmService{ ...@@ -25,8 +25,8 @@ public class AlarmServiceImpl implements IAlarmService{
private static final String ALARM_HTTP_URL = "http://alertserv-dataservice.quantgroup.cn/common/alert/dingtalk"; private static final String ALARM_HTTP_URL = "http://alertserv-dataservice.quantgroup.cn/common/alert/dingtalk";
private static final String ROBOT_WEB_HOOK = "https://oapi.dingtalk.com/robot/send?access_token=53a55ffe3d4a5398a7ba44e4fcee1a3ac006edcba9cfdc4b1f9f692ffc18a5b8"; private static final String ROBOT_WEB_HOOK = "https://oapi.dingtalk.com/robot/send?access_token=53a55ffe3d4a5398a7ba44e4fcee1a3ac006edcba9cfdc4b1f9f692ffc18a5b8";
@Value("${isDebug}") @Value("${alarmOpen}")
private Boolean isDebug; private Boolean alarmOpen;
@Autowired @Autowired
private IHttpService httpService; private IHttpService httpService;
...@@ -34,7 +34,7 @@ public class AlarmServiceImpl implements IAlarmService{ ...@@ -34,7 +34,7 @@ public class AlarmServiceImpl implements IAlarmService{
@Override @Override
public void dingtalkAlarm(String alarmLevel, String msgTitle, String msgContent) { public void dingtalkAlarm(String alarmLevel, String msgTitle, String msgContent) {
try { try {
if (isDebug) { return; } if (!alarmOpen) { return; }
Map<String, String> params = new HashMap<>(); Map<String, String> params = new HashMap<>();
params.put("webhook", ROBOT_WEB_HOOK); params.put("webhook", ROBOT_WEB_HOOK);
params.put("alarmLevel", alarmLevel); params.put("alarmLevel", alarmLevel);
......
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.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import com.quantgroup.asset.distribution.model.entity.fund.ChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.funding.IFundModuleChannelFundConfigNewService;
import com.quantgroup.asset.distribution.service.jpa.entity.FundModuleChannelFundConfigNew;
import com.quantgroup.asset.distribution.service.rule.vo.IRuleVO;
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;
import com.google.common.base.Stopwatch; import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.config.annotation.Attribute; import com.quantgroup.asset.distribution.config.annotation.Attribute;
import com.quantgroup.asset.distribution.enums.ExecuteType;
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;
...@@ -39,14 +16,19 @@ import com.quantgroup.asset.distribution.service.asset.IAssetAttributeService; ...@@ -39,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
...@@ -67,14 +49,6 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -67,14 +49,6 @@ public class AssetServiceImpl implements IAssetService{
private IAlarmService alarmService; private IAlarmService alarmService;
@Autowired @Autowired
private IDistributeFailLogService distributeFailLogService; private IDistributeFailLogService distributeFailLogService;
@Autowired
private IFundModuleChannelFundConfigNewService fundModuleChannelFundConfigNewService;
@Autowired
private IRuleService ruleService;
@Autowired
private IFinanceProductHitLogService financeProductHitLogService;
private static final ExecutorService executorPool = Executors.newFixedThreadPool(100);
@Async @Async
...@@ -92,12 +66,6 @@ public class AssetServiceImpl implements IAssetService{ ...@@ -92,12 +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);
// 资方配置空跑
doTestExecute(JSON.parseObject(JSON.toJSONString(assetForm), AssetForm.class), data);
// 如果使用资方模块则去命中资方,创建金融产品集
String hitFinanceProduct = hitFundIfUseFundModule(assetForm, data, ExecuteType.ONLINE);
// 资方模块结果处理
checkFundResult(assetForm, hitFinanceProduct);
// 资产分发 // 资产分发
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(),
......
...@@ -74,8 +74,8 @@ public class AssetDistributeRecordServiceImpl implements IAssetDistributeRecordS ...@@ -74,8 +74,8 @@ 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);
if (isDebug) { return; }
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 {
assetDistributeRecord.setAssetDistributeStatus(status); assetDistributeRecord.setAssetDistributeStatus(status);
......
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,28 @@ import com.quantgroup.asset.distribution.service.distribute.IAssetDistributeReco ...@@ -31,14 +21,28 @@ 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.product.IFinanceProductService;
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 +63,6 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -59,8 +63,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 +70,16 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -68,6 +70,16 @@ 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 IFinanceProductService financeProductService;
@Autowired
private IFinanceProductHitLogService financeProductHitLogService;
private static final ExecutorService executorPool = Executors.newFixedThreadPool(4);
/** /**
* 分发 * 分发
...@@ -92,13 +104,17 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -92,13 +104,17 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
if (valid) { if (valid) {
// 先创建记录,避免mq里消息来了就还没创建 // 先创建记录,避免mq里消息来了就还没创建
AssetDistributeRecord assetDistributeRecord = assetDistributeRecordService.saveDistributeRecord(asset, record, StatusConstants.WAIT, ruleType); AssetDistributeRecord assetDistributeRecord = assetDistributeRecordService.saveDistributeRecord(asset, record, StatusConstants.WAIT, ruleType);
int distributeStatus = beginDistribute(assetForm, asset, ruleType, assetDistributeRecord, data); int distributeStatus = beginDistribute(assetForm, asset, ruleType.intValue(), assetDistributeRecord, data);
// 分发成功 // 分发成功
if (distributeStatus == StatusConstants.SUCCESS || distributeStatus == StatusConstants.WAIT) { if (distributeStatus == StatusConstants.SUCCESS || distributeStatus == StatusConstants.WAIT) {
log.info("用户执行分发节点, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, ruleId : {}, ruleName : {}, distributeStatus : {}", log.info("用户执行分发节点, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, ruleId : {}, ruleName : {}, distributeStatus : {}",
assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getBizChannel(), ruleConfig.getId(), ruleConfig.getAssetDistributeRuleName(), assetForm.getUuid(), assetForm.getBizNo(), assetForm.getAssetNo(), assetForm.getBizChannel(), ruleConfig.getId(), ruleConfig.getAssetDistributeRuleName(),
distributeStatus); distributeStatus);
success = true; success = true;
} else if (distributeStatus == StatusConstants.FAIL) {
// 如果分发失败,直接更改状态
assetDistributeRecord.setAssetDistributeStatus(StatusConstants.FAIL);
assetDistributeRecordService.updateAssetDistribute(assetDistributeRecord);
} }
} }
// 保存节点尝试记录 // 保存节点尝试记录
...@@ -126,15 +142,20 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -126,15 +142,20 @@ 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);
// 资方模块结果处理
financeProductService.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); boolean response = aidFundRouteService.aidFundRoute(assetForm, asset, data);
int status = response.getCode() == 0 ? StatusConstants.SUCCESS : StatusConstants.FAIL; return response ? StatusConstants.WAIT : StatusConstants.FAIL;
// 助贷资金路由目前不从mq里接受终态
assetDistributeRecord.setAssetDistributeStatus(status);
assetDistributeRecordService.updateAssetDistribute(assetDistributeRecord);
return status;
} }
case DistributeConstants.RuleType.DIVERSION: case DistributeConstants.RuleType.DIVERSION:
notifyService.notifyFundServer(assetForm, data); notifyService.notifyFundServer(assetForm, data);
...@@ -210,7 +231,10 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -210,7 +231,10 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{
try { try {
Stopwatch stopwatch = Stopwatch.createStarted(); Stopwatch stopwatch = Stopwatch.createStarted();
// 1、更改分配记录状态 // 1、更改分配记录状态
if (fundingResult != FundingResult.HANG_UP) {
// HANG_UP不更改,
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, nextOperateDate); notifyService.notifyBusinessFlow(bizNo, fundingResult, nextOperateDate);
// 3、重新进行分发, 目前还没有,等接了助贷资金路由以后再增加 // 3、重新进行分发, 目前还没有,等接了助贷资金路由以后再增加
...@@ -225,4 +249,164 @@ public class AssetDistributeServiceImpl implements IAssetDistributeService{ ...@@ -225,4 +249,164 @@ 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 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.form.AssetForm;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import java.util.Map;
/**
* @author : Hyuk
* @description : IAidFundAssetService
* @date : 2020/3/27 5:07 下午
*/
public interface IAidFundAssetService {
/**
* 准入审核,预审
* @param assetForm
* @return
*/
public boolean preAudit(AssetForm assetForm, String fundId);
/**
* 进件审核
* @param assetForm
* @param data
* @param userLoanType
* @return true:进件成功 false:进件失败
*/
public boolean audit(AssetForm assetForm, Map<String, Object> data, Asset asset, String fundId);
}
package com.quantgroup.asset.distribution.service.funding;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
/**
* @author : Hyuk
* @description : IAidFundAuditOrderService
* @date : 2020/3/30 10:31 上午
*/
public interface IAidFundAuditOrderService {
public AidLoanFundAuditOrder saveAidFundAuditOrder(AidLoanFundAuditOrder aidLoanFundAuditOrder);
/**
* 更改助贷资金路由审核订单状态
* @param aidLoanFundAuditOrder
* @param status
* @return
*/
public AidLoanFundAuditOrder updateOrderStatus(AidLoanFundAuditOrder aidLoanFundAuditOrder, Integer status);
/**
* 根据三元素查找审核订单
* @param bizNo
* @param fundId
* @param auditResult
* @return
*/
public AidLoanFundAuditOrder findByBizNoAndFundId(String bizNo, String fundId);
}
...@@ -3,6 +3,10 @@ package com.quantgroup.asset.distribution.service.funding; ...@@ -3,6 +3,10 @@ package com.quantgroup.asset.distribution.service.funding;
import com.quantgroup.asset.distribution.enums.funding.FundingResult; import com.quantgroup.asset.distribution.enums.funding.FundingResult;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundRouteRecord; import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundRouteRecord;
import java.util.concurrent.TimeUnit;
import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.FINISH_ROUTE_AID_FUND_KEY;
/** /**
* Created by renfeng on 2019/7/17. * Created by renfeng on 2019/7/17.
*/ */
...@@ -11,20 +15,37 @@ public interface IAidFundRouteRecordService { ...@@ -11,20 +15,37 @@ public interface IAidFundRouteRecordService {
/** /**
* 资金分配结果通知 * 资金分配结果通知
*
* @param bizNo * @param bizNo
* @param fundingResult * @param fundingResult
*/ */
void fundingResultNotity(String bizNo,FundingResult fundingResult); void fundingResultNotity(String bizNo, FundingResult fundingResult);
/** /**
* 保存主贷资金路由记录 * 保存主贷资金路由记录
*
* @param aidLoanFundRouteRecord * @param aidLoanFundRouteRecord
*/ */
void saveAidLoanFundRouteRecord(AidLoanFundRouteRecord aidLoanFundRouteRecord); AidLoanFundRouteRecord saveAidLoanFundRouteRecord(AidLoanFundRouteRecord aidLoanFundRouteRecord);
/**
* 根据bizNo和fundId找路由记录
*
* @param bizNo
* @param fundId
* @return
*/
AidLoanFundRouteRecord findByBizNoAndFundId(String bizNo, String fundId);
/**
* 更改助贷资金路由记录状态
*
* @param aidLoanFundRouteRecord
* @param status
* @return
*/
AidLoanFundRouteRecord updateAidLoanFundRouteRecordStatus(AidLoanFundRouteRecord aidLoanFundRouteRecord, Integer status);
} }
...@@ -4,6 +4,7 @@ import java.util.Map; ...@@ -4,6 +4,7 @@ import java.util.Map;
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.jpa.entity.Asset;
/** /**
* Created by renfeng on 2019/7/17. * Created by renfeng on 2019/7/17.
...@@ -17,6 +18,6 @@ public interface IAidFundRouteService { ...@@ -17,6 +18,6 @@ public interface IAidFundRouteService {
* @param userLoanType * @param userLoanType
* @return * @return
*/ */
GlobalResponse aidFundRoute(AssetForm assetForm,Integer userLoanType, Map<String, Object> data); boolean aidFundRoute(AssetForm assetForm, Asset asset, Map<String, Object> data);
} }
...@@ -32,5 +32,5 @@ public interface IAidLoanFundConfigService { ...@@ -32,5 +32,5 @@ public interface IAidLoanFundConfigService {
*/ */
AidLoanFundConfig findByFundNo(String fundNo); AidLoanFundConfig findByFundNo(String fundNo);
void clearCache();
} }
package com.quantgroup.asset.distribution.service.funding;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
/**
* @author : Hyuk
* @description : IAidLOanFundUserTagService
* @date : 2020/4/28 10:43 上午
*/
public interface IAidLoanFundUserTagService {
public void saveUserTag(AssetForm assetForm, Asset asset, String fundId, String tagText);
}
package com.quantgroup.asset.distribution.service.funding.impl;
import com.quantgroup.asset.distribution.constant.AidFundConstants;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.funding.IAidFundAssetService;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @author : Hyuk
* @description : AidFundAssetServiceIMpl
* @date : 2020/3/27 5:22 下午
*/
@Slf4j
@Service
public class AidFundAssetServiceImpl implements IAidFundAssetService {
@Autowired
private INiwodaiAssetService niwodaiAssetService;
@Override
public boolean preAudit(AssetForm assetForm, String fundId) {
switch (fundId) {
case AidFundConstants.FundId.NIWODAI : {
return niwodaiAssetService.preAudit(assetForm.getUuid()).getPass().booleanValue();
}
default :
throw new QGException(QGExceptionType.UNKNOW_AID_FUND_ID);
}
}
@Override
public boolean audit(AssetForm assetForm, Map<String, Object> data, Asset asset, String fundId) {
switch (fundId) {
case AidFundConstants.FundId.NIWODAI : {
return niwodaiAssetService.incoming(assetForm, data, asset).getCode().equals(300007);
}
default :
throw new QGException(QGExceptionType.UNKNOW_AID_FUND_ID);
}
}
}
package com.quantgroup.asset.distribution.service.funding.impl;
import com.quantgroup.asset.distribution.constant.RedisKeyConstants;
import com.quantgroup.asset.distribution.service.funding.IAidFundAuditOrderService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
import com.quantgroup.asset.distribution.service.jpa.repository.IAidLoanFundAuditOrderRepository;
import com.quantgroup.asset.distribution.service.redis.IRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
/**
* @author : Hyuk
* @description : AidFundAuditOrderServiceIMpl
* @date : 2020/3/30 11:14 上午
*/
@Service
public class AidFundAuditOrderServiceImpl implements IAidFundAuditOrderService {
@Autowired
private IAidLoanFundAuditOrderRepository aidLoanFundAuditOrderRepository;
@Autowired
private IRedisService<AidLoanFundAuditOrder> redisService;
@Override
public AidLoanFundAuditOrder saveAidFundAuditOrder(AidLoanFundAuditOrder aidLoanFundAuditOrder) {
aidLoanFundAuditOrder = aidLoanFundAuditOrderRepository.save(aidLoanFundAuditOrder);
String key = RedisKeyConstants.AID_FUND_AUDIT_ORDER_KEY + aidLoanFundAuditOrder.getBizNo() + "_" + aidLoanFundAuditOrder.getFundId();
redisService.setEntityEx(key, aidLoanFundAuditOrder, 30, TimeUnit.MINUTES);
return aidLoanFundAuditOrder;
}
@Override
public AidLoanFundAuditOrder updateOrderStatus(AidLoanFundAuditOrder aidLoanFundAuditOrder, Integer status) {
aidLoanFundAuditOrder.setAuditResult(status);
return saveAidFundAuditOrder(aidLoanFundAuditOrder);
}
@Override
public AidLoanFundAuditOrder findByBizNoAndFundId(String bizNo, String fundId) {
String key = RedisKeyConstants.AID_FUND_AUDIT_ORDER_KEY + bizNo + "_" + fundId;
AidLoanFundAuditOrder aidLoanFundAuditOrder = redisService.getEntity(key);
if (aidLoanFundAuditOrder == null) {
aidLoanFundAuditOrder = aidLoanFundAuditOrderRepository.findByBizNoAndFundIdAndEnableIsTrue(bizNo, fundId);
if (aidLoanFundAuditOrder != null) {
redisService.setEntityEx(key, aidLoanFundAuditOrder, 30, TimeUnit.MINUTES);
}
}
return aidLoanFundAuditOrder;
}
}
...@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service; ...@@ -13,6 +13,7 @@ import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.AID_LOAN_COUNT_LIMIT_KEY; import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.AID_LOAN_COUNT_LIMIT_KEY;
import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.FINISH_ROUTE_AID_FUND_KEY;
/** /**
* Created by renfeng on 2019/7/19. * Created by renfeng on 2019/7/19.
...@@ -26,9 +27,8 @@ public class AidFundRouteRecordServiceImpl implements IAidFundRouteRecordService ...@@ -26,9 +27,8 @@ public class AidFundRouteRecordServiceImpl implements IAidFundRouteRecordService
@Autowired @Autowired
private IAidLoanFundRouteRecordRepository iAidLoanFundRouteRecordRepository; private IAidLoanFundRouteRecordRepository iAidLoanFundRouteRecordRepository;
@Autowired @Autowired
private IRedisService<String> redisService; private IRedisService<AidLoanFundRouteRecord> redisService;
/** /**
* 资金分配结果通知 * 资金分配结果通知
...@@ -59,9 +59,29 @@ public class AidFundRouteRecordServiceImpl implements IAidFundRouteRecordService ...@@ -59,9 +59,29 @@ public class AidFundRouteRecordServiceImpl implements IAidFundRouteRecordService
* @param aidLoanFundRouteRecord * @param aidLoanFundRouteRecord
*/ */
@Override @Override
public void saveAidLoanFundRouteRecord(AidLoanFundRouteRecord aidLoanFundRouteRecord) { public AidLoanFundRouteRecord saveAidLoanFundRouteRecord(AidLoanFundRouteRecord aidLoanFundRouteRecord) {
iAidLoanFundRouteRecordRepository.save(aidLoanFundRouteRecord); AidLoanFundRouteRecord record = iAidLoanFundRouteRecordRepository.save(aidLoanFundRouteRecord);
redisService.setEntityEx(FINISH_ROUTE_AID_FUND_KEY + record.getBizNo() + "_" + record.getFundId(),
record, 30, TimeUnit.MINUTES);
return record;
} }
@Override
public AidLoanFundRouteRecord findByBizNoAndFundId(String bizNo, String fundId) {
String key = FINISH_ROUTE_AID_FUND_KEY + bizNo + "_" + fundId;
AidLoanFundRouteRecord record = redisService.getEntity(key);
if (record == null) {
record = iAidLoanFundRouteRecordRepository.findByBizNoAndFundId(bizNo, fundId);
if (record != null) {
redisService.setEntityEx(key, record, 30, TimeUnit.MINUTES);
}
}
return record;
}
@Override
public AidLoanFundRouteRecord updateAidLoanFundRouteRecordStatus(AidLoanFundRouteRecord aidLoanFundRouteRecord, Integer status) {
aidLoanFundRouteRecord.setAidFundRouteStatus(status);
return saveAidLoanFundRouteRecord(aidLoanFundRouteRecord);
}
} }
package com.quantgroup.asset.distribution.service.funding.impl; package com.quantgroup.asset.distribution.service.funding.impl;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import com.google.common.base.Stopwatch;
import com.quantgroup.asset.distribution.constant.AidFundStatus;
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.funding.IAidFundRouteRecordService; import com.quantgroup.asset.distribution.service.funding.*;
import com.quantgroup.asset.distribution.service.funding.IAidFundRouteService; import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
import com.quantgroup.asset.distribution.service.funding.IAidLoanFundConfigService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundConfig; import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundConfig;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundRouteRecord; import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundRouteRecord;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.jpa.repository.ICustomerTypeRuleConfigRepository;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService;
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.util.DateUtil; import com.quantgroup.asset.distribution.util.DateUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.CollectionUtils;
...@@ -25,8 +29,7 @@ import java.util.TreeSet; ...@@ -25,8 +29,7 @@ import java.util.TreeSet;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.AID_LOAN_ALL_AMOUNT_LIMIT_KEY; import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.*;
import static com.quantgroup.asset.distribution.constant.RedisKeyConstants.AID_LOAN_COUNT_LIMIT_KEY;
/** /**
* Created by renfeng on 2019/7/19. * Created by renfeng on 2019/7/19.
...@@ -42,23 +45,30 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService { ...@@ -42,23 +45,30 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
private IAidFundRouteRecordService iAidFundRouteRecordService; private IAidFundRouteRecordService iAidFundRouteRecordService;
@Autowired @Autowired
private IRedisService<String> redisService; private IRedisService<String> redisService;
@Autowired @Autowired
private IRedisService<AssetForm> redisServiceAssetForm; private IRedisService<AidLoanFundRouteRecord> redisRouteRecord;
@Autowired
private IRuleService ruleService;
@Autowired @Autowired
private IHttpService iHttpService; private ICustomerTypeRuleConfigRepository iCustomerTypeRuleConfigRepository;
@Autowired
private IAidFundAssetService aidFundAssetService;
@Autowired
private IAidFundAuditOrderService aidFundAuditOrderService;
/** /**
* 助贷资金路由 * 助贷资金路由
* *
* @param assetForm * @param assetForm
* @param userLoanType * @param asset
* @param data
* @return * @return
*/ */
@Override @Override
public GlobalResponse aidFundRoute(AssetForm assetForm,Integer userLoanType, Map<String, Object> data) { public boolean aidFundRoute(AssetForm assetForm, Asset asset, Map<String, Object> data) {
Stopwatch started = Stopwatch.createStarted();
//第一步 查询所有助贷资金 //第一步 查询所有助贷资金
List<AidLoanFundConfig> aidLoanFundConfigList = iAidLoanFundConfigService.findAll(); List<AidLoanFundConfig> aidLoanFundConfigList = iAidLoanFundConfigService.findAll();
log.info("助贷资金路由开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList)); log.info("助贷资金路由开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList));
...@@ -73,53 +83,115 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService { ...@@ -73,53 +83,115 @@ public class AidFundRouteServiceImpl implements IAidFundRouteService {
.filter(aidLoanFundConfig->aidLoanFundConfig.getFundCountLimit() >=redisService.setIncr(AID_LOAN_COUNT_LIMIT_KEY + DateUtil.getDay(), 0, 3, TimeUnit.DAYS)) .filter(aidLoanFundConfig->aidLoanFundConfig.getFundCountLimit() >=redisService.setIncr(AID_LOAN_COUNT_LIMIT_KEY + DateUtil.getDay(), 0, 3, TimeUnit.DAYS))
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
//第四步 限制总额度筛选 //第四步 限制总额度筛选 额度筛选暂时没有用到
if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){ // if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){
// 获取已放款总金额 AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay() //TODO 放redis // // 获取已放款总金额 AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay() //TODO 放redis
String allAmount = redisService.getString(AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay()); // String allAmount = redisService.getString(AID_LOAN_ALL_AMOUNT_LIMIT_KEY + DateUtil.getDay());
aidLoanFundConfigList = aidLoanFundConfigList.parallelStream() // aidLoanFundConfigList = aidLoanFundConfigList.parallelStream()
.filter(aidLoanFundConfig->new BigDecimal(aidLoanFundConfig.getFundAllAmountLimit()).compareTo(new BigDecimal(StringUtils.isEmpty(allAmount)?"0":allAmount))>0) // .filter(aidLoanFundConfig->new BigDecimal(aidLoanFundConfig.getFundAllAmountLimit()).compareTo(new BigDecimal(StringUtils.isEmpty(allAmount)?"0":allAmount))>0)
.collect(Collectors.toList()); // .collect(Collectors.toList());
} // }
//第五步 开始路由 //第五步 开始路由
if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){ if(CollectionUtils.isNotEmpty(aidLoanFundConfigList)){
log.info("助贷资金优先级筛选开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList)); log.info("助贷资金优先级筛选开始, uuid : {} , bizNo : {} ,助贷资金池 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(aidLoanFundConfigList));
//按优先级排序 //按优先级排序
TreeSet<AidLoanFundConfig> aidLoanFundConfigSet = new TreeSet<>(Comparator.comparing(AidLoanFundConfig::getFundPriority)); TreeSet<AidLoanFundConfig> aidLoanFundConfigSet = new TreeSet<AidLoanFundConfig>(Comparator.comparing(AidLoanFundConfig::getFundPriority));
aidLoanFundConfigSet.addAll(aidLoanFundConfigList); aidLoanFundConfigSet.addAll(aidLoanFundConfigList);
AidLoanFundConfig first = aidLoanFundConfigSet.first();
log.info("助贷资金筛选完成, uuid : {} , bizNo : {} ,助贷资金 : {} ",assetForm.getUuid(),assetForm.getBizNo(),JSON.toJSONString(first));
for(AidLoanFundConfig aidLoanFundConfig : aidLoanFundConfigSet){
//保存主贷资金路由记录 //此助贷资方如果已经被这笔订单路由过 就跳过
AidLoanFundRouteRecord aidLoanFundRouteRecord = new AidLoanFundRouteRecord(); AidLoanFundRouteRecord aidLoanFundRouteRecord = iAidFundRouteRecordService.findByBizNoAndFundId(assetForm.getBizNo(), aidLoanFundConfig.getFundId());
aidLoanFundRouteRecord.setAidFundRouteStatus(1);//1-未完成 2-成功 3-失败 int status = aidLoanFundRouteRecord == null ? -1 : aidLoanFundRouteRecord.getAidFundRouteStatus().intValue();
if (status == AidFundStatus.Route.INCOMING_COMPLETE || status == AidFundStatus.Route.PRE_REJECT) {
// 进件完成和准入拒绝的直接跳过
continue;
}
//助贷资金分配规则校验
if(ruleService.valid(aidLoanFundConfig.getFundRuleEl(), data)){
// 助贷资金准入接口调用
boolean accessResult = false;
if (status == AidFundStatus.Route.PRE_PASS) {
accessResult = true;
} else {
accessResult = aidFundAssetService.preAudit(assetForm, aidLoanFundConfig.getFundId());
// 保存主贷资金路由记录
aidLoanFundRouteRecord = new AidLoanFundRouteRecord();
aidLoanFundRouteRecord.setAidFundRouteStatus(accessResult ? AidFundStatus.Route.PRE_PASS : AidFundStatus.Route.PRE_REJECT);//1-准入成功 2-准入失败 3-进件完成
aidLoanFundRouteRecord.setAssetNo(assetForm.getAssetNo()); aidLoanFundRouteRecord.setAssetNo(assetForm.getAssetNo());
aidLoanFundRouteRecord.setUuid(assetForm.getUuid()); aidLoanFundRouteRecord.setUuid(assetForm.getUuid());
aidLoanFundRouteRecord.setBizChannel(assetForm.getBizChannel()); aidLoanFundRouteRecord.setBizChannel(assetForm.getBizChannel());
aidLoanFundRouteRecord.setBizNo(assetForm.getBizNo()); aidLoanFundRouteRecord.setBizNo(assetForm.getBizNo());
aidLoanFundRouteRecord.setFinanceProductType(Integer.parseInt(assetForm.getBizType())); aidLoanFundRouteRecord.setFinanceProductType(Integer.parseInt(assetForm.getBizType()));
aidLoanFundRouteRecord.setUserLoanType(userLoanType); aidLoanFundRouteRecord.setUserLoanType(asset.getUserLoanType());
aidLoanFundRouteRecord.setFundNo(first.getFundNo()); aidLoanFundRouteRecord.setFundNo(aidLoanFundConfig.getFundNo());
aidLoanFundRouteRecord.setFundId(first.getFundId()); aidLoanFundRouteRecord.setFundId(aidLoanFundConfig.getFundId());
aidLoanFundRouteRecord.setFundProductId(aidLoanFundConfig.getFundProductId());
aidLoanFundRouteRecord.setEnable(true); aidLoanFundRouteRecord.setEnable(true);
iAidFundRouteRecordService.saveAidLoanFundRouteRecord(aidLoanFundRouteRecord); aidLoanFundRouteRecord = iAidFundRouteRecordService.saveAidLoanFundRouteRecord(aidLoanFundRouteRecord);
//通知资方
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.transToNotifyMap(data))); log.info("助贷资金路由-准入完成, bizChannel : {} , uuid : {} , bizNo : {} , fundId : {} , fundProductId : {} , 准入结果 : {} , 耗时 : {}",assetForm.getBizChannel(),assetForm.getUuid(),assetForm.getBizNo(),aidLoanFundRouteRecord.getFundId(),aidLoanFundRouteRecord.getFundProductId(),accessResult,started.elapsed(TimeUnit.MILLISECONDS));
if(response==null || response.size()==0 || !"200".equals(response.get("statusCode")) || "error".equals(response.get("response"))) {
assetForm.setRepeatCount(assetForm.getRepeatCount() + 1);
redisServiceAssetForm.rightPushEx("AID.LOAN.FUND.ROUTE.NOTIFY.83IUE",assetForm,1, TimeUnit.DAYS);
log.info("助贷资金路由-通知资金系统失败,response :{}, uuid : {} , bizNo : {} , callbackUrl:{},params:{}", JSON.toJSONString(response),assetForm.getUuid(),assetForm.getBizNo(),assetForm.getCallbackUrl(), JSON.toJSONString(assetForm));
} }
return GlobalResponse.success(); if(accessResult){
//客户类别区分 1-自然流量 2-拒绝流量 留在这里 你我贷暂时不用 等以后要用时 随时可用
// int customerType = 0 ;
// List<CustomerTypeRuleConfig> byEnableTrue = iCustomerTypeRuleConfigRepository.findByEnableTrue();
// if(CollectionUtils.isNotEmpty(byEnableTrue)) {
// for (CustomerTypeRuleConfig customerTypeRuleConfig : byEnableTrue) {
// if (ruleService.valid(customerTypeRuleConfig.getCustomerTypeRuleEl(), data)) {
// customerType = customerTypeRuleConfig.getCustomerType();
// }
// }
// }
// 先创建进件订单记录
AidLoanFundAuditOrder aidLoanFundAuditOrder = createAidFundAuditOrder(aidLoanFundRouteRecord, assetForm, asset, data);
// 调用助贷资方进件接口 异步
boolean incomingResult = aidFundAssetService.audit(assetForm, data, asset, aidLoanFundConfig.getFundId());
// 将助贷路由记录状态改为进件完成
iAidFundRouteRecordService.updateAidLoanFundRouteRecordStatus(aidLoanFundRouteRecord, AidFundStatus.Route.INCOMING_COMPLETE);
log.info("助贷资金路由-进件完成, bizChannel : {} , uuid : {} , bizNo : {} , fundId : {} , fundProductId : {} , 进件结果 : {}, 耗时 : {} ",assetForm.getBizChannel(),assetForm.getUuid(),assetForm.getBizNo(),aidLoanFundRouteRecord.getFundId(),aidLoanFundRouteRecord.getFundProductId(),incomingResult,started.stop().elapsed(TimeUnit.MILLISECONDS));
if (incomingResult) {
aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.WAIT);
return true;
} else {
aidFundAuditOrderService.updateOrderStatus(aidLoanFundAuditOrder, AidFundStatus.Incoming.REJECT);
}
}
}
}
}
return false;
}
/**
* 创建资方审核订单
* @param aidLoanFundRouteRecord
* @param assetForm
* @param asset
* @param data
*/
private AidLoanFundAuditOrder createAidFundAuditOrder(AidLoanFundRouteRecord aidLoanFundRouteRecord, AssetForm assetForm, Asset asset, Map<String, Object> data) {
AidLoanFundAuditOrder aidLoanFundAuditOrder = aidFundAuditOrderService.findByBizNoAndFundId(assetForm.getBizNo(), aidLoanFundRouteRecord.getFundId());
if (aidLoanFundAuditOrder != null) {
log.info("助贷资方审核订单已存在, 直接返回订单, uuid : {}, bizNo : {}, assetNo : {}, bizChannel : {}, orderStatus : {}", assetForm.getUuid(), assetForm.getBizNo(),
assetForm.getAssetNo(), assetForm.getBizChannel(), aidLoanFundAuditOrder.getAuditResult());
return aidLoanFundAuditOrder;
} }
return GlobalResponse.error("未匹配到助贷资金"); aidLoanFundAuditOrder = new AidLoanFundAuditOrder();
aidLoanFundAuditOrder.setAssetNo(asset.getAssetNo());
aidLoanFundAuditOrder.setFundNo(aidLoanFundRouteRecord.getFundNo());
aidLoanFundAuditOrder.setUuid(assetForm.getUuid());
aidLoanFundAuditOrder.setBizNo(assetForm.getBizNo());
aidLoanFundAuditOrder.setFundId(aidLoanFundRouteRecord.getFundId());
aidLoanFundAuditOrder.setFundProductId(aidLoanFundRouteRecord.getFundProductId());
aidLoanFundAuditOrder.setAssetFormText(JSON.toJSONString(assetForm));
aidLoanFundAuditOrder.setAssetText(JSON.toJSONString(asset));
aidLoanFundAuditOrder.setDataText(JSON.toJSONString(data));
aidLoanFundAuditOrder.setAuditResult(AidFundStatus.Incoming.PRE);
aidLoanFundAuditOrder.setEnable(true);
return aidFundAuditOrderService.saveAidFundAuditOrder(aidLoanFundAuditOrder);
} }
} }
...@@ -77,4 +77,9 @@ public class AidLoanFundConfigServiceImpl implements IAidLoanFundConfigService { ...@@ -77,4 +77,9 @@ public class AidLoanFundConfigServiceImpl implements IAidLoanFundConfigService {
public AidLoanFundConfig findByFundNo(String fundNo) { public AidLoanFundConfig findByFundNo(String fundNo) {
return iAidLoanFundConfigRepository.findByFundNo(fundNo); return iAidLoanFundConfigRepository.findByFundNo(fundNo);
} }
@Override
public void clearCache() {
redisService.del(AID_LOAN_POOLKEYS_HMSET_KEY);
}
} }
package com.quantgroup.asset.distribution.service.funding.impl;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.funding.IAidLoanFundUserTagService;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundUserTag;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.jpa.repository.IAidLoanFundUserTagRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import java.io.Serializable;
/**
* @author : Hyuk
* @description : AidLoanFundUserTagServiceImpl
* @date : 2020/4/28 10:44 上午
*/
@Slf4j
@Service
public class AidLoanFundUserTagServiceImpl implements IAidLoanFundUserTagService {
@Autowired
private IAidLoanFundUserTagRepository aidLoanFundUserTagRepository;
@Async
@Override
public void saveUserTag(AssetForm assetForm, Asset asset, String fundId, String tagText) {
AidLoanFundUserTag aidLoanFundUserTag = new AidLoanFundUserTag();
aidLoanFundUserTag.setAssetNo(asset.getAssetNo());
aidLoanFundUserTag.setUuid(assetForm.getUuid());
aidLoanFundUserTag.setBizNo(assetForm.getBizNo());
aidLoanFundUserTag.setFundId(fundId);
aidLoanFundUserTag.setTagText(tagText);
aidLoanFundUserTag.setEnable(true);
aidLoanFundUserTagRepository.save(aidLoanFundUserTag);
}
}
...@@ -78,4 +78,8 @@ public interface IHttpService { ...@@ -78,4 +78,8 @@ public interface IHttpService {
public Map<String,String> postHasResponse(String url, Map<String, String> parameters); public Map<String,String> postHasResponse(String url, Map<String, String> parameters);
public String post(String uri, Map<String, String> headers,Map<String, String> parameters,boolean isLog,int timeOut); public String post(String uri, Map<String, String> headers,Map<String, String> parameters,boolean isLog,int timeOut);
String postNiwodai(String uri, Map<String, String> headers, Map<String, String> parameters, boolean isLog);
String postNiwodaiJson(String uri, Map<String, String> headers, String jsonParams, boolean isLog);
} }
...@@ -47,6 +47,9 @@ public class HttpServiceImpl implements IHttpService { ...@@ -47,6 +47,9 @@ public class HttpServiceImpl implements IHttpService {
@Autowired @Autowired
@Qualifier("httpClient") @Qualifier("httpClient")
private CloseableHttpClient httpClient; private CloseableHttpClient httpClient;
@Autowired
@Qualifier("niwodaiHttpsClient")
private CloseableHttpClient niwodaiHttpsClient;
@Override @Override
public String get(String uri) { public String get(String uri) {
...@@ -275,6 +278,73 @@ public class HttpServiceImpl implements IHttpService { ...@@ -275,6 +278,73 @@ public class HttpServiceImpl implements IHttpService {
IOUtils.closeQuietly(httpResponse); IOUtils.closeQuietly(httpResponse);
} }
} }
@Override
public String postNiwodai(String uri, Map<String, String> headers, Map<String, String> parameters, boolean isLog) {
return doniwodaiHttps(RequestBuilder.post(),uri,headers,parameters,isLog,TIME_OUT_60);
}
@Override
public String postNiwodaiJson(String uri,Map<String, String> headers, String jsonParams,boolean isLog) {
return doniwodaiObjectHttps(RequestBuilder.post(),uri,headers,jsonParams,isLog,TIME_OUT_60);
}
public String doniwodaiObjectHttps(RequestBuilder requestBuilder, String uri, Map<String, String> headers, String jsonParams, boolean isLog, int timeOut){
String method = requestBuilder.getMethod();
HttpEntity httpEntity = null;
CloseableHttpResponse httpResponse = null;
try {
requestBuilder.setUri(uri);
this.setConfig(requestBuilder,timeOut);
this.setHeader(requestBuilder, headers);
this.setParameter(requestBuilder, jsonParams);
httpResponse = niwodaiHttpsClient.execute(requestBuilder.build());
int statusCode = httpResponse.getStatusLine().getStatusCode();
String response = null;
if(statusCode==200){
httpEntity = httpResponse.getEntity();
response = EntityUtils.toString(httpEntity, "UTF-8");
}
if(isLog) {
LOGGER.info("{}, uri:{},parameters:{},response:{},statusCode:{}", method, uri, jsonParams,response,statusCode);
}
return response;
} catch (Exception e) {
LOGGER.error("{}, uri:{}, parameters:{}", method, uri, jsonParams, e);
return null;
} finally {
EntityUtils.consumeQuietly(httpEntity);
IOUtils.closeQuietly(httpResponse);
}
}
public String doniwodaiHttps(RequestBuilder requestBuilder, String uri, Map<String, String> headers, Map<String, String> parameters, boolean isLog, int timeOut){
String method = requestBuilder.getMethod();
HttpEntity httpEntity = null;
CloseableHttpResponse httpResponse = null;
try {
requestBuilder.setUri(uri);
this.setConfig(requestBuilder,timeOut);
this.setHeader(requestBuilder, headers);
this.setParameter(requestBuilder, parameters);
httpResponse = niwodaiHttpsClient.execute(requestBuilder.build());
int statusCode = httpResponse.getStatusLine().getStatusCode();
String response = null;
if(statusCode==200){
httpEntity = httpResponse.getEntity();
response = EntityUtils.toString(httpEntity, "UTF-8");
}
if(isLog)
LOGGER.info("{}, uri:{},parameters:{},response:{},statusCode:{}", method, uri, parameters,response,statusCode);
return response;
} catch (Exception e) {
LOGGER.error("{}, uri:{}, parameters:{}", method, uri, parameters, e);
return null;
} finally {
EntityUtils.consumeQuietly(httpEntity);
IOUtils.closeQuietly(httpResponse);
}
}
/** /**
* Set Parameter * Set Parameter
* *
......
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 : AidLoanFundAuditOrder
* @date : 2020/3/30 1:28 上午
*/
@Entity
@Table(name="aid_loan_fund_audit_order")
@Data
public class AidLoanFundAuditOrder implements Serializable {
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "asset_no")
private String assetNo;
@Column(name = "fund_no")
private String fundNo;
@Column(name = "uuid")
private String uuid;
@Column(name = "biz_no")
private String bizNo;
@Column(name = "fund_id")
private String fundId;
@Column(name = "fund_product_id")
private String fundProductId;
@Column(name = "asset_form_text")
private String assetFormText;
@Column(name = "asset_text")
private String assetText;
@Column(name = "data_text")
private String dataText;
// 1-通过,2-拒绝,3-审核中
@Column(name = "audit_result")
private Integer auditResult;
@Column(name = "audit_context")
private String auditContext;
@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());
}
}
...@@ -45,9 +45,15 @@ public class AidLoanFundConfig implements Serializable{ ...@@ -45,9 +45,15 @@ public class AidLoanFundConfig implements Serializable{
@Column(name="fund_id") @Column(name="fund_id")
private String fundId; private String fundId;
@Column(name = "fund_product_id")
private String fundProductId;
@Column(name="fund_all_amount_limit") @Column(name="fund_all_amount_limit")
private String fundAllAmountLimit; private String fundAllAmountLimit;
@Column(name="fund_rule_el")
private String fundRuleEl;
@Column(name = "enable") @Column(name = "enable")
private Boolean enable; private Boolean enable;
......
...@@ -48,6 +48,9 @@ public class AidLoanFundRouteRecord implements Serializable{ ...@@ -48,6 +48,9 @@ public class AidLoanFundRouteRecord implements Serializable{
@Column(name="fund_id") @Column(name="fund_id")
private String fundId; private String fundId;
@Column(name = "fund_product_id")
private String fundProductId;
@Column(name="aid_fund_route_no") @Column(name="aid_fund_route_no")
private String aidFundRouteNo; private String aidFundRouteNo;
......
package com.quantgroup.asset.distribution.service.jpa.entity;
import lombok.Data;
import javax.persistence.*;
import java.sql.Timestamp;
/**
* @author : Hyuk
* @description : AidLoanFundUserTag
* @date : 2020/4/28 10:38 上午
*/
@Entity
@Table(name="aid_loan_fund_user_tag")
@Data
public class AidLoanFundUserTag {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "asset_no")
private String assetNo;
@Column(name = "uuid")
private String uuid;
@Column(name = "biz_no")
private String bizNo;
@Column(name = "fund_id")
private String fundId;
@Column(name = "tag_text")
private String tagText;
@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());
}
}
package com.quantgroup.asset.distribution.service.jpa.entity;
import lombok.Data;
import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
/**
* Created by renfeng on 2020/3/24.
*/
@Entity
@Table(name="customer_type_rule_config")
@Data
public class CustomerTypeRuleConfig implements Serializable{
private static final long serialVersionUID = -1L;
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name="customer_type_rule_no")
private String customerTypeRuleNo;
@Column(name="customer_type_rule_desc")
private String customerTypeRuleDesc;
@Column(name="customer_type")
private Integer customerType;
@Column(name="customer_type_rule_el")
private String customerTypeRuleEl;
@Column(name = "enable")
private Boolean enable;
@Column(name="created_by")
private String createdBy;
@Column(name="updated_by")
private String updatedBy;
@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());
}
}
package com.quantgroup.asset.distribution.service.jpa.repository;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundAuditOrder;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author : Hyuk
* @description : IAidLoanFundAuditOrderRepository
* @date : 2020/3/30 1:34 上午
*/
public interface IAidLoanFundAuditOrderRepository extends JpaRepository<AidLoanFundAuditOrder, Long> {
/**
* 根据三元素查找订单
* @param bizNo
* @param fundId
* @param auditResult
* @return
*/
public AidLoanFundAuditOrder findByBizNoAndFundIdAndEnableIsTrue(String bizNo, String fundId);
}
...@@ -13,5 +13,5 @@ public interface IAidLoanFundRouteRecordRepository extends JpaRepository<AidLoan ...@@ -13,5 +13,5 @@ public interface IAidLoanFundRouteRecordRepository extends JpaRepository<AidLoan
AidLoanFundRouteRecord findByBizNoAndAidFundRouteStatus(String bizNo,Integer aidFundRouteStatus); AidLoanFundRouteRecord findByBizNoAndAidFundRouteStatus(String bizNo,Integer aidFundRouteStatus);
AidLoanFundRouteRecord findByBizNoAndFundId(String bizNo, String fundId);
} }
package com.quantgroup.asset.distribution.service.jpa.repository;
import com.quantgroup.asset.distribution.service.jpa.entity.AidLoanFundUserTag;
import org.springframework.data.jpa.repository.JpaRepository;
/**
* @author : Hyuk
* @description : IAidLoanFundUserTag
* @date : 2020/4/28 10:42 上午
*/
public interface IAidLoanFundUserTagRepository extends JpaRepository<AidLoanFundUserTag, Long> {
}
package com.quantgroup.asset.distribution.service.jpa.repository;
import com.quantgroup.asset.distribution.service.jpa.entity.CustomerTypeRuleConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
/**
* Created by renfeng on 2019/7/17.
*/
public interface ICustomerTypeRuleConfigRepository extends JpaRepository<CustomerTypeRuleConfig, Long>{
List<CustomerTypeRuleConfig> findByEnableTrue();
}
package com.quantgroup.asset.distribution.service.niwodai;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiDataImportCheckResponseVO;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiIncomingResponseVO;
import com.quantgroup.asset.distribution.service.niwodai.vo.NiwodaiIncomingResultResponseVO;
import java.util.Map;
public interface INiwodaiAssetService {
NiwodaiIncomingResultResponseVO incomingResult(String orderId);
NiwodaiDataImportCheckResponseVO preAudit(String uuid);
NiwodaiIncomingResponseVO incoming(AssetForm assetForm, Map<String, Object> data, Asset asset);
Map<String,Object> queryUserBasic2Info(String userId, String phoneNo, boolean isQuery);
}
package com.quantgroup.asset.distribution.service.niwodai;
import com.quantgroup.asset.distribution.service.niwodai.vo.*;
public interface INiwodaiService {
NiwodaiDataImportCheckResponseVO dataImportCheck(NiwodaiDataImportCheckRequestVO requestVO, String uuid);
NiwodaiIncomingResponseVO incoming(NiwodaiIncomingRequestVO niwodaiIncomingRequestVO, String uuid);
NiwodaiIncomingResultResponseVO incoingResult(NiwodaiIncomingResultRequestVO requestVO);
}
package com.quantgroup.asset.distribution.service.niwodai.impl;
import cn.quantgroup.motan.bean.UserInfo;
import cn.quantgroup.motan.vo.UserSysResult;
import cn.quantgroup.user.IUserSdkService;
import cn.quantgroup.user.UserSdkServiceFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Stopwatch;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.lkb.data.hbase.dataservice.verify.OCRIdCardDataService;
import com.lkb.data.hbase.row.verify.OCRIdCardRow;
import com.quantgroup.asset.distribution.constant.AidFundConstants;
import com.quantgroup.asset.distribution.enums.UserLoanType;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.funding.IAidLoanFundUserTagService;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiService;
import com.quantgroup.asset.distribution.service.niwodai.vo.*;
import javafx.scene.paint.Stop;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class NiwodaiAssetServiceImpl implements INiwodaiAssetService {
@Autowired
private IAidLoanFundUserTagService aidLoanFundUserTagService;
@Autowired
IHttpService iHttpService;
@Autowired
@Qualifier("httpClient")
private CloseableHttpClient httpClient;
@Autowired
private INiwodaiService niwodaiService;
@Value("${user.sdk.url}")
private String userSysUrl;
private IUserSdkService userSdkService;
private static Gson GSON = new Gson();
@PostConstruct
private void init() {
userSdkService = UserSdkServiceFactory.generateSDKService(userSysUrl, httpClient);
}
@Override
public NiwodaiIncomingResultResponseVO incomingResult(String orderId){
NiwodaiIncomingResultRequestVO vo = new NiwodaiIncomingResultRequestVO();
vo.setOrderId(orderId);
return niwodaiService.incoingResult(vo);
}
@Override
public NiwodaiDataImportCheckResponseVO preAudit(String uuid) {
NiwodaiDataImportCheckRequestVO requestVO = new NiwodaiDataImportCheckRequestVO();
UserSysResult<UserInfo> userInfoByUuid = userSdkService.findUserInfoByUuid(uuid);
if (!userInfoByUuid.isSuccess()){
log.error("你我贷准入检查获取用户中心信息失败 uuid : {}",uuid);
throw new QGException(QGExceptionType.GET_USER_INFO_ERROR);
}
String phoneNo = userInfoByUuid.getData().getPhoneNo();
if (phoneNo.startsWith("170") || phoneNo.startsWith("171")) {
log.info("你我贷准入检查, 用户手机号段过滤, uuid : {}, phone : {}", uuid, phoneNo);
return NiwodaiDataImportCheckResponseVO.createPassFalse();
}
requestVO.setPhone(getPhoneNoMask(phoneNo));
requestVO.setIdcardNumber(getIdNoMask(userInfoByUuid.getData().getIdNo()));
requestVO.setRealName(userInfoByUuid.getData().getName());
Stopwatch stopwatch = Stopwatch.createStarted();
NiwodaiDataImportCheckResponseVO responseVO = niwodaiService.dataImportCheck(requestVO, uuid);
log.info("你我贷准入接口调用完成, uuid : {}, requestVo : {}, responseVo : {}, 耗时 : {}", uuid, JSON.toJSONString(requestVO), JSON.toJSONString(responseVO), stopwatch.stop().elapsed(TimeUnit.SECONDS));
return responseVO;
}
@Override
public NiwodaiIncomingResponseVO incoming(AssetForm assetForm, Map<String, Object> data, Asset asset) {
List<OCRIdCardRow> list = OCRIdCardDataService.get(assetForm.getUuid());
if (CollectionUtils.isEmpty(list)) {
log.error("你我贷进件申请获取用户OCR信息失败 uuid : {}, orderId : {}",assetForm.getUuid(), assetForm.getBizNo());
throw new QGException(QGExceptionType.OCR_DATA_MISS);
}
OCRIdCardRow ocrIdCardRow = list.get(0);
UserSysResult<UserInfo> userInfoByUuid = userSdkService.findUserInfoByUuid(assetForm.getUuid());
if (!userInfoByUuid.isSuccess()){
log.error("你我贷进件申请获取用户中心信息失败, uuid : {}, orderId : {}", assetForm.getUuid(), assetForm.getBizNo());
throw new QGException(QGExceptionType.GET_USER_INFO_ERROR);
}
IdCardA idCardFront = JSON.parseObject(ocrIdCardRow.getIdCardContentA(), IdCardA.class);
IdCardB idCardBack = JSON.parseObject(ocrIdCardRow.getIdCardContentB(), IdCardB.class);
Map<String,Object> infoMap = queryUserBasic2Info(assetForm.getUuid(), userInfoByUuid.getData().getPhoneNo(),true);
NiwodaiIncomingRequestVO vo = new NiwodaiIncomingRequestVO();
vo.setOrderId(assetForm.getBizNo());
NiwodaiCostant.UserInfo userInfo = new NiwodaiCostant.UserInfo();
userInfo.setRealName(idCardFront.getName());
userInfo.setIdcardNumber(idCardFront.getCitizen_id().replaceAll("x", "X"));
userInfo.setPhone(userInfoByUuid.getData().getPhoneNo());
userInfo.setMaritalStatus(conversMarryStatus((String) infoMap.get("marryStatus")).name());
userInfo.setGender("男".equals(idCardFront.getGender()) ? NiwodaiCostant.Gender.MALE.name() : NiwodaiCostant.Gender.FEMALE.name());
userInfo.setEducation(conversEducation((String) infoMap.get("education")).name());
userInfo.setOccupation(conversOccupation((String) infoMap.get("vocation")).name());
userInfo.setIdcardValidity(idCardBack.getValid_date_begin() + "-" + idCardBack.getValid_date_end());
userInfo.setIdcardFront(ocrIdCardRow.getIdCardBaseContentA());
userInfo.setIdcardBack(ocrIdCardRow.getIdCardBaseContentB());
userInfo.setBioPhoto(ocrIdCardRow.getLivePhotoContent());
userInfo.setImageType("BASE64");
userInfo.setProvince((String) infoMap.get("province"));
userInfo.setCity((String) infoMap.get("city"));
userInfo.setDistrict((String) infoMap.get("district"));
userInfo.setAddress(idCardFront.getAddress());
userInfo.setIndustry(conversIndustry((String) infoMap.get("vocation")).name());
userInfo.setIncome(conversIncome((String) infoMap.get("salary")).name());
// userInfo.setIncomeType(random(NiwodaiCostant.IncomeType.values()).name());
userInfo.setDebt(NiwodaiCostant.Debt.ZERO.name());
vo.setUserInfo(userInfo);
NiwodaiCostant.LoanInfo loanInfo = new NiwodaiCostant.LoanInfo();
// 写死
loanInfo.setAmount(new BigDecimal(12000));
loanInfo.setTerm(12);
loanInfo.setPurpose(NiwodaiCostant.Purpose.CONSUMPTION.name());
vo.setLoanInfo(loanInfo);
NiwodaiCostant.Contacts contacts = new NiwodaiCostant.Contacts();
contacts.setNameA((String) infoMap.get("firstName"));
contacts.setPhoneA((String) infoMap.get("firstMobile"));
contacts.setRelationshipA(conversRelationship((String)infoMap.get("firstRelation")).name());
contacts.setNameB((String) infoMap.get("secondName"));
contacts.setPhoneB((String) infoMap.get("secondMobile"));
contacts.setRelationshipB(conversRelationship((String)infoMap.get("secondRelation")).name());
vo.setContacts(contacts);
NiwodaiCostant.CompnayInfo compnayInfo = new NiwodaiCostant.CompnayInfo();
compnayInfo.setName(random(NiwodaiCostant.COMPANY_NAMES));
compnayInfo.setAddress(userInfo.getProvince() + userInfo.getCity() + compnayInfo.getName());
compnayInfo.setCity(userInfo.getCity());
compnayInfo.setProvince(userInfo.getProvince());
vo.setCompanyInfo(compnayInfo);
vo.setMnoData(new NiwodaiCostant.MnoData());
NiwodaiCostant.RiskData riskData = getRiskData(asset.getUserLoanType(), data);
vo.setChannelRiskData(JSON.toJSONString(riskData));
// 标签落库
aidLoanFundUserTagService.saveUserTag(assetForm, asset, AidFundConstants.FundId.NIWODAI, JSON.toJSONString(riskData));
return niwodaiService.incoming(vo, assetForm.getUuid());
}
private static <T> T random(T[] objects){
int index = (int) (Math.random() * objects.length);
return objects[index];
}
@Override
public Map<String,Object> queryUserBasic2Info(String userId, String phoneNo, boolean isQuery) {
String url = userSysUrl+"/innerapi/user-association/search/userId?phoneNo="+phoneNo;
Map<String,Object> mapResult = new HashMap<>();
try{
String result = iHttpService.get(url);
JSONObject resultJson = JSON.parseObject(result);
if(queryIsSuccess(resultJson)){
mapResult.put("checkResult", true);
BasicInfo2Detail basicInfo2Detail = GSON.fromJson(resultJson.getString("data"), new TypeToken<BasicInfo2Detail>(){}.getType());
Map<String,Object> convertMap = new HashMap<>();
check(basicInfo2Detail, mapResult, userId, convertMap);
if(!isQuery){
mapResult.put("info", "");
}else{
mapResult.put("info", convertMap);
}
mapResult.put("name", basicInfo2Detail.getName());
}else{
mapResult.put("checkResult", false);
}
}catch(Exception e){
mapResult.put("checkResult", false);
log.error("查询用户中心数据发生异常, userId: {} ", userId, e);
}
if (null == mapResult.get("info")){
return new HashMap<>();
}else {
return (Map<String, Object>) mapResult.get("info");
}
}
public static void check(BasicInfo2Detail basicInfo2Detail, Map<String,Object> map, String userId, Map<String,Object> convertMap){
valuesChecker(basicInfo2Detail, map, userId);
String vocation = basicInfo2Detail.getOccupationEnum();
if(StringUtils.isNotEmpty(vocation)){
convertMap.put("vocation", basicInfo2Detail.getOccupationEnum());
}
String salary = basicInfo2Detail.getIncomeRangeEnum();
if(StringUtils.isNotEmpty(salary)){
convertMap.put("salary", basicInfo2Detail.getIncomeRangeEnum());
}
String education = basicInfo2Detail.getEducationEnum();
if(StringUtils.isNotEmpty(education)){
convertMap.put("education", basicInfo2Detail.getEducationEnum());
}
String email = basicInfo2Detail.getEmail();
if(StringUtils.isNotEmpty(email)){
convertMap.put("email", basicInfo2Detail.getEmail());
}
String marryStatus = basicInfo2Detail.getMarryStatus();
if (StringUtils.isNotEmpty(marryStatus)){
convertMap.put("marryStatus",basicInfo2Detail.getMarryStatus());
}
List<Contacts> contacts = basicInfo2Detail.getContactList();
List<Address> addresses = basicInfo2Detail.getAddressList();
if(contacts!=null && contacts.size()>0){
for(int i=0;i<contacts.size();i++){
Contacts contacts1 = contacts.get(i);
if(i==0){
String firstName = contacts1.getName();
if(StringUtils.isNotEmpty(firstName)){
convertMap.put("firstName", contacts1.getName());
}
String firstMobile = contacts1.getPhoneNo();
if(StringUtils.isNotEmpty(firstMobile)){
convertMap.put("firstMobile", contacts1.getPhoneNo());
}
String relation = contacts1.getRelationName();
if(StringUtils.isNotEmpty(relation)){
convertMap.put("firstRelation", contacts1.getRelationName());
}
}else if(i==1){
String secondName = contacts1.getName();
if(StringUtils.isNotEmpty(secondName)){
convertMap.put("secondName", contacts1.getName());
}
String secondMobile = contacts1.getPhoneNo();
if(StringUtils.isNotEmpty(secondMobile)){
convertMap.put("secondMobile", contacts1.getPhoneNo());
}
String secondRelation = contacts1.getRelationName();
if(StringUtils.isNotEmpty(secondRelation)){
convertMap.put("secondRelation", contacts1.getRelationName());
}
}
valuesChecker(contacts1, map, userId);
}
if(contacts.size()<2) {
map.put("checkResult", false);
}
}
if(addresses!=null && addresses.size()>0){
Address address = addresses.get(0);
valuesChecker(address, map, userId);
Long provinceCode = address.getProvinceCode();
if(provinceCode!=null){
convertMap.put("provinceCode", address.getProvinceCode());
}
String province = address.getProvince();
if(StringUtils.isNotEmpty(province)){
convertMap.put("province", address.getProvince());
}
Long cityCode = address.getCityCode();
if(cityCode!=null){
convertMap.put("cityCode", address.getCityCode());
}
String city = address.getCity();
if(StringUtils.isNotEmpty(city)){
convertMap.put("city", address.getCity());
}
Long districtCode = address.getDistrictCode();
if(districtCode!=null){
convertMap.put("districtCode", address.getDistrictCode());
}
String district = address.getDistrict();
if(StringUtils.isNotEmpty(district)){
convertMap.put("district", address.getDistrict());
}
String address1 = address.getAddress();
if(StringUtils.isNotEmpty(address1)){
convertMap.put("address", address.getAddress());
}
}
}
public boolean queryIsSuccess(JSONObject resultJson){
if("0000".equals(resultJson.getString("code")) && "0000".equals(resultJson.getString("businessCode"))){
String userInfo = resultJson.getString("data");
if(StringUtils.isNotEmpty(userInfo)){
return true;
}
}
return false;
}
public static void valuesChecker(Object o, Map<String,Object> map, String userId){
try{
Field[] fields = o.getClass().getDeclaredFields();
Object[] values = new Object[fields.length];
Object[] names = new Object[fields.length];
for(int i=0;i<names.length;i++){
fields[i].setAccessible(true);
values[i] = fields[i].get(o);
if(values[i]==null || "".equals(values[i]) || "未知".equals(values[i]) || "暂未填写".equals(values[i])){
map.put("checkResult", false);
break;
}
}
}catch(Exception e){
map.put("checkResult", false);
log.error("校验基本信息参数异常, userId:{}", userId, e);
}
}
private static NiwodaiCostant.Industry conversIndustry(String occupation) {
switch (occupation) {
case ("工人") : return NiwodaiCostant.Industry.AGRICULTURE;
case ("教师") : return NiwodaiCostant.Industry.EDUCATION;
case ("白领") : return NiwodaiCostant.Industry.INFORMATION_TECHNOLOGY_SERVICES;
case ("学生") : return NiwodaiCostant.Industry.EDUCATION;
case ("创业者") : return NiwodaiCostant.Industry.TECHNOLOGICAL_SERVICES;
case ("个体户") : return NiwodaiCostant.Industry.RETAIL;
case ("公司职员") : return NiwodaiCostant.Industry.FINANCE;
case ("企业法人") : return NiwodaiCostant.Industry.ESTATE;
case ("网店店主") : return NiwodaiCostant.Industry.ENTERTAINMENT;
case ("暂无职业") :
case ("其他") :
default : return NiwodaiCostant.Industry.UNKNOWN;
}
}
private static NiwodaiCostant.Occupation conversOccupation(String occupation){
switch (occupation){
case ("工人") :
case ("教师") :
case ("白领") :
case ("公司职员") :
return NiwodaiCostant.Occupation.WORKER;
case ("学生") : return NiwodaiCostant.Occupation.STUDENT;
case ("创业者") :
case ("企业法人") : return NiwodaiCostant.Occupation.PRIVATE_OWNERS;
case ("个体户") :
return NiwodaiCostant.Occupation.BUSINESSMEN;
case ("网店店主") :
case ("其他") : return NiwodaiCostant.Occupation.PROFESSIONAL;
case ("暂无职业") :
default : return NiwodaiCostant.Occupation.BE_UNEMPLOYED;
}
}
private static NiwodaiCostant.EducationalBackground conversEducation(String education){
switch (education){
case ("小学"):
case ("初中") : return NiwodaiCostant.EducationalBackground.JUNIOR_SCHOOL_AND_BELOW;
case ("高中"):
case ("技校"):
case ("中专"): return NiwodaiCostant.EducationalBackground.HIGH_SCHOOL;
case ("大专") : return NiwodaiCostant.EducationalBackground.ACADEMY;
case ("本科") : return NiwodaiCostant.EducationalBackground.UNIVERSITY;
case ("硕士及以上") : return NiwodaiCostant.EducationalBackground.POSTGRADUATE_AND_ABOVE;
default:return NiwodaiCostant.EducationalBackground.JUNIOR_SCHOOL_AND_BELOW;
}
}
private static NiwodaiCostant.Income conversIncome(String income){
switch (income){
case ("1000至3000元"): return NiwodaiCostant.Income.ONE;
case ("3000至5000元"): return NiwodaiCostant.Income.TWO;
case ("5000至8000元"):
case ("8000至10000元"): return NiwodaiCostant.Income.THREE;
case ("10000至15000元"): return NiwodaiCostant.Income.FOUR;
case ("15000至20000元"): return NiwodaiCostant.Income.FIVE;
case ("大于20000元"): return NiwodaiCostant.Income.SIX;
case ("小于1000元"):
default:return NiwodaiCostant.Income.ZERO;
}
}
private static NiwodaiCostant.MaritalStatus conversMarryStatus(String marryStatus){
switch (marryStatus){
case ("已婚") : return NiwodaiCostant.MaritalStatus.MARRIED;
case ("离异") : return NiwodaiCostant.MaritalStatus.DIVORCE;
case ("丧偶") : return NiwodaiCostant.MaritalStatus.WIDOWEDSPOUSE;
case ("未知") :
case ("未婚") :
default:return NiwodaiCostant.MaritalStatus.UNMARRIED;
}
}
private static NiwodaiCostant.Relationship conversRelationship(String relationship){
switch (relationship){
case ("父母") : return NiwodaiCostant.Relationship.MOTHER;
case ("子女") : return NiwodaiCostant.Relationship.SON;
case ("兄弟姐妹") : return NiwodaiCostant.Relationship.BROTHER;
case ("同事") : return NiwodaiCostant.Relationship.COLLEAGUE;
case ("同学") : return NiwodaiCostant.Relationship.CLASSMATE;
case ("朋友") : return NiwodaiCostant.Relationship.FRIEND;
case ("夫妻") : return NiwodaiCostant.Relationship.SPOUSE;
case ("本人") :
case ("其他") :
default: return NiwodaiCostant.Relationship.OTHER;
}
}
/**
* 获取手机号掩码,后4位掩码
* @param phoneNo
* @return
*/
private static String getPhoneNoMask(String phoneNo) {
if (StringUtils.isEmpty(phoneNo)) { throw new QGException(QGExceptionType.USER_PHONE_NO_EMPTY); }
return phoneNo.substring(0, phoneNo.length() - 4) + "****";
}
/**
* 身份证号掩码,后5位掩码
* @param idNo
* @return
*/
private static String getIdNoMask(String idNo) {
if (StringUtils.isEmpty(idNo)) { throw new QGException(QGExceptionType.USER_ID_NO_EMPTY); }
return idNo.substring(0, idNo.length() - 5) + "*****";
}
/**
* 获取用户标签
* @param data
* @return
*/
private Integer getUserTag(int userLoanType, Map<String, Object> data) {
if (userLoanType == UserLoanType.FIRST_APPLY.getCode() || userLoanType == UserLoanType.RE_APPLY.getCode()) {
return NiwodaiCostant.Tag.NATURE;
} else {
if (data.get("model_exec_data_source#xinyan_v5") != null && data.get("third_data_source#tencent_md5_risk_new_riskScore") != null) {
return NiwodaiCostant.Tag.REJECT;
} else {
return NiwodaiCostant.Tag.NATURE;
}
}
}
/**
* 获取风控分数
* @param data
* @param key
* @return
*/
private BigDecimal getRiskScore(Map<String, Object> data, String key) {
return data.get(key) == null ? new BigDecimal(-9999999) : new BigDecimal(String.valueOf(data.get(key)));
}
/**
* 获取风控数据对象
* @param userLoanType
* @param data
* @return
*/
private NiwodaiCostant.RiskData getRiskData(int userLoanType, Map<String, Object> data) {
NiwodaiCostant.RiskData riskData = new NiwodaiCostant.RiskData();
riskData.setIn_label(String.valueOf(getUserTag(userLoanType, data)));
riskData.setRisk_score2(getRiskScore(data, "model_exec_data_source#xinyan_v5"));
riskData.setRisk_score3(getRiskScore(data, "third_data_source#tencent_md5_risk_new_riskScore"));
return riskData;
}
}
package com.quantgroup.asset.distribution.service.niwodai.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.quantgroup.asset.distribution.constant.RedisKeyConstants;
import com.quantgroup.asset.distribution.exception.QGException;
import com.quantgroup.asset.distribution.exception.QGExceptionType;
import com.quantgroup.asset.distribution.service.httpclient.IHttpService;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiService;
import com.quantgroup.asset.distribution.service.niwodai.vo.*;
import com.quantgroup.asset.distribution.service.redis.IRedisService;
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.Base64;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class NiwodaiServiceImpl implements INiwodaiService {
@Value("${niwodai.url.authDomain}")
private String domain;
@Value("${niwodai.url.dataDomain}")
private String domain2;
@Value("${niwodai.url.dataCheck}")
private String dataImportCheckUrl;
@Value("${niwodai.url.auth}")
private String authUrl;
@Value("${niwodai.url.incoming}")
private String incomingUrl;
private static String getIncomingResult = "/std/v1/apply-result";
@Value("${niwodai.client.id}")
private String clientId;
@Value("${niwodai.client.secret}")
private String clientSecret;
@Autowired
IRedisService<String> iRedisService;
@Autowired
IHttpService iHttpService;
@Override
public NiwodaiDataImportCheckResponseVO dataImportCheck(NiwodaiDataImportCheckRequestVO requestVO, String uuid) {
String token = getToken();
if (StringUtils.isEmpty(token)) {
log.error("你我贷准入检查时获取token失败, uuid : {}", uuid);
throw new QGException(QGExceptionType.GET_NIWODAI_TOKEN_ERROR);
}
String result = iHttpService.postNiwodaiJson(domain2 + dataImportCheckUrl, commonHeader(token), JSON.toJSONString(requestVO), true);
log.info("你我贷准入检查接口调用结束, uuid : {}, requestVo : {}, response : {}", uuid, JSON.toJSONString(requestVO), result);
if (StringUtils.isNotEmpty(result)) {
NiwodaiDataImportCheckResponseVO vo = JSON.parseObject(result, NiwodaiDataImportCheckResponseVO.class);
if (vo != null && vo.getPass() != null) {
return JSON.parseObject(result, NiwodaiDataImportCheckResponseVO.class);
}
}
throw new QGException(QGExceptionType.NIWODAI_PRE_AUDIT_RESULAT_ERROR, result);
}
@Override
public NiwodaiIncomingResponseVO incoming(NiwodaiIncomingRequestVO requestVO, String uuid) {
String token = getToken();
if (StringUtils.isEmpty(token)) {
log.error("你我贷进件时获取token失败, uuid : {}, bizNo : {}", uuid, requestVO.getOrderId());
throw new QGException(QGExceptionType.GET_NIWODAI_TOKEN_ERROR);
}
String result = iHttpService.postNiwodaiJson(domain2 + incomingUrl, commonHeader(token), JSON.toJSONString(requestVO),false);
log.info("你我贷进件接口审核接口结束, uuid : {}, bizNo : {}, response : {}", uuid, requestVO.getOrderId(), result);
if (StringUtils.isNotEmpty(result)) {
NiwodaiIncomingResponseVO vo = JSON.parseObject(result, NiwodaiIncomingResponseVO.class);
if (vo != null && vo.getCode() != null) {
return vo;
}
}
throw new QGException(QGExceptionType.NIWODAI_INCOMING_RESULT_ERROR);
}
@Override
public NiwodaiIncomingResultResponseVO incoingResult(NiwodaiIncomingResultRequestVO requestVO){
String token = getToken();
if (StringUtils.isEmpty(token)) {
log.error("你我贷获取进件结果时获取token失败, requestVO : {}", JSON.toJSONString(requestVO));
throw new QGException(QGExceptionType.GET_NIWODAI_TOKEN_ERROR);
}
String result = iHttpService.postNiwodaiJson(domain2 + getIncomingResult, commonHeader(token), JSON.toJSONString(requestVO),true);
if (StringUtils.isNotEmpty(result)){
NiwodaiIncomingResultResponseVO vo = JSON.parseObject(result, NiwodaiIncomingResultResponseVO.class);
if (vo != null && vo.getCode() != null) {
return vo;
}
}
throw new QGException(QGExceptionType.NIWODAI_INCOMING_AUDIT_RESULT_ERROR);
}
public String getToken() {
String token = iRedisService.getString(RedisKeyConstants.NI_WO_DAI_TOKEN_KEY);
if (StringUtils.isBlank(token)) {
NiwodaiAccessTokenResponseVO vo = acquireAccessToken();
if (vo != null){
token = vo.getAccessToken();
iRedisService.setStringEx(RedisKeyConstants.NI_WO_DAI_TOKEN_KEY,token,8, TimeUnit.MINUTES);
}else {
return null;
}
}
return token;
}
public NiwodaiAccessTokenResponseVO acquireAccessToken() {
Map<String, String> header = Maps.newHashMap();
header.put("Content-Type", "application/x-www-form-urlencoded");
header.put("Authorization", "Basic " + Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes()));
Map<String, String> parameters = Maps.newHashMap();
parameters.put("grant_type", "client_credentials");
String result = null;
try {
result = iHttpService.postNiwodai(domain + authUrl, header, parameters, true);
} catch (Exception e) {
e.printStackTrace();
}
if (StringUtils.isNotEmpty(result)) {
return JSON.parseObject(result, NiwodaiAccessTokenResponseVO.class);
}
return null;
}
private static Map<String, String> commonHeader(String token) {
Map<String, String> header = Maps.newHashMap();
header.put("Authorization", " bearer " + token);
header.put("Content-Type", "application/json");
return header;
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
/**
* @author fengjunkai
* @create 2018-05-25 下午 3:27
**/
@Data
public class Address implements Serializable{
private static final long serialVersionUID = 665730924402064515L;
private Long provinceCode;
private String province;
private Long cityCode;
private String city;
private Long districtCode;
private String district;
private String address;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* @author fengjunkai
* @create 2018-05-25 下午 10:47
**/
@Data
public class BasicInfo2Detail implements Serializable {
private static final long serialVersionUID = 8649600289150722511L;
private String email;
private String educationEnum;
private String occupationEnum;
private String incomeRangeEnum;
private String name;
private String marryStatus;
private List<Address> addressList;
private List<Contacts> contactList;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
/**
* 原本有一个联系人,为了兼容全量用户信息需要重新创建一个
*
* @author fengjunkai
* @create 2018-05-25 下午 10:57
**/
@Data
public class Contacts implements Serializable {
private static final long serialVersionUID = 3119705836615833451L;
private String name;
private String phoneNo;
private String relationName;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
public class IdCardA implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String name;
private String gender;//性别 男/女
private String nation;//民族
private String birthday;//出生日期 格式 :1990.02.14
private String citizen_id;//身份证号
private String address;
public IdCardA(String name, String gender, String nation, String birthday, String citizen_id, String address) {
super();
this.name = name;
this.gender = gender;
this.nation = nation;
this.birthday = birthday;
this.citizen_id = citizen_id;
this.address = address;
}
public IdCardA() {
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Builder;
import lombok.Data;
import java.io.Serializable;
@Data
@Builder
public class IdCardB implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String agency;//签发机关
private String valid_date_begin;//有效日期之起始日期 格式:20131022
private String valid_date_end;//有效日期之结束日期 格式:20231022
public IdCardB(String agency,String valid_date_begin,String valid_date_end) {
super();
this.agency = agency;
this.valid_date_begin = valid_date_begin;
this.valid_date_end = valid_date_end;
}
public IdCardB(){
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.io.Serializable;
@Data
public class NiwodaiAccessTokenResponseVO implements Serializable {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("expire_in")
private Long expireIn;
@JsonProperty("scope")
private String scope;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.math.BigDecimal;
public class NiwodaiCostant {
// 你我贷审核期数固定为12期
public static final String AUDIT_TERM = "12";
@Data
public static class UserInfo {
/**
* 姓名 必填
*/
private String realName;
/**
* 用户ID 非必填
*/
private String externalUserId;
/**
* 身份证号(遇到x统一转化为大写) 必填
*/
private String idcardNumber;
/**
* 手机号 必填
*/
private String phone;
/**
* 婚姻状况,参见附录 必填
*/
private String maritalStatus;
/**
* 子女数量,参见附录 非必填
*/
private Integer childrenNum;
/**
* 性别,参见附录 必填
*/
private String gender;
/**
* 学历,参见附录 必填
*/
private String education;
/**
* 常用邮箱 非必填
*/
private String email;
/**
* 职业,参见附录 必填
*/
private String occupation;
/**
* 身份证户籍地址 非必填
*/
private String idcardAddress;
/**
* 发证机关 非必填
*/
private String idcardAuthority;
/**
* 证件有效期(yyyyMMdd-yyyyMMdd) 必填
*/
private String idcardValidity;
/**
* 民族(如:汉) 非必填
*/
private String nation;
/**
* 身份证正面图片 必填
*/
private String idcardFront;
/**
* 身份证反面图片 必填
*/
private String idcardBack;
/**
* 活体照片 必填
*/
private String bioPhoto;
/**
* 手持身份证照片 非必填
*/
private String handIdPhoto;
/**
* 照片类型:URL, BASE64 必填
*/
private String imageType;
/**
* 所在省份 必填
*/
private String province;
/**
* 所在城市 必填
*/
private String city;
/**
* 所在区县 非必填
*/
private String district;
/**
* 详细居住地址 必填
*/
private String address;
/**
* 所属行业,参见附录 必填
*/
private String industry;
/**
* 月收入,参见附录 必填
*/
private String income;
/**
* 收入来源,参见附录 非必填
*/
private String incomeType;
/**
* 负债情况,参见附录 必填
*/
private String debt;
/**
* 借记卡卡号 非必填
*/
private String debitCardNumber;
/**
* 信用卡卡号 非必填
*/
private String creditCardNumber;
}
@Data
public static class LoanInfo{
/**
* 贷款金额(如:5000.00) 必填
*/
private BigDecimal amount;
/**
* 贷款期数 必填
*/
private Integer term;
/**
* 贷款用途 必填
*/
private String purpose;
}
@Data
public static class CompnayInfo{
/**
* 工作单位全称 必填
*/
private String name;
/**
* 公司所在省份 必填
*/
private String province;
/**
* 公司所在城市 必填
*/
private String city;
/**
* 公司所在区县 非必填
*/
private String district;
/**
* 公司电话 非必填
*/
private String phone;
/**
* 公司详细地址 必填
*/
private String address;
/**
* 当前公司入职日期,格式:2017-07-01 非必填
*/
private String hireDate;
/**
* 公司类型,参见附录 非必填
*/
private String type;
/**
* 职级,参见附录 非必填
*/
private String rank;
}
@Data
public static class Contacts{
/**
* 第一联系人姓名 必填
*/
private String nameA;
/**
* 第一联系人电话 必填
*/
private String phoneA;
/**
* 第一联系人关系 必填
*/
private String relationshipA;
/**
* 第二联系人姓名 必填
*/
private String nameB;
/**
* 第二联系人电话 必填
*/
private String phoneB;
/**
* 第二联系人关系 必填
*/
private String relationshipB;
}
@Data
public static class MnoData{
/**
* 运营商分析报告,JSON序列化后的字符串(需要GZIP压缩)
*/
private String report;
/**
* 运营商详单,JSON序列化后的字符串(需要GZIP压缩)
*/
private String details;
}
@Data
public static class CreditRefData{
/**
* 客户授权人行征信查询时间,精确到秒 非必填
*/
private String authTime;
}
public enum Gender{
/**
* 男
*/
MALE,
/**
* 女
*/
FEMALE;
}
public enum MaritalStatus{
/**
* 未婚
*/
UNMARRIED,
/**
* 已婚
*/
MARRIED,
/**
* 离异
*/
DIVORCE,
/**
* 丧偶
*/
WIDOWEDSPOUSE;
}
public enum ChildrenNum{
/**
* 无子女
*/
NONE,
/**
* 一个子女
*/
ONE,
/**
* 两个子女
*/
TWO,
/**
* 三个以上
*/
ABOVE_THREE;
}
public enum EducationalBackground{
/**
* 初中及以下
*/
JUNIOR_SCHOOL_AND_BELOW,
/**
* 高中或中专
*/
HIGH_SCHOOL,
/**
* 大学专科
*/
ACADEMY,
/**
* 大学本科
*/
UNIVERSITY,
/**
* 研究生或以上
*/
POSTGRADUATE_AND_ABOVE;
}
public enum Occupation{
/**
* 私营业主
*/
PRIVATE_OWNERS,
/**
* 上班族
*/
WORKER,
/**
* 个体工商户
*/
BUSINESSMEN,
/**
* 自由职业者
*/
PROFESSIONAL,
/**
* 退休/待业/无业
*/
BE_UNEMPLOYED,
/**
* 在校学生
*/
STUDENT,
/**
* 农民
*/
FARMER;
}
/**
* 所属行业
*/
public enum Industry{
/**
*农业/林业/畜牧业/渔业
**/
AGRICULTURE,
/**
*采矿业
**/
MINING_INDUSTRY,
/**
*制造业
**/
MANUFACTURING_INDUSTRY,
/**
*电力/热力/燃气/水生产/供应业
**/
SUPPLY_INDUSTRY,
/**
*建筑业
**/
CONSTRUCTION_BUSINESS,
/**
*批发/零售业
**/
RETAIL,
/**
*交通运输/仓储业/邮政业
**/
TRANSPORTATION,
/**
*住宿/餐饮业
**/
RESTAURANT,
/**
*信息传输/软件/信息技术服务业
**/
INFORMATION_TECHNOLOGY_SERVICES,
/**
*金融业
**/
FINANCE,
/**
*房地产业
**/
ESTATE,
/**
*租赁/商务服务业
**/
BUSINESS_SERVICES,
/**
*科学研究/技术服务业
**/
TECHNOLOGICAL_SERVICES,
/**
*水利/环境/公共设施管理业
**/
PUBLIC_FACILITY_MANAGEMENT,
/**
*居民服务/修理/其他服务业
**/
RESIDENT_SERVICE,
/**
*教育
**/
EDUCATION,
/**
*卫生/社会工作
**/
SOCIAL_WORK,
/**
*文化/体育/娱乐业
**/
ENTERTAINMENT,
/**
*公共管理/社会保障/社会组织/国际组织
**/
PUBLIC_ADMINISTRATION,
/**
*未知
**/
UNKNOWN;
}
/**
* 月收入
*/
public enum Income{
/**
* 无固定收入
*/
ZERO,
/**
* 0-3000元
*/
ONE,
/**
* 3000-6000元
*/
TWO,
/**
* 6000-10000元
*/
THREE,
/**
* 10000-15000元
*/
FOUR,
/**
* 15000-20000元
*/
FIVE,
/**
* 20000元及以上
*/
SIX;
}
/**
* 收入来源
*/
public enum IncomeType{
/**
* 工资奖金
*/
SALARY,
/**
* 经营收入
*/
OPERATING_INCOME,
/**
* 投资理财
*/
INVESTMENT,
/**
* 房租收入
*/
HOUSE_RENT,
/**
* 其他
*/
OTHER;
}
/**
* 负债情况
*/
public enum Debt{
/**
* 无负债
*/
ZERO,
/**
* 0-3000元
*/
ONE,
/**
* 3000-6000元
*/
TWO,
/**
* 6000-10000元
*/
THREE,
/**
* 10000-15000元
*/
FOUR,
/**
* 15000-20000元
*/
FIVE,
/**
* 20000元及以上
*/
SIX;
}
/**
* 贷款用途
*/
public enum Purpose{
/**
* 个人日常消费
*/
CONSUMPTION,
/**
* 房屋装修
*/
RENOVATION,
/**
* 电子数码
*/
ELECTRONIC_PRODUCT,
/**
* 旅游
*/
TOURISM;
}
/**
* 联系人关系
*/
public enum Relationship{
/**
* 父亲
*/
FATHER,
/**
* 母亲
*/
MOTHER,
/**
* 儿子
*/
SON,
/**
* 女儿
*/
DAUGHTER,
/**
* 哥哥
*/
BROTHER,
/**
* 弟弟
*/
YOUNGER_BROTHER,
/**
* 姐姐
*/
SISTER,
/**
* 妹妹
*/
YOUNGER_SISTER,
/**
* 配偶
*/
SPOUSE,
/**
* 同事
*/
COLLEAGUE,
/**
* 朋友
*/
FRIEND,
/**
* 同学
*/
CLASSMATE,
/**
* 其他
*/
OTHER;
}
/**
* 公司类型
*/
public enum Type{
/**
* 政府或企事业单位
*/
GOVERNMENT_OR_INSTITUTION,
/**
* 国企央企
*/
SOE,
/**
* 外资企业
*/
FOREIGN_ENTERPRISE,
/**
* 上市公司
*/
LISTED_COMPANY,
/**
* 普通民营企业
*/
PRIVATE_ENTERPRISE,
/**
* 个体工商户
*/
INDIVIDUAL_BUSINESS,
/**
* 其他
*/
OTHER;
}
/**
* 职级
*/
public enum Rank{
/**
* 高级领导
*/
DIRECTOR,
/**
* 中级领导
*/
MANAGER,
/**
* 一般员工
*/
EMPLOYEES,
/**
* 其他
*/
OTHER,
/**
* 未知
*/
UNKNOWN;
}
/**
* 公司名称固定几个
*/
public static final String[] COMPANY_NAMES = {"外企人力资源公司", "中智人力资源公司", "新绿人力资源公司", "东浩人力资源公司"};
public static class Tag {
/**
* 自然流量标签
*/
public static final Integer NATURE = 1;
/**
* 拒绝流量标签
*/
public static final Integer REJECT = 2;
}
/**
* 风控数据
*/
@Data
public static class RiskData {
/**
* 进件类型,1-自然流量,2-拒绝流量
*/
private String in_label;
/**
* 量子分8
*/
private BigDecimal risk_score2;
/**
* 量子分12
*/
private BigDecimal risk_score3;
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
@Data
public class NiwodaiDataImportCheckRequestVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 真实姓名 必填
*/
private String realName;
/**
*身份证号 必填
*/
private String idcardNumber;
/**
* 电话号码 必填
*/
private String phone;
/**
* 期望借款金额 非必填
*/
private BigDecimal amount;
/**
* 用户ID 非必填
*/
private String externalUserId;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class NiwodaiDataImportCheckResponseVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 是否通过,是:true,否:false 必须
*/
private Boolean pass;
/**
* 准入未通过原因 非必须
*/
private String reason;
public static NiwodaiDataImportCheckResponseVO createPassFalse() {
NiwodaiDataImportCheckResponseVO vo = new NiwodaiDataImportCheckResponseVO();
vo.setPass(false);
return vo;
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
/**
* @author : Hyuk
* @description : NiwodaiIncomingCallbackResponseVO
* @date : 2020/4/2 11:43 上午
*/
@Data
public class NiwodaiIncomingCallbackResponseVO implements Serializable {
private static final long serialVersionUID = 1L;
private String orderId;
private String type;
private Integer code;
private Long timestamp;
private String data;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import java.io.Serializable;
import java.util.Map;
@Data
public class NiwodaiIncomingRequestVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 资产渠道唯一标识当前申请信息的流水号 必填
*/
private String orderId;
/**
* 借款人基本信息 必填
*/
private NiwodaiCostant.UserInfo userInfo;
/**
* 借款申请信息 必填
*/
private NiwodaiCostant.LoanInfo loanInfo;
/**
* 公司信息 必填
*/
private NiwodaiCostant.CompnayInfo companyInfo;
/**
* 联系人信息 必填
*/
private NiwodaiCostant.Contacts contacts;
/**
* 运营商数据 必填
*/
private NiwodaiCostant.MnoData mnoData;
/**
* 手机安装App信息,JSON序列化后的字符串(需要GZIP压缩) 非必填
*/
private String appListData;
/**
* 设备信息,JSON序列化后的字符串(需要GZIP压缩) 非必填
*/
private String deviceInfo;
/**
* 人行征信授权信息 非必填
*/
private NiwodaiCostant.CreditRefData creditRefData;
/**
* 风控数据对象
*/
private String channelRiskData;
public Map<String,Object> toMap(){
return JSONObject.parseObject(JSON.toJSONString(this));
}
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class NiwodaiIncomingResponseVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 300004:进件处理中; 300005:进件拒绝 必填
*/
private Integer code;
/**
* 描述信息 非必填
*/
private String message;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
@Data
public class NiwodaiIncomingResultRequestVO implements Serializable {
private String orderId;
}
package com.quantgroup.asset.distribution.service.niwodai.vo;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class NiwodaiIncomingResultResponseVO implements Serializable {
/**
* 300004:进件处理中; 300005:进件拒绝; 300006: 审批通过
*/
private String code;
/**
* 审批金额
*/
private BigDecimal approvedAmount;
/**
* 最小借款金额
*/
private BigDecimal minAmount;
/**
* 步长
*/
private BigDecimal step;
/**
* 额度有效期
*/
private String validBefore;
/**
* 审批期限
*/
private Integer approveTerm;
}
...@@ -36,7 +36,8 @@ public class NotifyServiceImpl implements INotifyService{ ...@@ -36,7 +36,8 @@ public class NotifyServiceImpl implements INotifyService{
@Override @Override
public void notifyFundServer(AssetForm assetForm, Map<String, Object> data) { public void notifyFundServer(AssetForm assetForm, Map<String, Object> data) {
if (isDebug) { return; } // 测试环境也做通知
// if (isDebug) { return; }
Map<String, String> notifyMap = assetForm.transToNotifyMap(data); Map<String, String> notifyMap = assetForm.transToNotifyMap(data);
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())) {
......
package com.quantgroup.asset.distribution.service.product;
import com.quantgroup.asset.distribution.model.form.AssetForm;
/**
* @author : Hyuk
* @description : IFinanceProductService
* @date : 2020/3/30 5:10 下午
*/
public interface IFinanceProductService {
/**
* 创建单个资方金融产品集
* @param amount
* @param term
* @param fundId
* @return
*/
public String createSingletonFinanceProduct(String amount, String term, String fundId, String fundProId);
/**
* 结果处理
* @param assetForm
* @param hitFinanceProduct
* @return
*/
public AssetForm checkFundResult(AssetForm assetForm, String hitFinanceProduct, Long deadLine);
public AssetForm checkFundResult(AssetForm assetForm, String hitFinanceProduct);
}
package com.quantgroup.asset.distribution.service.product.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
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.service.product.IFinanceProductHitLogService;
import com.quantgroup.asset.distribution.service.product.IFinanceProductService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author : Hyuk
* @description : FInanceProdcutServiceIMpl
* @date : 2020/3/30 5:11 下午
*/
@Slf4j
@Service
public class FinanceProductServiceImpl implements IFinanceProductService {
@Autowired
private IFinanceProductHitLogService financeProductHitLogService;
@Override
public String createSingletonFinanceProduct(String amount, String term, String fundId, String fundProId) {
JSONArray fundArray = createSingletonFundArr(fundId, fundProId);
JSONArray financeProductArray = new JSONArray();
JSONObject amountJSON = new JSONObject();
financeProductArray.add(amountJSON);
amountJSON.put("min", amount);
amountJSON.put("max", amount);
JSONArray termArray = new JSONArray();
amountJSON.put("terms", termArray);
JSONObject termJSON = new JSONObject();
termArray.add(termJSON);
try {
// 不能是string,否则资方那边会报错
termJSON.put("term", Integer.parseInt(term));
} catch (Exception e) {
termJSON.put("term", Double.parseDouble(term));
}
termJSON.put("fundInfo", fundArray);
return JSON.toJSONString(financeProductArray);
}
@Override
public AssetForm checkFundResult(AssetForm assetForm, String hitFinanceProduct, Long deadLine) {
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");
}
// 截止时间替换
if (deadLine != null) { assetForm.setDeadLine(String.valueOf(deadLine)); }
// 保存日志
financeProductHitLogService.saveLog(assetForm, oldFinanceProduct, hitFinanceProduct, oldAuditResult, assetForm.getAuditResult(), ExecuteType.ONLINE);
log.info("资方命中后,审核最终结果, assetForm : {}", JSON.toJSONString(assetForm));
return assetForm;
}
@Override
public AssetForm checkFundResult(AssetForm assetForm, String hitFinanceProduct) {
return checkFundResult(assetForm, hitFinanceProduct, null);
}
private JSONArray createSingletonFundArr(String fundId, String fundProductId) {
JSONArray fundArray = new JSONArray();
JSONObject fundInfoJSON = new JSONObject();
fundInfoJSON.put("fundId", fundId);
fundInfoJSON.put("fundProductId", fundProductId);
fundInfoJSON.put("priority", 1);
fundInfoJSON.put("feeType", 1);
fundInfoJSON.put("rateType", 1);
fundInfoJSON.put("rate", 0);
fundArray.add(fundInfoJSON);
return fundArray;
}
}
package com.quantgroup.asset.distribution.util;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class AddressResolutionUtil {
public static Map<String, String> addressResolution(String address) {
String regex = "(?<province>[^省]+自治区|.*?省|.*?行政区|.*?市)(?<city>[^市]+自治州|.*?地区|.*?行政单位|.+盟|市辖区|.*?市|.*?县)(?<county>[^县]+县|.+区|.+市|.+旗|.+海域|.+岛)?(?<town>[^区]+区|.+镇)?(?<village>.*)";
Matcher m = Pattern.compile(regex).matcher(address);
String province, city, county, town, village;
Map<String, String> row = null;
while (m.find()) {
row = new LinkedHashMap<String, String>();
province = m.group("province");
row.put("province", province == null ? "" : province.trim());
city = m.group("city");
row.put("city", city == null ? "" : city.trim());
county = m.group("county");
row.put("county", county == null ? "" : county.trim());
town = m.group("town");
row.put("town", town == null ? "" : town.trim());
village = m.group("village");
row.put("village", village == null ? "" : village.trim());
}
return row;
}
}
package com.quantgroup.asset.distribution.util; package com.quantgroup.asset.distribution.util;
import java.sql.Timestamp;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
...@@ -27,4 +28,14 @@ public class DateUtil { ...@@ -27,4 +28,14 @@ public class DateUtil {
public static String getCurDateTime() { public static String getCurDateTime() {
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()); return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now());
} }
/**
* 将时间类型字符串转换为Long类型
* @param dateTime
* @param pattern
* @return
*/
public static Long transStringToLong(String dateTime, String pattern) {
return Timestamp.valueOf(LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern))).getTime();
}
} }
package com.quantgroup.asset.distribution.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class GZIPUtils {
public static String compress(String primStr) {
if (primStr == null || primStr.length() == 0) {
return primStr;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
GZIPOutputStream gzip = null;
try {
gzip = new GZIPOutputStream(out);
gzip.write(primStr.getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (gzip != null) {
try {
gzip.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return new sun.misc.BASE64Encoder().encode(out.toByteArray());
}
/**
* 使用gzip进行解压缩
*/
public static String uncompress(String compressedStr) {
if (compressedStr == null) {
return null;
}
ByteArrayOutputStream out = new ByteArrayOutputStream();
ByteArrayInputStream in = null;
GZIPInputStream ginzip = null;
byte[] compressed = null;
String decompressed = null;
try {
compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);
in = new ByteArrayInputStream(compressed);
ginzip = new GZIPInputStream(in);
byte[] buffer = new byte[1024];
int offset = -1;
while ((offset = ginzip.read(buffer)) != -1) {
out.write(buffer, 0, offset);
}
decompressed = out.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ginzip != null) {
try {
ginzip.close();
} catch (IOException e) {
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
try {
out.close();
} catch (IOException e) {
}
}
return decompressed;
}
}
...@@ -7,10 +7,10 @@ ...@@ -7,10 +7,10 @@
value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} --- [%thread] [%file:%line] %logger - %msg%n}"/> value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} --- [%thread] [%file:%line] %logger - %msg%n}"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/vpants/shaun/asset-distribution-9051/logs/rule-engine.log</file> <file>/vpants/shaun/asset-distribution-9051/logs/asset-distribution.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern> <fileNamePattern>
/vpants/shaun/asset-distribution-9051/logs/rule-engine.log.%d{yyyy-MM-dd} /vpants/shaun/asset-distribution-9051/logs/asset-distribution.log.%d{yyyy-MM-dd}
</fileNamePattern> </fileNamePattern>
<maxHistory>7</maxHistory> <maxHistory>7</maxHistory>
</rollingPolicy> </rollingPolicy>
......
package com.quantgroup.asset.distribution.niwodai;
import cn.quantgroup.user.IUserSdkService;
import cn.quantgroup.user.UserSdkServiceFactory;
import com.alibaba.fastjson.JSON;
import com.quantgroup.asset.distribution.AssetDistributionBootstrap;
import com.quantgroup.asset.distribution.model.form.AssetForm;
import com.quantgroup.asset.distribution.service.funding.IFundModuleService;
import com.quantgroup.asset.distribution.service.jpa.entity.Asset;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiAssetService;
import com.quantgroup.asset.distribution.service.niwodai.INiwodaiService;
import com.quantgroup.asset.distribution.service.niwodai.vo.*;
import com.quantgroup.asset.distribution.util.GZIPUtils;
import org.apache.http.impl.client.CloseableHttpClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AssetDistributionBootstrap.class)
public class NiwodaiTest {
@Autowired
private INiwodaiService niwodaiService;
@Autowired
private INiwodaiAssetService niwodaiAssetService;
@Autowired
@Qualifier("httpClient")
private CloseableHttpClient httpClient;
@Value("${user.sdk.url}")
private String userSysUrl;
private IUserSdkService userSdkService;
@Autowired
private IFundModuleService fundModuleService;
@PostConstruct
private void init() {
userSdkService = UserSdkServiceFactory.generateSDKService(userSysUrl, httpClient);
}
// @Test
// public void testCheck() throws Exception {
// NiwodaiDataImportCheckResponseVO responseVO = niwodaiAssetService.dataCheck("9f7f857c-10c3-42aa-8fc5-31c37e988b3e");
// System.out.println(JSON.toJSONString(responseVO));
// }
//
// @Test
// public void testUser(){
// Map<String,Object> userInfoByUuid = niwodaiAssetService.queryUserBasic2Info("ae7d04bf-1c5a-475b-98d2-b193be88cf2f","13780000000",true);
// System.out.println(JSON.toJSONString(userInfoByUuid));
// }
//
// @Test
// public void userBase(){
// System.out.println(JSON.toJSONString(userSdkService.findUserInfoByUuid("097aae98-5da4-428b-aa40-93530b6b5f4b")));
// }
//
//
//
@Test
public void testIncoming() {
AssetForm assetForm = new AssetForm();
assetForm.setUuid("2f0c65a8-c94e-4e03-87c6-b0ae99b100f0");
assetForm.setBizNo("AN000000135785633731526656");
NiwodaiIncomingResponseVO vo = niwodaiAssetService.incoming(assetForm,new HashMap<>(),new Asset());
System.out.println(JSON.toJSONString(vo));
}
//
@Test
public void testResult(){
NiwodaiIncomingResultResponseVO vo = niwodaiAssetService.incomingResult("AN000000135785633731526656");
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);
// }
}
app.id=asset-distribution
namespace=application,tech.service.urls,tech.common,tech.sleuth,tech.deploy,tech.msg.sdk
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<springProperty name="spring.application.name" source="spring.application.name"/>
<property name="LOG_LEVEL_PATTERN"
value="%clr(%5p) %clr([${spring.application.name:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]){yellow}"/>
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%10.10t]){faint} [%40.40file:%4.4line] %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
<!-- 这里面定义了 CONSOLE_LOG_PATTERN, FILE_LOG_PATTERN 等日志格式, 还定义了一些日志级别 -->
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${FILE_LOG_PATTERN}</pattern>
</layout>
</appender>
<logger name="com.atomikos" level="warn"/>
<logger name="org.springframework" level="warn"/>
<logger name="org.mybatis" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
</configuration>
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<springProperty name="spring.application.name" source="spring.application.name"/>
<property name="LOG_LEVEL_PATTERN"
value="%5p [${spring.application.name:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]"/>
<property name="FILE_LOG_PATTERN"
value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} --- [%thread] [%file:%line] %logger - %msg%n}"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/quant_group/logs/asset-distribution.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
/home/quant_group/logs/asset-distribution.log.%d{yyyy-MM-dd}
</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<logger name="com.atomikos" level="warn"/>
<logger name="org.springframework" level="warn"/>
<logger name="org.mybatis" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="info">
<appender-ref ref="FILE"/>
</root>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<springProperty name="spring.application.name" source="spring.application.name"/>
<property name="LOG_LEVEL_PATTERN"
value="%5p [${spring.application.name:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]"/>
<property name="FILE_LOG_PATTERN"
value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} --- [%thread] [%file:%line] %logger - %msg%n}"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/quant_group/asset-distribution/logs/asset-distribution.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
/home/quant_group/asset-distribution/logs/asset-distribution.log.%d{yyyy-MM-dd}
</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<!-- logstash -->
<appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>172.30.220.6:9623</destination>
<!-- encoder is required -->
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<logger name="com.atomikos" level="warn"/>
<logger name="org.springframework" level="warn"/>
<logger name="org.mybatis" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="info">
<appender-ref ref="FILE"/>
<appender-ref ref="stash"/>
</root>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
<springProperty name="spring.application.name" source="spring.application.name"/>
<property name="LOG_LEVEL_PATTERN"
value="%5p [${spring.application.name:-},%X{X-B3-TraceId:-},%X{X-B3-SpanId:-},%X{X-Span-Export:-}]"/>
<property name="FILE_LOG_PATTERN"
value="${FILE_LOG_PATTERN:-%d{yyyy-MM-dd HH:mm:ss.SSS} ${LOG_LEVEL_PATTERN:-%5p} --- [%thread] [%file:%line] %logger - %msg%n}"/>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/vpants/shaun/asset-distribution-9051/logs/rule-engine.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>
/vpants/shaun/asset-distribution-9051/logs/rule-engine.log.%d{yyyy-MM-dd}
</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<encoder>
<pattern>${FILE_LOG_PATTERN}</pattern>
</encoder>
</appender>
<logger name="com.atomikos" level="warn"/>
<logger name="org.springframework" level="warn"/>
<logger name="org.mybatis" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="info">
<appender-ref ref="FILE"/>
</root>
</configuration>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<!-- 测试环境+开发环境. 多个使用逗号隔开. -->
<springProfile name="test,dev">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{ISO8601} [%thread] [%-5level] %logger - %msg%n</pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/rule-engine.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/asset-distribution.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{ISO8601} [%thread] [%-5level] %logger - %msg%n</pattern>
</layout>
</appender>
<logger name="com.atomikos" level="warn"/>
<logger name="org.springframework" level="warn"/>
<logger name="org.mybatis" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="info">
<appender-ref ref="STDOUT"/>
<appender-ref ref="FILE"/>
</root>
</springProfile>
<!-- 生产环境. -->
<springProfile name="product">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{ISO8601} [%thread] [%-5level] %logger - %msg%n</pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>/home/quant_group/asset-distribution/logs/asset-distribution.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>/home/quant_group/asset-distribution/logs/asset-distribution.log.%d{yyyy-MM-dd}</fileNamePattern>
<maxHistory>7</maxHistory>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{ISO8601} [%thread] [%-5level] %logger - %msg%n</pattern>
</layout>
</appender>
<!-- logstash -->
<appender name="stash" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>172.30.220.6:9650</destination>
<!-- encoder is required -->
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<logger name="org.springframework" level="warn"/>
<logger name="org.apache" level="warn"/>
<logger name="ch.qos.logback" level="warn"/>
<logger name="org.apache.kafka.clients" level="error"/>
<root level="INFO">
<appender-ref ref="FILE"/>
<appender-ref ref="stash"/>
</root>
</springProfile>
</configuration>
\ No newline at end of file
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