package com.tourguide.modules.order.service;
|
|
import com.alibaba.fastjson.JSONObject;
|
import com.tourguide.common.exception.BusinessException;
|
import com.tourguide.common.huifu.properties.HuiFuProperties;
|
import com.tourguide.modules.order.payment.HuifuPaymentNotice;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeParseException;
|
|
@Service
|
public class HuifuPaymentCallbackService {
|
private static final Logger log = LoggerFactory.getLogger(HuifuPaymentCallbackService.class);
|
private static final DateTimeFormatter PAYMENT_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
|
private final HuiFuProperties properties;
|
private final TourOrderPaymentService orderPaymentService;
|
|
public HuifuPaymentCallbackService(HuiFuProperties properties,
|
TourOrderPaymentService orderPaymentService) {
|
this.properties = properties;
|
this.orderPaymentService = orderPaymentService;
|
}
|
|
public void handle(JSONObject body) {
|
String reqSeqId = first(body, "req_seq_id", "org_req_seq_id");
|
if (!StringUtils.hasText(reqSeqId)) throw new BusinessException(400, "汇付回调缺少请求流水号");
|
String callbackHuifuId = first(body, "huifu_id", "out_huifu_id");
|
validateMerchant(callbackHuifuId);
|
String transactionStatus = body.getString("trans_stat");
|
if (!"S".equals(transactionStatus)) {
|
log.info("汇付支付回调非成功状态,reqSeqId={},transStat={}", reqSeqId, transactionStatus);
|
return;
|
}
|
BigDecimal amount = amount(body);
|
HuifuPaymentNotice notice = new HuifuPaymentNotice(reqSeqId, callbackHuifuId,
|
transactionStatus, amount,
|
first(body, "hf_seq_id", "out_trans_id", "transaction_id"),
|
paymentTime(body));
|
boolean confirmed = orderPaymentService.confirm(notice);
|
log.info("汇付支付回调处理完成,reqSeqId={},首次确认={},providerTransactionId={}",
|
reqSeqId, confirmed, notice.getProviderTransactionId());
|
}
|
|
private void validateMerchant(String callbackHuifuId) {
|
if (!StringUtils.hasText(callbackHuifuId)) {
|
throw new BusinessException(400, "汇付回调缺少商户号");
|
}
|
if (!StringUtils.hasText(properties.getHuifuId())
|
|| !properties.getHuifuId().equals(callbackHuifuId)) {
|
throw new BusinessException(400, "汇付回调商户号不匹配");
|
}
|
}
|
|
private BigDecimal amount(JSONObject body) {
|
String value = first(body, "trans_amt", "ord_amt", "pay_amt");
|
if (!StringUtils.hasText(value)) throw new BusinessException(400, "汇付回调缺少支付金额");
|
try {
|
return new BigDecimal(value);
|
} catch (NumberFormatException exception) {
|
throw new BusinessException(400, "汇付回调支付金额格式错误");
|
}
|
}
|
|
private LocalDateTime paymentTime(JSONObject body) {
|
String value = first(body, "end_time", "trans_time", "pay_time");
|
if (!StringUtils.hasText(value)) return LocalDateTime.now();
|
String normalized = value.replace("-", "").replace(":", "").replace(" ", "");
|
try {
|
return LocalDateTime.parse(normalized, PAYMENT_TIME_FORMAT);
|
} catch (DateTimeParseException exception) {
|
return LocalDateTime.now();
|
}
|
}
|
|
private String first(JSONObject body, String... keys) {
|
for (String key : keys) {
|
String value = body.getString(key);
|
if (StringUtils.hasText(value)) return value;
|
}
|
return null;
|
}
|
}
|