package com.nuvole.hnnx.hnnxPay;
|
|
import cn.hutool.core.date.DatePattern;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpResponse;
|
import com.alibaba.fastjson.JSON;
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.parser.Feature;
|
import com.csii.sg.codec.Hex;
|
import com.csii.sg.security.ValidationException;
|
import com.csii.sg.security.impl.Permutation;
|
import com.csii.sg.security.impl.SignatureVerifier;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.nuvole.hnnx.conf.NxPayConfig;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.lang.StringUtils;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Component;
|
|
import java.io.File;
|
import java.io.FileWriter;
|
import java.io.IOException;
|
import java.math.BigDecimal;
|
import java.security.PrivateKey;
|
import java.security.PublicKey;
|
import java.util.Base64;
|
import java.util.Date;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* @ClassName HttpClientUtils
|
* @Author cy
|
* @Date 2023/9/27
|
* @Description
|
* @Version 1.0
|
**/
|
|
@Component
|
@Slf4j
|
//@ConditionalOnClass(name = "com.nuvole.hnnx.conf.NxPayConfig")
|
public class NXHttpClientUtils {
|
@Autowired
|
private PrivateKey nxPayPrivateKey;
|
@Autowired
|
private PrivateKey nxKjPayPrivateKey;
|
|
@Autowired
|
private PublicKey nxPayPublicKey;
|
@Autowired
|
private PublicKey nxKjPayPublicKey;
|
|
@Autowired
|
private NxPayConfig nxPayConfig;
|
|
private static SignatureSigner signable = new SignatureSigner();
|
|
private static SignatureVerifier verifier = new SignatureVerifier();
|
|
public String getPlatSubMerchantId() {
|
return nxPayConfig.getPlatSubMerchantId();
|
}
|
|
public String getKjPlatSubMerchantId() {
|
return nxPayConfig.getKjPlatSubMerchantId();
|
}
|
|
public String getBranchId() {
|
return nxPayConfig.getBranchId();
|
}
|
|
|
/**
|
* 分转为元
|
*
|
* @param payMoney
|
* @return
|
*/
|
public static BigDecimal convertToYuan(long payMoney) {
|
BigDecimal totalAmount = new BigDecimal("" + payMoney).divide(new BigDecimal("100"));
|
return totalAmount;
|
}
|
|
public static void writeToFile(String sign, String plainStr) {
|
File file = new File("D:\\dev_nginx-1.18.0\\html\\testNetPay4.html");
|
|
String content = "<!DOCTYPE html>\n" +
|
"<html lang=\"en\">\n" +
|
"<head>\n" +
|
" <meta charset=\"UTF-8\">\n" +
|
" <title>Title</title>\n" +
|
"\n" +
|
"</head>\n" +
|
"<body>\n" +
|
"\n" +
|
"</body>\n" +
|
"<script>\n" +
|
// " var url = \"http://221.176.112.3:8006/pmPay/pmPay/quickPayRequest.do\";\n" +
|
" var url = \"http://https://pay.hnnx.com/pmPay/pmPay/quickPayRequest.do\";\n" +
|
" var data ={\n" +
|
" \"deviceType\":\"5\",\n" +
|
" \"signature\": \"" + sign + "\",\n" +
|
" \"plain\": JSON.stringify(" + plainStr + ")\n" +
|
" }\n" +
|
" post(url, data);\n" +
|
" var myForm;\n" +
|
"\n" +
|
" function post(URL, pram) {\n" +
|
" var temp = document.createElement(\"form\");\n" +
|
" temp.action = URL;\n" +
|
" temp.method = \"post\";\n" +
|
" temp.style.display = \"none\";\n" +
|
" for (var x in pram) {\n" +
|
" var opt = document.createElement(\"textarea\");\n" +
|
" opt.name = x;\n" +
|
" opt.value = pram[x];\n" +
|
" // alert(opt.name)\n" +
|
" temp.appendChild(opt);\n" +
|
" }\n" +
|
" document.body.appendChild(temp);\n" +
|
" temp.submit();\n" +
|
"// myForm=temp;\n" +
|
" }\n" +
|
"</script>\n" +
|
"</html>\n";
|
|
try (FileWriter writer = new FileWriter(file)) {
|
writer.write(content);
|
System.out.println("内容成功写入文件。");
|
} catch (IOException e) {
|
System.err.println("写入文件时发生错误:" + e.getMessage());
|
}
|
}
|
|
public static void writeToFile(String url) {
|
File file = new File("D:\\dev_nginx-1.18.0\\html\\redirect1.html");
|
|
String content = "<!DOCTYPE html>\n" +
|
"<html>\n" +
|
"<head>\n" +
|
" <meta http-equiv=\"refresh\" content=\"0; URL='" + url +
|
"'\" />\n" +
|
"</head>\n" +
|
"<body>\n" +
|
" <h1>正在跳转,请稍等...</h1>\n" +
|
"</body>\n" +
|
"</html>\n";
|
|
try (FileWriter writer = new FileWriter(file)) {
|
writer.write(content);
|
System.out.println("内容成功写入文件。");
|
} catch (IOException e) {
|
System.err.println("写入文件时发生错误:" + e.getMessage());
|
}
|
}
|
|
/**
|
* 加签方法
|
*
|
* @param headerMap 加密报文头
|
* @param payloadJson 加密报文体
|
* @return
|
*/
|
public String sign(Map headerMap, String payloadJson) {
|
log.info("----------- 签名开始 ----------- ");
|
log.info("请求参数payloadJson:{}", payloadJson);
|
ObjectMapper objectMapper = new ObjectMapper();
|
String palin = null;
|
try {
|
if (payloadJson != null) {
|
Map payloadMap = objectMapper.readValue(payloadJson, Map.class);
|
headerMap.putAll(payloadMap);
|
}
|
palin = Permutation.sort(headerMap, "UTF-8");
|
log.info("待签名字符串:{}", palin);
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
String sign = signable.sign(palin, nxPayPrivateKey);
|
log.info("签名结果:{}", sign);
|
log.info("----------- 签名结束 ----------- ");
|
return sign;
|
}
|
|
public String kjSign(String palin) {
|
log.info("----------- 签名开始 ----------- ");
|
log.info("请求参数 palin:{}", palin);
|
String sign = signable.kjSign(palin, nxKjPayPrivateKey).replaceAll("\\s", "");
|
log.info("签名结果:{}", sign);
|
log.info("----------- 签名结束 ----------- ");
|
return sign;
|
}
|
|
// 回调通知校验
|
public boolean notifyRespVerify(String notifyParam) {
|
log.info("回调通知验签 body 为: {}", notifyParam);
|
int signIndex = notifyParam.lastIndexOf("&signature=");
|
|
if (signIndex == -1) {
|
return false;
|
}
|
|
String palin = notifyParam.substring(0, signIndex);
|
String sign = notifyParam.substring(signIndex).replace("&signature=", "");
|
|
boolean verfiy = false;
|
try {
|
verfiy = verifier.verify(HnnxConstant.ALGORITHM, palin.getBytes(), Hex.toByte(sign), nxPayPublicKey);
|
} catch (ValidationException e) {
|
e.printStackTrace();
|
}
|
|
if (verfiy) {
|
log.info("返回值验签 结果:{}", verfiy);
|
} else {
|
log.error("返回值验签 结果:{}", verfiy);
|
}
|
log.info("----------- 返回值验签 结束 ----------- ");
|
return verfiy;
|
}
|
|
public String sendForm(HttpRequest nxPayHttpClient, HashMap<String, Object> payLoadMap) {
|
log.info("transCode : {}", nxPayHttpClient.header("transCode"));
|
Map headerMap = nxPayConfig.getHeadMap(nxPayHttpClient.header("sequenceId"), nxPayHttpClient.header("timestamp"), nxPayHttpClient.header("branchId"));
|
HashMap<String, Object> formData = new HashMap<>();
|
formData.put("payload", JSONObject.toJSONString(payLoadMap));
|
// 及具体接口的请求报文构成。
|
log.info("请求头: {}", JSONObject.toJSONString(headerMap));
|
formData.put("signature", sign(headerMap, (String) formData.get("payload")));
|
log.info("请求参数: {}", JSONObject.toJSONString(formData));
|
HttpResponse httpResponse = nxPayHttpClient.form(formData).execute();
|
String body = httpResponse.body();
|
verify(body);
|
return body;
|
}
|
|
/**
|
* 预支付
|
* 可以实现用户到支付宝或微信的预支付功能。
|
*
|
* @param subMerchantId 二级商户号
|
* @param branchId 交易机构号
|
* @param merSeqNbr 商户总交易流水号
|
* @param transAmt 交易总金额
|
* @param timeStamp 商户交易时间
|
* @param channelNbr 渠道编号 01-O2O 02-B2C 03-扫码
|
* @param payTypCd B-支付宝扫码支付C-微信扫码支付D-银联扫码支付
|
* @param orderTitle 订单标题
|
*/
|
public String qrCodePrePay(String subMerchantId, String branchId, String operatorId, String merSeqNbr, String authCode, long transAmt, String timeStamp, String channelNbr, char payTypCd,
|
String merUrl, String orderTitle) {
|
log.info("----------------- 预支付 开始 订单号为: {},订单金额为:{}----------------- ", merSeqNbr, transAmt);
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
//请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
|
// String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
|
// nxPayHttpClient.header("sequenceId", sequenceId);
|
nxPayHttpClient.header("timestamp", timeStamp);
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_QRCODEPREPAY_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getMerNbr());
|
// 二级商户编号
|
formData.put("SubMerchantId", subMerchantId);
|
//商户交易时间
|
formData.put("MerTransDateTime", timeStamp);
|
//交易总金额
|
formData.put("TransAmt", convertToYuan(transAmt));
|
formData.put("AuthCode", authCode);
|
|
//渠道编号 01-O2O 02-B2C 03-扫码
|
formData.put("ChannelNbr", channelNbr);
|
//支付方式 8-线上支付宝扫码支付9-线上微信扫码支付A-线上银联扫码支付B-线下支付宝扫码支付C-线下微信扫码支付D-线下银联扫码支付
|
formData.put("PayTypCd", payTypCd);
|
formData.put("OrderTitle", orderTitle);
|
formData.put("CurrencyCd", "CNY");
|
//异步通知Url
|
formData.put("MerUrl", merUrl);
|
//操作员
|
formData.put("OperatorId", operatorId);
|
|
//支付订单号
|
formData.put("MerSeqNbr", merSeqNbr);
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 预支付 结束 ----------------- ");
|
return body;
|
}
|
|
/**
|
* 用户主动扫码生成
|
* 用户需要扫描商户收款码动码进行支付时,通过此接口生成商户收款码动码,生产上现在微信主扫动码已经停止使用。
|
*
|
* @param subMerchantId 二级商户号
|
* @param branchId 交易机构号
|
* @param merSeqNbr 商户总交易流水号
|
* @param transAmt 交易总金额
|
* @param timeStamp 商户交易时间
|
* @param channelNbr 渠道编号 01-O2O 02-B2C 03-扫码
|
* @param payTypCd B 支付宝扫码支付 C 微信扫码支付 D 银联扫码支付
|
* @param orderTitle 订单标题
|
*/
|
public String dyActiveQrCode(String subMerchantId, String branchId, String merSeqNbr, long transAmt, String timeStamp, String channelNbr, char payTypCd,
|
String merUrl, String orderTitle) {
|
log.info("----------------- 用户主动扫码生成 开始 订单号为: {},订单金额为:{}----------------- ", merSeqNbr, transAmt);
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
//请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
|
// String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
|
// nxPayHttpClient.header("sequenceId", sequenceId);
|
nxPayHttpClient.header("timestamp", timeStamp);
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_DYACTIVEQRCODE_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getMerNbr());
|
//商户总交易流水号
|
formData.put("MerSeqNbr", merSeqNbr);
|
//交易总金额
|
formData.put("TransAmt", convertToYuan(transAmt));
|
//商户交易时间
|
formData.put("MerTransDateTime", timeStamp);
|
//渠道编号 01-O2O 02-B2C 03-扫码
|
formData.put("ChannelNbr", channelNbr);
|
formData.put("CurrencyCd", "CNY");
|
//支付方式 B 支付宝扫码支付 C 微信扫码支付 D 银联扫码支付
|
formData.put("PayTypCd", payTypCd);
|
// 二级商户编号
|
formData.put("SubMerchantId", subMerchantId);
|
//异步通知Url
|
formData.put("MerUrl", merUrl);
|
formData.put("OrderTitle", orderTitle);
|
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 用户主动扫码生成 结束 ----------------- ");
|
return body;
|
}
|
|
/**
|
* 用户被扫支付
|
* 第三方平台扫描用户付款码,通过此接口提交支付
|
*/
|
public String coretoall(String subMerchantId, String branchId, String merSeqNbr, long transAmt, String payAuthCode, String timeStamp, String channelNbr,
|
String merUrl, String orderTitle, String terminalCode) {
|
log.info("----------------- 用户被扫支付 开始, 订单编号= {} ,订单金额为:{}----------------- ", merSeqNbr, transAmt);
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
|
nxPayHttpClient.header("timestamp", timeStamp);
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_CORETOALL_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getMerNbr());
|
//商户总交易流水号
|
formData.put("MerSeqNbr", merSeqNbr);
|
//交易总金额
|
formData.put("TransAmt", convertToYuan(transAmt));
|
//商户交易时间
|
formData.put("MerTransDateTime", timeStamp);
|
//二维码
|
formData.put("QrCodeInfo", payAuthCode);
|
//渠道编号 01-O2O 02-B2C 03-扫码
|
formData.put("ChannelNbr", channelNbr);
|
formData.put("CurrencyCd", HnnxConstant.CURRENCYCD);
|
formData.put("AreaInfo", HnnxConstant.AREAINFO);
|
|
// 二级商户编号
|
formData.put("SubMerchantId", subMerchantId);
|
//订单详情
|
formData.put("OrderTitle", orderTitle);
|
//异步通知Url
|
formData.put("MerUrl", merUrl);
|
//商户终端设备类型
|
formData.put("TerminalType", "04");
|
//终端编号 由柜员在后管添加终端时生成
|
formData.put("Equipid", "002000156");
|
//终端序列号
|
formData.put("Equipseqnbr", "000002041170132246");
|
formData.put("Lgtude", "113.988007");
|
formData.put("Lttude", "34.819642");
|
formData.put("AppVersion", "01234567");
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 用户被扫支付 结束 ----------------- ");
|
return body;
|
}
|
|
/**
|
* 订单交易状态查询
|
* 接口说明
|
* 该接口提供支付、退款交易的交易状态查询。
|
* 根据交易状态TransStatus确定交易结果;
|
* 微信退款交易状态查询,非银行卡交易一般在15秒内可查询交易成功,银行卡交易退款需在两分钟后可查询到交易成功。
|
*
|
* @param merSeqNbr 订单流水号
|
* @return
|
* @throws Exception
|
*/
|
public String qryQrOrderStatus(String merSeqNbr, String branchId) {
|
log.info("----------------- 订单交易状态查询 开始----------------- ");
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
String timeStamp = DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
|
//请求序列号【渠道端产生,一笔业务的唯一标识,贯穿整个交易始终】渠道代码(2位)+日期(yyMMdd 6位)+流水号(24位,appCode+剩余位数流水号)
|
// String sequenceId = getSequenceId(timeStamp, nxPayConfig.getAppCode());
|
// nxPayHttpClient.header("sequenceId", sequenceId);
|
nxPayHttpClient.header("timestamp", timeStamp);
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_QRYQRORDERSTATUS_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getMerNbr());
|
//商户总交易流水号
|
formData.put("MerSeqNbr", merSeqNbr);
|
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 订单交易状态查询 结束 ----------------- ");
|
return body;
|
}
|
|
/**
|
* 退款
|
*
|
* @param subMerchantId 原支付交易二级商户号
|
* @param branchId
|
* @param merSeqNbr 要退款的订单号
|
* @param merSeqDate 要退款的订单交易日期 例:20190810
|
* @param origTransAmt 要退款的订单的交易金额
|
* @param transAmt 退款金额
|
* @param timeStamp 当前日期 例:yyyyMMddHHmmss
|
* @return
|
*/
|
public String returntrans(String subMerchantId, String branchId, String merSeqNbr, String merSeqDate, long origTransAmt,
|
long transAmt, String timeStamp) {
|
log.info("----------------- 退款 开始----------------- ");
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
nxPayHttpClient.header("timestamp", timeStamp);
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_RETURNTRANS_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getMerNbr());
|
//商户总交易流水号
|
formData.put("MerSeqNbr", "TK_" + merSeqNbr);
|
//退货交易时间
|
formData.put("MerTransDateTime", timeStamp);
|
|
//原商户流水
|
formData.put("OrigMerSeqNbr", merSeqNbr);
|
//原商户日期
|
formData.put("OrigMerDate", merSeqDate);
|
//原支付交易金额
|
formData.put("OrigTransAmt", convertToYuan(origTransAmt));
|
//二级商户号
|
formData.put("SubMerchantId", subMerchantId);
|
|
//退货二级商户流水号(随机生成,不允许出现重复,可以和一级商户交易流水号保持一致)
|
formData.put("SubMerSeqNo", "TK_" + merSeqNbr);
|
//二级商户时间
|
formData.put("SubMerDateTime", timeStamp);
|
//二级商户退货交易退货金额
|
formData.put("SubTransAmt", convertToYuan(transAmt));
|
//原二级商户支付流水号(与原支付交易一级商户号流水号一致)
|
formData.put("OrigSubMerSeqNo", merSeqNbr);
|
//原二级商户支付交易日期(例:20190810)
|
formData.put("OrigSubMerDate", merSeqDate);
|
//订单号 与二级商户流水号保持一致
|
formData.put("OrderNbr", merSeqNbr);
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 退款 结束----------------- ");
|
return body;
|
}
|
|
/**
|
* 对账查询
|
* String subMerchantId, String branchId,
|
*
|
* @param clearDate 对账日期 YYYY-MM-DD
|
* @param branchId 交易机构号
|
* @return
|
*/
|
public String accountqry(String clearDate, String branchId) {
|
log.info("----------------- 对帐 开始----------------- ");
|
HttpRequest nxPayHttpClient = nxPayConfig.getPayCloseableHttpClient();
|
nxPayHttpClient.header("timestamp", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
|
nxPayHttpClient.header("transCode", HnnxConstant.TRANS_CODE_ACCOUNTQRY_PAY);
|
nxPayHttpClient.header("branchId", branchId);
|
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
formData.put("ClearDate", clearDate);
|
|
String body = sendForm(nxPayHttpClient, formData);
|
log.info("----------------- 对帐 结束----------------- ");
|
return body;
|
}
|
|
// 订单号生成规则 “渠道简称-订单号-主/优惠-发起支付次数”构成
|
// 例如商圈的主订单第一次发起支付,订单号就是“SQ-商圈订单id-Z-1”
|
// 如果这个订单关联有优惠金,优惠金订单号就是"SQ-商圈订单id-Y-1"
|
public static String getNxPayOrderId(String prefix, long orderId, char orderType, short tryNum) {
|
return new StringBuilder(prefix).append("-").append(orderId).append("-").append(orderType).append("-").append(tryNum).toString();
|
}
|
|
/**
|
* 验签
|
*
|
* @return
|
*/
|
public boolean verify(String body) {
|
log.info("返回值验签 body 为: {}", body);
|
log.info("----------- 返回值验签 开始 ----------- ");
|
boolean verfiy = false;
|
try {
|
Map<String, Object> bodyMap = JSON.parseObject(body, Feature.OrderedField);
|
String sign = (String) bodyMap.remove("signature");
|
String payload = (String) bodyMap.remove("payload");
|
|
ObjectMapper objectMapper = new ObjectMapper();
|
if (payload != null) {
|
Map payloadMap = objectMapper.readValue(payload, Map.class);
|
bodyMap.putAll(payloadMap);
|
}
|
String palin = null;
|
palin = Permutation.sort(bodyMap, "UTF-8");
|
log.info("排序后的字符串:{}", palin);
|
if (StringUtils.isNotEmpty(sign)) {
|
verfiy = verifier.verify(HnnxConstant.ALGORITHM, palin.getBytes(), Hex.toByte(sign), nxPayPublicKey);
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
log.error("返回值验签 结果:{}", verfiy);
|
log.info("----------- 返回值验签 结束 ----------- ");
|
return verfiy;
|
}
|
|
public boolean kjVerify(String sign, String palin) {
|
log.info("返回值验签 palin 为: {}", palin);
|
log.info("返回值验签 sign 为: {}", sign);
|
log.info("----------- 返回值验签 开始 ----------- ");
|
boolean verfiy = false;
|
try {
|
if (StringUtils.isNotEmpty(sign)) {
|
verfiy = verifier.verify(HnnxConstant.KJ_ALGORITHM, palin.getBytes(), Base64.getDecoder().decode(sign), nxKjPayPublicKey);
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
log.error("返回值验签 结果:{}", verfiy);
|
log.info("----------- 返回值验签 结束 ----------- ");
|
return verfiy;
|
}
|
|
/**
|
* 通用快捷支付
|
*
|
* @param merSeqNbr 商户流水号
|
* @param subMerchantId 二级商户号
|
* @param backURL 后台通知URL
|
* @param frontURL 返回前端URL
|
*/
|
public String quickPayRequest(String subMerchantId, String merSeqNbr, long transAmt, String nowTime,
|
String frontURL, String backURL, String orderTitle) {
|
log.info("----------------- 通用快捷支付 开始, 订单编号= {} ,订单金额为:{}----------------- ", merSeqNbr, transAmt);
|
|
|
// 拼接业务数据
|
JSONObject formData = new JSONObject();
|
formData.put("deviceType", "5");
|
|
HashMap<String, Object> plainData = new HashMap<>();
|
// plain 开始
|
//一级商户id
|
// plainData.put("merchId", "010020170801000001");
|
plainData.put("merchId", nxPayConfig.getKjMerNbr());
|
//优惠前金额 disCountAmt
|
//订单名称 orderName
|
plainData.put("orderName", orderTitle);
|
//币种 ccy
|
plainData.put("ccy", "01");
|
//返回前端URL frontURL
|
plainData.put("frontURL", frontURL);
|
//后台通知URL backURL
|
plainData.put("backURL", backURL);
|
//订单备注 orderRemark
|
plainData.put("orderRemark", "");
|
//渠道号 channelNbr
|
plainData.put("channelNbr", "02");
|
//交易总金额 txnAmt
|
plainData.put("txnAmt", convertToYuan(transAmt));
|
//商户流水号 merSeqNbr
|
plainData.put("merSeqNbr", merSeqNbr);
|
//交易时间 orderTime
|
plainData.put("orderTime", nowTime);
|
//收款方名称 payee
|
//优惠活动名称 specialOffers
|
|
//商户订单号 merchOrderId
|
plainData.put("merchOrderId", merSeqNbr);
|
|
JSONArray plainMerTrans = new JSONArray();
|
JSONObject plainMerTransData1 = new JSONObject();
|
//子交易金额
|
plainMerTransData1.put("subTransAmt", convertToYuan(transAmt));
|
//二级商户号
|
plainMerTransData1.put("subMerchantId", subMerchantId);
|
//二级商户交易时间 subMerDateTime
|
plainMerTransData1.put("subMerDateTime", nowTime);
|
//子流水号 subMerSeqNo
|
plainMerTransData1.put("subMerSeqNo", merSeqNbr);
|
//二级商户名称 subMerchantName
|
plainMerTransData1.put("subMerchantName", "");
|
//二级商户商品信息 productInfo
|
plainMerTransData1.put("productInfo", "");
|
//二级商户信息 subMerImport
|
// plainMerTransData1.put("subMerImport", "学费");
|
// plainMerTransData1.put("subMerImport", orderTitle);
|
//卡券号 platCouponId
|
plainMerTransData1.put("platCouponId", "");
|
//子卡券交易金额 platCouponAmount
|
plainMerTransData1.put("platCouponAmount", "");
|
//子积分数 bonusPoint
|
plainMerTransData1.put("bonusPoint", "");
|
//子积分交易金额 bonusPointAmount
|
plainMerTransData1.put("bonusPointAmount", "");
|
|
// plainMerTransData1.put("subInteralAmt", "0.01");
|
// plainMerTransData1.put("subCouponAmt", "");
|
|
plainMerTrans.add(plainMerTransData1);
|
plainData.put("MerTransList", plainMerTrans);
|
|
String plainStr = JSONObject.toJSONString(plainData);
|
log.info("请求参数:{}", plainStr);
|
// formData.put("plain", plainData);
|
formData.put("plain", plainStr);
|
// plain 结束
|
|
// 开始签名
|
String signature = kjSign(plainStr);
|
formData.put("signature", signature);
|
// writeToFile(signature, plainStr);
|
|
HttpResponse httpResponse = HttpRequest.post(nxPayConfig.getKjUrl() + HnnxConstant.QUICK_PAY_URL)
|
.contentType("application/x-www-form-urlencoded;")
|
.form(formData.getInnerMap())
|
.timeout(20000)//超时,毫秒
|
.execute();
|
String location = null;
|
log.info("----------------- 通用快捷支付 结束 ----------------- ");
|
if (httpResponse.getStatus() == 302) {
|
location = httpResponse.header("Location");
|
// writeToFile(location);
|
return location;
|
}else {
|
throw new RuntimeException(httpResponse.body());
|
}
|
|
}
|
|
/**
|
* 快捷支付 订单状态查询
|
*
|
* @param orderNbr 订单编号
|
* @param startDate 起始日期 yyyyMMdd
|
* @param endDate 结束日期 yyyyMMdd
|
* @param pageSize 每页记录数
|
* @param pageNum 当前第几页
|
* @return
|
*/
|
|
public String quickPayOrderQueryRequest(String orderNbr, String startDate, String endDate, int pageSize, int pageNum) {
|
log.info("----------------- 快捷支付订单交易状态查询 开始----------------- ");
|
String body = null;
|
JSONObject formData = new JSONObject();
|
formData.put("MerNbr", nxPayConfig.getKjMerNbr());
|
//订单编号
|
if (StringUtils.isNotEmpty(orderNbr)) {
|
formData.put("OrderNbr", orderNbr);
|
}
|
//起始日期
|
if (StringUtils.isNotEmpty(orderNbr)) {
|
formData.put("StartDate", startDate);
|
}
|
//结束日期
|
if (StringUtils.isNotEmpty(orderNbr)) {
|
formData.put("EndDate", endDate);
|
}
|
//每页记录数
|
formData.put("PageSize", pageSize);
|
//当前第几页
|
formData.put("PageNum", pageNum);
|
log.info("快捷支付订单查询参数:{}", formData);
|
body = HttpRequest.post(nxPayConfig.getKjUrl() + HnnxConstant.QUICK_PAY_QUERY_URL)
|
.contentType("application/x-www-form-urlencoded;")
|
.form(formData.getInnerMap())
|
.timeout(20000)//超时,毫秒
|
.execute().body();
|
log.info("快捷支付订单查询请求结果:{}", body);
|
log.info("----------------- 快捷支付订单交易状态查询 结束 ----------------- ");
|
return body;
|
}
|
|
/**
|
* 退款
|
*
|
* @param subMerchantId 原支付交易二级商户号
|
* @param merSeqNbr 要退款的订单号
|
* @param merSeqDate 要退款的订单交易日期 yyyyMMdd 例:20190810
|
* @param origTransAmt 要退款的订单的交易金额
|
* @param transAmt 退款金额
|
* @param timeStamp 当前日期 例:yyyyMMddHHmmss
|
* @return
|
*/
|
public String quickPayReturntrans(String subMerchantId, String merSeqNbr, String merSeqDate, long origTransAmt,
|
long transAmt, String timeStamp) {
|
log.info("----------------- 退款 开始----------------- ");
|
String timeStampWithSpace = timeStamp.substring(0, 8) + " " + timeStamp.substring(8);
|
// 拼接业务数据
|
HashMap<String, Object> formData = new HashMap<>();
|
// 一级商户号
|
formData.put("MerNbr", nxPayConfig.getKjMerNbr());
|
//商户总交易流水号
|
formData.put("MerSeqNbr", "TK_" + merSeqNbr);
|
//退货交易时间 yyyyMMdd HHmmss 差异!!!!
|
formData.put("MerTransDateTime", timeStampWithSpace);
|
// formData.put("MerTransDateTime", timeStamp);
|
|
//原商户流水
|
formData.put("OrigMerSeqNbr", merSeqNbr);
|
//原商户日期
|
formData.put("OrigMerDate", merSeqDate);
|
//原支付交易金额
|
formData.put("OrigTransAmt", convertToYuan(origTransAmt));
|
|
//二级商户号
|
formData.put("SubMerchantId", subMerchantId);
|
//退货二级商户流水号(随机生成,不允许出现重复,可以和一级商户交易流水号保持一致)
|
formData.put("SubMerSeqNo", "TK_" + merSeqNbr);
|
//二级商户时间
|
formData.put("SubMerDateTime", timeStampWithSpace);
|
// formData.put("SubMerDateTime", timeStamp);
|
//二级商户退货交易退货金额
|
formData.put("SubTransAmt", convertToYuan(transAmt));
|
|
|
//原二级商户支付流水号(与原支付交易一级商户号流水号一致)
|
formData.put("OrigSubMerSeqNo", merSeqNbr);
|
//原二级商户支付交易日期(例:20190810)
|
formData.put("OrigSubMerDate", merSeqDate);
|
//订单号 与二级商户流水号保持一致
|
formData.put("OrderNbr", merSeqNbr);
|
log.info("快捷支付订单退款参数:{}", formData);
|
|
String body = null;
|
HttpResponse httpResponse = HttpRequest.post(nxPayConfig.getKjUrl() + HnnxConstant.QUICK_PAY_RETURN_URL)
|
.contentType("application/x-www-form-urlencoded;")
|
.form(formData)
|
.timeout(20000)//超时,毫秒
|
.execute();
|
body = httpResponse.body();
|
log.info(" 快捷支付退款结果:{}", body);
|
log.info("----------------- 退款 结束----------------- ");
|
return body;
|
}
|
|
|
|
}
|