diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/enums/PayChannelCodeEnum.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/enums/PayChannelCodeEnum.java deleted file mode 100644 index 5a1140eb1..000000000 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/pay/enums/PayChannelCodeEnum.java +++ /dev/null @@ -1,28 +0,0 @@ -package cn.iocoder.yudao.adminserver.modules.pay.enums; - -import lombok.AllArgsConstructor; -import lombok.Getter; - -/** - * 支付渠道的编码的枚举 - * - * @author 芋道源码 - */ -@Getter -@AllArgsConstructor -public enum PayChannelCodeEnum { - - wx_pub("wx_pub", "微信 JSAPI 支付"); - - /** - * 编码 - * - * 参考 https://www.pingxx.com/api/支付渠道属性值.html - */ - private String code; - /** - * 名字 - */ - private String name; - -} diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java index 1c9fe64f5..aade111ea 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java @@ -3,16 +3,15 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO; +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum; +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderRefundStatusEnum; import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; -import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; import java.util.Date; -import java.util.Map; /** * 支付订单 DO @@ -61,7 +60,7 @@ public class PayOrderDO extends BaseDO { /** * 商户订单编号 - * 例如说,内部系统 A 的订单号。需要保证每个 PayMerchantDO 唯一 TODO 芋艿:需要在测试下 + * 例如说,内部系统 A 的订单号。需要保证每个 PayMerchantDO 唯一 */ private String merchantOrderId; /** @@ -72,6 +71,16 @@ public class PayOrderDO extends BaseDO { * 商品描述信息 */ private String body; + /** + * 异步通知地址 + */ + private String notifyUrl; + /** + * 通知商户支付结果的回调状态 + * + * 枚举 {@link PayOrderNotifyStatusEnum} + */ + private Integer notifyStatus; // /** // * 商户拓展参数 // */ @@ -99,11 +108,6 @@ public class PayOrderDO extends BaseDO { * 枚举 {@link PayOrderStatusEnum} */ private Integer status; - /** - * 通知商户支付结果的回调状态 - * TODO 芋艿:0 未发送 1 已发送 - */ - private Integer notifyStatus; /** * 用户 IP */ @@ -122,23 +126,12 @@ public class PayOrderDO extends BaseDO { * 关联 {@link PayOrderDO#getId()} */ private Long successExtensionId; - /** - * 支付渠道的额外参数 - * - * 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html - */ - @TableField(typeHandler = JacksonTypeHandler.class) - private Map channelExtras; - /** - * 异步通知地址 - */ - private String notifyUrl; // ========== 退款相关字段 ========== /** * 退款状态 * - * TODO 芋艿:0 - 未退款;1 - 部分退款; 2 - 全额退款 + * 枚举 {@link PayOrderRefundStatusEnum} */ private Integer refundStatus; /** diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java index f2734f8b1..5f629e094 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java @@ -3,9 +3,13 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; +import java.util.Map; + /** * 支付订单拓展 DO * @@ -49,7 +53,7 @@ public class PayOrderExtensionDO extends BaseDO { /** * 渠道编码 */ - private Integer channelCode; + private String channelCode; /** * 用户 IP */ @@ -61,6 +65,13 @@ public class PayOrderExtensionDO extends BaseDO { * 注意,只包含上述枚举的 WAITING 和 SUCCESS */ private Integer status; + /** + * 支付渠道的额外参数 + * + * 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map channelExtras; /** * 支付渠道异步通知的内容 * diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java index 9b88ea119..77e5a51e7 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java @@ -71,6 +71,15 @@ public class PayRefundDO extends BaseDO { // * 商户拓展参数 // */ // private String merchantExtra; + /** + * 异步通知地址 + */ + private String notifyUrl; + /** + * 通知商户退款结果的回调状态 + * TODO 芋艿:0 未发送 1 已发送 + */ + private Integer notifyStatus; // ========== 退款相关字段 ========== /** @@ -79,11 +88,6 @@ public class PayRefundDO extends BaseDO { * TODO 芋艿:状态枚举 */ private Integer status; - /** - * 通知商户退款结果的回调状态 - * TODO 芋艿:0 未发送 1 已发送 - */ - private Integer notifyStatus; /** * 用户 IP */ @@ -110,10 +114,6 @@ public class PayRefundDO extends BaseDO { * 参见 https://www.pingxx.com/api/Refunds%20退款概述.html */ private String channelExtra; - /** - * 异步通知地址 - */ - private String notifyUrl; // ========== 渠道相关字段 ========== /** diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderNotifyStatusEnum.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderNotifyStatusEnum.java new file mode 100644 index 000000000..4bda485d2 --- /dev/null +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderNotifyStatusEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.coreservice.modules.pay.enums.order; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付订单的通知状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayOrderNotifyStatusEnum implements IntArrayValuable { + + NO(0, "未通知"), + SUCCESS(10, "通知成功"), + FAILURE(20, "通知失败") + ; + + private final Integer status; + private final String name; + + @Override + public int[] array() { + return new int[0]; + } + +} diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderRefundStatusEnum.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderRefundStatusEnum.java new file mode 100644 index 000000000..3c283a9d5 --- /dev/null +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayOrderRefundStatusEnum.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.coreservice.modules.pay.enums.order; + +import cn.iocoder.yudao.framework.common.core.IntArrayValuable; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 支付订单的退款状态枚举 + * + * @author 芋道源码 + */ +@Getter +@AllArgsConstructor +public enum PayOrderRefundStatusEnum implements IntArrayValuable { + + NO(0, "未退款"), + SOME(10, "部分退款"), + ALL(20, "全部退款") + ; + + private final Integer status; + private final String name; + + @Override + public int[] array() { + return new int[0]; + } + +} diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java index 64e5240c2..60612a4f1 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java @@ -12,6 +12,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.validation.Valid; @@ -50,6 +51,7 @@ public class PayChannelCoreServiceImpl implements PayChannelCoreService { private PayClientFactory payClientFactory; @Override + @PostConstruct public void initPayClients() { // 获取支付渠道,如果有更新 List payChannels = this.loadPayChannelIfUpdate(maxUpdateTime); diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java index 329f28bab..40adf4ed2 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java @@ -28,6 +28,6 @@ public interface PayOrderCoreService { * @param reqDTO 提交请求 * @return 提交结果 */ - PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO); + PayOrderSubmitRespDTO submitPayOrder(@Valid PayOrderSubmitReqDTO reqDTO); } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java index 542d5a52e..007523678 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.order.dto; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; 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 DTO @@ -38,4 +41,10 @@ public class PayOrderSubmitReqDTO implements Serializable { @NotEmpty(message = "用户 IP 不能为空") private String userIp; + /** + * 支付渠道的额外参数 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map channelExtras; + } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java index f843ef780..344229c5a 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderCoreMapper; import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensionCoreMapper; +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum; import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService; import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; @@ -20,12 +21,14 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; -import javax.validation.Valid; import java.util.Date; +import java.util.Objects; import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; @@ -36,7 +39,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU * @author 芋道源码 */ @Service -@Valid +@Validated @Slf4j public class PayOrderCoreServiceImpl implements PayOrderCoreService { @@ -68,10 +71,16 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { } // 创建支付交易单 - // TODO 芋艿:需要看看,还有啥要补全的字段 order = PayOrderCoreConvert.INSTANCE.convert(reqDTO) - .setStatus(PayOrderStatusEnum.WAITING.getStatus()) - .setNotifyUrl(app.getPayNotifyUrl()); + .setMerchantId(app.getMerchantId()).setAppId(app.getId()); + // 商户相关字段 + order.setNotifyUrl(app.getPayNotifyUrl()) + .setNotifyStatus(PayOrderNotifyStatusEnum.NO.getStatus()); + // 订单相关字段 + order.setStatus(PayOrderStatusEnum.WAITING.getStatus()); + // 退款相关字段 + order.setRefundStatus(PayOrderNotifyStatusEnum.NO.getStatus()) + .setRefundTimes(0).setRefundAmount(0L); payOrderCoreMapper.insert(order); // 最终返回 return order.getId(); @@ -80,9 +89,9 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @Override public PayOrderSubmitRespDTO submitPayOrder(PayOrderSubmitReqDTO reqDTO) { // 校验 App - PayAppDO app = payAppCoreService.validPayApp(reqDTO.getId()); + PayAppDO app = payAppCoreService.validPayApp(reqDTO.getAppId()); // 校验支付渠道是否有效 - PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getId(), reqDTO.getChannelCode()); + PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getAppId(), reqDTO.getChannelCode()); // 校验支付客户端是否正确初始化 PayClient client = payClientFactory.getPayClient(channel.getId()); if (client == null) { @@ -92,7 +101,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { // 获得 PayOrderDO ,并校验其是否存在 PayOrderDO order = payOrderCoreMapper.selectById(reqDTO.getId()); - if (order == null || order.getAppId().equals(reqDTO.getAppId())) { // 是否存在 + if (order == null || !Objects.equals(order.getAppId(), reqDTO.getAppId())) { // 是否存在 throw exception(PAY_ORDER_NOT_FOUND); } if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付 @@ -102,18 +111,25 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { // 插入 PayOrderExtensionDO PayOrderExtensionDO orderExtension = PayOrderCoreConvert.INSTANCE.convert(reqDTO) .setOrderId(order.getId()).setNo(generateOrderExtensionNo()) + .setChannelId(channel.getId()).setChannelCode(channel.getCode()) .setStatus(PayOrderStatusEnum.WAITING.getStatus()); payOrderExtensionCoreMapper.insert(orderExtension); // 调用三方接口 - // TODO 暂时传入 extra = null - CommonResult invokeResult = client.unifiedOrder(PayOrderCoreConvert.INSTANCE.convert2(reqDTO)); - invokeResult.checkError(); + PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderCoreConvert.INSTANCE.convert2(reqDTO); + // 商户相关字段 + unifiedOrderReqDTO.setMerchantOrderId(order.getMerchantOrderId()) + .setSubject(order.getSubject()).setBody(order.getBody()) + .setNotifyUrl(app.getPayNotifyUrl()); + // 订单相关字段 + unifiedOrderReqDTO.setAmount(order.getAmount()).setExpireTime(order.getExpireTime()); + CommonResult unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO); + unifiedOrderResult.checkError(); // TODO 轮询三方接口,是否已经支付的任务 // 返回成功 return new PayOrderSubmitRespDTO().setExtensionId(orderExtension.getId()) - .setInvokeResponse(JsonUtils.toJsonString(invokeResult)); + .setInvokeResponse(JsonUtils.toJsonString(unifiedOrderResult)); } private String generateOrderExtensionNo() { diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreServiceTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreServiceTest.java new file mode 100644 index 000000000..2a5e13741 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreServiceTest.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.coreservice.modules.pay.service.order; + +import cn.iocoder.yudao.coreservice.BaseDbIntegrationTest; +import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.impl.PayAppCoreServiceImpl; +import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.impl.PayChannelCoreServiceImpl; +import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO; +import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; +import cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.PayOrderCoreServiceImpl; +import cn.iocoder.yudao.framework.common.util.date.DateUtils; +import cn.iocoder.yudao.framework.pay.config.YudaoPayAutoConfiguration; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Import; + +import javax.annotation.Resource; +import java.time.Duration; + +@Import({PayOrderCoreServiceImpl.class, PayAppCoreServiceImpl.class, + PayChannelCoreServiceImpl.class, YudaoPayAutoConfiguration.class}) +public class PayOrderCoreServiceTest extends BaseDbIntegrationTest { + + @Resource + private PayOrderCoreService payOrderCoreService; + + @Test + public void testCreatePayOrder() { + // 构造请求 + PayOrderCreateReqDTO reqDTO = new PayOrderCreateReqDTO(); + reqDTO.setAppId(6L); + reqDTO.setUserIp("127.0.0.1"); + reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); + reqDTO.setSubject("标题"); + reqDTO.setBody("内容"); + reqDTO.setAmount(100); + reqDTO.setExpireTime(DateUtils.addTime(Duration.ofDays(1))); + // 发起请求 + payOrderCoreService.createPayOrder(reqDTO); + } + + @Test + public void testSubmitPayOrder() { + // 构造请求 + PayOrderSubmitReqDTO reqDTO = new PayOrderSubmitReqDTO(); + reqDTO.setId(10L); + reqDTO.setAppId(6L); + reqDTO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); + reqDTO.setUserIp("127.0.0.1"); + // 发起请求 + payOrderCoreService.submitPayOrder(reqDTO); + } + +} diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/package-info.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/package-info.java new file mode 100644 index 000000000..13b4863a5 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/service/package-info.java @@ -0,0 +1 @@ +package cn.iocoder.yudao.coreservice.modules.pay.service; diff --git a/yudao-core-service/src/test-integration/resources/application-integration-test.yaml b/yudao-core-service/src/test-integration/resources/application-integration-test.yaml index 06796faab..06353ae11 100644 --- a/yudao-core-service/src/test-integration/resources/application-integration-test.yaml +++ b/yudao-core-service/src/test-integration/resources/application-integration-test.yaml @@ -60,7 +60,7 @@ mybatis-plus: logic-delete-value: 1 # 逻辑已删除值(默认为 1) logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) mapper-locations: classpath*:mapper/*.xml - type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject, ${yudao.core-service.base-package}.modules.*.dal.dataobject + type-aliases-package: ${yudao.core-service.base-package}.modules.*.dal.dataobject --- #################### 定时任务相关配置 #################### diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java index 29a8d38b8..17a1ef843 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/object/ObjectUtils.java @@ -29,4 +29,13 @@ public class ObjectUtils { return obj1.compareTo(obj2) > 0 ? obj1 : obj2; } + public static T defaultIfNull(T... array) { + for (T item : array) { + if (item != null) { + return item; + } + } + return null; + } + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java index 05278a9ce..ed2de63a8 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.framework.pay.core.client; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; /** @@ -17,7 +16,12 @@ public interface PayClient { */ Long getId(); - // TODO 缺少注释 - CommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO); + /** + * 调用支付渠道,统一下单 + * + * @param reqDTO 下单信息 + * @return 各支付渠道的返回结果 + */ + PayCommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java index cd1159adf..bb8c0d8dc 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java @@ -54,7 +54,7 @@ public class PayOrderUnifiedReqDTO { */ @NotNull(message = "支付金额不能为空") @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") - private Integer amount; + private Long amount; /** * 支付过期时间 diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java index 97850bdcf..1e228b252 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/AbstractPayClient.java @@ -1,10 +1,15 @@ package cn.iocoder.yudao.framework.pay.core.client.impl; +import cn.hutool.extra.validation.ValidationUtil; +import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; -import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; +import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import lombok.extern.slf4j.Slf4j; +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; + /** * 支付客户端的抽象类,提供模板方法,减少子类的冗余代码 * @@ -30,7 +35,7 @@ public abstract class AbstractPayClient implemen */ protected Config config; - protected Double calculateAmount(Integer amount) { + protected Double calculateAmount(Long amount) { return amount / 100.0; } @@ -70,4 +75,23 @@ public abstract class AbstractPayClient implemen return channelId; } + @Override + public final PayCommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + ValidationUtil.validate(reqDTO); + // 执行短信发送 + PayCommonResult result; + try { + result = doUnifiedOrder(reqDTO); + } catch (Throwable ex) { + // 打印异常日志 + log.error("[unifiedOrder][request({}) 发起支付失败]", toJsonString(reqDTO), ex); + // 封装返回 + return PayCommonResult.error(ex); + } + return result; + } + + protected abstract PayCommonResult doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) + throws Throwable; + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java index 96f5a286c..88b08d5d2 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; import cn.hutool.core.bean.BeanUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -42,7 +41,7 @@ public class AlipayQrPayClient extends AbstractPayClient } @Override - public CommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + public PayCommonResult doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { // 构建 AlipayTradePrecreateModel 请求 AlipayTradePrecreateModel model = new AlipayTradePrecreateModel(); model.setOutTradeNo(reqDTO.getMerchantOrderId()); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java index 94265b951..dbe73e27c 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; import cn.hutool.core.bean.BeanUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -37,7 +36,7 @@ public class AlipayWapPayClient extends AbstractPayClient } @Override - public CommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + public PayCommonResult doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { // 构建 AlipayTradeWapPayModel 请求 AlipayTradeWapPayModel model = new AlipayTradeWapPayModel(); model.setOutTradeNo(reqDTO.getMerchantOrderId()); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXCodeMapping.java index d52e83a5c..cb5e872e7 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXCodeMapping.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXCodeMapping.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx; +import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.exception.ErrorCode; import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants; import cn.iocoder.yudao.framework.pay.core.client.AbstractPayCodeMapping; @@ -44,6 +45,11 @@ public class WXCodeMapping extends AbstractPayCodeMapping { return PAY_OPENID_ERROR; } } + if (Objects.equals(apiCode, "CustomErrorCode")) { + if (StrUtil.contains(apiMsg, "必填字段")) { + return PAY_PARAM_MISSING; + } + } return null; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java index 5d8f042eb..d2a2de521 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java @@ -3,8 +3,8 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.wx; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.io.FileUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -21,7 +21,6 @@ import com.github.binarywang.wxpay.service.WxPayService; import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl; import lombok.extern.slf4j.Slf4j; -import static cn.hutool.core.util.ObjectUtil.defaultIfNull; import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.CODE_SUCCESS; import static cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXCodeMapping.MESSAGE_SUCCESS; @@ -62,7 +61,7 @@ public class WXPubPayClient extends AbstractPayClient { } @Override - public CommonResult unifiedOrder(PayOrderUnifiedReqDTO reqDTO) { + public PayCommonResult doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { WxPayMpOrderResult response; try { switch (config.getApiVersion()) { @@ -80,8 +79,8 @@ public class WXPubPayClient extends AbstractPayClient { } } catch (WxPayException e) { log.error("[unifiedOrder][request({}) 发起支付失败,原因({})]", toJsonString(reqDTO), e); - return PayCommonResult.build(defaultIfNull(e.getErrCode(), e.getReturnCode()), - defaultIfNull(e.getErrCodeDes(), e.getReturnMsg()),null, codeMapping); + return PayCommonResult.build(ObjectUtils.defaultIfNull(e.getErrCode(), e.getReturnCode(), "CustomErrorCode"), + ObjectUtils.defaultIfNull(e.getErrCodeDes(), e.getCustomErrorMsg()),null, codeMapping); } return PayCommonResult.build(CODE_SUCCESS, MESSAGE_SUCCESS, response, codeMapping); } @@ -92,9 +91,9 @@ public class WXPubPayClient extends AbstractPayClient { .outTradeNo(reqDTO.getMerchantOrderId()) // TODO 芋艿:貌似没 title? .body(reqDTO.getBody()) - .totalFee(reqDTO.getAmount()) // 单位分 + .totalFee(reqDTO.getAmount().intValue()) // 单位分 .timeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss")) - .spbillCreateIp(reqDTO.getClientIp()) + .spbillCreateIp(reqDTO.getUserIp()) .openid("ockUAwIZ-0OeMZl9ogcZ4ILrGba0") // TODO 芋艿:先随便写死 .notifyUrl(reqDTO.getNotifyUrl()) .build(); @@ -108,10 +107,10 @@ public class WXPubPayClient extends AbstractPayClient { request.setOutTradeNo(reqDTO.getMerchantOrderId()); // TODO 芋艿:貌似没 title? request.setDescription(reqDTO.getBody()); - request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount())); // 单位分 + request.setAmount(new WxPayUnifiedOrderV3Request.Amount().setTotal(reqDTO.getAmount().intValue())); // 单位分 request.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(), "yyyyMMddHHmmss")); request.setPayer(new WxPayUnifiedOrderV3Request.Payer().setOpenid("ockUAwIZ-0OeMZl9ogcZ4ILrGba0")); // TODO 芋艿:先随便写死 - request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getClientIp())); + request.setSceneInfo(new WxPayUnifiedOrderV3Request.SceneInfo().setPayerClientIp(reqDTO.getUserIp())); request.setNotifyUrl(reqDTO.getNotifyUrl()); // 执行请求 return client.createOrderV3(TradeTypeEnum.JSAPI, request); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java index 92b516029..7046b4c6f 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayFrameworkErrorCodeConstants.java @@ -20,6 +20,7 @@ public interface PayFrameworkErrorCodeConstants { // ========== 其它相关 2002000900 开头 ========== ErrorCode PAY_OPENID_ERROR = new ErrorCode(2002000900, "无效的 openid"); // 例如说,微信 openid 未授权过 + ErrorCode PAY_PARAM_MISSING = new ErrorCode(2002000901, "请求参数缺失"); // 例如说,支付少传了金额 ErrorCode EXCEPTION = new ErrorCode(2002000999, "调用异常"); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring.factories b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring.factories new file mode 100644 index 000000000..c135d7d79 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + cn.iocoder.yudao.framework.pay.config.YudaoPayAutoConfiguration diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java index e5ccbe836..d7f8e462f 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test-integration/java/cn/iocoder/yudao/framework/core/client/impl/PayClientFactoryImplTest.java @@ -117,11 +117,11 @@ public class PayClientFactoryImplTest { private static PayOrderUnifiedReqDTO buildPayOrderUnifiedReqDTO() { PayOrderUnifiedReqDTO reqDTO = new PayOrderUnifiedReqDTO(); - reqDTO.setAmount(123); + reqDTO.setAmount(123L); reqDTO.setSubject("IPhone 13"); reqDTO.setBody("biubiubiu"); reqDTO.setMerchantOrderId(String.valueOf(System.currentTimeMillis())); - reqDTO.setClientIp("127.0.0.1"); + reqDTO.setUserIp("127.0.0.1"); reqDTO.setNotifyUrl("http://127.0.0.1:8080"); return reqDTO; }