package com.gxwebsoft.payment.service.impl; import cn.hutool.core.util.IdUtil; import com.gxwebsoft.common.core.utils.CommonUtil; import com.gxwebsoft.common.system.entity.User; import com.gxwebsoft.payment.constants.PaymentConstants; import com.gxwebsoft.payment.dto.PaymentRequest; import com.gxwebsoft.payment.dto.PaymentResponse; import com.gxwebsoft.payment.dto.PaymentWithOrderRequest; import com.gxwebsoft.payment.enums.PaymentType; import com.gxwebsoft.payment.exception.PaymentException; import com.gxwebsoft.payment.service.PaymentService; import com.gxwebsoft.payment.service.WxPayConfigService; import com.gxwebsoft.payment.strategy.PaymentStrategy; import com.gxwebsoft.shop.dto.OrderCreateRequest; import com.gxwebsoft.shop.service.OrderBusinessService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; /** * 统一支付服务实现 * 基于策略模式实现多种支付方式的统一管理 * * @author 科技小王子 * @since 2025-01-26 */ @Slf4j @Service("unifiedPaymentServiceImpl") public class PaymentServiceImpl implements PaymentService { /** * 支付策略映射表 */ private final Map strategyMap = new ConcurrentHashMap<>(); /** * 注入所有支付策略实现 */ @Resource private List paymentStrategies; /** * 订单业务服务 */ @Resource private OrderBusinessService orderBusinessService; /** * 微信支付配置服务 */ @Resource private WxPayConfigService wxPayConfigService; /** * 初始化策略映射 */ @PostConstruct public void initStrategies() { if (paymentStrategies != null && !paymentStrategies.isEmpty()) { for (PaymentStrategy strategy : paymentStrategies) { try { PaymentType paymentType = strategy.getSupportedPaymentType(); strategyMap.put(paymentType, strategy); log.info("注册支付策略: {} -> {}", paymentType.getName(), strategy.getClass().getSimpleName()); } catch (Exception e) { log.warn("注册支付策略失败: {}, 错误: {}", strategy.getClass().getSimpleName(), e.getMessage()); } } } log.info("支付策略初始化完成,共注册 {} 种支付方式", strategyMap.size()); if (strategyMap.isEmpty()) { log.warn("⚠️ 没有可用的支付策略,支付功能将不可用"); } } @Override public PaymentResponse createPayment(PaymentRequest request) throws PaymentException { log.info("{}, 支付类型: {}, 租户ID: {}, 用户ID: {}, 金额: {}", PaymentConstants.LogMessage.PAYMENT_START, request.getPaymentType(), request.getTenantId(), request.getUserId(), request.getFormattedAmount()); try { // 基础参数验证 validatePaymentRequest(request); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(request.getPaymentType()); // 执行支付 PaymentResponse response = strategy.createPayment(request); log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}", PaymentConstants.LogMessage.PAYMENT_SUCCESS, request.getPaymentType(), request.getTenantId(), response.getOrderNo(), request.getFormattedAmount()); return response; } catch (PaymentException e) { log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", PaymentConstants.LogMessage.PAYMENT_FAILED, request.getPaymentType(), request.getTenantId(), e.getMessage()); throw e; } catch (Exception e) { log.error("{}, 支付类型: {}, 租户ID: {}, 系统错误: {}", PaymentConstants.LogMessage.PAYMENT_FAILED, request.getPaymentType(), request.getTenantId(), e.getMessage(), e); throw PaymentException.systemError("支付创建失败: " + e.getMessage(), e); } } @Override public PaymentResponse createPaymentWithOrder(PaymentWithOrderRequest request, User loginUser) throws PaymentException { log.info("开始创建支付订单(包含订单信息), 支付类型: {}, 租户ID: {}, 用户ID: {}, 金额: {}", request.getPaymentType(), request.getTenantId(), loginUser.getUserId(), request.getFormattedAmount()); try { // 1. 参数验证 validatePaymentWithOrderRequest(request, loginUser); // 2. 转换为订单创建请求 OrderCreateRequest orderRequest = convertToOrderCreateRequest(request, loginUser); // 3. 创建订单(包含商品验证、库存扣减等完整业务逻辑) Map wxOrderInfo = orderBusinessService.createOrder(orderRequest, loginUser); // 4. 构建支付响应(复用现有的微信支付返回格式) PaymentResponse response = buildPaymentResponseFromWxOrder(wxOrderInfo, request, orderRequest.getOrderNo()); log.info("支付订单创建成功(包含订单信息), 支付类型: {}, 租户ID: {}, 订单号: {}, 金额: {}", request.getPaymentType(), request.getTenantId(), response.getOrderNo(), request.getFormattedAmount()); return response; } catch (PaymentException e) { log.error("创建支付订单失败(包含订单信息), 支付类型: {}, 租户ID: {}, 错误: {}", request.getPaymentType(), request.getTenantId(), e.getMessage()); throw e; } catch (Exception e) { log.error("创建支付订单系统错误(包含订单信息), 支付类型: {}, 租户ID: {}, 系统错误: {}", request.getPaymentType(), request.getTenantId(), e.getMessage(), e); throw PaymentException.systemError("支付订单创建失败: " + e.getMessage(), e); } } @Override public PaymentResponse queryPayment(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { log.info("开始查询支付状态, 支付类型: {}, 租户ID: {}, 订单号: {}", paymentType, tenantId, orderNo); try { // 参数验证 validateQueryParams(orderNo, paymentType, tenantId); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(paymentType); // 检查是否支持查询 if (!strategy.supportQuery()) { throw PaymentException.unsupportedPayment("该支付方式不支持查询", paymentType); } // 执行查询 PaymentResponse response = strategy.queryPayment(orderNo, tenantId); log.info("支付状态查询成功, 支付类型: {}, 租户ID: {}, 订单号: {}, 状态: {}", paymentType, tenantId, orderNo, response.getPaymentStatus()); return response; } catch (PaymentException e) { log.error("支付状态查询失败, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", paymentType, tenantId, orderNo, e.getMessage()); throw e; } catch (Exception e) { log.error("支付状态查询系统错误, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", paymentType, tenantId, orderNo, e.getMessage(), e); throw PaymentException.systemError("支付查询失败: " + e.getMessage(), e); } } @Override public String handlePaymentNotify(PaymentType paymentType, Map headers, String body, Integer tenantId) throws PaymentException { log.info("{}, 支付类型: {}, 租户ID: {}", PaymentConstants.LogMessage.NOTIFY_START, paymentType, tenantId); try { // 参数验证 validateNotifyParams(paymentType, headers, body, tenantId); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(paymentType); // 检查是否需要异步通知 if (!strategy.needNotify()) { log.warn("该支付方式不需要异步通知, 支付类型: {}", paymentType); return PaymentConstants.Wechat.NOTIFY_SUCCESS; } // 处理回调 String result = strategy.handleNotify(headers, body, tenantId); log.info("{}, 支付类型: {}, 租户ID: {}", PaymentConstants.LogMessage.NOTIFY_SUCCESS, paymentType, tenantId); return result; } catch (PaymentException e) { log.error("{}, 支付类型: {}, 租户ID: {}, 错误: {}", PaymentConstants.LogMessage.NOTIFY_FAILED, paymentType, tenantId, e.getMessage()); throw e; } catch (Exception e) { log.error("{}, 支付类型: {}, 租户ID: {}, 系统错误: {}", PaymentConstants.LogMessage.NOTIFY_FAILED, paymentType, tenantId, e.getMessage(), e); throw PaymentException.systemError("支付回调处理失败: " + e.getMessage(), e); } } @Override public PaymentResponse refund(String orderNo, String refundNo, PaymentType paymentType, BigDecimal totalAmount, BigDecimal refundAmount, String reason, Integer tenantId) throws PaymentException { log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 退款金额: {}", PaymentConstants.LogMessage.REFUND_START, paymentType, tenantId, orderNo, refundNo, refundAmount); try { // 参数验证 validateRefundParams(orderNo, refundNo, paymentType, totalAmount, refundAmount, tenantId); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(paymentType); // 检查是否支持退款 if (!strategy.supportRefund()) { throw PaymentException.unsupportedPayment("该支付方式不支持退款", paymentType); } // 执行退款 PaymentResponse response = strategy.refund(orderNo, refundNo, totalAmount, refundAmount, reason, tenantId); log.info("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 退款金额: {}", PaymentConstants.LogMessage.REFUND_SUCCESS, paymentType, tenantId, orderNo, refundNo, refundAmount); return response; } catch (PaymentException e) { log.error("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 错误: {}", PaymentConstants.LogMessage.REFUND_FAILED, paymentType, tenantId, orderNo, refundNo, e.getMessage()); throw e; } catch (Exception e) { log.error("{}, 支付类型: {}, 租户ID: {}, 订单号: {}, 退款单号: {}, 系统错误: {}", PaymentConstants.LogMessage.REFUND_FAILED, paymentType, tenantId, orderNo, refundNo, e.getMessage(), e); throw PaymentException.systemError("退款申请失败: " + e.getMessage(), e); } } @Override public PaymentResponse queryRefund(String refundNo, PaymentType paymentType, Integer tenantId) throws PaymentException { log.info("开始查询退款状态, 支付类型: {}, 租户ID: {}, 退款单号: {}", paymentType, tenantId, refundNo); try { // 参数验证 validateRefundQueryParams(refundNo, paymentType, tenantId); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(paymentType); // 检查是否支持退款查询 if (!strategy.supportRefund()) { throw PaymentException.unsupportedPayment("该支付方式不支持退款查询", paymentType); } // 执行查询 PaymentResponse response = strategy.queryRefund(refundNo, tenantId); log.info("退款状态查询成功, 支付类型: {}, 租户ID: {}, 退款单号: {}, 状态: {}", paymentType, tenantId, refundNo, response.getPaymentStatus()); return response; } catch (PaymentException e) { log.error("退款状态查询失败, 支付类型: {}, 租户ID: {}, 退款单号: {}, 错误: {}", paymentType, tenantId, refundNo, e.getMessage()); throw e; } catch (Exception e) { log.error("退款状态查询系统错误, 支付类型: {}, 租户ID: {}, 退款单号: {}, 错误: {}", paymentType, tenantId, refundNo, e.getMessage(), e); throw PaymentException.systemError("退款查询失败: " + e.getMessage(), e); } } @Override public boolean closeOrder(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { log.info("开始关闭订单, 支付类型: {}, 租户ID: {}, 订单号: {}", paymentType, tenantId, orderNo); try { // 参数验证 validateCloseParams(orderNo, paymentType, tenantId); // 获取支付策略 PaymentStrategy strategy = getPaymentStrategy(paymentType); // 检查是否支持关闭订单 if (!strategy.supportClose()) { throw PaymentException.unsupportedPayment("该支付方式不支持关闭订单", paymentType); } // 执行关闭 boolean result = strategy.closeOrder(orderNo, tenantId); log.info("订单关闭{}, 支付类型: {}, 租户ID: {}, 订单号: {}", result ? "成功" : "失败", paymentType, tenantId, orderNo); return result; } catch (PaymentException e) { log.error("订单关闭失败, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", paymentType, tenantId, orderNo, e.getMessage()); throw e; } catch (Exception e) { log.error("订单关闭系统错误, 支付类型: {}, 租户ID: {}, 订单号: {}, 错误: {}", paymentType, tenantId, orderNo, e.getMessage(), e); throw PaymentException.systemError("订单关闭失败: " + e.getMessage(), e); } } @Override public List getSupportedPaymentTypes() { return new ArrayList<>(strategyMap.keySet()); } @Override public boolean isPaymentTypeSupported(PaymentType paymentType) { return strategyMap.containsKey(paymentType); } @Override public boolean isRefundSupported(PaymentType paymentType) { PaymentStrategy strategy = strategyMap.get(paymentType); return strategy != null && strategy.supportRefund(); } @Override public boolean isQuerySupported(PaymentType paymentType) { PaymentStrategy strategy = strategyMap.get(paymentType); return strategy != null && strategy.supportQuery(); } @Override public boolean isCloseSupported(PaymentType paymentType) { PaymentStrategy strategy = strategyMap.get(paymentType); return strategy != null && strategy.supportClose(); } @Override public boolean isNotifyNeeded(PaymentType paymentType) { PaymentStrategy strategy = strategyMap.get(paymentType); return strategy != null && strategy.needNotify(); } @Override public void validatePaymentRequest(PaymentRequest request) throws PaymentException { if (request == null) { throw PaymentException.paramError("支付请求不能为空"); } if (request.getPaymentType() == null) { throw PaymentException.paramError("支付类型不能为空"); } if (request.getTenantId() == null || request.getTenantId() <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } if (request.getUserId() == null || request.getUserId() <= 0) { throw PaymentException.paramError("用户ID不能为空且必须大于0"); } if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw PaymentException.amountError("支付金额必须大于0"); } if (!StringUtils.hasText(request.getSubject())) { throw PaymentException.paramError("订单标题不能为空"); } // 检查支付类型是否支持 if (!isPaymentTypeSupported(request.getPaymentType())) { throw PaymentException.unsupportedPayment("不支持的支付类型: " + request.getPaymentType(), request.getPaymentType()); } } @Override public Map getPaymentStrategyInfo(PaymentType paymentType) { PaymentStrategy strategy = strategyMap.get(paymentType); if (strategy == null) { return null; } Map info = new HashMap<>(); info.put("paymentType", paymentType); info.put("strategyName", strategy.getStrategyName()); info.put("strategyDescription", strategy.getStrategyDescription()); info.put("supportRefund", strategy.supportRefund()); info.put("supportQuery", strategy.supportQuery()); info.put("supportClose", strategy.supportClose()); info.put("needNotify", strategy.needNotify()); return info; } @Override public List> getAllPaymentStrategyInfo() { return strategyMap.keySet().stream() .map(this::getPaymentStrategyInfo) .collect(Collectors.toList()); } @Override public Map checkPaymentConfig(Integer tenantId) { Map result = new HashMap<>(); result.put("tenantId", tenantId); try { // 检查微信支付配置 wxPayConfigService.getPaymentConfigForStrategy(tenantId); result.put("wechatConfigExists", true); result.put("wechatConfigError", null); } catch (Exception e) { result.put("wechatConfigExists", false); result.put("wechatConfigError", e.getMessage()); } try { // 检查微信支付Config构建 wxPayConfigService.getWxPayConfig(tenantId); result.put("wechatConfigValid", true); result.put("wechatConfigValidError", null); } catch (Exception e) { result.put("wechatConfigValid", false); result.put("wechatConfigValidError", e.getMessage()); } return result; } /** * 获取支付策略 */ private PaymentStrategy getPaymentStrategy(PaymentType paymentType) throws PaymentException { PaymentStrategy strategy = strategyMap.get(paymentType); if (strategy == null) { throw PaymentException.unsupportedPayment("不支持的支付类型: " + paymentType, paymentType); } return strategy; } /** * 验证查询参数 */ private void validateQueryParams(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { if (!StringUtils.hasText(orderNo)) { throw PaymentException.paramError("订单号不能为空"); } if (paymentType == null) { throw PaymentException.paramError("支付类型不能为空"); } if (tenantId == null || tenantId <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } } /** * 验证回调参数 */ private void validateNotifyParams(PaymentType paymentType, Map headers, String body, Integer tenantId) throws PaymentException { if (paymentType == null) { throw PaymentException.paramError("支付类型不能为空"); } if (headers == null || headers.isEmpty()) { throw PaymentException.paramError("请求头不能为空"); } if (!StringUtils.hasText(body)) { throw PaymentException.paramError("请求体不能为空"); } if (tenantId == null || tenantId <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } } /** * 验证退款参数 */ private void validateRefundParams(String orderNo, String refundNo, PaymentType paymentType, BigDecimal totalAmount, BigDecimal refundAmount, Integer tenantId) throws PaymentException { if (!StringUtils.hasText(orderNo)) { throw PaymentException.paramError("订单号不能为空"); } if (!StringUtils.hasText(refundNo)) { throw PaymentException.paramError("退款单号不能为空"); } if (paymentType == null) { throw PaymentException.paramError("支付类型不能为空"); } if (totalAmount == null || totalAmount.compareTo(BigDecimal.ZERO) <= 0) { throw PaymentException.amountError("订单总金额必须大于0"); } if (refundAmount == null || refundAmount.compareTo(BigDecimal.ZERO) <= 0) { throw PaymentException.amountError("退款金额必须大于0"); } if (refundAmount.compareTo(totalAmount) > 0) { throw PaymentException.amountError("退款金额不能大于订单总金额"); } if (tenantId == null || tenantId <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } } /** * 验证退款查询参数 */ private void validateRefundQueryParams(String refundNo, PaymentType paymentType, Integer tenantId) throws PaymentException { if (!StringUtils.hasText(refundNo)) { throw PaymentException.paramError("退款单号不能为空"); } if (paymentType == null) { throw PaymentException.paramError("支付类型不能为空"); } if (tenantId == null || tenantId <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } } /** * 验证关闭订单参数 */ private void validateCloseParams(String orderNo, PaymentType paymentType, Integer tenantId) throws PaymentException { if (!StringUtils.hasText(orderNo)) { throw PaymentException.paramError("订单号不能为空"); } if (paymentType == null) { throw PaymentException.paramError("支付类型不能为空"); } if (tenantId == null || tenantId <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } } /** * 验证支付与订单创建请求参数 */ private void validatePaymentWithOrderRequest(PaymentWithOrderRequest request, User loginUser) throws PaymentException { if (request == null) { throw PaymentException.paramError("请求参数不能为空"); } if (loginUser == null) { throw PaymentException.paramError("用户未登录"); } if (request.getPaymentType() == null) { throw PaymentException.paramError("支付类型不能为空"); } if (request.getAmount() == null || request.getAmount().compareTo(BigDecimal.ZERO) <= 0) { throw PaymentException.amountError("支付金额必须大于0"); } if (!StringUtils.hasText(request.getSubject())) { throw PaymentException.paramError("订单标题不能为空"); } if (request.getTenantId() == null || request.getTenantId() <= 0) { throw PaymentException.paramError("租户ID不能为空且必须大于0"); } if (request.getOrderInfo() == null) { throw PaymentException.paramError("订单信息不能为空"); } if (request.getOrderInfo().getGoodsItems() == null || request.getOrderInfo().getGoodsItems().isEmpty()) { throw PaymentException.paramError("订单商品列表不能为空"); } } /** * 转换为订单创建请求 */ private OrderCreateRequest convertToOrderCreateRequest(PaymentWithOrderRequest request, User loginUser) { OrderCreateRequest orderRequest = new OrderCreateRequest(); // 生成订单号(使用雪花算法保证全局唯一) String orderNo = Long.toString(IdUtil.getSnowflakeNextId()); orderRequest.setOrderNo(orderNo); log.info("为订单创建请求生成订单号(雪花算法): {}", orderNo); // 设置基本信息 orderRequest.setType(request.getOrderInfo().getType()); orderRequest.setTitle(request.getSubject()); orderRequest.setComments(request.getOrderInfo().getComments()); orderRequest.setTenantId(request.getTenantId()); // 设置收货信息 orderRequest.setRealName(request.getOrderInfo().getRealName()); orderRequest.setAddress(request.getOrderInfo().getAddress()); orderRequest.setAddressId(request.getOrderInfo().getAddressId()); orderRequest.setDeliveryType(request.getOrderInfo().getDeliveryType()); // 设置商户信息 orderRequest.setMerchantId(request.getOrderInfo().getMerchantId()); orderRequest.setMerchantName(request.getOrderInfo().getMerchantName()); // 设置支付信息 orderRequest.setPayType(request.getPaymentType().getCode()); orderRequest.setTotalPrice(request.getAmount()); orderRequest.setPayPrice(request.getAmount()); // 设置优惠券 orderRequest.setCouponId(request.getOrderInfo().getCouponId()); // 转换商品列表 List goodsItems = request.getOrderInfo().getGoodsItems().stream() .map(this::convertToOrderGoodsItem) .collect(java.util.stream.Collectors.toList()); orderRequest.setGoodsItems(goodsItems); return orderRequest; } /** * 转换商品项 */ private OrderCreateRequest.OrderGoodsItem convertToOrderGoodsItem(PaymentWithOrderRequest.OrderGoodsItem item) { OrderCreateRequest.OrderGoodsItem orderItem = new OrderCreateRequest.OrderGoodsItem(); orderItem.setGoodsId(item.getGoodsId()); orderItem.setSkuId(item.getSkuId()); orderItem.setQuantity(item.getQuantity()); orderItem.setSpecInfo(item.getSpecInfo()); return orderItem; } /** * 从微信订单信息构建支付响应 */ private PaymentResponse buildPaymentResponseFromWxOrder(Map wxOrderInfo, PaymentWithOrderRequest request, String orderNo) { PaymentResponse response = PaymentResponse.wechatNative( orderNo, wxOrderInfo.get("codeUrl"), request.getAmount(), request.getTenantId() ); // 设置额外信息 response.setSuccess(true); // 确保orderNo被正确设置 response.setOrderNo(orderNo); // 调试日志 log.info("构建支付响应成功, 订单号: {}, 二维码URL: {}, 响应中的orderNo: {}", orderNo, wxOrderInfo.get("codeUrl"), response.getOrderNo()); return response; } }