pay: 接入支付宝 PC 支付的跳转模式

This commit is contained in:
YunaiV
2023-02-18 20:59:18 +08:00
parent df702e8d24
commit b34801f303
18 changed files with 276 additions and 172 deletions

View File

@ -2,9 +2,13 @@ package cn.iocoder.yudao.module.pay.controller.admin.order;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayMerchantDO;
@ -14,16 +18,9 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService;
import cn.iocoder.yudao.module.pay.service.merchant.PayMerchantService;
import cn.iocoder.yudao.module.pay.service.order.PayOrderExtensionService;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -94,10 +91,9 @@ public class PayOrderController {
@PostMapping("/submit")
@Operation(summary = "提交支付订单")
public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
PayOrderSubmitRespBO respDTO = payOrderService.submitPayOrder(
PayOrderConvert.INSTANCE.convert(reqVO, getClientIP()));
return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse()));
public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP());
return success(respVO);
}
@GetMapping("/page")

View File

@ -6,11 +6,11 @@ import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.awt.*;
import java.util.Map;
@Schema(description = "管理后台 - 支付订单提交 Request VO")
@Data
@Accessors(chain = true)
public class PayOrderSubmitReqVO {
@Schema(description = "支付单编号", required = true, example = "1024")
@ -24,4 +24,6 @@ public class PayOrderSubmitReqVO {
@Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数")
private Map<String, String> channelExtras;
@Schema(description = "展示模式", example = "url") // 参见 {@link PayDisplayModeEnum} 枚举。如果不传递,则每个支付渠道使用默认的方式
private String displayMode;
}

View File

@ -9,15 +9,12 @@ import lombok.experimental.Accessors;
@Schema(description = "管理后台 - 支付订单提交 Response VO")
@Data
@Accessors(chain = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PayOrderSubmitRespVO {
/**
* 调用支付渠道的响应结果
*/
private Object invokeResponse;
@Schema(description = "展示模式", required = true, example = "url") // 参见 PayDisplayModeEnum 枚举
private String displayMode;
@Schema(description = "展示内容", required = true)
private String displayContent;
}

View File

@ -1,11 +1,11 @@
package cn.iocoder.yudao.module.pay.controller.app.order;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
@ -33,9 +33,8 @@ public class AppPayOrderController {
@PostMapping("/submit")
@Operation(summary = "提交支付订单")
public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) {
PayOrderSubmitRespBO respDTO = orderService.submitPayOrder(
PayOrderConvert.INSTANCE.convert(reqVO, getClientIP()));
return success(new AppPayOrderSubmitRespVO(respDTO.getInvokeResponse()));
PayOrderSubmitRespVO respVO = orderService.submitPayOrder(reqVO, getClientIP());
return success(PayOrderConvert.INSTANCE.convert3(respVO));
}
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.pay.controller.app.order.vo;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
@ -10,18 +11,5 @@ import java.util.Map;
@Schema(description = "用户 APP - 支付订单提交 Request VO")
@Data
@Accessors(chain = true)
public class AppPayOrderSubmitReqVO {
@Schema(description = "支付单编号", required = true, example = "1024")
@NotNull(message = "支付单编号不能为空")
private Long id;
@Schema(description = "支付渠道", required = true, example = "wx_pub")
@NotEmpty(message = "支付渠道不能为空")
private String channelCode;
@Schema(description = "支付渠道的额外参数,例如说,微信公众号需要传递 openid 参数")
private Map<String, String> channelExtras;
public class AppPayOrderSubmitReqVO extends PayOrderSubmitReqVO {
}

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.module.pay.controller.app.order.vo;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -9,15 +10,6 @@ import lombok.experimental.Accessors;
@Schema(description = "用户 APP - 支付订单提交 Response VO")
@Data
@Accessors(chain = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class AppPayOrderSubmitRespVO {
/**
* 调用支付渠道的响应结果
*/
private Object invokeResponse;
public class AppPayOrderSubmitRespVO extends PayOrderSubmitRespVO {
}

View File

@ -2,13 +2,14 @@ package cn.iocoder.yudao.module.pay.convert.order;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderRespDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.app.order.vo.AppPayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@ -29,6 +30,8 @@ public interface PayOrderConvert {
PayOrderRespVO convert(PayOrderDO bean);
PayOrderRespDTO convert2(PayOrderDO order);
PayOrderDetailsRespVO orderDetailConvert(PayOrderDO bean);
PayOrderDetailsRespVO.PayOrderExtension orderDetailExtensionConvert(PayOrderExtensionDO bean);
@ -86,18 +89,15 @@ public interface PayOrderConvert {
return payOrderExcelVO;
}
PayOrderDO convert(PayOrderCreateReqDTO bean);
@Mapping(target = "id", ignore = true)
PayOrderExtensionDO convert(PayOrderSubmitReqBO bean);
PayOrderExtensionDO convert(PayOrderSubmitReqVO bean, String userIp);
PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqBO bean);
PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqVO reqVO);
PayOrderRespDTO convert2(PayOrderDO bean);
PayOrderSubmitRespVO convert(PayOrderUnifiedRespDTO bean);
PayOrderSubmitReqBO convert(AppPayOrderSubmitReqVO bean, String userIp);
PayOrderSubmitReqBO convert(PayOrderSubmitReqVO bean, String userIp);
AppPayOrderSubmitRespVO convert3(PayOrderSubmitRespVO bean);
}

View File

@ -1,16 +1,17 @@
package cn.iocoder.yudao.module.pay.service.order;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@ -81,10 +82,12 @@ public interface PayOrderService {
* 提交支付
* 此时,会发起支付渠道的调用
*
* @param reqDTO 提交请求
* @param reqVO 提交请求
* @param userIp 提交 IP
* @return 提交结果
*/
PayOrderSubmitRespBO submitPayOrder(@Valid PayOrderSubmitReqBO reqDTO);
PayOrderSubmitRespVO submitPayOrder(@Valid PayOrderSubmitReqVO reqVO,
@NotEmpty(message = "提交 IP 不能为空") String userIp);
/**
* 通知支付单成功

View File

@ -12,10 +12,13 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayNotifyDataDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.notify.PayOrderNotifyRespDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedRespDTO;
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderExportReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderPageReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitReqVO;
import cn.iocoder.yudao.module.pay.controller.admin.order.vo.PayOrderSubmitRespVO;
import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.merchant.PayChannelDO;
@ -31,8 +34,6 @@ import cn.iocoder.yudao.module.pay.service.merchant.PayAppService;
import cn.iocoder.yudao.module.pay.service.merchant.PayChannelService;
import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitReqBO;
import cn.iocoder.yudao.module.pay.service.order.bo.PayOrderSubmitRespBO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -126,22 +127,22 @@ public class PayOrderServiceImpl implements PayOrderService {
}
@Override
public PayOrderSubmitRespBO submitPayOrder(PayOrderSubmitReqBO reqBO) {
public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) {
// 1. 获得 PayOrderDO ,并校验其是否存在
PayOrderDO order = validatePayOrderCanSubmit(reqBO.getId());
PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId());
// 1.2 校验支付渠道是否有效
PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqBO.getChannelCode());
PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqVO.getChannelCode());
PayClient client = payClientFactory.getPayClient(channel.getId());
// 2. 插入 PayOrderExtensionDO
PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqBO)
PayOrderExtensionDO orderExtension = PayOrderConvert.INSTANCE.convert(reqVO, userIp)
.setOrderId(order.getId()).setNo(generateOrderExtensionNo())
.setChannelId(channel.getId()).setChannelCode(channel.getCode())
.setStatus(PayOrderStatusEnum.WAITING.getStatus());
orderExtensionMapper.insert(orderExtension);
// 3. 调用三方接口
PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqBO)
PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderConvert.INSTANCE.convert2(reqVO)
// 商户相关的字段
.setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性!
.setSubject(order.getSubject()).setBody(order.getBody())
@ -152,10 +153,11 @@ public class PayOrderServiceImpl implements PayOrderService {
CommonResult<?> unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO);
unifiedOrderResult.checkError();
PayOrderUnifiedRespDTO xx = (PayOrderUnifiedRespDTO) unifiedOrderResult.getData();
// TODO 轮询三方接口,是否已经支付的任务
// 返回成功
return new PayOrderSubmitRespBO().setExtensionId(orderExtension.getId())
.setInvokeResponse(unifiedOrderResult.getData());
return PayOrderConvert.INSTANCE.convert(xx);
}
private PayOrderDO validatePayOrderCanSubmit(Long id) {

View File

@ -1,41 +0,0 @@
package cn.iocoder.yudao.module.pay.service.order.bo;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.util.Map;
/**
* 支付单提交 Request BO
*/
@Data
@Accessors(chain = true)
public class PayOrderSubmitReqBO implements Serializable {
/**
* 支付单编号
*/
@NotNull(message = "支付单编号不能为空")
private Long id;
/**
* 支付渠道
*/
@NotEmpty(message = "支付渠道不能为空")
private String channelCode;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 支付渠道的额外参数
*/
private Map<String, String> channelExtras;
}

View File

@ -1,23 +0,0 @@
package cn.iocoder.yudao.module.pay.service.order.bo;
import lombok.Data;
import java.io.Serializable;
/**
* 支付单提交 Response BO
*/
@Data
public class PayOrderSubmitRespBO implements Serializable {
/**
* 支付拓展单的编号
*/
private Long extensionId;
/**
* 调用支付渠道的响应结果
*/
private Object invokeResponse;
}