package com.ruoyi.payment.application.service;
|
|
import com.alibaba.fastjson.JSON;
|
import com.ruoyi.payment.domain.enums.ClientType;
|
import com.ruoyi.payment.domain.enums.OrderStatus;
|
import com.ruoyi.payment.domain.enums.PayChannel;
|
import com.ruoyi.payment.domain.enums.TransactionStatus;
|
import com.ruoyi.payment.domain.model.PaymentOrder;
|
import com.ruoyi.payment.domain.model.PaymentTransaction;
|
import com.ruoyi.payment.infrastructure.channel.alipay.AlipayF2FClient;
|
import com.ruoyi.payment.infrastructure.channel.alipay.AlipayThirdPartyClient;
|
import com.ruoyi.payment.infrastructure.channel.wechat.WxPayV2Client;
|
import com.ruoyi.payment.infrastructure.config.AlipayConfig;
|
import com.ruoyi.payment.infrastructure.config.QrCodeConfig;
|
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentOrderMapper;
|
import com.ruoyi.payment.infrastructure.persistence.mapper.PaymentTransactionMapper;
|
import com.ruoyi.payment.infrastructure.util.QrCodeUtil;
|
import com.ruoyi.payment.infrastructure.util.SnowflakeIdGenerator;
|
import com.ruoyi.payment.interfaces.dto.PaymentRequest;
|
import com.ruoyi.payment.interfaces.dto.PaymentResponse;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.time.LocalDateTime;
|
import java.util.HashMap;
|
import java.util.Map;
|
|
/**
|
* 支付应用服务
|
*
|
* @author ruoyi
|
*/
|
@Slf4j
|
@Service
|
public class PaymentService {
|
|
@Autowired
|
private PaymentOrderMapper paymentOrderMapper;
|
|
@Autowired
|
private PaymentTransactionMapper paymentTransactionMapper;
|
|
@Autowired
|
private QrCodeUtil qrCodeUtil;
|
|
@Autowired
|
private QrCodeConfig qrCodeConfig;
|
|
@Autowired
|
private WxPayV2Client wxPayV2Client;
|
|
@Autowired
|
private AlipayF2FClient alipayF2FClient;
|
|
@Autowired
|
private AlipayThirdPartyClient alipayThirdPartyClient;
|
|
@Autowired
|
private AlipayConfig alipayConfig;
|
|
/**
|
* 发起微信Native支付
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public PaymentResponse createWechatNativePayment(PaymentRequest request) {
|
log.info("发起微信Native支付,请求参数: {}", JSON.toJSONString(request));
|
|
// 1. 查询或创建订单
|
PaymentOrder order = getOrCreateOrder(request, PayChannel.WECHAT.getCode());
|
|
// 2. 检查是否存在待支付交易(同一订单只允许一笔进行中)
|
PaymentTransaction existingTransaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
|
if (existingTransaction != null) {
|
log.info("订单{}已存在待支付交易{},直接返回", order.getId(), existingTransaction.getId());
|
return buildPaymentResponse(order, existingTransaction);
|
}
|
|
// 3. 调用微信下单接口(这里先模拟)
|
String codeUrl = callWechatUnifiedOrder(order);
|
|
// 4. 生成二维码Base64
|
String qrBase64 = qrCodeUtil.generateQrCodeBase64(codeUrl, qrCodeConfig.getSize());
|
|
// 5. 创建交易记录
|
PaymentTransaction transaction = new PaymentTransaction();
|
transaction.setId(SnowflakeIdGenerator.generateId());
|
transaction.setOrderId(order.getId());
|
transaction.setChannel(PayChannel.WECHAT.getCode());
|
transaction.setClientType(ClientType.NATIVE.getCode());
|
transaction.setStatus(TransactionStatus.PENDING.getCode());
|
transaction.setCodeOrQr(codeUrl);
|
transaction.setQrBase64(qrBase64);
|
transaction.setCreatedAt(LocalDateTime.now());
|
|
// 构造请求参数快照
|
Map<String, Object> requestParams = new HashMap<>();
|
requestParams.put("bizOrderId", request.getBizOrderId());
|
requestParams.put("amount", request.getAmount());
|
requestParams.put("subject", request.getSubject());
|
transaction.setRequestParams(JSON.toJSONString(requestParams));
|
|
paymentTransactionMapper.insert(transaction);
|
|
// 6. 更新订单最新交易ID
|
order.setLatestTransactionId(transaction.getId());
|
paymentOrderMapper.update(order);
|
|
log.info("微信Native支付创建成功,订单ID: {}, 交易ID: {}", order.getId(), transaction.getId());
|
|
return buildPaymentResponse(order, transaction);
|
}
|
|
/**
|
* 发起支付宝当面付
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public PaymentResponse createAlipayPrecreate(PaymentRequest request) {
|
log.info("发起支付宝当面付,请求参数: {}", JSON.toJSONString(request));
|
|
// 1. 查询或创建订单
|
PaymentOrder order = getOrCreateOrder(request, PayChannel.ALIPAY.getCode());
|
|
// 2. 检查是否存在待支付交易
|
PaymentTransaction existingTransaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
|
if (existingTransaction != null) {
|
log.info("订单{}已存在待支付交易{},直接返回", order.getId(), existingTransaction.getId());
|
return buildPaymentResponse(order, existingTransaction);
|
}
|
|
// 3. 调用支付宝下单接口(这里先模拟)
|
String qrCode = callAlipayPrecreate(order);
|
|
// 4. 生成二维码Base64
|
String qrBase64 = qrCodeUtil.generateQrCodeBase64(qrCode, qrCodeConfig.getSize());
|
|
// 5. 创建交易记录
|
PaymentTransaction transaction = new PaymentTransaction();
|
transaction.setId(SnowflakeIdGenerator.generateId());
|
transaction.setOrderId(order.getId());
|
transaction.setChannel(PayChannel.ALIPAY.getCode());
|
transaction.setClientType(ClientType.ALIPAY_PRECREATE.getCode());
|
transaction.setStatus(TransactionStatus.PENDING.getCode());
|
transaction.setCodeOrQr(qrCode);
|
transaction.setQrBase64(qrBase64);
|
transaction.setCreatedAt(LocalDateTime.now());
|
|
Map<String, Object> requestParams = new HashMap<>();
|
requestParams.put("bizOrderId", request.getBizOrderId());
|
requestParams.put("amount", request.getAmount());
|
requestParams.put("subject", request.getSubject());
|
transaction.setRequestParams(JSON.toJSONString(requestParams));
|
|
paymentTransactionMapper.insert(transaction);
|
|
// 6. 更新订单
|
order.setLatestTransactionId(transaction.getId());
|
paymentOrderMapper.update(order);
|
|
log.info("支付宝当面付创建成功,订单ID: {}, 交易ID: {}", order.getId(), transaction.getId());
|
|
return buildPaymentResponse(order, transaction);
|
}
|
|
/**
|
* 发起支付宝当面付(第三方接口)
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public PaymentResponse createAlipayThirdPartyPrecreate(PaymentRequest request) {
|
log.info("发起支付宝当面付(第三方接口),请求参数: {}", JSON.toJSONString(request));
|
|
// 1. 查询或创建订单
|
PaymentOrder order = getOrCreateOrder(request, PayChannel.ALIPAY.getCode());
|
|
// 2. 检查是否存在待支付交易
|
PaymentTransaction existingTransaction = paymentTransactionMapper.selectPendingByOrderId(order.getId());
|
if (existingTransaction != null) {
|
log.info("订单{}已存在待支付交易{},直接返回", order.getId(), existingTransaction.getId());
|
return buildPaymentResponse(order, existingTransaction);
|
}
|
|
// 3. 调用第三方支付宝接口生成支付URL
|
String payUrl = callAlipayThirdPartyPrecreate(order, request);
|
|
// 4. 生成二维码Base64
|
String qrBase64 = qrCodeUtil.generateQrCodeBase64(payUrl, qrCodeConfig.getSize());
|
|
// 5. 创建交易记录
|
PaymentTransaction transaction = new PaymentTransaction();
|
transaction.setId(SnowflakeIdGenerator.generateId());
|
transaction.setOrderId(order.getId());
|
transaction.setChannel(PayChannel.ALIPAY.getCode());
|
transaction.setClientType(ClientType.ALIPAY_PRECREATE.getCode());
|
transaction.setStatus(TransactionStatus.PENDING.getCode());
|
transaction.setCodeOrQr(payUrl);
|
transaction.setQrBase64(qrBase64);
|
transaction.setCreatedAt(LocalDateTime.now());
|
|
Map<String, Object> requestParams = new HashMap<>();
|
requestParams.put("bizOrderId", request.getBizOrderId());
|
requestParams.put("amount", request.getAmount());
|
requestParams.put("subject", request.getSubject());
|
requestParams.put("thirdParty", true);
|
transaction.setRequestParams(JSON.toJSONString(requestParams));
|
|
paymentTransactionMapper.insert(transaction);
|
|
// 6. 更新订单
|
order.setLatestTransactionId(transaction.getId());
|
paymentOrderMapper.update(order);
|
|
log.info("支付宝当面付(第三方接口)创建成功,订单ID: {}, 交易ID: {}", order.getId(), transaction.getId());
|
|
return buildPaymentResponse(order, transaction);
|
}
|
|
/**
|
* 查询或创建订单
|
*/
|
private PaymentOrder getOrCreateOrder(PaymentRequest request, String channel) {
|
// 先查询是否存在
|
PaymentOrder existingOrder = paymentOrderMapper.selectByBizOrderIdAndChannel(
|
request.getBizOrderId(), channel);
|
|
if (existingOrder != null) {
|
// 如果订单已过期,更新状态
|
if (existingOrder.isExpired() && OrderStatus.PENDING.getCode().equals(existingOrder.getStatus())) {
|
existingOrder.setStatus(OrderStatus.EXPIRED.getCode());
|
paymentOrderMapper.update(existingOrder);
|
}
|
return existingOrder;
|
}
|
|
// 创建新订单
|
PaymentOrder order = new PaymentOrder();
|
order.setId(SnowflakeIdGenerator.generateId());
|
order.setBizOrderId(request.getBizOrderId());
|
order.setAmount(request.getAmount());
|
order.setCurrency("CNY");
|
order.setChannel(channel);
|
order.setStatus(OrderStatus.PENDING.getCode());
|
order.setSubject(request.getSubject());
|
order.setDescription(request.getDescription());
|
order.setCallbackUrl(request.getCallbackUrl());
|
order.setExpireAt(LocalDateTime.now().plusHours(2)); // 2小时过期
|
order.setVersion(0);
|
order.setCreatedAt(LocalDateTime.now());
|
order.setUpdatedAt(LocalDateTime.now());
|
|
paymentOrderMapper.insert(order);
|
|
return order;
|
}
|
|
/**
|
* 调用微信统一下单接口
|
*/
|
private String callWechatUnifiedOrder(PaymentOrder order) {
|
try {
|
return wxPayV2Client.unifiedOrder(order);
|
} catch (Exception e) {
|
log.error("调用微信统一下单接口失败", e);
|
throw new RuntimeException("微信下单失败: " + e.getMessage(), e);
|
}
|
}
|
|
/**
|
* 调用支付宝当面付接口
|
*/
|
private String callAlipayPrecreate(PaymentOrder order) {
|
try {
|
return alipayF2FClient.precreate(order);
|
} catch (Exception e) {
|
log.error("调用支付宝当面付接口失败", e);
|
throw new RuntimeException("支付宝下单失败: " + e.getMessage(), e);
|
}
|
}
|
|
/**
|
* 调用第三方支付宝接口生成支付URL
|
*/
|
private String callAlipayThirdPartyPrecreate(PaymentOrder order, PaymentRequest request) {
|
try {
|
// 使用AlipayConfig中配置的回调地址
|
String notifyUrl = alipayConfig.getNotifyUrl();
|
String outTradeNo = String.valueOf(order.getId());
|
Integer totalFee = order.getAmount(); // 单位:分
|
String serviceOrdId = request.getBizOrderId(); // 业务订单ID
|
|
return alipayThirdPartyClient.createQrCodeUrl(notifyUrl, outTradeNo, totalFee, serviceOrdId);
|
} catch (Exception e) {
|
log.error("调用第三方支付宝接口失败", e);
|
throw new RuntimeException("第三方支付宝下单失败: " + e.getMessage(), e);
|
}
|
}
|
|
/**
|
* 构造支付响应
|
*/
|
private PaymentResponse buildPaymentResponse(PaymentOrder order, PaymentTransaction transaction) {
|
PaymentResponse response = new PaymentResponse();
|
response.setOrderId(order.getId());
|
response.setTransactionId(transaction.getId());
|
response.setStatus(order.getStatus());
|
response.setQrBase64(transaction.getQrBase64());
|
response.setExpireAt(order.getExpireAt());
|
return response;
|
}
|
|
/**
|
* 查询订单
|
*/
|
public PaymentOrder getOrder(Long orderId) {
|
return paymentOrderMapper.selectById(orderId);
|
}
|
|
/**
|
* 查询最新交易
|
*/
|
public PaymentTransaction getLatestTransaction(Long orderId) {
|
return paymentTransactionMapper.selectLatestByOrderId(orderId);
|
}
|
|
/**
|
* 查询支付宝第三方交易状态
|
*/
|
public String queryAlipayThirdPartyTradeStatus(Long orderId) {
|
try {
|
// 使用订单ID作为商户订单号
|
String outTradeNo = String.valueOf(orderId);
|
return alipayThirdPartyClient.queryTradeStatus(outTradeNo);
|
} catch (Exception e) {
|
log.error("查询支付宝第三方交易状态失败,订单ID: {}", orderId, e);
|
throw new RuntimeException("查询交易状态失败: " + e.getMessage(), e);
|
}
|
}
|
}
|