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 = "\n" + "\n" + "\n" + " \n" + " Title\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\n" + "\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 = "\n" + "\n" + "\n" + " \n" + "\n" + "\n" + "

正在跳转,请稍等...

\n" + "\n" + "\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 payLoadMap) { log.info("transCode : {}", nxPayHttpClient.header("transCode")); Map headerMap = nxPayConfig.getHeadMap(nxPayHttpClient.header("sequenceId"), nxPayHttpClient.header("timestamp"), nxPayHttpClient.header("branchId")); HashMap 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 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 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 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 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 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 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 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 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 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; } }