package com.jbkd.loan.payday.trdorder.shkj; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.jbkd.loan.payday.collection.constants.BaseConstants; import com.jbkd.loan.payday.common.service.FileService; import com.jbkd.loan.payday.common.util.Digest; import com.jbkd.loan.payday.common.util.HttpClientUtils; import com.jbkd.loan.payday.core.constant.BeanNameConstant; import com.jbkd.loan.payday.core.dto.SignatureProtocolRequestDTO; import com.jbkd.loan.payday.core.entity.CoreDictionaryItem; import com.jbkd.loan.payday.core.entity.CoreLoan; import com.jbkd.loan.payday.core.entity.CoreLoanWithdrawFlow; import com.jbkd.loan.payday.core.entity.Customer; import com.jbkd.loan.payday.core.entity.CustomerAccount; import com.jbkd.loan.payday.core.entity.CustomerFiles; import com.jbkd.loan.payday.core.enums.DealTypeEnum; import com.jbkd.loan.payday.core.enums.ProtocolTypeEnum; import com.jbkd.loan.payday.core.enums.UseageTypeEnum; import com.jbkd.loan.payday.core.service.CoreDictionaryItemService; import com.jbkd.loan.payday.core.service.CustomerAccountService; import com.jbkd.loan.payday.core.service.CustomerFilesService; import com.jbkd.loan.payday.core.service.CustomerService; import com.jbkd.loan.payday.core.service.CustomerTrdVerifyInfoService; import com.jbkd.loan.payday.core.entity.SyncShenhaiFlow; import com.jbkd.loan.payday.core.enums.SyncSHTypeEnum; import com.jbkd.loan.payday.repayment.info.dto.RepaymentInfoInDTO; import com.jbkd.loan.payday.repayment.info.dto.RepaymentInfoOutDTO; import com.jbkd.loan.payday.repayment.info.template.IRepaymentInfoTemplate; import com.jbkd.loan.payday.trdorder.common.util.RSAEncrypt; import java.io.ByteArrayOutputStream; import com.jbkd.loan.payday.trdorder.shkj.sync.SyncSHObserver; import com.jbkd.loan.payday.trdorder.shkj.sync.SyncSHSubject; import java.io.IOException; import java.io.InputStream; import java.math.BigDecimal; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.util.*; import java.net.URLEncoder; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Comparator; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.TreeMap; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; import org.apache.http.NameValuePair; import org.apache.pdfbox.io.IOUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Service; import javax.annotation.Resource; /** * Created by yangyafei on 19/7/1. * 白猫贷接口对接类 */ @Slf4j @Configuration public class BMDLoanService implements SyncSHSubject { //白猫贷版本号,配置文件配置注入 @Value("${bmd.version}") private String version; //白猫贷产品key,配置文件注入 @Value("${bmd.product.key}") private String productKey; //白猫贷appkey,配置文件注入 @Value("${bmd.app.key}") private String appKey; @Value("${bmd.private.key}") private String privateKey; //白猫贷url,配置文件注入 @Value("${bmd.base.uri}") private String bmdBaseUri; @Value("${bmd.public.key}") private String publicKey; @Value("${bmd.loanConfigNo}") private String loanConfigNo; @Value("${bmd.merchant.no}") private String merchantNo; @Value("${bmd.merchant.callBack.url}") private String callBackUrl; @Autowired private SyncSHObserver observer; @Override public void notifyObservers(SyncShenhaiFlow syncShenhaiFlow) { this.observer.saveSHFlow(syncShenhaiFlow); } @Autowired private CustomerService customerService; @Autowired private CustomerTrdVerifyInfoService customerTrdVerifyInfoService; @Autowired private CustomerFilesService customerFilesService; @Autowired private FileService fileService; @Autowired private CustomerAccountService customerAccountService; @Resource(name = BeanNameConstant.REPAYMENT_INFO_V0_TEMPLATE) private IRepaymentInfoTemplate repaymentInfoTemplate; @Autowired private CoreDictionaryItemService coreDictionaryItemService; public String generateSignature(Map params,Long mills,String nonce) throws Exception { TreeMap treeParams = new TreeMap<>(new Comparator() { @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); treeParams.putAll(params); StringBuilder temp = new StringBuilder(); temp.append("product_key=").append(productKey).append("&").append("app_key=").append(appKey).append("&").append("nonce=") .append(nonce).append("&").append("timestamp=").append(mills); treeParams.forEach((key,value) ->temp.append("&").append(key).append("=").append(value)); String data = temp.toString(); String signature = RSAEncrypt.rsaSign(data,privateKey,"SHA256withRSA"); return signature; } public Map generateBaseHeader(Map params){ try { String nonce = UUID.randomUUID().toString().replaceAll("-","").substring(0,16); Long mills = LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli(); String signature = generateSignature(params,mills,nonce); HashMap headers = new HashMap<>(); headers.put("BMD-COP-SIGNVERSION","1"); headers.put("BMD-COP-TIMESTAMP",String.valueOf(mills)); headers.put("BMD-COP-NONCE",nonce); headers.put("BMD-COP-PRODUCTKEY",productKey); headers.put("BMD-COP-APPKEY",appKey); headers.put("BMD-COP-SIGNATURE",signature); return headers; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 请求白猫贷方法 * @param params 白猫贷要求的字符串类参数 * @param fileMap 白猫贷要求的图片文件类参数 * @param syncSHTypeEnum * @return */ @Override public BMDResponse requestBmd(String bmdUri, Map params, Map> fileMap, SyncSHTypeEnum syncSHTypeEnum){ Map headers = generateBaseHeader(params); String responseStr = HttpClientUtils.doHttpPost(bmdUri,headers,params,fileMap,"UTF-8"); BMDResponse bmdResponse = transResponse(responseStr); // 更新流水记录 SyncShenhaiFlow syncShenhaiFlow =new SyncShenhaiFlow(); syncShenhaiFlow.setCopUserId(params.get("copUserId")) .setReqId(bmdResponse.getReqId()); if(Objects.nonNull(params)){ String request = JSON.toJSONString(params); syncShenhaiFlow.setResult(request); syncShenhaiFlow.setLoanNo(params.get("copOrderId")); } if(Objects.nonNull(bmdResponse) && bmdResponse.getSuccess()) { syncShenhaiFlow.setSyncStatus("Y"); }else{ syncShenhaiFlow.setSyncStatus("N"); } if(Objects.nonNull(syncSHTypeEnum)) { syncShenhaiFlow.setType(syncSHTypeEnum.name().toString()); } if(Objects.nonNull(bmdResponse)){ syncShenhaiFlow.setResult(JSON.toJSONString(bmdResponse)); } notifyObservers(syncShenhaiFlow); return bmdResponse; } //推送用户注册 public BMDResponse register(String userNo,String cellphone){ HashMap params = new HashMap<>(); params.put("copUserId",userNo); params.put("copRegPhoneNo",cellphone); return requestBmd(bmdBaseUri + "/api/v1/user_create",params,null, SyncSHTypeEnum.USER_CREATE); } public BMDResponse register(CoreLoan loan){ HashMap params = new HashMap<>(); Customer customer = customerService.getByCustomerNo(loan.getCustomerNo()); if(Objects.isNull(customer)){ return null; } params.put("copUserId",customer.getCustomerNo()); params.put("copRegPhoneNo",customer.getCellPhone()); return requestBmd(bmdBaseUri + "/api/v1/user_create",params,null, SyncSHTypeEnum.USER_CREATE); } //推送用户身份认证 public BMDResponse userVerify(CoreLoan loan){ if(Objects.isNull(loan)){ return null; } String userId = loan.getCustomerNo(); Customer customer = customerService.getByCustomerNo(userId); String realName = customer.getIdCardName(); String idcardNo = customer.getIdCardNo(); CustomerFiles idObverse = customerFilesService.getLastCustomerFileByCustomerNoAndType(userId, UseageTypeEnum.IDOBVERSE); CustomerFiles idReverse = customerFilesService.getLastCustomerFileByCustomerNoAndType(userId,UseageTypeEnum.IDREVERSE); String oberseFileName = idObverse.getFileName(); String reverseFileName = idReverse.getFileName(); InputStream idObverseIs = fileService.downloadFile(oberseFileName); InputStream idReverseIs = fileService.downloadFile(reverseFileName); try { byte[] idObverseBytes = IOUtils.toByteArray(idObverseIs); String oberseMd5 = Digest.signMD5(idObverseBytes,"UTF-8"); if(StringUtils.isNotBlank(oberseMd5)){ oberseMd5 = oberseMd5.toUpperCase(); } byte[] idReverseBytes = IOUtils.toByteArray(idReverseIs); String reverseMd5 = Digest.signMD5(idReverseBytes,"UTF-8"); if(StringUtils.isNotBlank(reverseMd5)){ reverseMd5 = reverseMd5.toUpperCase(); } Pair obversePair = ImmutablePair.of(idObverseBytes,"image/jpeg"); Pair reversePair = ImmutablePair.of(idReverseBytes,"image/jpeg"); Map> fileMap = new HashMap<>(); Map params = new HashMap<>(); fileMap.put("idcardFrontImgFile",obversePair); fileMap.put("idcardBackImgFile",reversePair); params.put("copUserId",userId); params.put("realName",realName); params.put("idcardNo",idcardNo); params.put("idcardFrontImgMd5",oberseMd5); params.put("idcardBackImgMd5",reverseMd5); return requestBmd(bmdBaseUri + "/api/v1/user_identify",params,fileMap,SyncSHTypeEnum.USER_IDENTIFY); } catch (IOException e) { e.printStackTrace(); } //Digest.signMD5() return null; } //用户活体检测 public BMDResponse userLive(CoreLoan loan){ CustomerFiles customerFiles = customerFilesService.getLastCustomerFileByCustomerNoAndType(loan.getCustomerNo(),UseageTypeEnum.LIVENESS_FRONT); if(Objects.isNull(customerFiles)){ return null; } String fileName = customerFiles.getFileName(); InputStream fileIs = fileService.downloadFile(fileName); try { byte[] content = IOUtils.toByteArray(fileIs); String md5 = Digest.signMD5(content,"UTF-8"); if(StringUtils.isNotBlank(md5)){ md5 = md5.toUpperCase(); } Pair pair = ImmutablePair.of(content,"image/jpeg"); Map> fileMap = new HashMap<>(); fileMap.put("livecheckImgFile",pair); Map params = new HashMap<>(); params.put("copUserId",loan.getCustomerNo()); params.put("livecheckImgMd5",md5); return requestBmd(bmdBaseUri + "/api/v1/user_livecheck",params,fileMap,SyncSHTypeEnum.USER_LIVECHECK); } catch (IOException e) { e.printStackTrace(); } return null; } //同步用户银行卡四要素 public BMDResponse userBankCard(CoreLoan loan){ String customerNo = loan.getCustomerNo(); CustomerAccount customerAccount = customerAccountService.getLastCustomerAccount(customerNo); if(Objects.isNull(customerAccount)){ return null; } String copUserId = customerNo; String realName = customerAccount.getAccountHolder(); String idcardNo = customerAccount.getAccountIdCardNo(); String bankCardNo = customerAccount.getAccountNumber(); String bankcardPhoneNo = customerAccount.getAccountPhone(); Map params = new HashMap<>(); params.put("copUserId",copUserId); params.put("realName",realName); params.put("idcardNo",idcardNo); params.put("bankcardNo",bankCardNo); params.put("bankcardPhoneNo",bankcardPhoneNo); return requestBmd(bmdBaseUri + "/api/v1/user_sync_bankcard_fourelements",params,null,SyncSHTypeEnum.FOURELEMENTS); } // public boolean pushUserInfo(CoreLoan loan){ // // // } //推送创建订单 // String orderNo,String userNo,long amount,String usage,String bankAccountName,String bankAccountNo,String repayPlan public BMDResponse orderCreate(CoreLoan loan){ HashMap params = new HashMap<>(); params.put("copOrderId",loan.getLoanNo()); params.put("loanConfigNo",loanConfigNo); params.put("copUserId",loan.getCustomerNo()); params.put("amount",String.valueOf(loan.getApprovedPrincipal().movePointRight(2))); String loanUdageName = coreDictionaryItemService.getByItemCode("REASON"+loan.getLoanUsageCode()).getItemName(); params.put("usage",loanUdageName); CustomerAccount customerAccount = customerAccountService.getLastCustomerAccount(loan.getCustomerNo()); if(Objects.isNull(customerAccount)){ return null; } params.put("bankAccountName",customerAccount.getAccountHolder()); params.put("bankAccountNo",customerAccount.getAccountNumber()); RepayPlan repayPlan = new RepayPlan(); repayPlan.setType(1); repayPlan.setIntervalUnitType("DAY"); repayPlan.setIntervalUnitCount(loan.getApprovedPeriod()); repayPlan.setDailyPenaltyRate(0.1); repayPlan.setEstimatePayTime(LocalDateToUdate(LocalDate.now())); RepayPlanItem repayPlanItem = new RepayPlanItem(); repayPlanItem.setCopRepayPlanItemId(loan.getLoanNo()); repayPlanItem.setPrincipal(loan.getApprovedPrincipal().movePointRight(2).longValue()); LocalDate dueDate = LocalDate.now().plusDays(loan.getApprovedPeriod() - 1); repayPlanItem.setEstimateRepayTime(LocalDateToUdate(dueDate)); repayPlan.setIntervalUnitInterestRate(loan.getInterestRate().movePointRight(2).setScale(3, BigDecimal.ROUND_HALF_UP).toString()); repayPlanItem.setInterests(0l); repayPlanItem.setFee(100l); repayPlanItem.setCommission(0l); repayPlanItem.setOther(loan.getApprovedInterest().movePointRight(2).longValue()-100l); List repayPlanItemList = new ArrayList<>(); repayPlanItemList.add(repayPlanItem); repayPlan.setItemList(repayPlanItemList); params.put("repayPlan",JSONObject.toJSONString(repayPlan)); return requestBmd(bmdBaseUri + "/api/v1/order_create",params,null,SyncSHTypeEnum.ORDER_CREATE); } //白猫贷查询订单 public BMDResponse getOrder(CoreLoan loan){ Map params = new HashMap<>(); params.put("copUserId",loan.getLoanNo()); return requestBmd(bmdBaseUri + "/api/v1/order_get",params,null,null); } public String LocalDateToUdate(LocalDate localDate) { ZoneId zone = ZoneId.systemDefault(); Instant instant = localDate.atStartOfDay().atZone(zone).toInstant(); java.util.Date date = Date.from(instant); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return simpleDateFormat.format(date); } public BMDResponse loanContract(CoreLoan loan,String fileName){ String loanNo = loan.getLoanNo(); InputStream contractIs = fileService.downloadFile(fileName); if(Objects.nonNull(contractIs)) { try { byte[] contractBytes = IOUtils.toByteArray(contractIs); try { contractIs.close(); }catch(Exception e){ log.error("close contract inputstream has error!"); } String md5 = Digest.signMD5(contractBytes,"UTF-8"); if(StringUtils.isNotBlank(md5)){ md5 = md5.toUpperCase(); } Map params = new HashMap<>(); params.put("contractMd5",md5); params.put("copOrderId",loanNo); Map> files = new HashMap<>(); files.put("contractFile",ImmutablePair.of(contractBytes,"application/pdf")); return requestBmd(bmdBaseUri + "/api/v1/order_upload_contract",params,files,SyncSHTypeEnum.ORDER_CONTRACT); } catch (IOException e) { e.printStackTrace(); } } return null; } //订单支付 public BMDResponse loanWithdraw(CoreLoanWithdrawFlow withdrawFlow){ if(Objects.isNull(withdrawFlow)){ return null; } Map params = new HashMap<>(); params.put("copOrderId",withdrawFlow.getLoanNo()); params.put("payMerchantNo",merchantNo); params.put("copPayRequestId",withdrawFlow.getRequestNo()); params.put("callbackUrl",callBackUrl); return requestBmd(bmdBaseUri + "/api/v1/order_pay",params,null,SyncSHTypeEnum.ORDER_WITHDRAW); } public BMDResponse transResponse(String responseStr){ if(StringUtils.isNotBlank(responseStr)){ JSONObject resultJson = JSONObject.parseObject(responseStr); BMDResponse result = new BMDResponse(); result.setReqId(resultJson.getString("reqId")); int code = resultJson.getInteger("code"); if(0 == code){ result.setCode(0); result.setSuccess(true); }else{ result.setCode(code); result.setSuccess(false); } result.setMsg(resultJson.getString("msg")); return result; } return null; } }