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.config.WechatPayConfig; 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; @Autowired private WechatPayConfig wechatPayConfig; /** * 发起微信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 requestParams = new HashMap<>(); requestParams.put("bizOrderId", request.getBizOrderId()); requestParams.put("amount", request.getAmount()); requestParams.put("subject", request.getSubject()); requestParams.put("notifyUrl",wechatPayConfig.getNotifyUrl()); 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 requestParams = new HashMap<>(); requestParams.put("bizOrderId", request.getBizOrderId()); requestParams.put("amount", request.getAmount()); requestParams.put("subject", request.getSubject()); requestParams.put("notifyUrl",alipayConfig.getNotifyUrl()); 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 requestParams = new HashMap<>(); requestParams.put("bizOrderId", request.getBizOrderId()); requestParams.put("amount", request.getAmount()); requestParams.put("subject", request.getSubject()); requestParams.put("thirdParty", true); requestParams.put("notifyUrl",alipayConfig.getThirdParty().getDefaultNotifyUrl()); 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.getThirdParty().getDefaultNotifyUrl(); 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); } } /** * 轮询查询支付状态(用于回调失败的补偿机制) * 支持微信和支付宝 * * @param orderId 订单ID * @return 轮询结果(包含订单状态和交易状态) */ @Transactional(rollbackFor = Exception.class) public Map pollPaymentStatus(Long orderId) { log.info("开始轮询查询支付状态,订单ID: {}", orderId); Map result = new HashMap<>(); // 1. 查询订单信息 PaymentOrder order = paymentOrderMapper.selectById(orderId); if (order == null) { log.error("订单不存在,订单ID: {}", orderId); throw new RuntimeException("订单不存在"); } // 如果订单已经是成功状态,直接返回 if (OrderStatus.SUCCEEDED.getCode().equals(order.getStatus())) { log.info("订单已成功,无需轮询,订单ID: {}", orderId); result.put("orderStatus", order.getStatus()); result.put("needPoll", false); result.put("message", "订单已成功"); return result; } // 2. 查询最新交易记录 PaymentTransaction transaction = paymentTransactionMapper.selectLatestByOrderId(orderId); if (transaction == null) { log.error("未找到交易记录,订单ID: {}", orderId); throw new RuntimeException("未找到交易记录"); } // 如果交易已成功,但订单状态未更新,更新订单状态 if (TransactionStatus.SUCCEEDED.getCode().equals(transaction.getStatus())) { log.info("交易已成功,同步订单状态,订单ID: {}", orderId); order.setStatus(OrderStatus.SUCCEEDED.getCode()); order.setUpdatedAt(LocalDateTime.now()); paymentOrderMapper.update(order); result.put("orderStatus", OrderStatus.SUCCEEDED.getCode()); result.put("transactionStatus", transaction.getStatus()); result.put("needPoll", false); result.put("message", "支付成功"); return result; } // 3. 根据支付渠道调用相应的查询接口 String channel = order.getChannel(); boolean paymentSuccess = false; String tradeStatus = null; try { if (PayChannel.WECHAT.getCode().equals(channel)) { // 查询微信支付状态 paymentSuccess = queryWechatPaymentStatus(order, transaction); tradeStatus = paymentSuccess ? "SUCCESS" : "NOTPAY"; result.put("paymethod","WECHAT"); } else if (PayChannel.ALIPAY.getCode().equals(channel)) { // 判断是否为第三方支付宝 boolean isThirdParty = isThirdPartyAlipay(transaction); result.put("paymethod","ALIPAY"); if (isThirdParty) { // 查询第三方支付宝状态 tradeStatus = queryAlipayThirdPartyTradeStatus(orderId); paymentSuccess = "SUCCESS".equals(tradeStatus); } else { // 查询官方支付宝状态 paymentSuccess = queryAlipayPaymentStatus(order, transaction); tradeStatus = paymentSuccess ? "TRADE_SUCCESS" : "WAIT_BUYER_PAY"; } } else { log.error("不支持的支付渠道: {}", channel); throw new RuntimeException("不支持的支付渠道"); } } catch (Exception e) { log.error("查询支付状态异常,订单ID: {}", orderId, e); result.put("orderStatus", order.getStatus()); result.put("transactionStatus", transaction.getStatus()); result.put("needPoll", true); result.put("error", e.getMessage()); result.put("message", "查询异常,请稍后重试"); return result; } // 4. 如果支付成功,更新订单和交易状态 if (paymentSuccess) { log.info("轮询查询发现支付成功,订单ID: {}, 交易状态: {}", orderId, tradeStatus); // 更新交易状态 transaction.setStatus(TransactionStatus.SUCCEEDED.getCode()); transaction.setPaidAt(LocalDateTime.now()); paymentTransactionMapper.update(transaction); // 更新订单状态 order.setStatus(OrderStatus.SUCCEEDED.getCode()); order.setUpdatedAt(LocalDateTime.now()); paymentOrderMapper.update(order); result.put("orderStatus", OrderStatus.SUCCEEDED.getCode()); result.put("transactionStatus", TransactionStatus.SUCCEEDED.getCode()); result.put("tradeStatus", tradeStatus); result.put("needPoll", false); result.put("message", "支付成功"); log.info("轮询查询处理完成,订单和交易状态已更新,订单ID: {}", orderId); } else { log.info("轮询查询,支付尚未完成,订单ID: {}, 交易状态: {}", orderId, tradeStatus); result.put("orderStatus", order.getStatus()); result.put("transactionStatus", transaction.getStatus()); result.put("tradeStatus", tradeStatus); result.put("needPoll", true); result.put("message", "支付尚未完成,请继续轮询"); } return result; } /** * 查询微信支付状态 */ private boolean queryWechatPaymentStatus(PaymentOrder order, PaymentTransaction transaction) throws Exception { log.info("查询微信支付状态,订单ID: {}", order.getId()); String outTradeNo = String.valueOf(order.getId()); Map queryResult = wxPayV2Client.queryOrder(outTradeNo); // 检查业务结果 if (!"SUCCESS".equals(queryResult.get("result_code"))) { log.warn("微信订单查询业务失败: {}", queryResult.get("err_code_des")); return false; } // 检查交易状态 String tradeState = queryResult.get("trade_state"); log.info("微信订单状态: {}", tradeState); return "SUCCESS".equals(tradeState); } /** * 查询支付宝支付状态(官方接口) */ private boolean queryAlipayPaymentStatus(PaymentOrder order, PaymentTransaction transaction) throws Exception { log.info("查询支付宝支付状态,订单ID: {}", order.getId()); String outTradeNo = String.valueOf(order.getId()); com.alipay.api.response.AlipayTradeQueryResponse queryResult = alipayF2FClient.queryOrder(outTradeNo); // 检查交易状态 String tradeStatus = queryResult.getTradeStatus(); log.info("支付宝订单状态: {}", tradeStatus); log.info("支付宝订单查询结果: {}", queryResult.getBody()); // TRADE_SUCCESS 或 TRADE_FINISHED 表示支付成功 return "TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus); } /** * 判断是否为第三方支付宝 */ private boolean isThirdPartyAlipay(PaymentTransaction transaction) { if (transaction.getRequestParams() == null) { return false; } try { Map params = JSON.parseObject(transaction.getRequestParams(), Map.class); return params.containsKey("thirdParty") && Boolean.TRUE.equals(params.get("thirdParty")); } catch (Exception e) { log.warn("解析交易请求参数失败", e); return false; } } /** * 根据交易单号查询微信支付状态 * * @param outTradeNo 商户订单号(交易单号) * @return 交易状态信息 */ public Map queryWechatTradeByOutTradeNo(String outTradeNo) { log.info("根据交易单号查询微信支付状态,商户订单号: {}", outTradeNo); Map result = new HashMap<>(); try { Map queryResult = wxPayV2Client.queryOrder(outTradeNo); // 检查调用是否成功 if (!"SUCCESS".equals(queryResult.get("return_code"))) { result.put("success", false); result.put("message", "微信查询接口调用失败: " + queryResult.get("return_msg")); return result; } // 检查业务结果 if (!"SUCCESS".equals(queryResult.get("result_code"))) { result.put("success", false); result.put("message", "微信订单查询业务失败: " + queryResult.get("err_code_des")); result.put("errorCode", queryResult.get("err_code")); return result; } // 返回交易信息 result.put("success", true); result.put("tradeState", queryResult.get("trade_state")); // 交易状态 result.put("tradeStateDesc", queryResult.get("trade_state_desc")); // 交易状态描述 result.put("outTradeNo", queryResult.get("out_trade_no")); // 商户订单号 result.put("transactionId", queryResult.get("transaction_id")); // 微信支付订单号 result.put("totalFee", queryResult.get("total_fee")); // 订单金额(分) result.put("timeEnd", queryResult.get("time_end")); // 支付完成时间 result.put("openid", queryResult.get("openid")); // 用户标识 // 判断是否支付成功 boolean isPaid = "SUCCESS".equals(queryResult.get("trade_state")); result.put("isPaid", isPaid); result.put("message", isPaid ? "支付成功" : "支付未完成"); log.info("微信交易查询成功,交易状态: {}", queryResult.get("trade_state")); } catch (Exception e) { log.error("查询微信交易状态异常,商户订单号: {}", outTradeNo, e); result.put("success", false); result.put("message", "查询异常: " + e.getMessage()); } return result; } /** * 根据交易单号查询支付宝支付状态 * * @param outTradeNo 商户订单号(交易单号) * @return 交易状态信息 */ public Map queryAlipayTradeByOutTradeNo(String outTradeNo) { log.info("根据交易单号查询支付宝支付状态,商户订单号: {}", outTradeNo); Map result = new HashMap<>(); try { com.alipay.api.response.AlipayTradeQueryResponse queryResult = alipayF2FClient.queryOrder(outTradeNo); // 检查调用是否成功 if (!queryResult.isSuccess()) { result.put("success", false); result.put("message", "支付宝查询失败: " + queryResult.getSubMsg()); result.put("errorCode", queryResult.getSubCode()); return result; } // 返回交易信息 result.put("success", true); result.put("tradeStatus", queryResult.getTradeStatus()); // 交易状态 result.put("outTradeNo", queryResult.getOutTradeNo()); // 商户订单号 result.put("tradeNo", queryResult.getTradeNo()); // 支付宝交易号 result.put("totalAmount", queryResult.getTotalAmount()); // 订单金额(元) result.put("buyerPayAmount", queryResult.getBuyerPayAmount()); // 买家实际支付金额 result.put("sendPayDate", queryResult.getSendPayDate()); // 交易支付时间 result.put("buyerLogonId", queryResult.getBuyerLogonId()); // 买家支付宝账号 // 判断是否支付成功 String tradeStatus = queryResult.getTradeStatus(); boolean isPaid = "TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus); result.put("isPaid", isPaid); // 状态说明 String message; if ("TRADE_SUCCESS".equals(tradeStatus)) { message = "交易支付成功"; } else if ("TRADE_FINISHED".equals(tradeStatus)) { message = "交易结束,不可退款"; } else if ("WAIT_BUYER_PAY".equals(tradeStatus)) { message = "交易创建,等待买家付款"; } else if ("TRADE_CLOSED".equals(tradeStatus)) { message = "未付款交易超时关闭,或支付完成后全额退款"; } else { message = "未知状态: " + tradeStatus; } result.put("message", message); log.info("支付宝交易查询成功,交易状态: {}", tradeStatus); } catch (Exception e) { log.error("查询支付宝交易状态异常,商户订单号: {}", outTradeNo, e); result.put("success", false); result.put("message", "查询异常: " + e.getMessage()); } return result; } }