mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	mall + pay:
1、调整 returnUrl 的实现
This commit is contained in:
		@@ -23,13 +23,4 @@ public class PayProperties {
 | 
			
		||||
    @URL(message = "回调地址的格式必须是 URL")
 | 
			
		||||
    private String callbackUrl;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 回跳地址
 | 
			
		||||
     *
 | 
			
		||||
     * 实际上,对应的 PayNotifyController 的 returnCallback 方法的 URL
 | 
			
		||||
     */
 | 
			
		||||
    @URL(message = "回跳地址的格式必须是 URL")
 | 
			
		||||
    @NotEmpty(message = "回跳地址不能为空")
 | 
			
		||||
    private String returnUrl;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,6 @@
 | 
			
		||||
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.map.MapUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.http.Method;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
 | 
			
		||||
@@ -41,11 +40,11 @@ public class AlipayPcPayClient extends AbstractAlipayClient {
 | 
			
		||||
        model.setTimeExpire(formatTime(reqDTO.getExpireTime()));
 | 
			
		||||
        model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前 PC 支付场景下仅支持 FAST_INSTANT_TRADE_PAY
 | 
			
		||||
        // ② 个性化的参数
 | 
			
		||||
        // 参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分
 | 
			
		||||
        model.setQrPayMode(MapUtil.getStr(reqDTO.getChannelExtras(), "qr_pay_mode"));
 | 
			
		||||
        model.setQrcodeWidth(MapUtil.getLong(reqDTO.getChannelExtras(), "qr_code_width"));
 | 
			
		||||
        // ③ 支付宝 PC 支付有多种展示模式,因此这里需要计算
 | 
			
		||||
        String displayMode = getDisplayMode(reqDTO.getDisplayMode(), model.getQrPayMode());
 | 
			
		||||
        // 如果想弄更多个性化的参数,可参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分进行拓展
 | 
			
		||||
        model.setQrPayMode("2"); // 跳转模式 - 订单码,效果参见:https://help.pingxx.com/article/1137360/
 | 
			
		||||
        // ③ 支付宝 PC 支付有两种展示模式:FORM、URL
 | 
			
		||||
        String displayMode = ObjectUtil.defaultIfNull(reqDTO.getDisplayMode(),
 | 
			
		||||
                PayDisplayModeEnum.URL.getMode());
 | 
			
		||||
 | 
			
		||||
        // 1.2 构建 AlipayTradePagePayRequest 请求
 | 
			
		||||
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
 | 
			
		||||
@@ -67,25 +66,4 @@ public class AlipayPcPayClient extends AbstractAlipayClient {
 | 
			
		||||
                .setDisplayContent(response.getBody());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获得最终的支付 UI 展示模式
 | 
			
		||||
     *
 | 
			
		||||
     * @param displayMode 前端传递的 UI 展示模式
 | 
			
		||||
     * @param qrPayMode 前端传递的二维码模式
 | 
			
		||||
     * @return 最终的支付 UI 展示模式
 | 
			
		||||
     */
 | 
			
		||||
    private String getDisplayMode(String displayMode, String qrPayMode) {
 | 
			
		||||
        // 1.1 支付宝二维码的前置模式
 | 
			
		||||
        if (StrUtil.equalsAny(qrPayMode, "0", "1", "3", "4")) {
 | 
			
		||||
            return PayDisplayModeEnum.IFRAME.getMode();
 | 
			
		||||
        }
 | 
			
		||||
        // 1.2 支付宝二维码的跳转模式
 | 
			
		||||
        if (StrUtil.equals(qrPayMode, "2")) {
 | 
			
		||||
            return PayDisplayModeEnum.URL.getMode();
 | 
			
		||||
        }
 | 
			
		||||
        // 2. 前端传递了 UI 展示模式
 | 
			
		||||
        return displayMode != null ? displayMode :
 | 
			
		||||
                PayDisplayModeEnum.URL.getMode(); // 模式使用 URL 跳转
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,5 @@
 | 
			
		||||
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.http.Method;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
 | 
			
		||||
@@ -37,9 +36,8 @@ public class AlipayWapPayClient extends AbstractAlipayClient {
 | 
			
		||||
        model.setTotalAmount(formatAmount(reqDTO.getAmount()));
 | 
			
		||||
        model.setProductCode("QUICK_WAP_PAY"); // 销售产品码. 目前 Wap 支付场景下仅支持 QUICK_WAP_PAY
 | 
			
		||||
        // ② 个性化的参数【无】
 | 
			
		||||
        // ③ 支付宝 Wap 支付只有一种展示,考虑到前端可能希望二维码扫描后,手机打开
 | 
			
		||||
        String displayMode = ObjectUtil.defaultIfNull(reqDTO.getDisplayMode(),
 | 
			
		||||
                PayDisplayModeEnum.URL.getMode());
 | 
			
		||||
        // ③ 支付宝 Wap 支付只有一种展示:URL
 | 
			
		||||
        String displayMode = PayDisplayModeEnum.URL.getMode();
 | 
			
		||||
 | 
			
		||||
        // 1.2 构建 AlipayTradeWapPayRequest 请求
 | 
			
		||||
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest();
 | 
			
		||||
 
 | 
			
		||||
@@ -93,6 +93,10 @@
 | 
			
		||||
            <groupId>cn.iocoder.boot</groupId>
 | 
			
		||||
            <artifactId>yudao-spring-boot-starter-excel</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
        <dependency>
 | 
			
		||||
            <groupId>cn.iocoder.boot</groupId>
 | 
			
		||||
            <artifactId>yudao-spring-boot-starter-biz-dict</artifactId>
 | 
			
		||||
        </dependency>
 | 
			
		||||
 | 
			
		||||
    </dependencies>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,8 +55,10 @@ public class AppTradeOrderDetailRespVO {
 | 
			
		||||
    @Schema(description = "付款超时时间", requiredMode = Schema.RequiredMode.REQUIRED)
 | 
			
		||||
    private LocalDateTime payExpireTime;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "支付渠道", requiredMode = Schema.RequiredMode.REQUIRED, example = "wx_lite_pay")
 | 
			
		||||
    @Schema(description = "支付渠道", example = "wx_lite_pay")
 | 
			
		||||
    private String payChannelCode;
 | 
			
		||||
    @Schema(description = "支付渠道名", example = "微信小程序支付")
 | 
			
		||||
    private String payChannelName;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "商品原价(总)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
 | 
			
		||||
    private Integer totalPrice;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,15 @@
 | 
			
		||||
package cn.iocoder.yudao.module.trade.convert.order;
 | 
			
		||||
 | 
			
		||||
import cn.hutool.core.collection.CollUtil;
 | 
			
		||||
import cn.hutool.core.util.StrUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.dict.core.util.DictFrameworkUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 | 
			
		||||
import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.enums.DictTypeConstants;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.comment.dto.ProductCommentCreateReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.property.dto.ProductPropertyValueDetailRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuUpdateStockReqDTO;
 | 
			
		||||
@@ -234,6 +237,9 @@ public interface TradeOrderConvert {
 | 
			
		||||
                                                List<ProductPropertyValueDetailRespDTO> propertyValueDetails, TradeOrderProperties tradeOrderProperties) {
 | 
			
		||||
        AppTradeOrderDetailRespVO orderVO = convert3(order, orderItems);
 | 
			
		||||
        orderVO.setPayExpireTime(addTime(tradeOrderProperties.getExpireTime()));
 | 
			
		||||
        if (StrUtil.isNotEmpty(order.getPayChannelCode())) {
 | 
			
		||||
            orderVO.setPayChannelName(DictFrameworkUtils.getDictDataLabel(DictTypeConstants.CHANNEL_CODE_TYPE, order.getPayChannelCode()));
 | 
			
		||||
        }
 | 
			
		||||
        // 处理商品属性
 | 
			
		||||
        Map<Long, ProductPropertyValueDetailRespDTO> propertyValueDetailMap = convertMap(propertyValueDetails, ProductPropertyValueDetailRespDTO::getValueId);
 | 
			
		||||
        for (int i = 0; i < orderItems.size(); i++) {
 | 
			
		||||
 
 | 
			
		||||
@@ -7,6 +7,8 @@ package cn.iocoder.yudao.module.pay.enums;
 | 
			
		||||
 */
 | 
			
		||||
public interface DictTypeConstants {
 | 
			
		||||
 | 
			
		||||
    String CHANNEL_CODE_TYPE = "pay_channel_code_type"; // 支付-渠道名
 | 
			
		||||
 | 
			
		||||
    String ORDER_STATUS = "pay_order_status"; // 支付-订单-订单状态
 | 
			
		||||
    String ORDER_NOTIFY_STATUS = "pay_order_notify_status"; // 支付-订单-订单回调商户状态
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,8 +6,6 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyReqDTO;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayRefundNotifyRespDTO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
			
		||||
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 | 
			
		||||
import io.swagger.v3.oas.annotations.Operation;
 | 
			
		||||
@@ -39,23 +37,6 @@ public class PayNotifyController {
 | 
			
		||||
    @Resource
 | 
			
		||||
    private PayClientFactory payClientFactory;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 统一的跳转页面,支付宝跳转参数说明
 | 
			
		||||
     *
 | 
			
		||||
     * <a href="https://opendocs.alipay.com/open/203/105285#前台回跳参数说明">支付宝 - 前台回跳参数说明</a>
 | 
			
		||||
     *
 | 
			
		||||
     * @param channelId 渠道编号
 | 
			
		||||
     * @return 返回跳转页面
 | 
			
		||||
     */
 | 
			
		||||
    @GetMapping(value = "/return/{channelId}")
 | 
			
		||||
    @Operation(summary = "渠道统一的支付成功返回地址")
 | 
			
		||||
    @Deprecated // TODO yunai:如果是 way 的情况,应该是跳转回前端地址
 | 
			
		||||
    public String returnCallback(@PathVariable("channelId") Long channelId,
 | 
			
		||||
                                 @RequestParam Map<String, String> params) {
 | 
			
		||||
        log.info("[returnCallback][app_id({}) 跳转]", params.get("app_id"));
 | 
			
		||||
        return String.format("渠道[%s]支付成功", channelId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 统一的渠道支付回调,支付宝的退款回调
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,10 @@ package cn.iocoder.yudao.module.pay.controller.admin.order.vo;
 | 
			
		||||
 | 
			
		||||
import io.swagger.v3.oas.annotations.media.Schema;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.experimental.Accessors;
 | 
			
		||||
import org.hibernate.validator.constraints.URL;
 | 
			
		||||
 | 
			
		||||
import javax.validation.constraints.NotEmpty;
 | 
			
		||||
import javax.validation.constraints.NotNull;
 | 
			
		||||
import java.awt.*;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Schema(description = "管理后台 - 支付订单提交 Request VO")
 | 
			
		||||
@@ -26,4 +25,9 @@ public class PayOrderSubmitReqVO {
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "展示模式", example = "url") // 参见 {@link PayDisplayModeEnum} 枚举。如果不传递,则每个支付渠道使用默认的方式
 | 
			
		||||
    private String displayMode;
 | 
			
		||||
 | 
			
		||||
    @Schema(description = "回跳地址")
 | 
			
		||||
    @URL(message = "回跳地址的格式必须是 URL")
 | 
			
		||||
    private String returnUrl;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,6 @@ Authorization: Bearer {{appToken}}
 | 
			
		||||
tenant-id: {{appTenentId}}
 | 
			
		||||
 | 
			
		||||
{
 | 
			
		||||
  "id": 125,
 | 
			
		||||
  "channelCode": "alipay_qr"
 | 
			
		||||
  "id": 174,
 | 
			
		||||
  "channelCode": "alipay_pc"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,6 @@ import cn.hutool.core.date.DateUtil;
 | 
			
		||||
import cn.hutool.core.util.ObjectUtil;
 | 
			
		||||
import cn.hutool.core.util.RandomUtil;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
			
		||||
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.config.PayProperties;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
 | 
			
		||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
 | 
			
		||||
@@ -44,7 +43,7 @@ import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.*;
 | 
			
		||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 支付订单 Service 实现类
 | 
			
		||||
@@ -147,7 +146,7 @@ public class PayOrderServiceImpl implements PayOrderService {
 | 
			
		||||
                .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性!
 | 
			
		||||
                .setSubject(order.getSubject()).setBody(order.getBody())
 | 
			
		||||
                .setNotifyUrl(genChannelPayNotifyUrl(channel))
 | 
			
		||||
                .setReturnUrl(genChannelReturnUrl(channel))
 | 
			
		||||
                .setReturnUrl(reqVO.getReturnUrl())
 | 
			
		||||
                // 订单相关字段
 | 
			
		||||
                .setAmount(order.getAmount()).setExpireTime(order.getExpireTime());
 | 
			
		||||
        PayOrderUnifiedRespDTO unifiedOrderRespDTO = client.unifiedOrder(unifiedOrderReqDTO);
 | 
			
		||||
@@ -183,15 +182,6 @@ public class PayOrderServiceImpl implements PayOrderService {
 | 
			
		||||
        return channel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据支付渠道的编码,生成支付渠道的返回地址
 | 
			
		||||
     * @param channel 支付渠道
 | 
			
		||||
     * @return 支付成功返回的地址。 配置地址 + "/" + channel id
 | 
			
		||||
     */
 | 
			
		||||
    private String genChannelReturnUrl(PayChannelDO channel) {
 | 
			
		||||
        return payProperties.getReturnUrl() + "/" + channel.getId();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 根据支付渠道的编码,生成支付渠道的回调地址
 | 
			
		||||
     *
 | 
			
		||||
 
 | 
			
		||||
@@ -168,7 +168,6 @@ yudao:
 | 
			
		||||
      - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
 | 
			
		||||
  pay:
 | 
			
		||||
    callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback
 | 
			
		||||
    return-url: http://yunai.natapp1.cc/admin-api/pay/notify/return
 | 
			
		||||
  demo: true # 开启演示模式
 | 
			
		||||
 | 
			
		||||
justauth:
 | 
			
		||||
 
 | 
			
		||||
@@ -195,7 +195,6 @@ yudao:
 | 
			
		||||
      - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求
 | 
			
		||||
  pay:
 | 
			
		||||
    callback-url: http://yunai.natapp1.cc/admin-api/pay/notify/callback
 | 
			
		||||
    return-url: http://yunai.natapp1.cc/admin-api/pay/notify/return
 | 
			
		||||
  access-log: # 访问日志的配置项
 | 
			
		||||
    enable: false
 | 
			
		||||
  error-code: # 错误码相关配置项
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user