package com.ruoyi.order.util.payment;
|
|
import cn.hutool.http.ContentType;
|
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpResponse;
|
import cn.hutool.http.HttpUtil;
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.ruoyi.order.util.payment.model.*;
|
import lombok.extern.slf4j.Slf4j;
|
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.*;
|
|
/**
|
* 转账代付工具类
|
* @author zhibing.pu
|
* @Date 2024/12/30 19:54
|
*/
|
@Slf4j
|
public class TransferUtil {
|
/**
|
* 商户密钥
|
*/
|
private static final String key = "925899fcc374430f9e4b4ba3db05b448";
|
/**
|
* 商户号
|
*/
|
private static final String merchantNo = "888122600004175";
|
/**
|
* 平台-报备商户号
|
*/
|
public static final String sysTradeMerchantNo = "777168500885852";
|
|
private static final String format = "yyyy-MM-dd HH:mm:ss";
|
/**
|
* 支付回调地址
|
*/
|
private static final String callbackUrl = "https://www.qijisheng.top";
|
|
|
/**
|
* 单笔代付
|
* @param singlePay
|
* @return
|
*/
|
public static SinglePayResult singlePay(SinglePay singlePay){
|
String url = "https://www.joinpay.com/payment/pay/singlePay";
|
HttpRequest post = HttpUtil.createPost(url);
|
post.contentType(ContentType.JSON.toString());
|
JSONObject body = new JSONObject();
|
//商户编号
|
body.put("userNo", merchantNo);
|
//报备商户号
|
// body.put("tradeMerchantNo", singlePay.getTradeMerchantNo());
|
//产品类型
|
body.put("productCode", "BANK_PAY_DAILY_ORDER");
|
//交易请求时间
|
body.put("requestTime", LocalDateTime.now().format(DateTimeFormatter.ofPattern(format)));
|
//商户订单号
|
body.put("merchantOrderNo", singlePay.getMerchantOrderNo());
|
//收款账户号,收款人银行卡卡号
|
body.put("receiverAccountNoEnc", singlePay.getReceiverAccountNoEnc());
|
//收款人,收款人银行卡持卡人名称
|
body.put("receiverNameEnc", singlePay.getReceiverNameEnc());
|
//账户类型
|
body.put("receiverAccountType", singlePay.getReceiverAccountType());
|
//收款账户联行号 对公账户必须填写此字段
|
body.put("receiverBankChannelNo", singlePay.getReceiverBankChannelNo());
|
//交易金额
|
body.put("paidAmount", singlePay.getPaidAmount());
|
//币种
|
body.put("currency", "201");
|
//是否复核 复核:201,不复核:202
|
body.put("isChecked", "202");
|
//代付说明
|
body.put("paidDesc", singlePay.getPaidDesc());
|
//代付用途
|
/**
|
* 工资奖金 201
|
* 活动经费 202
|
* 养老金 203
|
* 货款 204
|
* 劳务费 205
|
* 保险理财 206
|
* 资金下发 207
|
* 营业款 208
|
* 退回款项 210
|
* 消费款项 211
|
*/
|
body.put("paidUse", singlePay.getPaidUse());
|
//商户通知地址
|
body.put("callbackUrl", callbackUrl + singlePay.getCallbackUrl());
|
String sign = null;
|
try {
|
sign = sign(body);
|
} catch (Exception e) {
|
throw new RuntimeException(e);
|
}
|
body.put("hmac", sign);
|
post.body(body.toString());
|
log.info("单笔代付接口请求参数:" + body);
|
HttpResponse execute = post.execute();
|
log.info("单笔代付接口请求响应:" + execute.body());
|
if(200 != execute.getStatus()){
|
log.error("单笔代付接口异常:" + execute.body());
|
return null;
|
}
|
JSONObject jsonObject = JSON.parseObject(execute.body());
|
String statusCode = jsonObject.getString("statusCode");
|
if(!"2001".equals(statusCode) && !"2003".equals(statusCode)){
|
log.error("单笔代付接口异常:" + jsonObject.getString("message"));
|
return null;
|
}
|
if("2003".equals(statusCode)){
|
//汇聚不能确定订单状态,建议 10 分钟后发起查询确认。
|
log.error("单笔代付接口异常:汇聚不能确定订单状态,建议 10 分钟后发起查询确认。");
|
return null;
|
}
|
SinglePayResult uniPayResult = jsonObject.getObject("data", SinglePayResult.class);
|
return uniPayResult;
|
}
|
|
|
/**
|
* 单笔代付查询接口
|
* @param merchantOrderNo 订单号
|
* @return
|
*/
|
public static SinglePayQueryResult singlePayQuery(String merchantOrderNo){
|
String url = "https://www.joinpay.com/payment/pay/singlePayQuery";
|
HttpRequest post = HttpUtil.createPost(url);
|
post.contentType(ContentType.JSON.toString());
|
JSONObject body = new JSONObject();
|
//商户编号
|
body.put("userNo", merchantNo);
|
//商户订单号
|
body.put("merchantOrderNo", merchantOrderNo);
|
String sign = null;
|
try {
|
sign = sign(body);
|
} catch (Exception e) {
|
throw new RuntimeException(e);
|
}
|
body.put("hmac", sign);
|
post.body(body.toString());
|
log.info("单笔代付查询接口请求参数:" + body);
|
HttpResponse execute = post.execute();
|
log.info("单笔代付查询接口请求响应:" + execute.body());
|
if(200 != execute.getStatus()){
|
log.error("单笔代付查询接口异常:" + execute.body());
|
return null;
|
}
|
JSONObject jsonObject = JSON.parseObject(execute.body());
|
String statusCode = jsonObject.getString("statusCode");
|
if(!"2001".equals(statusCode) && !"2003".equals(statusCode)){
|
log.error("单笔代付查询接口异常:" + jsonObject.getString("message"));
|
return null;
|
}
|
if("2003".equals(statusCode)){
|
//汇聚不能确定订单状态,建议 10 分钟后发起查询确认。
|
log.error("单笔代付查询接口异常:汇聚不能确定订单状态,建议 10 分钟后发起查询确认。");
|
return null;
|
}
|
SinglePayQueryResult uniPayResult = jsonObject.getObject("data", SinglePayQueryResult.class);
|
return uniPayResult;
|
}
|
|
|
/**
|
* 可取余额查询
|
* @return
|
*/
|
public static AccountBalanceQueryResult accountBalanceQuery(){
|
String url = "https://www.joinpay.com/payment/pay/accountBalanceQuery";
|
HttpRequest post = HttpUtil.createPost(url);
|
post.contentType(ContentType.JSON.toString());
|
JSONObject body = new JSONObject();
|
//商户编号
|
body.put("userNo", merchantNo);
|
String sign = null;
|
try {
|
sign = sign(body);
|
} catch (Exception e) {
|
throw new RuntimeException(e);
|
}
|
body.put("hmac", sign);
|
post.body(body.toString());
|
log.info("可取余额查询接口请求参数:" + body);
|
HttpResponse execute = post.execute();
|
log.info("可取余额查询接口请求响应:" + execute.body());
|
if(200 != execute.getStatus()){
|
log.error("可取余额查询接口异常:" + execute.body());
|
return null;
|
}
|
JSONObject jsonObject = JSON.parseObject(execute.body());
|
String statusCode = jsonObject.getString("statusCode");
|
if(!"2001".equals(statusCode) && !"2003".equals(statusCode)){
|
log.error("可取余额查询接口异常:" + jsonObject.getString("message"));
|
return null;
|
}
|
if("2003".equals(statusCode)){
|
//汇聚不能确定订单状态,建议 10 分钟后发起查询确认。
|
log.error("可取余额查询接口异常:汇聚不能确定订单状态,建议 10 分钟后发起查询确认。");
|
return null;
|
}
|
AccountBalanceQueryResult uniPayResult = jsonObject.getObject("data", AccountBalanceQueryResult.class);
|
return uniPayResult;
|
}
|
|
|
|
|
public static String sign(JSONObject body) {
|
//构建字段顺序必须按照文档签名顺序
|
Set<Map.Entry<String, Object>> entries = body.entrySet();
|
// 构造签名键值对的格式
|
StringBuilder sb = new StringBuilder();
|
for (Map.Entry<String, Object> item : entries) {
|
if (item.getKey() != null || item.getKey() != "") {
|
Object val = item.getValue();
|
if (!(val == "" || val == null)) {
|
sb.append(val);
|
}
|
}
|
}
|
sb.append(key);
|
log.info("待签名串:{}", sb.toString());
|
return MD5AndKL.MD5(sb.toString());
|
}
|
|
|
}
|