记得上下班打卡 | git大法好,push需谨慎

Commit 2bf2ba2d authored by zhengfuxin's avatar zhengfuxin

抖音退款接口开发。

parent 745ac5fd
......@@ -13,6 +13,7 @@ public class DragonConstant {
public static final String REFUND_TYPE_WEB_ALIPAY="WEBALIPAY";//,"电脑网页内支付宝即时到账支付"),
public static final String REFUND_TYPE_WEB_WEPAY="WEBWEPAY";//,"电脑网页内微信二维码支付,用户打开微信扫码支付"),
public static final String REFUND_TYPE_JS_WEPAY="JSWEPAY";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_APPLET_DOUYIN="APPLETDOUYIN";//,"微信内网页、微信公众号"),
public static final String REFUND_TYPE_APPLET_WEPAY="APPLETWEPAY";//,"微信小程序");
......
......@@ -41,6 +41,8 @@ import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
......@@ -71,6 +73,7 @@ public class DragonOrderRefundsServiceImpl implements IDragonOrderRefundsService
dataUtils.setRefundNotifyUrl(orderRefundCode, notifyUrl);
DragonRefundChannelDto dto = null;
String localWePayCallBackUrl = url + "/refund/callBack/wepay";
String localDouYinCallBackUrl = url + "/refund/callBack/douYinPay";
if (insertResult) {
switch (paymentType) {
case DragonConstant.REFUND_TYPE_APP_ALIPAY:
......@@ -97,6 +100,9 @@ public class DragonOrderRefundsServiceImpl implements IDragonOrderRefundsService
case DragonConstant.REFUND_TYPE_APPLET_WEPAY:
dto = weyPayRefund(code, orderRefundCode, code, reason, price, priceTotal, paymentId, paymentType, localWePayCallBackUrl, nowTime);
break;
case DragonConstant.REFUND_TYPE_APPLET_DOUYIN:
dto = douYinRefund(code, orderRefundCode, code, reason, price, priceTotal, paymentId, paymentType, localDouYinCallBackUrl, nowTime);
break;
}
log.info("dto = " + JSON.toJSONString(dto));
......@@ -128,6 +134,112 @@ public class DragonOrderRefundsServiceImpl implements IDragonOrderRefundsService
return ResponseDto.failure("退款失败:" + e.getMessage());
}
}
/**
* @author zhangfuxin
* @Description: 抖音退款接口
* @date 2021/11/10 下午3:22
*/
public DragonRefundChannelDto douYinRefund(String orderRefundId, String refundCode, String code, String reason, BigDecimal price, BigDecimal priceTotal, String paymentId, String paymentType, String notifyUrl, LocalDateTime nowTime) {
try {
String refundStatus = DragonConstant.RefundStatusEnum.STATUS_ERROR.getCode();
DragonRefundChannelDto channelDto = new DragonRefundChannelDto();
RefundContentDto contentDto = new RefundContentDto();
SortedMap<String, Object> parameters = new TreeMap<>();
parameters.put("app_id",PayDouYinpayUtils.getInstance().getAPP_ID());
parameters.put("out_order_no",code);
parameters.put("out_refund_no",refundCode);
parameters.put("refund_amount",(int) (price.doubleValue() * 100));
parameters.put("reason",reason);
parameters.put("notify_url",notifyUrl);
String sign = PayDouYinpayUtils.getInstance().createSign(parameters);
parameters.put("sign",sign);
String data = JSON.toJSONString(parameters);
String refundError = "";
try {
log.info("调用抖音退款:{}",data);
HttpPost httpost = new HttpPost("https://developer.toutiao.com/api/apps/ecpay/v1/create_refund");
httpost.setEntity(new StringEntity(data, "UTF-8"));
CloseableHttpResponse response = PayDouYinpayUtils.getInstance().getHttpClient().execute(httpost);
try {
HttpEntity entity = response.getEntity();
entity.getContent();
String jsonStr = EntityUtils.toString(entity, "UTF-8");
log.info("douYinRefund 返参{}", jsonStr);
Map result=JSON.parseObject(jsonStr, HashMap.class);
//
if(!result.get("err_no").toString().equals("0")){
try {
refundStatus = DragonConstant.RefundStatusEnum.STATUS_ERROR.getCode();
refundError = result.get("err_tips").toString();
// 修改退款订单
mqHandleUtil.sendMySqlRedis(
SqlMapping.get("dragon_order_refund_error.update"),
new Object[]{nowTime, refundError, refundStatus, code},
DragonConstant.MysqlRedisQueueEnum.DRAGON_REFUND_KEY.getCode()
);
} catch (Exception e) {
e.printStackTrace();
//保存错误信息
log.error("");
channelDto.setResult("exception");
channelDto.setMessage("update order refund with db error: " + e.getMessage());
contentDto.setRequest(data);
contentDto.setResponse(jsonStr);
channelDto.setContent(contentDto);
return channelDto;
}
channelDto.setResult("error");
channelDto.setMessage(refundError);
contentDto.setRequest(data);
contentDto.setResponse(jsonStr);
channelDto.setContent(contentDto);
return channelDto;
}
// 创建退款日志
mqHandleUtil.sendMySqlRedis(
SqlMapping.get("dragon_order_refund_log.insert"),
new Object[]{orderRefundId, paymentType, data, nowTime, nowTime},
DragonConstant.MysqlRedisQueueEnum.DRAGON_REFUND_KEY.getCode()
);
try {
if (result.get("err_no").toString().equals("0")) {
refundStatus = DragonConstant.RefundStatusEnum.STATUS_REFUNDED.getCode();
}
mqHandleUtil.sendMySqlRedis(
SqlMapping.get("dragon_order_refund_success.update"),
new Object[]{nowTime, null, refundStatus, code},
DragonConstant.MysqlRedisQueueEnum.DRAGON_REFUND_KEY.getCode()
);
} catch (Exception e) {
e.printStackTrace();
log.error("");
channelDto.setResult("exception");
channelDto.setMessage("update order refund with db error: " + e.getMessage());
contentDto.setRequest(data);
contentDto.setResponse(jsonStr);
channelDto.setContent(contentDto);
return channelDto;
}
channelDto.setResult("refunded");
channelDto.setMessage(paymentType + " refund info: ");
contentDto.setRequest(data);
contentDto.setResponse(jsonStr);
channelDto.setContent(contentDto);
EntityUtils.consume(entity);
return channelDto;
} finally {
response.close();
}
} finally {
// PayWepayUtils.getInstance().getHttpClient().close();
}
}catch (Exception e) {
e.printStackTrace();
log.error("");
return null;
}
}
//微信退款接口
public DragonRefundChannelDto weyPayRefund(String orderRefundId, String refundCode, String code, String reason, BigDecimal price, BigDecimal priceTotal, String paymentId, String paymentType, String notifyUrl, LocalDateTime nowTime) {
......
package com.liquidnet.service.dragon.utils;
import com.alipay.api.internal.util.file.IOUtils;
import com.liquidnet.commons.lang.util.MD5Utils;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLContext;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.*;
public class PayDouYinpayUtils {
private CloseableHttpClient httpClient;
private static PayDouYinpayUtils instance = new PayDouYinpayUtils();
private final String merchantId = "1551961491";
private final String partnerKey = "itIuO65O9yKmemOu3S8g1S4orqvCGwXK";
private final String SALT = "D3rXySlTCR15LxYnmbEOaamGoOCbBNQAbFtaK39t";
private final String APP_ID="tt0d647bd9925c076801";
public static String md5FromStr(String inStr) {
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return "";
}
byte[] byteArray = inStr.getBytes(StandardCharsets.UTF_8);
byte[] md5Bytes = md5.digest(byteArray);
StringBuilder hexValue = new StringBuilder();
for (byte md5Byte : md5Bytes) {
int val = ((int) md5Byte) & 0xff;
if (val < 16) {
hexValue.append("0");
}
hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
}
public String createSign(Map<String, Object> paramsMap) {
List<String> paramsArr = new ArrayList<>();
for (Map.Entry<String, Object> entry : paramsMap.entrySet()) {
String key = entry.getKey();
if (key.equals("other_settle_params")) {
continue;
}
String value = entry.getValue().toString();
value = value.trim();
if (value.startsWith("\"") && value.endsWith("\"") && value.length() > 1) {
value = value.substring(1, value.length() - 1);
}
value = value.trim();
if (value.equals("") || value.equals("null")) {
continue;
}
switch (key) {
case "app_id":
case "thirdparty_id":
case "sign":
break;
default:
paramsArr.add(value);
break;
}
}
paramsArr.add(SALT);
Collections.sort(paramsArr);
StringBuilder signStr = new StringBuilder();
String sep = "";
for (String s : paramsArr) {
signStr.append(sep).append(s);
sep = "&";
}
return md5FromStr(signStr.toString());
}
public PayDouYinpayUtils() {
}
public static PayDouYinpayUtils getInstance() {
return instance;
}
public String getAPP_ID() {
return APP_ID;
}
public String getMerchantId() {
return merchantId;
}
public CloseableHttpClient getHttpClient() {
try {
if (httpClient == null) {
InputStream certStream = PayDouYinpayUtils.class.getClassLoader().getResourceAsStream("payCert/wepay/wepay_apiclient_cert.p12");
byte[] certData = IOUtils.toByteArray(certStream);
certStream.read(certData);
certStream.close();
KeyStore keyStore = KeyStore.getInstance("PKCS12");
ByteArrayInputStream inputStream = new ByteArrayInputStream(certData);
try {
keyStore.load(inputStream, merchantId.toCharArray());
} finally {
inputStream.close();
}
SSLContext sslcontext = SSLContexts.custom()
.loadKeyMaterial(keyStore, merchantId.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
httpClient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();
}
} catch (Exception e) {
e.printStackTrace();
}
return httpClient;
}
//生成随机字符串nonce_str
public String getNonceStr() {
String base = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 32; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
public String createSign(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
Object v = entry.getValue();
if (null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + partnerKey);
return MD5Utils.md5(sb.toString()).toUpperCase();
}
public String getRequestXml(SortedMap<String, Object> parameters) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
Set es = parameters.entrySet();
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
} else {
sb.append("<" + k + ">" + v + "</" + k + ">");
}
}
sb.append("</xml>");
return sb.toString();
}
public String unCodeReqInfo(String reqInfo) {
try {
Cipher cipher ;
String key = MD5Utils.md5(partnerKey);
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
Security.addProvider(new BouncyCastleProvider());
cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
Base64.Decoder decoder = Base64.getDecoder();
byte[] base64ByteArr = decoder.decode(reqInfo);
String result = new String(cipher.doFinal(base64ByteArr));
return result;
} catch (Exception e) {
e.printStackTrace();
return "";
}
}
@SuppressWarnings("unchecked")
public static Map<String, String> parseXml(InputStream inputStream) throws Exception {
if (inputStream == null) {
return null;
}
Map<String, String> map = new HashMap<String, String>();// 将解析结果存储在HashMap中
SAXReader reader = new SAXReader();// 读取输入流
Document document = reader.read(inputStream);
Element root = document.getRootElement();// 得到xml根元素
List<Element> elementList = root.elements();// 得到根元素的所有子节点
for (Element e : elementList) { // 遍历所有子节点
map.put(e.getName(), e.getText());
}
inputStream.close(); // 释放资源
inputStream = null;
return map;
}
public String getPartnerKey() {
return this.partnerKey;
}
public boolean notifySign(Map<String, String> result, String sign) {
String argNotifySign = getStringByStringMap(result) + "&key=" + this.partnerKey;
String notifySign = MD5Utils.md5(argNotifySign).toUpperCase();
if (notifySign.equals(sign)) {
return true;
} else {
return false;
}
}
public static String getStringByStringMap(Map<String, String> map) {
SortedMap<String, Object> smap = new TreeMap<String, Object>(map);
StringBuffer sb = new StringBuffer();
for (Map.Entry<String, Object> m : smap.entrySet()) {
sb.append(m.getKey()).append("=").append(m.getValue()).append("&");
}
sb.delete(sb.length() - 1, sb.length());
return sb.toString();
}
public static void main(String[] args) {
SortedMap<String, Object> paramMap = new TreeMap<String, Object>();
paramMap.put("appid", "wx86f9777acf2cb585");
paramMap.put("partnerid", "1551961491");
paramMap.put("prepayid", "wx26131443671359787bb3996a1fa0fc0000");
paramMap.put("package", "Sign=WXPay");
paramMap.put("noncestr", "rGcsOnNdZ4d9zu6k3yCbVJRG8Ombp8VW");
paramMap.put("timestamp", "1627276483");
String sign = PayDouYinpayUtils.getInstance().createSign(paramMap);
System.out.println("1627274771===="+sign);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment