package com.talentcard.server.business.payment.huifu;
|
|
import com.alibaba.fastjson.JSON;
|
import com.huifu.bspay.sdk.opps.client.BasePayClient;
|
import com.huifu.bspay.sdk.opps.core.BasePay;
|
import com.huifu.bspay.sdk.opps.core.config.MerConfig;
|
import com.huifu.bspay.sdk.opps.core.request.V3TradePaymentScanpayRefundRequest;
|
import com.huifu.bspay.sdk.opps.core.request.V3TradePaymentScanpayRefundqueryRequest;
|
import com.talentcard.server.common.BusinessException;
|
import com.talentcard.server.common.ErrorCode;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.stereotype.Service;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.LinkedHashMap;
|
import java.util.Map;
|
|
@Service
|
public class HuifuRefundGateway {
|
|
private static final Object SDK_INIT_LOCK = new Object();
|
private static final DateTimeFormatter REQUEST_DATE = DateTimeFormatter.ofPattern("yyyyMMdd");
|
private static final Logger log = LoggerFactory.getLogger(HuifuRefundGateway.class);
|
|
private final HuifuPaymentProperties properties;
|
private volatile boolean initialized;
|
|
public HuifuRefundGateway(HuifuPaymentProperties properties) {
|
this.properties = properties;
|
}
|
|
public Map<String, Object> createRefund(HuifuRefundCommand command) {
|
ensureConfigured();
|
initializeSdk();
|
V3TradePaymentScanpayRefundRequest request = new V3TradePaymentScanpayRefundRequest();
|
request.setReqDate(REQUEST_DATE.format(LocalDateTime.now()));
|
request.setReqSeqId(command.refundNo());
|
request.setHuifuId(properties.getMerchantId().trim());
|
request.setOrdAmt(BigDecimal.valueOf(command.amountInCent(), 2).toPlainString());
|
request.setOrgReqDate(command.originalRequestDate());
|
|
Map<String, Object> extendInfo = new LinkedHashMap<>();
|
if (!blank(command.originalProviderNo())) extendInfo.put("org_hf_seq_id", command.originalProviderNo());
|
if (!blank(command.paymentNo())) extendInfo.put("org_req_seq_id", command.paymentNo());
|
if (!blank(properties.getNotifyUrl())) extendInfo.put("notify_url", properties.getNotifyUrl().trim());
|
request.setExtendInfo(extendInfo);
|
return execute(request, "Huifu refund request failed");
|
}
|
|
public Map<String, Object> queryRefund(HuifuRefundCommand command, String providerRefundNo) {
|
ensureConfigured();
|
initializeSdk();
|
V3TradePaymentScanpayRefundqueryRequest request = new V3TradePaymentScanpayRefundqueryRequest();
|
request.setHuifuId(properties.getMerchantId().trim());
|
request.setOrgReqDate(command.originalRequestDate());
|
Map<String, Object> extendInfo = new LinkedHashMap<>();
|
if (!blank(providerRefundNo)) extendInfo.put("org_hf_seq_id", providerRefundNo);
|
if (!blank(command.refundNo())) extendInfo.put("org_req_seq_id", command.refundNo());
|
request.setExtendInfo(extendInfo);
|
return execute(request, "Huifu refund query failed");
|
}
|
|
private Map<String, Object> execute(Object request, String operation) {
|
try {
|
if (request instanceof V3TradePaymentScanpayRefundRequest refundRequest) {
|
return BasePayClient.request(refundRequest, false);
|
}
|
return BasePayClient.request((V3TradePaymentScanpayRefundqueryRequest) request, false);
|
} catch (Exception exception) {
|
log.warn("{}: type={}, message={}", operation, exception.getClass().getSimpleName(), safeMessage(exception.getMessage()));
|
throw new HuifuPaymentGatewayException("Huifu payment operation failed", isOutcomeUnknown(exception), exception);
|
}
|
}
|
|
private void ensureConfigured() {
|
if (!properties.isEnabled()) throw new BusinessException(ErrorCode.CONFLICT, "Huifu payment is disabled");
|
if (blank(properties.getSystemId()) || blank(properties.getProductId()) || blank(properties.getMerchantId())
|
|| blank(properties.getPrivateKey()) || blank(properties.getPlatformPublicKey())) {
|
throw new BusinessException(ErrorCode.CONFLICT, "Huifu payment configuration is incomplete");
|
}
|
}
|
|
private void initializeSdk() {
|
if (initialized) return;
|
synchronized (SDK_INIT_LOCK) {
|
if (initialized) return;
|
BasePay.debug = false;
|
BasePay.prodMode = "prod".equalsIgnoreCase(properties.getEnvironment()) ? BasePay.MODE_PROD : BasePay.MODE_TEST;
|
MerConfig config = new MerConfig();
|
config.setSysId(properties.getSystemId().trim());
|
config.setProductId(properties.getProductId().trim());
|
config.setRsaPrivateKey(properties.getPrivateKey().trim());
|
config.setRsaPublicKey(properties.getPlatformPublicKey().trim());
|
try {
|
BasePay.initWithMerConfig(config);
|
initialized = true;
|
} catch (Exception exception) {
|
throw new BusinessException(ErrorCode.CONFLICT, "Huifu payment SDK initialization failed");
|
}
|
}
|
}
|
|
private boolean blank(String value) { return value == null || value.isBlank(); }
|
|
private String safeMessage(String message) {
|
if (message == null || message.isBlank()) return "";
|
return message.length() > 500 ? message.substring(0, 500) : message;
|
}
|
|
private boolean isOutcomeUnknown(Exception exception) {
|
String message = safeMessage(exception.getMessage()).toLowerCase();
|
return message.contains("no response") || message.contains("timeout") || message.contains("timed out");
|
}
|
}
|