package com.nova.sankuai.domain.api.zhongan;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nova.sankuai.domain.entity.City;
import com.nova.sankuai.domain.entity.Customer;
import com.nova.sankuai.domain.enums.SourceTypeEnum;
import com.nova.sankuai.domain.enums.customerinfo.EnterpriseInfoEnum;
import com.nova.sankuai.domain.enums.customerinfo.MaritalStatusEnum;
import com.nova.sankuai.infra.config.CommonException;
import com.nova.sankuai.service.ICityService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
*
* description
*
*
* @author denglb 2021/11/16
*/
@Component
@Slf4j
public class ZhongAnUtil {
@Value("${rsa.local.privateKey}")
private String localPrivateKey;
@Value("${rsa.local.publicKey}")
private String localPublicKey;
@Value("${rsa.zhongan.publicKey}")
private String zhonganPublicKey;
@Value("${rsa.zhongan.appKey}")
private String zhonganAppKey;
@Value("${rsa.zhongan.creditApplyService}")
private String creditApplyService;
@Value("${rsa.zhongan.url}")
private String zhonganUrl;
@Value("${rsa.zhongan.callbackService}")
private String callbackService;
@Resource
private ICityService cityService;
private static final String API_NAME = "apiName";
private static final String CHANNEL_NO = "channelNo";
private static final String SUPPLIER_NO = "supplierNo";
private static final String REQ_DATE = "reqDate";
private static final String REQ_NO = "reqNo";
private static final String RESP_CODE = "respCode";
private static final String RESP_MSG = "respMsg";
private static final String RESP_NO = "respNo";
private static final String RESULT = "result";
private static final String THIRD_USER_NO = "thirdUserNo";
private static final String APPKEY = "appKey";
private static final String SERVICE_NAME = "serviceName";
private static final String BIZ_CONTENT = "bizContent";
private static final String TIMESTAMP = "timestamp";
private static final String FORMAT = "format";
private static final String SIGN_TYPE = "signType";
private static final String CHARSET = "charset";
private static final String VERSION = "version";
private static final String SIGN = "sign";
private static final String CERTI_NO = "certiNo";
private static final String PHONE = "phone";
private static final String IS_ALLOW_CREDIT = "isAllowCredit";
private static final String ERROR_CODE = "errorCode";
private static final String ERROR_MSG = "errorMsg";
private static final String VAL_CHANNEL_NO = "DL-ZAXD001";
private static final String VAL_CHARSET_DEFAULT = "UTF-8";
private static final String VAL_FORMAT_DEFAULT = "json";
private static final String VAL_SIGN_TYPE_DEFAULT = "RSA";
private static final String VAL_SUCCESS_CODE = "0000";
private static final String VAL_SUCCESS_MSG = "";
private static final String VAL_VERSION = "1.0.0";
public String buildAvailAmountResult(Customer customer, DuolaiRequest request) {
if (customer == null) {
throw new CommonException("未查询到相关信息");
}
AvailAmountQuery query = queryZhonganCustomerCardNo(request);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
AvailAmountResult result = new AvailAmountResult();
result.setCreditAmount(BigDecimal.valueOf(customer.getLoanAmount()));
result.setUsedAmount(BigDecimal.valueOf(0));
result.setFrozenAmount(BigDecimal.valueOf(0));
result.setAvailableAmount(BigDecimal.valueOf(customer.getLoanAmount()));
result.setStartLoanAmount(BigDecimal.valueOf(customer.getLoanAmount()));
String applyDate = sdf.format(customer.getApplyDate());
result.setEffectiveDate(applyDate);
Calendar cal = Calendar.getInstance();
cal.setTime(customer.getApplyDate());
cal.add(Calendar.YEAR, 1);
result.setExpireDate(sdf.format(cal.getTime()));
result.setStatus(1);
result.setMaxLoanPeriods(12);
result.setSupportPeriods(Collections.singletonList(12));
Map respInner = new HashMap<>();
respInner.put(RESULT, result);
respInner.put(RESP_CODE, "0000");
respInner.put(RESP_MSG, "成功");
respInner.put(RESP_NO, UUID.randomUUID().toString());
respInner.put(REQ_NO, query.getReqNo());
//使用众安的公钥加密
String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(respInner),
zhonganPublicKey);
return bizContent;
}
public Map buildAvailAmountResp(String bizContent, String resultCode, String resultMsg) {
Map resp = new HashMap<>();
resp.put(BIZ_CONTENT, bizContent);// 业务数据
resp.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码
resp.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型
resp.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳
resp.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型
resp.put(ERROR_CODE, resultCode == null ? "" : resultCode);// 错误码
resp.put(ERROR_MSG, resultMsg == null ? "" : resultMsg);// 错误信息
// 供应商的私钥加签
String sign = SignUtil.doSign(resp, localPrivateKey);
// sign签名当成请求入参
resp.put(SIGN, sign);
return resp;
}
public AvailAmountQuery queryZhonganCustomerCardNo(DuolaiRequest request) {
Map req = buildZhonganReq(request, creditApplyService);
String getSign = String.valueOf(req.get(SIGN));
// 使用众安的公钥验签
boolean verify = SignUtil.rsa256CheckContent(req, getSign, zhonganPublicKey);
Assert.isTrue(verify, "验签失败");
// 使用供应商的私钥解密
String decryptBizContent = SignUtil.decryptRSAByPrivateKeyForLongData(String.valueOf(req.get(BIZ_CONTENT)),
localPrivateKey);
log.info("众安参数:" + decryptBizContent);
AvailAmountQuery query = JSONObject.parseObject(decryptBizContent, AvailAmountQuery.class);
if (query == null || StringUtils.isBlank(query.getCertiNo())) {
log.error("接收参数异常:{}", query);
throw new CommonException("接收参数异常");
}
return query;
}
private DuolaiDto queryDuolaiDto(DuolaiRequest request) {
if (request == null) {
throw new CommonException("未接受到参数");
}
Map req = buildZhonganReq(request, creditApplyService);
String getSign = String.valueOf(req.get(SIGN));
// 使用众安的公钥验签
// boolean verify = SignUtil.rsa256CheckContent(req, getSign, zhonganPublicKey);
// Assert.isTrue(verify, "验签失败");
// 使用供应商的私钥解密
String decryptBizContent = SignUtil.decryptRSAByPrivateKeyForLongData(String.valueOf(req.get(BIZ_CONTENT)),
localPrivateKey);
log.info("众安参数:" + decryptBizContent);
DuolaiDto dto = JSONObject.parseObject(decryptBizContent, DuolaiDto.class);
return dto;
}
public Customer buildZhongAnCustomer(DuolaiRequest request) {
DuolaiDto dto = queryDuolaiDto(request);
Customer customer = new Customer();
OcrInfoDto infoDto = dto.getOcrInfoDto();
customer.setName(infoDto.getName());
customer.setPhone(dto.getMobile());
customer.setIdCard(infoDto.getCertiNo());
OtherCreditInfo otherCreditInfo = dto.getOtherCreditInfo();
City one = cityService.getOne(new LambdaQueryWrapper().like(City::getName, otherCreditInfo.getContactCity()));
if (one != null) {
customer.setCity(one.getCityId());
customer.setCityName(one.getName());
}
customer.setSourceChannel(SourceTypeEnum.ZhongAn.getCode());
customer.setApplyDate(dto.getCreditApplyTime());
customer.setIdCardFrontPath(dto.getCertFrontImageId());
customer.setIdCardBackPath(dto.getCertBackImageId());
if (otherCreditInfo.getContact1Relation().equals(RelationshipEnum.PARENT.getCode())) {
customer.setRelationship("0");
customer.setRelationshipName(otherCreditInfo.getContact1Name());
customer.setRelationshipPhone(otherCreditInfo.getContact1Mobile());
} else if (otherCreditInfo.getContact1Relation().equals(RelationshipEnum.CHILD.getCode())) {
customer.setRelationship("1");
customer.setRelationshipName(otherCreditInfo.getContact1Name());
customer.setRelationshipPhone(otherCreditInfo.getContact1Mobile());
} else {
customer.setContact1Name(otherCreditInfo.getContact1Name());
customer.setContact1Phone(otherCreditInfo.getContact1Mobile());
}
if (otherCreditInfo.getContact2Relation().equals(RelationshipEnum.PARENT.getCode())) {
customer.setRelationship1("0");
customer.setRelationship1Name(otherCreditInfo.getContact2Name());
customer.setRelationship1Phone(otherCreditInfo.getContact2Mobile());
} else if (otherCreditInfo.getContact2Relation().equals(RelationshipEnum.CHILD.getCode())) {
customer.setRelationship1("1");
customer.setRelationship1Name(otherCreditInfo.getContact2Name());
customer.setRelationship1Phone(otherCreditInfo.getContact2Mobile());
} else {
customer.setContactName(otherCreditInfo.getContact2Name());
customer.setContactPhone(otherCreditInfo.getContact2Mobile());
}
customer.setEducation(queryEducation(otherCreditInfo.getFilledDegree()));
customer.setMaritalStatus(queryMarital(otherCreditInfo.getMarriage()));
customer.setMonthlyIncome(queryInCome(otherCreditInfo.getMonthlyPay()));
customer.setAddress(otherCreditInfo.getDetailedAddress());
customer.setAge(getAge(dto.getOcrInfoDto().getBirthday()));
if (StringUtils.isBlank(otherCreditInfo.getCompanyName())) {
customer.setEnterpriseInfo(EnterpriseInfoEnum.Enterprise_1.getCode());
} else {
customer.setEnterpriseInfo(EnterpriseInfoEnum.Enterprise_2.getCode());
}
customer.setLoanAmount(buildLoanAmount());
return customer;
}
private Double buildLoanAmount() {
Random random = new Random();
int i = random.nextInt(5) + 1;
return i * 10000.00;
}
private Integer getAge(String strDate) {
if (StringUtils.isBlank(strDate)) {
return null;
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date birthDay = null;
try {
birthDay = sdf.parse(strDate);
} catch (ParseException e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
if (cal.before(birthDay)) { //出生日期晚于当前时间,无法计算
throw new IllegalArgumentException(
"The birthDay is before Now.It's unbelievable!");
}
int yearNow = cal.get(Calendar.YEAR); //当前年份
int monthNow = cal.get(Calendar.MONTH); //当前月份
int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH); //当前日期
cal.setTime(birthDay);
int yearBirth = cal.get(Calendar.YEAR);
int monthBirth = cal.get(Calendar.MONTH);
int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
int age = yearNow - yearBirth; //计算整岁数
if (monthNow <= monthBirth) {
if (monthNow == monthBirth) {
if (dayOfMonthNow < dayOfMonthBirth) {
age--;
}//当前日期在生日之前,年龄减一
} else {
age--;//当前月份在生日之前,年龄减一1
}
}
return age;
}
private Integer queryInCome(Integer monthlyPay) {
for (MonthPayEnum m : MonthPayEnum.values()) {
if (m.getCode().equals(monthlyPay)) {
return m.getSys();
}
}
return null;
}
private String queryMarital(Integer marriage) {
for (MaritalStatusEnum maritalStatusEnum : MaritalStatusEnum.values()) {
return maritalStatusEnum.getSys();
}
return null;
}
private String queryEducation(Integer zhonganEducation) {
for (ZhonganEducationEnum educationEnum : ZhonganEducationEnum.values()) {
if (educationEnum.getCode().equals(zhonganEducation)) {
return educationEnum.getSys();
}
}
return null;
}
private Map buildZhonganReq(DuolaiRequest request, String serviceName) {
Map req = new HashMap<>();
req.put(APPKEY, zhonganAppKey);// appKey
req.put(SERVICE_NAME, serviceName);// serviceName
req.put(BIZ_CONTENT, request.getBizContent());// 业务数据
req.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳
req.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型
req.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型
req.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码
req.put(VERSION, VAL_VERSION);// API版本号
req.put(SIGN, request.getSign());
return req;
}
public Map buildZhonganResp(DuolaiRequest request, String status, String resultCode, String resultMsg) {
DuolaiDto dto = queryDuolaiDto(request);
CreditApplyResult result = new CreditApplyResult();
result.setOuterCreditApplyNo(result.getOuterCreditApplyNo());
result.setStatus(status);
result.setResultCode(resultCode);
result.setResultMsg(resultMsg);
Map respInner = new HashMap<>();
respInner.put(RESULT, result);
respInner.put(RESP_CODE, resultCode == null ? "0000" : resultCode);
respInner.put(RESP_MSG, resultMsg);
respInner.put(RESP_NO, UUID.randomUUID().toString());
respInner.put(REQ_NO, dto.getReqNo());
//使用众安的公钥加密
String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(respInner),
zhonganPublicKey);
Map resp = new HashMap<>();
resp.put(BIZ_CONTENT, bizContent);// 业务数据
resp.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码
resp.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型
resp.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳
resp.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型
resp.put(ERROR_CODE, resultCode == null ? "" : resultCode);// 错误码
resp.put(ERROR_MSG, resultMsg == null ? "" : resultMsg);// 错误信息
// 供应商的私钥加签
String sign = SignUtil.doSign(resp, localPrivateKey);
// sign签名当成请求入参
resp.put(SIGN, sign);
return resp;
}
public void callback(DuolaiRequest request, String status, Double money) {
DuolaiDto dto = queryDuolaiDto(request);
Map map = new HashMap<>();
map.put(CHANNEL_NO, dto.getChannelNo());
map.put(REQ_DATE, dto.getReqDate());
map.put(REQ_NO, dto.getReqNo());
map.put(THIRD_USER_NO, dto.getThirdUserNo());
map.put("productCode", dto.getProductCode());
map.put("creditApplyNo", dto.getOuterCreditApplyNo());
map.put("status", status);
map.put("creditApplyTime", DateFormatUtils.format(dto.getCreditApplyTime(), "yyyy-MM-dd HH:mm:ss"));
if (ZhongAnStatus.STATUS_3.getCode().equals(status)) {
map.put("creditAmount", BigDecimal.valueOf(money));
map.put("availableAmount", BigDecimal.valueOf(money));
Calendar cal = Calendar.getInstance();
cal.setTime(dto.getCreditApplyTime());
cal.add(Calendar.YEAR, 1);
map.put("quotaInvalidDate", DateFormatUtils.format(cal.getTime(), "yyyy-MM-dd HH:mm:ss"));
} else {
map.put("resultMsg", "订单常见失败");
}
//使用众安的公钥加密
String bizContent = SignUtil.encryptByPublicKeyWithNoOrderForLongData(JSONObject.toJSONString(map),
zhonganPublicKey);
Map req = new HashMap<>();
req.put(APPKEY, zhonganAppKey);// appKey
req.put(SERVICE_NAME, callbackService);// serviceName
req.put(BIZ_CONTENT, bizContent);// 业务数据
req.put(TIMESTAMP, DateFormatUtils.format(new Date(), "yyyyMMddHHmmssSSS"));// 时间戳
req.put(FORMAT, VAL_FORMAT_DEFAULT);// 格式化类型
req.put(SIGN_TYPE, VAL_SIGN_TYPE_DEFAULT);// 签名类型
req.put(CHARSET, VAL_CHARSET_DEFAULT);// 字节编码
req.put(VERSION, VAL_VERSION);// API版本号
req.put(SUPPLIER_NO, request.getSupplierNo());//TODO 供应商发起请求该值必填,值为众安侧分配的编码
// 供应商的私钥加签
String sign = SignUtil.doSign(req, localPrivateKey);
// sign签名当成请求入参
req.put(SIGN, sign);
// HttpUtil.post(zhonganUrl, req);
}
}