BMDLoanService.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  1. package com.jbkd.loan.payday.trdorder.shkj;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.jbkd.loan.payday.collection.constants.BaseConstants;
  5. import com.jbkd.loan.payday.common.service.FileService;
  6. import com.jbkd.loan.payday.common.util.Digest;
  7. import com.jbkd.loan.payday.common.util.HttpClientUtils;
  8. import com.jbkd.loan.payday.core.constant.BeanNameConstant;
  9. import com.jbkd.loan.payday.core.dto.SignatureProtocolRequestDTO;
  10. import com.jbkd.loan.payday.core.entity.CoreDictionaryItem;
  11. import com.jbkd.loan.payday.core.entity.CoreLoan;
  12. import com.jbkd.loan.payday.core.entity.CoreLoanWithdrawFlow;
  13. import com.jbkd.loan.payday.core.entity.Customer;
  14. import com.jbkd.loan.payday.core.entity.CustomerAccount;
  15. import com.jbkd.loan.payday.core.entity.CustomerFiles;
  16. import com.jbkd.loan.payday.core.enums.DealTypeEnum;
  17. import com.jbkd.loan.payday.core.enums.ProtocolTypeEnum;
  18. import com.jbkd.loan.payday.core.enums.UseageTypeEnum;
  19. import com.jbkd.loan.payday.core.service.CoreDictionaryItemService;
  20. import com.jbkd.loan.payday.core.service.CustomerAccountService;
  21. import com.jbkd.loan.payday.core.service.CustomerFilesService;
  22. import com.jbkd.loan.payday.core.service.CustomerService;
  23. import com.jbkd.loan.payday.core.service.CustomerTrdVerifyInfoService;
  24. import com.jbkd.loan.payday.core.entity.SyncShenhaiFlow;
  25. import com.jbkd.loan.payday.core.enums.SyncSHTypeEnum;
  26. import com.jbkd.loan.payday.repayment.info.dto.RepaymentInfoInDTO;
  27. import com.jbkd.loan.payday.repayment.info.dto.RepaymentInfoOutDTO;
  28. import com.jbkd.loan.payday.repayment.info.template.IRepaymentInfoTemplate;
  29. import com.jbkd.loan.payday.trdorder.common.util.RSAEncrypt;
  30. import java.io.ByteArrayOutputStream;
  31. import com.jbkd.loan.payday.trdorder.shkj.sync.SyncSHObserver;
  32. import com.jbkd.loan.payday.trdorder.shkj.sync.SyncSHSubject;
  33. import java.io.IOException;
  34. import java.io.InputStream;
  35. import java.math.BigDecimal;
  36. import java.text.SimpleDateFormat;
  37. import java.time.*;
  38. import java.time.format.DateTimeFormatter;
  39. import java.util.*;
  40. import java.net.URLEncoder;
  41. import java.time.LocalDateTime;
  42. import java.time.ZoneOffset;
  43. import java.util.Comparator;
  44. import java.util.HashMap;
  45. import java.util.Map;
  46. import java.util.Objects;
  47. import java.util.TreeMap;
  48. import java.util.UUID;
  49. import lombok.extern.slf4j.Slf4j;
  50. import org.apache.commons.lang3.EnumUtils;
  51. import org.apache.commons.lang3.StringUtils;
  52. import org.apache.commons.lang3.tuple.ImmutablePair;
  53. import org.apache.commons.lang3.tuple.Pair;
  54. import org.apache.http.NameValuePair;
  55. import org.apache.pdfbox.io.IOUtils;
  56. import org.springframework.beans.factory.annotation.Autowired;
  57. import org.springframework.beans.factory.annotation.Value;
  58. import org.springframework.context.annotation.Configuration;
  59. import org.springframework.stereotype.Service;
  60. import javax.annotation.Resource;
  61. /**
  62. * Created by yangyafei on 19/7/1.
  63. * 白猫贷接口对接类
  64. */
  65. @Slf4j
  66. @Configuration
  67. public class BMDLoanService implements SyncSHSubject {
  68. //白猫贷版本号,配置文件配置注入
  69. @Value("${bmd.version}")
  70. private String version;
  71. //白猫贷产品key,配置文件注入
  72. @Value("${bmd.product.key}")
  73. private String productKey;
  74. //白猫贷appkey,配置文件注入
  75. @Value("${bmd.app.key}")
  76. private String appKey;
  77. @Value("${bmd.private.key}")
  78. private String privateKey;
  79. //白猫贷url,配置文件注入
  80. @Value("${bmd.base.uri}")
  81. private String bmdBaseUri;
  82. @Value("${bmd.public.key}")
  83. private String publicKey;
  84. @Value("${bmd.loanConfigNo}")
  85. private String loanConfigNo;
  86. @Value("${bmd.merchant.no}")
  87. private String merchantNo;
  88. @Value("${bmd.merchant.callBack.url}")
  89. private String callBackUrl;
  90. @Autowired
  91. private SyncSHObserver observer;
  92. @Override
  93. public void notifyObservers(SyncShenhaiFlow syncShenhaiFlow) {
  94. this.observer.saveSHFlow(syncShenhaiFlow);
  95. }
  96. @Autowired
  97. private CustomerService customerService;
  98. @Autowired
  99. private CustomerTrdVerifyInfoService customerTrdVerifyInfoService;
  100. @Autowired
  101. private CustomerFilesService customerFilesService;
  102. @Autowired
  103. private FileService fileService;
  104. @Autowired
  105. private CustomerAccountService customerAccountService;
  106. @Resource(name = BeanNameConstant.REPAYMENT_INFO_V0_TEMPLATE)
  107. private IRepaymentInfoTemplate repaymentInfoTemplate;
  108. @Autowired
  109. private CoreDictionaryItemService coreDictionaryItemService;
  110. public String generateSignature(Map<String,String> params,Long mills,String nonce) throws Exception {
  111. TreeMap<String,String> treeParams = new TreeMap<>(new Comparator<String>() {
  112. @Override
  113. public int compare(String o1, String o2) {
  114. return o1.compareTo(o2);
  115. }
  116. });
  117. treeParams.putAll(params);
  118. StringBuilder temp = new StringBuilder();
  119. temp.append("product_key=").append(productKey).append("&").append("app_key=").append(appKey).append("&").append("nonce=")
  120. .append(nonce).append("&").append("timestamp=").append(mills);
  121. treeParams.forEach((key,value) ->temp.append("&").append(key).append("=").append(value));
  122. String data = temp.toString();
  123. String signature = RSAEncrypt.rsaSign(data,privateKey,"SHA256withRSA");
  124. return signature;
  125. }
  126. public Map<String,String> generateBaseHeader(Map<String,String> params){
  127. try {
  128. String nonce = UUID.randomUUID().toString().replaceAll("-","").substring(0,16);
  129. Long mills = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli();
  130. String signature = generateSignature(params,mills,nonce);
  131. HashMap<String,String> headers = new HashMap<>();
  132. headers.put("BMD-COP-SIGNVERSION","1");
  133. headers.put("BMD-COP-TIMESTAMP",String.valueOf(mills));
  134. headers.put("BMD-COP-NONCE",nonce);
  135. headers.put("BMD-COP-PRODUCTKEY",productKey);
  136. headers.put("BMD-COP-APPKEY",appKey);
  137. headers.put("BMD-COP-SIGNATURE",signature);
  138. return headers;
  139. } catch (Exception e) {
  140. e.printStackTrace();
  141. }
  142. return null;
  143. }
  144. /**
  145. * 请求白猫贷方法
  146. * @param params 白猫贷要求的字符串类参数
  147. * @param fileMap 白猫贷要求的图片文件类参数
  148. * @param syncSHTypeEnum
  149. * @return
  150. */
  151. @Override
  152. public BMDResponse requestBmd(String bmdUri, Map<String, String> params, Map<String,Pair<byte[],String>> fileMap, SyncSHTypeEnum syncSHTypeEnum){
  153. Map<String,String> headers = generateBaseHeader(params);
  154. String responseStr = HttpClientUtils.doHttpPost(bmdUri,headers,params,fileMap,"UTF-8");
  155. BMDResponse bmdResponse = transResponse(responseStr);
  156. // 更新流水记录
  157. SyncShenhaiFlow syncShenhaiFlow =new SyncShenhaiFlow();
  158. syncShenhaiFlow.setCopUserId(params.get("copUserId"))
  159. .setReqId(bmdResponse.getReqId());
  160. if(Objects.nonNull(params)){
  161. String request = JSON.toJSONString(params);
  162. syncShenhaiFlow.setResult(request);
  163. syncShenhaiFlow.setLoanNo(params.get("copOrderId"));
  164. }
  165. if(Objects.nonNull(bmdResponse) && bmdResponse.getSuccess()) {
  166. syncShenhaiFlow.setSyncStatus("Y");
  167. }else{
  168. syncShenhaiFlow.setSyncStatus("N");
  169. }
  170. if(Objects.nonNull(syncSHTypeEnum)) {
  171. syncShenhaiFlow.setType(syncSHTypeEnum.name().toString());
  172. }
  173. if(Objects.nonNull(bmdResponse)){
  174. syncShenhaiFlow.setResult(JSON.toJSONString(bmdResponse));
  175. }
  176. notifyObservers(syncShenhaiFlow);
  177. return bmdResponse;
  178. }
  179. //推送用户注册
  180. public BMDResponse register(String userNo,String cellphone){
  181. HashMap<String,String> params = new HashMap<>();
  182. params.put("copUserId",userNo);
  183. params.put("copRegPhoneNo",cellphone);
  184. return requestBmd(bmdBaseUri + "/api/v1/user_create",params,null, SyncSHTypeEnum.USER_CREATE);
  185. }
  186. public BMDResponse register(CoreLoan loan){
  187. HashMap<String,String> params = new HashMap<>();
  188. Customer customer = customerService.getByCustomerNo(loan.getCustomerNo());
  189. if(Objects.isNull(customer)){
  190. return null;
  191. }
  192. params.put("copUserId",customer.getCustomerNo());
  193. params.put("copRegPhoneNo",customer.getCellPhone());
  194. return requestBmd(bmdBaseUri + "/api/v1/user_create",params,null, SyncSHTypeEnum.USER_CREATE);
  195. }
  196. //推送用户身份认证
  197. public BMDResponse userVerify(CoreLoan loan){
  198. if(Objects.isNull(loan)){
  199. return null;
  200. }
  201. String userId = loan.getCustomerNo();
  202. Customer customer = customerService.getByCustomerNo(userId);
  203. String realName = customer.getIdCardName();
  204. String idcardNo = customer.getIdCardNo();
  205. CustomerFiles idObverse = customerFilesService.getLastCustomerFileByCustomerNoAndType(userId, UseageTypeEnum.IDOBVERSE);
  206. CustomerFiles idReverse = customerFilesService.getLastCustomerFileByCustomerNoAndType(userId,UseageTypeEnum.IDREVERSE);
  207. String oberseFileName = idObverse.getFileName();
  208. String reverseFileName = idReverse.getFileName();
  209. InputStream idObverseIs = fileService.downloadFile(oberseFileName);
  210. InputStream idReverseIs = fileService.downloadFile(reverseFileName);
  211. try {
  212. byte[] idObverseBytes = IOUtils.toByteArray(idObverseIs);
  213. String oberseMd5 = Digest.signMD5(idObverseBytes,"UTF-8");
  214. if(StringUtils.isNotBlank(oberseMd5)){
  215. oberseMd5 = oberseMd5.toUpperCase();
  216. }
  217. byte[] idReverseBytes = IOUtils.toByteArray(idReverseIs);
  218. String reverseMd5 = Digest.signMD5(idReverseBytes,"UTF-8");
  219. if(StringUtils.isNotBlank(reverseMd5)){
  220. reverseMd5 = reverseMd5.toUpperCase();
  221. }
  222. Pair<byte[],String> obversePair = ImmutablePair.of(idObverseBytes,"image/jpeg");
  223. Pair<byte[],String> reversePair = ImmutablePair.of(idReverseBytes,"image/jpeg");
  224. Map<String,Pair<byte[],String>> fileMap = new HashMap<>();
  225. Map<String,String> params = new HashMap<>();
  226. fileMap.put("idcardFrontImgFile",obversePair);
  227. fileMap.put("idcardBackImgFile",reversePair);
  228. params.put("copUserId",userId);
  229. params.put("realName",realName);
  230. params.put("idcardNo",idcardNo);
  231. params.put("idcardFrontImgMd5",oberseMd5);
  232. params.put("idcardBackImgMd5",reverseMd5);
  233. return requestBmd(bmdBaseUri + "/api/v1/user_identify",params,fileMap,SyncSHTypeEnum.USER_IDENTIFY);
  234. } catch (IOException e) {
  235. e.printStackTrace();
  236. }
  237. //Digest.signMD5()
  238. return null;
  239. }
  240. //用户活体检测
  241. public BMDResponse userLive(CoreLoan loan){
  242. CustomerFiles customerFiles = customerFilesService.getLastCustomerFileByCustomerNoAndType(loan.getCustomerNo(),UseageTypeEnum.LIVENESS_FRONT);
  243. if(Objects.isNull(customerFiles)){
  244. return null;
  245. }
  246. String fileName = customerFiles.getFileName();
  247. InputStream fileIs = fileService.downloadFile(fileName);
  248. try {
  249. byte[] content = IOUtils.toByteArray(fileIs);
  250. String md5 = Digest.signMD5(content,"UTF-8");
  251. if(StringUtils.isNotBlank(md5)){
  252. md5 = md5.toUpperCase();
  253. }
  254. Pair<byte[],String> pair = ImmutablePair.of(content,"image/jpeg");
  255. Map<String,Pair<byte[],String>> fileMap = new HashMap<>();
  256. fileMap.put("livecheckImgFile",pair);
  257. Map<String,String> params = new HashMap<>();
  258. params.put("copUserId",loan.getCustomerNo());
  259. params.put("livecheckImgMd5",md5);
  260. return requestBmd(bmdBaseUri + "/api/v1/user_livecheck",params,fileMap,SyncSHTypeEnum.USER_LIVECHECK);
  261. } catch (IOException e) {
  262. e.printStackTrace();
  263. }
  264. return null;
  265. }
  266. //同步用户银行卡四要素
  267. public BMDResponse userBankCard(CoreLoan loan){
  268. String customerNo = loan.getCustomerNo();
  269. CustomerAccount customerAccount = customerAccountService.getLastCustomerAccount(customerNo);
  270. if(Objects.isNull(customerAccount)){
  271. return null;
  272. }
  273. String copUserId = customerNo;
  274. String realName = customerAccount.getAccountHolder();
  275. String idcardNo = customerAccount.getAccountIdCardNo();
  276. String bankCardNo = customerAccount.getAccountNumber();
  277. String bankcardPhoneNo = customerAccount.getAccountPhone();
  278. Map<String,String> params = new HashMap<>();
  279. params.put("copUserId",copUserId);
  280. params.put("realName",realName);
  281. params.put("idcardNo",idcardNo);
  282. params.put("bankcardNo",bankCardNo);
  283. params.put("bankcardPhoneNo",bankcardPhoneNo);
  284. return requestBmd(bmdBaseUri + "/api/v1/user_sync_bankcard_fourelements",params,null,SyncSHTypeEnum.FOURELEMENTS);
  285. }
  286. // public boolean pushUserInfo(CoreLoan loan){
  287. //
  288. //
  289. // }
  290. //推送创建订单
  291. // String orderNo,String userNo,long amount,String usage,String bankAccountName,String bankAccountNo,String repayPlan
  292. public BMDResponse orderCreate(CoreLoan loan){
  293. HashMap<String,String> params = new HashMap<>();
  294. params.put("copOrderId",loan.getLoanNo());
  295. params.put("loanConfigNo",loanConfigNo);
  296. params.put("copUserId",loan.getCustomerNo());
  297. params.put("amount",String.valueOf(loan.getApprovedPrincipal().movePointRight(2)));
  298. String loanUdageName = coreDictionaryItemService.getByItemCode("REASON"+loan.getLoanUsageCode()).getItemName();
  299. params.put("usage",loanUdageName);
  300. CustomerAccount customerAccount = customerAccountService.getLastCustomerAccount(loan.getCustomerNo());
  301. if(Objects.isNull(customerAccount)){
  302. return null;
  303. }
  304. params.put("bankAccountName",customerAccount.getAccountHolder());
  305. params.put("bankAccountNo",customerAccount.getAccountNumber());
  306. RepayPlan repayPlan = new RepayPlan();
  307. repayPlan.setType(1);
  308. repayPlan.setIntervalUnitType("DAY");
  309. repayPlan.setIntervalUnitCount(loan.getApprovedPeriod());
  310. repayPlan.setDailyPenaltyRate(0.1);
  311. repayPlan.setEstimatePayTime(LocalDateToUdate(LocalDate.now()));
  312. RepayPlanItem repayPlanItem = new RepayPlanItem();
  313. repayPlanItem.setCopRepayPlanItemId(loan.getLoanNo());
  314. repayPlanItem.setPrincipal(loan.getApprovedPrincipal().movePointRight(2).longValue());
  315. LocalDate dueDate = LocalDate.now().plusDays(loan.getApprovedPeriod() - 1);
  316. repayPlanItem.setEstimateRepayTime(LocalDateToUdate(dueDate));
  317. repayPlan.setIntervalUnitInterestRate(loan.getInterestRate().movePointRight(2).setScale(3, BigDecimal.ROUND_HALF_UP).toString());
  318. repayPlanItem.setInterests(0l);
  319. repayPlanItem.setFee(100l);
  320. repayPlanItem.setCommission(0l);
  321. repayPlanItem.setOther(loan.getApprovedInterest().movePointRight(2).longValue()-100l);
  322. List<RepayPlanItem> repayPlanItemList = new ArrayList<>();
  323. repayPlanItemList.add(repayPlanItem);
  324. repayPlan.setItemList(repayPlanItemList);
  325. params.put("repayPlan",JSONObject.toJSONString(repayPlan));
  326. return requestBmd(bmdBaseUri + "/api/v1/order_create",params,null,SyncSHTypeEnum.ORDER_CREATE);
  327. }
  328. //白猫贷查询订单
  329. public BMDResponse getOrder(CoreLoan loan){
  330. Map<String,String> params = new HashMap<>();
  331. params.put("copUserId",loan.getLoanNo());
  332. return requestBmd(bmdBaseUri + "/api/v1/order_get",params,null,null);
  333. }
  334. public String LocalDateToUdate(LocalDate localDate) {
  335. ZoneId zone = ZoneId.systemDefault();
  336. Instant instant = localDate.atStartOfDay().atZone(zone).toInstant();
  337. java.util.Date date = Date.from(instant);
  338. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  339. return simpleDateFormat.format(date);
  340. }
  341. public BMDResponse loanContract(CoreLoan loan,String fileName){
  342. String loanNo = loan.getLoanNo();
  343. InputStream contractIs = fileService.downloadFile(fileName);
  344. if(Objects.nonNull(contractIs)) {
  345. try {
  346. byte[] contractBytes = IOUtils.toByteArray(contractIs);
  347. try {
  348. contractIs.close();
  349. }catch(Exception e){
  350. log.error("close contract inputstream has error!");
  351. }
  352. String md5 = Digest.signMD5(contractBytes,"UTF-8");
  353. if(StringUtils.isNotBlank(md5)){
  354. md5 = md5.toUpperCase();
  355. }
  356. Map<String,String> params = new HashMap<>();
  357. params.put("contractMd5",md5);
  358. params.put("copOrderId",loanNo);
  359. Map<String,Pair<byte[],String>> files = new HashMap<>();
  360. files.put("contractFile",ImmutablePair.of(contractBytes,"application/pdf"));
  361. return requestBmd(bmdBaseUri + "/api/v1/order_upload_contract",params,files,SyncSHTypeEnum.ORDER_CONTRACT);
  362. } catch (IOException e) {
  363. e.printStackTrace();
  364. }
  365. }
  366. return null;
  367. }
  368. //订单支付
  369. public BMDResponse loanWithdraw(CoreLoanWithdrawFlow withdrawFlow){
  370. if(Objects.isNull(withdrawFlow)){
  371. return null;
  372. }
  373. Map<String,String> params = new HashMap<>();
  374. params.put("copOrderId",withdrawFlow.getLoanNo());
  375. params.put("payMerchantNo",merchantNo);
  376. params.put("copPayRequestId",withdrawFlow.getRequestNo());
  377. params.put("callbackUrl",callBackUrl);
  378. return requestBmd(bmdBaseUri + "/api/v1/order_pay",params,null,SyncSHTypeEnum.ORDER_WITHDRAW);
  379. }
  380. public BMDResponse transResponse(String responseStr){
  381. if(StringUtils.isNotBlank(responseStr)){
  382. JSONObject resultJson = JSONObject.parseObject(responseStr);
  383. BMDResponse result = new BMDResponse();
  384. result.setReqId(resultJson.getString("reqId"));
  385. int code = resultJson.getInteger("code");
  386. if(0 == code){
  387. result.setCode(0);
  388. result.setSuccess(true);
  389. }else{
  390. result.setCode(code);
  391. result.setSuccess(false);
  392. }
  393. result.setMsg(resultJson.getString("msg"));
  394. return result;
  395. }
  396. return null;
  397. }
  398. }