package cc.mrbird.febs.pay.util;
|
|
import cc.mrbird.febs.pay.model.RefundStatus;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
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 java.util.List;
|
import java.util.concurrent.*;
|
|
@Service(value="FiuuRefundUtil")
|
public class FiuuRefundUtil {
|
|
private static final String API_BASE_URL = "https://api.fiuu.com/RMS/API/refundAPI/";
|
private static final String MERCHANT_ID = "e2umart01";
|
private static final String VERIFY_KEY = "4e3a4ed58e62ddbfacf41f6d5ec56bf2";
|
private static final int MAX_RETRIES = 3;
|
private static final int POLL_INTERVAL = 1000; // 5秒
|
private static final int TIMEOUT = 60000; // 60秒超时
|
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
|
// 退款状态查询(根据TxnID)
|
public RefundStatus queryByTxnId(String txnId) throws Exception {
|
String signature = HashUtils.md5(txnId + MERCHANT_ID + VERIFY_KEY);
|
String url = API_BASE_URL + "q_by_txn.php?TxnID=" + txnId
|
+ "&MerchantID=" + MERCHANT_ID
|
+ "&Signature=" + signature;
|
|
return executeQuery(url);
|
}
|
|
// 退款状态查询(根据RefID)
|
public RefundStatus queryByRefId(String refId) throws Exception {
|
String signature = HashUtils.md5(refId + MERCHANT_ID + VERIFY_KEY);
|
String url = API_BASE_URL + "q_by_refID.php?RefID=" + refId
|
+ "&MerchantID=" + MERCHANT_ID
|
+ "&Signature=" + signature;
|
|
return executeQuery(url);
|
}
|
|
private RefundStatus executeQuery(String url) throws Exception {
|
HttpGet request = new HttpGet(url);
|
try (CloseableHttpClient client = HttpClients.createDefault()) {
|
String response = EntityUtils.toString(client.execute(request).getEntity());
|
List<RefundStatus> refundStatusList = objectMapper.readValue(
|
response,
|
objectMapper.getTypeFactory().constructCollectionType(List.class, RefundStatus.class));
|
return refundStatusList.get(0);
|
}
|
}
|
|
// 异步轮询退款状态
|
public RefundStatus pollRefundStatus(String txnId) throws Exception {
|
ExecutorService executor = Executors.newSingleThreadExecutor();
|
Future<RefundStatus> future = executor.submit(() -> {
|
int retryCount = 0;
|
while (retryCount < MAX_RETRIES) {
|
try {
|
RefundStatus status = queryByTxnId(txnId);
|
if (!"pending".equals(status.getStatus())) {
|
return status;
|
}
|
Thread.sleep(POLL_INTERVAL);
|
retryCount++;
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
throw new RuntimeException("Polling interrupted", e);
|
}
|
}
|
throw new TimeoutException("Max retries reached");
|
});
|
|
try {
|
return future.get(TIMEOUT, TimeUnit.MILLISECONDS);
|
} catch (TimeoutException e) {
|
future.cancel(true);
|
throw new RuntimeException("Refund status check timeout");
|
} finally {
|
executor.shutdown();
|
}
|
}
|
}
|