Commit b34801f303773ec8dcdd9d516f606b8a5701b085
1 parent
df702e8d
pay: 接入支付宝 PC 支付的跳转模式
Showing
17 changed files
with
262 additions
and
158 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedReqDTO.java
| 1 | package cn.iocoder.yudao.framework.pay.core.client.dto.order; | 1 | package cn.iocoder.yudao.framework.pay.core.client.dto.order; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum; | ||
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | import org.hibernate.validator.constraints.Length; | 5 | import org.hibernate.validator.constraints.Length; |
| 5 | import org.hibernate.validator.constraints.URL; | 6 | import org.hibernate.validator.constraints.URL; |
| @@ -7,6 +8,7 @@ import org.hibernate.validator.constraints.URL; | @@ -7,6 +8,7 @@ import org.hibernate.validator.constraints.URL; | ||
| 7 | import javax.validation.constraints.DecimalMin; | 8 | import javax.validation.constraints.DecimalMin; |
| 8 | import javax.validation.constraints.NotEmpty; | 9 | import javax.validation.constraints.NotEmpty; |
| 9 | import javax.validation.constraints.NotNull; | 10 | import javax.validation.constraints.NotNull; |
| 11 | +import java.awt.*; | ||
| 10 | import java.time.LocalDateTime; | 12 | import java.time.LocalDateTime; |
| 11 | import java.util.Map; | 13 | import java.util.Map; |
| 12 | 14 | ||
| @@ -78,4 +80,13 @@ public class PayOrderUnifiedReqDTO { | @@ -78,4 +80,13 @@ public class PayOrderUnifiedReqDTO { | ||
| 78 | */ | 80 | */ |
| 79 | private Map<String, String> channelExtras; | 81 | private Map<String, String> channelExtras; |
| 80 | 82 | ||
| 83 | + /** | ||
| 84 | + * 展示模式 | ||
| 85 | + * | ||
| 86 | + * 如果不传递,则每个支付渠道使用默认的方式 | ||
| 87 | + * | ||
| 88 | + * 枚举 {@link PayDisplayModeEnum} | ||
| 89 | + */ | ||
| 90 | + private String displayMode; | ||
| 91 | + | ||
| 81 | } | 92 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/bo/PayOrderSubmitRespBO.java renamed to yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/order/PayOrderUnifiedRespDTO.java
| 1 | -package cn.iocoder.yudao.module.pay.service.order.bo; | 1 | +package cn.iocoder.yudao.framework.pay.core.client.dto.order; |
| 2 | 2 | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 3 | import lombok.Data; | 4 | import lombok.Data; |
| 4 | 5 | ||
| 5 | -import java.io.Serializable; | ||
| 6 | - | ||
| 7 | /** | 6 | /** |
| 8 | - * 支付单提交 Response BO | 7 | + * 统一下单 Response DTO |
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 9 | */ | 10 | */ |
| 10 | @Data | 11 | @Data |
| 11 | -public class PayOrderSubmitRespBO implements Serializable { | 12 | +public class PayOrderUnifiedRespDTO { |
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | - * 支付拓展单的编号 | 15 | + * 展示模式 |
| 15 | */ | 16 | */ |
| 16 | - private Long extensionId; | ||
| 17 | - | 17 | + private String displayMode; |
| 18 | /** | 18 | /** |
| 19 | - * 调用支付渠道的响应结果 | 19 | + * 展示内容 |
| 20 | */ | 20 | */ |
| 21 | - private Object invokeResponse; | 21 | + private String displayContent; |
| 22 | 22 | ||
| 23 | } | 23 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java
| @@ -69,6 +69,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | @@ -69,6 +69,7 @@ public abstract class AbstractPayClient<Config extends PayClientConfig> implemen | ||
| 69 | this.init(); | 69 | this.init(); |
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | + // TODO 芋艿:后续抽取到工具类里 | ||
| 72 | protected Double calculateAmount(Integer amount) { | 73 | protected Double calculateAmount(Integer amount) { |
| 73 | return amount / 100.0; | 74 | return amount / 100.0; |
| 74 | } | 75 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPcPayClient.java
| 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; | 1 | package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.lang.Pair; | ||
| 4 | +import cn.hutool.core.map.MapUtil; | ||
| 5 | +import cn.hutool.core.util.ObjectUtil; | ||
| 3 | import cn.hutool.core.util.StrUtil; | 6 | import cn.hutool.core.util.StrUtil; |
| 4 | import cn.hutool.http.Method; | 7 | import cn.hutool.http.Method; |
| 8 | +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; | ||
| 5 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | 9 | import cn.iocoder.yudao.framework.common.util.json.JsonUtils; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; | 10 | import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; |
| 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 11 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 12 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | ||
| 8 | import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | 13 | import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; |
| 9 | -import com.alibaba.fastjson.JSONObject; | 14 | +import cn.iocoder.yudao.framework.pay.core.enums.PayDisplayModeEnum; |
| 10 | import com.alipay.api.AlipayApiException; | 15 | import com.alipay.api.AlipayApiException; |
| 11 | import com.alipay.api.domain.AlipayTradePagePayModel; | 16 | import com.alipay.api.domain.AlipayTradePagePayModel; |
| 12 | import com.alipay.api.request.AlipayTradePagePayRequest; | 17 | import com.alipay.api.request.AlipayTradePagePayRequest; |
| 13 | import com.alipay.api.response.AlipayTradePagePayResponse; | 18 | import com.alipay.api.response.AlipayTradePagePayResponse; |
| 14 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
| 15 | 20 | ||
| 21 | +import java.util.HashMap; | ||
| 22 | +import java.util.Objects; | ||
| 23 | + | ||
| 16 | 24 | ||
| 17 | /** | 25 | /** |
| 18 | * 支付宝【PC网站支付】的 PayClient 实现类 | 26 | * 支付宝【PC网站支付】的 PayClient 实现类 |
| @@ -28,35 +36,72 @@ public class AlipayPcPayClient extends AbstractAlipayClient { | @@ -28,35 +36,72 @@ public class AlipayPcPayClient extends AbstractAlipayClient { | ||
| 28 | } | 36 | } |
| 29 | 37 | ||
| 30 | @Override | 38 | @Override |
| 31 | - public PayCommonResult<AlipayTradePagePayResponse> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | ||
| 32 | - // 构建 AlipayTradePagePayModel 请求 | 39 | + public PayCommonResult<PayOrderUnifiedRespDTO> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { |
| 40 | + // 1.1 构建 AlipayTradePagePayModel 请求 | ||
| 33 | AlipayTradePagePayModel model = new AlipayTradePagePayModel(); | 41 | AlipayTradePagePayModel model = new AlipayTradePagePayModel(); |
| 34 | - // 构建 AlipayTradePagePayRequest | 42 | + // ① 通用的参数 |
| 43 | + model.setOutTradeNo(reqDTO.getMerchantOrderId()); | ||
| 44 | + model.setSubject(reqDTO.getSubject()); | ||
| 45 | + model.setTotalAmount(String.valueOf(calculateAmount(reqDTO.getAmount()))); | ||
| 46 | + model.setProductCode("FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前电脑支付场景下仅支持 FAST_INSTANT_TRADE_PAY | ||
| 47 | + // ② 个性化的参数 | ||
| 48 | + // 参考 https://www.pingxx.com/api/支付渠道 extra 参数说明.html 的 alipay_pc_direct 部分 | ||
| 49 | + model.setQrPayMode(MapUtil.getStr(reqDTO.getChannelExtras(), "qr_pay_mode")); | ||
| 50 | + model.setQrcodeWidth(MapUtil.getLong(reqDTO.getChannelExtras(), "qr_code_width")); | ||
| 51 | + // ③ 支付宝 PC 支付有多种展示模式,因此这里需要计算 | ||
| 52 | + String displayMode = getDisplayMode(reqDTO.getDisplayMode(), model.getQrPayMode()); | ||
| 53 | + | ||
| 54 | + // 1.2 构建 AlipayTradePagePayRequest 请求 | ||
| 35 | AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); | 55 | AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); |
| 36 | request.setBizModel(model); | 56 | request.setBizModel(model); |
| 37 | - JSONObject bizContent = new JSONObject(); | ||
| 38 | - // 参数说明可查看: https://opendocs.alipay.com/open/028r8t?scene=22 | ||
| 39 | - bizContent.put("out_trade_no", reqDTO.getMerchantOrderId()); | ||
| 40 | - bizContent.put("subject", reqDTO.getSubject()); | ||
| 41 | - bizContent.put("total_amount", calculateAmount(reqDTO.getAmount())); | ||
| 42 | - bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY"); // 销售产品码. 目前电脑支付场景下仅支持 FAST_INSTANT_TRADE_PAY | ||
| 43 | - // PC扫码支付的方式:支持前置模式和跳转模式。4: 订单码-可定义宽度的嵌入式二维码 | ||
| 44 | -// bizContent.put("qr_pay_mode", "4"); | ||
| 45 | - // 自定义二维码宽度 | ||
| 46 | -// bizContent.put("qrcode_width", "150"); | ||
| 47 | - request.setBizContent(bizContent.toJSONString()); | ||
| 48 | request.setNotifyUrl(reqDTO.getNotifyUrl()); | 57 | request.setNotifyUrl(reqDTO.getNotifyUrl()); |
| 49 | - request.setReturnUrl(""); | ||
| 50 | - // 执行请求 | 58 | + request.setReturnUrl(""); // TODO 芋艿,待搞 |
| 59 | + | ||
| 60 | + // 2.1 执行请求 | ||
| 51 | AlipayTradePagePayResponse response; | 61 | AlipayTradePagePayResponse response; |
| 52 | try { | 62 | try { |
| 53 | - response = client.pageExecute(request, Method.GET.name()); | 63 | + if (Objects.equals(displayMode, PayDisplayModeEnum.FORM.getMode())) { |
| 64 | + response = client.pageExecute(request, Method.POST.name()); // 需要特殊使用 POST 请求 | ||
| 65 | + } else { | ||
| 66 | + response = client.pageExecute(request, Method.GET.name()); | ||
| 67 | + } | ||
| 54 | } catch (AlipayApiException e) { | 68 | } catch (AlipayApiException e) { |
| 55 | log.error("[unifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e); | 69 | log.error("[unifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e); |
| 56 | return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); | 70 | return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); |
| 57 | } | 71 | } |
| 72 | + // 1. form | ||
| 73 | + // 2. url | ||
| 74 | + // 3. code | ||
| 75 | + // 4. code url | ||
| 76 | + | ||
| 77 | + // 2.2 处理结果 | ||
| 58 | System.out.println(response.getBody()); | 78 | System.out.println(response.getBody()); |
| 79 | + PayOrderUnifiedRespDTO respDTO = new PayOrderUnifiedRespDTO() | ||
| 80 | + .setDisplayMode(displayMode).setDisplayContent(response.getBody()); | ||
| 59 | // 响应为表单格式,前端可嵌入响应的页面或关闭当前支付窗口 | 81 | // 响应为表单格式,前端可嵌入响应的页面或关闭当前支付窗口 |
| 60 | - return PayCommonResult.build(StrUtil.blankToDefault(response.getCode(),"10000") ,response.getMsg(), response, codeMapping); | 82 | + return PayCommonResult.build(StrUtil.blankToDefault(response.getCode(),"10000"), |
| 83 | + response.getMsg(), respDTO, codeMapping); | ||
| 61 | } | 84 | } |
| 85 | + | ||
| 86 | + /** | ||
| 87 | + * 获得最终的支付 UI 展示模式 | ||
| 88 | + * | ||
| 89 | + * @param displayMode 前端传递的 UI 展示模式 | ||
| 90 | + * @param qrPayMode 前端传递的二维码模式 | ||
| 91 | + * @return 最终的支付 UI 展示模式 | ||
| 92 | + */ | ||
| 93 | + private String getDisplayMode(String displayMode, String qrPayMode) { | ||
| 94 | + // 1.1 支付宝二维码的前置模式 | ||
| 95 | + if (StrUtil.equalsAny(qrPayMode, "0", "1", "3", "4")) { | ||
| 96 | + return PayDisplayModeEnum.IFRAME.getMode(); | ||
| 97 | + } | ||
| 98 | + // 1.2 支付宝二维码的跳转模式 | ||
| 99 | + if (StrUtil.equals(qrPayMode, "2")) { | ||
| 100 | + return PayDisplayModeEnum.URL.getMode(); | ||
| 101 | + } | ||
| 102 | + // 2. 前端传递了 UI 展示模式 | ||
| 103 | + return displayMode != null ? displayMode : | ||
| 104 | + PayDisplayModeEnum.URL.getMode(); // 模式使用 URL 跳转 | ||
| 105 | + } | ||
| 106 | + | ||
| 62 | } | 107 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayDisplayModeEnum.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.pay.core.enums; | ||
| 2 | + | ||
| 3 | +import lombok.AllArgsConstructor; | ||
| 4 | +import lombok.Getter; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 支付 UI 展示模式 | ||
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 10 | + */ | ||
| 11 | +@Getter | ||
| 12 | +@AllArgsConstructor | ||
| 13 | +public enum PayDisplayModeEnum { | ||
| 14 | + | ||
| 15 | + URL("url"), // Redirect 跳转链接的方式 | ||
| 16 | + IFRAME("iframe"), // IFrame 内嵌链接的方式 | ||
| 17 | + FORM("form"), // HTML 表单提交 | ||
| 18 | + QR_CODE("qr_code"), // 二维码的文字内容 | ||
| 19 | + QR_CODE_URL("qr_code_url"), // 二维码的图片链接 | ||
| 20 | + ; | ||
| 21 | + | ||
| 22 | + /** | ||
| 23 | + * 展示模式 | ||
| 24 | + */ | ||
| 25 | + private final String mode; | ||
| 26 | + | ||
| 27 | +} |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
| @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.pay.controller.admin.order; | @@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.pay.controller.admin.order; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollectionUtil; | 3 | import cn.hutool.core.collection.CollectionUtil; |
| 4 | import cn.hutool.core.util.ObjectUtil; | 4 | import cn.hutool.core.util.ObjectUtil; |
| 5 | +import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 6 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 8 | +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||
| 9 | +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||
| 10 | +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | ||
| 5 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; | 11 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 6 | -import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; | ||
| 7 | -import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; | ||
| 8 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | 12 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 9 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; | 13 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; |
| 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayMerchantDO; | 14 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayMerchantDO; |
| @@ -14,16 +18,9 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; | @@ -14,16 +18,9 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; | ||
| 14 | import cn.iocoder.yudao.module.pay.service.merchant.PayMerchantService; | 18 | import cn.iocoder.yudao.module.pay.service.merchant.PayMerchantService; |
| 15 | import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; | 19 | import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService; |
| 16 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 20 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 17 | -import cn.iocoder.yudao.framework.common.pojo.CommonResult; | ||
| 18 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 19 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 20 | -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; | ||
| 21 | -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; | ||
| 22 | -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | ||
| 23 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO; | ||
| 24 | -import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 25 | -import io.swagger.v3.oas.annotations.Parameter; | ||
| 26 | import io.swagger.v3.oas.annotations.Operation; | 21 | import io.swagger.v3.oas.annotations.Operation; |
| 22 | +import io.swagger.v3.oas.annotations.Parameter; | ||
| 23 | +import io.swagger.v3.oas.annotations.tags.Tag; | ||
| 27 | import org.springframework.security.access.prepost.PreAuthorize; | 24 | import org.springframework.security.access.prepost.PreAuthorize; |
| 28 | import org.springframework.validation.annotation.Validated; | 25 | import org.springframework.validation.annotation.Validated; |
| 29 | import org.springframework.web.bind.annotation.*; | 26 | import org.springframework.web.bind.annotation.*; |
| @@ -94,10 +91,9 @@ public class PayOrderController { | @@ -94,10 +91,9 @@ public class PayOrderController { | ||
| 94 | 91 | ||
| 95 | @PostMapping("/submit") | 92 | @PostMapping("/submit") |
| 96 | @Operation(summary = "提交支付订单") | 93 | @Operation(summary = "提交支付订单") |
| 97 | - public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { | ||
| 98 | - PayOrderSubmitRespBO respDTO = payOrderService.submitPayOrder( | ||
| 99 | - PayOrderConvert.INSTANCE.convert(reqVO, getClientIP())); | ||
| 100 | - return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse())); | 94 | + public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) { |
| 95 | + PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP()); | ||
| 96 | + return success(respVO); | ||
| 101 | } | 97 | } |
| 102 | 98 | ||
| 103 | @GetMapping("/page") | 99 | @GetMapping("/page") |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitReqVO.java
| @@ -6,11 +6,11 @@ import lombok.experimental.Accessors; | @@ -6,11 +6,11 @@ import lombok.experimental.Accessors; | ||
| 6 | 6 | ||
| 7 | import javax.validation.constraints.NotEmpty; | 7 | import javax.validation.constraints.NotEmpty; |
| 8 | import javax.validation.constraints.NotNull; | 8 | import javax.validation.constraints.NotNull; |
| 9 | +import java.awt.*; | ||
| 9 | import java.util.Map; | 10 | import java.util.Map; |
| 10 | 11 | ||
| 11 | @Schema(description = "管理后台 - 支付订单提交 Request VO") | 12 | @Schema(description = "管理后台 - 支付订单提交 Request VO") |
| 12 | @Data | 13 | @Data |
| 13 | -@Accessors(chain = true) | ||
| 14 | public class PayOrderSubmitReqVO { | 14 | public class PayOrderSubmitReqVO { |
| 15 | 15 | ||
| 16 | @Schema(description = "支付单编号", required = true, example = "1024") | 16 | @Schema(description = "支付单编号", required = true, example = "1024") |
| @@ -24,4 +24,6 @@ public class PayOrderSubmitReqVO { | @@ -24,4 +24,6 @@ public class PayOrderSubmitReqVO { | ||
| 24 | @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数") | 24 | @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数") |
| 25 | private Map<String, String> channelExtras; | 25 | private Map<String, String> channelExtras; |
| 26 | 26 | ||
| 27 | + @Schema(description = "展示模式", example = "url") // 参见 {@link PayDisplayModeEnum} 枚举。如果不传递,则每个支付渠道使用默认的方式 | ||
| 28 | + private String displayMode; | ||
| 27 | } | 29 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/vo/PayOrderSubmitRespVO.java
| @@ -9,15 +9,12 @@ import lombok.experimental.Accessors; | @@ -9,15 +9,12 @@ import lombok.experimental.Accessors; | ||
| 9 | 9 | ||
| 10 | @Schema(description = "管理后台 - 支付订单提交 Response VO") | 10 | @Schema(description = "管理后台 - 支付订单提交 Response VO") |
| 11 | @Data | 11 | @Data |
| 12 | -@Accessors(chain = true) | ||
| 13 | -@Builder | ||
| 14 | -@NoArgsConstructor | ||
| 15 | -@AllArgsConstructor | ||
| 16 | public class PayOrderSubmitRespVO { | 12 | public class PayOrderSubmitRespVO { |
| 17 | 13 | ||
| 18 | - /** | ||
| 19 | - * 调用支付渠道的响应结果 | ||
| 20 | - */ | ||
| 21 | - private Object invokeResponse; | 14 | + @Schema(description = "展示模式", required = true, example = "url") // 参见 PayDisplayModeEnum 枚举 |
| 15 | + private String displayMode; | ||
| 16 | + | ||
| 17 | + @Schema(description = "展示内容", required = true) | ||
| 18 | + private String displayContent; | ||
| 22 | 19 | ||
| 23 | } | 20 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
| 1 | package cn.iocoder.yudao.module.pay.controller.app.order; | 1 | package cn.iocoder.yudao.module.pay.controller.app.order; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 4 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; | ||
| 4 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; | 5 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; |
| 5 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; | 6 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; |
| 6 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | 7 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 7 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 8 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 8 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO; | ||
| 9 | import io.swagger.v3.oas.annotations.Operation; | 9 | import io.swagger.v3.oas.annotations.Operation; |
| 10 | import io.swagger.v3.oas.annotations.tags.Tag; | 10 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 11 | import lombok.extern.slf4j.Slf4j; | 11 | import lombok.extern.slf4j.Slf4j; |
| @@ -33,9 +33,8 @@ public class AppPayOrderController { | @@ -33,9 +33,8 @@ public class AppPayOrderController { | ||
| 33 | @PostMapping("/submit") | 33 | @PostMapping("/submit") |
| 34 | @Operation(summary = "提交支付订单") | 34 | @Operation(summary = "提交支付订单") |
| 35 | public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { | 35 | public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) { |
| 36 | - PayOrderSubmitRespBO respDTO = orderService.submitPayOrder( | ||
| 37 | - PayOrderConvert.INSTANCE.convert(reqVO, getClientIP())); | ||
| 38 | - return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse())); | 36 | + PayOrderSubmitRespVO respVO = orderService.submitPayOrder(reqVO, getClientIP()); |
| 37 | + return success(PayOrderConvert.INSTANCE.convert3(respVO)); | ||
| 39 | } | 38 | } |
| 40 | 39 | ||
| 41 | } | 40 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitReqVO.java
| 1 | package cn.iocoder.yudao.module.pay.controller.app.order.vo; | 1 | package cn.iocoder.yudao.module.pay.controller.app.order.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.Data; | 5 | import lombok.Data; |
| 5 | import lombok.experimental.Accessors; | 6 | import lombok.experimental.Accessors; |
| @@ -10,18 +11,5 @@ import java.util.Map; | @@ -10,18 +11,5 @@ import java.util.Map; | ||
| 10 | 11 | ||
| 11 | @Schema(description = "用户 APP - 支付订单提交 Request VO") | 12 | @Schema(description = "用户 APP - 支付订单提交 Request VO") |
| 12 | @Data | 13 | @Data |
| 13 | -@Accessors(chain = true) | ||
| 14 | -public class AppPayOrderSubmitReqVO { | ||
| 15 | - | ||
| 16 | - @Schema(description = "支付单编号", required = true, example = "1024") | ||
| 17 | - @NotNull(message = "支付单编号不能为空") | ||
| 18 | - private Long id; | ||
| 19 | - | ||
| 20 | - @Schema(description = "支付渠道", required = true, example = "wx_pub") | ||
| 21 | - @NotEmpty(message = "支付渠道不能为空") | ||
| 22 | - private String channelCode; | ||
| 23 | - | ||
| 24 | - @Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数") | ||
| 25 | - private Map<String, String> channelExtras; | ||
| 26 | - | 14 | +public class AppPayOrderSubmitReqVO extends PayOrderSubmitReqVO { |
| 27 | } | 15 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/vo/AppPayOrderSubmitRespVO.java
| 1 | package cn.iocoder.yudao.module.pay.controller.app.order.vo; | 1 | package cn.iocoder.yudao.module.pay.controller.app.order.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | import lombok.AllArgsConstructor; | 5 | import lombok.AllArgsConstructor; |
| 5 | import lombok.Builder; | 6 | import lombok.Builder; |
| @@ -9,15 +10,6 @@ import lombok.experimental.Accessors; | @@ -9,15 +10,6 @@ import lombok.experimental.Accessors; | ||
| 9 | 10 | ||
| 10 | @Schema(description = "用户 APP - 支付订单提交 Response VO") | 11 | @Schema(description = "用户 APP - 支付订单提交 Response VO") |
| 11 | @Data | 12 | @Data |
| 12 | -@Accessors(chain = true) | ||
| 13 | -@Builder | ||
| 14 | -@NoArgsConstructor | ||
| 15 | -@AllArgsConstructor | ||
| 16 | -public class AppPayOrderSubmitRespVO { | ||
| 17 | - | ||
| 18 | - /** | ||
| 19 | - * 调用支付渠道的响应结果 | ||
| 20 | - */ | ||
| 21 | - private Object invokeResponse; | 13 | +public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO { |
| 22 | 14 | ||
| 23 | } | 15 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/order/PayOrderConvert.java
| @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.pay.convert.order; | @@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.pay.convert.order; | ||
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 5 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | ||
| 5 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | 6 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 6 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; | 7 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO; |
| 7 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; | 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*; |
| 8 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; | 9 | import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO; |
| 10 | +import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO; | ||
| 9 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 12 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 11 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO; | ||
| 12 | import org.mapstruct.Mapper; | 13 | import org.mapstruct.Mapper; |
| 13 | import org.mapstruct.Mapping; | 14 | import org.mapstruct.Mapping; |
| 14 | import org.mapstruct.factory.Mappers; | 15 | import org.mapstruct.factory.Mappers; |
| @@ -29,6 +30,8 @@ public interface PayOrderConvert { | @@ -29,6 +30,8 @@ public interface PayOrderConvert { | ||
| 29 | 30 | ||
| 30 | PayOrderRespVO convert(PayOrderDO bean); | 31 | PayOrderRespVO convert(PayOrderDO bean); |
| 31 | 32 | ||
| 33 | + PayOrderRespDTO convert2(PayOrderDO order); | ||
| 34 | + | ||
| 32 | PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean); | 35 | PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean); |
| 33 | 36 | ||
| 34 | PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean); | 37 | PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean); |
| @@ -86,18 +89,15 @@ public interface PayOrderConvert { | @@ -86,18 +89,15 @@ public interface PayOrderConvert { | ||
| 86 | return payOrderExcelVO; | 89 | return payOrderExcelVO; |
| 87 | } | 90 | } |
| 88 | 91 | ||
| 89 | - | ||
| 90 | PayOrderDO convert(PayOrderCreateReqDTO bean); | 92 | PayOrderDO convert(PayOrderCreateReqDTO bean); |
| 91 | 93 | ||
| 92 | @Mapping(target = "id", ignore = true) | 94 | @Mapping(target = "id", ignore = true) |
| 93 | - PayOrderExtensionDO convert(PayOrderSubmitReqBO bean); | ||
| 94 | - | ||
| 95 | - PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqBO bean); | 95 | + PayOrderExtensionDO convert(PayOrderSubmitReqVO bean, String userIp); |
| 96 | 96 | ||
| 97 | - PayOrderRespDTO convert2(PayOrderDO bean); | 97 | + PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO); |
| 98 | 98 | ||
| 99 | - PayOrderSubmitReqBO convert(AppPayOrderSubmitReqVO bean, String userIp); | 99 | + PayOrderSubmitRespVO convert(PayOrderUnifiedRespDTO bean); |
| 100 | 100 | ||
| 101 | - PayOrderSubmitReqBO convert(PayOrderSubmitReqVO bean, String userIp); | 101 | + AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean); |
| 102 | 102 | ||
| 103 | } | 103 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
| 1 | package cn.iocoder.yudao.module.pay.service.order; | 1 | package cn.iocoder.yudao.module.pay.service.order; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 4 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 3 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; |
| 6 | +import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | ||
| 4 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; | 7 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; |
| 5 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; | 8 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; |
| 6 | -import cn.iocoder.yudao.framework.common.pojo.PageResult; | ||
| 7 | -import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | 9 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; |
| 10 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; | ||
| 8 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 11 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 9 | -import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | ||
| 10 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO; | ||
| 11 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO; | ||
| 12 | 12 | ||
| 13 | import javax.validation.Valid; | 13 | import javax.validation.Valid; |
| 14 | +import javax.validation.constraints.NotEmpty; | ||
| 14 | import java.util.Collection; | 15 | import java.util.Collection; |
| 15 | import java.util.List; | 16 | import java.util.List; |
| 16 | import java.util.Map; | 17 | import java.util.Map; |
| @@ -81,10 +82,12 @@ public interface PayOrderService { | @@ -81,10 +82,12 @@ public interface PayOrderService { | ||
| 81 | * 提交支付 | 82 | * 提交支付 |
| 82 | * 此时,会发起支付渠道的调用 | 83 | * 此时,会发起支付渠道的调用 |
| 83 | * | 84 | * |
| 84 | - * @param reqDTO 提交请求 | 85 | + * @param reqVO 提交请求 |
| 86 | + * @param userIp 提交 IP | ||
| 85 | * @return 提交结果 | 87 | * @return 提交结果 |
| 86 | */ | 88 | */ |
| 87 | - PayOrderSubmitRespBO submitPayOrder(@Valid PayOrderSubmitReqBO reqDTO); | 89 | + PayOrderSubmitRespVO submitPayOrder(@Valid PayOrderSubmitReqVO reqVO, |
| 90 | + @NotEmpty(message = "提交 IP 不能为空") String userIp); | ||
| 88 | 91 | ||
| 89 | /** | 92 | /** |
| 90 | * 通知支付单成功 | 93 | * 通知支付单成功 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
| @@ -12,10 +12,13 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | @@ -12,10 +12,13 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | ||
| 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO; |
| 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; | 13 | import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO; |
| 14 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 14 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 15 | +import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO; | ||
| 15 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; | 16 | import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; |
| 16 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; | 17 | import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO; |
| 17 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; | 18 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO; |
| 18 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; | 19 | import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO; |
| 20 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO; | ||
| 21 | +import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO; | ||
| 19 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; | 22 | import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert; |
| 20 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; | 23 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO; |
| 21 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; | 24 | import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO; |
| @@ -31,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; | @@ -31,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService; | ||
| 31 | import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService; | 34 | import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService; |
| 32 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | 35 | import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; |
| 33 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | 36 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 34 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO; | ||
| 35 | -import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO; | ||
| 36 | import lombok.extern.slf4j.Slf4j; | 37 | import lombok.extern.slf4j.Slf4j; |
| 37 | import org.springframework.stereotype.Service; | 38 | import org.springframework.stereotype.Service; |
| 38 | import org.springframework.transaction.annotation.Transactional; | 39 | import org.springframework.transaction.annotation.Transactional; |
| @@ -126,22 +127,22 @@ public class PayOrderServiceImpl implements PayOrderService { | @@ -126,22 +127,22 @@ public class PayOrderServiceImpl implements PayOrderService { | ||
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | @Override | 129 | @Override |
| 129 | - public PayOrderSubmitRespBO submitPayOrder(PayOrderSubmitReqBO reqBO) { | 130 | + public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) { |
| 130 | // 1. 获得 PayOrderDO ,并校验其是否存在 | 131 | // 1. 获得 PayOrderDO ,并校验其是否存在 |
| 131 | - PayOrderDO order = validatePayOrderCanSubmit(reqBO.getId()); | 132 | + PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId()); |
| 132 | // 1.2 校验支付渠道是否有效 | 133 | // 1.2 校验支付渠道是否有效 |
| 133 | - PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqBO.getChannelCode()); | 134 | + PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqVO.getChannelCode()); |
| 134 | PayClient client = payClientFactory.getPayClient(channel.getId()); | 135 | PayClient client = payClientFactory.getPayClient(channel.getId()); |
| 135 | 136 | ||
| 136 | // 2. 插入 PayOrderExtensionDO | 137 | // 2. 插入 PayOrderExtensionDO |
| 137 | - PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqBO) | 138 | + PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp) |
| 138 | .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) | 139 | .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) |
| 139 | .setChannelId(channel.getId()).setChannelCode(channel.getCode()) | 140 | .setChannelId(channel.getId()).setChannelCode(channel.getCode()) |
| 140 | .setStatus(PayOrderStatusEnum.WAITING.getStatus()); | 141 | .setStatus(PayOrderStatusEnum.WAITING.getStatus()); |
| 141 | orderExtensionMapper.insert(orderExtension); | 142 | orderExtensionMapper.insert(orderExtension); |
| 142 | 143 | ||
| 143 | // 3. 调用三方接口 | 144 | // 3. 调用三方接口 |
| 144 | - PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqBO) | 145 | + PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO) |
| 145 | // 商户相关的字段 | 146 | // 商户相关的字段 |
| 146 | .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! | 147 | .setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! |
| 147 | .setSubject(order.getSubject()).setBody(order.getBody()) | 148 | .setSubject(order.getSubject()).setBody(order.getBody()) |
| @@ -152,10 +153,11 @@ public class PayOrderServiceImpl implements PayOrderService { | @@ -152,10 +153,11 @@ public class PayOrderServiceImpl implements PayOrderService { | ||
| 152 | CommonResult<?> unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO); | 153 | CommonResult<?> unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO); |
| 153 | unifiedOrderResult.checkError(); | 154 | unifiedOrderResult.checkError(); |
| 154 | 155 | ||
| 156 | + PayOrderUnifiedRespDTO xx = (PayOrderUnifiedRespDTO) unifiedOrderResult.getData(); | ||
| 157 | + | ||
| 155 | // TODO 轮询三方接口,是否已经支付的任务 | 158 | // TODO 轮询三方接口,是否已经支付的任务 |
| 156 | // 返回成功 | 159 | // 返回成功 |
| 157 | - return new PayOrderSubmitRespBO().setExtensionId(orderExtension.getId()) | ||
| 158 | - .setInvokeResponse(unifiedOrderResult.getData()); | 160 | + return PayOrderConvert.INSTANCE.convert(xx); |
| 159 | } | 161 | } |
| 160 | 162 | ||
| 161 | private PayOrderDO validatePayOrderCanSubmit(Long id) { | 163 | private PayOrderDO validatePayOrderCanSubmit(Long id) { |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/bo/PayOrderSubmitReqBO.java deleted
| 1 | -package cn.iocoder.yudao.module.pay.service.order.bo; | ||
| 2 | - | ||
| 3 | -import lombok.Data; | ||
| 4 | -import lombok.experimental.Accessors; | ||
| 5 | - | ||
| 6 | -import javax.validation.constraints.NotEmpty; | ||
| 7 | -import javax.validation.constraints.NotNull; | ||
| 8 | -import java.io.Serializable; | ||
| 9 | -import java.util.Map; | ||
| 10 | - | ||
| 11 | -/** | ||
| 12 | - * 支付单提交 Request BO | ||
| 13 | - */ | ||
| 14 | -@Data | ||
| 15 | -@Accessors(chain = true) | ||
| 16 | -public class PayOrderSubmitReqBO implements Serializable { | ||
| 17 | - | ||
| 18 | - /** | ||
| 19 | - * 支付单编号 | ||
| 20 | - */ | ||
| 21 | - @NotNull(message = "支付单编号不能为空") | ||
| 22 | - private Long id; | ||
| 23 | - | ||
| 24 | - /** | ||
| 25 | - * 支付渠道 | ||
| 26 | - */ | ||
| 27 | - @NotEmpty(message = "支付渠道不能为空") | ||
| 28 | - private String channelCode; | ||
| 29 | - | ||
| 30 | - /** | ||
| 31 | - * 用户 IP | ||
| 32 | - */ | ||
| 33 | - @NotEmpty(message = "用户 IP 不能为空") | ||
| 34 | - private String userIp; | ||
| 35 | - | ||
| 36 | - /** | ||
| 37 | - * 支付渠道的额外参数 | ||
| 38 | - */ | ||
| 39 | - private Map<String, String> channelExtras; | ||
| 40 | - | ||
| 41 | -} |
yudao-ui-admin/src/utils/constants.js
| @@ -151,6 +151,18 @@ export const PayChannelEnum = { | @@ -151,6 +151,18 @@ export const PayChannelEnum = { | ||
| 151 | } | 151 | } |
| 152 | 152 | ||
| 153 | /** | 153 | /** |
| 154 | + * 支付的展示模式每局 | ||
| 155 | + */ | ||
| 156 | +export const PayDisplayModeEnum = { | ||
| 157 | + URL: { | ||
| 158 | + "mode": "url", | ||
| 159 | + }, | ||
| 160 | + IFRAME: { | ||
| 161 | + "mode": "iframe", | ||
| 162 | + }, | ||
| 163 | +} | ||
| 164 | + | ||
| 165 | +/** | ||
| 154 | * 支付类型枚举 | 166 | * 支付类型枚举 |
| 155 | */ | 167 | */ |
| 156 | export const PayType = { | 168 | export const PayType = { |
yudao-ui-admin/src/views/pay/order/submit.vue
| @@ -12,7 +12,6 @@ | @@ -12,7 +12,6 @@ | ||
| 12 | </el-descriptions> | 12 | </el-descriptions> |
| 13 | </el-card> | 13 | </el-card> |
| 14 | 14 | ||
| 15 | - | ||
| 16 | <!-- 支付选择框 --> | 15 | <!-- 支付选择框 --> |
| 17 | <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="提交支付中..."> | 16 | <el-card style="margin-top: 10px" v-loading="submitLoading" element-loading-text="提交支付中..."> |
| 18 | <!-- 支付宝 --> | 17 | <!-- 支付宝 --> |
| @@ -42,12 +41,18 @@ | @@ -42,12 +41,18 @@ | ||
| 42 | </div> | 41 | </div> |
| 43 | </el-card> | 42 | </el-card> |
| 44 | 43 | ||
| 45 | - <!-- 支付二维码 --> | 44 | + <!-- 展示形式:二维码 --> |
| 46 | <el-dialog :title="qrCode.title" :visible.sync="qrCode.visible" width="350px" append-to-body | 45 | <el-dialog :title="qrCode.title" :visible.sync="qrCode.visible" width="350px" append-to-body |
| 47 | :close-on-press-escape="false"> | 46 | :close-on-press-escape="false"> |
| 48 | <qrcode-vue :value="qrCode.url" size="310" level="H" /> | 47 | <qrcode-vue :value="qrCode.url" size="310" level="H" /> |
| 49 | </el-dialog> | 48 | </el-dialog> |
| 50 | 49 | ||
| 50 | + <!-- 展示形式:iframe --> | ||
| 51 | + <el-dialog :title="iframe.title" :visible.sync="iframe.visible" width="800px" height="800px" append-to-body | ||
| 52 | + :close-on-press-escape="false"> | ||
| 53 | + <iframe :src="iframe.url" width="100%" /> | ||
| 54 | + </el-dialog> | ||
| 55 | + | ||
| 51 | <!-- 阿里支付 --> | 56 | <!-- 阿里支付 --> |
| 52 | <div ref="alipayWap" v-html="alipayHtml.value" /> | 57 | <div ref="alipayWap" v-html="alipayHtml.value" /> |
| 53 | 58 | ||
| @@ -57,7 +62,7 @@ | @@ -57,7 +62,7 @@ | ||
| 57 | import QrcodeVue from 'qrcode.vue' | 62 | import QrcodeVue from 'qrcode.vue' |
| 58 | import { DICT_TYPE, getDictDatas } from "@/utils/dict"; | 63 | import { DICT_TYPE, getDictDatas } from "@/utils/dict"; |
| 59 | import { getOrder, submitOrder } from '@/api/pay/order'; | 64 | import { getOrder, submitOrder } from '@/api/pay/order'; |
| 60 | -import { PayChannelEnum, PayOrderStatusEnum } from "@/utils/constants"; | 65 | +import {PayChannelEnum, PayDisplayModeEnum, PayOrderStatusEnum} from "@/utils/constants"; |
| 61 | 66 | ||
| 62 | export default { | 67 | export default { |
| 63 | name: "PayOrderSubmit", | 68 | name: "PayOrderSubmit", |
| @@ -83,11 +88,16 @@ export default { | @@ -83,11 +88,16 @@ export default { | ||
| 83 | mock: require("@/assets/images/pay/icon/mock.svg"), | 88 | mock: require("@/assets/images/pay/icon/mock.svg"), |
| 84 | }, | 89 | }, |
| 85 | submitLoading: false, // 提交支付的 loading | 90 | submitLoading: false, // 提交支付的 loading |
| 86 | - qrCode: { // 支付二维码 | 91 | + qrCode: { // 展示形式:二维码 |
| 87 | url: '', | 92 | url: '', |
| 88 | title: '', | 93 | title: '', |
| 89 | visible: false, | 94 | visible: false, |
| 90 | }, | 95 | }, |
| 96 | + iframe: { // 展示形式:iframe | ||
| 97 | + url: '', | ||
| 98 | + title: '', | ||
| 99 | + visible: false | ||
| 100 | + }, | ||
| 91 | interval: undefined, // 定时任务,轮询是否完成支付 | 101 | interval: undefined, // 定时任务,轮询是否完成支付 |
| 92 | alipayHtml: '' // 阿里支付的 HTML | 102 | alipayHtml: '' // 阿里支付的 HTML |
| 93 | }; | 103 | }; |
| @@ -146,21 +156,65 @@ export default { | @@ -146,21 +156,65 @@ export default { | ||
| 146 | this.submitLoading = true | 156 | this.submitLoading = true |
| 147 | submitOrder({ | 157 | submitOrder({ |
| 148 | id: this.id, | 158 | id: this.id, |
| 149 | - channelCode: channelCode | 159 | + channelCode: channelCode, |
| 160 | + ...this.buildSubmitParam(channelCode) | ||
| 150 | }).then(response => { | 161 | }).then(response => { |
| 151 | - const invokeResponse = response.data.invokeResponse | ||
| 152 | - // 不同的支付,调用不同的策略 | ||
| 153 | - if (channelCode === PayChannelEnum.ALIPAY_QR.code) { | ||
| 154 | - this.submitAfterAlipayQr(invokeResponse) | ||
| 155 | - } else if (channelCode === PayChannelEnum.ALIPAY_PC.code | ||
| 156 | - || channelCode === PayChannelEnum.ALIPAY_WAP.code) { | ||
| 157 | - this.submitAfterAlipayPc(invokeResponse) | 162 | + const data = response.data |
| 163 | + if (data.displayMode === 'iframe') { | ||
| 164 | + this.displayIFrame(channelCode, data) | ||
| 165 | + } else if (data.displayMode === 'url') { | ||
| 166 | + this.displayUrl(channelCode, data) | ||
| 158 | } | 167 | } |
| 168 | + // 不同的支付,调用不同的策略 | ||
| 169 | + // if (channelCode === PayChannelEnum.ALIPAY_QR.code) { | ||
| 170 | + // this.submitAfterAlipayQr(invokeResponse) | ||
| 171 | + // } else if (channelCode === PayChannelEnum.ALIPAY_PC.code | ||
| 172 | + // || channelCode === PayChannelEnum.ALIPAY_WAP.code) { | ||
| 173 | + // this.submitAfterAlipayPc(invokeResponse) | ||
| 174 | + // } | ||
| 159 | 175 | ||
| 160 | // 打开轮询任务 | 176 | // 打开轮询任务 |
| 161 | this.createQueryInterval() | 177 | this.createQueryInterval() |
| 162 | }) | 178 | }) |
| 163 | }, | 179 | }, |
| 180 | + /** 构建提交支付的额外参数 */ | ||
| 181 | + buildSubmitParam(channelCode) { | ||
| 182 | + // 支付宝网页支付时,有多种展示形态 | ||
| 183 | + if (channelCode === PayChannelEnum.ALIPAY_PC.code) { | ||
| 184 | + // 情况【前置模式】:将二维码前置到商户的订单确认页的模式。需要商户在自己的页面中以 iframe 方式请求支付宝页面。具体支持的枚举值有以下几种: | ||
| 185 | + // 0:订单码-简约前置模式,对应 iframe 宽度不能小于 600px,高度不能小于 300px | ||
| 186 | + // return { | ||
| 187 | + // "channelExtras": { | ||
| 188 | + // "qr_pay_mode": "0" | ||
| 189 | + // } | ||
| 190 | + // } | ||
| 191 | + // 1:订单码-前置模式,对应iframe 宽度不能小于 300px,高度不能小于 600px | ||
| 192 | + // return { | ||
| 193 | + // "channelExtras": { | ||
| 194 | + // "qr_pay_mode": "1" | ||
| 195 | + // } | ||
| 196 | + // } | ||
| 197 | + // 3:订单码-迷你前置模式,对应 iframe 宽度不能小于 75px,高度不能小于 75px | ||
| 198 | + // return { | ||
| 199 | + // "channelExtras": { | ||
| 200 | + // "qr_pay_mode": "3" | ||
| 201 | + // } | ||
| 202 | + // } | ||
| 203 | + // 4:订单码-可定义宽度的嵌入式二维码,商户可根据需要设定二维码的大小 | ||
| 204 | + // return { | ||
| 205 | + // "channelExtras": { | ||
| 206 | + // "qr_pay_mode": "2" | ||
| 207 | + // } | ||
| 208 | + // } | ||
| 209 | + // 情况【跳转模式】:跳转模式下,用户的扫码界面是由支付宝生成的,不在商户的域名下。支持传入的枚举值有 | ||
| 210 | + return { | ||
| 211 | + "channelExtras": { | ||
| 212 | + "qr_pay_mode": "2" | ||
| 213 | + } | ||
| 214 | + } | ||
| 215 | + } | ||
| 216 | + return {} | ||
| 217 | + }, | ||
| 164 | /** 提交支付后(支付宝扫码支付) */ | 218 | /** 提交支付后(支付宝扫码支付) */ |
| 165 | submitAfterAlipayQr(invokeResponse) { | 219 | submitAfterAlipayQr(invokeResponse) { |
| 166 | this.qrCode = { | 220 | this.qrCode = { |
| @@ -170,6 +224,19 @@ export default { | @@ -170,6 +224,19 @@ export default { | ||
| 170 | } | 224 | } |
| 171 | this.submitLoading = false | 225 | this.submitLoading = false |
| 172 | }, | 226 | }, |
| 227 | + displayIFrame(channelCode, data) { | ||
| 228 | + // this.iframe = { | ||
| 229 | + // title: '支付窗口', | ||
| 230 | + // url: data.displayContent, | ||
| 231 | + // visible: true | ||
| 232 | + // } | ||
| 233 | + window.open(data.displayContent) | ||
| 234 | + }, | ||
| 235 | + /** 提交支付后,URL 的展示形式 */ | ||
| 236 | + displayUrl(channelCode, data) { | ||
| 237 | + window.open(data.displayContent) | ||
| 238 | + this.submitLoading = false | ||
| 239 | + }, | ||
| 173 | /** 提交支付后(支付宝 PC 网站支付) */ | 240 | /** 提交支付后(支付宝 PC 网站支付) */ |
| 174 | submitAfterAlipayPc(invokeResponse) { | 241 | submitAfterAlipayPc(invokeResponse) { |
| 175 | // 渲染支付页面 | 242 | // 渲染支付页面 |
| @@ -188,6 +255,9 @@ export default { | @@ -188,6 +255,9 @@ export default { | ||
| 188 | }, | 255 | }, |
| 189 | /** 轮询查询任务 */ | 256 | /** 轮询查询任务 */ |
| 190 | createQueryInterval() { | 257 | createQueryInterval() { |
| 258 | + if (!this.interval) { | ||
| 259 | + return | ||
| 260 | + } | ||
| 191 | this.interval = setInterval(() => { | 261 | this.interval = setInterval(() => { |
| 192 | getOrder(this.id).then(response => { | 262 | getOrder(this.id).then(response => { |
| 193 | // 已支付 | 263 | // 已支付 |