From dbdc1ed6a3ecdcb20981b9e84200c69424444d6d Mon Sep 17 00:00:00 2001
From: KKSU <15274802129@163.com>
Date: Thu, 06 Feb 2025 15:59:20 +0800
Subject: [PATCH] feat(payment): 集成 FIUU 支付方式并优化退款流程

---
 src/main/java/cc/mrbird/febs/pay/util/FiuuUtil.java                              |  144 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java |    9 +-
 src/main/java/cc/mrbird/febs/mall/dto/ApplyRefundOrderDto.java                   |    2 
 src/main/java/cc/mrbird/febs/pay/controller/FIUUController.java                  |    1 
 4 files changed, 151 insertions(+), 5 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/mall/dto/ApplyRefundOrderDto.java b/src/main/java/cc/mrbird/febs/mall/dto/ApplyRefundOrderDto.java
index 1b26ae1..87fce06 100644
--- a/src/main/java/cc/mrbird/febs/mall/dto/ApplyRefundOrderDto.java
+++ b/src/main/java/cc/mrbird/febs/mall/dto/ApplyRefundOrderDto.java
@@ -20,7 +20,7 @@
     private Long itemId;
     //退款方式 1:微信 2:支付宝 3:其他
 
-    @ApiModelProperty(value = "退款方式 1:微信 2:支付宝 3:余额", example = "描述")
+    @ApiModelProperty(value = "退款方式 1:微信 2:支付宝 3:余额 5:FIUU支付", example = "描述")
     private Integer type;
     //退款状态 1:成功 2:失败 3:退款中
 
diff --git a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java
index 00ba3cf..b7b4795 100644
--- a/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/mall/service/impl/ApiMallTeamLeaderServiceImpl.java
@@ -17,6 +17,7 @@
 import cc.mrbird.febs.mall.vo.*;
 import cc.mrbird.febs.pay.model.OrderStateDto;
 import cc.mrbird.febs.pay.service.IXcxPayService;
+import cc.mrbird.febs.pay.util.FiuuUtil;
 import cc.mrbird.febs.pay.util.WeixinServiceUtil;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
@@ -57,6 +58,8 @@
     private final MallRefundMapper mallRefundMapper;
     @Autowired
     private WeixinServiceUtil weixinServiceUtil;
+    @Autowired
+    private FiuuUtil fiuuUtil;
     private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class);
     private final IMallMoneyFlowService mallMoneyFlowService;
     private final IApiMallMemberWalletService memberWalletService;
@@ -421,8 +424,6 @@
             String refundNo = mallRefundEntity.getRefundNo();
             //退款订单金额
             BigDecimal orderAmount = mallOrderInfo.getAmount();
-            BigDecimal aa = new BigDecimal(100);
-            int orderMoney = orderAmount.multiply(aa).intValue();
 
             //退款退款金额
 //            BigDecimal refundAmount = mallRefundEntity.getAmount();
@@ -488,11 +489,11 @@
             Boolean flag = false;
             Boolean debug = xcxProperties.getDebug();
             if (debug) {
-                boolean b = weixinServiceUtil.comRefund(orderNo, refundNo, 1, 1, null);
+                boolean b = fiuuUtil.comRefund(orderNo, refundNo, "1");
                 flag = b;
             } else {
                 log.info("开始调用退款接口。。。退款编号为{}", refundNo);
-                boolean b = weixinServiceUtil.comRefund(orderNo, refundNo, orderMoney, refundMoney, null);
+                boolean b = fiuuUtil.comRefund(orderNo, refundNo, orderAmount.toString());
                 flag = b;
             }
 
diff --git a/src/main/java/cc/mrbird/febs/pay/controller/FIUUController.java b/src/main/java/cc/mrbird/febs/pay/controller/FIUUController.java
index 3686198..e419e3e 100644
--- a/src/main/java/cc/mrbird/febs/pay/controller/FIUUController.java
+++ b/src/main/java/cc/mrbird/febs/pay/controller/FIUUController.java
@@ -146,6 +146,7 @@
         ValidateEntityUtils.ensureEqual(mallOrderInfo.getAmount().toString(), amount, "订单金额异常");
         // 更新订单状态
         if ("00".equals(status)) {
+            mallOrderInfo.setPayMethod("FIUU支付");
             mallOrderInfo.setStatus(OrderStatusEnum.WAIT_SHIPPING.getValue());
             mallOrderInfo.setPayResult("1");
             mallOrderInfo.setPayTime(DateUtil.parseDateTime(paydate));
diff --git a/src/main/java/cc/mrbird/febs/pay/util/FiuuUtil.java b/src/main/java/cc/mrbird/febs/pay/util/FiuuUtil.java
new file mode 100644
index 0000000..4dbfb32
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/pay/util/FiuuUtil.java
@@ -0,0 +1,144 @@
+package cc.mrbird.febs.pay.util;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.util.EntityUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.security.MessageDigest;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+@Slf4j
+@Service(value="FiuuUtil")
+public class FiuuUtil {
+
+	private static final String API_URL = "https://api.fiuu.com/RMS/API/refundAPI/index.php";
+	private static final String MERCHANT_ID = "e2umart01";
+	private static final String SECRET_KEY = "59c709fc18978a6a83b87f05d37cecbf";
+	@Transactional
+	public boolean comRefund(String outTradeNo, String outRefundNo,String amount){
+			// 退款请求参数
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put("RefundType", "P"); // P: Partial Refund, F: Full Refund
+			params.put("MerchantID", MERCHANT_ID);
+			params.put("RefID", outRefundNo); // 商户唯一退款ID
+			params.put("TxnID", outTradeNo); // Fiuu原始交易ID
+			params.put("Amount", amount); // 退款金额
+
+			// 生成签名
+		String signature = null;
+		try {
+			signature = generateSignature(params);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		params.put("Signature", signature);
+
+			// 发送GET请求
+		String response = null;
+		try {
+			response = sendRefundRequest(params);
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		System.out.println("退款响应: " + response);
+
+		JSONObject jsonObject = JSONUtil.parseObj(response);
+
+		String status = jsonObject.getStr("status");
+		if ("00".equals(status)) {
+			return true;
+		}else{
+			return false;
+		}
+
+	}
+	public static void main(String[] args) {
+		try {
+			// 退款请求参数
+			Map<String, String> params = new LinkedHashMap<>();
+			params.put("RefundType", "P"); // P: Partial Refund, F: Full Refund
+			params.put("MerchantID", MERCHANT_ID);
+			params.put("RefID", "REF123456"); // 商户唯一退款ID
+			params.put("TxnID", "123456789"); // Fiuu原始交易ID
+			params.put("Amount", "100.00"); // 退款金额
+			params.put("BankCode", "MBBEMYKL"); // 银行代码(可选)
+			params.put("BankCountry", "MY"); // 国家代码(可选)
+			params.put("BeneficiaryName", "John Doe"); // 收款人姓名(可选)
+			params.put("BeneficiaryAccNo", "1234567890"); // 收款账号(可选)
+
+			// 生成签名
+			String signature = generateSignature(params);
+			params.put("Signature", signature);
+
+			// 发送GET请求
+			String response = sendRefundRequest(params);
+			System.out.println("退款响应: " + response);
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+	/**
+	 * 生成MD5签名
+	 */
+	private static String generateSignature(Map<String, String> params) throws Exception {
+		// 按顺序拼接参数:RefundType + MerchantID + RefID + TxnID + Amount + SecretKey
+		String rawData = params.get("RefundType") +
+				params.get("MerchantID") +
+				params.get("RefID") +
+				params.get("TxnID") +
+				params.get("Amount") +
+				SECRET_KEY;
+
+		MessageDigest md = MessageDigest.getInstance("MD5");
+		byte[] hashBytes = md.digest(rawData.getBytes("UTF-8"));
+
+		// 转换为十六进制字符串
+		StringBuilder hexString = new StringBuilder();
+		for (byte b : hashBytes) {
+			String hex = Integer.toHexString(0xff & b);
+			if (hex.length() == 1) hexString.append('0');
+			hexString.append(hex);
+		}
+
+		return hexString.toString();
+	}
+
+	/**
+	 * 发送退款请求(GET方式)
+	 */
+	private static String sendRefundRequest(Map<String, String> params) throws Exception {
+		StringBuilder urlBuilder = new StringBuilder(API_URL);
+		urlBuilder.append("?");
+
+		// 拼接查询参数
+		for (Map.Entry<String, String> entry : params.entrySet()) {
+			urlBuilder.append(entry.getKey())
+					.append("=")
+					.append(entry.getValue())
+					.append("&");
+		}
+		String url = urlBuilder.toString().replaceAll("&$", ""); // 去除末尾的&
+
+		// 使用HttpClient发送请求
+		try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
+			HttpGet httpGet = new HttpGet(url);
+			try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
+				HttpEntity entity = response.getEntity();
+				return EntityUtils.toString(entity);
+			}
+		}
+	}
+	
+	
+}

--
Gitblit v1.9.1